From 9edd5665305502e2b18317d99c62b62152065d1e Mon Sep 17 00:00:00 2001 From: Mateusz Piesta Date: Thu, 29 Jul 2021 11:57:15 +0200 Subject: [PATCH] [BH-678] Add TimeSetFmtSpinner widget Added time set spinner widget with dynamic switching between time formats(24/12H). --- .../models/TimeUnitsModel.cpp | 10 +- .../widgets/TimeSetSpinnerListItem.cpp | 20 +- .../widgets/TimeSetSpinnerListItem.hpp | 4 +- module-apps/apps-common/CMakeLists.txt | 3 + .../apps-common/widgets/TimeSetFmtSpinner.cpp | 195 ++++++++++++++++++ .../apps-common/widgets/TimeSetFmtSpinner.hpp | 67 ++++++ .../apps-common/widgets/TimeSetSpinner.cpp | 39 +++- .../apps-common/widgets/TimeSetSpinner.hpp | 14 ++ module-gui/gui/widgets/Spinner.cpp | 10 +- module-gui/gui/widgets/Spinner.hpp | 3 + module-gui/gui/widgets/TextSpinner.cpp | 2 +- module-utils/time/time/time_locale.hpp | 9 +- 12 files changed, 352 insertions(+), 24 deletions(-) create mode 100644 module-apps/apps-common/widgets/TimeSetFmtSpinner.cpp create mode 100644 module-apps/apps-common/widgets/TimeSetFmtSpinner.hpp diff --git a/module-apps/application-bell-settings/models/TimeUnitsModel.cpp b/module-apps/application-bell-settings/models/TimeUnitsModel.cpp index 52c3e704d4b524a96f09fd417b314c10512a4f12..c9dc0e1ea70d8b1620fdab172fc1276675bbbabe 100644 --- a/module-apps/application-bell-settings/models/TimeUnitsModel.cpp +++ b/module-apps/application-bell-settings/models/TimeUnitsModel.cpp @@ -3,7 +3,7 @@ #include "TimeUnitsModel.hpp" -#include +#include #include #include #include @@ -57,8 +57,8 @@ namespace app::bell_settings { std::time_t now = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now()); struct std::tm *newTime = std::localtime(&now); - newTime->tm_hour = timeSetWidget->timeSetSpinner->getHour(); - newTime->tm_min = timeSetWidget->timeSetSpinner->getMinute(); + newTime->tm_hour = timeSetWidget->timeSetFmtSpinner->getHour(); + newTime->tm_min = timeSetWidget->timeSetFmtSpinner->getMinute(); LOG_INFO("Setting new time: %d:%d", newTime->tm_hour, newTime->tm_min); sendRtcUpdateTimeMessage(std::mktime(newTime)); } @@ -66,8 +66,8 @@ namespace app::bell_settings void TimeUnitsModel::loadData() { std::time_t now = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now()); - timeSetWidget->timeSetSpinner->setHour(std::localtime(&now)->tm_hour); - timeSetWidget->timeSetSpinner->setMinute(std::localtime(&now)->tm_min); + timeSetWidget->timeSetFmtSpinner->setHour(std::localtime(&now)->tm_hour); + timeSetWidget->timeSetFmtSpinner->setMinute(std::localtime(&now)->tm_min); } auto TimeUnitsModel::requestRecords(uint32_t offset, uint32_t limit) -> void diff --git a/module-apps/application-bell-settings/widgets/TimeSetSpinnerListItem.cpp b/module-apps/application-bell-settings/widgets/TimeSetSpinnerListItem.cpp index c61dc59dbf5990d6af97625b848d91ded1295238..0f3680e79b5b6cbe785c3747ec9b272c0e235cf7 100644 --- a/module-apps/application-bell-settings/widgets/TimeSetSpinnerListItem.cpp +++ b/module-apps/application-bell-settings/widgets/TimeSetSpinnerListItem.cpp @@ -4,7 +4,8 @@ #include "BellSettingsStyle.hpp" #include "TimeSetSpinnerListItem.hpp" -#include +#include +#include namespace gui { @@ -13,16 +14,21 @@ namespace gui : SideListItem(std::move(description)) { setMinimumSize(style::sidelistview::list_item::w, style::sidelistview::list_item::h); - - timeSetSpinner = new TimeSetSpinner(body, 0, 0, 0, 0); - timeSetSpinner->setMinimumSize(gui::bell_settings_style::time_set_spinner_list_item::w, - gui::bell_settings_style::time_set_spinner_list_item::h); - body->setFocusItem(timeSetSpinner); + timeSetFmtSpinner = new TimeSetFmtSpinner(body); + timeSetFmtSpinner->setMinimumSize(gui::bell_settings_style::time_set_spinner_list_item::w, + gui::bell_settings_style::time_set_spinner_list_item::h); + setFocusItem(body); dimensionChangedCallback = [&](gui::Item &, const BoundingBox &newDim) -> bool { body->setArea({0, 0, newDim.w, newDim.h}); return true; }; - inputCallback = [&](gui::Item &item, const gui::InputEvent &event) { return body->onInput(event); }; + + focusChangedCallback = [&](Item &item) { + setFocusItem(focus ? body : nullptr); + return true; + }; + + inputCallback = [&](Item &, const InputEvent &inputEvent) -> bool { return body->onInput(inputEvent); }; } } /* namespace gui */ diff --git a/module-apps/application-bell-settings/widgets/TimeSetSpinnerListItem.hpp b/module-apps/application-bell-settings/widgets/TimeSetSpinnerListItem.hpp index 77fe38b1281b49b60f766b4c3d5f74c92d2cea24..a402f44ba54e5e1ffa6dceadc71edda060403915 100644 --- a/module-apps/application-bell-settings/widgets/TimeSetSpinnerListItem.hpp +++ b/module-apps/application-bell-settings/widgets/TimeSetSpinnerListItem.hpp @@ -9,12 +9,12 @@ namespace gui { - class TimeSetSpinner; + class TimeSetFmtSpinner; class TimeSetSpinnerListItem : public SideListItem { public: - TimeSetSpinner *timeSetSpinner = nullptr; + TimeSetFmtSpinner *timeSetFmtSpinner = nullptr; TimeSetSpinnerListItem(gui::Length x, gui::Length y, gui::Length w, gui::Length h, std::string description); }; diff --git a/module-apps/apps-common/CMakeLists.txt b/module-apps/apps-common/CMakeLists.txt index 07a4328afce3980c6614de787ea977481a0b6e99..6ce0435cb8e9721e81b945109a5c4ba6cd66af03 100644 --- a/module-apps/apps-common/CMakeLists.txt +++ b/module-apps/apps-common/CMakeLists.txt @@ -38,12 +38,15 @@ target_sources(apps-common widgets/TextWithIconsWidget.cpp widgets/TimeSetSpinner.cpp widgets/AlarmSetSpinner.cpp + widgets/TimeSetFmtSpinner.cpp widgets/TimeWidget.cpp widgets/WidgetsUtils.cpp windows/AppWindow.cpp windows/BrightnessWindow.cpp windows/Dialog.cpp windows/OptionWindow.cpp + PUBLIC + widgets/TimeSetFmtSpinner.hpp ) add_subdirectory(popups) diff --git a/module-apps/apps-common/widgets/TimeSetFmtSpinner.cpp b/module-apps/apps-common/widgets/TimeSetFmtSpinner.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e3e73ce1bfe98e061529737a327c846b4da4bdbd --- /dev/null +++ b/module-apps/apps-common/widgets/TimeSetFmtSpinner.cpp @@ -0,0 +1,195 @@ +// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved. +// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md + +#include "TimeSetFmtSpinner.hpp" + +#include "TimeSetSpinner.hpp" + +#include +#include +#include +#include +#include + +namespace +{ + constexpr auto fmtSpinnerAMPos = 0U; + constexpr auto fmtSpinnerPMPos = 1U; +} // namespace + +namespace gui +{ + + TimeSetFmtSpinner::TimeSetFmtSpinner( + Item *parent, uint32_t x, uint32_t y, uint32_t w, uint32_t h, utils::time::Locale::TimeFormat timeFormat) + : HBox{parent, x, y, w, h} + { + using namespace utils; + + setAlignment(Alignment(Alignment::Horizontal::Center, Alignment::Vertical::Center)); + setEdges(RectangleEdge::None); + + timeSetSpinner = new TimeSetSpinner(this, 0, 0, 0, 0); + timeSetSpinner->setFont(fontName); + timeSetSpinner->setAlignment(Alignment(Alignment::Horizontal::Center, Alignment::Vertical::Center)); + timeSetSpinner->setMargins(Margins(0, 0, 0, 0)); + + auto minSize = getMinimumFmtSize(); + auto textRange = TextSpinner::TextRange{time::Locale::getAM(), time::Locale::getPM()}; + fmt = new TextSpinner(textRange, Boundaries::Continuous); + fmt->setMinimumSize(minSize.first, minSize.second); + fmt->setFont(fontName); + fmt->setAlignment(Alignment(Alignment::Horizontal::Center, Alignment::Vertical::Center)); + fmt->setEdges(RectangleEdge::None); + fmt->setVisible(false); + fmt->setPenFocusWidth(style::time_set_spinner::focus::size); + addWidget(fmt); + fmt->setEdges(RectangleEdge::Bottom); + + focusChangedCallback = [&](Item &) { + setFocusItem(focus ? timeSetSpinner : nullptr); + return true; + }; + + setTimeFormat(timeFormat); + } + + auto TimeSetFmtSpinner::setTimeFormat(utils::time::Locale::TimeFormat newFormat) noexcept -> void + { + using namespace utils; + timeFormat = newFormat; + switch (timeFormat) { + case utils::time::Locale::TimeFormat::FormatTime12H: { + fmt->setVisible(true); + timeSetSpinner->setHourMax(time::Locale::max_hour_12H_mode); + timeSetSpinner->setHourMin(time::Locale::min_hour_12H_mode); + + auto hours = std::chrono::hours(timeSetSpinner->getHour()); + timeSetSpinner->setHour(date::make12(hours).count()); + if (date::is_pm(hours)) { + fmt->setCurrentPosition(fmtSpinnerPMPos); + } + else { + fmt->setCurrentPosition(fmtSpinnerAMPos); + } + } break; + case utils::time::Locale::TimeFormat::FormatTime24H: { + fmt->setVisible(false); + timeSetSpinner->setHourMax(time::Locale::max_hour_24H_mode); + timeSetSpinner->setHourMin(time::Locale::min_hour_24H_mode); + + auto hours = std::chrono::hours(timeSetSpinner->getHour()); + timeSetSpinner->setHour(date::make24(hours, isPm(fmt->getCurrentText())).count()); + } break; + default: + break; + } + + resizeItems(); + + // If we make 12->24 switch while focused on fmt then change focus to hour + if (focusItem == fmt) { + setFocusItem(timeSetSpinner); + } + } + + auto TimeSetFmtSpinner::setMinute(int value) noexcept -> void + { + timeSetSpinner->setMinute(value); + } + + auto TimeSetFmtSpinner::setEditMode(EditMode newEditMode) noexcept -> void + { + editMode = newEditMode; + if (editMode == EditMode::Edit) { + setFocusItem(timeSetSpinner); + } + else { + setFocusItem(nullptr); + } + } + auto TimeSetFmtSpinner::getHour() const noexcept -> int + { + return timeSetSpinner->getHour(); + } + auto TimeSetFmtSpinner::getMinute() const noexcept -> int + { + return timeSetSpinner->getMinute(); + } + + auto TimeSetFmtSpinner::getFontHeight() const noexcept -> uint16_t + { + const auto font = FontManager::getInstance().getFont(fontName); + return font->info.line_height; + } + auto TimeSetFmtSpinner::getMinimumFmtSize() const noexcept -> std::pair + { + constexpr auto spacer = 5U; // space between two chars + const auto font = FontManager::getInstance().getFont(fontName); + return {font->getPixelWidth(utils::time::Locale::getAM()) + spacer, font->info.line_height}; + } + auto TimeSetFmtSpinner::setHour(int value) noexcept -> void + { + timeSetSpinner->setHour(value); + } + auto TimeSetFmtSpinner::setFont(std::string newFontName) noexcept -> void + { + fontName = std::move(newFontName); + auto fontHeight = getFontHeight(); + auto minFmtSize = getMinimumFmtSize(); + + timeSetSpinner->setFont(fontName); + fmt->setFont(fontName); + fmt->setMinimumSize(minFmtSize.first, minFmtSize.second); + fmt->setText(fmt->getText()); + + setMinimumSize(timeSetSpinner->getMinimumSize().first + minFmtSize.first, fontHeight); + resizeItems(); + } + + auto TimeSetFmtSpinner::onInput(const InputEvent &inputEvent) -> bool + { + // Ignore input event when not in edit mode + if (editMode != EditMode::Edit) { + return false; + } + + if (auto ret = this->focusItem->onInput(inputEvent)) { + return ret; + } + + if (inputEvent.isShortRelease()) { + switch (inputEvent.getKeyCode()) { + case KeyCode::KEY_ENTER: + return handleEnterKey(); + case KeyCode::KEY_RF: + return handleRightFunctionKey(); + + default: + break; + } + } + return false; + } + auto TimeSetFmtSpinner::handleEnterKey() -> bool + { + if (focusItem == timeSetSpinner) { + setFocusItem(fmt); + return true; + } + return false; + } + auto TimeSetFmtSpinner::handleRightFunctionKey() -> bool + { + if (focusItem == fmt) { + setFocusItem(timeSetSpinner); + return true; + } + + return false; + } + auto TimeSetFmtSpinner::isPm(const std::string_view str) const noexcept -> bool + { + return str == utils::time::Locale::getPM().c_str(); + } +} // namespace gui \ No newline at end of file diff --git a/module-apps/apps-common/widgets/TimeSetFmtSpinner.hpp b/module-apps/apps-common/widgets/TimeSetFmtSpinner.hpp new file mode 100644 index 0000000000000000000000000000000000000000..e0ac2eef7fd6495b3371c2f71a4844bbdfb30f02 --- /dev/null +++ b/module-apps/apps-common/widgets/TimeSetFmtSpinner.hpp @@ -0,0 +1,67 @@ +// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved. +// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md + +#pragma once + +#include +#include +#include