From d23563a9c0b08760eb64a257cf6e275e147a120a Mon Sep 17 00:00:00 2001 From: HJfod <60038575+HJfod@users.noreply.github.com> Date: Sat, 4 Feb 2023 11:28:33 +0200 Subject: [PATCH] Revert "working on a layout rewrite" This reverts commit ecbfd5ad0fbb638bcf81bd496598e47877b0e21e. --- .../include/Geode/cocos/base_nodes/CCNode.h | 7 +- .../include/Geode/cocos/base_nodes/Layout.hpp | 131 ++++------------- loader/src/cocos2d-ext/Layout.cpp | 135 +++++------------- loader/src/hooks/GeodeNodeMetadata.cpp | 18 +-- loader/src/ids/CreatorLayer.cpp | 4 +- loader/src/ids/EditLevelLayer.cpp | 25 +--- loader/src/ids/MenuLayer.cpp | 10 +- 7 files changed, 80 insertions(+), 250 deletions(-) diff --git a/loader/include/Geode/cocos/base_nodes/CCNode.h b/loader/include/Geode/cocos/base_nodes/CCNode.h index cc091cbb..62916885 100644 --- a/loader/include/Geode/cocos/base_nodes/CCNode.h +++ b/loader/include/Geode/cocos/base_nodes/CCNode.h @@ -921,14 +921,9 @@ public: * has been added, call updateLayout * @param layout Layout to set to this node * @param apply Whether to call updateLayout now or not - * @param respectAnchor If true, if the target node is - * isIgnoreAnchorPointForPosition, then it is set to false and the children - * are automatically moved to match where they should be positioned. - * Visually, this should result in no difference; however, when dealing with - * CCLayers / CCMenus, this will change where the children are located * @note Geode addition */ - GEODE_DLL void setLayout(Layout* layout, bool apply = true, bool respectAnchor = true); + GEODE_DLL void setLayout(Layout* layout, bool apply = true); /** * Get the Layout for this node * @returns The current layout, or nullptr if no layout is set diff --git a/loader/include/Geode/cocos/base_nodes/Layout.hpp b/loader/include/Geode/cocos/base_nodes/Layout.hpp index a24aebec..1367986c 100644 --- a/loader/include/Geode/cocos/base_nodes/Layout.hpp +++ b/loader/include/Geode/cocos/base_nodes/Layout.hpp @@ -18,20 +18,15 @@ class CCNode; * RowLayout, ColumnLayout, and GridLayout, but if you need a different kind * of layout you can inherit from the Layout class. */ -class GEODE_DLL Layout { -protected: - static CCArray* getNodesToPosition(CCNode* forNode); - +class Layout { public: /** * Automatically apply the layout's positioning on a set of nodes - * @param on Node to apply the layout on. Position's the node's children - * according to the layout. The content size of the node should be - * respected as a boundary the layout shouldn't overflow. The node may be - * rescaled to better fit its contents. Layouts should respect nodes that - * have their PositionHint marked as absolute + * @param nodes Nodes to position + * @param availableSize Give hints to the layout about how much space is + * available. Note that the layout may still overflow */ - virtual void apply(CCNode* on) = 0; + virtual void apply(CCArray* nodes, CCSize const& availableSize) = 0; }; /** @@ -61,62 +56,30 @@ enum class Alignment { */ class GEODE_DLL RowLayout : public Layout { protected: - std::optional m_vAlignment = Alignment::Center; + Alignment m_alignment = Alignment::Center; + std::optional m_alignVertically; float m_gap; - std::optional m_maxAutoScale = std::nullopt; - bool m_reverse = false; - bool m_fitInside = false; public: - void apply(CCNode* on) override; + void apply(CCArray* nodes, CCSize const& availableSize) override; /** * Create a new RowLayout. Note that this class is not automatically * managed by default, so you must assign it to a CCNode or manually - * manage the memory yourself. See the chainable setters on RowLayout for - * what options you can customize for the layout + * manage the memory yourself. + * @param gap Space between nodes + * @param alignVertically Whether to align the nodes vertically, and if so, + * what Y position to align them at * @returns Created RowLayout */ - static RowLayout* create(); + static RowLayout* create( + float gap = 5.f, + std::optional alignVertically = std::nullopt + ); - /** - * Sets where to align nodes on the Y-axis. If nullopt, the - * nodes' Y-position will not be affected, and the height of the node this - * layout applies to isn't altered. If an alignment is given, the height - * of the node this layout applies to is shrunk to fit the height of the - * nodes and no more. Any nodes that don't fit inside this space are - * aligned based on the value - * @param align Value - * @returns The same RowLayout this was applied on - */ - RowLayout* setVAlignment(std::optional align); - /** - * The spacing between the children of the node this layout applies to. - * Measured as the space between their edges, not centres - */ + RowLayout* setAlignment(Alignment align); RowLayout* setGap(float gap); - /** - * Whether to reverse the direction of the children in this layout or not - */ - RowLayout* setReverse(bool reverse); - /** - * If a value is provided, then the node this layout applies to may be - * automatically rescaled to fit its contents better. By default the value - * is nullopt, which means that the layout doesn't affect the node's scale - * in any way, and any nodes that might overflow will be squished using - * other methods. If the value is set, the layout assumes that the scaled - * content size of the target node is what the content should be fit - * inside of, and scales to fit that space. If the value is nullopt, the - * unscaled content size is used instead - */ - RowLayout* setMaxAutoScale(std::optional scale); - /** - * If true, the children of the node this layout is applied to will be - * contained entirely within the bounds of the node's content size. If - * false, the children's positions will be within the bounds, but they may - * visually overflow depending on their anchor point - */ - RowLayout* setFitInside(bool fit); + RowLayout* setAlignVertically(std::optional align); }; /** @@ -124,59 +87,21 @@ public: */ class GEODE_DLL ColumnLayout : public Layout { protected: - std::optional m_hAlignment = Alignment::Center; + Alignment m_alignment = Alignment::Center; + std::optional m_alignHorizontally; float m_gap; - std::optional m_maxAutoScale = std::nullopt; - bool m_reverse = false; - bool m_fitInside = false; public: - void apply(CCNode* on) override; + void apply(CCArray* nodes, CCSize const& availableSize) override; - /** - * Create a new ColumnLayout. Note that this class is not automatically - * managed by default, so you must assign it to a CCNode or manually - * manage the memory yourself. See the chainable setters on RowLayout for - * what options you can customize for the layout - * @returns Created ColumnLayout - */ - static ColumnLayout* create(); + static ColumnLayout* create( + float gap = 5.f, + std::optional alignHorizontally = std::nullopt + ); - /** - * Sets where to align nodes on the X-axis. If nullopt, the - * nodes' X-position will not be affected, and the width of the node this - * layout applies to isn't altered. If an alignment is given, the width - * of the node this layout applies to is shrunk to fit the width of the - * nodes and no more. Any nodes that don't fit inside this space are - * aligned based on the value - * @param align Value - * @returns The same RowLayout this was applied on - */ - ColumnLayout* setHAlignment(std::optional align); - /** - * The spacing between the children of the node this layout applies to. - * Measured as the space between their edges, not centres - */ + ColumnLayout* setAlignment(Alignment align); ColumnLayout* setGap(float gap); - /** - * Whether to reverse the direction of the children in this layout or not - */ - ColumnLayout* setReverse(bool reverse); - /** - * If a value is provided, then the node this layout applies to may be - * automatically rescaled to fit its contents better. By default the value - * is nullopt, which means that the layout doesn't affect the node's scale - * in any way, and any nodes that might overflow will be squished using - * other methods - */ - ColumnLayout* setMaxAutoScale(std::optional scale); - /** - * If true, the children of the node this layout is applied to will be - * contained entirely within the bounds of the node's content size. If - * false, the children's positions will be within the bounds, but they may - * visually overflow depending on their anchor point - */ - ColumnLayout* setFitInside(bool fit); + ColumnLayout* setAlignHorizontally(std::optional align); }; /** @@ -212,7 +137,7 @@ protected: std::optional m_rowSize; public: - void apply(CCNode* on) override; + void apply(CCArray* nodes, CCSize const& availableSize) override; static GridLayout* create( std::optional rowSize, diff --git a/loader/src/cocos2d-ext/Layout.cpp b/loader/src/cocos2d-ext/Layout.cpp index fd2d3367..c02b4cd3 100644 --- a/loader/src/cocos2d-ext/Layout.cpp +++ b/loader/src/cocos2d-ext/Layout.cpp @@ -1,7 +1,5 @@ #include #include -#include -#include USE_GEODE_NAMESPACE(); @@ -11,58 +9,17 @@ void CCNode::swapChildIndices(CCNode* first, CCNode* second) { m_pChildren->exchangeObject(first, second); } -CCArray* Layout::getNodesToPosition(CCNode* on) { - auto filtered = CCArray::create(); - for (auto& child : CCArrayExt(on->getChildren())) { - if (child->getPositionHint() != PositionHint::Absolute) { - filtered->addObject(child); - } - } - return filtered; -} - -void RowLayout::apply(CCNode* on) { - - auto nodes = getNodesToPosition(on); - if (m_reverse) { - nodes->reverseObjects(); - } - - auto availableWidth = m_maxAutoScale.has_value() ? - on->getScaledContentSize().width : - on->getContentSize().width; - - size_t ix = 0; +void RowLayout::apply(CCArray* nodes, CCSize const& availableSize) { float totalWidth = .0f; + size_t ix = 0; for (auto& node : CCArrayExt(nodes)) { - // if no need to fit fully inside, figure out what part may overflow - // for first item - if (ix == 0 && !m_fitInside) { - totalWidth += node->getScaledContentSize().width - * (1.f - node->getAnchorPoint().x); - } - // if no need to fit fully inside, figure out what part may overflow - // for last item - else if (ix == nodes->count() - 1 && !m_fitInside) { - totalWidth += node->getScaledContentSize().width - * node->getAnchorPoint().x; - } - // otherwise either we need to fit fully inside or this node is not - // at the start or end - else { - totalWidth += node->getScaledContentSize().width; - } + totalWidth += node->getScaledContentSize().width; if (ix) { totalWidth += m_gap; } ix++; } - auto squeeze = availableSize.width / totalWidth; - if (squeeze > 1.f) { - squeeze = 1.f; - } - float pos; switch (m_alignment) { default: @@ -83,16 +40,22 @@ void RowLayout::apply(CCNode* on) { if (m_alignVertically) { node->setPositionY(m_alignVertically.value()); } - pos += (sw + m_gap) * squeeze; + pos += sw + m_gap; } } -RowLayout* RowLayout::create() { - return new RowLayout(); +RowLayout* RowLayout::create( + float gap, + std::optional alignVertically +) { + auto ret = new RowLayout; + ret->m_gap = gap; + ret->m_alignVertically = alignVertically; + return ret; } -RowLayout* RowLayout::setVAlignment(std::optional align) { - m_vAlignment = align; +RowLayout* RowLayout::setAlignment(Alignment align) { + m_alignment = align; return this; } @@ -101,26 +64,14 @@ RowLayout* RowLayout::setGap(float gap) { return this; } -RowLayout* RowLayout::setReverse(bool reverse) { - m_reverse = reverse; +RowLayout* RowLayout::setAlignVertically(std::optional align) { + m_alignVertically = align; return this; } -RowLayout* RowLayout::setMaxAutoScale(std::optional scale) { - m_maxAutoScale = scale; - return this; -} - -RowLayout* RowLayout::setFitInside(bool fit) { - m_fitInside = fit; - return this; -} - -void ColumnLayout::apply(CCNode* on) { +void ColumnLayout::apply(CCArray* nodes, CCSize const& availableSize) { float totalHeight = .0f; size_t ix = 0; - auto nodes = getNodesToPosition(on); - auto availableSize = on->getScaledContentSize(); for (auto& node : CCArrayExt(nodes)) { totalHeight += node->getScaledContentSize().height; if (ix) { @@ -128,14 +79,6 @@ void ColumnLayout::apply(CCNode* on) { } } - auto squeeze = availableSize.height / totalHeight; - if (squeeze > 1.f) { - squeeze = 1.f; - } - if (totalHeight > availableSize.height) { - totalHeight = availableSize.height; - } - float pos; switch (m_alignment) { default: @@ -143,37 +86,35 @@ void ColumnLayout::apply(CCNode* on) { case Alignment::Begin: pos = -totalHeight; break; case Alignment::End: pos = 0.f; break; } - if (m_reverse) { - nodes->reverseObjects(); - } - log::debug("start pos: {}", pos); - log::debug("squeeze: {}", squeeze); for (auto& node : CCArrayExt(nodes)) { auto sh = node->getScaledContentSize().height; float disp; switch (m_alignment) { default: case Alignment::Center: disp = sh * node->getAnchorPoint().y; break; - case Alignment::Begin: disp = (m_reverse ? 0.f : sh); break; - case Alignment::End: disp = (m_reverse ? sh : 0.f); break; + case Alignment::Begin: disp = sh; break; + case Alignment::End: disp = 0.f; break; } - log::debug("positioning at: {}", pos + disp); node->setPositionY(pos + disp); if (m_alignHorizontally) { node->setPositionX(m_alignHorizontally.value()); } - auto opos = pos; - pos += (sh + m_gap) * squeeze; - log::debug("pos: {} -> {}", opos, pos); + pos += sh + m_gap; } } -ColumnLayout* ColumnLayout::create() { - return new ColumnLayout(); +ColumnLayout* ColumnLayout::create( + float gap, + std::optional alignHorizontally +) { + auto ret = new ColumnLayout; + ret->m_gap = gap; + ret->m_alignHorizontally = alignHorizontally; + return ret; } -ColumnLayout* ColumnLayout::setHAlignment(std::optional align) { - m_hAlignment = align; +ColumnLayout* ColumnLayout::setAlignment(Alignment align) { + m_alignment = align; return this; } @@ -182,22 +123,12 @@ ColumnLayout* ColumnLayout::setGap(float gap) { return this; } -ColumnLayout* ColumnLayout::setReverse(bool reverse) { - m_reverse = reverse; +ColumnLayout* ColumnLayout::setAlignHorizontally(std::optional align) { + m_alignHorizontally = align; return this; } -ColumnLayout* ColumnLayout::setMaxAutoScale(std::optional scale) { - m_maxAutoScale = scale; - return this; -} - -ColumnLayout* ColumnLayout::setFitInside(bool fit) { - m_fitInside = fit; - return this; -} - -void GridLayout::apply(CCNode* on) { +void GridLayout::apply(CCArray* nodes, CCSize const& availableSize) { // todo } diff --git a/loader/src/hooks/GeodeNodeMetadata.cpp b/loader/src/hooks/GeodeNodeMetadata.cpp index dfb707cc..777635ab 100644 --- a/loader/src/hooks/GeodeNodeMetadata.cpp +++ b/loader/src/hooks/GeodeNodeMetadata.cpp @@ -118,13 +118,7 @@ CCNode* CCNode::getChildByIDRecursive(std::string const& id) { return nullptr; } -void CCNode::setLayout(Layout* layout, bool apply, bool respectAnchor) { - if (respectAnchor && this->isIgnoreAnchorPointForPosition()) { - for (auto child : CCArrayExt(m_pChildren)) { - child->setPosition(child->getPosition() + this->getScaledContentSize()); - } - this->ignoreAnchorPointForPosition(false); - } +void CCNode::setLayout(Layout* layout, bool apply) { GeodeNodeMetadata::set(this)->m_layout.reset(layout); if (apply) { this->updateLayout(); @@ -137,7 +131,15 @@ Layout* CCNode::getLayout() { void CCNode::updateLayout() { if (auto layout = GeodeNodeMetadata::set(this)->m_layout.get()) { - layout->apply(this); + // nodes with absolute position should never be rearranged + auto filtered = CCArray::create(); + for (auto& child : CCArrayExt(m_pChildren)) { + if (child->getPositionHint() != PositionHint::Absolute) { + filtered->addObject(child); + } + } + layout->apply(filtered, m_obContentSize); + filtered->release(); } } diff --git a/loader/src/ids/CreatorLayer.cpp b/loader/src/ids/CreatorLayer.cpp index 4b2e2bee..d4745678 100644 --- a/loader/src/ids/CreatorLayer.cpp +++ b/loader/src/ids/CreatorLayer.cpp @@ -29,9 +29,9 @@ $register_ids(CreatorLayer) { detachAndCreateMenu( this, "top-right-menu", - ColumnLayout::create(), + ColumnLayout::create(5.f, 0.f)->setAlignment(Alignment::Begin), lockBtn - )->setAnchorPoint({ 0.f, 0.f }); + ); } // move treasure room button to its own menu diff --git a/loader/src/ids/EditLevelLayer.cpp b/loader/src/ids/EditLevelLayer.cpp index d8b9a010..8901f4cb 100644 --- a/loader/src/ids/EditLevelLayer.cpp +++ b/loader/src/ids/EditLevelLayer.cpp @@ -3,7 +3,6 @@ #include #include #include -#include USE_GEODE_NAMESPACE(); @@ -46,30 +45,8 @@ $register_ids(EditLevelLayer) { ); detachAndCreateMenu( - this, "folder-menu", ColumnLayout::create(), menu->getChildByID("folder-button") + menu, "folder-menu", ColumnLayout::create(), menu->getChildByID("folder-button") ); - menu->setPosition( - menu->getPositionX() + static_cast( - menu->getChildren()->firstObject() - )->getPositionX(), - 285.f - ); - menu->setLayout( - ColumnLayout::create() - ->setGap(7.f) - ->setReverse(true) - ->setAlignment(Alignment::Begin) - ->setAlignHorizontally(0.f) - ); - menu->setZOrder(1); - - for (int i = 0; i < rand() % 4; i++) { - auto btn = CircleButtonSprite::create( - CCLabelBMFont::create(std::to_string(i).c_str(), "bigFont.fnt") - ); - menu->addChild(btn); - } - menu->updateLayout(); } if (auto menu = this->getChildByID("back-button-menu")) setIDSafe(menu, 0, "back-button"); diff --git a/loader/src/ids/MenuLayer.cpp b/loader/src/ids/MenuLayer.cpp index 177ec766..a42364cb 100644 --- a/loader/src/ids/MenuLayer.cpp +++ b/loader/src/ids/MenuLayer.cpp @@ -44,7 +44,7 @@ $register_ids(MenuLayer) { pfp->setPositionHint(PositionHint::Absolute); } - menu->setLayout(RowLayout::create()->setGap(18.f)); + menu->setLayout(RowLayout::create(18.f, 0.f)); } // bottom menu if (auto menu = getChildOfType(this, 1)) { @@ -57,10 +57,10 @@ $register_ids(MenuLayer) { // move daily chest to its own menu if (auto dailyChest = setIDSafe(menu, -1, "daily-chest-button")) { - detachAndCreateMenu(this, "right-side-menu", ColumnLayout::create(), dailyChest); + detachAndCreateMenu(this, "right-side-menu", ColumnLayout::create(0.f, 0.f), dailyChest); } - menu->setLayout(RowLayout::create()); + menu->setLayout(RowLayout::create(5.f, ach->getPositionY())); } // social media menu if (auto menu = getChildOfType(this, 2)) { @@ -79,8 +79,8 @@ $register_ids(MenuLayer) { if (auto closeBtn = setIDSafe(menu, 1, "close-button")) { detachAndCreateMenu( - this, "close-menu", RowLayout::create(), closeBtn - )->setAnchorPoint({ 0.f, .5f }); + this, "close-menu", RowLayout::create(5.f, 0.f)->setAlignment(Alignment::Begin), closeBtn + ); } } }