mirror of
https://github.com/SoPat712/YTLitePlus.git
synced 2025-08-25 03:48:51 -04:00
added files via upload
This commit is contained in:
304
Tweaks/FLEX/ViewHierarchy/SnapshotExplorer/FHSSnapshotView.m
Normal file
304
Tweaks/FLEX/ViewHierarchy/SnapshotExplorer/FHSSnapshotView.m
Normal file
@@ -0,0 +1,304 @@
|
||||
//
|
||||
// FHSSnapshotView.m
|
||||
// FLEX
|
||||
//
|
||||
// Created by Tanner Bennett on 1/7/20.
|
||||
// Copyright © 2020 FLEX Team. All rights reserved.
|
||||
//
|
||||
|
||||
#import "FHSSnapshotView.h"
|
||||
#import "FHSSnapshotNodes.h"
|
||||
#import "SceneKit+Snapshot.h"
|
||||
#import "FLEXColor.h"
|
||||
|
||||
@interface FHSSnapshotView ()
|
||||
@property (nonatomic, readonly) SCNView *sceneView;
|
||||
@property (nonatomic) NSString *currentSummary;
|
||||
|
||||
/// Maps nodes by snapshot IDs
|
||||
@property (nonatomic) NSDictionary<NSString *, FHSSnapshotNodes *> *nodesMap;
|
||||
@property (nonatomic) NSInteger maxDepth;
|
||||
|
||||
@property (nonatomic) FHSSnapshotNodes *highlightedNodes;
|
||||
@property (nonatomic, getter=wantsHideHeaders) BOOL hideHeaders;
|
||||
@property (nonatomic, getter=wantsHideBorders) BOOL hideBorders;
|
||||
@property (nonatomic) BOOL suppressSelectionEvents;
|
||||
|
||||
@property (nonatomic, readonly) BOOL mustHideHeaders;
|
||||
@end
|
||||
|
||||
@implementation FHSSnapshotView
|
||||
|
||||
#pragma mark - Initialization
|
||||
|
||||
+ (instancetype)delegate:(id<FHSSnapshotViewDelegate>)delegate {
|
||||
FHSSnapshotView *view = [self new];
|
||||
view.delegate = delegate;
|
||||
return view;
|
||||
}
|
||||
|
||||
- (id)initWithFrame:(CGRect)frame {
|
||||
self = [super initWithFrame:CGRectZero];
|
||||
if (self) {
|
||||
[self initSpacingSlider];
|
||||
[self initDepthSlider];
|
||||
[self initSceneView]; // Must be last; calls setMaxDepth
|
||||
// self.hideHeaders = YES;
|
||||
|
||||
// Self
|
||||
self.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
|
||||
|
||||
// Scene
|
||||
self.sceneView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
|
||||
[self addGestureRecognizer:[[UITapGestureRecognizer alloc]
|
||||
initWithTarget:self action:@selector(handleTap:)
|
||||
]];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)initSceneView {
|
||||
_sceneView = [SCNView new];
|
||||
self.sceneView.allowsCameraControl = YES;
|
||||
|
||||
[self addSubview:self.sceneView];
|
||||
}
|
||||
|
||||
- (void)initSpacingSlider {
|
||||
_spacingSlider = [UISlider new];
|
||||
self.spacingSlider.minimumValue = 0;
|
||||
self.spacingSlider.maximumValue = 100;
|
||||
self.spacingSlider.continuous = YES;
|
||||
[self.spacingSlider
|
||||
addTarget:self
|
||||
action:@selector(spacingSliderDidChange:)
|
||||
forControlEvents:UIControlEventValueChanged
|
||||
];
|
||||
|
||||
self.spacingSlider.value = 50;
|
||||
}
|
||||
|
||||
- (void)initDepthSlider {
|
||||
_depthSlider = [FHSRangeSlider new];
|
||||
[self.depthSlider
|
||||
addTarget:self
|
||||
action:@selector(depthSliderDidChange:)
|
||||
forControlEvents:UIControlEventValueChanged
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
#pragma mark - Public
|
||||
|
||||
- (void)setSelectedView:(FHSViewSnapshot *)view {
|
||||
// Ivar set in selectSnapshot:
|
||||
[self selectSnapshot:view ? self.nodesMap[view.view.identifier] : nil];
|
||||
}
|
||||
|
||||
- (void)setSnapshots:(NSArray<FHSViewSnapshot *> *)snapshots {
|
||||
_snapshots = snapshots;
|
||||
|
||||
// Create new scene (possibly discarding old scene)
|
||||
SCNScene *scene = [SCNScene new];
|
||||
scene.background.contents = FLEXColor.primaryBackgroundColor;
|
||||
self.sceneView.scene = scene;
|
||||
|
||||
NSInteger depth = 0;
|
||||
NSMutableDictionary *nodesMap = [NSMutableDictionary new];
|
||||
|
||||
// Add every root snapshot to the root scene node with increasing depths
|
||||
SCNNode *root = scene.rootNode;
|
||||
for (FHSViewSnapshot *snapshot in self.snapshots) {
|
||||
[SCNNode
|
||||
snapshot:snapshot
|
||||
parent:nil
|
||||
parentNode:nil
|
||||
root:root
|
||||
depth:&depth
|
||||
nodesMap:nodesMap
|
||||
hideHeaders:_hideHeaders
|
||||
];
|
||||
}
|
||||
|
||||
self.maxDepth = depth;
|
||||
self.nodesMap = nodesMap;
|
||||
}
|
||||
|
||||
- (void)setHeaderExclusions:(NSArray<Class> *)headerExclusions {
|
||||
_headerExclusions = headerExclusions;
|
||||
|
||||
if (headerExclusions.count) {
|
||||
for (FHSSnapshotNodes *nodes in self.nodesMap.allValues) {
|
||||
if ([headerExclusions containsObject:nodes.snapshotItem.view.view.class]) {
|
||||
nodes.forceHideHeader = YES;
|
||||
} else {
|
||||
nodes.forceHideHeader = NO;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void)emphasizeViews:(NSArray<UIView *> *)emphasizedViews {
|
||||
if (emphasizedViews.count) {
|
||||
[self emphasizeViews:emphasizedViews inSnapshots:self.snapshots];
|
||||
[self setNeedsLayout];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)emphasizeViews:(NSArray<UIView *> *)emphasizedViews inSnapshots:(NSArray<FHSViewSnapshot *> *)snapshots {
|
||||
for (FHSViewSnapshot *snapshot in snapshots) {
|
||||
FHSSnapshotNodes *nodes = self.nodesMap[snapshot.view.identifier];
|
||||
nodes.dimmed = ![emphasizedViews containsObject:snapshot.view.view];
|
||||
[self emphasizeViews:emphasizedViews inSnapshots:snapshot.children];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)toggleShowHeaders {
|
||||
self.hideHeaders = !self.hideHeaders;
|
||||
}
|
||||
|
||||
- (void)toggleShowBorders {
|
||||
self.hideBorders = !self.hideBorders;
|
||||
}
|
||||
|
||||
- (void)hideView:(FHSViewSnapshot *)view {
|
||||
NSParameterAssert(view);
|
||||
FHSSnapshotNodes *nodes = self.nodesMap[view.view.identifier];
|
||||
[nodes.snapshot removeFromParentNode];
|
||||
}
|
||||
|
||||
#pragma mark - Helper
|
||||
|
||||
- (BOOL)mustHideHeaders {
|
||||
return self.spacingSlider.value <= kFHSSmallZOffset;
|
||||
}
|
||||
|
||||
- (void)setMaxDepth:(NSInteger)maxDepth {
|
||||
_maxDepth = maxDepth;
|
||||
|
||||
self.depthSlider.allowedMinValue = 0;
|
||||
self.depthSlider.allowedMaxValue = maxDepth;
|
||||
self.depthSlider.maxValue = maxDepth;
|
||||
self.depthSlider.minValue = 0;
|
||||
}
|
||||
|
||||
- (void)setHideHeaders:(BOOL)hideHeaders {
|
||||
if (_hideHeaders != hideHeaders) {
|
||||
_hideHeaders = hideHeaders;
|
||||
|
||||
if (!self.mustHideHeaders) {
|
||||
if (hideHeaders) {
|
||||
[self hideHeaders];
|
||||
} else {
|
||||
[self unhideHeaders];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void)setHideBorders:(BOOL)hideBorders {
|
||||
if (_hideBorders != hideBorders) {
|
||||
_hideBorders = hideBorders;
|
||||
|
||||
for (FHSSnapshotNodes *nodes in self.nodesMap.allValues) {
|
||||
nodes.border.hidden = hideBorders;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (FHSSnapshotNodes *)nodesAtPoint:(CGPoint)point {
|
||||
NSArray<SCNHitTestResult *> *results = [self.sceneView hitTest:point options:nil];
|
||||
for (SCNHitTestResult *result in results) {
|
||||
SCNNode *nearestSnapshot = result.node.nearestAncestorSnapshot;
|
||||
if (nearestSnapshot) {
|
||||
return self.nodesMap[nearestSnapshot.name];
|
||||
}
|
||||
}
|
||||
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (void)selectSnapshot:(FHSSnapshotNodes *)selected {
|
||||
// Notify delegate of de-select
|
||||
if (!selected && self.selectedView) {
|
||||
[self.delegate didDeselectView:self.selectedView];
|
||||
}
|
||||
|
||||
_selectedView = selected.snapshotItem;
|
||||
|
||||
// Case: selected the currently selected node
|
||||
if (selected == self.highlightedNodes) {
|
||||
return;
|
||||
}
|
||||
|
||||
// No-op if nothng is selected (yay objc!)
|
||||
self.highlightedNodes.highlighted = NO;
|
||||
self.highlightedNodes = nil;
|
||||
|
||||
// No node means we tapped the background
|
||||
if (selected) {
|
||||
selected.highlighted = YES;
|
||||
// TODO: update description text here
|
||||
self.highlightedNodes = selected;
|
||||
}
|
||||
|
||||
// Notify delegate
|
||||
[self.delegate didSelectView:selected.snapshotItem];
|
||||
|
||||
[self setNeedsLayout];
|
||||
}
|
||||
|
||||
- (void)hideHeaders {
|
||||
for (FHSSnapshotNodes *nodes in self.nodesMap.allValues) {
|
||||
nodes.header.hidden = YES;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)unhideHeaders {
|
||||
for (FHSSnapshotNodes *nodes in self.nodesMap.allValues) {
|
||||
if (!nodes.forceHideHeader) {
|
||||
nodes.header.hidden = NO;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#pragma mark - Event Handlers
|
||||
|
||||
- (void)handleTap:(UITapGestureRecognizer *)gesture {
|
||||
if (gesture.state == UIGestureRecognizerStateRecognized) {
|
||||
CGPoint tap = [gesture locationInView:self.sceneView];
|
||||
[self selectSnapshot:[self nodesAtPoint:tap]];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)spacingSliderDidChange:(UISlider *)slider {
|
||||
// TODO: hiding the header when flat logic
|
||||
|
||||
for (FHSSnapshotNodes *nodes in self.nodesMap.allValues) {
|
||||
nodes.snapshot.position = ({
|
||||
SCNVector3 pos = nodes.snapshot.position;
|
||||
pos.z = MAX(slider.value, kFHSSmallZOffset) * nodes.depth;
|
||||
pos;
|
||||
});
|
||||
|
||||
if (!self.wantsHideHeaders) {
|
||||
if (self.mustHideHeaders) {
|
||||
[self hideHeaders];
|
||||
} else {
|
||||
[self unhideHeaders];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void)depthSliderDidChange:(FHSRangeSlider *)slider {
|
||||
CGFloat min = slider.minValue, max = slider.maxValue;
|
||||
for (FHSSnapshotNodes *nodes in self.nodesMap.allValues) {
|
||||
CGFloat depth = nodes.depth;
|
||||
nodes.snapshot.hidden = depth < min || max < depth;
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
Reference in New Issue
Block a user