PackagedDocument/ViewController.m
/* |
Copyright (C) 2017 Apple Inc. All Rights Reserved. |
See LICENSE.txt for this sample’s licensing information |
Abstract: |
Primary NSViewController content for our document window. |
*/ |
#import "ViewController.h" |
#import "MyTextPictDocument.h" |
#import "AttachmentView.h" |
#import "WindowController.h" |
#import "ImageView.h" |
@import QuartzCore; // for CAMediaTimingFunction |
NSString *kClipImageName = @"clip"; |
@interface ViewController () <ImageViewDelegate> |
@property (assign) NSInteger discloseDelta; |
@property (weak) IBOutlet ImageView *imageView; |
@property (weak) IBOutlet NSTextField *imageViewLabel; |
@property (weak) IBOutlet AttachmentView *attachmentView; |
@property (weak) IBOutlet NSImageView *attachedImageView; |
@property (weak) IBOutlet NSButton *disclosureButton; |
@property (strong) IBOutlet NSLayoutConstraint *attachmentViewheightConstraint; |
@end |
#pragma mark - |
@implementation ViewController |
// ------------------------------------------------------------------------------- |
// viewDidLoad |
// |
// Use this method to handle any initialization after this view controller's window has |
// been loaded from the storyboard. |
// ------------------------------------------------------------------------------- |
- (void)viewDidLoad |
{ |
[super viewDidLoad]; |
[self.textView setAllowsUndo:YES]; |
// The entire attachment view determines the drag operation, we don't want these image views to accept drags. |
[self.imageView unregisterDraggedTypes]; |
[self.attachedImageView unregisterDraggedTypes]; |
// We want to be notified when our image view changes (via cut, paste, delete). |
self.imageView.delegate = self; |
} |
// ------------------------------------------------------------------------------- |
// viewWillAppear |
// ------------------------------------------------------------------------------- |
- (void)viewWillAppear |
{ |
[super viewWillAppear]; |
MyTextPictDocument *document = [self ourDocument]; |
if (document != nil) |
{ |
// Ask our document to update our text view and image view with it's model. |
[document updateTextView:self.textView]; |
[document updateImageView:self.imageView]; |
// If we have an image, update our clip image indicator. |
if (document.image != nil) |
{ |
self.attachedImageView.image = [NSImage imageNamed:kClipImageName]; |
} |
// Hide the image label if we have an image. |
self.imageViewLabel.hidden = (document.image != nil); |
} |
// Compute the amount to disclose/hide when the disclosure control is clicked. |
_discloseDelta = |
self.attachmentView.frame.size.height - |
(self.attachmentView.frame.size.height - self.disclosureButton.frame.origin.y) - 8; |
if (!(self.disclosureButton.state == self.disclosed)) |
{ |
// Disclose the attachment view only if our disclosure button is out of sync. |
self.disclosureButton.state = self.disclosed; |
[self disclose:NO]; |
} |
// Initially key focus on the text view. |
[self.view.window makeFirstResponder:self.textView]; |
} |
// ------------------------------------------------------------------------------- |
// ourDocument |
// |
// Accessor to reference our associated NSDocument through our window controller. |
// ------------------------------------------------------------------------------- |
- (MyTextPictDocument *)ourDocument |
{ |
WindowController *windowController = (WindowController *)self.view.window.windowController; |
return windowController.document; |
} |
#pragma mark - Actions |
// ------------------------------------------------------------------------------- |
// imageDidChange:sender |
// |
// User dragged an image to the imageView. |
// ------------------------------------------------------------------------------- |
- (void)imageDidChange:(id)sender |
{ |
// Draw the paper clip image if we received a valid image. |
self.attachedImageView.image = (self.imageView.image != nil) ? [NSImage imageNamed:kClipImageName] : nil; |
MyTextPictDocument *document = [self ourDocument]; |
[document updateImageModel:self.imageView.image]; |
// Hide the image label if we have an image. |
self.imageViewLabel.hidden = (document.image != nil); |
} |
// ------------------------------------------------------------------------------- |
// disclose:animated |
// ------------------------------------------------------------------------------- |
- (void)disclose:(BOOL)animated |
{ |
CGFloat discloseAmount = self.imageView.frame.size.height; |
// Adjust the height constraint by the amount of the image view's height, |
// causing the bottom of the header to be flush with the bottom of the overall disclosure view. |
// |
if (animated) |
{ |
[NSAnimationContext runAnimationGroup:^(NSAnimationContext *context) { |
context.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]; |
self.imageView.animator.hidden = !self.disclosureButton.state; |
if (self.disclosureButton.state) |
{ |
self.attachmentViewheightConstraint.animator.constant += discloseAmount; |
} |
else |
{ |
self.attachmentViewheightConstraint.animator.constant -= discloseAmount; |
} |
} completionHandler:^{ |
}]; |
} |
else |
{ |
self.imageView.hidden = !self.disclosureButton.state; |
if (self.disclosureButton.state) |
{ |
self.attachmentViewheightConstraint.constant += discloseAmount; |
} |
else |
{ |
self.attachmentViewheightConstraint.constant -= discloseAmount; |
} |
} |
// Call our delegate (MyTextPictDocument) notifying the attachment view disclosure state changed, |
// so we can save this state as part of the document data. |
// |
[self.delegate viewController:self didDiscloseImage:self.disclosureButton.state]; |
} |
// ------------------------------------------------------------------------------- |
// discloseAction:sender |
// |
// User clicked the disclosure control to expand/shrink the attachment view. |
// ------------------------------------------------------------------------------- |
- (IBAction)discloseAction:(id)sender |
{ |
[self disclose:YES]; |
} |
#pragma mark - NSTextDelegate |
// ------------------------------------------------------------------------------- |
// textDidChange:aNotification |
// |
// The text view content had changed, update our data model. |
// ------------------------------------------------------------------------------- |
- (void)textDidChange:(NSNotification *)aNotification |
{ |
MyTextPictDocument *document = [self ourDocument]; |
NSString *str = self.textView.textStorage.string; |
[document updateTextModel:str]; |
} |
// ------------------------------------------------------------------------------- |
// updateImage:image |
// |
// Our AttachmentView wants to set our image attachment update our data model. |
// ------------------------------------------------------------------------------- |
- (void)updateImage:(NSImage *)image |
{ |
self.imageView.image = image; |
self.imageViewLabel.hidden = YES; |
[self imageDidChange:self]; |
} |
#pragma mark - ImageViewDelegate |
// ------------------------------------------------------------------------------- |
// imageView:didChangeImage |
// |
// Called by our NSImageView subclass to inform us the image has changed (via cut, copy, or delete). |
// ------------------------------------------------------------------------------- |
- (void)imageView:(ImageView *)imageView didChangeImage:(NSImage *)image |
{ |
[self updateImage:image]; |
} |
#pragma mark - Version browser support |
// ------------------------------------------------------------------------------- |
// windowWillEnterVersionBrowser |
// |
// Use this method to customize this window for the versions browser. |
// ------------------------------------------------------------------------------- |
- (void)windowWillEnterVersionBrowser:(NSNotification *)notification |
{ } |
// ------------------------------------------------------------------------------- |
// windowDidExitVersionBrowser |
// |
// Use this method to undo the customization of this window (done in windowWillEnterVersionBrowser). |
// ------------------------------------------------------------------------------- |
- (void)windowDidExitVersionBrowser:(NSNotification *)notification |
{ } |
// ------------------------------------------------------------------------------- |
// willResizeForVersionBrowserWithMaxPreferredSize:maxPreferredFrameSize:maxAllowedFrameSize |
// |
// Help determine the optimal size for the version browser. |
// Windows entering the version browser will be resized to the size returned by this method. |
// ------------------------------------------------------------------------------- |
- (NSSize)window:(NSWindow *)window willResizeForVersionBrowserWithMaxPreferredSize:(NSSize)maxPreferredFrameSize maxAllowedSize:(NSSize)maxAllowedFrameSize |
{ |
NSSize contentSize = self.textView.enclosingScrollView.documentView.bounds.size; |
contentSize = [self.textView.enclosingScrollView.documentView convertSize:contentSize toView:self.textView.enclosingScrollView]; |
Class horizScrollerClass = [self.textView.enclosingScrollView.horizontalScroller class]; |
Class vertScrollerClass = [self.textView.enclosingScrollView.verticalScroller class]; |
NSSize windowContentSize = [NSScrollView frameSizeForContentSize:contentSize |
horizontalScrollerClass:horizScrollerClass |
verticalScrollerClass:vertScrollerClass |
borderType:self.textView.enclosingScrollView.borderType |
controlSize:NSControlSizeRegular |
scrollerStyle:NSScrollerStyleLegacy]; |
NSRect frameRect = [window frameRectForContentRect:(NSRect){ NSZeroPoint, windowContentSize }]; |
return frameRect.size; |
} |
@end |
Copyright © 2017 Apple Inc. All Rights Reserved. Terms of Use | Privacy Policy | Updated: 2017-03-09