fbchisellldbviewhelpers.py (112 lines of code) (raw):

#!/usr/bin/python # Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved # # This source code is licensed under the MIT license found in the # LICENSE file in the root directory of this source tree. import fbchisellldbbase as fb import fbchisellldbobjcruntimehelpers as runtimeHelpers def flushCoreAnimationTransaction(): fb.evaluateEffect("[CATransaction flush]") def setViewHidden(object, hidden): fb.evaluateEffect("[{} setHidden:{}]".format(object, int(hidden))) flushCoreAnimationTransaction() def maskView(viewOrLayer, color, alpha): unmaskView(viewOrLayer) window = fb.evaluateExpression( "(UIWindow *)[[UIApplication sharedApplication] keyWindow]" ) origin = convertPoint(0, 0, viewOrLayer, window) size = fb.evaluateExpressionValue( "(CGSize)((CGRect)[(id)%s frame]).size" % viewOrLayer ) rectExpr = "(CGRect){{%s, %s}, {%s, %s}}" % ( origin.GetChildMemberWithName("x").GetValue(), origin.GetChildMemberWithName("y").GetValue(), size.GetChildMemberWithName("width").GetValue(), size.GetChildMemberWithName("height").GetValue(), ) mask = fb.evaluateExpression("(id)[[UIView alloc] initWithFrame:%s]" % rectExpr) fb.evaluateEffect("[%s setTag:(NSInteger)%s]" % (mask, viewOrLayer)) fb.evaluateEffect("[%s setBackgroundColor:[UIColor %sColor]]" % (mask, color)) fb.evaluateEffect("[%s setAlpha:(CGFloat)%s]" % (mask, alpha)) fb.evaluateEffect("[%s addSubview:%s]" % (window, mask)) flushCoreAnimationTransaction() def unmaskView(viewOrLayer): window = fb.evaluateExpression( "(UIWindow *)[[UIApplication sharedApplication] keyWindow]" ) mask = fb.evaluateExpression( "(UIView *)[%s viewWithTag:(NSInteger)%s]" % (window, viewOrLayer) ) fb.evaluateEffect("[%s removeFromSuperview]" % mask) flushCoreAnimationTransaction() def convertPoint(x, y, fromViewOrLayer, toViewOrLayer): fromLayer = convertToLayer(fromViewOrLayer) toLayer = convertToLayer(toViewOrLayer) return fb.evaluateExpressionValue( "(CGPoint)[%s convertPoint:(CGPoint){ .x = %s, .y = %s } toLayer:(CALayer *)%s]" % (fromLayer, x, y, toLayer) ) def convertToLayer(viewOrLayer): if fb.evaluateBooleanExpression( "[(id)%s isKindOfClass:(Class)[CALayer class]]" % viewOrLayer ): return viewOrLayer elif fb.evaluateBooleanExpression( "[(id)%s respondsToSelector:(SEL)@selector(layer)]" % viewOrLayer ): return fb.evaluateExpression("(CALayer *)[%s layer]" % viewOrLayer) else: raise Exception("Argument must be a CALayer, UIView, or NSView.") def isUIView(obj): return not runtimeHelpers.isMacintoshArch() and fb.evaluateBooleanExpression( "[(id)%s isKindOfClass:(Class)[UIView class]]" % obj ) def isNSView(obj): return runtimeHelpers.isMacintoshArch() and fb.evaluateBooleanExpression( "[(id)%s isKindOfClass:(Class)[NSView class]]" % obj ) def isView(obj): return isUIView(obj) or isNSView(obj) # Generates a BFS of the views tree starting at the given view as root. # Yields a tuple of the current view in the tree and its level (view, level) def subviewsOfView(view): views = [(view, 0)] yield views[0] while views: (view, level) = views.pop(0) subviews = fb.evaluateExpression("(id)[%s subviews]" % view) subviewsCount = int(fb.evaluateExpression("(int)[(id)%s count]" % subviews)) for i in range(subviewsCount): subview = fb.evaluateExpression("(id)[%s objectAtIndex:%i]" % (subviews, i)) views.append((subview, level + 1)) yield (subview, level + 1) def upwardsRecursiveDescription(view, maxDepth=0): if not fb.evaluateBooleanExpression( "[(id)%s isKindOfClass:(Class)[UIView class]]" % view ) and not fb.evaluateBooleanExpression( "[(id)%s isKindOfClass:(Class)[NSView class]]" % view ): return None currentView = view recursiveDescription = [] depth = 0 while currentView and (maxDepth <= 0 or depth <= maxDepth): depth += 1 viewDescription = fb.evaluateExpressionValue( "(id)[%s debugDescription]" % (currentView) ).GetObjectDescription() currentView = fb.evaluateExpression("(void*)[%s superview]" % (currentView)) try: if int(currentView, 0) == 0: currentView = None except Exception: currentView = None if viewDescription: recursiveDescription.insert(0, viewDescription) if not len(viewDescription): return None currentPrefix = "" builder = "" for viewDescription in recursiveDescription: builder += currentPrefix + viewDescription + "\n" currentPrefix += " | " return builder def slowAnimation(speed=1): fb.evaluateEffect( '[[[UIApplication sharedApplication] windows] setValue:@(%s) forKeyPath:@"layer.speed"]' % speed )