import Toybox.Lang; import Toybox.Graphics; import Toybox.WatchUi; import Layout; // The glyphs that sit above the two top data slots, plus the battery and the // bluetooth rune. // // The comps contain three icons -- sunrise, weather, battery. The first two // are traced outlines whose finest features are two or three design pixels // across; rebuilding them from circles and lines looked right at 454 px and // turned to mush at 280. They ship instead as bitmaps rasterised from the // design paths once per screen width (tools/gen_icons.py) and are tinted with // the theme's accent at draw time. // // Everything else -- steps, calories, stairs, heart -- has no counterpart in // the comps, so those stay as primitives sized off the same design canvas. module Icons { var mSunrise = null; var mSunset = null; var mWeather = null; function load() as Void { mSunrise = WatchUi.loadResource(Rez.Drawables.IconSunrise); mSunset = WatchUi.loadResource(Rez.Drawables.IconSunset); mWeather = WatchUi.loadResource(Rez.Drawables.IconWeather); } function ready() as Boolean { return mSunrise != null; } // drawBitmap2 refuses a palettised source, which is why the generated // drawables carry packingFormat="png" to keep their alpha channel. function blit(dc as Graphics.Dc, bmp, cxDesign as Numeric, col as Number) as Void { if (bmp == null) { return; } dc.drawBitmap2(Layout.px(cxDesign) - bmp.getWidth() / 2, Layout.px(Layout.ICON_CY) - bmp.getHeight() / 2, bmp, {:tintColor => col}); } // Outline, charge bar and terminal. The bar tracks the real level, the // way the comp draws it at 40%. function battery(dc as Graphics.Dc, x as Numeric, cyDesign as Numeric, k as Float, col as Number, level as Float) as Void { var x0 = Layout.px(x); var y0 = Layout.px(cyDesign - Layout.BATT_H * k / 2); var w = Layout.px(Layout.BATT_W * k); var h = Layout.px(Layout.BATT_H * k); var wall = Layout.px(Layout.BATT_WALL * k); dc.setColor(col, Graphics.COLOR_TRANSPARENT); dc.fillRoundedRectangle(x0, y0, w, h, Layout.px(3.4 * k)); dc.fillRectangle(x0 + w, Layout.px(cyDesign - Layout.BATT_TH * k / 2), Layout.px(Layout.BATT_TW * k), Layout.px(Layout.BATT_TH * k)); var iw = w - 2 * wall; var ih = h - 2 * wall; dc.setColor(Graphics.COLOR_BLACK, Graphics.COLOR_TRANSPARENT); dc.fillRectangle(x0 + wall, y0 + wall, iw, ih); var fill = (iw * level).toNumber(); if (fill > 0) { dc.setColor(col, Graphics.COLOR_TRANSPARENT); dc.fillRectangle(x0 + wall, y0 + wall, fill, ih); } } // The standard bluetooth rune, drawn as one polyline. function bluetooth(dc as Graphics.Dc, col as Number) as Void { dc.setColor(col, Graphics.COLOR_TRANSPARENT); dc.setPenWidth(Layout.pen(3.2)); var l = Layout.BT_CX - Layout.BT_HW; var r = Layout.BT_CX + Layout.BT_HW; var t = Layout.BT_CY - Layout.BT_HH; var b = Layout.BT_CY + Layout.BT_HH; var qt = Layout.BT_CY - Layout.BT_HH / 2; var qb = Layout.BT_CY + Layout.BT_HH / 2; Layout.line(dc, l, qt, r, qb); Layout.line(dc, r, qb, Layout.BT_CX, b); Layout.line(dc, Layout.BT_CX, b, Layout.BT_CX, t); Layout.line(dc, Layout.BT_CX, t, r, qt); Layout.line(dc, r, qt, l, qb); } // Which glyph, if any, belongs above a given field id. Fields with no // natural icon -- dates, week numbers, custom text -- read fine bare. function forField(dc as Graphics.Dc, id as Number, xDesign as Numeric, col as Number, level as Float) as Void { if (id == 712 || id == 700) { blit(dc, mSunrise, xDesign, col); return; } if (id == 717 || id == 731) { blit(dc, mSunset, xDesign, col); return; } if (id == 306 || id == 639 || id == 300 || id == 301 || id == 302 || id == 304 || id == 305 || id == 307 || id == 308 || id == 309 || id == 310) { blit(dc, mWeather, xDesign, col); return; } if (id == 250 || id == 251 || id == 257) { battery(dc, xDesign - 14.4, Layout.ICON_CY, 1.0, col, level); return; } var r = 13.0; var cyd = Layout.ICON_CY; dc.setColor(col, Graphics.COLOR_TRANSPARENT); dc.setPenWidth(Layout.pen(3.0)); if (id == 2 || id == 603) { // calories: flame dc.fillPolygon([[Layout.px(xDesign), Layout.px(cyd - r)], [Layout.px(xDesign + r * 0.72), Layout.px(cyd + r * 0.25)], [Layout.px(xDesign + r * 0.40), Layout.px(cyd + r * 0.85)], [Layout.px(xDesign - r * 0.40), Layout.px(cyd + r * 0.85)], [Layout.px(xDesign - r * 0.72), Layout.px(cyd + r * 0.25)]]); } else if (id == 1 || id == 14 || id == 707) { // steps: two prints dc.fillRoundedRectangle(Layout.px(xDesign - r * 0.85), Layout.px(cyd - r * 0.75), Layout.px(r * 0.62), Layout.px(r * 1.15), Layout.px(r * 0.3)); dc.fillRoundedRectangle(Layout.px(xDesign + r * 0.22), Layout.px(cyd - r * 0.35), Layout.px(r * 0.62), Layout.px(r * 1.15), Layout.px(r * 0.3)); } else if (id == 3 || id == 9 || id == 615) { // distance: arrow dc.fillPolygon([[Layout.px(xDesign), Layout.px(cyd - r)], [Layout.px(xDesign + r * 0.75), Layout.px(cyd + r * 0.8)], [Layout.px(xDesign), Layout.px(cyd + r * 0.35)], [Layout.px(xDesign - r * 0.75), Layout.px(cyd + r * 0.8)]]); } else if (id == 618 || id == 276 || id == 623) { // heart dc.fillCircle(Layout.px(xDesign - r * 0.38), Layout.px(cyd - r * 0.28), Layout.px(r * 0.44)); dc.fillCircle(Layout.px(xDesign + r * 0.38), Layout.px(cyd - r * 0.28), Layout.px(r * 0.44)); dc.fillPolygon([[Layout.px(xDesign - r * 0.78), Layout.px(cyd - r * 0.12)], [Layout.px(xDesign + r * 0.78), Layout.px(cyd - r * 0.12)], [Layout.px(xDesign), Layout.px(cyd + r * 0.85)]]); } else if (id == 4 || id == 5 || id == 6) { // floors: stairs for (var i = 0; i < 3; i++) { dc.fillRectangle(Layout.px(xDesign - r * 0.85 + r * 0.58 * i), Layout.px(cyd + r * 0.6 - r * 0.55 * i), Layout.px(r * 0.62), Layout.px(r * 0.4)); } } } }