ticking context menu
This commit is contained in:
@@ -196,7 +196,7 @@ impl TestbedGeneric {
|
||||
button_context_menu.on_click({
|
||||
let tasks = testbed.tasks.clone();
|
||||
Box::new(move |_common, m| {
|
||||
tasks.push(TestbedTask::ShowContextMenu(m.mouse_pos_absolute.unwrap()));
|
||||
tasks.push(TestbedTask::ShowContextMenu(m.boundary.bottom_left()));
|
||||
Ok(())
|
||||
})
|
||||
});
|
||||
@@ -254,28 +254,25 @@ impl TestbedGeneric {
|
||||
data: &mut Data,
|
||||
position: Vec2,
|
||||
) -> anyhow::Result<()> {
|
||||
data.context_menu.open(&mut context_menu::OpenParams {
|
||||
globals: &self.globals,
|
||||
layout: &mut self.layout,
|
||||
data.context_menu.open(context_menu::OpenParams {
|
||||
position,
|
||||
on_action: Rc::new(move |action| {
|
||||
log::info!("got action: {}", action.name);
|
||||
}),
|
||||
cells: vec![
|
||||
context_menu::Cell {
|
||||
title: Translation::from_raw_text("Options"),
|
||||
action_name: "options".into(),
|
||||
},
|
||||
context_menu::Cell {
|
||||
title: Translation::from_raw_text("Exit software"),
|
||||
action_name: "exit".into(),
|
||||
},
|
||||
context_menu::Cell {
|
||||
title: Translation::from_raw_text("Restart software"),
|
||||
action_name: "restart".into(),
|
||||
},
|
||||
],
|
||||
})?;
|
||||
data: context_menu::Blueprint {
|
||||
cells: vec![
|
||||
context_menu::Cell {
|
||||
title: Translation::from_raw_text("Options"),
|
||||
action_name: "options".into(),
|
||||
},
|
||||
context_menu::Cell {
|
||||
title: Translation::from_raw_text("Exit software"),
|
||||
action_name: "exit".into(),
|
||||
},
|
||||
context_menu::Cell {
|
||||
title: Translation::from_raw_text("Restart software"),
|
||||
action_name: "restart".into(),
|
||||
},
|
||||
],
|
||||
},
|
||||
});
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -297,6 +294,11 @@ impl Testbed for TestbedGeneric {
|
||||
self.process_task(&task, &mut params, &mut data)?;
|
||||
}
|
||||
|
||||
let res = data.context_menu.tick(&mut self.layout)?;
|
||||
if let Some(action_name) = res.action_name {
|
||||
log::info!("got action: {}", action_name);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
@@ -68,6 +68,7 @@ impl Default for Params<'_> {
|
||||
|
||||
pub struct ButtonClickEvent {
|
||||
pub mouse_pos_absolute: Option<Vec2>,
|
||||
pub boundary: Boundary,
|
||||
}
|
||||
pub type ButtonClickCallback = Box<dyn Fn(&mut CallbackDataCommon, ButtonClickEvent) -> anyhow::Result<()>>;
|
||||
|
||||
@@ -388,6 +389,7 @@ fn register_event_mouse_release(
|
||||
common,
|
||||
ButtonClickEvent {
|
||||
mouse_pos_absolute: event_data.metadata.get_mouse_pos_absolute(),
|
||||
boundary: event_data.widget_data.cached_absolute_boundary,
|
||||
},
|
||||
)?;
|
||||
}
|
||||
|
||||
@@ -54,6 +54,41 @@ impl Boundary {
|
||||
}
|
||||
}
|
||||
|
||||
pub const fn bottom_left(&self) -> Vec2 {
|
||||
Vec2::new(self.pos.x, self.pos.y + self.size.y)
|
||||
}
|
||||
|
||||
pub const fn bottom_right(&self) -> Vec2 {
|
||||
Vec2::new(self.pos.x + self.size.x, self.pos.y + self.size.y)
|
||||
}
|
||||
|
||||
pub const fn top_right(&self) -> Vec2 {
|
||||
Vec2::new(self.pos.x + self.size.x, self.pos.y)
|
||||
}
|
||||
|
||||
pub const fn center(&self) -> Vec2 {
|
||||
Vec2::new(self.pos.x + self.size.x / 2.0, self.pos.y + self.size.y / 2.0)
|
||||
}
|
||||
|
||||
pub const fn width(&self) -> f32 {
|
||||
self.size.x
|
||||
}
|
||||
|
||||
pub const fn height(&self) -> f32 {
|
||||
self.size.y
|
||||
}
|
||||
|
||||
pub const fn area(&self) -> f32 {
|
||||
self.size.x * self.size.y
|
||||
}
|
||||
|
||||
pub const fn contains_point(&self, point: Vec2) -> bool {
|
||||
point.x >= self.pos.x
|
||||
&& point.x <= self.pos.x + self.size.x
|
||||
&& point.y >= self.pos.y
|
||||
&& point.y <= self.pos.y + self.size.y
|
||||
}
|
||||
|
||||
pub const fn top(&self) -> f32 {
|
||||
self.pos.y
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ use crate::{
|
||||
i18n::Translation,
|
||||
layout::Layout,
|
||||
parser::{self, Fetchable},
|
||||
task::Tasks,
|
||||
windowing::window::{WguiWindow, WguiWindowParams, WguiWindowParamsExtra},
|
||||
};
|
||||
|
||||
@@ -18,37 +19,60 @@ pub struct Cell {
|
||||
pub action_name: Rc<str>,
|
||||
}
|
||||
|
||||
pub struct Blueprint {
|
||||
pub cells: Vec<Cell>,
|
||||
}
|
||||
|
||||
pub struct ContextMenuAction<'a> {
|
||||
pub common: &'a mut CallbackDataCommon<'a>,
|
||||
pub name: Rc<str>, // action name
|
||||
}
|
||||
|
||||
pub struct OpenParams<'a> {
|
||||
pub struct OpenParams {
|
||||
pub position: Vec2,
|
||||
pub globals: &'a WguiGlobals,
|
||||
pub layout: &'a mut Layout,
|
||||
pub on_action: Rc<dyn Fn(ContextMenuAction)>,
|
||||
pub cells: Vec<Cell>,
|
||||
pub data: Blueprint,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
enum Task {
|
||||
ActionClicked(Rc<str>),
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct ContextMenu {
|
||||
window: WguiWindow,
|
||||
pending_open: Option<OpenParams>,
|
||||
tasks: Tasks<Task>,
|
||||
}
|
||||
|
||||
fn doc_params<'a>(globals: WguiGlobals) -> parser::ParseDocumentParams<'a> {
|
||||
fn doc_params<'a>(globals: &WguiGlobals) -> parser::ParseDocumentParams<'a> {
|
||||
parser::ParseDocumentParams {
|
||||
globals,
|
||||
globals: globals.clone(),
|
||||
path: AssetPath::WguiInternal("wgui/context_menu.xml"),
|
||||
extra: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct TickResult {
|
||||
pub action_name: Option<Rc<str>>,
|
||||
}
|
||||
|
||||
impl ContextMenu {
|
||||
pub fn open(&mut self, params: &mut OpenParams) -> anyhow::Result<()> {
|
||||
pub fn open(&mut self, params: OpenParams) {
|
||||
self.pending_open = Some(params);
|
||||
}
|
||||
|
||||
pub fn close(&self) {
|
||||
self.window.close();
|
||||
}
|
||||
|
||||
fn open_process(&mut self, params: &OpenParams, layout: &mut Layout) -> anyhow::Result<()> {
|
||||
let globals = layout.state.globals.clone();
|
||||
|
||||
self.window.open(&mut WguiWindowParams {
|
||||
globals: params.globals,
|
||||
layout: params.layout,
|
||||
globals: &globals,
|
||||
layout,
|
||||
position: params.position,
|
||||
extra: WguiWindowParamsExtra {
|
||||
with_decorations: false,
|
||||
@@ -59,46 +83,25 @@ impl ContextMenu {
|
||||
|
||||
let content = self.window.get_content();
|
||||
|
||||
let mut state = parser::parse_from_assets(&doc_params(params.globals.clone()), params.layout, content.id)?;
|
||||
let mut state = parser::parse_from_assets(&doc_params(&globals), layout, content.id)?;
|
||||
|
||||
let id_buttons = state.get_widget_id("buttons")?;
|
||||
|
||||
for (idx, cell) in params.cells.iter().enumerate() {
|
||||
for (idx, cell) in params.data.cells.iter().enumerate() {
|
||||
let mut par = HashMap::new();
|
||||
par.insert(Rc::from("text"), cell.title.generate(&mut params.globals.i18n()));
|
||||
let data_cell = state.parse_template(
|
||||
&doc_params(params.globals.clone()),
|
||||
"Cell",
|
||||
params.layout,
|
||||
id_buttons,
|
||||
par,
|
||||
)?;
|
||||
par.insert(Rc::from("text"), cell.title.generate(&mut globals.i18n()));
|
||||
let data_cell = state.parse_template(&doc_params(&globals), "Cell", layout, id_buttons, par)?;
|
||||
|
||||
let button = data_cell.fetch_component_as::<ComponentButton>("button")?;
|
||||
button.on_click({
|
||||
let on_action = params.on_action.clone();
|
||||
let name = cell.action_name.clone();
|
||||
let window = self.window.clone();
|
||||
Box::new(move |common, _| {
|
||||
(*on_action)(ContextMenuAction {
|
||||
name: name.clone(),
|
||||
// FIXME: why i can't just provide this as-is!?
|
||||
/* common: common, */
|
||||
common: &mut CallbackDataCommon {
|
||||
alterables: common.alterables,
|
||||
state: common.state,
|
||||
},
|
||||
});
|
||||
window.close();
|
||||
Ok(())
|
||||
})
|
||||
});
|
||||
self
|
||||
.tasks
|
||||
.handle_button(&button, Task::ActionClicked(cell.action_name.clone()));
|
||||
|
||||
if idx < params.cells.len() - 1 {
|
||||
if idx < params.data.cells.len() - 1 {
|
||||
state.parse_template(
|
||||
&doc_params(params.globals.clone()),
|
||||
&doc_params(&globals),
|
||||
"Separator",
|
||||
params.layout,
|
||||
layout,
|
||||
id_buttons,
|
||||
Default::default(),
|
||||
)?;
|
||||
@@ -108,7 +111,22 @@ impl ContextMenu {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn close(&self) {
|
||||
self.window.close();
|
||||
pub fn tick(&mut self, layout: &mut Layout) -> anyhow::Result<TickResult> {
|
||||
if let Some(p) = self.pending_open.take() {
|
||||
self.open_process(&p, layout)?;
|
||||
}
|
||||
|
||||
let mut result = TickResult::default();
|
||||
|
||||
for task in self.tasks.drain() {
|
||||
match task {
|
||||
Task::ActionClicked(action_name) => {
|
||||
result.action_name = Some(action_name);
|
||||
self.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(result)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user