Vibed the cleanup a bit
This commit is contained in:
parent
6bd3102593
commit
ead8dfe39f
@ -2,68 +2,76 @@
|
|||||||
#include "desktop_hander.h"
|
#include "desktop_hander.h"
|
||||||
#include "input_manager.h"
|
#include "input_manager.h"
|
||||||
#include "tft_handler.h"
|
#include "tft_handler.h"
|
||||||
|
#include "event_manager.h"
|
||||||
#include "GLOBALS.h"
|
#include "GLOBALS.h"
|
||||||
|
|
||||||
WindowManager* wm; // Globals
|
WindowManager* wm;
|
||||||
Desktop_Hander* dh;
|
Desktop_Hander* dh;
|
||||||
InputManager* im;
|
InputManager* im;
|
||||||
TFT_Handler* th;
|
TFT_Handler* th;
|
||||||
|
|
||||||
DISPLAY_STATE* _display_state;
|
DISPLAY_STATE* _display_state;
|
||||||
CLICK_EVENT* _click_event;
|
|
||||||
|
|
||||||
uint32_t totalHeap = ESP.getHeapSize();
|
TaskHandle_t InputTask;
|
||||||
uint32_t freeHeap = ESP.getFreeHeap();
|
|
||||||
uint32_t usedHeap = totalHeap - freeHeap;
|
|
||||||
float percentUsed = (float)usedHeap * 100.0 / totalHeap;
|
|
||||||
|
|
||||||
TaskHandle_t Task1;
|
void input_task(void* pvParameters) {
|
||||||
|
for(;;) {
|
||||||
|
im->update();
|
||||||
|
vTaskDelay(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void setup() {
|
void setup() {
|
||||||
Serial.begin(115200);
|
Serial.begin(115200);
|
||||||
Serial.println("Initializing...");
|
Serial.println("Initializing...");
|
||||||
|
|
||||||
|
// Create shared state
|
||||||
_display_state = new DISPLAY_STATE();
|
_display_state = new DISPLAY_STATE();
|
||||||
_display_state->update_display.store(false);
|
_display_state->update_display.store(false);
|
||||||
|
|
||||||
_click_event = new CLICK_EVENT();
|
// Create managers
|
||||||
_click_event->event = CLICK_EVENTS::NONE;
|
|
||||||
|
|
||||||
wm = new WindowManager();
|
wm = new WindowManager();
|
||||||
dh = new Desktop_Hander();
|
dh = new Desktop_Hander();
|
||||||
im = new InputManager();
|
im = new InputManager();
|
||||||
th = new TFT_Handler();
|
th = new TFT_Handler();
|
||||||
|
|
||||||
|
// Initialize in order
|
||||||
th->init(_display_state);
|
th->init(_display_state);
|
||||||
im->init(_display_state, th, _click_event);
|
|
||||||
dh->init(th);
|
|
||||||
wm->init(th);
|
|
||||||
|
|
||||||
delay(500);
|
// Initialize event manager (creates dispatcher task)
|
||||||
// Create InputManager thread
|
EventManager::getInstance().init();
|
||||||
|
|
||||||
|
// Initialize components (they subscribe to events)
|
||||||
|
im->init(_display_state, th);
|
||||||
|
dh->init(th, _display_state);
|
||||||
|
wm->init(th, _display_state);
|
||||||
|
|
||||||
|
// Create input task on Core 0
|
||||||
xTaskCreatePinnedToCore(
|
xTaskCreatePinnedToCore(
|
||||||
task1, /* Task function. */
|
input_task,
|
||||||
"task1", /* name of task. */
|
"input_task",
|
||||||
10000, /* Stack size of task */
|
4096,
|
||||||
NULL, /* parameter of the task */
|
NULL,
|
||||||
1, /* priority of the task */
|
1,
|
||||||
&Task1, /* Task handle to keep track of created task */
|
&InputTask,
|
||||||
0); /* pin task to core 0 */
|
0
|
||||||
delay(500);
|
);
|
||||||
|
|
||||||
|
delay(100);
|
||||||
|
|
||||||
|
// Create test windows
|
||||||
Window win1 = {
|
Window win1 = {
|
||||||
.id = 0,
|
.id = 0,
|
||||||
.x = 10,
|
.x = 10,
|
||||||
.y = 30,
|
.y = 30,
|
||||||
.width = 350,
|
.width = 350,
|
||||||
.height = 250,
|
.height = 250,
|
||||||
.background_color = 0xbdf7, // Blue
|
.background_color = 0xbdf7,
|
||||||
.foreground_color = COL_DARK_BLUE, // White
|
.foreground_color = COL_DARK_BLUE,
|
||||||
.focused = false,
|
.focused = false,
|
||||||
.title = "Hello Worl!",
|
.title = "Hello World!",
|
||||||
.window_actions = {},
|
.window_actions = {},
|
||||||
};
|
};
|
||||||
|
|
||||||
wm->create_window(win1);
|
wm->create_window(win1);
|
||||||
|
|
||||||
Window win2 = {
|
Window win2 = {
|
||||||
@ -72,30 +80,19 @@ void setup() {
|
|||||||
.y = 50,
|
.y = 50,
|
||||||
.width = 350,
|
.width = 350,
|
||||||
.height = 250,
|
.height = 250,
|
||||||
.background_color = 0xbdf7, // Blue
|
.background_color = 0xbdf7,
|
||||||
.foreground_color = COL_DARK_BLUE, // White
|
.foreground_color = COL_DARK_BLUE,
|
||||||
.focused = true,
|
.focused = true,
|
||||||
.title = "lmao",
|
.title = "Second Window",
|
||||||
.window_actions = {},
|
.window_actions = {},
|
||||||
};
|
};
|
||||||
|
|
||||||
wm->create_window(win2);
|
wm->create_window(win2);
|
||||||
|
|
||||||
|
Serial.println("Initialization complete");
|
||||||
}
|
}
|
||||||
|
|
||||||
void loop() {
|
void loop() {
|
||||||
totalHeap = ESP.getHeapSize();
|
// Only handle rendering in main loop
|
||||||
freeHeap = ESP.getFreeHeap();
|
|
||||||
usedHeap = totalHeap - freeHeap;
|
|
||||||
percentUsed = (float)usedHeap * 100.0 / totalHeap;
|
|
||||||
|
|
||||||
int start = millis();
|
|
||||||
|
|
||||||
int id = wm->click_event(*_click_event);
|
|
||||||
if (id >= 0)
|
|
||||||
_display_state->update_display.store(true);
|
|
||||||
|
|
||||||
_click_event->event = CLICK_EVENTS::NONE;
|
|
||||||
|
|
||||||
if (_display_state->update_display.load()) {
|
if (_display_state->update_display.load()) {
|
||||||
dh->re_draw_desktop();
|
dh->re_draw_desktop();
|
||||||
wm->draw_all();
|
wm->draw_all();
|
||||||
@ -103,19 +100,5 @@ void loop() {
|
|||||||
_display_state->update_display.store(false);
|
_display_state->update_display.store(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
int stop = millis();
|
|
||||||
|
|
||||||
//Serial.print("Total mem: "); Serial.println(ESP.getHeapSize());
|
|
||||||
//Serial.print("Mem left: "); Serial.println(ESP.getFreeHeap());
|
|
||||||
//Serial.print("Mem % used: "); Serial.println(percentUsed);
|
|
||||||
//Serial.println(stop - start);
|
|
||||||
|
|
||||||
delay(50);
|
delay(50);
|
||||||
}
|
}
|
||||||
|
|
||||||
void task1(void * pvParameters) {
|
|
||||||
for(;;) {
|
|
||||||
im->update();
|
|
||||||
vTaskDelay(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -7,6 +7,11 @@ enum CLICK_EVENTS {
|
|||||||
RIGHT_CLICK = 2,
|
RIGHT_CLICK = 2,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum REDRAW_EVENT {
|
||||||
|
DESKTOP = 0,
|
||||||
|
WINDOWS = 1,
|
||||||
|
};
|
||||||
|
|
||||||
struct CLICK_EVENT {
|
struct CLICK_EVENT {
|
||||||
int x;
|
int x;
|
||||||
int y;
|
int y;
|
||||||
|
|||||||
@ -1,10 +1,15 @@
|
|||||||
#include "desktop_hander.h"
|
#include "desktop_hander.h"
|
||||||
#include "tft_handler.h"
|
#include "tft_handler.h"
|
||||||
|
|
||||||
void Desktop_Hander::init(TFT_Handler* th) {
|
void Desktop_Hander::init(TFT_Handler* th, DISPLAY_STATE* ds) {
|
||||||
tft = th;
|
tft = th;
|
||||||
|
display_state = ds;
|
||||||
|
|
||||||
for (int i; i < 5; i++) {
|
// Subscribe to events
|
||||||
|
EventManager::getInstance().subscribe(this);
|
||||||
|
|
||||||
|
// Create desktop items
|
||||||
|
for (int i = 0; i < 5; i++) {
|
||||||
Desktop_Item di = {
|
Desktop_Item di = {
|
||||||
.id = i,
|
.id = i,
|
||||||
.place_x = i * 50 + 1,
|
.place_x = i * 50 + 1,
|
||||||
@ -34,7 +39,6 @@ void Desktop_Hander::draw_background(int color) {
|
|||||||
void Desktop_Hander::draw_task_bar(int color) {
|
void Desktop_Hander::draw_task_bar(int color) {
|
||||||
// bar
|
// bar
|
||||||
tft->draw_box(0, 293, 480, 40, color);
|
tft->draw_box(0, 293, 480, 40, color);
|
||||||
|
|
||||||
tft->draw_line(0, 294, 480, 294, 0xffff);
|
tft->draw_line(0, 294, 480, 294, 0xffff);
|
||||||
|
|
||||||
// Outer shadow
|
// Outer shadow
|
||||||
@ -50,10 +54,33 @@ void Desktop_Hander::draw_task_bar(int color) {
|
|||||||
tft->draw_box(6, 298, 50, 18, color);
|
tft->draw_box(6, 298, 50, 18, color);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Desktop_Hander::draw_desktop_Item(Desktop_Item desktop_item) {
|
void Desktop_Hander::draw_desktop_Item(const Desktop_Item& desktop_item) {
|
||||||
tft->draw_box(desktop_item.place_x, desktop_item.place_y, desktop_item.icon_size_x, desktop_item.icon_size_y, 0x4648);
|
tft->draw_box(desktop_item.place_x, desktop_item.place_y,
|
||||||
|
desktop_item.icon_size_x, desktop_item.icon_size_y, 0x4648);
|
||||||
}
|
}
|
||||||
|
|
||||||
int Desktop_Hander::click_event(CLICK_EVENT event) {
|
void Desktop_Hander::on_click_event(const CLICK_EVENT& event) {
|
||||||
return 0;
|
if (event.event != CLICK_EVENTS::LEFT_CLICK) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
handle_desktop_click(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Desktop_Hander::handle_desktop_click(const CLICK_EVENT& event) {
|
||||||
|
// Check if click is on desktop (not on taskbar or windows)
|
||||||
|
// This is where you'd check if an icon was clicked
|
||||||
|
for (const auto& item : items) {
|
||||||
|
if (event.x >= item.place_x &&
|
||||||
|
event.x <= (item.place_x + item.icon_size_x) &&
|
||||||
|
event.y >= item.place_y &&
|
||||||
|
event.y <= (item.place_y + item.icon_size_y)) {
|
||||||
|
|
||||||
|
Serial.print("Desktop item clicked: ");
|
||||||
|
Serial.println(item.id);
|
||||||
|
|
||||||
|
// TODO: Handle icon click (open window, etc.)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@ -1,19 +1,25 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "desktop.h"
|
#include "desktop.h"
|
||||||
#include "tft_handler.h"
|
#include "tft_handler.h"
|
||||||
|
#include "event_manager.h"
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include "GLOBALS.h"
|
#include "GLOBALS.h"
|
||||||
|
|
||||||
class Desktop_Hander {
|
class Desktop_Hander : public IEventListener {
|
||||||
private:
|
private:
|
||||||
TFT_Handler* tft;
|
TFT_Handler* tft;
|
||||||
|
DISPLAY_STATE* display_state;
|
||||||
std::vector<Desktop_Item> items;
|
std::vector<Desktop_Item> items;
|
||||||
|
|
||||||
|
void handle_desktop_click(const CLICK_EVENT& event);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void init(TFT_Handler* th);
|
void init(TFT_Handler* th, DISPLAY_STATE* ds);
|
||||||
void re_draw_desktop();
|
void re_draw_desktop();
|
||||||
void draw_background(int color);
|
void draw_background(int color);
|
||||||
void draw_task_bar(int color);
|
void draw_task_bar(int color);
|
||||||
void draw_desktop_Item(Desktop_Item desktop_item);
|
void draw_desktop_Item(const Desktop_Item& desktop_item);
|
||||||
int click_event(CLICK_EVENT event);
|
|
||||||
|
// IEventListener interface
|
||||||
|
void on_click_event(const CLICK_EVENT& event) override;
|
||||||
};
|
};
|
||||||
43
Desktop_Test/event_manager.cpp
Normal file
43
Desktop_Test/event_manager.cpp
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
#include "event_manager.h"
|
||||||
|
|
||||||
|
void EventManager::init() {
|
||||||
|
xTaskCreatePinnedToCore(
|
||||||
|
dispatch_task,
|
||||||
|
"event_dispatch",
|
||||||
|
4096,
|
||||||
|
this,
|
||||||
|
2, // Higher priority than input
|
||||||
|
&_dispatcher_task,
|
||||||
|
0
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void EventManager::publish(const CLICK_EVENT& event) {
|
||||||
|
xQueueSend(_event_queue, &event, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void EventManager::subscribe(IEventListener* listener) {
|
||||||
|
_listeners.push_back(listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
void EventManager::unsubscribe(IEventListener* listener) {
|
||||||
|
auto it = std::find(_listeners.begin(), _listeners.end(), listener);
|
||||||
|
if (it != _listeners.end()) {
|
||||||
|
_listeners.erase(it);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void EventManager::dispatch_task(void* pvParameters) {
|
||||||
|
EventManager* self = static_cast<EventManager*>(pvParameters);
|
||||||
|
CLICK_EVENT event;
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
if (xQueueReceive(self->_event_queue, &event, portMAX_DELAY)) {
|
||||||
|
// Dispatch to all listeners
|
||||||
|
for (auto* listener : self->_listeners) {
|
||||||
|
listener->on_click_event(event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
vTaskDelay(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
43
Desktop_Test/event_manager.h
Normal file
43
Desktop_Test/event_manager.h
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "freertos/FreeRTOS.h"
|
||||||
|
#include "freertos/task.h"
|
||||||
|
#include "freertos/queue.h"
|
||||||
|
#include "GLOBALS.h"
|
||||||
|
#include <functional>
|
||||||
|
#include <algorithm>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
// Forward declare to avoid circular dependency
|
||||||
|
class IEventListener {
|
||||||
|
public:
|
||||||
|
virtual void on_click_event(const CLICK_EVENT& event) = 0;
|
||||||
|
virtual ~IEventListener() = default;
|
||||||
|
};
|
||||||
|
|
||||||
|
class EventManager {
|
||||||
|
private:
|
||||||
|
QueueHandle_t _event_queue;
|
||||||
|
std::vector<IEventListener*> _listeners;
|
||||||
|
TaskHandle_t _dispatcher_task;
|
||||||
|
|
||||||
|
EventManager() {
|
||||||
|
_event_queue = xQueueCreate(10, sizeof(CLICK_EVENT));
|
||||||
|
}
|
||||||
|
|
||||||
|
EventManager(const EventManager&) = delete;
|
||||||
|
EventManager& operator=(const EventManager&) = delete;
|
||||||
|
|
||||||
|
static void dispatch_task(void* pvParameters);
|
||||||
|
|
||||||
|
public:
|
||||||
|
static EventManager& getInstance() {
|
||||||
|
static EventManager instance;
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
void init();
|
||||||
|
void publish(const CLICK_EVENT& event);
|
||||||
|
void subscribe(IEventListener* listener);
|
||||||
|
void unsubscribe(IEventListener* listener);
|
||||||
|
};
|
||||||
@ -1,11 +1,11 @@
|
|||||||
|
#include "event_manager.h"
|
||||||
#include "GLOBALS.h"
|
#include "GLOBALS.h"
|
||||||
#include "tft_handler.h"
|
#include "tft_handler.h"
|
||||||
#include "HardwareSerial.h"
|
#include "HardwareSerial.h"
|
||||||
#include "input_manager.h"
|
#include "input_manager.h"
|
||||||
|
|
||||||
void InputManager::init(DISPLAY_STATE* display_state, TFT_Handler* tf, CLICK_EVENT* event) {
|
void InputManager::init(DISPLAY_STATE* display_state, TFT_Handler* tf) {
|
||||||
_display_state = display_state;
|
_display_state = display_state;
|
||||||
_event = event;
|
|
||||||
_tf = tf;
|
_tf = tf;
|
||||||
|
|
||||||
mi = {
|
mi = {
|
||||||
@ -25,19 +25,15 @@ void InputManager::update() {
|
|||||||
for (int i = 0; i < NUM_BUTTONS; i++) {
|
for (int i = 0; i < NUM_BUTTONS; i++) {
|
||||||
int reading = digitalRead(BUTTON_PINS[i]);
|
int reading = digitalRead(BUTTON_PINS[i]);
|
||||||
|
|
||||||
// Check if button state changed
|
|
||||||
if (reading != lastButtonState[i]) {
|
if (reading != lastButtonState[i]) {
|
||||||
lastDebounceTime[i] = millis();
|
lastDebounceTime[i] = millis();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Only register change after debounce delay
|
|
||||||
if ((millis() - lastDebounceTime[i]) > DEBOUNCE_DELAY) {
|
if ((millis() - lastDebounceTime[i]) > DEBOUNCE_DELAY) {
|
||||||
if (reading != buttonState[i]) {
|
if (reading != buttonState[i]) {
|
||||||
buttonState[i] = reading;
|
buttonState[i] = reading;
|
||||||
|
|
||||||
// Button was pressed (went from HIGH to LOW)
|
|
||||||
if (buttonState[i] == LOW) {
|
if (buttonState[i] == LOW) {
|
||||||
// Add your button handling code here
|
|
||||||
handle_button_press(i);
|
handle_button_press(i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -48,43 +44,56 @@ void InputManager::update() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void InputManager::handle_button_press(int buttonIndex) {
|
void InputManager::handle_button_press(int buttonIndex) {
|
||||||
// Add your custom logic here for each button
|
bool needs_redraw = false;
|
||||||
|
|
||||||
switch(buttonIndex) {
|
switch(buttonIndex) {
|
||||||
case 0:
|
case 0: // Right
|
||||||
if (mi.x > 480)
|
mi.x = (mi.x + 5 > 476) ? 476 : mi.x + 5;
|
||||||
mi.x = 479;
|
needs_redraw = true;
|
||||||
else
|
|
||||||
mi.x += 5;
|
|
||||||
break;
|
break;
|
||||||
case 1:
|
|
||||||
if (mi.y > 320)
|
case 1: // Down
|
||||||
mi.y = 319;
|
mi.y = (mi.y + 5 > 316) ? 316 : mi.y + 5;
|
||||||
else
|
needs_redraw = true;
|
||||||
mi.y += 5;
|
|
||||||
break;
|
break;
|
||||||
case 2:
|
|
||||||
if (mi.y < 0)
|
case 2: // Up
|
||||||
mi.y = 1;
|
mi.y = (mi.y - 5 < 0) ? 0 : mi.y - 5;
|
||||||
else
|
needs_redraw = true;
|
||||||
mi.y -= 5;
|
|
||||||
break;
|
break;
|
||||||
case 3:
|
|
||||||
if (mi.x < 0)
|
case 3: // Left
|
||||||
mi.x = 1;
|
mi.x = (mi.x - 5 < 0) ? 0 : mi.x - 5;
|
||||||
else
|
needs_redraw = true;
|
||||||
mi.x -= 5;
|
|
||||||
break;
|
break;
|
||||||
case 4:
|
|
||||||
_event->event = CLICK_EVENTS::LEFT_CLICK;
|
case 4: // Click
|
||||||
_event->x = mi.x;
|
{
|
||||||
_event->y = mi.y;
|
CLICK_EVENT event = {
|
||||||
|
.x = mi.x,
|
||||||
|
.y = mi.y,
|
||||||
|
.event = CLICK_EVENTS::LEFT_CLICK
|
||||||
|
};
|
||||||
|
EventManager::getInstance().publish(event);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case 5:
|
|
||||||
|
case 5: // Right click
|
||||||
|
{
|
||||||
|
CLICK_EVENT event = {
|
||||||
|
.x = mi.x,
|
||||||
|
.y = mi.y,
|
||||||
|
.event = CLICK_EVENTS::RIGHT_CLICK
|
||||||
|
};
|
||||||
|
EventManager::getInstance().publish(event);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (needs_redraw) {
|
||||||
_display_state->update_display.store(true);
|
_display_state->update_display.store(true);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void InputManager::draw_button() {
|
void InputManager::draw_button() {
|
||||||
_tf->draw_box(mi.x, mi.y, mi.size_x, mi.size_y, mi.color);
|
_tf->draw_box(mi.x, mi.y, mi.size_x, mi.size_y, mi.color);
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "tft_handler.h"
|
#include "tft_handler.h"
|
||||||
|
#include "event_manager.h"
|
||||||
#include "GLOBALS.h"
|
#include "GLOBALS.h"
|
||||||
#include "icons.h"
|
#include "icons.h"
|
||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
@ -14,7 +15,6 @@ private:
|
|||||||
int buttonState[NUM_BUTTONS] = {HIGH, HIGH, HIGH, HIGH, HIGH, HIGH};
|
int buttonState[NUM_BUTTONS] = {HIGH, HIGH, HIGH, HIGH, HIGH, HIGH};
|
||||||
|
|
||||||
DISPLAY_STATE* _display_state;
|
DISPLAY_STATE* _display_state;
|
||||||
CLICK_EVENT* _event;
|
|
||||||
TFT_Handler* _tf;
|
TFT_Handler* _tf;
|
||||||
Mouse_Icon mi;
|
Mouse_Icon mi;
|
||||||
|
|
||||||
@ -22,7 +22,7 @@ private:
|
|||||||
bool are_buttons_pressed(int btn1, int btn2);
|
bool are_buttons_pressed(int btn1, int btn2);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void init(DISPLAY_STATE* display_state, TFT_Handler* tf, CLICK_EVENT* event);
|
void init(DISPLAY_STATE* display_state, TFT_Handler* tf);
|
||||||
void update();
|
void update();
|
||||||
void draw_button();
|
void draw_button();
|
||||||
};
|
};
|
||||||
|
|||||||
@ -8,22 +8,22 @@ void TFT_Handler::init(DISPLAY_STATE* display_state) {
|
|||||||
tft.fillScreen(0x0000);
|
tft.fillScreen(0x0000);
|
||||||
}
|
}
|
||||||
|
|
||||||
void TFT_Handler::draw_box(int x, int y, int size_x, int size_y, int color) {
|
void TFT_Handler::start_draw() {
|
||||||
tft.startWrite();
|
tft.startWrite();
|
||||||
|
}
|
||||||
|
|
||||||
tft.setRotation(3);
|
void TFT_Handler::end_draw() {
|
||||||
tft.fillRect(x, y, size_x, size_y, color);
|
|
||||||
|
|
||||||
tft.endWrite();
|
tft.endWrite();
|
||||||
}
|
}
|
||||||
|
|
||||||
void TFT_Handler::draw_rect(int x, int y, int size_x, int size_y, int thickness, int color) {
|
void TFT_Handler::draw_box(int x, int y, int size_x, int size_y, int color) {
|
||||||
tft.startWrite();
|
tft.setRotation(3);
|
||||||
|
tft.fillRect(x, y, size_x, size_y, color);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TFT_Handler::draw_rect(int x, int y, int size_x, int size_y, int thickness, int color) {
|
||||||
tft.setRotation(3);
|
tft.setRotation(3);
|
||||||
tft.drawRect(x, y, size_x, size_y, color);
|
tft.drawRect(x, y, size_x, size_y, color);
|
||||||
|
|
||||||
tft.endWrite();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void TFT_Handler::draw_line(int x1, int y1, int x2, int y2, int color) {
|
void TFT_Handler::draw_line(int x1, int y1, int x2, int y2, int color) {
|
||||||
@ -31,19 +31,15 @@ void TFT_Handler::draw_line(int x1, int y1, int x2, int y2, int color) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void TFT_Handler::draw_text(int x, int y, std::string str) {
|
void TFT_Handler::draw_text(int x, int y, std::string str) {
|
||||||
tft.startWrite();
|
|
||||||
|
|
||||||
tft.setTextColor(TFT_WHITE);
|
tft.setTextColor(TFT_WHITE);
|
||||||
tft.setTextSize(2);
|
tft.setTextSize(2);
|
||||||
tft.drawString(str.c_str(), x, y);
|
tft.drawString(str.c_str(), x, y);
|
||||||
|
|
||||||
tft.endWrite();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void TFT_Handler::fill_screen(int color) {
|
void TFT_Handler::fill_screen(int color) {
|
||||||
tft.startWrite();
|
|
||||||
|
|
||||||
tft.fillScreen(color);
|
tft.fillScreen(color);
|
||||||
|
}
|
||||||
tft.endWrite();
|
|
||||||
|
void TFT_Handler::draw_box_sprite(int x, int y, int size_x, int size_y, int color) {
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -55,9 +55,15 @@ public:
|
|||||||
DISPLAY_STATE* _display_state;
|
DISPLAY_STATE* _display_state;
|
||||||
|
|
||||||
void init(DISPLAY_STATE* display_state);
|
void init(DISPLAY_STATE* display_state);
|
||||||
|
|
||||||
|
void start_draw();
|
||||||
|
void end_draw();
|
||||||
|
|
||||||
void draw_box(int x, int y, int size_x, int size_y, int color);
|
void draw_box(int x, int y, int size_x, int size_y, int color);
|
||||||
void draw_rect(int x, int y, int size_x, int size_y, int thickness, int color);
|
void draw_rect(int x, int y, int size_x, int size_y, int thickness, int color);
|
||||||
void draw_line(int x1, int y1, int x2, int y2, int color);
|
void draw_line(int x1, int y1, int x2, int y2, int color);
|
||||||
void draw_text(int x, int y, std::string str);
|
void draw_text(int x, int y, std::string str);
|
||||||
void fill_screen(int color);
|
void fill_screen(int color);
|
||||||
|
|
||||||
|
void draw_box_sprite(int x, int y, int size_x, int size_y, int color);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,36 +1,39 @@
|
|||||||
#include "HardwareSerial.h"
|
|
||||||
#include "GLOBALS.h"
|
|
||||||
#include "window_manager.h"
|
#include "window_manager.h"
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
void WindowManager::init(TFT_Handler* th) {
|
void WindowManager::init(TFT_Handler* th, DISPLAY_STATE* ds) {
|
||||||
tft = th;
|
tft = th;
|
||||||
|
display_state = ds;
|
||||||
|
|
||||||
|
// Subscribe to events
|
||||||
|
EventManager::getInstance().subscribe(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
void WindowManager::create_window(Window window) {
|
void WindowManager::create_window(Window window) {
|
||||||
windows.push_back(window);
|
windows.push_back(window);
|
||||||
draw_window(window);
|
display_state->update_display.store(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void WindowManager::close_window(int window_id) {
|
void WindowManager::close_window(int window_id) {
|
||||||
for (auto it = windows.begin(); it != windows.end(); ++it) {
|
for (auto it = windows.begin(); it != windows.end(); ++it) {
|
||||||
if (it->id == window_id) {
|
if (it->id == window_id) {
|
||||||
windows.erase(it);
|
windows.erase(it);
|
||||||
|
display_state->update_display.store(true);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
draw_all();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void WindowManager::draw_all() {
|
void WindowManager::draw_all() {
|
||||||
|
tft->start_draw();
|
||||||
for (const auto& win : windows) {
|
for (const auto& win : windows) {
|
||||||
draw_window(win);
|
draw_window(win);
|
||||||
}
|
}
|
||||||
|
tft->end_draw();
|
||||||
}
|
}
|
||||||
|
|
||||||
void WindowManager::draw_window(Window window) {
|
void WindowManager::draw_window(const Window& window) {
|
||||||
// Outer shadow
|
// Outer shadow
|
||||||
//tft->draw_box(window.x, window.y, window.width + 2, window.height + 2, 0x0000);
|
|
||||||
tft->draw_rect(window.x, window.y, window.width + 2, window.height + 2, 1, 0x0000);
|
tft->draw_rect(window.x, window.y, window.width + 2, window.height + 2, 1, 0x0000);
|
||||||
|
|
||||||
// Inner shadow
|
// Inner shadow
|
||||||
@ -55,45 +58,49 @@ void WindowManager::draw_window(Window window) {
|
|||||||
tft->draw_text(window.x + 6 + 65, window.y + 10, window.title.c_str());
|
tft->draw_text(window.x + 6 + 65, window.y + 10, window.title.c_str());
|
||||||
|
|
||||||
// Window content
|
// Window content
|
||||||
tft->draw_box(window.x + 3, window.y + 30 + 5, window.width - 6, window.height - 7 - 30, COL_WHITE);
|
tft->draw_box(window.x + 3, window.y + 35, window.width - 6, window.height - 38, COL_WHITE);
|
||||||
}
|
}
|
||||||
|
|
||||||
int WindowManager::click_event(CLICK_EVENT event) {
|
void WindowManager::on_click_event(const CLICK_EVENT& event) {
|
||||||
int id = -1;
|
if (event.event != CLICK_EVENTS::LEFT_CLICK) {
|
||||||
|
return;
|
||||||
if (event.event == CLICK_EVENTS::NONE) {
|
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int clicked_id = handle_window_click(event);
|
||||||
|
|
||||||
|
if (clicked_id >= 0) {
|
||||||
|
display_state->update_display.store(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int WindowManager::handle_window_click(const CLICK_EVENT& event) {
|
||||||
// Iterate BACKWARDS - last window is on top
|
// Iterate BACKWARDS - last window is on top
|
||||||
for (int i = windows.size() - 1; i >= 0; i--) {
|
for (int i = windows.size() - 1; i >= 0; i--) {
|
||||||
Window& window = windows[i];
|
Window& window = windows[i];
|
||||||
|
|
||||||
if (event.event != CLICK_EVENTS::LEFT_CLICK)
|
// Check if click is within window bounds
|
||||||
continue;
|
if (event.x >= window.x && event.x <= (window.x + window.width) &&
|
||||||
|
event.y >= window.y && event.y <= (window.y + window.height)) {
|
||||||
|
|
||||||
if (event.x >= window.x && event.x <= (window.x + window.width)) {
|
if (window.focused) {
|
||||||
|
return -1;
|
||||||
if (event.y >= window.y && event.y <= (window.y + window.height)) {
|
}
|
||||||
|
|
||||||
if (window.focused)
|
|
||||||
break;
|
|
||||||
|
|
||||||
// Unfocus all windows
|
// Unfocus all windows
|
||||||
for (size_t j = 0; j < windows.size(); j++) {
|
for (auto& win : windows) {
|
||||||
windows[j].focused = false;
|
win.focused = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Focus this window
|
// Focus this window
|
||||||
window.focused = true;
|
window.focused = true;
|
||||||
id = window.id;
|
|
||||||
|
|
||||||
// Move window to end (top of z-order)
|
// Move window to end (top of z-order)
|
||||||
auto it = windows.begin() + i;
|
auto it = windows.begin() + i;
|
||||||
std::rotate(it, it + 1, windows.end());
|
std::rotate(it, it + 1, windows.end());
|
||||||
}
|
|
||||||
|
return window.id;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return id;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
#include "window.h"
|
#include "window.h"
|
||||||
#include "tft_handler.h"
|
#include "tft_handler.h"
|
||||||
|
#include "event_manager.h"
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include "GLOBALS.h"
|
#include "GLOBALS.h"
|
||||||
|
|
||||||
@ -12,16 +13,21 @@
|
|||||||
#define COL_DARK_BLUE 0x0014
|
#define COL_DARK_BLUE 0x0014
|
||||||
#define COL_RED 0xf800
|
#define COL_RED 0xf800
|
||||||
|
|
||||||
class WindowManager {
|
class WindowManager : public IEventListener {
|
||||||
private:
|
private:
|
||||||
TFT_Handler* tft; // Pointer to shared TFT handler
|
TFT_Handler* tft;
|
||||||
std::vector<Window> windows; // Track all windows
|
DISPLAY_STATE* display_state;
|
||||||
|
std::vector<Window> windows;
|
||||||
|
|
||||||
|
int handle_window_click(const CLICK_EVENT& event);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void init(TFT_Handler* th);
|
void init(TFT_Handler* th, DISPLAY_STATE* ds);
|
||||||
void create_window(Window window);
|
void create_window(Window window);
|
||||||
void close_window(int window_id);
|
void close_window(int window_id);
|
||||||
void draw_all(); // Redraw all windows
|
void draw_all();
|
||||||
void draw_window(Window window);
|
void draw_window(const Window& window);
|
||||||
int click_event(CLICK_EVENT event);
|
|
||||||
|
// IEventListener interface
|
||||||
|
void on_click_event(const CLICK_EVENT& event) override;
|
||||||
};
|
};
|
||||||
Loading…
Reference in New Issue
Block a user