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