]> uap-core.de Git - note.git/commitdiff
add note selections to the navigation stack
authorOlaf Wintermann <olaf.wintermann@gmail.com>
Sat, 6 Jun 2026 08:05:26 +0000 (10:05 +0200)
committerOlaf Wintermann <olaf.wintermann@gmail.com>
Sat, 6 Jun 2026 08:05:26 +0000 (10:05 +0200)
application/src/notebook.rs
application/src/window.rs
ui-rs/src/ui/toolkit.rs
ui/common/types.c

index 317d46c08a57f54d21623bb82b16c0a9f4c7534a..a97c4df37d678c2aa5dbe4724be4eb18ee076122 100644 (file)
@@ -48,8 +48,8 @@ impl Notebook {
         self.notes.update();
     }
 
-    /// Saves and detaches the current note. This does NOT change self.selected_note
-    pub fn detach_current_note(&self) {
+    /// Saves and detaches the current note.
+    pub fn detach_current_note(&mut self) {
         // detach the current note
         if let Some(current) = &self.selected_note {
             // doc_ref.get_doc() should never fail here
@@ -64,47 +64,81 @@ impl Notebook {
 
                 // detach the note
                 doc.ctx.detach(current);
+                self.selected_note = None;
             }
         }
     }
 
-    #[action]
-    pub fn note_selected(&mut self, event: &ActionEvent) {
-        if let EventType::ListSelection(s) = event.event_type {
-            self.selected_index = s.selected_index();
-            if self.selected_index.is_some() {
+    pub fn find_note(&self, id: NoteId) -> Option<usize> {
+        for (index, note) in self.notes.iter().enumerate() {
+            if note.id == id || note.orig_id == id {
+                return Some(index)
+            }
+        }
+        None
+    }
+
+    pub fn select_note_from(&mut self, from: NoteSelectFrom) -> Option<()> {
+        self.detach_current_note();
+        self.selected_note = None;
+        self.selected_index = None;
+
+        let mut add_to_nav = false;
+        let (selected_index, note) = match from {
+            NoteSelectFrom::ListSelection(s) => {
+                let index = s.selected_index()?;
                 self.detach_current_note();
-                self.selected_note = None;
+                let note = s.selected_element_mut(self.notes.data_mut())?;
+                add_to_nav = true;
+                (index, note)
+            },
+            NoteSelectFrom::NavigationItem(nav) => {
+                let index = self.find_note(nav.note_id?)?;
+                self.detach_current_note();
+                self.notes.select_with_event(index as i32, false);
+                let note = self.notes.data_mut().get_mut(index)?;
+                (index, note)
             }
-            if let Some(note) = s.selected_element_mut(self.notes.data_mut()) {
-                let nav = NavigationItem { collection_id: self.collection_id, note_id: Some(note.id.clone()) };
-                let doc = if let Some(doc) = &note.model {
-                    doc.clone()
+        };
+        self.selected_index = Some(selected_index);
+
+        let nav = NavigationItem { collection_id: self.collection_id, note_id: Some(note.id.clone()) };
+        let doc = if let Some(doc) = &note.model {
+            doc.clone()
+        } else {
+            // Create the new note
+            let note_data = crate::note::Note::new(note.id.clone(), self.collection_id, self.backend.clone());
+            // Create the note document object
+            UiDoc::new2(note_data, |n,d| {
+                n.doc = d.doc_ref();
+                if note.is_new() {
+                    n.init_new();
                 } else {
-                    // Create the new note
-                    let note_data = crate::note::Note::new(note.id.clone(), self.collection_id, self.backend.clone());
-                    // Create the note document object
-                    UiDoc::new2(note_data, |n,d| {
-                        n.doc = d.doc_ref();
-                        if note.is_new() {
-                            n.init_new();
-                        } else {
-                            n.init_from_model(&note.data);
-                            n.load_content(d);
-                        }
-                    })
-                };
-                note.model = Some(doc.clone());
-
-                if let Some(mut nb) = self.doc_ref.get_doc() {
-                    nb.ctx.attach(&doc);
-                    self.selected_note = Some(doc);
-                    
-                    let param: Box<dyn Any> = Box::new(nav);
-                    nb.ctx.call_action_with_parameter("navigation", param);
+                    n.init_from_model(&note.data);
+                    n.load_content(d);
                 }
+            })
+        };
+        note.model = Some(doc.clone());
+
+        if let Some(mut nb) = self.doc_ref.get_doc() {
+            nb.ctx.attach(&doc);
+            self.selected_note = Some(doc);
+
+            if add_to_nav {
+                let arg: Box<dyn Any> = Box::new(nav);
+                nb.ctx.call_action_with_parameter("navigation", arg);
             }
         }
+
+        Some(())
+    }
+
+    #[action]
+    pub fn note_selected(&mut self, event: &ActionEvent) {
+        if let EventType::ListSelection(s) = event.event_type {
+            self.select_note_from(NoteSelectFrom::ListSelection(s));
+        }
     }
 
     #[action]
@@ -117,6 +151,17 @@ impl Notebook {
         self.notes.select_with_event(0, true);
     }
 
+    #[action(NavigationItem)]
+    pub fn navigate_to_note(&mut self, _event: &ActionEvent, nav: &NavigationItem) {
+        println!("navigate to note");
+        if nav.collection_id != self.collection_id {
+            println!("invalid navigation event: notebook collection_id {} != {}", self.collection_id, nav.collection_id);
+            return;
+        }
+
+        self.select_note_from(NoteSelectFrom::NavigationItem(nav.clone()));
+    }
+
     pub fn update_note(&mut self, update: &NoteUpdate) {
         // Find the note in the list (or add it if it doesn't exist yet)
         // Start with the currently selected note
@@ -193,6 +238,11 @@ impl Drop for Notebook {
     }
 }
 
+enum NoteSelectFrom<'a> {
+    ListSelection(&'a ListSelection),
+    NavigationItem(NavigationItem),
+}
+
 /// SourceList sublist item
 pub struct NotebookItem {
     pub data: entity::collection::Model,
@@ -247,6 +297,7 @@ impl NotebookItem {
 /// ListView item
 pub struct NoteItem {
     id: NoteId,
+    orig_id: NoteId,
     data: entity::note::Model,
     model: Option<UiDoc<crate::note::Note>>,
 }
@@ -255,14 +306,20 @@ impl NoteItem {
     pub fn from_model(data: entity::note::Model) -> Self {
         NoteItem {
             id: NoteId::Id(data.note_id),
+            orig_id: NoteId::Id(data.note_id),
             data: data,
             model: None
         }
     }
 
     pub fn new(id: NoteId) -> Self {
+        let tmp_id = match id {
+            NoteId::Id(id) => 0,
+            NoteId::TmpId(id) => id
+        };
         let mut item = NoteItem {
-            id: id,
+            id: id.clone(),
+            orig_id: id,
             data: entity::note::Model::new(),
             model: None
         };
index 62907918afb53c258b7037d5d3f3846d0b8a55f7..c4fcf7dbdda9afc16c9597134d6a66d8a06162b6 100644 (file)
@@ -25,7 +25,7 @@
  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  * POSSIBILITY OF SUCH DAMAGE.
  */
-
+use std::any::Any;
 use ui_rs::{action, ui_actions, UiModel};
 use ui_rs::ui::*;
 use crate::App;
@@ -128,6 +128,11 @@ impl MainWindow {
         obj.ctx.attach(&notebook_doc);
         self.selected_notebook = Some(notebook_doc);
 
+        if let Some(note_id) = &nav.note_id {
+            let arg: Box<dyn Any> = Box::new(nav.clone());
+            obj.ctx.call_action_with_parameter("navigate_to_note", arg);
+        }
+
         Some(())
     }
 
@@ -287,7 +292,19 @@ pub struct Navigation {
 impl Navigation {
     pub fn push(&mut self, page: NavigationItem) {
         // If we are not at the end, truncate forward history
-        self.history.truncate(self.current + 1);
+        self.history.truncate(self.current);
+
+        if self.current > 1 && page.note_id.is_some() {
+            let prev = &mut self.history[self.current-1];
+            if prev.collection_id == page.collection_id && prev.note_id.is_none() {
+                // The previous navigation item was just a selected collection without note.
+                // Going back from a note to a navitem with the same collection but without
+                // a note looks like a NOOP for the user, because the current note is not
+                // unselected in that case.
+                prev.note_id = page.note_id;
+                return;
+            }
+        }
 
         self.history.push(page);
         self.current += 1;
index b5d7ea10135b691130795b7f80ffc665d041c527..3e781ab20743af3655e1a0e2e45488c54593e89f 100644 (file)
@@ -35,6 +35,7 @@ use crate::ui::{action_event_wrapper, event, ffi, ui_object_get_context, ui_obje
 use std::marker::PhantomData;
 use std::mem;
 use std::ptr::null_mut;
+use std::slice::{Iter, IterMut};
 use std::sync::{Arc, Mutex};
 use crate::ui::ffi::{UiCallback, UiThreadFunc};
 
@@ -770,6 +771,14 @@ impl<T> UiList<T> {
         list.init(&ctx, None);
         list
     }
+    
+    pub fn iter(&self) -> Iter<'_, T> {
+        self.data.iter()
+    }
+
+    pub fn iter_mut(&mut self) -> IterMut<'_, T> {
+        self.data.iter_mut()
+    }
 
     pub fn data_mut(&mut self) -> &mut Vec<T> {
         self.data.as_mut()
index bd4d384c8582a5e96e34b40eb0abf9a236e53012..72d5cd36da8d065c15ed239d3b04c70b632ac035 100644 (file)
@@ -812,16 +812,7 @@ void uic_range_unbind(UiRange *r) {
     r->obj = NULL;
 }
 
-void uic_list_unbind(UiList *l) {
-    // save selection
-    ui_list_selection_free(l->saved_selection);
-    if(l->getselection && l->save_selection) {
-        l->saved_selection = ui_list_get_selection_allocated(l);
-    } else {
-        l->saved_selection = NULL;
-    }
-    
-    // unbind
+void uic_list_unbind(UiList *l) {      
     l->update = NULL;
     l->getselection = NULL;
     l->setselection = NULL;