diff options
author | dec05eba <dec05eba@protonmail.com> | 2024-08-07 00:21:32 +0200 |
---|---|---|
committer | dec05eba <dec05eba@protonmail.com> | 2024-08-07 00:21:35 +0200 |
commit | a3e479d5b289166ff651fac4ff046656cf78cda0 (patch) | |
tree | 2ba345228acfe45acf9863bb122e163ed38db7db /src/gui | |
parent | b229b060add5f66bd5532698c4a790285095e98a (diff) |
Add radio button with simple/advanced view, add widget visibility
Diffstat (limited to 'src/gui')
-rw-r--r-- | src/gui/Button.cpp | 11 | ||||
-rw-r--r-- | src/gui/CheckBox.cpp | 11 | ||||
-rw-r--r-- | src/gui/ComboBox.cpp | 11 | ||||
-rw-r--r-- | src/gui/DropdownButton.cpp | 9 | ||||
-rw-r--r-- | src/gui/Entry.cpp | 9 | ||||
-rw-r--r-- | src/gui/Label.cpp | 6 | ||||
-rw-r--r-- | src/gui/List.cpp | 31 | ||||
-rw-r--r-- | src/gui/RadioButton.cpp | 129 | ||||
-rw-r--r-- | src/gui/ScrollablePage.cpp | 60 | ||||
-rw-r--r-- | src/gui/StaticPage.cpp | 13 | ||||
-rw-r--r-- | src/gui/Widget.cpp | 30 |
11 files changed, 302 insertions, 18 deletions
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 |