mirror of
https://github.com/geode-sdk/geode.git
synced 2024-11-22 23:48:08 -05:00
attempting to add grid layout impl
This commit is contained in:
parent
e36a5aea35
commit
50cf18bcc4
13 changed files with 476 additions and 318 deletions
15
loader/include/Geode/cocos/base_nodes/CCNode.h
vendored
15
loader/include/Geode/cocos/base_nodes/CCNode.h
vendored
|
@ -941,6 +941,21 @@ public:
|
||||||
* @note Geode addition
|
* @note Geode addition
|
||||||
*/
|
*/
|
||||||
GEODE_DLL void updateLayout();
|
GEODE_DLL void updateLayout();
|
||||||
|
/**
|
||||||
|
* Set the layout options for this node. Layout options can be used to
|
||||||
|
* control how this node is positioned in its parent's Layout, for example
|
||||||
|
* setting the grow size for a flex layout
|
||||||
|
* @param options The layout options
|
||||||
|
* @param apply Whether to update the layout of the parent node
|
||||||
|
* @note Geode addition
|
||||||
|
*/
|
||||||
|
GEODE_DLL void setLayoutOptions(LayoutOptions* options, bool apply = true);
|
||||||
|
/**
|
||||||
|
* Get the layout options for this node
|
||||||
|
* @returns The current layout options, or nullptr if no options are set
|
||||||
|
* @note Geode addition
|
||||||
|
*/
|
||||||
|
GEODE_DLL LayoutOptions* getLayoutOptions();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Give a hint to the current Layout about where this node should be
|
* Give a hint to the current Layout about where this node should be
|
||||||
|
|
148
loader/include/Geode/cocos/base_nodes/Layout.hpp
vendored
148
loader/include/Geode/cocos/base_nodes/Layout.hpp
vendored
|
@ -32,6 +32,13 @@ public:
|
||||||
* have their PositionHint marked as absolute
|
* have their PositionHint marked as absolute
|
||||||
*/
|
*/
|
||||||
virtual void apply(CCNode* on) = 0;
|
virtual void apply(CCNode* on) = 0;
|
||||||
|
|
||||||
|
virtual ~Layout() = default;
|
||||||
|
};
|
||||||
|
|
||||||
|
class GEODE_DLL LayoutOptions {
|
||||||
|
public:
|
||||||
|
virtual ~LayoutOptions() = default;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -47,31 +54,49 @@ enum class PositionHint {
|
||||||
Absolute,
|
Absolute,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum class Axis {
|
||||||
|
Row,
|
||||||
|
Column,
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Specifies the alignment of something
|
* Specifies the alignment of something
|
||||||
*/
|
*/
|
||||||
enum class Alignment {
|
enum class AxisAlignment {
|
||||||
Begin,
|
// Align items to the start
|
||||||
|
// |ooo......|
|
||||||
|
Start,
|
||||||
|
// All items are centered
|
||||||
|
// |...ooo...|
|
||||||
Center,
|
Center,
|
||||||
|
// Align items to the end
|
||||||
|
// |......ooo|
|
||||||
End,
|
End,
|
||||||
|
// Each item gets the same portion from the layout (disregards gap)
|
||||||
|
// |.o..o..o.|
|
||||||
|
Even,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Layout for arranging nodes along an axis. Used to implement row, column, and
|
||||||
|
* grid layouts
|
||||||
|
*/
|
||||||
class GEODE_DLL AxisLayout : public Layout {
|
class GEODE_DLL AxisLayout : public Layout {
|
||||||
public:
|
|
||||||
enum Axis : bool {
|
|
||||||
Row,
|
|
||||||
Column,
|
|
||||||
};
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
Axis m_axis;
|
Axis m_axis;
|
||||||
Alignment m_axisAlignment = Alignment::Center;
|
AxisAlignment m_axisAlignment = AxisAlignment::Center;
|
||||||
Alignment m_crossAlignment = Alignment::Center;
|
AxisAlignment m_crossAlignment = AxisAlignment::Center;
|
||||||
float m_gap = 5.f;
|
float m_gap = 5.f;
|
||||||
bool m_autoScale = true;
|
bool m_autoScale = true;
|
||||||
bool m_shrinkCrossAxis = true;
|
bool m_axisReverse = false;
|
||||||
bool m_reverse = false;
|
bool m_crossReverse = false;
|
||||||
bool m_fitInside = false;
|
bool m_allowCrossAxisOverflow = true;
|
||||||
|
bool m_growCrossAxis = false;
|
||||||
|
|
||||||
|
struct Row;
|
||||||
|
|
||||||
|
Row* fitInRow(CCNode* on, CCArray* nodes, float scale, float squish) const;
|
||||||
|
void tryFitLayout(CCNode* on, CCArray* nodes, float scale, float squish) const;
|
||||||
|
|
||||||
AxisLayout(Axis);
|
AxisLayout(Axis);
|
||||||
|
|
||||||
|
@ -79,45 +104,44 @@ public:
|
||||||
void apply(CCNode* on) override;
|
void apply(CCNode* on) override;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets where to align nodes on the Y-axis. If nullopt, the
|
* Sets where to align the target node's children on the cross-axis (Y for
|
||||||
* nodes' Y-position will not be affected, and the height of the node this
|
* Row, X for Column)
|
||||||
* 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
|
|
||||||
*/
|
*/
|
||||||
AxisLayout* setCrossAxisAlignment(Alignment align);
|
AxisLayout* setCrossAxisAlignment(AxisAlignment align);
|
||||||
AxisLayout* setAxisAlignment(Alignment align);
|
/**
|
||||||
|
* Sets where to align the target node's children on the main axis (X for
|
||||||
|
* Row, Y for Column)
|
||||||
|
*/
|
||||||
|
AxisLayout* setAxisAlignment(AxisAlignment align);
|
||||||
/**
|
/**
|
||||||
* The spacing between the children of the node this layout applies to.
|
* The spacing between the children of the node this layout applies to.
|
||||||
* Measured as the space between their edges, not centres
|
* Measured as the space between their edges, not centres. Does not apply
|
||||||
|
* on the main / cross axis if their alignment is AxisAlignment::Even
|
||||||
*/
|
*/
|
||||||
AxisLayout* setGap(float gap);
|
AxisLayout* setGap(float gap);
|
||||||
/**
|
/**
|
||||||
* Whether to reverse the direction of the children in this layout or not
|
* Whether to reverse the direction of the children in this layout or not
|
||||||
*/
|
*/
|
||||||
AxisLayout* setReverse(bool reverse);
|
AxisLayout* setAxisReverse(bool reverse);
|
||||||
/**
|
/**
|
||||||
* If a value is provided, then the node this layout applies to may be
|
* Whether to reverse the direction of the rows on the cross-axis or not
|
||||||
* 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
|
AxisLayout* setCrossAxisReverse(bool reverse);
|
||||||
* 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
|
* If enabled, then the layout may scale the target's children if they are
|
||||||
* content size of the target node is what the content should be fit
|
* about to overflow. Assumes that all the childrens' intended scale is 1
|
||||||
* inside of, and scales to fit that space. If the value is nullopt, the
|
|
||||||
* unscaled content size is used instead
|
|
||||||
*/
|
*/
|
||||||
AxisLayout* setAutoScale(bool enable);
|
AxisLayout* setAutoScale(bool enable);
|
||||||
/**
|
/**
|
||||||
* If true, the children of the node this layout is applied to will be
|
* If true, if the main axis overflows extra nodes will be placed on new
|
||||||
* contained entirely within the bounds of the node's content size. If
|
* rows/columns on the cross-axis
|
||||||
* false, the children's positions will be within the bounds, but they may
|
|
||||||
* visually overflow depending on their anchor point
|
|
||||||
*/
|
*/
|
||||||
AxisLayout* setFitInside(bool fit);
|
AxisLayout* setGrowCrossAxis(bool expand);
|
||||||
AxisLayout* setShrinkCrossAxis(bool shrink);
|
/**
|
||||||
|
* If true, the cross-axis content size of the target node will be
|
||||||
|
* automatically adjusted to fit the children
|
||||||
|
*/
|
||||||
|
AxisLayout* setCrossAxisOverflow(bool allow);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -156,50 +180,4 @@ public:
|
||||||
static ColumnLayout* create();
|
static ColumnLayout* create();
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* Grid direction; which direction the grid should add its next row to if the
|
|
||||||
* current row is full
|
|
||||||
*/
|
|
||||||
enum class GridDirection {
|
|
||||||
// Downward
|
|
||||||
Column,
|
|
||||||
// Upward
|
|
||||||
ReverseColumn,
|
|
||||||
// Right
|
|
||||||
Row,
|
|
||||||
// Left
|
|
||||||
ReverseRow,
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Grid alignment; same as normal Alignment but also features the "Stretch"
|
|
||||||
* option which will stretch the row out to be the same size as the others
|
|
||||||
*/
|
|
||||||
enum class GridAlignment {
|
|
||||||
Begin,
|
|
||||||
Center,
|
|
||||||
Stretch,
|
|
||||||
End,
|
|
||||||
};
|
|
||||||
|
|
||||||
class GEODE_DLL GridLayout : public Layout {
|
|
||||||
protected:
|
|
||||||
GridDirection m_direction = GridDirection::Column;
|
|
||||||
GridAlignment m_alignment = GridAlignment::Center;
|
|
||||||
std::optional<size_t> m_rowSize;
|
|
||||||
|
|
||||||
public:
|
|
||||||
void apply(CCNode* on) override;
|
|
||||||
|
|
||||||
static GridLayout* create(
|
|
||||||
std::optional<size_t> rowSize,
|
|
||||||
GridAlignment alignment = GridAlignment::Center,
|
|
||||||
GridDirection direction = GridDirection::Column
|
|
||||||
);
|
|
||||||
|
|
||||||
GridLayout* setDirection(GridDirection direction);
|
|
||||||
GridLayout* setAlignment(GridAlignment alignment);
|
|
||||||
GridLayout* setRowSize(std::optional<size_t> rowSize);
|
|
||||||
};
|
|
||||||
|
|
||||||
NS_CC_END
|
NS_CC_END
|
||||||
|
|
15
loader/include/Geode/cocos/cocoa/CCArray.h
vendored
15
loader/include/Geode/cocos/cocoa/CCArray.h
vendored
|
@ -234,13 +234,11 @@ public:
|
||||||
void fastRemoveObject(CCObject* object);
|
void fastRemoveObject(CCObject* object);
|
||||||
/** Fast way to remove an element with a certain index */
|
/** Fast way to remove an element with a certain index */
|
||||||
void fastRemoveObjectAtIndex(unsigned int index);
|
void fastRemoveObjectAtIndex(unsigned int index);
|
||||||
|
|
||||||
RT_ADD(
|
|
||||||
/**
|
/**
|
||||||
* Rob modification
|
* Fast way to remove an element with a certain index
|
||||||
* Fast way to remove an element with a certain index */
|
* @note RobTop addition
|
||||||
|
*/
|
||||||
void fastRemoveObjectAtIndexNew(unsigned int index);
|
void fastRemoveObjectAtIndexNew(unsigned int index);
|
||||||
);
|
|
||||||
|
|
||||||
// Rearranging Content
|
// Rearranging Content
|
||||||
|
|
||||||
|
@ -263,6 +261,13 @@ public:
|
||||||
*/
|
*/
|
||||||
virtual CCObject* copyWithZone(CCZone* pZone);
|
virtual CCObject* copyWithZone(CCZone* pZone);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a shallow copy of this array, aka only clones the pointers to
|
||||||
|
* the array members and not the members themselves
|
||||||
|
* @returns New array with same members
|
||||||
|
*/
|
||||||
|
GEODE_DLL CCArray* shallowCopy();
|
||||||
|
|
||||||
/* override functions */
|
/* override functions */
|
||||||
virtual void acceptVisitor(CCDataVisitor &visitor);
|
virtual void acceptVisitor(CCDataVisitor &visitor);
|
||||||
|
|
||||||
|
|
|
@ -16,4 +16,10 @@ void CCArray::removeFirstObject(bool bReleaseObj) {
|
||||||
this->removeObjectAtIndex(0, bReleaseObj);
|
this->removeObjectAtIndex(0, bReleaseObj);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CCArray* CCArray::shallowCopy() {
|
||||||
|
auto r = CCArray::createWithCapacity(this->capacity());
|
||||||
|
r->addObjectsFromArray(this);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
#pragma warning(pop)
|
#pragma warning(pop)
|
||||||
|
|
|
@ -22,189 +22,268 @@ CCArray* Layout::getNodesToPosition(CCNode* on) {
|
||||||
return filtered;
|
return filtered;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AxisLayout::apply(CCNode* on) {
|
static constexpr float AXIS_MIN_SCALE = 0.65f;
|
||||||
auto nodes = getNodesToPosition(on);
|
|
||||||
if (m_reverse) {
|
|
||||||
nodes->reverseObjects();
|
|
||||||
}
|
|
||||||
|
|
||||||
float availableAxisLength;
|
struct AxisPosition {
|
||||||
float originalCrossHeight;
|
|
||||||
|
|
||||||
if (m_axis == Axis::Row) {
|
|
||||||
availableAxisLength = on->getContentSize().width;
|
|
||||||
originalCrossHeight = on->getContentSize().height;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
availableAxisLength = on->getContentSize().height;
|
|
||||||
originalCrossHeight = on->getContentSize().width;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t ix = 0;
|
|
||||||
float totalAxisLength = .0f;
|
|
||||||
float maxCrossLength = 0.f;
|
|
||||||
for (auto& node : CCArrayExt<CCNode*>(nodes)) {
|
|
||||||
float axisLength;
|
|
||||||
float axisAnchor;
|
|
||||||
float crossLength;
|
|
||||||
if (m_axis == Axis::Row) {
|
|
||||||
axisLength = node->getScaledContentSize().width;
|
|
||||||
axisAnchor = node->getAnchorPoint().x;
|
|
||||||
crossLength = node->getScaledContentSize().height;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
axisLength = node->getScaledContentSize().height;
|
|
||||||
axisAnchor = node->getAnchorPoint().y;
|
|
||||||
crossLength = node->getScaledContentSize().width;
|
|
||||||
}
|
|
||||||
// if no need to fit fully inside and only one item exists, the total
|
|
||||||
// width taken up is 0
|
|
||||||
if (nodes->count() == 1 && !m_fitInside) {
|
|
||||||
totalAxisLength = 0;
|
|
||||||
}
|
|
||||||
// if no need to fit fully inside, figure out what part may overflow
|
|
||||||
// for first item
|
|
||||||
else if (ix == 0 && !m_fitInside) {
|
|
||||||
totalAxisLength += axisLength * (1.f - axisAnchor);
|
|
||||||
}
|
|
||||||
// if no need to fit fully inside, figure out what part may overflow
|
|
||||||
// for last item
|
|
||||||
else if (ix == nodes->count() - 1 && !m_fitInside) {
|
|
||||||
totalAxisLength += axisLength * axisAnchor;
|
|
||||||
}
|
|
||||||
// otherwise either we need to fit fully inside or this node is not
|
|
||||||
// at the start or end
|
|
||||||
else {
|
|
||||||
totalAxisLength += axisLength;
|
|
||||||
}
|
|
||||||
if (ix) {
|
|
||||||
totalAxisLength += m_gap;
|
|
||||||
}
|
|
||||||
if (crossLength > maxCrossLength) {
|
|
||||||
maxCrossLength = crossLength;
|
|
||||||
}
|
|
||||||
ix++;
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto minScale = .65f;
|
|
||||||
|
|
||||||
// assume intended scale is 1x
|
|
||||||
auto setScale = 1.f;
|
|
||||||
auto squeeze = 1.f;
|
|
||||||
|
|
||||||
// check for overflow
|
|
||||||
// first try to make the node smaller
|
|
||||||
if (totalAxisLength > availableAxisLength && m_autoScale) {
|
|
||||||
setScale = availableAxisLength / totalAxisLength;
|
|
||||||
if (setScale < minScale) {
|
|
||||||
setScale = minScale;
|
|
||||||
}
|
|
||||||
totalAxisLength *= setScale;
|
|
||||||
}
|
|
||||||
|
|
||||||
// if we're still overflowing, squeeze nodes closer together
|
|
||||||
if (totalAxisLength > availableAxisLength) {
|
|
||||||
squeeze = availableAxisLength / totalAxisLength;
|
|
||||||
totalAxisLength = availableAxisLength;
|
|
||||||
}
|
|
||||||
|
|
||||||
// resize target to match settings
|
|
||||||
if (m_shrinkCrossAxis) {
|
|
||||||
if (m_axis == Axis::Row) {
|
|
||||||
on->setContentSize({
|
|
||||||
availableAxisLength,
|
|
||||||
maxCrossLength,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
on->setContentSize({
|
|
||||||
maxCrossLength,
|
|
||||||
availableAxisLength,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
float pos;
|
|
||||||
switch (m_axisAlignment) {
|
|
||||||
case Alignment::Begin: {
|
|
||||||
pos = 0.f;
|
|
||||||
} break;
|
|
||||||
|
|
||||||
case Alignment::Center: {
|
|
||||||
pos = availableAxisLength / 2 - totalAxisLength / 2;
|
|
||||||
} break;
|
|
||||||
|
|
||||||
case Alignment::End: {
|
|
||||||
pos = availableAxisLength - totalAxisLength;
|
|
||||||
} break;
|
|
||||||
}
|
|
||||||
ix = 0;
|
|
||||||
for (auto& node : CCArrayExt<CCNode*>(nodes)) {
|
|
||||||
// rescale node if overflowing
|
|
||||||
if (m_autoScale) {
|
|
||||||
// CCMenuItemSpriteExtra is quirky af
|
|
||||||
if (auto btn = typeinfo_cast<CCMenuItemSpriteExtra*>(node)) {
|
|
||||||
btn->m_baseScale = setScale;
|
|
||||||
}
|
|
||||||
node->setScale(setScale);
|
|
||||||
}
|
|
||||||
float axisLength;
|
float axisLength;
|
||||||
float axisAnchor;
|
float axisAnchor;
|
||||||
float crossLength;
|
float crossLength;
|
||||||
float crossAnchor;
|
float crossAnchor;
|
||||||
|
};
|
||||||
|
|
||||||
|
static AxisPosition nodeAxis(CCNode* node, Axis axis, float scale) {
|
||||||
|
auto scaledSize = node->getScaledContentSize() * scale;
|
||||||
|
auto anchor = node->getAnchorPoint();
|
||||||
|
if (axis == Axis::Row) {
|
||||||
|
return AxisPosition {
|
||||||
|
.axisLength = scaledSize.width,
|
||||||
|
.axisAnchor = anchor.x,
|
||||||
|
.crossLength = scaledSize.height,
|
||||||
|
.crossAnchor = anchor.y,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return AxisPosition {
|
||||||
|
.axisLength = scaledSize.height,
|
||||||
|
.axisAnchor = anchor.y,
|
||||||
|
.crossLength = scaledSize.width,
|
||||||
|
.crossAnchor = anchor.x,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct AxisLayout::Row : public CCObject {
|
||||||
|
float nextOverflowScaleDownFactor;
|
||||||
|
float nextOverflowSquichFactor;
|
||||||
|
float axisLength;
|
||||||
|
float crossLength;
|
||||||
|
Ref<CCArray> nodes;
|
||||||
|
|
||||||
|
Row(
|
||||||
|
float scaleFactor,
|
||||||
|
float squishFactor,
|
||||||
|
float axisLength,
|
||||||
|
float crossLength,
|
||||||
|
CCArray* nodes
|
||||||
|
) : nextOverflowScaleDownFactor(scaleFactor),
|
||||||
|
nextOverflowSquichFactor(squishFactor),
|
||||||
|
axisLength(axisLength),
|
||||||
|
crossLength(crossLength),
|
||||||
|
nodes(nodes)
|
||||||
|
{
|
||||||
|
this->autorelease();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
AxisLayout::Row* AxisLayout::fitInRow(CCNode* on, CCArray* nodes, float scale, float squish) const {
|
||||||
|
float nextAxisLength = 0.f;
|
||||||
|
float axisLength;
|
||||||
|
float crossLength = 0.f;
|
||||||
|
auto res = CCArray::create();
|
||||||
|
|
||||||
|
auto available = nodeAxis(on, m_axis, 1.f);
|
||||||
|
size_t ix = 0;
|
||||||
|
for (auto& node : CCArrayExt<CCNode*>(nodes)) {
|
||||||
|
auto pos = nodeAxis(node, m_axis, scale * squish);
|
||||||
|
nextAxisLength += pos.axisLength;
|
||||||
|
// if multiple rows are allowed and this row is full, time for the
|
||||||
|
// next row
|
||||||
|
if (m_growCrossAxis && nextAxisLength > available.axisLength) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
res->addObject(node);
|
||||||
|
nodes->removeFirstObject();
|
||||||
|
if (ix) {
|
||||||
|
nextAxisLength += m_gap * squish;
|
||||||
|
axisLength += m_gap * squish;
|
||||||
|
}
|
||||||
|
axisLength += pos.axisLength;
|
||||||
|
if (pos.crossLength > crossLength) {
|
||||||
|
crossLength = pos.crossLength;
|
||||||
|
}
|
||||||
|
ix++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// reverse row if needed
|
||||||
|
if (m_axisReverse) {
|
||||||
|
res->reverseObjects();
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Row(
|
||||||
|
// how much should the nodes be scaled down to fit the next row
|
||||||
|
available.axisLength / (
|
||||||
|
nextAxisLength - m_gap * (res->count() - 1)
|
||||||
|
) * scale * squish,
|
||||||
|
available.axisLength / nextAxisLength * scale * squish,
|
||||||
|
axisLength,
|
||||||
|
crossLength,
|
||||||
|
res
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AxisLayout::tryFitLayout(CCNode* on, CCArray* nodes, float scale, float squish) const {
|
||||||
|
auto rows = CCArray::create();
|
||||||
|
float totalRowCrossLength = 0.f;
|
||||||
|
float crossScaleDownFactor = AXIS_MIN_SCALE;
|
||||||
|
float squishFactor = 1.f;
|
||||||
|
size_t ix = 0;
|
||||||
|
|
||||||
|
// fit everything into rows while possible
|
||||||
|
auto newNodes = nodes->shallowCopy();
|
||||||
|
while (newNodes->count()) {
|
||||||
|
auto row = this->fitInRow(on, newNodes, scale, squish);
|
||||||
|
rows->addObject(row);
|
||||||
|
if (
|
||||||
|
row->nextOverflowScaleDownFactor > crossScaleDownFactor &&
|
||||||
|
crossScaleDownFactor < 1.f
|
||||||
|
) {
|
||||||
|
crossScaleDownFactor = row->nextOverflowScaleDownFactor;
|
||||||
|
}
|
||||||
|
if (row->nextOverflowSquichFactor < squishFactor) {
|
||||||
|
squishFactor = row->nextOverflowSquichFactor;
|
||||||
|
}
|
||||||
|
totalRowCrossLength += row->crossLength;
|
||||||
|
if (ix) {
|
||||||
|
totalRowCrossLength += m_gap;
|
||||||
|
}
|
||||||
|
ix++;
|
||||||
|
}
|
||||||
|
newNodes->release();
|
||||||
|
|
||||||
|
auto available = nodeAxis(on, m_axis, 1.f);
|
||||||
|
|
||||||
|
// if cross axis overflow not allowed, try to scale down layout
|
||||||
|
if (!m_allowCrossAxisOverflow && totalRowCrossLength > available.crossLength) {
|
||||||
|
if (m_autoScale && scale > AXIS_MIN_SCALE) {
|
||||||
|
rows->release();
|
||||||
|
return this->tryFitLayout(on, nodes, crossScaleDownFactor, squish);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// if we're still overflowing, squeeze nodes closer together
|
||||||
|
if (totalRowCrossLength > available.crossLength) {
|
||||||
|
// if squishing rows would take less squishing that squishing columns,
|
||||||
|
// then squish rows
|
||||||
|
if (totalRowCrossLength / available.crossLength < squishFactor) {
|
||||||
|
rows->release();
|
||||||
|
return this->tryFitLayout(on, nodes, scale, squishFactor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// if we're here, the nodes are ready to be positioned
|
||||||
|
|
||||||
|
if (m_crossReverse) {
|
||||||
|
rows->reverseObjects();
|
||||||
|
}
|
||||||
|
|
||||||
|
// resize cross axis if needed
|
||||||
|
if (m_allowCrossAxisOverflow) {
|
||||||
|
available.crossLength = totalRowCrossLength;
|
||||||
if (m_axis == Axis::Row) {
|
if (m_axis == Axis::Row) {
|
||||||
axisLength = node->getScaledContentSize().width;
|
log::debug("axisLength: {}, totalRowCrossLength: {}", available.axisLength, totalRowCrossLength);
|
||||||
axisAnchor = node->getAnchorPoint().x;
|
on->setContentSize({
|
||||||
crossLength = node->getScaledContentSize().height;
|
available.axisLength,
|
||||||
crossAnchor = node->getAnchorPoint().y;
|
totalRowCrossLength,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
axisLength = node->getScaledContentSize().height;
|
on->setContentSize({
|
||||||
axisAnchor = node->getAnchorPoint().y;
|
totalRowCrossLength,
|
||||||
crossLength = node->getScaledContentSize().width;
|
available.axisLength,
|
||||||
crossAnchor = node->getAnchorPoint().x;
|
});
|
||||||
}
|
}
|
||||||
float axisPos;
|
|
||||||
if (ix == 0 && !m_fitInside) {
|
|
||||||
axisPos = pos;
|
|
||||||
pos += (axisLength * (1.f - axisAnchor) + m_gap * setScale) * squeeze;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
axisPos = pos + axisLength * axisAnchor * squeeze;
|
|
||||||
pos += (axisLength + m_gap * setScale) * squeeze;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
float crossPos;
|
float crossPos;
|
||||||
switch (m_crossAlignment) {
|
switch (m_crossAlignment) {
|
||||||
case Alignment::Begin: {
|
case AxisAlignment::Start: {
|
||||||
crossPos = crossLength * crossAnchor;
|
crossPos = 0.f;
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case Alignment::Center: {
|
case AxisAlignment::Center: {
|
||||||
crossPos = maxCrossLength / 2 - crossLength * (.5f - crossAnchor);
|
crossPos = available.crossLength / 2 - totalRowCrossLength / 2;
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case Alignment::End: {
|
case AxisAlignment::End: {
|
||||||
crossPos = maxCrossLength - crossLength * (1.f - crossAnchor);
|
crossPos = available.crossLength - totalRowCrossLength;
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case AxisAlignment::Even: {
|
||||||
|
crossPos = 0.f;
|
||||||
} break;
|
} break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (auto row : CCArrayExt<Row*>(rows)) {
|
||||||
|
float rowAxisPos;
|
||||||
|
switch (m_axisAlignment) {
|
||||||
|
case AxisAlignment::Start: {
|
||||||
|
rowAxisPos = 0.f;
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case AxisAlignment::Even: {
|
||||||
|
rowAxisPos = 0.f;
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case AxisAlignment::Center: {
|
||||||
|
rowAxisPos = available.axisLength / 2 - row->axisLength / 2;
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case AxisAlignment::End: {
|
||||||
|
rowAxisPos = available.axisLength - row->axisLength;
|
||||||
|
} break;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto& node : CCArrayExt<CCNode*>(row->nodes)) {
|
||||||
|
// rescale node if overflowing
|
||||||
|
if (m_autoScale) {
|
||||||
|
// CCMenuItemSpriteExtra is quirky af
|
||||||
|
if (auto btn = typeinfo_cast<CCMenuItemSpriteExtra*>(node)) {
|
||||||
|
btn->m_baseScale = scale;
|
||||||
|
}
|
||||||
|
node->setScale(scale);
|
||||||
|
}
|
||||||
|
auto pos = nodeAxis(node, m_axis, scale * squish);
|
||||||
|
float axisPos = rowAxisPos + pos.axisLength * pos.axisAnchor;
|
||||||
|
float crossPos;
|
||||||
|
switch (m_crossAlignment) {
|
||||||
|
case AxisAlignment::Start: {
|
||||||
|
crossPos = pos.crossLength * pos.crossAnchor;
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case AxisAlignment::Center: case AxisAlignment::Even: {
|
||||||
|
crossPos = row->crossLength / 2 - pos.crossLength * (.5f - pos.crossAnchor);
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case AxisAlignment::End: {
|
||||||
|
crossPos = row->crossLength - pos.crossLength * (1.f - pos.crossAnchor);
|
||||||
|
} break;
|
||||||
|
}
|
||||||
|
log::debug("axisPos: {}", axisPos);
|
||||||
|
log::debug("crossPos: {}", crossPos);
|
||||||
if (m_axis == Axis::Row) {
|
if (m_axis == Axis::Row) {
|
||||||
node->setPosition(axisPos, crossPos);
|
node->setPosition(axisPos, crossPos);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
node->setPosition(crossPos, axisPos);
|
node->setPosition(crossPos, axisPos);
|
||||||
}
|
}
|
||||||
ix++;
|
rowAxisPos += pos.axisLength + m_gap * squish;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AxisLayout::apply(CCNode* on) {
|
||||||
|
auto nodes = getNodesToPosition(on);
|
||||||
|
this->tryFitLayout(on, nodes, 1.f, 1.f);
|
||||||
}
|
}
|
||||||
|
|
||||||
AxisLayout::AxisLayout(Axis axis) : m_axis(axis) {}
|
AxisLayout::AxisLayout(Axis axis) : m_axis(axis) {}
|
||||||
|
|
||||||
AxisLayout* AxisLayout::setCrossAxisAlignment(Alignment align) {
|
AxisLayout* AxisLayout::setCrossAxisAlignment(AxisAlignment align) {
|
||||||
m_crossAlignment = align;
|
m_crossAlignment = align;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
AxisLayout* AxisLayout::setAxisAlignment(Alignment align) {
|
AxisLayout* AxisLayout::setAxisAlignment(AxisAlignment align) {
|
||||||
m_axisAlignment = align;
|
m_axisAlignment = align;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
@ -214,8 +293,18 @@ AxisLayout* AxisLayout::setGap(float gap) {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
AxisLayout* AxisLayout::setReverse(bool reverse) {
|
AxisLayout* AxisLayout::setAxisReverse(bool reverse) {
|
||||||
m_reverse = reverse;
|
m_axisReverse = reverse;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
AxisLayout* AxisLayout::setCrossAxisReverse(bool reverse) {
|
||||||
|
m_crossReverse = reverse;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
AxisLayout* AxisLayout::setCrossAxisOverflow(bool fit) {
|
||||||
|
m_allowCrossAxisOverflow = fit;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -224,56 +313,19 @@ AxisLayout* AxisLayout::setAutoScale(bool scale) {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
AxisLayout* AxisLayout::setFitInside(bool fit) {
|
AxisLayout* AxisLayout::setGrowCrossAxis(bool shrink) {
|
||||||
m_fitInside = fit;
|
m_growCrossAxis = shrink;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
AxisLayout* AxisLayout::setShrinkCrossAxis(bool shrink) {
|
RowLayout::RowLayout() : AxisLayout(Axis::Row) {}
|
||||||
m_shrinkCrossAxis = shrink;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
RowLayout::RowLayout() : AxisLayout(AxisLayout::Row) {}
|
|
||||||
|
|
||||||
RowLayout* RowLayout::create() {
|
RowLayout* RowLayout::create() {
|
||||||
return new RowLayout();
|
return new RowLayout();
|
||||||
}
|
}
|
||||||
|
|
||||||
ColumnLayout::ColumnLayout() : AxisLayout(AxisLayout::Column) {}
|
ColumnLayout::ColumnLayout() : AxisLayout(Axis::Column) {}
|
||||||
|
|
||||||
ColumnLayout* ColumnLayout::create() {
|
ColumnLayout* ColumnLayout::create() {
|
||||||
return new ColumnLayout();
|
return new ColumnLayout();
|
||||||
}
|
}
|
||||||
|
|
||||||
void GridLayout::apply(CCNode* on) {
|
|
||||||
// todo
|
|
||||||
}
|
|
||||||
|
|
||||||
GridLayout* GridLayout::create(
|
|
||||||
std::optional<size_t> rowSize,
|
|
||||||
GridAlignment alignment,
|
|
||||||
GridDirection direction
|
|
||||||
) {
|
|
||||||
auto ret = new GridLayout;
|
|
||||||
ret->m_rowSize = rowSize;
|
|
||||||
ret->m_alignment = alignment;
|
|
||||||
ret->m_direction = direction;
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
GridLayout* GridLayout::setDirection(GridDirection direction) {
|
|
||||||
m_direction = direction;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
GridLayout* GridLayout::setAlignment(GridAlignment alignment) {
|
|
||||||
m_alignment = alignment;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
GridLayout* GridLayout::setRowSize(std::optional<size_t> rowSize) {
|
|
||||||
m_rowSize = rowSize;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
|
@ -20,6 +20,7 @@ private:
|
||||||
Ref<cocos2d::CCObject> m_userObject;
|
Ref<cocos2d::CCObject> m_userObject;
|
||||||
std::string m_id = "";
|
std::string m_id = "";
|
||||||
std::unique_ptr<Layout> m_layout = nullptr;
|
std::unique_ptr<Layout> m_layout = nullptr;
|
||||||
|
std::unique_ptr<LayoutOptions> m_layoutOptions = nullptr;
|
||||||
PositionHint m_positionHint = PositionHint::Default;
|
PositionHint m_positionHint = PositionHint::Default;
|
||||||
std::unordered_map<std::string, std::any> m_attributes;
|
std::unordered_map<std::string, std::any> m_attributes;
|
||||||
|
|
||||||
|
@ -135,6 +136,17 @@ Layout* CCNode::getLayout() {
|
||||||
return GeodeNodeMetadata::set(this)->m_layout.get();
|
return GeodeNodeMetadata::set(this)->m_layout.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CCNode::setLayoutOptions(LayoutOptions* options, bool apply) {
|
||||||
|
GeodeNodeMetadata::set(this)->m_layoutOptions.reset(options);
|
||||||
|
if (apply && m_pParent) {
|
||||||
|
m_pParent->updateLayout();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
LayoutOptions* CCNode::getLayoutOptions() {
|
||||||
|
return GeodeNodeMetadata::set(this)->m_layoutOptions.get();
|
||||||
|
}
|
||||||
|
|
||||||
void CCNode::updateLayout() {
|
void CCNode::updateLayout() {
|
||||||
if (auto layout = GeodeNodeMetadata::set(this)->m_layout.get()) {
|
if (auto layout = GeodeNodeMetadata::set(this)->m_layout.get()) {
|
||||||
layout->apply(this);
|
layout->apply(this);
|
||||||
|
|
|
@ -26,33 +26,55 @@ $register_ids(CreatorLayer) {
|
||||||
|
|
||||||
// move vault button to its own menu
|
// move vault button to its own menu
|
||||||
if (auto lockBtn = setIDSafe(menu, -2, "vault-button")) {
|
if (auto lockBtn = setIDSafe(menu, -2, "vault-button")) {
|
||||||
detachAndCreateMenu(
|
auto menu = detachAndCreateMenu(
|
||||||
this,
|
this,
|
||||||
"top-right-menu",
|
"top-right-menu",
|
||||||
ColumnLayout::create()
|
ColumnLayout::create()
|
||||||
->setFitInside(false)
|
->setAxisAlignment(AxisAlignment::End),
|
||||||
->setAxisAlignment(Alignment::Begin),
|
|
||||||
lockBtn
|
lockBtn
|
||||||
)->setAnchorPoint({ .5f, 0.f });
|
);
|
||||||
|
menu->setPositionY(menu->getPositionY() - 125.f / 2);
|
||||||
|
menu->setContentSize({ 60.f, 125.f });
|
||||||
|
menu->updateLayout();
|
||||||
}
|
}
|
||||||
|
|
||||||
// move treasure room button to its own menu
|
// move treasure room button to its own menu
|
||||||
if (auto roomBtn = setIDSafe(menu, -1, "treasure-room-button")) {
|
if (auto roomBtn = setIDSafe(menu, -1, "treasure-room-button")) {
|
||||||
detachAndCreateMenu(
|
auto menu = detachAndCreateMenu(
|
||||||
this,
|
this,
|
||||||
"bottom-right-menu",
|
"bottom-right-menu",
|
||||||
ColumnLayout::create()
|
ColumnLayout::create()
|
||||||
->setFitInside(false)
|
->setAxisAlignment(AxisAlignment::Start),
|
||||||
->setAxisAlignment(Alignment::End),
|
|
||||||
roomBtn
|
roomBtn
|
||||||
)->setAnchorPoint({ .5f, 1.f });
|
);
|
||||||
|
menu->setPositionY(menu->getPositionY() + 125.f / 2);
|
||||||
|
menu->setContentSize({ 60.f, 125.f });
|
||||||
|
menu->updateLayout();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (auto menu = getChildOfType<CCMenu>(this, 1)) {
|
if (auto menu = getChildOfType<CCMenu>(this, 1)) {
|
||||||
menu->setID("exit-menu");
|
menu->setID("exit-menu");
|
||||||
setIDSafe(menu, 0, "exit-button");
|
setIDSafe(menu, 0, "exit-button");
|
||||||
|
menu->setPositionY(menu->getPositionY() - 125.f / 2);
|
||||||
|
menu->setContentSize({ 60.f, 125.f });
|
||||||
|
menu->setLayout(
|
||||||
|
ColumnLayout::create()
|
||||||
|
->setAxisAlignment(AxisAlignment::End)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// add a menu to the bottom left corner that is empty but prolly a place mods
|
||||||
|
// want to add stuff to
|
||||||
|
auto menu = CCMenu::create();
|
||||||
|
menu->setPosition(24.f, 24.f + 125.f / 2);
|
||||||
|
menu->setID("bottom-left-menu");
|
||||||
|
menu->setContentSize({ 60.f, 125.f });
|
||||||
|
menu->setLayout(
|
||||||
|
ColumnLayout::create()
|
||||||
|
->setAxisAlignment(AxisAlignment::Start)
|
||||||
|
);
|
||||||
|
this->addChild(menu);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct CreatorLayerIDs : Modify<CreatorLayerIDs, CreatorLayer> {
|
struct CreatorLayerIDs : Modify<CreatorLayerIDs, CreatorLayer> {
|
||||||
|
|
|
@ -30,6 +30,8 @@ $register_ids(EditLevelLayer) {
|
||||||
"info-button-menu"
|
"info-button-menu"
|
||||||
);
|
);
|
||||||
|
|
||||||
|
auto winSize = CCDirector::get()->getWinSize();
|
||||||
|
|
||||||
if (auto menu = this->getChildByID("level-action-menu")) {
|
if (auto menu = this->getChildByID("level-action-menu")) {
|
||||||
setIDs(menu, 0, "edit-button", "play-button", "share-button");
|
setIDs(menu, 0, "edit-button", "play-button", "share-button");
|
||||||
}
|
}
|
||||||
|
@ -52,16 +54,15 @@ $register_ids(EditLevelLayer) {
|
||||||
menu->getPositionX() + static_cast<CCNode*>(
|
menu->getPositionX() + static_cast<CCNode*>(
|
||||||
menu->getChildren()->firstObject()
|
menu->getChildren()->firstObject()
|
||||||
)->getPositionX(),
|
)->getPositionX(),
|
||||||
285.f
|
winSize.height / 2
|
||||||
);
|
);
|
||||||
|
menu->setContentSize({ 60.f, winSize.height - 50.f });
|
||||||
menu->setLayout(
|
menu->setLayout(
|
||||||
ColumnLayout::create()
|
ColumnLayout::create()
|
||||||
->setGap(7.f)
|
->setGap(7.f)
|
||||||
->setFitInside(false)
|
->setAxisAlignment(AxisAlignment::Start)
|
||||||
->setAxisAlignment(Alignment::Begin)
|
->setAxisReverse(true)
|
||||||
->setReverse(true)
|
|
||||||
);
|
);
|
||||||
menu->setAnchorPoint({ .5f, 0.f });
|
|
||||||
menu->setZOrder(1);
|
menu->setZOrder(1);
|
||||||
|
|
||||||
for (int i = 0; i < rand() % 4; i++) {
|
for (int i = 0; i < rand() % 4; i++) {
|
||||||
|
|
|
@ -42,15 +42,23 @@ $register_ids(EditorUI) {
|
||||||
"unlink-button"
|
"unlink-button"
|
||||||
);
|
);
|
||||||
|
|
||||||
detachAndCreateMenu(
|
auto toolbarTogglesMenu = detachAndCreateMenu(
|
||||||
this,
|
this,
|
||||||
"toolbar-toggles-menu",
|
"toolbar-toggles-menu",
|
||||||
GridLayout::create(2, GridAlignment::Begin, GridDirection::Column),
|
ColumnLayout::create()
|
||||||
|
->setCrossAxisOverflow(false)
|
||||||
|
->setAxisAlignment(AxisAlignment::Even)
|
||||||
|
->setCrossAxisAlignment(AxisAlignment::Even),
|
||||||
menu->getChildByID("swipe-button"),
|
menu->getChildByID("swipe-button"),
|
||||||
menu->getChildByID("free-move-button"),
|
menu->getChildByID("free-move-button"),
|
||||||
menu->getChildByID("snap-button"),
|
menu->getChildByID("snap-button"),
|
||||||
menu->getChildByID("rotate-button")
|
menu->getChildByID("rotate-button")
|
||||||
);
|
);
|
||||||
|
toolbarTogglesMenu->setPosition(
|
||||||
|
toolbarTogglesMenu->getPosition() - CCPoint { 50.f, 50.f }
|
||||||
|
);
|
||||||
|
toolbarTogglesMenu->setContentSize({ 100.f, 100.f });
|
||||||
|
toolbarTogglesMenu->updateLayout();
|
||||||
|
|
||||||
detachAndCreateMenu(
|
detachAndCreateMenu(
|
||||||
this,
|
this,
|
||||||
|
@ -108,24 +116,40 @@ $register_ids(EditorUI) {
|
||||||
"delete-help-icon"
|
"delete-help-icon"
|
||||||
);
|
);
|
||||||
|
|
||||||
detachAndCreateMenu(
|
auto deleteButtonMenu = detachAndCreateMenu(
|
||||||
menu,
|
menu,
|
||||||
"delete-button-menu",
|
"delete-button-menu",
|
||||||
GridLayout::create(2, GridAlignment::Begin, GridDirection::Column),
|
ColumnLayout::create()
|
||||||
|
->setCrossAxisOverflow(false)
|
||||||
|
->setAxisAlignment(AxisAlignment::Even)
|
||||||
|
->setCrossAxisAlignment(AxisAlignment::Even),
|
||||||
menu->getChildByID("delete-button"),
|
menu->getChildByID("delete-button"),
|
||||||
menu->getChildByID("delete-all-of-button"),
|
menu->getChildByID("delete-all-of-button"),
|
||||||
menu->getChildByID("delete-startpos-button")
|
menu->getChildByID("delete-startpos-button")
|
||||||
);
|
);
|
||||||
|
deleteButtonMenu->setPosition(
|
||||||
|
deleteButtonMenu->getPosition() - CCPoint { 50.f, 50.f }
|
||||||
|
);
|
||||||
|
deleteButtonMenu->setContentSize({ 100.f, 100.f });
|
||||||
|
deleteButtonMenu->updateLayout();
|
||||||
|
|
||||||
detachAndCreateMenu(
|
auto deleteFilterMenu = detachAndCreateMenu(
|
||||||
menu,
|
menu,
|
||||||
"delete-filter-menu",
|
"delete-filter-menu",
|
||||||
GridLayout::create(2, GridAlignment::Begin, GridDirection::Column),
|
ColumnLayout::create()
|
||||||
|
->setCrossAxisOverflow(false)
|
||||||
|
->setAxisAlignment(AxisAlignment::Even)
|
||||||
|
->setCrossAxisAlignment(AxisAlignment::Even),
|
||||||
menu->getChildByID("delete-filter-none"),
|
menu->getChildByID("delete-filter-none"),
|
||||||
menu->getChildByID("delete-filter-static"),
|
menu->getChildByID("delete-filter-static"),
|
||||||
menu->getChildByID("delete-filter-detail"),
|
menu->getChildByID("delete-filter-detail"),
|
||||||
menu->getChildByID("delete-filter-custom")
|
menu->getChildByID("delete-filter-custom")
|
||||||
);
|
);
|
||||||
|
deleteFilterMenu->setPosition(
|
||||||
|
deleteFilterMenu->getPosition() - CCPoint { 50.f, 50.f }
|
||||||
|
);
|
||||||
|
deleteFilterMenu->setContentSize({ 100.f, 100.f });
|
||||||
|
deleteFilterMenu->updateLayout();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (auto menu = getChildOfType<CCMenu>(this, 2)) {
|
if (auto menu = getChildOfType<CCMenu>(this, 2)) {
|
||||||
|
@ -174,20 +198,25 @@ $register_ids(EditorUI) {
|
||||||
"all-layers-button"
|
"all-layers-button"
|
||||||
);
|
);
|
||||||
|
|
||||||
detachAndCreateMenu(
|
auto topRightMenu = detachAndCreateMenu(
|
||||||
this,
|
this,
|
||||||
"top-right-menu",
|
"top-right-menu",
|
||||||
RowLayout::create()
|
RowLayout::create()
|
||||||
->setFitInside(false)
|
->setAxisAlignment(AxisAlignment::End),
|
||||||
->setAxisAlignment(Alignment::End),
|
|
||||||
menu->getChildByID("pause-button"),
|
menu->getChildByID("pause-button"),
|
||||||
menu->getChildByID("settings-button")
|
menu->getChildByID("settings-button")
|
||||||
)->setAnchorPoint({ 1.f, .5f });
|
);
|
||||||
|
topRightMenu->setContentSize({ 60.f, 125.f });
|
||||||
|
topRightMenu->setPositionX(topRightMenu->getPositionX() - 125.f / 2);
|
||||||
|
topRightMenu->updateLayout();
|
||||||
|
|
||||||
detachAndCreateMenu(
|
auto rightMenu = detachAndCreateMenu(
|
||||||
this,
|
this,
|
||||||
"editor-buttons-menu",
|
"editor-buttons-menu",
|
||||||
GridLayout::create(4, GridAlignment::End, GridDirection::Column),
|
ColumnLayout::create()
|
||||||
|
->setAxisAlignment(AxisAlignment::Even)
|
||||||
|
->setCrossAxisAlignment(AxisAlignment::End)
|
||||||
|
->setCrossAxisReverse(true),
|
||||||
menu->getChildByID("copy-paste-button"),
|
menu->getChildByID("copy-paste-button"),
|
||||||
menu->getChildByID("edit-object-button"),
|
menu->getChildByID("edit-object-button"),
|
||||||
menu->getChildByID("paste-color-button"),
|
menu->getChildByID("paste-color-button"),
|
||||||
|
@ -201,6 +230,9 @@ $register_ids(EditorUI) {
|
||||||
menu->getChildByID("copy-values-button"),
|
menu->getChildByID("copy-values-button"),
|
||||||
menu->getChildByID("hsv-button")
|
menu->getChildByID("hsv-button")
|
||||||
);
|
);
|
||||||
|
rightMenu->setContentSize({ 125.f, 125.f });
|
||||||
|
rightMenu->setPosition(rightMenu->getPosition() - CCPoint { 125.f, 125.f });
|
||||||
|
rightMenu->updateLayout();
|
||||||
|
|
||||||
detachAndCreateMenu(
|
detachAndCreateMenu(
|
||||||
this,
|
this,
|
||||||
|
|
|
@ -18,22 +18,40 @@ $register_ids(LevelBrowserLayer) {
|
||||||
setIDSafe(menu, 0, "new-level-button");
|
setIDSafe(menu, 0, "new-level-button");
|
||||||
|
|
||||||
if (auto myLevelsBtn = setIDSafe(menu, 1, "my-levels-button")) {
|
if (auto myLevelsBtn = setIDSafe(menu, 1, "my-levels-button")) {
|
||||||
detachAndCreateMenu(
|
auto menu = detachAndCreateMenu(
|
||||||
this,
|
this,
|
||||||
"my-levels-menu",
|
"my-levels-menu",
|
||||||
ColumnLayout::create()
|
ColumnLayout::create()
|
||||||
->setFitInside(false)
|
->setAxisAlignment(AxisAlignment::Start),
|
||||||
->setAxisAlignment(Alignment::End),
|
|
||||||
myLevelsBtn
|
myLevelsBtn
|
||||||
)->setAnchorPoint({ .5f, 1.f });
|
);
|
||||||
|
menu->setPositionY(menu->getPositionY() + 100.f / 2);
|
||||||
|
menu->setContentSize({ 50.f, 100.f });
|
||||||
|
menu->updateLayout();
|
||||||
}
|
}
|
||||||
|
|
||||||
menu->setLayout(
|
menu->setLayout(
|
||||||
ColumnLayout::create()
|
ColumnLayout::create()
|
||||||
->setFitInside(false)
|
->setAxisAlignment(AxisAlignment::Start)
|
||||||
->setAxisAlignment(Alignment::End)
|
|
||||||
);
|
);
|
||||||
menu->setAnchorPoint({ .5f, 1.f });
|
menu->setPositionY(menu->getPositionY() + 150.f / 2);
|
||||||
|
menu->setContentSize({ 50.f, 150.f });
|
||||||
|
menu->updateLayout();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (auto menu = getChildOfType<CCMenu>(this, 1)) {
|
||||||
|
if (auto searchBtn = setIDSafe(menu, 5, "search-button")) {
|
||||||
|
auto menu = detachAndCreateMenu(
|
||||||
|
this,
|
||||||
|
"search-menu",
|
||||||
|
ColumnLayout::create()
|
||||||
|
->setAxisAlignment(AxisAlignment::Start),
|
||||||
|
searchBtn
|
||||||
|
);
|
||||||
|
menu->setPositionY(menu->getPositionY() + 50.f / 2);
|
||||||
|
menu->setContentSize({ 50.f, 50.f });
|
||||||
|
menu->updateLayout();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,14 +43,16 @@ $register_ids(LevelInfoLayer) {
|
||||||
menu->setID("right-side-menu");
|
menu->setID("right-side-menu");
|
||||||
|
|
||||||
if (auto name = setIDSafe(menu, 0, "creator-name")) {
|
if (auto name = setIDSafe(menu, 0, "creator-name")) {
|
||||||
detachAndCreateMenu(
|
auto menu = detachAndCreateMenu(
|
||||||
this,
|
this,
|
||||||
"creator-info-menu",
|
"creator-info-menu",
|
||||||
ColumnLayout::create()
|
ColumnLayout::create()
|
||||||
->setFitInside(false)
|
->setAxisAlignment(AxisAlignment::Start),
|
||||||
->setAxisAlignment(Alignment::Begin),
|
|
||||||
name
|
name
|
||||||
)->setAnchorPoint({ .5f, 0.f });
|
);
|
||||||
|
menu->setPositionY(menu->getPositionY() + 100.f / 2);
|
||||||
|
menu->setContentSize({ 60.f, 100.f });
|
||||||
|
menu->updateLayout();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto leftSideMenu = CCMenu::create();
|
auto leftSideMenu = CCMenu::create();
|
||||||
|
|
|
@ -162,14 +162,15 @@ $register_ids(LevelSettingsLayer) {
|
||||||
menu->getChildByID("2-player-toggle")
|
menu->getChildByID("2-player-toggle")
|
||||||
);
|
);
|
||||||
|
|
||||||
detachAndCreateMenu(
|
auto fontButtonMenu = detachAndCreateMenu(
|
||||||
this,
|
this,
|
||||||
"font-button-menu",
|
"font-button-menu",
|
||||||
RowLayout::create()
|
RowLayout::create()
|
||||||
->setFitInside(false)
|
->setAxisAlignment(AxisAlignment::End),
|
||||||
->setAxisAlignment(Alignment::End),
|
|
||||||
menu->getChildByID("font-button")
|
menu->getChildByID("font-button")
|
||||||
)->setAnchorPoint({ .5f, 1.f });
|
);
|
||||||
|
fontButtonMenu->setPositionY(fontButtonMenu->getPositionY() - 100.f / 2);
|
||||||
|
fontButtonMenu->setContentSize({ 50.f, 100.f });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -41,18 +41,27 @@ $register_ids(MenuLayer) {
|
||||||
setIDSafe(menu, 2, "editor-button");
|
setIDSafe(menu, 2, "editor-button");
|
||||||
|
|
||||||
if (auto pfp = setIDSafe(menu, 3, "profile-button")) {
|
if (auto pfp = setIDSafe(menu, 3, "profile-button")) {
|
||||||
detachAndCreateMenu(
|
auto profileMenu = detachAndCreateMenu(
|
||||||
this, "profile-menu",
|
this, "profile-menu",
|
||||||
ColumnLayout::create()
|
ColumnLayout::create()
|
||||||
->setFitInside(false)
|
->setAxisAlignment(AxisAlignment::Start)
|
||||||
->setAxisAlignment(Alignment::Begin)
|
->setAxisReverse(true),
|
||||||
->setReverse(true),
|
|
||||||
pfp
|
pfp
|
||||||
)->setAnchorPoint({ .5f, .0f });
|
);
|
||||||
|
profileMenu->setContentSize({ 50.f, 200.f });
|
||||||
|
profileMenu->setPositionY(
|
||||||
|
profileMenu->getPositionY() + 200.f / 2 -
|
||||||
|
pfp->getScaledContentSize().height / 2
|
||||||
|
);
|
||||||
|
profileMenu->updateLayout();
|
||||||
}
|
}
|
||||||
|
|
||||||
menu->setContentSize({ 400.f, 65.f });
|
menu->setContentSize({ 400.f, 65.f });
|
||||||
menu->setLayout(RowLayout::create()->setGap(18.f));
|
menu->setLayout(
|
||||||
|
RowLayout::create()
|
||||||
|
->setGap(18.f)
|
||||||
|
->setCrossAxisOverflow(true)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
// bottom menu
|
// bottom menu
|
||||||
if (auto menu = getChildOfType<CCMenu>(this, 1)) {
|
if (auto menu = getChildOfType<CCMenu>(this, 1)) {
|
||||||
|
@ -68,7 +77,7 @@ $register_ids(MenuLayer) {
|
||||||
auto menu = detachAndCreateMenu(
|
auto menu = detachAndCreateMenu(
|
||||||
this,
|
this,
|
||||||
"right-side-menu",
|
"right-side-menu",
|
||||||
ColumnLayout::create()->setFitInside(true),
|
ColumnLayout::create(),
|
||||||
dailyChest
|
dailyChest
|
||||||
);
|
);
|
||||||
menu->setContentSize({ 65.f, 180.f });
|
menu->setContentSize({ 65.f, 180.f });
|
||||||
|
@ -76,7 +85,7 @@ $register_ids(MenuLayer) {
|
||||||
}
|
}
|
||||||
|
|
||||||
menu->setContentSize({ 360.f, 65.f });
|
menu->setContentSize({ 360.f, 65.f });
|
||||||
menu->setLayout(RowLayout::create()->setFitInside(true));
|
menu->setLayout(RowLayout::create());
|
||||||
}
|
}
|
||||||
// social media menu
|
// social media menu
|
||||||
if (auto menu = getChildOfType<CCMenu>(this, 2)) {
|
if (auto menu = getChildOfType<CCMenu>(this, 2)) {
|
||||||
|
@ -94,14 +103,19 @@ $register_ids(MenuLayer) {
|
||||||
// move close button to its own menu
|
// move close button to its own menu
|
||||||
|
|
||||||
if (auto closeBtn = setIDSafe(menu, 1, "close-button")) {
|
if (auto closeBtn = setIDSafe(menu, 1, "close-button")) {
|
||||||
detachAndCreateMenu(
|
auto closeMenu = detachAndCreateMenu(
|
||||||
this,
|
this,
|
||||||
"close-menu",
|
"close-menu",
|
||||||
RowLayout::create()
|
RowLayout::create()
|
||||||
->setFitInside(false)
|
->setAxisAlignment(AxisAlignment::Start),
|
||||||
->setAxisAlignment(Alignment::Begin),
|
|
||||||
closeBtn
|
closeBtn
|
||||||
)->setAnchorPoint({ 0.f, .5f });
|
);
|
||||||
|
closeMenu->setContentSize({ 200.f, 50.f });
|
||||||
|
closeMenu->setPositionX(
|
||||||
|
closeMenu->getPositionX() + 200.f / 2 -
|
||||||
|
closeBtn->getScaledContentSize().width / 2
|
||||||
|
);
|
||||||
|
closeMenu->updateLayout();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue