1
- use cosmic:: applet:: CosmicAppletHelper ;
1
+ use cosmic:: applet:: { cosmic_panel_config :: PanelAnchor , CosmicAppletHelper } ;
2
2
use cosmic:: iced:: wayland:: {
3
3
popup:: { destroy_popup, get_popup} ,
4
4
SurfaceIdWrapper ,
5
5
} ;
6
6
use cosmic:: iced:: {
7
7
time,
8
- widget:: { button, column, text} ,
9
- window, Alignment , Application , Color , Command , Length , Subscription ,
8
+ wayland:: InitialSurface ,
9
+ widget:: { button, column, text, vertical_space} ,
10
+ window, Alignment , Application , Color , Command , Length , Rectangle , Subscription ,
10
11
} ;
12
+ use cosmic:: iced_sctk:: layout:: Limits ;
11
13
use cosmic:: iced_style:: application:: { self , Appearance } ;
12
14
use cosmic:: theme;
13
- use cosmic:: { Element , Theme } ;
15
+ use cosmic:: {
16
+ widget:: { icon, rectangle_tracker:: * } ,
17
+ Element , Theme ,
18
+ } ;
14
19
15
20
use chrono:: { DateTime , Local , Timelike } ;
16
21
use std:: time:: Duration ;
17
22
18
23
pub fn main ( ) -> cosmic:: iced:: Result {
19
- let mut helper = CosmicAppletHelper :: default ( ) ;
20
- helper. window_size ( 120 , 16 ) ;
21
- Time :: run ( helper. window_settings ( ) )
24
+ let helper = CosmicAppletHelper :: default ( ) ;
25
+ let mut settings = helper. window_settings ( ) ;
26
+ match & mut settings. initial_surface {
27
+ InitialSurface :: XdgWindow ( s) => {
28
+ s. iced_settings . min_size = Some ( ( 1 , 1 ) ) ;
29
+ s. iced_settings . max_size = None ;
30
+ s. autosize = true ;
31
+ s. size_limits = Limits :: NONE
32
+ . min_height ( 1 )
33
+ . min_width ( 1 ) ;
34
+ }
35
+ _ => { }
36
+ } ;
37
+ Time :: run ( settings)
22
38
}
23
39
24
40
struct Time {
@@ -29,6 +45,8 @@ struct Time {
29
45
update_at : Every ,
30
46
now : DateTime < Local > ,
31
47
msg : String ,
48
+ rectangle_tracker : Option < RectangleTracker < u32 > > ,
49
+ rectangle : Rectangle ,
32
50
}
33
51
34
52
impl Default for Time {
@@ -41,6 +59,8 @@ impl Default for Time {
41
59
update_at : Every :: Minute ,
42
60
now : Local :: now ( ) ,
43
61
msg : String :: new ( ) ,
62
+ rectangle_tracker : None ,
63
+ rectangle : Rectangle :: default ( ) ,
44
64
}
45
65
}
46
66
}
@@ -57,6 +77,7 @@ enum Message {
57
77
TogglePopup ,
58
78
Tick ,
59
79
Ignore ,
80
+ Rectangle ( RectangleUpdate < u32 > ) ,
60
81
}
61
82
62
83
impl Application for Time {
@@ -103,10 +124,13 @@ impl Application for Time {
103
124
. with_nanosecond ( 0 )
104
125
. expect ( "Setting nanoseconds to 0 should always be possible." ) ;
105
126
let wait = 1 . max ( ( next - now) . num_milliseconds ( ) ) ;
106
- time:: every ( Duration :: from_millis (
107
- wait. try_into ( ) . unwrap_or ( FALLBACK_DELAY ) ,
108
- ) )
109
- . map ( |_| Message :: Tick )
127
+ Subscription :: batch ( vec ! [
128
+ rectangle_tracker_subscription( 0 ) . map( |( _, update) | Message :: Rectangle ( update) ) ,
129
+ time:: every( Duration :: from_millis(
130
+ wait. try_into( ) . unwrap_or( FALLBACK_DELAY ) ,
131
+ ) )
132
+ . map( |_| Message :: Tick ) ,
133
+ ] )
110
134
}
111
135
112
136
fn update ( & mut self , message : Message ) -> Command < Message > {
@@ -133,13 +157,25 @@ impl Application for Time {
133
157
let new_id = window:: Id :: new ( self . id_ctr ) ;
134
158
self . popup . replace ( new_id) ;
135
159
136
- let popup_settings = self . applet_helper . get_popup_settings (
160
+ let mut popup_settings = self . applet_helper . get_popup_settings (
137
161
window:: Id :: new ( 0 ) ,
138
162
new_id,
139
163
None ,
140
- Some ( 60 ) ,
164
+ None ,
141
165
None ,
142
166
) ;
167
+ let Rectangle {
168
+ x,
169
+ y,
170
+ width,
171
+ height,
172
+ } = self . rectangle ;
173
+ popup_settings. positioner . anchor_rect = Rectangle :: < i32 > {
174
+ x : x as i32 ,
175
+ y : y as i32 ,
176
+ width : width as i32 ,
177
+ height : height as i32 ,
178
+ } ;
143
179
get_popup ( popup_settings)
144
180
}
145
181
}
@@ -148,21 +184,65 @@ impl Application for Time {
148
184
Command :: none ( )
149
185
}
150
186
Message :: Ignore => Command :: none ( ) ,
187
+ Message :: Rectangle ( u) => {
188
+ match u {
189
+ RectangleUpdate :: Rectangle ( r) => {
190
+ self . rectangle = r. 1 ;
191
+ }
192
+ RectangleUpdate :: Init ( tracker) => {
193
+ self . rectangle_tracker = Some ( tracker) ;
194
+ }
195
+ }
196
+ Command :: none ( )
197
+ }
151
198
}
152
199
}
153
200
154
201
fn view ( & self , id : SurfaceIdWrapper ) -> Element < Message > {
155
202
match id {
156
203
SurfaceIdWrapper :: LayerSurface ( _) => unimplemented ! ( ) ,
157
- SurfaceIdWrapper :: Window ( _) => button (
158
- column ! [ text( self . now. format( "%b %-d %-I:%M %p" ) . to_string( ) ) ]
159
- . width ( Length :: Fill )
160
- . align_items ( Alignment :: Center ) ,
161
- )
162
- . on_press ( Message :: TogglePopup )
163
- . style ( theme:: Button :: Text )
164
- . width ( Length :: Units ( 120 ) )
165
- . into ( ) ,
204
+ SurfaceIdWrapper :: Window ( _) => {
205
+ let button = button (
206
+ if matches ! (
207
+ self . applet_helper. anchor,
208
+ PanelAnchor :: Top | PanelAnchor :: Bottom
209
+ ) {
210
+ column ! [ text( self . now. format( "%b %-d %-I:%M %p" ) . to_string( ) ) ]
211
+ } else {
212
+ let mut date_time_col = column ! [
213
+ icon(
214
+ "emoji-recent-symbolic" ,
215
+ self . applet_helper. suggested_size( ) . 0
216
+ )
217
+ . style( theme:: Svg :: Symbolic ) ,
218
+ text( self . now. format( "%I" ) . to_string( ) ) ,
219
+ text( self . now. format( "%M" ) . to_string( ) ) ,
220
+ text( self . now. format( "%p" ) . to_string( ) ) ,
221
+ vertical_space( Length :: Units ( 4 ) ) ,
222
+ // TODO better calendar icon?
223
+ icon(
224
+ "calendar-go-today-symbolic" ,
225
+ self . applet_helper. suggested_size( ) . 0
226
+ )
227
+ . style( theme:: Svg :: Symbolic ) ,
228
+ ]
229
+ . align_items ( Alignment :: Center )
230
+ . spacing ( 4 ) ;
231
+ for d in self . now . format ( "%x" ) . to_string ( ) . split ( "/" ) {
232
+ date_time_col = date_time_col. push ( text ( d. to_string ( ) ) ) ;
233
+ }
234
+ date_time_col
235
+ } ,
236
+ )
237
+ . on_press ( Message :: TogglePopup )
238
+ . style ( theme:: Button :: Text ) ;
239
+
240
+ if let Some ( tracker) = self . rectangle_tracker . as_ref ( ) {
241
+ tracker. container ( 0 , button) . into ( )
242
+ } else {
243
+ button. into ( )
244
+ }
245
+ }
166
246
SurfaceIdWrapper :: Popup ( _) => {
167
247
let content = column ! [ ]
168
248
. align_items ( Alignment :: Start )
0 commit comments