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 {
elements: Arc<Mutex<Vec<Element>>>,
screen_space_relative: Option<Output>,
scale: Arc<Mutex<f64>>,
}
pub type SeatMenuGrabState = Mutex<Option<MenuGrabState>>;
@ -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<State>,
screen_space_relative: Option<Output>,
scale: Arc<Mutex<f64>>,
}
impl PointerGrab<State> 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<i32, Global>,
size: Size<i32, Global>,
) -> Vec<Rectangle<i32, Global>> {
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<i32, Global>,
size: Size<i32, Global>,
x: AxisAlignment,
y: AxisAlignment,
) -> Vec<Rectangle<i32, Global>> {
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<Item = Item>,
position: Point<i32, Global>,
alignment: MenuAlignment,
screen_space_relative: bool,
screen_space_relative: Option<f64>,
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);
}
}

View file

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

View file

@ -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| {