[Add] Graphical application launcher.
This commit is contained in:
parent
996bf1c62c
commit
43907509eb
@ -15,7 +15,7 @@
|
|||||||
#include <ui/boot_sequence.h>
|
#include <ui/boot_sequence.h>
|
||||||
|
|
||||||
void GameState::_init_desktop(void) {
|
void GameState::_init_desktop(void) {
|
||||||
_desktop = std::make_unique<Desktop>(_screen_width, _screen_height);
|
_desktop = std::make_unique<Desktop>(_screen_width, _screen_height, _network.get());
|
||||||
|
|
||||||
auto term = std::make_unique<Terminal>(_network.get());
|
auto term = std::make_unique<Terminal>(_network.get());
|
||||||
auto term_window = std::make_unique<UIWindow>("Terminal", 100, 100, 800, 500);
|
auto term_window = std::make_unique<UIWindow>("Terminal", 100, 100, 800, 500);
|
||||||
|
|||||||
@ -6,6 +6,7 @@
|
|||||||
|
|
||||||
#include "desktop.h"
|
#include "desktop.h"
|
||||||
#include <SDL3/SDL_events.h>
|
#include <SDL3/SDL_events.h>
|
||||||
|
#include "client_network.h"
|
||||||
#include "gfx/shape_renderer.h"
|
#include "gfx/shape_renderer.h"
|
||||||
#include "gfx/txt_renderer.h"
|
#include "gfx/txt_renderer.h"
|
||||||
#include "terminal.h"
|
#include "terminal.h"
|
||||||
@ -22,9 +23,12 @@ static const std::string& get_random_snippet(const std::vector<std::string>& sni
|
|||||||
return snippets[rand() % snippets.size()];
|
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<Taskbar>(screen_width, screen_height);
|
_taskbar = std::make_unique<Taskbar>(screen_width, screen_height);
|
||||||
|
_network = network;
|
||||||
_focused_window = nullptr;
|
_focused_window = nullptr;
|
||||||
|
_launcher_is_open = false;
|
||||||
|
_launcher = std::make_unique<Launcher>(5, 5 + _taskbar->get_height(), 200);
|
||||||
|
|
||||||
/* Load snippets for temp wallpaper. */
|
/* Load snippets for temp wallpaper. */
|
||||||
std::ifstream snippet_file("assets/menu_background_snippets.txt");
|
std::ifstream snippet_file("assets/menu_background_snippets.txt");
|
||||||
@ -50,11 +54,8 @@ Desktop::~Desktop(void) {}
|
|||||||
|
|
||||||
void Desktop::add_window(std::unique_ptr<UIWindow> window) {
|
void Desktop::add_window(std::unique_ptr<UIWindow> window) {
|
||||||
_windows.push_back(std::move(window));
|
_windows.push_back(std::move(window));
|
||||||
/* I'm sick of reaching for my mouse to focus the terminal.. Stop that! */
|
/* Focus new window. */
|
||||||
if(_windows.size() == 1) {
|
_set_focused_window(_windows.back().get());
|
||||||
_focused_window = _windows.back().get();
|
|
||||||
_focused_window->set_focused(true);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Desktop::_set_focused_window(UIWindow* window) {
|
void Desktop::_set_focused_window(UIWindow* window) {
|
||||||
@ -69,17 +70,6 @@ void Desktop::_set_focused_window(UIWindow* window) {
|
|||||||
_focused_window = window;
|
_focused_window = window;
|
||||||
if(_focused_window) {
|
if(_focused_window) {
|
||||||
_focused_window->set_focused(true);
|
_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<UIWindow>& 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_x = event->button.x;
|
||||||
int mouse_y = event->button.y;
|
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. */
|
/* Find the top-most window that was clicked. */
|
||||||
for(int i = _windows.size()-1; i >= 0; --i) {
|
for(int i = _windows.size()-1; i >= 0; --i) {
|
||||||
if(_windows[i].get()->is_point_inside(mouse_x, mouse_y)) {
|
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) {
|
} else if(event->type == SDL_EVENT_MOUSE_BUTTON_UP) {
|
||||||
UIWindow* clicked_window = _taskbar->handle_event(event, screen_height, _windows);
|
if(_taskbar->is_start_button_clicked(event, screen_height)) {
|
||||||
if(clicked_window) {
|
_launcher_is_open = !_launcher_is_open;
|
||||||
if(clicked_window == _focused_window && !clicked_window->is_minimized()) {
|
} else if(_launcher_is_open) {
|
||||||
clicked_window->minimize();
|
std::string app_to_launch = _launcher->handle_event(event, screen_height);
|
||||||
_set_focused_window(nullptr);
|
if(app_to_launch == "Terminal") {
|
||||||
} else {
|
auto term = std::make_unique<Terminal>(_network);
|
||||||
clicked_window->restore();
|
auto term_window = std::make_unique<UIWindow>("Terminal", 150, 150, 800, 500);
|
||||||
_set_focused_window(clicked_window);
|
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) {
|
} 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,
|
void Desktop::render(ShapeRenderer* shape_renderer, TextRenderer* txt_renderer,
|
||||||
int screen_height, bool show_cursor) {
|
int screen_height, bool show_cursor) {
|
||||||
_render_wallpaper(txt_renderer);
|
_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);
|
_taskbar->render(shape_renderer, txt_renderer, _windows, _focused_window);
|
||||||
|
/* Render non-focused windows first. */
|
||||||
for(const auto& win : _windows) {
|
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);
|
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) {
|
void Desktop::_render_wallpaper(TextRenderer* txt_renderer) {
|
||||||
|
|||||||
@ -4,13 +4,15 @@
|
|||||||
#include <vector>
|
#include <vector>
|
||||||
#include <SDL3/SDL.h>
|
#include <SDL3/SDL.h>
|
||||||
|
|
||||||
|
#include "client_network.h"
|
||||||
#include "gfx/shape_renderer.h"
|
#include "gfx/shape_renderer.h"
|
||||||
#include "gfx/txt_renderer.h"
|
#include "gfx/txt_renderer.h"
|
||||||
#include "ui/ui_window.h"
|
#include "ui/ui_window.h"
|
||||||
#include "ui/taskbar.h"
|
#include "ui/taskbar.h"
|
||||||
|
#include "ui/launcher.h"
|
||||||
|
|
||||||
/* Animated background stuff. */
|
/* Animated background stuff. */
|
||||||
struct ScollingText {
|
struct ScrollingText {
|
||||||
std::string text;
|
std::string text;
|
||||||
float x;
|
float x;
|
||||||
float y;
|
float y;
|
||||||
@ -19,7 +21,7 @@ struct ScollingText {
|
|||||||
|
|
||||||
class Desktop {
|
class Desktop {
|
||||||
public:
|
public:
|
||||||
Desktop(int screen_width, int screen_height);
|
Desktop(int screen_width, int screen_height, ClientNetwork* network);
|
||||||
~Desktop(void);
|
~Desktop(void);
|
||||||
|
|
||||||
void add_window(std::unique_ptr<UIWindow> window);
|
void add_window(std::unique_ptr<UIWindow> window);
|
||||||
@ -35,8 +37,11 @@ private:
|
|||||||
void _render_wallpaper(TextRenderer* txt_renderer);
|
void _render_wallpaper(TextRenderer* txt_renderer);
|
||||||
|
|
||||||
std::vector<std::unique_ptr<UIWindow>> _windows;
|
std::vector<std::unique_ptr<UIWindow>> _windows;
|
||||||
std::unique_ptr<Taskbar> _taskbar;
|
std::unique_ptr<Taskbar> _taskbar;
|
||||||
UIWindow* _focused_window;
|
std::unique_ptr<Launcher> _launcher;
|
||||||
std::vector<ScollingText> _background_text;
|
UIWindow* _focused_window;
|
||||||
std::vector<std::string> _snippets;
|
ClientNetwork* _network;
|
||||||
|
std::vector<ScrollingText> _background_text;
|
||||||
|
std::vector<std::string> _snippets;
|
||||||
|
bool _launcher_is_open;
|
||||||
};
|
};
|
||||||
|
|||||||
66
client/src/ui/launcher.cpp
Normal file
66
client/src/ui/launcher.cpp
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
#include "launcher.h"
|
||||||
|
#include <SDL3/SDL_mouse.h>
|
||||||
|
#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. */
|
||||||
|
}
|
||||||
22
client/src/ui/launcher.h
Normal file
22
client/src/ui/launcher.h
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
#include <SDL3/SDL_events.h>
|
||||||
|
|
||||||
|
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<std::string> _apps;
|
||||||
|
};
|
||||||
@ -13,7 +13,8 @@
|
|||||||
Taskbar::Taskbar(int screen_width, int screen_height) {
|
Taskbar::Taskbar(int screen_width, int screen_height) {
|
||||||
_width = screen_width;
|
_width = screen_width;
|
||||||
_height = 32;
|
_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) {}
|
Taskbar::~Taskbar(void) {}
|
||||||
@ -27,12 +28,18 @@ void Taskbar::render(ShapeRenderer* shape_renderer, TextRenderer* txt_renderer,
|
|||||||
const Color button_focused_color = { 0.3f, 0.32f, 0.34f };
|
const Color button_focused_color = { 0.3f, 0.32f, 0.34f };
|
||||||
const Color button_text_color = { 0.9f, 0.9f, 0.9f };
|
const Color button_text_color = { 0.9f, 0.9f, 0.9f };
|
||||||
|
|
||||||
|
|
||||||
shape_renderer->draw_rect(0, _y_pos, _width, _height, taskbar_color);
|
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 button_width = 150;
|
||||||
int padding = 5;
|
int padding = 5;
|
||||||
int x_offset = padding;
|
int x_offset = _start_button_width + padding;
|
||||||
|
|
||||||
for(const auto& window : windows) {
|
for(const auto& window : windows) {
|
||||||
bool is_focused = (window.get() == focused_window);
|
bool is_focused = (window.get() == focused_window);
|
||||||
@ -44,7 +51,7 @@ void Taskbar::render(ShapeRenderer* shape_renderer, TextRenderer* txt_renderer,
|
|||||||
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);
|
_y_pos + 11, 1.0f, button_text_color);
|
||||||
x_offset += button_width + padding;
|
x_offset += button_width + padding;
|
||||||
|
}
|
||||||
/* Draw clock. */
|
/* Draw clock. */
|
||||||
auto now = std::chrono::system_clock::now();
|
auto now = std::chrono::system_clock::now();
|
||||||
auto in_time_t = std::chrono::system_clock::to_time_t(now);
|
auto in_time_t = std::chrono::system_clock::to_time_t(now);
|
||||||
@ -54,7 +61,6 @@ void Taskbar::render(ShapeRenderer* shape_renderer, TextRenderer* txt_renderer,
|
|||||||
|
|
||||||
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);
|
button_text_color);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
UIWindow* Taskbar::handle_event(SDL_Event* event, int screen_height,
|
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_x = event->button.x;
|
||||||
int mouse_y = screen_height - event->button.y; /* Convert to UI coords. */
|
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 button_width = 150;
|
int padding = 5;
|
||||||
int padding = 5;
|
int x_offset = _start_button_width + padding;
|
||||||
int x_offset = padding;
|
for(const auto& window : windows) {
|
||||||
for(auto& window : windows) {
|
if(mouse_x >= x_offset && mouse_x <= x_offset + button_width &&
|
||||||
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. */
|
return window.get(); /* Return clicked window. */
|
||||||
}
|
|
||||||
x_offset += button_width + padding;
|
|
||||||
}
|
}
|
||||||
|
x_offset += button_width + padding;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nullptr; /* No window button was clicked. */
|
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 {
|
int Taskbar::get_height(void) const {
|
||||||
return _height;
|
return _height;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -18,11 +18,13 @@ public:
|
|||||||
UIWindow* focused_window);
|
UIWindow* focused_window);
|
||||||
|
|
||||||
UIWindow* handle_event(SDL_Event* event, int screen_height,
|
UIWindow* handle_event(SDL_Event* event, int screen_height,
|
||||||
const std::vector<std::unique_ptr<UIWindow>>& windows);
|
const std::vector<std::unique_ptr<UIWindow>>& windows);
|
||||||
|
bool is_start_button_clicked(SDL_Event* event, int screen_height);
|
||||||
|
|
||||||
int get_height(void) const;
|
int get_height(void) const;
|
||||||
private:
|
private:
|
||||||
int _width;
|
int _width;
|
||||||
int _height;
|
int _height;
|
||||||
int _y_pos;
|
int _y_pos;
|
||||||
|
int _start_button_width;
|
||||||
};
|
};
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user