diff --git a/source/CourtRenderer.mc b/source/CourtRenderer.mc index 6e5d082..2f01452 100644 --- a/source/CourtRenderer.mc +++ b/source/CourtRenderer.mc @@ -5,26 +5,34 @@ import Toybox.Graphics; // in the given quadrant. Half-width HW and half-height HH keep it inside the // central band of the round screen. class CourtRenderer { - private const HW = 60; // half court width (px) - private const HH = 78; // half court height (px) - private const BALL_R = 6; + private const HW = 92; // half court width (px) + private const HH = 95; // half court height (px) + private const BALL_R = 7; + // bgColor fills the court surface (blue for now; a future settings screen + // will drive it via RulesConfig). public function draw(dc as Graphics.Dc, cx as Number, cy as Number, - quadrant as Number, showBall as Boolean) as Void { + quadrant as Number, showBall as Boolean, + bgColor as Number) as Void { var left = cx - HW; var top = cy - HH; + // Service line sits 3m from the back wall (7m from the net) on a 10m + // half, i.e. 0.7 of the way from the net to the back boundary. + var sl = (7 * HH) / 10; + + dc.setColor(bgColor, Graphics.COLOR_TRANSPARENT); + dc.fillRectangle(left, top, 2 * HW, 2 * HH); // court surface + dc.setColor(Graphics.COLOR_WHITE, Graphics.COLOR_TRANSPARENT); dc.setPenWidth(2); - dc.drawRectangle(left, top, 2 * HW, 2 * HH); // outer court - dc.drawLine(cx, top, cx, cy + HH); // center service line + dc.drawRectangle(left, top, 2 * HW, 2 * HH); // outer boundary + dc.drawLine(left, cy - sl, left + 2 * HW, cy - sl); // upper service line + dc.drawLine(left, cy + sl, left + 2 * HW, cy + sl); // lower service line + dc.drawLine(cx, cy - sl, cx, cy + sl); // center line (between service lines only) - dc.setPenWidth(1); - dc.drawLine(left, cy - HH / 2, left + 2 * HW, cy - HH / 2); // upper service line - dc.drawLine(left, cy + HH / 2, left + 2 * HW, cy + HH / 2); // lower service line - - dc.setPenWidth(3); - dc.drawLine(left, cy, left + 2 * HW, cy); // net + dc.setPenWidth(4); + dc.drawLine(left, cy, left + 2 * HW, cy); // net (boldest) if (showBall) { var pos = _ballPos(quadrant, cx, cy); @@ -35,7 +43,7 @@ class CourtRenderer { private function _ballPos(quadrant as Number, cx as Number, cy as Number) as Array { var dx = HW / 2; - var dy = HH / 2; + var dy = (17 * HH) / 20; // centered in the back zone, farthest from the net if (quadrant == QUAD_BOTTOM_RIGHT) { return [cx + dx, cy + dy]; } if (quadrant == QUAD_BOTTOM_LEFT) { return [cx - dx, cy + dy]; } if (quadrant == QUAD_UPPER_LEFT) { return [cx - dx, cy - dy]; } diff --git a/source/garmin-padelView.mc b/source/garmin-padelView.mc index e3856e8..8e7d90c 100644 --- a/source/garmin-padelView.mc +++ b/source/garmin-padelView.mc @@ -3,10 +3,12 @@ import Toybox.Graphics; import Toybox.WatchUi; import Toybox.System; import Toybox.Timer; +import Toybox.Math; class garmin_padelView extends WatchUi.View { private const ACCENT = 0x00E0A0; // padel green (sets/games) private const LABEL_COLOR = 0x808080; // muted grey (S/G/pts labels) + private const COURT_BLUE = 0x1560BD; // court surface fill (configurable later) private var _court as CourtRenderer; private var _timer as Timer.Timer; @@ -39,11 +41,11 @@ class garmin_padelView extends WatchUi.View { dc.setColor(Graphics.COLOR_WHITE, Graphics.COLOR_BLACK); dc.clear(); - _court.draw(dc, cx, cy, m.servingQuadrant(), !m.isMatchOver()); + _court.draw(dc, cx, cy, m.servingQuadrant(), !m.isMatchOver(), COURT_BLUE); _drawLeftColumn(dc, m); _drawRightColumn(dc, m, w); - _drawHeartRate(dc, cx, 40); - _drawTime(dc, cx, h - 44); + _drawHeartRate(dc, cx, cy); + _drawTime(dc, cx, h - 78); if (m.isMatchOver()) { _drawWinner(dc, cx, cy, m); @@ -52,11 +54,11 @@ class garmin_padelView extends WatchUi.View { // Left: S and G mini-columns, your team on top, opponents below. private function _drawLeftColumn(dc as Graphics.Dc, m as PadelMatch) as Void { - var sX = 24; - var gX = 60; - var labelY = 150; - var usY = 178; - var themY = 206; + var sX = 30; + var gX = 76; + var labelY = 148; + var usY = 184; + var themY = 240; dc.setColor(LABEL_COLOR, Graphics.COLOR_TRANSPARENT); dc.drawText(sX, labelY, Graphics.FONT_XTINY, "S", Graphics.TEXT_JUSTIFY_CENTER); @@ -65,58 +67,79 @@ class garmin_padelView extends WatchUi.View { dc.setColor(ACCENT, Graphics.COLOR_TRANSPARENT); dc.drawText(sX, usY, Graphics.FONT_TINY, m.sets(US).toString(), Graphics.TEXT_JUSTIFY_CENTER); dc.drawText(sX, themY, Graphics.FONT_TINY, m.sets(THEM).toString(), Graphics.TEXT_JUSTIFY_CENTER); + + dc.setColor(Graphics.COLOR_WHITE, Graphics.COLOR_TRANSPARENT); dc.drawText(gX, usY, Graphics.FONT_TINY, m.games(US).toString(), Graphics.TEXT_JUSTIFY_CENTER); dc.drawText(gX, themY, Graphics.FONT_TINY, m.games(THEM).toString(), Graphics.TEXT_JUSTIFY_CENTER); } - // Right: pts column, your team on top, opponents below. + // Right: Pts column, your team on top, opponents below. private function _drawRightColumn(dc as Graphics.Dc, m as PadelMatch, w as Number) as Void { - var pX = w - 42; - var labelY = 150; - var usY = 178; - var themY = 206; + var pX = w - 46; + var labelY = 148; + var usY = 184; + var themY = 240; dc.setColor(LABEL_COLOR, Graphics.COLOR_TRANSPARENT); - dc.drawText(pX, labelY, Graphics.FONT_XTINY, "pts", Graphics.TEXT_JUSTIFY_CENTER); + dc.drawText(pX, labelY, Graphics.FONT_XTINY, "Pts", Graphics.TEXT_JUSTIFY_CENTER); dc.setColor(Graphics.COLOR_WHITE, Graphics.COLOR_TRANSPARENT); dc.drawText(pX, usY, Graphics.FONT_TINY, m.pointLabel(US), Graphics.TEXT_JUSTIFY_CENTER); dc.drawText(pX, themY, Graphics.FONT_TINY, m.pointLabel(THEM), Graphics.TEXT_JUSTIFY_CENTER); } - private function _drawHeartRate(dc as Graphics.Dc, cx as Number, y as Number) as Void { + // Heart rate as a top arc gauge: 5 zone-colored segments (grey/blue/green/ + // orange/red), a white marker on the current zone, and the bpm number just + // below — mirroring the standard Garmin run-activity HR view. + private function _drawHeartRate(dc as Graphics.Dc, cx as Number, cy as Number) as Void { var hr = getApp().getHeartRate(); var bpm = hr.getHeartRate(); - var text = (bpm == null) ? "-- bpm" : bpm.toString() + " bpm"; - dc.setColor(Graphics.COLOR_RED, Graphics.COLOR_TRANSPARENT); - dc.drawText(cx, y, Graphics.FONT_TINY, text, Graphics.TEXT_JUSTIFY_CENTER); - _drawZoneBar(dc, cx, y + 26, hr.getZone()); + var zone = hr.getZone(); + var r = cx - 9; // arc radius, hugging the top bezel + + // 5 zone segments across the top (150deg .. 30deg, clockwise) + dc.setPenWidth(14); + for (var k = 0; k < 5; k += 1) { + var segStart = 150 - k * 24; + dc.setColor(_zoneColor(k + 1), Graphics.COLOR_TRANSPARENT); + dc.drawArc(cx, cy, r, Graphics.ARC_CLOCKWISE, segStart - 2, segStart - 22); + } + dc.setPenWidth(1); + + // marker on the current zone + if (zone >= 1 && zone <= 5) { + var mid = 150 - (zone - 1) * 24 - 12; + var rad = Math.toRadians(mid); + var mx = (cx + r * Math.cos(rad)).toNumber(); + var my = (cy - r * Math.sin(rad)).toNumber(); + dc.setColor(Graphics.COLOR_WHITE, Graphics.COLOR_TRANSPARENT); + dc.fillCircle(mx, my, 8); + dc.setColor(Graphics.COLOR_BLACK, Graphics.COLOR_TRANSPARENT); + dc.drawCircle(mx, my, 8); + } + + // exact rate, tucked just under the arc (dim placeholder when no reading, + // so it never reads as a court line) + var text = (bpm == null) ? "--" : bpm.toString(); + var col = (bpm == null) ? LABEL_COLOR : Graphics.COLOR_WHITE; + dc.setColor(col, Graphics.COLOR_TRANSPARENT); + dc.drawText(cx, cy - 178, Graphics.FONT_MEDIUM, text, Graphics.TEXT_JUSTIFY_CENTER); } - // 5-segment bar; segments up to the current zone are filled. - private function _drawZoneBar(dc as Graphics.Dc, cx as Number, y as Number, zone as Number) as Void { - var segW = 12; - var segH = 6; - var gap = 3; - var totalW = 5 * segW + 4 * gap; - var x = cx - totalW / 2; - for (var i = 1; i <= 5; i += 1) { - if (i <= zone) { - dc.setColor(ACCENT, Graphics.COLOR_TRANSPARENT); - dc.fillRectangle(x, y, segW, segH); - } else { - dc.setColor(LABEL_COLOR, Graphics.COLOR_TRANSPARENT); - dc.drawRectangle(x, y, segW, segH); - } - x += segW + gap; - } + // Garmin HR zone colors: 1 grey, 2 blue, 3 green, 4 orange, 5 red. + private function _zoneColor(z as Number) as Number { + if (z == 1) { return Graphics.COLOR_LT_GRAY; } + if (z == 2) { return Graphics.COLOR_BLUE; } + if (z == 3) { return Graphics.COLOR_GREEN; } + if (z == 4) { return Graphics.COLOR_ORANGE; } + return Graphics.COLOR_RED; } private function _drawTime(dc as Graphics.Dc, cx as Number, y as Number) as Void { var now = System.getClockTime(); var text = now.hour.format("%02d") + ":" + now.min.format("%02d"); dc.setColor(Graphics.COLOR_WHITE, Graphics.COLOR_TRANSPARENT); - dc.drawText(cx, y, Graphics.FONT_SMALL, text, Graphics.TEXT_JUSTIFY_CENTER); + dc.drawText(cx, y, Graphics.FONT_MEDIUM, text, Graphics.TEXT_JUSTIFY_CENTER); } private function _drawWinner(dc as Graphics.Dc, cx as Number, cy as Number, m as PadelMatch) as Void {