mirror of
https://github.com/smallmain/cocos-enhance-kit.git
synced 2025-09-24 09:47:55 +00:00
初始化
This commit is contained in:
115
cocos2d-x/cocos/ui/edit-box/EditBox-android.cpp
Normal file
115
cocos2d-x/cocos/ui/edit-box/EditBox-android.cpp
Normal file
@@ -0,0 +1,115 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2018 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos2d-x.org
|
||||
|
||||
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 "platform/android/jni/JniHelper.h"
|
||||
#include "cocos/scripting/js-bindings/jswrapper/SeApi.h"
|
||||
#include "cocos/scripting/js-bindings/manual/jsb_global.h"
|
||||
|
||||
#ifndef JCLS_EDITBOX
|
||||
#define JCLS_EDITBOX "org/cocos2dx/lib/Cocos2dxEditBox"
|
||||
#endif
|
||||
|
||||
#ifndef ORG_EDITBOX_CLASS_NAME
|
||||
#define ORG_EDITBOX_CLASS_NAME org_cocos2dx_lib_Cocos2dxEditBox
|
||||
#endif
|
||||
#define JNI_EDITBOX(FUNC) JNI_METHOD1(ORG_EDITBOX_CLASS_NAME,FUNC)
|
||||
|
||||
|
||||
NS_CC_BEGIN
|
||||
|
||||
void EditBox::show(const cocos2d::EditBox::ShowInfo& showInfo)
|
||||
{
|
||||
JniHelper::callStaticVoidMethod(JCLS_EDITBOX,
|
||||
"showNative",
|
||||
showInfo.defaultValue,
|
||||
showInfo.maxLength,
|
||||
showInfo.isMultiline,
|
||||
showInfo.confirmHold,
|
||||
showInfo.confirmType,
|
||||
showInfo.inputType);
|
||||
}
|
||||
|
||||
void EditBox::hide()
|
||||
{
|
||||
JniHelper::callStaticVoidMethod(JCLS_EDITBOX, "hideNative");
|
||||
}
|
||||
|
||||
void EditBox::updateRect(int x, int y, int width, int height)
|
||||
{
|
||||
// not supported ...
|
||||
}
|
||||
|
||||
NS_CC_END
|
||||
|
||||
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 std::string& type, const jstring& text)
|
||||
{
|
||||
getTextInputCallback();
|
||||
|
||||
se::AutoHandleScope scope;
|
||||
se::ValueArray args;
|
||||
args.push_back(se::Value(type));
|
||||
args.push_back(se::Value(cocos2d::JniHelper::jstring2string(text)));
|
||||
textInputCallback.toObject()->call(args, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
extern "C"
|
||||
{
|
||||
JNIEXPORT void JNICALL JNI_EDITBOX(onKeyboardInputNative)(JNIEnv* env, jclass, jstring text)
|
||||
{
|
||||
callJSFunc("input", text);
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL JNI_EDITBOX(onKeyboardCompleteNative)(JNIEnv* env, jclass, jstring text)
|
||||
{
|
||||
callJSFunc("complete", text);
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL JNI_EDITBOX(onKeyboardConfirmNative)(JNIEnv* env, jclass, jstring text)
|
||||
{
|
||||
callJSFunc("confirm", text);
|
||||
}
|
||||
}
|
482
cocos2d-x/cocos/ui/edit-box/EditBox-ios.mm
Normal file
482
cocos2d-x/cocos/ui/edit-box/EditBox-ios.mm
Normal file
@@ -0,0 +1,482 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2018 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos2d-x.org
|
||||
|
||||
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 "platform/CCApplication.h"
|
||||
#include "platform/ios/CCEAGLView-ios.h"
|
||||
#include "cocos/scripting/js-bindings/jswrapper/SeApi.h"
|
||||
#include "cocos/scripting/js-bindings/manual/jsb_global.h"
|
||||
|
||||
#import <UIKit/UITextField.h>
|
||||
#import <UIKit/UITextView.h>
|
||||
|
||||
#define TEXT_LINE_HEIGHT 40
|
||||
#define TEXT_VIEW_MAX_LINE_SHOWN 3
|
||||
#define BUTTON_HIGHT (TEXT_LINE_HEIGHT - 2)
|
||||
#define BUTTON_WIDTH 60
|
||||
|
||||
#define TO_TEXT_VIEW(textinput) ((UITextView*)textinput)
|
||||
#define TO_TEXT_FIELD(textinput) ((UITextField*)textinput)
|
||||
|
||||
/*************************************************************************
|
||||
Inner class declarations.
|
||||
************************************************************************/
|
||||
|
||||
// MARK: class declaration
|
||||
|
||||
@interface ButtonHandler : NSObject
|
||||
-(IBAction) buttonTapped:(UIButton *)button;
|
||||
@end
|
||||
|
||||
@interface KeyboardEventHandler : NSObject
|
||||
-(void)keyboardWillShow: (NSNotification*) notification;
|
||||
-(void)keyboardWillHide: (NSNotification*) notification;
|
||||
@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>
|
||||
- (BOOL) textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text;
|
||||
- (void) textViewDidChange:(UITextView *)textView;
|
||||
@end
|
||||
|
||||
/*************************************************************************
|
||||
Global variables and functions.
|
||||
************************************************************************/
|
||||
|
||||
// MARK: global variables and functions
|
||||
|
||||
namespace
|
||||
{
|
||||
bool g_isMultiline = false;
|
||||
bool g_confirmHold = false;
|
||||
int g_maxLength = INT_MAX;
|
||||
KeyboardEventHandler* g_keyboardHandler = nil;
|
||||
|
||||
// "#1fa014", a color of dark green, was used for confirm button background
|
||||
static UIColor* g_darkGreen = [UIColor colorWithRed:31/255.0 green:160/255.0 blue:20/255.0 alpha:0.8];
|
||||
|
||||
UITextField* g_textField = nil;
|
||||
TextFieldDelegate* g_textFieldDelegate = nil;
|
||||
UIButton* g_textFieldConfirmButton = nil;
|
||||
ButtonHandler* g_textFieldConfirmButtonHandler = nil;
|
||||
|
||||
UITextView* g_textView = nil;
|
||||
TextViewDelegate* g_textViewDelegate = nil;
|
||||
UIButton* g_textViewConfirmButton = nil;
|
||||
ButtonHandler* g_textViewConfirmButtonHander = nil;
|
||||
|
||||
UIView* getCurrentView()
|
||||
{
|
||||
if (g_isMultiline)
|
||||
return g_textView;
|
||||
else
|
||||
return g_textField;
|
||||
}
|
||||
|
||||
NSString* getCurrentText()
|
||||
{
|
||||
if (g_isMultiline)
|
||||
return g_textView.text;
|
||||
else
|
||||
return g_textField.text;
|
||||
}
|
||||
|
||||
void setText(NSString* text)
|
||||
{
|
||||
if (g_isMultiline)
|
||||
g_textView.text = text;
|
||||
else
|
||||
g_textField.text = text;
|
||||
}
|
||||
|
||||
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 std::string& type, const std::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);
|
||||
}
|
||||
|
||||
int getTextInputHeight()
|
||||
{
|
||||
if (g_isMultiline)
|
||||
return TEXT_LINE_HEIGHT * TEXT_VIEW_MAX_LINE_SHOWN;
|
||||
else
|
||||
return TEXT_LINE_HEIGHT;
|
||||
}
|
||||
|
||||
void createButton(UIButton** button, ButtonHandler** buttonHandler, const CGRect& viewRect, const std::string& title)
|
||||
{
|
||||
ButtonHandler *btnHandler = [[ButtonHandler alloc] init];
|
||||
UIButton* btn = [UIButton buttonWithType:UIButtonTypeRoundedRect];
|
||||
[btn addTarget:btnHandler action:@selector(buttonTapped:)
|
||||
forControlEvents:UIControlEventTouchUpInside];
|
||||
btn.frame = CGRectMake(0, 0, BUTTON_WIDTH, BUTTON_HIGHT);
|
||||
btn.backgroundColor = g_darkGreen;
|
||||
[btn setTitle: [NSString stringWithUTF8String:title.c_str()]
|
||||
forState:UIControlStateNormal];
|
||||
[btn setTitleColor: [UIColor whiteColor]
|
||||
forState:UIControlStateNormal];
|
||||
|
||||
*button = btn;
|
||||
*buttonHandler = btnHandler;
|
||||
}
|
||||
|
||||
void setTexFiledKeyboardType(UITextField* textField, const std::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 std::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 std::string& returnType)
|
||||
{
|
||||
NSString* titleKey = [NSString stringWithUTF8String: returnType.c_str()];
|
||||
return NSLocalizedString(titleKey, nil); // get i18n string to be the title
|
||||
}
|
||||
|
||||
void initTextField(const CGRect& rect, const cocos2d::EditBox::ShowInfo& showInfo)
|
||||
{
|
||||
if (! g_textField)
|
||||
{
|
||||
g_textField = [[UITextField alloc] initWithFrame:rect];
|
||||
g_textField.textColor = [UIColor blackColor];
|
||||
g_textField.backgroundColor = [UIColor whiteColor];
|
||||
[g_textField setBorderStyle:UITextBorderStyleLine];
|
||||
g_textField.backgroundColor = [UIColor whiteColor];
|
||||
|
||||
g_textFieldDelegate = [[TextFieldDelegate alloc] init];
|
||||
g_textField.delegate = g_textFieldDelegate;
|
||||
|
||||
// Assign the overlay button to a stored text field
|
||||
createButton(&g_textFieldConfirmButton, &g_textFieldConfirmButtonHandler, rect, showInfo.confirmType);
|
||||
g_textField.rightView = g_textFieldConfirmButton;
|
||||
g_textField.rightViewMode = UITextFieldViewModeAlways;
|
||||
[g_textField addTarget:g_textFieldDelegate action:@selector(textFieldDidChange:) forControlEvents:UIControlEventEditingChanged];
|
||||
}
|
||||
|
||||
g_textField.frame = rect;
|
||||
setTextFieldReturnType(g_textField, showInfo.confirmType);
|
||||
setTexFiledKeyboardType(g_textField, showInfo.inputType);
|
||||
g_textField.text = [NSString stringWithUTF8String: showInfo.defaultValue.c_str()];
|
||||
[g_textFieldConfirmButton setTitle:getConfirmButtonTitle(showInfo.confirmType) forState:UIControlStateNormal];
|
||||
}
|
||||
|
||||
void initTextView(const CGRect& viewRect, const CGRect& btnRect, const cocos2d::EditBox::ShowInfo& showInfo)
|
||||
{
|
||||
if (!g_textView)
|
||||
{
|
||||
g_textView = [[UITextView alloc] initWithFrame:btnRect];
|
||||
g_textView.textColor = [UIColor blackColor];
|
||||
g_textView.backgroundColor = [UIColor whiteColor];
|
||||
g_textViewDelegate = [[TextViewDelegate alloc] init];
|
||||
g_textView.delegate = g_textViewDelegate;
|
||||
|
||||
createButton(&g_textViewConfirmButton, &g_textViewConfirmButtonHander, btnRect, showInfo.confirmType);
|
||||
g_textViewConfirmButton.frame = CGRectMake(viewRect.size.width - BUTTON_WIDTH, 0, BUTTON_WIDTH, BUTTON_HIGHT);
|
||||
[g_textView addSubview:g_textViewConfirmButton];
|
||||
}
|
||||
|
||||
g_textView.frame = btnRect;
|
||||
g_textView.text = [NSString stringWithUTF8String: showInfo.defaultValue.c_str()];
|
||||
[g_textViewConfirmButton setTitle:getConfirmButtonTitle(showInfo.confirmType) forState:UIControlStateNormal];
|
||||
}
|
||||
|
||||
CGRect getSafeAreaRect()
|
||||
{
|
||||
UIView* view = (UIView*)cocos2d::Application::getInstance()->getView();
|
||||
CGRect viewRect = view.frame;
|
||||
|
||||
// safeAreaInsets is avaible since iOS 11.
|
||||
if (@available(iOS 11.0, *))
|
||||
{
|
||||
auto safeAreaInsets = view.safeAreaInsets;
|
||||
|
||||
UIInterfaceOrientation sataus = [UIApplication sharedApplication].statusBarOrientation;
|
||||
if (UIInterfaceOrientationLandscapeLeft == sataus) {
|
||||
viewRect.origin.x = 0;
|
||||
viewRect.size.width -= safeAreaInsets.right;
|
||||
}
|
||||
else {
|
||||
viewRect.origin.x += safeAreaInsets.left;
|
||||
viewRect.size.width -= safeAreaInsets.left;
|
||||
}
|
||||
}
|
||||
|
||||
return viewRect;
|
||||
}
|
||||
|
||||
void addTextInput(const cocos2d::EditBox::ShowInfo& showInfo)
|
||||
{
|
||||
auto safeAreaRect = getSafeAreaRect();
|
||||
int height = getTextInputHeight();
|
||||
CGRect rect = CGRectMake(safeAreaRect.origin.x,
|
||||
safeAreaRect.size.height - height,
|
||||
safeAreaRect.size.width,
|
||||
height);
|
||||
if (showInfo.isMultiline)
|
||||
initTextView(safeAreaRect, rect, showInfo);
|
||||
else
|
||||
initTextField(rect, showInfo);
|
||||
|
||||
UIView* textInput = getCurrentView();
|
||||
UIView* view = (UIView*)cocos2d::Application::getInstance()->getView();
|
||||
[view addSubview:textInput];
|
||||
[textInput becomeFirstResponder];
|
||||
}
|
||||
|
||||
void addKeyboardEventLisnters()
|
||||
{
|
||||
if (!g_keyboardHandler)
|
||||
g_keyboardHandler = [[KeyboardEventHandler alloc] init];
|
||||
|
||||
[[NSNotificationCenter defaultCenter] addObserver:g_keyboardHandler
|
||||
selector:@selector(keyboardWillShow:)
|
||||
name:UIKeyboardWillShowNotification
|
||||
object:nil];
|
||||
|
||||
[[NSNotificationCenter defaultCenter] addObserver:g_keyboardHandler
|
||||
selector:@selector(keyboardWillHide:)
|
||||
name:UIKeyboardWillHideNotification
|
||||
object:nil];
|
||||
}
|
||||
|
||||
void removeKeyboardEventLisnters()
|
||||
{
|
||||
if (!g_keyboardHandler)
|
||||
return;
|
||||
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:g_keyboardHandler];
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
Class implementations.
|
||||
************************************************************************/
|
||||
|
||||
// MARK: class implementation
|
||||
|
||||
@implementation KeyboardEventHandler
|
||||
-(void)keyboardWillShow: (NSNotification*) notification
|
||||
{
|
||||
UIView* textView = getCurrentView();
|
||||
if (!textView)
|
||||
return;
|
||||
|
||||
NSDictionary* keyboardInfo = [notification userInfo];
|
||||
NSValue* keyboardFrame = [keyboardInfo objectForKey:UIKeyboardFrameEndUserInfoKey];
|
||||
CGSize kbSize = [keyboardFrame CGRectValue].size;
|
||||
|
||||
int textHeight = getTextInputHeight();
|
||||
|
||||
CGRect screenRect = getSafeAreaRect();
|
||||
textView.frame = CGRectMake(screenRect.origin.x,
|
||||
screenRect.size.height - textHeight - kbSize.height,
|
||||
screenRect.size.width,
|
||||
textHeight);
|
||||
}
|
||||
|
||||
-(void)keyboardWillHide: (NSNotification*) notification
|
||||
{
|
||||
NSDictionary *info = [notification userInfo];
|
||||
|
||||
CGRect beginKeyboardRect = [[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue];
|
||||
CGRect endKeyboardRect = [[info objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue];
|
||||
CGFloat yOffset = endKeyboardRect.origin.y - beginKeyboardRect.origin.y;
|
||||
|
||||
if (yOffset <= 0) {
|
||||
cocos2d::EditBox::complete();
|
||||
cocos2d::EditBox::hide();
|
||||
}
|
||||
}
|
||||
@end
|
||||
|
||||
@implementation TextFieldDelegate
|
||||
- (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];
|
||||
auto newText = [textField.text substringToIndex:rangeIndex.location];
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
textField.text = newText;
|
||||
});
|
||||
}
|
||||
|
||||
callJSFunc("input", [textField.text UTF8String]);
|
||||
}
|
||||
|
||||
-(BOOL) textFieldShouldReturn:(UITextField *)textField
|
||||
{
|
||||
cocos2d::EditBox::complete();
|
||||
return YES;
|
||||
}
|
||||
@end
|
||||
|
||||
@implementation ButtonHandler
|
||||
-(IBAction) buttonTapped:(UIButton *)button
|
||||
{
|
||||
const std::string text([getCurrentText() UTF8String]);
|
||||
callJSFunc("confirm", text);
|
||||
if (!g_confirmHold)
|
||||
cocos2d::EditBox::complete();
|
||||
}
|
||||
@end
|
||||
|
||||
|
||||
@implementation TextViewDelegate
|
||||
- (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) {
|
||||
auto newText = [textView.text substringToIndex:g_maxLength];
|
||||
// fix undo crash
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
textView.text = newText;
|
||||
});
|
||||
}
|
||||
|
||||
callJSFunc("input", [textView.text UTF8String]);
|
||||
}
|
||||
@end
|
||||
|
||||
/*************************************************************************
|
||||
Implementation of EditBox.
|
||||
************************************************************************/
|
||||
|
||||
// MARK: EditBox
|
||||
|
||||
NS_CC_BEGIN
|
||||
|
||||
void EditBox::show(const cocos2d::EditBox::ShowInfo& showInfo)
|
||||
{
|
||||
// Should initialize them at first.
|
||||
g_maxLength = showInfo.maxLength;
|
||||
g_isMultiline = showInfo.isMultiline;
|
||||
g_confirmHold = showInfo.confirmHold;
|
||||
|
||||
[(CCEAGLView*)cocos2d::Application::getInstance()->getView() setPreventTouchEvent:true];
|
||||
addKeyboardEventLisnters();
|
||||
addTextInput(showInfo);
|
||||
}
|
||||
|
||||
void EditBox::hide()
|
||||
{
|
||||
removeKeyboardEventLisnters();
|
||||
|
||||
UIView* view = getCurrentView();
|
||||
if (view)
|
||||
{
|
||||
[view removeFromSuperview];
|
||||
[view resignFirstResponder];
|
||||
}
|
||||
|
||||
[(CCEAGLView*)cocos2d::Application::getInstance()->getView() setPreventTouchEvent:false];
|
||||
}
|
||||
|
||||
void EditBox::updateRect(int x, int y, int width, int height)
|
||||
{
|
||||
// not supported ...
|
||||
}
|
||||
|
||||
void EditBox::complete()
|
||||
{
|
||||
NSString* text = getCurrentText();
|
||||
callJSFunc("complete", [text UTF8String]);
|
||||
EditBox::hide();
|
||||
}
|
||||
|
||||
NS_CC_END
|
340
cocos2d-x/cocos/ui/edit-box/EditBox-mac.mm
Normal file
340
cocos2d-x/cocos/ui/edit-box/EditBox-mac.mm
Normal file
@@ -0,0 +1,340 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2018 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos2d-x.org
|
||||
|
||||
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 "platform/desktop/CCGLView-desktop.h"
|
||||
#include "platform/CCApplication.h"
|
||||
#include "cocos/scripting/js-bindings/jswrapper/SeApi.h"
|
||||
#include "cocos/scripting/js-bindings/manual/jsb_global.h"
|
||||
|
||||
/*************************************************************************
|
||||
Forward declaration of global functions.
|
||||
************************************************************************/
|
||||
namespace
|
||||
{
|
||||
void callJSFunc(const std::string& type, const std::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;
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
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;
|
||||
}
|
||||
@end
|
||||
|
||||
/*************************************************************************
|
||||
TextFieldDelegate
|
||||
************************************************************************/
|
||||
@interface TextFieldDelegate: NSObject<NSTextFieldDelegate>
|
||||
@end
|
||||
|
||||
@implementation TextFieldDelegate
|
||||
- (void)controlTextDidChange:(NSNotification *)notification
|
||||
{
|
||||
NSTextField *textField = [notification object];
|
||||
callJSFunc("input", [textField.stringValue UTF8String]);
|
||||
}
|
||||
@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
|
||||
{
|
||||
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 std::string& type, const std::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 cocos2d::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;
|
||||
|
||||
auto glfwWindow = ((cocos2d::GLView*)cocos2d::Application::getInstance()->getView())->getGLFWWindow();
|
||||
NSWindow* nsWindow = glfwGetCocoaWindow(glfwWindow);
|
||||
[nsWindow.contentView addSubview:g_scrollView];
|
||||
[nsWindow makeFirstResponder:g_scrollView];
|
||||
}
|
||||
|
||||
void doInitTextField(NSTextField* textField, const CGRect& rect, const cocos2d::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];
|
||||
|
||||
auto glfwWindow = ((cocos2d::GLView*)cocos2d::Application::getInstance()->getView())->getGLFWWindow();
|
||||
NSWindow* nsWindow = glfwGetCocoaWindow(glfwWindow);
|
||||
[nsWindow.contentView addSubview:textField];
|
||||
[textField becomeFirstResponder];
|
||||
}
|
||||
|
||||
void initTextField(const cocos2d::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 cocos2d::EditBox::ShowInfo& showInfo)
|
||||
{
|
||||
if (showInfo.isMultiline)
|
||||
initTextView(showInfo);
|
||||
else
|
||||
initTextField(showInfo);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
Implementation of EditBox.
|
||||
************************************************************************/
|
||||
|
||||
NS_CC_BEGIN
|
||||
|
||||
void EditBox::show(const ShowInfo& showInfo)
|
||||
{
|
||||
g_isMultiline = showInfo.isMultiline;
|
||||
g_maxLength = showInfo.maxLength;
|
||||
g_isPassword = showInfo.inputType == "password";
|
||||
|
||||
init(showInfo);
|
||||
((GLView*)Application::getInstance()->getView())->setIsEditboxEditing(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];
|
||||
}
|
||||
|
||||
((GLView*)Application::getInstance()->getView())->setIsEditboxEditing(false);
|
||||
}
|
||||
|
||||
void EditBox::complete()
|
||||
{
|
||||
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();
|
||||
}
|
||||
|
||||
void EditBox::updateRect(int x, int y, int width, int height) {
|
||||
CGRect rect = CGRectMake(x, y, width, height);
|
||||
auto glfwWindow = ((cocos2d::GLView*)cocos2d::Application::getInstance()->getView())->getGLFWWindow();
|
||||
NSWindow* nsWindow = glfwGetCocoaWindow(glfwWindow);
|
||||
const auto& subviews = [nsWindow.contentView subviews];
|
||||
if (g_scrollView && [subviews containsObject:g_scrollView])
|
||||
{
|
||||
g_scrollView.frame = rect;
|
||||
if (g_textView)
|
||||
{
|
||||
g_textView.frame = rect;
|
||||
}
|
||||
}
|
||||
else if (g_textField && [subviews containsObject:g_textField])
|
||||
{
|
||||
g_textField.frame = rect;
|
||||
}
|
||||
else if (g_secureTextField && [subviews containsObject:g_secureTextField])
|
||||
{
|
||||
g_secureTextField.frame = rect;
|
||||
}
|
||||
}
|
||||
|
||||
NS_CC_END
|
220
cocos2d-x/cocos/ui/edit-box/EditBox-win32.cpp
Normal file
220
cocos2d-x/cocos/ui/edit-box/EditBox-win32.cpp
Normal file
@@ -0,0 +1,220 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2018 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos2d-x.org
|
||||
|
||||
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 "platform/CCApplication.h"
|
||||
#include "platform/desktop/CCGLView-desktop.h"
|
||||
#include "cocos/scripting/js-bindings/jswrapper/SeApi.h"
|
||||
#include "cocos/scripting/js-bindings/manual/jsb_global.h"
|
||||
#include <windows.h>
|
||||
#include <locale>
|
||||
#include <codecvt>
|
||||
#include <stdlib.h>
|
||||
|
||||
NS_CC_BEGIN
|
||||
|
||||
/*************************************************************************
|
||||
Global variables and functions.
|
||||
************************************************************************/
|
||||
|
||||
namespace
|
||||
{
|
||||
HWND g_hwndEditBox = nullptr;
|
||||
WNDPROC g_prevMainWindowProc = nullptr;
|
||||
se::Value g_textInputCallback;
|
||||
|
||||
HWND getCocosWindow()
|
||||
{
|
||||
auto glfwWindow = ((GLView*)Application::getInstance()->getView())->getGLFWWindow();
|
||||
return glfwGetWin32Window(glfwWindow);
|
||||
}
|
||||
|
||||
int getCocosWindowHeight()
|
||||
{
|
||||
HWND parent = getCocosWindow();
|
||||
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 std::string& type, const std::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);
|
||||
}
|
||||
|
||||
std::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;
|
||||
std::string ret(convert.to_bytes(str));
|
||||
free(str);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::wstring str2ws(const std::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(getCocosWindow());
|
||||
break;
|
||||
case WM_COMMAND:
|
||||
if (EN_CHANGE == HIWORD(wParam))
|
||||
callJSFunc("input", getText(g_hwndEditBox).c_str());
|
||||
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return CallWindowProc(g_prevMainWindowProc, hwnd, msg, wParam, lParam);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
Implementation of EditBox.
|
||||
************************************************************************/
|
||||
void EditBox::show(const EditBox::ShowInfo& showInfo)
|
||||
{
|
||||
int windowHeight = getCocosWindowHeight();
|
||||
if (! g_hwndEditBox)
|
||||
{
|
||||
HWND parent = getCocosWindow();
|
||||
g_prevMainWindowProc = (WNDPROC)SetWindowLongPtr(parent, GWL_WNDPROC, (LONG_PTR)mainWindowProc);
|
||||
|
||||
UINT32 flags = WS_CHILD | ES_LEFT | WS_TABSTOP | ES_AUTOHSCROLL;
|
||||
if (showInfo.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);
|
||||
|
||||
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;
|
||||
CCLOG("Can not create editbox: %s", convert.to_bytes(buffer).c_str());
|
||||
}
|
||||
}
|
||||
|
||||
::SendMessageW(g_hwndEditBox, EM_LIMITTEXT, showInfo.maxLength, 0);
|
||||
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());
|
||||
::PostMessage(g_hwndEditBox, WM_ACTIVATE, 0, 0);
|
||||
::ShowWindow(g_hwndEditBox, SW_SHOW);
|
||||
SetFocus(g_hwndEditBox);
|
||||
}
|
||||
|
||||
void EditBox::hide()
|
||||
{
|
||||
DestroyWindow(g_hwndEditBox);
|
||||
g_hwndEditBox = nullptr;
|
||||
|
||||
SetWindowLongPtr(getCocosWindow(), GWL_WNDPROC, (LONG_PTR)g_prevMainWindowProc);
|
||||
}
|
||||
|
||||
void EditBox::updateRect(int x, int y, int width, int height)
|
||||
{
|
||||
int windowHeight = getCocosWindowHeight();
|
||||
SetWindowPos(g_hwndEditBox,
|
||||
HWND_NOTOPMOST,
|
||||
x,
|
||||
windowHeight - y - height,
|
||||
width,
|
||||
height,
|
||||
SWP_NOZORDER);
|
||||
}
|
||||
|
||||
void EditBox::complete()
|
||||
{
|
||||
callJSFunc("complete", getText(g_hwndEditBox).c_str());
|
||||
}
|
||||
|
||||
NS_CC_END
|
57
cocos2d-x/cocos/ui/edit-box/EditBox.h
Normal file
57
cocos2d-x/cocos/ui/edit-box/EditBox.h
Normal file
@@ -0,0 +1,57 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2018 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos2d-x.org
|
||||
|
||||
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 <string>
|
||||
#include "base/ccMacros.h"
|
||||
|
||||
NS_CC_BEGIN
|
||||
|
||||
class EditBox
|
||||
{
|
||||
public:
|
||||
struct ShowInfo
|
||||
{
|
||||
std::string defaultValue = "";
|
||||
std::string confirmType = "";
|
||||
std::string inputType = "";
|
||||
int maxLength = 0;
|
||||
int x = 0;
|
||||
int y = 0;
|
||||
int width = 0;
|
||||
int height = 0;
|
||||
bool confirmHold = false;
|
||||
bool isMultiline = false;
|
||||
};
|
||||
|
||||
static void show(const ShowInfo& showInfo);
|
||||
static void hide();
|
||||
static void updateRect(int x, int y, int width, int height);
|
||||
|
||||
// It is internally to send a complete message to JS.
|
||||
// Don't call it by yourself untile you know the effect.
|
||||
static void complete();
|
||||
};
|
||||
|
||||
NS_CC_END
|
296
cocos2d-x/cocos/ui/videoplayer/VideoPlayer-android.cpp
Normal file
296
cocos2d-x/cocos/ui/videoplayer/VideoPlayer-android.cpp
Normal file
@@ -0,0 +1,296 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2014 Chukong Technologies Inc.
|
||||
|
||||
http://www.cocos2d-x.org
|
||||
|
||||
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 "VideoPlayer.h"
|
||||
#include "base/CCLog.h"
|
||||
|
||||
#if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID)
|
||||
#include <unordered_map>
|
||||
#include <stdlib.h>
|
||||
#include <jni.h>
|
||||
#include <string>
|
||||
#include "platform/CCApplication.h"
|
||||
#include "platform/android/jni/JniHelper.h"
|
||||
#include "platform/CCFileUtils.h"
|
||||
#include "renderer/gfx/Texture2D.h"
|
||||
|
||||
//-----------------------------------------------------------------------------------------------------------
|
||||
|
||||
static const std::string videoHelperClassName = "org/cocos2dx/lib/Cocos2dxVideoHelper";
|
||||
|
||||
USING_NS_CC;
|
||||
|
||||
static void executeVideoCallback(int index,int event);
|
||||
|
||||
#define QUIT_FULLSCREEN 1000
|
||||
|
||||
extern "C" {
|
||||
void Java_org_cocos2dx_lib_Cocos2dxVideoHelper_nativeExecuteVideoCallback(JNIEnv * env, jobject obj, jint index,jint event) {
|
||||
executeVideoCallback(index,event);
|
||||
}
|
||||
}
|
||||
|
||||
int createVideoWidgetJNI()
|
||||
{
|
||||
JniMethodInfo t;
|
||||
int ret = -1;
|
||||
if (JniHelper::getStaticMethodInfo(t, videoHelperClassName.c_str(), "createVideoWidget", "()I")) {
|
||||
ret = t.env->CallStaticIntMethod(t.classID, t.methodID);
|
||||
|
||||
t.env->DeleteLocalRef(t.classID);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------------------------------------
|
||||
|
||||
static std::unordered_map<int, VideoPlayer*> s_allVideoPlayers;
|
||||
static jobject s_jobj = nullptr;
|
||||
|
||||
VideoPlayer::VideoPlayer()
|
||||
: _videoPlayerIndex(-1)
|
||||
, _fullScreenEnabled(false)
|
||||
, _fullScreenDirty(false)
|
||||
, _keepAspectRatioEnabled(false)
|
||||
, _videoPixels(nullptr)
|
||||
, _texDataSize(0)
|
||||
, _maxDataLen(0)
|
||||
{
|
||||
_videoPlayerIndex = createVideoWidgetJNI();
|
||||
s_allVideoPlayers[_videoPlayerIndex] = this;
|
||||
|
||||
#if CC_VIDEOPLAYER_DEBUG_DRAW
|
||||
_debugDrawNode = DrawNode::create();
|
||||
addChild(_debugDrawNode);
|
||||
#endif
|
||||
|
||||
if(s_jobj == nullptr) {
|
||||
s_jobj = JniHelper::getEnv()->NewGlobalRef(JniHelper::newObject(videoHelperClassName.c_str()));
|
||||
}
|
||||
}
|
||||
|
||||
VideoPlayer::~VideoPlayer()
|
||||
{
|
||||
s_allVideoPlayers.erase(_videoPlayerIndex);
|
||||
JniHelper::callStaticVoidMethod(videoHelperClassName, "removeVideoWidget", _videoPlayerIndex);
|
||||
|
||||
if (_videoPixels != nullptr) free(_videoPixels);
|
||||
}
|
||||
|
||||
void VideoPlayer::setURL(const std::string& videoUrl)
|
||||
{
|
||||
if (videoUrl.find("://") == std::string::npos)
|
||||
{
|
||||
_videoURL = FileUtils::getInstance()->fullPathForFilename(videoUrl);
|
||||
_videoSource = VideoPlayer::Source::FILENAME;
|
||||
}
|
||||
else
|
||||
{
|
||||
_videoURL = videoUrl;
|
||||
_videoSource = VideoPlayer::Source::URL;
|
||||
}
|
||||
|
||||
JniHelper::callStaticVoidMethod(videoHelperClassName, "setVideoUrl", _videoPlayerIndex,
|
||||
(int)_videoSource,_videoURL);
|
||||
}
|
||||
|
||||
void VideoPlayer::VideoPlayer::setFrame(float x, float y, float width, float height)
|
||||
{
|
||||
JniHelper::callStaticVoidMethod(videoHelperClassName, "setVideoRect", _videoPlayerIndex,
|
||||
(int)x, (int)y, (int)width, (int)height);
|
||||
}
|
||||
|
||||
void VideoPlayer::setFullScreenEnabled(bool enabled)
|
||||
{
|
||||
if (_fullScreenEnabled != enabled)
|
||||
{
|
||||
_fullScreenEnabled = enabled;
|
||||
JniHelper::callStaticVoidMethod(videoHelperClassName, "setFullScreenEnabled", _videoPlayerIndex, enabled);
|
||||
}
|
||||
}
|
||||
|
||||
void VideoPlayer::setKeepAspectRatioEnabled(bool enable)
|
||||
{
|
||||
if (_keepAspectRatioEnabled != enable)
|
||||
{
|
||||
_keepAspectRatioEnabled = enable;
|
||||
JniHelper::callStaticVoidMethod(videoHelperClassName, "setVideoKeepRatioEnabled", _videoPlayerIndex, enable);
|
||||
}
|
||||
}
|
||||
|
||||
void VideoPlayer::play()
|
||||
{
|
||||
if (! _videoURL.empty())
|
||||
{
|
||||
JniHelper::callStaticVoidMethod(videoHelperClassName, "startVideo", _videoPlayerIndex);
|
||||
}
|
||||
}
|
||||
|
||||
void VideoPlayer::pause()
|
||||
{
|
||||
if (! _videoURL.empty())
|
||||
{
|
||||
JniHelper::callStaticVoidMethod(videoHelperClassName, "pauseVideo", _videoPlayerIndex);
|
||||
}
|
||||
}
|
||||
|
||||
void VideoPlayer::stop()
|
||||
{
|
||||
if (! _videoURL.empty())
|
||||
{
|
||||
JniHelper::callStaticVoidMethod(videoHelperClassName, "stopVideo", _videoPlayerIndex);
|
||||
}
|
||||
}
|
||||
|
||||
void VideoPlayer::seekTo(float sec)
|
||||
{
|
||||
if (! _videoURL.empty())
|
||||
{
|
||||
JniHelper::callStaticVoidMethod(videoHelperClassName, "seekVideoTo", _videoPlayerIndex, int(sec * 1000));
|
||||
}
|
||||
}
|
||||
|
||||
void VideoPlayer::setVisible(bool visible)
|
||||
{
|
||||
JniHelper::callStaticVoidMethod(videoHelperClassName, "setVideoVisible", _videoPlayerIndex, visible);
|
||||
}
|
||||
|
||||
void VideoPlayer::addEventListener(const std::string& name, const VideoPlayer::ccVideoPlayerCallback& callback)
|
||||
{
|
||||
_eventCallback[name] = callback;
|
||||
}
|
||||
|
||||
void VideoPlayer::onPlayEvent(int event)
|
||||
{
|
||||
if (event == QUIT_FULLSCREEN)
|
||||
{
|
||||
_fullScreenEnabled = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
VideoPlayer::EventType videoEvent = (VideoPlayer::EventType)event;
|
||||
|
||||
|
||||
switch (videoEvent) {
|
||||
case EventType::PLAYING:
|
||||
_eventCallback["play"]();
|
||||
break;
|
||||
case EventType::PAUSED:
|
||||
_eventCallback["pause"]();
|
||||
break;
|
||||
case EventType::STOPPED:
|
||||
_eventCallback["stoped"]();
|
||||
break;
|
||||
case EventType::COMPLETED:
|
||||
_eventCallback["ended"]();
|
||||
break;
|
||||
case EventType::META_LOADED:
|
||||
_eventCallback["loadedmetadata"]();
|
||||
break;
|
||||
case EventType::CLICKED:
|
||||
_eventCallback["click"]();
|
||||
break;
|
||||
case EventType::READY_TO_PLAY:
|
||||
_eventCallback["suspend"]();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void executeVideoCallback(int index,int event)
|
||||
{
|
||||
auto it = s_allVideoPlayers.find(index);
|
||||
if (it != s_allVideoPlayers.end())
|
||||
{
|
||||
s_allVideoPlayers[index]->onPlayEvent(event);
|
||||
}
|
||||
}
|
||||
|
||||
float VideoPlayer::currentTime() const
|
||||
{
|
||||
return JniHelper::callStaticFloatMethod(videoHelperClassName, "getCurrentTime", _videoPlayerIndex);
|
||||
}
|
||||
|
||||
float VideoPlayer::duration() const
|
||||
{
|
||||
return JniHelper::callStaticFloatMethod(videoHelperClassName, "getDuration", _videoPlayerIndex);
|
||||
}
|
||||
|
||||
void VideoPlayer::getFrame() {
|
||||
jbyteArray arr = JniHelper::callObjectByteArrayMethod(s_jobj, videoHelperClassName, "getFrame", _videoPlayerIndex);
|
||||
if (arr == nullptr) return;
|
||||
jsize len = JniHelper::getEnv()->GetArrayLength(arr);
|
||||
if (len == 0) return;
|
||||
_texDataSize = len;
|
||||
if (len > _maxDataLen) {
|
||||
_maxDataLen = len;
|
||||
|
||||
if(_videoPixels != nullptr) free(_videoPixels);
|
||||
_videoPixels = (unsigned char*)malloc(len * sizeof(unsigned char));
|
||||
}
|
||||
|
||||
JniHelper::getEnv()->GetByteArrayRegion(arr, 0, len, reinterpret_cast<jbyte*>(_videoPixels));
|
||||
JniHelper::getEnv()->DeleteLocalRef(arr);
|
||||
}
|
||||
|
||||
int VideoPlayer::getFrameChannel() const {
|
||||
return (int)JniHelper::callObjectFloatMethod(s_jobj, videoHelperClassName, "getFrameChannel", _videoPlayerIndex);
|
||||
}
|
||||
|
||||
int VideoPlayer::getFrameWidth() const {
|
||||
return (int)JniHelper::callObjectFloatMethod(s_jobj, videoHelperClassName, "getFrameWidth", _videoPlayerIndex);
|
||||
}
|
||||
|
||||
int VideoPlayer::getFrameHeight() const {
|
||||
return (int)JniHelper::callObjectFloatMethod(s_jobj, videoHelperClassName, "getFrameHeight", _videoPlayerIndex);
|
||||
}
|
||||
|
||||
int VideoPlayer::getVideoTexDataSize() const {
|
||||
return _texDataSize;
|
||||
}
|
||||
|
||||
void VideoPlayer::pushFrameDataToTexture2D(cocos2d::renderer::Texture* tex) const {
|
||||
if(tex == nullptr) log("Can't find texture!");
|
||||
else {
|
||||
if(_videoPixels != nullptr && getFrameWidth() > 0 && getFrameHeight() > 0) {
|
||||
renderer::Texture::SubImageOption opt(0, 0, getFrameWidth(), getFrameHeight(), 0, false,
|
||||
false);
|
||||
opt.imageData = _videoPixels;
|
||||
((cocos2d::renderer::Texture2D*)tex)->updateSubImage(opt);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void VideoPlayer::setShowRawFrame(bool show) const {
|
||||
JniHelper::callObjectVoidMethod(s_jobj, videoHelperClassName, "setShowRawFrame", _videoPlayerIndex, show);
|
||||
}
|
||||
|
||||
void VideoPlayer::update() {
|
||||
//test
|
||||
}
|
||||
|
||||
#endif
|
631
cocos2d-x/cocos/ui/videoplayer/VideoPlayer-ios.mm
Normal file
631
cocos2d-x/cocos/ui/videoplayer/VideoPlayer-ios.mm
Normal file
@@ -0,0 +1,631 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2014-2016 Chukong Technologies Inc.
|
||||
|
||||
http://www.cocos2d-x.org
|
||||
|
||||
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 "VideoPlayer.h"
|
||||
|
||||
USING_NS_CC;
|
||||
|
||||
// No Available on tvOS
|
||||
#if CC_TARGET_PLATFORM == CC_PLATFORM_IOS && !defined(CC_TARGET_OS_TVOS)
|
||||
|
||||
//-------------------------------------------------------------------------------------
|
||||
|
||||
#import <AVKit/AVPlayerViewController.h>
|
||||
#import <CoreMedia/CMTime.h>
|
||||
#import <CoreVideo/CVPixelBuffer.h>
|
||||
|
||||
#include "platform/CCApplication.h"
|
||||
#include "platform/ios/CCEAGLView-ios.h"
|
||||
#include "platform/CCFileUtils.h"
|
||||
#include "renderer/gfx/Texture2D.h"
|
||||
|
||||
@interface UIVideoViewWrapperIos : NSObject
|
||||
|
||||
typedef NS_ENUM(NSInteger, PlayerbackState) {
|
||||
PlayerbackStateUnknown = 0,
|
||||
PlayerbackStatePaused,
|
||||
PlayerbackStopped,
|
||||
PlayerbackStatePlaying,
|
||||
PlayerbackStateCompleted
|
||||
};
|
||||
|
||||
@property (assign, nonatomic) AVPlayerViewController * playerController;
|
||||
|
||||
- (void) setFrame:(int) left :(int) top :(int) width :(int) height;
|
||||
- (void) setURL:(int) videoSource :(std::string&) videoUrl;
|
||||
- (void) play;
|
||||
- (void) pause;
|
||||
- (void) resume;
|
||||
- (void) stop;
|
||||
- (BOOL) isPlaying;
|
||||
- (void) seekTo:(float) sec;
|
||||
- (float) currentTime;
|
||||
- (float) duration;
|
||||
- (void) setVisible:(BOOL) visible;
|
||||
- (void) setKeepRatioEnabled:(BOOL) enabled;
|
||||
- (void) setFullScreenEnabled:(BOOL) enabled;
|
||||
- (void) showPlaybackControls:(BOOL) value;
|
||||
- (BOOL) isFullScreenEnabled;
|
||||
- (void) cleanup;
|
||||
-(id) init:(void*) videoPlayer;
|
||||
|
||||
- (unsigned char*) getFrame;
|
||||
- (bool) copyFinished;
|
||||
- (int) getFrameWidth;
|
||||
- (int) getFrameHeight;
|
||||
- (int) getFrameDataSize;
|
||||
- (int) getBitCount;
|
||||
- (void) setShowRaw:(BOOL) show;
|
||||
- (void) clearBuffers;
|
||||
|
||||
-(void) videoFinished:(NSNotification*) notification;
|
||||
|
||||
@end
|
||||
|
||||
@implementation UIVideoViewWrapperIos
|
||||
{
|
||||
int _left;
|
||||
int _top;
|
||||
int _width;
|
||||
int _height;
|
||||
bool _keepRatioEnabled;
|
||||
bool _fullscreen;
|
||||
CGRect _restoreRect;
|
||||
PlayerbackState _state;
|
||||
VideoPlayer* _videoPlayer;
|
||||
|
||||
int _frameWidth;
|
||||
int _frameHeight;
|
||||
int _frameDataSize;
|
||||
int _frameBitCount;
|
||||
unsigned char* _videoPixels;
|
||||
bool _finishCopy;
|
||||
}
|
||||
|
||||
-(id)init:(void*)videoPlayer
|
||||
{
|
||||
if (self = [super init]) {
|
||||
_keepRatioEnabled = FALSE;
|
||||
_left = _top = _width = _height = 0;
|
||||
|
||||
[self initPlayerController];
|
||||
_videoPlayer = (VideoPlayer*)videoPlayer;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
-(void)initPlayerController
|
||||
{
|
||||
self.playerController = [AVPlayerViewController new];
|
||||
[self setFrame:_left :_top :_width :_height];
|
||||
[self showPlaybackControls:TRUE];
|
||||
[self setKeepRatioEnabled:_keepRatioEnabled];
|
||||
_state = PlayerbackStateUnknown;
|
||||
|
||||
_frameWidth = 0;
|
||||
_frameHeight = 0;
|
||||
_frameDataSize = 0;
|
||||
_frameBitCount = 1;
|
||||
_videoPixels = nullptr;
|
||||
_finishCopy = false;
|
||||
|
||||
[self setShowRaw:YES];
|
||||
}
|
||||
|
||||
-(void) dealloc
|
||||
{
|
||||
if(_videoPixels != nullptr) free(_videoPixels);
|
||||
|
||||
_videoPlayer = nullptr;
|
||||
[self cleanup];
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
-(void) setFrame:(int)left :(int)top :(int)width :(int)height
|
||||
{
|
||||
if (_left == left && _width == width && _top == top && _height == height)
|
||||
return;
|
||||
|
||||
_left = left;
|
||||
_width = width;
|
||||
_top = top;
|
||||
_height = height;
|
||||
[self.playerController.view setFrame:CGRectMake(left, top, width, height)];
|
||||
}
|
||||
|
||||
-(unsigned char*) getFrame
|
||||
{
|
||||
UInt32 type = kCVPixelFormatType_32BGRA;
|
||||
AVPlayerItem* item = self.playerController.player.currentItem;
|
||||
if(item.outputs.count == 0) {
|
||||
NSDictionary* settings = @{ (id)kCVPixelBufferPixelFormatTypeKey : @(type) };
|
||||
AVPlayerItemVideoOutput* output = [[AVPlayerItemVideoOutput alloc] initWithPixelBufferAttributes:settings];
|
||||
[item addOutput:output];
|
||||
}
|
||||
AVPlayerItemOutput* output = item.outputs[0];
|
||||
|
||||
CMTime time = self.playerController.player.currentTime;
|
||||
CVPixelBufferRef pixelBuffer = [output copyPixelBufferForItemTime:time itemTimeForDisplay:nil];
|
||||
|
||||
_frameBitCount = 4;
|
||||
_frameHeight = (int)CVPixelBufferGetHeight(pixelBuffer);
|
||||
_frameWidth = (int)CVPixelBufferGetBytesPerRow(pixelBuffer) / _frameBitCount;
|
||||
_frameDataSize = (int)CVPixelBufferGetDataSize(pixelBuffer);
|
||||
|
||||
if(_videoPixels == nullptr && _frameWidth > 0 && _frameHeight > 0) {
|
||||
_videoPixels = (unsigned char*)calloc(_frameDataSize, 1);
|
||||
}
|
||||
|
||||
CVPixelBufferLockBaseAddress(pixelBuffer, 0);
|
||||
void* pixels = CVPixelBufferGetBaseAddress(pixelBuffer);
|
||||
if(_videoPixels != nullptr && pixels != nullptr) {
|
||||
memcpy(_videoPixels, pixels, _frameDataSize);
|
||||
_finishCopy = true;
|
||||
}
|
||||
CVPixelBufferUnlockBaseAddress(pixelBuffer, 0);
|
||||
|
||||
return _videoPixels;
|
||||
}
|
||||
|
||||
-(bool) copyFinished
|
||||
{
|
||||
return _finishCopy;
|
||||
}
|
||||
|
||||
-(int) getFrameWidth
|
||||
{
|
||||
return _frameWidth;
|
||||
}
|
||||
|
||||
-(int) getFrameHeight
|
||||
{
|
||||
return _frameHeight;
|
||||
}
|
||||
|
||||
-(int) getFrameDataSize
|
||||
{
|
||||
return _frameDataSize;
|
||||
}
|
||||
|
||||
-(int) getBitCount
|
||||
{
|
||||
return _frameBitCount;
|
||||
}
|
||||
|
||||
-(void) setShowRaw:(BOOL) show
|
||||
{
|
||||
if(show == YES) {
|
||||
self.playerController.view.alpha = 1;
|
||||
} else {
|
||||
self.playerController.view.alpha = 0;
|
||||
}
|
||||
}
|
||||
|
||||
-(void) setFullScreenEnabled:(BOOL) enabled
|
||||
{
|
||||
// AVPlayerViewController doesn't provide API to enable fullscreen. But you can toggle
|
||||
// fullsreen by the playback controllers.
|
||||
}
|
||||
|
||||
-(BOOL) isFullScreenEnabled
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
-(BOOL) isPlaying
|
||||
{
|
||||
return (self.playerController.player && self.playerController.player.rate != 0);
|
||||
}
|
||||
|
||||
-(void) setURL:(int)videoSource :(std::string &)videoUrl
|
||||
{
|
||||
[self clearBuffers];
|
||||
[self cleanup];
|
||||
[self initPlayerController];
|
||||
|
||||
if (videoSource == 1)
|
||||
self.playerController.player = [[[AVPlayer alloc] initWithURL:[NSURL URLWithString:@(videoUrl.c_str())]] autorelease];
|
||||
else
|
||||
self.playerController.player = [[[AVPlayer alloc] initWithURL:[NSURL fileURLWithPath:@(videoUrl.c_str())]] autorelease];
|
||||
|
||||
[self registerPlayerEventListener];
|
||||
}
|
||||
|
||||
-(void) seekTo:(float)sec
|
||||
{
|
||||
if (self.playerController.player)
|
||||
[self.playerController.player seekToTime:CMTimeMake(sec * 600, 600) toleranceBefore:kCMTimeZero toleranceAfter:kCMTimeZero];
|
||||
|
||||
}
|
||||
|
||||
-(float) currentTime
|
||||
{
|
||||
if (self.playerController.player)
|
||||
return CMTimeGetSeconds([self.playerController.player currentTime]);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
-(float) duration
|
||||
{
|
||||
if (self.playerController.player)
|
||||
return CMTimeGetSeconds(self.playerController.player.currentItem.asset.duration);
|
||||
|
||||
return -1;;
|
||||
}
|
||||
|
||||
-(void) setVisible:(BOOL)visible
|
||||
{
|
||||
[self.playerController.view setHidden:!visible];
|
||||
if (!visible)
|
||||
[self pause];
|
||||
}
|
||||
|
||||
-(void) setKeepRatioEnabled:(BOOL)enabled
|
||||
{
|
||||
_keepRatioEnabled = enabled;
|
||||
if (_keepRatioEnabled)
|
||||
self.playerController.videoGravity = AVLayerVideoGravityResizeAspectFill;
|
||||
else
|
||||
self.playerController.videoGravity = AVLayerVideoGravityResize;
|
||||
}
|
||||
|
||||
-(void) play
|
||||
{
|
||||
if (self.playerController.player && ![self isPlaying] ) {
|
||||
[self.playerController.player play];
|
||||
_state = PlayerbackStatePlaying;
|
||||
_videoPlayer->onPlayEvent((int)VideoPlayer::EventType::PLAYING);
|
||||
}
|
||||
}
|
||||
|
||||
-(void) pause
|
||||
{
|
||||
if ( [self isPlaying] ) {
|
||||
[self.playerController.player pause];
|
||||
_state = PlayerbackStatePaused;
|
||||
_videoPlayer->onPlayEvent((int)VideoPlayer::EventType::PAUSED);
|
||||
}
|
||||
}
|
||||
|
||||
-(void) resume
|
||||
{
|
||||
if (self.playerController.player && _state == PlayerbackStatePaused)
|
||||
[self play];
|
||||
}
|
||||
|
||||
-(void) stop
|
||||
{
|
||||
// AVPlayer doesn't have `stop` method, so just pause it, and seek time to 0.
|
||||
if (self.playerController.player && _state != PlayerbackStopped) {
|
||||
[self seekTo:0];
|
||||
[self.playerController.player pause];
|
||||
_state = PlayerbackStopped;
|
||||
|
||||
// stop() will be invoked in dealloc, which is invoked by _videoPlayer's destructor,
|
||||
// so do't send the message when _videoPlayer is being deleted.
|
||||
if (_videoPlayer)
|
||||
_videoPlayer->onPlayEvent((int)VideoPlayer::EventType::STOPPED);
|
||||
}
|
||||
}
|
||||
|
||||
// Private functions
|
||||
-(void) clearBuffers
|
||||
{
|
||||
if(_videoPixels != nullptr) {
|
||||
free(_videoPixels);
|
||||
_videoPixels = nullptr;
|
||||
}
|
||||
|
||||
AVPlayerItem* item = self.playerController.player.currentItem;
|
||||
if(item.outputs.count > 0) {
|
||||
AVPlayerItemOutput* output = item.outputs[0];
|
||||
[item removeOutput:output];
|
||||
[output dealloc];
|
||||
}
|
||||
}
|
||||
|
||||
-(void) cleanup
|
||||
{
|
||||
[self stop];
|
||||
[self removePlayerEventListener];
|
||||
[self.playerController.view removeFromSuperview];
|
||||
[self.playerController release];
|
||||
}
|
||||
|
||||
-(void) removePlayerEventListener {
|
||||
if (self.playerController.player)
|
||||
{
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self
|
||||
name:AVPlayerItemDidPlayToEndTimeNotification
|
||||
object:self.playerController.player.currentItem];
|
||||
|
||||
[self.playerController.player removeObserver:self forKeyPath:@"status"];
|
||||
}
|
||||
}
|
||||
|
||||
-(void) registerPlayerEventListener
|
||||
{
|
||||
if (self.playerController.player)
|
||||
{
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(videoFinished:)
|
||||
name:AVPlayerItemDidPlayToEndTimeNotification
|
||||
object:self.playerController.player.currentItem];
|
||||
|
||||
[self.playerController.player addObserver:self forKeyPath:@"status" options:0 context:nil];
|
||||
}
|
||||
}
|
||||
|
||||
-(void) showPlaybackControls:(BOOL)value
|
||||
{
|
||||
self.playerController.showsPlaybackControls = value;
|
||||
}
|
||||
|
||||
-(void) videoFinished:(NSNotification *)notification
|
||||
{
|
||||
if(_videoPlayer != nullptr) {
|
||||
_videoPlayer->onPlayEvent((int)VideoPlayer::EventType::COMPLETED);
|
||||
_state = PlayerbackStateCompleted;
|
||||
|
||||
// Seek to 0 to make it playable again.
|
||||
[self seekTo:0];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object
|
||||
change:(NSDictionary *)change context:(void *)context {
|
||||
|
||||
auto player = self.playerController.player;
|
||||
if (object == player && [keyPath isEqualToString:@"status"]) {
|
||||
if (player.status == AVPlayerStatusReadyToPlay) {
|
||||
[self addPlayerControllerSubView];
|
||||
_videoPlayer->onPlayEvent((int)VideoPlayer::EventType::META_LOADED);
|
||||
_videoPlayer->onPlayEvent((int)VideoPlayer::EventType::READY_TO_PLAY);
|
||||
} else if (player.status == AVPlayerStatusFailed) {
|
||||
// something went wrong. player.error should contain some information
|
||||
NSLog(@"Failed to load video");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
-(void)addPlayerControllerSubView {
|
||||
auto eaglview = (CCEAGLView*)cocos2d::Application::getInstance()->getView();
|
||||
[eaglview addSubview:self.playerController.view];
|
||||
}
|
||||
|
||||
@end
|
||||
//------------------------------------------------------------------------------------------------------------
|
||||
|
||||
VideoPlayer::VideoPlayer()
|
||||
: _videoPlayerIndex(-1)
|
||||
, _fullScreenEnabled(false)
|
||||
, _fullScreenDirty(false)
|
||||
, _keepAspectRatioEnabled(false)
|
||||
{
|
||||
_videoView = [[UIVideoViewWrapperIos alloc] init:this];
|
||||
|
||||
#if CC_VIDEOPLAYER_DEBUG_DRAW
|
||||
_debugDrawNode = DrawNode::create();
|
||||
addChild(_debugDrawNode);
|
||||
#endif
|
||||
|
||||
_videoPixels = nullptr;
|
||||
_texDataSize = 0;
|
||||
_maxDataLen = 0;
|
||||
}
|
||||
|
||||
VideoPlayer::~VideoPlayer()
|
||||
{
|
||||
if(_videoView)
|
||||
{
|
||||
[((UIVideoViewWrapperIos*)_videoView) dealloc];
|
||||
}
|
||||
}
|
||||
|
||||
void VideoPlayer::setURL(const std::string& videoUrl)
|
||||
{
|
||||
if (videoUrl.find("://") == std::string::npos)
|
||||
{
|
||||
_videoURL = FileUtils::getInstance()->fullPathForFilename(videoUrl);
|
||||
_videoSource = VideoPlayer::Source::FILENAME;
|
||||
}
|
||||
else
|
||||
{
|
||||
_videoURL = videoUrl;
|
||||
_videoSource = VideoPlayer::Source::URL;
|
||||
}
|
||||
|
||||
[((UIVideoViewWrapperIos*)_videoView) setURL:(int)_videoSource :_videoURL];
|
||||
}
|
||||
|
||||
void VideoPlayer::setFullScreenEnabled(bool enabled)
|
||||
{
|
||||
[((UIVideoViewWrapperIos*)_videoView) setFullScreenEnabled:enabled];
|
||||
}
|
||||
|
||||
void VideoPlayer::setKeepAspectRatioEnabled(bool enable)
|
||||
{
|
||||
if (_keepAspectRatioEnabled != enable)
|
||||
{
|
||||
_keepAspectRatioEnabled = enable;
|
||||
[((UIVideoViewWrapperIos*)_videoView) setKeepRatioEnabled:enable];
|
||||
}
|
||||
}
|
||||
|
||||
void VideoPlayer::play()
|
||||
{
|
||||
if (! _videoURL.empty() && _isVisible)
|
||||
{
|
||||
[((UIVideoViewWrapperIos*)_videoView) play];
|
||||
}
|
||||
}
|
||||
|
||||
void VideoPlayer::pause()
|
||||
{
|
||||
if (! _videoURL.empty())
|
||||
{
|
||||
[((UIVideoViewWrapperIos*)_videoView) pause];
|
||||
}
|
||||
}
|
||||
|
||||
void VideoPlayer::stop()
|
||||
{
|
||||
if (! _videoURL.empty())
|
||||
{
|
||||
[((UIVideoViewWrapperIos*)_videoView) stop];
|
||||
}
|
||||
}
|
||||
|
||||
void VideoPlayer::seekTo(float sec)
|
||||
{
|
||||
if (! _videoURL.empty())
|
||||
{
|
||||
[((UIVideoViewWrapperIos*)_videoView) seekTo:sec];
|
||||
}
|
||||
}
|
||||
|
||||
float VideoPlayer::currentTime()const
|
||||
{
|
||||
return [((UIVideoViewWrapperIos*)_videoView) currentTime];
|
||||
}
|
||||
|
||||
float VideoPlayer::duration()const
|
||||
{
|
||||
return [((UIVideoViewWrapperIos*)_videoView) duration];
|
||||
}
|
||||
|
||||
void VideoPlayer::setVisible(bool visible)
|
||||
{
|
||||
_isVisible = visible;
|
||||
|
||||
if (!visible)
|
||||
{
|
||||
[((UIVideoViewWrapperIos*)_videoView) setVisible:NO];
|
||||
}
|
||||
else
|
||||
{
|
||||
[((UIVideoViewWrapperIos*)_videoView) setVisible:YES];
|
||||
}
|
||||
}
|
||||
|
||||
void VideoPlayer::addEventListener(const std::string& name, const VideoPlayer::ccVideoPlayerCallback& callback)
|
||||
{
|
||||
_eventCallback[name] = callback;
|
||||
}
|
||||
|
||||
void VideoPlayer::onPlayEvent(int event)
|
||||
{
|
||||
switch ((EventType)event) {
|
||||
case EventType::PLAYING:
|
||||
_eventCallback["play"]();
|
||||
break;
|
||||
case EventType::PAUSED:
|
||||
_eventCallback["pause"]();
|
||||
break;
|
||||
case EventType::STOPPED:
|
||||
_eventCallback["stoped"]();
|
||||
break;
|
||||
case EventType::COMPLETED:
|
||||
_eventCallback["ended"]();
|
||||
break;
|
||||
case EventType::META_LOADED:
|
||||
_eventCallback["loadedmetadata"]();
|
||||
break;
|
||||
case EventType::CLICKED:
|
||||
_eventCallback["click"]();
|
||||
break;
|
||||
case EventType::READY_TO_PLAY:
|
||||
_eventCallback["suspend"]();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void VideoPlayer::setFrame(float x, float y, float width, float height)
|
||||
{
|
||||
auto eaglview = (CCEAGLView*)cocos2d::Application::getInstance()->getView();
|
||||
auto scaleFactor = [eaglview contentScaleFactor];
|
||||
[((UIVideoViewWrapperIos*)_videoView) setFrame:x/scaleFactor
|
||||
:y/scaleFactor
|
||||
:width/scaleFactor
|
||||
:height/scaleFactor];
|
||||
}
|
||||
|
||||
void VideoPlayer::getFrame()
|
||||
{
|
||||
_videoPixels = [((UIVideoViewWrapperIos*)_videoView) getFrame];
|
||||
}
|
||||
|
||||
int VideoPlayer::getFrameChannel() const
|
||||
{
|
||||
int res = VideoPlayer::PX_BGRA;
|
||||
return res;
|
||||
}
|
||||
|
||||
int VideoPlayer::getFrameWidth() const
|
||||
{
|
||||
return [((UIVideoViewWrapperIos*)_videoView) getFrameWidth];
|
||||
}
|
||||
|
||||
int VideoPlayer::getFrameHeight() const
|
||||
{
|
||||
return [((UIVideoViewWrapperIos*)_videoView) getFrameHeight];
|
||||
}
|
||||
|
||||
int VideoPlayer::getVideoTexDataSize() const
|
||||
{
|
||||
return [((UIVideoViewWrapperIos*)_videoView) getFrameDataSize];
|
||||
}
|
||||
|
||||
void VideoPlayer::update()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void VideoPlayer::pushFrameDataToTexture2D(cocos2d::renderer::Texture* tex) const
|
||||
{
|
||||
if(tex == nullptr) {
|
||||
printf("Can't find texture!\n");
|
||||
} else {
|
||||
bool finshCopy = [((UIVideoViewWrapperIos*)_videoView) copyFinished];
|
||||
if(_videoPixels != nullptr && getFrameWidth() > 0 && getFrameHeight() > 0 && finshCopy) {
|
||||
renderer::Texture::SubImageOption opt(0, 0, getFrameWidth(), getFrameHeight(), 0, false, false);
|
||||
opt.imageData = _videoPixels;
|
||||
((cocos2d::renderer::Texture2D*)tex)->updateSubImage(opt);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void VideoPlayer::setShowRawFrame(bool show) const
|
||||
{
|
||||
if(show)
|
||||
[((UIVideoViewWrapperIos*)_videoView) setShowRaw: YES];
|
||||
else
|
||||
[((UIVideoViewWrapperIos*)_videoView) setShowRaw: NO];
|
||||
}
|
||||
|
||||
#endif
|
211
cocos2d-x/cocos/ui/videoplayer/VideoPlayer.h
Normal file
211
cocos2d-x/cocos/ui/videoplayer/VideoPlayer.h
Normal file
@@ -0,0 +1,211 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2014-2016 Chukong Technologies Inc.
|
||||
|
||||
http://www.cocos2d-x.org
|
||||
|
||||
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/ccMacros.h"
|
||||
#include "base/CCData.h"
|
||||
#include "base/CCRef.h"
|
||||
#include <functional>
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include "renderer/gfx/Texture2D.h"
|
||||
|
||||
#ifndef OBJC_CLASS
|
||||
#ifdef __OBJC__
|
||||
#define OBJC_CLASS(name) @class name
|
||||
#else
|
||||
#define OBJC_CLASS(name) class name
|
||||
#endif
|
||||
#endif // OBJC_CLASS
|
||||
|
||||
NS_CC_BEGIN
|
||||
|
||||
/**
|
||||
* @class VideoPlayer
|
||||
* @brief Displays a video file.
|
||||
*
|
||||
* @note VideoPlayer displays a video file base on system widget.
|
||||
* It's mean VideoPlayer displays a video file above all graphical elements of cocos2d-x.
|
||||
* @js NA
|
||||
*/
|
||||
class VideoPlayer : public Ref
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Videoplayer play event type.
|
||||
*/
|
||||
enum class EventType
|
||||
{
|
||||
PLAYING = 0,
|
||||
PAUSED,
|
||||
STOPPED,
|
||||
COMPLETED,
|
||||
META_LOADED,
|
||||
CLICKED,
|
||||
READY_TO_PLAY
|
||||
};
|
||||
|
||||
VideoPlayer();
|
||||
|
||||
/**
|
||||
* A callback which will be called after specific VideoPlayer event happens.
|
||||
*/
|
||||
typedef std::function<void()> ccVideoPlayerCallback;
|
||||
|
||||
|
||||
/**
|
||||
* Sets a URL as a video source for VideoPlayer.
|
||||
*/
|
||||
virtual void setURL(const std::string &_videoURL);
|
||||
|
||||
/**
|
||||
* Starts playback.
|
||||
*/
|
||||
virtual void play();
|
||||
|
||||
/**
|
||||
* Pauses playback.
|
||||
*/
|
||||
virtual void pause();
|
||||
|
||||
/**
|
||||
* Stops playback.
|
||||
*/
|
||||
virtual void stop();
|
||||
|
||||
/**
|
||||
* Seeks to specified time position.
|
||||
*
|
||||
* @param sec The offset in seconds from the start to seek to.
|
||||
*/
|
||||
virtual void seekTo(float sec);
|
||||
|
||||
/**
|
||||
* Get the current play time, measure in seconds.
|
||||
*/
|
||||
float currentTime() const;
|
||||
|
||||
float duration() const;
|
||||
|
||||
/**
|
||||
* Get frame rgba pixel as bytes
|
||||
*/
|
||||
void getFrame();
|
||||
|
||||
int getFrameChannel() const;
|
||||
|
||||
int getFrameWidth() const;
|
||||
|
||||
int getFrameHeight() const;
|
||||
|
||||
int getVideoTexDataSize() const;
|
||||
|
||||
void update();
|
||||
|
||||
void pushFrameDataToTexture2D(cocos2d::renderer::Texture* tex) const;
|
||||
|
||||
void setShowRawFrame(bool show) const;
|
||||
|
||||
/**
|
||||
* Causes the video player to keep aspect ratio or no when displaying the video.
|
||||
*
|
||||
* @param enable Specify true to keep aspect ratio or false to scale the video until
|
||||
* both dimensions fit the visible bounds of the view exactly.
|
||||
*/
|
||||
virtual void setKeepAspectRatioEnabled(bool enable);
|
||||
|
||||
/**
|
||||
* Indicates whether the video player keep aspect ratio when displaying the video.
|
||||
*/
|
||||
virtual bool isKeepAspectRatioEnabled() const { return _keepAspectRatioEnabled; }
|
||||
|
||||
/**
|
||||
* Causes the video player to enter or exit full-screen mode.
|
||||
*
|
||||
* @param fullscreen Specify true to enter full-screen mode or false to exit full-screen mode.
|
||||
*/
|
||||
virtual void setFullScreenEnabled(bool fullscreen);
|
||||
|
||||
/**
|
||||
* Register a callback to be invoked when the video state is updated.
|
||||
*
|
||||
* @param callback The callback that will be run.
|
||||
*/
|
||||
virtual void addEventListener(const std::string& name, const VideoPlayer::ccVideoPlayerCallback& callback);
|
||||
|
||||
/**
|
||||
* @brief A function which will be called when video is playing.
|
||||
*
|
||||
* @param event @see VideoPlayer::EventType.
|
||||
*/
|
||||
virtual void onPlayEvent(int event);
|
||||
|
||||
/**
|
||||
* Toggle visibility of VideoPlayer.
|
||||
*/
|
||||
virtual void setVisible(bool visible);
|
||||
|
||||
/**
|
||||
* Set the rect of VideoPlayer.
|
||||
*/
|
||||
virtual void setFrame(float x, float y, float width, float height);
|
||||
|
||||
protected:
|
||||
|
||||
virtual ~VideoPlayer();
|
||||
|
||||
protected:
|
||||
|
||||
enum class Source
|
||||
{
|
||||
FILENAME = 0,
|
||||
URL
|
||||
};
|
||||
|
||||
bool _isVisible;
|
||||
bool _fullScreenDirty;
|
||||
bool _fullScreenEnabled;
|
||||
bool _keepAspectRatioEnabled;
|
||||
|
||||
std::string _videoURL;
|
||||
Source _videoSource;
|
||||
|
||||
int _videoPlayerIndex;
|
||||
std::map<std::string, ccVideoPlayerCallback> _eventCallback;
|
||||
|
||||
void *_videoView;
|
||||
|
||||
int _texDataSize;
|
||||
|
||||
private:
|
||||
unsigned char* _videoPixels;
|
||||
int _maxDataLen;
|
||||
|
||||
static const int PX_RGBA = 3;
|
||||
static const int PX_RGB565 = 6;
|
||||
static const int PX_BGRA = 7;
|
||||
};
|
||||
|
||||
NS_CC_END
|
173
cocos2d-x/cocos/ui/webview/WebView-inl.h
Normal file
173
cocos2d-x/cocos/ui/webview/WebView-inl.h
Normal file
@@ -0,0 +1,173 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2014-2016 Chukong Technologies Inc.
|
||||
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos2d-x.org
|
||||
|
||||
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 "WebView.h"
|
||||
#include "platform/CCFileUtils.h"
|
||||
#include "platform/CCPlatformConfig.h"
|
||||
|
||||
#if CC_TARGET_PLATFORM == CC_PLATFORM_IOS && !defined(CC_PLATFORM_OS_TVOS)
|
||||
#include "WebViewImpl-ios.h"
|
||||
#elif CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID
|
||||
#include "WebViewImpl-android.h"
|
||||
#else
|
||||
static_assert(false, "WebView only supported on iOS & Android");
|
||||
#endif
|
||||
|
||||
NS_CC_BEGIN
|
||||
|
||||
WebView::WebView()
|
||||
: _impl(new WebViewImpl(this)),
|
||||
_onJSCallback(nullptr),
|
||||
_onShouldStartLoading(nullptr),
|
||||
_onDidFinishLoading(nullptr),
|
||||
_onDidFailLoading(nullptr) {
|
||||
}
|
||||
|
||||
WebView::~WebView() {
|
||||
CC_SAFE_DELETE(_impl);
|
||||
}
|
||||
|
||||
WebView *WebView::create() {
|
||||
auto webView = new(std::nothrow) WebView();
|
||||
if (webView) {
|
||||
webView->autorelease();
|
||||
return webView;
|
||||
}
|
||||
CC_SAFE_DELETE(webView);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void WebView::setJavascriptInterfaceScheme(const std::string &scheme) {
|
||||
_impl->setJavascriptInterfaceScheme(scheme);
|
||||
}
|
||||
|
||||
void WebView::loadData(const cocos2d::Data &data,
|
||||
const std::string &MIMEType,
|
||||
const std::string &encoding,
|
||||
const std::string &baseURL) {
|
||||
_impl->loadData(data, MIMEType, encoding, baseURL);
|
||||
}
|
||||
|
||||
void WebView::loadHTMLString(const std::string &string, const std::string &baseURL) {
|
||||
_impl->loadHTMLString(string, baseURL);
|
||||
}
|
||||
|
||||
void WebView::loadURL(const std::string &url) {
|
||||
_impl->loadURL(url);
|
||||
}
|
||||
|
||||
void WebView::loadFile(const std::string &fileName) {
|
||||
_impl->loadFile(fileName);
|
||||
}
|
||||
|
||||
void WebView::stopLoading() {
|
||||
_impl->stopLoading();
|
||||
}
|
||||
|
||||
void WebView::reload() {
|
||||
_impl->reload();
|
||||
}
|
||||
|
||||
bool WebView::canGoBack() {
|
||||
return _impl->canGoBack();
|
||||
}
|
||||
|
||||
bool WebView::canGoForward() {
|
||||
return _impl->canGoForward();
|
||||
}
|
||||
|
||||
void WebView::goBack() {
|
||||
_impl->goBack();
|
||||
}
|
||||
|
||||
void WebView::goForward() {
|
||||
_impl->goForward();
|
||||
}
|
||||
|
||||
void WebView::evaluateJS(const std::string &js) {
|
||||
_impl->evaluateJS(js);
|
||||
}
|
||||
|
||||
void WebView::setScalesPageToFit(bool const scalesPageToFit) {
|
||||
_impl->setScalesPageToFit(scalesPageToFit);
|
||||
}
|
||||
|
||||
void WebView::setVisible(bool visible) {
|
||||
_impl->setVisible(visible);
|
||||
}
|
||||
|
||||
void WebView::setFrame(float x, float y, float width, float height) {
|
||||
_impl->setFrame(x, y, width, height);
|
||||
}
|
||||
|
||||
void WebView::setBounces(bool bounces) {
|
||||
_impl->setBounces(bounces);
|
||||
}
|
||||
|
||||
void WebView::setBackgroundTransparent(bool isTransparent) {
|
||||
_impl->setBackgroundTransparent(isTransparent);
|
||||
}
|
||||
|
||||
void WebView::setOnDidFailLoading(const ccWebViewCallback &callback) {
|
||||
_onDidFailLoading = callback;
|
||||
}
|
||||
|
||||
void WebView::setOnDidFinishLoading(const ccWebViewCallback &callback) {
|
||||
_onDidFinishLoading = callback;
|
||||
}
|
||||
|
||||
void WebView::setOnShouldStartLoading(
|
||||
const std::function<bool(WebView *sender, const std::string &url)> &callback) {
|
||||
_onShouldStartLoading = callback;
|
||||
}
|
||||
|
||||
void WebView::setOnJSCallback(const ccWebViewCallback &callback) {
|
||||
_onJSCallback = callback;
|
||||
}
|
||||
|
||||
std::function<bool(WebView
|
||||
*sender,
|
||||
const std::string &url
|
||||
)>
|
||||
|
||||
WebView::getOnShouldStartLoading() const {
|
||||
return _onShouldStartLoading;
|
||||
}
|
||||
|
||||
WebView::ccWebViewCallback WebView::getOnDidFailLoading() const {
|
||||
return _onDidFailLoading;
|
||||
}
|
||||
|
||||
WebView::ccWebViewCallback WebView::getOnDidFinishLoading() const {
|
||||
return _onDidFinishLoading;
|
||||
}
|
||||
|
||||
WebView::ccWebViewCallback WebView::getOnJSCallback() const {
|
||||
return _onJSCallback;
|
||||
}
|
||||
|
||||
} //namespace cocos2d
|
||||
|
||||
/// @endcond
|
246
cocos2d-x/cocos/ui/webview/WebView.h
Normal file
246
cocos2d-x/cocos/ui/webview/WebView.h
Normal file
@@ -0,0 +1,246 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2014-2016 Chukong Technologies Inc.
|
||||
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos2d-x.org
|
||||
|
||||
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 <functional>
|
||||
|
||||
#include "base/ccMacros.h"
|
||||
#include "base/CCRef.h"
|
||||
#include "base/CCData.h"
|
||||
#include "base/ccConfig.h"
|
||||
|
||||
/**
|
||||
* @addtogroup ui
|
||||
* @{
|
||||
*/
|
||||
|
||||
NS_CC_BEGIN
|
||||
|
||||
class WebViewImpl;
|
||||
|
||||
/**
|
||||
* @brief A View that displays web pages.
|
||||
*
|
||||
* @note WebView displays web pages base on system widget.
|
||||
* It's mean WebView displays web pages above all graphical elements of cocos2d-x.
|
||||
* @js NA
|
||||
*/
|
||||
class WebView : public Ref {
|
||||
public:
|
||||
/**
|
||||
* Allocates and initializes a WebView.
|
||||
*/
|
||||
static WebView *create();
|
||||
|
||||
/**
|
||||
* Set javascript interface scheme.
|
||||
*
|
||||
* @see WebView::setOnJSCallback()
|
||||
*/
|
||||
void setJavascriptInterfaceScheme(const std::string &scheme);
|
||||
|
||||
/**
|
||||
* Sets the main page contents, MIME type, content encoding, and base URL.
|
||||
*
|
||||
* @param data The content for the main page.
|
||||
* @param MIMEType The MIME type of the data.
|
||||
* @param encoding The encoding of the data.
|
||||
* @param baseURL The base URL for the content.
|
||||
*/
|
||||
void loadData(const cocos2d::Data &data,
|
||||
const std::string &MIMEType,
|
||||
const std::string &encoding,
|
||||
const std::string &baseURL);
|
||||
|
||||
/**
|
||||
* Sets the main page content and base URL.
|
||||
*
|
||||
* @param string The content for the main page.
|
||||
* @param baseURL The base URL for the content.
|
||||
*/
|
||||
void loadHTMLString(const std::string &string, const std::string &baseURL = "");
|
||||
|
||||
/**
|
||||
* Loads the given URL.
|
||||
*
|
||||
* @param url Content URL.
|
||||
*/
|
||||
void loadURL(const std::string &url);
|
||||
|
||||
/**
|
||||
* Loads the given fileName.
|
||||
*
|
||||
* @param fileName Content fileName.
|
||||
*/
|
||||
void loadFile(const std::string &fileName);
|
||||
|
||||
/**
|
||||
* Stops the current load.
|
||||
*/
|
||||
void stopLoading();
|
||||
|
||||
/**
|
||||
* Reloads the current URL.
|
||||
*/
|
||||
void reload();
|
||||
|
||||
/**
|
||||
* Gets whether this WebView has a back history item.
|
||||
*
|
||||
* @return WebView has a back history item.
|
||||
*/
|
||||
bool canGoBack();
|
||||
|
||||
/**
|
||||
* Gets whether this WebView has a forward history item.
|
||||
*
|
||||
* @return WebView has a forward history item.
|
||||
*/
|
||||
bool canGoForward();
|
||||
|
||||
/**
|
||||
* Goes back in the history.
|
||||
*/
|
||||
void goBack();
|
||||
|
||||
/**
|
||||
* Goes forward in the history.
|
||||
*/
|
||||
void goForward();
|
||||
|
||||
/**
|
||||
* Evaluates JavaScript in the context of the currently displayed page.
|
||||
*/
|
||||
void evaluateJS(const std::string &js);
|
||||
|
||||
/**
|
||||
* Set WebView should support zooming. The default value is false.
|
||||
*/
|
||||
void setScalesPageToFit(const bool scalesPageToFit);
|
||||
|
||||
/**
|
||||
* Call before a web view begins loading.
|
||||
*
|
||||
* @param callback The web view that is about to load new content.
|
||||
* @return YES if the web view should begin loading content; otherwise, NO.
|
||||
*/
|
||||
void setOnShouldStartLoading(
|
||||
const std::function<bool(WebView *sender, const std::string &url)> &callback);
|
||||
|
||||
/**
|
||||
* A callback which will be called when a WebView event happens.
|
||||
*/
|
||||
typedef std::function<void(WebView *sender, const std::string &url)> ccWebViewCallback;
|
||||
|
||||
/**
|
||||
* Call after a web view finishes loading.
|
||||
*
|
||||
* @param callback The web view that has finished loading.
|
||||
*/
|
||||
void setOnDidFinishLoading(const ccWebViewCallback &callback);
|
||||
|
||||
/**
|
||||
* Call if a web view failed to load content.
|
||||
*
|
||||
* @param callback The web view that has failed loading.
|
||||
*/
|
||||
void setOnDidFailLoading(const ccWebViewCallback &callback);
|
||||
|
||||
/**
|
||||
* This callback called when load URL that start with javascript interface scheme.
|
||||
*/
|
||||
void setOnJSCallback(const ccWebViewCallback &callback);
|
||||
|
||||
/**
|
||||
* Get the callback when WebView is about to start.
|
||||
*/
|
||||
std::function<bool(WebView *sender, const std::string &url)>
|
||||
getOnShouldStartLoading() const;
|
||||
|
||||
/**
|
||||
* Get the callback when WebView has finished loading.
|
||||
*/
|
||||
ccWebViewCallback getOnDidFinishLoading() const;
|
||||
|
||||
/**
|
||||
* Get the callback when WebView has failed loading.
|
||||
*/
|
||||
ccWebViewCallback getOnDidFailLoading() const;
|
||||
|
||||
/**
|
||||
*Get the Javascript callback.
|
||||
*/
|
||||
ccWebViewCallback getOnJSCallback() const;
|
||||
|
||||
/**
|
||||
* Set whether the webview bounces at end of scroll of WebView.
|
||||
*/
|
||||
void setBounces(bool bounce);
|
||||
|
||||
/**
|
||||
* Toggle visibility of WebView.
|
||||
*/
|
||||
virtual void setVisible(bool visible);
|
||||
|
||||
/**
|
||||
* Set the rect of WebView.
|
||||
*/
|
||||
virtual void setFrame(float x, float y, float width, float height);
|
||||
|
||||
/**
|
||||
* Set the background transparent
|
||||
*/
|
||||
virtual void setBackgroundTransparent(bool isTransparent);
|
||||
|
||||
protected:
|
||||
|
||||
std::function<bool(WebView *sender, const std::string &url)> _onShouldStartLoading;
|
||||
|
||||
ccWebViewCallback _onDidFinishLoading;
|
||||
|
||||
ccWebViewCallback _onDidFailLoading;
|
||||
|
||||
ccWebViewCallback _onJSCallback;
|
||||
|
||||
CC_CONSTRUCTOR_ACCESS:
|
||||
|
||||
/**
|
||||
* Default constructor.
|
||||
*/
|
||||
WebView();
|
||||
|
||||
/**
|
||||
* Default destructor.
|
||||
*/
|
||||
virtual ~WebView();
|
||||
|
||||
private:
|
||||
WebViewImpl *_impl;
|
||||
|
||||
friend class WebViewImpl;
|
||||
};
|
||||
|
||||
NS_CC_END
|
290
cocos2d-x/cocos/ui/webview/WebViewImpl-android.cpp
Normal file
290
cocos2d-x/cocos/ui/webview/WebViewImpl-android.cpp
Normal file
@@ -0,0 +1,290 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2014-2016 Chukong Technologies Inc.
|
||||
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos2d-x.org
|
||||
|
||||
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 <cstdlib>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
|
||||
#include "WebView-inl.h"
|
||||
|
||||
#include "platform/CCFileUtils.h"
|
||||
#include "platform/android/jni/JniHelper.h"
|
||||
|
||||
|
||||
static const std::string className = "org/cocos2dx/lib/Cocos2dxWebViewHelper";
|
||||
|
||||
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG,"",__VA_ARGS__)
|
||||
|
||||
static const std::string s_defaultBaseUrl = "file:///android_asset/";
|
||||
static const std::string s_sdRootBaseUrl = "file://";
|
||||
|
||||
static std::string getFixedBaseUrl(const std::string &baseUrl) {
|
||||
std::string fixedBaseUrl;
|
||||
if (baseUrl.empty()) {
|
||||
fixedBaseUrl = s_defaultBaseUrl;
|
||||
} else if (baseUrl.find(s_sdRootBaseUrl) != std::string::npos) {
|
||||
fixedBaseUrl = baseUrl;
|
||||
} else if (baseUrl.c_str()[0] != '/') {
|
||||
if (baseUrl.find("assets/") == 0) {
|
||||
fixedBaseUrl = s_defaultBaseUrl + baseUrl.c_str()[7];
|
||||
} else {
|
||||
fixedBaseUrl = s_defaultBaseUrl + baseUrl;
|
||||
}
|
||||
} else {
|
||||
fixedBaseUrl = s_sdRootBaseUrl + baseUrl;
|
||||
}
|
||||
|
||||
if (fixedBaseUrl.c_str()[fixedBaseUrl.length() - 1] != '/') {
|
||||
fixedBaseUrl += "/";
|
||||
}
|
||||
|
||||
return fixedBaseUrl;
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
/*
|
||||
* Class: org_cocos2dx_lib_Cocos2dxWebViewHelper
|
||||
* Method: shouldStartLoading
|
||||
* Signature: (ILjava/lang/String;)Z
|
||||
*/
|
||||
JNIEXPORT jboolean JNICALL
|
||||
Java_org_cocos2dx_lib_Cocos2dxWebViewHelper_shouldStartLoading(JNIEnv *env, jclass, jint index,
|
||||
jstring jurl) {
|
||||
auto charUrl = env->GetStringUTFChars(jurl, NULL);
|
||||
std::string url = charUrl;
|
||||
env->ReleaseStringUTFChars(jurl, charUrl);
|
||||
return cocos2d::WebViewImpl::shouldStartLoading(index, url);
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: org_cocos2dx_lib_Cocos2dxWebViewHelper
|
||||
* Method: didFinishLoading
|
||||
* Signature: (ILjava/lang/String;)V
|
||||
*/
|
||||
JNIEXPORT void JNICALL
|
||||
Java_org_cocos2dx_lib_Cocos2dxWebViewHelper_didFinishLoading(JNIEnv *env, jclass, jint index,
|
||||
jstring jurl) {
|
||||
// LOGD("didFinishLoading");
|
||||
auto charUrl = env->GetStringUTFChars(jurl, NULL);
|
||||
std::string url = charUrl;
|
||||
env->ReleaseStringUTFChars(jurl, charUrl);
|
||||
cocos2d::WebViewImpl::didFinishLoading(index, url);
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: org_cocos2dx_lib_Cocos2dxWebViewHelper
|
||||
* Method: didFailLoading
|
||||
* Signature: (ILjava/lang/String;)V
|
||||
*/
|
||||
JNIEXPORT void JNICALL
|
||||
Java_org_cocos2dx_lib_Cocos2dxWebViewHelper_didFailLoading(JNIEnv *env, jclass, jint index,
|
||||
jstring jurl) {
|
||||
// LOGD("didFailLoading");
|
||||
auto charUrl = env->GetStringUTFChars(jurl, NULL);
|
||||
std::string url = charUrl;
|
||||
env->ReleaseStringUTFChars(jurl, charUrl);
|
||||
cocos2d::WebViewImpl::didFailLoading(index, url);
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: org_cocos2dx_lib_Cocos2dxWebViewHelper
|
||||
* Method: onJsCallback
|
||||
* Signature: (ILjava/lang/String;)V
|
||||
*/
|
||||
JNIEXPORT void JNICALL
|
||||
Java_org_cocos2dx_lib_Cocos2dxWebViewHelper_onJsCallback(JNIEnv *env, jclass, jint index,
|
||||
jstring jmessage) {
|
||||
// LOGD("jsCallback");
|
||||
auto charMessage = env->GetStringUTFChars(jmessage, NULL);
|
||||
std::string message = charMessage;
|
||||
env->ReleaseStringUTFChars(jmessage, charMessage);
|
||||
cocos2d::WebViewImpl::onJsCallback(index, message);
|
||||
}
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
int createWebViewJNI() {
|
||||
cocos2d::JniMethodInfo t;
|
||||
if (cocos2d::JniHelper::getStaticMethodInfo(t, className.c_str(), "createWebView", "()I")) {
|
||||
// LOGD("error: %s,%d",__func__,__LINE__);
|
||||
jint viewTag = t.env->CallStaticIntMethod(t.classID, t.methodID);
|
||||
t.env->DeleteLocalRef(t.classID);
|
||||
return viewTag;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
std::string getUrlStringByFileName(const std::string &fileName) {
|
||||
// LOGD("error: %s,%d",__func__,__LINE__);
|
||||
const std::string basePath("file:///android_asset/");
|
||||
std::string fullPath = cocos2d::FileUtils::getInstance()->fullPathForFilename(fileName);
|
||||
const std::string assetsPath("assets/");
|
||||
|
||||
std::string urlString;
|
||||
if (fullPath.find(assetsPath) != std::string::npos) {
|
||||
urlString = fullPath.replace(fullPath.find_first_of(assetsPath), assetsPath.length(),
|
||||
basePath);
|
||||
} else {
|
||||
urlString = fullPath;
|
||||
}
|
||||
|
||||
return urlString;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
namespace cocos2d {
|
||||
|
||||
static std::unordered_map<int, WebViewImpl *> s_WebViewImpls;
|
||||
|
||||
WebViewImpl::WebViewImpl(WebView *webView) : _viewTag(-1), _webView(webView) {
|
||||
_viewTag = createWebViewJNI();
|
||||
s_WebViewImpls[_viewTag] = this;
|
||||
}
|
||||
|
||||
WebViewImpl::~WebViewImpl() {
|
||||
JniHelper::callStaticVoidMethod(className, "removeWebView", _viewTag);
|
||||
s_WebViewImpls.erase(_viewTag);
|
||||
}
|
||||
|
||||
void WebViewImpl::loadData(const Data &data, const std::string &MIMEType,
|
||||
const std::string &encoding, const std::string &baseURL) {
|
||||
std::string dataString(reinterpret_cast<char *>(data.getBytes()),
|
||||
static_cast<unsigned int>(data.getSize()));
|
||||
JniHelper::callStaticVoidMethod(className, "setJavascriptInterfaceScheme", _viewTag,
|
||||
dataString, MIMEType, encoding, baseURL);
|
||||
}
|
||||
|
||||
void WebViewImpl::loadHTMLString(const std::string &string, const std::string &baseURL) {
|
||||
JniHelper::callStaticVoidMethod(className, "loadHTMLString", _viewTag, string, baseURL);
|
||||
}
|
||||
|
||||
void WebViewImpl::loadURL(const std::string &url) {
|
||||
JniHelper::callStaticVoidMethod(className, "loadUrl", _viewTag, url);
|
||||
}
|
||||
|
||||
void WebViewImpl::loadFile(const std::string &fileName) {
|
||||
auto fullPath = getUrlStringByFileName(fileName);
|
||||
JniHelper::callStaticVoidMethod(className, "loadFile", _viewTag, fullPath);
|
||||
}
|
||||
|
||||
void WebViewImpl::stopLoading() {
|
||||
JniHelper::callStaticVoidMethod(className, "stopLoading", _viewTag);
|
||||
}
|
||||
|
||||
void WebViewImpl::reload() {
|
||||
JniHelper::callStaticVoidMethod(className, "reload", _viewTag);
|
||||
}
|
||||
|
||||
bool WebViewImpl::canGoBack() {
|
||||
return JniHelper::callStaticBooleanMethod(className, "canGoBack", _viewTag);
|
||||
}
|
||||
|
||||
bool WebViewImpl::canGoForward() {
|
||||
return JniHelper::callStaticBooleanMethod(className, "canGoForward", _viewTag);
|
||||
}
|
||||
|
||||
void WebViewImpl::goBack() {
|
||||
JniHelper::callStaticVoidMethod(className, "goBack", _viewTag);
|
||||
}
|
||||
|
||||
void WebViewImpl::goForward() {
|
||||
JniHelper::callStaticVoidMethod(className, "goForward", _viewTag);
|
||||
}
|
||||
|
||||
void WebViewImpl::setJavascriptInterfaceScheme(const std::string &scheme) {
|
||||
JniHelper::callStaticVoidMethod(className, "setJavascriptInterfaceScheme", _viewTag,
|
||||
scheme);
|
||||
}
|
||||
|
||||
void WebViewImpl::evaluateJS(const std::string &js) {
|
||||
JniHelper::callStaticVoidMethod(className, "evaluateJS", _viewTag, js);
|
||||
}
|
||||
|
||||
void WebViewImpl::setScalesPageToFit(const bool scalesPageToFit) {
|
||||
JniHelper::callStaticVoidMethod(className, "setScalesPageToFit", _viewTag, scalesPageToFit);
|
||||
}
|
||||
|
||||
bool WebViewImpl::shouldStartLoading(const int viewTag, const std::string &url) {
|
||||
bool allowLoad = true;
|
||||
auto it = s_WebViewImpls.find(viewTag);
|
||||
if (it != s_WebViewImpls.end()) {
|
||||
auto webView = it->second->_webView;
|
||||
if (webView->_onShouldStartLoading) {
|
||||
allowLoad = webView->_onShouldStartLoading(webView, url);
|
||||
}
|
||||
}
|
||||
return allowLoad;
|
||||
}
|
||||
|
||||
void WebViewImpl::didFinishLoading(const int viewTag, const std::string &url) {
|
||||
auto it = s_WebViewImpls.find(viewTag);
|
||||
if (it != s_WebViewImpls.end()) {
|
||||
auto webView = it->second->_webView;
|
||||
if (webView->_onDidFinishLoading) {
|
||||
webView->_onDidFinishLoading(webView, url);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void WebViewImpl::didFailLoading(const int viewTag, const std::string &url) {
|
||||
auto it = s_WebViewImpls.find(viewTag);
|
||||
if (it != s_WebViewImpls.end()) {
|
||||
auto webView = it->second->_webView;
|
||||
if (webView->_onDidFailLoading) {
|
||||
webView->_onDidFailLoading(webView, url);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void WebViewImpl::onJsCallback(const int viewTag, const std::string &message) {
|
||||
auto it = s_WebViewImpls.find(viewTag);
|
||||
if (it != s_WebViewImpls.end()) {
|
||||
auto webView = it->second->_webView;
|
||||
if (webView->_onJSCallback) {
|
||||
webView->_onJSCallback(webView, message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void WebViewImpl::setVisible(bool visible) {
|
||||
JniHelper::callStaticVoidMethod(className, "setVisible", _viewTag, visible);
|
||||
}
|
||||
|
||||
void WebViewImpl::setFrame(float x, float y, float width, float height) {
|
||||
JniHelper::callStaticVoidMethod(className, "setWebViewRect", _viewTag,
|
||||
(int) x, (int) y, (int) width, (int) height);
|
||||
}
|
||||
|
||||
void WebViewImpl::setBounces(bool bounces) {
|
||||
// empty function as this was mainly a fix for iOS
|
||||
}
|
||||
|
||||
void WebViewImpl::setBackgroundTransparent(bool isTransparent) {
|
||||
JniHelper::callStaticVoidMethod(className, "setBackgroundTransparent", _viewTag,
|
||||
isTransparent);
|
||||
}
|
||||
|
||||
} //namespace cocos2d
|
94
cocos2d-x/cocos/ui/webview/WebViewImpl-android.h
Normal file
94
cocos2d-x/cocos/ui/webview/WebViewImpl-android.h
Normal file
@@ -0,0 +1,94 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2014-2016 Chukong Technologies Inc.
|
||||
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos2d-x.org
|
||||
|
||||
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 <iosfwd>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "base/ccMacros.h"
|
||||
#include "base/CCData.h"
|
||||
|
||||
NS_CC_BEGIN
|
||||
|
||||
class WebView;
|
||||
|
||||
class WebViewImpl {
|
||||
|
||||
public:
|
||||
WebViewImpl(cocos2d::WebView *webView);
|
||||
|
||||
virtual ~WebViewImpl();
|
||||
|
||||
void setJavascriptInterfaceScheme(const std::string &scheme);
|
||||
|
||||
void loadData(const cocos2d::Data &data, const std::string &MIMEType,
|
||||
const std::string &encoding, const std::string &baseURL);
|
||||
|
||||
void loadHTMLString(const std::string &string, const std::string &baseURL);
|
||||
|
||||
void loadURL(const std::string &url);
|
||||
|
||||
void loadFile(const std::string &fileName);
|
||||
|
||||
void stopLoading();
|
||||
|
||||
void reload();
|
||||
|
||||
bool canGoBack();
|
||||
|
||||
bool canGoForward();
|
||||
|
||||
void goBack();
|
||||
|
||||
void goForward();
|
||||
|
||||
void evaluateJS(const std::string &js);
|
||||
|
||||
void setScalesPageToFit(const bool scalesPageToFit);
|
||||
|
||||
virtual void setVisible(bool visible);
|
||||
|
||||
virtual void setFrame(float x, float y, float width, float height);
|
||||
|
||||
void setBounces(bool bounces);
|
||||
|
||||
void setBackgroundTransparent(bool isTransparent);
|
||||
|
||||
static bool shouldStartLoading(const int viewTag, const std::string &url);
|
||||
|
||||
static void didFinishLoading(const int viewTag, const std::string &url);
|
||||
|
||||
static void didFailLoading(const int viewTag, const std::string &url);
|
||||
|
||||
static void onJsCallback(const int viewTag, const std::string &message);
|
||||
|
||||
private:
|
||||
int _viewTag;
|
||||
WebView *_webView;
|
||||
};
|
||||
|
||||
NS_CC_END
|
||||
|
90
cocos2d-x/cocos/ui/webview/WebViewImpl-ios.h
Normal file
90
cocos2d-x/cocos/ui/webview/WebViewImpl-ios.h
Normal file
@@ -0,0 +1,90 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2014-2016 Chukong Technologies Inc.
|
||||
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos2d-x.org
|
||||
|
||||
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.
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef __COCOS2D_UI_WEBVIEWIMPL_IOS_H_
|
||||
#define __COCOS2D_UI_WEBVIEWIMPL_IOS_H_
|
||||
/// @cond DO_NOT_SHOW
|
||||
|
||||
#include <iosfwd>
|
||||
|
||||
@class UIWebViewWrapper;
|
||||
|
||||
namespace cocos2d {
|
||||
|
||||
class Data;
|
||||
|
||||
class WebView;
|
||||
|
||||
class WebViewImpl {
|
||||
public:
|
||||
WebViewImpl(WebView *webView);
|
||||
|
||||
virtual ~WebViewImpl();
|
||||
|
||||
void setJavascriptInterfaceScheme(const std::string &scheme);
|
||||
|
||||
void loadData(const cocos2d::Data &data,
|
||||
const std::string &MIMEType,
|
||||
const std::string &encoding,
|
||||
const std::string &baseURL);
|
||||
|
||||
void loadHTMLString(const std::string &string, const std::string &baseURL);
|
||||
|
||||
void loadURL(const std::string &url);
|
||||
|
||||
void loadFile(const std::string &fileName);
|
||||
|
||||
void stopLoading();
|
||||
|
||||
void reload();
|
||||
|
||||
bool canGoBack();
|
||||
|
||||
bool canGoForward();
|
||||
|
||||
void goBack();
|
||||
|
||||
void goForward();
|
||||
|
||||
void evaluateJS(const std::string &js);
|
||||
|
||||
void setScalesPageToFit(const bool scalesPageToFit);
|
||||
|
||||
virtual void setVisible(bool visible);
|
||||
|
||||
virtual void setFrame(float x, float y, float width, float height);
|
||||
|
||||
void setBounces(bool bounces);
|
||||
|
||||
void setBackgroundTransparent(bool isTransparent);
|
||||
|
||||
private:
|
||||
UIWebViewWrapper *_uiWebViewWrapper;
|
||||
WebView *_webView;
|
||||
};
|
||||
}//namespace cocos2d
|
||||
|
||||
/// @endcond
|
||||
#endif /* __COCOS2D_UI_WEBVIEWIMPL_IOS_H_ */
|
395
cocos2d-x/cocos/ui/webview/WebViewImpl-ios.mm
Normal file
395
cocos2d-x/cocos/ui/webview/WebViewImpl-ios.mm
Normal file
@@ -0,0 +1,395 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2014-2016 Chukong Technologies Inc.
|
||||
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos2d-x.org
|
||||
|
||||
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 "platform/CCPlatformConfig.h"
|
||||
|
||||
// Webview not available on tvOS
|
||||
#if (USE_WEB_VIEW > 0) && (CC_TARGET_PLATFORM == CC_PLATFORM_IOS) && !defined(CC_TARGET_OS_TVOS)
|
||||
|
||||
#import <WebKit/WKWebView.h>
|
||||
#import <WebKit/WKUIDelegate.h>
|
||||
#import <WebKit/WKNavigationDelegate.h>
|
||||
|
||||
#include "WebView-inl.h"
|
||||
#include "platform/CCApplication.h"
|
||||
#include "platform/ios/CCEAGLView-ios.h"
|
||||
#include "platform/CCFileUtils.h"
|
||||
|
||||
@interface UIWebViewWrapper : NSObject
|
||||
@property (nonatomic) std::function<bool(std::string url)> shouldStartLoading;
|
||||
@property (nonatomic) std::function<void(std::string url)> didFinishLoading;
|
||||
@property (nonatomic) std::function<void(std::string url)> didFailLoading;
|
||||
@property (nonatomic) std::function<void(std::string url)> onJsCallback;
|
||||
|
||||
@property(nonatomic, readonly, getter=canGoBack) BOOL canGoBack;
|
||||
@property(nonatomic, readonly, getter=canGoForward) BOOL canGoForward;
|
||||
|
||||
+ (instancetype)webViewWrapper;
|
||||
|
||||
- (void)setVisible:(bool)visible;
|
||||
|
||||
- (void)setBounces:(bool)bounces;
|
||||
|
||||
- (void)setFrameWithX:(float)x y:(float)y width:(float)width height:(float)height;
|
||||
|
||||
- (void)setJavascriptInterfaceScheme:(const std::string &)scheme;
|
||||
|
||||
- (void)loadData:(const std::string &)data MIMEType:(const std::string &)MIMEType textEncodingName:(const std::string &)encodingName baseURL:(const std::string &)baseURL;
|
||||
|
||||
- (void)loadHTMLString:(const std::string &)string baseURL:(const std::string &)baseURL;
|
||||
|
||||
- (void)loadUrl:(const std::string &)urlString;
|
||||
|
||||
- (void)loadFile:(const std::string &)filePath;
|
||||
|
||||
- (void)stopLoading;
|
||||
|
||||
- (void)reload;
|
||||
|
||||
- (void)evaluateJS:(const std::string &)js;
|
||||
|
||||
- (void)goBack;
|
||||
|
||||
- (void)goForward;
|
||||
|
||||
- (void)setScalesPageToFit:(const bool)scalesPageToFit;
|
||||
|
||||
- (void)setBackgroundTransparent:(const bool)isTransparent;
|
||||
@end
|
||||
|
||||
|
||||
@interface UIWebViewWrapper () <WKUIDelegate, WKNavigationDelegate>
|
||||
@property(nonatomic, assign) WKWebView *uiWebView;
|
||||
@property(nonatomic, copy) NSString *jsScheme;
|
||||
@end
|
||||
|
||||
@implementation UIWebViewWrapper {
|
||||
|
||||
}
|
||||
|
||||
+ (instancetype)webViewWrapper {
|
||||
return [[[self alloc] init] autorelease];
|
||||
}
|
||||
|
||||
- (instancetype)init {
|
||||
self = [super init];
|
||||
if (self) {
|
||||
self.uiWebView = nil;
|
||||
self.shouldStartLoading = nullptr;
|
||||
self.didFinishLoading = nullptr;
|
||||
self.didFailLoading = nullptr;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc {
|
||||
self.uiWebView.UIDelegate = nil;
|
||||
[self.uiWebView removeFromSuperview];
|
||||
[self.uiWebView release];
|
||||
self.jsScheme = nil;
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
- (void)setupWebView {
|
||||
if (!self.uiWebView) {
|
||||
self.uiWebView = [[WKWebView alloc] init];
|
||||
self.uiWebView.UIDelegate = self;
|
||||
self.uiWebView.navigationDelegate = self;
|
||||
}
|
||||
if (!self.uiWebView.superview) {
|
||||
auto eaglview = (CCEAGLView*)cocos2d::Application::getInstance()->getView();
|
||||
[eaglview addSubview:self.uiWebView];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)setVisible:(bool)visible {
|
||||
self.uiWebView.hidden = !visible;
|
||||
}
|
||||
|
||||
- (void)setBounces:(bool)bounces {
|
||||
self.uiWebView.scrollView.bounces = bounces;
|
||||
}
|
||||
|
||||
- (void)setFrameWithX:(float)x y:(float)y width:(float)width height:(float)height {
|
||||
if (!self.uiWebView) {[self setupWebView];}
|
||||
CGRect newFrame = CGRectMake(x, y, width, height);
|
||||
if (!CGRectEqualToRect(self.uiWebView.frame, newFrame)) {
|
||||
self.uiWebView.frame = CGRectMake(x, y, width, height);
|
||||
}
|
||||
}
|
||||
|
||||
- (void)setJavascriptInterfaceScheme:(const std::string &)scheme {
|
||||
self.jsScheme = @(scheme.c_str());
|
||||
}
|
||||
|
||||
- (void)loadData:(const std::string &)data MIMEType:(const std::string &)MIMEType textEncodingName:(const std::string &)encodingName baseURL:(const std::string &)baseURL {
|
||||
auto path = [[NSBundle mainBundle] resourcePath];
|
||||
path = [path stringByAppendingPathComponent:@(baseURL.c_str() )];
|
||||
auto url = [NSURL fileURLWithPath:path];
|
||||
|
||||
[self.uiWebView loadData:[NSData dataWithBytes:data.c_str() length:data.length()]
|
||||
MIMEType:@(MIMEType.c_str())
|
||||
characterEncodingName:@(encodingName.c_str())
|
||||
baseURL:url];
|
||||
}
|
||||
|
||||
- (void)loadHTMLString:(const std::string &)string baseURL:(const std::string &)baseURL {
|
||||
if (!self.uiWebView) {[self setupWebView];}
|
||||
auto path = [[NSBundle mainBundle] resourcePath];
|
||||
path = [path stringByAppendingPathComponent:@(baseURL.c_str() )];
|
||||
auto url = [NSURL fileURLWithPath:path];
|
||||
[self.uiWebView loadHTMLString:@(string.c_str()) baseURL:url];
|
||||
}
|
||||
|
||||
- (void)loadUrl:(const std::string &)urlString {
|
||||
if (!self.uiWebView) {[self setupWebView];}
|
||||
NSURL *url = [NSURL URLWithString:@(urlString.c_str())];
|
||||
NSURLRequest *request = [NSURLRequest requestWithURL:url];
|
||||
[self.uiWebView loadRequest:request];
|
||||
}
|
||||
|
||||
- (void)loadFile:(const std::string &)filePath {
|
||||
if (!self.uiWebView) {[self setupWebView];}
|
||||
NSURL *url = [NSURL fileURLWithPath:@(filePath.c_str())];
|
||||
NSURLRequest *request = [NSURLRequest requestWithURL:url];
|
||||
[self.uiWebView loadRequest:request];
|
||||
}
|
||||
|
||||
- (void)stopLoading {
|
||||
[self.uiWebView stopLoading];
|
||||
}
|
||||
|
||||
- (void)reload {
|
||||
[self.uiWebView reload];
|
||||
}
|
||||
|
||||
- (BOOL)canGoForward {
|
||||
return self.uiWebView.canGoForward;
|
||||
}
|
||||
|
||||
- (BOOL)canGoBack {
|
||||
return self.uiWebView.canGoBack;
|
||||
}
|
||||
|
||||
- (void)goBack {
|
||||
[self.uiWebView goBack];
|
||||
}
|
||||
|
||||
- (void)goForward {
|
||||
[self.uiWebView goForward];
|
||||
}
|
||||
|
||||
- (void)evaluateJS:(const std::string &)js {
|
||||
if (!self.uiWebView) {[self setupWebView];}
|
||||
[self.uiWebView evaluateJavaScript:@(js.c_str()) completionHandler:nil];
|
||||
}
|
||||
|
||||
- (void)setScalesPageToFit:(const bool)scalesPageToFit {
|
||||
// TODO: there is not corresponding API in WK.
|
||||
// https://stackoverflow.com/questions/26295277/wkwebview-equivalent-for-uiwebviews-scalespagetofit/43048514 seems has a solution,
|
||||
// but it doesn't support setting it dynamically. If we want to set this feature dynamically, then it will be too complex.
|
||||
}
|
||||
|
||||
- (void)setBackgroundTransparent:(const bool)isTransparent {
|
||||
if (!self.uiWebView) {[self setupWebView];}
|
||||
[self.uiWebView setOpaque:isTransparent ? NO : YES];
|
||||
[self.uiWebView setBackgroundColor:isTransparent ? [UIColor clearColor] : [UIColor whiteColor]];
|
||||
}
|
||||
|
||||
#pragma mark - WKNavigationDelegate
|
||||
- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler {
|
||||
NSString *url = [[navigationAction request].URL.absoluteString stringByRemovingPercentEncoding];
|
||||
NSString* scheme = [navigationAction request].URL.scheme;
|
||||
if ([scheme isEqualToString:self.jsScheme]) {
|
||||
self.onJsCallback(url.UTF8String);
|
||||
decisionHandler(WKNavigationActionPolicyCancel);
|
||||
return;
|
||||
}
|
||||
if (self.shouldStartLoading && url) {
|
||||
if (self.shouldStartLoading(url.UTF8String) )
|
||||
decisionHandler(WKNavigationActionPolicyAllow);
|
||||
else
|
||||
decisionHandler(WKNavigationActionPolicyCancel);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
decisionHandler(WKNavigationActionPolicyAllow);
|
||||
}
|
||||
|
||||
- (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation {
|
||||
if (self.didFinishLoading) {
|
||||
NSString *url = [webView.URL absoluteString];
|
||||
self.didFinishLoading([url UTF8String]);
|
||||
}
|
||||
}
|
||||
|
||||
- (void)webView:(WKWebView *)webView didFailProvisionalNavigation:(WKNavigation *)navigation withError:(NSError *)error {
|
||||
if (self.didFailLoading) {
|
||||
NSString *errorInfo = error.userInfo[NSURLErrorFailingURLStringErrorKey];
|
||||
if (errorInfo) {
|
||||
self.didFailLoading([errorInfo UTF8String]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#pragma WKUIDelegate
|
||||
|
||||
// Implement js alert function.
|
||||
- (void)webView:(WKWebView *)webView runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)())completionHandler
|
||||
{
|
||||
UIAlertController *alertController = [UIAlertController alertControllerWithTitle:message
|
||||
message:nil
|
||||
preferredStyle:UIAlertControllerStyleAlert];
|
||||
[alertController addAction:[UIAlertAction actionWithTitle:@"Ok"
|
||||
style:UIAlertActionStyleCancel
|
||||
handler:^(UIAlertAction *action) {
|
||||
completionHandler();
|
||||
}]];
|
||||
|
||||
auto rootViewController = [UIApplication sharedApplication].keyWindow.rootViewController;
|
||||
[rootViewController presentViewController:alertController animated:YES completion:^{}];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
|
||||
namespace cocos2d {
|
||||
|
||||
WebViewImpl::WebViewImpl(WebView *webView)
|
||||
: _uiWebViewWrapper([UIWebViewWrapper webViewWrapper]),
|
||||
_webView(webView) {
|
||||
[_uiWebViewWrapper retain];
|
||||
|
||||
_uiWebViewWrapper.shouldStartLoading = [this](std::string url) {
|
||||
if (this->_webView->_onShouldStartLoading) {
|
||||
return this->_webView->_onShouldStartLoading(this->_webView, url);
|
||||
}
|
||||
return true;
|
||||
};
|
||||
_uiWebViewWrapper.didFinishLoading = [this](std::string url) {
|
||||
if (this->_webView->_onDidFinishLoading) {
|
||||
this->_webView->_onDidFinishLoading(this->_webView, url);
|
||||
}
|
||||
};
|
||||
_uiWebViewWrapper.didFailLoading = [this](std::string url) {
|
||||
if (this->_webView->_onDidFailLoading) {
|
||||
this->_webView->_onDidFailLoading(this->_webView, url);
|
||||
}
|
||||
};
|
||||
_uiWebViewWrapper.onJsCallback = [this](std::string url) {
|
||||
if (this->_webView->_onJSCallback) {
|
||||
this->_webView->_onJSCallback(this->_webView, url);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
WebViewImpl::~WebViewImpl(){
|
||||
[_uiWebViewWrapper release];
|
||||
_uiWebViewWrapper = nullptr;
|
||||
}
|
||||
|
||||
void WebViewImpl::setJavascriptInterfaceScheme(const std::string &scheme) {
|
||||
[_uiWebViewWrapper setJavascriptInterfaceScheme:scheme];
|
||||
}
|
||||
|
||||
void WebViewImpl::loadData(const Data &data,
|
||||
const std::string &MIMEType,
|
||||
const std::string &encoding,
|
||||
const std::string &baseURL) {
|
||||
|
||||
std::string dataString(reinterpret_cast<char *>(data.getBytes()), static_cast<unsigned int>(data.getSize()));
|
||||
[_uiWebViewWrapper loadData:dataString MIMEType:MIMEType textEncodingName:encoding baseURL:baseURL];
|
||||
}
|
||||
|
||||
void WebViewImpl::loadHTMLString(const std::string &string, const std::string &baseURL) {
|
||||
[_uiWebViewWrapper loadHTMLString:string baseURL:baseURL];
|
||||
}
|
||||
|
||||
void WebViewImpl::loadURL(const std::string &url) {
|
||||
[_uiWebViewWrapper loadUrl:url];
|
||||
}
|
||||
|
||||
void WebViewImpl::loadFile(const std::string &fileName) {
|
||||
auto fullPath = cocos2d::FileUtils::getInstance()->fullPathForFilename(fileName);
|
||||
[_uiWebViewWrapper loadFile:fullPath];
|
||||
}
|
||||
|
||||
void WebViewImpl::stopLoading() {
|
||||
[_uiWebViewWrapper stopLoading];
|
||||
}
|
||||
|
||||
void WebViewImpl::reload() {
|
||||
[_uiWebViewWrapper reload];
|
||||
}
|
||||
|
||||
bool WebViewImpl::canGoBack() {
|
||||
return _uiWebViewWrapper.canGoBack;
|
||||
}
|
||||
|
||||
bool WebViewImpl::canGoForward() {
|
||||
return _uiWebViewWrapper.canGoForward;
|
||||
}
|
||||
|
||||
void WebViewImpl::goBack() {
|
||||
[_uiWebViewWrapper goBack];
|
||||
}
|
||||
|
||||
void WebViewImpl::goForward() {
|
||||
[_uiWebViewWrapper goForward];
|
||||
}
|
||||
|
||||
void WebViewImpl::evaluateJS(const std::string &js) {
|
||||
[_uiWebViewWrapper evaluateJS:js];
|
||||
}
|
||||
|
||||
void WebViewImpl::setBounces(bool bounces) {
|
||||
[_uiWebViewWrapper setBounces:bounces];
|
||||
}
|
||||
|
||||
void WebViewImpl::setScalesPageToFit(const bool scalesPageToFit) {
|
||||
[_uiWebViewWrapper setScalesPageToFit:scalesPageToFit];
|
||||
}
|
||||
|
||||
void WebViewImpl::setVisible(bool visible){
|
||||
[_uiWebViewWrapper setVisible:visible];
|
||||
}
|
||||
|
||||
void WebViewImpl::setFrame(float x, float y, float width, float height){
|
||||
auto eaglview = (CCEAGLView*)cocos2d::Application::getInstance()->getView();
|
||||
auto scaleFactor = [eaglview contentScaleFactor];
|
||||
[_uiWebViewWrapper setFrameWithX:x/scaleFactor
|
||||
y:y/scaleFactor
|
||||
width:width/scaleFactor
|
||||
height:height/scaleFactor];
|
||||
}
|
||||
|
||||
void WebViewImpl::setBackgroundTransparent(bool isTransparent){
|
||||
[_uiWebViewWrapper setBackgroundTransparent:isTransparent];
|
||||
}
|
||||
} //namespace cocos2d
|
||||
|
||||
#endif // (USE_WEB_VIEW > 0) && (CC_TARGET_PLATFORM == CC_PLATFORM_IOS) && !defined(CC_TARGET_OS_TVOS)
|
Reference in New Issue
Block a user