cpu: move cpuload/cpuchunks options into private engine option space
[fio.git] / goptions.c
CommitLineData
9af4a244
JA
1#include <locale.h>
2#include <malloc.h>
3#include <string.h>
4
5#include <glib.h>
6#include <cairo.h>
7#include <gtk/gtk.h>
8
9#include "fio.h"
10#include "gfio.h"
11#include "ghelpers.h"
12#include "parse.h"
13
14struct gopt {
15 GtkWidget *box;
16 unsigned int opt_index;
17 unsigned int opt_type;
18};
19
20struct gopt_combo {
21 struct gopt gopt;
22 GtkWidget *combo;
23};
24
25struct gopt_int {
26 struct gopt gopt;
90265353
JA
27 unsigned int lastval;
28 unsigned int in_change;
9af4a244
JA
29 GtkWidget *spin;
30};
31
32struct gopt_bool {
33 struct gopt gopt;
a01a1bc5 34 unsigned int in_change;
9af4a244
JA
35 GtkWidget *check;
36};
37
38struct gopt_str {
39 struct gopt gopt;
40 GtkWidget *entry;
41};
42
1da10c19
JA
43#define GOPT_RANGE_SPIN 4
44
9af4a244
JA
45struct gopt_range {
46 struct gopt gopt;
1da10c19 47 GtkWidget *spins[GOPT_RANGE_SPIN];
9af4a244
JA
48};
49
7386d4ae
JA
50struct gopt_str_multi {
51 struct gopt gopt;
52 GtkWidget *checks[PARSE_MAX_VP];
53};
54
e8b0e958 55static GtkWidget *gopt_widgets[FIO_MAX_OPTS];
ec0218ff 56
e8b0e958
JA
57struct gopt_frame_widget {
58 GtkWidget *vbox[2];
59 unsigned int nr;
60};
61static struct gopt_frame_widget gopt_g_widgets[__FIO_OPT_G_NR];
ec0218ff 62
e8b0e958 63static GtkWidget *gopt_get_group_frame(GtkWidget *box, unsigned int groupmask)
ec0218ff 64{
e8b0e958
JA
65 unsigned int mask, group;
66 struct opt_group *og;
67 GtkWidget *frame, *hbox;
68 struct gopt_frame_widget *gfw;
69
70 if (!groupmask)
71 return 0;
72
73 mask = groupmask;
74 og = opt_group_cat_from_mask(&mask);
75 if (!og)
76 return NULL;
77
78 group = ffz(~groupmask);
79 gfw = &gopt_g_widgets[group];
80 if (!gfw->vbox[0]) {
81 frame = gtk_frame_new(og->name);
82 gtk_box_pack_start(GTK_BOX(box), frame, FALSE, FALSE, 3);
83 hbox = gtk_hbox_new(FALSE, 0);
84 gtk_container_add(GTK_CONTAINER(frame), hbox);
85 gfw->vbox[0] = gtk_vbox_new(TRUE, 5);
86 gfw->vbox[1] = gtk_vbox_new(TRUE, 5);
87 gtk_box_pack_start(GTK_BOX(hbox), gfw->vbox[0], TRUE, TRUE, 5);
88 gtk_box_pack_start(GTK_BOX(hbox), gfw->vbox[1], TRUE, TRUE, 5);
ec0218ff 89 }
e8b0e958
JA
90
91 hbox = gtk_hbox_new(FALSE, 3);
92 gtk_box_pack_start(GTK_BOX(gfw->vbox[gfw->nr++ & 1]), hbox, FALSE, FALSE, 5);
93 return hbox;
ec0218ff 94}
b6caa836
JA
95
96/*
97 * Mark children as invisible, if needed.
98 */
99static void gopt_set_children_visible(struct fio_option *parent, gboolean visible)
100{
101 struct fio_option *o;
102 int i;
103
104 /*
105 * This isn't super fast, but it should not be an issue. If it is, we
106 * can speed it up by caching the lookup at least. Or we can do it
107 * once, at init time.
108 */
109 for (i = 0; fio_options[i].name; i++) {
110 o = &fio_options[i];
ec0218ff 111 if (!o->parent || !o->hide)
b6caa836
JA
112 continue;
113
114 if (strcmp(parent->name, o->parent))
115 continue;
116
e8b0e958
JA
117 if (gopt_widgets[i])
118 gtk_widget_set_sensitive(gopt_widgets[i], visible);
b6caa836
JA
119 }
120}
121
122static void gopt_str_changed(GtkEntry *entry, gpointer data)
123{
124 struct gopt_str *s = (struct gopt_str *) data;
125 struct fio_option *o = &fio_options[s->gopt.opt_index];
126 const gchar *text;
127 int set;
128
129 text = gtk_entry_get_text(GTK_ENTRY(s->entry));
130 set = strcmp(text, "") != 0;
131 gopt_set_children_visible(o, set);
132}
133
ec0218ff 134static void gopt_mark_index(struct gopt *gopt, unsigned int idx)
b6caa836 135{
e8b0e958 136 assert(!gopt_widgets[idx]);
b6caa836 137 gopt->opt_index = idx;
e8b0e958 138 gopt_widgets[idx] = gopt->box;
b6caa836
JA
139}
140
141static struct gopt *gopt_new_str_store(struct fio_option *o, const char *text, unsigned int idx)
9af4a244
JA
142{
143 struct gopt_str *s;
144 GtkWidget *label;
145
146 s = malloc(sizeof(*s));
a01a1bc5 147 memset(s, 0, sizeof(*s));
9af4a244
JA
148
149 s->gopt.box = gtk_hbox_new(FALSE, 3);
e8b0e958
JA
150 if (!o->lname)
151 label = gtk_label_new(o->name);
152 else
153 label = gtk_label_new(o->lname);
9af4a244
JA
154
155 s->entry = gtk_entry_new();
ec0218ff 156 gopt_mark_index(&s->gopt, idx);
789f4ccd
JA
157 if (text)
158 gtk_entry_set_text(GTK_ENTRY(s->entry), text);
9af4a244 159 gtk_entry_set_editable(GTK_ENTRY(s->entry), 1);
b6caa836 160 g_signal_connect(GTK_OBJECT(s->entry), "changed", G_CALLBACK(gopt_str_changed), s);
9af4a244
JA
161
162 if (o->def)
163 gtk_entry_set_text(GTK_ENTRY(s->entry), o->def);
164
165 gtk_box_pack_start(GTK_BOX(s->gopt.box), s->entry, FALSE, FALSE, 0);
e8b0e958 166 gtk_box_pack_start(GTK_BOX(s->gopt.box), label, FALSE, FALSE, 0);
90265353 167 o->gui_data = s;
9af4a244
JA
168 return &s->gopt;
169}
170
b6caa836 171static void gopt_combo_changed(GtkComboBox *box, gpointer data)
9af4a244 172{
b6caa836
JA
173 struct gopt_combo *c = (struct gopt_combo *) data;
174 struct fio_option *o = &fio_options[c->gopt.opt_index];
175
176 printf("combo %s changed\n", o->name);
177}
178
179static struct gopt_combo *__gopt_new_combo(struct fio_option *o, unsigned int idx)
180{
181 struct gopt_combo *c;
9af4a244 182 GtkWidget *label;
9af4a244 183
b6caa836 184 c = malloc(sizeof(*c));
a01a1bc5 185 memset(c, 0, sizeof(*c));
9af4a244 186
b6caa836 187 c->gopt.box = gtk_hbox_new(FALSE, 3);
e8b0e958
JA
188 if (!o->lname)
189 label = gtk_label_new(o->name);
190 else
191 label = gtk_label_new(o->lname);
9af4a244 192
b6caa836 193 c->combo = gtk_combo_box_new_text();
ec0218ff 194 gopt_mark_index(&c->gopt, idx);
b6caa836
JA
195 g_signal_connect(GTK_OBJECT(c->combo), "changed", G_CALLBACK(gopt_combo_changed), c);
196
e8b0e958
JA
197 gtk_box_pack_start(GTK_BOX(c->gopt.box), c->combo, FALSE, FALSE, 0);
198 gtk_box_pack_start(GTK_BOX(c->gopt.box), label, FALSE, FALSE, 0);
199
90265353 200 o->gui_data = c;
b6caa836 201 return c;
39f04336
JA
202}
203
b6caa836 204static struct gopt *gopt_new_combo_str(struct fio_option *o, const char *text, unsigned int idx)
39f04336
JA
205{
206 struct gopt_combo *combo;
207 struct value_pair *vp;
208 int i, active = 0;
209
b6caa836 210 combo = __gopt_new_combo(o, idx);
39f04336 211
9af4a244
JA
212 i = 0;
213 vp = &o->posval[0];
214 while (vp->ival) {
215 gtk_combo_box_append_text(GTK_COMBO_BOX(combo->combo), vp->ival);
216 if (o->def && !strcmp(vp->ival, o->def))
217 active = i;
39f04336
JA
218 if (text && !strcmp(vp->ival, text))
219 active = i;
9af4a244
JA
220 vp++;
221 i++;
222 }
223
224 gtk_combo_box_set_active(GTK_COMBO_BOX(combo->combo), active);
225 return &combo->gopt;
226}
227
b6caa836 228static struct gopt *gopt_new_combo_int(struct fio_option *o, unsigned int *ip, unsigned int idx)
9af4a244 229{
39f04336
JA
230 struct gopt_combo *combo;
231 struct value_pair *vp;
232 int i, active = 0;
233
b6caa836 234 combo = __gopt_new_combo(o, idx);
39f04336
JA
235
236 i = 0;
237 vp = &o->posval[0];
238 while (vp->ival) {
239 gtk_combo_box_append_text(GTK_COMBO_BOX(combo->combo), vp->ival);
240 if (ip && vp->oval == *ip)
241 active = i;
242 vp++;
243 i++;
244 }
245
246 gtk_combo_box_set_active(GTK_COMBO_BOX(combo->combo), active);
247 return &combo->gopt;
248}
249
7386d4ae
JA
250static struct gopt *gopt_new_str_multi(struct fio_option *o, unsigned int idx)
251{
252 struct gopt_str_multi *m;
253 struct value_pair *vp;
254 GtkWidget *frame, *hbox;
255 int i;
256
257 m = malloc(sizeof(*m));
a01a1bc5 258 memset(m, 0, sizeof(*m));
7386d4ae
JA
259 m->gopt.box = gtk_hbox_new(FALSE, 3);
260 gopt_mark_index(&m->gopt, idx);
261
262 if (!o->lname)
263 frame = gtk_frame_new(o->name);
264 else
265 frame = gtk_frame_new(o->lname);
266 gtk_box_pack_start(GTK_BOX(m->gopt.box), frame, FALSE, FALSE, 3);
267
268 hbox = gtk_hbox_new(FALSE, 3);
269 gtk_container_add(GTK_CONTAINER(frame), hbox);
270
271 i = 0;
272 vp = &o->posval[0];
273 while (vp->ival) {
274 m->checks[i] = gtk_check_button_new_with_label(vp->ival);
275 gtk_widget_set_tooltip_text(m->checks[i], vp->help);
276 gtk_box_pack_start(GTK_BOX(hbox), m->checks[i], FALSE, FALSE, 3);
277 vp++;
278 }
279
280 return &m->gopt;
281}
282
b6caa836
JA
283static void gopt_int_changed(GtkSpinButton *spin, gpointer data)
284{
285 struct gopt_int *i = (struct gopt_int *) data;
286 struct fio_option *o = &fio_options[i->gopt.opt_index];
90265353
JA
287 GtkAdjustment *adj;
288 int value, delta;
289
290 adj = gtk_spin_button_get_adjustment(spin);
291 value = gtk_adjustment_get_value(adj);
292 delta = value - i->lastval;
293 i->lastval = value;
294
295 if (o->inv_opt) {
296 struct gopt_int *i_inv = o->inv_opt->gui_data;
297 int cur_val;
298
a01a1bc5
JA
299 assert(o->type == o->inv_opt->type);
300
90265353
JA
301 /*
302 * Don't recourse into notify changes. Is there a better
303 * way than this? We essentially want to block the update
304 * signal while we perform the below set_value().
305 */
306 if (i_inv->in_change)
307 return;
308
309 i->in_change = 1;
310 cur_val = gtk_spin_button_get_value(GTK_SPIN_BUTTON(i_inv->spin));
311 cur_val -= delta;
312 gtk_spin_button_set_value(GTK_SPIN_BUTTON(i_inv->spin), cur_val);
313 i->in_change = 0;
314 }
b6caa836
JA
315}
316
317static struct gopt_int *__gopt_new_int(struct fio_option *o, unsigned long long *p,
318 unsigned int idx)
39f04336
JA
319{
320 unsigned long long defval;
9af4a244 321 struct gopt_int *i;
20eb06bd 322 guint maxval, interval;
9af4a244
JA
323 GtkWidget *label;
324
325 i = malloc(sizeof(*i));
a01a1bc5 326 memset(i, 0, sizeof(*i));
9af4a244 327 i->gopt.box = gtk_hbox_new(FALSE, 3);
e8b0e958
JA
328 if (!o->lname)
329 label = gtk_label_new(o->name);
330 else
331 label = gtk_label_new(o->lname);
9af4a244
JA
332
333 maxval = o->maxval;
334 if (!maxval)
39f04336 335 maxval = UINT_MAX;
9af4a244
JA
336
337 defval = 0;
39f04336
JA
338 if (p)
339 defval = *p;
340 else if (o->def) {
9af4a244
JA
341 long long val;
342
343 check_str_bytes(o->def, &val, NULL);
344 defval = val;
345 }
346
20eb06bd
JA
347 interval = 1.0;
348 if (o->interval)
349 interval = o->interval;
350
351 i->spin = gtk_spin_button_new_with_range(o->minval, maxval, interval);
ec0218ff 352 gopt_mark_index(&i->gopt, idx);
9af4a244
JA
353 gtk_spin_button_set_update_policy(GTK_SPIN_BUTTON(i->spin), GTK_UPDATE_IF_VALID);
354 gtk_spin_button_set_value(GTK_SPIN_BUTTON(i->spin), defval);
90265353 355 i->lastval = defval;
e8b0e958 356 g_signal_connect(G_OBJECT(i->spin), "value-changed", G_CALLBACK(gopt_int_changed), i);
9af4a244
JA
357
358 gtk_box_pack_start(GTK_BOX(i->gopt.box), i->spin, FALSE, FALSE, 0);
e8b0e958 359 gtk_box_pack_start(GTK_BOX(i->gopt.box), label, FALSE, FALSE, 0);
b6caa836 360
90265353 361 o->gui_data = i;
b6caa836 362 return i;
9af4a244
JA
363}
364
b6caa836 365static struct gopt *gopt_new_int(struct fio_option *o, unsigned int *ip, unsigned int idx)
39f04336
JA
366{
367 unsigned long long ullp;
b6caa836 368 struct gopt_int *i;
39f04336
JA
369
370 if (ip) {
371 ullp = *ip;
b6caa836
JA
372 i = __gopt_new_int(o, &ullp, idx);
373 } else
374 i = __gopt_new_int(o, NULL, idx);
375
376 return &i->gopt;
377}
39f04336 378
b6caa836
JA
379static struct gopt *gopt_new_ullong(struct fio_option *o, unsigned long long *p,
380 unsigned int idx)
381{
382 struct gopt_int *i;
383
384 i = __gopt_new_int(o, p, idx);
385 return &i->gopt;
39f04336
JA
386}
387
b6caa836 388static void gopt_bool_toggled(GtkToggleButton *button, gpointer data)
39f04336 389{
b6caa836
JA
390 struct gopt_bool *b = (struct gopt_bool *) data;
391 struct fio_option *o = &fio_options[b->gopt.opt_index];
392 gboolean set;
393
394 set = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(b->check));
a01a1bc5
JA
395
396 if (o->inv_opt) {
397 struct gopt_bool *b_inv = o->inv_opt->gui_data;
398
399 assert(o->type == o->inv_opt->type);
400
401 /*
402 * Don't recourse into notify changes. Is there a better
403 * way than this? We essentially want to block the update
404 * signal while we perform the below set_value().
405 */
406 if (b_inv->in_change)
407 return;
408
409 b->in_change = 1;
410 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(b_inv->check), !set);
411 b->in_change = 0;
412 }
413
b6caa836 414 gopt_set_children_visible(o, set);
39f04336
JA
415}
416
b6caa836 417static struct gopt *gopt_new_bool(struct fio_option *o, unsigned int *val, unsigned int idx)
9af4a244
JA
418{
419 struct gopt_bool *b;
420 GtkWidget *label;
421 int defstate = 0;
422
423 b = malloc(sizeof(*b));
a01a1bc5 424 memset(b, 0, sizeof(*b));
9af4a244 425 b->gopt.box = gtk_hbox_new(FALSE, 3);
e8b0e958
JA
426 if (!o->lname)
427 label = gtk_label_new(o->name);
428 else
429 label = gtk_label_new(o->lname);
9af4a244
JA
430
431 b->check = gtk_check_button_new();
ec0218ff 432 gopt_mark_index(&b->gopt, idx);
39f04336
JA
433 if (val)
434 defstate = *val;
435 else if (o->def && !strcmp(o->def, "1"))
9af4a244
JA
436 defstate = 1;
437
d872fb4c
JA
438 if (o->neg)
439 defstate = !defstate;
440
9af4a244 441 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(b->check), defstate);
b6caa836 442 g_signal_connect(G_OBJECT(b->check), "toggled", G_CALLBACK(gopt_bool_toggled), b);
9af4a244
JA
443
444 gtk_box_pack_start(GTK_BOX(b->gopt.box), b->check, FALSE, FALSE, 0);
e8b0e958 445 gtk_box_pack_start(GTK_BOX(b->gopt.box), label, FALSE, FALSE, 0);
90265353 446 o->gui_data = b;
9af4a244
JA
447 return &b->gopt;
448}
449
1da10c19
JA
450/*
451 * These are paired 0/1 and 2/3. 0/2 are min values, 1/3 are max values.
452 * If the max is made smaller than min, adjust min down.
453 * If the min is made larger than max, adjust the max.
454 */
455static void range_value_changed(GtkSpinButton *spin, gpointer data)
456{
457 struct gopt_range *r = (struct gopt_range *) data;
458 int changed = -1, i;
459 gint val, mval;
460
461 for (i = 0; i < GOPT_RANGE_SPIN; i++) {
462 if (GTK_SPIN_BUTTON(r->spins[i]) == spin) {
463 changed = i;
464 break;
465 }
466 }
467
468 assert(changed != -1);
469
470 /*
471 * Min changed
472 */
473 if (changed == 0 || changed == 2) {
474 GtkWidget *mspin = r->spins[changed + 1];
475
476 val = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(r->spins[changed]));
477 mval = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(mspin));
478 if (val > mval)
479 gtk_spin_button_set_value(GTK_SPIN_BUTTON(mspin), val);
480 } else {
481 GtkWidget *mspin = r->spins[changed - 1];
482
483 val = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(r->spins[changed]));
484 mval = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(mspin));
485 if (val < mval)
486 gtk_spin_button_set_value(GTK_SPIN_BUTTON(mspin), val);
487 }
488}
489
b6caa836
JA
490static struct gopt *gopt_new_int_range(struct fio_option *o, unsigned int **ip,
491 unsigned int idx)
9af4a244
JA
492{
493 struct gopt_range *r;
494 gint maxval, defval;
495 GtkWidget *label;
20eb06bd 496 guint interval;
9af4a244
JA
497 int i;
498
499 r = malloc(sizeof(*r));
a01a1bc5 500 memset(r, 0, sizeof(*r));
9af4a244 501 r->gopt.box = gtk_hbox_new(FALSE, 3);
ec0218ff 502 gopt_mark_index(&r->gopt, idx);
e8b0e958
JA
503 if (!o->lname)
504 label = gtk_label_new(o->name);
505 else
506 label = gtk_label_new(o->lname);
9af4a244
JA
507
508 maxval = o->maxval;
509 if (!maxval)
510 maxval = INT_MAX;
511
512 defval = 0;
513 if (o->def) {
514 long long val;
515
516 check_str_bytes(o->def, &val, NULL);
517 defval = val;
518 }
519
20eb06bd
JA
520 interval = 1.0;
521 if (o->interval)
522 interval = o->interval;
523
1da10c19 524 for (i = 0; i < GOPT_RANGE_SPIN; i++) {
20eb06bd 525 r->spins[i] = gtk_spin_button_new_with_range(o->minval, maxval, interval);
9af4a244 526 gtk_spin_button_set_update_policy(GTK_SPIN_BUTTON(r->spins[i]), GTK_UPDATE_IF_VALID);
39f04336
JA
527 if (ip)
528 gtk_spin_button_set_value(GTK_SPIN_BUTTON(r->spins[i]), *ip[i]);
529 else
530 gtk_spin_button_set_value(GTK_SPIN_BUTTON(r->spins[i]), defval);
9af4a244
JA
531
532 gtk_box_pack_start(GTK_BOX(r->gopt.box), r->spins[i], FALSE, FALSE, 0);
1da10c19 533 g_signal_connect(G_OBJECT(r->spins[i]), "value-changed", G_CALLBACK(range_value_changed), r);
9af4a244
JA
534 }
535
e8b0e958 536 gtk_box_pack_start(GTK_BOX(r->gopt.box), label, FALSE, FALSE, 0);
90265353 537 o->gui_data = r;
9af4a244
JA
538 return &r->gopt;
539}
540
541static void gopt_add_option(GtkWidget *hbox, struct fio_option *o,
789f4ccd 542 unsigned int opt_index, struct thread_options *to)
9af4a244
JA
543{
544 struct gopt *go = NULL;
545
546 switch (o->type) {
39f04336
JA
547 case FIO_OPT_STR_VAL:
548 case FIO_OPT_STR_VAL_TIME: {
549 unsigned long long *ullp = NULL;
550
551 if (o->off1)
552 ullp = td_var(to, o->off1);
789f4ccd 553
b6caa836 554 go = gopt_new_ullong(o, ullp, opt_index);
9af4a244 555 break;
789f4ccd 556 }
39f04336
JA
557 case FIO_OPT_INT: {
558 unsigned int *ip = NULL;
559
560 if (o->off1)
561 ip = td_var(to, o->off1);
562
b6caa836 563 go = gopt_new_int(o, ip, opt_index);
9af4a244 564 break;
39f04336 565 }
9af4a244 566 case FIO_OPT_STR_SET:
39f04336
JA
567 case FIO_OPT_BOOL: {
568 unsigned int *ip = NULL;
569
570 if (o->off1)
571 ip = td_var(to, o->off1);
572
b6caa836 573 go = gopt_new_bool(o, ip, opt_index);
39f04336
JA
574 break;
575 }
576 case FIO_OPT_STR: {
d872fb4c
JA
577 if (o->posval[0].ival) {
578 unsigned int *ip = NULL;
39f04336 579
d872fb4c
JA
580 if (o->off1)
581 ip = td_var(to, o->off1);
582
583 go = gopt_new_combo_int(o, ip, opt_index);
584 } else {
585 /* TODO: usually ->cb, or unsigned int pointer */
586 go = gopt_new_str_store(o, NULL, opt_index);
587 }
39f04336 588
9af4a244 589 break;
39f04336
JA
590 }
591 case FIO_OPT_STR_STORE: {
592 char *text = NULL;
593
d3944493 594 if (o->off1) {
39f04336
JA
595 char **p = td_var(to, o->off1);
596 text = *p;
597 }
598
9af4a244 599 if (!o->posval[0].ival) {
b6caa836 600 go = gopt_new_str_store(o, text, opt_index);
9af4a244
JA
601 break;
602 }
39f04336 603
b6caa836 604 go = gopt_new_combo_str(o, text, opt_index);
39f04336
JA
605 break;
606 }
9af4a244 607 case FIO_OPT_STR_MULTI:
7386d4ae 608 go = gopt_new_str_multi(o, opt_index);
9af4a244 609 break;
39f04336
JA
610 case FIO_OPT_RANGE: {
611 unsigned int *ip[4] = { td_var(to, o->off1),
612 td_var(to, o->off2),
613 td_var(to, o->off3),
614 td_var(to, o->off4) };
615
b6caa836 616 go = gopt_new_int_range(o, ip, opt_index);
9af4a244 617 break;
39f04336 618 }
9af4a244
JA
619 /* still need to handle this one */
620 case FIO_OPT_FLOAT_LIST:
621 break;
622 case FIO_OPT_DEPRECATED:
623 break;
624 default:
625 printf("ignore type %u\n", o->type);
626 break;
627 }
628
629 if (go) {
e8b0e958
JA
630 GtkWidget *dest;
631
9af4a244
JA
632 if (o->help)
633 gtk_widget_set_tooltip_text(go->box, o->help);
e8b0e958 634
9af4a244 635 go->opt_type = o->type;
e8b0e958
JA
636
637 dest = gopt_get_group_frame(hbox, o->group);
638 if (!dest)
639 gtk_box_pack_start(GTK_BOX(hbox), go->box, FALSE, FALSE, 5);
640 else
641 gtk_box_pack_start(GTK_BOX(dest), go->box, FALSE, FALSE, 5);
9af4a244
JA
642 }
643}
644
789f4ccd 645static void gopt_add_options(GtkWidget **vboxes, struct thread_options *to)
9af4a244
JA
646{
647 GtkWidget *hbox = NULL;
648 int i;
649
90265353
JA
650 /*
651 * First add all options
652 */
9af4a244
JA
653 for (i = 0; fio_options[i].name; i++) {
654 struct fio_option *o = &fio_options[i];
655 unsigned int mask = o->category;
656 struct opt_group *og;
657
658 while ((og = opt_group_from_mask(&mask)) != NULL) {
659 GtkWidget *vbox = vboxes[ffz(~og->mask)];
660
661 hbox = gtk_hbox_new(FALSE, 3);
662 gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 5);
789f4ccd 663 gopt_add_option(hbox, o, i, to);
9af4a244
JA
664 }
665 }
666}
667
668static GtkWidget *gopt_add_group_tab(GtkWidget *notebook, struct opt_group *og)
669{
670 GtkWidget *box, *vbox, *scroll;
671
672 scroll = gtk_scrolled_window_new(NULL, NULL);
673 gtk_container_set_border_width(GTK_CONTAINER(scroll), 5);
674 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
675
676 vbox = gtk_vbox_new(FALSE, 3);
677 box = gtk_hbox_new(FALSE, 0);
678 gtk_box_pack_start(GTK_BOX(vbox), box, FALSE, FALSE, 5);
679 gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(scroll), vbox);
680 gtk_notebook_append_page(GTK_NOTEBOOK(notebook), scroll, gtk_label_new(og->name));
681
682 return vbox;
683}
684
685static void gopt_add_group_tabs(GtkWidget *notebook, GtkWidget **vbox)
686{
687 struct opt_group *og;
ec0218ff 688 unsigned int i;
9af4a244 689
ec0218ff 690 i = 0;
9af4a244
JA
691 do {
692 unsigned int mask = (1U << i);
693
694 og = opt_group_from_mask(&mask);
695 if (!og)
696 break;
697 vbox[i] = gopt_add_group_tab(notebook, og);
698 i++;
699 } while (1);
700}
701
789f4ccd 702void gopt_get_options_window(GtkWidget *window, struct thread_options *o)
9af4a244
JA
703{
704 GtkWidget *dialog, *notebook;
e8b0e958 705 GtkWidget *vboxes[__FIO_OPT_C_NR];
9af4a244
JA
706
707 dialog = gtk_dialog_new_with_buttons("Fio options",
708 GTK_WINDOW(window), GTK_DIALOG_DESTROY_WITH_PARENT,
709 GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
710 GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT, NULL);
711
712 gtk_widget_set_size_request(GTK_WIDGET(dialog), 1024, 768);
713
714 notebook = gtk_notebook_new();
715 gtk_notebook_set_scrollable(GTK_NOTEBOOK(notebook), 1);
716 gtk_notebook_popup_enable(GTK_NOTEBOOK(notebook));
717 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), notebook, TRUE, TRUE, 5);
718
719 gopt_add_group_tabs(notebook, vboxes);
720
789f4ccd 721 gopt_add_options(vboxes, o);
9af4a244
JA
722
723 gtk_widget_show_all(dialog);
724
725 gtk_dialog_run(GTK_DIALOG(dialog));
726
727 gtk_widget_destroy(dialog);
728}