diff --git a/src/shell/grabs/menu/mod.rs b/src/shell/grabs/menu/mod.rs index 4b7a516a..071090bd 100644 --- a/src/shell/grabs/menu/mod.rs +++ b/src/shell/grabs/menu/mod.rs @@ -60,6 +60,7 @@ pub use self::default::*; pub struct MenuGrabState { elements: Arc>>, screen_space_relative: Option, + scale: Arc>, } pub type SeatMenuGrabState = Mutex>; @@ -338,6 +339,7 @@ impl Program for ContextMenu { .unwrap() .loc; element.output_enter(&output, element.bbox()); + element.set_additional_scale(*grab_state.scale.lock().unwrap()); elements.push(Element { iced: element, @@ -505,6 +507,7 @@ pub struct MenuGrab { start_data: GrabStartData, seat: Seat, screen_space_relative: Option, + scale: Arc>, } impl PointerGrab for MenuGrab { @@ -853,14 +856,19 @@ pub struct MenuAlignment { #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum AxisAlignment { - Corner, + Corner(u32), Centered, + PreferCentered, } impl MenuAlignment { pub const CORNER: Self = MenuAlignment { - x: AxisAlignment::Corner, - y: AxisAlignment::Corner, + x: AxisAlignment::Corner(0), + y: AxisAlignment::Corner(0), + }; + pub const PREFER_CENTERED: Self = MenuAlignment { + x: AxisAlignment::PreferCentered, + y: AxisAlignment::PreferCentered, }; pub const CENTERED: Self = MenuAlignment { x: AxisAlignment::Centered, @@ -868,46 +876,140 @@ impl MenuAlignment { }; pub const HORIZONTALLY_CENTERED: Self = MenuAlignment { x: AxisAlignment::Centered, - y: AxisAlignment::Corner, + y: AxisAlignment::Corner(0), }; pub const VERTICALLY_CENTERED: Self = MenuAlignment { - x: AxisAlignment::Corner, + x: AxisAlignment::Corner(0), y: AxisAlignment::Centered, }; + pub fn horizontally_centered(offset: u32, fixed: bool) -> MenuAlignment { + MenuAlignment { + x: if fixed { + AxisAlignment::Centered + } else { + AxisAlignment::PreferCentered + }, + y: AxisAlignment::Corner(offset), + } + } + + pub fn vertically_centered(offset: u32, fixed: bool) -> MenuAlignment { + MenuAlignment { + x: AxisAlignment::Corner(offset), + y: if fixed { + AxisAlignment::Centered + } else { + AxisAlignment::PreferCentered + }, + } + } + fn rectangles( &self, position: Point, size: Size, ) -> Vec> { - match (self.x, self.y) { - (AxisAlignment::Corner, AxisAlignment::Corner) => vec![ - Rectangle::new(position, size), // normal - Rectangle::new(position - Point::from((size.w, 0)), size), // flipped left - Rectangle::new(position - Point::from((0, size.h)), size), // flipped up - Rectangle::new(position - size.to_point(), size), // flipped left & up - ], - (AxisAlignment::Centered, AxisAlignment::Corner) => { - let x = position.x - ((size.w as f64 / 2.).round() as i32); - vec![ - Rectangle::new(Point::from((x, position.y)), size), // below - Rectangle::new(Point::from((x, position.y - size.h)), size), // above - ] - } - (AxisAlignment::Corner, AxisAlignment::Centered) => { - let y = position.y - ((size.h as f64 / 2.).round() as i32); - vec![ - Rectangle::new(Point::from((position.x, y)), size), // left - Rectangle::new(Point::from((position.x - size.w, y)), size), // right - ] - } - (AxisAlignment::Centered, AxisAlignment::Centered) => { - vec![Rectangle::new( - position - size.to_f64().downscale(2.).to_i32_round().to_point(), + fn for_alignment( + position: Point, + size: Size, + x: AxisAlignment, + y: AxisAlignment, + ) -> Vec> { + match (x, y) { + (AxisAlignment::Corner(x_offset), AxisAlignment::Corner(y_offset)) => { + let offset = Point::from((x_offset as i32, y_offset as i32)); + vec![ + Rectangle::new(position + offset, size), // normal + Rectangle::new( + position - Point::from((size.w, 0)) + + Point::from((-(x_offset as i32), y_offset as i32)), + size, + ), // flipped left + Rectangle::new( + position + - Point::from((0, size.h)) + - Point::from((x_offset as i32, -(y_offset as i32))), + size, + ), // flipped up + Rectangle::new(position - size.to_point() - offset, size), // flipped left & up + ] + } + (AxisAlignment::Centered, AxisAlignment::Corner(offset)) => { + let x = position.x - ((size.w as f64 / 2.).round() as i32); + vec![ + Rectangle::new(Point::from((x, position.y + offset as i32)), size), // below + Rectangle::new(Point::from((x, position.y - size.h - offset as i32)), size), // above + ] + } + (AxisAlignment::Corner(offset), AxisAlignment::Centered) => { + let y = position.y - ((size.h as f64 / 2.).round() as i32); + vec![ + Rectangle::new(Point::from((position.x + offset as i32, y)), size), // left + Rectangle::new(Point::from((position.x - size.w - offset as i32, y)), size), // right + ] + } + (AxisAlignment::Centered, AxisAlignment::Centered) => { + vec![Rectangle::new( + position - size.to_f64().downscale(2.).to_i32_round().to_point(), + size, + )] + } + (AxisAlignment::PreferCentered, AxisAlignment::PreferCentered) => for_alignment( + position, size, - )] + AxisAlignment::Centered, + AxisAlignment::Centered, + ) + .into_iter() + .chain( + for_alignment( + position, + size, + AxisAlignment::Centered, + AxisAlignment::Corner(0), + ) + .into_iter(), + ) + .chain( + for_alignment( + position, + size, + AxisAlignment::Corner(0), + AxisAlignment::Centered, + ) + .into_iter(), + ) + .chain( + for_alignment( + position, + size, + AxisAlignment::Corner(0), + AxisAlignment::Corner(0), + ) + .into_iter(), + ) + .collect(), + (AxisAlignment::PreferCentered, y) => { + for_alignment(position, size, AxisAlignment::Centered, y) + .into_iter() + .chain( + for_alignment(position, size, AxisAlignment::Corner(0), y).into_iter(), + ) + .collect() + } + (x, AxisAlignment::PreferCentered) => { + for_alignment(position, size, x, AxisAlignment::Centered) + .into_iter() + .chain( + for_alignment(position, size, x, AxisAlignment::Corner(0)).into_iter(), + ) + .collect() + } } } + + for_alignment(position, size, self.x, self.y) } } @@ -918,7 +1020,7 @@ impl MenuGrab { items: impl Iterator, position: Point, alignment: MenuAlignment, - screen_space_relative: bool, + screen_space_relative: Option, handle: LoopHandle<'static, crate::state::State>, theme: cosmic::Theme, ) -> MenuGrab { @@ -931,8 +1033,16 @@ impl MenuGrab { element.resize(min_size); let output = seat.active_output(); + // TODO: This feels a lot like cheap xdg-positioner. Refactor and unify let position = alignment - .rectangles(position, min_size.as_global()) + .rectangles( + position, + min_size + .to_f64() + .upscale(screen_space_relative.unwrap_or(1.)) + .to_i32_round() + .as_global(), + ) .iter() .rev() // preference of max_by_key is backwards .max_by_key(|rect| { @@ -945,6 +1055,9 @@ impl MenuGrab { .loc; element.output_enter(&output, element.bbox()); + if let Some(scale) = screen_space_relative { + element.set_additional_scale(scale); + } let elements = Arc::new(Mutex::new(vec![Element { iced: element, @@ -953,11 +1066,13 @@ impl MenuGrab { touch_entered: None, }])); - let screen_space_relative = screen_space_relative.then_some(output); + let scale = Arc::new(Mutex::new(screen_space_relative.unwrap_or(1.))); + let screen_space_relative = screen_space_relative.is_some().then_some(output); let grab_state = MenuGrabState { elements: elements.clone(), screen_space_relative: screen_space_relative.clone(), + scale: scale.clone(), }; *seat @@ -972,6 +1087,14 @@ impl MenuGrab { start_data, seat: seat.clone(), screen_space_relative, + scale, + } + } + + pub fn set_additional_scale(&self, scale: f64) { + *self.scale.lock().unwrap() = scale; + for element in &*self.elements.lock().unwrap() { + element.iced.set_additional_scale(scale); } } diff --git a/src/shell/mod.rs b/src/shell/mod.rs index 91e4d6ff..96c2bee4 100644 --- a/src/shell/mod.rs +++ b/src/shell/mod.rs @@ -2850,7 +2850,7 @@ impl Shell { }, global_position, MenuAlignment::CORNER, - false, + None, evlh.clone(), self.theme.clone(), ); diff --git a/src/shell/zoom.rs b/src/shell/zoom.rs index 014ef11c..369ecc07 100644 --- a/src/shell/zoom.rs +++ b/src/shell/zoom.rs @@ -113,7 +113,7 @@ impl OutputZoomState { element.set_activate(true); element.resize(size); element.output_enter(output, Rectangle::new(Point::from((0, 0)), size)); - element.refresh(); + element.set_additional_scale(level.min(4.)); OutputZoomState { focal_point, @@ -153,6 +153,7 @@ impl OutputZoomState { } pub fn update(&self, level: f64, movement: ZoomMovement, increment: u32) { + self.element.set_additional_scale(level.min(4.)); self.element.queue_message(ZoomMessage::Update { level, movement, @@ -540,8 +541,9 @@ impl Program for ZoomProgram { )); let position = Point::<_, Local>::from(( location.x, - elem_location.y + elem_size.h, + elem_location.y + elem_size.h / 2., )); + std::mem::drop(output_state_ref); let grab = MenuGrab::new( start_data, @@ -596,8 +598,11 @@ impl Program for ZoomProgram { ] .into_iter(), position.to_global(&output).to_i32_round(), - MenuAlignment::HORIZONTALLY_CENTERED, - true, + MenuAlignment::horizontally_centered( + (elem_size.h / 2.).round() as u32, + false, + ), + Some(zoom_state.level.min(4.)), state.common.event_loop_handle.clone(), state.common.theme.clone(), ); @@ -648,8 +653,9 @@ impl Program for ZoomProgram { )); let position = Point::<_, Local>::from(( location.x, - elem_location.y + elem_size.h, + elem_location.y + (elem_size.h / 2.), )); + std::mem::drop(output_state_ref); let grab = MenuGrab::new( start_data, @@ -669,8 +675,8 @@ impl Program for ZoomProgram { }) }), position.to_global(&output).to_i32_round(), - MenuAlignment::CENTERED, - true, + MenuAlignment::PREFER_CENTERED, + Some(zoom_state.level.min(4.)), state.common.event_loop_handle.clone(), state.common.theme.clone(), ); @@ -690,14 +696,6 @@ impl Program for ZoomProgram { } }); } - - /* - let new_increment = self.increments[idx]; - let _ = loop_handle.insert_idle(move |state| { - state.common.config.cosmic_conf.accessibility_zoom.increment = new_increment; - // TODO: Write config - }); - */ } ZoomMessage::Close => { let _ = loop_handle.insert_idle(|state| {