mirror of
https://github.com/geode-sdk/geode.git
synced 2024-11-14 19:15:05 -05:00
add sane TextInput class
This commit is contained in:
parent
83cb61bb20
commit
28f393b4de
6 changed files with 253 additions and 3 deletions
2
VERSION
2
VERSION
|
@ -1 +1 @@
|
|||
2.0.0-beta.19
|
||||
2.0.0-beta.20
|
|
@ -5,7 +5,7 @@
|
|||
#include <cocos2d.h>
|
||||
|
||||
namespace geode {
|
||||
class GEODE_DLL InputNode : public cocos2d::CCMenuItem {
|
||||
class GEODE_DLL [[deprecated("Use geode::TextInput from the ui/TextInput.hpp header instead")]] InputNode : public cocos2d::CCMenuItem {
|
||||
protected:
|
||||
cocos2d::extension::CCScale9Sprite* m_bgSprite;
|
||||
CCTextInputNode* m_input;
|
||||
|
|
124
loader/include/Geode/ui/TextInput.hpp
Normal file
124
loader/include/Geode/ui/TextInput.hpp
Normal file
|
@ -0,0 +1,124 @@
|
|||
#pragma once
|
||||
|
||||
#include <Geode/DefaultInclude.hpp>
|
||||
#include <Geode/binding/CCTextInputNode.hpp>
|
||||
#include <cocos2d.h>
|
||||
|
||||
namespace geode {
|
||||
enum class CommonFilter {
|
||||
// Allow an unsigned integer
|
||||
Uint,
|
||||
// Allow a signed integer
|
||||
Int,
|
||||
// Allow a floating point number
|
||||
Float,
|
||||
// Allow letters, numbers, dashes, underscores, and dots
|
||||
ID,
|
||||
// Allow word-like characters & spaces
|
||||
Name,
|
||||
// Allows basically anything possible to type in an input
|
||||
Any,
|
||||
// Allow a hexadecimal number
|
||||
Hex,
|
||||
// Allow a non-URL-safe Base64 number
|
||||
Base64Normal,
|
||||
// Allow a URL-safe Base64 number
|
||||
Base64URL,
|
||||
};
|
||||
|
||||
GEODE_DLL const char* getCommonFilterAllowedChars(CommonFilter filter);
|
||||
|
||||
/**
|
||||
* A single-line text input node
|
||||
*/
|
||||
class GEODE_DLL TextInput : public cocos2d::CCNode, public TextInputDelegate {
|
||||
protected:
|
||||
cocos2d::extension::CCScale9Sprite* m_bgSprite;
|
||||
CCTextInputNode* m_input;
|
||||
std::function<void(std::string const&)> m_onInput = nullptr;
|
||||
|
||||
bool init(float width, std::string const& placeholder, std::string const& font);
|
||||
|
||||
void textChanged(CCTextInputNode* input) override;
|
||||
|
||||
public:
|
||||
/**
|
||||
* Create a single-line text input with a background.
|
||||
* Can either be used in delegate or callback mode;
|
||||
* with callback mode, you don't need to deal with adding
|
||||
* TextInputDelegate to your class' base list, you just install a
|
||||
* callback function directly to the input itself
|
||||
* @param width The width of the input
|
||||
* @param placeholder Placeholder text for the input
|
||||
* @param font The font to use
|
||||
*/
|
||||
static TextInput* create(float width, std::string const& placeholder, std::string const& font = "bigFont.fnt");
|
||||
|
||||
/**
|
||||
* Set the placeholder label for this input
|
||||
*/
|
||||
void setPlaceholder(std::string const& placeholder);
|
||||
/**
|
||||
* Set the filter (allowed characters) for this input
|
||||
* @param allowedChars String of allowed characters; each character in
|
||||
* the string represents one allowed character
|
||||
*/
|
||||
void setFilter(std::string const& allowedChars);
|
||||
/**
|
||||
* Set a commonly used filter (number, text, etc.)
|
||||
*/
|
||||
void setCommonFilter(CommonFilter filter);
|
||||
/**
|
||||
* Set the maximum amount of characters for this input. Use 0 for
|
||||
* infinite length
|
||||
*/
|
||||
void setMaxCharCount(size_t length);
|
||||
/**
|
||||
* Enable/disable password mode (all input characters are rendered as
|
||||
* dots rather than the actual characters)
|
||||
*/
|
||||
void setPasswordMode(bool enable);
|
||||
/**
|
||||
* Set the width of the label. This does not set the maximum character
|
||||
* count; use `setMaxCharCount` for that
|
||||
*/
|
||||
void setWidth(float width);
|
||||
/**
|
||||
* Install a delegate that handles input events. Removes any currently
|
||||
* set direct callbacks
|
||||
* @param delegate The delegate to install
|
||||
* @param tag Some legacy delegates use a tag to distinguish between
|
||||
* inputs; this is a convenience parameter for setting the tag of the
|
||||
* internal CCTextInputNode for those cases
|
||||
*/
|
||||
void setDelegate(TextInputDelegate* delegate, std::optional<int> tag = std::nullopt);
|
||||
/**
|
||||
* Set a direct callback function that is called when the user types in
|
||||
* the input. Overrides any delegate that is currently installed
|
||||
* @param onInput Function to call when the user changes the value of
|
||||
* the text input
|
||||
*/
|
||||
void setCallback(std::function<void(std::string const&)> onInput);
|
||||
|
||||
/**
|
||||
* Hides the background of this input. Shorthand for
|
||||
* `input->getBGSprite()->setVisible(false)`
|
||||
*/
|
||||
void hideBG();
|
||||
|
||||
/**
|
||||
* Set the value of the input
|
||||
* @param str The new text of the input
|
||||
* @param triggerCallback Whether this should trigger the callback
|
||||
* function / delegate's textChanged event or not
|
||||
*/
|
||||
void setString(std::string const& str, bool triggerCallback = false);
|
||||
/**
|
||||
* Get the current value of the input
|
||||
*/
|
||||
std::string getString() const;
|
||||
|
||||
CCTextInputNode* getInputNode() const;
|
||||
cocos2d::extension::CCScale9Sprite* getBGSprite() const;
|
||||
};
|
||||
}
|
|
@ -35,7 +35,7 @@ void CopySizeLayout::apply(CCNode* in) {
|
|||
// Prevent accidental infinite loop
|
||||
if (node == in) continue;
|
||||
node->ignoreAnchorPointForPosition(false);
|
||||
node->setContentSize(in->getContentSize());
|
||||
node->setContentSize(in->getContentSize() * ccp(1 / in->getScaleX(), 1 / in->getScaleY()));
|
||||
node->setPosition(in->getContentSize() / 2);
|
||||
node->updateLayout();
|
||||
}
|
||||
|
|
|
@ -61,7 +61,10 @@ CCScale9Sprite* InputNode::getBG() const {
|
|||
}
|
||||
|
||||
void InputNode::activate() {
|
||||
auto const size = m_input->getContentSize();
|
||||
auto const pos = m_input->convertToNodeSpace(getMousePos()) + m_input->m_textField->getAnchorPoint() * size;
|
||||
m_input->onClickTrackNode(true);
|
||||
m_input->updateCursorPosition(pos, { CCPointZero, size });
|
||||
}
|
||||
|
||||
void InputNode::setEnabled(bool enabled) {
|
||||
|
|
123
loader/src/ui/nodes/TextInput.cpp
Normal file
123
loader/src/ui/nodes/TextInput.cpp
Normal file
|
@ -0,0 +1,123 @@
|
|||
#include <Geode/binding/CCTextInputNode.hpp>
|
||||
#include <Geode/binding/TextInputDelegate.hpp>
|
||||
#include <Geode/ui/TextInput.hpp>
|
||||
|
||||
using namespace geode::prelude;
|
||||
|
||||
const char* geode::getCommonFilterAllowedChars(CommonFilter filter) {
|
||||
switch (filter) {
|
||||
default:
|
||||
case CommonFilter::Uint: return "0123456789";
|
||||
case CommonFilter::Int: return "-0123456789";
|
||||
case CommonFilter::Float: return "-.0123456789";
|
||||
case CommonFilter::ID: return "abcdefghijklmnopqrstuvwxyz0123456789-_.";
|
||||
case CommonFilter::Name: return "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_ ";
|
||||
case CommonFilter::Any: return "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_-+/\\&$%^~*\'\"{}()[]<>=!?@,;.:|• ";
|
||||
case CommonFilter::Hex: return "0123456789abcdefABCDEF";
|
||||
case CommonFilter::Base64Normal: return "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ+/=";
|
||||
case CommonFilter::Base64URL: return "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-_=";
|
||||
}
|
||||
}
|
||||
|
||||
bool TextInput::init(float width, std::string const& placeholder, std::string const& font) {
|
||||
if (!CCNode::init())
|
||||
return false;
|
||||
|
||||
constexpr float HEIGHT = 30.f;
|
||||
|
||||
this->setContentSize({ width, HEIGHT });
|
||||
this->setAnchorPoint({ .5f, .5f });
|
||||
|
||||
m_bgSprite = cocos2d::extension::CCScale9Sprite::create("square02b_001.png", { 0, 0, 80, 80 });
|
||||
m_bgSprite->setScale(.5f);
|
||||
m_bgSprite->setColor({ 0, 0, 0 });
|
||||
m_bgSprite->setOpacity(90);
|
||||
m_bgSprite->setContentSize({ width * 2, HEIGHT * 2 });
|
||||
this->addChildAtPosition(m_bgSprite, cocos2d::Anchor::Center);
|
||||
|
||||
m_input = CCTextInputNode::create(width - 10.f, HEIGHT, placeholder.c_str(), "Thonburi", 24, font.c_str());
|
||||
m_input->setLabelPlaceholderColor({ 150, 150, 150 });
|
||||
m_input->setLabelPlaceholderScale(.6f);
|
||||
m_input->setMaxLabelScale(.6f);
|
||||
this->addChildAtPosition(m_input, cocos2d::Anchor::Center);
|
||||
|
||||
handleTouchPriority(this);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
TextInput* TextInput::create(float width, std::string const& placeholder, std::string const& font) {
|
||||
auto ret = new TextInput();
|
||||
if (ret && ret->init(width, placeholder, font)) {
|
||||
ret->autorelease();
|
||||
return ret;
|
||||
}
|
||||
CC_SAFE_DELETE(ret);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void TextInput::textChanged(CCTextInputNode* input) {
|
||||
if (m_onInput) {
|
||||
m_onInput(input->getString());
|
||||
}
|
||||
}
|
||||
|
||||
void TextInput::setPlaceholder(std::string const& placeholder) {
|
||||
m_input->m_caption = placeholder;
|
||||
m_input->refreshLabel();
|
||||
}
|
||||
void TextInput::setFilter(std::string const& allowedChars) {
|
||||
m_input->m_allowedChars = allowedChars;
|
||||
}
|
||||
void TextInput::setCommonFilter(CommonFilter filter) {
|
||||
this->setFilter(getCommonFilterAllowedChars(filter));
|
||||
}
|
||||
void TextInput::setMaxCharCount(size_t length) {
|
||||
m_input->m_maxLabelLength = length == 0 ? 9999999 : length;
|
||||
}
|
||||
void TextInput::setPasswordMode(bool enable) {
|
||||
m_input->m_usePasswordChar = enable;
|
||||
m_input->refreshLabel();
|
||||
}
|
||||
void TextInput::setWidth(float width) {
|
||||
m_input->m_maxLabelWidth = width - 10;
|
||||
m_input->setContentWidth(width * 2);
|
||||
m_bgSprite->setContentWidth(width * 2);
|
||||
}
|
||||
void TextInput::setDelegate(TextInputDelegate* delegate, std::optional<int> tag) {
|
||||
m_input->setDelegate(delegate);
|
||||
m_onInput = nullptr;
|
||||
if (tag.has_value()) {
|
||||
m_input->setTag(tag.value());
|
||||
}
|
||||
}
|
||||
void TextInput::setCallback(std::function<void(std::string const&)> onInput) {
|
||||
this->setDelegate(this);
|
||||
m_onInput = onInput;
|
||||
}
|
||||
|
||||
void TextInput::hideBG() {
|
||||
m_bgSprite->setVisible(false);
|
||||
}
|
||||
|
||||
void TextInput::setString(std::string const& str, bool triggerCallback) {
|
||||
auto oldDelegate = m_input->m_delegate;
|
||||
// Avoid triggering the callback
|
||||
m_input->m_delegate = nullptr;
|
||||
m_input->setString(str);
|
||||
m_input->m_delegate = oldDelegate;
|
||||
if (triggerCallback && m_input->m_delegate) {
|
||||
m_input->m_delegate->textChanged(m_input);
|
||||
}
|
||||
}
|
||||
|
||||
std::string TextInput::getString() const {
|
||||
return m_input->getString();
|
||||
}
|
||||
|
||||
CCTextInputNode* TextInput::getInputNode() const {
|
||||
return m_input;
|
||||
}
|
||||
CCScale9Sprite* TextInput::getBGSprite() const {
|
||||
return m_bgSprite;
|
||||
}
|
Loading…
Reference in a new issue