diff --git a/Desktop_Test/Desktop_Test.ino b/Desktop_Test/Desktop_Test.ino index 4d52f58..ed2c5f2 100644 --- a/Desktop_Test/Desktop_Test.ino +++ b/Desktop_Test/Desktop_Test.ino @@ -38,11 +38,13 @@ void setup() { // Initialize in order th->init(_display_state); - sm->init(_display_state); // Initialize event manager (creates dispatcher task) EventManager::getInstance().init(); + // Initialize system manager with shell and tft references + sm->init(_display_state, _shell, th); + // Initialize components (they subscribe to events) im->init(_display_state, th); _shell->init(th, _display_state, sm); diff --git a/Desktop_Test/example_programs.h b/Desktop_Test/example_programs.h new file mode 100644 index 0000000..73aa24e --- /dev/null +++ b/Desktop_Test/example_programs.h @@ -0,0 +1,85 @@ +#pragma once +#include "program.h" +#include "shell.h" +#include "tft_handler.h" +#include + +// Example Program 1: Simple counter +class CounterProgram : public Program { +private: + int counter = 0; + +public: + void run() override { + Serial.println("Counter program started!"); + + while (_running) { + counter++; + Serial.printf("Counter: %d\n", counter); + + // You can modify the window title + if (_window) { + _window->title = "Counter: " + std::to_string(counter); + if (!_window->minimized) + _display_state->update_display.store(true); + } + + vTaskDelay(pdMS_TO_TICKS(1000)); + } + } +}; + +// Example Program 2: Text editor +class TextEditorProgram : public Program { +public: + void run() override { + Serial.println("Text editor started!"); + + // You have full access to the window and can draw to it + while (_running) { + // Handle text editing logic here + // Draw to the window content area using _tft + + vTaskDelay(pdMS_TO_TICKS(100)); + } + } +}; + +// Example Program 3: Calculator +class CalculatorProgram : public Program { +public: + void run() override { + Serial.println("Calculator started!"); + + while (_running) { + // Calculator logic here + vTaskDelay(pdMS_TO_TICKS(100)); + } + } +}; + +// Example Program 4: Game +class GameProgram : public Program { +public: + void run() override { + Serial.println("Game started!"); + + while (_running) { + // Game logic and rendering + vTaskDelay(pdMS_TO_TICKS(50)); // 20 FPS + } + } +}; + +// Example Program 5: Settings +class SettingsProgram : public Program { +public: + void run() override { + Serial.println("Settings started!"); + + while (_running) { + // Settings UI logic + vTaskDelay(pdMS_TO_TICKS(100)); + } + } +}; \ No newline at end of file diff --git a/Desktop_Test/program.cpp b/Desktop_Test/program.cpp index 9354481..7587741 100644 --- a/Desktop_Test/program.cpp +++ b/Desktop_Test/program.cpp @@ -1,31 +1,45 @@ -#include "freertos/idf_additions.h" -#include "esp_heap_caps.h" #include "program.h" +#include "shell.h" +#include "tft_handler.h" -Program::Program(DISPLAY_STATE* display_state) { - _display_state = display_state; +Program::Program() + : _window(nullptr), _shell(nullptr), _tft(nullptr), + _display_state(nullptr), _task_handle(nullptr), + _id(-1), _running(false) { } -int Program::init(int id, std::string name, Window* window) { +Program::~Program() { + close(); +} + +void Program::init(int id, std::string name, Window* window, Shell* shell, TFT_Handler* tft, DISPLAY_STATE* display_state) { _id = id; - _task_name = name; + _name = name; _window = window; + _shell = shell; + _tft = tft; + _display_state = display_state; + _running = true; - xTaskCreatePinnedToCore(loop, _task_name.c_str(), 4096, this, 1, &_task_handle, 0); + // Create the task + xTaskCreatePinnedToCore(task_wrapper, _name.c_str(), 4096, this, 1, &_task_handle, 0); +} - return _id; +void Program::task_wrapper(void* pvParameters) { + Program* program = static_cast(pvParameters); + + // Call the specific program's run method + program->run(); + + // If run() returns, the program has finished + program->_running = false; + vTaskDelete(NULL); } void Program::close() { - vTaskDelete(_task_handle); -} - -void Program::loop(void* pvParameters) { - Program* self = static_cast(pvParameters); - - (self->_installed_program.*(self->_program_func))(); - - while (true) { - vTaskDelay(pdMS_TO_TICKS(1000)); // Sleep for 1 second + _running = false; + if (_task_handle) { + vTaskDelete(_task_handle); + _task_handle = nullptr; } } \ No newline at end of file diff --git a/Desktop_Test/program.h b/Desktop_Test/program.h index 3c32fe6..4dc6e40 100644 --- a/Desktop_Test/program.h +++ b/Desktop_Test/program.h @@ -4,7 +4,10 @@ #include "GLOBALS.h" #include #include -#include "program_registry.h" + +// Forward declarations +class Shell; +class TFT_Handler; struct TaskBarItem { int id; @@ -24,6 +27,7 @@ struct DesktopItem { int icon_size_x; int icon_size_y; std::string name; + std::string program_class; // Which program class to instantiate }; enum class WindowAction { @@ -56,20 +60,35 @@ struct Window { std::vector window_decorations; }; +// Base Program class - all programs inherit from this class Program { -private: +protected: Window* _window; + Shell* _shell; + TFT_Handler* _tft; DISPLAY_STATE* _display_state; - TaskHandle_t _task_handle; - static void loop(void* pvParameters); + int _id; + std::string _name; + bool _running; + + static void task_wrapper(void* pvParameters); public: - int _id; - std::string _task_name = ""; - void (InstalledProgram::*_program_func)(); - InstalledProgram _installed_program; - Program(DISPLAY_STATE* display_state); - int init(int id, std::string name, Window* window); - void close(); + Program(); + virtual ~Program(); + + // Initialize the program with its window and shell reference + void init(int id, std::string name, Window* window, Shell* shell, TFT_Handler* tft, DISPLAY_STATE* display_state); + + // Override this in your specific programs + virtual void run() = 0; + + // Called when the program should stop + virtual void close(); + + // Getters + int get_id() const { return _id; } + std::string get_name() const { return _name; } + Window* get_window() const { return _window; } }; \ No newline at end of file diff --git a/Desktop_Test/shell.cpp b/Desktop_Test/shell.cpp index 56bc54f..e8bb192 100644 --- a/Desktop_Test/shell.cpp +++ b/Desktop_Test/shell.cpp @@ -10,27 +10,69 @@ void Shell::init(TFT_Handler* th, DISPLAY_STATE* ds, SystemManager* system_manag display_state = ds; _system_manager = system_manager; - // Subscribe to click events EventManager::getInstance().subscribe(this); draw_background(COL_TEAL); draw_task_bar(COL_GREY); - // Create desktop items - for (int i = 0; i < 5; i++) { - DesktopItem di = { - .id = i, - .place_x = i * 50 + 1, - .place_y = 10, - .icon_size_x = 45, - .icon_size_y = 50, - .name = std::to_string(i), - }; - items.push_back(di); - } + // Create desktop items with their associated program classes + DesktopItem di0 = { + .id = 0, + .place_x = 0 * 50 + 1, + .place_y = 10, + .icon_size_x = 45, + .icon_size_y = 50, + .name = "Counter", + .program_class = "CounterProgram" + }; + items.push_back(di0); - for (int i = 0; i < items.size(); ++i) { - draw_desktop_Item(items[i]); + DesktopItem di1 = { + .id = 1, + .place_x = 1 * 50 + 1, + .place_y = 10, + .icon_size_x = 45, + .icon_size_y = 50, + .name = "Text Editor", + .program_class = "TextEditorProgram" + }; + items.push_back(di1); + + DesktopItem di2 = { + .id = 2, + .place_x = 2 * 50 + 1, + .place_y = 10, + .icon_size_x = 45, + .icon_size_y = 50, + .name = "Calculator", + .program_class = "CalculatorProgram" + }; + items.push_back(di2); + + DesktopItem di3 = { + .id = 3, + .place_x = 3 * 50 + 1, + .place_y = 10, + .icon_size_x = 45, + .icon_size_y = 50, + .name = "Game", + .program_class = "GameProgram" + }; + items.push_back(di3); + + DesktopItem di4 = { + .id = 4, + .place_x = 4 * 50 + 1, + .place_y = 10, + .icon_size_x = 45, + .icon_size_y = 50, + .name = "Settings", + .program_class = "SettingsProgram" + }; + items.push_back(di4); + + for (const auto& item : items) { + draw_desktop_Item(item); } } @@ -284,20 +326,21 @@ int Shell::handle_window_click(CLICK_EVENT event) { } int Shell::handle_desktop_click(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)) { + 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)) { - for (int i = 0; i < _system_manager->_programs.size(); ++i) { - Serial.println(_system_manager->_programs[i]->_task_name.c_str()); - if (_system_manager->_programs[i]->_task_name == item.name) return -1; + // Check if program is already running + for (const auto& prog : _system_manager->_programs) { + if (prog->get_name() == item.name) { + return -1; // Already running + } } - WindowDecoration dec; + // Create window Window* win = new Window(); - WindowDecoration dec1 = { + WindowDecoration close_btn = { .x_offset = 6, .y_offset = 5, .width = 25, @@ -305,7 +348,7 @@ int Shell::handle_desktop_click(CLICK_EVENT event) { .action = WindowAction::CLOSE, }; - WindowDecoration dec2 = { + WindowDecoration minimize_btn = { .x_offset = 36, .y_offset = 5, .width = 25, @@ -313,8 +356,8 @@ int Shell::handle_desktop_click(CLICK_EVENT event) { .action = WindowAction::MINIMIZE, }; - win->window_decorations.push_back(dec1); - win->window_decorations.push_back(dec2); + win->window_decorations.push_back(close_btn); + win->window_decorations.push_back(minimize_btn); win->x = 10; win->y = 0; @@ -326,7 +369,8 @@ int Shell::handle_desktop_click(CLICK_EVENT event) { win->minimized = false; win->title = item.name; - bool result = _system_manager->spawn_program(win, win->title); + // Spawn program using the program_class + bool result = _system_manager->spawn_program(win, item.program_class); if (!result) { delete win; @@ -334,7 +378,6 @@ int Shell::handle_desktop_click(CLICK_EVENT event) { } create_window(win); - return item.id; } } diff --git a/Desktop_Test/system_manager.cpp b/Desktop_Test/system_manager.cpp index 8a31bc2..95c754e 100644 --- a/Desktop_Test/system_manager.cpp +++ b/Desktop_Test/system_manager.cpp @@ -1,48 +1,59 @@ -#include "program.h" #include "system_manager.h" +#include "shell.h" +#include "tft_handler.h" +#include "example_programs.h" #include -std::vector SystemManager::init(DISPLAY_STATE* display_state) { +void SystemManager::init(DISPLAY_STATE* display_state, Shell* shell, TFT_Handler* tft) { _display_state = display_state; + _shell = shell; + _tft = tft; - funcMap["0"] = &InstalledProgram::do_stuff; - funcMap["1"] = &InstalledProgram::do_some_other_stuff; - funcMap["2"] = &InstalledProgram::lol; - funcMap["3"] = &InstalledProgram::omagelol; - funcMap["4"] = &InstalledProgram::sheeesh; - - return _programs; + // Register all available programs + register_program("CounterProgram"); + register_program("TextEditorProgram"); + register_program("CalculatorProgram"); + register_program("GameProgram"); + register_program("SettingsProgram"); } -bool SystemManager::spawn_program(Window* window, std::string program_name) { - for (size_t i = 0; i < _programs.size(); ++i) { - if (_programs[i]->_task_name == window->title) return false; +bool SystemManager::spawn_program(Window* window, const std::string& program_class) { + // Check if program with same name is already running + for (const auto& prog : _programs) { + if (prog->get_name() == window->title) { + return false; + } } - // Check if the program exists in the map - if (funcMap.find(program_name) == funcMap.end()) { + // Check if the program class exists + auto it = _program_factories.find(program_class); + if (it == _program_factories.end()) { + Serial.printf("Program class '%s' not found!\n", program_class.c_str()); return false; } - Serial.println(window->title.c_str()); - - Program* program = new Program(_display_state); - - program->_program_func = funcMap[program_name]; + // Create the program instance using the factory + Program* program = it->second(); + + // Assign ID and initialize window->id = _next_program_id; - program->init(_next_program_id, window->title, window); + program->init(_next_program_id, window->title, window, _shell, _tft, _display_state); + _next_program_id++; _programs.push_back(program); + + Serial.printf("Spawned program: %s (ID: %d)\n", window->title.c_str(), window->id); + return true; } void SystemManager::close_program(int id) { for (size_t i = 0; i < _programs.size(); ++i) { - if (_programs[i]->_id == id) { - _programs[i]->close(); - delete _programs[i]; // Free the memory + if (_programs[i]->get_id() == id) { + Serial.printf("Closing program ID: %d\n", id); + delete _programs[i]; _programs.erase(_programs.begin() + i); - break; // Exit after erase + break; } } } \ No newline at end of file diff --git a/Desktop_Test/system_manager.h b/Desktop_Test/system_manager.h index 52e4d71..469a012 100644 --- a/Desktop_Test/system_manager.h +++ b/Desktop_Test/system_manager.h @@ -1,19 +1,43 @@ #pragma once #include "program.h" #include -#include "program_registry.h" #include #include +#include + +// Forward declarations +class Shell; +class TFT_Handler; class SystemManager { private: DISPLAY_STATE* _display_state; + Shell* _shell; + TFT_Handler* _tft; int _next_program_id = 1; + + // Factory function type: creates a new instance of a Program + using ProgramFactory = std::function; + + // Map of program class names to factory functions + std::unordered_map _program_factories; public: - std::unordered_map funcMap; std::vector _programs; - std::vector init(DISPLAY_STATE* display_state); - bool spawn_program(Window* window, std::string program_name); + + void init(DISPLAY_STATE* display_state, Shell* shell, TFT_Handler* tft); + + // Register a program type with a factory function + template + void register_program(const std::string& class_name) { + _program_factories[class_name] = []() -> Program* { + return new T(); + }; + } + + // Spawn a program by its class name + bool spawn_program(Window* window, const std::string& program_class); + + // Close a running program void close_program(int id); }; \ No newline at end of file