UNIXworkcode

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 "menu.h" 35 #include "button.h" 36 #include "icon.h" 37 #include "list.h" 38 #include <cx/mempool.h> 39 #include <cx/hash_map.h> 40 #include <cx/linked_list.h> 41 #include <cx/array_list.h> 42 #include "../common/context.h" 43 44 45 #if UI_GTK2 || UI_GTK3 46 47 GtkWidget* ui_create_toolbar(UiObject *obj) { 48 GtkWidget *toolbar = gtk_toolbar_new(); 49 #ifdef UI_GTK3 50 gtk_style_context_add_class( 51 gtk_widget_get_style_context(toolbar), 52 GTK_STYLE_CLASS_PRIMARY_TOOLBAR); 53 #endif 54 55 CxMap *items = uic_get_toolbar_items(); 56 CxList *left_defaults = uic_get_toolbar_defaults(UI_TOOLBAR_LEFT); 57 CxList *center_defaults = uic_get_toolbar_defaults(UI_TOOLBAR_CENTER); 58 CxList *right_defaults = uic_get_toolbar_defaults(UI_TOOLBAR_RIGHT); 59 60 ui_toolbar_add_items(obj, toolbar, items, left_defaults); 61 ui_toolbar_add_items(obj, toolbar, items, center_defaults); 62 ui_toolbar_add_items(obj, toolbar, items, right_defaults); 63 64 /* 65 GtkToolbar *tb = GTK_TOOLBAR(toolbar); 66 CxIterator i = cxListIterator(defaults); 67 cx_foreach(char *, def, i) { 68 UiToolItemI *item = cxMapGet(toolbar_items, def); 69 if(item) { 70 item->add_to(tb, item, obj); 71 } else if(!strcmp(def, "@separator")) { 72 gtk_toolbar_insert(tb, gtk_separator_tool_item_new(), -1); 73 } else { 74 fprintf(stderr, "UI Error: Unknown toolbar item: %s\n", def); 75 } 76 } 77 */ 78 79 return toolbar; 80 } 81 82 static void create_item(UiObject *obj, GtkWidget *toolbar, UiToolbarItemI *i) { 83 GtkToolbar *tb = GTK_TOOLBAR(toolbar); 84 switch(i->type) { 85 case UI_TOOLBAR_ITEM: { 86 add_toolitem_widget(tb, (UiToolbarItem*)i, obj); 87 break; 88 } 89 case UI_TOOLBAR_TOGGLEITEM: { 90 add_toolitem_toggle_widget(tb, (UiToolbarToggleItem*)i, obj); 91 break; 92 } 93 case UI_TOOLBAR_MENU: { 94 add_toolitem_menu_widget(tb, (UiToolbarMenuItem*)i, obj); 95 break; 96 } 97 default: fprintf(stderr, "toolbar item type unimplemented: %d\n", (int)i->type); 98 } 99 } 100 101 void ui_toolbar_add_items(UiObject *obj, GtkWidget *toolbar, CxMap *items, CxList *defaults) { 102 // add pre-configured items 103 CxIterator i = cxListIterator(defaults); 104 cx_foreach(char*, def, i) { 105 UiToolbarItemI* item = uic_toolbar_get_item(def); 106 if (!item) { 107 fprintf(stderr, "unknown toolbar item: %s\n", def); 108 continue; 109 } 110 create_item(obj, toolbar, item); 111 } 112 } 113 114 static void set_toolbutton_icon(GtkToolItem *item, const char *icon_name) { 115 #if GTK_MAJOR_VERSION >= 3 116 gtk_tool_button_set_icon_name(GTK_TOOL_BUTTON(item), icon_name); 117 #else 118 UiIcon *icon = ui_icon(icon_name, 24); 119 if(icon) { 120 GdkPixbuf *pixbuf = ui_icon_pixbuf(icon); 121 if(pixbuf) { 122 GtkWidget *image = gtk_image_new_from_pixbuf(pixbuf); 123 gtk_tool_button_set_icon_widget(GTK_TOOL_BUTTON(item), image); 124 } 125 } 126 #endif 127 } 128 129 void add_toolitem_widget(GtkToolbar *tb, UiToolbarItem *item, UiObject *obj) { 130 GtkToolItem *button; 131 if(item->args.stockid) { 132 #ifdef UI_GTK2 133 button = gtk_tool_button_new_from_stock(item->args.stockid); 134 #else 135 // TODO: gtk3 stock 136 button = gtk_tool_button_new(NULL, item->args.label); 137 #endif 138 } else { 139 button = gtk_tool_button_new(NULL, item->args.label); 140 } 141 142 gtk_tool_item_set_homogeneous(button, FALSE); 143 if(item->args.icon) { 144 set_toolbutton_icon(button, item->args.icon); 145 } 146 gtk_tool_item_set_is_important(button, TRUE); 147 148 ui_set_widget_ngroups(obj->ctx, GTK_WIDGET(button), item->args.groups, item->ngroups); 149 150 if(item->args.onclick) { 151 UiEventData *event = cxMalloc( 152 obj->ctx->allocator, 153 sizeof(UiEventData)); 154 event->obj = obj; 155 event->callback = item->args.onclick; 156 event->userdata = item->args.onclickdata; 157 event->customdata = NULL; 158 event->value = 0; 159 160 g_signal_connect( 161 button, 162 "clicked", 163 G_CALLBACK(ui_button_clicked), 164 event); 165 } 166 167 gtk_toolbar_insert(tb, button, -1); 168 169 /* 170 if(item->groups) { 171 uic_add_group_widget(obj->ctx, button, (ui_enablefunc)ui_set_enabled, item->groups); 172 } 173 */ 174 } 175 176 void add_toolitem_toggle_widget(GtkToolbar *tb, UiToolbarToggleItem *item, UiObject *obj) { 177 GtkToolItem *button; 178 if(item->args.stockid) { 179 #ifdef UI_GTK2 180 button = gtk_toggle_tool_button_new_from_stock(item->args.stockid); 181 #else 182 button = gtk_toggle_tool_button_new_from_stock(item->args.stockid); // TODO: gtk3 stock 183 #endif 184 } else { 185 button = gtk_toggle_tool_button_new(); 186 gtk_tool_item_set_homogeneous(button, FALSE); 187 if(item->args.label) { 188 gtk_tool_button_set_label(GTK_TOOL_BUTTON(button), item->args.label); 189 } 190 if(item->args.icon) { 191 set_toolbutton_icon(button, item->args.icon); 192 } 193 } 194 ui_set_widget_ngroups(obj->ctx, GTK_WIDGET(button), item->args.groups, item->ngroups); 195 196 UiVar* var = uic_widget_var(obj->ctx, obj->ctx, NULL, item->args.varname, UI_VAR_INTEGER); 197 if(var) { 198 UiInteger *i = (UiInteger*)var->value; 199 if(i) { 200 i->get = ui_tool_toggle_button_get; 201 i->set = ui_tool_toggle_button_set; 202 i->obj = button; 203 204 if(i->value != 0) { 205 gtk_toggle_tool_button_set_active(GTK_TOGGLE_TOOL_BUTTON(button), TRUE); 206 } 207 } 208 } 209 210 UiVarEventData *event = cxMalloc( 211 obj->ctx->allocator, 212 sizeof(UiVarEventData)); 213 event->obj = obj; 214 event->callback = item->args.onchange; 215 event->userdata = item->args.onchangedata; 216 event->var = var; 217 218 g_signal_connect( 219 button, 220 "toggled", 221 G_CALLBACK(ui_tool_button_toggled), 222 event); 223 224 // add item to toolbar 225 gtk_toolbar_insert(tb, button, -1); 226 227 /* 228 if(item->groups) { 229 uic_add_group_widget(obj->ctx, button, (ui_enablefunc)ui_set_enabled, item->groups); 230 } 231 */ 232 } 233 234 void ui_tool_button_toggled(GtkToggleToolButton *widget, UiVarEventData *event) { 235 UiEvent e; 236 e.obj = event->obj; 237 e.window = event->obj->window; 238 e.document = event->obj->ctx->document; 239 e.eventdata = NULL; 240 e.intval = gtk_toggle_tool_button_get_active(widget); 241 242 if(event->callback) { 243 event->callback(&e, event->userdata); 244 } 245 246 UiVar *var = event->var; 247 UiInteger *i = var ? var->value : NULL; 248 249 if(i) { 250 ui_notify_evt(i->observers, &e); 251 } 252 } 253 254 int64_t ui_tool_toggle_button_get(UiInteger *integer) { 255 integer->value = gtk_toggle_tool_button_get_active(GTK_TOGGLE_TOOL_BUTTON(integer->obj)); 256 return integer->value; 257 } 258 259 void ui_tool_toggle_button_set(UiInteger *integer, int64_t value) { 260 gboolean s = value != 0 ? TRUE : FALSE; 261 gtk_toggle_tool_button_set_active(GTK_TOGGLE_TOOL_BUTTON(integer->obj), s); 262 integer->value = s; 263 } 264 265 266 267 typedef struct UiToolbarMenuWidget { 268 GtkWidget *button; 269 GtkMenu *menu; 270 } UiToolbarMenuWidget; 271 272 static void ui_toolbar_menubutton_clicked(GtkWidget *widget, UiToolbarMenuWidget *menu) { 273 int x; 274 gtk_menu_popup_at_widget(menu->menu, menu->button, GDK_GRAVITY_SOUTH_WEST, GDK_GRAVITY_NORTH_WEST, NULL); 275 } 276 277 static void ui_toolbar_menubutton_destroy(GtkWidget *widget, UiToolbarMenuWidget *menu) { 278 free(menu); 279 } 280 281 void add_toolitem_menu_widget(GtkToolbar *tb, UiToolbarMenuItem *item, UiObject *obj) { 282 GtkToolItem *button; 283 if(item->args.stockid) { 284 #ifdef UI_GTK2 285 button = gtk_tool_button_new_from_stock(item->args.stockid); 286 #else 287 // TODO: gtk3 stock 288 button = gtk_tool_button_new(NULL, item->args.label); 289 #endif 290 } else { 291 button = gtk_tool_button_new(NULL, item->args.label); 292 } 293 294 gtk_tool_item_set_homogeneous(button, FALSE); 295 if(item->args.icon) { 296 set_toolbutton_icon(button, item->args.icon); 297 } 298 gtk_tool_item_set_is_important(button, TRUE); 299 300 gtk_toolbar_insert(tb, button, -1); 301 302 // menu 303 GtkWidget *menu_widget = gtk_menu_new(); 304 ui_add_menu_items(menu_widget, 0, &item->menu, obj); 305 gtk_widget_show_all(menu_widget); 306 307 UiToolbarMenuWidget *tbmenu = malloc(sizeof(UiToolbarMenuWidget)); 308 tbmenu->button = GTK_WIDGET(button); 309 tbmenu->menu = GTK_MENU(menu_widget); 310 311 g_signal_connect( 312 button, 313 "clicked", 314 G_CALLBACK(ui_toolbar_menubutton_clicked), 315 tbmenu); 316 317 g_signal_connect( 318 button, 319 "destroy", 320 G_CALLBACK(ui_toolbar_menubutton_destroy), 321 tbmenu); 322 } 323 324 325 326 327 // deprecated / unsupported 328 /* 329 void add_toolbar_combobox(GtkToolbar *tb, UiToolbarComboBox *cb, UiObject *obj) { 330 UiModel *modelinfo = ui_model(obj->ctx, UI_STRING, "", -1); 331 modelinfo->getvalue = cb->getvalue; 332 UiListModel *model = ui_list_model_new(obj, cb->var, modelinfo); 333 334 GtkWidget *combobox = ui_create_combobox(obj, model, cb->callback, cb->userdata); 335 GtkToolItem *item = gtk_tool_item_new(); 336 gtk_container_add(GTK_CONTAINER(item), combobox); 337 gtk_toolbar_insert(tb, item, -1); 338 } 339 340 void add_toolbar_combobox_nv(GtkToolbar *tb, UiToolbarComboBoxNV *cb, UiObject *obj) { 341 UiVar *var = uic_create_var(obj->ctx, cb->listname, UI_VAR_LIST); 342 if(var) { 343 UiModel *modelinfo = ui_model(obj->ctx, UI_STRING, "", -1); 344 modelinfo->getvalue = cb->getvalue; 345 UiListModel *model = ui_list_model_new(obj, var, modelinfo); 346 347 GtkWidget *combobox = ui_create_combobox(obj, model, cb->callback, cb->userdata); 348 GtkToolItem *item = gtk_tool_item_new(); 349 gtk_container_add(GTK_CONTAINER(item), combobox); 350 gtk_toolbar_insert(tb, item, -1); 351 } 352 } 353 */ 354 355 356 357 #ifdef UI_GTK3 358 359 GtkWidget* ui_create_headerbar(UiObject *obj) { 360 GtkWidget *headerbar = gtk_header_bar_new(); 361 362 CxMap *items = uic_get_toolbar_items(); 363 CxList *left_defaults = uic_get_toolbar_defaults(UI_TOOLBAR_LEFT); 364 CxList *center_defaults = uic_get_toolbar_defaults(UI_TOOLBAR_CENTER); 365 CxList *right_defaults = uic_get_toolbar_defaults(UI_TOOLBAR_RIGHT); 366 367 ui_toolbar_headerbar_add_items(obj, headerbar, items, left_defaults); 368 ui_toolbar_headerbar_add_items(obj, headerbar, items, center_defaults); 369 ui_toolbar_headerbar_add_items(obj, headerbar, items, right_defaults); 370 371 return headerbar; 372 } 373 374 static void hb_create_item(UiObject *obj, GtkWidget *toolbar, UiToolbarItemI *i) { 375 GtkHeaderBar *tb = GTK_HEADER_BAR(toolbar); 376 switch(i->type) { 377 case UI_TOOLBAR_ITEM: { 378 add_headerbar_item_widget(tb, (UiToolbarItem*)i, obj); 379 break; 380 } 381 case UI_TOOLBAR_TOGGLEITEM: { 382 add_headerbar_item_toggle_widget(tb, (UiToolbarToggleItem*)i, obj); 383 break; 384 } 385 case UI_TOOLBAR_MENU: { 386 add_headerbar_item_menu_widget(tb, (UiToolbarMenuItem*)i, obj); 387 break; 388 } 389 default: fprintf(stderr, "toolbar item type unimplemented: %d\n", (int)i->type); 390 } 391 } 392 393 394 void ui_toolbar_headerbar_add_items(UiObject *obj, GtkWidget *headerbar, CxMap *items, CxList *defaults) { 395 // add pre-configured items 396 CxIterator i = cxListIterator(defaults); 397 cx_foreach(char*, def, i) { 398 UiToolbarItemI* item = uic_toolbar_get_item(def); 399 if (!item) { 400 fprintf(stderr, "unknown toolbar item: %s\n", def); 401 continue; 402 } 403 hb_create_item(obj, headerbar, item); 404 } 405 } 406 407 void add_headerbar_item_widget(GtkHeaderBar *hb, UiToolbarItem *item, UiObject *obj) { 408 GtkWidget *button = gtk_button_new_with_label(item->args.label); 409 if(item->args.icon) { 410 ui_button_set_icon_name(button, item->args.icon); 411 } 412 ui_set_widget_groups(obj->ctx, button, item->args.groups); 413 414 gtk_header_bar_pack_start(hb, button); 415 416 } 417 418 void add_headerbar_item_toggle_widget(GtkHeaderBar *hb, UiToolbarToggleItem *item, UiObject *obj) { 419 420 } 421 422 void add_headerbar_item_menu_widget(GtkHeaderBar *hb, UiToolbarMenuItem *item, UiObject *obj) { 423 424 } 425 426 #endif /* UI_GTK3 */ 427 428 #endif /* UI_GTK2 || UI_GTK3 */ 429