bettola/client/src/ui/ui_window.cpp

214 lines
7.0 KiB
C++

#include "ui_window.h"
#include <SDL3/SDL_events.h>
#include <memory>
#include "gfx/shape_renderer.h"
#include "gfx/txt_renderer.h"
#include "gfx/types.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) :
_title(title),
_x(x),
_y(y),
_width(width),
_height(height),
_content(nullptr),
_is_dragging(false),
_is_hovered(false),
_is_focused(false),
_should_close(false),
_state(WindowState::NORMAL),
_is_resizing(false),
_resize_margin(10) {
/* Init title bar buttons. */
_title_bar_buttons.push_back({WindowButtonAction::CLOSE, {0.8f, 0.2f, 0.2f}});
_title_bar_buttons.push_back({WindowButtonAction::MAXIMIZE, {0.2f, 0.8f, 0.2f}});
_title_bar_buttons.push_back({WindowButtonAction::MINIMIZE, {0.8f, 0.8f, 0.2f}});
}
UIWindow::~UIWindow(void) {}
void UIWindow::minimize(void) {
_state = WindowState::MINIMIZED;
}
void UIWindow::restore(void) {
_state = WindowState::NORMAL;
}
bool UIWindow::is_minimized(void) const {
return _state == WindowState::MINIMIZED;
}
const std::string& UIWindow::get_title(void) const {
return _title;
}
bool UIWindow::is_mouse_over_resize_handle(int mouse_x, int mouse_y) const {
return (mouse_x >= _x + _width - _resize_margin && mouse_x <= _x + _width &&
mouse_y >= _y + _height - _resize_margin &&
mouse_y <= _y + _height);
}
bool UIWindow::should_close(void) const {
return _should_close;
}
void UIWindow::update(void) {
if(_content) {
if(_content->should_close()) { _should_close = true; }
}
}
void UIWindow::set_content(std::unique_ptr<IWindowContent> content) {
_content = std::move(content);
}
void UIWindow::set_focused(bool focused) {
_is_focused = focused;
}
IWindowContent* UIWindow::get_content(void) {
return _content.get();
}
bool UIWindow::is_point_inside(int x, int y) {
return (x >= _x && x <= _x + _width &&
y >= _y && y <= _y + _height);
}
void UIWindow::render(ShapeRenderer* shape_renderer, TextRenderer* txt_renderer,
int screen_height, bool show_cursor) {
int title_bar_height = 30;
/* Define colours. */
const Color frame_color = { 0.2f, 0.2f, 0.25f };
const Color title_bar_color = { 0.15f, 0.15f, 0.2f };
const Color focused_title_bar_color = { 0.3f, 0.3f, 0.4f };
const Color title_text_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. */
int y_gl = screen_height - _y - _height;
/* Draw main window frame/background. */
shape_renderer->draw_rect(_x, y_gl, _width, _height, frame_color);
/* Draw title bar. */
if(_is_focused) {
shape_renderer->draw_rect(_x, y_gl+_height-title_bar_height, _width, title_bar_height,
focused_title_bar_color);
} else {
shape_renderer->draw_rect(_x, y_gl+_height-title_bar_height, _width, title_bar_height,
title_bar_color);
}
/* Draw title text. */
txt_renderer->render_text(_title.c_str(), _x+5, y_gl+_height-title_bar_height+8,
1.0f, title_text_color);
/* Draw title bar buttons. */
int button_size = 20;
int button_margin = 5;
int x_offset = _x + _width - button_size - button_margin;
for(const auto& button : _title_bar_buttons) {
shape_renderer->draw_rect(x_offset, y_gl + _height - title_bar_height + button_margin,
button_size, button_size, button.color);
x_offset -= (button_size + button_margin);
}
/* Draw Resize handle. */
int corner_x = _x + _width;
int corner_y = y_gl;
shape_renderer->draw_triangle(corner_x, corner_y + 10, corner_x - 10,
corner_y, corner_x, corner_y, resize_handle_color);
if(_content) {
int content_y_gl = y_gl;
int content_height_gl = _height - title_bar_height;
_content->render(txt_renderer, _x, content_y_gl, _width, content_height_gl, show_cursor);
}
}
void UIWindow::handle_event(SDL_Event* event, int screen_width,
int screen_height, int taskbar_height) {
int title_bar_height = 30;
if(event->type == SDL_EVENT_MOUSE_BUTTON_DOWN) {
int mouse_x = event->button.x;
int mouse_y = event->button.y;
/* Check for title bar button clicks. */
int button_size = 20;
int button_margin = 5;
int x_offset = _x + _width - button_size - button_margin;
for(const auto& button : _title_bar_buttons) {
if(mouse_x >= x_offset && mouse_x <= x_offset + button_size &&
mouse_y >= _y + button_margin && mouse_y <= _y + button_margin + button_size) {
switch(button.action) {
case WindowButtonAction::CLOSE:
_should_close = true;
break;
case WindowButtonAction::MAXIMIZE:
if(_state == WindowState::MAXIMIZED) {
_x = _pre_maximize_rect.x;
_y = _pre_maximize_rect.y;
_width = _pre_maximize_rect.w;
_height = _pre_maximize_rect.h;
_state = WindowState::NORMAL;
} else {
_pre_maximize_rect = { _x, _y, _width, _height };
_x = 0; _y = 0;
_width = screen_width; _height = screen_height - taskbar_height;
_state = WindowState::MAXIMIZED;
}
break;
case WindowButtonAction::MINIMIZE:
minimize();
break;
}
return; /* Button clicked, no need to process further. */
}
x_offset -= (button_size + button_margin);
}
/* Check for resize handle click (bottom-right corner). */
if(is_mouse_over_resize_handle(mouse_x, mouse_y) &&
_state != WindowState::MAXIMIZED) {
_is_resizing = true;
} else if(mouse_x >= _x && mouse_x <= _x + _width &&
mouse_y >= _y && mouse_y <= _y + title_bar_height &&
_state != WindowState::MAXIMIZED) {
/* Is click within title bar? */
_is_dragging = true;
_drag_offset_x = mouse_x - _x;
_drag_offset_y = mouse_y - _y;
}
} else if(event->type == SDL_EVENT_MOUSE_BUTTON_UP) {
_is_dragging = false;
_is_resizing = false;
} else if(event->type == SDL_EVENT_MOUSE_MOTION) {
if(_is_dragging) {
_x = event->motion.x - _drag_offset_x;
_y = event->motion.y - _drag_offset_y;
} else if(_is_resizing) {
int new_width = event->motion.x - _x;
int new_height = event->motion.y - _y;
_width = (new_width > 100) ? new_width : 100; /* Min width. */
_height = (new_height > 80) ? new_height : 80; /* Min height. */
}
/* Check if mouse hovered over window. */
_is_hovered = is_point_inside(event->motion.x, event->motion.y);
} else if(event->type == SDL_EVENT_MOUSE_WHEEL) {
/* Only scroll window if mouse is hovering. */
if(_is_hovered && _content) {
/* SDL's wheel motion is negative scroll up on the y. */
int content_height_gl = _height - title_bar_height;
_content->scroll(-event->wheel.y, content_height_gl);
}
}
}