no message
This commit is contained in:
118
cocos/ui/edit-box/EditBox-android.cpp
Normal file
118
cocos/ui/edit-box/EditBox-android.cpp
Normal file
@@ -0,0 +1,118 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2018-2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
#include "EditBox.h"
|
||||
#include "cocos/bindings/jswrapper/SeApi.h"
|
||||
#include "cocos/bindings/manual/jsb_global.h"
|
||||
#include "engine/EngineEvents.h"
|
||||
#include "platform/java/jni/JniHelper.h"
|
||||
|
||||
#ifndef JCLS_EDITBOX
|
||||
#define JCLS_EDITBOX "com/cocos/lib/CocosEditBoxActivity"
|
||||
#endif
|
||||
|
||||
#ifndef ORG_EDITBOX_CLASS_NAME
|
||||
#define ORG_EDITBOX_CLASS_NAME com_cocos_lib_CocosEditBoxActivity
|
||||
#endif
|
||||
#define JNI_EDITBOX(FUNC) JNI_METHOD1(ORG_EDITBOX_CLASS_NAME, FUNC)
|
||||
|
||||
namespace {
|
||||
se::Value textInputCallback;
|
||||
|
||||
void getTextInputCallback() {
|
||||
if (!textInputCallback.isUndefined()) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto *global = se::ScriptEngine::getInstance()->getGlobalObject();
|
||||
se::Value jsbVal;
|
||||
if (global->getProperty("jsb", &jsbVal) && jsbVal.isObject()) {
|
||||
jsbVal.toObject()->getProperty("onTextInput", &textInputCallback);
|
||||
// free globle se::Value before ScriptEngine clean up
|
||||
se::ScriptEngine::getInstance()->addBeforeCleanupHook([]() {
|
||||
textInputCallback.setUndefined();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void callJSFunc(const ccstd::string &type, const ccstd::string &text) {
|
||||
getTextInputCallback();
|
||||
|
||||
se::AutoHandleScope scope;
|
||||
se::ValueArray args;
|
||||
args.push_back(se::Value(type));
|
||||
args.push_back(se::Value(text));
|
||||
textInputCallback.toObject()->call(args, nullptr);
|
||||
}
|
||||
} // namespace
|
||||
|
||||
namespace cc {
|
||||
|
||||
bool EditBox::_isShown = false; //NOLINT
|
||||
|
||||
void EditBox::show(const cc::EditBox::ShowInfo &showInfo) {
|
||||
JniHelper::callStaticVoidMethod(JCLS_EDITBOX,
|
||||
"showNative",
|
||||
showInfo.defaultValue,
|
||||
showInfo.maxLength,
|
||||
showInfo.isMultiline,
|
||||
showInfo.confirmHold,
|
||||
showInfo.confirmType,
|
||||
showInfo.inputType);
|
||||
_isShown = true;
|
||||
}
|
||||
|
||||
void EditBox::hide() {
|
||||
JniHelper::callStaticVoidMethod(JCLS_EDITBOX, "hideNative");
|
||||
_isShown = false;
|
||||
}
|
||||
|
||||
bool EditBox::complete() {
|
||||
if (!_isShown) {
|
||||
return false;
|
||||
}
|
||||
|
||||
EditBox::hide();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace cc
|
||||
|
||||
extern "C" {
|
||||
JNIEXPORT void JNICALL JNI_EDITBOX(onKeyboardInputNative)(JNIEnv * /*env*/, jclass /*unused*/, jstring text) {
|
||||
auto textStr = cc::JniHelper::jstring2string(text);
|
||||
callJSFunc("input", textStr);
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL JNI_EDITBOX(onKeyboardCompleteNative)(JNIEnv * /*env*/, jclass /*unused*/, jstring text) {
|
||||
auto textStr = cc::JniHelper::jstring2string(text);
|
||||
callJSFunc("complete", textStr);
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL JNI_EDITBOX(onKeyboardConfirmNative)(JNIEnv * /*env*/, jclass /*unused*/, jstring text) {
|
||||
auto textStr = cc::JniHelper::jstring2string(text);
|
||||
callJSFunc("confirm", textStr);
|
||||
}
|
||||
}
|
||||
641
cocos/ui/edit-box/EditBox-ios.mm
Normal file
641
cocos/ui/edit-box/EditBox-ios.mm
Normal file
@@ -0,0 +1,641 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2018-2022 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated engine source code (the "Software"), a limited,
|
||||
worldwide, royalty-free, non-assignable, revocable and non-exclusive license
|
||||
to use Cocos Creator solely to develop games on your target platforms. You shall
|
||||
not use Cocos Creator software for developing other software or tools that's
|
||||
used for developing games. You are not granted to publish, distribute,
|
||||
sublicense, and/or sell copies of Cocos Creator.
|
||||
|
||||
The software or tools in this License Agreement are licensed, not sold.
|
||||
Xiamen Yaji Software Co., Ltd. reserves all rights not expressly granted to you.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
/************************************************************
|
||||
TODO: New implementation of iOS inputbox
|
||||
UI Structure:
|
||||
==[| ][done]== >>> inputAccessoryView
|
||||
= q w e r t y u i o p =
|
||||
= a s d f g h j k l ; '' =
|
||||
= virtual [ ] keyboard = >>> inputView
|
||||
|
||||
Further needs:
|
||||
Customization of inputbox, developer DIY toolbar.
|
||||
==[Camera][| ][done]== >>> inputoopeAccessoryView
|
||||
= q w e r t y u i o p =
|
||||
= a s d f g h j k l ; '' =
|
||||
= virtual [ ] keyboard = >>> inputView
|
||||
The principle idea is to set inputAccessoryView from JS where developer can bind selector with js callback.
|
||||
JS API:
|
||||
jsb.InputBox customizeIBox = new jsb.InputBox();
|
||||
ibox.addComponent(sendBtn, (ClickEvent: event)=>{...}); automatically set as the last element.
|
||||
ibox.addComponent(inputFld, (InputEvent: event)=>{...});
|
||||
ibox.setLayout(sendBtn, inputFld);
|
||||
JSB binding:
|
||||
jsb_addComponent(se::Value){
|
||||
...
|
||||
inputBox.addComponent(cpt);
|
||||
}
|
||||
************************************************************/
|
||||
|
||||
#include "EditBox.h"
|
||||
#include "cocos/bindings/jswrapper/SeApi.h"
|
||||
#include "cocos/bindings/manual/jsb_global.h"
|
||||
#include "engine/EngineEvents.h"
|
||||
#import <UIKit/UIKit.h>
|
||||
#include "cocos/platform/ios/WarpCocosContent.h"
|
||||
|
||||
|
||||
#define ITEM_MARGIN_WIDTH 10
|
||||
#define ITEM_MARGIN_HEIGHT 10
|
||||
#define TEXT_LINE_HEIGHT 40
|
||||
#define TEXT_VIEW_MAX_LINE_SHOWN 1.5
|
||||
#define BUTTON_HEIGHT (TEXT_LINE_HEIGHT - ITEM_MARGIN_HEIGHT)
|
||||
#define BUTTON_WIDTH 60
|
||||
//TODO: change the proccedure of showing inputbox, possibly become a property
|
||||
const bool INPUTBOX_HIDDEN = true; // Toggle if Inputbox is visible
|
||||
/*************************************************************************
|
||||
Inner class declarations.
|
||||
************************************************************************/
|
||||
@interface EditboxManager : NSObject
|
||||
+ (instancetype)sharedInstance;
|
||||
- (void) show:(const cc::EditBox::ShowInfo*)showInfo;
|
||||
- (void) hide;
|
||||
- (UIView*) getCurrentViewInUse;
|
||||
- (NSString*) getCurrentText;
|
||||
@end
|
||||
|
||||
@interface ButtonHandler : NSObject
|
||||
- (IBAction) buttonTapped:(UIButton *)button;
|
||||
@end
|
||||
|
||||
@interface TextFieldDelegate : NSObject <UITextFieldDelegate>
|
||||
- (BOOL) textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string;
|
||||
- (void) textFieldDidChange:(UITextField *)textField;
|
||||
- (BOOL) textFieldShouldReturn:(UITextField *)textField;
|
||||
@end
|
||||
|
||||
@interface TextViewDelegate : NSObject <UITextViewDelegate> //Multiline
|
||||
- (BOOL) textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text;
|
||||
- (void) textViewDidChange:(UITextView *)textView;
|
||||
@end
|
||||
|
||||
/*************************************************************************
|
||||
Global variables and functions relative to script engine.
|
||||
************************************************************************/
|
||||
namespace {
|
||||
static bool g_isMultiline{false};
|
||||
static bool g_confirmHold{false};
|
||||
static int g_maxLength{INT_MAX};
|
||||
se::Value textInputCallback;
|
||||
|
||||
void getTextInputCallback() {
|
||||
if (!textInputCallback.isUndefined())
|
||||
return;
|
||||
|
||||
auto global = se::ScriptEngine::getInstance()->getGlobalObject();
|
||||
se::Value jsbVal;
|
||||
if (global->getProperty("jsb", &jsbVal) && jsbVal.isObject()) {
|
||||
jsbVal.toObject()->getProperty("onTextInput", &textInputCallback);
|
||||
// free globle se::Value before ScriptEngine clean up
|
||||
se::ScriptEngine::getInstance()->addBeforeCleanupHook([]() {
|
||||
textInputCallback.setUndefined();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void callJSFunc(const ccstd::string &type, const ccstd::string &text) {
|
||||
getTextInputCallback();
|
||||
|
||||
se::AutoHandleScope scope;
|
||||
se::ValueArray args;
|
||||
args.push_back(se::Value(type));
|
||||
args.push_back(se::Value(text));
|
||||
textInputCallback.toObject()->call(args, nullptr);
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
Global functions as tools to set values
|
||||
************************************************************************/
|
||||
|
||||
int getTextInputHeight(bool isMultiLine) {
|
||||
if (isMultiLine)
|
||||
return TEXT_LINE_HEIGHT * TEXT_VIEW_MAX_LINE_SHOWN;
|
||||
else
|
||||
return TEXT_LINE_HEIGHT;
|
||||
}
|
||||
|
||||
void setTextFieldKeyboardType(UITextField *textField, const ccstd::string &inputType) {
|
||||
if (0 == inputType.compare("password")) {
|
||||
textField.secureTextEntry = TRUE;
|
||||
textField.keyboardType = UIKeyboardTypeDefault;
|
||||
} else {
|
||||
textField.secureTextEntry = FALSE;
|
||||
if (0 == inputType.compare("email"))
|
||||
textField.keyboardType = UIKeyboardTypeEmailAddress;
|
||||
else if (0 == inputType.compare("number"))
|
||||
textField.keyboardType = UIKeyboardTypeDecimalPad;
|
||||
else if (0 == inputType.compare("url"))
|
||||
textField.keyboardType = UIKeyboardTypeURL;
|
||||
else if (0 == inputType.compare("text"))
|
||||
textField.keyboardType = UIKeyboardTypeDefault;
|
||||
}
|
||||
}
|
||||
|
||||
void setTextFieldReturnType(UITextField *textField, const ccstd::string &returnType) {
|
||||
if (0 == returnType.compare("done"))
|
||||
textField.returnKeyType = UIReturnKeyDone;
|
||||
else if (0 == returnType.compare("next"))
|
||||
textField.returnKeyType = UIReturnKeyNext;
|
||||
else if (0 == returnType.compare("search"))
|
||||
textField.returnKeyType = UIReturnKeySearch;
|
||||
else if (0 == returnType.compare("go"))
|
||||
textField.returnKeyType = UIReturnKeyGo;
|
||||
else if (0 == returnType.compare("send"))
|
||||
textField.returnKeyType = UIReturnKeySend;
|
||||
}
|
||||
|
||||
NSString *getConfirmButtonTitle(const ccstd::string &returnType) {
|
||||
NSString *titleKey = [NSString stringWithUTF8String:returnType.c_str()];
|
||||
return NSLocalizedString(titleKey, nil); // get i18n string to be the title
|
||||
}
|
||||
//
|
||||
CGRect getSafeAreaRect() {
|
||||
//UIView *view = UIApplication.sharedApplication.delegate.window.rootViewController.view;
|
||||
UIView *view = WarpCocosContent.shareInstance.renderView;
|
||||
|
||||
CGRect viewRect = view.frame;
|
||||
|
||||
// safeAreaInsets is avaible since iOS 11.
|
||||
if (@available(iOS 11.0, *)) {
|
||||
auto safeAreaInsets = view.safeAreaInsets;
|
||||
|
||||
UIInterfaceOrientation orient = [UIApplication sharedApplication].statusBarOrientation;
|
||||
if (UIInterfaceOrientationLandscapeLeft == orient) {
|
||||
viewRect.origin.x = 0;
|
||||
viewRect.size.width -= safeAreaInsets.left;
|
||||
viewRect.size.width -= safeAreaInsets.right;
|
||||
} else {
|
||||
viewRect.origin.x += safeAreaInsets.left;
|
||||
viewRect.size.width -= safeAreaInsets.left;
|
||||
viewRect.size.width -= safeAreaInsets.right;
|
||||
}
|
||||
}
|
||||
|
||||
return viewRect;
|
||||
}
|
||||
|
||||
//TODO: Get hash with different type of showInfo, for example different inputAccessoryView
|
||||
NSString* getTextInputType(const cc::EditBox::ShowInfo* showInfo) {
|
||||
return showInfo->isMultiline?@"textView":@"textField";
|
||||
}
|
||||
void onParentViewTouched(const cc::CustomEvent &touchEvent){
|
||||
[[EditboxManager sharedInstance] hide];
|
||||
}
|
||||
} // namespace
|
||||
|
||||
/*************************************************************************
|
||||
Class implementations.
|
||||
************************************************************************/
|
||||
@implementation TextViewDelegate {
|
||||
UITextView* tViewOnView;
|
||||
UITextView* tViewOnToolbar;
|
||||
}
|
||||
- (id) initWithPairs:(UITextView*) inputOnView and:(UITextView*) inputOnToolbar {
|
||||
if (self = [super init]) {
|
||||
tViewOnView = inputOnView;
|
||||
tViewOnToolbar = inputOnToolbar;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text {
|
||||
// REFINE: check length limit before text changed
|
||||
return YES;
|
||||
}
|
||||
- (void)textViewDidChange:(UITextView *)textView {
|
||||
if (textView.markedTextRange != nil)
|
||||
return;
|
||||
|
||||
// check length limit after text changed, a little rude
|
||||
if (textView.text.length > g_maxLength) {
|
||||
NSRange rangeIndex = [textView.text rangeOfComposedCharacterSequenceAtIndex:g_maxLength];
|
||||
textView.text = [textView.text substringToIndex:rangeIndex.location];
|
||||
}
|
||||
tViewOnView.text = textView.text;
|
||||
tViewOnToolbar.text = textView.text;
|
||||
callJSFunc("input", [textView.text UTF8String]);
|
||||
}
|
||||
@end
|
||||
@implementation TextFieldDelegate {
|
||||
UITextField* textFieldOnView;
|
||||
UITextField* textFieldOntoolbar;
|
||||
}
|
||||
|
||||
- (id) initWithPairs:(UITextField*) inputOnView and:(UITextField*) inputOnToolbar {
|
||||
if (self = [super init]) {
|
||||
textFieldOnView = inputOnView;
|
||||
textFieldOntoolbar = inputOnToolbar;
|
||||
|
||||
}
|
||||
return self;
|
||||
}
|
||||
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
|
||||
// REFINE: check length limit before text changed
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (void)textFieldDidChange:(UITextField *)textField {
|
||||
if (textField.markedTextRange != nil)
|
||||
return;
|
||||
|
||||
// check length limit after text changed, a little rude
|
||||
if (textField.text.length > g_maxLength) {
|
||||
NSRange rangeIndex = [textField.text rangeOfComposedCharacterSequenceAtIndex:g_maxLength];
|
||||
textField.text = [textField.text substringToIndex:rangeIndex.location];
|
||||
}
|
||||
textFieldOnView.text = textField.text;
|
||||
textFieldOntoolbar.text = textField.text;
|
||||
callJSFunc("input", [textField.text UTF8String]);
|
||||
}
|
||||
|
||||
- (BOOL)textFieldShouldReturn:(UITextField *)textField {
|
||||
cc::EditBox::complete();
|
||||
return YES;
|
||||
}
|
||||
@end
|
||||
|
||||
|
||||
static ButtonHandler* btnHandler = nil;
|
||||
@interface InputBoxPair : NSObject
|
||||
@property(readwrite) id inputOnView;
|
||||
@property(readwrite) id inputOnToolbar;
|
||||
@property(readwrite) id inputDelegate;
|
||||
@end
|
||||
@implementation InputBoxPair
|
||||
- (void)dealloc {
|
||||
[super dealloc];
|
||||
[_inputOnView release];
|
||||
[_inputOnToolbar release];
|
||||
[_inputDelegate release];
|
||||
}
|
||||
@end
|
||||
|
||||
@implementation EditboxManager
|
||||
{
|
||||
//recently there'ill be only 2 elements
|
||||
NSMutableDictionary<NSString*, InputBoxPair*>* textInputDictionnary;
|
||||
InputBoxPair* curView;
|
||||
|
||||
cc::events::Resize::Listener resizeListener;
|
||||
cc::events::Touch::Listener touchListener;
|
||||
cc::events::Close::Listener closeListener;
|
||||
}
|
||||
static EditboxManager *instance = nil;
|
||||
|
||||
+ (instancetype) sharedInstance {
|
||||
static dispatch_once_t pred = 0;
|
||||
dispatch_once(&pred, ^{
|
||||
instance = [[super allocWithZone:NULL] init];
|
||||
if (instance == nil) {
|
||||
CC_LOG_ERROR("Editbox manager init failed, plz check if you have enough space left");
|
||||
}
|
||||
});
|
||||
return instance;
|
||||
}
|
||||
+ (id)allocWithZone:(struct _NSZone*)zone {
|
||||
return [EditboxManager sharedInstance];
|
||||
}
|
||||
|
||||
- (id)copyWithZone:(struct _NSZone*)zone {
|
||||
return [EditboxManager sharedInstance];
|
||||
}
|
||||
|
||||
- (void)onOrientationChanged{
|
||||
cc::EditBox::complete();
|
||||
}
|
||||
- (id)init {
|
||||
if (self = [super init]) {
|
||||
|
||||
textInputDictionnary = [NSMutableDictionary new];
|
||||
if (textInputDictionnary == nil) {
|
||||
[self release];
|
||||
return nil;
|
||||
}
|
||||
|
||||
resizeListener.bind([&](int /*width*/, int /*height*/ , uint32_t /*windowId*/) {
|
||||
[[EditboxManager sharedInstance] onOrientationChanged];
|
||||
});
|
||||
//"onTouchStart" is a sub event for TouchEvent, so we can only add listener for this sub event rather than TouchEvent itself.
|
||||
touchListener.bind([&](const cc::TouchEvent& event) {
|
||||
if(event.type == cc::TouchEvent::Type::BEGAN) {
|
||||
cc::EditBox::complete();
|
||||
}
|
||||
});
|
||||
|
||||
closeListener.bind([&]() {
|
||||
[[EditboxManager sharedInstance] dealloc];
|
||||
});
|
||||
}
|
||||
return self;
|
||||
}
|
||||
- (void)dealloc {
|
||||
[textInputDictionnary release];
|
||||
[super dealloc];
|
||||
}
|
||||
- (UIBarButtonItem*) setInputWidthOf: (UIToolbar*)toolbar{
|
||||
CGFloat totalItemsWidth = ITEM_MARGIN_WIDTH;
|
||||
UIBarButtonItem *textViewBarButtonItem;
|
||||
UIView *view;
|
||||
for (UIBarButtonItem *barButtonItem in toolbar.items) {
|
||||
if ((view = [barButtonItem valueForKey:@"view"])) {
|
||||
if ([view isKindOfClass:[UITextView class]] || [view isKindOfClass:[UITextField class]]) {
|
||||
textViewBarButtonItem = barButtonItem;
|
||||
} else if ([view isKindOfClass:[UIButton class]]) {
|
||||
// Docs say width can be negative for variable size items
|
||||
totalItemsWidth += BUTTON_WIDTH + ITEM_MARGIN_WIDTH;
|
||||
}
|
||||
} else {
|
||||
totalItemsWidth += barButtonItem.width + ITEM_MARGIN_WIDTH;
|
||||
}
|
||||
totalItemsWidth += ITEM_MARGIN_WIDTH;
|
||||
}
|
||||
[[textViewBarButtonItem customView]
|
||||
setFrame:CGRectMake(0,
|
||||
0,
|
||||
getSafeAreaRect().size.width - totalItemsWidth,
|
||||
getTextInputHeight(g_isMultiline))];
|
||||
return textViewBarButtonItem;
|
||||
}
|
||||
- (void) addInputAccessoryViewForTextView: (InputBoxPair*)inputbox
|
||||
with:(const cc::EditBox::ShowInfo*)showInfo{
|
||||
CGRect safeView = getSafeAreaRect();
|
||||
UIToolbar* toolbar = [[UIToolbar alloc]
|
||||
initWithFrame:CGRectMake(0,
|
||||
0,
|
||||
safeView.size.width,
|
||||
getTextInputHeight(g_isMultiline) + ITEM_MARGIN_HEIGHT)];
|
||||
[toolbar setBackgroundColor:[UIColor darkGrayColor]];
|
||||
|
||||
UITextView* textView = [[UITextView alloc] init];
|
||||
textView.textColor = [UIColor blackColor];
|
||||
textView.backgroundColor = [UIColor whiteColor];
|
||||
textView.layer.cornerRadius = 5.0;
|
||||
textView.clipsToBounds = YES;
|
||||
textView.text = [NSString stringWithUTF8String:showInfo->defaultValue.c_str()];
|
||||
TextViewDelegate* delegate = [[TextViewDelegate alloc] initWithPairs:[inputbox inputOnView] and:textView];
|
||||
inputbox.inputDelegate = delegate;
|
||||
textView.delegate = delegate;
|
||||
UIBarButtonItem *textViewItem = [[UIBarButtonItem alloc] initWithCustomView:textView];
|
||||
|
||||
if (!btnHandler){
|
||||
btnHandler = [[ButtonHandler alloc] init];
|
||||
}
|
||||
UIButton *confirmBtn = [[UIButton alloc]
|
||||
initWithFrame:CGRectMake(0,
|
||||
0,
|
||||
BUTTON_WIDTH,
|
||||
BUTTON_HEIGHT)];
|
||||
[confirmBtn addTarget:btnHandler
|
||||
action:@selector(buttonTapped:)
|
||||
forControlEvents:UIControlEventTouchUpInside];
|
||||
[confirmBtn setTitle:[NSString stringWithUTF8String:showInfo->confirmType.c_str()]
|
||||
forState:UIControlStateNormal];
|
||||
[confirmBtn setTitleColor:[UIColor systemBlueColor]
|
||||
forState:UIControlStateNormal];
|
||||
[confirmBtn setTitleColor:[UIColor darkTextColor]
|
||||
forState:UIControlStateHighlighted]; // Hight light state triggered when the button is tapped.
|
||||
UIBarButtonItem *confirm = [[UIBarButtonItem alloc]initWithCustomView:confirmBtn];
|
||||
|
||||
[toolbar setItems:@[textViewItem, confirm] animated:YES];
|
||||
UIBarButtonItem* textViewBarButtonItem = [self setInputWidthOf:toolbar];
|
||||
((UITextView*)[inputbox inputOnView]).inputAccessoryView = toolbar;
|
||||
|
||||
[inputbox setInputOnToolbar:textViewBarButtonItem.customView];
|
||||
//release for NON ARC ENV
|
||||
[toolbar release];
|
||||
[textView release];
|
||||
[confirmBtn release];
|
||||
[textViewItem release];
|
||||
[confirm release];
|
||||
|
||||
}
|
||||
- (void) addInputAccessoryViewForTextField: (InputBoxPair*)inputbox
|
||||
with: (const cc::EditBox::ShowInfo*)showInfo{
|
||||
CGRect safeView = getSafeAreaRect();
|
||||
UIToolbar* toolbar = [[UIToolbar alloc]
|
||||
initWithFrame:CGRectMake(0,
|
||||
0,
|
||||
safeView.size.width,
|
||||
TEXT_LINE_HEIGHT + ITEM_MARGIN_HEIGHT)];
|
||||
[toolbar setBackgroundColor:[UIColor darkGrayColor]];
|
||||
|
||||
UITextField* textField = [[UITextField alloc] init];
|
||||
textField.borderStyle = UITextBorderStyleRoundedRect;
|
||||
textField.textColor = [UIColor blackColor];
|
||||
textField.backgroundColor = [UIColor whiteColor];
|
||||
textField.text = [NSString stringWithUTF8String:showInfo->defaultValue.c_str()];
|
||||
TextFieldDelegate* delegate = [[TextFieldDelegate alloc] initWithPairs:[inputbox inputOnView] and:textField];
|
||||
textField.delegate = delegate;
|
||||
inputbox.inputDelegate = delegate;
|
||||
[textField addTarget:delegate action:@selector(textFieldDidChange:) forControlEvents:UIControlEventEditingChanged];
|
||||
UIBarButtonItem *textFieldItem = [[UIBarButtonItem alloc] initWithCustomView:textField];
|
||||
|
||||
if (!btnHandler){
|
||||
btnHandler = [[ButtonHandler alloc] init];
|
||||
}
|
||||
UIButton *confirmBtn = [[UIButton alloc]
|
||||
initWithFrame:CGRectMake(0,
|
||||
0,
|
||||
BUTTON_WIDTH,
|
||||
BUTTON_HEIGHT)];
|
||||
[confirmBtn addTarget:btnHandler
|
||||
action:@selector(buttonTapped:)
|
||||
forControlEvents:UIControlEventTouchUpInside];
|
||||
[confirmBtn setTitle:[NSString stringWithUTF8String:showInfo->confirmType.c_str()]
|
||||
forState:UIControlStateNormal];
|
||||
[confirmBtn setTitleColor:[UIColor systemBlueColor]
|
||||
forState:UIControlStateNormal];
|
||||
[confirmBtn setTitleColor:[UIColor darkTextColor]
|
||||
forState:UIControlStateHighlighted]; // Hight light state triggered when the button is tapped.
|
||||
UIBarButtonItem *confirm = [[UIBarButtonItem alloc]initWithCustomView:confirmBtn];
|
||||
|
||||
[toolbar setItems:@[textFieldItem, confirm] animated:YES];
|
||||
|
||||
|
||||
UIBarButtonItem* textFieldBarButtonItem = [self setInputWidthOf:toolbar];
|
||||
((UITextField*)[inputbox inputOnView]).inputAccessoryView = toolbar;
|
||||
[inputbox setInputOnToolbar:textFieldBarButtonItem.customView];
|
||||
|
||||
//release for NON ARC ENV
|
||||
[toolbar release];
|
||||
[textField release];
|
||||
[confirmBtn release];
|
||||
[textFieldItem release];
|
||||
[confirm release];
|
||||
}
|
||||
|
||||
- (id) createTextView: (const cc::EditBox::ShowInfo *)showInfo {
|
||||
InputBoxPair* ret;
|
||||
// Visible view rect size of phone
|
||||
//CGRect viewRect = UIApplication.sharedApplication.delegate.window.rootViewController.view.frame;
|
||||
CGRect viewRect = WarpCocosContent.shareInstance.renderView.frame;
|
||||
|
||||
//TODO: object for key with real hash value
|
||||
NSString* inputType = getTextInputType(showInfo);
|
||||
|
||||
if ((ret = [textInputDictionnary objectForKey:inputType])) {
|
||||
[[ret inputOnView] setFrame:CGRectMake(showInfo->x,
|
||||
viewRect.size.height - showInfo->y - showInfo->height,
|
||||
showInfo->width,
|
||||
showInfo->height)];
|
||||
CGRect safeArea = getSafeAreaRect();
|
||||
[[[ret inputOnView] inputAccessoryView] setFrame:CGRectMake(0,
|
||||
0,
|
||||
safeArea.size.width,
|
||||
getTextInputHeight(g_isMultiline) + ITEM_MARGIN_HEIGHT)];
|
||||
[self setInputWidthOf:[[ret inputOnView] inputAccessoryView] ];
|
||||
} else {
|
||||
ret = [[InputBoxPair alloc] init];
|
||||
[ret setInputOnView:[[UITextView alloc]
|
||||
initWithFrame:CGRectMake(showInfo->x,
|
||||
viewRect.size.height - showInfo->y - showInfo->height,
|
||||
showInfo->width,
|
||||
showInfo->height)]];
|
||||
[textInputDictionnary setValue:ret forKey:inputType];
|
||||
[self addInputAccessoryViewForTextView:ret with:showInfo];
|
||||
}
|
||||
((UITextView*)[ret inputOnToolbar]).text = [NSString stringWithUTF8String:showInfo->defaultValue.c_str()];
|
||||
((UITextView*)[ret inputOnView]).text = [NSString stringWithUTF8String:showInfo->defaultValue.c_str()];
|
||||
return ret;
|
||||
}
|
||||
- (id) createTextField: (const cc::EditBox::ShowInfo*)showInfo {
|
||||
InputBoxPair* ret;
|
||||
CGRect viewRect = UIApplication.sharedApplication.delegate.window.rootViewController.view.frame;
|
||||
|
||||
//TODO: object for key with real hash value
|
||||
NSString* inputType = getTextInputType(showInfo);
|
||||
|
||||
if ((ret = [textInputDictionnary objectForKey:inputType])) {
|
||||
[[ret inputOnView] setFrame:CGRectMake(showInfo->x,
|
||||
viewRect.size.height - showInfo->y - showInfo->height,
|
||||
showInfo->width,
|
||||
showInfo->height)];
|
||||
CGRect safeArea = getSafeAreaRect();
|
||||
[[[ret inputOnView] inputAccessoryView] setFrame:CGRectMake(0,
|
||||
0,
|
||||
safeArea.size.width,
|
||||
getTextInputHeight(g_isMultiline) + ITEM_MARGIN_HEIGHT)];
|
||||
[self setInputWidthOf:[[ret inputOnView] inputAccessoryView] ];
|
||||
} else {
|
||||
ret = [[InputBoxPair alloc] init];
|
||||
[ret setInputOnView:[[UITextField alloc]
|
||||
initWithFrame:CGRectMake(showInfo->x,
|
||||
viewRect.size.height - showInfo->y - showInfo->height,
|
||||
showInfo->width,
|
||||
showInfo->height)]];
|
||||
[textInputDictionnary setValue:ret forKey:inputType];
|
||||
[self addInputAccessoryViewForTextField:ret with:showInfo];
|
||||
}
|
||||
((UITextField*)[ret inputOnToolbar]).text = [NSString stringWithUTF8String:showInfo->defaultValue.c_str()];
|
||||
((UITextField*)[ret inputOnView]).text = [NSString stringWithUTF8String:showInfo->defaultValue.c_str()];
|
||||
setTextFieldReturnType((UITextField*)[ret inputOnToolbar], showInfo->confirmType);
|
||||
setTextFieldReturnType((UITextField*)[ret inputOnView], showInfo->confirmType);
|
||||
setTextFieldKeyboardType((UITextField*)[ret inputOnToolbar], showInfo->inputType);
|
||||
setTextFieldKeyboardType((UITextField*)[ret inputOnView], showInfo->inputType);
|
||||
return ret;
|
||||
}
|
||||
|
||||
//TODO: show inputbox with width modified.
|
||||
- (void) show: (const cc::EditBox::ShowInfo*)showInfo {
|
||||
g_maxLength = showInfo->maxLength;
|
||||
g_isMultiline = showInfo->isMultiline;
|
||||
g_confirmHold = showInfo->confirmHold;
|
||||
|
||||
if (g_isMultiline) {
|
||||
curView = [self createTextView:showInfo];
|
||||
} else {
|
||||
curView = [self createTextField:showInfo];
|
||||
}
|
||||
[[curView inputOnView] setHidden:INPUTBOX_HIDDEN];
|
||||
//UIView *view = UIApplication.sharedApplication.delegate.window.rootViewController.view;
|
||||
UIView *view = WarpCocosContent.shareInstance.renderView;
|
||||
|
||||
[view addSubview:[curView inputOnView]];
|
||||
[[curView inputOnView] becomeFirstResponder];
|
||||
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
|
||||
if(![[curView inputOnToolbar] becomeFirstResponder]) {
|
||||
CC_LOG_ERROR("inputOnToolbar becomeFirstResponder error!");
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
// Change the focus point to the TextField or TextView on the toolbar.
|
||||
- (void) hide {
|
||||
if ([[curView inputOnToolbar] isFirstResponder]) {
|
||||
[[curView inputOnToolbar] resignFirstResponder];
|
||||
}
|
||||
if ([[curView inputOnView] isFirstResponder]) {
|
||||
[[curView inputOnView] resignFirstResponder];
|
||||
}
|
||||
[[curView inputOnView] removeFromSuperview];
|
||||
}
|
||||
|
||||
- (InputBoxPair*) getCurrentViewInUse {
|
||||
return curView;
|
||||
}
|
||||
- (NSString*) getCurrentText {
|
||||
if (g_isMultiline)
|
||||
return [(UITextView*)[curView inputOnToolbar] text];
|
||||
return [(UITextField*)[curView inputOnToolbar] text];
|
||||
}
|
||||
|
||||
|
||||
@end
|
||||
@implementation ButtonHandler
|
||||
- (IBAction)buttonTapped:(UIButton *)button {
|
||||
const ccstd::string text([[[EditboxManager sharedInstance]getCurrentText] UTF8String]);
|
||||
callJSFunc("confirm", text);
|
||||
if (!g_confirmHold)
|
||||
cc::EditBox::complete();
|
||||
}
|
||||
@end
|
||||
/*************************************************************************
|
||||
Implementation of EditBox.
|
||||
************************************************************************/
|
||||
|
||||
// MARK: EditBox
|
||||
|
||||
namespace cc{
|
||||
bool EditBox::_isShown = false;
|
||||
void EditBox::show(const cc::EditBox::ShowInfo &showInfo) {
|
||||
[[EditboxManager sharedInstance] show:&showInfo];
|
||||
EditBox::_isShown = true;
|
||||
}
|
||||
|
||||
void EditBox::hide() {
|
||||
[[EditboxManager sharedInstance] hide];
|
||||
EditBox::_isShown = false;
|
||||
}
|
||||
|
||||
bool EditBox::complete() {
|
||||
if(!EditBox::_isShown)
|
||||
return false;
|
||||
NSString *text = [[EditboxManager sharedInstance] getCurrentText];
|
||||
callJSFunc("complete", [text UTF8String]);
|
||||
EditBox::hide();
|
||||
|
||||
return true;
|
||||
}
|
||||
} // namespace cc
|
||||
40
cocos/ui/edit-box/EditBox-linux.cpp
Normal file
40
cocos/ui/edit-box/EditBox-linux.cpp
Normal file
@@ -0,0 +1,40 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2021-2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
#include "EditBox.h"
|
||||
|
||||
namespace cc {
|
||||
|
||||
void EditBox::show(const ShowInfo &showInfo) {
|
||||
return;
|
||||
}
|
||||
|
||||
void EditBox::hide() {
|
||||
return;
|
||||
}
|
||||
|
||||
bool EditBox::complete() {
|
||||
return true;
|
||||
}
|
||||
} // namespace cc
|
||||
309
cocos/ui/edit-box/EditBox-mac.mm
Normal file
309
cocos/ui/edit-box/EditBox-mac.mm
Normal file
@@ -0,0 +1,309 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2018-2022 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated engine source code (the "Software"), a limited,
|
||||
worldwide, royalty-free, non-assignable, revocable and non-exclusive license
|
||||
to use Cocos Creator solely to develop games on your target platforms. You shall
|
||||
not use Cocos Creator software for developing other software or tools that's
|
||||
used for developing games. You are not granted to publish, distribute,
|
||||
sublicense, and/or sell copies of Cocos Creator.
|
||||
|
||||
The software or tools in this License Agreement are licensed, not sold.
|
||||
Xiamen Yaji Software Co., Ltd. reserves all rights not expressly granted to you.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
#include "EditBox.h"
|
||||
|
||||
#include "cocos/bindings/jswrapper/SeApi.h"
|
||||
#include "cocos/bindings/manual/jsb_global.h"
|
||||
#include "engine/EngineEvents.h"
|
||||
#include "platform/SDLHelper.h"
|
||||
|
||||
#import <AppKit/AppKit.h>
|
||||
|
||||
/*************************************************************************
|
||||
Forward declaration of global functions.
|
||||
************************************************************************/
|
||||
namespace {
|
||||
void callJSFunc(const ccstd::string &type, const ccstd::string &text);
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
Global variables.
|
||||
************************************************************************/
|
||||
namespace {
|
||||
NSTextView *g_textView = nil;
|
||||
NSScrollView *g_scrollView = nil;
|
||||
NSTextField *g_textField = nil;
|
||||
NSSecureTextField *g_secureTextField = nil;
|
||||
bool g_isMultiline = false;
|
||||
bool g_isPassword = false;
|
||||
int g_maxLength = INT_MAX;
|
||||
se::Value g_textInputCallback;
|
||||
} // namespace
|
||||
|
||||
/*************************************************************************
|
||||
TextViewDelegate
|
||||
************************************************************************/
|
||||
@interface TextViewDelegate : NSObject <NSTextViewDelegate>
|
||||
@end
|
||||
|
||||
@implementation TextViewDelegate
|
||||
// Get notification when something is input.
|
||||
- (void)textDidChange:(NSNotification *)notification {
|
||||
callJSFunc("input", [[g_textView.textStorage string] UTF8String]);
|
||||
}
|
||||
|
||||
// Max length limitaion
|
||||
- (BOOL)textView:(NSTextView *)textView
|
||||
shouldChangeTextInRange:(NSRange)affectedCharRange
|
||||
replacementString:(NSString *)replacementString {
|
||||
NSUInteger newLength = [textView.string length] + [replacementString length] - affectedCharRange.length;
|
||||
if (newLength > g_maxLength)
|
||||
return FALSE;
|
||||
|
||||
if (!g_isMultiline && [replacementString containsString:@"\n"])
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
- (void)textDidEndEditing:(NSNotification *)notification {
|
||||
cc::EditBox::complete();
|
||||
}
|
||||
@end
|
||||
|
||||
/*************************************************************************
|
||||
TextFieldDelegate
|
||||
************************************************************************/
|
||||
@interface TextFieldDelegate : NSObject <NSTextFieldDelegate>
|
||||
@end
|
||||
|
||||
@implementation TextFieldDelegate
|
||||
- (void)controlTextDidChange:(NSNotification *)notification {
|
||||
NSTextField *textField = [notification object];
|
||||
callJSFunc("input", [textField.stringValue UTF8String]);
|
||||
}
|
||||
- (void)controlTextDidEndEditing:(NSNotification *)obj {
|
||||
cc::EditBox::complete();
|
||||
}
|
||||
@end
|
||||
|
||||
/*************************************************************************
|
||||
TextFieldFormatter: used for textfield length limitation.
|
||||
************************************************************************/
|
||||
@interface TextFieldFormatter : NSFormatter {
|
||||
int maxLength;
|
||||
}
|
||||
- (void)setMaximumLength:(int)len;
|
||||
@end
|
||||
|
||||
@implementation TextFieldFormatter
|
||||
|
||||
- (id)init {
|
||||
if (self = [super init])
|
||||
maxLength = INT_MAX;
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)setMaximumLength:(int)len {
|
||||
maxLength = len;
|
||||
}
|
||||
|
||||
- (NSString *)stringForObjectValue:(id)object {
|
||||
return (NSString *)object;
|
||||
}
|
||||
|
||||
- (BOOL)getObjectValue:(id *)object forString:(NSString *)string errorDescription:(NSString **)error {
|
||||
*object = string;
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (BOOL)isPartialStringValid:(NSString **)partialStringPtr
|
||||
proposedSelectedRange:(NSRangePointer)proposedSelRangePtr
|
||||
originalString:(NSString *)origString
|
||||
originalSelectedRange:(NSRange)origSelRange
|
||||
errorDescription:(NSString **)error {
|
||||
if ([*partialStringPtr length] > maxLength)
|
||||
return NO;
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (NSAttributedString *)attributedStringForObjectValue:(id)anObject withDefaultAttributes:(NSDictionary *)attributes {
|
||||
return nil;
|
||||
}
|
||||
@end
|
||||
|
||||
/*************************************************************************
|
||||
Implementation of global helper functions.
|
||||
************************************************************************/
|
||||
namespace {
|
||||
|
||||
static cc::events::Resize::Listener resizeListener;
|
||||
|
||||
void getTextInputCallback() {
|
||||
if (!g_textInputCallback.isUndefined())
|
||||
return;
|
||||
|
||||
auto global = se::ScriptEngine::getInstance()->getGlobalObject();
|
||||
se::Value jsbVal;
|
||||
if (global->getProperty("jsb", &jsbVal) && jsbVal.isObject()) {
|
||||
jsbVal.toObject()->getProperty("onTextInput", &g_textInputCallback);
|
||||
// free globle se::Value before ScriptEngine clean up
|
||||
se::ScriptEngine::getInstance()->addBeforeCleanupHook([]() {
|
||||
g_textInputCallback.setUndefined();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void callJSFunc(const ccstd::string &type, const ccstd::string &text) {
|
||||
getTextInputCallback();
|
||||
|
||||
se::AutoHandleScope scope;
|
||||
se::ValueArray args;
|
||||
args.push_back(se::Value(type));
|
||||
args.push_back(se::Value(text));
|
||||
g_textInputCallback.toObject()->call(args, nullptr);
|
||||
}
|
||||
|
||||
void initTextView(const cc::EditBox::ShowInfo &showInfo) {
|
||||
CGRect rect = CGRectMake(showInfo.x, showInfo.y, showInfo.width, showInfo.height);
|
||||
if (!g_textView) {
|
||||
g_textView = [[NSTextView alloc] initWithFrame:rect];
|
||||
g_textView.textColor = [NSColor blackColor];
|
||||
g_textView.backgroundColor = [NSColor whiteColor];
|
||||
g_textView.editable = TRUE;
|
||||
g_textView.hidden = FALSE;
|
||||
g_textView.delegate = [[TextViewDelegate alloc] init];
|
||||
|
||||
g_scrollView = [[NSScrollView alloc] initWithFrame:rect];
|
||||
[g_scrollView setBorderType:NSNoBorder];
|
||||
[g_scrollView setHasVerticalScroller:TRUE];
|
||||
[g_scrollView setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];
|
||||
[g_scrollView setDocumentView:g_textView];
|
||||
}
|
||||
g_textView.string = [NSString stringWithUTF8String:showInfo.defaultValue.c_str()];
|
||||
g_textView.frame = rect;
|
||||
g_scrollView.frame = rect;
|
||||
|
||||
NSWindow *nsWindow = NSApplication.sharedApplication.mainWindow;
|
||||
[nsWindow.contentView addSubview:g_scrollView];
|
||||
[nsWindow makeFirstResponder:g_scrollView];
|
||||
}
|
||||
|
||||
void doInitTextField(NSTextField *textField, const CGRect &rect, const cc::EditBox::ShowInfo &showInfo) {
|
||||
textField.editable = TRUE;
|
||||
textField.wantsLayer = TRUE;
|
||||
textField.frame = rect;
|
||||
textField.stringValue = [NSString stringWithUTF8String:showInfo.defaultValue.c_str()];
|
||||
[(TextFieldFormatter *)textField.formatter setMaximumLength:showInfo.maxLength];
|
||||
|
||||
NSWindow *nsWindow = NSApplication.sharedApplication.mainWindow;
|
||||
[nsWindow.contentView addSubview:textField];
|
||||
[textField becomeFirstResponder];
|
||||
}
|
||||
|
||||
void initTextField(const cc::EditBox::ShowInfo &showInfo) {
|
||||
CGRect rect = CGRectMake(showInfo.x, showInfo.y, showInfo.width, showInfo.height);
|
||||
|
||||
// Use NSSecureTextField for password, use NSTextField for others.
|
||||
if (g_isPassword) {
|
||||
if (!g_secureTextField) {
|
||||
g_secureTextField = [[NSSecureTextField alloc] init];
|
||||
g_secureTextField.textColor = [NSColor blackColor];
|
||||
g_secureTextField.backgroundColor = [NSColor whiteColor];
|
||||
g_secureTextField.delegate = [[TextFieldDelegate alloc] init];
|
||||
g_secureTextField.formatter = [[TextFieldFormatter alloc] init];
|
||||
}
|
||||
doInitTextField(g_secureTextField, rect, showInfo);
|
||||
} else {
|
||||
if (!g_textField) {
|
||||
g_textField = [[NSTextField alloc] init];
|
||||
g_textField.textColor = [NSColor blackColor];
|
||||
g_textField.backgroundColor = [NSColor whiteColor];
|
||||
g_textField.delegate = [[TextFieldDelegate alloc] init];
|
||||
g_textField.formatter = [[TextFieldFormatter alloc] init];
|
||||
}
|
||||
doInitTextField(g_textField, rect, showInfo);
|
||||
}
|
||||
}
|
||||
|
||||
void init(const cc::EditBox::ShowInfo &showInfo) {
|
||||
if (showInfo.isMultiline)
|
||||
initTextView(showInfo);
|
||||
else
|
||||
initTextField(showInfo);
|
||||
|
||||
resizeListener.bind([&](int /*width*/, int /*height*/ , uint32_t /*windowId*/) {
|
||||
cc::EditBox::complete();
|
||||
});
|
||||
}
|
||||
} // namespace
|
||||
|
||||
/*************************************************************************
|
||||
Implementation of EditBox.
|
||||
************************************************************************/
|
||||
|
||||
namespace cc {
|
||||
|
||||
bool EditBox::_isShown = false;
|
||||
|
||||
void EditBox::show(const ShowInfo &showInfo) {
|
||||
g_isMultiline = showInfo.isMultiline;
|
||||
g_maxLength = showInfo.maxLength;
|
||||
g_isPassword = showInfo.inputType == "password";
|
||||
|
||||
init(showInfo);
|
||||
|
||||
EditBox::_isShown = true;
|
||||
}
|
||||
|
||||
void EditBox::hide() {
|
||||
if (g_scrollView)
|
||||
[g_scrollView removeFromSuperview];
|
||||
|
||||
if (g_textField) {
|
||||
[g_textField resignFirstResponder];
|
||||
[g_textField removeFromSuperview];
|
||||
}
|
||||
|
||||
if (g_secureTextField) {
|
||||
[g_secureTextField resignFirstResponder];
|
||||
[g_secureTextField removeFromSuperview];
|
||||
}
|
||||
|
||||
EditBox::_isShown = false;
|
||||
}
|
||||
|
||||
bool EditBox::complete() {
|
||||
if (!_isShown)
|
||||
return false;
|
||||
|
||||
if (g_isMultiline)
|
||||
callJSFunc("complete", [[g_textView.textStorage string] UTF8String]);
|
||||
else {
|
||||
if (g_isPassword)
|
||||
callJSFunc("complete", [g_secureTextField.stringValue UTF8String]);
|
||||
else
|
||||
callJSFunc("complete", [g_textField.stringValue UTF8String]);
|
||||
}
|
||||
|
||||
EditBox::hide();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace cc
|
||||
119
cocos/ui/edit-box/EditBox-ohos.cpp
Normal file
119
cocos/ui/edit-box/EditBox-ohos.cpp
Normal file
@@ -0,0 +1,119 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2021-2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
#include "EditBox.h"
|
||||
#include "cocos/bindings/jswrapper/SeApi.h"
|
||||
#include "cocos/bindings/manual/jsb_global.h"
|
||||
#include "engine/EngineEvents.h"
|
||||
//#include "platform/Application.h"
|
||||
#include "platform/java/jni/JniHelper.h"
|
||||
|
||||
#ifndef JCLS_EDITBOX
|
||||
#define JCLS_EDITBOX "com/cocos/lib/CocosEditBoxAbility"
|
||||
#endif
|
||||
|
||||
#ifndef ORG_EDITBOX_CLASS_NAME
|
||||
#define ORG_EDITBOX_CLASS_NAME com_cocos_lib_CocosEditBoxAbility
|
||||
#endif
|
||||
#define JNI_EDITBOX(FUNC) JNI_METHOD1(ORG_EDITBOX_CLASS_NAME, FUNC)
|
||||
|
||||
namespace {
|
||||
se::Value textInputCallback;
|
||||
|
||||
void getTextInputCallback() {
|
||||
if (!textInputCallback.isUndefined()) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto global = se::ScriptEngine::getInstance()->getGlobalObject();
|
||||
se::Value jsbVal;
|
||||
if (global->getProperty("jsb", &jsbVal) && jsbVal.isObject()) {
|
||||
jsbVal.toObject()->getProperty("onTextInput", &textInputCallback);
|
||||
// free globle se::Value before ScriptEngine clean up
|
||||
se::ScriptEngine::getInstance()->addBeforeCleanupHook([]() {
|
||||
textInputCallback.setUndefined();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void callJSFunc(const ccstd::string &type, const ccstd::string &text) {
|
||||
getTextInputCallback();
|
||||
|
||||
se::AutoHandleScope scope;
|
||||
se::ValueArray args;
|
||||
args.push_back(se::Value(type));
|
||||
args.push_back(se::Value(text));
|
||||
textInputCallback.toObject()->call(args, nullptr);
|
||||
}
|
||||
} // namespace
|
||||
|
||||
namespace cc {
|
||||
|
||||
bool EditBox::_isShown = false; //NOLINT
|
||||
|
||||
void EditBox::show(const cc::EditBox::ShowInfo &showInfo) {
|
||||
JniHelper::callStaticVoidMethod(JCLS_EDITBOX,
|
||||
"showNative",
|
||||
showInfo.defaultValue,
|
||||
showInfo.maxLength,
|
||||
showInfo.isMultiline,
|
||||
showInfo.confirmHold,
|
||||
showInfo.confirmType,
|
||||
showInfo.inputType);
|
||||
_isShown = true;
|
||||
}
|
||||
|
||||
void EditBox::hide() {
|
||||
JniHelper::callStaticVoidMethod(JCLS_EDITBOX, "hideNative");
|
||||
_isShown = false;
|
||||
}
|
||||
|
||||
bool EditBox::complete() {
|
||||
if (!_isShown) {
|
||||
return false;
|
||||
}
|
||||
|
||||
EditBox::hide();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace cc
|
||||
|
||||
extern "C" {
|
||||
JNIEXPORT void JNICALL JNI_EDITBOX(onKeyboardInputNative)(JNIEnv * /*env*/, jclass /*unused*/, jstring text) {
|
||||
auto textStr = cc::JniHelper::jstring2string(text);
|
||||
callJSFunc("input", textStr);
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL JNI_EDITBOX(onKeyboardCompleteNative)(JNIEnv * /*env*/, jclass /*unused*/, jstring text) {
|
||||
auto textStr = cc::JniHelper::jstring2string(text);
|
||||
callJSFunc("complete", textStr);
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL JNI_EDITBOX(onKeyboardConfirmNative)(JNIEnv * /*env*/, jclass /*unused*/, jstring text) {
|
||||
auto textStr = cc::JniHelper::jstring2string(text);
|
||||
callJSFunc("confirm", textStr);
|
||||
}
|
||||
}
|
||||
107
cocos/ui/edit-box/EditBox-openharmony.cpp
Normal file
107
cocos/ui/edit-box/EditBox-openharmony.cpp
Normal file
@@ -0,0 +1,107 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2022-2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated engine source code (the "Software"), a limited,
|
||||
worldwide, royalty-free, non-assignable, revocable and non-exclusive license
|
||||
to use Cocos Creator solely to develop games on your target platforms. You shall
|
||||
not use Cocos Creator software for developing other software or tools that's
|
||||
used for developing games. You are not granted to publish, distribute,
|
||||
sublicense, and/or sell copies of Cocos Creator.
|
||||
|
||||
The software or tools in this License Agreement are licensed, not sold.
|
||||
Xiamen Yaji Software Co., Ltd. reserves all rights not expressly granted to you.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
#include "EditBox.h"
|
||||
#include "EditBox-openharmony.h"
|
||||
|
||||
#include "application/ApplicationManager.h"
|
||||
#include "platform/openharmony/napi/NapiHelper.h"
|
||||
#include "bindings/jswrapper/SeApi.h"
|
||||
|
||||
namespace cc {
|
||||
|
||||
/*************************************************************************
|
||||
Global variables and functions.
|
||||
************************************************************************/
|
||||
|
||||
namespace {
|
||||
se::Value g_textInputCallback;
|
||||
|
||||
void getTextInputCallback() {
|
||||
if (!g_textInputCallback.isUndefined())
|
||||
return;
|
||||
|
||||
auto global = se::ScriptEngine::getInstance()->getGlobalObject();
|
||||
se::Value jsbVal;
|
||||
if (global->getProperty("jsb", &jsbVal) && jsbVal.isObject()) {
|
||||
jsbVal.toObject()->getProperty("onTextInput", &g_textInputCallback);
|
||||
// free globle se::Value before ScriptEngine clean up
|
||||
se::ScriptEngine::getInstance()->addBeforeCleanupHook([]() {
|
||||
g_textInputCallback.setUndefined();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void callJSFunc(const ccstd::string &type, const ccstd::string &text) {
|
||||
getTextInputCallback();
|
||||
|
||||
se::AutoHandleScope scope;
|
||||
se::ValueArray args;
|
||||
args.push_back(se::Value(type));
|
||||
args.push_back(se::Value(text));
|
||||
g_textInputCallback.toObject()->call(args, nullptr);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
/*************************************************************************
|
||||
Implementation of EditBox.
|
||||
************************************************************************/
|
||||
void EditBox::show(const EditBox::ShowInfo &showInfo) {
|
||||
NapiHelper::postMessageToUIThread("showEditBox", Napi::String::New(NapiHelper::getWorkerEnv(), showInfo.defaultValue));
|
||||
}
|
||||
|
||||
void EditBox::hide() {
|
||||
NapiHelper::postMessageToUIThread("hideEditBox", Napi::String::New(NapiHelper::getWorkerEnv(), ""));
|
||||
}
|
||||
|
||||
bool EditBox::complete() {
|
||||
callJSFunc("complete", "");
|
||||
return true;
|
||||
}
|
||||
|
||||
void OpenHarmonyEditBox::napiOnComplete(const Napi::CallbackInfo &info) {
|
||||
EditBox::complete();
|
||||
}
|
||||
|
||||
void OpenHarmonyEditBox::napiOnTextChange(const Napi::CallbackInfo &info) {
|
||||
auto env = info.Env();
|
||||
if (info.Length() != 1) {
|
||||
Napi::Error::New(env, "napiOnTextChange, 1 argument expected").ThrowAsJavaScriptException();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!info[0].IsString()) {
|
||||
Napi::TypeError::New(env, "napiOnTextChange, string argument expected").ThrowAsJavaScriptException();
|
||||
return;
|
||||
}
|
||||
|
||||
ccstd::string buffer = info[0].As<Napi::String>().Utf8Value();
|
||||
callJSFunc("input", buffer);
|
||||
}
|
||||
|
||||
} // namespace cc
|
||||
|
||||
|
||||
47
cocos/ui/edit-box/EditBox-openharmony.h
Normal file
47
cocos/ui/edit-box/EditBox-openharmony.h
Normal file
@@ -0,0 +1,47 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2022-2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated engine source code (the "Software"), a limited,
|
||||
worldwide, royalty-free, non-assignable, revocable and non-exclusive license
|
||||
to use Cocos Creator solely to develop games on your target platforms. You shall
|
||||
not use Cocos Creator software for developing other software or tools that's
|
||||
used for developing games. You are not granted to publish, distribute,
|
||||
sublicense, and/or sell copies of Cocos Creator.
|
||||
|
||||
The software or tools in this License Agreement are licensed, not sold.
|
||||
Xiamen Yaji Software Co., Ltd. reserves all rights not expressly granted to you.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
#include "EditBox.h"
|
||||
#include "cocos/application/ApplicationManager.h"
|
||||
#include "platform/openharmony/napi/NapiHelper.h"
|
||||
|
||||
namespace cc {
|
||||
|
||||
class OpenHarmonyEditBox : public EditBox {
|
||||
public:
|
||||
static void napiOnComplete(const Napi::CallbackInfo &info);
|
||||
static void napiOnTextChange(const Napi::CallbackInfo &info);
|
||||
|
||||
static napi_value show(const std::string& inputMessage);
|
||||
static napi_value hide();
|
||||
private:
|
||||
static napi_ref showEditBoxFunction;
|
||||
static napi_ref hideEditBoxFunction;
|
||||
|
||||
};
|
||||
|
||||
} // namespace cc
|
||||
|
||||
|
||||
283
cocos/ui/edit-box/EditBox-win32.cpp
Normal file
283
cocos/ui/edit-box/EditBox-win32.cpp
Normal file
@@ -0,0 +1,283 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2018-2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
#include "EditBox.h"
|
||||
#include "cocos/application/ApplicationManager.h"
|
||||
#include "cocos/bindings/jswrapper/SeApi.h"
|
||||
#include "cocos/bindings/manual/jsb_global.h"
|
||||
#include "cocos/platform/interfaces/modules/ISystemWindow.h"
|
||||
#include "cocos/platform/interfaces/modules/ISystemWindowManager.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <windows.h>
|
||||
#include <codecvt>
|
||||
#include <locale>
|
||||
#include <memory>
|
||||
|
||||
#include "Richedit.h"
|
||||
|
||||
namespace cc {
|
||||
|
||||
/*************************************************************************
|
||||
Global variables and functions.
|
||||
************************************************************************/
|
||||
|
||||
namespace {
|
||||
bool g_isMultiline = false;
|
||||
HWND g_hwndEditBox = nullptr;
|
||||
WNDPROC g_prevMainWindowProc = nullptr;
|
||||
WNDPROC g_prevEditWindowProc = nullptr;
|
||||
se::Value g_textInputCallback;
|
||||
|
||||
HWND getCurrentWindowHwnd() {
|
||||
if (!CC_CURRENT_APPLICATION()) {
|
||||
return nullptr;
|
||||
}
|
||||
ISystemWindow *systemWindowIntf = CC_GET_MAIN_SYSTEM_WINDOW();
|
||||
if (!systemWindowIntf) {
|
||||
return nullptr;
|
||||
}
|
||||
return reinterpret_cast<HWND>(systemWindowIntf->getWindowHandle());
|
||||
}
|
||||
|
||||
int getCocosWindowHeight() {
|
||||
// HWND parent = cc_get_application_view()->getWindowHandle();
|
||||
HWND parent = getCurrentWindowHwnd();
|
||||
RECT rect;
|
||||
GetClientRect(parent, &rect);
|
||||
return (rect.bottom - rect.top);
|
||||
}
|
||||
|
||||
void getTextInputCallback() {
|
||||
if (!g_textInputCallback.isUndefined())
|
||||
return;
|
||||
|
||||
auto global = se::ScriptEngine::getInstance()->getGlobalObject();
|
||||
se::Value jsbVal;
|
||||
if (global->getProperty("jsb", &jsbVal) && jsbVal.isObject()) {
|
||||
jsbVal.toObject()->getProperty("onTextInput", &g_textInputCallback);
|
||||
// free globle se::Value before ScriptEngine clean up
|
||||
se::ScriptEngine::getInstance()->addBeforeCleanupHook([]() {
|
||||
g_textInputCallback.setUndefined();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void callJSFunc(const ccstd::string &type, const ccstd::string &text) {
|
||||
getTextInputCallback();
|
||||
|
||||
se::AutoHandleScope scope;
|
||||
se::ValueArray args;
|
||||
args.push_back(se::Value(type));
|
||||
args.push_back(se::Value(text));
|
||||
g_textInputCallback.toObject()->call(args, nullptr);
|
||||
}
|
||||
|
||||
ccstd::string getText(HWND hwnd) {
|
||||
int length = GetWindowTextLength(hwnd);
|
||||
LPWSTR str = (LPWSTR)malloc(sizeof(WCHAR) * (length + 1));
|
||||
GetWindowText(hwnd, str, length + 1);
|
||||
|
||||
std::wstring_convert<std::codecvt_utf8<wchar_t>> convert;
|
||||
ccstd::string ret(convert.to_bytes(str));
|
||||
free(str);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::wstring str2ws(const ccstd::string &text) {
|
||||
if (text.empty())
|
||||
return std::wstring();
|
||||
|
||||
int sz = MultiByteToWideChar(CP_UTF8, 0, &text[0], (int)text.size(), 0, 0);
|
||||
std::wstring res(sz, 0);
|
||||
MultiByteToWideChar(CP_UTF8, 0, &text[0], (int)text.size(), &res[0], sz);
|
||||
return res;
|
||||
}
|
||||
|
||||
LRESULT mainWindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
|
||||
switch (msg) {
|
||||
case WM_LBUTTONDOWN:
|
||||
EditBox::complete();
|
||||
EditBox::hide();
|
||||
SetFocus(getCurrentWindowHwnd());
|
||||
break;
|
||||
case WM_COMMAND:
|
||||
// EN_CHANGE => EN_UPDATE
|
||||
if (EN_UPDATE == HIWORD(wParam)) {
|
||||
callJSFunc("input", getText(g_hwndEditBox).c_str());
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return CallWindowProc(g_prevMainWindowProc, hwnd, msg, wParam, lParam);
|
||||
}
|
||||
|
||||
LRESULT editWindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
|
||||
switch (msg) {
|
||||
case WM_KEYUP:
|
||||
if (wParam == VK_RETURN && !g_isMultiline) {
|
||||
EditBox::complete();
|
||||
EditBox::hide();
|
||||
SetFocus(getCurrentWindowHwnd());
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return CallWindowProc(g_prevEditWindowProc, hwnd, msg, wParam, lParam);
|
||||
}
|
||||
} // namespace
|
||||
|
||||
/*************************************************************************
|
||||
Implementation of EditBox.
|
||||
************************************************************************/
|
||||
void EditBox::show(const EditBox::ShowInfo &showInfo) {
|
||||
int windowHeight = getCocosWindowHeight();
|
||||
if (!g_hwndEditBox) {
|
||||
HWND parent = getCurrentWindowHwnd();
|
||||
|
||||
UINT32 flags = WS_CHILD | showInfo.textAlignment | WS_TABSTOP | ES_AUTOHSCROLL;
|
||||
g_isMultiline = showInfo.isMultiline;
|
||||
if (g_isMultiline) {
|
||||
flags |= ES_MULTILINE;
|
||||
}
|
||||
if (showInfo.inputType == "password")
|
||||
flags |= WS_EX_TRANSPARENT;
|
||||
|
||||
/* g_hwndEditBox = CreateWindowEx(
|
||||
WS_EX_WINDOWEDGE,
|
||||
L"EDIT",
|
||||
NULL,
|
||||
flags,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
parent,
|
||||
0,
|
||||
NULL,
|
||||
NULL);*/
|
||||
LoadLibrary(TEXT("Msftedit.dll"));
|
||||
g_hwndEditBox = CreateWindowEx(
|
||||
0,
|
||||
MSFTEDIT_CLASS,
|
||||
NULL,
|
||||
flags,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
parent,
|
||||
0,
|
||||
NULL,
|
||||
NULL);
|
||||
|
||||
if (!g_hwndEditBox) {
|
||||
wchar_t buffer[256] = {0};
|
||||
FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
|
||||
NULL,
|
||||
GetLastError(),
|
||||
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
||||
buffer,
|
||||
sizeof(buffer) / sizeof(wchar_t),
|
||||
NULL);
|
||||
std::wstring_convert<std::codecvt_utf8<wchar_t>> convert;
|
||||
CC_LOG_DEBUG("Can not create editbox: %s", convert.to_bytes(buffer).c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
g_prevMainWindowProc = (WNDPROC)SetWindowLongPtr(parent, GWLP_WNDPROC, (LONG_PTR)mainWindowProc);
|
||||
g_prevEditWindowProc = (WNDPROC)SetWindowLongPtr(g_hwndEditBox, GWLP_WNDPROC, (LONG_PTR)editWindowProc);
|
||||
}
|
||||
|
||||
::SendMessageW(g_hwndEditBox, EM_LIMITTEXT, showInfo.maxLength, 0);
|
||||
|
||||
// SendMessage(g_hwndEditBox, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf);
|
||||
SetWindowPos(g_hwndEditBox,
|
||||
HWND_NOTOPMOST,
|
||||
showInfo.x,
|
||||
windowHeight - showInfo.y - showInfo.height,
|
||||
showInfo.width,
|
||||
showInfo.height,
|
||||
SWP_NOZORDER);
|
||||
|
||||
::SetWindowTextW(g_hwndEditBox, str2ws(showInfo.defaultValue).c_str());
|
||||
|
||||
// SendMessage(g_hwndEditBox, EM_SETFONTSIZE, 1, 0);
|
||||
SendMessage(g_hwndEditBox, EM_SETBKGNDCOLOR, 0, RGB((showInfo.backgroundColor & 0x000000ff), (showInfo.backgroundColor & 0x0000ff00) >> 8, (showInfo.backgroundColor & 0x00ff0000) >> 16));
|
||||
|
||||
::PostMessage(g_hwndEditBox, WM_ACTIVATE, 0, 0);
|
||||
::ShowWindow(g_hwndEditBox, SW_SHOW);
|
||||
/* Get current length of text in the box */
|
||||
int index = GetWindowTextLength(g_hwndEditBox);
|
||||
SetFocus(g_hwndEditBox);
|
||||
|
||||
SendMessage(g_hwndEditBox, EM_SETSEL, (WPARAM)0, (LPARAM)index);
|
||||
// int height = CC_GET_MAIN_SYSTEM_WINDOW()->kheight;
|
||||
CHARFORMAT2 cf;
|
||||
RECT rect;
|
||||
|
||||
GetWindowRect(getCurrentWindowHwnd(), &rect);
|
||||
float WindowRatio = (float)(rect.bottom - rect.top) / (float)CC_GET_MAIN_SYSTEM_WINDOW()->getViewSize().height;
|
||||
float JsFontRatio = float(showInfo.fontSize) / 5;
|
||||
/** A probale way to calculate the increase of font size
|
||||
* OriginalSize + Increase = OriginalSize * Ratio_of_js_fontSize * Ratio_of_window
|
||||
* Default value : OriginalSize = 8, Ratio_of_js_fontSize = showInfo.fontSize /5,
|
||||
* Ratio_of_window = (float)height / (float)CC_GET_MAIN_SYSTEM_WINDOW()->getViewSize().height
|
||||
* thus Increase was calculated.
|
||||
*/
|
||||
int fsize = (float)(JsFontRatio + 8) * WindowRatio - 8;
|
||||
|
||||
SendMessage(g_hwndEditBox, EM_SETFONTSIZE, fsize, 0);
|
||||
/* Set the caret to the end of the text in the box */
|
||||
SendMessage(g_hwndEditBox, EM_SETSEL, (WPARAM)index, (LPARAM)index);
|
||||
|
||||
cf.cbSize = sizeof(CHARFORMAT2);
|
||||
cf.crTextColor = RGB((showInfo.fontColor & 0x000000ff), (showInfo.fontColor & 0x0000ff00) >> 8, (showInfo.fontColor & 0x00ff0000) >> 16);
|
||||
|
||||
cf.crBackColor = RGB((showInfo.backColor & 0x000000ff), (showInfo.backColor & 0x0000ff00) >> 8, (showInfo.backColor & 0x00ff0000) >> 16);
|
||||
cf.dwMask = CFM_COLOR | CFM_BOLD | CFM_ITALIC | CFM_UNDERLINE;
|
||||
cf.dwEffects = (showInfo.isUnderline ? CFE_UNDERLINE : 0) | (showInfo.isBold ? CFE_BOLD : 0) | (showInfo.isItalic ? CFE_ITALIC : 0);
|
||||
cf.bUnderlineColor = showInfo.underlineColor;
|
||||
SendMessage(g_hwndEditBox, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf);
|
||||
}
|
||||
|
||||
void EditBox::hide() {
|
||||
DestroyWindow(g_hwndEditBox);
|
||||
|
||||
SetWindowLongPtr(getCurrentWindowHwnd(), GWLP_WNDPROC, (LONG_PTR)g_prevMainWindowProc);
|
||||
SetWindowLongPtr(g_hwndEditBox, GWLP_WNDPROC, (LONG_PTR)g_prevEditWindowProc);
|
||||
g_hwndEditBox = nullptr;
|
||||
}
|
||||
|
||||
bool EditBox::complete() {
|
||||
callJSFunc("complete", getText(g_hwndEditBox).c_str());
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace cc
|
||||
73
cocos/ui/edit-box/EditBox.h
Normal file
73
cocos/ui/edit-box/EditBox.h
Normal file
@@ -0,0 +1,73 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2018-2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "base/Macros.h"
|
||||
#include "base/std/container/string.h"
|
||||
|
||||
namespace cc {
|
||||
|
||||
class EditBox {
|
||||
public:
|
||||
enum TextAlignment {
|
||||
LEFT,
|
||||
CENTER,
|
||||
RIGHT
|
||||
};
|
||||
struct ShowInfo {
|
||||
ccstd::string defaultValue;
|
||||
ccstd::string confirmType;
|
||||
ccstd::string inputType;
|
||||
int maxLength = 0;
|
||||
int x = 0;
|
||||
int y = 0;
|
||||
int width = 0;
|
||||
int height = 0;
|
||||
bool confirmHold = false;
|
||||
bool isMultiline = false;
|
||||
//NEW PROPERTIES
|
||||
uint32_t fontSize = 20;
|
||||
uint32_t fontColor = 0x00000000;
|
||||
uint32_t backColor = 0x00000000; //font back color
|
||||
uint32_t backgroundColor = 0x00000000;
|
||||
bool isBold = false;
|
||||
bool isItalic = false;
|
||||
bool isUnderline = false;
|
||||
uint32_t underlineColor = 0x00000000;
|
||||
uint32_t textAlignment = LEFT; //By default, override with left, center or right
|
||||
};
|
||||
|
||||
static void show(const ShowInfo &showInfo);
|
||||
static void hide();
|
||||
|
||||
// It is internally to send a complete message to JS.
|
||||
// Don't call it by yourself untile you know the effect.
|
||||
static bool complete();
|
||||
|
||||
private:
|
||||
static bool _isShown; //NOLINT(readability-identifier-naming)
|
||||
};
|
||||
|
||||
} // namespace cc
|
||||
Reference in New Issue
Block a user