gfio: demo of how to inherit option values into edit window
[fio.git] / goptions.c
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
14 struct gopt {
15         GtkWidget *box;
16         unsigned int opt_index;
17         unsigned int opt_type;
18 };
19
20 struct gopt_combo {
21         struct gopt gopt;
22         GtkWidget *combo;
23 };
24
25 struct gopt_int {
26         struct gopt gopt;
27         GtkWidget *spin;
28 };
29
30 struct gopt_bool {
31         struct gopt gopt;
32         GtkWidget *check;
33 };
34
35 struct gopt_str {
36         struct gopt gopt;
37         GtkWidget *entry;
38 };
39
40 struct gopt_range {
41         struct gopt gopt;
42         GtkWidget *spins[4];
43 };
44
45 static struct gopt *gopt_new_str_store(struct fio_option *o, const char *text)
46 {
47         struct gopt_str *s;
48         GtkWidget *label;
49
50         s = malloc(sizeof(*s));
51
52         s->gopt.box = gtk_hbox_new(FALSE, 3);
53         label = gtk_label_new(o->name);
54         gtk_box_pack_start(GTK_BOX(s->gopt.box), label, FALSE, FALSE, 0);
55
56         s->entry = gtk_entry_new();
57         if (text)
58                 gtk_entry_set_text(GTK_ENTRY(s->entry), text);
59         gtk_entry_set_editable(GTK_ENTRY(s->entry), 1);
60
61         if (o->def)
62                 gtk_entry_set_text(GTK_ENTRY(s->entry), o->def);
63
64         gtk_box_pack_start(GTK_BOX(s->gopt.box), s->entry, FALSE, FALSE, 0);
65         return &s->gopt;
66 }
67
68 static struct gopt *gopt_new_combo(struct fio_option *o)
69 {
70         struct gopt_combo *combo;
71         struct value_pair *vp;
72         GtkWidget *label;
73         int i, active = 0;
74
75         combo = malloc(sizeof(*combo));
76
77         combo->gopt.box = gtk_hbox_new(FALSE, 3);
78         label = gtk_label_new(o->name);
79         gtk_box_pack_start(GTK_BOX(combo->gopt.box), label, FALSE, FALSE, 0);
80
81         combo->combo = gtk_combo_box_new_text();
82         gtk_box_pack_start(GTK_BOX(combo->gopt.box), combo->combo, FALSE, FALSE, 0);
83
84         i = 0;
85         vp = &o->posval[0];
86         while (vp->ival) {
87                 gtk_combo_box_append_text(GTK_COMBO_BOX(combo->combo), vp->ival);
88                 if (o->def && !strcmp(vp->ival, o->def))
89                         active = i;
90                 vp++;
91                 i++;
92         }
93
94         gtk_combo_box_set_active(GTK_COMBO_BOX(combo->combo), active);
95         return &combo->gopt;
96 }
97
98 static struct gopt *gopt_new_int(struct fio_option *o)
99 {
100         struct gopt_int *i;
101         gint maxval, defval;
102         GtkWidget *label;
103
104         i = malloc(sizeof(*i));
105         i->gopt.box = gtk_hbox_new(FALSE, 3);
106         label = gtk_label_new(o->name);
107         gtk_box_pack_start(GTK_BOX(i->gopt.box), label, FALSE, FALSE, 0);
108
109         maxval = o->maxval;
110         if (!maxval)
111                 maxval = INT_MAX;
112
113         defval = 0;
114         if (o->def) {
115                 long long val;
116
117                 check_str_bytes(o->def, &val, NULL);
118                 defval = val;
119         }
120
121         i->spin = gtk_spin_button_new_with_range(o->minval, maxval, 1.0);
122         gtk_spin_button_set_update_policy(GTK_SPIN_BUTTON(i->spin), GTK_UPDATE_IF_VALID);
123         gtk_spin_button_set_value(GTK_SPIN_BUTTON(i->spin), defval);
124
125         gtk_box_pack_start(GTK_BOX(i->gopt.box), i->spin, FALSE, FALSE, 0);
126         return &i->gopt;
127 }
128
129 static struct gopt *gopt_new_bool(struct fio_option *o)
130 {
131         struct gopt_bool *b;
132         GtkWidget *label;
133         int defstate = 0;
134
135         b = malloc(sizeof(*b));
136         b->gopt.box = gtk_hbox_new(FALSE, 3);
137         label = gtk_label_new(o->name);
138         gtk_box_pack_start(GTK_BOX(b->gopt.box), label, FALSE, FALSE, 0);
139
140         b->check = gtk_check_button_new();
141         if (o->def && !strcmp(o->def, "1"))
142                 defstate = 1;
143
144         gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(b->check), defstate);
145
146         gtk_box_pack_start(GTK_BOX(b->gopt.box), b->check, FALSE, FALSE, 0);
147         return &b->gopt;
148 }
149
150 static struct gopt *gopt_new_int_range(struct fio_option *o)
151 {
152         struct gopt_range *r;
153         gint maxval, defval;
154         GtkWidget *label;
155         int i;
156
157         r = malloc(sizeof(*r));
158         r->gopt.box = gtk_hbox_new(FALSE, 3);
159         label = gtk_label_new(o->name);
160         gtk_box_pack_start(GTK_BOX(r->gopt.box), label, FALSE, FALSE, 0);
161
162         maxval = o->maxval;
163         if (!maxval)
164                 maxval = INT_MAX;
165
166         defval = 0;
167         if (o->def) {
168                 long long val;
169
170                 check_str_bytes(o->def, &val, NULL);
171                 defval = val;
172         }
173
174         for (i = 0; i < 4; i++) {
175                 r->spins[i] = gtk_spin_button_new_with_range(o->minval, maxval, 1.0);
176                 gtk_spin_button_set_update_policy(GTK_SPIN_BUTTON(r->spins[i]), GTK_UPDATE_IF_VALID);
177                 gtk_spin_button_set_value(GTK_SPIN_BUTTON(r->spins[i]), defval);
178
179                 gtk_box_pack_start(GTK_BOX(r->gopt.box), r->spins[i], FALSE, FALSE, 0);
180         }
181
182         return &r->gopt;
183 }
184
185 static void gopt_add_option(GtkWidget *hbox, struct fio_option *o,
186                             unsigned int opt_index, struct thread_options *to)
187 {
188         struct gopt *go = NULL;
189
190         switch (o->type) {
191         case FIO_OPT_STR_STORE: {
192                 char **p = td_var(to, o->off1);
193
194                 go = gopt_new_str_store(o, *p);
195                 break;
196                 }
197         case FIO_OPT_STR_VAL:
198         case FIO_OPT_STR_VAL_TIME:
199         case FIO_OPT_INT:
200                 go = gopt_new_int(o);
201                 break;
202         case FIO_OPT_STR_SET:
203         case FIO_OPT_BOOL:
204                 go = gopt_new_bool(o);
205                 break;
206         case FIO_OPT_STR:
207                 if (!o->posval[0].ival) {
208                         go = gopt_new_str_store(o, NULL);
209                         break;
210                 }
211         case FIO_OPT_STR_MULTI:
212                 go = gopt_new_combo(o);
213                 break;
214         case FIO_OPT_RANGE:
215                 go = gopt_new_int_range(o);
216                 break;
217         /* still need to handle this one */
218         case FIO_OPT_FLOAT_LIST:
219                 break;
220         case FIO_OPT_DEPRECATED:
221                 break;
222         default:
223                 printf("ignore type %u\n", o->type);
224                 break;
225         }
226
227         if (go) {
228                 if (o->help)
229                         gtk_widget_set_tooltip_text(go->box, o->help);
230         
231                 gtk_box_pack_start(GTK_BOX(hbox), go->box, FALSE, FALSE, 5);
232                 go->opt_index = opt_index;
233                 go->opt_type = o->type;
234         }
235 }
236
237 static void gopt_add_options(GtkWidget **vboxes, struct thread_options *to)
238 {
239         GtkWidget *hbox = NULL;
240         int i;
241
242         for (i = 0; fio_options[i].name; i++) {
243                 struct fio_option *o = &fio_options[i];
244                 unsigned int mask = o->category;
245                 struct opt_group *og;
246
247                 while ((og = opt_group_from_mask(&mask)) != NULL) {
248                         GtkWidget *vbox = vboxes[ffz(~og->mask)];
249
250                         hbox = gtk_hbox_new(FALSE, 3);
251                         gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 5);
252                         gopt_add_option(hbox, o, i, to);
253                 }
254         }
255 }
256
257 static GtkWidget *gopt_add_group_tab(GtkWidget *notebook, struct opt_group *og)
258 {
259         GtkWidget *box, *vbox, *scroll;
260
261         scroll = gtk_scrolled_window_new(NULL, NULL);
262         gtk_container_set_border_width(GTK_CONTAINER(scroll), 5);
263         gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
264
265         vbox = gtk_vbox_new(FALSE, 3);
266         box = gtk_hbox_new(FALSE, 0);
267         gtk_box_pack_start(GTK_BOX(vbox), box, FALSE, FALSE, 5);
268         gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(scroll), vbox);
269         gtk_notebook_append_page(GTK_NOTEBOOK(notebook), scroll, gtk_label_new(og->name));
270
271         return vbox;
272 }
273
274 static void gopt_add_group_tabs(GtkWidget *notebook, GtkWidget **vbox)
275 {
276         struct opt_group *og;
277         unsigned int i = 0;
278
279         do {
280                 unsigned int mask = (1U << i);
281
282                 og = opt_group_from_mask(&mask);
283                 if (!og)
284                         break;
285                 vbox[i] = gopt_add_group_tab(notebook, og);
286                 i++;
287         } while (1);
288 }
289
290 void gopt_get_options_window(GtkWidget *window, struct thread_options *o)
291 {
292         GtkWidget *dialog, *notebook;
293         GtkWidget *vboxes[__FIO_OPT_G_NR];
294
295         dialog = gtk_dialog_new_with_buttons("Fio options",
296                         GTK_WINDOW(window), GTK_DIALOG_DESTROY_WITH_PARENT,
297                         GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
298                         GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT, NULL);
299
300         gtk_widget_set_size_request(GTK_WIDGET(dialog), 1024, 768);
301
302         notebook = gtk_notebook_new();
303         gtk_notebook_set_scrollable(GTK_NOTEBOOK(notebook), 1);
304         gtk_notebook_popup_enable(GTK_NOTEBOOK(notebook));
305         gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), notebook, TRUE, TRUE, 5);
306
307         gopt_add_group_tabs(notebook, vboxes);
308
309         gopt_add_options(vboxes, o);
310
311         gtk_widget_show_all(dialog);
312
313         gtk_dialog_run(GTK_DIALOG(dialog));
314
315         gtk_widget_destroy(dialog);
316 }