3 * Copyright (c) 2020 Project CHIP Authors
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
20 * @file ScreenManager.cpp
22 * Simple screen manager.
26 #include "ScreenManager.h"
28 #if CONFIG_HAVE_DISPLAY
30 #include <support/CHIPMem.h>
35 uint16_t ScreenFontHeight;
36 uint16_t ScreenTitleSafeTop;
37 uint16_t ScreenTitleSafeBottom;
39 color_t ScreenNormalColor = { 255, 255, 255 };
40 color_t ScreenFocusColor = { 128, 128, 255 };
41 color_t ScreenButtonColor = { 64, 64, 64 };
45 constexpr int kMainFont = DEJAVU24_FONT;
46 constexpr int kButtonFont = DEJAVU18_FONT;
48 constexpr int kVLEDWidth = 16;
49 constexpr int kVLEDHeight = 16;
51 SemaphoreHandle_t mutex;
55 Lock() { xSemaphoreTakeRecursive(mutex, portMAX_DELAY); }
56 ~Lock() { xSemaphoreGive(mutex); }
64 VLED(color_t color) : color(color), on(false)
73 std::vector<VLED> vleds;
75 std::vector<Screen *> screens;
77 bool focusBack = false;
80 bool dirtyDisplay = false;
84 LazyDisplay() { ++lazyDisplay; }
87 if (--lazyDisplay == 0)
91 ScreenManager::Display();
98 // Print text centered horizontally at x.
99 void PrintCentered(const char * s, int x, int y)
101 TFT_print(s, x - (TFT_getStringWidth(s) / 2), y);
104 // Print button text in appropriate location (1 to 3).
105 void DisplayButtonText(int id, const char * s)
107 tft_fg = ScreenButtonColor;
108 int x = (DisplayWidth / 2) + (id - 2) * (DisplayWidth * 3 / 10);
109 PrintCentered(s, x, DisplayHeight - (ScreenTitleSafeBottom / 2)); // within ScreenTitleSafeBottom
112 void DisplayVLED(int id)
114 TFT_fillRect(0, ScreenFontHeight * 3 / 2 + id * (kVLEDHeight + 2), kVLEDWidth, kVLEDHeight,
115 vleds[id].on ? vleds[id].color : vleds[id].color_off);
120 namespace ScreenManager {
124 mutex = xSemaphoreCreateRecursiveMutex();
126 // https://github.com/loboris/ESP32_TFT_library/issues/48
127 TFT_setFont(kButtonFont, nullptr);
128 ScreenTitleSafeBottom = TFT_getfontheight() * 2;
129 TFT_setFont(kMainFont, nullptr);
130 ScreenFontHeight = TFT_getfontheight();
131 ScreenTitleSafeTop = ScreenFontHeight * 5 / 2;
144 TFT_fillScreen(TFT_BLACK);
145 TFT_setFont(kMainFont, nullptr);
150 PrintCentered("No Screen", DisplayWidth / 2, DisplayHeight / 2);
154 if (screens.size() > 1)
156 tft_fg = focusBack ? ScreenFocusColor : ScreenNormalColor;
157 TFT_print("<", ScreenFontHeight, ScreenFontHeight / 2);
160 std::string title = screens.back()->GetTitle();
161 tft_fg = ScreenNormalColor;
162 TFT_print(title.c_str(), ScreenTitleSafeTop, ScreenFontHeight / 2); // within ScreenTitleSafeTop
163 TFT_drawRect(ScreenTitleSafeTop, ScreenFontHeight * 3 / 2, TFT_getStringWidth(title.c_str()), 2, ScreenNormalColor);
165 TFT_setFont(kButtonFont, nullptr);
166 if (screens.back()->IsFocusable())
168 DisplayButtonText(1, screens.back()->GetButtonText(1).c_str());
169 DisplayButtonText(2, screens.back()->GetButtonText(2).c_str());
173 DisplayButtonText(3, "Back");
175 else if (screens.back()->IsFocusable())
177 DisplayButtonText(3, screens.back()->GetButtonText(3).c_str());
179 TFT_setFont(kMainFont, nullptr);
181 for (int i = 0; i < vleds.size(); ++i)
186 screens.back()->Display();
189 void ButtonPressed(int id)
199 if (focusBack && id == 3)
203 else if (screens.back()->IsFocusable())
209 screens.back()->Focus(Screen::FocusType::PREVIOUS);
213 screens.back()->Focus(Screen::FocusType::NEXT);
216 screens.back()->Action();
223 void PushScreen(Screen * screen)
228 if (!screens.empty())
230 if (screens.back()->IsFocusable())
232 screens.back()->Focus(Screen::FocusType::BLUR);
234 screens.back()->Exit(false);
237 screen->Enter(true); // screen is not top when enter/pushed
238 screens.push_back(screen); // screen is pushed immediately after first enter
242 if (screens.back()->IsFocusable())
244 screens.back()->Focus(Screen::FocusType::NEXT);
264 Screen * screen = screens.back();
265 screens.pop_back(); // screen is popped immediately before last exit
266 screen->Exit(true); // screen is not top when exit/popped
267 chip::Platform::Delete(screen);
271 if (!screens.empty())
273 screens.back()->Enter(false);
274 if (screens.back()->IsFocusable())
276 screens.back()->Focus(Screen::FocusType::UNBLUR);
290 if (screens.size() > 1)
293 if (screens.back()->IsFocusable())
295 screens.back()->Focus(Screen::FocusType::NONE);
304 int AddVLED(color_t color)
307 int id = vleds.size();
308 vleds.emplace_back(color);
313 void SetVLED(int id, bool on)
316 if (vleds[id].on == on)
326 void ToggleVLED(int id)
329 vleds[id].on = !vleds[id].on;
334 } // namespace ScreenManager
336 #endif // CONFIG_HAVE_DISPLAY