OLD | NEW |
| (Empty) |
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 | |
3 // found in the LICENSE file. | |
4 | |
5 #include "chrome/browser/ui/views/panels/panel_frame_view.h" | |
6 | |
7 #include "build/build_config.h" | |
8 #include "chrome/browser/ui/panels/panel.h" | |
9 #include "chrome/browser/ui/panels/panel_constants.h" | |
10 #include "chrome/browser/ui/views/panels/panel_view.h" | |
11 #include "chrome/browser/ui/views/tab_icon_view.h" | |
12 #include "chrome/grit/generated_resources.h" | |
13 #include "content/public/browser/web_contents.h" | |
14 #include "grit/theme_resources.h" | |
15 #include "ui/base/hit_test.h" | |
16 #include "ui/base/l10n/l10n_util.h" | |
17 #include "ui/base/resource/resource_bundle.h" | |
18 #include "ui/display/screen.h" | |
19 #include "ui/gfx/canvas.h" | |
20 #include "ui/gfx/font_list.h" | |
21 #include "ui/gfx/path.h" | |
22 #include "ui/resources/grit/ui_resources.h" | |
23 #include "ui/views/controls/button/image_button.h" | |
24 #include "ui/views/controls/label.h" | |
25 #include "ui/views/resources/grit/views_resources.h" | |
26 #include "ui/views/widget/widget.h" | |
27 #include "ui/views/widget/widget_delegate.h" | |
28 | |
29 #if defined(USE_AURA) | |
30 #include "ui/aura/window.h" | |
31 #endif | |
32 | |
33 #if defined(OS_WIN) | |
34 #include "base/win/scoped_gdi_object.h" | |
35 #include "ui/base/win/shell.h" | |
36 #include "ui/gfx/path_win.h" | |
37 #include "ui/views/win/hwnd_util.h" | |
38 #endif | |
39 | |
40 namespace { | |
41 | |
42 // The thickness of the border when Aero is not enabled. In this case, the | |
43 // shadow around the window will not be painted by the system and we need to | |
44 // paint a frame in order to differentiate the client area from the background. | |
45 const int kNonAeroBorderThickness = 1; | |
46 | |
47 // The height and width in pixels of the icon. | |
48 const int kIconSize = 16; | |
49 | |
50 // The extra padding between the button and the top edge. | |
51 const int kExtraPaddingBetweenButtonAndTop = 1; | |
52 | |
53 // Colors used to draw titlebar background under default theme. | |
54 const SkColor kActiveBackgroundDefaultColor = SkColorSetRGB(0x3a, 0x3d, 0x3d); | |
55 const SkColor kInactiveBackgroundDefaultColor = SkColorSetRGB(0x7a, 0x7c, 0x7c); | |
56 const SkColor kAttentionBackgroundDefaultColor = | |
57 SkColorSetRGB(0x53, 0xa9, 0x3f); | |
58 | |
59 // Color used to draw the minimized panel. | |
60 const SkColor kMinimizeBackgroundDefaultColor = SkColorSetRGB(0xf5, 0xf4, 0xf0); | |
61 | |
62 // Color used to draw the title text under default theme. | |
63 const SkColor kTitleTextDefaultColor = SkColorSetRGB(0xf9, 0xf9, 0xf9); | |
64 | |
65 gfx::ImageSkia* CreateImageForColor(SkColor color) { | |
66 gfx::Canvas canvas(gfx::Size(1, 1), 1.0f, true); | |
67 canvas.DrawColor(color); | |
68 return new gfx::ImageSkia(canvas.ExtractImageRep()); | |
69 } | |
70 | |
71 #if defined(OS_WIN) | |
72 const gfx::ImageSkia& GetTopLeftCornerImage(panel::CornerStyle corner_style) { | |
73 static gfx::ImageSkia* rounded_image = NULL; | |
74 static gfx::ImageSkia* non_rounded_image = NULL; | |
75 if (!rounded_image) { | |
76 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); | |
77 rounded_image = rb.GetImageSkiaNamed(IDR_WINDOW_TOP_LEFT_CORNER); | |
78 non_rounded_image = rb.GetImageSkiaNamed(IDR_PANEL_TOP_LEFT_CORNER); | |
79 } | |
80 return (corner_style & panel::TOP_ROUNDED) ? *rounded_image | |
81 : *non_rounded_image; | |
82 } | |
83 | |
84 const gfx::ImageSkia& GetTopRightCornerImage(panel::CornerStyle corner_style) { | |
85 static gfx::ImageSkia* rounded_image = NULL; | |
86 static gfx::ImageSkia* non_rounded_image = NULL; | |
87 if (!rounded_image) { | |
88 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); | |
89 rounded_image = rb.GetImageSkiaNamed(IDR_WINDOW_TOP_RIGHT_CORNER); | |
90 non_rounded_image = rb.GetImageSkiaNamed(IDR_PANEL_TOP_RIGHT_CORNER); | |
91 } | |
92 return (corner_style & panel::TOP_ROUNDED) ? *rounded_image | |
93 : *non_rounded_image; | |
94 } | |
95 | |
96 const gfx::ImageSkia& GetBottomLeftCornerImage( | |
97 panel::CornerStyle corner_style) { | |
98 static gfx::ImageSkia* rounded_image = NULL; | |
99 static gfx::ImageSkia* non_rounded_image = NULL; | |
100 if (!rounded_image) { | |
101 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); | |
102 rounded_image = rb.GetImageSkiaNamed(IDR_WINDOW_BOTTOM_LEFT_CORNER); | |
103 non_rounded_image = rb.GetImageSkiaNamed(IDR_PANEL_BOTTOM_LEFT_CORNER); | |
104 } | |
105 return (corner_style & panel::BOTTOM_ROUNDED) ? *rounded_image | |
106 : *non_rounded_image; | |
107 } | |
108 | |
109 const gfx::ImageSkia& GetBottomRightCornerImage( | |
110 panel::CornerStyle corner_style) { | |
111 static gfx::ImageSkia* rounded_image = NULL; | |
112 static gfx::ImageSkia* non_rounded_image = NULL; | |
113 if (!rounded_image) { | |
114 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); | |
115 rounded_image = rb.GetImageSkiaNamed(IDR_WINDOW_BOTTOM_RIGHT_CORNER); | |
116 non_rounded_image = rb.GetImageSkiaNamed(IDR_PANEL_BOTTOM_RIGHT_CORNER); | |
117 } | |
118 return (corner_style & panel::BOTTOM_ROUNDED) ? *rounded_image | |
119 : *non_rounded_image; | |
120 } | |
121 | |
122 const gfx::ImageSkia& GetTopEdgeImage() { | |
123 static gfx::ImageSkia* image = NULL; | |
124 if (!image) { | |
125 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); | |
126 image = rb.GetImageSkiaNamed(IDR_WINDOW_TOP_CENTER); | |
127 } | |
128 return *image; | |
129 } | |
130 | |
131 const gfx::ImageSkia& GetBottomEdgeImage() { | |
132 static gfx::ImageSkia* image = NULL; | |
133 if (!image) { | |
134 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); | |
135 image = rb.GetImageSkiaNamed(IDR_WINDOW_BOTTOM_CENTER); | |
136 } | |
137 return *image; | |
138 } | |
139 | |
140 const gfx::ImageSkia& GetLeftEdgeImage() { | |
141 static gfx::ImageSkia* image = NULL; | |
142 if (!image) { | |
143 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); | |
144 image = rb.GetImageSkiaNamed(IDR_WINDOW_LEFT_SIDE); | |
145 } | |
146 return *image; | |
147 } | |
148 | |
149 const gfx::ImageSkia& GetRightEdgeImage() { | |
150 static gfx::ImageSkia* image = NULL; | |
151 if (!image) { | |
152 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); | |
153 image = rb.GetImageSkiaNamed(IDR_WINDOW_RIGHT_SIDE); | |
154 } | |
155 return *image; | |
156 } | |
157 #endif // defined(OS_WIN) | |
158 | |
159 const gfx::ImageSkia* GetActiveBackgroundDefaultImage() { | |
160 static gfx::ImageSkia* image = NULL; | |
161 if (!image) | |
162 image = CreateImageForColor(kActiveBackgroundDefaultColor); | |
163 return image; | |
164 } | |
165 | |
166 const gfx::ImageSkia* GetInactiveBackgroundDefaultImage() { | |
167 static gfx::ImageSkia* image = NULL; | |
168 if (!image) | |
169 image = CreateImageForColor(kInactiveBackgroundDefaultColor); | |
170 return image; | |
171 } | |
172 | |
173 const gfx::ImageSkia* GetAttentionBackgroundDefaultImage() { | |
174 static gfx::ImageSkia* image = NULL; | |
175 if (!image) | |
176 image = CreateImageForColor(kAttentionBackgroundDefaultColor); | |
177 return image; | |
178 } | |
179 | |
180 const gfx::ImageSkia* GetMinimizeBackgroundDefaultImage() { | |
181 static gfx::ImageSkia* image = NULL; | |
182 if (!image) | |
183 image = CreateImageForColor(kMinimizeBackgroundDefaultColor); | |
184 return image; | |
185 } | |
186 | |
187 int GetFrameEdgeHitTest(const gfx::Point& point, | |
188 const gfx::Size& frame_size, | |
189 int resize_area_size, | |
190 panel::Resizability resizability) { | |
191 int x = point.x(); | |
192 int y = point.y(); | |
193 int width = frame_size.width(); | |
194 int height = frame_size.height(); | |
195 if (x < resize_area_size) { | |
196 if (y < resize_area_size && (resizability & panel::RESIZABLE_TOP_LEFT)) { | |
197 return HTTOPLEFT; | |
198 } else if (y >= height - resize_area_size && | |
199 (resizability & panel::RESIZABLE_BOTTOM_LEFT)) { | |
200 return HTBOTTOMLEFT; | |
201 } else if (resizability & panel::RESIZABLE_LEFT) { | |
202 return HTLEFT; | |
203 } | |
204 } else if (x >= width - resize_area_size) { | |
205 if (y < resize_area_size && (resizability & panel::RESIZABLE_TOP_RIGHT)) { | |
206 return HTTOPRIGHT; | |
207 } else if (y >= height - resize_area_size && | |
208 (resizability & panel::RESIZABLE_BOTTOM_RIGHT)) { | |
209 return HTBOTTOMRIGHT; | |
210 } else if (resizability & panel::RESIZABLE_RIGHT) { | |
211 return HTRIGHT; | |
212 } | |
213 } | |
214 | |
215 if (y < resize_area_size && (resizability & panel::RESIZABLE_TOP)) { | |
216 return HTTOP; | |
217 } else if (y >= height - resize_area_size && | |
218 (resizability & panel::RESIZABLE_BOTTOM)) { | |
219 return HTBOTTOM; | |
220 } | |
221 | |
222 return HTNOWHERE; | |
223 } | |
224 | |
225 // Frameless is only supported when Aero is enabled and shadow effect is | |
226 // present. | |
227 bool ShouldRenderAsFrameless() { | |
228 #if defined(OS_WIN) | |
229 bool is_frameless = ui::win::IsAeroGlassEnabled(); | |
230 if (is_frameless) { | |
231 BOOL shadow_enabled = FALSE; | |
232 if (::SystemParametersInfo(SPI_GETDROPSHADOW, 0, &shadow_enabled, 0) && | |
233 !shadow_enabled) | |
234 is_frameless = false; | |
235 } | |
236 return is_frameless; | |
237 #else | |
238 return false; | |
239 #endif | |
240 } | |
241 | |
242 } // namespace | |
243 | |
244 // static | |
245 const char PanelFrameView::kViewClassName[] = "PanelFrameView"; | |
246 | |
247 PanelFrameView::PanelFrameView(PanelView* panel_view) | |
248 : is_frameless_(ShouldRenderAsFrameless()), | |
249 panel_view_(panel_view), | |
250 close_button_(NULL), | |
251 minimize_button_(NULL), | |
252 restore_button_(NULL), | |
253 title_icon_(NULL), | |
254 title_label_(NULL), | |
255 corner_style_(panel::ALL_ROUNDED) { | |
256 } | |
257 | |
258 PanelFrameView::~PanelFrameView() { | |
259 } | |
260 | |
261 void PanelFrameView::Init() { | |
262 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); | |
263 | |
264 close_button_ = new views::ImageButton(this); | |
265 close_button_->SetImage(views::CustomButton::STATE_NORMAL, | |
266 rb.GetImageSkiaNamed(IDR_PANEL_CLOSE)); | |
267 close_button_->SetImage(views::CustomButton::STATE_HOVERED, | |
268 rb.GetImageSkiaNamed(IDR_PANEL_CLOSE_H)); | |
269 close_button_->SetImage(views::CustomButton::STATE_PRESSED, | |
270 rb.GetImageSkiaNamed(IDR_PANEL_CLOSE_C)); | |
271 close_button_->SetImageAlignment(views::ImageButton::ALIGN_CENTER, | |
272 views::ImageButton::ALIGN_MIDDLE); | |
273 base::string16 tooltip_text = | |
274 l10n_util::GetStringUTF16(IDS_PANEL_CLOSE_TOOLTIP); | |
275 close_button_->SetTooltipText(tooltip_text); | |
276 AddChildView(close_button_); | |
277 | |
278 minimize_button_ = new views::ImageButton(this); | |
279 minimize_button_->SetImage(views::CustomButton::STATE_NORMAL, | |
280 rb.GetImageSkiaNamed(IDR_PANEL_MINIMIZE)); | |
281 minimize_button_->SetImage(views::CustomButton::STATE_HOVERED, | |
282 rb.GetImageSkiaNamed(IDR_PANEL_MINIMIZE_H)); | |
283 minimize_button_->SetImage(views::CustomButton::STATE_PRESSED, | |
284 rb.GetImageSkiaNamed(IDR_PANEL_MINIMIZE_C)); | |
285 tooltip_text = l10n_util::GetStringUTF16(IDS_PANEL_MINIMIZE_TOOLTIP); | |
286 minimize_button_->SetTooltipText(tooltip_text); | |
287 minimize_button_->SetImageAlignment(views::ImageButton::ALIGN_CENTER, | |
288 views::ImageButton::ALIGN_MIDDLE); | |
289 AddChildView(minimize_button_); | |
290 | |
291 restore_button_ = new views::ImageButton(this); | |
292 restore_button_->SetImage(views::CustomButton::STATE_NORMAL, | |
293 rb.GetImageSkiaNamed(IDR_PANEL_RESTORE)); | |
294 restore_button_->SetImage(views::CustomButton::STATE_HOVERED, | |
295 rb.GetImageSkiaNamed(IDR_PANEL_RESTORE_H)); | |
296 restore_button_->SetImage(views::CustomButton::STATE_PRESSED, | |
297 rb.GetImageSkiaNamed(IDR_PANEL_RESTORE_C)); | |
298 restore_button_->SetImageAlignment(views::ImageButton::ALIGN_CENTER, | |
299 views::ImageButton::ALIGN_MIDDLE); | |
300 tooltip_text = l10n_util::GetStringUTF16(IDS_PANEL_RESTORE_TOOLTIP); | |
301 restore_button_->SetTooltipText(tooltip_text); | |
302 restore_button_->SetVisible(false); // only visible when panel is minimized | |
303 AddChildView(restore_button_); | |
304 | |
305 title_icon_ = new TabIconView(this, NULL); | |
306 title_icon_->set_is_light(true); | |
307 AddChildView(title_icon_); | |
308 title_icon_->Update(); | |
309 | |
310 title_label_ = new views::Label( | |
311 panel_view_->panel()->GetWindowTitle(), | |
312 rb.GetFontList(ui::ResourceBundle::BoldFont)); | |
313 title_label_->SetHorizontalAlignment(gfx::ALIGN_LEFT); | |
314 title_label_->SetAutoColorReadabilityEnabled(false); | |
315 AddChildView(title_label_); | |
316 | |
317 #if defined(USE_AURA) | |
318 // Compute the thickness of the client area that needs to be counted towards | |
319 // mouse resizing. | |
320 // TODO(tdanderson): Remove this if possible (crbug.com/344924). | |
321 int thickness_for_mouse_resizing = | |
322 PanelView::kResizeInsideBoundsSize - BorderThickness(); | |
323 aura::Window* window = panel_view_->GetNativePanelWindow(); | |
324 window->set_hit_test_bounds_override_inner( | |
325 gfx::Insets(thickness_for_mouse_resizing)); | |
326 #endif | |
327 } | |
328 | |
329 void PanelFrameView::UpdateTitle() { | |
330 UpdateWindowTitle(); | |
331 } | |
332 | |
333 void PanelFrameView::UpdateIcon() { | |
334 UpdateWindowIcon(); | |
335 } | |
336 | |
337 void PanelFrameView::UpdateThrobber() { | |
338 title_icon_->Update(); | |
339 } | |
340 | |
341 void PanelFrameView::UpdateTitlebarMinimizeRestoreButtonVisibility() { | |
342 Panel* panel = panel_view_->panel(); | |
343 minimize_button_->SetVisible(panel->CanShowMinimizeButton()); | |
344 restore_button_->SetVisible(panel->CanShowRestoreButton()); | |
345 | |
346 // Reset the button states in case that the hover states are not cleared when | |
347 // mouse is clicked but not moved. | |
348 minimize_button_->SetState(views::CustomButton::STATE_NORMAL); | |
349 restore_button_->SetState(views::CustomButton::STATE_NORMAL); | |
350 } | |
351 | |
352 void PanelFrameView::SetWindowCornerStyle(panel::CornerStyle corner_style) { | |
353 corner_style_ = corner_style; | |
354 | |
355 #if defined(OS_WIN) | |
356 // Changing the window region is going to force a paint. Only change the | |
357 // window region if the region really differs. | |
358 HWND native_window = views::HWNDForWidget(panel_view_->window()); | |
359 base::win::ScopedRegion current_region(::CreateRectRgn(0, 0, 0, 0)); | |
360 ::GetWindowRgn(native_window, current_region.get()); | |
361 | |
362 gfx::Path window_mask; | |
363 GetWindowMask(size(), &window_mask); | |
364 base::win::ScopedRegion new_region; | |
365 if (!window_mask.isEmpty()) | |
366 new_region.reset(gfx::CreateHRGNFromSkPath(window_mask)); | |
367 | |
368 const bool has_current_region = current_region != NULL; | |
369 const bool has_new_region = new_region != NULL; | |
370 if (has_current_region != has_new_region || | |
371 (has_current_region && | |
372 !::EqualRgn(current_region.get(), new_region.get()))) { | |
373 // SetWindowRgn takes ownership of the new_region. | |
374 ::SetWindowRgn(native_window, new_region.release(), TRUE); | |
375 } | |
376 #endif | |
377 } | |
378 | |
379 gfx::Rect PanelFrameView::GetBoundsForClientView() const { | |
380 // The origin of client-area bounds starts after left border and titlebar and | |
381 // spans until hitting the right and bottom borders. | |
382 // +------------------------------+ | |
383 // | Top Titlebar | | |
384 // |-+--------------------------+-| | |
385 // |L| |R| | |
386 // |e| |i| | |
387 // |f| |g| | |
388 // |t| |h| | |
389 // | | Client |t| | |
390 // | | | | | |
391 // |B| Area |B| | |
392 // |o| |o| | |
393 // |r| |r| | |
394 // |d| |d| | |
395 // |e| |e| | |
396 // |r| |r| | |
397 // | +--------------------------+ | | |
398 // | Bottom Border | | |
399 // +------------------------------+ | |
400 int titlebar_height = TitlebarHeight(); | |
401 int border_thickness = BorderThickness(); | |
402 return gfx::Rect(border_thickness, | |
403 titlebar_height, | |
404 std::max(0, width() - border_thickness * 2), | |
405 std::max(0, height() - titlebar_height - border_thickness)); | |
406 } | |
407 | |
408 gfx::Rect PanelFrameView::GetWindowBoundsForClientBounds( | |
409 const gfx::Rect& client_bounds) const { | |
410 int titlebar_height = TitlebarHeight(); | |
411 int border_thickness = BorderThickness(); | |
412 // The window bounds include both client area and non-client area (titlebar | |
413 // and left, right and bottom borders). | |
414 return gfx::Rect(client_bounds.x() - border_thickness, | |
415 client_bounds.y() - titlebar_height, | |
416 client_bounds.width() + border_thickness * 2, | |
417 client_bounds.height() + titlebar_height + border_thickness); | |
418 } | |
419 | |
420 int PanelFrameView::NonClientHitTest(const gfx::Point& point) { | |
421 panel::Resizability resizability = panel_view_->panel()->CanResizeByMouse(); | |
422 | |
423 // Check the frame first, as we allow a small area overlapping the contents | |
424 // to be used for resize handles. | |
425 int frame_component = GetFrameEdgeHitTest( | |
426 point, size(), PanelView::kResizeInsideBoundsSize, resizability); | |
427 | |
428 if (frame_component != HTNOWHERE) | |
429 return frame_component; | |
430 | |
431 int client_component = | |
432 panel_view_->window()->client_view()->NonClientHitTest(point); | |
433 if (client_component != HTNOWHERE) | |
434 return client_component; | |
435 | |
436 if (close_button_ && close_button_->visible() && | |
437 close_button_->GetMirroredBounds().Contains(point)) | |
438 return HTCLOSE; | |
439 | |
440 if (minimize_button_ && minimize_button_->visible() && | |
441 minimize_button_->GetMirroredBounds().Contains(point)) | |
442 return HTMINBUTTON; | |
443 | |
444 if (restore_button_ && restore_button_->visible() && | |
445 restore_button_->GetMirroredBounds().Contains(point)) | |
446 return HTMAXBUTTON; | |
447 | |
448 return HTNOWHERE; | |
449 } | |
450 | |
451 void PanelFrameView::GetWindowMask(const gfx::Size& size, | |
452 gfx::Path* window_mask) { | |
453 int width = size.width(); | |
454 int height = size.height(); | |
455 | |
456 if (corner_style_ & panel::TOP_ROUNDED) { | |
457 window_mask->moveTo(0, 3); | |
458 window_mask->lineTo(1, 2); | |
459 window_mask->lineTo(1, 1); | |
460 window_mask->lineTo(2, 1); | |
461 window_mask->lineTo(3, 0); | |
462 window_mask->lineTo(SkIntToScalar(width - 3), 0); | |
463 window_mask->lineTo(SkIntToScalar(width - 2), 1); | |
464 window_mask->lineTo(SkIntToScalar(width - 1), 1); | |
465 window_mask->lineTo(SkIntToScalar(width - 1), 2); | |
466 window_mask->lineTo(SkIntToScalar(width - 1), 3); | |
467 } else { | |
468 window_mask->moveTo(0, 0); | |
469 window_mask->lineTo(width, 0); | |
470 } | |
471 | |
472 if (corner_style_ & panel::BOTTOM_ROUNDED) { | |
473 window_mask->lineTo(SkIntToScalar(width - 1), SkIntToScalar(height - 4)); | |
474 window_mask->lineTo(SkIntToScalar(width - 2), SkIntToScalar(height - 3)); | |
475 window_mask->lineTo(SkIntToScalar(width - 2), SkIntToScalar(height - 2)); | |
476 window_mask->lineTo(SkIntToScalar(width - 3), SkIntToScalar(height - 2)); | |
477 window_mask->lineTo(SkIntToScalar(width - 4), SkIntToScalar(height - 1)); | |
478 window_mask->lineTo(3, SkIntToScalar(height - 1)); | |
479 window_mask->lineTo(2, SkIntToScalar(height - 2)); | |
480 window_mask->lineTo(1, SkIntToScalar(height - 2)); | |
481 window_mask->lineTo(1, SkIntToScalar(height - 3)); | |
482 window_mask->lineTo(0, SkIntToScalar(height - 4)); | |
483 } else { | |
484 window_mask->lineTo(SkIntToScalar(width), SkIntToScalar(height)); | |
485 window_mask->lineTo(0, SkIntToScalar(height)); | |
486 } | |
487 | |
488 window_mask->close(); | |
489 } | |
490 | |
491 void PanelFrameView::ResetWindowControls() { | |
492 // The controls aren't affected by this constraint. | |
493 } | |
494 | |
495 void PanelFrameView::UpdateWindowIcon() { | |
496 title_icon_->SchedulePaint(); | |
497 } | |
498 | |
499 void PanelFrameView::UpdateWindowTitle() { | |
500 title_label_->SetText(panel_view_->panel()->GetWindowTitle()); | |
501 } | |
502 | |
503 void PanelFrameView::SizeConstraintsChanged() { | |
504 } | |
505 | |
506 gfx::Size PanelFrameView::GetPreferredSize() const { | |
507 gfx::Size pref_size = | |
508 panel_view_->window()->client_view()->GetPreferredSize(); | |
509 gfx::Rect bounds(0, 0, pref_size.width(), pref_size.height()); | |
510 return panel_view_->window()->non_client_view()-> | |
511 GetWindowBoundsForClientBounds(bounds).size(); | |
512 } | |
513 | |
514 const char* PanelFrameView::GetClassName() const { | |
515 return kViewClassName; | |
516 } | |
517 | |
518 gfx::Size PanelFrameView::GetMinimumSize() const { | |
519 return panel_view_->GetMinimumSize(); | |
520 } | |
521 | |
522 gfx::Size PanelFrameView::GetMaximumSize() const { | |
523 return panel_view_->GetMaximumSize(); | |
524 } | |
525 | |
526 void PanelFrameView::Layout() { | |
527 is_frameless_ = ShouldRenderAsFrameless(); | |
528 | |
529 // Layout the close button. | |
530 int right = width(); | |
531 close_button_->SetBounds( | |
532 width() - panel::kTitlebarRightPadding - panel::kPanelButtonSize, | |
533 (TitlebarHeight() - panel::kPanelButtonSize) / 2 + | |
534 kExtraPaddingBetweenButtonAndTop, | |
535 panel::kPanelButtonSize, | |
536 panel::kPanelButtonSize); | |
537 right = close_button_->x(); | |
538 | |
539 // Layout the minimize and restore button. Both occupy the same space, | |
540 // but at most one is visible at any time. | |
541 minimize_button_->SetBounds( | |
542 right - panel::kButtonPadding - panel::kPanelButtonSize, | |
543 (TitlebarHeight() - panel::kPanelButtonSize) / 2 + | |
544 kExtraPaddingBetweenButtonAndTop, | |
545 panel::kPanelButtonSize, | |
546 panel::kPanelButtonSize); | |
547 restore_button_->SetBoundsRect(minimize_button_->bounds()); | |
548 right = minimize_button_->x(); | |
549 | |
550 // Layout the icon. | |
551 int icon_y = (TitlebarHeight() - kIconSize) / 2; | |
552 title_icon_->SetBounds( | |
553 panel::kTitlebarLeftPadding, | |
554 icon_y, | |
555 kIconSize, | |
556 kIconSize); | |
557 | |
558 // Layout the title. | |
559 int title_x = title_icon_->bounds().right() + panel::kIconAndTitlePadding; | |
560 int title_height = title_label_->font_list().GetHeight(); | |
561 title_label_->SetBounds( | |
562 title_x, | |
563 icon_y + ((kIconSize - title_height - 1) / 2), | |
564 std::max(0, right - panel::kTitleAndButtonPadding - title_x), | |
565 title_height); | |
566 } | |
567 | |
568 void PanelFrameView::OnPaint(gfx::Canvas* canvas) { | |
569 UpdateControlStyles(GetPaintState()); | |
570 PaintFrameBackground(canvas); | |
571 PaintFrameEdge(canvas); | |
572 } | |
573 | |
574 bool PanelFrameView::OnMousePressed(const ui::MouseEvent& event) { | |
575 // If the mouse location falls within the resizing area of the titlebar, do | |
576 // not handle the event so that the system resizing logic can kick in. | |
577 if (event.IsOnlyLeftMouseButton() && | |
578 !IsWithinResizingArea(event.location())) { | |
579 // |event.location| is in the view's coordinate system. Convert it to the | |
580 // screen coordinate system. | |
581 gfx::Point mouse_location = event.location(); | |
582 views::View::ConvertPointToScreen(this, &mouse_location); | |
583 | |
584 if (panel_view_->OnTitlebarMousePressed(mouse_location)) | |
585 return true; | |
586 } | |
587 return NonClientFrameView::OnMousePressed(event); | |
588 } | |
589 | |
590 bool PanelFrameView::OnMouseDragged(const ui::MouseEvent& event) { | |
591 #if defined(OS_LINUX) && !defined(OS_CHROMEOS) | |
592 // Converting the mouse location to screen coordinates returns an incorrect | |
593 // location while the panel is moving. See crbug.com/353393 for more details. | |
594 // TODO(pkotwicz): Fix conversion to screen coordinates | |
595 display::Screen* screen = display::Screen::GetScreen(); | |
596 gfx::Point mouse_location = screen->GetCursorScreenPoint(); | |
597 #else | |
598 // |event.location| is in the view's coordinate system. Convert it to the | |
599 // screen coordinate system. | |
600 gfx::Point mouse_location = event.location(); | |
601 views::View::ConvertPointToScreen(this, &mouse_location); | |
602 #endif | |
603 | |
604 if (panel_view_->OnTitlebarMouseDragged(mouse_location)) | |
605 return true; | |
606 return NonClientFrameView::OnMouseDragged(event); | |
607 } | |
608 | |
609 void PanelFrameView::OnMouseReleased(const ui::MouseEvent& event) { | |
610 if (panel_view_->OnTitlebarMouseReleased( | |
611 event.IsControlDown() ? panel::APPLY_TO_ALL : panel::NO_MODIFIER)) | |
612 return; | |
613 NonClientFrameView::OnMouseReleased(event); | |
614 } | |
615 | |
616 void PanelFrameView::OnMouseCaptureLost() { | |
617 if (panel_view_->OnTitlebarMouseCaptureLost()) | |
618 return; | |
619 NonClientFrameView::OnMouseCaptureLost(); | |
620 } | |
621 | |
622 void PanelFrameView::ButtonPressed(views::Button* sender, | |
623 const ui::Event& event) { | |
624 if (sender == close_button_) { | |
625 panel_view_->ClosePanel(); | |
626 } else { | |
627 panel::ClickModifier modifier = | |
628 event.IsControlDown() ? panel::APPLY_TO_ALL : panel::NO_MODIFIER; | |
629 if (sender == minimize_button_) | |
630 panel_view_->panel()->OnMinimizeButtonClicked(modifier); | |
631 else if (sender == restore_button_) | |
632 panel_view_->panel()->OnRestoreButtonClicked(modifier); | |
633 } | |
634 } | |
635 | |
636 bool PanelFrameView::ShouldTabIconViewAnimate() const { | |
637 // This function is queried during the creation of the window as the | |
638 // TabIconView we host is initialized, so we need to NULL check the selected | |
639 // WebContents because in this condition there is not yet a selected tab. | |
640 content::WebContents* contents = panel_view_->panel()->GetWebContents(); | |
641 return contents ? contents->IsLoading() : false; | |
642 } | |
643 | |
644 gfx::ImageSkia PanelFrameView::GetFaviconForTabIconView() { | |
645 return panel_view_->window()->widget_delegate()->GetWindowIcon(); | |
646 } | |
647 | |
648 gfx::Size PanelFrameView::NonClientAreaSize() const { | |
649 if (is_frameless_) | |
650 return gfx::Size(0, TitlebarHeight()); | |
651 // When the frame is present, the width of non-client area consists of | |
652 // left and right borders, while the height consists of the top area | |
653 // (titlebar) and the bottom border. | |
654 return gfx::Size(2 * kNonAeroBorderThickness, | |
655 TitlebarHeight() + kNonAeroBorderThickness); | |
656 } | |
657 | |
658 int PanelFrameView::TitlebarHeight() const { | |
659 return panel::kTitlebarHeight; | |
660 } | |
661 | |
662 int PanelFrameView::BorderThickness() const { | |
663 return is_frameless_ ? 0 : kNonAeroBorderThickness; | |
664 } | |
665 | |
666 PanelFrameView::PaintState PanelFrameView::GetPaintState() const { | |
667 if (panel_view_->panel()->IsDrawingAttention()) | |
668 return PAINT_FOR_ATTENTION; | |
669 if (bounds().height() <= panel::kMinimizedPanelHeight) | |
670 return PAINT_AS_MINIMIZED; | |
671 if (panel_view_->IsPanelActive() && | |
672 !panel_view_->force_to_paint_as_inactive()) | |
673 return PAINT_AS_ACTIVE; | |
674 return PAINT_AS_INACTIVE; | |
675 } | |
676 | |
677 SkColor PanelFrameView::GetTitleColor(PaintState paint_state) const { | |
678 return kTitleTextDefaultColor; | |
679 } | |
680 | |
681 const gfx::ImageSkia* PanelFrameView::GetFrameBackground( | |
682 PaintState paint_state) const { | |
683 switch (paint_state) { | |
684 case PAINT_AS_INACTIVE: | |
685 return GetInactiveBackgroundDefaultImage(); | |
686 case PAINT_AS_ACTIVE: | |
687 return GetActiveBackgroundDefaultImage(); | |
688 case PAINT_AS_MINIMIZED: | |
689 return GetMinimizeBackgroundDefaultImage(); | |
690 case PAINT_FOR_ATTENTION: | |
691 return GetAttentionBackgroundDefaultImage(); | |
692 default: | |
693 NOTREACHED(); | |
694 return GetInactiveBackgroundDefaultImage(); | |
695 } | |
696 } | |
697 | |
698 void PanelFrameView::UpdateControlStyles(PaintState paint_state) { | |
699 title_label_->SetEnabledColor(GetTitleColor(paint_state)); | |
700 } | |
701 | |
702 void PanelFrameView::PaintFrameBackground(gfx::Canvas* canvas) { | |
703 // We only need to paint the title-bar since no resizing border is shown. | |
704 // Instead, we allow part of the inner content area be used to trigger the | |
705 // mouse resizing. | |
706 int titlebar_height = TitlebarHeight(); | |
707 const gfx::ImageSkia* image = GetFrameBackground(GetPaintState()); | |
708 canvas->TileImageInt(*image, 0, 0, width(), titlebar_height); | |
709 | |
710 if (is_frameless_) | |
711 return; | |
712 | |
713 // Left border, below title-bar. | |
714 canvas->TileImageInt(*image, 0, titlebar_height, kNonAeroBorderThickness, | |
715 height() - titlebar_height); | |
716 | |
717 // Right border, below title-bar. | |
718 canvas->TileImageInt(*image, width() - kNonAeroBorderThickness, | |
719 titlebar_height, kNonAeroBorderThickness, height() - titlebar_height); | |
720 | |
721 // Bottom border. | |
722 canvas->TileImageInt(*image, 0, height() - kNonAeroBorderThickness, width(), | |
723 kNonAeroBorderThickness); | |
724 } | |
725 | |
726 void PanelFrameView::PaintFrameEdge(gfx::Canvas* canvas) { | |
727 #if defined(OS_WIN) | |
728 // Border is not needed when panel is not shown as minimized. | |
729 if (GetPaintState() != PAINT_AS_MINIMIZED) | |
730 return; | |
731 | |
732 const gfx::ImageSkia& top_left_image = GetTopLeftCornerImage(corner_style_); | |
733 const gfx::ImageSkia& top_right_image = GetTopRightCornerImage(corner_style_); | |
734 const gfx::ImageSkia& bottom_left_image = | |
735 GetBottomLeftCornerImage(corner_style_); | |
736 const gfx::ImageSkia& bottom_right_image = | |
737 GetBottomRightCornerImage(corner_style_); | |
738 const gfx::ImageSkia& top_image = GetTopEdgeImage(); | |
739 const gfx::ImageSkia& bottom_image = GetBottomEdgeImage(); | |
740 const gfx::ImageSkia& left_image = GetLeftEdgeImage(); | |
741 const gfx::ImageSkia& right_image = GetRightEdgeImage(); | |
742 | |
743 // Draw the top border. | |
744 canvas->DrawImageInt(top_left_image, 0, 0); | |
745 canvas->TileImageInt(top_image, | |
746 top_left_image.width(), | |
747 0, | |
748 width() - top_right_image.width(), | |
749 top_image.height()); | |
750 canvas->DrawImageInt(top_right_image, width() - top_right_image.width(), 0); | |
751 | |
752 // Draw the right border. | |
753 canvas->TileImageInt(right_image, | |
754 width() - right_image.width(), | |
755 top_right_image.height(), | |
756 right_image.width(), | |
757 height() - top_right_image.height() - | |
758 bottom_right_image.height()); | |
759 | |
760 // Draw the bottom border. | |
761 canvas->DrawImageInt(bottom_right_image, | |
762 width() - bottom_right_image.width(), | |
763 height() - bottom_right_image.height()); | |
764 canvas->TileImageInt(bottom_image, | |
765 bottom_left_image.width(), | |
766 height() - bottom_image.height(), | |
767 width() - bottom_left_image.width() - | |
768 bottom_right_image.width(), | |
769 bottom_image.height()); | |
770 canvas->DrawImageInt(bottom_left_image, | |
771 0, | |
772 height() - bottom_left_image.height()); | |
773 | |
774 // Draw the left border. | |
775 canvas->TileImageInt(left_image, | |
776 0, | |
777 top_left_image.height(), | |
778 left_image.width(), | |
779 height() - top_left_image.height() - | |
780 bottom_left_image.height()); | |
781 #endif | |
782 } | |
783 | |
784 bool PanelFrameView::IsWithinResizingArea( | |
785 const gfx::Point& mouse_location) const { | |
786 panel::Resizability resizability = panel_view_->panel()->CanResizeByMouse(); | |
787 int edge_hittest = GetFrameEdgeHitTest( | |
788 mouse_location, size(), PanelView::kResizeInsideBoundsSize, resizability); | |
789 return edge_hittest != HTNOWHERE; | |
790 } | |
OLD | NEW |