custom_frame_view.cc revision f2477e01787aa58f445919b809d89e252beef54f
15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file. 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/views/window/custom_frame_view.h" 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <algorithm> 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/utf_string_conversions.h" 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "grit/ui_resources.h" 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "grit/ui_strings.h" 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/base/hit_test.h" 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/base/l10n/l10n_util.h" 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/base/resource/resource_bundle.h" 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/gfx/canvas.h" 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/gfx/font.h" 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/gfx/image/image.h" 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/gfx/path.h" 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/views/color_constants.h" 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/views/controls/button/image_button.h" 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/views/widget/widget.h" 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/views/widget/widget_delegate.h" 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/views/window/client_view.h" 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/views/window/frame_background.h" 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/views/window/window_resources.h" 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/views/window/window_shape.h" 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(USE_AURA) 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/views/widget/native_widget_aura.h" 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#elif defined(OS_WIN) 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/views/widget/native_widget_win.h" 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace views { 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace { 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The frame border is only visible in restored mode and is hardcoded to 4 px on 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// each side regardless of the system window border size. 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kFrameBorderThickness = 4; 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// In the window corners, the resize areas don't actually expand bigger, but the 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 16 px at the end of each edge triggers diagonal resizing. 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kResizeAreaCornerSize = 16; 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The titlebar never shrinks too short to show the caption button plus some 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// padding below it. 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kCaptionButtonHeightWithPadding = 19; 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The titlebar has a 2 px 3D edge along the top and bottom. 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kTitlebarTopAndBottomEdgeThickness = 2; 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The icon is inset 2 px from the left frame border. 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kIconLeftSpacing = 2; 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The icon never shrinks below 16 px on a side. 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kIconMinimumSize = 16; 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The space between the window icon and the title text. 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kTitleIconOffsetX = 4; 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The space between the title text and the caption buttons. 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kTitleCaptionSpacing = 5; 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 58f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#if defined(OS_CHROMEOS) 59f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)// Chrome OS uses a dark gray. 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const SkColor kDefaultColorFrame = SkColorSetRGB(109, 109, 109); 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const SkColor kDefaultColorFrameInactive = SkColorSetRGB(176, 176, 176); 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#else 63f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)// Windows and Linux use a blue. 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const SkColor kDefaultColorFrame = SkColorSetRGB(66, 116, 201); 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const SkColor kDefaultColorFrameInactive = SkColorSetRGB(161, 182, 228); 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const gfx::Font& GetTitleFont() { 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static gfx::Font* title_font = NULL; 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!title_font) { 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(USE_AURA) 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) title_font = new gfx::Font(NativeWidgetAura::GetWindowTitleFont()); 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#elif defined(OS_WIN) 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) title_font = new gfx::Font(NativeWidgetWin::GetWindowTitleFont()); 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#elif defined(OS_LINUX) 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // TODO(ben): need to resolve what font this is. 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) title_font = new gfx::Font(); 785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return *title_font; 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/////////////////////////////////////////////////////////////////////////////// 865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// CustomFrameView, public: 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)CustomFrameView::CustomFrameView() 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) : frame_(NULL), 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) window_icon_(NULL), 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) minimize_button_(NULL), 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) maximize_button_(NULL), 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) restore_button_(NULL), 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) close_button_(NULL), 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) should_show_minmax_buttons_(false), 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) frame_background_(new FrameBackground()) { 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)CustomFrameView::~CustomFrameView() { 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void CustomFrameView::Init(Widget* frame) { 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) frame_ = frame; 1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) close_button_ = new ImageButton(this); 1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) close_button_->SetAccessibleName( 1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) l10n_util::GetStringUTF16(IDS_APP_ACCNAME_CLOSE)); 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Close button images will be set in LayoutWindowControls(). 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AddChildView(close_button_); 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) minimize_button_ = InitWindowCaptionButton(IDS_APP_ACCNAME_MINIMIZE, 1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) IDR_MINIMIZE, IDR_MINIMIZE_H, IDR_MINIMIZE_P); 1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) maximize_button_ = InitWindowCaptionButton(IDS_APP_ACCNAME_MAXIMIZE, 1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) IDR_MAXIMIZE, IDR_MAXIMIZE_H, IDR_MAXIMIZE_P); 1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) restore_button_ = InitWindowCaptionButton(IDS_APP_ACCNAME_RESTORE, 1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) IDR_RESTORE, IDR_RESTORE_H, IDR_RESTORE_P); 1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) should_show_minmax_buttons_ = frame_->widget_delegate()->CanMaximize(); 1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (frame_->widget_delegate()->ShouldShowWindowIcon()) { 1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) window_icon_ = new ImageButton(this); 1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AddChildView(window_icon_); 1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/////////////////////////////////////////////////////////////////////////////// 1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// CustomFrameView, NonClientFrameView implementation: 1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)gfx::Rect CustomFrameView::GetBoundsForClientView() const { 1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return client_view_bounds_; 1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)gfx::Rect CustomFrameView::GetWindowBoundsForClientBounds( 1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const gfx::Rect& client_bounds) const { 1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int top_height = NonClientTopBorderHeight(); 1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int border_thickness = NonClientBorderThickness(); 1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return gfx::Rect(std::max(0, client_bounds.x() - border_thickness), 1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::max(0, client_bounds.y() - top_height), 1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) client_bounds.width() + (2 * border_thickness), 1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) client_bounds.height() + top_height + border_thickness); 1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int CustomFrameView::NonClientHitTest(const gfx::Point& point) { 1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Sanity check. 1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!bounds().Contains(point)) 1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return HTNOWHERE; 1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int frame_component = frame_->client_view()->NonClientHitTest(point); 1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // See if we're in the sysmenu region. (We check the ClientView first to be 1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // consistent with OpaqueBrowserFrameView; it's not really necessary here.) 1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gfx::Rect sysmenu_rect(IconBounds()); 1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // In maximized mode we extend the rect to the screen corner to take advantage 1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // of Fitts' Law. 1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (frame_->IsMaximized()) 1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sysmenu_rect.SetRect(0, 0, sysmenu_rect.right(), sysmenu_rect.bottom()); 1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sysmenu_rect.set_x(GetMirroredXForRect(sysmenu_rect)); 1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (sysmenu_rect.Contains(point)) 1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return (frame_component == HTCLIENT) ? HTCLIENT : HTSYSMENU; 1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (frame_component != HTNOWHERE) 1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return frame_component; 1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Then see if the point is within any of the window controls. 1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (close_button_->GetMirroredBounds().Contains(point)) 1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return HTCLOSE; 1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (restore_button_->GetMirroredBounds().Contains(point)) 1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return HTMAXBUTTON; 1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (maximize_button_->GetMirroredBounds().Contains(point)) 1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return HTMAXBUTTON; 1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (minimize_button_->GetMirroredBounds().Contains(point)) 1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return HTMINBUTTON; 1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (window_icon_ && window_icon_->GetMirroredBounds().Contains(point)) 1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return HTSYSMENU; 1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int window_component = GetHTComponentForFrame(point, FrameBorderThickness(), 1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NonClientBorderThickness(), kResizeAreaCornerSize, kResizeAreaCornerSize, 1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) frame_->widget_delegate()->CanResize()); 1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Fall back to the caption if no other component matches. 1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return (window_component == HTNOWHERE) ? HTCAPTION : window_component; 1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void CustomFrameView::GetWindowMask(const gfx::Size& size, 1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gfx::Path* window_mask) { 1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(window_mask); 1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (frame_->IsMaximized()) 1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GetDefaultWindowMask(size, window_mask); 1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void CustomFrameView::ResetWindowControls() { 1962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) restore_button_->SetState(CustomButton::STATE_NORMAL); 1972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) minimize_button_->SetState(CustomButton::STATE_NORMAL); 1982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) maximize_button_->SetState(CustomButton::STATE_NORMAL); 1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The close button isn't affected by this constraint. 2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void CustomFrameView::UpdateWindowIcon() { 2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (window_icon_) 2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) window_icon_->SchedulePaint(); 2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void CustomFrameView::UpdateWindowTitle() { 2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SchedulePaintInRect(title_bounds_); 2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/////////////////////////////////////////////////////////////////////////////// 2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// CustomFrameView, View overrides: 2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void CustomFrameView::OnPaint(gfx::Canvas* canvas) { 2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (frame_->IsMaximized()) 2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PaintMaximizedFrameBorder(canvas); 2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else 2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PaintRestoredFrameBorder(canvas); 2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PaintTitleBar(canvas); 2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (ShouldShowClientEdge()) 2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PaintRestoredClientEdge(canvas); 2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void CustomFrameView::Layout() { 2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LayoutWindowControls(); 2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LayoutTitleBar(); 2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LayoutClientView(); 2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)gfx::Size CustomFrameView::GetPreferredSize() { 2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return frame_->non_client_view()->GetWindowBoundsForClientBounds( 2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gfx::Rect(frame_->client_view()->GetPreferredSize())).size(); 2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 235c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)gfx::Size CustomFrameView::GetMinimumSize() { 236c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return frame_->non_client_view()->GetWindowBoundsForClientBounds( 237c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) gfx::Rect(frame_->client_view()->GetMinimumSize())).size(); 238c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} 239c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 240c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)gfx::Size CustomFrameView::GetMaximumSize() { 241c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) gfx::Size max_size = frame_->client_view()->GetMaximumSize(); 242c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) gfx::Size converted_size = 243c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) frame_->non_client_view()->GetWindowBoundsForClientBounds( 244c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) gfx::Rect(max_size)).size(); 245c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return gfx::Size(max_size.width() == 0 ? 0 : converted_size.width(), 246c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) max_size.height() == 0 ? 0 : converted_size.height()); 247c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} 248c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/////////////////////////////////////////////////////////////////////////////// 2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// CustomFrameView, ButtonListener implementation: 2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void CustomFrameView::ButtonPressed(Button* sender, const ui::Event& event) { 2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (sender == close_button_) 2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) frame_->Close(); 2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else if (sender == minimize_button_) 2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) frame_->Minimize(); 2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else if (sender == maximize_button_) 2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) frame_->Maximize(); 2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else if (sender == restore_button_) 2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) frame_->Restore(); 2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/////////////////////////////////////////////////////////////////////////////// 2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// CustomFrameView, private: 2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int CustomFrameView::FrameBorderThickness() const { 2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return frame_->IsMaximized() ? 0 : kFrameBorderThickness; 2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int CustomFrameView::NonClientBorderThickness() const { 2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // In maximized mode, we don't show a client edge. 2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return FrameBorderThickness() + 2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (ShouldShowClientEdge() ? kClientEdgeThickness : 0); 2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int CustomFrameView::NonClientTopBorderHeight() const { 2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return std::max(FrameBorderThickness() + IconSize(), 2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CaptionButtonY() + kCaptionButtonHeightWithPadding) + 2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TitlebarBottomThickness(); 2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int CustomFrameView::CaptionButtonY() const { 2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Maximized buttons start at window top so that even if their images aren't 2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // drawn flush with the screen edge, they still obey Fitts' Law. 2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return frame_->IsMaximized() ? FrameBorderThickness() : kFrameShadowThickness; 2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int CustomFrameView::TitlebarBottomThickness() const { 2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return kTitlebarTopAndBottomEdgeThickness + 2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (ShouldShowClientEdge() ? kClientEdgeThickness : 0); 2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int CustomFrameView::IconSize() const { 2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_WIN) 2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // This metric scales up if either the titlebar height or the titlebar font 2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // size are increased. 2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return GetSystemMetrics(SM_CYSMICON); 2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#else 2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return std::max(GetTitleFont().GetHeight(), kIconMinimumSize); 3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)gfx::Rect CustomFrameView::IconBounds() const { 3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int size = IconSize(); 3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int frame_thickness = FrameBorderThickness(); 3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Our frame border has a different "3D look" than Windows'. Theirs has a 3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // more complex gradient on the top that they push their icon/title below; 3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // then the maximized window cuts this off and the icon/title are centered 3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // in the remaining space. Because the apparent shape of our border is 3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // simpler, using the same positioning makes things look slightly uncentered 3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // with restored windows, so when the window is restored, instead of 3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // calculating the remaining space from below the frame border, we calculate 3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // from below the 3D edge. 3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int unavailable_px_at_top = frame_->IsMaximized() ? 3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) frame_thickness : kTitlebarTopAndBottomEdgeThickness; 3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // When the icon is shorter than the minimum space we reserve for the caption 3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // button, we vertically center it. We want to bias rounding to put extra 3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // space above the icon, since the 3D edge (+ client edge, for restored 3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // windows) below looks (to the eye) more like additional space than does the 3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // 3D edge (or nothing at all, for maximized windows) above; hence the +1. 3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int y = unavailable_px_at_top + (NonClientTopBorderHeight() - 3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) unavailable_px_at_top - size - TitlebarBottomThickness() + 1) / 2; 3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return gfx::Rect(frame_thickness + kIconLeftSpacing, y, size, size); 3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool CustomFrameView::ShouldShowClientEdge() const { 3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return !frame_->IsMaximized(); 3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void CustomFrameView::PaintRestoredFrameBorder(gfx::Canvas* canvas) { 3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) frame_background_->set_frame_color(GetFrameColor()); 3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const gfx::ImageSkia* frame_image = GetFrameImage(); 3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) frame_background_->set_theme_image(frame_image); 3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) frame_background_->set_top_area_height(frame_image->height()); 3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); 3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) frame_background_->SetCornerImages( 3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) rb.GetImageNamed(IDR_WINDOW_TOP_LEFT_CORNER).ToImageSkia(), 3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) rb.GetImageNamed(IDR_WINDOW_TOP_RIGHT_CORNER).ToImageSkia(), 3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) rb.GetImageNamed(IDR_WINDOW_BOTTOM_LEFT_CORNER).ToImageSkia(), 3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) rb.GetImageNamed(IDR_WINDOW_BOTTOM_RIGHT_CORNER).ToImageSkia()); 3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) frame_background_->SetSideImages( 3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) rb.GetImageNamed(IDR_WINDOW_LEFT_SIDE).ToImageSkia(), 3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) rb.GetImageNamed(IDR_WINDOW_TOP_CENTER).ToImageSkia(), 3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) rb.GetImageNamed(IDR_WINDOW_RIGHT_SIDE).ToImageSkia(), 3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) rb.GetImageNamed(IDR_WINDOW_BOTTOM_CENTER).ToImageSkia()); 3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) frame_background_->PaintRestored(canvas, this); 3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void CustomFrameView::PaintMaximizedFrameBorder(gfx::Canvas* canvas) { 3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const gfx::ImageSkia* frame_image = GetFrameImage(); 3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) frame_background_->set_theme_image(frame_image); 3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) frame_background_->set_top_area_height(frame_image->height()); 3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) frame_background_->PaintMaximized(canvas, this); 3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); 3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // TODO(jamescook): Migrate this into FrameBackground. 3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The bottom of the titlebar actually comes from the top of the Client Edge 3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // graphic, with the actual client edge clipped off the bottom. 3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const gfx::ImageSkia* titlebar_bottom = rb.GetImageNamed( 3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) IDR_APP_TOP_CENTER).ToImageSkia(); 3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int edge_height = titlebar_bottom->height() - 3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (ShouldShowClientEdge() ? kClientEdgeThickness : 0); 3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) canvas->TileImageInt(*titlebar_bottom, 0, 3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) frame_->client_view()->y() - edge_height, width(), edge_height); 3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void CustomFrameView::PaintTitleBar(gfx::Canvas* canvas) { 3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) WidgetDelegate* delegate = frame_->widget_delegate(); 3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // It seems like in some conditions we can be asked to paint after the window 3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // that contains us is WM_DESTROYed. At this point, our delegate is NULL. The 3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // correct long term fix may be to shut down the RootView in WM_DESTROY. 3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!delegate) 3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) canvas->DrawStringInt(delegate->GetWindowTitle(), GetTitleFont(), 3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SK_ColorWHITE, GetMirroredXForRect(title_bounds_), 3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) title_bounds_.y(), title_bounds_.width(), 3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) title_bounds_.height()); 3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void CustomFrameView::PaintRestoredClientEdge(gfx::Canvas* canvas) { 3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gfx::Rect client_area_bounds = frame_->client_view()->bounds(); 3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int client_area_top = client_area_bounds.y(); 3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); 3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const gfx::ImageSkia* top_left = rb.GetImageNamed( 3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) IDR_APP_TOP_LEFT).ToImageSkia(); 3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const gfx::ImageSkia* top = rb.GetImageNamed( 3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) IDR_APP_TOP_CENTER).ToImageSkia(); 3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const gfx::ImageSkia* top_right = rb.GetImageNamed( 3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) IDR_APP_TOP_RIGHT).ToImageSkia(); 3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const gfx::ImageSkia* right = rb.GetImageNamed( 3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) IDR_CONTENT_RIGHT_SIDE).ToImageSkia(); 3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const gfx::ImageSkia* bottom_right = rb.GetImageNamed( 4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) IDR_CONTENT_BOTTOM_RIGHT_CORNER).ToImageSkia(); 4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const gfx::ImageSkia* bottom = rb.GetImageNamed( 4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) IDR_CONTENT_BOTTOM_CENTER).ToImageSkia(); 4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const gfx::ImageSkia* bottom_left = rb.GetImageNamed( 4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) IDR_CONTENT_BOTTOM_LEFT_CORNER).ToImageSkia(); 4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const gfx::ImageSkia* left = rb.GetImageNamed( 4065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) IDR_CONTENT_LEFT_SIDE).ToImageSkia(); 4075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Top. 4095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int top_edge_y = client_area_top - top->height(); 4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) canvas->DrawImageInt(*top_left, client_area_bounds.x() - top_left->width(), 4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) top_edge_y); 4125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) canvas->TileImageInt(*top, client_area_bounds.x(), top_edge_y, 4135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) client_area_bounds.width(), top->height()); 4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) canvas->DrawImageInt(*top_right, client_area_bounds.right(), top_edge_y); 4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Right. 4175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int client_area_bottom = 4185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::max(client_area_top, client_area_bounds.bottom()); 4195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int client_area_height = client_area_bottom - client_area_top; 4205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) canvas->TileImageInt(*right, client_area_bounds.right(), client_area_top, 4215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) right->width(), client_area_height); 4225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Bottom. 4245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) canvas->DrawImageInt(*bottom_right, client_area_bounds.right(), 4255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) client_area_bottom); 4265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) canvas->TileImageInt(*bottom, client_area_bounds.x(), client_area_bottom, 4275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) client_area_bounds.width(), bottom_right->height()); 4285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) canvas->DrawImageInt(*bottom_left, 4295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) client_area_bounds.x() - bottom_left->width(), client_area_bottom); 4305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Left. 4325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) canvas->TileImageInt(*left, client_area_bounds.x() - left->width(), 4335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) client_area_top, left->width(), client_area_height); 4345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Draw the color to fill in the edges. 4365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) canvas->FillRect(gfx::Rect(client_area_bounds.x() - 1, client_area_top - 1, 4375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) client_area_bounds.width() + 1, client_area_bottom - client_area_top + 1), 4385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) kClientEdgeColor); 4395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SkColor CustomFrameView::GetFrameColor() const { 4425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return frame_->IsActive() ? kDefaultColorFrame : kDefaultColorFrameInactive; 4435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const gfx::ImageSkia* CustomFrameView::GetFrameImage() const { 4465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return ui::ResourceBundle::GetSharedInstance().GetImageNamed( 4475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) frame_->IsActive() ? IDR_FRAME : IDR_FRAME_INACTIVE).ToImageSkia(); 4485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void CustomFrameView::LayoutWindowControls() { 4515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) close_button_->SetImageAlignment(ImageButton::ALIGN_LEFT, 4525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ImageButton::ALIGN_BOTTOM); 4535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int caption_y = CaptionButtonY(); 4545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool is_maximized = frame_->IsMaximized(); 4555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // There should always be the same number of non-shadow pixels visible to the 4565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // side of the caption buttons. In maximized mode we extend the rightmost 4575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // button to the screen corner to obey Fitts' Law. 4585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int right_extra_width = is_maximized ? 4595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (kFrameBorderThickness - kFrameShadowThickness) : 0; 4605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gfx::Size close_button_size = close_button_->GetPreferredSize(); 4615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) close_button_->SetBounds(width() - FrameBorderThickness() - 4625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) right_extra_width - close_button_size.width(), caption_y, 4635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) close_button_size.width() + right_extra_width, 4645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) close_button_size.height()); 4655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // When the window is restored, we show a maximized button; otherwise, we show 4675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // a restore button. 4685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool is_restored = !is_maximized && !frame_->IsMinimized(); 4695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ImageButton* invisible_button = is_restored ? restore_button_ 4705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) : maximize_button_; 4715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) invisible_button->SetVisible(false); 4725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ImageButton* visible_button = is_restored ? maximize_button_ 4745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) : restore_button_; 4755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FramePartImage normal_part, hot_part, pushed_part; 4765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (should_show_minmax_buttons_) { 4775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) visible_button->SetVisible(true); 4785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) visible_button->SetImageAlignment(ImageButton::ALIGN_LEFT, 4795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ImageButton::ALIGN_BOTTOM); 4805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gfx::Size visible_button_size = visible_button->GetPreferredSize(); 4815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) visible_button->SetBounds(close_button_->x() - visible_button_size.width(), 4825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) caption_y, visible_button_size.width(), 4835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) visible_button_size.height()); 4845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) minimize_button_->SetVisible(true); 4865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) minimize_button_->SetImageAlignment(ImageButton::ALIGN_LEFT, 4875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ImageButton::ALIGN_BOTTOM); 4885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gfx::Size minimize_button_size = minimize_button_->GetPreferredSize(); 4895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) minimize_button_->SetBounds( 4905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) visible_button->x() - minimize_button_size.width(), caption_y, 4915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) minimize_button_size.width(), 4925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) minimize_button_size.height()); 4935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) normal_part = IDR_CLOSE; 4955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) hot_part = IDR_CLOSE_H; 4965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pushed_part = IDR_CLOSE_P; 4975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 4985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) visible_button->SetVisible(false); 4995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) minimize_button_->SetVisible(false); 5005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) normal_part = IDR_CLOSE_SA; 5025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) hot_part = IDR_CLOSE_SA_H; 5035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pushed_part = IDR_CLOSE_SA_P; 5045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); 5075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) close_button_->SetImage(CustomButton::STATE_NORMAL, 5095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) rb.GetImageNamed(normal_part).ToImageSkia()); 5102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) close_button_->SetImage(CustomButton::STATE_HOVERED, 5115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) rb.GetImageNamed(hot_part).ToImageSkia()); 5122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) close_button_->SetImage(CustomButton::STATE_PRESSED, 5135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) rb.GetImageNamed(pushed_part).ToImageSkia()); 5145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void CustomFrameView::LayoutTitleBar() { 5175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The window title position is calculated based on the icon position, even 5185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // when there is no icon. 5195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gfx::Rect icon_bounds(IconBounds()); 5205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool show_window_icon = window_icon_ != NULL; 5215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (show_window_icon) 5225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) window_icon_->SetBoundsRect(icon_bounds); 5235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The offset between the window left edge and the title text. 5255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int title_x = show_window_icon ? icon_bounds.right() + kTitleIconOffsetX 5265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) : icon_bounds.x(); 5275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int title_height = GetTitleFont().GetHeight(); 5285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We bias the title position so that when the difference between the icon and 5295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // title heights is odd, the extra pixel of the title is above the vertical 5305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // midline rather than below. This compensates for how the icon is already 5315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // biased downwards (see IconBounds()) and helps prevent descenders on the 5325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // title from overlapping the 3D edge at the bottom of the titlebar. 5335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) title_bounds_.SetRect(title_x, 5345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) icon_bounds.y() + ((icon_bounds.height() - title_height - 1) / 2), 5355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::max(0, (should_show_minmax_buttons_ ? 5365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) minimize_button_->x() : close_button_->x()) - kTitleCaptionSpacing - 5375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) title_x), title_height); 5385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void CustomFrameView::LayoutClientView() { 5415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int top_height = NonClientTopBorderHeight(); 5425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int border_thickness = NonClientBorderThickness(); 5435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) client_view_bounds_.SetRect(border_thickness, top_height, 5445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::max(0, width() - (2 * border_thickness)), 5455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::max(0, height() - top_height - border_thickness)); 5465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ImageButton* CustomFrameView::InitWindowCaptionButton( 5495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int accessibility_string_id, 5505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int normal_image_id, 5515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int hot_image_id, 5525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int pushed_image_id) { 5535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); 5545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ImageButton* button = new ImageButton(this); 5555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) button->SetAccessibleName(l10n_util::GetStringUTF16(accessibility_string_id)); 5562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) button->SetImage(CustomButton::STATE_NORMAL, 5575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) rb.GetImageNamed(normal_image_id).ToImageSkia()); 5582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) button->SetImage(CustomButton::STATE_HOVERED, 5595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) rb.GetImageNamed(hot_image_id).ToImageSkia()); 5602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) button->SetImage(CustomButton::STATE_PRESSED, 5615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) rb.GetImageNamed(pushed_image_id).ToImageSkia()); 5625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AddChildView(button); 5635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return button; 5645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace views 567