Merge pull request #14646 from s-hadinger/tx_fix_again

LVGL TS fix (again)
This commit is contained in:
s-hadinger 2022-01-28 23:12:16 +01:00 committed by GitHub
commit 6dafe7cb60
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
19 changed files with 10 additions and 3763 deletions

File diff suppressed because it is too large Load Diff

View File

@ -1,88 +0,0 @@
/*
THIS EXAMPLE IS REALLY JUST DOCUMENTATION TO GUIDE YOU THROUGH CHANGES IN
Adafruit_LvGL_Glue 2.0.
If youre coming to Adafruit_LvGL_Glue for the first time as a current user
of LittlevGL on other platforms, you're fine, there are no surprises here,
have a look at the other examples to see how to set up an Adafruit display
for your LittlevGL application.
BUT...if you've used a prior version of Adafruit_LvGL_Glue, and had written
Arduino sketches around it, you're unfortunately in for some extra work.
The "glue" hasn't changed at all, but LittlevGL has seen repeated overhauls,
and projects using earlier versions of Adafruit_LvGL_Glue will no longer
compile in the new system without substantial changes. Many function names,
constants, and styles in particular, will require updating. Many LittlevGL
projects are too much to fit on M0 (SAMD21) boards now -- it's best to work
with a device with more RAM -- M4 (SAMD51), nRF52 and ESP32 are currently
supported.
If desperate to get old code working, you can downgrade to lv_arduino 2.1.5
and Adafruit_LvGL_Glue 1.0.2, but this is NOT recommended when developing
for the long haul -- lv_arduino is altogether deprecated now and won't be
staging a comeback.
For starters, LittlevGL has moved to an entirely different Arduino library.
"lv_arduino" should be UNINSTALLED, and in its place, "lvgl" should be
INSTALLED. The latter is at version 7.11.0 as this is being written...if
there's a newer release, and if you find our glue examples failing to
compile, it's recommended to install that version until this library can be
updated. The LittlevGL developers' preference favors structural and
consistency upgrades over backwards compatibility -- and that's fine, their
project, their rules -- just explaining why this overhaul is necessary.
To repeat: in the Arduino Library Manager, uninstall lv_arduino, install
lvgl.
Also in the Arduino Library Manager, you'll see a related library called
"lv_examples" from the same developer. You can install that if you want, but
understand that this is not actually a library, nor will any of the examples
there compile in the Arduino IDE! But if you pick through these files
manually, there's C code you can dissect for insights in creating interfaces
with LittlevGL, and might create mash-ups with Adafruit_LvGL_Glue examples.
Adafruit_LvGL_Glue includes a lv_conf.file (LittlevGL configuration) that
should "just work" and enables some settings for best compatibility with
Adafruit displays. The only "gotcha" here is that user sketches MUST
#include Adafruit_LvGL_Glue.h BEFORE including lvgl.h, in order for
LittlevGL to pick up on the location of this header file.
BELOW IS A HYPOTHETICAL AND MINIMAL BUT ESSENTIALLY VALID ADAFRUIT_LVGL_GLUE
ARDUINO SKETCH. Please see the other examples for more realistic use. Actual
projects will have different display interfacing, backlight control, a set
of UI widgets and so forth.
*/
#include <Adafruit_LvGL_Glue.h> // Glue library header INCLUDE THIS FIRST!
#include <lvgl.h> // LittlevGL header
#include <Adafruit_ST7789.h> // Display-specific header
#define TFT_CS 1 // Display chip-select pin
#define TFT_DC 2 // Display data/command pin
#define TFT_RST 3 // Display reset pin
Adafruit_ST7789 tft(TFT_CS, TFT_DC, TFT_RST); // TFT on default SPI port
Adafruit_LvGL_Glue glue;
void setup(void) {
Serial.begin(115200);
tft.init(240, 240); // Initialize display
// Initialize glue, passing in address of display
LvGLStatus status = glue.begin(&tft);
if(status != LVGL_OK) {
Serial.printf("Glue error %d\r\n", (int)status);
for(;;);
}
// Create simple label centered on screen
lv_obj_t *label = lv_label_create(lv_scr_act(), NULL);
lv_label_set_text(label, "Hello Arduino!");
lv_obj_align(label, NULL, LV_ALIGN_CENTER, 0, 0);
}
void loop(void) {
lv_task_handler(); // Call LittleVGL task handler periodically
delay(5);
}

View File

@ -1,58 +0,0 @@
// Minimal "Hello" example for LittlevGL on Adafruit CLUE. Requires
// LittlevGL, Adafruit_LvGL_Glue, Adafruit_GFX and Adafruit_ST7735
// libraries.
// Prior Adafruit_LvGL_Glue users: see hello_changes example for updates!
#include <Adafruit_LvGL_Glue.h> // Always include this BEFORE lvgl.h!
#include <lvgl.h>
#include <Adafruit_ST7789.h>
#define TFT_ROTATION 1 // Landscape orientation on CLUE
#define TFT_SPI SPI1 // CLUE display peripheral & pins
#define TFT_CS 31
#define TFT_DC 32
#define TFT_RST 33
#define TFT_BACKLIGHT 34
Adafruit_ST7789 tft(&TFT_SPI, TFT_CS, TFT_DC, TFT_RST);
Adafruit_LvGL_Glue glue;
// This example sketch's LittlevGL UI-building calls are all in this
// function rather than in setup(), so simple programs can just
// copy-and-paste this sketch as a starting point, then embellish here:
void lvgl_setup(void) {
// Create simple label centered on screen
lv_obj_t *label = lv_label_create(lv_scr_act(), NULL);
lv_label_set_text(label, "Hello Arduino!");
lv_obj_align(label, NULL, LV_ALIGN_CENTER, 0, 0);
}
void setup(void) {
Serial.begin(115200);
// Initialize display BEFORE glue setup
tft.init(240, 240);
tft.setRotation(TFT_ROTATION);
pinMode(TFT_BACKLIGHT, OUTPUT);
digitalWrite(TFT_BACKLIGHT, HIGH);
// Initialize glue, passing in address of display
LvGLStatus status = glue.begin(&tft);
if(status != LVGL_OK) {
Serial.printf("Glue error %d\r\n", (int)status);
for(;;);
}
lvgl_setup(); // Call UI-building function above
}
void loop(void) {
lv_task_handler(); // Call LittleVGL task handler periodically
delay(5);
}
// NOTE TO FUTURE SELF: this sketch is essentially the same as the Gizmo
// widgets example. If updating one sketch, make sure the other is kept
// in sync. Aside from screen setup, differences include backlight control
// and A/B button setup & read (CPX is active high, CLUE is active low).

View File

@ -1,74 +0,0 @@
// Minimal "Hello" example for LittlevGL on Adafruit TFT FeatherWings.
// Requires LittlevGL, Adafruit_LvGL_Glue, Adafruit_STMPE610, Adafruit_GFX
// and Adafruit_ILI9341 (2.4" TFT) or Adafruit_HX8357 (3.5") libraries.
// This example doesn't use any touchscreen input, but it's declared anyway
// so this sketch can be copied-and-pasted to serve as a starting point for
// other projects. If display is scrambled, check that correct FeatherWing
// type is selected below (set BIG_FEATHERWING to 0 or 1 as needed).
// Prior Adafruit_LvGL_Glue users: see hello_changes example for updates!
#define BIG_FEATHERWING 0 // Set this to 1 for 3.5" (480x320) FeatherWing!
#include <Adafruit_LvGL_Glue.h> // Always include this BEFORE lvgl.h!
#include <lvgl.h>
#include <Adafruit_STMPE610.h>
#ifdef ESP32
#define TFT_CS 15
#define TFT_DC 33
#define STMPE_CS 32
#else
#define TFT_CS 9
#define TFT_DC 10
#define STMPE_CS 6
#endif
#define TFT_ROTATION 1 // Landscape orientation on FeatherWing
#define TFT_RST -1
#if BIG_FEATHERWING
#include <Adafruit_HX8357.h>
Adafruit_HX8357 tft(TFT_CS, TFT_DC, TFT_RST);
#else
#include <Adafruit_ILI9341.h>
Adafruit_ILI9341 tft(TFT_CS, TFT_DC);
#endif
Adafruit_STMPE610 ts(STMPE_CS);
Adafruit_LvGL_Glue glue;
// This example sketch's LittlevGL UI-building calls are all in this
// function rather than in setup(), so simple programs can just
// copy-and-paste this sketch as a starting point, then embellish here:
void lvgl_setup(void) {
// Create simple label centered on screen
lv_obj_t *label = lv_label_create(lv_scr_act(), NULL);
lv_label_set_text(label, "Hello Arduino!");
lv_obj_align(label, NULL, LV_ALIGN_CENTER, 0, 0);
}
void setup(void) {
Serial.begin(115200);
// Initialize display and touchscreen BEFORE glue setup
tft.begin();
tft.setRotation(TFT_ROTATION);
if(!ts.begin()) {
Serial.println("Couldn't start touchscreen controller");
for(;;);
}
// Initialize glue, passing in address of display & touchscreen
LvGLStatus status = glue.begin(&tft, &ts);
if(status != LVGL_OK) {
Serial.printf("Glue error %d\r\n", (int)status);
for(;;);
}
lvgl_setup(); // Call UI-building function above
}
void loop(void) {
lv_task_handler(); // Call LittleVGL task handler periodically
delay(5);
}

View File

@ -1,57 +0,0 @@
// Minimal "Hello" example for LittlevGL on TFT Gizmo display for Adafruit
// Circuit Playground Express or Circuit Playground Bluefruit. Requires
// LittlevGL, Adafruit_LvGL_Glue, Adafruit_GFX and Adafruit_ST7735 libraries.
// Prior Adafruit_LvGL_Glue users: see hello_changes example for updates!
#include <Adafruit_LvGL_Glue.h> // Always include this BEFORE lvgl.h!
#include <lvgl.h>
#include <Adafruit_ST7789.h>
#define TFT_ROTATION 2
#define TFT_CS A6
#define TFT_DC A7
#define TFT_RST -1
#define TFT_BACKLIGHT A3
#if defined(NRF52_SERIES) // Circuit Playground Bluefruit
#define TFT_SPI SPI
#else // Circuit Playground Express
#define TFT_SPI SPI1
#endif
Adafruit_ST7789 tft(&TFT_SPI, TFT_CS, TFT_DC, TFT_RST);
Adafruit_LvGL_Glue glue;
// This example sketch's LittlevGL UI-building calls are all in this
// function rather than in setup(), so simple programs can just
// copy-and-paste this sketch as a starting point, then embellish here:
void lvgl_setup(void) {
// Create simple label centered on screen
lv_obj_t *label = lv_label_create(lv_scr_act(), NULL);
lv_label_set_text(label, "Hello Arduino!");
lv_obj_align(label, NULL, LV_ALIGN_CENTER, 0, 0);
}
void setup(void) {
Serial.begin(115200);
// Initialize display BEFORE glue setup
tft.init(240, 240);
tft.setRotation(TFT_ROTATION);
pinMode(TFT_BACKLIGHT, OUTPUT);
analogWrite(TFT_BACKLIGHT, 255); // USE analogWrite() FOR GIZMO BACKLIGHT!
// Initialize glue, passing in address of display
LvGLStatus status = glue.begin(&tft);
if(status != LVGL_OK) {
Serial.printf("Glue error %d\r\n", (int)status);
for(;;);
}
lvgl_setup(); // Call UI-building function above
}
void loop(void) {
lv_task_handler(); // Call LittleVGL task handler periodically
delay(5);
}

View File

@ -1,74 +0,0 @@
// Minimal "Hello" example for LittlevGL on Adafruit PyPortal. Requires
// LittlevGL, Adafruit_LvGL_Glue, Adafruit Touchscreen, Adafruit_GFX and
// Adafruit_ILI9341 (PyPortal, PyPortal Pynt) or Adafruit_HX8357 (PyPortal
// Titano) libraries. This example doesn't use any touchscreen input, but
// it's declared anyway so this sketch can be copied-and-pasted to serve
// as a starting point for other projects. If display is scrambled, check
// that the correct board is selected -- PyPortal vs PyPortal Titano.
// Prior Adafruit_LvGL_Glue users: see hello_changes example for updates!
#include <Adafruit_LvGL_Glue.h> // Always include this BEFORE lvgl.h!
#include <lvgl.h>
#include <TouchScreen.h>
#define TFT_ROTATION 3 // Landscape orientation on PyPortal
#define TFT_D0 34 // PyPortal TFT pins
#define TFT_WR 26
#define TFT_DC 10
#define TFT_CS 11
#define TFT_RST 24
#define TFT_RD 9
#define TFT_BACKLIGHT 25
#define YP A4 // PyPortal touchscreen pins
#define XP A5
#define YM A6
#define XM A7
#if defined(ADAFRUIT_PYPORTAL_M4_TITANO)
#include <Adafruit_HX8357.h>
Adafruit_HX8357 tft(tft8bitbus, TFT_D0, TFT_WR, TFT_DC, TFT_CS, TFT_RST,
TFT_RD);
#else
#include <Adafruit_ILI9341.h>
Adafruit_ILI9341 tft(tft8bitbus, TFT_D0, TFT_WR, TFT_DC, TFT_CS, TFT_RST,
TFT_RD);
#endif
TouchScreen ts(XP, YP, XM, YM, 300);
Adafruit_LvGL_Glue glue;
// This example sketch's LittlevGL UI-building calls are all in this
// function rather than in setup(), so simple programs can just
// copy-and-paste this sketch as a starting point, then embellish here:
void lvgl_setup(void) {
// Create simple label centered on screen
lv_obj_t *label = lv_label_create(lv_scr_act(), NULL);
lv_label_set_text(label, "Hello Arduino!");
lv_obj_align(label, NULL, LV_ALIGN_CENTER, 0, 0);
}
void setup(void) {
Serial.begin(115200);
// Initialize display BEFORE glue setup
tft.begin();
tft.setRotation(TFT_ROTATION);
pinMode(TFT_BACKLIGHT, OUTPUT);
digitalWrite(TFT_BACKLIGHT, HIGH);
// PyPortal touchscreen needs no init
// Initialize glue, passing in address of display & touchscreen
LvGLStatus status = glue.begin(&tft, &ts);
if(status != LVGL_OK) {
Serial.printf("Glue error %d\r\n", (int)status);
for(;;);
}
lvgl_setup(); // Call UI-building function above
}
void loop(void) {
lv_task_handler(); // Call LittleVGL task handler periodically
delay(5);
}

View File

@ -1,203 +0,0 @@
// A more functional example for LittlevGL on Adafruit CLUE. Lacking
// touchscreen input, interaction options are limited (but not impossible).
// In this case we'll pretend like it's a status display for something --
// the left and right buttons switch between three different tabs, each
// displaying different information. The code's a bit more complex than
// the hello_clue example, so best get that working before trying this.
// Prior Adafruit_LvGL_Glue users: see hello_changes example for updates!
#include <Adafruit_LvGL_Glue.h> // Always include this BEFORE lvgl.h!
#include <lvgl.h>
#include <Adafruit_ST7789.h>
#define TFT_ROTATION 1 // Landscape orientation on CLUE
#define TFT_SPI SPI1 // CLUE display peripheral & pins
#define TFT_CS 31
#define TFT_DC 32
#define TFT_RST 33
#define TFT_BACKLIGHT 34
Adafruit_ST7789 tft(&TFT_SPI, TFT_CS, TFT_DC, TFT_RST);
Adafruit_LvGL_Glue glue;
lv_obj_t *tabview, // LittlevGL tabview object
*gauge, // Gauge object (on first of three tabs)
*chart, // Chart object (second tab)
*canvas; // Canvas object (third tab)
uint8_t active_tab = 0, // Index of currently-active tab (0-2)
prev_tab = 0; // Index of previously-active tab
lv_chart_series_t *series; // 'Series' data for the bar chart
// Canvas object is an image in memory. Although LittlevGL supports several
// internal image formats, only the TRUE_COLOR variety allows drawing
// operations. Fortunately nRF52840 has gobs of RAM for this. The canvas
// buffer is global because it's referenced both in the setup and main loop.
#define CANVAS_WIDTH 200 // Dimensions in pixels
#define CANVAS_HEIGHT 150
lv_color_t canvas_buffer[
LV_CANVAS_BUF_SIZE_TRUE_COLOR(CANVAS_WIDTH, CANVAS_HEIGHT)];
lv_draw_line_dsc_t draw_dsc; // Drawing style (for canvas) is similarly global
void lvgl_setup(void) {
// Create a tabview object, by default this covers the full display.
tabview = lv_tabview_create(lv_disp_get_scr_act(NULL), NULL);
// The CLUE display has a lot of pixels and can't refresh very fast.
// To show off the tabview animation, let's slow it down to 1 second.
lv_tabview_set_anim_time(tabview, 1000);
// Because they're referenced any time an object is drawn, styles need
// to be permanent in scope; either declared globally (outside all
// functions), or static. The styles used on tabs are never modified after
// they're used here, so let's use static on those...
static lv_style_t tab_style, tab_background_style, indicator_style;
// This is the background style "behind" the tabs. This is what shows
// through for "off" (inactive) tabs -- a vertical green gradient,
// minimal padding around edges (zero at bottom).
lv_style_init(&tab_background_style);
lv_style_set_bg_color(&tab_background_style, LV_STATE_DEFAULT, lv_color_hex(0x408040));
lv_style_set_bg_grad_color(&tab_background_style, LV_STATE_DEFAULT, lv_color_hex(0x304030));
lv_style_set_bg_grad_dir(&tab_background_style, LV_STATE_DEFAULT, LV_GRAD_DIR_VER);
lv_style_set_pad_top(&tab_background_style, LV_STATE_DEFAULT, 2);
lv_style_set_pad_left(&tab_background_style, LV_STATE_DEFAULT, 2);
lv_style_set_pad_right(&tab_background_style, LV_STATE_DEFAULT, 2);
lv_style_set_pad_bottom(&tab_background_style, LV_STATE_DEFAULT, 0);
lv_obj_add_style(tabview, LV_TABVIEW_PART_TAB_BG, &tab_background_style);
// Style for tabs. Active tab is white with opaque background, inactive
// tabs are transparent so the background shows through (only the white
// text is seen). A little top & bottom padding reduces scrunchyness.
lv_style_init(&tab_style);
lv_style_set_pad_top(&tab_style, LV_STATE_DEFAULT, 3);
lv_style_set_pad_bottom(&tab_style, LV_STATE_DEFAULT, 10);
lv_style_set_bg_color(&tab_style, LV_STATE_CHECKED, LV_COLOR_WHITE);
lv_style_set_bg_opa(&tab_style, LV_STATE_CHECKED, LV_OPA_100);
lv_style_set_text_color(&tab_style, LV_STATE_CHECKED, LV_COLOR_GRAY);
lv_style_set_bg_opa(&tab_style, LV_STATE_DEFAULT, LV_OPA_TRANSP);
lv_style_set_text_color(&tab_style, LV_STATE_DEFAULT, LV_COLOR_WHITE);
lv_obj_add_style(tabview, LV_TABVIEW_PART_TAB_BTN, &tab_style);
// Style for the small indicator bar that appears below the active tab.
lv_style_init(&indicator_style);
lv_style_set_bg_color(&indicator_style, LV_STATE_DEFAULT, LV_COLOR_RED);
lv_style_set_size(&indicator_style, LV_STATE_DEFAULT, 5);
lv_obj_add_style(tabview, LV_TABVIEW_PART_INDIC, &indicator_style);
// Back to creating widgets...
// Add three tabs to the tabview
lv_obj_t *tab1 = lv_tabview_add_tab(tabview, "Gauge");
lv_obj_t *tab2 = lv_tabview_add_tab(tabview, "Chart");
lv_obj_t *tab3 = lv_tabview_add_tab(tabview, "Canvas");
// And then add stuff in each tab...
// The first tab holds a gauge. To keep the demo simple, let's just use
// the default style and range (0-100). See LittlevGL docs for options.
gauge = lv_gauge_create(tab1, NULL);
lv_obj_set_size(gauge, 186, 186);
lv_obj_align(gauge, NULL, LV_ALIGN_CENTER, 0, 0);
// Second tab, make a chart...
chart = lv_chart_create(tab2, NULL);
lv_obj_set_size(chart, 200, 180);
lv_obj_align(chart, NULL, LV_ALIGN_CENTER, 0, 0);
lv_chart_set_type(chart, LV_CHART_TYPE_COLUMN);
// For simplicity, we'll stick with the chart's default 10 data points:
series = lv_chart_add_series(chart, LV_COLOR_RED);
lv_chart_init_points(chart, series, 0);
// Make each column shift left as new values enter on right:
lv_chart_set_update_mode(chart, LV_CHART_UPDATE_MODE_SHIFT);
// Third tab is a canvas, which we'll fill with random colored lines.
// LittlevGL draw functions only work on TRUE_COLOR canvas.
canvas = lv_canvas_create(tab3, NULL);
lv_canvas_set_buffer(canvas, canvas_buffer,
CANVAS_WIDTH, CANVAS_HEIGHT, LV_IMG_CF_TRUE_COLOR);
lv_obj_align(canvas, NULL, LV_ALIGN_CENTER, 0, 0);
lv_canvas_fill_bg(canvas, LV_COLOR_WHITE, LV_OPA_100);
// Set up canvas line-drawing style based on defaults.
// Later we'll change color settings when drawing each line.
lv_draw_line_dsc_init(&draw_dsc);
}
void setup(void) {
Serial.begin(115200);
// Initialize display BEFORE glue setup
tft.init(240, 240);
tft.setRotation(TFT_ROTATION);
pinMode(TFT_BACKLIGHT, OUTPUT);
digitalWrite(TFT_BACKLIGHT, HIGH);
// Initialize glue, passing in address of display
LvGLStatus status = glue.begin(&tft);
if(status != LVGL_OK) {
Serial.printf("Glue error %d\r\n", (int)status);
for(;;);
}
lvgl_setup(); // Call UI-building function above
// Enable "A" and "B" buttons as inputs
pinMode(PIN_BUTTON1, INPUT_PULLUP);
pinMode(PIN_BUTTON2, INPUT_PULLUP);
}
uint32_t prev_time = -1;
void loop(void) {
// Read left/right button inputs. Debouncing could be done better,
// but this'll do for a quick simple demo...
if(digitalRead(PIN_BUTTON1) == LOW) {
if(active_tab > 0) {
active_tab--;
}
while(digitalRead(PIN_BUTTON1) == LOW); // Wait for button release
} else if(digitalRead(PIN_BUTTON2) == LOW) {
if(active_tab < 2) {
active_tab++;
}
while(digitalRead(PIN_BUTTON2) == LOW); // Wait for button release
}
// Change active tab if button pressings happened
if(active_tab != prev_tab) {
lv_tabview_set_tab_act(tabview, active_tab, true);
prev_tab = active_tab;
}
// Make the gauge sweep a full sine wave over time
lv_gauge_set_value(gauge, 0, (int)(50.5 + sin(millis() / 1000.0) * 50.0));
// About 2X a second, things happen on the other two tabs...
uint32_t new_time = millis() / 500; // Current half-second
if(new_time != prev_time) { // freshly elapsed
prev_time = new_time;
// Add a new random item to the bar chart (old value shift left)
lv_chart_set_next(chart, series, random(100));
lv_chart_refresh(chart);
// Add a random line to the canvas
lv_point_t points[2];
points[0].x = random(CANVAS_WIDTH);
points[0].y = random(CANVAS_HEIGHT);
points[1].x = random(CANVAS_WIDTH);
points[1].y = random(CANVAS_HEIGHT);
draw_dsc.color.ch.red = random();
draw_dsc.color.ch.green = random();
draw_dsc.color.ch.blue = random();
lv_canvas_draw_line(canvas, points, 2, &draw_dsc);
// This forces the canvas to update (otherwise changes aren't
// seen unless leaving and returning to the canvas tab):
lv_canvas_set_buffer(canvas, canvas_buffer,
CANVAS_WIDTH, CANVAS_HEIGHT, LV_IMG_CF_TRUE_COLOR);
}
lv_task_handler(); // Call LittleVGL task handler periodically
delay(5);
}

View File

@ -1,261 +0,0 @@
// A more interesting example for LittlevGL on Adafruit TFT FeatherWings,
// showing use of the touchscreen. Code's a little more complex than the
// hello_featherwing example, so best get that working before trying this.
// By default, as written, on a 320x240 TFT FeatherWing the example is a
// pretend calculator keypad, while 480x320 TFT has a whole keyboard
// (though you'll probably need a stylus). These just seemed the right
// level of detail for their respective screens, but feel free to override
// and try either for yourself. If display is scrambled, check that
// correct FeatherWing type is selected below (set BIG_FEATHERWING to 0
// or 1 as needed).
// Prior Adafruit_LvGL_Glue users: see hello_changes example for updates!
// Feather M0 is no longer recommended for LittlevGL use. The calculator
// almost works (hangs after a few button presses) and keyboard won't run
// at all. A Feather M4 or other >32K RAM device is recommended.
#define BIG_FEATHERWING 0 // Set this to 1 for 3.5" (480x320) FeatherWing!
#include <Adafruit_LvGL_Glue.h> // Always include this BEFORE lvgl.h!
#include <lvgl.h>
#include <Adafruit_STMPE610.h>
#define DEMO_CALC 0
#define DEMO_TEXT 1
#ifdef ESP32
#define TFT_CS 15
#define TFT_DC 33
#define STMPE_CS 32
#else
#define TFT_CS 9
#define TFT_DC 10
#define STMPE_CS 6
#endif
#define TFT_RST -1
#if BIG_FEATHERWING
#include <Adafruit_HX8357.h>
Adafruit_HX8357 tft(TFT_CS, TFT_DC, TFT_RST);
#define DEMO DEMO_TEXT // On big TFT, do text/keyboard example
#else
#include <Adafruit_ILI9341.h>
Adafruit_ILI9341 tft(TFT_CS, TFT_DC);
#define DEMO DEMO_CALC // Smaller TFT, do keypad example
#endif
Adafruit_STMPE610 ts(STMPE_CS);
Adafruit_LvGL_Glue glue;
#if DEMO == DEMO_CALC
// "Pretend" calculator example. Please, PLEASE...do NOT implement the whole
// calculator and submit as a pull request, because it will NOT be merged!
// This sketch is meant only to be illustrative and not functional, just
// showing LittlevGL + Adafruit display/touch tied together with a modest
// amount of code. Even a simple but working calc would require WAY more
// code, distracting from that core idea (and is a waste of hardware).
// Daiso has better calculators for $1.50.
#define TFT_ROTATION 0 // Portrait orientation
lv_obj_t *digits_label = NULL; // LittlevGL label object showing digits
String digits = "0"; // Current digits string value
bool hasDecimal = false; // Only allow one decimal point
const char *buttons[] = { // Button matrix labels
"7", "8", "9", "/", "\n",
"4", "5", "6", "x", "\n",
"1", "2", "3", "-", "\n",
"0", ".", "=", "+", "" };
// This function processes events from the button matrix
void button_event_handler(lv_obj_t *obj, lv_event_t event) {
if(event == LV_EVENT_VALUE_CHANGED) {
const char *txt = lv_btnmatrix_get_active_btn_text(obj);
if(txt) { // NULL if pressed in frame area outside buttons
if(txt[0] == '.') {
// Decimal button pressed. Add decimal point to "digits" string
// if it's not too long and there's no decimal present yet...
if((digits.length() < 15) && !hasDecimal) {
digits += '.';
hasDecimal = true;
}
} else if((txt[0] >= '0') && (txt[0] <= '9')) {
// Number button (0-9) pressed. If there's nothing currently
// being displayed, take the digit literally. Otherwise, append
// the new digit if the "digits" string is not too long.
if(digits.equals("0")) {
digits = txt[0];
} else if(digits.length() < 15) {
digits += txt[0];
}
} else {
// Any other button, just reset the calculator display.
// It's all just pretend.
digits = "0";
hasDecimal = false;
}
if(digits_label != NULL) {
lv_label_set_text(digits_label, digits.c_str());
}
}
}
}
void lvgl_setup(void) {
// Just using the default styles for everything here, keeping
// it basic. See the official LittlevGL docs and examples for
// insights on applying styles.
// The calculator digits are held inside a LvGL container object
// as this gives us a little more control over positioning.
lv_obj_t *container = lv_cont_create(lv_scr_act(), NULL);
lv_cont_set_fit(container, LV_FIT_NONE); // Don't auto fit
lv_obj_set_size(container, tft.width(), 50); // Full width x 50 px
// Calculator digits are just a text label inside the container,
// refreshed whenever the global "digits" string changes.
digits_label = lv_label_create(container, NULL);
lv_label_set_text(digits_label, digits.c_str());
lv_obj_align(digits_label, NULL, LV_ALIGN_IN_TOP_LEFT, 20, 10);
lv_label_set_long_mode(digits_label, LV_LABEL_LONG_CROP);
lv_obj_set_size(digits_label, tft.width() - 40, 30);
lv_label_set_align(digits_label, LV_LABEL_ALIGN_RIGHT);
// Fill the remaining space with the button matrix.
lv_obj_t *button_matrix = lv_btnmatrix_create(lv_scr_act(), NULL);
lv_btnmatrix_set_map(button_matrix, buttons);
lv_obj_align(button_matrix, NULL, LV_ALIGN_IN_TOP_LEFT, 0, 50);
lv_obj_set_size(button_matrix, tft.width(), tft.height() - 50);
lv_obj_set_event_cb(button_matrix, button_event_handler);
}
#else // Keyboard demo
// Keyboard example, lets you enter and edit text in a field. Even on a
// 480x320 TFT it requires a stylus to be even half useful (fingertip
// is possible if very patient), but having the option of a keyboard at
// all on this device is pretty nifty!
#define TFT_ROTATION 1 // Landscape orientation
lv_obj_t *textarea,
*keyboard = NULL; // Created/deleted as needed
#if LV_USE_ANIMATION
// Called after keyboard slides closed - deletes keyboard object
void delete_keyboard(lv_anim_t * a) {
lv_obj_del((lv_obj_t *)a->var);
keyboard = NULL;
}
#endif
// Called when the close or ok button is pressed on the keyboard
void keyboard_event_handler(lv_obj_t *obj, lv_event_t event) {
lv_keyboard_def_event_cb(keyboard, event);
if(event == LV_EVENT_APPLY || event == LV_EVENT_CANCEL) {
#if LV_USE_ANIMATION
// If animation is enabled, make keyboard slide away
lv_anim_path_t path;
lv_anim_path_init(&path);
lv_anim_path_set_cb(&path, lv_anim_path_ease_in_out);
lv_anim_t a;
lv_anim_init(&a);
lv_anim_set_exec_cb(&a, (lv_anim_exec_xcb_t)lv_obj_set_y);
lv_anim_set_var(&a, keyboard);
lv_anim_set_time(&a, 300);
lv_anim_set_values(&a, lv_obj_get_y(keyboard), LV_VER_RES); // start, end
lv_anim_set_path(&a, &path);
lv_anim_set_ready_cb(&a, delete_keyboard);
lv_anim_start(&a);
#else
lv_obj_del(keyboard);
keyboard = NULL;
#endif
}
}
// Other clicks in the text area
void text_area_event_handler(lv_obj_t *obj, lv_event_t event) {
if(event == LV_EVENT_CLICKED) {
// Unsure why, but text area has an initial clicked event on
// creation, causing the keyboard to appear. This is a hacky
// workaround that just ignores the first click event, so
// subsequent actual clicks bring up the keyboard.
static bool first = true;
if(first) {
first = false;
return;
}
if(keyboard == NULL) {
// If not present, create keyboard object at bottom of screen
keyboard = lv_keyboard_create(lv_scr_act(), NULL);
lv_obj_set_size(keyboard, tft.width(), tft.height() * 7 / 16);
lv_obj_align(keyboard, textarea, LV_ALIGN_IN_BOTTOM_MID, 0, 0);
lv_keyboard_set_textarea(keyboard, textarea);
lv_keyboard_set_cursor_manage(keyboard, true);
lv_obj_set_event_cb(keyboard, keyboard_event_handler);
#if LV_USE_ANIMATION
// If animation is enabled, make keyboard slide into place
lv_anim_path_t path;
lv_anim_path_init(&path);
lv_anim_path_set_cb(&path, lv_anim_path_ease_in_out);
lv_anim_t a;
lv_anim_init(&a);
lv_anim_set_exec_cb(&a, (lv_anim_exec_xcb_t)lv_obj_set_y);
lv_anim_set_var(&a, keyboard);
lv_anim_set_time(&a, 300);
lv_anim_set_values(&a, LV_VER_RES, lv_obj_get_y(keyboard)); // start, end
lv_anim_set_path(&a, &path);
lv_anim_start(&a);
#endif
}
}
}
void lvgl_setup(void) {
textarea = lv_textarea_create(lv_scr_act(), NULL);
lv_obj_set_size(textarea, LV_HOR_RES, LV_VER_RES); // Whole screen
lv_obj_align(textarea, NULL, LV_ALIGN_CENTER, 0, 0);
lv_textarea_set_text(textarea, "This text is editable.");
lv_obj_set_event_cb(textarea, text_area_event_handler);
lv_textarea_set_cursor_pos(textarea, LV_TEXTAREA_CURSOR_LAST);
}
#endif // end calculator / keyboard examples
void setup(void) {
Serial.begin(115200);
// Initialize display and touchscreen BEFORE glue setup
tft.begin();
tft.setRotation(TFT_ROTATION);
if(!ts.begin()) {
Serial.println("Couldn't start touchscreen controller");
for(;;);
}
// Initialize glue, passing in address of display & touchscreen
LvGLStatus status = glue.begin(&tft, &ts);
if(status != LVGL_OK) {
Serial.printf("Glue error %d\r\n", (int)status);
for(;;);
}
lvgl_setup(); // Call UI-building function above
}
void loop(void) {
lv_task_handler(); // Call LittleVGL task handler periodically
delay(5);
}
// NOTE TO FUTURE SELF: this sketch is largely similar to the PyPortal
// widgets example. If updating/bugfixing one sketch, make sure the other
// is kept in sync.

View File

@ -1,225 +0,0 @@
// A more functional example for LittlevGL on Adafruit Circuit Playground
// Bluefruit (NOT Express!) with TFT Gizmo display. Lacking touchscreen
// input, interaction options are limited (but not impossible). In this
// case we'll pretend like it's a status display for something -- the left
// and right buttons (on the back if looking at the screen) switch between
// three different tabs, each displaying different information. The code's
// a bit more complex than the hello_gizmo example, so best get that
// working before trying this. This example is a bit too much for the
// Circuit Playground Express to handle now, but simpler LittlevGL
// programs should be possible.
// Prior Adafruit_LvGL_Glue users: see hello_changes example for updates!
#if !defined(NRF52_SERIES) // Circuit Playground Bluefruit
#error "This example is for Circuit Playground Bluefruit only."
#endif
#include <Adafruit_LvGL_Glue.h> // Always include this BEFORE lvgl.h!
#include <lvgl.h>
#include <Adafruit_ST7789.h>
#define TFT_ROTATION 2
#define TFT_CS A6
#define TFT_DC A7
#define TFT_RST -1
#define TFT_BACKLIGHT A3
#if defined(NRF52_SERIES) // Circuit Playground Bluefruit
#define TFT_SPI SPI
#else // Circuit Playground Express
#define TFT_SPI SPI1
// Though this example won't work on CP Express, including this
// here anyway for reference, if copying over to a simpler sketch.
#endif
Adafruit_ST7789 tft(&TFT_SPI, TFT_CS, TFT_DC, TFT_RST);
Adafruit_LvGL_Glue glue;
lv_obj_t *tabview, // LittlevGL tabview object
*gauge, // Gauge object (on first of three tabs)
*chart, // Chart object (second tab)
*canvas; // Canvas object (third tab)
uint8_t active_tab = 0, // Index of currently-active tab (0-2)
prev_tab = 0; // Index of previously-active tab
lv_chart_series_t *series; // 'Series' data for the bar chart
// Canvas object is an image in memory. Although LittlevGL supports several
// internal image formats, only the TRUE_COLOR variety allows drawing
// operations. Fortunately nRF52840 has gobs of RAM for this. The canvas
// buffer is global because it's referenced both in the setup and main loop.
// Circuit Playground Express (M0) doesn't have enough RAM for this.
#define CANVAS_WIDTH 200 // Dimensions in pixels
#define CANVAS_HEIGHT 150
lv_color_t canvas_buffer[
LV_CANVAS_BUF_SIZE_TRUE_COLOR(CANVAS_WIDTH, CANVAS_HEIGHT)];
lv_draw_line_dsc_t draw_dsc; // Drawing style (for canvas) is similarly global
void lvgl_setup(void) {
// Create a tabview object, by default this covers the full display.
tabview = lv_tabview_create(lv_disp_get_scr_act(NULL), NULL);
// The Gizmo display has a lot of pixels and can't refresh very fast.
// To show off the tabview animation, let's slow it down to 1 second.
lv_tabview_set_anim_time(tabview, 1000);
// Because they're referenced any time an object is drawn, styles need
// to be permanent in scope; either declared globally (outside all
// functions), or static. The styles used on tabs are never modified after
// they're used here, so let's use static on those...
static lv_style_t tab_style, tab_background_style, indicator_style;
// This is the background style "behind" the tabs. This is what shows
// through for "off" (inactive) tabs -- a vertical green gradient,
// minimal padding around edges (zero at bottom).
lv_style_init(&tab_background_style);
lv_style_set_bg_color(&tab_background_style, LV_STATE_DEFAULT, lv_color_hex(0x408040));
lv_style_set_bg_grad_color(&tab_background_style, LV_STATE_DEFAULT, lv_color_hex(0x304030));
lv_style_set_bg_grad_dir(&tab_background_style, LV_STATE_DEFAULT, LV_GRAD_DIR_VER);
lv_style_set_pad_top(&tab_background_style, LV_STATE_DEFAULT, 2);
lv_style_set_pad_left(&tab_background_style, LV_STATE_DEFAULT, 2);
lv_style_set_pad_right(&tab_background_style, LV_STATE_DEFAULT, 2);
lv_style_set_pad_bottom(&tab_background_style, LV_STATE_DEFAULT, 0);
lv_obj_add_style(tabview, LV_TABVIEW_PART_TAB_BG, &tab_background_style);
// Style for tabs. Active tab is white with opaque background, inactive
// tabs are transparent so the background shows through (only the white
// text is seen). A little top & bottom padding reduces scrunchyness.
lv_style_init(&tab_style);
lv_style_set_pad_top(&tab_style, LV_STATE_DEFAULT, 3);
lv_style_set_pad_bottom(&tab_style, LV_STATE_DEFAULT, 10);
lv_style_set_bg_color(&tab_style, LV_STATE_CHECKED, LV_COLOR_WHITE);
lv_style_set_bg_opa(&tab_style, LV_STATE_CHECKED, LV_OPA_100);
lv_style_set_text_color(&tab_style, LV_STATE_CHECKED, LV_COLOR_GRAY);
lv_style_set_bg_opa(&tab_style, LV_STATE_DEFAULT, LV_OPA_TRANSP);
lv_style_set_text_color(&tab_style, LV_STATE_DEFAULT, LV_COLOR_WHITE);
lv_obj_add_style(tabview, LV_TABVIEW_PART_TAB_BTN, &tab_style);
// Style for the small indicator bar that appears below the active tab.
lv_style_init(&indicator_style);
lv_style_set_bg_color(&indicator_style, LV_STATE_DEFAULT, LV_COLOR_RED);
lv_style_set_size(&indicator_style, LV_STATE_DEFAULT, 5);
lv_obj_add_style(tabview, LV_TABVIEW_PART_INDIC, &indicator_style);
// Back to creating widgets...
// Add three tabs to the tabview
lv_obj_t *tab1 = lv_tabview_add_tab(tabview, "Gauge");
lv_obj_t *tab2 = lv_tabview_add_tab(tabview, "Chart");
lv_obj_t *tab3 = lv_tabview_add_tab(tabview, "Canvas");
// And then add stuff in each tab...
// The first tab holds a gauge. To keep the demo simple, let's just use
// the default style and range (0-100). See LittlevGL docs for options.
gauge = lv_gauge_create(tab1, NULL);
lv_obj_set_size(gauge, 186, 186);
lv_obj_align(gauge, NULL, LV_ALIGN_CENTER, 0, 0);
// Second tab, make a chart...
chart = lv_chart_create(tab2, NULL);
lv_obj_set_size(chart, 200, 180);
lv_obj_align(chart, NULL, LV_ALIGN_CENTER, 0, 0);
lv_chart_set_type(chart, LV_CHART_TYPE_COLUMN);
// For simplicity, we'll stick with the chart's default 10 data points:
series = lv_chart_add_series(chart, LV_COLOR_RED);
lv_chart_init_points(chart, series, 0);
// Make each column shift left as new values enter on right:
lv_chart_set_update_mode(chart, LV_CHART_UPDATE_MODE_SHIFT);
// Third tab is a canvas, which we'll fill with random colored lines.
// LittlevGL draw functions only work on TRUE_COLOR canvas.
canvas = lv_canvas_create(tab3, NULL);
lv_canvas_set_buffer(canvas, canvas_buffer,
CANVAS_WIDTH, CANVAS_HEIGHT, LV_IMG_CF_TRUE_COLOR);
lv_obj_align(canvas, NULL, LV_ALIGN_CENTER, 0, 0);
lv_canvas_fill_bg(canvas, LV_COLOR_WHITE, LV_OPA_100);
// Set up canvas line-drawing style based on defaults.
// Later we'll change color settings when drawing each line.
lv_draw_line_dsc_init(&draw_dsc);
}
void setup(void) {
Serial.begin(115200);
// Initialize display BEFORE glue setup
tft.init(240, 240);
tft.setRotation(TFT_ROTATION);
analogWrite(TFT_BACKLIGHT, 255); // USE analogWrite() FOR GIZMO BACKLIGHT!
// Initialize glue, passing in address of display
LvGLStatus status = glue.begin(&tft);
if(status != LVGL_OK) {
Serial.printf("Glue error %d\r\n", (int)status);
for(;;);
}
lvgl_setup(); // Call UI-building function above
// Enable "A" and "B" buttons as inputs
pinMode(4, INPUT_PULLDOWN); // Left (A) button
pinMode(5, INPUT_PULLDOWN); // Right (B) button
}
uint32_t prev_time = -1;
void loop(void) {
// Read left/right button inputs. Debouncing could be done better,
// but this'll do for a quick simple demo. The arrangements of the
// buttons is intentionally flipped here (pin 5, the "right" button,
// moves one tab left, pin 4 the opposite) so the button placements
// make sense while looking at the screen on the reverse side.
if(digitalRead(5) == HIGH) {
if(active_tab > 0) {
active_tab--;
}
while(digitalRead(5) == HIGH); // Wait for button release
} else if(digitalRead(4) == HIGH) {
if(active_tab < 2) {
active_tab++;
}
while(digitalRead(4) == HIGH); // Wait for button release
}
// Change active tab if button pressings happened
if(active_tab != prev_tab) {
lv_tabview_set_tab_act(tabview, active_tab, true);
prev_tab = active_tab;
}
// Make the gauge sweep a full sine wave over timeCLUE
lv_gauge_set_value(gauge, 0, (int)(50.5 + sin(millis() / 1000.0) * 50.0));
// About 2X a second, things happen on the other two tabs...
uint32_t new_time = millis() / 500; // Current half-second
if(new_time != prev_time) { // freshly elapsed
prev_time = new_time;
// Add a new random item to the bar chart (old value shift left)
lv_chart_set_next(chart, series, random(100));
lv_chart_refresh(chart);
// Add a random line to the canvas
lv_point_t points[2];
points[0].x = random(CANVAS_WIDTH);
points[0].y = random(CANVAS_HEIGHT);
points[1].x = random(CANVAS_WIDTH);
points[1].y = random(CANVAS_HEIGHT);
draw_dsc.color.ch.red = random();
draw_dsc.color.ch.green = random();
draw_dsc.color.ch.blue = random();
lv_canvas_draw_line(canvas, points, 2, &draw_dsc);
// This forces the canvas to update (otherwise changes aren't
// seen unless leaving and returning to the canvas tab):
lv_canvas_set_buffer(canvas, canvas_buffer,
CANVAS_WIDTH, CANVAS_HEIGHT, LV_IMG_CF_TRUE_COLOR);
}
lv_task_handler(); // Call LittleVGL task handler periodically
delay(5);
}
// NOTE TO FUTURE SELF: this sketch is essentially the same as the CLUE
// widgets example. If updating one sketch, make sure the other is kept
// in sync. Aside from screen setup, differences include backlight control
// and A/B button setup & read (CPX is active high, CLUE is active low).

View File

@ -1,255 +0,0 @@
// A more interesting example for LittlevGL on Adafruit PyPortal, showing
// use of the touchscreen. Code's a little more complex than the
// hello_pyportal example, so best get that working before trying this.
// By default, as written, on regular (320x240) PyPortal the example is a
// pretend calculator keypad, while PyPortal Titano (480x320) has a whole
// keyboard (though you'll probably need a stylus). These just seemed the
// right level of detail for their respective screens, but feel free to
// override and try either for yourself.
// Prior Adafruit_LvGL_Glue users: see hello_changes example for updates!
#include <Adafruit_LvGL_Glue.h> // Always include this BEFORE lvgl.h!
#include <lvgl.h>
#include <TouchScreen.h>
#define DEMO_CALC 0
#define DEMO_TEXT 1
#define TFT_D0 34 // PyPortal TFT pins
#define TFT_WR 26
#define TFT_DC 10
#define TFT_CS 11
#define TFT_RST 24
#define TFT_RD 9
#define TFT_BACKLIGHT 25
#define YP A4 // PyPortal touchscreen pins
#define XP A5
#define YM A6
#define XM A7
#if defined(ADAFRUIT_PYPORTAL_M4_TITANO)
#include <Adafruit_HX8357.h>
Adafruit_HX8357 tft(tft8bitbus, TFT_D0, TFT_WR, TFT_DC, TFT_CS, TFT_RST,
TFT_RD);
#define DEMO DEMO_TEXT // On Titano, do text/keyboard example
#else
#include <Adafruit_ILI9341.h>
Adafruit_ILI9341 tft(tft8bitbus, TFT_D0, TFT_WR, TFT_DC, TFT_CS, TFT_RST,
TFT_RD);
#define DEMO DEMO_CALC // Smaller PyPortal, do keypad example
#endif
TouchScreen ts(XP, YP, XM, YM, 300);
Adafruit_LvGL_Glue glue;
#if DEMO == DEMO_CALC
// "Pretend" calculator example. Please, PLEASE...do NOT implement the whole
// calculator and submit as a pull request, because it will NOT be merged!
// This sketch is meant only to be illustrative and not functional, just
// showing LittlevGL + Adafruit display/touch tied together with a modest
// amount of code. Even a simple but working calc would require WAY more
// code, distracting from that core idea (and is a waste of PyPortal).
// Daiso has better calculators for $1.50.
#define TFT_ROTATION 0 // Portrait orientation on PyPortal (USB top)
lv_obj_t *digits_label = NULL; // LittlevGL label object showing digits
String digits = "0"; // Current digits string value
bool hasDecimal = false; // Only allow one decimal point
const char *buttons[] = { // Button matrix labels
"7", "8", "9", "/", "\n",
"4", "5", "6", "x", "\n",
"1", "2", "3", "-", "\n",
"0", ".", "=", "+", "" };
// This function processes events from the button matrix
void button_event_handler(lv_obj_t *obj, lv_event_t event) {
if(event == LV_EVENT_VALUE_CHANGED) {
const char *txt = lv_btnmatrix_get_active_btn_text(obj);
if(txt) { // NULL if pressed in frame area outside buttons
if(txt[0] == '.') {
// Decimal button pressed. Add decimal point to "digits" string
// if it's not too long and there's no decimal present yet...
if((digits.length() < 15) && !hasDecimal) {
digits += '.';
hasDecimal = true;
}
} else if((txt[0] >= '0') && (txt[0] <= '9')) {
// Number button (0-9) pressed. If there's nothing currently
// being displayed, take the digit literally. Otherwise, append
// the new digit if the "digits" string is not too long.
if(digits.equals("0")) {
digits = txt[0];
} else if(digits.length() < 15) {
digits += txt[0];
}
} else {
// Any other button, just reset the calculator display.
// It's all just pretend.
digits = "0";
hasDecimal = false;
}
if(digits_label != NULL) {
lv_label_set_text(digits_label, digits.c_str());
}
}
}
}
void lvgl_setup(void) {
// Just using the default styles for everything here, keeping
// it basic. See the official LittlevGL docs and examples for
// insights on applying styles.
// The calculator digits are held inside a LvGL container object
// as this gives us a little more control over positioning.
lv_obj_t *container = lv_cont_create(lv_scr_act(), NULL);
lv_cont_set_fit(container, LV_FIT_NONE); // Don't auto fit
lv_obj_set_size(container, tft.width(), 50); // Full width x 50 px
// Calculator digits are just a text label inside the container,
// refreshed whenever the global "digits" string changes.
digits_label = lv_label_create(container, NULL);
lv_label_set_text(digits_label, digits.c_str());
lv_obj_align(digits_label, NULL, LV_ALIGN_IN_TOP_LEFT, 20, 10);
lv_label_set_long_mode(digits_label, LV_LABEL_LONG_CROP);
lv_obj_set_size(digits_label, tft.width() - 40, 30);
lv_label_set_align(digits_label, LV_LABEL_ALIGN_RIGHT);
// Fill the remaining space with the button matrix.
lv_obj_t *button_matrix = lv_btnmatrix_create(lv_scr_act(), NULL);
lv_btnmatrix_set_map(button_matrix, buttons);
lv_obj_align(button_matrix, NULL, LV_ALIGN_IN_TOP_LEFT, 0, 50);
lv_obj_set_size(button_matrix, tft.width(), tft.height() - 50);
lv_obj_set_event_cb(button_matrix, button_event_handler);
}
#else // Keyboard demo
// Keyboard example, lets you enter and edit text in a field. Even on a
// PyPortal Titano it requires a stylus to be even half useful (fingertip
// is possible if very patient), but having the option of a keyboard at
// all on this device is pretty nifty!
#define TFT_ROTATION 3 // Landscape orientation on PyPortal (USB right)
lv_obj_t *textarea,
*keyboard = NULL; // Created/deleted as needed
#if LV_USE_ANIMATION
// Called after keyboard slides closed - deletes keyboard object
void delete_keyboard(lv_anim_t * a) {
lv_obj_del((lv_obj_t *)a->var);
keyboard = NULL;
}
#endif
// Called when the close or ok button is pressed on the keyboard
void keyboard_event_handler(lv_obj_t *obj, lv_event_t event) {
lv_keyboard_def_event_cb(keyboard, event);
if(event == LV_EVENT_APPLY || event == LV_EVENT_CANCEL) {
#if LV_USE_ANIMATION
// If animation is enabled, make keyboard slide away
lv_anim_path_t path;
lv_anim_path_init(&path);
lv_anim_path_set_cb(&path, lv_anim_path_ease_in_out);
lv_anim_t a;
lv_anim_init(&a);
lv_anim_set_exec_cb(&a, (lv_anim_exec_xcb_t)lv_obj_set_y);
lv_anim_set_var(&a, keyboard);
lv_anim_set_time(&a, 300);
lv_anim_set_values(&a, lv_obj_get_y(keyboard), LV_VER_RES); // start, end
lv_anim_set_path(&a, &path);
lv_anim_set_ready_cb(&a, delete_keyboard);
lv_anim_start(&a);
#else
lv_obj_del(keyboard);
keyboard = NULL;
#endif
}
}
// Other clicks in the text area
void text_area_event_handler(lv_obj_t *obj, lv_event_t event) {
if(event == LV_EVENT_CLICKED) {
// Unsure why, but text area has an initial clicked event on
// creation, causing the keyboard to appear. This is a hacky
// workaround that just ignores the first click event, so
// subsequent actual clicks bring up the keyboard.
static bool first = true;
if(first) {
first = false;
return;
}
if(keyboard == NULL) {
// If not present, create keyboard object at bottom of screen
keyboard = lv_keyboard_create(lv_scr_act(), NULL);
lv_obj_set_size(keyboard, tft.width(), tft.height() * 7 / 16);
lv_obj_align(keyboard, textarea, LV_ALIGN_IN_BOTTOM_MID, 0, 0);
lv_keyboard_set_textarea(keyboard, textarea);
lv_keyboard_set_cursor_manage(keyboard, true);
lv_obj_set_event_cb(keyboard, keyboard_event_handler);
#if LV_USE_ANIMATION
// If animation is enabled, make keyboard slide into place
lv_anim_path_t path;
lv_anim_path_init(&path);
lv_anim_path_set_cb(&path, lv_anim_path_ease_in_out);
lv_anim_t a;
lv_anim_init(&a);
lv_anim_set_exec_cb(&a, (lv_anim_exec_xcb_t)lv_obj_set_y);
lv_anim_set_var(&a, keyboard);
lv_anim_set_time(&a, 300);
lv_anim_set_values(&a, LV_VER_RES, lv_obj_get_y(keyboard)); // start, end
lv_anim_set_path(&a, &path);
lv_anim_start(&a);
#endif
}
}
}
void lvgl_setup(void) {
textarea = lv_textarea_create(lv_scr_act(), NULL);
lv_obj_set_size(textarea, LV_HOR_RES, LV_VER_RES); // Whole screen
lv_obj_align(textarea, NULL, LV_ALIGN_CENTER, 0, 0);
lv_textarea_set_text(textarea, "This text is editable.");
lv_obj_set_event_cb(textarea, text_area_event_handler);
lv_textarea_set_cursor_pos(textarea, LV_TEXTAREA_CURSOR_LAST);
}
#endif // end calculator / keyboard examples
void setup(void) {
Serial.begin(115200);
// Initialize display BEFORE glue setup
tft.begin();
tft.setRotation(TFT_ROTATION);
pinMode(TFT_BACKLIGHT, OUTPUT);
digitalWrite(TFT_BACKLIGHT, HIGH);
// PyPortal touchscreen needs no init
// Initialize glue, passing in address of display & touchscreen
LvGLStatus status = glue.begin(&tft, &ts);
if(status != LVGL_OK) {
Serial.printf("Glue error %d\r\n", (int)status);
for(;;);
}
lvgl_setup(); // Call UI-building function above
}
void loop(void) {
lv_task_handler(); // Call LittleVGL task handler periodically
delay(5);
}
// NOTE TO FUTURE SELF: this sketch is largely similar to the FeatherWing
// widgets example. If updating/bugfixing one sketch, make sure the other
// is kept in sync.

View File

@ -136,8 +136,8 @@ void Touch_Check(void(*rotconvert)(int16_t *x, int16_t *y)) {
if (FT5206_found) {
touched = FT5206_touched();
if (touched) {
touch_xp = FT5206_x();
touch_yp = FT5206_y();
raw_touch_xp = FT5206_x();
raw_touch_yp = FT5206_y();
}
}
#endif // USE_FT5206
@ -146,14 +146,14 @@ void Touch_Check(void(*rotconvert)(int16_t *x, int16_t *y)) {
if (XPT2046_found) {
touched = XPT2046_touched();
if (touched) {
touch_xp = XPT2046_x();
touch_yp = XPT2046_y();
raw_touch_xp = XPT2046_x();
raw_touch_yp = XPT2046_y();
}
}
#endif // USE_XPT2046
touch_xp = raw_touch_xp;
touch_yp = raw_touch_yp;
raw_touch_xp = touch_xp;
raw_touch_yp = touch_yp;
if (touched) {
was_touched = true;
#ifdef USE_TOUCH_BUTTONS
@ -185,10 +185,6 @@ void Touch_Check(void(*rotconvert)(int16_t *x, int16_t *y)) {
#endif // USE_TOUCH_BUTTONS
} else {
if (was_touched) {
AddLog(LOG_LEVEL_DEBUG_MORE, "TS : released x=%i y=%i (raw x=%i y=%i)", touch_xp, touch_yp, raw_touch_xp, raw_touch_yp);
was_touched = false;
}
#ifdef USE_M5STACK_CORE2
for (uint32_t tbut = 0; tbut < 3; tbut++) {
if (tbstate[tbut] & 1) {
@ -201,6 +197,10 @@ void Touch_Check(void(*rotconvert)(int16_t *x, int16_t *y)) {
#endif // USE_M5STACK_CORE2
rotconvert(&touch_xp, &touch_yp); // still do rot convert if not touched
if (was_touched) {
AddLog(LOG_LEVEL_DEBUG_MORE, "TS : released x=%i y=%i (raw x=%i y=%i)", touch_xp, touch_yp, raw_touch_xp, raw_touch_yp);
was_touched = false;
}
#ifdef USE_TOUCH_BUTTONS
CheckTouchButtons(touched, touch_xp, touch_yp);
#endif // USE_TOUCH_BUTTONS