shell: Rescale zoom UI with zoom factor

This commit is contained in:
Victoria Brekenfeld 2025-02-14 18:34:52 +01:00 • committed by Victoria Brekenfeld
parent 07a471f285
commit 3cff46d7e5
3 changed files with 170 additions and 49 deletions

View file

@ -60,6 +60,7 @@ pub use self::default::*;
pub struct MenuGrabState { pub struct MenuGrabState {
elements: Arc<Mutex<Vec<Element>>>, elements: Arc<Mutex<Vec<Element>>>,
screen_space_relative: Option<Output>, screen_space_relative: Option<Output>,
scale: Arc<Mutex<f64>>,
} }
pub type SeatMenuGrabState = Mutex<Option<MenuGrabState>>; pub type SeatMenuGrabState = Mutex<Option<MenuGrabState>>;
@ -338,6 +339,7 @@ impl Program for ContextMenu {
.unwrap() .unwrap()
.loc; .loc;
element.output_enter(&output, element.bbox()); element.output_enter(&output, element.bbox());
element.set_additional_scale(*grab_state.scale.lock().unwrap());
elements.push(Element { elements.push(Element {
iced: element, iced: element,
@ -505,6 +507,7 @@ pub struct MenuGrab {
start_data: GrabStartData, start_data: GrabStartData,
seat: Seat<State>, seat: Seat<State>,
screen_space_relative: Option<Output>, screen_space_relative: Option<Output>,
scale: Arc<Mutex<f64>>,
} }
impl PointerGrab<State> for MenuGrab { impl PointerGrab<State> for MenuGrab {
@ -853,14 +856,19 @@ pub struct MenuAlignment {
#[derive(Debug, Clone, Copy, PartialEq, Eq)] #[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum AxisAlignment { pub enum AxisAlignment {
Corner, Corner(u32),
Centered, Centered,
PreferCentered,
} }
impl MenuAlignment { impl MenuAlignment {
pub const CORNER: Self = MenuAlignment { pub const CORNER: Self = MenuAlignment {
x: AxisAlignment::Corner, x: AxisAlignment::Corner(0),
y: AxisAlignment::Corner, y: AxisAlignment::Corner(0),
};
pub const PREFER_CENTERED: Self = MenuAlignment {
x: AxisAlignment::PreferCentered,
y: AxisAlignment::PreferCentered,
}; };
pub const CENTERED: Self = MenuAlignment { pub const CENTERED: Self = MenuAlignment {
x: AxisAlignment::Centered, x: AxisAlignment::Centered,
@ -868,46 +876,140 @@ impl MenuAlignment {
}; };
pub const HORIZONTALLY_CENTERED: Self = MenuAlignment { pub const HORIZONTALLY_CENTERED: Self = MenuAlignment {
x: AxisAlignment::Centered, x: AxisAlignment::Centered,
y: AxisAlignment::Corner, y: AxisAlignment::Corner(0),
}; };
pub const VERTICALLY_CENTERED: Self = MenuAlignment { pub const VERTICALLY_CENTERED: Self = MenuAlignment {
x: AxisAlignment::Corner, x: AxisAlignment::Corner(0),
y: AxisAlignment::Centered, 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( fn rectangles(
&self, &self,
position: Point<i32, Global>, position: Point<i32, Global>,
size: Size<i32, Global>, size: Size<i32, Global>,
) -> Vec<Rectangle<i32, Global>> { ) -> Vec<Rectangle<i32, Global>> {
match (self.x, self.y) { fn for_alignment(
(AxisAlignment::Corner, AxisAlignment::Corner) => vec![ position: Point<i32, Global>,
Rectangle::new(position, size), // normal size: Size<i32, Global>,
Rectangle::new(position - Point::from((size.w, 0)), size), // flipped left x: AxisAlignment,
Rectangle::new(position - Point::from((0, size.h)), size), // flipped up y: AxisAlignment,
Rectangle::new(position - size.to_point(), size), // flipped left & up ) -> Vec<Rectangle<i32, Global>> {
], match (x, y) {
(AxisAlignment::Centered, AxisAlignment::Corner) => { (AxisAlignment::Corner(x_offset), AxisAlignment::Corner(y_offset)) => {
let x = position.x - ((size.w as f64 / 2.).round() as i32); let offset = Point::from((x_offset as i32, y_offset as i32));
vec![ vec![
Rectangle::new(Point::from((x, position.y)), size), // below Rectangle::new(position + offset, size), // normal
Rectangle::new(Point::from((x, position.y - size.h)), size), // above Rectangle::new(
] position - Point::from((size.w, 0))
} + Point::from((-(x_offset as i32), y_offset as i32)),
(AxisAlignment::Corner, AxisAlignment::Centered) => { size,
let y = position.y - ((size.h as f64 / 2.).round() as i32); ), // flipped left
vec![ Rectangle::new(
Rectangle::new(Point::from((position.x, y)), size), // left position
Rectangle::new(Point::from((position.x - size.w, y)), size), // right - Point::from((0, size.h))
] - Point::from((x_offset as i32, -(y_offset as i32))),
} size,
(AxisAlignment::Centered, AxisAlignment::Centered) => { ), // flipped up
vec![Rectangle::new( Rectangle::new(position - size.to_point() - offset, size), // flipped left & up
position - size.to_f64().downscale(2.).to_i32_round().to_point(), ]
}
(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, 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<Item = Item>, items: impl Iterator<Item = Item>,
position: Point<i32, Global>, position: Point<i32, Global>,
alignment: MenuAlignment, alignment: MenuAlignment,
screen_space_relative: bool, screen_space_relative: Option<f64>,
handle: LoopHandle<'static, crate::state::State>, handle: LoopHandle<'static, crate::state::State>,
theme: cosmic::Theme, theme: cosmic::Theme,
) -> MenuGrab { ) -> MenuGrab {
@ -931,8 +1033,16 @@ impl MenuGrab {
element.resize(min_size); element.resize(min_size);
let output = seat.active_output(); let output = seat.active_output();
// TODO: This feels a lot like cheap xdg-positioner. Refactor and unify
let position = alignment 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() .iter()
.rev() // preference of max_by_key is backwards .rev() // preference of max_by_key is backwards
.max_by_key(|rect| { .max_by_key(|rect| {
@ -945,6 +1055,9 @@ impl MenuGrab {
.loc; .loc;
element.output_enter(&output, element.bbox()); 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 { let elements = Arc::new(Mutex::new(vec![Element {
iced: element, iced: element,
@ -953,11 +1066,13 @@ impl MenuGrab {
touch_entered: None, 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 { let grab_state = MenuGrabState {
elements: elements.clone(), elements: elements.clone(),
screen_space_relative: screen_space_relative.clone(), screen_space_relative: screen_space_relative.clone(),
scale: scale.clone(),
}; };
*seat *seat
@ -972,6 +1087,14 @@ impl MenuGrab {
start_data, start_data,
seat: seat.clone(), seat: seat.clone(),
screen_space_relative, 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);
} }
} }

View file

@ -2850,7 +2850,7 @@ impl Shell {
}, },
global_position, global_position,
MenuAlignment::CORNER, MenuAlignment::CORNER,
false, None,
evlh.clone(), evlh.clone(),
self.theme.clone(), self.theme.clone(),
); );

View file

@ -113,7 +113,7 @@ impl OutputZoomState {
element.set_activate(true); element.set_activate(true);
element.resize(size); element.resize(size);
element.output_enter(output, Rectangle::new(Point::from((0, 0)), size)); element.output_enter(output, Rectangle::new(Point::from((0, 0)), size));
element.refresh(); element.set_additional_scale(level.min(4.));
OutputZoomState { OutputZoomState {
focal_point, focal_point,
@ -153,6 +153,7 @@ impl OutputZoomState {
} }
pub fn update(&self, level: f64, movement: ZoomMovement, increment: u32) { pub fn update(&self, level: f64, movement: ZoomMovement, increment: u32) {
self.element.set_additional_scale(level.min(4.));
self.element.queue_message(ZoomMessage::Update { self.element.queue_message(ZoomMessage::Update {
level, level,
movement, movement,
@ -540,8 +541,9 @@ impl Program for ZoomProgram {
)); ));
let position = Point::<_, Local>::from(( let position = Point::<_, Local>::from((
location.x, 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( let grab = MenuGrab::new(
start_data, start_data,
@ -596,8 +598,11 @@ impl Program for ZoomProgram {
] ]
.into_iter(), .into_iter(),
position.to_global(&output).to_i32_round(), position.to_global(&output).to_i32_round(),
MenuAlignment::HORIZONTALLY_CENTERED, MenuAlignment::horizontally_centered(
true, (elem_size.h / 2.).round() as u32,
false,
),
Some(zoom_state.level.min(4.)),
state.common.event_loop_handle.clone(), state.common.event_loop_handle.clone(),
state.common.theme.clone(), state.common.theme.clone(),
); );
@ -648,8 +653,9 @@ impl Program for ZoomProgram {
)); ));
let position = Point::<_, Local>::from(( let position = Point::<_, Local>::from((
location.x, 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( let grab = MenuGrab::new(
start_data, start_data,
@ -669,8 +675,8 @@ impl Program for ZoomProgram {
}) })
}), }),
position.to_global(&output).to_i32_round(), position.to_global(&output).to_i32_round(),
MenuAlignment::CENTERED, MenuAlignment::PREFER_CENTERED,
true, Some(zoom_state.level.min(4.)),
state.common.event_loop_handle.clone(), state.common.event_loop_handle.clone(),
state.common.theme.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 => { ZoomMessage::Close => {
let _ = loop_handle.insert_idle(|state| { let _ = loop_handle.insert_idle(|state| {