int UIAnchor::getHookedPoint(const UIWidgetPtr& hookedWidget, const UIWidgetPtr& parentWidget) { // determine hooked widget edge point Rect hookedWidgetRect = hookedWidget->getRect(); if(hookedWidget == parentWidget) hookedWidgetRect = parentWidget->getPaddingRect(); int point = 0; switch(m_hookedEdge) { case Fw::AnchorLeft: point = hookedWidgetRect.left(); break; case Fw::AnchorRight: point = hookedWidgetRect.right(); break; case Fw::AnchorTop: point = hookedWidgetRect.top(); break; case Fw::AnchorBottom: point = hookedWidgetRect.bottom(); break; case Fw::AnchorHorizontalCenter: point = hookedWidgetRect.horizontalCenter(); break; case Fw::AnchorVerticalCenter: point = hookedWidgetRect.verticalCenter(); break; default: // must never happens assert(false); break; } if(hookedWidget == parentWidget) { switch(m_hookedEdge) { case Fw::AnchorLeft: case Fw::AnchorRight: case Fw::AnchorHorizontalCenter: point -= parentWidget->getVirtualOffset().x; break; case Fw::AnchorBottom: case Fw::AnchorTop: case Fw::AnchorVerticalCenter: point -= parentWidget->getVirtualOffset().y; break; default: break; } } return point; }
bool UIHorizontalLayout::internalUpdate() { UIWidgetPtr parentWidget = getParentWidget(); if(!parentWidget) return false; UIWidgetList widgets = parentWidget->getChildren(); if(m_alignRight) std::reverse(widgets.begin(), widgets.end()); bool changed = false; Rect paddingRect = parentWidget->getPaddingRect(); Point pos = (m_alignRight) ? paddingRect.topRight() : paddingRect.topLeft(); int preferredWidth = 0; int gap; for(const UIWidgetPtr& widget : widgets) { if(!widget->isExplicitlyVisible()) continue; Size size = widget->getSize(); gap = (m_alignRight) ? -(widget->getMarginRight()+widget->getWidth()) : widget->getMarginLeft(); pos.x += gap; preferredWidth += gap; if(widget->isFixedSize()) { if(widget->getTextAlign() & Fw::AlignTop) { pos.y = paddingRect.top() + widget->getMarginTop(); } else if(widget->getTextAlign() & Fw::AlignBottom) { pos.y = paddingRect.bottom() - widget->getHeight() - widget->getMarginBottom(); pos.y = std::max<int>(pos.y, paddingRect.top()); } else { // center it pos.y = paddingRect.top() + (paddingRect.height() - (widget->getMarginTop() + widget->getHeight() + widget->getMarginBottom()))/2; pos.y = std::max<int>(pos.y, paddingRect.top()); } } else { // expand height size.setHeight(paddingRect.height() - (widget->getMarginTop() + widget->getMarginBottom())); pos.y = paddingRect.top() + (paddingRect.height() - size.height())/2; } if(widget->setRect(Rect(pos - parentWidget->getVirtualOffset(), size))) changed = true; gap = (m_alignRight) ? -widget->getMarginLeft() : (widget->getWidth() + widget->getMarginRight()); gap += m_spacing; pos.x += gap; preferredWidth += gap; } preferredWidth -= m_spacing; preferredWidth += parentWidget->getPaddingLeft() + parentWidget->getPaddingRight(); if(m_fitChildren && preferredWidth != parentWidget->getWidth()) { // must set the preferred width later g_dispatcher.addEvent([=] { parentWidget->setWidth(preferredWidth); }); } return changed; }
bool UIAnchorLayout::updateWidget(const UIWidgetPtr& widget, UIAnchorGroup& anchorGroup, UIWidgetPtr first) { UIWidgetPtr parentWidget = getParentWidget(); if(!parentWidget) return false; if(first == widget) { g_logger.error(stdext::format("child '%s' of parent widget '%s' is recursively anchored to itself, please fix this", widget->getId(), parentWidget->getId())); return false; } if(!first) first = widget; Rect newRect = widget->getRect(); bool verticalMoved = false; bool horizontalMoved = false; // calculates new rect based on anchors for(const UIAnchor& anchor : anchorGroup.getAnchors()) { // skip invalid anchors if(anchor.getHookedEdge() == Fw::AnchorNone) continue; // determine hooked widget UIWidgetPtr hookedWidget; if(parentWidget) { if(anchor.getHookedWidgetId() == "parent") hookedWidget = parentWidget; else if(anchor.getHookedWidgetId() == "next") hookedWidget = parentWidget->getChildAfter(widget); else if(anchor.getHookedWidgetId() == "prev") hookedWidget = parentWidget->getChildBefore(widget); else hookedWidget = parentWidget->getChildById(anchor.getHookedWidgetId()); } // skip invalid anchors if(!hookedWidget) continue; if(hookedWidget != getParentWidget()) { // update this hooked widget anchors auto it = m_anchorsGroups.find(hookedWidget); if(it != m_anchorsGroups.end()) { UIAnchorGroup& hookedAnchorGroup = it->second; if(!hookedAnchorGroup.isUpdated()) updateWidget(hookedWidget, hookedAnchorGroup, first); } } // determine hooked widget edge point Rect hookedWidgetRect = hookedWidget->getRect(); if(hookedWidget == parentWidget) hookedWidgetRect = parentWidget->getPaddingRect(); int point = 0; switch(anchor.getHookedEdge()) { case Fw::AnchorLeft: point = hookedWidgetRect.left(); break; case Fw::AnchorRight: point = hookedWidgetRect.right(); break; case Fw::AnchorTop: point = hookedWidgetRect.top(); break; case Fw::AnchorBottom: point = hookedWidgetRect.bottom(); break; case Fw::AnchorHorizontalCenter: point = hookedWidgetRect.horizontalCenter(); break; case Fw::AnchorVerticalCenter: point = hookedWidgetRect.verticalCenter(); break; default: // must never happens assert(false); break; } if(hookedWidget == parentWidget) { switch(anchor.getHookedEdge()) { case Fw::AnchorLeft: case Fw::AnchorRight: case Fw::AnchorHorizontalCenter: point -= parentWidget->getVirtualOffset().x; break; case Fw::AnchorBottom: case Fw::AnchorTop: case Fw::AnchorVerticalCenter: point -= parentWidget->getVirtualOffset().y; break; default: break; } } switch(anchor.getAnchoredEdge()) { case Fw::AnchorHorizontalCenter: newRect.moveHorizontalCenter(point + widget->getMarginLeft() - widget->getMarginRight()); horizontalMoved = true; break; case Fw::AnchorLeft: if(!horizontalMoved) { newRect.moveLeft(point + widget->getMarginLeft()); horizontalMoved = true; } else newRect.setLeft(point + widget->getMarginLeft()); break; case Fw::AnchorRight: if(!horizontalMoved) { newRect.moveRight(point - widget->getMarginRight()); horizontalMoved = true; } else newRect.setRight(point - widget->getMarginRight()); break; case Fw::AnchorVerticalCenter: newRect.moveVerticalCenter(point + widget->getMarginTop() - widget->getMarginBottom()); verticalMoved = true; break; case Fw::AnchorTop: if(!verticalMoved) { newRect.moveTop(point + widget->getMarginTop()); verticalMoved = true; } else newRect.setTop(point + widget->getMarginTop()); break; case Fw::AnchorBottom: if(!verticalMoved) { newRect.moveBottom(point - widget->getMarginBottom()); verticalMoved = true; } else newRect.setBottom(point - widget->getMarginBottom()); break; default: break; } } bool changed = false; if(widget->setRect(newRect)) changed = true; anchorGroup.setUpdated(true); return changed; }