diff --git a/wlx-overlay-s/src/assets/edit/flip180.svg b/wlx-overlay-s/src/assets/edit/flip180.svg new file mode 100644 index 0000000..7705399 --- /dev/null +++ b/wlx-overlay-s/src/assets/edit/flip180.svg @@ -0,0 +1,40 @@ + + + + + + + diff --git a/wlx-overlay-s/src/assets/edit/flip270.svg b/wlx-overlay-s/src/assets/edit/flip270.svg new file mode 100644 index 0000000..c91dfe6 --- /dev/null +++ b/wlx-overlay-s/src/assets/edit/flip270.svg @@ -0,0 +1,40 @@ + + + + + + + diff --git a/wlx-overlay-s/src/assets/edit/flip90.svg b/wlx-overlay-s/src/assets/edit/flip90.svg new file mode 100644 index 0000000..1b39320 --- /dev/null +++ b/wlx-overlay-s/src/assets/edit/flip90.svg @@ -0,0 +1,40 @@ + + + + + + + diff --git a/wlx-overlay-s/src/assets/edit/flipped.svg b/wlx-overlay-s/src/assets/edit/flipped.svg new file mode 100644 index 0000000..ecf153a --- /dev/null +++ b/wlx-overlay-s/src/assets/edit/flipped.svg @@ -0,0 +1,40 @@ + + + + + + + diff --git a/wlx-overlay-s/src/assets/edit/grabbable.svg b/wlx-overlay-s/src/assets/edit/grabbable.svg index ab36417..81ee4cd 100644 --- a/wlx-overlay-s/src/assets/edit/grabbable.svg +++ b/wlx-overlay-s/src/assets/edit/grabbable.svg @@ -1 +1 @@ - \ No newline at end of file + diff --git a/wlx-overlay-s/src/assets/edit/normal.svg b/wlx-overlay-s/src/assets/edit/normal.svg new file mode 100644 index 0000000..484ad8a --- /dev/null +++ b/wlx-overlay-s/src/assets/edit/normal.svg @@ -0,0 +1,40 @@ + + + + + + + diff --git a/wlx-overlay-s/src/assets/edit/rotate180.svg b/wlx-overlay-s/src/assets/edit/rotate180.svg new file mode 100644 index 0000000..b946ed8 --- /dev/null +++ b/wlx-overlay-s/src/assets/edit/rotate180.svg @@ -0,0 +1,40 @@ + + + + + + + diff --git a/wlx-overlay-s/src/assets/edit/rotate270.svg b/wlx-overlay-s/src/assets/edit/rotate270.svg new file mode 100644 index 0000000..73cb40b --- /dev/null +++ b/wlx-overlay-s/src/assets/edit/rotate270.svg @@ -0,0 +1,40 @@ + + + + + + + diff --git a/wlx-overlay-s/src/assets/edit/rotate90.svg b/wlx-overlay-s/src/assets/edit/rotate90.svg new file mode 100644 index 0000000..74a4f57 --- /dev/null +++ b/wlx-overlay-s/src/assets/edit/rotate90.svg @@ -0,0 +1,40 @@ + + + + + + + diff --git a/wlx-overlay-s/src/assets/gui/edit.xml b/wlx-overlay-s/src/assets/gui/edit.xml index 111579d..10bdbbf 100644 --- a/wlx-overlay-s/src/assets/gui/edit.xml +++ b/wlx-overlay-s/src/assets/gui/edit.xml @@ -45,6 +45,7 @@ + @@ -77,6 +78,19 @@ +
+
+ + + + + + + + + +
+
- \ No newline at end of file + diff --git a/wlx-overlay-s/src/gui/panel/helper.rs b/wlx-overlay-s/src/gui/panel/helper.rs index 92b7db7..a9c85fe 100644 --- a/wlx-overlay-s/src/gui/panel/helper.rs +++ b/wlx-overlay-s/src/gui/panel/helper.rs @@ -1,7 +1,7 @@ use regex::Regex; use std::{ fs, - io::{BufRead, BufReader, Read}, + io::{BufRead, BufReader}, process::Child, sync::{ Arc, LazyLock, diff --git a/wlx-overlay-s/src/gui/panel/mod.rs b/wlx-overlay-s/src/gui/panel/mod.rs index 4761a13..b461750 100644 --- a/wlx-overlay-s/src/gui/panel/mod.rs +++ b/wlx-overlay-s/src/gui/panel/mod.rs @@ -56,6 +56,7 @@ pub struct GuiPanel { context: WguiContext, timestep: Timestep, has_focus: [bool; 2], + last_content_size: Vec2, } pub type OnCustomIdFunc = Box< @@ -175,6 +176,7 @@ impl GuiPanel { gui_scale: params.gui_scale, initialized: false, has_focus: [false, false], + last_content_size: Vec2::ZERO, }) } @@ -206,6 +208,7 @@ impl GuiPanel { gui_scale: params.gui_scale, initialized: false, has_focus: [false, false], + last_content_size: Vec2::ZERO, }) } @@ -238,7 +241,6 @@ impl OverlayBackend for GuiPanel { if self.layout.content_size.x * self.layout.content_size.y != 0.0 { self.update_layout()?; self.interaction_transform = Some(ui_transform([ - //TODO: dynamic self.layout.content_size.x as _, self.layout.content_size.y as _, ])); @@ -275,6 +277,17 @@ impl OverlayBackend for GuiPanel { return Ok(ShouldRender::Unable); } + if !self + .last_content_size + .abs_diff_eq(self.layout.content_size, 0.1 /* pixels */) + { + self.interaction_transform = Some(ui_transform([ + self.layout.content_size.x as _, + self.layout.content_size.y as _, + ])); + self.last_content_size = self.layout.content_size; + } + Ok(if self.layout.check_toggle_needs_redraw() { ShouldRender::Should } else { diff --git a/wlx-overlay-s/src/overlays/edit/mod.rs b/wlx-overlay-s/src/overlays/edit/mod.rs index b05cc29..8fd0b07 100644 --- a/wlx-overlay-s/src/overlays/edit/mod.rs +++ b/wlx-overlay-s/src/overlays/edit/mod.rs @@ -14,6 +14,7 @@ use wgui::{ parser::Fetchable, widget::EventResult, }; +use wlx_capture::frame::Transform; use crate::{ attrib_value, @@ -24,6 +25,7 @@ use crate::{ gui::panel::{GuiPanel, NewGuiPanelParams, OnCustomAttribFunc, button::BUTTON_EVENTS}, overlays::edit::{ lock::InteractLockHandler, + mouse::new_mouse_tab_handler, pos::{PosTabState, new_pos_tab_handler}, sprite_tab::SpriteTabHandler, stereo::new_stereo_tab_handler, @@ -42,6 +44,7 @@ use crate::{ }; mod lock; +mod mouse; mod pos; mod sprite_tab; mod stereo; @@ -66,6 +69,7 @@ struct EditModeState { lock: InteractLockHandler, pos: SpriteTabHandler, stereo: SpriteTabHandler, + mouse: SpriteTabHandler, } type EditModeWrapPanel = GuiPanel; @@ -264,6 +268,7 @@ fn make_edit_panel(app: &mut AppState) -> anyhow::Result { lock: InteractLockHandler::default(), pos: SpriteTabHandler::default(), stereo: SpriteTabHandler::default(), + mouse: SpriteTabHandler::default(), }; let on_custom_attrib: OnCustomAttribFunc = Box::new(move |layout, attribs, _app| { @@ -323,6 +328,16 @@ fn make_edit_panel(app: &mut AppState) -> anyhow::Result { Ok(EventResult::Consumed) }) } + "::EditModeSetMouse" => { + let key = args.next().unwrap().to_owned(); + Box::new(move |common, _data, app, state| { + let sel = OverlaySelector::Id(*state.id.borrow()); + let task = state.mouse.button_clicked(common, &key); + app.tasks + .enqueue(TaskType::Overlay(OverlayTask::Modify(sel, task))); + Ok(EventResult::Consumed) + }) + } "::EditModeDeletePress" => Box::new(move |_common, _data, _app, state| { state.delete.pressed = Instant::now(); // TODO: animate to light up button after 2s @@ -361,9 +376,12 @@ fn make_edit_panel(app: &mut AppState) -> anyhow::Result { panel.state.pos = new_pos_tab_handler(&mut panel)?; panel.state.stereo = new_stereo_tab_handler(&mut panel)?; + panel.state.mouse = new_mouse_tab_handler(&mut panel)?; panel.state.lock = InteractLockHandler::new(&mut panel)?; - panel.state.tabs = - ButtonPaneTabSwitcher::new(&mut panel, &["none", "pos", "alpha", "curve", "stereo"])?; + panel.state.tabs = ButtonPaneTabSwitcher::new( + &mut panel, + &["none", "pos", "alpha", "curve", "stereo", "mouse"], + )?; set_up_checkbox(&mut panel, "additive_box", cb_assign_additive)?; set_up_slider(&mut panel, "lerp_slider", cb_assign_lerp)?; @@ -435,6 +453,19 @@ fn reset_panel( .set_tab_visible(&mut common, "stereo", false); } + if let Some(mouse) = attrib_value!( + owc.backend.get_attrib(BackendAttrib::MouseTransform), + BackendAttribValue::MouseTransform + ) { + panel.state.tabs.set_tab_visible(&mut common, "mouse", true); + panel.state.mouse.reset(&mut common, &mouse); + } else { + panel + .state + .tabs + .set_tab_visible(&mut common, "mouse", false); + } + panel.layout.process_alterables(alterables)?; Ok(()) diff --git a/wlx-overlay-s/src/overlays/edit/mouse.rs b/wlx-overlay-s/src/overlays/edit/mouse.rs new file mode 100644 index 0000000..6c008c3 --- /dev/null +++ b/wlx-overlay-s/src/overlays/edit/mouse.rs @@ -0,0 +1,72 @@ +use wlx_capture::frame::Transform; + +use crate::{ + overlays::edit::{ + EditModeWrapPanel, + sprite_tab::{SpriteTabHandler, SpriteTabKey}, + }, + windowing::backend::BackendAttribValue, +}; + +static MOUSE_NAMES: [&str; 9] = [ + "default", + "normal", + "rotate90", + "rotate180", + "rotate270", + "flipped", + "flip90", + "flip180", + "flip270", +]; + +pub fn new_mouse_tab_handler( + panel: &mut EditModeWrapPanel, +) -> anyhow::Result> { + SpriteTabHandler::new( + panel, + "mouse", + &MOUSE_NAMES, + Box::new(|_common, state| { + let mouse_transform = state.clone(); + Box::new(move |app, owc| { + owc.backend + .set_attrib(app, BackendAttribValue::MouseTransform(mouse_transform)); + }) + }), + None, + ) +} + +impl SpriteTabKey for Transform { + fn to_tab_key(&self) -> &'static str { + match self { + Transform::Undefined => "default", + Transform::Normal => "normal", + Transform::Rotated90 => "rotate90", + Transform::Rotated180 => "rotate180", + Transform::Rotated270 => "rotate270", + Transform::Flipped => "flipped", + Transform::Flipped90 => "flip90", + Transform::Flipped180 => "flip180", + Transform::Flipped270 => "flip270", + } + } + + fn from_tab_key(key: &str) -> Self { + match key { + "default" => Transform::Undefined, + "normal" => Transform::Normal, + "rotate90" => Transform::Rotated90, + "rotate180" => Transform::Rotated180, + "rotate270" => Transform::Rotated270, + "flipped" => Transform::Flipped, + "flip90" => Transform::Flipped90, + "flip180" => Transform::Flipped180, + "flip270" => Transform::Flipped270, + _ => { + panic!("cannot translate to mouse transform: {key}") + } + } + } +} diff --git a/wlx-overlay-s/src/overlays/edit/stereo.rs b/wlx-overlay-s/src/overlays/edit/stereo.rs index f873f90..658b115 100644 --- a/wlx-overlay-s/src/overlays/edit/stereo.rs +++ b/wlx-overlay-s/src/overlays/edit/stereo.rs @@ -45,7 +45,7 @@ impl SpriteTabKey for StereoMode { "topbottom" => StereoMode::TopBottom, "bottomtop" => StereoMode::BottomTop, _ => { - panic!("cannot translate to positioning: {key}") + panic!("cannot translate to stereo mode: {key}") } } } diff --git a/wlx-overlay-s/src/overlays/screen/backend.rs b/wlx-overlay-s/src/overlays/screen/backend.rs index 06febfd..170c1a2 100644 --- a/wlx-overlay-s/src/overlays/screen/backend.rs +++ b/wlx-overlay-s/src/overlays/screen/backend.rs @@ -16,7 +16,7 @@ use crate::{ subsystem::hid::{MOUSE_LEFT, MOUSE_MIDDLE, MOUSE_RIGHT, WheelDelta}, windowing::backend::{ BackendAttrib, BackendAttribValue, FrameMeta, OverlayBackend, OverlayEventData, - RenderResources, ShouldRender, StereoMode, + RenderResources, ShouldRender, StereoMode, ui_transform, }, }; @@ -47,6 +47,10 @@ pub struct ScreenBackend { mouse_transform: Affine2, interaction_transform: Option, stereo: Option, + pub(super) logical_pos: Vec2, + pub(super) logical_size: Vec2, + pub(super) mouse_transform_original: Transform, + mouse_transform_override: Transform, } impl ScreenBackend { @@ -63,49 +67,61 @@ impl ScreenBackend { mouse_transform: Affine2::ZERO, interaction_transform: None, stereo: None, + logical_pos: Vec2::ZERO, + logical_size: Vec2::ZERO, + mouse_transform_original: Transform::Undefined, + mouse_transform_override: Transform::Undefined, } } - pub(super) fn set_mouse_transform(&mut self, pos: Vec2, size: Vec2, transform: Transform) { + pub(super) fn apply_mouse_transform_with_override(&mut self, override_transform: Transform) { + let size = self.logical_size; + let pos = self.logical_pos; + + let transform = match override_transform { + Transform::Undefined => self.mouse_transform_original, + other => other, + }; + self.mouse_transform = match transform { - Transform::Rotated90 | Transform::Flipped90 => Affine2::from_cols( + Transform::Normal | Transform::Undefined => { + Affine2::from_cols(vec2(size.x, 0.), vec2(0., size.y), pos) + } + Transform::Rotated90 => Affine2::from_cols( vec2(0., size.y), vec2(-size.x, 0.), vec2(pos.x + size.x, pos.y), ), - Transform::Rotated180 | Transform::Flipped180 => Affine2::from_cols( + Transform::Rotated180 => Affine2::from_cols( vec2(-size.x, 0.), vec2(0., -size.y), vec2(pos.x + size.x, pos.y + size.y), ), - Transform::Rotated270 | Transform::Flipped270 => Affine2::from_cols( + Transform::Rotated270 => Affine2::from_cols( vec2(0., -size.y), vec2(size.x, 0.), vec2(pos.x, pos.y + size.y), ), - _ => Affine2::from_cols(vec2(size.x, 0.), vec2(0., size.y), pos), + Transform::Flipped => Affine2::from_cols( + vec2(-size.x, 0.), + vec2(0., size.y), + vec2(pos.x + size.x, pos.y), + ), + Transform::Flipped90 => { + Affine2::from_cols(vec2(0., size.y), vec2(size.x, 0.), vec2(pos.x, pos.y)) + } + Transform::Flipped180 => Affine2::from_cols( + vec2(size.x, 0.), + vec2(0., -size.y), + vec2(pos.x, pos.y + size.y), + ), + Transform::Flipped270 => Affine2::from_cols( + vec2(0., -size.y), + vec2(-size.x, 0.), + vec2(pos.x + size.x, pos.y + size.y), + ), }; } - - pub(super) fn set_interaction_transform(&mut self, res: Vec2, transform: Transform) { - let center = Vec2 { x: 0.5, y: 0.5 }; - self.interaction_transform = Some(match transform { - Transform::Rotated90 | Transform::Flipped90 => { - Affine2::from_cols(Vec2::NEG_Y * (res.x / res.y), Vec2::NEG_X, center) - } - Transform::Rotated180 | Transform::Flipped180 => { - Affine2::from_cols(Vec2::NEG_X, Vec2::NEG_Y * (-res.x / res.y), center) - } - Transform::Rotated270 | Transform::Flipped270 => { - Affine2::from_cols(Vec2::Y * (res.x / res.y), Vec2::X, center) - } - _ if res.y > res.x => { - // Xorg upright screens - Affine2::from_cols(Vec2::X * (res.y / res.x), Vec2::NEG_Y, center) - } - _ => Affine2::from_cols(Vec2::X, Vec2::NEG_Y * (res.x / res.y), center), - }); - } } impl OverlayBackend for ScreenBackend { @@ -175,17 +191,14 @@ impl OverlayBackend for ScreenBackend { .is_some_and(|old| old.extent[..2] != meta.extent[..2]) { pipeline.set_extent(app, [meta.extent[0] as _, meta.extent[1] as _])?; - self.set_interaction_transform( - meta.extent.extent_vec2(), - frame.get_transform(), - ); + self.interaction_transform = Some(ui_transform(meta.extent.extent_u32arr())); } } else { let pipeline = ScreenPipeline::new(&meta, app, self.stereo.unwrap_or(StereoMode::None))?; meta.extent[2] = pipeline.get_depth(); self.pipeline = Some(pipeline); - self.set_interaction_transform(meta.extent.extent_vec2(), frame.get_transform()); + self.interaction_transform = Some(ui_transform(meta.extent.extent_u32arr())); } self.meta = Some(meta); @@ -281,6 +294,9 @@ impl OverlayBackend for ScreenBackend { fn get_attrib(&self, attrib: BackendAttrib) -> Option { match attrib { BackendAttrib::Stereo => self.stereo.map(|s| BackendAttribValue::Stereo(s)), + BackendAttrib::MouseTransform => Some(BackendAttribValue::MouseTransform( + self.mouse_transform_override, + )), _ => None, } } @@ -299,6 +315,11 @@ impl OverlayBackend for ScreenBackend { false } } + BackendAttribValue::MouseTransform(new) => { + self.mouse_transform_override = new; + self.apply_mouse_transform_with_override(new); + true + } _ => false, } } diff --git a/wlx-overlay-s/src/overlays/screen/wl.rs b/wlx-overlay-s/src/overlays/screen/wl.rs index 6530d45..771a103 100644 --- a/wlx-overlay-s/src/overlays/screen/wl.rs +++ b/wlx-overlay-s/src/overlays/screen/wl.rs @@ -1,6 +1,7 @@ use glam::vec2; use wlx_capture::{ WlxCapture, + frame::Transform, wayland::{WlxClient, WlxOutput}, wlr_dmabuf::WlrDmabufCapture, wlr_screencopy::WlrScreencopyCapture, @@ -124,15 +125,14 @@ pub fn create_screens_wayland(wl: &mut WlxClient, app: &mut AppState) -> ScreenC &mut pw_tokens, app, ) { - let logical_pos = vec2(output.logical_pos.0 as f32, output.logical_pos.1 as f32); - let logical_size = vec2(output.logical_size.0 as f32, output.logical_size.1 as f32); - let transform = output.transform; - - backend.set_mouse_transform(logical_pos, logical_size, transform); + backend.logical_pos = vec2(output.logical_pos.0 as f32, output.logical_pos.1 as f32); + backend.logical_size = vec2(output.logical_size.0 as f32, output.logical_size.1 as f32); + backend.mouse_transform_original = output.transform; + backend.apply_mouse_transform_with_override(Transform::Undefined); let window_config = create_screen_from_backend( output.name.clone(), - transform, + output.transform, &app.session, Box::new(backend), ); diff --git a/wlx-overlay-s/src/overlays/screen/x11.rs b/wlx-overlay-s/src/overlays/screen/x11.rs index 70cb369..c3f9ee8 100644 --- a/wlx-overlay-s/src/overlays/screen/x11.rs +++ b/wlx-overlay-s/src/overlays/screen/x11.rs @@ -103,11 +103,9 @@ pub fn create_screens_x11pw(app: &mut AppState) -> anyhow::Result anyhow::Result