123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243 |
- /********************
- * screen_types.cpp *
- ********************/
-
- /****************************************************************************
- * Written By Marcio Teixeira 2018 - Aleph Objects, Inc. *
- * *
- * This program is free software: you can redistribute it and/or modify *
- * it under the terms of the GNU General Public License as published by *
- * the Free Software Foundation, either version 3 of the License, or *
- * (at your option) any later version. *
- * *
- * This program is distributed in the hope that it will be useful, *
- * but WITHOUT ANY WARRANTY; without even the implied warranty of *
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
- * GNU General Public License for more details. *
- * *
- * To view a copy of the GNU General Public License, go to the following *
- * location: <https://www.gnu.org/licenses/>. *
- ****************************************************************************/
-
- #pragma once
-
- typedef enum {
- BACKGROUND = 1,
- FOREGROUND = 2,
- BOTH = 3
- } draw_mode_t;
-
- /********************** VIRTUAL DISPATCH DATA TYPE ******************************/
-
- // True virtual classes are extremely expensive on the Arduino
- // as the compiler stores the virtual function tables in RAM.
- // We invent a data type called ScreenRef that gives us
- // polymorphism by mapping an ID to virtual methods on various
- // classes. This works by keeping a table in PROGMEM of pointers
- // to static methods.
-
- #define DECL_SCREEN(className) { \
- className::onStartup, \
- className::onEntry, \
- className::onExit, \
- className::onIdle, \
- className::onRefresh, \
- className::onRedraw, \
- className::onTouchStart, \
- className::onTouchHeld, \
- className::onTouchEnd \
- }
-
- #define GET_METHOD(type, method) reinterpret_cast<method##_func_t*>(pgm_read_ptr_far(&functionTable[type].method##_ptr))
- #define SCREEN_TABLE PROGMEM const ScreenRef::table_t ScreenRef::functionTable[] =
- #define SCREEN_TABLE_POST size_t ScreenRef::tableSize() { \
- constexpr size_t siz = sizeof(functionTable)/sizeof(functionTable[0]); \
- static_assert(siz > 0, "The screen table is empty!"); \
- return siz; \
- }
-
- class ScreenRef {
- protected:
- typedef void onStartup_func_t();
- typedef void onEntry_func_t();
- typedef void onExit_func_t();
- typedef void onIdle_func_t();
- typedef void onRefresh_func_t();
- typedef void onRedraw_func_t(draw_mode_t);
- typedef bool onTouchStart_func_t(uint8_t);
- typedef bool onTouchHeld_func_t(uint8_t);
- typedef bool onTouchEnd_func_t(uint8_t);
-
- private:
- typedef struct {
- onStartup_func_t *onStartup_ptr;
- onEntry_func_t *onEntry_ptr;
- onExit_func_t *onExit_ptr;
- onIdle_func_t *onIdle_ptr;
- onRefresh_func_t *onRefresh_ptr;
- onRedraw_func_t *onRedraw_ptr;
- onTouchStart_func_t *onTouchStart_ptr;
- onTouchHeld_func_t *onTouchHeld_ptr;
- onTouchEnd_func_t *onTouchEnd_ptr;
- } table_t;
-
- uint8_t type = 0;
- static PROGMEM const table_t functionTable[];
-
- public:
- static size_t tableSize();
-
- uint8_t getType() {return type;}
- void setType(uint8_t t) {type = t;}
-
- uint8_t lookupScreen(onRedraw_func_t onRedraw_ptr);
-
- void setScreen(onRedraw_func_t onRedraw_ptr);
-
- void onStartup() {GET_METHOD(type, onStartup)();}
- void onEntry() {GET_METHOD(type, onEntry)();}
- void onExit() {GET_METHOD(type, onExit)();}
- void onIdle() {GET_METHOD(type, onIdle)();}
- void onRefresh() {GET_METHOD(type, onRefresh)();}
- void onRedraw(draw_mode_t dm) {GET_METHOD(type, onRedraw)(dm);}
- bool onTouchStart(uint8_t tag) {return GET_METHOD(type, onTouchStart)(tag);}
- bool onTouchHeld(uint8_t tag) {return GET_METHOD(type, onTouchHeld)(tag);}
- bool onTouchEnd(uint8_t tag) {return GET_METHOD(type, onTouchEnd)(tag);}
-
- void initializeAll();
- };
-
- /********************** SCREEN STACK ******************************/
-
- // To conserve dynamic memory, the screen stack is hard-coded to
- // have four values, allowing a menu of up to four levels.
-
- class ScreenStack : public ScreenRef {
- private:
- uint8_t stack[4];
-
- public:
- void start();
- void push(onRedraw_func_t);
- void push();
- void pop();
- void forget();
- void goTo(onRedraw_func_t);
- void goBack();
-
- uint8_t peek() {return stack[0];}
- uint8_t getScreen() {return getType();}
- };
-
- extern ScreenStack current_screen;
-
- /********************** BASE SCREEN CLASS ******************************/
-
- /* UIScreen is the base class for all user interface screens.
- */
- class UIScreen {
- public:
- static void onStartup() {}
- static void onEntry() {current_screen.onRefresh();}
- static void onExit() {}
- static void onIdle() {}
- static bool onTouchStart(uint8_t) {return true;}
- static bool onTouchHeld(uint8_t) {return false;}
- static bool onTouchEnd(uint8_t) {return true;}
- };
-
- #define PUSH_SCREEN(screen) current_screen.push(screen::onRedraw)
- #define GOTO_SCREEN(screen) current_screen.goTo(screen::onRedraw)
- #define GOTO_PREVIOUS() current_screen.goBack();
- #define AT_SCREEN(screen) (current_screen.getType() == current_screen.lookupScreen(screen::onRedraw))
- #define IS_PARENT_SCREEN(screen) (current_screen.peek() == current_screen.lookupScreen(screen::onRedraw))
-
- /************************** CACHED VS UNCACHED SCREENS ***************************/
-
- class UncachedScreen {
- public:
- static void onRefresh() {
- using namespace FTDI;
- CommandProcessor cmd;
- cmd.cmd(CMD_DLSTART);
- #if ENABLED(TOUCH_UI_USE_UTF8)
- load_utf8_bitmaps(cmd);
- #endif
-
- current_screen.onRedraw(BOTH);
-
- cmd.cmd(DL::DL_DISPLAY);
- cmd.cmd(CMD_SWAP);
- cmd.execute();
- }
- };
-
- template<uint8_t DL_SLOT,uint32_t DL_SIZE = 0>
- class CachedScreen {
- protected:
- static void gfxError() {
- using namespace FTDI;
- CommandProcessor cmd;
- cmd.cmd(CMD_DLSTART)
- .cmd(CLEAR(true,true,true))
- .font(30)
- .text(0, 0, display_width, display_height, F("GFX MEM FULL"));
- }
-
- static bool storeBackground() {
- DLCache dlcache(DL_SLOT);
- if (!dlcache.store(DL_SIZE)) {
- SERIAL_ECHO_MSG("CachedScreen::storeBackground() failed: not enough DL cache space");
- gfxError(); // Try to cache a shorter error message instead.
- dlcache.store(DL_SIZE);
- return false;
- }
- return true;
- }
-
- static void repaintBackground() {
- using namespace FTDI;
- DLCache dlcache(DL_SLOT);
- CommandProcessor cmd;
-
- cmd.cmd(CMD_DLSTART);
- #if ENABLED(TOUCH_UI_USE_UTF8)
- load_utf8_bitmaps(cmd);
- #endif
- current_screen.onRedraw(BACKGROUND);
-
- dlcache.store(DL_SIZE);
- }
-
- public:
- static void onRefresh() {
- #if ENABLED(TOUCH_UI_DEBUG)
- const uint32_t start_time = millis();
- #endif
- using namespace FTDI;
- DLCache dlcache(DL_SLOT);
- CommandProcessor cmd;
-
- cmd.cmd(CMD_DLSTART);
-
- if (dlcache.has_data()) {
- dlcache.append();
- }
- else {
- #if ENABLED(TOUCH_UI_USE_UTF8)
- load_utf8_bitmaps(cmd);
- #endif
- current_screen.onRedraw(BACKGROUND);
- dlcache.store(DL_SIZE);
- }
-
- current_screen.onRedraw(FOREGROUND);
-
- cmd.cmd(DL::DL_DISPLAY);
- cmd.cmd(CMD_SWAP);
- cmd.execute();
- #if ENABLED(TOUCH_UI_DEBUG)
- SERIAL_ECHOLNPAIR("Time to draw screen (ms): ", millis() - start_time);
- #endif
- }
- };
|