diff --git a/bin/app/src/app/node.rs b/bin/app/src/app/node.rs index f172b6e3b..5140c3cd9 100644 --- a/bin/app/src/app/node.rs +++ b/bin/app/src/app/node.rs @@ -711,5 +711,9 @@ pub fn create_menu(name: &str) -> SceneNode { node.add_method("mark_alert", vec![("item_name", "Item name", CallArgType::Str)], None) .unwrap(); + node.add_method("cancel_edit", vec![], None).unwrap(); + + node.add_method("done_edit", vec![], None).unwrap(); + node } diff --git a/bin/app/src/app/schema/menu.rs b/bin/app/src/app/schema/menu.rs index fcb0e4c7c..008b1be99 100644 --- a/bin/app/src/app/schema/menu.rs +++ b/bin/app/src/app/schema/menu.rs @@ -192,6 +192,72 @@ pub async fn make(app: &App, content: SceneNodePtr, i18n_fish: &I18nBabelFish) { let version_block_is_visible = PropertyBool::wrap(&node, Role::App, "is_visible", 0).unwrap(); layer_node.link(node); + // Make buttons for cancel and done + + let node = create_layer("editbtn_layer"); + let prop = node.get_property("rect").unwrap(); + prop.set_f32(atom, Role::App, 0, 50.).unwrap(); + let code = cc.compile("h - 100 - 50").unwrap(); + prop.set_expr(atom, Role::App, 1, code).unwrap(); + let code = cc.compile("w - 100").unwrap(); + prop.set_expr(atom, Role::App, 2, code).unwrap(); + prop.set_f32(atom, Role::App, 3, 100.).unwrap(); + node.set_property_bool(atom, Role::App, "is_visible", false).unwrap(); + node.set_property_u32(atom, Role::App, "z_index", 2).unwrap(); + node.set_property_u32(atom, Role::App, "priority", 1).unwrap(); + let editlayer_node = node.setup(|me| Layer::new(me, app.renderer.clone())).await; + layer_node.link(editlayer_node.clone()); + + let editlayer_is_visible = + PropertyBool::wrap(&editlayer_node, Role::App, "is_visible", 0).unwrap(); + + let node = create_vector_art("btns_bg"); + let prop = node.get_property("rect").unwrap(); + prop.set_f32(atom, Role::App, 0, 0.).unwrap(); + prop.set_f32(atom, Role::App, 1, 0.).unwrap(); + prop.set_expr(atom, Role::App, 2, expr::load_var("w")).unwrap(); + prop.set_expr(atom, Role::App, 3, expr::load_var("h")).unwrap(); + node.set_property_u32(atom, Role::App, "z_index", 0).unwrap(); + + let mut shape = VectorShape::new(); + + shape.add_gradient_box( + expr::const_f32(0.), + expr::const_f32(0.), + expr::const_f32(200.), + expr::load_var("h"), + [[0., 0., 0., 1.], [0., 0., 0., 1.], [0.1, 0., 0., 1.], [0.1, 0., 0., 1.]], + ); + shape.add_outline( + expr::const_f32(0.), + expr::const_f32(0.), + expr::const_f32(200.), + expr::load_var("h"), + 1., + [1., 0., 0., 1.], + ); + + shape.add_gradient_box( + cc.compile("w - 200").unwrap(), + expr::const_f32(0.), + expr::load_var("w"), + expr::load_var("h"), + [[0., 0.1, 0.15, 1.], [0., 0.1, 0.15, 1.], [0., 0., 0., 1.], [0., 0., 0., 1.]], + ); + shape.add_outline( + cc.compile("w - 200").unwrap(), + expr::const_f32(0.), + expr::load_var("w"), + expr::load_var("h"), + 1., + [0., 0.94, 1., 1.], + ); + + let node = node.setup(|me| VectorArt::new(me, shape, app.renderer.clone())).await; + editlayer_node.link(node); + + // Menu + let node = create_menu("main_menu"); let prop = node.get_property("rect").unwrap(); prop.set_f32(atom, Role::App, 0, 0.).unwrap(); @@ -200,6 +266,7 @@ pub async fn make(app: &App, content: SceneNodePtr, i18n_fish: &I18nBabelFish) { let code = cc.compile("h - CHANNEL_LABEL_LINESPACE").unwrap(); prop.set_expr(atom, Role::App, 3, code).unwrap(); node.set_property_u32(atom, Role::App, "z_index", 0).unwrap(); + node.set_property_u32(atom, Role::App, "priority", 0).unwrap(); node.set_property_f32(atom, Role::App, "padding", CHANNEL_LABEL_LINESPACE).unwrap(); let prop = node.get_property("bg_color").unwrap(); @@ -273,9 +340,6 @@ pub async fn make(app: &App, content: SceneNodePtr, i18n_fish: &I18nBabelFish) { }); app.tasks.lock().unwrap().push(listen_click); - // Debug thing - version_block_is_visible.set(atom, false); - // Subscribe to edit_active signal to hide version block let (edit_slot, edit_recvr) = Slot::new("edit_activated"); node.register("edit_active", edit_slot).unwrap(); @@ -285,72 +349,14 @@ pub async fn make(app: &App, content: SceneNodePtr, i18n_fish: &I18nBabelFish) { debug!(target: "app::menu", "menu edit active"); let atom = &mut renderer.make_guard(gfxtag!("edit_active")); version_block_is_visible.set(atom, false); + editlayer_is_visible.set(atom, true); } }); app.tasks.lock().unwrap().push(edit_listen); - let node = node.setup(|me| Menu::new(me, window_scale.clone(), app.renderer.clone())).await; - layer_node.link(node); - - // Make buttons for cancel and done - - let editlayer_node = create_layer("editbtn_layer"); - let prop = editlayer_node.get_property("rect").unwrap(); - prop.set_f32(atom, Role::App, 0, 50.).unwrap(); - let code = cc.compile("h - 100 - 50").unwrap(); - prop.set_expr(atom, Role::App, 1, code).unwrap(); - let code = cc.compile("w - 100").unwrap(); - prop.set_expr(atom, Role::App, 2, code).unwrap(); - prop.set_f32(atom, Role::App, 3, 100.).unwrap(); - editlayer_node.set_property_bool(atom, Role::App, "is_visible", true).unwrap(); - editlayer_node.set_property_u32(atom, Role::App, "z_index", 2).unwrap(); - let editlayer_node = editlayer_node.setup(|me| Layer::new(me, app.renderer.clone())).await; - layer_node.link(editlayer_node.clone()); - - let node = create_vector_art("btns_bg"); - let prop = node.get_property("rect").unwrap(); - prop.set_f32(atom, Role::App, 0, 0.).unwrap(); - prop.set_f32(atom, Role::App, 1, 0.).unwrap(); - prop.set_expr(atom, Role::App, 2, expr::load_var("w")).unwrap(); - prop.set_expr(atom, Role::App, 3, expr::load_var("h")).unwrap(); - node.set_property_u32(atom, Role::App, "z_index", 0).unwrap(); - - let mut shape = VectorShape::new(); - - shape.add_gradient_box( - expr::const_f32(0.), - expr::const_f32(0.), - expr::const_f32(200.), - expr::load_var("h"), - [[0., 0., 0., 1.], [0., 0., 0., 1.], [0.1, 0., 0., 1.], [0.1, 0., 0., 1.]], - ); - shape.add_outline( - expr::const_f32(0.), - expr::const_f32(0.), - expr::const_f32(200.), - expr::load_var("h"), - 1., - [1., 0., 0., 1.], - ); - - shape.add_gradient_box( - cc.compile("w - 200").unwrap(), - expr::const_f32(0.), - expr::load_var("w"), - expr::load_var("h"), - [[0., 0.1, 0.15, 1.], [0., 0.1, 0.15, 1.], [0., 0., 0., 1.], [0., 0., 0., 1.]], - ); - shape.add_outline( - cc.compile("w - 200").unwrap(), - expr::const_f32(0.), - expr::load_var("w"), - expr::load_var("h"), - 1., - [0., 0.94, 1., 1.], - ); - - let node = node.setup(|me| VectorArt::new(me, shape, app.renderer.clone())).await; - editlayer_node.link(node); + let menu_node = + node.setup(|me| Menu::new(me, window_scale.clone(), app.renderer.clone())).await; + layer_node.link(menu_node.clone()); // Create the cancel button let node = create_button("cancel_btn"); @@ -363,9 +369,10 @@ pub async fn make(app: &App, content: SceneNodePtr, i18n_fish: &I18nBabelFish) { let (slot, recvr) = Slot::new("cancel_clicked"); node.register("click", slot).unwrap(); + let menu_node2 = menu_node.clone(); let listen_click = app.ex.spawn(async move { while let Ok(_) = recvr.recv().await { - info!("cancel"); + menu_node2.call_method("cancel_edit", vec![]).await.unwrap(); } }); app.tasks.lock().unwrap().push(listen_click); @@ -385,9 +392,10 @@ pub async fn make(app: &App, content: SceneNodePtr, i18n_fish: &I18nBabelFish) { let (slot, recvr) = Slot::new("done_clicked"); node.register("click", slot).unwrap(); + let menu_node2 = menu_node.clone(); let listen_click = app.ex.spawn(async move { while let Ok(_) = recvr.recv().await { - info!("done"); + menu_node2.call_method("done_edit", vec![]).await.unwrap(); } }); app.tasks.lock().unwrap().push(listen_click); diff --git a/bin/app/src/ui/menu/mod.rs b/bin/app/src/ui/menu/mod.rs index bb1ad4457..c14ea664a 100644 --- a/bin/app/src/ui/menu/mod.rs +++ b/bin/app/src/ui/menu/mod.rs @@ -612,6 +612,48 @@ impl Menu { true } + + /// Cancels edit mode changes, reverting any modifications made during edit mode + async fn process_cancel_method(me: &Weak, sub: &MethodCallSub) -> bool { + let Ok(method_call) = sub.receive().await else { + d!("Event relayer closed"); + return false + }; + + d!("method called: cancel({method_call:?})"); + assert!(method_call.send_res.is_none()); + + let Some(self_) = me.upgrade() else { + d!("Self destroyed"); + return true + }; + + // TODO: Implement cancel logic - revert edit mode changes + d!("cancel: stub - will revert edit mode changes"); + + true + } + + /// Accepts edit mode changes, finalizing any modifications made during edit mode + async fn process_done_method(me: &Weak, sub: &MethodCallSub) -> bool { + let Ok(method_call) = sub.receive().await else { + d!("Event relayer closed"); + return false + }; + + d!("method called: done({method_call:?})"); + assert!(method_call.send_res.is_none()); + + let Some(self_) = me.upgrade() else { + d!("Self destroyed"); + return true + }; + + // TODO: Implement done logic - accept edit mode changes + d!("done: stub - will accept edit mode changes"); + + true + } } #[async_trait] @@ -653,6 +695,16 @@ impl UIObject for Menu { async move { while Self::process_mark_alert_method(&me2, &method_sub).await {} }, ); + let method_sub = node_ref.subscribe_method_call("cancel_edit").unwrap(); + let me2 = me.clone(); + let cancel_task = + ex.spawn(async move { while Self::process_cancel_method(&me2, &method_sub).await {} }); + + let method_sub = node_ref.subscribe_method_call("done_edit").unwrap(); + let me2 = me.clone(); + let done_task = + ex.spawn(async move { while Self::process_done_method(&me2, &method_sub).await {} }); + let mut on_modify = OnModify::new(ex, self.node.clone(), me.clone()); async fn redraw(self_: Arc, batch: BatchGuardPtr) { @@ -669,7 +721,8 @@ impl UIObject for Menu { on_modify.when_change(self.sep_size.prop(), redraw); on_modify.when_change(self.sep_color.prop(), redraw); - let mut tasks = vec![motion_task, mark_active_task, mark_alert_task]; + let mut tasks = + vec![motion_task, mark_active_task, mark_alert_task, cancel_task, done_task]; tasks.append(&mut on_modify.tasks); *self.tasks.lock() = tasks; }