ui/gtk/list.c

changeset 115
e57ca2747782
parent 113
dde28a806552
equal deleted inserted replaced
114:3da24640513a 115:e57ca2747782
78 static UiListView* create_listview(UiObject *obj, UiListArgs *args) { 78 static UiListView* create_listview(UiObject *obj, UiListArgs *args) {
79 UiListView *tableview = malloc(sizeof(UiListView)); 79 UiListView *tableview = malloc(sizeof(UiListView));
80 memset(tableview, 0, sizeof(UiListView)); 80 memset(tableview, 0, sizeof(UiListView));
81 tableview->obj = obj; 81 tableview->obj = obj;
82 tableview->model = args->model; 82 tableview->model = args->model;
83 tableview->multiselection = args->multiselection;
83 tableview->onactivate = args->onactivate; 84 tableview->onactivate = args->onactivate;
84 tableview->onactivatedata = args->onactivatedata; 85 tableview->onactivatedata = args->onactivatedata;
85 tableview->onselection = args->onselection; 86 tableview->onselection = args->onselection;
86 tableview->onselectiondata = args->onselectiondata; 87 tableview->onselectiondata = args->onselectiondata;
87 tableview->ondragstart = args->ondragstart; 88 tableview->ondragstart = args->ondragstart;
96 tableview->getstyle = args->getstyle; 97 tableview->getstyle = args->getstyle;
97 tableview->getstyledata = args->getstyledata; 98 tableview->getstyledata = args->getstyledata;
98 tableview->onsave = args->onsave; 99 tableview->onsave = args->onsave;
99 tableview->onsavedata = args->onsavedata; 100 tableview->onsavedata = args->onsavedata;
100 101
102 #if GTK_CHECK_VERSION(4, 0, 0)
103 tableview->coldata.listview = tableview;
104 tableview->coldata.column = 0;
105 #endif
106
101 if(args->getvalue2) { 107 if(args->getvalue2) {
102 tableview->getvalue = args->getvalue2; 108 tableview->getvalue = args->getvalue2;
103 tableview->getvaluedata = args->getvalue2data; 109 tableview->getvaluedata = args->getvalue2data;
104 } else if(args->getvalue) { 110 } else if(args->getvalue) {
105 tableview->getvalue = getvalue_wrapper; 111 tableview->getvalue = getvalue_wrapper;
198 } 204 }
199 205
200 static void column_factory_setup(GtkListItemFactory *factory, GtkListItem *item, gpointer userdata) { 206 static void column_factory_setup(GtkListItemFactory *factory, GtkListItem *item, gpointer userdata) {
201 UiColData *col = userdata; 207 UiColData *col = userdata;
202 UiModel *model = col->listview->model; 208 UiModel *model = col->listview->model;
203 UiModelType type = model->types[col->model_column]; 209 UiModelType type = model->types[col->column];
204 if(type == UI_ICON_TEXT || type == UI_ICON_TEXT_FREE) { 210 if(type == UI_ICON_TEXT || type == UI_ICON_TEXT_FREE) {
205 GtkWidget *hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 6); 211 GtkWidget *hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 6);
206 GtkWidget *image = gtk_image_new(); 212 GtkWidget *image = gtk_image_new();
207 GtkWidget *label = gtk_label_new(NULL); 213 GtkWidget *label = gtk_label_new(NULL);
208 BOX_ADD(hbox, image); 214 BOX_ADD(hbox, image);
279 285
280 static void column_factory_bind(GtkListItemFactory *unused, GtkListItem *item, gpointer userdata) { 286 static void column_factory_bind(GtkListItemFactory *unused, GtkListItem *item, gpointer userdata) {
281 UiColData *col = userdata; 287 UiColData *col = userdata;
282 UiList *list = col->listview->var ? col->listview->var->value : NULL; 288 UiList *list = col->listview->var ? col->listview->var->value : NULL;
283 UiListView *listview = col->listview; 289 UiListView *listview = col->listview;
290 int datacolumn = listview->columns[col->column];
284 291
285 ObjWrapper *obj = gtk_list_item_get_item(item); 292 ObjWrapper *obj = gtk_list_item_get_item(item);
286 UiModel *model = col->listview->model; 293 UiModel *model = col->listview->model;
287 UiModelType type = model->types[col->model_column]; 294 UiModelType type = model->types[col->column];
288 295
289 // cache the GtkListItem 296 // cache the GtkListItem
290 CxHashKey row_key = cx_hash_key(&obj->i, sizeof(int)); 297 CxHashKey row_key = cx_hash_key(&obj->i, sizeof(int));
291 UiRowItems *row = cxMapGet(listview->bound_rows, row_key); 298 UiRowItems *row = cxMapGet(listview->bound_rows, row_key);
292 if(row) { 299 if(row) {
293 if(row->items[col->model_column] == NULL) { 300 if(row->items[col->column] == NULL) {
294 row->bound++; 301 row->bound++;
295 } 302 }
296 } else { 303 } else {
297 row = calloc(1, sizeof(UiRowItems) + listview->numcolumns * sizeof(GtkListItem*)); 304 row = calloc(1, sizeof(UiRowItems) + listview->numcolumns * sizeof(GtkListItem*));
298 cxMapPut(listview->bound_rows, row_key, row); 305 cxMapPut(listview->bound_rows, row_key, row);
299 row->bound = 1; 306 row->bound = 1;
300 } 307 }
301 row->items[col->model_column] = item; 308 row->items[col->column] = item;
302 309
303 UiBool freevalue = FALSE; 310 UiBool freevalue = FALSE;
304 void *data = listview->getvalue(list, obj->data, obj->i, col->data_column, listview->getvaluedata, &freevalue); 311 void *data = listview->getvalue(list, obj->data, obj->i, datacolumn, listview->getvaluedata, &freevalue);
305 GtkWidget *child = gtk_list_item_get_child(item); 312 GtkWidget *child = gtk_list_item_get_child(item);
306 313
307 PangoAttrList *attributes = NULL; 314 PangoAttrList *attributes = NULL;
308 UiTextStyle style = { 0, 0 }; 315 UiTextStyle style = { 0, 0 };
309 if(listview->getstyle) { 316 if(listview->getstyle) {
317 pango_attr_list_unref(listview->current_row_attributes); 324 pango_attr_list_unref(listview->current_row_attributes);
318 listview->current_row_attributes = textstyle2pangoattributes(style); 325 listview->current_row_attributes = textstyle2pangoattributes(style);
319 } 326 }
320 } 327 }
321 328
322 int style_col = col->data_column; 329 int style_col = datacolumn;
323 if(type == UI_ICON_TEXT || type == UI_ICON_TEXT_FREE) { 330 if(type == UI_ICON_TEXT || type == UI_ICON_TEXT_FREE) {
324 style_col++; // col->data_column is the icon, we need the next col for the label 331 style_col++; // col->data_column is the icon, we need the next col for the label
325 } 332 }
326 333
327 // get the column style 334 // get the column style
361 } 368 }
362 case UI_ICON_TEXT: { 369 case UI_ICON_TEXT: {
363 370
364 } 371 }
365 case UI_ICON_TEXT_FREE: { 372 case UI_ICON_TEXT_FREE: {
366 void *data2 = listview->getvalue(list, obj->data, obj->i, col->data_column+1, listview->getvaluedata, &freevalue); 373 void *data2 = listview->getvalue(list, obj->data, obj->i, datacolumn+1, listview->getvaluedata, &freevalue);
367 if(type == UI_ICON_TEXT_FREE) { 374 if(type == UI_ICON_TEXT_FREE) {
368 freevalue = TRUE; 375 freevalue = TRUE;
369 } 376 }
370 GtkWidget *image = g_object_get_data(G_OBJECT(child), "image"); 377 GtkWidget *image = g_object_get_data(G_OBJECT(child), "image");
371 GtkWidget *label = g_object_get_data(G_OBJECT(child), "label"); 378 GtkWidget *label = g_object_get_data(G_OBJECT(child), "label");
385 case UI_STRING_EDITABLE: { 392 case UI_STRING_EDITABLE: {
386 UiCellEntry *entry = g_object_get_data(G_OBJECT(child), "ui_entry_data"); 393 UiCellEntry *entry = g_object_get_data(G_OBJECT(child), "ui_entry_data");
387 if(entry) { 394 if(entry) {
388 entry->listview = col->listview; 395 entry->listview = col->listview;
389 entry->row = obj->i; 396 entry->row = obj->i;
390 entry->col = col->data_column; 397 entry->col = datacolumn;
391 entry->previous_value = strdup(data); 398 entry->previous_value = strdup(data);
392 } 399 }
393 ENTRY_SET_TEXT(child, data); 400 ENTRY_SET_TEXT(child, data);
394 break; 401 break;
395 } 402 }
403 if(attributes != listview->current_row_attributes) { 410 if(attributes != listview->current_row_attributes) {
404 pango_attr_list_unref(attributes); 411 pango_attr_list_unref(attributes);
405 } 412 }
406 } 413 }
407 414
408 static void column_factory_unbind(GtkSignalListItemFactory *self, GtkListItem *item, UiColData *col) { 415 static void column_factory_unbind(GtkSignalListItemFactory *self, GtkListItem *item, UiColData *col) {
409 ObjWrapper *obj = gtk_list_item_get_item(item); 416 ObjWrapper *obj = gtk_list_item_get_item(item);
410 UiListView *listview = col->listview; 417 UiListView *listview = col->listview;
411 CxHashKey row_key = cx_hash_key(&obj->i, sizeof(int)); 418 CxHashKey row_key = cx_hash_key(&obj->i, sizeof(int));
412 UiRowItems *row = cxMapGet(listview->bound_rows, row_key); 419 UiRowItems *row = cxMapGet(listview->bound_rows, row_key);
413 if(row) { 420 if(row) {
414 row->items[col->model_column] = NULL; 421 row->items[col->column] = NULL;
415 row->bound--; 422 row->bound--;
416 if(row->bound == 0) { 423 if(row->bound == 0) {
417 cxMapRemove(listview->bound_rows, row_key); 424 cxMapRemove(listview->bound_rows, row_key);
418 } 425 }
419 } // else: should not happen 426 } // else: should not happen
455 if(!args->getvalue && !args->getvalue2) { 462 if(!args->getvalue && !args->getvalue2) {
456 listview->getvalue = str_getvalue; 463 listview->getvalue = str_getvalue;
457 } 464 }
458 465
459 listview->numcolumns = 1; 466 listview->numcolumns = 1;
460 listview->columns = malloc(sizeof(UiColData)); 467 listview->columns = malloc(sizeof(int));
461 listview->columns->listview = listview; 468 listview->columns[0] = 0;
462 listview->columns->data_column = 0;
463 listview->columns->model_column = 0;
464 469
465 listview->bound_rows = cxHashMapCreate(NULL, CX_STORE_POINTERS, 128); 470 listview->bound_rows = cxHashMapCreate(NULL, CX_STORE_POINTERS, 128);
466 listview->bound_rows->collection.simple_destructor = (cx_destructor_func)free; 471 listview->bound_rows->collection.simple_destructor = (cx_destructor_func)free;
467 472
468 GtkListItemFactory *factory = gtk_signal_list_item_factory_new(); 473 GtkListItemFactory *factory = gtk_signal_list_item_factory_new();
469 g_signal_connect(factory, "setup", G_CALLBACK(column_factory_setup), listview->columns); 474 g_signal_connect(factory, "setup", G_CALLBACK(column_factory_setup), &listview->coldata);
470 g_signal_connect(factory, "bind", G_CALLBACK(column_factory_bind), listview->columns); 475 g_signal_connect(factory, "bind", G_CALLBACK(column_factory_bind), &listview->coldata);
476 g_signal_connect(factory, "unbind", G_CALLBACK(column_factory_unbind), &listview->coldata);
471 477
472 GtkSelectionModel *selection_model = create_selection_model(listview, ls, args->multiselection); 478 GtkSelectionModel *selection_model = create_selection_model(listview, ls, args->multiselection);
473 GtkWidget *view = gtk_list_view_new(GTK_SELECTION_MODEL(selection_model), factory); 479 GtkWidget *view = gtk_list_view_new(GTK_SELECTION_MODEL(selection_model), factory);
474 480
475 UiVar* var = uic_widget_var(obj->ctx, obj->ctx, args->list, args->varname, UI_VAR_LIST); 481 UiVar* var = uic_widget_var(obj->ctx, obj->ctx, args->list, args->varname, UI_VAR_LIST);
538 ct->add(ct, scroll_area, &layout); 544 ct->add(ct, scroll_area, &layout);
539 545
540 return scroll_area; 546 return scroll_area;
541 } 547 }
542 548
543 UIWIDGET ui_combobox_create(UiObject *obj, UiListArgs *args) { 549 UIWIDGET ui_dropdown_create(UiObject *obj, UiListArgs *args) {
544 // to simplify things and share code with ui_tableview_create, we also 550 // to simplify things and share code with ui_tableview_create, we also
545 // use a UiModel for the listview 551 // use a UiModel for the listview
546 UiModel *model = ui_model(obj->ctx, UI_STRING, "", -1); 552 UiModel *model = ui_model(obj->ctx, UI_STRING, "", -1);
547 args->model = model; 553 args->model = model;
548 554
552 if(!args->getvalue && !args->getvalue2) { 558 if(!args->getvalue && !args->getvalue2) {
553 listview->getvalue = str_getvalue; 559 listview->getvalue = str_getvalue;
554 } 560 }
555 561
556 listview->numcolumns = 1; 562 listview->numcolumns = 1;
557 listview->columns = malloc(sizeof(UiColData)); 563 listview->columns = malloc(sizeof(int));
558 listview->columns->listview = listview; 564 listview->columns[0] = 0;
559 listview->columns->data_column = 0;
560 listview->columns->model_column = 0;
561 565
562 listview->bound_rows = cxHashMapCreate(NULL, CX_STORE_POINTERS, 128); 566 listview->bound_rows = cxHashMapCreate(NULL, CX_STORE_POINTERS, 128);
563 listview->bound_rows->collection.simple_destructor = (cx_destructor_func)free; 567 listview->bound_rows->collection.simple_destructor = (cx_destructor_func)free;
564 568
565 GtkListItemFactory *factory = gtk_signal_list_item_factory_new(); 569 GtkListItemFactory *factory = gtk_signal_list_item_factory_new();
566 g_signal_connect(factory, "setup", G_CALLBACK(column_factory_setup), listview->columns); 570 g_signal_connect(factory, "setup", G_CALLBACK(column_factory_setup), &listview->coldata);
567 g_signal_connect(factory, "bind", G_CALLBACK(column_factory_bind), listview->columns); 571 g_signal_connect(factory, "bind", G_CALLBACK(column_factory_bind), &listview->coldata);
568 572
569 GtkWidget *view = gtk_drop_down_new(G_LIST_MODEL(ls), NULL); 573 GtkWidget *view = gtk_drop_down_new(G_LIST_MODEL(ls), NULL);
570 gtk_drop_down_set_factory(GTK_DROP_DOWN(view), factory); 574 gtk_drop_down_set_factory(GTK_DROP_DOWN(view), factory);
571 if(args->width > 0) { 575 if(args->width > 0) {
572 gtk_widget_set_size_request(view, args->width, -1); 576 gtk_widget_set_size_request(view, args->width, -1);
589 if(var && var->value) { 593 if(var && var->value) {
590 UiList *list = var->value; 594 UiList *list = var->value;
591 595
592 list->obj = listview; 596 list->obj = listview;
593 list->update = ui_listview_update2; 597 list->update = ui_listview_update2;
594 list->getselection = ui_combobox_getselection; 598 list->getselection = ui_dropdown_getselection;
595 list->setselection = ui_combobox_setselection; 599 list->setselection = ui_dropdown_setselection;
596 600
597 ui_update_liststore(ls, list); 601 ui_update_liststore(ls, list);
598 } else if (args->static_elements && args->static_nelm > 0) { 602 } else if (args->static_elements && args->static_nelm > 0) {
599 listview_copy_static_elements(listview, args->static_elements, args->static_nelm); 603 listview_copy_static_elements(listview, args->static_elements, args->static_nelm);
600 listview->getvalue = str_getvalue; // force string values 604 listview->getvalue = str_getvalue; // force string values
617 void ui_listview_select(UIWIDGET listview, int index) { 621 void ui_listview_select(UIWIDGET listview, int index) {
618 GtkSelectionModel *model = gtk_list_view_get_model(GTK_LIST_VIEW(listview)); 622 GtkSelectionModel *model = gtk_list_view_get_model(GTK_LIST_VIEW(listview));
619 gtk_selection_model_select_item(model, index, TRUE); 623 gtk_selection_model_select_item(model, index, TRUE);
620 } 624 }
621 625
622 void ui_combobox_select(UIWIDGET dropdown, int index) { 626 void ui_dropdown_select(UIWIDGET dropdown, int index) {
623 gtk_drop_down_set_selected(GTK_DROP_DOWN(dropdown), index); 627 gtk_drop_down_set_selected(GTK_DROP_DOWN(dropdown), index);
628 }
629
630 static void add_column(UiListView *tableview, int index) {
631 UiModel *model = tableview->model;
632
633 UiColData *col = malloc(sizeof(UiColData));
634 col->listview = tableview;
635 col->column = index;
636
637 GtkListItemFactory *factory = gtk_signal_list_item_factory_new();
638 g_signal_connect(factory, "setup", G_CALLBACK(column_factory_setup), col);
639 g_signal_connect(factory, "bind", G_CALLBACK(column_factory_bind), col);
640 g_object_set_data_full(G_OBJECT(factory), "coldata", col, (GDestroyNotify)free);
641
642 GtkColumnViewColumn *column = gtk_column_view_column_new(model->titles[index], factory);
643 gtk_column_view_column_set_resizable(column, true);
644 gtk_column_view_insert_column(GTK_COLUMN_VIEW(tableview->widget), index, column);
645
646 int size = model->columnsize[index];
647 if(size > 0) {
648 gtk_column_view_column_set_fixed_width(column, size);
649 } else if(size < 0) {
650 gtk_column_view_column_set_expand(column, TRUE);
651 }
624 } 652 }
625 653
626 UIWIDGET ui_table_create(UiObject *obj, UiListArgs *args) { 654 UIWIDGET ui_table_create(UiObject *obj, UiListArgs *args) {
627 GListStore *ls = g_list_store_new(G_TYPE_OBJECT); 655 GListStore *ls = g_list_store_new(G_TYPE_OBJECT);
628 //g_list_store_append(ls, v1); 656 //g_list_store_append(ls, v1);
648 tableview); 676 tableview);
649 677
650 678
651 // create columns from UiModel 679 // create columns from UiModel
652 UiModel *model = args->model; 680 UiModel *model = args->model;
653 int columns = model ? model->columns : 0; 681 int columns = 0;
654 682 if(model) {
655 tableview->columns = calloc(columns, sizeof(UiColData)); 683 columns = model->columns;
684 ui_model_add_observer(model, ui_listview_update_model, tableview);
685 }
686
687 tableview->columns = calloc(columns, sizeof(int));
656 tableview->numcolumns = columns; 688 tableview->numcolumns = columns;
657 689
658 tableview->bound_rows = cxHashMapCreate(NULL, CX_STORE_POINTERS, 128); 690 tableview->bound_rows = cxHashMapCreate(NULL, CX_STORE_POINTERS, 128);
659 tableview->bound_rows->collection.simple_destructor = (cx_destructor_func)free; 691 tableview->bound_rows->collection.simple_destructor = (cx_destructor_func)free;
660 692
661 int addi = 0; 693 int addi = 0;
662 for(int i=0;i<columns;i++) { 694 for(int i=0;i<columns;i++) {
663 tableview->columns[i].listview = tableview; 695 tableview->columns[i] = i+addi;
664 tableview->columns[i].model_column = i;
665 tableview->columns[i].data_column = i+addi;
666 696
667 if(model->types[i] == UI_ICON_TEXT || model->types[i] == UI_ICON_TEXT_FREE) { 697 if(model->types[i] == UI_ICON_TEXT || model->types[i] == UI_ICON_TEXT_FREE) {
668 // icon+text has 2 data columns 698 // icon+text has 2 data columns
669 addi++; 699 addi++;
670 } 700 }
671 701
672 GtkListItemFactory *factory = gtk_signal_list_item_factory_new(); 702 add_column(tableview, i);
673 UiColData *col = &tableview->columns[i];
674 g_signal_connect(factory, "setup", G_CALLBACK(column_factory_setup), col);
675 g_signal_connect(factory, "bind", G_CALLBACK(column_factory_bind), col);
676
677 GtkColumnViewColumn *column = gtk_column_view_column_new(model->titles[i], factory);
678 gtk_column_view_column_set_resizable(column, true);
679 gtk_column_view_append_column(GTK_COLUMN_VIEW(view), column);
680
681 int size = model->columnsize[i];
682 if(size > 0) {
683 gtk_column_view_column_set_fixed_width(column, size);
684 } else if(size < 0) {
685 gtk_column_view_column_set_expand(column, TRUE);
686 }
687 } 703 }
688 704
689 // bind listview to list 705 // bind listview to list
690 if(var && var->value) { 706 if(var && var->value) {
691 UiList *list = var->value; 707 UiList *list = var->value;
730 UiContainerPrivate *ct = (UiContainerPrivate*)obj->container_end; 746 UiContainerPrivate *ct = (UiContainerPrivate*)obj->container_end;
731 UiLayout layout = UI_ARGS2LAYOUT(args); 747 UiLayout layout = UI_ARGS2LAYOUT(args);
732 ct->add(ct, scroll_area, &layout); 748 ct->add(ct, scroll_area, &layout);
733 749
734 return scroll_area; 750 return scroll_area;
751 }
752
753 void ui_listview_update_model(UiModel *model, void *userdata, int insert_index, int delete_index) {
754 UiListView *listview = userdata;
755 if(insert_index >= listview->numcolumns) {
756 listview->numcolumns = insert_index+1;
757 listview->columns = realloc(listview->columns, listview->numcolumns * sizeof(UiColData));
758 }
759
760 gtk_column_view_set_model(GTK_COLUMN_VIEW(listview->widget), NULL);
761 cxMapClear(listview->bound_rows);
762
763 if(insert_index) {
764 int prev = 0;
765 if(insert_index > 0) {
766 prev = listview->columns[insert_index-1];
767 }
768 listview->columns[insert_index] = prev+1;
769 add_column(listview, insert_index);
770
771 if(insert_index+1 < listview->numcolumns) {
772 // the data index of trailing columns must be adjusted
773 UiModelType type = model->types[insert_index];
774 int add = 1;
775 if(type == UI_ICON_TEXT || type == UI_ICON_TEXT_FREE) {
776 add++;
777 }
778 for(int i=insert_index+1;i<listview->numcolumns;i++) {
779 listview->columns[i] += add;
780 }
781 }
782 } // TODO: delete_index
783
784 GListStore *ls = g_list_store_new(G_TYPE_OBJECT);
785 GtkSelectionModel *selection_model = create_selection_model(listview, ls, listview->multiselection);
786 gtk_column_view_set_model(GTK_COLUMN_VIEW(listview->widget), selection_model);
787 listview->selectionmodel = selection_model;
788 listview->liststore = ls;
789
790 if(listview->var) {
791 UiList *list = listview->var->value;
792 ui_list_update(list);
793 }
735 } 794 }
736 795
737 static UiListSelection selectionmodel_get_selection(GtkSelectionModel *model) { 796 static UiListSelection selectionmodel_get_selection(GtkSelectionModel *model) {
738 UiListSelection sel = { 0, NULL }; 797 UiListSelection sel = { 0, NULL };
739 GtkBitset *bitset = gtk_selection_model_get_selection(model); 798 GtkBitset *bitset = gtk_selection_model_get_selection(model);
858 } 917 }
859 } 918 }
860 919
861 void ui_listview_update2(UiList *list, int i) { 920 void ui_listview_update2(UiList *list, int i) {
862 UiListView *view = list->obj; 921 UiListView *view = list->obj;
922 view->current_row = -1;
863 if(i < 0) { 923 if(i < 0) {
924 cxMapClear(view->bound_rows);
864 ui_update_liststore(view->liststore, list); 925 ui_update_liststore(view->liststore, list);
865 } else { 926 } else {
866 void *value = list->get(list, i); 927 void *value = list->get(list, i);
867 if(value) { 928 if(value) {
868 ObjWrapper *obj = g_list_model_get_item(G_LIST_MODEL(view->liststore), i); 929 ObjWrapper *obj = g_list_model_get_item(G_LIST_MODEL(view->liststore), i);
871 } 932 }
872 933
873 CxHashKey row_key = cx_hash_key(&i, sizeof(int)); 934 CxHashKey row_key = cx_hash_key(&i, sizeof(int));
874 UiRowItems *row = cxMapGet(view->bound_rows, row_key); 935 UiRowItems *row = cxMapGet(view->bound_rows, row_key);
875 if(row) { 936 if(row) {
937 UiColData coldata;
938 coldata.listview = view;
876 for(int c=0;c<view->numcolumns;c++) { 939 for(int c=0;c<view->numcolumns;c++) {
877 if(row->items[c] != NULL) { 940 if(row->items[c] != NULL) {
878 column_factory_bind(NULL, row->items[c], &view->columns[c]); 941 coldata.column = c;
942 column_factory_bind(NULL, row->items[c], &coldata);
879 } 943 }
880 } 944 }
881 } 945 }
882 } 946 }
883 } 947 }
913 } 977 }
914 } 978 }
915 ui_setop_enable(FALSE); 979 ui_setop_enable(FALSE);
916 } 980 }
917 981
918 UiListSelection ui_combobox_getselection(UiList *list) { 982 UiListSelection ui_dropdown_getselection(UiList *list) {
919 UiListView *view = list->obj; 983 UiListView *view = list->obj;
920 guint selection = gtk_drop_down_get_selected(GTK_DROP_DOWN(view->widget)); 984 guint selection = gtk_drop_down_get_selected(GTK_DROP_DOWN(view->widget));
921 UiListSelection sel = { 0, NULL }; 985 UiListSelection sel = { 0, NULL };
922 if(selection != GTK_INVALID_LIST_POSITION) { 986 if(selection != GTK_INVALID_LIST_POSITION) {
923 sel.count = 1; 987 sel.count = 1;
925 sel.rows[0] = (int)selection; 989 sel.rows[0] = (int)selection;
926 } 990 }
927 return sel; 991 return sel;
928 } 992 }
929 993
930 void ui_combobox_setselection(UiList *list, UiListSelection selection) { 994 void ui_dropdown_setselection(UiList *list, UiListSelection selection) {
931 ui_setop_enable(TRUE); 995 ui_setop_enable(TRUE);
932 UiListView *view = list->obj; 996 UiListView *view = list->obj;
933 if(selection.count > 0) { 997 if(selection.count > 0) {
934 gtk_drop_down_set_selected(GTK_DROP_DOWN(view->widget), selection.rows[0]); 998 gtk_drop_down_set_selected(GTK_DROP_DOWN(view->widget), selection.rows[0]);
935 } else { 999 } else {
1154 1218
1155 UIWIDGET ui_listview_create(UiObject *obj, UiListArgs *args) { 1219 UIWIDGET ui_listview_create(UiObject *obj, UiListArgs *args) {
1156 // create treeview 1220 // create treeview
1157 GtkWidget *view = gtk_tree_view_new(); 1221 GtkWidget *view = gtk_tree_view_new();
1158 ui_set_name_and_style(view, args->name, args->style_class); 1222 ui_set_name_and_style(view, args->name, args->style_class);
1159 ui_set_widget_groups(obj->ctx, view, args->groups); 1223 ui_set_widget_states(obj->ctx, view, args->states);
1160 GtkCellRenderer *renderer = gtk_cell_renderer_text_new(); 1224 GtkCellRenderer *renderer = gtk_cell_renderer_text_new();
1161 GtkTreeViewColumn *column = gtk_tree_view_column_new_with_attributes(NULL, renderer, "text", 0, NULL); 1225 GtkTreeViewColumn *column = gtk_tree_view_column_new_with_attributes(NULL, renderer, "text", 0, NULL);
1162 gtk_tree_view_append_column(GTK_TREE_VIEW(view), column); 1226 gtk_tree_view_append_column(GTK_TREE_VIEW(view), column);
1163 1227
1164 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(view), FALSE); 1228 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(view), FALSE);
1270 GtkTreePath *path = gtk_tree_path_new_from_indicesv(&index, 1); 1334 GtkTreePath *path = gtk_tree_path_new_from_indicesv(&index, 1);
1271 gtk_tree_selection_select_path(sel, path); 1335 gtk_tree_selection_select_path(sel, path);
1272 //g_object_unref(path); 1336 //g_object_unref(path);
1273 } 1337 }
1274 1338
1275 void ui_combobox_select(UIWIDGET dropdown, int index) { 1339 void ui_dropdown_select(UIWIDGET dropdown, int index) {
1276 gtk_combo_box_set_active(GTK_COMBO_BOX(dropdown), index); 1340 gtk_combo_box_set_active(GTK_COMBO_BOX(dropdown), index);
1277 } 1341 }
1278 1342
1279 UIWIDGET ui_table_create(UiObject *obj, UiListArgs *args) { 1343 UIWIDGET ui_table_create(UiObject *obj, UiListArgs *args) {
1280 // create treeview 1344 // create treeview
1512 ui_setop_enable(FALSE); 1576 ui_setop_enable(FALSE);
1513 } 1577 }
1514 1578
1515 1579
1516 1580
1517 /* --------------------------- ComboBox --------------------------- */ 1581 /* --------------------------- Dropdown --------------------------- */
1518 1582
1519 UIWIDGET ui_combobox_create(UiObject *obj, UiListArgs *args) { 1583 UIWIDGET ui_dropdown_create(UiObject *obj, UiListArgs *args) {
1520 GtkWidget *combobox = gtk_combo_box_new(); 1584 GtkWidget *combobox = gtk_combo_box_new();
1521 if(args->width > 0) { 1585 if(args->width > 0) {
1522 gtk_widget_set_size_request(combobox, args->width, -1); 1586 gtk_widget_set_size_request(combobox, args->width, -1);
1523 } 1587 }
1524 1588
1525 ui_set_name_and_style(combobox, args->name, args->style_class); 1589 ui_set_name_and_style(combobox, args->name, args->style_class);
1526 ui_set_widget_groups(obj->ctx, combobox, args->groups); 1590 ui_set_widget_states(obj->ctx, combobox, args->states);
1527 UiContainerPrivate *ct = (UiContainerPrivate*)obj->container_end; 1591 UiContainerPrivate *ct = (UiContainerPrivate*)obj->container_end;
1528 UiLayout layout = UI_ARGS2LAYOUT(args); 1592 UiLayout layout = UI_ARGS2LAYOUT(args);
1529 ct->add(ct, combobox, &layout); 1593 ct->add(ct, combobox, &layout);
1530 1594
1531 UiListView *listview = create_listview(obj, args); 1595 UiListView *listview = create_listview(obj, args);
1542 UiList *list = var ? var->value : NULL; 1606 UiList *list = var ? var->value : NULL;
1543 GtkListStore *listmodel = create_list_store(listview, list); 1607 GtkListStore *listmodel = create_list_store(listview, list);
1544 if(var) { 1608 if(var) {
1545 listview->var = var; 1609 listview->var = var;
1546 list->update = ui_combobox_modelupdate; 1610 list->update = ui_combobox_modelupdate;
1547 list->getselection = ui_combobox_getselection; 1611 list->getselection = ui_dropdown_getselection;
1548 list->setselection = ui_combobox_setselection; 1612 list->setselection = ui_dropdown_setselection;
1549 list->obj = listview; 1613 list->obj = listview;
1550 list->update(list, -1); 1614 list->update(list, -1);
1551 } else if(args->static_nelm > 0) { 1615 } else if(args->static_nelm > 0) {
1552 listview_copy_static_elements(listview, args->static_elements, args->static_nelm); 1616 listview_copy_static_elements(listview, args->static_elements, args->static_nelm);
1553 for(int i=0;i<args->static_nelm;i++) { 1617 for(int i=0;i<args->static_nelm;i++) {
1620 GtkListStore *store = create_list_store(view, list); 1684 GtkListStore *store = create_list_store(view, list);
1621 gtk_combo_box_set_model(GTK_COMBO_BOX(view->widget), GTK_TREE_MODEL(store)); 1685 gtk_combo_box_set_model(GTK_COMBO_BOX(view->widget), GTK_TREE_MODEL(store));
1622 g_object_unref(store); 1686 g_object_unref(store);
1623 } 1687 }
1624 1688
1625 UiListSelection ui_combobox_getselection(UiList *list) { 1689 UiListSelection ui_dropdown_getselection(UiList *list) {
1626 UiListView *combobox = list->obj; 1690 UiListView *combobox = list->obj;
1627 UiListSelection ret; 1691 UiListSelection ret;
1628 ret.rows = malloc(sizeof(int*)); 1692 ret.rows = malloc(sizeof(int*));
1629 ret.count = 1; 1693 ret.count = 1;
1630 ret.rows[0] = gtk_combo_box_get_active(GTK_COMBO_BOX(combobox->widget)); 1694 ret.rows[0] = gtk_combo_box_get_active(GTK_COMBO_BOX(combobox->widget));
1631 return ret; 1695 return ret;
1632 } 1696 }
1633 1697
1634 void ui_combobox_setselection(UiList *list, UiListSelection selection) { 1698 void ui_dropdown_setselection(UiList *list, UiListSelection selection) {
1635 ui_setop_enable(TRUE); 1699 ui_setop_enable(TRUE);
1636 UiListView *combobox = list->obj; 1700 UiListView *combobox = list->obj;
1637 if(selection.count > 0) { 1701 if(selection.count > 0) {
1638 gtk_combo_box_set_active(GTK_COMBO_BOX(combobox->widget), selection.rows[0]); 1702 gtk_combo_box_set_active(GTK_COMBO_BOX(combobox->widget), selection.rows[0]);
1639 } 1703 }
2043 void ui_listview_destroy(GtkWidget *w, UiListView *v) { 2107 void ui_listview_destroy(GtkWidget *w, UiListView *v) {
2044 //gtk_tree_view_set_model(GTK_TREE_VIEW(w), NULL); 2108 //gtk_tree_view_set_model(GTK_TREE_VIEW(w), NULL);
2045 if(v->var) { 2109 if(v->var) {
2046 ui_destroy_boundvar(v->obj->ctx, v->var); 2110 ui_destroy_boundvar(v->obj->ctx, v->var);
2047 } 2111 }
2112 if(v->model) {
2113 ui_model_remove_observer(v->model, v);
2114 ui_model_unref(v->model);
2115 }
2048 if(v->elements) { 2116 if(v->elements) {
2049 for(int i=0;i<v->nelm;i++) { 2117 for(int i=0;i<v->nelm;i++) {
2050 free(v->elements[i]); 2118 free(v->elements[i]);
2051 } 2119 }
2052 free(v->elements); 2120 free(v->elements);
2158 UiListBoxSubList *sublist_ptr = cxListAt(uilistbox->sublists, cxListSize(sublists)-1); 2226 UiListBoxSubList *sublist_ptr = cxListAt(uilistbox->sublists, cxListSize(sublists)-1);
2159 if(uisublist.var && uisublist.var->value) { 2227 if(uisublist.var && uisublist.var->value) {
2160 UiList *list = uisublist.var->value; 2228 UiList *list = uisublist.var->value;
2161 list->obj = sublist_ptr; 2229 list->obj = sublist_ptr;
2162 list->update = ui_listbox_list_update; 2230 list->update = ui_listbox_list_update;
2231 list->getselection = ui_listbox_list_getselection;
2232 list->setselection = ui_listbox_list_setselection;
2163 } 2233 }
2164 } 2234 }
2165 2235
2166 UIEXPORT UIWIDGET ui_sourcelist_create(UiObject *obj, UiSourceListArgs *args) { 2236 UIEXPORT UIWIDGET ui_sourcelist_create(UiObject *obj, UiSourceListArgs *args) {
2167 #ifdef UI_GTK3 2237 #ifdef UI_GTK3
2179 gtk_list_box_set_header_func(GTK_LIST_BOX(listbox), listbox_create_header, NULL, NULL); 2249 gtk_list_box_set_header_func(GTK_LIST_BOX(listbox), listbox_create_header, NULL, NULL);
2180 GtkWidget *scroll_area = SCROLLEDWINDOW_NEW(); 2250 GtkWidget *scroll_area = SCROLLEDWINDOW_NEW();
2181 SCROLLEDWINDOW_SET_CHILD(scroll_area, listbox); 2251 SCROLLEDWINDOW_SET_CHILD(scroll_area, listbox);
2182 2252
2183 ui_set_name_and_style(listbox, args->name, args->style_class); 2253 ui_set_name_and_style(listbox, args->name, args->style_class);
2184 ui_set_widget_groups(obj->ctx, listbox, args->groups); 2254 ui_set_widget_states(obj->ctx, listbox, args->states);
2185 UiContainerPrivate *ct = (UiContainerPrivate*)obj->container_end; 2255 UiContainerPrivate *ct = (UiContainerPrivate*)obj->container_end;
2186 UiLayout layout = UI_ARGS2LAYOUT(args); 2256 UiLayout layout = UI_ARGS2LAYOUT(args);
2187 ct->add(ct, scroll_area, &layout); 2257 ct->add(ct, scroll_area, &layout);
2188 2258
2189 UiListBox *uilistbox = malloc(sizeof(UiListBox)); 2259 UiListBox *uilistbox = malloc(sizeof(UiListBox));
2221 UiVar* var = uic_widget_var(obj->ctx, obj->ctx, args->dynamic_sublist, args->varname, UI_VAR_LIST); 2291 UiVar* var = uic_widget_var(obj->ctx, obj->ctx, args->dynamic_sublist, args->varname, UI_VAR_LIST);
2222 if(var) { 2292 if(var) {
2223 UiList *list = var->value; 2293 UiList *list = var->value;
2224 list->obj = uilistbox; 2294 list->obj = uilistbox;
2225 list->update = ui_listbox_dynamic_update; 2295 list->update = ui_listbox_dynamic_update;
2296 list->getselection = ui_listbox_dynamic_getselection;
2297 list->setselection = ui_listbox_dynamic_setselection;
2226 2298
2227 ui_listbox_dynamic_update(list, -1); 2299 ui_listbox_dynamic_update(list, -1);
2228 } 2300 }
2229 } 2301 }
2230 2302
2290 add_sublist(uilistbox, new_sublists, sublist); 2362 add_sublist(uilistbox, new_sublists, sublist);
2291 sublist = list->next(list); 2363 sublist = list->next(list);
2292 } 2364 }
2293 2365
2294 ui_listbox_update(uilistbox, 0, cxListSize(uilistbox->sublists)); 2366 ui_listbox_update(uilistbox, 0, cxListSize(uilistbox->sublists));
2367 }
2368
2369 void ui_listbox_dynamic_setselection(UiList *list, UiListSelection sel) {
2370 UiListBox *uilistbox = list->obj;
2371 gtk_list_box_unselect_all(uilistbox->listbox);
2372 if(sel.count > 0) {
2373 int index = sel.rows[0];
2374 if(index >= 0) {
2375 GtkListBoxRow *row = gtk_list_box_get_row_at_index(uilistbox->listbox, index);
2376 if(row) {
2377 gtk_list_box_select_row(uilistbox->listbox, row);
2378 }
2379 }
2380 }
2381 }
2382
2383 UiListSelection ui_listbox_dynamic_getselection(UiList *list) {
2384 UiListSelection sel = { 0, NULL };
2385 UiListBox *uilistbox = list->obj;
2386 GtkListBoxRow *row = gtk_list_box_get_selected_row(uilistbox->listbox);
2387 if(row) {
2388 sel.count = 1;
2389 sel.rows = malloc(sizeof(int));
2390 sel.rows[0] = gtk_list_box_row_get_index(row);
2391 }
2392 return sel;
2295 } 2393 }
2296 2394
2297 void ui_listbox_update(UiListBox *listbox, int from, int to) { 2395 void ui_listbox_update(UiListBox *listbox, int from, int to) {
2298 CxIterator i = cxListIterator(listbox->sublists); 2396 CxIterator i = cxListIterator(listbox->sublists);
2299 size_t pos = 0; 2397 size_t pos = 0;
2657 } 2755 }
2658 2756
2659 ui_sourcelist_update_finished(); 2757 ui_sourcelist_update_finished();
2660 } 2758 }
2661 2759
2760 void ui_listbox_list_setselection(UiList *list, UiListSelection sel) {
2761 UiListBoxSubList *sublist = list->obj;
2762 UiListBox *uilistbox = sublist->listbox;
2763 gtk_list_box_unselect_all(uilistbox->listbox);
2764 if(sel.count > 0) {
2765 int index = sel.rows[0];
2766 if(index >= 0 && index < sublist->numitems) {
2767 int global_index = sublist->startpos + index;
2768 GtkListBoxRow *row = gtk_list_box_get_row_at_index(uilistbox->listbox, global_index);
2769 if(row) {
2770 gtk_list_box_select_row(uilistbox->listbox, row);
2771 }
2772 }
2773 }
2774 }
2775
2776 UiListSelection ui_listbox_list_getselection(UiList *list) {
2777 UiListSelection sel = { 0, NULL };
2778 UiListBoxSubList *sublist = list->obj;
2779 UiListBox *uilistbox = sublist->listbox;
2780 GtkListBoxRow *row = gtk_list_box_get_selected_row(uilistbox->listbox);
2781 if(row) {
2782 int index = gtk_list_box_row_get_index(row);
2783 size_t startpos = sublist->startpos;
2784 if(index >= startpos && index < startpos+sublist->numitems) {
2785 sel.count = 1;
2786 sel.rows = malloc(sizeof(int));
2787 sel.rows[0] = index - startpos;
2788 }
2789 }
2790 return sel;
2791 }
2792
2662 void ui_listbox_row_activate(GtkListBox *self, GtkListBoxRow *row, gpointer user_data) { 2793 void ui_listbox_row_activate(GtkListBox *self, GtkListBoxRow *row, gpointer user_data) {
2663 UiEventDataExt *data = g_object_get_data(G_OBJECT(row), "ui-listbox-row-eventdata"); 2794 UiEventDataExt *data = g_object_get_data(G_OBJECT(row), "ui-listbox-row-eventdata");
2664 if(!data) { 2795 if(!data) {
2665 return; 2796 return;
2666 } 2797 }

mercurial