aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authordec05eba <dec05eba@protonmail.com>2024-08-07 00:21:32 +0200
committerdec05eba <dec05eba@protonmail.com>2024-08-07 00:21:35 +0200
commita3e479d5b289166ff651fac4ff046656cf78cda0 (patch)
tree2ba345228acfe45acf9863bb122e163ed38db7db
parentb229b060add5f66bd5532698c4a790285095e98a (diff)
Add radio button with simple/advanced view, add widget visibility
-rw-r--r--TODO4
-rw-r--r--include/gui/RadioButton.hpp39
-rw-r--r--include/gui/ScrollablePage.hpp10
-rw-r--r--include/gui/StaticPage.hpp2
-rw-r--r--include/gui/Widget.hpp20
-rw-r--r--meson.build1
-rw-r--r--src/gui/Button.cpp11
-rw-r--r--src/gui/CheckBox.cpp11
-rw-r--r--src/gui/ComboBox.cpp11
-rw-r--r--src/gui/DropdownButton.cpp9
-rw-r--r--src/gui/Entry.cpp9
-rw-r--r--src/gui/Label.cpp6
-rw-r--r--src/gui/List.cpp31
-rw-r--r--src/gui/RadioButton.cpp129
-rw-r--r--src/gui/ScrollablePage.cpp60
-rw-r--r--src/gui/StaticPage.cpp13
-rw-r--r--src/gui/Widget.cpp30
-rw-r--r--src/main.cpp30
18 files changed, 403 insertions, 23 deletions
diff --git a/TODO b/TODO
index 06cffbd..873bd99 100644
--- a/TODO
+++ b/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. \ No newline at end of file
+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. \ No newline at end of file
diff --git a/include/gui/RadioButton.hpp b/include/gui/RadioButton.hpp
new file mode 100644
index 0000000..d4b1103
--- /dev/null
+++ b/include/gui/RadioButton.hpp
@@ -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;
+ };
+} \ No newline at end of file
diff --git a/include/gui/ScrollablePage.hpp b/include/gui/ScrollablePage.hpp
index 2ad3c92..9d4623b 100644
--- a/include/gui/ScrollablePage.hpp
+++ b/include/gui/ScrollablePage.hpp
@@ -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;
};
} \ No newline at end of file
diff --git a/include/gui/StaticPage.hpp b/include/gui/StaticPage.hpp
index 8b64ba6..e73083c 100644
--- a/include/gui/StaticPage.hpp
+++ b/include/gui/StaticPage.hpp
@@ -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;
};
diff --git a/include/gui/Widget.hpp b/include/gui/Widget.hpp
index 6c4a1cb..7a04338 100644
--- a/include/gui/Widget.hpp
+++ b/include/gui/Widget.hpp
@@ -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;
};
} \ No newline at end of file
diff --git a/meson.build b/meson.build
index f856e97..691d0fb 100644
--- a/meson.build
+++ b/meson.build
@@ -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',
diff --git a/src/gui/Button.cpp b/src/gui/Button.cpp
index 1849737..d2c4a2c 100644
--- a/src/gui/Button.cpp
+++ b/src/gui/Button.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;
diff --git a/src/gui/CheckBox.cpp b/src/gui/CheckBox.cpp
index b337d5f..94e5f9e 100644
--- a/src/gui/CheckBox.cpp
+++ b/src/gui/CheckBox.cpp
@@ -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;
diff --git a/src/gui/ComboBox.cpp b/src/gui/ComboBox.cpp
index 9decab7..0b232f2 100644
--- a/src/gui/ComboBox.cpp
+++ b/src/gui/ComboBox.cpp
@@ -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;
diff --git a/src/gui/DropdownButton.cpp b/src/gui/DropdownButton.cpp
index 5cc9a3d..50a3105 100644
--- a/src/gui/DropdownButton.cpp
+++ b/src/gui/DropdownButton.cpp
@@ -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;
}
diff --git a/src/gui/Entry.cpp b/src/gui/Entry.cpp
index e853bc8..e74e41e 100644
--- a/src/gui/Entry.cpp
+++ b/src/gui/Entry.cpp
@@ -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 };
diff --git a/src/gui/Label.cpp b/src/gui/Label.cpp
index 08f720b..09fd1a6 100644
--- a/src/gui/Label.cpp
+++ b/src/gui/Label.cpp
@@ -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;
}
} \ No newline at end of file
diff --git a/src/gui/List.cpp b/src/gui/List.cpp
index e8c02e0..0c5f78e 100644
--- a/src/gui/List.cpp
+++ b/src/gui/List.cpp
@@ -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);
diff --git a/src/gui/RadioButton.cpp b/src/gui/RadioButton.cpp
new file mode 100644
index 0000000..e5ba02a
--- /dev/null
+++ b/src/gui/RadioButton.cpp
@@ -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;
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/src/gui/ScrollablePage.cpp b/src/gui/ScrollablePage.cpp
index 73b445e..2c1143a 100644
--- a/src/gui/ScrollablePage.cpp
+++ b/src/gui/ScrollablePage.cpp
@@ -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) {
- 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;
+ if(!visible)
+ return;
- mgl_scissor prev_scissor;
- mgl_window_get_scissor(window.internal_window(), &prev_scissor);
+ const int margin_top = margin_top_scale * get_theme().window_height;
+ const int margin_left = margin_left_scale * get_theme().window_height;
- 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);
+ const mgl::vec2f draw_pos = position + offset;
+ 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;
}
} \ No newline at end of file
diff --git a/src/gui/StaticPage.cpp b/src/gui/StaticPage.cpp
index a6d9b64..73adfa0 100644
--- a/src/gui/StaticPage.cpp
+++ b/src/gui/StaticPage.cpp
@@ -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;
+ }
} \ No newline at end of file
diff --git a/src/gui/Widget.cpp b/src/gui/Widget.cpp
index 4baeff1..8732bd7 100644
--- a/src/gui/Widget.cpp
+++ b/src/gui/Widget.cpp
@@ -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;
+ }
} \ No newline at end of file
diff --git a/src/main.cpp b/src/main.cpp
index f2281ec..3a6ffd6 100644
--- a/src/main.cpp
+++ b/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));