From a293e34d9e2a5f057ff5817dfe130dc7b592a14e Mon Sep 17 00:00:00 2001 From: Olaf Wintermann Date: Sun, 23 Mar 2025 18:38:51 +0100 Subject: [PATCH] handle note title onchange event and update note item in notes list --- application/note.c | 20 ++++- application/note.h | 1 + application/notebook.c | 6 ++ application/notebook.h | 2 + application/window.c | 13 ++- application/window.h | 2 + ui/common/context.c | 2 +- ui/common/types.c | 2 - ui/gtk/list.c | 185 +++++++++++++++++++++++------------------ 9 files changed, 147 insertions(+), 86 deletions(-) diff --git a/application/note.c b/application/note.c index b05b98a..b965fb3 100644 --- a/application/note.c +++ b/application/note.c @@ -30,6 +30,7 @@ #include "store.h" #include "editor.h" +#include "notebook.h" static TextNoteParagraphStyles paragraph_styles[] = { { "Paragraph", EDITOR_STYLE_PARAGRAPH }, @@ -130,8 +131,9 @@ void note_save(UiObject *obj, NotebookModel *notebook, Note *note) { // new note note_store_new_note_async(obj, note, NULL, NULL); notebook->disable_selection_events = TRUE; + int index = notebook->notes->count(notebook->notes); ui_list_append(notebook->notes, note); - ui_list_update(notebook->notes); + notebook->notes->update(notebook->notes, index); notebook->disable_selection_events = FALSE; } else { note_store_save_note_async(obj, note, NULL, NULL); @@ -180,6 +182,22 @@ void note_text_style_set_code(NoteModel *note, UiBool enabled) { } + +void note_update_title(NotebookModel *notebook, Note *note) { + int index = notebookmode_get_note_index(notebook, note); + if(index < 0) { + return; + } + NoteModel *m = note->model; + m->modified = TRUE; + + char *title = ui_get(m->title); + cxFree(m->note_allocator, note->title); + note->title = cx_strdup_a(m->note_allocator, cx_str(title)).ptr; + + notebook->notes->update(notebook->notes, index); +} + const char* note_get_title(Note *note) { return note->title ? note->title : note->name; } diff --git a/application/note.h b/application/note.h index c2db417..e663d1c 100644 --- a/application/note.h +++ b/application/note.h @@ -59,6 +59,7 @@ void note_text_style_set_emphasis(NoteModel *note, UiBool enabled); void note_text_style_set_underline(NoteModel *note, UiBool enabled); void note_text_style_set_code(NoteModel *note, UiBool enabled); +void note_update_title(NotebookModel *notebook, Note *note); const char* note_get_title(Note *note); void note_destroy(const CxAllocator *a, Note *note); diff --git a/application/notebook.c b/application/notebook.c index 85d76d5..58ea1ac 100644 --- a/application/notebook.c +++ b/application/notebook.c @@ -270,3 +270,9 @@ void notebookmodel_add2navstack(NotebookModel *model) { } */ } + +int notebookmode_get_note_index(NotebookModel *model, Note *note) { + CxList *list = model->notes->data; + size_t index = cxListFind(list, note); + return cxListIndexValid(list, index) ? index : -1; +} diff --git a/application/notebook.h b/application/notebook.h index ec7178d..245ca85 100644 --- a/application/notebook.h +++ b/application/notebook.h @@ -56,6 +56,8 @@ void notebookmodel_delete_note(NotebookModel *model); void notebookmodel_add2navstack(NotebookModel *model); +int notebookmode_get_note_index(NotebookModel *model, Note *note); + #ifdef __cplusplus } diff --git a/application/window.c b/application/window.c index 3d8ec1d..144b1c9 100644 --- a/application/window.c +++ b/application/window.c @@ -73,7 +73,7 @@ void window_create() { ui_vbox0(obj) { ui_grid(obj, .margin = 10, .columnspacing = 10, .rowspacing = 10, .def_vfill = TRUE, .fill = UI_OFF) { //ui_label(obj, .label = "Title", .vfill = TRUE); - ui_textfield(obj, .varname = "note_title", .hexpand = TRUE, .groups = UI_GROUPS(APP_STATE_NOTE_SELECTED)); + ui_textfield(obj, .varname = "note_title", .onchange = action_note_title_changed, .hexpand = TRUE, .groups = UI_GROUPS(APP_STATE_NOTE_SELECTED)); ui_newline(obj); } ui_hbox(obj, .style_class = "note_toolbar", .margin = 10, .spacing = 4, .fill = UI_OFF) { @@ -306,6 +306,17 @@ void action_note_activated(UiEvent *event, void *userdata) { } } +void action_note_title_changed(UiEvent *event, void *userdata) { + MainWindow *window = event->window; + if(event->set) { + return; + } + NotebookModel *notebook = window->current_notebook; + if(notebook && notebook->current_note && notebook->current_note->model) { + note_update_title(notebook, notebook->current_note); + } +} + void action_textnote_style_strong(UiEvent *event, void *userdata) { if(event->set) { return; // only handle user interactions, not events triggered by ui_set diff --git a/application/window.h b/application/window.h index bb21ee1..5823316 100644 --- a/application/window.h +++ b/application/window.h @@ -56,6 +56,8 @@ void action_notebook_selected(UiEvent *event, void *userdata); void action_note_selected(UiEvent *event, void *userdata); void action_note_activated(UiEvent *event, void *userdata); +void action_note_title_changed(UiEvent *event, void *userdata); + void action_textnote_paragraph(UiEvent *event, void *userdata); void action_textnote_style_strong(UiEvent *event, void *userdata); void action_textnote_style_emphasis(UiEvent *event, void *userdata); diff --git a/ui/common/context.c b/ui/common/context.c index 6969d1e..5857194 100644 --- a/ui/common/context.c +++ b/ui/common/context.c @@ -101,7 +101,7 @@ void uic_context_attach_document(UiContext *ctx, void *document) { if(var_ctx->vars_unbound && cxMapSize(var_ctx->vars_unbound) > 0) { CxMapIterator i = cxMapIterator(var_ctx->vars_unbound); cx_foreach(CxMapEntry*, entry, i) { - printf("attach %.*s\n", (int)entry->key->len, entry->key->data); + printf("attach %s\n", entry->key->data); UiVar *var = entry->value; UiVar *docvar = cxMapGet(doc_ctx->vars, *entry->key); if(docvar) { diff --git a/ui/common/types.c b/ui/common/types.c index ab04faa..8bd07a6 100644 --- a/ui/common/types.c +++ b/ui/common/types.c @@ -162,9 +162,7 @@ void ui_list_clear(UiList *list) { UIEXPORT void ui_list_update(UiList *list) { if(list->update) { - ui_setop_enable(TRUE); list->update(list, -1); - ui_setop_enable(FALSE); } } diff --git a/ui/gtk/list.c b/ui/gtk/list.c index c3a2cfd..2743220 100644 --- a/ui/gtk/list.c +++ b/ui/gtk/list.c @@ -579,7 +579,17 @@ void ui_update_liststore_static(GListStore *liststore, char **elm, size_t nelm) void ui_listview_update2(UiList *list, int i) { UiListView *view = list->obj; - ui_update_liststore(view->liststore, list); + if(i < 0) { + ui_update_liststore(view->liststore, list); + } else { + void *value = list->get(list, i); + if(value) { + ObjWrapper *obj = obj_wrapper_new(value); + // TODO: if index i is selected, the selection is lost + // is it possible to update the item without removing it? + g_list_store_splice(view->liststore, i, 1, (void **)&obj, 1); + } + } } UiListSelection ui_listview_getselection2(UiList *list) { @@ -639,6 +649,86 @@ void ui_combobox_setselection(UiList *list, UiListSelection selection) { #else +static void update_list_row(GtkListStore *store, GtkTreeIter *iter, UiModel *model, void *elm) { + // set column values + int c = 0; + for(int i=0;icolumns;i++,c++) { + void *data = model->getvalue(elm, c); + + GValue value = G_VALUE_INIT; + switch(model->types[i]) { + case UI_STRING: + case UI_STRING_FREE: { + g_value_init(&value, G_TYPE_STRING); + g_value_set_string(&value, data); + if(model->types[i] == UI_STRING_FREE) { + free(data); + } + break; + } + case UI_INTEGER: { + g_value_init(&value, G_TYPE_INT); + intptr_t intptr = (intptr_t)data; + g_value_set_int(&value, (int)intptr); + break; + } + case UI_ICON: { + g_value_init(&value, G_TYPE_OBJECT); + UiIcon *icon = data; +#if GTK_MAJOR_VERSION >= 4 + g_value_set_object(&value, icon->info); // TODO: does this work? +#else + if(!icon->pixbuf && icon->info) { + GError *error = NULL; + GdkPixbuf *pixbuf = gtk_icon_info_load_icon(icon->info, &error); + icon->pixbuf = pixbuf; + } + + if(icon->pixbuf) { + g_value_set_object(&value, icon->pixbuf); + } +#endif + break; + } + case UI_ICON_TEXT: + case UI_ICON_TEXT_FREE: { + UiIcon *icon = data; +#if GTK_MAJOR_VERSION >= 4 + if(icon) { + GValue iconvalue = G_VALUE_INIT; + g_value_init(&iconvalue, G_TYPE_OBJECT); + g_value_set_object(&iconvalue, ui_icon_pixbuf(icon)); + gtk_list_store_set_value(store, &iter, c, &iconvalue); + } +#else + GValue pixbufvalue = G_VALUE_INIT; + if(icon) { + if(!icon->pixbuf && icon->info) { + GError *error = NULL; + GdkPixbuf *pixbuf = gtk_icon_info_load_icon(icon->info, &error); + icon->pixbuf = pixbuf; + } + g_value_init(&pixbufvalue, G_TYPE_OBJECT); + g_value_set_object(&pixbufvalue, icon->pixbuf); + gtk_list_store_set_value(store, iter, c, &pixbufvalue); + } +#endif + c++; + + char *str = model->getvalue(elm, c); + g_value_init(&value, G_TYPE_STRING); + g_value_set_string(&value, str); + if(model->types[i] == UI_ICON_TEXT_FREE) { + free(str); + } + break; + } + } + + gtk_list_store_set_value(store, iter, c, &value); + } +} + static GtkListStore* create_list_store(UiList *list, UiModel *model) { int columns = model->columns; GType types[2*columns]; @@ -666,83 +756,7 @@ static GtkListStore* create_list_store(UiList *list, UiModel *model) { GtkTreeIter iter; gtk_list_store_insert (store, &iter, -1); - // set column values - int c = 0; - for(int i=0;igetvalue(elm, c); - - GValue value = G_VALUE_INIT; - switch(model->types[i]) { - case UI_STRING: - case UI_STRING_FREE: { - g_value_init(&value, G_TYPE_STRING); - g_value_set_string(&value, data); - if(model->types[i] == UI_STRING_FREE) { - free(data); - } - break; - } - case UI_INTEGER: { - g_value_init(&value, G_TYPE_INT); - intptr_t intptr = (intptr_t)data; - g_value_set_int(&value, (int)intptr); - break; - } - case UI_ICON: { - g_value_init(&value, G_TYPE_OBJECT); - UiIcon *icon = data; -#if GTK_MAJOR_VERSION >= 4 - g_value_set_object(&value, icon->info); // TODO: does this work? -#else - if(!icon->pixbuf && icon->info) { - GError *error = NULL; - GdkPixbuf *pixbuf = gtk_icon_info_load_icon(icon->info, &error); - icon->pixbuf = pixbuf; - } - - if(icon->pixbuf) { - g_value_set_object(&value, icon->pixbuf); - } -#endif - break; - } - case UI_ICON_TEXT: - case UI_ICON_TEXT_FREE: { - UiIcon *icon = data; -#if GTK_MAJOR_VERSION >= 4 - if(icon) { - GValue iconvalue = G_VALUE_INIT; - g_value_init(&iconvalue, G_TYPE_OBJECT); - g_value_set_object(&iconvalue, ui_icon_pixbuf(icon)); - gtk_list_store_set_value(store, &iter, c, &iconvalue); - } -#else - GValue pixbufvalue = G_VALUE_INIT; - if(icon) { - if(!icon->pixbuf && icon->info) { - GError *error = NULL; - GdkPixbuf *pixbuf = gtk_icon_info_load_icon(icon->info, &error); - icon->pixbuf = pixbuf; - } - g_value_init(&pixbufvalue, G_TYPE_OBJECT); - g_value_set_object(&pixbufvalue, icon->pixbuf); - gtk_list_store_set_value(store, &iter, c, &pixbufvalue); - } -#endif - c++; - - char *str = model->getvalue(elm, c); - g_value_init(&value, G_TYPE_STRING); - g_value_set_string(&value, str); - if(model->types[i] == UI_ICON_TEXT_FREE) { - free(str); - } - break; - } - } - - gtk_list_store_set_value(store, &iter, c, &value); - } + update_list_row(store, &iter, model, elm); // next row elm = list->next(list); @@ -1039,9 +1053,18 @@ UIWIDGET ui_table_create(UiObject *obj, UiListArgs args) { void ui_listview_update(UiList *list, int i) { UiListView *view = list->obj; - GtkListStore *store = create_list_store(list, view->model); - gtk_tree_view_set_model(GTK_TREE_VIEW(view->widget), GTK_TREE_MODEL(store)); - g_object_unref(G_OBJECT(store)); + if(i < 0) { + GtkListStore *store = create_list_store(list, view->model); + gtk_tree_view_set_model(GTK_TREE_VIEW(view->widget), GTK_TREE_MODEL(store)); + g_object_unref(G_OBJECT(store)); + } else { + void *elm = list->get(list, i); + GtkTreeModel *store = gtk_tree_view_get_model(GTK_TREE_VIEW(view->widget)); + GtkTreeIter iter; + if(gtk_tree_model_iter_nth_child(store, &iter, NULL, i)) { + update_list_row(GTK_LIST_STORE(store), &iter, view->model, elm); + } + } } UiListSelection ui_listview_getselection(UiList *list) { -- 2.43.5