152 lines
4.7 KiB
C++
152 lines
4.7 KiB
C++
#include "ClockWidget.hpp"
|
|
#include <cmath>
|
|
|
|
#ifndef PI
|
|
#define PI 3.14159265358979323846f
|
|
#endif
|
|
|
|
ClockWidget::ClockWidget(const WidgetConfig& config)
|
|
: Widget(config)
|
|
{
|
|
}
|
|
|
|
lv_obj_t* ClockWidget::create(lv_obj_t* parent) {
|
|
obj_ = lv_obj_create(parent);
|
|
if (!obj_) return nullptr;
|
|
|
|
lv_obj_remove_style_all(obj_);
|
|
lv_obj_set_pos(obj_, config_.x, config_.y);
|
|
lv_obj_set_size(obj_,
|
|
config_.width > 0 ? config_.width : 200,
|
|
config_.height > 0 ? config_.height : 200);
|
|
lv_obj_clear_flag(obj_, LV_OBJ_FLAG_SCROLLABLE);
|
|
|
|
// Create hands
|
|
hourHand_ = lv_line_create(obj_);
|
|
minuteHand_ = lv_line_create(obj_);
|
|
secondHand_ = lv_line_create(obj_);
|
|
centerDot_ = lv_obj_create(obj_);
|
|
|
|
// Style center dot
|
|
lv_obj_remove_style_all(centerDot_);
|
|
lv_obj_set_size(centerDot_, 8, 8);
|
|
lv_obj_set_style_radius(centerDot_, LV_RADIUS_CIRCLE, 0);
|
|
lv_obj_center(centerDot_);
|
|
|
|
// Initial update to set positions (will be updated by loop)
|
|
time_t now;
|
|
time(&now);
|
|
struct tm t;
|
|
localtime_r(&now, &t);
|
|
updateHands(t);
|
|
|
|
return obj_;
|
|
}
|
|
|
|
void ClockWidget::applyStyle() {
|
|
if (!obj_) return;
|
|
|
|
// Face style (background)
|
|
if (config_.bgOpacity > 0) {
|
|
lv_obj_set_style_bg_color(obj_, lv_color_make(
|
|
config_.bgColor.r, config_.bgColor.g, config_.bgColor.b), 0);
|
|
lv_obj_set_style_bg_opa(obj_, config_.bgOpacity, 0);
|
|
}
|
|
|
|
if (config_.borderRadius > 0) {
|
|
lv_obj_set_style_radius(obj_, config_.borderRadius, 0); // Usually 50% for circle
|
|
} else {
|
|
lv_obj_set_style_radius(obj_, LV_RADIUS_CIRCLE, 0);
|
|
}
|
|
|
|
lv_obj_set_style_border_width(obj_, 2, 0);
|
|
lv_obj_set_style_border_color(obj_, lv_color_make(
|
|
config_.textColor.r, config_.textColor.g, config_.textColor.b), 0);
|
|
|
|
// Hand colors
|
|
lv_color_t handColor = lv_color_make(
|
|
config_.textColor.r, config_.textColor.g, config_.textColor.b);
|
|
lv_color_t secColor = lv_color_make(200, 50, 50); // Red for second hand
|
|
|
|
if (hourHand_) {
|
|
lv_obj_set_style_line_width(hourHand_, 6, 0);
|
|
lv_obj_set_style_line_color(hourHand_, handColor, 0);
|
|
lv_obj_set_style_line_rounded(hourHand_, true, 0);
|
|
}
|
|
if (minuteHand_) {
|
|
lv_obj_set_style_line_width(minuteHand_, 4, 0);
|
|
lv_obj_set_style_line_color(minuteHand_, handColor, 0);
|
|
lv_obj_set_style_line_rounded(minuteHand_, true, 0);
|
|
}
|
|
if (secondHand_) {
|
|
lv_obj_set_style_line_width(secondHand_, 2, 0);
|
|
lv_obj_set_style_line_color(secondHand_, secColor, 0);
|
|
lv_obj_set_style_line_rounded(secondHand_, true, 0);
|
|
}
|
|
if (centerDot_) {
|
|
lv_obj_set_style_bg_color(centerDot_, handColor, 0);
|
|
}
|
|
|
|
// Force redraw of hands with new style/dimensions
|
|
lastSecond_ = -1;
|
|
time_t now;
|
|
time(&now);
|
|
struct tm t;
|
|
localtime_r(&now, &t);
|
|
updateHands(t);
|
|
}
|
|
|
|
void ClockWidget::updateHands(const struct tm& t) {
|
|
if (t.tm_sec == lastSecond_ && t.tm_min == lastMinute_ && t.tm_hour == lastHour_) return;
|
|
|
|
lastSecond_ = t.tm_sec;
|
|
lastMinute_ = t.tm_min;
|
|
lastHour_ = t.tm_hour;
|
|
|
|
int32_t w = lv_obj_get_width(obj_);
|
|
int32_t h = lv_obj_get_height(obj_);
|
|
int32_t cx = w / 2;
|
|
int32_t cy = h / 2;
|
|
int32_t radius = (w < h ? w : h) / 2;
|
|
|
|
// Lengths
|
|
int32_t lenSec = radius - 10;
|
|
int32_t lenMin = radius - 20;
|
|
int32_t lenHour = radius * 0.6f;
|
|
|
|
// Angles (0 is top, clockwise)
|
|
// Second: 6 deg per sec
|
|
float angleSec = t.tm_sec * 6.0f;
|
|
// Minute: 6 deg per min + 0.1 deg per sec
|
|
float angleMin = t.tm_min * 6.0f + t.tm_sec * 0.1f;
|
|
// Hour: 30 deg per hour + 0.5 deg per min
|
|
float angleHour = (t.tm_hour % 12) * 30.0f + t.tm_min * 0.5f;
|
|
|
|
auto calcPoints = [&](float angle, int32_t len, lv_point_precise_t* p) {
|
|
float rad = (angle - 90.0f) * PI / 180.0f;
|
|
p[0].x = cx;
|
|
p[0].y = cy;
|
|
p[1].x = cx + static_cast<int32_t>(cos(rad) * len);
|
|
p[1].y = cy + static_cast<int32_t>(sin(rad) * len);
|
|
};
|
|
|
|
if (secondHand_) {
|
|
calcPoints(angleSec, lenSec, secondPoints_);
|
|
lv_line_set_points(secondHand_, secondPoints_, 2);
|
|
}
|
|
if (minuteHand_) {
|
|
calcPoints(angleMin, lenMin, minutePoints_);
|
|
lv_line_set_points(minuteHand_, minutePoints_, 2);
|
|
}
|
|
if (hourHand_) {
|
|
calcPoints(angleHour, lenHour, hourPoints_);
|
|
lv_line_set_points(hourHand_, hourPoints_, 2);
|
|
}
|
|
}
|
|
|
|
void ClockWidget::onKnxTime(const struct tm& value, TextSource source) {
|
|
// Only accept system time updates or explicitly configured KNX time sources if we supported them
|
|
// For now, ClockWidget listens to SYSTEM_TIME via WidgetManager broadcast
|
|
updateHands(value);
|
|
}
|