Browse Source

UI stuff

master
Adam PIppin 3 years ago
parent
commit
27fb0ad4d7
  1. 4
      watchos2/IDrawable.h
  2. 4
      watchos2/Kernel.cpp
  3. 2
      watchos2/Kernel.h
  4. 276
      watchos2/Module_UI.cpp
  5. 36
      watchos2/Module_UI.h
  6. 16
      watchos2/Task_Test.cpp
  7. 2
      watchos2/__vm/Compile.vmps.xml
  8. 2
      watchos2/__vm/Upload.vmps.xml
  9. 2
      watchos2/watchos.cpp
  10. 3
      watchos2/watchos.h
  11. 48
      watchos2/watchos2.ino
  12. 39
      watchos2/watchos2.vcxproj
  13. 67
      watchos2/watchos2.vcxproj.filters
  14. 13
      watchos2/watchos_config.h
  15. 15
      watchos2/watchos_consts.h

4
watchos2/IDrawable.h

@ -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

4
watchos2/Kernel.cpp

@ -160,14 +160,14 @@ void Kernel::releaseHandle(kernel_handle_t handle)
watchos::panic("Attempt to release invalid Kernel handle");
}
kernel_handle_t Kernel::registerTask(Task* task)
kernel_handle_t Kernel::registerTask(Task* task, well_known_handle_t wk_handle)
{
for (int i = 0; i < KERNEL_MAX_TASKS; i++)
{
if (m_task[i] == nullptr)
{
m_task[i] = new KernelTask();
m_task[i]->handle = allocHandle(WATCHOS_HANDLE_TYPE_TASK, task, (kernel_handle_destructor_t)destruct_task);
m_task[i]->handle = allocHandle(WATCHOS_HANDLE_TYPE_TASK, task, (kernel_handle_destructor_t)destruct_task, wk_handle);
m_task[i]->task = task;
useHandle(m_task[i]->handle);
return m_task[i]->handle;

2
watchos2/Kernel.h

@ -54,7 +54,7 @@ public:
kernel_handle_t getHandleForWellKnown(well_known_handle_t handle);
kernel_handle_t registerTask(Task* task);
kernel_handle_t registerTask(Task* task, well_known_handle_t wk_handle = WATCHOS_HANDLE_NULL);
void unregisterTask(Task* task);
void pushEvent(well_known_handle_t source, uint16_t event, byte param1, byte param2);

276
watchos2/Module_UI.cpp

@ -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;
}

36
watchos2/Module_UI.h

@ -8,14 +8,50 @@
#include "Task.h"
#include "IRunnable.h"
#include "IDrawable.h"
#define MODULE_UI_MAX_WINDOWS 32
#define MODULE_UI_MULTICORE_STACK_SIZE 10240
#define MODULE_UI_LAYOUT_MODE_NONE 0
#define MODULE_UI_LAYOUT_MODE_SPLIT_VERTICAL 1
#define MODULE_UI_LAYOUT_MODE_SPLIT_HORIZONTAL 2
#define MODULE_UI_LAYOUT_MODE_ABSOLUTE 3
struct UiWindow;
class Module_UI : public Task, public IRunnable
{
UiWindow* m_window[MODULE_UI_MAX_WINDOWS];
bool m_initialized = false;
bool m_dirty = false;
// temp, until we implement scenes
kernel_handle_t m_root;
int m_draw_x, m_draw_y, m_draw_w, m_draw_h;
void draw_window(UiWindow* window, int x, int y, int width, int height);
void local_to_screen(int* x, int* y);
public:
Module_UI();
kernel_handle_t createWindow(IDrawable* drawable, kernel_handle_t parent);
kernel_handle_t createWindow(kernel_handle_t parent);
kernel_handle_t getRoot();
void tick();
void draw();
void do_draw();
void setLayoutMode(kernel_handle_t window_handle, byte layout_mode);
void setDirty(kernel_handle_t window_handle);
int getWidth();
int getHeight();
void fill(uint16_t colour = COLOUR_SECONDARY);
void fill(int x, int y, int width, int height, uint16_t colour = COLOUR_SECONDARY);
void print(int x, int y, char* str, uint16_t colour = COLOUR_PRIMARY, void* font = nullptr);
};
#endif

16
watchos2/Task_Test.cpp

@ -1,11 +1,20 @@
#include "watchos.h"
#include "Module_UI.h"
class Task_Test : public IRunnable, public Task, public EventListener
class Task_Test : public IRunnable, public IDrawable, public Task, public EventListener
{
Module_UI* ui = nullptr;
kernel_handle_t window_handle;
public:
Task_Test()
{
watchos::subscribe(this, 0xffffffffffffffffu, 0xffffu);
ui = static_cast<Module_UI*>(watchos::module(WATCHOS_MODULE_UI));
ui->setLayoutMode(ui->getRoot(), MODULE_UI_LAYOUT_MODE_SPLIT_HORIZONTAL);
window_handle = ui->createWindow(this, ui->getRoot());
ui->createWindow(ui->getRoot());
}
void tick()
{
@ -19,4 +28,9 @@ public:
this->popEvent();
}
}
void draw(kernel_handle_t handle)
{
ui->fill(COLOUR_SECONDARY);
ui->print(0, ui->getHeight(), "Hello, world!");
}
};

2
watchos2/__vm/Compile.vmps.xml

File diff suppressed because one or more lines are too long

2
watchos2/__vm/Upload.vmps.xml

File diff suppressed because one or more lines are too long

2
watchos2/watchos.cpp

@ -58,7 +58,7 @@ Task* watchos::task(kernel_handle_t task)
return static_cast<Task*>(kernel()->getHandle(task));
}
Task* watchos::task(well_known_handle_t handle)
Task* watchos::module(well_known_handle_t handle)
{
return static_cast<Task*>(kernel()->getHandle(kernel()->getHandleForWellKnown(handle)));
}

3
watchos2/watchos.h

@ -12,6 +12,7 @@
#include "Kernel.h"
#include "Task.h"
#include "IRunnable.h"
#include "IDrawable.h"
class watchos
{
@ -26,7 +27,7 @@ public:
static Event* event(kernel_handle_t event);
static Task* task(kernel_handle_t task);
static Task* task(well_known_handle_t handle);
static Task* module(well_known_handle_t handle);
static void reference(kernel_handle_t handle);
static void release(kernel_handle_t handle);

48
watchos2/watchos2.ino

@ -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();
}

39
watchos2/watchos2.vcxproj

File diff suppressed because one or more lines are too long

67
watchos2/watchos2.vcxproj.filters

@ -20,4 +20,71 @@
<Filter>Misc Files</Filter>
</None>
</ItemGroup>
<ItemGroup>
<ClInclude Include="__vm\.watchos2.vsarduino.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Kernel.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="watchos.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="watchos_config.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="watchos_consts.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="watchos_hw.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="watchos_types.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Task.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="IRunnable.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="IDrawable.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Queue.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Event.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="EventListener.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Module_UI.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="Kernel.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="watchos.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="Task.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="Task_Test.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="Queue.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="EventListener.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="Module_UI.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
</Project>

13
watchos2/watchos_config.h

@ -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

15
watchos2/watchos_consts.h

@ -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…
Cancel
Save