Fri, 29 Oct 2021 07:38:50 +0300
#337 Min/max window size
* SetInteriorWidth/Height
--- a/Source/Gorgon/UI/Dimension.h Thu Oct 28 06:53:24 2021 +0300 +++ b/Source/Gorgon/UI/Dimension.h Fri Oct 29 07:38:50 2021 +0300 @@ -311,17 +311,17 @@ } /// Converts the given value to dimension with percentage units - inline constexpr DualDimension Percentage(int one, int two) { + inline constexpr DualDimension Percent(int one, int two) { return {{one, Dimension::Percent}, {two, Dimension::Percent}}; } /// Converts the given one, given twoue to dimension with percentage units - inline constexpr DualDimension Percentage(double one, double two) { + inline constexpr DualDimension Percent(double one, double two) { return {{one, Dimension::Percent}, {two, Dimension::Percent}}; } /// Converts the given one, given twoue to dimension with percentage units - inline constexpr DualDimension Percentage(float one, float two) { + inline constexpr DualDimension Percent(float one, float two) { return {{one, Dimension::Percent}, {two, Dimension::Percent}}; }
--- a/Source/Gorgon/UI/LayerAdapter.cpp Thu Oct 28 06:53:24 2021 +0300 +++ b/Source/Gorgon/UI/LayerAdapter.cpp Fri Oct 29 07:38:50 2021 +0300 @@ -53,6 +53,7 @@ s = base->GetCalculatedSize(); } + interiorsize = size; base->Resize(Convert(size, s, GetUnitSize(), GetSpacing(), Widgets::Registry::Active().GetEmSize())); return true;
--- a/Source/Gorgon/UI/LayerAdapter.h Thu Oct 28 06:53:24 2021 +0300 +++ b/Source/Gorgon/UI/LayerAdapter.h Fri Oct 29 07:38:50 2021 +0300 @@ -31,7 +31,15 @@ } virtual bool ResizeInterior(const UI::UnitSize &size) override; - + + virtual bool SetInteriorWidth(const UI::UnitDimension &size) override { + return ResizeInterior({size, interiorsize.Height}); + } + + virtual bool SetInteriorHeight(const UI::UnitDimension &size) override { + return ResizeInterior({interiorsize.Width, size}); + } + virtual bool IsDisplayed () const override { return base->IsVisible(); } @@ -115,6 +123,7 @@ int spacing = 0; int unitsize = 0; bool issizesset = false; + UnitSize interiorsize; }; } }
--- a/Source/Gorgon/UI/Widget.h Thu Oct 28 06:53:24 2021 +0300 +++ b/Source/Gorgon/UI/Widget.h Fri Oct 29 07:38:50 2021 +0300 @@ -89,10 +89,10 @@ int GetCurrentHeight() const { return GetCurrentSize().Height; } /// Sets the width of the widget - void SetWidth(UnitDimension width) { Resize(width, GetHeight()); } + virtual void SetWidth(UnitDimension width) { Resize(width, GetHeight()); } /// Sets the height of the widget - void SetHeight(UnitDimension height) { Resize(GetWidth(), height); } + virtual void SetHeight(UnitDimension height) { Resize(GetWidth(), height); } /// Activates the widget. This might perform the action if the /// widget is a button, forward the focus if it is a label or
--- a/Source/Gorgon/UI/WidgetContainer.h Thu Oct 28 06:53:24 2021 +0300 +++ b/Source/Gorgon/UI/WidgetContainer.h Fri Oct 29 07:38:50 2021 +0300 @@ -291,7 +291,17 @@ /// If resize operation cannot set the size exactly to the /// requested size, this function returns false. virtual bool ResizeInterior(const UI::UnitSize &size) = 0; - + + /// Should resize the interior (usable) size of the container. + /// If resize operation cannot set the size exactly to the + /// requested size, this function returns false. + virtual bool SetInteriorWidth(const UnitDimension &size) = 0; + + /// Should resize the interior (usable) size of the container. + /// If resize operation cannot set the size exactly to the + /// requested size, this function returns false. + virtual bool SetInteriorHeight(const UnitDimension &size) = 0; + /// Check if tab switch is enabled. Tab switch allows user to change /// focus to the next widget using tab key. Default is enabled. virtual bool IsTabSwitchEnabled() const { return tabswitch; }
--- a/Source/Gorgon/UI/Window.cpp Thu Oct 28 06:53:24 2021 +0300 +++ b/Source/Gorgon/UI/Window.cpp Fri Oct 29 07:38:50 2021 +0300 @@ -302,6 +302,8 @@ bool Window::ResizeInterior(const UI::UnitSize &size) { + interiorsize = size; + const auto &mon = WindowManager::Monitor::FromLocation(GetLocation()); Geometry::Size s = {0, 0};
--- a/Source/Gorgon/UI/Window.h Thu Oct 28 06:53:24 2021 +0300 +++ b/Source/Gorgon/UI/Window.h Fri Oct 29 07:38:50 2021 +0300 @@ -162,12 +162,22 @@ virtual void Resize(const Geometry::Size &size) override { Gorgon::Window::Resize(size); + + interiorsize = Pixels(size); distributeparentboundschanged(); } virtual bool ResizeInterior(const UI::UnitSize &size) override; + virtual bool SetInteriorWidth(const UI::UnitDimension &size) override { + return ResizeInterior({size, interiorsize.Height}); + } + + virtual bool SetInteriorHeight(const UI::UnitDimension &size) override { + return ResizeInterior({interiorsize.Width, size}); + } + /// Closes the window, returning the execution to the /// point where Run function is called. It allows current /// frame to be completed before quiting. @@ -281,6 +291,8 @@ } } + UnitSize interiorsize; + private: bool quiting = false; LayerAdapter extenderadapter, windowadapter, baradapter, dialogadapter, underadapter;
--- a/Source/Gorgon/Widgets/Composer.cpp Thu Oct 28 06:53:24 2021 +0300 +++ b/Source/Gorgon/Widgets/Composer.cpp Fri Oct 29 07:38:50 2021 +0300 @@ -161,13 +161,24 @@ } void ComponentStackComposer::resize(const Geometry::Size &size) { - if(interiorsized) { - ComponentStackWidget::resize(size + GetCurrentSize() - GetInteriorSize()); + if(interiorsized.first || interiorsized.second) { + Geometry::Size border = {0, 0}; + + auto innersize = stack.TagBounds(UI::ComponentTemplate::ViewPortTag).GetSize(); + + border = GetCurrentSize() - innersize; + + if(!interiorsized.first) + border.Width = 0; + if(!interiorsized.second) + border.Height = 0; + + ComponentStackWidget::resize(size + border); } else { ComponentStackWidget::resize(size); } - + if(HasOrganizer()) GetOrganizer().Reorganize(); @@ -216,4 +227,39 @@ } } + bool ComponentStackComposer::ResizeInterior(const UI::UnitSize &size) { + if(interiorsized != std::make_pair(true, true)) + lsize = {-1, -1}; + interiorsized = {true, true}; + ComponentStackWidget::Resize(size); + + return stack.TagBounds(UI::ComponentTemplate::ViewPortTag).GetSize() == lsize; + } + + bool ComponentStackComposer::SetInteriorWidth(const UI::UnitDimension &size) { + if(interiorsized.first != true) + lsize = {-1, -1}; + interiorsized = {true, interiorsized.second}; + ComponentStackWidget::Resize(size, GetSize().Height); + + return stack.TagBounds(UI::ComponentTemplate::ViewPortTag).GetSize().Width == lsize.Width; + } + + bool ComponentStackComposer::SetInteriorHeight(const UI::UnitDimension &size) { + if(interiorsized.second != true) + lsize = {-1, -1}; + interiorsized = {interiorsized.first, true}; + ComponentStackWidget::Resize(GetSize().Width, size); + + return stack.TagBounds(UI::ComponentTemplate::ViewPortTag).GetSize().Height == lsize.Height; + } + + +void ComponentStackComposer::Resize(const UI::UnitSize& size, std::pair< bool, bool > interiorsized) { + if(this->interiorsized != interiorsized) + lsize = {-1, -1}; + this->interiorsized = interiorsized; + ComponentStackWidget::Resize(size); +} + } }
--- a/Source/Gorgon/Widgets/Composer.h Thu Oct 28 06:53:24 2021 +0300 +++ b/Source/Gorgon/Widgets/Composer.h Fri Oct 29 07:38:50 2021 +0300 @@ -47,6 +47,16 @@ return true; } + virtual bool SetInteriorWidth(const UI::UnitDimension &size) override { + SetWidth(size); + return true; + } + + virtual bool SetInteriorHeight(const UI::UnitDimension &size) override { + SetHeight(size); + return true; + } + virtual Geometry::Point GetCurrentLocation() const override { return base.GetLocation(); } @@ -220,13 +230,6 @@ return stack.GetSize(); } - virtual bool ResizeInterior(const UI::UnitSize &size) override { - interiorsized = true; - Resize(size); - - return GetInteriorSize() == lsize; - } - virtual void SetVisible(bool value) override { ComponentStackWidget::SetVisible(value); distributeparentboundschanged(); @@ -258,13 +261,15 @@ virtual bool CharacterPressed(Char c) override { return distributecharevent(c); } virtual void Resize(const UI::UnitSize &size) override { - interiorsized = false; - ComponentStackWidget::Resize(size); + Resize(size, {false, false}); } + void Resize(const UI::UnitSize &size, std::pair<bool, bool> interiorsized); + + protected: - bool interiorsized = false; + std::pair<bool, bool> interiorsized = {false, false}; //ensure this object is derived ComponentStackComposer(const UI::Template &temp, std::map<UI::ComponentTemplate::Tag, std::function<Widget *(const UI::Template &)>> generators = {}) : @@ -323,6 +328,14 @@ return true; } + + virtual bool ResizeInterior(const UI::UnitSize &size) override; + + virtual bool SetInteriorWidth(const UI::UnitDimension &size) override; + + virtual bool SetInteriorHeight(const UI::UnitDimension &size) override; + + virtual Geometry::Size GetInteriorSize() const override { return stack.GetLayerOf(stack.IndexOfTag(UI::ComponentTemplate::ContentsTag)).GetSize(); }
--- a/Source/Gorgon/Widgets/Panel.cpp Thu Oct 28 06:53:24 2021 +0300 +++ b/Source/Gorgon/Widgets/Panel.cpp Fri Oct 29 07:38:50 2021 +0300 @@ -107,20 +107,47 @@ } bool Panel::ResizeInterior(const UI::UnitSize &size) { - interiorsized = true; + if(interiorsized != std::make_pair(true, true)) + lsize = {-1, -1}; + + interiorsized = {true, true}; ComponentStackWidget::Resize(size); - return stack.TagBounds(UI::ComponentTemplate::ContentsTag).GetSize() == lsize; + return stack.TagBounds(UI::ComponentTemplate::ViewPortTag).GetSize() == lsize; + } + + bool Panel::SetInteriorWidth(const UI::UnitDimension &size) { + if(interiorsized.first != true) + lsize = {-1, -1}; + + interiorsized = {true, interiorsized.second}; + ComponentStackWidget::Resize({size, GetSize().Height}); + + return stack.TagBounds(UI::ComponentTemplate::ViewPortTag).GetSize().Width == lsize.Width; } - + + bool Panel::SetInteriorHeight(const UI::UnitDimension &size) { + if(interiorsized.second != true) + lsize = {-1, -1}; + + interiorsized = {interiorsized.first, true}; + ComponentStackWidget::Resize({GetSize().Width, size}); + + return stack.TagBounds(UI::ComponentTemplate::ViewPortTag).GetSize().Height == lsize.Height; + } + void Panel::resize(const Geometry::Size &size) { - if(interiorsized) { + if(interiorsized.first || interiorsized.second) { Geometry::Size border = {0, 0}; auto innersize = stack.TagBounds(UI::ComponentTemplate::ViewPortTag).GetSize(); - if(innersize.Area() != 0) - border = GetCurrentSize() - innersize; + border = GetCurrentSize() - innersize; + + if(!interiorsized.first) + border.Width = 0; + if(!interiorsized.second) + border.Height = 0; ComponentStackWidget::resize(size + border); } @@ -270,5 +297,13 @@ } } + +void Panel::Resize(const UI::UnitSize& size, std::pair< bool, bool > interiorsized) { + if(this->interiorsized != interiorsized) + lsize = {-1, -1}; + this->interiorsized = interiorsized; + ComponentStackWidget::Resize(size); +} + } }
--- a/Source/Gorgon/Widgets/Panel.h Thu Oct 28 06:53:24 2021 +0300 +++ b/Source/Gorgon/Widgets/Panel.h Fri Oct 29 07:38:50 2021 +0300 @@ -31,7 +31,6 @@ distributeparentboundschanged(); } - virtual bool KeyPressed(Input::Key, float) override; @@ -43,9 +42,16 @@ virtual Geometry::Size GetInteriorSize() const override; + UI::UnitSize GetCalculatedInteriorSize(UI::Dimension::Unit unit) { + return Convert(unit, UI::Pixels(GetInteriorSize())); + } virtual bool ResizeInterior(const UI::UnitSize &size) override; - + + virtual bool SetInteriorWidth(const UI::UnitDimension &size) override; + + virtual bool SetInteriorHeight(const UI::UnitDimension &size) override; + /// Controls whether scrolling will be enabled vertically or horizontally. /// It is possible to use ScrollTo function without enabling scrolling but /// the user will not be able to scroll in this case. Enabling scrolling @@ -64,6 +70,12 @@ return hscroll; } + /// Sets the width of the widget + virtual void SetWidth(UnitDimension width) override { Resize({width, GetHeight()}, {false, interiorsized.second}); } + + /// Sets the height of the widget + virtual void SetHeight(UnitDimension height) override { Resize({GetWidth(), height}, {interiorsized.first, false}); } + virtual bool Done() override { if(HasFocusedWidget()) @@ -198,10 +210,11 @@ using ComponentStackWidget::Resize; virtual void Resize(const UI::UnitSize &size) override { - interiorsized = false; - ComponentStackWidget::Resize(size); + Resize(size, {false, false}); } + void Resize(const UI::UnitSize &size, std::pair<bool, bool> interiorsized); + protected: virtual bool allowfocus() const override; @@ -224,10 +237,6 @@ virtual void moved() override { distributeparentboundschanged(); } - bool updaterequired = false; - - Input::KeyRepeater repeater; - FocusStrategy getparentfocusstrategy() const override { if(HasParent()) return GetParent().CurrentFocusStrategy(); @@ -243,16 +252,20 @@ else if(state && IsEnabled()) distributeparentenabled(state); } - - int spacing = 0; - int unitwidth = 0; - bool issizesset = false; virtual void resize(const Geometry::Size &size) override; virtual void move(const Geometry::Point &location) override; - bool interiorsized = false; + bool updaterequired = false; + + Input::KeyRepeater repeater; + + int spacing = 0; + int unitwidth = 0; + bool issizesset = false; + + std::pair<bool, bool> interiorsized = {false, false}; private:
--- a/Source/Gorgon/Widgets/TabPanel.h Thu Oct 28 06:53:24 2021 +0300 +++ b/Source/Gorgon/Widgets/TabPanel.h Fri Oct 29 07:38:50 2021 +0300 @@ -59,6 +59,8 @@ * a container, its members are. Each tab is associated with a key. * Creating another with the same key will erase the tab, removing its * contents. + * + * TODO: InteriorSizing */ template <class Key_> class basic_TabPanel : public ComponentStackComposer {
--- a/Source/Gorgon/Widgets/Window.cpp Thu Oct 28 06:53:24 2021 +0300 +++ b/Source/Gorgon/Widgets/Window.cpp Fri Oct 29 07:38:50 2021 +0300 @@ -46,8 +46,6 @@ Center(); } - - minsize = GetCurrentSize() - GetInteriorSize() + Geometry::Size(stack.GetTemplate().GetUnitSize()*2, stack.GetTemplate().GetUnitSize()); } Window::Window(const UI::Template &temp, const std::string &title, const UI::UnitSize size, bool autoplace) : @@ -149,17 +147,38 @@ void Window::updatescrollvisibility() { auto val = stack.GetTargetValue(); + bool changed = false; if(val[2] == 1 || val[2] == 0 || !hscroll) { - stack.RemoveCondition(UI::ComponentCondition::HScroll); + if(hscrollon) { + stack.RemoveCondition(UI::ComponentCondition::HScroll); + changed = true; + hscrollon = false; + } } else { - stack.AddCondition(UI::ComponentCondition::HScroll); + if(!hscrollon) { + stack.AddCondition(UI::ComponentCondition::HScroll); + changed = true; + hscrollon = true; + } } if(val[3] == 1 || val[3] == 0 || !vscroll) { - stack.RemoveCondition(UI::ComponentCondition::VScroll); + if(vscrollon) { + stack.RemoveCondition(UI::ComponentCondition::VScroll); + changed = true; + vscrollon = false; + } } else { - stack.AddCondition(UI::ComponentCondition::VScroll); + if(!vscrollon) { + stack.AddCondition(UI::ComponentCondition::VScroll); + changed = true; + vscrollon = true; + } + } + + if(changed) { + Panel::resize(lsize); } } @@ -231,6 +250,7 @@ if(button == Input::Mouse::Button::Left) { moving = false; resizing = none; + pointertoken.Revert(); } } @@ -374,7 +394,8 @@ int h = ch + location.Y - dragoffset.Y; if(HasParent()) { - FitInto(h, minsize.Height, std::min((GetParent().GetInteriorSize().Height - GetCurrentLocation().Y) * 2, GetParent().GetInteriorSize().Height)); + FitInto(h, minsizepx.Height, std::min((GetParent().GetInteriorSize().Height - GetCurrentLocation().Y) * 2, maxsizepx.Height)); + std::cout << h << std::endl; } SetHeight(Pixels(h)); @@ -388,7 +409,7 @@ int h = ch - location.Y + dragoffset.Y; if(HasParent()) { - FitInto(h, minsize.Height, GetCurrentHeight()+GetCurrentLocation().Y); + FitInto(h, minsizepx.Height, std::min(GetCurrentHeight()+GetCurrentLocation().Y, maxsizepx.Height)); } SetHeight(Pixels(h)); @@ -410,7 +431,7 @@ int w = cw + location.X - dragoffset.X; if(HasParent()) { - FitInto(w, minsize.Width, std::min((GetParent().GetInteriorSize().Width - GetCurrentLocation().X) * 2, GetParent().GetInteriorSize().Width)); + FitInto(w, minsizepx.Width, std::min((GetParent().GetInteriorSize().Width - GetCurrentLocation().X) * 2, maxsizepx.Width)); } SetWidth(Pixels(w)); @@ -425,7 +446,7 @@ int w = cw - location.X + dragoffset.X; if(HasParent()) { - FitInto(w, minsize.Width, GetCurrentWidth()+GetCurrentLocation().X); + FitInto(w, minsizepx.Width, std::min(GetCurrentWidth()+GetCurrentLocation().X, maxsizepx.Width)); } SetWidth(Pixels(w)); @@ -528,6 +549,63 @@ return true; } + void Window::resize(const Geometry::Size& size) { + Panel::resize(size); + + //prevent recursion if there is a problem with min-max sizing + if(!updatingminmax) { + updatingminmax = true; + minsizepx = Convert(minsize); + maxsizepx = Convert(maxsize); + auto sz = GetInteriorSize(); + + if(sz.Width < minsizepx.Width && sz.Height < minsizepx.Height) { + ResizeInterior(minsize); + } + else if(sz.Width < minsizepx.Width) { + SetInteriorWidth(minsize.Width); + } + else if(sz.Height < minsizepx.Height) { + SetInteriorHeight(minsize.Height); + } + + sz = GetCurrentSize(); + if(sz.Width > maxsizepx.Width && sz.Height > maxsizepx.Height) { + Resize(maxsize); + } + else if(sz.Width > maxsizepx.Width) { + SetWidth(maxsize.Width); + } + else if(sz.Height > maxsizepx.Height) { + SetHeight(maxsize.Height); + } + + Geometry::Size border = {0, 0}; + + auto innersize = stack.TagBounds(UI::ComponentTemplate::ViewPortTag).GetSize(); + + border = GetCurrentSize() - innersize; + + minsizepx += border; + updatingminmax = false; + } + } + + void Window::SetMinSize(const UI::UnitSize& value) { + minsize = value; + + lsize = {-1, -1}; //force update + Resize(GetSize(), interiorsized); + } + + + void Window::SetMaxSize(const UI::UnitSize& value) { + maxsize = value; + + lsize = {-1, -1}; //force update + Resize(GetSize(), interiorsized); + } + } }
--- a/Source/Gorgon/Widgets/Window.h Thu Oct 28 06:53:24 2021 +0300 +++ b/Source/Gorgon/Widgets/Window.h Fri Oct 29 07:38:50 2021 +0300 @@ -197,6 +197,22 @@ void Center(); virtual void EnableScroll(bool vertical, bool horizontal) override; + + /// Sets minimum internal size of the widget, default value is 2x1 units. + void SetMinSize(const UI::UnitSize &value); + + /// Returns minimum internal size of the widget + UI::UnitSize GetMinSize() const { + return minsize; + } + + /// Sets maximum external size of the widget, default value is 100%, 100% + void SetMaxSize(const UI::UnitSize &value); + + /// Sets maximum external size of the widget + UI::UnitSize GetMaxSize() const { + return maxsize; + } /// Window title TextualProperty<Window, std::string, &Window::GetTitle, &Window::SetTitle> Title; @@ -239,6 +255,8 @@ void mouse_click(UI::ComponentTemplate::Tag tag, Geometry::Point location, Input::Mouse::Button button); + void resize(const Geometry::Size &size) override; + private: enum resizedir { none, @@ -264,8 +282,11 @@ Geometry::Point dragoffset; resizedir resizing = none; bool allowresize = false; - Geometry::Size minsize; + Geometry::Size minsizepx, maxsizepx; + UI::UnitSize minsize = UI::Units(2, 1), maxsize = UI::Percent(100, 100); Graphics::PointerStack::Token pointertoken; + bool hscrollon = false, vscrollon = true; + bool updatingminmax = false; }; } }
--- a/Testing/Source/Manual/UI_Generate.cpp Thu Oct 28 06:53:24 2021 +0300 +++ b/Testing/Source/Manual/UI_Generate.cpp Fri Oct 29 07:38:50 2021 +0300 @@ -320,6 +320,8 @@ Widgets::DialogWindow wind("My window", {6, 6}); wind.Add(btn); wind.Add(btn2); + wind.SetMinSize({6,1}); + wind.SetMaxSize({50_perc,8}); btn.Move(Pixels(0,0)); btn.Disable(); wind.OwnIcon(icon.CreateAnimation()); @@ -331,7 +333,7 @@ }); Widgets::Checkbox enableclosebtn("Enable close button", true); enableclosebtn.SetWidth(6_u); - enableclosebtn.SetAutosize(Gorgon::UI::Autosize::Unit, Gorgon::UI::Autosize::Automatic); + //enableclosebtn.SetAutosize(Gorgon::UI::Autosize::Unit, Gorgon::UI::Autosize::Automatic); enableclosebtn.ChangedEvent.Register([&] { wind.SetCloseButtonEnabled(bool(enableclosebtn)); }); wind.AddUnder(enableclosebtn); wind.AddUnder("Try resize");