bettola/client/src/ui/desktop.cpp

216 lines
7.2 KiB
C++

#include <algorithm>
#include <ctime>
#include <fstream>
#include <cmath>
#include <memory>
#include "ui/editor.h"
#include "desktop.h"
#include <SDL3/SDL_events.h>
#include "client_network.h"
#include "gfx/shape_renderer.h"
#include "gfx/txt_renderer.h"
#include "terminal.h"
#include "ui/i_window_content.h"
#include "ui/taskbar.h"
#include <SDL3/SDL_video.h>
#include <ui/cursor_manager.h>
#include "ui/ui_window.h"
static const std::string& get_random_snippet(const std::vector<std::string>& snippets) {
if(snippets.empty()) {
static const std::string err = "ERR";
return err;
}
return snippets[rand() % snippets.size()];
}
Desktop::Desktop(int screen_width, int screen_height, ClientNetwork* network) {
_taskbar = std::make_unique<Taskbar>(screen_width, screen_height);
_network = network;
_focused_window = nullptr;
_launcher_is_open = false;
_launcher = std::make_unique<Launcher>(5, 5 + _taskbar->get_height(), 200);
/* Load snippets for temp wallpaper. */
std::ifstream snippet_file("assets/menu_background_snippets.txt");
if(snippet_file.is_open()) {
std::string line;
while(std::getline(snippet_file, line)) {
if(!line.empty()) { _snippets.push_back(line); }
}
}
/* Init animated background. */
for(int i = 0; i < 100; ++i) {
float y_pos = (float)(rand() % screen_height);
_background_text.push_back(
{get_random_snippet(_snippets), (float)(rand() % screen_width),
y_pos,
(float)(rand() % 30 + 10) / 100.0f,
(int)y_pos
});
}
}
/* Desktop owns UIWindow, make sure we delete them. */
Desktop::~Desktop(void) {}
void Desktop::add_window(std::unique_ptr<UIWindow> window) {
_windows.push_back(std::move(window));
/* Focus new window. */
_set_focused_window(_windows.back().get());
}
void Desktop::_set_focused_window(UIWindow* window) {
if(window == _focused_window) {
return;
}
if(_focused_window) {
_focused_window->set_focused(false);
}
_focused_window = window;
if(_focused_window) {
_focused_window->set_focused(true);
}
}
void Desktop::handle_event(SDL_Event* event, int screen_width, int screen_height) {
if(event->type == SDL_EVENT_MOUSE_BUTTON_DOWN) {
int mouse_x = event->button.x;
int mouse_y = event->button.y;
/* When launcher open, check for outside click to close it. */
if(_launcher_is_open && !_launcher->is_point_inside(mouse_x, mouse_y, screen_height)) {
_launcher_is_open = false;
return;
}
/* Find the top-most window that was clicked. */
for(int i = _windows.size()-1; i >= 0; --i) {
if(_windows[i].get()->is_point_inside(mouse_x, mouse_y)) {
if(!_windows[i]->is_minimized()) {
_set_focused_window(_windows[i].get());
}
break;
}
}
} else if(event->type == SDL_EVENT_MOUSE_BUTTON_UP) {
if(_taskbar->is_start_button_clicked(event, screen_height)) {
_launcher_is_open = !_launcher_is_open;
} else if(_launcher_is_open) {
std::string app_to_launch = _launcher->handle_event(event, screen_height);
if(app_to_launch == "Terminal") {
auto term = std::make_unique<Terminal>(_network);
auto term_window = std::make_unique<UIWindow>("Terminal", 150, 150, 800, 500);
term_window->set_content(std::move(term));
add_window(std::move(term_window));
_launcher_is_open = false;
} else if(app_to_launch == "Editor") {
auto editor = std::make_unique<Editor>();
auto editor_window = std::make_unique<UIWindow>("Editor", 200, 200, 600, 400);
editor_window->set_content(std::move(editor));
add_window(std::move(editor_window));
_launcher_is_open = false;
}
} else {
UIWindow* clicked_window = _taskbar->handle_event(event, screen_height, _windows);
if(clicked_window) {
if(clicked_window == _focused_window && !clicked_window->is_minimized()) {
clicked_window->minimize();
_set_focused_window(nullptr);
} else {
clicked_window->restore();
_set_focused_window(clicked_window);
}
}
}
} else if(event->type == SDL_EVENT_MOUSE_MOTION) {
bool on_resize_handle = false;
/* Iterate backwards since top-most windows are at the end. */
for(int i = _windows.size() - 1; i >= 0; --i) {
if(_windows[i]->is_mouse_over_resize_handle(event->motion.x,
event->motion.y)) {
on_resize_handle = true;
break;
}
}
CursorManager::set_cursor(on_resize_handle ? CursorType::RESIZE_NWSE
: CursorType::ARROW);
}
if(_focused_window) {
_focused_window->handle_event(event, screen_width, screen_height,
_taskbar->get_height());
IWindowContent* content = _focused_window->get_content();
if(content) {
/*
* Only terminal should receive direct text input this way.
* Editor gets it through the generic handle_event call.
*/
content->handle_input(event);
}
}
}
void Desktop::update(int screen_width, int screen_height) {
/* Remove closed windows. */
_update_wallpaper(screen_width, screen_height);
_windows.erase(std::remove_if(_windows.begin(), _windows.end(),
[this](const std::unique_ptr<UIWindow>& w) {
if (w->should_close()) {
if (w.get() == _focused_window) {
_focused_window = nullptr;
}
return true;
}
return false;
}),
_windows.end());
}
UIWindow* Desktop::get_focused_window(void) {
return _focused_window;
}
void Desktop::render(ShapeRenderer* shape_renderer, TextRenderer* txt_renderer,
int screen_height, bool show_cursor) {
_render_wallpaper(txt_renderer);
if(_launcher_is_open) {
_launcher->render(shape_renderer, txt_renderer, screen_height);
}
_taskbar->render(shape_renderer, txt_renderer, _windows, _focused_window);
/* Render non-focused windows first. */
for(const auto& win : _windows) {
if(win.get() != _focused_window && !win->is_minimized()) {
win.get()->render(shape_renderer, txt_renderer, screen_height, show_cursor);
}
}
/* Render focused window last so it's on top. */
if(_focused_window && !_focused_window->is_minimized()) {
_focused_window->render(shape_renderer, txt_renderer, screen_height, show_cursor);
}
}
void Desktop::_render_wallpaper(TextRenderer* txt_renderer) {
const Color wallpaper_color = { 0.0f, 0.15f, 0.08f };
for(auto& line : _background_text) {
txt_renderer->render_text(line.text.c_str(), std::round(line.x),
line.render_y, 1.0f, wallpaper_color);
}
}
void Desktop::_update_wallpaper(int screen_width, int screen_height) {
for(auto& line : _background_text) {
line.y_precise -= line.speed;
line.render_y = static_cast<int>(std::round(line.y_precise));
if(line.render_y < 0) {
line.y_precise = screen_height;
line.x = (float)(rand() % screen_width);
line.text = get_random_snippet(_snippets);
}
}
}