#include "shell.h" #include "GLOBALS.h" #include #include "system_manager.h" void Shell::init(TFT_Handler* th, DISPLAY_STATE* ds, SystemManager* system_manager) { tft = th; 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, }; items.push_back(di); } for (int i = 0; i < items.size(); ++i) { draw_desktop_Item(items[i]); } } void Shell::on_click_event(CLICK_EVENT event) { if (event.event != CLICK_EVENTS::LEFT_CLICK) return; int window_id = handle_window_click(event); if (window_id >= 0) { display_state->update_display.store(true); return; } int icon_id = handle_desktop_click(event); if (icon_id != -1) { display_state->update_display.store(true); return; } int tast_icon_id = handle_taskbar_click(event); if (tast_icon_id != -1) { display_state->update_display.store(true); return; } bool ckicked_start_button = handle_start_button_click(event); if (ckicked_start_button) { display_state->update_display.store(true); return; } } // ======= Window ======= void Shell::create_window(Window* window) { int total_pos_x = window->x + window->width; int total_pos_y = window->y + window->height; // Clamp window within the screen size AND taskbar if (total_pos_x > MAX_SCREEN_WIDTH) window->x = MAX_SCREEN_WIDTH - window->width; if (total_pos_y > MAX_SCREEN_HEIGHT) window->y = MAX_SCREEN_HEIGHT - window->height - 29; windows.push_back(window); TaskBarItem item; item.id = window->id; item.focused = window->focused; item.name = window->title; item.width = 95; item.height = 18; item.offset_x = 100; item.place_y = 298; // Set place_x and place_y for ALL items if (task_bar_items.size() == 0) { item.place_x = 60; } else { // For subsequent items, use the previous item's position + offset const TaskBarItem& prev = task_bar_items.back(); item.place_x = prev.place_x + prev.offset_x; } task_bar_items.push_back(item); display_state->update_display.store(true); } void Shell::close_window(int window_id) { for (auto it = windows.begin(); it != windows.end(); ++it) { if ((*it)->id == window_id) { windows.erase(it); _system_manager->close_program((*it)->id); display_state->update_display.store(true); break; } } for (auto it = task_bar_items.begin(); it != task_bar_items.end(); ++it) { if (it->id == window_id) { task_bar_items.erase(it); display_state->update_display.store(true); break; } } for (int i = 0; i < task_bar_items.size(); ++i) { TaskBarItem item = task_bar_items[i]; if (i == 0) { item.place_x = 60; } else { // For subsequent items, use the previous item's position + offset const TaskBarItem& prev = task_bar_items.back(); item.place_x = prev.place_x + prev.offset_x; } task_bar_items[i] = item; } } void Shell::minimize_window(int window_id) { for (auto it = windows.begin(); it != windows.end(); ++it) { for (int i = 0; i < task_bar_items.size(); ++i) { if ((*it)->id == window_id && (*it)->id == task_bar_items[i].id) { (*it)->minimized = true; task_bar_items[i].focused = false; display_state->update_display.store(true); break; } } } } void Shell::draw_all() { tft->start_draw(); draw_background(0x0410); draw_task_bar(0xbdf7); for (const auto& item : items) { draw_desktop_Item(item); } for (const auto& win : windows) { if (!win->minimized) draw_window(*win); } tft->end_draw(); } void Shell::draw_window(Window window) { if (window.minimized) return; // Outer shadow tft->draw_rect(window.x, window.y, window.width + 2, window.height + 2, 1, 0x0000); // Inner shadow tft->draw_rect(window.x, window.y, window.width + 1, window.height + 1, 1, 0x8410); // Highlight tft->draw_rect(window.x - 1, window.y - 1, window.width + 1, window.height + 1, 1, 0xffff); // Window tft->draw_box(window.x, window.y, window.width, window.height, window.background_color); // Decorations tft->draw_box(window.x + 3, window.y + 3, window.width - 6, 30, window.foreground_color); for (auto it = window.window_decorations.begin(); it != window.window_decorations.end(); ++it) { if (it->action == WindowAction::CLOSE) { // Close button tft->draw_box(window.x + it->x_offset, window.y + it->y_offset, it->height, it->width, COL_RED); } if (it->action == WindowAction::MINIMIZE) { // Minimize button tft->draw_box(window.x + it->x_offset, window.y + it->y_offset, it->height, it->width, COL_LIGHT_GREY); } } // Window title tft->draw_text(window.x + 6 + 65, window.y + 10, window.title.c_str()); // Window content tft->draw_box(window.x + 3, window.y + 35, window.width - 6, window.height - 38, COL_WHITE); } // ======= Desktop ======= void Shell::draw_background(int color) { tft->fill_screen(color); } void Shell::draw_desktop_Item(DesktopItem 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 Shell::draw_task_bar(int color) { // bar tft->draw_box(0, 293, 480, 40, color); tft->draw_line(0, 294, 480, 294, 0xffff); // Outer shadow tft->draw_box(5, 297, 53, 21, 0x0000); // Inner shadow tft->draw_box(6, 298, 51, 19, 0x8410); // Highlight tft->draw_box(5, 297, 51, 19, 0xffff); // Button tft->draw_box(6, 298, 50, 18, color); Serial.println(task_bar_items.size()); for (TaskBarItem item : task_bar_items) { if (item.focused) { tft->draw_box(item.place_x - 2, item.place_y - 2, item.width + 3, item.height + 3, COL_BLACK); tft->draw_box(item.place_x - 1, item.place_y - 1, item.width + 2, item.height + 2, COL_DARK_GREY); tft->draw_box(item.place_x, item.place_y, item.width + 2, item.height + 2, COL_WHITE); tft->draw_box(item.place_x, item.place_y, item.width, item.height, COL_GREY); } else { tft->draw_box(item.place_x - 1, item.place_y - 1, item.width + 1, item.height + 1, COL_WHITE); tft->draw_box(item.place_x, item.place_y, item.width + 2, item.height + 2, COL_BLACK); tft->draw_rect(item.place_x, item.place_y, item.width + 1, item.height + 1, 1, COL_DARK_GREY); tft->draw_box(item.place_x, item.place_y, item.width, item.height, COL_GREY); } } } int Shell::handle_window_click(CLICK_EVENT event) { // Iterate BACKWARDS - last window is on top for (int i = windows.size() - 1; i >= 0; i--) { Window* window = windows[i]; // 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)) { for (auto it = window->window_decorations.begin(); it != window->window_decorations.end(); ++it) { int x = window->x + it->x_offset; int y = window->y + it->y_offset; if (event.x >= x && event.x <= (x + it->width) && event.y >= y && event.y <= (y + it->height) && it->action == WindowAction::CLOSE) { close_window(window->id); return window->id; } if (event.x >= x && event.x <= (x + it->width) && event.y >= y && event.y <= (y + it->height) && it->action == WindowAction::MINIMIZE) { minimize_window(window->id); return window->id; } } 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 -1; } 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)) { Serial.print("Desktop item clicked: "); Serial.println(item.id); WindowDecoration dec; Window* win = new Window(); WindowDecoration dec1 = { .x_offset = 6, .y_offset = 5, .width = 25, .height = 25, .action = WindowAction::CLOSE, }; WindowDecoration dec2 = { .x_offset = 36, .y_offset = 5, .width = 25, .height = 25, .action = WindowAction::MINIMIZE, }; win->window_decorations.push_back(dec1); win->window_decorations.push_back(dec2); win->id = 0; win->x = 10; win->y = 0; win->width = 350; win->height = 250; win->background_color = 0xbdf7; win->foreground_color = COL_DARK_BLUE; win->focused = true; win->minimized = false; win->title = "Hello World!"; _system_manager->spawn_program(win); create_window(win); // TODO: Handle icon click (open window, etc.) return item.id; } } return -1; } int Shell::handle_taskbar_click(CLICK_EVENT event) { return -1; } bool Shell::handle_start_button_click(CLICK_EVENT event) { if (event.x >= 6 && event.x <= (6 + 50) && event.y >= 298 && event.y <= (298 + 18)) { Serial.println("Taskbar button clicked"); // TODO: Handle icon click (open window, etc.) return true; } return false; }