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.

2191 lines
69 KiB

/****************************************************************************
* Written By Mark Pelletier 2018 - Aleph Objects, Inc. *
* 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: <http://www.gnu.org/licenses/>. *
****************************************************************************/
#define DISPLAY_UPDATE_INTERVAL 1000
#define TOUCH_REPEATS_PER_SECOND 4
#define DEBOUNCE_PERIOD 100
// To save MCU RAM, the status message is "baked" in to the status screen
// cache, so we reserve a large chunk of memory for the DL cache
#define STATUS_SCREEN_DL_SIZE 2048
#define DIALOG_BOX_DL_SIZE 3072
#define N_ELEMENTS(a) (sizeof(a)/sizeof(a[0]))
/**************************** GRID LAYOUT MACROS **************************/
/* The grid layout macros allow buttons to be arranged on a grid so
* that their locations become independent of the display size. The
* layout model is similar to that of HTML TABLEs.
*
* These macros are meant to be evaluated into constants at compile
* time, so resolution independence can be as efficient as using
* hard-coded coordinates.
*/
// Margin defines the margin (in pixels) on each side of a button in
// the layout
#if defined(LCD_800x480)
#define MARGIN_L 5
#define MARGIN_R 5
#define MARGIN_T 5
#define MARGIN_B 5
#else
#define MARGIN_L 3
#define MARGIN_R 3
#define MARGIN_T 3
#define MARGIN_B 3
#endif
// EDGE_R adds some black space on the right edge of the display
// This shifts some of the screens left to visually center them.
#define EDGE_R 0
// GRID_X and GRID_Y computes the positions of the divisions on
// the layout grid.
#if defined(LCD_PORTRAIT)
#define GRID_X(x) ((x)*(Vsize-EDGE_R)/GRID_COLS)
#define GRID_Y(y) ((y)*Hsize/GRID_ROWS)
#else
#define GRID_X(x) ((x)*(Hsize-EDGE_R)/GRID_COLS)
#define GRID_Y(y) ((y)*Vsize/GRID_ROWS)
#endif
// BTN_X, BTN_Y, BTN_W and BTN_X returns the top-left and width
// and height of a button, taking into account the button margins.
#define BTN_X(x) (GRID_X(x-1) + MARGIN_L)
#define BTN_Y(y) (GRID_Y(y-1) + MARGIN_T)
#define BTN_W(w) (GRID_X(w) - MARGIN_L - MARGIN_R)
#define BTN_H(h) (GRID_Y(h) - MARGIN_T - MARGIN_B)
// Abbreviations for common phrases, to allow a button to be
// defined in one line of source.
#define BTN_POS(x,y) BTN_X(x), BTN_Y(y)
#define BTN_SIZE(w,h) BTN_W(w), BTN_H(h)
#define BTN cmd.Cmd_Draw_Button
#define BTX cmd.Cmd_Draw_Button_Text
#define BTI cmd.Cmd_Draw_Button_Icon
#define BTN_TAG(t) cmd.Cmd_Set_Tag(t);
#define RGB(rgb) cmd.Cmd_Set_Foreground_Color(rgb);
#define THEME(color) cmd.Cmd_Set_Foreground_Color(Theme::color);
#define BTN_ENABLED(en) if(en) { \
cmd.Cmd_Set_Color(Theme::btn_rgb_enabled); \
cmd.Cmd_Set_Foreground_Color(Theme::btn_fg_enabled); \
} else { \
cmd.Cmd_Set_Color(Theme::btn_rgb_disabled); \
cmd.Cmd_Set_Foreground_Color(Theme::btn_fg_disabled); \
cmd.Cmd_Set_Tag(0); \
}
#define FONT_SML Theme::font_small
#define FONT_MED Theme::font_medium
#define FONT_LRG Theme::font_large
#define MENU_BTN_STYLE Theme::font_medium, OPT_3D
#define EXEC_GCODE(cmd) Marlin_LCD_API::runGCode(cmd)
/****************************** SCREEN STATIC DATA *************************/
// To save RAM, store state information related to a particular screen
// in a union. The values should be initialized in the onEntry method.
static union {
struct {uint8_t increment;} ValueAdjusters;
struct {uint8_t page, selected_tag;} FilesScreen;
} screen_data;
/************************* MENU SCREEN DECLARATIONS *************************/
class BootScreen : public UIScreen {
public:
static void onRefresh();
static void onIdle();
};
class AboutScreen : public UIScreen {
public:
static void onEntry();
static void onRefresh();
static bool onTouchStart(uint8_t tag);
};
class KillScreen {
// The KillScreen is behaves differently than the
// others, so we do not bother extending UIScreen.
public:
static void show(progmem_str msg);
};
class DialogBoxBaseClass : public UIScreen {
protected:
static void show(const progmem_str message[], size_t lines, progmem_str btn1, progmem_str btn2 );
static void onRefresh();
public:
static bool onTouchStart(uint8_t tag);
};
class AlertBoxScreen : public DialogBoxBaseClass {
public:
static void onRefresh();
static void show(const progmem_str line1, const progmem_str line2 = 0, const progmem_str line3 = 0);
};
class RestoreFailsafeScreen : public DialogBoxBaseClass {
public:
static void onRefresh();
static void onEntry();
static bool onTouchStart(uint8_t tag);
};
class ConfirmAbortPrint : public DialogBoxBaseClass {
public:
static void onRefresh();
static void onEntry();
static bool onTouchStart(uint8_t tag);
};
class StatusScreen : public UIScreen {
private:
static void static_axis_position();
static void static_temperature();
static void static_progress();
static void static_media_button();
static void static_interaction_buttons();
static void static_status_message(const char * const message);
static void dynamic_axis_position();
static void dynamic_temperature();
static void dynamic_progress();
static void dynamic_interaction_buttons();
public:
static void setStatusMessage(const char * message);
static void onRefresh();
static void onStartup();
static void onEntry();
static void onIdle();
static bool onTouchStart(uint8_t tag);
};
class MenuScreen : public UIScreen {
public:
static void onRefresh();
static bool onTouchStart(uint8_t tag);
};
class TuneScreen : public UIScreen {
public:
static void onRefresh();
static bool onTouchStart(uint8_t tag);
};
class CalibrationScreen : public UIScreen {
public:
static void onEntry();
static void onRefresh();
static void onIdle();
};
class CalibrationRegistersScreen : public UIScreen {
public:
static void onRefresh();
static bool onTouchStart(uint8_t tag);
};
class AdvancedSettingsScreen : public UIScreen {
public:
static void onRefresh();
static bool onTouchStart(uint8_t tag);
};
class ValueAdjusters : public UIScreen {
private:
static void draw_increment_btn(uint8_t line, const uint8_t tag, uint8_t decimals);
protected:
struct stacker_t {
uint8_t line;
void static_parts();
void dynamic_parts();
};
struct heading_t {
const char *label;
void static_parts(stacker_t &s) const;
void dynamic_parts(stacker_t &s) const;
};
struct adjuster_t {
uint8_t tag;
const char *label;
const char *units;
uint32_t color;
uint8_t decimals;
void static_parts(stacker_t &s) const;
void dynamic_parts(stacker_t &s,float value) const;
};
struct increment_t {
const uint8_t decimals;
void static_parts(stacker_t &s) const;
void dynamic_parts(stacker_t &s) const;
};
static float getIncrement();
public:
static void onEntry();
static bool onTouchStart(uint8_t tag);
};
class MoveAxisScreen : public ValueAdjusters {
public:
static void onRefresh();
static bool onTouchHeld(uint8_t tag);
};
class StepsScreen : public ValueAdjusters {
public:
static void onRefresh();
static bool onTouchHeld(uint8_t tag);
};
class ZOffsetScreen : public ValueAdjusters {
public:
static void onRefresh();
static bool onTouchHeld(uint8_t tag);
};
class FeedrateScreen : public ValueAdjusters {
public:
static void onRefresh();
static bool onTouchHeld(uint8_t tag);
};
class TemperatureScreen : public ValueAdjusters {
public:
static void onRefresh();
static bool onTouchHeld(uint8_t tag);
};
class FilesScreen : public UIScreen {
private:
static const char *getSelectedShortFilename();
static uint8_t getTagForIndex(uint16_t index);
static uint16_t getIndexForTag(uint8_t tag);
public:
static void onEntry();
static void onRefresh();
static bool onTouchStart(uint8_t tag);
};
/******************************* MENU SCREEN TABLE ******************************/
SCREEN_TABLE {
DECL_SCREEN(BootScreen),
DECL_SCREEN(AboutScreen),
DECL_SCREEN(AlertBoxScreen),
DECL_SCREEN(RestoreFailsafeScreen),
DECL_SCREEN(ConfirmAbortPrint),
DECL_SCREEN(CalibrationScreen),
DECL_SCREEN(StatusScreen),
DECL_SCREEN(MenuScreen),
DECL_SCREEN(TuneScreen),
DECL_SCREEN(MoveAxisScreen),
DECL_SCREEN(AdvancedSettingsScreen),
DECL_SCREEN(StepsScreen),
DECL_SCREEN(ZOffsetScreen),
DECL_SCREEN(FeedrateScreen),
DECL_SCREEN(TemperatureScreen),
DECL_SCREEN(CalibrationRegistersScreen),
DECL_SCREEN(FilesScreen),
};
SCREEN_TABLE_POST
/********************************* DL CACHE SLOTS ******************************/
// In order to reduce SPI traffic, we cache display lists (DL) in RAMG. This
// is done using the CLCD::DLCache class, which takes a unique ID for each
// cache location. These IDs are defined here:
enum {
STATUS_SCREEN_CACHE,
MENU_SCREEN_CACHE,
TUNE_SCREEN_CACHE,
DIALOG_BOX_CACHE,
ADVANCED_SETTINGS_SCREEN_CACHE,
MOVE_AXIS_SCREEN_CACHE,
TEMPERATURE_SCREEN_CACHE,
STEPS_SCREEN_CACHE,
ZOFFSET_SCREEN_CACHE,
FEEDRATE_SCREEN_CACHE,
FILES_SCREEN_CACHE
};
/************************************ MENU THEME ********************************/
namespace Theme {
const uint32_t theme_darkest = 0x2A2F0A;
const uint32_t theme_dark = 0x495212;
const uint32_t theme_light = 0x8C9D22;
const uint32_t background = theme_dark;
const uint32_t back_btn = theme_light;
const uint32_t x_axis = 0x500000;
const uint32_t y_axis = 0x005000;
const uint32_t z_axis = 0x000050;
const uint32_t e_axis = 0x000000;
const uint32_t feedrate = 0x000000;
const uint32_t toggle_on = theme_light;
const uint32_t toggle_off = theme_darkest;
// Disabled vs enabled buttons
const uint32_t btn_rgb_enabled = 0xFFFFFF;
const uint32_t btn_fg_enabled = theme_darkest;
const uint32_t btn_rgb_disabled = theme_dark;
const uint32_t btn_fg_disabled = theme_dark;
// Files screens
const uint32_t files_selected = theme_light;
// Adjustment Screens
const uint32_t incr_btn = theme_darkest;
// Status screen
const uint32_t status_bg = 0x707070;
const uint32_t status_dark = 0x404040;
const uint32_t stop_btn = 0xF02020;
const uint32_t prnt_btn = 0x20D020;
const uint32_t progress = 0x404040;
const uint32_t status_msg = 0x404040;
const uint32_t fan_speed = 0x6060D0;
const uint32_t temp = 0xD04000;
const uint32_t axis_label = 0x404040;
// Calibration Registers Screen
const uint32_t transformA = 0x3010D0;
const uint32_t transformB = 0x4010D0;
const uint32_t transformC = 0x5010D0;
const uint32_t transformD = 0x6010D0;
const uint32_t transformE = 0x7010D0;
const uint32_t transformF = 0x8010D0;
const uint32_t transformVal = 0x104010;
#if defined(LCD_800x480)
#if defined(LCD_PORTRAIT)
const int16_t font_small = 29;
const int16_t font_medium = 30;
const int16_t font_large = 30;
#else
const int16_t font_small = 30;
const int16_t font_medium = 30;
const int16_t font_large = 31;
#endif
const float icon_scale = 1.0;
#else
#if defined(LCD_PORTRAIT)
const int16_t font_small = 27;
const int16_t font_medium = 28;
const int16_t font_large = 28;
const float icon_scale = 0.7;
#else
const int16_t font_small = 27;
const int16_t font_medium = 28;
const int16_t font_large = 30;
const float icon_scale = 0.6;
#endif
#endif
const effect_t press_sound = CHACK;
const effect_t repeat_sound = CHACK;
const effect_t unpress_sound = POP;
};
/******************************** BOOT SCREEN ****************************/
void BootScreen::onRefresh() {
CLCD::CommandFifo cmd;
cmd.Cmd(CMD_DLSTART);
cmd.Cmd_Set_Clear_Color(Theme::background);
cmd.Cmd_Clear(1,1,1);
cmd.Cmd(DL_DISPLAY);
cmd.Cmd(CMD_SWAP);
cmd.Cmd_Execute();
cmd.Cmd_Wait_Until_Idle();
CLCD::Turn_On_Backlight();
CLCD::SoundPlayer::setVolume(255);
}
void BootScreen::onIdle() {
if(CLCD::Is_Touching()) {
// If the user is touching the screen at startup, then
// assume the user wants to re-calibrate the screen.
// This gives the user the ability to recover a
// miscalibration that has been stored to EEPROM.
GOTO_SCREEN(CalibrationScreen);
} else {
GOTO_SCREEN(StatusScreen);
}
}
/******************************** ABOUT SCREEN ****************************/
CLCD::SoundPlayer sound;
void AboutScreen::onEntry() {
UIScreen::onEntry();
CLCD::Mem_Write8(REG_VOL_SOUND, 0xFF);
sound.play(chimes);
}
void AboutScreen::onRefresh() {
CLCD::CommandFifo cmd;
cmd.Cmd(CMD_DLSTART);
cmd.Cmd_Set_Clear_Color(Theme::background);
cmd.Cmd_Clear(1,1,1);
#define GRID_COLS 4
#define GRID_ROWS 8
BTX( BTN_POS(1,2), BTN_SIZE(4,1), F("Color LCD Interface"), FONT_LRG);
BTN_TAG(2)
BTX( BTN_POS(1,3), BTN_SIZE(4,1), F("(c) 2018 Aleph Objects, Inc."), FONT_LRG);
BTX( BTN_POS(1,5), BTN_SIZE(4,1), Marlin_LCD_API::getFirmwareName(), FONT_LRG);
BTN_TAG(1) BTN_ENABLED(1) BTN( BTN_POS(2,7), BTN_SIZE(2,1), F("Okay"), MENU_BTN_STYLE);
cmd.Cmd(DL_DISPLAY);
cmd.Cmd(CMD_SWAP);
cmd.Cmd_Execute();
}
bool AboutScreen::onTouchStart(uint8_t tag) {
switch(tag) {
case 1: GOTO_PREVIOUS(); return true;
case 2: GOTO_SCREEN(CalibrationRegistersScreen); return true;
}
}
/**************************** GENERIC DIALOG BOX SCREEN ****************************/
void DialogBoxBaseClass::show(const progmem_str lines[], size_t n_lines, progmem_str btn1, progmem_str btn2 ) {
CLCD::DLCache dlcache(DIALOG_BOX_CACHE);
CLCD::CommandFifo cmd;
cmd.Cmd(CMD_DLSTART);
cmd.Cmd_Set_Clear_Color(Theme::background);
cmd.Cmd_Clear(1,1,1);
#define GRID_COLS 2
#define GRID_ROWS 8
for(uint8_t line = 0; line < n_lines; line++) {
BTX( BTN_POS(1,3-n_lines/2+line), BTN_SIZE(2,1), lines[line], FONT_LRG);
}
if(btn1 && btn2) {
BTN_TAG(1) BTN_ENABLED(1) BTN( BTN_POS(1,8), BTN_SIZE(1,1), btn1, MENU_BTN_STYLE);
BTN_TAG(2) BTN_ENABLED(1) BTN( BTN_POS(2,8), BTN_SIZE(1,1), btn2, MENU_BTN_STYLE);
} else if(btn1) {
BTN_TAG(1) BTN_ENABLED(1) BTN( BTN_POS(1,8), BTN_SIZE(2,1), btn1, MENU_BTN_STYLE);
} else if(btn2) {
BTN_TAG(2) BTN_ENABLED(1) BTN( BTN_POS(1,8), BTN_SIZE(2,1), btn2, MENU_BTN_STYLE);
}
cmd.Cmd(DL_DISPLAY);
cmd.Cmd(CMD_SWAP);
cmd.Cmd_Execute();
if(!dlcache.store(DIALOG_BOX_DL_SIZE)) {
#if defined (SERIAL_PROTOCOLLNPAIR)
SERIAL_PROTOCOLLN("Unable to set the confirmation message, not enough DL cache space");
#else
#if defined(UI_FRAMEWORK_DEBUG)
Serial.print(F("Unable to set the confirmation message, not enough DL cache space"));
#endif
#endif
}
}
void DialogBoxBaseClass::onRefresh() {
CLCD::DLCache dlcache(DIALOG_BOX_CACHE);
CLCD::CommandFifo cmd;
cmd.Cmd(CMD_DLSTART);
if(dlcache.hasData()) {
dlcache.append();
}
cmd.Cmd(DL_DISPLAY);
cmd.Cmd(CMD_SWAP);
cmd.Cmd_Execute();
}
bool DialogBoxBaseClass::onTouchStart(uint8_t tag) {
switch(tag) {
case 1: GOTO_PREVIOUS(); return true;
case 2: GOTO_PREVIOUS(); return true;
}
}
/****************************** ALERT BOX SCREEN *****************************/
void AlertBoxScreen::onRefresh() {
DialogBoxBaseClass::onRefresh();
}
void AlertBoxScreen::show(const progmem_str line1, const progmem_str line2, const progmem_str line3) {
progmem_str lines[] = {line1, line2, line3};
DialogBoxBaseClass::show(lines, line3 ? 3 : line2 ? 2 : 1, F("Okay"), 0);
sound.play(c_maj_arpeggio);
GOTO_SCREEN(AlertBoxScreen);
}
/**************************** RESTORE FAILSAFE SCREEN ***************************/
void RestoreFailsafeScreen::onEntry() {
progmem_str lines[] = {
F("Are you sure?"),
F("Customizations will be lost.")
};
DialogBoxBaseClass::show(lines, N_ELEMENTS(lines), F("Yes"), F("No"));
}
void RestoreFailsafeScreen::onRefresh() {
DialogBoxBaseClass::onRefresh();
}
bool RestoreFailsafeScreen::onTouchStart(uint8_t tag) {
switch(tag) {
case 1:
EXEC_GCODE(F("M502\nM500"));
AlertBoxScreen::show(F("Factory settings restored."));
// Remove RestoreFailsafeScreen from the stack
// so the alert box doesn't return to it.
current_screen.forget();
return true;
default:
return DialogBoxBaseClass::onTouchStart(tag);
}
}
/**************************** RESTORE FAILSAFE SCREEN ***************************/
void ConfirmAbortPrint::onEntry() {
progmem_str lines[] = {
F("Are you sure you want"),
F("to stop the print?")
};
DialogBoxBaseClass::show(lines, N_ELEMENTS(lines), F("Yes"), F("No"));
}
void ConfirmAbortPrint::onRefresh() {
DialogBoxBaseClass::onRefresh();
}
bool ConfirmAbortPrint::onTouchStart(uint8_t tag) {
switch(tag) {
case 1:
#if defined (SERIAL_PROTOCOLLNPAIR)
SERIAL_PROTOCOLLN("Abort confirmed");
#else
#if defined(UI_FRAMEWORK_DEBUG)
Serial.print(F("Abort confirmed"));
#endif
#endif
GOTO_PREVIOUS();
Marlin_LCD_API::stopPrint();
return true;
default:
return DialogBoxBaseClass::onTouchStart(tag);
}
}
/************************************ KILL SCREEN *******************************/
// The kill screen is an oddball that happens after Marlin has killed the events
// loop. So we only have a show() method rather than onRefresh(). The KillScreen
// should not be used as a model for other UI screens as it is an exception.
void KillScreen::show(progmem_str message) {
CLCD::CommandFifo cmd;
cmd.Cmd(CMD_DLSTART);
cmd.Cmd_Set_Clear_Color(Theme::background);
cmd.Cmd_Clear(1,1,1);
#define GRID_COLS 4
#define GRID_ROWS 8
BTX( BTN_POS(1,2), BTN_SIZE(4,1), message, FONT_LRG);
BTX( BTN_POS(1,3), BTN_SIZE(4,1), F("PRINTER HALTED"), FONT_LRG);
BTX( BTN_POS(1,6), BTN_SIZE(4,1), F("Please reset"), FONT_LRG);
cmd.Cmd(DL_DISPLAY);
cmd.Cmd(CMD_SWAP);
cmd.Cmd_Execute();
sound.play(sad_trombone);
// Marlin won't call the idle function anymore,
// so we have to loop here to play the sounds.
while(sound.hasMoreNotes()) {
sound.onIdle();
}
}
/*********************************** STATUS SCREEN ******************************/
#if defined(LCD_PORTRAIT)
#define GRID_ROWS 9
#define GRID_COLS 3
#else
#define GRID_ROWS 8
#define GRID_COLS 3
#endif
void StatusScreen::static_axis_position() {
CLCD::CommandFifo cmd;
BTN_TAG(6)
#if defined(LCD_PORTRAIT)
THEME(axis_label) BTN( BTN_POS(1,5), BTN_SIZE(2,1), F(""), FONT_LRG, OPT_FLAT);
THEME(axis_label) BTN( BTN_POS(1,6), BTN_SIZE(2,1), F(""), FONT_LRG, OPT_FLAT);
THEME(axis_label) BTN( BTN_POS(1,7), BTN_SIZE(2,1), F(""), FONT_LRG, OPT_FLAT);
BTX( BTN_POS(1,5), BTN_SIZE(1,1), F("X"), FONT_SML);
BTX( BTN_POS(1,6), BTN_SIZE(1,1), F("Y"), FONT_SML);
BTX( BTN_POS(1,7), BTN_SIZE(1,1), F("Z"), FONT_SML);
THEME(x_axis) BTN( BTN_POS(2,5), BTN_SIZE(2,1), F(""), FONT_MED, OPT_FLAT);
THEME(y_axis) BTN( BTN_POS(2,6), BTN_SIZE(2,1), F(""), FONT_MED, OPT_FLAT);
THEME(z_axis) BTN( BTN_POS(2,7), BTN_SIZE(2,1), F(""), FONT_MED, OPT_FLAT);
#else
THEME(axis_label) BTN( BTN_POS(1,5), BTN_SIZE(1,2), F(""), FONT_LRG, OPT_FLAT);
THEME(axis_label) BTN( BTN_POS(2,5), BTN_SIZE(1,2), F(""), FONT_LRG, OPT_FLAT);
THEME(axis_label) BTN( BTN_POS(3,5), BTN_SIZE(1,2), F(""), FONT_LRG, OPT_FLAT);
BTX( BTN_POS(1,5), BTN_SIZE(1,1), F("X"), FONT_SML);
BTX( BTN_POS(2,5), BTN_SIZE(1,1), F("Y"), FONT_SML);
BTX( BTN_POS(3,5), BTN_SIZE(1,1), F("Z"), FONT_SML);
THEME(x_axis) BTN( BTN_POS(1,6), BTN_SIZE(1,1), F(""), FONT_MED, OPT_FLAT);
THEME(y_axis) BTN( BTN_POS(2,6), BTN_SIZE(1,1), F(""), FONT_MED, OPT_FLAT);
THEME(z_axis) BTN( BTN_POS(3,6), BTN_SIZE(1,1), F(""), FONT_MED, OPT_FLAT);
#endif
}
void StatusScreen::dynamic_axis_position() {
CLCD::CommandFifo cmd;
char x_str[15];
char y_str[15];
char z_str[15];
dtostrf(Marlin_LCD_API::getAxisPosition_mm(Marlin_LCD_API::X), 5, 1, x_str);
dtostrf(Marlin_LCD_API::getAxisPosition_mm(Marlin_LCD_API::Y), 5, 1, y_str);
dtostrf(Marlin_LCD_API::getAxisPosition_mm(Marlin_LCD_API::Z), 5, 1, z_str);
strcat_P(x_str, PSTR(" mm"));
strcat_P(y_str, PSTR(" mm"));
strcat_P(z_str, PSTR(" mm"));
BTN_TAG(6)
#if defined(LCD_PORTRAIT)
BTX( BTN_POS(2,5), BTN_SIZE(2,1), x_str, FONT_MED);
BTX( BTN_POS(2,6), BTN_SIZE(2,1), y_str, FONT_MED);
BTX( BTN_POS(2,7), BTN_SIZE(2,1), z_str, FONT_MED);
#else
BTX( BTN_POS(1,6), BTN_SIZE(1,1), x_str, FONT_MED);
BTX( BTN_POS(2,6), BTN_SIZE(1,1), y_str, FONT_MED);
BTX( BTN_POS(3,6), BTN_SIZE(1,1), z_str, FONT_MED);
#endif
//#define MARGIN_T 5
}
#if defined(LCD_PORTRAIT)
#define GRID_COLS 8
#else
#define GRID_COLS 12
#endif
void StatusScreen::static_temperature() {
CLCD::CommandFifo cmd;
#if defined(LCD_PORTRAIT)
BTN_TAG(5)
THEME(temp) BTN( BTN_POS(1,1), BTN_SIZE(4,2), F(""), FONT_SML, OPT_FLAT);
THEME(temp) BTN( BTN_POS(1,1), BTN_SIZE(8,1), F(""), FONT_SML, OPT_FLAT);
THEME(fan_speed) BTN( BTN_POS(5,2), BTN_SIZE(4,1), F(""), FONT_SML, OPT_FLAT);
BTN_TAG(0)
THEME(progress) BTN( BTN_POS(1,3), BTN_SIZE(4,1), F(""), FONT_SML, OPT_FLAT);
THEME(progress) BTN( BTN_POS(5,3), BTN_SIZE(4,1), F(""), FONT_SML, OPT_FLAT);
#else
BTN_TAG(5)
THEME(temp) BTN( BTN_POS(1,1), BTN_SIZE(4,2), F(""), FONT_SML, OPT_FLAT);
THEME(temp) BTN( BTN_POS(1,1), BTN_SIZE(8,1), F(""), FONT_SML, OPT_FLAT);
THEME(fan_speed) BTN( BTN_POS(5,2), BTN_SIZE(4,1), F(""), FONT_SML, OPT_FLAT);
BTN_TAG(0)
THEME(progress) BTN( BTN_POS(9,1), BTN_SIZE(4,1), F(""), FONT_SML, OPT_FLAT);
THEME(progress) BTN( BTN_POS(9,2), BTN_SIZE(4,1), F(""), FONT_SML, OPT_FLAT);
#endif
// Draw Extruder Bitmap on Extruder Temperature Button
cmd.Cmd_Bitmap_Source(Extruder_Icon_Info);
cmd.Cmd_Bitmap_Layout(Extruder_Icon_Info);
cmd.Cmd_Bitmap_Size (Extruder_Icon_Info);
BTN_TAG(5)
BTI(BTN_POS(1,1), BTN_SIZE(1,1), Extruder_Icon_Info, Theme::icon_scale);
BTI(BTN_POS(5,1), BTN_SIZE(1,1), Extruder_Icon_Info, Theme::icon_scale);
// Draw Bed Heat Bitmap on Bed Heat Button
cmd.Cmd_Bitmap_Source(Bed_Heat_Icon_Info);
cmd.Cmd_Bitmap_Layout(Bed_Heat_Icon_Info);
cmd.Cmd_Bitmap_Size (Bed_Heat_Icon_Info);
BTI(BTN_POS(1,2), BTN_SIZE(1,1), Bed_Heat_Icon_Info, Theme::icon_scale);
// Draw Fan Percent Bitmap on Bed Heat Button
cmd.Cmd_Bitmap_Source(Fan_Icon_Info);
cmd.Cmd_Bitmap_Layout(Fan_Icon_Info);
cmd.Cmd_Bitmap_Size (Fan_Icon_Info);
BTI(BTN_POS(5,2), BTN_SIZE(1,1), Fan_Icon_Info, Theme::icon_scale);
}
#define ROUND(val) uint16_t((val)+0.5)
void StatusScreen::dynamic_temperature() {
CLCD::CommandFifo cmd;
char e0_str[15];
char e1_str[15];
char bed_str[15];
char fan_str[15];
sprintf_P(
fan_str,
PSTR("%-3d %%"),
int8_t(Marlin_LCD_API::getFan_percent(0))
);
sprintf_P(
bed_str,
PSTR("%-3d / %-3d " ),
ROUND(Marlin_LCD_API::getActualTemp_celsius(0)),
ROUND(Marlin_LCD_API::getTargetTemp_celsius(0))
);
sprintf_P(
e0_str,
PSTR("%-3d / %-3d C"),
ROUND(Marlin_LCD_API::getActualTemp_celsius(1)),
ROUND(Marlin_LCD_API::getTargetTemp_celsius(1))
);
#if EXTRUDERS == 2
sprintf_P(
e1_str,
PSTR("%-3d / %-3d C"),
ROUND(Marlin_LCD_API::getActualTemp_celsius(2)),
ROUND(Marlin_LCD_API::getTargetTemp_celsius(2))
);
#else
strcpy_P(
e1_str,
PSTR("-")
);
#endif
BTN_TAG(5)
BTX( BTN_POS(2,1), BTN_SIZE(3,1), e0_str, FONT_MED);
BTX( BTN_POS(6,1), BTN_SIZE(3,1), e1_str, FONT_MED);
BTX( BTN_POS(2,2), BTN_SIZE(3,1), bed_str, FONT_MED);
BTX( BTN_POS(6,2), BTN_SIZE(3,1), fan_str, FONT_MED);
}
void StatusScreen::static_progress() {
CLCD::CommandFifo cmd;
BTN_TAG(0)
#if defined(LCD_PORTRAIT)
THEME(progress) BTN( BTN_POS(1,3), BTN_SIZE(4,1), F(""), FONT_SML, OPT_FLAT);
THEME(progress) BTN( BTN_POS(5,3), BTN_SIZE(4,1), F(""), FONT_SML, OPT_FLAT);
#else
THEME(progress) BTN( BTN_POS(9,1), BTN_SIZE(4,1), F(""), FONT_SML, OPT_FLAT);
THEME(progress) BTN( BTN_POS(9,2), BTN_SIZE(4,1), F(""), FONT_SML, OPT_FLAT);
#endif
}
void StatusScreen::dynamic_progress() {
CLCD::CommandFifo cmd;
const uint32_t elapsed = Marlin_LCD_API::getProgress_seconds_elapsed();
const uint8_t hrs = elapsed/3600;
const uint8_t min = (elapsed/60)%60;
char time_str[10];
char progress_str[10];
sprintf_P(time_str, PSTR(" %02d : %02d"), hrs, min);
sprintf_P(progress_str, PSTR("%-3d %%"), Marlin_LCD_API::getProgress_percent() );
#if defined(LCD_PORTRAIT)
BTN_TAG(0)
BTX( BTN_POS(1,3), BTN_SIZE(4,1), time_str, FONT_MED);
BTX( BTN_POS(5,3), BTN_SIZE(4,1), progress_str, FONT_MED);
#else
BTN_TAG(0)
BTX( BTN_POS(9,1), BTN_SIZE(4,1), time_str, FONT_MED);
BTX( BTN_POS(9,2), BTN_SIZE(4,1), progress_str, FONT_MED);
#endif
}
#define GRID_COLS 4
void StatusScreen::static_media_button() {
CLCD::CommandFifo cmd;
if(Marlin_LCD_API::isMediaInserted()) {
BTN_TAG(3)
BTN_ENABLED(1)
} else {
BTN_TAG(0)
cmd.Cmd_Set_Color(Theme::status_bg);
cmd.Cmd_Set_Foreground_Color(Theme::status_bg);
}
#if defined(LCD_PORTRAIT)
BTN( BTN_POS(1,9), BTN_SIZE(2,1), F(""), MENU_BTN_STYLE);
#else
BTN( BTN_POS(3,7), BTN_SIZE(1,2), F(""), MENU_BTN_STYLE);
#endif
if(!Marlin_LCD_API::isMediaInserted()) {
cmd.Cmd_Set_Color(Theme::status_dark);
}
// Draw Thumb Drive Bitmap on USB Button
cmd.Cmd_Bitmap_Source(TD_Icon_Info);
cmd.Cmd_Bitmap_Layout(TD_Icon_Info);
cmd.Cmd_Bitmap_Size (TD_Icon_Info);
#if defined(LCD_PORTRAIT)
BTI(BTN_POS(1,9), BTN_SIZE(2,1), TD_Icon_Info, Theme::icon_scale);
#else
BTI(BTN_POS(3,7), BTN_SIZE(1,2), TD_Icon_Info, Theme::icon_scale);
#endif
}
void StatusScreen::static_interaction_buttons() {
CLCD::CommandFifo cmd;
#if defined(LCD_PORTRAIT)
BTN_TAG(4) BTN_ENABLED(1) BTN( BTN_POS(3,9), BTN_SIZE(2,1), F("MENU"), MENU_BTN_STYLE);
#else
BTN_TAG(4) BTN_ENABLED(1) BTN( BTN_POS(4,7), BTN_SIZE(1,2), F("MENU"), MENU_BTN_STYLE);
#endif
}
void StatusScreen::dynamic_interaction_buttons() {
CLCD::CommandFifo cmd;
if(Marlin_LCD_API::isPrintingFromMedia()) {
BTN_TAG(1)
THEME(stop_btn)
} else {
BTN_TAG(0)
cmd.Cmd_Set_Color(Theme::status_bg);
cmd.Cmd_Set_Foreground_Color(Theme::status_bg);
}
#if defined(LCD_PORTRAIT)
BTN( BTN_POS(1,8), BTN_SIZE(4,1), F("STOP"), MENU_BTN_STYLE);
#else
BTN( BTN_POS(1,7), BTN_SIZE(2,2), F("STOP"), MENU_BTN_STYLE);
#endif
}
#define GRID_COLS 1
void StatusScreen::static_status_message(const char * const message) {
CLCD::CommandFifo cmd;
BTN_TAG(0)
#if defined(LCD_PORTRAIT)
THEME(status_msg) BTN( BTN_POS(1,4), BTN_SIZE(1,1), message, FONT_LRG, OPT_FLAT);
#else
THEME(status_msg) BTN( BTN_POS(1,3), BTN_SIZE(1,2), message, FONT_LRG, OPT_FLAT);
#endif
}
void StatusScreen::setStatusMessage(const char * const message) {
CLCD::DLCache dlcache(STATUS_SCREEN_CACHE);
CLCD::CommandFifo cmd;
cmd.Cmd(CMD_DLSTART);
cmd.Cmd_Set_Clear_Color(Theme::status_bg);
cmd.Cmd_Clear(1,1,1);
static_temperature();
static_progress();
static_axis_position();
static_media_button();
static_interaction_buttons();
static_status_message(message);
if(!dlcache.store(STATUS_SCREEN_DL_SIZE)) {
#if defined (SERIAL_PROTOCOLLNPAIR)
SERIAL_PROTOCOLLNPAIR("Unable to set the status message, not enough DL cache space: ",message);
#else
#if defined(UI_FRAMEWORK_DEBUG)
Serial.print(F("Unable to set the status message, not enough DL cache space: "));
Serial.println(message);
#endif
#endif
}
if(current_screen.getType() == current_screen.lookupScreen(StatusScreen::onRefresh)) {
onRefresh();
}
}
#if defined(LCD_PORTRAIT)
#define GRID_COLS 8
#else
#define GRID_COLS 12
#endif
void StatusScreen::onStartup() {
// Load the bitmaps for the status screen
CLCD::Flash_Write_RGB332_Bitmap(TD_Icon_Info.RAMG_addr, TD_Icon, sizeof(TD_Icon));
CLCD::Flash_Write_RGB332_Bitmap(Extruder_Icon_Info.RAMG_addr, Extruder_Icon, sizeof(Extruder_Icon));
CLCD::Flash_Write_RGB332_Bitmap(Bed_Heat_Icon_Info.RAMG_addr, Bed_Heat_Icon, sizeof(Bed_Heat_Icon));
CLCD::Flash_Write_RGB332_Bitmap(Fan_Icon_Info.RAMG_addr, Fan_Icon, sizeof(Fan_Icon));
}
void StatusScreen::onRefresh() {
CLCD::DLCache dlcache(STATUS_SCREEN_CACHE);
CLCD::CommandFifo cmd;
cmd.Cmd(CMD_DLSTART);
if(dlcache.hasData()) {
dlcache.append();
} else {
// This should not happen, as setStatusMessage will
// populate the cache.
}
/* Dynamic content, non-cached data follows */
dynamic_temperature();
dynamic_progress();
dynamic_axis_position();
dynamic_interaction_buttons();
cmd.Cmd(DL_DISPLAY);
cmd.Cmd(CMD_SWAP);
cmd.Cmd_Execute();
}
void StatusScreen::onEntry() {
onRefresh();
}
void StatusScreen::onIdle() {
onRefresh();
}
bool StatusScreen::onTouchStart(uint8_t tag) {
switch(tag) {
case 1:
#if defined(UI_FRAMEWORK_DEBUG)
#if defined (SERIAL_PROTOCOLLNPGM)
SERIAL_PROTOCOLLNPGM("Aborting print");
#endif
#endif
GOTO_SCREEN(ConfirmAbortPrint);
break;
case 3: GOTO_SCREEN(FilesScreen); break;
case 4:
if(Marlin_LCD_API::isPrinting()) {
GOTO_SCREEN(TuneScreen);
} else {
GOTO_SCREEN(MenuScreen);
}
break;
case 5: GOTO_SCREEN(TemperatureScreen); break;
case 6:
if(!Marlin_LCD_API::isPrinting()) {
GOTO_SCREEN(MoveAxisScreen);
}
break;
}
return true;
}
/************************************ MENU SCREEN *******************************/
#if defined(LCD_PORTRAIT)
#define GRID_ROWS 7
#define GRID_COLS 2
#else
#define GRID_ROWS 5
#define GRID_COLS 2
#endif
void MenuScreen::onRefresh() {
CLCD::DLCache dlcache(MENU_SCREEN_CACHE);
CLCD::CommandFifo cmd;
cmd.Cmd(CMD_DLSTART);
if(dlcache.hasData()) {
dlcache.append();
} else {
cmd.Cmd_Set_Clear_Color(Theme::background);
cmd.Cmd_Clear(1,1,1);
#if defined(LCD_PORTRAIT)
BTN_TAG(2) BTN_ENABLED(1) BTN( BTN_POS(1,1), BTN_SIZE(1,1), F("Auto Home"), MENU_BTN_STYLE);
BTN_TAG(3) BTN_ENABLED(1) BTN( BTN_POS(2,1), BTN_SIZE(1,1), F("Auto Level"), MENU_BTN_STYLE);
BTN_TAG(4) BTN_ENABLED(1) BTN( BTN_POS(1,2), BTN_SIZE(1,1), F("Move Axis"), MENU_BTN_STYLE);
BTN_TAG(5) BTN_ENABLED(1) BTN( BTN_POS(2,2), BTN_SIZE(1,1), F("Motors Off"), MENU_BTN_STYLE);
BTN_TAG(6) BTN_ENABLED(1) BTN( BTN_POS(1,3), BTN_SIZE(2,1), F("Temperature"), MENU_BTN_STYLE);
BTN_TAG(7) BTN_ENABLED(0) BTN( BTN_POS(1,4), BTN_SIZE(2,1), F("Change Filament"), MENU_BTN_STYLE);
BTN_TAG(8) BTN_ENABLED(1) BTN( BTN_POS(1,5), BTN_SIZE(2,1), F("Advanced Settings"), MENU_BTN_STYLE);
BTN_TAG(9) BTN_ENABLED(1) BTN( BTN_POS(1,6), BTN_SIZE(2,1), F("About Firmware"), MENU_BTN_STYLE);
#else
BTN_TAG(2) BTN_ENABLED(1) BTN( BTN_POS(1,1), BTN_SIZE(1,1), F("Auto Home"), MENU_BTN_STYLE);
BTN_TAG(3) BTN_ENABLED(1) BTN( BTN_POS(2,1), BTN_SIZE(1,1), F("Auto Level"), MENU_BTN_STYLE);
BTN_TAG(4) BTN_ENABLED(1) BTN( BTN_POS(1,2), BTN_SIZE(1,1), F("Move Axis"), MENU_BTN_STYLE);
BTN_TAG(5) BTN_ENABLED(1) BTN( BTN_POS(2,2), BTN_SIZE(1,1), F("Motors Off"), MENU_BTN_STYLE);
BTN_TAG(6) BTN_ENABLED(1) BTN( BTN_POS(1,3), BTN_SIZE(1,1), F("Temperature"), MENU_BTN_STYLE);
BTN_TAG(7) BTN_ENABLED(0) BTN( BTN_POS(2,3), BTN_SIZE(1,1), F("Change Filament"), MENU_BTN_STYLE);
BTN_TAG(8) BTN_ENABLED(1) BTN( BTN_POS(1,4), BTN_SIZE(1,1), F("Advanced Settings"), MENU_BTN_STYLE);
BTN_TAG(9) BTN_ENABLED(1) BTN( BTN_POS(2,4), BTN_SIZE(1,1), F("About Firmware"), MENU_BTN_STYLE);
#endif
#if defined(LCD_PORTRAIT)
#define MARGIN_T 15
BTN_TAG(1) THEME(back_btn) BTN( BTN_POS(1,7), BTN_SIZE(2,1), F("Back"), MENU_BTN_STYLE);
#else
BTN_TAG(1) THEME(back_btn) BTN( BTN_POS(1,5), BTN_SIZE(2,1), F("Back"), MENU_BTN_STYLE);
#endif
#define MARGIN_T 5
dlcache.store();
}
cmd.Cmd(DL_DISPLAY);
cmd.Cmd(CMD_SWAP);
cmd.Cmd_Execute();
}
bool MenuScreen::onTouchStart(uint8_t tag) {
switch(tag) {
case 1: GOTO_PREVIOUS(); break;
case 2: EXEC_GCODE(F("G28")); break;
case 3: EXEC_GCODE(F(LULZBOT_MENU_AXIS_LEVELING_GCODE)); break;
case 4: GOTO_SCREEN(MoveAxisScreen); break;
case 5: EXEC_GCODE(F("M84")); break;
case 6: GOTO_SCREEN(TemperatureScreen); break;
case 8: GOTO_SCREEN(AdvancedSettingsScreen); break;
case 9: GOTO_SCREEN(AboutScreen); break;
default:
return false;
}
return true;
}
/************************************ TUNE SCREEN *******************************/
#if defined(LCD_PORTRAIT)
#define GRID_ROWS 5
#define GRID_COLS 2
#else
#define GRID_ROWS 3
#define GRID_COLS 2
#endif
void TuneScreen::onRefresh() {
CLCD::DLCache dlcache(TUNE_SCREEN_CACHE);
CLCD::CommandFifo cmd;
cmd.Cmd(CMD_DLSTART);
if(dlcache.hasData()) {
dlcache.append();
} else {
cmd.Cmd_Set_Clear_Color(Theme::background);
cmd.Cmd_Clear(1,1,1);
#if defined(LCD_PORTRAIT)
BTN_TAG(2) BTN_ENABLED(1) BTN( BTN_POS(1,1), BTN_SIZE(2,1), F("Temperature"), MENU_BTN_STYLE);
BTN_TAG(3) BTN_ENABLED(0) BTN( BTN_POS(1,2), BTN_SIZE(2,1), F("Change Filament"), MENU_BTN_STYLE);
BTN_TAG(4) BTN_ENABLED(1) BTN( BTN_POS(1,3), BTN_SIZE(2,1), F("Z Offset"), MENU_BTN_STYLE);
BTN_TAG(5) BTN_ENABLED(1) BTN( BTN_POS(1,4), BTN_SIZE(2,1), F("Print Speed"), MENU_BTN_STYLE);
#else
BTN_TAG(2) BTN_ENABLED(1) BTN( BTN_POS(1,1), BTN_SIZE(1,1), F("Temperature"), MENU_BTN_STYLE);
BTN_TAG(3) BTN_ENABLED(0) BTN( BTN_POS(1,2), BTN_SIZE(1,1), F("Change Filament"), MENU_BTN_STYLE);
BTN_TAG(4) BTN_ENABLED(1) BTN( BTN_POS(2,1), BTN_SIZE(1,1), F("Z Offset"), MENU_BTN_STYLE);
BTN_TAG(5) BTN_ENABLED(1) BTN( BTN_POS(2,2), BTN_SIZE(2,1), F("Print Speed"), MENU_BTN_STYLE);
#endif
#if defined(LCD_PORTRAIT)
#define MARGIN_T 15
BTN_TAG(1) THEME(back_btn) BTN( BTN_POS(1,5), BTN_SIZE(2,1), F("Back"), MENU_BTN_STYLE);
#else
BTN_TAG(1) THEME(back_btn) BTN( BTN_POS(1,3), BTN_SIZE(2,1), F("Back"), MENU_BTN_STYLE);
#endif
#define MARGIN_T 5
dlcache.store();
}
cmd.Cmd(DL_DISPLAY);
cmd.Cmd(CMD_SWAP);
cmd.Cmd_Execute();
}
bool TuneScreen::onTouchStart(uint8_t tag) {
switch(tag) {
case 1: GOTO_PREVIOUS(); break;
case 2: GOTO_SCREEN(TemperatureScreen); break;
case 4: GOTO_SCREEN(ZOffsetScreen); break;
case 5: GOTO_SCREEN(FeedrateScreen); break;
default:
return false;
}
return true;
}
/******************************* CONFIGURATION SCREEN ****************************/
#if defined(LCD_PORTRAIT)
#define GRID_ROWS 7
#define GRID_COLS 2
#else
#define GRID_ROWS 4
#define GRID_COLS 2
#endif
void AdvancedSettingsScreen::onRefresh() {
CLCD::DLCache dlcache(ADVANCED_SETTINGS_SCREEN_CACHE);
CLCD::CommandFifo cmd;
cmd.Cmd(CMD_DLSTART);
if(dlcache.hasData()) {
dlcache.append();
} else {
cmd.Cmd_Set_Clear_Color(Theme::background);
cmd.Cmd_Clear(1,1,1);
#if defined(LCD_PORTRAIT)
BTN_TAG(4) BTN_ENABLED(1) BTN( BTN_POS(1,1), BTN_SIZE(1,2), F("Z Offset "), MENU_BTN_STYLE);
BTN_TAG(5) BTN_ENABLED(1) BTN( BTN_POS(1,3), BTN_SIZE(1,1), F("Steps/mm"), MENU_BTN_STYLE);
BTN_TAG(6) BTN_ENABLED(0) BTN( BTN_POS(2,1), BTN_SIZE(1,1), F("Velocity "), MENU_BTN_STYLE);
BTN_TAG(7) BTN_ENABLED(0) BTN( BTN_POS(2,2), BTN_SIZE(1,1), F("Acceleration"), MENU_BTN_STYLE);
BTN_TAG(8) BTN_ENABLED(0) BTN( BTN_POS(2,3), BTN_SIZE(1,1), F("Jerk"), MENU_BTN_STYLE);
BTN_TAG(9) BTN_ENABLED(1) BTN( BTN_POS(1,4), BTN_SIZE(2,1), F("Recalibrate Screen"), MENU_BTN_STYLE);
BTN_TAG(10) BTN_ENABLED(1) BTN( BTN_POS(1,5), BTN_SIZE(2,1), F("Restore Factory Settings"), MENU_BTN_STYLE);
BTN_TAG(2) BTN_ENABLED(1) BTN( BTN_POS(1,6), BTN_SIZE(2,1), F("Save As Default"), MENU_BTN_STYLE);
BTN_TAG(1) THEME(back_btn) BTN( BTN_POS(1,7), BTN_SIZE(2,1), F("Back"), MENU_BTN_STYLE);
#else
BTN_TAG(4) BTN_ENABLED(1) BTN( BTN_POS(1,1), BTN_SIZE(1,1), F("Z Offset "), MENU_BTN_STYLE);
BTN_TAG(5) BTN_ENABLED(1) BTN( BTN_POS(1,2), BTN_SIZE(1,1), F("Steps/mm"), MENU_BTN_STYLE);
BTN_TAG(6) BTN_ENABLED(0) BTN( BTN_POS(2,1), BTN_SIZE(1,1), F("Velocity "), MENU_BTN_STYLE);
BTN_TAG(7) BTN_ENABLED(0) BTN( BTN_POS(2,2), BTN_SIZE(1,1), F("Acceleration"), MENU_BTN_STYLE);
BTN_TAG(8) BTN_ENABLED(0) BTN( BTN_POS(2,3), BTN_SIZE(1,1), F("Jerk"), MENU_BTN_STYLE);
BTN_TAG(10) BTN_ENABLED(1) BTN( BTN_POS(1,3), BTN_SIZE(1,1), F("Restore Failsafe"), MENU_BTN_STYLE);
BTN_TAG(2) BTN_ENABLED(1) BTN( BTN_POS(1,4), BTN_SIZE(1,1), F("Save"), MENU_BTN_STYLE);
BTN_TAG(1) THEME(back_btn) BTN( BTN_POS(2,4), BTN_SIZE(1,1), F("Back"), MENU_BTN_STYLE);
#endif
dlcache.store();
}
cmd.Cmd(DL_DISPLAY);
cmd.Cmd(CMD_SWAP);
cmd.Cmd_Execute();
}
bool AdvancedSettingsScreen::onTouchStart(uint8_t tag) {
switch(tag) {
case 1: GOTO_PREVIOUS(); break;
case 2:
current_screen.pop();
EXEC_GCODE(F("M500"));
AlertBoxScreen::show(F("Settings saved!"));
break;
case 4: GOTO_SCREEN(ZOffsetScreen); break;
case 5: GOTO_SCREEN(StepsScreen); break;
case 9: GOTO_SCREEN(CalibrationScreen); break;
case 10: GOTO_SCREEN(RestoreFailsafeScreen); break;
default:
return false;
}
return true;
}
/******************************** CALIBRATION SCREEN ****************************/
#define GRID_COLS 4
#define GRID_ROWS 16
void CalibrationScreen::onEntry() {
// Clear the display
CLCD::CommandFifo cmd;
cmd.Cmd(CMD_DLSTART);
cmd.Cmd_Set_Clear_Color(Theme::background);
cmd.Cmd_Clear(1,1,1);
cmd.Cmd(DL_DISPLAY);
cmd.Cmd(CMD_SWAP);
cmd.Cmd_Execute();
// Wait for the touch to release before starting,
// as otherwise the first calibration point could
// be misinterpreted.
while(CLCD::Is_Touching()) {
#if defined(UI_FRAMEWORK_DEBUG)
#if defined (SERIAL_PROTOCOLLNPGM)
SERIAL_PROTOCOLLNPGM("Waiting for touch release");
#endif
#endif
}
UIScreen::onEntry();
}
void CalibrationScreen::onRefresh() {
CLCD::CommandFifo cmd;
cmd.Cmd(CMD_DLSTART);
cmd.Cmd_Set_Clear_Color(Theme::background);
cmd.Cmd_Clear(1,1,1);
#if defined(LCD_PORTRAIT)
BTX( BTN_POS(1,8), BTN_SIZE(4,1), F("Touch the dots"), FONT_LRG);
BTX( BTN_POS(1,9), BTN_SIZE(4,1), F("to calibrate"), FONT_LRG);
#else
#if defined(LCD_800x480)
BTX( BTN_POS(1,1), BTN_SIZE(4,16), F("Touch the dots to calibrate"), FONT_LRG);
#else
BTX( BTN_POS(1,1), BTN_SIZE(4,16), F("Touch the dots to calibrate"), FONT_MED);
#endif
#endif
cmd.Cmd(CMD_CALIBRATE);
cmd.Cmd(DL_DISPLAY);
cmd.Cmd(CMD_SWAP);
cmd.Cmd_Execute();
}
void CalibrationScreen::onIdle() {
if(CLCD::CommandFifo::Cmd_Is_Idle()) {
#if defined(UI_FRAMEWORK_DEBUG)
#if defined (SERIAL_PROTOCOLLNPGM)
SERIAL_PROTOCOLLNPGM("Calibration finished");
#endif
#endif
GOTO_SCREEN(StatusScreen);
}
#if defined(UI_FRAMEWORK_DEBUG)
else {
#if defined (SERIAL_PROTOCOLLNPGM)
SERIAL_PROTOCOLLNPGM("Waiting for calibration to finish.");
#endif
}
#endif
}
/***************************** CALIBRATION REGISTERS SCREEN ****************************/
#define MARGIN_T 5
#define GRID_ROWS 7
#define GRID_COLS 2
void CalibrationRegistersScreen::onRefresh() {
const uint32_t T_Transform_A = CLCD::Mem_Read32(REG_TOUCH_TRANSFORM_A);
const uint32_t T_Transform_B = CLCD::Mem_Read32(REG_TOUCH_TRANSFORM_B);
const uint32_t T_Transform_C = CLCD::Mem_Read32(REG_TOUCH_TRANSFORM_C);
const uint32_t T_Transform_D = CLCD::Mem_Read32(REG_TOUCH_TRANSFORM_D);
const uint32_t T_Transform_E = CLCD::Mem_Read32(REG_TOUCH_TRANSFORM_E);
const uint32_t T_Transform_F = CLCD::Mem_Read32(REG_TOUCH_TRANSFORM_F);
char b[20];
CLCD::CommandFifo cmd;
cmd.Cmd(CMD_DLSTART);
cmd.Cmd_Set_Clear_Color(Theme::background);
cmd.Cmd_Clear(1,1,1);
BTN_TAG(0)
THEME(transformA) BTN( BTN_POS(1,1), BTN_SIZE(1,1), F("TOUCH TRANSFORM_A"), 28, OPT_3D);
THEME(transformB) BTN( BTN_POS(1,2), BTN_SIZE(1,1), F("TOUCH TRANSFORM_B"), 28, OPT_3D);
THEME(transformC) BTN( BTN_POS(1,3), BTN_SIZE(1,1), F("TOUCH TRANSFORM_C"), 28, OPT_3D);
THEME(transformD) BTN( BTN_POS(1,4), BTN_SIZE(1,1), F("TOUCH TRANSFORM_D"), 28, OPT_3D);
THEME(transformE) BTN( BTN_POS(1,5), BTN_SIZE(1,1), F("TOUCH TRANSFORM_E"), 28, OPT_3D);
THEME(transformF) BTN( BTN_POS(1,6), BTN_SIZE(1,1), F("TOUCH TRANSFORM_F"), 28, OPT_3D);
THEME(transformVal) BTN( BTN_POS(2,1), BTN_SIZE(1,1), F(""), 28, OPT_FLAT);
THEME(transformVal) BTN( BTN_POS(2,2), BTN_SIZE(1,1), F(""), 28, OPT_FLAT);
THEME(transformVal) BTN( BTN_POS(2,3), BTN_SIZE(1,1), F(""), 28, OPT_FLAT);
THEME(transformVal) BTN( BTN_POS(2,4), BTN_SIZE(1,1), F(""), 28, OPT_FLAT);
THEME(transformVal) BTN( BTN_POS(2,5), BTN_SIZE(1,1), F(""), 28, OPT_FLAT);
THEME(transformVal) BTN( BTN_POS(2,6), BTN_SIZE(1,1), F(""), 28, OPT_FLAT);
sprintf_P(b, PSTR("0x%08lX"), T_Transform_A); BTX( BTN_POS(2,1), BTN_SIZE(1,1), b, 28);
sprintf_P(b, PSTR("0x%08lX"), T_Transform_B); BTX( BTN_POS(2,2), BTN_SIZE(1,1), b, 28);
sprintf_P(b, PSTR("0x%08lX"), T_Transform_C); BTX( BTN_POS(2,3), BTN_SIZE(1,1), b, 28);
sprintf_P(b, PSTR("0x%08lX"), T_Transform_D); BTX( BTN_POS(2,4), BTN_SIZE(1,1), b, 28);
sprintf_P(b, PSTR("0x%08lX"), T_Transform_E); BTX( BTN_POS(2,5), BTN_SIZE(1,1), b, 28);
sprintf_P(b, PSTR("0x%08lX"), T_Transform_F); BTX( BTN_POS(2,6), BTN_SIZE(1,1), b, 28);
#define GRID_COLS 3
BTN_TAG(1) THEME(back_btn) BTN( BTN_POS(3,7), BTN_SIZE(1,1), F("Back"), MENU_BTN_STYLE);
cmd.Cmd(DL_DISPLAY);
cmd.Cmd(CMD_SWAP);
cmd.Cmd_Execute();
sound.play(js_bach_joy);
}
bool CalibrationRegistersScreen::onTouchStart(uint8_t tag) {
switch(tag) {
case 1: GOTO_PREVIOUS(); break;
default:
return false;
}
return true;
}
/*************************** GENERIC VALUE ADJUSTMENT SCREEN ******************************/
#if defined(LCD_PORTRAIT)
#define GRID_COLS 6
#define GRID_ROWS 10
#else
#define GRID_COLS 9
#define GRID_ROWS 6
#endif
void ValueAdjusters::stacker_t::static_parts() {
CLCD::CommandFifo cmd;
cmd.Cmd_Set_Clear_Color(Theme::background);
cmd.Cmd_Clear(1,1,1);
#if defined(LCD_PORTRAIT)
BTN_TAG(1) THEME(back_btn) BTN( BTN_POS(1,10), BTN_SIZE(6,1), F("Back"), MENU_BTN_STYLE);
#else
BTN_TAG(1) THEME(back_btn) BTN( BTN_POS(8,6), BTN_SIZE(2,1), F("Back"), MENU_BTN_STYLE);
#endif
line = 1;
}
void ValueAdjusters::stacker_t::dynamic_parts() {
line = 1;
}
void ValueAdjusters::draw_increment_btn(uint8_t line, const uint8_t tag, uint8_t decimals) {
CLCD::CommandFifo cmd;
const char *label = PSTR("?");
uint8_t pos;
switch(tag) {
case 240: label = PSTR( ".001"); pos = decimals - 3; break;
case 241: label = PSTR( ".01" ); pos = decimals - 2; break;
case 242: label = PSTR( "0.1" ); pos = decimals - 1; break;
case 243: label = PSTR( "1" ); pos = decimals + 0; break;
case 244: label = PSTR( "10" ); pos = decimals + 1; break;
case 245: label = PSTR("100" ); pos = decimals + 2; break;
default:
#if defined(UI_FRAMEWORK_DEBUG)
#if defined(SERIAL_PROTOCOLLNPAIR)
SERIAL_PROTOCOLLNPAIR("Unknown tag for increment btn: ", tag);
#else
Serial.print(F("Unknown tag for increment btn:"));
Serial.println(tag);
#endif
#endif
;
}
BTN_TAG(tag)
switch(pos) {
#if defined(LCD_PORTRAIT)
case 0: BTN( BTN_POS(3,line), BTN_SIZE(1,1), progmem_str(label), FONT_SML, OPT_3D); break;
case 1: BTN( BTN_POS(4,line), BTN_SIZE(1,1), progmem_str(label), FONT_SML, OPT_3D); break;
case 2: BTN( BTN_POS(5,line), BTN_SIZE(1,1), progmem_str(label), FONT_SML, OPT_3D); break;
#else
case 0: BTN( BTN_POS(8,2), BTN_SIZE(2,1), progmem_str(label), FONT_MED, OPT_3D); break;
case 1: BTN( BTN_POS(8,3), BTN_SIZE(2,1), progmem_str(label), FONT_MED, OPT_3D); break;
case 2: BTN( BTN_POS(8,4), BTN_SIZE(2,1), progmem_str(label), FONT_MED, OPT_3D); break;
#endif
}
}
void ValueAdjusters::increment_t::static_parts(stacker_t &s) const {
CLCD::CommandFifo cmd;
#if defined(LCD_PORTRAIT)
BTN_TAG(0) THEME(background) BTN( BTN_POS(1, s.line), BTN_SIZE(6,1), F("Increment:"), FONT_MED, OPT_FLAT);
#else
BTN_TAG(0) THEME(background) BTN( BTN_POS(8,1), BTN_SIZE(2,1), F("Increment"), FONT_MED, OPT_FLAT);
#endif
// Draw all the buttons in the off state.
THEME(toggle_off);
draw_increment_btn(s.line+1, 243 - decimals, decimals);
draw_increment_btn(s.line+1, 244 - decimals, decimals);
draw_increment_btn(s.line+1, 245 - decimals, decimals);
s.line += 2;
screen_data.ValueAdjusters.increment = 243 - decimals;
}
void ValueAdjusters::increment_t::dynamic_parts(stacker_t &s) const {
CLCD::CommandFifo cmd;
THEME(toggle_on);
draw_increment_btn(s.line+1, screen_data.ValueAdjusters.increment, decimals);
s.line += 2;
}
void ValueAdjusters::heading_t::static_parts(stacker_t &s) const {
CLCD::CommandFifo cmd;
#if defined(LCD_PORTRAIT)
BTN_TAG(0) THEME(background) BTN( BTN_POS(1, s.line), BTN_SIZE(6,1), (progmem_str) label, FONT_MED, OPT_FLAT);
#else
BTN_TAG(0) THEME(background) BTN( BTN_POS(3, s.line), BTN_SIZE(4,1), (progmem_str) label, FONT_MED, OPT_FLAT);
#endif
s.line++;
}
void ValueAdjusters::heading_t::dynamic_parts(stacker_t &s) const {
s.line++;
}
#if defined(LCD_PORTRAIT)
#if defined(LCD_800x480)
#define EDGE_R 20
#else
#define EDGE_R 10
#endif
#else
#if defined(LCD_800x480)
#define EDGE_R 40
#else
#define EDGE_R 20
#endif
#endif
void ValueAdjusters::adjuster_t::static_parts(stacker_t &s) const {
CLCD::CommandFifo cmd;
progmem_str str = (progmem_str) label;
BTN_TAG( 0 ) RGB(color) BTN( BTN_POS(3,s.line), BTN_SIZE(2,1), F(""), FONT_SML, OPT_FLAT);
BTN_TAG( 0 ) THEME(background) BTN( BTN_POS(1,s.line), BTN_SIZE(2,1), str, FONT_SML, OPT_FLAT);
BTN_TAG(tag ) BTN_ENABLED(1) BTN( BTN_POS(5,s.line), BTN_SIZE(1,1), F("-"), FONT_MED, OPT_3D);
BTN_TAG(tag + 1) BTN_ENABLED(1) BTN( BTN_POS(6,s.line), BTN_SIZE(1,1), F("+"), FONT_MED, OPT_3D);
s.line++;
}
void ValueAdjusters::adjuster_t::dynamic_parts(stacker_t &s, float value) const {
CLCD::CommandFifo cmd;
char b[32];
dtostrf(value, 5, decimals, b);
strcat_P(b, PSTR(" "));
strcat_P(b, (const char*) units);
BTN_TAG(0)
BTX( BTN_POS(3,s.line), BTN_SIZE(2,1), b, FONT_SML);
s.line++;
}
void ValueAdjusters::onEntry() {
screen_data.ValueAdjusters.increment = 242;
UIScreen::onEntry();
}
bool ValueAdjusters::onTouchStart(uint8_t tag) {
switch(tag) {
case 1: GOTO_PREVIOUS(); return true;
case 240 ... 245: screen_data.ValueAdjusters.increment = tag; break;
default: return current_screen.onTouchHeld(tag);
}
current_screen.onRefresh();
return true;
}
float ValueAdjusters::getIncrement() {
switch(screen_data.ValueAdjusters.increment) {
case 240: return 0.001;
case 241: return 0.01;
case 242: return 0.1;
case 243: return 1.0;
case 244: return 10.0;
case 245: return 100.0;
}
}
#define EDGE_R 0
/******************************** MOVE AXIS SCREEN ******************************/
void MoveAxisScreen::onRefresh() {
CLCD::DLCache dlcache(MOVE_AXIS_SCREEN_CACHE);
CLCD::CommandFifo cmd;
cmd.Cmd(CMD_DLSTART);
/* Tag Label: Units: Color: Precision: */
const heading_t h = { PSTR("Move Axis") };
const adjuster_t x = {2, PSTR("X:"), PSTR("mm"), Theme::x_axis, 1 };
const adjuster_t y = {4, PSTR("Y:"), PSTR("mm"), Theme::y_axis, 1 };
const adjuster_t z = {6, PSTR("Z:"), PSTR("mm"), Theme::z_axis, 1 };
#if EXTRUDERS == 1
const adjuster_t e0 = {8, PSTR("E:"), PSTR("mm"), Theme::e_axis, 1 };
#else EXTRUDERS == 2
const adjuster_t e0 = {8, PSTR("E0:"), PSTR("mm"), Theme::e_axis, 1 };
const adjuster_t e1 = {10, PSTR("E1:"), PSTR("mm"), Theme::e_axis, 1 };
#endif
const increment_t i = { 1 };
stacker_t s;
if(dlcache.hasData()) {
dlcache.append();
} else {
s.static_parts();
h.static_parts(s);
x.static_parts(s);
y.static_parts(s);
z.static_parts(s);
e0.static_parts(s);
#if EXTRUDERS == 2
e1.static_parts(s);
#endif
i.static_parts(s);
dlcache.store();
}
s.dynamic_parts();
h.dynamic_parts(s);
x.dynamic_parts(s,Marlin_LCD_API::getAxisPosition_mm(Marlin_LCD_API::X));
y.dynamic_parts(s,Marlin_LCD_API::getAxisPosition_mm(Marlin_LCD_API::Y));
z.dynamic_parts(s,Marlin_LCD_API::getAxisPosition_mm(Marlin_LCD_API::Z));
e0.dynamic_parts(s,Marlin_LCD_API::getAxisPosition_mm(Marlin_LCD_API::E0));
#if EXTRUDERS == 2
e1.dynamic_parts(s,Marlin_LCD_API::getAxisPosition_mm(Marlin_LCD_API::E1));
#endif
i.dynamic_parts(s);
cmd.Cmd(DL_DISPLAY);
cmd.Cmd(CMD_SWAP);
cmd.Cmd_Execute();
}
bool MoveAxisScreen::onTouchHeld(uint8_t tag) {
// We don't want to stack up moves, so wait until the
// machine is idle before sending another.
if(Marlin_LCD_API::isMoving()) {
return false;
}
float inc = getIncrement();
Marlin_LCD_API::axis_t axis;
const float feedrate_mm_s = inc * TOUCH_REPEATS_PER_SECOND;
switch(tag) {
case 2: axis = Marlin_LCD_API::X; inc *= -1; break;
case 3: axis = Marlin_LCD_API::X; inc *= 1; break;
case 4: axis = Marlin_LCD_API::Y; inc *= -1; break;
case 5: axis = Marlin_LCD_API::Y; inc *= 1; break;
case 6: axis = Marlin_LCD_API::Z; inc *= -1; break;
case 7: axis = Marlin_LCD_API::Z; inc *= 1; break;
case 8: axis = Marlin_LCD_API::E0; inc *= -1; break;
case 9: axis = Marlin_LCD_API::E0; inc *= 1; break;
case 10: axis = Marlin_LCD_API::E1; inc *= -1; break;
case 11: axis = Marlin_LCD_API::E1; inc *= 1; break;
default:
return false;
}
Marlin_LCD_API::setAxisPosition_mm(axis, Marlin_LCD_API::getAxisPosition_mm(axis) + inc, feedrate_mm_s);
onRefresh();
return true;
}
/******************************* TEMPERATURE SCREEN ******************************/
void TemperatureScreen::onRefresh() {
CLCD::DLCache dlcache(TEMPERATURE_SCREEN_CACHE);
CLCD::CommandFifo cmd;
cmd.Cmd(CMD_DLSTART);
/* Tag Label: Units: Color: Precision: */
const heading_t h = { PSTR("Temperature:") };
#if EXTRUDERS == 1
const adjuster_t n1 = {2, PSTR("Nozzle:"), PSTR("C"), Theme::temp, 0 };
#else
const adjuster_t n1 = {2, PSTR("Nozzle 1:"), PSTR("C"), Theme::temp, 0 };
const adjuster_t n2 = {4, PSTR("Nozzle 2:"), PSTR("C"), Theme::temp, 0 };
#endif
const adjuster_t b = {20, PSTR("Bed:"), PSTR("C"), Theme::temp, 0 };
const adjuster_t f1 = {10, PSTR("Fan Speed:"), PSTR("%"), Theme::fan_speed, 0 };
const increment_t i = { 0 };
stacker_t s;
if(dlcache.hasData()) {
dlcache.append();
} else {
s .static_parts();
h .static_parts(s);
n1.static_parts(s);
b .static_parts(s);
f1.static_parts(s);
i .static_parts(s);
dlcache.store();
}
s .dynamic_parts();
h .dynamic_parts(s);
n1.dynamic_parts(s, Marlin_LCD_API::getTargetTemp_celsius(1));
b .dynamic_parts(s, Marlin_LCD_API::getTargetTemp_celsius(0));
f1.dynamic_parts(s, Marlin_LCD_API::getFan_percent(0));
i .dynamic_parts(s);
cmd.Cmd(DL_DISPLAY);
cmd.Cmd(CMD_SWAP);
cmd.Cmd_Execute();
}
bool TemperatureScreen::onTouchHeld(uint8_t tag) {
switch(tag) {
case 20: Marlin_LCD_API::setTargetTemp_celsius(0, Marlin_LCD_API::getTargetTemp_celsius(0) - getIncrement()); break;
case 21: Marlin_LCD_API::setTargetTemp_celsius(0, Marlin_LCD_API::getTargetTemp_celsius(0) + getIncrement()); break;
case 2: Marlin_LCD_API::setTargetTemp_celsius(1, Marlin_LCD_API::getTargetTemp_celsius(1) - getIncrement()); break;
case 3: Marlin_LCD_API::setTargetTemp_celsius(1, Marlin_LCD_API::getTargetTemp_celsius(1) + getIncrement()); break;
case 4: Marlin_LCD_API::setTargetTemp_celsius(2, Marlin_LCD_API::getTargetTemp_celsius(2) - getIncrement()); break;
case 5: Marlin_LCD_API::setTargetTemp_celsius(2, Marlin_LCD_API::getTargetTemp_celsius(2) + getIncrement()); break;
case 10: Marlin_LCD_API::setFan_percent( 0, Marlin_LCD_API::getFan_percent(0) - getIncrement()); break;
case 11: Marlin_LCD_API::setFan_percent( 0, Marlin_LCD_API::getFan_percent(0) + getIncrement()); break;
default:
return false;
}
onRefresh();
return true;
}
/******************************* STEPS SCREEN ******************************/
void StepsScreen::onRefresh() {
CLCD::DLCache dlcache(STEPS_SCREEN_CACHE);
CLCD::CommandFifo cmd;
cmd.Cmd(CMD_DLSTART);
/* Tag Label: Units: Color: Precision: */
const heading_t h = { PSTR("Steps/mm") };
const adjuster_t x = {2, PSTR("X:"), PSTR(""), Theme::x_axis, 0 };
const adjuster_t y = {4, PSTR("Y:"), PSTR(""), Theme::y_axis, 0 };
const adjuster_t z = {6, PSTR("Z:"), PSTR(""), Theme::z_axis, 0 };
#if EXTRUDERS == 1
const adjuster_t e0 = {8, PSTR("E:"), PSTR(""), Theme::e_axis, 0 };
#else
const adjuster_t e0 = {8, PSTR("E0:"), PSTR(""), Theme::e_axis, 0 };
const adjuster_t e1 = {10, PSTR("E1:"), PSTR(""), Theme::e_axis, 0 };
#endif
const increment_t i = { 0 };
stacker_t s;
if(dlcache.hasData()) {
dlcache.append();
} else {
s.static_parts();
h.static_parts(s);
x.static_parts(s);
y.static_parts(s);
z.static_parts(s);
e0.static_parts(s);
#if EXTRUDERS == 2
e1.static_parts(s);
#endif
i.static_parts(s);
dlcache.store();
}
s.dynamic_parts();
h.dynamic_parts(s);
x.dynamic_parts(s,Marlin_LCD_API::getAxisSteps_per_mm(Marlin_LCD_API::X) );
y.dynamic_parts(s,Marlin_LCD_API::getAxisSteps_per_mm(Marlin_LCD_API::Y) );
z.dynamic_parts(s,Marlin_LCD_API::getAxisSteps_per_mm(Marlin_LCD_API::Z) );
e0.dynamic_parts(s,Marlin_LCD_API::getAxisSteps_per_mm(Marlin_LCD_API::E0));
#if EXTRUDERS == 2
e1.dynamic_parts(s,Marlin_LCD_API::getAxisSteps_per_mm(Marlin_LCD_API::E1));
#endif
i.dynamic_parts(s);
cmd.Cmd(DL_DISPLAY);
cmd.Cmd(CMD_SWAP);
cmd.Cmd_Execute();
}
bool StepsScreen::onTouchHeld(uint8_t tag) {
float inc = getIncrement();
Marlin_LCD_API::axis_t axis;
switch(tag) {
case 2: axis = Marlin_LCD_API::X; inc *= -1; break;
case 3: axis = Marlin_LCD_API::X; inc *= 1; break;
case 4: axis = Marlin_LCD_API::Y; inc *= -1; break;
case 5: axis = Marlin_LCD_API::Y; inc *= 1; break;
case 6: axis = Marlin_LCD_API::Z; inc *= -1; break;
case 7: axis = Marlin_LCD_API::Z; inc *= 1; break;
case 8: axis = Marlin_LCD_API::E0; inc *= -1; break;
case 9: axis = Marlin_LCD_API::E0; inc *= 1; break;
#if EXTRUDERS == 2
case 10: axis = Marlin_LCD_API::E1; inc *= -1; break;
case 11: axis = Marlin_LCD_API::E1; inc *= 1; break;
#endif
default:
return false;
}
Marlin_LCD_API::setAxisSteps_per_mm(axis, Marlin_LCD_API::getAxisSteps_per_mm(axis) + inc);
onRefresh();
return true;
}
/***************************** Z-OFFSET SCREEN ***************************/
void ZOffsetScreen::onRefresh() {
CLCD::DLCache dlcache(ZOFFSET_SCREEN_CACHE);
CLCD::CommandFifo cmd;
cmd.Cmd(CMD_DLSTART);
/* Tag Label: Units: Color: Precision: */
const heading_t h = { PSTR("Z Offset") };
const adjuster_t z = {4, PSTR("Z Offset:"), PSTR("mm"), Theme::z_axis, 3 };
const increment_t i = { 3 };
stacker_t s;
if(dlcache.hasData()) {
dlcache.append();
} else {
s.static_parts();
h.static_parts(s);
z.static_parts(s);
i.static_parts(s);
dlcache.store();
}
s.dynamic_parts();
h.dynamic_parts(s);
z.dynamic_parts(s,Marlin_LCD_API::getZOffset_mm());
i.dynamic_parts(s);
cmd.Cmd(DL_DISPLAY);
cmd.Cmd(CMD_SWAP);
cmd.Cmd_Execute();
}
bool ZOffsetScreen::onTouchHeld(uint8_t tag) {
switch(tag) {
case 4: Marlin_LCD_API::incrementZOffset_mm(-getIncrement()); break;
case 5: Marlin_LCD_API::incrementZOffset_mm( getIncrement()); break;
default:
return false;
}
onRefresh();
return true;
}
/***************************** FEEDRATE SCREEN ***************************/
void FeedrateScreen::onRefresh() {
CLCD::DLCache dlcache(FEEDRATE_SCREEN_CACHE);
CLCD::CommandFifo cmd;
cmd.Cmd(CMD_DLSTART);
/* Tag Label: Units: Color: Precision: */
const heading_t h = { PSTR("Print Speed") };
const adjuster_t f = {4, PSTR("Speed"), PSTR("%"), Theme::feedrate, 0 };
const increment_t i = { 0 };
stacker_t s;
if(dlcache.hasData()) {
dlcache.append();
} else {
s.static_parts();
h.static_parts(s);
f.static_parts(s);
i.static_parts(s);
dlcache.store();
}
s.dynamic_parts();
h.dynamic_parts(s);
f.dynamic_parts(s,Marlin_LCD_API::getFeedRate_percent());
i.dynamic_parts(s);
cmd.Cmd(DL_DISPLAY);
cmd.Cmd(CMD_SWAP);
cmd.Cmd_Execute();
}
bool FeedrateScreen::onTouchHeld(uint8_t tag) {
float inc = getIncrement();
switch(tag) {
case 4: Marlin_LCD_API::setFeedrate_percent(Marlin_LCD_API::getFeedRate_percent() - inc); break;
case 5: Marlin_LCD_API::setFeedrate_percent(Marlin_LCD_API::getFeedRate_percent() + inc); break;
default:
return false;
}
onRefresh();
return true;
}
/***************************** FILES SCREEN ***************************/
#if defined(LCD_PORTRAIT)
#define GRID_COLS 6
#define GRID_ROWS 14
#else
#define GRID_COLS 3
#define GRID_ROWS 6
#endif
const uint16_t filesPerPage = GRID_ROWS - 4;
void FilesScreen::onEntry() {
screen_data.FilesScreen.page = 0;
screen_data.FilesScreen.selected_tag = 0xFF;
UIScreen::onEntry();
}
const char *FilesScreen::getSelectedShortFilename() {
Marlin_LCD_API::Media_Iterator iterator(getIndexForTag(screen_data.FilesScreen.selected_tag));
return iterator.shortFilename();
}
uint8_t FilesScreen::getTagForIndex(uint16_t fileIndex) {
return fileIndex + 1;
}
uint16_t FilesScreen::getIndexForTag(uint8_t tag) {
return tag - 1;
}
void FilesScreen::onRefresh() {
CLCD::DLCache dlcache(FILES_SCREEN_CACHE);
CLCD::CommandFifo cmd;
cmd.Cmd(CMD_DLSTART);
cmd.Cmd_Set_Clear_Color(Theme::background);
cmd.Cmd_Clear(1,1,1);
#define MARGIN_T 0
#define MARGIN_B 0
bool dirSelected = false;
Marlin_LCD_API::Media_Iterator iterator(screen_data.FilesScreen.page * filesPerPage);
if(iterator.count()) {
do {
const uint16_t tag = getTagForIndex(iterator.value());
const bool isDir = iterator.isDirectory();
BTN_TAG(tag)
if(screen_data.FilesScreen.selected_tag == tag) {
RGB(Theme::files_selected)
dirSelected = isDir;
} else {
RGB(Theme::background)
}
BTN( BTN_POS(1,tag+2), BTN_SIZE(6,1), F(""), FONT_SML, OPT_FLAT);
BTX( BTN_POS(1,tag+2), BTN_SIZE(6,1), iterator.filename(), FONT_LRG, OPT_CENTERY);
if(isDir) {
BTX( BTN_POS(1,tag+2), BTN_SIZE(6,1), F("> "), FONT_LRG, OPT_CENTERY | OPT_RIGHTX);
}
iterator.next();
} while(iterator.hasMore());
}
#define MARGIN_T 5
#define MARGIN_B 5
const uint16_t pageCount = iterator.count() / filesPerPage + 1;
const bool prevEnabled = screen_data.FilesScreen.page > 0;
const bool nextEnabled = screen_data.FilesScreen.page < (pageCount - 1);
const bool itemSelected = screen_data.FilesScreen.selected_tag != 0xFF;
const uint8_t backTag = Marlin_LCD_API::isAtRootDir() ? 240 : 245;
char page_str[15];
sprintf_P(page_str, PSTR("Page %d of %d"), screen_data.FilesScreen.page + 1, pageCount);
#if defined(LCD_PORTRAIT)
BTN_TAG(0)
BTX( BTN_POS(1,1), BTN_SIZE(6,1), page_str, FONT_LRG, OPT_CENTER);
if(prevEnabled) {BTN_TAG(241); BTN( BTN_POS(1,1), BTN_SIZE(1,2), F("<"), MENU_BTN_STYLE);}
if(nextEnabled) {BTN_TAG(242); BTN( BTN_POS(6,1), BTN_SIZE(1,2), F(">"), MENU_BTN_STYLE);}
#define MARGIN_T 15
BTN_TAG(backTag) THEME(back_btn) BTN( BTN_POS(5,13), BTN_SIZE(2,2), F("Back"), MENU_BTN_STYLE);
BTN_ENABLED(itemSelected)
if(dirSelected) {
BTN_TAG(244); BTN( BTN_POS(1,13), BTN_SIZE(4,2), F("Open"), MENU_BTN_STYLE);
} else {
BTN_TAG(243); BTN( BTN_POS(1,13), BTN_SIZE(4,2), F("Print"), MENU_BTN_STYLE);
}
#else
BTN_TAG(backTag) THEME(back_btn) BTN( BTN_POS(1,4), BTN_SIZE(1,1), F("Back"), MENU_BTN_STYLE);
#endif
#define MARGIN_T 5
cmd.Cmd(DL_DISPLAY);
cmd.Cmd(CMD_SWAP);
cmd.Cmd_Execute();
}
bool FilesScreen::onTouchStart(uint8_t tag) {
switch(tag) {
case 240: GOTO_PREVIOUS(); return true;
case 241: screen_data.FilesScreen.page--; break;
case 242: screen_data.FilesScreen.page++; break;
case 243:
Marlin_LCD_API::printFromSDCard(getSelectedShortFilename());
lcd_setstatusPGM(PSTR("Print Starting"), 0);
GOTO_SCREEN(StatusScreen);
sound.play(start_print);
return true;
case 244:
Marlin_LCD_API::changeDir(getSelectedShortFilename());
break;
case 245:
Marlin_LCD_API::upDir();
break;
default:
if(tag < 240) {
if(screen_data.FilesScreen.selected_tag != tag) {
screen_data.FilesScreen.selected_tag = tag;
} else {
// Double clicked.
}
}
break;
}
onRefresh();
return true;
}
/******************************** MAIN EVENT HANDLER *******************************/
void lcd_setstatusPGM(const char * const message, int8_t level = 0);
void lcd_init() {
CLCD::Init();
CLCD::DLCache::init();
Marlin_LCD_API::initMedia();
lcd_setstatusPGM(PSTR(WELCOME_MSG));
current_screen.start();
}
void lcd_update() {
enum {
UNPRESSED = 0xFF, //255
IGNORE_UNPRESS = 0xFE, //254
DEBOUNCING = 0xFD //253
};
static uint8_t pressed_state = UNPRESSED;
static tiny_interval_t touch_timer;
static tiny_interval_t refresh_timer;
sound.onIdle();
if(refresh_timer.elapsed()) {
refresh_timer.wait_for(DISPLAY_UPDATE_INTERVAL);
current_screen.onIdle();
}
Marlin_LCD_API::checkMedia();
// If the LCD is processing commands, don't check
// for tags since they may be changing and could
// cause spurious events.
if(!CLCD::CommandFifo::Cmd_Is_Idle()) {
return;
}
const uint8_t tag = CLCD::Get_Tag();
switch(pressed_state) {
case UNPRESSED:
if(tag != 0) {
#if defined(UI_FRAMEWORK_DEBUG)
#if defined (SERIAL_PROTOCOLLNPAIR)
SERIAL_PROTOCOLLNPAIR("Touch start: ", tag);
#else
Serial.print(F("Touch start: "));
Serial.println(tag);
#endif
#endif
// When the user taps on a button, activate the onTouchStart handler
const uint8_t lastScreen = current_screen.getScreen();
if(current_screen.onTouchStart(tag)) {
touch_timer.wait_for(1000 / TOUCH_REPEATS_PER_SECOND);
sound.play(Theme::press_sound);
}
if(lastScreen != current_screen.getScreen()) {
// In the case in which a touch event triggered a new screen to be
// drawn, we don't issue a touchEnd since it would be sent to the
// wrong screen.
pressed_state = IGNORE_UNPRESS;
#if defined(UI_FRAMEWORK_DEBUG)
#if defined (SERIAL_PROTOCOLLNPAIR)
SERIAL_PROTOCOLLNPAIR("Ignoring press", tag);
#else
Serial.print(F("Ignoring press"));
Serial.println(tag);
#endif
#endif
} else {
pressed_state = tag;
}
}
break;
case DEBOUNCING:
if(tag == 0) {
if(touch_timer.elapsed()) {
pressed_state = UNPRESSED;
sound.play(Theme::unpress_sound);
}
} else {
pressed_state = IGNORE_UNPRESS;
}
break;
case IGNORE_UNPRESS:
if(tag == 0) {
// Ignore subsequent presses for a while to avoid bouncing
touch_timer.wait_for(DEBOUNCE_PERIOD);
pressed_state = DEBOUNCING;
}
break;
default: // PRESSED
if(tag == pressed_state) {
// The user is holding down a button.
if(touch_timer.elapsed() && current_screen.onTouchHeld(tag)) {
sound.play(Theme::repeat_sound);
touch_timer.wait_for(1000 / TOUCH_REPEATS_PER_SECOND);
}
}
else if(tag == 0) {
#if defined(UI_FRAMEWORK_DEBUG)
#if defined (SERIAL_PROTOCOLLNPAIR)
SERIAL_PROTOCOLLNPAIR("Touch end: ", pressed_state);
#else
Serial.print(F("Touch end: "));
Serial.println(pressed_state);
#endif
#endif
current_screen.onTouchEnd(pressed_state);
// Ignore subsequent presses for a while to avoid bouncing
touch_timer.wait_for(DEBOUNCE_PERIOD);
pressed_state = DEBOUNCING;
}
break;
}
}
inline bool lcd_hasstatus() { return true; }
void lcd_setstatus(const char * const message, const bool persist /* = false */) {
StatusScreen::setStatusMessage(message);
}
void lcd_setstatusPGM(const char * const message, int8_t level /* = 0 */) {
char buff[64];
strncpy_P(buff, message, sizeof(buff));
StatusScreen::setStatusMessage(buff);
}
void lcd_status_printf_P(const uint8_t level, const char * const fmt, ...) {
char buff[64];
va_list args;
va_start(args, fmt);
vsnprintf_P(buff, sizeof(buff), fmt, args);
va_end(args);
StatusScreen::setStatusMessage(buff);
}
void lcd_setalertstatusPGM(const char * const message) {
lcd_setstatusPGM(message, 1);
GOTO_SCREEN(StatusScreen);
}
void lcd_buttons_update() {}
inline void lcd_reset_alert_level() {}
inline void lcd_refresh() {current_screen.onIdle();}
void Marlin_LCD_API::onPrinterKilled(const char* lcd_msg) {
KillScreen::show(progmem_str(lcd_msg));
}
void Marlin_LCD_API::onCardInserted() {
lcd_setstatusPGM(PSTR(MSG_SD_INSERTED), 0);
sound.play(card_inserted);
}
void Marlin_LCD_API::onCardRemoved() {
lcd_setstatusPGM(PSTR(MSG_SD_REMOVED), 0);
sound.play(card_removed);
}
void Marlin_LCD_API::onPlayTone(const uint16_t frequency, const uint16_t duration) {
sound.playTone(frequency, duration);
}