summaryrefslogtreecommitdiff
path: root/ios/main.m
diff options
context:
space:
mode:
Diffstat (limited to 'ios/main.m')
-rw-r--r--ios/main.m492
1 files changed, 419 insertions, 73 deletions
diff --git a/ios/main.m b/ios/main.m
index 3a6a45f3..7b977928 100644
--- a/ios/main.m
+++ b/ios/main.m
@@ -12,6 +12,8 @@
#define GAP 20
#define INDICATOR_Y -44-24
+#define SLIDER_W (width - GAP - 24)
+#define SEARCH_W (width - GAP - 170)
static dispatch_queue_t queue;
static fz_glyph_cache *glyphcache = NULL;
@@ -21,8 +23,13 @@ static float screenScale = 1;
{
NSArray *files;
NSTimer *timer;
+ struct document *_doc; // temporaries for juggling password dialog
+ NSString *_filename;
}
- (void) openDocument: (NSString*)filename;
+- (void) askForPassword: (NSString*)prompt;
+- (void) onPasswordOkay;
+- (void) onPasswordCancel;
- (void) reload;
@end
@@ -35,6 +42,16 @@ static float screenScale = 1;
- (id) initWithTarget: (id)aTarget titles: (NSMutableArray*)aTitles pages: (NSMutableArray*)aPages;
@end
+@interface MuHitView : UIView
+{
+ CGSize pageSize;
+ int hitCount;
+ CGRect hitRects[500];
+}
+- (id) initWithSearchResults: (int)n forDocument: (struct document *)doc;
+- (void) setPageSize: (CGSize)s;
+@end
+
@interface MuPageView : UIScrollView <UIScrollViewDelegate>
{
struct document *doc;
@@ -42,6 +59,8 @@ static float screenScale = 1;
UIActivityIndicatorView *loadingView;
UIImageView *imageView;
UIImageView *tileView;
+ MuHitView *hitView;
+ CGSize pageSize;
CGRect tileFrame;
float tileScale;
BOOL cancel;
@@ -53,29 +72,37 @@ static float screenScale = 1;
- (void) loadTile;
- (void) willRotate;
- (void) resetZoomAnimated: (BOOL)animated;
+- (void) showSearchResults: (int)count;
+- (void) clearSearchResults;
- (int) number;
@end
-@interface MuDocumentController : UIViewController <UIScrollViewDelegate, UIGestureRecognizerDelegate>
+@interface MuDocumentController : UIViewController <UIScrollViewDelegate, UISearchBarDelegate>
{
struct document *doc;
NSString *key;
- NSMutableSet *visiblePages;
- NSMutableSet *recycledPages;
MuOutlineController *outline;
UIScrollView *canvas;
UILabel *indicator;
UISlider *slider;
- UIBarButtonItem *wrapper; // for slider
+ UISearchBar *searchBar;
+ UIBarButtonItem *nextButton, *prevButton, *cancelButton, *searchButton, *outlineButton;
+ UIBarButtonItem *sliderWrapper;
+ int searchPage;
+ int cancelSearch;
int width; // current screen size
int height;
int current; // currently visible page
int scroll_animating; // stop view updates during scrolling animations
}
-- (id) initWithFile: (NSString*)filename;
+- (id) initWithFilename: (NSString*)nsfilename document: (struct document *)aDoc;
- (void) createPageView: (int)number;
- (void) gotoPage: (int)number animated: (BOOL)animated;
- (void) onShowOutline: (id)sender;
+- (void) onShowSearch: (id)sender;
+- (void) onCancelSearch: (id)sender;
+- (void) resetSearch;
+- (void) showSearchResults: (int)count forPage: (int)number;
- (void) onSlide: (id)sender;
- (void) onTap: (UITapGestureRecognizer*)sender;
- (void) showNavigationBar;
@@ -147,15 +174,16 @@ static void releasePixmap(void *info, const void *data, size_t size)
static UIImage *newImageWithPixmap(fz_pixmap *pix)
{
CGDataProviderRef cgdata = CGDataProviderCreateWithData(pix, pix->samples, pix->w * 4 * pix->h, releasePixmap);
+ CGColorSpaceRef cgcolor = CGColorSpaceCreateDeviceRGB();
CGImageRef cgimage = CGImageCreate(pix->w, pix->h, 8, 32, 4 * pix->w,
- CGColorSpaceCreateDeviceRGB(),
- kCGBitmapByteOrderDefault,
+ cgcolor, kCGBitmapByteOrderDefault,
cgdata, NULL, NO, kCGRenderingIntentDefault);
UIImage *image = [[UIImage alloc]
initWithCGImage: cgimage
scale: screenScale
orientation: UIImageOrientationUp];
CGDataProviderRelease(cgdata);
+ CGColorSpaceRelease(cgcolor);
CGImageRelease(cgimage);
return image;
}
@@ -170,6 +198,13 @@ static CGSize fitPageToScreen(CGSize page, CGSize screen)
return CGSizeMake(hscale, vscale);
}
+static CGSize measurePage(struct document *doc, int number)
+{
+ CGSize pageSize;
+ measure_page(doc, number, &pageSize.width, &pageSize.height);
+ return pageSize;
+}
+
static UIImage *renderPage(struct document *doc, int number, CGSize screenSize)
{
CGSize pageSize;
@@ -317,19 +352,81 @@ static UIImage *renderTile(struct document *doc, int number, CGSize screenSize,
{
int row = [indexPath row];
if (row == 0)
- [self openDocument: @"../MuPDF.app/About.pdf"];
+ [self openDocument: @"../MuPDF.app/About.xps"];
else
[self openDocument: [files objectAtIndex: row - 1]];
}
-- (void) openDocument: (NSString*)filename
+- (void) openDocument: (NSString*)nsfilename
{
- MuDocumentController *document = [[MuDocumentController alloc] initWithFile: filename];
+ char filename[PATH_MAX];
+
+ dispatch_sync(queue, ^{});
+
+ strcpy(filename, [NSHomeDirectory() UTF8String]);
+ strcat(filename, "/Documents/");
+ strcat(filename, [nsfilename UTF8String]);
+
+ printf("open document '%s'\n", filename);
+
+ _filename = [nsfilename retain];
+ _doc = open_document(filename);
+ if (!_doc) {
+ showAlert(@"Cannot open document");
+ return;
+ }
+
+ if (needs_password(_doc))
+ [self askForPassword: @"'%@' needs a password:"];
+ else
+ [self onPasswordOkay];
+}
+
+- (void) askForPassword: (NSString*)prompt
+{
+ UIAlertView *passwordAlertView = [[UIAlertView alloc]
+ initWithTitle: @"Password Protected"
+ message: [NSString stringWithFormat: prompt, [_filename lastPathComponent]]
+ delegate: self
+ cancelButtonTitle: @"Cancel"
+ otherButtonTitles: @"Done", nil];
+ [passwordAlertView setAlertViewStyle: UIAlertViewStyleSecureTextInput];
+ [passwordAlertView show];
+ [passwordAlertView release];
+}
+
+- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
+{
+ char *password = (char*) [[[alertView textFieldAtIndex: 0] text] UTF8String];
+ [alertView dismissWithClickedButtonIndex: buttonIndex animated: TRUE];
+ if (buttonIndex == 1) {
+ if (authenticate_password(_doc, password))
+ [self onPasswordOkay];
+ else
+ [self askForPassword: @"Wrong password for '%@'. Try again:"];
+ } else {
+ [self onPasswordCancel];
+ }
+}
+
+- (void) onPasswordOkay
+{
+ MuDocumentController *document = [[MuDocumentController alloc] initWithFilename: _filename document: _doc];
if (document) {
[self setTitle: @"Library"];
[[self navigationController] pushViewController: document animated: YES];
[document release];
}
+ [_filename release];
+ _doc = NULL;
+}
+
+- (void) onPasswordCancel
+{
+ [_filename release];
+ printf("close document (password cancel)\n");
+ close_document(_doc);
+ _doc = NULL;
}
@end
@@ -404,6 +501,53 @@ static UIImage *renderTile(struct document *doc, int number, CGSize screenSize,
#pragma mark -
+@implementation MuHitView
+
+- (id) initWithSearchResults: (int)n forDocument: (struct document *)doc
+{
+ self = [super initWithFrame: CGRectMake(0,0,100,100)];
+ if (self) {
+ [self setOpaque: NO];
+
+ pageSize = CGSizeMake(100,100);
+
+ for (int i = 0; i < n && i < nelem(hitRects); i++) {
+ fz_bbox bbox = search_result_bbox(doc, i); // this is thread-safe enough
+ hitRects[i].origin.x = bbox.x0;
+ hitRects[i].origin.y = bbox.y0;
+ hitRects[i].size.width = bbox.x1 - bbox.x0;
+ hitRects[i].size.height = bbox.y1 - bbox.y0;
+ }
+ hitCount = n;
+ }
+ return self;
+}
+
+- (void) setPageSize: (CGSize)s
+{
+ pageSize = s;
+ // if page takes a long time to load we may have drawn at the initial (wrong) size
+ [self setNeedsDisplay];
+}
+
+- (void) drawRect: (CGRect)r
+{
+ CGSize scale = fitPageToScreen(pageSize, self.bounds.size);
+
+ [[UIColor colorWithRed: 0.3 green: 0.3 blue: 1 alpha: 0.5] set];
+
+ for (int i = 0; i < hitCount; i++) {
+ CGRect rect = hitRects[i];
+ rect.origin.x *= scale.width;
+ rect.origin.y *= scale.height;
+ rect.size.width *= scale.width;
+ rect.size.height *= scale.height;
+ UIRectFill(rect);
+ }
+}
+
+@end
+
@implementation MuPageView
- (id) initWithFrame: (CGRect)frame document: (struct document*)aDoc page: (int)aNumber
@@ -444,6 +588,7 @@ static UIImage *renderTile(struct document *doc, int number, CGSize screenSize,
__block id block_self = self; // don't auto-retain self!
dispatch_async(dispatch_get_main_queue(), ^{ [block_self dealloc]; });
} else {
+ [hitView release];
[tileView release];
[loadingView release];
[imageView release];
@@ -456,6 +601,30 @@ static UIImage *renderTile(struct document *doc, int number, CGSize screenSize,
return number;
}
+- (void) showSearchResults: (int)count
+{
+ if (hitView) {
+ [hitView removeFromSuperview];
+ [hitView release];
+ hitView = nil;
+ }
+ hitView = [[MuHitView alloc] initWithSearchResults: count forDocument: doc];
+ if (imageView) {
+ [hitView setFrame: [imageView frame]];
+ [hitView setPageSize: pageSize];
+ }
+ [self addSubview: hitView];
+}
+
+- (void) clearSearchResults
+{
+ if (hitView) {
+ [hitView removeFromSuperview];
+ [hitView release];
+ hitView = nil;
+ }
+}
+
- (void) resetZoomAnimated: (BOOL)animated
{
// discard tile and any pending tile jobs
@@ -485,8 +654,10 @@ static UIImage *renderTile(struct document *doc, int number, CGSize screenSize,
dispatch_async(queue, ^{
if (!cancel) {
printf("render page %d\n", number);
+ CGSize size = measurePage(doc, number);
UIImage *image = renderPage(doc, number, self.bounds.size);
dispatch_async(dispatch_get_main_queue(), ^{
+ pageSize = size;
[self displayImage: image];
[image release];
});
@@ -504,10 +675,15 @@ static UIImage *renderTile(struct document *doc, int number, CGSize screenSize,
loadingView = nil;
}
+ if (hitView)
+ [hitView setPageSize: pageSize];
+
if (!imageView) {
imageView = [[UIImageView alloc] initWithImage: image];
imageView.opaque = YES;
[self addSubview: imageView];
+ if (hitView)
+ [self bringSubviewToFront: hitView];
} else {
[imageView setImage: image];
}
@@ -530,7 +706,7 @@ static UIImage *renderTile(struct document *doc, int number, CGSize screenSize,
dispatch_async(queue, ^{
dispatch_async(dispatch_get_main_queue(), ^{
CGSize scale = fitPageToScreen(imageView.image.size, self.bounds.size);
- if (fabs(scale.width - 1) > 0.1)
+ if (fabs(scale.width - 1) > 0.01)
[self loadPage];
});
});
@@ -542,6 +718,7 @@ static UIImage *renderTile(struct document *doc, int number, CGSize screenSize,
[self layoutIfNeeded];
}
+
}
- (void) willRotate
@@ -577,6 +754,9 @@ static UIImage *renderTile(struct document *doc, int number, CGSize screenSize,
loadingView.frame = frameToCenter;
else
imageView.frame = frameToCenter;
+
+ if (hitView && imageView)
+ [hitView setFrame: [imageView frame]];
}
- (UIView*) viewForZoomingInScrollView: (UIScrollView*)scrollView
@@ -586,7 +766,7 @@ static UIImage *renderTile(struct document *doc, int number, CGSize screenSize,
- (void) loadTile
{
- CGSize pageSize = self.bounds.size;
+ CGSize screenSize = self.bounds.size;
tileFrame.origin = self.contentOffset;
tileFrame.size = self.bounds.size;
@@ -616,7 +796,7 @@ static UIImage *renderTile(struct document *doc, int number, CGSize screenSize,
}
printf("render tile\n");
- UIImage *image = renderTile(doc, number, pageSize, viewFrame, scale);
+ UIImage *image = renderTile(doc, number, screenSize, viewFrame, scale);
dispatch_async(dispatch_get_main_queue(), ^{
isValid = CGRectEqualToRect(frame, tileFrame) && scale == tileScale;
@@ -632,6 +812,8 @@ static UIImage *renderTile(struct document *doc, int number, CGSize screenSize,
tileView = [[UIImageView alloc] initWithFrame: frame];
[tileView setImage: image];
[self addSubview: tileView];
+ if (hitView)
+ [self bringSubviewToFront: hitView];
} else {
printf("discard tile\n");
}
@@ -666,53 +848,40 @@ static UIImage *renderTile(struct document *doc, int number, CGSize screenSize,
[self loadTile];
}
+- (void) scrollViewDidZoom: (UIScrollView*)scrollView
+{
+ if (hitView && imageView)
+ [hitView setFrame: [imageView frame]];
+}
+
@end
#pragma mark -
@implementation MuDocumentController
-- (id) initWithFile: (NSString*)nsfilename
+- (id) initWithFilename: (NSString*)filename document: (struct document *)aDoc
{
- char filename[PATH_MAX];
-
self = [super init];
if (!self)
return nil;
- key = [nsfilename retain];
+ key = [filename retain];
+ doc = aDoc;
dispatch_sync(queue, ^{});
- strcpy(filename, [NSHomeDirectory() UTF8String]);
- strcat(filename, "/Documents/");
- strcat(filename, [nsfilename UTF8String]);
-
- printf("open document '%s'\n", filename);
-
- doc = open_document(filename);
- if (!doc) {
- showAlert(@"Cannot open document");
- [self release];
- return nil;
- }
-
- NSMutableArray *titles = [[NSMutableArray alloc] init];
- NSMutableArray *pages = [[NSMutableArray alloc] init];
fz_outline *root = load_outline(doc);
if (root) {
+ NSMutableArray *titles = [[NSMutableArray alloc] init];
+ NSMutableArray *pages = [[NSMutableArray alloc] init];
flattenOutline(titles, pages, root, 0);
+ if ([titles count])
+ outline = [[MuOutlineController alloc] initWithTarget: self titles: titles pages: pages];
+ [titles release];
+ [pages release];
fz_free_outline(root);
}
- if ([titles count]) {
- outline = [[MuOutlineController alloc] initWithTarget: self titles: titles pages: pages];
- [[self navigationItem] setRightBarButtonItem:
- [[UIBarButtonItem alloc]
- initWithBarButtonSystemItem: UIBarButtonSystemItemBookmarks
- target:self action:@selector(onShowOutline:)]];
- }
- [titles release];
- [pages release];
return self;
}
@@ -729,9 +898,6 @@ static UIImage *renderTile(struct document *doc, int number, CGSize screenSize,
[view setAutoresizingMask: UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight];
[view setAutoresizesSubviews: YES];
- visiblePages = [[NSMutableSet alloc] init];
- recycledPages = [[NSMutableSet alloc] init];
-
canvas = [[UIScrollView alloc] initWithFrame: CGRectMake(0,0,GAP,0)];
[canvas setAutoresizingMask: UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight];
[canvas setPagingEnabled: YES];
@@ -752,31 +918,56 @@ static UIImage *renderTile(struct document *doc, int number, CGSize screenSize,
[indicator setBackgroundColor: [[UIColor blackColor] colorWithAlphaComponent: 0.5]];
[indicator setTextColor: [UIColor whiteColor]];
+ [view addSubview: canvas];
+ [view addSubview: indicator];
+
slider = [[UISlider alloc] initWithFrame: CGRectZero];
[slider setMinimumValue: 0];
[slider setMaximumValue: count_pages(doc) - 1];
[slider addTarget: self action: @selector(onSlide:) forControlEvents: UIControlEventValueChanged];
- [view addSubview: canvas];
- [view addSubview: indicator];
+ sliderWrapper = [[UIBarButtonItem alloc] initWithCustomView: slider];
- wrapper = [[UIBarButtonItem alloc] initWithCustomView: slider];
- [self setToolbarItems: [NSArray arrayWithObjects: wrapper, nil]];
+ [self setToolbarItems: [NSArray arrayWithObjects: sliderWrapper, nil]];
+
+ // Set up the buttons on the navigation and search bar
+
+ if (outline) {
+ outlineButton = [[UIBarButtonItem alloc]
+ initWithBarButtonSystemItem: UIBarButtonSystemItemBookmarks
+ target:self action:@selector(onShowOutline:)];
+ }
+ cancelButton = [[UIBarButtonItem alloc]
+ initWithTitle: @"Cancel" style: UIBarButtonItemStyleBordered
+ target:self action:@selector(onCancelSearch:)];
+ searchButton = [[UIBarButtonItem alloc]
+ initWithBarButtonSystemItem: UIBarButtonSystemItemSearch
+ target:self action:@selector(onShowSearch:)];
+ prevButton = [[UIBarButtonItem alloc]
+ initWithBarButtonSystemItem: UIBarButtonSystemItemRewind
+ target:self action:@selector(onSearchPrev:)];
+ nextButton = [[UIBarButtonItem alloc]
+ initWithBarButtonSystemItem: UIBarButtonSystemItemFastForward
+ target:self action:@selector(onSearchNext:)];
+
+ searchBar = [[UISearchBar alloc] initWithFrame: CGRectMake(0,0,50,32)];
+ [searchBar setPlaceholder: @"Search"];
+ [searchBar setDelegate: self];
+ // HACK to make transparent background
+ [[searchBar.subviews objectAtIndex:0] removeFromSuperview];
+
+ [prevButton setEnabled: NO];
+ [nextButton setEnabled: NO];
+
+ [[self navigationItem] setRightBarButtonItems:
+ [NSArray arrayWithObjects: searchButton, outlineButton, nil]];
+
+ // TODO: add activityindicator to search bar
[self setView: view];
[view release];
}
-- (void) viewDidUnload
-{
- [visiblePages release]; visiblePages = nil;
- [recycledPages release]; recycledPages = nil;
- [indicator release]; indicator = nil;
- [slider release]; slider = nil;
- [wrapper release]; wrapper = nil;
- [canvas release]; canvas = nil;
-}
-
- (void) dealloc
{
if (doc) {
@@ -786,6 +977,18 @@ static UIImage *renderTile(struct document *doc, int number, CGSize screenSize,
close_document(self_doc);
});
}
+
+ [indicator release]; indicator = nil;
+ [slider release]; slider = nil;
+ [sliderWrapper release]; sliderWrapper = nil;
+ [searchBar release]; searchBar = nil;
+ [outlineButton release]; outlineButton = nil;
+ [searchButton release]; searchButton = nil;
+ [cancelButton release]; cancelButton = nil;
+ [prevButton release]; prevButton = nil;
+ [nextButton release]; nextButton = nil;
+ [canvas release]; canvas = nil;
+
[outline release];
[key release];
[super dealloc];
@@ -807,7 +1010,8 @@ static UIImage *renderTile(struct document *doc, int number, CGSize screenSize,
[canvas setContentSize: CGSizeMake(count_pages(doc) * width, height)];
[canvas setContentOffset: CGPointMake(current * width, 0)];
- [wrapper setWidth: width - GAP - 24];
+ [sliderWrapper setWidth: SLIDER_W];
+ [searchBar setFrame: CGRectMake(0,0,SEARCH_W,32)];
[[self navigationController] setToolbarHidden: NO animated: animated];
}
@@ -844,6 +1048,8 @@ static UIImage *renderTile(struct document *doc, int number, CGSize screenSize,
- (void) hideNavigationBar
{
if (![[self navigationController] isNavigationBarHidden]) {
+ [searchBar resignFirstResponder];
+
[UIView beginAnimations: @"MuNavBar" context: NULL];
[UIView setAnimationDelegate: self];
[UIView setAnimationDidStopSelector: @selector(onHideNavigationBarFinished)];
@@ -868,6 +1074,139 @@ static UIImage *renderTile(struct document *doc, int number, CGSize screenSize,
[[self navigationController] pushViewController: outline animated: YES];
}
+- (void) onShowSearch: (id)sender
+{
+ [[self navigationItem] setTitleView: searchBar];
+ [[self navigationItem] setRightBarButtonItems:
+ [NSArray arrayWithObjects: nextButton, prevButton, nil]];
+ [[self navigationItem] setLeftBarButtonItem: cancelButton];
+ [searchBar becomeFirstResponder];
+}
+
+- (void) onCancelSearch: (id)sender
+{
+ cancelSearch = YES;
+ [searchBar resignFirstResponder];
+ [[self navigationItem] setTitleView: nil];
+ [[self navigationItem] setRightBarButtonItems:
+ [NSArray arrayWithObjects: searchButton, outlineButton, nil]];
+ [[self navigationItem] setLeftBarButtonItem: nil];
+ [self resetSearch];
+}
+
+- (void) resetSearch
+{
+ searchPage = -1;
+ for (MuPageView *view in [canvas subviews])
+ [view clearSearchResults];
+}
+
+- (void) showSearchResults: (int)count forPage: (int)number
+{
+ printf("search found match on page %d\n", number);
+ searchPage = number;
+ [self gotoPage: number animated: NO];
+ for (MuPageView *view in [canvas subviews])
+ if ([view number] == number)
+ [view showSearchResults: count];
+ else
+ [view clearSearchResults];
+}
+
+- (void) searchInDirection: (int)dir
+{
+ UITextField *searchField;
+ char *needle;
+ int start;
+
+ [searchBar resignFirstResponder];
+
+ if (searchPage == current)
+ start = current + dir;
+ else
+ start = current;
+
+ needle = strdup([[searchBar text] UTF8String]);
+
+ searchField = nil;
+ for (id view in [searchBar subviews])
+ if ([view isKindOfClass: [UITextField class]])
+ searchField = view;
+
+ [prevButton setEnabled: NO];
+ [nextButton setEnabled: NO];
+ [searchField setEnabled: NO];
+
+ cancelSearch = NO;
+
+ dispatch_async(queue, ^{
+ for (int i = start; i >= 0 && i < count_pages(doc); i += dir) {
+ int n = search_page(doc, i, needle);
+ if (n) {
+ dispatch_async(dispatch_get_main_queue(), ^{
+ [prevButton setEnabled: YES];
+ [nextButton setEnabled: YES];
+ [searchField setEnabled: YES];
+ [self showSearchResults: n forPage: i];
+ free(needle);
+ });
+ return;
+ }
+ if (cancelSearch) {
+ dispatch_async(dispatch_get_main_queue(), ^{
+ [prevButton setEnabled: YES];
+ [nextButton setEnabled: YES];
+ [searchField setEnabled: YES];
+ free(needle);
+ });
+ return;
+ }
+ }
+ dispatch_async(dispatch_get_main_queue(), ^{
+ printf("no search results found\n");
+ [prevButton setEnabled: YES];
+ [nextButton setEnabled: YES];
+ [searchField setEnabled: YES];
+ UIAlertView *alert = [[UIAlertView alloc]
+ initWithTitle: @"No matches found for:"
+ message: [NSString stringWithUTF8String: needle]
+ delegate: nil
+ cancelButtonTitle: @"Close"
+ otherButtonTitles: nil];
+ [alert show];
+ [alert release];
+ free(needle);
+ });
+ });
+}
+
+- (void) onSearchPrev: (id)sender
+{
+ [self searchInDirection: -1];
+}
+
+- (void) onSearchNext: (id)sender
+{
+ [self searchInDirection: 1];
+}
+
+- (void) searchBarSearchButtonClicked: (UISearchBar*)sender
+{
+ [self onSearchNext: sender];
+}
+
+- (void) searchBar: (UISearchBar*)sender textDidChange: (NSString*)searchText
+{
+ [self resetSearch];
+ if ([[searchBar text] length] > 0) {
+ [prevButton setEnabled: YES];
+ [nextButton setEnabled: YES];
+ } else {
+ [prevButton setEnabled: NO];
+ [nextButton setEnabled: NO];
+ }
+}
+
- (void) onSlide: (id)sender
{
int number = [slider value];
@@ -918,22 +1257,26 @@ static UIImage *renderTile(struct document *doc, int number, CGSize screenSize,
[indicator setText: [NSString stringWithFormat: @" %d of %d ", current+1, count_pages(doc)]];
[slider setValue: current];
- // swap the page views in and out
+ // swap the distant page views out
- for (MuPageView *view in visiblePages) {
+ NSMutableSet *invisiblePages = [[NSMutableSet alloc] init];
+ for (MuPageView *view in [canvas subviews]) {
if ([view number] != current)
[view resetZoomAnimated: YES];
- if ([view number] < current - 2 || [view number] > current + 2) {
- [recycledPages addObject: view];
- [view removeFromSuperview];
- }
+ if ([view number] < current - 2 || [view number] > current + 2)
+ [invisiblePages addObject: view];
}
- [visiblePages minusSet: recycledPages];
- [recycledPages removeAllObjects]; // don't bother recycling them...
+ for (MuPageView *view in invisiblePages)
+ [view removeFromSuperview];
+ [invisiblePages release]; // don't bother recycling them...
[self createPageView: current];
[self createPageView: current - 1];
[self createPageView: current + 1];
+
+ // reset search results when page has flipped
+ if (current != searchPage)
+ [self resetSearch];
}
- (void) createPageView: (int)number
@@ -946,7 +1289,6 @@ static UIImage *renderTile(struct document *doc, int number, CGSize screenSize,
found = 1;
if (!found) {
MuPageView *view = [[MuPageView alloc] initWithFrame: CGRectMake(number * width, 0, width-GAP, height) document: doc page: number];
- [visiblePages addObject: view];
[canvas addSubview: view];
[view release];
}
@@ -958,6 +1300,8 @@ static UIImage *renderTile(struct document *doc, int number, CGSize screenSize,
number = 0;
if (number >= count_pages(doc))
number = count_pages(doc) - 1;
+ if (current == number)
+ return;
if (animated) {
// setContentOffset:animated: does not use the normal animation
// framework. It also doesn't play nice with the tap gesture
@@ -973,7 +1317,7 @@ static UIImage *renderTile(struct document *doc, int number, CGSize screenSize,
[UIView setAnimationDelegate: self];
[UIView setAnimationDidStopSelector: @selector(onGotoPageFinished)];
- for (MuPageView *view in visiblePages)
+ for (MuPageView *view in [canvas subviews])
[view resetZoomAnimated: NO];
[canvas setContentOffset: CGPointMake(number * width, 0)];
@@ -982,7 +1326,7 @@ static UIImage *renderTile(struct document *doc, int number, CGSize screenSize,
[UIView commitAnimations];
} else {
- for (MuPageView *view in visiblePages)
+ for (MuPageView *view in [canvas subviews])
[view resetZoomAnimated: NO];
[canvas setContentOffset: CGPointMake(number * width, 0)];
}
@@ -1008,20 +1352,22 @@ static UIImage *renderTile(struct document *doc, int number, CGSize screenSize,
width = size.width;
height = size.height;
- [wrapper setWidth: width - GAP - 24];
+ [sliderWrapper setWidth: SLIDER_W];
+ [searchBar setFrame: CGRectMake(0,0,SEARCH_W,32)];
+
[[[self navigationController] toolbar] setNeedsLayout]; // force layout!
// use max_width so we don't clamp the content offset too early during animation
[canvas setContentSize: CGSizeMake(count_pages(doc) * max_width, height)];
[canvas setContentOffset: CGPointMake(current * width, 0)];
- for (MuPageView *view in visiblePages) {
+ for (MuPageView *view in [canvas subviews]) {
if ([view number] == current) {
[view setFrame: CGRectMake([view number] * width, 0, width-GAP, height)];
[view willRotate];
}
}
- for (MuPageView *view in visiblePages) {
+ for (MuPageView *view in [canvas subviews]) {
if ([view number] != current) {
[view setFrame: CGRectMake([view number] * width, 0, width-GAP, height)];
[view willRotate];