From: Olaf Wintermann Date: Wed, 20 May 2026 18:48:56 +0000 (+0200) Subject: implement NewNotebookDialog X-Git-Url: https://uap-core.de/gitweb/?a=commitdiff_plain;h=a19ef6e08dc228e46e2bdceda1d4a08addfe9523;p=note.git implement NewNotebookDialog --- diff --git a/application/src/backend.rs b/application/src/backend.rs index c7f18c1..8644692 100644 --- a/application/src/backend.rs +++ b/application/src/backend.rs @@ -227,4 +227,29 @@ impl BackendHandle { }); let _ = self.tx.send(cmd); } + + /// Creates a collection/notebook in the specified parent + pub fn add_notebook(&self, parent: &collection::Model, name: String, callback: F) + where F: FnOnce(Result) + Send + 'static { + let backend = self.backend.clone(); + let parent_path = format!("{}/{}", parent.parent, parent.name); + + let cmd = Box::pin(async move { + let profile_id = backend.current_profile.id; + + let insert_notebook = collection::ActiveModel { + profile_id: Set(profile_id), + name: Set(name.to_string()), + parent: Set(parent_path), + icon: Set("".to_string()), + kind: Set(CollectionType::Notebook), + + ..Default::default() + }; + + let result = insert_notebook.insert(&backend.db).await; + callback(result); + }); + let _ = self.tx.send(cmd); + } } diff --git a/application/src/newnotebook.rs b/application/src/newnotebook.rs index 395501b..1bb1aeb 100644 --- a/application/src/newnotebook.rs +++ b/application/src/newnotebook.rs @@ -26,18 +26,69 @@ * POSSIBILITY OF SUCH DAMAGE. */ -use ui_rs::{UiModel, UiActions}; +use ui_rs::{UiModel, ui_actions}; use ui_rs::ui::*; use entity::collection::{Model as Collection}; +use crate::backend::{BackendHandle}; -#[derive(UiModel, UiActions, Default)] +#[derive(UiModel)] struct NewNotebookDialog { + backend: BackendHandle, + + #[bind] name: UiString, + + #[bind] + message: UiString, + + #[bind] groups: UiList } -pub fn new_notebook_dialog(parent: &UiObject) { - let data = NewNotebookDialog::default(); +#[ui_actions] +impl NewNotebookDialog { + /// Creates a new notebook in the selected parent (group) + fn add_notebook(&mut self, obj: &UiObject) { + if self.name.get().len() == 0 { + self.message.set("Name required"); + return; + } + + let i = self.groups.selected_index(); + let collections = self.groups.data(); + let parent = usize::try_from(i).ok().and_then(|idx| collections.get(idx)); + if let Some(parent) = parent { + let proxy = obj.obj_proxy(); + + self.backend.add_notebook(parent, self.name.get(), |result|{ + proxy.call_mainthread(|obj, nnd|{ + match result { + Ok(_collection) => { + // we actually don't need the new collection object, we force + // a global reload + nnd.backend.reload_collections(); + obj.close(); + } + Err(err) => { + let msg = format!("add_notebook failed: {}", err); + nnd.message.set(msg.as_str()); + } + } + }); + }); + } else { + self.message.set("No parent selected"); + } + } +} + +pub fn new_notebook_dialog(parent: &UiObject, groups: &Vec, backend: BackendHandle) { + let data = NewNotebookDialog { + backend: backend, + name: Default::default(), + message: Default::default(), + groups: Default::default(), + }; parent.dialogwindow_builder() .title("Add Notebook") @@ -46,11 +97,21 @@ pub fn new_notebook_dialog(parent: &UiObject) { .lbutton1("Add") .rbutton4("Cancel") .default_button(1) - .onclick(|e|{ - e.obj.close(); + .onclick(|e: &mut Event|{ + if e.intval == 1 { + // button1 pressed + e.data.add_notebook(e.obj) + } else { + // button2 (Cancel) pressed + e.obj.close(); + } }) .create(data, |obj, data| { + // init data + data.groups.data().extend(groups.clone()); + + // create dialog UI obj.grid(|a| { a.margin(10); a.columnspacing(10); @@ -62,12 +123,15 @@ pub fn new_notebook_dialog(parent: &UiObject) { }, |obj| { obj.grid_row(|obj| { obj.rlabel_builder().label("Group").create(); - obj.dropdown_builder::().value(&data.groups).create(); + obj.dropdown_builder::().value(&data.groups).getvalue(|e, _col, _row| ListValue::String(e.name.clone()) ).create(); }); obj.grid_row(|obj| { obj.rlabel_builder().label("Name").create(); obj.textfield_builder().value(&data.name).create(); }); + obj.grid_row(|obj| { + obj.llabel_builder().value(&data.message).colspan(2).create(); + }); }); }).show(); } \ No newline at end of file diff --git a/application/src/window.rs b/application/src/window.rs index c95d98f..fad8730 100644 --- a/application/src/window.rs +++ b/application/src/window.rs @@ -35,8 +35,12 @@ use crate::newnotebook::new_notebook_dialog; #[derive(UiModel)] pub struct MainWindow { + pub obj: UiObjRef, + pub backend: BackendHandle, + groups: Vec, + #[bind] notebooks: UiSourceList } @@ -45,14 +49,16 @@ pub struct MainWindow { impl MainWindow { pub fn new(app: &App) -> MainWindow { MainWindow { + obj: UiObjRef::default(), backend: app.backend.clone(), + groups: Vec::new(), notebooks: UiSourceList::default() } } #[action] pub fn new_notebook(&mut self, event: &ActionEvent) { - new_notebook_dialog(event.obj); + new_notebook_dialog(event.obj, &self.groups, self.backend.clone()); } #[action] @@ -74,9 +80,29 @@ impl MainWindow { pub fn message(&mut self, _event: &ActionEvent) { while let Ok(msg) = self.backend.brx.try_recv() { match msg { - BroadcastMessage::NotebookStructureUpdate(nodes) => fill_sourcelist_from_nodes(&mut self.notebooks, &nodes), + BroadcastMessage::NotebookStructureUpdate(nodes) => self.update_notebook_structure(&nodes), + } + } + } + + fn update_notebook_structure(&mut self, nodes: &Vec) { + self.notebooks.clear(); + self.groups.clear(); + + for elm in nodes.iter() { + self.groups.push(elm.collection.clone()); + + let mut notebook = SubList::new(); + notebook.set_header(elm.collection.name.as_str()); + + let sublist_data = notebook.list().data(); + for child in elm.children.iter() { + sublist_data.push(child.collection.clone()); } + + self.notebooks.push(notebook); } + self.notebooks.update(); } } @@ -85,6 +111,7 @@ pub fn create_window(app: &App, ctx: &AppContext) -> UiObject) -> UiObject, nodes: &Vec) { - list.clear(); - - for elm in nodes.iter() { - let mut notebook = SubList::new(); - notebook.set_header(elm.collection.name.as_str()); - - let sublist_data = notebook.list().data(); - for child in elm.children.iter() { - sublist_data.push(child.collection.clone()); - } - - list.push(notebook); - } - list.update(); -} diff --git a/ui-rs/src/ui/label.rs b/ui-rs/src/ui/label.rs index 9de206e..9ce3b43 100644 --- a/ui-rs/src/ui/label.rs +++ b/ui-rs/src/ui/label.rs @@ -210,10 +210,11 @@ impl<'a, T> LabelBuilder<'a, T> { self } - pub fn value(&mut self, value: &toolkit::UiString) { + pub fn value(&mut self, value: &toolkit::UiString) -> &mut Self{ unsafe { ui_label_args_set_value(self.args, value.ptr); } + self } pub fn varname(&mut self, varname: &str) -> &mut Self { diff --git a/ui-rs/src/ui/toolkit.rs b/ui-rs/src/ui/toolkit.rs index bf9b568..5ee295f 100644 --- a/ui-rs/src/ui/toolkit.rs +++ b/ui-rs/src/ui/toolkit.rs @@ -207,7 +207,7 @@ impl UiObject { UiObjProxy::from_ptr(self.ptr) } - pub fn window_data(&mut self, f: F) + pub unsafe fn window_data(&self, f: F) where F: FnOnce(&mut T) { unsafe { let wdata_ptr: *mut T = ui_object_get_windowdata(self.ptr).cast(); @@ -339,12 +339,14 @@ impl UiObjProxy { } pub fn call_mainthread(self, f: F) - where F: FnOnce(&mut T) + Send + 'static { + where F: FnOnce(&UiObject, &mut T) + Send + 'static { call_mainthread(|| { - let mut obj: UiObject = UiObject::from_ptr(self.ptr); - obj.window_data(|wdata| { - f(wdata); - }); + let obj: UiObject = UiObject::from_ptr(self.ptr); + unsafe { + obj.window_data(|wdata| { + f(&obj, wdata); + }); + } drop(self); }); }