Sun, 07 Jun 2020 12:05:24 +0300
* ComponentStack review 4/4
* ComponentStack rework part 1
--- a/Source/Gorgon/Graphics/Font.cpp Fri Jun 05 09:41:00 2020 +0300 +++ b/Source/Gorgon/Graphics/Font.cpp Sun Jun 07 12:05:24 2020 +0300 @@ -1048,7 +1048,7 @@ [&](Glyph) { cur.Y += (int)std::round(renderer->GetLineGap() * vspace + pspace); if(maxx < cur.X) maxx = cur.X; cur.X = 0; } ); - return{maxx > 0 ? maxx + 1 : 0, cur.Y + 1}; + return{maxx > 0 ? maxx + 1 : 0, cur.Y > 0 ? (cur.Y + 1 - pspace + renderer->GetLineGap() * (1 - vspace)) : 0}; } Geometry::Size StyledRenderer::GetSize(const std::string &text, int width) const { @@ -1062,7 +1062,10 @@ internal::boundedprint( *renderer, text.begin(), text.end(), tot, [&](Glyph eol, internal::markvecit begin, internal::markvecit end, int width) { - y += (int)std::round(renderer->GetLineGap() * vspace + pspace); + y += (int)std::round(renderer->GetLineGap() * vspace); + if(eol != 0) + y += pspace; + if(width > maxx) maxx = width; @@ -1076,7 +1079,7 @@ std::bind(&internal::dodefaulttab<int>, 0, std::placeholders::_1, tabwidth ? tabwidth : 16) ); - return {maxx > 0 ? maxx + 1 : 0, y + 1}; + return {maxx > 0 ? maxx + 1 : 0, y > 0 ? y - pspace + renderer->GetLineGap() * (1 - vspace) + 1 : 0}; } int StyledRenderer::GetCharacterIndex(const std::string &text, Geometry::Point location) const{
--- a/Source/Gorgon/Graphics/Font.h Fri Jun 05 09:41:00 2020 +0300 +++ b/Source/Gorgon/Graphics/Font.h Sun Jun 07 12:05:24 2020 +0300 @@ -213,6 +213,12 @@ /// Returns the size of the EM dash virtual int GetEMSize() const = 0; + /// Get the distance of baseline from the top of the text + virtual float GetBaseLine() const = 0; + + /// Get the distance of baseline from the top of the text + virtual int GetHeight() const = 0; + /// Returns the size of the given text virtual Geometry::Size GetSize(const std::string &text) const = 0; @@ -346,7 +352,15 @@ virtual int GetEMSize() const override { return renderer->GetEMSize(); } - + + virtual float GetBaseLine() const override { + return renderer->GetBaseLine(); + } + + virtual int GetHeight() const override { + return renderer->GetHeight(); + } + virtual Geometry::Size GetSize(const std::string &text) const override; virtual Geometry::Size GetSize(const std::string &text, int width) const override; @@ -719,6 +733,14 @@ return renderer->GetEMSize(); } + virtual float GetBaseLine() const override { + return renderer->GetBaseLine(); + } + + virtual int GetHeight() const override { + return renderer->GetHeight(); + } + virtual const GlyphRenderer &GetGlyphRenderer() const override { return *renderer; }
--- a/Source/Gorgon/UI/Component.h Fri Jun 05 09:41:00 2020 +0300 +++ b/Source/Gorgon/UI/Component.h Sun Jun 07 12:05:24 2020 +0300 @@ -21,16 +21,6 @@ return *temp; } - static void Swap(Component &left, Component &right) { - using std::swap; - - swap(left.temp , right.temp ); - swap(left.location , right.location ); - swap(left.size , right.size ); - swap(left.innersize, right.innersize); - } - - Geometry::Point location = {0, 0}; Geometry::Size size = {-1, -1};
--- a/Source/Gorgon/UI/ComponentStack.cpp Fri Jun 05 09:41:00 2020 +0300 +++ b/Source/Gorgon/UI/ComponentStack.cpp Sun Jun 07 12:05:24 2020 +0300 @@ -6,7 +6,8 @@ #include "math.h" -//NOTE if a transition does not exists, but it is in the stack, its completion will be counted as 100% +//NOTE when does the condition for a + namespace Gorgon { namespace UI { @@ -113,14 +114,22 @@ //set our initial size Resize(size); - //search for emsize in textholders, use the first one found + //search for emsize in textholders, find the maximum ones to ensure + //when the default is to be used as size, it will be able to contain + //any font within the stack. for(int i=0; i<temp.GetCount(); i++) { if(temp[i].GetType() == ComponentType::Textholder) { const auto &th = dynamic_cast<const TextholderTemplate&>(temp[i]); if(th.IsReady()) { - emsize = th.GetRenderer().GetEMSize(); - break; + if(emsize < th.GetRenderer().GetEMSize()) + emsize = th.GetRenderer().GetEMSize(); + + if(textheight < th.GetRenderer().GetHeight()) + textheight = th.GetRenderer().GetHeight(); + + if(baseline < th.GetRenderer().GetBaseLine()) + baseline = th.GetRenderer().GetBaseLine(); } } } @@ -1450,6 +1459,38 @@ return emsize; } + int ComponentStack::getbaseline(const Component &comp) { + //if the component is a text holder + if(comp.GetTemplate().GetType() == ComponentType::Textholder) { + const auto &th = dynamic_cast<const TextholderTemplate&>(comp.GetTemplate()); + + //and ready + if(th.IsReady()) { + //return its own em size + return th.GetRenderer().GetBaseLine(); + } + } + + //otherwise return the global (first one found) emsize + return baseline; + } + + int ComponentStack::gettextheight(const Component &comp) { + //if the component is a text holder + if(comp.GetTemplate().GetType() == ComponentType::Textholder) { + const auto &th = dynamic_cast<const TextholderTemplate&>(comp.GetTemplate()); + + //and ready + if(th.IsReady()) { + //return its own em size + return th.GetRenderer().GetHeight(); + } + } + + //otherwise return the global (first one found) emsize + return baseline; + } + float ComponentStack::calculatevalue(const std::array<float, 4> &value, int channel, const Component &comp) const { //get the template const auto &temp = comp.GetTemplate(); @@ -1639,14 +1680,19 @@ return nullptr; } - void anchortoparent(Component &comp, const ComponentTemplate &temp, + ///Determines the location of the component in relation to its parent. + void ComponentStack::anchortoparent(Component &comp, const ComponentTemplate &temp, Geometry::Point offset, Geometry::Margin margin, Geometry::Size maxsize) { + //anchor on the parent Anchor pa = temp.GetContainerAnchor(); + //component anchor Anchor ca = temp.GetMyAnchor(); + //parent anchor point and component anchor point Geometry::Point pp, cp; + //determine parent anchor point switch(pa) { default: case Anchor::TopLeft: @@ -1663,8 +1709,11 @@ case Anchor::MiddleLeft: + pp = {margin.Left, margin.Top - margin.Bottom + maxsize.Height / 2}; + break; + case Anchor::FirstBaselineLeft: - pp = {margin.Left, margin.Top - margin.Bottom + maxsize.Height / 2}; + pp = {margin.Left, -margin.Bottom + baseline}; break; case Anchor::MiddleCenter: @@ -1672,14 +1721,19 @@ break; case Anchor::MiddleRight: - case Anchor::FirstBaselineRight: pp = { -margin.Right + maxsize.Width, margin.Top - margin.Bottom + maxsize.Height / 2}; break; + case Anchor::FirstBaselineRight: + pp = {-margin.Right + maxsize.Width, -margin.Bottom + baseline}; + break; case Anchor::BottomLeft: + pp = {margin.Left, -margin.Bottom + maxsize.Height}; + break; + case Anchor::LastBaselineLeft: - pp = {margin.Left, -margin.Bottom + maxsize.Height}; + pp = {margin.Left, -margin.Bottom + maxsize.Height - textheight + baseline}; break; case Anchor::BottomCenter: @@ -1687,44 +1741,19 @@ break; case Anchor::BottomRight: + pp = { -margin.Right + maxsize.Width, -margin.Bottom + maxsize.Height}; + break; + case Anchor::LastBaselineRight: - pp = { -margin.Right + maxsize.Width, -margin.Bottom + maxsize.Height}; + pp = { -margin.Right + maxsize.Width, -margin.Bottom + maxsize.Height - textheight + baseline}; break; } + //component size auto csize = comp.size; - if(temp.GetType() == ComponentType::Textholder && - (ca == Anchor::FirstBaselineLeft || ca == Anchor::FirstBaselineRight || ca == Anchor::LastBaselineLeft || ca == Anchor::LastBaselineRight) - ) { - const auto &th = dynamic_cast<const TextholderTemplate&>(temp); - - if(th.IsReady()) { - - switch(ca) { - case Anchor::FirstBaselineLeft: - cp = {-offset.X, int(-offset.Y-th.GetRenderer().GetGlyphRenderer().GetBaseLine())}; - break; - - case Anchor::FirstBaselineRight: - cp = {-offset.X + csize.Width, int(-offset.Y-th.GetRenderer().GetGlyphRenderer().GetBaseLine())}; - break; - - case Anchor::LastBaselineLeft: - cp = {-offset.X, int(offset.Y+th.GetRenderer().GetGlyphRenderer().GetBaseLine()-th.GetRenderer().GetGlyphRenderer().GetHeight()-csize.Height)}; - break; - - case Anchor::LastBaselineRight: - cp = {-offset.X + csize.Width, int(offset.Y+th.GetRenderer().GetGlyphRenderer().GetBaseLine()-th.GetRenderer().GetGlyphRenderer().GetHeight()-csize.Height)}; - break; - default: ;//to silence warnings - } - - ca = Anchor::None; - } - } - + //determine where the anchor point is on the component switch(ca) { default: case Anchor::TopLeft: @@ -1741,8 +1770,11 @@ case Anchor::MiddleLeft: + cp = {-offset.X, csize.Height / 2 - offset.Y}; + break; + case Anchor::FirstBaselineLeft: - cp = {-offset.X, csize.Height / 2 - offset.Y}; + cp = {-offset.X, getbaseline(comp) - offset.Y}; break; case Anchor::MiddleCenter: @@ -1750,31 +1782,41 @@ break; case Anchor::MiddleRight: + cp = { offset.X + csize.Width, csize.Height / 2 - offset.Y}; + break; + case Anchor::FirstBaselineRight: - cp = { offset.X + csize.Width, csize.Height / 2 - offset.Y}; + cp = {offset.X + csize.Width, getbaseline(comp) - offset.Y}; break; case Anchor::BottomLeft: - case Anchor::LastBaselineLeft: cp = {-offset.X, csize.Height + offset.Y}; break; - + + case Anchor::LastBaselineLeft: + cp = {-offset.X, csize.Height - gettextheight(comp) + getbaseline(comp) + offset.Y}; + break; + case Anchor::BottomCenter: cp = {-offset.X + csize.Width / 2, csize.Height + offset.Y}; break; case Anchor::BottomRight: + cp = { offset.X + csize.Width, csize.Height + offset.Y}; + break; + case Anchor::LastBaselineRight: - cp = { offset.X + csize.Width, csize.Height + offset.Y}; + cp = {offset.X + csize.Width, csize.Height - gettextheight(comp) + getbaseline(comp) + offset.Y}; break; } + //calculate the final offset comp.location = pp - cp; } - void anchortoother(Component &comp, const ComponentTemplate &temp, + void ComponentStack::anchortoother(Component &comp, const ComponentTemplate &temp, Geometry::Point offset, Geometry::Margin margin, Component &other, Graphics::Orientation orientation) { Anchor pa = temp.GetPreviousAnchor(); @@ -1957,543 +1999,614 @@ } void ComponentStack::update() { - if(!stacksizes[0]) return; - + //honor before update notification if(beforeupdate_fn) beforeupdate_fn(); - - get(0).size = size; - get(0).location = {0,0}; - get(0).parent = -1; - - //update repeat counts - for(auto &r : repeated) { - if(repeats.count(r.first->GetRepeatMode())) - r.second.resize(repeats[r.first->GetRepeatMode()].size(), Component(*r.first)); + + //clear everything + base.Clear(); + for(auto &s : storage) { + if(s.second->layer) + s.second->layer->Hide(); } - //calculate common emsize - for(int i=0; i<indices; i++) { - if(stacksizes[i] > 0) { - if(get(i).GetTemplate().GetType() == ComponentType::Textholder) { - const auto &th = dynamic_cast<const TextholderTemplate&>(get(i).GetTemplate()); - - if(th.IsReady()) { - emsize = th.GetRenderer().GetEMSize(); - break; + //update is no more required, set beforehand so that + //if necessary can be set again during update to + //run update next frame + updaterequired = false; + + //if root has something to be displayed + if(stacksizes[0]) { + //initial states + get(0).size = size; + get(0).location = {0,0}; + get(0).parent = -1; + + //update the component storage for repeated components + for(auto &r : repeated) { + r.second.resize( + repeats[r.first->GetRepeatMode()].size(), //size will be number of repeats + Component(*r.first) //the components will be instantiated from the repeat template + ); + } + + //search for emsize in textholders, find the maximum ones to ensure + //when the default is to be used as size, it will be able to contain + //any font within the stack. + for(int i=0; i<indices; i++) { + if(stacksizes[i] > 0) { + if(get(i).GetTemplate().GetType() == ComponentType::Textholder) { + const auto &th = dynamic_cast<const TextholderTemplate&>(get(i).GetTemplate()); + + if(th.IsReady()) { + if(emsize < th.GetRenderer().GetEMSize()) + emsize = th.GetRenderer().GetEMSize(); + + if(textheight < th.GetRenderer().GetHeight()) + textheight = th.GetRenderer().GetHeight(); + + if(baseline < th.GetRenderer().GetBaseLine()) + baseline = th.GetRenderer().GetBaseLine(); + } } } } + + //start the update from the root + update(get(0)); } - update(get(0)); - - updaterequired = false; + //update is complete + if(update_fn) + update_fn(); - base.Clear(); - for(auto &s : storage) - if(s.second->layer) - s.second->layer->Hide(); - - if(update_fn) - update_fn(); - + //if root has something to be displayed + if(stacksizes[0]) { //draw everything render(get(0), base, {0,0}); + } + //this is called after the render if(render_fn) render_fn(); } + int calculatemargin(int l, int r) { + if(l<0 || r<0) + return l+r; + else + return std::max(l, r); + } + //location depends on the container location void ComponentStack::update(Component &parent) { + //get the template const ComponentTemplate &ctemp = parent.GetTemplate(); - if(ctemp.GetType() != ComponentType::Container) return; + //just in case + ASSERT(ctemp.GetType() == ComponentType::Container, "Only containers are needed to be updated") ; + //get the container const ContainerTemplate &cont = dynamic_cast<const ContainerTemplate&>(ctemp); + //we need the innersize to arrange components parent.innersize = parent.size - cont.GetBorderSize(); - if(cont.GetHorizontalSizing() == cont.Fixed && parent.innersize.Width <= 0) return; - if(cont.GetVerticalSizing() == cont.Fixed && parent.innersize.Height <= 0) return; + //if sizing is fixed and the size is 0 and clipping is on, nothing can be displayed + if(cont.GetClip() && cont.GetHorizontalSizing() == cont.Fixed && parent.innersize.Width <= 0) + return; + + //if sizing is fixed and the size is 0 and clipping is on, nothing can be displayed + if(cont.GetClip() && cont.GetVerticalSizing() == cont.Fixed && parent.innersize.Height <= 0) + return; + + //this function will loop through all components, including the repeats and calls the given + //function for each component + auto forallcomponents = [&](auto fn) { + for(int i=0; i<cont.GetCount(); i++) { + + //get the component index + int ci = cont[i]; + + //just in case + if(ci >= indices) continue; + + //if empty, this index is not currently available + //this is not an edge case + if(!stacksizes[ci]) continue; + + //original component, used to distinguish from repeats + auto &comporg = get(cont[i]); + //original template + const auto &temporg = comporg.GetTemplate(); + + + for(int j = 0; + temporg.GetRepeatMode() == temporg.NoRepeat ? //if not repeating + j == 0 : //only do this once + repeats.count(temporg.GetRepeatMode()) && j < repeats[temporg.GetRepeatMode()].size(); //if not, repeat for every repeat + j++) + { + Component *compptr; + const ComponentTemplate *tempptr; + + //stores the reference value for this component + const std::array<float, 4> *val; + + //if not to be repeated + if(temporg.GetRepeatMode() == temporg.NoRepeat) { + //use originals + compptr = &comporg; + tempptr = &temporg; + val = &value; + } + else { + //get the repeated component + compptr = &repeated[&temporg][j]; + + //determine condition of the repeat, default is always + ComponentCondition rc = ComponentCondition::Always; + + //if condition is set + if(repeatconditions[temporg.GetRepeatMode()].count(j)) + rc = repeatconditions[temporg.GetRepeatMode()][j]; //use it + + //get the template depending on the condition + tempptr = &get(ci, rc).GetTemplate(); + val = &repeats[temporg.GetRepeatMode()][j]; + } + + //call the function + fn(*compptr, *tempptr, *val, getemsize(*compptr)); + } + } + }; + + //whether there is something requires a second pass bool requiresrepass = false; + + //when repass is done, it will be repeated bool repassdone = false; + //space left after the absolutely sized components are placed, will be used for percentage based + //components int spaceleft = 0; - + + //for easy access + auto ishor = cont.GetOrientation() == Graphics::Orientation::Horizontal; + realign: - // first pass for size, second pass will cover the sizes that are percent based. - for(int i=0; i<cont.GetCount(); i++) { - - int ci = cont[i]; - - if(ci >= indices) continue; - if(!stacksizes[ci]) continue; - - - auto &compparent = get(cont[i]); - - const auto &tempparent = compparent.GetTemplate(); - - - for(int j = 0; tempparent.GetRepeatMode() == tempparent.NoRepeat ? j == 0 : repeats.count(tempparent.GetRepeatMode()) && j < repeats[tempparent.GetRepeatMode()].size(); j++) { - Component *compptr; - const ComponentTemplate *tempptr; - - const std::array<float, 4> *val; - - if(tempparent.GetRepeatMode() == tempparent.NoRepeat) { - compptr = &compparent; - tempptr = &tempparent; - val = &value; + // first operation is for size. Second pass will cover the sizes that are percent based. + forallcomponents([&](Component &comp, const ComponentTemplate &temp, const std::array<float, 4> &val, int emsize) { + //set the index to be accessed later + comp.parent = cont.GetIndex(); + + //******************************** very dubious max size depends on where the component is anchored to + auto parentmargin = Convert( + temp.GetMargin(), parent.innersize, emsize + ).CombinePadding( + Convert(cont.GetPadding(), parent.size, emsize) + ) + + Convert(temp.GetIndent(), parent.innersize, emsize); + + auto maxsize = parent.innersize - parentmargin; + + if(temp.GetPositioning() != temp.Absolute && temp.GetPositioning() != temp.PolarAbsolute) { + if(cont.GetOrientation() == Graphics::Orientation::Horizontal) { + maxsize.Width = spaceleft - parentmargin.TotalX(); + if(maxsize.Width < 0) + maxsize.Width = 0; } else { - compptr = &repeated[&tempparent][j]; - ComponentCondition rc = ComponentCondition::Always; - - if(repeatconditions[tempparent.GetRepeatMode()].count(j)) - rc = repeatconditions[tempparent.GetRepeatMode()][j]; - - tempptr = &get(ci, rc).GetTemplate(); - val = &repeats[tempparent.GetRepeatMode()][j]; + maxsize.Height = spaceleft - parentmargin.TotalY(); + if(maxsize.Height < 0) + maxsize.Height = 0; } - - auto &comp = *compptr; - const auto &temp = *tempptr; - - comp.parent = cont.GetIndex(); - - //check if textholder and if so use emsize from the font - int emsize = getemsize(comp); + } + //************************************** + - auto parentmargin = Convert( - temp.GetMargin(), parent.innersize, emsize - ).CombinePadding( - Convert(cont.GetPadding(), parent.size, emsize) - ) + - Convert(temp.GetIndent(), parent.innersize, emsize); + auto size = temp.GetSize(); - auto maxsize = parent.innersize - parentmargin; - - if(temp.GetPositioning() != temp.Absolute && temp.GetPositioning() != temp.PolarAbsolute) { + //********** simplify this. + if(temp.GetValueModification() == temp.ModifySize) { + if(NumberOfSetBits(temp.GetValueSource()) == 1) { if(cont.GetOrientation() == Graphics::Orientation::Horizontal) { - maxsize.Width = spaceleft - parentmargin.TotalX(); - if(maxsize.Width < 0) - maxsize.Width = 0; + size = { + {int(calculatevalue(val, 0, comp)*10000), Dimension::BasisPoint}, + size.Height + }; } else { - maxsize.Height = spaceleft - parentmargin.TotalY(); - if(maxsize.Height < 0) - maxsize.Height = 0; - } - } - - auto size = temp.GetSize(); - - - if(temp.GetValueModification() == temp.ModifySize) { - if(NumberOfSetBits(temp.GetValueSource()) == 1) { - if(cont.GetOrientation() == Graphics::Orientation::Horizontal) { - size = { - {int(calculatevalue(*val, 0, comp)*10000), Dimension::BasisPoint}, - size.Height - }; - } - else { - size = { - size.Width, - {int(calculatevalue(*val, 0, comp)*10000), Dimension::BasisPoint} - }; - } - } - else { - size ={ - {int(calculatevalue(*val, 0, comp)*10000), Dimension::BasisPoint}, - {int(calculatevalue(*val, 1, comp)*10000), Dimension::BasisPoint} + size = { + size.Width, + {int(calculatevalue(val, 0, comp)*10000), Dimension::BasisPoint} }; } } - else if(temp.GetValueModification() == temp.ModifyWidth) { - size ={{int(calculatevalue(*val, 0, comp)*10000), Dimension::BasisPoint}, size.Height}; - } - else if(temp.GetValueModification() == temp.ModifyHeight) { - size ={size.Width, {int(calculatevalue(*val, 0, comp)*10000), Dimension::BasisPoint}}; - } - - if(temp.GetValueModification() == temp.ModifySize && NumberOfSetBits(temp.GetValueSource()) > 1) { - auto minimum = Convert(temp.GetSize(), maxsize, emsize); - - comp.size = Convert(size, maxsize - minimum, emsize) + minimum; - } - else if(temp.GetValueModification() == temp.ModifyWidth || (temp.GetValueModification() == temp.ModifySize && cont.GetOrientation() == Graphics::Orientation::Horizontal)) { - auto minimum = Convert(temp.GetSize(), maxsize, emsize); - - comp.size = Convert(size, {maxsize.Width - minimum.Width, maxsize.Height}, emsize) + Geometry::Size(minimum.Width, 0); - } - else if(temp.GetValueModification() == temp.ModifyHeight || (temp.GetValueModification() == temp.ModifySize && cont.GetOrientation() == Graphics::Orientation::Vertical)) { - auto minimum = Convert(temp.GetSize(), maxsize, emsize); - - comp.size = Convert(size, {maxsize.Width, maxsize.Height - minimum.Height}, emsize) + Geometry::Size(0, minimum.Height); - } - else if(tagsizes.count(temp.GetTag())) { - comp.size = tagsizes[temp.GetTag()]; - } else { - comp.size = Convert(size, maxsize, emsize); - } - - if( - (temp.GetPositioning() == temp.Relative || temp.GetPositioning() == temp.AbsoluteSliding) && - ( - (cont.GetOrientation() == Graphics::Orientation::Horizontal && - (size.Width.GetUnit() == Dimension::Percent || size.Width.GetUnit() == Dimension::BasisPoint)) || - (cont.GetOrientation() == Graphics::Orientation::Vertical && - (size.Height.GetUnit() == Dimension::Percent || size.Height.GetUnit() == Dimension::BasisPoint)) - ) - ) - requiresrepass = true; - - if(!(tagsizes.count(temp.GetTag())) && - (temp.GetHorizontalSizing() != temp.Fixed || temp.GetVerticalSizing() != temp.Fixed) && - !(temp.GetValueModification() == temp.ModifySize && NumberOfSetBits(temp.GetValueSource()) > 1) - ) { - auto &st = *storage[&temp]; - - auto orgsize = comp.size; - - if(temp.GetType() == ComponentType::Container) { - comp.size = {0, 0}; - update(comp); - } - else if(temp.GetType() == ComponentType::Graphics) { - if(st.primary) { - auto rectangular = dynamic_cast<const Graphics::RectangularDrawable*>(st.primary); - if(rectangular) - comp.size = rectangular->GetSize() + dynamic_cast<const GraphicsTemplate&>(temp).GetPadding(); - } - else { - comp.size = dynamic_cast<const GraphicsTemplate&>(temp).GetPadding().Total(); - } - } - else if(temp.GetType() == ComponentType::Textholder) { - const auto &th = dynamic_cast<const TextholderTemplate&>(temp); - - if(th.IsReady() && stringdata[temp.GetDataEffect()] != "") { - auto s = size.Width(maxsize.Width, emsize); - - if(tagnowrap.count(temp.GetTag())) - s = 0; - - if(s > 0) - comp.size = th.GetRenderer().GetSize(stringdata[temp.GetDataEffect()], s); - else - comp.size = th.GetRenderer().GetSize(stringdata[temp.GetDataEffect()]); - - } - } - else if(temp.GetType() == ComponentType::Placeholder) { - const auto &ph = dynamic_cast<const PlaceholderTemplate&>(temp); - - if(imagedata.Exists(ph.GetDataEffect())) { - auto rectangular = dynamic_cast<const Graphics::RectangularDrawable*>(&imagedata[ph.GetDataEffect()]); - if(rectangular) { - comp.size = rectangular->GetSize(); - } - } - else { - comp.size = {0, 0}; - } - } - - if(temp.GetHorizontalSizing() == ComponentTemplate::GrowOnly) { - if(comp.size.Width < orgsize.Width) - comp.size.Width = orgsize.Width; - } - else if(temp.GetHorizontalSizing() == ComponentTemplate::ShrinkOnly) { - if(comp.size.Width > orgsize.Width) - comp.size.Width = orgsize.Width; - } - - if(temp.GetHorizontalSizing() == ComponentTemplate::GrowOnly) { - if(comp.size.Height < orgsize.Height) - comp.size.Height = orgsize.Height; - } - else if(temp.GetHorizontalSizing() == ComponentTemplate::ShrinkOnly) { - if(comp.size.Height > orgsize.Height) - comp.size.Height = orgsize.Height; - } - - if(temp.GetValueModification() == temp.ModifySize) { - if(cont.GetOrientation() == Graphics::Orientation::Horizontal) - comp.size.Width = orgsize.Width; - else - comp.size.Height = orgsize.Height; - } - else if(temp.GetValueModification() == temp.ModifyWidth) { - comp.size.Width = orgsize.Width; - } - else if(temp.GetValueModification() == temp.ModifyHeight) { - comp.size.Height = orgsize.Height; - } - - if( - (cont.GetOrientation() == Graphics::Orientation::Horizontal && - (size.Width.GetUnit() == Dimension::Percent || size.Width.GetUnit() == Dimension::BasisPoint)) || - (cont.GetOrientation() == Graphics::Orientation::Vertical && - (size.Height.GetUnit() == Dimension::Percent || size.Height.GetUnit() == Dimension::BasisPoint)) - ) - { - if(maxsize.Width == 0) - comp.size.Width = 0; - if(maxsize.Height == 0) - comp.size.Height = 0; - } - - if(comp.size.Width < 0) - comp.size.Width = 0; - if(comp.size.Height < 0) - comp.size.Height = 0; + size ={ + {int(calculatevalue(val, 0, comp)*10000), Dimension::BasisPoint}, + {int(calculatevalue(val, 1, comp)*10000), Dimension::BasisPoint} + }; } } - } - - Component *prev = nullptr, *next = nullptr; - - //second pass will align everything - for(int i=0; i<cont.GetCount(); i++) { - - int ci = cont[i]; - - if(ci >= indices) continue; - if(!stacksizes[ci]) continue; - - - auto &compparent = get(cont[i]); - - const auto &temp = compparent.GetTemplate(); - - for(int j = 0; temp.GetRepeatMode() == temp.NoRepeat ? j == 0 : repeats.count(temp.GetRepeatMode()) && j < repeats[temp.GetRepeatMode()].size(); j++) { - Component *compptr; - const std::array<float, 4> *val; - - if(temp.GetRepeatMode() == temp.NoRepeat) { - compptr = &compparent; - val = &value; - } - else { - compptr = &repeated[&temp][j]; - val = &repeats[temp.GetRepeatMode()][j]; - } - - auto &comp = *compptr; - - //check if textholder and if so use emsize from the font - int emsize = getemsize(comp); - - //check anchor object by observing temp.GetPreviousAnchor and direction - Component *anch = nullptr; + else if(temp.GetValueModification() == temp.ModifyWidth) { + size ={{int(calculatevalue(val, 0, comp)*10000), Dimension::BasisPoint}, size.Height}; + } + else if(temp.GetValueModification() == temp.ModifyHeight) { + size ={size.Width, {int(calculatevalue(val, 0, comp)*10000), Dimension::BasisPoint}}; + } - //if absolute, nothing to anchor to but to parent - if(temp.GetPositioning() == temp.Relative && temp.GetPreviousAnchor() != Anchor::None) { - if(cont.GetOrientation() == Graphics::Orientation::Horizontal) { - if((IsLeft(temp.GetPreviousAnchor()) && IsRight(temp.GetMyAnchor())) || - (temp.GetPreviousAnchor() == Anchor::None && IsRight(temp.GetContainerAnchor()))) - { - anch = prev; - comp.anchorotherside = true; - } - else { - anch = next; + //****** combine with above + if(temp.GetValueModification() == temp.ModifySize && NumberOfSetBits(temp.GetValueSource()) > 1) { + auto minimum = Convert(temp.GetSize(), maxsize, emsize); + + comp.size = Convert(size, maxsize - minimum, emsize) + minimum; + } + else if(temp.GetValueModification() == temp.ModifyWidth || (temp.GetValueModification() == temp.ModifySize && cont.GetOrientation() == Graphics::Orientation::Horizontal)) { + auto minimum = Convert(temp.GetSize(), maxsize, emsize); + + comp.size = Convert(size, {maxsize.Width - minimum.Width, maxsize.Height}, emsize) + Geometry::Size(minimum.Width, 0); + } + else if(temp.GetValueModification() == temp.ModifyHeight || (temp.GetValueModification() == temp.ModifySize && cont.GetOrientation() == Graphics::Orientation::Vertical)) { + auto minimum = Convert(temp.GetSize(), maxsize, emsize); + + comp.size = Convert(size, {maxsize.Width, maxsize.Height - minimum.Height}, emsize) + Geometry::Size(0, minimum.Height); + } + else if(tagsizes.count(temp.GetTag())) { + comp.size = tagsizes[temp.GetTag()]; //********* this should be combined with regular size + modified size + } + else { + comp.size = Convert(size, maxsize, emsize); + } + + if( //if positioning is not free form + (temp.GetPositioning() == temp.Relative || temp.GetPositioning() == temp.AbsoluteSliding) && + ( //and size along the orientation depends on the remaining size + (cont.GetOrientation() == Graphics::Orientation::Horizontal && size.Width.IsRelative() ) || + (cont.GetOrientation() == Graphics::Orientation::Vertical && size.Height.IsRelative()) + ) + ) //this component requires a repass + requiresrepass = true; + + if(!(tagsizes.count(temp.GetTag())) && + (temp.GetHorizontalSizing() != temp.Fixed || temp.GetVerticalSizing() != temp.Fixed) && + !(temp.GetValueModification() == temp.ModifySize && NumberOfSetBits(temp.GetValueSource()) > 1) + ) { + auto &st = *storage[&temp]; + + auto orgsize = comp.size; + + if(temp.GetType() == ComponentType::Container) { + comp.size = {0, 0}; + update(comp); + } + else if(temp.GetType() == ComponentType::Graphics) { + if(st.primary) { + auto rectangular = dynamic_cast<const Graphics::RectangularDrawable*>(st.primary); + if(rectangular) + comp.size = rectangular->GetSize() + dynamic_cast<const GraphicsTemplate&>(temp).GetPadding(); + } + else { + comp.size = dynamic_cast<const GraphicsTemplate&>(temp).GetPadding().Total(); + } + } + else if(temp.GetType() == ComponentType::Textholder) { + const auto &th = dynamic_cast<const TextholderTemplate&>(temp); + + if(th.IsReady() && stringdata[temp.GetDataEffect()] != "") { + auto s = size.Width(maxsize.Width, emsize); + + if(tagnowrap.count(temp.GetTag())) + s = 0; + + if(s > 0) + comp.size = th.GetRenderer().GetSize(stringdata[temp.GetDataEffect()], s); + else + comp.size = th.GetRenderer().GetSize(stringdata[temp.GetDataEffect()]); + + } + } + else if(temp.GetType() == ComponentType::Placeholder) { + const auto &ph = dynamic_cast<const PlaceholderTemplate&>(temp); + + if(imagedata.Exists(ph.GetDataEffect())) { + auto rectangular = dynamic_cast<const Graphics::RectangularDrawable*>(&imagedata[ph.GetDataEffect()]); + if(rectangular) { + comp.size = rectangular->GetSize(); } } else { - if((IsTop(temp.GetPreviousAnchor()) && IsBottom(temp.GetMyAnchor())) || - (temp.GetPreviousAnchor() == Anchor::None && IsBottom(temp.GetContainerAnchor()))) - { - anch = prev; - comp.anchorotherside = true; - } - else { - anch = next; - } - } - } - - auto parentmargin = Convert(temp.GetMargin(), parent.innersize, emsize).CombinePadding(Convert(cont.GetPadding(), parent.size, emsize)) + Convert(temp.GetIndent(), parent.innersize, emsize); - - Geometry::Margin margin; - - if(anch) { - margin = Convert(temp.GetMargin(), parent.innersize, emsize).CombineMargins(Convert(anch->GetTemplate().GetMargin(), parent.innersize, emsize)); - } - else { - margin = parentmargin; - } - - auto maxsize = parent.innersize - parentmargin; - - auto pos = temp.GetPosition(); - - if(temp.GetValueModification() == temp.ModifyPosition) { - if(NumberOfSetBits(temp.GetValueSource()) == 1) { - if(cont.GetOrientation() == Graphics::Orientation::Horizontal) { - pos = {{int(calculatevalue(*val, 0, comp)*10000), Dimension::BasisPoint}, pos.Y}; - } - else { - pos = {pos.X, {int(calculatevalue(*val, 0, comp)*10000), Dimension::BasisPoint}}; - } - } - else { - pos ={{int(calculatevalue(*val, 0, comp)*10000), Dimension::BasisPoint}, {int(calculatevalue(*val, 1, comp)*10000), Dimension::BasisPoint}}; - } - } - else if(temp.GetValueModification() == temp.ModifyX) { - pos = {{int(calculatevalue(*val, 0, comp)*10000), Dimension::BasisPoint}, pos.Y}; - } - else if(temp.GetValueModification() == temp.ModifyY) { - pos = {pos.X, {int(calculatevalue(*val, 0, comp)*10000), Dimension::BasisPoint}}; - } - else if(taglocations.count(temp.GetTag())) { - pos = {taglocations[temp.GetTag()]}; - } - - if(temp.GetPositioning() == temp.PolarAbsolute) { - auto pcenter = Geometry::Pointf(cont.GetCenter().X.CalculateFloat((float)maxsize.Width, (float)emsize), cont.GetCenter().Y.CalculateFloat((float)maxsize.Height, (float)emsize)); - auto center = Geometry::Pointf(temp.GetCenter().X.CalculateFloat((float)comp.size.Width, (float)emsize), temp.GetCenter().Y.CalculateFloat((float)comp.size.Height, (float)emsize)); - - pcenter += parentmargin.TopLeft(); - - auto r = pos.X.CalculateFloat(Geometry::Point(maxsize).Distance()/(float)sqrt(2), (float)emsize); - - auto a = pos.Y.CalculateFloat(360, PI); - - a *= PI / 180.0f; - - comp.location = {int(std::round(r * cos(a) + pcenter.X - center.X)), int(std::round(r * sin(a) + pcenter.Y - center.Y))}; - } - else { - auto offset = Convert(pos, (temp.GetPositioning() == temp.AbsoluteSliding ? maxsize - comp.size : comp.size), emsize); - - if(anch) { - anchortoother(comp, temp, offset, margin, *anch, cont.GetOrientation()); - } - else { - anchortoparent(comp, temp, offset, margin, parent.innersize); + comp.size = {0, 0}; } } - //Which anchor side is to be changed - if(temp.GetPositioning() == temp.Relative) { + if(temp.GetHorizontalSizing() == ComponentTemplate::GrowOnly) { + if(comp.size.Width < orgsize.Width) + comp.size.Width = orgsize.Width; + } + else if(temp.GetHorizontalSizing() == ComponentTemplate::ShrinkOnly) { + if(comp.size.Width > orgsize.Width) + comp.size.Width = orgsize.Width; + } + + if(temp.GetHorizontalSizing() == ComponentTemplate::GrowOnly) { + if(comp.size.Height < orgsize.Height) + comp.size.Height = orgsize.Height; + } + else if(temp.GetHorizontalSizing() == ComponentTemplate::ShrinkOnly) { + if(comp.size.Height > orgsize.Height) + comp.size.Height = orgsize.Height; + } + + if(temp.GetValueModification() == temp.ModifySize) { + if(cont.GetOrientation() == Graphics::Orientation::Horizontal) + comp.size.Width = orgsize.Width; + else + comp.size.Height = orgsize.Height; + } + else if(temp.GetValueModification() == temp.ModifyWidth) { + comp.size.Width = orgsize.Width; + } + else if(temp.GetValueModification() == temp.ModifyHeight) { + comp.size.Height = orgsize.Height; + } + + if( + (cont.GetOrientation() == Graphics::Orientation::Horizontal && size.Width.IsRelative()) || + (cont.GetOrientation() == Graphics::Orientation::Vertical && size.Height.IsRelative() ) + ) + { + if(maxsize.Width == 0) + comp.size.Width = 0; + if(maxsize.Height == 0) + comp.size.Height = 0; + } + + if(comp.size.Width < 0) + comp.size.Width = 0; + if(comp.size.Height < 0) + comp.size.Height = 0; + } + }); //for size + + Component *startanch = nullptr, *endanch = nullptr; + + //Positioning stage, second pass will align everything. + forallcomponents([&](Component &comp, const ComponentTemplate &temp, const std::array<float, 4> &val, int emsize) { + //check anchor object by observing temp.GetPreviousAnchor and direction + Component *anch = nullptr; + + //if absolute, nothing to anchor to but to parent + if(temp.GetPositioning() == temp.Relative && temp.GetPreviousAnchor() != Anchor::None) { + if(cont.GetOrientation() == Graphics::Orientation::Horizontal) { + if((IsLeft(temp.GetPreviousAnchor()) && IsRight(temp.GetMyAnchor())) || + (temp.GetPreviousAnchor() == Anchor::None && IsRight(temp.GetContainerAnchor()))) + { + anch = startanch; + comp.anchorotherside = true; + } + else { + anch = endanch; + } + } + else { + if((IsTop(temp.GetPreviousAnchor()) && IsBottom(temp.GetMyAnchor())) || + (temp.GetPreviousAnchor() == Anchor::None && IsBottom(temp.GetContainerAnchor()))) + { + anch = startanch; + comp.anchorotherside = true; + } + else { + anch = endanch; + } + } + } + + auto parentmargin = Convert(temp.GetMargin(), parent.innersize, emsize).CombinePadding(Convert(cont.GetPadding(), parent.size, emsize)) + Convert(temp.GetIndent(), parent.innersize, emsize); + + Geometry::Margin margin; + + if(anch) { + margin = Convert(temp.GetMargin(), parent.innersize, emsize).CombineMargins(Convert(anch->GetTemplate().GetMargin(), parent.innersize, emsize)); + } + else { + margin = parentmargin; + } + + auto maxsize = parent.innersize - parentmargin; + + auto pos = temp.GetPosition(); + + if(temp.GetValueModification() == temp.ModifyPosition) { + if(NumberOfSetBits(temp.GetValueSource()) == 1) { if(cont.GetOrientation() == Graphics::Orientation::Horizontal) { - if(IsRight(temp.GetMyAnchor())) { - prev = ∁ + pos = {{int(calculatevalue(val, 0, comp)*10000), Dimension::BasisPoint}, pos.Y}; + } + else { + pos = {pos.X, {int(calculatevalue(val, 0, comp)*10000), Dimension::BasisPoint}}; + } + } + else { + pos ={{int(calculatevalue(val, 0, comp)*10000), Dimension::BasisPoint}, {int(calculatevalue(val, 1, comp)*10000), Dimension::BasisPoint}}; + } + } + else if(temp.GetValueModification() == temp.ModifyX) { + pos = {{int(calculatevalue(val, 0, comp)*10000), Dimension::BasisPoint}, pos.Y}; + } + else if(temp.GetValueModification() == temp.ModifyY) { + pos = {pos.X, {int(calculatevalue(val, 0, comp)*10000), Dimension::BasisPoint}}; + } + else if(taglocations.count(temp.GetTag())) { + pos = {taglocations[temp.GetTag()]}; + } + + if(temp.GetPositioning() == temp.PolarAbsolute) { + auto pcenter = Geometry::Pointf(cont.GetCenter().X.CalculateFloat((float)maxsize.Width, (float)emsize), cont.GetCenter().Y.CalculateFloat((float)maxsize.Height, (float)emsize)); + auto center = Geometry::Pointf(temp.GetCenter().X.CalculateFloat((float)comp.size.Width, (float)emsize), temp.GetCenter().Y.CalculateFloat((float)comp.size.Height, (float)emsize)); + + pcenter += parentmargin.TopLeft(); + + auto r = pos.X.CalculateFloat(Geometry::Point(maxsize).Distance()/(float)sqrt(2), (float)emsize); + + auto a = pos.Y.CalculateFloat(360, PI); + + a *= PI / 180.0f; + + comp.location = {int(std::round(r * cos(a) + pcenter.X - center.X)), int(std::round(r * sin(a) + pcenter.Y - center.Y))}; + } + else { + auto offset = Convert(pos, (temp.GetPositioning() == temp.AbsoluteSliding ? maxsize - comp.size : comp.size), emsize); + + if(anch) { + anchortoother(comp, temp, offset, margin, *anch, cont.GetOrientation()); + } + else { + anchortoparent(comp, temp, offset, margin, parent.innersize); + } + } + + //Which anchor side is to be changed + if(temp.GetPositioning() == temp.Relative) { + if(cont.GetOrientation() == Graphics::Orientation::Horizontal) { + if(IsRight(temp.GetMyAnchor())) { + startanch = ∁ + } + else { + endanch = ∁ + } + } + else { + if(IsBottom(temp.GetMyAnchor())) { + startanch = ∁ + } + else { + endanch = ∁ + } + } + } + }); //position pass + + if(requiresrepass && !repassdone) { + int startused = 0, endused = 0; + + Component *startmost = nullptr, *endmost = nullptr; + + //go through the components to see where they end + forallcomponents([&](Component &comp, const ComponentTemplate &temp, const std::array<float, 4> &, int) { + //only relatively sided components take up space + if(temp.GetPositioning() == temp.Relative) { + //the values will be overwritten successively to find the last ones + if(ishor) { + if(comp.anchorotherside) { //anchored to right + startmost = ∁ } - else { - next = ∁ + else { //to left + startmost = ∁ } } else { - if(IsBottom(temp.GetMyAnchor())) { - prev = ∁ + if(comp.anchorotherside) { //to bottom + endmost = ∁ } - else { - next = ∁ + else { //to top + startmost = ∁ } } } - } - }//for indices - - if(requiresrepass && !repassdone) { - if(cont.GetOrientation() == Graphics::Orientation::Horizontal) { - int rightused = 0, leftused = 0; - - for(int i=0; i<cont.GetCount(); i++) { + }); + + //this will calculate the necessary spacing between the last item(s) + int lastspacing = 0; + + if(ishor) { + if(startmost) { + //calculate the used space on the left + startused = startmost->location.X + startmost->size.Width; - int ci = cont[i]; - - if(ci >= indices) continue; - if(!stacksizes[ci]) continue; - - auto &compparent = get(cont[i]); - const auto &temp = compparent.GetTemplate(); - - for(int j = 0; temp.GetRepeatMode() == temp.NoRepeat ? j == 0 : repeats.count(temp.GetRepeatMode()) && j < repeats[temp.GetRepeatMode()].size(); j++) { - Component *compptr; - const std::array<float, 4> *val; - - if(temp.GetRepeatMode() == temp.NoRepeat) { - compptr = &compparent; - val = &value; - } - else { - compptr = &repeated[&temp][j]; - val = &repeats[temp.GetRepeatMode()][j]; - } - - auto &comp = *compptr; - - //check if textholder and if so use emsize from the font - int emsize = getemsize(comp); - - if(temp.GetPositioning() != temp.Absolute && temp.GetPositioning() != temp.PolarAbsolute) { - if(comp.anchorotherside) { - rightused = parent.innersize.Width - comp.location.X; - } - else if(comp.size.Width > 0) { - leftused = ( - comp.location.X + comp.size.Width + - std::max(temp.GetMargin().Right(parent.innersize.Width, emsize), cont.GetPadding().Right(parent.size.Width, emsize)) - - ); - } - } + //both sides exist, so we will be using the margins between them + if(endmost) { + //calculate the used space on the right + endused = parent.innersize.Width - endmost->location.X; + + //calculate margin + auto s = startmost->GetTemplate().GetMargin().Right(0, getemsize(*startmost)); + auto e = endmost->GetTemplate().GetMargin().Left(0, getemsize(*startmost)); + + //add indent + lastspacing = calculatemargin(s, e); + } + else { //only start side is there + //calculate margin + auto s = startmost->GetTemplate().GetMargin().Right(0, getemsize(*startmost)); + auto e = cont.GetPadding().Right(parent.innersize.Width, getemsize(*startmost)); + + //add indent + lastspacing = calculatemargin(s, e) + startmost->GetTemplate().GetIndent().Right(0, getemsize(*startmost)); } } - - spaceleft = parent.innersize.Width - rightused - leftused; + else if(endmost) { //only end side is there + //calculate the used space on the right + endused = parent.innersize.Width - endmost->location.X; + + //calculate margin + auto s = cont.GetPadding().Left(parent.innersize.Width, getemsize(*startmost)); + auto e = endmost->GetTemplate().GetMargin().Left(0, getemsize(*startmost)); + + //add indent + lastspacing = calculatemargin(s, e) + endmost->GetTemplate().GetIndent().Left(0, getemsize(*startmost)); + } } else { - int bottomused = 0, topused = 0; - - for(int i=0; i<cont.GetCount(); i++) { - - int ci = cont[i]; - - if(ci >= indices) continue; - if(!stacksizes[ci]) continue; - - auto &comp = get(cont[i]); - const auto &temp = comp.GetTemplate(); + if(startmost) { + //calculate the space used on the top side + startused = startmost->location.Y + startmost->size.Height; - //check if textholder and if so use emsize from the font - int emsize = getemsize(comp); - - if(temp.GetPositioning() != temp.Absolute && temp.GetPositioning() != temp.PolarAbsolute) { - if(comp.anchorotherside) { - bottomused = parent.innersize.Height - comp.location.X; - } - else if(comp.size.Height) { - topused = ( - comp.location.X + comp.size.Height + - std::max(temp.GetMargin().Right(parent.innersize.Height, emsize), cont.GetPadding().Right(parent.size.Height, emsize)) - - ); - } + //both sides exist, so we will be using the margins between them + if(endmost) { + //calculate the space used on the bottom side + endused = parent.innersize.Height - endmost->location.Y; + + //calculate margin + auto s = startmost->GetTemplate().GetMargin().Bottom(0, getemsize(*startmost)); + auto e = endmost->GetTemplate().GetMargin().Top(0, getemsize(*startmost)); + + lastspacing = calculatemargin(s, e); + } + else { //only start side is there + //calculate margin + auto s = startmost->GetTemplate().GetMargin().Bottom(0, getemsize(*startmost)); + auto e = cont.GetPadding().Bottom(parent.innersize.Width, getemsize(*startmost)); + + //add indent + lastspacing = calculatemargin(s, e) + startmost->GetTemplate().GetIndent().Bottom(0, getemsize(*startmost)); } } - - spaceleft = parent.innersize.Height - bottomused - topused; + else if(endmost) { //only end side is there + //calculate the space used on the bottom side + endused = parent.innersize.Height - endmost->location.Y; + + //calculate margin + auto s = cont.GetPadding().Top(parent.innersize.Width, getemsize(*startmost)); + auto e = endmost->GetTemplate().GetMargin().Top(0, getemsize(*startmost)); + + //add indent + lastspacing = calculatemargin(s, e) + endmost->GetTemplate().GetIndent().Top(0, getemsize(*startmost)); + } } + + //calculate remaining space for percent based components + spaceleft = parent.innersize.Width - startused - endused - lastspacing; repassdone = true; goto realign; } + //update the containers for(int i=0; i<cont.GetCount(); i++) { int ci = cont[i]; @@ -2512,7 +2625,7 @@ } } - + void ComponentStack::render(Component &comp, Graphics::Layer &parent, Geometry::Point offset, Graphics::RGBAf color, int ind) { const ComponentTemplate &tempp = comp.GetTemplate(); auto tempptr = &tempp; @@ -2569,17 +2682,18 @@ if(temp.GetType() == ComponentType::Container) { const auto &cont = dynamic_cast<const ContainerTemplate&>(temp); - offset += cont.GetBorderSize().TopLeft(); offset += comp.location; if(st.primary && target) { auto rectangular = dynamic_cast<const Graphics::RectangularDrawable*>(st.primary); if(rectangular) - rectangular->DrawIn(*target, offset-cont.GetBorderSize().TopLeft(), comp.size, color); + rectangular->DrawIn(*target, offset, comp.size, color); else - st.primary->Draw(*target, offset-cont.GetBorderSize().TopLeft(), color); + st.primary->Draw(*target, offset, color); } + offset += cont.GetBorderSize().TopLeft(); + for(int i=0; i<cont.GetCount(); i++) { if(cont[i] >= indices) continue; if(stacksizes[cont[i]]) { @@ -2596,6 +2710,8 @@ } } + offset -= cont.GetBorderSize().TopLeft(); + if(st.secondary && target) { auto rectangular = dynamic_cast<const Graphics::RectangularDrawable*>(st.secondary); if(rectangular) @@ -2603,8 +2719,6 @@ else st.secondary->Draw(*target, offset-cont.GetBorderSize().TopLeft()+cont.GetOverlayExtent().TopLeft(), color); } - - offset -= cont.GetBorderSize().TopLeft(); } else if(temp.GetType() == ComponentType::Graphics) { if(st.primary && target) {
--- a/Source/Gorgon/UI/ComponentStack.h Fri Jun 05 09:41:00 2020 +0300 +++ b/Source/Gorgon/UI/ComponentStack.h Sun Jun 07 12:05:24 2020 +0300 @@ -517,8 +517,18 @@ ///Return the component at the given index with the requested condition. Returns top of stack if condition does not exist. Component &get(int ind, ComponentCondition condition) const; - - ///starts update chain + + ///Calculates the position results from the anchoring the given component to the area determined by the + ///given size and margin. Offset is used to move away from the anchor and may result reversing of direction. + void anchortoparent(Component &comp, const ComponentTemplate &temp, + Geometry::Point offset, Geometry::Margin margin, Geometry::Size maxsize); + + + ///Calculates the position results from the anchoring the given component to another component + void anchortoother(Component &comp, const ComponentTemplate &temp, + Geometry::Point offset, Geometry::Margin margin, Component &other, Graphics::Orientation orientation); + + ///starts the update chain void update(); ///updates a specific container component @@ -534,6 +544,12 @@ ///returns the size of the emdash int getemsize(const Component &comp); + + ///returns the baseline point of the component + int getbaseline(const Component &comp); + + ///returns the height of the component + int gettextheight(const Component &comp); ///Calculates the value of the given channel for the given component. Uses stored value float calculatevalue(int channel, const Component &comp) const { return calculatevalue(value, channel, comp); } @@ -556,7 +572,13 @@ Component *gettag(ComponentTemplate::Tag tag) const; ///ComponentStack wide emsize - int emsize = 10; + int emsize = 0; + + ///ComponentStack wide baseline + int baseline = 0; + + ///ComponentStack wide baseline + int textheight = 0; ///This vector contains data for components. This piece of memory will be managed by the stack Component *data = nullptr;
--- a/Source/Gorgon/UI/Dimension.h Fri Jun 05 09:41:00 2020 +0300 +++ b/Source/Gorgon/UI/Dimension.h Sun Jun 07 12:05:24 2020 +0300 @@ -79,6 +79,11 @@ return (float)value; } } + + /// Returns if the dimension is relative to the parentwidth + bool IsRelative() const { + return unit == Percent || unit == BasisPoint; + } /// Returns the value of the dimension, should not be considered as /// pixels
--- a/Source/Gorgon/UI/Template.h Fri Jun 05 09:41:00 2020 +0300 +++ b/Source/Gorgon/UI/Template.h Sun Jun 07 12:05:24 2020 +0300 @@ -149,7 +149,8 @@ /// This anchor position should is only used to denote object will /// not be anchored to a previous object, only to its parent. If /// used as parent anchor it will be ignored and default anchor - /// will be used instead. + /// will be used instead. This should be paired with absolute + /// positioning. None = 0, /// Top left @@ -175,23 +176,19 @@ BottomRight, /// Baseline left, for text, this aligns to the baseline of - /// the last line; if there is no text related data, this will - /// align to the middle left. + /// the first line FirstBaselineLeft, /// Baseline right, for text, this aligns to the baseline of - /// the last line; if there is no text related data, this will - /// align to the middle right. + /// the first line FirstBaselineRight, /// Baseline left, for text, this aligns to the baseline of - /// the last line; if there is no text related data, this will - /// align to the bottom left. This mode only works properly if + /// the last line. This mode only works properly if /// Sizing is set to automatic. LastBaselineLeft, /// Baseline right, for text, this aligns to the baseline of - /// the last line; if there is no text related data, this will - /// align to the bottom right. This mode only works properly if + /// the last line. This mode only works properly if /// Sizing is set to automatic. LastBaselineRight, };