From: Olaf Wintermann Date: Sun, 2 Mar 2025 14:21:56 +0000 (+0100) Subject: add navstack X-Git-Url: https://uap-core.de/gitweb/?a=commitdiff_plain;h=fc5b7ac87017c0dd2834819c1d5c0279dddb0470;p=note.git add navstack --- diff --git a/application/application.c b/application/application.c index bef70d5..16e53d6 100644 --- a/application/application.c +++ b/application/application.c @@ -101,6 +101,28 @@ void application_startup(UiEvent *event, void *data) { /* ------------------------------- Actions ------------------------------- */ +void action_go_back(UiEvent *event, void *data) { + MainWindow *w = event->window; + if(cxListSize(w->navstack) > 0 && w->navstack_pos > 0) { + w->navstack_pos--; + NavStack *elm = cxListAt(w->navstack, w->navstack_pos); + if(elm) { + window_navigate(w, elm); + } + } +} + +void action_go_forward(UiEvent *event, void *data) { + MainWindow *w = event->window; + if(w->navstack_pos+1 < cxListSize(w->navstack)) { + w->navstack_pos++; + NavStack *elm = cxListAt(w->navstack, w->navstack_pos); + if(elm) { + window_navigate(w, elm); + } + } +} + void action_note_new(UiEvent *event, void *data) { NotebookModel *notebook = event->document; notebookmodel_new_note(notebook); diff --git a/application/application.h b/application/application.h index e91cb3f..22cd07d 100644 --- a/application/application.h +++ b/application/application.h @@ -40,15 +40,32 @@ extern "C" { #define APP_STATE_NOTEBOOK_SELECTED 100 #define APP_STATE_NOTE_SELECTED 110 + + +#define VIEW_FLAGS_NO_BROWSER 1 // typedefs for NotebookModel and NoteModel are in types.h +typedef struct NavStack { + int64_t collection_id; + int64_t note_id; + uint64_t view_flags; +} NavStack; + typedef struct MainWindow { UiObject *obj; + CxList *navstack; + size_t navstack_pos; + UIWIDGET splitpane; UIWIDGET document_tabview; + /* + * is the note list visible (splitpane child 0) + */ + UiBool notelist_isvisible; + UiList *notebooks; NotebookModel *current_notebook; @@ -122,6 +139,10 @@ void application_init(); void application_startup(UiEvent *event, void *data); + +void action_go_back(UiEvent *event, void *data); +void action_go_forward(UiEvent *event, void *data); + void action_note_new(UiEvent *event, void *data); diff --git a/application/menu.c b/application/menu.c index be0b5fa..fd89f9a 100644 --- a/application/menu.c +++ b/application/menu.c @@ -33,7 +33,11 @@ void menu_init() { } void toolbar_init() { + ui_toolbar_item("GoBack", .icon = UI_ICON_GO_BACK, .onclick = action_go_back); + ui_toolbar_item("GoForward", .icon = UI_ICON_GO_FORWARD, .onclick = action_go_forward); ui_toolbar_item("AddNote", .icon = UI_ICON_ADD, .onclick = action_note_new, .groups = UI_GROUPS(APP_STATE_NOTEBOOK_SELECTED)); + ui_toolbar_add_default("GoBack", UI_TOOLBAR_LEFT); + ui_toolbar_add_default("GoForward", UI_TOOLBAR_LEFT); ui_toolbar_add_default("AddNote", UI_TOOLBAR_LEFT); } diff --git a/application/notebook.c b/application/notebook.c index 5ba84fa..106bb14 100644 --- a/application/notebook.c +++ b/application/notebook.c @@ -58,13 +58,19 @@ void notebookmodel_attach(MainWindow *window, NotebookModel *model) { window->current_notebook = model; model->window = window; ui_list_update(model->notes); // TODO: this should be unnecessary, attaching the document should update all values - - // TODO: Again, this should work automatically. Why it doesn't work: - // UiList selection is not saved (should the toolkit actually do it?) - // values from sub-values are bound but not reloaded + if(model->current_note) { + // TODO: Again, this should work automatically. Why it doesn't work: + // UiList selection is not saved (should the toolkit actually do it?) + // values from sub-values are bound but not reloaded notelist_select_note(model, model->current_note); // notebookmodel_attach_note(model, model->current_note); + } else { + // TODO: When the previous workaround (manual notelist_select_note) + // is not necessary, notebookmodel_add2navstack must be called + // even if model->current_note is not NULL + // Currently, notelist_select_note will call notebookmodel_add2navstack + notebookmodel_add2navstack(model); } } @@ -128,6 +134,8 @@ void notebookmodel_attach_note(NotebookModel *model, Note *note) { if(!note->content_loaded) { note_load_content(model->window->obj, model, note); } + + notebookmodel_add2navstack(model); } void notebookmodel_detach_current_note(NotebookModel *model) { @@ -137,6 +145,25 @@ void notebookmodel_detach_current_note(NotebookModel *model) { } } +/* + * Returns the Note* object with the specified note_id + * + * If index is not NULL, it is set to the index in the model->notes list + */ +Note* notebookmodel_get_note_by_id(NotebookModel *model, int64_t note_id, size_t *index) { + CxList *list = model->notes->data; // UiList is based on CxList + CxIterator i = cxListIterator(list); + cx_foreach(Note *, note, i) { + if(note->note_id == note_id) { + if(index) { + *index = i.index; + } + return note; + } + } + return NULL; +} + void notebookmodel_new_note(NotebookModel *model) { Note *new_note = cxMalloc(model->current_notes_pool->allocator, sizeof(Note)); @@ -146,3 +173,48 @@ void notebookmodel_new_note(NotebookModel *model) { notebookmodel_attach_note(model, new_note); new_note->model->modified = TRUE; } + +/* + * Add the current state (notebook + note + ui options) to the navstack. + * If the user navigated through the navstack and the current pos is not the + * end of the navstack, all elements after the current pos are removed, + * before the new element is added + */ +void notebookmodel_add2navstack(NotebookModel *model) { + MainWindow *w = model->window; + if(!w->navstack) { + return; + } + UiBool list_visible = w->notelist_isvisible; + + // init NavStack element + NavStack nav; + nav.collection_id = model->collection_id; + nav.note_id = model->current_note ? model->current_note->note_id : 0; + nav.view_flags = 0; + + if(!list_visible) { + nav.view_flags |= VIEW_FLAGS_NO_BROWSER; + } + + // remove all elements after current navstack position + CxList *navstack = w->navstack; + size_t navstack_size = cxListSize(navstack); + if(w->navstack_pos+1 < navstack_size) { + for(size_t i=navstack_size-1;i>w->navstack_pos;i--) { + cxListRemove(navstack, i); + } + } + + // add new element + cxListAdd(navstack, &nav); + w->navstack_pos = cxListSize(navstack) - 1; + + /* + printf("\n\nnavstack\n"); + CxIterator i = cxListIterator(navstack); + cx_foreach(NavStack *, elm, i) { + printf("nav: %d - %d : %d\n", (int)elm->collection_id, (int)elm->note_id, (int)elm->view_flags); + } + */ +} diff --git a/application/notebook.h b/application/notebook.h index 8c8c50c..9ed6cbe 100644 --- a/application/notebook.h +++ b/application/notebook.h @@ -49,8 +49,12 @@ void notebookmodel_reload(UiObject *obj, NotebookModel *model); void notebookmodel_attach_note(NotebookModel *model, Note *note); void notebookmodel_detach_current_note(NotebookModel *model); +Note* notebookmodel_get_note_by_id(NotebookModel *model, int64_t note_id, size_t *index); + void notebookmodel_new_note(NotebookModel *model); +void notebookmodel_add2navstack(NotebookModel *model); + #ifdef __cplusplus } diff --git a/application/window.c b/application/window.c index a50aa73..4ab3bc9 100644 --- a/application/window.c +++ b/application/window.c @@ -85,6 +85,9 @@ MainWindow* window_init_data(UiObject *obj) { obj->window = wdata; wdata->obj = obj; + wdata->notelist_isvisible = TRUE; + wdata->navstack = cxArrayListCreateSimple(sizeof(NavStack), 32); + wdata->notebooks = ui_list_new(obj->ctx, NULL); update_sublists(obj->ctx, wdata->notebooks); @@ -93,6 +96,11 @@ MainWindow* window_init_data(UiObject *obj) { return wdata; } +void window_notelist_setvisible(MainWindow *window, UiBool visible) { + ui_splitpane_set_visible(window->splitpane, 0, visible); + window->notelist_isvisible = visible; +} + void window_sidebar_getvalue(void *sublist_userdata, void *rowdata, int index, UiSubListItem *item) { Collection *notebook = rowdata; item->label = strdup(notebook->display_name ? notebook->display_name : notebook->name); @@ -174,6 +182,45 @@ void* window_notelist_getvalue(void *data, int col) { return NULL; } + + +NotebookModel* window_get_cached_notebook(MainWindow *window, int64_t collection_id) { + CxHashKey key = cx_hash_key(&collection_id, sizeof(collection_id)); + return cxMapGet(window->notebook_cache, key); +} + +/* + * Loads the notebook/note with UI options specified by the NavStack element + */ +void window_navigate(MainWindow *window, NavStack *nav) { + if(nav->collection_id == 0) { + return; + } + // when a collection is on the navstack, it should also be in the cache + NotebookModel *notebook = window_get_cached_notebook(window, nav->collection_id); + if(!notebook) { + printf("window_navigate: notebook not in cache\n"); + return; + } + + size_t note_index; + Note *note = nav->note_id != 0 ? notebookmodel_get_note_by_id(notebook, nav->note_id, ¬e_index) : NULL; + + window_notelist_setvisible(window, !(nav->view_flags & VIEW_FLAGS_NO_BROWSER)); + + CxList *navstack = window->navstack; + window->navstack = NULL; // disable navstack temporarly + + notebookmodel_attach(window, notebook); + if(note) { + ui_list_setselection(notebook->notes, note_index); + } + + window->navstack = navstack; // re-enable navstack +} + + + void action_notebook_selected(UiEvent *event, void *userdata) { UiSubListEventData *data = event->eventdata; MainWindow *window = event->window; @@ -187,7 +234,7 @@ void action_notebook_selected(UiEvent *event, void *userdata) { } // reset splitpane visibility - ui_splitpane_set_visible(window->splitpane, 0, TRUE); + window_notelist_setvisible(window, TRUE); CxHashKey key = cx_hash_key(&collection->collection_id, sizeof(collection->collection_id)); NotebookModel *notebook = cxMapGet(window->notebook_cache, key); @@ -229,7 +276,11 @@ void action_note_selected(UiEvent *event, void *userdata) { void action_note_activated(UiEvent *event, void *userdata) { MainWindow *window = event->window; - if(select_note(event)) { - ui_splitpane_set_visible(window->splitpane, 0, FALSE); + // we have to hide the notelist first, because select_note will add the + // current UI state to the navstack + window_notelist_setvisible(window, FALSE); + if(!select_note(event)) { + // undo window_notelist_setvisible, however this should never happen + window_notelist_setvisible(window, TRUE); } } diff --git a/application/window.h b/application/window.h index 8644f54..1df1709 100644 --- a/application/window.h +++ b/application/window.h @@ -42,6 +42,12 @@ MainWindow* window_init_data(UiObject *obj); void window_sidebar_getvalue(void *sublist_userdata, void *rowdata, int index, UiSubListItem *item); +void window_notelist_setvisible(MainWindow *window, UiBool visible); + +NotebookModel* window_get_cached_notebook(MainWindow *window, int64_t collection_id); + +void window_navigate(MainWindow *window, NavStack *nav); + void update_sublists(UiContext *ctx, UiList *sublists); void* window_notelist_getvalue(void *data, int col);