ui/gtk/list.c

changeset 965
5d4419042d9b
parent 947
a335a12936ce
child 966
e411ed7c5f10
equal deleted inserted replaced
964:c563220d9aea 965:5d4419042d9b
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);

mercurial