| 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 tableview->onsave = args->onsave; |
| |
99 tableview->onsavedata = args->onsavedata; |
| 98 |
100 |
| 99 if(args->getvalue2) { |
101 if(args->getvalue2) { |
| 100 tableview->getvalue = args->getvalue2; |
102 tableview->getvalue = args->getvalue2; |
| 101 tableview->getvaluedata = args->getvalue2data; |
103 tableview->getvaluedata = args->getvalue2data; |
| 102 } else if(args->getvalue) { |
104 } else if(args->getvalue) { |
| 140 obj->i = i; |
142 obj->i = i; |
| 141 return obj; |
143 return obj; |
| 142 } |
144 } |
| 143 |
145 |
| 144 /* 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 if(data->listview->onsave(list, data->row, data->col, value, data->listview->onsavedata)) { |
| |
164 free(data->previous_value); |
| |
165 data->previous_value = strdup(str); |
| |
166 } else if(restore) { |
| |
167 ENTRY_SET_TEXT(data->entry, data->previous_value); |
| |
168 } |
| |
169 } |
| |
170 } |
| |
171 |
| |
172 static void cell_entry_leave_focus( |
| |
173 GtkEventControllerFocus *self, |
| |
174 UiCellEntry *data) |
| |
175 { |
| |
176 // TODO: use a different singal to track focus |
| |
177 // we only want to call cell_save_value, when another entry is selected, |
| |
178 // not when the window loses focus or something like that |
| |
179 cell_save_value(data, TRUE); |
| |
180 } |
| |
181 |
| |
182 static void cell_entry_destroy(GtkWidget *object, UiCellEntry *data) { |
| |
183 free(data->previous_value); |
| |
184 free(data); |
| |
185 } |
| |
186 |
| |
187 static void cell_entry_unmap(GtkWidget *w, UiCellEntry *data) { |
| |
188 const char *text = ENTRY_GET_TEXT(w); |
| |
189 cell_save_value(data, FALSE); |
| |
190 } |
| |
191 |
| |
192 static void cell_entry_activate( |
| |
193 GtkEntry *self, |
| |
194 UiCellEntry *data) |
| |
195 { |
| |
196 cell_save_value(data, TRUE); |
| |
197 } |
| 145 |
198 |
| 146 static void column_factory_setup(GtkListItemFactory *factory, GtkListItem *item, gpointer userdata) { |
199 static void column_factory_setup(GtkListItemFactory *factory, GtkListItem *item, gpointer userdata) { |
| 147 UiColData *col = userdata; |
200 UiColData *col = userdata; |
| 148 UiModel *model = col->listview->model; |
201 UiModel *model = col->listview->model; |
| 149 UiModelType type = model->types[col->model_column]; |
202 UiModelType type = model->types[col->model_column]; |
| 161 gtk_list_item_set_child(item, image); |
214 gtk_list_item_set_child(item, image); |
| 162 } else if(type == UI_STRING_EDITABLE) { |
215 } else if(type == UI_STRING_EDITABLE) { |
| 163 GtkWidget *textfield = gtk_entry_new(); |
216 GtkWidget *textfield = gtk_entry_new(); |
| 164 gtk_widget_add_css_class(textfield, "ui-table-entry"); |
217 gtk_widget_add_css_class(textfield, "ui-table-entry"); |
| 165 gtk_list_item_set_child(item, textfield); |
218 gtk_list_item_set_child(item, textfield); |
| |
219 |
| |
220 UiCellEntry *entry_data = malloc(sizeof(UiCellEntry)); |
| |
221 entry_data->entry = GTK_ENTRY(textfield); |
| |
222 entry_data->listview = NULL; |
| |
223 entry_data->previous_value = NULL; |
| |
224 entry_data->col = 0; |
| |
225 entry_data->row = 0; |
| |
226 g_object_set_data(G_OBJECT(textfield), "ui_entry_data", entry_data); |
| |
227 |
| |
228 g_signal_connect( |
| |
229 textfield, |
| |
230 "destroy", |
| |
231 G_CALLBACK(cell_entry_destroy), |
| |
232 entry_data); |
| |
233 g_signal_connect( |
| |
234 textfield, |
| |
235 "activate", |
| |
236 G_CALLBACK(cell_entry_activate), |
| |
237 entry_data); |
| |
238 g_signal_connect( |
| |
239 textfield, |
| |
240 "unmap", |
| |
241 G_CALLBACK(cell_entry_unmap), |
| |
242 entry_data); |
| |
243 |
| |
244 GtkEventController *focus_controller = gtk_event_controller_focus_new(); |
| |
245 g_signal_connect(focus_controller, "leave", G_CALLBACK(cell_entry_leave_focus), entry_data); |
| |
246 gtk_widget_add_controller(textfield, focus_controller); |
| 166 } else { |
247 } else { |
| 167 GtkWidget *label = gtk_label_new(NULL); |
248 GtkWidget *label = gtk_label_new(NULL); |
| 168 gtk_label_set_xalign(GTK_LABEL(label), 0); |
249 gtk_label_set_xalign(GTK_LABEL(label), 0); |
| 169 gtk_list_item_set_child(item, label); |
250 gtk_list_item_set_child(item, label); |
| 170 } |
251 } |
| 318 row->bound--; |
406 row->bound--; |
| 319 if(row->bound == 0) { |
407 if(row->bound == 0) { |
| 320 cxMapRemove(listview->bound_rows, row_key); |
408 cxMapRemove(listview->bound_rows, row_key); |
| 321 } |
409 } |
| 322 } // else: should not happen |
410 } // else: should not happen |
| |
411 |
| |
412 GtkWidget *child = gtk_list_item_get_child(item); |
| |
413 UiCellEntry *entry = g_object_get_data(G_OBJECT(child), "ui_entry_data"); |
| |
414 if(entry) { |
| |
415 cell_save_value(entry, FALSE); |
| |
416 entry->listview = NULL; |
| |
417 free(entry->previous_value); |
| |
418 entry->previous_value = NULL; |
| |
419 } |
| 323 } |
420 } |
| 324 |
421 |
| 325 |
422 |
| 326 static GtkSelectionModel* create_selection_model(UiListView *listview, GListStore *liststore, bool multiselection) { |
423 static GtkSelectionModel* create_selection_model(UiListView *listview, GListStore *liststore, bool multiselection) { |
| 327 GtkSelectionModel *selection_model; |
424 GtkSelectionModel *selection_model; |