Resolve #17 ObservableList
This commit is contained in:
@@ -26,6 +26,7 @@
|
||||
66AE19D21CC8C6B300B78B5E /* SVGParser.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66AE19D11CC8C6B300B78B5E /* SVGParser.swift */; };
|
||||
AD9EDEE3709C1668BED1B1BF /* Pods_Macaw.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BA114AD1025D7DA0B0DC35A8 /* Pods_Macaw.framework */; };
|
||||
B0086C561C789758008A4F69 /* GroupRenderer.swift in Sources */ = {isa = PBXBuildFile; fileRef = B0086C551C789758008A4F69 /* GroupRenderer.swift */; };
|
||||
B0090DBF1CEA1EDD0018D77C /* ObservableList.swift in Sources */ = {isa = PBXBuildFile; fileRef = B0090DBE1CEA1EDD0018D77C /* ObservableList.swift */; };
|
||||
B03275E51C78772F000BDD33 /* Align.swift in Sources */ = {isa = PBXBuildFile; fileRef = B03275B21C78772F000BDD33 /* Align.swift */; };
|
||||
B03275E61C78772F000BDD33 /* AspectRatio.swift in Sources */ = {isa = PBXBuildFile; fileRef = B03275B31C78772F000BDD33 /* AspectRatio.swift */; };
|
||||
B03275E71C78772F000BDD33 /* Baseline.swift in Sources */ = {isa = PBXBuildFile; fileRef = B03275B41C78772F000BDD33 /* Baseline.swift */; };
|
||||
@@ -103,6 +104,7 @@
|
||||
66AE19D11CC8C6B300B78B5E /* SVGParser.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = SVGParser.swift; path = svg/SVGParser.swift; sourceTree = "<group>"; };
|
||||
8A680FA7BCDE96402C10D8D2 /* Pods-Macaw.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Macaw.release.xcconfig"; path = "Pods/Target Support Files/Pods-Macaw/Pods-Macaw.release.xcconfig"; sourceTree = "<group>"; };
|
||||
B0086C551C789758008A4F69 /* GroupRenderer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GroupRenderer.swift; sourceTree = "<group>"; };
|
||||
B0090DBE1CEA1EDD0018D77C /* ObservableList.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ObservableList.swift; sourceTree = "<group>"; };
|
||||
B02E75D61C160F8D00D1971D /* Macaw.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Macaw.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
B02E76131C1612A900D1971D /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
B03275B21C78772F000BDD33 /* Align.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Align.swift; sourceTree = "<group>"; };
|
||||
@@ -237,6 +239,14 @@
|
||||
name = svg;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
B0090DBD1CEA1ECE0018D77C /* bindings */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
B0090DBE1CEA1EDD0018D77C /* ObservableList.swift */,
|
||||
);
|
||||
path = bindings;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
B02E75CC1C160F8D00D1971D = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
@@ -259,6 +269,7 @@
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
66AE19D01CC8C66E00B78B5E /* svg */,
|
||||
B0090DBD1CEA1ECE0018D77C /* bindings */,
|
||||
5742238C1CA540F8001EE463 /* animation */,
|
||||
B03275B01C78772F000BDD33 /* model */,
|
||||
585C04461C27CFB100335FF2 /* views */,
|
||||
@@ -567,6 +578,7 @@
|
||||
B03275ED1C78772F000BDD33 /* FontWeight.swift in Sources */,
|
||||
B03275F61C78772F000BDD33 /* Cubic.swift in Sources */,
|
||||
66AE19D21CC8C6B300B78B5E /* SVGParser.swift in Sources */,
|
||||
B0090DBF1CEA1EDD0018D77C /* ObservableList.swift in Sources */,
|
||||
574223901CA5448C001EE463 /* Animation.swift in Sources */,
|
||||
585C04481C27CFB100335FF2 /* MacawView.swift in Sources */,
|
||||
);
|
||||
|
||||
@@ -0,0 +1,212 @@
|
||||
//
|
||||
// https://github.com/safx/ObservableArray-RxSwift
|
||||
// ObservableArray.swift
|
||||
// ObservableArray
|
||||
//
|
||||
// Created by Safx Developer on 2015/02/19.
|
||||
// Copyright (c) 2016 Safx Developers. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import RxSwift
|
||||
|
||||
public struct ArrayChangeEvent {
|
||||
public let insertedIndices: [Int]
|
||||
public let deletedIndices: [Int]
|
||||
public let updatedIndices: [Int]
|
||||
|
||||
private init(inserted: [Int] = [], deleted: [Int] = [], updated: [Int] = []) {
|
||||
assert(inserted.count + deleted.count + updated.count > 0)
|
||||
self.insertedIndices = inserted
|
||||
self.deletedIndices = deleted
|
||||
self.updatedIndices = updated
|
||||
}
|
||||
}
|
||||
|
||||
public struct ObservableArray<Element>: ArrayLiteralConvertible {
|
||||
public typealias EventType = ArrayChangeEvent
|
||||
|
||||
internal var eventSubject: PublishSubject<EventType>!
|
||||
internal var elementsSubject: PublishSubject<[Element]>!
|
||||
internal var elements: [Element]
|
||||
|
||||
public init() {
|
||||
self.elements = []
|
||||
}
|
||||
|
||||
public init(count:Int, repeatedValue: Element) {
|
||||
self.elements = Array(count: count, repeatedValue: repeatedValue)
|
||||
}
|
||||
|
||||
public init<S : SequenceType where S.Generator.Element == Element>(_ s: S) {
|
||||
self.elements = Array(s)
|
||||
}
|
||||
|
||||
public init(arrayLiteral elements: Element...) {
|
||||
self.elements = elements
|
||||
}
|
||||
|
||||
public init(array elements: [Element]) {
|
||||
self.elements = elements
|
||||
}
|
||||
}
|
||||
|
||||
extension ObservableArray {
|
||||
public mutating func rx_elements() -> Observable<[Element]> {
|
||||
if elementsSubject == nil {
|
||||
self.elementsSubject = PublishSubject<[Element]>()
|
||||
}
|
||||
return elementsSubject
|
||||
}
|
||||
|
||||
public mutating func rx_events() -> Observable<EventType> {
|
||||
if eventSubject == nil {
|
||||
self.eventSubject = PublishSubject<EventType>()
|
||||
}
|
||||
return eventSubject
|
||||
}
|
||||
|
||||
private func arrayDidChange(event: EventType) {
|
||||
elementsSubject?.onNext(elements)
|
||||
eventSubject?.onNext(event)
|
||||
}
|
||||
}
|
||||
|
||||
extension ObservableArray: Indexable {
|
||||
public var startIndex: Int {
|
||||
return elements.startIndex
|
||||
}
|
||||
|
||||
public var endIndex: Int {
|
||||
return elements.endIndex
|
||||
}
|
||||
}
|
||||
|
||||
extension ObservableArray: RangeReplaceableCollectionType {
|
||||
public var capacity: Int {
|
||||
return elements.capacity
|
||||
}
|
||||
|
||||
public mutating func reserveCapacity(minimumCapacity: Int) {
|
||||
elements.reserveCapacity(minimumCapacity)
|
||||
}
|
||||
|
||||
public mutating func append(newElement: Element) {
|
||||
elements.append(newElement)
|
||||
arrayDidChange(ArrayChangeEvent(inserted: [elements.count - 1]))
|
||||
}
|
||||
|
||||
public mutating func appendContentsOf<S : SequenceType where S.Generator.Element == Element>(newElements: S) {
|
||||
let end = elements.count
|
||||
elements.appendContentsOf(newElements)
|
||||
guard end != elements.count else {
|
||||
return
|
||||
}
|
||||
arrayDidChange(ArrayChangeEvent(inserted: Array(end..<elements.count)))
|
||||
}
|
||||
|
||||
public mutating func appendContentsOf<C : CollectionType where C.Generator.Element == Element>(newElements: C) {
|
||||
guard !newElements.isEmpty else {
|
||||
return
|
||||
}
|
||||
let end = elements.count
|
||||
elements.appendContentsOf(newElements)
|
||||
arrayDidChange(ArrayChangeEvent(inserted: Array(end..<elements.count)))
|
||||
}
|
||||
|
||||
public mutating func removeLast() -> Element {
|
||||
let e = elements.removeLast()
|
||||
arrayDidChange(ArrayChangeEvent(deleted: [elements.count]))
|
||||
return e
|
||||
}
|
||||
|
||||
public mutating func insert(newElement: Element, atIndex i: Int) {
|
||||
elements.insert(newElement, atIndex: i)
|
||||
arrayDidChange(ArrayChangeEvent(inserted: [i]))
|
||||
}
|
||||
|
||||
public mutating func removeAtIndex(index: Int) -> Element {
|
||||
let e = elements.removeAtIndex(index)
|
||||
arrayDidChange(ArrayChangeEvent(deleted: [index]))
|
||||
return e
|
||||
}
|
||||
|
||||
public mutating func removeAll(keepCapacity: Bool = false) {
|
||||
guard !elements.isEmpty else {
|
||||
return
|
||||
}
|
||||
let es = elements
|
||||
elements.removeAll(keepCapacity: keepCapacity)
|
||||
arrayDidChange(ArrayChangeEvent(deleted: Array(0..<es.count)))
|
||||
}
|
||||
|
||||
public mutating func insertContentsOf(newElements: [Element], atIndex i: Int) {
|
||||
guard !newElements.isEmpty else {
|
||||
return
|
||||
}
|
||||
elements.insertContentsOf(newElements, at: i)
|
||||
arrayDidChange(ArrayChangeEvent(inserted: Array(i..<i + newElements.count)))
|
||||
}
|
||||
|
||||
public mutating func replaceRange<C : CollectionType where C.Generator.Element == Element>(subRange: Range<Int>, with newCollection: C) {
|
||||
let oldCount = elements.count
|
||||
elements.replaceRange(subRange, with: newCollection)
|
||||
guard let first = subRange.first else {
|
||||
return
|
||||
}
|
||||
let newCount = elements.count
|
||||
let end = first + (newCount - oldCount) + subRange.count
|
||||
arrayDidChange(ArrayChangeEvent(inserted: Array(first..<end),
|
||||
deleted: Array(subRange)))
|
||||
}
|
||||
|
||||
public mutating func popLast() -> Element? {
|
||||
let e = elements.popLast()
|
||||
if e != nil {
|
||||
arrayDidChange(ArrayChangeEvent(deleted: [elements.count]))
|
||||
}
|
||||
return e
|
||||
}
|
||||
}
|
||||
|
||||
extension ObservableArray: CustomDebugStringConvertible {
|
||||
public var description: String {
|
||||
return elements.description
|
||||
}
|
||||
}
|
||||
|
||||
extension ObservableArray: CustomStringConvertible {
|
||||
public var debugDescription: String {
|
||||
return elements.debugDescription
|
||||
}
|
||||
}
|
||||
|
||||
extension ObservableArray: CollectionType {
|
||||
public subscript(index: Int) -> Element {
|
||||
get {
|
||||
return elements[index]
|
||||
}
|
||||
set {
|
||||
elements[index] = newValue
|
||||
if index == elements.count {
|
||||
arrayDidChange(ArrayChangeEvent(inserted: [index]))
|
||||
} else {
|
||||
arrayDidChange(ArrayChangeEvent(updated: [index]))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public subscript(bounds: Range<Int>) -> ArraySlice<Element> {
|
||||
get {
|
||||
return elements[bounds]
|
||||
}
|
||||
set {
|
||||
elements[bounds] = newValue
|
||||
guard let first = bounds.first else {
|
||||
return
|
||||
}
|
||||
arrayDidChange(ArrayChangeEvent(inserted: Array(first..<first + newValue.count),
|
||||
deleted: Array(bounds)))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,14 +3,10 @@ import RxSwift
|
||||
|
||||
public class Group: Node {
|
||||
|
||||
public let contentsVar: Variable<[Node]>
|
||||
public var contents: [Node] {
|
||||
get { return contentsVar.value }
|
||||
set(val) { contentsVar.value = val }
|
||||
}
|
||||
public var contents: ObservableArray<Node>
|
||||
|
||||
public init(contents: [Node] = [], pos: Transform = Transform(), opaque: NSObject = true, visible: NSObject = true, clip: Locus? = nil, tag: [String] = []) {
|
||||
self.contentsVar = Variable<[Node]>(contents)
|
||||
self.contents = ObservableArray<Node>(array: contents)
|
||||
super.init(
|
||||
pos: pos,
|
||||
opaque: opaque,
|
||||
|
||||
@@ -20,13 +20,13 @@ class GroupRenderer: NodeRenderer {
|
||||
func onGroupChange(new: [Node]) {
|
||||
ctx.view.setNeedsDisplay()
|
||||
}
|
||||
group.contentsVar.asObservable().subscribeNext { new in
|
||||
onGroupChange(new)
|
||||
group.contents.rx_events().subscribeNext { new in
|
||||
onGroupChange(self.group.contents.elements)
|
||||
}.addDisposableTo(disposeBag)
|
||||
}
|
||||
|
||||
func render() {
|
||||
let contentRenderers = group.contents.map { RenderUtils.createNodeRenderer($0, context: ctx) }
|
||||
let contentRenderers = self.group.contents.map { RenderUtils.createNodeRenderer($0, context: ctx) }
|
||||
contentRenderers.forEach { renderer in
|
||||
if let rendererVal = renderer {
|
||||
CGContextSaveGState(ctx.cgContext)
|
||||
|
||||
Reference in New Issue
Block a user