|
@@ -1,794 +0,0 @@
|
|
|
-//
|
|
|
-// CCMenuAccount.h
|
|
|
-// Nextcloud
|
|
|
-//
|
|
|
-// Created by Marino Faggiana on 07/04/16.
|
|
|
-// Copyright (c) 2016 Marino Faggiana. All rights reserved.
|
|
|
-//
|
|
|
-// Author Marino Faggiana <marino.faggiana@nextcloud.com>
|
|
|
-//
|
|
|
-// This program is free software: you can redistribute it and/or modify
|
|
|
-// it under the terms of the GNU General Public License as published by
|
|
|
-// the Free Software Foundation, either version 3 of the License, or
|
|
|
-// (at your option) any later version.
|
|
|
-//
|
|
|
-// This program is distributed in the hope that it will be useful,
|
|
|
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
-// GNU General Public License for more details.
|
|
|
-//
|
|
|
-// You should have received a copy of the GNU General Public License
|
|
|
-// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
-//
|
|
|
-
|
|
|
-#import <Foundation/Foundation.h>
|
|
|
-#import <QuartzCore/QuartzCore.h>
|
|
|
-
|
|
|
-#import "CCMenuAccount.h"
|
|
|
-
|
|
|
-////////////////////////////////////////////////////////////////////////////////
|
|
|
-////////////////////////////////////////////////////////////////////////////////
|
|
|
-
|
|
|
-@interface CCMenuOverlay : UIView
|
|
|
-@end
|
|
|
-
|
|
|
-@implementation CCMenuOverlay
|
|
|
-
|
|
|
-- (id)initWithFrame:(CGRect)frame maskSetting:(Boolean)mask
|
|
|
-{
|
|
|
- self = [super initWithFrame:frame];
|
|
|
-
|
|
|
- if (self) {
|
|
|
-
|
|
|
- if (mask) {
|
|
|
- self.backgroundColor = [[UIColor blackColor] colorWithAlphaComponent:0.17];
|
|
|
- } else {
|
|
|
- self.backgroundColor = [UIColor clearColor];
|
|
|
- }
|
|
|
-
|
|
|
- UITapGestureRecognizer *gestureRecognizer;
|
|
|
- gestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self
|
|
|
- action:@selector(singleTap:)];
|
|
|
-
|
|
|
- [self addGestureRecognizer:gestureRecognizer];
|
|
|
- }
|
|
|
- return self;
|
|
|
-}
|
|
|
-
|
|
|
-// thank horaceho https://github.com/horaceho
|
|
|
-// for his solution described in https://github.com/kolyvan/kxmenu/issues/9
|
|
|
-
|
|
|
-- (void)singleTap:(UITapGestureRecognizer *)recognizer
|
|
|
-{
|
|
|
- for (UIView *v in self.subviews) {
|
|
|
-#pragma clang diagnostic push
|
|
|
-#pragma clang diagnostic ignored "-Wundeclared-selector"
|
|
|
- if ([v isKindOfClass:[CCMenuView class]] && [v respondsToSelector:@selector(dismissMenu:)]) {
|
|
|
- [v performSelector:@selector(dismissMenu:) withObject:@(YES)];
|
|
|
- }
|
|
|
-#pragma clang diagnostic pop
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-@end
|
|
|
-
|
|
|
-////////////////////////////////////////////////////////////////////////////////
|
|
|
-////////////////////////////////////////////////////////////////////////////////
|
|
|
-
|
|
|
-@implementation CCMenuItem
|
|
|
-
|
|
|
-+ (instancetype) menuItem:(NSString *)title argument:(NSString*)argument image:(UIImage *)image target:(id)target action:(SEL)action
|
|
|
-{
|
|
|
- return [[CCMenuItem alloc] init:title argument:argument image:image target:target action:action];
|
|
|
-}
|
|
|
-
|
|
|
-- (id)init:(NSString *)title argument:(NSString*)argument image:(UIImage *)image target:(id)target action:(SEL)action
|
|
|
-{
|
|
|
- NSParameterAssert(title.length || image);
|
|
|
-
|
|
|
- self = [super init];
|
|
|
- if (self) {
|
|
|
-
|
|
|
- _title = title;
|
|
|
- _argument = argument;
|
|
|
- _image = image;
|
|
|
- _target = target;
|
|
|
- _action = action;
|
|
|
- }
|
|
|
- return self;
|
|
|
-}
|
|
|
-
|
|
|
-- (BOOL)enabled
|
|
|
-{
|
|
|
- return _target != nil && _action != NULL;
|
|
|
-}
|
|
|
-
|
|
|
-- (void)performAction
|
|
|
-{
|
|
|
- __strong id target = self.target;
|
|
|
-
|
|
|
- if (target && [target respondsToSelector:_action]) {
|
|
|
-
|
|
|
- [target performSelectorOnMainThread:_action withObject:self waitUntilDone:YES];
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-- (NSString *)description
|
|
|
-{
|
|
|
- return [NSString stringWithFormat:@"<%@ #%p %@>", [self class], self, _title];
|
|
|
-}
|
|
|
-
|
|
|
-@end
|
|
|
-
|
|
|
-////////////////////////////////////////////////////////////////////////////////
|
|
|
-////////////////////////////////////////////////////////////////////////////////
|
|
|
-
|
|
|
-typedef enum {
|
|
|
-
|
|
|
- CCMenuViewArrowDirectionNone,
|
|
|
- CCMenuViewArrowDirectionUp,
|
|
|
- CCMenuViewArrowDirectionDown,
|
|
|
- CCMenuViewArrowDirectionLeft,
|
|
|
- CCMenuViewArrowDirectionRight,
|
|
|
-
|
|
|
-} CCMenuViewArrowDirection;
|
|
|
-
|
|
|
-@implementation CCMenuView {
|
|
|
-
|
|
|
- CCMenuViewArrowDirection _arrowDirection;
|
|
|
- CGFloat _arrowPosition;
|
|
|
- UIView *_contentView;
|
|
|
- NSArray *_menuItems;
|
|
|
-}
|
|
|
-
|
|
|
-- (id)init
|
|
|
-{
|
|
|
- self = [super initWithFrame:CGRectZero];
|
|
|
- if(self) {
|
|
|
-
|
|
|
- self.backgroundColor = [UIColor clearColor];
|
|
|
-
|
|
|
- self.opaque = YES;
|
|
|
- self.alpha = 0;
|
|
|
- }
|
|
|
-
|
|
|
- return self;
|
|
|
-}
|
|
|
-
|
|
|
-- (void)setupFrameInView:(UIView *)view fromRect:(CGRect)fromRect
|
|
|
-{
|
|
|
- const CGSize contentSize = _contentView.frame.size;
|
|
|
- const CGFloat outerWidth = view.bounds.size.width;
|
|
|
- const CGFloat rectXM = fromRect.origin.x + fromRect.size.width * 0.5f;
|
|
|
- const CGFloat widthHalf = contentSize.width * 0.5f;
|
|
|
- const CGFloat kMargin = 5.f;
|
|
|
- const CGFloat rectY = fromRect.origin.y;
|
|
|
-
|
|
|
- if (self.CCMenuViewOptions.shadowOfMenu) {
|
|
|
- self.layer.shadowOpacity = 0.5;
|
|
|
- self.layer.shadowOffset = CGSizeMake(2, 2);
|
|
|
- self.layer.shadowRadius = 2;
|
|
|
-
|
|
|
- self.layer.shadowColor = [[UIColor blackColor] CGColor];
|
|
|
- }
|
|
|
-
|
|
|
- _arrowDirection = CCMenuViewArrowDirectionUp;
|
|
|
-
|
|
|
- CGPoint point = (CGPoint){
|
|
|
- rectXM - widthHalf,
|
|
|
- rectY - 4
|
|
|
- };
|
|
|
-
|
|
|
- if (point.x < kMargin)
|
|
|
- point.x = kMargin;
|
|
|
-
|
|
|
- if ((point.x + contentSize.width + kMargin) > outerWidth)
|
|
|
- point.x = outerWidth - contentSize.width - kMargin;
|
|
|
-
|
|
|
- _arrowPosition = rectXM - point.x;
|
|
|
- _contentView.frame = (CGRect){CGPointZero, contentSize};
|
|
|
-
|
|
|
- self.frame = (CGRect) {
|
|
|
-
|
|
|
- point,
|
|
|
- contentSize.width,
|
|
|
- contentSize.height - self.CCMenuViewOptions.arrowSize
|
|
|
- };
|
|
|
-}
|
|
|
-
|
|
|
-- (void)showMenuInView:(UIView *)view fromRect:(CGRect)rect menuItems:(NSArray *)menuItems withOptions:(OptionalConfiguration)options
|
|
|
-{
|
|
|
-
|
|
|
- self.CCMenuViewOptions = options;
|
|
|
-
|
|
|
- _menuItems = menuItems;
|
|
|
-
|
|
|
- _contentView = [self mkContentView];
|
|
|
- [self addSubview:_contentView];
|
|
|
-
|
|
|
- [self setupFrameInView:view fromRect:rect];
|
|
|
-
|
|
|
- CCMenuOverlay *overlay = [[CCMenuOverlay alloc] initWithFrame:view.bounds maskSetting:self.CCMenuViewOptions.maskToBackground];
|
|
|
-
|
|
|
- [overlay addSubview:self];
|
|
|
- [view addSubview:overlay];
|
|
|
-
|
|
|
- _contentView.hidden = YES;
|
|
|
- const CGRect toFrame = self.frame;
|
|
|
- self.frame = (CGRect){self.arrowPoint, 1, 1};
|
|
|
-
|
|
|
- [UIView animateWithDuration:0.2
|
|
|
- animations:^(void) {
|
|
|
-
|
|
|
- self.alpha = 1.0f;
|
|
|
- self.frame = toFrame;
|
|
|
-
|
|
|
- } completion:^(BOOL completed) {
|
|
|
- _contentView.hidden = NO;
|
|
|
- }];
|
|
|
-
|
|
|
-}
|
|
|
-
|
|
|
-- (void)dismissMenu:(BOOL) noAnimated
|
|
|
-{
|
|
|
- if (self.superview) {
|
|
|
-
|
|
|
- if (!noAnimated) {
|
|
|
-
|
|
|
- const CGRect toFrame = (CGRect){self.arrowPoint, 1, 1};
|
|
|
- _contentView.hidden = YES;
|
|
|
-
|
|
|
- [UIView animateWithDuration:0.1
|
|
|
- animations:^(void) {
|
|
|
-
|
|
|
- self.alpha = 0;
|
|
|
- self.frame = toFrame;
|
|
|
-
|
|
|
- } completion:^(BOOL finished) {
|
|
|
-
|
|
|
- if ([self.superview isKindOfClass:[CCMenuOverlay class]])
|
|
|
- [self.superview removeFromSuperview];
|
|
|
- [self removeFromSuperview];
|
|
|
- }];
|
|
|
-
|
|
|
- } else {
|
|
|
-
|
|
|
- if ([self.superview isKindOfClass:[CCMenuOverlay class]])
|
|
|
- [self.superview removeFromSuperview];
|
|
|
- [self removeFromSuperview];
|
|
|
- }
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-- (void)performAction:(id)sender
|
|
|
-{
|
|
|
- [self dismissMenu:YES];
|
|
|
-
|
|
|
- UIButton *button = (UIButton *)sender;
|
|
|
- CCMenuItem *menuItem = _menuItems[button.tag];
|
|
|
- [menuItem performAction];
|
|
|
-}
|
|
|
-
|
|
|
-- (UIView *)mkContentView
|
|
|
-{
|
|
|
- for (UIView *v in self.subviews) {
|
|
|
- [v removeFromSuperview];
|
|
|
- }
|
|
|
-
|
|
|
- if (!_menuItems.count)
|
|
|
- return nil;
|
|
|
-
|
|
|
- const CGFloat kMinMenuItemHeight = 32.f;
|
|
|
- const CGFloat kMinMenuItemWidth = 32.f;
|
|
|
- const CGFloat kMarginX = self.CCMenuViewOptions.marginXSpacing;
|
|
|
- const CGFloat kMarginY = self.CCMenuViewOptions.marginYSpacing;
|
|
|
-
|
|
|
- UIFont *titleFont = [CCMenuAccount titleFont];
|
|
|
- if (!titleFont) titleFont = [UIFont boldSystemFontOfSize:16];
|
|
|
-
|
|
|
- CGFloat maxImageWidth = 0;
|
|
|
- CGFloat maxItemHeight = 0;
|
|
|
- CGFloat maxItemWidth = 0;
|
|
|
-
|
|
|
- for (CCMenuItem *menuItem in _menuItems) {
|
|
|
-
|
|
|
- const CGSize imageSize = menuItem.image.size;
|
|
|
- if (imageSize.width > maxImageWidth)
|
|
|
- maxImageWidth = imageSize.width;
|
|
|
- }
|
|
|
-
|
|
|
- if (maxImageWidth) {
|
|
|
- maxImageWidth += kMarginX;
|
|
|
- }
|
|
|
-
|
|
|
- for (CCMenuItem *menuItem in _menuItems) {
|
|
|
-
|
|
|
-#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 70000
|
|
|
- const CGSize titleSize = [menuItem.title sizeWithAttributes:@{NSFontAttributeName: titleFont}];
|
|
|
-#else
|
|
|
- const CGSize titleSize = [menuItem.title sizeWithFont:titleFont];
|
|
|
-#endif
|
|
|
- const CGSize imageSize = menuItem.image.size;
|
|
|
-
|
|
|
- const CGFloat itemHeight = MAX(titleSize.height, imageSize.height) + kMarginY * 2;
|
|
|
-
|
|
|
- const CGFloat itemWidth = ((!menuItem.enabled && !menuItem.image) ? titleSize.width : maxImageWidth + titleSize.width) + kMarginX * 2 + self.CCMenuViewOptions.intervalSpacing;
|
|
|
-
|
|
|
- if (itemHeight > maxItemHeight)
|
|
|
- maxItemHeight = itemHeight;
|
|
|
-
|
|
|
- if (itemWidth > maxItemWidth)
|
|
|
- maxItemWidth = itemWidth;
|
|
|
- }
|
|
|
-
|
|
|
- maxItemWidth = MAX(maxItemWidth, kMinMenuItemWidth);
|
|
|
- maxItemHeight = MAX(maxItemHeight, kMinMenuItemHeight);
|
|
|
-
|
|
|
- const CGFloat titleX = maxImageWidth + self.CCMenuViewOptions.intervalSpacing;
|
|
|
-
|
|
|
- const CGFloat titleWidth = maxItemWidth - titleX - kMarginX *2;
|
|
|
-
|
|
|
- UIImage *selectedImage = [CCMenuView selectedImage:(CGSize){maxItemWidth, maxItemHeight + 2}];
|
|
|
- int insets = 0;
|
|
|
-
|
|
|
- if (self.CCMenuViewOptions.seperatorLineHasInsets) {
|
|
|
- insets = 4;
|
|
|
- }
|
|
|
-
|
|
|
- UIImage *gradientLine = [CCMenuView gradientLine: (CGSize){maxItemWidth- kMarginX * insets, 0.4} color:self.CCMenuViewOptions.separatorColor];
|
|
|
-
|
|
|
- UIView *contentView = [[UIView alloc] initWithFrame:CGRectZero];
|
|
|
- contentView.autoresizingMask = UIViewAutoresizingNone;
|
|
|
-
|
|
|
- contentView.backgroundColor = [UIColor clearColor];
|
|
|
-
|
|
|
- contentView.opaque = NO;
|
|
|
-
|
|
|
- CGFloat itemY = kMarginY * 2;
|
|
|
-
|
|
|
- NSUInteger itemNum = 0;
|
|
|
-
|
|
|
- for (CCMenuItem *menuItem in _menuItems) {
|
|
|
-
|
|
|
- const CGRect itemFrame = (CGRect){0, itemY-kMarginY * 2 + self.CCMenuViewOptions.menuCornerRadius, maxItemWidth, maxItemHeight};
|
|
|
-
|
|
|
- UIView *itemView = [[UIView alloc] initWithFrame:itemFrame];
|
|
|
- itemView.autoresizingMask = UIViewAutoresizingNone;
|
|
|
-
|
|
|
- itemView.opaque = NO;
|
|
|
-
|
|
|
- [contentView addSubview:itemView];
|
|
|
-
|
|
|
- if (menuItem.enabled) {
|
|
|
-
|
|
|
- UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
|
|
|
- button.tag = itemNum;
|
|
|
- button.frame = itemView.bounds;
|
|
|
- button.enabled = menuItem.enabled;
|
|
|
-
|
|
|
- button.backgroundColor = [UIColor clearColor];
|
|
|
-
|
|
|
- button.opaque = NO;
|
|
|
- button.autoresizingMask = UIViewAutoresizingNone;
|
|
|
-
|
|
|
- [button addTarget:self
|
|
|
- action:@selector(performAction:)
|
|
|
- forControlEvents:UIControlEventTouchUpInside];
|
|
|
-
|
|
|
- [button setBackgroundImage:selectedImage forState:UIControlStateHighlighted];
|
|
|
-
|
|
|
- [itemView addSubview:button];
|
|
|
- }
|
|
|
-
|
|
|
- if (menuItem.title.length) {
|
|
|
-
|
|
|
- CGRect titleFrame;
|
|
|
-
|
|
|
- if (!menuItem.enabled && !menuItem.image) {
|
|
|
-
|
|
|
- titleFrame = (CGRect){
|
|
|
- kMarginX * 2,
|
|
|
- kMarginY,
|
|
|
- maxItemWidth - kMarginX * 4,
|
|
|
- maxItemHeight - kMarginY * 2
|
|
|
- };
|
|
|
-
|
|
|
- } else {
|
|
|
-
|
|
|
- titleFrame = (CGRect){
|
|
|
- titleX,
|
|
|
- kMarginY,
|
|
|
- titleWidth,
|
|
|
- maxItemHeight - kMarginY * 2
|
|
|
- };
|
|
|
- }
|
|
|
-
|
|
|
- UILabel *titleLabel = [[UILabel alloc] initWithFrame:titleFrame];
|
|
|
- titleLabel.text = menuItem.title;
|
|
|
- titleLabel.font = titleFont;
|
|
|
- titleLabel.textAlignment = menuItem.alignment;
|
|
|
-
|
|
|
- titleLabel.textColor = self.CCMenuViewOptions.textColor;
|
|
|
-
|
|
|
- titleLabel.backgroundColor = [UIColor clearColor];
|
|
|
-
|
|
|
- titleLabel.autoresizingMask = UIViewAutoresizingNone;
|
|
|
-
|
|
|
- [itemView addSubview:titleLabel];
|
|
|
- }
|
|
|
-
|
|
|
- if (menuItem.image) {
|
|
|
-
|
|
|
- const CGRect imageFrame = {kMarginX * 2, kMarginY, maxImageWidth, maxItemHeight - kMarginY * 2};
|
|
|
- UIImageView *imageView = [[UIImageView alloc] initWithFrame:imageFrame];
|
|
|
- imageView.image = menuItem.image;
|
|
|
- imageView.clipsToBounds = YES;
|
|
|
- imageView.contentMode = UIViewContentModeCenter;
|
|
|
- imageView.autoresizingMask = UIViewAutoresizingNone;
|
|
|
- [itemView addSubview:imageView];
|
|
|
- }
|
|
|
-
|
|
|
- if (itemNum < _menuItems.count - 1) {
|
|
|
-
|
|
|
- UIImageView *gradientView = [[UIImageView alloc] initWithImage:gradientLine];
|
|
|
-
|
|
|
- if (self.CCMenuViewOptions.seperatorLineHasInsets) {
|
|
|
- gradientView.frame = (CGRect){kMarginX * 2, maxItemHeight + 1, gradientLine.size};
|
|
|
- } else {
|
|
|
- gradientView.frame = (CGRect){0, maxItemHeight + 1 , gradientLine.size};
|
|
|
- }
|
|
|
-
|
|
|
- gradientView.contentMode = UIViewContentModeLeft;
|
|
|
-
|
|
|
- if (self.CCMenuViewOptions.hasSeperatorLine) {
|
|
|
- [itemView addSubview:gradientView];
|
|
|
- itemY += 2;
|
|
|
- }
|
|
|
-
|
|
|
- itemY += maxItemHeight;
|
|
|
- }
|
|
|
-
|
|
|
- ++itemNum;
|
|
|
- }
|
|
|
-
|
|
|
- itemY += self.CCMenuViewOptions.menuCornerRadius;
|
|
|
-
|
|
|
- contentView.frame = (CGRect){0, 0, maxItemWidth, itemY + kMarginY * 2 + 5.5 + self.CCMenuViewOptions.menuCornerRadius};
|
|
|
-
|
|
|
- return contentView;
|
|
|
-}
|
|
|
-
|
|
|
-- (CGPoint)arrowPoint
|
|
|
-{
|
|
|
- CGPoint point;
|
|
|
-
|
|
|
- if (_arrowDirection == CCMenuViewArrowDirectionUp) {
|
|
|
-
|
|
|
- point = (CGPoint){ CGRectGetMinX(self.frame) + _arrowPosition, CGRectGetMinY(self.frame) };
|
|
|
-
|
|
|
- } else if (_arrowDirection == CCMenuViewArrowDirectionDown) {
|
|
|
-
|
|
|
- point = (CGPoint){ CGRectGetMinX(self.frame) + _arrowPosition, CGRectGetMaxY(self.frame) };
|
|
|
-
|
|
|
- } else if (_arrowDirection == CCMenuViewArrowDirectionLeft) {
|
|
|
-
|
|
|
- point = (CGPoint){ CGRectGetMinX(self.frame), CGRectGetMinY(self.frame) + _arrowPosition };
|
|
|
-
|
|
|
- } else if (_arrowDirection == CCMenuViewArrowDirectionRight) {
|
|
|
-
|
|
|
- point = (CGPoint){ CGRectGetMaxX(self.frame), CGRectGetMinY(self.frame) + _arrowPosition };
|
|
|
-
|
|
|
- } else {
|
|
|
-
|
|
|
- point = self.center;
|
|
|
- }
|
|
|
-
|
|
|
- return point;
|
|
|
-}
|
|
|
-
|
|
|
-+ (UIImage *)selectedImage:(CGSize)size
|
|
|
-{
|
|
|
-
|
|
|
- const CGFloat locations[] = {0,1};
|
|
|
-
|
|
|
- const CGFloat components[] = {
|
|
|
- 0.890,0.890,0.890,1,
|
|
|
- 0.890,0.890,0.890,1
|
|
|
- };
|
|
|
-
|
|
|
- return [self gradientImageWithSize:size locations:locations components:components count:2];
|
|
|
-}
|
|
|
-
|
|
|
-+ (UIImage *)gradientLine:(CGSize)size color:(UIColor *)color
|
|
|
-{
|
|
|
- if (color == nil) color = UIColor.lightGrayColor;
|
|
|
- const CGFloat locations[5] = {0,0.2,0.5,0.8,1};
|
|
|
- const CGFloat *componentsColor = CGColorGetComponents(color.CGColor);
|
|
|
- const CGFloat R = componentsColor[0], G = componentsColor[1], B = componentsColor[2];
|
|
|
-
|
|
|
- const CGFloat components[20] = {
|
|
|
- R,G,B,1,
|
|
|
- R,G,B,1,
|
|
|
- R,G,B,1,
|
|
|
- R,G,B,1,
|
|
|
- R,G,B,1
|
|
|
- };
|
|
|
-
|
|
|
- return [self gradientImageWithSize:size locations:locations components:components count:5];
|
|
|
-}
|
|
|
-
|
|
|
-+ (UIImage *)gradientImageWithSize:(CGSize)size locations:(const CGFloat [])locations components:(const CGFloat [])components count:(NSUInteger)count
|
|
|
-{
|
|
|
- UIGraphicsBeginImageContextWithOptions(size, NO, 0);
|
|
|
- CGContextRef context = UIGraphicsGetCurrentContext();
|
|
|
-
|
|
|
- CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
|
|
|
- CGGradientRef colorGradient = CGGradientCreateWithColorComponents(colorSpace, components, locations, 2);
|
|
|
- CGColorSpaceRelease(colorSpace);
|
|
|
- CGContextDrawLinearGradient(context, colorGradient, (CGPoint){0, 0}, (CGPoint){size.width, 0}, 0);
|
|
|
- CGGradientRelease(colorGradient);
|
|
|
-
|
|
|
- UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
|
|
|
- UIGraphicsEndImageContext();
|
|
|
- return image;
|
|
|
-}
|
|
|
-
|
|
|
-- (void)drawRect:(CGRect)rect
|
|
|
-{
|
|
|
- [self drawBackground:self.bounds inContext:UIGraphicsGetCurrentContext()];
|
|
|
-}
|
|
|
-
|
|
|
-- (void)drawBackground:(CGRect)frame inContext:(CGContextRef)context
|
|
|
-{
|
|
|
- CGFloat R0 = self.CCMenuViewOptions.menuBackgroundColor.R, G0 = self.CCMenuViewOptions.menuBackgroundColor.G, B0 = self.CCMenuViewOptions.menuBackgroundColor.B;
|
|
|
-
|
|
|
- CGFloat R1 = R0, G1 = G0, B1 = B0;
|
|
|
-
|
|
|
- UIColor *tintColor = [CCMenuAccount tintColor];
|
|
|
- if (tintColor) {
|
|
|
-
|
|
|
- CGFloat a;
|
|
|
- [tintColor getRed:&R0 green:&G0 blue:&B0 alpha:&a];
|
|
|
- }
|
|
|
-
|
|
|
- CGFloat X0 = frame.origin.x;
|
|
|
- CGFloat X1 = frame.origin.x + frame.size.width;
|
|
|
- CGFloat Y0 = frame.origin.y;
|
|
|
- CGFloat Y1 = frame.origin.y + frame.size.height;
|
|
|
-
|
|
|
- // render arrow
|
|
|
-
|
|
|
- UIBezierPath *arrowPath = [UIBezierPath bezierPath];
|
|
|
-
|
|
|
- // fix the issue with gap of arrow's base if on the edge
|
|
|
- const CGFloat kEmbedFix = 3.f;
|
|
|
-
|
|
|
- if (_arrowDirection == CCMenuViewArrowDirectionUp) {
|
|
|
-
|
|
|
- const CGFloat arrowXM = _arrowPosition;
|
|
|
- const CGFloat arrowX0 = arrowXM - self.CCMenuViewOptions.arrowSize;
|
|
|
- const CGFloat arrowX1 = arrowXM + self.CCMenuViewOptions.arrowSize;
|
|
|
- const CGFloat arrowY0 = Y0;
|
|
|
- const CGFloat arrowY1 = Y0 + self.CCMenuViewOptions.arrowSize + kEmbedFix;
|
|
|
-
|
|
|
- [arrowPath moveToPoint: (CGPoint){arrowXM, arrowY0}];
|
|
|
- [arrowPath addLineToPoint: (CGPoint){arrowX1, arrowY1}];
|
|
|
- [arrowPath addLineToPoint: (CGPoint){arrowX0, arrowY1}];
|
|
|
- [arrowPath addLineToPoint: (CGPoint){arrowXM, arrowY0}];
|
|
|
-
|
|
|
-
|
|
|
- [[UIColor colorWithRed:R0 green:G0 blue:B0 alpha:1] set];
|
|
|
-
|
|
|
- Y0 += self.CCMenuViewOptions.arrowSize;
|
|
|
-
|
|
|
- } else if (_arrowDirection == CCMenuViewArrowDirectionDown) {
|
|
|
-
|
|
|
- const CGFloat arrowXM = _arrowPosition;
|
|
|
- const CGFloat arrowX0 = arrowXM - self.CCMenuViewOptions.arrowSize;
|
|
|
- const CGFloat arrowX1 = arrowXM + self.CCMenuViewOptions.arrowSize;
|
|
|
- const CGFloat arrowY0 = Y1 - self.CCMenuViewOptions.arrowSize - kEmbedFix;
|
|
|
- const CGFloat arrowY1 = Y1;
|
|
|
-
|
|
|
- [arrowPath moveToPoint: (CGPoint){arrowXM, arrowY1}];
|
|
|
- [arrowPath addLineToPoint: (CGPoint){arrowX1, arrowY0}];
|
|
|
- [arrowPath addLineToPoint: (CGPoint){arrowX0, arrowY0}];
|
|
|
- [arrowPath addLineToPoint: (CGPoint){arrowXM, arrowY1}];
|
|
|
-
|
|
|
- [[UIColor colorWithRed:R1 green:G1 blue:B1 alpha:1] set];
|
|
|
-
|
|
|
- Y1 -= self.CCMenuViewOptions.arrowSize;
|
|
|
-
|
|
|
- } else if (_arrowDirection == CCMenuViewArrowDirectionLeft) {
|
|
|
-
|
|
|
- const CGFloat arrowYM = _arrowPosition;
|
|
|
- const CGFloat arrowX0 = X0;
|
|
|
- const CGFloat arrowX1 = X0 + self.CCMenuViewOptions.arrowSize + kEmbedFix;
|
|
|
- const CGFloat arrowY0 = arrowYM - self.CCMenuViewOptions.arrowSize;;
|
|
|
- const CGFloat arrowY1 = arrowYM + self.CCMenuViewOptions.arrowSize;
|
|
|
-
|
|
|
- [arrowPath moveToPoint: (CGPoint){arrowX0, arrowYM}];
|
|
|
- [arrowPath addLineToPoint: (CGPoint){arrowX1, arrowY0}];
|
|
|
- [arrowPath addLineToPoint: (CGPoint){arrowX1, arrowY1}];
|
|
|
- [arrowPath addLineToPoint: (CGPoint){arrowX0, arrowYM}];
|
|
|
-
|
|
|
- [[UIColor colorWithRed:R0 green:G0 blue:B0 alpha:1] set];
|
|
|
-
|
|
|
- X0 += self.CCMenuViewOptions.arrowSize;
|
|
|
-
|
|
|
- } else if (_arrowDirection == CCMenuViewArrowDirectionRight) {
|
|
|
-
|
|
|
- const CGFloat arrowYM = _arrowPosition;
|
|
|
- const CGFloat arrowX0 = X1;
|
|
|
- const CGFloat arrowX1 = X1 - self.CCMenuViewOptions.arrowSize - kEmbedFix;
|
|
|
- const CGFloat arrowY0 = arrowYM - self.CCMenuViewOptions.arrowSize;;
|
|
|
- const CGFloat arrowY1 = arrowYM + self.CCMenuViewOptions.arrowSize;
|
|
|
-
|
|
|
- [arrowPath moveToPoint: (CGPoint){arrowX0, arrowYM}];
|
|
|
- [arrowPath addLineToPoint: (CGPoint){arrowX1, arrowY0}];
|
|
|
- [arrowPath addLineToPoint: (CGPoint){arrowX1, arrowY1}];
|
|
|
- [arrowPath addLineToPoint: (CGPoint){arrowX0, arrowYM}];
|
|
|
-
|
|
|
- [[UIColor colorWithRed:R1 green:G1 blue:B1 alpha:1] set];
|
|
|
-
|
|
|
- X1 -= self.CCMenuViewOptions.arrowSize;
|
|
|
- }
|
|
|
-
|
|
|
- [arrowPath fill];
|
|
|
-
|
|
|
- // render body
|
|
|
-
|
|
|
- const CGRect bodyFrame = {X0, Y0, X1 - X0, Y1 - Y0};
|
|
|
-
|
|
|
- UIBezierPath *borderPath = [UIBezierPath bezierPathWithRoundedRect:bodyFrame cornerRadius:self.CCMenuViewOptions.menuCornerRadius];
|
|
|
-
|
|
|
- const CGFloat locations[] = {0, 1};
|
|
|
- const CGFloat components[] = {
|
|
|
- R0, G0, B0, 1,
|
|
|
- R1, G1, B1, 1,
|
|
|
- };
|
|
|
-
|
|
|
- CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
|
|
|
- CGGradientRef gradient = CGGradientCreateWithColorComponents(colorSpace, components, locations, sizeof(locations)/sizeof(locations[0]));
|
|
|
- CGColorSpaceRelease(colorSpace);
|
|
|
-
|
|
|
- [borderPath addClip];
|
|
|
-
|
|
|
- CGPoint start, end;
|
|
|
-
|
|
|
- if (_arrowDirection == CCMenuViewArrowDirectionLeft ||
|
|
|
- _arrowDirection == CCMenuViewArrowDirectionRight) {
|
|
|
-
|
|
|
- start = (CGPoint){X0, Y0};
|
|
|
- end = (CGPoint){X1, Y0};
|
|
|
-
|
|
|
- } else {
|
|
|
-
|
|
|
- start = (CGPoint){X0, Y0};
|
|
|
- end = (CGPoint){X0, Y1};
|
|
|
- }
|
|
|
-
|
|
|
- CGContextDrawLinearGradient(context, gradient, start, end, 0);
|
|
|
-
|
|
|
- CGGradientRelease(gradient);
|
|
|
-}
|
|
|
-
|
|
|
-@end
|
|
|
-
|
|
|
-////////////////////////////////////////////////////////////////////////////////
|
|
|
-////////////////////////////////////////////////////////////////////////////////
|
|
|
-
|
|
|
-static CCMenuAccount *gMenu;
|
|
|
-static UIColor *gTintColor;
|
|
|
-static UIFont *gTitleFont;
|
|
|
-
|
|
|
-@implementation CCMenuAccount {
|
|
|
-
|
|
|
- CCMenuView *_menuView;
|
|
|
- BOOL _observing;
|
|
|
-}
|
|
|
-
|
|
|
-+ (instancetype)sharedMenu
|
|
|
-{
|
|
|
- static dispatch_once_t onceToken;
|
|
|
- dispatch_once(&onceToken, ^{
|
|
|
-
|
|
|
- gMenu = [[CCMenuAccount alloc] init];
|
|
|
- });
|
|
|
- return gMenu;
|
|
|
-}
|
|
|
-
|
|
|
-- (id)init
|
|
|
-{
|
|
|
- NSAssert(!gMenu, @"singleton object");
|
|
|
-
|
|
|
- self = [super init];
|
|
|
- if (self) {
|
|
|
- }
|
|
|
- return self;
|
|
|
-}
|
|
|
-
|
|
|
-- (void)dealloc
|
|
|
-{
|
|
|
- if (_observing) {
|
|
|
- [[NSNotificationCenter defaultCenter] removeObserver:self];
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-- (void)showMenuInView:(UIView *)view fromRect:(CGRect)rect menuItems:(NSArray *)menuItems withOptions:(OptionalConfiguration) options
|
|
|
-{
|
|
|
- NSParameterAssert(view);
|
|
|
- NSParameterAssert(menuItems.count);
|
|
|
-
|
|
|
- if (_menuView) {
|
|
|
-
|
|
|
- [_menuView dismissMenu:NO];
|
|
|
- _menuView = nil;
|
|
|
- }
|
|
|
-
|
|
|
- if (!_observing) {
|
|
|
-
|
|
|
- _observing = YES;
|
|
|
-
|
|
|
- [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(orientationWillChange:) name:UIApplicationWillChangeStatusBarOrientationNotification object:nil];
|
|
|
- }
|
|
|
-
|
|
|
-
|
|
|
- _menuView = [[CCMenuView alloc] init];
|
|
|
- [_menuView showMenuInView:view fromRect:rect menuItems:menuItems withOptions:options];
|
|
|
-}
|
|
|
-
|
|
|
-- (void)dismissMenu
|
|
|
-{
|
|
|
- if (_menuView) {
|
|
|
-
|
|
|
- [_menuView dismissMenu:NO];
|
|
|
- _menuView = nil;
|
|
|
- }
|
|
|
-
|
|
|
- if (_observing) {
|
|
|
-
|
|
|
- _observing = NO;
|
|
|
- [[NSNotificationCenter defaultCenter] removeObserver:self];
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-- (void)orientationWillChange: (NSNotification *) n
|
|
|
-{
|
|
|
- [self dismissMenu];
|
|
|
-}
|
|
|
-
|
|
|
-+ (void)showMenuInView:(UIView *)view fromRect:(CGRect)rect menuItems:(NSArray *)menuItems withOptions:(OptionalConfiguration)options
|
|
|
-{
|
|
|
- [[self sharedMenu] showMenuInView:view fromRect:rect menuItems:menuItems withOptions:options];
|
|
|
-}
|
|
|
-
|
|
|
-+ (void)dismissMenu
|
|
|
-{
|
|
|
- [[self sharedMenu] dismissMenu];
|
|
|
-}
|
|
|
-
|
|
|
-+ (UIColor *)tintColor
|
|
|
-{
|
|
|
- return gTintColor;
|
|
|
-}
|
|
|
-
|
|
|
-+ (void)setTintColor:(UIColor *)tintColor
|
|
|
-{
|
|
|
- if (tintColor != gTintColor) {
|
|
|
- gTintColor = tintColor;
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-+ (UIFont *)titleFont
|
|
|
-{
|
|
|
- return gTitleFont;
|
|
|
-}
|
|
|
-
|
|
|
-+ (void)setTitleFont:(UIFont *)titleFont
|
|
|
-{
|
|
|
- if (titleFont != gTitleFont) {
|
|
|
- gTitleFont = titleFont;
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-@end
|