Skip to content

Add a draggable button for mobile #54

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions mod.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,11 @@
"url": "https://github.com/geode-sdk/DevTools/issues",
"info": "If you encounter an issue using DevTools, please report it to the GitHub issues page."
},
"resources": {
"sprites": [
"resources/*.png"
]
},
"settings": {
"should-use-gd-window": {
"type": "bool",
Expand Down
Binary file added resources/devtools.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
16 changes: 15 additions & 1 deletion src/DevTools.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@ struct matjson::Serialize<Settings> {
.advancedSettings = value["advanced_settings"].asBool().unwrapOr(std::move(defaults.advancedSettings)),
.showMemoryViewer = value["show_memory_viewer"].asBool().unwrapOr(std::move(defaults.showMemoryViewer)),
.theme = value["theme"].asString().unwrapOr(std::move(defaults.theme)),
.buttonScale = value["button_scale"].as<float>().unwrapOr(std::move(defaults.buttonScale)),
.buttonOpacity = value["button_opacity"].as<int>().unwrapOr(std::move(defaults.buttonOpacity)),
.buttonInGameplay = value["button_gameplay"].asBool().unwrapOr(std::move(defaults.buttonInGameplay)),
.buttonInEditor = value["button_editor"].asBool().unwrapOr(std::move(defaults.buttonInEditor)),
});
}

Expand All @@ -39,6 +43,10 @@ struct matjson::Serialize<Settings> {
{ "advanced_settings", settings.advancedSettings },
{ "show_memory_viewer", settings.showMemoryViewer },
{ "theme", settings.theme },
{ "button_scale", settings.buttonScale },
{ "button_opacity", settings.buttonOpacity },
{ "button_gameplay", settings.buttonInGameplay },
{ "button_editor", settings.buttonInEditor },
});
}
};
Expand All @@ -50,9 +58,15 @@ DevTools* DevTools::get() {
return inst;
}

void DevTools::loadSettings() { m_settings = Mod::get()->getSavedValue<Settings>("settings"); }
void DevTools::loadSettings() {
m_settings = Mod::get()->getSavedValue<Settings>("settings");
}
void DevTools::saveSettings() { Mod::get()->setSavedValue("settings", m_settings); }

Settings DevTools::getSettings() {
return m_settings;
}

bool DevTools::shouldPopGame() const {
return m_visible && m_settings.GDInWindow;
}
Expand Down
6 changes: 6 additions & 0 deletions src/DevTools.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,11 @@ struct Settings {
bool advancedSettings = false;
bool showMemoryViewer = false;
std::string theme = DARK_THEME;

float buttonScale = 1.f;
int buttonOpacity = 255;
bool buttonInGameplay = false;
bool buttonInEditor = false;
};

class DevTools {
Expand Down Expand Up @@ -81,6 +86,7 @@ class DevTools {
static DevTools* get();
void loadSettings();
void saveSettings();
Settings getSettings();

bool shouldUseGDWindow() const;

Expand Down
25 changes: 13 additions & 12 deletions src/main.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@

#include "platform/platform.hpp"
#include <Geode/modify/CCKeyboardDispatcher.hpp>
#include <Geode/modify/AchievementNotifier.hpp>
Expand Down Expand Up @@ -30,17 +29,6 @@ class $modify(CCKeyboardDispatcher) {
}
};

#ifdef GEODE_IS_MOBILE
// lol
#include <Geode/modify/MenuLayer.hpp>
class $modify(MenuLayer) {
void onMoreGames(CCObject*) {
DevTools::get()->toggle();
}
};

#endif

class $modify(CCDirector) {
void willSwitchToScene(CCScene* scene) {
CCDirector::willSwitchToScene(scene);
Expand Down Expand Up @@ -112,3 +100,16 @@ class $modify(CCEGLView) {
CCEGLView::swapBuffers();
}
};


// For the one eclipse shortcut
struct ToggleDevToolsEvent : geode::Event {
ToggleDevToolsEvent() {}
};

$on_mod(Loaded) {
new EventListener<EventFilter<ToggleDevToolsEvent>>(+[](ToggleDevToolsEvent* e) {
DevTools::get()->toggle();
return ListenerResult::Stop;
});
}
177 changes: 177 additions & 0 deletions src/nodes/DragButton.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@
#include "../DevTools.hpp"
#include "DragButton.hpp"

DragButton *DragButton::m_instance = nullptr;

bool DragButton::init() {
if (!CCMenu::init())
return false;
m_sprite = CircleButtonSprite::createWithSprite("devtools.png"_spr, 1,
CircleBaseColor::Green, CircleBaseSize::MediumAlt);
m_sprite->setScale(.8f);
m_sprite->setID("sprite");
addChild(m_sprite);
setContentSize(m_sprite->getScaledContentSize());
m_sprite->setPosition(getContentSize() / 2);

CCScene::get()->addChild(this);
SceneManager::get()->keepAcrossScenes(this);
scheduleUpdate();

setZOrder(70000);

auto x = Mod::get()->getSavedValue<float>("button-x", 50.f);
auto y = Mod::get()->getSavedValue<float>("button-y", 50.f);
x = std::clamp(x, -getContentWidth() / 2, CCDirector::get()->getWinSize().width - getContentWidth() / 2);
y = std::clamp(y, -getContentHeight() / 2, CCDirector::get()->getWinSize().height - getContentHeight() / 2);
setPosition({x, y});

Mod::get()->setSavedValue<float>("button-x", x);
Mod::get()->setSavedValue<float>("button-y", y);
auto settings = DevTools::get()->getSettings();
setOpacity(settings.buttonOpacity);
setScale(settings.buttonScale);

setID("drag-button"_spr);

return true;
};

DragButton *DragButton::get() {
if (m_instance)
return m_instance;
m_instance = new DragButton();
if (m_instance && m_instance->init()) {
m_instance->autorelease();
return m_instance;
} else {
delete m_instance;
return nullptr;
}
}

void DragButton::registerWithTouchDispatcher() {
CCTouchDispatcher::get()->addTargetedDelegate(this, -512, true);
}

bool DragButton::ccTouchBegan(CCTouch *touch, CCEvent *evt) {
if (!m_handleTouch || !m_bVisible)
return false;
if (getScaledContentSize().width / 2 <
ccpDistance(m_sprite->getPosition(), convertToNodeSpace(touch->getLocation()))) {
return false;
}

m_diff = getPosition() - touch->getLocation();
m_startPos = new CCPoint(touch->getLocation());

m_moving = false;

m_sprite->stopAllActions();

// For some reason I could not get a recreation of CCEaseSineOut working on ios.
#ifdef GEODE_IS_IOS
m_sprite->runAction(CCEaseOut::create(CCScaleTo::create(0.3f, .8 * m_scale * m_multiplier), 1.6f));
#else
m_sprite->runAction(CCEaseSineOut::create(CCScaleTo::create(0.3f, .8 * m_scale * m_multiplier)));
#endif
return true;
}

void DragButton::ccTouchCancelled(CCTouch *touch, CCEvent *event) {
ccTouchEnded(touch, event);
}

void DragButton::ccTouchEnded(CCTouch *touch, CCEvent *evt) {
m_sprite->stopAllActions();

// For some reason I could not get a recreation of CCEaseSineOut working on ios.
#ifdef GEODE_IS_IOS
m_sprite->runAction(CCEaseOut::create(CCScaleTo::create(0.3f, .8 * m_scale), 1.6f));
#else
m_sprite->runAction(CCEaseSineOut::create(CCScaleTo::create(0.3f, .8 * m_scale)));
#endif
if (m_moving) {
Mod::get()->setSavedValue<float>("button-x", getPositionX());
Mod::get()->setSavedValue<float>("button-y", getPositionY());
return;
}
activate();
}

void DragButton::ccTouchMoved(CCTouch *touch, CCEvent *evt) {
if (!m_moving)
if (ccpDistance(*m_startPos, touch->getLocation()) > 3)
m_moving = true;
if (m_moving) {
auto pos = touch->getLocation() + m_diff;
pos.x = std::clamp(pos.x, -getContentWidth() / 2, CCDirector::get()->getWinSize().width - getContentWidth() / 2);
pos.y = std::clamp(pos.y, -getContentHeight() / 2, CCDirector::get()->getWinSize().height - getContentHeight() / 2);
setPosition(pos);
}
}

void DragButton::update(float delta) {
static auto devtools = DevTools::get();
bool shouldRender = true;
if (auto pl = PlayLayer::get(); pl && !pl->m_isPaused) {
shouldRender = devtools->getSettings().buttonInGameplay;
} else if(auto el = LevelEditorLayer::get()) {
if (devtools->getSettings().buttonInEditor) {
shouldRender = el->m_playbackMode != PlaybackMode::Playing || devtools->getSettings().buttonInGameplay;
} else {
shouldRender = false;
}
}
setVisible(shouldRender && m_render);
}

bool DragButton::isRendered() {
return m_render;
}

void DragButton::setRendered(bool render) {
m_render = render;
}

bool DragButton::isHandlingTouch() {
return m_render && m_handleTouch;
}

void DragButton::setHandlingTouch(bool handle) { m_handleTouch = handle; }

void DragButton::activate() {
DevTools::get()->toggle();
}

// Only make it show if on mobile
#ifdef GEODE_IS_MOBILE
#include <Geode/modify/CCScene.hpp>

class $modify(CCScene) {
int getHighestChildZ() {
int btnZ;
auto btn = DragButton::get();
if (btn) {
btnZ = btn->getZOrder();
btn->setZOrder(-1);
}
auto highest = CCScene::getHighestChildZ();
if (btn) {
btn->setZOrder(btnZ);
}
return highest;
}
};

#include <Geode/modify/MenuLayer.hpp>

class $modify(MenuLayer) {
bool init() {
if (!MenuLayer::init()) return false;

DragButton::get();
return true;
}
};
#endif
36 changes: 36 additions & 0 deletions src/nodes/DragButton.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
#pragma once

#include <Geode/Geode.hpp>

using namespace geode::prelude;

class DragButton : public cocos2d::CCMenu {
protected:
static DragButton *m_instance;

bool m_handleTouch = true;
bool m_render = true;
bool m_moving = false;

cocos2d::CCPoint *m_startPos;
cocos2d::CCPoint m_diff;
cocos2d::CCSprite *m_sprite;

float m_scale = 1.0f;
float m_multiplier = 0.8f;

bool init() override;
void update(float delta) override;
bool ccTouchBegan(cocos2d::CCTouch *touch, cocos2d::CCEvent *event) override;
void ccTouchEnded(cocos2d::CCTouch *touch, cocos2d::CCEvent *event) override;
void ccTouchMoved(cocos2d::CCTouch *touch, cocos2d::CCEvent *event) override;
void ccTouchCancelled(cocos2d::CCTouch *touch, cocos2d::CCEvent *event) override;
void registerWithTouchDispatcher() override;
public:
static DragButton *get();
void activate();
bool isRendered();
void setRendered(bool render);
bool isHandlingTouch();
void setHandlingTouch(bool handle);
};
21 changes: 21 additions & 0 deletions src/pages/Settings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include <fmod.hpp>
#include <numeric>
#include <Geode/binding/GameManager.hpp>
#include "../nodes/DragButton.hpp"

using namespace geode::prelude;

Expand Down Expand Up @@ -208,6 +209,26 @@ void DevTools::drawSettings() {
if (ImGui::Button("Reset Layout")) {
m_shouldRelayout = true;
}

#ifdef GEODE_IS_MOBILE
auto button = DragButton::get();

ImGui::Separator();

ImGui::Text("Draggable Button");

if (ImGui::DragFloat("Scale", &m_settings.buttonScale, 0.05f, 0.5f, 1.f)) {
button->setScale(m_settings.buttonScale);
}

if (ImGui::DragInt("Opacity", &m_settings.buttonOpacity, 1, 0, 255)) {
button->setOpacity(m_settings.buttonOpacity);
}

ImGui::Checkbox("Visible in Game", &m_settings.buttonInGameplay);
ImGui::Checkbox("Visible in Editor", &m_settings.buttonInEditor);

#endif
}

// TODO: this hook also isnt gd *
Expand Down