diff --git a/client/src/game_state.cpp b/client/src/game_state.cpp index 7b59683..79b51fa 100644 --- a/client/src/game_state.cpp +++ b/client/src/game_state.cpp @@ -15,7 +15,7 @@ #include void GameState::_init_desktop(void) { - _desktop = std::make_unique(_screen_width, _screen_height); + _desktop = std::make_unique(_screen_width, _screen_height, _network.get()); auto term = std::make_unique(_network.get()); auto term_window = std::make_unique("Terminal", 100, 100, 800, 500); diff --git a/client/src/ui/desktop.cpp b/client/src/ui/desktop.cpp index 4472150..16f18d6 100644 --- a/client/src/ui/desktop.cpp +++ b/client/src/ui/desktop.cpp @@ -6,6 +6,7 @@ #include "desktop.h" #include +#include "client_network.h" #include "gfx/shape_renderer.h" #include "gfx/txt_renderer.h" #include "terminal.h" @@ -22,9 +23,12 @@ static const std::string& get_random_snippet(const std::vector& sni return snippets[rand() % snippets.size()]; } -Desktop::Desktop(int screen_width, int screen_height) { +Desktop::Desktop(int screen_width, int screen_height, ClientNetwork* network) { _taskbar = std::make_unique(screen_width, screen_height); + _network = network; _focused_window = nullptr; + _launcher_is_open = false; + _launcher = std::make_unique(5, 5 + _taskbar->get_height(), 200); /* Load snippets for temp wallpaper. */ std::ifstream snippet_file("assets/menu_background_snippets.txt"); @@ -50,11 +54,8 @@ Desktop::~Desktop(void) {} void Desktop::add_window(std::unique_ptr window) { _windows.push_back(std::move(window)); - /* I'm sick of reaching for my mouse to focus the terminal.. Stop that! */ - if(_windows.size() == 1) { - _focused_window = _windows.back().get(); - _focused_window->set_focused(true); - } + /* Focus new window. */ + _set_focused_window(_windows.back().get()); } void Desktop::_set_focused_window(UIWindow* window) { @@ -69,17 +70,6 @@ void Desktop::_set_focused_window(UIWindow* window) { _focused_window = window; if(_focused_window) { _focused_window->set_focused(true); - - /* Find window in vector and move it to the end. */ - auto it = std::find_if(_windows.begin(), _windows.end(), - [window](const std::unique_ptr& w) - { return w.get() == window; }); - - if(it != _windows.end()) { - auto window_to_move = std::move(*it); - _windows.erase(it); - _windows.push_back(std::move(window_to_move)); - } } } @@ -88,6 +78,12 @@ void Desktop::handle_event(SDL_Event* event, int screen_width, int screen_height 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)) { @@ -98,14 +94,27 @@ void Desktop::handle_event(SDL_Event* event, int screen_width, int screen_height } } } else if(event->type == SDL_EVENT_MOUSE_BUTTON_UP) { - 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); + 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(_network); + auto term_window = std::make_unique("Terminal", 150, 150, 800, 500); + term_window->set_content(std::move(term)); + add_window(std::move(term_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) { @@ -154,12 +163,20 @@ UIWindow* Desktop::get_focused_window(void) { 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->is_minimized()) { + 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) { diff --git a/client/src/ui/desktop.h b/client/src/ui/desktop.h index b3e5ec2..dc2b91b 100644 --- a/client/src/ui/desktop.h +++ b/client/src/ui/desktop.h @@ -4,13 +4,15 @@ #include #include +#include "client_network.h" #include "gfx/shape_renderer.h" #include "gfx/txt_renderer.h" #include "ui/ui_window.h" #include "ui/taskbar.h" +#include "ui/launcher.h" /* Animated background stuff. */ -struct ScollingText { +struct ScrollingText { std::string text; float x; float y; @@ -19,7 +21,7 @@ struct ScollingText { class Desktop { public: - Desktop(int screen_width, int screen_height); + Desktop(int screen_width, int screen_height, ClientNetwork* network); ~Desktop(void); void add_window(std::unique_ptr window); @@ -35,8 +37,11 @@ private: void _render_wallpaper(TextRenderer* txt_renderer); std::vector> _windows; - std::unique_ptr _taskbar; - UIWindow* _focused_window; - std::vector _background_text; - std::vector _snippets; + std::unique_ptr _taskbar; + std::unique_ptr _launcher; + UIWindow* _focused_window; + ClientNetwork* _network; + std::vector _background_text; + std::vector _snippets; + bool _launcher_is_open; }; diff --git a/client/src/ui/launcher.cpp b/client/src/ui/launcher.cpp new file mode 100644 index 0000000..4c2cc66 --- /dev/null +++ b/client/src/ui/launcher.cpp @@ -0,0 +1,66 @@ +#include "launcher.h" +#include +#include "gfx/shape_renderer.h" +#include "gfx/txt_renderer.h" +#include "gfx/types.h" + +Launcher::Launcher(int x, int y, int width) : _x(x), _y(y), _width(width) { + /* TODO: Hardcode the launcher apps for now. */ + _apps.push_back("Terminal"); + + int item_height = 30; + _height = _apps.size() * item_height; +} + +Launcher::~Launcher(void) {} + +bool Launcher::is_point_inside(int x, int y, int screen_height) const { + int ui_y = screen_height - y; /* convert mouse y to GL/UI coords. */ + return (x >= _x && x <= _x + _width && ui_y >= _y && ui_y <= _y + _height); +} + +void Launcher::render(ShapeRenderer* shape_renderer, TextRenderer* txt_renderer, + int screen_height) { + const Color bg_color = { 0.15f, 0.17f, 0.19f }; + const Color text_color = { 0.9f, 0.9f, 0.9f }; + const Color hover_color = { 0.3f, 0.32f, 0.34f }; + + /* Note: y-coord is TOP of launcher menu. */ + shape_renderer->draw_rect(_x, _y, _width, _height, bg_color); + + int item_height = 30; + int item_y = _y; + + float mouse_x, mouse_y; + SDL_GetMouseState(&mouse_x, &mouse_y); + int ui_mouse_y = screen_height - mouse_y; + + for(const auto& app_name : _apps) { + /* Check for hover. */ + if(mouse_x >= _x && mouse_x <= _x + _width && + ui_mouse_y >= item_y && ui_mouse_y <= item_y + item_height) { + shape_renderer->draw_rect(_x, item_y, _width, item_height, hover_color); + } + + txt_renderer->render_text(app_name.c_str(), _x + 10, item_y + 8, 1.0f, text_color); + item_y += item_height; + } +} + +std::string Launcher::handle_event(SDL_Event* event, int screen_height) { + if(event->type == SDL_EVENT_MOUSE_BUTTON_UP) { + int mouse_x = event->button.x; + int ui_mouse_y = screen_height - event->button.y; + + int item_height = 30; + int item_y = _y; + for(const auto& app_name : _apps) { + if(mouse_x >= _x && mouse_x <= _x + _width && + ui_mouse_y >= item_y && ui_mouse_y <= item_y + item_height) { + return app_name; /* Return name of clicked app. */ + } + item_y += item_height; + } + } + return ""; /* Nothing clicked. */ +} diff --git a/client/src/ui/launcher.h b/client/src/ui/launcher.h new file mode 100644 index 0000000..7eb0dcd --- /dev/null +++ b/client/src/ui/launcher.h @@ -0,0 +1,22 @@ +#pragma once + +#include +#include +#include + +class ShapeRenderer; +class TextRenderer; + +class Launcher { +public: + Launcher(int x, int y, int width); + ~Launcher(void); + + void render(ShapeRenderer* shape_renderer, TextRenderer* txt_renderer, int screen_height); + std::string handle_event(SDL_Event* event, int screen_height); + bool is_point_inside(int x, int y, int screen_height) const; + +private: + int _x, _y, _width, _height; + std::vector _apps; +}; diff --git a/client/src/ui/taskbar.cpp b/client/src/ui/taskbar.cpp index 724ca80..c834029 100644 --- a/client/src/ui/taskbar.cpp +++ b/client/src/ui/taskbar.cpp @@ -13,7 +13,8 @@ Taskbar::Taskbar(int screen_width, int screen_height) { _width = screen_width; _height = 32; - _y_pos = 0; /* Taksbar at bottom because boring? */ + _y_pos = 0; /* Taskbar at bottom because boring? */ + _start_button_width = 60; } Taskbar::~Taskbar(void) {} @@ -27,24 +28,30 @@ void Taskbar::render(ShapeRenderer* shape_renderer, TextRenderer* txt_renderer, const Color button_focused_color = { 0.3f, 0.32f, 0.34f }; const Color button_text_color = { 0.9f, 0.9f, 0.9f }; - shape_renderer->draw_rect(0, _y_pos, _width, _height, taskbar_color); + /* Draw start button. */ + shape_renderer->draw_rect(5, _y_pos + 5, _start_button_width - 10, + _height - 10, button_color); + txt_renderer->render_text("[B]", 20, _y_pos + 11, 1.0f, + button_text_color); + + /* Draw app buttons. */ int button_width = 150; int padding = 5; - int x_offset = padding; + int x_offset = _start_button_width + padding; for(const auto& window : windows) { bool is_focused = (window.get() == focused_window); - shape_renderer->draw_rect(x_offset, _y_pos + padding, button_width, + shape_renderer->draw_rect(x_offset, _y_pos + padding, button_width, _height - (padding * 2), is_focused ? button_focused_color : button_color); /* TODO: Truncate text when too long. */ - txt_renderer->render_text(window->get_title().c_str(), x_offset + 10, + txt_renderer->render_text(window->get_title().c_str(), x_offset + 10, _y_pos + 11, 1.0f, button_text_color); x_offset += button_width + padding; - + } /* Draw clock. */ auto now = std::chrono::system_clock::now(); auto in_time_t = std::chrono::system_clock::to_time_t(now); @@ -52,9 +59,8 @@ void Taskbar::render(ShapeRenderer* shape_renderer, TextRenderer* txt_renderer, ss << std::put_time(std::localtime(&in_time_t), "%H:%M"); std::string time_str = ss.str(); - txt_renderer->render_text(time_str.c_str(), _width-50, _y_pos+11, 1.0f, + txt_renderer->render_text(time_str.c_str(), _width-50, _y_pos+11, 1.0f, button_text_color); - } } UIWindow* Taskbar::handle_event(SDL_Event* event, int screen_height, @@ -63,21 +69,30 @@ UIWindow* Taskbar::handle_event(SDL_Event* event, int screen_height, int mouse_x = event->button.x; int mouse_y = screen_height - event->button.y; /* Convert to UI coords. */ - if(mouse_y >= _y_pos && mouse_y <= _y_pos + _height) { - int button_width = 150; - int padding = 5; - int x_offset = padding; - for(auto& window : windows) { - if(mouse_x >= x_offset && mouse_x <= x_offset + button_width) { - return window.get(); /* Return clicked window. */ - } - x_offset += button_width + padding; + int button_width = 150; + int padding = 5; + int x_offset = _start_button_width + padding; + for(const auto& window : windows) { + if(mouse_x >= x_offset && mouse_x <= x_offset + button_width && + mouse_y >= _y_pos && mouse_y <= _y_pos + _height) { + return window.get(); /* Return clicked window. */ } + x_offset += button_width + padding; } } return nullptr; /* No window button was clicked. */ } +bool Taskbar::is_start_button_clicked(SDL_Event* event, int screen_height) { + if(event->type == SDL_EVENT_MOUSE_BUTTON_UP) { + int mouse_x = event->button.x; + int mouse_y = screen_height - event->button.y; + return (mouse_x >= 0 && mouse_x <= _start_button_width && mouse_y >= _y_pos && + mouse_y <= _y_pos + _height); + } + return false; +} + int Taskbar::get_height(void) const { return _height; } diff --git a/client/src/ui/taskbar.h b/client/src/ui/taskbar.h index 297d444..ac3882d 100644 --- a/client/src/ui/taskbar.h +++ b/client/src/ui/taskbar.h @@ -18,11 +18,13 @@ public: UIWindow* focused_window); UIWindow* handle_event(SDL_Event* event, int screen_height, - const std::vector>& windows); + const std::vector>& windows); + bool is_start_button_clicked(SDL_Event* event, int screen_height); int get_height(void) const; private: int _width; int _height; int _y_pos; + int _start_button_width; };