Simple GUIs

sample implementation check apps in example folders

Canvas

the fundation of our UI, a drawable area where GUI components like text and icons can be rendered.

  • __init__(self, width, height, background_color='white', init_image=None)

    • Initializes a new Canvas object with specified dimensions and optional background color and initial image.
    • Parameters:
      • init_image: An optional initial image to start with, if not provided, will be default white.
  • register_canvas_image(self)

    • Saves the current state of the canvas image as a checkpoint, next flush wont erase everything.
  • flush(self)

    • Resets the canvas image to the last checkpoint or to a new blank image if no checkpoint is set.
  • get_draw(self)

    • Returns a canvas as Image object.
  • draw_plus_pattern(self, density=10, start_pos=(5, 5), size=5)

    • Example of a pattern darwing to make the background pretty, a grid of plus (’+’) patterns across the canvas.

GUIComponent

A base class for GUI components that can be drawn on a canvas.

  • __init__(self, position=(0, 0))
    • Initialize the GUI component with a position (where the top left corner start).

Text

Text - a GUI component.

  • __init__(self, text, font_path, font_size)
    • Parameters:
      • font_path: any font file end with .ttf should work
  • draw(self, canvas, position, centered=False, max_width=None)
    • given the canvas object to draw on, with the starting position.
    • Parameters:
      • centered: if true it will ignore the x position and force fit at center
      • max_width: character over max_width will be trimed

Icon

Icon - a GUI component.

  • __init__(self, position, icon_path, height=32, padding=5)
    • Parameters:
      • position: Position (x, y) on the canvas.
      • icon_path: Path to the icon image (should have white background).
      • height : adjust the icon w,h ratio based on the height
  • draw(self, canvas)
    • given the canvas object to draw on, with the starting position.

Box

Represents a rectangular box that can be filled or outlined - part of the GUI.

  • __init__(self, position, size, fill=False, corner_radius=0, line_thickness=2, padding=3)

    • Initializes a Box component.
    • Parameters:
      • position: A tuple (x, y) representing the box’s position on the canvas.
      • size: A tuple (width, height) representing the dimensions of the box.
      • fill: Boolean indicating whether the box should be filled.
      • corner_radius: The radius of the box’s corners.
      • line_thickness: Thickness of the box’s outline.
      • padding: Padding inside the box.
  • draw(self, canvas)

    • Draws the box on the specified canvas.
  • invert_region(self, canvas)

    • Inverts colors of the region within the box, normally used to indicate selections

TextBox

Box + Text

  • __init__(self, text, font_path, font_size, icon_path=None, size=None, position=(0, 0), fill=False, corner_radius=1, line_thickness=0, padding=0)

    • Parameters:
      • same as box and text param
  • draw(self, canvas)

    • Draws the box, text and icon (optional) on the specified canvas.

GUI

Interface level class, managing all sub components.

  • __init__(self, width, height, **kwargs)

    • Initializes a GUI with specific dimensions.
    • additional Parameters (kwargs) can be init_image for init canvas and position
  • add_component(self, component)

    • add Text, Box or Icon object to the GUI
  • render_all(self)

    • render all objects on the canvas image
  • paste_image(self, image, position)

    • manually add an image to the gui canvas

ScrollGUI

Interface level class, GUI but specific designed for list of TextBox to serve as a scroll menu

  • __init__(self, width: int, height: int, bounding_box: tuple[int, int, int, int], line_space: int = 1, **kwargs)

    • Parameters:
      • width/height: size of the scroll box
      • bounding_box : x, y , max_x, max_y to describe the drawing area for the texts
      • line_space : space between list of textbox
  • get_selected_component(self)

    • based on index id, return the selected component
  • inject_texts(self, content: str, font_path: Optional[str] = DEFAULT_FONT_PATH, font_size: Optional[int] = 20)

    • a helper function to auto split the text to make sure everything fit into the bounding box
  • render_scroll

    • render the list of textboxes but also highlight the selected on (inverting color)
    • if used list of text obejct instead of textbox, it will render and disply one text object at a time

Page

Represents a page within the application that can be displayed on the e-ink screen.

  • __init__(self, app)

    • Initializes a new Page instance.
    • Parameters:
      • app: The application instance to which this page belongs.
  • render_page(self, image, **kwargs)

    • Renders the page with the given image.
    • Parameters:
      • image: The image to render on the page.
      • kwargs: Additional keyword arguments to pass to app.update_screen.
  • handle_input(self, input)

    • Method to handle button clicks. should be overrided to serve different apps

Application

Manages the lifecycle and rendering of pages on an e-ink display.

  • __init__(self)

    • Initializes the Application instance, setting up the e-ink screen and buttons peripherals.
  • switch_page(self, NewPage, **kwargs)

    • Switches to a new page within the application.
    • Parameters:
      • NewPage: The new page class to switch to.
      • kwargs: Additional keyword arguments for the new page.
  • update_screen(self, image, format='1bit', dithering=True)

    • Updates the e-ink screen with the given image.
    • Parameters:
      • image: The image to display.
      • format: The format of the image (‘1bit’ or ‘2bit’). 1bit is black and white, 2bit will have grey grad but slower to fresh the screen.
      • dithering: Whether to apply dithering (only applicable for ‘1bit’ format), so basically if its just black and white texts we dont need dithering to speed up the process.
  • press_callback(self, key)

    • Callback function for button presses.
    • Parameters:
      • key: The button that was pressed. (default 0 = up, 1 = down, 2 = enter)
  • _get_system_stats(self)

    • Retrieves the current system statistics such as CPU and RAM usage.
    • Returns:
      • A string representing the CPU and RAM usage.

Peripherals interfaces

Button

Handles button interactions and manages shutdown procedures, a child class of SAM (Signal Aggregation Module) our more lower level base class.

  • __init__(self, callback)

    • Initializes the Button with a callback function to handle button states.
    • Parameters :
      • callback: A callback function that processes button state changes.
  • process_button_state(self, state)

    • Processes the received button state and triggers the appropriate callback.
    • Parameters :
      • state: The button state byte to process.
  • press_callback(self, key)

    • Hijack the button press events callback to this one.
    • Parameters :
      • key: The identifier of the button that was pressed.
  • shutdown(self)

    • In the shutdown menu we wrote a hack way to hijack the screen from user, so the button press handle will be moved to the confirm screen

Cam

Cam operations including configuration, preview, and image capturing, specifically designed for use with an e-ink display.

  • __init__(self, eink)

    • Initializes the Cam class with an e-ink display object.
    • Parameters:
      • eink: The e-ink display object to which images will be sent.
  • _config(self)

    • Configures the camera settings for both preview and still capture modes, including image size and transformation such as horizontal and vertical flips.
    • To use your own customized cam setting, check out picamera2 lib
  • preview(self)

    • Starts the camera preview in a separate thread to continuously update the e-ink display with new images.
  • _start_cam(self, thread_event)

    • Initializes and starts the camera, capturing images in a loop until the thread is stopped. Updates the e-ink display with processed images.
    • Parameters:
      • thread_event: A threading.Event object used to control the execution of the thread.
  • capture(self)

    • Captures an image, stops the camera, saves the image to disk, and stops the thread worker.
    • Returns:
      • Optional[Image.Image]: The captured image if available, otherwise None.

Eink

Manages an e-ink display, handling animations, screen updates, and transitions between different bit modes.

  • start_animation Starts an animation on the e-ink display using images from a specified folder.

    • Parameters:
      • canvas_image (Image.Image): The background image for the animation.
      • image_folder (str): The directory containing the animation images.
  • stop_animation Stops the currently running animation.

  • transit_to_1bit Transitions the display to 1-bit byte array, for the eink firmware to consume.

  • clear_screen Clears the e-ink screen, setting it to a blank state.

  • update_screen_1bit Updates the e-ink display with a provided image in 1-bit format.

    • Parameters:
      • image (Image.Image): The image to display.
      • dithering (bool): Whether to apply dithering algo to the image.
  • update_screen_2bit Updates the e-ink display with a provided image in 2-bit format.

    • Parameters:
      • image (Image.Image): The image to display.
  • _status_check Checks and updates the display status to ensure proper mode transitions. this need to called whenever 2bit transite to 1bit

  • preprocess_1bit Prepares an image for 1-bit display.

    • Parameters:
      • image (Image.Image): The image to preprocess.
      • dtype (np.dtype): The data type for the numpy array, uint8 if no dithering else float32
  • preprocess_2bit Prepares an image for 2-bit display.

    • Parameters:
      • image (Image.Image): The image to preprocess.

AudioRecorder

Handles the audio recording process using pyaudio.

  • __init__(self)

    • Initializes the AudioRecorder, setting up pyaudio instantiation.
  • record_control(self)

    • Controls the start and stop of the recording.
    • Returns:
      • bool: True if recording started, False if stopped.
  • start_record(self)

    • Starts the audio recording.
    • Opens an audio stream and begins reading data into a buffer.
  • stop_record(self)

    • Stops the audio recording and closes the audio stream.
  • _record_loop(self, thread_event)

    • Continuously records audio while the thread event is set.
    • Parameters:
      • thread_event (threading.Event): Controls the active state of the recording loop.
  • save_wav(self)

    • Saves the recorded audio data to a .wav file.
    • Sets the channels, sample width, and frame rate for the .wav file before writing.

Audio/Speaker Functions

Plays an audio file specified by its path.

  • Parameters:
    • audio_path (str): The file path of the .wav audio file to be played.