diff --git a/wgui/src/components/slider.rs b/wgui/src/components/slider.rs
index 8afd9b70..2f6438b5 100644
--- a/wgui/src/components/slider.rs
+++ b/wgui/src/components/slider.rs
@@ -15,11 +15,11 @@ use crate::{
util,
},
widget::{
- ConstructEssentials, EventResult,
div::WidgetDiv,
label::{WidgetLabel, WidgetLabelParams},
rectangle::{WidgetRectangle, WidgetRectangleParams},
util::WLength,
+ ConstructEssentials, EventResult,
},
};
@@ -113,7 +113,8 @@ impl ComponentSlider {
pub fn get_value(&self) -> f32 {
self.state.borrow().values.value
}
- pub fn set_value(&mut self, common: &mut CallbackDataCommon, value: f32) {
+
+ pub fn set_value(&self, common: &mut CallbackDataCommon, value: f32) {
let mut state = self.state.borrow_mut();
state.set_value(common, &self.data, value);
}
diff --git a/wgui/src/drawing.rs b/wgui/src/drawing.rs
index 2a1ee566..077d7494 100644
--- a/wgui/src/drawing.rs
+++ b/wgui/src/drawing.rs
@@ -9,7 +9,7 @@ use crate::{
event::EventAlterables,
globals::Globals,
layout::Widget,
- renderer_vk::text::{TextShadow, custom_glyph::CustomGlyph},
+ renderer_vk::text::{custom_glyph::CustomGlyph, TextShadow},
stack::{self, ScissorBoundary, ScissorStack, TransformStack},
widget::{self, ScrollbarInfo, WidgetState},
};
@@ -264,7 +264,7 @@ fn draw_widget(
state.primitives.push(primitive_debug_rect(
&boundary,
&state.transform_stack.get().transform,
- Color::new(0.0, 1.0, 1.0, 0.5),
+ Color::new(0.0, 1.0, 1.0, 0.5 * params.alpha),
));
}
@@ -277,7 +277,7 @@ fn draw_widget(
state.primitives.push(primitive_debug_rect(
&boundary_relative,
&state.transform_stack.get().transform,
- Color::new(1.0, 0.0, 1.0, 1.0),
+ Color::new(1.0, 0.0, 1.0, params.alpha),
));
}
diff --git a/wgui/src/globals.rs b/wgui/src/globals.rs
index 2fab2248..20dd202c 100644
--- a/wgui/src/globals.rs
+++ b/wgui/src/globals.rs
@@ -11,11 +11,13 @@ use crate::{
i18n::I18n,
};
+#[derive(Clone)]
pub struct Defaults {
pub dark_mode: bool,
pub text_color: drawing::Color,
pub button_color: drawing::Color,
pub accent_color: drawing::Color,
+ pub danger_color: drawing::Color,
}
impl Default for Defaults {
@@ -25,6 +27,7 @@ impl Default for Defaults {
text_color: drawing::Color::new(1.0, 1.0, 1.0, 1.0),
button_color: drawing::Color::new(1.0, 1.0, 1.0, 0.05),
accent_color: drawing::Color::new(0.0, 0.54, 1.0, 1.0),
+ danger_color: drawing::Color::new(0.8, 0.0, 0.0, 1.0),
}
}
}
diff --git a/wgui/src/renderer_vk/context.rs b/wgui/src/renderer_vk/context.rs
index 3f3247ba..7c1e3f3d 100644
--- a/wgui/src/renderer_vk/context.rs
+++ b/wgui/src/renderer_vk/context.rs
@@ -2,21 +2,21 @@ use std::{cell::RefCell, rc::Rc, sync::Arc};
use cosmic_text::Buffer;
use glam::{Mat4, Vec2, Vec3};
-use slotmap::{SlotMap, new_key_type};
+use slotmap::{new_key_type, SlotMap};
use vulkano::pipeline::graphics::viewport;
use crate::{
drawing::{self},
font_config,
- gfx::{WGfx, cmd::GfxCommandBuffer},
+ gfx::{cmd::GfxCommandBuffer, WGfx},
};
use super::{
rect::{RectPipeline, RectRenderer},
text::{
- DEFAULT_METRICS, SWASH_CACHE, TextArea, TextBounds,
text_atlas::{TextAtlas, TextPipeline},
text_renderer::TextRenderer,
+ TextArea, TextBounds, DEFAULT_METRICS, SWASH_CACHE,
},
viewport::Viewport,
};
diff --git a/wlx-overlay-s/src/assets/gui/edit.xml b/wlx-overlay-s/src/assets/gui/edit.xml
index 1cf1fdc0..2eeacb61 100644
--- a/wlx-overlay-s/src/assets/gui/edit.xml
+++ b/wlx-overlay-s/src/assets/gui/edit.xml
@@ -7,48 +7,48 @@
-
+
-
\ No newline at end of file
+
diff --git a/wlx-overlay-s/src/assets/lang/en.json b/wlx-overlay-s/src/assets/lang/en.json
index 3dbf5b4c..5e8572ef 100644
--- a/wlx-overlay-s/src/assets/lang/en.json
+++ b/wlx-overlay-s/src/assets/lang/en.json
@@ -5,7 +5,7 @@
"BLENDING_ADDITIVE": "Additive",
"CURVATURE": "Curvature",
"DELETE": "Delete",
- "HINT_POINT_WINDOW": "Point on a window to change its parameters.\nOnce done, leave edit mode using the button on the right.",
+ "HINT_POINT_WINDOW": "Point at a window to change its parameters.\nOnce done, leave edit mode using the button on the right.",
"LEAVE": "Leave edit mode",
"LOCK_INTERACTION": "Lock interaction",
"MOVE_PRESS_AND_DRAG": "Move (press & drag)",
diff --git a/wlx-overlay-s/src/backend/openxr/overlay.rs b/wlx-overlay-s/src/backend/openxr/overlay.rs
index 0c93fc24..3c561919 100644
--- a/wlx-overlay-s/src/backend/openxr/overlay.rs
+++ b/wlx-overlay-s/src/backend/openxr/overlay.rs
@@ -4,9 +4,9 @@ use std::{f32::consts::PI, sync::Arc};
use vulkano::image::view::ImageView;
use xr::EyeVisibility;
-use super::{CompositionLayer, XrState, helpers, swapchain::WlxSwapchain};
+use super::{helpers, swapchain::WlxSwapchain, CompositionLayer, XrState};
use crate::{
- backend::openxr::swapchain::{SwapchainOpts, create_swapchain},
+ backend::openxr::swapchain::{create_swapchain, SwapchainOpts},
state::AppState,
windowing::window::OverlayWindowData,
};
@@ -74,6 +74,13 @@ impl OverlayWindowData {
(major / aspect_ratio, major)
};
+ let flags = if state.additive {
+ CompositionLayerFlags::BLEND_TEXTURE_SOURCE_ALPHA
+ } else {
+ CompositionLayerFlags::BLEND_TEXTURE_SOURCE_ALPHA
+ | CompositionLayerFlags::UNPREMULTIPLIED_ALPHA
+ };
+
if let Some(curvature) = state.curvature {
let radius = scale_x / (2.0 * PI * curvature);
let quat = helpers::transform_to_norm_quat(&transform);
@@ -83,7 +90,7 @@ impl OverlayWindowData {
let angle = 2.0 * (scale_x / (2.0 * radius));
let cylinder = xr::CompositionLayerCylinderKHR::new()
- .layer_flags(CompositionLayerFlags::BLEND_TEXTURE_SOURCE_ALPHA)
+ .layer_flags(flags)
.pose(posef)
.sub_image(sub_image)
.eye_visibility(EyeVisibility::BOTH)
@@ -95,7 +102,7 @@ impl OverlayWindowData {
} else {
let posef = helpers::transform_to_posef(&transform);
let quad = xr::CompositionLayerQuad::new()
- .layer_flags(CompositionLayerFlags::BLEND_TEXTURE_SOURCE_ALPHA)
+ .layer_flags(flags)
.pose(posef)
.sub_image(sub_image)
.eye_visibility(EyeVisibility::BOTH)
diff --git a/wlx-overlay-s/src/backend/task.rs b/wlx-overlay-s/src/backend/task.rs
index e7474e32..3bdfa7b4 100644
--- a/wlx-overlay-s/src/backend/task.rs
+++ b/wlx-overlay-s/src/backend/task.rs
@@ -83,6 +83,10 @@ impl TaskContainer {
}
}
+ pub fn transfer_from(&mut self, other: &mut TaskContainer) {
+ self.tasks.append(&mut other.tasks);
+ }
+
pub fn enqueue(&mut self, task: TaskType) {
self.tasks.push(AppTask {
not_before: Instant::now(),
diff --git a/wlx-overlay-s/src/gui/panel/button.rs b/wlx-overlay-s/src/gui/panel/button.rs
index 46d473ae..0ac45a15 100644
--- a/wlx-overlay-s/src/gui/panel/button.rs
+++ b/wlx-overlay-s/src/gui/panel/button.rs
@@ -18,23 +18,22 @@ use crate::backend::{task::TaskType, wayvr::WayVRAction};
use super::helper::read_label_from_pipe;
+pub const BUTTON_EVENTS: [(&str, EventListenerKind); 2] = [
+ ("_press", EventListenerKind::MousePress),
+ ("_release", EventListenerKind::MouseRelease),
+];
+
pub(super) fn setup_custom_button(
layout: &mut Layout,
attribs: &CustomAttribsInfoOwned,
_app: &AppState,
) {
- const EVENTS: [(&str, EventListenerKind); 2] = [
- ("_press", EventListenerKind::MousePress),
- ("_release", EventListenerKind::MouseRelease),
- ];
-
- for (name, kind) in &EVENTS {
+ for (name, kind) in &BUTTON_EVENTS {
let Some(action) = attribs.get_value(name) else {
continue;
};
let mut args = action.split_whitespace();
-
let Some(command) = args.next() else {
continue;
};
diff --git a/wlx-overlay-s/src/gui/panel/mod.rs b/wlx-overlay-s/src/gui/panel/mod.rs
index bdf0d434..526c8b94 100644
--- a/wlx-overlay-s/src/gui/panel/mod.rs
+++ b/wlx-overlay-s/src/gui/panel/mod.rs
@@ -1,33 +1,34 @@
use std::{cell::RefCell, rc::Rc};
use button::setup_custom_button;
-use glam::{Affine2, Vec2, vec2};
+use glam::{vec2, Affine2, Vec2};
use label::setup_custom_label;
use wgui::{
assets::AssetPath,
+ components::ComponentTrait,
drawing,
event::{
- Event as WguiEvent, EventCallback, EventListenerID, EventListenerKind,
- InternalStateChangeEvent, MouseButtonIndex, MouseDownEvent, MouseLeaveEvent,
- MouseMotionEvent, MouseUpEvent, MouseWheelEvent,
+ CallbackDataCommon, Event as WguiEvent, EventAlterables, EventCallback, EventListenerID,
+ EventListenerKind, InternalStateChangeEvent, MouseButtonIndex, MouseDownEvent,
+ MouseLeaveEvent, MouseMotionEvent, MouseUpEvent, MouseWheelEvent,
},
gfx::cmd::WGfxClearMode,
layout::{Layout, LayoutParams, WidgetID},
- parser::ParserState,
+ parser::{CustomAttribsInfoOwned, ParserState},
renderer_vk::context::Context as WguiContext,
- widget::{EventResult, label::WidgetLabel, rectangle::WidgetRectangle},
+ widget::{label::WidgetLabel, rectangle::WidgetRectangle, EventResult},
};
use crate::{
backend::input::{Haptics, HoverResult, PointerHit, PointerMode},
state::AppState,
subsystem::hid::WheelDelta,
- windowing::backend::{FrameMeta, OverlayBackend, RenderResources, ShouldRender, ui_transform},
+ windowing::backend::{ui_transform, FrameMeta, OverlayBackend, RenderResources, ShouldRender},
};
use super::{timer::GuiTimer, timestep::Timestep};
-mod button;
+pub mod button;
mod helper;
mod label;
@@ -57,8 +58,11 @@ pub type OnCustomIdFunc = Box<
) -> anyhow::Result<()>,
>;
+pub type OnCustomAttribFunc = Box;
+
pub struct NewGuiPanelParams {
pub on_custom_id: Option, // used only in `new_from_template`
+ pub on_custom_attrib: Option, // used only in `new_from_template`
pub resize_to_parent: bool,
pub gui_scale: f32,
}
@@ -67,6 +71,7 @@ impl Default for NewGuiPanelParams {
fn default() -> Self {
Self {
on_custom_id: None,
+ on_custom_attrib: None,
resize_to_parent: false,
gui_scale: 1.0,
}
@@ -133,6 +138,10 @@ impl GuiPanel {
{
setup_custom_button::(&mut layout, elem, app);
}
+
+ if let Some(on_custom_attrib) = ¶ms.on_custom_attrib {
+ on_custom_attrib(&mut layout, elem, app);
+ }
}
let context = WguiContext::new(&mut app.wgui_shared, 1.0)?;
@@ -202,6 +211,22 @@ impl GuiPanel {
) -> Option {
self.layout.add_event_listener(widget_id, kind, callback)
}
+
+ pub fn component_make_call(
+ &mut self,
+ component: Rc,
+ run: Box, &mut CallbackDataCommon)>,
+ ) -> anyhow::Result<()> {
+ let mut alterables = EventAlterables::default();
+ let mut common = CallbackDataCommon {
+ state: &self.layout.state,
+ alterables: &mut alterables,
+ };
+
+ run(component, &mut common);
+
+ self.layout.process_alterables(alterables)
+ }
}
impl OverlayBackend for GuiPanel {
@@ -264,7 +289,7 @@ impl OverlayBackend for GuiPanel {
globals: &mut globals,
layout: &mut self.layout,
debug_draw: false,
- alpha: rdr.alpha,
+ alpha: self.timestep.alpha,
})?;
self.context.draw(
&globals.font_system,
diff --git a/wlx-overlay-s/src/overlays/edit.rs b/wlx-overlay-s/src/overlays/edit.rs
index 03e5365e..499056db 100644
--- a/wlx-overlay-s/src/overlays/edit.rs
+++ b/wlx-overlay-s/src/overlays/edit.rs
@@ -1,23 +1,52 @@
use std::{
any::Any,
+ cell::RefCell,
mem::{self, ManuallyDrop},
- sync::Arc,
+ rc::Rc,
+ time::{Duration, Instant},
};
-use glam::{UVec2, vec2};
+use glam::{vec2, FloatExt, UVec2};
+use slotmap::Key;
+use wgui::{
+ animation::{Animation, AnimationEasing},
+ components::{checkbox::ComponentCheckbox, slider::ComponentSlider},
+ event::EventCallback,
+ layout::{Layout, WidgetID},
+ parser::{CustomAttribsInfoOwned, Fetchable},
+ widget::{rectangle::WidgetRectangle, EventResult},
+};
+#[cfg(feature = "wayvr")]
+use crate::{backend::task::TaskType, windowing::OverlaySelector};
use crate::{
- backend::input::HoverResult,
- gui::panel::{GuiPanel, NewGuiPanelParams},
+ backend::{input::HoverResult, task::TaskContainer},
+ gui::panel::{button::BUTTON_EVENTS, GuiPanel, NewGuiPanelParams},
state::AppState,
subsystem::hid::WheelDelta,
windowing::{
backend::{DummyBackend, OverlayBackend, RenderResources, ShouldRender},
- window::OverlayWindowConfig,
+ window::{OverlayWindowConfig, Positioning},
+ OverlayID,
},
};
-type EditModeWrapPanel = GuiPanel>;
+struct LongPressButtonState {
+ pressed: Instant,
+}
+
+struct EditModeState {
+ tasks: Rc>,
+ id: Rc>,
+ interact_lock: bool,
+ positioning: Positioning,
+ delete: LongPressButtonState,
+ rect_id: WidgetID,
+ rect_color: wgui::drawing::Color,
+ border_color: wgui::drawing::Color,
+}
+
+type EditModeWrapPanel = GuiPanel;
#[derive(Default)]
pub struct EditWrapperManager {
@@ -28,6 +57,7 @@ pub struct EditWrapperManager {
impl EditWrapperManager {
pub fn wrap_edit_mode(
&mut self,
+ id: OverlayID,
owc: &mut OverlayWindowConfig,
app: &mut AppState,
) -> anyhow::Result<()> {
@@ -50,7 +80,8 @@ impl EditWrapperManager {
)?);
}
let mut panel = panel.unwrap();
- panel.state = owc.name.clone();
+ panel_new_assignment(&mut panel, id, owc, app)?;
+
owc.backend = Box::new(EditModeBackendWrapper {
inner: ManuallyDrop::new(inner),
panel: ManuallyDrop::new(panel),
@@ -102,6 +133,11 @@ impl OverlayBackend for EditModeBackendWrapper {
self.panel.resume(app)
}
fn should_render(&mut self, app: &mut crate::state::AppState) -> anyhow::Result {
+ {
+ let mut local_tasks = self.panel.state.tasks.borrow_mut();
+ app.tasks.transfer_from(&mut local_tasks);
+ }
+
let i = self.inner.should_render(app)?;
if !matches!(i, ShouldRender::Unable)
@@ -188,15 +224,278 @@ fn make_edit_panel(
overlay_resolution.y
);
- let panel = GuiPanel::new_from_template(
+ let state = EditModeState {
+ id: Rc::new(RefCell::new(OverlayID::null())),
+ interact_lock: false,
+ positioning: Positioning::Static,
+ tasks: Rc::new(RefCell::new(TaskContainer::new())),
+ delete: LongPressButtonState {
+ pressed: Instant::now(),
+ },
+ rect_id: WidgetID::null(),
+ rect_color: wgui::drawing::Color::default(),
+ border_color: wgui::drawing::Color::default(),
+ };
+
+ let on_custom_attrib: Box =
+ Box::new(move |layout, attribs, _app| {
+ for (name, kind) in &BUTTON_EVENTS {
+ let Some(action) = attribs.get_value(name) else {
+ continue;
+ };
+
+ let mut args = action.split_whitespace();
+ let Some(command) = args.next() else {
+ continue;
+ };
+
+ let callback: EventCallback = match command {
+ "::EditModeToggleLock" => Box::new(move |common, _data, app, state| {
+ state.interact_lock = !state.interact_lock;
+
+ let defaults = app.wgui_globals.get().defaults.clone();
+ let rect_color = state.rect_color.clone();
+ let border_color = state.border_color.clone();
+
+ if state.interact_lock {
+ common.alterables.animate(Animation::new(
+ state.rect_id,
+ 10,
+ AnimationEasing::OutBack,
+ Box::new(move |common, data| {
+ let rect = data.obj.get_as_mut::().unwrap();
+ set_anim_color(
+ rect,
+ data.pos * 0.2,
+ rect_color,
+ border_color,
+ defaults.danger_color,
+ );
+ common.alterables.mark_redraw();
+ }),
+ ));
+ } else {
+ common.alterables.animate(Animation::new(
+ state.rect_id,
+ 10,
+ AnimationEasing::OutQuad,
+ Box::new(move |common, data| {
+ let rect = data.obj.get_as_mut::().unwrap();
+ set_anim_color(
+ rect,
+ 0.2 - (data.pos * 0.2),
+ rect_color,
+ border_color,
+ defaults.danger_color,
+ );
+ common.alterables.mark_redraw();
+ }),
+ ));
+ };
+
+ let interactable = !state.interact_lock;
+ app.tasks.enqueue(TaskType::Overlay(
+ OverlaySelector::Id(state.id.borrow().clone()),
+ Box::new(move |_app, owc| {
+ let state = owc.active_state.as_mut().unwrap(); //want panic
+ state.interactable = interactable;
+ }),
+ ));
+ Ok(EventResult::Consumed)
+ }),
+ "::EditModeDeletePress" => Box::new(move |_common, _data, _app, state| {
+ state.delete.pressed = Instant::now();
+ // TODO: animate to light up button after 2s
+ Ok(EventResult::Consumed)
+ }),
+ "::EditModeDeleteRelease" => Box::new(move |_common, _data, app, state| {
+ if state.delete.pressed.elapsed() > Duration::from_secs(2) {
+ return Ok(EventResult::Pass);
+ }
+ app.tasks.enqueue(TaskType::DropOverlay(OverlaySelector::Id(
+ state.id.borrow().clone(),
+ )));
+ Ok(EventResult::Consumed)
+ }),
+ _ => return,
+ };
+
+ let id = layout.add_event_listener(attribs.widget_id, *kind, callback);
+ log::debug!("Registered {action} on {:?} as {id:?}", attribs.widget_id);
+ }
+ });
+
+ let mut panel = GuiPanel::new_from_template(
app,
"gui/edit.xml",
- "".into(),
+ state,
NewGuiPanelParams {
+ on_custom_attrib: Some(on_custom_attrib),
resize_to_parent: true,
..Default::default()
},
)?;
+ set_up_shadow(&mut panel)?;
+ set_up_checkbox(&mut panel, "additive_box", cb_assign_additive)?;
+ set_up_slider(&mut panel, "alpha_slider", cb_assign_alpha)?;
+ set_up_slider(&mut panel, "curve_slider", cb_assign_curve)?;
+
Ok(panel)
}
+
+fn cb_assign_alpha(_app: &mut AppState, owc: &mut OverlayWindowConfig, alpha: f32) {
+ owc.dirty = true;
+ owc.active_state.as_mut().unwrap().alpha = alpha;
+}
+
+fn cb_assign_curve(_app: &mut AppState, owc: &mut OverlayWindowConfig, curvature: f32) {
+ owc.dirty = true;
+ owc.active_state.as_mut().unwrap().curvature = if curvature < 0.005 {
+ None
+ } else {
+ Some(curvature)
+ };
+}
+
+fn cb_assign_additive(_app: &mut AppState, owc: &mut OverlayWindowConfig, additive: bool) {
+ owc.dirty = true;
+ owc.active_state.as_mut().unwrap().additive = additive;
+}
+
+fn set_up_slider(
+ panel: &mut EditModeWrapPanel,
+ id: &str,
+ callback: fn(&mut AppState, &mut OverlayWindowConfig, f32),
+) -> anyhow::Result<()> {
+ let slider = panel
+ .parser_state
+ .fetch_component_as::(id)?;
+ let tasks = panel.state.tasks.clone();
+ let overlay_id = panel.state.id.clone();
+ slider.on_value_changed(Box::new(move |_common, e| {
+ let mut tasks = tasks.borrow_mut();
+ let e_value = e.value;
+
+ tasks.enqueue(TaskType::Overlay(
+ OverlaySelector::Id(overlay_id.borrow().clone()),
+ Box::new(move |app, owc| callback(app, owc, e_value)),
+ ));
+ Ok(())
+ }));
+
+ Ok(())
+}
+
+fn set_up_checkbox(
+ panel: &mut EditModeWrapPanel,
+ id: &str,
+ callback: fn(&mut AppState, &mut OverlayWindowConfig, bool),
+) -> anyhow::Result<()> {
+ let checkbox = panel
+ .parser_state
+ .fetch_component_as::(id)?;
+ let tasks = panel.state.tasks.clone();
+ let overlay_id = panel.state.id.clone();
+ checkbox.on_toggle(Box::new(move |_common, e| {
+ let mut tasks = tasks.borrow_mut();
+ let e_checked = e.checked;
+
+ tasks.enqueue(TaskType::Overlay(
+ OverlaySelector::Id(overlay_id.borrow().clone()),
+ Box::new(move |app, owc| callback(app, owc, e_checked)),
+ ));
+ Ok(())
+ }));
+
+ Ok(())
+}
+
+fn set_up_shadow(panel: &mut EditModeWrapPanel) -> anyhow::Result<()> {
+ panel.state.rect_id = panel.parser_state.get_widget_id("shadow")?;
+ let shadow_rect = panel
+ .layout
+ .state
+ .widgets
+ .get_as::(panel.state.rect_id)
+ .ok_or_else(|| anyhow::anyhow!("Element with id=\"shadow\" must be a "))?;
+ panel.state.rect_color = shadow_rect.params.color;
+ panel.state.border_color = shadow_rect.params.border_color;
+ Ok(())
+}
+
+fn panel_new_assignment(
+ panel: &mut EditModeWrapPanel,
+ id: OverlayID,
+ owc: &mut OverlayWindowConfig,
+ app: &mut AppState,
+) -> anyhow::Result<()> {
+ *panel.state.id.borrow_mut() = id;
+ let active_state = owc.active_state.as_mut().unwrap();
+ panel.state.interact_lock = !active_state.interactable;
+ panel.state.positioning = active_state.positioning;
+
+ let alpha = active_state.alpha;
+ let c = panel
+ .parser_state
+ .fetch_component_as::("alpha_slider")?;
+ panel.component_make_call(c, Box::new(move |c, cdc| c.set_value(cdc, alpha)))?;
+
+ let curve = active_state.curvature.unwrap_or(0.0);
+ let c = panel
+ .parser_state
+ .fetch_component_as::("curve_slider")?;
+ panel.component_make_call(c, Box::new(move |c, cdc| c.set_value(cdc, curve)))?;
+
+ let additive = active_state.additive;
+ let c = panel
+ .parser_state
+ .fetch_component_as::("additive_box")?;
+ panel.component_make_call(c, Box::new(move |c, cdc| c.set_checked(cdc, additive)))?;
+
+ let mut rect = panel
+ .layout
+ .state
+ .widgets
+ .get_as::(panel.state.rect_id)
+ .unwrap(); // can only fail if set_up_rect has issues
+
+ if active_state.interactable {
+ set_anim_color(
+ &mut rect,
+ 0.0,
+ panel.state.rect_color,
+ panel.state.border_color,
+ app.wgui_globals.get().defaults.danger_color,
+ );
+ } else {
+ set_anim_color(
+ &mut rect,
+ 0.2,
+ panel.state.rect_color,
+ panel.state.border_color,
+ app.wgui_globals.get().defaults.danger_color,
+ );
+ }
+
+ Ok(())
+}
+
+fn set_anim_color(
+ rect: &mut WidgetRectangle,
+ pos: f32,
+ rect_color: wgui::drawing::Color,
+ border_color: wgui::drawing::Color,
+ target_color: wgui::drawing::Color,
+) {
+ // rect to target_color
+ rect.params.color.r = rect_color.r.lerp(target_color.r, pos);
+ rect.params.color.g = rect_color.g.lerp(target_color.g, pos);
+ rect.params.color.b = rect_color.b.lerp(target_color.b, pos);
+
+ // border to white
+ rect.params.border_color.r = border_color.r.lerp(1.0, pos);
+ rect.params.border_color.g = border_color.g.lerp(1.0, pos);
+ rect.params.border_color.b = border_color.b.lerp(1.0, pos);
+ rect.params.border_color.a = border_color.a.lerp(1.0, pos);
+}
diff --git a/wlx-overlay-s/src/windowing/manager.rs b/wlx-overlay-s/src/windowing/manager.rs
index 79e429de..c344687e 100644
--- a/wlx-overlay-s/src/windowing/manager.rs
+++ b/wlx-overlay-s/src/windowing/manager.rs
@@ -9,14 +9,14 @@ use crate::{
edit::EditWrapperManager,
keyboard::builder::create_keyboard,
screen::create_screens,
- watch::{WATCH_NAME, create_watch},
+ watch::{create_watch, WATCH_NAME},
},
state::AppState,
windowing::{
- OverlayID, OverlaySelector,
set::{OverlayWindowSet, SerializedWindowSet},
snap_upright,
window::OverlayWindowData,
+ OverlayID, OverlaySelector,
},
};
@@ -197,13 +197,13 @@ impl OverlayWindowManager {
return;
};
- if &*overlay.config.name == WATCH_NAME {
+ if !overlay.config.default_state.grabbable {
return; // FIXME: not a proper solution
}
if enabled {
self.wrappers
- .wrap_edit_mode(&mut overlay.config, app)
+ .wrap_edit_mode(id, &mut overlay.config, app)
.unwrap(); // FIXME: unwrap
} else {
self.wrappers.unwrap_edit_mode(&mut overlay.config);
diff --git a/wlx-overlay-s/src/windowing/window.rs b/wlx-overlay-s/src/windowing/window.rs
index c8286ed4..ac4f8a7b 100644
--- a/wlx-overlay-s/src/windowing/window.rs
+++ b/wlx-overlay-s/src/windowing/window.rs
@@ -285,6 +285,7 @@ impl OverlayWindowConfig {
// Contains the window state for a given set
#[derive(Clone, Serialize, Deserialize)]
+#[serde(default)]
pub struct OverlayWindowState {
pub transform: Affine3A,
pub alpha: f32,
@@ -292,6 +293,7 @@ pub struct OverlayWindowState {
pub interactable: bool,
pub positioning: Positioning,
pub curvature: Option,
+ pub additive: bool,
}
impl Default for OverlayWindowState {
@@ -303,6 +305,7 @@ impl Default for OverlayWindowState {
positioning: Positioning::Floating,
curvature: None,
transform: Affine3A::IDENTITY,
+ additive: false,
}
}
}