Skip to content

Commit

Permalink
add scale snap customization
Browse files Browse the repository at this point in the history
  • Loading branch information
HJfod committed Oct 21, 2024
1 parent bad9bde commit 6cbd785
Show file tree
Hide file tree
Showing 9 changed files with 171 additions and 53 deletions.
1 change: 1 addition & 0 deletions changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

## v6.8.0-beta.4
* Add option for <cy>Hide Trigger Popup BG when Modifying Slider</c> to all triggers (huge thank you to <cp>TheSillyDoggo</c>!)
* Add option for changing the snap size on the Scale and Rotate Controls
* Make the build tabs responsive to screen size (huge thank you to <cg>Alphalaneous</c>!)
* Fix <cc>View Tab LDM</c> being applied outside the editor

Expand Down
8 changes: 4 additions & 4 deletions mod.json
Original file line number Diff line number Diff line change
Expand Up @@ -69,11 +69,11 @@
],
"ViewTabSheet": [
"resources/view/*.png"
],
"SupportSheet": [
"resources/images/support-shard-*.png"
]
}
},
"sprites": [
"resources/images/*.png"
]
},
"settings": {
"auto-save-rate": {
Expand Down
Binary file added resources/images/button-empty.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file removed resources/images/support-shard-0.png
Binary file not shown.
Binary file removed resources/images/support-shard-1.png
Binary file not shown.
Binary file removed resources/images/support-shard-2.png
Binary file not shown.
Binary file removed resources/images/support-shard-3.png
Binary file not shown.
199 changes: 164 additions & 35 deletions src/features/ImprovedScaleAndRotate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,78 @@
#include <Geode/modify/GJRotationControl.hpp>
#include <utils/Editor.hpp>
#include <numbers>
#include <span>

using namespace geode::prelude;

class ToggleSnapButton : public CCMenuItemSpriteExtra {
protected:
ButtonSprite* m_sprite;
size_t m_ix = 0;
std::span<float> m_snaps;
std::function<void(float)> m_callback;

bool init(std::span<float> snaps, std::function<void(float)> callback) {
m_sprite = ButtonSprite::create("", "bigFont.fnt", "button-empty.png"_spr, .8f);
m_sprite->setScale(.65f);
if (!CCMenuItemSpriteExtra::init(m_sprite, nullptr, nullptr, nullptr))
return false;

m_snaps = snaps;
m_callback = callback;
this->updateSprite();

return true;
}

void activate() override {
CCMenuItemSpriteExtra::activate();
m_ix += 1;
if (m_ix >= m_snaps.size()) {
m_ix = 0;
}
this->updateSprite();
if (m_callback) m_callback(m_snaps[m_ix]);
}

void updateSprite() {
m_sprite->setString(numToString(m_snaps[m_ix]).c_str());
m_sprite->m_label->setScale(.7f);
auto size = m_sprite->getScaledContentSize();
m_sprite->setPosition(size / 2);
m_sprite->setAnchorPoint(ccp(.5f, .5f));
this->setContentSize(size);
}

public:
static ToggleSnapButton* create(std::span<float> snaps, std::function<void(float)> callback) {
auto ret = new ToggleSnapButton();
if (ret && ret->init(snaps, callback)) {
ret->autorelease();
return ret;
}
CC_SAFE_DELETE(ret);
return nullptr;
}

void setIndex(size_t index) {
m_ix = index;
this->updateSprite();
if (m_callback) m_callback(m_snaps[m_ix]);
}
float getValue() const {
return m_snaps[m_ix];
}

void setEnabled(bool enabled) override {
CCMenuItemSpriteExtra::setEnabled(enabled);
m_sprite->setCascadeColorEnabled(true);
m_sprite->setCascadeOpacityEnabled(true);
m_sprite->setColor(enabled ? ccWHITE : ccGRAY);
m_sprite->setOpacity(enabled ? 255 : 155);
}
};

// Returns radians
static float angleOfPointOnCircle(CCPoint const& point) {
return atan2f(point.y, point.x) * (180.f / std::numbers::pi_v<float>);
Expand Down Expand Up @@ -37,18 +106,6 @@ class ScaleControlSnapLines : public CCNode {
this->setContentSize(ccp(210, 11));
this->setAnchorPoint(ccp(.5f, .5f));

// Smaller slider option
// The conditionals here are horrendous but eh I was lazy
bool big = GameManager::get()->getGameVariable("0112");
for (size_t i = (big ? 2 : 3); i < (big ? 16 : 8); i += 1) {
auto x = m_obContentSize.width / (big ? 15 : 6) * (i - (big ? 1 : 2));
auto spr = CCSprite::createWithSpriteFrameName(
(i % 4) ? "slider-tick-small.png"_spr : "slider-tick.png"_spr
);
spr->setOpacity((i % 4) ? 105 : 255);
this->addChildAtPosition(spr, Anchor::Left, ccp(x, 0));
}

return true;
}

Expand All @@ -62,13 +119,48 @@ class ScaleControlSnapLines : public CCNode {
CC_SAFE_DELETE(ret);
return nullptr;
}

void updateSnapSize(size_t snap) {
this->removeAllChildren();

// Bigger slider (from 0.25-4.00) option
bool big = GameManager::get()->getGameVariable("0112");

// Big slider starts at 0.25, small slider starts at 0.50
// The + .06f is for a lil buffer to make sure there aren't lines way
// too close to the edge
size_t start = ceilf(((big ? .25f : .50f) + .06f) * snap);

// Big slider ends at 4.00, small slider ends at 2.00
size_t count = (big ? snap * 4 : snap * 2);

float x = 42.f - 56.f / snap * (snap - start);
for (size_t i = start; i < count; i += 1) {
auto spr = CCSprite::createWithSpriteFrameName(
(i % snap) ? "slider-tick-small.png"_spr : "slider-tick.png"_spr
);
spr->setOpacity((i % snap) ? 105 : 255);
this->addChildAtPosition(spr, Anchor::Left, ccp(x, 0));
x += 56.f / snap;
}
}
};

class $modify(GJScaleControl) {
class $modify(SnappableScaleControl, GJScaleControl) {
$override
bool init() {
if (!GJScaleControl::init())
return false;

auto snapLinesX = ScaleControlSnapLines::create();
m_sliderX->addChild(snapLinesX);
m_sliderX->m_touchLogic->setZOrder(1);
auto snapLinesY = ScaleControlSnapLines::create();
m_sliderY->addChild(snapLinesY);
m_sliderY->m_touchLogic->setZOrder(1);
auto snapLinesXY = ScaleControlSnapLines::create();
m_sliderXY->addChild(snapLinesXY);
m_sliderXY->m_touchLogic->setZOrder(1);

m_scaleXLabel->setPositionX(-30);
m_scaleYLabel->setPositionX(-30);
Expand Down Expand Up @@ -115,27 +207,35 @@ class $modify(GJScaleControl) {

auto menu = m_scaleLockButton->getParent();
menu->setID("lock-menu"_spr);
menu->setContentWidth(50);
menu->setContentWidth(75);
menu->setLayout(RowLayout::create());

labelLockSpr(m_scaleLockButton->getNormalImage(), "Pos");

auto snapBtn = CCMenuItemToggler::create(
CCSprite::createWithSpriteFrameName("warpLockOffBtn_001.png"),
CCSprite::createWithSpriteFrameName("warpLockOnBtn_001.png"),
this, nullptr
this, menu_selector(SnappableScaleControl::onSnapLock)
);
snapBtn->toggle(false);
labelLockToggle(snapBtn, "Snap");
snapBtn->setID("snap-lock"_spr);
menu->addChild(snapBtn);

menu->setLayout(RowLayout::create());

m_sliderX->addChild(ScaleControlSnapLines::create());
m_sliderX->m_touchLogic->setZOrder(1);
m_sliderY->addChild(ScaleControlSnapLines::create());
m_sliderY->m_touchLogic->setZOrder(1);
m_sliderXY->addChild(ScaleControlSnapLines::create());
m_sliderXY->m_touchLogic->setZOrder(1);
static std::array SNAPS { 1.f / 3, .25f, .2f, 1.f / 6, .1f };
auto snapSizeBtn = ToggleSnapButton::create(
SNAPS, [snapLinesX, snapLinesY, snapLinesXY](float snap) {
snapLinesX->updateSnapSize(snap);
snapLinesY->updateSnapSize(snap);
snapLinesXY->updateSnapSize(snap);
}
);
snapSizeBtn->setEnabled(false);
snapSizeBtn->setIndex(1);
snapSizeBtn->setID("snap-lock-size"_spr);
menu->addChild(snapSizeBtn);

menu->updateLayout();

return true;
}
Expand Down Expand Up @@ -175,6 +275,10 @@ class $modify(GJScaleControl) {
labelLockSpr(m_scaleLockButton->getNormalImage(), "Pos");
}

void onSnapLock(CCObject* sender){
this->getSnapSizeBtn()->setEnabled(!static_cast<CCMenuItemToggler*>(sender)->m_toggled);
}

$override
void ccTouchMoved(CCTouch* touch, CCEvent* event) {
// Call original without the delegate so it doesn't fire an unnecessary
Expand All @@ -191,9 +295,11 @@ class $modify(GJScaleControl) {
auto scaleX = this->scaleFromValue(m_sliderX->getThumb()->getValue());
auto scaleY = this->scaleFromValue(m_sliderY->getThumb()->getValue());
auto ratio = scaleY / scaleX;
if (auto lock = this->getSnapLock(); lock && lock->isToggled()) {
scaleX = roundf(scaleX / .25f) * .25f;
scaleY = roundf(scaleY / .25f) * .25f;
auto snapBtn = this->getSnapSizeBtn();
if (auto lock = this->getSnapLock(); lock && snapBtn && lock->isToggled()) {
auto snap = snapBtn->getValue();
scaleX = roundf(scaleX / snap) * snap;
scaleY = roundf(scaleY / snap) * snap;
}

if (m_scaleButtonType == 0) {
Expand Down Expand Up @@ -261,6 +367,11 @@ class $modify(GJScaleControl) {
"hjfod.betteredit/lock-menu hjfod.betteredit/snap-lock"
));
}
ToggleSnapButton* getSnapSizeBtn() {
return static_cast<ToggleSnapButton*>(this->querySelector(
"hjfod.betteredit/lock-menu hjfod.betteredit/snap-lock-size"
));
}
};

class $modify(InputRotationControl, GJRotationControl) {
Expand All @@ -269,7 +380,6 @@ class $modify(InputRotationControl, GJRotationControl) {
if (!GJRotationControl::init())
return false;

// todo: you can place blocks through these
auto input = TextInput::create(50, "Num");
input->setScale(.8f);
input->setID("input-angle"_spr);
Expand All @@ -286,7 +396,7 @@ class $modify(InputRotationControl, GJRotationControl) {
this->addChild(input);

auto menu = CCMenu::create();
menu->setContentWidth(50);
menu->setContentWidth(75);
menu->setID("lock-menu"_spr);

auto posBtn = CCMenuItemToggler::create(
Expand All @@ -301,12 +411,19 @@ class $modify(InputRotationControl, GJRotationControl) {
auto snapBtn = CCMenuItemToggler::create(
CCSprite::createWithSpriteFrameName("warpLockOffBtn_001.png"),
CCSprite::createWithSpriteFrameName("warpLockOnBtn_001.png"),
this, nullptr
this, menu_selector(InputRotationControl::onSnapLock)
);
labelLockToggle(snapBtn, "Snap");
snapBtn->setID("snap-lock"_spr);
menu->addChild(snapBtn);

static std::array SNAPS { 10.f, 15.f, 18.f };
auto snapSizeBtn = ToggleSnapButton::create(SNAPS, nullptr);
snapSizeBtn->setEnabled(false);
snapSizeBtn->setIndex(1);
snapSizeBtn->setID("snap-lock-size"_spr);
menu->addChild(snapSizeBtn);

menu->setLayout(RowLayout::create());
menu->setPosition(110, 35);
this->addChild(menu);
Expand All @@ -318,11 +435,12 @@ class $modify(InputRotationControl, GJRotationControl) {
void draw() {
GJRotationControl::draw();
// Draw large ticks every 45° and small ticks every 15°
for (size_t i = 0; i < 24; i += 1) {
glLineWidth((i % 3) ? 1 : 2);
float len = (i % 3) ? 2.5f : 5;
float angle = i * 15;
ccDrawLine(pointOnCircle(angle, 60 - len), pointOnCircle(angle, 60 + len));
auto tickSize = this->getSnapSizeBtn()->getValue();
for (float angle = 0; angle < 360; angle += tickSize) {
bool isBigTick = size_t(angle) % 45;
glLineWidth(isBigTick ? 1 : 2);
float len = isBigTick ? 2.5f : 5;
ccDrawLine(pointOnCircle(angle + 90, 60 - len), pointOnCircle(angle + 90, 60 + len));
}
}

Expand All @@ -340,7 +458,8 @@ class $modify(InputRotationControl, GJRotationControl) {

auto angle = this->getThumbValue();
if (auto lock = this->getSnapLock(); lock && lock->isToggled()) {
angle = roundf(this->getThumbValue() / 15) * 15;
auto tickSize = this->getSnapSizeBtn()->getValue();
angle = roundf(this->getThumbValue() / tickSize) * tickSize;
m_controlSprite->setPosition(pointOnCircle(-angle + 90, 60));
}
m_delegate->angleChanged(angle);
Expand All @@ -356,6 +475,10 @@ class $modify(InputRotationControl, GJRotationControl) {
be::evilForceTouchPrio(static_cast<EditorUI*>(m_delegate), this->getInput()->getInputNode());
}

void onSnapLock(CCObject* sender){
this->getSnapSizeBtn()->setEnabled(!static_cast<CCMenuItemToggler*>(sender)->m_toggled);
}

float getThumbValue() const {
return -angleOfPointOnCircle(m_controlPosition) + 90;
}
Expand All @@ -378,6 +501,12 @@ class $modify(InputRotationControl, GJRotationControl) {
"hjfod.betteredit/lock-menu hjfod.betteredit/pos-lock"
));
}
// todo: this should probably be a field instead for efficiency
ToggleSnapButton* getSnapSizeBtn() {
return static_cast<ToggleSnapButton*>(this->querySelector(
"hjfod.betteredit/lock-menu hjfod.betteredit/snap-lock-size"
));
}
};

class $modify(EditorUI) {
Expand Down
16 changes: 2 additions & 14 deletions src/features/about/SupportPopup.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,8 @@
bool SupportPopup::setup(bool showDontShowAgain) {
m_bgSprite->setVisible(false);

// This incredibly silly practice is just to avoid CLI build times due to it not caching singular sprites
auto bg0 = CCSprite::createWithSpriteFrameName("support-shard-0.png"_spr);
bg0->setAnchorPoint({ 1, 0 });
m_mainLayer->addChildAtPosition(bg0, Anchor::Center);
auto bg1 = CCSprite::createWithSpriteFrameName("support-shard-1.png"_spr);
bg1->setAnchorPoint({ 0, 0 });
m_mainLayer->addChildAtPosition(bg1, Anchor::Center);
auto bg2 = CCSprite::createWithSpriteFrameName("support-shard-2.png"_spr);
bg2->setAnchorPoint({ 1, 1 });
m_mainLayer->addChildAtPosition(bg2, Anchor::Center);
auto bg3 = CCSprite::createWithSpriteFrameName("support-shard-3.png"_spr);
bg3->setAnchorPoint({ 0, 1 });
m_mainLayer->addChildAtPosition(bg3, Anchor::Center);
auto bg = CCSprite::create("support-popup.png"_spr);
m_mainLayer->addChildAtPosition(bg, Anchor::Center);

auto invisibleSupportSpr = ButtonSprite::create("Support", "goldFont.fnt", "GJ_button_01.png", .8f);
invisibleSupportSpr->setScale(1.8f);
Expand All @@ -29,7 +18,6 @@ bool SupportPopup::setup(bool showDontShowAgain) {
);
m_buttonMenu->addChildAtPosition(invisibleSupportBtn, Anchor::Center, ccp(0, 20));


auto bottomMenu = CCMenu::create();
bottomMenu->setContentWidth(200);
bottomMenu->setAnchorPoint({ .5f, .5f });
Expand Down

0 comments on commit 6cbd785

Please sign in to comment.