Convert UI to GUI Slice and cleanup some small stuff along the way
This commit is contained in:
parent
b765f65d9c
commit
8c8b4fd831
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -1 +1,3 @@
|
|||
build/
|
||||
serial_debugger*.bak
|
||||
gui_backup/
|
15
.vscode/settings.json
vendored
Normal file
15
.vscode/settings.json
vendored
Normal file
|
@ -0,0 +1,15 @@
|
|||
{
|
||||
"files.associations": {
|
||||
"xtemplate.h": "c",
|
||||
"guislice_drv.h": "c",
|
||||
"xradial.h": "c",
|
||||
"*.tpp": "cpp",
|
||||
"array": "cpp",
|
||||
"deque": "cpp",
|
||||
"string": "cpp",
|
||||
"unordered_map": "cpp",
|
||||
"vector": "cpp",
|
||||
"string_view": "cpp",
|
||||
"initializer_list": "cpp"
|
||||
}
|
||||
}
|
|
@ -1,3 +1,18 @@
|
|||
//<App !Start!>
|
||||
// FILE: [serial_debugger.ino]
|
||||
// Created by GUIslice Builder version: [0.15.b004]
|
||||
//
|
||||
// GUIslice Builder Generated File
|
||||
//
|
||||
// For the latest guides, updates and support view:
|
||||
// https://github.com/ImpulseAdventure/GUIslice
|
||||
//
|
||||
//<App !End!>
|
||||
|
||||
// ------------------------------------------------
|
||||
// Headers to include
|
||||
// ------------------------------------------------
|
||||
//<Includes !Start!>
|
||||
// Varous system includes
|
||||
#include <Arduino.h>
|
||||
|
||||
|
@ -8,22 +23,29 @@
|
|||
#include <BBQ10Keyboard.h>
|
||||
#include <CircularBuffer.h>
|
||||
|
||||
// Debugging via serial monitor (don't turn this on unless you're hacking on the firmware code)
|
||||
#define DEBUG true
|
||||
// Various local includes
|
||||
#include "serial_debugger_GSLC.h"
|
||||
|
||||
//<Includes !End!>
|
||||
|
||||
// ------------------------------------------------
|
||||
// Program Globals
|
||||
// ------------------------------------------------
|
||||
|
||||
// Battery level measurement
|
||||
#define VBATPIN A6
|
||||
float measuredVBat;
|
||||
float batteryPercent;
|
||||
int batteryPercent;
|
||||
|
||||
// TFT Setup
|
||||
#define TFT_CS 9
|
||||
#define TFT_DC 10
|
||||
Adafruit_ILI9341 tft(TFT_CS, TFT_DC);
|
||||
#include <Fonts/FreeMono9pt7b.h>
|
||||
#define CHARS_HORIZONTAL 28
|
||||
#define CHARS_ROWS 13
|
||||
CircularBuffer<char,364> textBuffer;
|
||||
#define CHARS_HORIZONTAL 29
|
||||
#define CHARS_ROWS 11
|
||||
#define CHARS_TOTAL CHARS_HORIZONTAL * CHARS_ROWS
|
||||
CircularBuffer<char,CHARS_TOTAL> textBuffer;
|
||||
|
||||
// Keyboard
|
||||
BBQ10Keyboard keyboard;
|
||||
|
@ -44,20 +66,48 @@ BBQ10Keyboard keyboard;
|
|||
Adafruit_NeoPixel pixels_board(PIXELS_NUM_BOARD, PIN_NEOPIXEL, NEO_GRB + NEO_KHZ800);
|
||||
Adafruit_NeoPixel pixels_wing(PIXELS_NUM_WING, PIXELS_WING_PIN, NEO_GRB + NEO_KHZ800);
|
||||
|
||||
// GUI state globals
|
||||
bool textChanged = false;
|
||||
|
||||
// Various loop handlers
|
||||
void handlerKeyboard();
|
||||
void handlerBatteryLevel();
|
||||
void processRingBuffer();
|
||||
|
||||
// UI screens
|
||||
void screenClear();
|
||||
// Save some element references for direct access
|
||||
//<Save_References !Start!>
|
||||
gslc_tsElemRef* m_pElemBatteryLevel= NULL;
|
||||
gslc_tsElemRef* m_pElemStatusText = NULL;
|
||||
gslc_tsElemRef* m_pElemText = NULL;
|
||||
//<Save_References !End!>
|
||||
|
||||
// Color conversion (RGB888 -> RGB565 used by Adafruit GFX)
|
||||
uint16_t RGB565(uint8_t r, uint8_t g, uint8_t b) {
|
||||
return ((r & 0b11111000) << 8) | ((g & 0b11111100) << 3) | (b >> 3);
|
||||
}
|
||||
// Define debug message function
|
||||
static int16_t DebugOut(char ch) { if (ch == (char)'\n') Serial.println(""); else Serial.write(ch); return 0; }
|
||||
|
||||
// ------------------------------------------------
|
||||
// Callback Methods
|
||||
// ------------------------------------------------
|
||||
//<Button Callback !Start!>
|
||||
//<Button Callback !End!>
|
||||
//<Checkbox Callback !Start!>
|
||||
//<Checkbox Callback !End!>
|
||||
//<Keypad Callback !Start!>
|
||||
//<Keypad Callback !End!>
|
||||
//<Spinner Callback !Start!>
|
||||
//<Spinner Callback !End!>
|
||||
//<Listbox Callback !Start!>
|
||||
//<Listbox Callback !End!>
|
||||
//<Draw Callback !Start!>
|
||||
//<Draw Callback !End!>
|
||||
//<Slider Enums !Start!>
|
||||
//<Slider Enums !End!>
|
||||
//<Tick Callback !Start!>
|
||||
//<Tick Callback !End!>
|
||||
|
||||
// Various things that need to be setup via the Arduino standard methods
|
||||
void setup() {
|
||||
|
||||
Serial.begin(115200);
|
||||
|
||||
// Setup red LED to indicate device is on (in case we disable NeoPixel battery level later)
|
||||
pinMode(3, OUTPUT);
|
||||
digitalWrite(3, HIGH);
|
||||
|
@ -80,50 +130,68 @@ void setup() {
|
|||
pixels_board.setPixelColor(0, pixels_board.Color(0, 0, 255));
|
||||
pixels_board.show();
|
||||
|
||||
// Setup TFT
|
||||
tft.begin();
|
||||
tft.setRotation(1);
|
||||
screenClear();
|
||||
tft.println("");
|
||||
tft.setFont(&FreeMono9pt7b);
|
||||
|
||||
// Setup BBQ10Keyboard
|
||||
Wire.begin();
|
||||
keyboard.begin();
|
||||
keyboard.setBacklight(0.5f);
|
||||
|
||||
// GUI Slice (TFT is setup through GUI Slice)
|
||||
gslc_InitDebug(&DebugOut);
|
||||
InitGUIslice_gen();
|
||||
}
|
||||
|
||||
// Main program via the Arduino standard methods
|
||||
// -----------------------------------
|
||||
// Main event loop
|
||||
// -----------------------------------
|
||||
void loop() {
|
||||
// Reset text changed state (processing methods will update if needed)
|
||||
textChanged = false;
|
||||
|
||||
// Handle keyboard events
|
||||
handlerKeyboard();
|
||||
|
||||
// Update battery level as appropriate
|
||||
handlerBatteryLevel();
|
||||
|
||||
// Update UI
|
||||
if (textChanged) {
|
||||
processRingBuffer();
|
||||
}
|
||||
gslc_Update(&m_gui);
|
||||
}
|
||||
|
||||
// Move text from buffer -> text box on screen
|
||||
void processRingBuffer() {
|
||||
// Add keycodes to text box
|
||||
char* textForDisplay = (char*) calloc(textBuffer.size(), sizeof(char));
|
||||
for (int i=0; i<textBuffer.size(); i++) {
|
||||
textForDisplay[i] = textBuffer[i];
|
||||
}
|
||||
gslc_ElemXTextboxAdd(&m_gui, m_pElemText, textForDisplay);
|
||||
}
|
||||
|
||||
// Keyboard handler
|
||||
void handlerKeyboard() {
|
||||
// Check if keys were pressed
|
||||
if (keyboard.keyCount()) {
|
||||
// Get keyboard event
|
||||
const BBQ10Keyboard::KeyEvent key = keyboard.keyEvent();
|
||||
|
||||
char output[28];
|
||||
snprintf(output, 28, "key: '%c' (dec %d, hex %02x)", key.key, key.key, key.key);
|
||||
for (int i=0; i<sizeof(output); i++) {
|
||||
char toPush = output[i];
|
||||
if (toPush != '\0') {
|
||||
textBuffer.push(toPush);
|
||||
// Add key code to display ring buffer *if* it's pressed ; no need for other events presently
|
||||
if (key.state == BBQ10Keyboard::StatePress) {
|
||||
char output[28];
|
||||
snprintf(output, 28, "key: '%c' (dec %d, hex %02x)", key.key, key.key, key.key);
|
||||
textChanged = true;
|
||||
for (int i=0; i<sizeof(output); i++) {
|
||||
char toPush = output[i];
|
||||
if (toPush != '\0') {
|
||||
textBuffer.push(toPush);
|
||||
}
|
||||
else if (toPush == '\0') {
|
||||
textBuffer.push('\n');
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (toPush == '\0') {
|
||||
textBuffer.push('\n');
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
screenClear();
|
||||
for (int i=0; i<textBuffer.size(); i++) {
|
||||
tft.print(textBuffer[i]);
|
||||
}
|
||||
|
||||
// Pick color for signaling a key was pressed (short or long press)
|
||||
|
@ -150,24 +218,32 @@ void handlerBatteryLevel() {
|
|||
measuredVBat *= 2; // we divided by 2, so multiply back
|
||||
measuredVBat *= 3.3; // Multiply by 3.3V, our reference voltage
|
||||
measuredVBat /= 1024; // convert to voltage
|
||||
batteryPercent = measuredVBat / 3.3;
|
||||
if (batteryPercent >= 0.75) {
|
||||
batteryPercent = (measuredVBat / 3.3) * 100;
|
||||
|
||||
gslc_tsColor colorForHeaderElements;
|
||||
if (batteryPercent >= 75) {
|
||||
pixels_board.setPixelColor(0, pixels_board.Color(0, 255, 0));
|
||||
colorForHeaderElements = GSLC_COL_GREEN;
|
||||
}
|
||||
else if (batteryPercent >= 0.50) {
|
||||
else if (batteryPercent >= 50) {
|
||||
colorForHeaderElements = GSLC_COL_YELLOW;
|
||||
pixels_board.setPixelColor(0, pixels_board.Color(255, 255, 0));
|
||||
}
|
||||
else if (batteryPercent >= 0.25) {
|
||||
else if (batteryPercent >= 25) {
|
||||
colorForHeaderElements = GSLC_COL_ORANGE;
|
||||
pixels_board.setPixelColor(0, pixels_board.Color(255, 128, 0));
|
||||
}
|
||||
else {
|
||||
colorForHeaderElements = GSLC_COL_RED;
|
||||
pixels_board.setPixelColor(0, pixels_board.Color(255, 0, 0));
|
||||
}
|
||||
|
||||
gslc_ElemXProgressSetVal(&m_gui, m_pElemBatteryLevel, batteryPercent);
|
||||
gslc_tsXProgress* pGauge = (gslc_tsXProgress*)gslc_GetXDataFromRef(&m_gui,m_pElemBatteryLevel,GSLC_TYPEX_PROGRESS,__LINE__);
|
||||
pGauge->colGauge = colorForHeaderElements;
|
||||
gslc_ElemSetTxtCol(&m_gui, m_pElemBatteryLevel, colorForHeaderElements);
|
||||
gslc_ElemSetTxtCol(&m_gui, m_pElemStatusText, colorForHeaderElements);
|
||||
|
||||
// Update GUI and NeoPixel with battery status information
|
||||
pixels_board.show();
|
||||
}
|
||||
|
||||
// Clear the screen
|
||||
void screenClear() {
|
||||
tft.setCursor(0, 0);
|
||||
tft.fillScreen(RGB565(0, 0, 0));
|
||||
}
|
203
serial_debugger.ino.beta
Normal file
203
serial_debugger.ino.beta
Normal file
|
@ -0,0 +1,203 @@
|
|||
// Varous system includes
|
||||
#include <Arduino.h>
|
||||
|
||||
// Various library includes
|
||||
#include <Adafruit_NeoPixel.h>
|
||||
#include <Adafruit_GFX.h>
|
||||
#include <Adafruit_ILI9341.h>
|
||||
#include <BBQ10Keyboard.h>
|
||||
#include <CircularBuffer.h>
|
||||
|
||||
// Various local includes
|
||||
#include "serial_debugger_GSLC.h"
|
||||
|
||||
// Battery level measurement
|
||||
#define VBATPIN A6
|
||||
float measuredVBat;
|
||||
int batteryPercent;
|
||||
|
||||
// TFT Setup
|
||||
#define TFT_CS 9
|
||||
#define TFT_DC 10
|
||||
Adafruit_ILI9341 tft(TFT_CS, TFT_DC);
|
||||
#include <Fonts/FreeMono9pt7b.h>
|
||||
#define CHARS_HORIZONTAL 28
|
||||
#define CHARS_ROWS 13
|
||||
CircularBuffer<char,364> textBuffer;
|
||||
|
||||
// Keyboard
|
||||
BBQ10Keyboard keyboard;
|
||||
#define KBD_BTN_1 0x06
|
||||
#define KBD_BTN_2 0x11
|
||||
#define KBD_BTN_3 0x07
|
||||
#define KBD_BTN_4 0x12
|
||||
#define KBD_SW_UP 0x01
|
||||
#define KBD_SW_DN 0x02
|
||||
#define KBD_SW_LF 0x03
|
||||
#define KBD_SW_RT 0x04
|
||||
#define KBD_SW_OK 0x05
|
||||
// NeoPixels
|
||||
#define PIXELS_NUM_BOARD 1
|
||||
#define PIXELS_NUM_WING 1
|
||||
#define PIXELS_WING_PIN 11
|
||||
Adafruit_NeoPixel pixels_board(PIXELS_NUM_BOARD, PIN_NEOPIXEL, NEO_GRB + NEO_KHZ800);
|
||||
Adafruit_NeoPixel pixels_wing(PIXELS_NUM_WING, PIXELS_WING_PIN, NEO_GRB + NEO_KHZ800);
|
||||
|
||||
// Various loop handlers
|
||||
void handlerKeyboard();
|
||||
void handlerBatteryLevel();
|
||||
|
||||
// GUI Slice
|
||||
gslc_tsElemRef* m_pElemBatteryLevel= NULL;
|
||||
gslc_tsElemRef* m_pElemStatusText = NULL;
|
||||
gslc_tsElemRef* m_pElemText = NULL;
|
||||
gslc_tsElemRef* m_pTextSlider = NULL;
|
||||
static int16_t DebugOut(char ch) { if (ch == (char)'\n') Serial.println(""); else Serial.write(ch); return 0; }
|
||||
bool CbSlidePos(void* pvGui,void* pvElemRef,int16_t nPos);
|
||||
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
|
||||
// Setup red LED to indicate device is on (in case we disable NeoPixel battery level later)
|
||||
pinMode(3, OUTPUT);
|
||||
digitalWrite(3, HIGH);
|
||||
|
||||
// Setup NeoPixels
|
||||
pixels_board.begin();
|
||||
pixels_wing.begin();
|
||||
pixels_board.clear();
|
||||
pixels_wing.clear();
|
||||
pixels_board.setBrightness(10);
|
||||
pixels_wing.setBrightness(5);
|
||||
|
||||
// Start with blank wing indicator
|
||||
pixels_wing.show();
|
||||
|
||||
// Green : pixels.Color(0, 255, 0)
|
||||
// Yellow : pixels.Color(255, 255, 0)
|
||||
// Orange : pixels.Color(255, 128, 0)
|
||||
// Red : pixels.Color(255, 0, 0)
|
||||
pixels_board.setPixelColor(0, pixels_board.Color(0, 0, 255));
|
||||
pixels_board.show();
|
||||
|
||||
// Setup BBQ10Keyboard
|
||||
Wire.begin();
|
||||
keyboard.begin();
|
||||
keyboard.setBacklight(0.5f);
|
||||
|
||||
// GUI Slice (TFT is setup through GUI Slice)
|
||||
gslc_InitDebug(&DebugOut);
|
||||
InitGUIslice_gen();
|
||||
}
|
||||
|
||||
// Main program via the Arduino standard methods
|
||||
void loop() {
|
||||
// Handle keyboard events
|
||||
handlerKeyboard();
|
||||
|
||||
// Update battery level as appropriate
|
||||
handlerBatteryLevel();
|
||||
|
||||
// Update UI
|
||||
gslc_Update(&m_gui);
|
||||
}
|
||||
|
||||
// Keyboard handler
|
||||
void handlerKeyboard() {
|
||||
// Check if keys were pressed
|
||||
if (keyboard.keyCount()) {
|
||||
// Get keyboard event
|
||||
const BBQ10Keyboard::KeyEvent key = keyboard.keyEvent();
|
||||
|
||||
char output[28];
|
||||
snprintf(output, 28, "key: '%c' (dec %d, hex %02x)", key.key, key.key, key.key);
|
||||
for (int i=0; i<sizeof(output); i++) {
|
||||
char toPush = output[i];
|
||||
if (toPush != '\0') {
|
||||
textBuffer.push(toPush);
|
||||
}
|
||||
else if (toPush == '\0') {
|
||||
textBuffer.push('\n');
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Add keycodes to text box
|
||||
for (int i=0; i<textBuffer.size(); i++) {
|
||||
//tft.print(textBuffer[i]);
|
||||
}
|
||||
|
||||
// Pick color for signaling a key was pressed (short or long press)
|
||||
uint32_t keyboard_pixel_color = pixels_wing.Color(0, 0, 255);
|
||||
if (key.state == BBQ10Keyboard::StateLongPress) {
|
||||
keyboard_pixel_color = pixels_wing.Color(0, 255, 255);
|
||||
}
|
||||
|
||||
// Display indicator accordingly
|
||||
if (key.state == BBQ10Keyboard::StatePress || key.state == BBQ10Keyboard::StateLongPress) {
|
||||
pixels_wing.setPixelColor(0, keyboard_pixel_color);
|
||||
pixels_wing.show();
|
||||
}
|
||||
else {
|
||||
pixels_wing.clear();
|
||||
pixels_wing.show();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Measure battery level and change NeoPixel accordingly
|
||||
void handlerBatteryLevel() {
|
||||
measuredVBat = analogRead(VBATPIN);
|
||||
measuredVBat *= 2; // we divided by 2, so multiply back
|
||||
measuredVBat *= 3.3; // Multiply by 3.3V, our reference voltage
|
||||
measuredVBat /= 1024; // convert to voltage
|
||||
batteryPercent = (measuredVBat / 3.3) * 100;
|
||||
|
||||
gslc_tsColor colorForHeaderElements;
|
||||
if (batteryPercent >= 75) {
|
||||
pixels_board.setPixelColor(0, pixels_board.Color(0, 255, 0));
|
||||
colorForHeaderElements = GSLC_COL_GREEN;
|
||||
}
|
||||
else if (batteryPercent >= 50) {
|
||||
colorForHeaderElements = GSLC_COL_YELLOW;
|
||||
pixels_board.setPixelColor(0, pixels_board.Color(255, 255, 0));
|
||||
}
|
||||
else if (batteryPercent >= 25) {
|
||||
colorForHeaderElements = GSLC_COL_ORANGE;
|
||||
pixels_board.setPixelColor(0, pixels_board.Color(255, 128, 0));
|
||||
}
|
||||
else {
|
||||
colorForHeaderElements = GSLC_COL_RED;
|
||||
pixels_board.setPixelColor(0, pixels_board.Color(255, 0, 0));
|
||||
}
|
||||
|
||||
gslc_ElemXProgressSetVal(&m_gui, m_pElemBatteryLevel, batteryPercent);
|
||||
gslc_tsXProgress* pGauge = (gslc_tsXProgress*)gslc_GetXDataFromRef(&m_gui,m_pElemBatteryLevel,GSLC_TYPEX_PROGRESS,__LINE__);
|
||||
pGauge->colGauge = colorForHeaderElements;
|
||||
gslc_ElemSetTxtCol(&m_gui, m_pElemBatteryLevel, colorForHeaderElements);
|
||||
gslc_ElemSetTxtCol(&m_gui, m_pElemStatusText, colorForHeaderElements);
|
||||
|
||||
// Update GUI and NeoPixel with battery status information
|
||||
gslc_Update(&m_gui);
|
||||
pixels_board.show();
|
||||
}
|
||||
|
||||
// Slider callback function
|
||||
bool CbSlidePos(void* pvGui,void* pvElemRef,int16_t nPos) {
|
||||
gslc_tsGui* pGui = (gslc_tsGui*)(pvGui);
|
||||
gslc_tsElemRef* pElemRef = (gslc_tsElemRef*)(pvElemRef);
|
||||
gslc_tsElem* pElem = gslc_GetElemFromRef(pGui,pElemRef);
|
||||
int16_t nVal;
|
||||
|
||||
// From the element's ID we can determine which slider was updated.
|
||||
switch (pElem->nId) {
|
||||
case E_TXTSCROLL:
|
||||
// Fetch the slider position
|
||||
nVal = gslc_ElemXSliderGetPos(pGui,m_pTextSlider);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
218
serial_debugger.ino.orig
Normal file
218
serial_debugger.ino.orig
Normal file
|
@ -0,0 +1,218 @@
|
|||
//<File !Start!>
|
||||
// Varous system includes
|
||||
#include <Arduino.h>
|
||||
//<File !End!>
|
||||
|
||||
// Various library includes
|
||||
#include <Adafruit_NeoPixel.h>
|
||||
#include <Adafruit_GFX.h>
|
||||
|
||||
//<Includes !Start!>
|
||||
//<Includes !End!>
|
||||
|
||||
#include <Adafruit_ILI9341.h>
|
||||
#include <BBQ10Keyboard.h>
|
||||
#include <CircularBuffer.h>
|
||||
|
||||
// Various local includes
|
||||
#include "serial_debugger_GSLC.h"
|
||||
|
||||
// Battery level measurement
|
||||
#define VBATPIN A6
|
||||
float measuredVBat;
|
||||
int batteryPercent;
|
||||
|
||||
// TFT Setup
|
||||
#define TFT_CS 9
|
||||
#define TFT_DC 10
|
||||
Adafruit_ILI9341 tft(TFT_CS, TFT_DC);
|
||||
#include <Fonts/FreeMono9pt7b.h>
|
||||
#define CHARS_HORIZONTAL 28
|
||||
#define CHARS_ROWS 13
|
||||
CircularBuffer<char,364> textBuffer;
|
||||
|
||||
// Keyboard
|
||||
BBQ10Keyboard keyboard;
|
||||
#define KBD_BTN_1 0x06
|
||||
#define KBD_BTN_2 0x11
|
||||
#define KBD_BTN_3 0x07
|
||||
#define KBD_BTN_4 0x12
|
||||
#define KBD_SW_UP 0x01
|
||||
#define KBD_SW_DN 0x02
|
||||
#define KBD_SW_LF 0x03
|
||||
#define KBD_SW_RT 0x04
|
||||
#define KBD_SW_OK 0x05
|
||||
// NeoPixels
|
||||
#define PIXELS_NUM_BOARD 1
|
||||
#define PIXELS_NUM_WING 1
|
||||
#define PIXELS_WING_PIN 11
|
||||
Adafruit_NeoPixel pixels_board(PIXELS_NUM_BOARD, PIN_NEOPIXEL, NEO_GRB + NEO_KHZ800);
|
||||
Adafruit_NeoPixel pixels_wing(PIXELS_NUM_WING, PIXELS_WING_PIN, NEO_GRB + NEO_KHZ800);
|
||||
|
||||
// Various loop handlers
|
||||
void handlerKeyboard();
|
||||
void handlerBatteryLevel();
|
||||
|
||||
// GUI Slice
|
||||
gslc_tsElemRef* m_pElemBatteryLevel= NULL;
|
||||
gslc_tsElemRef* m_pElemStatusText = NULL;
|
||||
gslc_tsElemRef* m_pElemText = NULL;
|
||||
gslc_tsElemRef* m_pTextSlider = NULL;
|
||||
static int16_t DebugOut(char ch) { if (ch == (char)'\n') Serial.println(""); else Serial.write(ch); return 0; }
|
||||
bool CbSlidePos(void* pvGui,void* pvElemRef,int16_t nPos);
|
||||
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
|
||||
// Setup red LED to indicate device is on (in case we disable NeoPixel battery level later)
|
||||
pinMode(3, OUTPUT);
|
||||
digitalWrite(3, HIGH);
|
||||
|
||||
// Setup NeoPixels
|
||||
pixels_board.begin();
|
||||
pixels_wing.begin();
|
||||
pixels_board.clear();
|
||||
pixels_wing.clear();
|
||||
pixels_board.setBrightness(10);
|
||||
pixels_wing.setBrightness(5);
|
||||
|
||||
// Start with blank wing indicator
|
||||
pixels_wing.show();
|
||||
|
||||
// Green : pixels.Color(0, 255, 0)
|
||||
// Yellow : pixels.Color(255, 255, 0)
|
||||
// Orange : pixels.Color(255, 128, 0)
|
||||
// Red : pixels.Color(255, 0, 0)
|
||||
pixels_board.setPixelColor(0, pixels_board.Color(0, 0, 255));
|
||||
pixels_board.show();
|
||||
|
||||
// Setup BBQ10Keyboard
|
||||
Wire.begin();
|
||||
keyboard.begin();
|
||||
keyboard.setBacklight(0.5f);
|
||||
|
||||
// GUI Slice (TFT is setup through GUI Slice)
|
||||
gslc_InitDebug(&DebugOut);
|
||||
InitGUIslice_gen();
|
||||
}
|
||||
|
||||
// Main program via the Arduino standard methods
|
||||
void loop() {
|
||||
// Handle keyboard events
|
||||
handlerKeyboard();
|
||||
|
||||
// Update battery level as appropriate
|
||||
handlerBatteryLevel();
|
||||
|
||||
// Update UI
|
||||
gslc_Update(&m_gui);
|
||||
}
|
||||
|
||||
// Keyboard handler
|
||||
void handlerKeyboard() {
|
||||
// Check if keys were pressed
|
||||
if (keyboard.keyCount()) {
|
||||
// Get keyboard event
|
||||
const BBQ10Keyboard::KeyEvent key = keyboard.keyEvent();
|
||||
|
||||
char output[28];
|
||||
snprintf(output, 28, "key: '%c' (dec %d, hex %02x)", key.key, key.key, key.key);
|
||||
for (int i=0; i<sizeof(output); i++) {
|
||||
char toPush = output[i];
|
||||
if (toPush != '\0') {
|
||||
textBuffer.push(toPush);
|
||||
}
|
||||
else if (toPush == '\0') {
|
||||
textBuffer.push('\n');
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Add keycodes to text box
|
||||
for (int i=0; i<textBuffer.size(); i++) {
|
||||
//tft.print(textBuffer[i]);
|
||||
}
|
||||
|
||||
// Pick color for signaling a key was pressed (short or long press)
|
||||
uint32_t keyboard_pixel_color = pixels_wing.Color(0, 0, 255);
|
||||
if (key.state == BBQ10Keyboard::StateLongPress) {
|
||||
keyboard_pixel_color = pixels_wing.Color(0, 255, 255);
|
||||
}
|
||||
|
||||
// Display indicator accordingly
|
||||
if (key.state == BBQ10Keyboard::StatePress || key.state == BBQ10Keyboard::StateLongPress) {
|
||||
pixels_wing.setPixelColor(0, keyboard_pixel_color);
|
||||
pixels_wing.show();
|
||||
}
|
||||
else {
|
||||
pixels_wing.clear();
|
||||
pixels_wing.show();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Measure battery level and change NeoPixel accordingly
|
||||
void handlerBatteryLevel() {
|
||||
measuredVBat = analogRead(VBATPIN);
|
||||
measuredVBat *= 2; // we divided by 2, so multiply back
|
||||
measuredVBat *= 3.3; // Multiply by 3.3V, our reference voltage
|
||||
measuredVBat /= 1024; // convert to voltage
|
||||
batteryPercent = (measuredVBat / 3.3) * 100;
|
||||
|
||||
gslc_tsColor colorForHeaderElements;
|
||||
if (batteryPercent >= 75) {
|
||||
pixels_board.setPixelColor(0, pixels_board.Color(0, 255, 0));
|
||||
colorForHeaderElements = GSLC_COL_GREEN;
|
||||
}
|
||||
else if (batteryPercent >= 50) {
|
||||
colorForHeaderElements = GSLC_COL_YELLOW;
|
||||
pixels_board.setPixelColor(0, pixels_board.Color(255, 255, 0));
|
||||
}
|
||||
else if (batteryPercent >= 25) {
|
||||
colorForHeaderElements = GSLC_COL_ORANGE;
|
||||
pixels_board.setPixelColor(0, pixels_board.Color(255, 128, 0));
|
||||
}
|
||||
else {
|
||||
colorForHeaderElements = GSLC_COL_RED;
|
||||
pixels_board.setPixelColor(0, pixels_board.Color(255, 0, 0));
|
||||
}
|
||||
|
||||
gslc_ElemXProgressSetVal(&m_gui, m_pElemBatteryLevel, batteryPercent);
|
||||
gslc_tsXProgress* pGauge = (gslc_tsXProgress*)gslc_GetXDataFromRef(&m_gui,m_pElemBatteryLevel,GSLC_TYPEX_PROGRESS,__LINE__);
|
||||
pGauge->colGauge = colorForHeaderElements;
|
||||
gslc_ElemSetTxtCol(&m_gui, m_pElemBatteryLevel, colorForHeaderElements);
|
||||
gslc_ElemSetTxtCol(&m_gui, m_pElemStatusText, colorForHeaderElements);
|
||||
|
||||
// Update GUI and NeoPixel with battery status information
|
||||
gslc_Update(&m_gui);
|
||||
pixels_board.show();
|
||||
}
|
||||
|
||||
// Slider callback function
|
||||
bool CbSlidePos(void* pvGui,void* pvElemRef,int16_t nPos) {
|
||||
gslc_tsGui* pGui = (gslc_tsGui*)(pvGui);
|
||||
gslc_tsElemRef* pElemRef = (gslc_tsElemRef*)(pvElemRef);
|
||||
gslc_tsElem* pElem = gslc_GetElemFromRef(pGui,pElemRef);
|
||||
int16_t nVal;
|
||||
|
||||
// From the element's ID we can determine which slider was updated.
|
||||
switch (pElem->nId) {
|
||||
case E_TXTSCROLL:
|
||||
// Fetch the slider position
|
||||
nVal = gslc_ElemXSliderGetPos(pGui,m_pTextSlider);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//<Checkbox Callback !Start!>
|
||||
//<Checkbox Callback !End!>
|
||||
//<Keypad Callback !Start!>
|
||||
//<Keypad Callback !End!>
|
||||
//<Spinner Callback !Start!>
|
||||
//<Spinner Callback !End!>
|
||||
//<Listbox Callback !Start!>
|
||||
//<Listbox Callback !End!>
|
BIN
serial_debugger.prj
Normal file
BIN
serial_debugger.prj
Normal file
Binary file not shown.
172
serial_debugger_GSLC.h
Normal file
172
serial_debugger_GSLC.h
Normal file
|
@ -0,0 +1,172 @@
|
|||
//<File !Start!>
|
||||
// FILE: [serial_debugger_GSLC.h]
|
||||
// Created by GUIslice Builder version: [0.15.b004]
|
||||
//
|
||||
// GUIslice Builder Generated GUI Framework File
|
||||
//
|
||||
// For the latest guides, updates and support view:
|
||||
// https://github.com/ImpulseAdventure/GUIslice
|
||||
//
|
||||
//<File !End!>
|
||||
|
||||
#ifndef _GUISLICE_GEN_H
|
||||
#define _GUISLICE_GEN_H
|
||||
|
||||
// ------------------------------------------------
|
||||
// Headers to include
|
||||
// ------------------------------------------------
|
||||
#include "src/guislice/GUIslice.h"
|
||||
#include "src/guislice/GUIslice_drv.h"
|
||||
|
||||
// Include any extended elements
|
||||
//<Includes !Start!>
|
||||
// Include extended elements
|
||||
#include "src/guislice/XProgress.h"
|
||||
#include "src/guislice/XTextbox.h"
|
||||
//<Includes !End!>
|
||||
|
||||
// ------------------------------------------------
|
||||
// Headers and Defines for fonts
|
||||
// Note that font files are located within the Adafruit-GFX library folder:
|
||||
// ------------------------------------------------
|
||||
//<Fonts !Start!>
|
||||
#if defined(DRV_DISP_TFT_ESPI)
|
||||
#error Project tab->Target Platform should be tft_espi
|
||||
#endif
|
||||
#include <Adafruit_GFX.h>
|
||||
#include "src/guislice/NotoMono8pt7b.h"
|
||||
//<Fonts !End!>
|
||||
|
||||
// ------------------------------------------------
|
||||
// Defines for resources
|
||||
// ------------------------------------------------
|
||||
//<Resources !Start!>
|
||||
//<Resources !End!>
|
||||
|
||||
// ------------------------------------------------
|
||||
// Enumerations for pages, elements, fonts, images
|
||||
// ------------------------------------------------
|
||||
//<Enum !Start!>
|
||||
enum {E_PG_MAIN};
|
||||
enum {E_ELEM_BATT_LEVEL,E_ELEM_STATUS,E_ELEM_TEXT};
|
||||
// Must use separate enum for fonts with MAX_FONT at end to use gslc_FontSet.
|
||||
enum {E_AO_NOTOMONO8PT7B,MAX_FONT};
|
||||
//<Enum !End!>
|
||||
|
||||
// ------------------------------------------------
|
||||
// Instantiate the GUI
|
||||
// ------------------------------------------------
|
||||
|
||||
// ------------------------------------------------
|
||||
// Define the maximum number of elements and pages
|
||||
// ------------------------------------------------
|
||||
//<ElementDefines !Start!>
|
||||
#define MAX_PAGE 1
|
||||
|
||||
#define MAX_ELEM_PG_MAIN 3 // # Elems total on page
|
||||
#define MAX_ELEM_PG_MAIN_RAM MAX_ELEM_PG_MAIN // # Elems in RAM
|
||||
//<ElementDefines !End!>
|
||||
|
||||
// ------------------------------------------------
|
||||
// Create element storage
|
||||
// ------------------------------------------------
|
||||
gslc_tsGui m_gui;
|
||||
gslc_tsDriver m_drv;
|
||||
gslc_tsFont m_asFont[MAX_FONT];
|
||||
gslc_tsPage m_asPage[MAX_PAGE];
|
||||
|
||||
//<GUI_Extra_Elements !Start!>
|
||||
gslc_tsElem m_asPage1Elem[MAX_ELEM_PG_MAIN_RAM];
|
||||
gslc_tsElemRef m_asPage1ElemRef[MAX_ELEM_PG_MAIN];
|
||||
gslc_tsXProgress m_sXBarGauge1;
|
||||
gslc_tsXTextbox m_sTextbox1;
|
||||
char m_acTextboxBuf1[952]; // NRows=17 NCols=56
|
||||
|
||||
#define MAX_STR 100
|
||||
|
||||
//<GUI_Extra_Elements !End!>
|
||||
|
||||
// ------------------------------------------------
|
||||
// Program Globals
|
||||
// ------------------------------------------------
|
||||
|
||||
// Element References for direct access
|
||||
//<Extern_References !Start!>
|
||||
extern gslc_tsElemRef* m_pElemBatteryLevel;
|
||||
extern gslc_tsElemRef* m_pElemStatusText;
|
||||
extern gslc_tsElemRef* m_pElemText;
|
||||
extern gslc_tsElemRef* m_pTextSlider;
|
||||
//<Extern_References !End!>
|
||||
|
||||
// Define debug message function
|
||||
static int16_t DebugOut(char ch);
|
||||
|
||||
// ------------------------------------------------
|
||||
// Callback Methods
|
||||
// ------------------------------------------------
|
||||
bool CbBtnCommon(void* pvGui,void *pvElemRef,gslc_teTouch eTouch,int16_t nX,int16_t nY);
|
||||
bool CbCheckbox(void* pvGui, void* pvElemRef, int16_t nSelId, bool bState);
|
||||
bool CbDrawScanner(void* pvGui,void* pvElemRef,gslc_teRedrawType eRedraw);
|
||||
bool CbKeypad(void* pvGui, void *pvElemRef, int16_t nState, void* pvData);
|
||||
bool CbListbox(void* pvGui, void* pvElemRef, int16_t nSelId);
|
||||
bool CbSlidePos(void* pvGui,void* pvElemRef,int16_t nPos);
|
||||
bool CbSpinner(void* pvGui, void *pvElemRef, int16_t nState, void* pvData);
|
||||
bool CbTickScanner(void* pvGui,void* pvScope);
|
||||
|
||||
// ------------------------------------------------
|
||||
// Create page elements
|
||||
// ------------------------------------------------
|
||||
void InitGUIslice_gen()
|
||||
{
|
||||
gslc_tsElemRef* pElemRef = NULL;
|
||||
|
||||
if (!gslc_Init(&m_gui,&m_drv,m_asPage,MAX_PAGE,m_asFont,MAX_FONT)) { return; }
|
||||
|
||||
// ------------------------------------------------
|
||||
// Load Fonts
|
||||
// ------------------------------------------------
|
||||
//<Load_Fonts !Start!>
|
||||
if (!gslc_FontSet(&m_gui,E_AO_NOTOMONO8PT7B,GSLC_FONTREF_PTR,&NotoMono8pt7b,1)) { return; }
|
||||
//<Load_Fonts !End!>
|
||||
|
||||
//<InitGUI !Start!>
|
||||
gslc_PageAdd(&m_gui,E_PG_MAIN,m_asPage1Elem,MAX_ELEM_PG_MAIN_RAM,m_asPage1ElemRef,MAX_ELEM_PG_MAIN);
|
||||
|
||||
// NOTE: The current page defaults to the first page added. Here we explicitly
|
||||
// ensure that the main page is the correct page no matter the add order.
|
||||
gslc_SetPageCur(&m_gui,E_PG_MAIN);
|
||||
|
||||
// Set Background to a flat color
|
||||
gslc_SetBkgndColor(&m_gui,GSLC_COL_BLACK);
|
||||
|
||||
// -----------------------------------
|
||||
// PAGE: E_PG_MAIN
|
||||
|
||||
|
||||
// Create progress bar E_ELEM_BATT_LEVEL
|
||||
pElemRef = gslc_ElemXProgressCreate(&m_gui,E_ELEM_BATT_LEVEL,E_PG_MAIN,&m_sXBarGauge1,
|
||||
(gslc_tsRect){263,5,50,15},0,100,0,GSLC_COL_GREEN,false);
|
||||
m_pElemBatteryLevel = pElemRef;
|
||||
|
||||
// Create E_ELEM_STATUS text label
|
||||
pElemRef = gslc_ElemCreateTxt(&m_gui,E_ELEM_STATUS,E_PG_MAIN,(gslc_tsRect){2,2,250,21},
|
||||
(char*)"UART0 / 1151200",0,E_AO_NOTOMONO8PT7B);
|
||||
gslc_ElemSetTxtCol(&m_gui,pElemRef,GSLC_COL_GREEN);
|
||||
m_pElemStatusText = pElemRef;
|
||||
|
||||
// Create textbox
|
||||
pElemRef = gslc_ElemXTextboxCreate(&m_gui,E_ELEM_TEXT,E_PG_MAIN,&m_sTextbox1,
|
||||
(gslc_tsRect){3,30,313,202},E_AO_NOTOMONO8PT7B,
|
||||
(char*)&m_acTextboxBuf1,17,56);
|
||||
gslc_ElemXTextboxWrapSet(&m_gui,pElemRef,true);
|
||||
gslc_ElemSetTxtCol(&m_gui,pElemRef,GSLC_COL_GRAY_LT3);
|
||||
gslc_ElemSetCol(&m_gui,pElemRef,GSLC_COL_GRAY,GSLC_COL_BLACK,GSLC_COL_BLACK);
|
||||
m_pElemText = pElemRef;
|
||||
//<InitGUI !End!>
|
||||
|
||||
//<Startup !Start!>
|
||||
//<Startup !End!>
|
||||
|
||||
}
|
||||
|
||||
#endif // end _GUISLICE_GEN_H
|
5140
src/guislice/GUIslice.c
Normal file
5140
src/guislice/GUIslice.c
Normal file
File diff suppressed because it is too large
Load diff
3801
src/guislice/GUIslice.h
Normal file
3801
src/guislice/GUIslice.h
Normal file
File diff suppressed because it is too large
Load diff
218
src/guislice/GUIslice_config.h
Normal file
218
src/guislice/GUIslice_config.h
Normal file
|
@ -0,0 +1,218 @@
|
|||
#ifndef _GUISLICE_CONFIG_H_
|
||||
#define _GUISLICE_CONFIG_H_
|
||||
|
||||
// =======================================================================
|
||||
// GUIslice library (user configuration) selection by device
|
||||
// - Calvin Hass
|
||||
// - https://www.impulseadventure.com/elec/guislice-gui.html
|
||||
// - https://github.com/ImpulseAdventure/GUIslice
|
||||
// =======================================================================
|
||||
//
|
||||
// The MIT License
|
||||
//
|
||||
// Copyright 2016-2020 Calvin Hass
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
//
|
||||
// =======================================================================
|
||||
// \file GUIslice_config.h
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif // __cplusplus
|
||||
|
||||
// =========================================================================================
|
||||
// SELECT ONE OF THE FOLLOWING EXAMPLE CONFIGURATIONS OR ADD YOUR OWN
|
||||
// - Uncomment one of the following lines
|
||||
// - These example configurations are located in the /configs folder
|
||||
// - To add your own, make a copy of an example config, rename it
|
||||
// and add it to the list here.
|
||||
// - If no line is uncommented, then the default combined configuration
|
||||
// file will be used, ie. GUIslice_config_ard.h / GUIslice_config_linux.h
|
||||
// which is selected at the bottom of this file
|
||||
// - Refer to https://github.com/ImpulseAdventure/GUIslice/wiki/Display-Config-Table
|
||||
// to help identify a suitable config for your MCU shield / display
|
||||
// - Multiple configurations can be supported using the method described here:
|
||||
// https://github.com/ImpulseAdventure/GUIslice/wiki/Arduino-Multiple-Configs
|
||||
// =========================================================================================
|
||||
|
||||
// =========================================================================================
|
||||
// IMPORTANT: Ensure you backup any custom config files before updating GUIslice!
|
||||
// The Arduino IDE deletes all files within the library when updating
|
||||
// =========================================================================================
|
||||
|
||||
// ---------------------------------------------------------------------------------------
|
||||
// Add your own configs here:
|
||||
// ---------------------------------------------------------------------------------------
|
||||
//#include "../configs/my-config.h"
|
||||
|
||||
// ---------------------------------------------------------------------------------------
|
||||
// Example configs included in library /configs:
|
||||
// ---------------------------------------------------------------------------------------
|
||||
|
||||
// Arduino, ARM SAMD, Cortex M0/M4, nRF52:
|
||||
// ------------------------------------------------------
|
||||
//#include "../configs/ard-shld-adafruit_18_joy.h"
|
||||
//#include "../configs/ard-shld-adafruit_28_cap.h"
|
||||
//#include "../configs/ard-shld-adafruit_28_res.h"
|
||||
//#include "../configs/ard-shld-eastrising_50_ra8875_res.h"
|
||||
//#include "../configs/ard-shld-eastrising_50_ra8875_sumo_res.h"
|
||||
//#include "../configs/ard-shld-eastrising_50_ssd1963_res.h"
|
||||
//#include "../configs/ard-shld-eastrising_70_ra8876_gv.h"
|
||||
//#include "../configs/ard-shld-elegoo_28_res.h"
|
||||
//#include "../configs/ard-shld-generic1_35_touch.h"
|
||||
//#include "../configs/ard-shld-gevino_tft.h"
|
||||
//#include "../configs/ard-shld-ili9341_16b_touch.h"
|
||||
//#include "../configs/ard-shld-mcufriend.h"
|
||||
//#include "../configs/ard-shld-mcufriend_4wire.h"
|
||||
//#include "../configs/ard-shld-mcufriend_xpt2046.h"
|
||||
//#include "../configs/ard-shld-osmart_22_68130_touch.h"
|
||||
//#include "../configs/ard-shld-waveshare_28_touch.h"
|
||||
//#include "../configs/ard-shld-waveshare_40_notouch.h"
|
||||
//#include "../configs/ard-shld-waveshare_40_xpt2046.h"
|
||||
//#include "../configs/ard-adagfx-hx8347-xpt2046.h"
|
||||
//#include "../configs/ard-adagfx-hx8357-ft6206.h"
|
||||
//#include "../configs/ard-adagfx-hx8357-notouch.h"
|
||||
//#include "../configs/ard-adagfx-hx8357-simple.h"
|
||||
//#include "../configs/ard-adagfx-hx8357-stmpe610.h"
|
||||
//#include "../configs/ard-adagfx-ili9341-ft6206.h"
|
||||
//#include "../configs/ard-adagfx-ili9341-input.h"
|
||||
//#include "../configs/ard-adagfx-ili9341-notouch.h"
|
||||
//#include "../configs/ard-adagfx-ili9341-simple.h"
|
||||
//#include "../configs/ard-adagfx-ili9341-stmpe610.h"
|
||||
//#include "../configs/ard-adagfx-ili9341-xpt2046.h"
|
||||
//#include "../configs/ard-adagfx-pcd8544-notouch.h"
|
||||
//#include "../configs/ard-adagfx-ra8875-notouch.h"
|
||||
//#include "../configs/ard-adagfx-ra8876-notouch.h"
|
||||
//#include "../configs/ard-adagfx-ra8876-ft5206.h"
|
||||
//#include "../configs/ard-adagfx-ssd1306-notouch.h"
|
||||
//#include "../configs/ard-adagfx-st7735-notouch.h"
|
||||
//#include "../configs/due-adagfx-ili9341-ft6206.h"
|
||||
//#include "../configs/due-adagfx-ili9341-urtouch.h"
|
||||
|
||||
// ESP8266, ESP32, M5stack, TTGO:
|
||||
// ------------------------------------------------------
|
||||
//#include "../configs/esp-shld-m5stack.h"
|
||||
//#include "../configs/esp-shld-ttgo_btc_ticker.h"
|
||||
//#include "../configs/esp-tftespi-default-ft6206.h"
|
||||
//#include "../configs/esp-tftespi-default-notouch.h"
|
||||
//#include "../configs/esp-tftespi-default-simple.h"
|
||||
//#include "../configs/esp-tftespi-default-stmpe610.h"
|
||||
//#include "../configs/esp-tftespi-default-xpt2046.h"
|
||||
//#include "../configs/esp-tftespi-default-xpt2046_int.h"
|
||||
|
||||
// Teensy:
|
||||
// ------------------------------------------------------
|
||||
//#include "../configs/teensy-adagfx-ili9341-xpt2046.h"
|
||||
//#include "../configs/teensy-adagfx-ili9341-xpt2046-audio.h"
|
||||
//#include "../configs/teensy-adagfx-ili9341_t3-xpt2046.h"
|
||||
//#include "../configs/teensy-adagfx-ili9341_t3-xpt2046-audio.h"
|
||||
|
||||
// STM32:
|
||||
// ------------------------------------------------------
|
||||
//#include "../configs/stm32-adagfx-mcufriend-notouch.h"
|
||||
//#include "../configs/stm32-adagfx-mcufriend-simple.h"
|
||||
|
||||
// Multi-device shields:
|
||||
// ------------------------------------------------------
|
||||
//#include "../configs/mult-shld-adafruit_24_feather_touch.h"
|
||||
//#include "../configs/mult-shld-adafruit_35_feather_touch.h"
|
||||
|
||||
// Raspberry Pi / LINUX:
|
||||
// ------------------------------------------------------
|
||||
//#include "../configs/rpi-sdl1-default-tslib.h"
|
||||
//#include "../configs/rpi-sdl1-default-sdl.h"
|
||||
//#include "../configs/linux-sdl1-default-mouse.h"
|
||||
|
||||
|
||||
// =========================================================================================
|
||||
// DETECT DEVICE PLATFORM
|
||||
// =========================================================================================
|
||||
|
||||
// Detect device platform
|
||||
// #if defined(__linux__)
|
||||
// #define GSLC_CFG_LINUX
|
||||
// #elif defined(__AVR__) && !defined(TEENSYDUINO)
|
||||
// // Note: Teensy 2 also defines __AVR__, so differentiate with TEENSYDUINO
|
||||
// #define GSLC_CFG_ARD
|
||||
// #elif defined(ARDUINO_SAMD_ZERO)
|
||||
// #define GSLC_CFG_ARD
|
||||
// #elif defined(ESP8266) || defined(ESP32)
|
||||
// #define GSLC_CFG_ARD
|
||||
// #elif defined(NRF52)
|
||||
// #define GSLC_CFG_ARD
|
||||
// #elif defined(ARDUINO_STM32_FEATHER) || defined(__STM32F1__)
|
||||
// #define GSLC_CFG_ARD
|
||||
// #elif defined(ARDUINO_ARCH_STM32) // ST Core from STMicroelectronics
|
||||
// #define GSLC_CFG_ARD
|
||||
// #elif defined(ARDUINO_ARCH_SAM) // Arduino Due
|
||||
// #define GSLC_CFG_ARD
|
||||
// #elif defined(ARDUINO_ARCH_SAMD) // M0_PRO
|
||||
// #define GSLC_CFG_ARD
|
||||
// #elif defined(__AVR__) && defined(TEENSYDUINO) // Teensy 2
|
||||
// #define GSLC_DEV_TEENSY_2
|
||||
// #define GSLC_CFG_ARD
|
||||
// #elif defined(__MKL26Z64__) // Teensy LC
|
||||
// #define GSLC_CFG_ARD
|
||||
// #define GSLC_DEV_TEENSY_LC
|
||||
// #elif defined(__MK20DX256__) // Teensy 3.2
|
||||
// #define GSLC_CFG_ARD
|
||||
// #define GSLC_DEV_TEENSY_3_2
|
||||
// #elif defined(__MK64FX512__) // Teensy 3.5
|
||||
// #define GSLC_CFG_ARD
|
||||
// #define GSLC_DEV_TEENSY_3_5
|
||||
// #elif defined(__MK66FX1M0__) // Teensy 3.6
|
||||
// #define GSLC_CFG_ARD
|
||||
// #define GSLC_DEV_TEENSY_3_6
|
||||
// #elif defined(__MK66FX1M0__) // Teensy 3.6
|
||||
// #define GSLC_CFG_ARD
|
||||
// #define GSLC_DEV_TEENSY_3_6
|
||||
// #elif defined(__IMXRT1062__)
|
||||
// #define GSLC_CFG_ARD
|
||||
// #define GSLC_DEV_TEENSY_4_0
|
||||
// #else
|
||||
// #warning Unknown
|
||||
// #error "Unknown device platform"
|
||||
// #endif
|
||||
|
||||
// Adafruit nRF52840 Feather
|
||||
#include "ard-adagfx-ili9341-stmpe610.h"
|
||||
// #include "ard-adagfx-ili9341-notouch.h"
|
||||
#define GSLC_CFG_ARD
|
||||
|
||||
// =========================================================================================
|
||||
// DEFAULT COMBINED CONFIGURATION FILE
|
||||
// - If no user configuration has been selected, a default config will be selected here
|
||||
// - Note that the include guard _GUISLICE_CONFIG_ARD_H_ and _GUISLICE_CONFIG_LINUX_H_
|
||||
// will prevent these from loading if any of the user configs have been loaded
|
||||
// =========================================================================================
|
||||
|
||||
#if defined(GSLC_CFG_LINUX)
|
||||
#include "GUIslice_config_linux.h"
|
||||
#elif defined(GSLC_CFG_ARD)
|
||||
#include "GUIslice_config_ard.h"
|
||||
#endif
|
||||
|
||||
// -----------------------------------------------------------------------------------------
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif // __cplusplus
|
||||
#endif // _GUISLICE_CONFIG_H_
|
526
src/guislice/GUIslice_config_ard.h
Normal file
526
src/guislice/GUIslice_config_ard.h
Normal file
|
@ -0,0 +1,526 @@
|
|||
#ifndef _GUISLICE_CONFIG_ARD_H_
|
||||
#define _GUISLICE_CONFIG_ARD_H_
|
||||
|
||||
#warning No config selected in GUIslice_config.h - resorting to defaults.
|
||||
|
||||
// =============================================================================
|
||||
// GUIslice library (user configuration) for:
|
||||
// - Arduino
|
||||
// - Cortex-M0
|
||||
// - ESP8266 / ESP32
|
||||
// - nRF52
|
||||
// - STM32
|
||||
//
|
||||
// - Calvin Hass
|
||||
// - https://www.impulseadventure.com/elec/guislice-gui.html
|
||||
// - https://github.com/ImpulseAdventure/GUIslice
|
||||
// =============================================================================
|
||||
//
|
||||
// The MIT License
|
||||
//
|
||||
// Copyright 2016-2020 Calvin Hass
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
//
|
||||
// =============================================================================
|
||||
// \file GUIslice_config_ard.h
|
||||
|
||||
// =============================================================================
|
||||
// User Configuration
|
||||
// - This file can be modified by the user to match the
|
||||
// intended target configuration
|
||||
// - Please refer to "docs/GUIslice_config_guide.xlsx" for detailed examples
|
||||
// specific to board and display combinations
|
||||
// =============================================================================
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif // __cplusplus
|
||||
|
||||
|
||||
// =============================================================================
|
||||
// DISPLAY CONFIGURATION - SELECT
|
||||
// =============================================================================
|
||||
|
||||
// Specify the graphics driver library
|
||||
// - Uncomment one of the following graphics drivers DRV_DISP_*
|
||||
// applicable to the device type in use
|
||||
|
||||
// --------------------------------------------------------------
|
||||
// Arduino / ATmega / AVR / Cortex-M0 / nRF52:
|
||||
#define DRV_DISP_ADAGFX // Adafruit-GFX library
|
||||
// --------------------------------------------------------------
|
||||
// ESP8266 / ESP32 / NodeMCU:
|
||||
// #define DRV_DISP_ADAGFX // Adafruit-GFX library
|
||||
// #define DRV_DISP_TFT_ESPI // Bodmer/TFT_eSPI library
|
||||
// #define DRV_DISP_M5STACK // m5stack/M5Stack library
|
||||
// --------------------------------------------------------------
|
||||
// STM32:
|
||||
// #define DRV_DISP_ADAGFX // Adafruit-GFX library
|
||||
// #define DRV_DISP_ADAGFX_AS // Adafruit-GFX-AS library, high speed using DMA
|
||||
// --------------------------------------------------------------
|
||||
|
||||
|
||||
// =============================================================================
|
||||
// TOUCH CONFIGURATION - SELECT
|
||||
// =============================================================================
|
||||
|
||||
// Specify the touchscreen driver
|
||||
// - Uncomment one of the following touchscreen drivers DRV_TOUCH_*
|
||||
// applicable to the controller chip in use
|
||||
|
||||
#define DRV_TOUCH_NONE // No touchscreen support & no input (GPIO / keyboard)
|
||||
// #define DRV_TOUCH_ADA_STMPE610 // Adafruit STMPE610 touch driver
|
||||
// #define DRV_TOUCH_ADA_FT6206 // Adafruit FT6206 touch driver
|
||||
// #define DRV_TOUCH_ADA_SIMPLE // Adafruit Touchscreen
|
||||
// #define DRV_TOUCH_TFT_ESPI // TFT_eSPI integrated XPT2046 touch driver
|
||||
// #define DRV_TOUCH_M5STACK // M5stack integrated button driver
|
||||
// #define DRV_TOUCH_XPT2046_PS // PaulStoffregen/XPT2046_Touchscreen
|
||||
// #define DRV_TOUCH_XPT2046_STM // Arduino_STM32/Serasidis_XPT2046_touch (XPT2046_touch.h)
|
||||
// #define DRV_TOUCH_INPUT // No touchscreen support, but input only (GPIO / keyboard)
|
||||
// #define DRV_TOUCH_HANDLER // touch handler class
|
||||
|
||||
|
||||
// =============================================================================
|
||||
// DISPLAY CONFIGURATION - DETAILS
|
||||
// - Graphics display driver-specific additional configuration
|
||||
// =============================================================================
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
#if defined(DRV_DISP_ADAGFX)
|
||||
|
||||
// The Adafruit-GFX library supports a number of displays
|
||||
// - Select a display sub-type by uncommenting one of the
|
||||
// following DRV_DISP_ADAGFX_* lines
|
||||
#define DRV_DISP_ADAGFX_ILI9341 // Adafruit ILI9341
|
||||
//#define DRV_DISP_ADAGFX_ILI9341_8BIT // Adafruit ILI9341 (8-bit interface)
|
||||
//#define DRV_DISP_ADAGFX_ST7735 // Adafruit ST7735
|
||||
//#define DRV_DISP_ADAGFX_SSD1306 // Adafruit SSD1306
|
||||
//#define DRV_DISP_ADAGFX_HX8347 // prenticedavid/HX8347D_kbv
|
||||
//#define DRV_DISP_ADAGFX_HX8357 // Adafruit HX8357
|
||||
//#define DRV_DISP_ADAGFX_PCD8544 // Adafruit PCD8544
|
||||
|
||||
// For Adafruit-GFX drivers, define pin connections
|
||||
// - Define general pins (modify these example pin assignments to match your board)
|
||||
// - Please refer to "docs/GUIslice_config_guide.xlsx" for detailed examples
|
||||
#define ADAGFX_PIN_CS 10 // Display chip select
|
||||
#define ADAGFX_PIN_DC 9 // Display SPI data/command
|
||||
#define ADAGFX_PIN_RST 0 // Display Reset (some displays could use pin 11)
|
||||
#define ADAGFX_PIN_SDCS 4 // SD card chip select
|
||||
#define ADAGFX_PIN_WR A1 // Display write pin (for parallel displays)
|
||||
#define ADAGFX_PIN_RD A0 // Display read pin (for parallel displays)
|
||||
|
||||
// Use hardware SPI interface?
|
||||
// - Set to 1 to enable hardware SPI interface, 0 to use software SPI
|
||||
// - Software SPI may support the use of custom pin selection (via ADAGFX_PIN_MOSI,
|
||||
// ADAGFX_PIN_MISO, ADAGFX_PIN_CLK). These pin definitions can be left blank in
|
||||
// hardware SPI mode.
|
||||
#define ADAGFX_SPI_HW 1
|
||||
|
||||
// Define custom SPI pin connections used in software SPI mode (ADAGFX_SPI_HW=0)
|
||||
// - These definitions can be left blank in hardware mode (ADAGFX_SPI_HW=1)
|
||||
#define ADAGFX_PIN_MOSI
|
||||
#define ADAGFX_PIN_MISO
|
||||
#define ADAGFX_PIN_CLK
|
||||
|
||||
// Set Default rotation
|
||||
// you can specify values 0,1,2,3, rotation is clockwise
|
||||
#define GSLC_ROTATE 1
|
||||
|
||||
|
||||
#elif defined(DRV_DISP_ADAGFX_AS)
|
||||
|
||||
//NOTE: this is a optimized driver for STM32 only
|
||||
|
||||
// The Adafruit-GFX-AS library supports a number of displays
|
||||
// - Select a display sub-type by uncommenting one of the
|
||||
// following DRV_DISP_ADAGFX_* lines
|
||||
#define DRV_DISP_ADAGFX_ILI9341_STM // Adafruit ILI9341 (STM32 version)
|
||||
|
||||
// For Adafruit-GFX drivers, define pin connections
|
||||
// - Define general pins (modify these example pin assignments to match your board)
|
||||
// - Please refer to "docs/GUIslice_config_guide.xlsx" for detailed examples
|
||||
|
||||
//Note: Fixed pin setting for HW SPI1
|
||||
// PA5 SCLK
|
||||
// PA6 MISO
|
||||
// PA7 MOSI
|
||||
|
||||
// USE Arduino STM32 PIN Notations
|
||||
// - Define to use Arduino STM32 PIN Notations
|
||||
// #define STM32_NOTATION
|
||||
|
||||
#if defined(STM32_NOTATION)
|
||||
// NOTE: Using Arduino STM32 pin notation
|
||||
#define ADAGFX_PIN_CS PA4 // Display chip select
|
||||
#define ADAGFX_PIN_DC PB1 // Display SPI data/command
|
||||
#define ADAGFX_PIN_RST PB0 // Display Reset (set to -1 in order to use Adafruit-GFX drivers w/o reset)
|
||||
#define ADAGFX_PIN_SDCS // SD card chip select
|
||||
#define ADAGFX_PIN_WR // Display write pin (for parallel displays)
|
||||
#define ADAGFX_PIN_RD // Display read pin (for parallel displays)
|
||||
#else
|
||||
// NOTE: Using Arduino pin notation
|
||||
#define ADAGFX_PIN_CS 10 // Display chip select
|
||||
#define ADAGFX_PIN_DC 9 // Display SPI data/command
|
||||
#define ADAGFX_PIN_RST 0 // Display Reset (some displays could use pin 11)
|
||||
#define ADAGFX_PIN_SDCS 4 // SD card chip select
|
||||
#define ADAGFX_PIN_WR A1 // Display write pin (for parallel displays)
|
||||
#define ADAGFX_PIN_RD A0 // Display read pin (for parallel displays)
|
||||
#endif
|
||||
|
||||
// Use hardware SPI interface?
|
||||
// - Set to 1 to enable hardware SPI interface, 0 to use software SPI
|
||||
// - Software SPI may support the use of custom pin selection (via ADAGFX_PIN_MOSI,
|
||||
// ADAGFX_PIN_MISO, ADAGFX_PIN_CLK). These pin definitions can be left blank in
|
||||
// hardware SPI mode.
|
||||
#define ADAGFX_SPI_HW 1
|
||||
|
||||
// Define custom SPI pin connections used in software SPI mode (ADAGFX_SPI_HW=0)
|
||||
// - These definitions can be left blank in hardware mode (ADAGFX_SPI_HW=1)
|
||||
#define ADAGFX_PIN_MOSI
|
||||
#define ADAGFX_PIN_MISO
|
||||
#define ADAGFX_PIN_CLK
|
||||
|
||||
|
||||
// Set Default rotation
|
||||
// you can specify values 0,1,2,3, rotation is clockwise
|
||||
#define GSLC_ROTATE 1
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
#elif defined(DRV_DISP_TFT_ESPI)
|
||||
|
||||
// NOTE: When using the TFT_eSPI library, there are additional
|
||||
// library-specific configuration files that may need
|
||||
// customization (including pin configuration), such as
|
||||
// "User_Setup_Select.h" (typically located in the
|
||||
// Arduino /libraries/TFT_eSPI folder). Please refer to
|
||||
// Bodmer's TFT_eSPI library for more details:
|
||||
// https://github.com/Bodmer/TFT_eSPI
|
||||
|
||||
// NOTE: To avoid potential SPI conflicts, it is recommended
|
||||
// that SUPPORT_TRANSACTIONS is defined in TFT_eSPI's "User Setup"
|
||||
|
||||
|
||||
// Set Default rotation
|
||||
// you can specify values 0,1,2,3, rotation is clockwise
|
||||
#define GSLC_ROTATE 1
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
#elif defined(DRV_DISP_M5STACK)
|
||||
|
||||
#define ADAGFX_PIN_SDCS 4 // SD card chip select
|
||||
#define TFT_LIGHT_PIN 32 // display backlight
|
||||
|
||||
// Set Default rotation
|
||||
// you can specify values 0,1,2,3, rotation is clockwise
|
||||
|
||||
// NOTE: M5stack has a fixed display. A setting of 1 should
|
||||
// match the built-in display and not need changing.
|
||||
#define GSLC_ROTATE 1
|
||||
|
||||
#else
|
||||
|
||||
#error "Unknown driver for display DRV_DISP_..."
|
||||
|
||||
#endif // DRV_DISP_*
|
||||
|
||||
|
||||
// =============================================================================
|
||||
// TOUCH CONFIGURATION - DETAILS
|
||||
// - Touch Driver-specific additional configuration
|
||||
// =============================================================================
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
#if defined(DRV_TOUCH_NONE)
|
||||
|
||||
//no touch defined
|
||||
|
||||
#elif defined(DRV_TOUCH_ADA_STMPE610)
|
||||
|
||||
// Select wiring method by setting one of the following to 1
|
||||
#define ADATOUCH_I2C_HW 0
|
||||
#define ADATOUCH_SPI_HW 1
|
||||
#define ADATOUCH_SPI_SW 0 // [TODO]
|
||||
|
||||
// For ADATOUCH_I2C_HW=1
|
||||
#define ADATOUCH_I2C_ADDR 0x41 // I2C address of touch device
|
||||
|
||||
// For ADATOUCH_SPI_HW=1
|
||||
#define ADATOUCH_PIN_CS 8 // From Adafruit 2.8" TFT touch shield
|
||||
|
||||
// Calibration values for touch display
|
||||
// - These values may need to be updated to match your display
|
||||
// - Typically used in resistive displays
|
||||
// - These values can be determined from the Adafruit touchtest example sketch
|
||||
// (check for min and max values reported from program as you touch display
|
||||
// corners)
|
||||
// - Note that X & Y directions reference the display's natural orientation
|
||||
#define ADATOUCH_X_MIN 230
|
||||
#define ADATOUCH_Y_MIN 260
|
||||
#define ADATOUCH_X_MAX 3800
|
||||
#define ADATOUCH_Y_MAX 3700
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
#elif defined(DRV_TOUCH_ADA_FT6206)
|
||||
// Define sensitivity coefficient (capacitive touch)
|
||||
#define ADATOUCH_SENSITIVITY 40
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
#elif defined(DRV_TOUCH_ADA_SIMPLE)
|
||||
|
||||
// Define 4-wire resistive touchscreen pinout
|
||||
#define ADATOUCH_PIN_YP A2 // "Y+": Must be an analog pin, use "An" notation
|
||||
#define ADATOUCH_PIN_XM A3 // "X-": Must be an analog pin, use "An" notation
|
||||
#define ADATOUCH_PIN_YM 44 // "Y-": Can be a digital pin
|
||||
#define ADATOUCH_PIN_XP 45 // "X+": Can be a digital pin
|
||||
#define ADATOUCH_RX 300 // "rxplate"
|
||||
|
||||
// Calibration values for touch display
|
||||
// - These values may need to be updated to match your display
|
||||
// - Typically used in resistive displays
|
||||
#define ADATOUCH_X_MIN 100
|
||||
#define ADATOUCH_Y_MIN 150
|
||||
#define ADATOUCH_X_MAX 900
|
||||
#define ADATOUCH_Y_MAX 900
|
||||
|
||||
// Define pressure threshold for detecting a touch
|
||||
#define ADATOUCH_PRESS_MIN 10
|
||||
#define ADATOUCH_PRESS_MAX 1000
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
#elif defined(DRV_TOUCH_TFT_ESPI)
|
||||
// The TFT_eSPI display library also includes support for XPT2046 touch controller
|
||||
// Note that TFT_eSPI's "User_Setup" should define TOUCH_CS
|
||||
#define DRV_TOUCH_IN_DISP // Use the display driver (TFT_eSPI) for touch events
|
||||
|
||||
// Define the XPT2046 touch driver calibration values
|
||||
// - The following are some example defaults, but they should be updated
|
||||
// to match your specific touch device.
|
||||
#define TFT_ESPI_TOUCH_CALIB { 321,3498,280,3593,3 }
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
#elif defined(DRV_TOUCH_M5STACK)
|
||||
// M5stack integrated button handler
|
||||
#define DRV_TOUCH_IN_DISP // Use the display driver (M5stack) for touch events
|
||||
|
||||
// NOTE: Long-press detection is only available in the latest
|
||||
// M5stack library releases. Uncomment the following
|
||||
// if the Btn wasReleasefor() API is available.
|
||||
//
|
||||
// Define duration (in ms) for a long-press button event
|
||||
//#define M5STACK_TOUCH_PRESS_LONG 300
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
#elif defined(DRV_TOUCH_XPT2046_PS)
|
||||
// PaulStoffregen/XPT2046_Touchscreen
|
||||
|
||||
// Chip select pin for touch
|
||||
#define XPT2046_CS 3
|
||||
|
||||
// Calibration values for touch display
|
||||
// - These values may need to be updated to match your display
|
||||
// - empirically found for XPT2046
|
||||
#define ADATOUCH_X_MIN 246
|
||||
#define ADATOUCH_Y_MIN 3925
|
||||
#define ADATOUCH_X_MAX 3837
|
||||
#define ADATOUCH_Y_MAX 370
|
||||
|
||||
// Define pressure threshold for detecting a touch
|
||||
#define ADATOUCH_PRESS_MIN 10
|
||||
#define ADATOUCH_PRESS_MAX 1000
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
#elif defined(DRV_TOUCH_XPT2046_STM)
|
||||
// Arduino_STM32/Serasidis_XPT2046_touch (XPT2046_touch.h)
|
||||
// NOTE: This touch library is included in the Arduino_STM32 library
|
||||
// While it still works on many non-STM32 targets, it is recommended
|
||||
// that users use DRV_TOUCH_XPT2046_PS instead.
|
||||
|
||||
// SPI2 is used. Due to some known issues of the TFT SPI driver working on SPI1
|
||||
// it was not possible to share the touch with SPI1.
|
||||
// On the Arduino STM32 these are the following pins:
|
||||
// PB13 SCLK
|
||||
// PB14 MISO
|
||||
// PB15 MOSI
|
||||
#define XPT2046_DEFINE_DPICLASS SPIClass XPT2046_spi(2); //Create an SPI instance on SPI2 port
|
||||
|
||||
// Chip select pin for touch SPI2
|
||||
#define XPT2046_CS PB12
|
||||
|
||||
// Calibration values for touch display
|
||||
// - These values may need to be updated to match your display
|
||||
// - empirically found for XPT2046
|
||||
#define ADATOUCH_X_MIN 398
|
||||
#define ADATOUCH_Y_MIN 280
|
||||
#define ADATOUCH_X_MAX 3877
|
||||
#define ADATOUCH_Y_MAX 3805
|
||||
|
||||
// Define pressure threshold for detecting a touch
|
||||
#define ADATOUCH_PRESS_MIN 10
|
||||
#define ADATOUCH_PRESS_MAX 1000
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
#elif defined(DRV_TOUCH_INPUT)
|
||||
// Include basic support for GPIO/keyboard only
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
#elif defined(DRV_TOUCH_HANDLER)
|
||||
// touch handler class
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
#else
|
||||
|
||||
#error "Unknown driver for touch DRV_TOUCH_..."
|
||||
|
||||
#endif // DRV_TOUCH_*
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
|
||||
// TODO: maybe those macros should be moved to one include file which is included by all drivers
|
||||
#define TOUCH_ROTATION_DATA 0x6350
|
||||
#define TOUCH_ROTATION_SWAPXY(rotation) ((( TOUCH_ROTATION_DATA >> ((rotation&0x03)*4) ) >> 2 ) & 0x01 )
|
||||
#define TOUCH_ROTATION_FLIPX(rotation) ((( TOUCH_ROTATION_DATA >> ((rotation&0x03)*4) ) >> 1 ) & 0x01 )
|
||||
#define TOUCH_ROTATION_FLIPY(rotation) ((( TOUCH_ROTATION_DATA >> ((rotation&0x03)*4) ) >> 0 ) & 0x01 )
|
||||
|
||||
// - Set any of the following to 1 to perform touch display
|
||||
// remapping functions, 0 to disable. Use DBG_TOUCH to determine which
|
||||
// remapping modes should be enabled for your display
|
||||
// - Please refer to the wiki for details:
|
||||
// https://github.com/ImpulseAdventure/GUIslice/wiki/Configure-Touch-Support
|
||||
#define ADATOUCH_SWAP_XY 0
|
||||
#define ADATOUCH_FLIP_X 0
|
||||
#define ADATOUCH_FLIP_Y 0
|
||||
|
||||
// Define the maximum number of touch events that are handled
|
||||
// per gslc_Update() call. Normally this can be set to 1 but certain
|
||||
// displays may require a greater value (eg. 30) in order to increase
|
||||
// responsiveness of the touch functionality.
|
||||
#define GSLC_TOUCH_MAX_EVT 1
|
||||
|
||||
|
||||
// =============================================================================
|
||||
// COMMON CONFIGURATION
|
||||
// =============================================================================
|
||||
|
||||
// Error reporting
|
||||
// - Set DEBUG_ERR to 1 to enable error reporting via the Serial connection
|
||||
// - Enabling DEBUG_ERR increases FLASH memory consumption which may be
|
||||
// limited on the baseline Arduino (ATmega328P) devices. Therefore it
|
||||
// is recommended to disable DEBUG_ERR (set to 0) on baseline Arduino
|
||||
// once initial device operation confirmed to work in examples ex01 and ex02.
|
||||
//
|
||||
#if defined(__AVR__)
|
||||
#define DEBUG_ERR 1 // Debugging enabled by default
|
||||
#else
|
||||
// For all other devices, DEBUG_ERR is enabled by default.
|
||||
// Since this mode increases FLASH memory considerably, it may be
|
||||
// necessary to disable this feature.
|
||||
#define DEBUG_ERR 1 // Debugging enabled by default
|
||||
#endif
|
||||
|
||||
// Debug initialization message
|
||||
// - By default, GUIslice outputs a message in DEBUG_ERR mode
|
||||
// to indicate the initialization status, even during success.
|
||||
// - To disable the messages during successful initialization,
|
||||
// uncomment the following line.
|
||||
//#define INIT_MSG_DISABLE
|
||||
|
||||
|
||||
// Enable of optional features
|
||||
// - For memory constrained devices such as Arduino, it is best to
|
||||
// set the following features to 0 (to disable) unless they are
|
||||
// required.
|
||||
|
||||
#define GSLC_FEATURE_COMPOUND 0 // Compound elements (eg. XSelNum)
|
||||
#define GSLC_FEATURE_XGAUGE_RADIAL 0 // XGauge control with radial support
|
||||
#define GSLC_FEATURE_XGAUGE_RAMP 0 // XGauge control with ramp support
|
||||
#define GSLC_FEATURE_XTEXTBOX_EMBED 0 // XTextbox control with embedded color
|
||||
#define GSLC_FEATURE_INPUT 0 // Keyboard / GPIO input control
|
||||
|
||||
|
||||
// Enable support for SD card
|
||||
// - Set to 1 to enable, 0 to disable
|
||||
// - Note that the inclusion of the SD library consumes considerable
|
||||
// RAM and flash memory which could be problematic for Arduino models
|
||||
// with limited resources.
|
||||
#define GSLC_SD_EN 0
|
||||
|
||||
// Define buffer size for loading images from SD
|
||||
// - A larger buffer will be faster but at the cost of RAM
|
||||
#define GSLC_SD_BUFFPIXEL 50
|
||||
|
||||
|
||||
// Enable support for graphics clipping (DrvSetClipRect)
|
||||
// - Note that this will impact performance of drawing graphics primitives
|
||||
#define GSLC_CLIP_EN 1
|
||||
|
||||
// Enable for bitmap transparency and definition of color to use
|
||||
#define GSLC_BMP_TRANS_EN 1 // 1 = enabled, 0 = disabled
|
||||
#define GSLC_BMP_TRANS_RGB 0xFF,0x00,0xFF // RGB color (default:pink)
|
||||
|
||||
|
||||
// In "Local String" mode, memory within internal element array is
|
||||
// used for strings. This mode incurs a memory cost for all elements,
|
||||
// irrespective of whether strings are used or their length. This
|
||||
// mode may make string definition convenient but is not memory-efficient.
|
||||
// Therefore, it is not recommended for limited memory devices such as
|
||||
// Arduino.
|
||||
// - When using element local string storage (GSLC_LOCAL_STR=1),
|
||||
// GSLC_LOCAL_STR_LEN defines the fixed length buffer used for every element
|
||||
#define GSLC_LOCAL_STR 0 // 1=Use local strings (in element array), 0=External
|
||||
#define GSLC_LOCAL_STR_LEN 30 // Max string length of text elements
|
||||
|
||||
#define GSLC_USE_FLOAT 0 // 1=Use floating pt library, 0=Fixed-point lookup tables
|
||||
|
||||
|
||||
// Debug diagnostic modes
|
||||
// - Uncomment any of the following to enable specific debug modes
|
||||
//#define DBG_LOG // Enable debugging log output
|
||||
//#define DBG_TOUCH // Enable debugging of touch-presses
|
||||
//#define DBG_FRAME_RATE // Enable diagnostic frame rate reporting
|
||||
//#define DBG_DRAW_IMM // Enable immediate rendering of drawing primitives
|
||||
//#define DBG_DRIVER // Enable graphics driver debug reporting
|
||||
|
||||
|
||||
// =============================================================================
|
||||
// INTERNAL CONFIGURATION
|
||||
// - Users should not need to modify the following
|
||||
// =============================================================================
|
||||
|
||||
// Display device string is only used in LINUX drivers
|
||||
#define GSLC_DEV_TOUCH "" // No device path used
|
||||
|
||||
|
||||
// Define compatibility for non-AVR to call PROGMEM functions
|
||||
#if defined(__AVR__)
|
||||
#define GSLC_USE_PROGMEM 1
|
||||
#else
|
||||
#define GSLC_USE_PROGMEM 0
|
||||
#endif
|
||||
|
||||
|
||||
// =============================================================================
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif // __cplusplus
|
||||
#endif // _GUISLICE_CONFIG_ARD_H_
|
191
src/guislice/GUIslice_config_linux.h
Normal file
191
src/guislice/GUIslice_config_linux.h
Normal file
|
@ -0,0 +1,191 @@
|
|||
#ifndef _GUISLICE_CONFIG_LINUX_H_
|
||||
#define _GUISLICE_CONFIG_LINUX_H_
|
||||
|
||||
#warning No config selected in GUIslice_config.h - resorting to defaults.
|
||||
|
||||
// =======================================================================
|
||||
// GUIslice library (user configuration) for LINUX / Raspberry Pi / Beaglebone
|
||||
// - Calvin Hass
|
||||
// - https://www.impulseadventure.com/elec/guislice-gui.html
|
||||
// - https://github.com/ImpulseAdventure/GUIslice
|
||||
// =======================================================================
|
||||
//
|
||||
// The MIT License
|
||||
//
|
||||
// Copyright 2016-2020 Calvin Hass
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
//
|
||||
// =======================================================================
|
||||
// \file GUIslice_config_linux.h
|
||||
// \brief GUIslice library (user configuration) for LINUX / Raspberry Pi / Beaglebone
|
||||
|
||||
// =======================================================================
|
||||
// User Configuration
|
||||
// - This file can be modified by the user to match the
|
||||
// intended target configuration
|
||||
// - Please refer to "docs/GUIslice_config_guide.xlsx" for detailed examples
|
||||
// specific to board and display combinations
|
||||
// =======================================================================
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif // __cplusplus
|
||||
|
||||
// -----------------------------------------------------------------------------------------
|
||||
|
||||
// Specify the graphics driver library
|
||||
// - Uncomment one of the following graphics drivers
|
||||
#define DRV_DISP_SDL1 // LINUX: SDL 1.2 library
|
||||
//#define DRV_DISP_SDL2 // LINUX: SDL 2.0 library
|
||||
|
||||
|
||||
|
||||
// Specify the touchscreen driver
|
||||
// - Uncomment one of the following touchscreen drivers
|
||||
//#define DRV_TOUCH_NONE // No touchscreen support
|
||||
//#define DRV_TOUCH_SDL // LINUX: Use SDL touch driver
|
||||
#define DRV_TOUCH_TSLIB // LINUX: Use tslib touch driver
|
||||
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------------------------
|
||||
// Enable of optional features
|
||||
// - For memory constrained devices such as Arduino, it is best to
|
||||
// set the following features to 0 (to disable) unless they are
|
||||
// required.
|
||||
|
||||
#define GSLC_FEATURE_COMPOUND 1 // Compound elements (eg. XSelNum)
|
||||
#define GSLC_FEATURE_XGAUGE_RADIAL 1 // XGauge control with radial support
|
||||
#define GSLC_FEATURE_XGAUGE_RAMP 1 // XGauge control with ramp support
|
||||
#define GSLC_FEATURE_XTEXTBOX_EMBED 0 // XTextbox control with embedded color
|
||||
#define GSLC_FEATURE_INPUT 1 // Keyboard / GPIO input control
|
||||
|
||||
// Error reporting
|
||||
// - Set DEBUG_ERR to 1 to enable error reporting via the console
|
||||
#define DEBUG_ERR 1 // Enable by default
|
||||
|
||||
// Debug initialization message
|
||||
// - By default, GUIslice outputs a message in DEBUG_ERR mode
|
||||
// to indicate the initialization status, even during success.
|
||||
// - To disable the messages during successful initialization,
|
||||
// uncomment the following line.
|
||||
//#define INIT_MSG_DISABLE
|
||||
|
||||
// -----------------------------------------------------------------------------------------
|
||||
|
||||
// Graphics display driver-specific additional configuration
|
||||
#if defined(DRV_DISP_SDL1)
|
||||
// Define default device paths for framebuffer & touchscreen
|
||||
#define GSLC_DEV_FB "/dev/fb1"
|
||||
#define GSLC_DEV_TOUCH "/dev/input/touchscreen"
|
||||
#define GSLC_DEV_VID_DRV "fbcon"
|
||||
|
||||
// Enable SDL startup workaround? (1 to enable, 0 to disable)
|
||||
#define DRV_SDL_FIX_START 0
|
||||
|
||||
// Show SDL mouse (1 to show, 0 to hide)
|
||||
#define DRV_SDL_MOUSE_SHOW 0
|
||||
|
||||
#define GSLC_LOCAL_STR 1
|
||||
#define GSLC_USE_FLOAT 1
|
||||
|
||||
|
||||
#elif defined(DRV_DISP_SDL2)
|
||||
// Define default device paths for framebuffer & touchscreen
|
||||
// - The following assumes display driver (eg. fbtft) reads from fb1
|
||||
// - Raspberry Pi can support hardware acceleration onto fb0
|
||||
// - To use SDL2.0 with hardware acceleration with such displays,
|
||||
// use fb0 as the target and then run fbcp to mirror fb0 to fb1
|
||||
#define GSLC_DEV_FB "/dev/fb0"
|
||||
#define GSLC_DEV_TOUCH ""
|
||||
#define GSLC_DEV_VID_DRV "x11"
|
||||
|
||||
// Show SDL mouse (1 to show, 0 to hide)
|
||||
#define DRV_SDL_MOUSE_SHOW 0
|
||||
// Enable hardware acceleration
|
||||
#define DRV_SDL_RENDER_ACCEL 1
|
||||
|
||||
#define GSLC_LOCAL_STR 1
|
||||
#define GSLC_USE_FLOAT 1
|
||||
|
||||
|
||||
#endif // DRV_DISP_*
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------------------------
|
||||
|
||||
// Touch Driver-specific additional configuration
|
||||
#if defined(DRV_TOUCH_SDL)
|
||||
#define DRV_TOUCH_IN_DISP // Use the display driver (SDL) for touch events
|
||||
|
||||
|
||||
#endif // DRV_TOUCH_*
|
||||
|
||||
|
||||
// NOTE: The GSLC_ROTATE feature is not yet supported in SDL mode
|
||||
// however, the following settings are provided for future use.
|
||||
|
||||
|
||||
// - Set any of the following to 1 to perform touch display
|
||||
// remapping functions, 0 to disable. Use DBG_TOUCH to determine which
|
||||
// remapping modes should be enabled for your display
|
||||
// - Please refer to the wiki for details:
|
||||
// https://github.com/ImpulseAdventure/GUIslice/wiki/Configure-Touch-Support
|
||||
#define ADATOUCH_SWAP_XY 0
|
||||
#define ADATOUCH_FLIP_X 0
|
||||
#define ADATOUCH_FLIP_Y 0
|
||||
|
||||
// Define the maximum number of touch events that are handled
|
||||
// per gslc_Update() call. Normally this can be set to 1 but certain
|
||||
// displays may require a greater value (eg. 30) in order to increase
|
||||
// responsiveness of the touch functionality.
|
||||
#define GSLC_TOUCH_MAX_EVT 1
|
||||
|
||||
// -----------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
// When using element local string storage (GSLC_LOCAL_STR=1),
|
||||
// this defines the fixed length buffer used for every element
|
||||
#define GSLC_LOCAL_STR_LEN 30 // Max string length of text elements
|
||||
|
||||
|
||||
// Debug modes
|
||||
// - Uncomment the following to enable specific debug modes
|
||||
//#define DBG_LOG // Enable debugging log output
|
||||
//#define DBG_TOUCH // Enable debugging of touch-presses
|
||||
//#define DBG_FRAME_RATE // Enable diagnostic frame rate reporting
|
||||
//#define DBG_DRAW_IMM // Enable immediate rendering of drawing primitives
|
||||
//#define DBG_DRIVER // Enable graphics driver debug reporting
|
||||
|
||||
// Enable for bitmap transparency and definition of color to use
|
||||
#define GSLC_BMP_TRANS_EN 1 // 1 = enabled, 0 = disabled
|
||||
#define GSLC_BMP_TRANS_RGB 0xFF,0x00,0xFF // RGB color (default:pink)
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------------------------
|
||||
|
||||
// Define compatibility for non-AVR to call PROGMEM functions
|
||||
#define GSLC_USE_PROGMEM 0
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif // __cplusplus
|
||||
#endif // _GUISLICE_CONFIG_LINUX_H_
|
66
src/guislice/GUIslice_drv.h
Normal file
66
src/guislice/GUIslice_drv.h
Normal file
|
@ -0,0 +1,66 @@
|
|||
#ifndef _GUISLICE_DRV_H_
|
||||
#define _GUISLICE_DRV_H_
|
||||
|
||||
// =======================================================================
|
||||
// GUIslice library (generic driver layer include)
|
||||
// - Calvin Hass
|
||||
// - https://www.impulseadventure.com/elec/guislice-gui.html
|
||||
// - https://github.com/ImpulseAdventure/GUIslice
|
||||
// =======================================================================
|
||||
//
|
||||
// The MIT License
|
||||
//
|
||||
// Copyright 2016-2020 Calvin Hass
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
//
|
||||
// =======================================================================
|
||||
|
||||
|
||||
// =======================================================================
|
||||
// Generic Driver Layer
|
||||
// =======================================================================
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif // __cplusplus
|
||||
|
||||
#if defined(DRV_DISP_SDL1)
|
||||
#include "GUIslice_drv_sdl.h"
|
||||
#elif defined(DRV_DISP_SDL2)
|
||||
#include "GUIslice_drv_sdl.h"
|
||||
#elif defined(DRV_DISP_ADAGFX) || defined(DRV_DISP_ADAGFX_AS)
|
||||
#include "GUIslice_drv_adagfx.h"
|
||||
#elif defined(DRV_DISP_TFT_ESPI)
|
||||
#include "GUIslice_drv_tft_espi.h"
|
||||
#elif defined(DRV_DISP_M5STACK)
|
||||
#include "GUIslice_drv_m5stack.h"
|
||||
#elif defined(DRV_DISP_UTFT)
|
||||
#include "GUIslice_drv_utft.h"
|
||||
#else
|
||||
#error "Driver needs to be specified in GUIslice_config_*.h (DRV_DISP_*)"
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif // __cplusplus
|
||||
#endif // _GUISLICE_DRV_H_
|
||||
|
3063
src/guislice/GUIslice_drv_adagfx.cpp
Normal file
3063
src/guislice/GUIslice_drv_adagfx.cpp
Normal file
File diff suppressed because it is too large
Load diff
757
src/guislice/GUIslice_drv_adagfx.h
Normal file
757
src/guislice/GUIslice_drv_adagfx.h
Normal file
|
@ -0,0 +1,757 @@
|
|||
#ifndef _GUISLICE_DRV_ADAGFX_H_
|
||||
#define _GUISLICE_DRV_ADAGFX_H_
|
||||
|
||||
// =======================================================================
|
||||
// GUIslice library (driver layer for Adafruit-GFX)
|
||||
// - Calvin Hass
|
||||
// - https://www.impulseadventure.com/elec/guislice-gui.html
|
||||
// - https://github.com/ImpulseAdventure/GUIslice
|
||||
// =======================================================================
|
||||
//
|
||||
// The MIT License
|
||||
//
|
||||
// Copyright 2016-2020 Calvin Hass
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
//
|
||||
// =======================================================================
|
||||
/// \file GUIslice_drv_adagfx.h
|
||||
/// \brief GUIslice library (driver layer for Adafruit-GFX)
|
||||
|
||||
|
||||
// =======================================================================
|
||||
// Driver Layer for Adafruit-GFX
|
||||
// =======================================================================
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif // __cplusplus
|
||||
|
||||
#include "GUIslice.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
|
||||
// Determine characteristics for configured touch driver
|
||||
// - DRV_TOUCH_TYPE_EXTERNAL: TDrv* external touch APIs are enabled
|
||||
// - DRV_TOUCH_TYPE_RES: Resistive overlay
|
||||
// - DRV_TOUCH_TYPE_CAP: Capacitive overlay
|
||||
// - DRV_TOUCH_TYPE_ANALOG: Analog input
|
||||
#if defined(DRV_TOUCH_ADA_STMPE610)
|
||||
#define DRV_TOUCH_TYPE_EXTERNAL
|
||||
#define DRV_TOUCH_TYPE_RES // Resistive
|
||||
#elif defined(DRV_TOUCH_ADA_FT6206)
|
||||
#define DRV_TOUCH_TYPE_EXTERNAL
|
||||
#define DRV_TOUCH_TYPE_CAP // Capacitive
|
||||
#elif defined(DRV_TOUCH_ADA_FT5206)
|
||||
#define DRV_TOUCH_TYPE_EXTERNAL
|
||||
#define DRV_TOUCH_TYPE_CAP // Capacitive
|
||||
#elif defined(DRV_TOUCH_ADA_SIMPLE)
|
||||
#define DRV_TOUCH_TYPE_EXTERNAL
|
||||
#define DRV_TOUCH_TYPE_RES // Resistive
|
||||
#define DRV_TOUCH_TYPE_ANALOG // Analog
|
||||
#elif defined(DRV_TOUCH_ADA_RA8875)
|
||||
#define DRV_TOUCH_TYPE_EXTERNAL
|
||||
#define DRV_TOUCH_TYPE_RES // Resistive
|
||||
#elif defined(DRV_TOUCH_ADA_RA8875_SUMO)
|
||||
#define DRV_TOUCH_TYPE_EXTERNAL
|
||||
#define DRV_TOUCH_TYPE_RES // Resistive
|
||||
#elif defined(DRV_TOUCH_XPT2046_STM)
|
||||
#define DRV_TOUCH_TYPE_EXTERNAL
|
||||
#define DRV_TOUCH_TYPE_RES // Resistive
|
||||
#elif defined(DRV_TOUCH_XPT2046_PS)
|
||||
#define DRV_TOUCH_TYPE_EXTERNAL
|
||||
#define DRV_TOUCH_TYPE_RES // Resistive
|
||||
#elif defined(DRV_TOUCH_URTOUCH)
|
||||
#define DRV_TOUCH_TYPE_EXTERNAL
|
||||
// Don't set DRV_TOUCH_TYPE_RES since URTouch provides its own calibration
|
||||
//#define DRV_TOUCH_TYPE_RES // Resistive
|
||||
#elif defined(DRV_TOUCH_INPUT)
|
||||
#define DRV_TOUCH_TYPE_EXTERNAL
|
||||
#elif defined(DRV_TOUCH_HANDLER)
|
||||
#define DRV_TOUCH_TYPE_EXTERNAL
|
||||
#elif defined(DRV_TOUCH_NONE)
|
||||
#endif // DRV_TOUCH_*
|
||||
|
||||
|
||||
// =======================================================================
|
||||
// API support definitions
|
||||
// - These defines indicate whether the driver includes optimized
|
||||
// support for various APIs. If a define is set to 0, then the
|
||||
// GUIslice core emulation will be used instead.
|
||||
// - At the very minimum, the point draw routine must be available:
|
||||
// gslc_DrvDrawPoint()
|
||||
// =======================================================================
|
||||
|
||||
#define DRV_HAS_DRAW_POINT 1 ///< Support gslc_DrvDrawPoint()
|
||||
|
||||
#define DRV_HAS_DRAW_POINTS 0 ///< Support gslc_DrvDrawPoints()
|
||||
#define DRV_HAS_DRAW_LINE 1 ///< Support gslc_DrvDrawLine()
|
||||
#define DRV_HAS_DRAW_RECT_FRAME 1 ///< Support gslc_DrvDrawFrameRect()
|
||||
#define DRV_HAS_DRAW_RECT_FILL 1 ///< Support gslc_DrvDrawFillRect()
|
||||
#define DRV_HAS_DRAW_RECT_ROUND_FRAME 1 ///< Support gslc_DrvDrawFrameRoundRect()
|
||||
#define DRV_HAS_DRAW_RECT_ROUND_FILL 1 ///< Support gslc_DrvDrawFillRoundRect()
|
||||
#define DRV_HAS_DRAW_CIRCLE_FRAME 1 ///< Support gslc_DrvDrawFrameCircle()
|
||||
#define DRV_HAS_DRAW_CIRCLE_FILL 1 ///< Support gslc_DrvDrawFillCircle()
|
||||
#define DRV_HAS_DRAW_TRI_FRAME 1 ///< Support gslc_DrvDrawFrameTriangle()
|
||||
#define DRV_HAS_DRAW_TRI_FILL 1 ///< Support gslc_DrvDrawFillTriangle()
|
||||
#define DRV_HAS_DRAW_TEXT 1 ///< Support gslc_DrvDrawTxt()
|
||||
#define DRV_HAS_DRAW_BMP_MEM 0 ///< Support gslc_DrvDrawBmp24FromMem()
|
||||
|
||||
#define DRV_OVERRIDE_TXT_ALIGN 0 ///< Driver provides text alignment
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// Driver-specific overrides
|
||||
// - Some drivers have exceptions to the above support configuration
|
||||
// -----------------------------------------------------------------------
|
||||
#if defined(DRV_DISP_WAVESHARE_ILI9486)
|
||||
#undef DRV_HAS_DRAW_RECT_ROUND_FRAME
|
||||
#undef DRV_HAS_DRAW_RECT_ROUND_FILL
|
||||
#undef DRV_HAS_DRAW_TRI_FRAME
|
||||
#undef DRV_HAS_DRAW_TRI_FILL
|
||||
|
||||
#define DRV_HAS_DRAW_RECT_ROUND_FRAME 0
|
||||
#define DRV_HAS_DRAW_RECT_ROUND_FILL 0
|
||||
#define DRV_HAS_DRAW_TRI_FRAME 0
|
||||
#define DRV_HAS_DRAW_TRI_FILL 0
|
||||
|
||||
#elif defined(DRV_DISP_LCDGFX)
|
||||
#undef DRV_HAS_DRAW_RECT_ROUND_FRAME
|
||||
#undef DRV_HAS_DRAW_RECT_ROUND_FILL
|
||||
#undef DRV_HAS_DRAW_CIRCLE_FRAME
|
||||
#undef DRV_HAS_DRAW_CIRCLE_FILL
|
||||
#undef DRV_HAS_DRAW_TRI_FRAME
|
||||
#undef DRV_HAS_DRAW_TRI_FILL
|
||||
|
||||
#define DRV_HAS_DRAW_RECT_ROUND_FRAME 0
|
||||
#define DRV_HAS_DRAW_RECT_ROUND_FILL 0
|
||||
#define DRV_HAS_DRAW_CIRCLE_FRAME 0
|
||||
#define DRV_HAS_DRAW_CIRCLE_FILL 0
|
||||
#define DRV_HAS_DRAW_TRI_FRAME 0
|
||||
#define DRV_HAS_DRAW_TRI_FILL 0
|
||||
|
||||
#elif defined(DRV_DISP_ADAGFX_RA8876)
|
||||
#undef DRV_HAS_DRAW_RECT_ROUND_FRAME
|
||||
#undef DRV_HAS_DRAW_RECT_ROUND_FILL
|
||||
|
||||
#define DRV_HAS_DRAW_RECT_ROUND_FRAME 0
|
||||
#define DRV_HAS_DRAW_RECT_ROUND_FILL 0
|
||||
|
||||
#elif defined(DRV_DISP_ADAGFX_RA8876_GV)
|
||||
#undef DRV_HAS_DRAW_RECT_ROUND_FRAME
|
||||
#undef DRV_HAS_DRAW_RECT_ROUND_FILL
|
||||
|
||||
#define DRV_HAS_DRAW_RECT_ROUND_FRAME 0
|
||||
#define DRV_HAS_DRAW_RECT_ROUND_FILL 0
|
||||
|
||||
|
||||
#elif defined(DRV_DISP_ADAGFX_ILI9341)
|
||||
// BLIT support in library
|
||||
#undef DRV_HAS_DRAW_BMP_MEM
|
||||
#define DRV_HAS_DRAW_BMP_MEM 1
|
||||
#endif
|
||||
|
||||
|
||||
// =======================================================================
|
||||
// Driver-specific members
|
||||
// =======================================================================
|
||||
typedef struct {
|
||||
gslc_tsColor nColBkgnd; ///< Background color (if not image-based)
|
||||
|
||||
gslc_tsRect rClipRect; ///< Clipping rectangle
|
||||
|
||||
} gslc_tsDriver;
|
||||
|
||||
|
||||
|
||||
// =======================================================================
|
||||
// Public APIs to GUIslice core library
|
||||
// - These functions define the renderer / driver-dependent
|
||||
// implementations for the core drawing operations within
|
||||
// GUIslice.
|
||||
// =======================================================================
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// Configuration Functions
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
///
|
||||
/// Initialize the SDL library
|
||||
/// - Performs clean startup workaround (if enabled)
|
||||
/// - Configures video mode
|
||||
/// - Initializes font support
|
||||
///
|
||||
/// PRE:
|
||||
/// - The environment variables should be configured before
|
||||
/// calling gslc_DrvInit(). This can be done with gslc_DrvInitEnv()
|
||||
/// or manually in user function.
|
||||
///
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
///
|
||||
/// \return true if success, false if fail
|
||||
///
|
||||
bool gslc_DrvInit(gslc_tsGui* pGui);
|
||||
|
||||
|
||||
///
|
||||
/// Perform any touchscreen-specific initialization
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] acDev: Device path to touchscreen
|
||||
/// eg. "/dev/input/touchscreen"
|
||||
///
|
||||
/// \return true if successful
|
||||
///
|
||||
bool gslc_DrvInitTs(gslc_tsGui* pGui,const char* acDev);
|
||||
|
||||
|
||||
///
|
||||
/// Free up any members associated with the driver
|
||||
/// - Eg. renderers, windows, background surfaces, etc.
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
///
|
||||
/// \return none
|
||||
///
|
||||
void gslc_DrvDestruct(gslc_tsGui* pGui);
|
||||
|
||||
|
||||
///
|
||||
/// Get the display driver name
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
///
|
||||
/// \return String containing driver name
|
||||
///
|
||||
const char* gslc_DrvGetNameDisp(gslc_tsGui* pGui);
|
||||
|
||||
|
||||
///
|
||||
/// Get the touch driver name
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
///
|
||||
/// \return String containing driver name
|
||||
///
|
||||
const char* gslc_DrvGetNameTouch(gslc_tsGui* pGui);
|
||||
|
||||
///
|
||||
/// Get the native display driver instance
|
||||
/// - This can be useful to access special commands
|
||||
/// available in the selected driver.
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
///
|
||||
/// \return Void pointer to the display driver instance.
|
||||
/// This pointer should be typecast to the particular
|
||||
/// driver being used. If no driver was created then
|
||||
/// this function will return NULL.
|
||||
///
|
||||
void* gslc_DrvGetDriverDisp(gslc_tsGui* pGui);
|
||||
|
||||
///
|
||||
/// Get the native touch driver instance
|
||||
/// - This can be useful to access special commands
|
||||
/// available in the selected driver.
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
///
|
||||
/// \return Void pointer to the touch driver instance.
|
||||
/// This pointer should be typecast to the particular
|
||||
/// driver being used. If no driver was created then
|
||||
/// this function will return NULL.
|
||||
///
|
||||
void* gslc_DrvGetDriverTouch(gslc_tsGui* pGui);
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// Image/surface handling Functions
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
|
||||
///
|
||||
/// Load a bitmap (*.bmp) and create a new image resource.
|
||||
/// Transparency is enabled by GSLC_BMP_TRANS_EN
|
||||
/// through use of color (GSLC_BMP_TRANS_RGB).
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] sImgRef: Image reference
|
||||
///
|
||||
/// \return Image pointer (surface/texture) or NULL if error
|
||||
///
|
||||
void* gslc_DrvLoadImage(gslc_tsGui* pGui,gslc_tsImgRef sImgRef);
|
||||
|
||||
|
||||
///
|
||||
/// Configure the background to use a bitmap image
|
||||
/// - The background is used when redrawing the entire page
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] sImgRef: Image reference
|
||||
///
|
||||
/// \return true if success, false if fail
|
||||
///
|
||||
bool gslc_DrvSetBkgndImage(gslc_tsGui* pGui,gslc_tsImgRef sImgRef);
|
||||
|
||||
///
|
||||
/// Configure the background to use a solid color
|
||||
/// - The background is used when redrawing the entire page
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] nCol: RGB Color to use
|
||||
///
|
||||
/// \return true if success, false if fail
|
||||
///
|
||||
bool gslc_DrvSetBkgndColor(gslc_tsGui* pGui,gslc_tsColor nCol);
|
||||
|
||||
///
|
||||
/// Set an element's normal-state image
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] pElem: Pointer to Element to update
|
||||
/// \param[in] sImgRef: Image reference
|
||||
///
|
||||
/// \return true if success, false if error
|
||||
///
|
||||
bool gslc_DrvSetElemImageNorm(gslc_tsGui* pGui,gslc_tsElem* pElem,gslc_tsImgRef sImgRef);
|
||||
|
||||
///
|
||||
/// Set an element's glow-state image
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] pElem: Pointer to Element to update
|
||||
/// \param[in] sImgRef: Image reference
|
||||
///
|
||||
/// \return true if success, false if error
|
||||
///
|
||||
bool gslc_DrvSetElemImageGlow(gslc_tsGui* pGui,gslc_tsElem* pElem,gslc_tsImgRef sImgRef);
|
||||
|
||||
|
||||
///
|
||||
/// Release an image surface
|
||||
///
|
||||
/// \param[in] pvImg: Void ptr to image
|
||||
///
|
||||
/// \return none
|
||||
///
|
||||
void gslc_DrvImageDestruct(void* pvImg);
|
||||
|
||||
|
||||
///
|
||||
/// Set the clipping rectangle for future drawing updates
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] pRect: Rectangular region to constrain edits
|
||||
///
|
||||
/// \return true if success, false if error
|
||||
///
|
||||
bool gslc_DrvSetClipRect(gslc_tsGui* pGui,gslc_tsRect* pRect);
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// Font handling Functions
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
///
|
||||
/// Load a font from a resource and return pointer to it
|
||||
///
|
||||
/// \param[in] eFontRefType: Font reference type (GSLC_FONTREF_PTR for Arduino)
|
||||
/// \param[in] pvFontRef: Font reference pointer (Pointer to the GFXFont array)
|
||||
/// \param[in] nFontSz: Typeface size to use
|
||||
///
|
||||
/// \return Void ptr to driver-specific font if load was successful, NULL otherwise
|
||||
///
|
||||
const void* gslc_DrvFontAdd(gslc_teFontRefType eFontRefType,const void* pvFontRef,uint16_t nFontSz);
|
||||
|
||||
///
|
||||
/// Release all fonts defined in the GUI
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
///
|
||||
/// \return none
|
||||
///
|
||||
void gslc_DrvFontsDestruct(gslc_tsGui* pGui);
|
||||
|
||||
|
||||
///
|
||||
/// Get the extent (width and height) of a text string
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] pFont: Ptr to Font structure
|
||||
/// \param[in] pStr: String to display
|
||||
/// \param[in] eTxtFlags: Flags associated with text string
|
||||
/// \param[out] pnTxtX: Ptr to offset X of text
|
||||
/// \param[out] pnTxtY: Ptr to offset Y of text
|
||||
/// \param[out] pnTxtSzW: Ptr to width of text
|
||||
/// \param[out] pnTxtSzH: Ptr to height of text
|
||||
///
|
||||
/// \return true if success, false if failure
|
||||
///
|
||||
bool gslc_DrvGetTxtSize(gslc_tsGui* pGui,gslc_tsFont* pFont,const char* pStr,gslc_teTxtFlags eTxtFlags,
|
||||
int16_t* pnTxtX,int16_t* pnTxtY,uint16_t* pnTxtSzW,uint16_t* pnTxtSzH);
|
||||
|
||||
|
||||
///
|
||||
/// Draw a text string at the given coordinate
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] nTxtX: X coordinate of top-left text string
|
||||
/// \param[in] nTxtY: Y coordinate of top-left text string
|
||||
/// \param[in] pFont: Ptr to Font
|
||||
/// \param[in] pStr: String to display
|
||||
/// \param[in] eTxtFlags: Flags associated with text string
|
||||
/// \param[in] colTxt: Color to draw text
|
||||
/// \param[in] colBg: unused in ADAGFX, defaults to black
|
||||
///
|
||||
/// \return true if success, false if failure
|
||||
///
|
||||
bool gslc_DrvDrawTxt(gslc_tsGui* pGui,int16_t nTxtX,int16_t nTxtY,gslc_tsFont* pFont,const char* pStr,gslc_teTxtFlags eTxtFlags,gslc_tsColor colTxt,gslc_tsColor colBg);
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// Screen Management Functions
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
///
|
||||
/// Force a page flip to occur. This generally copies active
|
||||
/// screen surface to the display.
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
///
|
||||
/// \return none
|
||||
///
|
||||
void gslc_DrvPageFlipNow(gslc_tsGui* pGui);
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// Graphics Primitives Functions
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
///
|
||||
/// Draw a point
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] nX: X coordinate of point
|
||||
/// \param[in] nY: Y coordinate of point
|
||||
/// \param[in] nCol: Color RGB value to draw
|
||||
///
|
||||
/// \return true if success, false if error
|
||||
///
|
||||
bool gslc_DrvDrawPoint(gslc_tsGui* pGui,int16_t nX,int16_t nY,gslc_tsColor nCol);
|
||||
|
||||
///
|
||||
/// Draw a point
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] asPt: Array of points to draw
|
||||
/// \param[in] nNumPt: Number of points in array
|
||||
/// \param[in] nCol: Color RGB value to draw
|
||||
///
|
||||
/// \return true if success, false if error
|
||||
///
|
||||
bool gslc_DrvDrawPoints(gslc_tsGui* pGui,gslc_tsPt* asPt,uint16_t nNumPt,gslc_tsColor nCol);
|
||||
|
||||
///
|
||||
/// Draw a framed rectangle
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] rRect: Rectangular region to frame
|
||||
/// \param[in] nCol: Color RGB value to frame
|
||||
///
|
||||
/// \return true if success, false if error
|
||||
///
|
||||
bool gslc_DrvDrawFrameRect(gslc_tsGui* pGui,gslc_tsRect rRect,gslc_tsColor nCol);
|
||||
|
||||
|
||||
///
|
||||
/// Draw a filled rectangle
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] rRect: Rectangular region to fill
|
||||
/// \param[in] nCol: Color RGB value to fill
|
||||
///
|
||||
/// \return true if success, false if error
|
||||
///
|
||||
bool gslc_DrvDrawFillRect(gslc_tsGui* pGui,gslc_tsRect rRect,gslc_tsColor nCol);
|
||||
|
||||
|
||||
///
|
||||
/// Draw a framed rounded rectangle
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] rRect: Rectangular region to frame
|
||||
/// \param[in] nRadius: Radius for rounded corners
|
||||
/// \param[in] nCol: Color RGB value to frame
|
||||
///
|
||||
/// \return true if success, false if error
|
||||
///
|
||||
bool gslc_DrvDrawFrameRoundRect(gslc_tsGui* pGui,gslc_tsRect rRect,int16_t nRadius,gslc_tsColor nCol);
|
||||
|
||||
|
||||
///
|
||||
/// Draw a filled rounded rectangle
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] rRect: Rectangular region to fill
|
||||
/// \param[in] nRadius: Radius for rounded corners
|
||||
/// \param[in] nCol: Color RGB value to fill
|
||||
///
|
||||
/// \return true if success, false if error
|
||||
///
|
||||
bool gslc_DrvDrawFillRoundRect(gslc_tsGui* pGui,gslc_tsRect rRect,int16_t nRadius,gslc_tsColor nCol);
|
||||
|
||||
|
||||
|
||||
///
|
||||
/// Draw a line
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] nX0: Line start (X coordinate)
|
||||
/// \param[in] nY0: Line start (Y coordinate)
|
||||
/// \param[in] nX1: Line finish (X coordinate)
|
||||
/// \param[in] nY1: Line finish (Y coordinate)
|
||||
/// \param[in] nCol: Color RGB value to draw
|
||||
///
|
||||
/// \return true if success, false if error
|
||||
///
|
||||
bool gslc_DrvDrawLine(gslc_tsGui* pGui,int16_t nX0,int16_t nY0,int16_t nX1,int16_t nY1,gslc_tsColor nCol);
|
||||
|
||||
|
||||
///
|
||||
/// Draw a framed circle
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] nMidX: Center of circle (X coordinate)
|
||||
/// \param[in] nMidY: Center of circle (Y coordinate)
|
||||
/// \param[in] nRadius: Radius of circle
|
||||
/// \param[in] nCol: Color RGB value to frame
|
||||
///
|
||||
/// \return true if success, false if error
|
||||
///
|
||||
bool gslc_DrvDrawFrameCircle(gslc_tsGui* pGui,int16_t nMidX,int16_t nMidY,uint16_t nRadius,gslc_tsColor nCol);
|
||||
|
||||
|
||||
///
|
||||
/// Draw a filled circle
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] nMidX: Center of circle (X coordinate)
|
||||
/// \param[in] nMidY: Center of circle (Y coordinate)
|
||||
/// \param[in] nRadius: Radius of circle
|
||||
/// \param[in] nCol: Color RGB value to fill
|
||||
///
|
||||
/// \return true if success, false if error
|
||||
///
|
||||
bool gslc_DrvDrawFillCircle(gslc_tsGui* pGui,int16_t nMidX,int16_t nMidY,uint16_t nRadius,gslc_tsColor nCol);
|
||||
|
||||
|
||||
///
|
||||
/// Draw a framed triangle
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] nX0: X Coordinate #1
|
||||
/// \param[in] nY0: Y Coordinate #1
|
||||
/// \param[in] nX1: X Coordinate #2
|
||||
/// \param[in] nY1: Y Coordinate #2
|
||||
/// \param[in] nX2: X Coordinate #3
|
||||
/// \param[in] nY2: Y Coordinate #3
|
||||
/// \param[in] nCol: Color RGB value to frame
|
||||
///
|
||||
/// \return true if success, false if error
|
||||
///
|
||||
bool gslc_DrvDrawFrameTriangle(gslc_tsGui* pGui,int16_t nX0,int16_t nY0,
|
||||
int16_t nX1,int16_t nY1,int16_t nX2,int16_t nY2,gslc_tsColor nCol);
|
||||
|
||||
|
||||
///
|
||||
/// Draw a filled triangle
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] nX0: X Coordinate #1
|
||||
/// \param[in] nY0: Y Coordinate #1
|
||||
/// \param[in] nX1: X Coordinate #2
|
||||
/// \param[in] nY1: Y Coordinate #2
|
||||
/// \param[in] nX2: X Coordinate #3
|
||||
/// \param[in] nY2: Y Coordinate #3
|
||||
/// \param[in] nCol: Color RGB value to fill
|
||||
///
|
||||
/// \return true if success, false if error
|
||||
///
|
||||
bool gslc_DrvDrawFillTriangle(gslc_tsGui* pGui,int16_t nX0,int16_t nY0,
|
||||
int16_t nX1,int16_t nY1,int16_t nX2,int16_t nY2,gslc_tsColor nCol);
|
||||
|
||||
|
||||
///
|
||||
/// Copy all of source image to destination screen at specified coordinate
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] nDstX: Destination X coord for copy
|
||||
/// \param[in] nDstY: Destination Y coord for copy
|
||||
/// \param[in] sImgRef: Image reference
|
||||
///
|
||||
/// \return true if success, false if fail
|
||||
///
|
||||
bool gslc_DrvDrawImage(gslc_tsGui* pGui,int16_t nDstX,int16_t nDstY,gslc_tsImgRef sImgRef);
|
||||
|
||||
|
||||
///
|
||||
/// Draw a monochrome bitmap from a memory array
|
||||
/// - Draw from the bitmap buffer using the foreground color
|
||||
/// defined in the header (unset bits are transparent)
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] nDstX: Destination X coord for copy
|
||||
/// \param[in] nDstY: Destination Y coord for copy
|
||||
/// \param[in] pBitmap: Pointer to bitmap buffer
|
||||
/// \param[in] bProgMem: Bitmap is stored in Flash if true, RAM otherwise
|
||||
///
|
||||
/// \return none
|
||||
///
|
||||
void gslc_DrvDrawMonoFromMem(gslc_tsGui* pGui,int16_t nDstX, int16_t nDstY, const unsigned char *pBitmap,bool bProgMem);
|
||||
|
||||
|
||||
///
|
||||
/// Draw a color 24-bit depth bitmap from a memory array
|
||||
/// - Note that users must convert images from their native
|
||||
/// format (eg. BMP, PNG, etc.) into a C array. Please
|
||||
/// refer to the following guide for details:
|
||||
/// https://github.com/ImpulseAdventure/GUIslice/wiki/Display-Images-from-FLASH
|
||||
/// - The converted file (c array) can then be included in the sketch.
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] nDstX: X coord for copy
|
||||
/// \param[in] nDstY: Y coord for copy
|
||||
/// \param[in] pBitmap: Pointer to bitmap buffer
|
||||
/// \param[in] bProgMem: Bitmap is stored in Flash if true, RAM otherwise
|
||||
///
|
||||
/// \return none
|
||||
///
|
||||
void gslc_DrvDrawBmp24FromMem(gslc_tsGui* pGui,int16_t nDstX, int16_t nDstY,const unsigned char* pBitmap,bool bProgMem);
|
||||
|
||||
///
|
||||
/// Copy the background image to destination screen
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
///
|
||||
/// \return true if success, false if fail
|
||||
///
|
||||
void gslc_DrvDrawBkgnd(gslc_tsGui* pGui);
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// Touch Functions (if using display driver library)
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
///
|
||||
/// Perform any touchscreen-specific initialization
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] acDev: Device path to touchscreen
|
||||
/// eg. "/dev/input/touchscreen"
|
||||
///
|
||||
/// \return true if successful
|
||||
///
|
||||
bool gslc_DrvInitTouch(gslc_tsGui* pGui,const char* acDev);
|
||||
|
||||
|
||||
///
|
||||
/// Get the last touch event from the internal touch handler
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[out] pnX: Ptr to X coordinate of last touch event
|
||||
/// \param[out] pnY: Ptr to Y coordinate of last touch event
|
||||
/// \param[out] pnPress: Ptr to Pressure level of last touch event (0 for none, 1 for touch)
|
||||
/// \param[out] peInputEvent Indication of event type
|
||||
/// \param[out] pnInputVal Additional data for event type
|
||||
///
|
||||
/// \return true if an event was detected or false otherwise
|
||||
///
|
||||
bool gslc_DrvGetTouch(gslc_tsGui* pGui,int16_t* pnX,int16_t* pnY,uint16_t* pnPress,gslc_teInputRawEvent* peInputEvent,int16_t* pnInputVal);
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// Touch Functions (if using external touch driver library)
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
// Check for deprecated config option
|
||||
// - This check will be removed in future releases
|
||||
#if defined(DRV_TOUCH_XPT2046)
|
||||
#error "NOTE: DRV_TOUCH_XPT2046 has been renamed to DRV_TOUCH_XPT2046_STM. Please update your config."
|
||||
#endif
|
||||
|
||||
#if defined(DRV_TOUCH_TYPE_EXTERNAL)
|
||||
///
|
||||
/// Perform any touchscreen-specific initialization
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] acDev: Device path to touchscreen
|
||||
/// eg. "/dev/input/touchscreen"
|
||||
///
|
||||
/// \return true if successful
|
||||
///
|
||||
bool gslc_TDrvInitTouch(gslc_tsGui* pGui,const char* acDev);
|
||||
|
||||
|
||||
///
|
||||
/// Get the last touch event from the SDL_Event handler
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[out] pnX: Ptr to X coordinate of last touch event
|
||||
/// \param[out] pnY: Ptr to Y coordinate of last touch event
|
||||
/// \param[out] pnPress: Ptr to Pressure level of last touch event (0 for none, 1 for touch)
|
||||
/// \param[out] peInputEvent Indication of event type
|
||||
/// \param[out] pnInputVal Additional data for event type
|
||||
///
|
||||
/// \return true if an event was detected or false otherwise
|
||||
///
|
||||
bool gslc_TDrvGetTouch(gslc_tsGui* pGui, int16_t* pnX, int16_t* pnY, uint16_t* pnPress, gslc_teInputRawEvent* peInputEvent, int16_t* pnInputVal);
|
||||
|
||||
#endif // DRV_TOUCH_*
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// Dynamic Screen rotation and Touch axes swap/flip functions
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
///
|
||||
/// Change rotation, automatically adapt touchscreen axes swap/flip
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] nRotation: Screen Rotation value (0, 1, 2 or 3)
|
||||
///
|
||||
/// \return true if successful
|
||||
///
|
||||
bool gslc_DrvRotate(gslc_tsGui* pGui, uint8_t nRotation);
|
||||
|
||||
|
||||
// =======================================================================
|
||||
// Private Functions
|
||||
// - These functions are not included in the scope of APIs used by
|
||||
// the core GUIslice library. Instead, these functions are used
|
||||
// to support the operations within this driver layer.
|
||||
// =======================================================================
|
||||
|
||||
uint16_t gslc_DrvAdaptColorToRaw(gslc_tsColor nCol);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif // __cplusplus
|
||||
#endif // _GUISLICE_DRV_ADAGFX_H_
|
1071
src/guislice/GUIslice_drv_m5stack.cpp
Normal file
1071
src/guislice/GUIslice_drv_m5stack.cpp
Normal file
File diff suppressed because it is too large
Load diff
656
src/guislice/GUIslice_drv_m5stack.h
Normal file
656
src/guislice/GUIslice_drv_m5stack.h
Normal file
|
@ -0,0 +1,656 @@
|
|||
#ifndef _GUISLICE_DRV_M5STACK_H_
|
||||
#define _GUISLICE_DRV_M5STACK_H_
|
||||
|
||||
// =======================================================================
|
||||
// GUIslice library (driver layer for m5stack/M5Stack)
|
||||
// - Calvin Hass
|
||||
// - https://www.impulseadventure.com/elec/guislice-gui.html
|
||||
// - https://github.com/ImpulseAdventure/GUIslice
|
||||
// =======================================================================
|
||||
//
|
||||
// The MIT License
|
||||
//
|
||||
// Copyright 2016-2020 Calvin Hass
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
//
|
||||
// =======================================================================
|
||||
/// \file GUIslice_drv_m5stack.h
|
||||
/// \brief GUIslice library (driver layer for M5stack)
|
||||
|
||||
|
||||
// =======================================================================
|
||||
// Driver Layer for m5stack/M5Stack
|
||||
// - https://github.com/m5stack/M5Stack
|
||||
// =======================================================================
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif // __cplusplus
|
||||
|
||||
#include "GUIslice.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Error Strings
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
extern const char GSLC_PMEM ERRSTR_NULL[];
|
||||
extern const char GSLC_PMEM ERRSTR_PXD_NULL[];
|
||||
|
||||
|
||||
|
||||
// =======================================================================
|
||||
// API support definitions
|
||||
// - These defines indicate whether the driver includes optimized
|
||||
// support for various APIs. If a define is set to 0, then the
|
||||
// GUIslice core emulation will be used instead.
|
||||
// - At the very minimum, the point draw routine must be available:
|
||||
// gslc_DrvDrawPoint()
|
||||
// =======================================================================
|
||||
|
||||
#define DRV_HAS_DRAW_POINT 1 ///< Support gslc_DrvDrawPoint()
|
||||
|
||||
#define DRV_HAS_DRAW_POINTS 0 ///< Support gslc_DrvDrawPoints()
|
||||
#define DRV_HAS_DRAW_LINE 1 ///< Support gslc_DrvDrawLine()
|
||||
#define DRV_HAS_DRAW_RECT_FRAME 1 ///< Support gslc_DrvDrawFrameRect()
|
||||
#define DRV_HAS_DRAW_RECT_FILL 1 ///< Support gslc_DrvDrawFillRect()
|
||||
#define DRV_HAS_DRAW_RECT_ROUND_FRAME 1 ///< Support gslc_DrvDrawFrameRoundRect()
|
||||
#define DRV_HAS_DRAW_RECT_ROUND_FILL 1 ///< Support gslc_DrvDrawFillRoundRect()
|
||||
#define DRV_HAS_DRAW_CIRCLE_FRAME 1 ///< Support gslc_DrvDrawFrameCircle()
|
||||
#define DRV_HAS_DRAW_CIRCLE_FILL 1 ///< Support gslc_DrvDrawFillCircle()
|
||||
#define DRV_HAS_DRAW_TRI_FRAME 1 ///< Support gslc_DrvDrawFrameTriangle()
|
||||
#define DRV_HAS_DRAW_TRI_FILL 1 ///< Support gslc_DrvDrawFillTriangle()
|
||||
#define DRV_HAS_DRAW_TEXT 1 ///< Support gslc_DrvDrawTxt()
|
||||
#define DRV_HAS_DRAW_BMP_MEM 0 ///< Support gslc_DrvDrawBmp24FromMem()
|
||||
|
||||
#define DRV_OVERRIDE_TXT_ALIGN 1 ///< Driver provides text alignment
|
||||
|
||||
// =======================================================================
|
||||
// Driver-specific members
|
||||
// =======================================================================
|
||||
typedef struct {
|
||||
gslc_tsColor nColBkgnd; ///< Background color (if not image-based)
|
||||
|
||||
gslc_tsRect rClipRect; ///< Clipping rectangle
|
||||
|
||||
} gslc_tsDriver;
|
||||
|
||||
|
||||
|
||||
// =======================================================================
|
||||
// Public APIs to GUIslice core library
|
||||
// - These functions define the renderer / driver-dependent
|
||||
// implementations for the core drawing operations within
|
||||
// GUIslice.
|
||||
// =======================================================================
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// Configuration Functions
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
///
|
||||
/// Initialize the SDL library
|
||||
/// - Performs clean startup workaround (if enabled)
|
||||
/// - Configures video mode
|
||||
/// - Initializes font support
|
||||
///
|
||||
/// PRE:
|
||||
/// - The environment variables should be configured before
|
||||
/// calling gslc_DrvInit(). This can be done with gslc_DrvInitEnv()
|
||||
/// or manually in user function.
|
||||
///
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
///
|
||||
/// \return true if success, false if fail
|
||||
///
|
||||
bool gslc_DrvInit(gslc_tsGui* pGui);
|
||||
|
||||
|
||||
///
|
||||
/// Perform any touchscreen-specific initialization
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] acDev: Device path to touchscreen
|
||||
/// eg. "/dev/input/touchscreen"
|
||||
///
|
||||
/// \return true if successful
|
||||
///
|
||||
bool gslc_DrvInitTs(gslc_tsGui* pGui,const char* acDev);
|
||||
|
||||
|
||||
///
|
||||
/// Free up any members associated with the driver
|
||||
/// - Eg. renderers, windows, background surfaces, etc.
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
///
|
||||
/// \return none
|
||||
///
|
||||
void gslc_DrvDestruct(gslc_tsGui* pGui);
|
||||
|
||||
|
||||
///
|
||||
/// Get the display driver name
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
///
|
||||
/// \return String containing driver name
|
||||
///
|
||||
const char* gslc_DrvGetNameDisp(gslc_tsGui* pGui);
|
||||
|
||||
|
||||
///
|
||||
/// Get the touch driver name
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
///
|
||||
/// \return String containing driver name
|
||||
///
|
||||
const char* gslc_DrvGetNameTouch(gslc_tsGui* pGui);
|
||||
|
||||
///
|
||||
/// Get the native display driver instance
|
||||
/// - This can be useful to access special commands
|
||||
/// available in the selected driver.
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
///
|
||||
/// \return Void pointer to the display driver instance.
|
||||
/// This pointer should be typecast to the particular
|
||||
/// driver being used. If no driver was created then
|
||||
/// this function will return NULL.
|
||||
///
|
||||
void* gslc_DrvGetDriverDisp(gslc_tsGui* pGui);
|
||||
|
||||
///
|
||||
/// Get the native touch driver instance
|
||||
/// - This can be useful to access special commands
|
||||
/// available in the selected driver.
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
///
|
||||
/// \return Void pointer to the touch driver instance.
|
||||
/// This pointer should be typecast to the particular
|
||||
/// driver being used. If no driver was created then
|
||||
/// this function will return NULL.
|
||||
///
|
||||
void* gslc_DrvGetDriverTouch(gslc_tsGui* pGui);
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// Image/surface handling Functions
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
|
||||
///
|
||||
/// Load a bitmap (*.bmp) and create a new image resource.
|
||||
/// Transparency is enabled by GSLC_BMP_TRANS_EN
|
||||
/// through use of color (GSLC_BMP_TRANS_RGB).
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] sImgRef: Image reference
|
||||
///
|
||||
/// \return Image pointer (surface/texture) or NULL if error
|
||||
///
|
||||
void* gslc_DrvLoadImage(gslc_tsGui* pGui,gslc_tsImgRef sImgRef);
|
||||
|
||||
|
||||
///
|
||||
/// Configure the background to use a bitmap image
|
||||
/// - The background is used when redrawing the entire page
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] sImgRef: Image reference
|
||||
///
|
||||
/// \return true if success, false if fail
|
||||
///
|
||||
bool gslc_DrvSetBkgndImage(gslc_tsGui* pGui,gslc_tsImgRef sImgRef);
|
||||
|
||||
///
|
||||
/// Configure the background to use a solid color
|
||||
/// - The background is used when redrawing the entire page
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] nCol: RGB Color to use
|
||||
///
|
||||
/// \return true if success, false if fail
|
||||
///
|
||||
bool gslc_DrvSetBkgndColor(gslc_tsGui* pGui,gslc_tsColor nCol);
|
||||
|
||||
///
|
||||
/// Set an element's normal-state image
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] pElem: Pointer to Element to update
|
||||
/// \param[in] sImgRef: Image reference
|
||||
///
|
||||
/// \return true if success, false if error
|
||||
///
|
||||
bool gslc_DrvSetElemImageNorm(gslc_tsGui* pGui,gslc_tsElem* pElem,gslc_tsImgRef sImgRef);
|
||||
|
||||
///
|
||||
/// Set an element's glow-state image
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] pElem: Pointer to Element to update
|
||||
/// \param[in] sImgRef: Image reference
|
||||
///
|
||||
/// \return true if success, false if error
|
||||
///
|
||||
bool gslc_DrvSetElemImageGlow(gslc_tsGui* pGui,gslc_tsElem* pElem,gslc_tsImgRef sImgRef);
|
||||
|
||||
|
||||
///
|
||||
/// Release an image surface
|
||||
///
|
||||
/// \param[in] pvImg: Void ptr to image
|
||||
///
|
||||
/// \return none
|
||||
///
|
||||
void gslc_DrvImageDestruct(void* pvImg);
|
||||
|
||||
|
||||
///
|
||||
/// Set the clipping rectangle for future drawing updates
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] pRect: Rectangular region to constrain edits
|
||||
///
|
||||
/// \return true if success, false if error
|
||||
///
|
||||
bool gslc_DrvSetClipRect(gslc_tsGui* pGui,gslc_tsRect* pRect);
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// Font handling Functions
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
///
|
||||
/// Load a font from a resource and return pointer to it
|
||||
///
|
||||
/// \param[in] eFontRefType: Font reference type (GSLC_FONTREF_PTR for Arduino)
|
||||
/// \param[in] pvFontRef: Font reference pointer (Pointer to the GFXFont array)
|
||||
/// \param[in] nFontSz: Typeface size to use
|
||||
///
|
||||
/// \return Void ptr to driver-specific font if load was successful, NULL otherwise
|
||||
///
|
||||
const void* gslc_DrvFontAdd(gslc_teFontRefType eFontRefType,const void* pvFontRef,uint16_t nFontSz);
|
||||
|
||||
///
|
||||
/// Release all fonts defined in the GUI
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
///
|
||||
/// \return none
|
||||
///
|
||||
void gslc_DrvFontsDestruct(gslc_tsGui* pGui);
|
||||
|
||||
|
||||
///
|
||||
/// Get the extent (width and height) of a text string
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] pFont: Ptr to Font structure
|
||||
/// \param[in] pStr: String to display
|
||||
/// \param[in] eTxtFlags: Flags associated with text string
|
||||
/// \param[out] pnTxtX: Ptr to offset X of text
|
||||
/// \param[out] pnTxtY: Ptr to offset Y of text
|
||||
/// \param[out] pnTxtSzW: Ptr to width of text
|
||||
/// \param[out] pnTxtSzH: Ptr to height of text
|
||||
///
|
||||
/// \return true if success, false if failure
|
||||
///
|
||||
bool gslc_DrvGetTxtSize(gslc_tsGui* pGui,gslc_tsFont* pFont,const char* pStr,gslc_teTxtFlags eTxtFlags,
|
||||
int16_t* pnTxtX,int16_t* pnTxtY,uint16_t* pnTxtSzW,uint16_t* pnTxtSzH);
|
||||
|
||||
|
||||
///
|
||||
/// Draw a text string at the given coordinate
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] nTxtX: X coordinate of top-left text string
|
||||
/// \param[in] nTxtY: Y coordinate of top-left text string
|
||||
/// \param[in] pFont: Ptr to Font
|
||||
/// \param[in] pStr: String to display
|
||||
/// \param[in] eTxtFlags: Flags associated with text string
|
||||
/// \param[in] colTxt: Color to draw text
|
||||
/// \param[in] colBg: unused in m5stack, defaults to black
|
||||
///
|
||||
/// \return true if success, false if failure
|
||||
///
|
||||
bool gslc_DrvDrawTxt(gslc_tsGui* pGui,int16_t nTxtX,int16_t nTxtY,gslc_tsFont* pFont,const char* pStr,gslc_teTxtFlags eTxtFlags,gslc_tsColor colTxt,gslc_tsColor colBg);
|
||||
|
||||
///
|
||||
/// Draw a text string in a bounding box using the specified alignment
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] nX0: X coordinate of top-left of bounding box
|
||||
/// \param[in] nY0: Y coordinate of top-left of bounding box
|
||||
/// \param[in] nX1: X coordinate of bot-right of bounding box
|
||||
/// \param[in] nY1: Y coordinate of bot-right of bounding box
|
||||
/// \param[in] eTxtAlign: Alignment mode]
|
||||
/// \param[in] pFont: Ptr to Font
|
||||
/// \param[in] pStr: String to display
|
||||
/// \param[in] eTxtFlags: Flags associated with text string
|
||||
/// \param[in] colTxt: Color to draw text
|
||||
/// \param[in] colBg: unused in m5stack, defaults to black
|
||||
///
|
||||
/// \return true if success, false if failure
|
||||
///
|
||||
bool gslc_DrvDrawTxtAlign(gslc_tsGui* pGui,int16_t nX0,int16_t nY0,int16_t nX1,int16_t nY1,int8_t eTxtAlign,
|
||||
gslc_tsFont* pFont,const char* pStr,gslc_teTxtFlags eTxtFlags,gslc_tsColor colTxt,gslc_tsColor colBg);
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// Screen Management Functions
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
///
|
||||
/// Force a page flip to occur. This generally copies active
|
||||
/// screen surface to the display.
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
///
|
||||
/// \return none
|
||||
///
|
||||
void gslc_DrvPageFlipNow(gslc_tsGui* pGui);
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// Graphics Primitives Functions
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
///
|
||||
/// Draw a point
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] nX: X coordinate of point
|
||||
/// \param[in] nY: Y coordinate of point
|
||||
/// \param[in] nCol: Color RGB value to draw
|
||||
///
|
||||
/// \return true if success, false if error
|
||||
///
|
||||
bool gslc_DrvDrawPoint(gslc_tsGui* pGui,int16_t nX,int16_t nY,gslc_tsColor nCol);
|
||||
|
||||
///
|
||||
/// Draw a point
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] asPt: Array of points to draw
|
||||
/// \param[in] nNumPt: Number of points in array
|
||||
/// \param[in] nCol: Color RGB value to draw
|
||||
///
|
||||
/// \return true if success, false if error
|
||||
///
|
||||
bool gslc_DrvDrawPoints(gslc_tsGui* pGui,gslc_tsPt* asPt,uint16_t nNumPt,gslc_tsColor nCol);
|
||||
|
||||
///
|
||||
/// Draw a framed rectangle
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] rRect: Rectangular region to frame
|
||||
/// \param[in] nCol: Color RGB value to frame
|
||||
///
|
||||
/// \return true if success, false if error
|
||||
///
|
||||
bool gslc_DrvDrawFrameRect(gslc_tsGui* pGui,gslc_tsRect rRect,gslc_tsColor nCol);
|
||||
|
||||
|
||||
///
|
||||
/// Draw a filled rectangle
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] rRect: Rectangular region to fill
|
||||
/// \param[in] nCol: Color RGB value to fill
|
||||
///
|
||||
/// \return true if success, false if error
|
||||
///
|
||||
bool gslc_DrvDrawFillRect(gslc_tsGui* pGui,gslc_tsRect rRect,gslc_tsColor nCol);
|
||||
|
||||
|
||||
///
|
||||
/// Draw a framed rounded rectangle
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] rRect: Rectangular region to frame
|
||||
/// \param[in] nRadius: Radius for rounded corners
|
||||
/// \param[in] nCol: Color RGB value to frame
|
||||
///
|
||||
/// \return true if success, false if error
|
||||
///
|
||||
bool gslc_DrvDrawFrameRoundRect(gslc_tsGui* pGui,gslc_tsRect rRect,int16_t nRadius,gslc_tsColor nCol);
|
||||
|
||||
|
||||
///
|
||||
/// Draw a filled rounded rectangle
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] rRect: Rectangular region to fill
|
||||
/// \param[in] nRadius: Radius for rounded corners
|
||||
/// \param[in] nCol: Color RGB value to fill
|
||||
///
|
||||
/// \return true if success, false if error
|
||||
///
|
||||
bool gslc_DrvDrawFillRoundRect(gslc_tsGui* pGui,gslc_tsRect rRect,int16_t nRadius,gslc_tsColor nCol);
|
||||
|
||||
|
||||
|
||||
///
|
||||
/// Draw a line
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] nX0: Line start (X coordinate)
|
||||
/// \param[in] nY0: Line start (Y coordinate)
|
||||
/// \param[in] nX1: Line finish (X coordinate)
|
||||
/// \param[in] nY1: Line finish (Y coordinate)
|
||||
/// \param[in] nCol: Color RGB value to draw
|
||||
///
|
||||
/// \return true if success, false if error
|
||||
///
|
||||
bool gslc_DrvDrawLine(gslc_tsGui* pGui,int16_t nX0,int16_t nY0,int16_t nX1,int16_t nY1,gslc_tsColor nCol);
|
||||
|
||||
|
||||
///
|
||||
/// Draw a framed circle
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] nMidX: Center of circle (X coordinate)
|
||||
/// \param[in] nMidY: Center of circle (Y coordinate)
|
||||
/// \param[in] nRadius: Radius of circle
|
||||
/// \param[in] nCol: Color RGB value to frame
|
||||
///
|
||||
/// \return true if success, false if error
|
||||
///
|
||||
bool gslc_DrvDrawFrameCircle(gslc_tsGui* pGui,int16_t nMidX,int16_t nMidY,uint16_t nRadius,gslc_tsColor nCol);
|
||||
|
||||
|
||||
///
|
||||
/// Draw a filled circle
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] nMidX: Center of circle (X coordinate)
|
||||
/// \param[in] nMidY: Center of circle (Y coordinate)
|
||||
/// \param[in] nRadius: Radius of circle
|
||||
/// \param[in] nCol: Color RGB value to fill
|
||||
///
|
||||
/// \return true if success, false if error
|
||||
///
|
||||
bool gslc_DrvDrawFillCircle(gslc_tsGui* pGui,int16_t nMidX,int16_t nMidY,uint16_t nRadius,gslc_tsColor nCol);
|
||||
|
||||
|
||||
///
|
||||
/// Draw a framed triangle
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] nX0: X Coordinate #1
|
||||
/// \param[in] nY0: Y Coordinate #1
|
||||
/// \param[in] nX1: X Coordinate #2
|
||||
/// \param[in] nY1: Y Coordinate #2
|
||||
/// \param[in] nX2: X Coordinate #3
|
||||
/// \param[in] nY2: Y Coordinate #3
|
||||
/// \param[in] nCol: Color RGB value to frame
|
||||
///
|
||||
/// \return true if success, false if error
|
||||
///
|
||||
bool gslc_DrvDrawFrameTriangle(gslc_tsGui* pGui,int16_t nX0,int16_t nY0,
|
||||
int16_t nX1,int16_t nY1,int16_t nX2,int16_t nY2,gslc_tsColor nCol);
|
||||
|
||||
|
||||
///
|
||||
/// Draw a filled triangle
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] nX0: X Coordinate #1
|
||||
/// \param[in] nY0: Y Coordinate #1
|
||||
/// \param[in] nX1: X Coordinate #2
|
||||
/// \param[in] nY1: Y Coordinate #2
|
||||
/// \param[in] nX2: X Coordinate #3
|
||||
/// \param[in] nY2: Y Coordinate #3
|
||||
/// \param[in] nCol: Color RGB value to fill
|
||||
///
|
||||
/// \return true if success, false if error
|
||||
///
|
||||
bool gslc_DrvDrawFillTriangle(gslc_tsGui* pGui,int16_t nX0,int16_t nY0,
|
||||
int16_t nX1,int16_t nY1,int16_t nX2,int16_t nY2,gslc_tsColor nCol);
|
||||
|
||||
|
||||
///
|
||||
/// Copy all of source image to destination screen at specified coordinate
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] nDstX: Destination X coord for copy
|
||||
/// \param[in] nDstY: Destination Y coord for copy
|
||||
/// \param[in] sImgRef: Image reference
|
||||
///
|
||||
/// \return true if success, false if fail
|
||||
///
|
||||
bool gslc_DrvDrawImage(gslc_tsGui* pGui,int16_t nDstX,int16_t nDstY,gslc_tsImgRef sImgRef);
|
||||
|
||||
|
||||
///
|
||||
/// Draw a monochrome bitmap from a memory array
|
||||
/// - Draw from the bitmap buffer using the foreground color
|
||||
/// defined in the header (unset bits are transparent)
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] nDstX: Destination X coord for copy
|
||||
/// \param[in] nDstY: Destination Y coord for copy
|
||||
/// \param[in] pBitmap: Pointer to bitmap buffer
|
||||
/// \param[in] bProgMem: Bitmap is stored in Flash if true, RAM otherwise
|
||||
///
|
||||
/// \return none
|
||||
///
|
||||
void gslc_DrvDrawMonoFromMem(gslc_tsGui* pGui,int16_t nDstX, int16_t nDstY, const unsigned char *pBitmap,bool bProgMem);
|
||||
|
||||
///
|
||||
/// Draw a color 24-bit depth bitmap from a memory array
|
||||
/// - Note that users must convert images from their native
|
||||
/// format (eg. BMP, PNG, etc.) into a C array. Please
|
||||
/// refer to the following guide for details:
|
||||
/// https://github.com/ImpulseAdventure/GUIslice/wiki/Display-Images-from-FLASH
|
||||
/// - The converted file (c array) can then be included in the sketch.
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] nDstX: X coord for copy
|
||||
/// \param[in] nDstY: Y coord for copy
|
||||
/// \param[in] pBitmap: Pointer to bitmap buffer
|
||||
/// \param[in] bProgMem: Bitmap is stored in Flash if true, RAM otherwise
|
||||
///
|
||||
/// \return none
|
||||
///
|
||||
void gslc_DrvDrawBmp24FromMem(gslc_tsGui* pGui,int16_t nDstX, int16_t nDstY,const unsigned char* pBitmap,bool bProgMem);
|
||||
|
||||
///
|
||||
/// Copy the background image to destination screen
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
///
|
||||
/// \return true if success, false if fail
|
||||
///
|
||||
void gslc_DrvDrawBkgnd(gslc_tsGui* pGui);
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// Touch Functions (if using display driver library)
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
#if defined(DRV_TOUCH_IN_DISP)
|
||||
// Use M5stack's integrated button handler
|
||||
|
||||
///
|
||||
/// Perform any touch-specific initialization
|
||||
/// - This function doesn't do anything in M5stack
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] acDev: Device path to touchscreen
|
||||
/// eg. "/dev/input/touchscreen"
|
||||
///
|
||||
/// \return true if successful
|
||||
///
|
||||
bool gslc_DrvInitTouch(gslc_tsGui* pGui,const char* acDev);
|
||||
|
||||
|
||||
///
|
||||
/// Get the last touch event from the internal button handler
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[out] pnX: Ptr to X coordinate of last touch event (UNUSED)
|
||||
/// \param[out] pnY: Ptr to Y coordinate of last touch event (UNUSED)
|
||||
/// \param[out] pnPress: Ptr to Pressure level of last touch event (0 for none, 1 for touch) (UNUSED)
|
||||
/// \param[out] peInputEvent Indication of event type
|
||||
/// \param[out] pnInputVal Additional data for event type
|
||||
///
|
||||
/// \return true if an event was detected or false otherwise
|
||||
///
|
||||
bool gslc_DrvGetTouch(gslc_tsGui* pGui,int16_t* pnX,int16_t* pnY,uint16_t* pnPress,gslc_teInputRawEvent* peInputEvent,int16_t* pnInputVal);
|
||||
|
||||
#endif // DRV_TOUCH_IN_DISP
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// Dynamic Screen rotation and Touch axes swap/flip functions
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
///
|
||||
/// Change rotation, automatically adapt touchscreen axes swap/flip
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] nRotation: Screen Rotation value (0, 1, 2 or 3)
|
||||
///
|
||||
/// \return true if successful
|
||||
///
|
||||
bool gslc_DrvRotate(gslc_tsGui* pGui, uint8_t nRotation);
|
||||
|
||||
|
||||
// =======================================================================
|
||||
// Private Functions
|
||||
// - These functions are not included in the scope of APIs used by
|
||||
// the core GUIslice library. Instead, these functions are used
|
||||
// to support the operations within this driver layer.
|
||||
// =======================================================================
|
||||
|
||||
uint16_t gslc_DrvAdaptColorToRaw(gslc_tsColor nCol);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif // __cplusplus
|
||||
#endif // _GUISLICE_DRV_M5STACK_H_
|
1470
src/guislice/GUIslice_drv_sdl.c
Normal file
1470
src/guislice/GUIslice_drv_sdl.c
Normal file
File diff suppressed because it is too large
Load diff
722
src/guislice/GUIslice_drv_sdl.h
Normal file
722
src/guislice/GUIslice_drv_sdl.h
Normal file
|
@ -0,0 +1,722 @@
|
|||
#ifndef _GUISLICE_DRV_SDL_H_
|
||||
#define _GUISLICE_DRV_SDL_H_
|
||||
|
||||
// =======================================================================
|
||||
// GUIslice library (driver layer for SDL 1.2 & 2.0)
|
||||
// - Calvin Hass
|
||||
// - https://www.impulseadventure.com/elec/guislice-gui.html
|
||||
// - https://github.com/ImpulseAdventure/GUIslice
|
||||
// =======================================================================
|
||||
//
|
||||
// The MIT License
|
||||
//
|
||||
// Copyright 2016-2020 Calvin Hass
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
//
|
||||
// =======================================================================
|
||||
/// \file GUIslice_drv_sdl.h
|
||||
/// \brief GUIslice library (driver layer for LINUX / SDL)
|
||||
|
||||
|
||||
// =======================================================================
|
||||
// Driver Layer for SDL
|
||||
// =======================================================================
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif // __cplusplus
|
||||
|
||||
#include "GUIslice.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#if defined(DRV_DISP_SDL1)
|
||||
#include <SDL/SDL.h>
|
||||
#include <SDL/SDL_getenv.h>
|
||||
#include <SDL/SDL_ttf.h>
|
||||
#endif
|
||||
#if defined(DRV_DISP_SDL2)
|
||||
#include <SDL2/SDL.h>
|
||||
#include <SDL2/SDL_ttf.h>
|
||||
#endif
|
||||
|
||||
// Includes for optional tslib touch handling
|
||||
#if defined(DRV_TOUCH_TSLIB)
|
||||
#include "tslib.h"
|
||||
#endif
|
||||
|
||||
// =======================================================================
|
||||
// API support definitions
|
||||
// - These defines indicate whether the driver includes optimized
|
||||
// support for various APIs. If a define is set to 0, then the
|
||||
// GUIslice core emulation will be used instead.
|
||||
// - At the very minimum, the point draw routine must be available:
|
||||
// gslc_DrvDrawPoint()
|
||||
// =======================================================================
|
||||
|
||||
#define DRV_HAS_DRAW_POINT 1 ///< Support gslc_DrvDrawPoint()
|
||||
|
||||
#if defined(DRV_DISP_SDL1)
|
||||
#define DRV_HAS_DRAW_POINTS 1 ///< Support gslc_DrvDrawPoints()
|
||||
#define DRV_HAS_DRAW_LINE 0 ///< Support gslc_DrvDrawLine()
|
||||
#define DRV_HAS_DRAW_RECT_FRAME 0 ///< Support gslc_DrvDrawFrameRect()
|
||||
#define DRV_HAS_DRAW_RECT_FILL 1 ///< Support gslc_DrvDrawFillRect()
|
||||
#define DRV_HAS_DRAW_RECT_ROUND_FRAME 0 ///< Support gslc_DrvDrawFrameRoundRect()
|
||||
#define DRV_HAS_DRAW_RECT_ROUND_FILL 0 ///< Support gslc_DrvDrawFillRoundRect()
|
||||
#define DRV_HAS_DRAW_CIRCLE_FRAME 0 ///< Support gslc_DrvDrawFrameCircle()
|
||||
#define DRV_HAS_DRAW_CIRCLE_FILL 0 ///< Support gslc_DrvDrawFillCircle()
|
||||
#define DRV_HAS_DRAW_TRI_FRAME 0 ///< Support gslc_DrvDrawFrameTriangle()
|
||||
#define DRV_HAS_DRAW_TRI_FILL 0 ///< Support gslc_DrvDrawFillTriangle()
|
||||
#define DRV_HAS_DRAW_TEXT 1 ///< Support gslc_DrvDrawTxt()
|
||||
#define DRV_HAS_DRAW_BMP_MEM 0 ///< Support gslc_DrvDrawBmp24FromMem()
|
||||
#endif
|
||||
|
||||
#if defined(DRV_DISP_SDL2)
|
||||
#define DRV_HAS_DRAW_POINTS 1 ///< Support gslc_DrvDrawPoints()
|
||||
#define DRV_HAS_DRAW_LINE 1 ///< Support gslc_DrvDrawLine()
|
||||
#define DRV_HAS_DRAW_RECT_FRAME 1 ///< Support gslc_DrvDrawFrameRect()
|
||||
#define DRV_HAS_DRAW_RECT_FILL 1 ///< Support gslc_DrvDrawFillRect()
|
||||
#define DRV_HAS_DRAW_RECT_ROUND_FRAME 0 ///< Support gslc_DrvDrawFrameRoundRect()
|
||||
#define DRV_HAS_DRAW_RECT_ROUND_FILL 0 ///< Support gslc_DrvDrawFillRoundRect()
|
||||
#define DRV_HAS_DRAW_CIRCLE_FRAME 0 ///< Support gslc_DrvDrawFrameCircle()
|
||||
#define DRV_HAS_DRAW_CIRCLE_FILL 0 ///< Support gslc_DrvDrawFillCircle()
|
||||
#define DRV_HAS_DRAW_TRI_FRAME 0 ///< Support gslc_DrvDrawFrameTriangle()
|
||||
#define DRV_HAS_DRAW_TRI_FILL 0 ///< Support gslc_DrvDrawFillTriangle()
|
||||
#define DRV_HAS_DRAW_TEXT 1 ///< Support gslc_DrvDrawTxt()
|
||||
#define DRV_HAS_DRAW_BMP_MEM 0 ///< Support gslc_DrvDrawBmp24FromMem()
|
||||
#endif
|
||||
|
||||
#define DRV_OVERRIDE_TXT_ALIGN 0 ///< Driver provides text alignment
|
||||
|
||||
// =======================================================================
|
||||
// Driver-specific members
|
||||
// =======================================================================
|
||||
typedef struct {
|
||||
|
||||
#if defined(DRV_DISP_SDL1)
|
||||
SDL_Surface* pSurfScreen; ///< Surface ptr for screen
|
||||
#endif
|
||||
|
||||
#if defined(DRV_DISP_SDL2)
|
||||
SDL_Window* pWind; ///< SDL2 Window
|
||||
SDL_Renderer* pRender; ///< SDL2 Rendering engine
|
||||
#endif
|
||||
|
||||
#if defined(DRV_TOUCH_TSLIB)
|
||||
struct tsdev* pTsDev; ///< Ptr to touchscreen device
|
||||
#endif
|
||||
|
||||
} gslc_tsDriver;
|
||||
|
||||
|
||||
|
||||
// =======================================================================
|
||||
// Public APIs to GUIslice core library
|
||||
// - These functions define the renderer / driver-dependent
|
||||
// implementations for the core drawing operations within
|
||||
// GUIslice.
|
||||
// =======================================================================
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// Configuration Functions
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
///
|
||||
/// Initialize the SDL library
|
||||
/// - Performs clean startup workaround (if enabled)
|
||||
/// - Configures video mode
|
||||
/// - Initializes font support
|
||||
///
|
||||
/// PRE:
|
||||
/// - The environment variables should be configured before
|
||||
/// calling gslc_DrvInit().
|
||||
///
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
///
|
||||
/// \return true if success, false if fail
|
||||
///
|
||||
bool gslc_DrvInit(gslc_tsGui* pGui);
|
||||
|
||||
|
||||
///
|
||||
/// Free up any members associated with the driver
|
||||
/// - Eg. renderers, windows, background surfaces, etc.
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
///
|
||||
/// \return none
|
||||
///
|
||||
void gslc_DrvDestruct(gslc_tsGui* pGui);
|
||||
|
||||
|
||||
///
|
||||
/// Get the display driver name
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
///
|
||||
/// \return String containing driver name
|
||||
///
|
||||
const char* gslc_DrvGetNameDisp(gslc_tsGui* pGui);
|
||||
|
||||
|
||||
///
|
||||
/// Get the touch driver name
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
///
|
||||
/// \return String containing driver name
|
||||
///
|
||||
const char* gslc_DrvGetNameTouch(gslc_tsGui* pGui);
|
||||
|
||||
///
|
||||
/// Get the native display driver instance
|
||||
/// - This can be useful to access special commands
|
||||
/// available in the selected driver.
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
///
|
||||
/// \return Void pointer to the display driver instance.
|
||||
/// This pointer should be typecast to the particular
|
||||
/// driver being used. If no driver was created then
|
||||
/// this function will return NULL.
|
||||
///
|
||||
void* gslc_DrvGetDriverDisp(gslc_tsGui* pGui);
|
||||
|
||||
///
|
||||
/// Get the native touch driver instance
|
||||
/// - This can be useful to access special commands
|
||||
/// available in the selected driver.
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
///
|
||||
/// \return Void pointer to the touch driver instance.
|
||||
/// This pointer should be typecast to the particular
|
||||
/// driver being used. If no driver was created then
|
||||
/// this function will return NULL.
|
||||
///
|
||||
void* gslc_DrvGetDriverTouch(gslc_tsGui* pGui);
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// Image/surface handling Functions
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
|
||||
///
|
||||
/// Load a bitmap (*.bmp) and create a new image resource.
|
||||
/// Transparency is enabled by GSLC_BMP_TRANS_EN
|
||||
/// through use of color (GSLC_BMP_TRANS_RGB).
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] sImgRef: Image reference
|
||||
///
|
||||
/// \return Image pointer (surface/texture/path) or NULL if error
|
||||
///
|
||||
void* gslc_DrvLoadImage(gslc_tsGui* pGui,gslc_tsImgRef sImgRef);
|
||||
|
||||
|
||||
///
|
||||
/// Configure the background to use a bitmap image
|
||||
/// - The background is used when redrawing the entire page
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] sImgRef: Image reference
|
||||
///
|
||||
/// \return true if success, false if fail
|
||||
///
|
||||
bool gslc_DrvSetBkgndImage(gslc_tsGui* pGui,gslc_tsImgRef sImgRef);
|
||||
|
||||
///
|
||||
/// Configure the background to use a solid color
|
||||
/// - The background is used when redrawing the entire page
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] nCol: RGB Color to use
|
||||
///
|
||||
/// \return true if success, false if fail
|
||||
///
|
||||
bool gslc_DrvSetBkgndColor(gslc_tsGui* pGui,gslc_tsColor nCol);
|
||||
|
||||
///
|
||||
/// Set an element's normal-state image
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] pElem: Pointer to Element to update
|
||||
/// \param[in] sImgRef: Image reference
|
||||
///
|
||||
/// \return true if success, false if error
|
||||
///
|
||||
bool gslc_DrvSetElemImageNorm(gslc_tsGui* pGui,gslc_tsElem* pElem,gslc_tsImgRef sImgRef);
|
||||
|
||||
///
|
||||
/// Set an element's glow-state image
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] pElem: Pointer to Element to update
|
||||
/// \param[in] sImgRef: Image reference
|
||||
///
|
||||
/// \return true if success, false if error
|
||||
///
|
||||
bool gslc_DrvSetElemImageGlow(gslc_tsGui* pGui,gslc_tsElem* pElem,gslc_tsImgRef sImgRef);
|
||||
|
||||
|
||||
///
|
||||
/// Release an image surface
|
||||
///
|
||||
/// \param[in] pvImg: Void ptr to image
|
||||
///
|
||||
/// \return none
|
||||
///
|
||||
void gslc_DrvImageDestruct(void* pvImg);
|
||||
|
||||
|
||||
///
|
||||
/// Set the clipping rectangle for future drawing updates
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] pRect: Rectangular region to constrain edits
|
||||
///
|
||||
/// \return true if success, false if error
|
||||
///
|
||||
bool gslc_DrvSetClipRect(gslc_tsGui* pGui,gslc_tsRect* pRect);
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// Font handling Functions
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
|
||||
///
|
||||
/// Load a font from a resource and return pointer to it
|
||||
///
|
||||
/// \param[in] eFontRefType: Font reference type (GSLC_FONTREF_FNAME for SDL)
|
||||
/// \param[in] pvFontRef: Font reference pointer (Pointer to the font filename)
|
||||
/// \param[in] nFontSz: Typeface size to use
|
||||
///
|
||||
/// \return Void ptr to driver-specific font if load was successful, NULL otherwise
|
||||
///
|
||||
const void* gslc_DrvFontAdd(gslc_teFontRefType eFontRefType,const void* pvFontRef,uint16_t nFontSz);
|
||||
|
||||
///
|
||||
/// Release all fonts defined in the GUI
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
///
|
||||
/// \return none
|
||||
///
|
||||
void gslc_DrvFontsDestruct(gslc_tsGui* pGui);
|
||||
|
||||
|
||||
///
|
||||
/// Get the extent (width and height) of a text string
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] pFont: Ptr to Font structure
|
||||
/// \param[in] pStr: String to display
|
||||
/// \param[in] eTxtFlags: Flags associated with text string
|
||||
/// \param[out] pnTxtX: Ptr to offset X of text
|
||||
/// \param[out] pnTxtY: Ptr to offset Y of text
|
||||
/// \param[out] pnTxtSzW: Ptr to width of text
|
||||
/// \param[out] pnTxtSzH: Ptr to height of text
|
||||
///
|
||||
/// \return true if success, false if failure
|
||||
///
|
||||
bool gslc_DrvGetTxtSize(gslc_tsGui* pGui,gslc_tsFont* pFont,const char* pStr,gslc_teTxtFlags eTxtFlags,
|
||||
int16_t* pnTxtX,int16_t* pnTxtY,uint16_t* pnTxtSzW,uint16_t* pnTxtSzH);
|
||||
|
||||
|
||||
///
|
||||
/// Draw a text string at the given coordinate
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] nTxtX: X coordinate of top-left text string
|
||||
/// \param[in] nTxtY: Y coordinate of top-left text string
|
||||
/// \param[in] pFont: Ptr to Font
|
||||
/// \param[in] pStr: String to display
|
||||
/// \param[in] eTxtFlags: Flags associated with text string
|
||||
/// \param[in] colTxt: Color to draw text
|
||||
/// \param[in] colBg: unused in SDL, defaults to black
|
||||
///
|
||||
/// \return true if success, false if failure
|
||||
///
|
||||
bool gslc_DrvDrawTxt(gslc_tsGui* pGui,int16_t nTxtX,int16_t nTxtY,gslc_tsFont* pFont,const char* pStr,gslc_teTxtFlags eTxtFlags,gslc_tsColor colTxt,gslc_tsColor colBg);
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// Screen Management Functions
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
///
|
||||
/// Force a page flip to occur. This generally copies active
|
||||
/// screen surface to the display.
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
///
|
||||
/// \return none
|
||||
///
|
||||
void gslc_DrvPageFlipNow(gslc_tsGui* pGui);
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// Graphics Primitives Functions
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
///
|
||||
/// Draw a point
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] nX: X coordinate of point
|
||||
/// \param[in] nY: Y coordinate of point
|
||||
/// \param[in] nCol: Color RGB value to draw
|
||||
///
|
||||
/// \return true if success, false if error
|
||||
///
|
||||
bool gslc_DrvDrawPoint(gslc_tsGui* pGui,int16_t nX,int16_t nY,gslc_tsColor nCol);
|
||||
|
||||
///
|
||||
/// Draw a point
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] asPt: Array of points to draw
|
||||
/// \param[in] nNumPt: Number of points in array
|
||||
/// \param[in] nCol: Color RGB value to draw
|
||||
///
|
||||
/// \return true if success, false if error
|
||||
///
|
||||
bool gslc_DrvDrawPoints(gslc_tsGui* pGui,gslc_tsPt* asPt,uint16_t nNumPt,gslc_tsColor nCol);
|
||||
|
||||
///
|
||||
/// Draw a framed rectangle
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] rRect: Rectangular region to frame
|
||||
/// \param[in] nCol: Color RGB value to frame
|
||||
///
|
||||
/// \return true if success, false if error
|
||||
///
|
||||
bool gslc_DrvDrawFrameRect(gslc_tsGui* pGui,gslc_tsRect rRect,gslc_tsColor nCol);
|
||||
|
||||
|
||||
///
|
||||
/// Draw a filled rectangle
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] rRect: Rectangular region to fill
|
||||
/// \param[in] nCol: Color RGB value to fill
|
||||
///
|
||||
/// \return true if success, false if error
|
||||
///
|
||||
bool gslc_DrvDrawFillRect(gslc_tsGui* pGui,gslc_tsRect rRect,gslc_tsColor nCol);
|
||||
|
||||
|
||||
///
|
||||
/// Draw a line
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] nX0: Line start (X coordinate)
|
||||
/// \param[in] nY0: Line start (Y coordinate)
|
||||
/// \param[in] nX1: Line finish (X coordinate)
|
||||
/// \param[in] nY1: Line finish (Y coordinate)
|
||||
/// \param[in] nCol: Color RGB value to draw
|
||||
///
|
||||
/// \return true if success, false if error
|
||||
///
|
||||
bool gslc_DrvDrawLine(gslc_tsGui* pGui,int16_t nX0,int16_t nY0,int16_t nX1,int16_t nY1,gslc_tsColor nCol);
|
||||
|
||||
|
||||
// TODO: Add DrvDrawFrameCircle()
|
||||
// TODO: Add DrvDrawFillCircle()
|
||||
// TODO: Add DrvDrawFrameTriangle()
|
||||
// TODO: Add DrvDrawFillTriangle()
|
||||
|
||||
|
||||
///
|
||||
/// Copy all of source image to destination screen at specified coordinate
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] nDstX: Destination X coord for copy
|
||||
/// \param[in] nDstY: Destination Y coord for copy
|
||||
/// \param[in] sImgRef: Image reference
|
||||
///
|
||||
/// \return true if success, false if fail
|
||||
///
|
||||
bool gslc_DrvDrawImage(gslc_tsGui* pGui,int16_t nDstX,int16_t nDstY,gslc_tsImgRef sImgRef);
|
||||
|
||||
|
||||
// TODO: Add DrvDrawMonoFromMem()
|
||||
// TODO: Add DrvDrawBmp24FromMem()
|
||||
|
||||
|
||||
///
|
||||
/// Copy the background image to destination screen
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
///
|
||||
/// \return true if success, false if fail
|
||||
///
|
||||
void gslc_DrvDrawBkgnd(gslc_tsGui* pGui);
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// Touch Functions
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
///
|
||||
/// Get the last touch event from the SDL_Event handler
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[out] pnX: Ptr to X coordinate of last touch event
|
||||
/// \param[out] pnY: Ptr to Y coordinate of last touch event
|
||||
/// \param[out] pnPress: Ptr to Pressure level of last touch event (0 for none, 1 for touch)
|
||||
/// \param[out] peInputEvent Indication of event type
|
||||
/// \param[out] pnInputVal Additional data for event type
|
||||
///
|
||||
/// \return true if an event was detected or false otherwise
|
||||
///
|
||||
bool gslc_DrvGetTouch(gslc_tsGui* pGui,int16_t* pnX,int16_t* pnY,uint16_t* pnPress,gslc_teInputRawEvent* peInputEvent,int16_t* pnInputVal);
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// Dynamic Screen rotation and Touch axes swap/flip functions
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
///
|
||||
/// Change rotation, automatically adapt touchscreen axes swap/flip
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] nRotation: Screen Rotation value (0, 1, 2 or 3)
|
||||
///
|
||||
/// \return true if successful
|
||||
///
|
||||
bool gslc_DrvRotate(gslc_tsGui* pGui, uint8_t nRotation);
|
||||
|
||||
|
||||
// =======================================================================
|
||||
// Private Functions
|
||||
// - These functions are not included in the scope of APIs used by
|
||||
// the core GUIslice library. Instead, these functions are used
|
||||
// to support the operations within this driver layer.
|
||||
// =======================================================================
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// Private Configuration Functions
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
///
|
||||
/// Ensure SDL initializes cleanly to workaround
|
||||
/// possible issues if previous SDL application
|
||||
/// failed to close down gracefully.
|
||||
///
|
||||
/// \param[in] sTTY: Terminal device (eg. "/dev/tty0")
|
||||
///
|
||||
/// \return true if success
|
||||
///
|
||||
bool gslc_DrvCleanStart(const char* sTTY);
|
||||
|
||||
|
||||
///
|
||||
/// Report driver debug info (before initialization)
|
||||
///
|
||||
/// \return none
|
||||
///
|
||||
void gslc_DrvReportInfoPre();
|
||||
|
||||
///
|
||||
/// Report driver debug info (after initialization)
|
||||
///
|
||||
/// \return none
|
||||
///
|
||||
void gslc_DrvReportInfoPost();
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// Private Conversion Functions
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
///
|
||||
/// Translate a gslc_tsRect into an SDL_Rect
|
||||
///
|
||||
/// \param[in] rRect: gslc_tsRect
|
||||
///
|
||||
/// \return Converted SDL_Rect
|
||||
///
|
||||
SDL_Rect gslc_DrvAdaptRect(gslc_tsRect rRect);
|
||||
|
||||
///
|
||||
/// Translate a gslc_tsColor into an SDL_Color
|
||||
///
|
||||
/// \param[in] sCol: gslc_tsColor
|
||||
///
|
||||
/// \return Converted SDL_Color
|
||||
///
|
||||
SDL_Color gslc_DrvAdaptColor(gslc_tsColor sCol);
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// Private Drawing Functions
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
#if defined(DRV_DISP_SDL1)
|
||||
///
|
||||
/// Lock an SDL surface so that direct pixel manipulation
|
||||
/// can be done safely. This function is called before any
|
||||
/// direct pixel updates.
|
||||
///
|
||||
/// POST:
|
||||
/// - Primary screen surface is locked
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
///
|
||||
/// \return true if success, false otherwise
|
||||
///
|
||||
bool gslc_DrvScreenLock(gslc_tsGui* pGui);
|
||||
|
||||
|
||||
///
|
||||
/// Unlock the SDL surface after pixel manipulation is
|
||||
/// complete. This function is called after all pixel updates
|
||||
/// are done.
|
||||
///
|
||||
/// POST:
|
||||
/// - Primary screen surface is unlocked
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
///
|
||||
/// \return none
|
||||
///
|
||||
void gslc_DrvScreenUnlock(gslc_tsGui* pGui);
|
||||
|
||||
|
||||
///
|
||||
/// Convert an RGB color triplet into the surface pixel value.
|
||||
/// This is called to produce the native pixel value required by
|
||||
/// the raw pixel manipulation routines.
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] nCol: RGB value for conversion
|
||||
///
|
||||
/// \return A pixel value for the current screen format
|
||||
///
|
||||
uint32_t gslc_DrvAdaptColorRaw(gslc_tsGui* pGui,gslc_tsColor nCol);
|
||||
|
||||
|
||||
///
|
||||
/// Get the pixel at (X,Y) from the active screen
|
||||
///
|
||||
/// PRE:
|
||||
/// - Screen surface must be locked
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] nX: Pixel X coordinate
|
||||
/// \param[in] nY: Pixel Y coordinate
|
||||
///
|
||||
/// \return Pixel color value from the coordinate or 0 if error
|
||||
///
|
||||
uint32_t gslc_DrvDrawGetPixelRaw(gslc_tsGui* pGui,int16_t nX,int16_t nY);
|
||||
|
||||
|
||||
///
|
||||
/// Set a pixel on the active screen to the given color
|
||||
///
|
||||
/// PRE:
|
||||
/// - Screen surface must be locked
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] nX: Pixel X coordinate to set
|
||||
/// \param[in] nY: Pixel Y coordinate to set
|
||||
/// \param[in] nPixelCol: Raw color pixel value to assign
|
||||
///
|
||||
/// \return none
|
||||
///
|
||||
void gslc_DrvDrawSetPixelRaw(gslc_tsGui* pGui,int16_t nX,int16_t nY,uint32_t nPixelCol);
|
||||
|
||||
///
|
||||
/// Copy one image region to another.
|
||||
/// - This is typically used to copy an image to the main screen surface
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] nX: Destination X coordinate of copy
|
||||
/// \param[in] nY: Destination Y coordinate of copy
|
||||
/// \param[in] pvSrc: Void Ptr to source surface (eg. a loaded image)
|
||||
/// \param[in] pvDest: Void Ptr to destination surface (typically the screen)
|
||||
///
|
||||
/// \return none
|
||||
///
|
||||
void gslc_DrvPasteSurface(gslc_tsGui* pGui,int16_t nX, int16_t nY, void* pvSrc, void* pvDest);
|
||||
|
||||
#endif // DRV_DISP_SDL1
|
||||
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// Private Touchscreen Functions (if using SDL)
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
///
|
||||
/// Perform any touchscreen-specific initialization
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] acDev: Device path to touchscreen
|
||||
/// eg. "/dev/input/touchscreen"
|
||||
///
|
||||
/// \return true if successful
|
||||
///
|
||||
bool gslc_DrvInitTouch(gslc_tsGui* pGui,const char* acDev);
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// Touchscreen Functions (if using tslib)
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
#if defined(DRV_TOUCH_TSLIB)
|
||||
///
|
||||
/// Perform any touchscreen-specific initialization
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] acDev: Device path to touchscreen
|
||||
/// eg. "/dev/input/touchscreen"
|
||||
///
|
||||
/// \return true if successful
|
||||
///
|
||||
bool gslc_TDrvInitTouch(gslc_tsGui* pGui,const char* acDev);
|
||||
|
||||
|
||||
///
|
||||
/// Get the last touch event from the tslib handler
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[out] pnX: Ptr to X coordinate of last touch event
|
||||
/// \param[out] pnY: Ptr to Y coordinate of last touch event
|
||||
/// \param[out] pnPress: Ptr to Pressure level of last touch event (0 for none, >0 for touch)
|
||||
/// \param[out] peInputEvent Indication of event type
|
||||
/// \param[out] pnInputVal Additional data for event type
|
||||
///
|
||||
/// \return non-zero if an event was detected or 0 otherwise
|
||||
///
|
||||
bool gslc_TDrvGetTouch(gslc_tsGui* pGui, int16_t* pnX, int16_t* pnY, uint16_t* pnPress, gslc_teInputRawEvent* peInputEvent, int16_t* pnInputVal);
|
||||
|
||||
#endif // DRV_TOUCH_TSLIB
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif // __cplusplus
|
||||
#endif // _GUISLICE_DRV_SDL_H_
|
2188
src/guislice/GUIslice_drv_tft_espi.cpp
Normal file
2188
src/guislice/GUIslice_drv_tft_espi.cpp
Normal file
File diff suppressed because it is too large
Load diff
755
src/guislice/GUIslice_drv_tft_espi.h
Normal file
755
src/guislice/GUIslice_drv_tft_espi.h
Normal file
|
@ -0,0 +1,755 @@
|
|||
#ifndef _GUISLICE_DRV_TFT_ESPI_H_
|
||||
#define _GUISLICE_DRV_TFT_ESPI_H_
|
||||
|
||||
// =======================================================================
|
||||
// GUIslice library (driver layer for bodmer/TFT_eSPI)
|
||||
// - Calvin Hass
|
||||
// - https://www.impulseadventure.com/elec/guislice-gui.html
|
||||
// - https://github.com/ImpulseAdventure/GUIslice
|
||||
// =======================================================================
|
||||
//
|
||||
// The MIT License
|
||||
//
|
||||
// Copyright 2016-2020 Calvin Hass
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
//
|
||||
// =======================================================================
|
||||
/// \file GUIslice_drv_tft_espi.h
|
||||
/// \brief GUIslice library (driver layer for TFT-eSPI)
|
||||
|
||||
|
||||
// =======================================================================
|
||||
// Driver Layer for bodmer/TFT_eSPI
|
||||
// - https://github.com/Bodmer/TFT_eSPI
|
||||
// =======================================================================
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif // __cplusplus
|
||||
|
||||
#include "GUIslice.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
|
||||
// Determine characteristics for configured touch driver
|
||||
// - DRV_TOUCH_TYPE_EXTERNAL: TDrv* external touch APIs are enabled
|
||||
// - DRV_TOUCH_TYPE_RES: Resistive overlay
|
||||
// - DRV_TOUCH_TYPE_CAP: Capacitive overlay
|
||||
// - DRV_TOUCH_TYPE_ANALOG: Analog input
|
||||
#if defined(DRV_TOUCH_ADA_STMPE610)
|
||||
#define DRV_TOUCH_TYPE_EXTERNAL
|
||||
#define DRV_TOUCH_TYPE_RES // Resistive
|
||||
#elif defined(DRV_TOUCH_ADA_FT6206)
|
||||
#define DRV_TOUCH_TYPE_EXTERNAL
|
||||
#define DRV_TOUCH_TYPE_CAP // Capacitive
|
||||
#elif defined(DRV_TOUCH_ADA_SIMPLE)
|
||||
#define DRV_TOUCH_TYPE_EXTERNAL
|
||||
#define DRV_TOUCH_TYPE_RES // Resistive
|
||||
#define DRV_TOUCH_TYPE_ANALOG // Analog
|
||||
#elif defined(DRV_TOUCH_XPT2046_STM)
|
||||
#define DRV_TOUCH_TYPE_EXTERNAL
|
||||
#define DRV_TOUCH_TYPE_RES // Resistive
|
||||
#elif defined(DRV_TOUCH_XPT2046_PS)
|
||||
#define DRV_TOUCH_TYPE_EXTERNAL
|
||||
#define DRV_TOUCH_TYPE_RES // Resistive
|
||||
#elif defined(DRV_TOUCH_TFT_ESPI)
|
||||
#define DRV_TOUCH_TYPE_RES // Resistive
|
||||
#elif defined(DRV_TOUCH_INPUT)
|
||||
#define DRV_TOUCH_TYPE_EXTERNAL
|
||||
#elif defined(DRV_TOUCH_HANDLER)
|
||||
#define DRV_TOUCH_TYPE_EXTERNAL
|
||||
#elif defined(DRV_TOUCH_NONE)
|
||||
#endif // DRV_TOUCH_*
|
||||
|
||||
// Additional defines
|
||||
// - Provide default if not in config file
|
||||
#if !defined(GSLC_SPIFFS_EN)
|
||||
#define GSLC_SPIFFS_EN 0
|
||||
#endif // GSLC_SPIFFS_EN
|
||||
|
||||
|
||||
// =======================================================================
|
||||
// API support definitions
|
||||
// - These defines indicate whether the driver includes optimized
|
||||
// support for various APIs. If a define is set to 0, then the
|
||||
// GUIslice core emulation will be used instead.
|
||||
// - At the very minimum, the point draw routine must be available:
|
||||
// gslc_DrvDrawPoint()
|
||||
// =======================================================================
|
||||
|
||||
#define DRV_HAS_DRAW_POINT 1 ///< Support gslc_DrvDrawPoint()
|
||||
|
||||
#define DRV_HAS_DRAW_POINTS 0 ///< Support gslc_DrvDrawPoints()
|
||||
#define DRV_HAS_DRAW_LINE 1 ///< Support gslc_DrvDrawLine()
|
||||
#define DRV_HAS_DRAW_RECT_FRAME 1 ///< Support gslc_DrvDrawFrameRect()
|
||||
#define DRV_HAS_DRAW_RECT_FILL 1 ///< Support gslc_DrvDrawFillRect()
|
||||
#define DRV_HAS_DRAW_RECT_ROUND_FRAME 1 ///< Support gslc_DrvDrawFrameRoundRect()
|
||||
#define DRV_HAS_DRAW_RECT_ROUND_FILL 1 ///< Support gslc_DrvDrawFillRoundRect()
|
||||
#define DRV_HAS_DRAW_CIRCLE_FRAME 1 ///< Support gslc_DrvDrawFrameCircle()
|
||||
#define DRV_HAS_DRAW_CIRCLE_FILL 1 ///< Support gslc_DrvDrawFillCircle()
|
||||
#define DRV_HAS_DRAW_TRI_FRAME 1 ///< Support gslc_DrvDrawFrameTriangle()
|
||||
#define DRV_HAS_DRAW_TRI_FILL 1 ///< Support gslc_DrvDrawFillTriangle()
|
||||
#define DRV_HAS_DRAW_TEXT 1 ///< Support gslc_DrvDrawTxt()
|
||||
#define DRV_HAS_DRAW_BMP_MEM 0 ///< Support gslc_DrvDrawBmp24FromMem()
|
||||
|
||||
#define DRV_OVERRIDE_TXT_ALIGN 1 ///< Driver provides text alignment
|
||||
|
||||
// =======================================================================
|
||||
// Driver-specific members
|
||||
// =======================================================================
|
||||
typedef struct {
|
||||
gslc_tsColor nColBkgnd; ///< Background color (if not image-based)
|
||||
|
||||
gslc_tsRect rClipRect; ///< Clipping rectangle
|
||||
|
||||
} gslc_tsDriver;
|
||||
|
||||
|
||||
|
||||
// =======================================================================
|
||||
// Public APIs to GUIslice core library
|
||||
// - These functions define the renderer / driver-dependent
|
||||
// implementations for the core drawing operations within
|
||||
// GUIslice.
|
||||
// =======================================================================
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// Configuration Functions
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
///
|
||||
/// Initialize the SDL library
|
||||
/// - Performs clean startup workaround (if enabled)
|
||||
/// - Configures video mode
|
||||
/// - Initializes font support
|
||||
///
|
||||
/// PRE:
|
||||
/// - The environment variables should be configured before
|
||||
/// calling gslc_DrvInit(). This can be done with gslc_DrvInitEnv()
|
||||
/// or manually in user function.
|
||||
///
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
///
|
||||
/// \return true if success, false if fail
|
||||
///
|
||||
bool gslc_DrvInit(gslc_tsGui* pGui);
|
||||
|
||||
|
||||
///
|
||||
/// Perform any touchscreen-specific initialization
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] acDev: Device path to touchscreen
|
||||
/// eg. "/dev/input/touchscreen"
|
||||
///
|
||||
/// \return true if successful
|
||||
///
|
||||
bool gslc_DrvInitTs(gslc_tsGui* pGui,const char* acDev);
|
||||
|
||||
|
||||
///
|
||||
/// Free up any members associated with the driver
|
||||
/// - Eg. renderers, windows, background surfaces, etc.
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
///
|
||||
/// \return none
|
||||
///
|
||||
void gslc_DrvDestruct(gslc_tsGui* pGui);
|
||||
|
||||
|
||||
///
|
||||
/// Get the display driver name
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
///
|
||||
/// \return String containing driver name
|
||||
///
|
||||
const char* gslc_DrvGetNameDisp(gslc_tsGui* pGui);
|
||||
|
||||
|
||||
///
|
||||
/// Get the touch driver name
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
///
|
||||
/// \return String containing driver name
|
||||
///
|
||||
const char* gslc_DrvGetNameTouch(gslc_tsGui* pGui);
|
||||
|
||||
///
|
||||
/// Get the native display driver instance
|
||||
/// - This can be useful to access special commands
|
||||
/// available in the selected driver.
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
///
|
||||
/// \return Void pointer to the display driver instance.
|
||||
/// This pointer should be typecast to the particular
|
||||
/// driver being used. If no driver was created then
|
||||
/// this function will return NULL.
|
||||
///
|
||||
void* gslc_DrvGetDriverDisp(gslc_tsGui* pGui);
|
||||
|
||||
///
|
||||
/// Get the native touch driver instance
|
||||
/// - This can be useful to access special commands
|
||||
/// available in the selected driver.
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
///
|
||||
/// \return Void pointer to the touch driver instance.
|
||||
/// This pointer should be typecast to the particular
|
||||
/// driver being used. If no driver was created then
|
||||
/// this function will return NULL.
|
||||
///
|
||||
void* gslc_DrvGetDriverTouch(gslc_tsGui* pGui);
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// Image/surface handling Functions
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
|
||||
///
|
||||
/// Load a bitmap (*.bmp) and create a new image resource.
|
||||
/// Transparency is enabled by GSLC_BMP_TRANS_EN
|
||||
/// through use of color (GSLC_BMP_TRANS_RGB).
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] sImgRef: Image reference
|
||||
///
|
||||
/// \return Image pointer (surface/texture) or NULL if error
|
||||
///
|
||||
void* gslc_DrvLoadImage(gslc_tsGui* pGui,gslc_tsImgRef sImgRef);
|
||||
|
||||
|
||||
///
|
||||
/// Configure the background to use a bitmap image
|
||||
/// - The background is used when redrawing the entire page
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] sImgRef: Image reference
|
||||
///
|
||||
/// \return true if success, false if fail
|
||||
///
|
||||
bool gslc_DrvSetBkgndImage(gslc_tsGui* pGui,gslc_tsImgRef sImgRef);
|
||||
|
||||
///
|
||||
/// Configure the background to use a solid color
|
||||
/// - The background is used when redrawing the entire page
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] nCol: RGB Color to use
|
||||
///
|
||||
/// \return true if success, false if fail
|
||||
///
|
||||
bool gslc_DrvSetBkgndColor(gslc_tsGui* pGui,gslc_tsColor nCol);
|
||||
|
||||
///
|
||||
/// Set an element's normal-state image
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] pElem: Pointer to Element to update
|
||||
/// \param[in] sImgRef: Image reference
|
||||
///
|
||||
/// \return true if success, false if error
|
||||
///
|
||||
bool gslc_DrvSetElemImageNorm(gslc_tsGui* pGui,gslc_tsElem* pElem,gslc_tsImgRef sImgRef);
|
||||
|
||||
///
|
||||
/// Set an element's glow-state image
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] pElem: Pointer to Element to update
|
||||
/// \param[in] sImgRef: Image reference
|
||||
///
|
||||
/// \return true if success, false if error
|
||||
///
|
||||
bool gslc_DrvSetElemImageGlow(gslc_tsGui* pGui,gslc_tsElem* pElem,gslc_tsImgRef sImgRef);
|
||||
|
||||
|
||||
///
|
||||
/// Release an image surface
|
||||
///
|
||||
/// \param[in] pvImg: Void ptr to image
|
||||
///
|
||||
/// \return none
|
||||
///
|
||||
void gslc_DrvImageDestruct(void* pvImg);
|
||||
|
||||
|
||||
///
|
||||
/// Set the clipping rectangle for future drawing updates
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] pRect: Rectangular region to constrain edits
|
||||
///
|
||||
/// \return true if success, false if error
|
||||
///
|
||||
bool gslc_DrvSetClipRect(gslc_tsGui* pGui,gslc_tsRect* pRect);
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// Font handling Functions
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
///
|
||||
/// Load a font from a resource and return pointer to it
|
||||
///
|
||||
/// \param[in] eFontRefType: Font reference type:
|
||||
/// - GSLC_FONTREF_PTR for Standard TFT_eSPI Fonts
|
||||
/// - GSLC_FONTREF_FNAME for antialiased Font in SPIFFS
|
||||
/// \param[in] pvFontRef: Font reference pointer / SPIFFS font filename without ext.
|
||||
/// \param[in] nFontSz: Typeface size to use, ignored for SPIFFS font
|
||||
///
|
||||
/// \return Void ptr to driver-specific font if load was successful, NULL otherwise
|
||||
///
|
||||
const void* gslc_DrvFontAdd(gslc_teFontRefType eFontRefType,const void* pvFontRef,uint16_t nFontSz);
|
||||
|
||||
///
|
||||
/// Release all fonts defined in the GUI
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
///
|
||||
/// \return none
|
||||
///
|
||||
void gslc_DrvFontsDestruct(gslc_tsGui* pGui);
|
||||
|
||||
|
||||
///
|
||||
/// Get the extent (width and height) of a text string
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] pFont: Ptr to Font structure
|
||||
/// \param[in] pStr: String to display
|
||||
/// \param[in] eTxtFlags: Flags associated with text string
|
||||
/// \param[out] pnTxtX: Ptr to offset X of text
|
||||
/// \param[out] pnTxtY: Ptr to offset Y of text
|
||||
/// \param[out] pnTxtSzW: Ptr to width of text
|
||||
/// \param[out] pnTxtSzH: Ptr to height of text
|
||||
///
|
||||
/// \return true if success, false if failure
|
||||
///
|
||||
bool gslc_DrvGetTxtSize(gslc_tsGui* pGui,gslc_tsFont* pFont,const char* pStr,gslc_teTxtFlags eTxtFlags,
|
||||
int16_t* pnTxtX,int16_t* pnTxtY,uint16_t* pnTxtSzW,uint16_t* pnTxtSzH);
|
||||
|
||||
|
||||
///
|
||||
/// Draw a text string at the given coordinate
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] nTxtX: X coordinate of top-left text string
|
||||
/// \param[in] nTxtY: Y coordinate of top-left text string
|
||||
/// \param[in] pFont: Ptr to Font
|
||||
/// \param[in] pStr: String to display
|
||||
/// \param[in] eTxtFlags: Flags associated with text string
|
||||
/// \param[in] colTxt: Color to draw text
|
||||
/// \param[in] colBg: Color of Background for antialias blending
|
||||
///
|
||||
/// \return true if success, false if failure
|
||||
///
|
||||
bool gslc_DrvDrawTxt(gslc_tsGui* pGui,int16_t nTxtX,int16_t nTxtY,gslc_tsFont* pFont,const char* pStr,gslc_teTxtFlags eTxtFlags,gslc_tsColor colTxt,gslc_tsColor colBg);
|
||||
|
||||
///
|
||||
/// Draw a text string in a bounding box using the specified alignment
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] nX0: X coordinate of top-left of bounding box
|
||||
/// \param[in] nY0: Y coordinate of top-left of bounding box
|
||||
/// \param[in] nX1: X coordinate of bot-right of bounding box
|
||||
/// \param[in] nY1: Y coordinate of bot-right of bounding box
|
||||
/// \param[in] eTxtAlign: Alignment mode]
|
||||
/// \param[in] pFont: Ptr to Font
|
||||
/// \param[in] pStr: String to display
|
||||
/// \param[in] eTxtFlags: Flags associated with text string
|
||||
/// \param[in] colTxt: Color to draw text
|
||||
/// \param[in] colBg: Color of Background for antialias blending
|
||||
//
|
||||
/// \return true if success, false if failure
|
||||
///
|
||||
bool gslc_DrvDrawTxtAlign(gslc_tsGui* pGui,int16_t nX0,int16_t nY0,int16_t nX1,int16_t nY1,int8_t eTxtAlign,
|
||||
gslc_tsFont* pFont,const char* pStr,gslc_teTxtFlags eTxtFlags,gslc_tsColor colTxt,gslc_tsColor colBg);
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// Screen Management Functions
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
///
|
||||
/// Force a page flip to occur. This generally copies active
|
||||
/// screen surface to the display.
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
///
|
||||
/// \return none
|
||||
///
|
||||
void gslc_DrvPageFlipNow(gslc_tsGui* pGui);
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// Graphics Primitives Functions
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
///
|
||||
/// Draw a point
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] nX: X coordinate of point
|
||||
/// \param[in] nY: Y coordinate of point
|
||||
/// \param[in] nCol: Color RGB value to draw
|
||||
///
|
||||
/// \return true if success, false if error
|
||||
///
|
||||
bool gslc_DrvDrawPoint(gslc_tsGui* pGui,int16_t nX,int16_t nY,gslc_tsColor nCol);
|
||||
|
||||
///
|
||||
/// Draw a point
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] asPt: Array of points to draw
|
||||
/// \param[in] nNumPt: Number of points in array
|
||||
/// \param[in] nCol: Color RGB value to draw
|
||||
///
|
||||
/// \return true if success, false if error
|
||||
///
|
||||
bool gslc_DrvDrawPoints(gslc_tsGui* pGui,gslc_tsPt* asPt,uint16_t nNumPt,gslc_tsColor nCol);
|
||||
|
||||
///
|
||||
/// Draw a framed rectangle
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] rRect: Rectangular region to frame
|
||||
/// \param[in] nCol: Color RGB value to frame
|
||||
///
|
||||
/// \return true if success, false if error
|
||||
///
|
||||
bool gslc_DrvDrawFrameRect(gslc_tsGui* pGui,gslc_tsRect rRect,gslc_tsColor nCol);
|
||||
|
||||
|
||||
///
|
||||
/// Draw a filled rectangle
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] rRect: Rectangular region to fill
|
||||
/// \param[in] nCol: Color RGB value to fill
|
||||
///
|
||||
/// \return true if success, false if error
|
||||
///
|
||||
bool gslc_DrvDrawFillRect(gslc_tsGui* pGui,gslc_tsRect rRect,gslc_tsColor nCol);
|
||||
|
||||
|
||||
///
|
||||
/// Draw a framed rounded rectangle
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] rRect: Rectangular region to frame
|
||||
/// \param[in] nRadius: Radius for rounded corners
|
||||
/// \param[in] nCol: Color RGB value to frame
|
||||
///
|
||||
/// \return true if success, false if error
|
||||
///
|
||||
bool gslc_DrvDrawFrameRoundRect(gslc_tsGui* pGui,gslc_tsRect rRect,int16_t nRadius,gslc_tsColor nCol);
|
||||
|
||||
|
||||
///
|
||||
/// Draw a filled rounded rectangle
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] rRect: Rectangular region to fill
|
||||
/// \param[in] nRadius: Radius for rounded corners
|
||||
/// \param[in] nCol: Color RGB value to fill
|
||||
///
|
||||
/// \return true if success, false if error
|
||||
///
|
||||
bool gslc_DrvDrawFillRoundRect(gslc_tsGui* pGui,gslc_tsRect rRect,int16_t nRadius,gslc_tsColor nCol);
|
||||
|
||||
|
||||
|
||||
///
|
||||
/// Draw a line
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] nX0: Line start (X coordinate)
|
||||
/// \param[in] nY0: Line start (Y coordinate)
|
||||
/// \param[in] nX1: Line finish (X coordinate)
|
||||
/// \param[in] nY1: Line finish (Y coordinate)
|
||||
/// \param[in] nCol: Color RGB value to draw
|
||||
///
|
||||
/// \return true if success, false if error
|
||||
///
|
||||
bool gslc_DrvDrawLine(gslc_tsGui* pGui,int16_t nX0,int16_t nY0,int16_t nX1,int16_t nY1,gslc_tsColor nCol);
|
||||
|
||||
|
||||
///
|
||||
/// Draw a framed circle
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] nMidX: Center of circle (X coordinate)
|
||||
/// \param[in] nMidY: Center of circle (Y coordinate)
|
||||
/// \param[in] nRadius: Radius of circle
|
||||
/// \param[in] nCol: Color RGB value to frame
|
||||
///
|
||||
/// \return true if success, false if error
|
||||
///
|
||||
bool gslc_DrvDrawFrameCircle(gslc_tsGui* pGui,int16_t nMidX,int16_t nMidY,uint16_t nRadius,gslc_tsColor nCol);
|
||||
|
||||
|
||||
///
|
||||
/// Draw a filled circle
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] nMidX: Center of circle (X coordinate)
|
||||
/// \param[in] nMidY: Center of circle (Y coordinate)
|
||||
/// \param[in] nRadius: Radius of circle
|
||||
/// \param[in] nCol: Color RGB value to fill
|
||||
///
|
||||
/// \return true if success, false if error
|
||||
///
|
||||
bool gslc_DrvDrawFillCircle(gslc_tsGui* pGui,int16_t nMidX,int16_t nMidY,uint16_t nRadius,gslc_tsColor nCol);
|
||||
|
||||
|
||||
///
|
||||
/// Draw a framed triangle
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] nX0: X Coordinate #1
|
||||
/// \param[in] nY0: Y Coordinate #1
|
||||
/// \param[in] nX1: X Coordinate #2
|
||||
/// \param[in] nY1: Y Coordinate #2
|
||||
/// \param[in] nX2: X Coordinate #3
|
||||
/// \param[in] nY2: Y Coordinate #3
|
||||
/// \param[in] nCol: Color RGB value to frame
|
||||
///
|
||||
/// \return true if success, false if error
|
||||
///
|
||||
bool gslc_DrvDrawFrameTriangle(gslc_tsGui* pGui,int16_t nX0,int16_t nY0,
|
||||
int16_t nX1,int16_t nY1,int16_t nX2,int16_t nY2,gslc_tsColor nCol);
|
||||
|
||||
|
||||
///
|
||||
/// Draw a filled triangle
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] nX0: X Coordinate #1
|
||||
/// \param[in] nY0: Y Coordinate #1
|
||||
/// \param[in] nX1: X Coordinate #2
|
||||
/// \param[in] nY1: Y Coordinate #2
|
||||
/// \param[in] nX2: X Coordinate #3
|
||||
/// \param[in] nY2: Y Coordinate #3
|
||||
/// \param[in] nCol: Color RGB value to fill
|
||||
///
|
||||
/// \return true if success, false if error
|
||||
///
|
||||
bool gslc_DrvDrawFillTriangle(gslc_tsGui* pGui,int16_t nX0,int16_t nY0,
|
||||
int16_t nX1,int16_t nY1,int16_t nX2,int16_t nY2,gslc_tsColor nCol);
|
||||
|
||||
|
||||
///
|
||||
/// Copy all of source image to destination screen at specified coordinate
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] nDstX: Destination X coord for copy
|
||||
/// \param[in] nDstY: Destination Y coord for copy
|
||||
/// \param[in] sImgRef: Image reference
|
||||
///
|
||||
/// \return true if success, false if fail
|
||||
///
|
||||
bool gslc_DrvDrawImage(gslc_tsGui* pGui,int16_t nDstX,int16_t nDstY,gslc_tsImgRef sImgRef);
|
||||
|
||||
|
||||
///
|
||||
/// Draw a monochrome bitmap from a memory array
|
||||
/// - Draw from the bitmap buffer using the foreground color
|
||||
/// defined in the header (unset bits are transparent)
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] nDstX: Destination X coord for copy
|
||||
/// \param[in] nDstY: Destination Y coord for copy
|
||||
/// \param[in] pBitmap: Pointer to bitmap buffer
|
||||
/// \param[in] bProgMem: Bitmap is stored in Flash if true, RAM otherwise
|
||||
///
|
||||
/// \return none
|
||||
///
|
||||
void gslc_DrvDrawMonoFromMem(gslc_tsGui* pGui,int16_t nDstX, int16_t nDstY, const unsigned char *pBitmap,bool bProgMem);
|
||||
|
||||
|
||||
///
|
||||
/// Draw a color 24-bit depth bitmap from a memory array
|
||||
/// - Note that users must convert images from their native
|
||||
/// format (eg. BMP, PNG, etc.) into a C array. Please
|
||||
/// refer to the following guide for details:
|
||||
/// https://github.com/ImpulseAdventure/GUIslice/wiki/Display-Images-from-FLASH
|
||||
/// - The converted file (c array) can then be included in the sketch.
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] nDstX: X coord for copy
|
||||
/// \param[in] nDstY: Y coord for copy
|
||||
/// \param[in] pBitmap: Pointer to bitmap buffer
|
||||
/// \param[in] bProgMem: Bitmap is stored in Flash if true, RAM otherwise
|
||||
///
|
||||
/// \return none
|
||||
///
|
||||
void gslc_DrvDrawBmp24FromMem(gslc_tsGui* pGui,int16_t nDstX, int16_t nDstY,const unsigned char* pBitmap,bool bProgMem);
|
||||
|
||||
#if (GSLC_SPIFFS_EN)
|
||||
///
|
||||
/// This routine uses TFT_eFEX library to draw a BMP file stored in SPIFFS file system
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] nDstX: Destination X coord for copy
|
||||
/// \param[in] nDstY: Destination Y coord for copy
|
||||
/// \param[in] sImgRef: Image reference
|
||||
///
|
||||
/// \return true if success, false if fail
|
||||
///
|
||||
bool gslc_DrvDrawBmpFromFile(gslc_tsGui* pGui,int16_t nDstX,int16_t nDstY,gslc_tsImgRef sImgRef);
|
||||
|
||||
|
||||
///
|
||||
/// This routine uses TFT_eFEX library to draw a JPEG file stored in SPIFFS file system
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] nDstX: Destination X coord for copy
|
||||
/// \param[in] nDstY: Destination Y coord for copy
|
||||
/// \param[in] sImgRef: Image reference
|
||||
///
|
||||
/// \return true if success, false if fail
|
||||
///
|
||||
bool gslc_DrvDrawJpegFromFile(gslc_tsGui* pGui,int16_t nDstX,int16_t nDstY,gslc_tsImgRef sImgRef);
|
||||
|
||||
#endif // end GSLC_SPIFFS_EN
|
||||
|
||||
///
|
||||
/// Copy the background image to destination screen
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
///
|
||||
/// \return true if success, false if fail
|
||||
///
|
||||
void gslc_DrvDrawBkgnd(gslc_tsGui* pGui);
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// Touch Functions (if using display driver library)
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
#if defined(DRV_TOUCH_IN_DISP)
|
||||
// Use TFT_eSPI's integrated XPT2046 touch driver
|
||||
|
||||
///
|
||||
/// Perform any touchscreen-specific initialization
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] acDev: Device path to touchscreen
|
||||
/// eg. "/dev/input/touchscreen"
|
||||
///
|
||||
/// \return true if successful
|
||||
///
|
||||
bool gslc_DrvInitTouch(gslc_tsGui* pGui,const char* acDev);
|
||||
|
||||
|
||||
///
|
||||
/// Get the last touch event from the internal XPT2046 touch handler
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[out] pnX: Ptr to X coordinate of last touch event
|
||||
/// \param[out] pnY: Ptr to Y coordinate of last touch event
|
||||
/// \param[out] pnPress: Ptr to Pressure level of last touch event (0 for none, 1 for touch)
|
||||
/// \param[out] peInputEvent Indication of event type
|
||||
/// \param[out] pnInputVal Additional data for event type
|
||||
///
|
||||
/// \return true if an event was detected or false otherwise
|
||||
///
|
||||
bool gslc_DrvGetTouch(gslc_tsGui* pGui,int16_t* pnX,int16_t* pnY,uint16_t* pnPress,gslc_teInputRawEvent* peInputEvent,int16_t* pnInputVal);
|
||||
|
||||
#endif // DRV_TOUCH_IN_DISP
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// Touch Functions (if using external touch driver library)
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
// Check for deprecated config option
|
||||
// - This check will be removed in future releases
|
||||
#if defined(DRV_TOUCH_XPT2046)
|
||||
#error "NOTE: DRV_TOUCH_XPT2046 has been renamed to DRV_TOUCH_XPT2046_STM. Please update your config."
|
||||
#endif
|
||||
|
||||
#if defined(DRV_TOUCH_TYPE_EXTERNAL)
|
||||
|
||||
///
|
||||
/// Perform any touchscreen-specific initialization
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] acDev: Device path to touchscreen
|
||||
/// eg. "/dev/input/touchscreen"
|
||||
///
|
||||
/// \return true if successful
|
||||
///
|
||||
bool gslc_TDrvInitTouch(gslc_tsGui* pGui,const char* acDev);
|
||||
|
||||
|
||||
///
|
||||
/// Get the last touch event from the SDL_Event handler
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[out] pnX: Ptr to X coordinate of last touch event
|
||||
/// \param[out] pnY: Ptr to Y coordinate of last touch event
|
||||
/// \param[out] pnPress: Ptr to Pressure level of last touch event (0 for none, 1 for touch)
|
||||
/// \param[out] peInputEvent Indication of event type
|
||||
/// \param[out] pnInputVal Additional data for event type
|
||||
///
|
||||
/// \return true if an event was detected or false otherwise
|
||||
///
|
||||
bool gslc_TDrvGetTouch(gslc_tsGui* pGui, int16_t* pnX, int16_t* pnY, uint16_t* pnPress, gslc_teInputRawEvent* peInputEvent, int16_t* pnInputVal);
|
||||
|
||||
#endif // DRV_TOUCH_*
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// Dynamic Screen rotation and Touch axes swap/flip functions
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
///
|
||||
/// Change rotation, automatically adapt touchscreen axes swap/flip
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] nRotation: Screen Rotation value (0, 1, 2 or 3)
|
||||
///
|
||||
/// \return true if successful
|
||||
///
|
||||
bool gslc_DrvRotate(gslc_tsGui* pGui, uint8_t nRotation);
|
||||
|
||||
|
||||
// =======================================================================
|
||||
// Private Functions
|
||||
// - These functions are not included in the scope of APIs used by
|
||||
// the core GUIslice library. Instead, these functions are used
|
||||
// to support the operations within this driver layer.
|
||||
// =======================================================================
|
||||
|
||||
uint16_t gslc_DrvAdaptColorToRaw(gslc_tsColor nCol);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif // __cplusplus
|
||||
#endif // _GUISLICE_DRV_TFT_ESPI_H_
|
1361
src/guislice/GUIslice_drv_utft.cpp
Normal file
1361
src/guislice/GUIslice_drv_utft.cpp
Normal file
File diff suppressed because it is too large
Load diff
672
src/guislice/GUIslice_drv_utft.h
Normal file
672
src/guislice/GUIslice_drv_utft.h
Normal file
|
@ -0,0 +1,672 @@
|
|||
#ifndef _GUISLICE_DRV_UTFT_H_
|
||||
#define _GUISLICE_DRV_UTFT_H_
|
||||
|
||||
// =======================================================================
|
||||
// GUIslice library (driver layer for UTFT)
|
||||
// - Calvin Hass
|
||||
// - https://www.impulseadventure.com/elec/guislice-gui.html
|
||||
// - https://github.com/ImpulseAdventure/GUIslice
|
||||
// =======================================================================
|
||||
//
|
||||
// The MIT License
|
||||
//
|
||||
// Copyright 2016-2020 Calvin Hass
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
//
|
||||
// =======================================================================
|
||||
/// \file GUIslice_drv_utft.h
|
||||
/// \brief GUIslice library (driver layer for UTFT)
|
||||
|
||||
|
||||
// =======================================================================
|
||||
// Driver Layer for UTFT
|
||||
// =======================================================================
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif // __cplusplus
|
||||
|
||||
#include "GUIslice.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
|
||||
// Determine characteristics for configured touch driver
|
||||
// - DRV_TOUCH_TYPE_EXTERNAL: TDrv* external touch APIs are enabled
|
||||
// - DRV_TOUCH_TYPE_RES: Resistive overlay
|
||||
// - DRV_TOUCH_TYPE_CAP: Capacitive overlay
|
||||
// - DRV_TOUCH_TYPE_ANALOG: Analog input
|
||||
#if defined(DRV_TOUCH_URTOUCH)
|
||||
#define DRV_TOUCH_TYPE_EXTERNAL
|
||||
// Don't set DRV_TOUCH_TYPE_RES since URTouch provides its own calibration
|
||||
//#define DRV_TOUCH_TYPE_RES // Resistive
|
||||
#elif defined(DRV_TOUCH_INPUT)
|
||||
#define DRV_TOUCH_TYPE_EXTERNAL
|
||||
#elif defined(DRV_TOUCH_NONE)
|
||||
#endif // DRV_TOUCH_*
|
||||
|
||||
|
||||
// =======================================================================
|
||||
// API support definitions
|
||||
// - These defines indicate whether the driver includes optimized
|
||||
// support for various APIs. If a define is set to 0, then the
|
||||
// GUIslice core emulation will be used instead.
|
||||
// - At the very minimum, the point draw routine must be available:
|
||||
// gslc_DrvDrawPoint()
|
||||
// =======================================================================
|
||||
|
||||
#define DRV_HAS_DRAW_POINT 1 ///< Support gslc_DrvDrawPoint()
|
||||
|
||||
#define DRV_HAS_DRAW_POINTS 0 ///< Support gslc_DrvDrawPoints()
|
||||
#define DRV_HAS_DRAW_LINE 1 ///< Support gslc_DrvDrawLine()
|
||||
#define DRV_HAS_DRAW_RECT_FRAME 1 ///< Support gslc_DrvDrawFrameRect()
|
||||
#define DRV_HAS_DRAW_RECT_FILL 1 ///< Support gslc_DrvDrawFillRect()
|
||||
#define DRV_HAS_DRAW_RECT_ROUND_FRAME 1 ///< Support gslc_DrvDrawFrameRoundRect()
|
||||
#define DRV_HAS_DRAW_RECT_ROUND_FILL 1 ///< Support gslc_DrvDrawFillRoundRect()
|
||||
#define DRV_HAS_DRAW_CIRCLE_FRAME 1 ///< Support gslc_DrvDrawFrameCircle()
|
||||
#define DRV_HAS_DRAW_CIRCLE_FILL 1 ///< Support gslc_DrvDrawFillCircle()
|
||||
#define DRV_HAS_DRAW_TRI_FRAME 0 ///< Support gslc_DrvDrawFrameTriangle()
|
||||
#define DRV_HAS_DRAW_TRI_FILL 0 ///< Support gslc_DrvDrawFillTriangle()
|
||||
#define DRV_HAS_DRAW_TEXT 1 ///< Support gslc_DrvDrawTxt()
|
||||
#define DRV_HAS_DRAW_BMP_MEM 0 ///< Support gslc_DrvDrawBmp24FromMem()
|
||||
|
||||
#define DRV_OVERRIDE_TXT_ALIGN 0 ///< Driver provides text alignment
|
||||
|
||||
// =======================================================================
|
||||
// Driver-specific members
|
||||
// =======================================================================
|
||||
typedef struct {
|
||||
gslc_tsColor nColBkgnd; ///< Background color (if not image-based)
|
||||
|
||||
gslc_tsRect rClipRect; ///< Clipping rectangle
|
||||
|
||||
} gslc_tsDriver;
|
||||
|
||||
|
||||
|
||||
// =======================================================================
|
||||
// Public APIs to GUIslice core library
|
||||
// - These functions define the renderer / driver-dependent
|
||||
// implementations for the core drawing operations within
|
||||
// GUIslice.
|
||||
// =======================================================================
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// Configuration Functions
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
///
|
||||
/// Initialize the SDL library
|
||||
/// - Performs clean startup workaround (if enabled)
|
||||
/// - Configures video mode
|
||||
/// - Initializes font support
|
||||
///
|
||||
/// PRE:
|
||||
/// - The environment variables should be configured before
|
||||
/// calling gslc_DrvInit(). This can be done with gslc_DrvInitEnv()
|
||||
/// or manually in user function.
|
||||
///
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
///
|
||||
/// \return true if success, false if fail
|
||||
///
|
||||
bool gslc_DrvInit(gslc_tsGui* pGui);
|
||||
|
||||
|
||||
///
|
||||
/// Perform any touchscreen-specific initialization
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] acDev: Device path to touchscreen
|
||||
/// eg. "/dev/input/touchscreen"
|
||||
///
|
||||
/// \return true if successful
|
||||
///
|
||||
bool gslc_DrvInitTs(gslc_tsGui* pGui,const char* acDev);
|
||||
|
||||
|
||||
///
|
||||
/// Free up any members associated with the driver
|
||||
/// - Eg. renderers, windows, background surfaces, etc.
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
///
|
||||
/// \return none
|
||||
///
|
||||
void gslc_DrvDestruct(gslc_tsGui* pGui);
|
||||
|
||||
|
||||
///
|
||||
/// Get the display driver name
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
///
|
||||
/// \return String containing driver name
|
||||
///
|
||||
const char* gslc_DrvGetNameDisp(gslc_tsGui* pGui);
|
||||
|
||||
|
||||
///
|
||||
/// Get the touch driver name
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
///
|
||||
/// \return String containing driver name
|
||||
///
|
||||
const char* gslc_DrvGetNameTouch(gslc_tsGui* pGui);
|
||||
|
||||
///
|
||||
/// Get the native display driver instance
|
||||
/// - This can be useful to access special commands
|
||||
/// available in the selected driver.
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
///
|
||||
/// \return Void pointer to the display driver instance.
|
||||
/// This pointer should be typecast to the particular
|
||||
/// driver being used. If no driver was created then
|
||||
/// this function will return NULL.
|
||||
///
|
||||
void* gslc_DrvGetDriverDisp(gslc_tsGui* pGui);
|
||||
|
||||
///
|
||||
/// Get the native touch driver instance
|
||||
/// - This can be useful to access special commands
|
||||
/// available in the selected driver.
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
///
|
||||
/// \return Void pointer to the touch driver instance.
|
||||
/// This pointer should be typecast to the particular
|
||||
/// driver being used. If no driver was created then
|
||||
/// this function will return NULL.
|
||||
///
|
||||
void* gslc_DrvGetDriverTouch(gslc_tsGui* pGui);
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// Image/surface handling Functions
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
|
||||
///
|
||||
/// Load a bitmap (*.bmp) and create a new image resource.
|
||||
/// Transparency is enabled by GSLC_BMP_TRANS_EN
|
||||
/// through use of color (GSLC_BMP_TRANS_RGB).
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] sImgRef: Image reference
|
||||
///
|
||||
/// \return Image pointer (surface/texture) or NULL if error
|
||||
///
|
||||
void* gslc_DrvLoadImage(gslc_tsGui* pGui,gslc_tsImgRef sImgRef);
|
||||
|
||||
|
||||
///
|
||||
/// Configure the background to use a bitmap image
|
||||
/// - The background is used when redrawing the entire page
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] sImgRef: Image reference
|
||||
///
|
||||
/// \return true if success, false if fail
|
||||
///
|
||||
bool gslc_DrvSetBkgndImage(gslc_tsGui* pGui,gslc_tsImgRef sImgRef);
|
||||
|
||||
///
|
||||
/// Configure the background to use a solid color
|
||||
/// - The background is used when redrawing the entire page
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] nCol: RGB Color to use
|
||||
///
|
||||
/// \return true if success, false if fail
|
||||
///
|
||||
bool gslc_DrvSetBkgndColor(gslc_tsGui* pGui,gslc_tsColor nCol);
|
||||
|
||||
///
|
||||
/// Set an element's normal-state image
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] pElem: Pointer to Element to update
|
||||
/// \param[in] sImgRef: Image reference
|
||||
///
|
||||
/// \return true if success, false if error
|
||||
///
|
||||
bool gslc_DrvSetElemImageNorm(gslc_tsGui* pGui,gslc_tsElem* pElem,gslc_tsImgRef sImgRef);
|
||||
|
||||
///
|
||||
/// Set an element's glow-state image
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] pElem: Pointer to Element to update
|
||||
/// \param[in] sImgRef: Image reference
|
||||
///
|
||||
/// \return true if success, false if error
|
||||
///
|
||||
bool gslc_DrvSetElemImageGlow(gslc_tsGui* pGui,gslc_tsElem* pElem,gslc_tsImgRef sImgRef);
|
||||
|
||||
|
||||
///
|
||||
/// Release an image surface
|
||||
///
|
||||
/// \param[in] pvImg: Void ptr to image
|
||||
///
|
||||
/// \return none
|
||||
///
|
||||
void gslc_DrvImageDestruct(void* pvImg);
|
||||
|
||||
|
||||
///
|
||||
/// Set the clipping rectangle for future drawing updates
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] pRect: Rectangular region to constrain edits
|
||||
///
|
||||
/// \return true if success, false if error
|
||||
///
|
||||
bool gslc_DrvSetClipRect(gslc_tsGui* pGui,gslc_tsRect* pRect);
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// Font handling Functions
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
///
|
||||
/// Load a font from a resource and return pointer to it
|
||||
///
|
||||
/// \param[in] eFontRefType: Font reference type (GSLC_FONTREF_PTR for Arduino)
|
||||
/// \param[in] pvFontRef: Font reference pointer (Pointer to the GFXFont array)
|
||||
/// \param[in] nFontSz: Typeface size to use
|
||||
///
|
||||
/// \return Void ptr to driver-specific font if load was successful, NULL otherwise
|
||||
///
|
||||
const void* gslc_DrvFontAdd(gslc_teFontRefType eFontRefType,const void* pvFontRef,uint16_t nFontSz);
|
||||
|
||||
///
|
||||
/// Release all fonts defined in the GUI
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
///
|
||||
/// \return none
|
||||
///
|
||||
void gslc_DrvFontsDestruct(gslc_tsGui* pGui);
|
||||
|
||||
|
||||
///
|
||||
/// Get the extent (width and height) of a text string
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] pFont: Ptr to Font structure
|
||||
/// \param[in] pStr: String to display
|
||||
/// \param[in] eTxtFlags: Flags associated with text string
|
||||
/// \param[out] pnTxtX: Ptr to offset X of text
|
||||
/// \param[out] pnTxtY: Ptr to offset Y of text
|
||||
/// \param[out] pnTxtSzW: Ptr to width of text
|
||||
/// \param[out] pnTxtSzH: Ptr to height of text
|
||||
///
|
||||
/// \return true if success, false if failure
|
||||
///
|
||||
bool gslc_DrvGetTxtSize(gslc_tsGui* pGui,gslc_tsFont* pFont,const char* pStr,gslc_teTxtFlags eTxtFlags,
|
||||
int16_t* pnTxtX,int16_t* pnTxtY,uint16_t* pnTxtSzW,uint16_t* pnTxtSzH);
|
||||
|
||||
|
||||
///
|
||||
/// Draw a text string at the given coordinate
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] nTxtX: X coordinate of top-left text string
|
||||
/// \param[in] nTxtY: Y coordinate of top-left text string
|
||||
/// \param[in] pFont: Ptr to Font
|
||||
/// \param[in] pStr: String to display
|
||||
/// \param[in] eTxtFlags: Flags associated with text string
|
||||
/// \param[in] colTxt: Color to draw text
|
||||
/// \param[in] colBg: unused in ADAGFX, defaults to black
|
||||
///
|
||||
/// \return true if success, false if failure
|
||||
///
|
||||
bool gslc_DrvDrawTxt(gslc_tsGui* pGui,int16_t nTxtX,int16_t nTxtY,gslc_tsFont* pFont,const char* pStr,gslc_teTxtFlags eTxtFlags,gslc_tsColor colTxt,gslc_tsColor colBg);
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// Screen Management Functions
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
///
|
||||
/// Force a page flip to occur. This generally copies active
|
||||
/// screen surface to the display.
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
///
|
||||
/// \return none
|
||||
///
|
||||
void gslc_DrvPageFlipNow(gslc_tsGui* pGui);
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// Graphics Primitives Functions
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
///
|
||||
/// Draw a point
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] nX: X coordinate of point
|
||||
/// \param[in] nY: Y coordinate of point
|
||||
/// \param[in] nCol: Color RGB value to draw
|
||||
///
|
||||
/// \return true if success, false if error
|
||||
///
|
||||
bool gslc_DrvDrawPoint(gslc_tsGui* pGui,int16_t nX,int16_t nY,gslc_tsColor nCol);
|
||||
|
||||
///
|
||||
/// Draw a point
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] asPt: Array of points to draw
|
||||
/// \param[in] nNumPt: Number of points in array
|
||||
/// \param[in] nCol: Color RGB value to draw
|
||||
///
|
||||
/// \return true if success, false if error
|
||||
///
|
||||
bool gslc_DrvDrawPoints(gslc_tsGui* pGui,gslc_tsPt* asPt,uint16_t nNumPt,gslc_tsColor nCol);
|
||||
|
||||
///
|
||||
/// Draw a framed rectangle
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] rRect: Rectangular region to frame
|
||||
/// \param[in] nCol: Color RGB value to frame
|
||||
///
|
||||
/// \return true if success, false if error
|
||||
///
|
||||
bool gslc_DrvDrawFrameRect(gslc_tsGui* pGui,gslc_tsRect rRect,gslc_tsColor nCol);
|
||||
|
||||
|
||||
///
|
||||
/// Draw a filled rectangle
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] rRect: Rectangular region to fill
|
||||
/// \param[in] nCol: Color RGB value to fill
|
||||
///
|
||||
/// \return true if success, false if error
|
||||
///
|
||||
bool gslc_DrvDrawFillRect(gslc_tsGui* pGui,gslc_tsRect rRect,gslc_tsColor nCol);
|
||||
|
||||
|
||||
///
|
||||
/// Draw a framed rounded rectangle
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] rRect: Rectangular region to frame
|
||||
/// \param[in] nRadius: Radius for rounded corners
|
||||
/// \param[in] nCol: Color RGB value to frame
|
||||
///
|
||||
/// \return true if success, false if error
|
||||
///
|
||||
bool gslc_DrvDrawFrameRoundRect(gslc_tsGui* pGui,gslc_tsRect rRect,int16_t nRadius,gslc_tsColor nCol);
|
||||
|
||||
|
||||
///
|
||||
/// Draw a filled rounded rectangle
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] rRect: Rectangular region to fill
|
||||
/// \param[in] nRadius: Radius for rounded corners
|
||||
/// \param[in] nCol: Color RGB value to fill
|
||||
///
|
||||
/// \return true if success, false if error
|
||||
///
|
||||
bool gslc_DrvDrawFillRoundRect(gslc_tsGui* pGui,gslc_tsRect rRect,int16_t nRadius,gslc_tsColor nCol);
|
||||
|
||||
|
||||
|
||||
///
|
||||
/// Draw a line
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] nX0: Line start (X coordinate)
|
||||
/// \param[in] nY0: Line start (Y coordinate)
|
||||
/// \param[in] nX1: Line finish (X coordinate)
|
||||
/// \param[in] nY1: Line finish (Y coordinate)
|
||||
/// \param[in] nCol: Color RGB value to draw
|
||||
///
|
||||
/// \return true if success, false if error
|
||||
///
|
||||
bool gslc_DrvDrawLine(gslc_tsGui* pGui,int16_t nX0,int16_t nY0,int16_t nX1,int16_t nY1,gslc_tsColor nCol);
|
||||
|
||||
|
||||
///
|
||||
/// Draw a framed circle
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] nMidX: Center of circle (X coordinate)
|
||||
/// \param[in] nMidY: Center of circle (Y coordinate)
|
||||
/// \param[in] nRadius: Radius of circle
|
||||
/// \param[in] nCol: Color RGB value to frame
|
||||
///
|
||||
/// \return true if success, false if error
|
||||
///
|
||||
bool gslc_DrvDrawFrameCircle(gslc_tsGui* pGui,int16_t nMidX,int16_t nMidY,uint16_t nRadius,gslc_tsColor nCol);
|
||||
|
||||
|
||||
///
|
||||
/// Draw a filled circle
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] nMidX: Center of circle (X coordinate)
|
||||
/// \param[in] nMidY: Center of circle (Y coordinate)
|
||||
/// \param[in] nRadius: Radius of circle
|
||||
/// \param[in] nCol: Color RGB value to fill
|
||||
///
|
||||
/// \return true if success, false if error
|
||||
///
|
||||
bool gslc_DrvDrawFillCircle(gslc_tsGui* pGui,int16_t nMidX,int16_t nMidY,uint16_t nRadius,gslc_tsColor nCol);
|
||||
|
||||
|
||||
///
|
||||
/// Draw a framed triangle
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] nX0: X Coordinate #1
|
||||
/// \param[in] nY0: Y Coordinate #1
|
||||
/// \param[in] nX1: X Coordinate #2
|
||||
/// \param[in] nY1: Y Coordinate #2
|
||||
/// \param[in] nX2: X Coordinate #3
|
||||
/// \param[in] nY2: Y Coordinate #3
|
||||
/// \param[in] nCol: Color RGB value to frame
|
||||
///
|
||||
/// \return true if success, false if error
|
||||
///
|
||||
bool gslc_DrvDrawFrameTriangle(gslc_tsGui* pGui,int16_t nX0,int16_t nY0,
|
||||
int16_t nX1,int16_t nY1,int16_t nX2,int16_t nY2,gslc_tsColor nCol);
|
||||
|
||||
|
||||
///
|
||||
/// Draw a filled triangle
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] nX0: X Coordinate #1
|
||||
/// \param[in] nY0: Y Coordinate #1
|
||||
/// \param[in] nX1: X Coordinate #2
|
||||
/// \param[in] nY1: Y Coordinate #2
|
||||
/// \param[in] nX2: X Coordinate #3
|
||||
/// \param[in] nY2: Y Coordinate #3
|
||||
/// \param[in] nCol: Color RGB value to fill
|
||||
///
|
||||
/// \return true if success, false if error
|
||||
///
|
||||
bool gslc_DrvDrawFillTriangle(gslc_tsGui* pGui,int16_t nX0,int16_t nY0,
|
||||
int16_t nX1,int16_t nY1,int16_t nX2,int16_t nY2,gslc_tsColor nCol);
|
||||
|
||||
|
||||
///
|
||||
/// Copy all of source image to destination screen at specified coordinate
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] nDstX: Destination X coord for copy
|
||||
/// \param[in] nDstY: Destination Y coord for copy
|
||||
/// \param[in] sImgRef: Image reference
|
||||
///
|
||||
/// \return true if success, false if fail
|
||||
///
|
||||
bool gslc_DrvDrawImage(gslc_tsGui* pGui,int16_t nDstX,int16_t nDstY,gslc_tsImgRef sImgRef);
|
||||
|
||||
|
||||
///
|
||||
/// Draw a monochrome bitmap from a memory array
|
||||
/// - Draw from the bitmap buffer using the foreground color
|
||||
/// defined in the header (unset bits are transparent)
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] nDstX: Destination X coord for copy
|
||||
/// \param[in] nDstY: Destination Y coord for copy
|
||||
/// \param[in] pBitmap: Pointer to bitmap buffer
|
||||
/// \param[in] bProgMem: Bitmap is stored in Flash if true, RAM otherwise
|
||||
///
|
||||
/// \return none
|
||||
///
|
||||
void gslc_DrvDrawMonoFromMem(gslc_tsGui* pGui,int16_t nDstX, int16_t nDstY, const unsigned char *pBitmap,bool bProgMem);
|
||||
|
||||
|
||||
///
|
||||
/// Draw a color 24-bit depth bitmap from a memory array
|
||||
/// - Note that users must convert images from their native
|
||||
/// format (eg. BMP, PNG, etc.) into a C array. Please
|
||||
/// refer to the following guide for details:
|
||||
/// https://github.com/ImpulseAdventure/GUIslice/wiki/Display-Images-from-FLASH
|
||||
/// - The converted file (c array) can then be included in the sketch.
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] nDstX: X coord for copy
|
||||
/// \param[in] nDstY: Y coord for copy
|
||||
/// \param[in] pBitmap: Pointer to bitmap buffer
|
||||
/// \param[in] bProgMem: Bitmap is stored in Flash if true, RAM otherwise
|
||||
///
|
||||
/// \return none
|
||||
///
|
||||
void gslc_DrvDrawBmp24FromMem(gslc_tsGui* pGui,int16_t nDstX, int16_t nDstY,const unsigned char* pBitmap,bool bProgMem);
|
||||
|
||||
///
|
||||
/// Copy the background image to destination screen
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
///
|
||||
/// \return true if success, false if fail
|
||||
///
|
||||
void gslc_DrvDrawBkgnd(gslc_tsGui* pGui);
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// Touch Functions (if using display driver library)
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
///
|
||||
/// Perform any touchscreen-specific initialization
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] acDev: Device path to touchscreen
|
||||
/// eg. "/dev/input/touchscreen"
|
||||
///
|
||||
/// \return true if successful
|
||||
///
|
||||
bool gslc_DrvInitTouch(gslc_tsGui* pGui,const char* acDev);
|
||||
|
||||
|
||||
///
|
||||
/// Get the last touch event from the internal touch handler
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[out] pnX: Ptr to X coordinate of last touch event
|
||||
/// \param[out] pnY: Ptr to Y coordinate of last touch event
|
||||
/// \param[out] pnPress: Ptr to Pressure level of last touch event (0 for none, 1 for touch)
|
||||
/// \param[out] peInputEvent Indication of event type
|
||||
/// \param[out] pnInputVal Additional data for event type
|
||||
///
|
||||
/// \return true if an event was detected or false otherwise
|
||||
///
|
||||
bool gslc_DrvGetTouch(gslc_tsGui* pGui,int16_t* pnX,int16_t* pnY,uint16_t* pnPress,gslc_teInputRawEvent* peInputEvent,int16_t* pnInputVal);
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// Touch Functions (if using external touch driver library)
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
|
||||
#if defined(DRV_TOUCH_TYPE_EXTERNAL)
|
||||
///
|
||||
/// Perform any touchscreen-specific initialization
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] acDev: Device path to touchscreen
|
||||
/// eg. "/dev/input/touchscreen"
|
||||
///
|
||||
/// \return true if successful
|
||||
///
|
||||
bool gslc_TDrvInitTouch(gslc_tsGui* pGui,const char* acDev);
|
||||
|
||||
|
||||
///
|
||||
/// Get the last touch event from the SDL_Event handler
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[out] pnX: Ptr to X coordinate of last touch event
|
||||
/// \param[out] pnY: Ptr to Y coordinate of last touch event
|
||||
/// \param[out] pnPress: Ptr to Pressure level of last touch event (0 for none, 1 for touch)
|
||||
/// \param[out] peInputEvent Indication of event type
|
||||
/// \param[out] pnInputVal Additional data for event type
|
||||
///
|
||||
/// \return true if an event was detected or false otherwise
|
||||
///
|
||||
bool gslc_TDrvGetTouch(gslc_tsGui* pGui, int16_t* pnX, int16_t* pnY, uint16_t* pnPress, gslc_teInputRawEvent* peInputEvent, int16_t* pnInputVal);
|
||||
|
||||
#endif // DRV_TOUCH_*
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// Dynamic Screen rotation and Touch axes swap/flip functions
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
///
|
||||
/// Change rotation, automatically adapt touchscreen axes swap/flip
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] nRotation: Screen Rotation value (0, 1, 2 or 3)
|
||||
///
|
||||
/// \return true if successful
|
||||
///
|
||||
bool gslc_DrvRotate(gslc_tsGui* pGui, uint8_t nRotation);
|
||||
|
||||
|
||||
// =======================================================================
|
||||
// Private Functions
|
||||
// - These functions are not included in the scope of APIs used by
|
||||
// the core GUIslice library. Instead, these functions are used
|
||||
// to support the operations within this driver layer.
|
||||
// =======================================================================
|
||||
|
||||
uint16_t gslc_DrvAdaptColorToRaw(gslc_tsColor nCol);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif // __cplusplus
|
||||
#endif // _GUISLICE_DRV_ADAGFX_H_
|
52
src/guislice/GUIslice_ex.h
Normal file
52
src/guislice/GUIslice_ex.h
Normal file
|
@ -0,0 +1,52 @@
|
|||
#ifndef _GUISLICE_EX_H_
|
||||
#define _GUISLICE_EX_H_
|
||||
|
||||
#include "GUIslice.h"
|
||||
|
||||
|
||||
// =======================================================================
|
||||
// GUIslice library (extensions)
|
||||
// - Calvin Hass
|
||||
// - https://www.impulseadventure.com/elec/guislice-gui.html
|
||||
// - https://github.com/ImpulseAdventure/GUIslice
|
||||
// =======================================================================
|
||||
//
|
||||
// The MIT License
|
||||
//
|
||||
// Copyright 2016-2020 Calvin Hass
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
//
|
||||
// =======================================================================
|
||||
/// \file GUIslice_ex.h
|
||||
|
||||
// Provide backwards compatibility until we have removed GUIslice_ex
|
||||
#include "XCheckbox.h"
|
||||
#include "XGauge.h"
|
||||
#include "XGraph.h"
|
||||
#include "XSelNum.h"
|
||||
#include "XSlider.h"
|
||||
#include "XTextbox.h"
|
||||
|
||||
// Warn users that they should update their includes
|
||||
// #warning "NOTE: Please replace `GUIslice_ex` per https://github.com/ImpulseAdventure/GUIslice/wiki/Note-_-Include-Extended-Elements"
|
||||
|
||||
|
||||
#endif // _GUISLICE_EX_H_
|
||||
|
119
src/guislice/GUIslice_th.cpp
Normal file
119
src/guislice/GUIslice_th.cpp
Normal file
|
@ -0,0 +1,119 @@
|
|||
// Abstract touch handler (TH) class
|
||||
// This is the abstract base class for creating specific touch handlers
|
||||
// The touch handler performs the adaption in between the GUIslice framework and any touch driver
|
||||
// The touch handler used is specified in the main program by calling gslc_InitTouchHandler(&touchHandler);
|
||||
|
||||
/// \file GUIslice_th.cpp
|
||||
|
||||
#include "GUIslice_th.h"
|
||||
|
||||
|
||||
///////////////////////////////////////////////////
|
||||
// Point x,y,z Class for usage in the touch handler
|
||||
|
||||
THPoint::THPoint(void) {
|
||||
x = y = z = 0;
|
||||
}
|
||||
|
||||
THPoint::THPoint(uint16_t x0, uint16_t y0, uint16_t z0) {
|
||||
x = x0;
|
||||
y = y0;
|
||||
z = z0;
|
||||
}
|
||||
|
||||
bool THPoint::operator==(THPoint p1) {
|
||||
return ((p1.x == x) && (p1.y == y) && (p1.z == z));
|
||||
}
|
||||
|
||||
bool THPoint::operator!=(THPoint p1) {
|
||||
return ((p1.x != x) || (p1.y != y) || (p1.z != z));
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////
|
||||
// Abstract TouchHandler - you have to inherit this
|
||||
|
||||
void TouchHandler::setSize(uint16_t _disp_xSize, uint16_t _disp_ySize)
|
||||
{
|
||||
disp_xSize = _disp_xSize;
|
||||
disp_ySize = _disp_ySize;
|
||||
}
|
||||
|
||||
void TouchHandler::setCalibration(uint16_t _ts_xMin, uint16_t _ts_xMax, uint16_t _ts_yMin, uint16_t _ts_yMax)
|
||||
{
|
||||
ts_xMin = _ts_xMin;
|
||||
ts_xMax = _ts_xMax;
|
||||
ts_yMin = _ts_yMin;
|
||||
ts_yMax = _ts_yMax;
|
||||
}
|
||||
|
||||
void TouchHandler::setSwapFlip(bool _swapXY,bool _flipX,bool _flipY)
|
||||
{
|
||||
swapXY = _swapXY;
|
||||
flipX = _flipX;
|
||||
flipY = _flipY;
|
||||
}
|
||||
|
||||
THPoint TouchHandler::scale(THPoint pIn)
|
||||
{
|
||||
THPoint pOut;
|
||||
|
||||
pOut.x = map(pIn.x, ts_xMin,ts_xMax, 0,disp_xSize);
|
||||
pOut.y = map(pIn.y, ts_yMin,ts_yMax, 0,disp_ySize);
|
||||
pOut.z = pIn.z;
|
||||
|
||||
pOut.x = constrain(pOut.x,0,disp_xSize-1);
|
||||
pOut.y = constrain(pOut.y,0,disp_ySize-1);
|
||||
pOut.z = constrain(pOut.z,0,4095);
|
||||
|
||||
if (swapXY)
|
||||
{
|
||||
uint16_t x = pOut.x;
|
||||
pOut.x = pOut.y;
|
||||
pOut.y = x;
|
||||
}
|
||||
|
||||
if (flipX)
|
||||
pOut.x = ( (!swapXY) ? disp_xSize-1 : disp_ySize-1 ) - pOut.x;
|
||||
|
||||
if (flipY)
|
||||
pOut.y = ( (!swapXY) ? disp_ySize-1 : disp_xSize-1 ) - pOut.y;
|
||||
|
||||
//Serial.print("disp_xSize= ");Serial.println(disp_xSize);
|
||||
|
||||
return pOut;
|
||||
}
|
||||
|
||||
|
||||
// overwrite this with your code to add initialisation of the touch driver used
|
||||
void TouchHandler::begin(void) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// overwrite this with your code to return the scaled touch coordinates
|
||||
THPoint TouchHandler::getPoint(void) {
|
||||
return THPoint();
|
||||
}
|
||||
|
||||
|
||||
/////////////////////////////////
|
||||
// init and set the touch handler
|
||||
|
||||
// Pointer to touch handler used by GUIslice
|
||||
TouchHandler *pTouchHandler = NULL; // NULL => no handler is available
|
||||
|
||||
// Init and set the touch hander
|
||||
void gslc_InitTouchHandler(TouchHandler *pTH) {
|
||||
//begin
|
||||
pTH->begin();
|
||||
//set the touch handler to be used by GUIslice_drv_...
|
||||
pTouchHandler = pTH;
|
||||
}
|
||||
|
||||
// Get the touch handler
|
||||
TouchHandler* gslc_getTouchHandler(void)
|
||||
{
|
||||
return pTouchHandler;
|
||||
}
|
||||
|
71
src/guislice/GUIslice_th.h
Normal file
71
src/guislice/GUIslice_th.h
Normal file
|
@ -0,0 +1,71 @@
|
|||
// Abstract touch handler (TH) class
|
||||
// This is the abstract base class for creating specific touch handlers
|
||||
// The touch handler performs the adaption in between the GUIslice framework and any touch driver
|
||||
// The touch handler used is specified in the main program by calling gslc_InitTouchHandler(&touchHandler);
|
||||
|
||||
/// \file GUIslice_th.h
|
||||
|
||||
#ifndef _GUISLICE_TH_H_
|
||||
#define _GUISLICE_TH_H_
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
///////////////////////////////////////////////////
|
||||
// Point x,y,z Class for usage in the touch handler
|
||||
|
||||
class THPoint {
|
||||
public:
|
||||
THPoint(void);
|
||||
THPoint(uint16_t x, uint16_t y, uint16_t z);
|
||||
|
||||
bool operator==(THPoint);
|
||||
bool operator!=(THPoint);
|
||||
|
||||
uint16_t x, y, z;
|
||||
};
|
||||
|
||||
|
||||
///////////////////////////////////////////////////
|
||||
// Abstract TouchHandler - you have to inherit this
|
||||
|
||||
class TouchHandler {
|
||||
public:
|
||||
//in order to create a specific touch handler you have to write your own constructor
|
||||
TouchHandler() {};
|
||||
|
||||
void setSize(uint16_t _disp_xSize, uint16_t _disp_ySize);
|
||||
void setCalibration(uint16_t ts_xMin, uint16_t ts_xMax, uint16_t ts_yMin, uint16_t ts_yMax);
|
||||
//order of operations: map, swap, constraint, flip
|
||||
void setSwapFlip(bool _swapXY,bool _flipX,bool _flipY);
|
||||
|
||||
THPoint scale(THPoint pIn);
|
||||
|
||||
//in order to create a specific touch handler you have to overwrite this methods
|
||||
virtual void begin(void);
|
||||
virtual THPoint getPoint(void);
|
||||
|
||||
private:
|
||||
//landscape perspective: x: width, y: heigth
|
||||
uint16_t disp_xSize = 320;
|
||||
uint16_t disp_ySize = 240;
|
||||
|
||||
uint16_t ts_xMin = 0;
|
||||
uint16_t ts_xMax = 4095;
|
||||
uint16_t ts_yMin = 0;
|
||||
uint16_t ts_yMax = 4095;
|
||||
|
||||
bool swapXY = false;
|
||||
bool flipX = false;
|
||||
bool flipY = false;
|
||||
};
|
||||
|
||||
|
||||
|
||||
/////////////////////////////////
|
||||
// init and set the touch handler
|
||||
|
||||
void gslc_InitTouchHandler(TouchHandler *pTHO);
|
||||
TouchHandler* gslc_getTouchHandler(void);
|
||||
|
||||
|
||||
#endif
|
52
src/guislice/GUIslice_th_XPT2046.h
Normal file
52
src/guislice/GUIslice_th_XPT2046.h
Normal file
|
@ -0,0 +1,52 @@
|
|||
// touch handler (TH) for XPT2046 using the arduino built in driver <XPT2046_touch.h>
|
||||
|
||||
// The touch handler performs the adaption in between the GUIslice framework and any touch driver
|
||||
// The touch handler used is specified in the main program by calling gslc_InitTouchHandler(&touchHandler);
|
||||
|
||||
/// \file GUIslice_th_XPT2046.h
|
||||
|
||||
#ifndef _GUISLICE_TH_XPT2046_H_
|
||||
#define _GUISLICE_TH_XPT2046_H_
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <GUIslice_th.h>
|
||||
#include <XPT2046_touch.h>
|
||||
|
||||
class TouchHandler_XPT2046: public TouchHandler {
|
||||
public:
|
||||
// parameters:
|
||||
// spi object to be used
|
||||
// chip select pin for spi
|
||||
TouchHandler_XPT2046(SPIClass &spi, uint8_t spi_cs_pin) : spi(spi), touchDriver(XPT2046_touch(spi_cs_pin, spi)) {
|
||||
//empirical calibration values, can be updated by calling setCalibration in the user program
|
||||
setCalibration(398,3877,280,3805);
|
||||
//swapping and flipping to adopt to default GUIslice orientation
|
||||
setSwapFlip(true,false,true);
|
||||
}
|
||||
|
||||
//begin is called by gslc_InitTouchHandler
|
||||
void begin(void) {
|
||||
//init the touch driver
|
||||
touchDriver.begin();
|
||||
}
|
||||
|
||||
//this method returns the scaled point provided by the touch driver
|
||||
THPoint getPoint(void) {
|
||||
//get the coordinates from the touch driver
|
||||
TS_Point pt = touchDriver.getPoint();
|
||||
//Serial.print("pt= ");Serial.print(pt.x);Serial.print(",");Serial.print(pt.y);Serial.print(",");Serial.println(pt.z);
|
||||
|
||||
//perform scaling (this includes swapping and flipping)
|
||||
THPoint ps = scale( THPoint(pt.x,pt.y,pt.z) );
|
||||
//Serial.print("ps= ");Serial.print(ps.x);Serial.print(",");Serial.print(ps.y);Serial.print(",");Serial.println(ps.z);
|
||||
|
||||
return ps;
|
||||
};
|
||||
|
||||
SPIClass spi;
|
||||
XPT2046_touch touchDriver;
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif
|
42
src/guislice/GUIslice_version.h
Normal file
42
src/guislice/GUIslice_version.h
Normal file
|
@ -0,0 +1,42 @@
|
|||
#ifndef _GUISLICE_VERSION_H_
|
||||
#define _GUISLICE_VERSION_H_
|
||||
|
||||
// =======================================================================
|
||||
// GUIslice library (version control)
|
||||
// - Calvin Hass
|
||||
// - https://www.impulseadventure.com/elec/guislice-gui.html
|
||||
// - https://github.com/ImpulseAdventure/GUIslice
|
||||
// =======================================================================
|
||||
//
|
||||
// The MIT License
|
||||
//
|
||||
// Copyright 2016-2020 Calvin Hass
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
//
|
||||
// =======================================================================
|
||||
|
||||
// =======================================================================
|
||||
// Define current release (X.Y.Z) & build number
|
||||
// =======================================================================
|
||||
|
||||
#define GUISLICE_VER "0.15.0"
|
||||
|
||||
#endif // _GUISLICE_VERSION_H_
|
||||
|
185
src/guislice/NotoMono8pt7b.h
Normal file
185
src/guislice/NotoMono8pt7b.h
Normal file
|
@ -0,0 +1,185 @@
|
|||
const uint8_t NotoMono8pt7bBitmaps[] PROGMEM = {
|
||||
0x00, 0xFF, 0xFD, 0x0F, 0xCF, 0x3C, 0xF3, 0x08, 0x86, 0x61, 0x11, 0xFF,
|
||||
0x11, 0x0C, 0xC2, 0x23, 0xFE, 0x22, 0x08, 0x84, 0x41, 0x10, 0x10, 0x21,
|
||||
0xFE, 0x89, 0x1A, 0x1C, 0x0E, 0x16, 0x26, 0x5F, 0xE1, 0x02, 0x00, 0x71,
|
||||
0xA2, 0x48, 0xB2, 0x28, 0x74, 0x01, 0x00, 0x80, 0x2E, 0x14, 0x4D, 0x12,
|
||||
0x45, 0x8E, 0x38, 0x36, 0x11, 0x08, 0x82, 0x81, 0x89, 0xE5, 0x96, 0x86,
|
||||
0x63, 0x33, 0xCF, 0x30, 0xFF, 0x11, 0x98, 0x8C, 0x63, 0x10, 0xC6, 0x30,
|
||||
0x86, 0x18, 0x40, 0x43, 0x0C, 0x21, 0x8C, 0x61, 0x18, 0xC6, 0x23, 0x31,
|
||||
0x00, 0x10, 0x22, 0x4F, 0xF2, 0x8D, 0x99, 0x00, 0x10, 0x20, 0x47, 0xF1,
|
||||
0x02, 0x04, 0x00, 0x6F, 0x60, 0xFC, 0xF0, 0x0C, 0x20, 0x86, 0x10, 0xC3,
|
||||
0x08, 0x61, 0x04, 0x30, 0x3C, 0x66, 0x42, 0xC3, 0xC3, 0x81, 0x81, 0xC3,
|
||||
0xC3, 0x42, 0x66, 0x3C, 0x37, 0xD1, 0x11, 0x11, 0x11, 0x11, 0x3C, 0xE3,
|
||||
0x03, 0x01, 0x03, 0x02, 0x04, 0x08, 0x10, 0x20, 0xC0, 0xFF, 0x7E, 0xC3,
|
||||
0x03, 0x03, 0x06, 0x38, 0x06, 0x03, 0x01, 0x03, 0x86, 0xFC, 0x06, 0x07,
|
||||
0x02, 0x83, 0x43, 0x21, 0x11, 0x09, 0x84, 0xFF, 0x81, 0x00, 0x80, 0x40,
|
||||
0xFE, 0xC0, 0xC0, 0x80, 0x80, 0xFC, 0x06, 0x03, 0x01, 0x03, 0x86, 0xFC,
|
||||
0x1E, 0x30, 0x40, 0xC0, 0xFC, 0xE2, 0xC3, 0x81, 0xC1, 0xC3, 0x66, 0x3C,
|
||||
0xFF, 0x03, 0x02, 0x02, 0x06, 0x04, 0x0C, 0x0C, 0x18, 0x18, 0x10, 0x30,
|
||||
0x3C, 0xC3, 0x81, 0xC3, 0x46, 0x3C, 0x66, 0xC3, 0x81, 0xC3, 0xC2, 0x3C,
|
||||
0x3C, 0x66, 0xC3, 0x83, 0x81, 0xC3, 0x47, 0x3F, 0x03, 0x02, 0x04, 0x78,
|
||||
0xF0, 0x03, 0xC0, 0x6C, 0x00, 0x03, 0x7B, 0x00, 0x01, 0x06, 0x38, 0xE0,
|
||||
0xE0, 0x38, 0x06, 0x01, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x80, 0x60, 0x1C,
|
||||
0x07, 0x07, 0x1C, 0x60, 0x80, 0x7C, 0xC3, 0x03, 0x01, 0x03, 0x06, 0x18,
|
||||
0x10, 0x30, 0x00, 0x30, 0x30, 0x1E, 0x08, 0x64, 0x09, 0x79, 0x92, 0x68,
|
||||
0x9A, 0x26, 0x89, 0xA6, 0xF7, 0x64, 0x00, 0x80, 0x1F, 0x00, 0x0C, 0x03,
|
||||
0x01, 0xE0, 0x48, 0x12, 0x0C, 0xC2, 0x10, 0xFC, 0x61, 0x90, 0x24, 0x0B,
|
||||
0x03, 0xFE, 0x87, 0x83, 0x83, 0x83, 0xFC, 0x86, 0x83, 0x83, 0x83, 0x86,
|
||||
0xFC, 0x1F, 0x73, 0x60, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0x60, 0x71,
|
||||
0x1F, 0xF8, 0x8E, 0x82, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x86, 0x8C,
|
||||
0xF8, 0xFF, 0x02, 0x04, 0x08, 0x1F, 0xE0, 0x40, 0x81, 0x02, 0x07, 0xF0,
|
||||
0xFF, 0x02, 0x04, 0x08, 0x1F, 0xE0, 0x40, 0x81, 0x02, 0x04, 0x00, 0x1E,
|
||||
0x72, 0x40, 0xC0, 0xC0, 0xC7, 0xC1, 0xC1, 0xC1, 0x41, 0x73, 0x3F, 0x81,
|
||||
0x81, 0x81, 0x81, 0x81, 0xFF, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0xFC,
|
||||
0x82, 0x08, 0x20, 0x82, 0x08, 0x20, 0x82, 0x3F, 0x02, 0x04, 0x08, 0x10,
|
||||
0x20, 0x40, 0x81, 0x02, 0x0E, 0x37, 0xC0, 0x81, 0xC1, 0xA1, 0x91, 0x89,
|
||||
0x85, 0x83, 0x61, 0x18, 0x84, 0x43, 0x20, 0xD0, 0x30, 0x80, 0x80, 0x80,
|
||||
0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0xFF, 0xC3, 0xC3, 0xC3,
|
||||
0xC3, 0xA5, 0xA5, 0xA5, 0xA5, 0x99, 0x99, 0x99, 0x91, 0xC1, 0xC1, 0xA1,
|
||||
0xA1, 0x91, 0x91, 0x89, 0x89, 0x85, 0x85, 0x83, 0x83, 0x3C, 0x66, 0x42,
|
||||
0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0x42, 0x66, 0x3C, 0xFC, 0x86, 0x83,
|
||||
0x83, 0x83, 0x82, 0xFC, 0x80, 0x80, 0x80, 0x80, 0x80, 0x3C, 0x66, 0x42,
|
||||
0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0x42, 0x66, 0x3C, 0x04, 0x02, 0x01,
|
||||
0xFC, 0x43, 0x20, 0xD0, 0x68, 0x34, 0x13, 0xF1, 0x18, 0x86, 0x41, 0x20,
|
||||
0xD0, 0x30, 0x3F, 0xE3, 0xC0, 0xC0, 0xC0, 0x78, 0x0E, 0x03, 0x01, 0x03,
|
||||
0x86, 0xFC, 0xFF, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
|
||||
0x10, 0x10, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0xC3, 0xC3,
|
||||
0x66, 0x3C, 0xC0, 0xD0, 0x24, 0x09, 0x86, 0x21, 0x08, 0x43, 0x30, 0x48,
|
||||
0x12, 0x07, 0x80, 0xC0, 0x30, 0x80, 0x70, 0x1C, 0x0F, 0x03, 0x4C, 0x93,
|
||||
0x24, 0xC9, 0x4A, 0x52, 0x94, 0xA6, 0x18, 0x84, 0xC0, 0xD8, 0x62, 0x10,
|
||||
0xCC, 0x1E, 0x03, 0x00, 0xC0, 0x78, 0x33, 0x08, 0x44, 0x1B, 0x03, 0xC0,
|
||||
0x90, 0x66, 0x10, 0x88, 0x12, 0x05, 0x00, 0xC0, 0x20, 0x08, 0x02, 0x00,
|
||||
0x80, 0x20, 0xFF, 0x03, 0x02, 0x04, 0x0C, 0x08, 0x10, 0x30, 0x20, 0x40,
|
||||
0xC0, 0xFF, 0xF8, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0xF0, 0xC1, 0x04,
|
||||
0x18, 0x20, 0xC3, 0x04, 0x18, 0x20, 0x83, 0xF1, 0x11, 0x11, 0x11, 0x11,
|
||||
0x11, 0x11, 0xF0, 0x18, 0x18, 0x24, 0x24, 0x46, 0x42, 0x83, 0xFF, 0xC0,
|
||||
0xC8, 0x80, 0x7E, 0x43, 0x03, 0x01, 0x3F, 0xC1, 0x83, 0xC7, 0x7D, 0x80,
|
||||
0x80, 0x80, 0x80, 0xBC, 0xE6, 0xC3, 0x83, 0x81, 0x83, 0xC3, 0xE6, 0xBC,
|
||||
0x3F, 0x61, 0xC0, 0xC0, 0x80, 0xC0, 0xC0, 0x61, 0x3F, 0x01, 0x01, 0x01,
|
||||
0x01, 0x3D, 0x67, 0xC3, 0xC1, 0x81, 0xC1, 0xC3, 0x67, 0x3D, 0x3C, 0x66,
|
||||
0xC3, 0xC1, 0xFF, 0x80, 0xC0, 0x61, 0x3E, 0x1E, 0x60, 0x81, 0x0F, 0xC4,
|
||||
0x08, 0x10, 0x20, 0x40, 0x81, 0x02, 0x00, 0x3F, 0xB1, 0x90, 0x48, 0x26,
|
||||
0x31, 0xF1, 0x80, 0x80, 0x7F, 0x60, 0xE0, 0x38, 0x37, 0xE0, 0x80, 0x80,
|
||||
0x80, 0x80, 0xBE, 0xE3, 0xC3, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x10,
|
||||
0x20, 0x00, 0x07, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x8F, 0xE0, 0x0C,
|
||||
0x30, 0x00, 0x7C, 0x10, 0x41, 0x04, 0x10, 0x41, 0x04, 0x10, 0x43, 0xF8,
|
||||
0x80, 0x80, 0x80, 0x80, 0x84, 0x88, 0x90, 0xA0, 0xE0, 0x90, 0x88, 0x84,
|
||||
0x86, 0x70, 0x20, 0x40, 0x81, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x8F,
|
||||
0xE0, 0xB6, 0xDB, 0xD9, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0xBE, 0xE3,
|
||||
0xC3, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x3C, 0x66, 0xC3, 0xC3, 0x81,
|
||||
0xC3, 0xC3, 0x66, 0x3C, 0xBC, 0xE6, 0xC3, 0x83, 0x81, 0x83, 0xC3, 0xE6,
|
||||
0xBC, 0x80, 0x80, 0x80, 0x80, 0x3D, 0x67, 0xC3, 0xC1, 0x81, 0xC1, 0xC3,
|
||||
0x67, 0x3D, 0x01, 0x01, 0x01, 0x01, 0x9F, 0x47, 0x04, 0x08, 0x10, 0x20,
|
||||
0x40, 0x80, 0x7F, 0x18, 0x38, 0x38, 0x30, 0x63, 0xF8, 0x20, 0x43, 0xF9,
|
||||
0x02, 0x04, 0x08, 0x10, 0x20, 0x60, 0x78, 0x81, 0x81, 0x81, 0x81, 0x81,
|
||||
0x81, 0xC3, 0xC7, 0x7D, 0xC3, 0x42, 0x42, 0x66, 0x24, 0x24, 0x3C, 0x18,
|
||||
0x18, 0x8C, 0x73, 0x34, 0xC9, 0x7A, 0x52, 0x94, 0xA5, 0x28, 0x8C, 0x21,
|
||||
0x00, 0x43, 0x66, 0x24, 0x18, 0x18, 0x3C, 0x24, 0x66, 0xC3, 0xC3, 0x42,
|
||||
0x42, 0x66, 0x24, 0x24, 0x3C, 0x18, 0x18, 0x18, 0x10, 0x30, 0xE0, 0xFC,
|
||||
0x30, 0x84, 0x30, 0x84, 0x30, 0xFC, 0x1C, 0xC2, 0x08, 0x20, 0x82, 0x30,
|
||||
0x60, 0x82, 0x08, 0x20, 0xC1, 0xC0, 0xFF, 0xFF, 0x80, 0xE0, 0xC1, 0x04,
|
||||
0x10, 0x41, 0x03, 0x18, 0x41, 0x04, 0x10, 0xCE, 0x00, 0x70, 0x99, 0x0E };
|
||||
|
||||
const GFXglyph NotoMono8pt7bGlyphs[] PROGMEM = {
|
||||
{ 0, 1, 1, 10, 0, 0 }, // 0x20 ' '
|
||||
{ 1, 2, 12, 10, 4, -11 }, // 0x21 '!'
|
||||
{ 4, 6, 4, 10, 2, -11 }, // 0x22 '"'
|
||||
{ 7, 10, 12, 10, 0, -11 }, // 0x23 '#'
|
||||
{ 22, 7, 14, 10, 2, -12 }, // 0x24 '$'
|
||||
{ 35, 10, 12, 10, 0, -11 }, // 0x25 '%'
|
||||
{ 50, 9, 12, 10, 1, -11 }, // 0x26 '&'
|
||||
{ 64, 2, 4, 10, 4, -11 }, // 0x27 '''
|
||||
{ 65, 5, 15, 10, 3, -11 }, // 0x28 '('
|
||||
{ 75, 5, 15, 10, 2, -11 }, // 0x29 ')'
|
||||
{ 85, 7, 7, 10, 1, -12 }, // 0x2A '*'
|
||||
{ 92, 7, 7, 10, 1, -8 }, // 0x2B '+'
|
||||
{ 99, 3, 4, 10, 3, -1 }, // 0x2C ','
|
||||
{ 101, 6, 1, 10, 2, -4 }, // 0x2D '-'
|
||||
{ 102, 2, 2, 10, 4, -1 }, // 0x2E '.'
|
||||
{ 103, 6, 12, 10, 2, -11 }, // 0x2F '/'
|
||||
{ 112, 8, 12, 10, 1, -11 }, // 0x30 '0'
|
||||
{ 124, 4, 12, 10, 2, -11 }, // 0x31 '1'
|
||||
{ 130, 8, 12, 10, 1, -11 }, // 0x32 '2'
|
||||
{ 142, 8, 12, 10, 1, -11 }, // 0x33 '3'
|
||||
{ 154, 9, 12, 10, 1, -11 }, // 0x34 '4'
|
||||
{ 168, 8, 12, 10, 1, -11 }, // 0x35 '5'
|
||||
{ 180, 8, 12, 10, 1, -11 }, // 0x36 '6'
|
||||
{ 192, 8, 12, 10, 1, -11 }, // 0x37 '7'
|
||||
{ 204, 8, 12, 10, 1, -11 }, // 0x38 '8'
|
||||
{ 216, 8, 12, 10, 1, -11 }, // 0x39 '9'
|
||||
{ 228, 2, 9, 10, 4, -8 }, // 0x3A ':'
|
||||
{ 231, 3, 11, 10, 3, -8 }, // 0x3B ';'
|
||||
{ 236, 8, 8, 10, 1, -9 }, // 0x3C '<'
|
||||
{ 244, 8, 5, 10, 1, -7 }, // 0x3D '='
|
||||
{ 249, 8, 8, 10, 1, -9 }, // 0x3E '>'
|
||||
{ 257, 8, 12, 10, 1, -11 }, // 0x3F '?'
|
||||
{ 269, 10, 13, 10, 0, -11 }, // 0x40 '@'
|
||||
{ 286, 10, 12, 10, 0, -11 }, // 0x41 'A'
|
||||
{ 301, 8, 12, 10, 1, -11 }, // 0x42 'B'
|
||||
{ 313, 8, 12, 10, 1, -11 }, // 0x43 'C'
|
||||
{ 325, 8, 12, 10, 1, -11 }, // 0x44 'D'
|
||||
{ 337, 7, 12, 10, 2, -11 }, // 0x45 'E'
|
||||
{ 348, 7, 12, 10, 2, -11 }, // 0x46 'F'
|
||||
{ 359, 8, 12, 10, 1, -11 }, // 0x47 'G'
|
||||
{ 371, 8, 12, 10, 1, -11 }, // 0x48 'H'
|
||||
{ 383, 6, 12, 10, 2, -11 }, // 0x49 'I'
|
||||
{ 392, 7, 12, 10, 1, -11 }, // 0x4A 'J'
|
||||
{ 403, 9, 12, 10, 1, -11 }, // 0x4B 'K'
|
||||
{ 417, 8, 12, 10, 1, -11 }, // 0x4C 'L'
|
||||
{ 429, 8, 12, 10, 1, -11 }, // 0x4D 'M'
|
||||
{ 441, 8, 12, 10, 1, -11 }, // 0x4E 'N'
|
||||
{ 453, 8, 12, 10, 1, -11 }, // 0x4F 'O'
|
||||
{ 465, 8, 12, 10, 1, -11 }, // 0x50 'P'
|
||||
{ 477, 8, 15, 10, 1, -11 }, // 0x51 'Q'
|
||||
{ 492, 9, 12, 10, 1, -11 }, // 0x52 'R'
|
||||
{ 506, 8, 12, 10, 1, -11 }, // 0x53 'S'
|
||||
{ 518, 8, 12, 10, 1, -11 }, // 0x54 'T'
|
||||
{ 530, 8, 12, 10, 1, -11 }, // 0x55 'U'
|
||||
{ 542, 10, 12, 10, 0, -11 }, // 0x56 'V'
|
||||
{ 557, 10, 12, 10, 0, -11 }, // 0x57 'W'
|
||||
{ 572, 10, 12, 10, 0, -11 }, // 0x58 'X'
|
||||
{ 587, 10, 12, 10, 0, -11 }, // 0x59 'Y'
|
||||
{ 602, 8, 12, 10, 1, -11 }, // 0x5A 'Z'
|
||||
{ 614, 4, 15, 10, 4, -11 }, // 0x5B '['
|
||||
{ 622, 6, 12, 10, 2, -11 }, // 0x5C '\'
|
||||
{ 631, 4, 15, 10, 2, -11 }, // 0x5D ']'
|
||||
{ 639, 8, 7, 10, 1, -11 }, // 0x5E '^'
|
||||
{ 646, 10, 1, 10, 0, 2 }, // 0x5F '_'
|
||||
{ 648, 3, 3, 10, 4, -12 }, // 0x60 '`'
|
||||
{ 650, 8, 9, 10, 1, -8 }, // 0x61 'a'
|
||||
{ 659, 8, 13, 10, 1, -12 }, // 0x62 'b'
|
||||
{ 672, 8, 9, 10, 1, -8 }, // 0x63 'c'
|
||||
{ 681, 8, 13, 10, 1, -12 }, // 0x64 'd'
|
||||
{ 694, 8, 9, 10, 1, -8 }, // 0x65 'e'
|
||||
{ 703, 7, 13, 10, 2, -12 }, // 0x66 'f'
|
||||
{ 715, 9, 13, 10, 0, -8 }, // 0x67 'g'
|
||||
{ 730, 8, 13, 10, 1, -12 }, // 0x68 'h'
|
||||
{ 743, 7, 13, 10, 1, -12 }, // 0x69 'i'
|
||||
{ 755, 6, 17, 10, 1, -12 }, // 0x6A 'j'
|
||||
{ 768, 8, 13, 10, 2, -12 }, // 0x6B 'k'
|
||||
{ 781, 7, 13, 10, 1, -12 }, // 0x6C 'l'
|
||||
{ 793, 8, 9, 10, 1, -8 }, // 0x6D 'm'
|
||||
{ 802, 8, 9, 10, 1, -8 }, // 0x6E 'n'
|
||||
{ 811, 8, 9, 10, 1, -8 }, // 0x6F 'o'
|
||||
{ 820, 8, 13, 10, 1, -8 }, // 0x70 'p'
|
||||
{ 833, 8, 13, 10, 1, -8 }, // 0x71 'q'
|
||||
{ 846, 7, 9, 10, 2, -8 }, // 0x72 'r'
|
||||
{ 854, 6, 9, 10, 2, -8 }, // 0x73 's'
|
||||
{ 861, 7, 11, 10, 2, -10 }, // 0x74 't'
|
||||
{ 871, 8, 9, 10, 1, -8 }, // 0x75 'u'
|
||||
{ 880, 8, 9, 10, 1, -8 }, // 0x76 'v'
|
||||
{ 889, 10, 9, 10, 0, -8 }, // 0x77 'w'
|
||||
{ 901, 8, 9, 10, 1, -8 }, // 0x78 'x'
|
||||
{ 910, 8, 13, 10, 1, -8 }, // 0x79 'y'
|
||||
{ 923, 6, 9, 10, 2, -8 }, // 0x7A 'z'
|
||||
{ 930, 6, 15, 10, 2, -11 }, // 0x7B '{'
|
||||
{ 942, 1, 17, 10, 4, -12 }, // 0x7C '|'
|
||||
{ 945, 6, 15, 10, 2, -11 }, // 0x7D '}'
|
||||
{ 957, 8, 3, 10, 1, -6 } }; // 0x7E '~'
|
||||
|
||||
const GFXfont NotoMono8pt7b PROGMEM = {
|
||||
(uint8_t *)NotoMono8pt7bBitmaps,
|
||||
(GFXglyph *)NotoMono8pt7bGlyphs,
|
||||
0x20, 0x7E, 18 };
|
||||
|
||||
// Approx. 1632 bytes
|
517
src/guislice/XCheckbox.c
Normal file
517
src/guislice/XCheckbox.c
Normal file
|
@ -0,0 +1,517 @@
|
|||
// =======================================================================
|
||||
// GUIslice library (extensions)
|
||||
// - Calvin Hass
|
||||
// - https://www.impulseadventure.com/elec/guislice-gui.html
|
||||
// - https://github.com/ImpulseAdventure/GUIslice
|
||||
// =======================================================================
|
||||
//
|
||||
// The MIT License
|
||||
//
|
||||
// Copyright 2016-2020 Calvin Hass
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
//
|
||||
// =======================================================================
|
||||
/// \file XCheckbox.c
|
||||
|
||||
|
||||
|
||||
// GUIslice library
|
||||
#include "GUIslice.h"
|
||||
#include "GUIslice_drv.h"
|
||||
|
||||
#include "XCheckbox.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#if (GSLC_USE_PROGMEM)
|
||||
#include <avr/pgmspace.h>
|
||||
#endif
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Error Messages
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
extern const char GSLC_PMEM ERRSTR_NULL[];
|
||||
extern const char GSLC_PMEM ERRSTR_PXD_NULL[];
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Extended element definitions
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// - This file extends the core GUIslice functionality with
|
||||
// additional widget types
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
// ============================================================================
|
||||
// Extended Element: Checkbox
|
||||
// - Checkbox with custom handler for touch tracking which
|
||||
// enables glow to be defined whenever touch is tracked over
|
||||
// the element.
|
||||
// ============================================================================
|
||||
|
||||
// Create a checkbox element and add it to the GUI element list
|
||||
// - Defines default styling for the element
|
||||
// - Defines callback for redraw but does not track touch/click
|
||||
gslc_tsElemRef* gslc_ElemXCheckboxCreate(gslc_tsGui* pGui,int16_t nElemId,int16_t nPage,
|
||||
gslc_tsXCheckbox* pXData,gslc_tsRect rElem,bool bRadio,gslc_teXCheckboxStyle nStyle,
|
||||
gslc_tsColor colCheck,bool bChecked)
|
||||
{
|
||||
if ((pGui == NULL) || (pXData == NULL)) {
|
||||
static const char GSLC_PMEM FUNCSTR[] = "ElemXCheckboxCreate";
|
||||
GSLC_DEBUG2_PRINT_CONST(ERRSTR_NULL,FUNCSTR);
|
||||
return NULL;
|
||||
}
|
||||
gslc_tsElem sElem;
|
||||
gslc_tsElemRef* pElemRef = NULL;
|
||||
sElem = gslc_ElemCreate(pGui,nElemId,nPage,GSLC_TYPEX_CHECKBOX,rElem,NULL,0,GSLC_FONT_NONE);
|
||||
sElem.nFeatures &= ~GSLC_ELEM_FEA_FRAME_EN;
|
||||
sElem.nFeatures |= GSLC_ELEM_FEA_FILL_EN;
|
||||
sElem.nFeatures |= GSLC_ELEM_FEA_CLICK_EN;
|
||||
sElem.nFeatures |= GSLC_ELEM_FEA_GLOW_EN;
|
||||
|
||||
// Default group assignment. Can override later with ElemSetGroup()
|
||||
sElem.nGroup = GSLC_GROUP_ID_NONE;
|
||||
|
||||
// Define other extended data
|
||||
pXData->bRadio = bRadio;
|
||||
pXData->bChecked = bChecked;
|
||||
pXData->colCheck = colCheck;
|
||||
pXData->nStyle = nStyle;
|
||||
pXData->pfuncXToggle = NULL;
|
||||
sElem.pXData = (void*)(pXData);
|
||||
// Specify the custom drawing callback
|
||||
sElem.pfuncXDraw = &gslc_ElemXCheckboxDraw;
|
||||
// Specify the custom touch tracking callback
|
||||
// - NOTE: This is optional (and can be set to NULL).
|
||||
// See the discussion under gslc_ElemXCheckboxTouch()
|
||||
sElem.pfuncXTouch = &gslc_ElemXCheckboxTouch;
|
||||
sElem.colElemFill = GSLC_COL_BLACK;
|
||||
sElem.colElemFillGlow = GSLC_COL_BLACK;
|
||||
sElem.colElemFrame = GSLC_COL_GRAY;
|
||||
sElem.colElemFrameGlow = GSLC_COL_WHITE;
|
||||
if (nPage != GSLC_PAGE_NONE) {
|
||||
pElemRef = gslc_ElemAdd(pGui,nPage,&sElem,GSLC_ELEMREF_DEFAULT);
|
||||
return pElemRef;
|
||||
#if (GSLC_FEATURE_COMPOUND)
|
||||
} else {
|
||||
// Save as temporary element
|
||||
pGui->sElemTmp = sElem;
|
||||
pGui->sElemRefTmp.pElem = &(pGui->sElemTmp);
|
||||
pGui->sElemRefTmp.eElemFlags = GSLC_ELEMREF_DEFAULT | GSLC_ELEMREF_REDRAW_FULL;
|
||||
return &(pGui->sElemRefTmp);
|
||||
#endif
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool gslc_ElemXCheckboxGetState(gslc_tsGui* pGui,gslc_tsElemRef* pElemRef)
|
||||
{
|
||||
gslc_tsXCheckbox* pCheckbox = (gslc_tsXCheckbox*)gslc_GetXDataFromRef(pGui, pElemRef, GSLC_TYPEX_CHECKBOX, __LINE__);
|
||||
if (!pCheckbox) return false;
|
||||
|
||||
return pCheckbox->bChecked;
|
||||
}
|
||||
|
||||
|
||||
// Determine which checkbox in the group has been "checked"
|
||||
gslc_tsElemRef* gslc_ElemXCheckboxFindChecked(gslc_tsGui* pGui,int16_t nGroupId)
|
||||
{
|
||||
int16_t nCurInd;
|
||||
gslc_tsElemRef* pCurElemRef = NULL;
|
||||
gslc_tsElem* pCurElem = NULL;
|
||||
int16_t nCurType;
|
||||
int16_t nCurGroup;
|
||||
bool bCurChecked;
|
||||
gslc_tsElemRef* pFoundElemRef = NULL;
|
||||
|
||||
// Operate on current page
|
||||
// TODO: Support other page layers
|
||||
gslc_tsPage* pPage = pGui->apPageStack[GSLC_STACK_CUR];
|
||||
if (pPage == NULL) {
|
||||
return NULL; // No page added yet
|
||||
}
|
||||
|
||||
if (pGui == NULL) {
|
||||
static const char GSLC_PMEM FUNCSTR[] = "ElemXCheckboxFindChecked";
|
||||
GSLC_DEBUG2_PRINT_CONST(ERRSTR_NULL,FUNCSTR);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
gslc_tsCollect* pCollect = &pPage->sCollect;
|
||||
for (nCurInd=0;nCurInd<pCollect->nElemCnt;nCurInd++) {
|
||||
// Fetch extended data
|
||||
pCurElemRef = &(pCollect->asElemRef[nCurInd]);
|
||||
pCurElem = gslc_GetElemFromRef(pGui,pCurElemRef);
|
||||
nCurType = pCurElem->nType;
|
||||
// Only want to proceed if it is a checkbox
|
||||
if (nCurType != GSLC_TYPEX_CHECKBOX) {
|
||||
continue;
|
||||
}
|
||||
|
||||
nCurGroup = pCurElem->nGroup;
|
||||
bCurChecked = gslc_ElemXCheckboxGetState(pGui,pCurElemRef);
|
||||
|
||||
// If this is in a different group, ignore it
|
||||
if (nCurGroup != nGroupId) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Did we find an element in the group that was checked?
|
||||
if (bCurChecked) {
|
||||
pFoundElemRef = pCurElemRef;
|
||||
break;
|
||||
}
|
||||
} // nCurInd
|
||||
return pFoundElemRef;
|
||||
}
|
||||
|
||||
// Assign the callback function for checkbox/radio state change events
|
||||
void gslc_ElemXCheckboxSetStateFunc(gslc_tsGui* pGui, gslc_tsElemRef* pElemRef, GSLC_CB_XCHECKBOX pfuncCb)
|
||||
{
|
||||
gslc_tsXCheckbox* pCheckbox = (gslc_tsXCheckbox*)gslc_GetXDataFromRef(pGui, pElemRef, GSLC_TYPEX_CHECKBOX, __LINE__);
|
||||
if (!pCheckbox) return;
|
||||
|
||||
pCheckbox->pfuncXToggle = pfuncCb;
|
||||
}
|
||||
|
||||
// Helper routine for gslc_ElemXCheckboxSetState()
|
||||
// - Updates the checkbox/radio control's state but does
|
||||
// not touch any other controls in the group
|
||||
void gslc_ElemXCheckboxSetStateHelp(gslc_tsGui* pGui,gslc_tsElemRef* pElemRef,bool bChecked,bool bDoCb)
|
||||
{
|
||||
gslc_tsXCheckbox* pCheckbox = (gslc_tsXCheckbox*)gslc_GetXDataFromRef(pGui, pElemRef, GSLC_TYPEX_CHECKBOX, __LINE__);
|
||||
if (!pCheckbox) return;
|
||||
|
||||
gslc_tsElem* pElem = gslc_GetElemFromRef(pGui,pElemRef);
|
||||
|
||||
// Update our data element
|
||||
bool const bCheckedOld = pCheckbox->bChecked;
|
||||
pCheckbox->bChecked = bChecked;
|
||||
|
||||
// Element needs redraw
|
||||
if (bChecked != bCheckedOld) {
|
||||
// Only need an incremental redraw
|
||||
gslc_ElemSetRedraw(pGui,pElemRef,GSLC_REDRAW_INC);
|
||||
} else {
|
||||
// Same state as before
|
||||
// - No need to do anything further since we don't need to
|
||||
// trigger any callbacks or redraw
|
||||
return;
|
||||
}
|
||||
|
||||
// If no callbacks requested, exit now
|
||||
if (!bDoCb) {
|
||||
return;
|
||||
}
|
||||
|
||||
// If any state callback is defined, call it now
|
||||
// - In all cases, return the ElementRef of the element that issued the callback
|
||||
//
|
||||
// For checkbox:
|
||||
// - If not selected: return current ID and state=false
|
||||
// - If selected: return current ID and state=true
|
||||
// For radio button:
|
||||
// - If none selected: return ID_NONE and state=false
|
||||
// - If one selected: return selected ID and state=true
|
||||
if (pCheckbox->pfuncXToggle != NULL) {
|
||||
gslc_tsElemRef* pRetRef = NULL;
|
||||
int16_t nGroup = GSLC_GROUP_ID_NONE;
|
||||
int16_t nSelId = GSLC_ID_NONE;
|
||||
if (!pCheckbox->bRadio) {
|
||||
// Checkbox
|
||||
nSelId = pElem->nId;
|
||||
} else {
|
||||
// Radio button
|
||||
// - Determine the group that the radio button belongs to
|
||||
nGroup = pElem->nGroup;
|
||||
// Determine if any radio button in the group has been selected
|
||||
pRetRef = gslc_ElemXCheckboxFindChecked(pGui, nGroup);
|
||||
if (pRetRef != NULL) {
|
||||
// One has been selected, return its ID
|
||||
bChecked = true;
|
||||
nSelId = pRetRef->pElem->nId;
|
||||
} else {
|
||||
// No radio button selected, return ID NONE
|
||||
bChecked = false;
|
||||
nSelId = GSLC_ID_NONE;
|
||||
}
|
||||
}
|
||||
// Now send the callback notification
|
||||
(*pCheckbox->pfuncXToggle)((void*)(pGui), (void*)(pElemRef), nSelId, bChecked);
|
||||
} // pfuncXToggle
|
||||
|
||||
}
|
||||
|
||||
// Update the checkbox/radio control's state. If it is a radio button
|
||||
// then also update the state of all other buttons in the group.
|
||||
void gslc_ElemXCheckboxSetState(gslc_tsGui* pGui,gslc_tsElemRef* pElemRef,bool bChecked)
|
||||
{
|
||||
gslc_tsXCheckbox* pCheckbox = (gslc_tsXCheckbox*)gslc_GetXDataFromRef(pGui, pElemRef, GSLC_TYPEX_CHECKBOX, __LINE__);
|
||||
if (!pCheckbox) return;
|
||||
|
||||
|
||||
gslc_tsElem* pElem = gslc_GetElemFromRef(pGui,pElemRef);
|
||||
gslc_tsPage* pPage = NULL;
|
||||
|
||||
bool bRadio = pCheckbox->bRadio;
|
||||
int16_t nGroup = pElem->nGroup;
|
||||
int16_t nElemId = pElem->nId;
|
||||
|
||||
// Special handling when we select a radio button
|
||||
if (bRadio && bChecked) {
|
||||
|
||||
// If we are selecting a radio button that is already
|
||||
// selected, then skip further update events.
|
||||
// NOTE: This check is not very efficient, but it avoids
|
||||
// the creation of extra events.
|
||||
gslc_tsElemRef* pTmpRef = gslc_ElemXCheckboxFindChecked(pGui, nGroup);
|
||||
if (pTmpRef == pElemRef) {
|
||||
// Same element, so skip
|
||||
return;
|
||||
}
|
||||
|
||||
// Proceed to deselect any other selected items in the group.
|
||||
// Note that SetState calls itself to deselect other items so it
|
||||
// is important to qualify this logic with bChecked=true
|
||||
int16_t nCurInd;
|
||||
int16_t nCurId;
|
||||
gslc_tsElem* pCurElem = NULL;
|
||||
gslc_tsElemRef* pCurElemRef = NULL;
|
||||
int16_t nCurType;
|
||||
int16_t nCurGroup;
|
||||
|
||||
// We use the GUI pointer for access to other elements
|
||||
|
||||
// Check all pages in case we are affecting radio buttons on other pages
|
||||
for (int8_t nPageInd=0;nPageInd<pGui->nPageCnt;nPageInd++) {
|
||||
pPage = &pGui->asPage[nPageInd];
|
||||
if (!pPage) {
|
||||
// If this stack page is not enabled, skip to next stack page
|
||||
continue;
|
||||
}
|
||||
|
||||
gslc_tsCollect* pCollect = &pPage->sCollect;
|
||||
for (nCurInd=0;nCurInd<pCollect->nElemRefCnt;nCurInd++) {
|
||||
// Fetch extended data
|
||||
pCurElemRef = &pCollect->asElemRef[nCurInd];
|
||||
pCurElem = gslc_GetElemFromRef(pGui,pCurElemRef);
|
||||
|
||||
// FIXME: Handle pCurElemRef->eElemFlags
|
||||
nCurId = pCurElem->nId;
|
||||
nCurType = pCurElem->nType;
|
||||
|
||||
// Only want to proceed if it is a checkbox
|
||||
if (nCurType != GSLC_TYPEX_CHECKBOX) {
|
||||
continue;
|
||||
}
|
||||
|
||||
nCurGroup = pCurElem->nGroup;
|
||||
|
||||
// If this is in a different group, ignore it
|
||||
if (nCurGroup != nGroup) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Is this our element? If so, ignore the deselect operation
|
||||
if (nCurId == nElemId) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Deselect all other elements
|
||||
// - But don't trigger any callbacks
|
||||
gslc_ElemXCheckboxSetStateHelp(pGui,pCurElemRef,false,false);
|
||||
|
||||
} // nInd
|
||||
} // nStackPage
|
||||
|
||||
} // bRadio
|
||||
|
||||
// Set the state of the current element
|
||||
// - Trigger callback if enabled
|
||||
gslc_ElemXCheckboxSetStateHelp(pGui,pElemRef,bChecked,true);
|
||||
}
|
||||
|
||||
// Toggle the checkbox control's state
|
||||
void gslc_ElemXCheckboxToggleState(gslc_tsGui* pGui,gslc_tsElemRef* pElemRef)
|
||||
{
|
||||
if (pElemRef == NULL) {
|
||||
static const char GSLC_PMEM FUNCSTR[] = "ElemXCheckboxToggleState";
|
||||
GSLC_DEBUG2_PRINT_CONST(ERRSTR_NULL,FUNCSTR);
|
||||
return;
|
||||
}
|
||||
// Update the data element
|
||||
bool bCheckNew = (gslc_ElemXCheckboxGetState(pGui,pElemRef))? false : true;
|
||||
gslc_ElemXCheckboxSetState(pGui,pElemRef,bCheckNew);
|
||||
|
||||
// Element needs redraw
|
||||
// - Only incremental is needed
|
||||
gslc_ElemSetRedraw(pGui,pElemRef,GSLC_REDRAW_INC);
|
||||
}
|
||||
|
||||
// Redraw the checkbox
|
||||
// - Note that this redraw is for the entire element rect region
|
||||
// - The Draw function parameters use void pointers to allow for
|
||||
// simpler callback function definition & scalability.
|
||||
bool gslc_ElemXCheckboxDraw(void* pvGui,void* pvElemRef,gslc_teRedrawType eRedraw)
|
||||
{
|
||||
// Typecast the parameters to match the GUI and element types
|
||||
gslc_tsGui* pGui = (gslc_tsGui*)(pvGui);
|
||||
gslc_tsElemRef* pElemRef = (gslc_tsElemRef*)(pvElemRef);
|
||||
|
||||
gslc_tsXCheckbox* pCheckbox = (gslc_tsXCheckbox*)gslc_GetXDataFromRef(pGui, pElemRef, GSLC_TYPEX_CHECKBOX, __LINE__);
|
||||
if (!pCheckbox) return false;
|
||||
|
||||
gslc_tsElem* pElem = gslc_GetElemFromRef(pGui,pElemRef);
|
||||
gslc_tsRect rInner;
|
||||
|
||||
bool bChecked = pCheckbox->bChecked;
|
||||
gslc_teXCheckboxStyle nStyle = pCheckbox->nStyle;
|
||||
bool bGlow = (pElem->nFeatures & GSLC_ELEM_FEA_GLOW_EN) && gslc_ElemGetGlow(pGui,pElemRef);
|
||||
|
||||
// Draw the background
|
||||
gslc_DrawFillRect(pGui,pElem->rElem,pElem->colElemFill);
|
||||
|
||||
// Generic coordinate calcs
|
||||
int16_t nX0,nY0,nX1,nY1,nMidX,nMidY;
|
||||
nX0 = pElem->rElem.x;
|
||||
nY0 = pElem->rElem.y;
|
||||
nX1 = pElem->rElem.x + pElem->rElem.w - 1;
|
||||
nY1 = pElem->rElem.y + pElem->rElem.h - 1;
|
||||
nMidX = (nX0+nX1)/2;
|
||||
nMidY = (nY0+nY1)/2;
|
||||
if (nStyle == GSLCX_CHECKBOX_STYLE_BOX) {
|
||||
// Draw the center indicator if checked
|
||||
rInner = gslc_ExpandRect(pElem->rElem,-5,-5);
|
||||
if (bChecked) {
|
||||
// If checked, fill in the inner region
|
||||
gslc_DrawFillRect(pGui,rInner,pCheckbox->colCheck);
|
||||
} else {
|
||||
// Assume the background fill has already been done so
|
||||
// we don't need to do anything more in the unchecked case
|
||||
}
|
||||
// Draw a frame around the checkbox
|
||||
gslc_DrawFrameRect(pGui,pElem->rElem,(bGlow)?pElem->colElemFrameGlow:pElem->colElemFrame);
|
||||
|
||||
} else if (nStyle == GSLCX_CHECKBOX_STYLE_X) {
|
||||
// Draw an X through center if checked
|
||||
if (bChecked) {
|
||||
gslc_DrawLine(pGui,nX0,nY0,nX1,nY1,pCheckbox->colCheck);
|
||||
gslc_DrawLine(pGui,nX0,nY1,nX1,nY0,pCheckbox->colCheck);
|
||||
}
|
||||
// Draw a frame around the checkbox
|
||||
gslc_DrawFrameRect(pGui,pElem->rElem,(bGlow)?pElem->colElemFrameGlow:pElem->colElemFrame);
|
||||
|
||||
} else if (nStyle == GSLCX_CHECKBOX_STYLE_ROUND) {
|
||||
// Draw inner circle if checked
|
||||
if (bChecked) {
|
||||
gslc_DrawFillCircle(pGui,nMidX,nMidY,5,pCheckbox->colCheck);
|
||||
}
|
||||
// Draw a frame around the checkbox
|
||||
gslc_DrawFrameCircle(pGui,nMidX,nMidY,(pElem->rElem.w/2),(bGlow)?pElem->colElemFrameGlow:pElem->colElemFrame);
|
||||
|
||||
}
|
||||
|
||||
// Clear the redraw flag
|
||||
gslc_ElemSetRedraw(pGui,pElemRef,GSLC_REDRAW_NONE);
|
||||
|
||||
// Mark page as needing flip
|
||||
gslc_PageFlipSet(pGui,true);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// This callback function is called by gslc_ElemSendEventTouch()
|
||||
// after any touch event
|
||||
// - NOTE: Adding this touch callback is optional. Without it, we
|
||||
// can still have a functional checkbox, but doing the touch
|
||||
// tracking allows us to change the glow state of the element
|
||||
// dynamically, as well as updating the checkbox state if the
|
||||
// user releases over it (ie. a click event).
|
||||
//
|
||||
bool gslc_ElemXCheckboxTouch(void* pvGui,void* pvElemRef,gslc_teTouch eTouch,int16_t nRelX,int16_t nRelY)
|
||||
{
|
||||
#if defined(DRV_TOUCH_NONE)
|
||||
return false;
|
||||
#else
|
||||
|
||||
// Typecast the parameters to match the GUI and element types
|
||||
gslc_tsGui* pGui = (gslc_tsGui*)(pvGui);
|
||||
gslc_tsElemRef* pElemRef = (gslc_tsElemRef*)(pvElemRef);
|
||||
|
||||
gslc_tsXCheckbox* pCheckbox = (gslc_tsXCheckbox*)gslc_GetXDataFromRef(pGui, pElemRef, GSLC_TYPEX_CHECKBOX, __LINE__);
|
||||
if (!pCheckbox) return false;
|
||||
|
||||
//gslc_tsElem* pElem = gslc_GetElemFromRef(pGui,pElemRef);
|
||||
|
||||
bool bRadio = pCheckbox->bRadio;
|
||||
bool bCheckedOld = pCheckbox->bChecked;
|
||||
bool bGlowingOld = gslc_ElemGetGlow(pGui,pElemRef);
|
||||
|
||||
switch(eTouch) {
|
||||
|
||||
case GSLC_TOUCH_DOWN_IN:
|
||||
gslc_ElemSetGlow(pGui,pElemRef,true);
|
||||
break;
|
||||
|
||||
case GSLC_TOUCH_MOVE_IN:
|
||||
gslc_ElemSetGlow(pGui,pElemRef,true);
|
||||
break;
|
||||
case GSLC_TOUCH_MOVE_OUT:
|
||||
gslc_ElemSetGlow(pGui,pElemRef,false);
|
||||
break;
|
||||
|
||||
case GSLC_TOUCH_UP_IN:
|
||||
gslc_ElemSetGlow(pGui,pElemRef,false);
|
||||
// Now that we released on element, update the state
|
||||
bool bCheckNew;
|
||||
if (bRadio) {
|
||||
// Radio button action: set
|
||||
bCheckNew = true;
|
||||
} else {
|
||||
// Checkbox button action: toggle
|
||||
bCheckNew = (pCheckbox->bChecked)?false:true;
|
||||
}
|
||||
gslc_ElemXCheckboxSetState(pGui,pElemRef,bCheckNew);
|
||||
break;
|
||||
case GSLC_TOUCH_UP_OUT:
|
||||
gslc_ElemSetGlow(pGui,pElemRef,false);
|
||||
break;
|
||||
|
||||
default:
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
|
||||
// If the checkbox changed state, redraw
|
||||
bool bChanged = false;
|
||||
if (gslc_ElemGetGlow(pGui,pElemRef) != bGlowingOld) { bChanged = true; }
|
||||
if (pCheckbox->bChecked != bCheckedOld) { bChanged = true; }
|
||||
if (bChanged) {
|
||||
// Incremental redraw
|
||||
gslc_ElemSetRedraw(pGui,pElemRef,GSLC_REDRAW_INC);
|
||||
}
|
||||
|
||||
return true;
|
||||
#endif // !DRV_TOUCH_NONE
|
||||
}
|
||||
|
||||
// ============================================================================
|
290
src/guislice/XCheckbox.h
Normal file
290
src/guislice/XCheckbox.h
Normal file
|
@ -0,0 +1,290 @@
|
|||
#ifndef _GUISLICE_EX_XCHECKBOX_H_
|
||||
#define _GUISLICE_EX_XCHECKBOX_H_
|
||||
|
||||
#include "GUIslice.h"
|
||||
|
||||
|
||||
// =======================================================================
|
||||
// GUIslice library extension: Checkbox/Radio button control
|
||||
// - Calvin Hass
|
||||
// - https://www.impulseadventure.com/elec/guislice-gui.html
|
||||
// - https://github.com/ImpulseAdventure/GUIslice
|
||||
// =======================================================================
|
||||
//
|
||||
// The MIT License
|
||||
//
|
||||
// Copyright 2016-2020 Calvin Hass
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
//
|
||||
// =======================================================================
|
||||
/// \file XCheckbox.h
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif // __cplusplus
|
||||
|
||||
// ============================================================================
|
||||
// Extended Element: Checkbox
|
||||
// ============================================================================
|
||||
|
||||
// Define unique identifier for extended element type
|
||||
// - Select any number above GSLC_TYPE_BASE_EXTEND
|
||||
#define GSLC_TYPEX_CHECKBOX GSLC_TYPE_BASE_EXTEND + 1
|
||||
|
||||
/// Checkbox drawing style
|
||||
typedef enum {
|
||||
GSLCX_CHECKBOX_STYLE_BOX, ///< Inner box
|
||||
GSLCX_CHECKBOX_STYLE_X, ///< Crossed
|
||||
GSLCX_CHECKBOX_STYLE_ROUND, ///< Circular
|
||||
} gslc_teXCheckboxStyle;
|
||||
|
||||
/// Callback function for checkbox/radio element state change
|
||||
/// - nSelId: Selected element's ID or GSLC_ID_NONE
|
||||
/// - bChecked: Element was selected if true, false otherwise
|
||||
typedef bool (*GSLC_CB_XCHECKBOX)(void* pvGui,void* pvElemRef,int16_t nSelId, bool bChecked);
|
||||
|
||||
// Extended element data structures
|
||||
// - These data structures are maintained in the gslc_tsElem
|
||||
// structure via the pXData pointer
|
||||
|
||||
/// Extended data for Checkbox element
|
||||
typedef struct {
|
||||
bool bRadio; ///< Radio-button operation if true
|
||||
gslc_teXCheckboxStyle nStyle; ///< Drawing style for element
|
||||
bool bChecked; ///< Indicates if it is selected (checked)
|
||||
gslc_tsColor colCheck; ///< Color of checked inner fill
|
||||
GSLC_CB_XCHECKBOX pfuncXToggle; ///< Callback event to say element has changed
|
||||
} gslc_tsXCheckbox;
|
||||
|
||||
|
||||
///
|
||||
/// Create a Checkbox or Radio button Element
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] nElemId: Element ID to assign (0..16383 or GSLC_ID_AUTO to autogen)
|
||||
/// \param[in] nPage: Page ID to attach element to
|
||||
/// \param[in] pXData: Ptr to extended element data structure
|
||||
/// \param[in] rElem: Rectangle coordinates defining checkbox size
|
||||
/// \param[in] bRadio: Radio-button functionality if true
|
||||
/// \param[in] nStyle: Drawing style for checkbox / radio button
|
||||
/// \param[in] colCheck: Color for inner fill when checked
|
||||
/// \param[in] bChecked: Default state
|
||||
///
|
||||
/// \return Pointer to Element reference or NULL if failure
|
||||
///
|
||||
gslc_tsElemRef* gslc_ElemXCheckboxCreate(gslc_tsGui* pGui,int16_t nElemId,int16_t nPage,
|
||||
gslc_tsXCheckbox* pXData,gslc_tsRect rElem,bool bRadio,
|
||||
gslc_teXCheckboxStyle nStyle,gslc_tsColor colCheck,bool bChecked);
|
||||
|
||||
|
||||
///
|
||||
/// Get a Checkbox element's current state
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] pElemRef: Pointer to Element reference
|
||||
///
|
||||
/// \return Current state
|
||||
///
|
||||
bool gslc_ElemXCheckboxGetState(gslc_tsGui* pGui,gslc_tsElemRef* pElemRef);
|
||||
|
||||
///
|
||||
/// Set a Checkbox element's current state
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] pElemRef: Pointer to Element reference
|
||||
/// \param[in] bChecked: New state
|
||||
///
|
||||
/// \return none
|
||||
///
|
||||
void gslc_ElemXCheckboxSetState(gslc_tsGui* pGui,gslc_tsElemRef* pElemRef,bool bChecked);
|
||||
|
||||
///
|
||||
/// Find the checkbox within a group that has been checked
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] nGroupId: Group ID to search
|
||||
///
|
||||
/// \return Element Ptr or NULL if none checked
|
||||
///
|
||||
gslc_tsElemRef* gslc_ElemXCheckboxFindChecked(gslc_tsGui* pGui,int16_t nGroupId);
|
||||
|
||||
///
|
||||
/// Toggle a Checkbox element's current state
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] pElemRef: Pointer to Element reference
|
||||
///
|
||||
/// \return none
|
||||
///
|
||||
void gslc_ElemXCheckboxToggleState(gslc_tsGui* pGui,gslc_tsElemRef* pElemRef);
|
||||
|
||||
///
|
||||
/// Assign the state callback function for a checkbox/radio button
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] pElemRef: Pointer to Element reference
|
||||
/// \param[in] pfuncCb: Function pointer to callback routine (or NULL for none)
|
||||
///
|
||||
/// \return none
|
||||
///
|
||||
void gslc_ElemXCheckboxSetStateFunc(gslc_tsGui* pGui, gslc_tsElemRef* pElemRef, GSLC_CB_XCHECKBOX pfuncCb);
|
||||
|
||||
///
|
||||
/// Draw a Checkbox element on the screen
|
||||
/// - Called from gslc_ElemDraw()
|
||||
///
|
||||
/// \param[in] pvGui: Void ptr to GUI (typecast to gslc_tsGui*)
|
||||
/// \param[in] pvElemRef: Void ptr to Element reference (typecast to gslc_tsElemRef*)
|
||||
/// \param[in] eRedraw: Redraw mode
|
||||
///
|
||||
/// \return true if success, false otherwise
|
||||
///
|
||||
bool gslc_ElemXCheckboxDraw(void* pvGui,void* pvElemRef,gslc_teRedrawType eRedraw);
|
||||
|
||||
///
|
||||
/// Handle touch events to Checkbox element
|
||||
/// - Called from gslc_ElemSendEventTouch()
|
||||
///
|
||||
/// \param[in] pvGui: Void ptr to GUI (typecast to gslc_tsGui*)
|
||||
/// \param[in] pvElemRef: Void ptr to Element reference (typecast to gslc_tsElemRef*)
|
||||
/// \param[in] eTouch: Touch event type
|
||||
/// \param[in] nRelX: Touch X coord relative to element
|
||||
/// \param[in] nRelY: Touch Y coord relative to element
|
||||
///
|
||||
/// \return true if success, false otherwise
|
||||
///
|
||||
bool gslc_ElemXCheckboxTouch(void* pvGui,void* pvElemRef,gslc_teTouch eTouch,int16_t nRelX,int16_t nRelY);
|
||||
// ============================================================================
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Read-only element macros
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
// Macro initializers for Read-Only Elements in Flash/PROGMEM
|
||||
//
|
||||
|
||||
|
||||
/// \def gslc_ElemXCheckboxCreate_P(pGui,nElemId,nPage,nX,nY,nW,nH,nGroup,bRadio_,nStyle_,colCheck_,bChecked_)
|
||||
///
|
||||
/// Create a Checkbox or Radio button Element in Flash
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] nElemId: Unique element ID to assign
|
||||
/// \param[in] nPage: Page ID to attach element to
|
||||
/// \param[in] nX: X coordinate of element
|
||||
/// \param[in] nY: Y coordinate of element
|
||||
/// \param[in] nW: Width of element
|
||||
/// \param[in] nH: Height of element
|
||||
/// \param[in] colFill: Color for the control background fill
|
||||
/// \param[in] bFillEn: True if background filled, false otherwise (recommend True)
|
||||
/// \param[in] nGroup: Group ID that radio buttons belong to (else GSLC_GROUP_NONE)
|
||||
/// \param[in] bRadio_: Radio-button functionality if true
|
||||
/// \param[in] nStyle_: Drawing style for checkbox / radio button
|
||||
/// \param[in] colCheck_: Color for inner fill when checked
|
||||
/// \param[in] bChecked_: Default state
|
||||
///
|
||||
/// \return none
|
||||
///
|
||||
|
||||
#if (GSLC_USE_PROGMEM)
|
||||
|
||||
#define gslc_ElemXCheckboxCreate_P(pGui,nElemId,nPage,nX,nY,nW,nH,colFill,bFillEn,nGroup,bRadio_,nStyle_,colCheck_,bChecked_) \
|
||||
static const uint8_t nFeatures##nElemId = GSLC_ELEM_FEA_VALID | \
|
||||
GSLC_ELEM_FEA_GLOW_EN | GSLC_ELEM_FEA_CLICK_EN | (bFillEn?GSLC_ELEM_FEA_FILL_EN:0); \
|
||||
static gslc_tsXCheckbox sCheckbox##nElemId; \
|
||||
sCheckbox##nElemId.bRadio = bRadio_; \
|
||||
sCheckbox##nElemId.bChecked = bChecked_; \
|
||||
sCheckbox##nElemId.colCheck = colCheck_; \
|
||||
sCheckbox##nElemId.nStyle = nStyle_; \
|
||||
static const gslc_tsElem sElem##nElemId PROGMEM = { \
|
||||
nElemId, \
|
||||
nFeatures##nElemId, \
|
||||
GSLC_TYPEX_CHECKBOX, \
|
||||
(gslc_tsRect){nX,nY,nW,nH}, \
|
||||
nGroup, \
|
||||
GSLC_COL_GRAY,colFill,GSLC_COL_WHITE,GSLC_COL_BLACK, \
|
||||
(gslc_tsImgRef){NULL,NULL,GSLC_IMGREF_NONE,NULL}, \
|
||||
(gslc_tsImgRef){NULL,NULL,GSLC_IMGREF_NONE,NULL}, \
|
||||
NULL, \
|
||||
NULL, \
|
||||
0, \
|
||||
(gslc_teTxtFlags)(GSLC_TXT_DEFAULT), \
|
||||
GSLC_COL_WHITE, \
|
||||
GSLC_COL_WHITE, \
|
||||
GSLC_ALIGN_MID_MID, \
|
||||
0, \
|
||||
0, \
|
||||
NULL, \
|
||||
(void*)(&sCheckbox##nElemId), \
|
||||
NULL, \
|
||||
&gslc_ElemXCheckboxDraw, \
|
||||
&gslc_ElemXCheckboxTouch, \
|
||||
NULL, \
|
||||
}; \
|
||||
gslc_ElemAdd(pGui,nPage,(gslc_tsElem*)&sElem##nElemId, \
|
||||
(gslc_teElemRefFlags)(GSLC_ELEMREF_SRC_PROG | GSLC_ELEMREF_VISIBLE | GSLC_ELEMREF_REDRAW_FULL));
|
||||
|
||||
|
||||
#else
|
||||
|
||||
#define gslc_ElemXCheckboxCreate_P(pGui,nElemId,nPage,nX,nY,nW,nH,colFill,bFillEn,nGroup,bRadio_,nStyle_,colCheck_,bChecked_) \
|
||||
static const uint8_t nFeatures##nElemId = GSLC_ELEM_FEA_VALID | \
|
||||
GSLC_ELEM_FEA_GLOW_EN | GSLC_ELEM_FEA_CLICK_EN | (bFillEn?GSLC_ELEM_FEA_FILL_EN:0); \
|
||||
static gslc_tsXCheckbox sCheckbox##nElemId; \
|
||||
sCheckbox##nElemId.bRadio = bRadio_; \
|
||||
sCheckbox##nElemId.bChecked = bChecked_; \
|
||||
sCheckbox##nElemId.colCheck = colCheck_; \
|
||||
sCheckbox##nElemId.nStyle = nStyle_; \
|
||||
static const gslc_tsElem sElem##nElemId = { \
|
||||
nElemId, \
|
||||
nFeatures##nElemId, \
|
||||
GSLC_TYPEX_CHECKBOX, \
|
||||
(gslc_tsRect){nX,nY,nW,nH}, \
|
||||
nGroup, \
|
||||
GSLC_COL_GRAY,colFill,GSLC_COL_WHITE,GSLC_COL_BLACK, \
|
||||
(gslc_tsImgRef){NULL,NULL,GSLC_IMGREF_NONE,NULL}, \
|
||||
(gslc_tsImgRef){NULL,NULL,GSLC_IMGREF_NONE,NULL}, \
|
||||
NULL, \
|
||||
NULL, \
|
||||
0, \
|
||||
(gslc_teTxtFlags)(GSLC_TXT_DEFAULT), \
|
||||
GSLC_COL_WHITE, \
|
||||
GSLC_COL_WHITE, \
|
||||
GSLC_ALIGN_MID_MID, \
|
||||
0, \
|
||||
0, \
|
||||
NULL, \
|
||||
(void*)(&sCheckbox##nElemId), \
|
||||
NULL, \
|
||||
&gslc_ElemXCheckboxDraw, \
|
||||
&gslc_ElemXCheckboxTouch, \
|
||||
NULL, \
|
||||
}; \
|
||||
gslc_ElemAdd(pGui,nPage,(gslc_tsElem*)&sElem##nElemId, \
|
||||
(gslc_teElemRefFlags)(GSLC_ELEMREF_SRC_CONST | GSLC_ELEMREF_VISIBLE | GSLC_ELEMREF_REDRAW_FULL));
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif // __cplusplus
|
||||
#endif // _GUISLICE_EX_XCHECKBOX_H_
|
||||
|
699
src/guislice/XGauge.c
Normal file
699
src/guislice/XGauge.c
Normal file
|
@ -0,0 +1,699 @@
|
|||
// =======================================================================
|
||||
// GUIslice library (extensions)
|
||||
// - Calvin Hass
|
||||
// - https://www.impulseadventure.com/elec/guislice-gui.html
|
||||
// - https://github.com/ImpulseAdventure/GUIslice
|
||||
// =======================================================================
|
||||
//
|
||||
// The MIT License
|
||||
//
|
||||
// Copyright 2016-2020 Calvin Hass
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
//
|
||||
// =======================================================================
|
||||
/// \file XGauge.c
|
||||
|
||||
// *-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
|
||||
// WARNING: The XGauge element has been replaced by XProgress / XRadial / XRamp
|
||||
// Please update your code according to the migration notes in:
|
||||
// https://github.com/ImpulseAdventure/GUIslice/pull/157
|
||||
// XGauge may be removed in a future release.
|
||||
// *-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
|
||||
|
||||
|
||||
// GUIslice library
|
||||
#include "GUIslice.h"
|
||||
#include "GUIslice_drv.h"
|
||||
|
||||
#include "XGauge.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <math.h> // For sin/cos in XGauge(RADIAL)
|
||||
|
||||
#if (GSLC_USE_PROGMEM)
|
||||
#include <avr/pgmspace.h>
|
||||
#endif
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Error Messages
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
extern const char GSLC_PMEM ERRSTR_NULL[];
|
||||
extern const char GSLC_PMEM ERRSTR_PXD_NULL[];
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Extended element definitions
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// - This file extends the core GUIslice functionality with
|
||||
// additional widget types
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
|
||||
// ============================================================================
|
||||
// Extended Element: Gauge
|
||||
// - Basic progress bar with support for positive/negative state
|
||||
// and vertical / horizontal orientation.
|
||||
// ============================================================================
|
||||
|
||||
// Create a gauge element and add it to the GUI element list
|
||||
// - Defines default styling for the element
|
||||
// - Defines callback for redraw but does not track touch/click
|
||||
gslc_tsElemRef* gslc_ElemXGaugeCreate(gslc_tsGui* pGui,int16_t nElemId,int16_t nPage,
|
||||
gslc_tsXGauge* pXData,gslc_tsRect rElem,
|
||||
int16_t nMin,int16_t nMax,int16_t nVal,gslc_tsColor colGauge,bool bVert)
|
||||
{
|
||||
if ((pGui == NULL) || (pXData == NULL)) {
|
||||
static const char GSLC_PMEM FUNCSTR[] = "ElemXGaugeCreate";
|
||||
GSLC_DEBUG2_PRINT_CONST(ERRSTR_NULL,FUNCSTR);
|
||||
return NULL;
|
||||
}
|
||||
gslc_tsElem sElem;
|
||||
gslc_tsElemRef* pElemRef = NULL;
|
||||
sElem = gslc_ElemCreate(pGui,nElemId,nPage,GSLC_TYPEX_GAUGE,rElem,NULL,0,GSLC_FONT_NONE);
|
||||
sElem.nFeatures |= GSLC_ELEM_FEA_FRAME_EN;
|
||||
sElem.nFeatures |= GSLC_ELEM_FEA_FILL_EN;
|
||||
sElem.nFeatures &= ~GSLC_ELEM_FEA_CLICK_EN; // Element is not "clickable"
|
||||
sElem.nFeatures &= ~GSLC_ELEM_FEA_GLOW_EN;
|
||||
sElem.nGroup = GSLC_GROUP_ID_NONE;
|
||||
pXData->nMin = nMin;
|
||||
pXData->nMax = nMax;
|
||||
pXData->nVal = nVal;
|
||||
pXData->nStyle = GSLCX_GAUGE_STYLE_PROG_BAR; // Default to progress bar
|
||||
pXData->bVert = bVert;
|
||||
pXData->bFlip = false;
|
||||
pXData->colGauge = colGauge;
|
||||
pXData->colTick = GSLC_COL_GRAY;
|
||||
pXData->nTickCnt = 8;
|
||||
pXData->nTickLen = 5;
|
||||
pXData->nIndicLen = 10; // Dummy default to be overridden
|
||||
pXData->nIndicTip = 3; // Dummy default to be overridden
|
||||
pXData->bIndicFill = false;
|
||||
sElem.pXData = (void*)(pXData);
|
||||
sElem.pfuncXDraw = &gslc_ElemXGaugeDraw;
|
||||
sElem.pfuncXTouch = NULL; // No need to track touches
|
||||
sElem.colElemFill = GSLC_COL_BLACK;
|
||||
sElem.colElemFillGlow = GSLC_COL_BLACK;
|
||||
sElem.colElemFrame = GSLC_COL_GRAY;
|
||||
sElem.colElemFrameGlow = GSLC_COL_GRAY;
|
||||
GSLC_DEBUG_PRINT("NOTE: XGauge has been replaced by XProgress/XRadial/XRamp\n","");
|
||||
if (nPage != GSLC_PAGE_NONE) {
|
||||
pElemRef = gslc_ElemAdd(pGui,nPage,&sElem,GSLC_ELEMREF_DEFAULT);
|
||||
return pElemRef;
|
||||
#if (GSLC_FEATURE_COMPOUND)
|
||||
} else {
|
||||
// Save as temporary element
|
||||
pGui->sElemTmp = sElem;
|
||||
pGui->sElemRefTmp.pElem = &(pGui->sElemTmp);
|
||||
pGui->sElemRefTmp.eElemFlags = GSLC_ELEMREF_DEFAULT | GSLC_ELEMREF_REDRAW_FULL;
|
||||
return &(pGui->sElemRefTmp);
|
||||
#endif
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
void gslc_ElemXGaugeSetStyle(gslc_tsGui* pGui,gslc_tsElemRef* pElemRef,gslc_teXGaugeStyle nStyle)
|
||||
{
|
||||
if (pElemRef == NULL) {
|
||||
static const char GSLC_PMEM FUNCSTR[] = "ElemXGaugeSetStyle";
|
||||
GSLC_DEBUG2_PRINT_CONST(ERRSTR_NULL,FUNCSTR);
|
||||
return;
|
||||
}
|
||||
gslc_tsElem* pElem = gslc_GetElemFromRef(pGui,pElemRef);
|
||||
gslc_tsXGauge* pGauge = (gslc_tsXGauge*)(pElem->pXData);
|
||||
|
||||
// Update the type element
|
||||
pGauge->nStyle = nStyle;
|
||||
|
||||
// Just in case we were called at runtime, mark as needing redraw
|
||||
gslc_ElemSetRedraw(pGui,pElemRef,GSLC_REDRAW_FULL);
|
||||
}
|
||||
|
||||
void gslc_ElemXGaugeSetIndicator(gslc_tsGui* pGui,gslc_tsElemRef* pElemRef,gslc_tsColor colGauge,
|
||||
uint16_t nIndicLen,uint16_t nIndicTip,bool bIndicFill)
|
||||
{
|
||||
if (pElemRef == NULL) {
|
||||
static const char GSLC_PMEM FUNCSTR[] = "ElemXGaugeSetIndicator";
|
||||
GSLC_DEBUG2_PRINT_CONST(ERRSTR_NULL,FUNCSTR);
|
||||
return;
|
||||
}
|
||||
gslc_tsElem* pElem = gslc_GetElemFromRef(pGui,pElemRef);
|
||||
gslc_tsXGauge* pGauge = (gslc_tsXGauge*)(pElem->pXData);
|
||||
|
||||
// Update the config
|
||||
pGauge->colGauge = colGauge;
|
||||
pGauge->nIndicLen = nIndicLen;
|
||||
pGauge->nIndicTip = nIndicTip;
|
||||
pGauge->bIndicFill = bIndicFill;
|
||||
|
||||
// Just in case we were called at runtime, mark as needing redraw
|
||||
gslc_ElemSetRedraw(pGui,pElemRef,GSLC_REDRAW_FULL);
|
||||
}
|
||||
|
||||
void gslc_ElemXGaugeSetTicks(gslc_tsGui* pGui,gslc_tsElemRef* pElemRef,gslc_tsColor colTick,uint16_t nTickCnt,uint16_t nTickLen)
|
||||
{
|
||||
if (pElemRef == NULL) {
|
||||
static const char GSLC_PMEM FUNCSTR[] = "ElemXGaugeSetTicks";
|
||||
GSLC_DEBUG2_PRINT_CONST(ERRSTR_NULL,FUNCSTR);
|
||||
return;
|
||||
}
|
||||
gslc_tsElem* pElem = gslc_GetElemFromRef(pGui,pElemRef);
|
||||
gslc_tsXGauge* pGauge = (gslc_tsXGauge*)(pElem->pXData);
|
||||
|
||||
// Update the config
|
||||
pGauge->colTick = colTick;
|
||||
pGauge->nTickCnt = nTickCnt;
|
||||
pGauge->nTickLen = nTickLen;
|
||||
|
||||
// Just in case we were called at runtime, mark as needing redraw
|
||||
gslc_ElemSetRedraw(pGui,pElemRef,GSLC_REDRAW_FULL);
|
||||
}
|
||||
|
||||
// Update the gauge control's current position
|
||||
void gslc_ElemXGaugeUpdate(gslc_tsGui* pGui,gslc_tsElemRef* pElemRef,int16_t nVal)
|
||||
{
|
||||
if (pElemRef == NULL) {
|
||||
static const char GSLC_PMEM FUNCSTR[] = "ElemXGaugeUpdate";
|
||||
GSLC_DEBUG2_PRINT_CONST(ERRSTR_NULL,FUNCSTR);
|
||||
return;
|
||||
}
|
||||
gslc_tsElem* pElem = gslc_GetElemFromRef(pGui,pElemRef);
|
||||
gslc_tsXGauge* pGauge = (gslc_tsXGauge*)(pElem->pXData);
|
||||
|
||||
// Update the data element
|
||||
int16_t nValOld = pGauge->nVal;
|
||||
pGauge->nVal = nVal;
|
||||
|
||||
// Element needs redraw
|
||||
if (nVal != nValOld) {
|
||||
// We only need an incremental redraw
|
||||
// NOTE: If the user configures the indicator to be
|
||||
// long enough that it overlaps some of the gauge indicators
|
||||
// then a full redraw should be done instead.
|
||||
gslc_ElemSetRedraw(pGui,pElemRef,GSLC_REDRAW_INC);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Update the gauge's fill direction
|
||||
// - Setting bFlip causes the gauge to be filled in the reverse direction
|
||||
// to the default
|
||||
// - Default fill direction for horizontal gauges: left-to-right
|
||||
// - Default fill direction for vertical gauges: bottom-to-top
|
||||
void gslc_ElemXGaugeSetFlip(gslc_tsGui* pGui,gslc_tsElemRef* pElemRef,bool bFlip)
|
||||
{
|
||||
if (pElemRef == NULL) {
|
||||
static const char GSLC_PMEM FUNCSTR[] = "ElemXGaugeSetFlip";
|
||||
GSLC_DEBUG2_PRINT_CONST(ERRSTR_NULL,FUNCSTR);
|
||||
return;
|
||||
}
|
||||
|
||||
// Fetch the element's extended data structure
|
||||
gslc_tsElem* pElem = gslc_GetElemFromRef(pGui,pElemRef);
|
||||
gslc_tsXGauge* pGauge = (gslc_tsXGauge*)(pElem->pXData);
|
||||
if (pGauge == NULL) {
|
||||
GSLC_DEBUG2_PRINT("ERROR: gslc_ElemXGaugeSetFlip(%s) pXData is NULL\n","");
|
||||
return;
|
||||
}
|
||||
pGauge->bFlip = bFlip;
|
||||
|
||||
// Mark for redraw
|
||||
gslc_ElemSetRedraw(pGui,pElemRef,GSLC_REDRAW_FULL);
|
||||
|
||||
}
|
||||
|
||||
|
||||
// Redraw the gauge
|
||||
// - Note that this redraw is for the entire element rect region
|
||||
// - The Draw function parameters use void pointers to allow for
|
||||
// simpler callback function definition & scalability.
|
||||
bool gslc_ElemXGaugeDraw(void* pvGui,void* pvElemRef,gslc_teRedrawType eRedraw)
|
||||
{
|
||||
if ((pvGui == NULL) || (pvElemRef == NULL)) {
|
||||
static const char GSLC_PMEM FUNCSTR[] = "ElemXGaugeDraw";
|
||||
GSLC_DEBUG2_PRINT_CONST(ERRSTR_NULL,FUNCSTR);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Typecast the parameters to match the GUI and element types
|
||||
gslc_tsGui* pGui = (gslc_tsGui*)(pvGui);
|
||||
gslc_tsElemRef* pElemRef = (gslc_tsElemRef*)(pvElemRef);
|
||||
gslc_tsElem* pElem = gslc_GetElemFromRef(pGui,pElemRef);
|
||||
|
||||
// Fetch the element's extended data structure
|
||||
gslc_tsXGauge* pGauge;
|
||||
pGauge = (gslc_tsXGauge*)(pElem->pXData);
|
||||
if (pGauge == NULL) {
|
||||
GSLC_DEBUG2_PRINT("ERROR: ElemXGaugeDraw(%s) pXData is NULL\n","");
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (pGauge->nStyle) {
|
||||
case GSLCX_GAUGE_STYLE_PROG_BAR:
|
||||
gslc_ElemXGaugeDrawProgressBar(pGui,pElemRef,eRedraw);
|
||||
break;
|
||||
case GSLCX_GAUGE_STYLE_RADIAL:
|
||||
#if (GSLC_FEATURE_XGAUGE_RADIAL)
|
||||
gslc_ElemXGaugeDrawRadial(pGui,pElemRef,eRedraw);
|
||||
#endif
|
||||
break;
|
||||
case GSLCX_GAUGE_STYLE_RAMP:
|
||||
#if (GSLC_FEATURE_XGAUGE_RAMP)
|
||||
gslc_ElemXGaugeDrawRamp(pGui,pElemRef,eRedraw);
|
||||
#endif
|
||||
break;
|
||||
default:
|
||||
// ERROR
|
||||
break;
|
||||
}
|
||||
|
||||
// Save as "last state" to support incremental erase/redraw
|
||||
pGauge->nValLast = pGauge->nVal;
|
||||
pGauge->bValLastValid = true;
|
||||
|
||||
// Clear the redraw flag
|
||||
gslc_ElemSetRedraw(pGui,pElemRef,GSLC_REDRAW_NONE);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool gslc_ElemXGaugeDrawProgressBar(gslc_tsGui* pGui,gslc_tsElemRef* pElemRef,gslc_teRedrawType eRedraw)
|
||||
{
|
||||
gslc_tsElem* pElem = gslc_GetElemFromRef(pGui,pElemRef);
|
||||
gslc_tsXGauge* pGauge = (gslc_tsXGauge*)(pElem->pXData);
|
||||
|
||||
gslc_tsRect rTmp; // Temporary rect for drawing
|
||||
gslc_tsRect rGauge; // Filled portion of gauge
|
||||
gslc_tsRect rEmpty; // Empty portion of gauge
|
||||
uint16_t nElemW,nElemH;
|
||||
int16_t nElemX0,nElemY0,nElemX1,nElemY1;
|
||||
int16_t nGaugeX0,nGaugeY0,nGaugeX1,nGaugeY1;
|
||||
|
||||
nElemX0 = pElem->rElem.x;
|
||||
nElemY0 = pElem->rElem.y;
|
||||
nElemX1 = pElem->rElem.x + pElem->rElem.w - 1;
|
||||
nElemY1 = pElem->rElem.y + pElem->rElem.h - 1;
|
||||
nElemW = pElem->rElem.w;
|
||||
nElemH = pElem->rElem.h;
|
||||
|
||||
bool bVert = pGauge->bVert;
|
||||
bool bFlip = pGauge->bFlip;
|
||||
int16_t nMax = pGauge->nMax;
|
||||
int16_t nMin = pGauge->nMin;
|
||||
int16_t nRng = pGauge->nMax - pGauge->nMin;
|
||||
|
||||
uint32_t nScl = 1;
|
||||
int16_t nGaugeMid = 0;
|
||||
int16_t nLen = 0;
|
||||
int16_t nTmp = 0;
|
||||
int32_t nTmpL = 0;
|
||||
|
||||
if (nRng == 0) {
|
||||
GSLC_DEBUG2_PRINT("ERROR: ElemXGaugeDraw() Zero gauge range [%d,%d]\n",nMin,nMax);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (bVert) {
|
||||
nScl = nElemH*32768/nRng;
|
||||
} else {
|
||||
nScl = nElemW*32768/nRng;
|
||||
}
|
||||
|
||||
// Calculate the control midpoint/zeropoint (for display purposes)
|
||||
nTmpL = -((int32_t)nMin * (int32_t)nScl / 32768);
|
||||
nGaugeMid = (int16_t)nTmpL;
|
||||
|
||||
|
||||
// Calculate the length of the bar
|
||||
// - Use long mult/divide to avoid need for floating point
|
||||
nTmpL = (int32_t)(pGauge->nVal) * (int32_t)(nScl) / 32768;
|
||||
nLen = (int16_t)(nTmpL);
|
||||
|
||||
// Define the gauge's fill rectangle region
|
||||
// depending on the orientation (bVert) and whether
|
||||
// the current position is negative or positive.
|
||||
if (nLen >= 0) {
|
||||
if (bVert) {
|
||||
nGaugeY0 = nElemY0 + nGaugeMid;
|
||||
nGaugeY1 = nElemY0 + nGaugeMid + nLen;
|
||||
} else {
|
||||
nGaugeX0 = nElemX0 + nGaugeMid;
|
||||
nGaugeX1 = nElemX0 + nGaugeMid + nLen;
|
||||
}
|
||||
} else {
|
||||
if (bVert) {
|
||||
nGaugeY0 = nElemY0 + nGaugeMid + nLen;
|
||||
nGaugeY1 = nElemY0 + nGaugeMid;
|
||||
} else {
|
||||
nGaugeX0 = nElemX0 + nGaugeMid + nLen;
|
||||
nGaugeX1 = nElemX0 + nGaugeMid;
|
||||
}
|
||||
}
|
||||
if (bVert) {
|
||||
nGaugeX0 = nElemX0;
|
||||
nGaugeX1 = nElemX1;
|
||||
} else {
|
||||
nGaugeY0 = nElemY0;
|
||||
nGaugeY1 = nElemY1;
|
||||
}
|
||||
|
||||
|
||||
// Clip the region
|
||||
nGaugeX0 = (nGaugeX0 < nElemX0)? nElemX0 : nGaugeX0;
|
||||
nGaugeY0 = (nGaugeY0 < nElemY0)? nElemY0 : nGaugeY0;
|
||||
nGaugeX1 = (nGaugeX1 > nElemX1)? nElemX1 : nGaugeX1;
|
||||
nGaugeY1 = (nGaugeY1 > nElemY1)? nElemY1 : nGaugeY1;
|
||||
|
||||
// Support flipping of gauge directionality
|
||||
// - The bFlip flag reverses the fill direction
|
||||
// - Vertical gauges are flipped by default
|
||||
|
||||
if (bVert && !bFlip) {
|
||||
nTmp = nElemY0+(nElemY1-nGaugeY1); // nTmp will be swapped into nGaugeY0
|
||||
nGaugeY1 = nElemY1-(nGaugeY0-nElemY0);
|
||||
nGaugeY0 = nTmp;
|
||||
nGaugeMid = nElemH-nGaugeMid-1;
|
||||
} else if (!bVert && bFlip) {
|
||||
nTmp = nElemX0+(nElemX1-nGaugeX1); // nTmp will be swapped into nGaugeX0
|
||||
nGaugeX1 = nElemX1-(nGaugeX0-nElemX0);
|
||||
nGaugeX0 = nTmp;
|
||||
nGaugeMid = nElemW-nGaugeMid-1;
|
||||
}
|
||||
|
||||
#ifdef DBG_LOG
|
||||
//printf("Gauge: nMin=%4d nMax=%4d nRng=%d nVal=%4d fScl=%6.3f nGaugeMid=%4d RectX=%4d RectW=%4d\n",
|
||||
// nMin,nMax,nRng,pGauge->nGaugeVal,fScl,nGaugeMid,rGauge.x,rGauge.w);
|
||||
#endif
|
||||
|
||||
// Draw a frame around the gauge
|
||||
// - Only draw this during full redraw
|
||||
if (eRedraw == GSLC_REDRAW_FULL) {
|
||||
gslc_DrawFrameRect(pGui, pElem->rElem, pElem->colElemFrame);
|
||||
}
|
||||
|
||||
// To avoid flicker, we only erase the portion of the gauge
|
||||
// that isn't "filled". Determine the gauge empty region and erase it
|
||||
// There are two empty regions (one in negative and one in positive)
|
||||
int16_t nEmptyPos;
|
||||
if (bVert) {
|
||||
// Empty Region #1 (negative)
|
||||
nEmptyPos = (nGaugeY0 > nElemY1) ? nElemY1 : nGaugeY0;
|
||||
rEmpty = (gslc_tsRect){nElemX0,nElemY0,nElemX1-nElemX0+1,nEmptyPos-nElemY0+1};
|
||||
rTmp = gslc_ExpandRect(rEmpty,-1,-1);
|
||||
gslc_DrawFillRect(pGui,rTmp,pElem->colElemFill);
|
||||
// Empty Region #2 (positive)
|
||||
nEmptyPos = (nGaugeY1 < nElemY0) ? nElemY0 : nGaugeY1;
|
||||
rEmpty = (gslc_tsRect){nElemX0,nEmptyPos,nElemX1-nElemX0+1,nElemY1-nEmptyPos+1};
|
||||
rTmp = gslc_ExpandRect(rEmpty,-1,-1);
|
||||
gslc_DrawFillRect(pGui,rTmp,pElem->colElemFill);
|
||||
} else {
|
||||
// Empty Region #1 (negative)
|
||||
nEmptyPos = (nGaugeX0 > nElemX1) ? nElemX1 : nGaugeX0;
|
||||
rEmpty = (gslc_tsRect){nElemX0,nElemY0,nEmptyPos-nElemX0+1,nElemY1-nElemY0+1};
|
||||
rTmp = gslc_ExpandRect(rEmpty,-1,-1);
|
||||
gslc_DrawFillRect(pGui, rTmp, pElem->colElemFill);
|
||||
// Empty Region #2 (positive)
|
||||
nEmptyPos = (nGaugeX1 < nElemX0) ? nElemX0 : nGaugeX1;
|
||||
rEmpty = (gslc_tsRect){nEmptyPos,nElemY0,nElemX1-nEmptyPos+1,nElemY1-nElemY0+1};
|
||||
rTmp = gslc_ExpandRect(rEmpty,-1,-1);
|
||||
gslc_DrawFillRect(pGui, rTmp, pElem->colElemFill);
|
||||
}
|
||||
|
||||
// Draw the gauge fill region
|
||||
rGauge = (gslc_tsRect){nGaugeX0,nGaugeY0,nGaugeX1-nGaugeX0+1,nGaugeY1-nGaugeY0+1};
|
||||
rTmp = gslc_ExpandRect(rGauge,-1,-1);
|
||||
gslc_DrawFillRect(pGui,rTmp,pGauge->colGauge);
|
||||
|
||||
|
||||
// Draw the midpoint line
|
||||
if (bVert) {
|
||||
if (nElemY0 + nGaugeMid < nElemY1) {
|
||||
gslc_DrawLine(pGui, nElemX0, nElemY0 + nGaugeMid, nElemX1, nElemY0 + nGaugeMid, pElem->colElemFrame);
|
||||
}
|
||||
} else {
|
||||
if (nElemX0 + nGaugeMid < nElemX1) {
|
||||
gslc_DrawLine(pGui, nElemX0 + nGaugeMid, nElemY0, nElemX0 + nGaugeMid, nElemY1, pElem->colElemFrame);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#if (GSLC_FEATURE_XGAUGE_RADIAL)
|
||||
void gslc_ElemXGaugeDrawRadialHelp(gslc_tsGui* pGui,int16_t nX,int16_t nY,uint16_t nArrowLen,uint16_t nArrowSz,int16_t n64Ang,bool bFill,gslc_tsColor colFrame)
|
||||
{
|
||||
int16_t nTipX,nTipY;
|
||||
int16_t nBaseX1,nBaseY1,nBaseX2,nBaseY2;
|
||||
int16_t nTipBaseX,nTipBaseY;
|
||||
|
||||
gslc_PolarToXY(nArrowLen,n64Ang,&nTipX,&nTipY);
|
||||
gslc_PolarToXY(nArrowLen-nArrowSz,n64Ang,&nTipBaseX,&nTipBaseY);
|
||||
gslc_PolarToXY(nArrowSz,n64Ang-90*64,&nBaseX1,&nBaseY1);
|
||||
gslc_PolarToXY(nArrowSz,n64Ang+90*64,&nBaseX2,&nBaseY2);
|
||||
|
||||
if (!bFill) {
|
||||
// Framed
|
||||
gslc_DrawLine(pGui,nX+nBaseX1,nY+nBaseY1,nX+nBaseX1+nTipBaseX,nY+nBaseY1+nTipBaseY,colFrame);
|
||||
gslc_DrawLine(pGui,nX+nBaseX2,nY+nBaseY2,nX+nBaseX2+nTipBaseX,nY+nBaseY2+nTipBaseY,colFrame);
|
||||
gslc_DrawLine(pGui,nX+nBaseX1+nTipBaseX,nY+nBaseY1+nTipBaseY,nX+nTipX,nY+nTipY,colFrame);
|
||||
gslc_DrawLine(pGui,nX+nBaseX2+nTipBaseX,nY+nBaseY2+nTipBaseY,nX+nTipX,nY+nTipY,colFrame);
|
||||
gslc_DrawLine(pGui,nX+nBaseX1,nY+nBaseY1,nX+nBaseX2,nY+nBaseY2,colFrame);
|
||||
|
||||
} else {
|
||||
// Filled
|
||||
gslc_tsPt asPt[4];
|
||||
|
||||
// Main body of pointer
|
||||
asPt[0] = (gslc_tsPt){nX+nBaseX1,nY+nBaseY1};
|
||||
asPt[1] = (gslc_tsPt){nX+nBaseX1+nTipBaseX,nY+nBaseY1+nTipBaseY};
|
||||
asPt[2] = (gslc_tsPt){nX+nBaseX2+nTipBaseX,nY+nBaseY2+nTipBaseY};
|
||||
asPt[3] = (gslc_tsPt){nX+nBaseX2,nY+nBaseY2};
|
||||
gslc_DrawFillQuad(pGui,asPt,colFrame);
|
||||
|
||||
// Tip of pointer
|
||||
asPt[0] = (gslc_tsPt){nX+nBaseX1+nTipBaseX,nY+nBaseY1+nTipBaseY};
|
||||
asPt[1] = (gslc_tsPt){nX+nTipX,nY+nTipY};
|
||||
asPt[2] = (gslc_tsPt){nX+nBaseX2+nTipBaseX,nY+nBaseY2+nTipBaseY};
|
||||
gslc_DrawFillTriangle(pGui,asPt[0].x,asPt[0].y,asPt[1].x,asPt[1].y,asPt[2].x,asPt[2].y,colFrame);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
bool gslc_ElemXGaugeDrawRadial(gslc_tsGui* pGui,gslc_tsElemRef* pElemRef,gslc_teRedrawType eRedraw)
|
||||
{
|
||||
gslc_tsElem* pElem = gslc_GetElemFromRef(pGui,pElemRef);
|
||||
gslc_tsXGauge* pGauge = (gslc_tsXGauge*)(pElem->pXData);
|
||||
|
||||
uint16_t nElemW,nElemH,nElemRad;
|
||||
int16_t nElemX0,nElemY0,nElemX1,nElemY1;
|
||||
int16_t nElemMidX,nElemMidY;
|
||||
nElemX0 = pElem->rElem.x;
|
||||
nElemY0 = pElem->rElem.y;
|
||||
nElemX1 = pElem->rElem.x + pElem->rElem.w - 1;
|
||||
nElemY1 = pElem->rElem.y + pElem->rElem.h - 1;
|
||||
nElemMidX = (nElemX0+nElemX1)/2;
|
||||
nElemMidY = (nElemY0+nElemY1)/2;
|
||||
nElemW = pElem->rElem.w;
|
||||
nElemH = pElem->rElem.h;
|
||||
nElemRad = (nElemW>=nElemH)? nElemH/2 : nElemW/2;
|
||||
|
||||
int16_t nMax = pGauge->nMax;
|
||||
int16_t nMin = pGauge->nMin;
|
||||
int16_t nRng = pGauge->nMax - pGauge->nMin;
|
||||
int16_t nVal = pGauge->nVal;
|
||||
int16_t nValLast = pGauge->nValLast;
|
||||
bool bValLastValid = pGauge->bValLastValid;
|
||||
uint16_t nTickLen = pGauge->nTickLen;
|
||||
uint16_t nTickAng = 360 / pGauge->nTickCnt;
|
||||
uint16_t nArrowLen = pGauge->nIndicLen;
|
||||
uint16_t nArrowSize = pGauge->nIndicTip;
|
||||
bool bFill = pGauge->bIndicFill;
|
||||
|
||||
int16_t n64Ang,n64AngLast;
|
||||
int16_t nInd;
|
||||
|
||||
|
||||
if (nRng == 0) {
|
||||
GSLC_DEBUG2_PRINT("ERROR: ElemXRadialDraw() Zero range [%d,%d]\n",nMin,nMax);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Support reversing of direction
|
||||
// TODO: Clean up excess integer typecasting
|
||||
if (pGauge->bFlip) {
|
||||
n64Ang = (int32_t)(nMax - nVal )* 360*64 /nRng;
|
||||
n64AngLast = (int32_t)(nMax - nValLast)* 360*64 /nRng;
|
||||
} else {
|
||||
n64Ang = (int32_t)(nVal - nMin)* 360*64 /nRng;
|
||||
n64AngLast = (int32_t)(nValLast - nMin)* 360*64 /nRng;
|
||||
}
|
||||
|
||||
// Clear old
|
||||
if (bValLastValid) {
|
||||
gslc_ElemXGaugeDrawRadialHelp(pGui,nElemMidX,nElemMidY,nArrowLen,nArrowSize,n64AngLast,bFill,pElem->colElemFill);
|
||||
}
|
||||
|
||||
// Draw frame
|
||||
if (eRedraw == GSLC_REDRAW_FULL) {
|
||||
gslc_DrawFillCircle(pGui,nElemMidX,nElemMidY,nElemRad,pElem->colElemFill); // Erase first
|
||||
gslc_DrawFrameCircle(pGui,nElemMidX,nElemMidY,nElemRad,pElem->colElemFrame);
|
||||
for (nInd=0;nInd<360;nInd+=nTickAng) {
|
||||
gslc_DrawLinePolar(pGui,nElemMidX,nElemMidY,nElemRad-nTickLen,nElemRad,nInd*64,pGauge->colTick);
|
||||
}
|
||||
}
|
||||
|
||||
// Draw pointer
|
||||
gslc_ElemXGaugeDrawRadialHelp(pGui,nElemMidX,nElemMidY,nArrowLen,nArrowSize,n64Ang,bFill,pGauge->colGauge);
|
||||
|
||||
return true;
|
||||
}
|
||||
#endif // GSLC_FEATURE_XGAUGE_RADIAL
|
||||
|
||||
#ifdef GSLC_FEATURE_XGAUGE_RAMP
|
||||
bool gslc_ElemXGaugeDrawRamp(gslc_tsGui* pGui,gslc_tsElemRef* pElemRef,gslc_teRedrawType eRedraw)
|
||||
{
|
||||
gslc_tsElem* pElem = gslc_GetElemFromRef(pGui,pElemRef);
|
||||
gslc_tsXGauge* pGauge = (gslc_tsXGauge*)(pElem->pXData);
|
||||
|
||||
uint16_t nElemW,nElemH;
|
||||
int16_t nElemX0,nElemY1;
|
||||
nElemX0 = pElem->rElem.x;
|
||||
nElemY1 = pElem->rElem.y + pElem->rElem.h - 1;
|
||||
nElemW = pElem->rElem.w;
|
||||
nElemH = pElem->rElem.h;
|
||||
|
||||
int16_t nMax = pGauge->nMax;
|
||||
int16_t nMin = pGauge->nMin;
|
||||
int16_t nRng = pGauge->nMax - pGauge->nMin;
|
||||
int16_t nVal = pGauge->nVal;
|
||||
int16_t nValLast = pGauge->nValLast;
|
||||
bool bValLastValid = pGauge->bValLastValid;
|
||||
int16_t nInd;
|
||||
|
||||
if (nRng == 0) {
|
||||
GSLC_DEBUG2_PRINT("ERROR: gslc_ElemXGaugeDrawRamp() Zero range [%d,%d]\n",nMin,nMax);
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t nSclFX;
|
||||
uint16_t nHeight;
|
||||
int32_t nHeightTmp;
|
||||
uint16_t nHeightBot;
|
||||
uint16_t nX;
|
||||
uint16_t nColInd;
|
||||
|
||||
// Calculate region to draw or clear
|
||||
bool bModeErase;
|
||||
int16_t nValStart;
|
||||
int16_t nValEnd;
|
||||
if ((eRedraw == GSLC_REDRAW_INC) && (!bValLastValid)) {
|
||||
// - If the request was incremental (GSLC_REDRAW_INC) but
|
||||
// the last value wasn't marked as valid (!bValLastValid)
|
||||
// then we want to force a full redraw.
|
||||
// - We don't expect to enter here since bValLastValid
|
||||
// should always be set after we perform our first
|
||||
// redraw.
|
||||
eRedraw = GSLC_REDRAW_FULL;
|
||||
}
|
||||
if (eRedraw == GSLC_REDRAW_FULL) {
|
||||
// If we haven't drawn anything before, draw full range from zero
|
||||
bModeErase = false;
|
||||
nValStart = 0;
|
||||
nValEnd = nVal;
|
||||
} else {
|
||||
if (nVal >= nValLast) {
|
||||
// As we are advancing the control, we just draw the new range
|
||||
bModeErase = false;
|
||||
nValStart = nValLast;
|
||||
nValEnd = nVal;
|
||||
} else {
|
||||
// Since we are retracting the control, we erase the new range
|
||||
bModeErase = true;
|
||||
nValStart = nVal;
|
||||
nValEnd = nValLast;
|
||||
}
|
||||
}
|
||||
|
||||
// Calculate the scaled gauge position
|
||||
// - TODO: Also support reversing of direction
|
||||
int16_t nPosXStart,nPosXEnd;
|
||||
nPosXStart = (nValStart - nMin)*nElemW/nRng;
|
||||
nPosXEnd = (nValEnd - nMin)*nElemW/nRng;
|
||||
|
||||
nSclFX = (uint32_t)nElemH*32767/(nElemW*nElemW);
|
||||
|
||||
for (nX=nPosXStart;nX<nPosXEnd;nX++) {
|
||||
nInd = nElemW-nX;
|
||||
nHeightTmp = nSclFX * nInd*nInd /32767;
|
||||
nHeight = nElemH-nHeightTmp;
|
||||
if (nHeight >= 20) {
|
||||
nHeightBot = nHeight-20;
|
||||
} else {
|
||||
nHeightBot = 0;
|
||||
}
|
||||
gslc_tsColor nCol;
|
||||
uint16_t nSteps = 10;
|
||||
uint16_t nGap = 3;
|
||||
|
||||
if (nSteps == 0) {
|
||||
nColInd = nX*1000/nElemW;
|
||||
nCol = gslc_ColorBlend3(GSLC_COL_GREEN,GSLC_COL_YELLOW,GSLC_COL_RED,500,nColInd);
|
||||
} else {
|
||||
uint16_t nBlockLen,nSegLen,nSegInd,nSegOffset,nSegStart;
|
||||
nBlockLen = (nElemW-(nSteps-1)*nGap)/nSteps;
|
||||
nSegLen = nBlockLen + nGap;
|
||||
nSegInd = nX/nSegLen;
|
||||
nSegOffset = nX % nSegLen;
|
||||
nSegStart = nSegInd * nSegLen;
|
||||
|
||||
if (nSegOffset <= nBlockLen) {
|
||||
// Inside block
|
||||
nColInd = (uint32_t)nSegStart*1000/nElemW;
|
||||
nCol = gslc_ColorBlend3(GSLC_COL_GREEN,GSLC_COL_YELLOW,GSLC_COL_RED,500,nColInd);
|
||||
|
||||
} else {
|
||||
// Inside gap
|
||||
// - No draw
|
||||
nCol = pElem->colElemFill;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (bModeErase) {
|
||||
nCol = pElem->colElemFill;
|
||||
}
|
||||
gslc_DrawLine(pGui,nElemX0+nX,nElemY1-nHeightBot,nElemX0+nX,nElemY1-nHeight,nCol);
|
||||
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
#endif // GLSC_FEATURE_XGAUGE_RAMP
|
||||
|
||||
|
||||
// ============================================================================
|
394
src/guislice/XGauge.h
Normal file
394
src/guislice/XGauge.h
Normal file
|
@ -0,0 +1,394 @@
|
|||
#ifndef _GUISLICE_EX_XGAUGE_H_
|
||||
#define _GUISLICE_EX_XGAUGE_H_
|
||||
|
||||
#include "GUIslice.h"
|
||||
|
||||
|
||||
// =======================================================================
|
||||
// GUIslice library extension: Gauge control (See replacement warning below)
|
||||
// - Calvin Hass
|
||||
// - https://www.impulseadventure.com/elec/guislice-gui.html
|
||||
// - https://github.com/ImpulseAdventure/GUIslice
|
||||
// =======================================================================
|
||||
//
|
||||
// The MIT License
|
||||
//
|
||||
// Copyright 2016-2020 Calvin Hass
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
//
|
||||
// =======================================================================
|
||||
/// \file XGauge.h
|
||||
|
||||
// *-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
|
||||
// WARNING: The XGauge element has been replaced by XProgress / XRadial / XRamp
|
||||
// Please update your code according to the migration notes in:
|
||||
// https://github.com/ImpulseAdventure/GUIslice/pull/157
|
||||
// XGauge may be removed in a future release.
|
||||
// *-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif // __cplusplus
|
||||
|
||||
|
||||
// ============================================================================
|
||||
// Extended Element: Gauge
|
||||
// ============================================================================
|
||||
|
||||
// Define unique identifier for extended element type
|
||||
// - Select any number above GSLC_TYPE_BASE_EXTEND
|
||||
#define GSLC_TYPEX_GAUGE GSLC_TYPE_BASE_EXTEND + 0
|
||||
|
||||
|
||||
/// Gauge drawing style
|
||||
typedef enum {
|
||||
GSLCX_GAUGE_STYLE_PROG_BAR, ///< Progress bar
|
||||
GSLCX_GAUGE_STYLE_RADIAL, ///< Radial indicator
|
||||
GSLCX_GAUGE_STYLE_RAMP, ///< Ramp indicator
|
||||
} gslc_teXGaugeStyle;
|
||||
|
||||
// Extended element data structures
|
||||
// - These data structures are maintained in the gslc_tsElem
|
||||
// structure via the pXData pointer
|
||||
|
||||
/// Extended data for Gauge element
|
||||
typedef struct {
|
||||
// Range config
|
||||
int16_t nMin; ///< Minimum control value
|
||||
int16_t nMax; ///< Maximum control value
|
||||
|
||||
// Current value
|
||||
int16_t nVal; ///< Current control value
|
||||
// Previous value
|
||||
int16_t nValLast; ///< Last value
|
||||
bool bValLastValid; ///< Last value valid?
|
||||
|
||||
// Appearance config
|
||||
gslc_teXGaugeStyle nStyle; ///< Gauge sub-type
|
||||
gslc_tsColor colGauge; ///< Color of gauge fill bar
|
||||
gslc_tsColor colTick; ///< Color of gauge tick marks
|
||||
uint16_t nTickCnt; ///< Number of gauge tick marks
|
||||
uint16_t nTickLen; ///< Length of gauge tick marks
|
||||
bool bVert; ///< Vertical if true, else Horizontal
|
||||
bool bFlip; ///< Reverse direction of gauge
|
||||
uint16_t nIndicLen; ///< Indicator length
|
||||
uint16_t nIndicTip; ///< Size of tip at end of indicator
|
||||
bool bIndicFill; ///< Fill the indicator if true
|
||||
|
||||
} gslc_tsXGauge;
|
||||
|
||||
|
||||
///
|
||||
/// Create a Gauge Element
|
||||
/// - Draws a gauge element that represents a proportion (nVal)
|
||||
/// between nMin and nMax.
|
||||
/// - Support gauge sub-types:
|
||||
/// - GSLC_TYPEX_GAUGE_PROG_BAR: Horizontal or vertical box with filled region
|
||||
/// - GSLC_TYPEX_GAUGE_RADIAL: Radial / compass indicator
|
||||
/// - Default appearance is a horizontal progress bar, but can be changed
|
||||
/// with gslc_ElemXGaugeSetStyle())
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] nElemId: Element ID to assign (0..16383 or GSLC_ID_AUTO to autogen)
|
||||
/// \param[in] nPage: Page ID to attach element to
|
||||
/// \param[in] pXData: Ptr to extended element data structure
|
||||
/// \param[in] rElem: Rectangle coordinates defining gauge size
|
||||
/// \param[in] nMin: Minimum value of gauge for nVal comparison
|
||||
/// \param[in] nMax: Maximum value of gauge for nVal comparison
|
||||
/// \param[in] nVal: Starting value of gauge
|
||||
/// \param[in] colGauge: Color for the gauge indicator
|
||||
/// \param[in] bVert: Flag to indicate vertical vs horizontal action
|
||||
/// (true = vertical, false = horizontal)
|
||||
///
|
||||
/// \return Pointer to Element reference or NULL if failure
|
||||
///
|
||||
gslc_tsElemRef* gslc_ElemXGaugeCreate(gslc_tsGui* pGui,int16_t nElemId,int16_t nPage,
|
||||
gslc_tsXGauge* pXData,gslc_tsRect rElem,int16_t nMin,int16_t nMax,int16_t nVal,gslc_tsColor colGauge,bool bVert);
|
||||
|
||||
|
||||
///
|
||||
/// Configure the style of a Gauge element
|
||||
/// - This function is used to select between one of several gauge types
|
||||
/// (eg. progress bar, radial dial, etc.)
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] pElemRef: Pointer to Element reference
|
||||
/// \param[in] nType: Gauge style enumeration
|
||||
///
|
||||
/// \return none
|
||||
///
|
||||
void gslc_ElemXGaugeSetStyle(gslc_tsGui* pGui,gslc_tsElemRef* pElemRef,gslc_teXGaugeStyle nType);
|
||||
|
||||
|
||||
///
|
||||
/// Configure the appearance of the Gauge indicator
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] pElemRef: Pointer to Element reference
|
||||
/// \param[in] colGauge: Color of the indicator
|
||||
/// \param[in] nIndicLen: Length of the indicator
|
||||
/// \param[in] nIndicTip: Size of the indicator tip
|
||||
/// \param[in] bIndicFill: Fill in the indicator if true
|
||||
///
|
||||
/// \return none
|
||||
///
|
||||
void gslc_ElemXGaugeSetIndicator(gslc_tsGui* pGui,gslc_tsElemRef* pElemRef,gslc_tsColor colGauge,
|
||||
uint16_t nIndicLen,uint16_t nIndicTip,bool bIndicFill);
|
||||
|
||||
|
||||
///
|
||||
/// Configure the appearance of the Gauge ticks
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] pElemRef: Pointer to Element reference
|
||||
/// \param[in] colTick: Color of the gauge ticks
|
||||
/// \param[in] nTickCnt: Number of ticks to draw around / along gauge
|
||||
/// \param[in] nTickLen: Length of the tick marks to draw
|
||||
///
|
||||
/// \return none
|
||||
///
|
||||
void gslc_ElemXGaugeSetTicks(gslc_tsGui* pGui,gslc_tsElemRef* pElemRef,gslc_tsColor colTick,uint16_t nTickCnt,uint16_t nTickLen);
|
||||
|
||||
|
||||
///
|
||||
/// Update a Gauge element's current value
|
||||
/// - Note that min & max values are assigned in create()
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] pElemRef: Pointer to Element reference
|
||||
/// \param[in] nVal: New value to show in gauge
|
||||
///
|
||||
/// \return none
|
||||
///
|
||||
void gslc_ElemXGaugeUpdate(gslc_tsGui* pGui,gslc_tsElemRef* pElemRef,int16_t nVal);
|
||||
|
||||
|
||||
///
|
||||
/// Set a Gauge element's fill direction
|
||||
/// - Setting bFlip reverses the default fill direction
|
||||
/// - Default fill direction for horizontal gauges: left-to-right
|
||||
/// - Default fill direction for vertical gauges: bottom-to-top
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] pElemRef: Pointer to Element reference
|
||||
/// \param[in] bFlip: If set, reverse direction of fill from default
|
||||
///
|
||||
/// \return none
|
||||
///
|
||||
void gslc_ElemXGaugeSetFlip(gslc_tsGui* pGui,gslc_tsElemRef* pElemRef,bool bFlip);
|
||||
|
||||
|
||||
///
|
||||
/// Draw a gauge element on the screen
|
||||
/// - Called from gslc_ElemDraw()
|
||||
///
|
||||
/// \param[in] pvGui: Void ptr to GUI (typecast to gslc_tsGui*)
|
||||
/// \param[in] pvElemRef: Void ptr to Element reference (typecast to gslc_tsElemRef*)
|
||||
/// \param[in] eRedraw: Redraw mode
|
||||
///
|
||||
/// \return true if success, false otherwise
|
||||
///
|
||||
bool gslc_ElemXGaugeDraw(void* pvGui,void* pvElemRef,gslc_teRedrawType eRedraw);
|
||||
|
||||
|
||||
///
|
||||
/// Helper function to draw a gauge with style: progress bar
|
||||
/// - Called from gslc_ElemXGaugeDraw()
|
||||
///
|
||||
/// \param[in] pGui: Ptr to GUI
|
||||
/// \param[in] pElemRef: Ptr to Element reference
|
||||
/// \param[in] eRedraw: Redraw status
|
||||
///
|
||||
/// \return true if success, false otherwise
|
||||
///
|
||||
bool gslc_ElemXGaugeDrawProgressBar(gslc_tsGui* pGui,gslc_tsElemRef* pElemRef,gslc_teRedrawType eRedraw);
|
||||
|
||||
#if (GSLC_FEATURE_XGAUGE_RADIAL)
|
||||
///
|
||||
/// Helper function to draw a gauge with style: radial
|
||||
/// - Called from gslc_ElemXGaugeDraw()
|
||||
///
|
||||
/// \param[in] pGui: Ptr to GUI
|
||||
/// \param[in] pElemRef: Ptr to Element reference
|
||||
/// \param[in] eRedraw: Redraw status
|
||||
///
|
||||
/// \return true if success, false otherwise
|
||||
///
|
||||
bool gslc_ElemXGaugeDrawRadial(gslc_tsGui* pGui,gslc_tsElemRef* pElemRef,gslc_teRedrawType eRedraw);
|
||||
#endif
|
||||
|
||||
#if (GSLC_FEATURE_XGAUGE_RAMP)
|
||||
///
|
||||
/// Helper function to draw a gauge with style: ramp
|
||||
/// - Called from gslc_ElemXGaugeDraw()
|
||||
///
|
||||
/// \param[in] pGui: Ptr to GUI
|
||||
/// \param[in] pElemRef: Ptr to Element reference
|
||||
/// \param[in] eRedraw: Redraw status
|
||||
///
|
||||
/// \return true if success, false otherwise
|
||||
///
|
||||
bool gslc_ElemXGaugeDrawRamp(gslc_tsGui* pGui,gslc_tsElemRef* pElemRef,gslc_teRedrawType eRedraw);
|
||||
#endif
|
||||
|
||||
// ============================================================================
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Read-only element macros
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
// Macro initializers for Read-Only Elements in Flash/PROGMEM
|
||||
//
|
||||
|
||||
|
||||
/// \def gslc_ElemXGaugeCreate_P(pGui,nElemId,nPage,nX,nY,nW,nH,
|
||||
/// nMin_,nMax_,nVal_,colFrame_,colFill_,colGauge_,bVert_)
|
||||
///
|
||||
/// Create a Gauge Element in Flash
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] nElemId: Unique element ID to assign
|
||||
/// \param[in] nPage: Page ID to attach element to
|
||||
/// \param[in] nX: X coordinate of element
|
||||
/// \param[in] nY: Y coordinate of element
|
||||
/// \param[in] nW: Width of element
|
||||
/// \param[in] nH: Height of element
|
||||
/// \param[in] nMin_: Minimum value of gauge for nVal comparison
|
||||
/// \param[in] nMax_: Maximum value of gauge for nVal comparison
|
||||
/// \param[in] nVal_: Starting value of gauge
|
||||
/// \param[in] colFrame_: Color for the gauge frame
|
||||
/// \param[in] colFill_: Color for the gauge background fill
|
||||
/// \param[in] colGauge_: Color for the gauge indicator
|
||||
/// \param[in] bVert_: Flag to indicate vertical vs horizontal action
|
||||
/// (true = vertical, false = horizontal)
|
||||
///
|
||||
/// \return none
|
||||
///
|
||||
|
||||
|
||||
#if (GSLC_USE_PROGMEM)
|
||||
|
||||
|
||||
#define gslc_ElemXGaugeCreate_P(pGui,nElemId,nPage,nX,nY,nW,nH,\
|
||||
nMin_,nMax_,nVal_,colFrame_,colFill_,colGauge_,bVert_) \
|
||||
static const uint8_t nFeatures##nElemId = GSLC_ELEM_FEA_VALID | \
|
||||
GSLC_ELEM_FEA_GLOW_EN | GSLC_ELEM_FEA_FILL_EN; \
|
||||
static gslc_tsXGauge sGauge##nElemId; \
|
||||
sGauge##nElemId.nMin = nMin_; \
|
||||
sGauge##nElemId.nMax = nMax_; \
|
||||
sGauge##nElemId.nVal = nVal_; \
|
||||
sGauge##nElemId.nValLast = nVal_; \
|
||||
sGauge##nElemId.bValLastValid = false; \
|
||||
sGauge##nElemId.nStyle = GSLCX_GAUGE_STYLE_PROG_BAR; \
|
||||
sGauge##nElemId.colGauge = colGauge_; \
|
||||
sGauge##nElemId.colTick = GSLC_COL_GRAY; \
|
||||
sGauge##nElemId.nTickCnt = 8; \
|
||||
sGauge##nElemId.nTickLen = 5; \
|
||||
sGauge##nElemId.bVert = bVert_; \
|
||||
sGauge##nElemId.bFlip = false; \
|
||||
sGauge##nElemId.nIndicLen = 10; \
|
||||
sGauge##nElemId.nIndicTip = 3; \
|
||||
sGauge##nElemId.bIndicFill = false; \
|
||||
static const gslc_tsElem sElem##nElemId PROGMEM = { \
|
||||
nElemId, \
|
||||
nFeatures##nElemId, \
|
||||
GSLC_TYPEX_GAUGE, \
|
||||
(gslc_tsRect){nX,nY,nW,nH}, \
|
||||
GSLC_GROUP_ID_NONE, \
|
||||
colFrame_,colFill_,colFrame_,colFill_, \
|
||||
(gslc_tsImgRef){NULL,NULL,GSLC_IMGREF_NONE,NULL}, \
|
||||
(gslc_tsImgRef){NULL,NULL,GSLC_IMGREF_NONE,NULL}, \
|
||||
NULL, \
|
||||
NULL, \
|
||||
0, \
|
||||
(gslc_teTxtFlags)(GSLC_TXT_DEFAULT), \
|
||||
GSLC_COL_WHITE, \
|
||||
GSLC_COL_WHITE, \
|
||||
GSLC_ALIGN_MID_MID, \
|
||||
0, \
|
||||
0, \
|
||||
NULL, \
|
||||
(void*)(&sGauge##nElemId), \
|
||||
NULL, \
|
||||
&gslc_ElemXGaugeDraw, \
|
||||
NULL, \
|
||||
NULL, \
|
||||
}; \
|
||||
gslc_ElemAdd(pGui,nPage,(gslc_tsElem*)&sElem##nElemId, \
|
||||
(gslc_teElemRefFlags)(GSLC_ELEMREF_SRC_PROG | GSLC_ELEMREF_VISIBLE | GSLC_ELEMREF_REDRAW_FULL));
|
||||
|
||||
#else
|
||||
|
||||
|
||||
#define gslc_ElemXGaugeCreate_P(pGui,nElemId,nPage,nX,nY,nW,nH,\
|
||||
nMin_,nMax_,nVal_,colFrame_,colFill_,colGauge_,bVert_) \
|
||||
static const uint8_t nFeatures##nElemId = GSLC_ELEM_FEA_VALID | \
|
||||
GSLC_ELEM_FEA_GLOW_EN | GSLC_ELEM_FEA_FILL_EN; \
|
||||
static gslc_tsXGauge sGauge##nElemId; \
|
||||
sGauge##nElemId.nMin = nMin_; \
|
||||
sGauge##nElemId.nMax = nMax_; \
|
||||
sGauge##nElemId.nVal = nVal_; \
|
||||
sGauge##nElemId.nValLast = nVal_; \
|
||||
sGauge##nElemId.bValLastValid = false; \
|
||||
sGauge##nElemId.nStyle = GSLCX_GAUGE_STYLE_PROG_BAR; \
|
||||
sGauge##nElemId.colGauge = colGauge_; \
|
||||
sGauge##nElemId.colTick = GSLC_COL_GRAY; \
|
||||
sGauge##nElemId.nTickCnt = 8; \
|
||||
sGauge##nElemId.nTickLen = 5; \
|
||||
sGauge##nElemId.bVert = bVert_; \
|
||||
sGauge##nElemId.bFlip = false; \
|
||||
sGauge##nElemId.nIndicLen = 10; \
|
||||
sGauge##nElemId.nIndicTip = 3; \
|
||||
sGauge##nElemId.bIndicFill = false; \
|
||||
static const gslc_tsElem sElem##nElemId = { \
|
||||
nElemId, \
|
||||
nFeatures##nElemId, \
|
||||
GSLC_TYPEX_GAUGE, \
|
||||
(gslc_tsRect){nX,nY,nW,nH}, \
|
||||
GSLC_GROUP_ID_NONE, \
|
||||
colFrame_,colFill_,colFrame_,colFill_, \
|
||||
(gslc_tsImgRef){NULL,NULL,GSLC_IMGREF_NONE,NULL}, \
|
||||
(gslc_tsImgRef){NULL,NULL,GSLC_IMGREF_NONE,NULL}, \
|
||||
NULL, \
|
||||
NULL, \
|
||||
0, \
|
||||
(gslc_teTxtFlags)(GSLC_TXT_DEFAULT), \
|
||||
GSLC_COL_WHITE, \
|
||||
GSLC_COL_WHITE, \
|
||||
GSLC_ALIGN_MID_MID, \
|
||||
0, \
|
||||
0, \
|
||||
NULL, \
|
||||
(void*)(&sGauge##nElemId), \
|
||||
NULL, \
|
||||
&gslc_ElemXGaugeDraw, \
|
||||
NULL, \
|
||||
NULL, \
|
||||
}; \
|
||||
gslc_ElemAdd(pGui,nPage,(gslc_tsElem*)&sElem##nElemId, \
|
||||
(gslc_teElemRefFlags)(GSLC_ELEMREF_SRC_CONST | GSLC_ELEMREF_VISIBLE | GSLC_ELEMREF_REDRAW_FULL));
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif // __cplusplus
|
||||
#endif // _GUISLICE_EX_XGAUGE_H_
|
||||
|
348
src/guislice/XGlowball.c
Normal file
348
src/guislice/XGlowball.c
Normal file
|
@ -0,0 +1,348 @@
|
|||
// =======================================================================
|
||||
// GUIslice library extension: XGlowball
|
||||
// - Calvin Hass
|
||||
// - https://www.impulseadventure.com/elec/guislice-gui.html
|
||||
// - https://github.com/ImpulseAdventure/GUIslice
|
||||
// =======================================================================
|
||||
//
|
||||
// The MIT License
|
||||
//
|
||||
// Copyright 2016-2020 Calvin Hass
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
//
|
||||
// =======================================================================
|
||||
/// \file XGlowball.c
|
||||
|
||||
|
||||
|
||||
// GUIslice library
|
||||
#include "GUIslice.h"
|
||||
#include "GUIslice_drv.h"
|
||||
|
||||
#include "XGlowball.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#if (GSLC_USE_PROGMEM)
|
||||
#include <avr/pgmspace.h>
|
||||
#endif
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Error Messages
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
extern const char GSLC_PMEM ERRSTR_NULL[];
|
||||
extern const char GSLC_PMEM ERRSTR_PXD_NULL[];
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Extended element definitions
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// - This file extends the core GUIslice functionality with
|
||||
// additional widget types
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
|
||||
// ============================================================================
|
||||
// Extended Element: XGlowball
|
||||
// ============================================================================
|
||||
|
||||
// Create a XGlowball element and add it to the GUI element list
|
||||
// - Defines default styling for the element
|
||||
// - Defines callback for redraw and touch
|
||||
gslc_tsElemRef* gslc_ElemXGlowballCreate(gslc_tsGui* pGui, int16_t nElemId, int16_t nPage,
|
||||
gslc_tsXGlowball* pXData, int16_t nMidX, int16_t nMidY, gslc_tsXGlowballRing* pRings, uint8_t nNumRings)
|
||||
{
|
||||
if ((pGui == NULL) || (pXData == NULL)) {
|
||||
static const char GSLC_PMEM FUNCSTR[] = "ElemXGlowballCreate";
|
||||
GSLC_DEBUG2_PRINT_CONST(ERRSTR_NULL,FUNCSTR);
|
||||
return NULL;
|
||||
}
|
||||
gslc_tsElem sElem;
|
||||
gslc_tsElemRef* pElemRef = NULL;
|
||||
|
||||
// Calculate the actual element dimensions based on the ring defintion
|
||||
// - Note that we use the outer radius of the last ring
|
||||
int16_t nRadMax;
|
||||
gslc_tsRect rElem;
|
||||
nRadMax = pRings[nNumRings - 1].nRad2;
|
||||
rElem.w = 2 * nRadMax;
|
||||
rElem.h = 2 * nRadMax;
|
||||
rElem.x = nMidX - nRadMax;
|
||||
rElem.y = nMidY - nRadMax;
|
||||
|
||||
sElem = gslc_ElemCreate(pGui,nElemId,nPage,GSLC_TYPEX_GLOW,rElem,NULL,0,GSLC_FONT_NONE);
|
||||
sElem.colElemFill = GSLC_COL_BLACK;
|
||||
sElem.colElemFillGlow = GSLC_COL_BLACK;
|
||||
sElem.colElemFrame = GSLC_COL_GRAY;
|
||||
sElem.colElemFrameGlow = GSLC_COL_GRAY;
|
||||
sElem.colElemText = GSLC_COL_WHITE;
|
||||
sElem.colElemTextGlow = GSLC_COL_WHITE;
|
||||
sElem.nFeatures |= GSLC_ELEM_FEA_FILL_EN;
|
||||
sElem.nFeatures &= ~GSLC_ELEM_FEA_FRAME_EN;
|
||||
sElem.nFeatures |= GSLC_ELEM_FEA_CLICK_EN;
|
||||
sElem.nFeatures |= GSLC_ELEM_FEA_GLOW_EN;
|
||||
sElem.eTxtAlign = GSLC_ALIGN_MID_LEFT;
|
||||
|
||||
sElem.nGroup = GSLC_GROUP_ID_NONE;
|
||||
|
||||
// Initialize any pxData members with default parameters
|
||||
pXData->nVal = 0;
|
||||
pXData->nQuality = 72;
|
||||
pXData->nAngStart = 0;
|
||||
pXData->nAngEnd = 360;
|
||||
pXData->pRings = pRings;
|
||||
pXData->nNumRings = nNumRings;
|
||||
pXData->nMidX = nMidX;
|
||||
pXData->nMidY = nMidY;
|
||||
pXData->colBg = GSLC_COL_BLACK;
|
||||
pXData->nValLast = 0;
|
||||
|
||||
|
||||
sElem.pXData = (void*)(pXData);
|
||||
// Specify the custom drawing callback
|
||||
sElem.pfuncXDraw = &gslc_ElemXGlowballDraw;
|
||||
// Specify the custom touch tracking callback
|
||||
sElem.pfuncXTouch = NULL;
|
||||
|
||||
if (nPage != GSLC_PAGE_NONE) {
|
||||
pElemRef = gslc_ElemAdd(pGui,nPage,&sElem,GSLC_ELEMREF_DEFAULT);
|
||||
return pElemRef;
|
||||
#if (GSLC_FEATURE_COMPOUND)
|
||||
} else {
|
||||
// Save as temporary element
|
||||
pGui->sElemTmp = sElem;
|
||||
pGui->sElemRefTmp.pElem = &(pGui->sElemTmp);
|
||||
pGui->sElemRefTmp.eElemFlags = GSLC_ELEMREF_DEFAULT | GSLC_ELEMREF_REDRAW_FULL;
|
||||
return &(pGui->sElemRefTmp);
|
||||
#endif
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
void drawXGlowballArc(gslc_tsGui* pGui, gslc_tsXGlowball* pGlowball, int16_t nMidX, int16_t nMidY, int16_t nRad1, int16_t nRad2, gslc_tsColor cArc, uint16_t nAngStart, uint16_t nAngEnd)
|
||||
{
|
||||
gslc_tsPt anPts[4];
|
||||
// TODO: Cleanup
|
||||
int16_t nStep64 = 64*360 / pGlowball->nQuality;
|
||||
int16_t nAng64;
|
||||
int16_t nX, nY;
|
||||
int16_t nSegStart, nSegEnd;
|
||||
nSegStart = nAngStart * pGlowball->nQuality / 360;
|
||||
nSegEnd = nAngEnd * pGlowball->nQuality / 360;
|
||||
|
||||
for (uint16_t nSegInd = nSegStart; nSegInd < nSegEnd; nSegInd++) {
|
||||
nAng64 = nSegInd * nStep64;
|
||||
nAng64 = nAng64 % (360 * 64);
|
||||
|
||||
gslc_PolarToXY(nRad1, nAng64, &nX, &nY);
|
||||
anPts[0] = (gslc_tsPt) { nMidX + nX, nMidY + nY };
|
||||
gslc_PolarToXY(nRad2, nAng64, &nX, &nY);
|
||||
anPts[1] = (gslc_tsPt) { nMidX + nX, nMidY + nY };
|
||||
gslc_PolarToXY(nRad2, nAng64 + nStep64, &nX, &nY);
|
||||
anPts[2] = (gslc_tsPt) { nMidX + nX, nMidY + nY };
|
||||
gslc_PolarToXY(nRad1, nAng64 + nStep64, &nX, &nY);
|
||||
anPts[3] = (gslc_tsPt) { nMidX + nX, nMidY + nY };
|
||||
|
||||
gslc_DrawFillQuad(pGui, anPts, cArc);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void drawXGlowballRing(gslc_tsGui* pGui, gslc_tsXGlowball* pGlowball, int16_t nMidX, int16_t nMidY, int16_t nVal, uint16_t nAngStart, uint16_t nAngEnd, bool bErase)
|
||||
{
|
||||
int16_t nRad1, nRad2;
|
||||
gslc_tsColor cCol;
|
||||
|
||||
if ((nVal <= 0) || (nVal > pGlowball->nNumRings)) {
|
||||
return;
|
||||
}
|
||||
|
||||
nRad1 = pGlowball->pRings[nVal - 1].nRad1;
|
||||
nRad2 = pGlowball->pRings[nVal - 1].nRad2;
|
||||
cCol = (bErase) ? pGlowball->colBg : pGlowball->pRings[nVal - 1].cCol;
|
||||
|
||||
drawXGlowballArc(pGui, pGlowball, nMidX, nMidY, nRad1, nRad2, cCol, nAngStart, nAngEnd);
|
||||
}
|
||||
|
||||
// nAngStart & nAngEnd define the range (in degrees) for the XGlowball arcs
|
||||
// - Angles are measured with 0 degrees at the top, incrementing clockwise
|
||||
// - Note that the supported range is 0..510 degrees
|
||||
// nVal represents the value to set (0.. NUM_RINGS)
|
||||
// nMidX,nMidY define the center of the XGlowball
|
||||
void drawXGlowball(gslc_tsGui* pGui,gslc_tsXGlowball* pGlowball, int16_t nMidX, int16_t nMidY, int16_t nVal, uint16_t nAngStart, uint16_t nAngEnd)
|
||||
{
|
||||
int16_t nValLast = pGlowball->nValLast;
|
||||
int8_t nRingInd;
|
||||
|
||||
if (nVal > nValLast) {
|
||||
for (nRingInd = nValLast + 1; nRingInd <= nVal; nRingInd++) {
|
||||
drawXGlowballRing(pGui, pGlowball, nMidX, nMidY, nRingInd, nAngStart, nAngEnd, false);
|
||||
}
|
||||
} else {
|
||||
for (nRingInd = nValLast; nRingInd > nVal; nRingInd--) {
|
||||
drawXGlowballRing(pGui, pGlowball, nMidX, nMidY, nRingInd, nAngStart, nAngEnd, true);
|
||||
}
|
||||
}
|
||||
pGlowball->nValLast = nVal;
|
||||
}
|
||||
|
||||
void gslc_ElemXGlowballSetVal(gslc_tsGui* pGui, gslc_tsElemRef* pElemRef, int16_t nVal)
|
||||
{
|
||||
if ((pGui == NULL) || (pElemRef == NULL)) {
|
||||
static const char GSLC_PMEM FUNCSTR[] = "ElemXGlowballSetVal";
|
||||
GSLC_DEBUG2_PRINT_CONST(ERRSTR_NULL,FUNCSTR);
|
||||
return;
|
||||
}
|
||||
gslc_tsElem* pElem = gslc_GetElemFromRef(pGui,pElemRef);
|
||||
gslc_tsXGlowball* pGlowball = (gslc_tsXGlowball*)(pElem->pXData);
|
||||
|
||||
// Update the value
|
||||
pGlowball->nVal = nVal;
|
||||
|
||||
// Mark for redraw
|
||||
// - Only need incremental redraw
|
||||
gslc_ElemSetRedraw(pGui,pElemRef,GSLC_REDRAW_INC);
|
||||
}
|
||||
|
||||
void gslc_ElemXGlowballSetAngles(gslc_tsGui* pGui, gslc_tsElemRef* pElemRef, int16_t nAngStart, int16_t nAngEnd)
|
||||
{
|
||||
if ((pGui == NULL) || (pElemRef == NULL)) {
|
||||
static const char GSLC_PMEM FUNCSTR[] = "ElemXGlowballSetAngles";
|
||||
GSLC_DEBUG2_PRINT_CONST(ERRSTR_NULL,FUNCSTR);
|
||||
return;
|
||||
}
|
||||
gslc_tsElem* pElem = gslc_GetElemFromRef(pGui,pElemRef);
|
||||
gslc_tsXGlowball* pGlowball = (gslc_tsXGlowball*)(pElem->pXData);
|
||||
|
||||
// Update the angular ranges
|
||||
pGlowball->nAngStart = nAngStart;
|
||||
pGlowball->nAngEnd = nAngEnd;
|
||||
|
||||
// Mark for redraw
|
||||
// - Force full redraw
|
||||
gslc_ElemSetRedraw(pGui,pElemRef,GSLC_REDRAW_FULL);
|
||||
}
|
||||
|
||||
void gslc_ElemXGlowballSetQuality(gslc_tsGui* pGui, gslc_tsElemRef* pElemRef, uint16_t nQuality)
|
||||
{
|
||||
if ((pGui == NULL) || (pElemRef == NULL)) {
|
||||
static const char GSLC_PMEM FUNCSTR[] = "ElemXGlowballSetQuality";
|
||||
GSLC_DEBUG2_PRINT_CONST(ERRSTR_NULL,FUNCSTR);
|
||||
return;
|
||||
}
|
||||
gslc_tsElem* pElem = gslc_GetElemFromRef(pGui,pElemRef);
|
||||
gslc_tsXGlowball* pGlowball = (gslc_tsXGlowball*)(pElem->pXData);
|
||||
|
||||
// Update the rendering quality setting
|
||||
pGlowball->nQuality = nQuality;
|
||||
|
||||
// Mark for redraw
|
||||
// - Force full redraw
|
||||
gslc_ElemSetRedraw(pGui,pElemRef,GSLC_REDRAW_FULL);
|
||||
}
|
||||
|
||||
void gslc_ElemXGlowballSetColorBack(gslc_tsGui* pGui, gslc_tsElemRef* pElemRef, gslc_tsColor colBg)
|
||||
{
|
||||
if ((pGui == NULL) || (pElemRef == NULL)) {
|
||||
static const char GSLC_PMEM FUNCSTR[] = "ElemXGlowballSetColorBack";
|
||||
GSLC_DEBUG2_PRINT_CONST(ERRSTR_NULL,FUNCSTR);
|
||||
return;
|
||||
}
|
||||
gslc_tsElem* pElem = gslc_GetElemFromRef(pGui,pElemRef);
|
||||
gslc_tsXGlowball* pGlowball = (gslc_tsXGlowball*)(pElem->pXData);
|
||||
|
||||
// Update the background color
|
||||
pGlowball->colBg = colBg;
|
||||
|
||||
// Mark for redraw
|
||||
// - Force full redraw
|
||||
gslc_ElemSetRedraw(pGui,pElemRef,GSLC_REDRAW_FULL);
|
||||
}
|
||||
|
||||
// Redraw the element
|
||||
// - Note that this redraw is for the entire element rect region
|
||||
// - The Draw function parameters use void pointers to allow for
|
||||
// simpler callback function definition & scalability.
|
||||
bool gslc_ElemXGlowballDraw(void* pvGui,void* pvElemRef,gslc_teRedrawType eRedraw)
|
||||
{
|
||||
if ((pvGui == NULL) || (pvElemRef == NULL)) {
|
||||
static const char GSLC_PMEM FUNCSTR[] = "ElemXGlowballDraw";
|
||||
GSLC_DEBUG2_PRINT_CONST(ERRSTR_NULL,FUNCSTR);
|
||||
return false;
|
||||
}
|
||||
// Typecast the parameters to match the GUI and element types
|
||||
gslc_tsGui* pGui = (gslc_tsGui*)(pvGui);
|
||||
gslc_tsElemRef* pElemRef = (gslc_tsElemRef*)(pvElemRef);
|
||||
gslc_tsElem* pElem = gslc_GetElemFromRef(pGui,pElemRef);
|
||||
|
||||
// Fetch the element's extended data structure
|
||||
gslc_tsXGlowball* pGlowball;
|
||||
pGlowball = (gslc_tsXGlowball*)(pElem->pXData);
|
||||
if (pGlowball == NULL) {
|
||||
GSLC_DEBUG2_PRINT("ERROR: ElemXGlowballDraw(%s) pXData is NULL\n","");
|
||||
return false;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// Init for default drawing
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
int16_t nElemX,nElemY;
|
||||
uint16_t nElemW,nElemH;
|
||||
|
||||
nElemX = pElem->rElem.x;
|
||||
nElemY = pElem->rElem.y;
|
||||
nElemW = pElem->rElem.w;
|
||||
nElemH = pElem->rElem.h;
|
||||
|
||||
// Calculate center of XGlowball
|
||||
int16_t nMidX, nMidY;
|
||||
nMidX = nElemX + (nElemW / 2);
|
||||
nMidY = nElemY + (nElemH / 2);
|
||||
|
||||
// Fetch the current value
|
||||
int16_t nVal = pGlowball->nVal;
|
||||
int16_t nAngStart = pGlowball->nAngStart;
|
||||
int16_t nAngEnd = pGlowball->nAngEnd;
|
||||
|
||||
// Check to see if we need full redraw
|
||||
if (eRedraw == GSLC_REDRAW_FULL) {
|
||||
// Erase the region
|
||||
gslc_DrawFillRect(pGui, pElem->rElem, pGlowball->colBg);
|
||||
// Now force redraw from zero level to current value
|
||||
pGlowball->nValLast = 0;
|
||||
}
|
||||
|
||||
// Draw the glowball
|
||||
drawXGlowball(pGui, pGlowball, nMidX, nMidY, nVal, nAngStart, nAngEnd);
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
// Mark the element as no longer requiring redraw
|
||||
gslc_ElemSetRedraw(pGui,pElemRef,GSLC_REDRAW_NONE);
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
// ============================================================================
|
136
src/guislice/XGlowball.h
Normal file
136
src/guislice/XGlowball.h
Normal file
|
@ -0,0 +1,136 @@
|
|||
#ifndef _GUISLICE_EX_XGLOWBALL_H_
|
||||
#define _GUISLICE_EX_XGLOWBALL_H_
|
||||
|
||||
#include "GUIslice.h"
|
||||
|
||||
|
||||
// =======================================================================
|
||||
// GUIslice library extension: XGlowball
|
||||
// - Calvin Hass
|
||||
// - https://www.impulseadventure.com/elec/guislice-gui.html
|
||||
// - https://github.com/ImpulseAdventure/GUIslice
|
||||
// =======================================================================
|
||||
//
|
||||
// The MIT License
|
||||
//
|
||||
// Copyright 2016-2020 Calvin Hass
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
//
|
||||
// =======================================================================
|
||||
/// \file XGlowball.h
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif // __cplusplus
|
||||
|
||||
|
||||
// ============================================================================
|
||||
// Extended Element: Example template
|
||||
// ============================================================================
|
||||
|
||||
// Define unique identifier for extended element type
|
||||
// - Select any number above GSLC_TYPE_BASE_EXTEND
|
||||
#define GSLC_TYPEX_GLOW GSLC_TYPE_BASE_EXTEND + 24
|
||||
|
||||
// Defines the attributes of each ring in the XGlowball gauge
|
||||
typedef struct {
|
||||
uint8_t nRad1; // Inner radius
|
||||
uint8_t nRad2; // Outer radius
|
||||
gslc_tsColor cCol; // Fill color
|
||||
} gslc_tsXGlowballRing;
|
||||
|
||||
// Extended element data structures
|
||||
// - These data structures are maintained in the gslc_tsElem
|
||||
// structure via the pXData pointer
|
||||
|
||||
/// Extended data for Slider element
|
||||
typedef struct {
|
||||
// Config
|
||||
int16_t nMidX; ///< Gauge midpoint X coord
|
||||
int16_t nMidY; ///< Gauge midpoint Y coord
|
||||
gslc_tsXGlowballRing* pRings; ///< Ring definition array
|
||||
uint8_t nNumRings; ///< Number of rings in definition
|
||||
// Style config
|
||||
uint16_t nQuality; ///< Rendering quality (number of segments / rotation)
|
||||
int16_t nAngStart; ///< Starting angle (0..510 degrees)
|
||||
int16_t nAngEnd; ///< Ending angle (0..510 degrees)
|
||||
gslc_tsColor colBg; ///< Background color (for redraw)
|
||||
// State
|
||||
int16_t nVal; ///< Current value
|
||||
int16_t nValLast; ///< Previous value
|
||||
// Callbacks
|
||||
} gslc_tsXGlowball;
|
||||
|
||||
|
||||
///
|
||||
/// Create a XGlowball element
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] nElemId: Element ID to assign (0..16383 or GSLC_ID_AUTO to autogen)
|
||||
/// \param[in] nPage: Page ID to attach element to
|
||||
/// \param[in] pXData: Ptr to extended element data structure
|
||||
/// \param[in] nMidX: Center X coordinate
|
||||
/// \param[in] nMidY: Center Y coordinate
|
||||
/// \param[in] pRings: Pointer to tsXGlowballRing structure array defining appearance
|
||||
/// \param[in] nNumRings: Number of rings in pRings array
|
||||
///
|
||||
/// \return Pointer to Element reference or NULL if failure
|
||||
///
|
||||
gslc_tsElemRef* gslc_ElemXGlowballCreate(gslc_tsGui* pGui, int16_t nElemId, int16_t nPage,
|
||||
gslc_tsXGlowball* pXData, int16_t nMidX, int16_t nMidY, gslc_tsXGlowballRing* pRings, uint8_t nNumRings);
|
||||
|
||||
|
||||
///
|
||||
/// Draw the XGlowball element on the screen
|
||||
/// - Called from gslc_ElemDraw()
|
||||
///
|
||||
/// \param[in] pvGui: Void ptr to GUI (typecast to gslc_tsGui*)
|
||||
/// \param[in] pvElemRef: Void ptr to Element (typecast to gslc_tsElemRef*)
|
||||
/// \param[in] eRedraw: Redraw mode
|
||||
///
|
||||
/// \return true if success, false otherwise
|
||||
///
|
||||
bool gslc_ElemXGlowballDraw(void* pvGui,void* pvElemRef,gslc_teRedrawType eRedraw);
|
||||
|
||||
// XGlowball draw helper routines
|
||||
void drawXGlowballArc(gslc_tsGui* pGui, gslc_tsXGlowball* pGlowball, int16_t nMidX, int16_t nMidY, int16_t nRad1, int16_t nRad2, gslc_tsColor cArc, uint16_t nAngStart, uint16_t nAngEnd);
|
||||
void drawXGlowballRing(gslc_tsGui* pGui, gslc_tsXGlowball* pGlowball, int16_t nMidX, int16_t nMidY, int16_t nVal, uint16_t nAngStart, uint16_t nAngEnd, bool bErase);
|
||||
void drawXGlowball(gslc_tsGui* pGui, gslc_tsXGlowball* pGlowball, int16_t nMidX, int16_t nMidY, int16_t nVal, uint16_t nAngStart, uint16_t nAngEnd);
|
||||
|
||||
void gslc_ElemXGlowballSetAngles(gslc_tsGui* pGui, gslc_tsElemRef* pElemRef, int16_t nAngStart, int16_t nAngEnd);
|
||||
void gslc_ElemXGlowballSetVal(gslc_tsGui* pGui, gslc_tsElemRef* pElemRef, int16_t nVal);
|
||||
void gslc_ElemXGlowballSetQuality(gslc_tsGui* pGui, gslc_tsElemRef* pElemRef, uint16_t nQuality);
|
||||
void gslc_ElemXGlowballSetColorBack(gslc_tsGui* pGui, gslc_tsElemRef* pElemRef, gslc_tsColor colBg);
|
||||
|
||||
// ============================================================================
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Read-only element macros
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
// Macro initializers for Read-Only Elements in Flash/PROGMEM
|
||||
//
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif // __cplusplus
|
||||
#endif // _GUISLICE_EX_XGLOWBALL_H_
|
||||
|
366
src/guislice/XGraph.c
Normal file
366
src/guislice/XGraph.c
Normal file
|
@ -0,0 +1,366 @@
|
|||
// =======================================================================
|
||||
// GUIslice library (extensions)
|
||||
// - Calvin Hass
|
||||
// - https://www.impulseadventure.com/elec/guislice-gui.html
|
||||
// - https://github.com/ImpulseAdventure/GUIslice
|
||||
// =======================================================================
|
||||
//
|
||||
// The MIT License
|
||||
//
|
||||
// Copyright 2016-2020 Calvin Hass
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
//
|
||||
// =======================================================================
|
||||
/// \file XGraph.c
|
||||
|
||||
|
||||
|
||||
// GUIslice library
|
||||
#include "GUIslice.h"
|
||||
#include "GUIslice_drv.h"
|
||||
|
||||
#include "XGraph.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#if (GSLC_USE_PROGMEM)
|
||||
#include <avr/pgmspace.h>
|
||||
#endif
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Error Messages
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
extern const char GSLC_PMEM ERRSTR_NULL[];
|
||||
extern const char GSLC_PMEM ERRSTR_PXD_NULL[];
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Extended element definitions
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// - This file extends the core GUIslice functionality with
|
||||
// additional widget types
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
// ============================================================================
|
||||
|
||||
gslc_tsElemRef* gslc_ElemXGraphCreate(gslc_tsGui* pGui,int16_t nElemId,int16_t nPage,
|
||||
gslc_tsXGraph* pXData,gslc_tsRect rElem,int16_t nFontId,int16_t* pBuf,
|
||||
uint16_t nBufMax,gslc_tsColor colGraph)
|
||||
{
|
||||
if ((pGui == NULL) || (pXData == NULL)) {
|
||||
static const char GSLC_PMEM FUNCSTR[] = "ElemXGraphCreate";
|
||||
GSLC_DEBUG2_PRINT_CONST(ERRSTR_NULL,FUNCSTR);
|
||||
return NULL;
|
||||
}
|
||||
gslc_tsElem sElem;
|
||||
gslc_tsElemRef* pElemRef = NULL;
|
||||
sElem = gslc_ElemCreate(pGui,nElemId,nPage,GSLC_TYPEX_GRAPH,rElem,NULL,0,nFontId);
|
||||
sElem.nFeatures |= GSLC_ELEM_FEA_FRAME_EN;
|
||||
sElem.nFeatures |= GSLC_ELEM_FEA_FILL_EN;
|
||||
sElem.nFeatures &= ~GSLC_ELEM_FEA_CLICK_EN;
|
||||
sElem.nFeatures &= ~GSLC_ELEM_FEA_GLOW_EN;
|
||||
|
||||
// Default group assignment. Can override later with ElemSetGroup()
|
||||
sElem.nGroup = GSLC_GROUP_ID_NONE;
|
||||
|
||||
// Define other extended data
|
||||
pXData->pBuf = pBuf;
|
||||
pXData->nMargin = 5;
|
||||
|
||||
pXData->nBufMax = nBufMax;
|
||||
pXData->nBufCnt = 0;
|
||||
pXData->nPlotIndStart = 0;
|
||||
|
||||
pXData->colGraph = colGraph;
|
||||
pXData->eStyle = GSLCX_GRAPH_STYLE_DOT;
|
||||
|
||||
// Define the visible region of the window
|
||||
// - The range in value can be overridden by the user
|
||||
pXData->nWndHeight = rElem.h - (2*pXData->nMargin);
|
||||
pXData->nWndWidth = rElem.w - (2*pXData->nMargin);
|
||||
|
||||
// Default scale is
|
||||
// - Each data point (buffer row) gets 1 pixel in X direction
|
||||
// - Data value is directly mapped to height in Y direction
|
||||
pXData->nPlotValMin = 0;
|
||||
pXData->nPlotValMax = pXData->nWndHeight;
|
||||
pXData->nPlotIndMax = pXData->nWndWidth;
|
||||
|
||||
|
||||
// Clear the buffer
|
||||
memset(pBuf,0,nBufMax*sizeof(int16_t));
|
||||
|
||||
|
||||
// Determine if scrollbar should be enabled
|
||||
if (pXData->nPlotIndMax >= pXData->nBufMax) {
|
||||
// Disable scrollbar as the window is larger
|
||||
// than the number of rows in the buffer
|
||||
pXData->bScrollEn = false;
|
||||
pXData->nScrollPos = 0;
|
||||
} else {
|
||||
// Scrollbar is enabled
|
||||
pXData->bScrollEn = true;
|
||||
pXData->nScrollPos = pXData->nBufMax - pXData->nPlotIndMax;
|
||||
}
|
||||
|
||||
sElem.pXData = (void*)(pXData);
|
||||
|
||||
// Specify the custom drawing callback
|
||||
sElem.pfuncXDraw = &gslc_ElemXGraphDraw;
|
||||
sElem.pfuncXTouch = NULL;
|
||||
sElem.colElemFill = GSLC_COL_BLACK;
|
||||
sElem.colElemFillGlow = GSLC_COL_BLACK;
|
||||
sElem.colElemFrame = GSLC_COL_GRAY;
|
||||
sElem.colElemFrameGlow = GSLC_COL_WHITE;
|
||||
if (nPage != GSLC_PAGE_NONE) {
|
||||
pElemRef = gslc_ElemAdd(pGui,nPage,&sElem,GSLC_ELEMREF_DEFAULT);
|
||||
return pElemRef;
|
||||
#if (GSLC_FEATURE_COMPOUND)
|
||||
} else {
|
||||
// Save as temporary element
|
||||
pGui->sElemTmp = sElem;
|
||||
pGui->sElemRefTmp.pElem = &(pGui->sElemTmp);
|
||||
pGui->sElemRefTmp.eElemFlags = GSLC_ELEMREF_DEFAULT | GSLC_ELEMREF_REDRAW_FULL;
|
||||
return &(pGui->sElemRefTmp);
|
||||
#endif
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
void gslc_ElemXGraphSetStyle(gslc_tsGui* pGui,gslc_tsElemRef* pElemRef,
|
||||
gslc_teXGraphStyle eStyle,uint8_t nMargin)
|
||||
{
|
||||
gslc_tsXGraph* pBox;
|
||||
gslc_tsElem* pElem = gslc_GetElemFromRef(pGui,pElemRef);
|
||||
pBox = (gslc_tsXGraph*)(pElem->pXData);
|
||||
|
||||
pBox->eStyle = eStyle;
|
||||
pBox->nMargin = nMargin;
|
||||
|
||||
// TODO: Recalculate the window extents and defaults
|
||||
// - Note that ElemXGraphSetStyle() was not intended to be
|
||||
// called after the control is already in use/displayed
|
||||
|
||||
// Set the redraw flag
|
||||
// - Force full redraw
|
||||
gslc_ElemSetRedraw(pGui,pElemRef,GSLC_REDRAW_FULL);
|
||||
|
||||
}
|
||||
|
||||
// TODO: Support scaling in X direction
|
||||
void gslc_ElemXGraphSetRange(gslc_tsGui* pGui,gslc_tsElemRef* pElemRef,
|
||||
int16_t nYMin,int16_t nYMax)
|
||||
{
|
||||
gslc_tsXGraph* pBox;
|
||||
gslc_tsElem* pElem = gslc_GetElemFromRef(pGui,pElemRef);
|
||||
pBox = (gslc_tsXGraph*)(pElem->pXData);
|
||||
|
||||
pBox->nPlotValMax = nYMax;
|
||||
pBox->nPlotValMin = nYMin;
|
||||
|
||||
// Set the redraw flag
|
||||
// - As we are changing the scale, force a full redraw
|
||||
// since incremental redraws may make assumption about
|
||||
// prior coordinate scaling
|
||||
gslc_ElemSetRedraw(pGui,pElemRef,GSLC_REDRAW_FULL);
|
||||
|
||||
}
|
||||
|
||||
|
||||
void gslc_ElemXGraphScrollSet(gslc_tsGui* pGui,gslc_tsElemRef* pElemRef,uint8_t nScrollPos,uint8_t nScrollMax)
|
||||
{
|
||||
|
||||
gslc_tsXGraph* pBox;
|
||||
gslc_tsElem* pElem = gslc_GetElemFromRef(pGui,pElemRef);
|
||||
pBox = (gslc_tsXGraph*)(pElem->pXData);
|
||||
|
||||
// Ensure scrollbar is enabled
|
||||
if (!pBox->bScrollEn) {
|
||||
// Scrollbar is disabled, so ignore
|
||||
return;
|
||||
}
|
||||
|
||||
// Assign proportional value based on visible window region
|
||||
uint16_t nScrollPosOld = pBox->nScrollPos;
|
||||
pBox->nScrollPos = nScrollPos * (pBox->nBufMax - pBox->nPlotIndMax) / nScrollMax;
|
||||
|
||||
// Set the redraw flag
|
||||
// - Only need incremental redraw
|
||||
// - Only redraw if changed actual scroll row
|
||||
if (pBox->nScrollPos != nScrollPosOld) {
|
||||
gslc_ElemSetRedraw(pGui,pElemRef,GSLC_REDRAW_INC);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Write a data value to the buffer
|
||||
// - Advance the write ptr, wrap if needed
|
||||
// - If encroach upon buffer read ptr, then drop the oldest line from the buffer
|
||||
void gslc_ElemXGraphAdd(gslc_tsGui* pGui,gslc_tsElemRef* pElemRef,int16_t nVal)
|
||||
{
|
||||
gslc_tsXGraph* pBox = NULL;
|
||||
gslc_tsElem* pElem = gslc_GetElemFromRef(pGui,pElemRef);
|
||||
pBox = (gslc_tsXGraph*)(pElem->pXData);
|
||||
|
||||
// Add the data value
|
||||
pBox->pBuf[pBox->nBufCnt] = nVal;
|
||||
|
||||
// Advance the pointer
|
||||
// - Wrap the pointers around end of buffer
|
||||
pBox->nBufCnt = (pBox->nBufCnt+1) % pBox->nBufMax;
|
||||
|
||||
// Set the redraw flag
|
||||
// - Only need incremental redraw
|
||||
gslc_ElemSetRedraw(pGui,pElemRef,GSLC_REDRAW_INC);
|
||||
}
|
||||
|
||||
|
||||
bool gslc_ElemXGraphDraw(void* pvGui,void* pvElemRef,gslc_teRedrawType eRedraw)
|
||||
{
|
||||
if ((pvGui == NULL) || (pvElemRef == NULL)) {
|
||||
static const char GSLC_PMEM FUNCSTR[] = "ElemXGraphDraw";
|
||||
GSLC_DEBUG2_PRINT_CONST(ERRSTR_NULL,FUNCSTR);
|
||||
return false;
|
||||
}
|
||||
// Typecast the parameters to match the GUI and element types
|
||||
gslc_tsGui* pGui = (gslc_tsGui*)(pvGui);
|
||||
gslc_tsElemRef* pElemRef = (gslc_tsElemRef*)(pvElemRef);
|
||||
gslc_tsElem* pElem = gslc_GetElemFromRef(pGui,pElemRef);
|
||||
|
||||
// Fetch the element's extended data structure
|
||||
gslc_tsXGraph* pBox;
|
||||
pBox = (gslc_tsXGraph*)(pElem->pXData);
|
||||
if (pBox == NULL) {
|
||||
GSLC_DEBUG2_PRINT("ERROR: ElemXGraphDraw(%s) pXData is NULL\n","");
|
||||
return false;
|
||||
}
|
||||
|
||||
bool bGlow = (pElem->nFeatures & GSLC_ELEM_FEA_GLOW_EN) && gslc_ElemGetGlow(pGui,pElemRef);
|
||||
bool bFrameEn = (pElem->nFeatures & GSLC_ELEM_FEA_FRAME_EN);
|
||||
|
||||
// Draw the frame
|
||||
if (eRedraw == GSLC_REDRAW_FULL) {
|
||||
if (bFrameEn) {
|
||||
gslc_DrawFrameRect(pGui,pElem->rElem,pElem->colElemFrame);
|
||||
}
|
||||
}
|
||||
|
||||
// Clear the background (inset from frame)
|
||||
// TODO: Support incremental redraw in which case we don't
|
||||
// erase the inner region. Instead we would just erase
|
||||
// old values and redraw new ones
|
||||
gslc_tsRect rInner = gslc_ExpandRect(pElem->rElem,-1,-1);
|
||||
gslc_DrawFillRect(pGui,rInner,(bGlow)?pElem->colElemFillGlow:pElem->colElemFill);
|
||||
|
||||
int16_t nDataVal;
|
||||
uint16_t nCurX = 0;
|
||||
int16_t nPixX,nPixY,nPixYBase,nPixYOffset;
|
||||
gslc_tsColor colGraph;
|
||||
|
||||
uint8_t nScrollMax;
|
||||
|
||||
// Initialize color state
|
||||
colGraph = pBox->colGraph;
|
||||
|
||||
// Calculate the current window position based on
|
||||
// the current buffer write pointer and scroll
|
||||
// position
|
||||
nScrollMax = pBox->nBufMax - pBox->nPlotIndMax;
|
||||
pBox->nPlotIndStart = pBox->nBufMax + pBox->nBufCnt;
|
||||
pBox->nPlotIndStart -= pBox->nPlotIndMax;
|
||||
// Only correct for scrollbar position if enabled
|
||||
if (pBox->bScrollEn) {
|
||||
pBox->nPlotIndStart -= (nScrollMax - pBox->nScrollPos);
|
||||
}
|
||||
pBox->nPlotIndStart = pBox->nPlotIndStart % pBox->nBufMax;
|
||||
|
||||
uint8_t nPlotInd = 0;
|
||||
uint8_t nIndMax = 0;
|
||||
nIndMax = (pBox->nBufMax < pBox->nPlotIndMax)? pBox->nBufMax : pBox->nPlotIndMax;
|
||||
for (nPlotInd=0;nPlotInd<nIndMax;nPlotInd++) {
|
||||
|
||||
// Calculate row offset after accounting for buffer wrap
|
||||
// and current window starting offset
|
||||
uint16_t nBufInd = pBox->nPlotIndStart + nPlotInd;
|
||||
nBufInd = nBufInd % pBox->nBufMax;
|
||||
|
||||
// NOTE: At the start of buffer fill when we have
|
||||
// only written a few values, we will continue to read
|
||||
// values out of the buffer so we are dependent upon
|
||||
// the reset to initialize the buffer to zero.
|
||||
|
||||
nDataVal = pBox->pBuf[nBufInd];
|
||||
|
||||
// Clip the value to the plot range
|
||||
if (nDataVal > pBox->nPlotValMax) { nDataVal = pBox->nPlotValMax; }
|
||||
else if (nDataVal < pBox->nPlotValMin) { nDataVal = pBox->nPlotValMin; }
|
||||
|
||||
// TODO: Make nCurX a scaled version of nPlotInd
|
||||
// - Support different modes for mapping multiple data points
|
||||
// a single X coordinate and mapping a single data point
|
||||
// to multiple X coordinates
|
||||
// - For now, just have a 1:1 correspondence between data
|
||||
// points and the X coordinate
|
||||
nCurX = nPlotInd;
|
||||
|
||||
// TODO: Scale data value
|
||||
|
||||
// TODO: Consider supporting various color mapping modes
|
||||
//colGraph = gslc_ColorBlend2(GSLC_COL_BLACK,GSLC_COL_WHITE,500,nDataVal*500/200);
|
||||
|
||||
// Determine the drawing coordinates
|
||||
nPixX = pElem->rElem.x + pBox->nMargin + nCurX;
|
||||
nPixYBase = pElem->rElem.y - pBox->nMargin + pElem->rElem.h-1;
|
||||
|
||||
// Calculate Y coordinate
|
||||
nPixYOffset = nDataVal;
|
||||
|
||||
// Clip plot Y coordinate
|
||||
if (nPixY > pBox->nWndHeight) { nPixY = pBox->nWndHeight; }
|
||||
if (nPixY < 0) { nPixY = 0; }
|
||||
|
||||
// Calculate final Y coordinate
|
||||
nPixY = pElem->rElem.y - pBox->nMargin + pElem->rElem.h-1 - nPixYOffset;
|
||||
|
||||
|
||||
// Render the datapoints
|
||||
if (pBox->eStyle == GSLCX_GRAPH_STYLE_DOT) {
|
||||
gslc_DrawSetPixel(pGui,nPixX,nPixY,colGraph);
|
||||
} else if (pBox->eStyle == GSLCX_GRAPH_STYLE_LINE) {
|
||||
} else if (pBox->eStyle == GSLCX_GRAPH_STYLE_FILL) {
|
||||
gslc_DrawLine(pGui,nPixX,nPixYBase,nPixX,nPixY,colGraph);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Clear the redraw flag
|
||||
gslc_ElemSetRedraw(pGui,pElemRef,GSLC_REDRAW_NONE);
|
||||
|
||||
// Mark page as needing flip
|
||||
gslc_PageFlipSet(pGui,true);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// ============================================================================
|
186
src/guislice/XGraph.h
Normal file
186
src/guislice/XGraph.h
Normal file
|
@ -0,0 +1,186 @@
|
|||
#ifndef _GUISLICE_EX_XGRAPH_H_
|
||||
#define _GUISLICE_EX_XGRAPH_H_
|
||||
|
||||
#include "GUIslice.h"
|
||||
|
||||
|
||||
// =======================================================================
|
||||
// GUIslice library extension: Graph control
|
||||
// - Calvin Hass
|
||||
// - https://www.impulseadventure.com/elec/guislice-gui.html
|
||||
// - https://github.com/ImpulseAdventure/GUIslice
|
||||
// =======================================================================
|
||||
//
|
||||
// The MIT License
|
||||
//
|
||||
// Copyright 2016-2020 Calvin Hass
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
//
|
||||
// =======================================================================
|
||||
/// \file XGraph.h
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif // __cplusplus
|
||||
|
||||
|
||||
// ============================================================================
|
||||
// Extended Element: Graph
|
||||
// ============================================================================
|
||||
|
||||
// Define unique identifier for extended element type
|
||||
// - Select any number above GSLC_TYPE_BASE_EXTEND
|
||||
#define GSLC_TYPEX_GRAPH GSLC_TYPE_BASE_EXTEND + 5
|
||||
|
||||
|
||||
/// Gauge drawing style
|
||||
typedef enum {
|
||||
GSLCX_GRAPH_STYLE_DOT, ///< Dot
|
||||
GSLCX_GRAPH_STYLE_LINE, ///< Line
|
||||
GSLCX_GRAPH_STYLE_FILL, ///< Filled
|
||||
} gslc_teXGraphStyle;
|
||||
|
||||
// Extended element data structures
|
||||
// - These data structures are maintained in the gslc_tsElem
|
||||
// structure via the pXData pointer
|
||||
|
||||
/// Extended data for Graph element
|
||||
typedef struct {
|
||||
// Config
|
||||
int16_t* pBuf; ///< Ptr to the data buffer (circular buffer))
|
||||
uint8_t nMargin; ///< Margin for graph area within element rect
|
||||
gslc_tsColor colGraph; ///< Color of the graph
|
||||
gslc_teXGraphStyle eStyle; ///< Style of the graph
|
||||
|
||||
uint16_t nBufMax; ///< Maximum number of points in buffer
|
||||
bool bScrollEn; ///< Enable for scrollbar
|
||||
uint16_t nScrollPos; ///< Current scrollbar position
|
||||
|
||||
uint16_t nWndHeight; ///< Visible window height
|
||||
uint16_t nWndWidth; ///< Visible window width
|
||||
int16_t nPlotValMax; ///< Visible window maximum value
|
||||
int16_t nPlotValMin; ///< Visible window minimum value
|
||||
uint16_t nPlotIndMax; ///< Number of data points to show in window
|
||||
|
||||
// Current status
|
||||
uint16_t nBufCnt; ///< Number of points in buffer
|
||||
uint16_t nPlotIndStart; ///< First row of current window
|
||||
|
||||
} gslc_tsXGraph;
|
||||
|
||||
|
||||
|
||||
///
|
||||
/// Create a Graph Element
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] nElemId: Element ID to assign (0..16383 or GSLC_ID_AUTO to autogen)
|
||||
/// \param[in] nPage: Page ID to attach element to
|
||||
/// \param[in] pXData: Ptr to extended element data structure
|
||||
/// \param[in] rElem: Rectangle coordinates defining checkbox size
|
||||
/// \param[in] nFontId: Font ID to use for graph area
|
||||
/// \param[in] pBuf: Ptr to data buffer (already allocated)
|
||||
/// with size (nBufMax) int16_t
|
||||
/// \param[in] nBufRows: Maximum number of points in buffer
|
||||
/// \param[in] colGraph: Color of the graph
|
||||
///
|
||||
/// \return Pointer to Element reference or NULL if failure
|
||||
///
|
||||
gslc_tsElemRef* gslc_ElemXGraphCreate(gslc_tsGui* pGui,int16_t nElemId,int16_t nPage,
|
||||
gslc_tsXGraph* pXData,gslc_tsRect rElem,int16_t nFontId,int16_t* pBuf,
|
||||
uint16_t nBufRows,gslc_tsColor colGraph);
|
||||
|
||||
///
|
||||
/// Set the graph's additional drawing characteristics
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] pElemRef: Pointer to Element reference
|
||||
/// \param[in] eStyle: Drawing style for the graph
|
||||
/// \param[in] nMargin: Margin to provide around graph area inside frame
|
||||
///
|
||||
/// \return none
|
||||
///
|
||||
void gslc_ElemXGraphSetStyle(gslc_tsGui* pGui,gslc_tsElemRef* pElemRef,
|
||||
gslc_teXGraphStyle eStyle,uint8_t nMargin);
|
||||
|
||||
///
|
||||
/// Set the graph's drawing range
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] pElemRef: Pointer to Element reference
|
||||
/// \param[in] nYMin: Minimum Y value to draw
|
||||
/// \param[in] nYMax: Maximum Y value to draw
|
||||
///
|
||||
/// \return none
|
||||
///
|
||||
void gslc_ElemXGraphSetRange(gslc_tsGui* pGui,gslc_tsElemRef* pElemRef,
|
||||
int16_t nYMin,int16_t nYMax);
|
||||
|
||||
///
|
||||
/// Draw a Graph element on the screen
|
||||
/// - Called from gslc_ElemDraw()
|
||||
///
|
||||
/// \param[in] pvGui: Void ptr to GUI (typecast to gslc_tsGui*)
|
||||
/// \param[in] pvElemRef: Void ptr to Element reference (typecast to gslc_tsElemRef*)
|
||||
/// \param[in] eRedraw: Redraw mode
|
||||
///
|
||||
/// \return true if success, false otherwise
|
||||
///
|
||||
bool gslc_ElemXGraphDraw(void* pvGui,void* pvElemRef,gslc_teRedrawType eRedraw);
|
||||
|
||||
/// Add a value to the graph at the latest position
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] pElemRef: Pointer to Element reference
|
||||
/// \param[in] nVal: Data value to add
|
||||
///
|
||||
/// \return none
|
||||
///
|
||||
void gslc_ElemXGraphAdd(gslc_tsGui* pGui,gslc_tsElemRef* pElemRef,int16_t nVal);
|
||||
|
||||
|
||||
///
|
||||
/// Set the graph scroll position (nScrollPos) as a fraction of
|
||||
/// nScrollMax
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] pElemRef: Pointer to Element reference
|
||||
/// \param[in] nScrollPos: New scroll position
|
||||
/// \param[in] nScrollMax: Maximum scroll position
|
||||
///
|
||||
/// \return none
|
||||
///
|
||||
void gslc_ElemXGraphScrollSet(gslc_tsGui* pGui,gslc_tsElemRef* pElemRef,uint8_t nScrollPos,uint8_t nScrollMax);
|
||||
|
||||
|
||||
// ============================================================================
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Read-only element macros
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
// Macro initializers for Read-Only Elements in Flash/PROGMEM
|
||||
//
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif // __cplusplus
|
||||
#endif // _GUISLICE_EX_XGRAPH_H_
|
||||
|
714
src/guislice/XKeyPad.c
Normal file
714
src/guislice/XKeyPad.c
Normal file
|
@ -0,0 +1,714 @@
|
|||
// =======================================================================
|
||||
// GUIslice library extension: XKeyPad control
|
||||
// - Paul Conti, Calvin Hass
|
||||
// - https://www.impulseadventure.com/elec/guislice-gui.html
|
||||
// - https://github.com/ImpulseAdventure/GUIslice
|
||||
// =======================================================================
|
||||
//
|
||||
// The MIT License
|
||||
//
|
||||
// Copyright 2016-2020 Calvin Hass
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
//
|
||||
// =======================================================================
|
||||
/// \file XKeyPad.c
|
||||
|
||||
|
||||
|
||||
// GUIslice library
|
||||
#include "GUIslice.h"
|
||||
#include "GUIslice_drv.h"
|
||||
|
||||
#include "XKeyPad.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#if (GSLC_USE_PROGMEM)
|
||||
#include <avr/pgmspace.h>
|
||||
#endif
|
||||
|
||||
#if (GSLC_FEATURE_COMPOUND)
|
||||
// ----------------------------------------------------------------------------
|
||||
// Error Messages
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
extern const char GSLC_PMEM ERRSTR_NULL[];
|
||||
extern const char GSLC_PMEM ERRSTR_PXD_NULL[];
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Extended element definitions
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// - This file extends the core GUIslice functionality with
|
||||
// additional widget types
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
|
||||
// ============================================================================
|
||||
// Extended Element: KeyPad
|
||||
// - Keypad element with numeric input
|
||||
// - Optionally supports floating point values
|
||||
// - Optionally supports negative values
|
||||
// ============================================================================
|
||||
|
||||
// Define the button labels
|
||||
// - TODO: Create more efficient storage for the labels
|
||||
// so that it doesn't consume 4 bytes even for labels
|
||||
// that can be generated (eg. 0..9, a--z, etc.)
|
||||
// - NOTE: Not using "const char" in order to support
|
||||
// modification of labels by user.
|
||||
|
||||
|
||||
const char KEYPAD_DISP_NEGATIVE = '-';
|
||||
const char KEYPAD_DISP_DECIMAL_PT = '.';
|
||||
|
||||
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// Create the keypad definition
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
|
||||
void XKeyPadAddKeyElem(gslc_tsGui* pGui, gslc_tsXKeyPad* pXData, int16_t nKeyId, bool bTxtField, int16_t nRow, int16_t nCol, int8_t nRowSpan, int8_t nColSpan,
|
||||
gslc_tsColor cColFill, gslc_tsColor cColGlow, bool bVisible)
|
||||
{
|
||||
gslc_tsXKeyPadCfg* pConfig;
|
||||
char* pKeyStr = NULL;
|
||||
|
||||
pConfig = &(pXData->sConfig);
|
||||
|
||||
gslc_tsElemRef* pElemRefTmp = NULL;
|
||||
gslc_tsElem* pElemTmp = NULL;
|
||||
|
||||
int16_t nButtonSzW = pConfig->nButtonSzW;
|
||||
int16_t nButtonSzH = pConfig->nButtonSzH;
|
||||
int16_t nOffsetX = pConfig->nOffsetX;
|
||||
int16_t nOffsetY = pConfig->nOffsetY;
|
||||
int8_t nFontId = pConfig->nFontId;
|
||||
|
||||
int16_t nButtonW = (nColSpan * nButtonSzW);
|
||||
int16_t nButtonH = (nRowSpan * nButtonSzH);
|
||||
|
||||
// Fetch the keypad key string
|
||||
if (bTxtField) {
|
||||
pKeyStr = (char*)pXData->acValStr;
|
||||
} else {
|
||||
XKEYPAD_LOOKUP pfuncLookup = pXData->pfuncLookup;
|
||||
int16_t nKeyInd = (*pfuncLookup)(pGui, nKeyId);
|
||||
pKeyStr = pXData->pacKeys[nKeyInd];
|
||||
}
|
||||
|
||||
//GSLC_DEBUG2_PRINT("DBG: KeyId=%d R=%d C=%d str=[%s] SubElemMax=%d\n", nKeyId, nRow,nCol,pKeyStr,pXData->nSubElemMax);
|
||||
|
||||
if (bTxtField) {
|
||||
// Text field
|
||||
pElemRefTmp = gslc_ElemCreateTxt(pGui, nKeyId, GSLC_PAGE_NONE,
|
||||
(gslc_tsRect) { nOffsetX + (nCol*nButtonSzW), nOffsetY + (nRow*nButtonSzH), nButtonW-1, nButtonH - 1 },
|
||||
pKeyStr, XKEYPAD_VAL_LEN, nFontId);
|
||||
gslc_ElemSetFrameEn(pGui, pElemRefTmp, true);
|
||||
gslc_ElemSetTxtMargin(pGui, pElemRefTmp, 5); // Apply default margin
|
||||
} else {
|
||||
// Text button
|
||||
//GSLC_DEBUG2_PRINT("DrawBtn: %d [%s] @ r=%d,c=%d,width=%d\n", nKeyId, pXData->pacKeys[nKeyId], nRow, nCol, nButtonW);
|
||||
pElemRefTmp = gslc_ElemCreateBtnTxt(pGui, nKeyId, GSLC_PAGE_NONE,
|
||||
(gslc_tsRect) { nOffsetX + (nCol*nButtonSzW), nOffsetY + (nRow*nButtonSzH), nButtonW - 1, nButtonH - 1 },
|
||||
pKeyStr, sizeof(pKeyStr), nFontId, &gslc_ElemXKeyPadClick);
|
||||
// For the text buttons, optionally use rounded profile if enabled
|
||||
gslc_ElemSetRoundEn(pGui, pElemRefTmp, pConfig->bRoundEn);
|
||||
}
|
||||
|
||||
// Set color
|
||||
gslc_ElemSetTxtCol(pGui, pElemRefTmp, GSLC_COL_WHITE);
|
||||
gslc_ElemSetCol(pGui, pElemRefTmp, GSLC_COL_WHITE, cColFill, cColGlow);
|
||||
|
||||
// Set the visibility status
|
||||
// FIXME: Need to fix dynamic visibility change
|
||||
// gslc_ElemSetVisible(pGui, pElemRefTmp, bVisible);
|
||||
if (!bVisible) {
|
||||
// For now, skip addition of invisible buttons
|
||||
return;
|
||||
}
|
||||
|
||||
// Add element to compound element collection
|
||||
pElemTmp = gslc_GetElemFromRef(pGui, pElemRefTmp);
|
||||
pElemRefTmp = gslc_CollectElemAdd(pGui, &pXData->sCollect, pElemTmp, GSLC_ELEMREF_DEFAULT);
|
||||
}
|
||||
|
||||
gslc_tsElemRef* gslc_ElemXKeyPadCreateBase(gslc_tsGui* pGui, int16_t nElemId, int16_t nPage,
|
||||
gslc_tsXKeyPad* pXData, int16_t nX0, int16_t nY0, int8_t nFontId, gslc_tsXKeyPadCfg* pConfig,
|
||||
XKEYPAD_CREATE pfuncCreate, XKEYPAD_LOOKUP pfuncLookup)
|
||||
{
|
||||
if ((pGui == NULL) || (pXData == NULL)) {
|
||||
static const char GSLC_PMEM FUNCSTR[] = "ElemXKeyPadCreate";
|
||||
GSLC_DEBUG2_PRINT_CONST(ERRSTR_NULL, FUNCSTR);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Fetch config options
|
||||
int8_t nButtonSzW = pConfig->nButtonSzW;
|
||||
int8_t nButtonSzH = pConfig->nButtonSzH;
|
||||
|
||||
gslc_tsRect rElem;
|
||||
rElem.x = nX0;
|
||||
rElem.y = nY0;
|
||||
rElem.w = (nButtonSzW * pConfig->nMaxCols) + (2 * pConfig->nFrameMargin);
|
||||
rElem.h = (nButtonSzH * pConfig->nMaxRows) + (2 * pConfig->nFrameMargin);
|
||||
|
||||
gslc_tsElem sElem;
|
||||
|
||||
// Initialize composite element
|
||||
sElem = gslc_ElemCreate(pGui, nElemId, nPage, GSLC_TYPEX_KEYPAD, rElem, NULL, 0, GSLC_FONT_NONE);
|
||||
sElem.nFeatures |= GSLC_ELEM_FEA_FRAME_EN;
|
||||
sElem.nFeatures |= GSLC_ELEM_FEA_FILL_EN;
|
||||
sElem.nFeatures |= GSLC_ELEM_FEA_CLICK_EN;
|
||||
sElem.nFeatures &= ~GSLC_ELEM_FEA_GLOW_EN; // Don't need to glow outer element
|
||||
sElem.nGroup = GSLC_GROUP_ID_NONE;
|
||||
|
||||
gslc_CollectReset(&pXData->sCollect, pXData->psElem, pXData->nSubElemMax, pXData->psElemRef, pXData->nSubElemMax);
|
||||
|
||||
sElem.pXData = (void*)(pXData);
|
||||
// Specify the custom drawing callback
|
||||
sElem.pfuncXDraw = &gslc_ElemXKeyPadDraw;
|
||||
// Specify the custom touch tracking callback
|
||||
sElem.pfuncXTouch = &gslc_ElemXKeyPadTouch;
|
||||
|
||||
// shouldn't be used
|
||||
sElem.colElemFill = GSLC_COL_BLACK;
|
||||
sElem.colElemFillGlow = GSLC_COL_BLACK;
|
||||
sElem.colElemFrame = GSLC_COL_BLUE;
|
||||
sElem.colElemFrameGlow = GSLC_COL_BLUE_LT4;
|
||||
|
||||
// Now create the sub elements
|
||||
gslc_tsElemRef* pElemRef = NULL;
|
||||
|
||||
// Determine offset coordinate of compound element so that we can
|
||||
// specify relative positioning during the sub-element Create() operations.
|
||||
int16_t nOffsetX = nX0 + pConfig->nFrameMargin;
|
||||
int16_t nOffsetY = nY0 + pConfig->nFrameMargin;
|
||||
|
||||
// Reset value string
|
||||
memset(pXData->acValStr, 0, XKEYPAD_VAL_LEN);
|
||||
pXData->nValStrPos = 0;
|
||||
|
||||
pXData->pacKeys = pConfig->pacKeys;
|
||||
pXData->pfuncCb = NULL;
|
||||
pXData->pfuncLookup = pfuncLookup;
|
||||
pXData->nTargetId = GSLC_ID_NONE; // Default to no target defined
|
||||
pXData->bValPositive = true;
|
||||
pXData->bValDecimalPt = false;
|
||||
|
||||
// Update config with constructor settings
|
||||
pConfig->nFontId = nFontId;
|
||||
pConfig->nOffsetX = nOffsetX;
|
||||
pConfig->nOffsetY = nOffsetY;
|
||||
|
||||
|
||||
// Copy content into local structure
|
||||
pXData->sConfig = *pConfig;
|
||||
|
||||
// Create the keypad definition
|
||||
// -- Call XKeyPadCreateKeys()
|
||||
if (pfuncCreate != NULL) {
|
||||
(*pfuncCreate)(pGui, pXData);
|
||||
}
|
||||
|
||||
// Now proceed to add the compound element to the page
|
||||
if (nPage != GSLC_PAGE_NONE) {
|
||||
pElemRef = gslc_ElemAdd(pGui, nPage, &sElem, GSLC_ELEMREF_DEFAULT);
|
||||
|
||||
// Now propagate the parent relationship to enable a cascade
|
||||
// of redrawing from low-level elements to the top
|
||||
gslc_CollectSetParent(pGui, &pXData->sCollect, pElemRef);
|
||||
return pElemRef;
|
||||
}
|
||||
else {
|
||||
#if defined(DEBUG_LOG)
|
||||
GSLC_DEBUG2_PRINT("ERROR: gslc_ElemXKeyPadCreate(%s) Compound elements inside compound elements not supported\n", "");
|
||||
#endif
|
||||
return NULL;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void gslc_ElemXKeyPadValSet(gslc_tsGui* pGui, gslc_tsElemRef* pElemRef, const char* pStrBuf)
|
||||
{
|
||||
gslc_tsXKeyPad* pKeyPad = (gslc_tsXKeyPad*)gslc_GetXDataFromRef(pGui, pElemRef, GSLC_TYPEX_KEYPAD, __LINE__);
|
||||
if (!pKeyPad) return;
|
||||
|
||||
// Copy over the new value string
|
||||
strncpy(pKeyPad->acValStr, pStrBuf, XKEYPAD_VAL_LEN);
|
||||
pKeyPad->acValStr[XKEYPAD_VAL_LEN - 1] = 0; // Force null terminate
|
||||
|
||||
// Handle negation and floating point detection
|
||||
pKeyPad->bValPositive = true;
|
||||
if (pKeyPad->acValStr[0] == KEYPAD_DISP_NEGATIVE) {
|
||||
pKeyPad->bValPositive = false;
|
||||
}
|
||||
pKeyPad->bValDecimalPt = false;
|
||||
if (strchr(pKeyPad->acValStr, KEYPAD_DISP_DECIMAL_PT)) {
|
||||
pKeyPad->bValDecimalPt = true;
|
||||
}
|
||||
|
||||
// Update the current buffer position
|
||||
pKeyPad->nValStrPos = strlen(pKeyPad->acValStr);
|
||||
|
||||
// Find element associated with text field
|
||||
gslc_tsElemRef* pTxtElemRef = gslc_CollectFindElemById(pGui, &pKeyPad->sCollect, KEYPAD_ID_TXT);
|
||||
|
||||
// Mark as needing redraw
|
||||
gslc_ElemSetRedraw(pGui,pTxtElemRef,GSLC_REDRAW_INC);
|
||||
}
|
||||
|
||||
void gslc_ElemXKeyPadTargetIdSet(gslc_tsGui* pGui, gslc_tsElemRef* pElemRef, int16_t nTargetId)
|
||||
{
|
||||
gslc_tsXKeyPad* pKeyPad = (gslc_tsXKeyPad*)gslc_GetXDataFromRef(pGui, pElemRef, GSLC_TYPEX_KEYPAD, __LINE__);
|
||||
if (!pKeyPad) return;
|
||||
pKeyPad->nTargetId = nTargetId;
|
||||
}
|
||||
|
||||
int16_t gslc_ElemXKeyPadDataTargetIdGet(gslc_tsGui* pGui, void* pvData)
|
||||
{
|
||||
if (pvData == NULL) {
|
||||
#if defined(DEBUG_LOG)
|
||||
GSLC_DEBUG2_PRINT("ERROR: gslc_ElemXKeyPadDataTargetIdGet() NULL data\n", "");
|
||||
#endif
|
||||
return GSLC_ID_NONE;
|
||||
}
|
||||
gslc_tsXKeyPadData* pData = (gslc_tsXKeyPadData*)pvData;
|
||||
return pData->nTargetId;
|
||||
}
|
||||
|
||||
char* gslc_ElemXKeyPadDataValGet(gslc_tsGui* pGui, void* pvData)
|
||||
{
|
||||
if (pvData == NULL) {
|
||||
#if defined(DEBUG_LOG)
|
||||
GSLC_DEBUG2_PRINT("ERROR: gslc_ElemXKeyPadDataValGet() NULL data\n", "");
|
||||
#endif
|
||||
return NULL;
|
||||
}
|
||||
gslc_tsXKeyPadData* pData = (gslc_tsXKeyPadData*)pvData;
|
||||
return pData->pStr;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// NOTE: API changed to pass nStrBufLen (total buffer size including terminator)
|
||||
// instead of nStrBufMax (max index value)
|
||||
bool gslc_ElemXKeyPadValGet(gslc_tsGui* pGui, gslc_tsElemRef* pElemRef, char* pStrBuf, uint8_t nStrBufLen)
|
||||
{
|
||||
gslc_tsXKeyPad* pKeyPad = (gslc_tsXKeyPad*)gslc_GetXDataFromRef(pGui, pElemRef, GSLC_TYPEX_KEYPAD, __LINE__);
|
||||
if (!pKeyPad) return false;
|
||||
|
||||
// - Check for negation flag
|
||||
// - If negative, copy minus sign
|
||||
// - Copy the remainder of the string
|
||||
// FIXME: check for shortest of XKEYPAD_VAL_LEN & nStrBufLen
|
||||
char* pBufPtr = pStrBuf;
|
||||
uint8_t nMaxCopyLen = nStrBufLen - 1;
|
||||
// FIXME: Do we still need to do this step?
|
||||
if (!pKeyPad->bValPositive) {
|
||||
*pBufPtr = KEYPAD_DISP_NEGATIVE;
|
||||
pBufPtr++;
|
||||
nMaxCopyLen--;
|
||||
}
|
||||
strncpy(pBufPtr, pKeyPad->acValStr, nMaxCopyLen);
|
||||
pStrBuf[nStrBufLen-1] = '\0'; // Force termination
|
||||
|
||||
// TODO: Do we need to reset the contents?
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// Redraw the KeyPad element
|
||||
// - When drawing a KeyPad we do not clear the background.
|
||||
// We do redraw the sub-element collection.
|
||||
bool gslc_ElemXKeyPadDraw(void* pvGui, void* pvElemRef, gslc_teRedrawType eRedraw)
|
||||
{
|
||||
gslc_tsGui* pGui = (gslc_tsGui*)(pvGui);
|
||||
gslc_tsElemRef* pElemRef = (gslc_tsElemRef*)(pvElemRef);
|
||||
|
||||
gslc_tsXKeyPad* pKeyPad = (gslc_tsXKeyPad*)gslc_GetXDataFromRef(pGui, pElemRef, GSLC_TYPEX_KEYPAD, __LINE__);
|
||||
if (!pKeyPad) return false;
|
||||
|
||||
gslc_tsElem* pElem = gslc_GetElemFromRef(pGui, pElemRef);
|
||||
|
||||
// Draw any parts of the compound element itself
|
||||
if (eRedraw == GSLC_REDRAW_FULL) {
|
||||
// Force the fill to ensure the background doesn't bleed thorugh gaps
|
||||
// between the sub-elements
|
||||
gslc_DrawFillRect(pGui, pElem->rElem, pElem->colElemFill);
|
||||
if (pElem->nFeatures & GSLC_ELEM_FEA_FRAME_EN) {
|
||||
gslc_DrawFrameRect(pGui, pElem->rElem, pElem->colElemFrame);
|
||||
}
|
||||
}
|
||||
|
||||
// Draw the sub-elements
|
||||
gslc_tsCollect* pCollect = &pKeyPad->sCollect;
|
||||
|
||||
if (eRedraw != GSLC_REDRAW_NONE) {
|
||||
uint8_t sEventSubType = GSLC_EVTSUB_DRAW_NEEDED;
|
||||
if (eRedraw == GSLC_REDRAW_FULL) {
|
||||
sEventSubType = GSLC_EVTSUB_DRAW_FORCE;
|
||||
}
|
||||
gslc_tsEvent sEvent = gslc_EventCreate(pGui, GSLC_EVT_DRAW, sEventSubType, (void*)(pCollect), NULL);
|
||||
gslc_CollectEvent(pGui, sEvent);
|
||||
}
|
||||
|
||||
// Clear the redraw flag
|
||||
gslc_ElemSetRedraw(pGui, pElemRef, GSLC_REDRAW_NONE);
|
||||
|
||||
// Mark page as needing flip
|
||||
gslc_PageFlipSet(pGui, true);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void gslc_ElemXKeyPadValSetCb(gslc_tsGui* pGui, gslc_tsElemRef* pElemRef, GSLC_CB_INPUT pfuncCb)
|
||||
{
|
||||
gslc_tsXKeyPad* pKeyPad = (gslc_tsXKeyPad*)gslc_GetXDataFromRef(pGui, pElemRef, GSLC_TYPEX_KEYPAD, __LINE__);
|
||||
if (!pKeyPad) return;
|
||||
|
||||
pKeyPad->pfuncCb = pfuncCb;
|
||||
}
|
||||
|
||||
// Change the sign of the number string
|
||||
// - This function also performs in-place shifting of the content
|
||||
void gslc_ElemXKeyPadValSetSign(gslc_tsGui* pGui, gslc_tsElemRef *pElemRef, bool bPositive)
|
||||
{
|
||||
gslc_tsXKeyPad* pKeyPad = (gslc_tsXKeyPad*)gslc_GetXDataFromRef(pGui, pElemRef, GSLC_TYPEX_KEYPAD, __LINE__);
|
||||
if (!pKeyPad) return;
|
||||
|
||||
char* pStrBuf = pKeyPad->acValStr;
|
||||
|
||||
//GSLC_DEBUG2_PRINT("SetSign: old=%d new=%d\n", pKeyPad->bValPositive, bPositive);
|
||||
if (pKeyPad->bValPositive == bPositive) {
|
||||
// No change to sign
|
||||
return;
|
||||
}
|
||||
|
||||
//GSLC_DEBUG2_PRINT("SetSign: str_old=[%s] idx=%d\n", pStrBuf,pKeyPad->nValStrPos);
|
||||
|
||||
if ((pKeyPad->bValPositive) && (!bPositive)) {
|
||||
// Change from positive to negative
|
||||
// - Shift string right one position, and replace first position with minus sign
|
||||
// - Increase current buffer position
|
||||
memmove(pStrBuf+1, pStrBuf, XKEYPAD_VAL_LEN-1);
|
||||
pStrBuf[0] = KEYPAD_DISP_NEGATIVE; // Overwrite with minus sign
|
||||
pStrBuf[XKEYPAD_VAL_LEN-1] = 0; // Force terminate
|
||||
pKeyPad->nValStrPos++; // Advance buffer position
|
||||
} else if ((!pKeyPad->bValPositive) && (bPositive)) {
|
||||
// Change from negative to positive
|
||||
// - Shift string left one position, overwriting the minus sign
|
||||
memmove(pStrBuf, pStrBuf+1, XKEYPAD_VAL_LEN-1);
|
||||
pStrBuf[XKEYPAD_VAL_LEN-1] = 0; // Force terminate
|
||||
if (pKeyPad->nValStrPos > 0) {
|
||||
// Expect that original position should be non-zero if previously minux
|
||||
pKeyPad->nValStrPos--; // Reduce buffer position
|
||||
}
|
||||
}
|
||||
|
||||
//GSLC_DEBUG2_PRINT("SetSign: str_new=[%s] idx=%d\n", pStrBuf,pKeyPad->nValStrPos);
|
||||
|
||||
// Update sign state
|
||||
pKeyPad->bValPositive = bPositive;
|
||||
|
||||
// The text string sub-element content has already been updated,
|
||||
// so now we can simply mark it for redraw
|
||||
gslc_tsElemRef* pTxtElemRef = gslc_CollectFindElemById(pGui, &pKeyPad->sCollect, KEYPAD_ID_TXT);
|
||||
gslc_ElemSetRedraw(pGui,pTxtElemRef,GSLC_REDRAW_INC);
|
||||
|
||||
}
|
||||
|
||||
bool ElemXKeyPadAddChar(gslc_tsGui* pGui, gslc_tsXKeyPad* pKeyPad, char ch)
|
||||
{
|
||||
bool bRedraw = false;
|
||||
// Do we have space for this character?
|
||||
if (pKeyPad->nValStrPos < XKEYPAD_VAL_LEN - 1) {
|
||||
pKeyPad->acValStr[pKeyPad->nValStrPos] = ch;
|
||||
pKeyPad->nValStrPos++;
|
||||
pKeyPad->acValStr[pKeyPad->nValStrPos] = '\0'; // Zero terminate
|
||||
bRedraw = true;
|
||||
}
|
||||
return bRedraw;
|
||||
}
|
||||
|
||||
// Handle the compound element main functionality
|
||||
// - This routine is called by gslc_ElemEvent() to handle
|
||||
// any click events that resulted from the touch tracking process.
|
||||
// - The code here will generally represent the core
|
||||
// functionality of the compound element and any communication
|
||||
// between sub-elements.
|
||||
// - pvElemRef is a void pointer to the element ref being tracked. From
|
||||
// the pElemRefParent member we can get the parent/compound element
|
||||
// data structures.
|
||||
bool gslc_ElemXKeyPadClick(void* pvGui, void *pvElemRef, gslc_teTouch eTouch, int16_t nX, int16_t nY)
|
||||
{
|
||||
#if defined(DRV_TOUCH_NONE)
|
||||
return false;
|
||||
#else
|
||||
|
||||
gslc_tsGui* pGui = (gslc_tsGui*)(pvGui);
|
||||
gslc_tsElemRef* pElemRef = (gslc_tsElemRef*)(pvElemRef);
|
||||
gslc_tsElem* pElem = gslc_GetElemFromRefD(pGui, pElemRef, __LINE__);
|
||||
|
||||
// Fetch the parent of the clicked element which is the compound
|
||||
// element itself. This enables us to access the extra control data.
|
||||
gslc_tsElemRef* pElemRefParent = pElem->pElemRefParent;
|
||||
if (pElemRefParent == NULL) {
|
||||
GSLC_DEBUG2_PRINT("ERROR: ElemXKeyPadClick(%s) parent ElemRef ptr NULL\n", "");
|
||||
return false;
|
||||
}
|
||||
|
||||
gslc_tsXKeyPad* pKeyPad = (gslc_tsXKeyPad*)gslc_GetXDataFromRef(pGui, pElemRefParent, GSLC_TYPEX_KEYPAD, __LINE__);
|
||||
if (!pKeyPad) return false;
|
||||
|
||||
//GSLC_DEBUG2_PRINT("KeyPad Click Touch=%d\n", eTouch);
|
||||
|
||||
// Handle the various button presses
|
||||
if (eTouch == GSLC_TOUCH_UP_IN) {
|
||||
// Get the tracked element ID
|
||||
gslc_tsElemRef* pElemRefTracked = pKeyPad->sCollect.pElemRefTracked;
|
||||
gslc_tsElem* pElemTracked = gslc_GetElemFromRef(pGui, pElemRefTracked);
|
||||
|
||||
int nSubElemId = pElemTracked->nId;
|
||||
int16_t nKeyInd = 0;
|
||||
bool bValRedraw = false;
|
||||
|
||||
GSLC_CB_INPUT pfuncXInput = pKeyPad->pfuncCb;
|
||||
XKEYPAD_LOOKUP pfuncLookup = pKeyPad->pfuncLookup;
|
||||
gslc_tsXKeyPadData sKeyPadData;
|
||||
|
||||
if (pfuncLookup != NULL) {
|
||||
// FIXME: ERROR
|
||||
}
|
||||
|
||||
// Prepare the return data
|
||||
sKeyPadData.pStr = pKeyPad->acValStr;
|
||||
sKeyPadData.nTargetId = pKeyPad->nTargetId;
|
||||
|
||||
//GSLC_DEBUG2_PRINT("KeyPad Click ID=%d\n", nSubElemId);
|
||||
|
||||
switch (nSubElemId) {
|
||||
|
||||
case KEYPAD_ID_ENTER:
|
||||
//GSLC_DEBUG2_PRINT("KeyPad Key=ENT\n", "");
|
||||
//GSLC_DEBUG2_PRINT("KeyPad Done Str=[%s]\n", pKeyPad->acValStr);
|
||||
|
||||
|
||||
// Issue callback with Done status
|
||||
if (pfuncXInput != NULL) {
|
||||
(*pfuncXInput)(pvGui, (void*)(pElemRefParent), XKEYPAD_CB_STATE_DONE, (void*)(&sKeyPadData));
|
||||
}
|
||||
|
||||
// Clear the contents
|
||||
memset(pKeyPad->acValStr, 0, XKEYPAD_VAL_LEN);
|
||||
pKeyPad->nValStrPos = 0;
|
||||
pKeyPad->nTargetId = GSLC_ID_NONE;
|
||||
break;
|
||||
|
||||
case KEYPAD_ID_ESC:
|
||||
//GSLC_DEBUG2_PRINT("KeyPad Key=ESC\n", "");
|
||||
// Clear the contents
|
||||
memset(pKeyPad->acValStr, 0, XKEYPAD_VAL_LEN);
|
||||
pKeyPad->nValStrPos = 0;
|
||||
pKeyPad->nTargetId = GSLC_ID_NONE;
|
||||
bValRedraw = true;
|
||||
//GSLC_DEBUG2_PRINT("KeyPad Done Str=[%s]\n", pKeyPad->acValStr);
|
||||
// Issue callback with Cancel status
|
||||
if (pfuncXInput != NULL) {
|
||||
(*pfuncXInput)(pvGui, (void*)(pElemRefParent), XKEYPAD_CB_STATE_CANCEL, (void*)(&sKeyPadData));
|
||||
}
|
||||
break;
|
||||
|
||||
case KEYPAD_ID_DECIMAL:
|
||||
//GSLC_DEBUG2_PRINT("KeyPad Key=Decimal\n", "");
|
||||
if (!pKeyPad->sConfig.bFloatEn) break; // Ignore if floating point not enabled
|
||||
if (!pKeyPad->bValDecimalPt) {
|
||||
bValRedraw |= ElemXKeyPadAddChar(pGui, pKeyPad, KEYPAD_DISP_DECIMAL_PT);
|
||||
}
|
||||
break;
|
||||
|
||||
case KEYPAD_ID_MINUS:
|
||||
//GSLC_DEBUG2_PRINT("KeyPad Key=Minus\n", "");
|
||||
if (!pKeyPad->sConfig.bSignEn) break; // Ignore if negative numbers not enabled
|
||||
// Toggle sign
|
||||
gslc_ElemXKeyPadValSetSign(pGui, pElemRefParent, pKeyPad->bValPositive ? false : true);
|
||||
bValRedraw = true;
|
||||
break;
|
||||
|
||||
case KEYPAD_ID_BACKSPACE:
|
||||
//GSLC_DEBUG2_PRINT("KeyPad Key=BS\n", "");
|
||||
if (pKeyPad->nValStrPos < 1) break;
|
||||
pKeyPad->nValStrPos--;
|
||||
// Handle the special case of decimal point if floating point enabled
|
||||
if (pKeyPad->sConfig.bFloatEn) {
|
||||
if (pKeyPad->acValStr[pKeyPad->nValStrPos] == KEYPAD_DISP_DECIMAL_PT) {
|
||||
//GSLC_DEBUG2_PRINT("KeyPad Key=BS across decimal\n", "");
|
||||
pKeyPad->bValDecimalPt = false;
|
||||
}
|
||||
}
|
||||
if (pKeyPad->nValStrPos == 0) {
|
||||
memset(pKeyPad->acValStr, 0, XKEYPAD_VAL_LEN);
|
||||
pKeyPad->bValPositive = true;
|
||||
}
|
||||
pKeyPad->acValStr[pKeyPad->nValStrPos] = '\0';
|
||||
bValRedraw = true;
|
||||
break;
|
||||
|
||||
case KEYPAD_ID_PERIOD:
|
||||
case KEYPAD_ID_SPACE:
|
||||
default:
|
||||
// Normal character
|
||||
//GSLC_DEBUG2_PRINT("KeyPad Key=Digit\n", "");
|
||||
// For basic buttons, we need to fetch the keypad string index
|
||||
nKeyInd = (*pfuncLookup)(pGui, nSubElemId);
|
||||
bValRedraw |= ElemXKeyPadAddChar(pGui, pKeyPad, pKeyPad->pacKeys[nKeyInd][0]);
|
||||
break;
|
||||
} // switch
|
||||
|
||||
// Do we need to redraw the text field?
|
||||
if (bValRedraw) {
|
||||
pElemRef = gslc_CollectFindElemById(pGui, &pKeyPad->sCollect, KEYPAD_ID_TXT);
|
||||
gslc_ElemSetRedraw(pGui, pElemRef, GSLC_REDRAW_INC);
|
||||
// Issue callback with Update status
|
||||
if (pfuncXInput != NULL) {
|
||||
(*pfuncXInput)(pvGui, (void*)(pElemRefParent), XKEYPAD_CB_STATE_UPDATE, (void*)(&sKeyPadData));
|
||||
}
|
||||
} // bValRedraw
|
||||
|
||||
} // eTouch
|
||||
|
||||
return true;
|
||||
#endif // !DRV_TOUCH_NONE
|
||||
}
|
||||
|
||||
bool gslc_ElemXKeyPadTouch(void* pvGui, void* pvElemRef, gslc_teTouch eTouch, int16_t nRelX, int16_t nRelY)
|
||||
{
|
||||
#if defined(DRV_TOUCH_NONE)
|
||||
return false;
|
||||
#else
|
||||
|
||||
if ((pvGui == NULL) || (pvElemRef == NULL)) {
|
||||
static const char GSLC_PMEM FUNCSTR[] = "ElemXKeyPadTouch";
|
||||
GSLC_DEBUG2_PRINT_CONST(ERRSTR_NULL, FUNCSTR);
|
||||
return false;
|
||||
}
|
||||
gslc_tsGui* pGui = NULL;
|
||||
gslc_tsElemRef* pElemRef = NULL;
|
||||
gslc_tsElem* pElem = NULL;
|
||||
gslc_tsXKeyPad* pKeyPad = NULL;
|
||||
|
||||
|
||||
// Typecast the parameters to match the GUI
|
||||
pGui = (gslc_tsGui*)(pvGui);
|
||||
pElemRef = (gslc_tsElemRef*)(pvElemRef);
|
||||
pElem = gslc_GetElemFromRef(pGui, pElemRef);
|
||||
pKeyPad = (gslc_tsXKeyPad*)(pElem->pXData);
|
||||
|
||||
// Get Collection
|
||||
gslc_tsCollect* pCollect = &pKeyPad->sCollect;
|
||||
|
||||
// Cascade the touch event to the sub-element collection
|
||||
return gslc_CollectTouchCompound(pvGui, pvElemRef, eTouch, nRelX, nRelY, pCollect);
|
||||
#endif // !DRV_TOUCH_NONE
|
||||
}
|
||||
|
||||
|
||||
|
||||
void gslc_ElemXKeyPadCfgSetButtonSz(gslc_tsXKeyPadCfg* pConfig, int8_t nButtonSzW, int8_t nButtonSzH)
|
||||
{
|
||||
pConfig->nButtonSzW = nButtonSzW;
|
||||
pConfig->nButtonSzH = nButtonSzH;
|
||||
}
|
||||
|
||||
void gslc_ElemXKeyPadCfgSetFloatEn(gslc_tsXKeyPadCfg* pConfig, bool bEn)
|
||||
{
|
||||
pConfig->bFloatEn = bEn;
|
||||
}
|
||||
|
||||
void gslc_ElemXKeyPadCfgSetSignEn(gslc_tsXKeyPadCfg* pConfig, bool bEn)
|
||||
{
|
||||
pConfig->bSignEn = bEn;
|
||||
}
|
||||
|
||||
void gslc_ElemXKeyPadCfgSetRoundEn(gslc_tsXKeyPadCfg* pConfig, bool bEn)
|
||||
{
|
||||
pConfig->bRoundEn = bEn;
|
||||
}
|
||||
|
||||
|
||||
// FIXME: Runtime API not fully functional yet - Do not use
|
||||
void gslc_ElemXKeyPadSetFloatEn(gslc_tsGui* pGui, gslc_tsElemRef* pElemRef, bool bEn)
|
||||
{
|
||||
gslc_tsXKeyPad* pKeyPad = (gslc_tsXKeyPad*)gslc_GetXDataFromRef(pGui, pElemRef, GSLC_TYPEX_KEYPAD, __LINE__);
|
||||
if (!pKeyPad) return;
|
||||
pKeyPad->sConfig.bFloatEn = bEn;
|
||||
// Mark as needing full redraw as button visibility may have changed
|
||||
gslc_ElemSetRedraw(pGui,pElemRef,GSLC_REDRAW_FULL);
|
||||
}
|
||||
|
||||
// FIXME: Runtime API not fully functional yet - Do not use
|
||||
void gslc_ElemXKeyPadSetSignEn(gslc_tsGui* pGui, gslc_tsElemRef* pElemRef, bool bEn)
|
||||
{
|
||||
gslc_tsXKeyPad* pKeyPad = (gslc_tsXKeyPad*)gslc_GetXDataFromRef(pGui, pElemRef, GSLC_TYPEX_KEYPAD, __LINE__);
|
||||
if (!pKeyPad) return;
|
||||
pKeyPad->sConfig.bSignEn = bEn;
|
||||
// Mark as needing full redraw as button visibility may have changed
|
||||
gslc_ElemSetRedraw(pGui,pElemRef,GSLC_REDRAW_FULL);
|
||||
}
|
||||
|
||||
void gslc_ElemXKeyPadInputAsk(gslc_tsGui* pGui, gslc_tsElemRef* pKeyPadRef, int16_t nPgPopup, gslc_tsElemRef* pTxtRef)
|
||||
{
|
||||
// Fetch the Element ID from the text element
|
||||
gslc_tsElem* pTxtElem = gslc_GetElemFromRefD(pGui,pTxtRef,__LINE__);
|
||||
if (!pTxtElem) return;
|
||||
int16_t nTxtElemId = pTxtElem->nId;
|
||||
|
||||
// Associate the keypad with the text field
|
||||
gslc_ElemXKeyPadTargetIdSet(pGui, pKeyPadRef, nTxtElemId);
|
||||
// Show a popup box for the keypad
|
||||
gslc_PopupShow(pGui, nPgPopup, true);
|
||||
// Preload text field with current value
|
||||
gslc_ElemXKeyPadValSet(pGui, pKeyPadRef, gslc_ElemGetTxtStr(pGui, pTxtRef));
|
||||
}
|
||||
|
||||
char* gslc_ElemXKeyPadInputGet(gslc_tsGui* pGui, gslc_tsElemRef* pTxtRef, void* pvCbData)
|
||||
{
|
||||
char* pStr = NULL;
|
||||
// Fetch the current value of the keypad popup
|
||||
pStr = gslc_ElemXKeyPadDataValGet(pGui, pvCbData);
|
||||
// Update the linked text item
|
||||
gslc_ElemSetTxtStr(pGui, pTxtRef, gslc_ElemXKeyPadDataValGet(pGui, pvCbData));
|
||||
// Hide the popup
|
||||
gslc_PopupHide(pGui);
|
||||
|
||||
// Return the text string in case the user wants it
|
||||
return pStr;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif // GSLC_FEATURE_COMPOUND
|
||||
|
||||
|
||||
// ============================================================================
|
409
src/guislice/XKeyPad.h
Normal file
409
src/guislice/XKeyPad.h
Normal file
|
@ -0,0 +1,409 @@
|
|||
#ifndef _GUISLICE_EX_XKEYPAD_H_
|
||||
#define _GUISLICE_EX_XKEYPAD_H_
|
||||
|
||||
#include "GUIslice.h"
|
||||
|
||||
|
||||
// =======================================================================
|
||||
// GUIslice library extension: XKeyPad control
|
||||
// - Paul Conti, Calvin Hass
|
||||
// - https://www.impulseadventure.com/elec/guislice-gui.html
|
||||
// - https://github.com/ImpulseAdventure/GUIslice
|
||||
// =======================================================================
|
||||
//
|
||||
// The MIT License
|
||||
//
|
||||
// Copyright 2016-2020 Calvin Hass
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
//
|
||||
// =======================================================================
|
||||
/// \file XKeyPad.h
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif // __cplusplus
|
||||
|
||||
|
||||
|
||||
#if (GSLC_FEATURE_COMPOUND)
|
||||
// ============================================================================
|
||||
// Extended Element: KeyPad (Number Selector)
|
||||
// - Demonstration of a compound element consisting of
|
||||
// a counter text field along with an increment and
|
||||
// decrement button.
|
||||
// ============================================================================
|
||||
|
||||
// Define unique identifier for extended element type
|
||||
// - Select any number above GSLC_TYPE_BASE_EXTEND
|
||||
#define GSLC_TYPEX_KEYPAD GSLC_TYPE_BASE_EXTEND + 20
|
||||
|
||||
#define XKEYPAD_VAL_LEN 12 // Maximum buffer length for input string
|
||||
|
||||
// Define the status for GSLC_CB_INPUT callback
|
||||
#define XKEYPAD_CB_STATE_DONE 1
|
||||
#define XKEYPAD_CB_STATE_CANCEL 2
|
||||
#define XKEYPAD_CB_STATE_UPDATE 3
|
||||
|
||||
|
||||
// Define global list of button ID types
|
||||
// - A given keypad may not use all of these
|
||||
enum {
|
||||
// --------------------------------------------
|
||||
// --- Special Buttons
|
||||
KEYPAD_ID_BACKSPACE,
|
||||
KEYPAD_ID_PERIOD,
|
||||
KEYPAD_ID_SPACE,
|
||||
KEYPAD_ID_DECIMAL,
|
||||
KEYPAD_ID_MINUS,
|
||||
KEYPAD_ID_ESC,
|
||||
KEYPAD_ID_ENTER,
|
||||
// --- Basic Buttons
|
||||
KEYPAD_ID_BASIC_START=100,
|
||||
// --------------------------------------------
|
||||
// --- Extra elements
|
||||
KEYPAD_ID_TXT=200, // Value string text area
|
||||
};
|
||||
|
||||
/// Function for KeyPad creation
|
||||
typedef int16_t (*XKEYPAD_LOOKUP)(gslc_tsGui* pGui, int16_t nKeyId);
|
||||
|
||||
|
||||
// Extended element data structures
|
||||
// - These data structures are maintained in the gslc_tsElem
|
||||
// structure via the pXData pointer
|
||||
|
||||
/// Configuration for the KeyPad
|
||||
typedef struct {
|
||||
bool bFloatEn; ///< Enable floating point (ie. decimal point)
|
||||
bool bSignEn; ///< Enable negative numbers
|
||||
bool bRoundEn; ///< Enable rounded corners
|
||||
int8_t nButtonSzW; ///< Button width (in pixels)
|
||||
int8_t nButtonSzH; ///< Button height (in pixels)
|
||||
char** pacKeys; ///< Array of character strings for KeyPad labels
|
||||
|
||||
// From constructor
|
||||
int16_t nFontId; ///< Configured font for KeyPad labels
|
||||
int16_t nOffsetX; ///< Configured offset (X direction) for buttons from parent container
|
||||
int16_t nOffsetY; ///< Configured offset (Y direction) for buttons from parent container
|
||||
|
||||
int8_t nFrameMargin; ///< Margin around text value field
|
||||
uint8_t nMaxCols; ///< Maximum number of columns to occupy
|
||||
uint8_t nMaxRows; ///< Maximum number of rows to occupy
|
||||
} gslc_tsXKeyPadCfg;
|
||||
|
||||
/// Input callback data structure
|
||||
/// - This struct is returned in GSLC_CB_INPUT when the
|
||||
/// KeyPad edits are complete, and is used to provide
|
||||
/// the resulting edited value.
|
||||
typedef struct {
|
||||
char* pStr; ///< Final value of edited value field
|
||||
int16_t nTargetId; ///< Target element ID to receive the value
|
||||
} gslc_tsXKeyPadData;
|
||||
|
||||
/// Extended data for KeyPad element
|
||||
typedef struct {
|
||||
|
||||
// State
|
||||
uint8_t nValStrPos; ///< Current number of characters stored in edit value string
|
||||
char acValStr[XKEYPAD_VAL_LEN]; ///< Storage for edit value string
|
||||
bool bValPositive; ///< Value is positive if true, negative if false
|
||||
bool bValDecimalPt; ///< Value string includes decimal point
|
||||
|
||||
// Config
|
||||
char** pacKeys; ///< Array of character strings for KeyPad labels
|
||||
gslc_tsXKeyPadCfg sConfig; ///< Configuration options
|
||||
|
||||
GSLC_CB_INPUT pfuncCb; ///< Callback function for KeyPad actions
|
||||
XKEYPAD_LOOKUP pfuncLookup; ///< Callback function for converting key into key label
|
||||
int16_t nTargetId; ///< Target element ID associated with keypad (GSLC_CB_INPUT)
|
||||
|
||||
// Internal sub-element members
|
||||
gslc_tsCollect sCollect; ///< Collection management for sub-elements
|
||||
uint8_t nSubElemMax; ///< Maximum number of sub-elements to create within KeyPad container
|
||||
gslc_tsElemRef* psElemRef; ///< Ptr to storage for sub-element references
|
||||
gslc_tsElem* psElem; ///< Ptr to storage for sub-elements
|
||||
|
||||
} gslc_tsXKeyPad;
|
||||
|
||||
|
||||
// Callback function for KeyPad creation
|
||||
typedef void (*XKEYPAD_CREATE)(gslc_tsGui* pGui,gslc_tsXKeyPad* pXData);
|
||||
|
||||
|
||||
///
|
||||
/// Add a key to the KeyPad control
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] pXData: Ptr to extended element data structure
|
||||
/// \param[in] nKeyId: ID to associated with the key
|
||||
/// \param[in] bTxtField: Is this the text value field?
|
||||
/// \param[in] nRow: Element placement position (row index, 0 at top)
|
||||
/// \param[in] nCol: Element placement position (column index, 0 at left)
|
||||
/// \param[in] nRowSpan: Number of columns to occupy by element (1 for normal size, 2 for double width)
|
||||
/// \param[in] nColSpan: Number of rows to occupy by element (1 for normal size, 2 for double height)
|
||||
/// \param[in] cColFill: Fill color for element
|
||||
/// \param[in] cColGlow: Fill color for element when glowing
|
||||
/// \param[in] bVisible: Initial key visibility state
|
||||
///
|
||||
/// \return none
|
||||
///
|
||||
void XKeyPadAddKeyElem(gslc_tsGui* pGui, gslc_tsXKeyPad* pXData, int16_t nKeyId, bool bTxtField, int16_t nRow, int16_t nCol,
|
||||
int8_t nRowSpan, int8_t nColSpan, gslc_tsColor cColFill, gslc_tsColor cColGlow, bool bVisible);
|
||||
|
||||
///
|
||||
/// Create a KeyPad Element
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] nElemId: Element ID to assign (0..16383 or GSLC_ID_AUTO to autogen)
|
||||
/// \param[in] nPage: Page ID to attach element to
|
||||
/// \param[in] pXData: Ptr to extended element data structure
|
||||
/// \param[in] nX0: X KeyPad Starting Coordinate
|
||||
/// \param[in] nY0: Y KeyPad Starting Coordinate
|
||||
/// \param[in] nFontId: Font ID to use for drawing the element
|
||||
/// \param[in] pConfig: Ptr to Config options
|
||||
/// \param[in] pfuncCreate: Ptr to callback function for creation
|
||||
/// \param[in] pfuncLookup: Ptr to callback function for button lookups
|
||||
///
|
||||
/// \return Pointer to Element or NULL if failure
|
||||
///
|
||||
gslc_tsElemRef* gslc_ElemXKeyPadCreateBase(gslc_tsGui* pGui, int16_t nElemId, int16_t nPage,
|
||||
gslc_tsXKeyPad* pXData, int16_t nX0, int16_t nY0, int8_t nFontId, gslc_tsXKeyPadCfg* pConfig,
|
||||
XKEYPAD_CREATE pfuncCreate, XKEYPAD_LOOKUP pfuncLookup);
|
||||
|
||||
|
||||
///
|
||||
/// Set the current value for the editable text field
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] pElemRef: Ptr to KeyPad Element reference
|
||||
/// \param[in] pStrBuf: String to copy into keypad
|
||||
///
|
||||
/// \return none
|
||||
///
|
||||
void gslc_ElemXKeyPadValSet(gslc_tsGui* pGui, gslc_tsElemRef* pElemRef, const char* pStrBuf);
|
||||
|
||||
///
|
||||
/// Set target element ID for KeyPad return value
|
||||
/// - The Target ID is used in the GSLC_CB_INPUT callback so that the user
|
||||
/// has the context needed to determine which field should be edited
|
||||
/// with the contents of the KeyPad edit field
|
||||
/// - It is expected that the user will call this function when showing
|
||||
/// the KeyPad popup dialog
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] pElemRef: Ptr to KeyPad Element reference
|
||||
/// \param[in] nId: Element enum ID for target of KeyPad value
|
||||
///
|
||||
/// \return none
|
||||
///
|
||||
void gslc_ElemXKeyPadTargetIdSet(gslc_tsGui* pGui, gslc_tsElemRef* pElemRef, int16_t nId);
|
||||
|
||||
|
||||
///
|
||||
/// Set the current output string buffer associated with NumericInput element
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] pElemRef: Ptr to KeyPad Element reference
|
||||
/// \param[in] pStrBuf: String to copy into element
|
||||
/// \param[in] nStrBufMax: Maximum length of string buffer (pStrBuf)
|
||||
///
|
||||
/// \return none
|
||||
///
|
||||
bool gslc_ElemXKeyPadValGet(gslc_tsGui* pGui, gslc_tsElemRef* pElemRef, char* pStrBuf, uint8_t nStrBufMax);
|
||||
|
||||
///
|
||||
/// Fetch the edited value string from the KeyPad
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] pvData : Void ptr to callback data structure
|
||||
///
|
||||
/// \return Pointer to edited character string
|
||||
///
|
||||
char* gslc_ElemXKeyPadDataValGet(gslc_tsGui* pGui, void* pvData);
|
||||
|
||||
|
||||
///
|
||||
/// Fetch the element target ID associated with this KeyPad
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] pvData : Void ptr to callback data structure
|
||||
///
|
||||
/// \return Target Element ID or GSLC_ID_NONE if unspecified
|
||||
///
|
||||
int16_t gslc_ElemXKeyPadDataTargetIdGet(gslc_tsGui* pGui, void* pvData);
|
||||
|
||||
///
|
||||
/// Draw a KeyPad element on the screen
|
||||
/// - Called during redraw
|
||||
///
|
||||
/// \param[in] pvGui: Void ptr to GUI (typecast to gslc_tsGui*)
|
||||
/// \param[in] pvElemRef: Void ptr to Element reference (typecast to gslc_tsElemRef*)
|
||||
/// \param[in] eRedraw: Redraw mode
|
||||
///
|
||||
/// \return true if success, false otherwise
|
||||
///
|
||||
bool gslc_ElemXKeyPadDraw(void* pvGui, void* pvElemRef, gslc_teRedrawType eRedraw);
|
||||
|
||||
///
|
||||
/// Handle a click event within the KeyPad
|
||||
/// - This is called internally by the KeyPad touch handler
|
||||
///
|
||||
/// \param[in] pvGui: Void ptr to GUI (typecast to gslc_tsGui*)
|
||||
/// \param[in] pvElemRef: Void ptr to Element Ref (typecast to gslc_tsElemRef*)
|
||||
/// \param[in] eTouch: Touch event type
|
||||
/// \param[in] nX: Touch X coord
|
||||
/// \param[in] nY: Touch Y coord
|
||||
///
|
||||
/// \return none
|
||||
///
|
||||
bool gslc_ElemXKeyPadClick(void* pvGui, void *pvElemRef, gslc_teTouch eTouch, int16_t nX, int16_t nY);
|
||||
|
||||
///
|
||||
/// Handle touch (up,down,move) events to KeyPad element
|
||||
/// - Called from gslc_ElemSendEventTouch()
|
||||
///
|
||||
/// \param[in] pvGui: Void ptr to GUI (typecast to gslc_tsGui*)
|
||||
/// \param[in] pvElemRef: Void ptr to Element ref (typecast to gslc_tsElemRef*)
|
||||
/// \param[in] eTouch: Touch event type
|
||||
/// \param[in] nRelX: Touch X coord relative to element
|
||||
/// \param[in] nRelY: Touch Y coord relative to element
|
||||
///
|
||||
/// \return true if success, false otherwise
|
||||
///
|
||||
bool gslc_ElemXKeyPadTouch(void* pvGui, void* pvElemRef, gslc_teTouch eTouch, int16_t nRelX, int16_t nRelY);
|
||||
|
||||
///
|
||||
/// Set the callback function associated with the KeyPad
|
||||
/// - This function will be called during updates and OK / Cancel
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] pElemRef: Pointer to Element Reference for KeyPad
|
||||
/// \param[in] pfuncCb: Callback function pointer
|
||||
///
|
||||
/// \return none
|
||||
///
|
||||
void gslc_ElemXKeyPadValSetCb(gslc_tsGui* pGui, gslc_tsElemRef* pElemRef, GSLC_CB_INPUT pfuncCb);
|
||||
|
||||
///
|
||||
/// Update the KeyPad configuration to enable floating point numbers
|
||||
/// - Effectively disables/enables the decimal point button & handling
|
||||
///
|
||||
/// \param[in] pConfig: Pointer to the XKeyPad config structure
|
||||
/// \param[in] bEn: Enable flag (true if floating point enabled)
|
||||
///
|
||||
/// \return none
|
||||
///
|
||||
void gslc_ElemXKeyPadCfgSetFloatEn(gslc_tsXKeyPadCfg* pConfig,bool bEn);
|
||||
|
||||
///
|
||||
/// Update the KeyPad configuration to enable negative numbers
|
||||
/// - Effectively disables/enables the sign button & handling
|
||||
///
|
||||
/// \param[in] pConfig: Pointer to the XKeyPad config structure
|
||||
/// \param[in] bEn: Enable flag (true if negative numbers enabled)
|
||||
///
|
||||
/// \return none
|
||||
///
|
||||
void gslc_ElemXKeyPadCfgSetSignEn(gslc_tsXKeyPadCfg* pConfig,bool bEn);
|
||||
|
||||
///
|
||||
/// Update the KeyPad configuration to enable rounded button corners
|
||||
///
|
||||
/// \param[in] pConfig: Pointer to the XKeyPad config structure
|
||||
/// \param[in] bEn: Enable rounded corners
|
||||
///
|
||||
/// \return none
|
||||
///
|
||||
void gslc_ElemXKeyPadCfgSetRoundEn(gslc_tsXKeyPadCfg* pConfig,bool bEn);
|
||||
|
||||
///
|
||||
/// Update the KeyPad configuration to define the KeyPad button sizing
|
||||
///
|
||||
/// \param[in] pConfig: Pointer to the XKeyPad config structure
|
||||
/// \param[in] nButtonSzW: Width of buttons in pixels
|
||||
/// \param[in] nButtonSzH: Width of buttons in pixels
|
||||
///
|
||||
/// \return none
|
||||
///
|
||||
void gslc_ElemXKeyPadCfgSetButtonSz(gslc_tsXKeyPadCfg* pConfig, int8_t nButtonSzW, int8_t nButtonSzH);
|
||||
|
||||
///
|
||||
/// Update the KeyPad active configuration to enable negative numbers
|
||||
/// - Effectively disables/enables the sign button & handling
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] pElemRef: Pointer to KeyPad element reference
|
||||
/// \param[in] bEn: Enable flag (true if negative numbers enabled)
|
||||
///
|
||||
/// \return none
|
||||
///
|
||||
void gslc_ElemXKeyPadSetFloatEn(gslc_tsGui* pGui, gslc_tsElemRef* pElemRef, bool bEn);
|
||||
|
||||
///
|
||||
/// Update the KeyPad active configuration to enable negative numbers
|
||||
/// - Effectively disables/enables the sign button & handling
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] pElemRef: Pointer to KeyPad element reference
|
||||
/// \param[in] bEn: Enable flag (true if negative numbers enabled)
|
||||
///
|
||||
/// \return none
|
||||
///
|
||||
void gslc_ElemXKeyPadSetSignEn(gslc_tsGui* pGui, gslc_tsElemRef* pElemRef, bool bEn);
|
||||
|
||||
///
|
||||
/// Trigger a KeyPad popup and associate it with a text element
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] pKeyPadRef: Pointer to KeyPad element reference
|
||||
/// \param[in] nPgPopup: Page enum that contains the popup to show
|
||||
/// \param[in] pTxtRef: Pointer to associated text field element reference
|
||||
///
|
||||
/// \return none
|
||||
///
|
||||
void gslc_ElemXKeyPadInputAsk(gslc_tsGui* pGui, gslc_tsElemRef* pKeyPadRef, int16_t nPgPopup, gslc_tsElemRef* pTxtRef);
|
||||
|
||||
///
|
||||
/// Complete a KeyPad popup by retrieving the input data and storing it in the text element
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] pTxtRef: Pointer to associated text field element reference
|
||||
/// \param[in] pvCbData: Void pointer to callback function's pvData
|
||||
///
|
||||
/// \return The text string that was fetched from the KeyPad
|
||||
///
|
||||
char* gslc_ElemXKeyPadInputGet(gslc_tsGui* pGui, gslc_tsElemRef* pTxtRef, void* pvCbData);
|
||||
|
||||
|
||||
#endif // GSLC_FEATURE_COMPOUND
|
||||
|
||||
// ============================================================================
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Read-only element macros
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
// Macro initializers for Read-Only Elements in Flash/PROGMEM
|
||||
//
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif // __cplusplus
|
||||
#endif // _GUISLICE_EX_XKEYPAD_H_
|
||||
|
204
src/guislice/XKeyPad_Alpha.c
Normal file
204
src/guislice/XKeyPad_Alpha.c
Normal file
|
@ -0,0 +1,204 @@
|
|||
// =======================================================================
|
||||
// GUIslice library extension: XKeyPad control (Alpha entry)
|
||||
// - Paul Conti, Calvin Hass
|
||||
// - https://www.impulseadventure.com/elec/guislice-gui.html
|
||||
// - https://github.com/ImpulseAdventure/GUIslice
|
||||
// =======================================================================
|
||||
//
|
||||
// The MIT License
|
||||
//
|
||||
// Copyright 2016-2020 Calvin Hass
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
//
|
||||
// =======================================================================
|
||||
/// \file XKeyPad.c
|
||||
|
||||
|
||||
|
||||
// GUIslice library
|
||||
#include "GUIslice.h"
|
||||
#include "GUIslice_drv.h"
|
||||
|
||||
#include "XKeyPad.h"
|
||||
#include "XKeyPad_Alpha.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#if (GSLC_USE_PROGMEM)
|
||||
#include <avr/pgmspace.h>
|
||||
#endif
|
||||
|
||||
#if (GSLC_FEATURE_COMPOUND)
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Error Messages
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
extern const char GSLC_PMEM ERRSTR_NULL[];
|
||||
extern const char GSLC_PMEM ERRSTR_PXD_NULL[];
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Extended element definitions
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// - This file extends the core GUIslice functionality with
|
||||
// additional widget types
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
|
||||
// ============================================================================
|
||||
// Extended Element: KeyPad
|
||||
// - Keypad element with alpha input
|
||||
// ============================================================================
|
||||
|
||||
// Define the button labels
|
||||
// - TODO: Create more efficient storage for the labels
|
||||
// so that it doesn't consume 4 bytes even for labels
|
||||
// that can be generated (eg. 0..9, a--z, etc.)
|
||||
// - TODO: Support use of PROGMEM. Note that these labels
|
||||
// are not currently using "const char" since we may
|
||||
// want to support user-modification of the labels.
|
||||
|
||||
static char* KEYPAD_LABEL_STRINGS[] = {
|
||||
// Special buttons
|
||||
"<", ".", " ", "ESC", "ENT",
|
||||
// Basic buttons
|
||||
"A", "B", "C", "D", "E", "F", "G", "H" ,"I", "J",
|
||||
"K", "L", "M", "N", "O", "P", "Q", "R" ,"S", "T",
|
||||
"U", "V", "W", "X", "Y", "Z",
|
||||
};
|
||||
|
||||
// Define enums for KEYPAD_LABEL_STRINGS
|
||||
enum {
|
||||
// - Special buttons
|
||||
KEYPAD_LBL_BACKSPACE,
|
||||
KEYPAD_LBL_PERIOD,
|
||||
KEYPAD_LBL_SPACE,
|
||||
KEYPAD_LBL_ESC,
|
||||
KEYPAD_LBL_ENTER,
|
||||
// - Basic buttons
|
||||
KEYPAD_LBL_BASIC_START
|
||||
};
|
||||
|
||||
|
||||
// Generate the keypad layout
|
||||
void XKeyPadCreateKeys_Alpha(gslc_tsGui* pGui, gslc_tsXKeyPad* pXData)
|
||||
{
|
||||
int16_t nKeyInd;
|
||||
int16_t nRow, nCol;
|
||||
|
||||
// - Create the "special" buttons
|
||||
XKeyPadAddKeyElem(pGui, pXData, KEYPAD_ID_BACKSPACE, false, 1, 6, 1, 2, GSLC_COL_GRAY_LT1, GSLC_COL_GRAY_LT3, true);
|
||||
XKeyPadAddKeyElem(pGui, pXData, KEYPAD_ID_PERIOD, false, 3, 7, 1, 1, GSLC_COL_GRAY_LT1, GSLC_COL_GRAY_LT3, true);
|
||||
XKeyPadAddKeyElem(pGui, pXData, KEYPAD_ID_SPACE, false, 3, 6, 1, 1, GSLC_COL_GRAY_LT1, GSLC_COL_GRAY_LT3, true);
|
||||
XKeyPadAddKeyElem(pGui, pXData, KEYPAD_ID_ESC, false, 2, 6, 1, 2, GSLC_COL_RED, GSLC_COL_RED_LT4, true);
|
||||
XKeyPadAddKeyElem(pGui, pXData, KEYPAD_ID_ENTER, false, 0, 6, 1, 2, GSLC_COL_GREEN, GSLC_COL_GREEN_LT4, true);
|
||||
|
||||
// - Create the "simple" buttons
|
||||
for (int16_t nKeyId = KEYPAD_ID_BASIC_START; nKeyId < (KEYPAD_ID_BASIC_START + XKEYPADALPHA_BTN_BASIC); nKeyId++) {
|
||||
nKeyInd = nKeyId - KEYPAD_ID_BASIC_START;
|
||||
nRow = (nKeyInd / 6) + 1;
|
||||
nCol = nKeyInd % 6;
|
||||
XKeyPadAddKeyElem(pGui, pXData, nKeyId, false, nRow, nCol, 1, 1, GSLC_COL_BLUE_LT1, GSLC_COL_BLUE_LT4, true);
|
||||
}
|
||||
|
||||
// - Create the text field
|
||||
XKeyPadAddKeyElem(pGui, pXData, KEYPAD_ID_TXT, true, 0, 0, 1, 6, GSLC_COL_BLACK, GSLC_COL_BLACK, true);
|
||||
}
|
||||
|
||||
// Convert between keypad ID and the index into the keypad label array
|
||||
int16_t XKeyPadLookup_Alpha(gslc_tsGui* pGui, int16_t nKeyId)
|
||||
{
|
||||
int16_t nKeyInd;
|
||||
|
||||
// Basic button
|
||||
if (nKeyId >= KEYPAD_ID_BASIC_START) {
|
||||
nKeyInd = (nKeyId - KEYPAD_ID_BASIC_START) + KEYPAD_LBL_BASIC_START;
|
||||
} else {
|
||||
// Special button
|
||||
switch (nKeyId) {
|
||||
case KEYPAD_ID_PERIOD:
|
||||
nKeyInd = KEYPAD_LBL_PERIOD;
|
||||
break;
|
||||
case KEYPAD_ID_SPACE:
|
||||
nKeyInd = KEYPAD_LBL_SPACE;
|
||||
break;
|
||||
case KEYPAD_ID_BACKSPACE:
|
||||
nKeyInd = KEYPAD_LBL_BACKSPACE;
|
||||
break;
|
||||
case KEYPAD_ID_ESC:
|
||||
nKeyInd = KEYPAD_LBL_ESC;
|
||||
break;
|
||||
case KEYPAD_ID_ENTER:
|
||||
nKeyInd = KEYPAD_LBL_ENTER;
|
||||
break;
|
||||
default:
|
||||
// FIXME: ERROR
|
||||
nKeyInd = -1; // Not expected
|
||||
break;
|
||||
}
|
||||
}
|
||||
return nKeyInd;
|
||||
}
|
||||
|
||||
// Create the XKeyPad_Alpha compound element
|
||||
// - Note that this also revises some of the members of the base XKeyPad struct
|
||||
gslc_tsElemRef* gslc_ElemXKeyPadCreate_Alpha(gslc_tsGui* pGui, int16_t nElemId, int16_t nPage,
|
||||
gslc_tsXKeyPad_Alpha* pXData, int16_t nX0, int16_t nY0, int8_t nFontId, gslc_tsXKeyPadCfg* pConfig)
|
||||
{
|
||||
gslc_tsXKeyPad* pXDataBase = (gslc_tsXKeyPad*)pXData;
|
||||
pXDataBase->nSubElemMax = XKEYPADALPHA_ELEM_MAX;
|
||||
pXDataBase->psElemRef = pXData->asElemRef;
|
||||
pXDataBase->psElem = pXData->asElem;
|
||||
|
||||
// Provide default config if none supplied
|
||||
gslc_tsXKeyPadCfg sConfigTmp;
|
||||
if (pConfig == NULL) {
|
||||
sConfigTmp = gslc_ElemXKeyPadCfgInit_Alpha();
|
||||
pConfig = &sConfigTmp;
|
||||
}
|
||||
|
||||
return gslc_ElemXKeyPadCreateBase(pGui, nElemId, nPage, pXDataBase, nX0, nY0, nFontId, pConfig,
|
||||
&XKeyPadCreateKeys_Alpha,&XKeyPadLookup_Alpha);
|
||||
}
|
||||
|
||||
// Reset the XKeyPad config struct
|
||||
// - This must be called before any XKeyPad config update APIs are called
|
||||
gslc_tsXKeyPadCfg gslc_ElemXKeyPadCfgInit_Alpha()
|
||||
{
|
||||
gslc_tsXKeyPadCfg sConfig;
|
||||
sConfig.nButtonSzW = 25;
|
||||
sConfig.nButtonSzH = 25;
|
||||
sConfig.bFloatEn = false; // Unused
|
||||
sConfig.bSignEn = false; // Unused
|
||||
sConfig.bRoundEn = false;
|
||||
sConfig.nFontId = GSLC_FONT_NONE; // Will be overwritten
|
||||
sConfig.pacKeys = KEYPAD_LABEL_STRINGS;
|
||||
sConfig.nMaxCols = 8;
|
||||
sConfig.nMaxRows = 6;
|
||||
sConfig.nFrameMargin = 2;
|
||||
return sConfig;
|
||||
}
|
||||
|
||||
#endif // GSLC_FEATURE_COMPOUND
|
||||
|
||||
// ============================================================================
|
100
src/guislice/XKeyPad_Alpha.h
Normal file
100
src/guislice/XKeyPad_Alpha.h
Normal file
|
@ -0,0 +1,100 @@
|
|||
#ifndef _GUISLICE_EX_XKEYPAD_ALPHA_H_
|
||||
#define _GUISLICE_EX_XKEYPAD_ALPHA_H_
|
||||
|
||||
#include "GUIslice.h"
|
||||
|
||||
#include "XKeyPad.h"
|
||||
|
||||
// =======================================================================
|
||||
// GUIslice library extension: XKeyPad control (alpha entry)
|
||||
// - Paul Conti, Calvin Hass
|
||||
// - https://www.impulseadventure.com/elec/guislice-gui.html
|
||||
// - https://github.com/ImpulseAdventure/GUIslice
|
||||
// =======================================================================
|
||||
//
|
||||
// The MIT License
|
||||
//
|
||||
// Copyright 2016-2020 Calvin Hass
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
//
|
||||
// =======================================================================
|
||||
/// \file XKeyPad.h
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif // __cplusplus
|
||||
|
||||
#if (GSLC_FEATURE_COMPOUND)
|
||||
|
||||
// Define number of buttons & elements
|
||||
// - Refer to the definitions in the XKeyPad_*.c file
|
||||
#define XKEYPADALPHA_BTN_BASIC 26
|
||||
#define XKEYPADALPHA_ELEM_MAX (6 + XKEYPADALPHA_BTN_BASIC)
|
||||
|
||||
// ============================================================================
|
||||
// Extended Element: KeyPad Character entry
|
||||
// - NOTE: The XKeyPad_Alpha extends the XKeyPad base element
|
||||
// ============================================================================
|
||||
|
||||
typedef struct {
|
||||
// Base XKeyPad struct
|
||||
// - The base type must appear at the top of the derived struct
|
||||
gslc_tsXKeyPad sKeyPad; ///< Base XKeyPad element
|
||||
|
||||
gslc_tsElemRef asElemRef[XKEYPADALPHA_ELEM_MAX]; ///< Storage for sub-element references
|
||||
gslc_tsElem asElem[XKEYPADALPHA_ELEM_MAX]; ///< Storage for sub-elements
|
||||
} gslc_tsXKeyPad_Alpha;
|
||||
|
||||
///
|
||||
/// Create a KeyPad Element
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] nElemId: Element ID to assign (0..16383 or GSLC_ID_AUTO to autogen)
|
||||
/// \param[in] nPage: Page ID to attach element to
|
||||
/// \param[in] pXData: Ptr to extended element data structure
|
||||
/// \param[in] nX0: X KeyPad Starting Coordinate
|
||||
/// \param[in] nY0: Y KeyPad Starting Coordinate
|
||||
/// \param[in] nFontId: Font ID to use for drawing the element
|
||||
/// \param[in] pConfig: Ptr to config options
|
||||
///
|
||||
/// \return Pointer to Element or NULL if failure
|
||||
///
|
||||
gslc_tsElemRef* gslc_ElemXKeyPadCreate_Alpha(gslc_tsGui* pGui, int16_t nElemId, int16_t nPage,
|
||||
gslc_tsXKeyPad_Alpha* pXData, int16_t nX0, int16_t nY0, int8_t nFontId, gslc_tsXKeyPadCfg* pConfig);
|
||||
|
||||
|
||||
///
|
||||
/// Initialize the KeyPad config structure
|
||||
/// - This routine should be called to initialize the configuration
|
||||
/// data structure before calling any of the KeyPad config APIs
|
||||
///
|
||||
/// \return Initialized KeyPad config structure
|
||||
///
|
||||
gslc_tsXKeyPadCfg gslc_ElemXKeyPadCfgInit_Alpha();
|
||||
|
||||
// ============================================================================
|
||||
|
||||
#endif // GSLC_FEATURE_COMPOUND
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif // __cplusplus
|
||||
#endif // _GUISLICE_EX_XKEYPAD_ALPHA_H_
|
||||
|
206
src/guislice/XKeyPad_Num.c
Normal file
206
src/guislice/XKeyPad_Num.c
Normal file
|
@ -0,0 +1,206 @@
|
|||
// =======================================================================
|
||||
// GUIslice library extension: XKeyPad control (Numeric entry)
|
||||
// - Paul Conti, Calvin Hass
|
||||
// - https://www.impulseadventure.com/elec/guislice-gui.html
|
||||
// - https://github.com/ImpulseAdventure/GUIslice
|
||||
// =======================================================================
|
||||
//
|
||||
// The MIT License
|
||||
//
|
||||
// Copyright 2016-2020 Calvin Hass
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
//
|
||||
// =======================================================================
|
||||
/// \file XKeyPad.c
|
||||
|
||||
|
||||
|
||||
// GUIslice library
|
||||
#include "GUIslice.h"
|
||||
#include "GUIslice_drv.h"
|
||||
|
||||
#include "XKeyPad.h"
|
||||
#include "XKeyPad_Num.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#if (GSLC_USE_PROGMEM)
|
||||
#include <avr/pgmspace.h>
|
||||
#endif
|
||||
|
||||
#if (GSLC_FEATURE_COMPOUND)
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Error Messages
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
extern const char GSLC_PMEM ERRSTR_NULL[];
|
||||
extern const char GSLC_PMEM ERRSTR_PXD_NULL[];
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Extended element definitions
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// - This file extends the core GUIslice functionality with
|
||||
// additional widget types
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
|
||||
// ============================================================================
|
||||
// Extended Element: KeyPad
|
||||
// - Keypad element with numeric input
|
||||
// - Optionally supports floating point values
|
||||
// - Optionally supports negative values
|
||||
// ============================================================================
|
||||
|
||||
// Define the button labels
|
||||
// - TODO: Create more efficient storage for the labels
|
||||
// so that it doesn't consume 4 bytes even for labels
|
||||
// that can be generated (eg. 0..9, a--z, etc.)
|
||||
// - TODO: Support use of PROGMEM. Note that these labels
|
||||
// are not currently using "const char" since we may
|
||||
// want to support user-modification of the labels.
|
||||
|
||||
static char* KEYPAD_LABEL_STRINGS[] = {
|
||||
// Special buttons
|
||||
"<", ".", "-", "ESC", "ENT",
|
||||
// Basic buttons
|
||||
"0", "1", "2", "3", "4", "5", "6", "7" ,"8", "9",
|
||||
};
|
||||
// Define enums for KEYPAD_LABEL_STRINGS
|
||||
enum {
|
||||
// - Special buttons
|
||||
KEYPAD_LBL_BACKSPACE,
|
||||
KEYPAD_LBL_DECIMAL,
|
||||
KEYPAD_LBL_MINUS,
|
||||
KEYPAD_LBL_ESC,
|
||||
KEYPAD_LBL_ENTER,
|
||||
// - Basic buttons
|
||||
KEYPAD_LBL_BASIC_START
|
||||
};
|
||||
|
||||
|
||||
// Generate the keypad layout
|
||||
void XKeyPadCreateKeys_Num(gslc_tsGui* pGui, gslc_tsXKeyPad* pXData)
|
||||
{
|
||||
int16_t nKeyInd;
|
||||
int16_t nRow, nCol;
|
||||
gslc_tsXKeyPadCfg* pConfig = &pXData->sConfig;
|
||||
|
||||
|
||||
// - Create the "special" buttons
|
||||
XKeyPadAddKeyElem(pGui, pXData, KEYPAD_ID_BACKSPACE, false, 1, 6, 1, 2, GSLC_COL_GRAY_LT1, GSLC_COL_GRAY_LT3, true);
|
||||
XKeyPadAddKeyElem(pGui, pXData, KEYPAD_ID_MINUS, false, 1, 5, 1, 1, GSLC_COL_GRAY_LT1, GSLC_COL_GRAY_LT3, pConfig->bSignEn);
|
||||
XKeyPadAddKeyElem(pGui, pXData, KEYPAD_ID_DECIMAL, false, 2, 5, 1, 1, GSLC_COL_GRAY_LT1, GSLC_COL_GRAY_LT3, pConfig->bFloatEn);
|
||||
XKeyPadAddKeyElem(pGui, pXData, KEYPAD_ID_ESC, false, 2, 6, 1, 2, GSLC_COL_RED, GSLC_COL_RED_LT4, true);
|
||||
XKeyPadAddKeyElem(pGui, pXData, KEYPAD_ID_ENTER, false, 0, 6, 1, 2, GSLC_COL_GREEN, GSLC_COL_GREEN_LT4, true);
|
||||
|
||||
// - Create the "simple" buttons
|
||||
for (int16_t nKeyId = KEYPAD_ID_BASIC_START; nKeyId < (KEYPAD_ID_BASIC_START + XKEYPADNUM_BTN_BASIC); nKeyId++) {
|
||||
nKeyInd = nKeyId - KEYPAD_ID_BASIC_START;
|
||||
nRow = (nKeyInd / 5) + 1;
|
||||
nCol = nKeyInd % 5;
|
||||
XKeyPadAddKeyElem(pGui, pXData, nKeyId, false, nRow, nCol, 1, 1, GSLC_COL_BLUE_LT1, GSLC_COL_BLUE_LT4, true);
|
||||
}
|
||||
|
||||
// - Create the text field
|
||||
XKeyPadAddKeyElem(pGui, pXData, KEYPAD_ID_TXT, true, 0, 0, 1, 6, GSLC_COL_BLACK, GSLC_COL_BLACK, true);
|
||||
}
|
||||
|
||||
// Convert between keypad ID and the index into the keypad label array
|
||||
int16_t XKeyPadLookup_Num(gslc_tsGui* pGui, int16_t nKeyId)
|
||||
{
|
||||
int16_t nKeyInd;
|
||||
|
||||
// Basic button
|
||||
if (nKeyId >= KEYPAD_ID_BASIC_START) {
|
||||
nKeyInd = (nKeyId - KEYPAD_ID_BASIC_START) + KEYPAD_LBL_BASIC_START;
|
||||
} else {
|
||||
// Special button
|
||||
switch (nKeyId) {
|
||||
case KEYPAD_ID_DECIMAL:
|
||||
nKeyInd = KEYPAD_LBL_DECIMAL;
|
||||
break;
|
||||
case KEYPAD_ID_MINUS:
|
||||
nKeyInd = KEYPAD_LBL_MINUS;
|
||||
break;
|
||||
case KEYPAD_ID_BACKSPACE:
|
||||
nKeyInd = KEYPAD_LBL_BACKSPACE;
|
||||
break;
|
||||
case KEYPAD_ID_ESC:
|
||||
nKeyInd = KEYPAD_LBL_ESC;
|
||||
break;
|
||||
case KEYPAD_ID_ENTER:
|
||||
nKeyInd = KEYPAD_LBL_ENTER;
|
||||
break;
|
||||
default:
|
||||
// FIXME: ERROR
|
||||
nKeyInd = -1; // Not expected
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
return nKeyInd;
|
||||
}
|
||||
|
||||
// Create the XKeyPad_Alpha compound element
|
||||
// - Note that this also revises some of the members of the base XKeyPad struct
|
||||
gslc_tsElemRef* gslc_ElemXKeyPadCreate_Num(gslc_tsGui* pGui, int16_t nElemId, int16_t nPage,
|
||||
gslc_tsXKeyPad_Num* pXData, int16_t nX0, int16_t nY0, int8_t nFontId, gslc_tsXKeyPadCfg* pConfig)
|
||||
{
|
||||
gslc_tsXKeyPad* pXDataBase = (gslc_tsXKeyPad*)pXData;
|
||||
pXDataBase->nSubElemMax = XKEYPADNUM_ELEM_MAX;
|
||||
pXDataBase->psElemRef = pXData->asElemRef;
|
||||
pXDataBase->psElem = pXData->asElem;
|
||||
|
||||
// Provide default config if none supplied
|
||||
gslc_tsXKeyPadCfg sConfigTmp;
|
||||
if (pConfig == NULL) {
|
||||
sConfigTmp = gslc_ElemXKeyPadCfgInit_Num();
|
||||
pConfig = &sConfigTmp;
|
||||
}
|
||||
|
||||
return gslc_ElemXKeyPadCreateBase(pGui, nElemId, nPage, pXDataBase, nX0, nY0, nFontId, pConfig,
|
||||
&XKeyPadCreateKeys_Num,&XKeyPadLookup_Num);
|
||||
}
|
||||
|
||||
// Reset the XKeyPad config struct
|
||||
// - This must be called before any XKeyPad config update APIs are called
|
||||
gslc_tsXKeyPadCfg gslc_ElemXKeyPadCfgInit_Num()
|
||||
{
|
||||
gslc_tsXKeyPadCfg sConfig;
|
||||
sConfig.nButtonSzW = 25;
|
||||
sConfig.nButtonSzH = 25;
|
||||
sConfig.bFloatEn = true;
|
||||
sConfig.bSignEn = true;
|
||||
sConfig.bRoundEn = false;
|
||||
sConfig.nFontId = GSLC_FONT_NONE; // Will be overwritten
|
||||
sConfig.pacKeys = KEYPAD_LABEL_STRINGS;
|
||||
sConfig.nMaxCols = 8;
|
||||
sConfig.nMaxRows = 3;
|
||||
sConfig.nFrameMargin = 2;
|
||||
return sConfig;
|
||||
}
|
||||
|
||||
#endif // GSLC_FEATURE_COMPOUND
|
||||
|
||||
// ============================================================================
|
100
src/guislice/XKeyPad_Num.h
Normal file
100
src/guislice/XKeyPad_Num.h
Normal file
|
@ -0,0 +1,100 @@
|
|||
#ifndef _GUISLICE_EX_XKEYPAD_NUM_H_
|
||||
#define _GUISLICE_EX_XKEYPAD_NUM_H_
|
||||
|
||||
#include "GUIslice.h"
|
||||
|
||||
#include "XKeyPad.h"
|
||||
|
||||
// =======================================================================
|
||||
// GUIslice library extension: XKeyPad control (numeric entry)
|
||||
// - Paul Conti, Calvin Hass
|
||||
// - https://www.impulseadventure.com/elec/guislice-gui.html
|
||||
// - https://github.com/ImpulseAdventure/GUIslice
|
||||
// =======================================================================
|
||||
//
|
||||
// The MIT License
|
||||
//
|
||||
// Copyright 2016-2020 Calvin Hass
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
//
|
||||
// =======================================================================
|
||||
/// \file XKeyPad.h
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif // __cplusplus
|
||||
|
||||
#if (GSLC_FEATURE_COMPOUND)
|
||||
|
||||
// Define number of buttons & elements
|
||||
// - Refer to the definitions in the XKeyPad_*.c file
|
||||
#define XKEYPADNUM_BTN_BASIC 10
|
||||
#define XKEYPADNUM_ELEM_MAX (6 + XKEYPADNUM_BTN_BASIC)
|
||||
|
||||
// ============================================================================
|
||||
// Extended Element: KeyPad Character entry
|
||||
// - NOTE: The XKeyPad_Alpha extends the XKeyPad base element
|
||||
// ============================================================================
|
||||
|
||||
typedef struct {
|
||||
// Base XKeyPad struct
|
||||
// - The base type must appear at the top of the derived struct
|
||||
gslc_tsXKeyPad sKeyPad; ///< Base XKeyPad element
|
||||
|
||||
gslc_tsElemRef asElemRef[XKEYPADNUM_ELEM_MAX]; ///< Storage for sub-element references
|
||||
gslc_tsElem asElem[XKEYPADNUM_ELEM_MAX]; ///< Storage for sub-elements
|
||||
} gslc_tsXKeyPad_Num;
|
||||
|
||||
///
|
||||
/// Create a KeyPad Element
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] nElemId: Element ID to assign (0..16383 or GSLC_ID_AUTO to autogen)
|
||||
/// \param[in] nPage: Page ID to attach element to
|
||||
/// \param[in] pXData: Ptr to extended element data structure
|
||||
/// \param[in] nX0: X KeyPad Starting Coordinate
|
||||
/// \param[in] nY0: Y KeyPad Starting Coordinate
|
||||
/// \param[in] nFontId: Font ID to use for drawing the element
|
||||
/// \param[in] pConfig: Ptr to config options
|
||||
///
|
||||
/// \return Pointer to Element or NULL if failure
|
||||
///
|
||||
gslc_tsElemRef* gslc_ElemXKeyPadCreate_Num(gslc_tsGui* pGui, int16_t nElemId, int16_t nPage,
|
||||
gslc_tsXKeyPad_Num* pXData, int16_t nX0, int16_t nY0, int8_t nFontId, gslc_tsXKeyPadCfg* pConfig);
|
||||
|
||||
|
||||
///
|
||||
/// Initialize the KeyPad config structure
|
||||
/// - This routine should be called to initialize the configuration
|
||||
/// data structure before calling any of the KeyPad config APIs
|
||||
///
|
||||
/// \return Initialized KeyPad config structure
|
||||
///
|
||||
gslc_tsXKeyPadCfg gslc_ElemXKeyPadCfgInit_Num();
|
||||
|
||||
// ============================================================================
|
||||
|
||||
#endif // GSLC_FEATURE_COMPOUND
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif // __cplusplus
|
||||
#endif // _GUISLICE_EX_XKEYPAD_NUM_H_
|
||||
|
982
src/guislice/XListbox.c
Normal file
982
src/guislice/XListbox.c
Normal file
|
@ -0,0 +1,982 @@
|
|||
// =======================================================================
|
||||
// GUIslice library (extensions)
|
||||
// - Calvin Hass
|
||||
// - https://www.impulseadventure.com/elec/guislice-gui.html
|
||||
// - https://github.com/ImpulseAdventure/GUIslice
|
||||
// =======================================================================
|
||||
//
|
||||
// The MIT License
|
||||
//
|
||||
// Copyright 2016-2020 Calvin Hass
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
//
|
||||
// =======================================================================
|
||||
/// \file XListbox.c
|
||||
|
||||
|
||||
|
||||
// GUIslice library
|
||||
#include "GUIslice.h"
|
||||
#include "GUIslice_drv.h"
|
||||
|
||||
#include "XListbox.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#if (GSLC_USE_PROGMEM)
|
||||
#include <avr/pgmspace.h>
|
||||
#endif
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Error Messages
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
extern const char GSLC_PMEM ERRSTR_NULL[];
|
||||
extern const char GSLC_PMEM ERRSTR_PXD_NULL[];
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Extended element definitions
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// - This file extends the core GUIslice functionality with
|
||||
// additional widget types
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
// TODO: Combine with GUIslice MAX_STR
|
||||
// Defines the maximum length of a listbox item
|
||||
#define XLISTBOX_MAX_STR 20
|
||||
|
||||
// ============================================================================
|
||||
// Extended Element: Listbox
|
||||
// - A Listbox control
|
||||
// ============================================================================
|
||||
|
||||
|
||||
// Basic debug functionality
|
||||
/*
|
||||
void debug_ElemXListboxDump(gslc_tsGui* pGui, gslc_tsElemRef* pElemRef)
|
||||
{
|
||||
gslc_tsElem* pElem = gslc_GetElemFromRef(pGui, pElemRef);
|
||||
gslc_tsXListbox* pListbox = (gslc_tsXListbox*)(pElem->pXData);
|
||||
|
||||
// Prevent runaway looping due to damaged buffer
|
||||
// Don't ask why I know to do this - PaulC
|
||||
|
||||
int16_t nSafety=0;
|
||||
char acTxt[50 + 1];
|
||||
GSLC_DEBUG2_PRINT("Xlistbox:Dump (nBufPos=%d nItemCnt=%d)\n", pListbox->nBufItemsPos,pListbox->nItemCnt);
|
||||
for (unsigned nInd = 0; nInd < pListbox->nBufItemsPos; nInd++) {
|
||||
nSafety++;
|
||||
if (nSafety > pListbox->nBufItemsMax) break;
|
||||
char ch = pListbox->pBufItems[nInd];
|
||||
if (ch == 0) {
|
||||
snprintf(acTxt, 40,"0x%04x: [%2u] = %02X = [NULL]", (char*)&pListbox->pBufItems[nInd],nInd, ch);
|
||||
}
|
||||
else {
|
||||
snprintf(acTxt, 40,"0x%04x: [%2u] = %02X = [%c]", (char*)&pListbox->pBufItems[nInd],nInd, ch, ch);
|
||||
}
|
||||
GSLC_DEBUG2_PRINT("XListbox:Dump: %s\n", acTxt);
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
char* gslc_ElemXListboxGetItemAddr(gslc_tsXListbox* pListbox, int16_t nItemCurSel)
|
||||
{
|
||||
char* pBuf = NULL;
|
||||
uint16_t nBufPos = 0;
|
||||
uint16_t nItemInd = 0;
|
||||
bool bFound = false;
|
||||
while (1) {
|
||||
if (nItemInd == nItemCurSel) {
|
||||
bFound = true;
|
||||
break;
|
||||
}
|
||||
if (nBufPos >= pListbox->nBufItemsMax) {
|
||||
break;
|
||||
}
|
||||
if (pListbox->pBufItems[nBufPos] == 0) {
|
||||
nItemInd++;
|
||||
}
|
||||
nBufPos++;
|
||||
}
|
||||
if (bFound) {
|
||||
pBuf = (char*)&(pListbox->pBufItems[nBufPos]);
|
||||
return pBuf;
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
// Recalculate listbox item sizing if enabled
|
||||
bool gslc_ElemXListboxRecalcSize(gslc_tsXListbox* pListbox,gslc_tsRect rElem)
|
||||
{
|
||||
int16_t nElem;
|
||||
int16_t nElemInner;
|
||||
int16_t nItemOuter;
|
||||
int16_t nItemWOld;
|
||||
bool bNeedRedraw = false;
|
||||
|
||||
// If number of rows was auto-sized based on content, then calculate now
|
||||
if (pListbox->nRows == XLISTBOX_SIZE_AUTO) {
|
||||
if (pListbox->nItemCnt == 0) {
|
||||
pListbox->nRows = 1; // Force at least one row
|
||||
} else {
|
||||
pListbox->nRows = ((pListbox->nItemCnt + 1) / pListbox->nCols);
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE: In the nElemInner calculation, we add nItemGap to account
|
||||
// for the fact that the last column does not include a "gap" after it.
|
||||
if (pListbox->bItemAutoSizeW) {
|
||||
nItemWOld = pListbox->nItemW;
|
||||
nElem = rElem.w;
|
||||
nElemInner = nElem - (2 * pListbox->nMarginW) + pListbox->nItemGap;
|
||||
nItemOuter = nElemInner / pListbox->nCols;
|
||||
pListbox->nItemW = nItemOuter - pListbox->nItemGap;
|
||||
if (pListbox->nItemW != nItemWOld) {
|
||||
bNeedRedraw = true;
|
||||
}
|
||||
}
|
||||
if (pListbox->bItemAutoSizeH) {
|
||||
nItemWOld = pListbox->nItemH;
|
||||
nElem = rElem.h;
|
||||
nElemInner = nElem - (2 * pListbox->nMarginH) + pListbox->nItemGap;
|
||||
nItemOuter = nElemInner / pListbox->nRows;
|
||||
pListbox->nItemH = nItemOuter - pListbox->nItemGap;
|
||||
if (pListbox->nItemH != nItemWOld) {
|
||||
bNeedRedraw = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Clear Need Recalc flag
|
||||
pListbox->bNeedRecalc = false;
|
||||
|
||||
return bNeedRedraw;
|
||||
}
|
||||
|
||||
void gslc_ElemXListboxSetSize(gslc_tsGui* pGui, gslc_tsElemRef* pElemRef, int8_t nRows, int8_t nCols)
|
||||
{
|
||||
gslc_tsXListbox* pListbox = (gslc_tsXListbox*)gslc_GetXDataFromRef(pGui, pElemRef, GSLC_TYPEX_LISTBOX, __LINE__);
|
||||
if (!pListbox) return;
|
||||
|
||||
pListbox->nRows = nRows;
|
||||
pListbox->nCols = nCols;
|
||||
pListbox->bNeedRecalc = true;
|
||||
// Mark as needing full redraw
|
||||
gslc_ElemSetRedraw(pGui, pElemRef, GSLC_REDRAW_FULL);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void gslc_ElemXListboxSetMargin(gslc_tsGui* pGui, gslc_tsElemRef* pElemRef, int8_t nMarginW, int8_t nMarginH)
|
||||
{
|
||||
gslc_tsXListbox* pListbox = (gslc_tsXListbox*)gslc_GetXDataFromRef(pGui, pElemRef, GSLC_TYPEX_LISTBOX, __LINE__);
|
||||
if (!pListbox) return;
|
||||
|
||||
pListbox->nMarginW = nMarginW;
|
||||
pListbox->nMarginH = nMarginH;
|
||||
pListbox->bNeedRecalc = true;
|
||||
// Mark as needing full redraw
|
||||
gslc_ElemSetRedraw(pGui, pElemRef, GSLC_REDRAW_FULL);
|
||||
}
|
||||
|
||||
|
||||
void gslc_ElemXListboxItemsSetSize(gslc_tsGui* pGui, gslc_tsElemRef* pElemRef, int16_t nItemW, int16_t nItemH)
|
||||
{
|
||||
gslc_tsXListbox* pListbox = (gslc_tsXListbox*)gslc_GetXDataFromRef(pGui, pElemRef, GSLC_TYPEX_LISTBOX, __LINE__);
|
||||
if (!pListbox) return;
|
||||
|
||||
pListbox->nItemW = nItemW;
|
||||
pListbox->nItemH = nItemH;
|
||||
// Determine if auto-sizing requested
|
||||
pListbox->bItemAutoSizeW = (nItemW == XLISTBOX_SIZE_AUTO) ? true : false;
|
||||
pListbox->bItemAutoSizeH = (nItemH == XLISTBOX_SIZE_AUTO) ? true : false;
|
||||
|
||||
pListbox->bNeedRecalc = true;
|
||||
// Mark as needing full redraw
|
||||
gslc_ElemSetRedraw(pGui, pElemRef, GSLC_REDRAW_FULL);
|
||||
}
|
||||
|
||||
void gslc_ElemXListboxItemsSetGap(gslc_tsGui* pGui, gslc_tsElemRef* pElemRef, int8_t nGap, gslc_tsColor colGap)
|
||||
{
|
||||
gslc_tsXListbox* pListbox = (gslc_tsXListbox*)gslc_GetXDataFromRef(pGui, pElemRef, GSLC_TYPEX_LISTBOX, __LINE__);
|
||||
if (!pListbox) return;
|
||||
|
||||
pListbox->nItemGap = nGap;
|
||||
pListbox->colGap = colGap;
|
||||
pListbox->bNeedRecalc = true;
|
||||
// Mark as needing full redraw
|
||||
gslc_ElemSetRedraw(pGui, pElemRef, GSLC_REDRAW_FULL);
|
||||
}
|
||||
|
||||
|
||||
void gslc_ElemXListboxReset(gslc_tsGui* pGui, gslc_tsElemRef* pElemRef)
|
||||
{
|
||||
gslc_tsXListbox* pListbox = (gslc_tsXListbox*)gslc_GetXDataFromRef(pGui, pElemRef, GSLC_TYPEX_LISTBOX, __LINE__);
|
||||
if (!pListbox) return;
|
||||
|
||||
pListbox->nBufItemsPos = 0;
|
||||
pListbox->nItemCnt = 0;
|
||||
pListbox->nItemCurSel = XLISTBOX_SEL_NONE;
|
||||
pListbox->bNeedRecalc = true;
|
||||
// Mark as needing full redraw
|
||||
gslc_ElemSetRedraw(pGui, pElemRef, GSLC_REDRAW_FULL);
|
||||
}
|
||||
|
||||
|
||||
bool gslc_ElemXListboxAddItem(gslc_tsGui* pGui, gslc_tsElemRef* pElemRef, const char* pStrItem)
|
||||
{
|
||||
gslc_tsXListbox* pListbox = (gslc_tsXListbox*)gslc_GetXDataFromRef(pGui, pElemRef, GSLC_TYPEX_LISTBOX, __LINE__);
|
||||
if (!pListbox) return false;
|
||||
|
||||
int8_t nStrItemLen;
|
||||
char* pBuf = NULL;
|
||||
uint16_t nBufItemsPos = pListbox->nBufItemsPos;
|
||||
uint16_t nBufItemsMax = pListbox->nBufItemsMax;
|
||||
|
||||
nStrItemLen = strlen(pStrItem);
|
||||
|
||||
if (nStrItemLen == 0) {
|
||||
// Nothing to add
|
||||
return false;
|
||||
}
|
||||
|
||||
// Ensure we won't overrun the buffer, including the terminator
|
||||
if (nBufItemsPos + nStrItemLen + 1 > nBufItemsMax) {
|
||||
// Proceed with truncation
|
||||
nStrItemLen = nBufItemsMax - pListbox->nBufItemsPos - 1;
|
||||
GSLC_DEBUG2_PRINT("ERROR: ElemXListboxAddItem() buffer too small\n", "");
|
||||
}
|
||||
|
||||
// If the truncation left nothing to add, skip out now
|
||||
if (nStrItemLen <= 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Treat this section of the buffer as [char]
|
||||
pBuf = (char*)pListbox->pBufItems + nBufItemsPos;
|
||||
strncpy(pBuf, pStrItem, nStrItemLen);
|
||||
pListbox->nBufItemsPos += nStrItemLen;
|
||||
|
||||
// Ensure terminator added
|
||||
pBuf += nStrItemLen;
|
||||
*pBuf = 0;
|
||||
pListbox->nBufItemsPos++;
|
||||
|
||||
pListbox->nItemCnt++;
|
||||
|
||||
//GSLC_DEBUG2_PRINT("Xlistbox:Add\n", "");
|
||||
//debug_ElemXListboxDump(pGui, pElemRef);
|
||||
|
||||
// Inidicate sizing may need update
|
||||
pListbox->bNeedRecalc = true;
|
||||
|
||||
// Mark as needing full redraw
|
||||
gslc_ElemSetRedraw(pGui, pElemRef, GSLC_REDRAW_FULL);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool gslc_ElemXListboxInsertItemAt(gslc_tsGui* pGui, gslc_tsElemRef* pElemRef, uint16_t nInsertPos,
|
||||
const char* pStrItem)
|
||||
{
|
||||
gslc_tsXListbox* pListbox = (gslc_tsXListbox*)gslc_GetXDataFromRef(pGui, pElemRef, GSLC_TYPEX_LISTBOX, __LINE__);
|
||||
if (!pListbox) return false;
|
||||
|
||||
int8_t nStrItemLen;
|
||||
char* pBuf = NULL;
|
||||
uint16_t nBufItemsPos = pListbox->nBufItemsPos;
|
||||
uint16_t nBufItemsMax = pListbox->nBufItemsMax;
|
||||
|
||||
if (nInsertPos > pListbox->nItemCnt) {
|
||||
GSLC_DEBUG2_PRINT("ERROR: ElemXListboxInsertItemAt() Current Count: %d Invalid Position %d\n",
|
||||
pListbox->nItemCnt,nInsertPos);
|
||||
return false;
|
||||
}
|
||||
nStrItemLen = strlen(pStrItem);
|
||||
|
||||
if (nStrItemLen == 0) {
|
||||
// Nothing to add
|
||||
return false;
|
||||
}
|
||||
|
||||
// Ensure we won't overrun the buffer, including the terminator
|
||||
if (nBufItemsPos + nStrItemLen + 1 > nBufItemsMax) {
|
||||
GSLC_DEBUG2_PRINT("ERROR: ElemXListboxInsertItemAt() buffer too small\n", "");
|
||||
return false;
|
||||
}
|
||||
|
||||
// If the truncation left nothing to add, skip out now
|
||||
if (nStrItemLen <= 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// GSLC_DEBUG2_PRINT("Xlistbox:InsertAt: %d\n", nInsertPos);
|
||||
// debug_ElemXListboxDump(pGui, pElemRef);
|
||||
|
||||
pBuf = gslc_ElemXListboxGetItemAddr(pListbox, nInsertPos);
|
||||
// If position is incorrect, bail out...
|
||||
if (pBuf == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Make a hole in the buffer to slot in the new item
|
||||
char* pSrc = (char*)pListbox->pBufItems+nBufItemsPos-1;
|
||||
char* pDest = pSrc+nStrItemLen+1;
|
||||
int16_t nMoveLen = (int16_t)(pSrc - pBuf)+1;
|
||||
uint8_t ch;
|
||||
for (uint16_t nInd = 0; nInd < nMoveLen; nInd++) {
|
||||
ch = *pSrc;
|
||||
*pDest = ch;
|
||||
pDest--;
|
||||
pSrc--;
|
||||
}
|
||||
|
||||
// Now slot in the new item
|
||||
memcpy(pBuf, pStrItem, nStrItemLen+1);
|
||||
|
||||
// update our buffer information
|
||||
pListbox->nBufItemsPos += nStrItemLen+1;
|
||||
pListbox->nItemCnt++;
|
||||
|
||||
// GSLC_DEBUG2_PRINT("Xlistbox:After InsertAt %d\n", nInsertPos);
|
||||
// debug_ElemXListboxDump(pGui, pElemRef);
|
||||
|
||||
// Indicate sizing may need update
|
||||
pListbox->bNeedRecalc = true;
|
||||
|
||||
// Mark as needing full redraw
|
||||
gslc_ElemSetRedraw(pGui, pElemRef, GSLC_REDRAW_FULL);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool gslc_ElemXListboxDeleteItemAt(gslc_tsGui* pGui, gslc_tsElemRef* pElemRef, uint16_t nDeletePos)
|
||||
{
|
||||
gslc_tsXListbox* pListbox = (gslc_tsXListbox*)gslc_GetXDataFromRef(pGui, pElemRef, GSLC_TYPEX_LISTBOX, __LINE__);
|
||||
if (!pListbox) return false;
|
||||
|
||||
int8_t nStrItemLen;
|
||||
char* pBuf = NULL;
|
||||
uint16_t nBufItemsPos = pListbox->nBufItemsPos;
|
||||
|
||||
// GSLC_DEBUG2_PRINT("Xlistbox:DeleteAt: %d\n", nDeletePos);
|
||||
// debug_ElemXListboxDump(pGui, pElemRef);
|
||||
|
||||
pBuf = gslc_ElemXListboxGetItemAddr(pListbox, nDeletePos);
|
||||
// If position is incorrect, bail out...
|
||||
if (pBuf == NULL) {
|
||||
return false;
|
||||
}
|
||||
nStrItemLen = strlen(pBuf);
|
||||
|
||||
// Pull items after this delete position up to delete this item
|
||||
char* pSrc = (char*)pBuf+nStrItemLen+1;
|
||||
char* pDest = (char*)pBuf;
|
||||
char* pEndOfBuf = (char*)(pListbox->pBufItems+nBufItemsPos);
|
||||
int16_t nMoveLen = (int16_t)(pEndOfBuf-pSrc)+1;
|
||||
uint8_t ch;
|
||||
if (nMoveLen > 1) {
|
||||
for (uint16_t nInd = 0; nInd < nMoveLen; nInd++) {
|
||||
ch = *pSrc;
|
||||
*pDest = ch;
|
||||
pDest++;
|
||||
pSrc++;
|
||||
}
|
||||
}
|
||||
|
||||
// update our buffer information
|
||||
pListbox->nBufItemsPos -= nStrItemLen+1;
|
||||
pListbox->nItemCnt--;
|
||||
|
||||
// unselect item
|
||||
gslc_ElemXListboxSetSel(pGui, pElemRef, XLISTBOX_SEL_NONE);
|
||||
|
||||
// GSLC_DEBUG2_PRINT("Xlistbox:After DeleteAt %d\n", nDeletePos);
|
||||
// debug_ElemXListboxDump(pGui, pElemRef);
|
||||
|
||||
// Indicate sizing may need update
|
||||
pListbox->bNeedRecalc = true;
|
||||
|
||||
// Mark as needing full redraw
|
||||
gslc_ElemSetRedraw(pGui, pElemRef, GSLC_REDRAW_FULL);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool gslc_ElemXListboxGetItem(gslc_tsGui* pGui, gslc_tsElemRef* pElemRef, int16_t nItemCurSel, char* pStrItem,
|
||||
uint8_t nStrItemLen)
|
||||
{
|
||||
gslc_tsXListbox* pListbox = (gslc_tsXListbox*)gslc_GetXDataFromRef(pGui, pElemRef, GSLC_TYPEX_LISTBOX, __LINE__);
|
||||
if (!pListbox) return false;
|
||||
|
||||
// Ensure user provided valid string
|
||||
if ((pStrItem == NULL) || (nStrItemLen == 0)) {
|
||||
// ERROR
|
||||
return false;
|
||||
}
|
||||
uint16_t nBufPos = 0;
|
||||
uint16_t nItemInd = 0;
|
||||
uint8_t* pBuf = NULL;
|
||||
bool bFound = false;
|
||||
while (1) {
|
||||
if (nItemInd == nItemCurSel) {
|
||||
bFound = true;
|
||||
break;
|
||||
}
|
||||
if (nBufPos >= pListbox->nBufItemsMax) {
|
||||
break;
|
||||
}
|
||||
if (pListbox->pBufItems[nBufPos] == 0) {
|
||||
nItemInd++;
|
||||
}
|
||||
nBufPos++;
|
||||
}
|
||||
if (bFound) {
|
||||
pBuf = &(pListbox->pBufItems[nBufPos]);
|
||||
strncpy(pStrItem, (char*)pBuf, nStrItemLen);
|
||||
// Ensure null terminated in case the buffer
|
||||
// was smaller than the item source
|
||||
pStrItem[nStrItemLen - 1] = 0;
|
||||
return true;
|
||||
} else {
|
||||
// If no item was found, return an empty string (NULL)
|
||||
pStrItem[0] = 0;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int16_t gslc_ElemXListboxGetItemCnt(gslc_tsGui* pGui, gslc_tsElemRef* pElemRef)
|
||||
{
|
||||
gslc_tsXListbox* pListbox = (gslc_tsXListbox*)gslc_GetXDataFromRef(pGui, pElemRef, GSLC_TYPEX_LISTBOX, __LINE__);
|
||||
if (!pListbox) return 0;
|
||||
|
||||
return pListbox->nItemCnt;
|
||||
}
|
||||
|
||||
|
||||
// Create a Listbox element and add it to the GUI element list
|
||||
// - Defines default styling for the element
|
||||
// - Defines callback for redraw and touch
|
||||
gslc_tsElemRef* gslc_ElemXListboxCreate(gslc_tsGui* pGui,int16_t nElemId,int16_t nPage,
|
||||
gslc_tsXListbox* pXData,gslc_tsRect rElem,int16_t nFontId,uint8_t* pBufItems,uint16_t nBufItemsMax,int16_t nItemDefault)
|
||||
{
|
||||
if ((pGui == NULL) || (pXData == NULL)) {
|
||||
static const char GSLC_PMEM FUNCSTR[] = "ElemXListboxCreate";
|
||||
GSLC_DEBUG2_PRINT_CONST(ERRSTR_NULL,FUNCSTR);
|
||||
return NULL;
|
||||
}
|
||||
gslc_tsElem sElem;
|
||||
gslc_tsElemRef* pElemRef = NULL;
|
||||
sElem = gslc_ElemCreate(pGui,nElemId,nPage,GSLC_TYPEX_LISTBOX,rElem,NULL,0,nFontId);
|
||||
sElem.nFeatures &= ~GSLC_ELEM_FEA_FRAME_EN;
|
||||
sElem.nFeatures |= GSLC_ELEM_FEA_FILL_EN;
|
||||
sElem.nFeatures |= GSLC_ELEM_FEA_CLICK_EN;
|
||||
sElem.nFeatures |= GSLC_ELEM_FEA_GLOW_EN;
|
||||
|
||||
sElem.nGroup = GSLC_GROUP_ID_NONE;
|
||||
pXData->pBufItems = pBufItems;
|
||||
pXData->nBufItemsMax = nBufItemsMax;
|
||||
pXData->nBufItemsPos = 0;
|
||||
pXData->nItemCnt = 0;
|
||||
pXData->nItemCurSel = nItemDefault;
|
||||
pXData->nItemCurSelLast = XLISTBOX_SEL_NONE;
|
||||
pXData->nItemSavedSel = XLISTBOX_SEL_NONE;
|
||||
pXData->nItemTop = 0;
|
||||
pXData->pfuncXSel = NULL;
|
||||
pXData->nCols = 1;
|
||||
pXData->nRows = XLISTBOX_SIZE_AUTO; // Auto-calculated from content
|
||||
pXData->bNeedRecalc = true; // Force auto-sizing
|
||||
pXData->nMarginW = 5;
|
||||
pXData->nMarginH = 5;
|
||||
pXData->bItemAutoSizeW = true; // Force auto-sizing
|
||||
pXData->bItemAutoSizeH = false;
|
||||
pXData->nItemW = XLISTBOX_SIZE_AUTO; // Auto-sized
|
||||
pXData->nItemH = 30;
|
||||
pXData->nItemGap = 2;
|
||||
pXData->colGap = GSLC_COL_BLACK;
|
||||
pXData->nItemCurSelLast = XLISTBOX_SEL_NONE;
|
||||
sElem.pXData = (void*)(pXData);
|
||||
// Specify the custom drawing callback
|
||||
sElem.pfuncXDraw = &gslc_ElemXListboxDraw;
|
||||
// Specify the custom touch tracking callback
|
||||
sElem.pfuncXTouch = &gslc_ElemXListboxTouch;
|
||||
|
||||
sElem.colElemFill = GSLC_COL_BLACK;
|
||||
sElem.colElemFillGlow = GSLC_COL_BLACK;
|
||||
sElem.colElemFrame = GSLC_COL_GRAY;
|
||||
sElem.colElemFrameGlow = GSLC_COL_WHITE;
|
||||
|
||||
// Set default text alignment:
|
||||
// - Vertical center, left justify
|
||||
sElem.eTxtAlign = GSLC_ALIGN_MID_LEFT;
|
||||
|
||||
if (nPage != GSLC_PAGE_NONE) {
|
||||
pElemRef = gslc_ElemAdd(pGui,nPage,&sElem,GSLC_ELEMREF_DEFAULT);
|
||||
return pElemRef;
|
||||
#if (GSLC_FEATURE_COMPOUND)
|
||||
} else {
|
||||
// Save as temporary element
|
||||
pGui->sElemTmp = sElem;
|
||||
pGui->sElemRefTmp.pElem = &(pGui->sElemTmp);
|
||||
pGui->sElemRefTmp.eElemFlags = GSLC_ELEMREF_DEFAULT | GSLC_ELEMREF_REDRAW_FULL;
|
||||
return &(pGui->sElemRefTmp);
|
||||
#endif
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
// Redraw the Listbox
|
||||
// - Note that this redraw is for the entire element rect region
|
||||
// - The Draw function parameters use void pointers to allow for
|
||||
// simpler callback function definition & scalability.
|
||||
bool gslc_ElemXListboxDraw(void* pvGui,void* pvElemRef,gslc_teRedrawType eRedraw)
|
||||
{
|
||||
// Typecast the parameters to match the GUI and element types
|
||||
gslc_tsGui* pGui = (gslc_tsGui*)(pvGui);
|
||||
gslc_tsElemRef* pElemRef = (gslc_tsElemRef*)(pvElemRef);
|
||||
|
||||
gslc_tsXListbox* pListbox = (gslc_tsXListbox*)gslc_GetXDataFromRef(pGui, pElemRef, GSLC_TYPEX_LISTBOX, __LINE__);
|
||||
if (!pListbox) return false;
|
||||
|
||||
gslc_tsElem* pElem = gslc_GetElemFromRef(pGui,pElemRef);
|
||||
|
||||
//bool bGlow = (pElem->nFeatures & GSLC_ELEM_FEA_GLOW_EN) && gslc_ElemGetGlow(pGui,pElemRef);
|
||||
int8_t nItemCurSel = pListbox->nItemCurSel;
|
||||
|
||||
|
||||
gslc_tsRect rElemRect;
|
||||
if (pElem->nFeatures & GSLC_ELEM_FEA_FRAME_EN) {
|
||||
rElemRect = gslc_ExpandRect(pElem->rElem, -1, -1);
|
||||
if (eRedraw == GSLC_REDRAW_FULL) {
|
||||
gslc_DrawFrameRect(pGui, pElem->rElem, pElem->colElemFrame);
|
||||
}
|
||||
} else {
|
||||
rElemRect = pElem->rElem;
|
||||
}
|
||||
|
||||
// If full redraw and gap is enabled:
|
||||
// - Clear background with gap color, as list items
|
||||
// will be overdrawn in colBg color
|
||||
if (eRedraw == GSLC_REDRAW_FULL) {
|
||||
if (pListbox->nItemGap > 0) {
|
||||
gslc_DrawFillRect(pGui, rElemRect, pListbox->colGap);
|
||||
}
|
||||
}
|
||||
|
||||
// Determine if we need to recalculate the item sizing
|
||||
if (pListbox->bNeedRecalc) {
|
||||
gslc_ElemXListboxRecalcSize(pListbox, rElemRect);
|
||||
}
|
||||
|
||||
int16_t nX0, nY0;
|
||||
nX0 = rElemRect.x;
|
||||
nY0 = rElemRect.y;
|
||||
|
||||
int8_t nRows = pListbox->nRows;
|
||||
int8_t nCols = pListbox->nCols;
|
||||
gslc_tsRect rItemRect;
|
||||
int16_t nItemBaseX, nItemBaseY;
|
||||
int16_t nItemX, nItemY;
|
||||
int16_t nItemW, nItemH;
|
||||
bool bItemSel;
|
||||
gslc_tsColor colFill, colTxt;
|
||||
|
||||
// Error check
|
||||
if (nCols == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Determine top-left coordinate of list matrix
|
||||
nItemBaseX = nX0 + pListbox->nMarginW;
|
||||
nItemBaseY = nY0 + pListbox->nMarginH;
|
||||
char acStr[XLISTBOX_MAX_STR+1] = "";
|
||||
|
||||
|
||||
// Loop through the items in the list
|
||||
int8_t nItemTop = pListbox->nItemTop;
|
||||
int8_t nItemCnt = pListbox->nItemCnt;
|
||||
int8_t nItemInd;
|
||||
|
||||
// Note that nItemTop is always pointing to an
|
||||
// item index at the start of a row
|
||||
|
||||
// Determine the list indices to display in the visible window due to scrolling
|
||||
int8_t nDispIndMax = (nRows * nCols);
|
||||
|
||||
for (int8_t nDispInd = 0; nDispInd < nDispIndMax; nDispInd++) {
|
||||
|
||||
// Calculate the item index based on the display index
|
||||
nItemInd = nItemTop + nDispInd;
|
||||
|
||||
// Did we go past the end of our list?
|
||||
if (nItemInd >= nItemCnt) {
|
||||
break;
|
||||
}
|
||||
|
||||
// Fetch the list item
|
||||
bool bOk = gslc_ElemXListboxGetItem(pGui, pElemRef, nItemInd, acStr, XLISTBOX_MAX_STR);
|
||||
if (!bOk) {
|
||||
// TODO: Erorr handling
|
||||
break;
|
||||
}
|
||||
|
||||
int8_t nItemIndX, nItemIndY;
|
||||
int16_t nItemOuterW, nItemOuterH;
|
||||
|
||||
// Convert linear count into row & column
|
||||
nItemIndY = nDispInd / nCols; // Round down
|
||||
nItemIndX = nDispInd % nCols;
|
||||
|
||||
// Calculate total spacing between items (including gap)
|
||||
nItemOuterW = pListbox->nItemW + pListbox->nItemGap;
|
||||
nItemOuterH = pListbox->nItemH + pListbox->nItemGap;
|
||||
|
||||
// Determine top-left corner of each item
|
||||
nItemW = pListbox->nItemW;
|
||||
nItemH = pListbox->nItemH;
|
||||
nItemY = nItemBaseY + (nItemIndY * nItemOuterH);
|
||||
nItemX = nItemBaseX + (nItemIndX * nItemOuterW);
|
||||
|
||||
// Create rect for item
|
||||
rItemRect = (gslc_tsRect) { nItemX, nItemY, nItemW, nItemH };
|
||||
|
||||
// Is the item selected?
|
||||
bItemSel = (nItemInd == nItemCurSel) ? true : false;
|
||||
|
||||
// Determine the color based on state
|
||||
colFill = (bItemSel) ? pElem->colElemFillGlow : pElem->colElemFill;
|
||||
colTxt = (bItemSel) ? pElem->colElemTextGlow : pElem->colElemText;
|
||||
|
||||
bool bDoRedraw = false;
|
||||
if (eRedraw == GSLC_REDRAW_FULL) {
|
||||
bDoRedraw = true;
|
||||
} else if (eRedraw == GSLC_REDRAW_INC) {
|
||||
// Redraw both the old selected item (ie. to unselect it)
|
||||
// and the current selected item (ie. to select it)
|
||||
if (nItemInd == pListbox->nItemCurSelLast) {
|
||||
bDoRedraw = true;
|
||||
} else if (nItemInd == nItemCurSel) {
|
||||
bDoRedraw = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Draw the list item
|
||||
if (bDoRedraw) {
|
||||
gslc_DrawFillRect(pGui, rItemRect, colFill);
|
||||
|
||||
// Set the text flags to indicate that the user has separately
|
||||
// allocated memory for the text strings.
|
||||
gslc_teTxtFlags eTxtFlags = GSLC_TXT_MEM_RAM | GSLC_TXT_ALLOC_EXT;
|
||||
|
||||
// Draw the aligned text string (by default it is GSLC_ALIGN_MID_LEFT)
|
||||
gslc_DrawTxtBase(pGui, acStr, rItemRect, pElem->pTxtFont, eTxtFlags,
|
||||
pElem->eTxtAlign, colTxt, colFill, pElem->nTxtMarginX, pElem->nTxtMarginY);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Save the last selected item during redraw
|
||||
pListbox->nItemCurSelLast = nItemCurSel;
|
||||
|
||||
// Clear the redraw flag
|
||||
gslc_ElemSetRedraw(pGui,pElemRef,GSLC_REDRAW_NONE);
|
||||
|
||||
// Mark page as needing flip
|
||||
gslc_PageFlipSet(pGui,true);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool gslc_ElemXListboxTouch(void* pvGui, void* pvElemRef, gslc_teTouch eTouch, int16_t nRelX, int16_t nRelY)
|
||||
{
|
||||
#if defined(DRV_TOUCH_NONE)
|
||||
return false;
|
||||
#else
|
||||
gslc_tsGui* pGui = NULL;
|
||||
gslc_tsElemRef* pElemRef = NULL;
|
||||
|
||||
// Typecast the parameters to match the GUI
|
||||
pGui = (gslc_tsGui*)(pvGui);
|
||||
pElemRef = (gslc_tsElemRef*)(pvElemRef);
|
||||
|
||||
gslc_tsXListbox* pListbox = (gslc_tsXListbox*)gslc_GetXDataFromRef(pGui, pElemRef, GSLC_TYPEX_LISTBOX, __LINE__);
|
||||
if (!pListbox) return false;
|
||||
|
||||
//bool bGlowingOld = gslc_ElemGetGlow(pGui, pElemRef);
|
||||
bool bIndexed = false;
|
||||
|
||||
int16_t nItemSavedSel = pListbox->nItemSavedSel;
|
||||
int16_t nItemCurSelOld = pListbox->nItemCurSel;
|
||||
int16_t nItemCurSel = XLISTBOX_SEL_NONE;
|
||||
bool bSelTrack = false;
|
||||
bool bSelSave = false;
|
||||
bool bSelInItem = true;
|
||||
|
||||
switch (eTouch) {
|
||||
|
||||
case GSLC_TOUCH_DOWN_IN:
|
||||
// Start glowing as must be over it
|
||||
gslc_ElemSetGlow(pGui, pElemRef, true);
|
||||
// User pressed inside elem: start selection
|
||||
bSelTrack = true;
|
||||
break;
|
||||
|
||||
case GSLC_TOUCH_MOVE_IN:
|
||||
gslc_ElemSetGlow(pGui, pElemRef, true);
|
||||
// Track changes in selection
|
||||
bSelTrack = true;
|
||||
break;
|
||||
case GSLC_TOUCH_MOVE_OUT:
|
||||
gslc_ElemSetGlow(pGui, pElemRef, false);
|
||||
// User has dragged to outside elem: deselect
|
||||
bSelTrack = true;
|
||||
break;
|
||||
|
||||
case GSLC_TOUCH_UP_IN:
|
||||
// End glow
|
||||
gslc_ElemSetGlow(pGui, pElemRef, false);
|
||||
// User released inside elem.
|
||||
// Save selection.
|
||||
// If selection is same as previous: toggle it
|
||||
bSelTrack = true;
|
||||
bSelSave = true;
|
||||
break;
|
||||
case GSLC_TOUCH_UP_OUT:
|
||||
// End glow
|
||||
gslc_ElemSetGlow(pGui, pElemRef, false);
|
||||
// User released outside elem: leave selection as-is
|
||||
bSelTrack = true;
|
||||
bSelSave = true; // Save SEL_NONE
|
||||
break;
|
||||
|
||||
case GSLC_TOUCH_SET_REL:
|
||||
case GSLC_TOUCH_SET_ABS:
|
||||
bIndexed = true;
|
||||
gslc_ElemSetGlow(pGui,pElemRef,true);
|
||||
// Keyboard / pin control
|
||||
bSelTrack = true;
|
||||
bSelSave = true;
|
||||
break;
|
||||
|
||||
default:
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
|
||||
uint8_t nCols = pListbox->nCols;
|
||||
uint8_t nRows = pListbox->nRows;
|
||||
|
||||
// If we need to update the Listbox selection, calculate the value
|
||||
// and perform the update
|
||||
if (bSelTrack) {
|
||||
|
||||
if (bIndexed) {
|
||||
// The selection is changed by direct control (eg. keyboard)
|
||||
// instead of touch coordinates
|
||||
|
||||
|
||||
// FIXME: Change the following to be either absolute or relative
|
||||
// value assignment instead of inc/dec. Then the user code can
|
||||
// define what the magnitude and direction should be.
|
||||
|
||||
if (eTouch == GSLC_TOUCH_SET_REL) {
|
||||
// Overload the "nRelY" parameter as an increment value
|
||||
nItemCurSel = nItemCurSelOld + nRelY;
|
||||
}
|
||||
else if (eTouch == GSLC_TOUCH_SET_ABS) {
|
||||
// Overload the "nRelY" parameter as an absolute value
|
||||
nItemCurSel = nRelY;
|
||||
}
|
||||
gslc_ElemXListboxSetSel(pGui, pElemRef, nItemCurSel);
|
||||
}
|
||||
else {
|
||||
// Determine which item we are tracking
|
||||
int16_t nItemOuterW, nItemOuterH;
|
||||
int16_t nDispR, nDispC;
|
||||
int16_t nItemR, nItemC;
|
||||
|
||||
// Get position relative to top-left list matrix cell
|
||||
nRelX -= pListbox->nMarginW;
|
||||
nRelY -= pListbox->nMarginH;
|
||||
|
||||
// Determine spacing between matrix cells
|
||||
nItemOuterW = pListbox->nItemW + pListbox->nItemGap;
|
||||
nItemOuterH = pListbox->nItemH + pListbox->nItemGap;
|
||||
|
||||
// Determine which matrix cell we are in
|
||||
nDispC = nRelX / nItemOuterW;
|
||||
nDispR = nRelY / nItemOuterH;
|
||||
|
||||
if ((nRelX < 0) || (nRelY < 0)) {
|
||||
bSelInItem = false;
|
||||
}
|
||||
|
||||
// Determine if the selection was inside the range of displayed items
|
||||
if ((nDispR < 0) || (nDispR >= nRows) || (nDispC < 0) || (nDispC >= nCols)) {
|
||||
bSelInItem = false;
|
||||
}
|
||||
if (bSelInItem) {
|
||||
|
||||
// We have confirmed that the selected cell is
|
||||
// within the visible display range. Now translate
|
||||
// the display cell index to the absolute list cell index
|
||||
// by taking into account the scroll position.
|
||||
// - Note that nItemTop is always pointing to an
|
||||
// item index at the start of a row
|
||||
nItemC = nDispC;
|
||||
nItemR = pListbox->nItemTop + nDispR;
|
||||
|
||||
// Now we have identified the cell within the list matrix
|
||||
nItemCurSel = nItemR * nCols + nItemC;
|
||||
|
||||
// Confirm we haven't selected out of range
|
||||
if (nItemCurSel >= pListbox->nItemCnt) {
|
||||
bSelInItem = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (bSelInItem) {
|
||||
// Now check for touch in gap region
|
||||
// - First find offset from top-left of matrix cell
|
||||
nRelX = nRelX % nItemOuterW;
|
||||
nRelY = nRelY % nItemOuterH;
|
||||
// If we are in the gap region, disable
|
||||
if (nRelX > pListbox->nItemW) {
|
||||
bSelInItem = false;
|
||||
}
|
||||
if (nRelY > pListbox->nItemH) {
|
||||
bSelInItem = false;
|
||||
}
|
||||
}
|
||||
|
||||
// If we determined that the coordinate was not inside an
|
||||
// element, then clear current selection
|
||||
if (!bSelInItem) {
|
||||
nItemCurSel = XLISTBOX_SEL_NONE;
|
||||
}
|
||||
|
||||
// If we have committed a touch press within an item
|
||||
// that was already selected, then toggle (deselect it)
|
||||
if ((bSelSave) && (nItemCurSel == nItemSavedSel)) {
|
||||
nItemCurSel = XLISTBOX_SEL_NONE;
|
||||
}
|
||||
|
||||
bool bDoRedraw = false;
|
||||
|
||||
if (nItemCurSel != nItemCurSelOld) {
|
||||
// Selection changed, so we will redraw
|
||||
bDoRedraw = true;
|
||||
}
|
||||
|
||||
if (bDoRedraw) {
|
||||
// Update the selection
|
||||
gslc_ElemXListboxSetSel(pGui, pElemRef, nItemCurSel);
|
||||
|
||||
// If any selection callback is defined, call it now
|
||||
if (pListbox->pfuncXSel != NULL) {
|
||||
(*pListbox->pfuncXSel)((void*)(pGui), (void*)(pElemRef), nItemCurSel);
|
||||
}
|
||||
// Redraw the element
|
||||
// - Note that ElemXListboxSetSel() above will also request redraw
|
||||
gslc_ElemSetRedraw(pGui, pElemRef, GSLC_REDRAW_INC);
|
||||
}
|
||||
|
||||
// Update the saved selection
|
||||
if (bSelSave) {
|
||||
pListbox->nItemSavedSel = nItemCurSel;
|
||||
}
|
||||
|
||||
} // bIndexed
|
||||
|
||||
} // bSelTrack
|
||||
|
||||
return true;
|
||||
|
||||
#endif // DRV_TOUCH_NONE
|
||||
}
|
||||
|
||||
int16_t gslc_ElemXListboxGetSel(gslc_tsGui* pGui,gslc_tsElemRef* pElemRef)
|
||||
{
|
||||
gslc_tsXListbox* pListbox = (gslc_tsXListbox*)gslc_GetXDataFromRef(pGui, pElemRef, GSLC_TYPEX_LISTBOX, __LINE__);
|
||||
if (!pListbox) return XLISTBOX_SEL_NONE;
|
||||
|
||||
return pListbox->nItemCurSel;
|
||||
}
|
||||
|
||||
bool gslc_ElemXListboxSetSel(gslc_tsGui* pGui,gslc_tsElemRef* pElemRef, int16_t nItemCurSel)
|
||||
{
|
||||
gslc_tsXListbox* pListbox = (gslc_tsXListbox*)gslc_GetXDataFromRef(pGui, pElemRef, GSLC_TYPEX_LISTBOX, __LINE__);
|
||||
if (!pListbox) return false;
|
||||
|
||||
bool bOk = false;
|
||||
if (nItemCurSel == XLISTBOX_SEL_NONE) { bOk = true; }
|
||||
if ((nItemCurSel >= 0) && (nItemCurSel < pListbox->nItemCnt)) { bOk = true; }
|
||||
if (bOk) {
|
||||
pListbox->nItemCurSel = nItemCurSel;
|
||||
gslc_ElemSetRedraw(pGui, pElemRef, GSLC_REDRAW_INC);
|
||||
}
|
||||
return bOk;
|
||||
}
|
||||
|
||||
bool gslc_ElemXListboxSetScrollPos(gslc_tsGui* pGui, gslc_tsElemRef* pElemRef, uint16_t nScrollPos)
|
||||
{
|
||||
gslc_tsXListbox* pListbox = (gslc_tsXListbox*)gslc_GetXDataFromRef(pGui, pElemRef, GSLC_TYPEX_LISTBOX, __LINE__);
|
||||
if (!pListbox) return false;
|
||||
|
||||
bool bOk = false;
|
||||
if ((nScrollPos >= 0) && (nScrollPos < pListbox->nItemCnt)) {
|
||||
bOk = true;
|
||||
}
|
||||
|
||||
int16_t nCols = pListbox->nCols;
|
||||
int16_t nItemCnt = pListbox->nItemCnt;
|
||||
|
||||
// Error handling: in case position out of bounds
|
||||
if (nScrollPos >= nItemCnt) {
|
||||
nScrollPos = (nItemCnt > 0) ? nItemCnt - 1 : 0;
|
||||
}
|
||||
|
||||
// Adjust the top item index to the start of its row
|
||||
// - This is done because we may have multiple columns
|
||||
// per row. This ensures nItemTop points to the list
|
||||
// index at the start of a row.
|
||||
nScrollPos = (nScrollPos / nCols) * nCols;
|
||||
pListbox->nItemTop = nScrollPos;
|
||||
|
||||
// Need to update all rows in display
|
||||
gslc_ElemSetRedraw(pGui, pElemRef, GSLC_REDRAW_FULL);
|
||||
return bOk;
|
||||
}
|
||||
|
||||
|
||||
// Assign the selection callback function for a Listbox
|
||||
void gslc_ElemXListboxSetSelFunc(gslc_tsGui* pGui,gslc_tsElemRef* pElemRef,GSLC_CB_XLISTBOX_SEL funcCb)
|
||||
{
|
||||
gslc_tsXListbox* pListbox = (gslc_tsXListbox*)gslc_GetXDataFromRef(pGui, pElemRef, GSLC_TYPEX_LISTBOX, __LINE__);
|
||||
if (!pListbox) return;
|
||||
|
||||
pListbox->pfuncXSel = funcCb;
|
||||
}
|
||||
|
||||
// ============================================================================
|
329
src/guislice/XListbox.h
Normal file
329
src/guislice/XListbox.h
Normal file
|
@ -0,0 +1,329 @@
|
|||
#ifndef _GUISLICE_EX_XLISTBOX_H_
|
||||
#define _GUISLICE_EX_XLISTBOX_H_
|
||||
|
||||
#include "GUIslice.h"
|
||||
|
||||
|
||||
// =======================================================================
|
||||
// GUIslice library extension: Listbox control
|
||||
// - Calvin Hass
|
||||
// - https://www.impulseadventure.com/elec/guislice-gui.html
|
||||
// - https://github.com/ImpulseAdventure/GUIslice
|
||||
// =======================================================================
|
||||
//
|
||||
// The MIT License
|
||||
//
|
||||
// Copyright 2016-2020 Calvin Hass
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
//
|
||||
// =======================================================================
|
||||
/// \file XListbox.h
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif // __cplusplus
|
||||
|
||||
|
||||
// ============================================================================
|
||||
// Extended Element: Listbox
|
||||
// - NOTE: The XListbox element is in beta development.
|
||||
// Therefore, its API is subject to change.
|
||||
// ============================================================================
|
||||
|
||||
// Define unique identifier for extended element type
|
||||
// - Select any number above GSLC_TYPE_BASE_EXTEND
|
||||
#define GSLC_TYPEX_LISTBOX GSLC_TYPE_BASE_EXTEND + 10
|
||||
|
||||
// Define constants specific to the control
|
||||
#define XLISTBOX_SEL_NONE -1 // Indicator for "no selection"
|
||||
#define XLISTBOX_SIZE_AUTO -1 // Indicator for "auto-size"
|
||||
#define XLISTBOX_BUF_OH_R 2 // Listbox buffer overhead per row
|
||||
|
||||
/// Callback function for Listbox feedback
|
||||
typedef bool (*GSLC_CB_XLISTBOX_SEL)(void* pvGui,void* pvElem,int16_t nSel);
|
||||
|
||||
// Extended element data structures
|
||||
// - These data structures are maintained in the gslc_tsElem
|
||||
// structure via the pXData pointer
|
||||
|
||||
/// Extended data for Listbox element
|
||||
typedef struct {
|
||||
|
||||
// Config
|
||||
uint8_t* pBufItems; ///< Buffer containing items
|
||||
uint16_t nBufItemsMax; ///< Max size of buffer containing items
|
||||
uint16_t nBufItemsPos; ///< Current buffer position
|
||||
int16_t nItemCnt; ///< Number of items in the list
|
||||
|
||||
// Style config
|
||||
int8_t nCols; ///< Number of columns
|
||||
int8_t nRows; ///< Number of columns (or XLSITBOX_SIZE_AUTO to calculate)
|
||||
bool bNeedRecalc; ///< Determine if sizing may need recalc
|
||||
int8_t nMarginW; ///< Margin inside main listbox area (X offset)
|
||||
int8_t nMarginH; ///< Margin inside main listbox area (Y offset)
|
||||
int16_t nItemW; ///< Width of listbox item
|
||||
int16_t nItemH; ///< Height of listbox item
|
||||
int8_t nItemGap; ///< Gap between listbox items
|
||||
gslc_tsColor colGap; ///< Gap color
|
||||
bool bItemAutoSizeW; ///< Enable auto-sizing of items (in width)
|
||||
bool bItemAutoSizeH; ///< Enable auto-sizing of items (in height)
|
||||
|
||||
// State
|
||||
int16_t nItemCurSel; ///< Currently selected item (XLISTBOX_SEL_NONE for none)
|
||||
int16_t nItemCurSelLast; ///< Old selected item to redraw (XLISTBOX_SEL_NONE for none)
|
||||
int16_t nItemSavedSel; ///< Persistent selected item (ie. saved selection)
|
||||
int16_t nItemTop; ///< Item to show at top of list after scrolling (0 is default)
|
||||
|
||||
// Callbacks
|
||||
GSLC_CB_XLISTBOX_SEL pfuncXSel; ///< Callback func ptr for selection update
|
||||
|
||||
} gslc_tsXListbox;
|
||||
|
||||
|
||||
///
|
||||
/// Create a Listbox Element
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] nElemId: Element ID to assign (0..16383 or GSLC_ID_AUTO to autogen)
|
||||
/// \param[in] nPage: Page ID to attach element to
|
||||
/// \param[in] pXData: Ptr to extended element data structure
|
||||
/// \param[in] rElem: Rectangle coordinates defining checkbox size
|
||||
/// \param[in] nFontId: Font ID for item display
|
||||
/// \param[in] pBufItems: Pointer to buffer that will contain list of items
|
||||
/// \param[in] nBufItemsMax: Max size of buffer for list of items (pBufItems)
|
||||
/// \param[in] nSelDefault: Default item to select
|
||||
///
|
||||
/// \return Pointer to Element reference or NULL if failure
|
||||
///
|
||||
gslc_tsElemRef* gslc_ElemXListboxCreate(gslc_tsGui* pGui, int16_t nElemId, int16_t nPage,
|
||||
gslc_tsXListbox* pXData, gslc_tsRect rElem, int16_t nFontId, uint8_t* pBufItems,
|
||||
uint16_t nBufItemsMax, int16_t nSelDefault);
|
||||
|
||||
|
||||
///
|
||||
/// Configure the number of rows & columns to display in the listbox
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] pElemRef: Ptr to Element Reference to update
|
||||
/// \param[in] nRows: Number of rows (>= 1, or XLISTBOX_SIZE_AUTO to base on content)
|
||||
/// \param[in] nCols: Number of columns (>= 1)
|
||||
///
|
||||
/// \return none
|
||||
///
|
||||
void gslc_ElemXListboxSetSize(gslc_tsGui* pGui, gslc_tsElemRef* pElemRef, int8_t nRows, int8_t nCols);
|
||||
|
||||
|
||||
///
|
||||
/// Configure the margin inside the listbox
|
||||
/// - Defines the region bewteen the element rect and the inner listbox items
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] pElemRef: Ptr to Element Reference to update
|
||||
/// \param[in] nMarginW: Set the margin (horizontal) inside the listbox (0 for none)
|
||||
/// \param[in] nMarginH: Set the margin (horizontal) inside the listbox (0 for none)
|
||||
///
|
||||
/// \return none
|
||||
///
|
||||
void gslc_ElemXListboxSetMargin(gslc_tsGui* pGui, gslc_tsElemRef* pElemRef, int8_t nMarginW, int8_t nMarginH);
|
||||
|
||||
///
|
||||
/// Configure the size of the listbox items
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] pElemRef: Ptr to Element Reference to update
|
||||
/// \param[in] nItemW: Set the width of a listbox item (or -1 to auto-size)
|
||||
/// \param[in] nItemH: Set the height of a listbox item
|
||||
///
|
||||
/// \return none
|
||||
///
|
||||
void gslc_ElemXListboxItemsSetSize(gslc_tsGui* pGui, gslc_tsElemRef* pElemRef, int16_t nItemW, int16_t nItemH);
|
||||
|
||||
///
|
||||
/// Configure the gap between listbox items
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] pElemRef: Ptr to Element Reference to update
|
||||
/// \param[in] nGap: Set the gap between listbox items (0 for none)
|
||||
/// \param[in] colGap: Set the color of the gap between listbox items
|
||||
///
|
||||
/// \return none
|
||||
///
|
||||
void gslc_ElemXListboxItemsSetGap(gslc_tsGui* pGui, gslc_tsElemRef* pElemRef, int8_t nGap, gslc_tsColor colGap);
|
||||
|
||||
|
||||
///
|
||||
/// Empty the listbox of all items
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] pElemRef: Ptr to Element Reference to update
|
||||
///
|
||||
/// \return none
|
||||
///
|
||||
void gslc_ElemXListboxReset(gslc_tsGui* pGui, gslc_tsElemRef* pElemRef);
|
||||
|
||||
|
||||
///
|
||||
/// Add an item to the listbox
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] pElemRef: Ptr to Element Reference to update
|
||||
/// \param[in] pStrItem: String to use when creating the listbox item
|
||||
///
|
||||
/// \return true if OK, false if fail (eg. insufficient buffer storage)
|
||||
///
|
||||
bool gslc_ElemXListboxAddItem(gslc_tsGui* pGui, gslc_tsElemRef* pElemRef, const char* pStrItem);
|
||||
|
||||
///
|
||||
/// Insert an item in the listbox at a specific position
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] pElemRef: Ptr to Element Reference to update
|
||||
/// \param[in] nInsertPos: Insertion position
|
||||
/// \param[in] pStrItem: String to use when creating the listbox item
|
||||
///
|
||||
/// \return true if OK, false if fail (eg. insufficient buffer storage)
|
||||
///
|
||||
bool gslc_ElemXListboxInsertItemAt(gslc_tsGui* pGui, gslc_tsElemRef* pElemRef, uint16_t nInsertPos,
|
||||
const char* pStrItem);
|
||||
|
||||
///
|
||||
/// Insert an item in the listbox at a specific position
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] pElemRef: Ptr to Element Reference to update
|
||||
/// \param[in] nDeletePos: Position to delete
|
||||
///
|
||||
/// \return true if OK, false if fail
|
||||
///
|
||||
bool gslc_ElemXListboxDeleteItemAt(gslc_tsGui* pGui, gslc_tsElemRef* pElemRef, uint16_t nDeletePos);
|
||||
|
||||
///
|
||||
/// Get the indexed listbox item
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] pElemRef: Ptr to Element Reference to update
|
||||
/// \param[in] nItemCurSel: Item index to fetch
|
||||
/// \param[out] pStrItem: Ptr to the string buffer to receive the item
|
||||
/// \param[in] nStrItemLen: Maximum buffer length of pStrItem
|
||||
///
|
||||
/// \return true if success, false if fail (eg. can't locate item)
|
||||
///
|
||||
bool gslc_ElemXListboxGetItem(gslc_tsGui* pGui, gslc_tsElemRef* pElemRef, int16_t nItemCurSel,
|
||||
char* pStrItem, uint8_t nStrItemLen);
|
||||
|
||||
|
||||
///
|
||||
/// Get the number of items in the listbox
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] pElemRef: Ptr to Element Reference to update
|
||||
///
|
||||
/// \return Number of items
|
||||
///
|
||||
int16_t gslc_ElemXListboxGetItemCnt(gslc_tsGui* pGui, gslc_tsElemRef* pElemRef);
|
||||
|
||||
///
|
||||
/// Draw a Listbox element on the screen
|
||||
/// - Called from gslc_ElemDraw()
|
||||
///
|
||||
/// \param[in] pvGui: Void ptr to GUI (typecast to gslc_tsGui*)
|
||||
/// \param[in] pvElemRef: Void ptr to Element (typecast to gslc_tsElemRef*)
|
||||
/// \param[in] eRedraw: Redraw mode
|
||||
///
|
||||
/// \return true if success, false otherwise
|
||||
///
|
||||
bool gslc_ElemXListboxDraw(void* pvGui,void* pvElemRef,gslc_teRedrawType eRedraw);
|
||||
|
||||
///
|
||||
/// Handle touch events to Listbox element
|
||||
/// - Called from gslc_ElemSendEventTouch()
|
||||
///
|
||||
/// \param[in] pvGui: Void ptr to GUI (typecast to gslc_tsGui*)
|
||||
/// \param[in] pvElemRef: Void ptr to Element ref (typecast to gslc_tsElemRef*)
|
||||
/// \param[in] eTouch: Touch event type
|
||||
/// \param[in] nRelX: Touch X coord relative to element
|
||||
/// \param[in] nRelY: Touch Y coord relative to element
|
||||
///
|
||||
/// \return true if success, false otherwise
|
||||
///
|
||||
bool gslc_ElemXListboxTouch(void* pvGui,void* pvElemRef,gslc_teTouch eTouch,int16_t nRelX,int16_t nRelY);
|
||||
|
||||
|
||||
///
|
||||
/// Get a Listbox element's current selection
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] pElemRef: Pointer to Element reference
|
||||
///
|
||||
/// \return Current Listbox selection (or -1 if none)
|
||||
///
|
||||
int16_t gslc_ElemXListboxGetSel(gslc_tsGui* pGui,gslc_tsElemRef* pElemRef);
|
||||
|
||||
|
||||
///
|
||||
/// Set a Listbox element's current selection
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] pElemRef: Pointer to Element reference
|
||||
/// \param[in] nItemCurSel: Listbox item to select (or -1 for none)
|
||||
///
|
||||
/// \return true if success, false if fail
|
||||
///
|
||||
bool gslc_ElemXListboxSetSel(gslc_tsGui* pGui, gslc_tsElemRef* pElemRef, int16_t nItemCurSel);
|
||||
|
||||
///
|
||||
/// Set the Listbox scroll position
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] pElemRef: Pointer to Element reference
|
||||
/// \param[in] nScrollPos: Scroll the listbox so that the nScrollPos item is at the top (0 default)
|
||||
///
|
||||
/// \return true if success, false if fail
|
||||
///
|
||||
bool gslc_ElemXListboxSetScrollPos(gslc_tsGui* pGui, gslc_tsElemRef* pElemRef, uint16_t nScrollPos);
|
||||
|
||||
|
||||
///
|
||||
/// Assign the selection callback function for a Listbox
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] pElemRef: Pointer to Element reference
|
||||
/// \param[in] funcCb: Function pointer to selection routine (or NULL for none)
|
||||
///
|
||||
/// \return none
|
||||
///
|
||||
void gslc_ElemXListboxSetSelFunc(gslc_tsGui* pGui,gslc_tsElemRef* pElemRef,GSLC_CB_XLISTBOX_SEL funcCb);
|
||||
|
||||
// ============================================================================
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Read-only element macros
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
// Macro initializers for Read-Only Elements in Flash/PROGMEM
|
||||
//
|
||||
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif // __cplusplus
|
||||
#endif // _GUISLICE_EX_XLISTBOX_H_
|
||||
|
365
src/guislice/XProgress.c
Normal file
365
src/guislice/XProgress.c
Normal file
|
@ -0,0 +1,365 @@
|
|||
// =======================================================================
|
||||
// GUIslice library (extensions)
|
||||
// - Calvin Hass
|
||||
// - https://www.impulseadventure.com/elec/guislice-gui.html
|
||||
// - https://github.com/ImpulseAdventure/GUIslice
|
||||
// =======================================================================
|
||||
//
|
||||
// The MIT License
|
||||
//
|
||||
// Copyright 2016-2020 Calvin Hass
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
//
|
||||
// =======================================================================
|
||||
/// \file XProgress.c
|
||||
|
||||
|
||||
|
||||
// GUIslice library
|
||||
#include "GUIslice.h"
|
||||
#include "GUIslice_drv.h"
|
||||
|
||||
#include "XProgress.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#if (GSLC_USE_PROGMEM)
|
||||
#include <avr/pgmspace.h>
|
||||
#endif
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Error Messages
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
extern const char GSLC_PMEM ERRSTR_NULL[];
|
||||
extern const char GSLC_PMEM ERRSTR_PXD_NULL[];
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Extended element definitions
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// - This file extends the core GUIslice functionality with
|
||||
// additional widget types
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
|
||||
// ============================================================================
|
||||
// Extended Element: Progress Bar
|
||||
// - Basic progress bar with support for vertical / horizontal orientation and
|
||||
// fill direction. Also provides an indicator of negative regions, depending
|
||||
// on the configured range.
|
||||
// ============================================================================
|
||||
|
||||
// Create a gauge element and add it to the GUI element list
|
||||
// - Defines default styling for the element
|
||||
// - Defines callback for redraw but does not track touch/click
|
||||
gslc_tsElemRef* gslc_ElemXProgressCreate(gslc_tsGui* pGui,int16_t nElemId,int16_t nPage,
|
||||
gslc_tsXProgress* pXData,gslc_tsRect rElem,
|
||||
int16_t nMin,int16_t nMax,int16_t nVal,gslc_tsColor colGauge,bool bVert)
|
||||
{
|
||||
if ((pGui == NULL) || (pXData == NULL)) {
|
||||
static const char GSLC_PMEM FUNCSTR[] = "ElemXProgressCreate";
|
||||
GSLC_DEBUG2_PRINT_CONST(ERRSTR_NULL,FUNCSTR);
|
||||
return NULL;
|
||||
}
|
||||
gslc_tsElem sElem;
|
||||
gslc_tsElemRef* pElemRef = NULL;
|
||||
sElem = gslc_ElemCreate(pGui,nElemId,nPage,GSLC_TYPEX_PROGRESS,rElem,NULL,0,GSLC_FONT_NONE);
|
||||
sElem.nFeatures |= GSLC_ELEM_FEA_FRAME_EN;
|
||||
sElem.nFeatures |= GSLC_ELEM_FEA_FILL_EN;
|
||||
sElem.nFeatures &= ~GSLC_ELEM_FEA_CLICK_EN; // Element is not "clickable"
|
||||
sElem.nFeatures &= ~GSLC_ELEM_FEA_GLOW_EN;
|
||||
sElem.nGroup = GSLC_GROUP_ID_NONE;
|
||||
pXData->nMin = nMin;
|
||||
pXData->nMax = nMax;
|
||||
pXData->nVal = nVal;
|
||||
pXData->bVert = bVert;
|
||||
pXData->bFlip = false;
|
||||
pXData->colGauge = colGauge;
|
||||
sElem.pXData = (void*)(pXData);
|
||||
sElem.pfuncXDraw = &gslc_ElemXProgressDraw;
|
||||
sElem.pfuncXTouch = NULL; // No need to track touches
|
||||
sElem.colElemFill = GSLC_COL_BLACK;
|
||||
sElem.colElemFillGlow = GSLC_COL_BLACK;
|
||||
sElem.colElemFrame = GSLC_COL_GRAY;
|
||||
sElem.colElemFrameGlow = GSLC_COL_GRAY;
|
||||
if (nPage != GSLC_PAGE_NONE) {
|
||||
pElemRef = gslc_ElemAdd(pGui,nPage,&sElem,GSLC_ELEMREF_DEFAULT);
|
||||
return pElemRef;
|
||||
#if (GSLC_FEATURE_COMPOUND)
|
||||
} else {
|
||||
// Save as temporary element
|
||||
pGui->sElemTmp = sElem;
|
||||
pGui->sElemRefTmp.pElem = &(pGui->sElemTmp);
|
||||
pGui->sElemRefTmp.eElemFlags = GSLC_ELEMREF_DEFAULT | GSLC_ELEMREF_REDRAW_FULL;
|
||||
return &(pGui->sElemRefTmp);
|
||||
#endif
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Update the gauge control's current position
|
||||
void gslc_ElemXProgressSetVal(gslc_tsGui* pGui,gslc_tsElemRef* pElemRef,int16_t nVal)
|
||||
{
|
||||
if (pElemRef == NULL) {
|
||||
static const char GSLC_PMEM FUNCSTR[] = "ElemXProgressSetVal";
|
||||
GSLC_DEBUG2_PRINT_CONST(ERRSTR_NULL,FUNCSTR);
|
||||
return;
|
||||
}
|
||||
gslc_tsXProgress* pGauge = (gslc_tsXProgress*)gslc_GetXDataFromRef(pGui,pElemRef,GSLC_TYPEX_PROGRESS,__LINE__);
|
||||
|
||||
// Update the data element
|
||||
int16_t nValOld = pGauge->nVal;
|
||||
pGauge->nVal = nVal;
|
||||
|
||||
// Element needs redraw
|
||||
if (nVal != nValOld) {
|
||||
// We only need an incremental redraw
|
||||
// NOTE: If the user configures the indicator to be
|
||||
// long enough that it overlaps some of the gauge indicators
|
||||
// then a full redraw should be done instead.
|
||||
gslc_ElemSetRedraw(pGui,pElemRef,GSLC_REDRAW_INC);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Update the gauge's fill direction
|
||||
// - Setting bFlip causes the gauge to be filled in the reverse direction
|
||||
// to the default
|
||||
// - Default fill direction for horizontal gauges: left-to-right
|
||||
// - Default fill direction for vertical gauges: bottom-to-top
|
||||
void gslc_ElemXProgressSetFlip(gslc_tsGui* pGui,gslc_tsElemRef* pElemRef,bool bFlip)
|
||||
{
|
||||
if (pElemRef == NULL) {
|
||||
static const char GSLC_PMEM FUNCSTR[] = "ElemXProgressSetFlip";
|
||||
GSLC_DEBUG2_PRINT_CONST(ERRSTR_NULL,FUNCSTR);
|
||||
return;
|
||||
}
|
||||
|
||||
// Fetch the element's extended data structure
|
||||
gslc_tsXProgress* pGauge = (gslc_tsXProgress*)gslc_GetXDataFromRef(pGui,pElemRef,GSLC_TYPEX_PROGRESS,__LINE__);
|
||||
|
||||
pGauge->bFlip = bFlip;
|
||||
|
||||
// Mark for redraw
|
||||
gslc_ElemSetRedraw(pGui,pElemRef,GSLC_REDRAW_FULL);
|
||||
|
||||
}
|
||||
|
||||
|
||||
// Redraw the gauge
|
||||
// - Note that this redraw is for the entire element rect region
|
||||
// - The Draw function parameters use void pointers to allow for
|
||||
// simpler callback function definition & scalability.
|
||||
bool gslc_ElemXProgressDraw(void* pvGui,void* pvElemRef,gslc_teRedrawType eRedraw)
|
||||
{
|
||||
if ((pvGui == NULL) || (pvElemRef == NULL)) {
|
||||
static const char GSLC_PMEM FUNCSTR[] = "ElemXProgressDraw";
|
||||
GSLC_DEBUG2_PRINT_CONST(ERRSTR_NULL,FUNCSTR);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Typecast the parameters to match the GUI and element types
|
||||
gslc_tsGui* pGui = (gslc_tsGui*)(pvGui);
|
||||
gslc_tsElemRef* pElemRef = (gslc_tsElemRef*)(pvElemRef);
|
||||
|
||||
// Fetch the element's extended data structure
|
||||
gslc_tsXProgress* pGauge = (gslc_tsXProgress*)gslc_GetXDataFromRef(pGui,pElemRef,GSLC_TYPEX_PROGRESS,__LINE__);
|
||||
|
||||
gslc_ElemXProgressDrawHelp(pGui,pElemRef,eRedraw);
|
||||
|
||||
// Save as "last state" to support incremental erase/redraw
|
||||
pGauge->nValLast = pGauge->nVal;
|
||||
pGauge->bValLastValid = true;
|
||||
|
||||
// Clear the redraw flag
|
||||
gslc_ElemSetRedraw(pGui,pElemRef,GSLC_REDRAW_NONE);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool gslc_ElemXProgressDrawHelp(gslc_tsGui* pGui,gslc_tsElemRef* pElemRef,gslc_teRedrawType eRedraw)
|
||||
{
|
||||
gslc_tsElem* pElem = gslc_GetElemFromRef(pGui,pElemRef);
|
||||
gslc_tsXProgress* pGauge = (gslc_tsXProgress*)gslc_GetXDataFromRef(pGui,pElemRef,GSLC_TYPEX_PROGRESS,__LINE__);
|
||||
|
||||
gslc_tsRect rTmp; // Temporary rect for drawing
|
||||
gslc_tsRect rGauge; // Filled portion of gauge
|
||||
gslc_tsRect rEmpty; // Empty portion of gauge
|
||||
uint16_t nElemW,nElemH;
|
||||
int16_t nElemX0,nElemY0,nElemX1,nElemY1;
|
||||
int16_t nGaugeX0,nGaugeY0,nGaugeX1,nGaugeY1;
|
||||
|
||||
nElemX0 = pElem->rElem.x;
|
||||
nElemY0 = pElem->rElem.y;
|
||||
nElemX1 = pElem->rElem.x + pElem->rElem.w - 1;
|
||||
nElemY1 = pElem->rElem.y + pElem->rElem.h - 1;
|
||||
nElemW = pElem->rElem.w;
|
||||
nElemH = pElem->rElem.h;
|
||||
|
||||
bool bVert = pGauge->bVert;
|
||||
bool bFlip = pGauge->bFlip;
|
||||
int16_t nMax = pGauge->nMax;
|
||||
int16_t nMin = pGauge->nMin;
|
||||
int16_t nRng = pGauge->nMax - pGauge->nMin;
|
||||
|
||||
uint32_t nScl = 1;
|
||||
int16_t nGaugeMid = 0;
|
||||
int16_t nLen = 0;
|
||||
int16_t nTmp = 0;
|
||||
int32_t nTmpL = 0;
|
||||
|
||||
if (nRng == 0) {
|
||||
GSLC_DEBUG2_PRINT("ERROR: ElemXProgressDraw() Zero gauge range [%d,%d]\n",nMin,nMax);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (bVert) {
|
||||
nScl = nElemH*32768/nRng;
|
||||
} else {
|
||||
nScl = nElemW*32768/nRng;
|
||||
}
|
||||
|
||||
// Calculate the control midpoint/zeropoint (for display purposes)
|
||||
nTmpL = -((int32_t)nMin * (int32_t)nScl / 32768);
|
||||
nGaugeMid = (int16_t)nTmpL;
|
||||
|
||||
|
||||
// Calculate the length of the bar
|
||||
// - Use long mult/divide to avoid need for floating point
|
||||
nTmpL = (int32_t)(pGauge->nVal) * (int32_t)(nScl) / 32768;
|
||||
nLen = (int16_t)(nTmpL);
|
||||
|
||||
// Define the gauge's fill rectangle region
|
||||
// depending on the orientation (bVert) and whether
|
||||
// the current position is negative or positive.
|
||||
if (nLen >= 0) {
|
||||
if (bVert) {
|
||||
nGaugeY0 = nElemY0 + nGaugeMid;
|
||||
nGaugeY1 = nElemY0 + nGaugeMid + nLen;
|
||||
} else {
|
||||
nGaugeX0 = nElemX0 + nGaugeMid;
|
||||
nGaugeX1 = nElemX0 + nGaugeMid + nLen;
|
||||
}
|
||||
} else {
|
||||
if (bVert) {
|
||||
nGaugeY0 = nElemY0 + nGaugeMid + nLen;
|
||||
nGaugeY1 = nElemY0 + nGaugeMid;
|
||||
} else {
|
||||
nGaugeX0 = nElemX0 + nGaugeMid + nLen;
|
||||
nGaugeX1 = nElemX0 + nGaugeMid;
|
||||
}
|
||||
}
|
||||
if (bVert) {
|
||||
nGaugeX0 = nElemX0;
|
||||
nGaugeX1 = nElemX1;
|
||||
} else {
|
||||
nGaugeY0 = nElemY0;
|
||||
nGaugeY1 = nElemY1;
|
||||
}
|
||||
|
||||
|
||||
// Clip the region
|
||||
nGaugeX0 = (nGaugeX0 < nElemX0)? nElemX0 : nGaugeX0;
|
||||
nGaugeY0 = (nGaugeY0 < nElemY0)? nElemY0 : nGaugeY0;
|
||||
nGaugeX1 = (nGaugeX1 > nElemX1)? nElemX1 : nGaugeX1;
|
||||
nGaugeY1 = (nGaugeY1 > nElemY1)? nElemY1 : nGaugeY1;
|
||||
|
||||
// Support flipping of gauge directionality
|
||||
// - The bFlip flag reverses the fill direction
|
||||
// - Vertical gauges are flipped by default
|
||||
|
||||
if (bVert && !bFlip) {
|
||||
nTmp = nElemY0+(nElemY1-nGaugeY1); // nTmp will be swapped into nGaugeY0
|
||||
nGaugeY1 = nElemY1-(nGaugeY0-nElemY0);
|
||||
nGaugeY0 = nTmp;
|
||||
nGaugeMid = nElemH-nGaugeMid-1;
|
||||
} else if (!bVert && bFlip) {
|
||||
nTmp = nElemX0+(nElemX1-nGaugeX1); // nTmp will be swapped into nGaugeX0
|
||||
nGaugeX1 = nElemX1-(nGaugeX0-nElemX0);
|
||||
nGaugeX0 = nTmp;
|
||||
nGaugeMid = nElemW-nGaugeMid-1;
|
||||
}
|
||||
|
||||
#ifdef DBG_LOG
|
||||
//printf("Gauge: nMin=%4d nMax=%4d nRng=%d nVal=%4d fScl=%6.3f nGaugeMid=%4d RectX=%4d RectW=%4d\n",
|
||||
// nMin,nMax,nRng,pGauge->nGaugeVal,fScl,nGaugeMid,rGauge.x,rGauge.w);
|
||||
#endif
|
||||
|
||||
// Draw a frame around the gauge
|
||||
// - Only draw this during full redraw
|
||||
if (eRedraw == GSLC_REDRAW_FULL) {
|
||||
gslc_DrawFrameRect(pGui, pElem->rElem, pElem->colElemFrame);
|
||||
}
|
||||
|
||||
// To avoid flicker, we only erase the portion of the gauge
|
||||
// that isn't "filled". Determine the gauge empty region and erase it
|
||||
// There are two empty regions (one in negative and one in positive)
|
||||
int16_t nEmptyPos;
|
||||
if (bVert) {
|
||||
// Empty Region #1 (negative)
|
||||
nEmptyPos = (nGaugeY0 > nElemY1) ? nElemY1 : nGaugeY0;
|
||||
rEmpty = (gslc_tsRect){nElemX0,nElemY0,nElemX1-nElemX0+1,nEmptyPos-nElemY0+1};
|
||||
rTmp = gslc_ExpandRect(rEmpty,-1,-1);
|
||||
gslc_DrawFillRect(pGui,rTmp,pElem->colElemFill);
|
||||
// Empty Region #2 (positive)
|
||||
nEmptyPos = (nGaugeY1 < nElemY0) ? nElemY0 : nGaugeY1;
|
||||
rEmpty = (gslc_tsRect){nElemX0,nEmptyPos,nElemX1-nElemX0+1,nElemY1-nEmptyPos+1};
|
||||
rTmp = gslc_ExpandRect(rEmpty,-1,-1);
|
||||
gslc_DrawFillRect(pGui,rTmp,pElem->colElemFill);
|
||||
} else {
|
||||
// Empty Region #1 (negative)
|
||||
nEmptyPos = (nGaugeX0 > nElemX1) ? nElemX1 : nGaugeX0;
|
||||
rEmpty = (gslc_tsRect){nElemX0,nElemY0,nEmptyPos-nElemX0+1,nElemY1-nElemY0+1};
|
||||
rTmp = gslc_ExpandRect(rEmpty,-1,-1);
|
||||
gslc_DrawFillRect(pGui, rTmp, pElem->colElemFill);
|
||||
// Empty Region #2 (positive)
|
||||
nEmptyPos = (nGaugeX1 < nElemX0) ? nElemX0 : nGaugeX1;
|
||||
rEmpty = (gslc_tsRect){nEmptyPos,nElemY0,nElemX1-nEmptyPos+1,nElemY1-nElemY0+1};
|
||||
rTmp = gslc_ExpandRect(rEmpty,-1,-1);
|
||||
gslc_DrawFillRect(pGui, rTmp, pElem->colElemFill);
|
||||
}
|
||||
|
||||
// Draw the gauge fill region
|
||||
rGauge = (gslc_tsRect){nGaugeX0,nGaugeY0,nGaugeX1-nGaugeX0+1,nGaugeY1-nGaugeY0+1};
|
||||
rTmp = gslc_ExpandRect(rGauge,-1,-1);
|
||||
gslc_DrawFillRect(pGui,rTmp,pGauge->colGauge);
|
||||
|
||||
|
||||
// Draw the midpoint line
|
||||
if (bVert) {
|
||||
if (nElemY0 + nGaugeMid < nElemY1) {
|
||||
gslc_DrawLine(pGui, nElemX0, nElemY0 + nGaugeMid, nElemX1, nElemY0 + nGaugeMid, pElem->colElemFrame);
|
||||
}
|
||||
} else {
|
||||
if (nElemX0 + nGaugeMid < nElemX1) {
|
||||
gslc_DrawLine(pGui, nElemX0 + nGaugeMid, nElemY0, nElemX0 + nGaugeMid, nElemY1, pElem->colElemFrame);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// ============================================================================
|
287
src/guislice/XProgress.h
Normal file
287
src/guislice/XProgress.h
Normal file
|
@ -0,0 +1,287 @@
|
|||
#ifndef _GUISLICE_EX_XPROGRESS_H_
|
||||
#define _GUISLICE_EX_XPROGRESS_H_
|
||||
|
||||
#include "GUIslice.h"
|
||||
|
||||
|
||||
// =======================================================================
|
||||
// GUIslice library extension: Progress Bar
|
||||
// - Calvin Hass
|
||||
// - https://www.impulseadventure.com/elec/guislice-gui.html
|
||||
// - https://github.com/ImpulseAdventure/GUIslice
|
||||
// =======================================================================
|
||||
//
|
||||
// The MIT License
|
||||
//
|
||||
// Copyright 2016-2020 Calvin Hass
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
//
|
||||
// =======================================================================
|
||||
/// \file XProgress.h
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif // __cplusplus
|
||||
|
||||
|
||||
// ============================================================================
|
||||
// Extended Element: Progress Bar
|
||||
// - Basic progress bar with support for vertical / horizontal orientation and
|
||||
// fill direction. Also provides an indicator of negative regions, depending
|
||||
// on the configured range.
|
||||
// ============================================================================
|
||||
|
||||
// Define unique identifier for extended element type
|
||||
// - Select any number above GSLC_TYPE_BASE_EXTEND
|
||||
#define GSLC_TYPEX_PROGRESS GSLC_TYPE_BASE_EXTEND + 60
|
||||
|
||||
|
||||
|
||||
// Extended element data structures
|
||||
// - These data structures are maintained in the gslc_tsElem
|
||||
// structure via the pXData pointer
|
||||
|
||||
/// Extended data for Gauge element
|
||||
typedef struct {
|
||||
// Range config
|
||||
int16_t nMin; ///< Minimum control value
|
||||
int16_t nMax; ///< Maximum control value
|
||||
|
||||
// Current value
|
||||
int16_t nVal; ///< Current control value
|
||||
// Previous value
|
||||
int16_t nValLast; ///< Last value
|
||||
bool bValLastValid; ///< Last value valid?
|
||||
|
||||
// Appearance config
|
||||
gslc_tsColor colGauge; ///< Color of gauge fill bar
|
||||
bool bVert; ///< Vertical if true, else Horizontal
|
||||
bool bFlip; ///< Reverse direction of gauge
|
||||
|
||||
} gslc_tsXProgress;
|
||||
|
||||
|
||||
///
|
||||
/// Create a Progress Bar Element
|
||||
/// - Draws a gauge element that represents a proportion (nVal)
|
||||
/// between nMin and nMax.
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] nElemId: Element ID to assign (0..16383 or GSLC_ID_AUTO to autogen)
|
||||
/// \param[in] nPage: Page ID to attach element to
|
||||
/// \param[in] pXData: Ptr to extended element data structure
|
||||
/// \param[in] rElem: Rectangle coordinates defining gauge size
|
||||
/// \param[in] nMin: Minimum value of gauge for nVal comparison
|
||||
/// \param[in] nMax: Maximum value of gauge for nVal comparison
|
||||
/// \param[in] nVal: Starting value of gauge
|
||||
/// \param[in] colGauge: Color for the gauge indicator
|
||||
/// \param[in] bVert: Flag to indicate vertical vs horizontal action
|
||||
/// (true = vertical, false = horizontal)
|
||||
///
|
||||
/// \return Pointer to Element reference or NULL if failure
|
||||
///
|
||||
gslc_tsElemRef* gslc_ElemXProgressCreate(gslc_tsGui* pGui,int16_t nElemId,int16_t nPage,
|
||||
gslc_tsXProgress* pXData,gslc_tsRect rElem,int16_t nMin,int16_t nMax,int16_t nVal,gslc_tsColor colGauge,bool bVert);
|
||||
|
||||
|
||||
///
|
||||
/// Update a Gauge element's current value
|
||||
/// - Note that min & max values are assigned in create()
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] pElemRef: Pointer to Element reference
|
||||
/// \param[in] nVal: New value to show in gauge
|
||||
///
|
||||
/// \return none
|
||||
///
|
||||
void gslc_ElemXProgressSetVal(gslc_tsGui* pGui,gslc_tsElemRef* pElemRef,int16_t nVal);
|
||||
|
||||
|
||||
///
|
||||
/// Set a Gauge element's fill direction
|
||||
/// - Setting bFlip reverses the default fill direction
|
||||
/// - Default fill direction for horizontal gauges: left-to-right
|
||||
/// - Default fill direction for vertical gauges: bottom-to-top
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] pElemRef: Pointer to Element reference
|
||||
/// \param[in] bFlip: If set, reverse direction of fill from default
|
||||
///
|
||||
/// \return none
|
||||
///
|
||||
void gslc_ElemXProgressSetFlip(gslc_tsGui* pGui,gslc_tsElemRef* pElemRef,bool bFlip);
|
||||
|
||||
|
||||
///
|
||||
/// Draw a gauge element on the screen
|
||||
/// - Called from gslc_ElemDraw()
|
||||
///
|
||||
/// \param[in] pvGui: Void ptr to GUI (typecast to gslc_tsGui*)
|
||||
/// \param[in] pvElemRef: Void ptr to Element reference (typecast to gslc_tsElemRef*)
|
||||
/// \param[in] eRedraw: Redraw mode
|
||||
///
|
||||
/// \return true if success, false otherwise
|
||||
///
|
||||
bool gslc_ElemXProgressDraw(void* pvGui,void* pvElemRef,gslc_teRedrawType eRedraw);
|
||||
|
||||
|
||||
///
|
||||
/// Helper function to draw a gauge with style: progress bar
|
||||
/// - Called from gslc_ElemXProgressDraw()
|
||||
///
|
||||
/// \param[in] pGui: Ptr to GUI
|
||||
/// \param[in] pElemRef: Ptr to Element reference
|
||||
/// \param[in] eRedraw: Redraw status
|
||||
///
|
||||
/// \return true if success, false otherwise
|
||||
///
|
||||
bool gslc_ElemXProgressDrawHelp(gslc_tsGui* pGui,gslc_tsElemRef* pElemRef,gslc_teRedrawType eRedraw);
|
||||
|
||||
|
||||
// ============================================================================
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Read-only element macros
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
// Macro initializers for Read-Only Elements in Flash/PROGMEM
|
||||
//
|
||||
|
||||
|
||||
/// \def gslc_ElemXProgressCreate_P(pGui,nElemId,nPage,nX,nY,nW,nH,
|
||||
/// nMin_,nMax_,nVal_,colFrame_,colFill_,colGauge_,bVert_)
|
||||
///
|
||||
/// Create a Gauge Element in Flash
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] nElemId: Unique element ID to assign
|
||||
/// \param[in] nPage: Page ID to attach element to
|
||||
/// \param[in] nX: X coordinate of element
|
||||
/// \param[in] nY: Y coordinate of element
|
||||
/// \param[in] nW: Width of element
|
||||
/// \param[in] nH: Height of element
|
||||
/// \param[in] nMin_: Minimum value of gauge for nVal comparison
|
||||
/// \param[in] nMax_: Maximum value of gauge for nVal comparison
|
||||
/// \param[in] nVal_: Starting value of gauge
|
||||
/// \param[in] colFrame_: Color for the gauge frame
|
||||
/// \param[in] colFill_: Color for the gauge background fill
|
||||
/// \param[in] colGauge_: Color for the gauge indicator
|
||||
/// \param[in] bVert_: Flag to indicate vertical vs horizontal action
|
||||
/// (true = vertical, false = horizontal)
|
||||
///
|
||||
/// \return none
|
||||
///
|
||||
|
||||
|
||||
#if (GSLC_USE_PROGMEM)
|
||||
|
||||
|
||||
#define gslc_ElemXProgressCreate_P(pGui,nElemId,nPage,nX,nY,nW,nH,\
|
||||
nMin_,nMax_,nVal_,colFrame_,colFill_,colGauge_,bVert_) \
|
||||
static const uint8_t nFeatures##nElemId = GSLC_ELEM_FEA_VALID | \
|
||||
GSLC_ELEM_FEA_GLOW_EN | GSLC_ELEM_FEA_FILL_EN; \
|
||||
static gslc_tsXProgress sGauge##nElemId; \
|
||||
sGauge##nElemId.nMin = nMin_; \
|
||||
sGauge##nElemId.nMax = nMax_; \
|
||||
sGauge##nElemId.nVal = nVal_; \
|
||||
sGauge##nElemId.nValLast = nVal_; \
|
||||
sGauge##nElemId.bValLastValid = false; \
|
||||
sGauge##nElemId.colGauge = colGauge_; \
|
||||
sGauge##nElemId.bVert = bVert_; \
|
||||
sGauge##nElemId.bFlip = false; \
|
||||
static const gslc_tsElem sElem##nElemId PROGMEM = { \
|
||||
nElemId, \
|
||||
nFeatures##nElemId, \
|
||||
GSLC_TYPEX_PROGRESS, \
|
||||
(gslc_tsRect){nX,nY,nW,nH}, \
|
||||
GSLC_GROUP_ID_NONE, \
|
||||
colFrame_,colFill_,colFrame_,colFill_, \
|
||||
(gslc_tsImgRef){NULL,NULL,GSLC_IMGREF_NONE,NULL}, \
|
||||
(gslc_tsImgRef){NULL,NULL,GSLC_IMGREF_NONE,NULL}, \
|
||||
NULL, \
|
||||
NULL, \
|
||||
0, \
|
||||
(gslc_teTxtFlags)(GSLC_TXT_DEFAULT), \
|
||||
GSLC_COL_WHITE, \
|
||||
GSLC_COL_WHITE, \
|
||||
GSLC_ALIGN_MID_MID, \
|
||||
0, \
|
||||
0, \
|
||||
NULL, \
|
||||
(void*)(&sGauge##nElemId), \
|
||||
NULL, \
|
||||
&gslc_ElemXProgressDraw, \
|
||||
NULL, \
|
||||
NULL, \
|
||||
}; \
|
||||
gslc_ElemAdd(pGui,nPage,(gslc_tsElem*)&sElem##nElemId, \
|
||||
(gslc_teElemRefFlags)(GSLC_ELEMREF_SRC_PROG | GSLC_ELEMREF_VISIBLE | GSLC_ELEMREF_REDRAW_FULL));
|
||||
|
||||
#else
|
||||
|
||||
|
||||
#define gslc_ElemXProgressCreate_P(pGui,nElemId,nPage,nX,nY,nW,nH,\
|
||||
nMin_,nMax_,nVal_,colFrame_,colFill_,colGauge_,bVert_) \
|
||||
static const uint8_t nFeatures##nElemId = GSLC_ELEM_FEA_VALID | \
|
||||
GSLC_ELEM_FEA_GLOW_EN | GSLC_ELEM_FEA_FILL_EN; \
|
||||
static gslc_tsXProgress sGauge##nElemId; \
|
||||
sGauge##nElemId.nMin = nMin_; \
|
||||
sGauge##nElemId.nMax = nMax_; \
|
||||
sGauge##nElemId.nVal = nVal_; \
|
||||
sGauge##nElemId.nValLast = nVal_; \
|
||||
sGauge##nElemId.bValLastValid = false; \
|
||||
sGauge##nElemId.colGauge = colGauge_; \
|
||||
sGauge##nElemId.bVert = bVert_; \
|
||||
sGauge##nElemId.bFlip = false; \
|
||||
static const gslc_tsElem sElem##nElemId = { \
|
||||
nElemId, \
|
||||
nFeatures##nElemId, \
|
||||
GSLC_TYPEX_PROGRESS, \
|
||||
(gslc_tsRect){nX,nY,nW,nH}, \
|
||||
GSLC_GROUP_ID_NONE, \
|
||||
colFrame_,colFill_,colFrame_,colFill_, \
|
||||
(gslc_tsImgRef){NULL,NULL,GSLC_IMGREF_NONE,NULL}, \
|
||||
(gslc_tsImgRef){NULL,NULL,GSLC_IMGREF_NONE,NULL}, \
|
||||
NULL, \
|
||||
NULL, \
|
||||
0, \
|
||||
(gslc_teTxtFlags)(GSLC_TXT_DEFAULT), \
|
||||
GSLC_COL_WHITE, \
|
||||
GSLC_COL_WHITE, \
|
||||
GSLC_ALIGN_MID_MID, \
|
||||
0, \
|
||||
0, \
|
||||
NULL, \
|
||||
(void*)(&sGauge##nElemId), \
|
||||
NULL, \
|
||||
&gslc_ElemXProgressDraw, \
|
||||
NULL, \
|
||||
NULL, \
|
||||
}; \
|
||||
gslc_ElemAdd(pGui,nPage,(gslc_tsElem*)&sElem##nElemId, \
|
||||
(gslc_teElemRefFlags)(GSLC_ELEMREF_SRC_CONST | GSLC_ELEMREF_VISIBLE | GSLC_ELEMREF_REDRAW_FULL));
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif // __cplusplus
|
||||
#endif // _GUISLICE_EX_XPROGRESS_H_
|
||||
|
363
src/guislice/XRadial.c
Normal file
363
src/guislice/XRadial.c
Normal file
|
@ -0,0 +1,363 @@
|
|||
// =======================================================================
|
||||
// GUIslice library (extensions)
|
||||
// - Calvin Hass
|
||||
// - https://www.impulseadventure.com/elec/guislice-gui.html
|
||||
// - https://github.com/ImpulseAdventure/GUIslice
|
||||
// =======================================================================
|
||||
//
|
||||
// The MIT License
|
||||
//
|
||||
// Copyright 2016-2020 Calvin Hass
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
//
|
||||
// =======================================================================
|
||||
/// \file XRadial.c
|
||||
|
||||
|
||||
|
||||
// GUIslice library
|
||||
#include "GUIslice.h"
|
||||
#include "GUIslice_drv.h"
|
||||
|
||||
#include "XRadial.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <math.h> // For sin/cos
|
||||
|
||||
#if (GSLC_USE_PROGMEM)
|
||||
#include <avr/pgmspace.h>
|
||||
#endif
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Error Messages
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
extern const char GSLC_PMEM ERRSTR_NULL[];
|
||||
extern const char GSLC_PMEM ERRSTR_PXD_NULL[];
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Extended element definitions
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// - This file extends the core GUIslice functionality with
|
||||
// additional widget types
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
|
||||
// ============================================================================
|
||||
// Extended Element: Radial Gauge
|
||||
// - A circular gauge that can be used to show direction or other
|
||||
// rotational values. Tick marks can be optionally drawn
|
||||
// around the gauge.
|
||||
// - Size, color and fill of the needle can be configured.
|
||||
// ============================================================================
|
||||
|
||||
// Create a radial gauge element and add it to the GUI element list
|
||||
// - Defines default styling for the element
|
||||
// - Defines callback for redraw but does not track touch/click
|
||||
gslc_tsElemRef* gslc_ElemXRadialCreate(gslc_tsGui* pGui,int16_t nElemId,int16_t nPage,
|
||||
gslc_tsXRadial* pXData,gslc_tsRect rElem,
|
||||
int16_t nMin,int16_t nMax,int16_t nVal,gslc_tsColor colGauge)
|
||||
{
|
||||
if ((pGui == NULL) || (pXData == NULL)) {
|
||||
static const char GSLC_PMEM FUNCSTR[] = "ElemXRadialCreate";
|
||||
GSLC_DEBUG2_PRINT_CONST(ERRSTR_NULL,FUNCSTR);
|
||||
return NULL;
|
||||
}
|
||||
gslc_tsElem sElem;
|
||||
gslc_tsElemRef* pElemRef = NULL;
|
||||
sElem = gslc_ElemCreate(pGui,nElemId,nPage,GSLC_TYPEX_RADIAL,rElem,NULL,0,GSLC_FONT_NONE);
|
||||
sElem.nFeatures |= GSLC_ELEM_FEA_FRAME_EN;
|
||||
sElem.nFeatures |= GSLC_ELEM_FEA_FILL_EN;
|
||||
sElem.nFeatures &= ~GSLC_ELEM_FEA_CLICK_EN; // Element is not "clickable"
|
||||
sElem.nFeatures &= ~GSLC_ELEM_FEA_GLOW_EN;
|
||||
sElem.nGroup = GSLC_GROUP_ID_NONE;
|
||||
pXData->nMin = nMin;
|
||||
pXData->nMax = nMax;
|
||||
pXData->nVal = nVal;
|
||||
pXData->bFlip = false;
|
||||
pXData->colGauge = colGauge;
|
||||
pXData->colTick = GSLC_COL_GRAY;
|
||||
pXData->nTickCnt = 8;
|
||||
pXData->nTickLen = 5;
|
||||
pXData->nIndicLen = 10; // Dummy default to be overridden
|
||||
pXData->nIndicTip = 3; // Dummy default to be overridden
|
||||
pXData->bIndicFill = false;
|
||||
sElem.pXData = (void*)(pXData);
|
||||
sElem.pfuncXDraw = &gslc_ElemXRadialDraw;
|
||||
sElem.pfuncXTouch = NULL; // No need to track touches
|
||||
sElem.colElemFill = GSLC_COL_BLACK;
|
||||
sElem.colElemFillGlow = GSLC_COL_BLACK;
|
||||
sElem.colElemFrame = GSLC_COL_GRAY;
|
||||
sElem.colElemFrameGlow = GSLC_COL_GRAY;
|
||||
if (nPage != GSLC_PAGE_NONE) {
|
||||
pElemRef = gslc_ElemAdd(pGui,nPage,&sElem,GSLC_ELEMREF_DEFAULT);
|
||||
return pElemRef;
|
||||
#if (GSLC_FEATURE_COMPOUND)
|
||||
} else {
|
||||
// Save as temporary element
|
||||
pGui->sElemTmp = sElem;
|
||||
pGui->sElemRefTmp.pElem = &(pGui->sElemTmp);
|
||||
pGui->sElemRefTmp.eElemFlags = GSLC_ELEMREF_DEFAULT | GSLC_ELEMREF_REDRAW_FULL;
|
||||
return &(pGui->sElemRefTmp);
|
||||
#endif
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
void gslc_ElemXRadialSetIndicator(gslc_tsGui* pGui,gslc_tsElemRef* pElemRef,gslc_tsColor colGauge,
|
||||
uint16_t nIndicLen,uint16_t nIndicTip,bool bIndicFill)
|
||||
{
|
||||
if (pElemRef == NULL) {
|
||||
static const char GSLC_PMEM FUNCSTR[] = "ElemXRadialSetIndicator";
|
||||
GSLC_DEBUG2_PRINT_CONST(ERRSTR_NULL,FUNCSTR);
|
||||
return;
|
||||
}
|
||||
gslc_tsXRadial* pGauge = (gslc_tsXRadial*)gslc_GetXDataFromRef(pGui,pElemRef,GSLC_TYPEX_RADIAL,__LINE__);
|
||||
|
||||
// Update the config
|
||||
pGauge->colGauge = colGauge;
|
||||
pGauge->nIndicLen = nIndicLen;
|
||||
pGauge->nIndicTip = nIndicTip;
|
||||
pGauge->bIndicFill = bIndicFill;
|
||||
|
||||
// Just in case we were called at runtime, mark as needing redraw
|
||||
gslc_ElemSetRedraw(pGui,pElemRef,GSLC_REDRAW_FULL);
|
||||
}
|
||||
|
||||
void gslc_ElemXRadialSetTicks(gslc_tsGui* pGui,gslc_tsElemRef* pElemRef,gslc_tsColor colTick,uint16_t nTickCnt,uint16_t nTickLen)
|
||||
{
|
||||
if (pElemRef == NULL) {
|
||||
static const char GSLC_PMEM FUNCSTR[] = "ElemXRadialSetTicks";
|
||||
GSLC_DEBUG2_PRINT_CONST(ERRSTR_NULL,FUNCSTR);
|
||||
return;
|
||||
}
|
||||
gslc_tsXRadial* pGauge = (gslc_tsXRadial*)gslc_GetXDataFromRef(pGui,pElemRef,GSLC_TYPEX_RADIAL,__LINE__);
|
||||
|
||||
// Update the config
|
||||
pGauge->colTick = colTick;
|
||||
pGauge->nTickCnt = nTickCnt;
|
||||
pGauge->nTickLen = nTickLen;
|
||||
|
||||
// Just in case we were called at runtime, mark as needing redraw
|
||||
gslc_ElemSetRedraw(pGui,pElemRef,GSLC_REDRAW_FULL);
|
||||
}
|
||||
|
||||
// Update the gauge control's current position
|
||||
void gslc_ElemXRadialSetVal(gslc_tsGui* pGui,gslc_tsElemRef* pElemRef,int16_t nVal)
|
||||
{
|
||||
if (pElemRef == NULL) {
|
||||
static const char GSLC_PMEM FUNCSTR[] = "ElemXRadialSetVal";
|
||||
GSLC_DEBUG2_PRINT_CONST(ERRSTR_NULL,FUNCSTR);
|
||||
return;
|
||||
}
|
||||
gslc_tsXRadial* pGauge = (gslc_tsXRadial*)gslc_GetXDataFromRef(pGui,pElemRef,GSLC_TYPEX_RADIAL,__LINE__);
|
||||
|
||||
// Update the data element
|
||||
int16_t nValOld = pGauge->nVal;
|
||||
pGauge->nVal = nVal;
|
||||
|
||||
// Element needs redraw
|
||||
if (nVal != nValOld) {
|
||||
// We only need an incremental redraw
|
||||
// NOTE: If the user configures the indicator to be
|
||||
// long enough that it overlaps some of the gauge indicators
|
||||
// then a full redraw should be done instead.
|
||||
gslc_ElemSetRedraw(pGui,pElemRef,GSLC_REDRAW_INC);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Update the gauge's rotation direction
|
||||
// - Setting bFlip reverses the rotation direction
|
||||
// - Default rotation is clockwise. When bFlip is set, uses counter-clockwise
|
||||
void gslc_ElemXRadialSetFlip(gslc_tsGui* pGui,gslc_tsElemRef* pElemRef,bool bFlip)
|
||||
{
|
||||
if (pElemRef == NULL) {
|
||||
static const char GSLC_PMEM FUNCSTR[] = "ElemXRadialSetFlip";
|
||||
GSLC_DEBUG2_PRINT_CONST(ERRSTR_NULL,FUNCSTR);
|
||||
return;
|
||||
}
|
||||
|
||||
// Fetch the element's extended data structure
|
||||
gslc_tsXRadial* pGauge = (gslc_tsXRadial*)gslc_GetXDataFromRef(pGui,pElemRef,GSLC_TYPEX_RADIAL,__LINE__);
|
||||
if (pGauge == NULL) {
|
||||
GSLC_DEBUG2_PRINT("ERROR: gslc_ElemXRadialSetFlip(%s) pXData is NULL\n","");
|
||||
return;
|
||||
}
|
||||
pGauge->bFlip = bFlip;
|
||||
|
||||
// Mark for redraw
|
||||
gslc_ElemSetRedraw(pGui,pElemRef,GSLC_REDRAW_FULL);
|
||||
|
||||
}
|
||||
|
||||
|
||||
// Redraw the gauge
|
||||
// - Note that this redraw is for the entire element rect region
|
||||
// - The Draw function parameters use void pointers to allow for
|
||||
// simpler callback function definition & scalability.
|
||||
bool gslc_ElemXRadialDraw(void* pvGui,void* pvElemRef,gslc_teRedrawType eRedraw)
|
||||
{
|
||||
if ((pvGui == NULL) || (pvElemRef == NULL)) {
|
||||
static const char GSLC_PMEM FUNCSTR[] = "ElemXRadialDraw";
|
||||
GSLC_DEBUG2_PRINT_CONST(ERRSTR_NULL,FUNCSTR);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Typecast the parameters to match the GUI and element types
|
||||
gslc_tsGui* pGui = (gslc_tsGui*)(pvGui);
|
||||
gslc_tsElemRef* pElemRef = (gslc_tsElemRef*)(pvElemRef);
|
||||
|
||||
// Fetch the element's extended data structure
|
||||
gslc_tsXRadial* pGauge = (gslc_tsXRadial*)gslc_GetXDataFromRef(pGui,pElemRef,GSLC_TYPEX_RADIAL,__LINE__);
|
||||
|
||||
gslc_ElemXRadialDrawRadial(pGui,pElemRef,eRedraw);
|
||||
|
||||
// Save as "last state" to support incremental erase/redraw
|
||||
pGauge->nValLast = pGauge->nVal;
|
||||
pGauge->bValLastValid = true;
|
||||
|
||||
// Clear the redraw flag
|
||||
gslc_ElemSetRedraw(pGui,pElemRef,GSLC_REDRAW_NONE);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void gslc_ElemXRadialDrawRadialHelp(gslc_tsGui* pGui,int16_t nX,int16_t nY,uint16_t nArrowLen,uint16_t nArrowSz,int16_t n64Ang,bool bFill,gslc_tsColor colFrame)
|
||||
{
|
||||
int16_t nTipX,nTipY;
|
||||
int16_t nBaseX1,nBaseY1,nBaseX2,nBaseY2;
|
||||
int16_t nTipBaseX,nTipBaseY;
|
||||
|
||||
gslc_PolarToXY(nArrowLen,n64Ang,&nTipX,&nTipY);
|
||||
gslc_PolarToXY(nArrowLen-nArrowSz,n64Ang,&nTipBaseX,&nTipBaseY);
|
||||
gslc_PolarToXY(nArrowSz,n64Ang-90*64,&nBaseX1,&nBaseY1);
|
||||
gslc_PolarToXY(nArrowSz,n64Ang+90*64,&nBaseX2,&nBaseY2);
|
||||
|
||||
// FIXME: There appears to be a wrapping bug in the trigonometry
|
||||
// calculations associated with the bottom-right corner
|
||||
// of the pointer body when angles approach 359 degrees.
|
||||
|
||||
if (!bFill) {
|
||||
// Framed
|
||||
gslc_DrawLine(pGui,nX+nBaseX1,nY+nBaseY1,nX+nBaseX1+nTipBaseX,nY+nBaseY1+nTipBaseY,colFrame);
|
||||
gslc_DrawLine(pGui,nX+nBaseX2,nY+nBaseY2,nX+nBaseX2+nTipBaseX,nY+nBaseY2+nTipBaseY,colFrame);
|
||||
gslc_DrawLine(pGui,nX+nBaseX1+nTipBaseX,nY+nBaseY1+nTipBaseY,nX+nTipX,nY+nTipY,colFrame);
|
||||
gslc_DrawLine(pGui,nX+nBaseX2+nTipBaseX,nY+nBaseY2+nTipBaseY,nX+nTipX,nY+nTipY,colFrame);
|
||||
gslc_DrawLine(pGui,nX+nBaseX1,nY+nBaseY1,nX+nBaseX2,nY+nBaseY2,colFrame);
|
||||
|
||||
} else {
|
||||
// Filled
|
||||
gslc_tsPt asPt[4];
|
||||
|
||||
// Main body of pointer
|
||||
asPt[0] = (gslc_tsPt){nX+nBaseX1,nY+nBaseY1};
|
||||
asPt[1] = (gslc_tsPt){nX+nBaseX1+nTipBaseX,nY+nBaseY1+nTipBaseY};
|
||||
asPt[2] = (gslc_tsPt){nX+nBaseX2+nTipBaseX,nY+nBaseY2+nTipBaseY};
|
||||
asPt[3] = (gslc_tsPt){nX+nBaseX2,nY+nBaseY2};
|
||||
gslc_DrawFillQuad(pGui,asPt,colFrame);
|
||||
|
||||
// Tip of pointer
|
||||
asPt[0] = (gslc_tsPt){nX+nBaseX1+nTipBaseX,nY+nBaseY1+nTipBaseY};
|
||||
asPt[1] = (gslc_tsPt){nX+nTipX,nY+nTipY};
|
||||
asPt[2] = (gslc_tsPt){nX+nBaseX2+nTipBaseX,nY+nBaseY2+nTipBaseY};
|
||||
gslc_DrawFillTriangle(pGui,asPt[0].x,asPt[0].y,asPt[1].x,asPt[1].y,asPt[2].x,asPt[2].y,colFrame);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
bool gslc_ElemXRadialDrawRadial(gslc_tsGui* pGui,gslc_tsElemRef* pElemRef,gslc_teRedrawType eRedraw)
|
||||
{
|
||||
gslc_tsElem* pElem = gslc_GetElemFromRef(pGui,pElemRef);
|
||||
gslc_tsXRadial* pGauge = (gslc_tsXRadial*)gslc_GetXDataFromRef(pGui,pElemRef,GSLC_TYPEX_RADIAL,__LINE__);
|
||||
|
||||
uint16_t nElemW,nElemH,nElemRad;
|
||||
int16_t nElemX0,nElemY0,nElemX1,nElemY1;
|
||||
int16_t nElemMidX,nElemMidY;
|
||||
nElemX0 = pElem->rElem.x;
|
||||
nElemY0 = pElem->rElem.y;
|
||||
nElemX1 = pElem->rElem.x + pElem->rElem.w - 1;
|
||||
nElemY1 = pElem->rElem.y + pElem->rElem.h - 1;
|
||||
nElemMidX = (nElemX0+nElemX1)/2;
|
||||
nElemMidY = (nElemY0+nElemY1)/2;
|
||||
nElemW = pElem->rElem.w;
|
||||
nElemH = pElem->rElem.h;
|
||||
nElemRad = (nElemW>=nElemH)? nElemH/2 : nElemW/2;
|
||||
|
||||
int16_t nMax = pGauge->nMax;
|
||||
int16_t nMin = pGauge->nMin;
|
||||
int16_t nRng = pGauge->nMax - pGauge->nMin;
|
||||
int16_t nVal = pGauge->nVal;
|
||||
int16_t nValLast = pGauge->nValLast;
|
||||
bool bValLastValid = pGauge->bValLastValid;
|
||||
uint16_t nTickLen = pGauge->nTickLen;
|
||||
uint16_t nTickAng = 360 / pGauge->nTickCnt;
|
||||
uint16_t nArrowLen = pGauge->nIndicLen;
|
||||
uint16_t nArrowSize = pGauge->nIndicTip;
|
||||
bool bFill = pGauge->bIndicFill;
|
||||
|
||||
int16_t n64Ang,n64AngLast;
|
||||
int16_t nInd;
|
||||
|
||||
|
||||
if (nRng == 0) {
|
||||
GSLC_DEBUG2_PRINT("ERROR: ElemXRadialDraw() Zero range [%d,%d]\n",nMin,nMax);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Support reversing of direction
|
||||
// TODO: Clean up excess integer typecasting
|
||||
if (pGauge->bFlip) {
|
||||
n64Ang = (int32_t)(nMax - nVal )* 360*64 /nRng;
|
||||
n64AngLast = (int32_t)(nMax - nValLast)* 360*64 /nRng;
|
||||
} else {
|
||||
n64Ang = (int32_t)(nVal - nMin)* 360*64 /nRng;
|
||||
n64AngLast = (int32_t)(nValLast - nMin)* 360*64 /nRng;
|
||||
}
|
||||
|
||||
// Clear old
|
||||
if (bValLastValid) {
|
||||
gslc_ElemXRadialDrawRadialHelp(pGui,nElemMidX,nElemMidY,nArrowLen,nArrowSize,n64AngLast,bFill,pElem->colElemFill);
|
||||
}
|
||||
|
||||
// Draw frame
|
||||
if (eRedraw == GSLC_REDRAW_FULL) {
|
||||
gslc_DrawFillCircle(pGui,nElemMidX,nElemMidY,nElemRad,pElem->colElemFill); // Erase first
|
||||
gslc_DrawFrameCircle(pGui,nElemMidX,nElemMidY,nElemRad,pElem->colElemFrame);
|
||||
for (nInd=0;nInd<360;nInd+=nTickAng) {
|
||||
gslc_DrawLinePolar(pGui,nElemMidX,nElemMidY,nElemRad-nTickLen,nElemRad,nInd*64,pGauge->colTick);
|
||||
}
|
||||
}
|
||||
|
||||
// Draw pointer
|
||||
gslc_ElemXRadialDrawRadialHelp(pGui,nElemMidX,nElemMidY,nArrowLen,nArrowSize,n64Ang,bFill,pGauge->colGauge);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// ============================================================================
|
327
src/guislice/XRadial.h
Normal file
327
src/guislice/XRadial.h
Normal file
|
@ -0,0 +1,327 @@
|
|||
#ifndef _GUISLICE_EX_XRADIAL_H_
|
||||
#define _GUISLICE_EX_XRADIAL_H_
|
||||
|
||||
#include "GUIslice.h"
|
||||
|
||||
|
||||
// =======================================================================
|
||||
// GUIslice library extension: Radial control
|
||||
// - Calvin Hass
|
||||
// - https://www.impulseadventure.com/elec/guislice-gui.html
|
||||
// - https://github.com/ImpulseAdventure/GUIslice
|
||||
// =======================================================================
|
||||
//
|
||||
// The MIT License
|
||||
//
|
||||
// Copyright 2016-2020 Calvin Hass
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
//
|
||||
// =======================================================================
|
||||
/// \file XRadial.h
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif // __cplusplus
|
||||
|
||||
|
||||
// ============================================================================
|
||||
// Extended Element: Radial Gauge
|
||||
// - A circular gauge that can be used to show direction or other
|
||||
// rotational values. Tick marks can be optionally drawn
|
||||
// around the gauge.
|
||||
// - Size, color and fill of the needle can be configured.
|
||||
// ============================================================================
|
||||
|
||||
// Define unique identifier for extended element type
|
||||
// - Select any number above GSLC_TYPE_BASE_EXTEND
|
||||
#define GSLC_TYPEX_RADIAL GSLC_TYPE_BASE_EXTEND + 61
|
||||
|
||||
|
||||
// Extended element data structures
|
||||
// - These data structures are maintained in the gslc_tsElem
|
||||
// structure via the pXData pointer
|
||||
|
||||
/// Extended data for Gauge element
|
||||
typedef struct {
|
||||
// Range config
|
||||
int16_t nMin; ///< Minimum control value
|
||||
int16_t nMax; ///< Maximum control value
|
||||
|
||||
// Current value
|
||||
int16_t nVal; ///< Current control value
|
||||
// Previous value
|
||||
int16_t nValLast; ///< Last value
|
||||
bool bValLastValid; ///< Last value valid?
|
||||
|
||||
// Appearance config
|
||||
gslc_tsColor colGauge; ///< Color of gauge fill bar
|
||||
gslc_tsColor colTick; ///< Color of gauge tick marks
|
||||
uint16_t nTickCnt; ///< Number of gauge tick marks
|
||||
uint16_t nTickLen; ///< Length of gauge tick marks
|
||||
bool bFlip; ///< Reverse direction of gauge
|
||||
uint16_t nIndicLen; ///< Indicator length
|
||||
uint16_t nIndicTip; ///< Size of tip at end of indicator
|
||||
bool bIndicFill; ///< Fill the indicator if true
|
||||
|
||||
} gslc_tsXRadial;
|
||||
|
||||
|
||||
///
|
||||
/// Create a Radial Gauge Element
|
||||
/// - Draws a gauge element that represents a proportion (nVal)
|
||||
/// between nMin and nMax.
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] nElemId: Element ID to assign (0..16383 or GSLC_ID_AUTO to autogen)
|
||||
/// \param[in] nPage: Page ID to attach element to
|
||||
/// \param[in] pXData: Ptr to extended element data structure
|
||||
/// \param[in] rElem: Rectangle coordinates defining gauge size
|
||||
/// \param[in] nMin: Minimum value of gauge for nVal comparison
|
||||
/// \param[in] nMax: Maximum value of gauge for nVal comparison
|
||||
/// \param[in] nVal: Starting value of gauge
|
||||
/// \param[in] colGauge: Color for the gauge indicator
|
||||
///
|
||||
/// \return Pointer to Element reference or NULL if failure
|
||||
///
|
||||
gslc_tsElemRef* gslc_ElemXRadialCreate(gslc_tsGui* pGui,int16_t nElemId,int16_t nPage,
|
||||
gslc_tsXRadial* pXData,gslc_tsRect rElem,int16_t nMin,int16_t nMax,int16_t nVal,gslc_tsColor colGauge);
|
||||
|
||||
|
||||
|
||||
///
|
||||
/// Configure the appearance of the Gauge indicator
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] pElemRef: Pointer to Element reference
|
||||
/// \param[in] colGauge: Color of the indicator
|
||||
/// \param[in] nIndicLen: Length of the indicator
|
||||
/// \param[in] nIndicTip: Size of the indicator tip
|
||||
/// \param[in] bIndicFill: Fill in the indicator if true
|
||||
///
|
||||
/// \return none
|
||||
///
|
||||
void gslc_ElemXRadialSetIndicator(gslc_tsGui* pGui,gslc_tsElemRef* pElemRef,gslc_tsColor colGauge,
|
||||
uint16_t nIndicLen,uint16_t nIndicTip,bool bIndicFill);
|
||||
|
||||
|
||||
///
|
||||
/// Configure the appearance of the Gauge ticks
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] pElemRef: Pointer to Element reference
|
||||
/// \param[in] colTick: Color of the gauge ticks
|
||||
/// \param[in] nTickCnt: Number of ticks to draw around / along gauge
|
||||
/// \param[in] nTickLen: Length of the tick marks to draw
|
||||
///
|
||||
/// \return none
|
||||
///
|
||||
void gslc_ElemXRadialSetTicks(gslc_tsGui* pGui,gslc_tsElemRef* pElemRef,gslc_tsColor colTick,uint16_t nTickCnt,uint16_t nTickLen);
|
||||
|
||||
|
||||
///
|
||||
/// Update a Gauge element's current value
|
||||
/// - Note that min & max values are assigned in create()
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] pElemRef: Pointer to Element reference
|
||||
/// \param[in] nVal: New value to show in gauge
|
||||
///
|
||||
/// \return none
|
||||
///
|
||||
void gslc_ElemXRadialSetVal(gslc_tsGui* pGui,gslc_tsElemRef* pElemRef,int16_t nVal);
|
||||
|
||||
|
||||
///
|
||||
/// Set a Gauge element's rotation direction
|
||||
/// - Setting bFlip reverses the rotation direction
|
||||
/// - Default rotation is clockwise. When bFlip is set, uses counter-clockwise
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] pElemRef: Pointer to Element reference
|
||||
/// \param[in] bFlip: If set, reverse direction of rotation from default
|
||||
///
|
||||
/// \return none
|
||||
///
|
||||
void gslc_ElemXRadialSetFlip(gslc_tsGui* pGui,gslc_tsElemRef* pElemRef,bool bFlip);
|
||||
|
||||
|
||||
///
|
||||
/// Draw a gauge element on the screen
|
||||
/// - Called from gslc_ElemDraw()
|
||||
///
|
||||
/// \param[in] pvGui: Void ptr to GUI (typecast to gslc_tsGui*)
|
||||
/// \param[in] pvElemRef: Void ptr to Element reference (typecast to gslc_tsElemRef*)
|
||||
/// \param[in] eRedraw: Redraw mode
|
||||
///
|
||||
/// \return true if success, false otherwise
|
||||
///
|
||||
bool gslc_ElemXRadialDraw(void* pvGui,void* pvElemRef,gslc_teRedrawType eRedraw);
|
||||
|
||||
|
||||
///
|
||||
/// Helper function to draw a gauge with style: radial
|
||||
/// - Called from gslc_ElemXRadialDraw()
|
||||
///
|
||||
/// \param[in] pGui: Ptr to GUI
|
||||
/// \param[in] pElemRef: Ptr to Element reference
|
||||
/// \param[in] eRedraw: Redraw status
|
||||
///
|
||||
/// \return true if success, false otherwise
|
||||
///
|
||||
bool gslc_ElemXRadialDrawRadial(gslc_tsGui* pGui,gslc_tsElemRef* pElemRef,gslc_teRedrawType eRedraw);
|
||||
|
||||
|
||||
// ============================================================================
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Read-only element macros
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
// Macro initializers for Read-Only Elements in Flash/PROGMEM
|
||||
//
|
||||
|
||||
/// \def gslc_ElemXRadialCreate_P(pGui,nElemId,nPage,nX,nY,nW,nH,
|
||||
/// nMin_,nMax_,nVal_,colFrame_,colFill_,colGauge_)
|
||||
///
|
||||
/// Create a Gauge Element in Flash
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] nElemId: Unique element ID to assign
|
||||
/// \param[in] nPage: Page ID to attach element to
|
||||
/// \param[in] nX: X coordinate of element
|
||||
/// \param[in] nY: Y coordinate of element
|
||||
/// \param[in] nW: Width of element
|
||||
/// \param[in] nH: Height of element
|
||||
/// \param[in] nMin_: Minimum value of gauge for nVal comparison
|
||||
/// \param[in] nMax_: Maximum value of gauge for nVal comparison
|
||||
/// \param[in] nVal_: Starting value of gauge
|
||||
/// \param[in] colFrame_: Color for the gauge frame
|
||||
/// \param[in] colFill_: Color for the gauge background fill
|
||||
/// \param[in] colGauge_: Color for the gauge indicator
|
||||
///
|
||||
/// \return none
|
||||
///
|
||||
|
||||
|
||||
#if (GSLC_USE_PROGMEM)
|
||||
|
||||
|
||||
#define gslc_ElemXRadialCreate_P(pGui,nElemId,nPage,nX,nY,nW,nH,\
|
||||
nMin_,nMax_,nVal_,colFrame_,colFill_,colGauge_) \
|
||||
static const uint8_t nFeatures##nElemId = GSLC_ELEM_FEA_VALID | \
|
||||
GSLC_ELEM_FEA_GLOW_EN | GSLC_ELEM_FEA_FILL_EN; \
|
||||
static gslc_tsXRadial sGauge##nElemId; \
|
||||
sGauge##nElemId.nMin = nMin_; \
|
||||
sGauge##nElemId.nMax = nMax_; \
|
||||
sGauge##nElemId.nVal = nVal_; \
|
||||
sGauge##nElemId.nValLast = nVal_; \
|
||||
sGauge##nElemId.bValLastValid = false; \
|
||||
sGauge##nElemId.colGauge = colGauge_; \
|
||||
sGauge##nElemId.colTick = GSLC_COL_GRAY; \
|
||||
sGauge##nElemId.nTickCnt = 8; \
|
||||
sGauge##nElemId.nTickLen = 5; \
|
||||
sGauge##nElemId.bFlip = false; \
|
||||
sGauge##nElemId.nIndicLen = 10; \
|
||||
sGauge##nElemId.nIndicTip = 3; \
|
||||
sGauge##nElemId.bIndicFill = false; \
|
||||
static const gslc_tsElem sElem##nElemId PROGMEM = { \
|
||||
nElemId, \
|
||||
nFeatures##nElemId, \
|
||||
GSLC_TYPEX_RADIAL, \
|
||||
(gslc_tsRect){nX,nY,nW,nH}, \
|
||||
GSLC_GROUP_ID_NONE, \
|
||||
colFrame_,colFill_,colFrame_,colFill_, \
|
||||
(gslc_tsImgRef){NULL,NULL,GSLC_IMGREF_NONE,NULL}, \
|
||||
(gslc_tsImgRef){NULL,NULL,GSLC_IMGREF_NONE,NULL}, \
|
||||
NULL, \
|
||||
NULL, \
|
||||
0, \
|
||||
(gslc_teTxtFlags)(GSLC_TXT_DEFAULT), \
|
||||
GSLC_COL_WHITE, \
|
||||
GSLC_COL_WHITE, \
|
||||
GSLC_ALIGN_MID_MID, \
|
||||
0, \
|
||||
0, \
|
||||
NULL, \
|
||||
(void*)(&sGauge##nElemId), \
|
||||
NULL, \
|
||||
&gslc_ElemXRadialDraw, \
|
||||
NULL, \
|
||||
NULL, \
|
||||
}; \
|
||||
gslc_ElemAdd(pGui,nPage,(gslc_tsElem*)&sElem##nElemId, \
|
||||
(gslc_teElemRefFlags)(GSLC_ELEMREF_SRC_PROG | GSLC_ELEMREF_VISIBLE | GSLC_ELEMREF_REDRAW_FULL));
|
||||
|
||||
#else
|
||||
|
||||
|
||||
#define gslc_ElemXRadialCreate_P(pGui,nElemId,nPage,nX,nY,nW,nH,\
|
||||
nMin_,nMax_,nVal_,colFrame_,colFill_,colGauge_) \
|
||||
static const uint8_t nFeatures##nElemId = GSLC_ELEM_FEA_VALID | \
|
||||
GSLC_ELEM_FEA_GLOW_EN | GSLC_ELEM_FEA_FILL_EN; \
|
||||
static gslc_tsXRadial sGauge##nElemId; \
|
||||
sGauge##nElemId.nMin = nMin_; \
|
||||
sGauge##nElemId.nMax = nMax_; \
|
||||
sGauge##nElemId.nVal = nVal_; \
|
||||
sGauge##nElemId.nValLast = nVal_; \
|
||||
sGauge##nElemId.bValLastValid = false; \
|
||||
sGauge##nElemId.colGauge = colGauge_; \
|
||||
sGauge##nElemId.colTick = GSLC_COL_GRAY; \
|
||||
sGauge##nElemId.nTickCnt = 8; \
|
||||
sGauge##nElemId.nTickLen = 5; \
|
||||
sGauge##nElemId.bFlip = false; \
|
||||
sGauge##nElemId.nIndicLen = 10; \
|
||||
sGauge##nElemId.nIndicTip = 3; \
|
||||
sGauge##nElemId.bIndicFill = false; \
|
||||
static const gslc_tsElem sElem##nElemId = { \
|
||||
nElemId, \
|
||||
nFeatures##nElemId, \
|
||||
GSLC_TYPEX_RADIAL, \
|
||||
(gslc_tsRect){nX,nY,nW,nH}, \
|
||||
GSLC_GROUP_ID_NONE, \
|
||||
colFrame_,colFill_,colFrame_,colFill_, \
|
||||
(gslc_tsImgRef){NULL,NULL,GSLC_IMGREF_NONE,NULL}, \
|
||||
(gslc_tsImgRef){NULL,NULL,GSLC_IMGREF_NONE,NULL}, \
|
||||
NULL, \
|
||||
NULL, \
|
||||
0, \
|
||||
(gslc_teTxtFlags)(GSLC_TXT_DEFAULT), \
|
||||
GSLC_COL_WHITE, \
|
||||
GSLC_COL_WHITE, \
|
||||
GSLC_ALIGN_MID_MID, \
|
||||
0, \
|
||||
0, \
|
||||
NULL, \
|
||||
(void*)(&sGauge##nElemId), \
|
||||
NULL, \
|
||||
&gslc_ElemXRadialDraw, \
|
||||
NULL, \
|
||||
NULL, \
|
||||
}; \
|
||||
gslc_ElemAdd(pGui,nPage,(gslc_tsElem*)&sElem##nElemId, \
|
||||
(gslc_teElemRefFlags)(GSLC_ELEMREF_SRC_CONST | GSLC_ELEMREF_VISIBLE | GSLC_ELEMREF_REDRAW_FULL));
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif // __cplusplus
|
||||
#endif // _GUISLICE_EX_XRADIAL_H_
|
||||
|
300
src/guislice/XRamp.c
Normal file
300
src/guislice/XRamp.c
Normal file
|
@ -0,0 +1,300 @@
|
|||
// =======================================================================
|
||||
// GUIslice library (extensions)
|
||||
// - Calvin Hass
|
||||
// - https://www.impulseadventure.com/elec/guislice-gui.html
|
||||
// - https://github.com/ImpulseAdventure/GUIslice
|
||||
// =======================================================================
|
||||
//
|
||||
// The MIT License
|
||||
//
|
||||
// Copyright 2016-2020 Calvin Hass
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
//
|
||||
// =======================================================================
|
||||
/// \file XRamp.c
|
||||
|
||||
|
||||
|
||||
// GUIslice library
|
||||
#include "GUIslice.h"
|
||||
#include "GUIslice_drv.h"
|
||||
|
||||
#include "XRamp.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#if (GSLC_USE_PROGMEM)
|
||||
#include <avr/pgmspace.h>
|
||||
#endif
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Error Messages
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
extern const char GSLC_PMEM ERRSTR_NULL[];
|
||||
extern const char GSLC_PMEM ERRSTR_PXD_NULL[];
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Extended element definitions
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// - This file extends the core GUIslice functionality with
|
||||
// additional widget types
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
|
||||
// ============================================================================
|
||||
// Extended Element: Ramp Gauge
|
||||
// - Demonstration of a gradient ramp (green-yellow-red) visual
|
||||
// control similar to certain linear tachometers.
|
||||
// - The ramp rises up and to the right according to the
|
||||
// current value.
|
||||
// - Note that this element is mainly intended as a demonstration
|
||||
// example. Additional APIs would be recommended to make it
|
||||
// more configurable.
|
||||
// ============================================================================
|
||||
|
||||
// Create a gauge element and add it to the GUI element list
|
||||
// - Defines default styling for the element
|
||||
// - Defines callback for redraw but does not track touch/click
|
||||
gslc_tsElemRef* gslc_ElemXRampCreate(gslc_tsGui* pGui,int16_t nElemId,int16_t nPage,
|
||||
gslc_tsXRamp* pXData,gslc_tsRect rElem,
|
||||
int16_t nMin,int16_t nMax,int16_t nVal,gslc_tsColor colGauge,bool bVert)
|
||||
{
|
||||
if ((pGui == NULL) || (pXData == NULL)) {
|
||||
static const char GSLC_PMEM FUNCSTR[] = "ElemXRampCreate";
|
||||
GSLC_DEBUG2_PRINT_CONST(ERRSTR_NULL,FUNCSTR);
|
||||
return NULL;
|
||||
}
|
||||
gslc_tsElem sElem;
|
||||
gslc_tsElemRef* pElemRef = NULL;
|
||||
sElem = gslc_ElemCreate(pGui,nElemId,nPage,GSLC_TYPEX_RAMP,rElem,NULL,0,GSLC_FONT_NONE);
|
||||
sElem.nFeatures |= GSLC_ELEM_FEA_FRAME_EN;
|
||||
sElem.nFeatures |= GSLC_ELEM_FEA_FILL_EN;
|
||||
sElem.nFeatures &= ~GSLC_ELEM_FEA_CLICK_EN; // Element is not "clickable"
|
||||
sElem.nFeatures &= ~GSLC_ELEM_FEA_GLOW_EN;
|
||||
sElem.nGroup = GSLC_GROUP_ID_NONE;
|
||||
pXData->nMin = nMin;
|
||||
pXData->nMax = nMax;
|
||||
pXData->nVal = nVal;
|
||||
sElem.pXData = (void*)(pXData);
|
||||
sElem.pfuncXDraw = &gslc_ElemXRampDraw;
|
||||
sElem.pfuncXTouch = NULL; // No need to track touches
|
||||
sElem.colElemFill = GSLC_COL_BLACK;
|
||||
sElem.colElemFillGlow = GSLC_COL_BLACK;
|
||||
sElem.colElemFrame = GSLC_COL_GRAY;
|
||||
sElem.colElemFrameGlow = GSLC_COL_GRAY;
|
||||
if (nPage != GSLC_PAGE_NONE) {
|
||||
pElemRef = gslc_ElemAdd(pGui,nPage,&sElem,GSLC_ELEMREF_DEFAULT);
|
||||
return pElemRef;
|
||||
#if (GSLC_FEATURE_COMPOUND)
|
||||
} else {
|
||||
// Save as temporary element
|
||||
pGui->sElemTmp = sElem;
|
||||
pGui->sElemRefTmp.pElem = &(pGui->sElemTmp);
|
||||
pGui->sElemRefTmp.eElemFlags = GSLC_ELEMREF_DEFAULT | GSLC_ELEMREF_REDRAW_FULL;
|
||||
return &(pGui->sElemRefTmp);
|
||||
#endif
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
// Update the gauge control's current position
|
||||
void gslc_ElemXRampSetVal(gslc_tsGui* pGui,gslc_tsElemRef* pElemRef,int16_t nVal)
|
||||
{
|
||||
if (pElemRef == NULL) {
|
||||
static const char GSLC_PMEM FUNCSTR[] = "ElemXRampSetVal";
|
||||
GSLC_DEBUG2_PRINT_CONST(ERRSTR_NULL,FUNCSTR);
|
||||
return;
|
||||
}
|
||||
gslc_tsXRamp* pGauge = (gslc_tsXRamp*)gslc_GetXDataFromRef(pGui,pElemRef,GSLC_TYPEX_RAMP,__LINE__);
|
||||
|
||||
// Update the data element
|
||||
int16_t nValOld = pGauge->nVal;
|
||||
pGauge->nVal = nVal;
|
||||
|
||||
// Element needs redraw
|
||||
if (nVal != nValOld) {
|
||||
// We only need an incremental redraw
|
||||
// NOTE: If the user configures the indicator to be
|
||||
// long enough that it overlaps some of the gauge indicators
|
||||
// then a full redraw should be done instead.
|
||||
gslc_ElemSetRedraw(pGui,pElemRef,GSLC_REDRAW_INC);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
// Redraw the gauge
|
||||
// - Note that this redraw is for the entire element rect region
|
||||
// - The Draw function parameters use void pointers to allow for
|
||||
// simpler callback function definition & scalability.
|
||||
bool gslc_ElemXRampDraw(void* pvGui,void* pvElemRef,gslc_teRedrawType eRedraw)
|
||||
{
|
||||
if ((pvGui == NULL) || (pvElemRef == NULL)) {
|
||||
static const char GSLC_PMEM FUNCSTR[] = "ElemXRampDraw";
|
||||
GSLC_DEBUG2_PRINT_CONST(ERRSTR_NULL,FUNCSTR);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Typecast the parameters to match the GUI and element types
|
||||
gslc_tsGui* pGui = (gslc_tsGui*)(pvGui);
|
||||
gslc_tsElemRef* pElemRef = (gslc_tsElemRef*)(pvElemRef);
|
||||
|
||||
// Fetch the element's extended data structure
|
||||
gslc_tsXRamp* pGauge = (gslc_tsXRamp*)gslc_GetXDataFromRef(pGui,pElemRef,GSLC_TYPEX_RAMP,__LINE__);
|
||||
|
||||
gslc_ElemXRampDrawHelp(pGui,pElemRef,eRedraw);
|
||||
|
||||
// Save as "last state" to support incremental erase/redraw
|
||||
pGauge->nValLast = pGauge->nVal;
|
||||
pGauge->bValLastValid = true;
|
||||
|
||||
// Clear the redraw flag
|
||||
gslc_ElemSetRedraw(pGui,pElemRef,GSLC_REDRAW_NONE);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool gslc_ElemXRampDrawHelp(gslc_tsGui* pGui,gslc_tsElemRef* pElemRef,gslc_teRedrawType eRedraw)
|
||||
{
|
||||
gslc_tsElem* pElem = gslc_GetElemFromRef(pGui,pElemRef);
|
||||
gslc_tsXRamp* pGauge = (gslc_tsXRamp*)gslc_GetXDataFromRef(pGui,pElemRef,GSLC_TYPEX_RAMP,__LINE__);
|
||||
|
||||
uint16_t nElemW,nElemH;
|
||||
int16_t nElemX0,nElemY1;
|
||||
nElemX0 = pElem->rElem.x;
|
||||
nElemY1 = pElem->rElem.y + pElem->rElem.h - 1;
|
||||
nElemW = pElem->rElem.w;
|
||||
nElemH = pElem->rElem.h;
|
||||
|
||||
int16_t nMax = pGauge->nMax;
|
||||
int16_t nMin = pGauge->nMin;
|
||||
int16_t nRng = pGauge->nMax - pGauge->nMin;
|
||||
int16_t nVal = pGauge->nVal;
|
||||
int16_t nValLast = pGauge->nValLast;
|
||||
bool bValLastValid = pGauge->bValLastValid;
|
||||
int16_t nInd;
|
||||
|
||||
if (nRng == 0) {
|
||||
GSLC_DEBUG2_PRINT("ERROR: gslc_ElemXRampDrawHelp() Zero range [%d,%d]\n",nMin,nMax);
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t nSclFX;
|
||||
uint16_t nHeight;
|
||||
int32_t nHeightTmp;
|
||||
uint16_t nHeightBot;
|
||||
uint16_t nX;
|
||||
uint16_t nColInd;
|
||||
|
||||
// Calculate region to draw or clear
|
||||
bool bModeErase;
|
||||
int16_t nValStart;
|
||||
int16_t nValEnd;
|
||||
if ((eRedraw == GSLC_REDRAW_INC) && (!bValLastValid)) {
|
||||
// - If the request was incremental (GSLC_REDRAW_INC) but
|
||||
// the last value wasn't marked as valid (!bValLastValid)
|
||||
// then we want to force a full redraw.
|
||||
// - We don't expect to enter here since bValLastValid
|
||||
// should always be set after we perform our first
|
||||
// redraw.
|
||||
eRedraw = GSLC_REDRAW_FULL;
|
||||
}
|
||||
if (eRedraw == GSLC_REDRAW_FULL) {
|
||||
// If we haven't drawn anything before, draw full range from zero
|
||||
bModeErase = false;
|
||||
nValStart = 0;
|
||||
nValEnd = nVal;
|
||||
} else {
|
||||
if (nVal >= nValLast) {
|
||||
// As we are advancing the control, we just draw the new range
|
||||
bModeErase = false;
|
||||
nValStart = nValLast;
|
||||
nValEnd = nVal;
|
||||
} else {
|
||||
// Since we are retracting the control, we erase the new range
|
||||
bModeErase = true;
|
||||
nValStart = nVal;
|
||||
nValEnd = nValLast;
|
||||
}
|
||||
}
|
||||
|
||||
// Calculate the scaled gauge position
|
||||
// - TODO: Also support reversing of direction
|
||||
int16_t nPosXStart,nPosXEnd;
|
||||
nPosXStart = (nValStart - nMin)*nElemW/nRng;
|
||||
nPosXEnd = (nValEnd - nMin)*nElemW/nRng;
|
||||
|
||||
nSclFX = (uint32_t)nElemH*32767/(nElemW*nElemW);
|
||||
|
||||
for (nX=nPosXStart;nX<nPosXEnd;nX++) {
|
||||
nInd = nElemW-nX;
|
||||
nHeightTmp = nSclFX * nInd*nInd /32767;
|
||||
nHeight = nElemH-nHeightTmp;
|
||||
if (nHeight >= 20) {
|
||||
nHeightBot = nHeight-20;
|
||||
} else {
|
||||
nHeightBot = 0;
|
||||
}
|
||||
gslc_tsColor nCol;
|
||||
uint16_t nSteps = 10;
|
||||
uint16_t nGap = 3;
|
||||
|
||||
if (nSteps == 0) {
|
||||
nColInd = nX*1000/nElemW;
|
||||
nCol = gslc_ColorBlend3(GSLC_COL_GREEN,GSLC_COL_YELLOW,GSLC_COL_RED,500,nColInd);
|
||||
} else {
|
||||
uint16_t nBlockLen,nSegLen,nSegInd,nSegOffset,nSegStart;
|
||||
nBlockLen = (nElemW-(nSteps-1)*nGap)/nSteps;
|
||||
nSegLen = nBlockLen + nGap;
|
||||
nSegInd = nX/nSegLen;
|
||||
nSegOffset = nX % nSegLen;
|
||||
nSegStart = nSegInd * nSegLen;
|
||||
|
||||
if (nSegOffset <= nBlockLen) {
|
||||
// Inside block
|
||||
nColInd = (uint32_t)nSegStart*1000/nElemW;
|
||||
nCol = gslc_ColorBlend3(GSLC_COL_GREEN,GSLC_COL_YELLOW,GSLC_COL_RED,500,nColInd);
|
||||
|
||||
} else {
|
||||
// Inside gap
|
||||
// - No draw
|
||||
nCol = pElem->colElemFill;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (bModeErase) {
|
||||
nCol = pElem->colElemFill;
|
||||
}
|
||||
gslc_DrawLine(pGui,nElemX0+nX,nElemY1-nHeightBot,nElemX0+nX,nElemY1-nHeight,nCol);
|
||||
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// ============================================================================
|
264
src/guislice/XRamp.h
Normal file
264
src/guislice/XRamp.h
Normal file
|
@ -0,0 +1,264 @@
|
|||
#ifndef _GUISLICE_EX_XRAMP_H_
|
||||
#define _GUISLICE_EX_XRAMP_H_
|
||||
|
||||
#include "GUIslice.h"
|
||||
|
||||
|
||||
// =======================================================================
|
||||
// GUIslice library extension: Ramp gauge
|
||||
// - Calvin Hass
|
||||
// - https://www.impulseadventure.com/elec/guislice-gui.html
|
||||
// - https://github.com/ImpulseAdventure/GUIslice
|
||||
// =======================================================================
|
||||
//
|
||||
// The MIT License
|
||||
//
|
||||
// Copyright 2016-2020 Calvin Hass
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
//
|
||||
// =======================================================================
|
||||
/// \file XRamp.h
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif // __cplusplus
|
||||
|
||||
|
||||
// ============================================================================
|
||||
// Extended Element: Ramp Gauge
|
||||
// - Demonstration of a gradient ramp (green-yellow-red) visual
|
||||
// control similar to certain linear tachometers.
|
||||
// - The ramp rises up and to the right according to the
|
||||
// current value.
|
||||
// - Note that this element is mainly intended as a demonstration
|
||||
// example. Additional APIs would be recommended to make it
|
||||
// more configurable.
|
||||
// ============================================================================
|
||||
|
||||
// Define unique identifier for extended element type
|
||||
// - Select any number above GSLC_TYPE_BASE_EXTEND
|
||||
#define GSLC_TYPEX_RAMP GSLC_TYPE_BASE_EXTEND + 62
|
||||
|
||||
|
||||
// Extended element data structures
|
||||
// - These data structures are maintained in the gslc_tsElem
|
||||
// structure via the pXData pointer
|
||||
|
||||
/// Extended data for Gauge element
|
||||
typedef struct {
|
||||
// Range config
|
||||
int16_t nMin; ///< Minimum control value
|
||||
int16_t nMax; ///< Maximum control value
|
||||
|
||||
// Current value
|
||||
int16_t nVal; ///< Current control value
|
||||
// Previous value
|
||||
int16_t nValLast; ///< Last value
|
||||
bool bValLastValid; ///< Last value valid?
|
||||
|
||||
// Appearance config
|
||||
|
||||
} gslc_tsXRamp;
|
||||
|
||||
|
||||
///
|
||||
/// Create a Ramp Gauge Element
|
||||
/// - Draws a gauge element that represents a proportion (nVal)
|
||||
/// between nMin and nMax.
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] nElemId: Element ID to assign (0..16383 or GSLC_ID_AUTO to autogen)
|
||||
/// \param[in] nPage: Page ID to attach element to
|
||||
/// \param[in] pXData: Ptr to extended element data structure
|
||||
/// \param[in] rElem: Rectangle coordinates defining gauge size
|
||||
/// \param[in] nMin: Minimum value of gauge for nVal comparison
|
||||
/// \param[in] nMax: Maximum value of gauge for nVal comparison
|
||||
/// \param[in] nVal: Starting value of gauge
|
||||
/// \param[in] colGauge: Color for the gauge indicator
|
||||
/// \param[in] bVert: Flag to indicate vertical vs horizontal action
|
||||
/// (true = vertical, false = horizontal)
|
||||
///
|
||||
/// \return Pointer to Element reference or NULL if failure
|
||||
///
|
||||
gslc_tsElemRef* gslc_ElemXRampCreate(gslc_tsGui* pGui,int16_t nElemId,int16_t nPage,
|
||||
gslc_tsXRamp* pXData,gslc_tsRect rElem,int16_t nMin,int16_t nMax,int16_t nVal,gslc_tsColor colGauge,bool bVert);
|
||||
|
||||
|
||||
|
||||
///
|
||||
/// Update a Gauge element's current value
|
||||
/// - Note that min & max values are assigned in create()
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] pElemRef: Pointer to Element reference
|
||||
/// \param[in] nVal: New value to show in gauge
|
||||
///
|
||||
/// \return none
|
||||
///
|
||||
void gslc_ElemXRampSetVal(gslc_tsGui* pGui,gslc_tsElemRef* pElemRef,int16_t nVal);
|
||||
|
||||
|
||||
|
||||
///
|
||||
/// Draw a gauge element on the screen
|
||||
/// - Called from gslc_ElemDraw()
|
||||
///
|
||||
/// \param[in] pvGui: Void ptr to GUI (typecast to gslc_tsGui*)
|
||||
/// \param[in] pvElemRef: Void ptr to Element reference (typecast to gslc_tsElemRef*)
|
||||
/// \param[in] eRedraw: Redraw mode
|
||||
///
|
||||
/// \return true if success, false otherwise
|
||||
///
|
||||
bool gslc_ElemXRampDraw(void* pvGui,void* pvElemRef,gslc_teRedrawType eRedraw);
|
||||
|
||||
|
||||
///
|
||||
/// Helper function to draw a gauge with style: ramp
|
||||
/// - Called from gslc_ElemXRampDraw()
|
||||
///
|
||||
/// \param[in] pGui: Ptr to GUI
|
||||
/// \param[in] pElemRef: Ptr to Element reference
|
||||
/// \param[in] eRedraw: Redraw status
|
||||
///
|
||||
/// \return true if success, false otherwise
|
||||
///
|
||||
bool gslc_ElemXRampDrawHelp(gslc_tsGui* pGui,gslc_tsElemRef* pElemRef,gslc_teRedrawType eRedraw);
|
||||
|
||||
// ============================================================================
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Read-only element macros
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
// Macro initializers for Read-Only Elements in Flash/PROGMEM
|
||||
//
|
||||
|
||||
|
||||
/// \def gslc_ElemXRampCreate_P(pGui,nElemId,nPage,nX,nY,nW,nH,
|
||||
/// nMin_,nMax_,nVal_,colFrame_,colFill_)
|
||||
///
|
||||
/// Create a Gauge Element in Flash
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] nElemId: Unique element ID to assign
|
||||
/// \param[in] nPage: Page ID to attach element to
|
||||
/// \param[in] nX: X coordinate of element
|
||||
/// \param[in] nY: Y coordinate of element
|
||||
/// \param[in] nW: Width of element
|
||||
/// \param[in] nH: Height of element
|
||||
/// \param[in] nMin_: Minimum value of gauge for nVal comparison
|
||||
/// \param[in] nMax_: Maximum value of gauge for nVal comparison
|
||||
/// \param[in] nVal_: Starting value of gauge
|
||||
/// \param[in] colFrame_: Color for the gauge frame
|
||||
/// \param[in] colFill_: Color for the gauge background fill
|
||||
///
|
||||
/// \return none
|
||||
///
|
||||
|
||||
|
||||
#if (GSLC_USE_PROGMEM)
|
||||
|
||||
|
||||
#define gslc_ElemXRampCreate_P(pGui,nElemId,nPage,nX,nY,nW,nH,\
|
||||
nMin_,nMax_,nVal_,colFrame_,colFill_) \
|
||||
static const uint8_t nFeatures##nElemId = GSLC_ELEM_FEA_VALID | \
|
||||
GSLC_ELEM_FEA_GLOW_EN | GSLC_ELEM_FEA_FILL_EN; \
|
||||
static gslc_tsXRamp sGauge##nElemId; \
|
||||
sGauge##nElemId.nMin = nMin_; \
|
||||
sGauge##nElemId.nMax = nMax_; \
|
||||
sGauge##nElemId.nVal = nVal_; \
|
||||
sGauge##nElemId.nValLast = nVal_; \
|
||||
sGauge##nElemId.bValLastValid = false; \
|
||||
static const gslc_tsElem sElem##nElemId PROGMEM = { \
|
||||
nElemId, \
|
||||
nFeatures##nElemId, \
|
||||
GSLC_TYPEX_RAMP, \
|
||||
(gslc_tsRect){nX,nY,nW,nH}, \
|
||||
GSLC_GROUP_ID_NONE, \
|
||||
colFrame_,colFill_,colFrame_,colFill_, \
|
||||
(gslc_tsImgRef){NULL,NULL,GSLC_IMGREF_NONE,NULL}, \
|
||||
(gslc_tsImgRef){NULL,NULL,GSLC_IMGREF_NONE,NULL}, \
|
||||
NULL, \
|
||||
NULL, \
|
||||
0, \
|
||||
(gslc_teTxtFlags)(GSLC_TXT_DEFAULT), \
|
||||
GSLC_COL_WHITE, \
|
||||
GSLC_COL_WHITE, \
|
||||
GSLC_ALIGN_MID_MID, \
|
||||
0, \
|
||||
0, \
|
||||
NULL, \
|
||||
(void*)(&sGauge##nElemId), \
|
||||
NULL, \
|
||||
&gslc_ElemXRampDraw, \
|
||||
NULL, \
|
||||
NULL, \
|
||||
}; \
|
||||
gslc_ElemAdd(pGui,nPage,(gslc_tsElem*)&sElem##nElemId, \
|
||||
(gslc_teElemRefFlags)(GSLC_ELEMREF_SRC_PROG | GSLC_ELEMREF_VISIBLE | GSLC_ELEMREF_REDRAW_FULL));
|
||||
|
||||
#else
|
||||
|
||||
|
||||
#define gslc_ElemXRampCreate_P(pGui,nElemId,nPage,nX,nY,nW,nH,\
|
||||
nMin_,nMax_,nVal_,colFrame_,colFill_) \
|
||||
static const uint8_t nFeatures##nElemId = GSLC_ELEM_FEA_VALID | \
|
||||
GSLC_ELEM_FEA_GLOW_EN | GSLC_ELEM_FEA_FILL_EN; \
|
||||
static gslc_tsXRamp sGauge##nElemId; \
|
||||
sGauge##nElemId.nMin = nMin_; \
|
||||
sGauge##nElemId.nMax = nMax_; \
|
||||
sGauge##nElemId.nVal = nVal_; \
|
||||
sGauge##nElemId.nValLast = nVal_; \
|
||||
sGauge##nElemId.bValLastValid = false; \
|
||||
static const gslc_tsElem sElem##nElemId = { \
|
||||
nElemId, \
|
||||
nFeatures##nElemId, \
|
||||
GSLC_TYPEX_RAMP, \
|
||||
(gslc_tsRect){nX,nY,nW,nH}, \
|
||||
GSLC_GROUP_ID_NONE, \
|
||||
colFrame_,colFill_,colFrame_,colFill_, \
|
||||
(gslc_tsImgRef){NULL,NULL,GSLC_IMGREF_NONE,NULL}, \
|
||||
(gslc_tsImgRef){NULL,NULL,GSLC_IMGREF_NONE,NULL}, \
|
||||
NULL, \
|
||||
NULL, \
|
||||
0, \
|
||||
(gslc_teTxtFlags)(GSLC_TXT_DEFAULT), \
|
||||
GSLC_COL_WHITE, \
|
||||
GSLC_COL_WHITE, \
|
||||
GSLC_ALIGN_MID_MID, \
|
||||
0, \
|
||||
0, \
|
||||
NULL, \
|
||||
(void*)(&sGauge##nElemId), \
|
||||
NULL, \
|
||||
&gslc_ElemXRampDraw, \
|
||||
NULL, \
|
||||
NULL, \
|
||||
}; \
|
||||
gslc_ElemAdd(pGui,nPage,(gslc_tsElem*)&sElem##nElemId, \
|
||||
(gslc_teElemRefFlags)(GSLC_ELEMREF_SRC_CONST | GSLC_ELEMREF_VISIBLE | GSLC_ELEMREF_REDRAW_FULL));
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif // __cplusplus
|
||||
#endif // _GUISLICE_EX_XRAMP_H_
|
||||
|
413
src/guislice/XRingGauge.c
Normal file
413
src/guislice/XRingGauge.c
Normal file
|
@ -0,0 +1,413 @@
|
|||
// =======================================================================
|
||||
// GUIslice library (Ring control)
|
||||
// - Calvin Hass
|
||||
// - https://www.impulseadventure.com/elec/guislice-gui.html
|
||||
// - https://github.com/ImpulseAdventure/GUIslice
|
||||
// =======================================================================
|
||||
//
|
||||
// The MIT License
|
||||
//
|
||||
// Copyright 2016-2020 Calvin Hass
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
//
|
||||
// =======================================================================
|
||||
/// \file XRingGauge.c
|
||||
|
||||
|
||||
|
||||
// GUIslice library
|
||||
#include "GUIslice.h"
|
||||
#include "GUIslice_drv.h"
|
||||
|
||||
#include "XRingGauge.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#if (GSLC_USE_PROGMEM)
|
||||
#include <avr/pgmspace.h>
|
||||
#endif
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Error Messages
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
extern const char GSLC_PMEM ERRSTR_NULL[];
|
||||
extern const char GSLC_PMEM ERRSTR_PXD_NULL[];
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Extended element definitions
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// - This file extends the core GUIslice functionality with
|
||||
// additional widget types
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
|
||||
// ============================================================================
|
||||
// Extended Element: Ring gauge
|
||||
// ============================================================================
|
||||
|
||||
// Create a text element and add it to the GUI element list
|
||||
// - Defines default styling for the element
|
||||
// - Defines callback for redraw and touch
|
||||
gslc_tsElemRef* gslc_ElemXRingGaugeCreate(gslc_tsGui* pGui, int16_t nElemId, int16_t nPage,
|
||||
gslc_tsXRingGauge* pXData, gslc_tsRect rElem, char* pStrBuf, uint8_t nStrBufMax, int16_t nFontId)
|
||||
{
|
||||
if ((pGui == NULL) || (pXData == NULL)) {
|
||||
static const char GSLC_PMEM FUNCSTR[] = "ElemXRingGaugeCreate";
|
||||
GSLC_DEBUG2_PRINT_CONST(ERRSTR_NULL,FUNCSTR);
|
||||
return NULL;
|
||||
}
|
||||
gslc_tsElem sElem;
|
||||
gslc_tsElemRef* pElemRef = NULL;
|
||||
sElem = gslc_ElemCreate(pGui,nElemId,nPage,GSLC_TYPEX_RING,rElem,pStrBuf,nStrBufMax,nFontId);
|
||||
sElem.colElemFill = GSLC_COL_BLACK;
|
||||
sElem.colElemFrame = GSLC_COL_BLUE;
|
||||
sElem.colElemText = GSLC_COL_YELLOW;
|
||||
sElem.nFeatures = GSLC_ELEM_FEA_FILL_EN;
|
||||
sElem.nFeatures &= ~GSLC_ELEM_FEA_FRAME_EN;
|
||||
sElem.nFeatures &= ~GSLC_ELEM_FEA_CLICK_EN;
|
||||
sElem.nFeatures &= ~GSLC_ELEM_FEA_GLOW_EN;
|
||||
sElem.eTxtAlign = GSLC_ALIGN_MID_MID;
|
||||
|
||||
sElem.nGroup = GSLC_GROUP_ID_NONE;
|
||||
|
||||
// Provide default config
|
||||
pXData->nValMin = 0;
|
||||
pXData->nValMax = 100;
|
||||
pXData->nAngStart = 0;
|
||||
pXData->nAngRange = 360;
|
||||
pXData->nThickness = 10;
|
||||
|
||||
pXData->nQuality = 72; // 360/72=5 degree segments
|
||||
|
||||
pXData->bGradient = false;
|
||||
pXData->nSegGap = 0;
|
||||
pXData->colRing1 = GSLC_COL_BLUE_LT4;
|
||||
pXData->colRing2 = GSLC_COL_RED;
|
||||
pXData->colRingRemain = (gslc_tsColor) { 0, 0, 48 };
|
||||
|
||||
pXData->nVal = 0;
|
||||
pXData->nValLast = 0;
|
||||
pXData->acStrLast[0] = 0;
|
||||
|
||||
|
||||
sElem.pXData = (void*)(pXData);
|
||||
// Specify the custom drawing callback
|
||||
sElem.pfuncXDraw = &gslc_ElemXRingGaugeDraw;
|
||||
// Specify the custom touch tracking callback
|
||||
sElem.pfuncXTouch = NULL;
|
||||
|
||||
if (nPage != GSLC_PAGE_NONE) {
|
||||
pElemRef = gslc_ElemAdd(pGui,nPage,&sElem,GSLC_ELEMREF_DEFAULT);
|
||||
return pElemRef;
|
||||
#if (GSLC_FEATURE_COMPOUND)
|
||||
} else {
|
||||
// Save as temporary element
|
||||
pGui->sElemTmp = sElem;
|
||||
pGui->sElemRefTmp.pElem = &(pGui->sElemTmp);
|
||||
pGui->sElemRefTmp.eElemFlags = GSLC_ELEMREF_DEFAULT | GSLC_ELEMREF_REDRAW_FULL;
|
||||
return &(pGui->sElemRefTmp);
|
||||
#endif
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
// Redraw the element
|
||||
// - Note that this redraw is for the entire element rect region
|
||||
// - The Draw function parameters use void pointers to allow for
|
||||
// simpler callback function definition & scalability.
|
||||
bool gslc_ElemXRingGaugeDraw(void* pvGui, void* pvElemRef, gslc_teRedrawType eRedraw)
|
||||
{
|
||||
gslc_tsGui* pGui = (gslc_tsGui*)pvGui;
|
||||
gslc_tsElemRef* pElemRef = (gslc_tsElemRef*)pvElemRef;
|
||||
gslc_tsElem* pElem = gslc_GetElemFromRefD(pGui, pElemRef, __LINE__);
|
||||
gslc_tsXRingGauge* pXRingGauge = (gslc_tsXRingGauge*)gslc_GetXDataFromRef(pGui, pElemRef, GSLC_TYPEX_RING, __LINE__);
|
||||
if (!pXRingGauge) return false;
|
||||
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// Init for default drawing
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
bool bGlowEn, bGlowing, bGlowNow;
|
||||
int16_t nElemX, nElemY;
|
||||
uint16_t nElemW, nElemH;
|
||||
|
||||
nElemX = pElem->rElem.x;
|
||||
nElemY = pElem->rElem.y;
|
||||
nElemW = pElem->rElem.w;
|
||||
nElemH = pElem->rElem.h;
|
||||
bGlowEn = pElem->nFeatures & GSLC_ELEM_FEA_GLOW_EN; // Does the element support glow state?
|
||||
bGlowing = gslc_ElemGetGlow(pGui, pElemRef); // Element should be glowing (if enabled)
|
||||
bGlowNow = bGlowEn & bGlowing; // Element is currently glowing
|
||||
|
||||
int16_t nVal = pXRingGauge->nVal;
|
||||
int16_t nValLast = pXRingGauge->nValLast;
|
||||
int16_t nValMin = pXRingGauge->nValMin;
|
||||
int16_t nValMax = pXRingGauge->nValMax;
|
||||
int16_t nValRange = (nValMax == nValMin)? 1 : (nValMax - nValMin); // Guard against div/0
|
||||
int16_t nAngStart = pXRingGauge->nAngStart;
|
||||
int16_t nAngRange = pXRingGauge->nAngRange;
|
||||
//int16_t nAngEnd = nAngStart + nAngRange;
|
||||
int16_t nQuality = pXRingGauge->nQuality;
|
||||
|
||||
gslc_tsColor colRingActive1 = pXRingGauge->colRing1;
|
||||
gslc_tsColor colRingActive2 = pXRingGauge->colRing2;
|
||||
gslc_tsColor colRingInactive = pXRingGauge->colRingRemain;
|
||||
bool bGradient = pXRingGauge->bGradient;
|
||||
gslc_tsColor colBg = pElem->colElemFill; // Background color used for text clearance
|
||||
|
||||
// Calculate the ring center and radius
|
||||
int16_t nMidX = nElemX + nElemW / 2;
|
||||
int16_t nMidY = nElemY + nElemH / 2;
|
||||
int16_t nRad2 = (nElemW < nElemH) ? nElemW / 2 : nElemH / 2;
|
||||
int16_t nRad1 = nRad2 - pXRingGauge->nThickness;
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
// Determine whether we should draw the full range (full redraw)
|
||||
// or a smaller, updated region (incremental redraw)
|
||||
bool bInc = (eRedraw == GSLC_REDRAW_INC) ? true : false;
|
||||
|
||||
int16_t nDrawStart = 0;
|
||||
int16_t nDrawVal = 0;
|
||||
int16_t nDrawEnd = 0;
|
||||
|
||||
bool bDrawActive = false;
|
||||
bool bDrawInactive = false;
|
||||
if (bInc) {
|
||||
if (nVal > nValLast) {
|
||||
// Incremental redraw: adding value, so draw with active color
|
||||
bDrawActive = true;
|
||||
nDrawStart = (int32_t)(nValLast - nValMin) * nAngRange / nValRange;
|
||||
nDrawVal = (int32_t)(nVal - nValMin) * nAngRange / nValRange;
|
||||
}
|
||||
else {
|
||||
// Incremental redraw: reducing value, so draw with inactive color
|
||||
bDrawInactive = true;
|
||||
nDrawVal = (int32_t)(nVal - nValMin) * nAngRange / nValRange;
|
||||
nDrawEnd = (int32_t)(nValLast - nValMin) * nAngRange / nValRange;
|
||||
}
|
||||
} else {
|
||||
// Full redraw: draw both active and inactive regions
|
||||
bDrawActive = true;
|
||||
bDrawInactive = true;
|
||||
nDrawStart = 0;
|
||||
nDrawVal = (int32_t)(nVal - nValMin) * nAngRange / nValRange;
|
||||
nDrawEnd = nAngRange;
|
||||
}
|
||||
|
||||
#if defined(DBG_REDRAW)
|
||||
GSLC_DEBUG2_PRINT("\n\nRingDraw: Val=%d ValLast=%d ValRange=%d PosMin=%d PosMax=%d Q=%d\n", nVal, nValLast, nValRange, nValMin, nValMax, nQuality);
|
||||
GSLC_DEBUG2_PRINT("RingDraw: Inc=%d ValLast=%d Val=%d Ang=%d..%d (Range=%d)\n", bInc,nValLast,nVal,nAngStart, nAngStart+nAngRange,nAngRange); //CAL!
|
||||
GSLC_DEBUG2_PRINT("RingDraw: DrawActive=%d DrawInactive=%d DrawStart=%d DrawVal=%d DrawEnd=%d\n",bDrawActive,bDrawInactive,nDrawStart,nDrawVal,nDrawEnd);//CAL!
|
||||
#endif
|
||||
|
||||
// Adjust for start of angular range
|
||||
nDrawStart += nAngStart;
|
||||
nDrawVal += nAngStart;
|
||||
nDrawEnd += nAngStart;
|
||||
|
||||
if (bDrawActive) {
|
||||
if (bGradient) {
|
||||
#if defined(DBG_REDRAW)
|
||||
GSLC_DEBUG2_PRINT("RingDraw: ActiveG start=%d end=%d astart=%d arange=%d\n", nDrawStart, nDrawVal,nAngStart,nAngRange);
|
||||
#endif
|
||||
gslc_DrawFillGradSector(pGui, nQuality, nMidX, nMidY,
|
||||
nRad1, nRad2, colRingActive1, colRingActive2, nDrawStart, nDrawVal, nAngStart, nAngRange);
|
||||
} else {
|
||||
#if defined(DBG_REDRAW)
|
||||
GSLC_DEBUG2_PRINT("RingDraw: Active start=%d end=%d\n", nDrawStart, nDrawVal);
|
||||
#endif
|
||||
gslc_DrawFillSector(pGui, nQuality, nMidX, nMidY,
|
||||
nRad1, nRad2, colRingActive1, nDrawStart, nDrawVal);
|
||||
}
|
||||
}
|
||||
|
||||
if (bDrawInactive) {
|
||||
#if defined(DBG_REDRAW)
|
||||
GSLC_DEBUG2_PRINT("RingDraw: Inactive start=%d end=%d\n", nDrawEnd, nDrawVal);
|
||||
#endif
|
||||
// Since we are erasing, we will reverse the redraw direction (swap Val & End)
|
||||
gslc_DrawFillSector(pGui, nQuality, nMidX, nMidY,
|
||||
nRad1, nRad2, colRingInactive, nDrawEnd, nDrawVal);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// Text overlays
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
// Draw text string if defined
|
||||
if (pElem->pStrBuf) {
|
||||
gslc_tsColor colTxt = (bGlowNow)? pElem->colElemTextGlow : pElem->colElemText;
|
||||
int8_t nMarginX = pElem->nTxtMarginX;
|
||||
int8_t nMarginY = pElem->nTxtMarginY;
|
||||
|
||||
// Erase old string content using "background" color
|
||||
if (strlen(pXRingGauge->acStrLast) != 0) {
|
||||
gslc_DrawTxtBase(pGui, pXRingGauge->acStrLast, pElem->rElem, pElem->pTxtFont, pElem->eTxtFlags,
|
||||
pElem->eTxtAlign, colBg, GSLC_COL_BLACK, nMarginX, nMarginY);
|
||||
}
|
||||
|
||||
// Draw new string content
|
||||
gslc_DrawTxtBase(pGui, pElem->pStrBuf, pElem->rElem, pElem->pTxtFont, pElem->eTxtFlags,
|
||||
pElem->eTxtAlign, colTxt, GSLC_COL_BLACK, nMarginX, nMarginY);
|
||||
|
||||
// Save a copy of the new string content so we can support future erase
|
||||
strncpy(pXRingGauge->acStrLast, pElem->pStrBuf, XRING_STR_MAX);
|
||||
pXRingGauge->acStrLast[XRING_STR_MAX - 1] = 0; // Force null terminator
|
||||
|
||||
} // pStrBuf
|
||||
|
||||
// Save the position to enable future incremental calculations
|
||||
pXRingGauge->nValLast = pXRingGauge->nVal;
|
||||
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
// Mark the element as no longer requiring redraw
|
||||
gslc_ElemSetRedraw(pGui,pElemRef,GSLC_REDRAW_NONE);
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
|
||||
void gslc_ElemXRingGaugeSetVal(gslc_tsGui* pGui, gslc_tsElemRef* pElemRef, int16_t nVal)
|
||||
{
|
||||
gslc_tsXRingGauge* pXRingGauge = (gslc_tsXRingGauge*)gslc_GetXDataFromRef(pGui, pElemRef, GSLC_TYPEX_RING, __LINE__);
|
||||
if (!pXRingGauge) return;
|
||||
|
||||
int16_t nValOld;
|
||||
|
||||
// Clip position
|
||||
if (nVal < pXRingGauge->nValMin) { nVal = pXRingGauge->nValMin; }
|
||||
if (nVal > pXRingGauge->nValMax) { nVal = pXRingGauge->nValMax; }
|
||||
|
||||
// Update
|
||||
nValOld = pXRingGauge->nVal;
|
||||
pXRingGauge->nVal = nVal;
|
||||
|
||||
// Only update if changed
|
||||
if (nVal != nValOld) {
|
||||
// Mark for redraw
|
||||
// - Only need incremental redraw
|
||||
gslc_ElemSetRedraw(pGui,pElemRef,GSLC_REDRAW_INC);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void gslc_ElemXRingGaugeSetValRange(gslc_tsGui* pGui, gslc_tsElemRef* pElemRef, int16_t nValMin, int16_t nValMax)
|
||||
{
|
||||
gslc_tsXRingGauge* pXRingGauge = (gslc_tsXRingGauge*)gslc_GetXDataFromRef(pGui, pElemRef, GSLC_TYPEX_RING, __LINE__);
|
||||
if (!pXRingGauge) return;
|
||||
|
||||
pXRingGauge->nValMin = nValMin;
|
||||
pXRingGauge->nValMax = nValMax;
|
||||
|
||||
// Mark for full redraw
|
||||
gslc_ElemSetRedraw(pGui,pElemRef,GSLC_REDRAW_FULL);
|
||||
}
|
||||
|
||||
void gslc_ElemXRingGaugeSetAngleRange(gslc_tsGui* pGui, gslc_tsElemRef* pElemRef, int16_t nStart, int16_t nRange, bool bClockwise)
|
||||
{
|
||||
gslc_tsXRingGauge* pXRingGauge = (gslc_tsXRingGauge*)gslc_GetXDataFromRef(pGui, pElemRef, GSLC_TYPEX_RING, __LINE__);
|
||||
if (!pXRingGauge) return;
|
||||
|
||||
pXRingGauge->nAngStart = nStart;
|
||||
pXRingGauge->nAngRange = nRange;
|
||||
|
||||
nRange = (nRange == 0) ? 1 : nRange; // Guard against div/0
|
||||
|
||||
// TODO: Support bClockwise
|
||||
|
||||
// Mark for full redraw
|
||||
gslc_ElemSetRedraw(pGui,pElemRef,GSLC_REDRAW_FULL);
|
||||
}
|
||||
|
||||
void gslc_ElemXRingGaugeSetThickness(gslc_tsGui* pGui, gslc_tsElemRef* pElemRef, int8_t nThickness)
|
||||
{
|
||||
gslc_tsXRingGauge* pXRingGauge = (gslc_tsXRingGauge*)gslc_GetXDataFromRef(pGui, pElemRef, GSLC_TYPEX_RING, __LINE__);
|
||||
if (!pXRingGauge) return;
|
||||
|
||||
pXRingGauge->nThickness = nThickness;
|
||||
|
||||
// Mark for full redraw
|
||||
gslc_ElemSetRedraw(pGui,pElemRef,GSLC_REDRAW_FULL);
|
||||
}
|
||||
|
||||
void gslc_ElemXRingGaugeSetColorActiveFlat(gslc_tsGui* pGui, gslc_tsElemRef* pElemRef, gslc_tsColor colActive)
|
||||
{
|
||||
gslc_tsXRingGauge* pXRingGauge = (gslc_tsXRingGauge*)gslc_GetXDataFromRef(pGui, pElemRef, GSLC_TYPEX_RING, __LINE__);
|
||||
if (!pXRingGauge) return;
|
||||
|
||||
pXRingGauge->bGradient = false;
|
||||
pXRingGauge->colRing1 = colActive;
|
||||
pXRingGauge->colRing2 = colActive;
|
||||
|
||||
// Mark for full redraw
|
||||
gslc_ElemSetRedraw(pGui,pElemRef,GSLC_REDRAW_FULL);
|
||||
}
|
||||
|
||||
void gslc_ElemXRingGaugeSetColorActiveGradient(gslc_tsGui* pGui, gslc_tsElemRef* pElemRef, gslc_tsColor colStart, gslc_tsColor colEnd)
|
||||
{
|
||||
gslc_tsXRingGauge* pXRingGauge = (gslc_tsXRingGauge*)gslc_GetXDataFromRef(pGui, pElemRef, GSLC_TYPEX_RING, __LINE__);
|
||||
if (!pXRingGauge) return;
|
||||
|
||||
pXRingGauge->bGradient = true;
|
||||
pXRingGauge->colRing1 = colStart;
|
||||
pXRingGauge->colRing2 = colEnd;
|
||||
|
||||
// Mark for full redraw
|
||||
gslc_ElemSetRedraw(pGui,pElemRef,GSLC_REDRAW_FULL);
|
||||
}
|
||||
|
||||
|
||||
void gslc_ElemXRingGaugeSetColorInactive(gslc_tsGui* pGui, gslc_tsElemRef* pElemRef, gslc_tsColor colInactive)
|
||||
{
|
||||
gslc_tsXRingGauge* pXRingGauge = (gslc_tsXRingGauge*)gslc_GetXDataFromRef(pGui, pElemRef, GSLC_TYPEX_RING, __LINE__);
|
||||
if (!pXRingGauge) return;
|
||||
|
||||
pXRingGauge->colRingRemain = colInactive;
|
||||
|
||||
// Mark for full redraw
|
||||
gslc_ElemSetRedraw(pGui,pElemRef,GSLC_REDRAW_FULL);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void gslc_ElemXRingGaugeSetQuality(gslc_tsGui* pGui, gslc_tsElemRef* pElemRef, uint16_t nSegments)
|
||||
{
|
||||
gslc_tsXRingGauge* pXRingGauge = (gslc_tsXRingGauge*)gslc_GetXDataFromRef(pGui, pElemRef, GSLC_TYPEX_RING, __LINE__);
|
||||
if (!pXRingGauge) return;
|
||||
|
||||
nSegments = (nSegments == 0) ? 72 : nSegments; // Guard against div/0 with default
|
||||
pXRingGauge->nQuality = nSegments;
|
||||
|
||||
// Mark for full redraw
|
||||
gslc_ElemSetRedraw(pGui,pElemRef,GSLC_REDRAW_FULL);
|
||||
}
|
||||
|
||||
|
||||
// ============================================================================
|
268
src/guislice/XRingGauge.h
Normal file
268
src/guislice/XRingGauge.h
Normal file
|
@ -0,0 +1,268 @@
|
|||
#ifndef _GUISLICE_EX_XRING_H_
|
||||
#define _GUISLICE_EX_XRING_H_
|
||||
|
||||
#include "GUIslice.h"
|
||||
|
||||
|
||||
// =======================================================================
|
||||
// GUIslice library extension: XRingGauge
|
||||
// - Calvin Hass
|
||||
// - https://www.impulseadventure.com/elec/guislice-gui.html
|
||||
// - https://github.com/ImpulseAdventure/GUIslice
|
||||
// =======================================================================
|
||||
//
|
||||
// The MIT License
|
||||
//
|
||||
// Copyright 2016-2020 Calvin Hass
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
//
|
||||
// =======================================================================
|
||||
/// \file XRingGauge.h
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif // __cplusplus
|
||||
|
||||
|
||||
// ============================================================================
|
||||
// Extended Element: XRingGauge
|
||||
// - Creates display element similar to a donut-chart.
|
||||
// - The element has an outer and inner radius to create a ring appearance.
|
||||
// - The ring has an angular range defined by SetAngleRange, which means that
|
||||
// the ring can be configured to cover a full circle or just a portion of
|
||||
// a circle.
|
||||
// - SetAngleRange defines the starting angle and direction of fill.
|
||||
// - When drawing the ring within the angular range, it is composed of
|
||||
// an active region (the angular region from the start to the current
|
||||
// position value) and an inactive region (from the current value to the
|
||||
// end of the angular range). The inactive region can be hidden (by
|
||||
// setting it to the background color).
|
||||
// - A text value can be drawn in the center of the ring, typically to
|
||||
// show the current value. The color defined by SetColorBackground() is
|
||||
// used when redrawing the text.
|
||||
// ============================================================================
|
||||
|
||||
// Define unique identifier for extended element type
|
||||
// - Select any number above GSLC_TYPE_BASE_EXTEND
|
||||
#define GSLC_TYPEX_RING GSLC_TYPE_BASE_EXTEND + 23
|
||||
|
||||
|
||||
// Extended element data structures
|
||||
// - These data structures are maintained in the gslc_tsElem
|
||||
// structure via the pXData pointer
|
||||
|
||||
#define XRING_STR_MAX 10
|
||||
|
||||
/// Extended data for XRingGauge element
|
||||
typedef struct {
|
||||
// Config
|
||||
int16_t nValMin;
|
||||
int16_t nValMax;
|
||||
|
||||
int16_t nAngStart;
|
||||
int16_t nAngRange;
|
||||
|
||||
// Style config
|
||||
int16_t nQuality;
|
||||
int8_t nThickness;
|
||||
bool bGradient;
|
||||
uint8_t nSegGap;
|
||||
gslc_tsColor colRing1;
|
||||
gslc_tsColor colRing2;
|
||||
gslc_tsColor colRingRemain;
|
||||
|
||||
// State
|
||||
int16_t nVal; ///< Current position value
|
||||
int16_t nValLast; ///< Previous position value
|
||||
char acStrLast[XRING_STR_MAX];
|
||||
|
||||
// Callbacks
|
||||
|
||||
} gslc_tsXRingGauge;
|
||||
|
||||
|
||||
///
|
||||
/// Create an XRingGauge element
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] nElemId: Element ID to assign (0..16383 or GSLC_ID_AUTO to autogen)
|
||||
/// \param[in] nPage: Page ID to attach element to
|
||||
/// \param[in] pXData: Ptr to extended element data structure
|
||||
/// \param[in] rElem: The square box that bounds the ring element. If a rectangular region is
|
||||
/// provided, then the ring control will be centered in the long axis.
|
||||
/// \param[in] pStrBuf: String buffer to use for gauge inner text
|
||||
/// \param[in] nStrBufMax: Maximum length of string buffer (pStrBuf)
|
||||
/// \param[in] nFontId: Font ID to use for text display
|
||||
///
|
||||
/// \return Pointer to Element reference or NULL if failure
|
||||
///
|
||||
gslc_tsElemRef* gslc_ElemXRingGaugeCreate(gslc_tsGui* pGui, int16_t nElemId, int16_t nPage,
|
||||
gslc_tsXRingGauge* pXData, gslc_tsRect rElem, char* pStrBuf, uint8_t nStrBufMax, int16_t nFontId);
|
||||
|
||||
///
|
||||
/// Draw the template element on the screen
|
||||
/// - Called from gslc_ElemDraw()
|
||||
///
|
||||
/// \param[in] pvGui: Void ptr to GUI (typecast to gslc_tsGui*)
|
||||
/// \param[in] pvElemRef: Void ptr to Element (typecast to gslc_tsElemRef*)
|
||||
/// \param[in] eRedraw: Redraw mode
|
||||
///
|
||||
/// \return true if success, false otherwise
|
||||
///
|
||||
bool gslc_ElemXRingGaugeDraw(void* pvGui,void* pvElemRef,gslc_teRedrawType eRedraw);
|
||||
|
||||
|
||||
///
|
||||
/// Set an Ring Gauge current indicator value
|
||||
///
|
||||
/// Updates the current value of the ring gauge. The active region will be drawn up
|
||||
/// to the position defined by nVal within the value range defined by SetValRange(nMin,nMax).
|
||||
/// A SetVal() close to nMin will cause a very small active region to be drawn and a large
|
||||
/// remainder drawn in the inactive color, whereas a SetVal() close to nMax will cause a
|
||||
/// more complete active region to be drawn.When SetVal() equals nMax, the entire angular
|
||||
/// range will be drawn in the active color (and no inactive region).
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] pElemRef: Pointer to Element reference
|
||||
/// \param[in] nVal: New position value
|
||||
///
|
||||
/// \return none
|
||||
///
|
||||
void gslc_ElemXRingGaugeSetVal(gslc_tsGui* pGui,gslc_tsElemRef* pElemRef,int16_t nVal);
|
||||
|
||||
///
|
||||
/// Defines the angular range of the gauge, including both the active
|
||||
/// and inactive regions.
|
||||
///
|
||||
/// - nStart defines the angle at the beginning of the active region.
|
||||
/// - The current position marks the end of the active region and the
|
||||
/// beginning of the inactive region.
|
||||
/// - nRange defines the angular range from the start of the active
|
||||
/// region to the end of the inactive region. In most cases, a
|
||||
/// range of 360 degrees is used.
|
||||
/// - All angles are measured in units of degrees.
|
||||
/// - Angles are measured with 0 at the top, 90 towards the right,
|
||||
/// 180 towards the bottom, 270 towards the left, etc.
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] pElemRef: Pointer to Element reference
|
||||
/// \param[in] nStart: Define angle of start of active region (measured in degrees)
|
||||
/// \param[in] nRange: Define angular range from strt of active region
|
||||
/// to end of the inactive region (measured in degrees)
|
||||
/// \param[in] bClockwise: Defines the direction in which the active
|
||||
/// region grows (true for clockwise) [FORCED TRUE, FOR FUTURE IMPLEMENTATION]
|
||||
///
|
||||
/// \return none
|
||||
///
|
||||
void gslc_ElemXRingGaugeSetAngleRange(gslc_tsGui* pGui, gslc_tsElemRef* pElemRef, int16_t nStart, int16_t nRange, bool bClockwise);
|
||||
|
||||
|
||||
/// Defines the range of values that may be passed into SetVal(), used to
|
||||
/// scale the input to SetVal().
|
||||
/// - Default is 0..100.
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] pElemRef: Pointer to Element reference
|
||||
/// \param[in] nValMin: Minimum value
|
||||
/// \param[in] nValMax: Maximum value
|
||||
///
|
||||
/// \return none
|
||||
///
|
||||
void gslc_ElemXRingGaugeSetValRange(gslc_tsGui* pGui, gslc_tsElemRef* pElemRef, int16_t nValMin, int16_t nValMax);
|
||||
|
||||
|
||||
/// Defines the thickness of the ring arcs. More specifically, it defines the reduction
|
||||
/// in radius from the outer radius to the inner radius in pixels.
|
||||
/// - Default thickness is 10 pixels
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] pElemRef: Pointer to Element reference
|
||||
/// \param[in] nThickness: Thickness of ring
|
||||
///
|
||||
/// \return none
|
||||
///
|
||||
void gslc_ElemXRingGaugeSetThickness(gslc_tsGui* pGui, gslc_tsElemRef* pElemRef, int8_t nThickness);
|
||||
|
||||
/// Sets the quality of the ring drawing by defining the number of segments that are used when
|
||||
/// rendering a 360 degree gauge.The larger the number, the more segments are used and the smoother the curve.
|
||||
/// A larger ring gauge may need a higher quality number to maintain a smoothed curve appearance.
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] pElemRef: Pointer to Element reference
|
||||
/// \param[in] nSegments: Number of arc segments to render a complete circle. The
|
||||
/// higher the value, the smoother the ring.
|
||||
/// Note that 360/nSegments should be an integer result,
|
||||
/// thus the allowable quality settings are: 360 (max quality),
|
||||
/// 180, 120, 90, 72, 60, 45, 40, 36 (low quality), etc.
|
||||
///
|
||||
/// \return none
|
||||
///
|
||||
void gslc_ElemXRingGaugeSetQuality(gslc_tsGui* pGui, gslc_tsElemRef* pElemRef, uint16_t nSegments);
|
||||
|
||||
/// Defines the color of the inactive region to be a flat (constant) color.
|
||||
/// The inactive color is often set to be the same as the background but it can
|
||||
/// be set to a different color to indicate the remainder of the value range that is yet to be filled.
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] pElemRef: Pointer to Element reference
|
||||
/// \param[in] colInactive: Color of inactive region
|
||||
///
|
||||
/// \return none
|
||||
///
|
||||
void gslc_ElemXRingGaugeSetColorInactive(gslc_tsGui* pGui, gslc_tsElemRef* pElemRef, gslc_tsColor colInactive);
|
||||
|
||||
/// Defines the color of the active region to be a flat (constant) color.
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] pElemRef: Pointer to Element reference
|
||||
/// \param[in] colActive: Color of active region
|
||||
///
|
||||
/// \return none
|
||||
///
|
||||
void gslc_ElemXRingGaugeSetColorActiveFlat(gslc_tsGui* pGui, gslc_tsElemRef* pElemRef, gslc_tsColor colActive);
|
||||
|
||||
/// Defines the color of the active region to be a gradient using two color stops. The
|
||||
/// active region will be filled according to the proportion between nMin and nMax.
|
||||
/// The gradient is defined by a linear RGB blend between the two color stops(colStart and colEnd)
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] pElemRef: Pointer to Element reference
|
||||
/// \param[in] colStart: Starting color of gradient fill
|
||||
/// \param[in] colEnd: Ending color of gradient fill
|
||||
///
|
||||
/// \return none
|
||||
///
|
||||
void gslc_ElemXRingGaugeSetColorActiveGradient(gslc_tsGui* pGui, gslc_tsElemRef* pElemRef, gslc_tsColor colStart, gslc_tsColor colEnd);
|
||||
|
||||
// ============================================================================
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Read-only element macros
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
// Macro initializers for Read-Only Elements in Flash/PROGMEM
|
||||
//
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif // __cplusplus
|
||||
#endif // _GUISLICE_EX_XRING_H_
|
||||
|
530
src/guislice/XSeekbar.c
Normal file
530
src/guislice/XSeekbar.c
Normal file
|
@ -0,0 +1,530 @@
|
|||
// =======================================================================
|
||||
// GUIslice library extension: Seekbar control
|
||||
// - Paul Conti
|
||||
// - Seekbar is a modern Slider Control with Android like style
|
||||
// - Based on Calvin Hass's Slider control
|
||||
// - https://www.impulseadventure.com/elec/guislice-gui.html
|
||||
// - https://github.com/ImpulseAdventure/GUIslice
|
||||
// =======================================================================
|
||||
//
|
||||
// The MIT License
|
||||
//
|
||||
// Copyright 2016-2020 Calvin Hass
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
//
|
||||
// =======================================================================
|
||||
/// \file XSeekbar.c
|
||||
|
||||
|
||||
|
||||
// GUIslice library
|
||||
#include "GUIslice.h"
|
||||
#include "GUIslice_drv.h"
|
||||
|
||||
#include "XSeekbar.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#if (GSLC_USE_PROGMEM)
|
||||
#include <avr/pgmspace.h>
|
||||
#endif
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Error Messages
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
extern const char GSLC_PMEM ERRSTR_NULL[];
|
||||
extern const char GSLC_PMEM ERRSTR_PXD_NULL[];
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Extended element definitions
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// - This file extends the core GUIslice functionality with
|
||||
// additional widget types
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
|
||||
// ============================================================================
|
||||
// Extended Element: Seekbar
|
||||
// - A linear slider control
|
||||
// ============================================================================
|
||||
|
||||
// Create a slider element and add it to the GUI element list
|
||||
// - Defines default styling for the element
|
||||
// - Defines callback for redraw and touch
|
||||
gslc_tsElemRef* gslc_ElemXSeekbarCreate(gslc_tsGui* pGui,int16_t nElemId,int16_t nPage,
|
||||
gslc_tsXSeekbar* pXData,gslc_tsRect rElem,int16_t nPosMin,int16_t nPosMax,int16_t nPos,
|
||||
uint8_t nProgressW,uint8_t nRemainW,uint8_t nThumbSz,
|
||||
gslc_tsColor colProgress,gslc_tsColor colRemain,gslc_tsColor colThumb,bool bVert)
|
||||
{
|
||||
if ((pGui == NULL) || (pXData == NULL)) {
|
||||
static const char GSLC_PMEM FUNCSTR[] = "ElemXSeekbarCreate";
|
||||
GSLC_DEBUG2_PRINT_CONST(ERRSTR_NULL,FUNCSTR);
|
||||
return NULL;
|
||||
}
|
||||
gslc_tsElem sElem;
|
||||
gslc_tsElemRef* pElemRef = NULL;
|
||||
sElem = gslc_ElemCreate(pGui,nElemId,nPage,GSLC_TYPEX_SEEKBAR,rElem,NULL,0,GSLC_FONT_NONE);
|
||||
sElem.nFeatures &= ~GSLC_ELEM_FEA_FRAME_EN;
|
||||
sElem.nFeatures |= GSLC_ELEM_FEA_FILL_EN;
|
||||
sElem.nFeatures |= GSLC_ELEM_FEA_CLICK_EN;
|
||||
sElem.nFeatures |= GSLC_ELEM_FEA_GLOW_EN;
|
||||
|
||||
sElem.nGroup = GSLC_GROUP_ID_NONE;
|
||||
|
||||
// Range check on nPos
|
||||
if (nPos < nPosMin) { nPos = nPosMin; }
|
||||
if (nPos > nPosMax) { nPos = nPosMax; }
|
||||
|
||||
pXData->bVert = bVert;
|
||||
pXData->nPosMin = nPosMin;
|
||||
pXData->nPosMax = nPosMax;
|
||||
pXData->nPos = nPos;
|
||||
pXData->nProgressW = nProgressW;
|
||||
pXData->nRemainW = nRemainW;
|
||||
pXData->nThumbSz = nThumbSz;
|
||||
pXData->colProgress = colProgress;
|
||||
pXData->colRemain = colRemain;
|
||||
pXData->colThumb = colThumb;
|
||||
pXData->bTrimThumb = false;
|
||||
pXData->colTrim = GSLC_COL_BLACK;
|
||||
pXData->bFrameThumb = false;
|
||||
pXData->colFrame = GSLC_COL_BLACK;
|
||||
pXData->nTickDiv = 0;
|
||||
pXData->nTickLen = 0;
|
||||
pXData->colTick = GSLC_COL_BLACK;
|
||||
pXData->pfuncXPos = NULL;
|
||||
sElem.pXData = (void*)(pXData);
|
||||
// Specify the custom drawing callback
|
||||
sElem.pfuncXDraw = &gslc_ElemXSeekbarDraw;
|
||||
// Specify the custom touch tracking callback
|
||||
sElem.pfuncXTouch = &gslc_ElemXSeekbarTouch;
|
||||
|
||||
sElem.colElemFill = GSLC_COL_BLACK;
|
||||
sElem.colElemFillGlow = GSLC_COL_BLACK;
|
||||
sElem.colElemFrame = GSLC_COL_GRAY;
|
||||
sElem.colElemFrameGlow = GSLC_COL_WHITE;
|
||||
|
||||
if (nPage != GSLC_PAGE_NONE) {
|
||||
pElemRef = gslc_ElemAdd(pGui,nPage,&sElem,GSLC_ELEMREF_DEFAULT);
|
||||
return pElemRef;
|
||||
#if (GSLC_FEATURE_COMPOUND)
|
||||
} else {
|
||||
// Save as temporary element
|
||||
pGui->sElemTmp = sElem;
|
||||
pGui->sElemRefTmp.pElem = &(pGui->sElemTmp);
|
||||
pGui->sElemRefTmp.eElemFlags = GSLC_ELEMREF_DEFAULT | GSLC_ELEMREF_REDRAW_FULL;
|
||||
return &(pGui->sElemRefTmp);
|
||||
#endif
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void gslc_ElemXSeekbarSetStyle(gslc_tsGui* pGui,gslc_tsElemRef* pElemRef,
|
||||
bool bTrimThumb,gslc_tsColor colTrim,bool bFrameThumb,gslc_tsColor colFrame,uint16_t nTickDiv,
|
||||
int16_t nTickLen,gslc_tsColor colTick)
|
||||
{
|
||||
if (pElemRef == NULL) {
|
||||
static const char GSLC_PMEM FUNCSTR[] = "ElemXSeekbarSetStyle";
|
||||
GSLC_DEBUG2_PRINT_CONST(ERRSTR_NULL,FUNCSTR);
|
||||
return;
|
||||
}
|
||||
gslc_tsElem* pElem = gslc_GetElemFromRef(pGui,pElemRef);
|
||||
gslc_tsXSeekbar* pSeekbar = (gslc_tsXSeekbar*)(pElem->pXData);
|
||||
|
||||
pSeekbar->bTrimThumb = bTrimThumb;
|
||||
pSeekbar->colTrim = colTrim;
|
||||
pSeekbar->bFrameThumb = bFrameThumb;
|
||||
pSeekbar->colFrame = colFrame;
|
||||
pSeekbar->nTickDiv = nTickDiv;
|
||||
pSeekbar->nTickLen = nTickLen;
|
||||
pSeekbar->colTick = colTick;
|
||||
|
||||
// Update
|
||||
gslc_ElemSetRedraw(pGui,pElemRef,GSLC_REDRAW_FULL);
|
||||
}
|
||||
|
||||
int gslc_ElemXSeekbarGetPos(gslc_tsGui* pGui,gslc_tsElemRef* pElemRef)
|
||||
{
|
||||
if (pElemRef == NULL) {
|
||||
static const char GSLC_PMEM FUNCSTR[] = "ElemXSeekbarGetPos";
|
||||
GSLC_DEBUG2_PRINT_CONST(ERRSTR_NULL,FUNCSTR);
|
||||
return 0;
|
||||
}
|
||||
gslc_tsElem* pElem = gslc_GetElemFromRef(pGui,pElemRef);
|
||||
gslc_tsXSeekbar* pSeekbar = (gslc_tsXSeekbar*)(pElem->pXData);
|
||||
|
||||
return pSeekbar->nPos;
|
||||
}
|
||||
|
||||
// Update the slider control's current state
|
||||
void gslc_ElemXSeekbarSetPos(gslc_tsGui* pGui,gslc_tsElemRef* pElemRef,int16_t nPos)
|
||||
{
|
||||
if ((pGui == NULL) || (pElemRef == NULL)) {
|
||||
static const char GSLC_PMEM FUNCSTR[] = "ElemXSeekbarSetPos";
|
||||
GSLC_DEBUG2_PRINT_CONST(ERRSTR_NULL,FUNCSTR);
|
||||
return;
|
||||
}
|
||||
gslc_tsElem* pElem = gslc_GetElemFromRef(pGui,pElemRef);
|
||||
gslc_tsXSeekbar* pSeekbar = (gslc_tsXSeekbar*)(pElem->pXData);
|
||||
int16_t nPosOld;
|
||||
// Clip position
|
||||
if (nPos < pSeekbar->nPosMin) { nPos = pSeekbar->nPosMin; }
|
||||
if (nPos > pSeekbar->nPosMax) { nPos = pSeekbar->nPosMax; }
|
||||
// Update
|
||||
nPosOld = pSeekbar->nPos;
|
||||
pSeekbar->nPos = nPos;
|
||||
|
||||
// Only update if changed
|
||||
if (nPos != nPosOld) {
|
||||
// If any position callback is defined, call it now
|
||||
if (pSeekbar->pfuncXPos != NULL) {
|
||||
(*pSeekbar->pfuncXPos)((void*)(pGui),(void*)(pElemRef),nPos);
|
||||
}
|
||||
|
||||
// Mark for redraw
|
||||
// - Only need incremental redraw
|
||||
gslc_ElemSetRedraw(pGui,pElemRef,GSLC_REDRAW_INC);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
// Assign the position callback function for a slider
|
||||
void gslc_ElemXSeekbarSetPosFunc(gslc_tsGui* pGui,gslc_tsElemRef* pElemRef,GSLC_CB_XSEEKBAR_POS funcCb)
|
||||
{
|
||||
if ((pElemRef == NULL) || (funcCb == NULL)) {
|
||||
static const char GSLC_PMEM FUNCSTR[] = "ElemXSeekbarSetPosFunc";
|
||||
GSLC_DEBUG2_PRINT_CONST(ERRSTR_NULL,FUNCSTR);
|
||||
return;
|
||||
}
|
||||
gslc_tsElem* pElem = gslc_GetElemFromRef(pGui,pElemRef);
|
||||
gslc_tsXSeekbar* pSeekbar = (gslc_tsXSeekbar*)(pElem->pXData);
|
||||
pSeekbar->pfuncXPos = funcCb;
|
||||
}
|
||||
|
||||
|
||||
// Redraw the slider
|
||||
// - Note that this redraw is for the entire element rect region
|
||||
// - The Draw function parameters use void pointers to allow for
|
||||
// simpler callback function definition & scalability.
|
||||
bool gslc_ElemXSeekbarDraw(void* pvGui,void* pvElemRef,gslc_teRedrawType eRedraw)
|
||||
{
|
||||
if ((pvGui == NULL) || (pvElemRef == NULL)) {
|
||||
static const char GSLC_PMEM FUNCSTR[] = "ElemXSeekbarDraw";
|
||||
GSLC_DEBUG2_PRINT_CONST(ERRSTR_NULL,FUNCSTR);
|
||||
return false;
|
||||
}
|
||||
// Typecast the parameters to match the GUI and element types
|
||||
gslc_tsGui* pGui = (gslc_tsGui*)(pvGui);
|
||||
gslc_tsElemRef* pElemRef = (gslc_tsElemRef*)(pvElemRef);
|
||||
gslc_tsElem* pElem = gslc_GetElemFromRef(pGui,pElemRef);
|
||||
|
||||
// Fetch the element's extended data structure
|
||||
gslc_tsXSeekbar* pSeekbar;
|
||||
pSeekbar = (gslc_tsXSeekbar*)(pElem->pXData);
|
||||
if (pSeekbar == NULL) {
|
||||
GSLC_DEBUG2_PRINT("ERROR: ElemXSeekbarDraw(%s) pXData is NULL\n","");
|
||||
return false;
|
||||
}
|
||||
|
||||
bool bGlow = (pElem->nFeatures & GSLC_ELEM_FEA_GLOW_EN) && gslc_ElemGetGlow(pGui,pElemRef);
|
||||
int16_t nPos = pSeekbar->nPos;
|
||||
int16_t nPosMin = pSeekbar->nPosMin;
|
||||
int16_t nPosMax = pSeekbar->nPosMax;
|
||||
uint8_t nProgressW = pSeekbar->nProgressW;
|
||||
uint8_t nRemainW = pSeekbar->nRemainW;
|
||||
uint8_t nThumbSz = pSeekbar->nThumbSz;
|
||||
bool bVert = pSeekbar->bVert;
|
||||
bool bTrimThumb = pSeekbar->bTrimThumb;
|
||||
bool bFrameThumb = pSeekbar->bFrameThumb;
|
||||
uint16_t nTickDiv = pSeekbar->nTickDiv;
|
||||
int16_t nTickLen = pSeekbar->nTickLen;
|
||||
gslc_tsColor colProgress = pSeekbar->colProgress;
|
||||
gslc_tsColor colRemain = pSeekbar->colRemain;
|
||||
gslc_tsColor colThumb = pSeekbar->colThumb;
|
||||
gslc_tsColor colFrame = pSeekbar->colFrame;
|
||||
gslc_tsColor colTrim = pSeekbar->colTrim;
|
||||
gslc_tsColor colTick = pSeekbar->colTick;
|
||||
|
||||
// Range check on nPos
|
||||
if (nPos < nPosMin) { nPos = nPosMin; }
|
||||
if (nPos > nPosMax) { nPos = nPosMax; }
|
||||
|
||||
int16_t nX0,nY0,nX1,nY1,nXMid,nYMid;
|
||||
nX0 = pElem->rElem.x;
|
||||
nY0 = pElem->rElem.y;
|
||||
nX1 = pElem->rElem.x + pElem->rElem.w - 1;
|
||||
nY1 = pElem->rElem.y + pElem->rElem.h - 1;
|
||||
nXMid = (nX0+nX1)/2;
|
||||
nYMid = (nY0+nY1)/2;
|
||||
|
||||
// Scale the current position
|
||||
int16_t nPosRng = nPosMax-nPosMin;
|
||||
// TODO: Check for nPosRng=0, reversed min/max
|
||||
int16_t nPosOffset = nPos-nPosMin;
|
||||
|
||||
// Provide some margin so thumb doesn't exceed control bounds
|
||||
int16_t nMargin = nThumbSz;
|
||||
int16_t nCtrlRng;
|
||||
if (!bVert) {
|
||||
nCtrlRng = (nX1-nMargin)-(nX0+nMargin);
|
||||
} else {
|
||||
nCtrlRng = (nY1-nMargin)-(nY0+nMargin);
|
||||
}
|
||||
int16_t nCtrlPos = (nPosOffset*nCtrlRng/nPosRng)+nMargin;
|
||||
|
||||
int16_t nCtrlX0,nCtrlY0;
|
||||
gslc_tsRect rThumb;
|
||||
if (!bVert) {
|
||||
nCtrlX0 = nX0+nCtrlPos-nThumbSz;
|
||||
nCtrlY0 = nYMid-nThumbSz;
|
||||
} else {
|
||||
nCtrlX0 = nXMid-nThumbSz;
|
||||
nCtrlY0 = nY0+nCtrlPos-nThumbSz;
|
||||
}
|
||||
rThumb.x = nCtrlX0;
|
||||
rThumb.y = nCtrlY0;
|
||||
rThumb.w = 2*nThumbSz;
|
||||
rThumb.h = 2*nThumbSz;
|
||||
|
||||
|
||||
// Draw the thumb control
|
||||
// work out size of thumb circle
|
||||
int16_t nLeftX = rThumb.x+nThumbSz;
|
||||
int16_t nLeftY = rThumb.y + nThumbSz;
|
||||
|
||||
// Draw the background
|
||||
// - TODO: To reduce flicker on unbuffered displays, one could consider
|
||||
// redrawing only the thumb (last drawn position) with fill and
|
||||
// then redraw other portions. This would prevent the
|
||||
// track / ticks from flickering needlessly. A full redraw would
|
||||
// be required if it was first draw action.
|
||||
gslc_DrawFillRect(pGui,pElem->rElem,(bGlow)?pElem->colElemFillGlow:pElem->colElemFill);
|
||||
|
||||
// Draw the progress part of track
|
||||
if (!bVert) {
|
||||
gslc_tsRect rTrack = {
|
||||
nX0+nMargin,
|
||||
nYMid-(nProgressW/2),
|
||||
nCtrlPos,
|
||||
nProgressW
|
||||
};
|
||||
gslc_DrawFillRect(pGui,rTrack,colProgress);
|
||||
} else {
|
||||
gslc_tsRect rTrack = {
|
||||
nXMid-(nProgressW/2),
|
||||
nY0+nMargin,
|
||||
nProgressW,
|
||||
nCtrlPos
|
||||
};
|
||||
gslc_DrawFillRect(pGui,rTrack,colProgress);
|
||||
}
|
||||
|
||||
// test for thumb trim color
|
||||
if (bTrimThumb) {
|
||||
// two color thumb
|
||||
gslc_DrawFillCircle(pGui,nLeftX,nLeftY,nThumbSz,colTrim);
|
||||
gslc_DrawFillCircle(pGui,nLeftX,nLeftY,3,colThumb);
|
||||
} else {
|
||||
// one solid color thumb
|
||||
gslc_DrawFillCircle(pGui,nLeftX,nLeftY,nThumbSz,colProgress);
|
||||
}
|
||||
if (bFrameThumb) {
|
||||
gslc_DrawFrameCircle(pGui,nLeftX,nLeftY,nThumbSz,colFrame);
|
||||
}
|
||||
|
||||
// Draw the remaining part of track
|
||||
if (!bVert) {
|
||||
if (nRemainW == 1) {
|
||||
gslc_DrawLine(pGui,nX0+nMargin,nYMid,nX1-nMargin,nYMid,colRemain);
|
||||
} else {
|
||||
gslc_tsRect rRemain = {
|
||||
nX0+nMargin+nCtrlPos,
|
||||
nYMid-(nRemainW/2),
|
||||
nX1 - (nX0 + nCtrlPos+ nMargin*2) +1,
|
||||
nRemainW
|
||||
};
|
||||
gslc_DrawFillRect(pGui,rRemain,colRemain);
|
||||
}
|
||||
} else {
|
||||
if (nRemainW == 1) {
|
||||
gslc_DrawLine(pGui,nXMid,nY0+nMargin,nXMid,nY1-nMargin,colRemain);
|
||||
} else {
|
||||
gslc_tsRect rRemain = {
|
||||
nXMid-(nRemainW/2),
|
||||
nY0+nMargin+nCtrlPos,
|
||||
nRemainW,
|
||||
(nY1-nMargin)-(nY0+nMargin+nCtrlPos)
|
||||
};
|
||||
gslc_DrawFillRect(pGui,rRemain,colRemain);
|
||||
}
|
||||
}
|
||||
|
||||
// Draw any ticks - we need to do this last or the ticks get over written
|
||||
// - Need at least one tick segment
|
||||
if (nTickDiv>=1) {
|
||||
uint16_t nTickInd;
|
||||
int16_t nTickOffset;
|
||||
for (nTickInd=0;nTickInd<=nTickDiv;nTickInd++) {
|
||||
nTickOffset = nTickInd * nCtrlRng / nTickDiv;
|
||||
if (!bVert) {
|
||||
gslc_DrawLine(pGui,nX0+nMargin+nTickOffset,nYMid-(nTickLen/2),
|
||||
nX0+nTickOffset+nMargin,nYMid+(nTickLen/2),colTick);
|
||||
} else {
|
||||
gslc_DrawLine(pGui,nXMid+(nTickLen/2),nY0+nTickOffset+nMargin,nXMid-(nTickLen/2),
|
||||
nY0+nTickOffset+nMargin,colTick);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Clear the redraw flag
|
||||
gslc_ElemSetRedraw(pGui,pElemRef,GSLC_REDRAW_NONE);
|
||||
|
||||
// Mark page as needing flip
|
||||
gslc_PageFlipSet(pGui,true);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// This callback function is called by gslc_ElemSendEventTouch()
|
||||
// after any touch event
|
||||
bool gslc_ElemXSeekbarTouch(void* pvGui,void* pvElemRef,gslc_teTouch eTouch,int16_t nRelX,int16_t nRelY)
|
||||
{
|
||||
#if defined(DRV_TOUCH_NONE)
|
||||
return false;
|
||||
#else
|
||||
|
||||
if ((pvGui == NULL) || (pvElemRef == NULL)) {
|
||||
static const char GSLC_PMEM FUNCSTR[] = "ElemXSeekbarTouch";
|
||||
GSLC_DEBUG2_PRINT_CONST(ERRSTR_NULL,FUNCSTR);
|
||||
return false;
|
||||
}
|
||||
gslc_tsGui* pGui = NULL;
|
||||
gslc_tsElemRef* pElemRef = NULL;
|
||||
gslc_tsElem* pElem = NULL;
|
||||
gslc_tsXSeekbar* pSeekbar = NULL;
|
||||
|
||||
// Typecast the parameters to match the GUI
|
||||
pGui = (gslc_tsGui*)(pvGui);
|
||||
pElemRef = (gslc_tsElemRef*)(pvElemRef);
|
||||
pElem = gslc_GetElemFromRef(pGui,pElemRef);
|
||||
pSeekbar = (gslc_tsXSeekbar*)(pElem->pXData);
|
||||
|
||||
bool bGlowingOld = gslc_ElemGetGlow(pGui,pElemRef);
|
||||
int16_t nPosRng;
|
||||
int16_t nPos = 0;
|
||||
bool bUpdatePos = false;
|
||||
bool bIndexed = false;
|
||||
|
||||
switch(eTouch) {
|
||||
|
||||
case GSLC_TOUCH_DOWN_IN:
|
||||
// Start glowing as must be over it
|
||||
gslc_ElemSetGlow(pGui,pElemRef,true);
|
||||
bUpdatePos = true;
|
||||
break;
|
||||
|
||||
case GSLC_TOUCH_MOVE_IN:
|
||||
gslc_ElemSetGlow(pGui,pElemRef,true);
|
||||
bUpdatePos = true;
|
||||
break;
|
||||
case GSLC_TOUCH_MOVE_OUT:
|
||||
gslc_ElemSetGlow(pGui,pElemRef,false);
|
||||
bUpdatePos = true;
|
||||
break;
|
||||
|
||||
case GSLC_TOUCH_UP_IN:
|
||||
// End glow
|
||||
gslc_ElemSetGlow(pGui,pElemRef,false);
|
||||
break;
|
||||
case GSLC_TOUCH_UP_OUT:
|
||||
// End glow
|
||||
gslc_ElemSetGlow(pGui,pElemRef,false);
|
||||
break;
|
||||
|
||||
case GSLC_TOUCH_SET_REL:
|
||||
case GSLC_TOUCH_SET_ABS:
|
||||
bIndexed = true;
|
||||
gslc_ElemSetGlow(pGui,pElemRef,true);
|
||||
bUpdatePos = true;
|
||||
break;
|
||||
|
||||
default:
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
// If we need to update the slider position, calculate the value
|
||||
// and perform the update
|
||||
if (bUpdatePos) {
|
||||
|
||||
if (bIndexed) {
|
||||
// The position is changed by direct control (eg. keyboard)
|
||||
// instead of touch coordinates
|
||||
|
||||
// FIXME: Change the following to be either absolute or relative
|
||||
// value assignment instead of inc/dec. Then the user code can
|
||||
// define what the magnitude and direction should be.
|
||||
|
||||
if (eTouch == GSLC_TOUCH_SET_REL) {
|
||||
// Overload the "nRelY" parameter
|
||||
nPos = pSeekbar->nPos;
|
||||
nPos += nRelY;
|
||||
nPos = (nPos > pSeekbar->nPosMax)? pSeekbar->nPosMax : nPos;
|
||||
nPos = (nPos < pSeekbar->nPosMin)? pSeekbar->nPosMin : nPos;
|
||||
} else if (eTouch == GSLC_TOUCH_SET_ABS) {
|
||||
// Overload the "nRelY" parameter
|
||||
nPos = nRelY;
|
||||
nPos = (nPos > pSeekbar->nPosMax)? pSeekbar->nPosMax : nPos;
|
||||
nPos = (nPos < pSeekbar->nPosMin)? pSeekbar->nPosMin : nPos;
|
||||
}
|
||||
} else {
|
||||
// Perform additional range checking
|
||||
nRelX = (nRelX < 0)? 0 : nRelX;
|
||||
nRelY = (nRelY < 0)? 0 : nRelY;
|
||||
|
||||
// Calc new position
|
||||
nPosRng = pSeekbar->nPosMax - pSeekbar->nPosMin;
|
||||
if (!pSeekbar->bVert) {
|
||||
nPos = (nRelX * nPosRng / pElem->rElem.w) + pSeekbar->nPosMin;
|
||||
} else {
|
||||
nPos = (nRelY * nPosRng / pElem->rElem.h) + pSeekbar->nPosMin;
|
||||
}
|
||||
}
|
||||
// Update the slider
|
||||
gslc_ElemXSeekbarSetPos(pGui,pElemRef,nPos);
|
||||
}
|
||||
|
||||
// If the slider changed state, redraw
|
||||
if (gslc_ElemGetGlow(pGui,pElemRef) != bGlowingOld) {
|
||||
gslc_ElemSetRedraw(pGui,pElemRef,GSLC_REDRAW_FULL);
|
||||
}
|
||||
|
||||
return true;
|
||||
#endif // !DRV_TOUCH_NONE
|
||||
}
|
||||
|
||||
// ============================================================================
|
336
src/guislice/XSeekbar.h
Normal file
336
src/guislice/XSeekbar.h
Normal file
|
@ -0,0 +1,336 @@
|
|||
#ifndef _GUISLICE_EX_XSEEKBAR_H_
|
||||
#define _GUISLICE_EX_XSEEKBAR_H_
|
||||
|
||||
#include "GUIslice.h"
|
||||
|
||||
|
||||
// =======================================================================
|
||||
// GUIslice library extension: Seekbar control
|
||||
// - Paul Conti
|
||||
// - Seekbar is a modern Slider Control with Android like style
|
||||
// - Based on Calvin Hass's Slider control
|
||||
// - https://www.impulseadventure.com/elec/guislice-gui.html
|
||||
// - https://github.com/ImpulseAdventure/GUIslice
|
||||
// =======================================================================
|
||||
//
|
||||
// The MIT License
|
||||
//
|
||||
// Copyright 2016-2020 Calvin Hass
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
//
|
||||
// =======================================================================
|
||||
/// \file XSeekbar.h
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif // __cplusplus
|
||||
|
||||
|
||||
// ============================================================================
|
||||
// Extended Element: Seekbar
|
||||
// ============================================================================
|
||||
|
||||
// Define unique identifier for extended element type
|
||||
// - Select any number above GSLC_TYPE_BASE_EXTEND
|
||||
#define GSLC_TYPEX_SEEKBAR GSLC_TYPE_BASE_EXTEND + 6
|
||||
|
||||
/// Callback function for slider feedback
|
||||
typedef bool (*GSLC_CB_XSEEKBAR_POS)(void* pvGui,void* pvElem,int16_t nPos);
|
||||
|
||||
// Extended element data structures
|
||||
// - These data structures are maintained in the gslc_tsElem
|
||||
// structure via the pXData pointer
|
||||
|
||||
/// Extended data for Seekbar element
|
||||
typedef struct {
|
||||
// Config
|
||||
bool bVert; ///< Orientation: true if vertical, else horizontal
|
||||
uint8_t nProgressW; ///< Width of progress track
|
||||
uint8_t nRemainW; ///< Width of remaining track
|
||||
uint8_t nThumbSz; ///< Size of the thumb control
|
||||
int16_t nPosMin; ///< Minimum position value of the slider
|
||||
int16_t nPosMax; ///< Maximum position value of the slider
|
||||
// Style config
|
||||
gslc_tsColor colProgress; ///< Style: color of progress fill bar
|
||||
gslc_tsColor colRemain; ///< Style: color remaining fill bar
|
||||
gslc_tsColor colThumb; ///< Style: color of thumb
|
||||
uint16_t nTickDiv; ///< Style: number of tickmark divisions (0 for none)
|
||||
int16_t nTickLen; ///< Style: length of tickmarks
|
||||
gslc_tsColor colTick; ///< Style: color of ticks
|
||||
bool bTrimThumb; ///< Style: show a trim color for thumb
|
||||
gslc_tsColor colTrim; ///< Style: color of trim
|
||||
bool bFrameThumb; ///< Style: draw frame around thumb
|
||||
gslc_tsColor colFrame; ///< Style: color of trim
|
||||
// State
|
||||
int16_t nPos; ///< Current position value of the slider
|
||||
// Callbacks
|
||||
GSLC_CB_XSEEKBAR_POS pfuncXPos; ///< Callback func ptr for position update
|
||||
} gslc_tsXSeekbar;
|
||||
|
||||
|
||||
///
|
||||
/// Create a Seekbar Element
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] nElemId: Element ID to assign (0..16383 or GSLC_ID_AUTO to autogen)
|
||||
/// \param[in] nPage: Page ID to attach element to
|
||||
/// \param[in] pXData: Ptr to extended element data structure
|
||||
/// \param[in] rElem: Rectangle coordinates defining checkbox size
|
||||
/// \param[in] nPosMin: Minimum position value
|
||||
/// \param[in] nPosMax: Maximum position value
|
||||
/// \param[in] nPos: Starting position value
|
||||
/// \param[in] nProgressW: Width of progress track
|
||||
/// \param[in] nRemainW: Width of remaining track
|
||||
/// \param[in] nThumbSz: Size of the thumb control
|
||||
/// \param[in] colProgress: Color of progress fill bar
|
||||
/// \param[in] colRemain: Color remaining fill bar
|
||||
/// \param[in] colThumb: Color for the thumb indicator
|
||||
/// \param[in] bVert: Orientation (true for vertical)
|
||||
///
|
||||
/// \return Pointer to Element reference or NULL if failure
|
||||
///
|
||||
gslc_tsElemRef* gslc_ElemXSeekbarCreate(gslc_tsGui* pGui,int16_t nElemId,int16_t nPage,
|
||||
gslc_tsXSeekbar* pXData,gslc_tsRect rElem,int16_t nPosMin,int16_t nPosMax,int16_t nPos,
|
||||
uint8_t nProgressW,uint8_t nRemainW,uint8_t nThumbSz,
|
||||
gslc_tsColor colProgress,gslc_tsColor colRemain,gslc_tsColor colThumb,bool bVert);
|
||||
|
||||
|
||||
///
|
||||
/// Set a Seekbar element's style, this includes thumb customizations and tick marks
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] pElemRef: Pointer to Element reference
|
||||
/// \param[in] bTrimThumb: Show a colored trim for thumb?
|
||||
/// \param[in] colTrim: Color of thumb trim
|
||||
/// \param[in] bFrameThumb: Show a frame around thumb?
|
||||
/// \param[in] colFrame: Color of thumb frame
|
||||
/// \param[in] nTickDiv: Number of tick divisions to show (0 for none)
|
||||
/// \param[in] nTickLen: Length of tick marks
|
||||
/// \param[in] colTick: Color of ticks
|
||||
///
|
||||
/// \return none
|
||||
///
|
||||
void gslc_ElemXSeekbarSetStyle(gslc_tsGui* pGui,gslc_tsElemRef* pElemRef,
|
||||
bool bTrimThumb,gslc_tsColor colTrim,bool bFrameThumb,gslc_tsColor colFrame,uint16_t nTickDiv,
|
||||
int16_t nTickLen,gslc_tsColor colTick);
|
||||
|
||||
///
|
||||
/// Get a Seekbar element's current position
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] pElemRef: Pointer to Element reference
|
||||
///
|
||||
/// \return Current slider position
|
||||
///
|
||||
int gslc_ElemXSeekbarGetPos(gslc_tsGui* pGui,gslc_tsElemRef* pElemRef);
|
||||
|
||||
|
||||
///
|
||||
/// Set a Seekbar element's current position
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] pElemRef: Pointer to Element reference
|
||||
/// \param[in] nPos: New position value
|
||||
///
|
||||
/// \return none
|
||||
///
|
||||
void gslc_ElemXSeekbarSetPos(gslc_tsGui* pGui,gslc_tsElemRef* pElemRef,int16_t nPos);
|
||||
|
||||
///
|
||||
/// Assign the position callback function for a slider
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] pElemRef: Pointer to Element reference
|
||||
/// \param[in] funcCb: Function pointer to position routine (or NULL for none)
|
||||
///
|
||||
/// \return none
|
||||
///
|
||||
void gslc_ElemXSeekbarSetPosFunc(gslc_tsGui* pGui,gslc_tsElemRef* pElemRef,GSLC_CB_XSEEKBAR_POS funcCb);
|
||||
|
||||
///
|
||||
/// Draw a Seekbar element on the screen
|
||||
/// - Called from gslc_ElemDraw()
|
||||
///
|
||||
/// \param[in] pvGui: Void ptr to GUI (typecast to gslc_tsGui*)
|
||||
/// \param[in] pvElemRef: Void ptr to Element (typecast to gslc_tsElemRef*)
|
||||
/// \param[in] eRedraw: Redraw mode
|
||||
///
|
||||
/// \return true if success, false otherwise
|
||||
///
|
||||
bool gslc_ElemXSeekbarDraw(void* pvGui,void* pvElemRef,gslc_teRedrawType eRedraw);
|
||||
|
||||
///
|
||||
/// Handle touch events to Seekbar element
|
||||
/// - Called from gslc_ElemSendEventTouch()
|
||||
///
|
||||
/// \param[in] pvGui: Void ptr to GUI (typecast to gslc_tsGui*)
|
||||
/// \param[in] pvElemRef: Void ptr to Element ref (typecast to gslc_tsElemRef*)
|
||||
/// \param[in] eTouch: Touch event type
|
||||
/// \param[in] nRelX: Touch X coord relative to element
|
||||
/// \param[in] nRelY: Touch Y coord relative to element
|
||||
///
|
||||
/// \return true if success, false otherwise
|
||||
///
|
||||
bool gslc_ElemXSeekbarTouch(void* pvGui,void* pvElemRef,gslc_teTouch eTouch,int16_t nRelX,int16_t nRelY);
|
||||
|
||||
// ============================================================================
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Read-only element macros
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
// Macro initializers for Read-Only Elements in Flash/PROGMEM
|
||||
//
|
||||
|
||||
|
||||
|
||||
/// \def gslc_ElemXSeekbarCreate_P(pGui,nElemId,nPage,nX,nY,nW,nH,
|
||||
/// nPosMin_,nPosMax_,nPos_,nThumbSz_,bVert_,colFrame_,colFill_)
|
||||
///
|
||||
/// Create a Seekbar Element in Flash
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] nElemId: Unique element ID to assign
|
||||
/// \param[in] nPage: Page ID to attach element to
|
||||
/// \param[in] nX: X coordinate of element
|
||||
/// \param[in] nY: Y coordinate of element
|
||||
/// \param[in] nW: Width of element
|
||||
/// \param[in] nH: Height of element
|
||||
/// \param[in] nPosMin_: Minimum position value
|
||||
/// \param[in] nPosMax_: Maximum position value
|
||||
/// \param[in] nPos_: Starting position value
|
||||
/// \param[in] nProgressW_: Width of progress track
|
||||
/// \param[in] nRemainW_: Width of remaining track
|
||||
/// \param[in] nThumbSz_: Size of the thumb control
|
||||
/// \param[in] colProgress_: Color of progress fill bar
|
||||
/// \param[in] colRemain_: Color remaining fill bar
|
||||
/// \param[in] colThumb_: Color for the thumb indicator
|
||||
/// \param[in] bVert_: Orientation (true for vertical)
|
||||
/// \param[in] colFrame_: Color of the element frame
|
||||
/// \param[in] colFill_: Color of the element fill
|
||||
///
|
||||
/// \return none
|
||||
///
|
||||
|
||||
#if (GSLC_USE_PROGMEM)
|
||||
|
||||
|
||||
#define gslc_ElemXSeekbarCreate_P(pGui,nElemId,nPage,nX,nY,nW,nH,nPosMin_,nPosMax_, \
|
||||
nPos_,nProgressW_,nRemainW_,nThumbSz_,colProgress_,colRemain_,colThumb_,bVert_, \
|
||||
colFrame_,colFill_) \
|
||||
static const uint8_t nFeatures##nElemId = GSLC_ELEM_FEA_VALID | \
|
||||
GSLC_ELEM_FEA_GLOW_EN | GSLC_ELEM_FEA_CLICK_EN | GSLC_ELEM_FEA_FILL_EN; \
|
||||
static gslc_tsXSeekbar sSeekbar##nElemId; \
|
||||
sSeekbar##nElemId.bVert = bVert_; \
|
||||
sSeekbar##nElemId.nProgressW = nProgressW_; \
|
||||
sSeekbar##nElemId.nRemainW = nRemainW_; \
|
||||
sSeekbar##nElemId.nThumbSz = nThumbSz_; \
|
||||
sSeekbar##nElemId.nPosMin = nPosMin_; \
|
||||
sSeekbar##nElemId.nPosMax = nPosMax_; \
|
||||
sSeekbar##nElemId.colProgress = colProgress_; \
|
||||
sSeekbar##nElemId.colRemain = colRemain_; \
|
||||
sSeekbar##nElemId.colThumb = colThumb_; \
|
||||
sSeekbar##nElemId.nPos = nPos_; \
|
||||
sSeekbar##nElemId.pfuncXPos = NULL; \
|
||||
static const gslc_tsElem sElem##nElemId PROGMEM = { \
|
||||
nElemId, \
|
||||
nFeatures##nElemId, \
|
||||
GSLC_TYPEX_SEEKBAR, \
|
||||
(gslc_tsRect){nX,nY,nW,nH}, \
|
||||
GSLC_GROUP_ID_NONE, \
|
||||
colFrame_,colFill_,colFrame_,colFill_, \
|
||||
(gslc_tsImgRef){NULL,NULL,GSLC_IMGREF_NONE,NULL}, \
|
||||
(gslc_tsImgRef){NULL,NULL,GSLC_IMGREF_NONE,NULL}, \
|
||||
NULL, \
|
||||
NULL, \
|
||||
0, \
|
||||
(gslc_teTxtFlags)(GSLC_TXT_DEFAULT), \
|
||||
GSLC_COL_WHITE, \
|
||||
GSLC_COL_WHITE, \
|
||||
GSLC_ALIGN_MID_MID, \
|
||||
0, \
|
||||
0, \
|
||||
NULL, \
|
||||
(void*)(&sSeekbar##nElemId), \
|
||||
NULL, \
|
||||
&gslc_ElemXSeekbarDraw, \
|
||||
&gslc_ElemXSeekbarTouch, \
|
||||
NULL, \
|
||||
}; \
|
||||
gslc_ElemAdd(pGui,nPage,(gslc_tsElem*)&sElem##nElemId, \
|
||||
(gslc_teElemRefFlags)(GSLC_ELEMREF_SRC_PROG | GSLC_ELEMREF_VISIBLE | GSLC_ELEMREF_REDRAW_FULL));
|
||||
|
||||
#else
|
||||
|
||||
|
||||
#define gslc_ElemXSeekbarCreate_P(pGui,nElemId,nPage,nX,nY,nW,nH,nPosMin_,nPosMax_, \
|
||||
nPos_,nProgressW_,nRemainW_,nThumbSz_,colProgress_,colRemain_,colThumb_,bVert_, \
|
||||
colFrame_,colFill_) \
|
||||
static const uint8_t nFeatures##nElemId = GSLC_ELEM_FEA_VALID | \
|
||||
GSLC_ELEM_FEA_GLOW_EN | GSLC_ELEM_FEA_CLICK_EN | GSLC_ELEM_FEA_FILL_EN; \
|
||||
static gslc_tsXSeekbar sSeekbar##nElemId; \
|
||||
sSeekbar##nElemId.bVert = bVert_; \
|
||||
sSeekbar##nElemId.nProgressW = nProgressW_; \
|
||||
sSeekbar##nElemId.nRemainW = nRemainW_; \
|
||||
sSeekbar##nElemId.nThumbSz = nThumbSz_; \
|
||||
sSeekbar##nElemId.nPosMin = nPosMin_; \
|
||||
sSeekbar##nElemId.nPosMax = nPosMax_; \
|
||||
sSeekbar##nElemId.colProgress = colProgress_; \
|
||||
sSeekbar##nElemId.colRemain = colRemain_; \
|
||||
sSeekbar##nElemId.colThumb = colThumb_; \
|
||||
sSeekbar##nElemId.nPos = nPos_; \
|
||||
sSeekbar##nElemId.pfuncXPos = NULL; \
|
||||
static const gslc_tsElem sElem##nElemId = { \
|
||||
nElemId, \
|
||||
nFeatures##nElemId, \
|
||||
GSLC_TYPEX_SEEKBAR, \
|
||||
(gslc_tsRect){nX,nY,nW,nH}, \
|
||||
GSLC_GROUP_ID_NONE, \
|
||||
colFrame_,colFill_,colFrame_,colFill_, \
|
||||
(gslc_tsImgRef){NULL,NULL,GSLC_IMGREF_NONE,NULL}, \
|
||||
(gslc_tsImgRef){NULL,NULL,GSLC_IMGREF_NONE,NULL}, \
|
||||
NULL, \
|
||||
NULL, \
|
||||
0, \
|
||||
(gslc_teTxtFlags)(GSLC_TXT_DEFAULT), \
|
||||
GSLC_COL_WHITE, \
|
||||
GSLC_COL_WHITE, \
|
||||
GSLC_ALIGN_MID_MID, \
|
||||
0, \
|
||||
0, \
|
||||
NULL, \
|
||||
(void*)(&sSeekbar##nElemId), \
|
||||
NULL, \
|
||||
&gslc_ElemXSeekbarDraw, \
|
||||
&gslc_ElemXSeekbarTouch, \
|
||||
NULL, \
|
||||
}; \
|
||||
gslc_ElemAdd(pGui,nPage,(gslc_tsElem*)&sElem##nElemId, \
|
||||
(gslc_teElemRefFlags)(GSLC_ELEMREF_SRC_CONST | GSLC_ELEMREF_VISIBLE | GSLC_ELEMREF_REDRAW_FULL));
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif // __cplusplus
|
||||
#endif // _GUISLICE_EX_XSEEKBAR_H_
|
384
src/guislice/XSelNum.c
Normal file
384
src/guislice/XSelNum.c
Normal file
|
@ -0,0 +1,384 @@
|
|||
// =======================================================================
|
||||
// GUIslice library (extensions)
|
||||
// - Calvin Hass
|
||||
// - https://www.impulseadventure.com/elec/guislice-gui.html
|
||||
// - https://github.com/ImpulseAdventure/GUIslice
|
||||
// =======================================================================
|
||||
//
|
||||
// The MIT License
|
||||
//
|
||||
// Copyright 2016-2020 Calvin Hass
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
//
|
||||
// =======================================================================
|
||||
/// \file XSelNum.c
|
||||
|
||||
|
||||
|
||||
// GUIslice library
|
||||
#include "GUIslice.h"
|
||||
#include "GUIslice_drv.h"
|
||||
|
||||
#include "XSelNum.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#if (GSLC_USE_PROGMEM)
|
||||
#include <avr/pgmspace.h>
|
||||
#endif
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Error Messages
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
extern const char GSLC_PMEM ERRSTR_NULL[];
|
||||
extern const char GSLC_PMEM ERRSTR_PXD_NULL[];
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Extended element definitions
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// - This file extends the core GUIslice functionality with
|
||||
// additional widget types
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
|
||||
#if (GSLC_FEATURE_COMPOUND)
|
||||
// ============================================================================
|
||||
// Extended Element: SelNum
|
||||
// - SelNum (Select Number) element demonstrates a simple up/down counter
|
||||
// - This is a compound element containing two buttons and
|
||||
// a text area to represent the current count
|
||||
// ============================================================================
|
||||
|
||||
// Private sub Element ID definitions
|
||||
static const int16_t SELNUM_ID_BTN_INC = 100;
|
||||
static const int16_t SELNUM_ID_BTN_DEC = 101;
|
||||
static const int16_t SELNUM_ID_TXT = 102;
|
||||
|
||||
// Create a compound element
|
||||
// - For now just two buttons and a text area
|
||||
gslc_tsElemRef* gslc_ElemXSelNumCreate(gslc_tsGui* pGui,int16_t nElemId,int16_t nPage,
|
||||
gslc_tsXSelNum* pXData,gslc_tsRect rElem,int8_t nFontId)
|
||||
{
|
||||
|
||||
if ((pGui == NULL) || (pXData == NULL)) {
|
||||
static const char GSLC_PMEM FUNCSTR[] = "ElemXSelNumCreate";
|
||||
GSLC_DEBUG2_PRINT_CONST(ERRSTR_NULL,FUNCSTR);
|
||||
return NULL;
|
||||
}
|
||||
gslc_tsElem sElem;
|
||||
|
||||
|
||||
// Initialize composite element
|
||||
sElem = gslc_ElemCreate(pGui,nElemId,nPage,GSLC_TYPEX_SELNUM,rElem,NULL,0,GSLC_FONT_NONE);
|
||||
sElem.nFeatures |= GSLC_ELEM_FEA_FRAME_EN;
|
||||
sElem.nFeatures |= GSLC_ELEM_FEA_FILL_EN;
|
||||
sElem.nFeatures |= GSLC_ELEM_FEA_CLICK_EN;
|
||||
sElem.nFeatures &= ~GSLC_ELEM_FEA_GLOW_EN; // Don't need to glow outer element
|
||||
sElem.nGroup = GSLC_GROUP_ID_NONE;
|
||||
|
||||
pXData->nCounter = 0;
|
||||
|
||||
// Determine the maximum number of elements that we can store
|
||||
// in the sub-element array. We do this at run-time with sizeof()
|
||||
// instead of using #define to avoid polluting the global namespace.
|
||||
int16_t nSubElemMax = sizeof(pXData->asElem) / sizeof(pXData->asElem[0]);
|
||||
|
||||
// NOTE: The count parameters in CollectReset() must match the size of
|
||||
// the asElem[] array. It is used for bounds checking when we
|
||||
// add new elements.
|
||||
// NOTE: We only use RAM for subelement storage
|
||||
gslc_CollectReset(&pXData->sCollect,pXData->asElem,nSubElemMax,pXData->asElemRef,nSubElemMax);
|
||||
|
||||
|
||||
sElem.pXData = (void*)(pXData);
|
||||
// Specify the custom drawing callback
|
||||
sElem.pfuncXDraw = &gslc_ElemXSelNumDraw;
|
||||
// Specify the custom touch tracking callback
|
||||
sElem.pfuncXTouch = &gslc_ElemXSelNumTouch;
|
||||
|
||||
sElem.colElemFill = GSLC_COL_BLACK;
|
||||
sElem.colElemFillGlow = GSLC_COL_BLACK;
|
||||
sElem.colElemFrame = GSLC_COL_GRAY;
|
||||
sElem.colElemFrameGlow = GSLC_COL_WHITE;
|
||||
|
||||
|
||||
// Now create the sub elements
|
||||
// - Ensure page is set to GSLC_PAGE_NONE so that
|
||||
// we create the element struct but not add it to a specific page.
|
||||
// - When we create an element with GSLC_PAGE_NONE it is
|
||||
// saved in the GUI's temporary element storage.
|
||||
// - When we have finished creating / styling the element, we then
|
||||
// copy it into the permanent sub-element storage
|
||||
|
||||
// - The element IDs assigned to the sub-elements are
|
||||
// arbitrary (with local scope in the compound element),
|
||||
// so they don't need to be unique globally across the GUI.
|
||||
gslc_tsElemRef* pElemRefTmp = NULL;
|
||||
gslc_tsElem* pElemTmp = NULL;
|
||||
gslc_tsElemRef* pElemRef = NULL;
|
||||
|
||||
// Determine offset coordinate of compound element so that we can
|
||||
// specify relative positioning during the sub-element Create() operations.
|
||||
int16_t nOffsetX = rElem.x;
|
||||
int16_t nOffsetY = rElem.y;
|
||||
|
||||
gslc_tsRect rSubElem;
|
||||
|
||||
rSubElem = (gslc_tsRect) { nOffsetX+40,nOffsetY+10,30,30 };
|
||||
rSubElem = gslc_ExpandRect(rSubElem, -1, -1);
|
||||
#if (GSLC_LOCAL_STR)
|
||||
pElemRefTmp = gslc_ElemCreateBtnTxt(pGui,SELNUM_ID_BTN_INC,GSLC_PAGE_NONE,
|
||||
rSubElem,"+",0,nFontId,&gslc_ElemXSelNumClick);
|
||||
#else
|
||||
strncpy(pXData->acElemTxt[0],"+",SELNUM_STR_LEN-1);
|
||||
pElemRefTmp = gslc_ElemCreateBtnTxt(pGui,SELNUM_ID_BTN_INC,GSLC_PAGE_NONE,
|
||||
rSubElem,pXData->acElemTxt[0],SELNUM_STR_LEN,
|
||||
nFontId,&gslc_ElemXSelNumClick);
|
||||
#endif
|
||||
gslc_ElemSetCol(pGui,pElemRefTmp,(gslc_tsColor){0,0,192},(gslc_tsColor){0,0,128},(gslc_tsColor){0,0,224});
|
||||
gslc_ElemSetTxtCol(pGui,pElemRefTmp,GSLC_COL_WHITE);
|
||||
pElemTmp = gslc_GetElemFromRef(pGui,pElemRefTmp);
|
||||
gslc_CollectElemAdd(pGui,&pXData->sCollect,pElemTmp,GSLC_ELEMREF_DEFAULT);
|
||||
|
||||
rSubElem = (gslc_tsRect) { nOffsetX+80,nOffsetY+10,30,30 };
|
||||
rSubElem = gslc_ExpandRect(rSubElem, -1, -1);
|
||||
#if (GSLC_LOCAL_STR)
|
||||
pElemRefTmp = gslc_ElemCreateBtnTxt(pGui,SELNUM_ID_BTN_DEC,GSLC_PAGE_NONE,
|
||||
rSubElem,"-",0,nFontId,&gslc_ElemXSelNumClick);
|
||||
#else
|
||||
strncpy(pXData->acElemTxt[1],"-",SELNUM_STR_LEN-1);
|
||||
pElemRefTmp = gslc_ElemCreateBtnTxt(pGui,SELNUM_ID_BTN_DEC,GSLC_PAGE_NONE,
|
||||
rSubElem,pXData->acElemTxt[1],SELNUM_STR_LEN,
|
||||
nFontId,&gslc_ElemXSelNumClick);
|
||||
#endif
|
||||
gslc_ElemSetCol(pGui,pElemRefTmp,(gslc_tsColor){0,0,192},(gslc_tsColor){0,0,128},(gslc_tsColor){0,0,224});
|
||||
gslc_ElemSetTxtCol(pGui,pElemRefTmp,GSLC_COL_WHITE);
|
||||
pElemTmp = gslc_GetElemFromRef(pGui,pElemRefTmp);
|
||||
gslc_CollectElemAdd(pGui,&pXData->sCollect,pElemTmp,GSLC_ELEMREF_DEFAULT);
|
||||
|
||||
rSubElem = (gslc_tsRect) { nOffsetX+10,nOffsetY+10,20,30 };
|
||||
rSubElem = gslc_ExpandRect(rSubElem, -1, -1);
|
||||
#if (GSLC_LOCAL_STR)
|
||||
pElemRefTmp = gslc_ElemCreateTxt(pGui,SELNUM_ID_TXT,GSLC_PAGE_NONE,
|
||||
rSubElem,"0",0,nFontId);
|
||||
#else
|
||||
strncpy(pXData->acElemTxt[2],"0",SELNUM_STR_LEN-1);
|
||||
pElemRefTmp = gslc_ElemCreateTxt(pGui,SELNUM_ID_TXT,GSLC_PAGE_NONE,
|
||||
rSubElem,pXData->acElemTxt[2],SELNUM_STR_LEN,nFontId);
|
||||
#endif
|
||||
pElemTmp = gslc_GetElemFromRef(pGui,pElemRefTmp);
|
||||
gslc_CollectElemAdd(pGui,&pXData->sCollect,pElemTmp,GSLC_ELEMREF_DEFAULT);
|
||||
|
||||
|
||||
// Now proceed to add the compound element to the page
|
||||
if (nPage != GSLC_PAGE_NONE) {
|
||||
pElemRef = gslc_ElemAdd(pGui,nPage,&sElem,GSLC_ELEMREF_DEFAULT);
|
||||
|
||||
// Now propagate the parent relationship to enable a cascade
|
||||
// of redrawing from low-level elements to the top
|
||||
gslc_CollectSetParent(pGui,&pXData->sCollect,pElemRef);
|
||||
|
||||
return pElemRef;
|
||||
} else {
|
||||
GSLC_DEBUG2_PRINT("ERROR: ElemXSelNumCreate(%s) Compound elements inside compound elements not supported\n","");
|
||||
return NULL;
|
||||
|
||||
// TODO: For now, disable compound elements within
|
||||
// compound elements. If we want to enable this, we
|
||||
// would probably use the temporary element reference
|
||||
// the GUI.
|
||||
// Save as temporary element for further processing
|
||||
//pGui->sElemTmp = sElem; // Need fixing
|
||||
//return &(pGui->sElemTmp); // Need fixing
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
// Redraw the compound element
|
||||
// - When drawing a compound element, we clear the background
|
||||
// and then redraw the sub-element collection.
|
||||
bool gslc_ElemXSelNumDraw(void* pvGui,void* pvElemRef,gslc_teRedrawType eRedraw)
|
||||
{
|
||||
gslc_tsGui* pGui = (gslc_tsGui*)(pvGui);
|
||||
gslc_tsElemRef* pElemRef = (gslc_tsElemRef*)(pvElemRef);
|
||||
gslc_tsElem* pElem = gslc_GetElemFromRef(pGui,pElemRef);
|
||||
gslc_tsXSelNum* pSelNum = (gslc_tsXSelNum*)gslc_GetXDataFromRef(pGui, pElemRef, GSLC_TYPEX_SELNUM, __LINE__);
|
||||
if (!pSelNum) return false;
|
||||
|
||||
bool bGlow = (pElem->nFeatures & GSLC_ELEM_FEA_GLOW_EN) && gslc_ElemGetGlow(pGui,pElemRef);
|
||||
|
||||
// Draw the compound element fill (background)
|
||||
// - Should only need to do this in full redraw
|
||||
if (eRedraw == GSLC_REDRAW_FULL) {
|
||||
gslc_DrawFillRect(pGui,pElem->rElem,(bGlow)?pElem->colElemFillGlow:pElem->colElemFill);
|
||||
}
|
||||
|
||||
// Draw the sub-elements
|
||||
// - For now, force redraw of entire compound element
|
||||
gslc_tsCollect* pCollect = &pSelNum->sCollect;
|
||||
|
||||
gslc_tsEvent sEvent = gslc_EventCreate(pGui,GSLC_EVT_DRAW,GSLC_EVTSUB_DRAW_FORCE,(void*)(pCollect),NULL);
|
||||
gslc_CollectEvent(pGui,sEvent);
|
||||
|
||||
// Optionally, draw a frame around the compound element
|
||||
// - This could instead be done by creating a sub-element
|
||||
// of type box.
|
||||
// - We don't need to show any glowing of the compound element
|
||||
|
||||
if (eRedraw == GSLC_REDRAW_FULL) {
|
||||
gslc_DrawFrameRect(pGui, pElem->rElem, (bGlow) ? pElem->colElemFrameGlow : pElem->colElemFrame);
|
||||
}
|
||||
|
||||
// Clear the redraw flag
|
||||
gslc_ElemSetRedraw(pGui,pElemRef,GSLC_REDRAW_NONE);
|
||||
|
||||
// Mark page as needing flip
|
||||
gslc_PageFlipSet(pGui,true);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Fetch the current value of the element's counter
|
||||
int gslc_ElemXSelNumGetCounter(gslc_tsGui* pGui,gslc_tsXSelNum* pSelNum)
|
||||
{
|
||||
if ((pGui == NULL) || (pSelNum == NULL)) {
|
||||
static const char GSLC_PMEM FUNCSTR[] = "ElemXSelNumGetCounter";
|
||||
GSLC_DEBUG2_PRINT_CONST(ERRSTR_NULL,FUNCSTR);
|
||||
return 0;
|
||||
}
|
||||
return pSelNum->nCounter;
|
||||
}
|
||||
|
||||
|
||||
void gslc_ElemXSelNumSetCounter(gslc_tsGui* pGui,gslc_tsXSelNum* pSelNum,int16_t nCount)
|
||||
{
|
||||
if (pSelNum == NULL) {
|
||||
static const char GSLC_PMEM FUNCSTR[] = "ElemXSelNumSetCounter";
|
||||
GSLC_DEBUG2_PRINT_CONST(ERRSTR_NULL,FUNCSTR);
|
||||
return;
|
||||
}
|
||||
pSelNum->nCounter = nCount;
|
||||
|
||||
// Determine new counter text
|
||||
// FIXME: Consider replacing the printf() with an optimized function to
|
||||
// conserve RAM. Potentially leverage GSLC_DEBUG2_PRINT().
|
||||
char acStrNew[GSLC_LOCAL_STR_LEN];
|
||||
snprintf(acStrNew,GSLC_LOCAL_STR_LEN,"%hd",pSelNum->nCounter);
|
||||
|
||||
// Update the element
|
||||
gslc_tsElemRef* pElemRef = gslc_CollectFindElemById(pGui,&pSelNum->sCollect,SELNUM_ID_TXT);
|
||||
gslc_ElemSetTxtStr(pGui,pElemRef,acStrNew);
|
||||
|
||||
}
|
||||
|
||||
|
||||
// Handle the compound element main functionality
|
||||
// - This routine is called by gslc_ElemEvent() to handle
|
||||
// any click events that resulted from the touch tracking process.
|
||||
// - The code here will generally represent the core
|
||||
// functionality of the compound element and any communication
|
||||
// between sub-elements.
|
||||
// - pvElemRef is a void pointer to the element ref being tracked. From
|
||||
// the pElemRefParent member we can get the parent/compound element
|
||||
// data structures.
|
||||
bool gslc_ElemXSelNumClick(void* pvGui,void *pvElemRef,gslc_teTouch eTouch,int16_t nX,int16_t nY)
|
||||
{
|
||||
#if defined(DRV_TOUCH_NONE)
|
||||
return false;
|
||||
#else
|
||||
|
||||
gslc_tsGui* pGui = (gslc_tsGui*)(pvGui);
|
||||
gslc_tsElemRef* pElemRef = (gslc_tsElemRef*)(pvElemRef);
|
||||
gslc_tsElem* pElem = gslc_GetElemFromRefD(pGui, pElemRef, __LINE__);
|
||||
if (!pElem) return false;
|
||||
|
||||
// Fetch the parent of the clicked element which is the compound
|
||||
// element itself. This enables us to access the extra control data.
|
||||
gslc_tsElemRef* pElemRefParent = pElem->pElemRefParent;
|
||||
if (pElemRefParent == NULL) {
|
||||
GSLC_DEBUG2_PRINT("ERROR: ElemXSelNumClick(%s) parent ElemRef ptr NULL\n","");
|
||||
return false;
|
||||
}
|
||||
|
||||
gslc_tsElem* pElemParent = gslc_GetElemFromRef(pGui,pElemRefParent);
|
||||
gslc_tsXSelNum* pSelNum = (gslc_tsXSelNum*)(pElemParent->pXData);
|
||||
if (pSelNum == NULL) {
|
||||
GSLC_DEBUG2_PRINT("ERROR: ElemXSelNumClick() element (ID=%d) has NULL pXData\n",pElem->nId);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Begin the core compound element functionality
|
||||
int nCounter = pSelNum->nCounter;
|
||||
|
||||
// Handle the various button presses
|
||||
if (eTouch == GSLC_TOUCH_UP_IN) {
|
||||
|
||||
// Get the tracked element ID
|
||||
gslc_tsElemRef* pElemRefTracked = pSelNum->sCollect.pElemRefTracked;
|
||||
gslc_tsElem* pElemTracked = gslc_GetElemFromRef(pGui,pElemRefTracked);
|
||||
int nSubElemId = pElemTracked->nId;
|
||||
|
||||
if (nSubElemId == SELNUM_ID_BTN_INC) {
|
||||
// Increment button
|
||||
if (nCounter < 100) {
|
||||
nCounter++;
|
||||
}
|
||||
gslc_ElemXSelNumSetCounter(pGui,pSelNum,nCounter);
|
||||
|
||||
} else if (nSubElemId == SELNUM_ID_BTN_DEC) {
|
||||
// Decrement button
|
||||
if (nCounter > 0) {
|
||||
nCounter--;
|
||||
}
|
||||
gslc_ElemXSelNumSetCounter(pGui,pSelNum,nCounter);
|
||||
|
||||
}
|
||||
} // eTouch
|
||||
|
||||
return true;
|
||||
#endif // !DRV_TOUCH_NONE
|
||||
}
|
||||
|
||||
bool gslc_ElemXSelNumTouch(void* pvGui,void* pvElemRef,gslc_teTouch eTouch,int16_t nRelX,int16_t nRelY)
|
||||
{
|
||||
#if defined(DRV_TOUCH_NONE)
|
||||
return false;
|
||||
#else
|
||||
|
||||
gslc_tsGui* pGui = (gslc_tsGui*)(pvGui);
|
||||
gslc_tsElemRef* pElemRef = (gslc_tsElemRef*)(pvElemRef);
|
||||
gslc_tsXSelNum* pSelNum = (gslc_tsXSelNum*)gslc_GetXDataFromRef(pGui, pElemRef, GSLC_TYPEX_SELNUM, __LINE__);
|
||||
if (!pSelNum) return false;
|
||||
|
||||
// Get Collection
|
||||
gslc_tsCollect* pCollect = &pSelNum->sCollect;
|
||||
return gslc_CollectTouchCompound(pvGui, pvElemRef, eTouch, nRelX, nRelY, pCollect);
|
||||
|
||||
#endif // !DRV_TOUCH_NONE
|
||||
}
|
||||
#endif // GSLC_FEATURE_COMPOUND
|
||||
|
||||
|
||||
// ============================================================================
|
177
src/guislice/XSelNum.h
Normal file
177
src/guislice/XSelNum.h
Normal file
|
@ -0,0 +1,177 @@
|
|||
#ifndef _GUISLICE_EX_XSELNUM_H_
|
||||
#define _GUISLICE_EX_XSELNUM_H_
|
||||
|
||||
#include "GUIslice.h"
|
||||
|
||||
|
||||
// =======================================================================
|
||||
// GUIslice library extension: Select Number (SelNum) control
|
||||
// - Calvin Hass
|
||||
// - https://www.impulseadventure.com/elec/guislice-gui.html
|
||||
// - https://github.com/ImpulseAdventure/GUIslice
|
||||
// =======================================================================
|
||||
//
|
||||
// The MIT License
|
||||
//
|
||||
// Copyright 2016-2020 Calvin Hass
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
//
|
||||
// =======================================================================
|
||||
/// \file XSelNum.h
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif // __cplusplus
|
||||
|
||||
|
||||
|
||||
#if (GSLC_FEATURE_COMPOUND)
|
||||
// ============================================================================
|
||||
// Extended Element: SelNum (Number Selector)
|
||||
// - Demonstration of a compound element consisting of
|
||||
// a counter text field along with an increment and
|
||||
// decrement button.
|
||||
// ============================================================================
|
||||
|
||||
// Define unique identifier for extended element type
|
||||
// - Select any number above GSLC_TYPE_BASE_EXTEND
|
||||
#define GSLC_TYPEX_SELNUM GSLC_TYPE_BASE_EXTEND + 3
|
||||
|
||||
#define SELNUM_STR_LEN 6
|
||||
|
||||
// Extended element data structures
|
||||
// - These data structures are maintained in the gslc_tsElem
|
||||
// structure via the pXData pointer
|
||||
/// Extended data for SelNum element
|
||||
typedef struct {
|
||||
|
||||
// Core functionality for SelNum
|
||||
int16_t nCounter; ///< Counter for demo purposes
|
||||
|
||||
// Internal sub-element members
|
||||
gslc_tsCollect sCollect; ///< Collection management for sub-elements
|
||||
gslc_tsElemRef asElemRef[4]; ///< Storage for sub-element references
|
||||
gslc_tsElem asElem[4]; ///< Storage for sub-elements
|
||||
|
||||
#if (GSLC_LOCAL_STR == 0)
|
||||
// If elements don't provide their own internal string buffer, then
|
||||
// we need to provide storage here in the extended data of the compound
|
||||
// element. For now, simply provide a fixed-length memory buffer.
|
||||
char acElemTxt[4][SELNUM_STR_LEN]; ///< Storage for strings
|
||||
#endif
|
||||
} gslc_tsXSelNum;
|
||||
|
||||
|
||||
|
||||
|
||||
///
|
||||
/// Create a SelNum Element
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] nElemId: Element ID to assign (0..16383 or GSLC_ID_AUTO to autogen)
|
||||
/// \param[in] nPage: Page ID to attach element to
|
||||
/// \param[in] pXData: Ptr to extended element data structure
|
||||
/// \param[in] rElem: Rectangle coordinates defining element size
|
||||
/// \param[in] nFontId: Font ID to use for drawing the element
|
||||
///
|
||||
/// \return Pointer to Element or NULL if failure
|
||||
///
|
||||
gslc_tsElemRef* gslc_ElemXSelNumCreate(gslc_tsGui* pGui,int16_t nElemId,int16_t nPage,
|
||||
gslc_tsXSelNum* pXData,gslc_tsRect rElem,int8_t nFontId);
|
||||
|
||||
|
||||
///
|
||||
/// Draw a SelNum element on the screen
|
||||
/// - Called during redraw
|
||||
///
|
||||
/// \param[in] pvGui: Void ptr to GUI (typecast to gslc_tsGui*)
|
||||
/// \param[in] pvElemRef: Void ptr to Element ref (typecast to gslc_tsElemRef*)
|
||||
/// \param[in] eRedraw: Redraw mode
|
||||
///
|
||||
/// \return true if success, false otherwise
|
||||
///
|
||||
bool gslc_ElemXSelNumDraw(void* pvGui,void* pvElemRef,gslc_teRedrawType eRedraw);
|
||||
|
||||
|
||||
///
|
||||
/// Get the current counter associated with SelNum
|
||||
///
|
||||
/// \param[in] pGui: Ptr to GUI
|
||||
/// \param[in] pSelNum: Ptr to Element
|
||||
///
|
||||
/// \return Current counter value
|
||||
///
|
||||
int gslc_ElemXSelNumGetCounter(gslc_tsGui* pGui,gslc_tsXSelNum* pSelNum);
|
||||
|
||||
|
||||
///
|
||||
/// Set the current counter associated with SelNum
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] pSelNum: Ptr to Element
|
||||
/// \param[in] nCount: New counter value
|
||||
///
|
||||
/// \return none
|
||||
///
|
||||
void gslc_ElemXSelNumSetCounter(gslc_tsGui* pGui,gslc_tsXSelNum* pSelNum,int16_t nCount);
|
||||
|
||||
|
||||
///
|
||||
/// Handle a click event within the SelNum
|
||||
/// - This is called internally by the SelNum touch handler
|
||||
///
|
||||
/// \param[in] pvGui: Void ptr to GUI (typecast to gslc_tsGui*)
|
||||
/// \param[in] pvElemRef: Void ptr to Element ref (typecast to gslc_tsElemRef*)
|
||||
/// \param[in] eTouch: Touch event type
|
||||
/// \param[in] nX: Touch X coord
|
||||
/// \param[in] nY: Touch Y coord
|
||||
///
|
||||
/// \return none
|
||||
///
|
||||
bool gslc_ElemXSelNumClick(void* pvGui,void *pvElemRef,gslc_teTouch eTouch,int16_t nX,int16_t nY);
|
||||
|
||||
///
|
||||
/// Handle touch (up,down,move) events to SelNum element
|
||||
/// - Called from gslc_ElemSendEventTouch()
|
||||
///
|
||||
/// \param[in] pvGui: Void ptr to GUI (typecast to gslc_tsGui*)
|
||||
/// \param[in] pvElemRef: Void ptr to Element ref (typecast to gslc_tsElemRef*)
|
||||
/// \param[in] eTouch: Touch event type
|
||||
/// \param[in] nRelX: Touch X coord relative to element
|
||||
/// \param[in] nRelY: Touch Y coord relative to element
|
||||
///
|
||||
/// \return true if success, false otherwise
|
||||
///
|
||||
bool gslc_ElemXSelNumTouch(void* pvGui,void* pvElemRef,gslc_teTouch eTouch,int16_t nRelX,int16_t nRelY);
|
||||
#endif // GLSC_COMPOUND
|
||||
|
||||
// ============================================================================
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Read-only element macros
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
// Macro initializers for Read-Only Elements in Flash/PROGMEM
|
||||
//
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif // __cplusplus
|
||||
#endif // _GUISLICE_EX_XSELNUM_H_
|
||||
|
478
src/guislice/XSlider.c
Normal file
478
src/guislice/XSlider.c
Normal file
|
@ -0,0 +1,478 @@
|
|||
// =======================================================================
|
||||
// GUIslice library (extensions)
|
||||
// - Calvin Hass
|
||||
// - https://www.impulseadventure.com/elec/guislice-gui.html
|
||||
// - https://github.com/ImpulseAdventure/GUIslice
|
||||
// =======================================================================
|
||||
//
|
||||
// The MIT License
|
||||
//
|
||||
// Copyright 2016-2020 Calvin Hass
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
//
|
||||
// =======================================================================
|
||||
/// \file XSlider.c
|
||||
|
||||
|
||||
|
||||
// GUIslice library
|
||||
#include "GUIslice.h"
|
||||
#include "GUIslice_drv.h"
|
||||
|
||||
#include "XSlider.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#if (GSLC_USE_PROGMEM)
|
||||
#include <avr/pgmspace.h>
|
||||
#endif
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Error Messages
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
extern const char GSLC_PMEM ERRSTR_NULL[];
|
||||
extern const char GSLC_PMEM ERRSTR_PXD_NULL[];
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Extended element definitions
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// - This file extends the core GUIslice functionality with
|
||||
// additional widget types
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
|
||||
// ============================================================================
|
||||
// Extended Element: Slider
|
||||
// - A linear slider control
|
||||
// ============================================================================
|
||||
|
||||
// Create a slider element and add it to the GUI element list
|
||||
// - Defines default styling for the element
|
||||
// - Defines callback for redraw and touch
|
||||
gslc_tsElemRef* gslc_ElemXSliderCreate(gslc_tsGui* pGui,int16_t nElemId,int16_t nPage,
|
||||
gslc_tsXSlider* pXData,gslc_tsRect rElem,int16_t nPosMin,int16_t nPosMax,int16_t nPos,
|
||||
uint16_t nThumbSz,bool bVert)
|
||||
{
|
||||
if ((pGui == NULL) || (pXData == NULL)) {
|
||||
static const char GSLC_PMEM FUNCSTR[] = "ElemXSliderCreate";
|
||||
GSLC_DEBUG2_PRINT_CONST(ERRSTR_NULL,FUNCSTR);
|
||||
return NULL;
|
||||
}
|
||||
gslc_tsElem sElem;
|
||||
gslc_tsElemRef* pElemRef = NULL;
|
||||
sElem = gslc_ElemCreate(pGui,nElemId,nPage,GSLC_TYPEX_SLIDER,rElem,NULL,0,GSLC_FONT_NONE);
|
||||
sElem.nFeatures &= ~GSLC_ELEM_FEA_FRAME_EN;
|
||||
sElem.nFeatures |= GSLC_ELEM_FEA_FILL_EN;
|
||||
sElem.nFeatures |= GSLC_ELEM_FEA_CLICK_EN;
|
||||
sElem.nFeatures |= GSLC_ELEM_FEA_GLOW_EN;
|
||||
|
||||
sElem.nGroup = GSLC_GROUP_ID_NONE;
|
||||
|
||||
// Range check on nPos
|
||||
if (nPos < nPosMin) { nPos = nPosMin; }
|
||||
if (nPos > nPosMax) { nPos = nPosMax; }
|
||||
|
||||
pXData->nPosMin = nPosMin;
|
||||
pXData->nPosMax = nPosMax;
|
||||
pXData->nPos = nPos;
|
||||
pXData->nThumbSz = nThumbSz;
|
||||
pXData->bVert = bVert;
|
||||
pXData->bTrim = false;
|
||||
pXData->colTrim = GSLC_COL_BLACK;
|
||||
pXData->nTickDiv = 0;
|
||||
pXData->pfuncXPos = NULL;
|
||||
sElem.pXData = (void*)(pXData);
|
||||
// Specify the custom drawing callback
|
||||
sElem.pfuncXDraw = &gslc_ElemXSliderDraw;
|
||||
// Specify the custom touch tracking callback
|
||||
sElem.pfuncXTouch = &gslc_ElemXSliderTouch;
|
||||
|
||||
sElem.colElemFill = GSLC_COL_BLACK;
|
||||
sElem.colElemFillGlow = GSLC_COL_BLACK;
|
||||
sElem.colElemFrame = GSLC_COL_GRAY;
|
||||
sElem.colElemFrameGlow = GSLC_COL_WHITE;
|
||||
|
||||
if (nPage != GSLC_PAGE_NONE) {
|
||||
pElemRef = gslc_ElemAdd(pGui,nPage,&sElem,GSLC_ELEMREF_DEFAULT);
|
||||
return pElemRef;
|
||||
#if (GSLC_FEATURE_COMPOUND)
|
||||
} else {
|
||||
// Save as temporary element
|
||||
pGui->sElemTmp = sElem;
|
||||
pGui->sElemRefTmp.pElem = &(pGui->sElemTmp);
|
||||
pGui->sElemRefTmp.eElemFlags = GSLC_ELEMREF_DEFAULT | GSLC_ELEMREF_REDRAW_FULL;
|
||||
return &(pGui->sElemRefTmp);
|
||||
#endif
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void gslc_ElemXSliderSetStyle(gslc_tsGui* pGui,gslc_tsElemRef* pElemRef,
|
||||
bool bTrim,gslc_tsColor colTrim,uint16_t nTickDiv,
|
||||
int16_t nTickLen,gslc_tsColor colTick)
|
||||
{
|
||||
if (pElemRef == NULL) {
|
||||
static const char GSLC_PMEM FUNCSTR[] = "ElemXSliderSetStyle";
|
||||
GSLC_DEBUG2_PRINT_CONST(ERRSTR_NULL,FUNCSTR);
|
||||
return;
|
||||
}
|
||||
gslc_tsElem* pElem = gslc_GetElemFromRef(pGui,pElemRef);
|
||||
gslc_tsXSlider* pSlider = (gslc_tsXSlider*)(pElem->pXData);
|
||||
|
||||
pSlider->bTrim = bTrim;
|
||||
pSlider->colTrim = colTrim;
|
||||
pSlider->nTickDiv = nTickDiv;
|
||||
pSlider->nTickLen = nTickLen;
|
||||
pSlider->colTick = colTick;
|
||||
|
||||
// Update
|
||||
gslc_ElemSetRedraw(pGui,pElemRef,GSLC_REDRAW_FULL);
|
||||
}
|
||||
|
||||
int gslc_ElemXSliderGetPos(gslc_tsGui* pGui,gslc_tsElemRef* pElemRef)
|
||||
{
|
||||
if (pElemRef == NULL) {
|
||||
static const char GSLC_PMEM FUNCSTR[] = "ElemXSliderGetPos";
|
||||
GSLC_DEBUG2_PRINT_CONST(ERRSTR_NULL,FUNCSTR);
|
||||
return 0;
|
||||
}
|
||||
gslc_tsElem* pElem = gslc_GetElemFromRef(pGui,pElemRef);
|
||||
gslc_tsXSlider* pSlider = (gslc_tsXSlider*)(pElem->pXData);
|
||||
|
||||
return pSlider->nPos;
|
||||
}
|
||||
|
||||
// Update the slider control's current state
|
||||
void gslc_ElemXSliderSetPos(gslc_tsGui* pGui,gslc_tsElemRef* pElemRef,int16_t nPos)
|
||||
{
|
||||
if ((pGui == NULL) || (pElemRef == NULL)) {
|
||||
static const char GSLC_PMEM FUNCSTR[] = "ElemXSliderSetPos";
|
||||
GSLC_DEBUG2_PRINT_CONST(ERRSTR_NULL,FUNCSTR);
|
||||
return;
|
||||
}
|
||||
gslc_tsElem* pElem = gslc_GetElemFromRef(pGui,pElemRef);
|
||||
gslc_tsXSlider* pSlider = (gslc_tsXSlider*)(pElem->pXData);
|
||||
int16_t nPosOld;
|
||||
// Clip position
|
||||
if (nPos < pSlider->nPosMin) { nPos = pSlider->nPosMin; }
|
||||
else if (nPos > pSlider->nPosMax) { nPos = pSlider->nPosMax; }
|
||||
// Update
|
||||
nPosOld = pSlider->nPos;
|
||||
pSlider->nPos = nPos;
|
||||
|
||||
// Only update if changed
|
||||
if (nPos != nPosOld) {
|
||||
// If any position callback is defined, call it now
|
||||
if (pSlider->pfuncXPos != NULL) {
|
||||
(*pSlider->pfuncXPos)((void*)(pGui),(void*)(pElemRef),nPos);
|
||||
}
|
||||
|
||||
// Mark for redraw
|
||||
// - Only need incremental redraw
|
||||
gslc_ElemSetRedraw(pGui,pElemRef,GSLC_REDRAW_INC);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
// Assign the position callback function for a slider
|
||||
void gslc_ElemXSliderSetPosFunc(gslc_tsGui* pGui,gslc_tsElemRef* pElemRef,GSLC_CB_XSLIDER_POS funcCb)
|
||||
{
|
||||
if ((pElemRef == NULL) || (funcCb == NULL)) {
|
||||
static const char GSLC_PMEM FUNCSTR[] = "ElemXSliderSetPosFunc";
|
||||
GSLC_DEBUG2_PRINT_CONST(ERRSTR_NULL,FUNCSTR);
|
||||
return;
|
||||
}
|
||||
gslc_tsElem* pElem = gslc_GetElemFromRef(pGui,pElemRef);
|
||||
gslc_tsXSlider* pSlider = (gslc_tsXSlider*)(pElem->pXData);
|
||||
pSlider->pfuncXPos = funcCb;
|
||||
}
|
||||
|
||||
|
||||
// Redraw the slider
|
||||
// - Note that this redraw is for the entire element rect region
|
||||
// - The Draw function parameters use void pointers to allow for
|
||||
// simpler callback function definition & scalability.
|
||||
bool gslc_ElemXSliderDraw(void* pvGui,void* pvElemRef,gslc_teRedrawType eRedraw)
|
||||
{
|
||||
if ((pvGui == NULL) || (pvElemRef == NULL)) {
|
||||
static const char GSLC_PMEM FUNCSTR[] = "ElemXSliderDraw";
|
||||
GSLC_DEBUG2_PRINT_CONST(ERRSTR_NULL,FUNCSTR);
|
||||
return false;
|
||||
}
|
||||
// Typecast the parameters to match the GUI and element types
|
||||
gslc_tsGui* pGui = (gslc_tsGui*)(pvGui);
|
||||
gslc_tsElemRef* pElemRef = (gslc_tsElemRef*)(pvElemRef);
|
||||
gslc_tsElem* pElem = gslc_GetElemFromRef(pGui,pElemRef);
|
||||
|
||||
// Fetch the element's extended data structure
|
||||
gslc_tsXSlider* pSlider;
|
||||
pSlider = (gslc_tsXSlider*)(pElem->pXData);
|
||||
if (pSlider == NULL) {
|
||||
GSLC_DEBUG2_PRINT("ERROR: ElemXSliderDraw(%s) pXData is NULL\n","");
|
||||
return false;
|
||||
}
|
||||
|
||||
bool bGlow = (pElem->nFeatures & GSLC_ELEM_FEA_GLOW_EN) && gslc_ElemGetGlow(pGui,pElemRef);
|
||||
int16_t nPos = pSlider->nPos;
|
||||
int16_t nPosMin = pSlider->nPosMin;
|
||||
int16_t nPosMax = pSlider->nPosMax;
|
||||
bool bVert = pSlider->bVert;
|
||||
int16_t nThumbSz = pSlider->nThumbSz;
|
||||
bool bTrim = pSlider->bTrim;
|
||||
gslc_tsColor colTrim = pSlider->colTrim;
|
||||
uint16_t nTickDiv = pSlider->nTickDiv;
|
||||
int16_t nTickLen = pSlider->nTickLen;
|
||||
gslc_tsColor colTick = pSlider->colTick;
|
||||
|
||||
// Range check on nPos
|
||||
if (nPos < nPosMin) { nPos = nPosMin; }
|
||||
else if (nPos > nPosMax) { nPos = nPosMax; }
|
||||
|
||||
int16_t nX0,nY0,nX1,nY1,nXMid,nYMid;
|
||||
nX0 = pElem->rElem.x;
|
||||
nY0 = pElem->rElem.y;
|
||||
nX1 = pElem->rElem.x + pElem->rElem.w - 1;
|
||||
nY1 = pElem->rElem.y + pElem->rElem.h - 1;
|
||||
nXMid = (nX0+nX1)/2;
|
||||
nYMid = (nY0+nY1)/2;
|
||||
|
||||
// Scale the current position
|
||||
int16_t nPosRng = nPosMax-nPosMin;
|
||||
// TODO: Check for nPosRng=0, reversed min/max
|
||||
int16_t nPosOffset = nPos-nPosMin;
|
||||
|
||||
// Provide some margin so thumb doesn't exceed control bounds
|
||||
// TODO: Handle nCtrlRng <= 0
|
||||
int16_t nMargin = nThumbSz;
|
||||
int16_t nCtrlRng;
|
||||
if (!bVert) {
|
||||
nCtrlRng = (nX1-nMargin)-(nX0+nMargin);
|
||||
} else {
|
||||
nCtrlRng = (nY1-nMargin)-(nY0+nMargin);
|
||||
}
|
||||
|
||||
int16_t nCtrlPos = (int16_t)((int32_t)nPosOffset * (int32_t)nCtrlRng / (int32_t)nPosRng) + nMargin;
|
||||
|
||||
// Draw the background
|
||||
// - TODO: To reduce flicker on unbuffered displays, one could consider
|
||||
// redrawing only the thumb (last drawn position) with fill and
|
||||
// then redraw other portions. This would prevent the
|
||||
// track / ticks from flickering needlessly. A full redraw would
|
||||
// be required if it was first draw action.
|
||||
gslc_DrawFillRect(pGui,pElem->rElem,(bGlow)?pElem->colElemFillGlow:pElem->colElemFill);
|
||||
|
||||
// Draw any ticks
|
||||
// - Need at least one tick segment
|
||||
if (nTickDiv>=1) {
|
||||
uint16_t nTickInd;
|
||||
int16_t nTickOffset;
|
||||
for (nTickInd=0;nTickInd<=nTickDiv;++nTickInd) {
|
||||
nTickOffset = (int16_t)((int32_t)nTickInd * (int32_t)nCtrlRng / (int32_t)nTickDiv);
|
||||
if (!bVert) {
|
||||
gslc_DrawLine(pGui,nX0+nMargin+ nTickOffset,nYMid,
|
||||
nX0+nMargin + nTickOffset,nYMid+nTickLen,colTick);
|
||||
} else {
|
||||
gslc_DrawLine(pGui,nXMid,nY0+nMargin+ nTickOffset,
|
||||
nXMid+nTickLen,nY0+nMargin + nTickOffset,colTick);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Draw the track
|
||||
if (!bVert) {
|
||||
// Make the track highlight during glow
|
||||
gslc_DrawLine(pGui,nX0+nMargin,nYMid,nX1-nMargin,nYMid,
|
||||
bGlow? pElem->colElemFrameGlow : pElem->colElemFrame);
|
||||
// Optionally draw a trim line
|
||||
if (bTrim) {
|
||||
gslc_DrawLine(pGui,nX0+nMargin,nYMid+1,nX1-nMargin,nYMid+1,colTrim);
|
||||
}
|
||||
|
||||
} else {
|
||||
// Make the track highlight during glow
|
||||
gslc_DrawLine(pGui,nXMid,nY0+nMargin,nXMid,nY1-nMargin,
|
||||
bGlow? pElem->colElemFrameGlow : pElem->colElemFrame);
|
||||
// Optionally draw a trim line
|
||||
if (bTrim) {
|
||||
gslc_DrawLine(pGui,nXMid+1,nY0+nMargin,nXMid+1,nY1-nMargin,colTrim);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int16_t nCtrlX0,nCtrlY0;
|
||||
gslc_tsRect rThumb;
|
||||
if (!bVert) {
|
||||
nCtrlX0 = nX0+nCtrlPos-nThumbSz;
|
||||
nCtrlY0 = nYMid-nThumbSz;
|
||||
} else {
|
||||
nCtrlX0 = nXMid-nThumbSz;
|
||||
nCtrlY0 = nY0+nCtrlPos-nThumbSz;
|
||||
}
|
||||
rThumb.x = nCtrlX0;
|
||||
rThumb.y = nCtrlY0;
|
||||
rThumb.w = 2*nThumbSz;
|
||||
rThumb.h = 2*nThumbSz;
|
||||
|
||||
// Draw the thumb control
|
||||
gslc_DrawFillRect(pGui,rThumb,(bGlow)?pElem->colElemFillGlow:pElem->colElemFill);
|
||||
gslc_DrawFrameRect(pGui,rThumb,(bGlow)?pElem->colElemFrameGlow:pElem->colElemFrame);
|
||||
if (bTrim) {
|
||||
gslc_tsRect rThumbTrim;
|
||||
rThumbTrim = gslc_ExpandRect(rThumb,-1,-1);
|
||||
gslc_DrawFrameRect(pGui,rThumbTrim,pSlider->colTrim);
|
||||
}
|
||||
|
||||
|
||||
// Clear the redraw flag
|
||||
gslc_ElemSetRedraw(pGui,pElemRef,GSLC_REDRAW_NONE);
|
||||
|
||||
// Mark page as needing flip
|
||||
gslc_PageFlipSet(pGui,true);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// This callback function is called by gslc_ElemSendEventTouch()
|
||||
// after any touch event
|
||||
bool gslc_ElemXSliderTouch(void* pvGui,void* pvElemRef,gslc_teTouch eTouch,int16_t nRelX,int16_t nRelY)
|
||||
{
|
||||
#if defined(DRV_TOUCH_NONE)
|
||||
return false;
|
||||
#else
|
||||
|
||||
if ((pvGui == NULL) || (pvElemRef == NULL)) {
|
||||
static const char GSLC_PMEM FUNCSTR[] = "ElemXSliderTouch";
|
||||
GSLC_DEBUG2_PRINT_CONST(ERRSTR_NULL,FUNCSTR);
|
||||
return false;
|
||||
}
|
||||
gslc_tsGui* pGui = NULL;
|
||||
gslc_tsElemRef* pElemRef = NULL;
|
||||
gslc_tsElem* pElem = NULL;
|
||||
gslc_tsXSlider* pSlider = NULL;
|
||||
|
||||
// Typecast the parameters to match the GUI
|
||||
pGui = (gslc_tsGui*)(pvGui);
|
||||
pElemRef = (gslc_tsElemRef*)(pvElemRef);
|
||||
pElem = gslc_GetElemFromRef(pGui,pElemRef);
|
||||
pSlider = (gslc_tsXSlider*)(pElem->pXData);
|
||||
|
||||
bool bGlowingOld = gslc_ElemGetGlow(pGui,pElemRef);
|
||||
int16_t nPosRng;
|
||||
int16_t nPos = 0;
|
||||
bool bUpdatePos = false;
|
||||
bool bIndexed = false;
|
||||
|
||||
switch(eTouch) {
|
||||
|
||||
case GSLC_TOUCH_DOWN_IN:
|
||||
// Start glowing as must be over it
|
||||
gslc_ElemSetGlow(pGui,pElemRef,true);
|
||||
bUpdatePos = true;
|
||||
break;
|
||||
|
||||
case GSLC_TOUCH_MOVE_IN:
|
||||
gslc_ElemSetGlow(pGui,pElemRef,true);
|
||||
bUpdatePos = true;
|
||||
break;
|
||||
case GSLC_TOUCH_MOVE_OUT:
|
||||
gslc_ElemSetGlow(pGui,pElemRef,false);
|
||||
bUpdatePos = true;
|
||||
break;
|
||||
|
||||
case GSLC_TOUCH_UP_IN:
|
||||
// End glow
|
||||
gslc_ElemSetGlow(pGui,pElemRef,false);
|
||||
break;
|
||||
case GSLC_TOUCH_UP_OUT:
|
||||
// End glow
|
||||
gslc_ElemSetGlow(pGui,pElemRef,false);
|
||||
break;
|
||||
|
||||
case GSLC_TOUCH_SET_REL:
|
||||
case GSLC_TOUCH_SET_ABS:
|
||||
bIndexed = true;
|
||||
gslc_ElemSetGlow(pGui,pElemRef,true);
|
||||
bUpdatePos = true;
|
||||
break;
|
||||
|
||||
default:
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
// If we need to update the slider position, calculate the value
|
||||
// and perform the update
|
||||
if (bUpdatePos) {
|
||||
|
||||
if (bIndexed) {
|
||||
// The position is changed by direct control (eg. keyboard)
|
||||
// instead of touch coordinates
|
||||
|
||||
// FIXME: Change the following to be either absolute or relative
|
||||
// value assignment instead of inc/dec. Then the user code can
|
||||
// define what the magnitude and direction should be.
|
||||
|
||||
if (eTouch == GSLC_TOUCH_SET_REL) {
|
||||
// Overload the "nRelY" parameter
|
||||
nPos = pSlider->nPos;
|
||||
nPos += nRelY;
|
||||
nPos = (nPos > pSlider->nPosMax)? pSlider->nPosMax : nPos;
|
||||
nPos = (nPos < pSlider->nPosMin)? pSlider->nPosMin : nPos;
|
||||
} else if (eTouch == GSLC_TOUCH_SET_ABS) {
|
||||
// Overload the "nRelY" parameter
|
||||
nPos = nRelY;
|
||||
nPos = (nPos > pSlider->nPosMax)? pSlider->nPosMax : nPos;
|
||||
nPos = (nPos < pSlider->nPosMin)? pSlider->nPosMin : nPos;
|
||||
}
|
||||
} else {
|
||||
// Perform additional range checking
|
||||
nRelX = (nRelX < 0)? 0 : nRelX;
|
||||
nRelY = (nRelY < 0)? 0 : nRelY;
|
||||
|
||||
// Calc new position
|
||||
nPosRng = pSlider->nPosMax - pSlider->nPosMin;
|
||||
if (!pSlider->bVert) {
|
||||
nPos = (int16_t)((int32_t)nRelX * (int32_t)nPosRng / (int32_t)pElem->rElem.w) + pSlider->nPosMin;
|
||||
} else {
|
||||
nPos = (int16_t)((int32_t)nRelY * (int32_t)nPosRng / (int32_t)pElem->rElem.h) + pSlider->nPosMin;
|
||||
}
|
||||
}
|
||||
// Update the slider
|
||||
gslc_ElemXSliderSetPos(pGui,pElemRef,nPos);
|
||||
}
|
||||
|
||||
// If the slider changed state, redraw
|
||||
if (gslc_ElemGetGlow(pGui,pElemRef) != bGlowingOld) {
|
||||
gslc_ElemSetRedraw(pGui,pElemRef,GSLC_REDRAW_FULL);
|
||||
}
|
||||
|
||||
return true;
|
||||
#endif // !DRV_TOUCH_NONE
|
||||
}
|
||||
|
||||
// ============================================================================
|
315
src/guislice/XSlider.h
Normal file
315
src/guislice/XSlider.h
Normal file
|
@ -0,0 +1,315 @@
|
|||
#ifndef _GUISLICE_EX_XSLIDER_H_
|
||||
#define _GUISLICE_EX_XSLIDER_H_
|
||||
|
||||
#include "GUIslice.h"
|
||||
|
||||
|
||||
// =======================================================================
|
||||
// GUIslice library extension: Slider control
|
||||
// - Calvin Hass
|
||||
// - https://www.impulseadventure.com/elec/guislice-gui.html
|
||||
// - https://github.com/ImpulseAdventure/GUIslice
|
||||
// =======================================================================
|
||||
//
|
||||
// The MIT License
|
||||
//
|
||||
// Copyright 2016-2020 Calvin Hass
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
//
|
||||
// =======================================================================
|
||||
/// \file XSlider.h
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif // __cplusplus
|
||||
|
||||
|
||||
// ============================================================================
|
||||
// Extended Element: Slider
|
||||
// ============================================================================
|
||||
|
||||
// Define unique identifier for extended element type
|
||||
// - Select any number above GSLC_TYPE_BASE_EXTEND
|
||||
#define GSLC_TYPEX_SLIDER GSLC_TYPE_BASE_EXTEND + 2
|
||||
|
||||
/// Callback function for slider feedback
|
||||
typedef bool (*GSLC_CB_XSLIDER_POS)(void* pvGui,void* pvElem,int16_t nPos);
|
||||
|
||||
// Extended element data structures
|
||||
// - These data structures are maintained in the gslc_tsElem
|
||||
// structure via the pXData pointer
|
||||
|
||||
/// Extended data for Slider element
|
||||
typedef struct {
|
||||
// Config
|
||||
bool bVert; ///< Orientation: true if vertical, else horizontal
|
||||
int16_t nThumbSz; ///< Size of the thumb control
|
||||
int16_t nPosMin; ///< Minimum position value of the slider
|
||||
int16_t nPosMax; ///< Maximum position value of the slider
|
||||
// Style config
|
||||
uint16_t nTickDiv; ///< Style: number of tickmark divisions (0 for none)
|
||||
int16_t nTickLen; ///< Style: length of tickmarks
|
||||
gslc_tsColor colTick; ///< Style: color of ticks
|
||||
bool bTrim; ///< Style: show a trim color
|
||||
gslc_tsColor colTrim; ///< Style: color of trim
|
||||
// State
|
||||
int16_t nPos; ///< Current position value of the slider
|
||||
// Callbacks
|
||||
GSLC_CB_XSLIDER_POS pfuncXPos; ///< Callback func ptr for position update
|
||||
} gslc_tsXSlider;
|
||||
|
||||
|
||||
///
|
||||
/// Create a Slider Element
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] nElemId: Element ID to assign (0..16383 or GSLC_ID_AUTO to autogen)
|
||||
/// \param[in] nPage: Page ID to attach element to
|
||||
/// \param[in] pXData: Ptr to extended element data structure
|
||||
/// \param[in] rElem: Rectangle coordinates defining checkbox size
|
||||
/// \param[in] nPosMin: Minimum position value
|
||||
/// \param[in] nPosMax: Maximum position value
|
||||
/// \param[in] nPos: Starting position value
|
||||
/// \param[in] nThumbSz: Size of the thumb control
|
||||
/// \param[in] bVert: Orientation (true for vertical)
|
||||
///
|
||||
/// \return Pointer to Element reference or NULL if failure
|
||||
///
|
||||
gslc_tsElemRef* gslc_ElemXSliderCreate(gslc_tsGui* pGui,int16_t nElemId,int16_t nPage,
|
||||
gslc_tsXSlider* pXData,gslc_tsRect rElem,int16_t nPosMin,int16_t nPosMax,int16_t nPos,
|
||||
uint16_t nThumbSz,bool bVert);
|
||||
|
||||
|
||||
///
|
||||
/// Set a Slider element's current position
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] pElemRef: Pointer to Element reference
|
||||
/// \param[in] bTrim: Show a colored trim?
|
||||
/// \param[in] colTrim: Color of trim
|
||||
/// \param[in] nTickDiv: Number of tick divisions to show (0 for none)
|
||||
/// \param[in] nTickLen: Length of tickmarks
|
||||
/// \param[in] colTick: Color of ticks
|
||||
///
|
||||
/// \return none
|
||||
///
|
||||
void gslc_ElemXSliderSetStyle(gslc_tsGui* pGui,gslc_tsElemRef* pElemRef,
|
||||
bool bTrim,gslc_tsColor colTrim,uint16_t nTickDiv,
|
||||
int16_t nTickLen,gslc_tsColor colTick);
|
||||
|
||||
|
||||
///
|
||||
/// Get a Slider element's current position
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] pElemRef: Pointer to Element reference
|
||||
///
|
||||
/// \return Current slider position
|
||||
///
|
||||
int gslc_ElemXSliderGetPos(gslc_tsGui* pGui,gslc_tsElemRef* pElemRef);
|
||||
|
||||
|
||||
///
|
||||
/// Set a Slider element's current position
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] pElemRef: Pointer to Element reference
|
||||
/// \param[in] nPos: New position value
|
||||
///
|
||||
/// \return none
|
||||
///
|
||||
void gslc_ElemXSliderSetPos(gslc_tsGui* pGui,gslc_tsElemRef* pElemRef,int16_t nPos);
|
||||
|
||||
///
|
||||
/// Assign the position callback function for a slider
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] pElemRef: Pointer to Element reference
|
||||
/// \param[in] funcCb: Function pointer to position routine (or NULL for none)
|
||||
///
|
||||
/// \return none
|
||||
///
|
||||
void gslc_ElemXSliderSetPosFunc(gslc_tsGui* pGui,gslc_tsElemRef* pElemRef,GSLC_CB_XSLIDER_POS funcCb);
|
||||
|
||||
///
|
||||
/// Draw a Slider element on the screen
|
||||
/// - Called from gslc_ElemDraw()
|
||||
///
|
||||
/// \param[in] pvGui: Void ptr to GUI (typecast to gslc_tsGui*)
|
||||
/// \param[in] pvElemRef: Void ptr to Element (typecast to gslc_tsElemRef*)
|
||||
/// \param[in] eRedraw: Redraw mode
|
||||
///
|
||||
/// \return true if success, false otherwise
|
||||
///
|
||||
bool gslc_ElemXSliderDraw(void* pvGui,void* pvElemRef,gslc_teRedrawType eRedraw);
|
||||
|
||||
///
|
||||
/// Handle touch events to Slider element
|
||||
/// - Called from gslc_ElemSendEventTouch()
|
||||
///
|
||||
/// \param[in] pvGui: Void ptr to GUI (typecast to gslc_tsGui*)
|
||||
/// \param[in] pvElemRef: Void ptr to Element ref (typecast to gslc_tsElemRef*)
|
||||
/// \param[in] eTouch: Touch event type
|
||||
/// \param[in] nRelX: Touch X coord relative to element
|
||||
/// \param[in] nRelY: Touch Y coord relative to element
|
||||
///
|
||||
/// \return true if success, false otherwise
|
||||
///
|
||||
bool gslc_ElemXSliderTouch(void* pvGui,void* pvElemRef,gslc_teTouch eTouch,int16_t nRelX,int16_t nRelY);
|
||||
|
||||
// ============================================================================
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Read-only element macros
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
// Macro initializers for Read-Only Elements in Flash/PROGMEM
|
||||
//
|
||||
|
||||
|
||||
|
||||
/// \def gslc_ElemXSliderCreate_P(pGui,nElemId,nPage,nX,nY,nW,nH,
|
||||
/// nPosMin_,nPosMax_,nPos_,nThumbSz_,bVert_,colFrame_,colFill_)
|
||||
///
|
||||
/// Create a Slider Element in Flash
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] nElemId: Unique element ID to assign
|
||||
/// \param[in] nPage: Page ID to attach element to
|
||||
/// \param[in] nX: X coordinate of element
|
||||
/// \param[in] nY: Y coordinate of element
|
||||
/// \param[in] nW: Width of element
|
||||
/// \param[in] nH: Height of element
|
||||
/// \param[in] nPosMin_: Minimum position value
|
||||
/// \param[in] nPosMax_: Maximum position value
|
||||
/// \param[in] nPos_: Starting position value
|
||||
/// \param[in] nThumbSz_: Size of the thumb control
|
||||
/// \param[in] bVert_: Orientation (true for vertical)
|
||||
/// \param[in] colFrame_: Color of the element frame
|
||||
/// \param[in] colFill_: Color of the element fill
|
||||
///
|
||||
/// \return none
|
||||
///
|
||||
|
||||
|
||||
#if (GSLC_USE_PROGMEM)
|
||||
|
||||
|
||||
#define gslc_ElemXSliderCreate_P(pGui,nElemId,nPage,nX,nY,nW,nH, \
|
||||
nPosMin_,nPosMax_,nPos_,nThumbSz_,bVert_,colFrame_,colFill_) \
|
||||
static const uint8_t nFeatures##nElemId = GSLC_ELEM_FEA_VALID | \
|
||||
GSLC_ELEM_FEA_GLOW_EN | GSLC_ELEM_FEA_CLICK_EN | GSLC_ELEM_FEA_FILL_EN; \
|
||||
static gslc_tsXSlider sSlider##nElemId; \
|
||||
sSlider##nElemId.bVert = bVert_; \
|
||||
sSlider##nElemId.nThumbSz = nThumbSz_; \
|
||||
sSlider##nElemId.nPosMin = nPosMin_; \
|
||||
sSlider##nElemId.nPosMax = nPosMax_; \
|
||||
sSlider##nElemId.nTickDiv = 0; \
|
||||
sSlider##nElemId.nTickLen = 0; \
|
||||
sSlider##nElemId.colTick = GSLC_COL_WHITE; \
|
||||
sSlider##nElemId.bTrim = false; \
|
||||
sSlider##nElemId.colTrim = GSLC_COL_BLACK; \
|
||||
sSlider##nElemId.nPos = nPos_; \
|
||||
sSlider##nElemId.pfuncXPos = NULL; \
|
||||
static const gslc_tsElem sElem##nElemId PROGMEM = { \
|
||||
nElemId, \
|
||||
nFeatures##nElemId, \
|
||||
GSLC_TYPEX_SLIDER, \
|
||||
(gslc_tsRect){nX,nY,nW,nH}, \
|
||||
GSLC_GROUP_ID_NONE, \
|
||||
colFrame_,colFill_,colFrame_,colFill_, \
|
||||
(gslc_tsImgRef){NULL,NULL,GSLC_IMGREF_NONE,NULL}, \
|
||||
(gslc_tsImgRef){NULL,NULL,GSLC_IMGREF_NONE,NULL}, \
|
||||
NULL, \
|
||||
NULL, \
|
||||
0, \
|
||||
(gslc_teTxtFlags)(GSLC_TXT_DEFAULT), \
|
||||
GSLC_COL_WHITE, \
|
||||
GSLC_COL_WHITE, \
|
||||
GSLC_ALIGN_MID_MID, \
|
||||
0, \
|
||||
0, \
|
||||
NULL, \
|
||||
(void*)(&sSlider##nElemId), \
|
||||
NULL, \
|
||||
&gslc_ElemXSliderDraw, \
|
||||
&gslc_ElemXSliderTouch, \
|
||||
NULL, \
|
||||
}; \
|
||||
gslc_ElemAdd(pGui,nPage,(gslc_tsElem*)&sElem##nElemId, \
|
||||
(gslc_teElemRefFlags)(GSLC_ELEMREF_SRC_PROG | GSLC_ELEMREF_VISIBLE | GSLC_ELEMREF_REDRAW_FULL));
|
||||
|
||||
#else
|
||||
|
||||
|
||||
#define gslc_ElemXSliderCreate_P(pGui,nElemId,nPage,nX,nY,nW,nH, \
|
||||
nPosMin_,nPosMax_,nPos_,nThumbSz_,bVert_,colFrame_,colFill_) \
|
||||
static const uint8_t nFeatures##nElemId = GSLC_ELEM_FEA_VALID | \
|
||||
GSLC_ELEM_FEA_GLOW_EN | GSLC_ELEM_FEA_CLICK_EN | GSLC_ELEM_FEA_FILL_EN; \
|
||||
static gslc_tsXSlider sSlider##nElemId; \
|
||||
sSlider##nElemId.bVert = bVert_; \
|
||||
sSlider##nElemId.nThumbSz = nThumbSz_; \
|
||||
sSlider##nElemId.nPosMin = nPosMin_; \
|
||||
sSlider##nElemId.nPosMax = nPosMax_; \
|
||||
sSlider##nElemId.nTickDiv = 0; \
|
||||
sSlider##nElemId.nTickLen = 0; \
|
||||
sSlider##nElemId.colTick = GSLC_COL_WHITE; \
|
||||
sSlider##nElemId.bTrim = false; \
|
||||
sSlider##nElemId.colTrim = GSLC_COL_BLACK; \
|
||||
sSlider##nElemId.nPos = nPos_; \
|
||||
sSlider##nElemId.pfuncXPos = NULL; \
|
||||
static const gslc_tsElem sElem##nElemId = { \
|
||||
nElemId, \
|
||||
nFeatures##nElemId, \
|
||||
GSLC_TYPEX_SLIDER, \
|
||||
(gslc_tsRect){nX,nY,nW,nH}, \
|
||||
GSLC_GROUP_ID_NONE, \
|
||||
colFrame_,colFill_,colFrame_,colFill_, \
|
||||
(gslc_tsImgRef){NULL,NULL,GSLC_IMGREF_NONE,NULL}, \
|
||||
(gslc_tsImgRef){NULL,NULL,GSLC_IMGREF_NONE,NULL}, \
|
||||
NULL, \
|
||||
NULL, \
|
||||
0, \
|
||||
(gslc_teTxtFlags)(GSLC_TXT_DEFAULT), \
|
||||
GSLC_COL_WHITE, \
|
||||
GSLC_COL_WHITE, \
|
||||
GSLC_ALIGN_MID_MID, \
|
||||
0, \
|
||||
0, \
|
||||
NULL, \
|
||||
(void*)(&sSlider##nElemId), \
|
||||
NULL, \
|
||||
&gslc_ElemXSliderDraw, \
|
||||
&gslc_ElemXSliderTouch, \
|
||||
NULL, \
|
||||
}; \
|
||||
gslc_ElemAdd(pGui,nPage,(gslc_tsElem*)&sElem##nElemId, \
|
||||
(gslc_teElemRefFlags)(GSLC_ELEMREF_SRC_CONST | GSLC_ELEMREF_VISIBLE | GSLC_ELEMREF_REDRAW_FULL));
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif // __cplusplus
|
||||
#endif // _GUISLICE_EX_XSLIDER_H_
|
||||
|
425
src/guislice/XSpinner.c
Normal file
425
src/guislice/XSpinner.c
Normal file
|
@ -0,0 +1,425 @@
|
|||
// =======================================================================
|
||||
// GUIslice library (extensions)
|
||||
// - Calvin Hass
|
||||
// - https://www.impulseadventure.com/elec/guislice-gui.html
|
||||
// - https://github.com/ImpulseAdventure/GUIslice
|
||||
// =======================================================================
|
||||
//
|
||||
// The MIT License
|
||||
//
|
||||
// Copyright 2016-2020 Calvin Hass
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
//
|
||||
// =======================================================================
|
||||
/// \file XSpinner.c
|
||||
|
||||
|
||||
|
||||
// GUIslice library
|
||||
#include "GUIslice.h"
|
||||
#include "GUIslice_drv.h"
|
||||
|
||||
#include "XSpinner.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#if (GSLC_USE_PROGMEM)
|
||||
#include <avr/pgmspace.h>
|
||||
#endif
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Error Messages
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
extern const char GSLC_PMEM ERRSTR_NULL[];
|
||||
extern const char GSLC_PMEM ERRSTR_PXD_NULL[];
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Extended element definitions
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// - This file extends the core GUIslice functionality with
|
||||
// additional widget types
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
|
||||
#if (GSLC_FEATURE_COMPOUND)
|
||||
// ============================================================================
|
||||
// Extended Element: Spinner
|
||||
// - Spinner element demonstrates a simple up/down counter
|
||||
// - This is a compound element containing two buttons and
|
||||
// a text area to represent the current value
|
||||
// ============================================================================
|
||||
|
||||
// Private sub Element ID definitions
|
||||
static const int16_t SPINNER_ID_BTN_INC = 100;
|
||||
static const int16_t SPINNER_ID_BTN_DEC = 101;
|
||||
static const int16_t SPINNER_ID_TXT = 102;
|
||||
|
||||
// Create a compound element
|
||||
// - For now just two buttons and a text area
|
||||
gslc_tsElemRef* gslc_ElemXSpinnerCreate(gslc_tsGui* pGui, int16_t nElemId, int16_t nPage, gslc_tsXSpinner* pXData,
|
||||
gslc_tsRect rElem, int16_t nMin, int16_t nMax, int16_t nVal, int16_t nIncr,
|
||||
int8_t nFontId, int8_t nButtonSz, GSLC_CB_INPUT cbInput)
|
||||
{
|
||||
|
||||
if ((pGui == NULL) || (pXData == NULL)) {
|
||||
static const char GSLC_PMEM FUNCSTR[] = "ElemXSpinnerCreate";
|
||||
GSLC_DEBUG2_PRINT_CONST(ERRSTR_NULL, FUNCSTR);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// determine size of our text box
|
||||
// first calculate number of digits required
|
||||
int16_t nTxtBoxW,nTxtBoxH,nBtnPosY;
|
||||
char acTxtNum[XSPINNER_STR_LEN];
|
||||
// FIXME: Consider replacing the sprintf() with an optimized function to
|
||||
// conserve RAM. Potentially leverage GSLC_DEBUG2_PRINT().
|
||||
nTxtBoxW = rElem.w - 2 * (nButtonSz);
|
||||
// Determine the maximum width of a digit, we will use button size for height.
|
||||
// now we can work out our rectangle
|
||||
nTxtBoxH = rElem.h;
|
||||
|
||||
nBtnPosY = rElem.y + (rElem.h - nButtonSz) / 2;
|
||||
|
||||
// set our intial value for our text field
|
||||
snprintf(acTxtNum, XSPINNER_STR_LEN - 1, "%d", nVal);
|
||||
|
||||
gslc_tsElem sElem;
|
||||
|
||||
// Initialize composite element
|
||||
sElem = gslc_ElemCreate(pGui, nElemId, nPage, GSLC_TYPEX_SPINNER, rElem, NULL, 0, GSLC_FONT_NONE);
|
||||
sElem.nFeatures |= GSLC_ELEM_FEA_FRAME_EN;
|
||||
sElem.nFeatures |= GSLC_ELEM_FEA_FILL_EN;
|
||||
sElem.nFeatures |= GSLC_ELEM_FEA_CLICK_EN;
|
||||
sElem.nFeatures &= ~GSLC_ELEM_FEA_GLOW_EN; // Don't need to glow outer element
|
||||
sElem.nGroup = GSLC_GROUP_ID_NONE;
|
||||
|
||||
pXData->nCounter = nVal;
|
||||
pXData->nMin = nMin;
|
||||
pXData->nMax = nMax;
|
||||
pXData->nIncr = nIncr;
|
||||
pXData->pfuncXInput = cbInput;
|
||||
|
||||
|
||||
// Initialize the collection of sub-elements within the compound element
|
||||
// - XSELNUM_COMP_CNT defines the maximum number of sub-elements we have allocated space for
|
||||
// - Note that this example shows RAM being used for storage
|
||||
gslc_CollectReset(&pXData->sCollect, pXData->asElem, XSPINNER_COMP_CNT, pXData->asElemRef, XSPINNER_COMP_CNT);
|
||||
|
||||
|
||||
sElem.pXData = (void*)(pXData);
|
||||
// Specify the custom drawing callback
|
||||
sElem.pfuncXDraw = &gslc_ElemXSpinnerDraw;
|
||||
// Specify the custom touch tracking callback
|
||||
sElem.pfuncXTouch = &gslc_ElemXSpinnerTouch;
|
||||
|
||||
sElem.colElemFill = GSLC_COL_BLACK;
|
||||
sElem.colElemFillGlow = GSLC_COL_BLACK;
|
||||
sElem.colElemFrame = GSLC_COL_GRAY;
|
||||
sElem.colElemFrameGlow = GSLC_COL_WHITE;
|
||||
|
||||
|
||||
// Now create the sub elements
|
||||
// - Ensure page is set to GSLC_PAGE_NONE so that
|
||||
// we create the element struct but not add it to a specific page.
|
||||
// - When we create an element with GSLC_PAGE_NONE it is
|
||||
// saved in the GUI's temporary element storage.
|
||||
// - When we have finished creating / styling the element, we then
|
||||
// copy it into the permanent sub-element storage
|
||||
|
||||
// - The element IDs assigned to the sub-elements are
|
||||
// arbitrary (with local scope in the compound element),
|
||||
// so they don't need to be unique globally across the GUI.
|
||||
gslc_tsElemRef* pElemRefTmp = NULL;
|
||||
gslc_tsElem* pElemTmp = NULL;
|
||||
gslc_tsElemRef* pElemRef = NULL;
|
||||
|
||||
// Determine offset coordinate of compound element so that we can
|
||||
// specify relative positioning during the sub-element Create() operations.
|
||||
int16_t nOffsetX = rElem.x;
|
||||
int16_t nOffsetY = rElem.y;
|
||||
|
||||
gslc_tsRect rSubElem;
|
||||
|
||||
// Create button sub-element
|
||||
strcpy(pXData->acIncr,"\030");
|
||||
rSubElem = (gslc_tsRect) { nOffsetX+nTxtBoxW, nBtnPosY, nButtonSz, nButtonSz };
|
||||
rSubElem = gslc_ExpandRect(rSubElem, -1, -1);
|
||||
pElemRefTmp = gslc_ElemCreateBtnTxt(pGui, SPINNER_ID_BTN_INC, GSLC_PAGE_NONE,
|
||||
rSubElem, pXData->acIncr, 2, nFontId, &gslc_ElemXSpinnerClick);
|
||||
gslc_ElemSetCol(pGui, pElemRefTmp, (gslc_tsColor) { 0, 0, 192 }, (gslc_tsColor) { 0, 0, 128 }, (gslc_tsColor) { 0, 0, 224 });
|
||||
gslc_ElemSetTxtCol(pGui, pElemRefTmp, GSLC_COL_WHITE);
|
||||
pElemTmp = gslc_GetElemFromRef(pGui, pElemRefTmp);
|
||||
gslc_CollectElemAdd(pGui, &pXData->sCollect, pElemTmp, GSLC_ELEMREF_DEFAULT);
|
||||
|
||||
// Create button sub-element
|
||||
strcpy(pXData->acDecr,"\031");
|
||||
rSubElem = (gslc_tsRect) { nOffsetX+nTxtBoxW+nButtonSz, nBtnPosY, nButtonSz, nButtonSz };
|
||||
rSubElem = gslc_ExpandRect(rSubElem, -1, -1);
|
||||
pElemRefTmp = gslc_ElemCreateBtnTxt(pGui, SPINNER_ID_BTN_DEC, GSLC_PAGE_NONE,
|
||||
rSubElem, pXData->acDecr, 2, nFontId, &gslc_ElemXSpinnerClick);
|
||||
gslc_ElemSetCol(pGui, pElemRefTmp, (gslc_tsColor) { 0, 0, 192 }, (gslc_tsColor) { 0, 0, 128 }, (gslc_tsColor) { 0, 0, 224 });
|
||||
gslc_ElemSetTxtCol(pGui, pElemRefTmp, GSLC_COL_WHITE);
|
||||
pElemTmp = gslc_GetElemFromRef(pGui, pElemRefTmp);
|
||||
gslc_CollectElemAdd(pGui, &pXData->sCollect, pElemTmp, GSLC_ELEMREF_DEFAULT);
|
||||
|
||||
// Create dynamic text sub-element
|
||||
// - Note that we are using string storage in the extended element data
|
||||
// structure (pXData).
|
||||
rSubElem = (gslc_tsRect) { nOffsetX, nOffsetY, nTxtBoxW, nTxtBoxH };
|
||||
rSubElem = gslc_ExpandRect(rSubElem, -1, -1);
|
||||
strncpy(pXData->acElemTxt[0], acTxtNum, XSPINNER_STR_LEN - 1);
|
||||
pElemRefTmp = gslc_ElemCreateTxt(pGui, SPINNER_ID_TXT, GSLC_PAGE_NONE,
|
||||
rSubElem, pXData->acElemTxt[0], XSPINNER_STR_LEN, nFontId);
|
||||
gslc_ElemSetTxtAlign(pGui, pElemRefTmp, GSLC_ALIGN_MID_MID);
|
||||
pElemTmp = gslc_GetElemFromRef(pGui, pElemRefTmp);
|
||||
gslc_CollectElemAdd(pGui, &pXData->sCollect, pElemTmp, GSLC_ELEMREF_DEFAULT);
|
||||
|
||||
|
||||
// Now proceed to add the compound element to the page
|
||||
if (nPage != GSLC_PAGE_NONE) {
|
||||
pElemRef = gslc_ElemAdd(pGui, nPage, &sElem, GSLC_ELEMREF_DEFAULT);
|
||||
|
||||
// save our ElemRef for the callback
|
||||
pXData->pElemRef = pElemRef;
|
||||
|
||||
// Now propagate the parent relationship to enable a cascade
|
||||
// of redrawing from low-level elements to the top
|
||||
gslc_CollectSetParent(pGui, &pXData->sCollect, pElemRef);
|
||||
|
||||
return pElemRef;
|
||||
}
|
||||
else {
|
||||
GSLC_DEBUG2_PRINT("ERROR: ElemXSpinnerCreate(%s) Compound elements inside compound elements not supported\n", "");
|
||||
return NULL;
|
||||
|
||||
// TODO: For now, disable compound elements within
|
||||
// compound elements. If we want to enable this, we
|
||||
// would probably use the temporary element reference
|
||||
// the GUI.
|
||||
// Save as temporary element for further processing
|
||||
//pGui->sElemTmp = sElem; // Need fixing
|
||||
//return &(pGui->sElemTmp); // Need fixing
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
bool gslc_ElemXSpinnerSetChars(void* pvGui,gslc_tsElemRef* pElemRef,uint8_t cIncr, uint8_t cDecr)
|
||||
{
|
||||
gslc_tsGui* pGui = (gslc_tsGui*)(pvGui);
|
||||
gslc_tsElem* pElem = gslc_GetElemFromRefD(pGui, pElemRef, __LINE__);
|
||||
if (!pElem) return false;
|
||||
gslc_tsXSpinner* pSpinner = (gslc_tsXSpinner*)gslc_GetXDataFromRef(pGui, pElemRef, GSLC_TYPEX_SPINNER, __LINE__);
|
||||
if (!pSpinner) return false;
|
||||
|
||||
char acIncr[2] = { cIncr, '\0'};
|
||||
char acDecr[2] = { cDecr, '\0'};
|
||||
gslc_tsElemRef* pElemRefUp = gslc_CollectFindElemById(pGui,&pSpinner->sCollect,SPINNER_ID_BTN_INC);
|
||||
gslc_ElemSetTxtStr(pGui,pElemRefUp,acIncr);
|
||||
gslc_tsElemRef* pElemRefDown = gslc_CollectFindElemById(pGui,&pSpinner->sCollect,SPINNER_ID_BTN_DEC);
|
||||
gslc_ElemSetTxtStr(pGui,pElemRefDown,acDecr);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// Redraw the compound element
|
||||
// - When drawing a compound element, we clear the background
|
||||
// and then redraw the sub-element collection.
|
||||
bool gslc_ElemXSpinnerDraw(void* pvGui,void* pvElemRef,gslc_teRedrawType eRedraw)
|
||||
{
|
||||
gslc_tsGui* pGui = (gslc_tsGui*)(pvGui);
|
||||
gslc_tsElemRef* pElemRef = (gslc_tsElemRef*)(pvElemRef);
|
||||
gslc_tsElem* pElem = gslc_GetElemFromRef(pGui,pElemRef);
|
||||
gslc_tsXSpinner* pSpinner = (gslc_tsXSpinner*)gslc_GetXDataFromRef(pGui, pElemRef, GSLC_TYPEX_SPINNER, __LINE__);
|
||||
if (!pSpinner) return false;
|
||||
|
||||
bool bGlow = (pElem->nFeatures & GSLC_ELEM_FEA_GLOW_EN) && gslc_ElemGetGlow(pGui,pElemRef);
|
||||
|
||||
// Draw the compound element fill (background)
|
||||
// - Should only need to do this in full redraw
|
||||
if (eRedraw == GSLC_REDRAW_FULL) {
|
||||
gslc_DrawFillRect(pGui,pElem->rElem,(bGlow)?pElem->colElemFillGlow:pElem->colElemFill);
|
||||
}
|
||||
|
||||
// Draw the sub-elements
|
||||
// - For now, force redraw of entire compound element
|
||||
gslc_tsCollect* pCollect = &pSpinner->sCollect;
|
||||
if (eRedraw != GSLC_REDRAW_NONE) {
|
||||
uint8_t sEventSubType = GSLC_EVTSUB_DRAW_NEEDED;
|
||||
if (eRedraw == GSLC_REDRAW_FULL) {
|
||||
sEventSubType = GSLC_EVTSUB_DRAW_FORCE;
|
||||
}
|
||||
gslc_tsEvent sEvent = gslc_EventCreate(pGui, GSLC_EVT_DRAW, sEventSubType, (void*)(pCollect), NULL);
|
||||
gslc_CollectEvent(pGui, sEvent);
|
||||
}
|
||||
|
||||
// Optionally, draw a frame around the compound element
|
||||
// - This could instead be done by creating a sub-element
|
||||
// of type box.
|
||||
// - We don't need to show any glowing of the compound element
|
||||
|
||||
if (eRedraw == GSLC_REDRAW_FULL) {
|
||||
gslc_DrawFrameRect(pGui, pElem->rElem, (bGlow) ? pElem->colElemFrameGlow : pElem->colElemFrame);
|
||||
}
|
||||
|
||||
// Clear the redraw flag
|
||||
gslc_ElemSetRedraw(pGui,pElemRef,GSLC_REDRAW_NONE);
|
||||
|
||||
// Mark page as needing flip
|
||||
gslc_PageFlipSet(pGui,true);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Fetch the current value of the element's counter
|
||||
int gslc_ElemXSpinnerGetCounter(gslc_tsGui* pGui,gslc_tsXSpinner* pSpinner)
|
||||
{
|
||||
if ((pGui == NULL) || (pSpinner == NULL)) {
|
||||
static const char GSLC_PMEM FUNCSTR[] = "ElemXSpinnerGetCounter";
|
||||
GSLC_DEBUG2_PRINT_CONST(ERRSTR_NULL,FUNCSTR);
|
||||
return 0;
|
||||
}
|
||||
return pSpinner->nCounter;
|
||||
}
|
||||
|
||||
|
||||
void gslc_ElemXSpinnerSetCounter(gslc_tsGui* pGui,gslc_tsXSpinner* pSpinner,int16_t nCount)
|
||||
{
|
||||
if (pSpinner == NULL) {
|
||||
static const char GSLC_PMEM FUNCSTR[] = "ElemXSpinnerSetCounter";
|
||||
GSLC_DEBUG2_PRINT_CONST(ERRSTR_NULL,FUNCSTR);
|
||||
return;
|
||||
}
|
||||
pSpinner->nCounter = nCount;
|
||||
|
||||
// Determine new counter text
|
||||
// FIXME: Consider replacing the printf() with an optimized function to
|
||||
// conserve RAM. Potentially leverage GSLC_DEBUG2_PRINT().
|
||||
char acStrNew[GSLC_LOCAL_STR_LEN];
|
||||
snprintf(acStrNew,GSLC_LOCAL_STR_LEN,"%hd",pSpinner->nCounter);
|
||||
|
||||
// Update the element
|
||||
gslc_tsElemRef* pElemRef = gslc_CollectFindElemById(pGui,&pSpinner->sCollect,SPINNER_ID_TXT);
|
||||
gslc_ElemSetTxtStr(pGui,pElemRef,acStrNew);
|
||||
|
||||
}
|
||||
|
||||
|
||||
// Handle the compound element main functionality
|
||||
// - This routine is called by gslc_ElemEvent() to handle
|
||||
// any click events that resulted from the touch tracking process.
|
||||
// - The code here will generally represent the core
|
||||
// functionality of the compound element and any communication
|
||||
// between sub-elements.
|
||||
// - pvElemRef is a void pointer to the element ref being tracked. From
|
||||
// the pElemRefParent member we can get the parent/compound element
|
||||
// data structures.
|
||||
bool gslc_ElemXSpinnerClick(void* pvGui,void *pvElemRef,gslc_teTouch eTouch,int16_t nX,int16_t nY)
|
||||
{
|
||||
#if defined(DRV_TOUCH_NONE)
|
||||
return false;
|
||||
#else
|
||||
|
||||
gslc_tsGui* pGui = (gslc_tsGui*)(pvGui);
|
||||
gslc_tsElemRef* pElemRef = (gslc_tsElemRef*)(pvElemRef);
|
||||
gslc_tsElem* pElem = gslc_GetElemFromRefD(pGui, pElemRef, __LINE__);
|
||||
if (!pElem) return false;
|
||||
|
||||
// Fetch the parent of the clicked element which is the compound
|
||||
// element itself. This enables us to access the extra control data.
|
||||
gslc_tsElemRef* pElemRefParent = pElem->pElemRefParent;
|
||||
if (pElemRefParent == NULL) {
|
||||
GSLC_DEBUG2_PRINT("ERROR: ElemXSpinnerClick(%s) parent ElemRef ptr NULL\n","");
|
||||
return false;
|
||||
}
|
||||
|
||||
gslc_tsElem* pElemParent = gslc_GetElemFromRef(pGui,pElemRefParent);
|
||||
gslc_tsXSpinner* pSpinner = (gslc_tsXSpinner*)(pElemParent->pXData);
|
||||
if (pSpinner == NULL) {
|
||||
GSLC_DEBUG2_PRINT("ERROR: ElemXSpinnerClick() element (ID=%d) has NULL pXData\n",pElem->nId);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Begin the core compound element functionality
|
||||
int nCounter = pSpinner->nCounter;
|
||||
|
||||
// Handle the various button presses
|
||||
GSLC_CB_INPUT pfuncXInput = NULL;
|
||||
if (eTouch == GSLC_TOUCH_UP_IN) {
|
||||
|
||||
// Get the tracked element ID
|
||||
gslc_tsElemRef* pElemRefTracked = pSpinner->sCollect.pElemRefTracked;
|
||||
gslc_tsElem* pElemTracked = gslc_GetElemFromRef(pGui,pElemRefTracked);
|
||||
int nSubElemId = pElemTracked->nId;
|
||||
|
||||
if (nSubElemId == SPINNER_ID_BTN_INC) {
|
||||
// Increment button
|
||||
if (nCounter < pSpinner->nMax) {
|
||||
nCounter += pSpinner->nIncr;
|
||||
}
|
||||
gslc_ElemXSpinnerSetCounter(pGui,pSpinner,nCounter);
|
||||
|
||||
} else if (nSubElemId == SPINNER_ID_BTN_DEC) {
|
||||
// Decrement button
|
||||
if (nCounter > pSpinner->nMin) {
|
||||
nCounter -= pSpinner->nIncr;
|
||||
}
|
||||
gslc_ElemXSpinnerSetCounter(pGui,pSpinner,nCounter);
|
||||
|
||||
}
|
||||
|
||||
// Invoke the callback function
|
||||
pfuncXInput = pSpinner->pfuncXInput;
|
||||
if (pfuncXInput != NULL) {
|
||||
(*pfuncXInput)(pvGui, (void*)(pSpinner->pElemRef), XSPINNER_CB_STATE_UPDATE, NULL);
|
||||
}
|
||||
|
||||
} // eTouch
|
||||
|
||||
return true;
|
||||
#endif // !DRV_TOUCH_NONE
|
||||
}
|
||||
|
||||
bool gslc_ElemXSpinnerTouch(void* pvGui,void* pvElemRef,gslc_teTouch eTouch,int16_t nRelX,int16_t nRelY)
|
||||
{
|
||||
#if defined(DRV_TOUCH_NONE)
|
||||
return false;
|
||||
#else
|
||||
gslc_tsGui* pGui = (gslc_tsGui*)(pvGui);
|
||||
gslc_tsElemRef* pElemRef = (gslc_tsElemRef*)(pvElemRef);
|
||||
gslc_tsXSpinner* pSpinner = (gslc_tsXSpinner*)gslc_GetXDataFromRef(pGui, pElemRef, GSLC_TYPEX_SPINNER, __LINE__);
|
||||
if (!pSpinner) return false;
|
||||
|
||||
// Get Collection
|
||||
gslc_tsCollect* pCollect = &pSpinner->sCollect;
|
||||
|
||||
return gslc_CollectTouchCompound(pvGui, pvElemRef, eTouch, nRelX, nRelY, pCollect);
|
||||
|
||||
#endif // !DRV_TOUCH_NONE
|
||||
}
|
||||
#endif // GSLC_FEATURE_COMPOUND
|
||||
|
||||
|
||||
// ============================================================================
|
210
src/guislice/XSpinner.h
Normal file
210
src/guislice/XSpinner.h
Normal file
|
@ -0,0 +1,210 @@
|
|||
#ifndef _GUISLICE_EX_XSPINNER_H_
|
||||
#define _GUISLICE_EX_XSPINNER_H_
|
||||
|
||||
#include "GUIslice.h"
|
||||
|
||||
|
||||
// =======================================================================
|
||||
// GUIslice library extension: Spinner (number selection) control
|
||||
// - Extension by Paul Conti, Calvin Hass
|
||||
// - https://www.impulseadventure.com/elec/guislice-gui.html
|
||||
// - https://github.com/ImpulseAdventure/GUIslice
|
||||
// =======================================================================
|
||||
//
|
||||
// The MIT License
|
||||
//
|
||||
// Copyright 2016-2020 Calvin Hass
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
//
|
||||
// =======================================================================
|
||||
/// \file XSpinner.h
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif // __cplusplus
|
||||
|
||||
|
||||
|
||||
#if (GSLC_FEATURE_COMPOUND)
|
||||
// ============================================================================
|
||||
// Extended Element: Spinner (Number Selector)
|
||||
// - Demonstration of a compound element consisting of
|
||||
// a counter text field along with an increment and
|
||||
// decrement button.
|
||||
// ============================================================================
|
||||
|
||||
// Define unique identifier for extended element type
|
||||
// - Select any number above GSLC_TYPE_BASE_EXTEND
|
||||
#define GSLC_TYPEX_SPINNER GSLC_TYPE_BASE_EXTEND + 15
|
||||
|
||||
// Define the max number of sub-elements in compound element
|
||||
#define XSPINNER_COMP_CNT 3
|
||||
|
||||
// Define the max string length to allocate for dynamic text elements
|
||||
#define XSPINNER_STR_LEN 8
|
||||
|
||||
// Define the status for GSLC_CB_INPUT callback
|
||||
#define XSPINNER_CB_STATE_UPDATE 3
|
||||
|
||||
// Extended element data structures
|
||||
// - These data structures are maintained in the gslc_tsElem
|
||||
// structure via the pXData pointer
|
||||
/// Extended data for Spinner element
|
||||
typedef struct {
|
||||
|
||||
// Core functionality for Spinner
|
||||
int16_t nMin; ///< Minimum control value
|
||||
int16_t nMax; ///< Maximum control value
|
||||
int16_t nIncr; ///< Increment by value
|
||||
int16_t nCounter; ///< Current value
|
||||
GSLC_CB_INPUT pfuncXInput; ///< Callback func ptr for input ready
|
||||
gslc_tsElemRef* pElemRef; ///< Save our ElemRef for the callback
|
||||
|
||||
// Internal sub-element members
|
||||
gslc_tsCollect sCollect; ///< Collection management for sub-elements
|
||||
gslc_tsElemRef asElemRef[XSPINNER_COMP_CNT]; ///< Storage for sub-element references
|
||||
gslc_tsElem asElem[XSPINNER_COMP_CNT]; ///< Storage for sub-elements
|
||||
|
||||
// Provide storage for any dynamic text elements
|
||||
// Simple example here uses fixed-length character array
|
||||
char acElemTxt[1][XSPINNER_STR_LEN]; ///< Storage for strings
|
||||
char acIncr[2]; ///< Increment character string
|
||||
char acDecr[2]; ///< Decrement character string
|
||||
|
||||
} gslc_tsXSpinner;
|
||||
|
||||
|
||||
|
||||
|
||||
///
|
||||
/// Create a Spinner Element
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] nElemId: Element ID to assign (0..16383 or GSLC_ID_AUTO to autogen)
|
||||
/// \param[in] nPage: Page ID to attach element to
|
||||
/// \param[in] pXData: Ptr to extended element data structure
|
||||
/// \param[in] rElem: Rectangle coordinates defining overall size
|
||||
/// \param[in] nMin: Minimum value of Spinner
|
||||
/// \param[in] nMax: Maximum value of Spinner
|
||||
/// \param[in] nVal: Starting value of Spinner
|
||||
/// \param[in] nIncr: Increment Spinner by this value
|
||||
/// \param[in] nFontId: Font ID to use for drawing the element
|
||||
/// \param[in] nButtonSz: Size of individual buttons
|
||||
/// \param[in] cbInput: Callback for touch events
|
||||
///
|
||||
/// \return Pointer to Element or NULL if failure
|
||||
///
|
||||
gslc_tsElemRef* gslc_ElemXSpinnerCreate(gslc_tsGui* pGui, int16_t nElemId, int16_t nPage, gslc_tsXSpinner* pXData,
|
||||
gslc_tsRect rElem, int16_t nMin, int16_t nMax, int16_t nVal, int16_t nIncr,
|
||||
int8_t nFontId, int8_t nButtonSz, GSLC_CB_INPUT cbInput);
|
||||
|
||||
|
||||
///
|
||||
/// Set Up and Down characters for the Spinner element
|
||||
/// - Called during redraw
|
||||
///
|
||||
/// \param[in] pvGui: Void ptr to GUI (typecast to gslc_tsGui*)
|
||||
/// \param[in] pElemRef: Ptr to ElementRef
|
||||
/// \param[in] cIncr: Character to use to indicate incrementing the spinner
|
||||
/// \param[in] cDecr: Character to use to indicate decrementing the spinner
|
||||
///
|
||||
/// \return true if success, false otherwise
|
||||
///
|
||||
bool gslc_ElemXSpinnerSetChars(void* pvGui,gslc_tsElemRef* pElemRef,uint8_t cIncr, uint8_t cDecr);
|
||||
|
||||
|
||||
///
|
||||
/// Draw a Spinner element on the screen
|
||||
/// - Called during redraw
|
||||
///
|
||||
/// \param[in] pvGui: Void ptr to GUI (typecast to gslc_tsGui*)
|
||||
/// \param[in] pvElemRef: Void ptr to Element (typecast to gslc_tsElemRef*)
|
||||
/// \param[in] eRedraw: Redraw mode
|
||||
///
|
||||
/// \return true if success, false otherwise
|
||||
///
|
||||
bool gslc_ElemXSpinnerDraw(void* pvGui,void* pvElemRef,gslc_teRedrawType eRedraw);
|
||||
|
||||
///
|
||||
/// Get the current counter associated with Spinner
|
||||
///
|
||||
/// \param[in] pGui: Ptr to GUI
|
||||
/// \param[in] pSpinner: Ptr to Element
|
||||
///
|
||||
/// \return Current counter value
|
||||
///
|
||||
int gslc_ElemXSpinnerGetCounter(gslc_tsGui* pGui,gslc_tsXSpinner* pSpinner);
|
||||
|
||||
|
||||
///
|
||||
/// Set the current counter associated with Spinner
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] pSpinner: Ptr to Element
|
||||
/// \param[in] nCount: New counter value
|
||||
///
|
||||
/// \return none
|
||||
///
|
||||
void gslc_ElemXSpinnerSetCounter(gslc_tsGui* pGui,gslc_tsXSpinner* pSpinner,int16_t nCount);
|
||||
|
||||
|
||||
///
|
||||
/// Handle a click event within the Spinner
|
||||
/// - This is called internally by the Spinner touch handler
|
||||
///
|
||||
/// \param[in] pvGui: Void ptr to GUI (typecast to gslc_tsGui*)
|
||||
/// \param[in] pvElemRef Void ptr to Element ref (typecast to gslc_tsElemRef*)
|
||||
/// \param[in] eTouch: Touch event type
|
||||
/// \param[in] nX: Touch X coord
|
||||
/// \param[in] nY: Touch Y coord
|
||||
///
|
||||
/// \return none
|
||||
///
|
||||
bool gslc_ElemXSpinnerClick(void* pvGui,void *pvElemRef,gslc_teTouch eTouch,int16_t nX,int16_t nY);
|
||||
|
||||
///
|
||||
/// Handle touch (up,down,move) events to Spinner element
|
||||
/// - Called from gslc_ElemSendEventTouch()
|
||||
///
|
||||
/// \param[in] pvGui: Void ptr to GUI (typecast to gslc_tsGui*)
|
||||
/// \param[in] pvElemRef: Void ptr to Element ref (typecast to gslc_tsElemRef*)
|
||||
/// \param[in] eTouch: Touch event type
|
||||
/// \param[in] nRelX: Touch X coord relative to element
|
||||
/// \param[in] nRelY: Touch Y coord relative to element
|
||||
///
|
||||
/// \return true if success, false otherwise
|
||||
///
|
||||
bool gslc_ElemXSpinnerTouch(void* pvGui,void* pvElemRef,gslc_teTouch eTouch,int16_t nRelX,int16_t nRelY);
|
||||
|
||||
#endif // GLSC_COMPOUND
|
||||
|
||||
// ============================================================================
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Read-only element macros
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
// Macro initializers for Read-Only Elements in Flash/PROGMEM
|
||||
//
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif // __cplusplus
|
||||
#endif // _GUISLICE_EX_XSPINNER_H_
|
||||
|
307
src/guislice/XTemplate.c
Normal file
307
src/guislice/XTemplate.c
Normal file
|
@ -0,0 +1,307 @@
|
|||
// =======================================================================
|
||||
// GUIslice library (extensions template)
|
||||
// - Calvin Hass
|
||||
// - https://www.impulseadventure.com/elec/guislice-gui.html
|
||||
// - https://github.com/ImpulseAdventure/GUIslice
|
||||
// =======================================================================
|
||||
//
|
||||
// The MIT License
|
||||
//
|
||||
// Copyright 2016-2020 Calvin Hass
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
//
|
||||
// =======================================================================
|
||||
/// \file XTemplate.c
|
||||
|
||||
|
||||
|
||||
// GUIslice library
|
||||
#include "GUIslice.h"
|
||||
#include "GUIslice_drv.h"
|
||||
|
||||
#include "XTemplate.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#if (GSLC_USE_PROGMEM)
|
||||
#include <avr/pgmspace.h>
|
||||
#endif
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Error Messages
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
extern const char GSLC_PMEM ERRSTR_NULL[];
|
||||
extern const char GSLC_PMEM ERRSTR_PXD_NULL[];
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Extended element definitions
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// - This file extends the core GUIslice functionality with
|
||||
// additional widget types
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
|
||||
// ============================================================================
|
||||
// Extended Element: Template example
|
||||
// - Demonstrates minimum code to implement an extended element
|
||||
// ============================================================================
|
||||
|
||||
// Create a text element and add it to the GUI element list
|
||||
// - Defines default styling for the element
|
||||
// - Defines callback for redraw and touch
|
||||
gslc_tsElemRef* gslc_ElemXTemplateCreate(gslc_tsGui* pGui, int16_t nElemId, int16_t nPage,
|
||||
gslc_tsXTemplate* pXData, gslc_tsRect rElem, char* pStrBuf, uint8_t nStrBufMax, int16_t nFontId)
|
||||
{
|
||||
if ((pGui == NULL) || (pXData == NULL)) {
|
||||
static const char GSLC_PMEM FUNCSTR[] = "ElemXTemplateCreate";
|
||||
GSLC_DEBUG2_PRINT_CONST(ERRSTR_NULL,FUNCSTR);
|
||||
return NULL;
|
||||
}
|
||||
gslc_tsElem sElem;
|
||||
gslc_tsElemRef* pElemRef = NULL;
|
||||
sElem = gslc_ElemCreate(pGui,nElemId,nPage,GSLC_TYPEX_TEMPLATE,rElem,pStrBuf,nStrBufMax,nFontId);
|
||||
sElem.colElemFill = GSLC_COL_BLACK;
|
||||
sElem.colElemFillGlow = GSLC_COL_BLACK;
|
||||
sElem.colElemFrame = GSLC_COL_GRAY;
|
||||
sElem.colElemFrameGlow = GSLC_COL_GRAY;
|
||||
sElem.colElemText = GSLC_COL_WHITE;
|
||||
sElem.colElemTextGlow = GSLC_COL_WHITE;
|
||||
sElem.nFeatures |= GSLC_ELEM_FEA_FILL_EN;
|
||||
sElem.nFeatures &= ~GSLC_ELEM_FEA_FRAME_EN;
|
||||
sElem.nFeatures |= GSLC_ELEM_FEA_CLICK_EN;
|
||||
sElem.nFeatures |= GSLC_ELEM_FEA_GLOW_EN;
|
||||
sElem.eTxtAlign = GSLC_ALIGN_MID_LEFT;
|
||||
|
||||
sElem.nGroup = GSLC_GROUP_ID_NONE;
|
||||
|
||||
// TODO:
|
||||
// - Initialize any pxData members with the constructor parameters
|
||||
// eg. pXData->nPos = nPos;
|
||||
|
||||
sElem.pXData = (void*)(pXData);
|
||||
// Specify the custom drawing callback
|
||||
sElem.pfuncXDraw = &gslc_ElemXTemplateDraw;
|
||||
// Specify the custom touch tracking callback
|
||||
sElem.pfuncXTouch = &gslc_ElemXTemplateTouch;
|
||||
|
||||
if (nPage != GSLC_PAGE_NONE) {
|
||||
pElemRef = gslc_ElemAdd(pGui,nPage,&sElem,GSLC_ELEMREF_DEFAULT);
|
||||
return pElemRef;
|
||||
#if (GSLC_FEATURE_COMPOUND)
|
||||
} else {
|
||||
// Save as temporary element
|
||||
pGui->sElemTmp = sElem;
|
||||
pGui->sElemRefTmp.pElem = &(pGui->sElemTmp);
|
||||
pGui->sElemRefTmp.eElemFlags = GSLC_ELEMREF_DEFAULT | GSLC_ELEMREF_REDRAW_FULL;
|
||||
return &(pGui->sElemRefTmp);
|
||||
#endif
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
// Redraw the element
|
||||
// - Note that this redraw is for the entire element rect region
|
||||
// - The Draw function parameters use void pointers to allow for
|
||||
// simpler callback function definition & scalability.
|
||||
bool gslc_ElemXTemplateDraw(void* pvGui,void* pvElemRef,gslc_teRedrawType eRedraw)
|
||||
{
|
||||
if ((pvGui == NULL) || (pvElemRef == NULL)) {
|
||||
static const char GSLC_PMEM FUNCSTR[] = "ElemXTemplateDraw";
|
||||
GSLC_DEBUG2_PRINT_CONST(ERRSTR_NULL,FUNCSTR);
|
||||
return false;
|
||||
}
|
||||
// Typecast the parameters to match the GUI and element types
|
||||
gslc_tsGui* pGui = (gslc_tsGui*)(pvGui);
|
||||
gslc_tsElemRef* pElemRef = (gslc_tsElemRef*)(pvElemRef);
|
||||
gslc_tsElem* pElem = gslc_GetElemFromRef(pGui,pElemRef);
|
||||
|
||||
// Fetch the element's extended data structure
|
||||
gslc_tsXTemplate* pTemplate = (gslc_tsXTemplate*)(pElem->pXData);
|
||||
if (pTemplate == NULL) {
|
||||
GSLC_DEBUG2_PRINT("ERROR: ElemXTemplateDraw(%s) pXData is NULL\n","");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Template example drawing routine implements formatted text field
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// Init for default drawing
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
bool bGlowEn,bGlowing,bGlowNow;
|
||||
//int16_t nElemX,nElemY;
|
||||
//uint16_t nElemW,nElemH;
|
||||
|
||||
//nElemX = pElem->rElem.x;
|
||||
//nElemY = pElem->rElem.y;
|
||||
//nElemW = pElem->rElem.w;
|
||||
//nElemH = pElem->rElem.h;
|
||||
bGlowEn = pElem->nFeatures & GSLC_ELEM_FEA_GLOW_EN; // Does the element support glow state?
|
||||
bGlowing = gslc_ElemGetGlow(pGui,pElemRef); // Element should be glowing (if enabled)
|
||||
bGlowNow = bGlowEn & bGlowing; // Element is currently glowing
|
||||
gslc_tsColor colBg = GSLC_COL_BLACK;
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// Background
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
// Fill in the background
|
||||
gslc_tsRect rElemInner = pElem->rElem;
|
||||
// - If both fill and frame are enabled then contract
|
||||
// the fill region slightly so that we don't overdraw
|
||||
// the frame (prevent unnecessary flicker).
|
||||
if ((pElem->nFeatures & GSLC_ELEM_FEA_FILL_EN) && (pElem->nFeatures & GSLC_ELEM_FEA_FRAME_EN)) {
|
||||
// NOTE: If the region is already too small to shrink (eg. w=1 or h=1)
|
||||
// then a zero dimension box will be returned by ExpandRect() and not drawn
|
||||
rElemInner = gslc_ExpandRect(rElemInner,-1,-1);
|
||||
}
|
||||
// - This also changes the fill color if selected and glow state is enabled
|
||||
if (pElem->nFeatures & GSLC_ELEM_FEA_FILL_EN) {
|
||||
if (bGlowEn && bGlowing) {
|
||||
colBg = pElem->colElemFillGlow;
|
||||
} else {
|
||||
colBg = pElem->colElemFill;
|
||||
}
|
||||
if (pElem->nFeatures & GSLC_ELEM_FEA_ROUND_EN) {
|
||||
gslc_DrawFillRoundRect(pGui, rElemInner, pGui->nRoundRadius, colBg);
|
||||
} else {
|
||||
gslc_DrawFillRect(pGui, rElemInner, colBg);
|
||||
}
|
||||
} else {
|
||||
// TODO: If unfilled, then we might need
|
||||
// to redraw the background layer(s)
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// Frame
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
// Frame the region
|
||||
if (pElem->nFeatures & GSLC_ELEM_FEA_FRAME_EN) {
|
||||
if (pElem->nFeatures & GSLC_ELEM_FEA_ROUND_EN) {
|
||||
gslc_DrawFrameRoundRect(pGui, pElem->rElem, pGui->nRoundRadius, pElem->colElemFrame);
|
||||
} else {
|
||||
gslc_DrawFrameRect(pGui, pElem->rElem, pElem->colElemFrame);
|
||||
}
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// Text overlays
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
// Draw text string if defined
|
||||
if (pElem->pStrBuf) {
|
||||
gslc_tsColor colTxt = (bGlowNow)? pElem->colElemTextGlow : pElem->colElemText;
|
||||
int8_t nMarginX = pElem->nTxtMarginX;
|
||||
int8_t nMarginY = pElem->nTxtMarginY;
|
||||
|
||||
gslc_DrawTxtBase(pGui, pElem->pStrBuf, pElem->rElem, pElem->pTxtFont, pElem->eTxtFlags,
|
||||
pElem->eTxtAlign, colTxt, colBg, nMarginX, nMarginY);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
// Mark the element as no longer requiring redraw
|
||||
gslc_ElemSetRedraw(pGui,pElemRef,GSLC_REDRAW_NONE);
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
|
||||
// This callback function is called by gslc_ElemSendEventTouch()
|
||||
// after any touch event
|
||||
bool gslc_ElemXTemplateTouch(void* pvGui,void* pvElemRef,gslc_teTouch eTouch,int16_t nRelX,int16_t nRelY)
|
||||
{
|
||||
#if defined(DRV_TOUCH_NONE)
|
||||
return false;
|
||||
#else
|
||||
|
||||
// Define any specific touch handling here
|
||||
|
||||
if ((pvGui == NULL) || (pvElemRef == NULL)) {
|
||||
static const char GSLC_PMEM FUNCSTR[] = "ElemXTemplateTouch";
|
||||
GSLC_DEBUG2_PRINT_CONST(ERRSTR_NULL,FUNCSTR);
|
||||
return false;
|
||||
}
|
||||
gslc_tsGui* pGui = NULL;
|
||||
gslc_tsElemRef* pElemRef = NULL;
|
||||
//gslc_tsElem* pElem = NULL;
|
||||
//gslc_tsXTemplate* pTemplate = NULL;
|
||||
|
||||
// Typecast the parameters to match the GUI
|
||||
pGui = (gslc_tsGui*)(pvGui);
|
||||
pElemRef = (gslc_tsElemRef*)(pvElemRef);
|
||||
//pElem = gslc_GetElemFromRef(pGui,pElemRef);
|
||||
//pTemplate = (gslc_tsXTemplate*)(pElem->pXData);
|
||||
|
||||
bool bGlowingOld = gslc_ElemGetGlow(pGui,pElemRef);
|
||||
|
||||
// Example touch handler simply tracks "glowing" status
|
||||
|
||||
switch(eTouch) {
|
||||
|
||||
case GSLC_TOUCH_DOWN_IN:
|
||||
// Start glowing as must be over it
|
||||
gslc_ElemSetGlow(pGui,pElemRef,true);
|
||||
break;
|
||||
|
||||
case GSLC_TOUCH_MOVE_IN:
|
||||
gslc_ElemSetGlow(pGui,pElemRef,true);
|
||||
break;
|
||||
case GSLC_TOUCH_MOVE_OUT:
|
||||
gslc_ElemSetGlow(pGui,pElemRef,false);
|
||||
break;
|
||||
|
||||
case GSLC_TOUCH_UP_IN:
|
||||
// End glow
|
||||
gslc_ElemSetGlow(pGui,pElemRef,false);
|
||||
break;
|
||||
case GSLC_TOUCH_UP_OUT:
|
||||
// End glow
|
||||
gslc_ElemSetGlow(pGui,pElemRef,false);
|
||||
break;
|
||||
|
||||
case GSLC_TOUCH_SET_REL:
|
||||
case GSLC_TOUCH_SET_ABS:
|
||||
gslc_ElemSetGlow(pGui,pElemRef,true);
|
||||
break;
|
||||
|
||||
default:
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
|
||||
// If the slider changed state, redraw
|
||||
if (gslc_ElemGetGlow(pGui,pElemRef) != bGlowingOld) {
|
||||
gslc_ElemSetRedraw(pGui,pElemRef,GSLC_REDRAW_FULL);
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
#endif // !DRV_TOUCH_NONE
|
||||
}
|
||||
|
||||
// ============================================================================
|
128
src/guislice/XTemplate.h
Normal file
128
src/guislice/XTemplate.h
Normal file
|
@ -0,0 +1,128 @@
|
|||
#ifndef _GUISLICE_EX_XTEMPLATE_H_
|
||||
#define _GUISLICE_EX_XTEMPLATE_H_
|
||||
|
||||
#include "GUIslice.h"
|
||||
|
||||
|
||||
// =======================================================================
|
||||
// GUIslice library extension: Example template
|
||||
// - Calvin Hass
|
||||
// - https://www.impulseadventure.com/elec/guislice-gui.html
|
||||
// - https://github.com/ImpulseAdventure/GUIslice
|
||||
// =======================================================================
|
||||
//
|
||||
// The MIT License
|
||||
//
|
||||
// Copyright 2016-2020 Calvin Hass
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
//
|
||||
// =======================================================================
|
||||
/// \file XTemplate.h
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif // __cplusplus
|
||||
|
||||
|
||||
// ============================================================================
|
||||
// Extended Element: Example template
|
||||
// ============================================================================
|
||||
|
||||
// Define unique identifier for extended element type
|
||||
// - Select any number above GSLC_TYPE_BASE_EXTEND
|
||||
#define GSLC_TYPEX_TEMPLATE GSLC_TYPE_BASE_EXTEND + 12
|
||||
|
||||
/// Callback function for slider feedback
|
||||
//typedef bool (*GSLC_CB_XTEMPLATE_POS)(void* pvGui,void* pvElem,int16_t nPos);
|
||||
|
||||
// Extended element data structures
|
||||
// - These data structures are maintained in the gslc_tsElem
|
||||
// structure via the pXData pointer
|
||||
|
||||
/// Extended data for Slider element
|
||||
typedef struct {
|
||||
// Config
|
||||
// Style config
|
||||
// State
|
||||
//int16_t nPos; ///< Example position value
|
||||
// Callbacks
|
||||
//GSLC_CB_XTEXTEX_POS pfuncXPos; ///< Callback func ptr for position update
|
||||
} gslc_tsXTemplate;
|
||||
|
||||
|
||||
///
|
||||
/// Create an Extended Text Field Element
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] nElemId: Element ID to assign (0..16383 or GSLC_ID_AUTO to autogen)
|
||||
/// \param[in] nPage: Page ID to attach element to
|
||||
/// \param[in] pXData: Ptr to extended element data structure
|
||||
/// \param[in] rElem: Rectangle coordinates defining element size
|
||||
/// \param[in] pStrBuf: Ptr to string buffer
|
||||
/// \param[in] nStrBufMax: Maximum buffer alength allocated to pStrBuf
|
||||
/// \param[in] nFontId: ID of font to use for text output
|
||||
///
|
||||
/// \return Pointer to Element reference or NULL if failure
|
||||
///
|
||||
gslc_tsElemRef* gslc_ElemXTemplateCreate(gslc_tsGui* pGui, int16_t nElemId, int16_t nPage,
|
||||
gslc_tsXTemplate* pXData, gslc_tsRect rElem, char* pStrBuf, uint8_t nStrBufMax, int16_t nFontId);
|
||||
|
||||
|
||||
///
|
||||
/// Draw the template element on the screen
|
||||
/// - Called from gslc_ElemDraw()
|
||||
///
|
||||
/// \param[in] pvGui: Void ptr to GUI (typecast to gslc_tsGui*)
|
||||
/// \param[in] pvElemRef: Void ptr to Element (typecast to gslc_tsElemRef*)
|
||||
/// \param[in] eRedraw: Redraw mode
|
||||
///
|
||||
/// \return true if success, false otherwise
|
||||
///
|
||||
bool gslc_ElemXTemplateDraw(void* pvGui,void* pvElemRef,gslc_teRedrawType eRedraw);
|
||||
|
||||
///
|
||||
/// Handle touch events to template element
|
||||
/// - Called from gslc_ElemSendEventTouch()
|
||||
///
|
||||
/// \param[in] pvGui: Void ptr to GUI (typecast to gslc_tsGui*)
|
||||
/// \param[in] pvElemRef: Void ptr to Element ref (typecast to gslc_tsElemRef*)
|
||||
/// \param[in] eTouch: Touch event type
|
||||
/// \param[in] nRelX: Touch X coord relative to element
|
||||
/// \param[in] nRelY: Touch Y coord relative to element
|
||||
///
|
||||
/// \return true if success, false otherwise
|
||||
///
|
||||
bool gslc_ElemXTemplateTouch(void* pvGui,void* pvElemRef,gslc_teTouch eTouch,int16_t nRelX,int16_t nRelY);
|
||||
|
||||
// ============================================================================
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Read-only element macros
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
// Macro initializers for Read-Only Elements in Flash/PROGMEM
|
||||
//
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif // __cplusplus
|
||||
#endif // _GUISLICE_EX_XTEMPLATE_H_
|
||||
|
663
src/guislice/XTextbox.c
Normal file
663
src/guislice/XTextbox.c
Normal file
|
@ -0,0 +1,663 @@
|
|||
// =======================================================================
|
||||
// GUIslice library (extensions)
|
||||
// - Calvin Hass
|
||||
// - https://www.impulseadventure.com/elec/guislice-gui.html
|
||||
// - https://github.com/ImpulseAdventure/GUIslice
|
||||
// =======================================================================
|
||||
//
|
||||
// The MIT License
|
||||
//
|
||||
// Copyright 2016-2020 Calvin Hass
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
//
|
||||
// =======================================================================
|
||||
/// \file XTextbox.c
|
||||
|
||||
|
||||
|
||||
// GUIslice library
|
||||
#include "GUIslice.h"
|
||||
#include "GUIslice_drv.h"
|
||||
|
||||
#include "XTextbox.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#if (GSLC_USE_PROGMEM)
|
||||
#include <avr/pgmspace.h>
|
||||
#endif
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Error Messages
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
extern const char GSLC_PMEM ERRSTR_NULL[];
|
||||
extern const char GSLC_PMEM ERRSTR_PXD_NULL[];
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Extended element definitions
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// - This file extends the core GUIslice functionality with
|
||||
// additional widget types
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
|
||||
// ============================================================================
|
||||
|
||||
gslc_tsElemRef* gslc_ElemXTextboxCreate(gslc_tsGui* pGui,int16_t nElemId,int16_t nPage,
|
||||
gslc_tsXTextbox* pXData,gslc_tsRect rElem,int16_t nFontId,char* pBuf,
|
||||
uint16_t nBufRows,uint16_t nBufCols)
|
||||
{
|
||||
if ((pGui == NULL) || (pXData == NULL)) {
|
||||
static const char GSLC_PMEM FUNCSTR[] = "ElemXTextboxCreate";
|
||||
GSLC_DEBUG2_PRINT_CONST(ERRSTR_NULL,FUNCSTR);
|
||||
return NULL;
|
||||
}
|
||||
gslc_tsElem sElem;
|
||||
gslc_tsElemRef* pElemRef = NULL;
|
||||
sElem = gslc_ElemCreate(pGui,nElemId,nPage,GSLC_TYPEX_TEXTBOX,rElem,NULL,0,nFontId);
|
||||
sElem.nFeatures |= GSLC_ELEM_FEA_FRAME_EN;
|
||||
sElem.nFeatures |= GSLC_ELEM_FEA_FILL_EN;
|
||||
sElem.nFeatures &= ~GSLC_ELEM_FEA_CLICK_EN;
|
||||
sElem.nFeatures &= ~GSLC_ELEM_FEA_GLOW_EN;
|
||||
// Default group assignment. Can override later with ElemSetGroup()
|
||||
sElem.nGroup = GSLC_GROUP_ID_NONE;
|
||||
|
||||
// Define other extended data
|
||||
pXData->pBuf = pBuf;
|
||||
pXData->nMarginX = 5;
|
||||
pXData->nMarginY = 5;
|
||||
pXData->bWrapEn = true;
|
||||
pXData->nCurPosX = 0;
|
||||
pXData->nCurPosY = 0;
|
||||
|
||||
pXData->nBufRows = nBufRows;
|
||||
pXData->nBufCols = nBufCols;
|
||||
pXData->nBufPosX = 0;
|
||||
pXData->nBufPosY = 0;
|
||||
pXData->nWndRowStart = 0;
|
||||
|
||||
pXData->nRedrawRow = XTEXTBOX_REDRAW_ALL;
|
||||
|
||||
// Clear the buffer
|
||||
memset(pBuf,0,nBufRows*nBufCols*sizeof(char));
|
||||
|
||||
// Precalculate certain parameters
|
||||
// Determine the maximum size of a character
|
||||
// - For now, assume we are using a monospaced font and derive
|
||||
// text pixel coords from the size of a worst-case character.
|
||||
int16_t nChOffsetX, nChOffsetY, nChOffsetTmp;
|
||||
uint16_t nChSzW,nChSzH,nChSzTmp;
|
||||
|
||||
// Fetch X & Y sizing and offsets independently, based on characters that
|
||||
// are likely to maximize the ascenders / descenders / width attributes
|
||||
char acMonoH[3] = "p$";
|
||||
char acMonoW[2] = "W";
|
||||
|
||||
gslc_DrvGetTxtSize(pGui, sElem.pTxtFont, (char*)&acMonoH, sElem.eTxtFlags, &nChOffsetTmp, &nChOffsetY, &nChSzTmp, &nChSzH);
|
||||
gslc_DrvGetTxtSize(pGui, sElem.pTxtFont, (char*)&acMonoW, sElem.eTxtFlags, &nChOffsetX, &nChOffsetTmp, &nChSzW, &nChSzTmp);
|
||||
|
||||
pXData->nWndCols = (rElem.w - (2*pXData->nMarginX)) / nChSzW;
|
||||
pXData->nWndRows = (rElem.h - (2*pXData->nMarginY)) / nChSzH;
|
||||
|
||||
// Adjust margin to correct for character offsets
|
||||
pXData->nMarginX -= nChOffsetX;
|
||||
pXData->nMarginY -= nChOffsetY;
|
||||
|
||||
pXData->nChSizeX = nChSzW;
|
||||
pXData->nChSizeY = nChSzH;
|
||||
|
||||
// Determine if scrollbar should be enabled
|
||||
if (pXData->nWndRows >= pXData->nBufRows) {
|
||||
// Disable scrollbar as the window is larger
|
||||
// than the number of rows in the buffer
|
||||
pXData->bScrollEn = false;
|
||||
pXData->nScrollPos = 0;
|
||||
} else {
|
||||
// Scrollbar is enabled
|
||||
pXData->bScrollEn = true;
|
||||
pXData->nScrollPos = 0;
|
||||
}
|
||||
|
||||
sElem.pXData = (void*)(pXData);
|
||||
|
||||
// Specify the custom drawing callback
|
||||
sElem.pfuncXDraw = &gslc_ElemXTextboxDraw;
|
||||
sElem.pfuncXTouch = NULL;
|
||||
sElem.colElemFill = GSLC_COL_BLACK;
|
||||
sElem.colElemFillGlow = GSLC_COL_BLACK;
|
||||
sElem.colElemFrame = GSLC_COL_GRAY;
|
||||
sElem.colElemFrameGlow = GSLC_COL_WHITE;
|
||||
if (nPage != GSLC_PAGE_NONE) {
|
||||
pElemRef = gslc_ElemAdd(pGui,nPage,&sElem,GSLC_ELEMREF_DEFAULT);
|
||||
return pElemRef;
|
||||
#if (GSLC_FEATURE_COMPOUND)
|
||||
} else {
|
||||
// Save as temporary element
|
||||
pGui->sElemTmp = sElem;
|
||||
pGui->sElemRefTmp.pElem = &(pGui->sElemTmp);
|
||||
pGui->sElemRefTmp.eElemFlags = GSLC_ELEMREF_DEFAULT | GSLC_ELEMREF_REDRAW_FULL;
|
||||
return &(pGui->sElemRefTmp);
|
||||
#endif
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
void gslc_ElemXTextboxReset(gslc_tsGui* pGui,gslc_tsElemRef* pElemRef)
|
||||
{
|
||||
if (pElemRef == NULL) {
|
||||
static const char GSLC_PMEM FUNCSTR[] = "ElemXTextboxReset";
|
||||
GSLC_DEBUG2_PRINT_CONST(ERRSTR_NULL,FUNCSTR);
|
||||
return;
|
||||
}
|
||||
gslc_tsXTextbox* pBox;
|
||||
gslc_tsElem* pElem = gslc_GetElemFromRef(pGui,pElemRef);
|
||||
pBox = (gslc_tsXTextbox*)(pElem->pXData);
|
||||
|
||||
// Reset the positional state
|
||||
pBox->nCurPosX = 0;
|
||||
pBox->nCurPosY = 0;
|
||||
pBox->nBufPosX = 0;
|
||||
pBox->nBufPosY = 0;
|
||||
pBox->nWndRowStart = 0;
|
||||
|
||||
// Clear the buffer
|
||||
memset(pBox->pBuf,0,pBox->nBufRows*pBox->nBufCols*sizeof(char));
|
||||
|
||||
// Set the redraw flag
|
||||
// - Only need incremental redraw
|
||||
pBox->nRedrawRow = XTEXTBOX_REDRAW_ALL; // All-row update
|
||||
gslc_ElemSetRedraw(pGui,pElemRef,GSLC_REDRAW_INC);
|
||||
}
|
||||
|
||||
// Advance the buffer writer to the next line
|
||||
// The window is also shifted if we are eating the first row
|
||||
void gslc_ElemXTextboxLineWrAdv(gslc_tsGui* pGui,gslc_tsElemRef* pElemRef)
|
||||
{
|
||||
if (pElemRef == NULL) {
|
||||
static const char GSLC_PMEM FUNCSTR[] = "ElemXTextboxLineWrAdv";
|
||||
GSLC_DEBUG2_PRINT_CONST(ERRSTR_NULL,FUNCSTR);
|
||||
return;
|
||||
}
|
||||
gslc_tsXTextbox* pBox;
|
||||
gslc_tsElem* pElem = gslc_GetElemFromRef(pGui,pElemRef);
|
||||
pBox = (gslc_tsXTextbox*)(pElem->pXData);
|
||||
|
||||
pBox->nBufPosX = 0;
|
||||
pBox->nBufPosY++;
|
||||
|
||||
// Wrap the pointers around end of buffer
|
||||
pBox->nBufPosY = pBox->nBufPosY % pBox->nBufRows;
|
||||
|
||||
// Did the buffer write pointer start to encroach upon
|
||||
// the visible window region? If so, shift the window
|
||||
if (pBox->nBufPosY == pBox->nWndRowStart) {
|
||||
// Advance the window (with wrap if needed)
|
||||
pBox->nWndRowStart = (pBox->nWndRowStart + 1) % pBox->nBufRows;
|
||||
// Ensure all rows get redrawn
|
||||
pBox->nRedrawRow = XTEXTBOX_REDRAW_ALL;
|
||||
gslc_ElemSetRedraw(pGui,pElemRef,GSLC_REDRAW_INC);
|
||||
}
|
||||
}
|
||||
|
||||
void gslc_ElemXTextboxScrollSet(gslc_tsGui* pGui,gslc_tsElemRef* pElemRef,uint8_t nScrollPos,uint8_t nScrollMax)
|
||||
{
|
||||
|
||||
gslc_tsXTextbox* pBox;
|
||||
gslc_tsElem* pElem = gslc_GetElemFromRef(pGui,pElemRef);
|
||||
pBox = (gslc_tsXTextbox*)(pElem->pXData);
|
||||
|
||||
// Ensure scrollbar is enabled
|
||||
if (!pBox->bScrollEn) {
|
||||
// Scrollbar is disabled, so ignore
|
||||
return;
|
||||
}
|
||||
|
||||
// Check for out-of-range values
|
||||
if (nScrollPos > nScrollMax) {
|
||||
GSLC_DEBUG2_PRINT("ERROR: ElemXTextboxScrollSet() pos [%u] exceeds max [%u]\n", nScrollPos,nScrollMax);
|
||||
// Force the position to the max
|
||||
nScrollPos = nScrollMax;
|
||||
}
|
||||
|
||||
// Assign proportional value based on visible window region
|
||||
uint16_t nScrollPosOld = pBox->nScrollPos;
|
||||
pBox->nScrollPos = nScrollPos * (pBox->nBufRows - pBox->nWndRows) / nScrollMax;
|
||||
|
||||
// Set the redraw flag
|
||||
// - Only need incremental redraw
|
||||
// - Only redraw if changed actual scroll row
|
||||
if (pBox->nScrollPos != nScrollPosOld) {
|
||||
// Ensure all rows get redrawn
|
||||
pBox->nRedrawRow = XTEXTBOX_REDRAW_ALL;
|
||||
gslc_ElemSetRedraw(pGui,pElemRef,GSLC_REDRAW_INC);
|
||||
}
|
||||
}
|
||||
|
||||
// Write a character to the buffer
|
||||
// - Advance the write ptr, wrap if needed
|
||||
// - If encroach upon buffer read ptr, then drop the oldest line from the buffer
|
||||
// NOTE: This should not be called with newline char!
|
||||
void gslc_ElemXTextboxBufAdd(gslc_tsGui* pGui,gslc_tsElemRef* pElemRef,unsigned char chNew,bool bAdvance)
|
||||
{
|
||||
gslc_tsXTextbox* pBox;
|
||||
gslc_tsElem* pElem = gslc_GetElemFromRef(pGui,pElemRef);
|
||||
pBox = (gslc_tsXTextbox*)(pElem->pXData);
|
||||
|
||||
// Ensure that we haven't gone past end of line
|
||||
// - Note that we have to leave one extra byte for the line terminator (NULL)
|
||||
if ((pBox->nBufPosX+1) >= pBox->nBufCols) {
|
||||
if (pBox->bWrapEn) {
|
||||
// Perform line wrap
|
||||
// - Force a null at the end of the current line first
|
||||
pBox->pBuf[pBox->nBufPosY * pBox->nBufCols + (pBox->nBufCols-1)] = 0;
|
||||
gslc_ElemXTextboxLineWrAdv(pGui,pElemRef);
|
||||
} else {
|
||||
// Ignore the write
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
uint16_t nBufPos = pBox->nBufPosY * pBox->nBufCols + pBox->nBufPosX;
|
||||
|
||||
// Add the character
|
||||
pBox->pBuf[nBufPos] = chNew;
|
||||
|
||||
// Only trigger redraw if we have output a printable character
|
||||
// to the display buffer. For simplicity, just check for
|
||||
// null for now.
|
||||
// TODO: Consider checking isprint()
|
||||
if (chNew == 0) {
|
||||
// Don't update redraw on non-printing characters
|
||||
} else {
|
||||
|
||||
// Mark this specific row as needing redraw
|
||||
if (pBox->nRedrawRow == XTEXTBOX_REDRAW_NONE) {
|
||||
// No redraw was pending, so mark single row pending
|
||||
pBox->nRedrawRow = pBox->nBufPosY;
|
||||
}
|
||||
else if (pBox->nRedrawRow == XTEXTBOX_REDRAW_ALL) {
|
||||
// All-row redraw was pending, so no change
|
||||
}
|
||||
else {
|
||||
// Single row redraw was pending
|
||||
if (pBox->nRedrawRow != pBox->nBufPosY) {
|
||||
// But the pending row differs from the current row,
|
||||
// so promote redraw to all lines
|
||||
pBox->nRedrawRow = XTEXTBOX_REDRAW_ALL;
|
||||
}
|
||||
else {
|
||||
// Pending row is the same, so no change
|
||||
}
|
||||
}
|
||||
} // chNew
|
||||
|
||||
// Optionally advance the pointer
|
||||
// - The only time we don't advance is if we added NULL
|
||||
// but note that in some special commands there may be
|
||||
// zero values added, so we still need to advance these
|
||||
if (bAdvance) {
|
||||
pBox->nBufPosX++;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void gslc_ElemXTextboxColSet(gslc_tsGui* pGui,gslc_tsElemRef* pElemRef,gslc_tsColor nCol)
|
||||
{
|
||||
#if (GSLC_FEATURE_XTEXTBOX_EMBED == 0)
|
||||
GSLC_DEBUG2_PRINT("ERROR: gslc_ElemXTextboxColSet() not enabled. Requires GSLC_FEATURE_XTEXTBOX_EMBED=1 %s\n","");
|
||||
return;
|
||||
#else
|
||||
gslc_tsXTextbox* pBox = NULL;
|
||||
gslc_tsElem* pElem = gslc_GetElemFromRef(pGui,pElemRef);
|
||||
pBox = (gslc_tsXTextbox*)(pElem->pXData);
|
||||
|
||||
// Ensure that there are enough free columns in current
|
||||
// buffer row to accommodate the color code (4 bytes)
|
||||
if (pBox->nBufPosX +4 >= pBox->nBufCols) {
|
||||
// Not enough space for the code, so ignore it
|
||||
GSLC_DEBUG2_PRINT("ERROR: gslc_ElemXTextboxColSet() not enough cols [Pos=%u Cols=%u]\n",pBox->nBufPosX,pBox->nBufCols);
|
||||
return;
|
||||
}
|
||||
|
||||
gslc_ElemXTextboxBufAdd(pGui,pElemRef,GSLC_XTEXTBOX_CODE_COL_SET,true);
|
||||
gslc_ElemXTextboxBufAdd(pGui,pElemRef,nCol.r,true);
|
||||
gslc_ElemXTextboxBufAdd(pGui,pElemRef,nCol.g,true);
|
||||
gslc_ElemXTextboxBufAdd(pGui,pElemRef,nCol.b,true);
|
||||
#endif
|
||||
}
|
||||
|
||||
void gslc_ElemXTextboxColReset(gslc_tsGui* pGui,gslc_tsElemRef* pElemRef)
|
||||
{
|
||||
#if (GSLC_FEATURE_XTEXTBOX_EMBED == 0)
|
||||
GSLC_DEBUG2_PRINT("ERROR: gslc_ElemXTextboxColReset() not enabled. Requires GSLC_FEATURE_XTEXTBOX_EMBED=1 %s\n","");
|
||||
return;
|
||||
#else
|
||||
gslc_tsXTextbox* pBox = NULL;
|
||||
gslc_tsElem* pElem = gslc_GetElemFromRef(pGui,pElemRef);
|
||||
pBox = (gslc_tsXTextbox*)(pElem->pXData);
|
||||
(void)pBox; // Unused
|
||||
gslc_ElemXTextboxBufAdd(pGui,pElemRef,GSLC_XTEXTBOX_CODE_COL_RESET,true);
|
||||
#endif
|
||||
}
|
||||
|
||||
void gslc_ElemXTextboxWrapSet(gslc_tsGui* pGui,gslc_tsElemRef* pElemRef,bool bWrapEn)
|
||||
{
|
||||
gslc_tsXTextbox* pBox = NULL;
|
||||
gslc_tsElem* pElem = gslc_GetElemFromRef(pGui,pElemRef);
|
||||
pBox = (gslc_tsXTextbox*)(pElem->pXData);
|
||||
pBox->bWrapEn = bWrapEn;
|
||||
}
|
||||
|
||||
|
||||
void gslc_ElemXTextboxAdd(gslc_tsGui* pGui,gslc_tsElemRef* pElemRef,char* pTxt)
|
||||
{
|
||||
|
||||
// Warn the user about mode compatibility
|
||||
#if (GSLC_FEATURE_XTEXTBOX_EMBED)
|
||||
gslc_tsElem* pElem = gslc_GetElemFromRef(pGui,pElemRef);
|
||||
//gslc_tsXTextbox* pBox = (gslc_tsXTextbox*)(pElem->pXData);
|
||||
static bool bWarned = false; // Warn only once
|
||||
bool bEncUtf8 = ((pElem->eTxtFlags & GSLC_TXT_ENC) == GSLC_TXT_ENC_UTF8);
|
||||
if ((!bWarned) && (bEncUtf8)) {
|
||||
// Continue to render the text, but issue warning to the user
|
||||
GSLC_DEBUG2_PRINT("WARNING: ElemXTextboxAdd(%s) UTF-8 encoding not supported in GSLC_FEATURE_XTEXTBOX_EMBED=1 mode\n","");
|
||||
bWarned = true;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Add null-terminated string to the bottom of the buffer
|
||||
// If the string exceeds the buffer length then it will wrap
|
||||
// back to the beginning.
|
||||
// TODO: Ensure that buffer wrap doesn't encroach upon visible region!
|
||||
// TODO: Assert (pBox)
|
||||
bool bDone = false;
|
||||
uint16_t nTxtPos = 0;
|
||||
unsigned char chNext;
|
||||
|
||||
if (pTxt == NULL) { bDone = true; }
|
||||
while (!bDone) {
|
||||
chNext = pTxt[nTxtPos];
|
||||
nTxtPos++;
|
||||
if (chNext == 0) {
|
||||
// Reached terminator character
|
||||
// Add terminator to buffer but don't advance write pointer
|
||||
// since we want next write to overwrite this
|
||||
gslc_ElemXTextboxBufAdd(pGui,pElemRef,0,false);
|
||||
|
||||
bDone = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
// FIXME: It is possible that the following check may no longer be
|
||||
// appropriate when using UTF-8 encoding mode.
|
||||
if (chNext == '\n') {
|
||||
// Terminate the line
|
||||
gslc_ElemXTextboxBufAdd(pGui,pElemRef,0,false);
|
||||
// Advance the writer by one line
|
||||
gslc_ElemXTextboxLineWrAdv(pGui,pElemRef);
|
||||
} else {
|
||||
// TODO: Check to see if we are in mask/truncate state
|
||||
// Note that this routine also handles line wrap
|
||||
gslc_ElemXTextboxBufAdd(pGui,pElemRef,chNext,true);
|
||||
}
|
||||
}
|
||||
|
||||
// Set the redraw flag
|
||||
// - Only need incremental redraw
|
||||
gslc_ElemSetRedraw(pGui,pElemRef,GSLC_REDRAW_INC);
|
||||
}
|
||||
|
||||
bool gslc_ElemXTextboxDraw(void* pvGui,void* pvElemRef,gslc_teRedrawType eRedraw)
|
||||
{
|
||||
if ((pvGui == NULL) || (pvElemRef == NULL)) {
|
||||
static const char GSLC_PMEM FUNCSTR[] = "ElemXTextboxDraw";
|
||||
GSLC_DEBUG2_PRINT_CONST(ERRSTR_NULL,FUNCSTR);
|
||||
return false;
|
||||
}
|
||||
// Typecast the parameters to match the GUI and element types
|
||||
gslc_tsGui* pGui = (gslc_tsGui*)(pvGui);
|
||||
gslc_tsElemRef* pElemRef = (gslc_tsElemRef*)(pvElemRef);
|
||||
gslc_tsElem* pElem = gslc_GetElemFromRef(pGui,pElemRef);
|
||||
gslc_tsColor colBg = GSLC_COL_BLACK;
|
||||
// Fetch the element's extended data structure
|
||||
gslc_tsXTextbox* pBox;
|
||||
pBox = (gslc_tsXTextbox*)(pElem->pXData);
|
||||
if (pBox == NULL) {
|
||||
GSLC_DEBUG2_PRINT("ERROR: ElemXTextboxDraw(%s) pXData is NULL\n","");
|
||||
return false;
|
||||
}
|
||||
|
||||
bool bGlow = (pElem->nFeatures & GSLC_ELEM_FEA_GLOW_EN) && gslc_ElemGetGlow(pGui,pElemRef);
|
||||
bool bFrameEn = (pElem->nFeatures & GSLC_ELEM_FEA_FRAME_EN);
|
||||
|
||||
// Draw the frame
|
||||
if (eRedraw == GSLC_REDRAW_FULL) {
|
||||
if (bFrameEn) {
|
||||
gslc_DrawFrameRect(pGui,pElem->rElem,pElem->colElemFrame);
|
||||
}
|
||||
}
|
||||
|
||||
// Clear the background (inset from frame)
|
||||
// - Only do this if we need to redraw all rows
|
||||
if ((eRedraw == GSLC_REDRAW_FULL) || (pBox->nRedrawRow == XTEXTBOX_REDRAW_ALL)) {
|
||||
gslc_tsRect rInner = gslc_ExpandRect(pElem->rElem, -1, -1);
|
||||
colBg = (bGlow) ? pElem->colElemFillGlow : pElem->colElemFill;
|
||||
gslc_DrawFillRect(pGui, rInner, colBg);
|
||||
}
|
||||
|
||||
uint16_t nBufPos = 0;
|
||||
|
||||
uint16_t nTxtPixX;
|
||||
uint16_t nTxtPixY;
|
||||
gslc_tsColor colTxt;
|
||||
//bool bEncUtf8;
|
||||
bool bRedrawLine;
|
||||
|
||||
// Determine what encoding method is used for text
|
||||
// Not used at the moment
|
||||
//bEncUtf8 = ((pElem->eTxtFlags & GSLC_TXT_ENC) == GSLC_TXT_ENC_UTF8);
|
||||
|
||||
// Initialize color state
|
||||
colTxt = pElem->colElemText;
|
||||
|
||||
// Calculate the starting row for the window
|
||||
uint16_t nWndRowStartScr = pBox->nWndRowStart;
|
||||
|
||||
// Only correct for scrollbar position if enabled
|
||||
if (pBox->bScrollEn) {
|
||||
nWndRowStartScr = (pBox->nWndRowStart + pBox->nScrollPos) % pBox->nBufRows;
|
||||
}
|
||||
|
||||
#if (GSLC_FEATURE_XTEXTBOX_EMBED == 0)
|
||||
|
||||
// Normal mode support (no embedded text color)
|
||||
// - This mode is much faster and is able to support UTF-8 text encoding
|
||||
|
||||
uint8_t nCurY = 0;
|
||||
|
||||
uint8_t nOutRow = 0;
|
||||
uint8_t nMaxRow = 0;
|
||||
|
||||
nMaxRow = (pBox->nBufRows < pBox->nWndRows)? pBox->nBufRows : pBox->nWndRows;
|
||||
for (nOutRow=0;nOutRow<nMaxRow;nOutRow++) {
|
||||
|
||||
bRedrawLine = true; // Default to drawing the row
|
||||
|
||||
// Calculate row offset after accounting for buffer wrap
|
||||
// and current window starting offset
|
||||
uint16_t nRowCur = nWndRowStartScr + nOutRow;
|
||||
nRowCur = nRowCur % pBox->nBufRows;
|
||||
|
||||
// If we are doing incremental redraw and only a single
|
||||
// row has been marked as requiring redraw, then skip
|
||||
// all other rows
|
||||
if (eRedraw == GSLC_REDRAW_INC) {
|
||||
if ((pBox->nRedrawRow >= 0) && (pBox->nRedrawRow != nRowCur)) {
|
||||
// Single-row redraw, but we are not on that row, so skip
|
||||
bRedrawLine = false;
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE: At the start of buffer fill where we have
|
||||
// only written a couple rows, we don't stop reading
|
||||
// across all of the rows. We are dependent upon
|
||||
// the reset to initialize all rows with NULL terminator
|
||||
// so that we don't show garbage.
|
||||
|
||||
if (bRedrawLine) {
|
||||
nBufPos = nRowCur * pBox->nBufCols;
|
||||
|
||||
nTxtPixX = pElem->rElem.x + pBox->nMarginX + 0 * pBox->nChSizeX;
|
||||
nTxtPixY = pElem->rElem.y + pBox->nMarginY + nCurY * pBox->nChSizeY;
|
||||
#if (DRV_OVERRIDE_TXT_ALIGN)
|
||||
gslc_DrvDrawTxtAlign(pGui,nTxtPixX,nTxtPixY,nTxtPixX,nTxtPixY,GSLC_ALIGN_TOP_LEFT,pElem->pTxtFont,
|
||||
(char*)&(pBox->pBuf[nBufPos]),pElem->eTxtFlags,colTxt,colBg);
|
||||
#else
|
||||
gslc_DrvDrawTxt(pGui, nTxtPixX, nTxtPixY, pElem->pTxtFont, (char*)&(pBox->pBuf[nBufPos]), pElem->eTxtFlags, colTxt, colBg);
|
||||
#endif
|
||||
}
|
||||
|
||||
nCurY++;
|
||||
} // nOutRow
|
||||
|
||||
#else
|
||||
|
||||
// Embedded color mode support
|
||||
// - This mode supports inline changing of text color
|
||||
// - However, it does not support UTF-8 character encoding
|
||||
// - It is also slower since rendering is per-character
|
||||
|
||||
enum {TBOX_NORM, TBOX_COL_SET};
|
||||
int16_t eTBoxState = TBOX_NORM;
|
||||
uint16_t nTBoxStateCnt = 0;
|
||||
|
||||
unsigned char chNext;
|
||||
uint8_t nCurX = 0;
|
||||
uint8_t nCurY = 0;
|
||||
|
||||
uint8_t nOutRow = 0;
|
||||
uint8_t nOutCol = 0;
|
||||
uint8_t nMaxCol = 0;
|
||||
uint8_t nMaxRow = 0;
|
||||
bool bRowDone = false;
|
||||
nMaxCol = (pBox->nBufCols < pBox->nWndCols)? pBox->nBufCols : pBox->nWndCols;
|
||||
nMaxRow = (pBox->nBufRows < pBox->nWndRows)? pBox->nBufRows : pBox->nWndRows;
|
||||
for (nOutRow=0;nOutRow<nMaxRow;nOutRow++) {
|
||||
|
||||
bRedrawLine = true; // Default to drawing the row
|
||||
|
||||
// Calculate row offset after accounting for buffer wrap
|
||||
// and current window starting offset
|
||||
uint16_t nRowCur = nWndRowStartScr + nOutRow;
|
||||
nRowCur = nRowCur % pBox->nBufRows;
|
||||
|
||||
// If we are doing incremental redraw and only a single
|
||||
// row has been marked as requiring redraw, then skip
|
||||
// all other rows
|
||||
if (eRedraw == GSLC_REDRAW_INC) {
|
||||
if ((pBox->nRedrawRow >= 0) && (pBox->nRedrawRow != nRowCur)) {
|
||||
// Single-row redraw, but we are not on that row, so skip
|
||||
bRedrawLine = false;
|
||||
}
|
||||
}
|
||||
|
||||
bRowDone = false;
|
||||
nCurX = 0;
|
||||
for (nOutCol=0;(!bRowDone)&&(bRedrawLine)&&(nOutCol<nMaxCol);nOutCol++) {
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// NOTE: At the start of buffer fill where we have
|
||||
// only written a couple rows, we don't stop reading
|
||||
// across all of the rows. We are dependent upon
|
||||
// the reset to initialize all rows with NULL terminator
|
||||
// so that we don't show garbage.
|
||||
|
||||
nBufPos = nRowCur * pBox->nBufCols + nOutCol;
|
||||
chNext = pBox->pBuf[nBufPos];
|
||||
|
||||
if (eTBoxState == TBOX_NORM) {
|
||||
if (chNext == 0) {
|
||||
// Reached early terminator
|
||||
bRowDone = true;
|
||||
continue;
|
||||
} else if (chNext == GSLC_XTEXTBOX_CODE_COL_SET) {
|
||||
// Set color (enter FSM)
|
||||
eTBoxState = TBOX_COL_SET;
|
||||
nTBoxStateCnt = 0;
|
||||
} else if (chNext == GSLC_XTEXTBOX_CODE_COL_RESET) {
|
||||
// Reset color
|
||||
colTxt = pElem->colElemText;
|
||||
} else {
|
||||
|
||||
// Render the character
|
||||
// TODO: Optimize by coalescing all characters in row before calling DrvDrawTxt
|
||||
// - Note that this would make it harder to change aspects (such as color)
|
||||
// in mid-line.
|
||||
char acChToDraw[2] = "";
|
||||
acChToDraw[0] = chNext;
|
||||
acChToDraw[1] = 0;
|
||||
nTxtPixX = pElem->rElem.x + pBox->nMarginX + nCurX * pBox->nChSizeX;
|
||||
nTxtPixY = pElem->rElem.y + pBox->nMarginY + nCurY * pBox->nChSizeY;
|
||||
#if (DRV_OVERRIDE_TXT_ALIGN)
|
||||
gslc_DrvDrawTxtAlign(pGui,nTxtPixX,nTxtPixY,nTxtPixX,nTxtPixY,GSLC_ALIGN_TOP_LEFT,pElem->pTxtFont,
|
||||
(char*)&acChToDraw,pElem->eTxtFlags,colTxt,colBg);
|
||||
#else
|
||||
gslc_DrvDrawTxt(pGui,nTxtPixX,nTxtPixY,pElem->pTxtFont,(char*)&acChToDraw,pElem->eTxtFlags,colTxt,colBg);
|
||||
#endif
|
||||
nCurX++;
|
||||
|
||||
}
|
||||
|
||||
} else if (eTBoxState == TBOX_COL_SET) {
|
||||
nTBoxStateCnt++;
|
||||
if (nTBoxStateCnt == 1) { colTxt.r = chNext; }
|
||||
else if (nTBoxStateCnt == 2) { colTxt.g = chNext; }
|
||||
else if (nTBoxStateCnt == 3) {
|
||||
colTxt.b = chNext;
|
||||
eTBoxState = TBOX_NORM;
|
||||
}
|
||||
} // eTBoxState
|
||||
|
||||
} // nOutCol
|
||||
nCurY++;
|
||||
} // nOutRow
|
||||
|
||||
#endif // GSLC_FEATURE_XTEXTBOX_EMBED
|
||||
|
||||
// Clear the redraw flag
|
||||
pBox->nRedrawRow = XTEXTBOX_REDRAW_NONE;
|
||||
gslc_ElemSetRedraw(pGui,pElemRef,GSLC_REDRAW_NONE);
|
||||
|
||||
// Mark page as needing flip
|
||||
gslc_PageFlipSet(pGui,true);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// ============================================================================
|
221
src/guislice/XTextbox.h
Normal file
221
src/guislice/XTextbox.h
Normal file
|
@ -0,0 +1,221 @@
|
|||
#ifndef _GUISLICE_EX_XTEXTBOX_H_
|
||||
#define _GUISLICE_EX_XTEXTBOX_H_
|
||||
|
||||
#include "GUIslice.h"
|
||||
|
||||
|
||||
// =======================================================================
|
||||
// GUIslice library extension: Textbox control
|
||||
// - Calvin Hass
|
||||
// - https://www.impulseadventure.com/elec/guislice-gui.html
|
||||
// - https://github.com/ImpulseAdventure/GUIslice
|
||||
// =======================================================================
|
||||
//
|
||||
// The MIT License
|
||||
//
|
||||
// Copyright 2016-2020 Calvin Hass
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
//
|
||||
// =======================================================================
|
||||
/// \file XTextbox.h
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif // __cplusplus
|
||||
|
||||
|
||||
|
||||
// ============================================================================
|
||||
// Extended Element: Textbox
|
||||
// ============================================================================
|
||||
|
||||
// Define unique identifier for extended element type
|
||||
// - Select any number above GSLC_TYPE_BASE_EXTEND
|
||||
#define GSLC_TYPEX_TEXTBOX GSLC_TYPE_BASE_EXTEND + 4
|
||||
|
||||
/// Definitions for textbox special inline codes
|
||||
#define GSLC_XTEXTBOX_CODE_COL_SET 187
|
||||
#define GSLC_XTEXTBOX_CODE_COL_RESET 188
|
||||
|
||||
#define XTEXTBOX_REDRAW_NONE -1
|
||||
#define XTEXTBOX_REDRAW_ALL -2
|
||||
|
||||
// Extended element data structures
|
||||
// - These data structures are maintained in the gslc_tsElem
|
||||
// structure via the pXData pointer
|
||||
|
||||
/// Extended data for Textbox element
|
||||
typedef struct {
|
||||
// Config
|
||||
char* pBuf; ///< Ptr to the text buffer (circular buffer))
|
||||
int8_t nMarginX; ///< Margin for text area within element rect (X)
|
||||
int8_t nMarginY; ///< Margin for text area within element rect (Y)
|
||||
bool bWrapEn; ///< Enable for line wrapping
|
||||
|
||||
uint16_t nBufRows; ///< Number of rows in buffer
|
||||
uint16_t nBufCols; ///< Number of columns in buffer
|
||||
bool bScrollEn; ///< Enable for scrollbar
|
||||
uint16_t nScrollPos; ///< Current scrollbar position
|
||||
|
||||
// Precalculated params
|
||||
uint8_t nChSizeX; ///< Width of characters (pixels)
|
||||
uint8_t nChSizeY; ///< Height of characters (pixels)
|
||||
uint8_t nWndCols; ///< Window X size
|
||||
uint8_t nWndRows; ///< Window Y size
|
||||
// Current status
|
||||
uint8_t nCurPosX; ///< Cursor X position
|
||||
uint8_t nCurPosY; ///< Cursor Y position
|
||||
uint8_t nBufPosX; ///< Buffer X position
|
||||
uint8_t nBufPosY; ///< Buffer Y position
|
||||
uint8_t nWndRowStart; ///< First row of current window
|
||||
// Redraw
|
||||
int16_t nRedrawRow; ///< Specific row to update in redraw (if not -1)
|
||||
|
||||
} gslc_tsXTextbox;
|
||||
|
||||
|
||||
|
||||
///
|
||||
/// Create a Textbox Element
|
||||
/// - The textbox is a scrolling window designed for displaying multi-line
|
||||
/// text using a monospaced font. A character buffer is defined by nBufRows*nBufCols
|
||||
/// to capture the added text. If the allocation buffer is larger than the
|
||||
/// display size (defined by rElem), then a scrollbar will be shown.
|
||||
/// - Support for changing color within a row can be enabled with GSLC_FEATURE_XTEXTBOX_EMBED 1
|
||||
/// - Note that each color change command will consume 4 of the available "column" bytes.
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] nElemId: Element ID to assign (0..16383 or GSLC_ID_AUTO to autogen)
|
||||
/// \param[in] nPage: Page ID to attach element to
|
||||
/// \param[in] pXData: Ptr to extended element data structure
|
||||
/// \param[in] rElem: Rectangle coordinates defining textbox size
|
||||
/// \param[in] nFontId: Font ID to use for text area
|
||||
/// \param[in] pBuf: Ptr to text buffer (already allocated)
|
||||
/// with size (nBufRows*nBufCols) chars
|
||||
/// \param[in] nBufRows: Number of rows in buffer
|
||||
/// \param[in] nBufCols: Number of columns in buffer (incl special codes)
|
||||
///
|
||||
/// \return Pointer to Element reference or NULL if failure
|
||||
///
|
||||
gslc_tsElemRef* gslc_ElemXTextboxCreate(gslc_tsGui* pGui,int16_t nElemId,int16_t nPage,
|
||||
gslc_tsXTextbox* pXData,gslc_tsRect rElem,int16_t nFontId,char* pBuf,
|
||||
uint16_t nBufRows,uint16_t nBufCols);
|
||||
|
||||
|
||||
/// Reset the contents of the textbox
|
||||
/// - Clears the buffer and resets the position
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] pElemRef: Pointer to Element reference
|
||||
///
|
||||
/// \return none
|
||||
///
|
||||
void gslc_ElemXTextboxReset(gslc_tsGui* pGui,gslc_tsElemRef* pElemRef);
|
||||
|
||||
|
||||
///
|
||||
/// Draw a Textbox element on the screen
|
||||
/// - Called from gslc_ElemDraw()
|
||||
///
|
||||
/// \param[in] pvGui: Void ptr to GUI (typecast to gslc_tsGui*)
|
||||
/// \param[in] pvElemRef: Void ptr to Element reference (typecast to gslc_tsElemRef*)
|
||||
/// \param[in] eRedraw: Redraw mode
|
||||
///
|
||||
/// \return true if success, false otherwise
|
||||
///
|
||||
bool gslc_ElemXTextboxDraw(void* pvGui,void* pvElemRef,gslc_teRedrawType eRedraw);
|
||||
|
||||
/// Add a text string to the textbox
|
||||
/// - If it includes a newline then the buffer will
|
||||
/// advance to the next row
|
||||
/// - If wrap has been enabled, then a newline will
|
||||
/// be forced
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] pElemRef: Pointer to Element reference
|
||||
/// \param[in] pTxt Pointer to text string (null-terminated)
|
||||
///
|
||||
/// \return none
|
||||
///
|
||||
void gslc_ElemXTextboxAdd(gslc_tsGui* pGui,gslc_tsElemRef* pElemRef,char* pTxt);
|
||||
|
||||
///
|
||||
/// Insert a color set code into the current buffer position
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] pElemRef: Pointer to Element reference
|
||||
/// \param[in] nCol: Color to assign for next text written to textbox
|
||||
///
|
||||
/// \return none
|
||||
///
|
||||
void gslc_ElemXTextboxColSet(gslc_tsGui* pGui,gslc_tsElemRef* pElemRef,gslc_tsColor nCol);
|
||||
|
||||
///
|
||||
/// Insert a color reset code into the current buffer position
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] pElemRef: Pointer to Element reference
|
||||
///
|
||||
/// \return none
|
||||
///
|
||||
void gslc_ElemXTextboxColReset(gslc_tsGui* pGui,gslc_tsElemRef* pElemRef);
|
||||
|
||||
///
|
||||
/// Enable or disable line wrap within textbox
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] pElemRef: Pointer to Element reference
|
||||
/// \param[in] bWrapEn: Enable line wrap if true
|
||||
///
|
||||
/// \return none
|
||||
///
|
||||
void gslc_ElemXTextboxWrapSet(gslc_tsGui* pGui,gslc_tsElemRef* pElemRef,bool bWrapEn);
|
||||
|
||||
|
||||
///
|
||||
/// Set the textbox scroll position (nScrollPos) as a fraction of
|
||||
/// nScrollMax
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] pElemRef: Pointer to Element reference
|
||||
/// \param[in] nScrollPos: New scroll position
|
||||
/// \param[in] nScrollMax: Maximum scroll position
|
||||
///
|
||||
/// \return none
|
||||
///
|
||||
void gslc_ElemXTextboxScrollSet(gslc_tsGui* pGui,gslc_tsElemRef* pElemRef,uint8_t nScrollPos,uint8_t nScrollMax);
|
||||
|
||||
|
||||
|
||||
|
||||
// ============================================================================
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Read-only element macros
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
// Macro initializers for Read-Only Elements in Flash/PROGMEM
|
||||
//
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif // __cplusplus
|
||||
#endif // _GUISLICE_EX_XTEXTBOX_H_
|
||||
|
453
src/guislice/XTogglebtn.c
Normal file
453
src/guislice/XTogglebtn.c
Normal file
|
@ -0,0 +1,453 @@
|
|||
// =======================================================================
|
||||
// GUIslice library extension: Toggle button control
|
||||
// - Paul Conti
|
||||
// - Toggle button with Android and iOS like styles
|
||||
// - Based on Calvin Hass' Checkbox control
|
||||
// - https://www.impulseadventure.com/elec/guislice-gui.html
|
||||
// - https://github.com/ImpulseAdventure/GUIslice
|
||||
// =======================================================================
|
||||
//
|
||||
// The MIT License
|
||||
//
|
||||
// Copyright 2016-2020 Calvin Hass and Paul Conti
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
//
|
||||
// =======================================================================
|
||||
/// \file XTogglebtn.c
|
||||
|
||||
|
||||
|
||||
// GUIslice library
|
||||
#include "GUIslice.h"
|
||||
#include "GUIslice_drv.h"
|
||||
|
||||
//#include "XTogglebtn.h"
|
||||
#include "XTogglebtn.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#if (GSLC_USE_PROGMEM)
|
||||
#include <avr/pgmspace.h>
|
||||
#endif
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Error Messages
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
extern const char GSLC_PMEM ERRSTR_NULL[];
|
||||
extern const char GSLC_PMEM ERRSTR_PXD_NULL[];
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Extended element definitions
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// - This file extends the core GUIslice functionality with
|
||||
// additional widget types
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
// ============================================================================
|
||||
// Extended Element: Togglebtn
|
||||
// - Togglebtn
|
||||
// Acts much like a checkbox but with styles that are similar to iOS and
|
||||
// Android slider buttons.
|
||||
// ============================================================================
|
||||
|
||||
// Create a togglebtn element and add it to the GUI element list
|
||||
gslc_tsElemRef* gslc_ElemXTogglebtnCreate(gslc_tsGui* pGui,int16_t nElemId,int16_t nPage,
|
||||
gslc_tsXTogglebtn* pXData,gslc_tsRect rElem,
|
||||
gslc_tsColor colThumb,gslc_tsColor colOnState,gslc_tsColor colOffState,
|
||||
bool bCircular,bool bChecked,GSLC_CB_TOUCH cbTouch)
|
||||
{
|
||||
if ((pGui == NULL) || (pXData == NULL)) {
|
||||
static const char GSLC_PMEM FUNCSTR[] = "ElemXTogglebtnCreate";
|
||||
GSLC_DEBUG2_PRINT_CONST(ERRSTR_NULL,FUNCSTR);
|
||||
return NULL;
|
||||
}
|
||||
gslc_tsElem sElem;
|
||||
gslc_tsElemRef* pElemRef = NULL;
|
||||
sElem = gslc_ElemCreate(pGui,nElemId,nPage,GSLC_TYPEX_TOGGLEBTN,rElem,NULL,0,GSLC_FONT_NONE);
|
||||
sElem.nFeatures |= GSLC_ELEM_FEA_FRAME_EN;
|
||||
sElem.nFeatures |= GSLC_ELEM_FEA_FILL_EN;
|
||||
sElem.nFeatures |= GSLC_ELEM_FEA_CLICK_EN;
|
||||
sElem.nFeatures |= GSLC_ELEM_FEA_GLOW_EN;
|
||||
|
||||
// Define other extended data
|
||||
sElem.pXData = (void*)(pXData);
|
||||
pXData->bOn = bChecked; // save on/off status
|
||||
pXData->pfunctUser = cbTouch; // save user's callback in our extra data
|
||||
pXData->nMyPageId = nPage; // save our page id for group by access later, if needed.
|
||||
pXData->colThumb = colThumb; // save thumb color
|
||||
pXData->colOnState = colOnState; // save on color
|
||||
pXData->colOffState = colOffState; // save off color
|
||||
pXData->bCircular = bCircular; // save button style
|
||||
|
||||
// Specify the custom drawing callback
|
||||
sElem.pfuncXDraw = &gslc_ElemXTogglebtnDraw;
|
||||
|
||||
// Specify the custom touch handler
|
||||
sElem.pfuncXTouch = &gslc_ElemXTogglebtnTouch;
|
||||
sElem.colElemFill = GSLC_COL_BLACK;
|
||||
sElem.colElemFillGlow = GSLC_COL_BLACK;
|
||||
sElem.colElemFrame = GSLC_COL_GRAY;
|
||||
sElem.colElemFrameGlow = GSLC_COL_WHITE;
|
||||
|
||||
if (nPage != GSLC_PAGE_NONE) {
|
||||
pElemRef = gslc_ElemAdd(pGui,nPage,&sElem,GSLC_ELEMREF_DEFAULT);
|
||||
return pElemRef;
|
||||
#if (GSLC_FEATURE_COMPOUND)
|
||||
} else {
|
||||
// Save as temporary element
|
||||
pGui->sElemTmp = sElem;
|
||||
pGui->sElemRefTmp.pElem = &(pGui->sElemTmp);
|
||||
pGui->sElemRefTmp.eElemFlags = GSLC_ELEMREF_DEFAULT | GSLC_ELEMREF_REDRAW_FULL;
|
||||
return &(pGui->sElemRefTmp);
|
||||
#endif
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool gslc_ElemXTogglebtnGetState(gslc_tsGui* pGui,gslc_tsElemRef* pElemRef)
|
||||
{
|
||||
gslc_tsXTogglebtn* pTogglebtn = (gslc_tsXTogglebtn*)gslc_GetXDataFromRef(pGui, pElemRef, GSLC_TYPEX_TOGGLEBTN, __LINE__);
|
||||
if (!pTogglebtn) return false;
|
||||
|
||||
return pTogglebtn->bOn;
|
||||
}
|
||||
|
||||
// Helper routine for gslc_ElemXTogglebtnSetState()
|
||||
// - Updates the togglebtn control's state but does
|
||||
// not touch any other controls in the group
|
||||
void gslc_ElemXTogglebtnSetStateHelp(gslc_tsGui* pGui,gslc_tsElemRef* pElemRef,bool bOn)
|
||||
{
|
||||
gslc_tsXTogglebtn* pTogglebtn = (gslc_tsXTogglebtn*)gslc_GetXDataFromRef(pGui, pElemRef, GSLC_TYPEX_TOGGLEBTN, __LINE__);
|
||||
if (!pTogglebtn) return;
|
||||
|
||||
// Update our data element
|
||||
bool bStateOld = pTogglebtn->bOn;
|
||||
pTogglebtn->bOn = bOn;
|
||||
|
||||
// Element needs redraw
|
||||
if (bOn != bStateOld) {
|
||||
// Only need an incremental redraw
|
||||
gslc_ElemSetRedraw(pGui,pElemRef,GSLC_REDRAW_INC);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Update the togglebtn control's state. If it's part of a group
|
||||
// then also update the state of all other buttons in the group.
|
||||
void gslc_ElemXTogglebtnSetState(gslc_tsGui* pGui,gslc_tsElemRef* pElemRef,bool bOn)
|
||||
{
|
||||
gslc_tsXTogglebtn* pTogglebtn = (gslc_tsXTogglebtn*)gslc_GetXDataFromRef(pGui, pElemRef, GSLC_TYPEX_TOGGLEBTN, __LINE__);
|
||||
if (!pTogglebtn) return;
|
||||
|
||||
gslc_tsElem* pElem = gslc_GetElemFromRef(pGui,pElemRef);
|
||||
|
||||
int16_t nGroup = pElem->nGroup;
|
||||
int16_t nElemId = pElem->nId;
|
||||
|
||||
if (bOn && pElem->nGroup != GSLC_GROUP_ID_NONE) {
|
||||
|
||||
// If we are selecting a button that is already
|
||||
// selected, then skip further update events.
|
||||
// NOTE: This check is not very efficient, but it avoids
|
||||
// the creation of extra events.
|
||||
gslc_tsElemRef* pTmpRef = gslc_ElemXTogglebtnFindSelected(pGui, nGroup);
|
||||
if (pTmpRef == pElemRef) {
|
||||
// Same element, so skip
|
||||
return;
|
||||
}
|
||||
|
||||
// Proceed to deselect any other selected items in the group.
|
||||
// Note that SetState calls itself to deselect other items so it
|
||||
// is important to qualify this logic with bOn=true
|
||||
int16_t nCurInd;
|
||||
int16_t nCurId;
|
||||
gslc_tsElem* pCurElem = NULL;
|
||||
gslc_tsElemRef* pCurElemRef = NULL;
|
||||
int16_t nCurGroup;
|
||||
|
||||
/*
|
||||
* The elements must be grouped on the same layer but do not need to be on the current
|
||||
* page. This allows us to place grouped elements on the base page.
|
||||
* p conti.
|
||||
*/
|
||||
// Find our page layer
|
||||
gslc_tsPage* pPage = gslc_PageFindById(pGui, pTogglebtn->nMyPageId);
|
||||
if (pPage == NULL) {
|
||||
GSLC_DEBUG2_PRINT("ERROR: gslc_ElemXTogglebtnSetState() can't find page (ID=%d)\n",
|
||||
pTogglebtn->nMyPageId);
|
||||
return;
|
||||
}
|
||||
|
||||
gslc_tsCollect* pCollect = &pPage->sCollect;
|
||||
for (nCurInd=0;nCurInd<pCollect->nElemRefCnt;nCurInd++) {
|
||||
// Fetch extended data
|
||||
pCurElemRef = &pCollect->asElemRef[nCurInd];
|
||||
pCurElem = gslc_GetElemFromRef(pGui,pCurElemRef);
|
||||
|
||||
// NOTE: Sorry but I have no idea what this FIXME is talking about - p conti
|
||||
// FIXME: Handle pCurElemRef->eElemFlags
|
||||
nCurId = pCurElem->nId;
|
||||
|
||||
nCurGroup = pCurElem->nGroup;
|
||||
|
||||
// If this is in a different group, ignore it
|
||||
if (nCurGroup != nGroup) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Is this our element? If so, ignore the deselect operation
|
||||
if (nCurId == nElemId) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Deselect all other elements
|
||||
gslc_ElemSetGlow(pGui,pCurElemRef,false); // trurn off glow state
|
||||
gslc_ElemXTogglebtnSetStateHelp(pGui,pCurElemRef,false);
|
||||
|
||||
} // nInd
|
||||
|
||||
} // bOn
|
||||
|
||||
// Set the state of the current element
|
||||
gslc_ElemXTogglebtnSetStateHelp(pGui,pElemRef,bOn);
|
||||
}
|
||||
|
||||
// Toggle the togglebtn control's state
|
||||
void gslc_ElemXTogglebtnToggleState(gslc_tsGui* pGui,gslc_tsElemRef* pElemRef)
|
||||
{
|
||||
if (pElemRef == NULL) {
|
||||
static const char GSLC_PMEM FUNCSTR[] = "ElemXTogglebtnToggleState";
|
||||
GSLC_DEBUG2_PRINT_CONST(ERRSTR_NULL,FUNCSTR);
|
||||
return;
|
||||
}
|
||||
// Toggle the data element value
|
||||
bool bStateNew = (gslc_ElemXTogglebtnGetState(pGui,pElemRef))? false : true;
|
||||
gslc_ElemXTogglebtnSetState(pGui,pElemRef,bStateNew);
|
||||
}
|
||||
|
||||
void gslc_ElemXTogglebtnDrawCircularHelp(gslc_tsGui* pGui,gslc_tsElem* pElem,gslc_tsXTogglebtn* pTogglebtn)
|
||||
{
|
||||
// frame enabled?
|
||||
bool bFrameEn = pElem->nFeatures & GSLC_ELEM_FEA_FRAME_EN;
|
||||
|
||||
// Work out the sizes of the inner rectangles
|
||||
gslc_tsRect rInner = gslc_ExpandRect(pElem->rElem,-1,-1);
|
||||
|
||||
// work out our circle positions
|
||||
uint16_t nRadius = rInner.h / 2;
|
||||
int16_t nLeftX = rInner.x + nRadius;
|
||||
int16_t nLeftY = rInner.y + nRadius;
|
||||
int16_t nRightX = rInner.x + pElem->rElem.w - nRadius -1;
|
||||
int16_t nRightY = rInner.y + nRadius;
|
||||
|
||||
if (pTogglebtn->bOn) {
|
||||
// draw our main body
|
||||
gslc_DrawFillRoundRect(pGui,rInner,rInner.h,pTogglebtn->colOnState);
|
||||
// place thumb on left-hand side
|
||||
gslc_DrawFillCircle(pGui,nLeftX,nLeftY,nRadius-1,pTogglebtn->colThumb);
|
||||
if (bFrameEn) {
|
||||
gslc_DrawFrameRoundRect(pGui,pElem->rElem,pElem->rElem.h,pElem->colElemFrame);
|
||||
gslc_DrawFrameCircle(pGui,nLeftX,nLeftY,nRadius,pElem->colElemFrame);
|
||||
}
|
||||
} else {
|
||||
// draw our main body
|
||||
gslc_DrawFillRoundRect(pGui,rInner,rInner.h,pTogglebtn->colOffState);
|
||||
// place thumb on right-hand side
|
||||
gslc_DrawFillCircle(pGui,nRightX,nRightY,nRadius-1,pTogglebtn->colThumb);
|
||||
if (bFrameEn) {
|
||||
gslc_DrawFrameRoundRect(pGui,pElem->rElem,pElem->rElem.h,pElem->colElemFrame);
|
||||
gslc_DrawFrameCircle(pGui,nRightX,nRightY,nRadius,pElem->colElemFrame);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void gslc_ElemXTogglebtnDrawRectangularHelp(gslc_tsGui* pGui,gslc_tsElem* pElem,gslc_tsXTogglebtn* pTogglebtn)
|
||||
{
|
||||
// frame enabled?
|
||||
bool bFrameEn = pElem->nFeatures & GSLC_ELEM_FEA_FRAME_EN;
|
||||
|
||||
// Work out the sizes of the inner rectangles
|
||||
gslc_tsRect rSquare = {
|
||||
pElem->rElem.x,
|
||||
pElem->rElem.y,
|
||||
pElem->rElem.h, // force a square
|
||||
pElem->rElem.h
|
||||
};
|
||||
gslc_tsRect rInner = gslc_ExpandRect(pElem->rElem,-1,-1);
|
||||
|
||||
if (pTogglebtn->bOn) {
|
||||
gslc_DrawFillRect(pGui,rInner,pTogglebtn->colOnState);
|
||||
// place thumb on left-hand side
|
||||
gslc_DrawFillRect(pGui,rSquare,pTogglebtn->colThumb);
|
||||
if (bFrameEn) {
|
||||
gslc_DrawFrameRect(pGui,pElem->rElem,pElem->colElemFrame);
|
||||
gslc_DrawFrameRect(pGui,rSquare,pElem->colElemFrame);
|
||||
}
|
||||
} else {
|
||||
gslc_DrawFillRect(pGui,rInner,pTogglebtn->colOffState);
|
||||
// place thumb on right-hand side
|
||||
rSquare.x = rInner.x + rInner.w - rInner.h - 1;
|
||||
gslc_DrawFillRect(pGui,rSquare,pTogglebtn->colThumb);
|
||||
if (bFrameEn) {
|
||||
gslc_DrawFrameRect(pGui,pElem->rElem,pElem->colElemFrame);
|
||||
gslc_DrawFrameRect(pGui,rSquare,pElem->colElemFrame);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Redraw the togglebtn
|
||||
// - Note that this redraw is for the entire element rect region
|
||||
// - The Draw function parameters use void pointers to allow for
|
||||
// simpler callback function definition & scalability.
|
||||
|
||||
bool gslc_ElemXTogglebtnDraw(void* pvGui,void* pvElemRef,gslc_teRedrawType eRedraw)
|
||||
{
|
||||
// Typecast the parameters to match the GUI and element types
|
||||
gslc_tsGui* pGui = (gslc_tsGui*)(pvGui);
|
||||
gslc_tsElemRef* pElemRef = (gslc_tsElemRef*)(pvElemRef);
|
||||
|
||||
gslc_tsXTogglebtn* pTogglebtn = (gslc_tsXTogglebtn*)gslc_GetXDataFromRef(pGui, pElemRef, GSLC_TYPEX_TOGGLEBTN, __LINE__);
|
||||
if (!pTogglebtn) {
|
||||
GSLC_DEBUG_PRINT("ERROR: gslc_ElemXTogglebtnDraw(%s) pXData is NULL\n","");
|
||||
return false;
|
||||
}
|
||||
|
||||
gslc_tsElem* pElem = gslc_GetElemFromRef(pGui,pElemRef);
|
||||
|
||||
if (pTogglebtn->bCircular) {
|
||||
gslc_ElemXTogglebtnDrawCircularHelp(pGui, pElem, pTogglebtn);
|
||||
} else {
|
||||
gslc_ElemXTogglebtnDrawRectangularHelp(pGui, pElem, pTogglebtn);
|
||||
}
|
||||
|
||||
// Clear the redraw flag
|
||||
gslc_ElemSetRedraw(pGui,pElemRef,GSLC_REDRAW_NONE);
|
||||
|
||||
// Mark page as needing flip
|
||||
gslc_PageFlipSet(pGui,true);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// This callback function is called by gslc_ElemSendEventTouch()
|
||||
// after any touch event
|
||||
// - NOTE: Adding this touch callback is optional. Without it, we
|
||||
// can still have a functional togglebtn, but doing the touch
|
||||
// tracking allows us to change the glow state of the element
|
||||
// dynamically, as well as updating the togglebtn state if the
|
||||
// user releases over it (ie. a click event).
|
||||
//
|
||||
bool gslc_ElemXTogglebtnTouch(void* pvGui,void* pvElemRef,gslc_teTouch eTouch,int16_t nRelX,int16_t nRelY)
|
||||
{
|
||||
#if defined(DRV_TOUCH_NONE)
|
||||
return false;
|
||||
#else
|
||||
|
||||
// Typecast the parameters to match the GUI and element types
|
||||
gslc_tsGui* pGui = (gslc_tsGui*)(pvGui);
|
||||
gslc_tsElemRef* pElemRef = (gslc_tsElemRef*)(pvElemRef);
|
||||
|
||||
gslc_tsXTogglebtn* pTogglebtn = (gslc_tsXTogglebtn*)gslc_GetXDataFromRef(pGui, pElemRef, GSLC_TYPEX_TOGGLEBTN, __LINE__);
|
||||
if (!pTogglebtn) return false;
|
||||
|
||||
//gslc_tsElem* pElem = gslc_GetElemFromRef(pGui,pElemRef);
|
||||
bool bStateOld = pTogglebtn->bOn;
|
||||
|
||||
switch(eTouch) {
|
||||
|
||||
case GSLC_TOUCH_UP_IN:
|
||||
// Now that we released on element, update the state
|
||||
// Togglebtn button action: toggle
|
||||
gslc_ElemXTogglebtnToggleState(pGui,pElemRef);
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
|
||||
// If the togglebtn changed state, redraw and notify user
|
||||
if (pTogglebtn->bOn != bStateOld) {
|
||||
// Now send the callback notification
|
||||
(*pTogglebtn->pfunctUser)((void*)(pGui), (void*)(pElemRef), eTouch, nRelX, nRelY);
|
||||
// Incremental redraw
|
||||
gslc_ElemSetRedraw(pGui,pElemRef,GSLC_REDRAW_INC);
|
||||
}
|
||||
|
||||
return true;
|
||||
#endif // !DRV_TOUCH_NONE
|
||||
}
|
||||
|
||||
// Determine which togglebtn in the group is selected "on"
|
||||
gslc_tsElemRef* gslc_ElemXTogglebtnFindSelected(gslc_tsGui* pGui,int16_t nGroupId)
|
||||
{
|
||||
int16_t nCurInd;
|
||||
gslc_tsElemRef* pCurElemRef = NULL;
|
||||
gslc_tsElem* pCurElem = NULL;
|
||||
int16_t nCurType;
|
||||
int16_t nCurGroup;
|
||||
bool bCurSelected;
|
||||
gslc_tsElemRef* pFoundElemRef = NULL;
|
||||
|
||||
// Operate on current page
|
||||
// TODO: Support other page layers
|
||||
gslc_tsPage* pPage = pGui->apPageStack[GSLC_STACK_CUR];
|
||||
if (pPage == NULL) {
|
||||
return NULL; // No page added yet
|
||||
}
|
||||
|
||||
if (pGui == NULL) {
|
||||
static const char GSLC_PMEM FUNCSTR[] = "ElemXTogglebtnFindChecked";
|
||||
GSLC_DEBUG2_PRINT_CONST(ERRSTR_NULL,FUNCSTR);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
gslc_tsCollect* pCollect = &pPage->sCollect;
|
||||
for (nCurInd=0;nCurInd<pCollect->nElemCnt;nCurInd++) {
|
||||
// Fetch extended data
|
||||
pCurElemRef = &(pCollect->asElemRef[nCurInd]);
|
||||
pCurElem = gslc_GetElemFromRef(pGui,pCurElemRef);
|
||||
nCurType = pCurElem->nType;
|
||||
// Only want to proceed if it is a togglebtn
|
||||
if (nCurType != GSLC_TYPEX_TOGGLEBTN) {
|
||||
continue;
|
||||
}
|
||||
|
||||
nCurGroup = pCurElem->nGroup;
|
||||
bCurSelected = gslc_ElemXTogglebtnGetState(pGui,pCurElemRef);
|
||||
|
||||
// If this is in a different group, ignore it
|
||||
if (nCurGroup != nGroupId) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Did we find an element in the group that was checked?
|
||||
if (bCurSelected) {
|
||||
pFoundElemRef = pCurElemRef;
|
||||
break;
|
||||
}
|
||||
} // nCurInd
|
||||
return pFoundElemRef;
|
||||
}
|
||||
|
||||
// ============================================================================
|
282
src/guislice/XTogglebtn.h
Normal file
282
src/guislice/XTogglebtn.h
Normal file
|
@ -0,0 +1,282 @@
|
|||
#ifndef _GUISLICE_EX_XTOGGLEBTN_H_
|
||||
#define _GUISLICE_EX_XTOGGLEBTN_H_
|
||||
|
||||
#include "GUIslice.h"
|
||||
|
||||
|
||||
// =======================================================================
|
||||
// GUIslice library extension: Toggle button control
|
||||
// - Paul Conti
|
||||
// - Toggle button with Android and iOS like styles
|
||||
// - Based on Calvin Hass' Checkbox control
|
||||
// - https://www.impulseadventure.com/elec/guislice-gui.html
|
||||
// - https://github.com/ImpulseAdventure/GUIslice
|
||||
// =======================================================================
|
||||
//
|
||||
// The MIT License
|
||||
//
|
||||
// Copyright 2016-2020 Calvin Hass and Paul Conti
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
//
|
||||
// =======================================================================
|
||||
/// \file XTogglebtn.h
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif // __cplusplus
|
||||
|
||||
// ============================================================================
|
||||
// Extended Element: Togglebtn
|
||||
// - Togglebtn
|
||||
// Acts much like a checkbox but with styles that are similar to iOS and
|
||||
// Android slider buttons.
|
||||
// ============================================================================
|
||||
|
||||
// Define unique identifier for extended element type
|
||||
// - Select any number above GSLC_TYPE_BASE_EXTEND
|
||||
#define GSLC_TYPEX_TOGGLEBTN GSLC_TYPE_BASE_EXTEND + 40
|
||||
|
||||
// Extended element data structures
|
||||
// - These data structures are maintained in the gslc_tsElem
|
||||
// structure via the pXData pointer
|
||||
|
||||
/// Extended data for Togglebtn element
|
||||
typedef struct {
|
||||
bool bOn; ///< Indicates if button is ON or OFF
|
||||
int16_t nMyPageId; ///< We need to track our page in case of grouping elements
|
||||
///< on a non current layer, like base layer
|
||||
gslc_tsColor colThumb; ///< Color of thumb
|
||||
gslc_tsColor colOnState; ///< Color of button in ON state
|
||||
gslc_tsColor colOffState; ///< Color of button in OFF state
|
||||
bool bCircular; ///< Style of the toggle button circular or rectangular
|
||||
GSLC_CB_TOUCH pfunctUser; ///< User's Callback event to say element has changed
|
||||
} gslc_tsXTogglebtn;
|
||||
|
||||
|
||||
///
|
||||
/// Create a Togglebtn button Element
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] nElemId: Element ID to assign (0..16383 or GSLC_ID_AUTO to autogen)
|
||||
/// \param[in] nPage: Page ID to attach element to
|
||||
/// \param[in] pXData: Ptr to extended element data structure
|
||||
/// \param[in] rElem: Rectangle coordinates defining togglebtn size
|
||||
/// \param[in] colThumb: Color of thumb
|
||||
/// \param[in] colOnState: Color to indicate on position
|
||||
/// \param[in] colOffState: Color to indicate off position
|
||||
/// \param[in] bCircular: Style of the toggle button circular or rectangular
|
||||
/// \param[in] bChecked: Default state
|
||||
/// \param[in] cbTouch: Callback for touch events
|
||||
///
|
||||
/// \return Pointer to Element reference or NULL if failure
|
||||
///
|
||||
gslc_tsElemRef* gslc_ElemXTogglebtnCreate(gslc_tsGui* pGui,int16_t nElemId,int16_t nPage,
|
||||
gslc_tsXTogglebtn* pXData,gslc_tsRect rElem,
|
||||
gslc_tsColor colThumb,gslc_tsColor colOnState,gslc_tsColor colOffState,
|
||||
bool bCircular,bool bChecked,GSLC_CB_TOUCH cbTouch);
|
||||
|
||||
|
||||
///
|
||||
/// Get a Togglebtn element's current state
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] pElemRef: Pointer to Element reference
|
||||
///
|
||||
/// \return Current state
|
||||
///
|
||||
bool gslc_ElemXTogglebtnGetState(gslc_tsGui* pGui,gslc_tsElemRef* pElemRef);
|
||||
|
||||
///
|
||||
/// Set a Togglebtn element's current state
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] pElemRef: Pointer to Element reference
|
||||
/// \param[in] bOn: New state
|
||||
///
|
||||
/// \return none
|
||||
///
|
||||
void gslc_ElemXTogglebtnSetState(gslc_tsGui* pGui,gslc_tsElemRef* pElemRef,bool bOn);
|
||||
|
||||
///
|
||||
/// Toggle a Togglebtn element's current state
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] pElemRef: Pointer to Element reference
|
||||
///
|
||||
/// \return none
|
||||
///
|
||||
void gslc_ElemXTogglebtnToggleState(gslc_tsGui* pGui,gslc_tsElemRef* pElemRef);
|
||||
|
||||
///
|
||||
/// Draw a Togglebtn element on the screen
|
||||
/// - Called from gslc_ElemDraw()
|
||||
///
|
||||
/// \param[in] pvGui: Void ptr to GUI (typecast to gslc_tsGui*)
|
||||
/// \param[in] pvElemRef: Void ptr to Element reference (typecast to gslc_tsElemRef*)
|
||||
/// \param[in] eRedraw: Redraw mode
|
||||
///
|
||||
/// \return true if success, false otherwise
|
||||
///
|
||||
bool gslc_ElemXTogglebtnDraw(void* pvGui,void* pvElemRef,gslc_teRedrawType eRedraw);
|
||||
|
||||
///
|
||||
/// Handle touch events to Togglebtn element
|
||||
/// - Called from gslc_ElemSendEventTouch()
|
||||
///
|
||||
/// \param[in] pvGui: Void ptr to GUI (typecast to gslc_tsGui*)
|
||||
/// \param[in] pvElemRef: Void ptr to Element reference (typecast to gslc_tsElemRef*)
|
||||
/// \param[in] eTouch: Touch event type
|
||||
/// \param[in] nRelX: Touch X coord relative to element
|
||||
/// \param[in] nRelY: Touch Y coord relative to element
|
||||
///
|
||||
/// \return true if success, false otherwise
|
||||
///
|
||||
bool gslc_ElemXTogglebtnTouch(void* pvGui,void* pvElemRef,gslc_teTouch eTouch,int16_t nRelX,int16_t nRelY);
|
||||
|
||||
///
|
||||
/// Find the togglebtn within a group that has been selected
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] nGroupId: Group ID to search
|
||||
///
|
||||
/// \return Element Ptr or NULL if none selected
|
||||
///
|
||||
gslc_tsElemRef* gslc_ElemXTogglebtnFindSelected(gslc_tsGui* pGui,int16_t nGroupId);
|
||||
|
||||
// ============================================================================
|
||||
// ------------------------------------------------------------------------
|
||||
// Read-only element macros
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
// Macro initializers for Read-Only Elements in Flash/PROGMEM
|
||||
//
|
||||
|
||||
|
||||
/// \def gslc_ElemXTogglebtnCreate_P(pGui,nElemId,nPage,nX,nY,nW,nH,nGroup,bRadio_,nStyle_,colCheck_,bChecked_)
|
||||
///
|
||||
/// Create a Togglebtn button Element
|
||||
///
|
||||
/// \param[in] pGui: Pointer to GUI
|
||||
/// \param[in] nElemId: Element ID to assign (0..16383 or GSLC_ID_AUTO to autogen)
|
||||
/// \param[in] nPage: Page ID to attach element to
|
||||
/// \param[in] nX: X coordinate of element
|
||||
/// \param[in] nY: Y coordinate of element
|
||||
/// \param[in] nW: Width of element
|
||||
/// \param[in] nH: Height of element
|
||||
/// \param[in] colThumb_: Color of thumb
|
||||
/// \param[in] colOnState_: Color to indicate on position
|
||||
/// \param[in] colOffState_: Color to indicate off position
|
||||
/// \param[in] bCircular_: Style of the toggle button circular or rectangular
|
||||
/// \param[in] bChecked_: Default state
|
||||
/// \param[in] cbTouch: Callback for touch events
|
||||
///
|
||||
/// \return none
|
||||
///
|
||||
|
||||
#if (GSLC_USE_PROGMEM)
|
||||
|
||||
#define gslc_ElemXTogglebtnCreate_P(pGui,nElemId,nPage,nX,nY,nW,nH,colThumb_,colOnState_,colOffState_,bCircular_,bChecked_,cbTouch) \
|
||||
static const uint8_t nFeatures##nElemId = GSLC_ELEM_FEA_VALID | \
|
||||
GSLC_ELEM_FEA_GLOW_EN | GSLC_ELEM_FEA_CLICK_EN | GSLC_ELEM_FEA_FILL_EN; \
|
||||
static gslc_tsXTogglebtn sTogglebtn##nElemId; \
|
||||
sTogglebtn##nElemId.bOn = bChecked_; \
|
||||
sTogglebtn##nElemId.nMyPageId = nPage; \
|
||||
sTogglebtn##nElemId.colThumb = colThumb_; \
|
||||
sTogglebtn##nElemId.colOnState = colOnState_; \
|
||||
sTogglebtn##nElemId.colOffState = colOffState_; \
|
||||
sTogglebtn##nElemId.bCircular = bCircular_; \
|
||||
sTogglebtn##nElemId.pfunctUser = cbTouch; \
|
||||
static const gslc_tsElem sElem##nElemId PROGMEM = { \
|
||||
nElemId, \
|
||||
nFeatures##nElemId, \
|
||||
GSLC_TYPEX_TOGGLEBTN, \
|
||||
(gslc_tsRect){nX,nY,nW,nH}, \
|
||||
0, \
|
||||
GSLC_COL_GRAY,GSLC_COL_BLACK,GSLC_COL_WHITE,GSLC_COL_BLACK, \
|
||||
(gslc_tsImgRef){NULL,NULL,GSLC_IMGREF_NONE,NULL}, \
|
||||
(gslc_tsImgRef){NULL,NULL,GSLC_IMGREF_NONE,NULL}, \
|
||||
NULL, \
|
||||
NULL, \
|
||||
0, \
|
||||
(gslc_teTxtFlags)(GSLC_TXT_DEFAULT), \
|
||||
GSLC_COL_WHITE, \
|
||||
GSLC_COL_WHITE, \
|
||||
GSLC_ALIGN_MID_MID, \
|
||||
0, \
|
||||
0, \
|
||||
NULL, \
|
||||
(void*)(&sTogglebtn##nElemId), \
|
||||
NULL, \
|
||||
&gslc_ElemXTogglebtnDraw, \
|
||||
&gslc_ElemXTogglebtnTouch, \
|
||||
NULL, \
|
||||
}; \
|
||||
gslc_ElemAdd(pGui,nPage,(gslc_tsElem*)&sElem##nElemId, \
|
||||
(gslc_teElemRefFlags)(GSLC_ELEMREF_SRC_PROG | GSLC_ELEMREF_VISIBLE | GSLC_ELEMREF_REDRAW_FULL));
|
||||
|
||||
|
||||
#else
|
||||
|
||||
#define gslc_ElemXTogglebtnCreate_P(pGui,nElemId,nPage,nX,nY,nW,nH,colThumb_,colOnState_,colOffState_,bCircular_,bChecked_,cbTouch) \
|
||||
static const uint8_t nFeatures##nElemId = GSLC_ELEM_FEA_VALID | \
|
||||
GSLC_ELEM_FEA_GLOW_EN | GSLC_ELEM_FEA_CLICK_EN | GSLC_ELEM_FEA_FILL_EN; \
|
||||
static gslc_tsXTogglebtn sTogglebtn##nElemId; \
|
||||
sTogglebtn##nElemId.bOn = bChecked_; \
|
||||
sTogglebtn##nElemId.nMyPageId = nPage; \
|
||||
sTogglebtn##nElemId.colThumb = colThumb_; \
|
||||
sTogglebtn##nElemId.colOnState = colOnState_; \
|
||||
sTogglebtn##nElemId.colOffState = colOffState_; \
|
||||
sTogglebtn##nElemId.bCircular = bCircular_; \
|
||||
sTogglebtn##nElemId.pfunctUser = cbTouch; \
|
||||
static const gslc_tsElem sElem##nElemId = { \
|
||||
nElemId, \
|
||||
nFeatures##nElemId, \
|
||||
GSLC_TYPEX_TOGGLEBTN, \
|
||||
(gslc_tsRect){nX,nY,nW,nH}, \
|
||||
0, \
|
||||
GSLC_COL_GRAY,GSLC_COL_BLACK,GSLC_COL_WHITE,GSLC_COL_BLACK, \
|
||||
(gslc_tsImgRef){NULL,NULL,GSLC_IMGREF_NONE,NULL}, \
|
||||
(gslc_tsImgRef){NULL,NULL,GSLC_IMGREF_NONE,NULL}, \
|
||||
NULL, \
|
||||
NULL, \
|
||||
0, \
|
||||
(gslc_teTxtFlags)(GSLC_TXT_DEFAULT), \
|
||||
GSLC_COL_WHITE, \
|
||||
GSLC_COL_WHITE, \
|
||||
GSLC_ALIGN_MID_MID, \
|
||||
0, \
|
||||
0, \
|
||||
NULL, \
|
||||
(void*)(&sTogglebtn##nElemId), \
|
||||
NULL, \
|
||||
&gslc_ElemXTogglebtnDraw, \
|
||||
&gslc_ElemXTogglebtnTouch, \
|
||||
NULL, \
|
||||
}; \
|
||||
gslc_ElemAdd(pGui,nPage,(gslc_tsElem*)&sElem##nElemId, \
|
||||
(gslc_teElemRefFlags)(GSLC_ELEMREF_SRC_PROG | GSLC_ELEMREF_VISIBLE | GSLC_ELEMREF_REDRAW_FULL));
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif // __cplusplus
|
||||
#endif // _GUISLICE_EX_XTOGGLEBTN_H_
|
207
src/guislice/ard-adagfx-ili9341-notouch.h
Normal file
207
src/guislice/ard-adagfx-ili9341-notouch.h
Normal file
|
@ -0,0 +1,207 @@
|
|||
#ifndef _GUISLICE_CONFIG_ARD_H_
|
||||
#define _GUISLICE_CONFIG_ARD_H_
|
||||
|
||||
// =============================================================================
|
||||
// GUIslice library (example user configuration) for:
|
||||
// - CPU: Arduino UNO / MEGA / etc
|
||||
// - Display: ILI9341
|
||||
// - Touch: None
|
||||
// - Wiring: Custom breakout
|
||||
// - Pinout:
|
||||
//
|
||||
// - Example display:
|
||||
// -
|
||||
//
|
||||
// DIRECTIONS:
|
||||
// - To use this example configuration, include in "GUIslice_config.h"
|
||||
//
|
||||
// WIRING:
|
||||
// - As this config file is designed for a breakout board, customization
|
||||
// of the Pinout in SECTION 2 will be required to match your display.
|
||||
//
|
||||
// =============================================================================
|
||||
// - Calvin Hass
|
||||
// - https://github.com/ImpulseAdventure/GUIslice
|
||||
// =============================================================================
|
||||
//
|
||||
// The MIT License
|
||||
//
|
||||
// Copyright 2016-2020 Calvin Hass
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
//
|
||||
// =============================================================================
|
||||
// \file GUIslice_config_ard.h
|
||||
|
||||
// =============================================================================
|
||||
// User Configuration
|
||||
// - This file can be modified by the user to match the
|
||||
// intended target configuration
|
||||
// =============================================================================
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif // __cplusplus
|
||||
|
||||
|
||||
// =============================================================================
|
||||
// USER DEFINED CONFIGURATION
|
||||
// =============================================================================
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// SECTION 1: Device Mode Selection
|
||||
// - The following defines the display and touch drivers
|
||||
// and should not require modifications for this example config
|
||||
// -----------------------------------------------------------------------------
|
||||
#define DRV_DISP_ADAGFX // Adafruit-GFX library
|
||||
#define DRV_DISP_ADAGFX_ILI9341 // Adafruit ILI9341
|
||||
#define DRV_TOUCH_NONE // No touch enabled
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// SECTION 2: Pinout
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
// For shields, the following pinouts are typically hardcoded
|
||||
#define ADAGFX_PIN_CS 9 // Display chip select
|
||||
#define ADAGFX_PIN_DC 10 // Display SPI data/command
|
||||
#define ADAGFX_PIN_RST 0 // Display Reset
|
||||
|
||||
// Display interface type
|
||||
#define ADAGFX_SPI_HW 1 // Display uses SPI interface: 1=hardware 0=software
|
||||
|
||||
// Display interface software SPI
|
||||
// - Hardware SPI: the following definitions are unused
|
||||
// - Software SPI: the following pins need to be defined
|
||||
#define ADAGFX_PIN_MOSI 11
|
||||
#define ADAGFX_PIN_MISO 12
|
||||
#define ADAGFX_PIN_CLK 13
|
||||
|
||||
// SD Card
|
||||
#define ADAGFX_PIN_SDCS 5 // SD card chip select (if GSLC_SD_EN=1)
|
||||
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// SECTION 3: Orientation
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
// Set Default rotation of the display
|
||||
// - Values 0,1,2,3. Rotation is clockwise
|
||||
#define GSLC_ROTATE 1
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// SECTION 5: Diagnostics
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
// Error reporting
|
||||
// - Set DEBUG_ERR to >0 to enable error reporting via the Serial connection
|
||||
// - Enabling DEBUG_ERR increases FLASH memory consumption which may be
|
||||
// limited on the baseline Arduino (ATmega328P) devices.
|
||||
// - DEBUG_ERR 0 = Disable all error messaging
|
||||
// - DEBUG_ERR 1 = Enable critical error messaging (eg. init)
|
||||
// - DEBUG_ERR 2 = Enable verbose error messaging (eg. bad parameters, etc.)
|
||||
// - For baseline Arduino UNO, recommended to disable this after one has
|
||||
// confirmed basic operation of the library is successful.
|
||||
#define DEBUG_ERR 1 // 1,2 to enable, 0 to disable
|
||||
|
||||
// Debug initialization message
|
||||
// - By default, GUIslice outputs a message in DEBUG_ERR mode
|
||||
// to indicate the initialization status, even during success.
|
||||
// - To disable the messages during successful initialization,
|
||||
// uncomment the following line.
|
||||
//#define INIT_MSG_DISABLE
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// SECTION 6: Optional Features
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
// Enable of optional features
|
||||
// - For memory constrained devices such as Arduino, it is best to
|
||||
// set the following features to 0 (to disable) unless they are
|
||||
// required.
|
||||
#define GSLC_FEATURE_COMPOUND 1 // Compound elements (eg. XSelNum)
|
||||
#define GSLC_FEATURE_XTEXTBOX_EMBED 1 // XTextbox control with embedded color
|
||||
#define GSLC_FEATURE_INPUT 1 // Keyboard / GPIO input control
|
||||
|
||||
// Enable support for SD card
|
||||
// - Set to 1 to enable, 0 to disable
|
||||
// - Note that the inclusion of the SD library consumes considerable
|
||||
// RAM and flash memory which could be problematic for Arduino models
|
||||
// with limited resources.
|
||||
#define GSLC_SD_EN 0
|
||||
|
||||
|
||||
// =============================================================================
|
||||
// SECTION 10: INTERNAL CONFIGURATION
|
||||
// - The following settings should not require modification by users
|
||||
// =============================================================================
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Touch Handling
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
// Define the maximum number of touch events that are handled
|
||||
// per gslc_Update() call. Normally this can be set to 1 but certain
|
||||
// displays may require a greater value (eg. 30) in order to increase
|
||||
// responsiveness of the touch functionality.
|
||||
#define GSLC_TOUCH_MAX_EVT 1
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Misc
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
// Define buffer size for loading images from SD
|
||||
// - A larger buffer will be faster but at the cost of RAM
|
||||
#define GSLC_SD_BUFFPIXEL 50
|
||||
|
||||
// Enable support for graphics clipping (DrvSetClipRect)
|
||||
// - Note that this will impact performance of drawing graphics primitives
|
||||
#define GSLC_CLIP_EN 1
|
||||
|
||||
// Enable for bitmap transparency and definition of color to use
|
||||
#define GSLC_BMP_TRANS_EN 1 // 1 = enabled, 0 = disabled
|
||||
#define GSLC_BMP_TRANS_RGB 0xFF,0x00,0xFF // RGB color (default: MAGENTA)
|
||||
|
||||
#define GSLC_USE_FLOAT 1 // 1=Use floating pt library, 0=Fixed-point lookup tables
|
||||
|
||||
#define GSLC_DEV_TOUCH ""
|
||||
#define GSLC_USE_PROGMEM 0
|
||||
|
||||
#define GSLC_LOCAL_STR 1 // 1=Use local strings (in element array), 0=External
|
||||
#define GSLC_LOCAL_STR_LEN 30 // Max string length of text elements
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Debug diagnostic modes
|
||||
// -----------------------------------------------------------------------------
|
||||
// - Uncomment any of the following to enable specific debug modes
|
||||
//#define DBG_LOG // Enable debugging log output
|
||||
//#define DBG_TOUCH // Enable debugging of touch-presses
|
||||
//#define DBG_FRAME_RATE // Enable diagnostic frame rate reporting
|
||||
//#define DBG_DRAW_IMM // Enable immediate rendering of drawing primitives
|
||||
//#define DBG_DRIVER // Enable graphics driver debug reporting
|
||||
|
||||
|
||||
// =============================================================================
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif // __cplusplus
|
||||
#endif // _GUISLICE_CONFIG_ARD_H_
|
246
src/guislice/ard-adagfx-ili9341-stmpe610.h
Normal file
246
src/guislice/ard-adagfx-ili9341-stmpe610.h
Normal file
|
@ -0,0 +1,246 @@
|
|||
#ifndef _GUISLICE_CONFIG_ARD_H_
|
||||
#define _GUISLICE_CONFIG_ARD_H_
|
||||
|
||||
// =============================================================================
|
||||
// GUIslice library (example user configuration) for:
|
||||
// - CPU: Arduino UNO / MEGA / etc
|
||||
// - Display: ILI9341
|
||||
// - Touch: STMPE610 (Resistive)
|
||||
// - Wiring: Custom breakout
|
||||
// - Pinout:
|
||||
//
|
||||
// - Example display:
|
||||
// - Adafruit 2.8" TFT LCD Shield w/ Touchscreen (resistive)
|
||||
//
|
||||
// DIRECTIONS:
|
||||
// - To use this example configuration, include in "GUIslice_config.h"
|
||||
//
|
||||
// WIRING:
|
||||
// - As this config file is designed for a breakout board, customization
|
||||
// of the Pinout in SECTION 2 will be required to match your display.
|
||||
//
|
||||
// =============================================================================
|
||||
// - Calvin Hass
|
||||
// - https://github.com/ImpulseAdventure/GUIslice
|
||||
// =============================================================================
|
||||
//
|
||||
// The MIT License
|
||||
//
|
||||
// Copyright 2016-2020 Calvin Hass
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
//
|
||||
// =============================================================================
|
||||
// \file GUIslice_config_ard.h
|
||||
|
||||
// =============================================================================
|
||||
// User Configuration
|
||||
// - This file can be modified by the user to match the
|
||||
// intended target configuration
|
||||
// =============================================================================
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif // __cplusplus
|
||||
|
||||
|
||||
// =============================================================================
|
||||
// USER DEFINED CONFIGURATION
|
||||
// =============================================================================
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// SECTION 1: Device Mode Selection
|
||||
// - The following defines the display and touch drivers
|
||||
// and should not require modifications for this example config
|
||||
// -----------------------------------------------------------------------------
|
||||
#define DRV_DISP_ADAGFX // Adafruit-GFX library
|
||||
#define DRV_DISP_ADAGFX_ILI9341 // Adafruit ILI9341
|
||||
#define DRV_TOUCH_ADA_STMPE610 // Adafruit STMPE610 touch driver
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// SECTION 2: Pinout
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
// For shields, the following pinouts are typically hardcoded
|
||||
#define ADAGFX_PIN_CS 9 // Display chip select
|
||||
#define ADAGFX_PIN_DC 10 // Display SPI data/command
|
||||
#define ADAGFX_PIN_RST 0 // Display Reset
|
||||
|
||||
// Display interface type
|
||||
#define ADAGFX_SPI_HW 1 // Display uses SPI interface: 1=hardware 0=software
|
||||
|
||||
// Display interface software SPI
|
||||
// - Hardware SPI: the following definitions are unused
|
||||
// - Software SPI: the following pins need to be defined
|
||||
#define ADAGFX_PIN_MOSI 11
|
||||
#define ADAGFX_PIN_MISO 12
|
||||
#define ADAGFX_PIN_CLK 13
|
||||
|
||||
// SD Card
|
||||
#define ADAGFX_PIN_SDCS 5 // SD card chip select (if GSLC_SD_EN=1)
|
||||
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// SECTION 3: Orientation
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
// Set Default rotation of the display
|
||||
// - Values 0,1,2,3. Rotation is clockwise
|
||||
#define GSLC_ROTATE 1
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// SECTION 4: Touch Handling
|
||||
// - Documentation for configuring touch support can be found at:
|
||||
// https://github.com/ImpulseAdventure/GUIslice/wiki/Configure-Touch-Support
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
|
||||
// . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
|
||||
// SECTION 4A: Update your pin connections here
|
||||
// . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
|
||||
|
||||
// Select touch device wiring method by setting one of the following to 1, others to 0
|
||||
#define ADATOUCH_I2C_HW 0 // Touch controller via hardware I2C (uses ADATOUCH_I2C_ADDR)
|
||||
#define ADATOUCH_SPI_HW 1 // Touch controller via hardware SPI (uses ADATOUCH_PIN_CS)
|
||||
#define ADATOUCH_SPI_SW 0 // Touch controller via software SPI [not yet supported]
|
||||
|
||||
// Touch bus & pinout
|
||||
#define ADATOUCH_I2C_ADDR 0x41 // Touch device I2C address (for ADATOUCH_I2C_HW=1)
|
||||
#define ADATOUCH_PIN_CS 6 // Touch device chip select (for ADATOUCH_SPI_HW=1)
|
||||
|
||||
|
||||
// . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
|
||||
// SECTION 4B: Update your calibration settings here
|
||||
// - These values should come from the diag_ard_touch_calib sketch output
|
||||
// - Please update the values to the right of ADATOUCH_X/Y_MIN/MAX_* accordingly
|
||||
// . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
|
||||
|
||||
// Calibration settings from diag_ard_touch_calib:
|
||||
// DRV_TOUCH_ADA_STMPE610 [240x320]:
|
||||
#define ADATOUCH_X_MIN 150
|
||||
#define ADATOUCH_X_MAX 3800
|
||||
#define ADATOUCH_Y_MIN 130
|
||||
#define ADATOUCH_Y_MAX 4000
|
||||
#define ADATOUCH_REMAP_YX 0 // Some touch controllers may swap X & Y coords
|
||||
|
||||
// . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
|
||||
// SECTION 4D: Additional touch configuration
|
||||
// . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// SECTION 5: Diagnostics
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
// Error reporting
|
||||
// - Set DEBUG_ERR to >0 to enable error reporting via the Serial connection
|
||||
// - Enabling DEBUG_ERR increases FLASH memory consumption which may be
|
||||
// limited on the baseline Arduino (ATmega328P) devices.
|
||||
// - DEBUG_ERR 0 = Disable all error messaging
|
||||
// - DEBUG_ERR 1 = Enable critical error messaging (eg. init)
|
||||
// - DEBUG_ERR 2 = Enable verbose error messaging (eg. bad parameters, etc.)
|
||||
// - For baseline Arduino UNO, recommended to disable this after one has
|
||||
// confirmed basic operation of the library is successful.
|
||||
#define DEBUG_ERR 1 // 1,2 to enable, 0 to disable
|
||||
|
||||
// Debug initialization message
|
||||
// - By default, GUIslice outputs a message in DEBUG_ERR mode
|
||||
// to indicate the initialization status, even during success.
|
||||
// - To disable the messages during successful initialization,
|
||||
// uncomment the following line.
|
||||
//#define INIT_MSG_DISABLE
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// SECTION 6: Optional Features
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
// Enable of optional features
|
||||
// - For memory constrained devices such as Arduino, it is best to
|
||||
// set the following features to 0 (to disable) unless they are
|
||||
// required.
|
||||
#define GSLC_FEATURE_COMPOUND 1 // Compound elements (eg. XSelNum)
|
||||
#define GSLC_FEATURE_XTEXTBOX_EMBED 1 // XTextbox control with embedded color
|
||||
#define GSLC_FEATURE_INPUT 1 // Keyboard / GPIO input control
|
||||
|
||||
// Enable support for SD card
|
||||
// - Set to 1 to enable, 0 to disable
|
||||
// - Note that the inclusion of the SD library consumes considerable
|
||||
// RAM and flash memory which could be problematic for Arduino models
|
||||
// with limited resources.
|
||||
#define GSLC_SD_EN 0
|
||||
|
||||
|
||||
// =============================================================================
|
||||
// SECTION 10: INTERNAL CONFIGURATION
|
||||
// - The following settings should not require modification by users
|
||||
// =============================================================================
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Touch Handling
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
// Define the maximum number of touch events that are handled
|
||||
// per gslc_Update() call. Normally this can be set to 1 but certain
|
||||
// displays may require a greater value (eg. 30) in order to increase
|
||||
// responsiveness of the touch functionality.
|
||||
#define GSLC_TOUCH_MAX_EVT 1
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Misc
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
// Define buffer size for loading images from SD
|
||||
// - A larger buffer will be faster but at the cost of RAM
|
||||
#define GSLC_SD_BUFFPIXEL 50
|
||||
|
||||
// Enable support for graphics clipping (DrvSetClipRect)
|
||||
// - Note that this will impact performance of drawing graphics primitives
|
||||
#define GSLC_CLIP_EN 1
|
||||
|
||||
// Enable for bitmap transparency and definition of color to use
|
||||
#define GSLC_BMP_TRANS_EN 1 // 1 = enabled, 0 = disabled
|
||||
#define GSLC_BMP_TRANS_RGB 0xFF,0x00,0xFF // RGB color (default: MAGENTA)
|
||||
|
||||
#define GSLC_USE_FLOAT 1 // 1=Use floating pt library, 0=Fixed-point lookup tables
|
||||
|
||||
#define GSLC_DEV_TOUCH ""
|
||||
#define GSLC_USE_PROGMEM 0
|
||||
|
||||
#define GSLC_LOCAL_STR 1 // 1=Use local strings (in element array), 0=External
|
||||
#define GSLC_LOCAL_STR_LEN 30 // Max string length of text elements
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Debug diagnostic modes
|
||||
// -----------------------------------------------------------------------------
|
||||
// - Uncomment any of the following to enable specific debug modes
|
||||
//#define DBG_LOG // Enable debugging log output
|
||||
//#define DBG_TOUCH // Enable debugging of touch-presses
|
||||
//#define DBG_FRAME_RATE // Enable diagnostic frame rate reporting
|
||||
//#define DBG_DRAW_IMM // Enable immediate rendering of drawing primitives
|
||||
//#define DBG_DRIVER // Enable graphics driver debug reporting
|
||||
|
||||
|
||||
// =============================================================================
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif // __cplusplus
|
||||
#endif // _GUISLICE_CONFIG_ARD_H_
|
Reference in a new issue