Adam PIppin
3 years ago
15 changed files with 491 additions and 38 deletions
@ -1,10 +1,12 @@ |
|||
#ifndef _IDRAWABLE_h |
|||
#define _IDRAWABLE_h |
|||
|
|||
#include "watchos_types.h" |
|||
|
|||
class IDrawable |
|||
{ |
|||
public: |
|||
virtual void draw(int hwnd, int x, int y, int width, int height) = 0; |
|||
virtual void draw(kernel_handle_t handle) = 0; |
|||
}; |
|||
|
|||
#endif |
@ -0,0 +1,276 @@ |
|||
#include "watchos.h" |
|||
#include "Module_UI.h" |
|||
#include <GxEPD2_BW.h> |
|||
#include <Fonts/FreeMono12pt7b.h> |
|||
|
|||
GxEPD2_BW<GxEPD2_154_D67, GxEPD2_154_D67::HEIGHT> gfx = GxEPD2_154_D67(HW_DISPLAY_CS, HW_DISPLAY_DC, HW_DISPLAY_RESET, HW_DISPLAY_BUSY); |
|||
|
|||
struct UiWindow |
|||
{ |
|||
kernel_handle_t handle; |
|||
IDrawable* drawable; |
|||
byte layout_mode; |
|||
UiWindow* parent; |
|||
bool dirty; |
|||
}; |
|||
|
|||
void destruct_window(kernel_handle_t handle, void* object) |
|||
{ |
|||
} |
|||
|
|||
#ifdef WATCHOS_UI_MULTICORE |
|||
TaskHandle_t draw_task; |
|||
void draw_wrapper(void* parameter) |
|||
{ |
|||
Module_UI* ui = static_cast<Module_UI*>(parameter); |
|||
ui->do_draw(); |
|||
draw_task = nullptr; |
|||
vTaskDelete(NULL); |
|||
} |
|||
#endif |
|||
|
|||
Module_UI::Module_UI() |
|||
{ |
|||
for (int i = 0; i < MODULE_UI_MAX_WINDOWS; i++) |
|||
{ |
|||
m_window[i] = nullptr; |
|||
} |
|||
|
|||
m_root = createWindow(WATCHOS_HANDLE_NULL); |
|||
} |
|||
|
|||
void Module_UI::tick() |
|||
{ |
|||
draw(); |
|||
} |
|||
|
|||
kernel_handle_t Module_UI::createWindow(IDrawable* drawable, kernel_handle_t parent) |
|||
{ |
|||
for (int i = 0; i < MODULE_UI_MAX_WINDOWS; i++) |
|||
{ |
|||
if (m_window[i] == nullptr) |
|||
{ |
|||
m_window[i] = new UiWindow(); |
|||
m_window[i]->drawable = drawable; |
|||
m_window[i]->handle = watchos::kernel()->allocHandle(WATCHOS_HANDLE_TYPE_UI_WINDOW, m_window[i], (kernel_handle_destructor_t)destruct_window); |
|||
m_window[i]->layout_mode = MODULE_UI_LAYOUT_MODE_NONE; |
|||
m_window[i]->parent = nullptr; |
|||
m_window[i]->dirty = false; |
|||
|
|||
if (parent != WATCHOS_HANDLE_NULL) |
|||
{ |
|||
for (int j = 0; j < MODULE_UI_MAX_WINDOWS; j++) |
|||
{ |
|||
if (m_window[j] != nullptr && m_window[j]->handle == parent) |
|||
{ |
|||
m_window[i]->parent = m_window[j]; |
|||
break; |
|||
} |
|||
} |
|||
|
|||
if (m_window[i]->parent == nullptr) |
|||
{ |
|||
watchos::panic("Cannot find parent window handle %#010x", parent); |
|||
} |
|||
} |
|||
|
|||
return m_window[i]->handle; |
|||
} |
|||
} |
|||
|
|||
watchos::panic("Exceeded MODULE_UI_MAX_WINDOWS"); |
|||
} |
|||
|
|||
kernel_handle_t Module_UI::createWindow(kernel_handle_t parent) |
|||
{ |
|||
return createWindow(nullptr, parent); |
|||
} |
|||
|
|||
kernel_handle_t Module_UI::getRoot() |
|||
{ |
|||
return m_root; |
|||
} |
|||
|
|||
void Module_UI::draw() |
|||
{ |
|||
#ifdef WATCHOS_UI_MULTICORE |
|||
if (draw_task == nullptr) |
|||
{ |
|||
xTaskCreatePinnedToCore(draw_wrapper, "Draw", MODULE_UI_MULTICORE_STACK_SIZE, this, 0, &draw_task, 0); |
|||
} |
|||
#else |
|||
do_draw(); |
|||
#endif |
|||
} |
|||
|
|||
void Module_UI::do_draw() |
|||
{ |
|||
// TODO: Disable light/deep sleep
|
|||
|
|||
// Initialize gfx if necessary
|
|||
if (!m_initialized) |
|||
{ |
|||
m_initialized = true; |
|||
gfx.init(0, false); |
|||
} |
|||
|
|||
for (int i = 0; i < MODULE_UI_MAX_WINDOWS; i++) |
|||
{ |
|||
if (m_window[i] != nullptr && m_window[i]->handle == m_root) |
|||
{ |
|||
draw_window(m_window[i], 0, 0, DISPLAY_WIDTH, DISPLAY_HEIGHT); |
|||
break; |
|||
} |
|||
} |
|||
|
|||
// TODO: Redraw only parts of the screen if necessary, etc
|
|||
gfx.display(true); |
|||
|
|||
// TODO: Reenable sleep
|
|||
} |
|||
|
|||
void Module_UI::draw_window(UiWindow* window, int x, int y, int width, int height) |
|||
{ |
|||
m_draw_x = x; |
|||
m_draw_y = y; |
|||
m_draw_w = width; |
|||
m_draw_h = height; |
|||
|
|||
// Draw window
|
|||
if (window->drawable != nullptr) |
|||
{ |
|||
window->drawable->draw(window->handle); |
|||
} |
|||
|
|||
// Count children
|
|||
int child_count = 0; |
|||
for (int i = 0; i < MODULE_UI_MAX_WINDOWS; i++) |
|||
{ |
|||
if (m_window[i] != nullptr && m_window[i]->parent == window) |
|||
{ |
|||
child_count++; |
|||
} |
|||
} |
|||
|
|||
if (child_count == 0) |
|||
{ |
|||
// No children to draw, we're done!
|
|||
return; |
|||
} |
|||
|
|||
int child_offset = 0; |
|||
int child_width, child_height; |
|||
switch (window->layout_mode) |
|||
{ |
|||
case MODULE_UI_LAYOUT_MODE_NONE: |
|||
for (int i = 0; i < MODULE_UI_MAX_WINDOWS; i++) |
|||
{ |
|||
if (m_window[i] != nullptr && m_window[i]->parent == window) |
|||
{ |
|||
draw_window(m_window[i], x, y, width, height); |
|||
} |
|||
} |
|||
break; |
|||
case MODULE_UI_LAYOUT_MODE_SPLIT_HORIZONTAL: |
|||
child_height = height / child_count; |
|||
for (int i = 0; i < MODULE_UI_MAX_WINDOWS; i++) |
|||
{ |
|||
if (m_window[i] != nullptr && m_window[i]->parent == window) |
|||
{ |
|||
draw_window(m_window[i], x, y + (child_offset++ * child_height), width, child_height); |
|||
} |
|||
} |
|||
break; |
|||
case MODULE_UI_LAYOUT_MODE_SPLIT_VERTICAL: |
|||
child_width = width / child_count; |
|||
for (int i = 0; i < MODULE_UI_MAX_WINDOWS; i++) |
|||
{ |
|||
if (m_window[i] != nullptr && m_window[i]->parent == window) |
|||
{ |
|||
draw_window(m_window[i], x + (child_offset++ * child_width), y, child_width, height); |
|||
} |
|||
} |
|||
break; |
|||
case MODULE_UI_LAYOUT_MODE_ABSOLUTE: |
|||
// TODO:
|
|||
break; |
|||
} |
|||
} |
|||
|
|||
void Module_UI::setLayoutMode(kernel_handle_t window_handle, byte layout_mode) |
|||
{ |
|||
for (int i = 0; i < MODULE_UI_MAX_WINDOWS; i++) |
|||
{ |
|||
if (m_window[i] != nullptr && m_window[i]->handle == window_handle) |
|||
{ |
|||
m_window[i]->layout_mode = layout_mode; |
|||
return; |
|||
} |
|||
} |
|||
watchos::panic("Trying to set layout mode on non-existent handle: %#010x", window_handle); |
|||
} |
|||
|
|||
void Module_UI::setDirty(kernel_handle_t window_handle) |
|||
{ |
|||
for (int i = 0; i < MODULE_UI_MAX_WINDOWS; i++) |
|||
{ |
|||
if (m_window[i] != nullptr && m_window[i]->handle == window_handle) |
|||
{ |
|||
m_window[i]->dirty = true; |
|||
m_dirty = true; |
|||
return; |
|||
} |
|||
} |
|||
watchos::panic("Trying to set dirty non-existent window handle: %#010x", window_handle); |
|||
} |
|||
|
|||
int Module_UI::getWidth() |
|||
{ |
|||
return m_draw_w; |
|||
} |
|||
|
|||
int Module_UI::getHeight() |
|||
{ |
|||
return m_draw_h; |
|||
} |
|||
|
|||
void Module_UI::fill(uint16_t colour) |
|||
{ |
|||
fill(m_draw_x, m_draw_y, m_draw_w, m_draw_h, colour); |
|||
} |
|||
|
|||
void Module_UI::fill(int x, int y, int width, int height, uint16_t colour) |
|||
{ |
|||
local_to_screen(&x, &y); |
|||
gfx.fillRect(x, y, width, height, colour); |
|||
} |
|||
|
|||
void Module_UI::print(int x, int y, char* str, uint16_t colour, void* font) |
|||
{ |
|||
local_to_screen(&x, &y); |
|||
gfx.setCursor(x, y); |
|||
gfx.setTextColor(colour); |
|||
if (font == nullptr) |
|||
{ |
|||
gfx.setFont(&FreeMono12pt7b); |
|||
} |
|||
else |
|||
{ |
|||
gfx.setFont(static_cast<GFXfont*>(font)); |
|||
} |
|||
gfx.print(str); |
|||
} |
|||
|
|||
void Module_UI::local_to_screen(int* x, int* y) |
|||
{ |
|||
// TODO: Check bounds?
|
|||
if (x < 0) |
|||
*x = (m_draw_w - *x) + m_draw_x; |
|||
else |
|||
*x = m_draw_x + *x; |
|||
|
|||
if (y < 0) |
|||
*y = (m_draw_h - *y) + m_draw_y; |
|||
else |
|||
*y = m_draw_y + *y; |
|||
} |
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -1,25 +1,27 @@ |
|||
/*
|
|||
Name: watchos2.ino |
|||
Created: 6/30/2021 9:38:10 PM |
|||
Author: Adam |
|||
*/ |
|||
/*
|
|||
Name: watchos2.ino |
|||
Created: 6/30/2021 9:38:10 PM |
|||
Author: Adam |
|||
*/ |
|||
|
|||
#include "watchos.h" |
|||
#include "Task_Test.cpp" |
|||
#include <Preferences.h> |
|||
|
|||
#include "watchos.h" |
|||
#include "Task_Test.cpp" |
|||
#include <Preferences.h> |
|||
|
|||
// the setup function runs once when you press reset or power the board
|
|||
void setup() { |
|||
delay(500); |
|||
watchos::initialize(); |
|||
Kernel* kernel = watchos::kernel(); |
|||
watchos::run(new Task_Test()); |
|||
watchos::debug("Setup done!"); |
|||
kernel->pushEvent(0xDEADBEEFu, 0x01, 0x10, 0x20); |
|||
|
|||
} |
|||
|
|||
// the loop function runs over and over again until power down or reset
|
|||
void loop() { |
|||
watchos::kernel()->tick(); |
|||
} |
|||
void setup() { |
|||
delay(500); |
|||
watchos::initialize(); |
|||
Kernel* kernel = watchos::kernel(); |
|||
kernel->registerTask(new Module_UI(), WATCHOS_MODULE_UI); |
|||
watchos::run(new Task_Test()); |
|||
watchos::debug("Setup done!"); |
|||
kernel->pushEvent(0xDEADBEEFu, 0x01, 0x10, 0x20); |
|||
|
|||
} |
|||
|
|||
// the loop function runs over and over again until power down or reset
|
|||
void loop() { |
|||
watchos::debug("Tick!"); |
|||
watchos::kernel()->tick(); |
|||
} |
|||
|
File diff suppressed because one or more lines are too long
@ -0,0 +1,13 @@ |
|||
#ifndef _WATCHOS_CONFIG_h |
|||
#define _WATCHOS_CONFIG_h |
|||
|
|||
// If defined, enable debugging output.
|
|||
#define WATCHOS_DEBUG |
|||
|
|||
// If defined, use black background + white fg
|
|||
#define WATCHOS_DARK_MODE |
|||
|
|||
// If defined, use the second core for drawing
|
|||
#define WATCHOS_UI_MULTICORE |
|||
|
|||
#endif |
@ -1,14 +1,23 @@ |
|||
#ifndef _WATCHOS_CONSTS_h |
|||
#define _WATCHOS_CONSTS_h |
|||
|
|||
// If defined, enable debugging output.
|
|||
#define WATCHOS_DEBUG |
|||
#include "watchos_config.h" |
|||
|
|||
#define WATCHOS_WK_TEST 0x00000001 |
|||
#ifdef WATCHOS_DARK_MODE |
|||
#define COLOUR_PRIMARY 0xFFFF // white
|
|||
#define COLOUR_SECONDARY 0x0000 // black
|
|||
#else |
|||
#define COLOUR_PRIMARY 0x0000 // black
|
|||
#define COLOUR_SECONDARY 0xFFFF // white
|
|||
#endif |
|||
|
|||
#define WATCHOS_MODULE_UI 0x00000001 |
|||
|
|||
#define WATCHOS_HANDLE_NULL 0x00000000 |
|||
|
|||
#define WATCHOS_HANDLE_TYPE_TASK 0x01 |
|||
#define WATCHOS_HANDLE_TYPE_EVENT 0x02 |
|||
#define WATCHOS_HANDLE_TYPE_EVENT_SUBSCRIPTION 0x03 |
|||
#define WATCHOS_HANDLE_TYPE_UI_WINDOW 0x04 |
|||
|
|||
#endif |
Loading…
Reference in new issue