fix(time): use autosized surface for correct sizing of time widget and add support for Left/Right anchors
This commit is contained in:
parent
0fee545797
commit
a4ea05d718
1 changed files with 102 additions and 22 deletions
|
|
@ -1,24 +1,40 @@
|
||||||
use cosmic::applet::CosmicAppletHelper;
|
use cosmic::applet::{cosmic_panel_config::PanelAnchor, CosmicAppletHelper};
|
||||||
use cosmic::iced::wayland::{
|
use cosmic::iced::wayland::{
|
||||||
popup::{destroy_popup, get_popup},
|
popup::{destroy_popup, get_popup},
|
||||||
SurfaceIdWrapper,
|
SurfaceIdWrapper,
|
||||||
};
|
};
|
||||||
use cosmic::iced::{
|
use cosmic::iced::{
|
||||||
time,
|
time,
|
||||||
widget::{button, column, text},
|
wayland::InitialSurface,
|
||||||
window, Alignment, Application, Color, Command, Length, Subscription,
|
widget::{button, column, text, vertical_space},
|
||||||
|
window, Alignment, Application, Color, Command, Length, Rectangle, Subscription,
|
||||||
};
|
};
|
||||||
|
use cosmic::iced_sctk::layout::Limits;
|
||||||
use cosmic::iced_style::application::{self, Appearance};
|
use cosmic::iced_style::application::{self, Appearance};
|
||||||
use cosmic::theme;
|
use cosmic::theme;
|
||||||
use cosmic::{Element, Theme};
|
use cosmic::{
|
||||||
|
widget::{icon, rectangle_tracker::*},
|
||||||
|
Element, Theme,
|
||||||
|
};
|
||||||
|
|
||||||
use chrono::{DateTime, Local, Timelike};
|
use chrono::{DateTime, Local, Timelike};
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
pub fn main() -> cosmic::iced::Result {
|
pub fn main() -> cosmic::iced::Result {
|
||||||
let mut helper = CosmicAppletHelper::default();
|
let helper = CosmicAppletHelper::default();
|
||||||
helper.window_size(120, 16);
|
let mut settings = helper.window_settings();
|
||||||
Time::run(helper.window_settings())
|
match &mut settings.initial_surface {
|
||||||
|
InitialSurface::XdgWindow(s) => {
|
||||||
|
s.iced_settings.min_size = Some((1, 1));
|
||||||
|
s.iced_settings.max_size = None;
|
||||||
|
s.autosize = true;
|
||||||
|
s.size_limits = Limits::NONE
|
||||||
|
.min_height(1)
|
||||||
|
.min_width(1);
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
};
|
||||||
|
Time::run(settings)
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Time {
|
struct Time {
|
||||||
|
|
@ -29,6 +45,8 @@ struct Time {
|
||||||
update_at: Every,
|
update_at: Every,
|
||||||
now: DateTime<Local>,
|
now: DateTime<Local>,
|
||||||
msg: String,
|
msg: String,
|
||||||
|
rectangle_tracker: Option<RectangleTracker<u32>>,
|
||||||
|
rectangle: Rectangle,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for Time {
|
impl Default for Time {
|
||||||
|
|
@ -41,6 +59,8 @@ impl Default for Time {
|
||||||
update_at: Every::Minute,
|
update_at: Every::Minute,
|
||||||
now: Local::now(),
|
now: Local::now(),
|
||||||
msg: String::new(),
|
msg: String::new(),
|
||||||
|
rectangle_tracker: None,
|
||||||
|
rectangle: Rectangle::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -57,6 +77,7 @@ enum Message {
|
||||||
TogglePopup,
|
TogglePopup,
|
||||||
Tick,
|
Tick,
|
||||||
Ignore,
|
Ignore,
|
||||||
|
Rectangle(RectangleUpdate<u32>),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Application for Time {
|
impl Application for Time {
|
||||||
|
|
@ -103,10 +124,13 @@ impl Application for Time {
|
||||||
.with_nanosecond(0)
|
.with_nanosecond(0)
|
||||||
.expect("Setting nanoseconds to 0 should always be possible.");
|
.expect("Setting nanoseconds to 0 should always be possible.");
|
||||||
let wait = 1.max((next - now).num_milliseconds());
|
let wait = 1.max((next - now).num_milliseconds());
|
||||||
time::every(Duration::from_millis(
|
Subscription::batch(vec![
|
||||||
wait.try_into().unwrap_or(FALLBACK_DELAY),
|
rectangle_tracker_subscription(0).map(|(_, update)| Message::Rectangle(update)),
|
||||||
))
|
time::every(Duration::from_millis(
|
||||||
.map(|_| Message::Tick)
|
wait.try_into().unwrap_or(FALLBACK_DELAY),
|
||||||
|
))
|
||||||
|
.map(|_| Message::Tick),
|
||||||
|
])
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update(&mut self, message: Message) -> Command<Message> {
|
fn update(&mut self, message: Message) -> Command<Message> {
|
||||||
|
|
@ -133,13 +157,25 @@ impl Application for Time {
|
||||||
let new_id = window::Id::new(self.id_ctr);
|
let new_id = window::Id::new(self.id_ctr);
|
||||||
self.popup.replace(new_id);
|
self.popup.replace(new_id);
|
||||||
|
|
||||||
let popup_settings = self.applet_helper.get_popup_settings(
|
let mut popup_settings = self.applet_helper.get_popup_settings(
|
||||||
window::Id::new(0),
|
window::Id::new(0),
|
||||||
new_id,
|
new_id,
|
||||||
None,
|
None,
|
||||||
Some(60),
|
None,
|
||||||
None,
|
None,
|
||||||
);
|
);
|
||||||
|
let Rectangle {
|
||||||
|
x,
|
||||||
|
y,
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
} = self.rectangle;
|
||||||
|
popup_settings.positioner.anchor_rect = Rectangle::<i32> {
|
||||||
|
x: x as i32,
|
||||||
|
y: y as i32,
|
||||||
|
width: width as i32,
|
||||||
|
height: height as i32,
|
||||||
|
};
|
||||||
get_popup(popup_settings)
|
get_popup(popup_settings)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -148,21 +184,65 @@ impl Application for Time {
|
||||||
Command::none()
|
Command::none()
|
||||||
}
|
}
|
||||||
Message::Ignore => Command::none(),
|
Message::Ignore => Command::none(),
|
||||||
|
Message::Rectangle(u) => {
|
||||||
|
match u {
|
||||||
|
RectangleUpdate::Rectangle(r) => {
|
||||||
|
self.rectangle = r.1;
|
||||||
|
}
|
||||||
|
RectangleUpdate::Init(tracker) => {
|
||||||
|
self.rectangle_tracker = Some(tracker);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Command::none()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn view(&self, id: SurfaceIdWrapper) -> Element<Message> {
|
fn view(&self, id: SurfaceIdWrapper) -> Element<Message> {
|
||||||
match id {
|
match id {
|
||||||
SurfaceIdWrapper::LayerSurface(_) => unimplemented!(),
|
SurfaceIdWrapper::LayerSurface(_) => unimplemented!(),
|
||||||
SurfaceIdWrapper::Window(_) => button(
|
SurfaceIdWrapper::Window(_) => {
|
||||||
column![text(self.now.format("%b %-d %-I:%M %p").to_string())]
|
let button = button(
|
||||||
.width(Length::Fill)
|
if matches!(
|
||||||
.align_items(Alignment::Center),
|
self.applet_helper.anchor,
|
||||||
)
|
PanelAnchor::Top | PanelAnchor::Bottom
|
||||||
.on_press(Message::TogglePopup)
|
) {
|
||||||
.style(theme::Button::Text)
|
column![text(self.now.format("%b %-d %-I:%M %p").to_string())]
|
||||||
.width(Length::Units(120))
|
} else {
|
||||||
.into(),
|
let mut date_time_col = column![
|
||||||
|
icon(
|
||||||
|
"emoji-recent-symbolic",
|
||||||
|
self.applet_helper.suggested_size().0
|
||||||
|
)
|
||||||
|
.style(theme::Svg::Symbolic),
|
||||||
|
text(self.now.format("%I").to_string()),
|
||||||
|
text(self.now.format("%M").to_string()),
|
||||||
|
text(self.now.format("%p").to_string()),
|
||||||
|
vertical_space(Length::Units(4)),
|
||||||
|
// TODO better calendar icon?
|
||||||
|
icon(
|
||||||
|
"calendar-go-today-symbolic",
|
||||||
|
self.applet_helper.suggested_size().0
|
||||||
|
)
|
||||||
|
.style(theme::Svg::Symbolic),
|
||||||
|
]
|
||||||
|
.align_items(Alignment::Center)
|
||||||
|
.spacing(4);
|
||||||
|
for d in self.now.format("%x").to_string().split("/") {
|
||||||
|
date_time_col = date_time_col.push(text(d.to_string()));
|
||||||
|
}
|
||||||
|
date_time_col
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.on_press(Message::TogglePopup)
|
||||||
|
.style(theme::Button::Text);
|
||||||
|
|
||||||
|
if let Some(tracker) = self.rectangle_tracker.as_ref() {
|
||||||
|
tracker.container(0, button).into()
|
||||||
|
} else {
|
||||||
|
button.into()
|
||||||
|
}
|
||||||
|
}
|
||||||
SurfaceIdWrapper::Popup(_) => {
|
SurfaceIdWrapper::Popup(_) => {
|
||||||
let content = column![]
|
let content = column![]
|
||||||
.align_items(Alignment::Start)
|
.align_items(Alignment::Start)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue