Lightweight and User-Friendly GUI Solution for Embedded Systems – LameUI

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

Lightweight and User-Friendly GUI Solution for Embedded Systems - LameUI

With the continuous development of information technology, embedded systems have become the core of various smart devices. These systems often face the challenge of limited resources, so it is particularly important to use lightweight and easy-to-implement libraries when developing user interfaces. LameUI has emerged as a lightweight and platform-independent graphical user interface library, aiming to provide developers with a simple UI solution, especially suitable for resource-constrained embedded systems. LameUI offers a rich set of components and features, including common elements such as images, text, buttons, and supports custom layouts and styles. In addition, LameUI also provides a flexible event handling mechanism and animation effects, allowing developers to easily implement complex interactive experiences. In summary, LameUI is a very practical and easy-to-use embedded graphical user interface library, which is of great significance for developing embedded systems.
Lightweight and User-Friendly GUI Solution for Embedded Systems - 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.

Lightweight and User-Friendly GUI Solution for Embedded Systems - LameUI

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.

Leave a Comment