]> uap-core.de Git - note.git/commitdiff
add navstack
authorOlaf Wintermann <olaf.wintermann@gmail.com>
Sun, 2 Mar 2025 14:21:56 +0000 (15:21 +0100)
committerOlaf Wintermann <olaf.wintermann@gmail.com>
Sun, 2 Mar 2025 14:21:56 +0000 (15:21 +0100)
application/application.c
application/application.h
application/menu.c
application/notebook.c
application/notebook.h
application/window.c
application/window.h

index bef70d5cbd27e18f5cfd01ed2f5c03e02d9b2055..16e53d65cd8ae0838150cab915e74a624f862611 100644 (file)
@@ -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);
index e91cb3f2fa00a2456c316516ec74f36cae359b9a..22cd07deed81c82581bd4bdceba480b16971d2f2 100644 (file)
@@ -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);
 
 
index be0b5fae1fcfecdf4e376a1fe82436690f380dba..fd89f9a3f2e602024d813c14d8b05756b57dcf5d 100644 (file)
@@ -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);
 }
index 5ba84fadd6959b5d9bc4865189adab3ea5662729..106bb141d507315466b8819728a1d7cdbbe302df 100644 (file)
@@ -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);
+    }
+    */
+}
index 8c8c50c25a7f205d94e752d6f3ea2f8b263746a6..9ed6cbe479952d934021a3b394881769d513a6a9 100644 (file)
@@ -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
 }
index a50aa734908a2235c3450df9ffe5e12c2fb9a399..4ab3bc90abed517c7333b8560b112cb9b3b8f6f1 100644 (file)
@@ -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, &note_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);
     }
 }
index 8644f54a8387f7726b0e5608d845ac467cb00d19..1df1709893c86ad8d7663e759b8d4de31188c9ad 100644 (file)
@@ -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);