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