Marlin 2.0 for Flying Bear 4S/5
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

243 lines
8.0 KiB

/********************
* 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
}
};