123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642 |
- //
- // ReaderMainPagebar.m
- // Reader v2.8.6
- //
- // Created by Julius Oklamcak on 2011-09-01.
- // Copyright © 2011-2015 Julius Oklamcak. All rights reserved.
- //
- // Permission is hereby granted, free of charge, to any person obtaining a copy
- // of this software and associated documentation files (the "Software"), to deal
- // in the Software without restriction, including without limitation the rights to
- // use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
- // of the Software, and to permit persons to whom the Software is furnished to
- // do so, subject to the following conditions:
- //
- // The above copyright notice and this permission notice shall be included in all
- // copies or substantial portions of the Software.
- //
- // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
- // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
- // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- //
- #import "ReaderConstants.h"
- #import "ReaderMainPagebar.h"
- #import "ReaderThumbCache.h"
- #import "ReaderDocument.h"
- #import <QuartzCore/QuartzCore.h>
- @implementation ReaderMainPagebar
- {
- ReaderDocument *document;
- ReaderTrackControl *trackControl;
- NSMutableDictionary *miniThumbViews;
- ReaderPagebarThumb *pageThumbView;
- UILabel *pageNumberLabel;
- UIView *pageNumberView;
- NSTimer *enableTimer;
- NSTimer *trackTimer;
- }
- #pragma mark - Constants
- #define THUMB_SMALL_GAP 2
- #define THUMB_SMALL_WIDTH 22
- #define THUMB_SMALL_HEIGHT 28
- #define THUMB_LARGE_WIDTH 32
- #define THUMB_LARGE_HEIGHT 42
- #define PAGE_NUMBER_WIDTH 96.0f
- #define PAGE_NUMBER_HEIGHT 30.0f
- #define PAGE_NUMBER_SPACE_SMALL 16.0f
- #define PAGE_NUMBER_SPACE_LARGE 32.0f
- #define SHADOW_HEIGHT 4.0f
- #pragma mark - Properties
- @synthesize delegate;
- #pragma mark - ReaderMainPagebar class methods
- + (Class)layerClass
- {
- #if (READER_FLAT_UI == FALSE) // Option
- return [CAGradientLayer class];
- #else
- return [CALayer class];
- #endif // end of READER_FLAT_UI Option
- }
- #pragma mark - ReaderMainPagebar instance methods
- - (instancetype)initWithFrame:(CGRect)frame
- {
- return [self initWithFrame:frame document:nil];
- }
- - (void)updatePageThumbView:(NSInteger)page
- {
- NSInteger pages = [document.pageCount integerValue];
- if (pages > 1) // Only update frame if more than one page
- {
- CGFloat controlWidth = trackControl.bounds.size.width;
- CGFloat useableWidth = (controlWidth - THUMB_LARGE_WIDTH);
- CGFloat stride = (useableWidth / (pages - 1)); // Page stride
- NSInteger X = (stride * (page - 1)); CGFloat pageThumbX = X;
- CGRect pageThumbRect = pageThumbView.frame; // Current frame
- if (pageThumbX != pageThumbRect.origin.x) // Only if different
- {
- pageThumbRect.origin.x = pageThumbX; // The new X position
- pageThumbView.frame = pageThumbRect; // Update the frame
- }
- }
- if (page != pageThumbView.tag) // Only if page number changed
- {
- pageThumbView.tag = page; [pageThumbView reuse]; // Reuse the thumb view
- CGSize size = CGSizeMake(THUMB_LARGE_WIDTH, THUMB_LARGE_HEIGHT); // Maximum thumb size
- NSURL *fileURL = document.fileURL; NSString *guid = document.guid; NSString *phrase = document.password;
- ReaderThumbRequest *request = [ReaderThumbRequest newForView:pageThumbView fileURL:fileURL password:phrase guid:guid page:page size:size];
- UIImage *image = [[ReaderThumbCache sharedInstance] thumbRequest:request priority:YES]; // Request the thumb
- UIImage *thumb = ([image isKindOfClass:[UIImage class]] ? image : nil); [pageThumbView showImage:thumb];
- }
- }
- - (void)updatePageNumberText:(NSInteger)page
- {
- if (page != pageNumberLabel.tag) // Only if page number changed
- {
- NSInteger pages = [document.pageCount integerValue]; // Total pages
- NSString *format = NSLocalizedString(@"%i of %i", @"format"); // Format
- NSString *number = [[NSString alloc] initWithFormat:format, (int)page, (int)pages];
- pageNumberLabel.text = number; // Update the page number label text
- pageNumberLabel.tag = page; // Update the last page number tag
- }
- }
- - (instancetype)initWithFrame:(CGRect)frame document:(ReaderDocument *)object
- {
- assert(object != nil); // Must have a valid ReaderDocument
- if ((self = [super initWithFrame:frame]))
- {
- self.autoresizesSubviews = YES;
- self.userInteractionEnabled = YES;
- self.contentMode = UIViewContentModeRedraw;
- self.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleTopMargin;
- if ([self.layer isKindOfClass:[CAGradientLayer class]])
- {
- self.backgroundColor = [UIColor clearColor];
- CAGradientLayer *layer = (CAGradientLayer *)self.layer;
- UIColor *liteColor = [UIColor colorWithWhite:0.82f alpha:0.8f];
- UIColor *darkColor = [UIColor colorWithWhite:0.32f alpha:0.8f];
- layer.colors = [NSArray arrayWithObjects:(id)liteColor.CGColor, (id)darkColor.CGColor, nil];
- CGRect shadowRect = self.bounds; shadowRect.size.height = SHADOW_HEIGHT; shadowRect.origin.y -= shadowRect.size.height;
- ReaderPagebarShadow *shadowView = [[ReaderPagebarShadow alloc] initWithFrame:shadowRect];
- [self addSubview:shadowView]; // Add shadow to toolbar
- }
- else // Follow The Fuglyosity of Flat Fad
- {
- self.backgroundColor = [UIColor colorWithWhite:0.94f alpha:0.94f];
- CGRect lineRect = self.bounds; lineRect.size.height = 1.0f; lineRect.origin.y -= lineRect.size.height;
- UIView *lineView = [[UIView alloc] initWithFrame:lineRect];
- lineView.autoresizesSubviews = NO;
- lineView.userInteractionEnabled = NO;
- lineView.contentMode = UIViewContentModeRedraw;
- lineView.autoresizingMask = UIViewAutoresizingFlexibleWidth;
- lineView.backgroundColor = [UIColor colorWithWhite:0.64f alpha:0.94f];
- [self addSubview:lineView];
- }
- CGFloat space = (([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPad) ? PAGE_NUMBER_SPACE_LARGE : PAGE_NUMBER_SPACE_SMALL);
- CGFloat numberY = (0.0f - (PAGE_NUMBER_HEIGHT + space)); CGFloat numberX = ((self.bounds.size.width - PAGE_NUMBER_WIDTH) * 0.5f);
- CGRect numberRect = CGRectMake(numberX, numberY, PAGE_NUMBER_WIDTH, PAGE_NUMBER_HEIGHT);
- pageNumberView = [[UIView alloc] initWithFrame:numberRect]; // Page numbers view
- pageNumberView.autoresizesSubviews = NO;
- pageNumberView.userInteractionEnabled = NO;
- pageNumberView.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin;
- pageNumberView.backgroundColor = [UIColor colorWithWhite:0.0f alpha:0.4f];
- pageNumberView.layer.shadowOffset = CGSizeMake(0.0f, 0.0f);
- pageNumberView.layer.shadowColor = [UIColor colorWithWhite:0.0f alpha:0.6f].CGColor;
- pageNumberView.layer.shadowPath = [UIBezierPath bezierPathWithRect:pageNumberView.bounds].CGPath;
- pageNumberView.layer.shadowRadius = 2.0f; pageNumberView.layer.shadowOpacity = 1.0f;
- CGRect textRect = CGRectInset(pageNumberView.bounds, 4.0f, 2.0f); // Inset the text a bit
- pageNumberLabel = [[UILabel alloc] initWithFrame:textRect]; // Page numbers label
- pageNumberLabel.autoresizesSubviews = NO;
- pageNumberLabel.autoresizingMask = UIViewAutoresizingNone;
- pageNumberLabel.textAlignment = NSTextAlignmentCenter;
- pageNumberLabel.backgroundColor = [UIColor clearColor];
- pageNumberLabel.textColor = [UIColor whiteColor];
- pageNumberLabel.font = [UIFont systemFontOfSize:16.0f];
- pageNumberLabel.shadowOffset = CGSizeMake(0.0f, 1.0f);
- pageNumberLabel.shadowColor = [UIColor blackColor];
- pageNumberLabel.adjustsFontSizeToFitWidth = YES;
- pageNumberLabel.minimumScaleFactor = 0.75f;
- [pageNumberView addSubview:pageNumberLabel]; // Add label view
- [self addSubview:pageNumberView]; // Add page numbers display view
- trackControl = [[ReaderTrackControl alloc] initWithFrame:self.bounds]; // Track control view
- [trackControl addTarget:self action:@selector(trackViewTouchDown:) forControlEvents:UIControlEventTouchDown];
- [trackControl addTarget:self action:@selector(trackViewValueChanged:) forControlEvents:UIControlEventValueChanged];
- [trackControl addTarget:self action:@selector(trackViewTouchUp:) forControlEvents:UIControlEventTouchUpOutside];
- [trackControl addTarget:self action:@selector(trackViewTouchUp:) forControlEvents:UIControlEventTouchUpInside];
- [self addSubview:trackControl]; // Add the track control and thumbs view
- document = object; // Retain the document object for our use
- [self updatePageNumberText:[document.pageNumber integerValue]];
- miniThumbViews = [NSMutableDictionary new]; // Small thumbs
- }
- return self;
- }
- - (void)removeFromSuperview
- {
- [trackTimer invalidate]; [enableTimer invalidate];
- [super removeFromSuperview];
- }
- - (void)layoutSubviews
- {
- CGRect controlRect = CGRectInset(self.bounds, 4.0f, 0.0f);
- CGFloat thumbWidth = (THUMB_SMALL_WIDTH + THUMB_SMALL_GAP);
- NSInteger thumbs = (controlRect.size.width / thumbWidth);
- NSInteger pages = [document.pageCount integerValue]; // Pages
- if (thumbs > pages) thumbs = pages; // No more than total pages
- CGFloat controlWidth = ((thumbs * thumbWidth) - THUMB_SMALL_GAP);
- controlRect.size.width = controlWidth; // Update control width
- CGFloat widthDelta = (self.bounds.size.width - controlWidth);
- NSInteger X = (widthDelta * 0.5f); controlRect.origin.x = X;
- trackControl.frame = controlRect; // Update track control frame
- if (pageThumbView == nil) // Create the page thumb view when needed
- {
- CGFloat heightDelta = (controlRect.size.height - THUMB_LARGE_HEIGHT);
- NSInteger thumbY = (heightDelta * 0.5f); NSInteger thumbX = 0; // Thumb X, Y
- CGRect thumbRect = CGRectMake(thumbX, thumbY, THUMB_LARGE_WIDTH, THUMB_LARGE_HEIGHT);
- pageThumbView = [[ReaderPagebarThumb alloc] initWithFrame:thumbRect]; // Create the thumb view
- pageThumbView.layer.zPosition = 1.0f; // Z position so that it sits on top of the small thumbs
- [trackControl addSubview:pageThumbView]; // Add as the first subview of the track control
- }
- [self updatePageThumbView:[document.pageNumber integerValue]]; // Update page thumb view
- NSInteger strideThumbs = (thumbs - 1); if (strideThumbs < 1) strideThumbs = 1;
- CGFloat stride = ((CGFloat)pages / (CGFloat)strideThumbs); // Page stride
- CGFloat heightDelta = (controlRect.size.height - THUMB_SMALL_HEIGHT);
- NSInteger thumbY = (heightDelta * 0.5f); NSInteger thumbX = 0; // Initial X, Y
- CGRect thumbRect = CGRectMake(thumbX, thumbY, THUMB_SMALL_WIDTH, THUMB_SMALL_HEIGHT);
- NSMutableDictionary *thumbsToHide = [miniThumbViews mutableCopy];
- for (NSInteger thumb = 0; thumb < thumbs; thumb++) // Iterate through needed thumbs
- {
- NSInteger page = ((stride * thumb) + 1); if (page > pages) page = pages; // Page
- NSNumber *key = [NSNumber numberWithInteger:page]; // Page number key for thumb view
- ReaderPagebarThumb *smallThumbView = [miniThumbViews objectForKey:key]; // Thumb view
- if (smallThumbView == nil) // We need to create a new small thumb view for the page number
- {
- CGSize size = CGSizeMake(THUMB_SMALL_WIDTH, THUMB_SMALL_HEIGHT); // Maximum thumb size
- NSURL *fileURL = document.fileURL; NSString *guid = document.guid; NSString *phrase = document.password;
- smallThumbView = [[ReaderPagebarThumb alloc] initWithFrame:thumbRect small:YES]; // Create a small thumb view
- ReaderThumbRequest *thumbRequest = [ReaderThumbRequest newForView:smallThumbView fileURL:fileURL password:phrase guid:guid page:page size:size];
- UIImage *image = [[ReaderThumbCache sharedInstance] thumbRequest:thumbRequest priority:NO]; // Request the thumb
- if ([image isKindOfClass:[UIImage class]]) [smallThumbView showImage:image]; // Use thumb image from cache
- [trackControl addSubview:smallThumbView]; [miniThumbViews setObject:smallThumbView forKey:key];
- }
- else // Resue existing small thumb view for the page number
- {
- smallThumbView.hidden = NO; [thumbsToHide removeObjectForKey:key];
- if (CGRectEqualToRect(smallThumbView.frame, thumbRect) == false)
- {
- smallThumbView.frame = thumbRect; // Update thumb frame
- }
- }
- thumbRect.origin.x += thumbWidth; // Next thumb X position
- }
- [thumbsToHide enumerateKeysAndObjectsUsingBlock: // Hide unused thumbs
- ^(id key, id object, BOOL *stop)
- {
- ReaderPagebarThumb *thumb = object; thumb.hidden = YES;
- }
- ];
- }
- - (void)updatePagebarViews
- {
- NSInteger page = [document.pageNumber integerValue]; // #
- [self updatePageNumberText:page]; // Update page number text
- [self updatePageThumbView:page]; // Update page thumb view
- }
- - (void)updatePagebar
- {
- if (self.hidden == NO) // Only if visible
- {
- [self updatePagebarViews]; // Update views
- }
- }
- - (void)hidePagebar
- {
- if (self.hidden == NO) // Only if visible
- {
- [UIView animateWithDuration:0.25 delay:0.0
- options:UIViewAnimationOptionCurveLinear | UIViewAnimationOptionAllowUserInteraction
- animations:^(void)
- {
- self.alpha = 0.0f;
- }
- completion:^(BOOL finished)
- {
- self.hidden = YES;
- }
- ];
- }
- }
- - (void)showPagebar
- {
- if (self.hidden == YES) // Only if hidden
- {
- [self updatePagebarViews]; // Update views first
- [UIView animateWithDuration:0.25 delay:0.0
- options:UIViewAnimationOptionCurveLinear | UIViewAnimationOptionAllowUserInteraction
- animations:^(void)
- {
- self.hidden = NO;
- self.alpha = 1.0f;
- }
- completion:NULL
- ];
- }
- }
- #pragma mark - ReaderTrackControl action methods
- - (void)trackTimerFired:(NSTimer *)timer
- {
- [trackTimer invalidate]; trackTimer = nil; // Cleanup timer
- if (trackControl.tag != [document.pageNumber integerValue]) // Only if different
- {
- [delegate pagebar:self gotoPage:trackControl.tag]; // Go to document page
- }
- }
- - (void)enableTimerFired:(NSTimer *)timer
- {
- [enableTimer invalidate]; enableTimer = nil; // Cleanup timer
- trackControl.userInteractionEnabled = YES; // Enable track control interaction
- }
- - (void)restartTrackTimer
- {
- if (trackTimer != nil) { [trackTimer invalidate]; trackTimer = nil; } // Invalidate and release previous timer
- trackTimer = [NSTimer scheduledTimerWithTimeInterval:0.25 target:self selector:@selector(trackTimerFired:) userInfo:nil repeats:NO];
- }
- - (void)startEnableTimer
- {
- if (enableTimer != nil) { [enableTimer invalidate]; enableTimer = nil; } // Invalidate and release previous timer
- enableTimer = [NSTimer scheduledTimerWithTimeInterval:0.25 target:self selector:@selector(enableTimerFired:) userInfo:nil repeats:NO];
- }
- - (NSInteger)trackViewPageNumber:(ReaderTrackControl *)trackView
- {
- CGFloat controlWidth = trackView.bounds.size.width; // View width
- CGFloat stride = (controlWidth / [document.pageCount integerValue]);
- NSInteger page = (trackView.value / stride); // Integer page number
- return (page + 1); // + 1
- }
- - (void)trackViewTouchDown:(ReaderTrackControl *)trackView
- {
- NSInteger page = [self trackViewPageNumber:trackView]; // Page
- if (page != [document.pageNumber integerValue]) // Only if different
- {
- [self updatePageNumberText:page]; // Update page number text
- [self updatePageThumbView:page]; // Update page thumb view
- [self restartTrackTimer]; // Start the track timer
- }
- trackView.tag = page; // Start page tracking
- }
- - (void)trackViewValueChanged:(ReaderTrackControl *)trackView
- {
- NSInteger page = [self trackViewPageNumber:trackView]; // Page
- if (page != trackView.tag) // Only if the page number has changed
- {
- [self updatePageNumberText:page]; // Update page number text
- [self updatePageThumbView:page]; // Update page thumb view
- trackView.tag = page; // Update the page tracking tag
- [self restartTrackTimer]; // Restart the track timer
- }
- }
- - (void)trackViewTouchUp:(ReaderTrackControl *)trackView
- {
- [trackTimer invalidate]; trackTimer = nil; // Cleanup
- if (trackView.tag != [document.pageNumber integerValue]) // Only if different
- {
- trackView.userInteractionEnabled = NO; // Disable track control interaction
- [delegate pagebar:self gotoPage:trackView.tag]; // Go to document page
- [self startEnableTimer]; // Start track control enable timer
- }
- trackView.tag = 0; // Reset page tracking
- }
- @end
- #pragma mark -
- //
- // ReaderTrackControl class implementation
- //
- @implementation ReaderTrackControl
- {
- CGFloat _value;
- }
- #pragma mark - Properties
- @synthesize value = _value;
- #pragma mark - ReaderTrackControl instance methods
- - (instancetype)initWithFrame:(CGRect)frame
- {
- if ((self = [super initWithFrame:frame]))
- {
- self.autoresizesSubviews = NO;
- self.userInteractionEnabled = YES;
- self.contentMode = UIViewContentModeRedraw;
- self.autoresizingMask = UIViewAutoresizingNone;
- self.backgroundColor = [UIColor clearColor];
- self.exclusiveTouch = YES;
- }
- return self;
- }
- - (CGFloat)limitValue:(CGFloat)valueX
- {
- CGFloat minX = self.bounds.origin.x; // 0.0f;
- CGFloat maxX = (self.bounds.size.width - 1.0f);
- if (valueX < minX) valueX = minX; // Minimum X
- if (valueX > maxX) valueX = maxX; // Maximum X
- return valueX;
- }
- #pragma mark - UIControl subclass methods
- - (BOOL)beginTrackingWithTouch:(UITouch *)touch withEvent:(UIEvent *)event
- {
- CGPoint point = [touch locationInView:self]; // Touch point
- _value = [self limitValue:point.x]; // Limit control value
- return YES;
- }
- - (BOOL)continueTrackingWithTouch:(UITouch *)touch withEvent:(UIEvent *)event
- {
- if (self.touchInside == YES) // Only if inside the control
- {
- CGPoint point = [touch locationInView:touch.view]; // Touch point
- CGFloat x = [self limitValue:point.x]; // Potential new control value
- if (x != _value) // Only if the new value has changed since the last time
- {
- _value = x; [self sendActionsForControlEvents:UIControlEventValueChanged];
- }
- }
- return YES;
- }
- - (void)endTrackingWithTouch:(UITouch *)touch withEvent:(UIEvent *)event
- {
- CGPoint point = [touch locationInView:self]; // Touch point
- _value = [self limitValue:point.x]; // Limit control value
- }
- @end
- #pragma mark -
- //
- // ReaderPagebarThumb class implementation
- //
- @implementation ReaderPagebarThumb
- #pragma mark - ReaderPagebarThumb instance methods
- - (instancetype)initWithFrame:(CGRect)frame
- {
- return [self initWithFrame:frame small:NO];
- }
- - (instancetype)initWithFrame:(CGRect)frame small:(BOOL)small
- {
- if ((self = [super initWithFrame:frame])) // Superclass init
- {
- CGFloat value = (small ? 0.6f : 0.7f); // Size based alpha value
- UIColor *background = [UIColor colorWithWhite:0.8f alpha:value];
- self.backgroundColor = background; imageView.backgroundColor = background;
- imageView.layer.borderColor = [UIColor colorWithWhite:0.4f alpha:0.6f].CGColor;
- imageView.layer.borderWidth = 1.0f; // Give the thumb image view a border
- }
- return self;
- }
- @end
- #pragma mark -
- //
- // ReaderPagebarShadow class implementation
- //
- @implementation ReaderPagebarShadow
- #pragma mark - ReaderPagebarShadow class methods
- + (Class)layerClass
- {
- return [CAGradientLayer class];
- }
- #pragma mark - ReaderPagebarShadow instance methods
- - (instancetype)initWithFrame:(CGRect)frame
- {
- if ((self = [super initWithFrame:frame]))
- {
- self.autoresizesSubviews = NO;
- self.userInteractionEnabled = NO;
- self.contentMode = UIViewContentModeRedraw;
- self.autoresizingMask = UIViewAutoresizingFlexibleWidth;
- self.backgroundColor = [UIColor clearColor];
- CAGradientLayer *layer = (CAGradientLayer *)self.layer;
- UIColor *blackColor = [UIColor colorWithWhite:0.42f alpha:1.0f];
- UIColor *clearColor = [UIColor colorWithWhite:0.42f alpha:0.0f];
- layer.colors = [NSArray arrayWithObjects:(id)clearColor.CGColor, (id)blackColor.CGColor, nil];
- }
- return self;
- }
- @end
|