Menu bar for for text editor etc.
This commit is contained in:
parent
30ae57d0ba
commit
a6e159f0da
@ -4,6 +4,7 @@
|
|||||||
#include <thread>
|
#include <thread>
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
|
|
||||||
|
#include "gfx/types.h"
|
||||||
#include "network_manager.h"
|
#include "network_manager.h"
|
||||||
#include "game_state.h"
|
#include "game_state.h"
|
||||||
#include "gfx/shape_renderer.h"
|
#include "gfx/shape_renderer.h"
|
||||||
@ -135,7 +136,7 @@ void GameState::update(void) {
|
|||||||
if(separator_pos != std::string::npos) {
|
if(separator_pos != std::string::npos) {
|
||||||
std::string filepath = payload.substr(0, separator_pos);
|
std::string filepath = payload.substr(0, separator_pos);
|
||||||
std::string content = payload.substr(separator_pos+2);
|
std::string content = payload.substr(separator_pos+2);
|
||||||
auto editor = std::make_unique<Editor>();
|
auto editor = std::make_unique<Editor>(filepath);
|
||||||
editor->set_buffer_content(content);
|
editor->set_buffer_content(content);
|
||||||
auto editor_window = std::make_unique<UIWindow>(filepath.c_str(),
|
auto editor_window = std::make_unique<UIWindow>(filepath.c_str(),
|
||||||
200, 200, 600, 400);
|
200, 200, 600, 400);
|
||||||
@ -192,22 +193,21 @@ void GameState::update(void) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void GameState::render(ShapeRenderer* shape_renderer, TextRenderer* txt_renderer,
|
void GameState::render(const RenderContext& context) {
|
||||||
int screen_height, bool show_cursor) {
|
|
||||||
switch(_current_screen) {
|
switch(_current_screen) {
|
||||||
case Screen::MAIN_MENU:
|
case Screen::MAIN_MENU:
|
||||||
if(_main_menu) {
|
if(_main_menu) {
|
||||||
_main_menu->render(shape_renderer, txt_renderer);
|
_main_menu->render(context.shape_renderer, context.txt_renderer);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case Screen::BOOTING:
|
case Screen::BOOTING:
|
||||||
if(_boot_sequence) {
|
if(_boot_sequence) {
|
||||||
_boot_sequence->render(txt_renderer, screen_height);
|
_boot_sequence->render(context.txt_renderer, context.screen_height);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case Screen::DESKTOP:
|
case Screen::DESKTOP:
|
||||||
if(_desktop) {
|
if(_desktop) {
|
||||||
_desktop->render(shape_renderer, txt_renderer, screen_height, show_cursor);
|
_desktop->render(context);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,6 +2,8 @@
|
|||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
|
#include "gfx/types.h"
|
||||||
|
|
||||||
class ClientNetwork;
|
class ClientNetwork;
|
||||||
class Desktop;
|
class Desktop;
|
||||||
class BootSequence;
|
class BootSequence;
|
||||||
@ -25,8 +27,7 @@ public:
|
|||||||
void start_single_player_now(int screen_width, int screen_height);
|
void start_single_player_now(int screen_width, int screen_height);
|
||||||
void handle_event(SDL_Event* event, int screen_width, int screen_height);
|
void handle_event(SDL_Event* event, int screen_width, int screen_height);
|
||||||
void update(void);
|
void update(void);
|
||||||
void render(ShapeRenderer* shape_renderer, TextRenderer* txt_renderer,
|
void render(const RenderContext& context);
|
||||||
int screen_height, bool show_cursor);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::unique_ptr<ClientNetwork> _network;
|
std::unique_ptr<ClientNetwork> _network;
|
||||||
|
|||||||
@ -1,5 +1,8 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
class ShapeRenderer;
|
||||||
|
class TextRenderer;
|
||||||
|
|
||||||
struct Color {
|
struct Color {
|
||||||
float r, g, b;
|
float r, g, b;
|
||||||
};
|
};
|
||||||
@ -7,3 +10,10 @@ struct Color {
|
|||||||
struct Rect {
|
struct Rect {
|
||||||
int x, y, w, h;
|
int x, y, w, h;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct RenderContext {
|
||||||
|
ShapeRenderer* shape_renderer;
|
||||||
|
TextRenderer* txt_renderer;
|
||||||
|
int screen_height;
|
||||||
|
bool show_cursor;
|
||||||
|
};
|
||||||
|
|||||||
@ -8,6 +8,7 @@
|
|||||||
#include "gfx/shape_renderer.h"
|
#include "gfx/shape_renderer.h"
|
||||||
#include "gfx/txt_renderer.h"
|
#include "gfx/txt_renderer.h"
|
||||||
#include "game_state.h"
|
#include "game_state.h"
|
||||||
|
#include "gfx/types.h"
|
||||||
#include "ui/cursor_manager.h"
|
#include "ui/cursor_manager.h"
|
||||||
|
|
||||||
const int SCREEN_WIDTH = 1280;
|
const int SCREEN_WIDTH = 1280;
|
||||||
@ -109,7 +110,13 @@ int main(int argc, char** argv) {
|
|||||||
glClearColor(0.04f, 0.05f, 0.06, 1.0f);
|
glClearColor(0.04f, 0.05f, 0.06, 1.0f);
|
||||||
glClear(GL_COLOR_BUFFER_BIT);
|
glClear(GL_COLOR_BUFFER_BIT);
|
||||||
|
|
||||||
game_state->render(shape_renderer_instance, txt_render_instance, SCREEN_HEIGHT, show_cursor);
|
RenderContext context = {
|
||||||
|
shape_renderer_instance,
|
||||||
|
txt_render_instance,
|
||||||
|
SCREEN_HEIGHT,
|
||||||
|
show_cursor
|
||||||
|
};
|
||||||
|
game_state->render(context);
|
||||||
|
|
||||||
/* It's really odd to call it SwapWindow now, rather than SwapBuffer. */
|
/* It's really odd to call it SwapWindow now, rather than SwapBuffer. */
|
||||||
SDL_GL_SwapWindow(window);
|
SDL_GL_SwapWindow(window);
|
||||||
|
|||||||
@ -88,7 +88,7 @@ void Terminal::_on_ret_press(void) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Terminal::handle_input(SDL_Event* event) {
|
void Terminal::handle_input(SDL_Event* event, int window_x, int window_y, int window_gl_y) {
|
||||||
/* Pass input to TextView; if true, RET was pressed. */
|
/* Pass input to TextView; if true, RET was pressed. */
|
||||||
if(_input_view->handle_event(event)) { _on_ret_press(); }
|
if(_input_view->handle_event(event)) { _on_ret_press(); }
|
||||||
}
|
}
|
||||||
@ -111,8 +111,7 @@ void Terminal::scroll(int amount, int win_content_height) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Terminal::render(TextRenderer* renderer, int x, int y, int width, int height,
|
void Terminal::render(const RenderContext& context, int x, int y, int width, int height) {
|
||||||
bool show_cursor) {
|
|
||||||
|
|
||||||
const Color white = { 1.0f, 1.0f, 1.0f };
|
const Color white = { 1.0f, 1.0f, 1.0f };
|
||||||
const Color green = { 0.2f, 1.0f, 0.2f };
|
const Color green = { 0.2f, 1.0f, 0.2f };
|
||||||
@ -126,7 +125,7 @@ void Terminal::render(TextRenderer* renderer, int x, int y, int width, int heigh
|
|||||||
/* Draw History. */
|
/* Draw History. */
|
||||||
for(size_t i = _scroll_offset; i < _history.size(); ++i) {
|
for(size_t i = _scroll_offset; i < _history.size(); ++i) {
|
||||||
float y_pos = (y+height) - padding - line_height - ((i - _scroll_offset) * line_height);
|
float y_pos = (y+height) - padding - line_height - ((i - _scroll_offset) * line_height);
|
||||||
renderer->render_text(_history[i].c_str(), x+padding, y_pos, 1.0f, white);
|
context.txt_renderer->render_text(_history[i].c_str(), x+padding, y_pos, 1.0f, white);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Draw current input line. */
|
/* Draw current input line. */
|
||||||
@ -135,12 +134,13 @@ void Terminal::render(TextRenderer* renderer, int x, int y, int width, int heigh
|
|||||||
|
|
||||||
/* Render prompt string. */
|
/* Render prompt string. */
|
||||||
std::string prompt_str = _prompt + "> ";
|
std::string prompt_str = _prompt + "> ";
|
||||||
renderer->render_text(prompt_str.c_str(), x + padding, prompt_y_pos, 1.0f, green);
|
context.txt_renderer->render_text(prompt_str.c_str(), x+padding, prompt_y_pos, 1.0f, green);
|
||||||
|
|
||||||
/* Render text view for the input right after prompt. */
|
/* Render text view for the input right after prompt. */
|
||||||
float input_x_pos = x + padding + (prompt_str.length() * 8.5f); /* Estimate width */
|
float input_x_pos = x + padding + (prompt_str.length() * 8.5f); /* Estimate width */
|
||||||
float input_width = width - (input_x_pos-x);
|
float input_width = width - (input_x_pos-x);
|
||||||
_input_view->render(renderer, input_x_pos, prompt_y_pos, input_width, line_height, show_cursor);
|
_input_view->render(context.txt_renderer, input_x_pos, prompt_y_pos, input_width,
|
||||||
|
line_height, context.show_cursor);
|
||||||
/* Disable scissor test. */
|
/* Disable scissor test. */
|
||||||
glDisable(GL_SCISSOR_TEST);
|
glDisable(GL_SCISSOR_TEST);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -4,8 +4,8 @@
|
|||||||
#include <memory>
|
#include <memory>
|
||||||
#include <SDL3/SDL.h>
|
#include <SDL3/SDL.h>
|
||||||
|
|
||||||
#include "gfx/txt_renderer.h"
|
|
||||||
#include "client_network.h"
|
#include "client_network.h"
|
||||||
|
#include "gfx/types.h"
|
||||||
#include "ui/text_buffer.h"
|
#include "ui/text_buffer.h"
|
||||||
#include "ui/text_view.h"
|
#include "ui/text_view.h"
|
||||||
#include "ui/i_window_content.h"
|
#include "ui/i_window_content.h"
|
||||||
@ -17,8 +17,8 @@ public:
|
|||||||
~Terminal(void);
|
~Terminal(void);
|
||||||
|
|
||||||
void update(void) override;
|
void update(void) override;
|
||||||
void handle_input(SDL_Event* event) override;
|
void handle_input(SDL_Event* event, int window_x, int window_y, int window_gl_y) override;
|
||||||
void render(TextRenderer* renderer, int x, int y, int width, int height, bool show_cursor) override;
|
void render(const RenderContext& context, int x, int y, int width, int height) override;
|
||||||
void scroll(int amount, int content_height) override;
|
void scroll(int amount, int content_height) override;
|
||||||
void add_history(const std::string& line);
|
void add_history(const std::string& line);
|
||||||
void set_prompt(const std::string& prompt);
|
void set_prompt(const std::string& prompt);
|
||||||
|
|||||||
@ -5,6 +5,7 @@
|
|||||||
#include <functional>
|
#include <functional>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
|
#include "gfx/types.h"
|
||||||
#include "ui/editor.h"
|
#include "ui/editor.h"
|
||||||
#include "desktop.h"
|
#include "desktop.h"
|
||||||
#include <SDL3/SDL_events.h>
|
#include <SDL3/SDL_events.h>
|
||||||
@ -146,14 +147,6 @@ void Desktop::handle_event(SDL_Event* event, int screen_width, int screen_height
|
|||||||
if(_focused_window) {
|
if(_focused_window) {
|
||||||
_focused_window->handle_event(event, screen_width, screen_height,
|
_focused_window->handle_event(event, screen_width, screen_height,
|
||||||
_taskbar->get_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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -202,22 +195,21 @@ UIWindow* Desktop::get_focused_window(void) {
|
|||||||
return _focused_window;
|
return _focused_window;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Desktop::render(ShapeRenderer* shape_renderer, TextRenderer* txt_renderer,
|
void Desktop::render(const RenderContext& context) {
|
||||||
int screen_height, bool show_cursor) {
|
_render_wallpaper(context.txt_renderer);
|
||||||
_render_wallpaper(txt_renderer);
|
|
||||||
if(_launcher_is_open) {
|
if(_launcher_is_open) {
|
||||||
_launcher->render(shape_renderer, txt_renderer, screen_height);
|
_launcher->render(context.shape_renderer, context.txt_renderer, context.screen_height);
|
||||||
}
|
}
|
||||||
_taskbar->render(shape_renderer, txt_renderer, _windows, _focused_window);
|
_taskbar->render(context.shape_renderer, context.txt_renderer, _windows, _focused_window);
|
||||||
/* Render non-focused windows first. */
|
/* Render non-focused windows first. */
|
||||||
for(const auto& win : _windows) {
|
for(const auto& win : _windows) {
|
||||||
if(win.get() != _focused_window && !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(context);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* Render focused window last so it's on top. */
|
/* Render focused window last so it's on top. */
|
||||||
if(_focused_window && !_focused_window->is_minimized()) {
|
if(_focused_window && !_focused_window->is_minimized()) {
|
||||||
_focused_window->render(shape_renderer, txt_renderer, screen_height, show_cursor);
|
_focused_window->render(context);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -5,8 +5,8 @@
|
|||||||
#include <SDL3/SDL.h>
|
#include <SDL3/SDL.h>
|
||||||
|
|
||||||
#include "client_network.h"
|
#include "client_network.h"
|
||||||
#include "gfx/shape_renderer.h"
|
|
||||||
#include "gfx/txt_renderer.h"
|
#include "gfx/txt_renderer.h"
|
||||||
|
#include "gfx/types.h"
|
||||||
#include "ui/ui_window.h"
|
#include "ui/ui_window.h"
|
||||||
#include "ui/taskbar.h"
|
#include "ui/taskbar.h"
|
||||||
#include "ui/launcher.h"
|
#include "ui/launcher.h"
|
||||||
@ -28,8 +28,7 @@ public:
|
|||||||
void add_window(std::unique_ptr<UIWindow> window);
|
void add_window(std::unique_ptr<UIWindow> window);
|
||||||
void handle_event(SDL_Event* event, int screen_width, int screen_height);
|
void handle_event(SDL_Event* event, int screen_width, int screen_height);
|
||||||
void update(int screen_width, int screen_height);
|
void update(int screen_width, int screen_height);
|
||||||
void render(ShapeRenderer* shape_renderer, TextRenderer* txt_renderer, int screen_height,
|
void render(const RenderContext& context);
|
||||||
bool show_cursor);
|
|
||||||
|
|
||||||
UIWindow* get_focused_window(void);
|
UIWindow* get_focused_window(void);
|
||||||
|
|
||||||
|
|||||||
@ -1,11 +1,28 @@
|
|||||||
#include "editor.h"
|
#include "editor.h"
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include "gfx/txt_renderer.h"
|
#include "gfx/types.h"
|
||||||
#include "ui/window_action.h"
|
#include "ui/window_action.h"
|
||||||
|
|
||||||
Editor::Editor(void)
|
Editor::Editor(void)
|
||||||
: _should_close(false), _pending_action({ActionType::NONE}) {
|
: _should_close(false), _pending_action({ActionType::NONE}),
|
||||||
|
_filename("untitled.txt") {
|
||||||
_view = std::make_unique<TextView>(&_buffer, true);
|
_view = std::make_unique<TextView>(&_buffer, true);
|
||||||
|
_menu_bar = std::make_unique<MenuBar>(25);
|
||||||
|
_menu_bar->add_menu("File");
|
||||||
|
_menu_bar->add_menu_item("File", "Save", [this]() {
|
||||||
|
_pending_action = {ActionType::WRITE_FILE, _filename, _buffer.get_text()};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
Editor::Editor(const std::string& filename)
|
||||||
|
: _should_close(false), _pending_action({ActionType::NONE}),
|
||||||
|
_filename(filename) {
|
||||||
|
_view = std::make_unique<TextView>(&_buffer, true);
|
||||||
|
_menu_bar = std::make_unique<MenuBar>(25);
|
||||||
|
_menu_bar->add_menu("File");
|
||||||
|
_menu_bar->add_menu_item("File", "Save", [this]() {
|
||||||
|
_pending_action = {ActionType::WRITE_FILE, _filename, _buffer.get_text()};
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
Editor::~Editor(void) {}
|
Editor::~Editor(void) {}
|
||||||
@ -14,20 +31,28 @@ void Editor::update(void) {
|
|||||||
/* Nothing to do yet. */
|
/* Nothing to do yet. */
|
||||||
}
|
}
|
||||||
|
|
||||||
void Editor::handle_input(SDL_Event* event) {
|
void Editor::handle_input(SDL_Event* event, int window_x, int window_y, int window_gl_y) {
|
||||||
|
if(!event) return;
|
||||||
|
|
||||||
|
_menu_bar->handle_event(event, window_x, window_y, window_gl_y);
|
||||||
|
|
||||||
/* We don't care about the return val here. RET is just newline. */
|
/* We don't care about the return val here. RET is just newline. */
|
||||||
if(event->type == SDL_EVENT_KEY_DOWN && event->key.key == SDLK_S &&
|
if(event->type == SDL_EVENT_KEY_DOWN && event->key.key == SDLK_S &&
|
||||||
(event->key.mod & SDL_KMOD_CTRL)) {
|
(event->key.mod & SDL_KMOD_CTRL)) {
|
||||||
/* C-S pressed, create a save action. */
|
/* C-S pressed, create a save action. */
|
||||||
_pending_action = { ActionType::WRITE_FILE, "test.txt", _buffer.get_text() };
|
_pending_action = { ActionType::WRITE_FILE, _filename, _buffer.get_text() };
|
||||||
} else {
|
} else {
|
||||||
_view->handle_event(event);
|
_view->handle_event(event);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Editor::render(TextRenderer* renderer, int x, int y, int width, int height,
|
void Editor::render(const RenderContext& context, int x, int y, int width, int height) {
|
||||||
bool show_cursor) {
|
int menu_bar_height = _menu_bar->get_height();
|
||||||
_view->render(renderer, x, y, width, height, show_cursor);
|
int menu_bar_y_gl = y + height - menu_bar_height;
|
||||||
|
_menu_bar->render(context.shape_renderer, context.txt_renderer, x, menu_bar_y_gl, width);
|
||||||
|
|
||||||
|
_view->render(context.txt_renderer, x, y, width, height - menu_bar_height,
|
||||||
|
context.show_cursor);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Editor::scroll(int amount, int content_height) {
|
void Editor::scroll(int amount, int content_height) {
|
||||||
@ -47,3 +72,7 @@ WindowAction Editor::get_pending_action(void) {
|
|||||||
_pending_action.type = ActionType::NONE; /* Clear action. */
|
_pending_action.type = ActionType::NONE; /* Clear action. */
|
||||||
return action;
|
return action;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const std::string& Editor::get_filename(void) const {
|
||||||
|
return _filename;
|
||||||
|
}
|
||||||
|
|||||||
@ -2,29 +2,33 @@
|
|||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
#include "gfx/txt_renderer.h"
|
#include "gfx/types.h"
|
||||||
#include "i_window_content.h"
|
#include "i_window_content.h"
|
||||||
#include "ui/text_buffer.h"
|
#include "ui/text_buffer.h"
|
||||||
#include "text_view.h"
|
#include "text_view.h"
|
||||||
#include "ui/window_action.h"
|
#include "ui/window_action.h"
|
||||||
|
#include "ui/menu_bar.h"
|
||||||
|
|
||||||
class Editor : public IWindowContent {
|
class Editor : public IWindowContent {
|
||||||
public:
|
public:
|
||||||
Editor(void);
|
Editor(void);
|
||||||
|
Editor(const std::string& filename);
|
||||||
~Editor(void) override;
|
~Editor(void) override;
|
||||||
|
|
||||||
void update(void) override;
|
void update(void) override;
|
||||||
void handle_input(SDL_Event* event) override;
|
void handle_input(SDL_Event* event, int window_x, int window_y, int window_gl_y) override;
|
||||||
void render(TextRenderer* renderer, int x, int y, int width, int height,
|
void render(const RenderContext& context, int x, int y, int width, int height) override;
|
||||||
bool show_cursor) override;
|
|
||||||
void scroll(int amount, int content_height) override;
|
void scroll(int amount, int content_height) override;
|
||||||
bool should_close(void) override;
|
bool should_close(void) override;
|
||||||
void set_buffer_content(const std::string& content);
|
void set_buffer_content(const std::string& content);
|
||||||
WindowAction get_pending_action(void) override;
|
WindowAction get_pending_action(void) override;
|
||||||
|
const std::string& get_filename(void) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
TextBuffer _buffer;
|
TextBuffer _buffer;
|
||||||
std::unique_ptr<TextView> _view;
|
std::unique_ptr<TextView> _view;
|
||||||
|
std::unique_ptr<MenuBar> _menu_bar;
|
||||||
bool _should_close;
|
bool _should_close;
|
||||||
WindowAction _pending_action;
|
WindowAction _pending_action;
|
||||||
|
std::string _filename;
|
||||||
};
|
};
|
||||||
|
|||||||
@ -3,16 +3,14 @@
|
|||||||
#include <SDL3/SDL_events.h>
|
#include <SDL3/SDL_events.h>
|
||||||
|
|
||||||
#include "window_action.h"
|
#include "window_action.h"
|
||||||
|
#include "gfx/types.h"
|
||||||
class TextRenderer;
|
|
||||||
|
|
||||||
class IWindowContent {
|
class IWindowContent {
|
||||||
public:
|
public:
|
||||||
virtual ~IWindowContent(void) = default;
|
virtual ~IWindowContent(void) = default;
|
||||||
virtual void update(void) = 0;
|
virtual void update(void) = 0;
|
||||||
virtual void handle_input(SDL_Event* event) = 0;
|
virtual void handle_input(SDL_Event* event, int window_x, int window_y, int window_gl_y) = 0;
|
||||||
virtual void render(TextRenderer* renderer, int x, int y, int width, int height,
|
virtual void render(const RenderContext& context, int x, int y, int width, int height) = 0;
|
||||||
bool show_cursor = 0) = 0;
|
|
||||||
virtual void scroll(int amount, int content_height) = 0;
|
virtual void scroll(int amount, int content_height) = 0;
|
||||||
virtual bool should_close(void) = 0;
|
virtual bool should_close(void) = 0;
|
||||||
virtual WindowAction get_pending_action() = 0;
|
virtual WindowAction get_pending_action() = 0;
|
||||||
|
|||||||
95
client/src/ui/menu_bar.cpp
Normal file
95
client/src/ui/menu_bar.cpp
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
#include "menu_bar.h"
|
||||||
|
#include "gfx/shape_renderer.h"
|
||||||
|
#include "gfx/txt_renderer.h"
|
||||||
|
#include "gfx/types.h"
|
||||||
|
|
||||||
|
MenuBar::MenuBar(int height)
|
||||||
|
: _height(height) {}
|
||||||
|
|
||||||
|
MenuBar::~MenuBar(void) {}
|
||||||
|
|
||||||
|
void MenuBar::add_menu(const std::string& label) {
|
||||||
|
_menus.push_back({label, {}, false});
|
||||||
|
}
|
||||||
|
|
||||||
|
void MenuBar::add_menu_item(const std::string& menu_label, const std::string& item_label,
|
||||||
|
std::function<void()> action) {
|
||||||
|
for(auto& menu : _menus) {
|
||||||
|
if(menu.label == menu_label) {
|
||||||
|
menu.items.push_back({item_label, action});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int MenuBar::get_height(void) const {
|
||||||
|
return _height;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MenuBar::handle_event(SDL_Event* event, int window_x, int window_y, int window_gl_y) {
|
||||||
|
if(event->type == SDL_EVENT_MOUSE_BUTTON_DOWN) {
|
||||||
|
int mouse_x = event->button.x;
|
||||||
|
int mouse_y = event->button.y;
|
||||||
|
|
||||||
|
int menu_x = window_x;
|
||||||
|
for(size_t i = 0; i < _menus.size(); ++i) {
|
||||||
|
int menu_width = 60; /* Just hardcode this for now. */
|
||||||
|
if(mouse_x >= menu_x && mouse_x <= menu_x + menu_width &&
|
||||||
|
mouse_y >= window_y && mouse_y <= window_y + _height) {
|
||||||
|
|
||||||
|
if(_open_menu_index == (int)i) {
|
||||||
|
_open_menu_index = -1; /* Close if open already. */
|
||||||
|
} else {
|
||||||
|
_open_menu_index = i;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
menu_x += menu_width;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(_open_menu_index != -1) {
|
||||||
|
Menu& open_menu = _menus[_open_menu_index];
|
||||||
|
int item_y = window_gl_y + _height;
|
||||||
|
int item_height = 30;
|
||||||
|
int dropdown_width = 150;
|
||||||
|
for(const auto& item: open_menu.items) {
|
||||||
|
if(mouse_x >= window_x && mouse_x <= window_x + dropdown_width &&
|
||||||
|
(window_gl_y - mouse_y) >= item_y && (window_gl_y - mouse_y) <= item_y + item_height) {
|
||||||
|
item.action();
|
||||||
|
_open_menu_index = -1; /* Close menu. */
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
item_y += item_height;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* Close any open menu when clicked outside. */
|
||||||
|
_open_menu_index = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MenuBar::render(ShapeRenderer* shape_renderer, TextRenderer* txt_renderer,
|
||||||
|
int x, int y_gl, int width) {
|
||||||
|
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};
|
||||||
|
|
||||||
|
shape_renderer->draw_rect(x, y_gl, width, _height, bg_color);
|
||||||
|
|
||||||
|
int menu_x = x;
|
||||||
|
for(size_t i = 0; i < _menus.size(); ++i) {
|
||||||
|
int menu_width = 60;
|
||||||
|
txt_renderer->render_text(_menus[i].label.c_str(), menu_x+10, y_gl+8, 1.0f, text_color);
|
||||||
|
|
||||||
|
if(_open_menu_index == (int)i) {
|
||||||
|
int item_gl_y = y_gl - 30; /* Draw items below the bar. */
|
||||||
|
int item_height = 30;
|
||||||
|
int dropdown_width = 150;
|
||||||
|
for(const auto& item : _menus[i].items) {
|
||||||
|
shape_renderer->draw_rect(menu_x, item_gl_y, dropdown_width, item_height, bg_color);
|
||||||
|
txt_renderer->render_text(item.label.c_str(), menu_x+10, item_gl_y+8, 1.0f, text_color);
|
||||||
|
item_gl_y -= item_height;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
menu_x += menu_width;
|
||||||
|
}
|
||||||
|
}
|
||||||
40
client/src/ui/menu_bar.h
Normal file
40
client/src/ui/menu_bar.h
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
#include <functional>
|
||||||
|
#include <SDL3/SDL_events.h>
|
||||||
|
|
||||||
|
#include "gfx/shape_renderer.h"
|
||||||
|
#include "gfx/txt_renderer.h"
|
||||||
|
|
||||||
|
struct MenuItem {
|
||||||
|
std::string label;
|
||||||
|
std::function<void()> action;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Menu {
|
||||||
|
std::string label;
|
||||||
|
std::vector<MenuItem> items;
|
||||||
|
bool is_open = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
class MenuBar {
|
||||||
|
public:
|
||||||
|
MenuBar(int height);
|
||||||
|
~MenuBar(void);
|
||||||
|
|
||||||
|
void add_menu(const std::string& label);
|
||||||
|
void add_menu_item(const std::string& menu_label, const std::string& item_label,
|
||||||
|
std::function<void()> action);
|
||||||
|
|
||||||
|
void handle_event(SDL_Event* event, int window_x, int window_y, int window_gl_y);
|
||||||
|
void render(ShapeRenderer* shape_renderer, TextRenderer* txt_renderer, int x,
|
||||||
|
int y_gl, int width);
|
||||||
|
|
||||||
|
int get_height(void) const;
|
||||||
|
private:
|
||||||
|
int _height;
|
||||||
|
std::vector<Menu> _menus;
|
||||||
|
int _open_menu_index = -1;
|
||||||
|
};
|
||||||
@ -5,7 +5,6 @@
|
|||||||
#include "gfx/txt_renderer.h"
|
#include "gfx/txt_renderer.h"
|
||||||
#include "gfx/types.h"
|
#include "gfx/types.h"
|
||||||
#include "ui/i_window_content.h"
|
#include "ui/i_window_content.h"
|
||||||
#include "ui/window_action.h"
|
|
||||||
|
|
||||||
UIWindow::UIWindow(const char* title, int x, int y, int width, int height) :
|
UIWindow::UIWindow(const char* title, int x, int y, int width, int height) :
|
||||||
_title(title),
|
_title(title),
|
||||||
@ -78,8 +77,7 @@ bool UIWindow::is_point_inside(int x, int y) {
|
|||||||
y >= _y && y <= _y + _height);
|
y >= _y && y <= _y + _height);
|
||||||
}
|
}
|
||||||
|
|
||||||
void UIWindow::render(ShapeRenderer* shape_renderer, TextRenderer* txt_renderer,
|
void UIWindow::render(const RenderContext& context) {
|
||||||
int screen_height, bool show_cursor) {
|
|
||||||
int title_bar_height = 30;
|
int title_bar_height = 30;
|
||||||
|
|
||||||
/* Define colours. */
|
/* Define colours. */
|
||||||
@ -90,22 +88,22 @@ void UIWindow::render(ShapeRenderer* shape_renderer, TextRenderer* txt_renderer,
|
|||||||
const Color resize_handle_color = { 0.9f, 0.9f, 0.9f };
|
const Color resize_handle_color = { 0.9f, 0.9f, 0.9f };
|
||||||
|
|
||||||
/* Convert top-left coords to bottom-left for OpenGL. */
|
/* Convert top-left coords to bottom-left for OpenGL. */
|
||||||
int y_gl = screen_height - _y - _height;
|
int y_gl = context.screen_height - _y - _height;
|
||||||
|
|
||||||
/* Draw main window frame/background. */
|
/* Draw main window frame/background. */
|
||||||
shape_renderer->draw_rect(_x, y_gl, _width, _height, frame_color);
|
context.shape_renderer->draw_rect(_x, y_gl, _width, _height, frame_color);
|
||||||
|
|
||||||
/* Draw title bar. */
|
/* Draw title bar. */
|
||||||
if(_is_focused) {
|
if(_is_focused) {
|
||||||
shape_renderer->draw_rect(_x, y_gl+_height-title_bar_height, _width, title_bar_height,
|
context.shape_renderer->draw_rect(_x, y_gl+_height-title_bar_height, _width, title_bar_height,
|
||||||
focused_title_bar_color);
|
focused_title_bar_color);
|
||||||
} else {
|
} else {
|
||||||
shape_renderer->draw_rect(_x, y_gl+_height-title_bar_height, _width, title_bar_height,
|
context.shape_renderer->draw_rect(_x, y_gl+_height-title_bar_height, _width, title_bar_height,
|
||||||
title_bar_color);
|
title_bar_color);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Draw title text. */
|
/* Draw title text. */
|
||||||
txt_renderer->render_text(_title.c_str(), _x+5, y_gl+_height-title_bar_height+8,
|
context.txt_renderer->render_text(_title.c_str(), _x+5, y_gl+_height-title_bar_height+8,
|
||||||
1.0f, title_text_color);
|
1.0f, title_text_color);
|
||||||
|
|
||||||
/* Draw title bar buttons. */
|
/* Draw title bar buttons. */
|
||||||
@ -113,7 +111,7 @@ void UIWindow::render(ShapeRenderer* shape_renderer, TextRenderer* txt_renderer,
|
|||||||
int button_margin = 5;
|
int button_margin = 5;
|
||||||
int x_offset = _x + _width - button_size - button_margin;
|
int x_offset = _x + _width - button_size - button_margin;
|
||||||
for(const auto& button : _title_bar_buttons) {
|
for(const auto& button : _title_bar_buttons) {
|
||||||
shape_renderer->draw_rect(x_offset, y_gl + _height - title_bar_height + button_margin,
|
context.shape_renderer->draw_rect(x_offset, y_gl + _height - title_bar_height + button_margin,
|
||||||
button_size, button_size, button.color);
|
button_size, button_size, button.color);
|
||||||
x_offset -= (button_size + button_margin);
|
x_offset -= (button_size + button_margin);
|
||||||
}
|
}
|
||||||
@ -121,13 +119,13 @@ void UIWindow::render(ShapeRenderer* shape_renderer, TextRenderer* txt_renderer,
|
|||||||
/* Draw Resize handle. */
|
/* Draw Resize handle. */
|
||||||
int corner_x = _x + _width;
|
int corner_x = _x + _width;
|
||||||
int corner_y = y_gl;
|
int corner_y = y_gl;
|
||||||
shape_renderer->draw_triangle(corner_x, corner_y + 10, corner_x - 10,
|
context.shape_renderer->draw_triangle(corner_x, corner_y + 10, corner_x - 10,
|
||||||
corner_y, corner_x, corner_y, resize_handle_color);
|
corner_y, corner_x, corner_y, resize_handle_color);
|
||||||
|
|
||||||
if(_content) {
|
if(_content) {
|
||||||
int content_y_gl = y_gl;
|
int content_y_gl = y_gl;
|
||||||
int content_height_gl = _height - title_bar_height;
|
int content_height_gl = _height - title_bar_height;
|
||||||
_content->render(txt_renderer, _x, content_y_gl, _width, content_height_gl, show_cursor);
|
_content->render(context, _x, content_y_gl, _width, content_height_gl);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -209,5 +207,9 @@ void UIWindow::handle_event(SDL_Event* event, int screen_width,
|
|||||||
_content->scroll(-event->wheel.y, content_height_gl);
|
_content->scroll(-event->wheel.y, content_height_gl);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if(_content) {
|
||||||
|
int y_gl = screen_height - _y - _height;
|
||||||
|
_content->handle_input(event, _x, _y, y_gl);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -4,8 +4,7 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "gfx/shape_renderer.h"
|
#include "gfx/types.h"
|
||||||
#include "gfx/txt_renderer.h"
|
|
||||||
#include "i_window_content.h"
|
#include "i_window_content.h"
|
||||||
|
|
||||||
enum class WindowState {
|
enum class WindowState {
|
||||||
@ -31,8 +30,7 @@ public:
|
|||||||
~UIWindow(void);
|
~UIWindow(void);
|
||||||
|
|
||||||
void update(void);
|
void update(void);
|
||||||
void render(ShapeRenderer* shape_renderer, TextRenderer* txt_renderer, int screen_height,
|
void render(const RenderContext& context);
|
||||||
bool show_cursor);
|
|
||||||
void handle_event(SDL_Event* event, int screen_width, int screen_height,
|
void handle_event(SDL_Event* event, int screen_width, int screen_height,
|
||||||
int taskbar_height);
|
int taskbar_height);
|
||||||
void minimize(void);
|
void minimize(void);
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user