Skip to content

Commit 0af4b00

Browse files
authored
Merge pull request #28 from Alphalaneous/thumbnail-popup
Thumbnail Popup and Crash Fixes
2 parents f4e6632 + 1ee1061 commit 0af4b00

6 files changed

+293
-33
lines changed

src/ImageCache.cpp

+2
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ ImageCache::ImageCache(){
1111

1212
void ImageCache::addImage(CCImage* image, std::string key){
1313

14+
if(!image) return;
15+
1416
if(m_imageDict->count() >= Mod::get()->getSettingValue<int64_t>("cache-limit")){
1517
m_imageDict->removeObjectForKey(static_cast<CCString*>(m_imageDict->allKeys()->objectAtIndex(0))->getCString());
1618
}

src/ThumbnailPopup.cpp

+89-25
Original file line numberDiff line numberDiff line change
@@ -8,22 +8,17 @@ using namespace geode::prelude;
88
#include "utils.hpp"
99
#include "ImageCache.hpp"
1010

11-
void ThumbnailPopup::onDownload(CCObject*sender){
11+
void ThumbnailPopup::onDownload(CCObject* sender){
1212
std::string URL = fmt::format("https://raw.githubusercontent.com/cdc-sys/level-thumbnails/main/thumbs/{}.png", m_levelID);
1313
CCApplication::sharedApplication()->openURL(URL.c_str());
1414
}
1515

16-
void ThumbnailPopup::openDiscordServerPopup(){
17-
if (Mod::get()->getSavedValue<bool>("discord-ad-shown")){
18-
return;
19-
}
20-
else{
21-
Mod::get()->setSavedValue<bool>("discord-ad-shown",true);
22-
}
16+
void ThumbnailPopup::openDiscordServerPopup(CCObject* sender){
17+
2318
createQuickPopup(
2419
"Uh Oh!",
2520
"Hm.. This level seems to not have a <cj>Thumbnail</c>...\n"
26-
"Worry not! You can join our <cg>Discord Server</c> and submit a thumbnail <cy>YOURSELF!</c>\n<cb>(Don't worry, you can always find the server link in the mod about page..)</c>",
21+
"Worry not! You can join our <cg>Discord Server</c> and submit a thumbnail <cy>YOURSELF!</c>",
2722
"No Thanks", "JOIN!",
2823
[this](auto, bool btn2) {
2924
if (btn2) {
@@ -36,17 +31,63 @@ void ThumbnailPopup::openDiscordServerPopup(){
3631
bool ThumbnailPopup::setup(int id) {
3732
m_noElasticity = false;
3833
auto winSize = CCDirector::sharedDirector()->getWinSize();
34+
setID("ThumbnailPopup");
35+
setTitle("");
36+
37+
CCScale9Sprite* border = CCScale9Sprite::create("GJ_square07.png");
38+
border->setContentSize(m_bgSprite->getContentSize());
39+
border->setPosition(m_bgSprite->getPosition());
40+
border->setZOrder(2);
41+
42+
CCLayerColor* mask = CCLayerColor::create({255, 255, 255});
43+
mask->setContentSize({391, 220});
44+
mask->setPosition({m_bgSprite->getContentSize().width / 2 - 391/2, m_bgSprite->getContentSize().height/2 - 220/2});
45+
46+
m_bgSprite->setColor({50,50,50});
47+
48+
m_clippingNode = CCClippingNode::create();
49+
m_clippingNode->setContentSize(m_bgSprite->getContentSize());
50+
m_clippingNode->setStencil(mask);
51+
m_clippingNode->setZOrder(1);
3952

40-
setTitle("Thumbnail");
53+
m_mainLayer->addChild(border);
54+
m_mainLayer->addChild(m_clippingNode);
4155

42-
CCMenu* downloadMenu = CCMenu::create();
4356
CCSprite* downloadSprite = CCSprite::createWithSpriteFrameName("GJ_downloadBtn_001.png");
44-
m_downloadBtn = CCMenuItemSpriteExtra::create(downloadSprite,this,menu_selector(ThumbnailPopup::onDownload));
57+
m_downloadBtn = CCMenuItemSpriteExtra::create(downloadSprite, this, menu_selector(ThumbnailPopup::onDownload));
4558
m_downloadBtn->setEnabled(false);
4659
m_downloadBtn->setColor({125,125,125});
47-
downloadMenu->setPosition({m_mainLayer->getContentWidth()-28,30});
48-
downloadMenu->addChild(m_downloadBtn);
49-
m_mainLayer->addChild(downloadMenu);
60+
61+
m_downloadBtn->setPosition({m_mainLayer->getContentSize().width - 5, 5});
62+
63+
m_buttonMenu->addChild(m_downloadBtn);
64+
65+
CCSprite* recenterSprite = CCSprite::createWithSpriteFrameName("GJ_undoBtn_001.png");
66+
CCMenuItemSpriteExtra* recenterBtn = CCMenuItemSpriteExtra::create(recenterSprite, this, menu_selector(ThumbnailPopup::recenter));
67+
68+
recenterBtn->setPosition({5, 5});
69+
m_buttonMenu->addChild(recenterBtn);
70+
71+
#ifndef GEODE_IS_WINDOWS
72+
recenterBtn->setVisible(false);
73+
#endif
74+
75+
ButtonSprite* infoSprite = ButtonSprite::create("More Info");
76+
m_infoBtn = CCMenuItemSpriteExtra::create(infoSprite, this, menu_selector(ThumbnailPopup::openDiscordServerPopup));
77+
78+
m_infoBtn->setPosition({m_mainLayer->getContentSize().width/2, 6});
79+
m_infoBtn->setVisible(false);
80+
m_infoBtn->setZOrder(3);
81+
82+
m_buttonMenu->addChild(m_infoBtn);
83+
84+
m_theFunny = CCLabelBMFont::create("Hey there! OwO", "bigFont.fnt");
85+
m_theFunny->setPosition(m_bgSprite->getPosition());
86+
m_theFunny->setVisible(false);
87+
m_theFunny->setScale(0.25f);
88+
89+
m_mainLayer->addChild(m_theFunny);
90+
5091
m_loadingCircle->setParentLayer(m_mainLayer);
5192
m_loadingCircle->setPosition({ -70,-40 });
5293
m_loadingCircle->setScale(1.f);
@@ -77,7 +118,6 @@ bool ThumbnailPopup::setup(int id) {
77118
imageCreationFinished(m_image);
78119
});
79120
});
80-
m_loadingCircle->fadeAndRemove();
81121
imageThread.detach();
82122
}
83123
}
@@ -96,28 +136,52 @@ void ThumbnailPopup::imageCreationFinished(CCImage* image){
96136
onDownloadFinished(CCSprite::createWithTexture(texture));
97137
}
98138

99-
void ThumbnailPopup::onDownloadFinished(CCSprite* sprite) {
139+
void ThumbnailPopup::recenter(CCObject* sender){
140+
141+
if(CCNode* node = m_clippingNode->getChildByID("thumbnail")) {
142+
node->setPosition({m_mainLayer->getContentWidth()/2,m_mainLayer->getContentHeight()/2});
143+
node->stopAllActions();
144+
float scale = m_maxHeight/node->getContentSize().height;
145+
node->setUserObject("new-scale", CCFloat::create(scale));
146+
node->setScale(scale);
147+
}
148+
}
149+
150+
void ThumbnailPopup::onDownloadFinished(CCSprite* image) {
100151
// thanks for fucking this up sheepdotcom
101152
m_downloadBtn->setEnabled(true);
102153
m_downloadBtn->setColor({255,255,255});
103-
CCSprite* image = sprite;
104-
image->setScale(0.65f / levelthumbs::getQualityMultiplier());
105-
image->setPosition({(m_mainLayer->getContentWidth()/2),(m_mainLayer->getContentHeight()/2)-10.f});
106-
m_mainLayer->addChild(image);
154+
155+
float scale = m_maxHeight/image->getContentSize().height;
156+
image->setScale(scale);
157+
image->setUserObject("scale", CCFloat::create(scale));
158+
image->setPosition({m_mainLayer->getContentWidth()/2,m_mainLayer->getContentHeight()/2});
159+
160+
image->setID("thumbnail");
161+
m_clippingNode->addChild(image);
162+
m_loadingCircle->fadeAndRemove();
107163
}
108164

109165
void ThumbnailPopup::onDownloadFail() {
110166
// thanks for the image cvolton ;)
111167
CCSprite* image = CCSprite::create("noThumb.png"_spr);
112-
image->setScale(0.65f );
113-
image->setPosition({(m_mainLayer->getContentWidth()/2),(m_mainLayer->getContentHeight()/2)-10.f});
114-
m_mainLayer->addChild(image);
168+
float scale = m_maxHeight/image->getContentSize().height;
169+
image->setScale(scale);
170+
image->setUserObject("scale", CCFloat::create(scale));
171+
image->setPosition({m_mainLayer->getContentWidth()/2, m_mainLayer->getContentHeight()/2});
172+
image->setID("thumbnail");
173+
174+
m_infoBtn->setVisible(true);
175+
m_theFunny->setVisible(true);
176+
m_clippingNode->addChild(image);
177+
m_loadingCircle->fadeAndRemove();
178+
115179
}
116180

117181
ThumbnailPopup* ThumbnailPopup::create(int id) {
118182
auto ret = new ThumbnailPopup();
119183
ret->m_levelID = id;
120-
if (ret && ret->initAnchored(420, 240, -1, "GJ_square01.png")) {
184+
if (ret && ret->initAnchored(395, 225, -1, "GJ_square05.png")) {
121185
ret->autorelease();
122186
return ret;
123187
}

src/ThumbnailPopup.hpp

+7-2
Original file line numberDiff line numberDiff line change
@@ -7,17 +7,22 @@ using namespace geode::prelude;
77
class ThumbnailPopup : public Popup<int> {
88
protected:
99
int m_levelID;
10+
float m_maxHeight = 220;
1011
EventListener<web::WebTask> m_downloadListener;
1112
LoadingCircle* m_loadingCircle = LoadingCircle::create();
1213
CCMenuItemSpriteExtra* m_downloadBtn;
14+
CCMenuItemSpriteExtra* m_infoBtn;
15+
CCClippingNode* m_clippingNode;
1316
Ref<CCImage> m_image;
17+
CCLabelBMFont* m_theFunny;
1418

1519
bool setup(int id) override;
1620
void onDownloadFinished(CCSprite* sprite);
1721
void onDownloadFail();
1822
void imageCreationFinished(CCImage* image);
19-
void onDownload(CCObject*sender);
20-
void openDiscordServerPopup();
23+
void onDownload(CCObject* sender);
24+
void openDiscordServerPopup(CCObject* sender);
25+
void recenter(CCObject* sender);
2126

2227
public:
2328
static ThumbnailPopup* create(int id);

src/Zoom.cpp

+148
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
#include "Zoom.hpp"
2+
3+
#ifdef GEODE_IS_WINDOWS
4+
5+
#include <Geode/modify/CCMouseDispatcher.hpp>
6+
#include <Geode/modify/CCEGLView.hpp>
7+
#include <Geode/modify/CCScheduler.hpp>
8+
9+
Zoom* Zoom::instance = nullptr;
10+
11+
bool checkIfInside(CCLayer* layer, CCPoint pos){
12+
float x = layer->getPosition().x - layer->getContentSize().width * layer->getAnchorPoint().x;
13+
float y = layer->getPosition().y - layer->getContentSize().height * layer->getAnchorPoint().y;
14+
float width = layer->getContentSize().width;
15+
float height = layer->getContentSize().height;
16+
17+
CCRect r = {x, y, width, height};
18+
19+
CCPoint local = CCScene::get()->convertToNodeSpace(pos);
20+
21+
return r.containsPoint(local);
22+
}
23+
24+
void Zoom::doZoom(float y){
25+
26+
float zoom = 0.1f * (y > 0 ? -1 : 1);
27+
auto pos = getMousePos();
28+
29+
CCNode* thumbnailPopup = CCScene::get()->getChildByID("ThumbnailPopup");
30+
if (!thumbnailPopup) return;
31+
32+
CCLayer* popupLayer = getChildOfType<CCLayer>(thumbnailPopup, 0);
33+
if(!popupLayer) return;
34+
35+
CCNode* thumbnail = thumbnailPopup->getChildByIDRecursive("thumbnail");
36+
if(!thumbnail) return;
37+
38+
if(!checkIfInside(popupLayer, pos)) return;
39+
40+
CCSize contentSize = thumbnail->getContentSize();
41+
42+
float oldScale = thumbnail->getScale();
43+
44+
if(CCFloat* val = static_cast<CCFloat*>(thumbnail->getUserObject("new-scale"))){
45+
oldScale = val->getValue();
46+
}
47+
48+
float newScale;
49+
float origScale = static_cast<CCFloat*>(thumbnail->getUserObject("scale"))->getValue();
50+
51+
if (zoom < 0) {
52+
newScale = oldScale / (1 - zoom);
53+
} else {
54+
newScale = oldScale * (1 + zoom);
55+
}
56+
57+
if (newScale < origScale * 0.75) {
58+
newScale = origScale * 0.75;
59+
}
60+
61+
if (newScale > origScale * 100) {
62+
newScale = origScale * 100;
63+
}
64+
65+
float currentScale = thumbnail->getScale();
66+
67+
auto prevPos = thumbnail->convertToNodeSpace(pos);
68+
thumbnail->setScale(newScale);
69+
auto newPos = thumbnail->convertToWorldSpace(prevPos);
70+
thumbnail->setScale(currentScale);
71+
thumbnail->setUserObject("new-scale", CCFloat::create(newScale));
72+
73+
thumbnail->stopAllActions();
74+
thumbnail->runAction(CCMoveTo::create(0.1, thumbnail->getPosition() + pos - newPos));
75+
thumbnail->runAction(CCScaleTo::create(0.1, newScale));
76+
}
77+
78+
void Zoom::update(float dt){
79+
auto pos = getMousePos();
80+
auto lastMousePos = m_lastMousePos;
81+
82+
CCNode* thumbnailPopup = CCScene::get()->getChildByID("ThumbnailPopup");
83+
if (!thumbnailPopup) return;
84+
85+
CCLayer* popupLayer = getChildOfType<CCLayer>(thumbnailPopup, 0);
86+
if(!popupLayer) return;
87+
88+
CCNode* thumbnail = thumbnailPopup->getChildByIDRecursive("thumbnail");
89+
if(!thumbnail) return;
90+
91+
m_deltaMousePos = CCPoint{ pos.x - lastMousePos.x, pos.y - lastMousePos.y };
92+
m_lastMousePos = pos;
93+
94+
if(!checkIfInside(popupLayer, pos) && !m_isDragging) return;
95+
96+
if (m_isTouching) {
97+
98+
m_isDragging = true;
99+
m_deltaMousePos = thumbnailPopup->convertToNodeSpace(m_deltaMousePos) ;
100+
101+
CCPoint pos = thumbnail->getPosition();
102+
103+
CCPoint newPos = pos + m_deltaMousePos;
104+
105+
float posX = newPos.x;
106+
float posY = newPos.y;
107+
108+
109+
thumbnail->setPosition({posX, posY});
110+
}
111+
else {
112+
m_isDragging = false;
113+
}
114+
}
115+
116+
class $modify(CCScheduler) {
117+
virtual void update(float dt) {
118+
Zoom::get()->update(dt);
119+
CCScheduler::update(dt);
120+
}
121+
};
122+
123+
class $modify(CCMouseDispatcher) {
124+
bool dispatchScrollMSG(float y, float x) {
125+
Zoom::get()->doZoom(y);
126+
return CCMouseDispatcher::dispatchScrollMSG(y, x);
127+
}
128+
};
129+
130+
class $modify(CCEGLView) {
131+
void onGLFWMouseCallBack(GLFWwindow* window, int button, int action, int mods) {
132+
if (button == GLFW_MOUSE_BUTTON_LEFT) {
133+
switch(action){
134+
case GLFW_PRESS: {
135+
Zoom::get()->m_isTouching = true;
136+
break;
137+
}
138+
case GLFW_RELEASE: {
139+
Zoom::get()->m_isTouching = false;
140+
break;
141+
}
142+
}
143+
}
144+
CCEGLView::onGLFWMouseCallBack(window, button, action, mods);
145+
}
146+
};
147+
148+
#endif

src/Zoom.hpp

+34
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
#pragma once
2+
3+
#ifndef __ZOOM_H
4+
#define __ZOOM_H
5+
6+
#include <Geode/Geode.hpp>
7+
8+
using namespace geode::prelude;
9+
10+
class Zoom {
11+
12+
protected:
13+
static Zoom* instance;
14+
CCPoint m_lastMousePos;
15+
CCPoint m_deltaMousePos;
16+
bool m_isDragging = false;
17+
public:
18+
bool m_isTouching = false;
19+
20+
void onScroll(float x, float y);
21+
void update(float dt);
22+
void doZoom(float zoom);
23+
24+
static Zoom* get(){
25+
26+
if (!instance) {
27+
instance = new Zoom();
28+
};
29+
return instance;
30+
}
31+
};
32+
33+
34+
#endif

0 commit comments

Comments
 (0)