wip: edit mode overlay
This commit is contained in:
44
wlx-overlay-s/src/assets/gui/adjust.xml
Normal file
44
wlx-overlay-s/src/assets/gui/adjust.xml
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
<layout>
|
||||||
|
<theme>
|
||||||
|
<var key="border" value="2" />
|
||||||
|
<var key="tint_color" value="#0044CC99" />
|
||||||
|
</theme>
|
||||||
|
|
||||||
|
<template name="TopButton">
|
||||||
|
<rectangle id="~id" color="~bg_color" padding="8" round="50%">
|
||||||
|
<sprite color="~device_color" width="48" height="48" src="${src}" />
|
||||||
|
</rectangle>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<macro name="button_style"
|
||||||
|
margin="2" overflow="hidden" box_sizing="border_box" align_items="center" justify_content="center"
|
||||||
|
border_color="#0044CC" border="2" round="8" color="#000A1C" color2="#000002" gradient="vertical" />
|
||||||
|
|
||||||
|
<elements>
|
||||||
|
<div width="600" height="600">
|
||||||
|
<rectangle width="100%" height="100%" padding="4" gap="4" align_items="center" justify_content="center" color="#000000DD" flex_direction="row">
|
||||||
|
<div></div>
|
||||||
|
<div flex_direction="column">
|
||||||
|
<div></div>
|
||||||
|
<rectangle padding="10" gap="8" round="100%" color="~bg_color" justify_content="center" >
|
||||||
|
<TopButton id="lock" src="bar/lock_open.svg" />
|
||||||
|
<TopButton id="anchor" src="bar/anchor.svg" />
|
||||||
|
<TopButton id="mouse" src="bar/mouse.svg" />
|
||||||
|
<TopButton id="fade" src="bar/fade.svg" />
|
||||||
|
<TopButton id="move" src="bar/move-all.svg" />
|
||||||
|
<TopButton id="resize" src="bar/resize.svg" />
|
||||||
|
<TopButton id="inout" src="bar/inout.svg" />
|
||||||
|
<TopButton id="delete" src="bar/delete.svg" />
|
||||||
|
</rectangle>
|
||||||
|
<rectangle padding="8" gap="8" round="100%" color="~bg_color_active" justify_content="center" align_items="center">
|
||||||
|
<label text="range 10-20 value 15" />
|
||||||
|
<Slider width="200" height="16" min_value="10" max_value="20" value="15" />
|
||||||
|
<CheckBox id="test0" text="AM/PM clock" />
|
||||||
|
</rectangle>
|
||||||
|
<div></div>
|
||||||
|
</div>
|
||||||
|
<div></div>
|
||||||
|
</rectangle>
|
||||||
|
</div>
|
||||||
|
</elements>
|
||||||
|
</layout>
|
||||||
@@ -19,7 +19,7 @@ use super::task::{TaskContainer, TaskType};
|
|||||||
#[derive(Clone, Default)]
|
#[derive(Clone, Default)]
|
||||||
pub struct HoverResult {
|
pub struct HoverResult {
|
||||||
pub haptics: Option<Haptics>,
|
pub haptics: Option<Haptics>,
|
||||||
/// If true, the laster shows at this position and no further raycasting will be done.
|
/// If true, the laser shows at this position and no further raycasting will be done.
|
||||||
pub consume: bool,
|
pub consume: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -344,15 +344,18 @@ where
|
|||||||
// focus change
|
// focus change
|
||||||
if let Some(hovered_id) = hovered_id
|
if let Some(hovered_id) = hovered_id
|
||||||
&& hovered_id != hit.overlay
|
&& hovered_id != hit.overlay
|
||||||
&& let Some(old_hovered) = overlays.mut_by_id(hovered_id)
|
|
||||||
{
|
{
|
||||||
|
if let Some(old_hovered) = overlays.mut_by_id(hovered_id) {
|
||||||
if old_hovered.primary_pointer.is_some_and(|i| i == idx) {
|
if old_hovered.primary_pointer.is_some_and(|i| i == idx) {
|
||||||
old_hovered.primary_pointer = None;
|
old_hovered.primary_pointer = None;
|
||||||
}
|
}
|
||||||
log::debug!("{} on_left (focus changed)", old_hovered.config.name);
|
log::debug!("{} on_left (focus changed)", old_hovered.config.name);
|
||||||
old_hovered.config.backend.on_left(app, idx);
|
old_hovered.config.backend.on_left(app, idx);
|
||||||
}
|
}
|
||||||
|
overlays.edit_overlay(hovered_id, false, app);
|
||||||
|
}
|
||||||
|
|
||||||
|
overlays.edit_overlay(hit.overlay, true, app);
|
||||||
let Some(hovered) = overlays.mut_by_id(hit.overlay) else {
|
let Some(hovered) = overlays.mut_by_id(hit.overlay) else {
|
||||||
log::warn!("Hit overlay {:?} does not exist", hit.overlay);
|
log::warn!("Hit overlay {:?} does not exist", hit.overlay);
|
||||||
return (0.0, None); // no hit
|
return (0.0, None); // no hit
|
||||||
@@ -424,12 +427,13 @@ fn handle_no_hit<O>(
|
|||||||
overlays: &mut OverlayWindowManager<O>,
|
overlays: &mut OverlayWindowManager<O>,
|
||||||
app: &mut AppState,
|
app: &mut AppState,
|
||||||
) {
|
) {
|
||||||
if let Some(hovered_id) = hovered_id
|
if let Some(hovered_id) = hovered_id {
|
||||||
&& let Some(hovered) = overlays.mut_by_id(hovered_id)
|
if let Some(hovered) = overlays.mut_by_id(hovered_id) {
|
||||||
{
|
|
||||||
log::debug!("{} on_left (no hit)", hovered.config.name);
|
log::debug!("{} on_left (no hit)", hovered.config.name);
|
||||||
hovered.config.backend.on_left(app, pointer_idx);
|
hovered.config.backend.on_left(app, pointer_idx);
|
||||||
}
|
}
|
||||||
|
overlays.edit_overlay(hovered_id, false, app);
|
||||||
|
}
|
||||||
|
|
||||||
// in case click released while not aiming at anything
|
// in case click released while not aiming at anything
|
||||||
// send release event to overlay that was originally clicked
|
// send release event to overlay that was originally clicked
|
||||||
@@ -568,7 +572,7 @@ where
|
|||||||
};
|
};
|
||||||
|
|
||||||
let result = overlay.config.backend.on_hover(app, &hit);
|
let result = overlay.config.backend.on_hover(app, &hit);
|
||||||
if result.consume {
|
if result.consume || overlay.config.editing {
|
||||||
return (Some(hit), result.haptics);
|
return (Some(hit), result.haptics);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ use wgui::{
|
|||||||
InternalStateChangeEvent, MouseButtonIndex, MouseDownEvent, MouseLeaveEvent,
|
InternalStateChangeEvent, MouseButtonIndex, MouseDownEvent, MouseLeaveEvent,
|
||||||
MouseMotionEvent, MouseUpEvent, MouseWheelEvent,
|
MouseMotionEvent, MouseUpEvent, MouseWheelEvent,
|
||||||
},
|
},
|
||||||
|
gfx::cmd::WGfxClearMode,
|
||||||
layout::{Layout, LayoutParams, WidgetID},
|
layout::{Layout, LayoutParams, WidgetID},
|
||||||
parser::ParserState,
|
parser::ParserState,
|
||||||
renderer_vk::context::Context as WguiContext,
|
renderer_vk::context::Context as WguiContext,
|
||||||
@@ -32,8 +33,7 @@ mod button;
|
|||||||
mod helper;
|
mod helper;
|
||||||
mod label;
|
mod label;
|
||||||
|
|
||||||
const MAX_SIZE: u32 = 2048;
|
const DEFAULT_MAX_SIZE: f32 = 2048.0;
|
||||||
const MAX_SIZE_VEC2: Vec2 = vec2(MAX_SIZE as _, MAX_SIZE as _);
|
|
||||||
|
|
||||||
const COLOR_ERR: drawing::Color = drawing::Color::new(1., 0., 1., 1.);
|
const COLOR_ERR: drawing::Color = drawing::Color::new(1., 0., 1., 1.);
|
||||||
|
|
||||||
@@ -42,6 +42,7 @@ pub struct GuiPanel<S> {
|
|||||||
pub state: S,
|
pub state: S,
|
||||||
pub timers: Vec<GuiTimer>,
|
pub timers: Vec<GuiTimer>,
|
||||||
pub parser_state: ParserState,
|
pub parser_state: ParserState,
|
||||||
|
pub max_size: Vec2,
|
||||||
interaction_transform: Option<Affine2>,
|
interaction_transform: Option<Affine2>,
|
||||||
context: WguiContext,
|
context: WguiContext,
|
||||||
timestep: Timestep,
|
timestep: Timestep,
|
||||||
@@ -63,6 +64,7 @@ impl<S: 'static> GuiPanel<S> {
|
|||||||
path: &str,
|
path: &str,
|
||||||
state: S,
|
state: S,
|
||||||
on_custom_id: Option<OnCustomIdFunc>,
|
on_custom_id: Option<OnCustomIdFunc>,
|
||||||
|
resize_to_parent: bool,
|
||||||
) -> anyhow::Result<Self> {
|
) -> anyhow::Result<Self> {
|
||||||
let custom_elems = Rc::new(RefCell::new(vec![]));
|
let custom_elems = Rc::new(RefCell::new(vec![]));
|
||||||
|
|
||||||
@@ -81,7 +83,7 @@ impl<S: 'static> GuiPanel<S> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let (mut layout, mut parser_state) =
|
let (mut layout, mut parser_state) =
|
||||||
wgui::parser::new_layout_from_assets(&doc_params, &LayoutParams::default())?;
|
wgui::parser::new_layout_from_assets(&doc_params, &LayoutParams { resize_to_parent })?;
|
||||||
|
|
||||||
if let Some(on_element_id) = on_custom_id {
|
if let Some(on_element_id) = on_custom_id {
|
||||||
let ids = parser_state.data.ids.clone(); // FIXME: copying all ids?
|
let ids = parser_state.data.ids.clone(); // FIXME: copying all ids?
|
||||||
@@ -125,13 +127,14 @@ impl<S: 'static> GuiPanel<S> {
|
|||||||
timestep,
|
timestep,
|
||||||
state,
|
state,
|
||||||
parser_state,
|
parser_state,
|
||||||
|
max_size: vec2(DEFAULT_MAX_SIZE as _, DEFAULT_MAX_SIZE as _),
|
||||||
timers: vec![],
|
timers: vec![],
|
||||||
interaction_transform: None,
|
interaction_transform: None,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_blank(app: &mut AppState, state: S) -> anyhow::Result<Self> {
|
pub fn new_blank(app: &mut AppState, state: S, resize_to_parent: bool) -> anyhow::Result<Self> {
|
||||||
let layout = Layout::new(app.wgui_globals.clone(), &LayoutParams::default())?;
|
let layout = Layout::new(app.wgui_globals.clone(), &LayoutParams { resize_to_parent })?;
|
||||||
let context = WguiContext::new(&mut app.wgui_shared, 1.0)?;
|
let context = WguiContext::new(&mut app.wgui_shared, 1.0)?;
|
||||||
let mut timestep = Timestep::new();
|
let mut timestep = Timestep::new();
|
||||||
timestep.set_tps(60.0);
|
timestep.set_tps(60.0);
|
||||||
@@ -142,13 +145,14 @@ impl<S: 'static> GuiPanel<S> {
|
|||||||
timestep,
|
timestep,
|
||||||
state,
|
state,
|
||||||
parser_state: ParserState::default(),
|
parser_state: ParserState::default(),
|
||||||
|
max_size: vec2(DEFAULT_MAX_SIZE as _, DEFAULT_MAX_SIZE as _),
|
||||||
timers: vec![],
|
timers: vec![],
|
||||||
interaction_transform: None,
|
interaction_transform: None,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn update_layout(&mut self) -> anyhow::Result<()> {
|
pub fn update_layout(&mut self) -> anyhow::Result<()> {
|
||||||
self.layout.update(MAX_SIZE_VEC2, 0.0)
|
self.layout.update(self.max_size, 0.0)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn push_event(&mut self, app: &mut AppState, event: &WguiEvent) -> EventResult {
|
pub fn push_event(&mut self, app: &mut AppState, event: &WguiEvent) -> EventResult {
|
||||||
@@ -223,21 +227,25 @@ impl<S: 'static> OverlayBackend for GuiPanel<S> {
|
|||||||
app: &mut AppState,
|
app: &mut AppState,
|
||||||
tgt: Arc<ImageView>,
|
tgt: Arc<ImageView>,
|
||||||
buf: &mut CommandBuffers,
|
buf: &mut CommandBuffers,
|
||||||
alpha: f32,
|
mut alpha: f32,
|
||||||
) -> anyhow::Result<bool> {
|
) -> anyhow::Result<bool> {
|
||||||
self.context
|
self.context
|
||||||
.update_viewport(&mut app.wgui_shared, tgt.extent_u32arr(), 1.0)?;
|
.update_viewport(&mut app.wgui_shared, tgt.extent_u32arr(), 1.0)?;
|
||||||
self.layout.update(MAX_SIZE_VEC2, self.timestep.alpha)?;
|
self.layout.update(self.max_size, self.timestep.alpha)?;
|
||||||
|
|
||||||
|
// FIXME: pass this properly
|
||||||
|
let mut clear = WGfxClearMode::Clear([0., 0., 0., 0.]);
|
||||||
|
if alpha < 0. {
|
||||||
|
alpha *= -1.;
|
||||||
|
clear = WGfxClearMode::Keep;
|
||||||
|
}
|
||||||
|
|
||||||
let mut cmd_buf = app
|
let mut cmd_buf = app
|
||||||
.gfx
|
.gfx
|
||||||
.create_gfx_command_buffer(CommandBufferUsage::OneTimeSubmit)
|
.create_gfx_command_buffer(CommandBufferUsage::OneTimeSubmit)
|
||||||
.unwrap(); // want panic
|
.unwrap(); // want panic
|
||||||
|
|
||||||
cmd_buf.begin_rendering(
|
cmd_buf.begin_rendering(tgt, clear)?;
|
||||||
tgt,
|
|
||||||
wgui::gfx::cmd::WGfxClearMode::Clear([0.0, 0.0, 0.0, 0.0]),
|
|
||||||
)?;
|
|
||||||
|
|
||||||
let globals = self.layout.state.globals.clone(); // sorry
|
let globals = self.layout.state.globals.clone(); // sorry
|
||||||
let mut globals = globals.get();
|
let mut globals = globals.get();
|
||||||
@@ -263,8 +271,8 @@ impl<S: 'static> OverlayBackend for GuiPanel<S> {
|
|||||||
fn frame_meta(&mut self) -> Option<FrameMeta> {
|
fn frame_meta(&mut self) -> Option<FrameMeta> {
|
||||||
Some(FrameMeta {
|
Some(FrameMeta {
|
||||||
extent: [
|
extent: [
|
||||||
MAX_SIZE.min(self.layout.content_size.x as _),
|
self.max_size.x.min(self.layout.content_size.x) as _,
|
||||||
MAX_SIZE.min(self.layout.content_size.y as _),
|
self.max_size.y.min(self.layout.content_size.y) as _,
|
||||||
1,
|
1,
|
||||||
],
|
],
|
||||||
..Default::default()
|
..Default::default()
|
||||||
@@ -301,7 +309,7 @@ impl<S: 'static> OverlayBackend for GuiPanel<S> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn on_left(&mut self, app: &mut AppState, pointer: usize) {
|
fn on_left(&mut self, app: &mut AppState, pointer: usize) {
|
||||||
log::info!("panel: on left");
|
log::debug!("panel: on left");
|
||||||
let e = WguiEvent::MouseLeave(MouseLeaveEvent { device: pointer });
|
let e = WguiEvent::MouseLeave(MouseLeaveEvent { device: pointer });
|
||||||
self.push_event(app, &e);
|
self.push_event(app, &e);
|
||||||
}
|
}
|
||||||
|
|||||||
195
wlx-overlay-s/src/overlays/adjust.rs
Normal file
195
wlx-overlay-s/src/overlays/adjust.rs
Normal file
@@ -0,0 +1,195 @@
|
|||||||
|
use std::{
|
||||||
|
any::Any,
|
||||||
|
mem::{self, ManuallyDrop},
|
||||||
|
sync::Arc,
|
||||||
|
};
|
||||||
|
|
||||||
|
use glam::vec2;
|
||||||
|
use vulkano::image::{view::ImageView, ImageUsage};
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
backend::input::HoverResult,
|
||||||
|
gui::panel::GuiPanel,
|
||||||
|
state::AppState,
|
||||||
|
windowing::{
|
||||||
|
backend::{DummyBackend, OverlayBackend, ShouldRender},
|
||||||
|
window::OverlayWindowConfig,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
type EditModeWrapPanel = GuiPanel<Arc<str>>;
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct EditModeManager {
|
||||||
|
panel_pool: Vec<EditModeWrapPanel>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl EditModeManager {
|
||||||
|
pub fn wrap_edit_mode(
|
||||||
|
&mut self,
|
||||||
|
owc: &mut OverlayWindowConfig,
|
||||||
|
app: &mut AppState,
|
||||||
|
) -> anyhow::Result<()> {
|
||||||
|
if owc.editing {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
log::debug!("EditMode wrap on {}", owc.name);
|
||||||
|
let inner = mem::replace(&mut owc.backend, Box::new(DummyBackend {}));
|
||||||
|
let mut panel = self.panel_pool.pop();
|
||||||
|
if panel.is_none() {
|
||||||
|
panel = Some(make_adjustment_panel(app)?);
|
||||||
|
}
|
||||||
|
let mut panel = panel.unwrap();
|
||||||
|
panel.state = owc.name.clone();
|
||||||
|
owc.backend = Box::new(EditModeBackendWrapper {
|
||||||
|
inner: ManuallyDrop::new(inner),
|
||||||
|
panel: ManuallyDrop::new(panel),
|
||||||
|
can_render_inner: false,
|
||||||
|
image: None,
|
||||||
|
});
|
||||||
|
owc.editing = true;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn unwrap_edit_mode(&mut self, owc: &mut OverlayWindowConfig) {
|
||||||
|
if !owc.editing {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
log::debug!("EditMode unwrap on {}", owc.name);
|
||||||
|
let wrapper = mem::replace(&mut owc.backend, Box::new(DummyBackend {}));
|
||||||
|
let mut wrapper: Box<dyn Any> = wrapper;
|
||||||
|
let wrapper = wrapper
|
||||||
|
.downcast_mut::<EditModeBackendWrapper>()
|
||||||
|
.expect("Wrong type to unwrap");
|
||||||
|
|
||||||
|
let panel = unsafe { ManuallyDrop::take(&mut wrapper.panel) };
|
||||||
|
self.panel_pool.push(panel);
|
||||||
|
|
||||||
|
let inner = unsafe { ManuallyDrop::take(&mut wrapper.inner) };
|
||||||
|
owc.backend = inner;
|
||||||
|
owc.editing = false;
|
||||||
|
|
||||||
|
// wrapper is destroyed with nothing left inside
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct EditModeBackendWrapper {
|
||||||
|
panel: ManuallyDrop<EditModeWrapPanel>,
|
||||||
|
inner: ManuallyDrop<Box<dyn OverlayBackend>>,
|
||||||
|
image: Option<Arc<ImageView>>,
|
||||||
|
can_render_inner: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl OverlayBackend for EditModeBackendWrapper {
|
||||||
|
fn init(&mut self, app: &mut crate::state::AppState) -> anyhow::Result<()> {
|
||||||
|
self.inner.init(app)?;
|
||||||
|
self.panel.init(app)
|
||||||
|
}
|
||||||
|
fn pause(&mut self, app: &mut crate::state::AppState) -> anyhow::Result<()> {
|
||||||
|
self.inner.pause(app)?;
|
||||||
|
self.panel.pause(app)
|
||||||
|
}
|
||||||
|
fn resume(&mut self, app: &mut crate::state::AppState) -> anyhow::Result<()> {
|
||||||
|
self.inner.resume(app)?;
|
||||||
|
self.panel.resume(app)
|
||||||
|
}
|
||||||
|
fn should_render(&mut self, app: &mut crate::state::AppState) -> anyhow::Result<ShouldRender> {
|
||||||
|
let i = self.inner.should_render(app)?;
|
||||||
|
|
||||||
|
self.can_render_inner = !matches!(i, ShouldRender::Unable);
|
||||||
|
if self.can_render_inner
|
||||||
|
&& let Some(ref frame_meta) = self.inner.frame_meta()
|
||||||
|
{
|
||||||
|
let new_size = vec2(frame_meta.extent[0] as _, frame_meta.extent[1] as _);
|
||||||
|
if self.panel.max_size != new_size {
|
||||||
|
log::debug!("EditWrapperGui size {} → {new_size}", self.panel.max_size);
|
||||||
|
self.panel.max_size = new_size;
|
||||||
|
self.panel.update_layout()?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let p = self.panel.should_render(app)?;
|
||||||
|
|
||||||
|
Ok(match (i, p) {
|
||||||
|
(ShouldRender::Should, ShouldRender::Should) => ShouldRender::Should,
|
||||||
|
(ShouldRender::Should, ShouldRender::Can) => ShouldRender::Should,
|
||||||
|
(ShouldRender::Can, ShouldRender::Should) => ShouldRender::Should,
|
||||||
|
(ShouldRender::Can, ShouldRender::Can) => ShouldRender::Can,
|
||||||
|
// (ShouldRender::Unable, ShouldRender::Should) if self.image.is_some() => {
|
||||||
|
// ShouldRender::Should
|
||||||
|
// }
|
||||||
|
// (ShouldRender::Unable, ShouldRender::Can) if self.image.is_some() => ShouldRender::Can,
|
||||||
|
_ => ShouldRender::Unable,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
fn render(
|
||||||
|
&mut self,
|
||||||
|
app: &mut crate::state::AppState,
|
||||||
|
tgt: std::sync::Arc<vulkano::image::view::ImageView>,
|
||||||
|
buf: &mut crate::graphics::CommandBuffers,
|
||||||
|
alpha: f32,
|
||||||
|
) -> anyhow::Result<bool> {
|
||||||
|
if self.can_render_inner {
|
||||||
|
if self.image.is_none()
|
||||||
|
&& let Some(ref meta) = self.inner.frame_meta()
|
||||||
|
{
|
||||||
|
let image = app.gfx.new_image(
|
||||||
|
meta.extent[0],
|
||||||
|
meta.extent[1],
|
||||||
|
app.gfx.surface_format,
|
||||||
|
ImageUsage::COLOR_ATTACHMENT | ImageUsage::SAMPLED,
|
||||||
|
)?;
|
||||||
|
self.image = Some(ImageView::new_default(image)?);
|
||||||
|
}
|
||||||
|
self.inner.render(app, tgt.clone(), buf, alpha)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.panel.render(app, tgt, buf, -1.)
|
||||||
|
}
|
||||||
|
fn frame_meta(&mut self) -> Option<crate::windowing::backend::FrameMeta> {
|
||||||
|
self.inner.frame_meta().or_else(|| self.panel.frame_meta())
|
||||||
|
}
|
||||||
|
fn on_hover(
|
||||||
|
&mut self,
|
||||||
|
app: &mut crate::state::AppState,
|
||||||
|
hit: &crate::backend::input::PointerHit,
|
||||||
|
) -> HoverResult {
|
||||||
|
// pass through hover events to force pipewire to capture frames for us
|
||||||
|
let _ = self.inner.on_hover(app, hit);
|
||||||
|
self.panel.on_hover(app, hit)
|
||||||
|
}
|
||||||
|
fn on_left(&mut self, app: &mut crate::state::AppState, pointer: usize) {
|
||||||
|
self.inner.on_left(app, pointer);
|
||||||
|
self.panel.on_left(app, pointer);
|
||||||
|
}
|
||||||
|
fn on_pointer(
|
||||||
|
&mut self,
|
||||||
|
app: &mut crate::state::AppState,
|
||||||
|
hit: &crate::backend::input::PointerHit,
|
||||||
|
pressed: bool,
|
||||||
|
) {
|
||||||
|
self.panel.on_pointer(app, hit, pressed);
|
||||||
|
}
|
||||||
|
fn on_scroll(
|
||||||
|
&mut self,
|
||||||
|
app: &mut crate::state::AppState,
|
||||||
|
hit: &crate::backend::input::PointerHit,
|
||||||
|
delta_y: f32,
|
||||||
|
delta_x: f32,
|
||||||
|
) {
|
||||||
|
self.panel.on_scroll(app, hit, delta_y, delta_x);
|
||||||
|
}
|
||||||
|
fn get_interaction_transform(&mut self) -> Option<glam::Affine2> {
|
||||||
|
self.inner.get_interaction_transform()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn make_adjustment_panel(app: &mut AppState) -> anyhow::Result<EditModeWrapPanel> {
|
||||||
|
let mut panel = GuiPanel::new_from_template(app, "gui/adjust.xml", "".into(), None, true)?;
|
||||||
|
panel.update_layout()?;
|
||||||
|
|
||||||
|
Ok(panel)
|
||||||
|
}
|
||||||
@@ -9,7 +9,7 @@ use crate::windowing::Z_ORDER_ANCHOR;
|
|||||||
pub static ANCHOR_NAME: LazyLock<Arc<str>> = LazyLock::new(|| Arc::from("anchor"));
|
pub static ANCHOR_NAME: LazyLock<Arc<str>> = LazyLock::new(|| Arc::from("anchor"));
|
||||||
|
|
||||||
pub fn create_anchor(app: &mut AppState) -> anyhow::Result<OverlayWindowConfig> {
|
pub fn create_anchor(app: &mut AppState) -> anyhow::Result<OverlayWindowConfig> {
|
||||||
let mut panel = GuiPanel::new_from_template(app, "gui/anchor.xml", (), None)?;
|
let mut panel = GuiPanel::new_from_template(app, "gui/anchor.xml", (), None, false)?;
|
||||||
panel.update_layout()?;
|
panel.update_layout()?;
|
||||||
|
|
||||||
Ok(OverlayWindowConfig {
|
Ok(OverlayWindowConfig {
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ struct BarState {}
|
|||||||
#[allow(clippy::match_same_arms)] // TODO: remove later
|
#[allow(clippy::match_same_arms)] // TODO: remove later
|
||||||
pub fn create_bar(app: &mut AppState) -> anyhow::Result<OverlayWindowConfig> {
|
pub fn create_bar(app: &mut AppState) -> anyhow::Result<OverlayWindowConfig> {
|
||||||
let state = BarState {};
|
let state = BarState {};
|
||||||
let mut panel = GuiPanel::new_from_template(app, "gui/bar.xml", state, None)?;
|
let mut panel = GuiPanel::new_from_template(app, "gui/bar.xml", state, None, false)?;
|
||||||
|
|
||||||
for (id, _widget_id) in &panel.parser_state.data.ids {
|
for (id, _widget_id) in &panel.parser_state.data.ids {
|
||||||
match id.as_ref() {
|
match id.as_ref() {
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ pub fn create_custom(app: &mut AppState, name: Arc<str>) -> Option<OverlayWindow
|
|||||||
|
|
||||||
unreachable!();
|
unreachable!();
|
||||||
|
|
||||||
let panel = GuiPanel::new_blank(app, ()).ok()?;
|
let panel = GuiPanel::new_blank(app, (), false).ok()?;
|
||||||
panel.update_layout().ok()?;
|
panel.update_layout().ok()?;
|
||||||
|
|
||||||
Some(OverlayWindowConfig {
|
Some(OverlayWindowConfig {
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ use wgui::{
|
|||||||
layout::LayoutParams,
|
layout::LayoutParams,
|
||||||
parser::Fetchable,
|
parser::Fetchable,
|
||||||
renderer_vk::util,
|
renderer_vk::util,
|
||||||
taffy::{self, prelude::length},
|
taffy::{self, prelude::length, BoxSizing},
|
||||||
widget::{
|
widget::{
|
||||||
div::WidgetDiv,
|
div::WidgetDiv,
|
||||||
rectangle::{WidgetRectangle, WidgetRectangleParams},
|
rectangle::{WidgetRectangle, WidgetRectangleParams},
|
||||||
@@ -53,7 +53,7 @@ pub fn create_keyboard(
|
|||||||
processes: vec![],
|
processes: vec![],
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut panel = GuiPanel::new_blank(app, state)?;
|
let mut panel = GuiPanel::new_blank(app, state, false)?;
|
||||||
|
|
||||||
let (background, _) = panel.layout.add_child(
|
let (background, _) = panel.layout.add_child(
|
||||||
panel.layout.content_root_widget,
|
panel.layout.content_root_widget,
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
pub mod adjust;
|
||||||
pub mod anchor;
|
pub mod anchor;
|
||||||
pub mod bar;
|
pub mod bar;
|
||||||
pub mod custom;
|
pub mod custom;
|
||||||
|
|||||||
@@ -170,7 +170,7 @@ fn new_toast(toast: Toast, app: &mut AppState) -> Option<OverlayWindowConfig> {
|
|||||||
toast.title
|
toast.title
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut panel = GuiPanel::new_blank(app, ()).ok()?;
|
let mut panel = GuiPanel::new_blank(app, (), false).ok()?;
|
||||||
|
|
||||||
let globals = panel.layout.state.globals.clone();
|
let globals = panel.layout.state.globals.clone();
|
||||||
|
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ pub fn create_watch(app: &mut AppState, num_sets: usize) -> anyhow::Result<Overl
|
|||||||
Ok(())
|
Ok(())
|
||||||
},
|
},
|
||||||
)),
|
)),
|
||||||
|
false,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
panel
|
panel
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
use glam::{Affine2, Affine3A, Vec2};
|
use glam::{Affine2, Affine3A, Vec2};
|
||||||
use std::sync::Arc;
|
use std::{any::Any, sync::Arc};
|
||||||
use vulkano::{format::Format, image::view::ImageView};
|
use vulkano::{format::Format, image::view::ImageView};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
@@ -25,7 +25,7 @@ pub enum ShouldRender {
|
|||||||
Unable,
|
Unable,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait OverlayBackend {
|
pub trait OverlayBackend: Any {
|
||||||
/// Called once, before the first frame is rendered
|
/// Called once, before the first frame is rendered
|
||||||
fn init(&mut self, app: &mut AppState) -> anyhow::Result<()>;
|
fn init(&mut self, app: &mut AppState) -> anyhow::Result<()>;
|
||||||
fn pause(&mut self, app: &mut AppState) -> anyhow::Result<()>;
|
fn pause(&mut self, app: &mut AppState) -> anyhow::Result<()>;
|
||||||
@@ -46,7 +46,7 @@ pub trait OverlayBackend {
|
|||||||
/// Called to retrieve the effective extent of the image
|
/// Called to retrieve the effective extent of the image
|
||||||
/// Used for creating swapchains.
|
/// Used for creating swapchains.
|
||||||
///
|
///
|
||||||
/// Must be true if should_render was also true on the same frame.
|
/// Must be Some if should_render was Should or Can on the same frame.
|
||||||
fn frame_meta(&mut self) -> Option<FrameMeta>;
|
fn frame_meta(&mut self) -> Option<FrameMeta>;
|
||||||
|
|
||||||
fn on_hover(&mut self, app: &mut AppState, hit: &PointerHit) -> HoverResult;
|
fn on_hover(&mut self, app: &mut AppState, hit: &PointerHit) -> HoverResult;
|
||||||
@@ -69,3 +69,42 @@ pub fn ui_transform(extent: [u32; 2]) -> Affine2 {
|
|||||||
let center = Vec2 { x: 0.5, y: 0.5 };
|
let center = Vec2 { x: 0.5, y: 0.5 };
|
||||||
Affine2::from_scale_angle_translation(scale, 0.0, center)
|
Affine2::from_scale_angle_translation(scale, 0.0, center)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct DummyBackend {}
|
||||||
|
|
||||||
|
impl OverlayBackend for DummyBackend {
|
||||||
|
fn init(&mut self, _: &mut AppState) -> anyhow::Result<()> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
fn pause(&mut self, _: &mut AppState) -> anyhow::Result<()> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
fn resume(&mut self, _: &mut AppState) -> anyhow::Result<()> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
fn should_render(&mut self, _: &mut AppState) -> anyhow::Result<ShouldRender> {
|
||||||
|
Ok(ShouldRender::Unable)
|
||||||
|
}
|
||||||
|
fn render(
|
||||||
|
&mut self,
|
||||||
|
_: &mut AppState,
|
||||||
|
_: Arc<ImageView>,
|
||||||
|
_: &mut CommandBuffers,
|
||||||
|
_: f32,
|
||||||
|
) -> anyhow::Result<bool> {
|
||||||
|
Ok(false)
|
||||||
|
}
|
||||||
|
fn frame_meta(&mut self) -> Option<FrameMeta> {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
fn on_hover(&mut self, _: &mut AppState, _: &PointerHit) -> HoverResult {
|
||||||
|
HoverResult::default()
|
||||||
|
}
|
||||||
|
fn on_left(&mut self, _: &mut AppState, _: usize) {}
|
||||||
|
fn on_pointer(&mut self, _: &mut AppState, _: &PointerHit, _: bool) {}
|
||||||
|
fn on_scroll(&mut self, _: &mut AppState, _: &PointerHit, _: f32, _: f32) {}
|
||||||
|
fn get_interaction_transform(&mut self) -> Option<glam::Affine2> {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -5,8 +5,8 @@ use slotmap::{HopSlotMap, Key, SecondaryMap};
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
overlays::{
|
overlays::{
|
||||||
anchor::create_anchor, keyboard::builder::create_keyboard, screen::create_screens,
|
adjust::EditModeManager, anchor::create_anchor, keyboard::builder::create_keyboard,
|
||||||
watch::create_watch,
|
screen::create_screens, watch::create_watch,
|
||||||
},
|
},
|
||||||
state::AppState,
|
state::AppState,
|
||||||
windowing::{
|
windowing::{
|
||||||
@@ -18,6 +18,7 @@ use crate::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
pub struct OverlayWindowManager<T> {
|
pub struct OverlayWindowManager<T> {
|
||||||
|
wrappers: EditModeManager,
|
||||||
overlays: HopSlotMap<OverlayID, OverlayWindowData<T>>,
|
overlays: HopSlotMap<OverlayID, OverlayWindowData<T>>,
|
||||||
sets: Vec<OverlayWindowSet>,
|
sets: Vec<OverlayWindowSet>,
|
||||||
/// The set that is currently visible.
|
/// The set that is currently visible.
|
||||||
@@ -37,6 +38,7 @@ where
|
|||||||
let mut maybe_keymap = None;
|
let mut maybe_keymap = None;
|
||||||
|
|
||||||
let mut me = Self {
|
let mut me = Self {
|
||||||
|
wrappers: EditModeManager::default(),
|
||||||
overlays: HopSlotMap::with_key(),
|
overlays: HopSlotMap::with_key(),
|
||||||
current_set: Some(0),
|
current_set: Some(0),
|
||||||
restore_set: 0,
|
restore_set: 0,
|
||||||
@@ -168,6 +170,20 @@ impl<T> OverlayWindowManager<T> {
|
|||||||
self.restore_set = (app.session.config.last_set as usize).min(self.sets.len() - 1);
|
self.restore_set = (app.session.config.last_set as usize).min(self.sets.len() - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn edit_overlay(&mut self, id: OverlayID, enabled: bool, app: &mut AppState) {
|
||||||
|
let Some(overlay) = self.overlays.get_mut(id) else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
if enabled {
|
||||||
|
self.wrappers
|
||||||
|
.wrap_edit_mode(&mut overlay.config, app)
|
||||||
|
.unwrap(); // FIXME: unwrap
|
||||||
|
} else {
|
||||||
|
self.wrappers.unwrap_edit_mode(&mut overlay.config);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn mut_by_selector(
|
pub fn mut_by_selector(
|
||||||
&mut self,
|
&mut self,
|
||||||
selector: &OverlaySelector,
|
selector: &OverlaySelector,
|
||||||
|
|||||||
@@ -99,6 +99,8 @@ pub struct OverlayWindowConfig {
|
|||||||
pub global: bool,
|
pub global: bool,
|
||||||
/// True if transform, curvature, alpha has changed. Only used by OpenVR.
|
/// True if transform, curvature, alpha has changed. Only used by OpenVR.
|
||||||
pub dirty: bool,
|
pub dirty: bool,
|
||||||
|
/// True if the window is showing the edit overlay
|
||||||
|
pub editing: bool,
|
||||||
pub saved_transform: Option<Affine3A>,
|
pub saved_transform: Option<Affine3A>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -118,6 +120,7 @@ impl OverlayWindowConfig {
|
|||||||
show_on_spawn: false,
|
show_on_spawn: false,
|
||||||
global: false,
|
global: false,
|
||||||
dirty: true,
|
dirty: true,
|
||||||
|
editing: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user