import Toybox.Application; import Toybox.Graphics; import Toybox.Lang; import Toybox.Math; import Toybox.WatchUi; // Rotating 10-icon ring modelled after the watch Controls menu. // Selection point is fixed at the 3 o'clock position (START/STOP // button height). UP/DOWN input rotates the ring. class MenuView extends WatchUi.View { const STORAGE_KEY = "menu_idx"; private var _items as Array; private var _selectedIndex as Number = 0; private var _bitmaps as Dictionary = {}; function initialize() { View.initialize(); _items = Config.menuItems(); var stored = Application.Storage.getValue(STORAGE_KEY); if (stored instanceof Number && stored >= 0 && stored < _items.size()) { _selectedIndex = stored; } } function onLayout(dc as Dc) as Void { for (var i = 0; i < _items.size(); i++) { var iconId = _items[i][:icon]; _bitmaps[iconId] = WatchUi.loadResource(iconId) as BitmapResource; } } function rotateNext() as Void { _selectedIndex = (_selectedIndex + 1) % _items.size(); Application.Storage.setValue(STORAGE_KEY, _selectedIndex); WatchUi.requestUpdate(); } function rotatePrev() as Void { _selectedIndex = (_selectedIndex - 1 + _items.size()) % _items.size(); Application.Storage.setValue(STORAGE_KEY, _selectedIndex); WatchUi.requestUpdate(); } function selectedItem() as Dictionary { return _items[_selectedIndex]; } function onUpdate(dc as Dc) as Void { dc.setColor(Config.COLOR_FG, Config.COLOR_BG); dc.clear(); var cx = LayoutMetrics.centerX(dc); var cy = LayoutMetrics.centerY(dc); var radius = LayoutMetrics.ringRadius(dc); var baseSize = LayoutMetrics.iconSize(dc); var selSize = LayoutMetrics.selectedIconSize(dc); var n = _items.size(); var selectionAngle = Config.SELECTION_ANGLE_DEG * Math.PI / 180.0; for (var i = 0; i < n; i++) { var offset = i - _selectedIndex; var angle = selectionAngle + (2.0 * Math.PI * offset) / n; var x = (cx + radius * Math.cos(angle)).toNumber(); var y = (cy + radius * Math.sin(angle)).toNumber(); var isSelected = (i == _selectedIndex); var targetSize = isSelected ? selSize : baseSize; var iconId = _items[i][:icon]; var bmp = _bitmaps[iconId] as BitmapResource; if (bmp != null) { _drawScaledIcon(dc, bmp, x, y, targetSize); } if (isSelected) { dc.setPenWidth(LayoutMetrics.accentPenWidth(dc)); dc.setColor(Config.COLOR_ACCENT, Config.COLOR_BG); dc.drawCircle(x, y, targetSize / 2 + 5); } } var lines = _items[_selectedIndex][:lines] as Array; dc.setColor(Config.COLOR_FG, Config.COLOR_BG); TextUtils.drawCentered(dc, lines, cx, cy, Graphics.FONT_TINY); } // Scales a bitmap to the requested pixel size and draws it centered // at (cx, cy). Uses drawBitmap2 so icons stay crisp on any resolution. private function _drawScaledIcon(dc as Dc, bmp as BitmapResource, cx as Number, cy as Number, targetSize as Number) as Void { var bmpW = bmp.getWidth(); var scale = targetSize.toFloat() / bmpW.toFloat(); dc.drawBitmap2( cx - targetSize / 2, cy - targetSize / 2, bmp, { :scaleX => scale, :scaleY => scale } ); } }