Permalink
Browse files

Merge pull request #11 from github/AppKitBridging

Basic bridging into AppKit with TUIViewNSViewContainer
  • Loading branch information...
2 parents 0a61d4b + 6c107f3 commit f068dff8303dd09da2ab20a8f9a2ec21aef72fd5 @joshaber joshaber committed Jul 19, 2012
Showing with 2,557 additions and 186 deletions.
  1. +1 −0 ExampleProject/ConcordeExample/ExampleTableViewCell.h
  2. +16 −0 ExampleProject/ConcordeExample/ExampleTableViewCell.m
  3. +15 −1 LICENSE.txt
  4. +180 −20 TwUI.xcodeproj/project.pbxproj
  5. +39 −0 lib/Support/CALayer+TUIExtensions.h
  6. +55 −0 lib/Support/CALayer+TUIExtensions.m
  7. +22 −0 lib/Support/CATransaction+TUIExtensions.h
  8. +22 −0 lib/Support/CATransaction+TUIExtensions.m
  9. +15 −0 lib/Support/NSTextView+TUIExtensions.h
  10. +43 −0 lib/Support/NSTextView+TUIExtensions.m
  11. +23 −0 lib/Support/TUIAnimationManager.h
  12. +114 −0 lib/Support/TUIAnimationManager.m
  13. +36 −0 lib/Support/TUICAAction.h
  14. +261 −0 lib/Support/TUICAAction.m
  15. +19 −0 lib/UIKit/NSClipView+TUIExtensions.h
  16. +46 −0 lib/UIKit/NSClipView+TUIExtensions.m
  17. +23 −0 lib/UIKit/NSScrollView+TUIExtensions.h
  18. +34 −0 lib/UIKit/NSScrollView+TUIExtensions.m
  19. +29 −0 lib/UIKit/NSView+TUIExtensions.h
  20. +127 −0 lib/UIKit/NSView+TUIExtensions.m
  21. +50 −0 lib/UIKit/TUIBridgedScrollView.h
  22. +153 −0 lib/UIKit/TUIBridgedView.h
  23. +33 −0 lib/UIKit/TUIHostView.h
  24. +30 −21 lib/UIKit/TUIKit.h
  25. +24 −0 lib/UIKit/TUINSHostView.h
  26. +69 −0 lib/UIKit/TUINSHostView.m
  27. +1 −1 lib/UIKit/TUINSView+Accessibility.m
  28. +4 −4 lib/UIKit/TUINSView+Hyperfocus.m
  29. +37 −0 lib/UIKit/TUINSView+Private.h
  30. +2 −2 lib/UIKit/TUINSView.h
  31. +331 −30 lib/UIKit/TUINSView.m
  32. +19 −0 lib/UIKit/TUIScrollView+TUIBridgedScrollView.h
  33. +34 −0 lib/UIKit/TUIScrollView+TUIBridgedScrollView.m
  34. +18 −10 lib/UIKit/TUIView+Animation.m
  35. +1 −3 lib/UIKit/TUIView+Private.h
  36. +0 −71 lib/UIKit/TUIView+Private.m
  37. +20 −0 lib/UIKit/TUIView+TUIBridgedView.h
  38. +176 −0 lib/UIKit/TUIView+TUIBridgedView.m
  39. +7 −0 lib/UIKit/TUIView.h
  40. +80 −1 lib/UIKit/TUIView.m
  41. +58 −0 lib/UIKit/TUIViewNSViewContainer+Private.h
  42. +41 −11 lib/UIKit/TUIViewNSViewContainer.h
  43. +249 −11 lib/UIKit/TUIViewNSViewContainer.m
View
1 ExampleProject/ConcordeExample/ExampleTableViewCell.h
@@ -22,5 +22,6 @@
}
@property (nonatomic, copy) NSAttributedString *attributedString;
+@property (nonatomic, strong) TUIView *textFieldContainer;
@end
View
16 ExampleProject/ConcordeExample/ExampleTableViewCell.m
@@ -34,10 +34,26 @@ - (id)initWithStyle:(TUITableViewCellStyle)style reuseIdentifier:(NSString *)reu
set before it can be drawn, we do that in drawRect: below.
*/
self.textRenderers = [NSArray arrayWithObjects:textRenderer, nil];
+
+ NSTextField *textField = [[NSTextField alloc] initWithFrame:NSMakeRect(20, 180, 91, 22)];
+ [textField.cell setUsesSingleLineMode:YES];
+ [textField.cell setScrollable:YES];
+
+ self.textFieldContainer = [[TUIViewNSViewContainer alloc] initWithNSView:textField];
+ self.textFieldContainer.backgroundColor = [TUIColor blueColor];
+ [self addSubview:self.textFieldContainer];
}
return self;
}
+- (void)layoutSubviews {
+ [super layoutSubviews];
+
+ CGSize textFieldSize = self.textFieldContainer.bounds.size;
+ CGFloat textFieldLeft = CGRectGetWidth(self.bounds) - textFieldSize.width - 16;
+
+ self.textFieldContainer.frame = CGRectMake(textFieldLeft, 14, textFieldSize.width, textFieldSize.height);
+}
- (NSAttributedString *)attributedString
{
View
16 LICENSE.txt
@@ -10,4 +10,18 @@ Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
-limitations under the License.
+limitations under the License.
+
+-----------------
+
+Code from the Velvet framework is used in TwUI.
+Velvet is copyright (c) 2012, Bitswift, Inc.
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+ * Neither the name of the Bitswift, Inc. nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
View
200 TwUI.xcodeproj/project.pbxproj
@@ -61,7 +61,6 @@
5EE983E413BE7834005F430D /* TUIView+Event.m in Sources */ = {isa = PBXBuildFile; fileRef = CBB74C8413BE6E1900C85CB5 /* TUIView+Event.m */; };
5EE983E513BE7834005F430D /* TUIView+NSTextInputClient.m in Sources */ = {isa = PBXBuildFile; fileRef = CBB74C8613BE6E1900C85CB5 /* TUIView+NSTextInputClient.m */; };
5EE983E613BE7834005F430D /* TUIView+PasteboardDragging.m in Sources */ = {isa = PBXBuildFile; fileRef = CBB74C8813BE6E1900C85CB5 /* TUIView+PasteboardDragging.m */; };
- 5EE983E713BE7834005F430D /* TUIView+Private.m in Sources */ = {isa = PBXBuildFile; fileRef = CBB74C8A13BE6E1900C85CB5 /* TUIView+Private.m */; };
5EE983E813BE7834005F430D /* TUIView.m in Sources */ = {isa = PBXBuildFile; fileRef = CBB74C8C13BE6E1900C85CB5 /* TUIView.m */; };
5EE983E913BE7834005F430D /* TUIViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = CBB74C8E13BE6E1900C85CB5 /* TUIViewController.m */; };
5EE983EA13BE7834005F430D /* TUIViewNSViewContainer.m in Sources */ = {isa = PBXBuildFile; fileRef = CBB74C9013BE6E1900C85CB5 /* TUIViewNSViewContainer.m */; };
@@ -180,7 +179,6 @@
CB5E326213BE70CA004B7899 /* TUIView+Event.m in Sources */ = {isa = PBXBuildFile; fileRef = CBB74C8413BE6E1900C85CB5 /* TUIView+Event.m */; };
CB5E326413BE70CA004B7899 /* TUIView+NSTextInputClient.m in Sources */ = {isa = PBXBuildFile; fileRef = CBB74C8613BE6E1900C85CB5 /* TUIView+NSTextInputClient.m */; };
CB5E326613BE70CA004B7899 /* TUIView+PasteboardDragging.m in Sources */ = {isa = PBXBuildFile; fileRef = CBB74C8813BE6E1900C85CB5 /* TUIView+PasteboardDragging.m */; };
- CB5E326813BE70CA004B7899 /* TUIView+Private.m in Sources */ = {isa = PBXBuildFile; fileRef = CBB74C8A13BE6E1900C85CB5 /* TUIView+Private.m */; };
CB5E326A13BE70CA004B7899 /* TUIView.m in Sources */ = {isa = PBXBuildFile; fileRef = CBB74C8C13BE6E1900C85CB5 /* TUIView.m */; };
CB5E326C13BE70CA004B7899 /* TUIViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = CBB74C8E13BE6E1900C85CB5 /* TUIViewController.m */; };
CB5E326E13BE70CA004B7899 /* TUIViewNSViewContainer.m in Sources */ = {isa = PBXBuildFile; fileRef = CBB74C9013BE6E1900C85CB5 /* TUIViewNSViewContainer.m */; };
@@ -268,13 +266,69 @@
CBB74CDE13BE6E1900C85CB5 /* TUIView+PasteboardDragging.h in Headers */ = {isa = PBXBuildFile; fileRef = CBB74C8713BE6E1900C85CB5 /* TUIView+PasteboardDragging.h */; settings = {ATTRIBUTES = (Public, ); }; };
CBB74CDF13BE6E1900C85CB5 /* TUIView+PasteboardDragging.m in Sources */ = {isa = PBXBuildFile; fileRef = CBB74C8813BE6E1900C85CB5 /* TUIView+PasteboardDragging.m */; };
CBB74CE013BE6E1900C85CB5 /* TUIView+Private.h in Headers */ = {isa = PBXBuildFile; fileRef = CBB74C8913BE6E1900C85CB5 /* TUIView+Private.h */; settings = {ATTRIBUTES = (Public, ); }; };
- CBB74CE113BE6E1900C85CB5 /* TUIView+Private.m in Sources */ = {isa = PBXBuildFile; fileRef = CBB74C8A13BE6E1900C85CB5 /* TUIView+Private.m */; };
CBB74CE213BE6E1900C85CB5 /* TUIView.h in Headers */ = {isa = PBXBuildFile; fileRef = CBB74C8B13BE6E1900C85CB5 /* TUIView.h */; settings = {ATTRIBUTES = (Public, ); }; };
CBB74CE313BE6E1900C85CB5 /* TUIView.m in Sources */ = {isa = PBXBuildFile; fileRef = CBB74C8C13BE6E1900C85CB5 /* TUIView.m */; };
CBB74CE413BE6E1900C85CB5 /* TUIViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = CBB74C8D13BE6E1900C85CB5 /* TUIViewController.h */; settings = {ATTRIBUTES = (Public, ); }; };
CBB74CE513BE6E1900C85CB5 /* TUIViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = CBB74C8E13BE6E1900C85CB5 /* TUIViewController.m */; };
CBB74CE613BE6E1900C85CB5 /* TUIViewNSViewContainer.h in Headers */ = {isa = PBXBuildFile; fileRef = CBB74C8F13BE6E1900C85CB5 /* TUIViewNSViewContainer.h */; settings = {ATTRIBUTES = (Public, ); }; };
CBB74CE713BE6E1900C85CB5 /* TUIViewNSViewContainer.m in Sources */ = {isa = PBXBuildFile; fileRef = CBB74C9013BE6E1900C85CB5 /* TUIViewNSViewContainer.m */; };
+ D040610D15B6A77500F753ED /* TUIAnimationManager.m in Sources */ = {isa = PBXBuildFile; fileRef = D040610915B6A77500F753ED /* TUIAnimationManager.m */; };
+ D040610E15B6A77500F753ED /* TUIAnimationManager.m in Sources */ = {isa = PBXBuildFile; fileRef = D040610915B6A77500F753ED /* TUIAnimationManager.m */; };
+ D040610F15B6A77500F753ED /* TUIAnimationManager.m in Sources */ = {isa = PBXBuildFile; fileRef = D040610915B6A77500F753ED /* TUIAnimationManager.m */; };
+ D040611615B6A7CD00F753ED /* NSTextView+TUIExtensions.m in Sources */ = {isa = PBXBuildFile; fileRef = D040611215B6A7CC00F753ED /* NSTextView+TUIExtensions.m */; };
+ D040611715B6A7CD00F753ED /* NSTextView+TUIExtensions.m in Sources */ = {isa = PBXBuildFile; fileRef = D040611215B6A7CC00F753ED /* NSTextView+TUIExtensions.m */; };
+ D040611815B6A7CD00F753ED /* NSTextView+TUIExtensions.m in Sources */ = {isa = PBXBuildFile; fileRef = D040611215B6A7CC00F753ED /* NSTextView+TUIExtensions.m */; };
+ D0C764EB15B611C200E7AC2C /* TUIBridgedView.h in Headers */ = {isa = PBXBuildFile; fileRef = D0C764EA15B611C200E7AC2C /* TUIBridgedView.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ D0C764EC15B611C200E7AC2C /* TUIBridgedView.h in Headers */ = {isa = PBXBuildFile; fileRef = D0C764EA15B611C200E7AC2C /* TUIBridgedView.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ D0C764ED15B611C200E7AC2C /* TUIBridgedView.h in Headers */ = {isa = PBXBuildFile; fileRef = D0C764EA15B611C200E7AC2C /* TUIBridgedView.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ D0C7650515B6156A00E7AC2C /* TUIHostView.h in Headers */ = {isa = PBXBuildFile; fileRef = D0C7650415B6156A00E7AC2C /* TUIHostView.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ D0C7650615B6156A00E7AC2C /* TUIHostView.h in Headers */ = {isa = PBXBuildFile; fileRef = D0C7650415B6156A00E7AC2C /* TUIHostView.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ D0C7650715B6156A00E7AC2C /* TUIHostView.h in Headers */ = {isa = PBXBuildFile; fileRef = D0C7650415B6156A00E7AC2C /* TUIHostView.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ D0C7651115B6189D00E7AC2C /* TUINSHostView.m in Sources */ = {isa = PBXBuildFile; fileRef = D0C7650D15B6189D00E7AC2C /* TUINSHostView.m */; };
+ D0C7651215B6189D00E7AC2C /* TUINSHostView.m in Sources */ = {isa = PBXBuildFile; fileRef = D0C7650D15B6189D00E7AC2C /* TUINSHostView.m */; };
+ D0C7651315B6189D00E7AC2C /* TUINSHostView.m in Sources */ = {isa = PBXBuildFile; fileRef = D0C7650D15B6189D00E7AC2C /* TUINSHostView.m */; };
+ D0C7651615B61E5A00E7AC2C /* TUIBridgedScrollView.h in Headers */ = {isa = PBXBuildFile; fileRef = D0C7651515B61E5900E7AC2C /* TUIBridgedScrollView.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ D0C7651715B61E5A00E7AC2C /* TUIBridgedScrollView.h in Headers */ = {isa = PBXBuildFile; fileRef = D0C7651515B61E5900E7AC2C /* TUIBridgedScrollView.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ D0C7651815B61E5A00E7AC2C /* TUIBridgedScrollView.h in Headers */ = {isa = PBXBuildFile; fileRef = D0C7651515B61E5900E7AC2C /* TUIBridgedScrollView.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ D0C7652715B6232100E7AC2C /* CALayer+TUIExtensions.m in Sources */ = {isa = PBXBuildFile; fileRef = D0C7652115B6232100E7AC2C /* CALayer+TUIExtensions.m */; };
+ D0C7652815B6232100E7AC2C /* CALayer+TUIExtensions.m in Sources */ = {isa = PBXBuildFile; fileRef = D0C7652115B6232100E7AC2C /* CALayer+TUIExtensions.m */; };
+ D0C7652915B6232100E7AC2C /* CALayer+TUIExtensions.m in Sources */ = {isa = PBXBuildFile; fileRef = D0C7652115B6232100E7AC2C /* CALayer+TUIExtensions.m */; };
+ D0C7652D15B6232100E7AC2C /* CATransaction+TUIExtensions.m in Sources */ = {isa = PBXBuildFile; fileRef = D0C7652315B6232100E7AC2C /* CATransaction+TUIExtensions.m */; };
+ D0C7652E15B6232100E7AC2C /* CATransaction+TUIExtensions.m in Sources */ = {isa = PBXBuildFile; fileRef = D0C7652315B6232100E7AC2C /* CATransaction+TUIExtensions.m */; };
+ D0C7652F15B6232100E7AC2C /* CATransaction+TUIExtensions.m in Sources */ = {isa = PBXBuildFile; fileRef = D0C7652315B6232100E7AC2C /* CATransaction+TUIExtensions.m */; };
+ D0C7653315B624D900E7AC2C /* NSView+TUIExtensions.h in Headers */ = {isa = PBXBuildFile; fileRef = D0C7653115B624D800E7AC2C /* NSView+TUIExtensions.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ D0C7653415B624D900E7AC2C /* NSView+TUIExtensions.h in Headers */ = {isa = PBXBuildFile; fileRef = D0C7653115B624D800E7AC2C /* NSView+TUIExtensions.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ D0C7653515B624D900E7AC2C /* NSView+TUIExtensions.h in Headers */ = {isa = PBXBuildFile; fileRef = D0C7653115B624D800E7AC2C /* NSView+TUIExtensions.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ D0C7653615B624D900E7AC2C /* NSView+TUIExtensions.m in Sources */ = {isa = PBXBuildFile; fileRef = D0C7653215B624D800E7AC2C /* NSView+TUIExtensions.m */; };
+ D0C7653715B624D900E7AC2C /* NSView+TUIExtensions.m in Sources */ = {isa = PBXBuildFile; fileRef = D0C7653215B624D800E7AC2C /* NSView+TUIExtensions.m */; };
+ D0C7653815B624D900E7AC2C /* NSView+TUIExtensions.m in Sources */ = {isa = PBXBuildFile; fileRef = D0C7653215B624D800E7AC2C /* NSView+TUIExtensions.m */; };
+ D0C7654615B626E200E7AC2C /* TUIView+TUIBridgedView.h in Headers */ = {isa = PBXBuildFile; fileRef = D0C7653E15B626E200E7AC2C /* TUIView+TUIBridgedView.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ D0C7654715B626E200E7AC2C /* TUIView+TUIBridgedView.h in Headers */ = {isa = PBXBuildFile; fileRef = D0C7653E15B626E200E7AC2C /* TUIView+TUIBridgedView.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ D0C7654815B626E200E7AC2C /* TUIView+TUIBridgedView.h in Headers */ = {isa = PBXBuildFile; fileRef = D0C7653E15B626E200E7AC2C /* TUIView+TUIBridgedView.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ D0C7654915B626E200E7AC2C /* TUIView+TUIBridgedView.m in Sources */ = {isa = PBXBuildFile; fileRef = D0C7653F15B626E200E7AC2C /* TUIView+TUIBridgedView.m */; };
+ D0C7654A15B626E200E7AC2C /* TUIView+TUIBridgedView.m in Sources */ = {isa = PBXBuildFile; fileRef = D0C7653F15B626E200E7AC2C /* TUIView+TUIBridgedView.m */; };
+ D0C7654B15B626E200E7AC2C /* TUIView+TUIBridgedView.m in Sources */ = {isa = PBXBuildFile; fileRef = D0C7653F15B626E200E7AC2C /* TUIView+TUIBridgedView.m */; };
+ D0C7655215B6294400E7AC2C /* TUIScrollView+TUIBridgedScrollView.h in Headers */ = {isa = PBXBuildFile; fileRef = D0C7655015B6294400E7AC2C /* TUIScrollView+TUIBridgedScrollView.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ D0C7655315B6294400E7AC2C /* TUIScrollView+TUIBridgedScrollView.h in Headers */ = {isa = PBXBuildFile; fileRef = D0C7655015B6294400E7AC2C /* TUIScrollView+TUIBridgedScrollView.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ D0C7655415B6294400E7AC2C /* TUIScrollView+TUIBridgedScrollView.h in Headers */ = {isa = PBXBuildFile; fileRef = D0C7655015B6294400E7AC2C /* TUIScrollView+TUIBridgedScrollView.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ D0C7655515B6294400E7AC2C /* TUIScrollView+TUIBridgedScrollView.m in Sources */ = {isa = PBXBuildFile; fileRef = D0C7655115B6294400E7AC2C /* TUIScrollView+TUIBridgedScrollView.m */; };
+ D0C7655615B6294400E7AC2C /* TUIScrollView+TUIBridgedScrollView.m in Sources */ = {isa = PBXBuildFile; fileRef = D0C7655115B6294400E7AC2C /* TUIScrollView+TUIBridgedScrollView.m */; };
+ D0C7655715B6294400E7AC2C /* TUIScrollView+TUIBridgedScrollView.m in Sources */ = {isa = PBXBuildFile; fileRef = D0C7655115B6294400E7AC2C /* TUIScrollView+TUIBridgedScrollView.m */; };
+ D0C7655D15B6297300E7AC2C /* NSClipView+TUIExtensions.h in Headers */ = {isa = PBXBuildFile; fileRef = D0C7655915B6297200E7AC2C /* NSClipView+TUIExtensions.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ D0C7655E15B6297300E7AC2C /* NSClipView+TUIExtensions.h in Headers */ = {isa = PBXBuildFile; fileRef = D0C7655915B6297200E7AC2C /* NSClipView+TUIExtensions.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ D0C7655F15B6297300E7AC2C /* NSClipView+TUIExtensions.h in Headers */ = {isa = PBXBuildFile; fileRef = D0C7655915B6297200E7AC2C /* NSClipView+TUIExtensions.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ D0C7656015B6297300E7AC2C /* NSClipView+TUIExtensions.m in Sources */ = {isa = PBXBuildFile; fileRef = D0C7655A15B6297200E7AC2C /* NSClipView+TUIExtensions.m */; };
+ D0C7656115B6297300E7AC2C /* NSClipView+TUIExtensions.m in Sources */ = {isa = PBXBuildFile; fileRef = D0C7655A15B6297200E7AC2C /* NSClipView+TUIExtensions.m */; };
+ D0C7656215B6297300E7AC2C /* NSClipView+TUIExtensions.m in Sources */ = {isa = PBXBuildFile; fileRef = D0C7655A15B6297200E7AC2C /* NSClipView+TUIExtensions.m */; };
+ D0C7656315B6297300E7AC2C /* NSScrollView+TUIExtensions.h in Headers */ = {isa = PBXBuildFile; fileRef = D0C7655B15B6297300E7AC2C /* NSScrollView+TUIExtensions.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ D0C7656415B6297300E7AC2C /* NSScrollView+TUIExtensions.h in Headers */ = {isa = PBXBuildFile; fileRef = D0C7655B15B6297300E7AC2C /* NSScrollView+TUIExtensions.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ D0C7656515B6297300E7AC2C /* NSScrollView+TUIExtensions.h in Headers */ = {isa = PBXBuildFile; fileRef = D0C7655B15B6297300E7AC2C /* NSScrollView+TUIExtensions.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ D0C7656615B6297300E7AC2C /* NSScrollView+TUIExtensions.m in Sources */ = {isa = PBXBuildFile; fileRef = D0C7655C15B6297300E7AC2C /* NSScrollView+TUIExtensions.m */; };
+ D0C7656715B6297300E7AC2C /* NSScrollView+TUIExtensions.m in Sources */ = {isa = PBXBuildFile; fileRef = D0C7655C15B6297300E7AC2C /* NSScrollView+TUIExtensions.m */; };
+ D0C7656815B6297300E7AC2C /* NSScrollView+TUIExtensions.m in Sources */ = {isa = PBXBuildFile; fileRef = D0C7655C15B6297300E7AC2C /* NSScrollView+TUIExtensions.m */; };
+ D0C7657415B6341800E7AC2C /* TUICAAction.m in Sources */ = {isa = PBXBuildFile; fileRef = D0C7657015B6341800E7AC2C /* TUICAAction.m */; };
+ D0C7657515B6341800E7AC2C /* TUICAAction.m in Sources */ = {isa = PBXBuildFile; fileRef = D0C7657015B6341800E7AC2C /* TUICAAction.m */; };
+ D0C7657615B6341800E7AC2C /* TUICAAction.m in Sources */ = {isa = PBXBuildFile; fileRef = D0C7657015B6341800E7AC2C /* TUICAAction.m */; };
D039723F15B7D7CB0092CD26 /* TUILayoutConstraint.m in Sources */ = {isa = PBXBuildFile; fileRef = 48A10E7E15B7769A007F9EE3 /* TUILayoutConstraint.m */; };
D039724115B7D7CC0092CD26 /* TUILayoutConstraint.m in Sources */ = {isa = PBXBuildFile; fileRef = 48A10E7E15B7769A007F9EE3 /* TUILayoutConstraint.m */; };
D039724215B7D7CE0092CD26 /* TUILayoutManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 48A10E8015B7769A007F9EE3 /* TUILayoutManager.m */; };
@@ -430,13 +484,39 @@
CBB74C8713BE6E1900C85CB5 /* TUIView+PasteboardDragging.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "TUIView+PasteboardDragging.h"; sourceTree = "<group>"; };
CBB74C8813BE6E1900C85CB5 /* TUIView+PasteboardDragging.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "TUIView+PasteboardDragging.m"; sourceTree = "<group>"; };
CBB74C8913BE6E1900C85CB5 /* TUIView+Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "TUIView+Private.h"; sourceTree = "<group>"; };
- CBB74C8A13BE6E1900C85CB5 /* TUIView+Private.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "TUIView+Private.m"; sourceTree = "<group>"; };
CBB74C8B13BE6E1900C85CB5 /* TUIView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TUIView.h; sourceTree = "<group>"; };
CBB74C8C13BE6E1900C85CB5 /* TUIView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TUIView.m; sourceTree = "<group>"; };
CBB74C8D13BE6E1900C85CB5 /* TUIViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TUIViewController.h; sourceTree = "<group>"; };
CBB74C8E13BE6E1900C85CB5 /* TUIViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TUIViewController.m; sourceTree = "<group>"; };
CBB74C8F13BE6E1900C85CB5 /* TUIViewNSViewContainer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TUIViewNSViewContainer.h; sourceTree = "<group>"; };
CBB74C9013BE6E1900C85CB5 /* TUIViewNSViewContainer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TUIViewNSViewContainer.m; sourceTree = "<group>"; };
+ D040610815B6A77500F753ED /* TUIAnimationManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TUIAnimationManager.h; sourceTree = "<group>"; };
+ D040610915B6A77500F753ED /* TUIAnimationManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TUIAnimationManager.m; sourceTree = "<group>"; };
+ D040611115B6A7CC00F753ED /* NSTextView+TUIExtensions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSTextView+TUIExtensions.h"; sourceTree = "<group>"; };
+ D040611215B6A7CC00F753ED /* NSTextView+TUIExtensions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSTextView+TUIExtensions.m"; sourceTree = "<group>"; };
+ D0C764EA15B611C200E7AC2C /* TUIBridgedView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TUIBridgedView.h; sourceTree = "<group>"; };
+ D0C7650415B6156A00E7AC2C /* TUIHostView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TUIHostView.h; sourceTree = "<group>"; };
+ D0C7650C15B6189D00E7AC2C /* TUINSHostView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TUINSHostView.h; sourceTree = "<group>"; };
+ D0C7650D15B6189D00E7AC2C /* TUINSHostView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TUINSHostView.m; sourceTree = "<group>"; };
+ D0C7651515B61E5900E7AC2C /* TUIBridgedScrollView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TUIBridgedScrollView.h; sourceTree = "<group>"; };
+ D0C7652015B6232100E7AC2C /* CALayer+TUIExtensions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "CALayer+TUIExtensions.h"; sourceTree = "<group>"; };
+ D0C7652115B6232100E7AC2C /* CALayer+TUIExtensions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "CALayer+TUIExtensions.m"; sourceTree = "<group>"; };
+ D0C7652215B6232100E7AC2C /* CATransaction+TUIExtensions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "CATransaction+TUIExtensions.h"; sourceTree = "<group>"; };
+ D0C7652315B6232100E7AC2C /* CATransaction+TUIExtensions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "CATransaction+TUIExtensions.m"; sourceTree = "<group>"; };
+ D0C7653115B624D800E7AC2C /* NSView+TUIExtensions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSView+TUIExtensions.h"; sourceTree = "<group>"; };
+ D0C7653215B624D800E7AC2C /* NSView+TUIExtensions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSView+TUIExtensions.m"; sourceTree = "<group>"; };
+ D0C7653E15B626E200E7AC2C /* TUIView+TUIBridgedView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "TUIView+TUIBridgedView.h"; sourceTree = "<group>"; };
+ D0C7653F15B626E200E7AC2C /* TUIView+TUIBridgedView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "TUIView+TUIBridgedView.m"; sourceTree = "<group>"; };
+ D0C7655015B6294400E7AC2C /* TUIScrollView+TUIBridgedScrollView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "TUIScrollView+TUIBridgedScrollView.h"; sourceTree = "<group>"; };
+ D0C7655115B6294400E7AC2C /* TUIScrollView+TUIBridgedScrollView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "TUIScrollView+TUIBridgedScrollView.m"; sourceTree = "<group>"; };
+ D0C7655915B6297200E7AC2C /* NSClipView+TUIExtensions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSClipView+TUIExtensions.h"; sourceTree = "<group>"; };
+ D0C7655A15B6297200E7AC2C /* NSClipView+TUIExtensions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSClipView+TUIExtensions.m"; sourceTree = "<group>"; };
+ D0C7655B15B6297300E7AC2C /* NSScrollView+TUIExtensions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSScrollView+TUIExtensions.h"; sourceTree = "<group>"; };
+ D0C7655C15B6297300E7AC2C /* NSScrollView+TUIExtensions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSScrollView+TUIExtensions.m"; sourceTree = "<group>"; };
+ D0C7656915B62EFA00E7AC2C /* TUINSView+Private.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "TUINSView+Private.h"; sourceTree = "<group>"; };
+ D0C7656D15B6322A00E7AC2C /* TUIViewNSViewContainer+Private.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "TUIViewNSViewContainer+Private.h"; sourceTree = "<group>"; };
+ D0C7656F15B6341800E7AC2C /* TUICAAction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TUICAAction.h; sourceTree = "<group>"; };
+ D0C7657015B6341800E7AC2C /* TUICAAction.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TUICAAction.m; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
@@ -583,6 +663,16 @@
CBB74C3C13BE6E1900C85CB5 /* CoreText+Additions.m */,
884E8F591538809C000F7A8D /* CAAnimation+TUIExtensions.h */,
884E8F5A1538809C000F7A8D /* CAAnimation+TUIExtensions.m */,
+ D0C7652015B6232100E7AC2C /* CALayer+TUIExtensions.h */,
+ D0C7652115B6232100E7AC2C /* CALayer+TUIExtensions.m */,
+ D0C7652215B6232100E7AC2C /* CATransaction+TUIExtensions.h */,
+ D0C7652315B6232100E7AC2C /* CATransaction+TUIExtensions.m */,
+ D040611115B6A7CC00F753ED /* NSTextView+TUIExtensions.h */,
+ D040611215B6A7CC00F753ED /* NSTextView+TUIExtensions.m */,
+ D040610815B6A77500F753ED /* TUIAnimationManager.h */,
+ D040610915B6A77500F753ED /* TUIAnimationManager.m */,
+ D0C7656F15B6341800E7AC2C /* TUICAAction.h */,
+ D0C7657015B6341800E7AC2C /* TUICAAction.m */,
);
name = Support;
path = lib/Support;
@@ -591,13 +681,20 @@
CBB74C3D13BE6E1900C85CB5 /* UIKit */ = {
isa = PBXGroup;
children = (
- CBB74C5B13BE6E1900C85CB5 /* TUIKit.m */,
+ D0C7655915B6297200E7AC2C /* NSClipView+TUIExtensions.h */,
+ D0C7655A15B6297200E7AC2C /* NSClipView+TUIExtensions.m */,
+ D0C7655B15B6297300E7AC2C /* NSScrollView+TUIExtensions.h */,
+ D0C7655C15B6297300E7AC2C /* NSScrollView+TUIExtensions.m */,
+ D0C7653115B624D800E7AC2C /* NSView+TUIExtensions.h */,
+ D0C7653215B624D800E7AC2C /* NSView+TUIExtensions.m */,
CBB74C3E13BE6E1900C85CB5 /* TUIAccessibility.h */,
CBB74C3F13BE6E1900C85CB5 /* TUIAccessibility.m */,
CBB74C4013BE6E1900C85CB5 /* TUIActivityIndicatorView.h */,
CBB74C4113BE6E1900C85CB5 /* TUIActivityIndicatorView.m */,
CBB74C4213BE6E1900C85CB5 /* TUIAttributedString.h */,
CBB74C4313BE6E1900C85CB5 /* TUIAttributedString.m */,
+ D0C7651515B61E5900E7AC2C /* TUIBridgedScrollView.h */,
+ D0C764EA15B611C200E7AC2C /* TUIBridgedView.h */,
88CC1F3513E3684400827793 /* TUIButton+Accessibility.h */,
88CC1F3613E3684600827793 /* TUIButton+Accessibility.m */,
CBB74C4413BE6E1900C85CB5 /* TUIButton+Content.m */,
@@ -607,11 +704,11 @@
CBB74C4813BE6E1900C85CB5 /* TUICGAdditions.m */,
CBB74C4913BE6E1900C85CB5 /* TUIColor.h */,
CBB74C4A13BE6E1900C85CB5 /* TUIColor.m */,
- CBB74C4B13BE6E1900C85CB5 /* TUIControl+TargetAction.m */,
88CC1F2D13E365B500827793 /* TUIControl+Accessibility.h */,
88CC1F2E13E365B500827793 /* TUIControl+Accessibility.m */,
886EBA7D13D64393006DE018 /* TUIControl+Private.h */,
886EBA7E13D64393006DE018 /* TUIControl+Private.m */,
+ CBB74C4B13BE6E1900C85CB5 /* TUIControl+TargetAction.m */,
CBB74C4C13BE6E1900C85CB5 /* TUIControl.h */,
CBB74C4D13BE6E1900C85CB5 /* TUIControl.m */,
CBB74C4E13BE6E1900C85CB5 /* TUIFastIndexPath.h */,
@@ -620,64 +717,71 @@
CBB74C5113BE6E1900C85CB5 /* TUIFont.m */,
CBB74C5213BE6E1900C85CB5 /* TUIGeometry.h */,
CBB74C5313BE6E1900C85CB5 /* TUIGeometry.m */,
+ D0C7650415B6156A00E7AC2C /* TUIHostView.h */,
CBB74C5413BE6E1900C85CB5 /* TUIImage+Drawing.h */,
CBB74C5513BE6E1900C85CB5 /* TUIImage+Drawing.m */,
CBB74C5613BE6E1900C85CB5 /* TUIImage.h */,
CBB74C5713BE6E1900C85CB5 /* TUIImage.m */,
CBB74C5813BE6E1900C85CB5 /* TUIImageView.h */,
CBB74C5913BE6E1900C85CB5 /* TUIImageView.m */,
+ CBB74C5B13BE6E1900C85CB5 /* TUIKit.m */,
CBB74C5C13BE6E1900C85CB5 /* TUILabel.h */,
CBB74C5D13BE6E1900C85CB5 /* TUILabel.m */,
+ D0C7650C15B6189D00E7AC2C /* TUINSHostView.h */,
+ D0C7650D15B6189D00E7AC2C /* TUINSHostView.m */,
+ 8819794A13E26E5800AA39EB /* TUINSView+Accessibility.h */,
+ 8819794B13E26E5800AA39EB /* TUINSView+Accessibility.m */,
48A10E7D15B7769A007F9EE3 /* TUILayoutConstraint.h */,
48A10E7E15B7769A007F9EE3 /* TUILayoutConstraint.m */,
48A10E7F15B7769A007F9EE3 /* TUILayoutManager.h */,
48A10E8015B7769A007F9EE3 /* TUILayoutManager.m */,
CBB74C5E13BE6E1900C85CB5 /* TUINSView+Hyperfocus.h */,
CBB74C5F13BE6E1900C85CB5 /* TUINSView+Hyperfocus.m */,
CBB74C6013BE6E1900C85CB5 /* TUINSView+NSTextInputClient.m */,
+ D0C7656915B62EFA00E7AC2C /* TUINSView+Private.h */,
CBB74C6113BE6E1900C85CB5 /* TUINSView.h */,
CBB74C6213BE6E1900C85CB5 /* TUINSView.m */,
- 8819794A13E26E5800AA39EB /* TUINSView+Accessibility.h */,
- 8819794B13E26E5800AA39EB /* TUINSView+Accessibility.m */,
CBB74C6313BE6E1900C85CB5 /* TUINSWindow.h */,
CBB74C6413BE6E1900C85CB5 /* TUINSWindow.m */,
- 30D399C6156D8ADD006ECDAE /* TUIProgressBar.h */,
- 30D399C7156D8ADD006ECDAE /* TUIProgressBar.m */,
884E8F5015387E11000F7A8D /* TUIPopover.h */,
884E8F5115387E11000F7A8D /* TUIPopover.m */,
+ 30D399C6156D8ADD006ECDAE /* TUIProgressBar.h */,
+ 30D399C7156D8ADD006ECDAE /* TUIProgressBar.m */,
CBB74C6513BE6E1900C85CB5 /* TUIResponder.h */,
CBB74C6613BE6E1900C85CB5 /* TUIResponder.m */,
CBB74C6713BE6E1900C85CB5 /* TUIScrollKnob.h */,
CBB74C6813BE6E1900C85CB5 /* TUIScrollKnob.m */,
- 88D81CFD1577EF0D009D453B /* TUIStyledView.h */,
- 88D81CFE1577EF0D009D453B /* TUIStyledView.m */,
CBB74C6913BE6E1900C85CB5 /* TUIScrollView.h */,
CBB74C6A13BE6E1900C85CB5 /* TUIScrollView.m */,
+ D0C7655015B6294400E7AC2C /* TUIScrollView+TUIBridgedScrollView.h */,
+ D0C7655115B6294400E7AC2C /* TUIScrollView+TUIBridgedScrollView.m */,
CBB74C6B13BE6E1900C85CB5 /* TUIStringDrawing.h */,
CBB74C6C13BE6E1900C85CB5 /* TUIStringDrawing.m */,
+ 88D81CFD1577EF0D009D453B /* TUIStyledView.h */,
+ 88D81CFE1577EF0D009D453B /* TUIStyledView.m */,
CBB74C6D13BE6E1900C85CB5 /* TUITableView+Additions.h */,
CBB74C6E13BE6E1900C85CB5 /* TUITableView+Additions.m */,
+ 88D25F5313F5D96500CFAAA9 /* TUITableView+Cell.h */,
+ 88D25F5413F5D96500CFAAA9 /* TUITableView+Cell.m */,
CBB74C6F13BE6E1900C85CB5 /* TUITableView+Derepeater.h */,
CBB74C7013BE6E1900C85CB5 /* TUITableView+Derepeater.m */,
CBB74C7113BE6E1900C85CB5 /* TUITableView.h */,
CBB74C7213BE6E1900C85CB5 /* TUITableView.m */,
CBB74C7313BE6E1900C85CB5 /* TUITableViewCell.h */,
CBB74C7413BE6E1900C85CB5 /* TUITableViewCell.m */,
- 88D25F5313F5D96500CFAAA9 /* TUITableView+Cell.h */,
- 88D25F5413F5D96500CFAAA9 /* TUITableView+Cell.m */,
887F272A13F9969800D75DE6 /* TUITableViewSectionHeader.h */,
887F272B13F9969800D75DE6 /* TUITableViewSectionHeader.m */,
CBB74C7513BE6E1900C85CB5 /* TUITextEditor.h */,
CBB74C7613BE6E1900C85CB5 /* TUITextEditor.m */,
CBB74C7713BE6E1900C85CB5 /* TUITextField.h */,
CBB74C7813BE6E1900C85CB5 /* TUITextField.m */,
+ 88A4AFDC145A16C90071CF22 /* TUITextRenderer+Accessibility.h */,
+ 88A4AFDD145A16C90071CF22 /* TUITextRenderer+Accessibility.m */,
CBB74C7913BE6E1900C85CB5 /* TUITextRenderer+Event.h */,
CBB74C7A13BE6E1900C85CB5 /* TUITextRenderer+Event.m */,
CBB74C7B13BE6E1900C85CB5 /* TUITextRenderer+KeyBindings.m */,
CBB74C7C13BE6E1900C85CB5 /* TUITextRenderer.h */,
CBB74C7D13BE6E1900C85CB5 /* TUITextRenderer.m */,
- 88A4AFDC145A16C90071CF22 /* TUITextRenderer+Accessibility.h */,
- 88A4AFDD145A16C90071CF22 /* TUITextRenderer+Accessibility.m */,
CBB74C7E13BE6E1900C85CB5 /* TUITextView.h */,
CBB74C7F13BE6E1900C85CB5 /* TUITextView.m */,
88EFFB4F13F417E200CF91A9 /* TUITextViewEditor.h */,
@@ -696,13 +800,15 @@
CBB74C8713BE6E1900C85CB5 /* TUIView+PasteboardDragging.h */,
CBB74C8813BE6E1900C85CB5 /* TUIView+PasteboardDragging.m */,
CBB74C8913BE6E1900C85CB5 /* TUIView+Private.h */,
- CBB74C8A13BE6E1900C85CB5 /* TUIView+Private.m */,
+ D0C7653E15B626E200E7AC2C /* TUIView+TUIBridgedView.h */,
+ D0C7653F15B626E200E7AC2C /* TUIView+TUIBridgedView.m */,
CBB74C8B13BE6E1900C85CB5 /* TUIView.h */,
CBB74C8C13BE6E1900C85CB5 /* TUIView.m */,
CBB74C8D13BE6E1900C85CB5 /* TUIViewController.h */,
CBB74C8E13BE6E1900C85CB5 /* TUIViewController.m */,
CBB74C8F13BE6E1900C85CB5 /* TUIViewNSViewContainer.h */,
CBB74C9013BE6E1900C85CB5 /* TUIViewNSViewContainer.m */,
+ D0C7656D15B6322A00E7AC2C /* TUIViewNSViewContainer+Private.h */,
);
name = UIKit;
path = lib/UIKit;
@@ -725,6 +831,14 @@
887F272E13F9969800D75DE6 /* TUITableViewSectionHeader.h in Headers */,
884E8F5415387E11000F7A8D /* TUIPopover.h in Headers */,
884E8F5D1538809C000F7A8D /* CAAnimation+TUIExtensions.h in Headers */,
+ D0C764ED15B611C200E7AC2C /* TUIBridgedView.h in Headers */,
+ D0C7650715B6156A00E7AC2C /* TUIHostView.h in Headers */,
+ D0C7651815B61E5A00E7AC2C /* TUIBridgedScrollView.h in Headers */,
+ D0C7653515B624D900E7AC2C /* NSView+TUIExtensions.h in Headers */,
+ D0C7654815B626E200E7AC2C /* TUIView+TUIBridgedView.h in Headers */,
+ D0C7655415B6294400E7AC2C /* TUIScrollView+TUIBridgedScrollView.h in Headers */,
+ D0C7655F15B6297300E7AC2C /* NSClipView+TUIExtensions.h in Headers */,
+ D0C7656515B6297300E7AC2C /* NSScrollView+TUIExtensions.h in Headers */,
D039724715B7D7D70092CD26 /* TUIView+Layout.h in Headers */,
D039724915B7D7DC0092CD26 /* TUILayoutManager.h in Headers */,
D039724B15B7D7DE0092CD26 /* TUILayoutConstraint.h in Headers */,
@@ -789,6 +903,14 @@
88EFFB5113F417E200CF91A9 /* TUITextViewEditor.h in Headers */,
88D25F5513F5D96500CFAAA9 /* TUITableView+Cell.h in Headers */,
88A4AFDE145A16CA0071CF22 /* TUITextRenderer+Accessibility.h in Headers */,
+ D0C764EB15B611C200E7AC2C /* TUIBridgedView.h in Headers */,
+ D0C7650515B6156A00E7AC2C /* TUIHostView.h in Headers */,
+ D0C7651615B61E5A00E7AC2C /* TUIBridgedScrollView.h in Headers */,
+ D0C7653315B624D900E7AC2C /* NSView+TUIExtensions.h in Headers */,
+ D0C7654615B626E200E7AC2C /* TUIView+TUIBridgedView.h in Headers */,
+ D0C7655215B6294400E7AC2C /* TUIScrollView+TUIBridgedScrollView.h in Headers */,
+ D0C7655D15B6297300E7AC2C /* NSClipView+TUIExtensions.h in Headers */,
+ D0C7656315B6297300E7AC2C /* NSScrollView+TUIExtensions.h in Headers */,
48A10E8115B7769A007F9EE3 /* TUILayoutConstraint.h in Headers */,
48A10E8315B7769A007F9EE3 /* TUILayoutManager.h in Headers */,
48A10E8B15B77A46007F9EE3 /* TUIView+Layout.h in Headers */,
@@ -809,6 +931,14 @@
887F272D13F9969800D75DE6 /* TUITableViewSectionHeader.h in Headers */,
884E8F5315387E11000F7A8D /* TUIPopover.h in Headers */,
884E8F5C1538809C000F7A8D /* CAAnimation+TUIExtensions.h in Headers */,
+ D0C764EC15B611C200E7AC2C /* TUIBridgedView.h in Headers */,
+ D0C7650615B6156A00E7AC2C /* TUIHostView.h in Headers */,
+ D0C7651715B61E5A00E7AC2C /* TUIBridgedScrollView.h in Headers */,
+ D0C7653415B624D900E7AC2C /* NSView+TUIExtensions.h in Headers */,
+ D0C7654715B626E200E7AC2C /* TUIView+TUIBridgedView.h in Headers */,
+ D0C7655315B6294400E7AC2C /* TUIScrollView+TUIBridgedScrollView.h in Headers */,
+ D0C7655E15B6297300E7AC2C /* NSClipView+TUIExtensions.h in Headers */,
+ D0C7656415B6297300E7AC2C /* NSScrollView+TUIExtensions.h in Headers */,
D039724615B7D7D60092CD26 /* TUIView+Layout.h in Headers */,
D039724815B7D7DB0092CD26 /* TUILayoutManager.h in Headers */,
D039724A15B7D7DE0092CD26 /* TUILayoutConstraint.h in Headers */,
@@ -1000,7 +1130,6 @@
5EE983E413BE7834005F430D /* TUIView+Event.m in Sources */,
5EE983E513BE7834005F430D /* TUIView+NSTextInputClient.m in Sources */,
5EE983E613BE7834005F430D /* TUIView+PasteboardDragging.m in Sources */,
- 5EE983E713BE7834005F430D /* TUIView+Private.m in Sources */,
5EE983E813BE7834005F430D /* TUIView.m in Sources */,
5EE983E913BE7834005F430D /* TUIViewController.m in Sources */,
5EE983EA13BE7834005F430D /* TUIViewNSViewContainer.m in Sources */,
@@ -1014,6 +1143,17 @@
887F273113F9969800D75DE6 /* TUITableViewSectionHeader.m in Sources */,
884E8F5715387E11000F7A8D /* TUIPopover.m in Sources */,
884E8F601538809C000F7A8D /* CAAnimation+TUIExtensions.m in Sources */,
+ D0C7651315B6189D00E7AC2C /* TUINSHostView.m in Sources */,
+ D0C7652915B6232100E7AC2C /* CALayer+TUIExtensions.m in Sources */,
+ D0C7652F15B6232100E7AC2C /* CATransaction+TUIExtensions.m in Sources */,
+ D0C7653815B624D900E7AC2C /* NSView+TUIExtensions.m in Sources */,
+ D0C7654B15B626E200E7AC2C /* TUIView+TUIBridgedView.m in Sources */,
+ D0C7655715B6294400E7AC2C /* TUIScrollView+TUIBridgedScrollView.m in Sources */,
+ D0C7656215B6297300E7AC2C /* NSClipView+TUIExtensions.m in Sources */,
+ D0C7656815B6297300E7AC2C /* NSScrollView+TUIExtensions.m in Sources */,
+ D0C7657615B6341800E7AC2C /* TUICAAction.m in Sources */,
+ D040610F15B6A77500F753ED /* TUIAnimationManager.m in Sources */,
+ D040611815B6A7CD00F753ED /* NSTextView+TUIExtensions.m in Sources */,
D039724115B7D7CC0092CD26 /* TUILayoutConstraint.m in Sources */,
D039724315B7D7CE0092CD26 /* TUILayoutManager.m in Sources */,
D039724515B7D7D40092CD26 /* TUIView+Layout.m in Sources */,
@@ -1066,7 +1206,6 @@
CBB74CDB13BE6E1900C85CB5 /* TUIView+Event.m in Sources */,
CBB74CDD13BE6E1900C85CB5 /* TUIView+NSTextInputClient.m in Sources */,
CBB74CDF13BE6E1900C85CB5 /* TUIView+PasteboardDragging.m in Sources */,
- CBB74CE113BE6E1900C85CB5 /* TUIView+Private.m in Sources */,
CBB74CE313BE6E1900C85CB5 /* TUIView.m in Sources */,
CBB74CE513BE6E1900C85CB5 /* TUIViewController.m in Sources */,
CBB74CE713BE6E1900C85CB5 /* TUIViewNSViewContainer.m in Sources */,
@@ -1083,6 +1222,17 @@
884E8F5E1538809C000F7A8D /* CAAnimation+TUIExtensions.m in Sources */,
30D399C9156D8ADD006ECDAE /* TUIProgressBar.m in Sources */,
88D81D001577EF0D009D453B /* TUIStyledView.m in Sources */,
+ D0C7651115B6189D00E7AC2C /* TUINSHostView.m in Sources */,
+ D0C7652715B6232100E7AC2C /* CALayer+TUIExtensions.m in Sources */,
+ D0C7652D15B6232100E7AC2C /* CATransaction+TUIExtensions.m in Sources */,
+ D0C7653615B624D900E7AC2C /* NSView+TUIExtensions.m in Sources */,
+ D0C7654915B626E200E7AC2C /* TUIView+TUIBridgedView.m in Sources */,
+ D0C7655515B6294400E7AC2C /* TUIScrollView+TUIBridgedScrollView.m in Sources */,
+ D0C7656015B6297300E7AC2C /* NSClipView+TUIExtensions.m in Sources */,
+ D0C7656615B6297300E7AC2C /* NSScrollView+TUIExtensions.m in Sources */,
+ D0C7657415B6341800E7AC2C /* TUICAAction.m in Sources */,
+ D040610D15B6A77500F753ED /* TUIAnimationManager.m in Sources */,
+ D040611615B6A7CD00F753ED /* NSTextView+TUIExtensions.m in Sources */,
48A10E8215B7769A007F9EE3 /* TUILayoutConstraint.m in Sources */,
48A10E8415B7769A007F9EE3 /* TUILayoutManager.m in Sources */,
48A10E8915B778E8007F9EE3 /* TUIView+Layout.m in Sources */,
@@ -1144,7 +1294,6 @@
CB5E326213BE70CA004B7899 /* TUIView+Event.m in Sources */,
CB5E326413BE70CA004B7899 /* TUIView+NSTextInputClient.m in Sources */,
CB5E326613BE70CA004B7899 /* TUIView+PasteboardDragging.m in Sources */,
- CB5E326813BE70CA004B7899 /* TUIView+Private.m in Sources */,
CB5E326A13BE70CA004B7899 /* TUIView.m in Sources */,
CB5E326C13BE70CA004B7899 /* TUIViewController.m in Sources */,
CB5E326E13BE70CA004B7899 /* TUIViewNSViewContainer.m in Sources */,
@@ -1158,6 +1307,17 @@
887F273013F9969800D75DE6 /* TUITableViewSectionHeader.m in Sources */,
884E8F5615387E11000F7A8D /* TUIPopover.m in Sources */,
884E8F5F1538809C000F7A8D /* CAAnimation+TUIExtensions.m in Sources */,
+ D0C7651215B6189D00E7AC2C /* TUINSHostView.m in Sources */,
+ D0C7652815B6232100E7AC2C /* CALayer+TUIExtensions.m in Sources */,
+ D0C7652E15B6232100E7AC2C /* CATransaction+TUIExtensions.m in Sources */,
+ D0C7653715B624D900E7AC2C /* NSView+TUIExtensions.m in Sources */,
+ D0C7654A15B626E200E7AC2C /* TUIView+TUIBridgedView.m in Sources */,
+ D0C7655615B6294400E7AC2C /* TUIScrollView+TUIBridgedScrollView.m in Sources */,
+ D0C7656115B6297300E7AC2C /* NSClipView+TUIExtensions.m in Sources */,
+ D0C7656715B6297300E7AC2C /* NSScrollView+TUIExtensions.m in Sources */,
+ D0C7657515B6341800E7AC2C /* TUICAAction.m in Sources */,
+ D040610E15B6A77500F753ED /* TUIAnimationManager.m in Sources */,
+ D040611715B6A7CD00F753ED /* NSTextView+TUIExtensions.m in Sources */,
D039723F15B7D7CB0092CD26 /* TUILayoutConstraint.m in Sources */,
D039724215B7D7CE0092CD26 /* TUILayoutManager.m in Sources */,
D039724415B7D7D40092CD26 /* TUIView+Layout.m in Sources */,
View
39 lib/Support/CALayer+TUIExtensions.h
@@ -0,0 +1,39 @@
+//
+// CALayer+TUIExtensions.h
+//
+// Created by Josh Vera on 11/26/11.
+// Copyright (c) 2011 Bitswift. All rights reserved.
+//
+
+#import <QuartzCore/QuartzCore.h>
+
+/**
+ * Additional geometry conversions and geometrical functions for CALayer.
+ */
+@interface CALayer (TUIExtensions)
+/**
+ * Converts a rectangle from the receiver's coordinate system to that of a given
+ * layer, taking into account any layer clipping between the two.
+ *
+ * This will traverse the layer hierarchy, finding a common ancestor between the
+ * receiver and 'layer' to use as a base for geometry conversion. If any layers
+ * along the way (including the receiver, 'layer', and the common ancestor) have
+ * masksToBounds set to YES, the rectangle takes into account their clipping
+ * paths, such that the final result represents a rectangle that would actually
+ * be visible on screen.
+ *
+ * The receiver and 'layer' must have a common ancestor.
+ */
+- (CGRect)tui_convertAndClipRect:(CGRect)rect toLayer:(CALayer *)layer;
+
+/**
+ * Converts a rectangle from the coordinate system of 'layer' to the
+ * receiver's, taking into account any layer clipping between the two.
+ *
+ * This will call -tui_convertAndClipRect:toLayer:> on 'layer' with the receiver
+ * as the argument.
+ *
+ * The receiver and 'layer' must have a common ancestor.
+ */
+- (CGRect)tui_convertAndClipRect:(CGRect)rect fromLayer:(CALayer *)layer;
+@end
View
55 lib/Support/CALayer+TUIExtensions.m
@@ -0,0 +1,55 @@
+//
+// CALayer+TUIExtensions.m
+//
+// Created by Josh Vera on 11/26/11.
+// Copyright (c) 2011 Bitswift. All rights reserved.
+//
+
+#import "CALayer+TUIExtensions.h"
+
+static CGRect convertAndClipRectFromSuperlayers (CGRect rect, CALayer *layer);
+
+static CGRect convertAndClipRectFromSuperlayers (CGRect rect, CALayer *layer) {
+ CALayer *superlayer = layer.superlayer;
+ if (superlayer) {
+ rect = convertAndClipRectFromSuperlayers(rect, superlayer);
+ if (CGRectIsNull(rect))
+ return CGRectNull;
+
+ rect = [layer convertRect:rect fromLayer:superlayer];
+ }
+
+ if (layer.masksToBounds) {
+ rect = CGRectIntersection(rect, layer.visibleRect);
+ }
+
+ return rect;
+}
+
+@implementation CALayer (TUIExtensions)
+- (CGRect)tui_convertAndClipRect:(CGRect)rect toLayer:(CALayer *)layer {
+ CALayer *clippingLayer = self.superlayer;
+ CALayer *lastLayer = self;
+ while (clippingLayer) {
+ if (lastLayer.masksToBounds) {
+ rect = CGRectIntersection(rect, lastLayer.visibleRect);
+ if (CGRectIsNull(rect))
+ return CGRectNull;
+ }
+
+ rect = [clippingLayer convertRect:rect fromLayer:lastLayer];
+
+ lastLayer = clippingLayer;
+ clippingLayer = clippingLayer.superlayer;
+ }
+
+ // 'rect' is in the coordinate system of the root layer, and has been
+ // clipped accordingly
+ return convertAndClipRectFromSuperlayers(rect, layer);
+}
+
+- (CGRect)tui_convertAndClipRect:(CGRect)rect fromLayer:(CALayer *)layer {
+ return [layer tui_convertAndClipRect:rect toLayer:self];
+}
+
+@end
View
22 lib/Support/CATransaction+TUIExtensions.h
@@ -0,0 +1,22 @@
+//
+// CATransaction+TUIExtensions.h
+//
+// Created by James Lawton on 11/23/11.
+// Copyright (c) 2011 Bitswift. All rights reserved.
+//
+
+#import <QuartzCore/QuartzCore.h>
+
+/**
+ * Extends CATransaction with useful block-based features.
+ */
+@interface CATransaction (TUIExtensions)
+
+/**
+ * Executes a block with actions disabled.
+ *
+ * This will have the effect of suppressing animation.
+ */
++ (void)tui_performWithDisabledActions:(void(^)(void))block;
+
+@end
View
22 lib/Support/CATransaction+TUIExtensions.m
@@ -0,0 +1,22 @@
+//
+// CATransaction+TUIExtensions.m
+//
+// Created by James Lawton on 11/23/11.
+// Copyright (c) 2011 Bitswift. All rights reserved.
+//
+
+#import "CATransaction+TUIExtensions.h"
+
+@implementation CATransaction (TUIExtensions)
++ (void)tui_performWithDisabledActions:(void(^)(void))block {
+ if ([self disableActions]) {
+ // actions are already disabled
+ block();
+ } else {
+ [self setDisableActions:YES];
+ block();
+ [self setDisableActions:NO];
+ }
+}
+
+@end
View
15 lib/Support/NSTextView+TUIExtensions.h
@@ -0,0 +1,15 @@
+//
+// NSTextView+TUIExtensions.h
+//
+// Created by Justin Spahr-Summers on 10.03.12.
+// Copyright (c) 2012 Bitswift. All rights reserved.
+//
+
+#import <Cocoa/Cocoa.h>
+
+/**
+ * This private category fixes blurry text in layer-backed text views and text
+ * fields.
+ */
+@interface NSTextView (TUIExtensions)
+@end
View
43 lib/Support/NSTextView+TUIExtensions.m
@@ -0,0 +1,43 @@
+//
+// NSTextView+TUIExtensions.m
+//
+// Created by Justin Spahr-Summers on 10.03.12.
+// Copyright (c) 2012 Bitswift. All rights reserved.
+//
+
+#import "NSTextView+TUIExtensions.h"
+#import <objc/runtime.h>
+
+static void (*originalDrawRectIMP)(id, SEL, NSRect);
+
+static void fixedDrawRect (NSTextView *self, SEL _cmd, NSRect rect) {
+ CGContextRef context = [NSGraphicsContext currentContext].graphicsPort;
+
+ CGContextSetAllowsAntialiasing(context, YES);
+ CGContextSetAllowsFontSmoothing(context, YES);
+ CGContextSetAllowsFontSubpixelPositioning(context, YES);
+ CGContextSetAllowsFontSubpixelQuantization(context, YES);
+
+ CGContextSetShouldAntialias(context, YES);
+ CGContextSetShouldSmoothFonts(context, YES);
+ CGContextSetShouldSubpixelPositionFonts(context, YES);
+ CGContextSetShouldSubpixelQuantizeFonts(context, YES);
+
+ if (self.superview) {
+ // NSTextView likes to fall on non-integral points sometimes -- fix that
+ self.frame = [self.superview backingAlignedRect:self.frame options:NSAlignAllEdgesNearest];
+ }
+
+ originalDrawRectIMP(self, _cmd, rect);
+}
+
+@implementation NSTextView (TUIExtensions)
+
++ (void)load {
+ Method drawRect = class_getInstanceMethod(self, @selector(drawRect:));
+ originalDrawRectIMP = (void (*)(id, SEL, NSRect))method_getImplementation(drawRect);
+
+ class_replaceMethod(self, method_getName(drawRect), (IMP)&fixedDrawRect, method_getTypeEncoding(drawRect));
+}
+
+@end
View
23 lib/Support/TUIAnimationManager.h
@@ -0,0 +1,23 @@
+//
+// TUIAnimationManager.h
+//
+// Created by Justin Spahr-Summers on 10.03.12.
+// Copyright (c) 2012 Bitswift. All rights reserved.
+//
+
+#import <Foundation/Foundation.h>
+
+/**
+ * This private class is responsible for disabling implicit NSView animations.
+ *
+ * This class may be expanded in the future to add other global animation
+ * capabilities.
+ */
+@interface TUIAnimationManager : NSObject
+
+/*
+ * Returns the singleton instance of this class.
+ */
++ (TUIAnimationManager *)defaultManager;
+
+@end
View
114 lib/Support/TUIAnimationManager.m
@@ -0,0 +1,114 @@
+//
+// TUIAnimationManager.m
+//
+// Created by Justin Spahr-Summers on 10.03.12.
+// Copyright (c) 2012 Bitswift. All rights reserved.
+//
+
+#import "TUIAnimationManager.h"
+
+/**
+ * Disables implicit AppKit animations on every run loop iteration.
+ */
+static void mainRunLoopObserverCallback (CFRunLoopObserverRef observer, CFRunLoopActivity activity, void *info) {
+ [[NSAnimationContext currentContext] setDuration:0];
+}
+
+@interface TUIAnimationManager ()
+/**
+ * The observer associated with the main run loop, responsible for invoking the
+ * mainRunLoopObserverCallback.
+ */
+@property (nonatomic) CFRunLoopObserverRef mainRunLoopObserver;
+
+/**
+ * Invoked on the defaultManager when the application has finished launching.
+ */
+- (void)applicationDidFinishLaunchingNotification:(NSNotification *)notification;
+
+/**
+ * Registers an observer on the main run loop which will invoke the
+ * mainRunLoopObserverCallback.
+ */
+- (void)registerRunLoopObserver;
+@end
+
+@implementation TUIAnimationManager
+
+#pragma mark Properties
+
+@synthesize mainRunLoopObserver = m_mainRunLoopObserver;
+
+- (void)setMainRunLoopObserver:(CFRunLoopObserverRef)observer {
+ if (observer == m_mainRunLoopObserver)
+ return;
+
+ if (m_mainRunLoopObserver) {
+ CFRunLoopRemoveObserver(CFRunLoopGetMain(), m_mainRunLoopObserver, kCFRunLoopCommonModes);
+ CFRelease(m_mainRunLoopObserver);
+ }
+
+ if (observer)
+ CFRetain(observer);
+
+ m_mainRunLoopObserver = observer;
+}
+
+#pragma mark Lifecycle
+
++ (void)load {
+ @autoreleasepool {
+ [[NSNotificationCenter defaultCenter]
+ addObserver:[self defaultManager]
+ selector:@selector(applicationDidFinishLaunchingNotification:)
+ name:NSApplicationDidFinishLaunchingNotification
+ object:nil
+ ];
+ }
+}
+
++ (TUIAnimationManager *)defaultManager; {
+ static id singleton = nil;
+ static dispatch_once_t pred;
+
+ dispatch_once(&pred, ^{
+ singleton = [[self alloc] init];
+ });
+
+ return singleton;
+}
+
+- (void)dealloc {
+ [[NSNotificationCenter defaultCenter] removeObserver:self];
+
+ self.mainRunLoopObserver = NULL;
+}
+
+#pragma mark Run Loop Observer
+
+- (void)registerRunLoopObserver; {
+ // set up an observer on the main run loop that can disable implicit
+ // animations
+ CFRunLoopObserverRef observer = CFRunLoopObserverCreate(
+ NULL,
+ kCFRunLoopBeforeTimers,
+ YES,
+ 10000,
+ &mainRunLoopObserverCallback,
+ NULL
+ );
+
+ CFRunLoopAddObserver(CFRunLoopGetMain(), observer, kCFRunLoopCommonModes);
+
+ self.mainRunLoopObserver = observer;
+ CFRelease(observer);
+}
+
+#pragma mark Notifications
+
+- (void)applicationDidFinishLaunchingNotification:(NSNotification *)notification; {
+ [[NSNotificationCenter defaultCenter] removeObserver:self name:notification.name object:nil];
+ [self registerRunLoopObserver];
+}
+
+@end
View
36 lib/Support/TUICAAction.h
@@ -0,0 +1,36 @@
+//
+// TUICAAction.h
+//
+// Created by James Lawton on 11/21/11.
+// Copyright (c) 2011 Bitswift. All rights reserved.
+//
+
+#import <Foundation/Foundation.h>
+#import <QuartzCore/QuartzCore.h>
+
+/*
+ * A CAAction which finds AppKit views contained in Velvet and animates them
+ * alongside. We pass through to the default animation to animate the Velvet
+ * views.
+ */
+@interface TUICAAction : NSObject <CAAction>
+
+/*
+ * Initializes an action which proxies for the given action, and handles animation
+ * of all descendent TUIViewNSViewContainer instances along with the layer being acted upon.
+ *
+ * This is the designated initializer.
+ */
+- (id)initWithAction:(id<CAAction>)innerAction;
+
+/*
+ * Returns an action initialized with <initWithAction:>.
+ */
++ (id)actionWithAction:(id<CAAction>)innerAction;
+
+/*
+ * Whether objects of this class add features to actions for the given key.
+ */
++ (BOOL)interceptsActionForKey:(NSString *)key;
+
+@end
View
261 lib/Support/TUICAAction.m
@@ -0,0 +1,261 @@
+//
+// TUICAAction.m
+//
+// Created by James Lawton on 11/21/11.
+// Copyright (c) 2011 Bitswift. All rights reserved.
+//
+
+#import "TUICAAction.h"
+#import "TUINSWindow.h"
+#import "TUIView.h"
+#import "TUIViewNSViewContainer+Private.h"
+#import "CATransaction+TUIExtensions.h"
+#import <objc/runtime.h>
+
+@interface TUICAAction ()
+/*
+ * The action that this action is proxying, as specified at the time of
+ * initialization.
+ */
+@property (nonatomic, strong, readonly) id<CAAction> innerAction;
+
+/*
+ * The first responder when the animation began, to be restored when the
+ * animation completes.
+ */
+@property (nonatomic, strong) NSResponder *originalFirstResponder;
+
+/*
+ * Invoked whenever the geometry property `key` of `layer` has changed.
+ */
+- (void)geometryChangedForKey:(NSString *)key layer:(CALayer *)layer;
+
+/*
+ * Invoked whenever the opacity of `layer` has changed.
+ */
+- (void)opacityChangedForLayer:(CALayer *)layer;
+
+/*
+ * Renders the `NSView` of the given view into its layer and hides the `NSView`.
+ *
+ * This can be used to capture a static rendering of the `NSView` for animation
+ * or other purposes.
+ *
+ * @param view The <TUIViewNSViewContainer> hosting the `NSView`.
+ *
+ * @note <stopRenderingNSViewOfView:> should be invoked to restore the normal
+ * rendering of the `NSView`. Calls to these methods cannot be nested.
+ */
+- (void)startRenderingNSViewOfView:(TUIViewNSViewContainer *)view;
+
+/*
+ * Restores the normal rendering of the given view's `NSView` after a previous
+ * call to <startRenderingNSViewOfView:>.
+ *
+ * @param view The <TUIViewNSViewContainer> hosting the `NSView`.
+ *
+ * @note Calls to this method cannot be nested.
+ */
+- (void)stopRenderingNSViewOfView:(TUIViewNSViewContainer *)view;
+
+/*
+ * Schedules the given block to execute when the animation represented by the
+ * receiver completes.
+ *
+ * @param block A block to be run when the animation completes.
+ * @param layer The layer that the receiver is attached to.
+ */
+- (void)runWhenAnimationCompletes:(void (^)(void))block forLayer:(CALayer *)layer;
+
+/*
+ * Returns `YES` if objects of this class add features to actions for the given
+ * geometry property.
+ */
++ (BOOL)interceptsGeometryActionForKey:(NSString *)key;
+
+@end
+
+@implementation TUICAAction
+
+#pragma mark Properties
+
+@synthesize innerAction = m_innerAction;
+@synthesize originalFirstResponder = m_originalFirstResponder;
+
+#pragma mark Lifecycle
+
+- (id)initWithAction:(id<CAAction>)innerAction {
+ self = [super init];
+ if (!self)
+ return nil;
+
+ m_innerAction = innerAction;
+ return self;
+}
+
++ (id)actionWithAction:(id<CAAction>)innerAction {
+ return [[self alloc] initWithAction:innerAction];
+}
+
+#pragma mark TUIViewNSViewContainer support
+
+- (void)enumerateTUIViewNSViewContainersInLayer:(CALayer *)layer block:(void(^)(TUIViewNSViewContainer *))block {
+ if ([layer.delegate isKindOfClass:[TUIViewNSViewContainer class]]) {
+ block(layer.delegate);
+ } else {
+ for (CALayer *sublayer in [layer sublayers]) {
+ [self enumerateTUIViewNSViewContainersInLayer:sublayer block:block];
+ }
+ }
+}
+
+- (void)startRenderingNSViewOfView:(TUIViewNSViewContainer *)view; {
+ // Resign first responder on an animating NSView
+ // to disable focus ring.
+ id responder = view.nsWindow.firstResponder;
+ if ([responder isKindOfClass:[NSView class]] && [responder isDescendantOf:view.rootView]) {
+ // find the next responder which is not in this NSView hierarchy, and
+ // make that the first responder for the duration of the animation
+ id nextResponder = [responder nextResponder];
+
+ BOOL (^validResponder)(id) = ^(id obj){
+ if (!obj)
+ return YES;
+
+ if ([obj isKindOfClass:[NSView class]] && [responder isDescendantOf:view.rootView])
+ return NO;
+
+ if (![obj acceptsFirstResponder])
+ return NO;
+
+ return YES;
+ };
+
+ while (!validResponder(nextResponder)) {
+ nextResponder = [nextResponder nextResponder];
+ }
+
+ if ([view.nsWindow makeFirstResponder:nextResponder]) {
+ self.originalFirstResponder = responder;
+ }
+ }
+
+ BOOL wasAlreadyRendering = view.renderingContainedView;
+
+ [view startRenderingContainedView];
+ if (!wasAlreadyRendering) {
+ view.rootView.alphaValue = 0.0;
+ }
+}
+
+- (void)stopRenderingNSViewOfView:(TUIViewNSViewContainer *)view; {
+ [view stopRenderingContainedView];
+
+ if (!view.renderingContainedView) {
+ [view synchronizeNSViewGeometry];
+ view.rootView.alphaValue = 1.0;
+ }
+
+ if (self.originalFirstResponder) {
+ [view.nsWindow makeFirstResponder:self.originalFirstResponder];
+ self.originalFirstResponder = nil;
+ }
+}
+
+#pragma mark Action interception
+
+- (void)runActionForKey:(NSString *)key object:(id)anObject arguments:(NSDictionary *)dict {
+ if (![[NSNull null] isEqual:self.innerAction])
+ [self.innerAction runActionForKey:key object:anObject arguments:dict];
+
+ CAAnimation *animation = [anObject animationForKey:key];
+ if (!animation)
+ return;
+
+ if ([key isEqualToString:@"opacity"]) {
+ [self opacityChangedForLayer:anObject];
+ } else if ([[self class] interceptsGeometryActionForKey:key]) {
+ [self geometryChangedForKey:key layer:anObject];
+ }
+}
+
++ (BOOL)interceptsGeometryActionForKey:(NSString *)key {
+ return [key isEqualToString:@"position"] || [key isEqualToString:@"bounds"] || [key isEqualToString:@"transform"];
+}
+
++ (BOOL)interceptsActionForKey:(NSString *)key {
+ return [key isEqualToString:@"opacity"] || [self interceptsGeometryActionForKey:key];
+}
+
+#pragma mark Action handlers
+
+- (void)geometryChangedForKey:(NSString *)key layer:(CALayer *)layer {
+ // For all contained TUIViewNSViewContainers, render their NSView into their layer
+ // and hide the NSView. Now the visual element is part of the layer
+ // hierarchy we're animating.
+ NSMutableArray *cachedViews = [NSMutableArray array];
+ [self enumerateTUIViewNSViewContainersInLayer:layer block:^(TUIViewNSViewContainer *view) {
+ [self startRenderingNSViewOfView:view];
+ [cachedViews addObject:view];
+ }];
+
+ // If we did nothing, there's no cleanup needed.
+ if (![cachedViews count])
+ return;
+
+ // return NSViews to rendering themselves after this animation completes
+ [self runWhenAnimationCompletes:^{
+ [cachedViews enumerateObjectsUsingBlock:^(TUIViewNSViewContainer *view, NSUInteger idx, BOOL *stop) {
+ [self stopRenderingNSViewOfView:view];
+ }];
+ } forLayer:layer];
+}
+
+- (void)opacityChangedForLayer:(CALayer *)layer; {
+ float newOpacity = layer.opacity;
+
+ if (fabs(1 - newOpacity) < 0.001) {
+ // return NSViews to rendering themselves after this animation completes
+ [self runWhenAnimationCompletes:^{
+ [self enumerateTUIViewNSViewContainersInLayer:layer block:^(TUIViewNSViewContainer *view) {
+ [self stopRenderingNSViewOfView:view];
+ }];
+ } forLayer:layer];
+ } else {
+ // For all contained TUIViewNSViewContainers, render their NSView into their layer
+ // and hide the NSView. Now the visual element is part of the layer
+ // hierarchy we're animating.
+ [self enumerateTUIViewNSViewContainersInLayer:layer block:^(TUIViewNSViewContainer *view) {
+ [self startRenderingNSViewOfView:view];
+ }];
+ }
+}
+
+- (void)runWhenAnimationCompletes:(void (^)(void))block forLayer:(CALayer *)layer; {
+ NSParameterAssert(block != nil);
+ NSParameterAssert(layer != nil);
+
+ CFTimeInterval duration = [CATransaction animationDuration];
+
+ if ([(id)self.innerAction isKindOfClass:[CAAnimation class]]) {
+ CAAnimation *animation = (id)self.innerAction;
+ if (animation.duration)
+ duration = animation.duration;
+
+ duration += animation.beginTime;
+ duration /= animation.speed;
+
+ do {
+ duration += layer.beginTime - layer.timeOffset;
+ duration /= layer.speed;
+
+ layer = layer.superlayer;
+ } while (layer);
+ }
+
+ dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(duration * NSEC_PER_SEC));
+ dispatch_after(popTime, dispatch_get_main_queue(), block);
+}
+
+@end
+
View
19 lib/UIKit/NSClipView+TUIExtensions.h
@@ -0,0 +1,19 @@
+//
+// NSClipView+TUIExtensions.h
+// TwUI
+//
+// Created by Justin Spahr-Summers on 17.07.12.
+//
+// Portions of this code were taken from Velvet,
+// which is copyright (c) 2012 Bitswift, Inc.
+// See LICENSE.txt for more information.
+//
+
+#import <Cocoa/Cocoa.h>
+#import "TUIBridgedScrollView.h"
+
+/**
+ * Implements <TUIBridgedScrollView> for NSClipView.
+ */
+@interface NSClipView (TUIExtensions) <TUIBridgedScrollView>
+@end
View
46 lib/UIKit/NSClipView+TUIExtensions.m
@@ -0,0 +1,46 @@
+//
+// NSClipView+TUIExtensions.m
+// TwUI
+//
+// Created by Justin Spahr-Summers on 17.07.12.
+//
+// Portions of this code were taken from Velvet,
+// which is copyright (c) 2012 Bitswift, Inc.
+// See LICENSE.txt for more information.
+//
+
+#import "NSClipView+TUIExtensions.h"
+#import "NSView+TUIExtensions.h"
+
+@implementation NSClipView (TUIExtensions)
+
+#pragma mark TUIBridgedView
+
+// implemented on NSView
+@dynamic layer;
+@dynamic hostView;
+
+#pragma mark TUIBridgedScrollView
+
+- (void)scrollToIncludeRect:(CGRect)rect; {
+ CGRect visibleRect = self.documentVisibleRect;
+ CGSize visibleSize = visibleRect.size;
+
+ CGPoint newScrollPoint = visibleRect.origin;
+
+ if (CGRectGetMinX(rect) < CGRectGetMinX(visibleRect)) {
+ newScrollPoint.x = CGRectGetMinX(rect);
+ } else if (CGRectGetMaxX(rect) > CGRectGetMaxX(visibleRect)) {
+ newScrollPoint.x = fmax(0, CGRectGetMaxX(rect) - visibleSize.width);
+ }
+
+ if (CGRectGetMinY(rect) < CGRectGetMinY(visibleRect)) {
+ newScrollPoint.y = CGRectGetMinY(rect);
+ } else if (CGRectGetMaxY(rect) > CGRectGetMaxY(visibleRect)) {
+ newScrollPoint.y = fmax(0, CGRectGetMaxY(rect) - visibleSize.width);
+ }
+
+ [self scrollToPoint:newScrollPoint];
+}
+
+@end
View
23 lib/UIKit/NSScrollView+TUIExtensions.h
@@ -0,0 +1,23 @@
+//
+// NSScrollView+TUIExtensions.h
+// TwUI
+//
+// Created by Justin Spahr-Summers on 17.07.12.
+//
+// Portions of this code were taken from Velvet,
+// which is copyright (c) 2012 Bitswift, Inc.
+// See LICENSE.txt for more information.
+//
+
+#import <Cocoa/Cocoa.h>
+#import "TUIBridgedScrollView.h"
+
+/**
+ * Implements <TUIBridgedScrollView> for NSScrollView.
+ *
+ * Because the <TUIBridgedScrollView> protocol is already implemented for NSClipView,
+ * this category is simply a convenience that invokes the protocol methods
+ * against the underlying contentView.
+ */
+@interface NSScrollView (TUIExtensions) <TUIBridgedScrollView>
+@end
View
34 lib/UIKit/NSScrollView+TUIExtensions.m
@@ -0,0 +1,34 @@
+//
+// NSScrollView+TUIExtensions.m
+// TwUI
+//
+// Created by Justin Spahr-Summers on 17.07.12.
+//
+// Portions of this code were taken from Velvet,
+// which is copyright (c) 2012 Bitswift, Inc.
+// See LICENSE.txt for more information.
+//
+
+#import "NSScrollView+TUIExtensions.h"
+#import "NSClipView+TUIExtensions.h"
+#import "NSView+TUIExtensions.h"
+
+@implementation NSScrollView (TUIExtensions)
+
+#pragma mark TUIBridgedView
+
+// implemented on NSView
+@dynamic layer;
+@dynamic hostView;
+
+#pragma mark TUIBridgedScrollView
+
+- (void)scrollToPoint:(CGPoint)point; {
+ [self.contentView scrollToPoint:point];
+}
+
+- (void)scrollToIncludeRect:(CGRect)rect; {
+ [self.contentView scrollToIncludeRect:rect];
+}
+
+@end
View
29 lib/UIKit/NSView+TUIExtensions.h
@@ -0,0 +1,29 @@
+//
+// NSView+TUIExtensions.h
+// TwUI
+//
+// Created by Justin Spahr-Summers on 17.07.12.
+//
+// Portions of this code were taken from Velvet,
+// which is copyright (c) 2012 Bitswift, Inc.
+// See LICENSE.txt for more information.
+//
+
+#import <AppKit/AppKit.h>
+#import "TUIBridgedView.h"
+#import "TUIHostView.h"
+
+@class TUIViewNSViewContainer;
+
+/**
+ * Implements <TUIBridgedView> for NSView.
+ */
+@interface NSView (TUIExtensions) <TUIBridgedView>
+
+/**
+ * The TUIViewNSViewContainer that is hosting this view, or nil if it exists
+ * independently of a TwUI hierarchy.
+ */
+@property (nonatomic, unsafe_unretained) TUIViewNSViewContainer<TUIHostView> *hostView;
+
+@end
View
127 lib/UIKit/NSView+TUIExtensions.m
@@ -0,0 +1,127 @@
+//
+// NSView+TUIExtensions.m
+// TwUI
+//
+// Created by Justin Spahr-Summers on 17.07.12.
+//
+// Portions of this code were taken from Velvet,
+// which is copyright (c) 2012 Bitswift, Inc.
+// See LICENSE.txt for more information.
+//
+
+#import "NSView+TUIExtensions.h"
+#import "TUINSView.h"
+#import "TUIBridgedScrollView.h"
+#import <objc/runtime.h>
+
+@implementation NSView (TUIExtensions)
+
+// NSView already implements a layer property
+@dynamic layer;
+
+#pragma mark View hierarchy
+
+- (id<TUIHostView>)hostView {
+ id<TUIHostView> hostView = objc_getAssociatedObject(self, @selector(hostView));
+ if (hostView)
+ return hostView;
+ else
+ return self.superview.hostView;
+}
+
+- (id<TUIBridgedView>)immediateParentView {
+ id<TUIHostView> hostView = objc_getAssociatedObject(self, @selector(hostView));
+ if (hostView)
+ return hostView;
+ else
+ return self.superview;
+}
+
+- (void)setHostView:(id<TUIHostView>)hostView {
+ objc_setAssociatedObject(self, @selector(hostView), hostView, OBJC_ASSOCIATION_ASSIGN);
+}
+
+- (void)ancestorDidLayout; {
+ [self.subviews makeObjectsPerformSelector:_cmd];
+}
+
+- (TUINSView *)ancestorTUINSView; {
+ NSView *view = self;
+
+ do {
+ if ([view isKindOfClass:[TUINSView class]])
+ return (id)view;
+
+ view = view.superview;
+ } while (view);
+
+ return nil;
+}
+
+- (id<TUIBridgedScrollView>)ancestorScrollView {
+ if ([self conformsToProtocol:@protocol(TUIBridgedScrollView)])
+ return (id)self;
+
+ return self.immediateParentView.ancestorScrollView;
+}
+
+#pragma mark Geometry
+
+- (CGPoint)convertFromWindowPoint:(CGPoint)point; {
+ NSPoint windowPoint = NSPointFromCGPoint(point);
+ NSPoint selfPoint = [self convertPoint:windowPoint fromView:nil];
+ return NSPointToCGPoint(selfPoint);
+}
+
+- (CGPoint)convertToWindowPoint:(CGPoint)point; {
+ NSPoint windowPoint = NSPointFromCGPoint(point);
+ NSPoint selfPoint = [self convertPoint:windowPoint toView:nil];
+ return NSPointToCGPoint(selfPoint);
+}
+
+- (CGRect)convertFromWindowRect:(CGRect)rect; {
+ NSRect windowRect = NSRectFromCGRect(rect);
+ NSRect selfRect = [self convertRect:windowRect fromView:nil];
+ return NSRectToCGRect(selfRect);
+}
+
+- (CGRect)convertToWindowRect:(CGRect)rect; {
+ NSRect windowRect = NSRectFromCGRect(rect);
+ NSRect selfRect = [self convertRect:windowRect toView:nil];
+ return NSRectToCGRect(selfRect);
+}
+
+#pragma mark Hit testing
+
+- (id<TUIBridgedView>)descendantViewAtPoint:(NSPoint)point {
+ NSPoint superviewPoint = [self convertPoint:point toView:self.superview];
+ id hitView = [self hitTest:superviewPoint];
+
+ if ([hitView isKindOfClass:[TUINSView class]]) {
+ NSPoint descendantPoint = [self convertPoint:point toView:hitView];
+ return [hitView descendantViewAtPoint:descendantPoint];
+ }
+
+ return hitView;
+}
+
+- (BOOL)pointInside:(CGPoint)point {
+ NSPoint superviewPoint = [self convertPoint:point toView:self.superview];
+ return [self hitTest:superviewPoint] ? YES : NO;
+}
+
+#pragma mark View hierarchy
+
+- (void)willMoveToTUINSView:(TUINSView *)view; {
+ [self.subviews makeObjectsPerformSelector:_cmd withObject:view];
+}
+
+- (void)didMoveFromTUINSView:(TUINSView *)view; {
+ [self.subviews makeObjectsPerformSelector:_cmd withObject:view];
+}
+
+- (void)viewHierarchyDidChange {
+ [self.subviews makeObjectsPerformSelector:_cmd];
+}
+
+@end
View
50 lib/UIKit/TUIBridgedScrollView.h
@@ -0,0 +1,50 @@
+//
+// TUIBridgedScrollView.h
+// TwUI
+//
+// Created by Justin Spahr-Summers on 17.07.12.
+//
+// Portions of this code were taken from Velvet,
+// which is copyright (c) 2012 Bitswift, Inc.
+// See LICENSE.txt for more information.
+//
+
+#import <Foundation/Foundation.h>
+#import "TUIBridgedView.h"
+
+/**
+ * Represents any kind of bridged scroll view.
+ */
+@protocol TUIBridgedScrollView <TUIBridgedView>
+@required
+
+/**
+ * @name Scrolling
+ */
+
+/**
+ * Scrolls the receiver such that the visible rectangle originates at the given
+ * point in the receiver's coordinate system. This method should enable any
+ * applicable animations.
+ *
+ * If scrolling to the given point would result in a rectangle extending past
+ * the scroll view's content, the behavior is unspecified; however, the
+ * resulting visible rectangle should still include the given point.
+ */
+- (void)scrollToPoint:(CGPoint)point;
+
+/**
+ * Scrolls the receiver the minimum distance required to ensure that the given
+ * rectangle is made visible. This method should enable any applicable
+ * animations.
+ *
+ * If the given rectangle is already visible in the scroll view, nothing
+ * happens. If the rectangle is larger than the size of the scroll view, as much
+ * of the rectangle as possible should be made visible; however, it is
+ * unspecified which part of the rectangle will be used.
+ *
+ * This method is named to avoid method signature conflicts with AppKit.
+ */
+- (void)scrollToIncludeRect:(CGRect)rect;
+
+@end
View
153 lib/UIKit/TUIBridgedView.h
@@ -0,0 +1,153 @@
+//
+// TUIBridgedView.h
+// TwUI
+//
+// Created by Justin Spahr-Summers on 17.07.12.
+//
+// Portions of this code were taken from Velvet,
+// which is copyright (c) 2012 Bitswift, Inc.
+// See LICENSE.txt for more information.
+//
+
+#import <Foundation/Foundation.h>
+
+@protocol TUIBridgedScrollView;
+@protocol TUIHostView;
+@class TUINSView;
+
+/**
+ * Represents a view that can be bridged by TwUI.
+ *
+ * Currently, only NSView and TUIView conform to this protocol.
+ */
+@protocol TUIBridgedView <NSObject>
+@required
+
+/**
+ * Converts a point from the coordinate system of the window to that of the
+ * receiver.
+ */
+- (CGPoint)convertFromWindowPoint:(CGPoint)point;
+
+/**
+ * Converts a point from the receiver's coordinate system to that of its window.
+ */
+- (CGPoint)convertToWindowPoint:(CGPoint)point;
+
+/**
+ * Converts a rectangle from the coordinate system of the window to that of the
+ * receiver.
+ */
+- (CGRect)convertFromWindowRect:(CGRect)rect;
+
+/**
+ * Converts a rectangle from the receiver's coordinate system to that of its window.
+ */
+- (CGRect)convertToWindowRect:(CGRect)rect;
+
+/**
+ * The layer backing the receiver.
+ *
+ * This property must never be nil.
+ */
+@property (nonatomic, strong, readonly) CALayer *layer;
+
+/**
+ * The view directly or indirectly hosting the receiver, or nil if the
+ * receiver is not part of a hosted view hierarchy.
+ *
+ * The receiver or one of its ancestors will be the [TUIHostView rootView] of
+ * this view.
+ *
+ * Implementing classes may require that this property be of a more specific
+ * type.
+ *
+ * This property should not be set except by the TUIHostView itself.
+ */
+@property (nonatomic, unsafe_unretained) id<TUIHostView> hostView;
+
+/**
+ * Returns the receiver's hostView or superview, whichever is closer in the
+ * hierarchy.
+ */
+- (id<TUIBridgedView>)immediateParentView;
+
+/**
+ * Invoked any time an ancestor of the receiver has relaid itself out,
+ * potentially moving or clipping the receiver relative to one of its ancestor
+ * views.
+ *
+ * The receiver _must_ forward this message to all of its subviews and any
+ * [TUIHostView rootView].
+ */
+- (void)ancestorDidLayout;
+
+/**
+ * Invoked any time the receiver has changed absolute positions in the view
+ * hierarchy.
+ *
+ * This will include, for example, any time the receiver or one of its ancestors
+ * changes superviews, changes host views, is reordered within its superview,
+ * etc.
+ *
+ * The receiver _must_ forward this message to all of its subviews and any
+ * [TUIHostView rootView].
+ */
+- (void)viewHierarchyDidChange;
+
+/**
+ * Returns the nearest <TUINSView> that is an ancestor of the receiver, or of
+ * a view hosting the receiver.
+ *
+ * Returns nil if the receiver is not part of a TwUI-hosted view hierarchy.
+ */
+- (TUINSView *)ancestorTUINSView;
+
+/**
+ * Walks up the receiver's ancestor views, returning the nearest
+ * <TUIBridgedScrollView>.
+ *
+ * Returns nil if no scroll view is an ancestor of the receiver.
+ */
+- (id<TUIBridgedScrollView>)ancestorScrollView;
+
+/**
+ * Invoked when the receiver is moving to a new <ancestorTUINSView>.
+ *
+ * 'view' will be nil if the receiver is being detached from its current
+ * <ancestorTUINSView>.
+ *
+ * The receiver _must_ forward this message to all of its subviews and any
+ * [TUIHostView rootView].
+ */
+- (void)willMoveToTUINSView:(TUINSView *)view;
+
+/**
+ * Invoked when the receiver has moved to a new <ancestorTUINSView>.
+ *
+ * 'view' will be nil if the receiver was previously not hosted.
+ *
+ * The receiver _must_ forward this message to all of its subviews and any
+ * [TUIHostView rootView].
+ */
+- (void)didMoveFromTUINSView:(TUINSView *)view;
+
+/**
+ * Hit tests the receiver's view hierarchy, returning the <TUIBridgedView> which
+ * is occupying the given point, or nil if there is no such view.
+ *
+ * This method should only traverse views which are visible and allow user
+ * interaction.
+ *
+ * 'point' should be specified in the coordinate system of the receiver.
+ */
+- (id<TUIBridgedView>)descendantViewAtPoint:(CGPoint)point;
+
+/**
+ * Returns whether the receiver is occupying the given point.
+ *
+ * 'point' should be specified in the coordinate system of the receiver.
+ */
+- (BOOL)pointInside:(CGPoint)point;
+
+@end
View
33 lib/UIKit/TUIHostView.h
@@ -0,0 +1,33 @@
+//
+// TUIHostView.h
+// TwUI
+//
+// Created by Justin Spahr-Summers on 17.07.12.
+//
+// Portions of this code were taken from Velvet,
+// which is copyright (c) 2012 Bitswift, Inc.
+// See LICENSE.txt for more information.
+//
+
+#import <Foundation/Foundation.h>
+#import "TUIBridgedView.h"
+
+/**
+ * Represents a view that can host views of other types (i.e., can bridge across
+ * UI frameworks).
+ */
+@protocol TUIHostView <TUIBridgedView>
+@required
+
+/**
+ * The view hosted by the receiver.
+ *
+ * Implementing classes may require that this property be of a more specific
+ * type.
+ *
+ * When this property is set, the given view's [TUIBridgedView hostView]
+ * property should automatically be set to the receiver.
+ */
+@property (nonatomic, strong) id<TUIBridgedView> rootView;
+
+@end
View
51 lib/UIKit/TUIKit.h
@@ -16,35 +16,44 @@
#import <Foundation/Foundation.h>
-#import "TUIResponder.h"
-#import "TUIFont.h"
+#import "CAAnimation+TUIExtensions.h"
+#import "CoreText+Additions.h"
+#import "NSClipView+TUIExtensions.h"
+#import "NSScrollView+TUIExtensions.h"
+#import "NSView+TUIExtensions.h"
+#import "TUIActivityIndicatorView.h"
+#import "TUIAttributedString.h"
+#import "TUIBridgedScrollView.h"
+#import "TUIBridgedView.h"
+#import "TUIButton.h"
+#import "TUICGAdditions.h"
#import "TUIColor.h"
-#import "TUIImage.h"
-#import "TUIView.h"
-#import "TUIScrollView.h"
#import "TUIFastIndexPath.h"
-#import "TUITableView.h"
-#import "TUITableView+Additions.h"
-#import "TUITableViewCell.h"
-#import "TUITableViewSectionHeader.h"
-#import "TUILabel.h"
+#import "TUIFont.h"
+#import "TUIHostView.h"
+#import "TUIImage.h"
#import "TUIImageView.h"
-#import "TUIButton.h"
-#import "TUITextView.h"
-#import "TUITextField.h"
-#import "TUIAttributedString.h"
-#import "TUIActivityIndicatorView.h"
+#import "TUILabel.h"
#import "TUINSView.h"
#import "TUINSWindow.h"
-#import "TUIStringDrawing.h"
-#import "TUIViewController.h"
-#import "TUICGAdditions.h"
-#import "CoreText+Additions.h"
-#import "TUITextEditor.h"
#import "TUIPopover.h"
#import "TUIProgressBar.h"
-#import "CAAnimation+TUIExtensions.h"
+#import "TUIResponder.h"
+#import "TUIScrollView.h"
+#import "TUIScrollView+TUIBridgedScrollView.h"
+#import "TUIStringDrawing.h"
#import "TUIStyledView.h"
+#import "TUITableView+Additions.h"
+#import "TUITableView.h"
+#import "TUITableViewCell.h"
+#import "TUITableViewSectionHeader.h"
+#import "TUITextEditor.h"
+#import "TUITextField.h"
+#import "TUITextView.h"
+#import "TUIView.h"
+#import "TUIView+TUIBridgedView.h"
+#import "TUIViewController.h"
+#import "TUIViewNSViewContainer.h"
extern CGContextRef TUIGraphicsGetCurrentContext(void);
extern void TUIGraphicsPushContext(CGContextRef context);
View
24 lib/UIKit/TUINSHostView.h
@@ -0,0 +1,24 @@
+//
+// TUINSHostView.h
+// TwUI
+//
+// Created by Justin Spahr-Summers on 17.07.12.
+//
+// Portions of this code were taken from Velvet,
+// which is copyright (c) 2012 Bitswift, Inc.
+// See LICENSE.txt for more information.
+//
+
+#import <Cocoa/Cocoa.h>
+
+@class TUINSView;
+
+/*
+ * Private layer-hosted view class, containing the whole TwUI view hierarchy.
+ * This class needs to be a subview of an TUINSView, because the latter is
+ * layer-backed (not layer-hosted), in order to support a separate NSView
+ * hierarchy.
+ */
+@interface TUINSHostView : NSView
+- (TUINSView *)superview;
+@end
View
69 lib/UIKit/TUINSHostView.m
@@ -0,0 +1,69 @@
+//
+// TUINSHostView.m
+// TwUI
+//
+// Created by Justin Spahr-Summers on 17.07.12.
+//
+// Portions of this code were taken from Velvet,
+// which is copyright (c) 2012 Bitswift, Inc.
+// See LICENSE.txt for more information.
+//
+
+#import "TUINSHostView.h"
+
+@interface TUINSHostView ()
+/*
+ * Configures all the necessary properties on the receiver. This is outside of
+ * an initializer because NSView has no true designated initializer.
+ */
+- (void)setUp;
+@end
+
+@implementation TUINSHostView
+
+#pragma mark Properties
+
+- (TUINSView *)superview {
+ return (TUINSView *)[super superview];
+}
+
+#pragma mark Lifecycle
+
+- (id)initWithCoder:(NSCoder *)coder {
+ self = [super initWithCoder:coder];
+ if (!self)
+ return nil;
+
+ [self setUp];
+ return self;
+}
+
+- (id)initWithFrame:(NSRect)frame; {
+ self = [super initWithFrame:frame];
+ if (!self)
+ return nil;
+
+ [self setUp];
+ return self;
+}
+
+- (void)setUp; {
+ // set up layer hosting
+ self.layer = [CALayer layer];
+ self.wantsLayer = YES;
+}
+
+#pragma mark Rendering
+
+- (BOOL)needsDisplay {
+ // mark this view as needing display anytime the layer is
+ return [super needsDisplay] || [self.layer needsDisplay];
+}
+
+#pragma mark Event Handling
+
+- (NSView *)hitTest:(NSPoint)point {
+ return nil;
+}
+
+@end
View
2 lib/UIKit/TUINSView+Accessibility.m
@@ -16,7 +16,7 @@ - (id)accessibilityHitTest:(NSPoint)point
{
NSPoint windowPoint = [[self window] convertScreenToBase:point];
NSPoint localPoint = [self convertPoint:windowPoint fromView:nil];
- return [rootView accessibilityHitTest:localPoint];
+ return [self.rootView accessibilityHitTest:localPoint];
}
- (BOOL)accessibilityIsIgnored
View
8 lib/UIKit/TUINSView+Hyperfocus.m
@@ -43,10 +43,10 @@ - (void)hyperFocus:(TUIView *)focusView completion:(void(^)(BOOL))completion
CGRect focusRect = [focusView frameInNSView];
CGFloat startRadius = 1.0;
- CGFloat endRadius = MAX(rootView.bounds.size.width, rootView.bounds.size.height);
+ CGFloat endRadius = MAX(self.rootView.bounds.size.width, self.rootView.bounds.size.height);
CGPoint center = CGPointMake(focusRect.origin.x + focusRect.size.width * 0.5, focusRect.origin.y + focusRect.size.height * 0.5);
- TUIView *fade = [[TUIView alloc] initWithFrame:rootView.bounds];
+ TUIView *fade = [[TUIView alloc] initWithFrame:self.rootView.bounds];
fade.userInteractionEnabled = NO;
fade.autoresizingMask = TUIViewAutoresizingFlexibleSize;
fade.opaque = NO;
@@ -64,7 +64,7 @@ - (void)hyperFocus:(TUIView *)focusView completion:(void(^)(BOOL))completion
CGGradientRef gradient = CGGradientCreateWithColorComponents(space, components, locations, 3);
// CGContextSaveGState(ctx);
-// CGContextClipToRoundRect(ctx, rootView.bounds, 9);
+// CGContextClipToRoundRect(ctx, self.rootView.bounds, 9);
CGContextDrawRadialGradient(ctx, gradient, center, startRadius, center, endRadius, kCGGradientDrawsBeforeStartLocation | kCGGradientDrawsAfterEndLocation);
// CGContextRestoreGState(ctx);
@@ -74,7 +74,7 @@ - (void)hyperFocus:(TUIView *)focusView completion:(void(^)(BOOL))completion
[CATransaction begin];
fade.alpha = 0.0;
- [rootView addSubview:fade];
+ [self.rootView addSubview:fade];
[CATransaction flush];
[CATransaction commit];
View
37 lib/UIKit/TUINSView+Private.h
@@ -0,0 +1,37 @@
+//
+// TUINSView+Private.h
+// TwUI
+//
+// Created by Justin Spahr-Summers on 17.07.12.
+//
+// Portions of this code were taken from Velvet,
+// which is copyright (c) 2012 Bitswift, Inc.
+// See LICENSE.txt for more information.
+//
+
+#import "TUINSView.h"
+
+/*
+ * Private functionality of TUINSView that needs to be exposed to other parts of
+ * the framework.
+ */
+@interface TUINSView ()
+
+/*
+ * The layer-backed view which actually holds the AppKit hierarchy.
+ */
+@property (nonatomic, readonly, strong) NSView *appKitHostView;
+
+/*
+ * Informs the receiver that the clipping of a TUIViewNSViewContainer it is hosting has
+ * changed, and asks it to update clipping paths accordingly.
+ */
+- (void)recalculateNSViewClipping;
+
+/*
+ * Informs the receiver that the ordering of a TUIViewNSViewContainer it is hosting has
+ * changed, and asks it to reorder its subviews to match TwUI.
+ */
+- (void)recalculateNSViewOrdering;
+
+@end
View
4 lib/UIKit/TUINSView.h
@@ -15,14 +15,14 @@
*/
#import <Cocoa/Cocoa.h>
+#import "TUIView+TUIBridgedView.h"
#import "TUIKit.h"
/**
TUINSView is the bridge that hosts a TUIView-based interface heirarchy. You may add it as the contentView of your window if you want to build a pure TwUI-based UI, or you can use it for a small part.
*/
-@interface TUINSView : NSView <NSTextInputClient>
+@interface TUINSView : NSView <NSTextInputClient, TUIHostView>
{
- TUIView *rootView;
TUIView *_hoverView;
__unsafe_unretained TUIView *_trackingView; // dragging view, weak
View
361 lib/UIKit/TUINSView.m
@@ -14,13 +14,95 @@
limitations under the License.
*/
+// Portions of this code were taken from Velvet,
+// which is copyright (c) 2012 Bitswift, Inc.
+// See LICENSE.txt for more information.
+
#import "TUINSView.h"
+#import "CALayer+TUIExtensions.h"
+#import "TUIBridgedScrollView.h"
+#import "TUINSHostView.h"
+#import "TUINSView+Private.h"
+#import "TUIViewNSViewContainer.h"
#import "TUIView+Private.h"
+#import "TUIView+TUIBridgedView.h"
#import "TUITextRenderer+Event.h"
#import "TUITooltipWindow.h"
#import <CoreFoundation/CoreFoundation.h>
+static NSComparisonResult compareNSViewOrdering (NSView *viewA, NSView *viewB, void *context) {
+ TUIViewNSViewContainer *hostA = viewA.hostView;
+ TUIViewNSViewContainer *hostB = viewB.hostView;
+
+ // hosted NSViews should be on top of everything else
+ if (!hostA) {
+ if (!hostB) {
+ return NSOrderedSame;
+ } else {
+ return NSOrderedAscending;
+ }
+ } else if (!hostB) {
+ return NSOrderedDescending;
+ }
+
+ TUIView *ancestor = [hostA ancestorSharedWithView:(TUIView *)hostB];
+ NSCAssert2(ancestor, @"TwUI-hosted NSViews in the same TUINSView should share a TwUI ancestor: %@, %@", viewA, viewB);
+
+ __block NSInteger orderA = -1;
+ __block NSInteger orderB = -1;
+
+ [ancestor.subviews enumerateObjectsUsingBlock:^(TUIView *subview, NSUInteger index, BOOL *stop){
+ if ([hostA isDescendantOfView:subview]) {
+ orderA = (NSInteger)index;
+ } else if ([hostB isDescendantOfView:subview]) {
+ orderB = (NSInteger)index;
+ }
+
+ if (orderA >= 0 && orderB >= 0) {
+ *stop = YES;
+ }
+ }];
+
+ if (orderA < orderB) {
+ return NSOrderedAscending;
+ } else if (orderA > orderB) {
+ return NSOrderedDescending;
+ } else {
+ return NSOrderedSame;
+ }
+}
+
@interface TUINSView ()
+
+/*
+ * The layer-hosted view which actually holds the TwUI hierarchy.
+ */
+@property (nonatomic, readonly, strong) TUINSHostView *tuiHostView;
+
+- (void)recalculateNSViewClipping;
+- (void)recalculateNSViewOrdering;
+
+/*
+ * A layer used to mask the rendering of NSView-owned layers added to the
+ * receiver.
+ *
+ * This masking will keep the rendering of a given NSView consistent with the
+ * clipping its TUIViewNSViewContainer would have in the TwUI hierarchy.
+ */
+@property (nonatomic, strong) CAShapeLayer *maskLayer;
+
+/*
+ * Returns any existing AppKit-created focus ring layer for the given view, or
+ * nil if one could not be found.
+ */
+- (CALayer *)focusRingLayerForView:(NSView *)view;
+
+/*
+ * Configures all the necessary properties on the receiver. This is outside of
+ * an initializer because NSView has no true designated initializer.
+ */
+- (void)setUp;
+
- (void)windowDidResignKey:(NSNotification *)notification;
- (void)windowDidBecomeKey:(NSNotification *)notification;
- (void)screenProfileOrBackingPropertiesDidChange:(NSNotification *)notification;
@@ -29,25 +111,41 @@ - (void)screenProfileOrBackingPropertiesDidChange:(NSNotification *)notification
@implementation TUINSView
-@synthesize rootView;
+// implemented by TUIView
+@dynamic layer;
+
+// these cannot be implicitly synthesized because they're from protocols/categories
+@synthesize hostView = _hostView;
+@synthesize appKitHostView = _appKitHostView;
+
+- (id)initWithCoder:(NSCoder *)coder
+{
+ self = [super initWithCoder:coder];
+ if (self == nil)
+ return nil;
+
+ [self setUp];
+ return self;
+}
- (id)initWithFrame:(NSRect)frameRect
{
- if((self = [super initWithFrame:frameRect])) {
- opaque = YES;
- }
+ self = [super initWithFrame:frameRect];
+ if (self == nil)
+ return nil;
+
+ [self setUp];
return self;
}
- (void)dealloc
{
- [[NSNotificationCenter defaultCenter] removeObserver:self name:NSWindowDidResignKeyNotification object:nil];
- [[NSNotificationCenter defaultCenter] removeObserver:self name:NSWindowDidBecomeKeyNotification object:nil];
+ [[NSNotificationCenter defaultCenter] removeObserver:self];
- rootView.nsView = nil;
- [rootView removeFromSuperview];
+ _rootView.nsView = nil;
+ [_rootView removeFromSuperview];
- rootView = nil;
+ _rootView = nil;
_hoverView = nil;
_trackingView = nil;
_trackingArea = nil;
@@ -99,7 +197,7 @@ - (void)viewWillStartLiveResize
{
[super viewWillStartLiveResize];
inLiveResize = YES;
- [rootView viewWillStartLiveResize];
+ [_rootView viewWillStartLiveResize];
}
- (BOOL)inLiveResize
@@ -111,7 +209,7 @@ - (void)viewDidEndLiveResize
{
[super viewDidEndLiveResize];
inLiveResize = NO;
- [rootView viewDidEndLiveResize]; // will send to all subviews
+ [_rootView viewDidEndLiveResize]; // will send to all subviews
if([[self window] respondsToSelector:@selector(ensureWindowRectIsOnScreen)])
[[self window] performSelector:@selector(ensureWindowRectIsOnScreen)];
@@ -121,19 +219,17 @@ - (void)setRootView:(TUIView *)v
{
v.autoresizingMask = TUIViewAutoresizingFlexibleSize;
- rootView.nsView = nil;
- rootView = v;
- rootView.nsView = self;
+ _rootView.nsView = nil;
+ _rootView.hostView = nil;
+ _rootView = v;
+ _rootView.nsView = self;
+ _rootView.hostView = self;
- [rootView setNextResponder:self];
+ [_rootView setNextResponder:self];
CGSize s = [self frame].size;
v.frame = CGRectMake(0, 0, s.width, s.height);
-
- [self setWantsLayer:YES];
- CALayer *layer = [self layer];
- [layer setDelegate:self];
- [layer addSublayer:rootView.layer];
+ [self.tuiHostView.layer addSublayer:_rootView.layer];
[self _updateLayerScaleFactor];
}
@@ -156,15 +252,16 @@ - (void)viewWillMoveToWindow:(NSWindow *)newWindow {
[[NSNotificationCenter defaultCenter] removeObserver:self name:NSWindowDidChangeScreenProfileNotification object:self.window];
}
- if(newWindow != nil && rootView.layer.superlayer != [self layer]) {
- rootView.layer.frame = self.layer.bounds;
- [[self layer] addSublayer:rootView.layer];
+ CALayer *hostLayer = self.tuiHostView.layer;
+ if(newWindow != nil && _rootView.layer.superlayer != hostLayer) {
+ _rootView.layer.frame = hostLayer.bounds;
+ [hostLayer addSublayer:_rootView.layer];
}
[self.rootView willMoveToWindow:(TUINSWindow *) newWindow];
if(newWindow == nil) {
- [rootView removeFromSuperview];
+ [_rootView removeFromSuperview];
}
}
@@ -191,9 +288,9 @@ - (void)_updateLayerScaleFactor {
scale = [[self window] backingScaleFactor];
}
- if([self.layer respondsToSelector:@selector(setContentsScale:)]) {
- if(fabs(self.layer.contentsScale - scale) > 0.1f) {
- self.layer.contentsScale = scale;
+ if([self.tuiHostView.layer respondsToSelector:@selector(setContentsScale:)]) {
+ if(fabs(self.tuiHostView.layer.contentsScale - scale) > 0.1f) {
+ self.tuiHostView.layer.contentsScale = scale;
}
}
@@ -208,7 +305,7 @@ - (void)screenProfileOrBackingPropertiesDidChange:(NSNotification *)notification
- (TUIView *)viewForLocalPoint:(NSPoint)p
{
- return [rootView hitTest:p withEvent:nil];
+ return [_rootView hitTest:p withEvent:nil];
}
- (NSPoint)localPointForLocationInWindow:(NSPoint)locationInWindow
@@ -435,12 +532,12 @@ - (void)keyDown:(NSEvent *)event
- (BOOL)performKeyEquivalent:(NSEvent *)event
{
- return [rootView performKeyEquivalent:event];
+ return [_rootView performKeyEquivalent:event];
}
- (void)setEverythingNeedsDisplay
{
- [rootView setEverythingNeedsDisplay];
+ [_rootView setEverythingNeedsDisplay];
}
- (BOOL)isTrackingSubviewOfView:(TUIView *)v
@@ -523,8 +620,212 @@ - (NSMenu *)menuForEvent:(NSEvent *)event
return nil;
}
+- (void)setUp {
+ opaque = YES;
+
+ _maskLayer = [CAShapeLayer layer];
+
+ // enable layer-backing for this view
+ self.wantsLayer = YES;
+ self.layerContentsRedrawPolicy = NSViewLayerContentsRedrawNever;
+
+ _tuiHostView = [[TUINSHostView alloc] initWithFrame:self.bounds];
+ _tuiHostView.autoresizingMask = NSViewWidthSizable | NSViewHeightSizable;
+ [self addSubview:_tuiHostView];
+
+ _appKitHostView = [[NSView alloc] initWithFrame:self.bounds];
+ _appKitHostView.autoresizesSubviews = NO;
+ _appKitHostView.autoresizingMask = NSViewWidthSizable | NSViewHeightSizable;
+ _appKitHostView.wantsLayer = YES;
+ _appKitHostView.layerContentsRedrawPolicy = NSViewLayerContentsRedrawNever;
+ [self addSubview:_appKitHostView];
+
+ // set up masking on the AppKit host view, and make ourselves the layout
+ // manager, so that we'll know when new sublayers are added
+ self.appKitHostView.layer.mask = self.maskLayer;
+ self.appKitHostView.layer.layoutManager = self;
+ [self recalculateNSViewClipping];
+}
+
+- (void)didAddSubview:(NSView *)view {
+ NSAssert(view == self.tuiHostView || view == self.appKitHostView, @"Subviews should not be added to TUINSView %@: %@", self, view);
+ [super didAddSubview:view];
+}
+
#define ENABLE_NSTEXT_INPUT_CLIENT
#import "TUINSView+NSTextInputClient.m"
#undef ENABLE_NSTEXT_INPUT_CLIENT
+#pragma mark AppKit bridging
+
+- (NSView *)hitTest:(NSPoint)point {
+ // convert point into our coordinate system, so it's ready to go for all
+ // subviews (which expect it in their superview's coordinate system)
+ point = [self convertPoint:point fromView:self.superview];
+
+ if (!CGRectContainsPoint(self.bounds, point))
+ return nil;
+
+ __block NSView *result = self;
+
+ // we need to avoid hitting any NSViews that are clipped by their
+ // corresponding TwUI views
+ [self.appKitHostView.subviews enumerateObjectsWithOptions:NSEnumerationReverse usingBlock:^(NSView *view, NSUInteger index, BOOL *stop){
+ id<TUIBridgedView> hostView = view.hostView;
+ if (hostView) {