#ifndef _MODULE_UI_h #define _MODULE_UI_h #include #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 /// /// How to lay out the children of a given window /// enum ui_layout_mode : byte { /// /// Perform no layout, all children will overlap /// NONE = 0, /// /// Split vertically, windows laid out left to right /// SPLIT_VERTICAL = 1, /// /// Split horizontally, windows laid out top to bottom /// SPLIT_HORIZONTAL = 2, /// /// Manually lay out windows, each child must have its position and size set /// ABSOLUTE = 3 }; struct UiWindow; struct UiFont; /// /// Module to handle layout out and putting things on the screen /// class Module_UI : public Task, public IRunnable { /// /// 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 /// Module_Power* module_power; /// /// All registered/created windows /// UiWindow* m_window[MODULE_UI_MAX_WINDOWS]; /// /// All fonts registered with the UI system /// UiFont* m_font[MODULE_UI_MAX_FONTS]; /// /// Whether we've initialized the graphics hardware /// /// /// 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. /// bool m_initialized = false; /// /// Whether any windows have been marked as "dirty" (requiring a redraw) since the last draw /// bool m_dirty = false; /// /// Whether we desire a full-screen redraw at the next available opportunity /// bool m_redraw = false; /// /// Handle to the root window /// /// /// We only dirty / draw windows that exist somewhere underneath the root window /// 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. /// /// The X offset of the window we're currently drawing /// int m_draw_x; /// /// The Y offset of the window we're currently drawing /// int m_draw_y; /// /// The width of the window we're currently drawing /// int m_draw_w; /// /// The height of the window we're currently drawing /// int m_draw_h; /// /// Draw a window to screen, including all of its children /// /// window to draw /// x offset on screen to start at /// y offset on screen to start at /// width of the space to draw within /// height of the space to draw within 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(); /// /// Create a new window /// /// drawable object /// handle of a window to create this window under, WATCHOS_HANDLE_NULL for a root window /// handle of the newly created window kernel_handle_t createWindow(IDrawable* drawable, kernel_handle_t parent); /// /// Create a new placeholder window -- one that can have children, but is not drawn itself /// /// handle of the window to create this window under, WATCHOS_HANDLE_NULL for a root window /// handle of the newly created window kernel_handle_t createWindow(kernel_handle_t parent); /// /// Get the handle of the current root window /// /// handle of the current root window kernel_handle_t getRoot(); /// /// Set the current root window /// /// /// Triggers a full screen redraw /// /// handle of the window that should be the root window void setRoot(kernel_handle_t handle); void initialize(); void start(); void tick(); /// /// Trigger a draw /// /// /// Will either perform the draw synchronously (if multicore is disabled) or spawns a task /// on the other core to run the draw asynchronously. /// void draw(); /// /// Internal draw call, either called by draw() or indirectly if spawned on another core /// void do_draw(); /// /// Set the layout mode of a window /// /// handle of the window to set the layout mode of /// one of the layout mode enum void setLayoutMode(kernel_handle_t window_handle, ui_layout_mode layout_mode); /// /// Set the absolute position of an absolutely positioned window relative to parent /// /// /// This only has any effect if the parent window is set to absolute layout /// /// handle to set the location of /// x offset from parent /// y offset from parent /// width of window /// height of window void setAbsolutePosition(kernel_handle_t window_handle, byte x, byte y, byte w, byte h); /// /// Mark the window as dirty, requiring a draw /// /// handle of window to mark dirty void setDirty(kernel_handle_t window_handle); /// /// Get the width of the current window /// /// width in pixels int getWidth(); /// /// Get the height of the current window /// /// height in pixels int getHeight(); /// /// Fill the current window with the given colour /// /// colour to fill with; either COLOUR_PRIMARY or COLOUR_SECONDARY void fill(uint16_t colour = COLOUR_SECONDARY); /// /// Fill a portion of the current window with the given colour /// /// x offset within window /// y offset within window /// width of area to fill /// height of area to fill /// colour to fill with; either COLOUR_PRIMARY or COLOUR_SECONDARY void fill(int x, int y, int width, int height, uint16_t colour = COLOUR_SECONDARY); /// /// Print text to the screen /// /// x offset within window to place bottom left corner of text /// y offset within window to place bottom left corner of text /// text to write /// colour to render text with; either COLOUR_PRIMARY or COLOUR_SECONDARY /// pointer to GFXfont to use for text void print(int x, int y, char* str, uint16_t colour, void* font); /// /// Print text to the screen /// /// x offset within window to place bottom left corner of text /// y offset within window to place bottom left corner of text /// text to write /// colour to render text with; either COLOUR_PRIMARY or COLOUR_SECONDARY /// id of a registered font 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); /// /// Register a font with an id /// /// /// This can be passed to print(), avoids having to pull in the entire GFX library in order to /// print text. /// /// id to register the font with /// a pointer to a GFXfont void registerFont(byte id, const void* font); }; #endif