#include "window.h" #include "GLOBALS.h" #include "window_manager.h" #include void WindowManager::init(TFT_Handler* th, DISPLAY_STATE* ds) { tft = th; display_state = ds; // Subscribe to events EventManager::getInstance().subscribe(this); } void WindowManager::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); display_state->update_display.store(true); } void WindowManager::close_window(int window_id) { for (auto it = windows.begin(); it != windows.end(); ++it) { if (it->id == window_id) { windows.erase(it); display_state->update_display.store(true); break; } } } void WindowManager::draw_all() { tft->start_draw(); for (const auto& win : windows) { draw_window(win); } tft->end_draw(); } void WindowManager::draw_window(Window window) { // 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); } void WindowManager::on_click_event(CLICK_EVENT event) { if (event.event != CLICK_EVENTS::LEFT_CLICK) return; int clicked_id = handle_window_click(event); if (clicked_id >= 0) display_state->update_display.store(true); } int WindowManager::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; Serial.printf("x: %i y: %i\n", x, y); 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 (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; }