ui/gtk/list.c

changeset 786
150a1180f7ec
parent 781
b15ada8bdd8f
child 801
e096c441e874
equal deleted inserted replaced
785:b943e3d618f0 786:150a1180f7ec
93 tableview->selection.count = 0; 93 tableview->selection.count = 0;
94 tableview->selection.rows = NULL; 94 tableview->selection.rows = NULL;
95 tableview->current_row = -1; 95 tableview->current_row = -1;
96 tableview->getstyle = args->getstyle; 96 tableview->getstyle = args->getstyle;
97 tableview->getstyledata = args->getstyledata; 97 tableview->getstyledata = args->getstyledata;
98 #if GTK_CHECK_VERSION(4, 10, 0) 98 tableview->onsave = args->onsave;
99 tableview->default_attributes = pango_attr_list_new(); 99 tableview->onsavedata = args->onsavedata;
100 #endif
101 100
102 if(args->getvalue2) { 101 if(args->getvalue2) {
103 tableview->getvalue = args->getvalue2; 102 tableview->getvalue = args->getvalue2;
104 tableview->getvaluedata = args->getvalue2data; 103 tableview->getvaluedata = args->getvalue2data;
105 } else if(args->getvalue) { 104 } else if(args->getvalue) {
143 obj->i = i; 142 obj->i = i;
144 return obj; 143 return obj;
145 } 144 }
146 145
147 /* END GObject wrapper for generic pointers */ 146 /* END GObject wrapper for generic pointers */
147
148 typedef struct UiCellEntry {
149 GtkEntry *entry;
150 UiListView *listview;
151 char *previous_value;
152 int row;
153 int col;
154 } UiCellEntry;
155
156 static void cell_save_value(UiCellEntry *data, int restore) {
157 if(data->listview && data->listview->onsave) {
158 UiVar *var = data->listview->var;
159 UiList *list = var ? var->value : NULL;
160 const char *str = ENTRY_GET_TEXT(data->entry);
161 UiCellValue value;
162 value.string = str;
163 value.type = UI_STRING_EDITABLE;
164 if(data->listview->onsave(list, data->row, data->col, &value, data->listview->onsavedata)) {
165 free(data->previous_value);
166 data->previous_value = strdup(str);
167 } else if(restore) {
168 ENTRY_SET_TEXT(data->entry, data->previous_value);
169 }
170 }
171 }
172
173 static void cell_entry_leave_focus(
174 GtkEventControllerFocus *self,
175 UiCellEntry *data)
176 {
177 // TODO: use a different singal to track focus
178 // we only want to call cell_save_value, when another entry is selected,
179 // not when the window loses focus or something like that
180 cell_save_value(data, TRUE);
181 }
182
183 static void cell_entry_destroy(GtkWidget *object, UiCellEntry *data) {
184 free(data->previous_value);
185 free(data);
186 }
187
188 static void cell_entry_unmap(GtkWidget *w, UiCellEntry *data) {
189 const char *text = ENTRY_GET_TEXT(w);
190 cell_save_value(data, FALSE);
191 }
192
193 static void cell_entry_activate(
194 GtkEntry *self,
195 UiCellEntry *data)
196 {
197 cell_save_value(data, TRUE);
198 }
148 199
149 static void column_factory_setup(GtkListItemFactory *factory, GtkListItem *item, gpointer userdata) { 200 static void column_factory_setup(GtkListItemFactory *factory, GtkListItem *item, gpointer userdata) {
150 UiColData *col = userdata; 201 UiColData *col = userdata;
151 UiModel *model = col->listview->model; 202 UiModel *model = col->listview->model;
152 UiModelType type = model->types[col->model_column]; 203 UiModelType type = model->types[col->model_column];
160 g_object_set_data(G_OBJECT(hbox), "image", image); 211 g_object_set_data(G_OBJECT(hbox), "image", image);
161 g_object_set_data(G_OBJECT(hbox), "label", label); 212 g_object_set_data(G_OBJECT(hbox), "label", label);
162 } else if(type == UI_ICON) { 213 } else if(type == UI_ICON) {
163 GtkWidget *image = gtk_image_new(); 214 GtkWidget *image = gtk_image_new();
164 gtk_list_item_set_child(item, image); 215 gtk_list_item_set_child(item, image);
216 } else if(type == UI_STRING_EDITABLE) {
217 GtkWidget *textfield = gtk_entry_new();
218 gtk_widget_add_css_class(textfield, "ui-table-entry");
219 gtk_list_item_set_child(item, textfield);
220
221 UiCellEntry *entry_data = malloc(sizeof(UiCellEntry));
222 entry_data->entry = GTK_ENTRY(textfield);
223 entry_data->listview = NULL;
224 entry_data->previous_value = NULL;
225 entry_data->col = 0;
226 entry_data->row = 0;
227 g_object_set_data(G_OBJECT(textfield), "ui_entry_data", entry_data);
228
229 g_signal_connect(
230 textfield,
231 "destroy",
232 G_CALLBACK(cell_entry_destroy),
233 entry_data);
234 g_signal_connect(
235 textfield,
236 "activate",
237 G_CALLBACK(cell_entry_activate),
238 entry_data);
239 g_signal_connect(
240 textfield,
241 "unmap",
242 G_CALLBACK(cell_entry_unmap),
243 entry_data);
244
245 GtkEventController *focus_controller = gtk_event_controller_focus_new();
246 g_signal_connect(focus_controller, "leave", G_CALLBACK(cell_entry_leave_focus), entry_data);
247 gtk_widget_add_controller(textfield, focus_controller);
165 } else { 248 } else {
166 GtkWidget *label = gtk_label_new(NULL); 249 GtkWidget *label = gtk_label_new(NULL);
167 gtk_label_set_xalign(GTK_LABEL(label), 0); 250 gtk_label_set_xalign(GTK_LABEL(label), 0);
168 gtk_list_item_set_child(item, label); 251 gtk_list_item_set_child(item, label);
169 } 252 }
294 if(freevalue) { 377 if(freevalue) {
295 free(data2); 378 free(data2);
296 } 379 }
297 break; 380 break;
298 } 381 }
382 case UI_STRING_EDITABLE: {
383 UiCellEntry *entry = g_object_get_data(G_OBJECT(child), "ui_entry_data");
384 if(entry) {
385 entry->listview = col->listview;
386 entry->row = obj->i;
387 entry->col = col->data_column;
388 entry->previous_value = strdup(data);
389 }
390 ENTRY_SET_TEXT(child, data);
391 break;
392 }
299 } 393 }
300 394
301 if(attributes != listview->current_row_attributes) { 395 if(attributes != listview->current_row_attributes) {
302 pango_attr_list_unref(attributes); 396 pango_attr_list_unref(attributes);
303 } 397 }
313 row->bound--; 407 row->bound--;
314 if(row->bound == 0) { 408 if(row->bound == 0) {
315 cxMapRemove(listview->bound_rows, row_key); 409 cxMapRemove(listview->bound_rows, row_key);
316 } 410 }
317 } // else: should not happen 411 } // else: should not happen
412
413 GtkWidget *child = gtk_list_item_get_child(item);
414 UiCellEntry *entry = g_object_get_data(G_OBJECT(child), "ui_entry_data");
415 if(entry) {
416 cell_save_value(entry, FALSE);
417 entry->listview = NULL;
418 free(entry->previous_value);
419 entry->previous_value = NULL;
420 }
318 } 421 }
319 422
320 423
321 static GtkSelectionModel* create_selection_model(UiListView *listview, GListStore *liststore, bool multiselection) { 424 static GtkSelectionModel* create_selection_model(UiListView *listview, GListStore *liststore, bool multiselection) {
322 GtkSelectionModel *selection_model; 425 GtkSelectionModel *selection_model;
1906 } 2009 }
1907 free(v->elements); 2010 free(v->elements);
1908 } 2011 }
1909 #if GTK_CHECK_VERSION(4, 10, 0) 2012 #if GTK_CHECK_VERSION(4, 10, 0)
1910 free(v->columns); 2013 free(v->columns);
1911 pango_attr_list_unref(v->default_attributes);
1912 pango_attr_list_unref(v->current_row_attributes); 2014 pango_attr_list_unref(v->current_row_attributes);
1913 cxMapFree(v->bound_rows); 2015 cxMapFree(v->bound_rows);
1914 #endif 2016 #endif
1915 free(v->selection.rows); 2017 free(v->selection.rows);
1916 free(v); 2018 free(v);
2180 if(data->callback2) { 2282 if(data->callback2) {
2181 data->callback2(&event, data->userdata2); 2283 data->callback2(&event, data->userdata2);
2182 } 2284 }
2183 } 2285 }
2184 2286
2185 static GtkWidget* create_listbox_row(UiListBox *listbox, UiListBoxSubList *sublist, UiSubListItem *item, int index) { 2287 static void listbox_fill_row(UiListBox *listbox, GtkWidget *row, UiListBoxSubList *sublist, UiSubListItem *item, int index) {
2186 GtkWidget *hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 10); 2288 GtkWidget *hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 10);
2187 if(item->icon) { 2289 if(item->icon) {
2188 GtkWidget *icon = ICON_IMAGE(item->icon); 2290 GtkWidget *icon = ICON_IMAGE(item->icon);
2189 BOX_ADD(hbox, icon); 2291 BOX_ADD(hbox, icon);
2190 } 2292 }
2192 gtk_widget_set_halign(label, GTK_ALIGN_START); 2294 gtk_widget_set_halign(label, GTK_ALIGN_START);
2193 BOX_ADD_EXPAND(hbox, label); 2295 BOX_ADD_EXPAND(hbox, label);
2194 if(item->badge) { 2296 if(item->badge) {
2195 2297
2196 } 2298 }
2197 GtkWidget *row = gtk_list_box_row_new();
2198 LISTBOX_ROW_SET_CHILD(row, hbox); 2299 LISTBOX_ROW_SET_CHILD(row, hbox);
2199 2300
2200 // signals 2301 // signals
2201 UiEventDataExt *event = malloc(sizeof(UiEventDataExt)); 2302 UiEventDataExt *event = malloc(sizeof(UiEventDataExt));
2202 memset(event, 0, sizeof(UiEventDataExt)); 2303 memset(event, 0, sizeof(UiEventDataExt));
2243 "clicked", 2344 "clicked",
2244 G_CALLBACK(listbox_button_clicked), 2345 G_CALLBACK(listbox_button_clicked),
2245 event 2346 event
2246 ); 2347 );
2247 } 2348 }
2248 2349 }
2249 return row; 2350
2351 static void update_sublist_item(UiListBox *listbox, UiListBoxSubList *sublist, int index) {
2352 GtkListBoxRow *row = gtk_list_box_get_row_at_index(listbox->listbox, sublist->startpos + index);
2353 if(!row) {
2354 return;
2355 }
2356 UiList *list = sublist->var->value;
2357 if(!list) {
2358 return;
2359 }
2360
2361 void *elm = list->get(list, index);
2362 UiSubListItem item = { NULL, NULL, NULL, NULL, NULL, NULL };
2363 if(listbox->getvalue) {
2364 listbox->getvalue(list, sublist->userdata, elm, index, &item, listbox->getvaluedata);
2365 } else {
2366 item.label = strdup(elm);
2367 }
2368
2369 LISTBOX_ROW_REMOVE_CHILD(row);
2370
2371 listbox_fill_row(listbox, GTK_WIDGET(row), sublist, &item, index);
2372
2373 // cleanup
2374 free(item.label);
2375 free(item.icon);
2376 free(item.button_label);
2377 free(item.button_icon);
2378 free(item.badge);
2250 } 2379 }
2251 2380
2252 void ui_listbox_update_sublist(UiListBox *listbox, UiListBoxSubList *sublist, size_t listbox_insert_index) { 2381 void ui_listbox_update_sublist(UiListBox *listbox, UiListBoxSubList *sublist, size_t listbox_insert_index) {
2253 // clear sublist 2382 // clear sublist
2254 CxIterator r = cxListIterator(sublist->widgets); 2383 CxIterator r = cxListIterator(sublist->widgets);
2291 } else { 2420 } else {
2292 item.label = strdup(elm); 2421 item.label = strdup(elm);
2293 } 2422 }
2294 2423
2295 // create listbox item 2424 // create listbox item
2296 GtkWidget *row = create_listbox_row(listbox, sublist, &item, (int)index); 2425 GtkWidget *row = gtk_list_box_row_new();
2426 listbox_fill_row(listbox, row, sublist, &item, (int)index);
2297 if(index == 0) { 2427 if(index == 0) {
2298 // first row in the sublist, set ui_listbox data to the row 2428 // first row in the sublist, set ui_listbox data to the row
2299 // which is then used by the headerfunc 2429 // which is then used by the headerfunc
2300 g_object_set_data(G_OBJECT(row), "ui_listbox", listbox); 2430 g_object_set_data(G_OBJECT(row), "ui_listbox", listbox);
2301 g_object_set_data(G_OBJECT(row), "ui_listbox_sublist", sublist); 2431 g_object_set_data(G_OBJECT(row), "ui_listbox_sublist", sublist);
2325 sublist->numitems = cxListSize(sublist->widgets); 2455 sublist->numitems = cxListSize(sublist->widgets);
2326 } 2456 }
2327 2457
2328 void ui_listbox_list_update(UiList *list, int i) { 2458 void ui_listbox_list_update(UiList *list, int i) {
2329 UiListBoxSubList *sublist = list->obj; 2459 UiListBoxSubList *sublist = list->obj;
2330 ui_listbox_update_sublist(sublist->listbox, sublist, sublist->startpos); 2460 if(i < 0) {
2331 size_t pos = 0; 2461 ui_listbox_update_sublist(sublist->listbox, sublist, sublist->startpos);
2332 CxIterator it = cxListIterator(sublist->listbox->sublists); 2462 size_t pos = 0;
2333 cx_foreach(UiListBoxSubList *, ls, it) { 2463 CxIterator it = cxListIterator(sublist->listbox->sublists);
2334 ls->startpos = pos; 2464 cx_foreach(UiListBoxSubList *, ls, it) {
2335 pos += sublist->numitems; 2465 ls->startpos = pos;
2336 } 2466 pos += ls->numitems;
2337 2467 }
2468 } else {
2469 update_sublist_item(sublist->listbox, sublist, i);
2470 }
2338 } 2471 }
2339 2472
2340 void ui_listbox_row_activate(GtkListBox *self, GtkListBoxRow *row, gpointer user_data) { 2473 void ui_listbox_row_activate(GtkListBox *self, GtkListBoxRow *row, gpointer user_data) {
2341 UiEventDataExt *data = g_object_get_data(G_OBJECT(row), "ui-listbox-row-eventdata"); 2474 UiEventDataExt *data = g_object_get_data(G_OBJECT(row), "ui-listbox-row-eventdata");
2342 if(!data) { 2475 if(!data) {

mercurial