1use alloc::format;
15use alloc::string::String;
16
17use gfx::{Surface, FMT_PARGB};
18use plat::taskbar::{self, JumpTask, TaskbarProgress};
19use plat::tray::{self, TrayIcon};
20
21use super::cmd::Gfx;
22use super::consts::FONT_BOLD;
23use super::Ui;
24
25const BADGE_BG: u32 = 0xFFC4_2B1C;
27const BADGE_FG: u32 = 0xFFFF_FFFF;
28
29impl Ui {
30 pub fn taskbar_progress(&mut self, p: TaskbarProgress) -> bool {
32 tray::set_dry_run(self.headless);
33 taskbar::taskbar_progress(p)
34 }
35
36 pub fn taskbar_badge(&mut self, n: u32) -> bool {
38 tray::set_dry_run(self.headless);
39 if n != 0 && taskbar::taskbar_badge_shown(n) {
40 return true; }
42 let icon = if n == 0 { None } else { self.badge_icon(n) };
43 taskbar::taskbar_badge(n, icon.as_ref())
44 }
45
46 pub fn taskbar_tasks(&mut self, tasks: &[JumpTask]) -> bool {
48 tray::set_dry_run(self.headless);
49 taskbar::taskbar_tasks(tasks)
50 }
51
52 pub(crate) fn badge_icon(&mut self, n: u32) -> Option<TrayIcon> {
54 let side = ((16 * self.wp.rt.dpi.max(96) + 48) / 96).clamp(16, 64);
55 let label = if n > 99 { String::from("99+") } else { format!("{n}") };
56 let mut sf = Surface::new(side, side, FMT_PARGB);
57 if sf.px.is_empty() {
58 return None;
59 }
60 let saved = self.text.get_font();
61 self.dc.begin(&sf);
62 {
63 let mut g = Gfx { dc: &mut self.dc, sf: &mut sf, text: &mut self.text };
64 g.dc.set_color(BADGE_BG);
65 g.shapes().fill_circle_fx(side << 7, side << 7, side << 7);
66 let mut px = side * 3 / 4;
68 loop {
69 g.text.set_font(FONT_BOLD, px << 8);
70 if px <= 6 || g.text.width(&label) <= side - side / 4 {
71 break;
72 }
73 px -= 1;
74 }
75 let w = g.text.width(&label);
76 let (asc, desc) = (g.text.ascent(), g.text.descent());
77 let base = (side + asc - desc + 1) / 2;
78 g.dc.set_color(BADGE_FG);
79 g.text.draw(g.dc, g.sf, (side - w + 1) / 2, base, label.as_bytes());
80 }
81 self.dc.end();
82 self.text.set_font(saved.0, saved.1);
83 super::tray::icon_of(&sf)
84 }
85}