Project Address:https://github.com/abhra0897/LameUI

Features of LameUI
Super Simple:
One of LameUI’s design principles is simplicity and ease of use. It provides a set of basic UI elements, such as buttons and text boxes, allowing developers to quickly implement basic user interfaces. This is very important for resource-constrained embedded systems. It achieves efficient operating performance by using minimal files and memory, making it very suitable for small embedded devices (such as ESP32, Arduino, etc.).
Platform Independent:
Another important feature is the platform independence of LameUI. Whether based on ARM architecture or MIPS architecture embedded systems, LameUI can work well without special adaptations, greatly facilitating developers.
Low Resource Consumption:
LameUI is designed for low-resource environments, so its consumption of system resources is very low. This means that even on embedded devices with limited memory and processor speed, LameUI can run well, providing users with a smooth interface experience.
Diverse UI Component Support
LameUI currently implements various basic UI components, such as labels, buttons, sliders, checkboxes, text boxes, etc. These components enable developers to create colorful user interfaces that meet the needs of different application scenarios.
Basic Usage of LameUI
Quick Start
Using the TFT_eSPI library for a simple example on the Arduino framework. In this example, we will only see how to register the display driver and touch input device, without adding any UI components.
// This example uses TFT_eSPI library on Arduino framework// Hardware: [MCU = ESP32, Display: ILI9341, Touch IC = XPT2046]
#include <TFT_eSPI.h> // Graphics and font library for ILI9341 driver chip
#include <SPI.h>// ... [ Include LameUI library and other required headers too] ...
#define HOR_RES 320#define VERT_RES 240#define DISP_BUFF_PX_CNT (HOR_RES * 10)
uint16_t disp_buffer[DISP_BUFF_PX_CNT];
TFT_eSPI tft = TFT_eSPI(); // Invoke library
uint8_t lui_memory[4000];
void draw_disp_buff_cb(uint16_t* disp_buff, lui_area_t* area);{
tft.setAddrWindow(area->x, area->y, area->w, area->h);
tft.pushColors(disp_buff, (area->w * area->h), 1);}
void read_touch_input_cb(lui_touch_input_data_t* inputdata){
uint16_t x = 0, y = 0; // To store the touch coordinates
// Pressed will be set true is there is a valid touch on the screen
bool pressed = tft.getTouch(&x, &y);
inputdata->is_pressed = pressed;
if (pressed) {
inputdata->x = x;
inputdata->y = y;
}
else {
inputdata->x = -1;
inputdata->y = -1;
}}
void setup(void) {
// Initialize tft
tft.init();
tft.setTouch(touch_cal_data);
// Initialize LameUI with some memory
lui_init(lui_memory, sizeof(lui_memory));
// Create a display driver object
lui_dispdrv_t* display_driver = lui_dispdrv_create();
lui_dispdrv_register(display_driver);
lui_dispdrv_set_resolution(display_driver, HOR_RES, VERT_RES);
lui_dispdrv_set_disp_buff(my_display_driver, disp_buffer, DISP_BUFF_PX_CNT);
lui_dispdrv_set_draw_disp_buff_cb(my_display_driver, draw_disp_buff_cb);
// Create touch input device
lui_touch_input_dev_t* input_device = lui_touch_inputdev_create();
lui_touch_inputdev_register(input_device);
lui_touch_inputdev_set_read_input_cb(input_device, read_touch_input_cb);
// ... [Add scene (mandatory) and other widgets] ...}
void loop(){ // Must update the UI periodically lui_update();
// ... [Do other stuffs] ...}
Creating UI Components
Next, you can create different UI components such as buttons and labels using LameUI. Here is an example of how to implement buttons and labels:
#include<stdio.h>#include "LameUI/lame_ui.h"//... other required includes ....
#define HOR_RES 320#define VERT_RES 240
// [Mandatory] Display buffer. Buffer pixel count must be multiple of Horizontal Resolution
#define DISP_BUFF_PX_CNT (HOR_RES * 10)uint16_t disp_buffer[DISP_BUFF_PX_CNT];
// [Mandatory] LameUI memory. Here we are giving it 2KB to work with.uint8_t lameui_memory[2000];
//----------- callback function prototypes ------------
void my_draw_disp_buff_cb (uint16_t* disp_buff, lui_area_t* area);
void my_input_read_cb (lui_touch_input_data_t *input);
void button_1_cb(lui_obj_t* button_obj);//-----------------------------------------------------
int main (){ // [Mandatory] At the starting, initialize LameUI with some working memory. // This memory is used to create objects lui_init(lameui_memory, sizeof(lameui_memory));
//---------------------------------------------------------- //[Mandatory] creating display driver object lui_dispdrv_t *my_display_driver = lui_dispdrv_create(); lui_dispdrv_register(my_display_driver); lui_dispdrv_set_resolution(my_display_driver, HOR_RES, VERT_RES); lui_dispdrv_set_disp_buff(my_display_driver, disp_buffer, DISP_BUFF_PX_CNT); lui_dispdrv_set_draw_disp_buff_cb(my_display_driver, my_draw_disp_buff_cb);
//[Optional] creating input device object lui_touch_input_dev_t *my_input_device = lui_touch_inputdev_create(); lui_touch_inputdev_register(my_input_device); lui_touch_inputdev_set_read_input_cb(my_input_device, my_input_read_cb);
//---------------------------------------------------------- //[Mandatory] create and add a scene // There must be at least one scene. It is at the top of the hierarchy. All // other objects will be under the hierarchy of a scene. There can be multiple // scenes. A particular object can be under only one scene at a time. lui_obj_t* scene_1 = lui_scene_create(); // [Mandatory] A scene must be set as active scene. Only the active scene // is rendered. lui_scene_set_active(scene_1);
// Create a label lui_obj_t* label_1 = lui_label_create(); // [Mandatory] An object must have a parent which is either a `scene` or a // descendent of `scene`. lui_object_add_to_parent(label_1, scene_1); lui_object_set_position(label_1, 5, 50); lui_label_set_text(label_1, "This is Label 1. Below is Button 1");
// Create a button lui_obj_t* button_1 = lui_button_create(); // [Mandatory] Add a parent lui_object_add_to_parent(button_1, scene_1); lui_object_set_area(button_1, 110, 40); lui_object_set_position(button_1, 65, 100); lui_button_set_label_text(button_1, "Button 1"); lui_object_set_callback(button_1, button_1_cb);
while (1) { // LameUI has no built-in timer. So, update LameUI periodically. // lui_update() function reads inputs, checks if anything needs to be drawn, and fires callbacks if and when needed. lui_update(); sleep_ms(15); }
return 0;}
//----------- callback function definitions ------------
void my_draw_disp_buff_cb(uint16_t* disp_buff, lui_area_t* area);{ uint16_t x = area->x; // start x uint16_t y = area->y; // start y uint16_t w = area->w; // width uint16_t h = area->h; // height display_draw_buffer(disp_buff, x, y, w, h);}
void my_input_read_cb (lui_touch_input_data_t *input){ // Assuming that user has a function display_get_touch() that returns a `touch_data_t` variable. // Also assuming that members of `touch_data_t` are: pressed(uint8_t), x(uint16_t), y(uint16_t). touch_data_t touch = display_get_touch();
input->is_pressed = touch.pressed; // `touch.pressed` should be 1 if touched, 0 if not touched if (input->is_pressed == 1) { input->y = touch.y; input->x = touch.x; } else { // IMPORTANT: User MUST set x and y as -1 when display is NOT touched. input->y = -1; input->x = -1; }}
void button_1_cb(lui_obj_t* button_obj){ // Get the event of callback int8_t event = lui_object_get_event(button_obj); if (event == -1) return; if (event == LUI_EVENT_PRESSED) { // Button is pressed. Do something fprintf(stderr, "Button 1 is pressed"); } else if (event == LUI_EVENT_RELEASED) { // Button is released. Do something fprintf(stderr, "Button 1 is released"); }}
Conclusion
LameUI is a lightweight graphical user interface library that is very suitable for embedded systems. It features simplicity and efficient performance, allowing both experienced developers and beginners to quickly get started and meet different project needs.