270 ret = a; |
345 ret = a; |
271 #endif |
346 #endif |
272 return ret; |
347 return ret; |
273 } |
348 } |
274 |
349 |
275 UIWIDGET ui_vbox_sp(UiObject *obj, int margin, int spacing) { |
350 UIWIDGET ui_box_create(UiObject *obj, UiContainerArgs args, UiSubContainerType type) { |
276 UiContainer *ct = uic_get_current_container(obj); |
351 UiObject *current = uic_current_obj(obj); |
277 |
352 UiContainer *ct = current->container; |
278 GtkWidget *vbox = ui_gtk_vbox_new(spacing); |
353 UI_APPLY_LAYOUT1(current, args); |
279 GtkWidget *widget = margin > 0 ? box_set_margin(vbox, margin) : vbox; |
354 |
|
355 GtkWidget *box = type == UI_CONTAINER_VBOX ? ui_gtk_vbox_new(args.spacing) : ui_gtk_hbox_new(args.spacing); |
|
356 ui_set_name_and_style(box, args.name, args.style_class); |
|
357 GtkWidget *widget = args.margin > 0 ? ui_box_set_margin(box, args.margin) : box; |
280 ct->add(ct, widget, TRUE); |
358 ct->add(ct, widget, TRUE); |
281 |
359 |
282 UiObject *newobj = uic_object_new(obj, vbox); |
360 UiObject *newobj = uic_object_new(obj, box); |
283 newobj->container = ui_box_container(obj, vbox); |
361 newobj->container = ui_box_container(obj, box, type); |
284 uic_obj_add(obj, newobj); |
362 uic_obj_add(obj, newobj); |
285 |
363 |
286 return widget; |
364 return widget; |
287 } |
365 } |
288 |
366 |
289 UIWIDGET ui_hbox_sp(UiObject *obj, int margin, int spacing) { |
367 UIEXPORT UIWIDGET ui_vbox_create(UiObject *obj, UiContainerArgs args) { |
290 UiContainer *ct = uic_get_current_container(obj); |
368 return ui_box_create(obj, args, UI_CONTAINER_VBOX); |
291 |
369 } |
292 GtkWidget *hbox = ui_gtk_hbox_new(spacing); |
370 |
293 GtkWidget *widget = margin > 0 ? box_set_margin(hbox, margin) : hbox; |
371 UIEXPORT UIWIDGET ui_hbox_create(UiObject *obj, UiContainerArgs args) { |
294 ct->add(ct, widget, TRUE); |
372 return ui_box_create(obj, args, UI_CONTAINER_HBOX); |
295 |
373 } |
296 UiObject *newobj = uic_object_new(obj, hbox); |
374 |
297 newobj->container = ui_box_container(obj, hbox); |
375 GtkWidget* ui_create_grid_widget(int colspacing, int rowspacing) { |
298 uic_obj_add(obj, newobj); |
376 #if GTK_MAJOR_VERSION >= 3 |
299 |
377 GtkWidget *grid = gtk_grid_new(); |
300 return widget; |
378 gtk_grid_set_column_spacing(GTK_GRID(grid), colspacing); |
301 } |
379 gtk_grid_set_row_spacing(GTK_GRID(grid), rowspacing); |
302 |
380 #else |
303 UIWIDGET ui_grid(UiObject *obj) { |
381 GtkWidget *grid = gtk_table_new(1, 1, FALSE); |
304 return ui_grid_sp(obj, 0, 0, 0); |
382 gtk_table_set_col_spacings(GTK_TABLE(grid), colspacing); |
305 } |
383 gtk_table_set_row_spacings(GTK_TABLE(grid), rowspacing); |
306 |
384 #endif |
307 UIWIDGET ui_grid_sp(UiObject *obj, int margin, int columnspacing, int rowspacing) { |
385 return grid; |
308 UiContainer *ct = uic_get_current_container(obj); |
386 } |
|
387 |
|
388 UIWIDGET ui_grid_create(UiObject *obj, UiContainerArgs args) { |
|
389 UiObject* current = uic_current_obj(obj); |
|
390 UI_APPLY_LAYOUT1(current, args); |
309 GtkWidget *widget; |
391 GtkWidget *widget; |
310 |
392 |
311 #ifdef UI_GTK3 |
393 GtkWidget *grid = ui_create_grid_widget(args.columnspacing, args.rowspacing); |
312 GtkWidget *grid = gtk_grid_new(); |
394 ui_set_name_and_style(grid, args.name, args.style_class); |
313 gtk_grid_set_column_spacing(GTK_GRID(grid), columnspacing); |
395 widget = ui_box_set_margin(grid, args.margin); |
314 gtk_grid_set_row_spacing(GTK_GRID(grid), rowspacing); |
396 current->container->add(current->container, widget, TRUE); |
315 #if GTK_MAJOR_VERSION == 3 && GTK_MINOR_VERSION >= 12 |
|
316 gtk_widget_set_margin_start(grid, margin); |
|
317 gtk_widget_set_margin_end(grid, margin); |
|
318 #else |
|
319 gtk_widget_set_margin_left(grid, margin); |
|
320 gtk_widget_set_margin_right(grid, margin); |
|
321 #endif |
|
322 gtk_widget_set_margin_top(grid, margin); |
|
323 gtk_widget_set_margin_bottom(grid, margin); |
|
324 |
|
325 widget = grid; |
|
326 #elif defined(UI_GTK2) |
|
327 GtkWidget *grid = gtk_table_new(1, 1, FALSE); |
|
328 |
|
329 gtk_table_set_col_spacings(GTK_TABLE(grid), columnspacing); |
|
330 gtk_table_set_row_spacings(GTK_TABLE(grid), rowspacing); |
|
331 |
|
332 if(margin > 0) { |
|
333 GtkWidget *a = gtk_alignment_new(0.5, 0.5, 1, 1); |
|
334 gtk_alignment_set_padding(GTK_ALIGNMENT(a), margin, margin, margin, margin); |
|
335 gtk_container_add(GTK_CONTAINER(a), grid); |
|
336 widget = a; |
|
337 } else { |
|
338 widget = grid; |
|
339 } |
|
340 #endif |
|
341 ct->add(ct, widget, TRUE); |
|
342 |
397 |
343 UiObject *newobj = uic_object_new(obj, grid); |
398 UiObject *newobj = uic_object_new(obj, grid); |
344 newobj->container = ui_grid_container(obj, grid); |
399 newobj->container = ui_grid_container(obj, grid); |
345 uic_obj_add(obj, newobj); |
400 uic_obj_add(obj, newobj); |
346 |
401 |
347 return widget; |
402 return widget; |
348 } |
403 } |
349 |
404 |
350 UIWIDGET ui_scrolledwindow(UiObject *obj) { |
405 UIWIDGET ui_frame_create(UiObject *obj, UiFrameArgs args) { |
351 UiContainer *ct = uic_get_current_container(obj); |
406 UiObject* current = uic_current_obj(obj); |
352 GtkWidget *sw = gtk_scrolled_window_new(NULL, NULL); |
407 UI_APPLY_LAYOUT1(current, args); |
353 ct->add(ct, sw, TRUE); |
408 |
|
409 GtkWidget *frame = gtk_frame_new(args.label); |
|
410 UiObject *newobj = uic_object_new(obj, frame); |
|
411 GtkWidget *sub = ui_subcontainer_create(args.subcontainer, newobj, args.spacing, args.columnspacing, args.rowspacing, args.margin); |
|
412 if(sub) { |
|
413 FRAME_SET_CHILD(frame, sub); |
|
414 } else { |
|
415 newobj->widget = frame; |
|
416 newobj->container = ui_frame_container(obj, frame); |
|
417 } |
|
418 current->container->add(current->container, frame, FALSE); |
|
419 uic_obj_add(obj, newobj); |
|
420 |
|
421 return frame; |
|
422 } |
|
423 |
|
424 UIEXPORT UIWIDGET ui_expander_create(UiObject *obj, UiFrameArgs args) { |
|
425 UiObject* current = uic_current_obj(obj); |
|
426 UI_APPLY_LAYOUT1(current, args); |
|
427 |
|
428 GtkWidget *expander = gtk_expander_new(args.label); |
|
429 gtk_expander_set_expanded(GTK_EXPANDER(expander), args.isexpanded); |
|
430 UiObject *newobj = uic_object_new(obj, expander); |
|
431 GtkWidget *sub = ui_subcontainer_create(args.subcontainer, newobj, args.spacing, args.columnspacing, args.rowspacing, args.margin); |
|
432 if(sub) { |
|
433 EXPANDER_SET_CHILD(expander, sub); |
|
434 } else { |
|
435 newobj->widget = expander; |
|
436 newobj->container = ui_expander_container(obj, expander); |
|
437 } |
|
438 current->container->add(current->container, expander, FALSE); |
|
439 uic_obj_add(obj, newobj); |
|
440 |
|
441 return expander; |
|
442 } |
|
443 |
|
444 |
|
445 UIWIDGET ui_scrolledwindow_create(UiObject* obj, UiFrameArgs args) { |
|
446 UiObject* current = uic_current_obj(obj); |
|
447 UI_APPLY_LAYOUT1(current, args); |
|
448 |
|
449 GtkWidget *sw = SCROLLEDWINDOW_NEW(); |
|
450 ui_set_name_and_style(sw, args.name, args.style_class); |
|
451 GtkWidget *widget = ui_box_set_margin(sw, args.margin); |
|
452 current->container->add(current->container, widget, TRUE); |
354 |
453 |
355 UiObject *newobj = uic_object_new(obj, sw); |
454 UiObject *newobj = uic_object_new(obj, sw); |
356 newobj->container = ui_scrolledwindow_container(obj, sw); |
455 GtkWidget *sub = ui_subcontainer_create(args.subcontainer, newobj, args.spacing, args.columnspacing, args.rowspacing, args.margin); |
|
456 if(sub) { |
|
457 SCROLLEDWINDOW_SET_CHILD(sw, sub); |
|
458 } else { |
|
459 newobj->widget = sw; |
|
460 newobj->container = ui_scrolledwindow_container(obj, sw); |
|
461 } |
|
462 |
357 uic_obj_add(obj, newobj); |
463 uic_obj_add(obj, newobj); |
358 |
464 |
359 return sw; |
465 return sw; |
360 } |
466 } |
361 |
467 |
362 UIWIDGET ui_tabview(UiObject *obj) { |
468 |
363 GtkWidget *tabview = gtk_notebook_new(); |
469 void ui_notebook_tab_select(UIWIDGET tabview, int tab) { |
364 gtk_notebook_set_show_border(GTK_NOTEBOOK(tabview), FALSE); |
|
365 gtk_notebook_set_show_tabs(GTK_NOTEBOOK(tabview), FALSE); |
|
366 |
|
367 UiContainer *ct = uic_get_current_container(obj); |
|
368 ct->add(ct, tabview, TRUE); |
|
369 |
|
370 UiObject *tabviewobj = uic_object_new(obj, tabview); |
|
371 tabviewobj->container = ui_tabview_container(obj, tabview); |
|
372 uic_obj_add(obj, tabviewobj); |
|
373 |
|
374 return tabview; |
|
375 } |
|
376 |
|
377 void ui_tab(UiObject *obj, char *title) { |
|
378 UiContainer *ct = uic_get_current_container(obj); |
|
379 ct->layout.label = title; |
|
380 ui_vbox(obj); |
|
381 } |
|
382 |
|
383 void ui_select_tab(UIWIDGET tabview, int tab) { |
|
384 gtk_notebook_set_current_page(GTK_NOTEBOOK(tabview), tab); |
470 gtk_notebook_set_current_page(GTK_NOTEBOOK(tabview), tab); |
385 } |
471 } |
386 |
472 |
|
473 void ui_notebook_tab_remove(UIWIDGET tabview, int tab) { |
|
474 gtk_notebook_remove_page(GTK_NOTEBOOK(tabview), tab); |
|
475 } |
|
476 |
|
477 void ui_notebook_tab_add(UIWIDGET widget, int index, const char *name, UIWIDGET child) { |
|
478 gtk_notebook_insert_page( |
|
479 GTK_NOTEBOOK(widget), |
|
480 child, |
|
481 gtk_label_new(name), |
|
482 index); |
|
483 } |
|
484 |
|
485 int64_t ui_notebook_get(UiInteger *i) { |
|
486 GtkNotebook *nb = i->obj; |
|
487 i->value = gtk_notebook_get_current_page(nb); |
|
488 return i->value; |
|
489 } |
|
490 |
|
491 void ui_notebook_set(UiInteger *i, int64_t value) { |
|
492 GtkNotebook *nb = i->obj; |
|
493 gtk_notebook_set_current_page(nb, value); |
|
494 i->value = gtk_notebook_get_current_page(nb); |
|
495 } |
|
496 |
|
497 |
|
498 #if GTK_MAJOR_VERSION >= 4 |
|
499 static int stack_set_page(GtkWidget *stack, int index) { |
|
500 GtkSelectionModel *pages = gtk_stack_get_pages(GTK_STACK(stack)); |
|
501 GListModel *list = G_LIST_MODEL(pages); |
|
502 GtkStackPage *page = g_list_model_get_item(list, index); |
|
503 if(page) { |
|
504 gtk_stack_set_visible_child(GTK_STACK(stack), gtk_stack_page_get_child(page)); |
|
505 } else { |
|
506 fprintf(stderr, "UI Error: ui_stack_set value out of bounds\n"); |
|
507 return -1; |
|
508 } |
|
509 return index; |
|
510 } |
|
511 |
|
512 void ui_stack_tab_select(UIWIDGET tabview, int tab) { |
|
513 stack_set_page(tabview, tab); |
|
514 } |
|
515 |
|
516 void ui_stack_tab_remove(UIWIDGET tabview, int tab) { |
|
517 GtkStack *stack = GTK_STACK(tabview); |
|
518 GtkWidget *current = gtk_stack_get_visible_child(stack); |
|
519 GtkSelectionModel *pages = gtk_stack_get_pages(stack); |
|
520 GListModel *list = G_LIST_MODEL(pages); |
|
521 GtkStackPage *page = g_list_model_get_item(list, tab); |
|
522 if(page) { |
|
523 gtk_stack_remove(stack, gtk_stack_page_get_child(page)); |
|
524 } |
|
525 } |
|
526 |
|
527 void ui_stack_tab_add(UIWIDGET widget, int index, const char *name, UIWIDGET child) { |
|
528 (void)gtk_stack_add_titled(GTK_STACK(widget), child, name, name); |
|
529 } |
|
530 |
|
531 int64_t ui_stack_get(UiInteger *i) { |
|
532 GtkStack *stack = GTK_STACK(i->obj); |
|
533 GtkWidget *current = gtk_stack_get_visible_child(stack); |
|
534 GtkSelectionModel *pages = gtk_stack_get_pages(stack); |
|
535 GListModel *list = G_LIST_MODEL(pages); |
|
536 int nitems = g_list_model_get_n_items(list); |
|
537 for(int p=0;p<nitems;p++) { |
|
538 GtkStackPage *page = g_list_model_get_item(list, p); |
|
539 GtkWidget *child = gtk_stack_page_get_child(page); |
|
540 if(child == current) { |
|
541 i->value = p; |
|
542 break; |
|
543 } |
|
544 } |
|
545 return i->value; |
|
546 } |
|
547 |
|
548 void ui_stack_set(UiInteger *i, int64_t value) { |
|
549 GtkWidget *widget = i->obj; |
|
550 if(stack_set_page(widget, value) >= 0) { |
|
551 i->value = value; |
|
552 } |
|
553 } |
|
554 #elif GTK_MAJOR_VERSION >= 3 |
|
555 static GtkWidget* stack_get_child(GtkWidget *stack, int index) { |
|
556 GList *children = gtk_container_get_children(GTK_CONTAINER(stack)); |
|
557 if(children) { |
|
558 return g_list_nth_data(children, index); |
|
559 } |
|
560 return NULL; |
|
561 } |
|
562 |
|
563 void ui_stack_tab_select(UIWIDGET tabview, int tab) { |
|
564 GtkWidget *child = stack_get_child(tabview, tab); |
|
565 if(child) { |
|
566 gtk_stack_set_visible_child(GTK_STACK(tabview), child); |
|
567 } |
|
568 } |
|
569 |
|
570 void ui_stack_tab_remove(UIWIDGET tabview, int tab) { |
|
571 GtkWidget *child = stack_get_child(tabview, tab); |
|
572 if(child) { |
|
573 gtk_container_remove(GTK_CONTAINER(tabview), child); |
|
574 } |
|
575 } |
|
576 |
|
577 void ui_stack_tab_add(UIWIDGET widget, int index, const char *name, UIWIDGET child) { |
|
578 gtk_stack_add_titled(GTK_STACK(widget), child, name, name); |
|
579 } |
|
580 |
|
581 int64_t ui_stack_get(UiInteger *i) { |
|
582 GtkWidget *visible = gtk_stack_get_visible_child(GTK_STACK(i->obj)); |
|
583 GList *children = gtk_container_get_children(GTK_CONTAINER(i->obj)); |
|
584 GList *elm = children; |
|
585 int n = 0; |
|
586 int64_t v = -1; |
|
587 while(elm) { |
|
588 GtkWidget *child = elm->data; |
|
589 if(child == visible) { |
|
590 v = n; |
|
591 break; |
|
592 } |
|
593 |
|
594 elm = elm->next; |
|
595 n++; |
|
596 } |
|
597 g_list_free(children); |
|
598 i->value = v; |
|
599 return v; |
|
600 } |
|
601 |
|
602 void ui_stack_set(UiInteger *i, int64_t value) { |
|
603 GtkWidget *child = stack_get_child(i->obj, value); |
|
604 if(child) { |
|
605 gtk_stack_set_visible_child(GTK_STACK(i->obj), child); |
|
606 i->value = value; |
|
607 } |
|
608 } |
|
609 |
|
610 #endif |
|
611 |
|
612 |
|
613 |
|
614 |
|
615 UiGtkTabView* ui_widget_get_tabview_data(UIWIDGET tabview) { |
|
616 return g_object_get_data(G_OBJECT(tabview), "ui_tabview"); |
|
617 } |
|
618 |
|
619 typedef int64_t(*ui_tabview_get_func)(UiInteger*); |
|
620 typedef void (*ui_tabview_set_func)(UiInteger*, int64_t); |
|
621 |
|
622 UIWIDGET ui_tabview_create(UiObject* obj, UiTabViewArgs args) { |
|
623 UiGtkTabView *data = malloc(sizeof(UiGtkTabView)); |
|
624 data->margin = args.margin; |
|
625 data->spacing = args.spacing; |
|
626 data->columnspacing = args.columnspacing; |
|
627 data->rowspacing = args.rowspacing; |
|
628 |
|
629 ui_tabview_get_func getfunc = NULL; |
|
630 ui_tabview_set_func setfunc = NULL; |
|
631 |
|
632 GtkWidget *widget = NULL; |
|
633 GtkWidget *data_widget = NULL; |
|
634 switch(args.tabview) { |
|
635 case UI_TABVIEW_DOC: { |
|
636 // TODO |
|
637 break; |
|
638 } |
|
639 case UI_TABVIEW_NAVIGATION_SIDE: { |
|
640 #if GTK_CHECK_VERSION(3, 10, 0) |
|
641 widget = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0); |
|
642 GtkWidget *sidebar = gtk_stack_sidebar_new(); |
|
643 BOX_ADD(widget, sidebar); |
|
644 GtkWidget *stack = gtk_stack_new(); |
|
645 gtk_stack_set_transition_type (GTK_STACK(stack), GTK_STACK_TRANSITION_TYPE_SLIDE_UP_DOWN); |
|
646 gtk_stack_sidebar_set_stack(GTK_STACK_SIDEBAR(sidebar), GTK_STACK(stack)); |
|
647 BOX_ADD_EXPAND(widget, stack); |
|
648 data->select_tab = ui_stack_tab_select; |
|
649 data->remove_tab = ui_stack_tab_remove; |
|
650 data->add_tab = ui_stack_tab_add; |
|
651 getfunc = ui_stack_get; |
|
652 setfunc = ui_stack_set; |
|
653 data_widget = stack; |
|
654 #else |
|
655 // TODO |
|
656 #endif |
|
657 break; |
|
658 } |
|
659 case UI_TABVIEW_DEFAULT: /* fall through */ |
|
660 case UI_TABVIEW_NAVIGATION_TOP: /* fall through */ |
|
661 case UI_TABVIEW_INVISIBLE: /* fall through */ |
|
662 case UI_TABVIEW_NAVIGATION_TOP2: { |
|
663 widget = gtk_notebook_new(); |
|
664 data_widget = widget; |
|
665 data->select_tab = ui_notebook_tab_select; |
|
666 data->remove_tab = ui_notebook_tab_remove; |
|
667 data->add_tab = ui_notebook_tab_add; |
|
668 getfunc = ui_notebook_get; |
|
669 setfunc = ui_notebook_set; |
|
670 if(args.tabview == UI_TABVIEW_INVISIBLE) { |
|
671 gtk_notebook_set_show_tabs(GTK_NOTEBOOK(widget), FALSE); |
|
672 gtk_notebook_set_show_border(GTK_NOTEBOOK(widget), FALSE); |
|
673 } |
|
674 break; |
|
675 } |
|
676 } |
|
677 |
|
678 UiObject* current = uic_current_obj(obj); |
|
679 if(args.value || args.varname) { |
|
680 UiVar *var = uic_widget_var(obj->ctx, current->ctx, args.value, args.varname, UI_VAR_INTEGER); |
|
681 UiInteger *i = var->value; |
|
682 i->get = getfunc; |
|
683 i->set = setfunc; |
|
684 i->obj = data_widget; |
|
685 } |
|
686 |
|
687 g_object_set_data(G_OBJECT(widget), "ui_tabview", data); |
|
688 data->widget = data_widget; |
|
689 data->subcontainer = args.subcontainer; |
|
690 |
|
691 UI_APPLY_LAYOUT1(current, args); |
|
692 current->container->add(current->container, widget, TRUE); |
|
693 |
|
694 UiObject *newobj = uic_object_new(obj, widget); |
|
695 newobj->container = ui_tabview_container(obj, widget); |
|
696 uic_obj_add(obj, newobj); |
|
697 data->obj = newobj; |
|
698 |
|
699 return widget; |
|
700 } |
|
701 |
|
702 void ui_tab_create(UiObject* obj, const char* title) { |
|
703 UiObject* current = uic_current_obj(obj); |
|
704 UiGtkTabView *data = ui_widget_get_tabview_data(current->widget); |
|
705 if(!data) { |
|
706 fprintf(stderr, "UI Error: widget is not a tabview\n"); |
|
707 return; |
|
708 } |
|
709 |
|
710 UiObject *newobj = ui_tabview_add(current->widget, title, -1); |
|
711 current->next = newobj; |
|
712 } |
|
713 |
|
714 |
|
715 |
|
716 void ui_tabview_select(UIWIDGET tabview, int tab) { |
|
717 UiGtkTabView *data = ui_widget_get_tabview_data(tabview); |
|
718 if(!data) { |
|
719 fprintf(stderr, "UI Error: widget is not a tabview\n"); |
|
720 return; |
|
721 } |
|
722 data->select_tab(tabview, tab); |
|
723 } |
|
724 |
|
725 void ui_tabview_remove(UIWIDGET tabview, int tab) { |
|
726 UiGtkTabView *data = ui_widget_get_tabview_data(tabview); |
|
727 if(!data) { |
|
728 fprintf(stderr, "UI Error: widget is not a tabview\n"); |
|
729 return; |
|
730 } |
|
731 data->remove_tab(tabview, tab); |
|
732 } |
|
733 |
|
734 UiObject* ui_tabview_add(UIWIDGET tabview, const char *name, int tab_index) { |
|
735 UiGtkTabView *data = ui_widget_get_tabview_data(tabview); |
|
736 if(!data) { |
|
737 fprintf(stderr, "UI Error: widget is not a tabview\n"); |
|
738 return NULL; |
|
739 } |
|
740 |
|
741 UiObject *newobj = cxCalloc(data->obj->ctx->allocator, 1, sizeof(UiObject)); |
|
742 newobj->ctx = data->obj->ctx; |
|
743 |
|
744 GtkWidget *sub; |
|
745 switch(data->subcontainer) { |
|
746 default: { |
|
747 sub = ui_gtk_vbox_new(data->spacing); |
|
748 newobj->container = ui_box_container(newobj, sub, data->subcontainer); |
|
749 break; |
|
750 } |
|
751 case UI_CONTAINER_HBOX: { |
|
752 sub = ui_gtk_hbox_new(data->spacing); |
|
753 newobj->container = ui_box_container(newobj, sub, data->subcontainer); |
|
754 break; |
|
755 } |
|
756 case UI_CONTAINER_GRID: { |
|
757 sub = ui_create_grid_widget(data->columnspacing, data->rowspacing); |
|
758 newobj->container = ui_grid_container(newobj, sub); |
|
759 break; |
|
760 } |
|
761 } |
|
762 newobj->widget = sub; |
|
763 GtkWidget *widget = ui_box_set_margin(sub, data->margin); |
|
764 |
|
765 data->add_tab(data->widget, tab_index, name, widget); |
|
766 |
|
767 return newobj; |
|
768 } |
|
769 |
|
770 |
|
771 /* -------------------- Headerbar -------------------- */ |
|
772 |
|
773 static void hb_set_part(UiObject *obj, int part) { |
|
774 UiObject* current = uic_current_obj(obj); |
|
775 GtkWidget *headerbar = current->widget; |
|
776 |
|
777 UiHeaderbarContainer *hb = cxCalloc( |
|
778 obj->ctx->allocator, |
|
779 1, |
|
780 sizeof(UiHeaderbarContainer)); |
|
781 memcpy(hb, current->container, sizeof(UiHeaderbarContainer)); |
|
782 |
|
783 UiObject *newobj = uic_object_new(obj, headerbar); |
|
784 newobj->container = (UiContainer*)hb; |
|
785 uic_obj_add(obj, newobj); |
|
786 |
|
787 hb->part = part; |
|
788 } |
|
789 |
|
790 void ui_headerbar_start_create(UiObject *obj) { |
|
791 hb_set_part(obj, 0); |
|
792 } |
|
793 |
|
794 void ui_headerbar_center_create(UiObject *obj) { |
|
795 hb_set_part(obj, 2); |
|
796 } |
|
797 |
|
798 void ui_headerbar_end_create(UiObject *obj) { |
|
799 hb_set_part(obj, 1); |
|
800 } |
|
801 |
|
802 UIWIDGET ui_headerbar_fallback_create(UiObject *obj, UiHeaderbarArgs args) { |
|
803 UiObject *current = uic_current_obj(obj); |
|
804 UiContainer *ct = current->container; |
|
805 UI_APPLY_LAYOUT1(current, args); |
|
806 |
|
807 GtkWidget *box = ui_gtk_hbox_new(args.alt_spacing); |
|
808 ui_set_name_and_style(box, args.name, args.style_class); |
|
809 ct->add(ct, box, FALSE); |
|
810 |
|
811 UiObject *newobj = uic_object_new(obj, box); |
|
812 newobj->container = ui_headerbar_fallback_container(obj, box); |
|
813 uic_obj_add(obj, newobj); |
|
814 |
|
815 return box; |
|
816 } |
|
817 |
|
818 static void hb_fallback_set_part(UiObject *obj, int part) { |
|
819 UiObject* current = uic_current_obj(obj); |
|
820 GtkWidget *headerbar = current->widget; |
|
821 |
|
822 UiObject *newobj = uic_object_new(obj, headerbar); |
|
823 newobj->container = ui_headerbar_container(obj, headerbar); |
|
824 uic_obj_add(obj, newobj); |
|
825 |
|
826 UiHeaderbarContainer *hb = (UiHeaderbarContainer*)newobj->container; |
|
827 hb->part = part; |
|
828 } |
|
829 |
|
830 UiContainer* ui_headerbar_fallback_container(UiObject *obj, GtkWidget *headerbar) { |
|
831 UiHeaderbarContainer *ct = cxCalloc( |
|
832 obj->ctx->allocator, |
|
833 1, |
|
834 sizeof(UiHeaderbarContainer)); |
|
835 ct->container.widget = headerbar; |
|
836 ct->container.add = ui_headerbar_fallback_container_add; |
|
837 return (UiContainer*)ct; |
|
838 } |
|
839 |
|
840 void ui_headerbar_fallback_container_add(UiContainer *ct, GtkWidget *widget, UiBool fill) { |
|
841 UiHeaderbarContainer *hb = (UiHeaderbarContainer*)ct; |
|
842 BOX_ADD(ct->widget, widget); |
|
843 } |
|
844 |
|
845 #if GTK_CHECK_VERSION(3, 10, 0) |
|
846 |
|
847 UIWIDGET ui_headerbar_create(UiObject *obj, UiHeaderbarArgs args) { |
|
848 GtkWidget *headerbar = g_object_get_data(G_OBJECT(obj->widget), "ui_headerbar"); |
|
849 if(!headerbar) { |
|
850 return ui_headerbar_fallback_create(obj, args); |
|
851 } |
|
852 |
|
853 UiObject *newobj = uic_object_new(obj, headerbar); |
|
854 newobj->container = ui_headerbar_container(obj, headerbar); |
|
855 uic_obj_add(obj, newobj); |
|
856 |
|
857 return headerbar; |
|
858 } |
|
859 |
|
860 UiContainer* ui_headerbar_container(UiObject *obj, GtkWidget *headerbar) { |
|
861 UiHeaderbarContainer *ct = cxCalloc( |
|
862 obj->ctx->allocator, |
|
863 1, |
|
864 sizeof(UiHeaderbarContainer)); |
|
865 ct->container.widget = headerbar; |
|
866 ct->container.add = ui_headerbar_container_add; |
|
867 return (UiContainer*)ct; |
|
868 } |
|
869 |
|
870 void ui_headerbar_container_add(UiContainer *ct, GtkWidget *widget, UiBool fill) { |
|
871 UiHeaderbarContainer *hb = (UiHeaderbarContainer*)ct; |
|
872 if(hb->part == 0) { |
|
873 UI_HEADERBAR_PACK_START(ct->widget, widget); |
|
874 } else if(hb->part == 1) { |
|
875 UI_HEADERBAR_PACK_END(ct->widget, widget); |
|
876 } else if(hb->part == 2) { |
|
877 if(!hb->centerbox) { |
|
878 GtkWidget *box = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 6); |
|
879 hb->centerbox = box; |
|
880 UI_HEADERBAR_SET_TITLE_WIDGET(ct->widget, box); |
|
881 } |
|
882 BOX_ADD(hb->centerbox, widget); |
|
883 } |
|
884 } |
|
885 |
|
886 #else |
|
887 |
|
888 UIWIDGET ui_headerbar_create(UiObject *obj, UiHeaderbarArgs args) { |
|
889 return ui_headerbar_fallback_create(obj, args); |
|
890 } |
|
891 |
|
892 #endif |
|
893 |
|
894 /* -------------------- Sidebar -------------------- */ |
|
895 |
|
896 #ifdef UI_LIBADWAITA |
|
897 UIWIDGET ui_sidebar_create(UiObject *obj, UiSidebarArgs args) { |
|
898 GtkWidget *sidebar_toolbar_view = g_object_get_data(G_OBJECT(obj->widget), "ui_sidebar"); |
|
899 if(!sidebar_toolbar_view) { |
|
900 fprintf(stderr, "Error: window is not configured for sidebar\n"); |
|
901 return NULL; |
|
902 } |
|
903 |
|
904 GtkWidget *box = ui_gtk_vbox_new(args.spacing); |
|
905 ui_box_set_margin(box, args.margin); |
|
906 adw_toolbar_view_set_content(ADW_TOOLBAR_VIEW(sidebar_toolbar_view), box); |
|
907 |
|
908 UiObject *newobj = uic_object_new(obj, box); |
|
909 newobj->container = ui_box_container(obj, box, UI_CONTAINER_VBOX); |
|
910 uic_obj_add(obj, newobj); |
|
911 |
|
912 return box; |
|
913 } |
|
914 #else |
|
915 UIWIDGET ui_sidebar_create(UiObject *obj, UiSidebarArgs args) { |
|
916 GtkWidget *sidebar_vbox = g_object_get_data(G_OBJECT(obj->widget), "ui_sidebar"); |
|
917 |
|
918 GtkWidget *box = ui_gtk_vbox_new(args.spacing); |
|
919 ui_box_set_margin(box, args.margin); |
|
920 BOX_ADD_EXPAND(sidebar_vbox, box); |
|
921 |
|
922 UiObject *newobj = uic_object_new(obj, box); |
|
923 newobj->container = ui_box_container(obj, box, UI_CONTAINER_VBOX); |
|
924 uic_obj_add(obj, newobj); |
|
925 |
|
926 return box; |
|
927 } |
|
928 #endif |
|
929 |
387 /* -------------------- Splitpane -------------------- */ |
930 /* -------------------- Splitpane -------------------- */ |
388 |
931 |
389 static GtkWidget* create_paned(UiOrientation orientation) { |
932 static GtkWidget* create_paned(UiOrientation orientation) { |
390 #ifdef UI_GTK3 |
933 #if GTK_MAJOR_VERSION >= 3 |
391 switch(orientation) { |
934 switch(orientation) { |
392 case UI_HORIZONTAL: return gtk_paned_new(GTK_ORIENTATION_HORIZONTAL); |
935 case UI_HORIZONTAL: return gtk_paned_new(GTK_ORIENTATION_HORIZONTAL); |
393 case UI_VERTICAL: return gtk_paned_new(GTK_ORIENTATION_VERTICAL); |
936 case UI_VERTICAL: return gtk_paned_new(GTK_ORIENTATION_VERTICAL); |
394 } |
937 } |
395 #else |
938 #else |
399 } |
942 } |
400 #endif |
943 #endif |
401 return NULL; |
944 return NULL; |
402 } |
945 } |
403 |
946 |
404 UIWIDGET ui_splitpane(UiObject *obj, int max, UiOrientation orientation) { |
947 |
405 GtkWidget *paned = create_paned(orientation); |
948 |
406 UiContainer *ct = uic_get_current_container(obj); |
949 /* -------------------- ItemList Container -------------------- */ |
407 ct->add(ct, paned, TRUE); |
950 |
408 |
951 static void remove_item(void *data, void *item) { |
409 if(max <= 0) max = INT_MAX; |
952 UiGtkItemListContainer *ct = data; |
410 |
953 UiObject *obj = item; |
411 UiPanedContainer *pctn = ucx_mempool_calloc( |
954 if(ct->remove_items) { |
412 obj->ctx->mempool, |
955 BOX_REMOVE(ct->widget, obj->widget); |
413 1, |
956 } |
414 sizeof(UiPanedContainer)); |
957 uic_object_destroy(obj); |
415 pctn->container.widget = paned; |
958 } |
416 pctn->container.add = ui_paned_container_add; |
959 |
417 pctn->current_pane = paned; |
960 static void update_itemlist(UiList *list, int c) { |
418 pctn->orientation = orientation; |
961 UiGtkItemListContainer *ct = list->obj; |
419 pctn->max = max; |
962 |
420 pctn->cur = 0; |
963 CxMap *new_items = cxHashMapCreateSimple(CX_STORE_POINTERS); |
421 |
964 new_items->collection.advanced_destructor = remove_item; |
422 UiObject *pobj = uic_object_new(obj, paned); |
965 new_items->collection.destructor_data = ct; |
423 pobj->container = (UiContainer*)pctn; |
966 |
424 |
967 // only create new widgets for new elements, so at first we have |
425 uic_obj_add(obj, pobj); |
968 // to find which elements are new |
426 |
969 // check which elements in the list are already in the container |
427 return paned; |
970 void *elm = list->first(list); |
428 } |
971 int j = 0; |
429 |
972 while(elm) { |
430 UIWIDGET ui_hsplitpane(UiObject *obj, int max) { |
973 CxHashKey key = cx_hash_key(&elm, sizeof(void*)); |
431 return ui_splitpane(obj, max, UI_HORIZONTAL); |
974 UiObject *item_obj = cxMapRemoveAndGet(ct->current_items, key); |
432 } |
975 if(item_obj) { |
433 |
976 g_object_ref(G_OBJECT(item_obj->widget)); |
434 UIWIDGET ui_vsplitpane(UiObject *obj, int max) { |
977 BOX_REMOVE(ct->widget, item_obj->widget); |
435 return ui_splitpane(obj, max, UI_VERTICAL); |
978 cxMapPut(new_items, key, item_obj); |
436 } |
979 } |
437 |
980 elm = list->next(list); |
438 void ui_paned_container_add(UiContainer *ct, GtkWidget *widget, UiBool fill) { |
981 j++; |
439 UiPanedContainer *pctn = (UiPanedContainer*)ct; |
982 } |
440 |
983 |
441 gboolean resize = (ct->layout.hexpand || ct->layout.vexpand) ? TRUE : FALSE; |
984 // ct->current_items only contains elements, that are not in the list |
442 int width = ct->layout.width; |
985 cxMapDestroy(ct->current_items); // calls destructor remove_item |
443 ui_reset_layout(ct->layout); |
986 ct->current_items = new_items; |
444 |
987 |
445 if(pctn->cur == 0) { |
988 // add all items |
446 gtk_paned_pack1(GTK_PANED(pctn->current_pane), widget, resize, resize); |
989 int index = 0; |
447 } else if(pctn->cur < pctn->max-1) { |
990 elm = list->first(list); |
448 GtkWidget *nextPane = create_paned(pctn->orientation); |
991 while(elm) { |
449 gtk_paned_pack2(GTK_PANED(pctn->current_pane), nextPane, TRUE, TRUE); |
992 CxHashKey key = cx_hash_key(&elm, sizeof(void*)); |
450 gtk_paned_pack1(GTK_PANED(nextPane), widget, resize, resize); |
993 UiObject *item_obj = cxMapGet(ct->current_items, key); |
451 pctn->current_pane = nextPane; |
994 if(item_obj) { |
452 } else if(pctn->cur == pctn->max-1) { |
995 // re-add previously created widget |
453 gtk_paned_pack2(GTK_PANED(pctn->current_pane), widget, resize, resize); |
996 ui_box_container_add(ct->container, item_obj->widget, FALSE); |
454 width = 0; // disable potential call of gtk_paned_set_position |
997 } else { |
455 } else { |
998 // create new widget and object for this list element |
456 fprintf(stderr, "Splitpane max reached: %d\n", pctn->max); |
999 CxMempool *mp = cxBasicMempoolCreate(256); |
457 return; |
1000 const CxAllocator *a = mp->allocator; |
458 } |
1001 UiObject *obj = cxCalloc(a, 1, sizeof(UiObject)); |
459 |
1002 obj->ctx = uic_context(obj, mp); |
460 if(width > 0) { |
1003 obj->window = NULL; |
461 gtk_paned_set_position(GTK_PANED(pctn->current_pane), width); |
1004 obj->widget = ui_subcontainer_create( |
462 } |
1005 ct->subcontainer, |
463 |
1006 obj, |
464 pctn->cur++; |
1007 ct->spacing, |
465 } |
1008 ct->columnspacing, |
466 |
1009 ct->rowspacing, |
467 |
1010 ct->margin); |
468 /* -------------------- Sidebar (deprecated) -------------------- */ |
1011 ui_box_container_add(ct->container, obj->widget, FALSE); |
469 UIWIDGET ui_sidebar(UiObject *obj) { |
1012 if(ct->create_ui) { |
470 #ifdef UI_GTK3 |
1013 ct->create_ui(obj, index, elm, ct->userdata); |
471 GtkWidget *paned = gtk_paned_new(GTK_ORIENTATION_HORIZONTAL); |
1014 } |
472 #else |
1015 cxMapPut(new_items, key, obj); |
473 GtkWidget *paned = gtk_hpaned_new(); |
1016 } |
474 #endif |
1017 elm = list->next(list); |
475 gtk_paned_set_position(GTK_PANED(paned), 200); |
1018 index++; |
476 |
1019 } |
477 GtkWidget *sidebar = ui_gtk_vbox_new(0); |
1020 } |
478 gtk_paned_pack1(GTK_PANED(paned), sidebar, TRUE, FALSE); |
1021 |
479 |
1022 static void destroy_itemlist_container(GtkWidget *w, UiGtkItemListContainer *container) { |
480 UiObject *left = uic_object_new(obj, sidebar); |
1023 container->remove_items = FALSE; |
481 UiContainer *ct1 = ui_box_container(obj, sidebar); |
1024 cxMapDestroy(container->current_items); |
482 left->container = ct1; |
1025 free(container); |
483 |
1026 } |
484 UiObject *right = uic_object_new(obj, sidebar); |
1027 |
485 UiContainer *ct2 = ucx_mempool_malloc( |
1028 UIWIDGET ui_itemlist_create(UiObject *obj, UiItemListContainerArgs args) { |
486 obj->ctx->mempool, |
1029 UiObject *current = uic_current_obj(obj); |
487 sizeof(UiContainer)); |
1030 UiContainer *ct = current->container; |
488 ct2->widget = paned; |
1031 UI_APPLY_LAYOUT1(current, args); |
489 ct2->add = ui_split_container_add2; |
1032 |
490 right->container = ct2; |
1033 GtkWidget *box = args.container == UI_CONTAINER_VBOX ? ui_gtk_vbox_new(args.spacing) : ui_gtk_hbox_new(args.spacing); |
491 |
1034 ui_set_name_and_style(box, args.name, args.style_class); |
492 UiContainer *ct = uic_get_current_container(obj); |
1035 GtkWidget *widget = args.margin > 0 ? ui_box_set_margin(box, args.margin) : box; |
493 ct->add(ct, paned, TRUE); |
1036 ct->add(ct, widget, TRUE); |
494 |
1037 |
495 uic_obj_add(obj, right); |
1038 UiGtkItemListContainer *container = malloc(sizeof(UiGtkItemListContainer)); |
496 uic_obj_add(obj, left); |
1039 container->parent = obj; |
497 |
1040 container->widget = box; |
498 return sidebar; |
1041 container->container = ui_box_container(current, box, args.container); |
499 } |
1042 container->create_ui = args.create_ui; |
500 |
1043 container->userdata = args.userdata; |
501 void ui_split_container_add1(UiContainer *ct, GtkWidget *widget, UiBool fill) { |
1044 container->subcontainer = args.subcontainer; |
502 // TODO: remove |
1045 container->current_items = cxHashMapCreateSimple(CX_STORE_POINTERS); |
503 gtk_paned_pack1(GTK_PANED(ct->widget), widget, TRUE, FALSE); |
1046 container->current_items->collection.advanced_destructor = remove_item; |
504 |
1047 container->current_items->collection.destructor_data = container; |
505 ui_reset_layout(ct->layout); |
1048 container->margin = args.sub_margin; |
506 ct->current = widget; |
1049 container->spacing = args.sub_spacing; |
507 } |
1050 container->columnspacing = args.sub_columnspacing; |
508 |
1051 container->rowspacing = args.sub_rowspacing; |
509 void ui_split_container_add2(UiContainer *ct, GtkWidget *widget, UiBool fill) { |
1052 container->remove_items = TRUE; |
510 gtk_paned_pack2(GTK_PANED(ct->widget), widget, TRUE, FALSE); |
1053 |
511 |
1054 UiVar* var = uic_widget_var(obj->ctx, current->ctx, args.value, args.varname, UI_VAR_LIST); |
512 ui_reset_layout(ct->layout); |
1055 if(var) { |
513 ct->current = widget; |
1056 UiList *list = var->value; |
514 } |
1057 list->obj = container; |
515 |
1058 list->update = update_itemlist; |
516 |
1059 update_itemlist(list, 0); |
517 /* -------------------- Document Tabview -------------------- */ |
1060 } |
518 static void page_change(GtkNotebook *notebook, GtkWidget *page, guint page_num, gpointer data) { |
|
519 GQuark q = g_quark_from_static_string("ui.tab.object"); |
|
520 UiObject *tab = g_object_get_qdata(G_OBJECT(page), q); |
|
521 if(!tab) { |
|
522 return; |
|
523 } |
|
524 |
|
525 //printf("page_change: %d\n", page_num); |
|
526 UiContext *ctx = tab->ctx; |
|
527 uic_context_detach_all(ctx->parent); // TODO: fix? |
|
528 ctx->parent->attach_document(ctx->parent, ctx->document); |
|
529 } |
|
530 |
|
531 UiTabbedPane* ui_tabbed_document_view(UiObject *obj) { |
|
532 GtkWidget *tabview = gtk_notebook_new(); |
|
533 gtk_notebook_set_show_border(GTK_NOTEBOOK(tabview), FALSE); |
|
534 |
|
535 g_signal_connect( |
1061 g_signal_connect( |
536 tabview, |
1062 box, |
537 "switch-page", |
1063 "destroy", |
538 G_CALLBACK(page_change), |
1064 G_CALLBACK(destroy_itemlist_container), |
539 NULL); |
1065 container); |
540 |
1066 |
541 UiContainer *ct = uic_get_current_container(obj); |
1067 return box; |
542 ct->add(ct, tabview, TRUE); |
1068 } |
543 |
1069 |
544 UiTabbedPane *tabbedpane = ui_malloc(obj->ctx, sizeof(UiTabbedPane)); |
|
545 tabbedpane->ctx = uic_current_obj(obj)->ctx; |
|
546 tabbedpane->widget = tabview; |
|
547 tabbedpane->document = NULL; |
|
548 |
|
549 return tabbedpane; |
|
550 } |
|
551 |
|
552 UiObject* ui_document_tab(UiTabbedPane *view) { |
|
553 GtkWidget *frame = gtk_frame_new(NULL); |
|
554 gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_NONE); |
|
555 // TODO: label |
|
556 gtk_notebook_append_page(GTK_NOTEBOOK(view->widget), frame, NULL); |
|
557 |
|
558 UiObject *tab = ui_malloc(view->ctx, sizeof(UiObject)); |
|
559 tab->widget = NULL; // initialization for uic_context() |
|
560 tab->ctx = uic_context(tab, view->ctx->mempool); |
|
561 tab->ctx->parent = view->ctx; |
|
562 tab->ctx->attach_document = uic_context_attach_document; |
|
563 tab->ctx->detach_document2 = uic_context_detach_document2; |
|
564 tab->widget = frame; |
|
565 tab->window = view->ctx->obj->window; |
|
566 tab->container = ui_frame_container(tab, frame); |
|
567 tab->next = NULL; |
|
568 |
|
569 GQuark q = g_quark_from_static_string("ui.tab.object"); |
|
570 g_object_set_qdata(G_OBJECT(frame), q, tab); |
|
571 |
|
572 return tab; |
|
573 } |
|
574 |
|
575 void ui_tab_set_document(UiContext *ctx, void *document) { |
|
576 // TODO: remove? |
|
577 if(ctx->parent->document) { |
|
578 //ctx->parent->detach_document(ctx->parent, ctx->parent->document); |
|
579 } |
|
580 //uic_context_set_document(ctx, document); |
|
581 //uic_context_set_document(ctx->parent, document); |
|
582 //ctx->parent->document = document; |
|
583 } |
|
584 |
|
585 void ui_tab_detach_document(UiContext *ctx) { |
|
586 // TODO: remove? |
|
587 //uic_context_detach_document(ctx->parent); |
|
588 } |
|
589 |
1070 |
590 |
1071 |
591 /* |
1072 /* |
592 * -------------------- Layout Functions -------------------- |
1073 * -------------------- Layout Functions -------------------- |
593 * |
1074 * |