Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
84 changes: 59 additions & 25 deletions Stitch/Graph/LayerInspector/LayerInspectorView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ struct LayerInspectorView: View {
if !filteredInputs.isEmpty {
LayerInspectorInputsSectionView(
sectionName: sectionName,
layerInputs: filteredInputs,
layerInputs: .init(layerInputs: filteredInputs),
graph: graph,
nodeId: node
)
Expand Down Expand Up @@ -193,13 +193,59 @@ enum LayerInspectorSectionName: String, Equatable, Hashable {
typography = "Typography",
stroke = "Stroke",
rotation = "Rotation",
// shadow = "Shadow",
layerEffects = "Layer Effects"
}

// Named Tuple
typealias LayerInputAndObserver = (layerInput: LayerInputPort,
portObserver: LayerInputObserver)
@Observable
final class LayerInputAndObserver {
let layerInput: LayerInputPort
let portObserver: LayerInputObserver

init(layerInput: LayerInputPort,
portObserver: LayerInputObserver) {
self.layerInput = layerInput
self.portObserver = portObserver
}
}

@Observable
final class LayerInputsAndObservers {
let layerInputs: [LayerInputAndObserver]

init(layerInputs: [LayerInputAndObserver]) {
self.layerInputs = layerInputs
}
}

struct LayerInspectorInputView: View {

// `@Bindable var` (vs. `let`) seems to improve a strange issue where toggling scroll-enabled input on iPad would update the LayerInputObserver's blockedFields set but not re-render the view.
@Bindable var layerInput: LayerInputAndObserver
@Bindable var graph: GraphState
let nodeId: NodeId

var body: some View {
let layerInputObserver: LayerInputObserver = layerInput.portObserver

let blockedFields = layerInputObserver.blockedFields

let allFieldsBlockedOut = layerInputObserver
.fieldValueTypes.first?
.fieldObservers.allSatisfy({ $0.isBlocked(blockedFields)})
?? false

if !allFieldsBlockedOut {
LayerInspectorInputPortView(layerInputObserver: layerInputObserver,
graph: graph,
nodeId: nodeId)
.modifier(LayerPropertyRowOriginReader(graph: graph,
layerInput: layerInput.layerInput))
} else {
EmptyView()
}
}

}

// This view now needs to receive the inputs it will be listing,
// rather than receiving the entire layer node.
Expand All @@ -208,7 +254,7 @@ struct LayerInspectorInputsSectionView: View {
let sectionName: LayerInspectorSectionName

// This section's layer inputs, filtered to excluded any not supported by this specific layer.
let layerInputs: [LayerInputAndObserver]
@Bindable var layerInputs: LayerInputsAndObservers
@Bindable var graph: GraphState
let nodeId: NodeId

Expand All @@ -217,23 +263,10 @@ struct LayerInspectorInputsSectionView: View {

var body: some View {
Section(isExpanded: $expanded) {
ForEach(layerInputs, id: \.layerInput) { layerInput in
let layerInputObserver: LayerInputObserver = layerInput.portObserver

let blockedFields = layerInputObserver.blockedFields

let allFieldsBlockedOut = layerInputObserver
.fieldValueTypes.first?
.fieldObservers.allSatisfy({ $0.isBlocked(blockedFields)})
?? false

if !allFieldsBlockedOut {
LayerInspectorInputPortView(layerInputObserver: layerInputObserver,
graph: graph,
nodeId: nodeId)
.modifier(LayerPropertyRowOriginReader(graph: graph,
layerInput: layerInput.layerInput))
}
ForEach(layerInputs.layerInputs, id: \.layerInput) { (layerInput: LayerInputAndObserver) in
LayerInspectorInputView(layerInput: layerInput,
graph: graph,
nodeId: nodeId)
}
.transition(.slideInAndOut(edge: .top))
} header: {
Expand Down Expand Up @@ -267,7 +300,7 @@ struct LayerInspectorInputsSectionView: View {
self.expanded.toggle()
dispatch(LayerInspectorSectionToggled(section: sectionName))

layerInputs.forEach { layerInput in
layerInputs.layerInputs.forEach { layerInput in
if case let .layerInput(x) = graph.graphUI.propertySidebar.selectedProperty,
x.layerInput == layerInput.layerInput {
graph.graphUI.propertySidebar.selectedProperty = nil
Expand Down Expand Up @@ -328,6 +361,7 @@ extension GraphState {
node: NodeId,
inputs: LayerInputObserverDict,
outputs: [OutputLayerNodeRowData])? {
// log("getLayerInspectorData called")

// Any time orderedSidebarLayers changes, that will retrigger LayerInspector
guard !self.orderedSidebarLayers.isEmpty else {
Expand All @@ -336,7 +370,7 @@ extension GraphState {

var inspectorFocusedLayers = self.layersSidebarViewModel.selectionState.primary

log("getLayerInspectorData: inspectorFocusedLayers: \(inspectorFocusedLayers)")
// log("getLayerInspectorData: inspectorFocusedLayers: \(inspectorFocusedLayers)")

#if DEV_DEBUG
// For debug
Expand Down
2 changes: 1 addition & 1 deletion Stitch/Graph/Node/Model/RowData/LayerInputType.swift
Original file line number Diff line number Diff line change
Expand Up @@ -1570,7 +1570,7 @@ extension LayerInputPort {
case .deviceAppearance:
return useShortLabel ? "Appearance" : "Device Appearance"
case .scrollContentSize:
return "Content Size"
return useShortLabel ? "Content" : "Content Size"
case .scrollXEnabled:
return "Scroll X Enabled"
case .scrollJumpToXStyle:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,12 +51,11 @@ struct NativeScrollGestureView<T: View>: View {
@MainActor
var hasScrollInteraction: Bool {
let _hasScrollInteraction = layerViewModel.isScrollXEnabled || layerViewModel.isScrollYEnabled
log("NativeScrollGestureView: hasScrollInteraction: _hasScrollInteraction: \(_hasScrollInteraction)")
// log("NativeScrollGestureView: hasScrollInteraction: _hasScrollInteraction: \(_hasScrollInteraction)")
return _hasScrollInteraction
}

var body: some View {
// logInView("NativeScrollGestureView: var body")
if hasScrollInteraction {
view()
.modifier(NativeScrollGestureViewInner(
Expand Down Expand Up @@ -127,7 +126,6 @@ struct NativeScrollGestureViewInner: ViewModifier {
@State var viewId: UUID = .init()

func body(content: Content) -> some View {
// logInView("NativeScrollGestureViewInner: var body")

ScrollView(self.scrollAxes) {

Expand All @@ -138,8 +136,6 @@ struct NativeScrollGestureViewInner: ViewModifier {
.frame(height: self.customContentHeight)

// factor out parent-scroll's offset, so that view does not move unless we explicitly connect scroll interaction node's output to the layer's position input
// .offset(x: self.scrollOffset.x,
// y: self.scrollOffset.y)
.offset(x: self.finalScrollOffset.x,
y: self.finalScrollOffset.y)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -97,9 +97,5 @@ struct PreviewAbsoluteShapeLayerModifier: ViewModifier {
size: size,
parentSize: parentSize,
minimumDragDistance: DEFAULT_MINIMUM_DRAG_DISTANCE))

// .modifier(NativeScrollGestureView(
// layerViewModel: viewModel,
// graph: graph))
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -143,10 +143,6 @@ struct PreviewCommonModifierWithoutFrame: ViewModifier {
size: sizeForAnchoringAndGestures,
parentSize: parentSize,
minimumDragDistance: minimumDragDistance))

// .modifier(NativeScrollGestureView(
// layerViewModel: layerViewModel,
// graph: graph))
}
}

23 changes: 1 addition & 22 deletions Stitch/Graph/PrototypePreview/Layer/View/Type/PreviewGroup.swift
Original file line number Diff line number Diff line change
Expand Up @@ -121,8 +121,6 @@ struct PreviewGroupLayer: View {

var body: some View {

logInView("PreviewGroupLayer: var body")

groupLayer

// TODO: add "child alignment" input on Group Layer node? or find some other solution for how a group with an orientation can position children that have static sizes
Expand Down Expand Up @@ -242,30 +240,11 @@ struct PreviewGroupLayer: View {
size: _size,
parentSize: parentSize,
minimumDragDistance: DEFAULT_MINIMUM_DRAG_DISTANCE))

// .modifier(NativeScrollGestureView(
// layerViewModel: layerViewModel,
// graph: graph))
}

@ViewBuilder
private var groupLayer: some View {
logInView("PreviewGroupLayer: groupLayer")
// PreviewLayersView(document: document,
// graph: graph,
// layers: layersInGroup,
// // This Group's size will be the `parentSize` for the `layersInGroup`
// parentSize: _size,
// parentId: interactiveLayer.id.layerNodeId,
// parentOrientation: orientation,
// parentSpacing: spacing,
// parentCornerRadius: cornerRadius,
// // i.e. if this view (a LayerGroup) uses .hug, then its children will not use their own .position values.
// parentUsesHug: usesHug,
// noFixedSizeForLayerGroup: noFixedSizeForLayerGroup,
// parentGridData: gridData,
// isGhostView: !isPinnedViewRendering)


NativeScrollGestureView(layerViewModel: layerViewModel,
graph: graph,
isClipped: isClipped,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,15 @@ extension ProjectSidebarObservable {
func sidebarItemTapped(id: Self.ItemID,
shiftHeld: Bool,
commandHeld: Bool) {
log("sidebarItemTapped: id: \(id)")
log("sidebarItemTapped: shiftHeld: \(shiftHeld)")
// log("sidebarItemTapped: id: \(id)")
// log("sidebarItemTapped: shiftHeld: \(shiftHeld)")

let originalSelections = self.selectionState.primary

// Set sidebar to be focused:
self.graphDelegate?.graphUI.isSidebarFocused = true

log("sidebarItemTapped: originalSelections: \(originalSelections)")
// log("sidebarItemTapped: originalSelections: \(originalSelections)")

if shiftHeld, originalSelections.isEmpty {
// Special case: if no current selections, shift-click just selects from the top to the clicked item; and the shift-clicked item counts as the 'last selected item'
Expand All @@ -49,7 +49,7 @@ extension ProjectSidebarObservable {
!originalSelections.isEmpty,
let lastClickedItemId = self.selectionState.lastFocused {

log("sidebarItemTapped: shift select")
// log("sidebarItemTapped: shift select")

guard let clickedItem = self.retrieveItem(id),
let lastClickedItem = self.retrieveItem(lastClickedItemId) else {
Expand All @@ -58,7 +58,7 @@ extension ProjectSidebarObservable {
return
}

log("sidebarItemTapped: lastClickedItemId: \(lastClickedItemId)")
// log("sidebarItemTapped: lastClickedItemId: \(lastClickedItemId)")

let flatList = self.items.flattenedItems

Expand All @@ -84,12 +84,12 @@ extension ProjectSidebarObservable {
// If we ended up selecting the exact same as the original,
// then we actually DE-SELECTED the range.
let newSelections = self.selectionState.primary
log("sidebarItemTapped: selected range: newSelections: \(newSelections)")
// log("sidebarItemTapped: selected range: newSelections: \(newSelections)")
if newSelections == originalSelections {
log("sidebarItemTapped: selected range; will wipe inspectorFocusedLayers")
// log("sidebarItemTapped: selected range; will wipe inspectorFocusedLayers")

itemsBetween.forEach { itemBetween in
log("sidebarItemTapped: will remove item Between \(itemBetween)")
// log("sidebarItemTapped: will remove item Between \(itemBetween)")
self.selectionState.primary.remove(itemBetween.id)
}
}
Expand All @@ -99,11 +99,11 @@ extension ProjectSidebarObservable {
self.graphDelegate?.deselectAllCanvasItems()

} else {
log("sidebarItemTapped: did not have itemsBetween")
// log("sidebarItemTapped: did not have itemsBetween")
// TODO: this can happen when just-clicked == last-clicked, but some apps do not any deselection etc.
// If we shift click the last-clicked item, then remove everything in the island?
if clickedItem.id == lastClickedItem.id {
log("clicked the same item as the last clicked; will deselect original island and select only last selected")
// log("clicked the same item as the last clicked; will deselect original island and select only last selected")
originalIsland.forEach {
self.selectionState.primary.remove($0.id)
}
Expand All @@ -122,7 +122,7 @@ extension ProjectSidebarObservable {

else if commandHeld {

log("sidebarItemTapped: command select")
// log("sidebarItemTapped: command select")

let alreadySelected = self.selectionState.primary.contains(id)

Expand All @@ -141,7 +141,7 @@ extension ProjectSidebarObservable {
}

} else {
log("sidebarItemTapped: normal select")
// log("sidebarItemTapped: normal select")

self.selectionState.resetEditModeSelections()

Expand Down