ui/gtk/list.c

changeset 108
77254bd6dccb
parent 103
6606616eca9f
child 109
c3dfcb8f0be7
equal deleted inserted replaced
107:b34bd1557c6c 108:77254bd6dccb
46 46
47 void* ui_strmodel_getvalue(void *elm, int column) { 47 void* ui_strmodel_getvalue(void *elm, int column) {
48 return column == 0 ? elm : NULL; 48 return column == 0 ? elm : NULL;
49 } 49 }
50 50
51 static void* model_getvalue(UiModel *model, UiList *list, void *elm, int row, int col, UiBool *freeResult) {
52 if(model->getvalue2) {
53 return model->getvalue2(list, elm, row, col, model->getvalue2data, freeResult);
54 } else if(model->getvalue) {
55 return model->getvalue(elm, col);
56 }
57 return NULL;
58 }
59
51 /* 60 /*
52 static GtkTargetEntry targetentries[] = 61 static GtkTargetEntry targetentries[] =
53 { 62 {
54 { "STRING", 0, 0 }, 63 { "STRING", 0, 0 },
55 { "text/plain", 0, 1 }, 64 { "text/plain", 0, 1 },
71 /* BEGIN GObject wrapper for generic pointers */ 80 /* BEGIN GObject wrapper for generic pointers */
72 81
73 typedef struct _ObjWrapper { 82 typedef struct _ObjWrapper {
74 GObject parent_instance; 83 GObject parent_instance;
75 void *data; 84 void *data;
85 int i;
76 } ObjWrapper; 86 } ObjWrapper;
77 87
78 typedef struct _ObjWrapperClass { 88 typedef struct _ObjWrapperClass {
79 GObjectClass parent_class; 89 GObjectClass parent_class;
80 } ObjWrapperClass; 90 } ObjWrapperClass;
87 97
88 static void obj_wrapper_init(ObjWrapper *self) { 98 static void obj_wrapper_init(ObjWrapper *self) {
89 self->data = NULL; 99 self->data = NULL;
90 } 100 }
91 101
92 ObjWrapper* obj_wrapper_new(void* data) { 102 ObjWrapper* obj_wrapper_new(void* data, int i) {
93 ObjWrapper *obj = g_object_new(obj_wrapper_get_type(), NULL); 103 ObjWrapper *obj = g_object_new(obj_wrapper_get_type(), NULL);
94 obj->data = data; 104 obj->data = data;
105 obj->i = i;
95 return obj; 106 return obj;
96 } 107 }
97 108
98 /* END GObject wrapper for generic pointers */ 109 /* END GObject wrapper for generic pointers */
99 110
120 } 131 }
121 } 132 }
122 133
123 static void column_factory_bind( GtkListItemFactory *factory, GtkListItem *item, gpointer userdata) { 134 static void column_factory_bind( GtkListItemFactory *factory, GtkListItem *item, gpointer userdata) {
124 UiColData *col = userdata; 135 UiColData *col = userdata;
136 UiList *list = col->listview->var ? col->listview->var->value : NULL;
125 137
126 ObjWrapper *obj = gtk_list_item_get_item(item); 138 ObjWrapper *obj = gtk_list_item_get_item(item);
127 UiModel *model = col->listview->model; 139 UiModel *model = col->listview->model;
128 UiModelType type = model->types[col->model_column]; 140 UiModelType type = model->types[col->model_column];
129 141
130 void *data = model->getvalue(obj->data, col->data_column); 142 UiBool freevalue = FALSE;
143 void *data = model_getvalue(model, list, obj->data, obj->i, col->data_column, &freevalue);
131 GtkWidget *child = gtk_list_item_get_child(item); 144 GtkWidget *child = gtk_list_item_get_child(item);
132 145
133 bool freevalue = TRUE;
134 switch(type) { 146 switch(type) {
147 case UI_STRING_FREE: {
148 freevalue = TRUE;
149 }
135 case UI_STRING: { 150 case UI_STRING: {
136 freevalue = FALSE;
137 }
138 case UI_STRING_FREE: {
139 gtk_label_set_label(GTK_LABEL(child), data); 151 gtk_label_set_label(GTK_LABEL(child), data);
140 if(freevalue) { 152 if(freevalue) {
141 free(data); 153 free(data);
142 } 154 }
143 break; 155 break;
155 gtk_image_set_from_paintable(GTK_IMAGE(child), GDK_PAINTABLE(icon->info)); 167 gtk_image_set_from_paintable(GTK_IMAGE(child), GDK_PAINTABLE(icon->info));
156 } 168 }
157 break; 169 break;
158 } 170 }
159 case UI_ICON_TEXT: { 171 case UI_ICON_TEXT: {
160 freevalue = FALSE; 172
161 } 173 }
162 case UI_ICON_TEXT_FREE: { 174 case UI_ICON_TEXT_FREE: {
163 void *data2 = model->getvalue(obj->data, col->data_column+1); 175 void *data2 = model_getvalue(model, list, obj->data, obj->i, col->data_column+1, &freevalue);
176 if(type == UI_ICON_TEXT_FREE) {
177 freevalue = TRUE;
178 }
164 GtkWidget *image = g_object_get_data(G_OBJECT(child), "image"); 179 GtkWidget *image = g_object_get_data(G_OBJECT(child), "image");
165 GtkWidget *label = g_object_get_data(G_OBJECT(child), "label"); 180 GtkWidget *label = g_object_get_data(G_OBJECT(child), "label");
166 if(data && image) { 181 if(data && image) {
167 UiIcon *icon = data; 182 UiIcon *icon = data;
168 gtk_image_set_from_paintable(GTK_IMAGE(image), GDK_PAINTABLE(icon->info)); 183 gtk_image_set_from_paintable(GTK_IMAGE(image), GDK_PAINTABLE(icon->info));
187 } 202 }
188 g_signal_connect(selection_model, "selection-changed", G_CALLBACK(ui_listview_selection_changed), listview); 203 g_signal_connect(selection_model, "selection-changed", G_CALLBACK(ui_listview_selection_changed), listview);
189 return selection_model; 204 return selection_model;
190 } 205 }
191 206
192 static UiListView* create_listview(UiObject *obj, UiListArgs args) { 207 static UiListView* create_listview(UiObject *obj, UiListArgs *args) {
193 UiListView *tableview = malloc(sizeof(UiListView)); 208 UiListView *tableview = malloc(sizeof(UiListView));
194 memset(tableview, 0, sizeof(UiListView)); 209 memset(tableview, 0, sizeof(UiListView));
195 tableview->obj = obj; 210 tableview->obj = obj;
196 tableview->model = args.model; 211 tableview->model = args->model;
197 tableview->onactivate = args.onactivate; 212 tableview->onactivate = args->onactivate;
198 tableview->onactivatedata = args.onactivatedata; 213 tableview->onactivatedata = args->onactivatedata;
199 tableview->onselection = args.onselection; 214 tableview->onselection = args->onselection;
200 tableview->onselectiondata = args.onselectiondata; 215 tableview->onselectiondata = args->onselectiondata;
201 tableview->ondragstart = args.ondragstart; 216 tableview->ondragstart = args->ondragstart;
202 tableview->ondragstartdata = args.ondragstartdata; 217 tableview->ondragstartdata = args->ondragstartdata;
203 tableview->ondragcomplete = args.ondragcomplete; 218 tableview->ondragcomplete = args->ondragcomplete;
204 tableview->ondragcompletedata = args.ondragcompletedata; 219 tableview->ondragcompletedata = args->ondragcompletedata;
205 tableview->ondrop = args.ondrop; 220 tableview->ondrop = args->ondrop;
206 tableview->ondropdata = args.ondropsdata; 221 tableview->ondropdata = args->ondropdata;
207 tableview->selection.count = 0; 222 tableview->selection.count = 0;
208 tableview->selection.rows = NULL; 223 tableview->selection.rows = NULL;
209 return tableview; 224 return tableview;
210 } 225 }
211 226
212 UIWIDGET ui_listview_create(UiObject *obj, UiListArgs args) { 227 UIWIDGET ui_listview_create(UiObject *obj, UiListArgs *args) {
213 UiObject* current = uic_current_obj(obj); 228 UiObject* current = uic_current_obj(obj);
214 229
215 // to simplify things and share code with ui_table_create, we also 230 // to simplify things and share code with ui_table_create, we also
216 // use a UiModel for the listview 231 // use a UiModel for the listview
217 UiModel *model = ui_model(obj->ctx, UI_STRING, "", -1); 232 UiModel *model = ui_model(obj->ctx, UI_STRING, "", -1);
218 model->getvalue = args.getvalue ? args.getvalue : ui_strmodel_getvalue; 233 if(args->getvalue2) {
219 args.model = model; 234 model->getvalue2 = args->getvalue2;
235 model->getvalue2data = args->getvalue2data;
236 } else if(args->getvalue) {
237 model->getvalue = args->getvalue;
238 } else {
239 model->getvalue = ui_strmodel_getvalue;
240 }
241 args->model = model;
220 242
221 GListStore *ls = g_list_store_new(G_TYPE_OBJECT); 243 GListStore *ls = g_list_store_new(G_TYPE_OBJECT);
222 UiListView *listview = create_listview(obj, args); 244 UiListView *listview = create_listview(obj, args);
223 245
224 listview->columns = malloc(sizeof(UiColData)); 246 listview->columns = malloc(sizeof(UiColData));
228 250
229 GtkListItemFactory *factory = gtk_signal_list_item_factory_new(); 251 GtkListItemFactory *factory = gtk_signal_list_item_factory_new();
230 g_signal_connect(factory, "setup", G_CALLBACK(column_factory_setup), listview->columns); 252 g_signal_connect(factory, "setup", G_CALLBACK(column_factory_setup), listview->columns);
231 g_signal_connect(factory, "bind", G_CALLBACK(column_factory_bind), listview->columns); 253 g_signal_connect(factory, "bind", G_CALLBACK(column_factory_bind), listview->columns);
232 254
233 GtkSelectionModel *selection_model = create_selection_model(listview, ls, args.multiselection); 255 GtkSelectionModel *selection_model = create_selection_model(listview, ls, args->multiselection);
234 GtkWidget *view = gtk_list_view_new(GTK_SELECTION_MODEL(selection_model), factory); 256 GtkWidget *view = gtk_list_view_new(GTK_SELECTION_MODEL(selection_model), factory);
235 257
236 UiVar* var = uic_widget_var(obj->ctx, current->ctx, args.list, args.varname, UI_VAR_LIST); 258 UiVar* var = uic_widget_var(obj->ctx, current->ctx, args->list, args->varname, UI_VAR_LIST);
237 259
238 // init listview 260 // init listview
239 listview->widget = view; 261 listview->widget = view;
240 listview->var = var; 262 listview->var = var;
241 listview->liststore = ls; 263 listview->liststore = ls;
254 list->update = ui_listview_update2; 276 list->update = ui_listview_update2;
255 list->getselection = ui_listview_getselection2; 277 list->getselection = ui_listview_getselection2;
256 list->setselection = ui_listview_setselection2; 278 list->setselection = ui_listview_setselection2;
257 279
258 ui_update_liststore(ls, list); 280 ui_update_liststore(ls, list);
259 } else if (args.static_elements && args.static_nelm > 0) { 281 } else if (args->static_elements && args->static_nelm > 0) {
260 listview_copy_static_elements(listview, args.static_elements, args.static_nelm); 282 listview_copy_static_elements(listview, args->static_elements, args->static_nelm);
261 listview->model->getvalue = ui_strmodel_getvalue; // force strmodel 283 listview->model->getvalue = ui_strmodel_getvalue; // force strmodel
262 ui_update_liststore_static(ls, listview->elements, listview->nelm); 284 ui_update_liststore_static(ls, listview->elements, listview->nelm);
263 } 285 }
264 286
265 // event handling 287 // event handling
266 if(args.onactivate) { 288 if(args->onactivate) {
267 // columnview and listview can use the same callback function, because 289 // columnview and listview can use the same callback function, because
268 // the first parameter (which is technically a different pointer type) 290 // the first parameter (which is technically a different pointer type)
269 // is ignored 291 // is ignored
270 g_signal_connect(view, "activate", G_CALLBACK(ui_columnview_activate), listview); 292 g_signal_connect(view, "activate", G_CALLBACK(ui_columnview_activate), listview);
293 }
294 if(args->contextmenu) {
295 UIMENU menu = ui_contextmenu_create(args->contextmenu, obj, view);
296 ui_widget_set_contextmenu(view, menu);
271 } 297 }
272 298
273 // add widget to parent 299 // add widget to parent
274 GtkWidget *scroll_area = SCROLLEDWINDOW_NEW(); 300 GtkWidget *scroll_area = SCROLLEDWINDOW_NEW();
275 gtk_scrolled_window_set_policy( 301 gtk_scrolled_window_set_policy(
276 GTK_SCROLLED_WINDOW(scroll_area), 302 GTK_SCROLLED_WINDOW(scroll_area),
277 GTK_POLICY_AUTOMATIC, 303 GTK_POLICY_AUTOMATIC,
278 GTK_POLICY_AUTOMATIC); // GTK_POLICY_ALWAYS 304 GTK_POLICY_AUTOMATIC); // GTK_POLICY_ALWAYS
279 SCROLLEDWINDOW_SET_CHILD(scroll_area, view); 305 SCROLLEDWINDOW_SET_CHILD(scroll_area, view);
280 306
281 UI_APPLY_LAYOUT1(current, args); 307 UI_APPLY_LAYOUT2(current, args);
282 current->container->add(current->container, scroll_area, FALSE); 308 current->container->add(current->container, scroll_area);
283 309
284 // ct->current should point to view, not scroll_area, to make it possible 310 // ct->current should point to view, not scroll_area, to make it possible
285 // to add a context menu 311 // to add a context menu
286 current->container->current = view; 312 current->container->current = view;
287 313
288 return scroll_area; 314 return scroll_area;
289 } 315 }
290 316
291 UIWIDGET ui_combobox_create(UiObject *obj, UiListArgs args) { 317 UIWIDGET ui_combobox_create(UiObject *obj, UiListArgs *args) {
292 UiObject* current = uic_current_obj(obj); 318 UiObject* current = uic_current_obj(obj);
293 319
294 // to simplify things and share code with ui_tableview_create, we also 320 // to simplify things and share code with ui_tableview_create, we also
295 // use a UiModel for the listview 321 // use a UiModel for the listview
296 UiModel *model = ui_model(obj->ctx, UI_STRING, "", -1); 322 UiModel *model = ui_model(obj->ctx, UI_STRING, "", -1);
297 model->getvalue = args.getvalue ? args.getvalue : ui_strmodel_getvalue; 323 if(args->getvalue2) {
298 args.model = model; 324 model->getvalue2 = args->getvalue2;
325 model->getvalue2data = args->getvalue2data;
326 } else if(args->getvalue) {
327 model->getvalue = args->getvalue;
328 } else {
329 model->getvalue = ui_strmodel_getvalue;
330 }
331 args->model = model;
299 332
300 GListStore *ls = g_list_store_new(G_TYPE_OBJECT); 333 GListStore *ls = g_list_store_new(G_TYPE_OBJECT);
301 UiListView *listview = create_listview(obj, args); 334 UiListView *listview = create_listview(obj, args);
302 335
303 listview->columns = malloc(sizeof(UiColData)); 336 listview->columns = malloc(sizeof(UiColData));
310 g_signal_connect(factory, "bind", G_CALLBACK(column_factory_bind), listview->columns); 343 g_signal_connect(factory, "bind", G_CALLBACK(column_factory_bind), listview->columns);
311 344
312 GtkWidget *view = gtk_drop_down_new(G_LIST_MODEL(ls), NULL); 345 GtkWidget *view = gtk_drop_down_new(G_LIST_MODEL(ls), NULL);
313 gtk_drop_down_set_factory(GTK_DROP_DOWN(view), factory); 346 gtk_drop_down_set_factory(GTK_DROP_DOWN(view), factory);
314 347
315 UiVar* var = uic_widget_var(obj->ctx, current->ctx, args.list, args.varname, UI_VAR_LIST); 348 UiVar* var = uic_widget_var(obj->ctx, current->ctx, args->list, args->varname, UI_VAR_LIST);
316 349
317 // init listview 350 // init listview
318 listview->widget = view; 351 listview->widget = view;
319 listview->var = var; 352 listview->var = var;
320 listview->liststore = ls; 353 listview->liststore = ls;
333 list->update = ui_listview_update2; 366 list->update = ui_listview_update2;
334 list->getselection = ui_combobox_getselection; 367 list->getselection = ui_combobox_getselection;
335 list->setselection = ui_combobox_setselection; 368 list->setselection = ui_combobox_setselection;
336 369
337 ui_update_liststore(ls, list); 370 ui_update_liststore(ls, list);
338 } else if (args.static_elements && args.static_nelm > 0) { 371 } else if (args->static_elements && args->static_nelm > 0) {
339 listview_copy_static_elements(listview, args.static_elements, args.static_nelm); 372 listview_copy_static_elements(listview, args->static_elements, args->static_nelm);
340 listview->model->getvalue = ui_strmodel_getvalue; // force strmodel 373 listview->model->getvalue = ui_strmodel_getvalue; // force strmodel
341 ui_update_liststore_static(ls, listview->elements, listview->nelm); 374 ui_update_liststore_static(ls, listview->elements, listview->nelm);
342 } 375 }
343 376
344 // event handling 377 // event handling
345 if(args.onactivate) { 378 if(args->onactivate) {
346 g_signal_connect(view, "notify::selected", G_CALLBACK(ui_dropdown_notify), listview); 379 g_signal_connect(view, "notify::selected", G_CALLBACK(ui_dropdown_notify), listview);
347 } 380 }
348 381
349 // add widget to parent 382 // add widget to parent
350 UI_APPLY_LAYOUT1(current, args); 383 UI_APPLY_LAYOUT2(current, args);
351 current->container->add(current->container, view, FALSE); 384 current->container->add(current->container, view);
352 return view; 385 return view;
353 } 386 }
354 387
355 void ui_listview_select(UIWIDGET listview, int index) { 388 void ui_listview_select(UIWIDGET listview, int index) {
356 GtkSelectionModel *model = gtk_list_view_get_model(GTK_LIST_VIEW(listview)); 389 GtkSelectionModel *model = gtk_list_view_get_model(GTK_LIST_VIEW(listview));
359 392
360 void ui_combobox_select(UIWIDGET dropdown, int index) { 393 void ui_combobox_select(UIWIDGET dropdown, int index) {
361 gtk_drop_down_set_selected(GTK_DROP_DOWN(dropdown), index); 394 gtk_drop_down_set_selected(GTK_DROP_DOWN(dropdown), index);
362 } 395 }
363 396
364 UIWIDGET ui_table_create(UiObject *obj, UiListArgs args) { 397 UIWIDGET ui_table_create(UiObject *obj, UiListArgs *args) {
365 UiObject* current = uic_current_obj(obj); 398 UiObject* current = uic_current_obj(obj);
366 399
367 GListStore *ls = g_list_store_new(G_TYPE_OBJECT); 400 GListStore *ls = g_list_store_new(G_TYPE_OBJECT);
368 //g_list_store_append(ls, v1); 401 //g_list_store_append(ls, v1);
369 402
370 // create obj to store all relevant data we need for handling events 403 // create obj to store all relevant data we need for handling events
371 // and list updates 404 // and list updates
372 UiListView *tableview = create_listview(obj, args); 405 UiListView *tableview = create_listview(obj, args);
373 406
374 GtkSelectionModel *selection_model = create_selection_model(tableview, ls, args.multiselection); 407 GtkSelectionModel *selection_model = create_selection_model(tableview, ls, args->multiselection);
375 GtkWidget *view = gtk_column_view_new(GTK_SELECTION_MODEL(selection_model)); 408 GtkWidget *view = gtk_column_view_new(GTK_SELECTION_MODEL(selection_model));
376 409
377 UiVar* var = uic_widget_var(obj->ctx, current->ctx, args.list, args.varname, UI_VAR_LIST); 410 UiVar* var = uic_widget_var(obj->ctx, current->ctx, args->list, args->varname, UI_VAR_LIST);
378 411
379 // init tableview 412 // init tableview
380 tableview->widget = view; 413 tableview->widget = view;
381 tableview->var = var; 414 tableview->var = var;
382 tableview->liststore = ls; 415 tableview->liststore = ls;
387 G_CALLBACK(ui_listview_destroy), 420 G_CALLBACK(ui_listview_destroy),
388 tableview); 421 tableview);
389 422
390 423
391 // create columns from UiModel 424 // create columns from UiModel
392 UiModel *model = args.model; 425 UiModel *model = args->model;
393 int columns = model ? model->columns : 0; 426 int columns = model ? model->columns : 0;
394 427
395 tableview->columns = calloc(columns, sizeof(UiColData)); 428 tableview->columns = calloc(columns, sizeof(UiColData));
396 429
397 int addi = 0; 430 int addi = 0;
433 466
434 ui_update_liststore(ls, list); 467 ui_update_liststore(ls, list);
435 } 468 }
436 469
437 // event handling 470 // event handling
438 if(args.onactivate) { 471 if(args->onactivate) {
439 g_signal_connect(view, "activate", G_CALLBACK(ui_columnview_activate), tableview); 472 g_signal_connect(view, "activate", G_CALLBACK(ui_columnview_activate), tableview);
473 }
474 if(args->contextmenu) {
475 UIMENU menu = ui_contextmenu_create(args->contextmenu, obj, view);
476 ui_widget_set_contextmenu(view, menu);
440 } 477 }
441 478
442 // add widget to parent 479 // add widget to parent
443 GtkWidget *scroll_area = SCROLLEDWINDOW_NEW(); 480 GtkWidget *scroll_area = SCROLLEDWINDOW_NEW();
444 gtk_scrolled_window_set_policy( 481 gtk_scrolled_window_set_policy(
445 GTK_SCROLLED_WINDOW(scroll_area), 482 GTK_SCROLLED_WINDOW(scroll_area),
446 GTK_POLICY_AUTOMATIC, 483 GTK_POLICY_AUTOMATIC,
447 GTK_POLICY_AUTOMATIC); // GTK_POLICY_ALWAYS 484 GTK_POLICY_AUTOMATIC); // GTK_POLICY_ALWAYS
448 SCROLLEDWINDOW_SET_CHILD(scroll_area, view); 485 SCROLLEDWINDOW_SET_CHILD(scroll_area, view);
449 486
450 UI_APPLY_LAYOUT1(current, args); 487 UI_APPLY_LAYOUT2(current, args);
451 current->container->add(current->container, scroll_area, FALSE); 488 current->container->add(current->container, scroll_area);
452 489
453 // ct->current should point to view, not scroll_area, to make it possible 490 // ct->current should point to view, not scroll_area, to make it possible
454 // to add a context menu 491 // to add a context menu
455 current->container->current = view; 492 current->container->current = view;
456 493
472 event.obj = view->obj; 509 event.obj = view->obj;
473 event.document = event.obj->ctx->document; 510 event.document = event.obj->ctx->document;
474 event.window = event.obj->window; 511 event.window = event.obj->window;
475 event.intval = view->selection.count; 512 event.intval = view->selection.count;
476 event.eventdata = &view->selection; 513 event.eventdata = &view->selection;
514 event.eventdatatype = UI_EVENT_DATA_LIST_SELECTION;
477 event.set = ui_get_setop(); 515 event.set = ui_get_setop();
478 if(cb) { 516 if(cb) {
479 cb(&event, cbdata); 517 cb(&event, cbdata);
480 } 518 }
481 } 519 }
515 event.obj = view->obj; 553 event.obj = view->obj;
516 event.document = event.obj->ctx->document; 554 event.document = event.obj->ctx->document;
517 event.window = event.obj->window; 555 event.window = event.obj->window;
518 event.intval = index; 556 event.intval = index;
519 event.eventdata = eventdata->data; 557 event.eventdata = eventdata->data;
558 event.eventdatatype = UI_EVENT_DATA_LIST_ELM;
520 event.set = ui_get_setop(); 559 event.set = ui_get_setop();
521 view->onactivate(&event, view->onactivatedata); 560 view->onactivate(&event, view->onactivatedata);
522 } 561 }
523 } 562 }
524 563
552 event.obj = view->obj; 591 event.obj = view->obj;
553 event.document = event.obj->ctx->document; 592 event.document = event.obj->ctx->document;
554 event.window = event.obj->window; 593 event.window = event.obj->window;
555 event.intval = view->selection.count; 594 event.intval = view->selection.count;
556 event.eventdata = &view->selection; 595 event.eventdata = &view->selection;
596 event.eventdatatype = UI_EVENT_DATA_LIST_SELECTION;
557 event.set = ui_get_setop(); 597 event.set = ui_get_setop();
558 view->onactivate(&event, view->onactivatedata); 598 view->onactivate(&event, view->onactivatedata);
559 } 599 }
560 } 600 }
561 601
562 void ui_update_liststore(GListStore *liststore, UiList *list) { 602 void ui_update_liststore(GListStore *liststore, UiList *list) {
563 g_list_store_remove_all(liststore); 603 g_list_store_remove_all(liststore);
604 int i = 0;
564 void *elm = list->first(list); 605 void *elm = list->first(list);
565 while(elm) { 606 while(elm) {
566 ObjWrapper *obj = obj_wrapper_new(elm); 607 ObjWrapper *obj = obj_wrapper_new(elm, i++);
567 g_list_store_append(liststore, obj); 608 g_list_store_append(liststore, obj);
568 elm = list->next(list); 609 elm = list->next(list);
569 } 610 }
570 } 611 }
571 612
572 void ui_update_liststore_static(GListStore *liststore, char **elm, size_t nelm) { 613 void ui_update_liststore_static(GListStore *liststore, char **elm, size_t nelm) {
573 g_list_store_remove_all(liststore); 614 g_list_store_remove_all(liststore);
574 for(int i=0;i<nelm;i++) { 615 for(int i=0;i<nelm;i++) {
575 ObjWrapper *obj = obj_wrapper_new(elm[i]); 616 ObjWrapper *obj = obj_wrapper_new(elm[i], i);
576 g_list_store_append(liststore, obj); 617 g_list_store_append(liststore, obj);
577 } 618 }
578 } 619 }
579 620
580 void ui_listview_update2(UiList *list, int i) { 621 void ui_listview_update2(UiList *list, int i) {
582 if(i < 0) { 623 if(i < 0) {
583 ui_update_liststore(view->liststore, list); 624 ui_update_liststore(view->liststore, list);
584 } else { 625 } else {
585 void *value = list->get(list, i); 626 void *value = list->get(list, i);
586 if(value) { 627 if(value) {
587 ObjWrapper *obj = obj_wrapper_new(value); 628 ObjWrapper *obj = obj_wrapper_new(value, i);
588 // TODO: if index i is selected, the selection is lost 629 // TODO: if index i is selected, the selection is lost
589 // is it possible to update the item without removing it? 630 // is it possible to update the item without removing it?
590 g_list_store_splice(view->liststore, i, 1, (void **)&obj, 1); 631 int count = g_list_model_get_n_items(G_LIST_MODEL(view->liststore));
632 if(count <= i) {
633 g_list_store_splice(view->liststore, i, 0, (void **)&obj, 1);
634 } else {
635 g_list_store_splice(view->liststore, i, 1, (void **)&obj, 1);
636 }
591 } 637 }
592 } 638 }
593 } 639 }
594 640
595 UiListSelection ui_listview_getselection2(UiList *list) { 641 UiListSelection ui_listview_getselection2(UiList *list) {
647 ui_setop_enable(FALSE); 693 ui_setop_enable(FALSE);
648 } 694 }
649 695
650 #else 696 #else
651 697
652 static void update_list_row(GtkListStore *store, GtkTreeIter *iter, UiModel *model, void *elm) { 698 static void update_list_row(GtkListStore *store, GtkTreeIter *iter, UiModel *model, UiList *list, void *elm, int row) {
653 // set column values 699 // set column values
654 int c = 0; 700 int c = 0;
655 for(int i=0;i<model->columns;i++,c++) { 701 for(int i=0;i<model->columns;i++,c++) {
656 void *data = model->getvalue(elm, c); 702 UiBool freevalue = FALSE;
703 void *data = model_getvalue(model, list, elm, row, c, &freevalue);
657 704
658 GValue value = G_VALUE_INIT; 705 GValue value = G_VALUE_INIT;
659 switch(model->types[i]) { 706 switch(model->types[i]) {
660 case UI_STRING:
661 case UI_STRING_FREE: { 707 case UI_STRING_FREE: {
708 freevalue = TRUE;
709 }
710 case UI_STRING: {
662 g_value_init(&value, G_TYPE_STRING); 711 g_value_init(&value, G_TYPE_STRING);
663 g_value_set_string(&value, data); 712 g_value_set_string(&value, data);
664 if(model->types[i] == UI_STRING_FREE) { 713 if(freevalue) {
665 free(data); 714 free(data);
666 } 715 }
667 break; 716 break;
668 } 717 }
669 case UI_INTEGER: { 718 case UI_INTEGER: {
712 g_value_set_object(&pixbufvalue, icon->pixbuf); 761 g_value_set_object(&pixbufvalue, icon->pixbuf);
713 gtk_list_store_set_value(store, iter, c, &pixbufvalue); 762 gtk_list_store_set_value(store, iter, c, &pixbufvalue);
714 } 763 }
715 #endif 764 #endif
716 c++; 765 c++;
717 766
718 char *str = model->getvalue(elm, c); 767 freevalue = FALSE;
768 char *str = model_getvalue(model, list, elm, row, c, &freevalue);
719 g_value_init(&value, G_TYPE_STRING); 769 g_value_init(&value, G_TYPE_STRING);
720 g_value_set_string(&value, str); 770 g_value_set_string(&value, str);
721 if(model->types[i] == UI_ICON_TEXT_FREE) { 771 if(model->types[i] == UI_ICON_TEXT_FREE || freevalue) {
722 free(str); 772 free(str);
723 } 773 }
724 break; 774 break;
725 } 775 }
726 } 776 }
749 799
750 GtkListStore *store = gtk_list_store_newv(c, types); 800 GtkListStore *store = gtk_list_store_newv(c, types);
751 801
752 if(list) { 802 if(list) {
753 void *elm = list->first(list); 803 void *elm = list->first(list);
804 int i = 0;
754 while(elm) { 805 while(elm) {
755 // insert new row 806 // insert new row
756 GtkTreeIter iter; 807 GtkTreeIter iter;
757 gtk_list_store_insert (store, &iter, -1); 808 gtk_list_store_insert (store, &iter, -1);
758 809
759 update_list_row(store, &iter, model, elm); 810 update_list_row(store, &iter, model, list, elm, i++);
760 811
761 // next row 812 // next row
762 elm = list->next(list); 813 elm = list->next(list);
763 } 814 }
764 } 815 }
765 816
766 return store; 817 return store;
767 } 818 }
768 819
769 820
770 UIWIDGET ui_listview_create(UiObject *obj, UiListArgs args) { 821 UIWIDGET ui_listview_create(UiObject *obj, UiListArgs *args) {
771 UiObject* current = uic_current_obj(obj); 822 UiObject* current = uic_current_obj(obj);
772 823
773 // create treeview 824 // create treeview
774 GtkWidget *view = gtk_tree_view_new(); 825 GtkWidget *view = gtk_tree_view_new();
775 ui_set_name_and_style(view, args.name, args.style_class); 826 ui_set_name_and_style(view, args->name, args->style_class);
776 ui_set_widget_groups(obj->ctx, view, args.groups); 827 ui_set_widget_groups(obj->ctx, view, args->groups);
777 GtkCellRenderer *renderer = gtk_cell_renderer_text_new(); 828 GtkCellRenderer *renderer = gtk_cell_renderer_text_new();
778 GtkTreeViewColumn *column = gtk_tree_view_column_new_with_attributes(NULL, renderer, "text", 0, NULL); 829 GtkTreeViewColumn *column = gtk_tree_view_column_new_with_attributes(NULL, renderer, "text", 0, NULL);
779 gtk_tree_view_append_column(GTK_TREE_VIEW(view), column); 830 gtk_tree_view_append_column(GTK_TREE_VIEW(view), column);
780 831
781 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(view), FALSE); 832 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(view), FALSE);
788 #else 839 #else
789 // TODO: implement for gtk2 840 // TODO: implement for gtk2
790 #endif 841 #endif
791 842
792 UiModel *model = ui_model(obj->ctx, UI_STRING, "", -1); 843 UiModel *model = ui_model(obj->ctx, UI_STRING, "", -1);
793 model->getvalue = args.getvalue ? args.getvalue : ui_strmodel_getvalue; 844 if(args->getvalue2) {
794 845 model->getvalue2 = args->getvalue2;
795 UiVar* var = uic_widget_var(obj->ctx, current->ctx, args.list, args.varname, UI_VAR_LIST); 846 model->getvalue2data = args->getvalue2data;
847 } else if(args->getvalue) {
848 model->getvalue = args->getvalue;
849 } else {
850 model->getvalue = ui_strmodel_getvalue;
851 }
852
853 UiVar* var = uic_widget_var(obj->ctx, current->ctx, args->list, args->varname, UI_VAR_LIST);
796 854
797 UiList *list = var ? var->value : NULL; 855 UiList *list = var ? var->value : NULL;
798 GtkListStore *listmodel = create_list_store(list, model); 856 GtkListStore *listmodel = create_list_store(list, model);
799 gtk_tree_view_set_model(GTK_TREE_VIEW(view), GTK_TREE_MODEL(listmodel)); 857 gtk_tree_view_set_model(GTK_TREE_VIEW(view), GTK_TREE_MODEL(listmodel));
800 g_object_unref(listmodel); 858 g_object_unref(listmodel);
820 list->obj = listview; 878 list->obj = listview;
821 879
822 // add callback 880 // add callback
823 UiTreeEventData *event = malloc(sizeof(UiTreeEventData)); 881 UiTreeEventData *event = malloc(sizeof(UiTreeEventData));
824 event->obj = obj; 882 event->obj = obj;
825 event->activate = args.onactivate; 883 event->activate = args->onactivate;
826 event->activatedata = args.onactivatedata; 884 event->activatedata = args->onactivatedata;
827 event->selection = args.onselection; 885 event->selection = args->onselection;
828 event->selectiondata = args.onselectiondata; 886 event->selectiondata = args->onselectiondata;
829 g_signal_connect( 887 g_signal_connect(
830 view, 888 view,
831 "destroy", 889 "destroy",
832 G_CALLBACK(ui_destroy_userdata), 890 G_CALLBACK(ui_destroy_userdata),
833 event); 891 event);
834 892
835 if(args.onactivate) { 893 if(args->onactivate) {
836 g_signal_connect( 894 g_signal_connect(
837 view, 895 view,
838 "row-activated", 896 "row-activated",
839 G_CALLBACK(ui_listview_activate_event), 897 G_CALLBACK(ui_listview_activate_event),
840 event); 898 event);
841 } 899 }
842 if(args.onselection) { 900 if(args->onselection) {
843 GtkTreeSelection *selection = gtk_tree_view_get_selection( 901 GtkTreeSelection *selection = gtk_tree_view_get_selection(
844 GTK_TREE_VIEW(view)); 902 GTK_TREE_VIEW(view));
845 g_signal_connect( 903 g_signal_connect(
846 selection, 904 selection,
847 "changed", 905 "changed",
848 G_CALLBACK(ui_listview_selection_event), 906 G_CALLBACK(ui_listview_selection_event),
849 event); 907 event);
850 } 908 }
851 if(args.contextmenu) { 909 if(args->contextmenu) {
852 UIMENU menu = ui_contextmenu_create(args.contextmenu, obj, view); 910 UIMENU menu = ui_contextmenu_create(args->contextmenu, obj, view);
853 ui_widget_set_contextmenu(view, menu); 911 ui_widget_set_contextmenu(view, menu);
854 } 912 }
855 913
856 914
857 // add widget to the current container 915 // add widget to the current container
860 GTK_SCROLLED_WINDOW(scroll_area), 918 GTK_SCROLLED_WINDOW(scroll_area),
861 GTK_POLICY_AUTOMATIC, 919 GTK_POLICY_AUTOMATIC,
862 GTK_POLICY_AUTOMATIC); // GTK_POLICY_ALWAYS 920 GTK_POLICY_AUTOMATIC); // GTK_POLICY_ALWAYS
863 SCROLLEDWINDOW_SET_CHILD(scroll_area, view); 921 SCROLLEDWINDOW_SET_CHILD(scroll_area, view);
864 922
865 UI_APPLY_LAYOUT1(current, args); 923 UI_APPLY_LAYOUT2(current, args);
866 current->container->add(current->container, scroll_area, FALSE); 924 current->container->add(current->container, scroll_area, FALSE);
867 925
868 // ct->current should point to view, not scroll_area, to make it possible 926 // ct->current should point to view, not scroll_area, to make it possible
869 // to add a context menu 927 // to add a context menu
870 current->container->current = view; 928 current->container->current = view;
881 939
882 void ui_combobox_select(UIWIDGET dropdown, int index) { 940 void ui_combobox_select(UIWIDGET dropdown, int index) {
883 gtk_combo_box_set_active(GTK_COMBO_BOX(dropdown), index); 941 gtk_combo_box_set_active(GTK_COMBO_BOX(dropdown), index);
884 } 942 }
885 943
886 UIWIDGET ui_table_create(UiObject *obj, UiListArgs args) { 944 UIWIDGET ui_table_create(UiObject *obj, UiListArgs *args) {
887 UiObject* current = uic_current_obj(obj); 945 UiObject* current = uic_current_obj(obj);
888 946
889 // create treeview 947 // create treeview
890 GtkWidget *view = gtk_tree_view_new(); 948 GtkWidget *view = gtk_tree_view_new();
891 949
892 UiModel *model = args.model; 950 UiModel *model = args->model;
893 int columns = model ? model->columns : 0; 951 int columns = model ? model->columns : 0;
894 952
895 int addi = 0; 953 int addi = 0;
896 for(int i=0;i<columns;i++) { 954 for(int i=0;i<columns;i++) {
897 GtkTreeViewColumn *column = NULL; 955 GtkTreeViewColumn *column = NULL;
944 //gtk_tree_view_set_activate_on_single_click(GTK_TREE_VIEW(view), TRUE); 1002 //gtk_tree_view_set_activate_on_single_click(GTK_TREE_VIEW(view), TRUE);
945 #else 1003 #else
946 1004
947 #endif 1005 #endif
948 1006
949 UiVar* var = uic_widget_var(obj->ctx, current->ctx, args.list, args.varname, UI_VAR_LIST); 1007 UiVar* var = uic_widget_var(obj->ctx, current->ctx, args->list, args->varname, UI_VAR_LIST);
950 1008
951 UiList *list = var ? var->value : NULL; 1009 UiList *list = var ? var->value : NULL;
952 GtkListStore *listmodel = create_list_store(list, model); 1010 GtkListStore *listmodel = create_list_store(list, model);
953 gtk_tree_view_set_model(GTK_TREE_VIEW(view), GTK_TREE_MODEL(listmodel)); 1011 gtk_tree_view_set_model(GTK_TREE_VIEW(view), GTK_TREE_MODEL(listmodel));
954 g_object_unref(listmodel); 1012 g_object_unref(listmodel);
962 memset(tableview, 0, sizeof(UiListView)); 1020 memset(tableview, 0, sizeof(UiListView));
963 tableview->obj = obj; 1021 tableview->obj = obj;
964 tableview->widget = view; 1022 tableview->widget = view;
965 tableview->var = var; 1023 tableview->var = var;
966 tableview->model = model; 1024 tableview->model = model;
967 tableview->ondragstart = args.ondragstart; 1025 tableview->ondragstart = args->ondragstart;
968 tableview->ondragstartdata = args.ondragstartdata; 1026 tableview->ondragstartdata = args->ondragstartdata;
969 tableview->ondragcomplete = args.ondragcomplete; 1027 tableview->ondragcomplete = args->ondragcomplete;
970 tableview->ondragcompletedata = args.ondragcompletedata; 1028 tableview->ondragcompletedata = args->ondragcompletedata;
971 tableview->ondrop = args.ondrop; 1029 tableview->ondrop = args->ondrop;
972 tableview->ondropdata = args.ondropsdata; 1030 tableview->ondropdata = args->ondropdata;
973 tableview->selection.count = 0; 1031 tableview->selection.count = 0;
974 tableview->selection.rows = NULL; 1032 tableview->selection.rows = NULL;
975 g_signal_connect( 1033 g_signal_connect(
976 view, 1034 view,
977 "destroy", 1035 "destroy",
985 list->obj = tableview; 1043 list->obj = tableview;
986 1044
987 // add callback 1045 // add callback
988 UiTreeEventData *event = ui_malloc(obj->ctx, sizeof(UiTreeEventData)); 1046 UiTreeEventData *event = ui_malloc(obj->ctx, sizeof(UiTreeEventData));
989 event->obj = obj; 1047 event->obj = obj;
990 event->activate = args.onactivate; 1048 event->activate = args->onactivate;
991 event->selection = args.onselection; 1049 event->selection = args->onselection;
992 event->activatedata = args.onactivatedata; 1050 event->activatedata = args->onactivatedata;
993 event->selectiondata = args.onselectiondata; 1051 event->selectiondata = args->onselectiondata;
994 if(args.onactivate) { 1052 if(args->onactivate) {
995 g_signal_connect( 1053 g_signal_connect(
996 view, 1054 view,
997 "row-activated", 1055 "row-activated",
998 G_CALLBACK(ui_listview_activate_event), 1056 G_CALLBACK(ui_listview_activate_event),
999 event); 1057 event);
1000 } 1058 }
1001 if(args.onselection) { 1059 if(args->onselection) {
1002 GtkTreeSelection *selection = gtk_tree_view_get_selection( 1060 GtkTreeSelection *selection = gtk_tree_view_get_selection(
1003 GTK_TREE_VIEW(view)); 1061 GTK_TREE_VIEW(view));
1004 g_signal_connect( 1062 g_signal_connect(
1005 selection, 1063 selection,
1006 "changed", 1064 "changed",
1008 event); 1066 event);
1009 } 1067 }
1010 // TODO: destroy callback 1068 // TODO: destroy callback
1011 1069
1012 1070
1013 if(args.ondragstart) { 1071 if(args->ondragstart) {
1014 ui_listview_add_dnd(tableview, &args); 1072 ui_listview_add_dnd(tableview, args);
1015 } 1073 }
1016 if(args.ondrop) { 1074 if(args->ondrop) {
1017 ui_listview_enable_drop(tableview, &args); 1075 ui_listview_enable_drop(tableview, args);
1018 } 1076 }
1019 1077
1020 GtkTreeSelection *selection = gtk_tree_view_get_selection (GTK_TREE_VIEW(view)); 1078 GtkTreeSelection *selection = gtk_tree_view_get_selection (GTK_TREE_VIEW(view));
1021 if(args.multiselection) { 1079 if(args->multiselection) {
1022 gtk_tree_selection_set_mode(selection, GTK_SELECTION_MULTIPLE); 1080 gtk_tree_selection_set_mode(selection, GTK_SELECTION_MULTIPLE);
1023 } 1081 }
1024 1082
1025 // add widget to the current container 1083 // add widget to the current container
1026 GtkWidget *scroll_area = SCROLLEDWINDOW_NEW(); 1084 GtkWidget *scroll_area = SCROLLEDWINDOW_NEW();
1028 GTK_SCROLLED_WINDOW(scroll_area), 1086 GTK_SCROLLED_WINDOW(scroll_area),
1029 GTK_POLICY_AUTOMATIC, 1087 GTK_POLICY_AUTOMATIC,
1030 GTK_POLICY_AUTOMATIC); // GTK_POLICY_ALWAYS 1088 GTK_POLICY_AUTOMATIC); // GTK_POLICY_ALWAYS
1031 SCROLLEDWINDOW_SET_CHILD(scroll_area, view); 1089 SCROLLEDWINDOW_SET_CHILD(scroll_area, view);
1032 1090
1033 if(args.contextmenu) { 1091 if(args->contextmenu) {
1034 UIMENU menu = ui_contextmenu_create(args.contextmenu, obj, scroll_area); 1092 UIMENU menu = ui_contextmenu_create(args->contextmenu, obj, scroll_area);
1035 #if GTK_MAJOR_VERSION >= 4 1093 #if GTK_MAJOR_VERSION >= 4
1036 ui_widget_set_contextmenu(scroll_area, menu); 1094 ui_widget_set_contextmenu(scroll_area, menu);
1037 #else 1095 #else
1038 ui_widget_set_contextmenu(view, menu); 1096 ui_widget_set_contextmenu(view, menu);
1039 #endif 1097 #endif
1040 } 1098 }
1041 1099
1042 UI_APPLY_LAYOUT1(current, args); 1100 UI_APPLY_LAYOUT2(current, args);
1043 current->container->add(current->container, scroll_area, FALSE); 1101 current->container->add(current->container, scroll_area, FALSE);
1044 1102
1045 // ct->current should point to view, not scroll_area, to make it possible 1103 // ct->current should point to view, not scroll_area, to make it possible
1046 // to add a context menu 1104 // to add a context menu
1047 current->container->current = view; 1105 current->container->current = view;
1060 } else { 1118 } else {
1061 void *elm = list->get(list, i); 1119 void *elm = list->get(list, i);
1062 GtkTreeModel *store = gtk_tree_view_get_model(GTK_TREE_VIEW(view->widget)); 1120 GtkTreeModel *store = gtk_tree_view_get_model(GTK_TREE_VIEW(view->widget));
1063 GtkTreeIter iter; 1121 GtkTreeIter iter;
1064 if(gtk_tree_model_iter_nth_child(store, &iter, NULL, i)) { 1122 if(gtk_tree_model_iter_nth_child(store, &iter, NULL, i)) {
1065 update_list_row(GTK_LIST_STORE(store), &iter, view->model, elm); 1123 update_list_row(GTK_LIST_STORE(store), &iter, view->model, list, elm, i);
1066 } 1124 }
1067 } 1125 }
1068 } 1126 }
1069 1127
1070 UiListSelection ui_listview_getselection(UiList *list) { 1128 UiListSelection ui_listview_getselection(UiList *list) {
1087 1145
1088 1146
1089 1147
1090 /* --------------------------- ComboBox --------------------------- */ 1148 /* --------------------------- ComboBox --------------------------- */
1091 1149
1092 UIWIDGET ui_combobox_create(UiObject *obj, UiListArgs args) { 1150 UIWIDGET ui_combobox_create(UiObject *obj, UiListArgs *args) {
1093 UiObject* current = uic_current_obj(obj); 1151 UiObject* current = uic_current_obj(obj);
1094 1152
1095 UiModel *model = ui_model(obj->ctx, UI_STRING, "", -1); 1153 UiModel *model = ui_model(obj->ctx, UI_STRING, "", -1);
1096 model->getvalue = args.getvalue ? args.getvalue : ui_strmodel_getvalue; 1154 if(args->getvalue2) {
1097 1155 model->getvalue2 = args->getvalue2;
1098 UiVar* var = uic_widget_var(obj->ctx, current->ctx, args.list, args.varname, UI_VAR_LIST); 1156 model->getvalue2data = args->getvalue2data;
1099 1157 } else if(args->getvalue) {
1100 GtkWidget *combobox = ui_create_combobox(obj, model, var, args.static_elements, args.static_nelm, args.onactivate, args.onactivatedata); 1158 model->getvalue = args->getvalue;
1101 ui_set_name_and_style(combobox, args.name, args.style_class); 1159 } else {
1102 ui_set_widget_groups(obj->ctx, combobox, args.groups); 1160 model->getvalue = ui_strmodel_getvalue;
1103 UI_APPLY_LAYOUT1(current, args); 1161 }
1162
1163 UiVar* var = uic_widget_var(obj->ctx, current->ctx, args->list, args->varname, UI_VAR_LIST);
1164
1165 GtkWidget *combobox = ui_create_combobox(obj, model, var, args->static_elements, args->static_nelm, args->onactivate, args->onactivatedata);
1166 ui_set_name_and_style(combobox, args->name, args->style_class);
1167 ui_set_widget_groups(obj->ctx, combobox, args->groups);
1168 UI_APPLY_LAYOUT2(current, args);
1104 current->container->add(current->container, combobox, FALSE); 1169 current->container->add(current->container, combobox, FALSE);
1105 current->container->current = combobox; 1170 current->container->current = combobox;
1106 return combobox; 1171 return combobox;
1107 } 1172 }
1108 1173
1321 UiEvent event; 1386 UiEvent event;
1322 event.obj = listview->obj; 1387 event.obj = listview->obj;
1323 event.window = event.obj->window; 1388 event.window = event.obj->window;
1324 event.document = event.obj->ctx->document; 1389 event.document = event.obj->ctx->document;
1325 event.eventdata = dnd; 1390 event.eventdata = dnd;
1391 event.eventdatatype = UI_EVENT_DATA_DND;
1326 event.intval = 0; 1392 event.intval = 0;
1327 event.set = ui_get_setop(); 1393 event.set = ui_get_setop();
1328 listview->ondragstart(&event, listview->ondragstartdata); 1394 listview->ondragstart(&event, listview->ondragstartdata);
1329 } 1395 }
1330 1396
1357 UiEvent event; 1423 UiEvent event;
1358 event.obj = listview->obj; 1424 event.obj = listview->obj;
1359 event.window = event.obj->window; 1425 event.window = event.obj->window;
1360 event.document = event.obj->ctx->document; 1426 event.document = event.obj->ctx->document;
1361 event.eventdata = &dnd; 1427 event.eventdata = &dnd;
1428 event.eventdatatype = UI_EVENT_DATA_DND;
1362 event.intval = 0; 1429 event.intval = 0;
1363 event.set = ui_get_setop(); 1430 event.set = ui_get_setop();
1364 listview->ondragcomplete(&event, listview->ondragcompletedata); 1431 listview->ondragcomplete(&event, listview->ondragcompletedata);
1365 } 1432 }
1366 } 1433 }
1386 UiEvent event; 1453 UiEvent event;
1387 event.obj = listview->obj; 1454 event.obj = listview->obj;
1388 event.window = event.obj->window; 1455 event.window = event.obj->window;
1389 event.document = event.obj->ctx->document; 1456 event.document = event.obj->ctx->document;
1390 event.eventdata = &dnd; 1457 event.eventdata = &dnd;
1458 event.eventdatatype = UI_EVENT_DATA_DND;
1391 event.intval = 0; 1459 event.intval = 0;
1392 event.set = ui_get_setop(); 1460 event.set = ui_get_setop();
1393 listview->ondrop(&event, listview->ondropdata); 1461 listview->ondrop(&event, listview->ondropdata);
1394 } 1462 }
1395 1463
1743 } 1811 }
1744 1812
1745 cxListAdd(sublists, &uisublist); 1813 cxListAdd(sublists, &uisublist);
1746 } 1814 }
1747 1815
1748 UIEXPORT UIWIDGET ui_sourcelist_create(UiObject *obj, UiSourceListArgs args) { 1816 UIEXPORT UIWIDGET ui_sourcelist_create(UiObject *obj, UiSourceListArgs *args) {
1749 UiObject* current = uic_current_obj(obj); 1817 UiObject* current = uic_current_obj(obj);
1750 1818
1751 #ifdef UI_GTK3 1819 #ifdef UI_GTK3
1752 GtkWidget *listbox = g_object_new(ui_sidebar_list_box_get_type(), NULL); 1820 GtkWidget *listbox = g_object_new(ui_sidebar_list_box_get_type(), NULL);
1753 #else 1821 #else
1754 GtkWidget *listbox = gtk_list_box_new(); 1822 GtkWidget *listbox = gtk_list_box_new();
1755 #endif 1823 #endif
1756 if(!args.style_class) { 1824 if(!args->style_class) {
1757 #if GTK_MAJOR_VERSION >= 4 1825 #if GTK_MAJOR_VERSION >= 4
1758 WIDGET_ADD_CSS_CLASS(listbox, "navigation-sidebar"); 1826 WIDGET_ADD_CSS_CLASS(listbox, "navigation-sidebar");
1759 #else 1827 #else
1760 WIDGET_ADD_CSS_CLASS(listbox, "sidebar"); 1828 WIDGET_ADD_CSS_CLASS(listbox, "sidebar");
1761 #endif 1829 #endif
1762 } 1830 }
1763 gtk_list_box_set_header_func(GTK_LIST_BOX(listbox), listbox_create_header, NULL, NULL); 1831 gtk_list_box_set_header_func(GTK_LIST_BOX(listbox), listbox_create_header, NULL, NULL);
1764 GtkWidget *scroll_area = SCROLLEDWINDOW_NEW(); 1832 GtkWidget *scroll_area = SCROLLEDWINDOW_NEW();
1765 SCROLLEDWINDOW_SET_CHILD(scroll_area, listbox); 1833 SCROLLEDWINDOW_SET_CHILD(scroll_area, listbox);
1766 1834
1767 ui_set_name_and_style(listbox, args.name, args.style_class); 1835 ui_set_name_and_style(listbox, args->name, args->style_class);
1768 ui_set_widget_groups(obj->ctx, listbox, args.groups); 1836 ui_set_widget_groups(obj->ctx, listbox, args->groups);
1769 UI_APPLY_LAYOUT1(current, args); 1837 UI_APPLY_LAYOUT2(current, args);
1770 current->container->add(current->container, scroll_area, TRUE); 1838 current->container->add(current->container, scroll_area);
1771 1839
1772 UiListBox *uilistbox = malloc(sizeof(UiListBox)); 1840 UiListBox *uilistbox = malloc(sizeof(UiListBox));
1773 uilistbox->obj = obj; 1841 uilistbox->obj = obj;
1774 uilistbox->listbox = GTK_LIST_BOX(listbox); 1842 uilistbox->listbox = GTK_LIST_BOX(listbox);
1775 uilistbox->getvalue = args.getvalue; 1843 uilistbox->getvalue = args->getvalue;
1776 uilistbox->onactivate = args.onactivate; 1844 uilistbox->getvaluedata = args->getvaluedata;
1777 uilistbox->onactivatedata = args.onactivatedata; 1845 uilistbox->onactivate = args->onactivate;
1778 uilistbox->onbuttonclick = args.onbuttonclick; 1846 uilistbox->onactivatedata = args->onactivatedata;
1779 uilistbox->onbuttonclickdata = args.onbuttonclickdata; 1847 uilistbox->onbuttonclick = args->onbuttonclick;
1848 uilistbox->onbuttonclickdata = args->onbuttonclickdata;
1780 uilistbox->sublists = cxArrayListCreateSimple(sizeof(UiListBoxSubList), 4); 1849 uilistbox->sublists = cxArrayListCreateSimple(sizeof(UiListBoxSubList), 4);
1781 uilistbox->sublists->collection.advanced_destructor = (cx_destructor_func2)sublist_destroy; 1850 uilistbox->sublists->collection.advanced_destructor = (cx_destructor_func2)sublist_destroy;
1782 uilistbox->sublists->collection.destructor_data = obj; 1851 uilistbox->sublists->collection.destructor_data = obj;
1783 uilistbox->first_row = NULL; 1852 uilistbox->first_row = NULL;
1784 1853
1785 if(args.sublists) { 1854 if(args->sublists) {
1786 // static sublist initalization 1855 // static sublist initalization
1787 if(args.numsublists == 0 && args.sublists) { 1856 if(args->numsublists == 0 && args->sublists) {
1788 args.numsublists = INT_MAX; 1857 args->numsublists = INT_MAX;
1789 } 1858 }
1790 for(int i=0;i<args.numsublists;i++) { 1859 for(int i=0;i<args->numsublists;i++) {
1791 UiSubList sublist = args.sublists[i]; 1860 UiSubList sublist = args->sublists[i];
1792 if(!sublist.varname && !sublist.value) { 1861 if(!sublist.varname && !sublist.value) {
1793 break; 1862 break;
1794 } 1863 }
1795 1864
1796 add_sublist(uilistbox, uilistbox->sublists, &sublist); 1865 add_sublist(uilistbox, uilistbox->sublists, &sublist);
1797 } 1866 }
1798 1867
1799 // fill items 1868 // fill items
1800 ui_listbox_update(uilistbox, 0, cxListSize(uilistbox->sublists)); 1869 ui_listbox_update(uilistbox, 0, cxListSize(uilistbox->sublists));
1801 } else { 1870 } else {
1802 UiVar* var = uic_widget_var(obj->ctx, current->ctx, args.dynamic_sublist, args.varname, UI_VAR_LIST); 1871 UiVar* var = uic_widget_var(obj->ctx, current->ctx, args->dynamic_sublist, args->varname, UI_VAR_LIST);
1803 if(var) { 1872 if(var) {
1804 UiList *list = var->value; 1873 UiList *list = var->value;
1805 list->obj = uilistbox; 1874 list->obj = uilistbox;
1806 list->update = ui_listbox_dynamic_update; 1875 list->update = ui_listbox_dynamic_update;
1807 1876
1808 ui_listbox_dynamic_update(list, 0); 1877 ui_listbox_dynamic_update(list, -1);
1809 } 1878 }
1810 } 1879 }
1811 1880
1812 // register uilistbox for both widgets, so it doesn't matter which 1881 // register uilistbox for both widgets, so it doesn't matter which
1813 // widget is used later 1882 // widget is used later
1819 listbox, 1888 listbox,
1820 "destroy", 1889 "destroy",
1821 G_CALLBACK(ui_destroy_sourcelist), 1890 G_CALLBACK(ui_destroy_sourcelist),
1822 uilistbox); 1891 uilistbox);
1823 1892
1824 if(args.onactivate) { 1893 if(args->onactivate) {
1825 g_signal_connect( 1894 g_signal_connect(
1826 listbox, 1895 listbox,
1827 "row-activated", 1896 "row-activated",
1828 G_CALLBACK(ui_listbox_row_activate), 1897 G_CALLBACK(ui_listbox_row_activate),
1829 NULL); 1898 NULL);
1836 UiListBox *uilistbox = list->obj; 1905 UiListBox *uilistbox = list->obj;
1837 1906
1838 // unbind/free previous list vars 1907 // unbind/free previous list vars
1839 CxIterator i = cxListIterator(uilistbox->sublists); 1908 CxIterator i = cxListIterator(uilistbox->sublists);
1840 cx_foreach(UiListBoxSubList *, s, i) { 1909 cx_foreach(UiListBoxSubList *, s, i) {
1910 // TODO: "unbind/free previous list vars" will also remove
1911 // the widget list. This makes the widget optimization
1912 // in ui_listbox_update_sublist pointless
1913 // Is it actually possible to not recreate the whole list?
1914 CxIterator r = cxListIterator(s->widgets);
1915 cx_foreach(GtkWidget*, widget, r) {
1916 LISTBOX_REMOVE(uilistbox->listbox, widget);
1917 }
1918
1841 if(s->var) { 1919 if(s->var) {
1842 UiList *sl = s->var->value; 1920 UiList *sl = s->var->value;
1843 sl->obj = NULL; 1921 sl->obj = NULL;
1844 sl->update = NULL; 1922 sl->update = NULL;
1845 if(s->var->type == UI_VAR_SPECIAL) { 1923 if(s->var->type == UI_VAR_SPECIAL) {
1934 2012
1935 size_t index = 0; 2013 size_t index = 0;
1936 void *elm = list->first(list); 2014 void *elm = list->first(list);
1937 while(elm) { 2015 while(elm) {
1938 UiSubListItem item = { NULL, NULL, NULL, NULL, NULL, NULL }; 2016 UiSubListItem item = { NULL, NULL, NULL, NULL, NULL, NULL };
1939 listbox->getvalue(sublist->userdata, elm, index, &item); 2017 if(listbox->getvalue) {
2018 listbox->getvalue(list, sublist->userdata, elm, index, &item, listbox->getvaluedata);
2019 } else {
2020 item.label = strdup(elm);
2021 }
1940 2022
1941 // create listbox item 2023 // create listbox item
1942 GtkWidget *row = create_listbox_row(listbox, sublist, &item, (int)index); 2024 GtkWidget *row = create_listbox_row(listbox, sublist, &item, (int)index);
1943 if(index == 0) { 2025 if(index == 0) {
1944 // first row in the sublist, set ui_listbox data to the row 2026 // first row in the sublist, set ui_listbox data to the row
1985 UiSubListEventData eventdata; 2067 UiSubListEventData eventdata;
1986 eventdata.list = sublist->var->value; 2068 eventdata.list = sublist->var->value;
1987 eventdata.sublist_index = sublist->index; 2069 eventdata.sublist_index = sublist->index;
1988 eventdata.row_index = data->value0; 2070 eventdata.row_index = data->value0;
1989 eventdata.sublist_userdata = sublist->userdata; 2071 eventdata.sublist_userdata = sublist->userdata;
1990 eventdata.row_data = ui_list_get(eventdata.list, eventdata.row_index); 2072 eventdata.row_data = eventdata.list->get(eventdata.list, eventdata.row_index);
1991 eventdata.event_data = data->customdata2; 2073 eventdata.event_data = data->customdata2;
1992 2074
1993 UiEvent event; 2075 UiEvent event;
1994 event.obj = data->obj; 2076 event.obj = data->obj;
1995 event.window = event.obj->window; 2077 event.window = event.obj->window;
1996 event.document = event.obj->ctx->document; 2078 event.document = event.obj->ctx->document;
1997 event.eventdata = &eventdata; 2079 event.eventdata = &eventdata;
2080 event.eventdatatype = UI_EVENT_DATA_SUBLIST;
1998 event.intval = data->value0; 2081 event.intval = data->value0;
1999 event.set = ui_get_setop(); 2082 event.set = ui_get_setop();
2000 2083
2001 if(data->callback) { 2084 if(data->callback) {
2002 data->callback(&event, data->userdata); 2085 data->callback(&event, data->userdata);

mercurial