| 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 tableview->coldata.listview = tableview; |
| |
103 tableview->coldata.column = 0; |
| |
104 |
| 101 if(args->getvalue2) { |
105 if(args->getvalue2) { |
| 102 tableview->getvalue = args->getvalue2; |
106 tableview->getvalue = args->getvalue2; |
| 103 tableview->getvaluedata = args->getvalue2data; |
107 tableview->getvaluedata = args->getvalue2data; |
| 104 } else if(args->getvalue) { |
108 } else if(args->getvalue) { |
| 105 tableview->getvalue = getvalue_wrapper; |
109 tableview->getvalue = getvalue_wrapper; |
| 198 } |
202 } |
| 199 |
203 |
| 200 static void column_factory_setup(GtkListItemFactory *factory, GtkListItem *item, gpointer userdata) { |
204 static void column_factory_setup(GtkListItemFactory *factory, GtkListItem *item, gpointer userdata) { |
| 201 UiColData *col = userdata; |
205 UiColData *col = userdata; |
| 202 UiModel *model = col->listview->model; |
206 UiModel *model = col->listview->model; |
| 203 UiModelType type = model->types[col->model_column]; |
207 UiModelType type = model->types[col->column]; |
| 204 if(type == UI_ICON_TEXT || type == UI_ICON_TEXT_FREE) { |
208 if(type == UI_ICON_TEXT || type == UI_ICON_TEXT_FREE) { |
| 205 GtkWidget *hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 6); |
209 GtkWidget *hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 6); |
| 206 GtkWidget *image = gtk_image_new(); |
210 GtkWidget *image = gtk_image_new(); |
| 207 GtkWidget *label = gtk_label_new(NULL); |
211 GtkWidget *label = gtk_label_new(NULL); |
| 208 BOX_ADD(hbox, image); |
212 BOX_ADD(hbox, image); |
| 279 |
283 |
| 280 static void column_factory_bind(GtkListItemFactory *unused, GtkListItem *item, gpointer userdata) { |
284 static void column_factory_bind(GtkListItemFactory *unused, GtkListItem *item, gpointer userdata) { |
| 281 UiColData *col = userdata; |
285 UiColData *col = userdata; |
| 282 UiList *list = col->listview->var ? col->listview->var->value : NULL; |
286 UiList *list = col->listview->var ? col->listview->var->value : NULL; |
| 283 UiListView *listview = col->listview; |
287 UiListView *listview = col->listview; |
| |
288 int datacolumn = listview->columns[col->column]; |
| 284 |
289 |
| 285 ObjWrapper *obj = gtk_list_item_get_item(item); |
290 ObjWrapper *obj = gtk_list_item_get_item(item); |
| 286 UiModel *model = col->listview->model; |
291 UiModel *model = col->listview->model; |
| 287 UiModelType type = model->types[col->model_column]; |
292 UiModelType type = model->types[col->column]; |
| 288 |
293 |
| 289 // cache the GtkListItem |
294 // cache the GtkListItem |
| 290 CxHashKey row_key = cx_hash_key(&obj->i, sizeof(int)); |
295 CxHashKey row_key = cx_hash_key(&obj->i, sizeof(int)); |
| 291 UiRowItems *row = cxMapGet(listview->bound_rows, row_key); |
296 UiRowItems *row = cxMapGet(listview->bound_rows, row_key); |
| 292 if(row) { |
297 if(row) { |
| 293 if(row->items[col->model_column] == NULL) { |
298 if(row->items[col->column] == NULL) { |
| 294 row->bound++; |
299 row->bound++; |
| 295 } |
300 } |
| 296 } else { |
301 } else { |
| 297 row = calloc(1, sizeof(UiRowItems) + listview->numcolumns * sizeof(GtkListItem*)); |
302 row = calloc(1, sizeof(UiRowItems) + listview->numcolumns * sizeof(GtkListItem*)); |
| 298 cxMapPut(listview->bound_rows, row_key, row); |
303 cxMapPut(listview->bound_rows, row_key, row); |
| 299 row->bound = 1; |
304 row->bound = 1; |
| 300 } |
305 } |
| 301 row->items[col->model_column] = item; |
306 row->items[col->column] = item; |
| 302 |
307 |
| 303 UiBool freevalue = FALSE; |
308 UiBool freevalue = FALSE; |
| 304 void *data = listview->getvalue(list, obj->data, obj->i, col->data_column, listview->getvaluedata, &freevalue); |
309 void *data = listview->getvalue(list, obj->data, obj->i, datacolumn, listview->getvaluedata, &freevalue); |
| 305 GtkWidget *child = gtk_list_item_get_child(item); |
310 GtkWidget *child = gtk_list_item_get_child(item); |
| 306 |
311 |
| 307 PangoAttrList *attributes = NULL; |
312 PangoAttrList *attributes = NULL; |
| 308 UiTextStyle style = { 0, 0 }; |
313 UiTextStyle style = { 0, 0 }; |
| 309 if(listview->getstyle) { |
314 if(listview->getstyle) { |
| 317 pango_attr_list_unref(listview->current_row_attributes); |
322 pango_attr_list_unref(listview->current_row_attributes); |
| 318 listview->current_row_attributes = textstyle2pangoattributes(style); |
323 listview->current_row_attributes = textstyle2pangoattributes(style); |
| 319 } |
324 } |
| 320 } |
325 } |
| 321 |
326 |
| 322 int style_col = col->data_column; |
327 int style_col = datacolumn; |
| 323 if(type == UI_ICON_TEXT || type == UI_ICON_TEXT_FREE) { |
328 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 |
329 style_col++; // col->data_column is the icon, we need the next col for the label |
| 325 } |
330 } |
| 326 |
331 |
| 327 // get the column style |
332 // get the column style |
| 361 } |
366 } |
| 362 case UI_ICON_TEXT: { |
367 case UI_ICON_TEXT: { |
| 363 |
368 |
| 364 } |
369 } |
| 365 case UI_ICON_TEXT_FREE: { |
370 case UI_ICON_TEXT_FREE: { |
| 366 void *data2 = listview->getvalue(list, obj->data, obj->i, col->data_column+1, listview->getvaluedata, &freevalue); |
371 void *data2 = listview->getvalue(list, obj->data, obj->i, datacolumn+1, listview->getvaluedata, &freevalue); |
| 367 if(type == UI_ICON_TEXT_FREE) { |
372 if(type == UI_ICON_TEXT_FREE) { |
| 368 freevalue = TRUE; |
373 freevalue = TRUE; |
| 369 } |
374 } |
| 370 GtkWidget *image = g_object_get_data(G_OBJECT(child), "image"); |
375 GtkWidget *image = g_object_get_data(G_OBJECT(child), "image"); |
| 371 GtkWidget *label = g_object_get_data(G_OBJECT(child), "label"); |
376 GtkWidget *label = g_object_get_data(G_OBJECT(child), "label"); |
| 385 case UI_STRING_EDITABLE: { |
390 case UI_STRING_EDITABLE: { |
| 386 UiCellEntry *entry = g_object_get_data(G_OBJECT(child), "ui_entry_data"); |
391 UiCellEntry *entry = g_object_get_data(G_OBJECT(child), "ui_entry_data"); |
| 387 if(entry) { |
392 if(entry) { |
| 388 entry->listview = col->listview; |
393 entry->listview = col->listview; |
| 389 entry->row = obj->i; |
394 entry->row = obj->i; |
| 390 entry->col = col->data_column; |
395 entry->col = datacolumn; |
| 391 entry->previous_value = strdup(data); |
396 entry->previous_value = strdup(data); |
| 392 } |
397 } |
| 393 ENTRY_SET_TEXT(child, data); |
398 ENTRY_SET_TEXT(child, data); |
| 394 break; |
399 break; |
| 395 } |
400 } |
| 409 ObjWrapper *obj = gtk_list_item_get_item(item); |
414 ObjWrapper *obj = gtk_list_item_get_item(item); |
| 410 UiListView *listview = col->listview; |
415 UiListView *listview = col->listview; |
| 411 CxHashKey row_key = cx_hash_key(&obj->i, sizeof(int)); |
416 CxHashKey row_key = cx_hash_key(&obj->i, sizeof(int)); |
| 412 UiRowItems *row = cxMapGet(listview->bound_rows, row_key); |
417 UiRowItems *row = cxMapGet(listview->bound_rows, row_key); |
| 413 if(row) { |
418 if(row) { |
| 414 row->items[col->model_column] = NULL; |
419 row->items[col->column] = NULL; |
| 415 row->bound--; |
420 row->bound--; |
| 416 if(row->bound == 0) { |
421 if(row->bound == 0) { |
| 417 cxMapRemove(listview->bound_rows, row_key); |
422 cxMapRemove(listview->bound_rows, row_key); |
| 418 } |
423 } |
| 419 } // else: should not happen |
424 } // else: should not happen |
| 455 if(!args->getvalue && !args->getvalue2) { |
460 if(!args->getvalue && !args->getvalue2) { |
| 456 listview->getvalue = str_getvalue; |
461 listview->getvalue = str_getvalue; |
| 457 } |
462 } |
| 458 |
463 |
| 459 listview->numcolumns = 1; |
464 listview->numcolumns = 1; |
| 460 listview->columns = malloc(sizeof(UiColData)); |
465 listview->columns = malloc(sizeof(int)); |
| 461 listview->columns->listview = listview; |
466 listview->columns[0] = 0; |
| 462 listview->columns->data_column = 0; |
|
| 463 listview->columns->model_column = 0; |
|
| 464 |
467 |
| 465 listview->bound_rows = cxHashMapCreate(NULL, CX_STORE_POINTERS, 128); |
468 listview->bound_rows = cxHashMapCreate(NULL, CX_STORE_POINTERS, 128); |
| 466 listview->bound_rows->collection.simple_destructor = (cx_destructor_func)free; |
469 listview->bound_rows->collection.simple_destructor = (cx_destructor_func)free; |
| 467 |
470 |
| 468 GtkListItemFactory *factory = gtk_signal_list_item_factory_new(); |
471 GtkListItemFactory *factory = gtk_signal_list_item_factory_new(); |
| 469 g_signal_connect(factory, "setup", G_CALLBACK(column_factory_setup), listview->columns); |
472 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); |
473 g_signal_connect(factory, "bind", G_CALLBACK(column_factory_bind), &listview->coldata); |
| 471 |
474 |
| 472 GtkSelectionModel *selection_model = create_selection_model(listview, ls, args->multiselection); |
475 GtkSelectionModel *selection_model = create_selection_model(listview, ls, args->multiselection); |
| 473 GtkWidget *view = gtk_list_view_new(GTK_SELECTION_MODEL(selection_model), factory); |
476 GtkWidget *view = gtk_list_view_new(GTK_SELECTION_MODEL(selection_model), factory); |
| 474 |
477 |
| 475 UiVar* var = uic_widget_var(obj->ctx, obj->ctx, args->list, args->varname, UI_VAR_LIST); |
478 UiVar* var = uic_widget_var(obj->ctx, obj->ctx, args->list, args->varname, UI_VAR_LIST); |
| 552 if(!args->getvalue && !args->getvalue2) { |
555 if(!args->getvalue && !args->getvalue2) { |
| 553 listview->getvalue = str_getvalue; |
556 listview->getvalue = str_getvalue; |
| 554 } |
557 } |
| 555 |
558 |
| 556 listview->numcolumns = 1; |
559 listview->numcolumns = 1; |
| 557 listview->columns = malloc(sizeof(UiColData)); |
560 listview->columns = malloc(sizeof(int)); |
| 558 listview->columns->listview = listview; |
561 listview->columns[0] = 0; |
| 559 listview->columns->data_column = 0; |
|
| 560 listview->columns->model_column = 0; |
|
| 561 |
562 |
| 562 listview->bound_rows = cxHashMapCreate(NULL, CX_STORE_POINTERS, 128); |
563 listview->bound_rows = cxHashMapCreate(NULL, CX_STORE_POINTERS, 128); |
| 563 listview->bound_rows->collection.simple_destructor = (cx_destructor_func)free; |
564 listview->bound_rows->collection.simple_destructor = (cx_destructor_func)free; |
| 564 |
565 |
| 565 GtkListItemFactory *factory = gtk_signal_list_item_factory_new(); |
566 GtkListItemFactory *factory = gtk_signal_list_item_factory_new(); |
| 566 g_signal_connect(factory, "setup", G_CALLBACK(column_factory_setup), listview->columns); |
567 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); |
568 g_signal_connect(factory, "bind", G_CALLBACK(column_factory_bind), &listview->coldata); |
| 568 |
569 |
| 569 GtkWidget *view = gtk_drop_down_new(G_LIST_MODEL(ls), NULL); |
570 GtkWidget *view = gtk_drop_down_new(G_LIST_MODEL(ls), NULL); |
| 570 gtk_drop_down_set_factory(GTK_DROP_DOWN(view), factory); |
571 gtk_drop_down_set_factory(GTK_DROP_DOWN(view), factory); |
| 571 if(args->width > 0) { |
572 if(args->width > 0) { |
| 572 gtk_widget_set_size_request(view, args->width, -1); |
573 gtk_widget_set_size_request(view, args->width, -1); |
| 621 |
622 |
| 622 void ui_combobox_select(UIWIDGET dropdown, int index) { |
623 void ui_combobox_select(UIWIDGET dropdown, int index) { |
| 623 gtk_drop_down_set_selected(GTK_DROP_DOWN(dropdown), index); |
624 gtk_drop_down_set_selected(GTK_DROP_DOWN(dropdown), index); |
| 624 } |
625 } |
| 625 |
626 |
| |
627 static void add_column(UiListView *tableview, int index) { |
| |
628 UiModel *model = tableview->model; |
| |
629 |
| |
630 UiColData *col = malloc(sizeof(UiColData)); |
| |
631 col->listview = tableview; |
| |
632 col->column = index; |
| |
633 |
| |
634 GtkListItemFactory *factory = gtk_signal_list_item_factory_new(); |
| |
635 g_signal_connect(factory, "setup", G_CALLBACK(column_factory_setup), col); |
| |
636 g_signal_connect(factory, "bind", G_CALLBACK(column_factory_bind), col); |
| |
637 g_object_set_data_full(G_OBJECT(factory), "coldata", col, (GDestroyNotify)free); |
| |
638 |
| |
639 GtkColumnViewColumn *column = gtk_column_view_column_new(model->titles[index], factory); |
| |
640 gtk_column_view_column_set_resizable(column, true); |
| |
641 gtk_column_view_insert_column(GTK_COLUMN_VIEW(tableview->widget), index, column); |
| |
642 |
| |
643 int size = model->columnsize[index]; |
| |
644 if(size > 0) { |
| |
645 gtk_column_view_column_set_fixed_width(column, size); |
| |
646 } else if(size < 0) { |
| |
647 gtk_column_view_column_set_expand(column, TRUE); |
| |
648 } |
| |
649 } |
| |
650 |
| 626 UIWIDGET ui_table_create(UiObject *obj, UiListArgs *args) { |
651 UIWIDGET ui_table_create(UiObject *obj, UiListArgs *args) { |
| 627 GListStore *ls = g_list_store_new(G_TYPE_OBJECT); |
652 GListStore *ls = g_list_store_new(G_TYPE_OBJECT); |
| 628 //g_list_store_append(ls, v1); |
653 //g_list_store_append(ls, v1); |
| 629 |
654 |
| 630 // create obj to store all relevant data we need for handling events |
655 // create obj to store all relevant data we need for handling events |
| 648 tableview); |
673 tableview); |
| 649 |
674 |
| 650 |
675 |
| 651 // create columns from UiModel |
676 // create columns from UiModel |
| 652 UiModel *model = args->model; |
677 UiModel *model = args->model; |
| 653 int columns = model ? model->columns : 0; |
678 int columns = 0; |
| |
679 if(model) { |
| |
680 columns = model->columns; |
| |
681 ui_model_add_observer(model, ui_listview_update_model, tableview); |
| |
682 } |
| 654 |
683 |
| 655 tableview->columns = calloc(columns, sizeof(UiColData)); |
684 tableview->columns = calloc(columns, sizeof(UiColData)); |
| 656 tableview->numcolumns = columns; |
685 tableview->numcolumns = columns; |
| 657 |
686 |
| 658 tableview->bound_rows = cxHashMapCreate(NULL, CX_STORE_POINTERS, 128); |
687 tableview->bound_rows = cxHashMapCreate(NULL, CX_STORE_POINTERS, 128); |
| 659 tableview->bound_rows->collection.simple_destructor = (cx_destructor_func)free; |
688 tableview->bound_rows->collection.simple_destructor = (cx_destructor_func)free; |
| 660 |
689 |
| 661 int addi = 0; |
690 int addi = 0; |
| 662 for(int i=0;i<columns;i++) { |
691 for(int i=0;i<columns;i++) { |
| 663 tableview->columns[i].listview = tableview; |
692 tableview->columns[i] = i+addi; |
| 664 tableview->columns[i].model_column = i; |
|
| 665 tableview->columns[i].data_column = i+addi; |
|
| 666 |
693 |
| 667 if(model->types[i] == UI_ICON_TEXT || model->types[i] == UI_ICON_TEXT_FREE) { |
694 if(model->types[i] == UI_ICON_TEXT || model->types[i] == UI_ICON_TEXT_FREE) { |
| 668 // icon+text has 2 data columns |
695 // icon+text has 2 data columns |
| 669 addi++; |
696 addi++; |
| 670 } |
697 } |
| 671 |
698 |
| 672 GtkListItemFactory *factory = gtk_signal_list_item_factory_new(); |
699 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 } |
700 } |
| 688 |
701 |
| 689 // bind listview to list |
702 // bind listview to list |
| 690 if(var && var->value) { |
703 if(var && var->value) { |
| 691 UiList *list = var->value; |
704 UiList *list = var->value; |
| 730 UiContainerPrivate *ct = (UiContainerPrivate*)obj->container_end; |
743 UiContainerPrivate *ct = (UiContainerPrivate*)obj->container_end; |
| 731 UiLayout layout = UI_ARGS2LAYOUT(args); |
744 UiLayout layout = UI_ARGS2LAYOUT(args); |
| 732 ct->add(ct, scroll_area, &layout); |
745 ct->add(ct, scroll_area, &layout); |
| 733 |
746 |
| 734 return scroll_area; |
747 return scroll_area; |
| |
748 } |
| |
749 |
| |
750 void ui_listview_update_model(UiModel *model, void *userdata, int insert_index, int delete_index) { |
| |
751 UiListView *listview = userdata; |
| |
752 if(insert_index >= listview->numcolumns) { |
| |
753 listview->numcolumns = insert_index+1; |
| |
754 listview->columns = realloc(listview->columns, listview->numcolumns * sizeof(UiColData)); |
| |
755 } |
| |
756 |
| |
757 gtk_column_view_set_model(GTK_COLUMN_VIEW(listview->widget), NULL); |
| |
758 |
| |
759 if(insert_index) { |
| |
760 listview->columns[insert_index] = insert_index; |
| |
761 add_column(listview, insert_index); |
| |
762 // TODO: adjust data_column if insert_index < numcolumns |
| |
763 } // TODO: delete_index |
| |
764 |
| |
765 GListStore *ls = g_list_store_new(G_TYPE_OBJECT); |
| |
766 GtkSelectionModel *selection_model = create_selection_model(listview, ls, listview->multiselection); |
| |
767 gtk_column_view_set_model(GTK_COLUMN_VIEW(listview->widget), selection_model); |
| |
768 listview->selectionmodel = selection_model; |
| |
769 listview->liststore = ls; |
| |
770 |
| |
771 if(listview->var) { |
| |
772 UiList *list = listview->var->value; |
| |
773 ui_list_update(list); |
| |
774 } |
| 735 } |
775 } |
| 736 |
776 |
| 737 static UiListSelection selectionmodel_get_selection(GtkSelectionModel *model) { |
777 static UiListSelection selectionmodel_get_selection(GtkSelectionModel *model) { |
| 738 UiListSelection sel = { 0, NULL }; |
778 UiListSelection sel = { 0, NULL }; |
| 739 GtkBitset *bitset = gtk_selection_model_get_selection(model); |
779 GtkBitset *bitset = gtk_selection_model_get_selection(model); |
| 2044 void ui_listview_destroy(GtkWidget *w, UiListView *v) { |
2084 void ui_listview_destroy(GtkWidget *w, UiListView *v) { |
| 2045 //gtk_tree_view_set_model(GTK_TREE_VIEW(w), NULL); |
2085 //gtk_tree_view_set_model(GTK_TREE_VIEW(w), NULL); |
| 2046 if(v->var) { |
2086 if(v->var) { |
| 2047 ui_destroy_boundvar(v->obj->ctx, v->var); |
2087 ui_destroy_boundvar(v->obj->ctx, v->var); |
| 2048 } |
2088 } |
| |
2089 if(v->model) { |
| |
2090 ui_model_remove_observer(v->model, v); |
| |
2091 ui_model_unref(v->model); |
| |
2092 } |
| 2049 if(v->elements) { |
2093 if(v->elements) { |
| 2050 for(int i=0;i<v->nelm;i++) { |
2094 for(int i=0;i<v->nelm;i++) { |
| 2051 free(v->elements[i]); |
2095 free(v->elements[i]); |
| 2052 } |
2096 } |
| 2053 free(v->elements); |
2097 free(v->elements); |