OLD | NEW |
---|---|
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #import "chrome/browser/ui/cocoa/dev_tools_controller.h" | 5 #import "chrome/browser/ui/cocoa/dev_tools_controller.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 #include <cmath> | |
8 | 9 |
9 #include <Cocoa/Cocoa.h> | 10 #include <Cocoa/Cocoa.h> |
10 | 11 |
11 #include "base/prefs/pref_service.h" | 12 #include "base/prefs/pref_service.h" |
12 #include "chrome/browser/browser_process.h" | 13 #include "chrome/browser/browser_process.h" |
13 #include "chrome/browser/profiles/profile.h" | 14 #include "chrome/browser/profiles/profile.h" |
14 #import "chrome/browser/ui/cocoa/view_id_util.h" | 15 #import "chrome/browser/ui/cocoa/view_id_util.h" |
15 #include "chrome/common/pref_names.h" | 16 #include "chrome/common/pref_names.h" |
16 #include "content/public/browser/web_contents.h" | 17 #include "content/public/browser/web_contents.h" |
17 #include "content/public/browser/web_contents_view.h" | 18 #include "content/public/browser/web_contents_view.h" |
18 #include "ui/base/cocoa/focus_tracker.h" | 19 #include "ui/base/cocoa/focus_tracker.h" |
20 #include "ui/gfx/size_conversions.h" | |
19 | 21 |
20 using content::WebContents; | 22 using content::WebContents; |
21 | 23 |
22 @interface GraySplitView : NSSplitView { | 24 @interface DevToolsContainerView : NSView { |
23 BOOL dividerHidden_; | 25 NSSize topLeftContentsOffset_; |
26 NSSize bottomRightContentsOffset_; | |
27 NSView* devToolsView_; | |
28 NSView* contentsView_; | |
Avi (use Gerrit)
2013/12/09 16:13:36
Comment these as being weak (ownership via -subvie
dgozman
2013/12/10 14:51:47
Done.
| |
24 } | 29 } |
25 | 30 |
26 @property(assign, nonatomic) BOOL dividerHidden; | 31 - (void)setContentsOffsetsTopLeft:(NSSize)topLeft |
27 | 32 bottomRight:(NSSize)bottomRight; |
28 - (NSColor*)dividerColor; | 33 - (void)adjustSubviews; |
29 - (CGFloat)dividerThickness; | 34 - (void)resizeSubviewsWithOldSize:(NSSize)oldBoundsSize; |
Avi (use Gerrit)
2013/12/09 16:13:36
unused; remove
dgozman
2013/12/10 14:51:47
This is an NSView override. Removed from interface
| |
35 - (void)showDevTools:(NSView*)devToolsView; | |
36 - (void)hideDevTools; | |
30 | 37 |
31 @end | 38 @end |
32 | 39 |
33 | 40 |
34 @implementation GraySplitView | 41 @implementation DevToolsContainerView |
35 | 42 |
36 @synthesize dividerHidden = dividerHidden_; | 43 - (DevToolsContainerView*) initWithFrame:(NSRect)frame { |
Avi (use Gerrit)
2013/12/09 16:13:36
No space between ) and i.
dgozman
2013/12/10 14:51:47
Done.
| |
37 | 44 if (self = [super initWithFrame:frame]) { |
38 - (NSColor*)dividerColor { | 45 devToolsView_ = nil; |
39 return [NSColor darkGrayColor]; | 46 contentsView_ = nil; |
47 topLeftContentsOffset_ = NSZeroSize; | |
48 bottomRightContentsOffset_ = NSZeroSize; | |
Avi (use Gerrit)
2013/12/09 16:13:36
This initialization isn't needed; ivars start out
dgozman
2013/12/10 14:51:47
Done.
| |
49 } | |
50 return self; | |
40 } | 51 } |
41 | 52 |
42 - (CGFloat)dividerThickness { | 53 - (void)setContentsOffsetsTopLeft:(NSSize)topLeft |
43 return dividerHidden_ ? 0 : [super dividerThickness]; | 54 bottomRight:(NSSize)bottomRight { |
55 topLeftContentsOffset_ = topLeft; | |
56 bottomRightContentsOffset_ = bottomRight; | |
57 } | |
58 | |
59 - (void)resizeSubviewsWithOldSize:(NSSize)oldBoundsSize { | |
Avi (use Gerrit)
2013/12/09 16:13:36
unused; remove
dgozman
2013/12/10 14:51:47
This is NSView override invoked when view is resiz
Avi (use Gerrit)
2013/12/10 16:32:40
Oh.
| |
60 [self adjustSubviews]; | |
61 } | |
62 | |
63 - (void)showDevTools:(NSView*)devToolsView { | |
64 NSArray* subviews = [self subviews]; | |
65 DCHECK_EQ([subviews count], 1u); | |
Avi (use Gerrit)
2013/12/09 16:13:36
In DCHECK land, expected values are the first para
dgozman
2013/12/10 14:51:47
Done.
| |
66 contentsView_ = [subviews objectAtIndex:0]; | |
67 devToolsView_ = devToolsView; | |
68 // Place DevTools under contents. | |
69 [self addSubview:devToolsView positioned:NSWindowBelow relativeTo:nil]; | |
70 } | |
71 | |
72 - (void)hideDevTools { | |
73 DCHECK_EQ([[self subviews] count], 2u); | |
74 [devToolsView_ removeFromSuperview]; | |
75 contentsView_ = nil; | |
76 devToolsView_ = nil; | |
77 } | |
78 | |
79 - (void)adjustSubviews { | |
80 if (![[self subviews] count]) | |
81 return; | |
82 | |
83 if (!devToolsView_) { | |
84 DCHECK_EQ([[self subviews] count], 1u); | |
85 NSView* contents = [[self subviews] objectAtIndex:0]; | |
86 [contents setFrame:[self bounds]]; | |
87 return; | |
88 } | |
89 | |
90 DCHECK_EQ([[self subviews] count], 2u); | |
91 NSRect bounds = [self bounds]; | |
92 | |
93 [devToolsView_ setFrame:bounds]; | |
94 | |
95 CGFloat contentsWidth = std::max(0.f, NSWidth(bounds) - | |
96 topLeftContentsOffset_.width - bottomRightContentsOffset_.width); | |
97 CGFloat contentsHeight = std::max(0.f, NSHeight(bounds) - | |
98 topLeftContentsOffset_.height - bottomRightContentsOffset_.height); | |
99 CGFloat contentsTop = | |
100 std::min(topLeftContentsOffset_.height, NSHeight(bounds)); | |
101 CGFloat contentsLeft = | |
102 std::min(topLeftContentsOffset_.width, NSWidth(bounds)); | |
103 | |
104 [contentsView_ setFrame:NSMakeRect( | |
105 contentsLeft, | |
106 contentsTop, | |
107 contentsWidth, | |
108 contentsHeight)]; | |
Avi (use Gerrit)
2013/12/09 16:13:36
Weird wrapping; can you get this to be on one line
dgozman
2013/12/10 14:51:47
Done.
| |
44 } | 109 } |
45 | 110 |
46 @end | 111 @end |
47 | 112 |
48 @interface DevToolsController (Private) | 113 @interface DevToolsController (Private) |
49 - (void)showDevToolsContainer; | 114 - (void)showDevToolsView; |
50 - (void)hideDevToolsContainer; | 115 - (void)hideDevToolsView; |
51 - (void)updateDevToolsSplitPosition; | |
52 @end | 116 @end |
53 | 117 |
54 | 118 |
55 @implementation DevToolsController | 119 @implementation DevToolsController |
56 | 120 |
57 - (id)init { | 121 - (id)init { |
58 if ((self = [super init])) { | 122 if ((self = [super init])) { |
59 splitView_.reset([[GraySplitView alloc] initWithFrame:NSZeroRect]); | 123 devToolsContainerView_.reset( |
60 [splitView_ setDividerStyle:NSSplitViewDividerStyleThin]; | 124 [[DevToolsContainerView alloc] initWithFrame:NSZeroRect]); |
61 [splitView_ setVertical:NO]; | 125 [devToolsContainerView_ |
62 [splitView_ setAutoresizingMask:NSViewWidthSizable|NSViewHeightSizable]; | 126 setAutoresizingMask:NSViewWidthSizable|NSViewHeightSizable]; |
63 [splitView_ setDelegate:self]; | |
64 [splitView_ setDividerHidden:NO]; | |
65 | |
66 dockSide_ = DEVTOOLS_DOCK_SIDE_BOTTOM; | |
67 } | 127 } |
68 return self; | 128 return self; |
69 } | 129 } |
70 | 130 |
71 - (void)dealloc { | |
72 [splitView_ setDelegate:nil]; | |
73 [super dealloc]; | |
74 } | |
75 | |
76 - (NSView*)view { | 131 - (NSView*)view { |
77 return splitView_.get(); | 132 return devToolsContainerView_.get(); |
78 } | |
79 | |
80 - (NSSplitView*)splitView { | |
81 return splitView_.get(); | |
82 } | 133 } |
83 | 134 |
84 - (void)updateDevToolsForWebContents:(WebContents*)contents | 135 - (void)updateDevToolsForWebContents:(WebContents*)contents |
85 withProfile:(Profile*)profile { | 136 withProfile:(Profile*)profile { |
86 DevToolsWindow* newDevToolsWindow = contents ? | 137 DevToolsWindow* newDevToolsWindow = contents ? |
87 DevToolsWindow::GetDockedInstanceForInspectedTab(contents) : NULL; | 138 DevToolsWindow::GetDockedInstanceForInspectedTab(contents) : NULL; |
88 | 139 |
89 // Fast return in case of the same window having same orientation. | 140 bool shouldHide = devToolsWindow_ && devToolsWindow_ != newDevToolsWindow; |
90 if (devToolsWindow_ == newDevToolsWindow) { | 141 bool shouldShow = newDevToolsWindow && devToolsWindow_ != newDevToolsWindow; |
91 if (!newDevToolsWindow || | 142 |
92 (newDevToolsWindow->dock_side() == dockSide_)) { | 143 if (shouldHide) |
93 return; | 144 [self hideDevToolsView]; |
94 } | 145 |
146 devToolsWindow_ = newDevToolsWindow; | |
147 if (devToolsWindow_) { | |
148 gfx::Insets insets = devToolsWindow_->GetContentsInsets();; | |
Avi (use Gerrit)
2013/12/09 16:13:36
Too many semicolons.
dgozman
2013/12/10 14:51:47
Done.
| |
149 devToolsWindow_->web_contents()->GetView()->SetOverlayView( | |
150 contents->GetView(), gfx::Point(insets.left(), insets.top())); | |
Avi (use Gerrit)
2013/12/09 16:13:36
Yikes. SetOverlayView takes a flipped Y? Can you a
dgozman
2013/12/10 14:51:47
SetOverlayView takes the usual coordinates (top-le
| |
151 | |
152 // Swap top and bottom offsets for NSView geometry. | |
Avi (use Gerrit)
2013/12/09 16:13:36
:(
If you are calling parameters "top left" and "
dgozman
2013/12/10 14:51:47
Ok, so the right way is to always use logical top,
Avi (use Gerrit)
2013/12/10 16:32:40
Well, if you have a parameter called "top left" th
| |
153 [devToolsContainerView_ | |
154 setContentsOffsetsTopLeft:NSMakeSize(insets.left(), insets.bottom()) | |
155 bottomRight:NSMakeSize(insets.right(), insets.top())]; | |
Avi (use Gerrit)
2013/12/09 16:13:36
Oh wow, this is awkward. Cocoa's equivalent to gfx
dgozman
2013/12/10 14:51:47
Done.
| |
156 } else { | |
157 [devToolsContainerView_ | |
158 setContentsOffsetsTopLeft:NSZeroSize | |
Avi (use Gerrit)
2013/12/09 16:13:36
Surely this fits on the previous line.
dgozman
2013/12/10 14:51:47
Done.
| |
159 bottomRight:NSZeroSize]; | |
95 } | 160 } |
96 | 161 |
97 // Store last used position. | 162 if (shouldShow) |
98 if (devToolsWindow_) { | 163 [self showDevToolsView]; |
99 NSArray* subviews = [splitView_ subviews]; | |
100 DCHECK_EQ([subviews count], 2u); | |
101 NSView* devToolsView = [subviews objectAtIndex:1]; | |
102 if (dockSide_ == DEVTOOLS_DOCK_SIDE_RIGHT) | |
103 devToolsWindow_->SetWidth(NSWidth([devToolsView frame])); | |
104 else if (dockSide_ == DEVTOOLS_DOCK_SIDE_BOTTOM) | |
105 devToolsWindow_->SetHeight(NSHeight([devToolsView frame])); | |
106 } | |
107 | 164 |
108 if (devToolsWindow_) | 165 [devToolsContainerView_ adjustSubviews]; |
109 [self hideDevToolsContainer]; | 166 if (shouldHide || shouldShow) |
110 | 167 [[devToolsContainerView_ window] disableScreenUpdatesUntilFlush]; |
111 devToolsWindow_ = newDevToolsWindow; | |
112 | |
113 if (devToolsWindow_) { | |
114 dockSide_ = devToolsWindow_->dock_side(); | |
115 [self showDevToolsContainer]; | |
116 } | |
117 } | 168 } |
118 | 169 |
119 - (void)showDevToolsContainer { | 170 - (void)showDevToolsView { |
120 NSArray* subviews = [splitView_ subviews]; | |
121 DCHECK_EQ([subviews count], 1u); | |
122 WebContents* devToolsContents = devToolsWindow_->web_contents(); | |
123 focusTracker_.reset( | 171 focusTracker_.reset( |
124 [[FocusTracker alloc] initWithWindow:[splitView_ window]]); | 172 [[FocusTracker alloc] initWithWindow:[devToolsContainerView_ window]]); |
125 | 173 |
126 // |devToolsView| is a TabContentsViewCocoa object, whose ViewID was | 174 // |devToolsView| is a WebContentsViewCocoa object, whose ViewID was |
Avi (use Gerrit)
2013/12/09 16:13:36
:)
| |
127 // set to VIEW_ID_TAB_CONTAINER initially, so we need to change it to | 175 // set to VIEW_ID_TAB_CONTAINER initially, so we need to change it to |
128 // VIEW_ID_DEV_TOOLS_DOCKED here. | 176 // VIEW_ID_DEV_TOOLS_DOCKED here. |
129 NSView* devToolsView = devToolsContents->GetView()->GetNativeView(); | 177 NSView* devToolsView = |
178 devToolsWindow_->web_contents()->GetView()->GetNativeView(); | |
130 view_id_util::SetID(devToolsView, VIEW_ID_DEV_TOOLS_DOCKED); | 179 view_id_util::SetID(devToolsView, VIEW_ID_DEV_TOOLS_DOCKED); |
131 [splitView_ addSubview:devToolsView]; | |
132 | 180 |
133 BOOL isVertical = devToolsWindow_->dock_side() == DEVTOOLS_DOCK_SIDE_RIGHT; | 181 [devToolsContainerView_ showDevTools:devToolsView]; |
134 [splitView_ setVertical:isVertical]; | |
135 [self updateDevToolsSplitPosition]; | |
136 } | 182 } |
137 | 183 |
138 - (void)hideDevToolsContainer { | 184 - (void)hideDevToolsView { |
139 NSArray* subviews = [splitView_ subviews]; | 185 devToolsWindow_->web_contents()->GetView()->RemoveOverlayView(); |
140 DCHECK_EQ([subviews count], 2u); | 186 [devToolsContainerView_ hideDevTools]; |
141 NSView* oldDevToolsContentsView = [subviews objectAtIndex:1]; | 187 [focusTracker_ restoreFocusInWindow:[devToolsContainerView_ window]]; |
142 [oldDevToolsContentsView removeFromSuperview]; | |
143 [splitView_ adjustSubviews]; | |
144 [focusTracker_ restoreFocusInWindow:[splitView_ window]]; | |
145 focusTracker_.reset(); | 188 focusTracker_.reset(); |
146 } | 189 } |
147 | 190 |
148 - (void)updateDevToolsSplitPosition { | |
149 NSArray* subviews = [splitView_ subviews]; | |
150 | |
151 // It seems as if |-setPosition:ofDividerAtIndex:| should do what's needed, | |
152 // but I can't figure out how to use it. Manually resize web and devtools. | |
153 // TODO(alekseys): either make setPosition:ofDividerAtIndex: work or to add a | |
154 // category on NSSplitView to handle manual resizing. | |
155 NSView* webView = [subviews objectAtIndex:0]; | |
156 NSRect webFrame = [webView frame]; | |
157 NSView* devToolsView = [subviews objectAtIndex:1]; | |
158 NSRect devToolsFrame = [devToolsView frame]; | |
159 | |
160 BOOL noDivider = devToolsWindow_->dock_side() == DEVTOOLS_DOCK_SIDE_MINIMIZED; | |
161 [splitView_ setDividerHidden:noDivider]; | |
162 | |
163 if (devToolsWindow_->dock_side() == DEVTOOLS_DOCK_SIDE_RIGHT) { | |
164 CGFloat size = devToolsWindow_->GetWidth(NSWidth([splitView_ frame])); | |
165 devToolsFrame.size.width = size; | |
166 webFrame.size.width = | |
167 NSWidth([splitView_ frame]) - ([splitView_ dividerThickness] + size); | |
168 } else { | |
169 CGFloat size = | |
170 devToolsWindow_->dock_side() == DEVTOOLS_DOCK_SIDE_MINIMIZED ? | |
171 devToolsWindow_->GetMinimizedHeight() : | |
172 devToolsWindow_->GetHeight(NSHeight([splitView_ frame])); | |
173 devToolsFrame.size.height = size; | |
174 webFrame.size.height = | |
175 NSHeight([splitView_ frame]) - ([splitView_ dividerThickness] + size); | |
176 } | |
177 | |
178 [[splitView_ window] disableScreenUpdatesUntilFlush]; | |
179 [webView setFrame:webFrame]; | |
180 [devToolsView setFrame:devToolsFrame]; | |
181 | |
182 [splitView_ adjustSubviews]; | |
183 } | |
184 | |
185 // NSSplitViewDelegate protocol. | |
186 - (BOOL)splitView:(NSSplitView *)splitView | |
187 shouldAdjustSizeOfSubview:(NSView *)subview { | |
188 // Return NO for the devTools view to indicate that it should not be resized | |
189 // automatically. It preserves the height set by the user and also keeps | |
190 // view height the same while changing tabs when one of the tabs shows infobar | |
191 // and others are not. | |
192 if ([[splitView_ subviews] indexOfObject:subview] == 1) | |
193 return NO; | |
194 return YES; | |
195 } | |
196 | |
197 - (NSRect)splitView:(NSSplitView*)splitView | |
198 effectiveRect:(NSRect)proposedEffectiveRect | |
199 forDrawnRect:(NSRect)drawnRect | |
200 ofDividerAtIndex:(NSInteger)dividerIndex { | |
201 if (devToolsWindow_->dock_side() == DEVTOOLS_DOCK_SIDE_MINIMIZED) { | |
202 return NSZeroRect; | |
203 } else { | |
204 return proposedEffectiveRect; | |
205 } | |
206 } | |
207 | |
208 - (CGFloat)splitView:(NSSplitView*)splitView | |
209 constrainMaxCoordinate:(CGFloat)proposedMax | |
210 ofSubviewAt:(NSInteger)dividerIndex { | |
211 if ([splitView_ isVertical]) { | |
212 return NSWidth([splitView_ frame]) - [splitView_ dividerThickness] - | |
213 devToolsWindow_->GetMinimumWidth(); | |
214 } else { | |
215 return NSHeight([splitView_ frame]) - [splitView_ dividerThickness] - | |
216 devToolsWindow_->GetMinimumHeight(); | |
217 } | |
218 } | |
219 | |
220 - (CGFloat)splitView:(NSSplitView *)splitView | |
221 constrainSplitPosition:(CGFloat)proposedPosition | |
222 ofSubviewAt:(NSInteger)dividerIndex { | |
223 return round(proposedPosition); | |
224 } | |
225 | |
226 -(void)splitViewWillResizeSubviews:(NSNotification *)notification { | |
227 [[splitView_ window] disableScreenUpdatesUntilFlush]; | |
228 } | |
229 | |
230 @end | 191 @end |
OLD | NEW |