Compare commits
2 Commits
6d04d15449
...
36dd179def
| Author | SHA1 | Date | |
|---|---|---|---|
| 36dd179def | |||
| af36f344a5 |
@ -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);
|
||||
|
||||
98
Desktop_Test/example_programs.h
Normal file
98
Desktop_Test/example_programs.h
Normal 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));
|
||||
}
|
||||
}
|
||||
};
|
||||
@ -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<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() {
|
||||
vTaskDelete(_task_handle);
|
||||
}
|
||||
|
||||
void Program::loop(void* pvParameters) {
|
||||
Program* self = static_cast<Program*>(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;
|
||||
}
|
||||
}
|
||||
@ -4,7 +4,10 @@
|
||||
#include "GLOBALS.h"
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#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 {
|
||||
@ -42,6 +46,12 @@ struct WindowDecoration {
|
||||
WindowAction action;
|
||||
};
|
||||
|
||||
struct WindowContentText {
|
||||
int x;
|
||||
int y;
|
||||
std::string text;
|
||||
};
|
||||
|
||||
struct Window {
|
||||
int id;
|
||||
int x;
|
||||
@ -54,22 +64,38 @@ struct Window {
|
||||
bool minimized;
|
||||
std::string title;
|
||||
std::vector<WindowDecoration> window_decorations;
|
||||
std::vector<WindowContentText> window_content_text;
|
||||
};
|
||||
|
||||
// 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; }
|
||||
};
|
||||
@ -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");
|
||||
}
|
||||
@ -1,9 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
struct InstalledProgram {
|
||||
void do_stuff();
|
||||
void do_some_other_stuff();
|
||||
void lol();
|
||||
void omagelol();
|
||||
void sheeesh();
|
||||
};
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@ -182,6 +224,10 @@ void Shell::draw_window(Window window) {
|
||||
|
||||
// Window content
|
||||
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 =======
|
||||
@ -284,20 +330,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 +352,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 +360,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;
|
||||
@ -325,8 +372,10 @@ int Shell::handle_desktop_click(CLICK_EVENT event) {
|
||||
win->focused = true;
|
||||
win->minimized = false;
|
||||
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) {
|
||||
delete win;
|
||||
@ -334,7 +383,6 @@ int Shell::handle_desktop_click(CLICK_EVENT event) {
|
||||
}
|
||||
|
||||
create_window(win);
|
||||
|
||||
return item.id;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,48 +1,59 @@
|
||||
#include "program.h"
|
||||
#include "system_manager.h"
|
||||
#include "shell.h"
|
||||
#include "tft_handler.h"
|
||||
#include "example_programs.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;
|
||||
_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>("CounterProgram");
|
||||
register_program<TextEditorProgram>("TextEditorProgram");
|
||||
register_program<CalculatorProgram>("CalculatorProgram");
|
||||
register_program<GameProgram>("GameProgram");
|
||||
register_program<SettingsProgram>("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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,19 +1,43 @@
|
||||
#pragma once
|
||||
#include "program.h"
|
||||
#include <vector>
|
||||
#include "program_registry.h"
|
||||
#include <unordered_map>
|
||||
#include <string>
|
||||
#include <functional>
|
||||
|
||||
// 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<Program*()>;
|
||||
|
||||
// Map of program class names to factory functions
|
||||
std::unordered_map<std::string, ProgramFactory> _program_factories;
|
||||
|
||||
public:
|
||||
std::unordered_map<std::string, void(InstalledProgram::*)()> funcMap;
|
||||
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);
|
||||
};
|
||||
Loading…
Reference in New Issue
Block a user