Repo created

This commit is contained in:
Fr4nz D13trich 2025-11-22 13:58:55 +01:00
parent 4af19165ec
commit 68073add76
12458 changed files with 12350765 additions and 2 deletions

View file

@ -0,0 +1,18 @@
#import "MWMMyPositionMode.h"
@interface MWMSideButtons : NSObject
+ (MWMSideButtons *)buttons;
@property (nonatomic) BOOL zoomHidden;
@property (nonatomic) BOOL hidden;
@property (nonatomic, readonly) UIView *view;
- (instancetype)init __attribute__((unavailable("init is not available")));
- (instancetype)initWithParentView:(UIView *)view;
- (void)processMyPositionStateModeEvent:(MWMMyPositionMode)mode;
+ (void)updateAvailableArea:(CGRect)frame;
@end

View file

@ -0,0 +1,149 @@
#import "MWMSideButtons.h"
#import "MWMButton.h"
#import "MWMLocationManager.h"
#import "MWMMapViewControlsManager.h"
#import "MWMRouter.h"
#import "MWMSettings.h"
#import "MWMSideButtonsView.h"
#import "SwiftBridge.h"
#include <CoreApi/Framework.h>
namespace
{
NSString * const kMWMSideButtonsViewNibName = @"MWMSideButtonsView";
NSString * const kUDDidShowLongTapToShowSideButtonsToast = @"kUDDidShowLongTapToShowSideButtonsToast";
} // namespace
@interface MWMMapViewControlsManager ()
@property(nonatomic) MWMSideButtons * sideButtons;
@end
@interface MWMSideButtons ()
@property(nonatomic) IBOutlet MWMSideButtonsView * sideView;
@property(weak, nonatomic) IBOutlet MWMButton * zoomInButton;
@property(weak, nonatomic) IBOutlet MWMButton * zoomOutButton;
@property(weak, nonatomic) IBOutlet MWMButton * locationButton;
@property(nonatomic) BOOL zoomSwipeEnabled;
@property(nonatomic, readonly) BOOL isZoomEnabled;
@property(nonatomic) MWMMyPositionMode locationMode;
@end
@implementation MWMSideButtons
- (UIView *)view {
return self.sideView;
}
+ (MWMSideButtons *)buttons { return [MWMMapViewControlsManager manager].sideButtons; }
- (instancetype)initWithParentView:(UIView *)view
{
self = [super init];
if (self)
{
[NSBundle.mainBundle loadNibNamed:kMWMSideButtonsViewNibName owner:self options:nil];
[view addSubview:self.sideView];
[self.sideView setNeedsLayout];
self.zoomSwipeEnabled = NO;
self.zoomHidden = NO;
}
return self;
}
+ (void)updateAvailableArea:(CGRect)frame { [[self buttons].sideView updateAvailableArea:frame]; }
- (void)zoomIn
{
GetFramework().Scale(Framework::SCALE_MAG, true);
}
- (void)zoomOut
{
GetFramework().Scale(Framework::SCALE_MIN, true);
}
- (void)processMyPositionStateModeEvent:(MWMMyPositionMode)mode
{
[self refreshLocationButtonState:mode];
self.locationMode = mode;
}
#pragma mark - Location button
- (void)refreshLocationButtonState:(MWMMyPositionMode)state
{
MWMButton * locBtn = self.locationButton;
[locBtn.imageView stopRotation];
switch (state)
{
case MWMMyPositionModePendingPosition:
{
[locBtn setStyleNameAndApply: @"ButtonPending"];
[locBtn.imageView startRotation:1];
break;
}
case MWMMyPositionModeNotFollow:
case MWMMyPositionModeNotFollowNoPosition: [locBtn setStyleNameAndApply: @"ButtonGetPosition"]; break;
case MWMMyPositionModeFollow: [locBtn setStyleNameAndApply: @"ButtonFollow"]; break;
case MWMMyPositionModeFollowAndRotate: [locBtn setStyleNameAndApply: @"ButtonFollowAndRotate"]; break;
}
}
#pragma mark - Actions
- (IBAction)zoomTouchDown:(UIButton *)sender { self.zoomSwipeEnabled = YES; }
- (IBAction)zoomTouchUpInside:(UIButton *)sender
{
self.zoomSwipeEnabled = NO;
if ([sender isEqual:self.zoomInButton])
[self zoomIn];
else
[self zoomOut];
}
- (IBAction)zoomTouchUpOutside:(UIButton *)sender { self.zoomSwipeEnabled = NO; }
- (IBAction)zoomSwipe:(UIPanGestureRecognizer *)sender
{
if (!self.zoomSwipeEnabled)
return;
UIView * const superview = self.sideView.superview;
CGFloat const translation =
-[sender translationInView:superview].y / superview.bounds.size.height;
CGFloat const scaleFactor = exp(translation);
GetFramework().Scale(scaleFactor, false);
}
- (IBAction)locationTouchUpInside
{
[MWMLocationManager enableLocationAlert];
GetFramework().SwitchMyPositionNextMode();
}
#pragma mark - Properties
- (BOOL)zoomHidden { return self.sideView.zoomHidden; }
- (void)setZoomHidden:(BOOL)zoomHidden
{
if ([MWMRouter isRoutingActive])
self.sideView.zoomHidden = NO;
else
self.sideView.zoomHidden = [MWMSettings zoomButtonsEnabled] ? zoomHidden : YES;
}
- (BOOL)hidden { return self.sideView.hidden; }
- (void)setHidden:(BOOL)hidden
{
if (!self.hidden && hidden)
[Toast showWithText:L(@"long_tap_toast")];
return [self.sideView setHidden:hidden animated:YES];
}
@end

View file

@ -0,0 +1,12 @@
@interface MWMSideButtonsView : UIView
@property (nonatomic) BOOL zoomHidden;
- (instancetype)initWithFrame:(CGRect)frame __attribute__((unavailable("initWithFrame is not available")));
- (instancetype)init __attribute__((unavailable("init is not available")));
- (void)setHidden:(BOOL)hidden animated:(BOOL)animated;
- (void)updateAvailableArea:(CGRect)frame;
@end

View file

@ -0,0 +1,170 @@
#import "MWMSideButtonsView.h"
#import "MWMButton.h"
#import "MWMRouter.h"
#import "MWMMapViewControlsCommon.h"
#include "base/math.hpp"
namespace {
CGFloat const kLocationButtonSpacingMax = 52;
CGFloat const kLocationButtonSpacingMin = 8;
CGFloat const kButtonsTopOffset = 6;
CGFloat const kButtonsBottomOffset = 6;
} // namespace
@interface MWMSideButtonsView ()
@property(weak, nonatomic) IBOutlet MWMButton *zoomIn;
@property(weak, nonatomic) IBOutlet MWMButton *zoomOut;
@property(weak, nonatomic) IBOutlet MWMButton *location;
@property(nonatomic) CGRect availableArea;
@end
@implementation MWMSideButtonsView
- (void)awakeFromNib {
[super awakeFromNib];
self.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
}
- (void)layoutSubviews {
CGFloat spacing = self.availableHeight - self.zoomOut.maxY - self.location.height;
spacing = math::Clamp(spacing, kLocationButtonSpacingMin, kLocationButtonSpacingMax);
if (!IPAD && (UIDevice.currentDevice.orientation == UIDeviceOrientationLandscapeLeft || UIDevice.currentDevice.orientation == UIDeviceOrientationLandscapeRight) && [MWMRouter isRoutingActive]) {
spacing = spacing - 36;
}
self.location.minY = self.zoomOut.maxY + spacing;
self.bounds = {{}, {self.zoomOut.width, self.location.maxY}};
if (self.zoomHidden)
self.height = self.location.height;
self.location.maxY = self.height;
[self animate];
[super layoutSubviews];
}
- (void)layoutXPosition:(BOOL)hidden {
if (UIApplication.sharedApplication.userInterfaceLayoutDirection == UIUserInterfaceLayoutDirectionRightToLeft) {
if (hidden)
self.maxX = 0;
else
self.minX = self.availableArea.origin.x + kViewControlsOffsetToBounds;
} else {
const auto availableAreaMaxX = self.availableArea.origin.x + self.availableArea.size.width;
if (hidden)
self.minX = self.superview.width;
else
self.maxX = availableAreaMaxX - kViewControlsOffsetToBounds;
}
}
- (void)layoutYPosition {
CGFloat const centerShift = (self.height - self.zoomIn.midY - self.zoomOut.midY) / 2;
[UIView animateWithDuration:kDefaultAnimationDuration
animations:^{
self.midY = centerShift + self.superview.height / 2;
if ([MWMRouter isRoutingActive]) {
self.midY = self.midY - 18;
}
if (self.maxY > self.bottomBound)
self.maxY = self.bottomBound;
}];
}
- (void)fadeZoomButtonsShow:(BOOL)show {
CGFloat const alpha = show ? 1.0 : 0.0;
[UIView animateWithDuration:kDefaultAnimationDuration
animations:^{
self.zoomIn.alpha = alpha;
self.zoomOut.alpha = alpha;
}];
}
- (void)fadeLocationButtonShow:(BOOL)show {
[UIView animateWithDuration:kDefaultAnimationDuration
animations:^{
self.location.alpha = show ? 1.0 : 0.0;
}];
}
// Show/hide zoom and location buttons depending on available vertical space.
- (void)animate {
[self layoutYPosition];
BOOL const isZoomHidden = self.zoomIn.alpha == 0.0;
BOOL const willZoomHide = (self.location.maxY > self.availableHeight);
if (willZoomHide != isZoomHidden)
[self fadeZoomButtonsShow: !willZoomHide];
BOOL const isLocationHidden = self.location.alpha == 0.0;
BOOL const willLocationHide = (self.location.height > self.availableHeight);
if (willLocationHide != isLocationHidden)
[self fadeLocationButtonShow: !willLocationHide];
}
#pragma mark - Properties
- (void)setZoomHidden:(BOOL)zoomHidden {
_zoomHidden = zoomHidden;
self.zoomIn.hidden = zoomHidden;
self.zoomOut.hidden = zoomHidden;
[self setNeedsLayout];
}
- (void)setHidden:(BOOL)hidden animated:(BOOL)animated {
if (animated) {
if (self.hidden == hidden)
return;
// Side buttons should be visible during any our show/hide anamation.
// Visibility should be detemined by alpha, not self.hidden.
self.hidden = NO;
[UIView animateWithDuration:kDefaultAnimationDuration
animations:^{
self.alpha = hidden ? 0.0 : 1.0;
[self layoutXPosition:hidden];
}
completion:^(BOOL finished) {
self.hidden = hidden;
}];
} else {
self.hidden = hidden;
}
}
- (void)updateAvailableArea:(CGRect)frame {
if (CGRectEqualToRect(self.availableArea, frame))
return;
// If during our show/hide animation position is changed it is corrupted.
// Such kind of animation has 2 keys (opacity and position).
// But there are other animation cases like change of orientation.
// So we can use condition below:
// if (self.layer.animationKeys.count != 2)
// More elegant way is to check if x values are changed.
// If no - there is no need to update self x values.
if (self.availableArea.origin.x != frame.origin.x || self.availableArea.size.width != frame.size.width)
{
self.availableArea = frame;
[self layoutXPosition:self.hidden];
}
else
self.availableArea = frame;
[self setNeedsLayout];
}
- (CGFloat)availableHeight {
return self.availableArea.size.height - kButtonsTopOffset - kButtonsBottomOffset;
}
- (CGFloat)topBound {
return self.availableArea.origin.y + kButtonsTopOffset;
}
- (CGFloat)bottomBound {
auto const area = self.availableArea;
return area.origin.y + area.size.height - kButtonsBottomOffset;
}
@end

View file

@ -0,0 +1,91 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="15702" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
<device id="retina4_7" orientation="portrait" appearance="light"/>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="15704"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner" customClass="MWMSideButtons">
<connections>
<outlet property="locationButton" destination="fUK-2V-4ya" id="CBK-kp-DFE"/>
<outlet property="sideView" destination="ek2-ZW-pCm" id="sbV-Vv-Wrp"/>
<outlet property="zoomInButton" destination="NO3-Xl-Oka" id="ePH-BR-gfW"/>
<outlet property="zoomOutButton" destination="hwn-8L-cFX" id="fYk-mf-gUY"/>
</connections>
</placeholder>
<view contentMode="scaleToFill" id="ek2-ZW-pCm" customClass="MWMSideButtonsView" propertyAccessControl="none">
<rect key="frame" x="0.0" y="0.0" width="56" height="228"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<subviews>
<button opaque="NO" contentMode="scaleToFill" fixedFrame="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="NO3-Xl-Oka" userLabel="ZoomIn" customClass="MWMButton">
<rect key="frame" x="0.0" y="0.0" width="56" height="56"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<state key="normal" image="btn_zoom_in_light">
<color key="titleShadowColor" red="0.5" green="0.5" blue="0.5" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</state>
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="string" keyPath="styleName" value="ButtonZoomIn"/>
</userDefinedRuntimeAttributes>
<connections>
<action selector="zoomTouchDown:" destination="-1" eventType="touchDown" id="5VF-m8-Lwc"/>
<action selector="zoomTouchUpInside:" destination="-1" eventType="touchUpInside" id="wbL-zf-fH8"/>
<action selector="zoomTouchUpOutside:" destination="-1" eventType="touchUpOutside" id="w6V-A2-cZM"/>
</connections>
</button>
<button opaque="NO" contentMode="scaleToFill" fixedFrame="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="hwn-8L-cFX" userLabel="ZoomOut" customClass="MWMButton">
<rect key="frame" x="0.0" y="64" width="56" height="56"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<state key="normal" image="btn_zoom_out_light">
<color key="titleShadowColor" red="0.5" green="0.5" blue="0.5" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</state>
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="string" keyPath="styleName" value="ButtonZoomOut"/>
</userDefinedRuntimeAttributes>
<connections>
<action selector="zoomTouchDown:" destination="-1" eventType="touchDown" id="o4X-Kp-9ka"/>
<action selector="zoomTouchUpInside:" destination="-1" eventType="touchUpInside" id="Gcq-hm-Nk8"/>
<action selector="zoomTouchUpOutside:" destination="-1" eventType="touchUpOutside" id="cX7-sp-3L3"/>
</connections>
</button>
<button opaque="NO" contentMode="scaleToFill" fixedFrame="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="fUK-2V-4ya" userLabel="Location" customClass="MWMButton">
<rect key="frame" x="0.0" y="172" width="56" height="56"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<state key="normal" image="btn_get_position_light">
<color key="titleShadowColor" red="0.5" green="0.5" blue="0.5" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</state>
<connections>
<action selector="locationTouchUpInside" destination="-1" eventType="touchUpInside" id="CMC-xb-Dpk"/>
</connections>
</button>
</subviews>
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
<gestureRecognizers/>
<nil key="simulatedStatusBarMetrics"/>
<nil key="simulatedTopBarMetrics"/>
<nil key="simulatedBottomBarMetrics"/>
<freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
<viewLayoutGuide key="safeArea" id="rMs-pl-xhs"/>
<connections>
<outlet property="location" destination="fUK-2V-4ya" id="lgn-MB-VVy"/>
<outlet property="zoomIn" destination="NO3-Xl-Oka" id="1sc-ei-oRj"/>
<outlet property="zoomOut" destination="hwn-8L-cFX" id="htY-bc-Ugh"/>
<outletCollection property="gestureRecognizers" destination="6qU-Ff-Ae5" appends="YES" id="jeT-Jr-P7T"/>
</connections>
<point key="canvasLocation" x="165" y="-6"/>
</view>
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
<panGestureRecognizer minimumNumberOfTouches="1" id="6qU-Ff-Ae5">
<connections>
<action selector="zoomSwipe:" destination="-1" id="jq1-Qs-vUJ"/>
</connections>
</panGestureRecognizer>
</objects>
<resources>
<image name="btn_get_position_light" width="56" height="56"/>
<image name="btn_zoom_in_light" width="56" height="56"/>
<image name="btn_zoom_out_light" width="56" height="56"/>
</resources>
</document>

View file

@ -0,0 +1,13 @@
@class MWMZoomButtonsView;
@interface MWMZoomButtons : NSObject
@property (nonatomic) BOOL hidden;
- (instancetype)init __attribute__((unavailable("init is not available")));
- (instancetype)initWithParentView:(UIView *)view;
- (void)setTopBound:(CGFloat)bound;
- (void)setBottomBound:(CGFloat)bound;
- (void)mwm_refreshUI;
@end

View file

@ -0,0 +1,122 @@
#import "MWMZoomButtons.h"
#import "MWMZoomButtonsView.h"
#import "Statistics.h"
#include "Framework.h"
#include "platform/settings.hpp"
#include "indexer/scales.hpp"
static NSString * const kMWMZoomButtonsViewNibName = @"MWMZoomButtonsView";
@interface MWMZoomButtons()
@property (nonatomic) IBOutlet MWMZoomButtonsView * zoomView;
@property (weak, nonatomic) IBOutlet UIButton * zoomInButton;
@property (weak, nonatomic) IBOutlet UIButton * zoomOutButton;
@property (nonatomic) BOOL zoomSwipeEnabled;
@property (nonatomic, readonly) BOOL isZoomEnabled;
@end
@implementation MWMZoomButtons
- (instancetype)initWithParentView:(UIView *)view
{
self = [super init];
if (self)
{
[[NSBundle mainBundle] loadNibNamed:kMWMZoomButtonsViewNibName owner:self options:nil];
[view addSubview:self.zoomView];
[self.zoomView layoutIfNeeded];
self.zoomView.topBound = 0.0;
self.zoomView.bottomBound = view.height;
self.zoomSwipeEnabled = NO;
}
return self;
}
- (void)setTopBound:(CGFloat)bound
{
self.zoomView.topBound = bound;
}
- (void)setBottomBound:(CGFloat)bound
{
self.zoomView.bottomBound = bound;
}
- (void)zoomIn
{
[Statistics logEvent:kStatEventName(kStatZoom, kStatIn)];
GetFramework().Scale(Framework::SCALE_MAG, true);
}
- (void)zoomOut
{
[Statistics logEvent:kStatEventName(kStatZoom, kStatOut)];
GetFramework().Scale(Framework::SCALE_MIN, true);
}
- (void)mwm_refreshUI
{
[self.zoomView mwm_refreshUI];
}
#pragma mark - Actions
- (IBAction)zoomTouchDown:(UIButton *)sender
{
self.zoomSwipeEnabled = YES;
}
- (IBAction)zoomTouchUpInside:(UIButton *)sender
{
self.zoomSwipeEnabled = NO;
if ([sender isEqual:self.zoomInButton])
[self zoomIn];
else
[self zoomOut];
}
- (IBAction)zoomTouchUpOutside:(UIButton *)sender
{
self.zoomSwipeEnabled = NO;
}
- (IBAction)zoomSwipe:(UIPanGestureRecognizer *)sender
{
if (!self.zoomSwipeEnabled)
return;
UIView * const superview = self.zoomView.superview;
CGFloat const translation = -[sender translationInView:superview].y / superview.bounds.size.height;
CGFloat const scaleFactor = exp(translation);
GetFramework().Scale(scaleFactor, false);
}
#pragma mark - Properties
- (BOOL)isZoomEnabled
{
bool zoomButtonsEnabled = true;
(void)settings::Get("ZoomButtonsEnabled", zoomButtonsEnabled);
return zoomButtonsEnabled;
}
- (BOOL)hidden
{
return self.isZoomEnabled ? self.zoomView.hidden : YES;
}
- (void)setHidden:(BOOL)hidden
{
if (self.isZoomEnabled)
[self.zoomView setHidden:hidden animated:YES];
else
self.zoomView.hidden = YES;
}
@end

View file

@ -0,0 +1,13 @@
#import <UIKit/UIKit.h>
@interface MWMZoomButtonsView : UIView
@property (nonatomic) CGFloat topBound;
@property (nonatomic) CGFloat bottomBound;
- (instancetype)initWithFrame:(CGRect)frame __attribute__((unavailable("initWithFrame is not available")));
- (instancetype)init __attribute__((unavailable("init is not available")));
- (void)setHidden:(BOOL)hidden animated:(BOOL)animated;
@end

View file

@ -0,0 +1,137 @@
#import "Common.h"
#import "MWMZoomButtonsView.h"
#import "MWMMapViewControlsCommon.h"
static CGFloat const kZoomViewOffsetToTopBound = 12.0;
static CGFloat const kZoomViewOffsetToBottomBound = 40.0;
static CGFloat const kZoomViewOffsetToFrameBound = 294.0;
static CGFloat const kZoomViewHideBoundPercent = 0.4;
@interface MWMZoomButtonsView()
@property (nonatomic) CGRect defaultBounds;
@end
@implementation MWMZoomButtonsView
- (void)awakeFromNib
{
self.defaultBounds = self.bounds;
self.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
}
- (void)layoutSubviews
{
self.bounds = self.defaultBounds;
[self layoutXPosition:self.hidden];
[self layoutYPosition];
[super layoutSubviews];
}
- (void)layoutXPosition:(BOOL)hidden
{
if (hidden)
self.minX = self.superview.width;
else
self.maxX = self.superview.width - kViewControlsOffsetToBounds;
}
- (void)layoutYPosition
{
CGFloat const maxY = MIN(self.superview.height - kZoomViewOffsetToFrameBound, self.bottomBound - kZoomViewOffsetToBottomBound);
self.minY = MAX(maxY - self.height, self.topBound + kZoomViewOffsetToTopBound);
}
- (void)moveAnimated
{
if (self.hidden)
return;
[UIView animateWithDuration:framesDuration(kMenuViewMoveFramesCount) animations:^{ [self layoutYPosition]; }];
}
- (void)fadeAnimatedIn:(BOOL)show
{
[UIView animateWithDuration:framesDuration(kMenuViewHideFramesCount) animations:^{ self.alpha = show ? 1.0 : 0.0; }];
}
- (void)animate
{
CGFloat const hideBound = kZoomViewHideBoundPercent * self.superview.height;
BOOL const isHidden = self.alpha == 0.0;
BOOL const willHide = (self.bottomBound < hideBound) || (self.defaultBounds.size.height > self.bottomBound - self.topBound);
if (willHide)
{
if (!isHidden)
[self fadeAnimatedIn:NO];
}
else
{
[self moveAnimated];
if (isHidden)
[self fadeAnimatedIn:YES];
}
}
#pragma mark - Properties
- (void)setHidden:(BOOL)hidden animated:(BOOL)animated
{
if (animated)
{
if (self.hidden == hidden)
return;
if (!hidden)
self.hidden = NO;
[self layoutXPosition:!hidden];
[UIView animateWithDuration:framesDuration(kMenuViewHideFramesCount) animations:^
{
[self layoutXPosition:hidden];
}
completion:^(BOOL finished)
{
if (hidden)
self.hidden = YES;
}];
}
else
{
self.hidden = hidden;
}
}
@synthesize topBound = _topBound;
- (void)setTopBound:(CGFloat)topBound
{
if (equalScreenDimensions(_topBound, topBound))
return;
_topBound = topBound;
[self animate];
}
- (CGFloat)topBound
{
return MAX(0.0, _topBound);
}
@synthesize bottomBound = _bottomBound;
- (void)setBottomBound:(CGFloat)bottomBound
{
if (equalScreenDimensions(_bottomBound, bottomBound))
return;
_bottomBound = bottomBound;
[self animate];
}
- (CGFloat)bottomBound
{
if (!self.superview)
return _bottomBound;
BOOL const isPortrait = self.superview.width < self.superview.height;
CGFloat limit = IPAD ? 320.0 : isPortrait ? 200.0 : 80.0;
return MIN(self.superview.height - limit, _bottomBound);
}
@end

View file

@ -0,0 +1,72 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="9531" systemVersion="15A284" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none">
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="9529"/>
</dependencies>
<objects>
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner" customClass="MWMZoomButtons">
<connections>
<outlet property="zoomInButton" destination="NO3-Xl-Oka" id="ePH-BR-gfW"/>
<outlet property="zoomOutButton" destination="hwn-8L-cFX" id="fYk-mf-gUY"/>
<outlet property="zoomView" destination="ek2-ZW-pCm" id="N0e-Rh-Unp"/>
</connections>
</placeholder>
<view contentMode="scaleToFill" id="ek2-ZW-pCm" customClass="MWMZoomButtonsView">
<rect key="frame" x="0.0" y="0.0" width="56" height="116"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<subviews>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" id="NO3-Xl-Oka" userLabel="ZoomIn" customClass="MWMButton">
<rect key="frame" x="0.0" y="0.0" width="56" height="56"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<state key="normal" image="btn_zoom_in_light">
<color key="titleShadowColor" white="0.5" alpha="1" colorSpace="calibratedWhite"/>
</state>
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="string" keyPath="imageName" value="btn_zoom_in"/>
</userDefinedRuntimeAttributes>
<connections>
<action selector="zoomTouchDown:" destination="-1" eventType="touchDown" id="5VF-m8-Lwc"/>
<action selector="zoomTouchUpInside:" destination="-1" eventType="touchUpInside" id="wbL-zf-fH8"/>
<action selector="zoomTouchUpOutside:" destination="-1" eventType="touchUpOutside" id="w6V-A2-cZM"/>
</connections>
</button>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" id="hwn-8L-cFX" userLabel="ZoomOut" customClass="MWMButton">
<rect key="frame" x="0.0" y="60" width="56" height="56"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<state key="normal" image="btn_zoom_out_light">
<color key="titleShadowColor" white="0.5" alpha="1" colorSpace="calibratedWhite"/>
</state>
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="string" keyPath="imageName" value="btn_zoom_out"/>
</userDefinedRuntimeAttributes>
<connections>
<action selector="zoomTouchDown:" destination="-1" eventType="touchDown" id="o4X-Kp-9ka"/>
<action selector="zoomTouchUpInside:" destination="-1" eventType="touchUpInside" id="Gcq-hm-Nk8"/>
<action selector="zoomTouchUpOutside:" destination="-1" eventType="touchUpOutside" id="cX7-sp-3L3"/>
</connections>
</button>
</subviews>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
<gestureRecognizers/>
<nil key="simulatedStatusBarMetrics"/>
<nil key="simulatedTopBarMetrics"/>
<nil key="simulatedBottomBarMetrics"/>
<freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
<connections>
<outletCollection property="gestureRecognizers" destination="6qU-Ff-Ae5" appends="YES" id="jeT-Jr-P7T"/>
</connections>
<point key="canvasLocation" x="165" y="-6"/>
</view>
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
<panGestureRecognizer minimumNumberOfTouches="1" id="6qU-Ff-Ae5">
<connections>
<action selector="zoomSwipe:" destination="-1" id="jq1-Qs-vUJ"/>
</connections>
</panGestureRecognizer>
</objects>
<resources>
<image name="btn_zoom_in_light" width="56" height="56"/>
<image name="btn_zoom_out_light" width="56" height="56"/>
</resources>
</document>