// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved. // For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md #include "timeWidget.hpp" #include "SettingsStyle.hpp" #include #include namespace gui { TimeWidget::TimeWidget(Item *parent, const std::string &description, std::function bottomBarTemporaryMode, std::function bottomBarRestoreFromTemporaryMode) : VBox(parent, 0, 0, style::window::default_body_width, style::settings::widget::time::h), bottomBarTemporaryMode(std::move(bottomBarTemporaryMode)), bottomBarRestoreFromTemporaryMode(std::move(bottomBarRestoreFromTemporaryMode)) { setEdges(RectangleEdge::None); descriptionLabel = new gui::Label( this, 0, 0, style::window::default_body_width, style::settings::widget::time::description_label_h); descriptionLabel->setEdges(gui::RectangleEdge::None); descriptionLabel->setAlignment(Alignment(gui::Alignment::Horizontal::Left, gui::Alignment::Vertical::Center)); descriptionLabel->setFont(style::window::font::small); descriptionLabel->activeItem = false; descriptionLabel->setText(description); hBox = new gui::HBox(this, 0, 0, style::window::default_body_width, style::settings::widget::time::body_h); hBox->setEdges(gui::RectangleEdge::None); hBox->activeItem = false; hourInput = new gui::Text(hBox, 0, 0, style::settings::widget::time::input_w, style::settings::widget::time::body_h); hourInput->setEdges(gui::RectangleEdge::Bottom); hourInput->setAlignment(gui::Alignment(gui::Alignment::Horizontal::Center, gui::Alignment::Vertical::Center)); hourInput->setFont(style::window::font::largelight); hourInput->setInputMode(new InputMode({InputMode::digit})); hourInput->setPenFocusWidth(style::window::default_border_focus_w); hourInput->setPenWidth(style::window::default_border_rect_no_focus); hourInput->setEditMode(gui::EditMode::Edit); colonLabel = new gui::Label( hBox, 0, 0, style::settings::widget::time::separator_w, style::settings::widget::time::body_h); colonLabel->setEdges(gui::RectangleEdge::None); colonLabel->setAlignment(Alignment(gui::Alignment::Horizontal::Center, gui::Alignment::Vertical::Center)); colonLabel->setFont(style::window::font::medium); colonLabel->setText(":"); colonLabel->activeItem = false; minuteInput = new gui::Text(hBox, 0, 0, style::settings::widget::time::input_w, style::settings::widget::time::body_h); minuteInput->setEdges(gui::RectangleEdge::Bottom); minuteInput->setAlignment(gui::Alignment(gui::Alignment::Horizontal::Center, gui::Alignment::Vertical::Center)); minuteInput->setFont(style::window::font::largelight); minuteInput->setInputMode(new InputMode({InputMode::digit})); minuteInput->setPenFocusWidth(style::window::default_border_focus_w); minuteInput->setPenWidth(style::window::default_border_rect_no_focus); minuteInput->setEditMode(gui::EditMode::Edit); separatorLabel = new gui::Label( hBox, 0, 0, style::settings::widget::time::separator_w, style::settings::widget::time::body_h); separatorLabel->setEdges(gui::RectangleEdge::None); separatorLabel->activeItem = false; meridiemInput = new gui::Label(hBox, 0, 0, style::settings::widget::time::input_w, style::settings::widget::time::body_h); meridiemInput->setEdges(gui::RectangleEdge::Bottom); meridiemInput->setAlignment( gui::Alignment(gui::Alignment::Horizontal::Center, gui::Alignment::Vertical::Center)); meridiemInput->setFont(style::window::font::largelight); meridiemInput->setPenFocusWidth(style::window::default_border_focus_w); meridiemInput->setPenWidth(style::window::default_border_rect_no_focus); applyFocusCallbacks(); applyInputCallbacks(); setTime(std::chrono::minutes(style::settings::widget::time::default_time_in_minutes)); } auto TimeWidget::getTime() const noexcept -> std::chrono::minutes { std::chrono::minutes currentTimeDuration; int currentHourRaw; int currentMinutesRaw; try { currentHourRaw = std::stoi(hourInput->getText()); } catch (const std::exception &e) { LOG_ERROR("TimeWidget::getTime::currentHourRaw %s", e.what()); currentHourRaw = 0; } if (meridiemInput->getText() == style::settings::widget::time::after_noon) { currentHourRaw += style::settings::widget::time::max_hour; } try { currentMinutesRaw = std::stoi(minuteInput->getText()); } catch (const std::exception &e) { LOG_ERROR("TimeWidget::getTime::currentMinutesRaw %s", e.what()); currentMinutesRaw = 0; } currentTimeDuration = std::chrono::hours(currentHourRaw); currentTimeDuration += std::chrono::minutes(currentMinutesRaw); return currentTimeDuration; } void TimeWidget::setTime(std::chrono::minutes newTimeMinutes) { auto isPm = false; auto newTimeHours = std::chrono::duration_cast(newTimeMinutes); newTimeMinutes -= std::chrono::duration_cast(newTimeHours); auto newHourRaw = newTimeHours.count(); auto newMinuteRaw = newTimeMinutes.count(); if (newHourRaw > style::settings::widget::time::max_hour) { newHourRaw -= style::settings::widget::time::max_hour; isPm = true; } hourInput->setText(std::to_string(newHourRaw)); minuteInput->setText(std::to_string(newMinuteRaw)); if (isPm) { meridiemInput->setText(style::settings::widget::time::after_noon); } else { meridiemInput->setText(style::settings::widget::time::before_noon); } } void TimeWidget::applyFocusCallbacks() { focusChangedCallback = [&](Item &item) { setFocusItem(focus ? hBox : nullptr); return true; }; hourInput->focusChangedCallback = [&](Item &item) { if (!item.focus) { if (hourInput->isEmpty()) { hourInput->setText(style::settings::widget::time::default_input_string); } } return true; }; minuteInput->focusChangedCallback = [&](Item &item) { if (!item.focus) { if (minuteInput->isEmpty()) { minuteInput->setText(style::settings::widget::time::default_input_string); } } return true; }; meridiemInput->focusChangedCallback = [&](Item &item) { if (item.focus) { bottomBarTemporaryMode(utils::localize.get("common_switch")); } else { bottomBarRestoreFromTemporaryMode(); } return true; }; } void TimeWidget::applyInputCallbacks() { inputCallback = [&](Item &item, const InputEvent &event) { auto focusedItem = getFocusItem(); if (!event.isShortPress()) { return false; } if (event.is(gui::KeyCode::KEY_ENTER) || event.is(gui::KeyCode::KEY_RF)) { return false; } if (focusedItem->onInput(event)) { return readTimeFromInputFields(); } else if (hBox->onInput(event)) { return true; } return false; }; auto isMoveDeleteSaveEvent = [](auto inputEvent) { return inputEvent.is(gui::KeyCode::KEY_LEFT) || inputEvent.is(gui::KeyCode::KEY_RIGHT) || inputEvent.is(gui::KeyCode::KEY_PND) || inputEvent.is(gui::KeyCode::KEY_UP) || inputEvent.is(gui::KeyCode::KEY_DOWN) || inputEvent.is(gui::KeyCode::KEY_RF) || inputEvent.is(gui::KeyCode::KEY_ENTER); }; hourInput->inputCallback = [&](Item &item, const InputEvent &event) { if (!event.isShortPress()) { return false; } if (hourInput->getText().length() > 1 && !isMoveDeleteSaveEvent(event)) { return true; } return false; }; minuteInput->inputCallback = [&](Item &item, const InputEvent &event) { if (!event.isShortPress()) { return false; } if (minuteInput->getText().length() > 1 && !isMoveDeleteSaveEvent(event)) { return true; } return false; }; meridiemInput->inputCallback = [&](Item &item, const InputEvent &event) { if (!event.isShortPress()) { return false; } if (event.is(gui::KeyCode::KEY_LF)) { if (meridiemInput->getText() == style::settings::widget::time::before_noon) { meridiemInput->setText(style::settings::widget::time::after_noon); } else { meridiemInput->setText(style::settings::widget::time::before_noon); } return true; } return false; }; } auto TimeWidget::readTimeFromInputFields() const -> bool { uint32_t hours; uint32_t minutes; try { hours = std::stoi(hourInput->getText().c_str()); } catch (const std::exception &e) { LOG_ERROR("EventTimeItem::applyInputCallbacks hours: %s", e.what()); return false; } try { minutes = std::stoi(minuteInput->getText().c_str()); } catch (const std::exception &e) { LOG_ERROR("EventTimeItem::applyInputCallbacks minutes: %s", e.what()); return false; } if (hours > style::settings::widget::time::max_hour) { hourInput->setText(style::settings::widget::time::max_hour_string); } if (minutes > style::settings::widget::time::max_minutes) { minuteInput->setText(style::settings::widget::time::max_minutes_string); } return true; } } /* namespace gui */