From ead8dfe39f14ee8fcc5edc5f26f0a500966a9d2d Mon Sep 17 00:00:00 2001 From: rasmus Date: Mon, 15 Dec 2025 19:06:44 +0100 Subject: [PATCH] Vibed the cleanup a bit --- Desktop_Test/Desktop_Test.ino | 99 ++++++++++++++------------------- Desktop_Test/GLOBALS.h | 5 ++ Desktop_Test/desktop_hander.cpp | 41 +++++++++++--- Desktop_Test/desktop_hander.h | 16 ++++-- Desktop_Test/event_manager.cpp | 43 ++++++++++++++ Desktop_Test/event_manager.h | 43 ++++++++++++++ Desktop_Test/input_manager.cpp | 75 ++++++++++++++----------- Desktop_Test/input_manager.h | 4 +- Desktop_Test/tft_handler.cpp | 26 ++++----- Desktop_Test/tft_handler.h | 6 ++ Desktop_Test/window_manager.cpp | 79 ++++++++++++++------------ Desktop_Test/window_manager.h | 20 ++++--- 12 files changed, 294 insertions(+), 163 deletions(-) create mode 100644 Desktop_Test/event_manager.cpp create mode 100644 Desktop_Test/event_manager.h diff --git a/Desktop_Test/Desktop_Test.ino b/Desktop_Test/Desktop_Test.ino index 9ca710d..07c1cce 100644 --- a/Desktop_Test/Desktop_Test.ino +++ b/Desktop_Test/Desktop_Test.ino @@ -2,68 +2,76 @@ #include "desktop_hander.h" #include "input_manager.h" #include "tft_handler.h" +#include "event_manager.h" #include "GLOBALS.h" -WindowManager* wm; // Globals +WindowManager* wm; Desktop_Hander* dh; InputManager* im; TFT_Handler* th; DISPLAY_STATE* _display_state; -CLICK_EVENT* _click_event; -uint32_t totalHeap = ESP.getHeapSize(); -uint32_t freeHeap = ESP.getFreeHeap(); -uint32_t usedHeap = totalHeap - freeHeap; -float percentUsed = (float)usedHeap * 100.0 / totalHeap; +TaskHandle_t InputTask; -TaskHandle_t Task1; +void input_task(void* pvParameters) { + for(;;) { + im->update(); + vTaskDelay(1); + } +} void setup() { Serial.begin(115200); Serial.println("Initializing..."); + // Create shared state _display_state = new DISPLAY_STATE(); _display_state->update_display.store(false); - - _click_event = new CLICK_EVENT(); - _click_event->event = CLICK_EVENTS::NONE; + // Create managers wm = new WindowManager(); dh = new Desktop_Hander(); im = new InputManager(); th = new TFT_Handler(); + // Initialize in order th->init(_display_state); - im->init(_display_state, th, _click_event); - dh->init(th); - wm->init(th); + + // Initialize event manager (creates dispatcher task) + EventManager::getInstance().init(); + + // Initialize components (they subscribe to events) + im->init(_display_state, th); + dh->init(th, _display_state); + wm->init(th, _display_state); - delay(500); - // Create InputManager thread + // Create input task on Core 0 xTaskCreatePinnedToCore( - task1, /* Task function. */ - "task1", /* name of task. */ - 10000, /* Stack size of task */ - NULL, /* parameter of the task */ - 1, /* priority of the task */ - &Task1, /* Task handle to keep track of created task */ - 0); /* pin task to core 0 */ - delay(500); + input_task, + "input_task", + 4096, + NULL, + 1, + &InputTask, + 0 + ); + delay(100); + + // Create test windows Window win1 = { .id = 0, .x = 10, .y = 30, .width = 350, .height = 250, - .background_color = 0xbdf7, // Blue - .foreground_color = COL_DARK_BLUE, // White + .background_color = 0xbdf7, + .foreground_color = COL_DARK_BLUE, .focused = false, - .title = "Hello Worl!", + .title = "Hello World!", .window_actions = {}, }; - wm->create_window(win1); Window win2 = { @@ -72,30 +80,19 @@ void setup() { .y = 50, .width = 350, .height = 250, - .background_color = 0xbdf7, // Blue - .foreground_color = COL_DARK_BLUE, // White + .background_color = 0xbdf7, + .foreground_color = COL_DARK_BLUE, .focused = true, - .title = "lmao", + .title = "Second Window", .window_actions = {}, }; - wm->create_window(win2); + + Serial.println("Initialization complete"); } void loop() { - totalHeap = ESP.getHeapSize(); - 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; - + // Only handle rendering in main loop if (_display_state->update_display.load()) { dh->re_draw_desktop(); wm->draw_all(); @@ -103,19 +100,5 @@ void loop() { _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); -} - -void task1(void * pvParameters) { - for(;;) { - im->update(); - vTaskDelay(1); - } } \ No newline at end of file diff --git a/Desktop_Test/GLOBALS.h b/Desktop_Test/GLOBALS.h index 229427f..57f4e53 100644 --- a/Desktop_Test/GLOBALS.h +++ b/Desktop_Test/GLOBALS.h @@ -7,6 +7,11 @@ enum CLICK_EVENTS { RIGHT_CLICK = 2, }; +enum REDRAW_EVENT { + DESKTOP = 0, + WINDOWS = 1, +}; + struct CLICK_EVENT { int x; int y; diff --git a/Desktop_Test/desktop_hander.cpp b/Desktop_Test/desktop_hander.cpp index e025f0f..ab62296 100644 --- a/Desktop_Test/desktop_hander.cpp +++ b/Desktop_Test/desktop_hander.cpp @@ -1,10 +1,15 @@ #include "desktop_hander.h" #include "tft_handler.h" -void Desktop_Hander::init(TFT_Handler* th) { +void Desktop_Hander::init(TFT_Handler* th, DISPLAY_STATE* ds) { 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 = { .id = i, .place_x = i * 50 + 1, @@ -34,7 +39,6 @@ void Desktop_Hander::draw_background(int color) { void Desktop_Hander::draw_task_bar(int color) { // bar tft->draw_box(0, 293, 480, 40, color); - tft->draw_line(0, 294, 480, 294, 0xffff); // Outer shadow @@ -50,10 +54,33 @@ void Desktop_Hander::draw_task_bar(int color) { tft->draw_box(6, 298, 50, 18, color); } -void Desktop_Hander::draw_desktop_Item(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); +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); } -int Desktop_Hander::click_event(CLICK_EVENT event) { - return 0; +void Desktop_Hander::on_click_event(const CLICK_EVENT& event) { + 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; + } + } } \ No newline at end of file diff --git a/Desktop_Test/desktop_hander.h b/Desktop_Test/desktop_hander.h index b233428..ffcde90 100644 --- a/Desktop_Test/desktop_hander.h +++ b/Desktop_Test/desktop_hander.h @@ -1,19 +1,25 @@ #pragma once #include "desktop.h" #include "tft_handler.h" +#include "event_manager.h" #include #include "GLOBALS.h" -class Desktop_Hander { +class Desktop_Hander : public IEventListener { private: TFT_Handler* tft; + DISPLAY_STATE* display_state; std::vector items; + void handle_desktop_click(const CLICK_EVENT& event); + public: - void init(TFT_Handler* th); + void init(TFT_Handler* th, DISPLAY_STATE* ds); void re_draw_desktop(); void draw_background(int color); void draw_task_bar(int color); - void draw_desktop_Item(Desktop_Item desktop_item); - int click_event(CLICK_EVENT event); -}; + void draw_desktop_Item(const Desktop_Item& desktop_item); + + // IEventListener interface + void on_click_event(const CLICK_EVENT& event) override; +}; \ No newline at end of file diff --git a/Desktop_Test/event_manager.cpp b/Desktop_Test/event_manager.cpp new file mode 100644 index 0000000..93d4a6b --- /dev/null +++ b/Desktop_Test/event_manager.cpp @@ -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(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); + } +} \ No newline at end of file diff --git a/Desktop_Test/event_manager.h b/Desktop_Test/event_manager.h new file mode 100644 index 0000000..5ceff42 --- /dev/null +++ b/Desktop_Test/event_manager.h @@ -0,0 +1,43 @@ +#pragma once + +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "freertos/queue.h" +#include "GLOBALS.h" +#include +#include +#include + +// 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 _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); +}; \ No newline at end of file diff --git a/Desktop_Test/input_manager.cpp b/Desktop_Test/input_manager.cpp index c710c6d..c76da06 100644 --- a/Desktop_Test/input_manager.cpp +++ b/Desktop_Test/input_manager.cpp @@ -1,11 +1,11 @@ +#include "event_manager.h" #include "GLOBALS.h" #include "tft_handler.h" #include "HardwareSerial.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; - _event = event; _tf = tf; mi = { @@ -25,19 +25,15 @@ void InputManager::update() { for (int i = 0; i < NUM_BUTTONS; i++) { int reading = digitalRead(BUTTON_PINS[i]); - // Check if button state changed if (reading != lastButtonState[i]) { lastDebounceTime[i] = millis(); } - // Only register change after debounce delay if ((millis() - lastDebounceTime[i]) > DEBOUNCE_DELAY) { if (reading != buttonState[i]) { buttonState[i] = reading; - // Button was pressed (went from HIGH to LOW) if (buttonState[i] == LOW) { - // Add your button handling code here handle_button_press(i); } } @@ -48,42 +44,55 @@ void InputManager::update() { } void InputManager::handle_button_press(int buttonIndex) { - // Add your custom logic here for each button + bool needs_redraw = false; + switch(buttonIndex) { - case 0: - if (mi.x > 480) - mi.x = 479; - else - mi.x += 5; + case 0: // Right + mi.x = (mi.x + 5 > 476) ? 476 : mi.x + 5; + needs_redraw = true; break; - case 1: - if (mi.y > 320) - mi.y = 319; - else - mi.y += 5; + + case 1: // Down + mi.y = (mi.y + 5 > 316) ? 316 : mi.y + 5; + needs_redraw = true; break; - case 2: - if (mi.y < 0) - mi.y = 1; - else - mi.y -= 5; + + case 2: // Up + mi.y = (mi.y - 5 < 0) ? 0 : mi.y - 5; + needs_redraw = true; break; - case 3: - if (mi.x < 0) - mi.x = 1; - else - mi.x -= 5; + + case 3: // Left + mi.x = (mi.x - 5 < 0) ? 0 : mi.x - 5; + needs_redraw = true; break; - case 4: - _event->event = CLICK_EVENTS::LEFT_CLICK; - _event->x = mi.x; - _event->y = mi.y; + + case 4: // Click + { + CLICK_EVENT event = { + .x = mi.x, + .y = mi.y, + .event = CLICK_EVENTS::LEFT_CLICK + }; + EventManager::getInstance().publish(event); + } 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; } - _display_state->update_display.store(true); + if (needs_redraw) { + _display_state->update_display.store(true); + } } void InputManager::draw_button() { diff --git a/Desktop_Test/input_manager.h b/Desktop_Test/input_manager.h index b04cd30..174bdb2 100644 --- a/Desktop_Test/input_manager.h +++ b/Desktop_Test/input_manager.h @@ -1,5 +1,6 @@ #pragma once #include "tft_handler.h" +#include "event_manager.h" #include "GLOBALS.h" #include "icons.h" #include @@ -14,7 +15,6 @@ private: int buttonState[NUM_BUTTONS] = {HIGH, HIGH, HIGH, HIGH, HIGH, HIGH}; DISPLAY_STATE* _display_state; - CLICK_EVENT* _event; TFT_Handler* _tf; Mouse_Icon mi; @@ -22,7 +22,7 @@ private: bool are_buttons_pressed(int btn1, int btn2); 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 draw_button(); }; diff --git a/Desktop_Test/tft_handler.cpp b/Desktop_Test/tft_handler.cpp index dd36a2f..090146c 100644 --- a/Desktop_Test/tft_handler.cpp +++ b/Desktop_Test/tft_handler.cpp @@ -8,22 +8,22 @@ void TFT_Handler::init(DISPLAY_STATE* display_state) { 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.setRotation(3); - tft.fillRect(x, y, size_x, size_y, color); - +void TFT_Handler::end_draw() { tft.endWrite(); } -void TFT_Handler::draw_rect(int x, int y, int size_x, int size_y, int thickness, int color) { - tft.startWrite(); +void TFT_Handler::draw_box(int x, int y, int size_x, int size_y, int color) { + 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.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) { @@ -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) { - tft.startWrite(); - tft.setTextColor(TFT_WHITE); tft.setTextSize(2); tft.drawString(str.c_str(), x, y); - - tft.endWrite(); } void TFT_Handler::fill_screen(int color) { - tft.startWrite(); - tft.fillScreen(color); +} - tft.endWrite(); +void TFT_Handler::draw_box_sprite(int x, int y, int size_x, int size_y, int color) { + } \ No newline at end of file diff --git a/Desktop_Test/tft_handler.h b/Desktop_Test/tft_handler.h index f4946b0..d6fe287 100644 --- a/Desktop_Test/tft_handler.h +++ b/Desktop_Test/tft_handler.h @@ -55,9 +55,15 @@ public: 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_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_text(int x, int y, std::string str); void fill_screen(int color); + + void draw_box_sprite(int x, int y, int size_x, int size_y, int color); }; diff --git a/Desktop_Test/window_manager.cpp b/Desktop_Test/window_manager.cpp index 4c87567..84f1575 100644 --- a/Desktop_Test/window_manager.cpp +++ b/Desktop_Test/window_manager.cpp @@ -1,36 +1,39 @@ -#include "HardwareSerial.h" -#include "GLOBALS.h" #include "window_manager.h" #include -void WindowManager::init(TFT_Handler* th) { +void WindowManager::init(TFT_Handler* th, DISPLAY_STATE* ds) { tft = th; + display_state = ds; + + // Subscribe to events + EventManager::getInstance().subscribe(this); } void WindowManager::create_window(Window window) { windows.push_back(window); - draw_window(window); + display_state->update_display.store(true); } void WindowManager::close_window(int window_id) { for (auto it = windows.begin(); it != windows.end(); ++it) { if (it->id == window_id) { windows.erase(it); + display_state->update_display.store(true); break; } } - draw_all(); } void WindowManager::draw_all() { + tft->start_draw(); for (const auto& win : windows) { draw_window(win); } + tft->end_draw(); } -void WindowManager::draw_window(Window window) { +void WindowManager::draw_window(const Window& window) { // 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); // 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()); // 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) { - int id = -1; - - if (event.event == CLICK_EVENTS::NONE) { - return -1; +void WindowManager::on_click_event(const CLICK_EVENT& event) { + if (event.event != CLICK_EVENTS::LEFT_CLICK) { + return; } - + + 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 for (int i = windows.size() - 1; i >= 0; i--) { Window& window = windows[i]; - if (event.event != CLICK_EVENTS::LEFT_CLICK) - continue; + // Check if click is within window bounds + 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 (event.y >= window.y && event.y <= (window.y + window.height)) { - - if (window.focused) - break; - - // Unfocus all windows - for (size_t j = 0; j < windows.size(); j++) { - windows[j].focused = false; - } - - // Focus this window - window.focused = true; - id = window.id; - - // Move window to end (top of z-order) - auto it = windows.begin() + i; - std::rotate(it, it + 1, windows.end()); + if (window.focused) { + return -1; } + + // Unfocus all windows + for (auto& win : windows) { + win.focused = false; + } + + // Focus this window + window.focused = true; + + // Move window to end (top of z-order) + auto it = windows.begin() + i; + std::rotate(it, it + 1, windows.end()); + + return window.id; } } - return id; + return -1; } \ No newline at end of file diff --git a/Desktop_Test/window_manager.h b/Desktop_Test/window_manager.h index 0977b52..76a6cd4 100644 --- a/Desktop_Test/window_manager.h +++ b/Desktop_Test/window_manager.h @@ -2,6 +2,7 @@ #include "window.h" #include "tft_handler.h" +#include "event_manager.h" #include #include "GLOBALS.h" @@ -12,16 +13,21 @@ #define COL_DARK_BLUE 0x0014 #define COL_RED 0xf800 -class WindowManager { +class WindowManager : public IEventListener { private: - TFT_Handler* tft; // Pointer to shared TFT handler - std::vector windows; // Track all windows + TFT_Handler* tft; + DISPLAY_STATE* display_state; + std::vector windows; + + int handle_window_click(const CLICK_EVENT& event); public: - void init(TFT_Handler* th); + void init(TFT_Handler* th, DISPLAY_STATE* ds); void create_window(Window window); void close_window(int window_id); - void draw_all(); // Redraw all windows - void draw_window(Window window); - int click_event(CLICK_EVENT event); + void draw_all(); + void draw_window(const Window& window); + + // IEventListener interface + void on_click_event(const CLICK_EVENT& event) override; }; \ No newline at end of file