mirror of
https://repo.dec05eba.com/gpu-screen-recorder-ui
synced 2026-03-31 09:17:04 +09:00
Add radio button with simple/advanced view, add widget visibility
This commit is contained in:
4
TODO
4
TODO
@@ -14,4 +14,6 @@ Optimize list/page when having a few items in it (dont use vector<unique_ptr<Wid
|
||||
|
||||
Only redraw ui if changed (dirty state, propagate upward. Set dirty when adding widget or changing any visible properly on a widget or when event updates how the widget should be displayed).
|
||||
|
||||
Use _NET_WM_ALLOWED_ACTIONS. Same for notifications.
|
||||
Use _NET_WM_ALLOWED_ACTIONS. Same for notifications.
|
||||
|
||||
Handle events in draw function because the render position of elements is available there so why duplicate it in event handler.
|
||||
39
include/gui/RadioButton.hpp
Normal file
39
include/gui/RadioButton.hpp
Normal file
@@ -0,0 +1,39 @@
|
||||
#pragma once
|
||||
|
||||
#include "Widget.hpp"
|
||||
|
||||
#include <mglpp/graphics/Text.hpp>
|
||||
#include <vector>
|
||||
#include <functional>
|
||||
|
||||
namespace gsr {
|
||||
class RadioButton : public Widget {
|
||||
public:
|
||||
RadioButton(mgl::Font *font);
|
||||
RadioButton(const RadioButton&) = delete;
|
||||
RadioButton& operator=(const RadioButton&) = delete;
|
||||
|
||||
bool on_event(mgl::Event &event, mgl::Window &window, mgl::vec2f offset) override;
|
||||
void draw(mgl::Window &window, mgl::vec2f offset) override;
|
||||
|
||||
void add_item(const std::string &text, const std::string &id);
|
||||
void set_selected_item(const std::string &id);
|
||||
|
||||
mgl::vec2f get_size() override;
|
||||
|
||||
std::function<void(const std::string &text, const std::string &id)> on_selection_changed;
|
||||
private:
|
||||
void update_if_dirty();
|
||||
private:
|
||||
struct Item {
|
||||
mgl::Text text;
|
||||
std::string id;
|
||||
};
|
||||
|
||||
mgl::Font *font;
|
||||
std::vector<Item> items;
|
||||
size_t selected_item = 0;
|
||||
bool dirty = true;
|
||||
mgl::vec2f size;
|
||||
};
|
||||
}
|
||||
@@ -12,10 +12,16 @@ namespace gsr {
|
||||
bool on_event(mgl::Event &event, mgl::Window &window, mgl::vec2f offset) override;
|
||||
void draw(mgl::Window &window, mgl::vec2f offset) override;
|
||||
|
||||
mgl::vec2f get_size() override { return size; }
|
||||
mgl::vec2f get_size() override;
|
||||
|
||||
void set_margins(float top, float bottom, float left, float right);
|
||||
private:
|
||||
float get_border_size(mgl::Window &window) const;
|
||||
float get_border_size() const;
|
||||
private:
|
||||
mgl::vec2f size;
|
||||
float margin_top_scale = 0.0f;
|
||||
float margin_bottom_scale = 0.0f;
|
||||
float margin_left_scale = 0.0f;
|
||||
float margin_right_scale = 0.0f;
|
||||
};
|
||||
}
|
||||
@@ -12,7 +12,7 @@ namespace gsr {
|
||||
bool on_event(mgl::Event &event, mgl::Window &window, mgl::vec2f offset) override;
|
||||
void draw(mgl::Window &window, mgl::vec2f offset) override;
|
||||
|
||||
mgl::vec2f get_size() override { return size; }
|
||||
mgl::vec2f get_size() override;
|
||||
private:
|
||||
mgl::vec2f size;
|
||||
};
|
||||
|
||||
@@ -14,6 +14,12 @@ namespace gsr {
|
||||
friend class List;
|
||||
friend class Page;
|
||||
public:
|
||||
enum class Alignment {
|
||||
START,
|
||||
CENTER,
|
||||
END
|
||||
};
|
||||
|
||||
Widget();
|
||||
Widget(const Widget&) = delete;
|
||||
Widget& operator=(const Widget&) = delete;
|
||||
@@ -28,12 +34,26 @@ namespace gsr {
|
||||
|
||||
virtual mgl::vec2f get_position() const;
|
||||
virtual mgl::vec2f get_size() = 0;
|
||||
|
||||
void set_horizontal_alignment(Alignment alignment);
|
||||
void set_vertical_alignment(Alignment alignment);
|
||||
|
||||
Alignment get_horizontal_alignment() const;
|
||||
Alignment get_vertical_alignment() const;
|
||||
|
||||
void set_visible(bool visible);
|
||||
protected:
|
||||
void set_widget_as_selected_in_parent();
|
||||
void remove_widget_as_selected_in_parent();
|
||||
bool has_parent_with_selected_child_widget() const;
|
||||
protected:
|
||||
mgl::vec2f position;
|
||||
Widget *parent_widget = nullptr;
|
||||
Widget *selected_child_widget = nullptr;
|
||||
|
||||
Alignment horizontal_aligment;
|
||||
Alignment vertical_aligment;
|
||||
|
||||
bool visible = true;
|
||||
};
|
||||
}
|
||||
@@ -10,6 +10,7 @@ src = [
|
||||
'src/Theme.cpp',
|
||||
'src/gui/ScrollablePage.cpp',
|
||||
'src/gui/Button.cpp',
|
||||
'src/gui/RadioButton.cpp',
|
||||
'src/gui/Entry.cpp',
|
||||
'src/gui/CheckBox.cpp',
|
||||
'src/gui/ComboBox.cpp',
|
||||
|
||||
@@ -17,6 +17,9 @@ namespace gsr {
|
||||
}
|
||||
|
||||
bool Button::on_event(mgl::Event &event, mgl::Window&, mgl::vec2f offset) {
|
||||
if(!visible)
|
||||
return true;
|
||||
|
||||
const mgl::vec2f item_size = get_size().floor();
|
||||
if(event.type == mgl::Event::MouseButtonPressed && event.mouse_button.button == mgl::Mouse::Left) {
|
||||
const bool clicked_inside = mgl::FloatRect(position + offset, item_size).contains({ (float)event.mouse_button.x, (float)event.mouse_button.y });
|
||||
@@ -27,6 +30,9 @@ namespace gsr {
|
||||
}
|
||||
|
||||
void Button::draw(mgl::Window &window, mgl::vec2f offset) {
|
||||
if(!visible)
|
||||
return;
|
||||
|
||||
const mgl::vec2f draw_pos = position + offset;
|
||||
|
||||
const mgl::vec2f item_size = get_size().floor();
|
||||
@@ -38,12 +44,15 @@ namespace gsr {
|
||||
text.set_position((draw_pos + item_size * 0.5f - text.get_bounds().size * 0.5f).floor());
|
||||
window.draw(text);
|
||||
|
||||
const bool mouse_inside = mgl::FloatRect(draw_pos, item_size).contains(window.get_mouse_position().to_vec2f());
|
||||
const bool mouse_inside = mgl::FloatRect(draw_pos, item_size).contains(window.get_mouse_position().to_vec2f()) && !has_parent_with_selected_child_widget();
|
||||
if(mouse_inside)
|
||||
draw_rectangle_outline(window, draw_pos, item_size, get_theme().tint_color, border_scale * get_theme().window_height);
|
||||
}
|
||||
|
||||
mgl::vec2f Button::get_size() {
|
||||
if(!visible)
|
||||
return {0.0f, 0.0f};
|
||||
|
||||
const int padding_top = padding_top_scale * get_theme().window_height;
|
||||
const int padding_bottom = padding_bottom_scale * get_theme().window_height;
|
||||
const int padding_left = padding_left_scale * get_theme().window_height;
|
||||
|
||||
@@ -16,6 +16,9 @@ namespace gsr {
|
||||
}
|
||||
|
||||
bool CheckBox::on_event(mgl::Event &event, mgl::Window&, mgl::vec2f offset) {
|
||||
if(!visible)
|
||||
return true;
|
||||
|
||||
if(event.type == mgl::Event::MouseButtonPressed && event.mouse_button.button == mgl::Mouse::Left) {
|
||||
const bool clicked_inside = mgl::FloatRect(position + offset, get_size()).contains({ (float)event.mouse_button.x, (float)event.mouse_button.y });
|
||||
if(clicked_inside)
|
||||
@@ -25,6 +28,9 @@ namespace gsr {
|
||||
}
|
||||
|
||||
void CheckBox::draw(mgl::Window &window, mgl::vec2f offset) {
|
||||
if(!visible)
|
||||
return;
|
||||
|
||||
const mgl::vec2f draw_pos = position + offset;
|
||||
|
||||
const mgl::vec2f checkbox_size = get_checkbox_size();
|
||||
@@ -45,7 +51,7 @@ namespace gsr {
|
||||
text.set_position((draw_pos + mgl::vec2f(checkbox_size.x + spacing_scale * get_theme().window_height, checkbox_size.y * 0.5f - text_bounds.y * 0.5f)).floor());
|
||||
window.draw(text);
|
||||
|
||||
const bool mouse_inside = mgl::FloatRect(draw_pos, get_size()).contains(window.get_mouse_position().to_vec2f());
|
||||
const bool mouse_inside = mgl::FloatRect(draw_pos, get_size()).contains(window.get_mouse_position().to_vec2f()) && !has_parent_with_selected_child_widget();
|
||||
if(mouse_inside) {
|
||||
const int border_size = std::max(1.0f, border_scale * get_theme().window_height);
|
||||
const mgl::Color border_color = get_theme().tint_color;
|
||||
@@ -54,6 +60,9 @@ namespace gsr {
|
||||
}
|
||||
|
||||
mgl::vec2f CheckBox::get_size() {
|
||||
if(!visible)
|
||||
return {0.0f, 0.0f};
|
||||
|
||||
mgl::vec2f size = text.get_bounds().size;
|
||||
const mgl::vec2f checkbox_size = get_checkbox_size();
|
||||
size.x += checkbox_size.x + spacing_scale * get_theme().window_height;
|
||||
|
||||
@@ -19,6 +19,9 @@ namespace gsr {
|
||||
}
|
||||
|
||||
bool ComboBox::on_event(mgl::Event &event, mgl::Window&, mgl::vec2f offset) {
|
||||
if(!visible)
|
||||
return true;
|
||||
|
||||
const int padding_top = padding_top_scale * get_theme().window_height;
|
||||
const int padding_bottom = padding_bottom_scale * get_theme().window_height;
|
||||
const int padding_left = padding_left_scale * get_theme().window_height;
|
||||
@@ -60,6 +63,9 @@ namespace gsr {
|
||||
}
|
||||
|
||||
void ComboBox::draw(mgl::Window &window, mgl::vec2f offset) {
|
||||
if(!visible)
|
||||
return;
|
||||
|
||||
update_if_dirty();
|
||||
|
||||
if(items.empty())
|
||||
@@ -92,7 +98,7 @@ namespace gsr {
|
||||
window.draw(dropdown_arrow);
|
||||
}
|
||||
|
||||
const bool mouse_inside = mgl::FloatRect(draw_pos, item_size).contains(window.get_mouse_position().to_vec2f());
|
||||
const bool mouse_inside = mgl::FloatRect(draw_pos, item_size).contains(window.get_mouse_position().to_vec2f()) && !has_parent_with_selected_child_widget();
|
||||
mgl::vec2f pos = draw_pos + mgl::vec2f(padding_left, padding_top);
|
||||
|
||||
Item &item = items[selected_item];
|
||||
@@ -164,6 +170,9 @@ namespace gsr {
|
||||
}
|
||||
|
||||
mgl::vec2f ComboBox::get_size() {
|
||||
if(!visible)
|
||||
return {0.0f, 0.0f};
|
||||
|
||||
update_if_dirty();
|
||||
|
||||
const int padding_top = padding_top_scale * get_theme().window_height;
|
||||
|
||||
@@ -26,6 +26,9 @@ namespace gsr {
|
||||
}
|
||||
|
||||
bool DropdownButton::on_event(mgl::Event &event, mgl::Window&, mgl::vec2f offset) {
|
||||
if(!visible)
|
||||
return true;
|
||||
|
||||
if(event.type == mgl::Event::MouseMoved) {
|
||||
const mgl::vec2f draw_pos = position + offset;
|
||||
const mgl::vec2f collision_margin(1.0f, 1.0f); // Makes sure that multiple buttons that are next to each other wont activate at the same time when the cursor is right between them
|
||||
@@ -56,6 +59,9 @@ namespace gsr {
|
||||
}
|
||||
|
||||
void DropdownButton::draw(mgl::Window &window, mgl::vec2f offset) {
|
||||
if(!visible)
|
||||
return;
|
||||
|
||||
update_if_dirty();
|
||||
|
||||
const mgl::vec2f draw_pos = position + offset;
|
||||
@@ -199,6 +205,9 @@ namespace gsr {
|
||||
}
|
||||
|
||||
mgl::vec2f DropdownButton::get_size() {
|
||||
if(!visible)
|
||||
return {0.0f, 0.0f};
|
||||
|
||||
update_if_dirty();
|
||||
return size;
|
||||
}
|
||||
|
||||
@@ -22,6 +22,9 @@ namespace gsr {
|
||||
}
|
||||
|
||||
bool Entry::on_event(mgl::Event &event, mgl::Window&, mgl::vec2f offset) {
|
||||
if(!visible)
|
||||
return true;
|
||||
|
||||
if(event.type == mgl::Event::MouseButtonPressed && event.mouse_button.button == mgl::Mouse::Left) {
|
||||
selected = mgl::FloatRect(position + offset, get_size()).contains({ (float)event.mouse_button.x, (float)event.mouse_button.y });
|
||||
} else if(event.type == mgl::Event::KeyPressed && selected) {
|
||||
@@ -40,6 +43,9 @@ namespace gsr {
|
||||
}
|
||||
|
||||
void Entry::draw(mgl::Window &window, mgl::vec2f offset) {
|
||||
if(!visible)
|
||||
return;
|
||||
|
||||
const mgl::vec2f draw_pos = position + offset;
|
||||
|
||||
const int padding_top = padding_top_scale * get_theme().window_height;
|
||||
@@ -66,6 +72,9 @@ namespace gsr {
|
||||
}
|
||||
|
||||
mgl::vec2f Entry::get_size() {
|
||||
if(!visible)
|
||||
return {0.0f, 0.0f};
|
||||
|
||||
const int padding_top = padding_top_scale * get_theme().window_height;
|
||||
const int padding_bottom = padding_bottom_scale * get_theme().window_height;
|
||||
return { max_width, text.get_bounds().size.y + padding_top + padding_bottom };
|
||||
|
||||
@@ -11,11 +11,17 @@ namespace gsr {
|
||||
}
|
||||
|
||||
void Label::draw(mgl::Window &window, mgl::vec2f offset) {
|
||||
if(!visible)
|
||||
return;
|
||||
|
||||
text.set_position((position + offset).floor());
|
||||
window.draw(text);
|
||||
}
|
||||
|
||||
mgl::vec2f Label::get_size() {
|
||||
if(!visible)
|
||||
return {0.0f, 0.0f};
|
||||
|
||||
return text.get_bounds().size;
|
||||
}
|
||||
}
|
||||
@@ -12,6 +12,9 @@ namespace gsr {
|
||||
List::List(Orientation orientation, Alignment content_alignment) : orientation(orientation), content_alignment(content_alignment) {}
|
||||
|
||||
bool List::on_event(mgl::Event &event, mgl::Window &window, mgl::vec2f) {
|
||||
if(!visible)
|
||||
return true;
|
||||
|
||||
// We want to store the selected child widget since it can change in the event loop below
|
||||
Widget *selected_widget = selected_child_widget;
|
||||
if(selected_widget) {
|
||||
@@ -55,19 +58,33 @@ namespace gsr {
|
||||
void List::draw(mgl::Window &window, mgl::vec2f offset) {
|
||||
update();
|
||||
|
||||
if(!visible)
|
||||
return;
|
||||
|
||||
mgl::vec2f draw_pos = position + offset;
|
||||
offset = {0.0f, 0.0f};
|
||||
Widget *selected_widget = selected_child_widget;
|
||||
|
||||
// TODO: Handle start/end alignment
|
||||
const mgl::vec2f size = get_size();
|
||||
const mgl::vec2f parent_size = parent_widget ? parent_widget->get_size() : mgl::vec2f(0.0f, 0.0f);
|
||||
|
||||
const mgl::vec2f spacing = (spacing_scale * get_theme().window_height).floor();
|
||||
switch(orientation) {
|
||||
case Orientation::VERTICAL: {
|
||||
for(auto &widget : widgets) {
|
||||
if(content_alignment == Alignment::CENTER)
|
||||
if(!widget->visible)
|
||||
continue;
|
||||
|
||||
// TODO: Do this parent widget alignment for horizontal alignment and for other types of widget alignment
|
||||
// and other widgets.
|
||||
// Also take this widget alignment into consideration in get_size.
|
||||
if(widget->get_horizontal_alignment() == Widget::Alignment::CENTER && parent_size.x > 0.001f)
|
||||
offset.x = floor(parent_size.x * 0.5f - widget->get_size().x * 0.5f);
|
||||
else if(content_alignment == Alignment::CENTER)
|
||||
offset.x = floor(size.x * 0.5f - widget->get_size().x * 0.5f);
|
||||
else
|
||||
offset.x = 0.0f;
|
||||
widget->set_position(draw_pos + offset);
|
||||
if(widget.get() != selected_widget)
|
||||
widget->draw(window, mgl::vec2f(0.0f, 0.0f));
|
||||
@@ -77,6 +94,9 @@ namespace gsr {
|
||||
}
|
||||
case Orientation::HORIZONTAL: {
|
||||
for(auto &widget : widgets) {
|
||||
if(!widget->visible)
|
||||
continue;
|
||||
|
||||
if(content_alignment == Alignment::CENTER)
|
||||
offset.y = floor(size.y * 0.5f - widget->get_size().y * 0.5f);
|
||||
widget->set_position(draw_pos + offset);
|
||||
@@ -121,11 +141,17 @@ namespace gsr {
|
||||
|
||||
// TODO: Cache result
|
||||
mgl::vec2f List::get_size() {
|
||||
if(!visible)
|
||||
return {0.0f, 0.0f};
|
||||
|
||||
mgl::vec2f size;
|
||||
const mgl::vec2f spacing = (spacing_scale * get_theme().window_height).floor();
|
||||
switch(orientation) {
|
||||
case Orientation::VERTICAL: {
|
||||
for(auto &widget : widgets) {
|
||||
if(!widget->visible)
|
||||
continue;
|
||||
|
||||
const auto widget_size = widget->get_size();
|
||||
size.x = std::max(size.x, widget_size.x);
|
||||
size.y += widget_size.y + spacing.y;
|
||||
@@ -134,6 +160,9 @@ namespace gsr {
|
||||
}
|
||||
case Orientation::HORIZONTAL: {
|
||||
for(auto &widget : widgets) {
|
||||
if(!widget->visible)
|
||||
continue;
|
||||
|
||||
const auto widget_size = widget->get_size();
|
||||
size.x += widget_size.x + spacing.x;
|
||||
size.y = std::max(size.y, widget_size.y);
|
||||
|
||||
129
src/gui/RadioButton.cpp
Normal file
129
src/gui/RadioButton.cpp
Normal file
@@ -0,0 +1,129 @@
|
||||
#include "../../include/gui/RadioButton.hpp"
|
||||
#include "../../include/gui/Utils.hpp"
|
||||
#include "../../include/Theme.hpp"
|
||||
#include <mglpp/graphics/Rectangle.hpp>
|
||||
#include <mglpp/window/Window.hpp>
|
||||
#include <mglpp/window/Event.hpp>
|
||||
#include <mglpp/system/FloatRect.hpp>
|
||||
|
||||
namespace gsr {
|
||||
static const float padding_top_scale = 0.004629f;
|
||||
static const float padding_bottom_scale = 0.004629f;
|
||||
static const float padding_left_scale = 0.007f;
|
||||
static const float padding_right_scale = 0.007f;
|
||||
static const float spacing_scale = 0.007f;
|
||||
static const float border_scale = 0.0015f;
|
||||
|
||||
RadioButton::RadioButton(mgl::Font *font) : font(font) {
|
||||
|
||||
}
|
||||
|
||||
bool RadioButton::on_event(mgl::Event &event, mgl::Window&, mgl::vec2f offset) {
|
||||
if(!visible)
|
||||
return true;
|
||||
|
||||
const int padding_top = padding_top_scale * get_theme().window_height;
|
||||
const int padding_bottom = padding_bottom_scale * get_theme().window_height;
|
||||
const int padding_left = padding_left_scale * get_theme().window_height;
|
||||
const int padding_right = padding_right_scale * get_theme().window_height;
|
||||
|
||||
if(event.type == mgl::Event::MouseButtonPressed && event.mouse_button.button == mgl::Mouse::Left) {
|
||||
mgl::vec2f draw_pos = position + offset;
|
||||
for(size_t i = 0; i < items.size(); ++i) {
|
||||
auto &item = items[i];
|
||||
const mgl::vec2f item_size = item.text.get_bounds().size + mgl::vec2f(padding_left + padding_right, padding_top + padding_bottom);
|
||||
|
||||
const bool mouse_inside = mgl::FloatRect(draw_pos, item_size).contains(mgl::vec2f(event.mouse_button.x, event.mouse_button.y));
|
||||
if(mouse_inside) {
|
||||
const size_t prev_selected_item = selected_item;
|
||||
selected_item = i;
|
||||
|
||||
if(selected_item != prev_selected_item && on_selection_changed)
|
||||
on_selection_changed(item.text.get_string(), item.id);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
draw_pos.x += item_size.x + spacing_scale * get_theme().window_height;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void RadioButton::draw(mgl::Window &window, mgl::vec2f offset) {
|
||||
if(!visible)
|
||||
return;
|
||||
|
||||
update_if_dirty();
|
||||
|
||||
const int padding_top = padding_top_scale * get_theme().window_height;
|
||||
const int padding_bottom = padding_bottom_scale * get_theme().window_height;
|
||||
const int padding_left = padding_left_scale * get_theme().window_height;
|
||||
const int padding_right = padding_right_scale * get_theme().window_height;
|
||||
|
||||
const bool can_select_item = !has_parent_with_selected_child_widget();
|
||||
|
||||
mgl::vec2f draw_pos = position + offset;
|
||||
for(size_t i = 0; i < items.size(); ++i) {
|
||||
auto &item = items[i];
|
||||
const mgl::vec2f item_size = item.text.get_bounds().size + mgl::vec2f(padding_left + padding_right, padding_top + padding_bottom);
|
||||
mgl::Rectangle background(item_size.floor());
|
||||
background.set_position(draw_pos.floor());
|
||||
background.set_color(i == selected_item ? get_theme().tint_color : mgl::Color(0, 0, 0, 120));
|
||||
window.draw(background);
|
||||
|
||||
const bool mouse_inside = mgl::FloatRect(draw_pos, item_size).contains(window.get_mouse_position().to_vec2f());
|
||||
if(can_select_item && mouse_inside) {
|
||||
const int border_size = border_scale * get_theme().window_height;
|
||||
const mgl::Color border_color = get_theme().tint_color;
|
||||
draw_rectangle_outline(window, draw_pos.floor(), item_size.floor(), border_color, border_size);
|
||||
}
|
||||
|
||||
item.text.set_position((draw_pos + item_size * 0.5f - item.text.get_bounds().size * 0.5f).floor());
|
||||
window.draw(item.text);
|
||||
|
||||
draw_pos.x += item_size.x + spacing_scale * get_theme().window_height;
|
||||
}
|
||||
}
|
||||
|
||||
void RadioButton::update_if_dirty() {
|
||||
if(!dirty)
|
||||
return;
|
||||
|
||||
const int padding_top = padding_top_scale * get_theme().window_height;
|
||||
const int padding_bottom = padding_bottom_scale * get_theme().window_height;
|
||||
const int padding_left = padding_left_scale * get_theme().window_height;
|
||||
const int padding_right = padding_right_scale * get_theme().window_height;
|
||||
|
||||
size = { 0.0f, font->get_character_size() + (float)padding_top + (float)padding_bottom };
|
||||
for(Item &item : items) {
|
||||
const mgl::vec2f bounds = item.text.get_bounds().size;
|
||||
size.x += bounds.x + padding_left + padding_right;
|
||||
}
|
||||
if(items.size() > 1)
|
||||
size.x += (items.size() - 1) * spacing_scale * get_theme().window_height;
|
||||
dirty = false;
|
||||
}
|
||||
|
||||
mgl::vec2f RadioButton::get_size() {
|
||||
if(!visible)
|
||||
return {0.0f, 0.0f};
|
||||
|
||||
update_if_dirty();
|
||||
return size;
|
||||
}
|
||||
|
||||
void RadioButton::add_item(const std::string &text, const std::string &id) {
|
||||
items.push_back({mgl::Text(text, *font), id});
|
||||
dirty = true;
|
||||
}
|
||||
|
||||
void RadioButton::set_selected_item(const std::string &id) {
|
||||
for(size_t i = 0; i < items.size(); ++i) {
|
||||
if(items[i].id == id) {
|
||||
selected_item = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -8,8 +8,14 @@ namespace gsr {
|
||||
ScrollablePage::ScrollablePage(mgl::vec2f size) : size(size) {}
|
||||
|
||||
bool ScrollablePage::on_event(mgl::Event &event, mgl::Window &window, mgl::vec2f offset) {
|
||||
if(!visible)
|
||||
return true;
|
||||
|
||||
const int margin_top = margin_top_scale * get_theme().window_height;
|
||||
const int margin_left = margin_left_scale * get_theme().window_height;
|
||||
|
||||
const mgl::vec2f draw_pos = position + offset;
|
||||
offset = draw_pos + mgl::vec2f(0.0f, get_border_size(window)).floor();
|
||||
offset = draw_pos + mgl::vec2f(margin_left, get_border_size() + margin_top).floor();
|
||||
Widget *selected_widget = selected_child_widget;
|
||||
|
||||
if(selected_widget) {
|
||||
@@ -29,29 +35,37 @@ namespace gsr {
|
||||
}
|
||||
|
||||
void ScrollablePage::draw(mgl::Window &window, mgl::vec2f offset) {
|
||||
if(!visible)
|
||||
return;
|
||||
|
||||
const int margin_top = margin_top_scale * get_theme().window_height;
|
||||
const int margin_left = margin_left_scale * get_theme().window_height;
|
||||
|
||||
const mgl::vec2f draw_pos = position + offset;
|
||||
offset = draw_pos + mgl::vec2f(0.0f, get_border_size(window)).floor();
|
||||
Widget *selected_widget = selected_child_widget;
|
||||
|
||||
mgl_scissor prev_scissor;
|
||||
mgl_window_get_scissor(window.internal_window(), &prev_scissor);
|
||||
|
||||
mgl_scissor new_scissor = {
|
||||
mgl_vec2i{(int)draw_pos.x, (int)draw_pos.y},
|
||||
mgl_vec2i{(int)size.x, (int)size.y}
|
||||
};
|
||||
mgl_window_set_scissor(window.internal_window(), &new_scissor);
|
||||
offset = draw_pos + mgl::vec2f(margin_left, get_border_size() + margin_top).floor();
|
||||
|
||||
mgl::Rectangle background(size.floor());
|
||||
background.set_position(draw_pos);
|
||||
background.set_color(get_theme().scrollable_page_bg_color);
|
||||
window.draw(background);
|
||||
|
||||
mgl::Rectangle border(mgl::vec2f(size.x, get_border_size(window)).floor());
|
||||
mgl::Rectangle border(mgl::vec2f(size.x, get_border_size()).floor());
|
||||
border.set_position(draw_pos);
|
||||
border.set_color(get_theme().tint_color);
|
||||
window.draw(border);
|
||||
|
||||
mgl_scissor prev_scissor;
|
||||
mgl_window_get_scissor(window.internal_window(), &prev_scissor);
|
||||
|
||||
const mgl::vec2f content_size = get_size();
|
||||
mgl_scissor new_scissor = {
|
||||
mgl_vec2i{(int)offset.x, (int)offset.y},
|
||||
mgl_vec2i{(int)content_size.x, (int)content_size.y}
|
||||
};
|
||||
mgl_window_set_scissor(window.internal_window(), &new_scissor);
|
||||
|
||||
Widget *selected_widget = selected_child_widget;
|
||||
|
||||
for(auto &widget : widgets) {
|
||||
if(widget.get() != selected_widget)
|
||||
widget->draw(window, offset);
|
||||
@@ -63,7 +77,25 @@ namespace gsr {
|
||||
mgl_window_set_scissor(window.internal_window(), &prev_scissor);
|
||||
}
|
||||
|
||||
float ScrollablePage::get_border_size(mgl::Window &window) const {
|
||||
return window.get_size().y * 0.004f;
|
||||
mgl::vec2f ScrollablePage::get_size() {
|
||||
if(!visible)
|
||||
return {0.0f, 0.0f};
|
||||
|
||||
const int margin_top = margin_top_scale * get_theme().window_height;
|
||||
const int margin_bottom = margin_bottom_scale * get_theme().window_height;
|
||||
const int margin_left = margin_left_scale * get_theme().window_height;
|
||||
const int margin_right = margin_right_scale * get_theme().window_height;
|
||||
return size - mgl::vec2f(margin_left + margin_right, margin_top + margin_bottom + get_border_size());
|
||||
}
|
||||
|
||||
void ScrollablePage::set_margins(float top, float bottom, float left, float right) {
|
||||
margin_top_scale = top;
|
||||
margin_bottom_scale = bottom;
|
||||
margin_left_scale = left;
|
||||
margin_right_scale = right;
|
||||
}
|
||||
|
||||
float ScrollablePage::get_border_size() const {
|
||||
return 0.004f * get_theme().window_height;
|
||||
}
|
||||
}
|
||||
@@ -6,6 +6,9 @@ namespace gsr {
|
||||
StaticPage::StaticPage(mgl::vec2f size) : size(size) {}
|
||||
|
||||
bool StaticPage::on_event(mgl::Event &event, mgl::Window &window, mgl::vec2f offset) {
|
||||
if(!visible)
|
||||
return true;
|
||||
|
||||
const mgl::vec2f draw_pos = position + offset;
|
||||
offset = draw_pos;
|
||||
Widget *selected_widget = selected_child_widget;
|
||||
@@ -27,6 +30,9 @@ namespace gsr {
|
||||
}
|
||||
|
||||
void StaticPage::draw(mgl::Window &window, mgl::vec2f offset) {
|
||||
if(!visible)
|
||||
return;
|
||||
|
||||
const mgl::vec2f draw_pos = position + offset;
|
||||
offset = draw_pos;
|
||||
Widget *selected_widget = selected_child_widget;
|
||||
@@ -50,4 +56,11 @@ namespace gsr {
|
||||
|
||||
mgl_window_set_scissor(window.internal_window(), &prev_scissor);
|
||||
}
|
||||
|
||||
mgl::vec2f StaticPage::get_size() {
|
||||
if(!visible)
|
||||
return {0.0f, 0.0f};
|
||||
|
||||
return size;
|
||||
}
|
||||
}
|
||||
@@ -32,4 +32,34 @@ namespace gsr {
|
||||
parent_widget->remove_widget_as_selected_in_parent();
|
||||
}
|
||||
}
|
||||
|
||||
bool Widget::has_parent_with_selected_child_widget() const {
|
||||
// TODO: Optimize since this is called in draw function in widgets
|
||||
if(parent_widget) {
|
||||
if(parent_widget->selected_child_widget)
|
||||
return true;
|
||||
return parent_widget->has_parent_with_selected_child_widget();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void Widget::set_horizontal_alignment(Alignment alignment) {
|
||||
horizontal_aligment = alignment;
|
||||
}
|
||||
|
||||
void Widget::set_vertical_alignment(Alignment alignment) {
|
||||
vertical_aligment = alignment;
|
||||
}
|
||||
|
||||
Widget::Alignment Widget::get_horizontal_alignment() const {
|
||||
return horizontal_aligment;
|
||||
}
|
||||
|
||||
Widget::Alignment Widget::get_vertical_alignment() const {
|
||||
return vertical_aligment;
|
||||
}
|
||||
|
||||
void Widget::set_visible(bool visible) {
|
||||
this->visible = visible;
|
||||
}
|
||||
}
|
||||
30
src/main.cpp
30
src/main.cpp
@@ -3,6 +3,7 @@
|
||||
#include "../include/gui/ScrollablePage.hpp"
|
||||
#include "../include/gui/DropdownButton.hpp"
|
||||
#include "../include/gui/Button.hpp"
|
||||
#include "../include/gui/RadioButton.hpp"
|
||||
#include "../include/gui/Entry.hpp"
|
||||
#include "../include/gui/CheckBox.hpp"
|
||||
#include "../include/gui/ComboBox.hpp"
|
||||
@@ -214,8 +215,18 @@ static void add_widgets_to_settings_page(mgl::vec2i window_size, mgl::vec2f sett
|
||||
settings_page->add_widget(std::move(back_button));
|
||||
|
||||
auto settings_list = std::make_unique<gsr::List>(gsr::List::Orientation::VERTICAL);
|
||||
settings_list->set_position(mgl::vec2f(0.02f * gsr::get_theme().window_height, 0.02f * gsr::get_theme().window_height).floor());
|
||||
{
|
||||
auto view_radio_button = std::make_unique<gsr::RadioButton>(&gsr::get_theme().body_font);
|
||||
view_radio_button->add_item("Simple view", "simple");
|
||||
view_radio_button->add_item("Advanced view", "advanced");
|
||||
view_radio_button->set_horizontal_alignment(gsr::Widget::Alignment::CENTER);
|
||||
gsr::RadioButton *view_radio_button_ptr = view_radio_button.get();
|
||||
settings_list->add_widget(std::move(view_radio_button));
|
||||
|
||||
gsr::Widget *color_range_list_ptr = nullptr;
|
||||
gsr::Widget *codec_list_ptr = nullptr;
|
||||
gsr::Widget *framerate_mode_list_ptr = nullptr;
|
||||
|
||||
auto record_area_list = std::make_unique<gsr::List>(gsr::List::Orientation::VERTICAL);
|
||||
{
|
||||
record_area_list->add_widget(std::make_unique<gsr::Label>(&gsr::get_theme().body_font, "Record area:", gsr::get_theme().text_color));
|
||||
@@ -302,6 +313,7 @@ static void add_widgets_to_settings_page(mgl::vec2i window_size, mgl::vec2f sett
|
||||
color_range_box->add_item("Full", "full");
|
||||
color_range_list->add_widget(std::move(color_range_box));
|
||||
}
|
||||
color_range_list_ptr = color_range_list.get();
|
||||
quality_list->add_widget(std::move(color_range_list));
|
||||
}
|
||||
settings_list->add_widget(std::move(quality_list));
|
||||
@@ -341,6 +353,7 @@ static void add_widgets_to_settings_page(mgl::vec2i window_size, mgl::vec2f sett
|
||||
}
|
||||
codec_list->add_widget(std::move(audio_codec_list));
|
||||
}
|
||||
codec_list_ptr = codec_list.get();
|
||||
settings_list->add_widget(std::move(codec_list));
|
||||
|
||||
auto framerate_info_list = std::make_unique<gsr::List>(gsr::List::Orientation::HORIZONTAL);
|
||||
@@ -363,6 +376,7 @@ static void add_widgets_to_settings_page(mgl::vec2i window_size, mgl::vec2f sett
|
||||
framerate_mode_box->add_item("Variable", "vfr");
|
||||
framerate_mode_list->add_widget(std::move(framerate_mode_box));
|
||||
}
|
||||
framerate_mode_list_ptr = framerate_mode_list.get();
|
||||
framerate_info_list->add_widget(std::move(framerate_mode_list));
|
||||
}
|
||||
settings_list->add_widget(std::move(framerate_info_list));
|
||||
@@ -397,6 +411,16 @@ static void add_widgets_to_settings_page(mgl::vec2i window_size, mgl::vec2f sett
|
||||
settings_list->add_widget(std::make_unique<gsr::CheckBox>(&gsr::get_theme().body_font, "Show recording started notification"));
|
||||
//settings_list->add_widget(std::make_unique<gsr::CheckBox>(&gsr::get_theme().body_font, "Show recording stopped notification"));
|
||||
settings_list->add_widget(std::make_unique<gsr::CheckBox>(&gsr::get_theme().body_font, "Show video saved notification"));
|
||||
|
||||
view_radio_button_ptr->on_selection_changed = [=](const std::string &text, const std::string &id) {
|
||||
(void)text;
|
||||
const bool advanced_view = id == "advanced";
|
||||
color_range_list_ptr->set_visible(advanced_view);
|
||||
codec_list_ptr->set_visible(advanced_view);
|
||||
framerate_mode_list_ptr->set_visible(advanced_view);
|
||||
};
|
||||
|
||||
view_radio_button_ptr->on_selection_changed("Simple", "simple");
|
||||
}
|
||||
settings_content_page->add_widget(std::move(settings_list));
|
||||
}
|
||||
@@ -515,18 +539,22 @@ int main(int argc, char **argv) {
|
||||
|
||||
const mgl::vec2f settings_page_size(window_size.x * 0.3333f, window_size.y * 0.7f);
|
||||
const mgl::vec2f settings_page_position = (window_size.to_vec2f() * 0.5f - settings_page_size * 0.5f).floor();
|
||||
const float settings_body_margin = 0.02f;
|
||||
|
||||
auto replay_settings_content = std::make_unique<gsr::ScrollablePage>(settings_page_size);
|
||||
gsr::ScrollablePage *replay_settings_content_ptr = replay_settings_content.get();
|
||||
replay_settings_content->set_position(settings_page_position);
|
||||
replay_settings_content->set_margins(settings_body_margin, settings_body_margin, settings_body_margin, settings_body_margin);
|
||||
|
||||
auto record_settings_content = std::make_unique<gsr::ScrollablePage>(settings_page_size);
|
||||
gsr::ScrollablePage *record_settings_content_ptr = record_settings_content.get();
|
||||
record_settings_content->set_position(settings_page_position);
|
||||
record_settings_content->set_margins(settings_body_margin, settings_body_margin, settings_body_margin, settings_body_margin);
|
||||
|
||||
auto stream_settings_content = std::make_unique<gsr::ScrollablePage>(settings_page_size);
|
||||
gsr::ScrollablePage *stream_settings_content_ptr = stream_settings_content.get();
|
||||
stream_settings_content->set_position(settings_page_position);
|
||||
stream_settings_content->set_margins(settings_body_margin, settings_body_margin, settings_body_margin, settings_body_margin);
|
||||
|
||||
gsr::StaticPage replay_settings_page(window_size.to_vec2f());
|
||||
replay_settings_page.add_widget(std::move(replay_settings_content));
|
||||
|
||||
Reference in New Issue
Block a user