From 595324814a28d044496fc7a0ff036bd61adc852c Mon Sep 17 00:00:00 2001 From: galister <22305755+galister@users.noreply.github.com> Date: Thu, 13 Nov 2025 15:40:08 +0900 Subject: [PATCH] opacity & additive & curvature works --- wgui/src/components/slider.rs | 5 +- wgui/src/drawing.rs | 6 +- wgui/src/globals.rs | 3 + wgui/src/renderer_vk/context.rs | 6 +- wlx-overlay-s/src/assets/gui/edit.xml | 28 +- wlx-overlay-s/src/assets/lang/en.json | 2 +- wlx-overlay-s/src/backend/openxr/overlay.rs | 15 +- wlx-overlay-s/src/backend/task.rs | 4 + wlx-overlay-s/src/gui/panel/button.rs | 13 +- wlx-overlay-s/src/gui/panel/mod.rs | 43 ++- wlx-overlay-s/src/overlays/edit.rs | 317 +++++++++++++++++++- wlx-overlay-s/src/windowing/manager.rs | 8 +- wlx-overlay-s/src/windowing/window.rs | 3 + 13 files changed, 397 insertions(+), 56 deletions(-) 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, } } }