From db32eef615de8efe62951f4c2bcc43208ea0e907 Mon Sep 17 00:00:00 2001 From: nhjschulz Date: Sun, 13 Oct 2024 11:50:50 +0200 Subject: [PATCH 1/4] DateTimePlugin: Adding analog clock view configuration HTML: * Make config container responsive No margin below small devices * Add radio button groups for analog mode * Allow to customize seconds visualisation over web pages (radio buttons). Webserver: Added keyword DISPLAY_HEIGHT and DISPLAY_WIDTH. They get replaced with the resolution of the display. Used to enable/disable resolution dependend elements. --- lib/DateTimePlugin/src/DateTimePlugin.cpp | 118 +++++++++++++++-- lib/DateTimePlugin/src/DateTimePlugin.h | 24 +++- lib/DateTimePlugin/web/DateTimePlugin.html | 139 ++++++++++++++++++-- lib/Views/src/IDateTimeView.h | 76 ++++++++++- lib/Views/src/layouts/DateTimeView32x8.h | 45 +++++++ lib/Views/src/layouts/DateTimeView64x64.cpp | 68 ++++++---- lib/Views/src/layouts/DateTimeView64x64.h | 79 +++++++++-- src/Web/Pages.cpp | 5 +- 8 files changed, 494 insertions(+), 60 deletions(-) diff --git a/lib/DateTimePlugin/src/DateTimePlugin.cpp b/lib/DateTimePlugin/src/DateTimePlugin.cpp index 6e4f6459..f6f9ba4a 100644 --- a/lib/DateTimePlugin/src/DateTimePlugin.cpp +++ b/lib/DateTimePlugin/src/DateTimePlugin.cpp @@ -59,13 +59,23 @@ *****************************************************************************/ /* Initialize plugin topic. */ -const char* DateTimePlugin::TOPIC_CONFIG = "/dateTime"; +const char DateTimePlugin::TOPIC_CONFIG[] = "/dateTime"; /* Initialize default time format. */ -const char* DateTimePlugin::TIME_FORMAT_DEFAULT = "%I:%M %p"; +const char DateTimePlugin::TIME_FORMAT_DEFAULT[] = "%I:%M %p"; /* Initialize default date format. */ -const char* DateTimePlugin::DATE_FORMAT_DEFAULT = "%m/%d"; +const char DateTimePlugin::DATE_FORMAT_DEFAULT[] = "%m/%d"; + +/* Color key names for the analog clock configuration. */ +const char* DateTimePlugin::ANALOG_CLOCK_COLOR_KEYS[IDateTimeView::ANA_CLK_COL_MAX] = +{ + "handHourCol", + "handMinCol", + "handSecCol", + "ringFiveMinCol", + "ringMinDotCol" +}; /****************************************************************************** * Public Methods @@ -95,18 +105,22 @@ bool DateTimePlugin::setTopic(const String& topic, const JsonObjectConst& value) if (true == topic.equals(TOPIC_CONFIG)) { - const size_t JSON_DOC_SIZE = 512U; + const IDateTimeView::AnalogClockConfig* analogClockCfg = nullptr; + + const size_t JSON_DOC_SIZE = 768U; DynamicJsonDocument jsonDoc(JSON_DOC_SIZE); JsonObject jsonCfg = jsonDoc.to(); JsonVariantConst jsonMode = value["mode"]; + JsonVariantConst jsonViewMode = value["viewMode"]; JsonVariantConst jsonTimeFormat = value["timeFormat"]; JsonVariantConst jsonDateFormat = value["dateFormat"]; JsonVariantConst jsonTimeZone = value["timeZone"]; JsonVariantConst jsonStartOfWeek = value["startOfWeek"]; JsonVariantConst jsonDayOnColor = value["dayOnColor"]; JsonVariantConst jsonDayOffColor = value["dayOffColor"]; - - /* The received configuration may not contain all single key/value pair. + JsonObjectConst jsonAnalogClock = value["analogClock"]; + + /* The received configuration may not contain all single key/value pair. * Therefore read first the complete internal configuration and * overwrite them with the received ones. */ @@ -122,7 +136,13 @@ bool DateTimePlugin::setTopic(const String& topic, const JsonObjectConst& value) jsonCfg["mode"] = jsonMode.as(); isSuccessful = true; } - + + if (false == jsonViewMode.isNull()) + { + jsonCfg["viewMode"] = jsonViewMode.as(); + isSuccessful = true; + } + if (false == jsonTimeFormat.isNull()) { jsonCfg["timeFormat"] = jsonTimeFormat.as(); @@ -158,6 +178,12 @@ bool DateTimePlugin::setTopic(const String& topic, const JsonObjectConst& value) jsonCfg["dayOffColor"] = jsonDayOffColor.as(); isSuccessful = true; } + + if (false == jsonAnalogClock.isNull()) + { + jsonCfg["analogClock"] = jsonAnalogClock; + isSuccessful = true; + } if (true == isSuccessful) { @@ -262,33 +288,58 @@ void DateTimePlugin::update(YAGfx& gfx) void DateTimePlugin::getConfiguration(JsonObject& jsonCfg) const { + const IDateTimeView::AnalogClockConfig* analogClockCfg = nullptr; + MutexGuard guard(m_mutex); jsonCfg["mode"] = m_mode; + jsonCfg["viewMode"] = m_view.getViewMode(); jsonCfg["timeFormat"] = m_timeFormat; jsonCfg["dateFormat"] = m_dateFormat; jsonCfg["timeZone"] = m_timeZone; jsonCfg["startOfWeek"] = m_view.getStartOfWeek(); jsonCfg["dayOnColor"] = colorToHtml(m_view.getDayOnColor()); jsonCfg["dayOffColor"] = colorToHtml(m_view.getDayOffColor()); + + if (nullptr != (analogClockCfg = m_view.getAnalogClockConfig())) + { + /* View supports analog clock, add the additinal config elements for it. + */ + JsonObject jsonAnalogClock = jsonCfg.createNestedObject("analogClock"); + jsonAnalogClock["secondsMode"] = analogClockCfg->m_secondsMode; + for (uint32_t index = 0U; index < IDateTimeView::ANA_CLK_COL_MAX; ++index) + { + jsonAnalogClock[ANALOG_CLOCK_COLOR_KEYS[index]]= colorToHtml(analogClockCfg->m_colors[index]); + } + } + } bool DateTimePlugin::setConfiguration(const JsonObjectConst& jsonCfg) { bool status = false; JsonVariantConst jsonMode = jsonCfg["mode"]; + JsonVariantConst jsonViewMode = jsonCfg["viewMode"]; JsonVariantConst jsonTimeFormat = jsonCfg["timeFormat"]; JsonVariantConst jsonDateFormat = jsonCfg["dateFormat"]; JsonVariantConst jsonTimeZone = jsonCfg["timeZone"]; JsonVariantConst jsonStartOfWeek = jsonCfg["startOfWeek"]; JsonVariantConst jsonDayOnColor = jsonCfg["dayOnColor"]; JsonVariantConst jsonDayOffColor = jsonCfg["dayOffColor"]; + JsonVariantConst jsonAnalogClock = jsonCfg["analogClock"]; + + IDateTimeView::AnalogClockConfig analogClockConfig; if ((false == jsonMode.is()) && (MODE_MAX <= jsonMode.as())) { LOG_WARNING("JSON mode not found or invalid type."); } + else if ((false == jsonViewMode.is()) && + (IDateTimeView::VIEW_MODE_MAX <= jsonViewMode.as())) + { + LOG_WARNING("JSON view mode not found or invalid type."); + } else if (false == jsonTimeFormat.is()) { LOG_WARNING("JSON time format not found or invalid type."); @@ -313,6 +364,9 @@ bool DateTimePlugin::setConfiguration(const JsonObjectConst& jsonCfg) { LOG_WARNING("JSON day off color not found or invalid type."); } + else if (false == checkAnalogClockConfig(jsonAnalogClock, analogClockConfig)) + /* Error printed in checkAnalogClockConfig() already. */ + ; else { MutexGuard guard(m_mutex); @@ -325,6 +379,12 @@ bool DateTimePlugin::setConfiguration(const JsonObjectConst& jsonCfg) status = m_view.setStartOfWeek(jsonStartOfWeek.as()); m_view.setDayOnColor(colorFromHtml(jsonDayOnColor.as())); m_view.setDayOffColor(colorFromHtml(jsonDayOffColor.as())); + m_view.setViewMode(static_cast(jsonViewMode.as())); + + if (false == jsonAnalogClock.isNull()) + { + m_view.setAnalogClockConfig(analogClockConfig); + } m_hasTopicChanged = true; } @@ -511,7 +571,7 @@ bool DateTimePlugin::getTimeAsString(String& time, const String& format, const t return isSuccessful; } -String DateTimePlugin::colorToHtml(const Color& color) const +String DateTimePlugin::colorToHtml(const Color& color) { char buffer[8]; /* '#' + 3x byte in hex + '\0' */ @@ -520,7 +580,7 @@ String DateTimePlugin::colorToHtml(const Color& color) const return String(buffer); } -Color DateTimePlugin::colorFromHtml(const String& htmlColor) const +Color DateTimePlugin::colorFromHtml(const String& htmlColor) { Color color; @@ -532,6 +592,46 @@ Color DateTimePlugin::colorFromHtml(const String& htmlColor) const return color; } +bool DateTimePlugin::checkAnalogClockConfig(JsonVariantConst& jsonCfg, IDateTimeView::AnalogClockConfig & cfg) +{ + bool result = true; + + if (false == jsonCfg.isNull()) + { + JsonVariantConst jsonSecondsMode = jsonCfg["secondsMode"]; + + if ((false == jsonSecondsMode.is()) && + (IDateTimeView::SECONDS_DISP_MAX <= jsonSecondsMode.as())) + { + LOG_WARNING("JSON seconds mode not found or invalid type."); + result = false; + } + else + { + cfg.m_secondsMode = static_cast(jsonSecondsMode.as()); + + for (uint32_t idx = 0U; idx < IDateTimeView::ANA_CLK_COL_MAX; ++ idx) + { + JsonVariantConst color = jsonCfg[ANALOG_CLOCK_COLOR_KEYS[idx]]; + + if (false == color.is()) + { + LOG_WARNING( + "JSON attribute %s not found or invalid type.", + ANALOG_CLOCK_COLOR_KEYS[idx]); + result = false; + } + else + { + cfg.m_colors[idx] = colorFromHtml(color); + } + } + } + } + + return result; +} + /****************************************************************************** * External Functions *****************************************************************************/ diff --git a/lib/DateTimePlugin/src/DateTimePlugin.h b/lib/DateTimePlugin/src/DateTimePlugin.h index 0d3e2c9d..188fe77a 100644 --- a/lib/DateTimePlugin/src/DateTimePlugin.h +++ b/lib/DateTimePlugin/src/DateTimePlugin.h @@ -279,7 +279,7 @@ class DateTimePlugin : public PluginWithConfig /** * Plugin topic, used to read/write the configuration. */ - static const char* TOPIC_CONFIG; + static const char TOPIC_CONFIG[]; /** Time to check date update period in ms */ static const uint32_t CHECK_UPDATE_PERIOD = SIMPLE_TIMER_SECONDS(1U); @@ -288,10 +288,13 @@ class DateTimePlugin : public PluginWithConfig static const uint32_t MS_TO_SEC_DIVIDER = 1000U; /** Default time format according to strftime(). */ - static const char* TIME_FORMAT_DEFAULT; + static const char TIME_FORMAT_DEFAULT[]; /** Default date format according to strftime(). */ - static const char* DATE_FORMAT_DEFAULT; + static const char DATE_FORMAT_DEFAULT[]; + + /** Color key names for the analog clock configuration. */ + static const char* ANALOG_CLOCK_COLOR_KEYS[IDateTimeView::ANA_CLK_COL_MAX]; /** * If the slot duration is infinite (0s), the default duration of 30s shall be assumed as base @@ -359,7 +362,7 @@ class DateTimePlugin : public PluginWithConfig * * @return Color in HTML format */ - String colorToHtml(const Color& color) const; + static String colorToHtml(const Color& color); /** * Convert color from HTML format. @@ -368,7 +371,18 @@ class DateTimePlugin : public PluginWithConfig * * @return Color */ - Color colorFromHtml(const String& htmlColor) const; + static Color colorFromHtml(const String& htmlColor); + + /** + * Check if analog cfg is valid when present. + * + * @param jsonCfg[in] The json configuration, may be isNull(). + * @param cfg[out] The parsed config data if json present and valid. + * @return true If no configuration or valid json values. + */ + static bool checkAnalogClockConfig( + JsonVariantConst& jsonCfg, + IDateTimeView::AnalogClockConfig & cfg); }; /****************************************************************************** diff --git a/lib/DateTimePlugin/web/DateTimePlugin.html b/lib/DateTimePlugin/web/DateTimePlugin.html index f5bd8f56..2a766a19 100644 --- a/lib/DateTimePlugin/web/DateTimePlugin.html +++ b/lib/DateTimePlugin/web/DateTimePlugin.html @@ -72,7 +72,7 @@

Set configuration about what the plugin shall show.

Configuration

Display

-
+
@@ -118,8 +118,84 @@

Display

-
- +
+ +
+
@@ -197,6 +273,7 @@

Display

function getConfig(pluginUid) { disableUI(); + return utils.makeRequest({ method: "GET", url: "/rest/api/v1/display/uid/" + pluginUid + "/dateTime", @@ -209,6 +286,17 @@

Display

$("#startOfWeek").val(rsp.data.startOfWeek); $("#dayOnColor").val(rsp.data.dayOnColor); $("#dayOffColor").val(rsp.data.dayOffColor); + $("#viewMode").val(rsp.data.viewMode); + + if (rsp.data.hasOwnProperty("analogClock")) { + jsonAnalogClock = rsp.data.analogClock; + $("#handHourCol").val(jsonAnalogClock.handHourCol); + $("#handMinCol").val(jsonAnalogClock.handMinCol); + $("#handSecCol").val(jsonAnalogClock.handSecCol); + $("#ringFiveMinCol").val(jsonAnalogClock.ringFiveMinCol); + $("#ringMinDotCol").val(jsonAnalogClock.ringMinDotCol); + } + }).catch(function(rsp) { alert("Internal error."); }).finally(function() { @@ -218,19 +306,41 @@

Display

function setConfig(pluginUid) { disableUI(); - return utils.makeRequest({ - method: "POST", - url: "/rest/api/v1/display/uid/" + pluginUid + "/dateTime", - isJsonResponse: true, - parameter: { + + let displayWidth = ~DISPLAY_HEIGHT~; + let displayHeight = ~DISPLAY_HEIGHT~; + + configJson = { mode: $("#mode").val(), timeFormat: $("#timeFormat").val(), dateFormat: $("#dateFormat").val(), timeZone: $("#timeZone").val(), startOfWeek: $("#startOfWeek").val(), dayOnColor: $("#dayOnColor").val(), - dayOffColor: $("#dayOffColor").val() - } + dayOffColor: $("#dayOffColor").val(), + handHourCol: $("#handHourCol").val(), + viewMode: $('input[name=viewMode]:checked').val() + + }; + + if ((64 <= ~DISPLAY_HEIGHT~) && (64 <= ~DISPLAY_WIDTH~)) + { + configJson["analogClock"] = + { + secondsMode: $('input[name=secondsMode]:checked').val(), + handHourCol: $("#handHourCol").val(), + handMinCol: $("#handMinCol").val(), + handSecCol: $("#handSecCol").val(), + ringFiveMinCol: $("#ringFiveMinCol").val(), + ringMinDotCol: $("#ringMinDotCol").val() + }; + } + + return utils.makeRequest({ + method: "POST", + url: "/rest/api/v1/display/uid/" + pluginUid + "/dateTime", + isJsonResponse: true, + parameter: configJson }).then(function(rsp) { alert("Ok."); }).catch(function(rsp) { @@ -249,6 +359,15 @@

Display

/* Disable all forms, until the plugin instances are loaded. */ disableUI(); + let displayWidth = ~DISPLAY_WIDTH~; + let displayHeight = ~DISPLAY_HEIGHT~; + + /* Enable extended options for screens >= 64x64. */ + if ((displayWidth >= 64) && (displayHeight >= 64)) { + let opt64x64 = document.getElementById("options64x64"); + opt64x64.style.display = "block"; + } + /* Load all plugin instances. */ getPluginInstances().then(function(cnt) { var select = document.getElementById("pluginUid"); diff --git a/lib/Views/src/IDateTimeView.h b/lib/Views/src/IDateTimeView.h index 7a533bfa..ebabcf77 100644 --- a/lib/Views/src/IDateTimeView.h +++ b/lib/Views/src/IDateTimeView.h @@ -69,6 +69,50 @@ class IDateTimeView { } + /** + * The view modes, which influences how the data is + * shown on the display. + */ + enum ViewMode + { + DIGITAL_ONLY = 0U, /**< Show date and time */ + ANALOG_ONLY, /**< Show only the date */ + DIGITAL_AND_ANALOG, /**< Show only the time */ + VIEW_MODE_MAX /**< Number of configurations */ + }; + + /** + * Options for displaying seconds in analog clock. + */ + enum SecondsDisplayMode + { + SECOND_DISP_OFF = 0U, /**< No second indicator display. */ + SECOND_DISP_HAND = 1U, /**< Draw second clock hand. */ + SECOND_DISP_RING = 2U, /**< Show passed seconds on minute tick ring. */ + SECOND_DISP_BOTH = 3U, /**< Show hand and on ring. */ + SECONDS_DISP_MAX /**< Number of configurations. */ + }; + + /** + * Color array indexes for the analog clock drawing. + */ + enum AnalogClockColor + { + ANA_CLK_COL_HAND_HOUR = 0U, /**< Hour clock hand color. */ + ANA_CLK_COL_HAND_MIN, /**< Minutes clock hand color. */ + ANA_CLK_COL_HAND_SEC, /**< Seconds colock hand color */ + ANA_CLK_COL_RING_MIN5_MARK, /**< Ring five minute marks color. */ + ANA_CLK_COL_RING_MIN_DOT, /**< Ring minut dots color. */ + ANA_CLK_COL_MAX /**< Number of colors. */ + }; + + /** Analog clock appearance configuration. */ + struct AnalogClockConfig + { + SecondsDisplayMode m_secondsMode; /**< Seconds visualisation mode. */ + Color m_colors[ANA_CLK_COL_MAX]; /**< Clock colors to use. */ + }; + /** * Initialize view, which will prepare the widgets and the default values. */ @@ -160,10 +204,40 @@ class IDateTimeView */ virtual void setDayOffColor(const Color& color) = 0; + /** + * Get the view mode (analog, digital or both). + * + * @return ViewMode + */ + virtual ViewMode getViewMode() const = 0; + + /** + * Set the view mode (analog, digital or both). + * + * @return bool success of failure + */ + virtual bool setViewMode(ViewMode mode) = 0; + + /** + * Get the analog clock clonfiguration. + * + * @return AnalogClockConfig or nullptr if unsupported. + */ + virtual const AnalogClockConfig* getAnalogClockConfig() const = 0; + + /** + * Set the analog clock configuration. + * + * @param[in] cfg The new configuration to apply. + * + * @return success or failure + */ + virtual bool setAnalogClockConfig(const AnalogClockConfig& cfg) = 0; + /** * @brief Update current time values in view. * - * @param now current time + * @param[in] now current time */ virtual void setCurrentTime(const tm& now) = 0; diff --git a/lib/Views/src/layouts/DateTimeView32x8.h b/lib/Views/src/layouts/DateTimeView32x8.h index a07eb6b6..135cb5ae 100644 --- a/lib/Views/src/layouts/DateTimeView32x8.h +++ b/lib/Views/src/layouts/DateTimeView32x8.h @@ -249,6 +249,51 @@ class DateTimeView32x8 : public IDateTimeView updateLampWidgetsColors(); } + /** + * Get the view mode (analog, digital or both). + * + * @return ViewMode + */ + ViewMode getViewMode() const override + { + return ViewMode::DIGITAL_ONLY; /* 32X8 layout can only do digital.*/ + } + + /** + * Set the view mode (analog, digital or both). + * + * @return ViewMode + */ + bool setViewMode(ViewMode mode) override + { + if (ViewMode::DIGITAL_ONLY != mode) + { + LOG_WARNING("Illegal DateTime view mode for 32X8: (%hhu)", mode); + return false; + } + return true; + } + + /** + * Get the analog clock seconds display mode (none, ring, hand or both). + * + * @return SecondsDisplayMode pointer or nullptr if unsupported. + */ + virtual const AnalogClockConfig* getAnalogClockConfig() const override + { + return nullptr; /* 32X8 layout can only do digital.*/ + } + + /** + * Set the analog clock seconds display mode (none, ring, hand or both). + * + * @return success of failure + */ + virtual bool setAnalogClockConfig(const AnalogClockConfig& cfg) override + { + return true; /* No analog clock in 32x8 layout, ignore request. */ + } + /** * @brief Update current time values in view. * diff --git a/lib/Views/src/layouts/DateTimeView64x64.cpp b/lib/Views/src/layouts/DateTimeView64x64.cpp index d88b929a..e5b1d2e1 100644 --- a/lib/Views/src/layouts/DateTimeView64x64.cpp +++ b/lib/Views/src/layouts/DateTimeView64x64.cpp @@ -121,34 +121,54 @@ void DateTimeView64x64::update(YAGfx& gfx) gfx.fillScreen(ColorDef::BLACK); - m_textWidget.update(gfx); - for (idx = 0; MAX_LAMPS > idx; ++idx) { m_lampWidgets[idx].update(gfx); } - /* Draw analog clock minute circle. */ - drawAnalogClockBackground(gfx); - - /* Draw analog clock hands. */ - drawAnalogClockHand(gfx, m_now.tm_min, ANALOG_RADIUS - 6, ColorDef::GRAY); - drawAnalogClockHand(gfx, m_now.tm_hour * 5 + m_now.tm_min / 12 , ANALOG_RADIUS - 13, ColorDef::WHITE); - - if (0U != (m_secondsDisplayMode & SECOND_DISP_HAND)) + if ((ViewMode::DIGITAL_AND_ANALOG == m_mode) || (ViewMode::ANALOG_ONLY == m_mode)) { - drawAnalogClockHand(gfx, m_now.tm_sec, ANALOG_RADIUS - 1, ColorDef::YELLOW); + uint32_t centerRingCol = m_analogClockCfg.m_colors[ANA_CLK_COL_HAND_MIN]; + + /* Draw analog clock minute circle. */ + drawAnalogClockBackground(gfx); + + /* Draw analog clock hands. */ + drawAnalogClockHand( + gfx, + m_now.tm_min, + ANALOG_RADIUS - 6, + m_analogClockCfg.m_colors[ANA_CLK_COL_HAND_MIN]); + + drawAnalogClockHand(gfx, + m_now.tm_hour * 5 + m_now.tm_min / 12 , + ANALOG_RADIUS - 13, + m_analogClockCfg.m_colors[ANA_CLK_COL_HAND_HOUR]); + + if (0U != (m_analogClockCfg.m_secondsMode & SECOND_DISP_HAND)) + { + /* Use second hand color also for the middle ring if this hand is enabled. */ + centerRingCol = m_analogClockCfg.m_colors[ANA_CLK_COL_HAND_SEC]; + drawAnalogClockHand( + gfx, + m_now.tm_sec, + ANALOG_RADIUS - 1, + centerRingCol); + } + + /* Draw analog clock hand center */ + gfx.drawRectangle(ANALOG_CENTER_X - 2, ANALOG_CENTER_Y - 2, 5, 5, centerRingCol); + gfx.drawPixel(ANALOG_CENTER_X, ANALOG_CENTER_Y, ColorDef::BLACK); + gfx.drawPixel(ANALOG_CENTER_X-2, ANALOG_CENTER_Y-2, ColorDef::BLACK); + gfx.drawPixel(ANALOG_CENTER_X-2, ANALOG_CENTER_Y+2, ColorDef::BLACK); + gfx.drawPixel(ANALOG_CENTER_X+2, ANALOG_CENTER_Y-2, ColorDef::BLACK); + gfx.drawPixel(ANALOG_CENTER_X+2, ANALOG_CENTER_Y+2, ColorDef::BLACK); } - /* Draw analog clock hand center */ - gfx.drawRectangle(ANALOG_CENTER_X - 2, ANALOG_CENTER_Y - 2, 5, 5, ColorDef::YELLOW); - gfx.drawPixel(ANALOG_CENTER_X, ANALOG_CENTER_Y, ColorDef::BLACK); - gfx.drawPixel(ANALOG_CENTER_X-2, ANALOG_CENTER_Y-2, ColorDef::BLACK); - gfx.drawPixel(ANALOG_CENTER_X-2, ANALOG_CENTER_Y+2, ColorDef::BLACK); - gfx.drawPixel(ANALOG_CENTER_X+2, ANALOG_CENTER_Y-2, ColorDef::BLACK); - gfx.drawPixel(ANALOG_CENTER_X+2, ANALOG_CENTER_Y+2, ColorDef::BLACK); - - m_textWidget.update(gfx); + if ((ViewMode::DIGITAL_AND_ANALOG == m_mode) || (ViewMode::DIGITAL_ONLY == m_mode)) + { + m_textWidget.update(gfx); + } m_lastUpdateSecondVal = m_now.tm_sec; } @@ -180,14 +200,14 @@ void DateTimeView64x64::drawAnalogClockBackground(YAGfx& gfx) int16_t xe(ANALOG_CENTER_X + (dx * (ANALOG_RADIUS - 4)) / SINUS_VAL_SCALE); int16_t ye(ANALOG_CENTER_Y + (dy * (ANALOG_RADIUS - 4)) / SINUS_VAL_SCALE); - gfx.drawLine(xs, ys, xe, ye, ColorDef::BLUE); + gfx.drawLine(xs, ys, xe, ye, m_analogClockCfg.m_colors[ANA_CLK_COL_RING_MIN5_MARK]); } - Color tickMarkCol(ColorDef::DARKGRAY); - if ((0U != (SECOND_DISP_RING & m_secondsDisplayMode)) && (angle <= secondAngle)) + Color tickMarkCol = m_analogClockCfg.m_colors[ANA_CLK_COL_RING_MIN_DOT]; + if ((0U != (SECOND_DISP_RING & m_analogClockCfg.m_secondsMode)) && (angle <= secondAngle)) { /* Draw minute tick marks with passed seconds highlighting. */ - tickMarkCol = ColorDef::YELLOW; + tickMarkCol = m_analogClockCfg.m_colors[ANA_CLK_COL_HAND_SEC]; } gfx.drawPixel(xs, ys, tickMarkCol); } diff --git a/lib/Views/src/layouts/DateTimeView64x64.h b/lib/Views/src/layouts/DateTimeView64x64.h index a8218296..f81ac842 100644 --- a/lib/Views/src/layouts/DateTimeView64x64.h +++ b/lib/Views/src/layouts/DateTimeView64x64.h @@ -70,7 +70,18 @@ class DateTimeView64x64 : public DateTimeViewGeneric */ DateTimeView64x64() : DateTimeViewGeneric(), - m_secondsDisplayMode(SECOND_DISP_RING), + m_mode(ViewMode::DIGITAL_AND_ANALOG), + m_analogClockCfg( + { + SECOND_DISP_RING, + { + ColorDef::WHITE, + ColorDef::GRAY, + ColorDef::YELLOW, + ColorDef::BLUE, + ColorDef::YELLOW + } + }), m_lastUpdateSecondVal(-1) { /* Disable fade effect in case the user required to show seconds, @@ -101,20 +112,68 @@ class DateTimeView64x64 : public DateTimeViewGeneric void update(YAGfx& gfx) override; + /** + * Get the view mode (analog, digital or both). + * + * @return ViewMode + */ + ViewMode getViewMode() const override + { + return m_mode; + } -protected: + /** + * Set the view mode (analog, digital or both). + * + * @return success or failure + */ + bool setViewMode(ViewMode mode) override + { + bool ret = false; + + if (ViewMode::VIEW_MODE_MAX <= mode) + { + LOG_WARNING("Illegal DateTime view mode (%hhu)", mode); + } + else + { + m_mode = mode; + ret = true; + } + + return true; + } - /** Options for displaying seconds in analog clock + /** + * Get the analog clock configuration. + * + * @return SecondsDisplayMode + */ + const AnalogClockConfig* getAnalogClockConfig() const override + { + return &m_analogClockCfg; + } + + /** + * Set the analog clock configuration. + * + * @return success of failure */ - enum SecondsDisplayMode + bool setAnalogClockConfig(const AnalogClockConfig& cfg) override { - SECOND_DISP_OFF = 0U, /**< No second indicator display. */ - SECOND_DISP_HAND = 1U, /**< Draw second clock hand. */ - SECOND_DISP_RING = 2U, /**< Show passed seconds on minute tick ring. */ - SECOND_DISP_BOTH = 3U, /**< Show hand and on ring. */ - }; + if (SecondsDisplayMode::SECONDS_DISP_MAX <= cfg.m_secondsMode) + { + LOG_WARNING("Illegal Seconds Display mode (%hhu)", cfg.m_secondsMode); + return false; + } + + m_analogClockCfg = cfg; + return true; + } +protected: - SecondsDisplayMode m_secondsDisplayMode; /**< How to visualize seconds in analog clock. */ + ViewMode m_mode; /**< Used View mode analog, digital or both. */ + AnalogClockConfig m_analogClockCfg; /**< The clock drawing configuration options. */ /** diff --git a/src/Web/Pages.cpp b/src/Web/Pages.cpp index da26f38b..6620ad42 100644 --- a/src/Web/Pages.cpp +++ b/src/Web/Pages.cpp @@ -37,6 +37,7 @@ #include "Version.h" #include "UpdateMgr.h" #include "DisplayMgr.h" +#include "Display.h" #include "RestApi.h" #include "PluginList.h" #include "WiFiUtil.h" @@ -159,7 +160,9 @@ static TmplKeyWordFunc gTmplKeyWordToFunc[] = "TARGET", []() -> String { return Version::TARGET; }, "WS_ENDPOINT", []() -> String { return WebConfig::WEBSOCKET_PATH; }, "WS_PORT", []() -> String { return String(WebConfig::WEBSOCKET_PORT); }, - "WS_PROTOCOL", []() -> String { return WebConfig::WEBSOCKET_PROTOCOL; } + "WS_PROTOCOL", []() -> String { return WebConfig::WEBSOCKET_PROTOCOL; }, + "DISPLAY_HEIGHT", []() -> String { return String(Display::getInstance().getHeight()); }, + "DISPLAY_WIDTH", []() -> String { return String(Display::getInstance().getWidth()); } }; /****************************************************************************** From a6c2a239f973311bbe0572c3a64e7af181e82645 Mon Sep 17 00:00:00 2001 From: nhjschulz Date: Wed, 6 Nov 2024 19:23:53 +0100 Subject: [PATCH 2/4] DateTimePlugin: Analog clock code review Addressed code review findings https://github.com/BlueAndi/Pixelix/pull/198 --- lib/DateTimePlugin/src/DateTimePlugin.cpp | 8 +- lib/DateTimePlugin/web/DateTimePlugin.html | 10 +- lib/Views/src/layouts/DateTimeView32x8.h | 4 +- lib/Views/src/layouts/DateTimeView64x64.cpp | 162 ++++++++++++++------ lib/Views/src/layouts/DateTimeView64x64.h | 16 -- src/Web/Pages.cpp | 4 +- 6 files changed, 126 insertions(+), 78 deletions(-) diff --git a/lib/DateTimePlugin/src/DateTimePlugin.cpp b/lib/DateTimePlugin/src/DateTimePlugin.cpp index f6f9ba4a..aaf6ceba 100644 --- a/lib/DateTimePlugin/src/DateTimePlugin.cpp +++ b/lib/DateTimePlugin/src/DateTimePlugin.cpp @@ -301,7 +301,8 @@ void DateTimePlugin::getConfiguration(JsonObject& jsonCfg) const jsonCfg["dayOnColor"] = colorToHtml(m_view.getDayOnColor()); jsonCfg["dayOffColor"] = colorToHtml(m_view.getDayOffColor()); - if (nullptr != (analogClockCfg = m_view.getAnalogClockConfig())) + analogClockCfg = m_view.getAnalogClockConfig(); + if (nullptr != analogClockCfg) { /* View supports analog clock, add the additinal config elements for it. */ @@ -365,8 +366,9 @@ bool DateTimePlugin::setConfiguration(const JsonObjectConst& jsonCfg) LOG_WARNING("JSON day off color not found or invalid type."); } else if (false == checkAnalogClockConfig(jsonAnalogClock, analogClockConfig)) - /* Error printed in checkAnalogClockConfig() already. */ - ; + { + /* Error printed inside checkAnalogClockConfig() already. */ + } else { MutexGuard guard(m_mutex); diff --git a/lib/DateTimePlugin/web/DateTimePlugin.html b/lib/DateTimePlugin/web/DateTimePlugin.html index 2a766a19..9be5d66c 100644 --- a/lib/DateTimePlugin/web/DateTimePlugin.html +++ b/lib/DateTimePlugin/web/DateTimePlugin.html @@ -167,13 +167,13 @@

Display

- +
- +
- +
@@ -185,10 +185,10 @@

Display

- +
- +
diff --git a/lib/Views/src/layouts/DateTimeView32x8.h b/lib/Views/src/layouts/DateTimeView32x8.h index 135cb5ae..ea229722 100644 --- a/lib/Views/src/layouts/DateTimeView32x8.h +++ b/lib/Views/src/layouts/DateTimeView32x8.h @@ -279,7 +279,7 @@ class DateTimeView32x8 : public IDateTimeView * * @return SecondsDisplayMode pointer or nullptr if unsupported. */ - virtual const AnalogClockConfig* getAnalogClockConfig() const override + const AnalogClockConfig* getAnalogClockConfig() const override { return nullptr; /* 32X8 layout can only do digital.*/ } @@ -289,7 +289,7 @@ class DateTimeView32x8 : public IDateTimeView * * @return success of failure */ - virtual bool setAnalogClockConfig(const AnalogClockConfig& cfg) override + bool setAnalogClockConfig(const AnalogClockConfig& cfg) override { return true; /* No analog clock in 32x8 layout, ignore request. */ } diff --git a/lib/Views/src/layouts/DateTimeView64x64.cpp b/lib/Views/src/layouts/DateTimeView64x64.cpp index e5b1d2e1..d6f66e18 100644 --- a/lib/Views/src/layouts/DateTimeView64x64.cpp +++ b/lib/Views/src/layouts/DateTimeView64x64.cpp @@ -44,8 +44,44 @@ * Macros *****************************************************************************/ +/** Center X-coordinate of analog clock. */ +static const int16_t ANALOG_CENTER_X = 32; + +/** Center Y-coordinate of analog clock. */ +static const int16_t ANALOG_CENTER_Y = 31; + +/** Anaolog Clock radius. */ +static const int16_t ANALOG_RADIUS = 31; + /** Factor by which sinus/cosinus values are scaled to use integer math. */ -static const int16_t SINUS_VAL_SCALE = 10000; +static const int16_t SINUS_VAL_SCALE = 10000; + +/** Angle difference between two minute marks on analog clock ring. */ +static const int16_t MINUTES_ANGLE_DELTA = 6; + +/** Each hour mark spawns 5 minutes. */ +static const int16_t MINUTE_HOUR_DELTA = 5; + +/** Number of minute marks on clock. */ +static const int16_t MINUTE_MARKS_COUNT = 12; + +/** Angle difference between 2 hour marks on analog clock ring. */ +static const int16_t HOURS_ANGLE_DELTA = MINUTE_HOUR_DELTA * MINUTES_ANGLE_DELTA; + +/** Pixel length of hour marks on analog clock ring. */ +static const int16_t HOUR_MARK_LENGTH = ANALOG_RADIUS - 4; + +/** Pixel length of hour hand.*/ +static const int16_t HOUR_HAND_LENGTH = ANALOG_RADIUS - 13; + +/** Pixel length of minute hand.*/ +static const int16_t MINUTE_HAND_LENGTH = ANALOG_RADIUS - 6; + +/** Pixel length of second hand.*/ +static const int16_t SECOND_HAND_LENGTH = ANALOG_RADIUS - 2; + +/** Clock hand distance from clock center. */ +static const int16_t HAND_CENTER_DISTANCE = 3; /****************************************************************************** * Types and classes @@ -56,11 +92,11 @@ static const int16_t SINUS_VAL_SCALE = 10000; *****************************************************************************/ /** -* @brief Get the Minute Sinus value -* -* @param[in] angle Minute angle, must be multiple of 6° (360 °/ 60 minutes) -* @return sinus value for angle (scaled by 10.000) -*/ + * @brief Get the Minute Sinus value + * + * @param[in] angle Minute angle, must be multiple of 6° (360 °/ 60 minutes) + * @return sinus value for angle (scaled by 10.000) + */ static int16_t getMinuteSinus(uint16_t angle); /** @@ -71,6 +107,21 @@ static int16_t getMinuteSinus(uint16_t angle); */ static int16_t getMinuteCosinus(uint16_t angle); +/** + * @brief Get hour hand destination minute mark. + * + * The hour hand direction also depends on the elapsed minutes of + * the actual hour to avoid long jumps at hour change. + * + * Example: At 12:30, it should point to the middle between 12 and 1. + * + * @param[in] current hour value + * @param[in] current minute value + * + * @return minute value the hour hand should point to. + */ +static int16_t getHourHandDestination(int hour, int minute); + /****************************************************************************** * Local Variables *****************************************************************************/ @@ -132,19 +183,19 @@ void DateTimeView64x64::update(YAGfx& gfx) /* Draw analog clock minute circle. */ drawAnalogClockBackground(gfx); - + /* Draw analog clock hands. */ drawAnalogClockHand( - gfx, + gfx, m_now.tm_min, - ANALOG_RADIUS - 6, + MINUTE_HAND_LENGTH, m_analogClockCfg.m_colors[ANA_CLK_COL_HAND_MIN]); - drawAnalogClockHand(gfx, - m_now.tm_hour * 5 + m_now.tm_min / 12 , - ANALOG_RADIUS - 13, + drawAnalogClockHand(gfx, + getHourHandDestination(m_now.tm_hour, m_now.tm_min), + HOUR_HAND_LENGTH, m_analogClockCfg.m_colors[ANA_CLK_COL_HAND_HOUR]); - + if (0U != (m_analogClockCfg.m_secondsMode & SECOND_DISP_HAND)) { /* Use second hand color also for the middle ring if this hand is enabled. */ @@ -152,17 +203,19 @@ void DateTimeView64x64::update(YAGfx& gfx) drawAnalogClockHand( gfx, m_now.tm_sec, - ANALOG_RADIUS - 1, + SECOND_HAND_LENGTH, centerRingCol); } - - /* Draw analog clock hand center */ + + /* Draw analog clock hand center + * As it is small, we aproximate the circle with a four pixel rectangle + * and make the four corners black. + */ gfx.drawRectangle(ANALOG_CENTER_X - 2, ANALOG_CENTER_Y - 2, 5, 5, centerRingCol); - gfx.drawPixel(ANALOG_CENTER_X, ANALOG_CENTER_Y, ColorDef::BLACK); - gfx.drawPixel(ANALOG_CENTER_X-2, ANALOG_CENTER_Y-2, ColorDef::BLACK); - gfx.drawPixel(ANALOG_CENTER_X-2, ANALOG_CENTER_Y+2, ColorDef::BLACK); - gfx.drawPixel(ANALOG_CENTER_X+2, ANALOG_CENTER_Y-2, ColorDef::BLACK); - gfx.drawPixel(ANALOG_CENTER_X+2, ANALOG_CENTER_Y+2, ColorDef::BLACK); + gfx.drawPixel(ANALOG_CENTER_X - 2, ANALOG_CENTER_Y - 2, ColorDef::BLACK); + gfx.drawPixel(ANALOG_CENTER_X - 2, ANALOG_CENTER_Y + 2, ColorDef::BLACK); + gfx.drawPixel(ANALOG_CENTER_X + 2, ANALOG_CENTER_Y - 2, ColorDef::BLACK); + gfx.drawPixel(ANALOG_CENTER_X + 2, ANALOG_CENTER_Y + 2, ColorDef::BLACK); } if ((ViewMode::DIGITAL_AND_ANALOG == m_mode) || (ViewMode::DIGITAL_ONLY == m_mode)) @@ -184,21 +237,24 @@ void DateTimeView64x64::update(YAGfx& gfx) void DateTimeView64x64::drawAnalogClockBackground(YAGfx& gfx) { - /* draw minute ring */ - uint16_t secondAngle(270U + m_now.tm_sec * 6U); + /* Draw minute ring starting at 270°, which draws towards the top. + * X-direction is using cos, and cos(270) is 0 (straight up or down). + * Y-direction is using sin, and sin(270) is -1 (going up). + */ + const uint16_t secondAngle = 270U + m_now.tm_sec * MINUTES_ANGLE_DELTA; - for (uint16_t angle = 270U; angle < (270U + 360U); angle += 6U) + for (uint16_t angle = 270U; angle < (270U + 360U); angle += MINUTES_ANGLE_DELTA) { - int16_t dx(getMinuteCosinus(angle)); - int16_t dy(getMinuteSinus(angle)); + const int16_t dx = getMinuteCosinus(angle); + const int16_t dy = getMinuteSinus(angle); - int16_t xs(ANALOG_CENTER_X + (dx * ANALOG_RADIUS) / SINUS_VAL_SCALE); - int16_t ys(ANALOG_CENTER_Y + (dy * ANALOG_RADIUS) / SINUS_VAL_SCALE); + const int16_t xs = ANALOG_CENTER_X + (dx * ANALOG_RADIUS) / SINUS_VAL_SCALE; + const int16_t ys = ANALOG_CENTER_Y + (dy * ANALOG_RADIUS) / SINUS_VAL_SCALE; - if (0U == (angle % 30U)) /* Draw stronger marks at hour angles. */ + if (0U == (angle % HOURS_ANGLE_DELTA)) /* Draw stronger marks at hour angles (each 30°). */ { - int16_t xe(ANALOG_CENTER_X + (dx * (ANALOG_RADIUS - 4)) / SINUS_VAL_SCALE); - int16_t ye(ANALOG_CENTER_Y + (dy * (ANALOG_RADIUS - 4)) / SINUS_VAL_SCALE); + const int16_t xe = ANALOG_CENTER_X + (dx * HOUR_MARK_LENGTH) / SINUS_VAL_SCALE; + const int16_t ye = ANALOG_CENTER_Y + (dy * HOUR_MARK_LENGTH) / SINUS_VAL_SCALE; gfx.drawLine(xs, ys, xe, ye, m_analogClockCfg.m_colors[ANA_CLK_COL_RING_MIN5_MARK]); } @@ -206,8 +262,8 @@ void DateTimeView64x64::drawAnalogClockBackground(YAGfx& gfx) Color tickMarkCol = m_analogClockCfg.m_colors[ANA_CLK_COL_RING_MIN_DOT]; if ((0U != (SECOND_DISP_RING & m_analogClockCfg.m_secondsMode)) && (angle <= secondAngle)) { - /* Draw minute tick marks with passed seconds highlighting. */ - tickMarkCol = m_analogClockCfg.m_colors[ANA_CLK_COL_HAND_SEC]; + /* Draw minute tick marks with passed seconds highlighting. */ + tickMarkCol = m_analogClockCfg.m_colors[ANA_CLK_COL_HAND_SEC]; } gfx.drawPixel(xs, ys, tickMarkCol); } @@ -216,15 +272,15 @@ void DateTimeView64x64::drawAnalogClockBackground(YAGfx& gfx) void DateTimeView64x64::drawAnalogClockHand(YAGfx& gfx, int16_t minute, int16_t radius, const Color& col) { /* Convert minute to angle starting at 270°, which draws towards the top of the clock. */ - minute %= 60; - minute = 270 + minute * 6; + minute %= 60; + minute = 270 + minute * MINUTES_ANGLE_DELTA; - int16_t dx(getMinuteCosinus(minute)); - int16_t dy(getMinuteSinus(minute)); + const int16_t dx = getMinuteCosinus(minute); + const int16_t dy = getMinuteSinus(minute); - gfx.drawLine( - ANALOG_CENTER_X + (3 * dx) / SINUS_VAL_SCALE, - ANALOG_CENTER_Y + (3 * dy) / SINUS_VAL_SCALE, + gfx.drawLine( + ANALOG_CENTER_X + (HAND_CENTER_DISTANCE * dx) / SINUS_VAL_SCALE, + ANALOG_CENTER_Y + (HAND_CENTER_DISTANCE * dy) / SINUS_VAL_SCALE, ANALOG_CENTER_X + (radius * dx) / SINUS_VAL_SCALE, ANALOG_CENTER_Y + (radius * dy) / SINUS_VAL_SCALE, col); @@ -240,34 +296,40 @@ void DateTimeView64x64::drawAnalogClockHand(YAGfx& gfx, int16_t minute, int16_t static int16_t getMinuteSinus(uint16_t angle) { - angle %= 360U; - /* * Lookup table only stores 1st quadrant sinus values. * Others are calculated based on sinus curve symetries. */ - int16_t sinus(0); - if (90U >= angle) /* quadrant 1 */ + int16_t sinus = 0; + + angle %= 360U; + + if (90U >= angle) /* quadrant 1 */ { - sinus = MINUTE_SIN_TAB[angle / 6U]; + sinus = MINUTE_SIN_TAB[angle / MINUTES_ANGLE_DELTA]; } else if (180U >= angle) /* quadrant 2 is symetric to quadrant 1*/ { - sinus = MINUTE_SIN_TAB[(180U - angle) / 6U]; + sinus = MINUTE_SIN_TAB[(180U - angle) / MINUTES_ANGLE_DELTA]; } - else if ( 270U >= angle) /* quadrant 3 is point symetric to 2 */ + else if (270U >= angle) /* quadrant 3 is point symetric to 2 */ { - sinus = (-1) * MINUTE_SIN_TAB[(angle - 180U) / 6U]; + sinus = (-1) * MINUTE_SIN_TAB[(angle - 180U) / MINUTES_ANGLE_DELTA]; } else /* quadrant 4 is symetric to 3 */ { - sinus = (-1) * MINUTE_SIN_TAB[(360 - angle) / 6U]; + sinus = (-1) * MINUTE_SIN_TAB[(360 - angle) / MINUTES_ANGLE_DELTA]; } return sinus; } -int16_t getMinuteCosinus(uint16_t angle) +static int16_t getMinuteCosinus(uint16_t angle) { return getMinuteSinus(angle + 90U); } + +static int16_t getHourHandDestination(int hour, int minute) +{ + return (hour * MINUTE_HOUR_DELTA) + (minute / MINUTE_MARKS_COUNT); +} diff --git a/lib/Views/src/layouts/DateTimeView64x64.h b/lib/Views/src/layouts/DateTimeView64x64.h index f81ac842..5ab429b5 100644 --- a/lib/Views/src/layouts/DateTimeView64x64.h +++ b/lib/Views/src/layouts/DateTimeView64x64.h @@ -175,22 +175,6 @@ class DateTimeView64x64 : public DateTimeViewGeneric ViewMode m_mode; /**< Used View mode analog, digital or both. */ AnalogClockConfig m_analogClockCfg; /**< The clock drawing configuration options. */ - - /** - * Center x-coordinate of analog clock - */ - static const int16_t ANALOG_CENTER_X = 32; - - /** - * Center y-coordinate of analog clock - */ - static const int16_t ANALOG_CENTER_Y = 31; - - /** - * Anaolog Clock radius - */ - static const int16_t ANALOG_RADIUS = 31; - /** * Seconds value of last display update. Used to avoid unecessary redrawing. */ diff --git a/src/Web/Pages.cpp b/src/Web/Pages.cpp index 6620ad42..444a7ab6 100644 --- a/src/Web/Pages.cpp +++ b/src/Web/Pages.cpp @@ -161,8 +161,8 @@ static TmplKeyWordFunc gTmplKeyWordToFunc[] = "WS_ENDPOINT", []() -> String { return WebConfig::WEBSOCKET_PATH; }, "WS_PORT", []() -> String { return String(WebConfig::WEBSOCKET_PORT); }, "WS_PROTOCOL", []() -> String { return WebConfig::WEBSOCKET_PROTOCOL; }, - "DISPLAY_HEIGHT", []() -> String { return String(Display::getInstance().getHeight()); }, - "DISPLAY_WIDTH", []() -> String { return String(Display::getInstance().getWidth()); } + "DISPLAY_HEIGHT", []() -> String { return String(CONFIG_LED_MATRIX_HEIGHT); }, + "DISPLAY_WIDTH", []() -> String { return String(CONFIG_LED_MATRIX_WIDTH); } }; /****************************************************************************** From ae5f4b3a90624e1e4ae0526df2c49ec206ff1cec Mon Sep 17 00:00:00 2001 From: nhjschulz Date: Wed, 6 Nov 2024 19:55:39 +0100 Subject: [PATCH 3/4] DateTimePlugin: XHTML format fixes User proper " />" terminator if body is empty. --- lib/DateTimePlugin/web/DateTimePlugin.html | 28 +++++++++++----------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/lib/DateTimePlugin/web/DateTimePlugin.html b/lib/DateTimePlugin/web/DateTimePlugin.html index 9be5d66c..1590b479 100644 --- a/lib/DateTimePlugin/web/DateTimePlugin.html +++ b/lib/DateTimePlugin/web/DateTimePlugin.html @@ -117,7 +117,7 @@

Display

- +
- + - + - +
@@ -145,17 +145,17 @@

Display

- + - + - + - +
@@ -167,13 +167,13 @@

Display

- +
- +
- +
@@ -185,17 +185,17 @@

Display

- +
- +
- + From 9f39572432743e3722d21fb029f2bac765e61a8e Mon Sep 17 00:00:00 2001 From: nhjschulz Date: Wed, 6 Nov 2024 20:04:46 +0100 Subject: [PATCH 4/4] Pages.cpp: Removed obsolete header --- src/Web/Pages.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Web/Pages.cpp b/src/Web/Pages.cpp index 444a7ab6..a4efabc5 100644 --- a/src/Web/Pages.cpp +++ b/src/Web/Pages.cpp @@ -37,7 +37,6 @@ #include "Version.h" #include "UpdateMgr.h" #include "DisplayMgr.h" -#include "Display.h" #include "RestApi.h" #include "PluginList.h" #include "WiFiUtil.h"