fix ranges::reverse + add break line option to AxisLayoutOptions

also EditorPauseLayer ids but didn't finish the layouts yet
This commit is contained in:
HJfod 2023-02-14 21:54:45 +02:00
parent f7ddf0af2e
commit ffd50eb0f1
7 changed files with 251 additions and 128 deletions

View file

@ -616,17 +616,15 @@ public:
* Return an array of children
*
* Composing a "tree" structure is a very important feature of CCNode
* Here's a sample code of traversing children array:
* @code
* @example
* // Here's a sample code of traversing children array:
* CCNode* node = NULL;
* CCARRAY_FOREACH(parent->getChildren(), node)
* {
* node->setPosition(0,0);
* }
* @endcode
* This sample code traverses all children nodes, and set theie position to (0,0)
*
* @return An array of children
* // This sample code traverses all children nodes, and set theie position to (0,0)
* @returns An array of children
*/
virtual CCArray* getChildren();

View file

@ -81,12 +81,14 @@ class GEODE_DLL AxisLayoutOptions : public LayoutOptions {
protected:
std::optional<float> m_maxScale = 1.f;
std::optional<float> m_length = std::nullopt;
bool m_breakLine = false;
public:
static AxisLayoutOptions* create();
std::optional<float> getMaxScale();
std::optional<float> getLength();
std::optional<float> getMaxScale() const;
std::optional<float> getLength() const;
bool getBreakLine() const;
/**
* Set the maximum scale this node can be if it's contained in an
@ -106,6 +108,12 @@ public:
* dynamically calculated based on content size
*/
AxisLayoutOptions* setLength(std::optional<float> length);
/**
* 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);
};
/**

View file

@ -563,86 +563,6 @@ namespace geode::cocos {
*/
GEODE_DLL bool fileExistsInSearchPaths(char const* filename);
template <typename T>
struct CCArrayIterator {
public:
CCArrayIterator(T* p) : m_ptr(p) {}
T* m_ptr;
auto& operator*() {
return *m_ptr;
}
auto& operator*() const {
return *m_ptr;
}
auto operator->() {
return m_ptr;
}
auto operator->() const {
return m_ptr;
}
auto& operator++() {
++m_ptr;
return *this;
}
auto& operator--() {
--m_ptr;
return *this;
}
auto& operator+=(size_t val) {
m_ptr += val;
return *this;
}
auto& operator-=(size_t val) {
m_ptr -= val;
return *this;
}
auto operator+(size_t val) const {
return CCArrayIterator<T>(m_ptr + val);
}
auto operator-(size_t val) const {
return CCArrayIterator<T>(m_ptr - val);
}
auto operator-(CCArrayIterator<T> const& other) const {
return m_ptr - other.m_ptr;
}
bool operator<(CCArrayIterator<T> const& other) const {
return m_ptr < other.m_ptr;
}
bool operator>(CCArrayIterator<T> const& other) const {
return m_ptr > other.m_ptr;
}
bool operator<=(CCArrayIterator<T> const& other) const {
return m_ptr <= other.m_ptr;
}
bool operator>=(CCArrayIterator<T> const& other) const {
return m_ptr >= other.m_ptr;
}
bool operator==(CCArrayIterator<T> const& other) const {
return m_ptr == other.m_ptr;
}
bool operator!=(CCArrayIterator<T> const& other) const {
return m_ptr != other.m_ptr;
}
};
inline void ccDrawColor4B(cocos2d::ccColor4B const& color) {
cocos2d::ccDrawColor4B(color.r, color.g, color.b, color.a);
}
@ -781,16 +701,6 @@ namespace std {
return std::hash<T*>()(ref.data());
}
};
template <typename T>
struct iterator_traits<geode::cocos::CCArrayIterator<T>> {
using difference_type = ptrdiff_t;
using value_type = T;
using pointer = T*;
using reference = T&;
using iterator_category =
std::random_access_iterator_tag; // its random access but im too lazy to implement it
};
}
// more utils
@ -822,9 +732,14 @@ namespace geode::cocos {
using T = std::remove_pointer_t<_Type>;
public:
using value_type = T;
using iterator = T**;
using const_iterator = const T**;
CCArrayExt() : m_arr(cocos2d::CCArray::create()) {}
CCArrayExt(cocos2d::CCArray* arr) : m_arr(arr) {}
CCArrayExt(cocos2d::CCArray* arr)
: m_arr(arr) {}
CCArrayExt(CCArrayExt const& a) : m_arr(a.m_arr) {}
@ -834,18 +749,26 @@ namespace geode::cocos {
~CCArrayExt() {}
auto begin() {
T** begin() const {
if (!m_arr) {
return CCArrayIterator<T*>(nullptr);
return nullptr;
}
return CCArrayIterator<T*>(reinterpret_cast<T**>(m_arr->data->arr));
return reinterpret_cast<T**>(m_arr->data->arr);
}
auto end() {
T** end() const {
if (!m_arr) {
return CCArrayIterator<T*>(nullptr);
return nullptr;
}
return CCArrayIterator<T*>(reinterpret_cast<T**>(m_arr->data->arr) + m_arr->count());
return reinterpret_cast<T**>(m_arr->data->arr) + m_arr->count();
}
auto rbegin() const {
return std::reverse_iterator(this->end());
}
auto rend() const {
return std::reverse_iterator(this->begin());
}
size_t size() const {

View file

@ -289,23 +289,21 @@ namespace geode::utils::ranges {
return member(*it);
}
template <ValidConstContainer C>
struct ConstReverseWrapper {
C const& iter;
template <class C>
struct ReverseWrapper {
C iter;
decltype(auto) begin() {
return std::rbegin(iter);
}
decltype(auto) end() {
return std::rend(iter);
}
};
template <ValidConstContainer C>
auto begin(ConstReverseWrapper<C> const& c) {
return std::rbegin(c.iter);
}
template <ValidConstContainer C>
auto end(ConstReverseWrapper<C> const& c) {
return std::rend(c.iter);
}
template <ValidConstContainer C>
ConstReverseWrapper<C> reverse(C const& iter) {
return { iter };
template <class C>
auto reverse(C&& iter) {
return ReverseWrapper<C>{std::forward<C>(iter)};
}
}

View file

@ -3,6 +3,7 @@
#include <Geode/utils/ranges.hpp>
#include <Geode/loader/Log.hpp>
#include <Geode/binding/CCMenuItemSpriteExtra.hpp>
#include <Geode/binding/CCMenuItemToggler.hpp>
USE_GEODE_NAMESPACE();
@ -40,6 +41,18 @@ CCArray* Layout::getNodesToPosition(CCNode* on) {
return filtered;
}
static AxisLayoutOptions* axisOpts(CCNode* node) {
if (!node) return nullptr;
return typeinfo_cast<AxisLayoutOptions*>(node->getLayoutOptions());
}
static bool isOptsBreakLine(CCNode* node) {
if (auto opts = axisOpts(node)) {
return opts->getBreakLine();
}
return false;
}
static constexpr float AXIS_MIN_SCALE = 0.65f;
struct AxisPosition {
@ -52,9 +65,13 @@ struct AxisPosition {
static AxisPosition nodeAxis(CCNode* node, Axis axis, float scale) {
auto scaledSize = node->getScaledContentSize() * scale;
std::optional<float> axisLength = std::nullopt;
if (auto opts = typeinfo_cast<AxisLayoutOptions*>(node->getLayoutOptions())) {
if (auto opts = axisOpts(node)) {
axisLength = opts->getLength();
}
// CCMenuItemToggler is a common quirky class
if (auto toggle = typeinfo_cast<CCMenuItemToggler*>(node)) {
scaledSize = toggle->m_offButton->getScaledContentSize();
}
auto anchor = node->getAnchorPoint();
if (axis == Axis::Row) {
return AxisPosition {
@ -104,10 +121,11 @@ AxisLayout::Row* AxisLayout::fitInRow(CCNode* on, CCArray* nodes, float scale, f
auto res = CCArray::create();
auto available = nodeAxis(on, m_axis, 1.f);
CCNode* prev = nullptr;
size_t ix = 0;
for (auto& node : CCArrayExt<CCNode*>(nodes)) {
if (m_autoScale) {
if (auto opts = typeinfo_cast<AxisLayoutOptions*>(node->getLayoutOptions())) {
if (auto opts = axisOpts(node)) {
if (auto max = opts->getMaxScale()) {
node->setScale(max.value());
}
@ -122,7 +140,12 @@ AxisLayout::Row* AxisLayout::fitInRow(CCNode* on, CCArray* nodes, float scale, f
// 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 && ix != 0) {
if (
m_growCrossAxis && (
(nextAxisLength > available.axisLength || isOptsBreakLine(prev)) &&
ix != 0
)
) {
break;
}
res->addObject(node);
@ -134,6 +157,7 @@ AxisLayout::Row* AxisLayout::fitInRow(CCNode* on, CCArray* nodes, float scale, f
if (pos.crossLength > crossLength) {
crossLength = pos.crossLength;
}
prev = node;
ix++;
}
@ -502,14 +526,18 @@ AxisLayoutOptions* AxisLayoutOptions::create() {
return new AxisLayoutOptions();
}
std::optional<float> AxisLayoutOptions::getMaxScale() {
std::optional<float> AxisLayoutOptions::getMaxScale() const {
return m_maxScale;
}
std::optional<float> AxisLayoutOptions::getLength() {
std::optional<float> AxisLayoutOptions::getLength() const {
return m_length;
}
bool AxisLayoutOptions::getBreakLine() const {
return m_breakLine;
}
AxisLayoutOptions* AxisLayoutOptions::setMaxScale(float scale) {
m_maxScale = scale;
return this;
@ -524,3 +552,8 @@ AxisLayoutOptions* AxisLayoutOptions::setLength(std::optional<float> length) {
m_length = length;
return this;
}
AxisLayoutOptions* AxisLayoutOptions::setBreakLine(bool enable) {
m_breakLine = enable;
return this;
}

View file

@ -82,10 +82,10 @@ static CCMenu* detachAndCreateMenu(CCNode* parent, const char* menuID, Layout* l
newMenu->addChild(first);
first->release();
newMenu->setLayout(layout);
(switchToMenu(args, newMenu), ...);
newMenu->setLayout(layout);
return newMenu;
}

View file

@ -0,0 +1,163 @@
#include "AddIDs.hpp"
#include <Geode/modify/EditorPauseLayer.hpp>
USE_GEODE_NAMESPACE();
$register_ids(EditorPauseLayer) {
auto winSize = CCDirector::get()->getWinSize();
if (auto menu = getChildOfType<CCMenu>(this, 0)) {
menu->setID("resume-menu");
setIDs(
menu, 0,
"resume-button",
"save-and-play-button",
"save-and-exit-button",
"save-button",
"exit-button"
);
menu->setContentSize({ 100.f, 220.f });
menu->setLayout(
ColumnLayout::create()
->setGap(10.f)
->setAxisReverse(true)
);
}
setIDs(
this, 2,
"ignore-damage-label",
"follow-player-label",
"select-filter-label",
"show-grid-label",
"show-object-info-label",
"show-ground-label",
"preview-mode-label",
"object-count-label",
"length-label",
"length-name-label"
);
if (auto menu = getChildOfType<CCMenu>(this, 1)) {
menu->setID("bottom-menu");
setIDs(
menu, 0,
"guidelines-enable-button",
"help-button",
"guidelines-disable-button",
"uncheck-portals-button",
"reset-unused-button",
"create-edges-button",
"create-outlines-button",
"create-base-button",
"build-helper-button",
"align-x-button",
"align-y-button",
"select-all-button",
"select-all-left-button",
"select-all-right-button",
"ignore-damage-toggle",
"follow-player-toggle",
"select-filter-toggle",
"show-grid-toggle",
"show-object-info-toggle",
"show-ground-toggle",
"preview-mode-toggle",
"keys-button",
"settings-button"
);
auto smallActionsMenu = detachAndCreateMenu(
this,
"small-actions-menu",
ColumnLayout::create(),
menu->getChildByID("align-x-button"),
menu->getChildByID("align-y-button"),
menu->getChildByID("select-all-button"),
menu->getChildByID("select-all-left-button"),
menu->getChildByID("select-all-right-button")
);
auto actionsMenu = detachAndCreateMenu(
this,
"actions-menu",
ColumnLayout::create(),
menu->getChildByID("uncheck-portals-button"),
menu->getChildByID("reset-unused-button"),
menu->getChildByID("create-edges-button"),
menu->getChildByID("create-outlines-button"),
menu->getChildByID("create-base-button"),
menu->getChildByID("build-helper-button"),
menu->getChildByID("keys-button")
);
auto optionsMenu = detachAndCreateMenu(
this,
"options-menu",
ColumnLayout::create()
->setGap(-1.f)
->setAxisAlignment(AxisAlignment::Start)
->setGrowCrossAxis(true)
->setCrossAxisAlignment(AxisAlignment::Start)
->setCrossAxisOverflow(false),
menu->getChildByID("ignore-damage-toggle"),
this->getChildByID("ignore-damage-label"),
menu->getChildByID("follow-player-toggle"),
this->getChildByID("follow-player-label"),
menu->getChildByID("select-filter-toggle"),
this->getChildByID("select-filter-label"),
menu->getChildByID("show-grid-toggle"),
this->getChildByID("show-grid-label"),
menu->getChildByID("show-object-info-toggle"),
this->getChildByID("show-object-info-label"),
menu->getChildByID("show-ground-toggle"),
this->getChildByID("show-ground-label"),
menu->getChildByID("preview-mode-toggle"),
this->getChildByID("preview-mode-label")
);
for (auto node : CCArrayExt<CCNode>(optionsMenu->getChildren())) {
if (auto label = typeinfo_cast<CCLabelBMFont*>(node)) {
label->setLayoutOptions(
AxisLayoutOptions::create()
->setBreakLine(true)
);
}
}
optionsMenu->setContentSize({ 120.f, winSize.height - 100.f });
optionsMenu->setPosition(70.f, winSize.height / 2 - 50.f + 10.f);
optionsMenu->updateLayout();
auto settingsMenu = detachAndCreateMenu(
this,
"settings-menu",
RowLayout::create()
->setAxisReverse(true),
menu->getChildByID("settings-button")
);
}
}
struct EditorPauseLayerIDs : Modify<EditorPauseLayerIDs, EditorPauseLayer> {
static void onModify(auto& self) {
if (!self.setHookPriority("EditorPauseLayer::init", GEODE_ID_PRIORITY)) {
log::warn("Failed to set EditorPauseLayer::init hook priority, node IDs may not work properly");
}
}
bool init(LevelEditorLayer* lel) {
if (!EditorPauseLayer::init(lel)) return false;
NodeIDs::get()->provide(this);
return true;
}
};