diff --git a/program/MainWindow.cs b/program/MainWindow.cs index d7c98a1..2f91720 100644 --- a/program/MainWindow.cs +++ b/program/MainWindow.cs @@ -29,8 +29,7 @@ [UI] private Image ConnectionIcon = null; // was GtkIconView in the old glade [UI] private Label ConnectionAlertLabel = null; - [UI] private Image BatteryIcon = null; - [UI] private Label BatteryLabel = null; + [UI] private DrawingArea BatteryArea = null; private uint _retryTimerId; @@ -59,6 +58,7 @@ internal SoundWindow _soundWindow; internal MapWindow _mapWindow; // Battery + private BatteryStatus _battery = new BatteryStatus(); private uint _batteryTimerId; private const uint BatteryPollMs = 10000; @@ -134,8 +134,8 @@ _Language.Register("LanguageLabel", LanguageLabel); _Language.Register("LanguageToggle", LanguageToggle); _Language.RegisterDynamic("ConnectionIcon", ConnectionIcon); - _Language.RegisterDynamic("BatteryIcon", BatteryIcon); - _Language.RegisterDynamic("BatteryLabel", BatteryLabel); + _Language.RegisterDynamic("BatteryArea", BatteryArea); + if (BatteryArea != null) BatteryArea.Drawn += OnBatteryDrawn; ConnectionAlertLabel.Name = "ConnectionAlertLabel"; _Language.Register("ConnectionAlertLabel", ConnectionAlertLabel); @@ -292,34 +292,141 @@ private void UpdateBattery() { - if (BatteryIcon == null) return; + if (BatteryArea == null) return; - BatteryStatus b = BatteryMonitor.Read(); + _battery = BatteryMonitor.Read(); - if (!b.Present) // desktop / dev machine — hide it entirely + if (!_battery.Present) // desktop / dev machine — hide it entirely { - BatteryIcon.Visible = false; - if (BatteryLabel != null) BatteryLabel.Visible = false; + BatteryArea.Visible = false; return; } - BatteryIcon.Visible = true; - BatteryIcon.SetFromIconName(PickBatteryIcon(b), IconSize.Dnd); + string key = _battery.Full ? "BatteryIcon.Full" + : _battery.Charging ? "BatteryIcon.Charging" + : "BatteryIcon.Discharging"; - string key = b.Full ? "BatteryIcon.Full" - : b.Charging ? "BatteryIcon.Charging" - : "BatteryIcon.Discharging"; - BatteryIcon.TooltipText = _Language.Format(key, b.Percent); + BatteryArea.Visible = true; + BatteryArea.TooltipText = _Language.Format(key, _battery.Percent); + BatteryArea.QueueDraw(); + } + + private void OnBatteryDrawn(object o, DrawnArgs args) + { + DrawingArea area = (DrawingArea)o; + Cairo.Context cr = args.Cr; - if (BatteryLabel != null) + double w = area.AllocatedWidth; + double h = area.AllocatedHeight; + + Gdk.RGBA fg = area.StyleContext.GetColor(StateFlags.Normal); + + double stroke = Math.Max(1.5, h * 0.07); + double nub = Math.Max(2.0, w * 0.055); + double gap = Math.Max(1.0, w * 0.02); + + double bw = w - nub - gap - stroke; + double bh = Math.Min(h - stroke, bw * 0.52); + double bx = stroke / 2; + double by = (h - bh) / 2; + double r = bh * 0.20; + + // shell + cr.LineWidth = stroke; + cr.SetSourceRGBA(fg.Red, fg.Green, fg.Blue, fg.Alpha); + RoundedRect(cr, bx, by, bw, bh, r); + cr.Stroke(); + + // terminal + double th = bh * 0.42; + cr.Rectangle(bx + bw + gap, (h - th) / 2, nub, th); + cr.Fill(); + + // level fill + double pad = stroke * 1.4; + double ix = bx + pad, iy = by + pad; + double iw = bw - 2 * pad, ih = bh - 2 * pad; + double pct = Math.Max(0, Math.Min(100, _battery.Percent)); + double fillW = iw * (pct / 100.0); + + if (fillW > 0.5) { - BatteryLabel.Visible = true; - BatteryLabel.Text = b.Percent.ToString(CultureInfo.InvariantCulture) + "%"; + double fr, fgc, fb; + if (!_battery.Charging && pct <= 10) { fr = 0.78; fgc = 0.16; fb = 0.16; } + else if (!_battery.Charging && pct <= 25) { fr = 0.93; fgc = 0.62; fb = 0.09; } + else { fr = 0.18; fgc = 0.65; fb = 0.31; } - var ctx = BatteryLabel.StyleContext; - if (b.Percent <= 15 && !b.Charging) ctx.AddClass("battery-low"); - else ctx.RemoveClass("battery-low"); + cr.Save(); + RoundedRect(cr, ix, iy, iw, ih, Math.Max(0, r - pad * 0.5)); + cr.Clip(); + cr.NewPath(); + cr.Rectangle(ix, iy, fillW, ih); + cr.SetSourceRGB(fr, fgc, fb); + cr.Fill(); + cr.Restore(); } + + // contents: optional charging bolt + the number + string text = _battery.Present + ? _battery.Percent.ToString(CultureInfo.InvariantCulture) + : "--"; + + cr.SelectFontFace("Sans", Cairo.FontSlant.Normal, Cairo.FontWeight.Bold); + cr.SetFontSize(bh * 0.60); + Cairo.TextExtents te = cr.TextExtents(text); + + double boltW = _battery.Charging ? bh * 0.36 : 0; + double boltG = _battery.Charging ? bh * 0.14 : 0; + double startX = bx + (bw - (boltW + boltG + te.Width)) / 2; + double tx = startX + boltW + boltG - te.XBearing; + double ty = by + (bh - te.Height) / 2 - te.YBearing; + + System.Action paint = () => + { + if (_battery.Charging) + DrawBolt(cr, startX, by + bh * 0.16, boltW, bh * 0.68); + cr.MoveTo(tx, ty); + cr.ShowText(text); + }; + + cr.Save(); // over the fill -> light + cr.Rectangle(ix, 0, fillW, h); + cr.Clip(); + cr.SetSourceRGB(1, 1, 1); + paint(); + cr.Restore(); + + cr.Save(); // over the empty part -> theme fg + cr.Rectangle(ix + fillW, 0, w, h); + cr.Clip(); + cr.SetSourceRGBA(fg.Red, fg.Green, fg.Blue, fg.Alpha); + paint(); + cr.Restore(); + } + + private static void RoundedRect(Cairo.Context cr, double x, double y, + double w, double h, double r) + { + cr.NewPath(); + cr.Arc(x + w - r, y + r, r, -Math.PI / 2, 0); + cr.Arc(x + w - r, y + h - r, r, 0, Math.PI / 2); + cr.Arc(x + r, y + h - r, r, Math.PI / 2, Math.PI); + cr.Arc(x + r, y + r, r, Math.PI, 3 * Math.PI / 2); + cr.ClosePath(); + } + + private static void DrawBolt(Cairo.Context cr, double x, double y, + double w, double h) + { + cr.NewPath(); + cr.MoveTo(x + w * 0.58, y); + cr.LineTo(x, y + h * 0.58); + cr.LineTo(x + w * 0.42, y + h * 0.58); + cr.LineTo(x + w * 0.32, y + h); + cr.LineTo(x + w, y + h * 0.40); + cr.LineTo(x + w * 0.56, y + h * 0.40); + cr.ClosePath(); + cr.Fill(); } private static string PickBatteryIcon(BatteryStatus b) diff --git a/program/homepageallv7.glade b/program/homepageallv7.glade index 5fafdb1..f97663a 100644 --- a/program/homepageallv7.glade +++ b/program/homepageallv7.glade @@ -81,32 +81,21 @@ 4 center - - True - False - battery-missing - 6 - center - - - False - False - 0 - - - - - True - False - center - --% - - - False - False - 1 - - + + True + False + center + 12 + 70 + 34 + True + + + False + False + 3 + + False diff --git a/program/touch_friendly.css b/program/touch_friendly.css index 207a7d8..0c4851a 100644 --- a/program/touch_friendly.css +++ b/program/touch_friendly.css @@ -208,4 +208,6 @@ background-color: #C62828; padding: 10px 24px; margin: 8px 40px; -} \ No newline at end of file +} +/* #BatteryLabel { margin-left: 4px; } */ +#BatteryLabel.battery-low { color: #c62828; font-weight: bold; } \ No newline at end of file