Compare commits

...

2 Commits

Author SHA1 Message Date
36dd179def You can now add stuff to show in a window 2026-01-06 19:06:47 +01:00
af36f344a5 Refactored 2026-01-05 18:23:46 +01:00
9 changed files with 309 additions and 117 deletions

View File

@ -38,11 +38,13 @@ void setup() {
// Initialize in order // Initialize in order
th->init(_display_state); th->init(_display_state);
sm->init(_display_state);
// Initialize event manager (creates dispatcher task) // Initialize event manager (creates dispatcher task)
EventManager::getInstance().init(); EventManager::getInstance().init();
// Initialize system manager with shell and tft references
sm->init(_display_state, _shell, th);
// Initialize components (they subscribe to events) // Initialize components (they subscribe to events)
im->init(_display_state, th); im->init(_display_state, th);
_shell->init(th, _display_state, sm); _shell->init(th, _display_state, sm);

View File

@ -0,0 +1,98 @@
#pragma once
#include "program.h"
#include "shell.h"
#include "tft_handler.h"
#include <Arduino.h>
// Example Program 1: Simple counter
class CounterProgram : public Program {
private:
int counter = 0;
public:
void run() override {
Serial.println("Counter program started!");
WindowContentText text;
text.x = _window->x + 10;
text.y = _window->y + 50;
_window->window_content_text.push_back(text);
while (_running) {
counter++;
Serial.printf("Counter: %d\n", counter);
// You can modify the window title
if (_window) {
if (!_window->minimized) {
_window->title = "Counter: " + std::to_string(counter);
for (int i = 0; i < _window->window_content_text.size(); i++) {
_window->window_content_text[i].text = std::to_string(counter);
}
_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));
}
}
};

View File

@ -1,31 +1,45 @@
#include "freertos/idf_additions.h"
#include "esp_heap_caps.h"
#include "program.h" #include "program.h"
#include "shell.h"
#include "tft_handler.h"
Program::Program(DISPLAY_STATE* display_state) { Program::Program()
_display_state = display_state; : _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; _id = id;
_task_name = name; _name = name;
_window = window; _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<Program*>(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() { void Program::close() {
vTaskDelete(_task_handle); _running = false;
} if (_task_handle) {
vTaskDelete(_task_handle);
void Program::loop(void* pvParameters) { _task_handle = nullptr;
Program* self = static_cast<Program*>(pvParameters);
(self->_installed_program.*(self->_program_func))();
while (true) {
vTaskDelay(pdMS_TO_TICKS(1000)); // Sleep for 1 second
} }
} }

View File

@ -4,7 +4,10 @@
#include "GLOBALS.h" #include "GLOBALS.h"
#include <string> #include <string>
#include <vector> #include <vector>
#include "program_registry.h"
// Forward declarations
class Shell;
class TFT_Handler;
struct TaskBarItem { struct TaskBarItem {
int id; int id;
@ -24,6 +27,7 @@ struct DesktopItem {
int icon_size_x; int icon_size_x;
int icon_size_y; int icon_size_y;
std::string name; std::string name;
std::string program_class; // Which program class to instantiate
}; };
enum class WindowAction { enum class WindowAction {
@ -42,6 +46,12 @@ struct WindowDecoration {
WindowAction action; WindowAction action;
}; };
struct WindowContentText {
int x;
int y;
std::string text;
};
struct Window { struct Window {
int id; int id;
int x; int x;
@ -54,22 +64,38 @@ struct Window {
bool minimized; bool minimized;
std::string title; std::string title;
std::vector<WindowDecoration> window_decorations; std::vector<WindowDecoration> window_decorations;
std::vector<WindowContentText> window_content_text;
}; };
// Base Program class - all programs inherit from this
class Program { class Program {
private: protected:
Window* _window; Window* _window;
Shell* _shell;
TFT_Handler* _tft;
DISPLAY_STATE* _display_state; DISPLAY_STATE* _display_state;
TaskHandle_t _task_handle; TaskHandle_t _task_handle;
static void loop(void* pvParameters); int _id;
std::string _name;
bool _running;
static void task_wrapper(void* pvParameters);
public: public:
int _id; Program();
std::string _task_name = ""; virtual ~Program();
void (InstalledProgram::*_program_func)();
InstalledProgram _installed_program; // Initialize the program with its window and shell reference
Program(DISPLAY_STATE* display_state); void init(int id, std::string name, Window* window, Shell* shell, TFT_Handler* tft, DISPLAY_STATE* display_state);
int init(int id, std::string name, Window* window);
void close(); // 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; }
}; };

View File

@ -1,22 +0,0 @@
#include "program_registry.h"
#include <Arduino.h>
void InstalledProgram::do_stuff() {
Serial.println("lol");
}
void InstalledProgram::do_some_other_stuff() {
Serial.println("ASDDSAASDASD");
}
void InstalledProgram::lol() {
Serial.println("ffffrf");
}
void InstalledProgram::omagelol() {
Serial.println("11111");
}
void InstalledProgram::sheeesh() {
Serial.println("44444");
}

View File

@ -1,9 +0,0 @@
#pragma once
struct InstalledProgram {
void do_stuff();
void do_some_other_stuff();
void lol();
void omagelol();
void sheeesh();
};

View File

@ -10,27 +10,69 @@ void Shell::init(TFT_Handler* th, DISPLAY_STATE* ds, SystemManager* system_manag
display_state = ds; display_state = ds;
_system_manager = system_manager; _system_manager = system_manager;
// Subscribe to click events
EventManager::getInstance().subscribe(this); EventManager::getInstance().subscribe(this);
draw_background(COL_TEAL); draw_background(COL_TEAL);
draw_task_bar(COL_GREY); draw_task_bar(COL_GREY);
// Create desktop items // Create desktop items with their associated program classes
for (int i = 0; i < 5; i++) { DesktopItem di0 = {
DesktopItem di = { .id = 0,
.id = i, .place_x = 0 * 50 + 1,
.place_x = i * 50 + 1, .place_y = 10,
.place_y = 10, .icon_size_x = 45,
.icon_size_x = 45, .icon_size_y = 50,
.icon_size_y = 50, .name = "Counter",
.name = std::to_string(i), .program_class = "CounterProgram"
}; };
items.push_back(di); items.push_back(di0);
}
for (int i = 0; i < items.size(); ++i) { DesktopItem di1 = {
draw_desktop_Item(items[i]); .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);
} }
} }
@ -182,6 +224,10 @@ void Shell::draw_window(Window window) {
// Window content // Window content
tft->draw_box(window.x + 3, window.y + 35, window.width - 6, window.height - 38, COL_WHITE); tft->draw_box(window.x + 3, window.y + 35, window.width - 6, window.height - 38, COL_WHITE);
for (WindowContentText text : window.window_content_text) {
tft->draw_text(text.x, text.y, text.text, COL_BLACK);
}
} }
// ======= Desktop ======= // ======= Desktop =======
@ -284,20 +330,21 @@ int Shell::handle_window_click(CLICK_EVENT event) {
} }
int Shell::handle_desktop_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) { 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) { // Check if program is already running
Serial.println(_system_manager->_programs[i]->_task_name.c_str()); for (const auto& prog : _system_manager->_programs) {
if (_system_manager->_programs[i]->_task_name == item.name) return -1; if (prog->get_name() == item.name) {
return -1; // Already running
}
} }
WindowDecoration dec; // Create window
Window* win = new Window(); Window* win = new Window();
WindowDecoration dec1 = { WindowDecoration close_btn = {
.x_offset = 6, .x_offset = 6,
.y_offset = 5, .y_offset = 5,
.width = 25, .width = 25,
@ -305,7 +352,7 @@ int Shell::handle_desktop_click(CLICK_EVENT event) {
.action = WindowAction::CLOSE, .action = WindowAction::CLOSE,
}; };
WindowDecoration dec2 = { WindowDecoration minimize_btn = {
.x_offset = 36, .x_offset = 36,
.y_offset = 5, .y_offset = 5,
.width = 25, .width = 25,
@ -313,8 +360,8 @@ int Shell::handle_desktop_click(CLICK_EVENT event) {
.action = WindowAction::MINIMIZE, .action = WindowAction::MINIMIZE,
}; };
win->window_decorations.push_back(dec1); win->window_decorations.push_back(close_btn);
win->window_decorations.push_back(dec2); win->window_decorations.push_back(minimize_btn);
win->x = 10; win->x = 10;
win->y = 0; win->y = 0;
@ -325,8 +372,10 @@ int Shell::handle_desktop_click(CLICK_EVENT event) {
win->focused = true; win->focused = true;
win->minimized = false; win->minimized = false;
win->title = item.name; win->title = item.name;
win->window_content_text = {};
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) { if (!result) {
delete win; delete win;
@ -334,7 +383,6 @@ int Shell::handle_desktop_click(CLICK_EVENT event) {
} }
create_window(win); create_window(win);
return item.id; return item.id;
} }
} }

View File

@ -1,48 +1,59 @@
#include "program.h"
#include "system_manager.h" #include "system_manager.h"
#include "shell.h"
#include "tft_handler.h"
#include "example_programs.h"
#include <Arduino.h> #include <Arduino.h>
std::vector<Program*> SystemManager::init(DISPLAY_STATE* display_state) { void SystemManager::init(DISPLAY_STATE* display_state, Shell* shell, TFT_Handler* tft) {
_display_state = display_state; _display_state = display_state;
_shell = shell;
_tft = tft;
funcMap["0"] = &InstalledProgram::do_stuff; // Register all available programs
funcMap["1"] = &InstalledProgram::do_some_other_stuff; register_program<CounterProgram>("CounterProgram");
funcMap["2"] = &InstalledProgram::lol; register_program<TextEditorProgram>("TextEditorProgram");
funcMap["3"] = &InstalledProgram::omagelol; register_program<CalculatorProgram>("CalculatorProgram");
funcMap["4"] = &InstalledProgram::sheeesh; register_program<GameProgram>("GameProgram");
register_program<SettingsProgram>("SettingsProgram");
return _programs;
} }
bool SystemManager::spawn_program(Window* window, std::string program_name) { bool SystemManager::spawn_program(Window* window, const std::string& program_class) {
for (size_t i = 0; i < _programs.size(); ++i) { // Check if program with same name is already running
if (_programs[i]->_task_name == window->title) return false; for (const auto& prog : _programs) {
if (prog->get_name() == window->title) {
return false;
}
} }
// Check if the program exists in the map // Check if the program class exists
if (funcMap.find(program_name) == funcMap.end()) { 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; return false;
} }
Serial.println(window->title.c_str()); // Create the program instance using the factory
Program* program = it->second();
Program* program = new Program(_display_state);
// Assign ID and initialize
program->_program_func = funcMap[program_name];
window->id = _next_program_id; 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++; _next_program_id++;
_programs.push_back(program); _programs.push_back(program);
Serial.printf("Spawned program: %s (ID: %d)\n", window->title.c_str(), window->id);
return true; return true;
} }
void SystemManager::close_program(int id) { void SystemManager::close_program(int id) {
for (size_t i = 0; i < _programs.size(); ++i) { for (size_t i = 0; i < _programs.size(); ++i) {
if (_programs[i]->_id == id) { if (_programs[i]->get_id() == id) {
_programs[i]->close(); Serial.printf("Closing program ID: %d\n", id);
delete _programs[i]; // Free the memory delete _programs[i];
_programs.erase(_programs.begin() + i); _programs.erase(_programs.begin() + i);
break; // Exit after erase break;
} }
} }
} }

View File

@ -1,19 +1,43 @@
#pragma once #pragma once
#include "program.h" #include "program.h"
#include <vector> #include <vector>
#include "program_registry.h"
#include <unordered_map> #include <unordered_map>
#include <string> #include <string>
#include <functional>
// Forward declarations
class Shell;
class TFT_Handler;
class SystemManager { class SystemManager {
private: private:
DISPLAY_STATE* _display_state; DISPLAY_STATE* _display_state;
Shell* _shell;
TFT_Handler* _tft;
int _next_program_id = 1; int _next_program_id = 1;
// Factory function type: creates a new instance of a Program
using ProgramFactory = std::function<Program*()>;
// Map of program class names to factory functions
std::unordered_map<std::string, ProgramFactory> _program_factories;
public: public:
std::unordered_map<std::string, void(InstalledProgram::*)()> funcMap;
std::vector<Program*> _programs; std::vector<Program*> _programs;
std::vector<Program*> 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<typename T>
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); void close_program(int id);
}; };