You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
263 lines
9.0 KiB
263 lines
9.0 KiB
#ifndef _MODULE_UI_h
|
|
#define _MODULE_UI_h
|
|
|
|
#include <Arduino.h>
|
|
#include "watchos_consts.h"
|
|
#include "watchos_hw.h"
|
|
#include "watchos_types.h"
|
|
|
|
#include "Task.h"
|
|
#include "Module_Power.h"
|
|
#include "IRunnable.h"
|
|
#include "IDrawable.h"
|
|
|
|
// The maximum number of windows that can be created within the UI system.
|
|
#define MODULE_UI_MAX_WINDOWS 32
|
|
// The maximum number of fonts that can be registered with the UI system.
|
|
#define MODULE_UI_MAX_FONTS 32
|
|
|
|
/// <summary>
|
|
/// How to lay out the children of a given window
|
|
/// </summary>
|
|
enum ui_layout_mode : byte {
|
|
/// <summary>
|
|
/// Perform no layout, all children will overlap
|
|
/// </summary>
|
|
NONE = 0,
|
|
/// <summary>
|
|
/// Split vertically, windows laid out left to right
|
|
/// </summary>
|
|
SPLIT_VERTICAL = 1,
|
|
/// <summary>
|
|
/// Split horizontally, windows laid out top to bottom
|
|
/// </summary>
|
|
SPLIT_HORIZONTAL = 2,
|
|
/// <summary>
|
|
/// Manually lay out windows, each child must have its position and size set
|
|
/// </summary>
|
|
ABSOLUTE = 3
|
|
};
|
|
|
|
struct UiWindow;
|
|
struct UiFont;
|
|
|
|
/// <summary>
|
|
/// Module to handle layout out and putting things on the screen
|
|
/// </summary>
|
|
class Module_UI : public Task, public IRunnable
|
|
{
|
|
/// <summary>
|
|
/// Reference to the power module so we can disable sleep while draws are in progress; the display chip
|
|
/// doesn't like it when you kill power mid-draw
|
|
/// </summary>
|
|
Module_Power* module_power;
|
|
|
|
/// <summary>
|
|
/// All registered/created windows
|
|
/// </summary>
|
|
UiWindow* m_window[MODULE_UI_MAX_WINDOWS];
|
|
/// <summary>
|
|
/// All fonts registered with the UI system
|
|
/// </summary>
|
|
UiFont* m_font[MODULE_UI_MAX_FONTS];
|
|
|
|
/// <summary>
|
|
/// Whether we've initialized the graphics hardware
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// This has to be done after every power-on (reset or deep sleep), but we do it lazily since it's often
|
|
/// not necessary and is time consuming.
|
|
/// </remarks>
|
|
bool m_initialized = false;
|
|
|
|
/// <summary>
|
|
/// Whether any windows have been marked as "dirty" (requiring a redraw) since the last draw
|
|
/// </summary>
|
|
bool m_dirty = false;
|
|
/// <summary>
|
|
/// Whether we desire a full-screen redraw at the next available opportunity
|
|
/// </summary>
|
|
bool m_redraw = false;
|
|
|
|
/// <summary>
|
|
/// Handle to the root window
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// We only dirty / draw windows that exist somewhere underneath the root window
|
|
/// </remarks>
|
|
kernel_handle_t m_root;
|
|
|
|
|
|
// We track these values so methods like print/fill/etc can be aware of context when called by
|
|
// tasks and automatically draw within their allocated space.
|
|
|
|
/// <summary>
|
|
/// The X offset of the window we're currently drawing
|
|
/// </summary>
|
|
int m_draw_x;
|
|
/// <summary>
|
|
/// The Y offset of the window we're currently drawing
|
|
/// </summary>
|
|
int m_draw_y;
|
|
/// <summary>
|
|
/// The width of the window we're currently drawing
|
|
/// </summary>
|
|
int m_draw_w;
|
|
/// <summary>
|
|
/// The height of the window we're currently drawing
|
|
/// </summary>
|
|
int m_draw_h;
|
|
|
|
/// <summary>
|
|
/// Draw a window to screen, including all of its children
|
|
/// </summary>
|
|
/// <param name="window">window to draw</param>
|
|
/// <param name="x">x offset on screen to start at</param>
|
|
/// <param name="y">y offset on screen to start at</param>
|
|
/// <param name="width">width of the space to draw within</param>
|
|
/// <param name="height">height of the space to draw within</param>
|
|
void draw_window(UiWindow* window, int x, int y, int width, int height);
|
|
void local_to_screen(int* x, int* y);
|
|
void get_screen_coordinates(UiWindow* window, int* x, int* y);
|
|
|
|
public:
|
|
Module_UI();
|
|
|
|
/// <summary>
|
|
/// Create a new window
|
|
/// </summary>
|
|
/// <param name="drawable">drawable object</param>
|
|
/// <param name="parent">handle of a window to create this window under, WATCHOS_HANDLE_NULL for a root window</param>
|
|
/// <returns>handle of the newly created window</returns>
|
|
kernel_handle_t createWindow(IDrawable* drawable, kernel_handle_t parent);
|
|
/// <summary>
|
|
/// Create a new placeholder window -- one that can have children, but is not drawn itself
|
|
/// </summary>
|
|
/// <param name="parent">handle of the window to create this window under, WATCHOS_HANDLE_NULL for a root window</param>
|
|
/// <returns>handle of the newly created window</returns>
|
|
kernel_handle_t createWindow(kernel_handle_t parent);
|
|
|
|
/// <summary>
|
|
/// Get the handle of the current root window
|
|
/// </summary>
|
|
/// <returns>handle of the current root window</returns>
|
|
kernel_handle_t getRoot();
|
|
|
|
/// <summary>
|
|
/// Set the current root window
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// Triggers a full screen redraw
|
|
/// </remarks>
|
|
/// <param name="handle">handle of the window that should be the root window</param>
|
|
void setRoot(kernel_handle_t handle);
|
|
|
|
void initialize();
|
|
void start();
|
|
void tick();
|
|
|
|
/// <summary>
|
|
/// Trigger a draw
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// Will either perform the draw synchronously (if multicore is disabled) or spawns a task
|
|
/// on the other core to run the draw asynchronously.
|
|
/// </remarks>
|
|
void draw();
|
|
|
|
/// <summary>
|
|
/// Internal draw call, either called by draw() or indirectly if spawned on another core
|
|
/// </summary>
|
|
void do_draw();
|
|
|
|
/// <summary>
|
|
/// Set the layout mode of a window
|
|
/// </summary>
|
|
/// <param name="window_handle">handle of the window to set the layout mode of</param>
|
|
/// <param name="layout_mode">one of the layout mode enum</param>
|
|
void setLayoutMode(kernel_handle_t window_handle, ui_layout_mode layout_mode);
|
|
|
|
/// <summary>
|
|
/// Set the absolute position of an absolutely positioned window relative to parent
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// This only has any effect if the parent window is set to absolute layout
|
|
/// </remarks>
|
|
/// <param name="window_handle">handle to set the location of</param>
|
|
/// <param name="x">x offset from parent</param>
|
|
/// <param name="y">y offset from parent</param>
|
|
/// <param name="w">width of window</param>
|
|
/// <param name="h">height of window</param>
|
|
void setAbsolutePosition(kernel_handle_t window_handle, byte x, byte y, byte w, byte h);
|
|
|
|
/// <summary>
|
|
/// Mark the window as dirty, requiring a draw
|
|
/// </summary>
|
|
/// <param name="window_handle">handle of window to mark dirty</param>
|
|
void setDirty(kernel_handle_t window_handle);
|
|
|
|
/// <summary>
|
|
/// Get the width of the current window
|
|
/// </summary>
|
|
/// <returns>width in pixels</returns>
|
|
int getWidth();
|
|
/// <summary>
|
|
/// Get the height of the current window
|
|
/// </summary>
|
|
/// <returns>height in pixels</returns>
|
|
int getHeight();
|
|
|
|
/// <summary>
|
|
/// Fill the current window with the given colour
|
|
/// </summary>
|
|
/// <param name="colour">colour to fill with; either COLOUR_PRIMARY or COLOUR_SECONDARY</param>
|
|
void fill(uint16_t colour = COLOUR_SECONDARY);
|
|
|
|
/// <summary>
|
|
/// Fill a portion of the current window with the given colour
|
|
/// </summary>
|
|
/// <param name="x">x offset within window</param>
|
|
/// <param name="y">y offset within window</param>
|
|
/// <param name="width">width of area to fill</param>
|
|
/// <param name="height">height of area to fill</param>
|
|
/// <param name="colour">colour to fill with; either COLOUR_PRIMARY or COLOUR_SECONDARY</param>
|
|
void fill(int x, int y, int width, int height, uint16_t colour = COLOUR_SECONDARY);
|
|
|
|
/// <summary>
|
|
/// Print text to the screen
|
|
/// </summary>
|
|
/// <param name="x">x offset within window to place bottom left corner of text</param>
|
|
/// <param name="y">y offset within window to place bottom left corner of text</param>
|
|
/// <param name="str">text to write</param>
|
|
/// <param name="colour">colour to render text with; either COLOUR_PRIMARY or COLOUR_SECONDARY</param>
|
|
/// <param name="font">pointer to GFXfont to use for text</param>
|
|
void print(int x, int y, char* str, uint16_t colour, void* font);
|
|
/// <summary>
|
|
/// Print text to the screen
|
|
/// </summary>
|
|
/// <param name="x">x offset within window to place bottom left corner of text</param>
|
|
/// <param name="y">y offset within window to place bottom left corner of text</param>
|
|
/// <param name="str">text to write</param>
|
|
/// <param name="colour">colour to render text with; either COLOUR_PRIMARY or COLOUR_SECONDARY</param>
|
|
/// <param name="font_id">id of a registered font</param>
|
|
void print(int x, int y, char* str, uint16_t colour = COLOUR_PRIMARY, byte font_id = 0);
|
|
|
|
void rectangle(int x, int y, int w, int h, uint16_t colour = COLOUR_PRIMARY);
|
|
void fillRectangle(int x, int y, int w, int h, uint16_t colour = COLOUR_PRIMARY);
|
|
void line(int x0, int y0, int x1, int y1, uint16_t colour = COLOUR_PRIMARY);
|
|
void horizontalLine(int y, uint16_t colour = COLOUR_PRIMARY);
|
|
void verticalLine(int x, uint16_t colour = COLOUR_PRIMARY);
|
|
|
|
/// <summary>
|
|
/// Register a font with an id
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// This can be passed to print(), avoids having to pull in the entire GFX library in order to
|
|
/// print text.
|
|
/// </remarks>
|
|
/// <param name="id">id to register the font with</param>
|
|
/// <param name="font">a pointer to a GFXfont</param>
|
|
void registerFont(byte id, const void* font);
|
|
};
|
|
|
|
#endif
|