Refactored
This commit is contained in:
parent
6d04d15449
commit
af36f344a5
@ -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);
|
||||||
|
|||||||
85
Desktop_Test/example_programs.h
Normal file
85
Desktop_Test/example_programs.h
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
#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!");
|
||||||
|
|
||||||
|
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));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
@ -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
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -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 {
|
||||||
@ -56,20 +60,35 @@ struct Window {
|
|||||||
std::vector<WindowDecoration> window_decorations;
|
std::vector<WindowDecoration> window_decorations;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 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; }
|
||||||
};
|
};
|
||||||
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -284,20 +326,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 +348,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 +356,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;
|
||||||
@ -326,7 +369,8 @@ int Shell::handle_desktop_click(CLICK_EVENT event) {
|
|||||||
win->minimized = false;
|
win->minimized = false;
|
||||||
win->title = item.name;
|
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) {
|
if (!result) {
|
||||||
delete win;
|
delete win;
|
||||||
@ -334,7 +378,6 @@ int Shell::handle_desktop_click(CLICK_EVENT event) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
create_window(win);
|
create_window(win);
|
||||||
|
|
||||||
return item.id;
|
return item.id;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -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);
|
||||||
};
|
};
|
||||||
Loading…
Reference in New Issue
Block a user