/* ------------------------------- 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);
#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;
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);
}
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);
}
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);
}
}
if(!note->content_loaded) {
note_load_content(model->window->obj, model, note);
}
+
+ notebookmodel_add2navstack(model);
}
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));
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);
+ }
+ */
+}
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
}
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);
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);
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;
}
// 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);
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);
}
}
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);