//
// Teensy 4.1 RA8875 template - version 1.0 dated 20240921-2100
//
// - designed & written by Mark J Culross (KD5RXT)
//
// - controlled via buttons/sliders displayed on a 7" RA8875 800x480 display w/ touchscreen from here:
//
// https://www.buydisplay.com/7-inch-lcd-module-capacitive-touch-screen-panel-i2c-spi-serial
//
// Display options (ER-TFTM070-5):
// Interface: Pin Header Connection-4-wire SPI
// VDD: 5.0V (can always change the jumper later to power from 3.3VDC)
// Touch Panel: 7" Capacitive Touch Panel with Controller
// MicroSD Card Interface: Pin Header Connection (not useable - see display docs)
// Font Chip: (none selected)
//
// Make sure to edit C:\Program Files (x86)\Arduino\hardware\teensy\avr\libraries\RA8875\_settings\RA8875UserSettings.h
// - uncomment the following line: #define USE_FT5206_TOUCH//capacitive touch screen
//
// Arduino IDE Configuration (last built with Arduino 1.8.19 + Teensyduino 1.59):
// Tools/Board: "Teensy 4.1"
// Tools/USB Type: "Serial"
// Tools/CPU Speed: "600MHz"
// Tools/Optimize: "Faster"
// Tools/Keyboard Layout: "US English"
// Tools/Port: "COMx Serial (Teensy 4.1)"
//
//
const String VERSION0 = "1.0";
const String VERSION1 = ">> Teensy RA8875 template <<";
const String VERSION2 = "version " + VERSION0 + " dated 09/21/2024 @2100";
const String VERSION3 = "designed & written by Mark J Culross (KD5RXT)";
//#define DISABLE_BACKLIGHT_CONTROL // uncomment to disable backlight control (NOTE: enabling may induce 230Hz tone in LINE OUT audio)
//#define DEBUG_TOUCHSCREEN // uncomment to print touchscreen coordinates & touch state to SerialMonitor
//#define DEBUG_SLIDER_BUMP // uncomment to print slider bump up/down calculations & intermediate values to SerialMonitor
#include <SPI.h> // to avoid unnecessary compile errors, this *must* appear in the list of includes *before* RA8875
#include <RA8875.h>
// when used w/ Audio Adapter, must use an alternate CS pin for the display
const int RA8875_CHIP_SELECT = 38; // Teensy 38 (A14) -to- RA8875 05
const int RA8875_RESET = 3; // Teensy 03 (D03) -to -RA8875 11
const int RA8875_MISO = 39; // Teensy 39 (A15) -to- RA8875 06
const int RA8875_MOSI = 26; // Teensy 26 (A12) -to- RA8875 07
const int RA8875_SCLK = 27; // Teensy 27 (A13) -to- RA8875 08
const int RA8875_TS_INT = 2; // Teensy 02 (D02) -to- RA8875 33
const int RA8875_MAX_TOUCH_LIMIT = 1;
RA8875 tft = RA8875(RA8875_CHIP_SELECT, RA8875_RESET, RA8875_MOSI, RA8875_SCLK, RA8875_MISO);
//
// The following pins are used in this project:
//
// PIN D0 = (not used)
// PIN D1 = (not used)
// PIN D2 = RA8875 Touchscreen INT
// PIN D3 = RA8875 Touchscreen RESET
// PIN D4 = CHECK_BATTERY_PIN
// PIN D5 = (not used)
// PIN D6 = (not used)
// PIN D7 = (not used)
// PIN D8 = (not used)
// PIN D9 = (not used)
// PIN D10 = (not used)
// PIN D11 = (not used)
// PIN D12 = (not used)
// PIN D13 = (not used)
// PIN D14/A0 = (not used)
// PIN D15/A1 = (not used)
// PIN D16/A2 = (not used)
// PIN D17/A3 = (not used)
// PIN D18/A4 = (not used)
// PIN D19/A5 = (not used)
// PIN D20/A6 = (not used)
// PIN D21/A7 = (not used)
// PIN D22/A8 = (not used)
// PIN D23/A9 = (not used)
// PIN D24/A10 = (not used)
// PIN D25/A11 = (not used)
// PIN D26/A12 = RA8875 Touchscreen MOSI (MOSI1)
// PIN D27/A13 = RA8875 Touchscreen SCLK (SCK1)
// PIN D28 = (not used)
// PIN D29 = (not used)
// PIN D30 = (not used)
// PIN D31 = (not used)
// PIN D32 = (not used)
// PIN D33 = (not used)
// PIN D34 = (not used)
// PIN D35 = (not used)
// PIN D36 = (not used)
// PIN D37 = (not used)
// PIN D38/A14 = RA8875 Touchscreen CS (CS1)
// PIN D39/A15 = RA8875 Touchscreen MISO (MISO1)
// PIN D40/A16 = (not used)
// PIN D41/A17 = (not used)
// onboard LED on pin 13
#define LED_PIN 13
#define LED_PIN_ON 16
#define LED_PIN_OFF 0
// keep track of splash screen delay
const int CHECK_SPLASH_MILLIS = 4000;
unsigned long check_splash_time;
// keep track of when the screen needs to be updated
boolean screen_update_required = false;
// keep track of how often to check touchscreen
const int CHECK_TOUCHSCREEN_MILLIS = 20;
unsigned long check_touchscreen_time = millis();
// custom RA8875 TFT colors (5-bit RED, 6-bit GREEN, 5-bit BLUE)
#define RA8875_DIMGREY 0x6B4D
#define RA8875_MDGREY 0x8410
#define RA8875_ASHGREY 0xB5F6
#define RA8875_ORANGE 0xFB00
typedef enum
{
CONFIG_MODE_SPLASH = 0, CONFIG_MODE_INIT_SCREEN,
CONFIG_MODE_MENU1, CONFIG_MODE_MENU2, CONFIG_MODE_MENU3, CONFIG_MODE_MENU4,
} CONFIG_MODE;
CONFIG_MODE config_mode = CONFIG_MODE_SPLASH;
boolean previously_touched = false;
boolean touch_triggered = false;
// global touchscreen coordinates (in pixels) where touched
int16_t BtnX = -1, BtnY = -1;
struct BUTTON_TYPE
{
unsigned int xCenterLoc;
unsigned int yCenterLoc;
unsigned int xSize;
unsigned int ySize;
const String* textPtr;
uint16_t textColor;
uint16_t buttonColor;
uint16_t borderColor;
boolean activated;
};
// create button objects, passing in the display object
// UNIQUE PORTION OF THE DISPLAY SCREEN (only used for clearing the bottom portion of the screen & detecting touches)
const String uniqueScreenAreaText = "";
BUTTON_TYPE uniqueScreenArea = {400, 270, 800, 420, &uniqueScreenAreaText, RA8875_BLACK, RA8875_BLACK, RA8875_BLACK, true};
// CHANGING BUTTON PORTION OF THE DISPLAY SCREEN (only used for clearing/redrawing buttons when changing menus)
const String buttonScreenAreaText = "";
BUTTON_TYPE buttonScreenArea = {400, 81, 630, 50, &buttonScreenAreaText, RA8875_BLACK, RA8875_BLACK, RA8875_BLACK, true};
// PRIMARY BUTTONS
const String menu1ButtonText = "MENU 1";
BUTTON_TYPE menu1Button = {120, 48, 70, 36, &menu1ButtonText, RA8875_BLACK, RA8875_GREEN, RA8875_ORANGE, false};
const String menu2ButtonText = "MENU 2";
BUTTON_TYPE menu2Button = {195, 48, 70, 36, &menu2ButtonText, RA8875_BLACK, RA8875_GREEN, RA8875_ORANGE, false};
const String menu3ButtonText = "MENU 3";
BUTTON_TYPE menu3Button = {270, 48, 70, 36, &menu3ButtonText, RA8875_BLACK, RA8875_GREEN, RA8875_ORANGE, false};
const String menu4ButtonText = "MENU 4";
BUTTON_TYPE menu4Button = {345, 48, 70, 36, &menu4ButtonText, RA8875_BLACK, RA8875_GREEN, RA8875_ORANGE, false};
// MENU 1 BUTTONS
const String menu1BacklightButtonTextV = "BACKLIGHT";
BUTTON_TYPE menu1BacklightButtonV = {750, 91, 90, 30, &menu1BacklightButtonTextV, RA8875_GREEN, RA8875_BLACK, RA8875_RED, true};
const String menu1BacklightButtonTextH = "BACKLIGHT";
BUTTON_TYPE menu1BacklightButtonH = {400, 240, 90, 30, &menu1BacklightButtonTextH, RA8875_GREEN, RA8875_BLACK, RA8875_RED, true};
const String menu1Button1Text = "BUTTON 1-1";
BUTTON_TYPE menu1Button1 = {100, 200, 90, 30, &menu1Button1Text, RA8875_BLACK, RA8875_GREEN, RA8875_RED, true};
const String menu1Button2Text = "BUTTON 1-2";
BUTTON_TYPE menu1Button2 = {100, 250, 90, 30, &menu1Button2Text, RA8875_BLACK, RA8875_GREEN, RA8875_RED, true};
const String menu1Button3Text = "BUTTON 1-3";
BUTTON_TYPE menu1Button3 = {100, 300, 90, 30, &menu1Button3Text, RA8875_BLACK, RA8875_GREEN, RA8875_RED, true};
const String menu1Button4Text = "BUTTON 1-4";
BUTTON_TYPE menu1Button4 = {100, 350, 90, 30, &menu1Button4Text, RA8875_BLACK, RA8875_GREEN, RA8875_RED, true};
// MENU 2 BUTTONS
const String menu2Button1Text = "BUTTON 2-1";
BUTTON_TYPE menu2Button1 = {100, 200, 90, 30, &menu2Button1Text, RA8875_BLACK, RA8875_GREEN, RA8875_RED, true};
const String menu2Button2Text = "BUTTON 2-2";
BUTTON_TYPE menu2Button2 = {100, 250, 90, 30, &menu2Button2Text, RA8875_BLACK, RA8875_GREEN, RA8875_RED, true};
const String menu2Button3Text = "BUTTON 2-3";
BUTTON_TYPE menu2Button3 = {100, 300, 90, 30, &menu2Button3Text, RA8875_BLACK, RA8875_GREEN, RA8875_RED, true};
const String menu2Button4Text = "BUTTON 2-4";
BUTTON_TYPE menu2Button4 = {100, 350, 90, 30, &menu2Button4Text, RA8875_BLACK, RA8875_GREEN, RA8875_RED, true};
// MENU 3 BUTTONS
const String menu3Button1Text = "BUTTON 3-1";
BUTTON_TYPE menu3Button1 = {100, 200, 90, 30, &menu3Button1Text, RA8875_BLACK, RA8875_GREEN, RA8875_RED, true};
const String menu3Button2Text = "BUTTON 3-2";
BUTTON_TYPE menu3Button2 = {100, 250, 90, 30, &menu3Button2Text, RA8875_BLACK, RA8875_GREEN, RA8875_RED, true};
const String menu3Button3Text = "BUTTON 3-3";
BUTTON_TYPE menu3Button3 = {100, 300, 90, 30, &menu3Button3Text, RA8875_BLACK, RA8875_GREEN, RA8875_RED, true};
const String menu3Button4Text = "BUTTON 3-4";
BUTTON_TYPE menu3Button4 = {100, 350, 90, 30, &menu3Button4Text, RA8875_BLACK, RA8875_GREEN, RA8875_RED, true};
// MENU 4 BUTTONS
const String menu4Button1Text = "BUTTON 4-1";
BUTTON_TYPE menu4Button1 = {100, 200, 90, 30, &menu4Button1Text, RA8875_BLACK, RA8875_GREEN, RA8875_RED, true};
const String menu4Button2Text = "BUTTON 4-2";
BUTTON_TYPE menu4Button2 = {100, 250, 90, 30, &menu4Button2Text, RA8875_BLACK, RA8875_GREEN, RA8875_RED, true};
const String menu4Button3Text = "BUTTON 4-3";
BUTTON_TYPE menu4Button3 = {100, 300, 90, 30, &menu4Button3Text, RA8875_BLACK, RA8875_GREEN, RA8875_RED, true};
const String menu4Button4Text = "BUTTON 4-4";
BUTTON_TYPE menu4Button4 = {100, 350, 90, 30, &menu4Button4Text, RA8875_BLACK, RA8875_GREEN, RA8875_RED, true};
#define BUMP_REPEAT_START_DELAY_MILLISECONDS 750
typedef enum
{
SLIDER_MODE_HORIZONTAL = 0, SLIDER_MODE_VERTICAL
} SLIDER_MODE;
struct SLIDER_TYPE
{
unsigned int xCenterLoc;
unsigned int yCenterLoc;
unsigned int xSize;
unsigned int ySize;
float value;
unsigned int minorTickSections; // normally = 10
unsigned int majorTickSections; // normally = 2
unsigned int placesBeforeTheDecimal;
unsigned int placesAfterTheDecimal;
boolean showPlusMinusSign;
float minValue; // for HORIZONTAL = all the way to the left, for VERTICAL, all the way up
float maxValue; // for HORIZONTAL = all the way to the right, for VERTICAL, all the way down
boolean withBumpUpArrow;
boolean withBumpDownArrow;
float bumpValue;
unsigned int xValueCenterLoc;
unsigned int yValueCenterLoc;
uint16_t valueColor;
uint16_t backgroundColor;
uint16_t borderColor;
uint16_t scaleColor;
uint16_t handleColor;
uint16_t handleBorderColor;
uint16_t backgroundColorDisabled;
uint16_t borderColorDisabled;
uint16_t scaleColorDisabled;
uint16_t handleColorDisabled;
uint16_t handleBorderColorDisabled;
uint16_t bumpBackgroundColor;
boolean activated;
boolean repeatEnabled;
boolean previouslyTouched;
unsigned long touchStartMillis;
unsigned int repeatMilliseconds;
SLIDER_MODE orientation;
};
SLIDER_TYPE menu1BacklightSliderV = { 750, 305, 30, 255, 127.00, 16, 2, 3, 0, false, 1.0, 255.0, true, true, 1.00, 750, 115, RA8875_WHITE, RA8875_MDGREY, RA8875_GREEN, RA8875_BLACK, RA8875_GREEN, RA8875_BLACK, RA8875_BLACK, RA8875_MDGREY, RA8875_MDGREY, RA8875_MDGREY, RA8875_BLACK, RA8875_BLACK, true, true, false, 0, 250, SLIDER_MODE_VERTICAL };
SLIDER_TYPE menu1BacklightSliderH = { 400, 305, 255, 30, 127.00, 16, 2, 3, 0, false, 1.0, 255.0, true, true, 1.00, 400, 265, RA8875_WHITE, RA8875_MDGREY, RA8875_GREEN, RA8875_BLACK, RA8875_GREEN, RA8875_BLACK, RA8875_BLACK, RA8875_MDGREY, RA8875_MDGREY, RA8875_MDGREY, RA8875_BLACK, RA8875_BLACK, true, true, false, 0, 250, SLIDER_MODE_HORIZONTAL };
// function headers
void centerDrawText(const String text, unsigned int xCenterLoc, unsigned int yCenterLoc, uint16_t textColor, uint16_t textBackground);
boolean checkButton(BUTTON_TYPE thisButton);
boolean checkSlider(SLIDER_TYPE* thisSlider);
boolean checkSliderBumpDown(SLIDER_TYPE* thisSlider);
boolean checkSliderBumpUp(SLIDER_TYPE* thisSlider);
void drawButton(BUTTON_TYPE thisButton);
void drawScreen(void);
void drawSlider(SLIDER_TYPE thisSlider);
void loop();
boolean processTouchscreen(void);
void setup();
// draw text, centered around xLoc & yLoc
void centerDrawText(const String text, unsigned int xCenterLoc, unsigned int yCenterLoc, uint16_t textColor, uint16_t textBackground)
{
unsigned int xOffset = (text.length() * 8) / 2;
unsigned int yOffset = 8;
tft.setTextColor(textColor, textBackground);
tft.setTextSize(1);
tft.setCursor(xCenterLoc - xOffset, yCenterLoc - yOffset);
tft.print(text);
} // centerDrawText
// check if a button was pressed
boolean checkButton(BUTTON_TYPE thisButton)
{
boolean retVal = false;
// if touched most recently in thisButton
if ((BtnX >= (uint16_t)(thisButton.xCenterLoc - (thisButton.xSize / 2))) &&
(BtnX <= (uint16_t)(thisButton.xCenterLoc + (thisButton.xSize / 2))) &&
(BtnY >= (uint16_t)(thisButton.yCenterLoc - (thisButton.ySize / 2))) &&
(BtnY <= (uint16_t)(thisButton.yCenterLoc + (thisButton.ySize / 2))))
{
retVal = true;
}
return (retVal);
} // checkButton()
// check if a slider has changed
boolean checkSlider(SLIDER_TYPE* thisSlider)
{
boolean retVal = false;
float newValue = 0.0f;
// if thisSlider is active & touched most recently in thisSlider
if (thisSlider->activated)
{
if (thisSlider->orientation == SLIDER_MODE_VERTICAL)
{
// if touched most recently in thisSlider
if ((BtnX >= (uint16_t)(thisSlider->xCenterLoc - ((thisSlider->xSize / 2) + 15))) &&
(BtnX <= (uint16_t)(thisSlider->xCenterLoc + ((thisSlider->xSize / 2) + 15))) &&
(BtnY >= (uint16_t)(thisSlider->yCenterLoc - ((thisSlider->ySize / 2)))) &&
(BtnY <= (uint16_t)(thisSlider->yCenterLoc + ((thisSlider->ySize / 2)))))
{
if (BtnX < (uint16_t)(thisSlider->xCenterLoc - (thisSlider->xSize / 2)))
{
BtnX = (uint16_t)(thisSlider->xCenterLoc - (thisSlider->xSize / 2));
}
if (BtnX > (uint16_t)(thisSlider->xCenterLoc + (thisSlider->xSize / 2)))
{
BtnX = (uint16_t)(thisSlider->xCenterLoc + (thisSlider->xSize / 2));
}
if (BtnY < (uint16_t)(thisSlider->yCenterLoc - (thisSlider->ySize / 2)))
{
BtnY = (uint16_t)(thisSlider->yCenterLoc - (thisSlider->ySize / 2));
}
if (BtnY > (uint16_t)(thisSlider->yCenterLoc + (thisSlider->ySize / 2)))
{
BtnY = (uint16_t)(thisSlider->yCenterLoc + (thisSlider->ySize / 2));
}
newValue = (float)map((float)BtnY, (float)(thisSlider->yCenterLoc - (thisSlider->ySize / 2)), (float)(thisSlider->yCenterLoc + (thisSlider->ySize / 2)), thisSlider->maxValue, thisSlider->minValue);
if (newValue != thisSlider->value)
{
thisSlider->value = newValue;
retVal = true;
}
} else {
// if thisSlider is active & has either bump arrow & has been held & was touched most recently in thisSlider's bump arrow area
if ((thisSlider->withBumpDownArrow || thisSlider->withBumpUpArrow) && (thisSlider->repeatEnabled))
{
// if touched most recently in thisSlider's bump up arrow
if ((BtnX >= (uint16_t)(thisSlider->xCenterLoc - ((thisSlider->xSize / 2)))) &&
(BtnX <= (uint16_t)(thisSlider->xCenterLoc + ((thisSlider->xSize / 2)))) &&
(BtnY >= (uint16_t)(thisSlider->yCenterLoc - ((thisSlider->ySize / 2) + 50))) &&
(BtnY <= (uint16_t)(thisSlider->yCenterLoc - ((thisSlider->ySize / 2)))))
{
#ifdef DEBUG_SLIDER_BUMP
Serial.print("initial slider value: ");
Serial.println(thisSlider->value);
Serial.print("slider bump up value: ");
Serial.println(thisSlider->bumpValue);
#endif
if (!(thisSlider->previouslyTouched))
{
thisSlider->previouslyTouched = true;
thisSlider->touchStartMillis = millis();
} else {
if ((millis() - thisSlider->touchStartMillis) > BUMP_REPEAT_START_DELAY_MILLISECONDS)
{
if ((thisSlider->value + thisSlider->bumpValue) < thisSlider->maxValue)
{
thisSlider->value = (float)((round)(thisSlider->value / thisSlider->bumpValue)) * thisSlider->bumpValue;
thisSlider->value += thisSlider->bumpValue;
} else {
thisSlider->value = thisSlider->maxValue;
}
#ifdef DEBUG_SLIDER_BUMP
Serial.print("resulting slider value: ");
Serial.println(thisSlider->value);
Serial.println("");
#endif
retVal = true;
}
}
} else {
// if touched most recently in thisSlider's bump down arrow
if ((BtnX >= (uint16_t)(thisSlider->xCenterLoc - ((thisSlider->xSize / 2)))) &&
(BtnX <= (uint16_t)(thisSlider->xCenterLoc + ((thisSlider->xSize / 2)))) &&
(BtnY >= (uint16_t)(thisSlider->yCenterLoc + (thisSlider->ySize / 2))) &&
(BtnY <= (uint16_t)(thisSlider->yCenterLoc + ((thisSlider->ySize / 2) + 50))))
{
#ifdef DEBUG_SLIDER_BUMP
Serial.print("initial slider value: ");
Serial.println(thisSlider->value);
Serial.print("slider bump down value: ");
Serial.println(thisSlider->bumpValue);
#endif
if (!(thisSlider->previouslyTouched))
{
thisSlider->previouslyTouched = true;
thisSlider->touchStartMillis = millis();
} else {
if ((millis() - thisSlider->touchStartMillis) > BUMP_REPEAT_START_DELAY_MILLISECONDS)
{
if ((thisSlider->value - thisSlider->bumpValue) > thisSlider->minValue)
{
thisSlider->value = (float)((round)(thisSlider->value / thisSlider->bumpValue)) * thisSlider->bumpValue;
thisSlider->value -= thisSlider->bumpValue;
} else {
thisSlider->value = thisSlider->minValue;
}
#ifdef DEBUG_SLIDER_BUMP
Serial.print("resulting slider value: ");
Serial.println(thisSlider->value);
Serial.println("");
#endif
retVal = true;
}
}
} else {
// force another wait delay before repeat
thisSlider->previouslyTouched = false;
}
}
} else {
// force another wait delay before repeat
thisSlider->previouslyTouched = false;
}
}
} else { // SLIDER_MODE_HORIZONTAL
// if touched most recently in thisSlider
if ((BtnX >= (uint16_t)(thisSlider->xCenterLoc - ((thisSlider->xSize / 2) + 15))) &&
(BtnX <= (uint16_t)(thisSlider->xCenterLoc + ((thisSlider->xSize / 2) + 15))) &&
(BtnY >= (uint16_t)(thisSlider->yCenterLoc - ((thisSlider->ySize / 2)))) &&
(BtnY <= (uint16_t)(thisSlider->yCenterLoc + ((thisSlider->ySize / 2)))))
{
if (BtnX < (uint16_t)(thisSlider->xCenterLoc - (thisSlider->xSize / 2)))
{
BtnX = (uint16_t)(thisSlider->xCenterLoc - (thisSlider->xSize / 2));
}
if (BtnX > (uint16_t)(thisSlider->xCenterLoc + (thisSlider->xSize / 2)))
{
BtnX = (uint16_t)(thisSlider->xCenterLoc + (thisSlider->xSize / 2));
}
if (BtnY < (uint16_t)(thisSlider->yCenterLoc - (thisSlider->ySize / 2)))
{
BtnY = (uint16_t)(thisSlider->yCenterLoc - (thisSlider->ySize / 2));
}
if (BtnY > (uint16_t)(thisSlider->yCenterLoc + (thisSlider->ySize / 2)))
{
BtnY = (uint16_t)(thisSlider->yCenterLoc + (thisSlider->ySize / 2));
}
newValue = (float)map((float)BtnX, (float)(thisSlider->xCenterLoc - (thisSlider->xSize / 2)), (float)(thisSlider->xCenterLoc + (thisSlider->xSize / 2)), thisSlider->minValue, thisSlider->maxValue);
if (newValue != thisSlider->value)
{
thisSlider->value = newValue;
retVal = true;
}
} else {
// if thisSlider is active & has either bump arrow & has been held & was touched most recently in thisSlider's bump arrow area
if ((thisSlider->withBumpDownArrow || thisSlider->withBumpUpArrow) && (thisSlider->repeatEnabled))
{
// if touched most recently in thisSlider's bump up arrow
if ((BtnX >= (uint16_t)(thisSlider->xCenterLoc + ((thisSlider->xSize / 2)))) &&
(BtnX <= (uint16_t)(thisSlider->xCenterLoc + ((thisSlider->xSize / 2) + 50))) &&
(BtnY >= (uint16_t)(thisSlider->yCenterLoc - ((thisSlider->ySize / 2)))) &&
(BtnY <= (uint16_t)(thisSlider->yCenterLoc + ((thisSlider->ySize / 2)))))
{
#ifdef DEBUG_SLIDER_BUMP
Serial.print("initial slider value: ");
Serial.println(thisSlider->value);
Serial.print("slider bump up value: ");
Serial.println(thisSlider->bumpValue);
#endif
if (!(thisSlider->previouslyTouched))
{
thisSlider->previouslyTouched = true;
thisSlider->touchStartMillis = millis();
} else {
if ((millis() - thisSlider->touchStartMillis) > BUMP_REPEAT_START_DELAY_MILLISECONDS)
{
if ((thisSlider->value + thisSlider->bumpValue) < thisSlider->maxValue)
{
thisSlider->value = (float)((round)(thisSlider->value / thisSlider->bumpValue)) * thisSlider->bumpValue;
thisSlider->value += thisSlider->bumpValue;
} else {
thisSlider->value = thisSlider->maxValue;
}
#ifdef DEBUG_SLIDER_BUMP
Serial.print("resulting slider value: ");
Serial.println(thisSlider->value);
Serial.println("");
#endif
retVal = true;
}
}
} else {
// if touched most recently in thisSlider's bump down arrow
if ((BtnX >= (uint16_t)(thisSlider->xCenterLoc - ((thisSlider->xSize / 2) + 50))) &&
(BtnX <= (uint16_t)(thisSlider->xCenterLoc - ((thisSlider->xSize / 2)))) &&
(BtnY >= (uint16_t)(thisSlider->yCenterLoc - (thisSlider->ySize / 2))) &&
(BtnY <= (uint16_t)(thisSlider->yCenterLoc + ((thisSlider->ySize / 2)))))
{
#ifdef DEBUG_SLIDER_BUMP
Serial.print("initial slider value: ");
Serial.println(thisSlider->value);
Serial.print("slider bump down value: ");
Serial.println(thisSlider->bumpValue);
#endif
if (!(thisSlider->previouslyTouched))
{
thisSlider->previouslyTouched = true;
thisSlider->touchStartMillis = millis();
} else {
if ((millis() - thisSlider->touchStartMillis) > BUMP_REPEAT_START_DELAY_MILLISECONDS)
{
if ((thisSlider->value - thisSlider->bumpValue) > thisSlider->minValue)
{
thisSlider->value = (float)((round)(thisSlider->value / thisSlider->bumpValue)) * thisSlider->bumpValue;
thisSlider->value -= thisSlider->bumpValue;
} else {
thisSlider->value = thisSlider->minValue;
}
#ifdef DEBUG_SLIDER_BUMP
Serial.print("resulting slider value: ");
Serial.println(thisSlider->value);
Serial.println("");
#endif
retVal = true;
}
}
} else {
// force another wait delay before repeat
thisSlider->previouslyTouched = false;
}
}
} else {
// force another wait delay before repeat
thisSlider->previouslyTouched = false;
}
}
}
}
return (retVal);
} // checkSlider()
// check if a slider bump down arrow has been pressed
boolean checkSliderBumpDown(SLIDER_TYPE * thisSlider)
{
boolean retVal = false;
// if thisSlider is active & has a bump down arrow & was touched most recently in thisSlider's bump down arrow area
if ((thisSlider->activated) && (thisSlider->withBumpDownArrow))
{
if (thisSlider->orientation == SLIDER_MODE_VERTICAL)
{
// if touched most recently in thisSlider's bump down arrow
if ((BtnX >= (uint16_t)(thisSlider->xCenterLoc - ((thisSlider->xSize / 2)))) &&
(BtnX <= (uint16_t)(thisSlider->xCenterLoc + ((thisSlider->xSize / 2)))) &&
(BtnY >= (uint16_t)(thisSlider->yCenterLoc + ((thisSlider->ySize / 2)))) &&
(BtnY <= (uint16_t)(thisSlider->yCenterLoc + ((thisSlider->ySize / 2) + 50))))
{
#ifdef DEBUG_SLIDER_BUMP
Serial.print("initial slider value: ");
Serial.println(thisSlider->value);
Serial.print("slider bump down value: ");
Serial.println(thisSlider->bumpValue);
#endif
if ((thisSlider->value - thisSlider->bumpValue) > (thisSlider->minValue))
{
thisSlider->value = (float)((round)(thisSlider->value / thisSlider->bumpValue)) * thisSlider->bumpValue;
thisSlider->value -= thisSlider->bumpValue;
} else {
thisSlider->value = thisSlider->minValue;
}
#ifdef DEBUG_SLIDER_BUMP
Serial.print("resulting slider value: ");
Serial.println(thisSlider->value);
Serial.println("");
#endif
retVal = true;
// force another wait delay before repeat
thisSlider->previouslyTouched = false;
}
} else { // SLIDER_MODE_HORIZONTAL
// if touched most recently in thisSlider's bump down arrow
if ((BtnX >= (uint16_t)(thisSlider->xCenterLoc - ((thisSlider->xSize / 2) + 50))) &&
(BtnX <= (uint16_t)(thisSlider->xCenterLoc - ((thisSlider->xSize / 2)))) &&
(BtnY >= (uint16_t)(thisSlider->yCenterLoc - ((thisSlider->ySize / 2)))) &&
(BtnY <= (uint16_t)(thisSlider->yCenterLoc + ((thisSlider->ySize / 2)))))
{
#ifdef DEBUG_SLIDER_BUMP
Serial.print("initial slider value: ");
Serial.println(thisSlider->value);
Serial.print("slider bump down value: ");
Serial.println(thisSlider->bumpValue);
#endif
if ((thisSlider->value - thisSlider->bumpValue) > (thisSlider->minValue))
{
thisSlider->value = (float)((round)(thisSlider->value / thisSlider->bumpValue)) * thisSlider->bumpValue;
thisSlider->value -= thisSlider->bumpValue;
} else {
thisSlider->value = thisSlider->minValue;
}
#ifdef DEBUG_SLIDER_BUMP
Serial.print("resulting slider value: ");
Serial.println(thisSlider->value);
Serial.println("");
#endif
retVal = true;
// force another wait delay before repeat
thisSlider->previouslyTouched = false;
}
}
}
return (retVal);
} // checkSliderBumpDown()
// check if a slider bump up arrow has been pressed
boolean checkSliderBumpUp(SLIDER_TYPE * thisSlider)
{
boolean retVal = false;
// if thisSlider is active & has a bump up arrow & was touched most recently in thisSlider's bump up arrow area
if ((thisSlider->activated) && (thisSlider->withBumpUpArrow))
{
if (thisSlider->orientation == SLIDER_MODE_VERTICAL)
{
// if touched most recently in thisSlider's bump up arrow
if ((BtnX >= (uint16_t)(thisSlider->xCenterLoc - ((thisSlider->xSize / 2)))) &&
(BtnX <= (uint16_t)(thisSlider->xCenterLoc + ((thisSlider->xSize / 2)))) &&
(BtnY >= (uint16_t)(thisSlider->yCenterLoc - ((thisSlider->ySize / 2) + 50))) &&
(BtnY <= (uint16_t)(thisSlider->yCenterLoc - ((thisSlider->ySize / 2)))))
{
#ifdef DEBUG_SLIDER_BUMP
Serial.print("initial slider value: ");
Serial.println(thisSlider->value);
Serial.print("slider bump up value: ");
Serial.println(thisSlider->bumpValue);
#endif
if ((thisSlider->value + thisSlider->bumpValue) < thisSlider->maxValue)
{
thisSlider->value = (float)((round)(thisSlider->value / thisSlider->bumpValue)) * thisSlider->bumpValue;
thisSlider->value += thisSlider->bumpValue;
} else {
thisSlider->value = thisSlider->maxValue;
}
#ifdef DEBUG_SLIDER_BUMP
Serial.print("resulting slider value: ");
Serial.println(thisSlider->value);
Serial.println("");
#endif
retVal = true;
// force another wait delay before repeat
thisSlider->previouslyTouched = false;
}
} else {
// if touched most recently in thisSlider's bump up arrow
if ((BtnX >= (uint16_t)(thisSlider->xCenterLoc + ((thisSlider->xSize / 2)))) &&
(BtnX <= (uint16_t)(thisSlider->xCenterLoc + ((thisSlider->xSize / 2) + 50))) &&
(BtnY >= (uint16_t)(thisSlider->yCenterLoc - ((thisSlider->ySize / 2)))) &&
(BtnY <= (uint16_t)(thisSlider->yCenterLoc + ((thisSlider->ySize / 2)))))
{
#ifdef DEBUG_SLIDER_BUMP
Serial.print("initial slider value: ");
Serial.println(thisSlider->value);
Serial.print("slider bump up value: ");
Serial.println(thisSlider->bumpValue);
#endif
if ((thisSlider->value + thisSlider->bumpValue) < thisSlider->maxValue)
{
thisSlider->value = (float)((round)(thisSlider->value / thisSlider->bumpValue)) * thisSlider->bumpValue;
thisSlider->value += thisSlider->bumpValue;
} else {
thisSlider->value = thisSlider->maxValue;
}
#ifdef DEBUG_SLIDER_BUMP
Serial.print("resulting slider value: ");
Serial.println(thisSlider->value);
Serial.println("");
#endif
retVal = true;
// force another wait delay before repeat
thisSlider->previouslyTouched = false;
}
}
}
return (retVal);
} // checkSliderBumpUp()
// draw a button
void drawButton(BUTTON_TYPE thisButton)
{
if (thisButton.activated)
{
tft.fillRect(thisButton.xCenterLoc - (thisButton.xSize / 2) + 1, thisButton.yCenterLoc - (thisButton.ySize / 2) + 1, thisButton.xSize - 2, thisButton.ySize - 2, thisButton.buttonColor);
tft.drawRect(thisButton.xCenterLoc - (thisButton.xSize / 2), thisButton.yCenterLoc - (thisButton.ySize / 2), thisButton.xSize, thisButton.ySize, thisButton.borderColor);
centerDrawText(*(thisButton.textPtr), thisButton.xCenterLoc, thisButton.yCenterLoc, thisButton.textColor, thisButton.buttonColor);
} else {
tft.fillRect(thisButton.xCenterLoc - (thisButton.xSize / 2) + 1, thisButton.yCenterLoc - (thisButton.ySize / 2) + 1, thisButton.xSize - 2, thisButton.ySize - 2, thisButton.borderColor);
tft.drawRect(thisButton.xCenterLoc - (thisButton.xSize / 2), thisButton.yCenterLoc - (thisButton.ySize / 2), thisButton.xSize, thisButton.ySize, thisButton.buttonColor);
centerDrawText(*(thisButton.textPtr), thisButton.xCenterLoc, thisButton.yCenterLoc, thisButton.textColor, thisButton.borderColor);
}
} // drawButton()
// update the screen based upon the current mode
void drawScreen(void)
{
if (config_mode != CONFIG_MODE_SPLASH)
{
// clear the unique portion of the display screen
drawButton(uniqueScreenArea);
menu1Button.activated = false;
menu2Button.activated = false;
menu3Button.activated = false;
menu4Button.activated = false;
}
switch (config_mode)
{
case CONFIG_MODE_SPLASH:
{
tft.clearScreen(RA8875_BLACK);
// NOTE: first character printed to TFT after restart is lost (so print a "don't care" space character)
centerDrawText(" ", tft.width() / 2, tft.height() / 2 - 100, RA8875_GREEN, RA8875_BLACK);
centerDrawText(VERSION1, tft.width() / 2, tft.height() / 2 - 50, RA8875_GREEN, RA8875_BLACK);
centerDrawText(VERSION2, tft.width() / 2, tft.height() / 2, RA8875_YELLOW, RA8875_BLACK);
centerDrawText(VERSION3, tft.width() / 2, tft.height() / 2 + 50, RA8875_RED, RA8875_BLACK);
}
break;
case CONFIG_MODE_INIT_SCREEN:
{
tft.clearScreen(RA8875_BLACK);
tft.setTextColor(RA8875_GREEN, RA8875_BLACK);
tft.setCursor(95, 6);
tft.print(VERSION1);
tft.setCursor(405, 6);
tft.print(" [");
tft.print(VERSION2);
tft.print("]");
}
break;
case CONFIG_MODE_MENU1:
{
menu1Button.activated = true;
}
break;
case CONFIG_MODE_MENU2:
{
menu2Button.activated = true;
}
break;
case CONFIG_MODE_MENU3:
{
menu3Button.activated = true;
}
break;
case CONFIG_MODE_MENU4:
{
menu4Button.activated = true;
}
break;
}
if (config_mode > CONFIG_MODE_INIT_SCREEN)
{
// clear the button portion of the display screen
drawButton(buttonScreenArea);
drawButton(menu1Button);
drawButton(menu2Button);
drawButton(menu3Button);
drawButton(menu4Button);
}
// update screen using the current config mode
switch (config_mode)
{
case CONFIG_MODE_SPLASH:
case CONFIG_MODE_INIT_SCREEN:
{
}
break;
case CONFIG_MODE_MENU1:
{
tft.setTextSize(1);
tft.setTextColor(RA8875_WHITE);
#ifndef DISABLE_BACKLIGHT_CONTROL
drawSlider(menu1BacklightSliderV);
drawButton(menu1BacklightButtonV);
drawSlider(menu1BacklightSliderH);
drawButton(menu1BacklightButtonH);
drawButton(menu1Button1);
drawButton(menu1Button2);
drawButton(menu1Button3);
drawButton(menu1Button4);
#endif
}
break;
case CONFIG_MODE_MENU2:
{
drawButton(menu2Button1);
drawButton(menu2Button2);
drawButton(menu2Button3);
drawButton(menu2Button4);
}
break;
case CONFIG_MODE_MENU3:
{
drawButton(menu3Button1);
drawButton(menu3Button2);
drawButton(menu3Button3);
drawButton(menu3Button4);
}
break;
case CONFIG_MODE_MENU4:
{
drawButton(menu4Button1);
drawButton(menu4Button2);
drawButton(menu4Button3);
drawButton(menu4Button4);
}
break;
}
} // drawScreen()
// draw a slider
void drawSlider(SLIDER_TYPE thisSlider)
{
int characterCount = 0;
String outString = "";
if (thisSlider.value < thisSlider.minValue)
{
thisSlider.value = thisSlider.minValue;
}
if (thisSlider.value > thisSlider.maxValue)
{
thisSlider.value = thisSlider.maxValue;
}
if (thisSlider.orientation == SLIDER_MODE_HORIZONTAL)
{
if (thisSlider.activated)
{
// clear the bump down arrow area if enabled
if (thisSlider.withBumpDownArrow)
{
// clear the slider bump down arrow area
tft.fillRect(thisSlider.xCenterLoc - (thisSlider.xSize / 2) - 42, thisSlider.yCenterLoc - (thisSlider.ySize / 2) - 3, 35, thisSlider.ySize + 6, thisSlider.bumpBackgroundColor);
// draw the slider bump down arrow outline
tft.drawRect(thisSlider.xCenterLoc - (thisSlider.xSize / 2) - 42, thisSlider.yCenterLoc - (thisSlider.ySize / 2) - 3, 35, thisSlider.ySize + 6, thisSlider.borderColor);
tft.drawRect(thisSlider.xCenterLoc - (thisSlider.xSize / 2) - 40, thisSlider.yCenterLoc - (thisSlider.ySize / 2) - 1, 31, thisSlider.ySize + 2, thisSlider.borderColor);
// draw the slider bump down arrow
for (int i = 0; i < 7; i++)
{
tft.drawLine(thisSlider.xCenterLoc - (thisSlider.xSize / 2) - 23 - i, thisSlider.yCenterLoc - (7 - i), thisSlider.xCenterLoc - (thisSlider.xSize / 2) - 23 - i, thisSlider.yCenterLoc + (7 - i), thisSlider.handleColor);
}
}
// clear the bump up arrow area if enabled
if (thisSlider.withBumpUpArrow)
{
// clear the slider bump up arrow area
tft.fillRect(thisSlider.xCenterLoc + (thisSlider.xSize / 2) + 9, thisSlider.yCenterLoc - (thisSlider.ySize / 2) - 3, 35, thisSlider.ySize + 6, thisSlider.bumpBackgroundColor);
// draw the slider bump up arrow outline
tft.drawRect(thisSlider.xCenterLoc + (thisSlider.xSize / 2) + 9, thisSlider.yCenterLoc - (thisSlider.ySize / 2) - 3, 35, thisSlider.ySize + 6, thisSlider.borderColor);
tft.drawRect(thisSlider.xCenterLoc + (thisSlider.xSize / 2) + 11, thisSlider.yCenterLoc - (thisSlider.ySize / 2) - 1, 31, thisSlider.ySize + 2, thisSlider.borderColor);
// draw the slider bump up arrow
for (int i = 0; i < 7; i++)
{
tft.drawLine(thisSlider.xCenterLoc + (thisSlider.xSize / 2) + 30 - i, thisSlider.yCenterLoc - i - 1, thisSlider.xCenterLoc + (thisSlider.xSize / 2) + 30 - i, thisSlider.yCenterLoc + i + 1, thisSlider.handleColor);
}
}
// clear the entire slider
tft.fillRect(thisSlider.xCenterLoc - (thisSlider.xSize / 2) - 7, thisSlider.yCenterLoc - (thisSlider.ySize / 2) - 3, thisSlider.xSize + 15, thisSlider.ySize + 6, thisSlider.backgroundColor);
// draw the slider outline
tft.drawRect(thisSlider.xCenterLoc - (thisSlider.xSize / 2) - 7, thisSlider.yCenterLoc - (thisSlider.ySize / 2) - 3, thisSlider.xSize + 15, thisSlider.ySize + 6, thisSlider.borderColor);
// draw the slider handle
tft.fillRect((int)map(thisSlider.value, thisSlider.minValue, thisSlider.maxValue, thisSlider.xCenterLoc - (thisSlider.xSize / 2), thisSlider.xCenterLoc + (thisSlider.xSize / 2)) - 6, thisSlider.yCenterLoc - (2 + thisSlider.ySize * 4 / 10), 13, (thisSlider.ySize * 8 / 10) + 4, RA8875_BLACK);
tft.fillRect((int)map(thisSlider.value, thisSlider.minValue, thisSlider.maxValue, thisSlider.xCenterLoc - (thisSlider.xSize / 2), thisSlider.xCenterLoc + (thisSlider.xSize / 2)) - 4, thisSlider.yCenterLoc - thisSlider.ySize * 4 / 10, 9, thisSlider.ySize * 8 / 10, thisSlider.handleColor);
// draw the slider guide line
tft.drawLine(thisSlider.xCenterLoc - (thisSlider.xSize / 2), thisSlider.yCenterLoc, thisSlider.xCenterLoc + (thisSlider.xSize / 2), thisSlider.yCenterLoc, thisSlider.scaleColor); // guide line
tft.drawLine(thisSlider.xCenterLoc - (thisSlider.xSize / 2), thisSlider.yCenterLoc - 7, thisSlider.xCenterLoc - (thisSlider.xSize / 2), thisSlider.yCenterLoc + 7, thisSlider.scaleColor); // left end
tft.drawLine(thisSlider.xCenterLoc + (thisSlider.xSize / 2), thisSlider.yCenterLoc - 7, thisSlider.xCenterLoc + (thisSlider.xSize / 2), thisSlider.yCenterLoc + 7, thisSlider.scaleColor); // right end
// draw the slider minor tick lines
for (unsigned int i = 1; i < thisSlider.minorTickSections; i++)
{
tft.drawLine(thisSlider.xCenterLoc - thisSlider.xSize / 2 + (thisSlider.xSize * i / thisSlider.minorTickSections), thisSlider.yCenterLoc - 2, thisSlider.xCenterLoc - thisSlider.xSize / 2 + (thisSlider.xSize * i / thisSlider.minorTickSections), thisSlider.yCenterLoc + 2, thisSlider.scaleColor); // minor tick lines
}
// draw the slider major tick lines
for (unsigned int i = 1; i < thisSlider.majorTickSections; i++)
{
tft.drawLine(thisSlider.xCenterLoc - thisSlider.xSize / 2 + (thisSlider.xSize * i / thisSlider.majorTickSections), thisSlider.yCenterLoc - 4, thisSlider.xCenterLoc - thisSlider.xSize / 2 + (thisSlider.xSize * i / thisSlider.majorTickSections), thisSlider.yCenterLoc + 4, thisSlider.scaleColor); // major tick lines
}
} else {
// clear the entire slider
tft.fillRect(thisSlider.xCenterLoc - (thisSlider.xSize / 2) - 7, thisSlider.yCenterLoc - (thisSlider.ySize / 2) - 3, thisSlider.xSize + 15, thisSlider.ySize + 6, thisSlider.backgroundColorDisabled);
// draw the slider outline
tft.drawRect(thisSlider.xCenterLoc - (thisSlider.xSize / 2) - 7, thisSlider.yCenterLoc - (thisSlider.ySize / 2) - 3, thisSlider.xSize + 15, thisSlider.ySize + 6, thisSlider.borderColorDisabled);
// draw the slider handle
tft.fillRect((int)map(thisSlider.value, thisSlider.minValue, thisSlider.maxValue, thisSlider.xCenterLoc - (thisSlider.xSize / 2), thisSlider.xCenterLoc + (thisSlider.xSize / 2)) - 6, thisSlider.yCenterLoc - (2 + thisSlider.ySize * 4 / 10), 13, (thisSlider.ySize * 8 / 10) + 4, RA8875_BLACK);
tft.fillRect((int)map(thisSlider.value, thisSlider.minValue, thisSlider.maxValue, thisSlider.xCenterLoc - (thisSlider.xSize / 2), thisSlider.xCenterLoc + (thisSlider.xSize / 2)) - 4, thisSlider.yCenterLoc - thisSlider.ySize * 4 / 10, 9, thisSlider.ySize * 8 / 10, thisSlider.handleColorDisabled);
// draw the slider guide line
tft.drawLine(thisSlider.xCenterLoc - (thisSlider.xSize / 2), thisSlider.yCenterLoc, thisSlider.xCenterLoc + (thisSlider.xSize / 2), thisSlider.yCenterLoc, thisSlider.scaleColorDisabled); // guide line
tft.drawLine(thisSlider.xCenterLoc - (thisSlider.xSize / 2), thisSlider.yCenterLoc - 7, thisSlider.xCenterLoc - (thisSlider.xSize / 2), thisSlider.yCenterLoc + 7, thisSlider.scaleColorDisabled); // left end
tft.drawLine(thisSlider.xCenterLoc + (thisSlider.xSize / 2), thisSlider.yCenterLoc - 7, thisSlider.xCenterLoc + (thisSlider.xSize / 2), thisSlider.yCenterLoc + 7, thisSlider.scaleColorDisabled); // right end
// draw the slider minor tick lines
for (unsigned int i = 1; i < thisSlider.minorTickSections; i++)
{
tft.drawLine(thisSlider.xCenterLoc - thisSlider.xSize / 2 + (thisSlider.xSize * i / thisSlider.minorTickSections), thisSlider.yCenterLoc - 2, thisSlider.xCenterLoc - thisSlider.xSize / 2 + (thisSlider.xSize * i / thisSlider.minorTickSections), thisSlider.yCenterLoc + 2, thisSlider.scaleColorDisabled); // minor tick lines
}
// draw the slider major tick lines
for (unsigned int i = 1; i < thisSlider.majorTickSections; i++)
{
tft.drawLine(thisSlider.xCenterLoc - thisSlider.xSize / 2 + (thisSlider.xSize * i / thisSlider.majorTickSections), thisSlider.yCenterLoc - 4, thisSlider.xCenterLoc - thisSlider.xSize / 2 + (thisSlider.xSize * i / thisSlider.majorTickSections), thisSlider.yCenterLoc + 4, thisSlider.scaleColorDisabled); // major tick lines
}
}
} else { // SLIDER_MODE_VERTICAL
if (thisSlider.activated)
{
// clear the bump down arrow area if enabled
if (thisSlider.withBumpDownArrow)
{
// clear the slider bump down arrow area
tft.fillRect(thisSlider.xCenterLoc - (thisSlider.xSize / 2) - 3, thisSlider.yCenterLoc + (thisSlider.ySize / 2) + 8, thisSlider.xSize + 6, 40, thisSlider.bumpBackgroundColor);
// draw the slider bump down arrow outline
tft.drawRect(thisSlider.xCenterLoc - (thisSlider.xSize / 2) - 3, thisSlider.yCenterLoc + (thisSlider.ySize / 2) + 8, thisSlider.xSize + 6, 40, thisSlider.borderColor);
tft.drawRect(thisSlider.xCenterLoc - (thisSlider.xSize / 2) - 1, thisSlider.yCenterLoc + (thisSlider.ySize / 2) + 10, thisSlider.xSize + 2, 36, thisSlider.borderColor);
// draw the slider bump down arrow
for (int i = 0; i < 7; i++)
{
tft.drawLine(thisSlider.xCenterLoc - (7 - i), thisSlider.yCenterLoc + (thisSlider.ySize / 2) + i + 24, thisSlider.xCenterLoc + (7 - i), thisSlider.yCenterLoc + (thisSlider.ySize / 2) + i + 24, thisSlider.handleColor);
}
}
// clear the bump up arrow area if enabled
if (thisSlider.withBumpUpArrow)
{
// clear the slider bump up arrow area
tft.fillRect(thisSlider.xCenterLoc - (thisSlider.xSize / 2) - 3, thisSlider.yCenterLoc - (thisSlider.ySize / 2) - 46, thisSlider.xSize + 6, 40, thisSlider.bumpBackgroundColor);
// draw the slider bump up arrow outline
tft.drawRect(thisSlider.xCenterLoc - (thisSlider.xSize / 2) - 3, thisSlider.yCenterLoc - (thisSlider.ySize / 2) - 46, thisSlider.xSize + 6, 40, thisSlider.borderColor);
tft.drawRect(thisSlider.xCenterLoc - (thisSlider.xSize / 2) - 1, thisSlider.yCenterLoc - (thisSlider.ySize / 2) - 44, thisSlider.xSize + 2, 36, thisSlider.borderColor);
// draw the slider bump up arrow
for (int i = 0; i < 7; i++)
{
tft.drawLine(thisSlider.xCenterLoc - (7 - i), thisSlider.yCenterLoc - (thisSlider.ySize / 2) - i - 24, thisSlider.xCenterLoc + (7 - i), thisSlider.yCenterLoc - (thisSlider.ySize / 2) - i - 24, thisSlider.handleColor);
}
}
// clear the entire slider
tft.fillRect(thisSlider.xCenterLoc - (thisSlider.xSize / 2) - 3, thisSlider.yCenterLoc - (thisSlider.ySize / 2) - 7, thisSlider.xSize + 6, thisSlider.ySize + 15, thisSlider.backgroundColor);
// draw the slider outline
tft.drawRect(thisSlider.xCenterLoc - (thisSlider.xSize / 2) - 3, thisSlider.yCenterLoc - (thisSlider.ySize / 2) - 7, thisSlider.xSize + 6, thisSlider.ySize + 15, thisSlider.borderColor);
// draw the slider handle
tft.fillRect(thisSlider.xCenterLoc - (2 + thisSlider.xSize * 4 / 10), (int)map(thisSlider.value, thisSlider.maxValue, thisSlider.minValue, thisSlider.yCenterLoc - (thisSlider.ySize / 2), thisSlider.yCenterLoc + (thisSlider.ySize / 2)) - 6, (thisSlider.xSize * 8 / 10) + 4, 13, RA8875_BLACK);
tft.fillRect(thisSlider.xCenterLoc - thisSlider.xSize * 4 / 10, (int)map(thisSlider.value, thisSlider.maxValue, thisSlider.minValue, thisSlider.yCenterLoc - (thisSlider.ySize / 2), thisSlider.yCenterLoc + (thisSlider.ySize / 2)) - 4, thisSlider.xSize * 8 / 10, 9, thisSlider.handleColor);
// draw the slider guide line
tft.drawLine(thisSlider.xCenterLoc, thisSlider.yCenterLoc - (thisSlider.ySize / 2), thisSlider.xCenterLoc, thisSlider.yCenterLoc + (thisSlider.ySize / 2), thisSlider.scaleColor); // guide line
tft.drawLine(thisSlider.xCenterLoc - 7, thisSlider.yCenterLoc - (thisSlider.ySize / 2), thisSlider.xCenterLoc + 7, thisSlider.yCenterLoc - (thisSlider.ySize / 2), thisSlider.scaleColor); // top end
tft.drawLine(thisSlider.xCenterLoc - 7, thisSlider.yCenterLoc + (thisSlider.ySize / 2), thisSlider.xCenterLoc + 7, thisSlider.yCenterLoc + (thisSlider.ySize / 2), thisSlider.scaleColor); // bottom end
// draw the slider minor tick lines
for (unsigned int i = 1; i < thisSlider.minorTickSections; i++)
{
tft.drawLine(thisSlider.xCenterLoc - 2, thisSlider.yCenterLoc - thisSlider.ySize / 2 + (thisSlider.ySize * i / thisSlider.minorTickSections), thisSlider.xCenterLoc + 2, thisSlider.yCenterLoc - thisSlider.ySize / 2 + (thisSlider.ySize * i / thisSlider.minorTickSections), thisSlider.scaleColor); // minor tick lines
}
// draw the slider major tick lines
for (unsigned int i = 1; i < thisSlider.majorTickSections; i++)
{
tft.drawLine(thisSlider.xCenterLoc - 4, thisSlider.yCenterLoc - thisSlider.ySize / 2 + (thisSlider.ySize * i / thisSlider.majorTickSections), thisSlider.xCenterLoc + 4, thisSlider.yCenterLoc - thisSlider.ySize / 2 + (thisSlider.ySize * i / thisSlider.majorTickSections), thisSlider.scaleColor); // major tick lines
}
} else {
// clear the bump uparrow area if enabled
if (thisSlider.withBumpUpArrow)
{
// clear the slider bump up arrow area
tft.fillRect(thisSlider.xCenterLoc - (thisSlider.xSize / 2) - 3, thisSlider.yCenterLoc - (thisSlider.ySize / 2) - 46, thisSlider.xSize + 6, 40, thisSlider.backgroundColorDisabled);
// draw the slider bump up arrow outline
tft.drawRect(thisSlider.xCenterLoc - (thisSlider.xSize / 2) - 3, thisSlider.yCenterLoc - (thisSlider.ySize / 2) - 46, thisSlider.xSize + 6, 40, thisSlider.borderColorDisabled);
tft.drawRect(thisSlider.xCenterLoc - (thisSlider.xSize / 2) - 1, thisSlider.yCenterLoc - (thisSlider.ySize / 2) - 44, thisSlider.xSize + 2, 36, thisSlider.borderColorDisabled);
// draw the slider bump up arrow
for (int i = 0; i < 7; i++)
{
tft.drawLine(thisSlider.xCenterLoc - (7 - i), thisSlider.yCenterLoc - (thisSlider.ySize / 2) - i - 24, thisSlider.xCenterLoc + (7 - i), thisSlider.yCenterLoc - (thisSlider.ySize / 2) - i - 24, thisSlider.borderColorDisabled);
}
}
// clear the entire slider
tft.fillRect(thisSlider.xCenterLoc - (thisSlider.xSize / 2) - 3, thisSlider.yCenterLoc - (thisSlider.ySize / 2) - 7, thisSlider.xSize + 6, thisSlider.ySize + 15, thisSlider.backgroundColorDisabled);
// draw the slider outline
tft.drawRect(thisSlider.xCenterLoc - (thisSlider.xSize / 2) - 3, thisSlider.yCenterLoc - (thisSlider.ySize / 2) - 7, thisSlider.xSize + 6, thisSlider.ySize + 15, thisSlider.borderColorDisabled);
// draw the slider handle
tft.drawRect(thisSlider.xCenterLoc - (2 + thisSlider.xSize * 4 / 10), (int)map(thisSlider.value, thisSlider.maxValue, thisSlider.minValue, thisSlider.yCenterLoc - (thisSlider.ySize / 2), thisSlider.yCenterLoc + (thisSlider.ySize / 2)) - 4, (thisSlider.xSize * 8 / 10) + 4, 9, thisSlider.borderColorDisabled);
// draw the slider guide line
tft.drawLine(thisSlider.xCenterLoc, thisSlider.yCenterLoc - (thisSlider.ySize / 2), thisSlider.xCenterLoc, thisSlider.yCenterLoc + (thisSlider.ySize / 2), thisSlider.scaleColorDisabled); // guide line
tft.drawLine(thisSlider.xCenterLoc - 7, thisSlider.yCenterLoc - (thisSlider.ySize / 2), thisSlider.xCenterLoc + 7, thisSlider.yCenterLoc - (thisSlider.ySize / 2), thisSlider.scaleColorDisabled); // top end
tft.drawLine(thisSlider.xCenterLoc - 7, thisSlider.yCenterLoc + (thisSlider.ySize / 2), thisSlider.xCenterLoc + 7, thisSlider.yCenterLoc + (thisSlider.ySize / 2), thisSlider.scaleColorDisabled); // bottom end
// draw the slider minor tick lines
for (unsigned int i = 1; i < thisSlider.minorTickSections; i++)
{
tft.drawLine(thisSlider.xCenterLoc - 2, thisSlider.yCenterLoc - thisSlider.ySize / 2 + (thisSlider.ySize * i / thisSlider.minorTickSections), thisSlider.xCenterLoc + 2, thisSlider.yCenterLoc - thisSlider.ySize / 2 + (thisSlider.ySize * i / thisSlider.minorTickSections), thisSlider.scaleColorDisabled); // minor tick lines
}
// draw the slider major tick lines
for (unsigned int i = 1; i < thisSlider.majorTickSections; i++)
{
tft.drawLine(thisSlider.xCenterLoc - 4, thisSlider.yCenterLoc - thisSlider.ySize / 2 + (thisSlider.ySize * i / thisSlider.majorTickSections), thisSlider.xCenterLoc + 4, thisSlider.yCenterLoc - thisSlider.ySize / 2 + (thisSlider.ySize * i / thisSlider.majorTickSections), thisSlider.scaleColorDisabled); // major tick lines
}
}
}
characterCount = thisSlider.placesBeforeTheDecimal + thisSlider.placesAfterTheDecimal;
if (thisSlider.placesAfterTheDecimal != 0)
{
// add one character for the decimal point
characterCount++;
}
if (thisSlider.showPlusMinusSign)
{
// add one for the +/- sign
characterCount++;
if (thisSlider.value >= 0.0)
{
outString = outString + "+";
} else {
outString = outString + "-";
}
}
switch (thisSlider.placesBeforeTheDecimal)
{
case 5:
{
if (abs(thisSlider.value) >= 10000.0)
{
outString = outString + (char)(((int)(abs(thisSlider.value)) / 10000) + 0x30);
}
}
// no break, so fall-thru
case 4:
{
if (abs(thisSlider.value) >= 1000)
{
outString = outString + (char)((((int)(abs(thisSlider.value)) % 10000) / 1000) + 0x30);
}
}
// no break, so fall-thru
case 3:
{
if (abs(thisSlider.value) >= 100)
{
outString = outString + (char)((((int)(abs(thisSlider.value)) % 1000) / 100) + 0x30);
}
}
// no break, so fall-thru
case 2:
{
if (abs(thisSlider.value) >= 10)
{
outString = outString + (char)((((int)(abs(thisSlider.value)) % 100) / 10) + 0x30);
}
}
// no break, so fall-thru
}
outString = outString + (char)(((int)(abs(thisSlider.value)) % 10) + 0x30);
if (thisSlider.placesAfterTheDecimal != 0)
{
outString = outString + ".";
}
switch (thisSlider.placesAfterTheDecimal)
{
case 1:
{
outString = outString + (char)(((int)((abs(thisSlider.value) * 10.0f)) % 10) + 0x30);
}
break;
case 2:
{
outString = outString + (char)(((int)((abs(thisSlider.value) * 10.0f)) % 10) + 0x30);
outString = outString + (char)(((int)((abs(thisSlider.value) * 100.0f)) % 10) + 0x30);
}
break;
}
tft.fillRect(thisSlider.xValueCenterLoc - ((thisSlider.placesBeforeTheDecimal + thisSlider.placesAfterTheDecimal + 2) * 4), thisSlider.yValueCenterLoc - 4, (thisSlider.placesBeforeTheDecimal + thisSlider.placesAfterTheDecimal + 2) * 8, 10, RA8875_BLACK);
centerDrawText(outString, thisSlider.xValueCenterLoc + 1, thisSlider.yValueCenterLoc, thisSlider.valueColor, RA8875_BLACK);
} // drawSlider()
// main loop
void loop()
{
if ((config_mode == CONFIG_MODE_SPLASH) && (millis() > (check_splash_time + CHECK_SPLASH_MILLIS)))
{
config_mode = CONFIG_MODE_INIT_SCREEN;
drawScreen();
config_mode = CONFIG_MODE_MENU1;
drawScreen();
}
// if the touchscreen is being touched anywhere
if ((config_mode > CONFIG_MODE_INIT_SCREEN) && ((millis() - check_touchscreen_time) > CHECK_TOUCHSCREEN_MILLIS) && processTouchscreen())
{
check_touchscreen_time = millis();
switch (config_mode)
{
case CONFIG_MODE_SPLASH:
case CONFIG_MODE_INIT_SCREEN:
{
}
break;
case CONFIG_MODE_MENU1:
{
#ifndef DISABLE_BACKLIGHT_CONTROL
if (checkSlider(&menu1BacklightSliderV))
{
menu1BacklightSliderH.value = menu1BacklightSliderV.value;
drawSlider(menu1BacklightSliderV);
drawSlider(menu1BacklightSliderH);
tft.brightness(menu1BacklightSliderV.value);
}
if (checkSlider(&menu1BacklightSliderH))
{
menu1BacklightSliderV.value = menu1BacklightSliderH.value;
drawSlider(menu1BacklightSliderV);
drawSlider(menu1BacklightSliderH);
tft.brightness(menu1BacklightSliderV.value);
}
#endif
}
break;
case CONFIG_MODE_MENU2:
{
}
break;
case CONFIG_MODE_MENU3:
{
}
break;
case CONFIG_MODE_MENU4:
{
}
break;
}
} else {
// if the touchscreen was touched, but is no longer being touched
if (touch_triggered)
{
touch_triggered = false;
// if the touchscreen was last touched within menu1Button
if (checkButton(menu1Button))
{
config_mode = CONFIG_MODE_MENU1;
screen_update_required = true;
}
// if the touchscreen was last touched within menu2Button
if (checkButton(menu2Button))
{
config_mode = CONFIG_MODE_MENU2;
screen_update_required = true;
}
// if the touchscreen was last touched within menu3Button
if (checkButton(menu3Button))
{
config_mode = CONFIG_MODE_MENU3;
screen_update_required = true;
}
// if the touchscreen was last touched within menu4Button
if (checkButton(menu4Button))
{
config_mode = CONFIG_MODE_MENU4;
screen_update_required = true;
}
switch (config_mode)
{
case CONFIG_MODE_SPLASH:
case CONFIG_MODE_INIT_SCREEN:
{
}
break;
case CONFIG_MODE_MENU1:
{
#ifndef DISABLE_BACKLIGHT_CONTROL
if (checkButton(menu1BacklightButtonV) || checkButton(menu1BacklightButtonH))
{
if (menu1BacklightSliderV.value != 127)
{
menu1BacklightSliderV.value = 127;
menu1BacklightSliderH.value = 127;
} else {
menu1BacklightSliderV.value = 255;
menu1BacklightSliderH.value = 255;
}
drawSlider(menu1BacklightSliderV);
drawSlider(menu1BacklightSliderH);
tft.brightness(menu1BacklightSliderV.value);
}
#endif
if (checkSliderBumpDown(&menu1BacklightSliderV))
{
menu1BacklightSliderH.value = menu1BacklightSliderV.value;
drawSlider(menu1BacklightSliderV);
drawSlider(menu1BacklightSliderH);
}
if (checkSliderBumpUp(&menu1BacklightSliderV))
{
menu1BacklightSliderH.value = menu1BacklightSliderV.value;
drawSlider(menu1BacklightSliderV);
drawSlider(menu1BacklightSliderH);
}
if (checkSliderBumpDown(&menu1BacklightSliderH))
{
menu1BacklightSliderV.value = menu1BacklightSliderH.value;
drawSlider(menu1BacklightSliderV);
drawSlider(menu1BacklightSliderH);
}
if (checkSliderBumpUp(&menu1BacklightSliderH))
{
menu1BacklightSliderV.value = menu1BacklightSliderH.value;
drawSlider(menu1BacklightSliderV);
drawSlider(menu1BacklightSliderH);
}
if (checkButton(menu1Button1))
{
menu1Button1.activated = !menu1Button1.activated;
drawButton(menu1Button1);
if (menu1Button1.activated)
{
Serial.println("...activated BUTTON 1 in MENU 1...");
} else {
Serial.println("...deactivated BUTTON 1 in MENU 1...");
}
}
if (checkButton(menu1Button2))
{
menu1Button2.activated = !menu1Button2.activated;
drawButton(menu1Button2);
if (menu1Button2.activated)
{
Serial.println("...activated BUTTON 2 in MENU 1...");
} else {
Serial.println("...deactivated BUTTON 2 in MENU 1...");
}
}
if (checkButton(menu1Button3))
{
menu1Button3.activated = !menu1Button3.activated;
drawButton(menu1Button3);
if (menu1Button3.activated)
{
Serial.println("...activated BUTTON 3 in MENU 1...");
} else {
Serial.println("...deactivated BUTTON 3 in MENU 1...");
}
}
if (checkButton(menu1Button4))
{
menu1Button4.activated = !menu1Button4.activated;
drawButton(menu1Button4);
if (menu1Button4.activated)
{
Serial.println("...activated BUTTON 4 in MENU 1...");
} else {
Serial.println("...deactivated BUTTON 4 in MENU 1...");
}
}
}
break;
case CONFIG_MODE_MENU2:
{
if (checkButton(menu2Button1))
{
menu2Button1.activated = !menu2Button1.activated;
drawButton(menu2Button1);
if (menu2Button1.activated)
{
Serial.println("...activated BUTTON 1 in MENU 2...");
} else {
Serial.println("...deactivated BUTTON 1 in MENU 2...");
}
}
if (checkButton(menu2Button2))
{
menu2Button2.activated = !menu2Button2.activated;
drawButton(menu2Button2);
if (menu2Button2.activated)
{
Serial.println("...activated BUTTON 2 in MENU 2...");
} else {
Serial.println("...deactivated BUTTON 2 in MENU 2...");
}
}
if (checkButton(menu2Button3))
{
menu2Button3.activated = !menu2Button3.activated;
drawButton(menu2Button3);
if (menu2Button3.activated)
{
Serial.println("...activated BUTTON 3 in MENU 2...");
} else {
Serial.println("...deactivated BUTTON 3 in MENU 2...");
}
}
if (checkButton(menu2Button4))
{
menu2Button4.activated = !menu2Button4.activated;
drawButton(menu2Button4);
if (menu2Button4.activated)
{
Serial.println("...activated BUTTON 4 in MENU 2...");
} else {
Serial.println("...deactivated BUTTON 4 in MENU 2...");
}
}
}
break;
case CONFIG_MODE_MENU3:
{
if (checkButton(menu3Button1))
{
menu3Button1.activated = !menu3Button1.activated;
drawButton(menu3Button1);
if (menu3Button1.activated)
{
Serial.println("...activated BUTTON 1 in MENU 3...");
} else {
Serial.println("...deactivated BUTTON 1 in MENU 3...");
}
}
if (checkButton(menu3Button2))
{
menu3Button2.activated = !menu3Button2.activated;
drawButton(menu3Button2);
if (menu3Button2.activated)
{
Serial.println("...activated BUTTON 2 in MENU 3...");
} else {
Serial.println("...deactivated BUTTON 2 in MENU 3...");
}
}
if (checkButton(menu3Button3))
{
menu3Button3.activated = !menu3Button3.activated;
drawButton(menu3Button3);
if (menu3Button3.activated)
{
Serial.println("...activated BUTTON 3 in MENU 3...");
} else {
Serial.println("...deactivated BUTTON 3 in MENU 3...");
}
}
if (checkButton(menu3Button4))
{
menu3Button4.activated = !menu3Button4.activated;
drawButton(menu3Button4);
if (menu3Button4.activated)
{
Serial.println("...activated BUTTON 4 in MENU 3...");
} else {
Serial.println("...deactivated BUTTON 4 in MENU 3...");
}
}
}
break;
case CONFIG_MODE_MENU4:
{
if (checkButton(menu4Button1))
{
menu4Button1.activated = !menu4Button1.activated;
drawButton(menu4Button1);
if (menu4Button1.activated)
{
Serial.println("...activated BUTTON 1 in MENU 4...");
} else {
Serial.println("...deactivated BUTTON 1 in MENU 4...");
}
}
if (checkButton(menu4Button2))
{
menu4Button2.activated = !menu4Button2.activated;
drawButton(menu4Button2);
if (menu4Button2.activated)
{
Serial.println("...activated BUTTON 2 in MENU 4...");
} else {
Serial.println("...deactivated BUTTON 2 in MENU 4...");
}
}
if (checkButton(menu4Button3))
{
menu4Button3.activated = !menu4Button3.activated;
drawButton(menu4Button3);
if (menu4Button3.activated)
{
Serial.println("...activated BUTTON 3 in MENU 4...");
} else {
Serial.println("...deactivated BUTTON 3 in MENU 4...");
}
}
if (checkButton(menu4Button4))
{
menu4Button4.activated = !menu4Button4.activated;
drawButton(menu4Button4);
if (menu4Button4.activated)
{
Serial.println("...activated BUTTON 4 in MENU 4...");
} else {
Serial.println("...deactivated BUTTON 4 in MENU 4...");
}
}
}
break;
}
if (screen_update_required)
{
drawScreen();
screen_update_required = false;
}
}
}
} // loop()
// process any touchscreen activity
boolean processTouchscreen(void)
{
uint16_t coordinates[RA8875_MAX_TOUCH_LIMIT][2]; // array to hold the touch coordinates
boolean currently_touched = false;
// fill the FT5206 registers to get access to the data inside the library...
tft.updateTS();
currently_touched = tft.getTouches();
if (!currently_touched && previously_touched)
{
touch_triggered = true;
}
if (currently_touched)
{
tft.getTScoordinates(coordinates);
// range-check the values before using them
if ((coordinates[0][0] > 0) && (coordinates[0][0] < tft.width()) && (coordinates[0][1] > 0) && (coordinates[0][1] < tft.height()))
{
BtnX = coordinates[0][0];
BtnY = coordinates[0][1];
}
previously_touched = true;
#ifdef DEBUG_TOUCHSCREEN
Serial.print("X : ");
Serial.print(BtnX);
Serial.print(" Y : ");
Serial.println(BtnY);
#endif
} else {
previously_touched = false;
}
return (currently_touched); // whether the touchscreen is being touched or not
} // processTouchscreen()
// one-time setup
void setup()
{
unsigned long check_time;
pinMode(RA8875_CHIP_SELECT, OUTPUT);
digitalWrite(RA8875_CHIP_SELECT, HIGH);
pinMode(RA8875_RESET, OUTPUT);
digitalWrite(RA8875_RESET, LOW);
check_time = millis();
while ((millis() - check_time) <= 100);
digitalWrite(RA8875_RESET, HIGH);
Serial.begin(57600);
check_time = millis();
while (!Serial && ((millis() - check_time) <= 2000));
Serial.println("===================================================");
Serial.print(" ");
Serial.println(VERSION1);
Serial.print(" ");
Serial.println(VERSION2);
Serial.print(" ");
Serial.println(VERSION3);
Serial.println("===================================================");
Serial.println("");
Serial.println("");
if (CrashReport) {
Serial.print(CrashReport);
}
tft.begin(RA8875_800x480);
tft.DMA_enable();
tft.setRotation(2);
tft.clearScreen(RA8875_BLACK);
#ifdef DISABLE_BACKLIGHT_CONTROL
menu1BacklightSliderV.value = 127;
menu1BacklightSliderH.value = 127;
#endif
tft.brightness(menu1BacklightSliderV.value);
tft.useCapINT(RA8875_TS_INT); // use the FT5206 chip interrupt
tft.setTouchLimit(RA8875_MAX_TOUCH_LIMIT);
tft.enableCapISR(true); // capacitive touch screen interrupt it's armed
tft.writeTo(L1); // write to layer 1
check_splash_time = millis();
drawScreen();
pinMode(LED_PIN, OUTPUT);
} // setup()
// EOF placeholder