A simple operating system for the ESP32-based M5StickC
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.
 
 
 

218 lines
4.8 KiB

#include <M5StickC.h>
#include "Kernel.h"
#include "UI.h"
#include "EAT.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 rotation = ROTATION_HORIZONTAL_BUTTON_LEFT;
int UI(int pid, unsigned int signal)
{
if (signal & SIGNAL_START)
{
Kernel_signal_mask(pid, SIGNAL_START | SIGNAL_STOP | SIGNAL_REDRAW | SIGNAL_INPUT_A);
windows[0].hwnd = next_hwnd++;
windows[0].hwnd_parent = 0;
windows[0].layout_mode = LAYOUT_MODE_SPLIT_AUTO;
windows[0].callback = &base_window_callback;
if (EAT_allocate(3, 1))
{
EAT_write(3, 0, rotation);
}
else
{
rotation = EAT_read(3, 0);
}
}
if (signal & SIGNAL_STOP)
{
EAT_write(3, 0, rotation);
return 255;
}
if (signal & SIGNAL_INPUT_A)
{
rotation = rotation + 1;
if (rotation == 4)
rotation = 0;
Kernel_signal(SIGNAL_REDRAW);
}
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);
if (rotation == ROTATION_HORIZONTAL_BUTTON_LEFT || rotation == ROTATION_HORIZONTAL_BUTTON_RIGHT)
{
// Horizontal
UI_draw(windows[i].hwnd, 0, 0, 160, 80);
}
else if (rotation == ROTATION_VERTICAL_BUTTON_UP || rotation == ROTATION_VERTICAL_BUTTON_DOWN)
{
// 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];
}
}
int layout_mode = parent_window->layout_mode;
if (layout_mode == LAYOUT_MODE_SPLIT_AUTO)
{
if (rotation == ROTATION_HORIZONTAL_BUTTON_LEFT || rotation == ROTATION_HORIZONTAL_BUTTON_RIGHT)
{
layout_mode = LAYOUT_MODE_SPLIT_VERTICAL;
}
else if (rotation == ROTATION_VERTICAL_BUTTON_UP || rotation == ROTATION_VERTICAL_BUTTON_DOWN)
{
layout_mode = LAYOUT_MODE_SPLIT_HORIZONTAL;
}
}
switch (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(rotation);
}
int UI_create_window(void (*callback)(int, int, int, int, int), int parent /* = 0 */, int zorder /* = 0 */)
{
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 = false;
window->callback = callback;
return window->hwnd;
}
int UI_create_window(int parent /* = 0 */, int zorder /* = 0 */)
{
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 = true;
return window->hwnd;
}
void UI_set_layout_mode(int hwnd, int layout_mode)
{
Window* window = UI_get_window(hwnd);
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 &empty;
}