Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
54dcb05
Added rich text!
abb2k Jan 28, 2026
ef54576
remove CCObjects and changed to geode::Function
abb2k Jan 28, 2026
8c6b489
small naming changes and stuff!
abb2k Jan 28, 2026
5001acc
some styling improvements
abb2k Jan 28, 2026
2cd0a0f
some more very small changes
abb2k Jan 28, 2026
e9f1fa2
Merge remote-tracking branch 'upstream/main' into v5
abb2k Feb 2, 2026
d29597c
split rich text functionality to RichTextArea!
abb2k Feb 3, 2026
b8ab3bc
Merge remote-tracking branch 'upstream/main' into v5
abb2k Feb 3, 2026
a3c1f38
added links and clickable text keys :) (pls let me know what i can do…
abb2k Feb 3, 2026
c55bd57
Merge remote-tracking branch 'upstream/main' into rich-txt-area
xblazegmd Feb 3, 2026
5e66c45
changed fmt::localtime and moved registerRichTextKey out of impl
abb2k Feb 3, 2026
96218fa
changed localtime (again)
abb2k Feb 3, 2026
88807e9
Better pimpl
xblazegmd Feb 3, 2026
46eae0a
Merge remote-tracking branch 'upstream/main' into rich-txt-area
xblazegmd Feb 3, 2026
cfaca0b
Forgot abt this 🫠
xblazegmd Feb 3, 2026
4a44ac4
Merge branch 'v5' into rich-txt-area
xblazegmd Feb 3, 2026
d0aaad9
Merge pull request #1 from xblazegmd/rich-txt-area
abb2k Feb 3, 2026
d0f7028
Merge remote-tracking branch 'upstream/main' into v5
abb2k Feb 3, 2026
e3e0d89
Merge remote-tracking branch 'upstream/main' into v5
abb2k Feb 4, 2026
5fad745
fixed pimpl kinda but also rich text not working anymore?? :( help
abb2k Feb 4, 2026
9abf2d0
made both classes use the same m_impl variable so they actually work …
abb2k Feb 4, 2026
26194b3
Some polish
xblazegmd Feb 5, 2026
f565c01
Fix history
xblazegmd Feb 5, 2026
e9915b1
Merge remote-tracking branch 'origin/main' into rich-txt-area-fix
xblazegmd Feb 5, 2026
e5a1e46
Merge pull request #2 from xblazegmd/rich-txt-area-fix
abb2k Feb 5, 2026
392151c
Merge remote-tracking branch 'upstream/main' into v5
abb2k Feb 6, 2026
3ed3f57
rich text fixed! added wave effect key!
abb2k Feb 6, 2026
1894478
Merge remote-tracking branch 'upstream/main' into v5
abb2k Feb 14, 2026
052c7c8
removed wave effect :(
abb2k Feb 14, 2026
bacd1e8
Merge remote-tracking branch 'upstream/main' into v5
abb2k Feb 16, 2026
35ff21e
moved Impl into geode namespace
abb2k Feb 16, 2026
192b132
fixed includes being wrong
abb2k Feb 16, 2026
6053444
Merge remote-tracking branch 'upstream/main' into v5
abb2k Apr 11, 2026
80a7283
solved first issue i think
abb2k Apr 11, 2026
b4a87e4
attempted to remove saving castedImpl as a variable as from what i gu…
abb2k Apr 11, 2026
e65ea73
split link click functionality into a separate function
abb2k Apr 11, 2026
4474348
fixed RichTextArea not getting itself (oops)
abb2k Apr 11, 2026
94c6712
added method for getting the raw text with the rich keys
abb2k Apr 11, 2026
6e4459d
made 'registerRichTextKey' not template so that others can add their …
abb2k Apr 11, 2026
a525ebb
moved a small amount of generic functions so i can actually register …
abb2k Apr 11, 2026
9541593
added a way for people to use local index relative to key origin when…
abb2k Apr 11, 2026
66d61a2
fix for link buttons crash and color
abb2k Apr 11, 2026
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
200 changes: 195 additions & 5 deletions loader/include/Geode/ui/TextArea.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
#include <cocos2d.h>

namespace geode {
class SimpleTextAreaImpl;

enum WrappingMode {
NO_WRAP,
WORD_WRAP,
Expand All @@ -24,6 +26,7 @@ namespace geode {
*
* Contact me on Discord (\@smjs) if you have any questions, suggestions or bugs.
*/

class GEODE_DLL SimpleTextArea : public cocos2d::CCNode {
public:
static SimpleTextArea* create(std::string text, std::string font = "chatFont.fnt", float scale = 1.0f);
Expand All @@ -37,7 +40,7 @@ namespace geode {
cocos2d::CCTextAlignment getAlignment();
void setWrappingMode(WrappingMode mode);
WrappingMode getWrappingMode();
void setText(std::string text);
virtual void setText(std::string text);
std::string getText();
void setMaxLines(size_t maxLines);
size_t getMaxLines();
Expand All @@ -50,17 +53,204 @@ namespace geode {
std::vector<cocos2d::CCLabelBMFont*> getLines();
float getHeight();
float getLineHeight();

protected:
SimpleTextArea();
~SimpleTextArea() override;


virtual std::unique_ptr<SimpleTextAreaImpl> createImpl();
std::unique_ptr<SimpleTextAreaImpl> m_impl;

bool init(std::string font, std::string text, float scale, float width, const bool artificialWidth);
private:
static SimpleTextArea* create(std::string font, std::string text, float scale, float width, const bool artificialWidth);
};

bool init(std::string font, std::string text, float scale, float width, const bool artificialWidth);
// abb2k wuz here :)

template <class T>
class RichTextKey;

class RichTextKeyInstanceBase {
public:
virtual ~RichTextKeyInstanceBase() = default;
virtual void applyChangesToSprite(cocos2d::CCFontSprite* spr, int localIndex, int index) = 0;
virtual std::string getKey() const = 0;
virtual bool isCancellation() const = 0;
virtual std::string runStrAddition() = 0;
virtual bool isButton() const = 0;
virtual void callButton(bool keyDown, cocos2d::CCFontSprite* spr, std::set<cocos2d::CCFontSprite*> const& word) = 0;
};

template <class T>
class RichTextKeyInstance final : public RichTextKeyInstanceBase {
public:
RichTextKeyInstance(RichTextKey<T>* key, T data, bool cancellation)
: m_key(std::move(key)), m_value(std::move(data)), m_cancellation(std::move(cancellation)) {}

RichTextKey<T>* m_key = nullptr;
T m_value;
bool m_cancellation = false;

void applyChangesToSprite(cocos2d::CCFontSprite* spr, int localIndex, int index) override {
if (m_key->m_applyToSprite != NULL)
m_key->m_applyToSprite(m_value, spr, localIndex, index);
}

std::string getKey() const override {
return m_key->getKey();
}

bool isCancellation() const override {
return m_cancellation;
}

std::string runStrAddition() override {
if (m_key->m_stringAddition != NULL)
return m_key->m_stringAddition(m_value);
return "";
}

bool isButton() const override {
return m_key->m_buttonFunctionallity != NULL;
}

void callButton(bool keyDown, cocos2d::CCFontSprite* spr, std::set<cocos2d::CCFontSprite*> const& word){
if (m_key->m_buttonFunctionallity != NULL)
m_key->m_buttonFunctionallity(m_value, keyDown, spr, word);
}
};

class RichTextKeyBase {
public:
virtual ~RichTextKeyBase() = default;
virtual Result<std::shared_ptr<RichTextKeyInstanceBase>> createInstance(std::string const& value, bool cancellation) = 0;
virtual std::string getKey() const = 0;
};

template <class T>
class RichTextKey final : public RichTextKeyBase {
public:
/**
@param key The identifier name for this rich text key
@param validCheck Function to validate and parse the value string into type T (if an error is returned the key will not be processed)
@param applyToSprite Function to apply the parsed value to a font sprite (optional)
*/
RichTextKey(
std::string key,
geode::Function<Result<T>(std::string const& value)> validCheck,
geode::Function<void(
T const& value,
bool keyDown,
cocos2d::CCFontSprite* specificSpriteClicked,
std::set<cocos2d::CCFontSprite*> const& wordClicked)> buttonFunctionallity
) : m_key(std::move(key)),
m_validCheck(std::move(validCheck)),
m_buttonFunctionallity(std::move(buttonFunctionallity)) {}
/**
@param key The identifier name for this rich text key
@param validCheck Function to validate and parse the value string into type T (if an error is returned the key will not be processed)
@param applyToSprite Function to apply the parsed value to a font sprite (optional)
*/
RichTextKey(
std::string key,
geode::Function<Result<T>(std::string const& value)> validCheck,
geode::Function<void(T const& value, cocos2d::CCFontSprite* sprite, int localIndex, int charIndex)> applyToSprite
) : m_key(std::move(key)),
m_validCheck(std::move(validCheck)),
m_applyToSprite(std::move(applyToSprite)) {}
/**
@param key The identifier name for this rich text key
@param validCheck Function to validate and parse the value string into type T (if an error is returned the key will not be processed)
@param stringAddition Function to add a new string at the point where the key is (optional)
*/
RichTextKey(
std::string key,
geode::Function<Result<T>(std::string const& value)> validCheck,
geode::Function<std::string(T const& value)> stringAddition
) : m_key(std::move(key)),
m_validCheck(std::move(validCheck)),
m_stringAddition(std::move(stringAddition)) {}
/**
@param key The identifier name for this rich text key
@param validCheck Function to validate and parse the value string into type T (if an error is returned the key will not be processed)
@param applyToSprite Function to apply the parsed value to a font sprite (optional)
@param stringAddition Function to add a new string at the point where the key is (optional)
*/
RichTextKey(
std::string key,
geode::Function<Result<T>(std::string const& value)> validCheck,
geode::Function<void(T const& value, cocos2d::CCFontSprite* sprite, int localIndex, int charIndex)> applyToSprite,
geode::Function<std::string(T const& value)> stringAddition
) : m_key(std::move(key)),
m_validCheck(std::move(validCheck)),
m_applyToSprite(std::move(applyToSprite)),
m_stringAddition(std::move(stringAddition)) {}

Result<std::shared_ptr<RichTextKeyInstanceBase>> createInstance(std::string const& value, bool cancellation) override {
if (cancellation){
if (value == ""){
return Ok(std::make_shared<RichTextKeyInstance<T>>(
RichTextKeyInstance<T>(this, T(), true))
);
}
else return Err("Cancellation tags cannot have values");
}

auto res = m_validCheck(value);

if (res.isErr()) return Err(res.unwrapErr());

return Ok(std::make_shared<RichTextKeyInstance<T>>(
RichTextKeyInstance<T>(this, res.unwrap(), false))
);
}

std::string getKey() const override {
return m_key;
}

private:
std::string m_key;

public:
geode::Function<Result<T>(std::string const& value)> m_validCheck = NULL;
geode::Function<void(T const& value, cocos2d::CCFontSprite* sprite, int localIndex, int charIndex)> m_applyToSprite = NULL;
geode::Function<std::string(T const& value)> m_stringAddition = NULL;
geode::Function<void(
T const& value,
bool keyDown,
cocos2d::CCFontSprite* specificSpriteClicked,
std::set<cocos2d::CCFontSprite*> const& wordClicked)> m_buttonFunctionallity = NULL;
};


class GEODE_DLL RichTextArea : public SimpleTextArea, public cocos2d::CCTouchDelegate {
public:
static RichTextArea* create(std::string text, std::string font = "chatFont.fnt", float scale = 1.0f);
static RichTextArea* create(std::string text, std::string font, float scale, float width);

void setText(std::string text) override;
std::string getRawText();

void registerRichTextKey(std::shared_ptr<RichTextKeyBase> key);
protected:
RichTextArea();
~RichTextArea();

class RichImpl;
std::unique_ptr<SimpleTextAreaImpl> createImpl() override;

private:
class Impl;
std::unique_ptr<Impl> m_impl;
static RichTextArea* create(std::string font, std::string text, float scale, float width, const bool artificialWidth);

bool init(std::string font, std::string text, float scale, float width, const bool artificialWidth);

bool ccTouchBegan(cocos2d::CCTouch *pTouch, cocos2d::CCEvent *pEvent) override;

void ccTouchEnded(cocos2d::CCTouch *pTouch, cocos2d::CCEvent *pEvent) override;
void ccTouchCancelled(cocos2d::CCTouch *pTouch, cocos2d::CCEvent *pEvent) override;

RichImpl* castedImpl();
};
}
Loading