[Add] Graphical application launcher.
This commit is contained in:
parent
996bf1c62c
commit
43907509eb
@ -15,7 +15,7 @@
|
||||
#include <ui/boot_sequence.h>
|
||||
|
||||
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_window = std::make_unique<UIWindow>("Terminal", 100, 100, 800, 500);
|
||||
|
||||
@ -6,6 +6,7 @@
|
||||
|
||||
#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"
|
||||
@ -22,9 +23,12 @@ static const std::string& get_random_snippet(const std::vector<std::string>& 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<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");
|
||||
@ -50,11 +54,8 @@ Desktop::~Desktop(void) {}
|
||||
|
||||
void Desktop::add_window(std::unique_ptr<UIWindow> 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<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_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,6 +94,18 @@ void Desktop::handle_event(SDL_Event* event, int screen_width, int screen_height
|
||||
}
|
||||
}
|
||||
} 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 {
|
||||
UIWindow* clicked_window = _taskbar->handle_event(event, screen_height, _windows);
|
||||
if(clicked_window) {
|
||||
if(clicked_window == _focused_window && !clicked_window->is_minimized()) {
|
||||
@ -108,6 +116,7 @@ void Desktop::handle_event(SDL_Event* event, int screen_width, int screen_height
|
||||
_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. */
|
||||
@ -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) {
|
||||
|
||||
@ -4,13 +4,15 @@
|
||||
#include <vector>
|
||||
#include <SDL3/SDL.h>
|
||||
|
||||
#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<UIWindow> window);
|
||||
@ -36,7 +38,10 @@ private:
|
||||
|
||||
std::vector<std::unique_ptr<UIWindow>> _windows;
|
||||
std::unique_ptr<Taskbar> _taskbar;
|
||||
std::unique_ptr<Launcher> _launcher;
|
||||
UIWindow* _focused_window;
|
||||
std::vector<ScollingText> _background_text;
|
||||
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) {
|
||||
_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,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_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);
|
||||
@ -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,
|
||||
_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);
|
||||
@ -55,7 +62,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,
|
||||
button_text_color);
|
||||
}
|
||||
}
|
||||
|
||||
UIWindow* Taskbar::handle_event(SDL_Event* event, int screen_height,
|
||||
const std::vector<std::unique_ptr<UIWindow>>& windows) {
|
||||
@ -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) {
|
||||
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;
|
||||
}
|
||||
|
||||
@ -19,10 +19,12 @@ public:
|
||||
|
||||
UIWindow* handle_event(SDL_Event* event, int screen_height,
|
||||
const std::vector<std::unique_ptr<UIWindow>>& 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;
|
||||
};
|
||||
|
||||
Loading…
Reference in New Issue
Block a user