HoverButton.m 2.7 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798
  1. // Copyright (c) 2010 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #import "HoverButton.h"
  5. @implementation HoverButton {
  6. @private
  7. // Tracking area for button mouseover states.
  8. NSTrackingArea* trackingArea_;
  9. }
  10. - (id)initWithFrame:(NSRect)frameRect {
  11. if ((self = [super initWithFrame:frameRect])) {
  12. [self setTrackingEnabled:YES];
  13. hoverState_ = kHoverStateNone;
  14. [self updateTrackingAreas];
  15. }
  16. return self;
  17. }
  18. - (void)awakeFromNib {
  19. [self setTrackingEnabled:YES];
  20. hoverState_ = kHoverStateNone;
  21. [self updateTrackingAreas];
  22. }
  23. - (void)dealloc {
  24. [self setTrackingEnabled:NO];
  25. }
  26. - (void)mouseEntered:(NSEvent*)theEvent {
  27. hoverState_ = kHoverStateMouseOver;
  28. [self setNeedsDisplay:YES];
  29. }
  30. - (void)mouseExited:(NSEvent*)theEvent {
  31. hoverState_ = kHoverStateNone;
  32. [self setNeedsDisplay:YES];
  33. }
  34. - (void)mouseDown:(NSEvent*)theEvent {
  35. hoverState_ = kHoverStateMouseDown;
  36. [self setNeedsDisplay:YES];
  37. // The hover button needs to hold onto itself here for a bit. Otherwise,
  38. // it can be freed while |super mouseDown:| is in it's loop, and the
  39. // |checkImageState| call will crash.
  40. // http://crbug.com/28220
  41. // scoped_nsobject<HoverButton> myself([self retain]);
  42. [super mouseDown:theEvent];
  43. // We need to check the image state after the mouseDown event loop finishes.
  44. // It's possible that we won't get a mouseExited event if the button was
  45. // moved under the mouse during tab resize, instead of the mouse moving over
  46. // the button.
  47. // http://crbug.com/31279
  48. [self checkImageState];
  49. }
  50. - (void)setTrackingEnabled:(BOOL)enabled {
  51. if (enabled) {
  52. trackingArea_ = [[NSTrackingArea alloc] initWithRect:[self bounds]
  53. options:NSTrackingMouseEnteredAndExited | NSTrackingActiveAlways
  54. owner:self
  55. userInfo:nil];
  56. [self addTrackingArea:trackingArea_];
  57. // If you have a separate window that overlaps the close button, and you
  58. // move the mouse directly over the close button without entering another
  59. // part of the tab strip, we don't get any mouseEntered event since the
  60. // tracking area was disabled when we entered.
  61. [self checkImageState];
  62. } else if (trackingArea_) {
  63. [self removeTrackingArea:trackingArea_];
  64. trackingArea_ = nil;
  65. }
  66. }
  67. - (void)updateTrackingAreas {
  68. [super updateTrackingAreas];
  69. [self checkImageState];
  70. }
  71. - (void)checkImageState {
  72. if (!trackingArea_)
  73. return;
  74. // Update the button's state if the button has moved.
  75. NSPoint mouseLoc = [[self window] mouseLocationOutsideOfEventStream];
  76. mouseLoc = [self convertPoint:mouseLoc fromView:nil];
  77. hoverState_ = NSPointInRect(mouseLoc, [self bounds]) ?
  78. kHoverStateMouseOver : kHoverStateNone;
  79. [self setNeedsDisplay:YES];
  80. }
  81. @end