blob: 4f82bf08b1399edbc82a44cc70969789941c2fc9 (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
|
// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#import "chrome/browser/cocoa/reload_button.h"
#include "base/nsimage_cache_mac.h"
#include "chrome/app/chrome_dll_resource.h"
#import "chrome/browser/cocoa/view_id_util.h"
namespace {
NSString* const kReloadImageName = @"reload_Template.pdf";
NSString* const kStopImageName = @"stop_Template.pdf";
} // namespace
@implementation ReloadButton
- (void)dealloc {
if (trackingArea_) {
[self removeTrackingArea:trackingArea_];
trackingArea_.reset();
}
[super dealloc];
}
- (void)updateTrackingAreas {
// If the mouse is hovering when the tracking area is updated, the
// control could end up locked into inappropriate behavior for
// awhile, so unwind state.
if (isMouseInside_)
[self mouseExited:nil];
if (trackingArea_) {
[self removeTrackingArea:trackingArea_];
trackingArea_.reset();
}
trackingArea_.reset([[NSTrackingArea alloc]
initWithRect:[self bounds]
options:(NSTrackingMouseEnteredAndExited |
NSTrackingActiveInActiveApp)
owner:self
userInfo:nil]);
[self addTrackingArea:trackingArea_];
}
- (void)awakeFromNib {
[self updateTrackingAreas];
// Don't allow multi-clicks, because the user probably wouldn't ever
// want to stop+reload or reload+stop.
[self setIgnoresMultiClick:YES];
}
- (void)setIsLoading:(BOOL)isLoading force:(BOOL)force {
pendingReloadMode_ = NO;
// Can always transition to stop mode. Only transition to reload
// mode if forced or if the mouse isn't hovering. Otherwise, note
// that reload mode is desired and make no change.
if (isLoading) {
[self setImage:nsimage_cache::ImageNamed(kStopImageName)];
[self setTag:IDC_STOP];
} else if (force || ![self isMouseInside]) {
[self setImage:nsimage_cache::ImageNamed(kReloadImageName)];
[self setTag:IDC_RELOAD];
} else if ([self tag] == IDC_STOP) {
pendingReloadMode_ = YES;
}
}
- (BOOL)sendAction:(SEL)theAction to:(id)theTarget {
if ([self tag] == IDC_STOP) {
// The stop command won't be valid after the attempt to change
// back to reload. But it "worked", so short-circuit it.
const BOOL ret =
pendingReloadMode_ ? YES : [super sendAction:theAction to:theTarget];
// When the stop is processed, immediately change to reload mode,
// even though the IPC still has to bounce off the renderer and
// back before the regular |-setIsLoaded:force:| will be called.
// [This is how views and gtk do it.]
if (ret)
[self setIsLoading:NO force:YES];
return ret;
}
return [super sendAction:theAction to:theTarget];
}
- (void)mouseEntered:(NSEvent*)theEvent {
isMouseInside_ = YES;
}
- (void)mouseExited:(NSEvent*)theEvent {
isMouseInside_ = NO;
// Reload mode was requested during the hover.
if (pendingReloadMode_)
[self setIsLoading:NO force:YES];
}
- (BOOL)isMouseInside {
return trackingArea_ && isMouseInside_;
}
- (ViewID)viewID {
return VIEW_ID_RELOAD_BUTTON;
}
@end // ReloadButton
@implementation ReloadButton (Testing)
- (NSTrackingArea*)trackingArea {
return trackingArea_;
}
@end
|