- Add Editor support
This commit is contained in:
1 parent
5974642e25
commit
1bff59846f
298 files changed
+14488
-1174
No files matched your search
+13
@@ -0,0 +1,13 @@
|
||||
//
|
||||
// CLEmoticonTool.h
|
||||
//
|
||||
// Created by Mokhlas Hussein on 01/02/14.
|
||||
// Copyright (c) 2014 iMokhles. All rights reserved.
|
||||
// CLImageEditor Author sho yakushiji.
|
||||
//
|
||||
|
||||
#import "CLImageToolBase.h"
|
||||
|
||||
@interface CLEmoticonTool : CLImageToolBase
|
||||
|
||||
@end
|
||||
+387
@@ -0,0 +1,387 @@
|
||||
//
|
||||
// CLEmoticonTool.m
|
||||
//
|
||||
// Created by Mokhlas Hussein on 01/02/14.
|
||||
// Copyright (c) 2014 iMokhles. All rights reserved.
|
||||
// CLImageEditor Author sho yakushiji.
|
||||
//
|
||||
|
||||
#import "CLEmoticonTool.h"
|
||||
|
||||
#import "CLCircleView.h"
|
||||
|
||||
static NSString* const kCLEmoticonToolEmoticonPathKey = @"EmoticonPath";
|
||||
static NSString* const kCLEmoticonToolDeleteIconName = @"deleteIconAssetsName";
|
||||
|
||||
@interface _CLEmoticonView : UIView
|
||||
+ (void)setActiveEmoticonView:(_CLEmoticonView*)view;
|
||||
- (UIImageView*)imageView;
|
||||
- (id)initWithImage:(UIImage *)image tool:(CLEmoticonTool*)tool;
|
||||
- (void)setScale:(CGFloat)scale;
|
||||
@end
|
||||
|
||||
|
||||
|
||||
@implementation CLEmoticonTool
|
||||
{
|
||||
UIImage *_originalImage;
|
||||
|
||||
UIView *_workingView;
|
||||
|
||||
UIScrollView *_menuScroll;
|
||||
}
|
||||
|
||||
+ (NSArray*)subtools
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
|
||||
+ (NSString*)defaultTitle
|
||||
{
|
||||
return [CLImageEditorTheme localizedString:@"CLEmoticonTool_DefaultTitle" withDefault:@"Emoticons"];
|
||||
}
|
||||
|
||||
+ (BOOL)isAvailable
|
||||
{
|
||||
return ([UIDevice iosVersion] >= 5.0);
|
||||
}
|
||||
|
||||
+ (CGFloat)defaultDockedNumber
|
||||
{
|
||||
return 7;
|
||||
}
|
||||
|
||||
#pragma mark- optional info
|
||||
|
||||
+ (NSString*)defaultEmoticonPath
|
||||
{
|
||||
return [[[CLImageEditorTheme bundle] bundlePath] stringByAppendingPathComponent:[NSString stringWithFormat:@"%@/Emoticons", NSStringFromClass(self)]];
|
||||
}
|
||||
|
||||
+ (NSDictionary*)optionalInfo
|
||||
{
|
||||
return @{
|
||||
kCLEmoticonToolEmoticonPathKey:[self defaultEmoticonPath],
|
||||
kCLEmoticonToolDeleteIconName:@"",
|
||||
};
|
||||
}
|
||||
|
||||
#pragma mark- implementation
|
||||
|
||||
- (void)setup
|
||||
{
|
||||
_originalImage = self.editor.imageView.image;
|
||||
|
||||
[self.editor fixZoomScaleWithAnimated:YES];
|
||||
|
||||
_menuScroll = [[UIScrollView alloc] initWithFrame:self.editor.menuView.frame];
|
||||
_menuScroll.backgroundColor = self.editor.menuView.backgroundColor;
|
||||
_menuScroll.showsHorizontalScrollIndicator = NO;
|
||||
[self.editor.view addSubview:_menuScroll];
|
||||
|
||||
_workingView = [[UIView alloc] initWithFrame:[self.editor.view convertRect:self.editor.imageView.frame fromView:self.editor.imageView.superview]];
|
||||
_workingView.clipsToBounds = YES;
|
||||
[self.editor.view addSubview:_workingView];
|
||||
|
||||
[self setEmoticonMenu];
|
||||
|
||||
_menuScroll.transform = CGAffineTransformMakeTranslation(0, self.editor.view.height-_menuScroll.top);
|
||||
[UIView animateWithDuration:kCLImageToolAnimationDuration
|
||||
animations:^{
|
||||
self->_menuScroll.transform = CGAffineTransformIdentity;
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)cleanup
|
||||
{
|
||||
[self.editor resetZoomScaleWithAnimated:YES];
|
||||
|
||||
[_workingView removeFromSuperview];
|
||||
|
||||
[UIView animateWithDuration:kCLImageToolAnimationDuration
|
||||
animations:^{
|
||||
self->_menuScroll.transform = CGAffineTransformMakeTranslation(0, self.editor.view.height-self->_menuScroll.top);
|
||||
}
|
||||
completion:^(BOOL finished) {
|
||||
[self->_menuScroll removeFromSuperview];
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)executeWithCompletionBlock:(void (^)(UIImage *, NSError *, NSDictionary *))completionBlock
|
||||
{
|
||||
[_CLEmoticonView setActiveEmoticonView:nil];
|
||||
|
||||
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
|
||||
UIImage *image = [self buildImage:self->_originalImage];
|
||||
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
completionBlock(image, nil, nil);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
#pragma mark-
|
||||
|
||||
- (void)setEmoticonMenu
|
||||
{
|
||||
CGFloat W = 70;
|
||||
CGFloat H = _menuScroll.height;
|
||||
CGFloat x = 0;
|
||||
|
||||
NSString *EmoticonPath = self.toolInfo.optionalInfo[kCLEmoticonToolEmoticonPathKey];
|
||||
if(EmoticonPath==nil){ EmoticonPath = [[self class] defaultEmoticonPath]; }
|
||||
|
||||
NSFileManager *fileManager = [NSFileManager defaultManager];
|
||||
|
||||
NSError *error = nil;
|
||||
NSArray *list = [fileManager contentsOfDirectoryAtPath:EmoticonPath error:&error];
|
||||
|
||||
for(NSString *path in list){
|
||||
NSString *filePath = [NSString stringWithFormat:@"%@/%@", EmoticonPath, path];
|
||||
UIImage *image = [UIImage imageWithContentsOfFile:filePath];
|
||||
if(image){
|
||||
CLToolbarMenuItem *view = [CLImageEditorTheme menuItemWithFrame:CGRectMake(x, 0, W, H) target:self action:@selector(tappedEmoticonPanel:) toolInfo:nil];
|
||||
view.iconImage = [image aspectFit:CGSizeMake(50, 50)];
|
||||
view.userInfo = @{@"filePath" : filePath};
|
||||
|
||||
[_menuScroll addSubview:view];
|
||||
x += W;
|
||||
}
|
||||
}
|
||||
_menuScroll.contentSize = CGSizeMake(MAX(x, _menuScroll.frame.size.width+1), 0);
|
||||
}
|
||||
|
||||
- (void)tappedEmoticonPanel:(UITapGestureRecognizer*)sender
|
||||
{
|
||||
UIView *view = sender.view;
|
||||
|
||||
NSString *filePath = view.userInfo[@"filePath"];
|
||||
if(filePath){
|
||||
_CLEmoticonView *view = [[_CLEmoticonView alloc] initWithImage:[UIImage imageWithContentsOfFile:filePath] tool:self];
|
||||
CGFloat ratio = MIN( (0.5 * _workingView.width) / view.width, (0.5 * _workingView.height) / view.height);
|
||||
[view setScale:ratio];
|
||||
view.center = CGPointMake(_workingView.width/2, _workingView.height/2);
|
||||
|
||||
[_workingView addSubview:view];
|
||||
[_CLEmoticonView setActiveEmoticonView:view];
|
||||
}
|
||||
|
||||
view.alpha = 0.2;
|
||||
[UIView animateWithDuration:kCLImageToolAnimationDuration
|
||||
animations:^{
|
||||
view.alpha = 1;
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
- (UIImage*)buildImage:(UIImage*)image
|
||||
{
|
||||
__block CALayer *layer = nil;
|
||||
__block CGFloat scale = 1;
|
||||
|
||||
safe_dispatch_sync_main(^{
|
||||
scale = image.size.width / self->_workingView.width;
|
||||
layer = self->_workingView.layer;
|
||||
});
|
||||
|
||||
UIGraphicsBeginImageContextWithOptions(image.size, NO, image.scale);
|
||||
|
||||
[image drawAtPoint:CGPointZero];
|
||||
|
||||
CGContextScaleCTM(UIGraphicsGetCurrentContext(), scale, scale);
|
||||
[layer renderInContext:UIGraphicsGetCurrentContext()];
|
||||
|
||||
UIImage *tmp = UIGraphicsGetImageFromCurrentImageContext();
|
||||
|
||||
UIGraphicsEndImageContext();
|
||||
|
||||
return tmp;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@implementation _CLEmoticonView
|
||||
{
|
||||
UIImageView *_imageView;
|
||||
UIButton *_deleteButton;
|
||||
CLCircleView *_circleView;
|
||||
|
||||
CGFloat _scale;
|
||||
CGFloat _arg;
|
||||
|
||||
CGPoint _initialPoint;
|
||||
CGFloat _initialArg;
|
||||
CGFloat _initialScale;
|
||||
}
|
||||
|
||||
+ (void)setActiveEmoticonView:(_CLEmoticonView*)view
|
||||
{
|
||||
static _CLEmoticonView *activeView = nil;
|
||||
if(view != activeView){
|
||||
[activeView setAvtive:NO];
|
||||
activeView = view;
|
||||
[activeView setAvtive:YES];
|
||||
|
||||
[activeView.superview bringSubviewToFront:activeView];
|
||||
}
|
||||
}
|
||||
|
||||
- (id)initWithImage:(UIImage *)image tool:(CLEmoticonTool*)tool
|
||||
{
|
||||
self = [super initWithFrame:CGRectMake(0, 0, image.size.width+32, image.size.height+32)];
|
||||
if(self){
|
||||
_imageView = [[UIImageView alloc] initWithImage:image];
|
||||
_imageView.layer.borderColor = [[UIColor blackColor] CGColor];
|
||||
_imageView.layer.cornerRadius = 3;
|
||||
_imageView.center = self.center;
|
||||
[self addSubview:_imageView];
|
||||
|
||||
_deleteButton = [UIButton buttonWithType:UIButtonTypeCustom];
|
||||
|
||||
[_deleteButton setImage:[tool imageForKey:kCLEmoticonToolDeleteIconName defaultImageName:@"btn_delete.png"] forState:UIControlStateNormal];
|
||||
_deleteButton.frame = CGRectMake(0, 0, 32, 32);
|
||||
_deleteButton.center = _imageView.frame.origin;
|
||||
[_deleteButton addTarget:self action:@selector(pushedDeleteBtn:) forControlEvents:UIControlEventTouchUpInside];
|
||||
[self addSubview:_deleteButton];
|
||||
|
||||
_circleView = [[CLCircleView alloc] initWithFrame:CGRectMake(0, 0, 32, 32)];
|
||||
_circleView.center = CGPointMake(_imageView.width + _imageView.frame.origin.x, _imageView.height + _imageView.frame.origin.y);
|
||||
_circleView.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleTopMargin;
|
||||
_circleView.radius = 0.7;
|
||||
_circleView.color = [UIColor whiteColor];
|
||||
_circleView.borderColor = [UIColor blackColor];
|
||||
_circleView.borderWidth = 5;
|
||||
[self addSubview:_circleView];
|
||||
|
||||
_scale = 1;
|
||||
_arg = 0;
|
||||
|
||||
[self initGestures];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)initGestures
|
||||
{
|
||||
_imageView.userInteractionEnabled = YES;
|
||||
[_imageView addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(viewDidTap:)]];
|
||||
[_imageView addGestureRecognizer:[[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(viewDidPan:)]];
|
||||
[_circleView addGestureRecognizer:[[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(circleViewDidPan:)]];
|
||||
}
|
||||
|
||||
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
|
||||
{
|
||||
UIView* view= [super hitTest:point withEvent:event];
|
||||
if(view==self){
|
||||
return nil;
|
||||
}
|
||||
return view;
|
||||
}
|
||||
|
||||
- (UIImageView*)imageView
|
||||
{
|
||||
return _imageView;
|
||||
}
|
||||
|
||||
- (void)pushedDeleteBtn:(id)sender
|
||||
{
|
||||
_CLEmoticonView *nextTarget = nil;
|
||||
|
||||
const NSInteger index = [self.superview.subviews indexOfObject:self];
|
||||
|
||||
for(NSInteger i=index+1; i<self.superview.subviews.count; ++i){
|
||||
UIView *view = [self.superview.subviews objectAtIndex:i];
|
||||
if([view isKindOfClass:[_CLEmoticonView class]]){
|
||||
nextTarget = (_CLEmoticonView*)view;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(nextTarget==nil){
|
||||
for(NSInteger i=index-1; i>=0; --i){
|
||||
UIView *view = [self.superview.subviews objectAtIndex:i];
|
||||
if([view isKindOfClass:[_CLEmoticonView class]]){
|
||||
nextTarget = (_CLEmoticonView*)view;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[[self class] setActiveEmoticonView:nextTarget];
|
||||
[self removeFromSuperview];
|
||||
}
|
||||
|
||||
- (void)setAvtive:(BOOL)active
|
||||
{
|
||||
_deleteButton.hidden = !active;
|
||||
_circleView.hidden = !active;
|
||||
_imageView.layer.borderWidth = (active) ? 1/_scale : 0;
|
||||
}
|
||||
|
||||
- (void)setScale:(CGFloat)scale
|
||||
{
|
||||
_scale = scale;
|
||||
|
||||
self.transform = CGAffineTransformIdentity;
|
||||
|
||||
_imageView.transform = CGAffineTransformMakeScale(_scale, _scale);
|
||||
|
||||
CGRect rct = self.frame;
|
||||
rct.origin.x += (rct.size.width - (_imageView.width + 32)) / 2;
|
||||
rct.origin.y += (rct.size.height - (_imageView.height + 32)) / 2;
|
||||
rct.size.width = _imageView.width + 32;
|
||||
rct.size.height = _imageView.height + 32;
|
||||
self.frame = rct;
|
||||
|
||||
_imageView.center = CGPointMake(rct.size.width/2, rct.size.height/2);
|
||||
|
||||
self.transform = CGAffineTransformMakeRotation(_arg);
|
||||
|
||||
_imageView.layer.borderWidth = 1/_scale;
|
||||
_imageView.layer.cornerRadius = 3/_scale;
|
||||
}
|
||||
|
||||
- (void)viewDidTap:(UITapGestureRecognizer*)sender
|
||||
{
|
||||
[[self class] setActiveEmoticonView:self];
|
||||
}
|
||||
|
||||
- (void)viewDidPan:(UIPanGestureRecognizer*)sender
|
||||
{
|
||||
[[self class] setActiveEmoticonView:self];
|
||||
|
||||
CGPoint p = [sender translationInView:self.superview];
|
||||
|
||||
if(sender.state == UIGestureRecognizerStateBegan){
|
||||
_initialPoint = self.center;
|
||||
}
|
||||
self.center = CGPointMake(_initialPoint.x + p.x, _initialPoint.y + p.y);
|
||||
}
|
||||
|
||||
- (void)circleViewDidPan:(UIPanGestureRecognizer*)sender
|
||||
{
|
||||
CGPoint p = [sender translationInView:self.superview];
|
||||
|
||||
static CGFloat tmpR = 1;
|
||||
static CGFloat tmpA = 0;
|
||||
if(sender.state == UIGestureRecognizerStateBegan){
|
||||
_initialPoint = [self.superview convertPoint:_circleView.center fromView:_circleView.superview];
|
||||
|
||||
CGPoint p = CGPointMake(_initialPoint.x - self.center.x, _initialPoint.y - self.center.y);
|
||||
tmpR = sqrt(p.x*p.x + p.y*p.y);
|
||||
tmpA = atan2(p.y, p.x);
|
||||
|
||||
_initialArg = _arg;
|
||||
_initialScale = _scale;
|
||||
}
|
||||
|
||||
p = CGPointMake(_initialPoint.x + p.x - self.center.x, _initialPoint.y + p.y - self.center.y);
|
||||
CGFloat R = sqrt(p.x*p.x + p.y*p.y);
|
||||
CGFloat arg = atan2(p.y, p.x);
|
||||
|
||||
_arg = _initialArg + arg - tmpA;
|
||||
[self setScale:MAX(_initialScale * R / tmpR, 0.2)];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,12 @@
|
||||
//
|
||||
// CLResizeTool.h
|
||||
//
|
||||
// Created by sho yakushiji on 2013/12/12.
|
||||
// Copyright (c) 2013年 CALACULU. All rights reserved.
|
||||
//
|
||||
|
||||
#import "CLImageToolBase.h"
|
||||
|
||||
@interface CLResizeTool : CLImageToolBase
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,526 @@
|
||||
//
|
||||
// CLResizeTool.m
|
||||
//
|
||||
// Created by sho yakushiji on 2013/12/12.
|
||||
// Copyright (c) 2013年 CALACULU. All rights reserved.
|
||||
//
|
||||
|
||||
#import "CLResizeTool.h"
|
||||
|
||||
static NSString* const kCLResizeToolPresetSizes = @"presetSizes";
|
||||
static NSString* const kCLResizeToolLimitSize = @"limitSize";
|
||||
static NSString* const kCLResizeToolHorizontalIconName = @"horizontalIconAssetsName";
|
||||
static NSString* const kCLResizeToolVerticalIconName = @"verticalIconAssetsName";
|
||||
static NSString* const kCLResizeToolChainOnIconName = @"chainOnIconAssetsName";
|
||||
static NSString* const kCLResizeToolChainOffIconName = @"chainOffIconAssetsName";
|
||||
|
||||
@interface _CLResizePanel : UIView
|
||||
<UITextFieldDelegate>
|
||||
- (id)initWithFrame:(CGRect)frame originalSize:(CGSize)size tool:(CLResizeTool*)tool;
|
||||
- (void)setImageWidth:(CGFloat)width;
|
||||
- (void)setImageHeight:(CGFloat)height;
|
||||
- (void)setLimitSize:(CGFloat)limit;
|
||||
- (CGSize)imageSize;
|
||||
@end
|
||||
|
||||
|
||||
@implementation CLResizeTool
|
||||
{
|
||||
UIImage *_originalImage;
|
||||
|
||||
UIView *_menuContainer;
|
||||
CLToolbarMenuItem *_switchBtn;
|
||||
UIScrollView *_menuScroll;
|
||||
_CLResizePanel *_resizePanel;
|
||||
}
|
||||
|
||||
+ (NSArray*)subtools
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
|
||||
+ (NSString*)defaultTitle
|
||||
{
|
||||
return [CLImageEditorTheme localizedString:@"CLResizeTool_DefaultTitle" withDefault:@"Resize"];
|
||||
}
|
||||
|
||||
+ (BOOL)isAvailable
|
||||
{
|
||||
return ([UIDevice iosVersion] >= 5.0);
|
||||
}
|
||||
|
||||
+ (CGFloat)defaultDockedNumber
|
||||
{
|
||||
return 5.5;
|
||||
}
|
||||
|
||||
#pragma mark- optional info
|
||||
|
||||
+ (NSArray*)defaultPresetSizes
|
||||
{
|
||||
return @[@240, @320, @480, @640, @800, @960, @1024, @2048];
|
||||
}
|
||||
|
||||
+ (NSNumber*)defaultLimitSize
|
||||
{
|
||||
return @3200;
|
||||
}
|
||||
|
||||
+ (NSDictionary*)optionalInfo
|
||||
{
|
||||
return @{
|
||||
kCLResizeToolPresetSizes:[self defaultPresetSizes],
|
||||
kCLResizeToolLimitSize:[self defaultLimitSize],
|
||||
kCLResizeToolHorizontalIconName:@"",
|
||||
kCLResizeToolVerticalIconName:@"",
|
||||
kCLResizeToolChainOnIconName:@"",
|
||||
kCLResizeToolChainOffIconName:@"",
|
||||
};
|
||||
}
|
||||
|
||||
#pragma mark- implementation
|
||||
|
||||
- (void)setup
|
||||
{
|
||||
_originalImage = self.editor.imageView.image;
|
||||
|
||||
[self.editor fixZoomScaleWithAnimated:YES];
|
||||
|
||||
_menuContainer = [[UIView alloc] initWithFrame:self.editor.menuView.frame];
|
||||
_menuContainer.backgroundColor = self.editor.menuView.backgroundColor;
|
||||
[self.editor.view addSubview:_menuContainer];
|
||||
|
||||
_menuScroll = [[UIScrollView alloc] initWithFrame:CGRectMake(0, 0, _menuContainer.width - 70, _menuContainer.height)];
|
||||
_menuScroll.backgroundColor = [UIColor clearColor];
|
||||
_menuScroll.showsHorizontalScrollIndicator = NO;
|
||||
_menuScroll.clipsToBounds = NO;
|
||||
[_menuContainer addSubview:_menuScroll];
|
||||
|
||||
UIView *btnPanel = [[UIView alloc] initWithFrame:CGRectMake(_menuScroll.right, 0, 70, _menuContainer.height)];
|
||||
btnPanel.backgroundColor = [_menuContainer.backgroundColor colorWithAlphaComponent:0.97];
|
||||
[_menuContainer addSubview:btnPanel];
|
||||
|
||||
_switchBtn = [CLImageEditorTheme menuItemWithFrame:CGRectMake(0, 0, 70, btnPanel.height) target:self action:@selector(pushedSwitchBtn:) toolInfo:nil];
|
||||
_switchBtn.tag = 0;
|
||||
|
||||
_switchBtn.iconImage = [self imageForKey:kCLResizeToolHorizontalIconName defaultImageName:@"btn_width.png"];
|
||||
[btnPanel addSubview:_switchBtn];
|
||||
|
||||
NSNumber *limit = self.toolInfo.optionalInfo[kCLResizeToolLimitSize];
|
||||
if(limit==nil){ limit = [self.class defaultLimitSize]; }
|
||||
|
||||
_resizePanel = [[_CLResizePanel alloc] initWithFrame:self.editor.imageView.superview.frame originalSize:_originalImage.size tool:self];
|
||||
_resizePanel.backgroundColor = [[CLImageEditorTheme toolbarColor] colorWithAlphaComponent:0.4];
|
||||
[_resizePanel setLimitSize:limit.floatValue];
|
||||
[self.editor.view addSubview:_resizePanel];
|
||||
|
||||
[self setResizeMenu];
|
||||
|
||||
_menuContainer.transform = CGAffineTransformMakeTranslation(0, self.editor.view.height-_menuScroll.top);
|
||||
[UIView animateWithDuration:kCLImageToolAnimationDuration
|
||||
animations:^{
|
||||
self->_menuContainer.transform = CGAffineTransformIdentity;
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)cleanup
|
||||
{
|
||||
[self.editor resetZoomScaleWithAnimated:YES];
|
||||
|
||||
[_resizePanel endEditing:YES];
|
||||
[_resizePanel removeFromSuperview];
|
||||
|
||||
[UIView animateWithDuration:kCLImageToolAnimationDuration
|
||||
animations:^{
|
||||
self->_menuContainer.transform = CGAffineTransformMakeTranslation(0, self.editor.view.height-self->_menuScroll.top);
|
||||
}
|
||||
completion:^(BOOL finished) {
|
||||
[self->_menuContainer removeFromSuperview];
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)executeWithCompletionBlock:(void (^)(UIImage *, NSError *, NSDictionary *))completionBlock
|
||||
{
|
||||
CGSize size = _resizePanel.imageSize;
|
||||
|
||||
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
|
||||
|
||||
if(size.width>0 && size.height>0){
|
||||
UIImage *image = [self->_originalImage resize:size];
|
||||
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
completionBlock(image, nil, nil);
|
||||
});
|
||||
}
|
||||
else{
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
completionBlock(nil, nil, nil);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
#pragma mark-
|
||||
|
||||
- (UIImage*)imageWithString:(NSString*)str
|
||||
{
|
||||
UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 100, 100)];
|
||||
label.textAlignment = NSTextAlignmentCenter;
|
||||
label.text = str;
|
||||
label.font = [UIFont boldSystemFontOfSize:30];
|
||||
label.minimumScaleFactor = 0.5;
|
||||
|
||||
label.backgroundColor = [[CLImageEditorTheme theme] toolbarTextColor];
|
||||
label.textColor = [[CLImageEditorTheme theme] toolbarColor];
|
||||
|
||||
UIGraphicsBeginImageContextWithOptions(label.frame.size, NO, 0.0);
|
||||
[label.layer renderInContext:UIGraphicsGetCurrentContext()];
|
||||
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
|
||||
UIGraphicsEndImageContext();
|
||||
|
||||
return image;
|
||||
}
|
||||
|
||||
- (void)setResizeMenu
|
||||
{
|
||||
CGFloat W = 70;
|
||||
CGFloat H = _menuScroll.height;
|
||||
CGFloat x = 0;
|
||||
|
||||
NSArray *sizes = self.toolInfo.optionalInfo[kCLResizeToolPresetSizes];
|
||||
if(sizes==nil || ![sizes isKindOfClass:[NSArray class]] || sizes.count==0){
|
||||
sizes = [[self class] defaultPresetSizes];
|
||||
}
|
||||
|
||||
for(NSNumber *size in sizes){
|
||||
CLToolbarMenuItem *view = [CLImageEditorTheme menuItemWithFrame:CGRectMake(x, 0, W, H) target:self action:@selector(tappedResizePanel:) toolInfo:nil];
|
||||
view.userInfo = @{@"size":size};
|
||||
view.iconImage = [self imageWithString:[NSString stringWithFormat:@"%@", size]];
|
||||
|
||||
[_menuScroll addSubview:view];
|
||||
x += W;
|
||||
}
|
||||
_menuScroll.contentSize = CGSizeMake(MAX(x, _menuScroll.frame.size.width+1), 0);
|
||||
}
|
||||
|
||||
- (void)pushedSwitchBtn:(UITapGestureRecognizer*)sender
|
||||
{
|
||||
if(_switchBtn.tag==0){
|
||||
_switchBtn.tag = 1;
|
||||
_switchBtn.iconImage = [self imageForKey:kCLResizeToolVerticalIconName defaultImageName:@"btn_height.png"];
|
||||
}
|
||||
else{
|
||||
_switchBtn.tag = 0;
|
||||
_switchBtn.iconImage = [self imageForKey:kCLResizeToolHorizontalIconName defaultImageName:@"btn_width.png"];
|
||||
}
|
||||
|
||||
_switchBtn.alpha = 0.2;
|
||||
[UIView animateWithDuration:kCLImageToolAnimationDuration
|
||||
animations:^{
|
||||
self->_switchBtn.alpha = 1;
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
- (void)tappedResizePanel:(UITapGestureRecognizer*)sender
|
||||
{
|
||||
UIView *view = sender.view;
|
||||
|
||||
NSNumber *size = view.userInfo[@"size"];
|
||||
if(size){
|
||||
if(_switchBtn.tag==0){
|
||||
[_resizePanel setImageWidth:size.floatValue];
|
||||
}
|
||||
else{
|
||||
[_resizePanel setImageHeight:size.floatValue];
|
||||
}
|
||||
}
|
||||
|
||||
view.alpha = 0.2;
|
||||
[UIView animateWithDuration:kCLImageToolAnimationDuration
|
||||
animations:^{
|
||||
view.alpha = 1;
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@implementation _CLResizePanel
|
||||
{
|
||||
UIView *_infoPanel;
|
||||
CGSize _originalSize;
|
||||
|
||||
CGFloat _limitSize;
|
||||
UITextField *_fieldW;
|
||||
UITextField *_fieldH;
|
||||
|
||||
UIButton *_chainBtn;
|
||||
}
|
||||
|
||||
- (id)initWithFrame:(CGRect)frame
|
||||
{
|
||||
self = [super initWithFrame:frame];
|
||||
if(self){
|
||||
_infoPanel = [[UIView alloc] initWithFrame:CGRectMake(0, 0, frame.size.width*0.85, 180)];
|
||||
_infoPanel.backgroundColor = [[CLImageEditorTheme toolbarColor] colorWithAlphaComponent:0.9];
|
||||
_infoPanel.layer.cornerRadius = 5;
|
||||
_infoPanel.center = CGPointMake(self.width/2, self.height/2);
|
||||
_infoPanel.autoresizingMask = UIViewAutoresizingFlexibleBottomMargin | UIViewAutoresizingFlexibleTopMargin;
|
||||
[self addSubview:_infoPanel];
|
||||
|
||||
[self addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(viewDidTap:)]];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyBoardWillChange:) name:UIKeyboardWillShowNotification object:nil];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyBoardWillChange:) name:UIKeyboardWillHideNotification object:nil];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
||||
}
|
||||
|
||||
- (id)initWithFrame:(CGRect)frame originalSize:(CGSize)size tool:(CLResizeTool *)tool
|
||||
{
|
||||
self = [self initWithFrame:frame];
|
||||
if(self){
|
||||
_originalSize = size;
|
||||
[self initInfoPanelWithTool:tool];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)initInfoPanelWithTool:(CLResizeTool*)tool
|
||||
{
|
||||
UIFont *font = [CLImageEditorTheme toolbarTextFont];
|
||||
|
||||
CGFloat y = 0;
|
||||
UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(10, 5, _infoPanel.width-20, 30)];
|
||||
[label setTextColor:[CLImageEditorTheme toolbarTextColor]];
|
||||
label.backgroundColor = [UIColor clearColor];
|
||||
label.font = [font fontWithSize:17];
|
||||
|
||||
label.text = [CLImageEditorTheme localizedString:@"CLResizeTool_InfoPanelTextOriginalSize" withDefault:@"Original Image Size:"];
|
||||
[_infoPanel addSubview:label];
|
||||
y = label.bottom;
|
||||
|
||||
label = [[UILabel alloc] initWithFrame:CGRectMake(10, y, _infoPanel.width-20, 50)];
|
||||
[label setTextColor:[CLImageEditorTheme toolbarTextColor]];
|
||||
label.backgroundColor = [UIColor clearColor];
|
||||
label.font = [font fontWithSize:30];
|
||||
label.text = [NSString stringWithFormat:@"%ld x %ld", (long)_originalSize.width, (long)_originalSize.height];
|
||||
label.textAlignment = NSTextAlignmentCenter;
|
||||
[_infoPanel addSubview:label];
|
||||
//y = label.bottom;
|
||||
|
||||
label = [[UILabel alloc] initWithFrame:CGRectMake(10, _infoPanel.height/2, _infoPanel.width-20, 30)];
|
||||
[label setTextColor:[CLImageEditorTheme toolbarTextColor]];
|
||||
label.backgroundColor = [UIColor clearColor];
|
||||
label.font = [font fontWithSize:17];
|
||||
label.text = [CLImageEditorTheme localizedString:@"CLResizeTool_InfoPanelTextNewSize" withDefault:@"New Image Size:"];
|
||||
[_infoPanel addSubview:label];
|
||||
y = label.bottom;
|
||||
/*
|
||||
label = [[UILabel alloc] initWithFrame:CGRectMake(10, y, _infoPanel.width-20, 50)];
|
||||
label.backgroundColor = [UIColor clearColor];
|
||||
label.font = [font fontWithSize:30];
|
||||
label.text = @"x";
|
||||
label.textAlignment = NSTextAlignmentCenter;
|
||||
[_infoPanel addSubview:label];
|
||||
*/
|
||||
_chainBtn = [UIButton buttonWithType:UIButtonTypeCustom];
|
||||
_chainBtn.frame = CGRectMake(0, 0, 35, 35);
|
||||
_chainBtn.center = CGPointMake(label.center.x, y + 25);
|
||||
|
||||
[_chainBtn setImage:[tool imageForKey:kCLResizeToolChainOffIconName defaultImageName:@"btn_chain_off.png"] forState:UIControlStateNormal];
|
||||
[_chainBtn setImage:[tool imageForKey:kCLResizeToolChainOnIconName defaultImageName:@"btn_chain_on.png"] forState:UIControlStateSelected];
|
||||
[_chainBtn addTarget:self action:@selector(chainBtnDidPush:) forControlEvents:UIControlEventTouchUpInside];
|
||||
_chainBtn.selected = YES;
|
||||
[_infoPanel addSubview:_chainBtn];
|
||||
|
||||
_fieldW = [[UITextField alloc] initWithFrame:CGRectMake(_chainBtn.left - 110, y+5, 100, 40)];
|
||||
[_fieldW setTextColor:[CLImageEditorTheme toolbarTextColor]];
|
||||
_fieldW.font = [font fontWithSize:30];
|
||||
_fieldW.textAlignment = NSTextAlignmentCenter;
|
||||
_fieldW.keyboardType = UIKeyboardTypeNumberPad;
|
||||
_fieldW.layer.borderWidth = 1;
|
||||
_fieldW.layer.borderColor = [[[CLImageEditorTheme theme] toolbarTextColor] CGColor];
|
||||
_fieldW.text = [NSString stringWithFormat:@"%ld", (long)_originalSize.width];
|
||||
_fieldW.delegate = self;
|
||||
[_fieldW addTarget:self action:@selector(textFieldDidChanged:) forControlEvents:UIControlEventEditingChanged];
|
||||
[_infoPanel addSubview:_fieldW];
|
||||
|
||||
_fieldH = [[UITextField alloc] initWithFrame:CGRectMake(_chainBtn.right + 10, y+5, 100, 40)];
|
||||
[_fieldH setTextColor:[CLImageEditorTheme toolbarTextColor]];
|
||||
_fieldH.font = [font fontWithSize:30];
|
||||
_fieldH.textAlignment = NSTextAlignmentCenter;
|
||||
_fieldH.keyboardType = UIKeyboardTypeNumberPad;
|
||||
_fieldH.layer.borderWidth = 1;
|
||||
_fieldH.layer.borderColor = _fieldW.layer.borderColor;
|
||||
_fieldH.text = [NSString stringWithFormat:@"%ld", (long)_originalSize.height];
|
||||
_fieldH.delegate = self;
|
||||
[_fieldH addTarget:self action:@selector(textFieldDidChanged:) forControlEvents:UIControlEventEditingChanged];
|
||||
[_infoPanel addSubview:_fieldH];
|
||||
}
|
||||
|
||||
#pragma mark - gesture events
|
||||
|
||||
- (void)viewDidTap:(UITapGestureRecognizer*)sender
|
||||
{
|
||||
[self endEditing:YES];
|
||||
}
|
||||
|
||||
- (void)chainBtnDidPush:(UIButton*)sender
|
||||
{
|
||||
sender.selected = !sender.selected;
|
||||
|
||||
CGFloat W = _fieldW.text.floatValue;
|
||||
CGFloat H = _fieldH.text.floatValue;
|
||||
if(W>H){
|
||||
[self setImageWidth:W];
|
||||
}
|
||||
else{
|
||||
[self setImageHeight:H];
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - keyboard events
|
||||
|
||||
- (void)keyBoardWillChange:(NSNotification *)notificatioin
|
||||
{
|
||||
CGRect keyboardFrame = [[notificatioin.userInfo objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue];
|
||||
keyboardFrame = [self.superview convertRect:keyboardFrame fromView:self.window];
|
||||
|
||||
UIViewAnimationCurve animationCurve = [[notificatioin.userInfo objectForKey:UIKeyboardAnimationCurveUserInfoKey] integerValue];
|
||||
double duration = [[notificatioin.userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue];
|
||||
|
||||
[UIView animateWithDuration:duration
|
||||
delay:0
|
||||
options:UIViewAnimationOptionBeginFromCurrentState | (animationCurve<<16)
|
||||
animations:^{
|
||||
CGFloat H = MIN(self.height, keyboardFrame.origin.y - self.top);
|
||||
self->_infoPanel.center = CGPointMake(self->_infoPanel.center.x, H/2);
|
||||
} completion:^(BOOL finished) {
|
||||
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
#pragma mark- Size settings
|
||||
|
||||
- (void)setLimitSize:(CGFloat)limit
|
||||
{
|
||||
_limitSize = limit;
|
||||
[self setImageWidth:_fieldW.text.floatValue];
|
||||
}
|
||||
|
||||
- (void)setImageWidth:(CGFloat)width
|
||||
{
|
||||
width = MIN(width, _limitSize);
|
||||
|
||||
if(_chainBtn.selected){
|
||||
if(width>0){
|
||||
CGFloat height = MAX(1, width * _originalSize.height / _originalSize.width);
|
||||
|
||||
if(height>_limitSize){
|
||||
[self setImageHeight:_limitSize];
|
||||
}
|
||||
else{
|
||||
_fieldW.text = [NSString stringWithFormat:@"%ld", (long)width];
|
||||
_fieldH.text = [NSString stringWithFormat:@"%ld", (long)height];
|
||||
}
|
||||
}
|
||||
else{
|
||||
_fieldH.text = @"";
|
||||
}
|
||||
}
|
||||
else if(width>0){
|
||||
_fieldW.text = [NSString stringWithFormat:@"%ld", (long)width];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)setImageHeight:(CGFloat)height
|
||||
{
|
||||
height = MIN(height, _limitSize);
|
||||
|
||||
if(_chainBtn.selected){
|
||||
if(height>0){
|
||||
CGFloat width = MAX(1, height * _originalSize.width / _originalSize.height);
|
||||
|
||||
if(width>_limitSize){
|
||||
[self setImageWidth:_limitSize];
|
||||
}
|
||||
else{
|
||||
_fieldW.text = [NSString stringWithFormat:@"%ld", (long)width];
|
||||
_fieldH.text = [NSString stringWithFormat:@"%ld", (long)height];
|
||||
}
|
||||
}
|
||||
else{
|
||||
_fieldW.text = @"";
|
||||
}
|
||||
}
|
||||
else if(height>0){
|
||||
_fieldH.text = [NSString stringWithFormat:@"%ld", (long)height];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)textFieldDidChanged:(id)sender
|
||||
{
|
||||
if(sender==_fieldW){
|
||||
[self setImageWidth:_fieldW.text.floatValue];
|
||||
}
|
||||
else if(sender==_fieldH){
|
||||
[self setImageHeight:_fieldH.text.floatValue];
|
||||
}
|
||||
}
|
||||
|
||||
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
|
||||
{
|
||||
if(textField==_fieldW || textField==_fieldH){
|
||||
if((string != nil) && (![@"" isEqualToString:string])){
|
||||
const char *c = [string cStringUsingEncoding:NSASCIIStringEncoding];
|
||||
if(c[0]==0){ return YES; }
|
||||
else if([textField.text length]>=4){ return NO; }
|
||||
else {return [self isNumber:string]; }
|
||||
}
|
||||
}
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (BOOL)isNumber:(NSString *)value
|
||||
{
|
||||
if(value == nil || [@"" isEqualToString:value]){ return NO; }
|
||||
|
||||
BOOL isNum = NO;
|
||||
|
||||
for(int i=0; i<[value length]; i++){
|
||||
NSString *str = [[value substringFromIndex:i] substringToIndex:1];
|
||||
|
||||
const char *c = [str cStringUsingEncoding:NSASCIIStringEncoding];
|
||||
isNum = ((c!=NULL)&&(c[0]>=0x30)&&(c[0]<=0x39));
|
||||
|
||||
if(_fieldW.text.length==0 && i==0 && (c!=NULL&&c[0]==0x30)){ isNum = NO; }
|
||||
|
||||
if(!isNum){ break; }
|
||||
}
|
||||
|
||||
return isNum;
|
||||
}
|
||||
|
||||
- (CGSize)imageSize
|
||||
{
|
||||
__block CGSize size = CGSizeZero;
|
||||
|
||||
safe_dispatch_sync_main(^{
|
||||
size = CGSizeMake(self->_fieldW.text.floatValue, self->_fieldH.text.floatValue);
|
||||
});
|
||||
return size;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
//
|
||||
// CLSplashTool.h
|
||||
//
|
||||
// Created by sho yakushiji on 2014/06/21.
|
||||
// Copyright (c) 2014年 CALACULU. All rights reserved.
|
||||
//
|
||||
|
||||
#import "CLImageToolBase.h"
|
||||
|
||||
@interface CLSplashTool : CLImageToolBase
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,291 @@
|
||||
//
|
||||
// CLSplashTool.m
|
||||
//
|
||||
// Created by sho yakushiji on 2014/06/21.
|
||||
// Copyright (c) 2014年 CALACULU. All rights reserved.
|
||||
//
|
||||
|
||||
#import "CLSplashTool.h"
|
||||
|
||||
static NSString* const kCLSplashToolEraserIconName = @"eraserIconAssetsName";
|
||||
|
||||
@implementation CLSplashTool
|
||||
{
|
||||
UIImageView *_drawingView;
|
||||
UIImage *_maskImage;
|
||||
UIImage *_grayImage;
|
||||
CGSize _originalImageSize;
|
||||
|
||||
CGPoint _prevDraggingPosition;
|
||||
UIView *_menuView;
|
||||
UISlider *_widthSlider;
|
||||
UIView *_strokePreview;
|
||||
UIView *_strokePreviewBackground;
|
||||
UIImageView *_eraserIcon;
|
||||
|
||||
CLToolbarMenuItem *_colorBtn;
|
||||
}
|
||||
|
||||
+ (NSArray*)subtools
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
|
||||
+ (NSString*)defaultTitle
|
||||
{
|
||||
return [CLImageEditorTheme localizedString:@"CLSplashTool_DefaultTitle" withDefault:@"Splash"];
|
||||
}
|
||||
|
||||
+ (BOOL)isAvailable
|
||||
{
|
||||
return YES;
|
||||
}
|
||||
|
||||
+ (CGFloat)defaultDockedNumber
|
||||
{
|
||||
return 4.6;
|
||||
}
|
||||
|
||||
#pragma mark- optional info
|
||||
|
||||
+ (NSDictionary*)optionalInfo
|
||||
{
|
||||
return @{
|
||||
kCLSplashToolEraserIconName : @"",
|
||||
};
|
||||
}
|
||||
|
||||
#pragma mark- implementation
|
||||
|
||||
- (void)setup
|
||||
{
|
||||
_originalImageSize = self.editor.imageView.image.size;
|
||||
|
||||
_drawingView = [[UIImageView alloc] initWithFrame:self.editor.imageView.bounds];
|
||||
_drawingView.contentMode = UIViewContentModeScaleAspectFit;
|
||||
|
||||
_grayImage = [[self.editor.imageView.image aspectFit:CGSizeMake(_drawingView.width*2, _drawingView.height*2)] grayScaleImage];
|
||||
_drawingView.image = _grayImage;
|
||||
|
||||
UIPanGestureRecognizer *panGesture = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(drawingViewDidPan:)];
|
||||
panGesture.maximumNumberOfTouches = 1;
|
||||
|
||||
_drawingView.userInteractionEnabled = YES;
|
||||
[_drawingView addGestureRecognizer:panGesture];
|
||||
|
||||
[self.editor.imageView addSubview:_drawingView];
|
||||
self.editor.imageView.userInteractionEnabled = YES;
|
||||
self.editor.scrollView.panGestureRecognizer.minimumNumberOfTouches = 2;
|
||||
self.editor.scrollView.panGestureRecognizer.delaysTouchesBegan = NO;
|
||||
self.editor.scrollView.pinchGestureRecognizer.delaysTouchesBegan = NO;
|
||||
|
||||
_menuView = [[UIView alloc] initWithFrame:self.editor.menuView.frame];
|
||||
_menuView.backgroundColor = self.editor.menuView.backgroundColor;
|
||||
[self.editor.view addSubview:_menuView];
|
||||
|
||||
[self setMenu];
|
||||
|
||||
_menuView.transform = CGAffineTransformMakeTranslation(0, self.editor.view.height-_menuView.top);
|
||||
[UIView animateWithDuration:kCLImageToolAnimationDuration
|
||||
animations:^{
|
||||
self->_menuView.transform = CGAffineTransformIdentity;
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)cleanup
|
||||
{
|
||||
[_drawingView removeFromSuperview];
|
||||
self.editor.imageView.userInteractionEnabled = NO;
|
||||
self.editor.scrollView.panGestureRecognizer.minimumNumberOfTouches = 1;
|
||||
|
||||
[UIView animateWithDuration:kCLImageToolAnimationDuration
|
||||
animations:^{
|
||||
self->_menuView.transform = CGAffineTransformMakeTranslation(0, self.editor.view.height-self->_menuView.top);
|
||||
}
|
||||
completion:^(BOOL finished) {
|
||||
[self->_menuView removeFromSuperview];
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)executeWithCompletionBlock:(void (^)(UIImage *, NSError *, NSDictionary *))completionBlock
|
||||
{
|
||||
UIImage *backgroundImage = self.editor.imageView.image;
|
||||
|
||||
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
|
||||
UIImage *image = [self buildImageWithBackgroundImage:backgroundImage];
|
||||
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
completionBlock(image, nil, nil);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
#pragma mark-
|
||||
|
||||
- (UISlider*)defaultSliderWithWidth:(CGFloat)width
|
||||
{
|
||||
UISlider *slider = [[UISlider alloc] initWithFrame:CGRectMake(0, 0, width, 34)];
|
||||
|
||||
[slider setMaximumTrackImage:[UIImage new] forState:UIControlStateNormal];
|
||||
[slider setMinimumTrackImage:[UIImage new] forState:UIControlStateNormal];
|
||||
[slider setThumbImage:[UIImage new] forState:UIControlStateNormal];
|
||||
slider.thumbTintColor = [UIColor whiteColor];
|
||||
|
||||
return slider;
|
||||
}
|
||||
|
||||
- (UIImage*)widthSliderBackground
|
||||
{
|
||||
CGSize size = _widthSlider.frame.size;
|
||||
|
||||
UIGraphicsBeginImageContextWithOptions(size, NO, 0.0);
|
||||
|
||||
CGContextRef context = UIGraphicsGetCurrentContext();
|
||||
|
||||
UIColor *color = [[[CLImageEditorTheme theme] toolbarTextColor] colorWithAlphaComponent:0.5];
|
||||
|
||||
CGFloat strRadius = 1;
|
||||
CGFloat endRadius = size.height/2 * 0.6;
|
||||
|
||||
CGPoint strPoint = CGPointMake(strRadius + 5, size.height/2 - 2);
|
||||
CGPoint endPoint = CGPointMake(size.width-endRadius - 1, strPoint.y);
|
||||
|
||||
CGMutablePathRef path = CGPathCreateMutable();
|
||||
CGPathAddArc(path, NULL, strPoint.x, strPoint.y, strRadius, -M_PI/2, M_PI-M_PI/2, YES);
|
||||
CGPathAddLineToPoint(path, NULL, endPoint.x, endPoint.y + endRadius);
|
||||
CGPathAddArc(path, NULL, endPoint.x, endPoint.y, endRadius, M_PI/2, M_PI+M_PI/2, YES);
|
||||
CGPathAddLineToPoint(path, NULL, strPoint.x, strPoint.y - strRadius);
|
||||
|
||||
CGPathCloseSubpath(path);
|
||||
|
||||
CGContextAddPath(context, path);
|
||||
CGContextSetFillColorWithColor(context, color.CGColor);
|
||||
CGContextFillPath(context);
|
||||
|
||||
UIImage *tmp = UIGraphicsGetImageFromCurrentImageContext();
|
||||
|
||||
CGPathRelease(path);
|
||||
|
||||
UIGraphicsEndImageContext();
|
||||
|
||||
return tmp;
|
||||
}
|
||||
|
||||
- (void)setMenu
|
||||
{
|
||||
CGFloat W = 70;
|
||||
|
||||
_widthSlider = [self defaultSliderWithWidth:_menuView.width - W - 20];
|
||||
_widthSlider.left = 10;
|
||||
_widthSlider.top = _menuView.height/2 - _widthSlider.height/2;
|
||||
[_widthSlider addTarget:self action:@selector(widthSliderDidChange:) forControlEvents:UIControlEventValueChanged];
|
||||
_widthSlider.value = 0.1;
|
||||
_widthSlider.backgroundColor = [UIColor colorWithPatternImage:[self widthSliderBackground]];
|
||||
[_menuView addSubview:_widthSlider];
|
||||
|
||||
_strokePreview = [[UIView alloc] initWithFrame:CGRectMake(0, 0, W - 5, W - 5)];
|
||||
_strokePreview.layer.cornerRadius = _strokePreview.height/2;
|
||||
_strokePreview.layer.borderWidth = 1;
|
||||
_strokePreview.layer.borderColor = [[[CLImageEditorTheme theme] toolbarTextColor] CGColor];
|
||||
_strokePreview.center = CGPointMake(_menuView.width-W/2, _menuView.height/2);
|
||||
[_menuView addSubview:_strokePreview];
|
||||
|
||||
_strokePreviewBackground = [[UIView alloc] initWithFrame:_strokePreview.frame];
|
||||
_strokePreviewBackground.layer.cornerRadius = _strokePreviewBackground.height/2;
|
||||
_strokePreviewBackground.alpha = 0.3;
|
||||
[_strokePreviewBackground addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(strokePreviewDidTap:)]];
|
||||
[_menuView insertSubview:_strokePreviewBackground aboveSubview:_strokePreview];
|
||||
|
||||
_strokePreview.backgroundColor = [[CLImageEditorTheme theme] toolbarTextColor];
|
||||
_strokePreviewBackground.backgroundColor = _strokePreview.backgroundColor;
|
||||
|
||||
_eraserIcon = [[UIImageView alloc] initWithFrame:_strokePreview.frame];
|
||||
_eraserIcon.image = [self imageForKey:kCLSplashToolEraserIconName defaultImageName:@"btn_eraser.png"];
|
||||
_eraserIcon.hidden = YES;
|
||||
[_menuView addSubview:_eraserIcon];
|
||||
|
||||
[self widthSliderDidChange:_widthSlider];
|
||||
|
||||
_menuView.clipsToBounds = NO;
|
||||
}
|
||||
|
||||
- (void)widthSliderDidChange:(UISlider*)sender
|
||||
{
|
||||
CGFloat scale = MAX(0.05, _widthSlider.value);
|
||||
_strokePreview.transform = CGAffineTransformMakeScale(scale, scale);
|
||||
_strokePreview.layer.borderWidth = 2/scale;
|
||||
}
|
||||
|
||||
- (void)strokePreviewDidTap:(UITapGestureRecognizer*)sender
|
||||
{
|
||||
_eraserIcon.hidden = !_eraserIcon.hidden;
|
||||
}
|
||||
|
||||
- (void)drawingViewDidPan:(UIPanGestureRecognizer*)sender
|
||||
{
|
||||
CGPoint currentDraggingPosition = [sender locationInView:_drawingView];
|
||||
|
||||
if(sender.state == UIGestureRecognizerStateBegan){
|
||||
_prevDraggingPosition = currentDraggingPosition;
|
||||
}
|
||||
|
||||
if(sender.state != UIGestureRecognizerStateEnded){
|
||||
[self drawLine:_prevDraggingPosition to:currentDraggingPosition];
|
||||
_drawingView.image = [_grayImage maskedImage:_maskImage];
|
||||
}
|
||||
_prevDraggingPosition = currentDraggingPosition;
|
||||
}
|
||||
|
||||
-(void)drawLine:(CGPoint)from to:(CGPoint)to
|
||||
{
|
||||
CGSize size = _drawingView.frame.size;
|
||||
UIGraphicsBeginImageContextWithOptions(size, NO, 0.0);
|
||||
|
||||
CGContextRef context = UIGraphicsGetCurrentContext();
|
||||
|
||||
CGFloat strokeWidth = MAX(1, _widthSlider.value * 65);
|
||||
|
||||
if(_maskImage==nil){
|
||||
CGContextSetFillColorWithColor(context, [[UIColor blackColor] CGColor]);
|
||||
CGContextFillRect(context, CGRectMake(0, 0, size.width, size.height));
|
||||
}
|
||||
else{
|
||||
[_maskImage drawAtPoint:CGPointZero];
|
||||
}
|
||||
|
||||
CGContextSetLineWidth(context, strokeWidth);
|
||||
CGContextSetLineCap(context, kCGLineCapRound);
|
||||
|
||||
if(!_eraserIcon.hidden){
|
||||
CGContextSetStrokeColorWithColor(context, [[UIColor blackColor] CGColor]);
|
||||
}
|
||||
else{
|
||||
CGContextSetStrokeColorWithColor(context, [[UIColor whiteColor] CGColor]);
|
||||
}
|
||||
|
||||
CGContextMoveToPoint(context, from.x, from.y);
|
||||
CGContextAddLineToPoint(context, to.x, to.y);
|
||||
CGContextStrokePath(context);
|
||||
|
||||
_maskImage = UIGraphicsGetImageFromCurrentImageContext();
|
||||
|
||||
UIGraphicsEndImageContext();
|
||||
}
|
||||
|
||||
- (UIImage*)buildImageWithBackgroundImage:(UIImage*)backgroundImage
|
||||
{
|
||||
_grayImage = [backgroundImage grayScaleImage];
|
||||
|
||||
UIGraphicsBeginImageContextWithOptions(_originalImageSize, NO, backgroundImage.scale);
|
||||
|
||||
[backgroundImage drawAtPoint:CGPointZero];
|
||||
[[_grayImage maskedImage:_maskImage] drawInRect:CGRectMake(0, 0, _originalImageSize.width, _originalImageSize.height)];
|
||||
|
||||
UIImage *tmp = UIGraphicsGetImageFromCurrentImageContext();
|
||||
|
||||
UIGraphicsEndImageContext();
|
||||
|
||||
return tmp;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,12 @@
|
||||
//
|
||||
// CLStickerTool.h
|
||||
//
|
||||
// Created by sho yakushiji on 2013/12/11.
|
||||
// Copyright (c) 2013年 CALACULU. All rights reserved.
|
||||
//
|
||||
|
||||
#import "CLImageToolBase.h"
|
||||
|
||||
@interface CLStickerTool : CLImageToolBase
|
||||
|
||||
@end
|
||||
+389
@@ -0,0 +1,389 @@
|
||||
//
|
||||
// CLStickerTool.m
|
||||
//
|
||||
// Created by sho yakushiji on 2013/12/11.
|
||||
// Copyright (c) 2013年 CALACULU. All rights reserved.
|
||||
//
|
||||
|
||||
#import "CLStickerTool.h"
|
||||
|
||||
#import "CLCircleView.h"
|
||||
|
||||
static NSString* const kCLStickerToolStickerPathKey = @"stickerPath";
|
||||
static NSString* const kCLStickerToolDeleteIconName = @"deleteIconAssetsName";
|
||||
|
||||
@interface _CLStickerView : UIView
|
||||
+ (void)setActiveStickerView:(_CLStickerView*)view;
|
||||
- (UIImageView*)imageView;
|
||||
- (id)initWithImage:(UIImage *)image tool:(CLStickerTool*)tool;
|
||||
- (void)setScale:(CGFloat)scale;
|
||||
@end
|
||||
|
||||
|
||||
|
||||
@implementation CLStickerTool
|
||||
{
|
||||
UIImage *_originalImage;
|
||||
|
||||
UIView *_workingView;
|
||||
|
||||
UIScrollView *_menuScroll;
|
||||
}
|
||||
|
||||
+ (NSArray*)subtools
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
|
||||
+ (NSString*)defaultTitle
|
||||
{
|
||||
return [CLImageEditorTheme localizedString:@"CLStickerTool_DefaultTitle" withDefault:@"Sticker"];
|
||||
}
|
||||
|
||||
+ (BOOL)isAvailable
|
||||
{
|
||||
return ([UIDevice iosVersion] >= 5.0);
|
||||
}
|
||||
|
||||
+ (CGFloat)defaultDockedNumber
|
||||
{
|
||||
return 7;
|
||||
}
|
||||
|
||||
#pragma mark- optional info
|
||||
|
||||
+ (NSString*)defaultStickerPath
|
||||
{
|
||||
return [[[CLImageEditorTheme bundle] bundlePath] stringByAppendingPathComponent:[NSString stringWithFormat:@"%@/stickers", NSStringFromClass(self)]];
|
||||
}
|
||||
|
||||
+ (NSDictionary*)optionalInfo
|
||||
{
|
||||
return @{
|
||||
kCLStickerToolStickerPathKey:[self defaultStickerPath],
|
||||
kCLStickerToolDeleteIconName:@"",
|
||||
};
|
||||
}
|
||||
|
||||
#pragma mark- implementation
|
||||
|
||||
- (void)setup
|
||||
{
|
||||
_originalImage = self.editor.imageView.image;
|
||||
|
||||
[self.editor fixZoomScaleWithAnimated:YES];
|
||||
|
||||
_menuScroll = [[UIScrollView alloc] initWithFrame:self.editor.menuView.frame];
|
||||
_menuScroll.backgroundColor = self.editor.menuView.backgroundColor;
|
||||
_menuScroll.showsHorizontalScrollIndicator = NO;
|
||||
[self.editor.view addSubview:_menuScroll];
|
||||
|
||||
_workingView = [[UIView alloc] initWithFrame:[self.editor.view convertRect:self.editor.imageView.frame fromView:self.editor.imageView.superview]];
|
||||
_workingView.clipsToBounds = YES;
|
||||
[self.editor.view addSubview:_workingView];
|
||||
|
||||
[self setStickerMenu];
|
||||
|
||||
_menuScroll.transform = CGAffineTransformMakeTranslation(0, self.editor.view.height-_menuScroll.top);
|
||||
[UIView animateWithDuration:kCLImageToolAnimationDuration
|
||||
animations:^{
|
||||
self->_menuScroll.transform = CGAffineTransformIdentity;
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)cleanup
|
||||
{
|
||||
[self.editor resetZoomScaleWithAnimated:YES];
|
||||
|
||||
[_workingView removeFromSuperview];
|
||||
|
||||
[UIView animateWithDuration:kCLImageToolAnimationDuration
|
||||
animations:^{
|
||||
self->_menuScroll.transform = CGAffineTransformMakeTranslation(0, self.editor.view.height-self->_menuScroll.top);
|
||||
}
|
||||
completion:^(BOOL finished) {
|
||||
[self->_menuScroll removeFromSuperview];
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)executeWithCompletionBlock:(void (^)(UIImage *, NSError *, NSDictionary *))completionBlock
|
||||
{
|
||||
[_CLStickerView setActiveStickerView:nil];
|
||||
|
||||
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
|
||||
UIImage *image = [self buildImage:self->_originalImage];
|
||||
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
completionBlock(image, nil, nil);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
#pragma mark-
|
||||
|
||||
- (void)setStickerMenu
|
||||
{
|
||||
CGFloat W = 70;
|
||||
CGFloat H = _menuScroll.height;
|
||||
CGFloat x = 0;
|
||||
|
||||
NSString *stickerPath = self.toolInfo.optionalInfo[kCLStickerToolStickerPathKey];
|
||||
if(stickerPath==nil){ stickerPath = [[self class] defaultStickerPath]; }
|
||||
|
||||
NSFileManager *fileManager = [NSFileManager defaultManager];
|
||||
|
||||
NSError *error = nil;
|
||||
NSArray *list = [fileManager contentsOfDirectoryAtPath:stickerPath error:&error];
|
||||
|
||||
NSArray *sortedList = [list sortedArrayUsingSelector:@selector(compare:)]; //sort stickers alphabetically
|
||||
|
||||
for(NSString *path in sortedList){
|
||||
NSString *filePath = [NSString stringWithFormat:@"%@/%@", stickerPath, path];
|
||||
UIImage *image = [UIImage imageWithContentsOfFile:filePath];
|
||||
if(image){
|
||||
CLToolbarMenuItem *view = [CLImageEditorTheme menuItemWithFrame:CGRectMake(x, 0, W, H) target:self action:@selector(tappedStickerPanel:) toolInfo:nil];
|
||||
view.iconImage = [image aspectFit:CGSizeMake(50, 50)];
|
||||
view.userInfo = @{@"filePath" : filePath};
|
||||
view.iconImageContentMode = UIViewContentModeScaleAspectFit;
|
||||
|
||||
[_menuScroll addSubview:view];
|
||||
x += W;
|
||||
}
|
||||
}
|
||||
_menuScroll.contentSize = CGSizeMake(MAX(x, _menuScroll.frame.size.width+1), 0);
|
||||
}
|
||||
|
||||
- (void)tappedStickerPanel:(UITapGestureRecognizer*)sender
|
||||
{
|
||||
UIView *view = sender.view;
|
||||
|
||||
NSString *filePath = view.userInfo[@"filePath"];
|
||||
if(filePath){
|
||||
_CLStickerView *view = [[_CLStickerView alloc] initWithImage:[UIImage imageWithContentsOfFile:filePath] tool:self];
|
||||
CGFloat ratio = MIN( (0.5 * _workingView.width) / view.width, (0.5 * _workingView.height) / view.height);
|
||||
[view setScale:ratio];
|
||||
view.center = CGPointMake(_workingView.width/2, _workingView.height/2);
|
||||
|
||||
[_workingView addSubview:view];
|
||||
[_CLStickerView setActiveStickerView:view];
|
||||
}
|
||||
|
||||
view.alpha = 0.2;
|
||||
[UIView animateWithDuration:kCLImageToolAnimationDuration
|
||||
animations:^{
|
||||
view.alpha = 1;
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
- (UIImage*)buildImage:(UIImage*)image
|
||||
{
|
||||
__block CALayer *layer = nil;
|
||||
__block CGFloat scale = 1;
|
||||
|
||||
safe_dispatch_sync_main(^{
|
||||
scale = image.size.width / self->_workingView.width;
|
||||
layer = self->_workingView.layer;
|
||||
});
|
||||
|
||||
UIGraphicsBeginImageContextWithOptions(image.size, NO, image.scale);
|
||||
|
||||
[image drawAtPoint:CGPointZero];
|
||||
|
||||
CGContextScaleCTM(UIGraphicsGetCurrentContext(), scale, scale);
|
||||
[layer renderInContext:UIGraphicsGetCurrentContext()];
|
||||
|
||||
UIImage *tmp = UIGraphicsGetImageFromCurrentImageContext();
|
||||
|
||||
UIGraphicsEndImageContext();
|
||||
|
||||
return tmp;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@implementation _CLStickerView
|
||||
{
|
||||
UIImageView *_imageView;
|
||||
UIButton *_deleteButton;
|
||||
CLCircleView *_circleView;
|
||||
|
||||
CGFloat _scale;
|
||||
CGFloat _arg;
|
||||
|
||||
CGPoint _initialPoint;
|
||||
CGFloat _initialArg;
|
||||
CGFloat _initialScale;
|
||||
}
|
||||
|
||||
+ (void)setActiveStickerView:(_CLStickerView*)view
|
||||
{
|
||||
static _CLStickerView *activeView = nil;
|
||||
if(view != activeView){
|
||||
[activeView setAvtive:NO];
|
||||
activeView = view;
|
||||
[activeView setAvtive:YES];
|
||||
|
||||
[activeView.superview bringSubviewToFront:activeView];
|
||||
}
|
||||
}
|
||||
|
||||
- (id)initWithImage:(UIImage *)image tool:(CLStickerTool*)tool
|
||||
{
|
||||
self = [super initWithFrame:CGRectMake(0, 0, image.size.width+32, image.size.height+32)];
|
||||
if(self){
|
||||
_imageView = [[UIImageView alloc] initWithImage:image];
|
||||
_imageView.layer.borderColor = [[UIColor blackColor] CGColor];
|
||||
_imageView.layer.cornerRadius = 3;
|
||||
_imageView.center = self.center;
|
||||
[self addSubview:_imageView];
|
||||
|
||||
_deleteButton = [UIButton buttonWithType:UIButtonTypeCustom];
|
||||
|
||||
[_deleteButton setImage:[tool imageForKey:kCLStickerToolDeleteIconName defaultImageName:@"btn_delete.png"] forState:UIControlStateNormal];
|
||||
_deleteButton.frame = CGRectMake(0, 0, 32, 32);
|
||||
_deleteButton.center = _imageView.frame.origin;
|
||||
[_deleteButton addTarget:self action:@selector(pushedDeleteBtn:) forControlEvents:UIControlEventTouchUpInside];
|
||||
[self addSubview:_deleteButton];
|
||||
|
||||
_circleView = [[CLCircleView alloc] initWithFrame:CGRectMake(0, 0, 32, 32)];
|
||||
_circleView.center = CGPointMake(_imageView.width + _imageView.frame.origin.x, _imageView.height + _imageView.frame.origin.y);
|
||||
_circleView.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleTopMargin;
|
||||
_circleView.radius = 0.7;
|
||||
_circleView.color = [UIColor whiteColor];
|
||||
_circleView.borderColor = [UIColor blackColor];
|
||||
_circleView.borderWidth = 5;
|
||||
[self addSubview:_circleView];
|
||||
|
||||
_scale = 1;
|
||||
_arg = 0;
|
||||
|
||||
[self initGestures];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)initGestures
|
||||
{
|
||||
_imageView.userInteractionEnabled = YES;
|
||||
[_imageView addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(viewDidTap:)]];
|
||||
[_imageView addGestureRecognizer:[[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(viewDidPan:)]];
|
||||
[_circleView addGestureRecognizer:[[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(circleViewDidPan:)]];
|
||||
}
|
||||
|
||||
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
|
||||
{
|
||||
UIView* view= [super hitTest:point withEvent:event];
|
||||
if(view==self){
|
||||
return nil;
|
||||
}
|
||||
return view;
|
||||
}
|
||||
|
||||
- (UIImageView*)imageView
|
||||
{
|
||||
return _imageView;
|
||||
}
|
||||
|
||||
- (void)pushedDeleteBtn:(id)sender
|
||||
{
|
||||
_CLStickerView *nextTarget = nil;
|
||||
|
||||
const NSInteger index = [self.superview.subviews indexOfObject:self];
|
||||
|
||||
for(NSInteger i=index+1; i<self.superview.subviews.count; ++i){
|
||||
UIView *view = [self.superview.subviews objectAtIndex:i];
|
||||
if([view isKindOfClass:[_CLStickerView class]]){
|
||||
nextTarget = (_CLStickerView*)view;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(nextTarget==nil){
|
||||
for(NSInteger i=index-1; i>=0; --i){
|
||||
UIView *view = [self.superview.subviews objectAtIndex:i];
|
||||
if([view isKindOfClass:[_CLStickerView class]]){
|
||||
nextTarget = (_CLStickerView*)view;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[[self class] setActiveStickerView:nextTarget];
|
||||
[self removeFromSuperview];
|
||||
}
|
||||
|
||||
- (void)setAvtive:(BOOL)active
|
||||
{
|
||||
_deleteButton.hidden = !active;
|
||||
_circleView.hidden = !active;
|
||||
_imageView.layer.borderWidth = (active) ? 1/_scale : 0;
|
||||
}
|
||||
|
||||
- (void)setScale:(CGFloat)scale
|
||||
{
|
||||
_scale = scale;
|
||||
|
||||
self.transform = CGAffineTransformIdentity;
|
||||
|
||||
_imageView.transform = CGAffineTransformMakeScale(_scale, _scale);
|
||||
|
||||
CGRect rct = self.frame;
|
||||
rct.origin.x += (rct.size.width - (_imageView.width + 32)) / 2;
|
||||
rct.origin.y += (rct.size.height - (_imageView.height + 32)) / 2;
|
||||
rct.size.width = _imageView.width + 32;
|
||||
rct.size.height = _imageView.height + 32;
|
||||
self.frame = rct;
|
||||
|
||||
_imageView.center = CGPointMake(rct.size.width/2, rct.size.height/2);
|
||||
|
||||
self.transform = CGAffineTransformMakeRotation(_arg);
|
||||
|
||||
_imageView.layer.borderWidth = 1/_scale;
|
||||
_imageView.layer.cornerRadius = 3/_scale;
|
||||
}
|
||||
|
||||
- (void)viewDidTap:(UITapGestureRecognizer*)sender
|
||||
{
|
||||
[[self class] setActiveStickerView:self];
|
||||
}
|
||||
|
||||
- (void)viewDidPan:(UIPanGestureRecognizer*)sender
|
||||
{
|
||||
[[self class] setActiveStickerView:self];
|
||||
|
||||
CGPoint p = [sender translationInView:self.superview];
|
||||
|
||||
if(sender.state == UIGestureRecognizerStateBegan){
|
||||
_initialPoint = self.center;
|
||||
}
|
||||
self.center = CGPointMake(_initialPoint.x + p.x, _initialPoint.y + p.y);
|
||||
}
|
||||
|
||||
- (void)circleViewDidPan:(UIPanGestureRecognizer*)sender
|
||||
{
|
||||
CGPoint p = [sender translationInView:self.superview];
|
||||
|
||||
static CGFloat tmpR = 1;
|
||||
static CGFloat tmpA = 0;
|
||||
if(sender.state == UIGestureRecognizerStateBegan){
|
||||
_initialPoint = [self.superview convertPoint:_circleView.center fromView:_circleView.superview];
|
||||
|
||||
CGPoint p = CGPointMake(_initialPoint.x - self.center.x, _initialPoint.y - self.center.y);
|
||||
tmpR = sqrt(p.x*p.x + p.y*p.y);
|
||||
tmpA = atan2(p.y, p.x);
|
||||
|
||||
_initialArg = _arg;
|
||||
_initialScale = _scale;
|
||||
}
|
||||
|
||||
p = CGPointMake(_initialPoint.x + p.x - self.center.x, _initialPoint.y + p.y - self.center.y);
|
||||
CGFloat R = sqrt(p.x*p.x + p.y*p.y);
|
||||
CGFloat arg = atan2(p.y, p.x);
|
||||
|
||||
_arg = _initialArg + arg - tmpA;
|
||||
[self setScale:MAX(_initialScale * R / tmpR, 0.2)];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,30 @@
|
||||
//
|
||||
// CLFontPickerView.h
|
||||
//
|
||||
// Created by sho yakushiji on 2013/12/14.
|
||||
// Copyright (c) 2013年 CALACULU. All rights reserved.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
@protocol CLFontPickerViewDelegate;
|
||||
|
||||
@interface CLFontPickerView : UIView
|
||||
|
||||
@property (nonatomic, weak) id<CLFontPickerViewDelegate> delegate;
|
||||
@property (nonatomic, strong) NSArray *fontList;
|
||||
@property (nonatomic, strong) NSArray *fontSizes;
|
||||
@property (nonatomic, strong) UIFont *font;
|
||||
@property (nonatomic, strong) NSString *text;
|
||||
@property (nonatomic, assign) BOOL sizeComponentHidden;
|
||||
@property (nonatomic, strong) UIColor *foregroundColor;
|
||||
@property (nonatomic, strong) UIColor *textColor;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@protocol CLFontPickerViewDelegate <NSObject>
|
||||
@optional
|
||||
- (void)fontPickerView:(CLFontPickerView*)pickerView didSelectFont:(UIFont*)font;
|
||||
|
||||
@end
|
||||
+211
@@ -0,0 +1,211 @@
|
||||
//
|
||||
// CLFontPickerView.m
|
||||
//
|
||||
// Created by sho yakushiji on 2013/12/14.
|
||||
// Copyright (c) 2013年 CALACULU. All rights reserved.
|
||||
//
|
||||
|
||||
#import "CLFontPickerView.h"
|
||||
|
||||
#import "UIView+Frame.h"
|
||||
#import "CLPickerView.h"
|
||||
|
||||
const CGFloat kCLFontPickerViewConstantFontSize = 14;
|
||||
|
||||
@interface CLFontPickerView()
|
||||
<CLPickerViewDelegate, CLPickerViewDataSource>
|
||||
@end
|
||||
|
||||
@implementation CLFontPickerView
|
||||
{
|
||||
CLPickerView *_pickerView;
|
||||
}
|
||||
|
||||
+ (NSArray*)allFontList
|
||||
{
|
||||
NSMutableArray *list = [NSMutableArray array];
|
||||
|
||||
for(NSString *familyName in [UIFont familyNames]){
|
||||
for(NSString *fontName in [UIFont fontNamesForFamilyName:familyName]){
|
||||
[list addObject:[UIFont fontWithName:fontName size:kCLFontPickerViewConstantFontSize]];
|
||||
}
|
||||
}
|
||||
|
||||
return [list sortedArrayUsingDescriptors:@[[NSSortDescriptor sortDescriptorWithKey:@"fontName" ascending:YES]]];
|
||||
}
|
||||
|
||||
+ (NSArray*)defaultSizes
|
||||
{
|
||||
return @[@8, @10, @12, @14, @16, @18, @20, @24, @28, @32, @38, @44, @50];
|
||||
}
|
||||
|
||||
+ (UIFont*)defaultFont
|
||||
{
|
||||
return [UIFont fontWithName:@"HiraKakuProN-W3"size:kCLFontPickerViewConstantFontSize];
|
||||
}
|
||||
|
||||
- (id)initWithFrame:(CGRect)frame
|
||||
{
|
||||
self = [super initWithFrame:frame];
|
||||
if (self) {
|
||||
self.clipsToBounds = YES;
|
||||
|
||||
_pickerView = [[CLPickerView alloc] initWithFrame:self.bounds];
|
||||
_pickerView.center = CGPointMake(self.width/2, self.height/2);
|
||||
_pickerView.backgroundColor = [UIColor clearColor];
|
||||
_pickerView.dataSource = self;
|
||||
_pickerView.delegate = self;
|
||||
[self addSubview:_pickerView];
|
||||
|
||||
self.fontList = [self.class allFontList];
|
||||
self.fontSizes = [self.class defaultSizes];
|
||||
self.font = [self.class defaultFont];
|
||||
self.foregroundColor = [UIColor colorWithWhite:1 alpha:0.8];
|
||||
self.textColor = [UIColor blackColor];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)setForegroundColor:(UIColor *)foregroundColor
|
||||
{
|
||||
_pickerView.foregroundColor = foregroundColor;
|
||||
}
|
||||
|
||||
- (UIColor*)foregroundColor
|
||||
{
|
||||
return _pickerView.foregroundColor;
|
||||
}
|
||||
|
||||
- (void)setFontList:(NSArray *)fontList
|
||||
{
|
||||
if(fontList != _fontList){
|
||||
_fontList = fontList;
|
||||
[_pickerView reloadComponent:0];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)setFontSizes:(NSArray *)fontSizes
|
||||
{
|
||||
if(fontSizes != _fontSizes){
|
||||
_fontSizes = fontSizes;
|
||||
[_pickerView reloadComponent:1];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)setFont:(UIFont *)font
|
||||
{
|
||||
UIFont *tmp = [font fontWithSize:kCLFontPickerViewConstantFontSize];
|
||||
|
||||
NSInteger fontIndex = [self.fontList indexOfObject:tmp];
|
||||
if(fontIndex==NSNotFound){ fontIndex = 0; }
|
||||
|
||||
NSInteger sizeIndex = 0;
|
||||
for(sizeIndex=0; sizeIndex<self.fontSizes.count; sizeIndex++){
|
||||
if(font.pointSize<=[self.fontSizes[sizeIndex] floatValue]){
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
[_pickerView selectRow:fontIndex inComponent:0 animated:NO];
|
||||
[_pickerView selectRow:sizeIndex inComponent:1 animated:NO];
|
||||
}
|
||||
|
||||
- (UIFont*)font
|
||||
{
|
||||
UIFont *font = self.fontList[[_pickerView selectedRowInComponent:0]];
|
||||
CGFloat size = [self.fontSizes[[_pickerView selectedRowInComponent:1]] floatValue];
|
||||
return [font fontWithSize:size];
|
||||
}
|
||||
|
||||
- (void)setSizeComponentHidden:(BOOL)sizeComponentHidden
|
||||
{
|
||||
_sizeComponentHidden = sizeComponentHidden;
|
||||
|
||||
[_pickerView setNeedsLayout];
|
||||
}
|
||||
|
||||
#pragma mark- UIPickerViewDataSource
|
||||
|
||||
- (NSInteger)numberOfComponentsInPickerView:(CLPickerView *)pickerView
|
||||
{
|
||||
return 2;
|
||||
}
|
||||
|
||||
- (NSInteger)pickerView:(CLPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component
|
||||
{
|
||||
switch (component) {
|
||||
case 0:
|
||||
return self.fontList.count;
|
||||
case 1:
|
||||
return self.fontSizes.count;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#pragma mark- UIPickerViewDelegate
|
||||
|
||||
- (CGFloat)pickerView:(CLPickerView *)pickerView rowHeightForComponent:(NSInteger)component
|
||||
{
|
||||
return self.height/4;
|
||||
}
|
||||
|
||||
- (CGFloat)pickerView:(CLPickerView *)pickerView widthForComponent:(NSInteger)component
|
||||
{
|
||||
CGFloat ratio = self.sizeComponentHidden ? 1 : 0.8;
|
||||
switch (component) {
|
||||
case 0:
|
||||
return self.width*ratio;
|
||||
case 1:
|
||||
return self.width*(1-ratio);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
- (UIView*)pickerView:(CLPickerView *)pickerView viewForRow:(NSInteger)row forComponent:(NSInteger)component reusingView:(UIView *)view
|
||||
{
|
||||
UILabel *lbl = nil;
|
||||
|
||||
if([view isKindOfClass:[UILabel class]]){
|
||||
lbl = (UILabel*)view;
|
||||
}
|
||||
else{
|
||||
CGFloat W = [self pickerView:pickerView widthForComponent:component];
|
||||
CGFloat H = [self pickerView:pickerView rowHeightForComponent:component];
|
||||
CGFloat dx = 10;
|
||||
lbl = [[UILabel alloc] initWithFrame:CGRectMake(dx, 0, W-2*dx, H)];
|
||||
lbl.backgroundColor = [UIColor clearColor];
|
||||
lbl.adjustsFontSizeToFitWidth = YES;
|
||||
lbl.minimumScaleFactor = 0.5;
|
||||
lbl.textAlignment = NSTextAlignmentCenter;
|
||||
lbl.textColor = self.textColor;
|
||||
}
|
||||
|
||||
switch (component) {
|
||||
case 0:
|
||||
lbl.font = self.fontList[row];
|
||||
if(self.text.length>0){
|
||||
lbl.text = self.text;
|
||||
}
|
||||
else{
|
||||
lbl.text = [NSString stringWithFormat:@"%@", lbl.font.fontName];
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
lbl.font = [UIFont systemFontOfSize:kCLFontPickerViewConstantFontSize];
|
||||
lbl.text = [NSString stringWithFormat:@"%@", self.fontSizes[row]];
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return lbl;
|
||||
}
|
||||
|
||||
- (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component
|
||||
{
|
||||
if([self.delegate respondsToSelector:@selector(fontPickerView:didSelectFont:)]){
|
||||
[self.delegate fontPickerView:self didSelectFont:self.font];
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,43 @@
|
||||
//
|
||||
// CLPickerDrum.h
|
||||
//
|
||||
// Created by sho yakushiji on 2013/12/15.
|
||||
// Copyright (c) 2013年 CALACULU. All rights reserved.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
@protocol CLPickerDrumDataSource;
|
||||
@protocol CLPickerDrumDelegate;
|
||||
|
||||
|
||||
@interface CLPickerDrum : UIView
|
||||
|
||||
@property (nonatomic, weak) id<CLPickerDrumDataSource> dataSource;
|
||||
@property (nonatomic, weak) id<CLPickerDrumDelegate> delegate;
|
||||
@property (nonatomic, strong) UIColor *foregroundColor;
|
||||
|
||||
- (void)reload;
|
||||
- (void)selectRow:(NSInteger)row animated:(BOOL)animated;
|
||||
- (NSInteger)selectedRow;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
|
||||
|
||||
@protocol CLPickerDrumDataSource <NSObject>
|
||||
@required
|
||||
- (NSInteger)numberOfRowsInPickerDrum:(CLPickerDrum *)pickerDrum;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@protocol CLPickerDrumDelegate <NSObject>
|
||||
@optional
|
||||
- (CGFloat)rowHeightInPickerDrum:(CLPickerDrum *)pickerDrum;
|
||||
- (UIView*)pickerDrum:(CLPickerDrum *)pickerDrum viewForRow:(NSInteger)row reusingView:(UIView *)view;
|
||||
- (NSString *)pickerDrum:(CLPickerDrum *)pickerDrum titleForRow:(NSInteger)row;
|
||||
- (void)pickerDrum:(CLPickerDrum *)pickerDrum didSelectRow:(NSInteger)row;
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,336 @@
|
||||
//
|
||||
// CLPickerDrum.m
|
||||
//
|
||||
// Created by sho yakushiji on 2013/12/15.
|
||||
// Copyright (c) 2013年 CALACULU. All rights reserved.
|
||||
//
|
||||
|
||||
#import "CLPickerDrum.h"
|
||||
|
||||
#import "UIView+Frame.h"
|
||||
|
||||
|
||||
#define MAX_SCROLLABLE_VIEWS 10000
|
||||
|
||||
|
||||
@interface CLPickerDrum()
|
||||
<UIScrollViewDelegate>
|
||||
@property (nonatomic, assign) NSInteger centerContentIndex;
|
||||
@end
|
||||
|
||||
|
||||
@implementation CLPickerDrum
|
||||
{
|
||||
CGFloat _VIEW_WIDTH;
|
||||
CGFloat _VIEW_HEIGHT;
|
||||
|
||||
NSInteger _VIEW_NUM;
|
||||
NSInteger _ROW_NUM;
|
||||
|
||||
NSInteger _topContentIndex;
|
||||
NSInteger _topViewIndex;
|
||||
NSInteger _bottomViewIndex;
|
||||
NSInteger _centerViewIndex;
|
||||
|
||||
UIImageView *_imageView;
|
||||
UIScrollView *_scrollView;
|
||||
|
||||
BOOL _didLoad;
|
||||
}
|
||||
|
||||
- (id)initWithFrame:(CGRect)frame
|
||||
{
|
||||
self = [super initWithFrame:frame];
|
||||
if (self) {
|
||||
[self customInit];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)awakeFromNib
|
||||
{
|
||||
[super awakeFromNib];
|
||||
[self customInit];
|
||||
}
|
||||
|
||||
- (void)customInit
|
||||
{
|
||||
_didLoad = NO;
|
||||
_centerContentIndex = 0;
|
||||
|
||||
self.foregroundColor = [UIColor colorWithWhite:1 alpha:0.5];
|
||||
|
||||
_imageView = [[UIImageView alloc] initWithFrame:self.bounds];
|
||||
_imageView.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
|
||||
[self addSubview:_imageView];
|
||||
|
||||
_scrollView = [[UIScrollView alloc] initWithFrame:self.bounds];
|
||||
_scrollView.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
|
||||
_scrollView.showsHorizontalScrollIndicator = NO;
|
||||
_scrollView.showsVerticalScrollIndicator = NO;
|
||||
_scrollView.pagingEnabled = NO;
|
||||
_scrollView.delegate = self;
|
||||
[self insertSubview:_scrollView atIndex:0];
|
||||
}
|
||||
|
||||
- (void)setDataSource:(id<CLPickerDrumDataSource>)dataSource
|
||||
{
|
||||
if(dataSource != _dataSource){
|
||||
_dataSource = dataSource;
|
||||
_didLoad = NO;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)setDelegate:(id<CLPickerDrumDelegate>)delegate
|
||||
{
|
||||
if(delegate != _delegate){
|
||||
_delegate = delegate;
|
||||
_didLoad = NO;
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark- Build foreground image
|
||||
|
||||
- (UIImage*)foregroundImage
|
||||
{
|
||||
UIGraphicsBeginImageContextWithOptions(self.frame.size, NO, 0.0);
|
||||
|
||||
CGContextRef context = UIGraphicsGetCurrentContext();
|
||||
|
||||
CGContextSetFillColorWithColor(context, self.foregroundColor.CGColor);
|
||||
CGContextFillRect(context, self.bounds);
|
||||
|
||||
CGRect rct = CGRectMake(0, (self.height - _VIEW_HEIGHT)/2, self.width, _VIEW_HEIGHT);
|
||||
CGContextClearRect(context, rct);
|
||||
|
||||
UIImage *tmp = UIGraphicsGetImageFromCurrentImageContext();
|
||||
|
||||
UIGraphicsEndImageContext();
|
||||
|
||||
return tmp;
|
||||
}
|
||||
|
||||
#pragma mark- Instance method
|
||||
|
||||
- (void)reload
|
||||
{
|
||||
_didLoad = NO;
|
||||
[self layoutSubviews];
|
||||
}
|
||||
|
||||
- (void)selectRow:(NSInteger)row animated:(BOOL)animated
|
||||
{
|
||||
_centerContentIndex = row;
|
||||
|
||||
if(_didLoad){
|
||||
_didLoad = NO;
|
||||
[self refreshViews];
|
||||
}
|
||||
else{
|
||||
[self layoutSubviews];
|
||||
}
|
||||
}
|
||||
|
||||
- (NSInteger)selectedRow
|
||||
{
|
||||
return self.centerContentIndex;
|
||||
}
|
||||
|
||||
#pragma mark- Info from delegate
|
||||
|
||||
- (CGFloat)rowHeight
|
||||
{
|
||||
if([self.delegate respondsToSelector:@selector(rowHeightInPickerDrum:)]){
|
||||
return [self.delegate rowHeightInPickerDrum:self];
|
||||
}
|
||||
return ceil(self.height/3.0);
|
||||
}
|
||||
|
||||
- (NSInteger)rowNumberFromIndex:(NSInteger)index
|
||||
{
|
||||
NSInteger N = _ROW_NUM;
|
||||
if(N!=0){ index = (index+N)%N; }
|
||||
return index;
|
||||
}
|
||||
|
||||
- (UIView*)viewForIndex:(NSInteger)index reusingView:(UIView*)view
|
||||
{
|
||||
NSInteger row = [self rowNumberFromIndex:index];
|
||||
|
||||
if(row >=0 && row<_ROW_NUM && [self.delegate respondsToSelector:@selector(pickerDrum:viewForRow:reusingView:)]){
|
||||
return [self.delegate pickerDrum:self viewForRow:row reusingView:view];
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (NSString*)titleForIndex:(NSInteger)index
|
||||
{
|
||||
NSInteger row = [self rowNumberFromIndex:index];
|
||||
|
||||
if(row >=0 && row<_ROW_NUM && [self.delegate respondsToSelector:@selector(pickerDrum:titleForRow:)]){
|
||||
return [self.delegate pickerDrum:self titleForRow:row];
|
||||
}
|
||||
return @"";
|
||||
}
|
||||
|
||||
#pragma mark- View layout
|
||||
|
||||
- (void)layoutSubviews
|
||||
{
|
||||
_scrollView.bounds = self.bounds;
|
||||
|
||||
_VIEW_NUM = 0;
|
||||
_VIEW_WIDTH = self.width;
|
||||
_VIEW_HEIGHT = self.rowHeight;
|
||||
_ROW_NUM = [self.dataSource numberOfRowsInPickerDrum:self];
|
||||
|
||||
_imageView.image = [self foregroundImage];
|
||||
|
||||
[self refreshViews];
|
||||
}
|
||||
|
||||
- (void)refreshViews
|
||||
{
|
||||
for(UIView *view in _scrollView.subviews){ [view removeFromSuperview]; }
|
||||
|
||||
self.centerContentIndex = _centerContentIndex;
|
||||
|
||||
NSInteger marginNum = ceil((self.height-_VIEW_HEIGHT)/(2*_VIEW_HEIGHT));
|
||||
_VIEW_NUM = 2*marginNum + 3;
|
||||
NSInteger centerIndex = _VIEW_NUM/2;
|
||||
|
||||
_scrollView.contentOffset = CGPointMake(0, _VIEW_HEIGHT*MAX_SCROLLABLE_VIEWS/2);
|
||||
_scrollView.contentSize = CGSizeMake(0, _VIEW_HEIGHT*MAX_SCROLLABLE_VIEWS);
|
||||
|
||||
CGRect viewFrame = CGRectMake(0, _scrollView.contentOffset.y+(_scrollView.height-_VIEW_HEIGHT)/2-centerIndex*_VIEW_HEIGHT, _VIEW_WIDTH, _VIEW_HEIGHT);
|
||||
for(NSInteger i=0; i<_VIEW_NUM; ++i){
|
||||
UIView *view = [self viewForIndex:i-centerIndex+self.centerContentIndex reusingView:nil];
|
||||
|
||||
if(view==nil){
|
||||
UILabel *label = [UILabel new];
|
||||
label.textAlignment = NSTextAlignmentCenter;
|
||||
label.text = [self titleForIndex:i-centerIndex+self.centerContentIndex];
|
||||
view = label;
|
||||
}
|
||||
view.frame = viewFrame;
|
||||
|
||||
[_scrollView addSubview:view];
|
||||
viewFrame.origin.y += _VIEW_HEIGHT;
|
||||
}
|
||||
|
||||
_topContentIndex = MAX_SCROLLABLE_VIEWS/2;
|
||||
_topViewIndex = 0;
|
||||
_bottomViewIndex = _VIEW_NUM-1;
|
||||
|
||||
_didLoad = YES;
|
||||
}
|
||||
|
||||
#pragma mark- Scrolling
|
||||
|
||||
- (void)setCenterContentIndex:(NSInteger)centerContentIndex
|
||||
{
|
||||
if(_ROW_NUM>0){
|
||||
centerContentIndex = (centerContentIndex + _ROW_NUM)%_ROW_NUM;
|
||||
}
|
||||
else{
|
||||
centerContentIndex = 0;
|
||||
}
|
||||
|
||||
if(centerContentIndex != _centerContentIndex){
|
||||
_centerContentIndex = centerContentIndex;
|
||||
|
||||
if([self.delegate respondsToSelector:@selector(pickerDrum:didSelectRow:)]){
|
||||
[self.delegate pickerDrum:self didSelectRow:_centerContentIndex];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (NSInteger)calcViewIndex:(NSInteger)index incremental:(NSInteger)incremental
|
||||
{
|
||||
return (index + incremental + _VIEW_NUM) % _VIEW_NUM;
|
||||
}
|
||||
|
||||
- (void)scrollWithDirection:(BOOL)upperDirection
|
||||
{
|
||||
NSInteger incremental = 0;
|
||||
NSInteger viewIndex = 0;
|
||||
NSInteger contentIndex = 0;
|
||||
if(upperDirection){
|
||||
incremental = -1;
|
||||
viewIndex = _bottomViewIndex;
|
||||
}
|
||||
else{
|
||||
incremental = 1;
|
||||
viewIndex = _topViewIndex;
|
||||
}
|
||||
|
||||
if(viewIndex<_scrollView.subviews.count){
|
||||
_topContentIndex = _topContentIndex + incremental;
|
||||
self.centerContentIndex = self.centerContentIndex + incremental;
|
||||
|
||||
if(upperDirection){
|
||||
contentIndex = self.centerContentIndex - _VIEW_NUM/2;
|
||||
}
|
||||
else{
|
||||
contentIndex = self.centerContentIndex - _VIEW_NUM/2 + _VIEW_NUM - 1;
|
||||
}
|
||||
|
||||
UIView *reuse = [_scrollView.subviews objectAtIndex:viewIndex];
|
||||
UIView *view = [self viewForIndex:contentIndex reusingView:reuse];
|
||||
|
||||
if(view==nil){
|
||||
if([reuse isKindOfClass:[UILabel class]]){
|
||||
UILabel *label = (UILabel*)reuse;
|
||||
label.text = [self titleForIndex:contentIndex];
|
||||
}
|
||||
}
|
||||
else if(view!=reuse){
|
||||
view.frame = reuse.frame;
|
||||
[reuse removeFromSuperview];
|
||||
[_scrollView addSubview:view];
|
||||
reuse = view;
|
||||
}
|
||||
|
||||
reuse.top = reuse.top + _VIEW_HEIGHT * _VIEW_NUM * incremental;
|
||||
|
||||
_topViewIndex = [self calcViewIndex:_topViewIndex incremental:incremental];
|
||||
_bottomViewIndex = [self calcViewIndex:_bottomViewIndex incremental:incremental];
|
||||
}
|
||||
}
|
||||
|
||||
#pragma UIScrollViewDelegate
|
||||
|
||||
- (void)scrollViewDidScroll:(UIScrollView *)sender
|
||||
{
|
||||
CGFloat position = sender.contentOffset.y / _VIEW_HEIGHT;
|
||||
CGFloat delta = position - (CGFloat)_topContentIndex;
|
||||
NSInteger count = (NSInteger)MAX(fabs(delta-0.5), fabs(delta+0.5));
|
||||
|
||||
for(NSInteger i=0; i<count; ++i){
|
||||
[self scrollWithDirection:(delta<0)];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)adjustContentOffset
|
||||
{
|
||||
[UIView animateWithDuration:0.25
|
||||
delay:0
|
||||
options:UIViewAnimationOptionBeginFromCurrentState | UIViewAnimationOptionCurveEaseInOut
|
||||
animations:^{
|
||||
self->_scrollView.contentOffset = CGPointMake(0, self->_VIEW_HEIGHT*self->_topContentIndex);
|
||||
}
|
||||
completion:^(BOOL finished) { }
|
||||
];
|
||||
}
|
||||
|
||||
- (void)scrollViewDidEndDecelerating:(UIScrollView *)sender
|
||||
{
|
||||
[self adjustContentOffset];
|
||||
}
|
||||
|
||||
- (void)scrollViewDidEndDragging:(UIScrollView *)sender willDecelerate:(BOOL)decelerate
|
||||
{
|
||||
[self adjustContentOffset];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,47 @@
|
||||
//
|
||||
// CLPickerView.h
|
||||
//
|
||||
// Created by sho yakushiji on 2013/12/15.
|
||||
// Copyright (c) 2013年 CALACULU. All rights reserved.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
@protocol CLPickerViewDataSource;
|
||||
@protocol CLPickerViewDelegate;
|
||||
|
||||
|
||||
@interface CLPickerView : UIView
|
||||
|
||||
@property (nonatomic, weak) id<CLPickerViewDataSource> dataSource;
|
||||
@property (nonatomic, weak) id<CLPickerViewDelegate> delegate;
|
||||
@property (nonatomic, strong) UIColor *foregroundColor;
|
||||
|
||||
- (void)reloadComponent:(NSInteger)component;
|
||||
- (void)selectRow:(NSInteger)row inComponent:(NSInteger)component animated:(BOOL)animated;
|
||||
- (NSInteger)selectedRowInComponent:(NSInteger)component;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@protocol CLPickerViewDataSource <NSObject>
|
||||
@required
|
||||
- (NSInteger)numberOfComponentsInPickerView:(CLPickerView *)pickerView;
|
||||
- (NSInteger)pickerView:(CLPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@protocol CLPickerViewDelegate <NSObject>
|
||||
@optional
|
||||
- (CGFloat)pickerView:(CLPickerView *)pickerView widthForComponent:(NSInteger)component;
|
||||
- (NSString *)pickerView:(CLPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component;
|
||||
- (UIView *)pickerView:(CLPickerView *)pickerView viewForRow:(NSInteger)row forComponent:(NSInteger)component reusingView:(UIView *)view;
|
||||
- (CGFloat)pickerView:(CLPickerView *)pickerView rowHeightForComponent:(NSInteger)component;
|
||||
|
||||
- (void)pickerView:(CLPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component;
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,182 @@
|
||||
//
|
||||
// CLPickerView.m
|
||||
//
|
||||
// Created by sho yakushiji on 2013/12/15.
|
||||
// Copyright (c) 2013年 CALACULU. All rights reserved.
|
||||
//
|
||||
|
||||
#import "CLPickerView.h"
|
||||
|
||||
#import "UIView+Frame.h"
|
||||
#import "CLPickerDrum.h"
|
||||
|
||||
@interface CLPickerView()
|
||||
<CLPickerDrumDelegate, CLPickerDrumDataSource>
|
||||
@end
|
||||
|
||||
|
||||
@implementation CLPickerView
|
||||
{
|
||||
NSMutableArray *_drums;
|
||||
BOOL _didLoad;
|
||||
}
|
||||
|
||||
- (id)initWithFrame:(CGRect)frame
|
||||
{
|
||||
self = [super initWithFrame:frame];
|
||||
if (self) {
|
||||
[self customInit];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)awakeFromNib
|
||||
{
|
||||
[super awakeFromNib];
|
||||
[self customInit];
|
||||
}
|
||||
|
||||
- (void)customInit
|
||||
{
|
||||
_didLoad = NO;
|
||||
_drums = [NSMutableArray array];
|
||||
}
|
||||
|
||||
- (void)setDataSource:(id<CLPickerViewDataSource>)dataSource
|
||||
{
|
||||
if(dataSource != _dataSource){
|
||||
_dataSource = dataSource;
|
||||
_didLoad = NO;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)setDelegate:(id<CLPickerViewDelegate>)delegate
|
||||
{
|
||||
if(delegate != _delegate){
|
||||
_delegate = delegate;
|
||||
_didLoad = NO;
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark- picker info
|
||||
|
||||
- (void)reloadComponent:(NSInteger)component
|
||||
{
|
||||
if(!_didLoad){ [self layoutSubviews]; }
|
||||
|
||||
if(component>=0 && component<_drums.count){
|
||||
CLPickerDrum *drum = _drums[component];
|
||||
[drum reload];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)selectRow:(NSInteger)row inComponent:(NSInteger)component animated:(BOOL)animated
|
||||
{
|
||||
if(!_didLoad){ [self layoutSubviews]; }
|
||||
|
||||
if(component>=0 && component<_drums.count){
|
||||
CLPickerDrum *drum = _drums[component];
|
||||
[drum selectRow:row animated:animated];
|
||||
}
|
||||
}
|
||||
|
||||
- (NSInteger)selectedRowInComponent:(NSInteger)component
|
||||
{
|
||||
if(component>=0 && component<_drums.count){
|
||||
CLPickerDrum *drum = _drums[component];
|
||||
return [drum selectedRow];
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#pragma mark- Info from delegate
|
||||
|
||||
- (CGFloat)widthForComponent:(NSInteger)component
|
||||
{
|
||||
if([self.delegate respondsToSelector:@selector(pickerView:widthForComponent:)]){
|
||||
return [self.delegate pickerView:self widthForComponent:component];
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#pragma mark- View layout
|
||||
|
||||
- (void)layoutSubviews
|
||||
{
|
||||
NSInteger N = [self.dataSource numberOfComponentsInPickerView:self];
|
||||
CGFloat x = 0;
|
||||
|
||||
for(NSInteger i=0; i<N; ++i){
|
||||
CGFloat width = [self widthForComponent:i];
|
||||
if(width==0){ width = self.width / N; }
|
||||
|
||||
CLPickerDrum *drum = nil;
|
||||
if(i<_drums.count){
|
||||
drum = _drums[i];
|
||||
}
|
||||
else{
|
||||
drum = [[CLPickerDrum alloc] initWithFrame:CGRectMake(x, 0, width, self.height)];
|
||||
[_drums addObject:drum];
|
||||
[self addSubview:drum];
|
||||
}
|
||||
|
||||
drum.frame = CGRectMake(x, 0, width, self.height);
|
||||
drum.tag = i;
|
||||
drum.backgroundColor = [UIColor clearColor];
|
||||
drum.foregroundColor = self.foregroundColor;
|
||||
drum.dataSource = self;
|
||||
drum.delegate = self;
|
||||
[drum reload];
|
||||
|
||||
x += width;
|
||||
}
|
||||
for(NSInteger i=_drums.count-1; i>=N; --i){
|
||||
CLPickerDrum *drum = [_drums objectAtIndex:i];
|
||||
[drum removeFromSuperview];
|
||||
[_drums removeObject:drum];
|
||||
}
|
||||
|
||||
_didLoad = YES;
|
||||
}
|
||||
|
||||
#pragma mark- CLPickerDrum data source
|
||||
|
||||
- (NSInteger)numberOfRowsInPickerDrum:(CLPickerDrum *)pickerDrum
|
||||
{
|
||||
return [self.dataSource pickerView:self numberOfRowsInComponent:pickerDrum.tag];
|
||||
}
|
||||
|
||||
#pragma mark- CLPickerDrum delegate
|
||||
|
||||
- (CGFloat)rowHeightInPickerDrum:(CLPickerDrum *)pickerDrum
|
||||
{
|
||||
if([self.delegate respondsToSelector:@selector(pickerView:rowHeightForComponent:)]){
|
||||
return [self.delegate pickerView:self rowHeightForComponent:pickerDrum.tag];
|
||||
}
|
||||
return ceil(self.height / 3);
|
||||
}
|
||||
|
||||
- (UIView*)pickerDrum:(CLPickerDrum *)pickerDrum viewForRow:(NSInteger)row reusingView:(UIView *)view
|
||||
{
|
||||
if([self.delegate respondsToSelector:@selector(pickerView:viewForRow:forComponent:reusingView:)]){
|
||||
return [self.delegate pickerView:self viewForRow:row forComponent:pickerDrum.tag reusingView:view];
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (NSString *)pickerDrum:(CLPickerDrum *)pickerDrum titleForRow:(NSInteger)row
|
||||
{
|
||||
if([self.delegate respondsToSelector:@selector(pickerView:titleForRow:forComponent:)]){
|
||||
return [self.delegate pickerView:self titleForRow:row forComponent:pickerDrum.tag];
|
||||
}
|
||||
return [NSString stringWithFormat:@"%ld - %ld", (long)pickerDrum.tag, (long)row];
|
||||
}
|
||||
|
||||
- (void)pickerDrum:(CLPickerDrum *)pickerDrum didSelectRow:(NSInteger)row
|
||||
{
|
||||
if([self.delegate respondsToSelector:@selector(pickerView:didSelectRow:inComponent:)]){
|
||||
[self.delegate pickerView:self didSelectRow:row inComponent:pickerDrum.tag];
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,15 @@
|
||||
//
|
||||
// CLTextLabel.h
|
||||
//
|
||||
// Created by sho yakushiji on 2013/12/16.
|
||||
// Copyright (c) 2013年 CALACULU. All rights reserved.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
@interface CLTextLabel : UILabel
|
||||
|
||||
@property (nonatomic, strong) UIColor *outlineColor;
|
||||
@property (nonatomic, assign) CGFloat outlineWidth;
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,59 @@
|
||||
//
|
||||
// CLTextLabel.m
|
||||
//
|
||||
// Created by sho yakushiji on 2013/12/16.
|
||||
// Copyright (c) 2013年 CALACULU. All rights reserved.
|
||||
//
|
||||
|
||||
#import "CLTextLabel.h"
|
||||
|
||||
@implementation CLTextLabel
|
||||
|
||||
- (id)initWithFrame:(CGRect)frame
|
||||
{
|
||||
self = [super initWithFrame:frame];
|
||||
if (self) {
|
||||
// Initialization code
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)setOutlineColor:(UIColor *)outlineColor
|
||||
{
|
||||
if(outlineColor != _outlineColor){
|
||||
_outlineColor = outlineColor;
|
||||
[self setNeedsDisplay];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)setOutlineWidth:(CGFloat)outlineWidth
|
||||
{
|
||||
if(outlineWidth != _outlineWidth){
|
||||
_outlineWidth = outlineWidth;
|
||||
[self setNeedsDisplay];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)drawTextInRect:(CGRect)rect
|
||||
{
|
||||
CGSize shadowOffset = self.shadowOffset;
|
||||
UIColor *txtColor = self.textColor;
|
||||
|
||||
CGFloat outlineSize = self.outlineWidth * self.font.pointSize * 0.3;
|
||||
|
||||
CGContextRef contextRef = UIGraphicsGetCurrentContext();
|
||||
CGContextSetLineWidth(contextRef, outlineSize);
|
||||
CGContextSetLineJoin(contextRef, kCGLineJoinRound);
|
||||
|
||||
CGContextSetTextDrawingMode(contextRef, kCGTextStroke);
|
||||
self.textColor = self.outlineColor;
|
||||
[super drawTextInRect:CGRectInset(rect, outlineSize/4, outlineSize/4)];
|
||||
|
||||
CGContextSetTextDrawingMode(contextRef, kCGTextFill);
|
||||
self.textColor = txtColor;
|
||||
[super drawTextInRect:CGRectInset(rect, outlineSize/4, outlineSize/4)];
|
||||
|
||||
self.shadowOffset = shadowOffset;
|
||||
}
|
||||
|
||||
@end
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
//
|
||||
// CLTextSettingView.h
|
||||
//
|
||||
// Created by sho yakushiji on 2013/12/18.
|
||||
// Copyright (c) 2013年 CALACULU. All rights reserved.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
@protocol CLTextSettingViewDelegate;
|
||||
|
||||
@interface CLTextSettingView : UIView
|
||||
|
||||
@property (nonatomic, weak) id<CLTextSettingViewDelegate> delegate;
|
||||
@property (nonatomic, strong) NSString *selectedText;
|
||||
@property (nonatomic, strong) UIColor *selectedFillColor;
|
||||
@property (nonatomic, strong) UIColor *selectedBorderColor;
|
||||
@property (nonatomic, assign) CGFloat selectedBorderWidth;
|
||||
@property (nonatomic, strong) UIFont *selectedFont;
|
||||
|
||||
|
||||
- (void)setTextColor:(UIColor*)textColor;
|
||||
- (void)setFontPickerForegroundColor:(UIColor*)foregroundColor;
|
||||
|
||||
- (void)showSettingMenuWithIndex:(NSInteger)index animated:(BOOL)animated;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
|
||||
@protocol CLTextSettingViewDelegate <NSObject>
|
||||
@optional
|
||||
- (void)textSettingView:(CLTextSettingView*)settingView didChangeText:(NSString*)text;
|
||||
- (void)textSettingView:(CLTextSettingView*)settingView didChangeFillColor:(UIColor*)fillColor;
|
||||
- (void)textSettingView:(CLTextSettingView*)settingView didChangeBorderColor:(UIColor*)borderColor;
|
||||
- (void)textSettingView:(CLTextSettingView*)settingView didChangeBorderWidth:(CGFloat)borderWidth;
|
||||
- (void)textSettingView:(CLTextSettingView*)settingView didChangeFont:(UIFont*)font;
|
||||
|
||||
@end
|
||||
+317
@@ -0,0 +1,317 @@
|
||||
//
|
||||
// CLTextSettingView.m
|
||||
//
|
||||
// Created by sho yakushiji on 2013/12/18.
|
||||
// Copyright (c) 2013年 CALACULU. All rights reserved.
|
||||
//
|
||||
|
||||
#import "CLTextSettingView.h"
|
||||
|
||||
#import "UIView+Frame.h"
|
||||
#import "CLImageEditorTheme.h"
|
||||
#import "CLColorPickerView.h"
|
||||
#import "CLFontPickerView.h"
|
||||
#import "CLCircleView.h"
|
||||
|
||||
@interface CLTextSettingView()
|
||||
<CLColorPickerViewDelegate, CLFontPickerViewDelegate, UITextViewDelegate>
|
||||
@property (nonatomic, strong) UIView *selectedMode;
|
||||
@end
|
||||
|
||||
|
||||
@implementation CLTextSettingView
|
||||
{
|
||||
UIScrollView *_scrollView;
|
||||
|
||||
UITextView *_textView;
|
||||
CLColorPickerView *_colorPickerView;
|
||||
CLFontPickerView *_fontPickerView;
|
||||
|
||||
UIView *_colorPanel;
|
||||
CLCircleView *_fillCircle;
|
||||
CLCircleView *_pathCircle;
|
||||
UISlider *_pathSlider;
|
||||
}
|
||||
|
||||
- (id)initWithFrame:(CGRect)frame
|
||||
{
|
||||
self = [super initWithFrame:frame];
|
||||
if (self) {
|
||||
[self customInit];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)setColorPanel
|
||||
{
|
||||
_colorPickerView = [[CLColorPickerView alloc] initWithFrame:CGRectMake(0, 0, 0, 160)];
|
||||
_colorPickerView.delegate = self;
|
||||
_colorPickerView.center = CGPointMake(_colorPanel.width/2 - 10, _colorPickerView.height/2 - 5);
|
||||
[_colorPanel addSubview:_colorPickerView];
|
||||
|
||||
_pathSlider = [[UISlider alloc] initWithFrame:CGRectMake(0, 0, _colorPickerView.width*0.8, 34)];
|
||||
_pathSlider.center = CGPointMake(_colorPickerView.center.x, _colorPickerView.bottom + 5);
|
||||
_pathSlider.minimumValue = 0;
|
||||
_pathSlider.maximumValue = 1;
|
||||
_pathSlider.value = 0;
|
||||
[_pathSlider addTarget:self action:@selector(pathSliderDidChange:) forControlEvents:UIControlEventValueChanged];
|
||||
[_colorPanel addSubview:_pathSlider];
|
||||
|
||||
_pathCircle = [[CLCircleView alloc] initWithFrame:CGRectMake(0, 0, 40, 40)];
|
||||
_pathCircle.right = _colorPanel.width - 10;
|
||||
_pathCircle.bottom = _pathSlider.center.y;
|
||||
_pathCircle.radius = 0.6;
|
||||
_pathCircle.borderWidth = 2;
|
||||
_pathCircle.borderColor = [UIColor blackColor];
|
||||
_pathCircle.color = [UIColor clearColor];
|
||||
[_colorPanel addSubview:_pathCircle];
|
||||
|
||||
_fillCircle = [[CLCircleView alloc] initWithFrame:_pathCircle.frame];
|
||||
_fillCircle.bottom = _pathCircle.top;
|
||||
_fillCircle.radius = 0.6;
|
||||
[_colorPanel addSubview:_fillCircle];
|
||||
|
||||
[_pathCircle addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(modeViewTapped:)]];
|
||||
[_fillCircle addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(modeViewTapped:)]];
|
||||
|
||||
_fillCircle.tag = 0;
|
||||
_pathCircle.tag = 1;
|
||||
self.selectedMode = _fillCircle;
|
||||
}
|
||||
|
||||
- (void)customInit
|
||||
{
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyBoardWillShow:) name:UIKeyboardWillShowNotification object:nil];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyBoardWillHide:) name:UIKeyboardWillHideNotification object:nil];
|
||||
|
||||
_scrollView = [[UIScrollView alloc] initWithFrame:self.bounds];
|
||||
_scrollView.pagingEnabled = YES;
|
||||
_scrollView.showsHorizontalScrollIndicator = NO;
|
||||
_scrollView.showsVerticalScrollIndicator = NO;
|
||||
_scrollView.scrollEnabled = NO;
|
||||
[self addSubview:_scrollView];
|
||||
|
||||
_textView = [[UITextView alloc] initWithFrame:CGRectMake(10, 0, self.width-42, 80)];
|
||||
_textView.delegate = self;
|
||||
_textView.backgroundColor = [UIColor clearColor];
|
||||
[_scrollView addSubview:_textView];
|
||||
|
||||
_colorPanel = [[UIView alloc] initWithFrame:CGRectMake(self.width, 0, self.width, self.height)];
|
||||
_colorPanel.backgroundColor = [UIColor clearColor];
|
||||
[_scrollView addSubview:_colorPanel];
|
||||
[self setColorPanel];
|
||||
|
||||
_fontPickerView = [[CLFontPickerView alloc] initWithFrame:CGRectMake(self.width * 2, 0, self.width, self.height)];
|
||||
_fontPickerView.delegate = self;
|
||||
_fontPickerView.sizeComponentHidden = YES;
|
||||
[_scrollView addSubview:_fontPickerView];
|
||||
|
||||
_scrollView.contentSize = CGSizeMake(self.width * 3, self.height);
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
||||
}
|
||||
|
||||
- (void)setTextColor:(UIColor*)textColor
|
||||
{
|
||||
_fontPickerView.textColor = textColor;
|
||||
_textView.textColor = textColor;
|
||||
}
|
||||
|
||||
- (BOOL)isFirstResponder
|
||||
{
|
||||
return _textView.isFirstResponder;
|
||||
}
|
||||
|
||||
- (BOOL)becomeFirstResponder
|
||||
{
|
||||
return [_textView becomeFirstResponder];
|
||||
}
|
||||
|
||||
- (BOOL)resignFirstResponder
|
||||
{
|
||||
return [_textView resignFirstResponder];
|
||||
}
|
||||
|
||||
- (void)modeViewTapped:(UITapGestureRecognizer*)sender
|
||||
{
|
||||
self.selectedMode = sender.view;
|
||||
}
|
||||
|
||||
#pragma mark - Properties
|
||||
|
||||
- (void)setSelectedMode:(UIView *)selectedMode
|
||||
{
|
||||
if(selectedMode != _selectedMode){
|
||||
_selectedMode.backgroundColor = [UIColor clearColor];
|
||||
_selectedMode = selectedMode;
|
||||
_selectedMode.backgroundColor = [[CLImageEditorTheme theme] toolbarSelectedButtonColor];
|
||||
|
||||
if(_selectedMode==_fillCircle){
|
||||
_colorPickerView.color = _fillCircle.color;
|
||||
}
|
||||
else{
|
||||
_colorPickerView.color = _pathCircle.borderColor;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void)setSelectedText:(NSString *)selectedText
|
||||
{
|
||||
_textView.text = selectedText;
|
||||
}
|
||||
|
||||
- (NSString*)selectedText
|
||||
{
|
||||
return _textView.text;
|
||||
}
|
||||
|
||||
- (void)setSelectedFillColor:(UIColor *)selectedFillColor
|
||||
{
|
||||
_fillCircle.color = selectedFillColor;
|
||||
|
||||
if(self.selectedMode==_fillCircle){
|
||||
_colorPickerView.color = _fillCircle.color;
|
||||
}
|
||||
}
|
||||
|
||||
- (UIColor*)selectedFillColor
|
||||
{
|
||||
return _fillCircle.color;
|
||||
}
|
||||
|
||||
- (void)setSelectedBorderColor:(UIColor *)selectedBorderColor
|
||||
{
|
||||
_pathCircle.borderColor = selectedBorderColor;
|
||||
|
||||
if(self.selectedMode==_pathCircle){
|
||||
_colorPickerView.color = _pathCircle.borderColor;
|
||||
}
|
||||
}
|
||||
|
||||
- (UIColor*)selectedBorderColor
|
||||
{
|
||||
return _pathCircle.borderColor;
|
||||
}
|
||||
|
||||
- (void)setSelectedBorderWidth:(CGFloat)selectedBorderWidth
|
||||
{
|
||||
_pathSlider.value = selectedBorderWidth;
|
||||
}
|
||||
|
||||
- (CGFloat)selectedBorderWidth
|
||||
{
|
||||
return _pathSlider.value;
|
||||
}
|
||||
|
||||
- (void)setSelectedFont:(UIFont *)selectedFont
|
||||
{
|
||||
_fontPickerView.font = selectedFont;
|
||||
}
|
||||
|
||||
- (UIFont*)selectedFont
|
||||
{
|
||||
return _fontPickerView.font;
|
||||
}
|
||||
|
||||
- (void)setFontPickerForegroundColor:(UIColor*)foregroundColor
|
||||
{
|
||||
_fontPickerView.foregroundColor = foregroundColor;
|
||||
}
|
||||
|
||||
- (void)showSettingMenuWithIndex:(NSInteger)index animated:(BOOL)animated
|
||||
{
|
||||
[_scrollView setContentOffset:CGPointMake(index * self.width, 0) animated:animated];
|
||||
}
|
||||
|
||||
#pragma mark - keyboard events
|
||||
|
||||
- (void)keyBoardWillShow:(NSNotification *)notificatioin
|
||||
{
|
||||
[self keyBoardWillChange:notificatioin withTextViewHeight:80];
|
||||
[_textView scrollRangeToVisible:_textView.selectedRange];
|
||||
}
|
||||
|
||||
- (void)keyBoardWillHide:(NSNotification *)notificatioin
|
||||
{
|
||||
[self keyBoardWillChange:notificatioin withTextViewHeight:self.height - 20];
|
||||
}
|
||||
|
||||
- (void)keyBoardWillChange:(NSNotification *)notificatioin withTextViewHeight:(CGFloat)height
|
||||
{
|
||||
CGRect keyboardFrame = [[notificatioin.userInfo objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue];
|
||||
keyboardFrame = [self.superview convertRect:keyboardFrame fromView:self.window];
|
||||
|
||||
UIViewAnimationCurve animationCurve = [[notificatioin.userInfo objectForKey:UIKeyboardAnimationCurveUserInfoKey] integerValue];
|
||||
double duration = [[notificatioin.userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue];
|
||||
|
||||
[UIView animateWithDuration:duration
|
||||
delay:0
|
||||
options:UIViewAnimationOptionBeginFromCurrentState | (animationCurve<<16)
|
||||
animations:^{
|
||||
self->_textView.height = height;
|
||||
CGFloat dy = MIN(0, (keyboardFrame.origin.y - self->_textView.height) - self.top);
|
||||
self.transform = CGAffineTransformMakeTranslation(0, dy);
|
||||
} completion:^(BOOL finished) {
|
||||
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
#pragma mark- Color picker delegate
|
||||
|
||||
- (void)colorPickerView:(CLColorPickerView *)picker colorDidChange:(UIColor *)color
|
||||
{
|
||||
if(self.selectedMode==_fillCircle){
|
||||
_fillCircle.color = color;
|
||||
if([self.delegate respondsToSelector:@selector(textSettingView:didChangeFillColor:)]){
|
||||
[self.delegate textSettingView:self didChangeFillColor:color];
|
||||
}
|
||||
}
|
||||
else{
|
||||
_pathCircle.borderColor = color;
|
||||
if([self.delegate respondsToSelector:@selector(textSettingView:didChangeBorderColor:)]){
|
||||
[self.delegate textSettingView:self didChangeBorderColor:color];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark- PathSlider event
|
||||
|
||||
- (void)pathSliderDidChange:(UISlider*)sender
|
||||
{
|
||||
if([self.delegate respondsToSelector:@selector(textSettingView:didChangeBorderWidth:)]){
|
||||
[self.delegate textSettingView:self didChangeBorderWidth:_pathSlider.value];
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark- Font picker delegate
|
||||
|
||||
- (void)fontPickerView:(CLFontPickerView *)pickerView didSelectFont:(UIFont *)font
|
||||
{
|
||||
if([self.delegate respondsToSelector:@selector(textSettingView:didChangeFont:)]){
|
||||
[self.delegate textSettingView:self didChangeFont:font];
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark- UITextView delegate
|
||||
|
||||
- (void)textViewDidChange:(UITextView*)textView
|
||||
{
|
||||
NSRange selection = textView.selectedRange;
|
||||
if(selection.location+selection.length == textView.text.length && [textView.text characterAtIndex:textView.text.length-1] == '\n') {
|
||||
[textView layoutSubviews];
|
||||
[textView scrollRectToVisible:CGRectMake(0, textView.contentSize.height - 1, 1, 1) animated:YES];
|
||||
}
|
||||
else {
|
||||
[textView scrollRangeToVisible:textView.selectedRange];
|
||||
}
|
||||
|
||||
if([self.delegate respondsToSelector:@selector(textSettingView:didChangeText:)]){
|
||||
[self.delegate textSettingView:self didChangeText:textView.text];
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,12 @@
|
||||
//
|
||||
// CLTextTool.h
|
||||
//
|
||||
// Created by sho yakushiji on 2013/12/15.
|
||||
// Copyright (c) 2013年 CALACULU. All rights reserved.
|
||||
//
|
||||
|
||||
#import "CLImageToolBase.h"
|
||||
|
||||
@interface CLTextTool : CLImageToolBase
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,735 @@
|
||||
//
|
||||
// CLTextTool.m
|
||||
//
|
||||
// Created by sho yakushiji on 2013/12/15.
|
||||
// Copyright (c) 2013年 CALACULU. All rights reserved.
|
||||
//
|
||||
|
||||
#import "CLTextTool.h"
|
||||
|
||||
#import "CLCircleView.h"
|
||||
#import "CLColorPickerView.h"
|
||||
#import "CLFontPickerView.h"
|
||||
#import "CLTextLabel.h"
|
||||
|
||||
#import "CLTextSettingView.h"
|
||||
|
||||
static NSString* const CLTextViewActiveViewDidChangeNotification = @"CLTextViewActiveViewDidChangeNotificationString";
|
||||
static NSString* const CLTextViewActiveViewDidTapNotification = @"CLTextViewActiveViewDidTapNotificationString";
|
||||
|
||||
static NSString* const kCLTextToolDeleteIconName = @"deleteIconAssetsName";
|
||||
static NSString* const kCLTextToolCloseIconName = @"closeIconAssetsName";
|
||||
static NSString* const kCLTextToolNewTextIconName = @"newTextIconAssetsName";
|
||||
static NSString* const kCLTextToolEditTextIconName = @"editTextIconAssetsName";
|
||||
static NSString* const kCLTextToolFontIconName = @"fontIconAssetsName";
|
||||
static NSString* const kCLTextToolAlignLeftIconName = @"alignLeftIconAssetsName";
|
||||
static NSString* const kCLTextToolAlignCenterIconName = @"alignCenterIconAssetsName";
|
||||
static NSString* const kCLTextToolAlignRightIconName = @"alignRightIconAssetsName";
|
||||
|
||||
|
||||
@interface _CLTextView : UIView
|
||||
@property (nonatomic, strong) NSString *text;
|
||||
@property (nonatomic, strong) UIFont *font;
|
||||
@property (nonatomic, strong) UIColor *fillColor;
|
||||
@property (nonatomic, strong) UIColor *borderColor;
|
||||
@property (nonatomic, assign) CGFloat borderWidth;
|
||||
@property (nonatomic, assign) NSTextAlignment textAlignment;
|
||||
|
||||
+ (void)setActiveTextView:(_CLTextView*)view;
|
||||
- (id)initWithTool:(CLTextTool*)tool;
|
||||
- (void)setScale:(CGFloat)scale;
|
||||
- (void)sizeToFitWithMaxWidth:(CGFloat)width lineHeight:(CGFloat)lineHeight;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
|
||||
@interface CLTextTool()
|
||||
<CLColorPickerViewDelegate, CLFontPickerViewDelegate, UITextViewDelegate, CLTextSettingViewDelegate>
|
||||
@property (nonatomic, strong) _CLTextView *selectedTextView;
|
||||
@end
|
||||
|
||||
@implementation CLTextTool
|
||||
{
|
||||
UIImage *_originalImage;
|
||||
|
||||
UIView *_workingView;
|
||||
|
||||
CLTextSettingView *_settingView;
|
||||
|
||||
CLToolbarMenuItem *_textBtn;
|
||||
CLToolbarMenuItem *_colorBtn;
|
||||
CLToolbarMenuItem *_fontBtn;
|
||||
|
||||
CLToolbarMenuItem *_alignLeftBtn;
|
||||
CLToolbarMenuItem *_alignCenterBtn;
|
||||
CLToolbarMenuItem *_alignRightBtn;
|
||||
|
||||
UIScrollView *_menuScroll;
|
||||
}
|
||||
|
||||
+ (NSArray*)subtools
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
|
||||
+ (NSString*)defaultTitle
|
||||
{
|
||||
return [CLImageEditorTheme localizedString:@"CLTextTool_DefaultTitle" withDefault:@"Text"];
|
||||
}
|
||||
|
||||
+ (BOOL)isAvailable
|
||||
{
|
||||
return ([UIDevice iosVersion] >= 5.0);
|
||||
}
|
||||
|
||||
+ (CGFloat)defaultDockedNumber
|
||||
{
|
||||
return 8;
|
||||
}
|
||||
|
||||
#pragma mark- optional info
|
||||
|
||||
+ (NSDictionary*)optionalInfo
|
||||
{
|
||||
return @{
|
||||
kCLTextToolDeleteIconName:@"",
|
||||
kCLTextToolCloseIconName:@"",
|
||||
kCLTextToolNewTextIconName:@"",
|
||||
kCLTextToolEditTextIconName:@"",
|
||||
kCLTextToolFontIconName:@"",
|
||||
kCLTextToolAlignLeftIconName:@"",
|
||||
kCLTextToolAlignCenterIconName:@"",
|
||||
kCLTextToolAlignRightIconName:@"",
|
||||
};
|
||||
}
|
||||
|
||||
#pragma mark- implementation
|
||||
|
||||
- (void)setup
|
||||
{
|
||||
_originalImage = self.editor.imageView.image;
|
||||
|
||||
[self.editor fixZoomScaleWithAnimated:YES];
|
||||
|
||||
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(activeTextViewDidChange:) name:CLTextViewActiveViewDidChangeNotification object:nil];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(activeTextViewDidTap:) name:CLTextViewActiveViewDidTapNotification object:nil];
|
||||
|
||||
_menuScroll = [[UIScrollView alloc] initWithFrame:self.editor.menuView.frame];
|
||||
_menuScroll.backgroundColor = self.editor.menuView.backgroundColor;
|
||||
_menuScroll.showsHorizontalScrollIndicator = NO;
|
||||
[self.editor.view addSubview:_menuScroll];
|
||||
|
||||
_workingView = [[UIView alloc] initWithFrame:[self.editor.view convertRect:self.editor.imageView.frame fromView:self.editor.imageView.superview]];
|
||||
_workingView.clipsToBounds = YES;
|
||||
[self.editor.view addSubview:_workingView];
|
||||
|
||||
_settingView = [[CLTextSettingView alloc] initWithFrame:CGRectMake(0, 0, self.editor.view.width, 180)];
|
||||
_settingView.top = _menuScroll.top - _settingView.height;
|
||||
_settingView.backgroundColor = [CLImageEditorTheme toolbarColor];
|
||||
_settingView.textColor = [CLImageEditorTheme toolbarTextColor];
|
||||
_settingView.fontPickerForegroundColor = _settingView.backgroundColor;
|
||||
_settingView.delegate = self;
|
||||
[self.editor.view addSubview:_settingView];
|
||||
|
||||
UIButton *okButton = [UIButton buttonWithType:UIButtonTypeCustom];
|
||||
[okButton setImage:[self imageForKey:kCLTextToolCloseIconName defaultImageName:@"btn_delete.png"] forState:UIControlStateNormal];
|
||||
okButton.frame = CGRectMake(_settingView.width-32, 0, 32, 32);
|
||||
[okButton addTarget:self action:@selector(pushedButton:) forControlEvents:UIControlEventTouchUpInside];
|
||||
[_settingView addSubview:okButton];
|
||||
|
||||
[self setMenu];
|
||||
|
||||
self.selectedTextView = nil;
|
||||
|
||||
_menuScroll.transform = CGAffineTransformMakeTranslation(0, self.editor.view.height-_menuScroll.top);
|
||||
[UIView animateWithDuration:kCLImageToolAnimationDuration
|
||||
animations:^{
|
||||
self->_menuScroll.transform = CGAffineTransformIdentity;
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)cleanup
|
||||
{
|
||||
[self.editor resetZoomScaleWithAnimated:YES];
|
||||
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
||||
|
||||
[_settingView endEditing:YES];
|
||||
[_settingView removeFromSuperview];
|
||||
[_workingView removeFromSuperview];
|
||||
|
||||
[UIView animateWithDuration:kCLImageToolAnimationDuration
|
||||
animations:^{
|
||||
self->_menuScroll.transform = CGAffineTransformMakeTranslation(0, self.editor.view.height-self->_menuScroll.top);
|
||||
}
|
||||
completion:^(BOOL finished) {
|
||||
[self->_menuScroll removeFromSuperview];
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)executeWithCompletionBlock:(void (^)(UIImage *, NSError *, NSDictionary *))completionBlock
|
||||
{
|
||||
[_CLTextView setActiveTextView:nil];
|
||||
|
||||
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
|
||||
UIImage *image = [self buildImage:self->_originalImage];
|
||||
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
completionBlock(image, nil, nil);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
#pragma mark-
|
||||
|
||||
- (UIImage*)buildImage:(UIImage*)image
|
||||
{
|
||||
__block CALayer *layer = nil;
|
||||
__block CGFloat scale = 1;
|
||||
|
||||
safe_dispatch_sync_main(^{
|
||||
scale = image.size.width / self->_workingView.width;
|
||||
layer = self->_workingView.layer;
|
||||
});
|
||||
|
||||
UIGraphicsBeginImageContextWithOptions(image.size, NO, image.scale);
|
||||
|
||||
[image drawAtPoint:CGPointZero];
|
||||
|
||||
CGContextScaleCTM(UIGraphicsGetCurrentContext(), scale, scale);
|
||||
[layer renderInContext:UIGraphicsGetCurrentContext()];
|
||||
|
||||
UIImage *tmp = UIGraphicsGetImageFromCurrentImageContext();
|
||||
|
||||
UIGraphicsEndImageContext();
|
||||
|
||||
return tmp;
|
||||
}
|
||||
|
||||
- (void)setMenuBtnEnabled:(BOOL)enabled
|
||||
{
|
||||
_textBtn.userInteractionEnabled =
|
||||
_colorBtn.userInteractionEnabled =
|
||||
_fontBtn.userInteractionEnabled =
|
||||
_alignLeftBtn.userInteractionEnabled =
|
||||
_alignCenterBtn.userInteractionEnabled =
|
||||
_alignRightBtn.userInteractionEnabled = enabled;
|
||||
}
|
||||
|
||||
- (void)setSelectedTextView:(_CLTextView *)selectedTextView
|
||||
{
|
||||
if(selectedTextView != _selectedTextView){
|
||||
_selectedTextView = selectedTextView;
|
||||
}
|
||||
|
||||
[self setMenuBtnEnabled:(_selectedTextView!=nil)];
|
||||
|
||||
if(_selectedTextView==nil){
|
||||
[self hideSettingView];
|
||||
|
||||
_colorBtn.iconView.backgroundColor = _settingView.selectedFillColor;
|
||||
_alignLeftBtn.selected = _alignCenterBtn.selected = _alignRightBtn.selected = NO;
|
||||
}
|
||||
else{
|
||||
_colorBtn.iconView.backgroundColor = selectedTextView.fillColor;
|
||||
_colorBtn.iconView.layer.borderColor = selectedTextView.borderColor.CGColor;
|
||||
_colorBtn.iconView.layer.borderWidth = MAX(2, 10*selectedTextView.borderWidth);
|
||||
|
||||
_settingView.selectedText = selectedTextView.text;
|
||||
_settingView.selectedFillColor = selectedTextView.fillColor;
|
||||
_settingView.selectedBorderColor = selectedTextView.borderColor;
|
||||
_settingView.selectedBorderWidth = selectedTextView.borderWidth;
|
||||
_settingView.selectedFont = selectedTextView.font;
|
||||
[self setTextAlignment:selectedTextView.textAlignment];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)activeTextViewDidChange:(NSNotification*)notification
|
||||
{
|
||||
self.selectedTextView = notification.object;
|
||||
}
|
||||
|
||||
- (void)activeTextViewDidTap:(NSNotification*)notification
|
||||
{
|
||||
[self beginTextEditing];
|
||||
}
|
||||
|
||||
- (void)setMenu
|
||||
{
|
||||
CGFloat W = 70;
|
||||
CGFloat H = _menuScroll.height;
|
||||
CGFloat x = 0;
|
||||
|
||||
NSArray *_menu = @[
|
||||
@{@"title":[CLImageEditorTheme localizedString:@"CLTextTool_MenuItemNew" withDefault:@"New"], @"icon":[self imageForKey:kCLTextToolNewTextIconName defaultImageName:@"btn_add.png"]},
|
||||
@{@"title":[CLImageEditorTheme localizedString:@"CLTextTool_MenuItemText" withDefault:@"Text"], @"icon":[self imageForKey:kCLTextToolEditTextIconName defaultImageName:@"icon.png"]},
|
||||
@{@"title":[CLImageEditorTheme localizedString:@"CLTextTool_MenuItemColor" withDefault:@"Color"]},
|
||||
@{@"title":[CLImageEditorTheme localizedString:@"CLTextTool_MenuItemFont" withDefault:@"Font"], @"icon":[self imageForKey:kCLTextToolFontIconName defaultImageName:@"btn_font.png"]},
|
||||
@{@"title":[CLImageEditorTheme localizedString:@"CLTextTool_MenuItemAlignLeft" withDefault:@" "], @"icon":[self imageForKey:kCLTextToolAlignLeftIconName defaultImageName:@"btn_align_left.png"]},
|
||||
@{@"title":[CLImageEditorTheme localizedString:@"CLTextTool_MenuItemAlignCenter" withDefault:@" "], @"icon":[self imageForKey:kCLTextToolAlignCenterIconName defaultImageName:@"btn_align_center.png"]},
|
||||
@{@"title":[CLImageEditorTheme localizedString:@"CLTextTool_MenuItemAlignRight" withDefault:@" "], @"icon":[self imageForKey:kCLTextToolAlignRightIconName defaultImageName:@"btn_align_right.png"]},
|
||||
];
|
||||
|
||||
NSInteger tag = 0;
|
||||
for(NSDictionary *obj in _menu){
|
||||
CLToolbarMenuItem *view = [CLImageEditorTheme menuItemWithFrame:CGRectMake(x, 0, W, H) target:self action:@selector(tappedMenuPanel:) toolInfo:nil];
|
||||
view.tag = tag++;
|
||||
view.title = obj[@"title"];
|
||||
view.iconImage = obj[@"icon"];
|
||||
|
||||
switch (view.tag) {
|
||||
case 1:
|
||||
_textBtn = view;
|
||||
break;
|
||||
case 2:
|
||||
_colorBtn = view;
|
||||
_colorBtn.iconView.layer.borderWidth = 2;
|
||||
_colorBtn.iconView.layer.borderColor = [[UIColor blackColor] CGColor];
|
||||
break;
|
||||
case 3:
|
||||
_fontBtn = view;
|
||||
break;
|
||||
case 4:
|
||||
_alignLeftBtn = view;
|
||||
break;
|
||||
case 5:
|
||||
_alignCenterBtn = view;
|
||||
break;
|
||||
case 6:
|
||||
_alignRightBtn = view;
|
||||
break;
|
||||
}
|
||||
|
||||
[_menuScroll addSubview:view];
|
||||
x += W;
|
||||
}
|
||||
_menuScroll.contentSize = CGSizeMake(MAX(x, _menuScroll.frame.size.width+1), 0);
|
||||
}
|
||||
|
||||
- (void)tappedMenuPanel:(UITapGestureRecognizer*)sender
|
||||
{
|
||||
UIView *view = sender.view;
|
||||
|
||||
switch (view.tag) {
|
||||
case 0:
|
||||
[self addNewText];
|
||||
break;
|
||||
case 1:
|
||||
case 2:
|
||||
case 3:
|
||||
[self showSettingViewWithMenuIndex:view.tag-1];
|
||||
break;
|
||||
case 4:
|
||||
[self setTextAlignment:NSTextAlignmentLeft];
|
||||
break;
|
||||
case 5:
|
||||
[self setTextAlignment:NSTextAlignmentCenter];
|
||||
break;
|
||||
case 6:
|
||||
[self setTextAlignment:NSTextAlignmentRight];
|
||||
break;
|
||||
}
|
||||
|
||||
view.alpha = 0.2;
|
||||
[UIView animateWithDuration:kCLImageToolAnimationDuration
|
||||
animations:^{
|
||||
view.alpha = 1;
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
- (void)addNewText
|
||||
{
|
||||
_CLTextView *view = [[_CLTextView alloc] initWithTool:self];
|
||||
view.fillColor = _settingView.selectedFillColor;
|
||||
view.borderColor = _settingView.selectedBorderColor;
|
||||
view.borderWidth = _settingView.selectedBorderWidth;
|
||||
view.font = _settingView.selectedFont;
|
||||
|
||||
CGFloat ratio = MIN( (0.8 * _workingView.width) / view.width, (0.2 * _workingView.height) / view.height);
|
||||
[view setScale:ratio];
|
||||
view.center = CGPointMake(_workingView.width/2, view.height/2 + 10);
|
||||
|
||||
[_workingView addSubview:view];
|
||||
[_CLTextView setActiveTextView:view];
|
||||
|
||||
[self beginTextEditing];
|
||||
}
|
||||
|
||||
- (void)hideSettingView
|
||||
{
|
||||
[_settingView endEditing:YES];
|
||||
_settingView.hidden = YES;
|
||||
}
|
||||
|
||||
- (void)showSettingViewWithMenuIndex:(NSInteger)index
|
||||
{
|
||||
if(_settingView.hidden){
|
||||
_settingView.hidden = NO;
|
||||
[_settingView showSettingMenuWithIndex:index animated:NO];
|
||||
}
|
||||
else{
|
||||
[_settingView showSettingMenuWithIndex:index animated:YES];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)beginTextEditing
|
||||
{
|
||||
[self showSettingViewWithMenuIndex:0];
|
||||
[_settingView becomeFirstResponder];
|
||||
}
|
||||
|
||||
- (void)setTextAlignment:(NSTextAlignment)alignment
|
||||
{
|
||||
self.selectedTextView.textAlignment = alignment;
|
||||
|
||||
_alignLeftBtn.selected = _alignCenterBtn.selected = _alignRightBtn.selected = NO;
|
||||
switch (alignment) {
|
||||
case NSTextAlignmentLeft:
|
||||
_alignLeftBtn.selected = YES;
|
||||
break;
|
||||
case NSTextAlignmentCenter:
|
||||
_alignCenterBtn.selected = YES;
|
||||
break;
|
||||
case NSTextAlignmentRight:
|
||||
_alignRightBtn.selected = YES;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)pushedButton:(UIButton*)button
|
||||
{
|
||||
if(_settingView.isFirstResponder){
|
||||
[_settingView resignFirstResponder];
|
||||
}
|
||||
else{
|
||||
[self hideSettingView];
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark- Setting view delegate
|
||||
|
||||
- (void)textSettingView:(CLTextSettingView *)settingView didChangeText:(NSString *)text
|
||||
{
|
||||
// set text
|
||||
self.selectedTextView.text = text;
|
||||
[self.selectedTextView sizeToFitWithMaxWidth:0.8*_workingView.width lineHeight:0.2*_workingView.height];
|
||||
}
|
||||
|
||||
- (void)textSettingView:(CLTextSettingView*)settingView didChangeFillColor:(UIColor*)fillColor
|
||||
{
|
||||
_colorBtn.iconView.backgroundColor = fillColor;
|
||||
self.selectedTextView.fillColor = fillColor;
|
||||
}
|
||||
|
||||
- (void)textSettingView:(CLTextSettingView*)settingView didChangeBorderColor:(UIColor*)borderColor
|
||||
{
|
||||
_colorBtn.iconView.layer.borderColor = borderColor.CGColor;
|
||||
self.selectedTextView.borderColor = borderColor;
|
||||
}
|
||||
|
||||
- (void)textSettingView:(CLTextSettingView*)settingView didChangeBorderWidth:(CGFloat)borderWidth
|
||||
{
|
||||
_colorBtn.iconView.layer.borderWidth = MAX(2, 10*borderWidth);
|
||||
self.selectedTextView.borderWidth = borderWidth;
|
||||
}
|
||||
|
||||
- (void)textSettingView:(CLTextSettingView *)settingView didChangeFont:(UIFont *)font
|
||||
{
|
||||
self.selectedTextView.font = font;
|
||||
[self.selectedTextView sizeToFitWithMaxWidth:0.8*_workingView.width lineHeight:0.2*_workingView.height];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
|
||||
const CGFloat MAX_FONT_SIZE = 50.0;
|
||||
|
||||
|
||||
#pragma mark- _CLTextView
|
||||
|
||||
@implementation _CLTextView
|
||||
{
|
||||
CLTextLabel *_label;
|
||||
UIButton *_deleteButton;
|
||||
CLCircleView *_circleView;
|
||||
|
||||
CGFloat _scale;
|
||||
CGFloat _arg;
|
||||
|
||||
CGPoint _initialPoint;
|
||||
CGFloat _initialArg;
|
||||
CGFloat _initialScale;
|
||||
}
|
||||
|
||||
+ (void)setActiveTextView:(_CLTextView*)view
|
||||
{
|
||||
static _CLTextView *activeView = nil;
|
||||
if(view != activeView){
|
||||
[activeView setAvtive:NO];
|
||||
activeView = view;
|
||||
[activeView setAvtive:YES];
|
||||
|
||||
[activeView.superview bringSubviewToFront:activeView];
|
||||
|
||||
NSNotification *n = [NSNotification notificationWithName:CLTextViewActiveViewDidChangeNotification object:view userInfo:nil];
|
||||
[[NSNotificationCenter defaultCenter] performSelectorOnMainThread:@selector(postNotification:) withObject:n waitUntilDone:NO];
|
||||
}
|
||||
}
|
||||
|
||||
- (id)initWithTool:(CLTextTool*)tool
|
||||
{
|
||||
self = [super initWithFrame:CGRectMake(0, 0, 132, 132)];
|
||||
if(self){
|
||||
_label = [[CLTextLabel alloc] init];
|
||||
[_label setTextColor:[CLImageEditorTheme toolbarTextColor]];
|
||||
_label.numberOfLines = 0;
|
||||
_label.backgroundColor = [UIColor clearColor];
|
||||
_label.layer.borderColor = [[UIColor blackColor] CGColor];
|
||||
_label.layer.cornerRadius = 3;
|
||||
_label.font = [UIFont systemFontOfSize:MAX_FONT_SIZE];
|
||||
_label.minimumScaleFactor = 1/MAX_FONT_SIZE;
|
||||
_label.adjustsFontSizeToFitWidth = YES;
|
||||
_label.textAlignment = NSTextAlignmentCenter;
|
||||
self.text = @"";
|
||||
[self addSubview:_label];
|
||||
|
||||
CGSize size = [_label sizeThatFits:CGSizeMake(FLT_MAX, FLT_MAX)];
|
||||
_label.frame = CGRectMake(16, 16, size.width, size.height);
|
||||
self.frame = CGRectMake(0, 0, size.width + 32, size.height + 32);
|
||||
|
||||
_deleteButton = [UIButton buttonWithType:UIButtonTypeCustom];
|
||||
[_deleteButton setImage:[tool imageForKey:kCLTextToolDeleteIconName defaultImageName:@"btn_delete.png"] forState:UIControlStateNormal];
|
||||
_deleteButton.frame = CGRectMake(0, 0, 32, 32);
|
||||
_deleteButton.center = _label.frame.origin;
|
||||
[_deleteButton addTarget:self action:@selector(pushedDeleteBtn:) forControlEvents:UIControlEventTouchUpInside];
|
||||
[self addSubview:_deleteButton];
|
||||
|
||||
_circleView = [[CLCircleView alloc] initWithFrame:CGRectMake(0, 0, 32, 32)];
|
||||
_circleView.center = CGPointMake(_label.width + _label.left, _label.height + _label.top);
|
||||
_circleView.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleTopMargin;
|
||||
_circleView.radius = 0.7;
|
||||
_circleView.color = [UIColor whiteColor];
|
||||
_circleView.borderColor = [UIColor blackColor];
|
||||
_circleView.borderWidth = 5;
|
||||
[self addSubview:_circleView];
|
||||
|
||||
_arg = 0;
|
||||
[self setScale:1];
|
||||
|
||||
[self initGestures];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)initGestures
|
||||
{
|
||||
_label.userInteractionEnabled = YES;
|
||||
[_label addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(viewDidTap:)]];
|
||||
[_label addGestureRecognizer:[[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(viewDidPan:)]];
|
||||
[_circleView addGestureRecognizer:[[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(circleViewDidPan:)]];
|
||||
}
|
||||
|
||||
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
|
||||
{
|
||||
UIView* view= [super hitTest:point withEvent:event];
|
||||
if(view==self){
|
||||
return nil;
|
||||
}
|
||||
return view;
|
||||
}
|
||||
|
||||
#pragma mark- Properties
|
||||
|
||||
- (void)setAvtive:(BOOL)active
|
||||
{
|
||||
_deleteButton.hidden = !active;
|
||||
_circleView.hidden = !active;
|
||||
_label.layer.borderWidth = (active) ? 1/_scale : 0;
|
||||
}
|
||||
|
||||
- (BOOL)active
|
||||
{
|
||||
return !_deleteButton.hidden;
|
||||
}
|
||||
|
||||
- (void)sizeToFitWithMaxWidth:(CGFloat)width lineHeight:(CGFloat)lineHeight
|
||||
{
|
||||
self.transform = CGAffineTransformIdentity;
|
||||
_label.transform = CGAffineTransformIdentity;
|
||||
|
||||
CGSize size = [_label sizeThatFits:CGSizeMake(width / (15/MAX_FONT_SIZE), FLT_MAX)];
|
||||
_label.frame = CGRectMake(16, 16, size.width, size.height);
|
||||
|
||||
CGFloat viewW = (_label.width + 32);
|
||||
CGFloat viewH = _label.font.lineHeight;
|
||||
|
||||
CGFloat ratio = MIN(width / viewW, lineHeight / viewH);
|
||||
[self setScale:ratio];
|
||||
}
|
||||
|
||||
- (void)setScale:(CGFloat)scale
|
||||
{
|
||||
_scale = scale;
|
||||
|
||||
self.transform = CGAffineTransformIdentity;
|
||||
|
||||
_label.transform = CGAffineTransformMakeScale(_scale, _scale);
|
||||
|
||||
CGRect rct = self.frame;
|
||||
rct.origin.x += (rct.size.width - (_label.width + 32)) / 2;
|
||||
rct.origin.y += (rct.size.height - (_label.height + 32)) / 2;
|
||||
rct.size.width = _label.width + 32;
|
||||
rct.size.height = _label.height + 32;
|
||||
self.frame = rct;
|
||||
|
||||
_label.center = CGPointMake(rct.size.width/2, rct.size.height/2);
|
||||
|
||||
self.transform = CGAffineTransformMakeRotation(_arg);
|
||||
|
||||
_label.layer.borderWidth = 1/_scale;
|
||||
_label.layer.cornerRadius = 3/_scale;
|
||||
}
|
||||
|
||||
- (void)setFillColor:(UIColor *)fillColor
|
||||
{
|
||||
_label.textColor = fillColor;
|
||||
}
|
||||
|
||||
- (UIColor*)fillColor
|
||||
{
|
||||
return _label.textColor;
|
||||
}
|
||||
|
||||
- (void)setBorderColor:(UIColor *)borderColor
|
||||
{
|
||||
_label.outlineColor = borderColor;
|
||||
}
|
||||
|
||||
- (UIColor*)borderColor
|
||||
{
|
||||
return _label.outlineColor;
|
||||
}
|
||||
|
||||
- (void)setBorderWidth:(CGFloat)borderWidth
|
||||
{
|
||||
_label.outlineWidth = borderWidth;
|
||||
}
|
||||
|
||||
- (CGFloat)borderWidth
|
||||
{
|
||||
return _label.outlineWidth;
|
||||
}
|
||||
|
||||
- (void)setFont:(UIFont *)font
|
||||
{
|
||||
_label.font = [font fontWithSize:MAX_FONT_SIZE];
|
||||
}
|
||||
|
||||
- (UIFont*)font
|
||||
{
|
||||
return _label.font;
|
||||
}
|
||||
|
||||
- (void)setTextAlignment:(NSTextAlignment)textAlignment
|
||||
{
|
||||
_label.textAlignment = textAlignment;
|
||||
}
|
||||
|
||||
- (NSTextAlignment)textAlignment
|
||||
{
|
||||
return _label.textAlignment;
|
||||
}
|
||||
|
||||
- (void)setText:(NSString *)text
|
||||
{
|
||||
if(![text isEqualToString:_text]){
|
||||
_text = text;
|
||||
_label.text = (_text.length>0) ? _text : [CLImageEditorTheme localizedString:@"CLTextTool_EmptyText" withDefault:@"Text"];
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark- gesture events
|
||||
|
||||
- (void)pushedDeleteBtn:(id)sender
|
||||
{
|
||||
_CLTextView *nextTarget = nil;
|
||||
|
||||
const NSInteger index = [self.superview.subviews indexOfObject:self];
|
||||
|
||||
for(NSInteger i=index+1; i<self.superview.subviews.count; ++i){
|
||||
UIView *view = [self.superview.subviews objectAtIndex:i];
|
||||
if([view isKindOfClass:[_CLTextView class]]){
|
||||
nextTarget = (_CLTextView*)view;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(nextTarget==nil){
|
||||
for(NSInteger i=index-1; i>=0; --i){
|
||||
UIView *view = [self.superview.subviews objectAtIndex:i];
|
||||
if([view isKindOfClass:[_CLTextView class]]){
|
||||
nextTarget = (_CLTextView*)view;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[[self class] setActiveTextView:nextTarget];
|
||||
[self removeFromSuperview];
|
||||
}
|
||||
|
||||
- (void)viewDidTap:(UITapGestureRecognizer*)sender
|
||||
{
|
||||
if(self.active){
|
||||
NSNotification *n = [NSNotification notificationWithName:CLTextViewActiveViewDidTapNotification object:self userInfo:nil];
|
||||
[[NSNotificationCenter defaultCenter] performSelectorOnMainThread:@selector(postNotification:) withObject:n waitUntilDone:NO];
|
||||
}
|
||||
[[self class] setActiveTextView:self];
|
||||
}
|
||||
|
||||
- (void)viewDidPan:(UIPanGestureRecognizer*)sender
|
||||
{
|
||||
[[self class] setActiveTextView:self];
|
||||
|
||||
CGPoint p = [sender translationInView:self.superview];
|
||||
|
||||
if(sender.state == UIGestureRecognizerStateBegan){
|
||||
_initialPoint = self.center;
|
||||
}
|
||||
self.center = CGPointMake(_initialPoint.x + p.x, _initialPoint.y + p.y);
|
||||
}
|
||||
|
||||
- (void)circleViewDidPan:(UIPanGestureRecognizer*)sender
|
||||
{
|
||||
CGPoint p = [sender translationInView:self.superview];
|
||||
|
||||
static CGFloat tmpR = 1;
|
||||
static CGFloat tmpA = 0;
|
||||
if(sender.state == UIGestureRecognizerStateBegan){
|
||||
_initialPoint = [self.superview convertPoint:_circleView.center fromView:_circleView.superview];
|
||||
|
||||
CGPoint p = CGPointMake(_initialPoint.x - self.center.x, _initialPoint.y - self.center.y);
|
||||
tmpR = sqrt(p.x*p.x + p.y*p.y);
|
||||
tmpA = atan2(p.y, p.x);
|
||||
|
||||
_initialArg = _arg;
|
||||
_initialScale = _scale;
|
||||
}
|
||||
|
||||
p = CGPointMake(_initialPoint.x + p.x - self.center.x, _initialPoint.y + p.y - self.center.y);
|
||||
CGFloat R = sqrt(p.x*p.x + p.y*p.y);
|
||||
CGFloat arg = atan2(p.y, p.x);
|
||||
|
||||
_arg = _initialArg + arg - tmpA;
|
||||
[self setScale:MAX(_initialScale * R / tmpR, 15/MAX_FONT_SIZE)];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
Reference in new issue
Block a user