I have just seen the announcment of iPhone 5 and it says that the pixel resolution has changed to 1136*640, affecting in this way the ASPECT RATIO of the app.
How should I deal with this in my Cocos2d game? I got all the graphics done for the "old" 960*640 retina display screen and I guess that those will be distorted on the iPhone 5 screen.
Am I right? Or will there be the "old resolution" images shown without modifying the aspect ratio and leaving some screen black?
EDIT: Is there a way to get Cocos2d to detect if it is iPhone 5 and in that case draw the background files in the top part of the screen (top 960 pixels) and get some other custom background files to be drawn in the remaining pixels (e.g. those could be some custom ad banners or some extra buttons available in our Game only for iPhone 5).
I have just added 4 inch support to my app this morning. Cocos2d runs fine (in the simulator) with no modifications. All of my scenes have resized correctly, I just had to make a few modifications to some positions as they were fixed coordinates not relative.
There is currently no way to load different images easily, I suspect there will be a new naming convention similar to -hd in the next few days.
As for your edit question, you will probably find that once you enable the 4 inch mode your layout will have a large black space at the top already. Of course you can put whatever you want there.
You can detect if it is a tall screen using
[[UIScreen mainScreen] bounds].size.height
iOS will automatically place thin black bars on either side of the app
so it remains consistent with the way the apps were originally
designed for previous versions of the iPhone
Several sources report this, this is from here.
As of yet, with no devices nor iOS 6 being available, we don't even know if or which kind of modifications would need to be done to cocos2d to support iPhone 5. Stop worrying. Don't assume. Wait and see.
As with all other devices, there will be ways to detect the exact device type. Again, this would have to wait until we get at least iOS 6. You could join the beta program in hopes of finding out, but as long as its in beta such information is under NDA and you can only find out perhaps via the private Apple developer forums.
COCOS2d - v2.x
replace CCFileUtils.h and .m with following codes and add line inside delegate: [sharedFileUtils setiPhone5DisplaySuffix:#"-568h"]; // >>>>>> iPhone 5 -568h
.h
/*
* cocos2d for iPhone: http://www.cocos2d-iphone.org
*
* Copyright (c) 2008-2010 Ricardo Quesada
* Copyright (c) 2011 Zynga Inc.
*
* 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.
*
*/
#import <Foundation/Foundation.h>
#import "../ccTypes.h"
/** Helper class to handle file operations */
#interface CCFileUtils : NSObject
{
NSFileManager *fileManager_;
NSBundle *bundle_;
NSMutableDictionary *fullPathCache_;
NSMutableDictionary *removeSuffixCache_;
#ifdef __CC_PLATFORM_IOS
BOOL enableFallbackSuffixes_;
NSString *iPhoneRetinaDisplaySuffix_;
NSString *iPhone5DisplaySuffix_; // <<<<<<<<<<<<< ADDED
NSString *iPadSuffix_;
NSString *iPadRetinaDisplaySuffix_;
#endif // __CC_PLATFORM_IOS
}
/** NSBundle used by CCFileUtils. By default it uses [NSBundle mainBundle].
#since v2.0
*/
#property (nonatomic, readwrite, retain) NSBundle *bundle;
/** NSFileManager used by CCFileUtils. By default it uses its own intance.
#since v2.0
*/
#property (nonatomic, readwrite, retain) NSFileManager *fileManager;
#ifdef __CC_PLATFORM_IOS
/** The iPhone RetinaDisplay suffixes to load resources.
By default it is "-hd" and "" in that order.
Only valid on iOS. Not valid for OS X.
#since v1.1
*/
#property (nonatomic,readwrite, copy, setter = setiPhoneRetinaDisplaySuffix:) NSString *iPhoneRetinaDisplaySuffix;
/** The iPhone 5 suffixes to load resources.
By default it is "-hd" and "" in that order.
Only valid on iOS. Not valid for OS X.
#since v1.1
*/
#property (nonatomic,readwrite, copy, setter = setiPhone5DisplaySuffix:) NSString *iPhone5DisplaySuffix;
/** The iPad suffixes to load resources.
By default it is "-ipad", "-hd", "", in that order.
Only valid on iOS. Not valid for OS X.
#since v1.1
*/
#property (nonatomic,readwrite, copy, setter = setiPadSuffix:) NSString *iPadSuffix;
/** Sets the iPad Retina Display suffixes to load resources.
By default it is "-ipadhd", "-ipad", "-hd", "", in that order.
Only valid on iOS. Not valid for OS X.
#since v2.0
*/
#property (nonatomic,readwrite, copy, setter = setiPadRetinaDisplaySuffix:) NSString *iPadRetinaDisplaySuffix;
/** Whether of not the fallback sufixes is enabled.
When enabled it will try to search for the following suffixes in the following order until one is found:
* On iPad HD : iPad HD suffix, iPad suffix, iPhone HD suffix, Without suffix
* On iPad : iPad suffix, iPhone HD suffix, Without suffix
* On iPhone HD: iPhone HD suffix, Without suffix
By default this functionality is off;
*/
#property (nonatomic, readwrite) BOOL enableFallbackSuffixes;
#endif // __CC_PLATFORM_IOS
/** returns the shared file utils instance */
+(CCFileUtils*) sharedFileUtils;
/** Purge cached entries.
Will be called automatically by the Director when a memory warning is received
*/
-(void) purgeCachedEntries;
/** Returns the fullpath of an filename.
If in iPhoneRetinaDisplay mode, and a RetinaDisplay file is found, it will return that path.
If in iPad mode, and an iPad file is found, it will return that path.
Examples:
* In iPad mode: "image.png" -> "/full/path/image-ipad.png" (in case the -ipad file exists)
* In iPhone RetinaDisplay mode: "image.png" -> "/full/path/image-hd.png" (in case the -hd file exists)
* In iPad RetinaDisplay mode: "image.png" -> "/full/path/image-ipadhd.png" (in case the -ipadhd file exists)
*/
-(NSString*) fullPathFromRelativePath:(NSString*) relPath;
/** Returns the fullpath of an filename including the resolution of the image.
If in RetinaDisplay mode, and a RetinaDisplay file is found, it will return that path.
If in iPad mode, and an iPad file is found, it will return that path.
Examples:
* In iPad mode: "image.png" -> "/full/path/image-ipad.png" (in case the -ipad file exists)
* In iPhone RetinaDisplay mode: "image.png" -> "/full/path/image-hd.png" (in case the -hd file exists)
* In iPad RetinaDisplay mode: "image.png" -> "/full/path/image-ipadhd.png" (in case the -ipadhd file exists)
If an iPad file is found, it will set resolution type to kCCResolutioniPad
If a RetinaDisplay file is found, it will set resolution type to kCCResolutionRetinaDisplay
*/
-(NSString*) fullPathFromRelativePath:(NSString*)relPath resolutionType:(ccResolutionType*)resolutionType;
#ifdef __CC_PLATFORM_IOS
/** removes the suffix from a path
* On iPhone RetinaDisplay it will remove the -hd suffix
* On iPad it will remove the -ipad suffix
* On iPad RetinaDisplay it will remove the -ipadhd suffix
Only valid on iOS. Not valid for OS X.
#since v0.99.5
*/
-(NSString *)removeSuffixFromFile:(NSString*) path;
/** Returns whether or not a given path exists with the iPhone RetinaDisplay suffix.
Only available on iOS. Not supported on OS X.
#since v1.1
*/
-(BOOL) iPhoneRetinaDisplayFileExistsAtPath:(NSString*)filename;
/** Returns whether or not a given path exists with the iPhone 5 suffix.
Only available on iOS. Not supported on OS X.
#since v1.1
*/
-(BOOL) iPhone5DisplayFileExistsAtPath:(NSString*)filename;
/** Returns whether or not a given filename exists with the iPad suffix.
Only available on iOS. Not supported on OS X.
#since v1.1
*/
-(BOOL) iPadFileExistsAtPath:(NSString*)filename;
/** Returns whether or not a given filename exists with the iPad RetinaDisplay suffix.
Only available on iOS. Not supported on OS X.
#since v2.0
*/
-(BOOL) iPadRetinaDisplayFileExistsAtPath:(NSString*)filename;
#endif // __CC_PLATFORM_IOS
#end
#ifdef __cplusplus
extern "C" {
#endif
/** loads a file into memory.
the caller should release the allocated buffer.
#returns the size of the allocated buffer
#since v0.99.5
*/
NSInteger ccLoadFileIntoMemory(const char *filename, unsigned char **out);
#ifdef __cplusplus
}
#endif
.m
/*
* cocos2d for iPhone: http://www.cocos2d-iphone.org
*
* Copyright (c) 2008-2010 Ricardo Quesada
* Copyright (c) 2011 Zynga Inc.
*
* 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.
*
*/
#import "CCFileUtils.h"
#import "../CCConfiguration.h"
#import "../ccMacros.h"
#import "../ccConfig.h"
#import "../ccTypes.h"
enum {
kCCiPhone,
kCCiPhoneRetinaDisplay,
kCCiPhone5Display,
kCCiPad,
kCCiPadRetinaDisplay,
};
#pragma mark - Helper free functions
NSInteger ccLoadFileIntoMemory(const char *filename, unsigned char **out)
{
NSCAssert( out, #"ccLoadFileIntoMemory: invalid 'out' parameter");
NSCAssert( &*out, #"ccLoadFileIntoMemory: invalid 'out' parameter");
size_t size = 0;
FILE *f = fopen(filename, "rb");
if( !f ) {
*out = NULL;
return -1;
}
fseek(f, 0, SEEK_END);
size = ftell(f);
fseek(f, 0, SEEK_SET);
*out = malloc(size);
size_t read = fread(*out, 1, size, f);
if( read != size ) {
free(*out);
*out = NULL;
return -1;
}
fclose(f);
return size;
}
#pragma mark - CCCacheValue
#interface CCCacheValue : NSObject
{
NSString *fullpath_;
ccResolutionType resolutionType_;
}
#property (nonatomic, readwrite, retain) NSString *fullpath;
#property (nonatomic, readwrite ) ccResolutionType resolutionType;
#end
#implementation CCCacheValue
#synthesize fullpath = fullpath_, resolutionType = resolutionType_;
-(id) initWithFullPath:(NSString*)path resolutionType:(ccResolutionType)resolutionType
{
if( (self=[super init]) )
{
self.fullpath = path;
self.resolutionType = resolutionType;
}
return self;
}
- (void)dealloc
{
[fullpath_ release];
[super dealloc];
}
#end
#pragma mark - CCFileUtils
#ifdef __CC_PLATFORM_IOS
#interface CCFileUtils()
-(NSString *) removeSuffix:(NSString*)suffix fromPath:(NSString*)path;
-(BOOL) fileExistsAtPath:(NSString*)string withSuffix:(NSString*)suffix;
-(NSInteger) runningDevice;
#end
#endif // __CC_PLATFORM_IOS
#implementation CCFileUtils
#synthesize fileManager=fileManager_, bundle=bundle_;
#ifdef __CC_PLATFORM_IOS
#synthesize iPhoneRetinaDisplaySuffix = iPhoneRetinaDisplaySuffix_;
#synthesize iPhone5DisplaySuffix = iPhone5DisplaySuffix_;
#synthesize iPadSuffix = iPadSuffix_;
#synthesize iPadRetinaDisplaySuffix = iPadRetinaDisplaySuffix_;
#synthesize enableFallbackSuffixes = enableFallbackSuffixes_;
#endif // __CC_PLATFORM_IOS
+ (id)sharedFileUtils
{
static dispatch_once_t pred;
static CCFileUtils *fileUtils = nil;
dispatch_once(&pred, ^{
fileUtils = [[self alloc] init];
});
return fileUtils;
}
-(id) init
{
if( (self=[super init])) {
fileManager_ = [[NSFileManager alloc] init];
fullPathCache_ = [[NSMutableDictionary alloc] initWithCapacity:30];
removeSuffixCache_ = [[NSMutableDictionary alloc] initWithCapacity:30];
bundle_ = [[NSBundle mainBundle] retain];
#ifdef __CC_PLATFORM_IOS
iPhoneRetinaDisplaySuffix_ = #"-hd";
iPhone5DisplaySuffix_ = #"-568h";
iPadSuffix_ = #"-ipad";
iPadRetinaDisplaySuffix_ = #"-ipadhd";
enableFallbackSuffixes_ = NO;
#endif // __CC_PLATFORM_IOS
}
return self;
}
-(void) purgeCachedEntries
{
[fullPathCache_ removeAllObjects];
[removeSuffixCache_ removeAllObjects];
}
- (void)dealloc
{
[fileManager_ release];
[bundle_ release];
[fullPathCache_ release];
[removeSuffixCache_ release];
#ifdef __CC_PLATFORM_IOS
[iPhoneRetinaDisplaySuffix_ release];
[iPhone5DisplaySuffix_ release];
[iPadSuffix_ release];
[iPadRetinaDisplaySuffix_ release];
#endif // __CC_PLATFORM_IOS
[super dealloc];
}
-(NSString*) pathForResource:(NSString*)resource ofType:(NSString *)ext inDirectory:(NSString *)subpath
{
return [bundle_ pathForResource:resource
ofType:ext
inDirectory:subpath];
}
-(NSString*) getPath:(NSString*)path forSuffix:(NSString*)suffix
{
NSString *newName = path;
// only recreate filename if suffix is valid
if( suffix && [suffix length] > 0)
{
NSString *pathWithoutExtension = [path stringByDeletingPathExtension];
NSString *name = [pathWithoutExtension lastPathComponent];
// check if path already has the suffix.
if( [name rangeOfString:suffix].location == NSNotFound ) {
NSString *extension = [path pathExtension];
if( [extension isEqualToString:#"ccz"] || [extension isEqualToString:#"gz"] )
{
// All ccz / gz files should be in the format filename.xxx.ccz
// so we need to pull off the .xxx part of the extension as well
extension = [NSString stringWithFormat:#"%#.%#", [pathWithoutExtension pathExtension], extension];
pathWithoutExtension = [pathWithoutExtension stringByDeletingPathExtension];
}
newName = [pathWithoutExtension stringByAppendingString:suffix];
newName = [newName stringByAppendingPathExtension:extension];
} else
CCLOGWARN(#"cocos2d: WARNING Filename(%#) already has the suffix %#. Using it.", name, suffix);
}
NSString *ret = nil;
// only if it is not an absolute path
if( ! [path isAbsolutePath] ) {
// pathForResource also searches in .lproj directories. issue #1230
NSString *imageDirectory = [path stringByDeletingLastPathComponent];
// If the file does not exist it will return nil.
ret = [self pathForResource:[newName lastPathComponent]
ofType:nil
inDirectory:imageDirectory];
}
else if( [fileManager_ fileExistsAtPath:newName] )
ret = newName;
if( ! ret )
CCLOGINFO(#"cocos2d: CCFileUtils: file not found: %#", [newName lastPathComponent] );
return ret;
}
-(NSString*) fullPathFromRelativePath:(NSString*)relPath resolutionType:(ccResolutionType*)resolutionType
{
NSAssert(relPath != nil, #"CCFileUtils: Invalid path");
CCCacheValue *value = [fullPathCache_ objectForKey:relPath];
if( value ) {
*resolutionType = value.resolutionType;
return value.fullpath;
}
// Initialize to non-nil
NSString *ret = #"";
#ifdef __CC_PLATFORM_IOS
NSInteger device = [self runningDevice];
// iPad HD ?
if( device == kCCiPadRetinaDisplay ) {
ret = [self getPath:relPath forSuffix:iPadRetinaDisplaySuffix_];
*resolutionType = kCCResolutioniPadRetinaDisplay;
}
// iPad ?
if( device == kCCiPad || (enableFallbackSuffixes_ && !ret) ) {
ret = [self getPath:relPath forSuffix:iPadSuffix_];
*resolutionType = kCCResolutioniPad;
}
// iPhone HD ?
if( device == kCCiPhoneRetinaDisplay || (enableFallbackSuffixes_ && !ret) ) {
ret = [self getPath:relPath forSuffix:iPhoneRetinaDisplaySuffix_];
*resolutionType = kCCResolutioniPhoneRetinaDisplay;
}
// If it is not Phone HD, or if the previous "getPath" failed, then use iPhone images.
if( device == kCCiPhone || !ret )
{
ret = [self getPath:relPath forSuffix:#""];
*resolutionType = kCCResolutioniPhone;
}
#elif defined(__CC_PLATFORM_MAC)
*resolutionType = kCCResolutionMac;
ret = [self getPath:relPath forSuffix:#""];
#endif // __CC_PLATFORM_MAC
if( ! ret ) {
CCLOGWARN(#"cocos2d: Warning: File not found: %#", relPath);
ret = relPath;
}
value = [[CCCacheValue alloc] initWithFullPath:ret resolutionType:*resolutionType];
[fullPathCache_ setObject:value forKey:relPath];
[value release];
return ret;
}
-(NSString*) fullPathFromRelativePath:(NSString*) relPath
{
ccResolutionType ignore;
return [self fullPathFromRelativePath:relPath resolutionType:&ignore];
}
#pragma mark CCFileUtils - Suffix (iOS only)
#ifdef __CC_PLATFORM_IOS
// XXX: Optimization: This should be called only once
-(NSInteger) runningDevice
{
NSInteger ret=-1;
if( UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad)
{
if( CC_CONTENT_SCALE_FACTOR() == 2 )
ret = kCCiPadRetinaDisplay;
else
ret = kCCiPad;
}
else
{
if( CC_CONTENT_SCALE_FACTOR() == 2 )
if (([[UIScreen mainScreen] bounds].size.width == 640) || ([[UIScreen mainScreen] bounds].size.width == 1136))
{
ret = kCCiPhone5Display;
} else {
ret = kCCiPhoneRetinaDisplay;
}
else
ret = kCCiPhone;
}
return ret;
}
-(NSString *) removeSuffix:(NSString*)suffix fromPath:(NSString*)path
{
// quick return
if( ! suffix || [suffix length] == 0 )
return path;
NSString *name = [path lastPathComponent];
// check if path already has the suffix.
if( [name rangeOfString:suffix].location != NSNotFound ) {
CCLOGINFO(#"cocos2d: Filename(%#) contains %# suffix. Removing it. See cocos2d issue #1040", path, suffix);
NSString *newLastname = [name stringByReplacingOccurrencesOfString:suffix withString:#""];
NSString *pathWithoutLastname = [path stringByDeletingLastPathComponent];
return [pathWithoutLastname stringByAppendingPathComponent:newLastname];
}
// suffix was not removed
return nil;
}
-(NSString*) removeSuffixFromFile:(NSString*) path
{
NSString *withoutSuffix = [removeSuffixCache_ objectForKey:path];
if( withoutSuffix )
return withoutSuffix;
// Initial value should be non-nil
NSString *ret = #"";
NSInteger device = [self runningDevice];
if( device == kCCiPadRetinaDisplay )
ret = [self removeSuffix:iPadRetinaDisplaySuffix_ fromPath:path];
if( device == kCCiPad || (enableFallbackSuffixes_ && !ret) )
ret = [self removeSuffix:iPadSuffix_ fromPath:path];
if( device == kCCiPhoneRetinaDisplay || (enableFallbackSuffixes_ && !ret) )
ret = [self removeSuffix:iPhoneRetinaDisplaySuffix_ fromPath:path];
if( device == kCCiPhone5Display || (enableFallbackSuffixes_ && !ret) )
ret = [self removeSuffix:iPhone5DisplaySuffix_ fromPath:path];
if( device == kCCiPhone || !ret )
ret = path;
if( ret )
[removeSuffixCache_ setObject:ret forKey:path];
return ret;
}
-(BOOL) fileExistsAtPath:(NSString*)relPath withSuffix:(NSString*)suffix
{
NSString *fullpath = nil;
// only if it is not an absolute path
if( ! [relPath isAbsolutePath] ) {
// pathForResource also searches in .lproj directories. issue #1230
NSString *file = [relPath lastPathComponent];
NSString *imageDirectory = [relPath stringByDeletingLastPathComponent];
fullpath = [bundle_ pathForResource:file
ofType:nil
inDirectory:imageDirectory];
}
if (fullpath == nil)
fullpath = relPath;
NSString *path = [self getPath:fullpath forSuffix:suffix];
return ( path != nil );
}
-(BOOL) iPhoneRetinaDisplayFileExistsAtPath:(NSString*)path
{
return [self fileExistsAtPath:path withSuffix:iPhoneRetinaDisplaySuffix_];
}
-(BOOL) iPhone5DisplayFileExistsAtPath:(NSString*)path
{
return [self fileExistsAtPath:path withSuffix:iPhoneRetinaDisplaySuffix_];
}
-(BOOL) iPadFileExistsAtPath:(NSString*)path
{
return [self fileExistsAtPath:path withSuffix:iPadSuffix_];
}
-(BOOL) iPadRetinaDisplayFileExistsAtPath:(NSString*)path
{
return [self fileExistsAtPath:path withSuffix:iPadRetinaDisplaySuffix_];
}
#endif // __CC_PLATFORM_IOS
#end
All of you suggested good solutions but there will some sort of naming convention like #2x and h#2x for ratina display and iphone 5 launch images respectively.
Thanks
Mano
Related
I'm trying to add the RedLaser SDK to my project, and when trying to open the PickerController I get an error at:
0x39b70538: push {r4, r5, r6, r7, lr}.
This is the code how I instantiate the PickerController:
- (IBAction) redBoxScanButtonPressed
{
RLSampleViewControllerRequestVideoAuthorization(^void (void) {
RedBoxPickerController *redBoxPickerController =
[[RedBoxPickerController alloc] initWithNibName:#"RedBoxPickerController" bundle:nil];
redBoxPickerController.delegate = self;
// hide the status bar and show the scanner view
[[UIApplication sharedApplication] setStatusBarHidden:YES];
[self presentViewController:redBoxPickerController animated:NO completion:nil];// presentModalViewController:redBoxPickerController animated:FALSE];
//[redBoxPickerController release];
});
}
method to request Authorization:
static void RLSampleViewControllerRequestVideoAuthorization(dispatch_block_t completionHandler) {
RL_RequestVideoAuthorization(^void (RL_VideoAuthorizationStatus status) {
if (status == RL_VideoAuthorizationStatusAuthorized) {
dispatch_async(dispatch_get_main_queue(), ^void (void) {
completionHandler();
});
}
});
}
BackTrace
(lldb) bt
* thread #11: tid = 0xc81db, 0x39b70538 libc++abi.dylib`__cxa_throw, queue = 'ZXing', stop reason = breakpoint 1.2 * frame #0: 0x39b70538 libc++abi.dylib`__cxa_throw
frame #1: 0x00187e32 IRON TRAINERS`zxing::GlobalHistogramBinarizer::estimate(std::vector<int, std::allocator<int> >&) + 370
frame #2: 0x00187f60 IRON TRAINERS`zxing::GlobalHistogramBinarizer::getBlackMatrix() + 268
frame #3: 0x00186580 IRON TRAINERS`zxing::BinaryBitmap::getBlackMatrix() + 12
frame #4: 0x001a9b00 IRON TRAINERS`zxing::qrcode::QRCodeReader::decode(zxing::Ref<zxing::BinaryBitmap>, zxing::DecodeHints) + 44
frame #5: 0x001b086e IRON TRAINERS`zxing::Reader::decode(zxing::Ref<zxing::BinaryBitmap>) + 278
frame #6: 0x001b4a86 IRON TRAINERS`-[FormatReader decode:] + 142
frame #7: 0x00185da8 IRON TRAINERS`-[ZXingDecoder findCodesInBitmap:bytesPerRow:width:height:] + 796
frame #8: 0x001ba93e IRON TRAINERS`-[BarcodePhotoEngine zxingFindBarcodesInPixmap:] + 226
frame #9: 0x001b318c IRON TRAINERS`__38-[BarcodeEngine findBarcodesInPixMap:]_block_invoke55 + 76
frame #10: 0x0081e172 libdispatch.dylib`_dispatch_call_block_and_release + 10
frame #11: 0x00826d66 libdispatch.dylib`_dispatch_queue_drain + 1718
frame #12: 0x00820a60 libdispatch.dylib`_dispatch_queue_invoke + 88
frame #13: 0x00828b08 libdispatch.dylib`_dispatch_root_queue_drain + 1308
frame #14: 0x00829e18 libdispatch.dylib`_dispatch_worker_thread3 + 100
frame #15: 0x3a91adc0 libsystem_pthread.dylib`_pthread_wqthread + 668 (lldb)
I'm not sure what to look for, I've tried to add a few breakpoints but didn't find the problem.
The sample project works fine, so I guess I'm missing some code.
Here is the complete code of the PickerController:
/*******************************************************************************
RedBoxPickerController.m
Part of RLSample
This is a scan overlay example that frames discovered barcodes with red boxes.
Chall Fry
November 2012
Copyright (c) 2012 eBay Inc. All rights reserved.
*/
#import "RedBoxPickerController.h"
#implementation RedBoxPickerController
/*******************************************************************************
didReceiveMemoryWarning
*/
- (void) didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
}
/*******************************************************************************
viewWillAppear:
Sets up the initial state of UI elements in the overlay.
*/
- (void) viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
inRangeLabel.hidden = true;
numBarcodesFoundLabel.text = #"";
torchButton.enabled = self.hasTorch;
torchButton.style = self.isTorchOn ? UIBarButtonItemStyleDone :
UIBarButtonItemStyleBordered;
}
#pragma mark Button Handlers
/*******************************************************************************
cancelScan
Action proc for the 'Done' button.
*/
- (IBAction) cancelScan
{
[self doneScanning];
}
/*******************************************************************************
captureImage
Action proc for the 'Cap' button.
Need to have reportCameraImage enabled for this.
*/
- (IBAction) captureImage
{
if (!imageSaveInProgress)
{
[self requestCameraSnapshot:true];
savingImageLabel.hidden = false;
captureButton.enabled = false;
}
}
/*******************************************************************************
toggleFrontBackCamera
Action proc for the 'Front/Back' button.
*/
- (IBAction) toggleFrontBackCamera
{
self.useFrontCamera = !self.useFrontCamera;
}
/*******************************************************************************
toggleTorch
Action proc for the 'Light' button.
*/
- (IBAction) toggleTorch
{
[self turnTorch:!self.isTorchOn];
torchButton.style = self.isTorchOn ? UIBarButtonItemStyleDone :
UIBarButtonItemStyleBordered;
}
#pragma mark Status Updates
/*******************************************************************************
statusUpdated:
The RedLaser SDK will call this method repeatedly while scanning for barcodes.
*/
- (void) statusUpdated:(NSDictionary*) status
{
NSSet *foundBarcodes = [status objectForKey:#"FoundBarcodes"];
// Report how many barcodes we've found so far
numBarcodesFoundLabel.text = [NSString stringWithFormat:#"%d Barcodes found",
[foundBarcodes count]];
// Show the right guidance string for the guidance level
// Guidance is used for detecting long Code 39 codes in parts.
// See the documentation for more info.
int guidanceLevel = [[status objectForKey:#"Guidance"] intValue];
if (guidanceLevel == 1)
{
guidanceLabel.text = #"Try moving the camera close to each part of the barcode";
} else if (guidanceLevel == 2)
{
guidanceLabel.text = [NSString stringWithFormat:#"%#…",
[status objectForKey:#"PartialBarcode"]];
} else {
guidanceLabel.text = #"";
}
// Show the in range label if we're in range of an EAN barcode
inRangeLabel.hidden = ![[status objectForKey:#"InRange"] boolValue];
// Tell the Red Box View to update its display
redBoxView.barcodes = foundBarcodes;
[redBoxView setNeedsDisplay];
// If the user clicked the "Capture" button, this key will have a UIImage in it
// on a subsequent statusUpdated call. Otherwise, the key won't be present.
// If we have a camera image, save it to the device's photo album.
UIImage *cameraImage = [status objectForKey:#"CameraSnapshot"];
if (cameraImage && cameraImage != (id) [NSNull null])
{
imageSaveInProgress = true;
UIImageWriteToSavedPhotosAlbum(cameraImage, self,
#selector(image:didFinishSavingWithError:contextInfo:), nil);
}
}
/*******************************************************************************
image:didFinishSavingWithError:contextInfo:
Called when UIImageWriteToSavedPhotosAlbum() has finished saving an image to
the camera roll.
Reenables the Capture button and hides the "Saving Image..." label.
*/
- (void) image: (UIImage *) image didFinishSavingWithError: (NSError *) error
contextInfo: (void *) contextInfo
{
imageSaveInProgress = false;
savingImageLabel.hidden = true;
captureButton.enabled = true;
}
#end
#implementation RedBoxView
#synthesize barcodes;
/*******************************************************************************
drawRect:
RedBoxView is a UIView subclass that exists to override this method.
When it redraws itself, it looks for any barcodes in the found barcode set that
have been 'seen' in the last second, makes a UIBezierPath from the corner
locations of the barcode, and then fills and strokes the path.
*/
- (void) drawRect:(CGRect)rect
{
for (BarcodeResult *val in self.barcodes)
{
// Has this barcode been seen on-screen recently, or is it stale?
if ([val.mostRecentScanTime timeIntervalSinceNow] < -1.0)
{
continue;
}
// Don't bother displaying a path that only has 2 points--this is rare but can happen
if ([val.barcodeLocation count] < 2)
continue;
// Generate a UIBezierPath of the points, close it, and fill it
UIBezierPath *path = [UIBezierPath bezierPath];
[path moveToPoint:[[val.barcodeLocation objectAtIndex:0] CGPointValue]];
for (int index = 1; index < [val.barcodeLocation count]; ++index)
{
[path addLineToPoint:[[val.barcodeLocation objectAtIndex:index] CGPointValue]];
}
[path closePath];
[[UIColor colorWithRed:1.0 green:0.0 blue:0.0 alpha:0.2] set];
[path fill];
[[UIColor colorWithRed:1.0 green:0.0 blue:0.0 alpha:0.3] set];
[path stroke];
}
// Be sure to clear out the barcodes once we've drawn them
self.barcodes = nil;
}
- (void) didMoveToSuperview
{
CGRect superviewFrame = [[self superview] frame];
superviewFrame.origin.x = superviewFrame.origin.y = 0;
self.frame = superviewFrame;
[super didMoveToSuperview];
}
#end
You can "Enable Zombie Objects" in you application scheme. This will give you proper error messages.
Just Click on you application name ( Right side of stop button on xCode ) then click on Edit Scheme then click on RUN in left Panel now go to "Diagnostics" tab there you will see Memory Management header under which you can enable "Enable Zombie Objects".
Hope this will help you.
I am running an example code form a book, it is about using openCv on IOS device to do video processing. but I got "No viable overloaded '='" error, and i did search the StackOverFlow and found some similar posts and answers, but all solutions does not work for me, so I post code as below, and hope anyone can give some suggestions. Really appreciate it!
This is ViewController.h file:
#import <UIKit/UIKit.h>
#import <opencv2/imgcodecs/ios.h>
#import "CvEffects/RetroFilter.hpp"
#import <opencv2/videoio/cap_ios.h>
#interface ViewController : UIViewController<CvVideoCameraDelegate>
{
CvVideoCamera* videoCamera;
BOOL isCapturing;
RetroFilter::Parameters params;
cv::Ptr<RetroFilter> filter;
uint64_t prevTime;
}
#property (nonatomic, strong) CvVideoCamera* videoCamera;
#property (nonatomic, strong) IBOutlet UIImageView* imageView;
#property (nonatomic, strong) IBOutlet UIToolbar* toolbar;
#property (nonatomic, weak) IBOutlet
UIBarButtonItem* startCaptureButton;
#property (nonatomic, weak) IBOutlet
UIBarButtonItem* stopCaptureButton;
-(IBAction)startCaptureButtonPressed:(id)sender;
-(IBAction)stopCaptureButtonPressed:(id)sender;
#end
This is the ViewController.m file:
#import "ViewController.h"
#import <mach/mach_time.h>
#interface ViewController ()
#end
#implementation ViewController
#synthesize imageView;
#synthesize startCaptureButton;
#synthesize toolbar;
#synthesize videoCamera;
- (void)viewDidLoad
{
[super viewDidLoad];
// Initialize camera
videoCamera = [[CvVideoCamera alloc]
initWithParentView:imageView];
videoCamera.delegate = self;
videoCamera.defaultAVCaptureDevicePosition =
AVCaptureDevicePositionFront;
videoCamera.defaultAVCaptureSessionPreset =
AVCaptureSessionPreset352x288;
videoCamera.defaultAVCaptureVideoOrientation =
AVCaptureVideoOrientationPortrait;
videoCamera.defaultFPS = 30;
isCapturing = NO;
// Load textures
UIImage* resImage = [UIImage imageNamed:#"scratches.png"];
UIImageToMat(resImage, params.scratches);
resImage = [UIImage imageNamed:#"fuzzy_border.png"];
UIImageToMat(resImage, params.fuzzyBorder);
filter = NULL;
prevTime = mach_absolute_time();
}
- (NSInteger)supportedInterfaceOrientations
{
// Only portrait orientation
return UIInterfaceOrientationMaskPortrait;
}
-(IBAction)startCaptureButtonPressed:(id)sender
{
[videoCamera start];
isCapturing = YES;
params.frameSize = cv::Size(videoCamera.imageWidth,
videoCamera.imageHeight);
if (!filter)
filter = new RetroFilter(params);
}
-(IBAction)stopCaptureButtonPressed:(id)sender
{
[videoCamera stop];
isCapturing = NO;
}
//TODO: may be remove this code
static double machTimeToSecs(uint64_t time)
{
mach_timebase_info_data_t timebase;
mach_timebase_info(&timebase);
return (double)time * (double)timebase.numer /
(double)timebase.denom / 1e9;
}
// Macros for time measurements
#if 1
#define TS(name) int64 t_##name = cv::getTickCount()
#define TE(name) printf("TIMER_" #name ": %.2fms\n", \
1000.*((cv::getTickCount() - t_##name) / cv::getTickFrequency()))
#else
#define TS(name)
#define TE(name)
#endif
- (void)processImage:(cv::Mat&)image
{
cv::Mat inputFrame = image;
BOOL isNeedRotation = image.size() != params.frameSize;
if (isNeedRotation)
inputFrame = image.t();
// Apply filter
cv::Mat finalFrame;
TS(ApplyingFilter);
filter->applyToVideo(inputFrame, finalFrame);
TE(ApplyingFilter);
if (isNeedRotation)
finalFrame = finalFrame.t();
// Add fps label to the frame
uint64_t currTime = mach_absolute_time();
double timeInSeconds = machTimeToSecs(currTime - prevTime);
prevTime = currTime;
double fps = 1.0 / timeInSeconds;
NSString* fpsString =
[NSString stringWithFormat:#"FPS = %3.2f", fps];
cv::putText(finalFrame, [fpsString UTF8String],
cv::Point(30, 30), cv::FONT_HERSHEY_COMPLEX_SMALL,
0.8, cv::Scalar::all(255));
finalFrame.copyTo(image);
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (void)viewDidDisappear:(BOOL)animated
{
[super viewDidDisappear:animated];
if (isCapturing)
{
[videoCamera stop];
}
}
- (void)dealloc
{
videoCamera.delegate = nil;
}
#end
And I got the error at two statements:
filter = NULL;
and
filter = new RetroFilter(params);
First issue, assigning the pointer:
filter = Ptr<RetroFilter>(new RetroFilter(params));
Second issue, Nulling the pointer:
filter = cv::Ptr<RetroFilter>::Ptr();
The reason is that the cv::Ptr object does not have overrides that make this simpler. The standard library's smart pointer class does a much nicer job of being easy to use.
The first issue is that the only = operator provided is this:
Ptr& operator = (const Ptr& ptr);
This means that you can't assign a RetroFilter to it, only another cv::Ptr, so you need to wrap the RetroFilter already.
The second issue, similar to the first, there is no override = operator that takes NULL. The best way to express a null cv::Ptr is
cv::Ptr<RetroFilter>::Ptr();
Which, being an instance of cv::Ptr can be assigned using the '=' operator.
Glad I could help!
Many thanks to #KirkSpaziani.
I figured that following code works, but do not know why?
Try filter = cv::Ptr<RetroFilter>(new RetroFilter(params);
filter = cv::Ptr<RetroFilter>::Ptr()
I am trying to use ephemeral NSURLSessions to provide separate cookie handling for several tasks within my app. These tasks are not directly bound to a UI.
Problem: Whatever I do, the cookieAcceptPolicy of the ephemeral NSHTTPCookieStorage remains NSHTTPCookieAcceptPolicyNever.
Here's my code:
// use a pure in-memory configuration with its own private cache, cookie, and credential store
__block NSURLSessionConfiguration* config = [NSURLSessionConfiguration ephemeralSessionConfiguration];
// do anything to accept all cookies
config.HTTPShouldSetCookies = YES;
config.HTTPCookieAcceptPolicy = NSHTTPCookieAcceptPolicyAlways;
config.HTTPCookieStorage.cookieAcceptPolicy = NSHTTPCookieAcceptPolicyAlways;
__block NSURLSession* session = [NSURLSession sessionWithConfiguration:config];
NSURLSessionDataTask* task = [session dataTaskWithURL:[NSURL URLWithString:#"https://test.cgmlife.com/Catalogs"]
completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
NSHTTPCookieStorage* cookies = session.configuration.HTTPCookieStorage;
NSLog(#"%#", cookies);
NSLog(#"%lu", cookies.cookieAcceptPolicy);
}];
[task resume];
The output from NSLog is always:
Ephemeral <NSHTTPCookieStorage cookies count:0>
1
where 1 is the value for NSHTTPCookieAcceptPolicyNever (expected 0 for NSHTTPCookieAcceptPolicyAlways). The headers in the response are there.
What can I do to have the NSHTTPCookieStorage remember my cookies while the session is alive? I don't need and don't want any persistence. I just want to keep cookies in memory so that they are reused for further requests in the same session.
It looks like ephemeral sessions don't store cookies ever. eskimo1 says on the devforums:
ISTR that ephemeral session configurations don't work the way that
folks expect based on the documentation. I never got around to
looking at this in detail but it seems like you have. You should file
a bug about this; the implementation and documentation are clearly out
of sync, so one of them needs to be fixed.
It looks like the iOS9 ephemeralSessionConfiguration works as expected. On iOS8 though, it seems like the cookie storage returns Never for its policy and it can't be reset. The implementation appears to be no-storage despite the private class name, instead of memory-only.
For iOS8, I was able to substitute a rudimentary implementation though, and it seems to work (at least in the simulator with light testing). Implementing the new methods that take task objects was essential.
#import <Foundation/Foundation.h>
#interface MemoryCookieStorage : NSHTTPCookieStorage
#property (nonatomic, strong) NSMutableArray *internalCookies;
#property (atomic, assign) NSHTTPCookieAcceptPolicy policy;
#end
#implementation MemoryCookieStorage
- (id)init
{
if (self = [super init]) {
_internalCookies = [NSMutableArray new];
_policy = NSHTTPCookieAcceptPolicyOnlyFromMainDocumentDomain;
}
return self;
}
- (NSHTTPCookieAcceptPolicy)cookieAcceptPolicy {
return self.policy;
}
- (void)setCookieAcceptPolicy:(NSHTTPCookieAcceptPolicy)cookieAcceptPolicy {
self.policy = cookieAcceptPolicy;
}
- (NSUInteger)_indexOfCookie:(NSHTTPCookie *)target
{
return [_internalCookies indexOfObjectPassingTest:^BOOL(NSHTTPCookie *cookie, NSUInteger idx, BOOL *stop) {
return ([target.name caseInsensitiveCompare:cookie.name] == NSOrderedSame &&
[target.domain caseInsensitiveCompare:cookie.domain] == NSOrderedSame &&
(target.path == cookie.path || [target.path isEqual:cookie.path]));
}];
}
- (void)setCookie:(NSHTTPCookie *)cookie
{
if (self.cookieAcceptPolicy != NSHTTPCookieAcceptPolicyNever)
{
#synchronized(_internalCookies) {
NSInteger idx = [self _indexOfCookie:cookie];
if (idx == NSNotFound)
[_internalCookies addObject:cookie];
else
[_internalCookies replaceObjectAtIndex:idx withObject:cookie];
}
}
}
- (void)deleteCookie:(NSHTTPCookie *)cookie
{
#synchronized(_internalCookies) {
NSInteger idx = [self _indexOfCookie:cookie];
if (idx != NSNotFound)
[_internalCookies removeObjectAtIndex:idx];
}
}
- (NSArray *)cookies
{
#synchronized(_internalCookies) {
return [_internalCookies copy];
}
}
static BOOL HasCaseSuffix(NSString *string, NSString *suffix)
{
return [string rangeOfString:suffix options:NSCaseInsensitiveSearch|NSAnchoredSearch|NSBackwardsSearch].length > 0;
}
static BOOL IsDomainOK(NSString *cookieDomain, NSString *host)
{
return ([cookieDomain caseInsensitiveCompare:host] == NSOrderedSame ||
([cookieDomain hasPrefix:#"."] && HasCaseSuffix(host, cookieDomain)) ||
(cookieDomain && HasCaseSuffix(host, [#"." stringByAppendingString:cookieDomain])));
}
- (NSArray *)cookiesForURL:(NSURL *)URL
{
NSMutableArray *array = [NSMutableArray new];
NSString *host = URL.host;
NSString *path = URL.path;
#synchronized(_internalCookies)
{
for (NSHTTPCookie *cookie in _internalCookies)
{
if (!IsDomainOK(cookie.domain, host))
continue;
BOOL pathOK = cookie.path.length == 0 || [cookie.path isEqual:#"/"] || [path hasPrefix:cookie.path];
if (!pathOK)
continue;
if (cookie.isSecure && [URL.scheme caseInsensitiveCompare:#"https"] != NSOrderedSame)
continue;
if ([cookie.expiresDate timeIntervalSinceNow] > 0)
continue;
[array addObject:cookie];
}
}
array = (id)[array sortedArrayUsingComparator:^NSComparisonResult(NSHTTPCookie *c1, NSHTTPCookie *c2) {
/* More specific cookies, i.e. matching the longest portion of the path, come first */
NSInteger path1 = c1.path.length;
NSInteger path2 = c2.path.length;
if (path1 > path2)
return NSOrderedAscending;
if (path2 > path1)
return NSOrderedDescending;
return [c1.name caseInsensitiveCompare:c2.name];
}];
return array;
}
- (NSArray *)sortedCookiesUsingDescriptors:(NSArray *)sortOrder
{
return [[self cookies] sortedArrayUsingDescriptors:sortOrder];
}
- (void)getCookiesForTask:(NSURLSessionTask *)task completionHandler:(void (^) (NSArray *taskCookies))completionHandler
{
NSArray *urlCookies = [self cookiesForURL:task.currentRequest.URL];
completionHandler(urlCookies);
}
- (void)setCookies:(NSArray *)newCookies forURL:(NSURL *)URL mainDocumentURL:(NSURL *)mainDocumentURL
{
NSString *host = mainDocumentURL.host;
for (NSHTTPCookie *cookie in newCookies)
{
switch (self.cookieAcceptPolicy)
{
case NSHTTPCookieAcceptPolicyAlways:
[self setCookie:cookie];
break;
case NSHTTPCookieAcceptPolicyNever:
break;
case NSHTTPCookieAcceptPolicyOnlyFromMainDocumentDomain:
if (IsDomainOK(cookie.domain, host))
[self setCookie:cookie];
break;
}
}
}
- (void)storeCookies:(NSArray *)taskCookies forTask:(NSURLSessionTask *)task
{
NSURL *mainURL = task.currentRequest.mainDocumentURL ?: task.originalRequest.mainDocumentURL ?: task.originalRequest.URL;
[self setCookies:taskCookies forURL:task.currentRequest.URL mainDocumentURL:mainURL];
}
#end
It should be possible to test sessionConfiguration.HTTPCookieStorage.cookieAcceptPolicy == NSHTTPCookieAcceptPolicyNever after creating the ephemeral session to see if the HTTPCookieStorage needs to be replaced with an instance of the above class (shouldn't need it on iOS9). There are probably some bugs... I just needed this for a demo and it worked well enough for that. But they shouldn't be too hard to fix if any come up.
I am trying to generate bar graph using JSON Data which i am getting from Web-services, basically my requirement is to show a "Bar Graph" using "JSON" data.
Basically I am Android Developer and very new to Blackberry 10 Native, so i don't know much about Blackberry, So If any one can guide me regarding generating graph in Blackberry-10.
I have searched a lot in google and every where else where i can, but i didn't come with any conclusion. Still i am searching a solution for it, So basically my "JSON" data is in following format.
{"Ax":"3:41","Ay":"04:41","Bx":"10:47 ","By":"12:47","Cx":"18:30","Cy":"19:30","Az":3,"Bz":2,"Cz":1,"condition":2}
Here "Ax":"3:41","Ay":"04:41" this is parameter is hour of starting and ending work, and at last it calculates the total number of hour like "Az":3,"Bz":2,"Cz":1 and generate graph based on that. So similarly my graph would look something like this
http://postimg.org/image/nb6dnpwax/
Please help me how can i generate graph based on this, some of the link which i have refered to generate graph is
http://elycharts.com/examples
http://g.raphaeljs.com/
How to make charts/graphs (such as line graphs, bar graphs, circle graphs), etc. in C++, Qt, QML, Blackberry 10 Cascades Beta 3 SDK?
http://devblog.blackberry.com/2014/01/conference-app-secrets-part-3-json-vs-xml/
One thing i am clearly mentioning is i want solution using qml and C++ way with Blackberry-10 so please do not suggest any other method like Java and other all.
Thank you in advance for helping me out.
So there is this article on BlackBerry Support Forums. All the basics are there, but I do so much work with runtime generated images I decided to create a class to encapsulate it. As requested here is a simple sample based on one of the Cascades templates. You should also become familiar with the documentation at:
http://qt-project.org/doc/qt-4.8/
https://developer.blackberry.com/native/documentation/cascades/
And the sample files at the BlackBerry GIT Hub.
QML file:
/*
* Copyright (c) 2011-2014 BlackBerry Limited.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import bb.cascades 1.2
Page {
Container {
layout: DockLayout {
}
Label {
// Localized text with the dynamic translation and locale updates support
text: qsTr("Bar Graph") + Retranslate.onLocaleOrLanguageChanged
textStyle.base: SystemDefaults.TextStyles.BigText
horizontalAlignment: HorizontalAlignment.Center
}
ImageView {
objectName: "barGraph"
verticalAlignment: VerticalAlignment.Center
horizontalAlignment: HorizontalAlignment.Center
}
}
}
Here is the header file:
/*
* DrawableImage.hpp
*
* Created on: Jul 11, 2014
* Author: richard
*/
#ifndef DRAWABLEIMAGE_HPP_
#define DRAWABLEIMAGE_HPP_
#include <bb/ImageData>
#include <QtGui/QImage>
#include <bb/cascades/ImageView>
namespace net
{
namespace test
{
class DrawableImage : public QImage
{
public:
DrawableImage();
DrawableImage(QSize imageSize, QImage::Format format);
virtual ~DrawableImage();
void emitRenderingBegin();
void emitRenderingFinished();
DrawableImage& operator = (const QImage &image) { QImage::operator =(image); return *this; }
QPainter &painter();
public:
void updateToView(bb::cascades::ImageView *imageView);
private:
void deleteBuffer();
QPainter m_painter;
QSize m_sizeInPixels;
unsigned char* m_buffer; // pixel data in PixelBufferData format
};
} /* namespace test */
} /* namespace net */
#endif /* DRAWABLEIMAGE_HPP_ */
And the cpp file:
/*
* DrawableImage.cpp
*
* Created on: Jul 11, 2014
* Author: richard
*/
#include <src/DrawableImage.hpp>
namespace net
{
namespace test
{
DrawableImage::DrawableImage()
: m_painter(), m_sizeInPixels(0,0), m_buffer(NULL)
{
// TODO Auto-generated constructor stub
}
DrawableImage::DrawableImage(QSize imageSize, QImage::Format format)
: QImage(imageSize, format), m_painter(), m_sizeInPixels(0,0), m_buffer(NULL)
{
}
DrawableImage::~DrawableImage() {
// TODO Auto-generated destructor stub
}
/*
void DrawableImage::emitRenderingBegin() {
emit renderingBegin();
}
void DrawableImage::emitRenderingFinished() {
emit renderingFinished();
}
*/
QPainter& DrawableImage::painter() {
if (!m_painter.isActive()) {
m_painter.begin(this);
}
return m_painter;
}
void DrawableImage::deleteBuffer()
{
if (m_buffer != 0)
{
delete [] m_buffer;
m_buffer = 0;
}
}
void DrawableImage::updateToView(bb::cascades::ImageView *imageView) {
if (m_painter.isActive()) {
m_painter.end();
}
Q_ASSERT(imageView != NULL);
QImage swapped = rgbSwapped();
QSize swappedSize = swapped.size();
int w = swappedSize.width();
int h = swappedSize.height();
int numBytes = w * h * 4;
if (swappedSize != m_sizeInPixels)
{
deleteBuffer();
m_sizeInPixels = QSize(w, h);
m_buffer = new uchar[numBytes];
}
// Copy the memory over.
// We'll add defensive code in case rgbSwapped has a different size
const uchar* from = swapped.constBits();
int numFromBytes = swapped.numBytes();
int numToCopy = std::min(numFromBytes, numBytes);
memcpy(m_buffer, from, numToCopy);
if (numToCopy < numBytes)
{
memset(m_buffer + numToCopy, 0x00, numBytes - numToCopy);
}
bb::ImageData imageData = bb::ImageData::fromPixels(m_buffer, bb::PixelFormat::RGBA_Premultiplied,
m_sizeInPixels.width(),
m_sizeInPixels.height(),
m_sizeInPixels.width() * 4);
imageView->setImage(imageData);
}
} /* namespace test */
} /* namespace net */
And here is the applicationui.cpp (applicationui.hpp is not modified):
/*
* Copyright (c) 2011-2014 BlackBerry Limited.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "applicationui.hpp"
#include <bb/cascades/Application>
#include <bb/cascades/QmlDocument>
#include <bb/cascades/AbstractPane>
#include <bb/cascades/LocaleHandler>
#include <src/DrawableImage.hpp>
using namespace bb::cascades;
using namespace net::test;
ApplicationUI::ApplicationUI() :
QObject()
{
// prepare the localization
m_pTranslator = new QTranslator(this);
m_pLocaleHandler = new LocaleHandler(this);
bool res = QObject::connect(m_pLocaleHandler, SIGNAL(systemLanguageChanged()), this, SLOT(onSystemLanguageChanged()));
// This is only available in Debug builds
Q_ASSERT(res);
// Since the variable is not used in the app, this is added to avoid a
// compiler warning
Q_UNUSED(res);
// initial load
onSystemLanguageChanged();
// Create scene document from main.qml asset, the parent is set
// to ensure the document gets destroyed properly at shut down.
QmlDocument *qml = QmlDocument::create("asset:///main.qml").parent(this);
// Create root object for the UI
AbstractPane *root = qml->createRootObject<AbstractPane>();
/*
* This code exercises the DrawableImage
*/
QSize graphImageSize(700, 700);
DrawableImage graph;
ImageView* graphImageView = root->findChild<ImageView*>("barGraph");
// Initialise graph and fill with transparent black.
graph = QImage(graphImageSize, QImage::Format_ARGB32_Premultiplied);
graph.fill(Qt::black);
// Set the background mode
graph.painter().setBackgroundMode(Qt::TransparentMode);
// Set rendering hints
graph.painter().setRenderHint(QPainter::Antialiasing, true);
for (int i = 0; i < 10; i++) {
int x = i * (graphImageSize.width()/10);
int h = i * (graphImageSize.height()/10) + graphImageSize.height()/20;
int w = graphImageSize.width()/10 - 20;
graph.painter().fillRect( x + 10, graphImageSize.height()-h, w, h, Qt::darkGreen);
}
// Once the image is drawn transfer it to the Cascades ImageView
graph.updateToView(graphImageView);
// Set created root object as the application scene
Application::instance()->setScene(root);
}
void ApplicationUI::onSystemLanguageChanged()
{
QCoreApplication::instance()->removeTranslator(m_pTranslator);
// Initiate, load and install the application translation files.
QString locale_string = QLocale().name();
QString file_name = QString("BarGraph_%1").arg(locale_string);
if (m_pTranslator->load(file_name, "app/native/qm")) {
QCoreApplication::instance()->installTranslator(m_pTranslator);
}
}
You will also need to add a LIBS line to the .pro file:
APP_NAME = BarGraph
CONFIG += qt warn_on cascades10
LIBS += -lbb
include(config.pri)
This is the result:
Is it possible to use UIAutomation with cocos2d or any opengl application for that matter?
Specifically I want to use the zucchini framework to test my cocos2d game but that just uses UIAutomation anyway.
You can create custom steps in Zucchini and specify the coordinates to tap, e.g.
'Choose the red bird' : ->
target.tap({x:278, y:36})
'Press Fire' : ->
target.tap({x:170, y:260})
So, I got started with calabash-iOS and expanding on its backdoor. This is just for starters but with this you can get the accessibility label of the current CCScene, so you can check what screen is currently on and thus use for scripting actions. I'm not used to working with objc runtime, but as you can see it's possible to get properties, methods etc. A bit more digging and it should be possible to wrap more functionality, and hopefully something to wrap the cocos2d CCNode structure as well. This is a work in progress.
To use this you need to install https://github.com/calabash/calabash-ios and then implement the below function in the app delegate. Don't forget to set .accessibilityLabel to something like #"menu", #"game" or similar in your code. Optimally, only for the *-cal target, you don't want this code in production builds.
-(NSString*)calabashBackdoor:(NSString*)aIgnorable {
DLog(#"calabashBackdoor: %#", aIgnorable);
// UIApplication* app = [UIApplication sharedApplication];
if (aIgnorable != nil) {
NSArray* p = [aIgnorable componentsSeparatedByString:#" "];
NSString* command = [p objectAtIndex:0];
if ([command isEqualToString:#"getCurrentSceneLabel"]) {
CCDirector* director = [CCDirector sharedDirector];
DLog(#"director.runningScene.accessibilityLabel: %#", director.runningScene.accessibilityLabel);
return director.runningScene.accessibilityLabel;
}
else if ([command isEqualToString:#"class_copyMethodList"]) {
CCDirector* director = [CCDirector sharedDirector];
id inspectThisObject = director.runningScene;
DLog(#"inspectThisObject: %#, %#", [inspectThisObject class], inspectThisObject);
unsigned int count;
// To get the class methods of a class, use class_copyMethodList(object_getClass(cls), &count).
Method* methods = class_copyMethodList(object_getClass(inspectThisObject), &count);
//NSMutableString* returnstring = [NSMutableString string];
NSMutableArray* arrayOfMethodnames = [NSMutableArray array];
if (methods != NULL) {
for (int i = 0; i < count; i++) {
Method method = methods[i];
NSString* stringMethod = NSStringFromSelector(method_getName(method)); //NSStringFromSelector(method->method_name);
[arrayOfMethodnames addObject:stringMethod];
}
// An array of pointers of type Method describing the instance methods implemented by the class—any instance methods implemented by superclasses are not included. The array contains *outCount pointers followed by a NULL terminator. You must free the array with free().
free(methods);
}
DLog(#"arrayOfMethodnames: %#", arrayOfMethodnames);
return [arrayOfMethodnames componentsJoinedByString:#","];
}
else if ([command isEqualToString:#"class_copyPropertyList"]) {
CCDirector* director = [CCDirector sharedDirector];
id inspectThisObject = director.runningScene;
DLog(#"inspectThisObject: %#, %#", [inspectThisObject class], inspectThisObject);
unsigned int count;
// An array of pointers of type objc_property_t describing the properties declared by the class. Any properties declared by superclasses are not included. The array contains *outCount pointers followed by a NULL terminator. You must free the array with free().
//
// If cls declares no properties, or cls is Nil, returns NULL and *outCount is 0.
//
objc_property_t* properties = class_copyPropertyList(object_getClass(inspectThisObject), &count);
NSMutableArray* arrayOfProperties = [NSMutableArray array];
if (properties != NULL) {
for (int i = 0; i < count; i++) {
objc_property_t property = properties[i];
const char* CCS = property_getName(property);
NSString* str = [NSString stringWithUTF8String:CCS];
[arrayOfProperties addObject:str];
}
free(properties);
}
DLog(#"arrayOfProperties: %#", arrayOfProperties);
return [arrayOfProperties componentsJoinedByString:#","];
}
else {
DLog(#"Unhandled command: %#", command);
}
}
return #"calabashBackdoor nil!";
}
In Prefix.pch put this
#ifdef DEBUG
# define DLog( s, ... ) NSLog( #"<%p %#:(%d)> %#", self, [[NSString stringWithUTF8String:__FILE__] lastPathComponent], __LINE__, [NSString stringWithFormat:(s), ##__VA_ARGS__] )
#else
# define DLog(...) /* */
#endif
#define ALog(...) NSLog(__VA_ARGS__)
When you get calabash-ios and running, add this in step_definitions/somesteps.rb:
Then(/^I backdoor (.+)$/) do |x|
backdoor("calabashBackdoor:", x)
end