| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336 |
- /*
- *
- * Copyright (c) 2020 Project CHIP Authors
- * All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- /**
- * @file ScreenManager.cpp
- *
- * Simple screen manager.
- *
- */
- #include "ScreenManager.h"
- #if CONFIG_HAVE_DISPLAY
- #include <lib/support/CHIPMem.h>
- #include <cassert>
- #include <vector>
- uint16_t ScreenFontHeight;
- uint16_t ScreenTitleSafeTop;
- uint16_t ScreenTitleSafeBottom;
- color_t ScreenNormalColor = { 255, 255, 255 };
- color_t ScreenFocusColor = { 128, 128, 255 };
- color_t ScreenButtonColor = { 64, 64, 64 };
- namespace {
- constexpr int kMainFont = DEJAVU24_FONT;
- constexpr int kButtonFont = DEJAVU18_FONT;
- constexpr int kVLEDWidth = 16;
- constexpr int kVLEDHeight = 16;
- SemaphoreHandle_t mutex;
- struct Lock
- {
- Lock() { xSemaphoreTakeRecursive(mutex, portMAX_DELAY); }
- ~Lock() { xSemaphoreGiveRecursive(mutex); }
- };
- struct VLED
- {
- color_t color;
- color_t color_off;
- bool on;
- VLED(color_t color) : color(color), on(false)
- {
- color_off = color;
- color_off.r &= 0x1F;
- color_off.g &= 0x1F;
- color_off.b &= 0x1F;
- }
- };
- std::vector<VLED> vleds;
- std::vector<Screen *> screens;
- bool focusBack = false;
- int lazyDisplay = 0;
- bool dirtyDisplay = false;
- struct LazyDisplay
- {
- LazyDisplay() { ++lazyDisplay; }
- ~LazyDisplay()
- {
- if (--lazyDisplay == 0)
- {
- if (dirtyDisplay)
- {
- ScreenManager::Display();
- dirtyDisplay = false;
- }
- }
- }
- };
- // Print text centered horizontally at x.
- void PrintCentered(const char * s, int x, int y)
- {
- TFT_print(s, x - (TFT_getStringWidth(s) / 2), y);
- }
- // Print button text in appropriate location (1 to 3).
- void DisplayButtonText(int id, const char * s)
- {
- tft_fg = ScreenButtonColor;
- int x = (DisplayWidth / 2) + (id - 2) * (DisplayWidth * 3 / 10);
- PrintCentered(s, x, DisplayHeight - (ScreenTitleSafeBottom / 2)); // within ScreenTitleSafeBottom
- }
- void DisplayVLED(int id)
- {
- TFT_fillRect(0, ScreenFontHeight * 3 / 2 + id * (kVLEDHeight + 2), kVLEDWidth, kVLEDHeight,
- vleds[id].on ? vleds[id].color : vleds[id].color_off);
- }
- } // namespace
- namespace ScreenManager {
- void Init()
- {
- mutex = xSemaphoreCreateRecursiveMutex();
- // https://github.com/loboris/ESP32_TFT_library/issues/48
- TFT_setFont(kButtonFont, nullptr);
- ScreenTitleSafeBottom = TFT_getfontheight() * 2;
- TFT_setFont(kMainFont, nullptr);
- ScreenFontHeight = TFT_getfontheight();
- ScreenTitleSafeTop = ScreenFontHeight * 5 / 2;
- }
- void Display()
- {
- Lock lock;
- if (lazyDisplay)
- {
- dirtyDisplay = true;
- return;
- }
- TFT_fillScreen(TFT_BLACK);
- TFT_setFont(kMainFont, nullptr);
- if (screens.empty())
- {
- tft_fg = TFT_RED;
- PrintCentered("No Screen", DisplayWidth / 2, DisplayHeight / 2);
- return;
- }
- if (screens.size() > 1)
- {
- tft_fg = focusBack ? ScreenFocusColor : ScreenNormalColor;
- TFT_print("<", ScreenFontHeight, ScreenFontHeight / 2);
- }
- std::string title = screens.back()->GetTitle();
- tft_fg = ScreenNormalColor;
- TFT_print(title.c_str(), ScreenTitleSafeTop, ScreenFontHeight / 2); // within ScreenTitleSafeTop
- TFT_drawRect(ScreenTitleSafeTop, ScreenFontHeight * 3 / 2, TFT_getStringWidth(title.c_str()), 2, ScreenNormalColor);
- TFT_setFont(kButtonFont, nullptr);
- if (screens.back()->IsFocusable())
- {
- DisplayButtonText(1, screens.back()->GetButtonText(1).c_str());
- DisplayButtonText(2, screens.back()->GetButtonText(2).c_str());
- }
- if (focusBack)
- {
- DisplayButtonText(3, "Back");
- }
- else if (screens.back()->IsFocusable())
- {
- DisplayButtonText(3, screens.back()->GetButtonText(3).c_str());
- }
- TFT_setFont(kMainFont, nullptr);
- for (int i = 0; i < vleds.size(); ++i)
- {
- DisplayVLED(i);
- }
- screens.back()->Display();
- }
- void ButtonPressed(int id)
- {
- Lock lock;
- LazyDisplay lazy;
- if (screens.empty())
- {
- return;
- }
- if (focusBack && id == 3)
- {
- PopScreen();
- }
- else if (screens.back()->IsFocusable())
- {
- switch (id)
- {
- case 1:
- focusBack = false;
- screens.back()->Focus(Screen::FocusType::PREVIOUS);
- break;
- case 2:
- focusBack = false;
- screens.back()->Focus(Screen::FocusType::NEXT);
- break;
- case 3:
- screens.back()->Action();
- break;
- }
- Display();
- }
- }
- void PushScreen(Screen * screen)
- {
- Lock lock;
- LazyDisplay lazy;
- if (!screens.empty())
- {
- if (screens.back()->IsFocusable())
- {
- screens.back()->Focus(Screen::FocusType::BLUR);
- }
- screens.back()->Exit(false);
- }
- screen->Enter(true); // screen is not top when enter/pushed
- screens.push_back(screen); // screen is pushed immediately after first enter
- focusBack = false;
- if (screens.back()->IsFocusable())
- {
- screens.back()->Focus(Screen::FocusType::NEXT);
- }
- else
- {
- focusBack = true;
- }
- Display();
- }
- void PopScreen()
- {
- Lock lock;
- LazyDisplay lazy;
- if (screens.empty())
- {
- return;
- }
- Screen * screen = screens.back();
- screens.pop_back(); // screen is popped immediately before last exit
- screen->Exit(true); // screen is not top when exit/popped
- chip::Platform::Delete(screen);
- focusBack = false;
- if (!screens.empty())
- {
- screens.back()->Enter(false);
- if (screens.back()->IsFocusable())
- {
- screens.back()->Focus(Screen::FocusType::UNBLUR);
- }
- else
- {
- focusBack = true;
- }
- }
- Display();
- }
- void FocusBack()
- {
- Lock lock;
- if (screens.size() > 1)
- {
- focusBack = true;
- if (screens.back()->IsFocusable())
- {
- screens.back()->Focus(Screen::FocusType::NONE);
- }
- }
- else
- {
- focusBack = false;
- }
- }
- int AddVLED(color_t color)
- {
- Lock lock;
- int id = vleds.size();
- vleds.emplace_back(color);
- DisplayVLED(id);
- return id;
- }
- void SetVLED(int id, bool on)
- {
- Lock lock;
- if (vleds[id].on == on)
- {
- return;
- }
- vleds[id].on = on;
- DisplayVLED(id);
- WakeDisplay();
- }
- void ToggleVLED(int id)
- {
- Lock lock;
- vleds[id].on = !vleds[id].on;
- DisplayVLED(id);
- WakeDisplay();
- }
- } // namespace ScreenManager
- #endif // CONFIG_HAVE_DISPLAY
|