add existing code (build system, libs, initial mizucp code)
[mizunara.git] / ui / gtk / toolbar.c
1 /*
2  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3  *
4  * Copyright 2017 Olaf Wintermann. All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions are met:
8  *
9  *   1. Redistributions of source code must retain the above copyright
10  *      notice, this list of conditions and the following disclaimer.
11  *
12  *   2. Redistributions in binary form must reproduce the above copyright
13  *      notice, this list of conditions and the following disclaimer in the
14  *      documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
20  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26  * POSSIBILITY OF SUCH DAMAGE.
27  */
28
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <string.h>
32
33 #include "toolbar.h"
34 #include "button.h"
35 #include "image.h"
36 #include "tree.h"
37 #include <ucx/mempool.h>
38 #include "../common/context.h"
39
40 static UcxMap *toolbar_items;
41 static UcxList *defaults;
42
43 void ui_toolbar_init() {
44     toolbar_items = ucx_map_new(16);
45 }
46
47 void ui_toolitem(char *name, char *label, ui_callback f, void *udata) {
48     ui_toolitem_img(name, label, NULL, f, udata);
49 }
50
51 void ui_toolitem_st(char *name, char *stockid, ui_callback f, void *userdata) {
52     ui_toolitem_stgr(name, stockid, f, userdata, -1);
53 }
54
55 void ui_toolitem_sti(char *name, char *stockid, ui_callback f, void *userdata) {
56     ui_toolitem_stgri(name, stockid, f, userdata, -1);
57 }
58
59 void ui_toolitem_stgr(char *name, char *stockid, ui_callback f, void *userdata, ...) {
60     va_list ap;
61     va_start(ap, userdata);
62     ui_toolitem_vstgr(name, stockid, 0, f, userdata, ap);
63     va_end(ap);
64 }
65
66 void ui_toolitem_stgri(char *name, char *stockid, ui_callback f, void *userdata, ...) {
67     va_list ap;
68     va_start(ap, userdata);
69     ui_toolitem_vstgr(name, stockid, 1, f, userdata, ap);
70     va_end(ap);
71 }
72
73 void ui_toolitem_img(char *name, char *label, char *img, ui_callback f, void *udata) {
74     UiToolItem *item = malloc(sizeof(UiToolItem));
75     item->item.add_to = (ui_toolbar_add_f)add_toolitem_widget;
76     item->label = label;
77     item->image = img;
78     item->callback = f;
79     item->userdata = udata;
80     item->isimportant = 0;
81     item->groups = NULL;
82     
83     ucx_map_cstr_put(toolbar_items, name, item);
84 }
85
86 void ui_toolitem_vstgr(
87         char *name,
88         char *stockid,
89         int isimportant,
90         ui_callback f,
91         void *userdata,
92         va_list ap)
93 {
94     UiStToolItem *item = malloc(sizeof(UiStToolItem));
95     item->item.add_to = (ui_toolbar_add_f)add_toolitem_st_widget;
96     item->stockid = stockid;
97     item->callback = f;
98     item->userdata = userdata;
99     item->groups = NULL;
100     item->isimportant = isimportant;
101     
102     // add groups
103     int group;
104     while((group = va_arg(ap, int)) != -1) {
105         item->groups = ucx_list_append(item->groups, (void*)(intptr_t)group);
106     }
107     
108     ucx_map_cstr_put(toolbar_items, name, item);
109 }
110
111 void ui_toolitem_toggle(const char *name, const char *label, const char *img, UiInteger *i) {
112     UiToggleToolItem *item = malloc(sizeof(UiToggleToolItem));
113     item->item.add_to = (ui_toolbar_add_f)add_toolitem_toggle_widget;
114     item->label = label;
115     item->image = img;
116     item->stockid = NULL;
117     item->groups = NULL;
118     item->isimportant = 0;
119     item->value = i;
120     item->var = NULL;
121     
122     ucx_map_cstr_put(toolbar_items, name, item);
123 }
124
125 void ui_toolitem_toggle_st(const char *name, const char *stockid, UiInteger *i) {
126     UiToggleToolItem *item = malloc(sizeof(UiToggleToolItem));
127     item->item.add_to = (ui_toolbar_add_f)add_toolitem_toggle_widget;
128     item->label = NULL;
129     item->image = NULL;
130     item->stockid = stockid;
131     item->groups = NULL;
132     item->isimportant = 0;
133     item->value = i;
134     item->var = NULL;
135     
136     ucx_map_cstr_put(toolbar_items, name, item);
137 }
138
139 void ui_toolitem_toggle_nv(const char *name, const char *label, const char *img, const char *intvar) {
140     UiToggleToolItem *item = malloc(sizeof(UiToggleToolItem));
141     item->item.add_to = (ui_toolbar_add_f)add_toolitem_toggle_widget;
142     item->label = label;
143     item->image = img;
144     item->stockid = NULL;
145     item->groups = NULL;
146     item->isimportant = 0;
147     item->value = NULL;
148     item->var = intvar;
149     
150     ucx_map_cstr_put(toolbar_items, name, item);
151 }
152
153 void ui_toolitem_toggle_stnv(const char *name, const char *stockid, const char *intvar) {
154     UiToggleToolItem *item = malloc(sizeof(UiToggleToolItem));
155     item->item.add_to = (ui_toolbar_add_f)add_toolitem_toggle_widget;
156     item->label = NULL;
157     item->image = NULL;
158     item->stockid = stockid;
159     item->groups = NULL;
160     item->isimportant = 0;
161     item->value = NULL;
162     item->var = intvar;
163     
164     ucx_map_cstr_put(toolbar_items, name, item);
165 }
166
167
168 void ui_toolbar_combobox(
169         char *name,
170         UiList *list,
171         ui_getvaluefunc getvalue,
172         ui_callback f,
173         void *udata)
174 {
175     UiToolbarComboBox *cb = malloc(sizeof(UiToolbarComboBox));
176     cb->item.add_to = (ui_toolbar_add_f)add_toolbar_combobox;
177     UiVar *var = malloc(sizeof(UiVar));
178     var->value = list;
179     var->type = UI_VAR_SPECIAL;
180     var->from = NULL;
181     var->from_ctx = NULL;
182     cb->var = var;
183     cb->getvalue = getvalue;
184     cb->callback = f;
185     cb->userdata = udata;
186     
187     ucx_map_cstr_put(toolbar_items, name, cb);
188 }
189
190 void ui_toolbar_combobox_str(
191         char *name,
192         UiList *list,
193         ui_callback f,
194         void *udata)
195 {
196     ui_toolbar_combobox(name, list, ui_strmodel_getvalue, f, udata);
197 }
198
199 void ui_toolbar_combobox_nv(
200         char *name,
201         char *listname,
202         ui_getvaluefunc getvalue,
203         ui_callback f,
204         void *udata)
205 {
206     UiToolbarComboBoxNV *cb = malloc(sizeof(UiToolbarComboBoxNV));
207     cb->item.add_to = (ui_toolbar_add_f)add_toolbar_combobox_nv;  
208     cb->listname = listname;
209     cb->getvalue = getvalue;
210     cb->callback = f;
211     cb->userdata = udata;
212     
213     ucx_map_cstr_put(toolbar_items, name, cb);
214 }
215
216
217 void ui_toolbar_add_default(char *name) {
218     char *s = strdup(name);
219     defaults = ucx_list_append(defaults, s);
220 }
221
222 GtkWidget* ui_create_toolbar(UiObject *obj) {
223     if(!defaults) {
224         return NULL;
225     }
226     
227     GtkWidget *toolbar = gtk_toolbar_new();
228 #ifdef UI_GTK3
229     gtk_style_context_add_class(
230             gtk_widget_get_style_context(toolbar),
231             GTK_STYLE_CLASS_PRIMARY_TOOLBAR);
232 #endif
233     
234     GtkToolbar *tb = GTK_TOOLBAR(toolbar);
235     UCX_FOREACH(elm, defaults) {
236         UiToolItemI *item = ucx_map_cstr_get(toolbar_items, elm->data);
237         if(item) {
238             item->add_to(tb, item, obj);
239         } else if(!strcmp(elm->data, "@separator")) {
240             gtk_toolbar_insert(tb, gtk_separator_tool_item_new(), -1);
241         } else {
242             fprintf(stderr, "UI Error: Unknown toolbar item: %s\n", elm->data);
243         }
244     }
245     
246     return toolbar;
247 }
248
249 void add_toolitem_widget(GtkToolbar *tb, UiToolItem *item, UiObject *obj) {
250     GtkToolItem *button = gtk_tool_button_new(NULL, item->label);
251     gtk_tool_item_set_homogeneous(button, FALSE);
252     if(item->image) {
253         GdkPixbuf *pixbuf = ui_get_image(item->image);
254         GtkWidget *image = gtk_image_new_from_pixbuf(pixbuf);
255         gtk_tool_button_set_icon_widget(GTK_TOOL_BUTTON(button), image);
256     } else {
257         gtk_tool_item_set_is_important(button, TRUE);
258     }
259     
260     if(item->callback) {
261         UiEventData *event = ucx_mempool_malloc(
262                 obj->ctx->mempool,
263                 sizeof(UiEventData));
264         event->obj = obj;
265         event->userdata = item->userdata;
266         event->callback = item->callback;
267         
268         g_signal_connect(
269                 button,
270                 "clicked",
271                 G_CALLBACK(ui_button_clicked),
272                 event);
273     }
274     
275     gtk_toolbar_insert(tb, button, -1);
276     
277     if(item->groups) {
278         uic_add_group_widget(obj->ctx, button, (ui_enablefunc)ui_set_enabled, item->groups);
279     }
280 }
281
282 void add_toolitem_st_widget(GtkToolbar *tb, UiStToolItem *item, UiObject *obj) {
283     GtkToolItem *button = gtk_tool_button_new_from_stock(item->stockid);
284     gtk_tool_item_set_homogeneous(button, FALSE);
285     if(item->isimportant) {
286         gtk_tool_item_set_is_important(button, TRUE);
287     }
288     
289     if(item->callback) {
290         UiEventData *event = ucx_mempool_malloc(
291                 obj->ctx->mempool,
292                 sizeof(UiEventData));
293         event->obj = obj;
294         event->userdata = item->userdata;
295         event->callback = item->callback;
296         
297         g_signal_connect(
298                 button,
299                 "clicked",
300                 G_CALLBACK(ui_button_clicked),
301                 event);
302     }
303     
304     gtk_toolbar_insert(tb, button, -1);
305     
306     if(item->groups) {
307         uic_add_group_widget(obj->ctx, button, (ui_enablefunc)ui_set_enabled, item->groups);
308     }
309 }
310
311 void add_toolitem_toggle_widget(GtkToolbar *tb, UiToggleToolItem *item, UiObject *obj) {
312     GtkToolItem *button;
313     if(item->stockid) {
314         button = gtk_toggle_tool_button_new_from_stock(item->stockid);
315     } else {
316         button = gtk_toggle_tool_button_new();
317         gtk_tool_item_set_homogeneous(button, FALSE);
318         if(item->label) {
319             gtk_tool_button_set_label(GTK_TOOL_BUTTON(button), item->label);
320         }
321         if(item->image) {
322             GdkPixbuf *pixbuf = ui_get_image(item->image);
323             GtkWidget *image = gtk_image_new_from_pixbuf(pixbuf);
324             gtk_tool_button_set_icon_widget(GTK_TOOL_BUTTON(button), image);
325         }    
326     }
327     
328     UiVar *var;
329     if(item->value) {
330         var = malloc(sizeof(UiVar));
331         var->value = item->value;
332         var->type = UI_VAR_SPECIAL;
333         var->from = NULL;
334         var->from_ctx = NULL;
335     } else {
336         var = uic_create_var(obj->ctx, item->var, UI_VAR_INTEGER);
337     }
338     
339     if(var->value) {
340         UiInteger *i = var->value;
341         i->get = ui_tool_toggle_button_get;
342         i->set = ui_tool_toggle_button_set;
343         i->obj = button;
344         
345         if(i->value != 0) {
346             gtk_toggle_tool_button_set_active(GTK_TOGGLE_TOOL_BUTTON(button), TRUE);
347         }
348     }
349     
350     // register event
351     // the event func will call the UiInteger observer callbacks
352     UiEventData *event = ucx_mempool_malloc(
353             obj->ctx->mempool,
354             sizeof(UiEventData));
355     event->obj = obj;
356     event->userdata = var;
357     event->callback = NULL;
358
359     g_signal_connect(
360             button,
361             "toggled",
362             G_CALLBACK(ui_tool_button_toggled),
363             event);
364     
365     // add item to toolbar
366     gtk_toolbar_insert(tb, button, -1);
367     
368     if(item->groups) {
369         uic_add_group_widget(obj->ctx, button, (ui_enablefunc)ui_set_enabled, item->groups);
370     }
371 }
372
373 void ui_tool_button_toggled(GtkToggleToolButton *widget, UiEventData *event) {
374     UiEvent e;
375     e.obj = event->obj;
376     e.window = event->obj->window;
377     e.document = event->obj->ctx->document;
378     e.eventdata = NULL;
379     e.intval = gtk_toggle_tool_button_get_active(widget);
380     
381     UiVar *var = event->userdata;
382     UiInteger *i = var->value;
383     
384     ui_notify_evt(i->observers, &e);
385 }
386
387 int64_t ui_tool_toggle_button_get(UiInteger *integer) {
388     integer->value = gtk_toggle_tool_button_get_active(GTK_TOGGLE_TOOL_BUTTON(integer->obj));
389     return integer->value;
390 }
391
392 void ui_tool_toggle_button_set(UiInteger *integer, int64_t value) {
393     gboolean s = value != 0 ? TRUE : FALSE;
394     gtk_toggle_tool_button_set_active(GTK_TOGGLE_TOOL_BUTTON(integer->obj), s);
395     integer->value = s;
396 }
397
398 void add_toolbar_combobox(GtkToolbar *tb, UiToolbarComboBox *cb, UiObject *obj) {
399     UiModel *modelinfo = ui_model(obj->ctx, UI_STRING, "", -1);
400     modelinfo->getvalue = cb->getvalue;
401     UiListModel *model = ui_list_model_new(obj, cb->var, modelinfo);
402     
403     GtkWidget *combobox = ui_create_combobox(obj, model, cb->callback, cb->userdata);
404     GtkToolItem *item = gtk_tool_item_new();
405     gtk_container_add(GTK_CONTAINER(item), combobox);
406     gtk_toolbar_insert(tb, item, -1);
407 }
408
409 void add_toolbar_combobox_nv(GtkToolbar *tb, UiToolbarComboBoxNV *cb, UiObject *obj) {
410     UiVar *var = uic_create_var(obj->ctx, cb->listname, UI_VAR_LIST);
411     if(var) {
412         UiModel *modelinfo = ui_model(obj->ctx, UI_STRING, "", -1);
413         modelinfo->getvalue = cb->getvalue;
414         UiListModel *model = ui_list_model_new(obj, var, modelinfo);
415         
416         GtkWidget *combobox = ui_create_combobox(obj, model, cb->callback, cb->userdata);
417         GtkToolItem *item = gtk_tool_item_new();
418         gtk_container_add(GTK_CONTAINER(item), combobox);
419         gtk_toolbar_insert(tb, item, -1);
420     }
421 }
422