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] [workspace.dependencies.libcosmic]
git = "https://github.com/pop-os/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] [workspace.dependencies.cosmic-config]
git = "https://github.com/pop-os/libcosmic" git = "https://github.com/pop-os/libcosmic"
@ -35,10 +43,6 @@ git = "https://github.com/smithay/client-toolkit/"
package = "smithay-client-toolkit" package = "smithay-client-toolkit"
rev = "3bed072" rev = "3bed072"
[profile.dev]
opt-level = 2
lto = false
[profile.release] [profile.release]
opt-level = 3 opt-level = 3
lto = "thin" 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 OnPlacementFunc<Message> = Box<dyn Fn(OutputKey, i32, i32) -> Message>;
pub type OnSelectFunc<Message> = Box<dyn Fn(segmented_button::Entity) -> Message>; pub type OnSelectFunc<Message> = Box<dyn Fn(segmented_button::Entity) -> Message>;
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum Pan {
Left,
Right,
}
#[must_use] #[must_use]
#[derive(derive_setters::Setters)] #[derive(derive_setters::Setters)]
pub struct Arrangement<'a, Message> { pub struct Arrangement<'a, Message> {
@ -27,6 +33,8 @@ pub struct Arrangement<'a, Message> {
#[setters(skip)] #[setters(skip)]
tab_model: &'a SingleSelectModel, tab_model: &'a SingleSelectModel,
#[setters(skip)] #[setters(skip)]
on_pan: Option<Box<dyn Fn(Pan) -> Message>>,
#[setters(skip)]
on_placement: Option<OnPlacementFunc<Message>>, on_placement: Option<OnPlacementFunc<Message>>,
#[setters(skip)] #[setters(skip)]
on_select: Option<OnSelectFunc<Message>>, on_select: Option<OnSelectFunc<Message>>,
@ -39,6 +47,7 @@ impl<'a, Message> Arrangement<'a, Message> {
Self { Self {
list, list,
tab_model, tab_model,
on_pan: None,
on_placement: None, on_placement: None,
on_select: None, on_select: None,
width: Length::Shrink, 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( pub fn on_placement(
mut self, mut self,
on_placement: impl Fn(OutputKey, i32, i32) -> Message + 'static, 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); 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 width = ((max_dimensions.0 as f32 * 2.0) as i32 + display_area.0) as f32 / UNIT_PIXELS;
let height = (max_dimensions.1 as i32 * 2 + display_area.1) 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>(); let state = tree.state.downcast_mut::<State>();
state.max_dimensions = ( state.max_dimensions = (
@ -146,16 +160,25 @@ impl<'a, Message: Clone> Widget<Message, cosmic::Theme, Renderer> for Arrangemen
_renderer: &Renderer, _renderer: &Renderer,
_clipboard: &mut dyn Clipboard, _clipboard: &mut dyn Clipboard,
shell: &mut Shell<'_, Message>, shell: &mut Shell<'_, Message>,
_viewport: &Rectangle, viewport: &Rectangle,
) -> event::Status { ) -> event::Status {
let bounds = layout.bounds(); let bounds = layout.bounds();
match event { match event {
core::Event::Mouse(mouse::Event::CursorMoved { .. }) core::Event::Mouse(mouse::Event::CursorMoved { position, .. })
| core::Event::Touch(touch::Event::FingerMoved { .. }) => { | core::Event::Touch(touch::Event::FingerMoved { position, .. }) => {
if let Some(position) = cursor.position() { let state = tree.state.downcast_mut::<State>();
let state = tree.state.downcast_mut::<State>();
if let Some((output_key, region)) = state.dragging.as_mut() { 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( update_dragged_region(
self.tab_model, self.tab_model,
self.list, self.list,
@ -163,7 +186,10 @@ impl<'a, Message: Clone> Widget<Message, cosmic::Theme, Renderer> for Arrangemen
*output_key, *output_key,
region, region,
state.max_dimensions, 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; return event::Status::Captured;

View file

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