mirror of
https://github.com/geode-sdk/geode.git
synced 2024-11-27 01:45:35 -05:00
add SpacerNode & bring back Dispatch
This commit is contained in:
parent
c1d4a89f8b
commit
b44b5d3cd3
5 changed files with 176 additions and 35 deletions
|
@ -23,7 +23,7 @@ class CCNode;
|
|||
*/
|
||||
class GEODE_DLL Layout : public CCObject {
|
||||
protected:
|
||||
CCArray* getNodesToPosition(CCNode* forNode);
|
||||
CCArray* getNodesToPosition(CCNode* forNode) const;
|
||||
|
||||
bool m_ignoreInvisibleChildren = false;
|
||||
|
||||
|
@ -37,6 +37,11 @@ public:
|
|||
*/
|
||||
virtual void apply(CCNode* on) = 0;
|
||||
|
||||
/**
|
||||
* Get how much space this layout would like to take up for a given target
|
||||
*/
|
||||
virtual CCSize getSizeHint(CCNode* on) const = 0;
|
||||
|
||||
void ignoreInvisibleChildren(bool ignore);
|
||||
bool isIgnoreInvisibleChildren() const;
|
||||
|
||||
|
@ -262,6 +267,7 @@ public:
|
|||
static AxisLayout* create(Axis axis = Axis::Row);
|
||||
|
||||
void apply(CCNode* on) override;
|
||||
CCSize getSizeHint(CCNode* on) const override;
|
||||
|
||||
Axis getAxis() const;
|
||||
AxisAlignment getAxisAlignment() const;
|
||||
|
|
59
loader/include/Geode/cocos/base_nodes/SpacerNode.hpp
vendored
Normal file
59
loader/include/Geode/cocos/base_nodes/SpacerNode.hpp
vendored
Normal file
|
@ -0,0 +1,59 @@
|
|||
#pragma once
|
||||
|
||||
#include "CCNode.h"
|
||||
|
||||
NS_CC_BEGIN
|
||||
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable: 4275)
|
||||
|
||||
/**
|
||||
* A node for controlling spacing in Layouts. When a Layout is applied, if
|
||||
* space is left over, the remaining space is divided among all SpacerNodes in
|
||||
* the Layout. The space each node gets is the proprotion between its growth
|
||||
* factor and the sum of all the SpacerNodes' growth factors in the Layout
|
||||
* @example
|
||||
* node->addChild(SpacerNode::create(1));
|
||||
* node->addChild(SpacerNode::create(2));
|
||||
* node->addChild(SpacerNode::create(1));
|
||||
* node->updateLayout();
|
||||
* // Total SpacerNode growth sum is 1 + 2 + 1 = 4
|
||||
* // So s1 and s3 get 1/4 of the remaining space and s2 gets 2/4
|
||||
* @note If you want to specify a minimum width for a SpacerNode, add
|
||||
* AxisLayoutOptions for it and use setLength
|
||||
*/
|
||||
class GEODE_DLL SpacerNode : public CCNode {
|
||||
protected:
|
||||
size_t m_grow;
|
||||
|
||||
bool init(size_t grow);
|
||||
|
||||
public:
|
||||
/**
|
||||
* Create a new spacer node. When the layout is applied,
|
||||
* if there is space left over the remaining space is distributed among
|
||||
* all spacer nodes in proportion to the sum of all the spacers' grow
|
||||
* factors (akin to CSS flew grow)
|
||||
* @param grow The grow factor for this node. Default is 1
|
||||
*/
|
||||
static SpacerNode* create(size_t grow = 1);
|
||||
|
||||
/**
|
||||
* Set the grow factor for this spacer node. When the layout is applied,
|
||||
* if there is space left over the remaining space is distributed among
|
||||
* all spacer nodes in proportion to the sum of all the spacers' grow
|
||||
* factors (akin to CSS flew grow)
|
||||
* @param grow The new grow factor for this node. Default is 1
|
||||
* @note Make sure to call updateLayout on the spacer's parent afterwards
|
||||
*/
|
||||
void setGrow(size_t grow);
|
||||
|
||||
/**
|
||||
* Get the grow factor for this spacer node
|
||||
*/
|
||||
size_t getGrow() const;
|
||||
};
|
||||
|
||||
#pragma warning(pop)
|
||||
|
||||
NS_CC_END
|
1
loader/include/Geode/cocos/include/cocos2d.h
vendored
1
loader/include/Geode/cocos/include/cocos2d.h
vendored
|
@ -59,6 +59,7 @@ THE SOFTWARE.
|
|||
// base_nodes
|
||||
#include "../base_nodes/CCNode.h"
|
||||
#include "../base_nodes/CCAtlasNode.h"
|
||||
#include "../base_nodes/SpacerNode.hpp"
|
||||
|
||||
// cocoa
|
||||
#include "../cocoa/CCAffineTransform.h"
|
||||
|
|
|
@ -9,42 +9,41 @@
|
|||
namespace geode {
|
||||
// Mod interoperability
|
||||
|
||||
// todo: update to new event system
|
||||
template <class... Args>
|
||||
class DispatchEvent : public Event {
|
||||
protected:
|
||||
std::string m_id;
|
||||
std::tuple<Args...> m_args;
|
||||
|
||||
// template <typename... Args>
|
||||
// class DispatchEvent : public Event {
|
||||
// std::string m_selector;
|
||||
// std::tuple<Args...> m_args;
|
||||
public:
|
||||
DispatchEvent(std::string const& id, Args&&... args)
|
||||
: m_id(id), m_args(std::make_tuple(args...)) {}
|
||||
|
||||
// public:
|
||||
// DispatchEvent(std::string const& name, Args... args) :
|
||||
// m_selector(name), m_args(std::make_tuple(args...)) {}
|
||||
std::tuple<Args...> getArgs() const {
|
||||
return m_args;
|
||||
}
|
||||
|
||||
// std::string const& selector() {
|
||||
// return m_selector;
|
||||
// }
|
||||
// };
|
||||
std::string getID() const {
|
||||
return m_id;
|
||||
}
|
||||
};
|
||||
|
||||
// template <typename... Args>
|
||||
// class DispatchHandler : public EventHandler<DispatchEvent<Args...>> {
|
||||
// std::string m_selector;
|
||||
// utils::MiniFunction<void(Args...)> m_callback;
|
||||
template <class... Args>
|
||||
class DispatchFilter : public EventFilter<DispatchEvent<Args...>> {
|
||||
protected:
|
||||
std::string m_id;
|
||||
|
||||
// DispatchHandler(std::string const& name, utils::MiniFunction<void(Args...)> callback) :
|
||||
// m_selector(name), m_callback(callback) {}
|
||||
public:
|
||||
using Ev = DispatchEvent<Args...>;
|
||||
using Callback = ListenerResult(Args...);
|
||||
|
||||
// public:
|
||||
// bool handle(DispatchEvent<Args...>* ev) {
|
||||
// if (ev->name() == m_selector) {
|
||||
// std::apply(m_callback, ev->m_args);
|
||||
// }
|
||||
// return true;
|
||||
// }
|
||||
ListenerResult handle(utils::MiniFunction<Callback> fn, Ev* event) {
|
||||
if (event->getID() == m_id) {
|
||||
return std::apply(fn, event->getArgs());
|
||||
}
|
||||
return ListenerResult::Propagate;
|
||||
}
|
||||
|
||||
// static DispatchHandler* create(
|
||||
// std::string const& name, utils::MiniFunction<void(Args...)> callback
|
||||
// ) {
|
||||
// return new DispatchHandler(name, callback);
|
||||
// }
|
||||
// };
|
||||
DispatchFilter(std::string const& id) : m_id(id) {}
|
||||
};
|
||||
}
|
|
@ -50,7 +50,7 @@ bool CCNode::hasAncestor(CCNode* ancestor) {
|
|||
return false;
|
||||
}
|
||||
|
||||
CCArray* Layout::getNodesToPosition(CCNode* on) {
|
||||
CCArray* Layout::getNodesToPosition(CCNode* on) const {
|
||||
auto arr = CCArray::create();
|
||||
for (auto child : CCArrayExt<CCNode>(on->getChildren())) {
|
||||
if (!m_ignoreInvisibleChildren || child->isVisible()) {
|
||||
|
@ -176,6 +176,32 @@ struct AxisLayout::Row : public CCObject {
|
|||
{
|
||||
this->autorelease();
|
||||
}
|
||||
|
||||
void accountSpacers(Axis axis, float availableLength) {
|
||||
std::vector<SpacerNode*> spacers;
|
||||
for (auto& node : CCArrayExt<CCNode>(nodes)) {
|
||||
if (auto spacer = typeinfo_cast<SpacerNode*>(node)) {
|
||||
spacers.push_back(spacer);
|
||||
}
|
||||
}
|
||||
if (spacers.size()) {
|
||||
auto unusedSpace = availableLength - this->axisLength;
|
||||
size_t sum = 0;
|
||||
for (auto& spacer : spacers) {
|
||||
sum += spacer->getGrow();
|
||||
}
|
||||
for (auto& spacer : spacers) {
|
||||
auto size = unusedSpace * spacer->getGrow() / static_cast<float>(sum);
|
||||
if (axis == Axis::Row) {
|
||||
spacer->setContentSize({ size, this->crossLength });
|
||||
}
|
||||
else {
|
||||
spacer->setContentSize({ this->crossLength, size });
|
||||
}
|
||||
}
|
||||
this->axisLength = availableLength;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
struct AxisPosition {
|
||||
|
@ -195,6 +221,9 @@ static AxisPosition nodeAxis(CCNode* node, Axis axis, float scale) {
|
|||
if (auto toggle = typeinfo_cast<CCMenuItemToggler*>(node)) {
|
||||
scaledSize = toggle->m_offButton->getScaledContentSize();
|
||||
}
|
||||
if (auto spacer = typeinfo_cast<SpacerNode*>(node)) {
|
||||
scaledSize = CCSizeZero;
|
||||
}
|
||||
auto anchor = node->getAnchorPoint();
|
||||
if (axis == Axis::Row) {
|
||||
return AxisPosition {
|
||||
|
@ -611,6 +640,8 @@ void AxisLayout::tryFitLayout(
|
|||
float rowEvenSpace = available.crossLength / rows->count();
|
||||
|
||||
for (auto row : CCArrayExt<Row*>(rows)) {
|
||||
row->accountSpacers(m_axis, available.axisLength);
|
||||
|
||||
if (m_crossAlignment == AxisAlignment::Even) {
|
||||
rowCrossPos -= rowEvenSpace / 2 + row->crossLength / 2;
|
||||
}
|
||||
|
@ -756,6 +787,24 @@ void AxisLayout::apply(CCNode* on) {
|
|||
);
|
||||
}
|
||||
|
||||
CCSize AxisLayout::getSizeHint(CCNode* on) const {
|
||||
// Ideal is single row / column with no scaling
|
||||
auto nodes = getNodesToPosition(on);
|
||||
float length = 0.f;
|
||||
float cross = 0.f;
|
||||
for (auto& node : CCArrayExt<CCNode*>(nodes)) {
|
||||
auto axis = nodeAxis(node, m_axis, 1.f);
|
||||
length += axis.axisLength;
|
||||
cross += axis.crossLength;
|
||||
}
|
||||
if (m_axis == Axis::Row) {
|
||||
return { length, cross };
|
||||
}
|
||||
else {
|
||||
return { cross, length };
|
||||
}
|
||||
}
|
||||
|
||||
AxisLayout::AxisLayout(Axis axis) : m_axis(axis) {}
|
||||
|
||||
Axis AxisLayout::getAxis() const {
|
||||
|
@ -969,3 +1018,30 @@ AxisLayoutOptions* AxisLayoutOptions::setScalePriority(int priority) {
|
|||
m_scalePriority = priority;
|
||||
return this;
|
||||
}
|
||||
|
||||
bool SpacerNode::init(size_t grow) {
|
||||
if (!CCNode::init())
|
||||
return false;
|
||||
|
||||
m_grow = grow;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
SpacerNode* SpacerNode::create(size_t grow) {
|
||||
auto ret = new SpacerNode;
|
||||
if (ret && ret->init(grow)) {
|
||||
ret->autorelease();
|
||||
return ret;
|
||||
}
|
||||
CC_SAFE_DELETE(ret);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void SpacerNode::setGrow(size_t grow) {
|
||||
m_grow = grow;
|
||||
}
|
||||
|
||||
size_t SpacerNode::getGrow() const {
|
||||
return m_grow;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue