|
|
|
#include <M5StickC.h>
|
|
|
|
#include "Kernel.h"
|
|
|
|
#include "UI.h"
|
|
|
|
|
|
|
|
#define MAX_WINDOWS 8
|
|
|
|
|
|
|
|
struct Window *UI_get_window(int hwnd);
|
|
|
|
void base_window_callback(int hwnd, int x, int y, int width, int height);
|
|
|
|
void UI_draw(int parent_hwnd, int x, int y, int width, int height);
|
|
|
|
|
|
|
|
struct Window windows[MAX_WINDOWS];
|
|
|
|
int next_hwnd = 1;
|
|
|
|
|
|
|
|
int UI(int pid, unsigned int signal)
|
|
|
|
{
|
|
|
|
if (signal & SIGNAL_START)
|
|
|
|
{
|
|
|
|
Kernel_signal_mask(pid, SIGNAL_START | SIGNAL_STOP | SIGNAL_REDRAW);
|
|
|
|
windows[0].hwnd = next_hwnd++;
|
|
|
|
windows[0].hwnd_parent = 0;
|
|
|
|
windows[0].layout_mode = LAYOUT_MODE_SPLIT_VERTICAL;
|
|
|
|
windows[0].callback = &base_window_callback;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (signal & SIGNAL_STOP)
|
|
|
|
{
|
|
|
|
return 255;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (signal & SIGNAL_REDRAW)
|
|
|
|
{
|
|
|
|
for (int i=0; i<MAX_WINDOWS; i++)
|
|
|
|
{
|
|
|
|
if (windows[i].hwnd == 0 || windows[i].hwnd_parent != 0)
|
|
|
|
{
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
M5.Lcd.setTextColor(TFT_WHITE, TFT_DARKGREY);
|
|
|
|
// TODO: Get actual screen bounds somehow
|
|
|
|
// Horizontal
|
|
|
|
UI_draw(windows[i].hwnd, 0, 0, 160, 80);
|
|
|
|
// Vertical
|
|
|
|
//UI_draw(windows[i].hwnd, 0, 0, 80, 160);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void UI_draw(int parent_hwnd, int x, int y, int width, int height)
|
|
|
|
{
|
|
|
|
// Trigger draw
|
|
|
|
Window* parent_window = UI_get_window(parent_hwnd);
|
|
|
|
if (parent_window->hwnd == -1)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Call callback on parent if available
|
|
|
|
if (parent_window->placeholder != true)
|
|
|
|
{
|
|
|
|
(*parent_window->callback)(parent_hwnd, x, y, width, height);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Count the number of children
|
|
|
|
int child_count = 0;
|
|
|
|
for (int i=0; i<MAX_WINDOWS; i++)
|
|
|
|
{
|
|
|
|
if (windows[i].hwnd_parent == parent_hwnd)
|
|
|
|
{
|
|
|
|
child_count++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (child_count == 0)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Grab all the children
|
|
|
|
Window* children[child_count];
|
|
|
|
int next_child = 0;
|
|
|
|
for (int i=0; i<MAX_WINDOWS; i++)
|
|
|
|
{
|
|
|
|
if (windows[i].hwnd_parent == parent_hwnd)
|
|
|
|
{
|
|
|
|
children[next_child++] = &windows[i];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (parent_window->layout_mode)
|
|
|
|
{
|
|
|
|
case LAYOUT_MODE_NONE:
|
|
|
|
{
|
|
|
|
for (int i=0; i<child_count; i++)
|
|
|
|
{
|
|
|
|
UI_draw(children[i]->hwnd, x, y, width, height);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case LAYOUT_MODE_SPLIT_VERTICAL:
|
|
|
|
{
|
|
|
|
int child_width = width / child_count;
|
|
|
|
for (int i=0; i<child_count; i++)
|
|
|
|
{
|
|
|
|
UI_draw(children[i]->hwnd, x + (i * child_width), y, child_width, height);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case LAYOUT_MODE_SPLIT_HORIZONTAL:
|
|
|
|
{
|
|
|
|
int child_height = height / child_count;
|
|
|
|
for (int i=0; i<child_count; i++)
|
|
|
|
{
|
|
|
|
UI_draw(children[i]->hwnd, x, y + (i * child_height), width, child_height);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void base_window_callback(int hwnd, int x, int y, int width, int height)
|
|
|
|
{
|
|
|
|
M5.Lcd.fillScreen(TFT_DARKGREY);
|
|
|
|
M5.Lcd.setRotation(3);
|
|
|
|
}
|
|
|
|
|
|
|
|
int UI_create_window(void (*callback)(int, int, int, int, int), int parent /* = 0 */, int zorder /* = 0 */, bool placeholder /* = true */)
|
|
|
|
{
|
|
|
|
Window* window = UI_get_window(0);
|
|
|
|
if (window->hwnd == -1)
|
|
|
|
{
|
|
|
|
Kernel_panic("Cannot create window! Out of handles!");
|
|
|
|
}
|
|
|
|
|
|
|
|
window->hwnd = next_hwnd++;
|
|
|
|
window->hwnd_parent = parent;
|
|
|
|
window->placeholder = placeholder;
|
|
|
|
window->callback = callback;
|
|
|
|
return window->hwnd;
|
|
|
|
}
|
|
|
|
|
|
|
|
void UI_set_layout_mode(int hwnd, int layout_mode)
|
|
|
|
{
|
|
|
|
Window* window = UI_get_window(0);
|
|
|
|
if (window->hwnd == -1)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
window->layout_mode = layout_mode;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct Window *UI_get_window(int hwnd)
|
|
|
|
{
|
|
|
|
for (int i=0; i<MAX_WINDOWS; i++)
|
|
|
|
{
|
|
|
|
if (windows[i].hwnd == hwnd)
|
|
|
|
{
|
|
|
|
return &windows[i];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
struct Window empty = Window();
|
|
|
|
empty.hwnd = -1;
|
|
|
|
return ∅
|
|
|
|
}
|