mirror of
https://github.com/geode-sdk/geode.git
synced 2025-02-17 00:30:26 -05:00
adding new big stuff to layouts, this def wont work
also removed PositionHint
This commit is contained in:
parent
ffd50eb0f1
commit
3827a00964
7 changed files with 428 additions and 115 deletions
16
loader/include/Geode/cocos/base_nodes/CCNode.h
vendored
16
loader/include/Geode/cocos/base_nodes/CCNode.h
vendored
|
@ -973,22 +973,6 @@ public:
|
|||
*/
|
||||
GEODE_DLL LayoutOptions* getLayoutOptions();
|
||||
|
||||
/**
|
||||
* Give a hint to the current Layout about where this node should be
|
||||
* positioned in it. Allows detaching the node from the current
|
||||
* layout by setting position to absolute
|
||||
* @param hint The hint to set
|
||||
* @note The layout definitely should, but might not respect the hint
|
||||
* given
|
||||
* @note Geode addition
|
||||
*/
|
||||
GEODE_DLL void setPositionHint(PositionHint hint);
|
||||
/**
|
||||
* Get the current position hint for this node
|
||||
* @note Geode addition
|
||||
*/
|
||||
GEODE_DLL PositionHint getPositionHint();
|
||||
|
||||
/**
|
||||
* Swap two children
|
||||
* @param first One of the nodes to swap
|
||||
|
|
146
loader/include/Geode/cocos/base_nodes/Layout.hpp
vendored
146
loader/include/Geode/cocos/base_nodes/Layout.hpp
vendored
|
@ -28,8 +28,7 @@ public:
|
|||
* @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
|
||||
* rescaled to better fit its contents
|
||||
*/
|
||||
virtual void apply(CCNode* on) = 0;
|
||||
|
||||
|
@ -42,25 +41,15 @@ public:
|
|||
};
|
||||
|
||||
/**
|
||||
* Determines how a node should be positioned within its parent, if that
|
||||
* parent has an automatically positioning layout
|
||||
* The direction of an AxisLayout
|
||||
*/
|
||||
enum class PositionHint {
|
||||
// The container can determine the best position
|
||||
// for this node
|
||||
Default,
|
||||
// The container's layout should not affect the
|
||||
// position of this node
|
||||
Absolute,
|
||||
};
|
||||
|
||||
enum class Axis {
|
||||
Row,
|
||||
Column,
|
||||
};
|
||||
|
||||
/**
|
||||
* Specifies the alignment of something
|
||||
* Specifies the alignment of something in an AxisLayout
|
||||
*/
|
||||
enum class AxisAlignment {
|
||||
// Align items to the start
|
||||
|
@ -77,18 +66,46 @@ enum class AxisAlignment {
|
|||
Even,
|
||||
};
|
||||
|
||||
constexpr float AXISLAYOUT_DEFAULT_MIN_SCALE = 0.65f;
|
||||
constexpr int AXISLAYOUT_DEFAULT_PRIORITY = 0;
|
||||
|
||||
/**
|
||||
* Options for controlling the behaviour of individual nodes in an AxisLayout
|
||||
* @example
|
||||
* auto node = CCNode::create();
|
||||
* // this node will have 10 units of spacing between it and the next one
|
||||
* node->setLayoutOptions(
|
||||
* AxisLayoutOptions::create()
|
||||
* ->setNextGap(10.f)
|
||||
* );
|
||||
* someNodeWithALayout->addChild(node);
|
||||
*/
|
||||
class GEODE_DLL AxisLayoutOptions : public LayoutOptions {
|
||||
protected:
|
||||
std::optional<float> m_maxScale = 1.f;
|
||||
std::optional<bool> m_autoScale = std::nullopt;
|
||||
float m_maxScale = 1.f;
|
||||
float m_minScale = AXISLAYOUT_DEFAULT_MIN_SCALE;
|
||||
float m_relativeScale = 1.f;
|
||||
std::optional<float> m_length = std::nullopt;
|
||||
std::optional<float> m_nextGap = std::nullopt;
|
||||
std::optional<float> m_prevGap = std::nullopt;
|
||||
bool m_breakLine = false;
|
||||
bool m_sameLine = false;
|
||||
int m_scalePriority = AXISLAYOUT_DEFAULT_PRIORITY;
|
||||
|
||||
public:
|
||||
static AxisLayoutOptions* create();
|
||||
|
||||
std::optional<float> getMaxScale() const;
|
||||
std::optional<bool> getAutoScale() const;
|
||||
float getMaxScale() const;
|
||||
float getMinScale() const;
|
||||
float getRelativeScale() const;
|
||||
std::optional<float> getLength() const;
|
||||
std::optional<float> getPrevGap() const;
|
||||
std::optional<float> getNextGap() const;
|
||||
bool getBreakLine() const;
|
||||
bool getSameLine() const;
|
||||
int getScalePriority() const;
|
||||
|
||||
/**
|
||||
* Set the maximum scale this node can be if it's contained in an
|
||||
|
@ -97,11 +114,22 @@ public:
|
|||
AxisLayoutOptions* setMaxScale(float scale);
|
||||
|
||||
/**
|
||||
* Disables auto-scaling for this node, even if the layout the node is
|
||||
* contained in has it enabled. To enable auto-scaling, provide a max
|
||||
* scale for the node in setMaxScale
|
||||
* Set the minimum scale this node can be if it's contained in an
|
||||
* auto-scaled layout. Default is AXISLAYOUT_DEFAULT_MIN_SCALE
|
||||
*/
|
||||
AxisLayoutOptions* setMinScale(float scale);
|
||||
|
||||
/**
|
||||
* Set the relative scale of this node compared to other nodes if it's
|
||||
* contained in an auto-scaled layout. Default is 1
|
||||
*/
|
||||
AxisLayoutOptions* setRelativeScale(float scale);
|
||||
|
||||
/**
|
||||
* Set auto-scaling for this node, overriding the layout's auto-scale
|
||||
* setting. If nullopt, the layout's auto-scale options will be used
|
||||
*/
|
||||
AxisLayoutOptions* disableAutoScale();
|
||||
AxisLayoutOptions* setAutoScale(std::optional<bool> enabled);
|
||||
|
||||
/**
|
||||
* Set an absolute length for this node. If nullopt, the length will be
|
||||
|
@ -109,16 +137,67 @@ public:
|
|||
*/
|
||||
AxisLayoutOptions* setLength(std::optional<float> length);
|
||||
|
||||
/**
|
||||
* Override the default gap in the layout between this node and the
|
||||
* previous one. If nullopt, the default gap of the layout will be used
|
||||
*/
|
||||
AxisLayoutOptions* setPrevGap(std::optional<float> gap);
|
||||
|
||||
/**
|
||||
* Override the default gap in the layout between this node and the next
|
||||
* one. If nullopt, the default gap of the layout will be used
|
||||
*/
|
||||
AxisLayoutOptions* setNextGap(std::optional<float> gap);
|
||||
|
||||
/**
|
||||
* If enabled, the node will always cause a growable axis layout to break
|
||||
* into a new line even if the current line could've fit the next node
|
||||
*/
|
||||
AxisLayoutOptions* setBreakLine(bool enable);
|
||||
|
||||
/**
|
||||
* If enabled, the node will be forced to be on the same line as the
|
||||
* previous node even if doing this would overflow
|
||||
*/
|
||||
AxisLayoutOptions* setSameLine(bool enable);
|
||||
|
||||
/**
|
||||
* Set the scale priority of this node. Nodes with higher priority will be
|
||||
* scaled down first before nodes with lower priority when an auto-scaled
|
||||
* layout attempts to fit its contents. Default is
|
||||
* AXISLAYOUT_DEFAULT_PRIORITY
|
||||
* @note For optimal performance, the priorities should all be close to
|
||||
* each other with no gaps
|
||||
*/
|
||||
AxisLayoutOptions* setScalePriority(int priority);
|
||||
};
|
||||
|
||||
/**
|
||||
* Layout for arranging nodes along an axis. Used to implement row, column, and
|
||||
* grid layouts
|
||||
* A multi-purpose dynamic layout for arranging nodes along an axis. Can be
|
||||
* used to arrange nodes in a single line, a grid, or a flex layout. The
|
||||
* RowLayout and ColumnLayout classes function as simple thin wrappers over
|
||||
* AxisLayout. The positioning of individual nodes in the layout can be
|
||||
* further controlled using AxisLayoutOptions
|
||||
* @warning Calculating layouts can get increasingly expensive for large
|
||||
* amounts of child nodes being fit into a small space - while this should
|
||||
* never prove a real performance concern as most layouts only have a few
|
||||
* hundred children at the very most, be aware that you probably shouldn't
|
||||
* call CCNode::updateLayout every frame for a menu with thousands of children
|
||||
* @example
|
||||
* auto menu = CCMenu::create();
|
||||
* // The menu's children will be arranged horizontally, unless they overflow
|
||||
* // the content size width in which case a new line will be inserted and
|
||||
* // aligned to the left. The menu automatically will automatically grow in
|
||||
* // height to fit all the rows
|
||||
* menu->setLayout(
|
||||
* RowLayout::create()
|
||||
* ->setGap(10.f)
|
||||
* ->setGrowCrossAxis(true)
|
||||
* ->setAxisAlignment(AxisAlignment::Start)
|
||||
* );
|
||||
* menu->setContentSize({ 200.f, 0.f });
|
||||
* menu->addChild(...);
|
||||
* menu->updateLayout();
|
||||
*/
|
||||
class GEODE_DLL AxisLayout : public Layout {
|
||||
protected:
|
||||
|
@ -134,8 +213,27 @@ protected:
|
|||
|
||||
struct Row;
|
||||
|
||||
Row* fitInRow(CCNode* on, CCArray* nodes, float scale, float squish) const;
|
||||
void tryFitLayout(CCNode* on, CCArray* nodes, float scale, float squish) const;
|
||||
std::tuple<
|
||||
std::pair<int, int>,
|
||||
std::pair<float, float>,
|
||||
bool
|
||||
> findProps(CCArray* nodes) const;
|
||||
bool shouldAutoScale(AxisLayoutOptions* opts) const;
|
||||
float nextGap(AxisLayoutOptions* now, AxisLayoutOptions* next) const;
|
||||
Row* fitInRow(
|
||||
CCNode* on, CCArray* nodes,
|
||||
std::pair<float, float> const& minMaxScales,
|
||||
std::pair<int, int> const& minMaxPrios,
|
||||
bool doAutoScale,
|
||||
float scale, float squish, int prio
|
||||
) const;
|
||||
void tryFitLayout(
|
||||
CCNode* on, CCArray* nodes,
|
||||
std::pair<float, float> const& minMaxScales,
|
||||
std::pair<int, int> const& minMaxPrios,
|
||||
bool doAutoScale,
|
||||
float scale, float squish, int prio
|
||||
) const;
|
||||
|
||||
AxisLayout(Axis);
|
||||
|
||||
|
|
|
@ -58,6 +58,17 @@ namespace geode {
|
|||
return buf.str();
|
||||
}
|
||||
|
||||
template <class T>
|
||||
requires requires(T t) {
|
||||
parse(t);
|
||||
}
|
||||
std::string parse(std::optional<T> const& thing) {
|
||||
if (thing.has_value()) {
|
||||
return "opt(" + parse(thing.value()) + ")";
|
||||
}
|
||||
return "nullopt";
|
||||
}
|
||||
|
||||
// Log component system
|
||||
|
||||
struct GEODE_DLL ComponentTrait {
|
||||
|
|
|
@ -32,13 +32,10 @@ void CCNode::insertAfter(CCNode* child, CCNode* after) {
|
|||
}
|
||||
|
||||
CCArray* Layout::getNodesToPosition(CCNode* on) {
|
||||
auto filtered = CCArray::create();
|
||||
for (auto& child : CCArrayExt<CCNode>(on->getChildren())) {
|
||||
if (child->getPositionHint() != PositionHint::Absolute) {
|
||||
filtered->addObject(child);
|
||||
}
|
||||
if (!on->getChildren()) {
|
||||
return CCArray::create();
|
||||
}
|
||||
return filtered;
|
||||
return on->getChildren()->shallowCopy();
|
||||
}
|
||||
|
||||
static AxisLayoutOptions* axisOpts(CCNode* node) {
|
||||
|
@ -46,14 +43,64 @@ static AxisLayoutOptions* axisOpts(CCNode* node) {
|
|||
return typeinfo_cast<AxisLayoutOptions*>(node->getLayoutOptions());
|
||||
}
|
||||
|
||||
static bool isOptsBreakLine(CCNode* node) {
|
||||
if (auto opts = axisOpts(node)) {
|
||||
static bool isOptsBreakLine(AxisLayoutOptions* opts) {
|
||||
if (opts) {
|
||||
return opts->getBreakLine();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static constexpr float AXIS_MIN_SCALE = 0.65f;
|
||||
static bool isOptsSameLine(AxisLayoutOptions* opts) {
|
||||
if (opts) {
|
||||
return opts->getSameLine();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static int optsScalePrio(AxisLayoutOptions* opts) {
|
||||
if (opts) {
|
||||
return opts->getScalePriority();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static float optsMinScale(AxisLayoutOptions* opts) {
|
||||
if (opts) {
|
||||
return opts->getMinScale();
|
||||
}
|
||||
return AXISLAYOUT_DEFAULT_MIN_SCALE;
|
||||
}
|
||||
|
||||
static float optsMaxScale(AxisLayoutOptions* opts) {
|
||||
if (opts) {
|
||||
return opts->getMaxScale();
|
||||
}
|
||||
return 1.f;
|
||||
}
|
||||
|
||||
struct AxisLayout::Row : public CCObject {
|
||||
float nextOverflowScaleDownFactor;
|
||||
float axisLength;
|
||||
float crossLength;
|
||||
float axisEndsLength;
|
||||
// all layout calculations happen within a single frame so no Ref needed
|
||||
CCArray* nodes;
|
||||
|
||||
Row(
|
||||
float scaleFactor,
|
||||
float axisLength,
|
||||
float crossLength,
|
||||
float axisEndsLength,
|
||||
CCArray* nodes
|
||||
) : nextOverflowScaleDownFactor(scaleFactor),
|
||||
axisLength(axisLength),
|
||||
crossLength(crossLength),
|
||||
axisEndsLength(axisEndsLength),
|
||||
nodes(nodes)
|
||||
{
|
||||
this->autorelease();
|
||||
}
|
||||
};
|
||||
|
||||
struct AxisPosition {
|
||||
float axisLength;
|
||||
|
@ -91,73 +138,146 @@ static AxisPosition nodeAxis(CCNode* node, Axis axis, float scale) {
|
|||
}
|
||||
}
|
||||
|
||||
struct AxisLayout::Row : public CCObject {
|
||||
float nextOverflowScaleDownFactor;
|
||||
float axisLength;
|
||||
float crossLength;
|
||||
float axisEndsLength;
|
||||
Ref<CCArray> nodes;
|
||||
|
||||
Row(
|
||||
float scaleFactor,
|
||||
float axisLength,
|
||||
float crossLength,
|
||||
float axisEndsLength,
|
||||
CCArray* nodes
|
||||
) : nextOverflowScaleDownFactor(scaleFactor),
|
||||
axisLength(axisLength),
|
||||
crossLength(crossLength),
|
||||
axisEndsLength(axisEndsLength),
|
||||
nodes(nodes)
|
||||
{
|
||||
this->autorelease();
|
||||
float AxisLayout::nextGap(AxisLayoutOptions* now, AxisLayoutOptions* next) const {
|
||||
std::optional<float> gap;
|
||||
if (now) {
|
||||
gap = now->getNextGap();
|
||||
}
|
||||
};
|
||||
if (next && (!gap || gap.value() < next->getPrevGap())) {
|
||||
gap = next->getPrevGap();
|
||||
}
|
||||
return gap.value_or(m_gap);
|
||||
}
|
||||
|
||||
AxisLayout::Row* AxisLayout::fitInRow(CCNode* on, CCArray* nodes, float scale, float squish) const {
|
||||
bool AxisLayout::shouldAutoScale(AxisLayoutOptions* opts) const {
|
||||
if (!opts) return m_autoScale;
|
||||
return opts->getAutoScale().value_or(m_autoScale);
|
||||
}
|
||||
|
||||
std::tuple<
|
||||
std::pair<int, int>,
|
||||
std::pair<float, float>,
|
||||
bool
|
||||
> AxisLayout::findProps(CCArray* nodes) const {
|
||||
std::pair<int, int> minMaxPrio;
|
||||
std::pair<float, float> minMaxScale;
|
||||
bool doAutoScale = m_autoScale;
|
||||
bool first = true;
|
||||
for (auto node : CCArrayExt<CCNode>(nodes)) {
|
||||
int prio = 0;
|
||||
float max = 1.f;
|
||||
float min = AXISLAYOUT_DEFAULT_MIN_SCALE;
|
||||
if (auto opts = axisOpts(node)) {
|
||||
prio = opts->getScalePriority();
|
||||
max = opts->getMaxScale();
|
||||
min = opts->getMinScale();
|
||||
if (opts->getAutoScale().value_or(false)) {
|
||||
doAutoScale = true;
|
||||
}
|
||||
}
|
||||
if (first) {
|
||||
minMaxPrio = { prio, prio };
|
||||
minMaxScale = { min, max };
|
||||
first = false;
|
||||
}
|
||||
else {
|
||||
if (prio < minMaxPrio.first) {
|
||||
minMaxPrio.first = prio;
|
||||
}
|
||||
if (prio > minMaxPrio.second) {
|
||||
minMaxPrio.second = prio;
|
||||
}
|
||||
if (min < minMaxPrio.first) {
|
||||
minMaxPrio.first = min;
|
||||
}
|
||||
if (max > minMaxPrio.second) {
|
||||
minMaxPrio.second = max;
|
||||
}
|
||||
}
|
||||
}
|
||||
return { minMaxPrio, minMaxScale, doAutoScale };
|
||||
}
|
||||
|
||||
AxisLayout::Row* AxisLayout::fitInRow(
|
||||
CCNode* on, CCArray* nodes,
|
||||
std::pair<float, float> const& minMaxScales,
|
||||
std::pair<int, int> const& minMaxPrios,
|
||||
bool doAutoScale,
|
||||
float scale, float squish, int prio
|
||||
) const {
|
||||
float nextAxisLength = 0.f;
|
||||
float axisLength = 0.f;
|
||||
float crossLength = 0.f;
|
||||
auto res = CCArray::create();
|
||||
|
||||
auto available = nodeAxis(on, m_axis, 1.f);
|
||||
CCNode* prev = nullptr;
|
||||
AxisLayoutOptions* prev = nullptr;
|
||||
size_t ix = 0;
|
||||
for (auto& node : CCArrayExt<CCNode*>(nodes)) {
|
||||
if (m_autoScale) {
|
||||
if (auto opts = axisOpts(node)) {
|
||||
if (auto max = opts->getMaxScale()) {
|
||||
node->setScale(max.value());
|
||||
}
|
||||
auto opts = axisOpts(node);
|
||||
if (this->shouldAutoScale(opts)) {
|
||||
if (opts) {
|
||||
node->setScale(opts->getMaxScale() * opts->getRelativeScale());
|
||||
}
|
||||
else {
|
||||
node->setScale(1);
|
||||
}
|
||||
}
|
||||
auto pos = nodeAxis(node, m_axis, scale * squish);
|
||||
AxisPosition pos;
|
||||
// if this node's scale prio is higher than current, don't scale it
|
||||
// down
|
||||
if (prio > optsScalePrio(opts)) {
|
||||
pos = nodeAxis(node, m_axis, squish);
|
||||
}
|
||||
// otherwise if it matches scale it down by the factor
|
||||
else if (prio == optsScalePrio(opts)) {
|
||||
auto trueScale = scale;
|
||||
auto min = optsMinScale(opts);
|
||||
auto max = optsMaxScale(opts);
|
||||
if (trueScale < min) {
|
||||
trueScale = min;
|
||||
}
|
||||
if (trueScale > max) {
|
||||
trueScale = max;
|
||||
}
|
||||
pos = nodeAxis(node, m_axis, trueScale * squish);
|
||||
}
|
||||
// otherwise it's been scaled down to minimum
|
||||
else {
|
||||
pos = nodeAxis(node, m_axis, optsMinScale(opts) * squish);
|
||||
}
|
||||
nextAxisLength += pos.axisLength;
|
||||
// if multiple rows are allowed and this row is full, time for the
|
||||
// next row
|
||||
// also force at least one object to be added to this row, because if
|
||||
// it's too large for this row it's gonna be too large for all rows
|
||||
if (
|
||||
m_growCrossAxis && (
|
||||
(nextAxisLength > available.axisLength || isOptsBreakLine(prev)) &&
|
||||
ix != 0
|
||||
)
|
||||
m_growCrossAxis && ((
|
||||
(nextAxisLength > available.axisLength) &&
|
||||
ix != 0 &&
|
||||
!isOptsSameLine(opts)
|
||||
) || isOptsBreakLine(prev))
|
||||
) {
|
||||
break;
|
||||
}
|
||||
res->addObject(node);
|
||||
if (ix) {
|
||||
nextAxisLength += m_gap * scale * squish;
|
||||
axisLength += m_gap * scale * squish;
|
||||
auto gap = nextGap(prev, opts);
|
||||
// if we've exhausted all priority scale options, scale gap too
|
||||
if (prio == minMaxPrios.first) {
|
||||
nextAxisLength += gap * scale * squish;
|
||||
axisLength += gap * scale * squish;
|
||||
}
|
||||
else {
|
||||
nextAxisLength += gap * squish;
|
||||
axisLength += gap * squish;
|
||||
}
|
||||
}
|
||||
axisLength += pos.axisLength;
|
||||
if (pos.crossLength > crossLength) {
|
||||
crossLength = pos.crossLength;
|
||||
}
|
||||
prev = node;
|
||||
prev = opts;
|
||||
ix++;
|
||||
}
|
||||
|
||||
|
@ -191,7 +311,13 @@ AxisLayout::Row* AxisLayout::fitInRow(CCNode* on, CCArray* nodes, float scale, f
|
|||
);
|
||||
}
|
||||
|
||||
void AxisLayout::tryFitLayout(CCNode* on, CCArray* nodes, float scale, float squish) const {
|
||||
void AxisLayout::tryFitLayout(
|
||||
CCNode* on, CCArray* nodes,
|
||||
std::pair<float, float> const& minMaxScales,
|
||||
std::pair<int, int> const& minMaxPrios,
|
||||
bool doAutoScale,
|
||||
float scale, float squish, int prio
|
||||
) const {
|
||||
// where do all of these magical calculations come from?
|
||||
// idk i got tired of doing the math but they work so ¯\_(ツ)_/¯
|
||||
// like i genuinely have no clue fr why some of these work tho,
|
||||
|
@ -205,7 +331,11 @@ void AxisLayout::tryFitLayout(CCNode* on, CCArray* nodes, float scale, float squ
|
|||
size_t ix = 0;
|
||||
auto newNodes = nodes->shallowCopy();
|
||||
while (newNodes->count()) {
|
||||
auto row = this->fitInRow(on, newNodes, scale, squish);
|
||||
auto row = this->fitInRow(
|
||||
on, newNodes,
|
||||
minMaxScales, minMaxPrios, doAutoScale,
|
||||
scale, squish, prio
|
||||
);
|
||||
rows->addObject(row);
|
||||
if (
|
||||
row->nextOverflowScaleDownFactor > crossScaleDownFactor &&
|
||||
|
@ -224,10 +354,33 @@ void AxisLayout::tryFitLayout(CCNode* on, CCArray* nodes, float scale, float squ
|
|||
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 && crossScaleDownFactor > AXIS_MIN_SCALE) {
|
||||
if (
|
||||
!m_allowCrossAxisOverflow &&
|
||||
doAutoScale &&
|
||||
totalRowCrossLength > available.crossLength
|
||||
) {
|
||||
bool attemptRescale = false;
|
||||
if (
|
||||
crossScaleDownFactor < minMaxScales.first ||
|
||||
// if the scale down factor is the same as before, then we've
|
||||
// entered an infinite loop
|
||||
crossScaleDownFactor == scale
|
||||
) {
|
||||
if (prio > minMaxPrios.first) {
|
||||
prio -= 1;
|
||||
attemptRescale = true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
attemptRescale = true;
|
||||
}
|
||||
if (attemptRescale) {
|
||||
rows->release();
|
||||
return this->tryFitLayout(on, nodes, crossScaleDownFactor, squish);
|
||||
return this->tryFitLayout(
|
||||
on, nodes,
|
||||
minMaxScales, minMaxPrios, doAutoScale,
|
||||
crossScaleDownFactor, squish, prio
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -237,7 +390,11 @@ void AxisLayout::tryFitLayout(CCNode* on, CCArray* nodes, float scale, float squ
|
|||
// then squish rows
|
||||
if (totalRowCrossLength / available.crossLength < crossScaleDownFactor) {
|
||||
rows->release();
|
||||
return this->tryFitLayout(on, nodes, scale, crossScaleDownFactor);
|
||||
return this->tryFitLayout(
|
||||
on, nodes,
|
||||
minMaxScales, minMaxPrios, doAutoScale,
|
||||
scale, crossScaleDownFactor, prio
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -316,8 +473,8 @@ void AxisLayout::tryFitLayout(CCNode* on, CCArray* nodes, float scale, float squ
|
|||
row->axisLength /= scale * squish;
|
||||
if (m_autoScale) {
|
||||
rowScale = available.axisLength / row->axisLength;
|
||||
if (rowScale < AXIS_MIN_SCALE) {
|
||||
rowScale = AXIS_MIN_SCALE;
|
||||
if (rowScale < AXISLAYOUT_DEFAULT_MIN_SCALE) {
|
||||
rowScale = AXISLAYOUT_DEFAULT_MIN_SCALE;
|
||||
}
|
||||
row->axisLength *= rowScale;
|
||||
}
|
||||
|
@ -352,19 +509,20 @@ void AxisLayout::tryFitLayout(CCNode* on, CCArray* nodes, float scale, float squ
|
|||
float evenSpace = available.axisLength / row->nodes->count();
|
||||
|
||||
size_t ix = 0;
|
||||
AxisLayoutOptions* prev = nullptr;
|
||||
for (auto& node : CCArrayExt<CCNode*>(row->nodes)) {
|
||||
auto scale = rowScale;
|
||||
auto opts = axisOpts(node);
|
||||
// rescale node if overflowing
|
||||
if (m_autoScale) {
|
||||
if (auto opts = typeinfo_cast<AxisLayoutOptions*>(node->getLayoutOptions())) {
|
||||
if (auto max = opts->getMaxScale()) {
|
||||
if (scale > max.value()) {
|
||||
scale = max.value();
|
||||
}
|
||||
if (this->shouldAutoScale(opts)) {
|
||||
if (opts) {
|
||||
if (scale > opts->getMaxScale()) {
|
||||
scale = opts->getMaxScale();
|
||||
}
|
||||
else {
|
||||
scale = node->getScale();
|
||||
}
|
||||
scale *= opts->getRelativeScale();
|
||||
}
|
||||
// CCMenuItemSpriteExtra is quirky af
|
||||
if (auto btn = typeinfo_cast<CCMenuItemSpriteExtra*>(node)) {
|
||||
|
@ -380,8 +538,11 @@ void AxisLayout::tryFitLayout(CCNode* on, CCArray* nodes, float scale, float squ
|
|||
row->axisEndsLength * scale * (1.f - rowSquish) * 1.f / nodes->count();
|
||||
}
|
||||
else {
|
||||
if (ix) {
|
||||
rowAxisPos += this->nextGap(prev, opts) * scale * rowSquish;
|
||||
}
|
||||
axisPos = rowAxisPos + pos.axisLength * pos.axisAnchor;
|
||||
rowAxisPos += pos.axisLength + m_gap * scale * rowSquish -
|
||||
rowAxisPos += pos.axisLength -
|
||||
row->axisEndsLength * scale * (1.f - rowSquish) * 1.f / nodes->count();
|
||||
}
|
||||
float crossOffset;
|
||||
|
@ -404,6 +565,7 @@ void AxisLayout::tryFitLayout(CCNode* on, CCArray* nodes, float scale, float squ
|
|||
else {
|
||||
node->setPosition(rowCrossPos + crossOffset, axisPos);
|
||||
}
|
||||
prev = opts;
|
||||
ix++;
|
||||
}
|
||||
|
||||
|
@ -420,7 +582,8 @@ void AxisLayout::tryFitLayout(CCNode* on, CCArray* nodes, float scale, float squ
|
|||
|
||||
void AxisLayout::apply(CCNode* on) {
|
||||
auto nodes = getNodesToPosition(on);
|
||||
this->tryFitLayout(on, nodes, 1.f, 1.f);
|
||||
auto [prios, scales, doAutoScale] = findProps(nodes);
|
||||
this->tryFitLayout(on, nodes, scales, prios, doAutoScale, scales.second, 1.f, prios.second);
|
||||
}
|
||||
|
||||
AxisLayout::AxisLayout(Axis axis) : m_axis(axis) {}
|
||||
|
@ -510,41 +673,85 @@ AxisLayout* AxisLayout::create(Axis axis) {
|
|||
return new AxisLayout(axis);
|
||||
}
|
||||
|
||||
// RowLayout
|
||||
|
||||
RowLayout::RowLayout() : AxisLayout(Axis::Row) {}
|
||||
|
||||
RowLayout* RowLayout::create() {
|
||||
return new RowLayout();
|
||||
}
|
||||
|
||||
// ColumnLayout
|
||||
|
||||
ColumnLayout::ColumnLayout() : AxisLayout(Axis::Column) {}
|
||||
|
||||
ColumnLayout* ColumnLayout::create() {
|
||||
return new ColumnLayout();
|
||||
}
|
||||
|
||||
// AxisLayoutOptions
|
||||
|
||||
AxisLayoutOptions* AxisLayoutOptions::create() {
|
||||
return new AxisLayoutOptions();
|
||||
}
|
||||
|
||||
std::optional<float> AxisLayoutOptions::getMaxScale() const {
|
||||
std::optional<bool> AxisLayoutOptions::getAutoScale() const {
|
||||
return m_autoScale;
|
||||
}
|
||||
|
||||
float AxisLayoutOptions::getMaxScale() const {
|
||||
return m_maxScale;
|
||||
}
|
||||
|
||||
float AxisLayoutOptions::getMinScale() const {
|
||||
return m_minScale;
|
||||
}
|
||||
|
||||
float AxisLayoutOptions::getRelativeScale() const {
|
||||
return m_relativeScale;
|
||||
}
|
||||
|
||||
std::optional<float> AxisLayoutOptions::getLength() const {
|
||||
return m_length;
|
||||
}
|
||||
|
||||
std::optional<float> AxisLayoutOptions::getPrevGap() const {
|
||||
return m_prevGap;
|
||||
}
|
||||
|
||||
std::optional<float> AxisLayoutOptions::getNextGap() const {
|
||||
return m_nextGap;
|
||||
}
|
||||
|
||||
bool AxisLayoutOptions::getBreakLine() const {
|
||||
return m_breakLine;
|
||||
}
|
||||
|
||||
bool AxisLayoutOptions::getSameLine() const {
|
||||
return m_sameLine;
|
||||
}
|
||||
|
||||
int AxisLayoutOptions::getScalePriority() const {
|
||||
return m_scalePriority;
|
||||
}
|
||||
|
||||
AxisLayoutOptions* AxisLayoutOptions::setMaxScale(float scale) {
|
||||
m_maxScale = scale;
|
||||
return this;
|
||||
}
|
||||
|
||||
AxisLayoutOptions* AxisLayoutOptions::disableAutoScale() {
|
||||
m_maxScale = std::nullopt;
|
||||
AxisLayoutOptions* AxisLayoutOptions::setMinScale(float scale) {
|
||||
m_minScale = scale;
|
||||
return this;
|
||||
}
|
||||
|
||||
AxisLayoutOptions* AxisLayoutOptions::setRelativeScale(float scale) {
|
||||
m_relativeScale = scale;
|
||||
return this;
|
||||
}
|
||||
|
||||
AxisLayoutOptions* AxisLayoutOptions::setAutoScale(std::optional<bool> enabled) {
|
||||
m_autoScale = enabled;
|
||||
return this;
|
||||
}
|
||||
|
||||
|
@ -553,7 +760,27 @@ AxisLayoutOptions* AxisLayoutOptions::setLength(std::optional<float> length) {
|
|||
return this;
|
||||
}
|
||||
|
||||
AxisLayoutOptions* AxisLayoutOptions::setPrevGap(std::optional<float> gap) {
|
||||
m_prevGap = gap;
|
||||
return this;
|
||||
}
|
||||
|
||||
AxisLayoutOptions* AxisLayoutOptions::setNextGap(std::optional<float> gap) {
|
||||
m_nextGap = gap;
|
||||
return this;
|
||||
}
|
||||
|
||||
AxisLayoutOptions* AxisLayoutOptions::setBreakLine(bool enable) {
|
||||
m_breakLine = enable;
|
||||
return this;
|
||||
}
|
||||
|
||||
AxisLayoutOptions* AxisLayoutOptions::setSameLine(bool enable) {
|
||||
m_sameLine = enable;
|
||||
return this;
|
||||
}
|
||||
|
||||
AxisLayoutOptions* AxisLayoutOptions::setScalePriority(int priority) {
|
||||
m_scalePriority = priority;
|
||||
return this;
|
||||
}
|
||||
|
|
|
@ -21,7 +21,6 @@ private:
|
|||
std::string m_id = "";
|
||||
std::unique_ptr<Layout> m_layout = nullptr;
|
||||
std::unique_ptr<LayoutOptions> m_layoutOptions = nullptr;
|
||||
PositionHint m_positionHint = PositionHint::Default;
|
||||
std::unordered_map<std::string, std::any> m_attributes;
|
||||
|
||||
friend class ProxyCCNode;
|
||||
|
@ -156,14 +155,6 @@ void CCNode::updateLayout(bool updateChildOrder) {
|
|||
}
|
||||
}
|
||||
|
||||
void CCNode::setPositionHint(PositionHint hint) {
|
||||
GeodeNodeMetadata::set(this)->m_positionHint = hint;
|
||||
}
|
||||
|
||||
PositionHint CCNode::getPositionHint() {
|
||||
return GeodeNodeMetadata::set(this)->m_positionHint;
|
||||
}
|
||||
|
||||
void CCNode::setAttribute(std::string const& attr, std::any value) {
|
||||
GeodeNodeMetadata::set(this)->m_attributes[attr] = value;
|
||||
}
|
||||
|
|
|
@ -103,7 +103,7 @@ $register_ids(EditorPauseLayer) {
|
|||
auto optionsMenu = detachAndCreateMenu(
|
||||
this,
|
||||
"options-menu",
|
||||
ColumnLayout::create()
|
||||
RowLayout::create()
|
||||
->setGap(-1.f)
|
||||
->setAxisAlignment(AxisAlignment::Start)
|
||||
->setGrowCrossAxis(true)
|
||||
|
@ -129,6 +129,8 @@ $register_ids(EditorPauseLayer) {
|
|||
label->setLayoutOptions(
|
||||
AxisLayoutOptions::create()
|
||||
->setBreakLine(true)
|
||||
->setSameLine(true)
|
||||
->setRelativeScale(.5f)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -308,7 +308,7 @@ $register_ids(EditorUI) {
|
|||
|
||||
this->getChildByID("layer-index-label")->setLayoutOptions(
|
||||
AxisLayoutOptions::create()
|
||||
->disableAutoScale()
|
||||
->setAutoScale(false)
|
||||
->setLength(25.f)
|
||||
);
|
||||
|
||||
|
|
Loading…
Reference in a new issue