/*
Simple dynamic GUI demo by SSC,2024/2/22
hardware SPI
Color format:16bit RGB565
for example:hex #39c5bb -> RGB565 #3e37
tested on UNO R4
*ok to connect touch unit
*/
/* Hardware Setup */
#include <XPT2046_Touchscreen.h>
#include "SPI.h"
#include <Arduino_GFX_Library.h>
#define CS_PIN A0 // for touch unit
#define GFX_BL 10
XPT2046_Touchscreen ts(CS_PIN);
Arduino_DataBus *bus = new Arduino_HWSPI(8 /* DC */, 9 /* CS */);
Arduino_GFX *gfx = new Arduino_ILI9341(bus, DF_GFX_RST, 0 /* rotation */, false /* IPS */);
/* Variable Setup */
int s=0;
// messageBox's position when startup
int messageBox_xPos = 8;
int messageBox_yPos = gfx->height()+5;
int messageBox_width = 8;
int messageBox_height = 8;
int messageBox_radius = 4;
// previous position
int p_messageBox_xPos;
int p_messageBox_yPos;
int p_messageBox_width;
int p_messageBox_height;
int p_messageBox_radius;
// speed&show time
int messageBox_delay = 5;
int messageBox_time = 0;
// contents
char *msg_title,*msg_line1,*msg_line2,*msg_line3;
// scroll text
int title_xPos=gfx->width();
int title_speed;
int len;
/* Background color Setup */
// choose a background color!
//int bgColor = 0xFEFB; //pink
//int bgColor = 0x1082; // dark gray
//int bgColor = 0xF7FF; // light blue
int bgColor = 0x6855; // EVA
//int bgColor = 0x3E37; // miku blue
//int bgColor = 0x3F97; // miku blue light
//int bgColor = 0x0944; // miku blue dark
//int bgColor = 0x0000; // black
//int bgColor = 0xffff; // white
/* Function Setup */
void sCon(); // for test
void drawAlignmentText(int object_x,int object_y,int object_width,int object_height,int text_size,char *position,char *text); // basic function used in below
void messageBox_switchToStatus(int messageBox_t_xPos, int messageBox_t_yPos, int messageBox_t_width, int messageBox_t_height, int messageBox_t_radius); // msgBox func pt.1
void messageBox_animation(); // msgBox func pt.2
void messageBox_Runtime(); // msgBox func pt.3
void popMessageBox(int time/*ms*/,char *title,char *line1,char *line2,char *line3); // msgBox func pt.4
void ScrollText(int x1,int x2,int y, char *titleText /* 传入要显示的信息 */);
void drawBotton(int x,int y,char mode[],char *label);
void drawSwitch(int x,int y,char mode[],char *label);
void drawValueBox(int x,int y,char mode[],char *label,int value);
void statusBar(int icon_count);
/* Main Structure */
void setup() {
Serial.begin(9600);
Serial.println("ILI9341 Test!");
ts.begin();
gfx->begin(40000000);
//gfx->begin(4000000); // low speed SPI
gfx->fillScreen(bgColor);
GUI_init();
// make the screen's brightness gradually up
#ifdef GFX_BL
pinMode(GFX_BL, OUTPUT);
//digitalWrite(GFX_BL, HIGH);
for (int i=0;i<255;i++){
analogWrite(GFX_BL, i);
delay(1);
}
#endif
}
void GUI_init(){
drawBotton(6, 30, "init", "botton");
drawSwitch(84,30,"init","switch");
drawValueBox(162,30,"init","sValue",s);
drawValueBox(6,95,"init","msgTime",messageBox_time);
drawValueBox(6,160,"init","text_X",title_xPos);
drawValueBox(84,160,"init","textLen",len);
statusBar(3);
}
void loop(void) {
sCon(2);
ScrollText(100,232,108,"gfx ScrollText()");
drawValueBox(162,30,"on","sValue",s);
drawValueBox(6,95,"on","msgTime",messageBox_time);
drawValueBox(6,160,"on","text_X",title_xPos);
drawValueBox(84,160,"on","textLen",len);
messageBox_Runtime();
}
/* Functions */
void sCon(int num){
/* 自动控制变量用于测试 */
static unsigned long lastTime = 0;
//int s = Serial.read();
if (millis() - lastTime >= 2000) {
lastTime = millis();
////////////////////////////////////////
s+=1;
if (s >= num) {
s=0;
//popMessageBox(70,"MessageTitle","Hi,there!This is","a message from","messageBox()"); //70
// 下一排字的个数必须大于等于上一排字的个数,可以用空格充数
popMessageBox(90,"title"/*5个字*/,"MsgBox()"/*8个字*/,"content "/*7个字+1空格*/," "/*8空格(此处必须留空!)*/);
}
drawBotton(6, 30, "on", "botton");
drawSwitch(84,30,"on","switch");
////////////////////////////////////////
}
}
void drawAlignmentText(int object_x,int object_y,int object_width,int object_height,int text_size,char *position,char *text){
/* 将文本与对象左侧/居中/右侧对齐,并打印在对象下方 */
if (position=="center"){
gfx->setCursor(object_x+object_width/2-(strlen(text)/2)*(text_size+9),object_y+object_height+text_size);
}
if (position=="left"){
gfx->setCursor(object_x,object_y);
}
gfx->setTextColor(~bgColor,bgColor); gfx->setTextSize(text_size); gfx->setTextWrap(false);
gfx->print(text);
}
void statusBar(int icon_count){
#include "icons.c"
gfx->fillRect(0, 0, gfx->width(), 28, BLACK);
//gfx->drawLine(0,28,gfx->width(),28,0x630C);
gfx->draw16bitRGBBitmap(gfx->width()-24*3-2*3, 2, (const uint16_t *)Calendar, 24, 24);
gfx->draw16bitRGBBitmap(gfx->width()-24*2-2*2, 0, (const uint16_t *)Wifi_Ok, 24, 24);
gfx->draw16bitRGBBitmap(gfx->width()-24-2, 2, (const uint16_t *)Battery_Ok, 24, 24);
}
void drawValueBox(int x,int y,char mode[],char *label,int value){
if(mode=="init"){
gfx->fillRoundRect(x,y,72,40,15,0xC638);
gfx->fillRoundRect(x+4,y+4,64,32,12,bgColor);
drawAlignmentText(x, y, 72, 40, 2, "center",label);
}
else {
gfx->setTextBound(x+4,y+4,64,32);
gfx->setCursor(x+10, y+10);
gfx->setTextColor(~bgColor,bgColor); gfx->setTextSize(3); gfx->setTextWrap(true);
gfx->print(value);
gfx->print(" ");
gfx->setTextBound(0,0,gfx->width(),gfx->height());
}
}
void drawSwitch(int x,int y,char mode[],char *label){
if(mode=="init"){
gfx->fillRoundRect(x,y,72,40,15,0xC638);
gfx->fillRoundRect(x+4,y+4,32,32,12,bgColor);
drawAlignmentText(x, y, 72, 40, 2, "center",label);
}
if(s==1){ // on
gfx->fillRoundRect(x,y,72,40,15,0xC638);
gfx->fillRoundRect(x+36,y+4,32,32,12,~bgColor);
}
if(s==0){ // off
gfx->fillRoundRect(x,y,72,40,15,0xC638);
gfx->fillRoundRect(x+4,y+4,64,32,12,bgColor);
gfx->fillRoundRect(x+4,y+4,32,32,12,~bgColor);
}
}
void drawBotton(int x,int y,char mode[],char *label){
if(mode=="init"){
gfx->fillRoundRect(x,y,72,40,15,0xC638);
gfx->fillRoundRect(x+4,y+4,64,32,12,bgColor);
drawAlignmentText(x, y, 72, 40, 2, "center",label);
}
if(s==1){ // on
gfx->fillRoundRect(x,y,72,40,15,0xC638);
gfx->fillRoundRect(x+4,y+4,64,32,12,~bgColor);
}
if(s==0){ // off
gfx->fillRoundRect(x,y,72,40,15,0xC638);
//gfx->fillRoundRect(x+4,y+4,64,32,12,bgColor);
}
}
void messageBox_switchToStatus(int messageBox_t_xPos, int messageBox_t_yPos, int messageBox_t_width, int messageBox_t_height, int messageBox_t_radius){
// previous
p_messageBox_xPos = messageBox_xPos;
p_messageBox_yPos = messageBox_yPos;
p_messageBox_width = messageBox_width;
p_messageBox_height = messageBox_height;
p_messageBox_radius = messageBox_radius;
int messageBox_xPos_speed = round((messageBox_t_xPos - messageBox_xPos)*0.2);
int messageBox_yPos_speed = round((messageBox_t_yPos - messageBox_yPos)*0.2);
int messageBox_width_speed = round((messageBox_t_width - messageBox_width)*0.2);
int messageBox_height_speed = round((messageBox_t_height - messageBox_height)*0.2);
int messageBox_radius_speed = round((messageBox_t_radius - messageBox_radius)*0.1);
messageBox_xPos += messageBox_xPos_speed;
messageBox_yPos += messageBox_yPos_speed;
messageBox_width += messageBox_width_speed;
messageBox_height += messageBox_height_speed;
messageBox_radius += messageBox_radius_speed;
}
void messageBox_animation(){
////////////////////////////////////////
if (messageBox_time > 24){ // 预览
// title and 3 lines
gfx->setTextBound(messageBox_xPos+32, messageBox_yPos+8, messageBox_width-40, 50);
drawAlignmentText(messageBox_xPos+32, messageBox_yPos+8, messageBox_width-40, messageBox_height-16,2,"left",msg_title);
gfx->print("\n");
gfx->print(msg_line1);
gfx->print("\n");
gfx->print(msg_line2);
gfx->print("\n");
gfx->print(msg_line3);
gfx->setTextBound(0,0,gfx->width(),gfx->height());
messageBox_switchToStatus(0, gfx->height()-80, gfx->width()-2, 64, 20);
}
else if (messageBox_time > 16){ // 圆点
// clear text
gfx->fillRect(messageBox_xPos+16, messageBox_yPos+8, messageBox_width-24, messageBox_height-16,bgColor);
messageBox_switchToStatus(8, gfx->height()-40, 32, 32, 15);
}
else /*if (messageBox_time > 0)*/ { // 隐藏
messageBox_switchToStatus(8, gfx->height()+5, 8, 8, 4);
}
////////////////////////////////////////
if ((p_messageBox_xPos != messageBox_xPos) | (p_messageBox_yPos != messageBox_yPos) | (p_messageBox_width != messageBox_width) | (p_messageBox_height != messageBox_height)){
gfx->drawRoundRect(p_messageBox_xPos, p_messageBox_yPos, p_messageBox_width, p_messageBox_height, p_messageBox_radius, bgColor);
}
gfx->drawRoundRect(messageBox_xPos, messageBox_yPos, messageBox_width, messageBox_height, messageBox_radius, ~bgColor);
}
void messageBox_Runtime(){
if (messageBox_time > 0){
static unsigned long lastTime2 = 0;
if (millis() - lastTime2 >= messageBox_delay) {
lastTime2 = millis();
////////////////////////////////////////
messageBox_animation();
messageBox_time-=1;
////////////////////////////////////////
}
}
}
void popMessageBox(int time/*ms*/,char *title,char *line1,char *line2,char *line3){
msg_title = title;
msg_line1 = line1;
msg_line2 = line2;
msg_line3 = line3;
messageBox_time = time;
}
void ScrollText(int x1,int x2,int y,char *titleText /* 传入要显示的信息 */) {
// print title
len=strlen(titleText);
unsigned long currentTime1 = millis();
static unsigned long lastTime1 = 0;
if (currentTime1 - lastTime1 >= 30) {
lastTime1 = currentTime1;
//////////////////////////////////////////
title_speed = 1;
if (title_xPos <= x1-len*12-12) { // 如果显示完全,移动到x2
title_xPos = x2;
} else title_xPos = title_xPos - title_speed; // 否则向左移动
gfx->setTextBound(x1, y, x2-x1, 18); // gfx库的TextSize(2)高为14px
gfx->setCursor(title_xPos, y);
gfx->setTextColor(~bgColor,bgColor); gfx->setTextSize(2); gfx->setTextWrap(false);
gfx->print(titleText);
gfx->print(" ");
gfx->setTextBound(0,0,gfx->width(),gfx->height());
//gfx->setCursor(x1-12, y);
//gfx->print(" ");
//gfx->fillRect(x1-12, y, 12, 18, bgColor);
//gfx->drawRect(x1, y, x2-x1, 18, ~bgColor); // ScrollText显示的范围
//////////////////////////////////////////
}
}
unsigned long testFillScreen() {
unsigned long start = micros();
gfx->fillScreen(BLACK);
yield();
gfx->fillScreen(RED);
yield();
gfx->fillScreen(GREEN);
yield();
gfx->fillScreen(BLUE);
yield();
gfx->fillScreen(BLACK);
yield();
return micros() - start;
}