#import #import #import #import "FileContentController.h" #import "ROOTObjectController.h" #import "FileContainerElement.h" #import "SlideshowController.h" #import "TransparentToolbar.h" #import "SearchController.h" #import "ObjectShortcut.h" #import "Shortcuts.h" #import "SpotView.h" //C++ imports. #import "IOSPad.h" #import "FileUtils.h" @interface FileContentController () { NSMutableArray *objectShortcuts; UISearchBar *searchBar; UIPopoverController *searchPopover; SearchController *searchController; UIBarButtonItem *slideShowBtn; BOOL animateDirAfterLoad; BOOL animateObjAfterLoad; unsigned spotElement; } - (void) highlightDirectory : (unsigned)tag; - (void) highlightObject : (unsigned)tag; @end @implementation FileContentController @synthesize fileContainer; //____________________________________________________________________________________________________ - (void) initToolbarItems { UIToolbar *toolbar = [[TransparentToolbar alloc] initWithFrame : CGRectMake(0.f, 0.f, 250.f, 44.f)]; toolbar.barStyle = UIBarStyleBlackTranslucent; NSMutableArray *items = [[NSMutableArray alloc] initWithCapacity : 2]; searchBar = [[UISearchBar alloc] initWithFrame:CGRectMake(0.f, 0.f, 150.f, 44.f)]; searchBar.delegate = self; UIBarButtonItem *searchItem = [[UIBarButtonItem alloc] initWithCustomView : searchBar]; [items addObject : searchItem]; slideShowBtn = [[UIBarButtonItem alloc] initWithTitle : @"Slide show" style : UIBarButtonItemStyleBordered target : self action : @selector(startSlideshow)]; [items addObject : slideShowBtn]; [toolbar setItems : items animated : NO]; UIBarButtonItem *rightItem = [[UIBarButtonItem alloc] initWithCustomView : toolbar]; rightItem.style = UIBarButtonItemStylePlain; self.navigationItem.rightBarButtonItem = rightItem; } //____________________________________________________________________________________________________ - (id)initWithNibName : (NSString *)nibNameOrNil bundle : (NSBundle *)nibBundleOrNil { self = [super initWithNibName : nibNameOrNil bundle : nibBundleOrNil]; if (self) { [self view]; [self initToolbarItems]; searchController = [[SearchController alloc] initWithStyle : UITableViewStylePlain]; searchController.delegate = self; } return self; } //____________________________________________________________________________________________________ - (void)didReceiveMemoryWarning { // Releases the view if it doesn't have a superview. [super didReceiveMemoryWarning]; // Release any cached data, images, etc that aren't in use. } #pragma mark - View lifecycle //____________________________________________________________________________________________________ - (void) correctFramesForOrientation : (UIInterfaceOrientation) orientation { //TODO: all this staff with manual geometry management should be deleted, as soon as I switch to //ThumbnailView class. CGRect mainFrame; CGRect scrollFrame; if (orientation == UIInterfaceOrientationPortrait || orientation == UIInterfaceOrientationPortraitUpsideDown) { mainFrame = CGRectMake(0.f, 0.f, 768.f, 1004.f); scrollFrame = CGRectMake(0.f, 44.f, 768.f, 960.f); } else { mainFrame = CGRectMake(0.f, 0.f, 1024.f, 748.f); scrollFrame = CGRectMake(0.f, 44.f, 1024.f, 704.f); } self.view.frame = mainFrame; scrollView.frame = scrollFrame; if ([[scrollView subviews] count]) [ShorcutUtil placeShortcuts : objectShortcuts inScrollView : scrollView withSize : CGSizeMake([ObjectShortcut iconWidth], [ObjectShortcut iconHeight] + [ObjectShortcut textHeight]) andSpace : 100.f]; } //____________________________________________________________________________________________________ - (void) viewWillAppear:(BOOL)animated { //TODO: all this staff with manual geometry management should be deleted, as soon as I switch to //ThumbnailView class. //self.interfaceOrientation ? [self correctFramesForOrientation : [UIApplication sharedApplication].statusBarOrientation]; } //____________________________________________________________________________________________________ - (void) viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view from its nib. } //____________________________________________________________________________________________________ - (void) viewDidAppear:(BOOL)animated { [super viewDidAppear : animated]; if (animateDirAfterLoad) { [self highlightDirectory : spotElement]; animateDirAfterLoad = NO; } else if (animateObjAfterLoad) { [self highlightObject : spotElement]; animateObjAfterLoad = NO; } } //____________________________________________________________________________________________________ - (void) viewDidUnload { [super viewDidUnload]; // Release any retained subviews of the main view. // e.g. self.myOutlet = nil; } //____________________________________________________________________________________________________ - (BOOL) shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation { // Return YES for supported orientations return YES; } //____________________________________________________________________________________________________ - (void) willAnimateRotationToInterfaceOrientation : (UIInterfaceOrientation)interfaceOrientation duration:(NSTimeInterval)duration { //TODO: all this staff with manual geometry management should be deleted, as soon as I switch to //ThumbnailView class. [self correctFramesForOrientation : interfaceOrientation]; } //____________________________________________________________________________________________________ - (void) didRotateFromInterfaceOrientation : (UIInterfaceOrientation)fromInterfaceOrientation { //Bring back the popover after rotating. if (searchPopover) { [searchPopover presentPopoverFromRect : searchBar.bounds inView : searchBar permittedArrowDirections : UIPopoverArrowDirectionAny animated : NO]; } } //____________________________________________________________________________________________________ - (void) clearScrollview { NSArray *viewsToRemove = [scrollView subviews]; for (UIView *v in viewsToRemove) [v removeFromSuperview]; } //____________________________________________________________________________________________________ - (void) addShortcutForObjectAtIndex : (unsigned) objIndex { const CGRect rect = CGRectMake(0.f, 0.f, [ObjectShortcut iconWidth], [ObjectShortcut iconHeight]); UIGraphicsBeginImageContext(rect.size); CGContextRef ctx = UIGraphicsGetCurrentContext(); if (!ctx) { UIGraphicsEndImageContext(); return; } //Now draw into this context. CGContextTranslateCTM(ctx, 0.f, rect.size.height); CGContextScaleCTM(ctx, 1.f, -1.f); //Fill bitmap with white first. CGContextSetRGBFillColor(ctx, 1.f, 1.f, 1.f, 1.f); CGContextFillRect(ctx, rect); //Set context and paint pad's contents. ROOT::iOS::Pad *pad = fileContainer->GetPadAttached(objIndex); pad->cd(); pad->SetViewWH(rect.size.width, rect.size.height); pad->SetContext(ctx); pad->PaintThumbnail(); UIImage *thumbnailImage = UIGraphicsGetImageFromCurrentImageContext();//autoreleased UIImage. UIGraphicsEndImageContext(); ObjectShortcut *shortcut = [[ObjectShortcut alloc] initWithFrame : [ObjectShortcut defaultRect] controller : self forObjectAtIndex:objIndex withThumbnail : thumbnailImage]; shortcut.layer.shadowColor = [UIColor blackColor].CGColor; shortcut.layer.shadowOffset = CGSizeMake(20.f, 20.f); shortcut.layer.shadowOpacity = 0.3f; [scrollView addSubview : shortcut]; [objectShortcuts addObject : shortcut]; UIBezierPath *path = [UIBezierPath bezierPathWithRect : rect]; shortcut.layer.shadowPath = path.CGPath; } //____________________________________________________________________________________________________ - (void) addShortcutForFolderAtIndex : (unsigned) index { ObjectShortcut *shortcut = [[ObjectShortcut alloc] initWithFrame : [ObjectShortcut defaultRect] controller : self forFolderAtIndex : index]; [scrollView addSubview : shortcut]; [objectShortcuts addObject : shortcut]; } //____________________________________________________________________________________________________ - (void) addObjectsIntoScrollview { using namespace ROOT::iOS::Browser; [self clearScrollview]; objectShortcuts = [[NSMutableArray alloc] init]; //Add directories first. for (FileContainer::size_type i = 0; i < fileContainer->GetNumberOfDirectories(); ++i) [self addShortcutForFolderAtIndex : i]; //Now add objects. for (FileContainer::size_type i = 0; i < fileContainer->GetNumberOfObjects(); ++i) [self addShortcutForObjectAtIndex : i]; } //____________________________________________________________________________________________________ - (void) activateForFile : (ROOT::iOS::Browser::FileContainer *)container { fileContainer = container; self.navigationItem.title = [NSString stringWithFormat : @"Contents of %s", container->GetFileName()]; slideShowBtn.enabled = fileContainer->GetNumberOfObjects() > 1 ? YES : NO; //Prepare objects' thymbnails. [self addObjectsIntoScrollview]; [self correctFramesForOrientation : [UIApplication sharedApplication].statusBarOrientation]; } //____________________________________________________________________________________________________ - (void) startSlideshow { SlideshowController *slideshowController = [[SlideshowController alloc] initWithNibName : @"SlideshowController" bundle : nil fileContainer : fileContainer]; [self.navigationController pushViewController : slideshowController animated : YES]; } //____________________________________________________________________________________________________ - (void) doTest { const unsigned testIndex = 1 + rand() % (fileContainer->GetNumberOfObjects() - 1); ROOTObjectController *objectController = [[ROOTObjectController alloc] initWithNibName:@"ROOTObjectController" bundle : nil]; [objectController setNavigationForObjectWithIndex : testIndex fromContainer : fileContainer]; [self.navigationController pushViewController : objectController animated : YES]; } //____________________________________________________________________________________________________ - (void) selectObjectFromFile : (ObjectShortcut *) shortcut { if (shortcut.isDirectory) { //Create another FileContentController and push it on stack. FileContentController *contentController = [[FileContentController alloc] initWithNibName : @"FileContentController" bundle : nil]; [contentController activateForFile : fileContainer->GetDirectory(shortcut.objectIndex)]; [self.navigationController pushViewController : contentController animated : YES]; } else { ROOTObjectController *objectController = [[ROOTObjectController alloc] initWithNibName : @"ROOTObjectController" bundle : nil]; [objectController setNavigationForObjectWithIndex : shortcut.objectIndex fromContainer : fileContainer]; [self.navigationController pushViewController : objectController animated : YES]; } } #pragma mark - Search delegate. //____________________________________________________________________________________________________ - (void) searchBarTextDidBeginEditing : (UISearchBar *)aSearchBar { typedef ROOT::iOS::Browser::FileContainer::size_type size_type; if (auto nEntities = fileContainer->GetNumberOfDescriptors()) { if (!searchPopover) { UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController : searchController]; searchPopover = [[UIPopoverController alloc] initWithContentViewController : navController]; searchPopover.delegate = self; searchPopover.passthroughViews = [NSArray arrayWithObject : searchBar]; } NSMutableArray *keys = [[NSMutableArray alloc] init]; for (size_type i = 0; i < nEntities; ++i) { const auto &descriptor = fileContainer->GetElementDescriptor(i); NSString *formatString = descriptor.fIsDir ? @"%s (directory)" : @"%s"; FileContainerElement *newKey = [[FileContainerElement alloc] init]; newKey.elementName = [NSString stringWithFormat : formatString, descriptor.fName.c_str()]; newKey.elementIndex = i; [keys addObject : newKey]; } searchController.keys = keys; [searchPopover presentPopoverFromRect : [searchBar bounds] inView : searchBar permittedArrowDirections : UIPopoverArrowDirectionAny animated : YES]; } } //____________________________________________________________________________________________________ - (void) searchBarTextDidEndEditing : (UISearchBar *)aSearchBar { if (searchPopover) { [searchPopover dismissPopoverAnimated:YES]; searchPopover = nil; } [aSearchBar resignFirstResponder]; } //____________________________________________________________________________________________________ - (void) searchBar : (UISearchBar *)searchBar textDidChange : (NSString *)searchText { // When the search string changes, filter the recents list accordingly. [searchController filterResultsUsingString : searchText]; } //____________________________________________________________________________________________________ - (void) searchBarSearchButtonClicked : (UISearchBar *)aSearchBar { //NSLog(@"search clicked"); [searchPopover dismissPopoverAnimated : YES]; [searchBar resignFirstResponder]; } #pragma mark - Popover controller delegate. //____________________________________________________________________________________________________ - (void) popoverControllerDidDismissPopover : (UIPopoverController *)popoverController { //NSLog(@"popover dismiss"); [searchBar resignFirstResponder]; } #pragma mark - Search delegate. //____________________________________________________________________________________________________ - (void) searchesController : (SearchController *)controller didSelectKey : (FileContainerElement *)key { //NSLog(@"selected %@ with index %d", key.elementName, key.elementIndex); assert(key.elementIndex < fileContainer->GetNumberOfDescriptors()); [searchPopover dismissPopoverAnimated : YES]; searchPopover = nil; [searchBar resignFirstResponder]; const auto &descriptor = fileContainer->GetElementDescriptor(key.elementIndex); if (descriptor.fOwner == fileContainer) { descriptor.fIsDir ? [self highlightDirectory : descriptor.fIndex] : [self highlightObject : descriptor.fIndex]; } else { //Create another FileContentController and push it on stack. FileContentController *contentController = [[FileContentController alloc] initWithNibName : @"FileContentController" bundle : nil]; [contentController activateForFile : descriptor.fOwner]; if (descriptor.fIsDir) contentController->animateDirAfterLoad = YES; else contentController->animateObjAfterLoad = YES; contentController->spotElement = descriptor.fIndex; [self.navigationController pushViewController : contentController animated : YES]; } } #pragma mark - adjust file container to show search result //____________________________________________________________________________________________________ - (void) animateShortcut : (ObjectShortcut *) sh { CGAffineTransform originalTransform = sh.transform; CGAffineTransform newTransform = CGAffineTransformScale(originalTransform, 1.2f, 1.2f); [UIView beginAnimations : @"hide_object" context : nil]; [UIView setAnimationDuration : 1.5f]; [UIView setAnimationCurve : UIViewAnimationCurveLinear]; [UIView setAnimationTransition : UIViewAnimationTransitionNone forView : sh cache : YES]; sh.transform = newTransform; sh.spot.alpha = 0.8f; [UIView commitAnimations]; [UIView beginAnimations : @"show_object" context : nil]; [UIView setAnimationDuration : 1.f]; [UIView setAnimationCurve : UIViewAnimationCurveLinear]; [UIView setAnimationTransition : UIViewAnimationTransitionNone forView : sh cache : YES]; sh.transform = originalTransform; sh.spot.alpha = 0.f; [UIView commitAnimations]; } //____________________________________________________________________________________________________ - (void) highlightDirectory : (unsigned)tag { for (ObjectShortcut *sh in objectShortcuts) { if (sh.objectIndex == tag && sh.isDirectory) { const CGRect thumbFrame = sh.frame; const CGRect scrollBounds = scrollView.bounds; if (CGRectGetMaxY(thumbFrame) > CGRectGetMaxY(scrollBounds)) { //We have to scroll view to show object's or directory's shortcut. //Find new Y for bounds. const CGFloat newY = CGRectGetMaxY(thumbFrame) - scrollBounds.size.height; CGRect newBounds = scrollBounds; newBounds.origin.y = newY; [scrollView scrollRectToVisible : newBounds animated : YES]; } [self animateShortcut : sh]; break; } } } //____________________________________________________________________________________________________ - (void) highlightObject : (unsigned)tag { for (ObjectShortcut *sh in objectShortcuts) { if (sh.objectIndex == tag && !sh.isDirectory) { CGRect thumbFrame = sh.frame; const CGRect scrollBounds = scrollView.bounds; if (CGRectGetMaxY(thumbFrame) > CGRectGetMaxY(scrollBounds)) { //We have to scroll view to show object's or directory's shortcut. //Find new Y for bounds. const CGFloat newY = CGRectGetMaxY(thumbFrame) - scrollBounds.size.height; CGRect newBounds = scrollBounds; newBounds.origin.y = newY; [scrollView scrollRectToVisible : newBounds animated : YES]; } [self animateShortcut : sh]; break; } } } @end