From: Olaf Wintermann Date: Sat, 6 Jun 2026 08:05:26 +0000 (+0200) Subject: add note selections to the navigation stack X-Git-Url: https://uap-core.de/gitweb/?a=commitdiff_plain;h=3402717834e0ca37a566625ac6affc21d0b9eb00;p=note.git add note selections to the navigation stack --- diff --git a/application/src/notebook.rs b/application/src/notebook.rs index 317d46c..a97c4df 100644 --- a/application/src/notebook.rs +++ b/application/src/notebook.rs @@ -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 { + 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) = ¬e.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) = ¬e.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(¬e.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 = Box::new(nav); - nb.ctx.call_action_with_parameter("navigation", param); + n.init_from_model(¬e.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 = 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>, } @@ -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 }; diff --git a/application/src/window.rs b/application/src/window.rs index 6290791..c4fcf7d 100644 --- a/application/src/window.rs +++ b/application/src/window.rs @@ -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(¬ebook_doc); self.selected_notebook = Some(notebook_doc); + if let Some(note_id) = &nav.note_id { + let arg: Box = 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; diff --git a/ui-rs/src/ui/toolkit.rs b/ui-rs/src/ui/toolkit.rs index b5d7ea1..3e781ab 100644 --- a/ui-rs/src/ui/toolkit.rs +++ b/ui-rs/src/ui/toolkit.rs @@ -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 UiList { 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 { self.data.as_mut() diff --git a/ui/common/types.c b/ui/common/types.c index bd4d384..72d5cd3 100644 --- a/ui/common/types.c +++ b/ui/common/types.c @@ -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;