| // Copyright 2020 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #import "ios/chrome/common/ui/util/pointer_interaction_util.h" |
| |
| #import <ostream> |
| |
| #import "base/logging.h" |
| |
| namespace { |
| // Returns a pointer style with a hover effect with a slight tint and no pointer |
| // shape (i.e., the pointer stays the same). |
| UIPointerStyle* CreateHoverEffectNoShapePointerStyle(UIButton* button) { |
| UITargetedPreview* preview = [[UITargetedPreview alloc] initWithView:button]; |
| UIPointerHoverEffect* effect = |
| [UIPointerHoverEffect effectWithPreview:preview]; |
| effect.preferredTintMode = UIPointerEffectTintModeOverlay; |
| effect.prefersScaledContent = NO; |
| effect.prefersShadow = NO; |
| return [UIPointerStyle styleWithEffect:effect shape:nil]; |
| } |
| |
| // Returns a pointer style with a highlight effect and a rounded rectangle |
| // pointer shape sized to the button frame. |
| UIPointerStyle* CreateHighlightEffectRectShapePointerStyle(UIButton* button) { |
| UITargetedPreview* preview = [[UITargetedPreview alloc] initWithView:button]; |
| UIPointerHighlightEffect* effect = |
| [UIPointerHighlightEffect effectWithPreview:preview]; |
| UIPointerShape* shape = [UIPointerShape shapeWithRoundedRect:button.frame]; |
| return [UIPointerStyle styleWithEffect:effect shape:shape]; |
| } |
| } // namespace |
| |
| UIButtonPointerStyleProvider CreateDefaultEffectCirclePointerStyleProvider() { |
| return ^UIPointerStyle*(UIButton* button, UIPointerEffect* proposedEffect, |
| UIPointerShape* proposedShape) { |
| CGRect frame = button.frame; |
| if (abs(frame.size.width - frame.size.height) > 0.5) { |
| LOG(ERROR) << "Button frame for circular pointer isn't square: (" |
| << frame.size.width << " x " << frame.size.height << ")"; |
| } |
| UIBezierPath* path = [UIBezierPath bezierPathWithOvalInRect:frame]; |
| UIPointerShape* shape = [UIPointerShape shapeWithPath:path]; |
| return [UIPointerStyle styleWithEffect:proposedEffect shape:shape]; |
| }; |
| } |
| |
| UIButtonPointerStyleProvider CreateLiftEffectCirclePointerStyleProvider() { |
| return ^UIPointerStyle*(UIButton* button, UIPointerEffect* proposedEffect, |
| UIPointerShape* proposedShape) { |
| CGRect frame = button.frame; |
| if (abs(frame.size.width - frame.size.height) > 0.5) { |
| LOG(ERROR) << "Button frame for circular pointer isn't square: (" |
| << frame.size.width << " x " << frame.size.height << ")"; |
| } |
| UITargetedPreview* preview = |
| [[UITargetedPreview alloc] initWithView:button]; |
| UIPointerLiftEffect* effect = |
| [UIPointerLiftEffect effectWithPreview:preview]; |
| UIBezierPath* path = [UIBezierPath bezierPathWithOvalInRect:frame]; |
| UIPointerShape* shape = [UIPointerShape shapeWithPath:path]; |
| return [UIPointerStyle styleWithEffect:effect shape:shape]; |
| }; |
| } |
| |
| UIButtonPointerStyleProvider CreateOpaqueButtonPointerStyleProvider() { |
| return ^UIPointerStyle*(UIButton* button, UIPointerEffect* proposedEffect, |
| UIPointerShape* proposedShape) { |
| if (!button.backgroundColor || |
| button.backgroundColor == [UIColor clearColor]) { |
| LOG(ERROR) << "Expected an opaque background for button."; |
| } |
| return CreateHoverEffectNoShapePointerStyle(button); |
| }; |
| } |
| |
| UIButtonPointerStyleProvider CreateTransparentButtonPointerStyleProvider() { |
| return ^UIPointerStyle*(UIButton* button, UIPointerEffect* proposedEffect, |
| UIPointerShape* proposedShape) { |
| if (button.backgroundColor && |
| button.backgroundColor != [UIColor clearColor]) { |
| LOG(ERROR) << "Expected a transparent background for button."; |
| } |
| return CreateHighlightEffectRectShapePointerStyle(button); |
| }; |
| } |
| |
| UIButtonPointerStyleProvider |
| CreateOpaqueOrTransparentButtonPointerStyleProvider() { |
| return ^UIPointerStyle*(UIButton* button, UIPointerEffect* proposedEffect, |
| UIPointerShape* proposedShape) { |
| if (button.backgroundColor && |
| button.backgroundColor != [UIColor clearColor]) { |
| return CreateHoverEffectNoShapePointerStyle(button); |
| } |
| return CreateHighlightEffectRectShapePointerStyle(button); |
| }; |
| } |
| |
| @interface ViewPointerInteraction () |
| @property(nonatomic, strong) UIPointerInteraction* pointerInteraction; |
| @end |
| |
| @implementation ViewPointerInteraction |
| |
| - (instancetype)init { |
| self = [super init]; |
| if (self) { |
| self.pointerInteraction = |
| [[UIPointerInteraction alloc] initWithDelegate:self]; |
| } |
| return self; |
| } |
| |
| #pragma mark UIInteraction |
| |
| - (__kindof UIView*)view { |
| return [self.pointerInteraction view]; |
| } |
| |
| - (void)didMoveToView:(UIView*)view { |
| [self.pointerInteraction didMoveToView:view]; |
| } |
| |
| - (void)willMoveToView:(UIView*)view { |
| [self.pointerInteraction willMoveToView:view]; |
| } |
| |
| #pragma mark UIPointerInteractionDelegate |
| |
| - (UIPointerRegion*)pointerInteraction:(UIPointerInteraction*)interaction |
| regionForRequest:(UIPointerRegionRequest*)request |
| defaultRegion:(UIPointerRegion*)defaultRegion { |
| return defaultRegion; |
| } |
| |
| - (UIPointerStyle*)pointerInteraction:(UIPointerInteraction*)interaction |
| styleForRegion:(UIPointerRegion*)region { |
| if (!interaction.view.window) { |
| return nil; |
| } |
| |
| UIPointerHoverEffect* effect = [UIPointerHoverEffect |
| effectWithPreview:[[UITargetedPreview alloc] |
| initWithView:interaction.view]]; |
| effect.prefersScaledContent = NO; |
| effect.prefersShadow = NO; |
| return [UIPointerStyle styleWithEffect:effect shape:nil]; |
| } |
| |
| @end |