Skip to content

Commit 5200f74

Browse files
committed
status line: Custom widget for mouse input handling
1 parent e22ad3f commit 5200f74

File tree

6 files changed

+193
-13
lines changed

6 files changed

+193
-13
lines changed

Cargo.lock

Lines changed: 12 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

cosmic-applet-status-line/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ version = "0.1.0"
44
edition = "2021"
55

66
[dependencies]
7+
delegate = "0.9"
78
libcosmic = { git = "https://github.com/pop-os/libcosmic/", branch = "master", default-features = false, features = ["tokio", "wayland", "applet"] }
89
serde = { version = "1.0", features = ["derive"] }
910
serde_json = "1.0"
Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
use cosmic::{
2+
iced::{Length, Point, Rectangle},
3+
iced_native::{
4+
clipboard::Clipboard,
5+
event::{self, Event},
6+
layout::{Layout, Limits, Node},
7+
mouse,
8+
renderer::Style,
9+
touch,
10+
widget::{self, operation::Operation, Tree, Widget},
11+
Shell,
12+
},
13+
};
14+
15+
use crate::protocol::ClickEvent;
16+
17+
const BTN_LEFT: u32 = 0x110;
18+
const BTN_RIGHT: u32 = 0x111;
19+
const BTN_MIDDLE: u32 = 0x112;
20+
21+
/// Wraps a `Row` widget, handling mouse input
22+
pub struct BarWidget<'a, Msg> {
23+
pub row: widget::Row<'a, Msg, cosmic::Renderer>,
24+
pub name_instance: Vec<(Option<&'a str>, Option<&'a str>)>,
25+
pub on_press: fn(ClickEvent) -> Msg,
26+
}
27+
28+
impl<'a, Msg> Widget<Msg, cosmic::Renderer> for BarWidget<'a, Msg> {
29+
delegate::delegate! {
30+
to self.row {
31+
fn children(&self) -> Vec<Tree>;
32+
fn diff(&self, tree: &mut Tree);
33+
fn layout(&self, renderer: &cosmic::Renderer, limits: &Limits) -> Node;
34+
fn operate(
35+
&self,
36+
tree: &mut Tree,
37+
layout: Layout<'_>,
38+
operation: &mut dyn Operation<Msg>,
39+
);
40+
fn draw(
41+
&self,
42+
state: &Tree,
43+
renderer: &mut cosmic::Renderer,
44+
theme: &cosmic::Theme,
45+
style: &Style,
46+
layout: Layout,
47+
cursor_position: Point,
48+
viewport: &Rectangle,
49+
);
50+
}
51+
}
52+
53+
fn width(&self) -> Length {
54+
Widget::width(&self.row)
55+
}
56+
57+
fn height(&self) -> Length {
58+
Widget::height(&self.row)
59+
}
60+
61+
fn on_event(
62+
&mut self,
63+
tree: &mut Tree,
64+
event: Event,
65+
layout: Layout<'_>,
66+
cursor_position: Point,
67+
renderer: &cosmic::Renderer,
68+
clipboard: &mut dyn Clipboard,
69+
shell: &mut Shell<'_, Msg>,
70+
) -> event::Status {
71+
if self.update(&event, layout, cursor_position, shell) == event::Status::Captured {
72+
return event::Status::Captured;
73+
}
74+
self.row.on_event(
75+
tree,
76+
event,
77+
layout,
78+
cursor_position,
79+
renderer,
80+
clipboard,
81+
shell,
82+
)
83+
}
84+
}
85+
86+
impl<'a, Msg> From<BarWidget<'a, Msg>> for cosmic::Element<'a, Msg>
87+
where
88+
Msg: 'a,
89+
{
90+
fn from(widget: BarWidget<'a, Msg>) -> cosmic::Element<'a, Msg> {
91+
cosmic::Element::new(widget)
92+
}
93+
}
94+
95+
impl<'a, Msg> BarWidget<'a, Msg> {
96+
fn update(
97+
&mut self,
98+
event: &Event,
99+
layout: Layout<'_>,
100+
cursor_position: Point,
101+
shell: &mut Shell<'_, Msg>,
102+
) -> event::Status {
103+
let (button, event_code) = match event {
104+
Event::Mouse(mouse::Event::ButtonPressed(mouse::Button::Left)) => (1, BTN_LEFT),
105+
Event::Mouse(mouse::Event::ButtonPressed(mouse::Button::Middle)) => (2, BTN_MIDDLE),
106+
Event::Mouse(mouse::Event::ButtonPressed(mouse::Button::Right)) => (3, BTN_RIGHT),
107+
Event::Touch(touch::Event::FingerPressed { .. }) => (1, BTN_LEFT),
108+
_ => {
109+
return event::Status::Ignored;
110+
}
111+
};
112+
113+
let Some((n, bounds)) = layout.children().map(|x| x.bounds()).enumerate().find(|(_, bounds)| bounds.contains(cursor_position)) else {
114+
return event::Status::Ignored;
115+
};
116+
117+
let (name, instance) = self.name_instance.get(n).cloned().unwrap_or((None, None));
118+
119+
// TODO coordinate space? int conversion?
120+
let x = cursor_position.x as u32;
121+
let y = cursor_position.y as u32;
122+
let relative_x = (cursor_position.x - bounds.x) as u32;
123+
let relative_y = (cursor_position.y - bounds.y) as u32;
124+
let width = bounds.width as u32;
125+
let height = bounds.height as u32;
126+
127+
shell.publish((self.on_press)(ClickEvent {
128+
name: name.map(str::to_owned),
129+
instance: instance.map(str::to_owned),
130+
x,
131+
y,
132+
button,
133+
event: event_code,
134+
relative_x,
135+
relative_y,
136+
width,
137+
height,
138+
}));
139+
140+
event::Status::Captured
141+
}
142+
}

cosmic-applet-status-line/src/main.rs

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,14 @@ use cosmic::{
88
iced_style::application,
99
};
1010

11+
mod bar_widget;
12+
use bar_widget::BarWidget;
1113
mod protocol;
1214

1315
#[derive(Debug)]
1416
enum Msg {
1517
Protocol(protocol::StatusLine),
18+
ClickEvent(protocol::ClickEvent),
1619
CloseRequest,
1720
}
1821

@@ -56,13 +59,35 @@ impl iced::Application for App {
5659
println!("{:?}", status_line);
5760
self.status_line = status_line;
5861
}
62+
Msg::ClickEvent(click_event) => {
63+
println!("{:?}", click_event);
64+
if self.status_line.click_events {
65+
// TODO: pass click event to backend
66+
}
67+
}
5968
Msg::CloseRequest => {}
6069
}
6170
iced::Command::none()
6271
}
6372

6473
fn view(&self, _id: window::Id) -> cosmic::Element<Msg> {
65-
iced::widget::row(self.status_line.blocks.iter().map(block_view).collect()).into()
74+
let (block_views, name_instance): (Vec<_>, Vec<_>) = self
75+
.status_line
76+
.blocks
77+
.iter()
78+
.map(|block| {
79+
(
80+
block_view(block),
81+
(block.name.as_deref(), block.instance.as_deref()),
82+
)
83+
})
84+
.unzip();
85+
BarWidget {
86+
row: iced::widget::row(block_views),
87+
name_instance,
88+
on_press: Msg::ClickEvent,
89+
}
90+
.into()
6691
}
6792
}
6893

cosmic-applet-status-line/src/protocol/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@ use std::{
1010
use tokio::sync::mpsc;
1111

1212
mod serialization;
13-
pub use serialization::Block;
1413
use serialization::Header;
14+
pub use serialization::{Block, ClickEvent};
1515

1616
#[derive(Debug, Default)]
1717
pub struct StatusLine {

cosmic-applet-status-line/src/protocol/serialization.rs

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -128,15 +128,15 @@ pub struct Block {
128128
}
129129

130130
#[derive(Clone, Debug, serde::Serialize)]
131-
struct ClickEvent {
132-
name: Option<String>,
133-
instance: Option<String>,
134-
x: u32,
135-
y: u32,
136-
button: u32,
137-
event: u32,
138-
relative_x: u32,
139-
relative_y: u32,
140-
width: u32,
141-
height: u32,
131+
pub struct ClickEvent {
132+
pub name: Option<String>,
133+
pub instance: Option<String>,
134+
pub x: u32,
135+
pub y: u32,
136+
pub button: u32,
137+
pub event: u32,
138+
pub relative_x: u32,
139+
pub relative_y: u32,
140+
pub width: u32,
141+
pub height: u32,
142142
}

0 commit comments

Comments
 (0)