#337 Templates now use Dimension for their sizes 4.x-dev

Fri, 29 Oct 2021 14:08:50 +0300

author
cemkalyoncu
date
Fri, 29 Oct 2021 14:08:50 +0300
branch
4.x-dev
changeset 1748
f965ac36d227
parent 1747
2f9ad833617f
child 1749
f66c1dbd5e5e

#337 Templates now use Dimension for their sizes

Source/Gorgon/UI/ComponentStack.cpp file | annotate | diff | comparison | revisions
Source/Gorgon/UI/ComponentStack.h file | annotate | diff | comparison | revisions
Source/Gorgon/UI/ComponentStackWidget.h file | annotate | diff | comparison | revisions
Source/Gorgon/UI/Template.h file | annotate | diff | comparison | revisions
Source/Gorgon/Widgets/Dropdown.h file | annotate | diff | comparison | revisions
Source/Gorgon/Widgets/Generator.cpp file | annotate | diff | comparison | revisions
Source/Gorgon/Widgets/Listbox.h file | annotate | diff | comparison | revisions
Source/Gorgon/Widgets/RadioButtons.h file | annotate | diff | comparison | revisions
Testing/Source/Manual/UI_Generate.cpp file | annotate | diff | comparison | revisions
--- a/Source/Gorgon/UI/ComponentStack.cpp	Fri Oct 29 07:38:50 2021 +0300
+++ b/Source/Gorgon/UI/ComponentStack.cpp	Fri Oct 29 14:08:50 2021 +0300
@@ -2926,7 +2926,7 @@
                     else if(widgets.Exists(&temp)) {
                         //use default size of the template. Once widget autosizing
                         //is complete this should be updated
-                        comp.size = ph.GetTemplate().GetSize();
+                        comp.size = ph.GetTemplate().GetSize(this->size);
                     }
                     else {
                         //nothing found, reset to zero
--- a/Source/Gorgon/UI/ComponentStack.h	Fri Oct 29 07:38:50 2021 +0300
+++ b/Source/Gorgon/UI/ComponentStack.h	Fri Oct 29 14:08:50 2021 +0300
@@ -63,9 +63,9 @@
         ComponentStack(const Template &temp, Geometry::Size size, std::map<ComponentTemplate::Tag, std::function<Widget *(const Template &)>> generators = {});
         
         /// Initiates a component stack with default size
-        explicit ComponentStack(const Template &temp) : ComponentStack(temp, temp.GetSize()) 
+        explicit ComponentStack(const Template &temp) : ComponentStack(temp, temp.GetSize({0,0}))
         { }
-        
+
         /// Destructor
         virtual ~ComponentStack();
 
--- a/Source/Gorgon/UI/ComponentStackWidget.h	Fri Oct 29 07:38:50 2021 +0300
+++ b/Source/Gorgon/UI/ComponentStackWidget.h	Fri Oct 29 14:08:50 2021 +0300
@@ -14,8 +14,8 @@
     class ComponentStackWidget : public Widget {
     public:
         ComponentStackWidget(const Template &temp, std::map<ComponentTemplate::Tag, std::function<Widget *(const Template &)>> generators = {}) :
-            Widget(Pixels(temp.GetSize())),
-            stack(*new ComponentStack(temp, temp.GetSize(), generators))
+            Widget(temp.GetSize()),
+            stack(*new ComponentStack(temp, temp.GetSize({0, 0}), generators))
         {
             stack.SetCeilToUnitSize([this](int s) {
                 int w;
--- a/Source/Gorgon/UI/Template.h	Fri Oct 29 07:38:50 2021 +0300
+++ b/Source/Gorgon/UI/Template.h	Fri Oct 29 14:08:50 2021 +0300
@@ -516,34 +516,39 @@
         }
 
         /// Changes the size of the template
-        void SetSize(int w, int h) {
+        void SetSize(const UnitDimension &w, const UnitDimension &h) {
             size = {w, h};
             ChangedEvent();
         }
 
         /// Changes the size of the template
-        void SetSize(Geometry::Size value) {
+        void SetSize(const UnitSize &value) {
             size = value;
             ChangedEvent();
         }
 
         /// Returns the size of the template
-        Geometry::Size GetSize() const {
+        UnitSize GetSize() const {
             return size;
         }
 
+        /// Returns the size of the template in Pixels
+        Geometry::Size GetSize(const Geometry::Size &parentsize) const {
+            return Convert(size, parentsize, GetUnitSize(), GetSpacing());
+        }
+
         /// Returns the size of the template
-        int GetWidth() const {
+        UnitDimension GetWidth() const {
             return size.Width;
         }
 
         /// Returns the size of the template
-        int GetHeight() const {
+        UnitDimension GetHeight() const {
             return size.Height;
         }
 
         /// Changes the additional size of the template. This value should only be set and
-        /// used if the size mode is multiple
+        /// used if the size mode is multiple. This value is in pixels
         void SetAdditionalSize(int w, int h) {
             additional = {w, h};
             ChangedEvent();
@@ -659,7 +664,8 @@
 
         /// This event is fired whenever template or its components are changed.
         Event<Template> ChangedEvent = Event<Template>{*this};
-        
+
+        /// This is mainly for debugging
         std::string Name;
         
     private:
@@ -668,7 +674,7 @@
         std::map<std::pair<ComponentCondition, ComponentCondition>, int> durations;
 
         SizeMode xsizing = Free, ysizing = Free;
-        Geometry::Size size;
+        UnitSize size;
         Geometry::Size additional = {0, 0};
         int spacing = 4;
         int unitsize = 25;
--- a/Source/Gorgon/Widgets/Dropdown.h	Fri Oct 29 07:38:50 2021 +0300
+++ b/Source/Gorgon/Widgets/Dropdown.h	Fri Oct 29 14:08:50 2021 +0300
@@ -105,9 +105,9 @@
             reversed  = false;
             
             if(below < defaultheight && above > below) {
-                bool fit = list.FitHeight(below);
+                bool fit = list.FitHeight(Pixels(below));
                 if(!fit) {
-                    fit = list.FitHeight(above);
+                    fit = list.FitHeight(Pixels(above));
                     if(!fit)
                         list.SetHeight(Pixels(above));
                     
@@ -115,7 +115,7 @@
                 }
             }
             else {
-                list.FitHeight(std::min(defaultheight, below));
+                list.FitHeight(Pixels(std::min(defaultheight, below)));
             }
             
             if(reversed) {
--- a/Source/Gorgon/Widgets/Generator.cpp	Fri Oct 29 07:38:50 2021 +0300
+++ b/Source/Gorgon/Widgets/Generator.cpp	Fri Oct 29 14:08:50 2021 +0300
@@ -41,6 +41,11 @@
 #define BdC(c) Colors[Graphics::Color::c].Bordercolor
 
 namespace Gorgon { namespace Widgets {
+    using UI::UnitSize;
+    using UI::UnitDimension;
+    using UI::Units;
+    using UI::Pixels;
+
     //for std::map
     bool operator <(const SimpleGenerator::AssetID &l, const SimpleGenerator::AssetID &r) {
         return MultiLess(
@@ -998,7 +1003,7 @@
     }
     
     UI::Template SimpleGenerator::Button(bool border) {
-        Geometry::Size defsize = {GetUnitSize(3), border ? unitsize : borderlessheight};
+        UnitSize defsize = {Units(3), border ? Units(1): Pixels(borderlessheight)};
         
         UI::Template temp = maketemplate();
         temp.SetSize(defsize);
@@ -1096,7 +1101,7 @@
         UI::Template temp = maketemplate();
         temp.SetSpacing(spacing);
         
-        temp.SetSize(GetUnitSize(), GetUnitSize());
+        temp.SetSize(Units(1, 1));
         
         temp.AddContainer(0, UI::ComponentCondition::Always)
             .AddIndex(1) //background
@@ -1181,7 +1186,7 @@
     }
     
     UI::Template SimpleGenerator::DialogButton() {
-        Geometry::Size defsize = {GetUnitSize(3), unitsize};
+        UnitSize defsize = Units(3, 1);
         
         UI::Template temp = maketemplate();
         temp.SetSize(defsize);
@@ -1281,7 +1286,7 @@
     }
 
     UI::Template SimpleGenerator::Checkbox() {
-        Geometry::Size defsize = {GetUnitSize(6), borderlessheight};
+        UnitSize defsize = {Units(1), Pixels(borderlessheight)};
         
         UI::Template temp = maketemplate();
         temp.SetSpacing(spacing);
@@ -1346,7 +1351,7 @@
         
         UI::Template temp = maketemplate();
         temp.SetSpacing(spacing);
-        temp.SetSize(unitsize, unitsize);
+        temp.SetSize(Units(1, 1));
         
 
         temp.AddContainer(0, UI::ComponentCondition::Always)
@@ -1462,7 +1467,7 @@
     }
 
     UI::Template SimpleGenerator::RadioButton() {
-        Geometry::Size defsize = {GetUnitSize(6), borderlessheight};
+        UnitSize defsize = {Units(6), Pixels(borderlessheight)};
         
         UI::Template temp = maketemplate();
         temp.SetSpacing(spacing);
@@ -1527,7 +1532,7 @@
     
     //TODO: join labels into two or three functions
     UI::Template SimpleGenerator::Label() {
-        Geometry::Size defsize = {GetUnitSize(6), borderlessheight};
+        UnitSize defsize = {Units(6), Pixels(borderlessheight)};
         
         UI::Template temp = maketemplate();
         temp.SetSpacing(spacing);
@@ -1562,7 +1567,7 @@
     }
 
     UI::Template SimpleGenerator::ErrorLabel() {
-        Geometry::Size defsize = {GetUnitSize(6), borderlessheight};
+        UnitSize defsize = {Units(6), Pixels(borderlessheight)};
         
         UI::Template temp = maketemplate();
         temp.SetSpacing(spacing);
@@ -1599,7 +1604,7 @@
     }
     
     UI::Template SimpleGenerator::BoldLabel() {
-        Geometry::Size defsize = {GetUnitSize(6), borderlessheight};
+        UnitSize defsize = {Units(6), Pixels(borderlessheight)};
         
         UI::Template temp = maketemplate();
         temp.SetSpacing(spacing);
@@ -1634,7 +1639,7 @@
     }
 
     UI::Template SimpleGenerator::TitleLabel() {
-        Geometry::Size defsize = {GetUnitSize(6), borderlessheight + h1renderer->GetHeight() - regularrenderer->GetHeight()};
+        UnitSize defsize = {GetUnitSize(6), Pixels(borderlessheight + h1renderer->GetHeight() - regularrenderer->GetHeight())};
         
         UI::Template temp = maketemplate();
         temp.SetSpacing(spacing);
@@ -1677,7 +1682,7 @@
     }
 
     UI::Template SimpleGenerator::SubtitleLabel() {
-        Geometry::Size defsize = {GetUnitSize(6), borderlessheight + h3renderer->GetHeight() - regularrenderer->GetHeight()};
+        UnitSize defsize = {GetUnitSize(6), Pixels(borderlessheight + h3renderer->GetHeight() - regularrenderer->GetHeight())};
         
         UI::Template temp = maketemplate();
         temp.SetSpacing(spacing);
@@ -1721,7 +1726,7 @@
     }
 
     UI::Template SimpleGenerator::LeadingLabel() {
-        Geometry::Size defsize = {GetUnitSize(6), borderlessheight + bold.GetHeight() - regularrenderer->GetHeight()};
+        UnitSize defsize = {GetUnitSize(6), Pixels(borderlessheight + bold.GetHeight() - regularrenderer->GetHeight())};
         
         UI::Template temp = maketemplate();
         temp.SetSpacing(spacing);
@@ -1765,7 +1770,7 @@
     }
 
     UI::Template SimpleGenerator::InfoLabel() {
-        Geometry::Size defsize = {GetUnitSize(6), unitsize};
+        UnitSize defsize = {Units(6), Units(1)};
         
         UI::Template temp = maketemplate();
         temp.SetSpacing(spacing);
@@ -1814,7 +1819,7 @@
     }
 
     UI::Template SimpleGenerator::IconLabel() {
-        Geometry::Size defsize = {GetUnitSize(1), GetUnitSize(1)};
+        UnitSize defsize = Units(1, 1);
         
         UI::Template temp = maketemplate();
         temp.SetSpacing(spacing);
@@ -1856,10 +1861,10 @@
     }
 
     UI::Template SimpleGenerator::makepanel(SimpleGenerator::AssetID::BorderSide edge, bool scrollers, bool spaced, bool nobg) {
-        Geometry::Size defsize = {
+        UnitSize defsize = Pixels(
             GetUnitSize(6) + Border.Width * 2 * spaced + spacing * 2,
             GetUnitSize(10) + Border.Width * 2 * spaced + spacing * 2
-        };
+        );
         
         if(AssetID::VBorders(edge) == 1) {
             defsize.Height = unitsize + Border.Width + spacing * 2;
@@ -1919,7 +1924,7 @@
             auto &vst = operator[](Scrollbar_Vertical);
             auto &hst = operator[](Scrollbar_Horizontal);
             
-            temp.SetSize(temp.GetWidth() + vst.GetWidth() + spacing, temp.GetHeight());
+            temp.SetSize(Pixels(temp.GetSize({0, 0}).Width + vst.GetSize({0, 0}).Width + spacing), temp.GetHeight());
             
             bg
                 .AddIndex(3) //VScroll
@@ -1941,7 +1946,7 @@
             hs.SetSize({100, UI::Dimension::Percent}, hst.GetHeight());
             hs.SetSizing(UI::ComponentTemplate::Fixed);
             hs.SetAnchor(UI::Anchor::None, UI::Anchor::BottomCenter, UI::Anchor::BottomCenter);
-            hs.SetMargin(0, spacing, vst.GetWidth()+spacing, 0);
+            hs.SetMargin(0, spacing, vst.GetSize({0,0}).Width+spacing, 0);
             
             auto &vp = temp.AddContainer(1, UI::ComponentCondition::HScroll)
                 .AddIndex(2)
@@ -1950,7 +1955,7 @@
             vp.SetSize(100, 100, UI::Dimension::Percent);
             vp.SetAnchor(UI::Anchor::TopLeft, UI::Anchor::TopLeft, UI::Anchor::TopLeft);
             vp.SetClip(true);
-            vp.SetIndent(0, 0, 0, hst.GetHeight()+spacing);
+            vp.SetIndent(0, 0, 0, hst.GetSize({0,0}).Height+spacing);
         }
         
         return temp;
@@ -1985,7 +1990,7 @@
     }
     
     UI::Template SimpleGenerator::Inputbox() {
-        Geometry::Size defsize = {GetUnitSize(3), unitsize};
+        UnitSize defsize = Units(3, 1);
         
         UI::Template temp = maketemplate();
         temp.SetSpacing(spacing);
@@ -2084,7 +2089,7 @@
 
     UI::Template SimpleGenerator::Progressbar() {
         int h = std::max(Border.Radius * 2 + Border.Width * 2 + 4, spacing * 3);
-        Geometry::Size defsize = {GetUnitSize(6), h};
+        UnitSize defsize = {Units(6), Pixels(h)};
         
         UI::Template temp = maketemplate();
         temp.SetSpacing(spacing);
@@ -2117,7 +2122,7 @@
     }
     
     UI::Template SimpleGenerator::BlankLayerbox() {
-        Geometry::Size defsize = {GetUnitSize(6), GetUnitSize(4)};
+        UnitSize defsize = Units(6, 4);
         
         UI::Template temp = maketemplate();
         temp.SetSize(defsize);
@@ -2139,7 +2144,7 @@
     }
     
     UI::Template SimpleGenerator::Layerbox() {
-        Geometry::Size defsize = {GetUnitSize(6), GetUnitSize(4)};
+        UnitSize defsize = Units(6, 4);
         
         UI::Template temp = maketemplate();
         temp.SetSize(defsize);
@@ -2167,7 +2172,7 @@
         auto dist = int(std::round(spacing / 3.f));
         int w = std::max(Border.Radius * 2 + std::max(0, dist - Border.Radius / 2) * 2, spacing * 2);
         
-        Geometry::Size defsize = {w, unitsize * 3 - Border.Width * 2};
+        UnitSize defsize = {Pixels(w), Units(3)};
         
         UI::Template temp = maketemplate();
         temp.SetSize(defsize);
@@ -2205,7 +2210,7 @@
         auto dist = int(std::round(spacing / 3.f));
         int h = std::max(Border.Radius * 2 + std::max(0, dist - Border.Radius / 2) * 2, spacing * 2);
         
-        Geometry::Size defsize = {GetUnitSize(6), h};
+        UnitSize defsize = {Units(6), Pixels(h)};
         
         UI::Template temp = maketemplate();
         temp.SetSize(defsize);
@@ -2239,7 +2244,7 @@
     }
     
     UI::Template SimpleGenerator::Listbox() {
-        Geometry::Size defsize = {GetUnitSize(6), GetUnitSize(8)};
+        UnitSize defsize = Units(6, 8);
         
         UI::Template temp = maketemplate();
         
@@ -2260,7 +2265,7 @@
         auto &viewport = temp.AddContainer(1, UI::ComponentCondition::Always)
             .AddIndex(2)
         ;
-        viewport.SetTag(UI::ComponentTemplate::ContentsTag);
+        viewport.SetTag(UI::ComponentTemplate::ViewPortTag);
         viewport.SetClip(true);
         
         auto &contents = temp.AddContainer(2, UI::ComponentCondition::Always);
@@ -2291,7 +2296,7 @@
         //****** listitem
         
         //TODO fix height
-        listbox_listitem.SetSize(defsize.Width - (Border.Width + std::max(Border.Radius / 2, Focus.Spacing)) * 2, borderlessheight);
+        listbox_listitem.SetSize(Pixels(defsize.Width(0, GetUnitSize(), GetSpacing()) - (Border.Width + std::max(Border.Radius / 2, Focus.Spacing)) * 2, borderlessheight));
         
         listbox_listitem.AddContainer(0, UI::ComponentCondition::Always)
             .AddIndex(1) //background
@@ -2392,7 +2397,7 @@
     }
     
     UI::Template SimpleGenerator::Dropdown() {
-        Geometry::Size defsize = {GetUnitSize(4), GetUnitSize()};
+        UnitSize defsize = Units(4, 1);
         
         UI::Template temp = maketemplate();
         temp.SetSize(defsize);
@@ -2483,7 +2488,7 @@
     
     UI::Template SimpleGenerator::Window() {
         auto tmp = makepanel(AssetID::All, true, false);
-        tmp.SetSize({GetUnitSize(9), GetUnitSize(10)});
+        tmp.SetSize(Units(10, 8));
         
         auto &cbg = dynamic_cast<UI::ContainerTemplate&>(tmp[0]);
         cbg.Background.SetAnimation(A(Background, Container));
@@ -2583,7 +2588,7 @@
     
     UI::Template SimpleGenerator::DialogWindow() {
         auto temp = Window();
-        temp.SetSize({GetUnitSize(10) + Border.Width*2 + spacing*2, GetUnitSize(5)});
+        temp.SetSize(Pixels(GetUnitSize(10) + Border.Width*2 + spacing*2, GetUnitSize(5)));
         
         auto &cbg = dynamic_cast<UI::ContainerTemplate&>(temp[0]);
         //auto tmp = makepanel(AssetID::AllExceptBottom, true);
@@ -2627,13 +2632,13 @@
         auto temp = Layerbox();
         auto w = GetUnitSize(6);
         auto h = (w-26)/12*9 + 22;
-        temp.SetSize(w, h);
+        temp.SetSize(Pixels(w, h));
         
         return temp;
     }
     
     UI::Template SimpleGenerator::ColorPicker() {
-        Geometry::Size defsize = {GetUnitSize(4), GetUnitSize()};
+        UnitSize defsize = Units(4, 1);
         
         UI::Template temp = maketemplate();
         temp.SetSpacing(spacing);
@@ -2766,10 +2771,10 @@
     }
 
     UI::Template SimpleGenerator::TabPanel() {
-        Geometry::Size defsize = {
-            GetUnitSize(6) + Border.Width * 2  + spacing * 3 + (*this)[Scrollbar_Vertical].GetSize().Width,
+        UnitSize defsize = Pixels(
+            GetUnitSize(6) + Border.Width * 2  + spacing * 3 + (*this)[Scrollbar_Vertical].GetSize().Width(GetUnitSize(6), GetUnitSize(), GetSpacing(), GetEmSize()),
             GetUnitSize(10) + Border.Width * 2 + spacing * 2
-        };
+        );
 
         UI::Template temp = maketemplate();
         temp.SetSize(defsize);
@@ -2827,7 +2832,7 @@
     }
 
     UI::Template SimpleGenerator::Textarea() {
-        Geometry::Size defsize = {GetUnitSize(6), GetUnitSize(3)};
+        UnitSize defsize = Units(6, 3);
 
         UI::Template temp = maketemplate();
         temp.SetSpacing(spacing);
@@ -2921,7 +2926,7 @@
         auto &vst = operator[](Scrollbar_Vertical);
         auto &hst = operator[](Scrollbar_Horizontal);
 
-        temp.SetSize(temp.GetWidth() + vst.GetWidth() + spacing, temp.GetHeight());
+        temp.SetSize(Pixels(GetUnitSize(6) + vst.GetSize({0, 0}).Width + spacing), temp.GetHeight());
 
         boxed
             .AddIndex(9) //VScroll
@@ -2943,7 +2948,7 @@
         hs.SetSize({100, UI::Dimension::Percent}, hst.GetHeight());
         hs.SetSizing(UI::ComponentTemplate::Fixed);
         hs.SetAnchor(UI::Anchor::None, UI::Anchor::BottomCenter, UI::Anchor::BottomCenter);
-        hs.SetMargin(0, spacing, vst.GetWidth()+spacing, 0);
+        hs.SetMargin(0, spacing, vst.GetSize({0,0}).Width+spacing, 0);
 
 
         auto &contenthscroll = temp.AddContainer(5, UI::ComponentCondition::HScroll)
@@ -2955,7 +2960,7 @@
         contenthscroll.SetPositioning(UI::ComponentTemplate::Absolute);
         contenthscroll.SetAnchor(UI::Anchor::TopLeft, UI::Anchor::TopLeft, UI::Anchor::TopLeft);
         contenthscroll.SetTag(UI::ComponentTemplate::ViewPortTag);
-        contenthscroll.SetIndent(0, 0, 0, hst.GetHeight()+spacing);
+        contenthscroll.SetIndent(0, 0, 0, hst.GetSize({0,0}).Height+spacing);
 
 
         return temp;
--- a/Source/Gorgon/Widgets/Listbox.h	Fri Oct 29 07:38:50 2021 +0300
+++ b/Source/Gorgon/Widgets/Listbox.h	Fri Oct 29 14:08:50 2021 +0300
@@ -1803,62 +1803,6 @@
             return maxdisplay;
         }
         
-        /// This function will try to set the height of the listbox to contain
-        /// all its elements. If the size necessary to do so is larger than
-        /// maxpixels, then maxpixels will be used and this function will return
-        /// false. This function may give up before fully exceeding maxpixels if
-        /// elements have different heights. But it will never surpass maxpixels.
-        bool FitHeight(int maxpixels) {
-            int curh = GetInteriorSize().Height;
-            int overhead = GetCurrentHeight() - curh;
-            int defh = stack.GetTemplate().GetUnitSize();
-            
-            auto li = stack.GetTemplate(UI::ComponentTemplate::ItemTag);
-            if(li)
-                defh = li->GetHeight();
-            
-            int expected = int( std::ceil( (this->GetCount()+overscroll) * (maxdisplay == 0 ? defh : curh/maxdisplay) ) ) + overhead;
-            bool smalldone = false;
-            
-            //will possibly fit
-            if(expected < maxpixels) {
-                
-                int tried = 0;
-                
-                do {
-                    SetHeight(Pixels(expected));
-                    stack.Update(true);
-                    Refresh();
-                    
-                    auto diff = maxdisplay - (this->GetCount()+overscroll);
-                    
-                    //it fits everything, might not be tightest but that's ok. We can also eat up a bit of overscroll
-                    if((diff < 1 && diff >= -overscroll/2) || maxdisplay == 0)
-                        return true;
-                    
-                    curh = GetInteriorSize().Height;
-                    overhead = GetCurrentHeight() - curh;
-                    int curexpected = int( std::ceil( (this->GetCount()+overscroll) * (curh/maxdisplay) ) ) + overhead;
-                    
-                    if(abs(expected - curexpected) == 0) { //no progress, exit
-                        break;
-                    }
-                    else if(abs(expected - curexpected) < 0.1 && smalldone) { //we will allow one small progress, no more
-                        break;
-                    }
-                    else if(abs(expected - curexpected) < 0.1) {
-                        smalldone = true;
-                    }
-                    expected = curexpected;
-                    tried++;
-                } while(expected < maxpixels && tried < 5);
-                
-            }
-            
-            SetHeight(Pixels(maxpixels));
-            return false;
-        }
-        
         Geometry::Size GetInteriorSize() const {
             auto b = stack.TagBounds(UI::ComponentTemplate::ViewPortTag);
             if(b.Width() == 0 || b.Height() == 0)
@@ -1918,7 +1862,37 @@
 
             return false;
         }
-        
+
+        /// This function will try to set the height of the listbox to contain
+        /// all its elements. If the size necessary to do so is larger than
+        /// maxsize, then maxsize will be used and this function will return
+        /// false. This function may give up before fully exceeding maxsize if
+        /// elements have different heights. But it will never surpass maxsize.
+        bool FitHeight(const UI::UnitDimension &maxsize) {
+            return fitheight(Convert(maxsize, true, true));
+        }
+
+        /// This function will try to set the height of the listbox to contain
+        /// all its elements. If the size necessary to do so is larger than
+        /// maxsize, then maxsize will be used and this function will return
+        /// false. This function may give up before fully exceeding maxsize if
+        /// elements have different heights. But it will never surpass maxsize.
+        bool FitHeight(float elms) {
+            if(widgetlist.empty())
+                return fitheight(Convert(Units(elms), true, true));
+            else {
+                int sp = stack.GetTemplate().GetSpacing() / 2;
+                int border = 0;
+
+                auto innersize = stack.TagBounds(UI::ComponentTemplate::ViewPortTag).GetSize();
+                border = GetCurrentSize().Height - innersize.Height;
+                if(border < 0)
+                    border = 0;
+
+                return fitheight((int)std::round((widgetlist.begin()->second->GetCurrentHeight() + sp)*elms - sp + border));
+            }
+        }
+
     protected:
         ListboxWidgetBase(const UI::Template &temp) : 
             ComponentStackWidget(temp, { 
@@ -1990,9 +1964,60 @@
                     EnsureVisible(ind);
                 }
 
-            });            
+            });
         }
         
+        bool fitheight(int maxpixels) {
+            int curh = GetInteriorSize().Height;
+            int overhead = GetCurrentHeight() - curh;
+            int defh = stack.GetTemplate().GetUnitSize();
+
+            auto li = stack.GetTemplate(UI::ComponentTemplate::ItemTag);
+            if(li)
+                defh = li->GetSize(GetCurrentSize()).Height;
+
+            int expected = int( std::ceil( (this->GetCount()+overscroll) * (maxdisplay == 0 ? defh : curh/maxdisplay) ) ) + overhead;
+            bool smalldone = false;
+
+            //will possibly fit
+            if(expected < maxpixels) {
+
+                int tried = 0;
+
+                do {
+                    SetHeight(Pixels(expected));
+                    stack.Update(true);
+                    Refresh();
+
+                    auto diff = maxdisplay - (this->GetCount()+overscroll);
+
+                    //it fits everything, might not be tightest but that's ok. We can also eat up a bit of overscroll
+                    if((diff < 1 && diff >= -overscroll/2) || maxdisplay == 0)
+                        return true;
+
+                    curh = GetInteriorSize().Height;
+                    overhead = GetCurrentHeight() - curh;
+                    int curexpected = int( std::ceil( (this->GetCount()+overscroll) * (curh/maxdisplay) ) ) + overhead;
+
+                    if(abs(expected - curexpected) == 0) { //no progress, exit
+                        break;
+                    }
+                    else if(abs(expected - curexpected) < 0.1 && smalldone) { //we will allow one small progress, no more
+                        break;
+                    }
+                    else if(abs(expected - curexpected) < 0.1) {
+                        smalldone = true;
+                    }
+                    expected = curexpected;
+                    tried++;
+                } while(expected < maxpixels && tried < 5);
+
+            }
+
+            SetHeight(Pixels(maxpixels));
+            return false;
+        }
+
         ~ListboxWidgetBase() {
             for(auto &p : widgets) {
                 p.second.Destroy();
@@ -2120,7 +2145,7 @@
         virtual void boundschanged() override {
             Refresh();
         }
-        
+
         std::map<UI::ComponentTemplate::Tag, Containers::Collection<W_>> widgets;
         std::map<const W_*, long> indexes;
         std::map<long, W_*> widgetlist;
--- a/Source/Gorgon/Widgets/RadioButtons.h	Fri Oct 29 07:38:50 2021 +0300
+++ b/Source/Gorgon/Widgets/RadioButtons.h	Fri Oct 29 14:08:50 2021 +0300
@@ -21,7 +21,7 @@
     class RadioButtons : public Composer, protected UI::RadioControl<T_, W_> {
         friend class UI::WidgetContainer;
     public:
-        explicit RadioButtons(const UI::Template &temp) : Composer(Pixels(temp.GetSize())), temp(temp) {
+        explicit RadioButtons(const UI::Template &temp) : Composer(temp.GetSize()), temp(temp) {
             spacing = temp.GetSpacing();
             this->own = true;
         }
--- a/Testing/Source/Manual/UI_Generate.cpp	Fri Oct 29 07:38:50 2021 +0300
+++ b/Testing/Source/Manual/UI_Generate.cpp	Fri Oct 29 14:08:50 2021 +0300
@@ -245,7 +245,7 @@
         /*if(index >= 1)
             list.Remove(index - 1);*/
     });
-    list.EnsureVisible(11);
+    //list.EnsureVisible(11);
     list.EnsureVisible(1);
     //list.Clear();
     //list.FitHeight(list.GetHeight());

mercurial