From d42e861b48d267ba6da5345ff971aae2c81b6e98 Mon Sep 17 00:00:00 2001 From: joshaber Date: Sat, 28 Mar 2015 22:24:52 -0400 Subject: [PATCH 01/13] What if we don't have a view? --- Few-Mac/Mac.swift | 4 ++-- Few-Mac/ScrollView.swift | 2 +- Few-Mac/TableView.swift | 14 ++++++------ FewCore/Component.swift | 15 ++++++++----- FewCore/Element.swift | 28 ++++++++++++++---------- FewCore/RealizedElement.swift | 41 +++++++++++++++++++++++++++++++---- 6 files changed, 73 insertions(+), 31 deletions(-) diff --git a/Few-Mac/Mac.swift b/Few-Mac/Mac.swift index 67459a5..a82813b 100644 --- a/Few-Mac/Mac.swift +++ b/Few-Mac/Mac.swift @@ -21,6 +21,6 @@ internal func markNeedsDisplay(view: ViewType) { view.needsDisplay = true } -internal func configureViewToAutoresize(view: ViewType) { - view.autoresizingMask = .ViewWidthSizable | .ViewHeightSizable +internal func configureViewToAutoresize(view: ViewType?) { + view?.autoresizingMask = .ViewWidthSizable | .ViewHeightSizable } diff --git a/Few-Mac/ScrollView.swift b/Few-Mac/ScrollView.swift index fa1f7a5..0e8cff8 100644 --- a/Few-Mac/ScrollView.swift +++ b/Few-Mac/ScrollView.swift @@ -64,7 +64,7 @@ private class ScrollViewElement: Element { return view } - private override func addRealizedChildView(childView: ViewType, selfView: ViewType) { + private override func addRealizedChildView(childView: ViewType?, selfView: ViewType?) { let scrollVew = selfView as FewScrollView scrollVew.scrollView.documentView = childView } diff --git a/Few-Mac/TableView.swift b/Few-Mac/TableView.swift index a49c9f0..9947828 100644 --- a/Few-Mac/TableView.swift +++ b/Few-Mac/TableView.swift @@ -22,18 +22,18 @@ private class FewListCell: NSTableCellView { element.applyDiff(realizedElement.element, realizedSelf: realizedElement) } else { realizedElement.element.derealize() - realizedElement.view.removeFromSuperview() + realizedElement.view?.removeFromSuperview() let newRealizedElement = element.realize() - newRealizedElement.view.autoresizingMask = .ViewWidthSizable | .ViewHeightSizable - newRealizedElement.view.frame = bounds - addSubview(newRealizedElement.view) + newRealizedElement.view?.autoresizingMask = .ViewWidthSizable | .ViewHeightSizable + newRealizedElement.view?.frame = bounds + addSubview <^> newRealizedElement.view } } else { let newRealizedElement = element.realize() - newRealizedElement.view.autoresizingMask = .ViewWidthSizable | .ViewHeightSizable - newRealizedElement.view.frame = bounds - addSubview(newRealizedElement.view) + newRealizedElement.view?.autoresizingMask = .ViewWidthSizable | .ViewHeightSizable + newRealizedElement.view?.frame = bounds + addSubview <^> newRealizedElement.view realizedElement = newRealizedElement } diff --git a/FewCore/Component.swift b/FewCore/Component.swift index 997a304..cb61af5 100644 --- a/FewCore/Component.swift +++ b/FewCore/Component.swift @@ -84,7 +84,7 @@ public class Component: Element { configureViewToAutoresize(realized.view) - realizedRoot?.view.removeFromSuperview() + realizedRoot?.view?.removeFromSuperview() realizedRoot = realized } @@ -112,11 +112,11 @@ public class Component: Element { if newRoot.canDiff(rootElement) { newRoot.applyDiff(rootElement, realizedSelf: realizedRoot) } else { - let superview = realizedRoot!.view.superview! + let superview = realizedRoot!.view!.superview! rootElement.derealize() realizeNewRoot(newRoot) - superview.addSubview(realizedRoot!.view) + superview.addSubview(realizedRoot!.view!) newRoot.elementDidRealize(realizedRoot!) } @@ -171,12 +171,15 @@ public class Component: Element { frame = hostView.bounds performInitialRenderIfNeeded() realizeRootIfNeeded() - hostView.addSubview(realizedRoot!.view) + + assert(realizedRoot!.view != nil, "\(self) doesn't realize to a view!") + hostView.addSubview(realizedRoot!.view!) + rootElement?.elementDidRealize(realizedRoot!) #if os(OSX) hostView.postsFrameChangedNotifications = true - realizedRoot!.view.autoresizesSubviews = false + realizedRoot!.view?.autoresizesSubviews = false frameChangedTrampoline.action = { [weak self] in if let strongSelf = self { @@ -312,7 +315,7 @@ public class Component: Element { rootElement?.derealize() rootElement = nil - realizedRoot?.view.removeFromSuperview() + realizedRoot?.view?.removeFromSuperview() realizedRoot = nil componentDidDerealize() diff --git a/FewCore/Element.swift b/FewCore/Element.swift index e44f01a..032ed8d 100644 --- a/FewCore/Element.swift +++ b/FewCore/Element.swift @@ -34,17 +34,19 @@ public class Element { // On OS X we have to reverse our children since the default coordinate // system is flipped. -#if os(OSX) public var children: [Element] { didSet { +#if os(OSX) if direction == .Column { children = children.reverse() } +#endif + + for child in children { + child.parent = self + } } } -#else - public var children: [Element] -#endif #if os(OSX) public var direction: Direction { @@ -69,6 +71,8 @@ public class Element { /// Should the input make itself the focus after it's been realized? public var autofocus: Bool + public weak var parent: Element? + public init(frame: CGRect = CGRect(x: 0, y: 0, width: Node.Undefined, height: Node.Undefined), key: String? = nil, hidden: Bool = false, alpha: CGFloat = 1, autofocus: Bool = false, children: [Element] = [], direction: Direction = .Row, margin: Edges = Edges(), padding: Edges = Edges(), wrap: Bool = false, justification: Justification = .FlexStart, selfAlignment: SelfAlignment = .Auto, childAlignment: ChildAlignment = .Stretch, flex: CGFloat = 0) { self.frame = frame self.key = key @@ -165,14 +169,14 @@ public class Element { println() } - public func createView() -> ViewType { - return ViewType(frame: frame) + public func createView() -> ViewType? { + return nil } /// Realize the element. internal func realize() -> RealizedElement { let view = createView() - view.frame = frame.integerRect + view?.frame = frame.integerRect let realizedSelf = RealizedElement(element: self, view: view) let realizedChildren = children.map { $0.realize() } @@ -183,8 +187,10 @@ public class Element { return realizedSelf } - internal func addRealizedChildView(childView: ViewType, selfView: ViewType) { - selfView.addSubview(childView) + internal func addRealizedChildView(childView: ViewType?, selfView: ViewType?) { + if let childView = childView { + selfView?.addSubview(childView) + } } /// Derealize the element. @@ -240,9 +246,9 @@ public class Element { } if autofocus { - let window = realizedSelf.view.window! + let window = realizedSelf.view?.window! #if os(OSX) - window.makeFirstResponder(realizedSelf.view) + window?.makeFirstResponder(realizedSelf.view) #else realizedSelf.view.becomeFirstResponder() #endif diff --git a/FewCore/RealizedElement.swift b/FewCore/RealizedElement.swift index 59f345e..0a0325d 100644 --- a/FewCore/RealizedElement.swift +++ b/FewCore/RealizedElement.swift @@ -21,29 +21,62 @@ internal func indexOfObject(array: [T], element: T) -> Int? { public class RealizedElement { public var element: Element - public let view: ViewType + public let view: ViewType? + public weak var parent: RealizedElement? internal var children: [RealizedElement] = [] - public init(element: Element, view: ViewType) { + public init(element: Element, view: ViewType?) { self.element = element self.view = view } public func addRealizedChild(child: RealizedElement, index: Int?) { + child.parent = self + if let index = index { children.insert(child, atIndex: index) } else { children.append(child) } - element.addRealizedChildView(child.view, selfView: view) + var hostView = view + if hostView == nil { + hostView = findParentWithView()?.view + if let childView = child.view { + child.view?.frame = frameRelativeToParent(self, frame: childView.frame) + } + } + + element.addRealizedChildView(child.view, selfView: hostView) } public func removeRealizedChild(child: RealizedElement) { - child.view.removeFromSuperview() + child.parent = nil + child.view?.removeFromSuperview() if let index = indexOfObject(children, child) { children.removeAtIndex(index) } } + + public func findParentWithView() -> RealizedElement? { + var currentParent = parent + while currentParent != nil { + if currentParent?.view != nil { return currentParent } + currentParent = currentParent?.parent + } + + return nil + } + + public func frameRelativeToParent(destinationParent: RealizedElement, frame: CGRect) -> CGRect { + var currentParent = parent + var translatedFrame = frame + while currentParent !== destinationParent { + translatedFrame.origin.x += currentParent?.element.frame.origin.x ?? 0 + translatedFrame.origin.y += currentParent?.element.frame.origin.y ?? 0 + } + + return translatedFrame + } } From e103da51cb928b8a6cfd3350e4c22663243a5ab4 Mon Sep 17 00:00:00 2001 From: joshaber Date: Tue, 14 Apr 2015 20:49:19 -0400 Subject: [PATCH 02/13] Yeah but what if we don't have views. --- Few-Mac/QuickLook.swift | 2 +- Few-Mac/ScrollView.swift | 16 +++++++--- Few-Mac/TableView.swift | 4 +-- Few-iOS/ScrollView.swift | 18 +++++++---- Few-iOS/TableView.swift | 10 +++--- Few-iOS/iOS.swift | 4 +-- FewCore/Component.swift | 47 +++++++++++++++++++++------ FewCore/Element.swift | 45 ++++++++++++-------------- FewCore/RealizedElement.swift | 51 ++++++++++++------------------ FewDemo/AppDelegate.swift | 2 +- FewDemo/Demo.swift | 8 ++--- FewDemo/TemperatureConverter.swift | 4 +-- 12 files changed, 119 insertions(+), 92 deletions(-) diff --git a/Few-Mac/QuickLook.swift b/Few-Mac/QuickLook.swift index b703537..c7c3c05 100644 --- a/Few-Mac/QuickLook.swift +++ b/Few-Mac/QuickLook.swift @@ -10,7 +10,7 @@ import Foundation extension Element { public func debugQuickLookObject() -> AnyObject? { - let realizedSelf = realize() + let realizedSelf = realize(nil) return realizedSelf.view } diff --git a/Few-Mac/ScrollView.swift b/Few-Mac/ScrollView.swift index ecc0ac2..9d13dfd 100644 --- a/Few-Mac/ScrollView.swift +++ b/Few-Mac/ScrollView.swift @@ -48,6 +48,13 @@ private class FewScrollView: NSView { } } +private class RealizedScrollViewElement: RealizedElement { + private override func addRealizedViewForChild(child: RealizedElement) { + let scrollVew = view as! FewScrollView + scrollVew.scrollView.documentView = child.view + } +} + private class ScrollViewElement: Element { private let didScroll: CGRect -> () @@ -64,13 +71,12 @@ private class ScrollViewElement: Element { return view } - private override func addRealizedChildView(childView: ViewType?, selfView: ViewType?) { - let scrollVew = selfView as! FewScrollView - scrollVew.scrollView.documentView = childView + private override func createRealizedElement(view: ViewType?) -> RealizedElement { + return RealizedScrollViewElement(element: self, view: view) } - private override func realize() -> RealizedElement { - let realizedElement = super.realize() + private override func realize(parent: RealizedElement?) -> RealizedElement { + let realizedElement = super.realize(parent) let scrollView = realizedElement.view as! FewScrollView let documentView = scrollView.scrollView.documentView as! NSView diff --git a/Few-Mac/TableView.swift b/Few-Mac/TableView.swift index a54ead8..06012e8 100644 --- a/Few-Mac/TableView.swift +++ b/Few-Mac/TableView.swift @@ -24,13 +24,13 @@ private class FewListCell: NSTableCellView { realizedElement.element.derealize() realizedElement.view?.removeFromSuperview() - let newRealizedElement = element.realize() + let newRealizedElement = element.realize(nil) newRealizedElement.view?.autoresizingMask = .ViewWidthSizable | .ViewHeightSizable newRealizedElement.view?.frame = bounds addSubview <^> newRealizedElement.view } } else { - let newRealizedElement = element.realize() + let newRealizedElement = element.realize(nil) newRealizedElement.view?.autoresizingMask = .ViewWidthSizable | .ViewHeightSizable newRealizedElement.view?.frame = bounds addSubview <^> newRealizedElement.view diff --git a/Few-iOS/ScrollView.swift b/Few-iOS/ScrollView.swift index e783b92..9cdfcf6 100644 --- a/Few-iOS/ScrollView.swift +++ b/Few-iOS/ScrollView.swift @@ -29,6 +29,14 @@ private class FewScrollView: UIScrollView, UIScrollViewDelegate { } } +private class RealizedScrollViewElement: RealizedElement { + private override func addRealizedViewForChild(child: RealizedElement) { + let scrollView = view as! FewScrollView + scrollView.subviews.first?.removeFromSuperview() + scrollView.addSubview <^> child.view + } +} + private class ScrollViewElement: Element { private let didScroll: CGRect -> () @@ -41,12 +49,10 @@ private class ScrollViewElement: Element { private override func createView() -> ViewType { return FewScrollView(frame: frame, didScroll: didScroll) } - - private override func addRealizedChildView(childView: ViewType, selfView: ViewType) { - let scrollView = selfView as! FewScrollView - scrollView.subviews.first?.removeFromSuperview() - scrollView.addSubview(childView) - } + + private override func createRealizedElement(view: ViewType?) -> RealizedElement { + return RealizedScrollViewElement(element: self, view: view) + } private override func realize() -> RealizedElement { let realizedElement = super.realize() diff --git a/Few-iOS/TableView.swift b/Few-iOS/TableView.swift index f109d71..d0941e6 100644 --- a/Few-iOS/TableView.swift +++ b/Few-iOS/TableView.swift @@ -21,16 +21,16 @@ private class FewListCell: UITableViewCell { element.applyDiff(realizedElement.element, realizedSelf: realizedElement) } else { realizedElement.element.derealize() - realizedElement.view.removeFromSuperview() + realizedElement.view?.removeFromSuperview() let newRealizedElement = element.realize() - newRealizedElement.view.frame = bounds - addSubview(newRealizedElement.view) + newRealizedElement.view?.frame = bounds + addSubview <^> newRealizedElement.view } } else { let newRealizedElement = element.realize() - newRealizedElement.view.frame = bounds - addSubview(newRealizedElement.view) + newRealizedElement.view?.frame = bounds + addSubview <^> newRealizedElement.view realizedElement = newRealizedElement } diff --git a/Few-iOS/iOS.swift b/Few-iOS/iOS.swift index 7027d6e..d7c8ccf 100644 --- a/Few-iOS/iOS.swift +++ b/Few-iOS/iOS.swift @@ -17,6 +17,6 @@ internal func compareAndSetAlpha(view: UIView, alpha: CGFloat) { } } -internal func configureViewToAutoresize(view: ViewType) { - view.autoresizingMask = .FlexibleWidth | .FlexibleHeight +internal func configureViewToAutoresize(view: ViewType?) { + view?.autoresizingMask = .FlexibleWidth | .FlexibleHeight } diff --git a/FewCore/Component.swift b/FewCore/Component.swift index d77cbf4..66d8995 100644 --- a/FewCore/Component.swift +++ b/FewCore/Component.swift @@ -40,6 +40,8 @@ public class Component: Element { /// Is the component a root? private var root = false + private var parent: RealizedElement? + private var frameChangedTrampoline = TargetActionTrampoline() /// Initializes the component with its initial state. The render function @@ -79,13 +81,35 @@ public class Component: Element { } } + final private func assembleNewViewHierarchy(root: RealizedElement, parentView: ViewType?, offset: CGPoint = CGPointZero) { + if parentView == nil && root.view == nil { + println("creating view for \(self)") + root.view = ViewType(frame: root.element.viewFrame) + } else if parentView != nil { + root.view?.frame.origin.x += offset.x + root.view?.frame.origin.y += offset.y + parentView!.addSubview <^> root.view + } + + for child in root.children { + var parentViewForChild = root.view ?? parentView + var offset = (root.view != nil ? CGPointZero : CGPoint(x: offset.x + root.element.frame.origin.x, y: offset.y + root.element.frame.origin.y)) + assembleNewViewHierarchy(child, parentView: parentViewForChild, offset: offset) + } + } + + final private func assembleViewHierarchy(parent: RealizedElement?) { + assembleNewViewHierarchy(realizedRoot!, parentView: parent?.view) + } + final private func realizeNewRoot(newRoot: Element) { - let realized = newRoot.realize() + let realized = newRoot.realize(parent) configureViewToAutoresize(realized.view) - realizedRoot?.view?.removeFromSuperview() realizedRoot = realized + + assembleViewHierarchy(parent) } final private func renderNewRoot() { @@ -112,13 +136,13 @@ public class Component: Element { if newRoot.canDiff(rootElement) { newRoot.applyDiff(rootElement, realizedSelf: realizedRoot) } else { - let superview = realizedRoot!.view!.superview! - rootElement.derealize() + let hostView = realizedRoot!.view!.superview! + realizedRoot?.remove() realizeNewRoot(newRoot) - superview.addSubview(realizedRoot!.view!) + hostView.addSubview(realizedRoot!.view!) - newRoot.elementDidRealize(realizedRoot!) +// newRoot.elementDidRealize(realizedRoot!) } componentDidRender() @@ -175,7 +199,7 @@ public class Component: Element { assert(realizedRoot!.view != nil, "\(self) doesn't realize to a view!") hostView.addSubview(realizedRoot!.view!) - rootElement?.elementDidRealize(realizedRoot!) +// rootElement?.elementDidRealize(realizedRoot!) #if os(OSX) hostView.postsFrameChangedNotifications = true @@ -303,9 +327,12 @@ public class Component: Element { renderNewRoot() } - public override func realize() -> RealizedElement { + public override func realize(parent: RealizedElement?) -> RealizedElement { + self.parent = parent + performInitialRenderIfNeeded() realizeRootIfNeeded() + // TODO: What if we use a nil view here? return RealizedElement(element: self, view: realizedRoot!.view) } @@ -315,9 +342,11 @@ public class Component: Element { rootElement?.derealize() rootElement = nil - realizedRoot?.view?.removeFromSuperview() + realizedRoot?.remove() realizedRoot = nil + parent = nil + componentDidDerealize() } diff --git a/FewCore/Element.swift b/FewCore/Element.swift index 032ed8d..3ab4396 100644 --- a/FewCore/Element.swift +++ b/FewCore/Element.swift @@ -41,10 +41,6 @@ public class Element { children = children.reverse() } #endif - - for child in children { - child.parent = self - } } } @@ -71,8 +67,6 @@ public class Element { /// Should the input make itself the focus after it's been realized? public var autofocus: Bool - public weak var parent: Element? - public init(frame: CGRect = CGRect(x: 0, y: 0, width: Node.Undefined, height: Node.Undefined), key: String? = nil, hidden: Bool = false, alpha: CGFloat = 1, autofocus: Bool = false, children: [Element] = [], direction: Direction = .Row, margin: Edges = Edges(), padding: Edges = Edges(), wrap: Bool = false, justification: Justification = .FlexStart, selfAlignment: SelfAlignment = .Auto, childAlignment: ChildAlignment = .Stretch, flex: CGFloat = 0) { self.frame = frame self.key = key @@ -123,8 +117,8 @@ public class Element { compareAndSetAlpha(view, alpha) } - if frame != old.frame { - view?.frame = frame.integerRect + if viewFrame != old.viewFrame { + view?.frame = viewFrame } realizedSelf?.element = self @@ -137,14 +131,13 @@ public class Element { } for child in childrenDiff.remove { - child.element.derealize() - realizedSelf.removeRealizedChild(child) + child.remove() } for child in childrenDiff.add { - let realizedChild = child.realize() + let realizedChild = child.realize(realizedSelf) realizedSelf.addRealizedChild(realizedChild, index: indexOfObject(children, child)) - child.elementDidRealize(realizedChild) +// child.elementDidRealize(realizedChild) } for child in childrenDiff.diff { @@ -154,6 +147,8 @@ public class Element { } private final func printChildDiff(diff: ElementListDiff, old: Element) { + if old.children.count == 0 && children.count == 0 { return } + println("**** old: \(old.children)") println("**** new: \(children)") @@ -164,7 +159,7 @@ public class Element { } println("**** diffing \(diffs)") - println("**** removing \(diff.remove)") + println("**** removing \(diff.remove.map { $0.element })") println("**** adding \(diff.add)") println() } @@ -173,13 +168,21 @@ public class Element { return nil } + var viewFrame: CGRect { + return frame.integerRect + } + + public func createRealizedElement(view: ViewType?) -> RealizedElement { + return RealizedElement(element: self, view: view) + } + /// Realize the element. - internal func realize() -> RealizedElement { + internal func realize(parent: RealizedElement?) -> RealizedElement { let view = createView() - view?.frame = frame.integerRect + view?.frame = viewFrame - let realizedSelf = RealizedElement(element: self, view: view) - let realizedChildren = children.map { $0.realize() } + let realizedSelf = createRealizedElement(view) + let realizedChildren = children.map { $0.realize(realizedSelf) } for child in realizedChildren { realizedSelf.addRealizedChild(child, index: nil) } @@ -187,12 +190,6 @@ public class Element { return realizedSelf } - internal func addRealizedChildView(childView: ViewType?, selfView: ViewType?) { - if let childView = childView { - selfView?.addSubview(childView) - } - } - /// Derealize the element. public func derealize() { for child in children { @@ -250,7 +247,7 @@ public class Element { #if os(OSX) window?.makeFirstResponder(realizedSelf.view) #else - realizedSelf.view.becomeFirstResponder() + realizedSelf.view?.becomeFirstResponder() #endif } } diff --git a/FewCore/RealizedElement.swift b/FewCore/RealizedElement.swift index 0a0325d..23645b7 100644 --- a/FewCore/RealizedElement.swift +++ b/FewCore/RealizedElement.swift @@ -21,9 +21,9 @@ internal func indexOfObject(array: [T], element: T) -> Int? { public class RealizedElement { public var element: Element - public let view: ViewType? - public weak var parent: RealizedElement? + public var view: ViewType? internal var children: [RealizedElement] = [] + public weak var parent: RealizedElement? public init(element: Element, view: ViewType?) { self.element = element @@ -39,44 +39,33 @@ public class RealizedElement { children.append(child) } - var hostView = view - if hostView == nil { - hostView = findParentWithView()?.view - if let childView = child.view { - child.view?.frame = frameRelativeToParent(self, frame: childView.frame) - } - } - - element.addRealizedChildView(child.view, selfView: hostView) + addRealizedViewForChild(child) } - public func removeRealizedChild(child: RealizedElement) { - child.parent = nil - child.view?.removeFromSuperview() - - if let index = indexOfObject(children, child) { - children.removeAtIndex(index) + public func addRealizedViewForChild(child: RealizedElement) { + if let childView = child.view { + view?.addSubview(childView) } } - public func findParentWithView() -> RealizedElement? { - var currentParent = parent - while currentParent != nil { - if currentParent?.view != nil { return currentParent } - currentParent = currentParent?.parent + public func remove() { + for child in children { + child.remove() } - return nil - } + view?.removeFromSuperview() + element.derealize() - public func frameRelativeToParent(destinationParent: RealizedElement, frame: CGRect) -> CGRect { - var currentParent = parent - var translatedFrame = frame - while currentParent !== destinationParent { - translatedFrame.origin.x += currentParent?.element.frame.origin.x ?? 0 - translatedFrame.origin.y += currentParent?.element.frame.origin.y ?? 0 + if let parent = parent { + parent.removeRealizedChild(self) } - return translatedFrame + parent = nil + } + + private func removeRealizedChild(child: RealizedElement) { + if let index = indexOfObject(children, child) { + children.removeAtIndex(index) + } } } diff --git a/FewDemo/AppDelegate.swift b/FewDemo/AppDelegate.swift index dbcdae0..0ec58f1 100644 --- a/FewDemo/AppDelegate.swift +++ b/FewDemo/AppDelegate.swift @@ -26,7 +26,7 @@ func renderApp(component: Few.Component, state: ActiveComponent contentComponent = Counter() } - return Element() + return View() .justification(.Center) .childAlignment(.Center) .direction(.Column) diff --git a/FewDemo/Demo.swift b/FewDemo/Demo.swift index 5ddfe15..ead21c3 100644 --- a/FewDemo/Demo.swift +++ b/FewDemo/Demo.swift @@ -31,7 +31,7 @@ private func renderInput(component: Few.Component, label: String, se input = Input(action: action).autofocus(true) } - return View() + return Element() .direction(.Row) .padding(Edges(bottom: 4)) .children([ @@ -84,7 +84,7 @@ private func renderScrollView() -> Element { } private func renderRow(row: Int) -> Element { - return View() + return Element() .direction(.Column) .children([ Label("I am a banana.", textColor: NSColor.yellowColor(), font: NSFont.systemFontOfSize(18)), @@ -115,7 +115,7 @@ private func renderLogin() -> Element { private func renderThingy(count: Int) -> Element { let even = count % 2 == 0 - return (even ? Empty() : View(backgroundColor: NSColor.blueColor())).size(100, 50) + return (even ? Element() : View(backgroundColor: NSColor.blueColor())).size(100, 50) } typealias Demo = Demo_<()> @@ -125,7 +125,7 @@ class Demo_: Few.Component<()> { } override func render() -> Element { - return View() + return Element() .justification(.Center) .childAlignment(.Center) .direction(.Column) diff --git a/FewDemo/TemperatureConverter.swift b/FewDemo/TemperatureConverter.swift index 9243e43..97dd543 100644 --- a/FewDemo/TemperatureConverter.swift +++ b/FewDemo/TemperatureConverter.swift @@ -29,7 +29,7 @@ private func f2c(f: CGFloat) -> CGFloat { } private func renderLabeledInput(label: String, value: String, autofocus: Bool, fn: String -> ()) -> Element { - return View() + return Element() .direction(.Row) .padding(Edges(bottom: 4)) .children([ @@ -56,7 +56,7 @@ class TemperatureConverter_: Few.Component { override func render() -> Element { let state = getState() - return View() + return Element() .justification(.Center) .childAlignment(.Center) .direction(.Column) From 195deb3e6a5f08a78fb2e07091dd24902aefbde5 Mon Sep 17 00:00:00 2001 From: joshaber Date: Wed, 15 Apr 2015 20:47:59 -0400 Subject: [PATCH 03/13] do u realize --- External/SwiftBox | 2 +- FewCore/Component.swift | 38 ++++++++++++----------------------- FewCore/RealizedElement.swift | 25 ++++++++++++++++++++++- 3 files changed, 38 insertions(+), 27 deletions(-) diff --git a/External/SwiftBox b/External/SwiftBox index 1e6608b..0b9eb01 160000 --- a/External/SwiftBox +++ b/External/SwiftBox @@ -1 +1 @@ -Subproject commit 1e6608b7911877ba7a39758ab383119f879dc682 +Subproject commit 0b9eb010b567854ad9e86e08731083d5da72d72d diff --git a/FewCore/Component.swift b/FewCore/Component.swift index 66d8995..1192f08 100644 --- a/FewCore/Component.swift +++ b/FewCore/Component.swift @@ -14,6 +14,17 @@ import SwiftBox import AppKit #endif +public class RealizedComponent: RealizedElement { + public init(component: Component, view: ViewType?) { + super.init(element: component, view: view) + } + + public override func assembleNewViewHierarchy(parentView: ViewType?, offset: CGPoint) { + let c = element as! Component + c.realizedRoot?.assembleNewViewHierarchy(parentView, offset: offset) + } +} + /// Components are stateful elements and the bridge between Few and /// AppKit/UIKit. /// @@ -81,35 +92,12 @@ public class Component: Element { } } - final private func assembleNewViewHierarchy(root: RealizedElement, parentView: ViewType?, offset: CGPoint = CGPointZero) { - if parentView == nil && root.view == nil { - println("creating view for \(self)") - root.view = ViewType(frame: root.element.viewFrame) - } else if parentView != nil { - root.view?.frame.origin.x += offset.x - root.view?.frame.origin.y += offset.y - parentView!.addSubview <^> root.view - } - - for child in root.children { - var parentViewForChild = root.view ?? parentView - var offset = (root.view != nil ? CGPointZero : CGPoint(x: offset.x + root.element.frame.origin.x, y: offset.y + root.element.frame.origin.y)) - assembleNewViewHierarchy(child, parentView: parentViewForChild, offset: offset) - } - } - - final private func assembleViewHierarchy(parent: RealizedElement?) { - assembleNewViewHierarchy(realizedRoot!, parentView: parent?.view) - } - final private func realizeNewRoot(newRoot: Element) { let realized = newRoot.realize(parent) configureViewToAutoresize(realized.view) realizedRoot = realized - - assembleViewHierarchy(parent) } final private func renderNewRoot() { @@ -195,6 +183,7 @@ public class Component: Element { frame = hostView.bounds performInitialRenderIfNeeded() realizeRootIfNeeded() + realizedRoot?.assembleNewViewHierarchy(hostView) assert(realizedRoot!.view != nil, "\(self) doesn't realize to a view!") hostView.addSubview(realizedRoot!.view!) @@ -332,8 +321,7 @@ public class Component: Element { performInitialRenderIfNeeded() realizeRootIfNeeded() - // TODO: What if we use a nil view here? - return RealizedElement(element: self, view: realizedRoot!.view) + return RealizedComponent(component: self, view: nil) } public override func derealize() { diff --git a/FewCore/RealizedElement.swift b/FewCore/RealizedElement.swift index 23645b7..dd8ffef 100644 --- a/FewCore/RealizedElement.swift +++ b/FewCore/RealizedElement.swift @@ -42,9 +42,15 @@ public class RealizedElement { addRealizedViewForChild(child) } + public func parentViewWithView() -> ViewType? { + if view != nil { return view } + + return parent?.parentViewWithView() + } + public func addRealizedViewForChild(child: RealizedElement) { if let childView = child.view { - view?.addSubview(childView) + child.assembleNewViewHierarchy(parentViewWithView()) } } @@ -68,4 +74,21 @@ public class RealizedElement { children.removeAtIndex(index) } } + + public func assembleNewViewHierarchy(parentView: ViewType?, offset: CGPoint = CGPointZero) { + if parentView == nil && view == nil { + println("creating view for \(element)") + view = ViewType(frame: element.viewFrame) + } else if parentView != nil { + view?.frame.origin.x += offset.x + view?.frame.origin.y += offset.y + parentView!.addSubview <^> view + } + + for child in children { + var parentViewForChild = view ?? parentView + var offset = (view != nil ? CGPointZero : CGPoint(x: offset.x + element.frame.origin.x, y: offset.y + element.frame.origin.y)) + child.assembleNewViewHierarchy(parentViewForChild, offset: offset) + } + } } From 00517bf66d005ccfe7cae86055b754bc1822067e Mon Sep 17 00:00:00 2001 From: joshaber Date: Wed, 15 Apr 2015 23:28:49 -0400 Subject: [PATCH 04/13] Update iOS --- Few-iOS/ScrollView.swift | 4 ++-- Few-iOS/TableView.swift | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Few-iOS/ScrollView.swift b/Few-iOS/ScrollView.swift index 9cdfcf6..614dd40 100644 --- a/Few-iOS/ScrollView.swift +++ b/Few-iOS/ScrollView.swift @@ -54,8 +54,8 @@ private class ScrollViewElement: Element { return RealizedScrollViewElement(element: self, view: view) } - private override func realize() -> RealizedElement { - let realizedElement = super.realize() + private override func realize(parent: RealizedElement?) -> RealizedElement { + let realizedElement = super.realize(parent) let scrollView = realizedElement.view as! FewScrollView if let element = children.first { diff --git a/Few-iOS/TableView.swift b/Few-iOS/TableView.swift index d0941e6..ddee2e7 100644 --- a/Few-iOS/TableView.swift +++ b/Few-iOS/TableView.swift @@ -23,12 +23,12 @@ private class FewListCell: UITableViewCell { realizedElement.element.derealize() realizedElement.view?.removeFromSuperview() - let newRealizedElement = element.realize() + let newRealizedElement = element.realize(nil) newRealizedElement.view?.frame = bounds addSubview <^> newRealizedElement.view } } else { - let newRealizedElement = element.realize() + let newRealizedElement = element.realize(nil) newRealizedElement.view?.frame = bounds addSubview <^> newRealizedElement.view From 5972edc2584127e3cdf0464ec28e71d129d96e48 Mon Sep 17 00:00:00 2001 From: joshaber Date: Wed, 15 Apr 2015 23:28:58 -0400 Subject: [PATCH 05/13] Update tests --- FewCore/Element.swift | 2 +- FewTests/DiffTests.swift | 19 ++++++++----------- 2 files changed, 9 insertions(+), 12 deletions(-) diff --git a/FewCore/Element.swift b/FewCore/Element.swift index 3ab4396..db625f1 100644 --- a/FewCore/Element.swift +++ b/FewCore/Element.swift @@ -177,7 +177,7 @@ public class Element { } /// Realize the element. - internal func realize(parent: RealizedElement?) -> RealizedElement { + public func realize(parent: RealizedElement?) -> RealizedElement { let view = createView() view?.frame = viewFrame diff --git a/FewTests/DiffTests.swift b/FewTests/DiffTests.swift index 3ae0d59..0692ea2 100644 --- a/FewTests/DiffTests.swift +++ b/FewTests/DiffTests.swift @@ -14,46 +14,43 @@ class DiffTests: QuickSpec { override func spec() { describe("diffElementLists") { let button = Button(title: "Hi") {} - let view = button.realize() - let realizedButton = RealizedElement(element: button, children: [], view: view) - - let label = Label("Hey") + let realizedButton = button.realize(nil) + let label = Label("Hey").size(100, 23) it("should detect simple diffing") { - let diff = diffElementLists([realizedButton], [button]) + let diff = diffElementLists([ realizedButton ], [ button ]) expect(diff.add.count).to(equal(0)) expect(diff.remove.count).to(equal(0)) expect(diff.diff.count).to(equal(1)) } it("should detect replacement") { - let diff = diffElementLists([realizedButton], [label]) + let diff = diffElementLists([ realizedButton ], [ label ]) expect(diff.add.count).to(equal(1)) expect(diff.remove.count).to(equal(1)) expect(diff.diff.count).to(equal(0)) } it("should detect removal") { - let diff = diffElementLists([realizedButton], []) + let diff = diffElementLists([ realizedButton ], []) expect(diff.add.count).to(equal(0)) expect(diff.remove.count).to(equal(1)) expect(diff.diff.count).to(equal(0)) } it("should detect addition") { - let diff = diffElementLists([realizedButton], [button, label]) + let diff = diffElementLists([ realizedButton ], [ button, label ]) expect(diff.add.count).to(equal(1)) expect(diff.remove.count).to(equal(0)) expect(diff.diff.count).to(equal(1)) } it("should use keys to match even when position changes") { - let labelView = label.realize() - let realizedLabel = RealizedElement(element: label, children: [], view: labelView) + let realizedLabel = label.realize(nil) let newLabel = Label("No.") newLabel.key = "key" - let diff = diffElementLists([realizedButton, realizedLabel], [button, newLabel, label]) + let diff = diffElementLists([ realizedButton, realizedLabel ], [ button, newLabel, label ]) expect(diff.add.count).to(equal(1)) expect(diff.remove.count).to(equal(0)) expect(diff.diff.count).to(equal(2)) From 6a42d08d5e5605ce63642154b64032b553e9f069 Mon Sep 17 00:00:00 2001 From: joshaber Date: Wed, 15 Apr 2015 23:29:04 -0400 Subject: [PATCH 06/13] Update the playground. --- .../{section-1.swift => Contents.swift} | 0 FewDemo/MyPlayground.playground/contents.xcplayground | 5 +---- 2 files changed, 1 insertion(+), 4 deletions(-) rename FewDemo/MyPlayground.playground/{section-1.swift => Contents.swift} (100%) diff --git a/FewDemo/MyPlayground.playground/section-1.swift b/FewDemo/MyPlayground.playground/Contents.swift similarity index 100% rename from FewDemo/MyPlayground.playground/section-1.swift rename to FewDemo/MyPlayground.playground/Contents.swift diff --git a/FewDemo/MyPlayground.playground/contents.xcplayground b/FewDemo/MyPlayground.playground/contents.xcplayground index 4937636..06828af 100644 --- a/FewDemo/MyPlayground.playground/contents.xcplayground +++ b/FewDemo/MyPlayground.playground/contents.xcplayground @@ -1,7 +1,4 @@ - - - - + \ No newline at end of file From f3b4b0abaa001b97414afb31f7523d05354b336d Mon Sep 17 00:00:00 2001 From: joshaber Date: Thu, 16 Apr 2015 00:39:05 -0400 Subject: [PATCH 07/13] Turn the whole thing inside out. --- Few-Mac/ScrollView.swift | 4 +-- FewCore/Component.swift | 13 +++------ FewCore/Element.swift | 13 +++++---- FewCore/RealizedElement.swift | 51 +++++++++++++---------------------- 4 files changed, 31 insertions(+), 50 deletions(-) diff --git a/Few-Mac/ScrollView.swift b/Few-Mac/ScrollView.swift index 9d13dfd..7de7097 100644 --- a/Few-Mac/ScrollView.swift +++ b/Few-Mac/ScrollView.swift @@ -71,8 +71,8 @@ private class ScrollViewElement: Element { return view } - private override func createRealizedElement(view: ViewType?) -> RealizedElement { - return RealizedScrollViewElement(element: self, view: view) + private override func createRealizedElement(view: ViewType?, parent: RealizedElement?) -> RealizedElement { + return RealizedScrollViewElement(element: self, view: view, parent: parent) } private override func realize(parent: RealizedElement?) -> RealizedElement { diff --git a/FewCore/Component.swift b/FewCore/Component.swift index 1192f08..5eae9eb 100644 --- a/FewCore/Component.swift +++ b/FewCore/Component.swift @@ -15,13 +15,8 @@ import AppKit #endif public class RealizedComponent: RealizedElement { - public init(component: Component, view: ViewType?) { - super.init(element: component, view: view) - } - - public override func assembleNewViewHierarchy(parentView: ViewType?, offset: CGPoint) { - let c = element as! Component - c.realizedRoot?.assembleNewViewHierarchy(parentView, offset: offset) + public init(component: Component, view: ViewType?, parent: RealizedElement?) { + super.init(element: component, view: view, parent: parent) } } @@ -181,9 +176,9 @@ public class Component: Element { public func addToView(hostView: ViewType) { root = true frame = hostView.bounds + parent = RealizedElement(element: self, view: hostView, parent: nil) performInitialRenderIfNeeded() realizeRootIfNeeded() - realizedRoot?.assembleNewViewHierarchy(hostView) assert(realizedRoot!.view != nil, "\(self) doesn't realize to a view!") hostView.addSubview(realizedRoot!.view!) @@ -321,7 +316,7 @@ public class Component: Element { performInitialRenderIfNeeded() realizeRootIfNeeded() - return RealizedComponent(component: self, view: nil) + return RealizedComponent(component: self, view: nil, parent: parent) } public override func derealize() { diff --git a/FewCore/Element.swift b/FewCore/Element.swift index db625f1..48c454b 100644 --- a/FewCore/Element.swift +++ b/FewCore/Element.swift @@ -172,8 +172,8 @@ public class Element { return frame.integerRect } - public func createRealizedElement(view: ViewType?) -> RealizedElement { - return RealizedElement(element: self, view: view) + public func createRealizedElement(view: ViewType?, parent: RealizedElement?) -> RealizedElement { + return RealizedElement(element: self, view: view, parent: parent) } /// Realize the element. @@ -181,11 +181,10 @@ public class Element { let view = createView() view?.frame = viewFrame - let realizedSelf = createRealizedElement(view) - let realizedChildren = children.map { $0.realize(realizedSelf) } - for child in realizedChildren { - realizedSelf.addRealizedChild(child, index: nil) - } + let realizedSelf = createRealizedElement(view, parent: parent) + parent?.addRealizedChild(realizedSelf, index: nil) + + realizedSelf.children = children.map { $0.realize(realizedSelf) } return realizedSelf } diff --git a/FewCore/RealizedElement.swift b/FewCore/RealizedElement.swift index dd8ffef..0c789c8 100644 --- a/FewCore/RealizedElement.swift +++ b/FewCore/RealizedElement.swift @@ -21,18 +21,18 @@ internal func indexOfObject(array: [T], element: T) -> Int? { public class RealizedElement { public var element: Element - public var view: ViewType? + public let view: ViewType? internal var children: [RealizedElement] = [] public weak var parent: RealizedElement? + internal var frameOffset = CGPointZero - public init(element: Element, view: ViewType?) { + public init(element: Element, view: ViewType?, parent: RealizedElement?) { self.element = element self.view = view + self.parent = parent } public func addRealizedChild(child: RealizedElement, index: Int?) { - child.parent = self - if let index = index { children.insert(child, atIndex: index) } else { @@ -42,16 +42,23 @@ public class RealizedElement { addRealizedViewForChild(child) } - public func parentViewWithView() -> ViewType? { - if view != nil { return view } + public func addRealizedViewForChild(child: RealizedElement) { + if child.view == nil { return } - return parent?.parentViewWithView() - } + var parent: RealizedElement? = self + var offset = CGPointZero + while let currentParent = parent { + if currentParent.view != nil { break } - public func addRealizedViewForChild(child: RealizedElement) { - if let childView = child.view { - child.assembleNewViewHierarchy(parentViewWithView()) + offset.x += currentParent.element.frame.origin.x + currentParent.frameOffset.x + offset.y += currentParent.element.frame.origin.y + currentParent.frameOffset.y + parent = currentParent.parent } + + child.view?.frame.origin.x += offset.x + child.view?.frame.origin.y += offset.y + child.frameOffset = offset + parent?.view?.addSubview(child.view!) } public func remove() { @@ -62,10 +69,7 @@ public class RealizedElement { view?.removeFromSuperview() element.derealize() - if let parent = parent { - parent.removeRealizedChild(self) - } - + parent?.removeRealizedChild(self) parent = nil } @@ -74,21 +78,4 @@ public class RealizedElement { children.removeAtIndex(index) } } - - public func assembleNewViewHierarchy(parentView: ViewType?, offset: CGPoint = CGPointZero) { - if parentView == nil && view == nil { - println("creating view for \(element)") - view = ViewType(frame: element.viewFrame) - } else if parentView != nil { - view?.frame.origin.x += offset.x - view?.frame.origin.y += offset.y - parentView!.addSubview <^> view - } - - for child in children { - var parentViewForChild = view ?? parentView - var offset = (view != nil ? CGPointZero : CGPoint(x: offset.x + element.frame.origin.x, y: offset.y + element.frame.origin.y)) - child.assembleNewViewHierarchy(parentViewForChild, offset: offset) - } - } } From 61aca3a8f27cf12b4ff42d97cac5c4321c983b72 Mon Sep 17 00:00:00 2001 From: joshaber Date: Thu, 16 Apr 2015 00:40:56 -0400 Subject: [PATCH 08/13] Don't need that subclass anymore. --- FewCore/Component.swift | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/FewCore/Component.swift b/FewCore/Component.swift index 5eae9eb..3e5fe0a 100644 --- a/FewCore/Component.swift +++ b/FewCore/Component.swift @@ -14,12 +14,6 @@ import SwiftBox import AppKit #endif -public class RealizedComponent: RealizedElement { - public init(component: Component, view: ViewType?, parent: RealizedElement?) { - super.init(element: component, view: view, parent: parent) - } -} - /// Components are stateful elements and the bridge between Few and /// AppKit/UIKit. /// @@ -316,7 +310,7 @@ public class Component: Element { performInitialRenderIfNeeded() realizeRootIfNeeded() - return RealizedComponent(component: self, view: nil, parent: parent) + return RealizedElement(element: self, view: nil, parent: parent) } public override func derealize() { From 6ea8a7899fca746451a392cc5665380558983204 Mon Sep 17 00:00:00 2001 From: joshaber Date: Thu, 16 Apr 2015 00:48:01 -0400 Subject: [PATCH 09/13] It's cool if the root itself doesn't realize to a view. --- FewCore/Component.swift | 3 +-- FewDemo/AppDelegate.swift | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/FewCore/Component.swift b/FewCore/Component.swift index 3e5fe0a..fe709df 100644 --- a/FewCore/Component.swift +++ b/FewCore/Component.swift @@ -174,8 +174,7 @@ public class Component: Element { performInitialRenderIfNeeded() realizeRootIfNeeded() - assert(realizedRoot!.view != nil, "\(self) doesn't realize to a view!") - hostView.addSubview(realizedRoot!.view!) + hostView.addSubview <^> realizedRoot?.view // rootElement?.elementDidRealize(realizedRoot!) diff --git a/FewDemo/AppDelegate.swift b/FewDemo/AppDelegate.swift index 0ec58f1..dbcdae0 100644 --- a/FewDemo/AppDelegate.swift +++ b/FewDemo/AppDelegate.swift @@ -26,7 +26,7 @@ func renderApp(component: Few.Component, state: ActiveComponent contentComponent = Counter() } - return View() + return Element() .justification(.Center) .childAlignment(.Center) .direction(.Column) From 5e9dea697b58c4a8660984a3f577933ae460dba0 Mon Sep 17 00:00:00 2001 From: joshaber Date: Thu, 16 Apr 2015 21:23:36 -0400 Subject: [PATCH 10/13] Clean up realization and derealization. --- FewCore/Component.swift | 13 +------------ FewCore/Element.swift | 10 ++-------- FewCore/RealizedElement.swift | 18 ++++++++++-------- 3 files changed, 13 insertions(+), 28 deletions(-) diff --git a/FewCore/Component.swift b/FewCore/Component.swift index fe709df..989bf55 100644 --- a/FewCore/Component.swift +++ b/FewCore/Component.swift @@ -113,13 +113,8 @@ public class Component: Element { if newRoot.canDiff(rootElement) { newRoot.applyDiff(rootElement, realizedSelf: realizedRoot) } else { - let hostView = realizedRoot!.view!.superview! realizedRoot?.remove() - realizeNewRoot(newRoot) - hostView.addSubview(realizedRoot!.view!) - -// newRoot.elementDidRealize(realizedRoot!) } componentDidRender() @@ -174,10 +169,6 @@ public class Component: Element { performInitialRenderIfNeeded() realizeRootIfNeeded() - hostView.addSubview <^> realizedRoot?.view - -// rootElement?.elementDidRealize(realizedRoot!) - #if os(OSX) hostView.postsFrameChangedNotifications = true realizedRoot!.view?.autoresizesSubviews = false @@ -315,11 +306,9 @@ public class Component: Element { public override func derealize() { componentWillDerealize() - rootElement?.derealize() - rootElement = nil - realizedRoot?.remove() realizedRoot = nil + rootElement = nil parent = nil diff --git a/FewCore/Element.swift b/FewCore/Element.swift index 48c454b..f249033 100644 --- a/FewCore/Element.swift +++ b/FewCore/Element.swift @@ -136,8 +136,6 @@ public class Element { for child in childrenDiff.add { let realizedChild = child.realize(realizedSelf) - realizedSelf.addRealizedChild(realizedChild, index: indexOfObject(children, child)) -// child.elementDidRealize(realizedChild) } for child in childrenDiff.diff { @@ -182,7 +180,7 @@ public class Element { view?.frame = viewFrame let realizedSelf = createRealizedElement(view, parent: parent) - parent?.addRealizedChild(realizedSelf, index: nil) + parent?.addRealizedChild(realizedSelf, index: indexOfObject(children, self)) realizedSelf.children = children.map { $0.realize(realizedSelf) } @@ -190,11 +188,7 @@ public class Element { } /// Derealize the element. - public func derealize() { - for child in children { - child.derealize() - } - } + public func derealize() {} internal func assembleLayoutNode() -> Node { let childNodes = children.map { $0.assembleLayoutNode() } diff --git a/FewCore/RealizedElement.swift b/FewCore/RealizedElement.swift index 0c789c8..c5be17e 100644 --- a/FewCore/RealizedElement.swift +++ b/FewCore/RealizedElement.swift @@ -10,10 +10,7 @@ import Foundation internal func indexOfObject(array: [T], element: T) -> Int? { for (i, e) in enumerate(array) { - // HAHA SWIFT WHY DOES POINTER EQUALITY NOT WORK - let ptr1 = Unmanaged.passUnretained(element).toOpaque() - let ptr2 = Unmanaged.passUnretained(e).toOpaque() - if ptr1 == ptr2 { return i } + if element === e { return i } } return nil @@ -22,9 +19,10 @@ internal func indexOfObject(array: [T], element: T) -> Int? { public class RealizedElement { public var element: Element public let view: ViewType? - internal var children: [RealizedElement] = [] public weak var parent: RealizedElement? - internal var frameOffset = CGPointZero + + internal var children: [RealizedElement] = [] + private var frameOffset = CGPointZero public init(element: Element, view: ViewType?, parent: RealizedElement?) { self.element = element @@ -43,7 +41,10 @@ public class RealizedElement { } public func addRealizedViewForChild(child: RealizedElement) { - if child.view == nil { return } + if child.view == nil { + child.element.elementDidRealize(child) + return + } var parent: RealizedElement? = self var offset = CGPointZero @@ -59,6 +60,7 @@ public class RealizedElement { child.view?.frame.origin.y += offset.y child.frameOffset = offset parent?.view?.addSubview(child.view!) + child.element.elementDidRealize(child) } public func remove() { @@ -73,7 +75,7 @@ public class RealizedElement { parent = nil } - private func removeRealizedChild(child: RealizedElement) { + private final func removeRealizedChild(child: RealizedElement) { if let index = indexOfObject(children, child) { children.removeAtIndex(index) } From 2d66539b4c478aea7a340367aa9c1644a036322c Mon Sep 17 00:00:00 2001 From: joshaber Date: Thu, 16 Apr 2015 22:10:19 -0400 Subject: [PATCH 11/13] Fix TableView. --- Few-Mac/TableView.swift | 17 +++++------------ Few-iOS/ScrollView.swift | 4 ++-- Few-iOS/TableView.swift | 17 ++++++----------- 3 files changed, 13 insertions(+), 25 deletions(-) diff --git a/Few-Mac/TableView.swift b/Few-Mac/TableView.swift index 06012e8..5618dc3 100644 --- a/Few-Mac/TableView.swift +++ b/Few-Mac/TableView.swift @@ -21,21 +21,14 @@ private class FewListCell: NSTableCellView { if element.canDiff(realizedElement.element) { element.applyDiff(realizedElement.element, realizedSelf: realizedElement) } else { - realizedElement.element.derealize() - realizedElement.view?.removeFromSuperview() + realizedElement.remove() - let newRealizedElement = element.realize(nil) - newRealizedElement.view?.autoresizingMask = .ViewWidthSizable | .ViewHeightSizable - newRealizedElement.view?.frame = bounds - addSubview <^> newRealizedElement.view + let parent = RealizedElement(element: Element(), view: self, parent: nil) + self.realizedElement = element.realize(parent) } } else { - let newRealizedElement = element.realize(nil) - newRealizedElement.view?.autoresizingMask = .ViewWidthSizable | .ViewHeightSizable - newRealizedElement.view?.frame = bounds - addSubview <^> newRealizedElement.view - - realizedElement = newRealizedElement + let parent = RealizedElement(element: Element(), view: self, parent: nil) + realizedElement = element.realize(parent) } } diff --git a/Few-iOS/ScrollView.swift b/Few-iOS/ScrollView.swift index 614dd40..61bc5ea 100644 --- a/Few-iOS/ScrollView.swift +++ b/Few-iOS/ScrollView.swift @@ -50,8 +50,8 @@ private class ScrollViewElement: Element { return FewScrollView(frame: frame, didScroll: didScroll) } - private override func createRealizedElement(view: ViewType?) -> RealizedElement { - return RealizedScrollViewElement(element: self, view: view) + private override func createRealizedElement(view: ViewType?, parent: RealizedElement?) -> RealizedElement { + return RealizedScrollViewElement(element: self, view: view, parent: parent) } private override func realize(parent: RealizedElement?) -> RealizedElement { diff --git a/Few-iOS/TableView.swift b/Few-iOS/TableView.swift index ddee2e7..b072fde 100644 --- a/Few-iOS/TableView.swift +++ b/Few-iOS/TableView.swift @@ -20,19 +20,14 @@ private class FewListCell: UITableViewCell { if element.canDiff(realizedElement.element) { element.applyDiff(realizedElement.element, realizedSelf: realizedElement) } else { - realizedElement.element.derealize() - realizedElement.view?.removeFromSuperview() - - let newRealizedElement = element.realize(nil) - newRealizedElement.view?.frame = bounds - addSubview <^> newRealizedElement.view + realizedElement.remove() + + let parent = RealizedElement(element: Element(), view: self, parent: nil) + self.realizedElement = element.realize(parent) } } else { - let newRealizedElement = element.realize(nil) - newRealizedElement.view?.frame = bounds - addSubview <^> newRealizedElement.view - - realizedElement = newRealizedElement + let parent = RealizedElement(element: Element(), view: self, parent: nil) + realizedElement = element.realize(parent) } } } From 39dfdbc2cde9eb08d75252cd2c71cfa8b0681524 Mon Sep 17 00:00:00 2001 From: joshaber Date: Fri, 17 Apr 2015 19:30:48 -0400 Subject: [PATCH 12/13] More unification of realization. --- FewCore/Component.swift | 13 ++++++------- FewCore/Element.swift | 34 ++++++++++++++++------------------ 2 files changed, 22 insertions(+), 25 deletions(-) diff --git a/FewCore/Component.swift b/FewCore/Component.swift index 989bf55..307f24c 100644 --- a/FewCore/Component.swift +++ b/FewCore/Component.swift @@ -94,7 +94,7 @@ public class Component: Element { newRoot.frame = frame let node = newRoot.assembleLayoutNode() - var layout: Layout! + let layout: Layout if root { layout = node.layout(maxWidth: frame.size.width) } else { @@ -165,9 +165,8 @@ public class Component: Element { public func addToView(hostView: ViewType) { root = true frame = hostView.bounds - parent = RealizedElement(element: self, view: hostView, parent: nil) - performInitialRenderIfNeeded() - realizeRootIfNeeded() + let parent = RealizedElement(element: self, view: hostView, parent: nil) + realize(parent) #if os(OSX) hostView.postsFrameChangedNotifications = true @@ -284,9 +283,9 @@ public class Component: Element { public override func applyDiff(old: Element, realizedSelf: RealizedElement?) { super.applyDiff(old, realizedSelf: realizedSelf) - // Use `unsafeBitCast` instead of `as` to avoid a runtime crash. - let oldComponent = unsafeBitCast(old, Component.self) + let oldComponent = old as! Component + parent = oldComponent.parent root = oldComponent.root state = oldComponent.state rootElement = oldComponent.rootElement @@ -300,7 +299,7 @@ public class Component: Element { performInitialRenderIfNeeded() realizeRootIfNeeded() - return RealizedElement(element: self, view: nil, parent: parent) + return super.realize(parent) } public override func derealize() { diff --git a/FewCore/Element.swift b/FewCore/Element.swift index f249033..7b1b04e 100644 --- a/FewCore/Element.swift +++ b/FewCore/Element.swift @@ -8,7 +8,6 @@ import Foundation import CoreGraphics -import SwiftBox public var LogDiff = false @@ -105,7 +104,7 @@ public class Element { /// should call super before doing their own diffing. public func applyDiff(old: Element, realizedSelf: RealizedElement?) { if LogDiff { - println("*** Diffing \(reflect(self).summary)") + println("*** Diffing \(self)") } let view = realizedSelf?.view @@ -147,18 +146,21 @@ public class Element { private final func printChildDiff(diff: ElementListDiff, old: Element) { if old.children.count == 0 && children.count == 0 { return } - println("**** old: \(old.children)") - println("**** new: \(children)") + let oldChildren = old.children.map { "\($0.dynamicType)" } + println("**** old: \(oldChildren)") - let diffs: [String] = diff.diff.map { - let existing = $0.existing.element - let replacement = $0.replacement - return "\(replacement) => \(existing)" + let newChildren = children.map { "\($0.dynamicType)" } + println("**** new: \(newChildren)") + + for d in diff.diff { + println("**** applying \(d.replacement.dynamicType) => \(d.existing.element.dynamicType)") } - println("**** diffing \(diffs)") - println("**** removing \(diff.remove.map { $0.element })") - println("**** adding \(diff.add)") + let removing = diff.remove.map { "\($0.element.dynamicType)" } + println("**** removing \(removing)") + + let adding = diff.add.map { "\($0.dynamicType)" } + println("**** adding \(adding)") println() } @@ -182,7 +184,9 @@ public class Element { let realizedSelf = createRealizedElement(view, parent: parent) parent?.addRealizedChild(realizedSelf, index: indexOfObject(children, self)) - realizedSelf.children = children.map { $0.realize(realizedSelf) } + for child in children { + child.realize(realizedSelf) + } return realizedSelf } @@ -229,12 +233,6 @@ public class Element { } public func elementDidRealize(realizedSelf: RealizedElement) { - // Tell our children first so that we still end up grabbing focus even - // if a child also has autofocus. - for child in realizedSelf.children { - child.element.elementDidRealize(child) - } - if autofocus { let window = realizedSelf.view?.window! #if os(OSX) From 4da9de5171b8ce22507fa7dd7e4d0324218d5a5d Mon Sep 17 00:00:00 2001 From: joshaber Date: Fri, 17 Apr 2015 19:30:56 -0400 Subject: [PATCH 13/13] Update iOS + playground. --- FewDemo-iOS/ViewController.swift | 18 ++++++++++++------ FewDemo/MyPlayground.playground/Contents.swift | 15 +++++++++++++-- 2 files changed, 25 insertions(+), 8 deletions(-) diff --git a/FewDemo-iOS/ViewController.swift b/FewDemo-iOS/ViewController.swift index 4e8873e..429ffaf 100644 --- a/FewDemo-iOS/ViewController.swift +++ b/FewDemo-iOS/ViewController.swift @@ -12,7 +12,7 @@ import Few func renderCounter(component: Component, count: Int) -> Element { let updateCounter = { component.updateState { $0 + 1 } } - return View() + return Element() // The view itself should be centered. .justification(.Center) // The children should be centered in the view. @@ -48,7 +48,9 @@ private func renderRow(row: Int) -> Element { } func renderTableView(component: Component<()>, state: ()) -> Element { - return TableView((1...100).map(renderRow), selectionChanged: println) + return TableView((1...100).map(renderRow), selectionChanged: println) + .flex(1) + .selfAlignment(.Stretch) } let TableViewDemo = { Component(initialState: (), render: renderTableView) } @@ -101,14 +103,18 @@ func renderApp(component: Few.Component, state: AppState) -> Element { return Element() .direction(.Column) .children([ - contentComponent - .margin(Edges(top: 20)) - .flex(1), + Element() + .children([ + contentComponent + ]) + .childAlignment(.Center) + .justification(.Center) + .flex(1), Button(title: "Show me more!", action: showMore) .width(200) .margin(Edges(uniform: 10)) .selfAlignment(.Center) - ]) + ]) } func toggleDisplay(var state: AppState) -> AppState { diff --git a/FewDemo/MyPlayground.playground/Contents.swift b/FewDemo/MyPlayground.playground/Contents.swift index 2cfb749..92c24a6 100644 --- a/FewDemo/MyPlayground.playground/Contents.swift +++ b/FewDemo/MyPlayground.playground/Contents.swift @@ -4,5 +4,16 @@ import Cocoa import Few import XCPlayground -let view = View(backgroundColor: NSColor.redColor()).size(100, 100) -view.ql +let view = View(backgroundColor: NSColor.redColor()) + .direction(.Column) + .justification(.FlexEnd) + .children([ + Label("Bleh").size(100, 23), + Label("World").size(100, 23), + Button(title: "Yoo").margin(Edges(uniform: 4)) + ]) +let component = Component(initialState: ()) { _, _ in view } + +let host = NSView(frame: CGRect(x: 0, y: 0, width: 100, height: 100)) +component.addToView(host) +host