feat(displays): pan left and right when dragging displays to edge

This commit is contained in:
Michael Aaron Murphy 2024-07-18 11:43:31 +02:00 committed by Michael Murphy
parent 48fedb6e75
commit e8106a975e
3 changed files with 66 additions and 14 deletions

View file

@ -12,7 +12,15 @@ tokio = { version = "1.37.0", features = ["macros"] }
[workspace.dependencies.libcosmic]
git = "https://github.com/pop-os/libcosmic"
features = ["dbus-config", "single-instance", "multi-window", "tokio", "wayland", "wgpu", "xdg-portal"]
features = [
"dbus-config",
"single-instance",
"multi-window",
"tokio",
"wayland",
"wgpu",
"xdg-portal",
]
[workspace.dependencies.cosmic-config]
git = "https://github.com/pop-os/libcosmic"
@ -35,10 +43,6 @@ git = "https://github.com/smithay/client-toolkit/"
package = "smithay-client-toolkit"
rev = "3bed072"
[profile.dev]
opt-level = 2
lto = false
[profile.release]
opt-level = 3
lto = "thin"

View file

@ -19,6 +19,12 @@ const UNIT_PIXELS: f32 = 12.0;
pub type OnPlacementFunc<Message> = Box<dyn Fn(OutputKey, i32, i32) -> Message>;
pub type OnSelectFunc<Message> = Box<dyn Fn(segmented_button::Entity) -> Message>;
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum Pan {
Left,
Right,
}
#[must_use]
#[derive(derive_setters::Setters)]
pub struct Arrangement<'a, Message> {
@ -27,6 +33,8 @@ pub struct Arrangement<'a, Message> {
#[setters(skip)]
tab_model: &'a SingleSelectModel,
#[setters(skip)]
on_pan: Option<Box<dyn Fn(Pan) -> Message>>,
#[setters(skip)]
on_placement: Option<OnPlacementFunc<Message>>,
#[setters(skip)]
on_select: Option<OnSelectFunc<Message>>,
@ -39,6 +47,7 @@ impl<'a, Message> Arrangement<'a, Message> {
Self {
list,
tab_model,
on_pan: None,
on_placement: None,
on_select: None,
width: Length::Shrink,
@ -46,6 +55,11 @@ impl<'a, Message> Arrangement<'a, Message> {
}
}
pub fn on_pan(mut self, on_pan: impl Fn(Pan) -> Message + 'static) -> Self {
self.on_pan = Some(Box::new(on_pan));
self
}
pub fn on_placement(
mut self,
on_placement: impl Fn(OutputKey, i32, i32) -> Message + 'static,
@ -119,8 +133,8 @@ impl<'a, Message: Clone> Widget<Message, cosmic::Theme, Renderer> for Arrangemen
display_area.1 = display_area.1.max(height as i32 + output.position.1);
}
let width = (max_dimensions.0 as i32 * 2 + display_area.0) as f32 / UNIT_PIXELS;
let height = (max_dimensions.1 as i32 * 2 + display_area.1) as f32 / UNIT_PIXELS;
let width = ((max_dimensions.0 as f32 * 2.0) as i32 + display_area.0) as f32 / UNIT_PIXELS;
let height = ((max_dimensions.1 as f32 * 2.0) as i32 + display_area.1) as f32 / UNIT_PIXELS;
let state = tree.state.downcast_mut::<State>();
state.max_dimensions = (
@ -146,16 +160,25 @@ impl<'a, Message: Clone> Widget<Message, cosmic::Theme, Renderer> for Arrangemen
_renderer: &Renderer,
_clipboard: &mut dyn Clipboard,
shell: &mut Shell<'_, Message>,
_viewport: &Rectangle,
viewport: &Rectangle,
) -> event::Status {
let bounds = layout.bounds();
match event {
core::Event::Mouse(mouse::Event::CursorMoved { .. })
| core::Event::Touch(touch::Event::FingerMoved { .. }) => {
if let Some(position) = cursor.position() {
let state = tree.state.downcast_mut::<State>();
if let Some((output_key, region)) = state.dragging.as_mut() {
core::Event::Mouse(mouse::Event::CursorMoved { position, .. })
| core::Event::Touch(touch::Event::FingerMoved { position, .. }) => {
let state = tree.state.downcast_mut::<State>();
if let Some((output_key, region)) = state.dragging.as_mut() {
if let Some(ref mut on_pan) = self.on_pan {
if bounds.x + viewport.width - 150.0 < position.x {
shell.publish(on_pan(Pan::Right));
} else if bounds.x + 150.0 > position.x {
shell.publish(on_pan(Pan::Left));
}
}
if let Some(inner_position) = cursor.position() {
update_dragged_region(
self.tab_model,
self.list,
@ -163,7 +186,10 @@ impl<'a, Message: Clone> Widget<Message, cosmic::Theme, Renderer> for Arrangemen
*output_key,
region,
state.max_dimensions,
(position.x - state.offset.0, position.y - state.offset.1),
(
inner_position.x - state.offset.0,
inner_position.y - state.offset.1,
),
);
return event::Status::Captured;

View file

@ -76,6 +76,8 @@ pub enum Message {
// NightLightContext,
/// Set the orientation of a display.
Orientation(Transform),
/// Pan the displays view
Pan(arrangement::Pan),
/// Status of an applied display change.
RandrResult(Arc<std::io::Result<ExitStatus>>),
/// Request to reload the page.
@ -123,6 +125,8 @@ pub struct Page {
cache: ViewCache,
// context: Option<ContextDrawer>,
display_arrangement_scrollable: widget::Id,
/// Tracks the last pan status.
last_pan: f32,
/// The setting to revert to if the next dialog page is cancelled.
dialog: Option<Randr>,
/// the instant the setting was changed.
@ -143,6 +147,7 @@ impl Default for Page {
cache: ViewCache::default(),
// context: None,
display_arrangement_scrollable: widget::Id::unique(),
last_pan: 0.5,
dialog: None,
dialog_countdown: 0,
show_display_options: true,
@ -413,6 +418,21 @@ impl Page {
// }
Message::Orientation(orientation) => return self.set_orientation(orientation),
Message::Pan(pan) => {
match pan {
arrangement::Pan::Left => self.last_pan = 0.0f32.max(self.last_pan - 0.01),
arrangement::Pan::Right => self.last_pan = 1.0f32.min(self.last_pan + 0.01),
}
return cosmic::iced::widget::scrollable::snap_to(
self.display_arrangement_scrollable.clone(),
RelativeOffset {
x: self.last_pan,
y: 0.0,
},
);
}
Message::Position(display, x, y) => return self.set_position(display, x, y),
Message::Refresh => {
@ -447,6 +467,7 @@ impl Page {
}
}
self.last_pan = 0.5;
cosmic::iced::widget::scrollable::snap_to(
self.display_arrangement_scrollable.clone(),
RelativeOffset { x: 0.5, y: 0.5 },
@ -958,6 +979,7 @@ pub fn display_arrangement() -> Section<crate::pages::Message> {
.push({
Arrangement::new(&page.list, &page.display_tabs)
.on_select(|id| pages::Message::Displays(Message::Display(id)))
.on_pan(|pan| pages::Message::Displays(Message::Pan(pan)))
.on_placement(|id, x, y| {
pages::Message::Displays(Message::Position(id, x, y))
})