Files
fenix8v3-watchface/source/Fenix8V3View.mc
ericwyuan 696b728c78 收紧常亮模式:去掉进度环,时间日期压暗到 38%
按要求把常亮再砍一档。常亮下现在不画:整条日期带底色、整个进度环、
四个数据位与电池;保留的时间、冒号、日期由 55% 压暗到 38%。

实测(fenix847mm,取表盘内区):

                  点亮像素数    平均亮度(功耗代理)
    普通模式         27.6%          14.1%
    常亮(改前)      10.4%           3.0%
    常亮(改后)       9.7%           2.5%

两个口径的差别值得记一笔:「点亮像素数」把每个抗锯齿边缘像素都算成亮的,
对大号数字表盘天然不友好 —— 时间数字压到 38% 后白色仍有 ~97 亮度,照样计入。
AMOLED 的实际功耗更接近各子像素亮度之和,也就是「平均亮度」那一列。
两个口径现在都留了余量,38% 下时间和日期在模拟器里依然清晰可读。

LICENSE、UserProfile 的 try 保护、CHANGELOG 与版本号 1.1.0 已在上一个提交
22340b0 完成,本次只动常亮相关部分与对应文档。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-10 11:37:58 +08:00

454 lines
23 KiB
MonkeyC
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import Toybox.Graphics;
import Toybox.Lang;
import Toybox.Math;
import Toybox.ActivityMonitor;
import Toybox.SensorHistory;
import Toybox.System;
import Toybox.Time;
import Toybox.Time.Gregorian;
import Toybox.WatchUi;
import Themes;
import Fields;
import Layout;
import Icons;
import Settings;
import Comp;
// ============================================================================
// 表盘主体
// ----------------------------------------------------------------------------
// 负责:进度环、盖在环上的各个元素、以及 AMOLED 常亮时的简化版画面。
//
// 分工约定(改代码前先看清楚该动哪个文件):
// 位置尺寸 → Layout.mc
// 数据取值 → Fields.mc
// 配色 → Themes.mc自动生成
// 设置读取 → Settings.mc
// 图标 → Icons.mc
// 留在本文件里的只有「按什么顺序画」。
// ============================================================================
class Fenix8V3View extends WatchUi.WatchFace {
// 常亮显示状态。
// AMOLED 屏在息屏常亮时必须大幅减少点亮像素Garmin 上架审核会卡这一条,
// 而且不这么做既费电又有烧屏风险MIP 屏不受影响,照常全量绘制。
private var mSleeping = false;
private var mBurnIn = false;
function initialize() {
WatchFace.initialize();
}
// 进入低功耗息屏。AMOLED 机型从这一刻起改画简化版面。
function onEnterSleep() as Void {
mSleeping = true;
WatchUi.requestUpdate();
}
// 抬腕唤醒,恢复完整版面。
function onExitSleep() as Void {
mSleeping = false;
WatchUi.requestUpdate();
}
// 表盘加载时调一次;如果 onUpdate 发现缓存失效(分辨率变了,或资源还没
// 加载好)会再调一次。所有「一次性、开销大」的准备工作都放这里。
function onLayout(dc as Dc) as Void {
Layout.init(dc);
Fields.loadStrings();
Icons.load();
var ds = System.getDeviceSettings();
mBurnIn = (ds != null) && (ds has :requiresBurnInProtection)
&& ds.requiresBurnInProtection;
}
// ------------------------------- 进度环 -------------------------------
// 计算四段弧各自的进度0..1。
// ⚠️ 这里的 idx 是**进度环自己的一张短表**(见 Settings.ringTR 的注释),
// 和数据位那套 125 项的字段编号完全是两回事,别混。
function ringProgress(idx as Number, info as ActivityMonitor.Info?) as Float {
if (info == null) { return 0.0f; }
var p = 0.0f;
if (idx == 0) { // 步数:对每日目标
if (info.stepGoal != null && info.stepGoal > 0 && info.steps != null) {
p = info.steps.toFloat() / info.stepGoal.toFloat();
}
} else if (idx == 1) { // 卡路里:固定 2000 kcal 为满
if (info.calories != null) { p = info.calories.toFloat() / 2000.0f; }
} else if (idx == 2) { // 距离10 km 为满distance 单位是厘米)
if (info.distance != null) { p = info.distance.toFloat() / 1000000.0f; }
} else if (idx == 3) { // 楼层:对每日目标,取不到目标就按 10 层
if (info.floorsClimbed != null) {
var goal = (info.floorsClimbedGoal != null && info.floorsClimbedGoal > 0)
? info.floorsClimbedGoal.toFloat() : 10.0f;
p = info.floorsClimbed.toFloat() / goal;
}
} else if (idx == 5) { // 活动分钟:对**每周**目标
if ((info has :activeMinutesWeek) && info.activeMinutesWeek != null
&& (info has :activeMinutesWeekGoal)
&& info.activeMinutesWeekGoal != null
&& info.activeMinutesWeekGoal > 0) {
p = info.activeMinutesWeek.total.toFloat()
/ info.activeMinutesWeekGoal.toFloat();
}
} else if (idx == 6) { // 身体电量:本身就是 0..100
var bb = Fields.latest(SensorHistory.getBodyBatteryHistory({:period => 1}));
if (bb != null) { p = bb.toFloat() / 100.0; }
} else if (idx == 4) {
// ⚠️ 动动条是**整数等级**0..MOVE_BAR_LEVEL_MAX通常是 5
// 不是 0..1 的比例。初版直接当比例用结果等级≥1 就被钳成满环,
// 中间状态全丢了。
if (info.moveBarLevel != null) {
var span = (ActivityMonitor.MOVE_BAR_LEVEL_MAX
- ActivityMonitor.MOVE_BAR_LEVEL_MIN).toFloat();
if (span > 0) {
p = (info.moveBarLevel - ActivityMonitor.MOVE_BAR_LEVEL_MIN) / span;
}
}
}
if (p > 1.0f) { p = 1.0f; }
if (p < 0.0f) { p = 0.0f; }
return p;
}
// 画一根刻度:环形扇区,用四点多边形填充。
// 扇区两条弧边其实是曲线,但 3° 弧的弓高不到 0.1 像素,用直边完全够精确,
// 而 fillPolygon 比 drawArc 行为更确定(各机型的 drawArc 端点样式不一致)。
function tick(dc as Dc, ang as Float, hw as Float) as Void {
var a0 = ang - hw;
var a1 = ang + hw;
var ro = Layout.R_OUT * Layout.scale;
var ri = Layout.R_IN * Layout.scale;
dc.fillPolygon([[Layout.polarX(a0, ro), Layout.polarY(a0, ro)],
[Layout.polarX(a1, ro), Layout.polarY(a1, ro)],
[Layout.polarX(a1, ri), Layout.polarY(a1, ri)],
[Layout.polarX(a0, ri), Layout.polarY(a0, ri)]]);
}
// 通用画弧。点亮方向与设计稿一致:
// 两条顶弧:从 9 点 / 3 点那一端朝 12 点方向填充fromEnd=true
// 两条底弧:从 6 点朝两侧填充fromEnd=false
// mirror 用来把同一组角度镜像到左半边,这样左右弧共用一份角度表和配色表。
function arc(dc as Dc, ramp as Array<Number>, off as Number, lit as Number,
phase as Float, pitch as Float, hw as Float, n as Number,
base as Float, mirror as Boolean, fromEnd as Boolean) as Void {
for (var i = 0; i < n; i++) {
var a = phase + pitch * i;
var on = fromEnd ? (i >= n - lit) : (i < lit);
dc.setColor(on ? ramp[i] : off, Graphics.COLOR_TRANSPARENT);
tick(dc, base + (mirror ? -a : a), hw);
}
}
function drawRing(dc as Dc, ti as Number, pTR as Float, pTL as Float,
pBR as Float, pBL as Float) as Void {
// 四段弧共用两份配色表:两条顶弧用 RINGTOP两条底弧用 RINGBOTTOM。
// 左右弧靠 mirror 参数镜像,颜色按刻度下标取,所以左右对称位置同色。
var top = Themes.RINGTOP[ti] as Array<Number>;
var bot = Themes.RINGBOTTOM[ti] as Array<Number>;
var off = Themes.TICKOFF[ti] as Number;
arc(dc, top, off, (pTR * Layout.TOP_N).toNumber(), Layout.TOP_PH,
Layout.TOP_PITCH, Layout.TOP_HW, Layout.TOP_N, 0.0, false, true);
arc(dc, top, off, (pTL * Layout.TOP_N).toNumber(), Layout.TOP_PH,
Layout.TOP_PITCH, Layout.TOP_HW, Layout.TOP_N, 0.0, true, true);
arc(dc, bot, off, (pBL * Layout.BOT_N).toNumber(), Layout.BOT_PH,
Layout.BOT_PITCH, Layout.BOT_HW, Layout.BOT_N, 180.0, false, false);
arc(dc, bot, off, (pBR * Layout.BOT_N).toNumber(), Layout.BOT_PH,
Layout.BOT_PITCH, Layout.BOT_HW, Layout.BOT_N, 180.0, true, false);
// 四个锚点圆点,压在四段弧的接缝处。
dc.setColor(Themes.ANCHORDOT[ti] as Number, Graphics.COLOR_TRANSPARENT);
var r = Layout.px(Layout.DOT_R);
var rad = Layout.DOT_RAD * Layout.scale;
for (var i = 0; i < Layout.DOT_ANG.size(); i++) {
var a = Layout.DOT_ANG[i];
dc.fillCircle(Layout.polarX(a, rad), Layout.polarY(a, rad), r);
}
}
// ------------------------------- 各元素 -------------------------------
// 顶部中央:电池图标 + 百分比。
function drawBattery(dc as Dc, ti as Number, level as Float) as Void {
Icons.battery(dc, Layout.BATT_X, Layout.BATT_CY, 1.0,
Themes.ACCENT[ti] as Number, level);
Layout.text(dc, Layout.BATT_VX, Layout.BATT_CY, Layout.fontBand,
(level * 100.0).toNumber().format("%d") + "%",
Graphics.TEXT_JUSTIFY_LEFT, Themes.TEXTPRIMARY[ti] as Number);
}
// 顶部单个数据位:上方图标 + 下方数值。
// 数值走 fittedText太长会自动降字号不会冲出表盘。
function drawTopSlot(dc as Dc, ti as Number, id as Number, isLeft as Boolean,
ctx as Fields.Ctx, level as Float) as Void {
var x = isLeft ? Layout.LEFT_X : Layout.RIGHT_X;
Icons.forField(dc, id, x, Themes.ACCENT[ti] as Number, level);
Layout.fittedText(dc, x, Layout.VALUE_CY, Layout.fontComp,
Fields.value(id, ctx), Graphics.TEXT_JUSTIFY_CENTER,
Themes.TEXTPRIMARY[ti] as Number, Layout.TOP_MAX_W);
}
// 日期带:整条横幅底色 + 蓝牙符号 + 星期 + 月日 + 上午/下午。
// 24 小时制下不显示上午/下午(跟随手表设置)。
function drawDateBand(dc as Dc, ti as Number, ds as System.DeviceSettings?) as Void {
var fill = Themes.BANDFILL[ti] as Number;
dc.setColor(fill, fill);
dc.fillRectangle(0, Layout.px(Layout.BAND_Y), Layout.width,
Layout.px(Layout.BAND_H));
var col = Themes.BANDTEXT[ti] as Number;
// 手机断连时把蓝牙符号**压暗**而不是隐藏 —— 否则手机一走远日期带就
// 少一块,整条带子的视觉重心跟着变,很干扰。
Icons.bluetooth(dc, (ds != null && !ds.phoneConnected)
? blend(col, fill, 0.6) : col);
// ⚠️ 必须用 FORMAT_SHORT不能用 FORMAT_MEDIUM。
// 只有短格式的 day_of_week / month 返回的是**数字**;中格式返回的是
// 本地化字符串,拿去做数组下标会直接抛类型异常 —— 初版就是这么崩的,
// 而且是每次更新都崩。
var g = Gregorian.info(Time.now(), Time.FORMAT_SHORT);
Layout.text(dc, Layout.DOW_CX, Layout.BAND_CY, Layout.fontBand,
Fields.dow(g), Graphics.TEXT_JUSTIFY_CENTER, col);
Layout.text(dc, Layout.MD_CX, Layout.BAND_CY, Layout.fontBand,
Fields.monthDay(g), Graphics.TEXT_JUSTIFY_CENTER, col);
if (ds == null || !ds.is24Hour) {
Layout.text(dc, Layout.AMPM_R, Layout.BAND_CY, Layout.fontBand,
Fields.meridiem(g), Graphics.TEXT_JUSTIFY_RIGHT, col);
}
}
// 中央时间。小时和分钟各自带竖向渐变gradText 内部会分带多次绘制),
// 中间的冒号是两个实心方块,位置写死在设计稿坐标上。
function drawTime(dc as Dc, ti as Number, ds as System.DeviceSettings?) as Void {
var g = Gregorian.info(Time.now(), Time.FORMAT_SHORT);
var h = g.hour;
if (ds == null || !ds.is24Hour) {
if (h == 0) { h = 12; } else if (h > 12) { h = h - 12; }
}
Layout.gradText(dc, Layout.HOURS_R, Layout.TIME_CY, Layout.fontTime,
h.format("%d"), Graphics.TEXT_JUSTIFY_RIGHT,
Themes.HOURS[ti] as Array<Number>);
Layout.gradText(dc, Layout.MINUTES_L, Layout.TIME_CY, Layout.fontTime,
g.min.format("%02d"), Graphics.TEXT_JUSTIFY_LEFT,
Themes.MINUTES[ti] as Array<Number>);
dc.setColor(Themes.COLON[ti] as Number, Graphics.COLOR_TRANSPARENT);
dc.fillRectangle(Layout.px(Layout.COLON_X), Layout.px(Layout.COLON_Y1),
Layout.px(Layout.COLON_W), Layout.px(Layout.COLON_H));
dc.fillRectangle(Layout.px(Layout.COLON_X), Layout.px(Layout.COLON_Y2),
Layout.px(Layout.COLON_W), Layout.px(Layout.COLON_H));
}
// 底部两格:各自「数值 + 小标签」。
// 标签跟随所选字段自动变化,不需要单独配置。
function drawBottom(dc as Dc, ti as Number, ctx as Fields.Ctx) as Void {
var value = Themes.TEXTPRIMARY[ti] as Number;
var label = Themes.ACCENT[ti] as Number;
var left = Settings.bottomLeft();
var right = Settings.bottomRight();
Layout.fittedText(dc, Layout.DIST_R, Layout.BOT_VAL_CY, Layout.fontComp,
Fields.value(left, ctx), Graphics.TEXT_JUSTIFY_RIGHT,
value, Layout.BOT_MAX_W);
Layout.fittedText(dc, Layout.DIST_R, Layout.BOT_LAB_CY, Layout.fontComp,
Fields.label(left), Graphics.TEXT_JUSTIFY_RIGHT,
label, Layout.BOT_MAX_W);
Layout.fittedText(dc, Layout.STEP_L, Layout.BOT_VAL_CY, Layout.fontComp,
Fields.value(right, ctx), Graphics.TEXT_JUSTIFY_LEFT,
value, Layout.BOT_MAX_W);
Layout.fittedText(dc, Layout.STEP_L, Layout.BOT_LAB_CY, Layout.fontComp,
Fields.label(right), Graphics.TEXT_JUSTIFY_LEFT,
label, Layout.BOT_MAX_W);
}
// ------------------------------- 颜色工具 ------------------------------
// 两色按比例混合f=0 取 c1f=1 取 c2。
function blend(c1 as Number, c2 as Number, f as Float) as Number {
var r1 = (c1 >> 16) & 0xFF;
var g1 = (c1 >> 8) & 0xFF;
var b1 = c1 & 0xFF;
var r = r1 + (((((c2 >> 16) & 0xFF) - r1) * f)).toNumber();
var g = g1 + (((((c2 >> 8) & 0xFF) - g1) * f)).toNumber();
var b = b1 + ((((c2 & 0xFF) - b1) * f)).toNumber();
return (r << 16) | (g << 8) | b;
}
// 整体压暗到 f 倍(常亮模式用)。
function dim(col as Number, f as Float) as Number {
var r = (((col >> 16) & 0xFF) * f).toNumber();
var g = (((col >> 8) & 0xFF) * f).toNumber();
var b = ((col & 0xFF) * f).toNumber();
return (r << 16) | (g << 8) | b;
}
// ------------------------------- 常亮模式 ------------------------------
// 低功耗画面。相比正常画面砍掉的东西:
// - 日期带底色(整条亮橙色横幅是最费电的元素,直接不画)
// - **整个进度环**
// - 时间、冒号、日期压暗到 38%
//
// 度量口径要注意:「点亮像素数」把每个抗锯齿边缘像素都算成亮的,和实际
// 功耗对不上AMOLED 功耗更接近各子像素亮度之和(平均亮度)。
// 本实现两个口径都留了余量,实测数字见 README 的常亮小节。
// - 四个数据位、电池(全部隐藏)
// 保留的时间和日期压暗到 55%。
//
// 另外整个画面按分钟在 ±4 像素内游走,避免同一个像素长期点亮导致烧屏。
// pTR/pTL/pBR/pBL 现在用不上(常亮下不画环),保留形参是为了以后要把环
// 加回来时不必改调用点。
function drawAmbient(dc as Dc, ti as Number, ds as System.DeviceSettings?,
pTR as Float, pTL as Float, pBR as Float, pBL as Float) as Void {
var g = Gregorian.info(Time.now(), Time.FORMAT_SHORT);
var ox = ((g.min % 5) - 2) * 2.0 / Layout.scale; // ±4 设备像素,换算回设计像素
var oy = ((g.min / 5) % 5 - 2) * 2.0 / Layout.scale;
// 进度环在常亮下不画 —— 它是点亮像素数的大头。
var h = g.hour;
if (ds == null || !ds.is24Hour) {
if (h == 0) { h = 12; } else if (h > 12) { h = h - 12; }
}
var hours = Themes.HOURS[ti] as Array<Number>;
var mins = Themes.MINUTES[ti] as Array<Number>;
Layout.text(dc, Layout.HOURS_R + ox, Layout.TIME_CY + oy, Layout.fontTime,
h.format("%d"), Graphics.TEXT_JUSTIFY_RIGHT,
dim(hours[hours.size() / 2], 0.38));
Layout.text(dc, Layout.MINUTES_L + ox, Layout.TIME_CY + oy, Layout.fontTime,
g.min.format("%02d"), Graphics.TEXT_JUSTIFY_LEFT,
dim(mins[mins.size() / 2], 0.38));
dc.setColor(dim(Themes.COLON[ti] as Number, 0.38), Graphics.COLOR_TRANSPARENT);
dc.fillRectangle(Layout.px(Layout.COLON_X + ox), Layout.px(Layout.COLON_Y1 + oy),
Layout.px(Layout.COLON_W), Layout.px(Layout.COLON_H));
dc.fillRectangle(Layout.px(Layout.COLON_X + ox), Layout.px(Layout.COLON_Y2 + oy),
Layout.px(Layout.COLON_W), Layout.px(Layout.COLON_H));
var band = dim(Themes.ACCENT[ti] as Number, 0.38);
Layout.text(dc, Layout.DOW_CX + ox, Layout.BAND_CY + oy, Layout.fontBand,
Fields.dow(g), Graphics.TEXT_JUSTIFY_CENTER, band);
Layout.text(dc, Layout.MD_CX + ox, Layout.BAND_CY + oy, Layout.fontBand,
Fields.monthDay(g), Graphics.TEXT_JUSTIFY_CENTER, band);
}
// ------------------------------- 秒针刷新 ------------------------------
// 表盘正常只有每分钟一次的 onUpdate秒数根本走不动。
// 这里实现 onPartialUpdate系统每秒回调一次但要非常克制
// - 只有当真的有数据位选了「秒」时才做事,否则直接返回
// - 只重绘那一格,用 setClip 把绘制限制在格子的包围盒内
// (每秒重绘整个表盘的功耗预算是不够的)
// - 常亮的 AMOLED 机型直接跳过:那时数据位本来就不显示
function isSeconds(id as Number) as Boolean {
return id == 850 || id == 869;
}
function wantsSeconds() as Boolean {
if (Settings.showTop()
&& (isSeconds(Settings.leftTop()) || isSeconds(Settings.rightTop()))) {
return true;
}
return Settings.showBottom()
&& (isSeconds(Settings.bottomLeft()) || isSeconds(Settings.bottomRight()));
}
// 重绘单个格子:先把它的包围盒涂黑,再把新值画回去。
function repaintSlot(dc as Dc, ti as Number, ctx as Fields.Ctx, id as Number,
x as Numeric, cyDesign as Numeric, just as Number,
maxW as Float, col as Number) as Void {
var half = maxW / 2.0;
var x0 = x - half;
if (just == Graphics.TEXT_JUSTIFY_RIGHT) { x0 = x - maxW; }
else if (just == Graphics.TEXT_JUSTIFY_LEFT) { x0 = x; }
var h = Layout.CAP_COMP * 1.6;
dc.setClip(Layout.px(x0), Layout.px(cyDesign - h / 2),
Layout.px(maxW), Layout.px(h));
// 全屏涂黑。设计稿的底色就是纯黑AMOLED 上黑像素也最省电。
dc.setColor(Graphics.COLOR_BLACK, Graphics.COLOR_BLACK);
dc.clear();
Layout.fittedText(dc, x, cyDesign, Layout.fontComp, Fields.value(id, ctx),
just, col, maxW);
dc.clearClip();
}
function onPartialUpdate(dc as Dc) as Void {
if (mBurnIn || !Layout.ready() || !Fields.ready()) { return; }
if (!wantsSeconds()) { return; }
var ti = Settings.themeIndex(Themes.NAMES.size());
var ctx = new Fields.Ctx(System.getDeviceSettings(), Settings.tempUnit());
var col = Themes.TEXTPRIMARY[ti] as Number;
if (Settings.showTop()) {
if (isSeconds(Settings.leftTop())) {
repaintSlot(dc, ti, ctx, Settings.leftTop(), Layout.LEFT_X,
Layout.VALUE_CY, Graphics.TEXT_JUSTIFY_CENTER,
Layout.TOP_MAX_W, col);
}
if (isSeconds(Settings.rightTop())) {
repaintSlot(dc, ti, ctx, Settings.rightTop(), Layout.RIGHT_X,
Layout.VALUE_CY, Graphics.TEXT_JUSTIFY_CENTER,
Layout.TOP_MAX_W, col);
}
}
if (Settings.showBottom()) {
if (isSeconds(Settings.bottomLeft())) {
repaintSlot(dc, ti, ctx, Settings.bottomLeft(), Layout.DIST_R,
Layout.BOT_VAL_CY, Graphics.TEXT_JUSTIFY_RIGHT,
Layout.BOT_MAX_W, col);
}
if (isSeconds(Settings.bottomRight())) {
repaintSlot(dc, ti, ctx, Settings.bottomRight(), Layout.STEP_L,
Layout.BOT_VAL_CY, Graphics.TEXT_JUSTIFY_LEFT,
Layout.BOT_MAX_W, col);
}
}
}
// ------------------------------- 主绘制 --------------------------------
// 每分钟调用一次(以及唤醒、设置变更时)。
function onUpdate(dc as Dc) as Void {
if (!Layout.ready() || Layout.width != dc.getWidth()
|| !Fields.ready() || !Icons.ready()) {
onLayout(dc);
}
if (dc has :setAntiAlias) { dc.setAntiAlias(true); }
// 每次绘制只构造一个 Ctx四个数据位共用 —— 天气、用户档案这些
// 开销大的查询因此每帧最多做一次,且只在真有格子要用时才做。
var ti = Settings.themeIndex(Themes.NAMES.size());
var ds = System.getDeviceSettings();
var ctx = new Fields.Ctx(ds, Settings.tempUnit());
Comp.beginFrame(); // 让第三方 App 列表这一帧只枚举一次
var info = ctx.info();
var stats = ctx.stats();
var level = 0.0f;
if (stats != null && stats.battery != null) { level = stats.battery / 100.0; }
if (level > 1.0f) { level = 1.0f; }
if (level < 0.0f) { level = 0.0f; }
dc.setColor(Graphics.COLOR_BLACK, Graphics.COLOR_BLACK);
dc.clear();
var pTR = ringProgress(Settings.ringTR(), info);
var pTL = ringProgress(Settings.ringTL(), info);
var pBR = ringProgress(Settings.ringBR(), info);
var pBL = ringProgress(Settings.ringBL(), info);
// 常亮模式走另一条绘制路径,画完直接返回。
if (mSleeping && mBurnIn) {
drawAmbient(dc, ti, ds, pTR, pTL, pBR, pBL);
return;
}
drawRing(dc, ti, pTR, pTL, pBR, pBL);
if (Settings.showTop()) {
drawBattery(dc, ti, level);
drawTopSlot(dc, ti, Settings.leftTop(), true, ctx, level);
drawTopSlot(dc, ti, Settings.rightTop(), false, ctx, level);
}
drawTime(dc, ti, ds);
if (Settings.showBand()) {
drawDateBand(dc, ti, ds);
}
if (Settings.showBottom()) {
drawBottom(dc, ti, ctx);
}
}
}