2022-10-10 13:58:47 -04:00
|
|
|
#pragma once
|
|
|
|
|
2022-10-22 15:10:36 -04:00
|
|
|
#include "../include/ccMacros.h"
|
|
|
|
#include "../cocoa/CCAffineTransform.h"
|
|
|
|
#include "../cocoa/CCArray.h"
|
2022-10-10 13:58:47 -04:00
|
|
|
#include <Geode/platform/platform.hpp>
|
|
|
|
#include <optional>
|
|
|
|
#include <unordered_map>
|
|
|
|
|
|
|
|
NS_CC_BEGIN
|
|
|
|
|
|
|
|
class CCNode;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Layouts automatically handle the positioning of nodes. Use CCNode::setLayout
|
|
|
|
* to apply a layout to a node, and then use CCNode::updateLayout to apply
|
|
|
|
* the layout's positioning. Geode comes with a few default layouts like
|
|
|
|
* RowLayout, ColumnLayout, and GridLayout, but if you need a different kind
|
|
|
|
* of layout you can inherit from the Layout class.
|
|
|
|
*/
|
2023-02-02 10:08:13 -05:00
|
|
|
class GEODE_DLL Layout {
|
|
|
|
protected:
|
|
|
|
static CCArray* getNodesToPosition(CCNode* forNode);
|
|
|
|
|
2022-10-10 13:58:47 -04:00
|
|
|
public:
|
|
|
|
/**
|
|
|
|
* Automatically apply the layout's positioning on a set of nodes
|
2023-02-02 10:08:13 -05:00
|
|
|
* @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
|
2022-10-10 13:58:47 -04:00
|
|
|
*/
|
2023-02-02 10:08:13 -05:00
|
|
|
virtual void apply(CCNode* on) = 0;
|
2023-02-06 14:36:08 -05:00
|
|
|
|
|
|
|
virtual ~Layout() = default;
|
|
|
|
};
|
|
|
|
|
|
|
|
class GEODE_DLL LayoutOptions {
|
|
|
|
public:
|
|
|
|
virtual ~LayoutOptions() = default;
|
2022-10-10 13:58:47 -04:00
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Determines how a node should be positioned within its parent, if that
|
|
|
|
* parent has an automatically positioning layout
|
|
|
|
*/
|
|
|
|
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,
|
|
|
|
};
|
|
|
|
|
2023-02-06 14:36:08 -05:00
|
|
|
enum class Axis {
|
|
|
|
Row,
|
|
|
|
Column,
|
|
|
|
};
|
|
|
|
|
2022-10-10 13:58:47 -04:00
|
|
|
/**
|
|
|
|
* Specifies the alignment of something
|
|
|
|
*/
|
2023-02-06 14:36:08 -05:00
|
|
|
enum class AxisAlignment {
|
|
|
|
// Align items to the start
|
|
|
|
// |ooo......|
|
|
|
|
Start,
|
|
|
|
// All items are centered
|
|
|
|
// |...ooo...|
|
2022-10-10 13:58:47 -04:00
|
|
|
Center,
|
2023-02-06 14:36:08 -05:00
|
|
|
// Align items to the end
|
|
|
|
// |......ooo|
|
2022-10-10 13:58:47 -04:00
|
|
|
End,
|
2023-02-06 14:36:08 -05:00
|
|
|
// Each item gets the same portion from the layout (disregards gap)
|
|
|
|
// |.o..o..o.|
|
|
|
|
Even,
|
2022-10-10 13:58:47 -04:00
|
|
|
};
|
|
|
|
|
2023-02-06 14:36:08 -05:00
|
|
|
/**
|
|
|
|
* Layout for arranging nodes along an axis. Used to implement row, column, and
|
|
|
|
* grid layouts
|
|
|
|
*/
|
2023-02-04 08:58:10 -05:00
|
|
|
class GEODE_DLL AxisLayout : public Layout {
|
2022-10-10 13:58:47 -04:00
|
|
|
protected:
|
2023-02-04 08:58:10 -05:00
|
|
|
Axis m_axis;
|
2023-02-06 14:36:08 -05:00
|
|
|
AxisAlignment m_axisAlignment = AxisAlignment::Center;
|
|
|
|
AxisAlignment m_crossAlignment = AxisAlignment::Center;
|
2023-02-04 08:58:10 -05:00
|
|
|
float m_gap = 5.f;
|
|
|
|
bool m_autoScale = true;
|
2023-02-06 14:36:08 -05:00
|
|
|
bool m_axisReverse = false;
|
|
|
|
bool m_crossReverse = 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;
|
2022-10-10 13:58:47 -04:00
|
|
|
|
2023-02-04 08:58:10 -05:00
|
|
|
AxisLayout(Axis);
|
|
|
|
|
2022-10-10 13:58:47 -04:00
|
|
|
public:
|
2023-02-11 10:50:14 -05:00
|
|
|
/**
|
|
|
|
* Create a new AxisLayout. 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 AxisLayout for
|
|
|
|
* what options you can customize for the layout
|
|
|
|
* @param axis The direction of the layout
|
|
|
|
* @note For convenience, you can use the RowLayout and ColumnLayout
|
|
|
|
* classes, which are just thin wrappers over AxisLayout
|
|
|
|
* @returns Created AxisLayout
|
|
|
|
*/
|
|
|
|
static AxisLayout* create(Axis axis = Axis::Row);
|
|
|
|
|
2023-02-02 10:08:13 -05:00
|
|
|
void apply(CCNode* on) override;
|
2022-10-10 13:58:47 -04:00
|
|
|
|
2023-02-11 05:06:01 -05:00
|
|
|
Axis getAxis() const;
|
|
|
|
AxisAlignment getAxisAlignment() const;
|
|
|
|
AxisAlignment getCrossAxisAlignment() const;
|
|
|
|
float getGap() const;
|
|
|
|
bool getAxisReverse() const;
|
|
|
|
bool getCrossAxisReverse() const;
|
|
|
|
bool getAutoScale() const;
|
|
|
|
bool getGrowCrossAxis() const;
|
|
|
|
bool getCrossAxisOverflow() const;
|
|
|
|
|
2023-02-11 10:50:14 -05:00
|
|
|
AxisLayout* setAxis(Axis axis);
|
2023-02-06 14:36:08 -05:00
|
|
|
/**
|
|
|
|
* Sets where to align the target node's children on the main axis (X for
|
|
|
|
* Row, Y for Column)
|
2023-02-02 10:08:13 -05:00
|
|
|
*/
|
2023-02-06 14:36:08 -05:00
|
|
|
AxisLayout* setAxisAlignment(AxisAlignment align);
|
2023-02-11 05:06:01 -05:00
|
|
|
/**
|
|
|
|
* Sets where to align the target node's children on the cross-axis (Y for
|
|
|
|
* Row, X for Column)
|
|
|
|
*/
|
|
|
|
AxisLayout* setCrossAxisAlignment(AxisAlignment align);
|
2023-02-02 10:08:13 -05:00
|
|
|
/**
|
|
|
|
* The spacing between the children of the node this layout applies to.
|
2023-02-06 14:36:08 -05:00
|
|
|
* Measured as the space between their edges, not centres. Does not apply
|
|
|
|
* on the main / cross axis if their alignment is AxisAlignment::Even
|
2023-02-02 10:08:13 -05:00
|
|
|
*/
|
2023-02-04 08:58:10 -05:00
|
|
|
AxisLayout* setGap(float gap);
|
2023-02-02 10:08:13 -05:00
|
|
|
/**
|
|
|
|
* Whether to reverse the direction of the children in this layout or not
|
|
|
|
*/
|
2023-02-06 14:36:08 -05:00
|
|
|
AxisLayout* setAxisReverse(bool reverse);
|
|
|
|
/**
|
|
|
|
* Whether to reverse the direction of the rows on the cross-axis or not
|
|
|
|
*/
|
|
|
|
AxisLayout* setCrossAxisReverse(bool reverse);
|
2023-02-02 10:08:13 -05:00
|
|
|
/**
|
2023-02-06 14:36:08 -05:00
|
|
|
* If enabled, then the layout may scale the target's children if they are
|
|
|
|
* about to overflow. Assumes that all the childrens' intended scale is 1
|
2023-02-02 10:08:13 -05:00
|
|
|
*/
|
2023-02-04 08:58:10 -05:00
|
|
|
AxisLayout* setAutoScale(bool enable);
|
2023-02-02 10:08:13 -05:00
|
|
|
/**
|
2023-02-06 14:36:08 -05:00
|
|
|
* If true, if the main axis overflows extra nodes will be placed on new
|
|
|
|
* rows/columns on the cross-axis
|
|
|
|
*/
|
|
|
|
AxisLayout* setGrowCrossAxis(bool expand);
|
|
|
|
/**
|
|
|
|
* If true, the cross-axis content size of the target node will be
|
|
|
|
* automatically adjusted to fit the children
|
2023-02-02 10:08:13 -05:00
|
|
|
*/
|
2023-02-06 14:36:08 -05:00
|
|
|
AxisLayout* setCrossAxisOverflow(bool allow);
|
2022-10-10 13:58:47 -04:00
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
2023-02-04 08:58:10 -05:00
|
|
|
* Simple layout for arranging nodes in a row (horizontal line)
|
2022-10-10 13:58:47 -04:00
|
|
|
*/
|
2023-02-04 08:58:10 -05:00
|
|
|
class GEODE_DLL RowLayout : public AxisLayout {
|
2022-10-10 13:58:47 -04:00
|
|
|
protected:
|
2023-02-04 08:58:10 -05:00
|
|
|
RowLayout();
|
2022-10-10 13:58:47 -04:00
|
|
|
|
|
|
|
public:
|
2023-02-04 08:58:10 -05:00
|
|
|
/**
|
|
|
|
* 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
|
|
|
|
* @returns Created RowLayout
|
|
|
|
*/
|
|
|
|
static RowLayout* create();
|
|
|
|
};
|
2022-10-10 13:58:47 -04:00
|
|
|
|
2023-02-04 08:58:10 -05:00
|
|
|
/**
|
|
|
|
* Simple layout for arranging nodes in a column (vertical line)
|
|
|
|
*/
|
|
|
|
class GEODE_DLL ColumnLayout : public AxisLayout {
|
|
|
|
protected:
|
|
|
|
ColumnLayout();
|
|
|
|
|
|
|
|
public:
|
2023-02-02 10:08:13 -05:00
|
|
|
/**
|
|
|
|
* 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();
|
2022-10-10 13:58:47 -04:00
|
|
|
};
|
|
|
|
|
|
|
|
NS_CC_END
|