feat(displays): pan left and right when dragging displays to edge
This commit is contained in:
parent
48fedb6e75
commit
e8106a975e
3 changed files with 66 additions and 14 deletions
14
Cargo.toml
14
Cargo.toml
|
|
@ -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"
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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))
|
||||||
})
|
})
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue