diff options
author | pkasting@chromium.org <pkasting@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-01-30 02:36:54 +0000 |
---|---|---|
committer | pkasting@chromium.org <pkasting@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-01-30 02:36:54 +0000 |
commit | eabd506f273e5680225f0b0cabf6b2a162126cd4 (patch) | |
tree | 5cc9bddbda42f1473a39fa60712232cbd667b0ca /chrome | |
parent | 13324b2fe5b579fe0338ab30084b01e92e7523be (diff) | |
download | chromium_src-eabd506f273e5680225f0b0cabf6b2a162126cd4.zip chromium_src-eabd506f273e5680225f0b0cabf6b2a162126cd4.tar.gz chromium_src-eabd506f273e5680225f0b0cabf6b2a162126cd4.tar.bz2 |
Fix various problems with constrained windows and/or custom frame windows:
* Wrong titlebar height
* Titlebars not handling custom font size properly
* Drawing errors in maximized mode
* One-pixel overlap glitch on bottom corners of client edges
* Borders not handling custom border sizes correctly
* Unnecessarily small top resize area (unlike in the main window, there's no competition here between resizing and window dragging in the same small strip)
* Wrong icon sizing (only a problem in theory, no one uses this code ATM)
These files are now very much like simplified versions of the opaque_non_client_view.cc code (which was the goal); eventually all these should be refactorable.
BUG=5054
Review URL: http://codereview.chromium.org/19484
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@8947 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome')
-rw-r--r-- | chrome/browser/views/constrained_window_impl.cc | 113 | ||||
-rw-r--r-- | chrome/views/custom_frame_window.cc | 260 |
2 files changed, 266 insertions, 107 deletions
diff --git a/chrome/browser/views/constrained_window_impl.cc b/chrome/browser/views/constrained_window_impl.cc index e42a72a..dac5356 100644 --- a/chrome/browser/views/constrained_window_impl.cc +++ b/chrome/browser/views/constrained_window_impl.cc @@ -13,6 +13,7 @@ #include "chrome/browser/tab_contents/web_contents.h" #include "chrome/browser/tab_contents/web_contents_view.h" #include "chrome/browser/toolbar_model.h" +#include "chrome/browser/views/frame/browser_view.h" #include "chrome/browser/web_app.h" #include "chrome/browser/window_sizer.h" #include "chrome/common/chrome_constants.h" @@ -216,10 +217,23 @@ class ConstrainedWindowNonClientView virtual void ButtonPressed(views::BaseButton* sender); private: + // Returns the thickness of the border that makes up the window frame edges. + // This does not include any client edge. + int FrameBorderThickness() const; + + // Returns the thickness of the entire nonclient left, right, and bottom + // borders, including both the window frame and any client edge. + int NonClientBorderThickness() const; + // Returns the height of the entire nonclient top border, including the window // frame, any title area, and any connected client edge. int NonClientTopBorderHeight() const; + // Calculates multiple values related to title layout. Returns the height of + // the entire titlebar including any connected client edge. + int TitleCoordinates(int* title_top_spacing, + int* title_thickness) const; + // Paints different parts of the window to the incoming canvas. void PaintFrameBorder(ChromeCanvas* canvas); void PaintTitleBar(ChromeCanvas* canvas); @@ -252,20 +266,31 @@ class ConstrainedWindowNonClientView }; ChromeFont ConstrainedWindowNonClientView::title_font_; -static const int kWindowLeftSpacing = 5; -static const int kWindowControlsTopOffset = 1; -static const int kWindowControlsRightOffset = 4; -static const int kTitleTopOffset = 6; -static const int kTitleBottomSpacing = 5; -static const int kNoTitleTopSpacing = 8; -static const int kResizeAreaSize = 5; -static const int kResizeAreaNorthSize = 3; -static const int kResizeAreaCornerSize = 16; -static const int kWindowHorizontalBorderSize = 5; -static const int kWindowVerticalBorderSize = 5; -static const int kWindowIconSize = 16; namespace { +// The frame border is only visible in restored mode and is hardcoded to 4 px on +// each side regardless of the system window border size. +const int kFrameBorderThickness = 4; +// Various edges of the frame border have a 1 px shadow along their edges; in a +// few cases we shift elements based on this amount for visual appeal. +const int kFrameShadowThickness = 1; +// In the window corners, the resize areas don't actually expand bigger, but the +// 16 px at the end of each edge triggers diagonal resizing. +const int kResizeAreaCornerSize = 16; +// The titlebar never shrinks to less than 20 px tall, including the height of +// the frame border and client edge. +const int kTitlebarMinimumHeight = 20; +// The icon is inset 2 px from the left frame border. +const int kIconLeftSpacing = 2; +// The title text starts 2 px below the bottom of the top frame border. +const int kTitleTopSpacing = 2; +// There is a 5 px gap between the title text and the caption buttons. +const int kTitleCaptionSpacing = 5; +// The caption buttons are always drawn 1 px down from the visible top of the +// window (the true top in restored mode, or the top of the screen in maximized +// mode). +const int kCaptionTopSpacing = 1; + const SkColor kContentsBorderShadow = SkColorSetARGB(51, 0, 0, 0); const SkColor kContentsBorderColor = SkColorSetRGB(219, 235, 255); } @@ -315,16 +340,18 @@ gfx::Rect ConstrainedWindowNonClientView::CalculateClientAreaBounds( int width, int height) const { int top_height = NonClientTopBorderHeight(); - return gfx::Rect(kWindowHorizontalBorderSize, top_height, - std::max(0, width - (2 * kWindowHorizontalBorderSize)), - std::max(0, height - top_height - kWindowVerticalBorderSize)); + int border_thickness = NonClientBorderThickness(); + return gfx::Rect(border_thickness, top_height, + std::max(0, width - (2 * border_thickness)), + std::max(0, height - top_height - border_thickness)); } gfx::Size ConstrainedWindowNonClientView::CalculateWindowSizeForClientSize( int width, int height) const { - return gfx::Size(width + (2 * kWindowHorizontalBorderSize), - height + NonClientTopBorderHeight() + kWindowVerticalBorderSize); + int border_thickness = NonClientBorderThickness(); + return gfx::Size(width + (2 * border_thickness), + height + NonClientTopBorderHeight() + border_thickness); } CPoint ConstrainedWindowNonClientView::GetSystemMenuPoint() const { @@ -344,8 +371,8 @@ int ConstrainedWindowNonClientView::NonClientHitTest(const gfx::Point& point) { if (close_button_->GetBounds(APPLY_MIRRORING_TRANSFORMATION).Contains(point)) return HTCLOSE; - int window_component = GetHTComponentForFrame(point, kResizeAreaNorthSize, - kResizeAreaSize, kResizeAreaCornerSize, + int window_component = GetHTComponentForFrame(point, FrameBorderThickness(), + NonClientBorderThickness(), kResizeAreaCornerSize, container_->window_delegate()->CanResize()); // Fall back to the caption if no other component matches. return ((window_component == HTNOWHERE) && bounds().Contains(point)) ? @@ -396,8 +423,9 @@ void ConstrainedWindowNonClientView::Layout() { gfx::Size ConstrainedWindowNonClientView::GetPreferredSize() { gfx::Size prefsize(container_->client_view()->GetPreferredSize()); - prefsize.Enlarge(2 * kWindowHorizontalBorderSize, - NonClientTopBorderHeight() + kWindowVerticalBorderSize); + int border_thickness = NonClientBorderThickness(); + prefsize.Enlarge(2 * border_thickness, + NonClientTopBorderHeight() + border_thickness); return prefsize; } @@ -422,8 +450,31 @@ void ConstrainedWindowNonClientView::ButtonPressed(views::BaseButton* sender) { //////////////////////////////////////////////////////////////////////////////// // ConstrainedWindowNonClientView, private: +int ConstrainedWindowNonClientView::FrameBorderThickness() const { + return kFrameBorderThickness; +} + +int ConstrainedWindowNonClientView::NonClientBorderThickness() const { + return FrameBorderThickness() + kClientEdgeThickness; +} + int ConstrainedWindowNonClientView::NonClientTopBorderHeight() const { - return kTitleTopOffset + title_font_.height() + kTitleBottomSpacing; + int title_top_spacing, title_thickness; + return TitleCoordinates(&title_top_spacing, &title_thickness); +} + +int ConstrainedWindowNonClientView::TitleCoordinates( + int* title_top_spacing, + int* title_thickness) const { + int frame_thickness = FrameBorderThickness(); + int min_titlebar_height = kTitlebarMinimumHeight + frame_thickness; + *title_top_spacing = frame_thickness + kTitleTopSpacing; + // The bottom spacing should be the same apparent height as the top spacing, + // plus have the client edge tacked on. + int title_bottom_spacing = *title_top_spacing + kClientEdgeThickness; + *title_thickness = std::max(title_font_.height(), + min_titlebar_height - *title_top_spacing - title_bottom_spacing); + return *title_top_spacing + *title_thickness + title_bottom_spacing; } void ConstrainedWindowNonClientView::PaintFrameBorder(ChromeCanvas* canvas) { @@ -480,7 +531,7 @@ void ConstrainedWindowNonClientView::PaintClientEdge(ChromeCanvas* canvas) { gfx::Rect client_edge_bounds(CalculateClientAreaBounds(width(), height())); client_edge_bounds.Inset(-kClientEdgeThickness, -kClientEdgeThickness); gfx::Rect frame_shadow_bounds(client_edge_bounds); - frame_shadow_bounds.Inset(-1, -1); + frame_shadow_bounds.Inset(-kFrameShadowThickness, -kFrameShadowThickness); canvas->FillRectInt(kContentsBorderShadow, frame_shadow_bounds.x(), frame_shadow_bounds.y(), frame_shadow_bounds.width(), @@ -494,18 +545,20 @@ void ConstrainedWindowNonClientView::PaintClientEdge(ChromeCanvas* canvas) { void ConstrainedWindowNonClientView::LayoutWindowControls() { gfx::Size close_button_size = close_button_->GetPreferredSize(); close_button_->SetBounds( - width() - close_button_size.width() - kWindowControlsRightOffset, - kWindowControlsTopOffset, close_button_size.width(), + width() - close_button_size.width() - FrameBorderThickness(), + kCaptionTopSpacing, close_button_size.width(), close_button_size.height()); } void ConstrainedWindowNonClientView::LayoutTitleBar() { // Size the title. - int title_x = kWindowLeftSpacing; - int title_top_spacing = NonClientTopBorderHeight(); - title_bounds_.SetRect(title_x, kTitleTopOffset, - close_button_->x() - kWindowLeftSpacing - title_x, - title_font_.height()); + int title_x = FrameBorderThickness() + kIconLeftSpacing; + int title_top_spacing, title_thickness; + TitleCoordinates(&title_top_spacing, &title_thickness); + title_bounds_.SetRect(title_x, + title_top_spacing + ((title_thickness - title_font_.height()) / 2), + std::max(0, close_button_->x() - kTitleCaptionSpacing - title_x), + title_font_.height()); } void ConstrainedWindowNonClientView::LayoutClientView() { diff --git a/chrome/views/custom_frame_window.cc b/chrome/views/custom_frame_window.cc index 76735fd..a97b921 100644 --- a/chrome/views/custom_frame_window.cc +++ b/chrome/views/custom_frame_window.cc @@ -216,7 +216,6 @@ class InactiveWindowResources : public WindowResources { SkBitmap* ActiveWindowResources::standard_frame_bitmaps_[]; SkBitmap* InactiveWindowResources::standard_frame_bitmaps_[]; - /////////////////////////////////////////////////////////////////////////////// // // DefaultNonClientView @@ -251,18 +250,32 @@ class DefaultNonClientView : public NonClientView, virtual void ButtonPressed(BaseButton* sender); private: - // Updates the system menu icon button. - void SetWindowIcon(SkBitmap window_icon); + // Returns the thickness of the border that makes up the window frame edges. + // This does not include any client edge. + int FrameBorderThickness() const; + + // Returns the thickness of the entire nonclient left, right, and bottom + // borders, including both the window frame and any client edge. + int NonClientBorderThickness() const; // Returns the height of the entire nonclient top border, including the window // frame, any title area, and any connected client edge. int NonClientTopBorderHeight() const; + // A bottom border, and, in restored mode, a client edge are drawn at the + // bottom of the titlebar. This returns the total height drawn. + int BottomEdgeThicknessWithinNonClientHeight() const; + + // Calculates multiple values related to title layout. Returns the height of + // the entire titlebar including any connected client edge. + int TitleCoordinates(int* title_top_spacing, + int* title_thickness) const; + // Paint various sub-components of this view. void PaintRestoredFrameBorder(ChromeCanvas* canvas); void PaintMaximizedFrameBorder(ChromeCanvas* canvas); void PaintTitleBar(ChromeCanvas* canvas); - void PaintClientEdge(ChromeCanvas* canvas); + void PaintRestoredClientEdge(ChromeCanvas* canvas); // Layout various sub-components of this view. void LayoutWindowControls(); @@ -307,22 +320,50 @@ class DefaultNonClientView : public NonClientView, WindowResources* DefaultNonClientView::active_resources_ = NULL; WindowResources* DefaultNonClientView::inactive_resources_ = NULL; ChromeFont DefaultNonClientView::title_font_; -static const int kWindowControlsTopOffset = 1; -static const int kWindowControlsRightOffset = 5; -static const int kWindowControlsTopZoomedOffset = 1; -static const int kWindowControlsRightZoomedOffset = 5; -static const int kWindowTopMarginZoomed = 1; -static const int kWindowIconLeftOffset = 5; -static const int kWindowIconTopOffset = 5; -static const int kTitleTopOffset = 6; -static const int kWindowIconTitleSpacing = 3; -static const int kTitleBottomSpacing = 6; -static const int kNoTitleTopSpacing = 8; -static const int kResizeAreaSize = 5; -static const int kResizeAreaNorthSize = 3; -static const int kResizeAreaCornerSize = 16; -static const int kWindowHorizontalBorderSize = 4; -static const int kWindowVerticalBorderSize = 4; + +namespace { +// The frame border is only visible in restored mode and is hardcoded to 4 px on +// each side regardless of the system window border size. +const int kFrameBorderThickness = 4; +// Various edges of the frame border have a 1 px shadow along their edges; in a +// few cases we shift elements based on this amount for visual appeal. +const int kFrameShadowThickness = 1; +// While resize areas on Windows are normally the same size as the window +// borders, our top area is shrunk by 1 px to make it easier to move the window +// around with our thinner top grabbable strip. (Incidentally, our side and +// bottom resize areas don't match the frame border thickness either -- they +// span the whole nonclient area, so there's no "dead zone" for the mouse.) +const int kTopResizeAdjust = 1; +// In the window corners, the resize areas don't actually expand bigger, but the +// 16 px at the end of each edge triggers diagonal resizing. +const int kResizeAreaCornerSize = 16; +// The titlebar never shrinks to less than 18 px tall, plus the height of the +// frame border and any bottom edge. +const int kTitlebarMinimumHeight = 18; +// The icon is inset 2 px from the left frame border. +const int kIconLeftSpacing = 2; +// The icon takes up 16/25th of the available titlebar height. (This is +// expressed as two ints to avoid precision losses leading to off-by-one pixel +// errors.) +const int kIconHeightFractionNumerator = 16; +const int kIconHeightFractionDenominator = 25; +// The icon never shrinks below 16 px on a side. +const int kIconMinimumSize = 16; +// Because our frame border has a different "3D look" than Windows', with a less +// cluttered top edge, we need to shift the icon up by 1 px in restored mode so +// it looks more centered. +const int kIconRestoredAdjust = 1; +// There is a 4 px gap between the icon and the title text. +const int kIconTitleSpacing = 4; +// The title text starts 2 px below the bottom of the top frame border. +const int kTitleTopSpacing = 2; +// There is a 5 px gap between the title text and the caption buttons. +const int kTitleCaptionSpacing = 5; +// The caption buttons are always drawn 1 px down from the visible top of the +// window (the true top in restored mode, or the top of the screen in maximized +// mode). +const int kCaptionTopSpacing = 1; +} /////////////////////////////////////////////////////////////////////////////// // DefaultNonClientView, public: @@ -386,17 +427,18 @@ DefaultNonClientView::~DefaultNonClientView() { gfx::Rect DefaultNonClientView::CalculateClientAreaBounds(int width, int height) const { int top_height = NonClientTopBorderHeight(); - int border_thickness = kWindowHorizontalBorderSize; + int border_thickness = NonClientBorderThickness(); return gfx::Rect(border_thickness, top_height, - std::max(0, width - (2 * border_thickness)), - std::max(0, height - top_height - kWindowVerticalBorderSize)); + std::max(0, width - (2 * border_thickness)), + std::max(0, height - top_height - border_thickness)); } gfx::Size DefaultNonClientView::CalculateWindowSizeForClientSize( int width, int height) const { - return gfx::Size(width + (2 * kWindowHorizontalBorderSize), - height + NonClientTopBorderHeight() + kWindowVerticalBorderSize); + int border_thickness = NonClientBorderThickness(); + return gfx::Size(width + (2 * border_thickness), + height + NonClientTopBorderHeight() + border_thickness); } CPoint DefaultNonClientView::GetSystemMenuPoint() const { @@ -431,8 +473,8 @@ int DefaultNonClientView::NonClientHitTest(const gfx::Point& point) { point)) return HTSYSMENU; - int window_component = GetHTComponentForFrame(point, kResizeAreaNorthSize, - kResizeAreaSize, kResizeAreaCornerSize, + int window_component = GetHTComponentForFrame(point, FrameBorderThickness(), + NonClientBorderThickness(), kResizeAreaCornerSize, container_->window_delegate()->CanResize()); // Fall back to the caption if no other component matches. return ((window_component == HTNOWHERE) && bounds().Contains(point)) ? @@ -482,7 +524,8 @@ void DefaultNonClientView::Paint(ChromeCanvas* canvas) { else PaintRestoredFrameBorder(canvas); PaintTitleBar(canvas); - PaintClientEdge(canvas); + if (!container_->IsMaximized()) + PaintRestoredClientEdge(canvas); } void DefaultNonClientView::Layout() { @@ -493,8 +536,9 @@ void DefaultNonClientView::Layout() { gfx::Size DefaultNonClientView::GetPreferredSize() { gfx::Size prefsize(container_->client_view()->GetPreferredSize()); - prefsize.Enlarge(2 * kWindowHorizontalBorderSize, - NonClientTopBorderHeight() + kWindowVerticalBorderSize); + int border_thickness = NonClientBorderThickness(); + prefsize.Enlarge(2 * border_thickness, + NonClientTopBorderHeight() + border_thickness); return prefsize; } @@ -524,8 +568,50 @@ void DefaultNonClientView::ButtonPressed(BaseButton* sender) { /////////////////////////////////////////////////////////////////////////////// // DefaultNonClientView, private: +int DefaultNonClientView::FrameBorderThickness() const { + return container_->IsMaximized() ? + GetSystemMetrics(SM_CXSIZEFRAME) : kFrameBorderThickness; +} + +int DefaultNonClientView::NonClientBorderThickness() const { + // In maximized mode, we don't show a client edge. + return FrameBorderThickness() + + (container_->IsMaximized() ? 0 : kClientEdgeThickness); +} + int DefaultNonClientView::NonClientTopBorderHeight() const { - return kTitleTopOffset + title_font_.height() + kTitleBottomSpacing; + int title_top_spacing, title_thickness; + return TitleCoordinates(&title_top_spacing, &title_thickness); +} + +int DefaultNonClientView::BottomEdgeThicknessWithinNonClientHeight() const { + return kFrameShadowThickness + + (container_->IsMaximized() ? 0 : kClientEdgeThickness); +} + +int DefaultNonClientView::TitleCoordinates(int* title_top_spacing, + int* title_thickness) const { + int frame_thickness = FrameBorderThickness(); + int min_titlebar_height = kTitlebarMinimumHeight + frame_thickness; + *title_top_spacing = frame_thickness + kTitleTopSpacing; + // The bottom spacing should be the same apparent height as the top spacing. + // Because the actual top spacing height varies based on the system border + // thickness, we calculate this based on the restored top spacing and then + // adjust for maximized mode. We also don't include the frame shadow here, + // since while it's part of the bottom spacing it will be added in at the end. + int title_bottom_spacing = + kFrameBorderThickness + kTitleTopSpacing - kFrameShadowThickness; + if (container_->IsMaximized()) { + // When we maximize, the top border appears to be chopped off; shift the + // title down to stay centered within the remaining space. + int title_adjust = (kFrameBorderThickness / 2); + *title_top_spacing += title_adjust; + title_bottom_spacing -= title_adjust; + } + *title_thickness = std::max(title_font_.height(), + min_titlebar_height - *title_top_spacing - title_bottom_spacing); + return *title_top_spacing + *title_thickness + title_bottom_spacing + + BottomEdgeThicknessWithinNonClientHeight(); } void DefaultNonClientView::PaintRestoredFrameBorder(ChromeCanvas* canvas) { @@ -575,7 +661,15 @@ void DefaultNonClientView::PaintRestoredFrameBorder(ChromeCanvas* canvas) { void DefaultNonClientView::PaintMaximizedFrameBorder( ChromeCanvas* canvas) { SkBitmap* top_edge = resources()->GetPartBitmap(FRAME_TOP_EDGE); - canvas->TileImageInt(*top_edge, 0, 0, width(), top_edge->height()); + canvas->TileImageInt(*top_edge, 0, FrameBorderThickness(), width(), + top_edge->height()); + + // The bottom of the titlebar actually comes from the top of the Client Edge + // graphic, with the actual client edge clipped off the bottom. + SkBitmap* titlebar_bottom = resources()->GetPartBitmap(FRAME_CLIENT_EDGE_TOP); + int edge_height = titlebar_bottom->height() - kClientEdgeThickness; + canvas->TileImageInt(*titlebar_bottom, 0, + container_->client_view()->y() - edge_height, width(), edge_height); } void DefaultNonClientView::PaintTitleBar(ChromeCanvas* canvas) { @@ -585,7 +679,7 @@ void DefaultNonClientView::PaintTitleBar(ChromeCanvas* canvas) { title_bounds_.width(), title_bounds_.height()); } -void DefaultNonClientView::PaintClientEdge(ChromeCanvas* canvas) { +void DefaultNonClientView::PaintRestoredClientEdge(ChromeCanvas* canvas) { gfx::Rect client_area_bounds = container_->client_view()->bounds(); int client_area_top = client_area_bounds.y(); @@ -613,22 +707,23 @@ void DefaultNonClientView::PaintClientEdge(ChromeCanvas* canvas) { canvas->DrawBitmapInt(*top_right, client_area_bounds.right(), top_edge_y); // Right. + int client_area_bottom = + std::max(client_area_top, client_area_bounds.bottom()); + int client_area_height = client_area_bottom - client_area_top; canvas->TileImageInt(*right, client_area_bounds.right(), client_area_top, - right->width(), client_area_bounds.height()); + right->width(), client_area_height); // Bottom. canvas->DrawBitmapInt(*bottom_right, client_area_bounds.right(), - client_area_bounds.bottom()); - canvas->TileImageInt(*bottom, client_area_bounds.x(), - client_area_bounds.bottom(), + client_area_bottom); + canvas->TileImageInt(*bottom, client_area_bounds.x(), client_area_bottom, client_area_bounds.width(), bottom_right->height()); canvas->DrawBitmapInt(*bottom_left, - client_area_bounds.x() - bottom_left->width(), - client_area_bounds.bottom()); + client_area_bounds.x() - bottom_left->width(), client_area_bottom); // Left. canvas->TileImageInt(*left, client_area_bounds.x() - left->width(), - client_area_top, left->width(), client_area_bounds.height()); + client_area_top, left->width(), client_area_height); } void DefaultNonClientView::LayoutWindowControls() { @@ -636,14 +731,16 @@ void DefaultNonClientView::LayoutWindowControls() { // Maximized buttons start at window top so that even if their images aren't // drawn flush with the screen edge, they still obey Fitts' Law. bool is_maximized = container_->IsMaximized(); - int caption_y = is_maximized ? 0 : kWindowControlsTopOffset; - int top_extra_height = is_maximized ? kWindowControlsTopZoomedOffset : 0; + int frame_thickness = FrameBorderThickness(); + int caption_y = is_maximized ? frame_thickness : kCaptionTopSpacing; + int top_extra_height = is_maximized ? kCaptionTopSpacing : 0; // There should always be the same number of non-shadow pixels visible to the // side of the caption buttons. In maximized mode we extend the rightmost // button to the screen corner to obey Fitts' Law. - int right_extra_width = is_maximized ? kWindowControlsRightZoomedOffset : 0; + int right_extra_width = is_maximized ? + (kFrameBorderThickness - kFrameShadowThickness) : 0; int right_spacing = is_maximized ? - kWindowControlsRightZoomedOffset : kWindowControlsRightOffset; + (GetSystemMetrics(SM_CXSIZEFRAME) + right_extra_width) : frame_thickness; gfx::Size close_button_size = close_button_->GetPreferredSize(); close_button_->SetBounds(width() - close_button_size.width() - right_spacing, caption_y, @@ -698,41 +795,48 @@ void DefaultNonClientView::LayoutWindowControls() { } void DefaultNonClientView::LayoutTitleBar() { - int top_offset = container_->IsMaximized() ? kWindowTopMarginZoomed : 0; - WindowDelegate* d = container_->window_delegate(); - - // Size the window icon, if visible. - if (d->ShouldShowWindowIcon()) { - system_menu_button_->SetVisible(true); - gfx::Size ps = system_menu_button_->GetPreferredSize(); - system_menu_button_->SetBounds( - kWindowIconLeftOffset, kWindowIconTopOffset + top_offset, ps.width(), - ps.height()); - } else { - // Put the menu in the right place at least even if it is hidden so we - // can size the title based on its position. - system_menu_button_->SetBounds(kWindowIconLeftOffset, - kWindowIconTopOffset, 0, 0); - } + // Always lay out the icon, even when it's not present, so we can lay out the + // window title based on its position. + int frame_thickness = FrameBorderThickness(); + int icon_x = frame_thickness + kIconLeftSpacing; + + // The usable height of the titlebar area is the total height minus the top + // resize border and any edge area we draw at its bottom. + int title_top_spacing, title_thickness; + int top_height = TitleCoordinates(&title_top_spacing, &title_thickness); + int available_height = top_height - frame_thickness - + BottomEdgeThicknessWithinNonClientHeight(); + + // The icon takes up a constant fraction of the available height, down to a + // minimum size, and is always an even number of pixels on a side (presumably + // to make scaled icons look better). It's centered within the usable height. + int icon_size = std::max((available_height * kIconHeightFractionNumerator / + kIconHeightFractionDenominator) / 2 * 2, kIconMinimumSize); + int icon_y = ((available_height - icon_size) / 2) + frame_thickness; + + // Hack: Our frame border has a different "3D look" than Windows'. Theirs has + // a more complex gradient on the top that they push their icon/title below; + // then the maximized window cuts this off and the icon/title are centered in + // the remaining space. Because the apparent shape of our border is simpler, + // using the same positioning makes things look slightly uncentered with + // restored windows, so we come up to compensate. + if (!container_->IsMaximized()) + icon_y -= kIconRestoredAdjust; + + views::WindowDelegate* d = container_->window_delegate(); + if (!d->ShouldShowWindowIcon()) + icon_size = 0; + system_menu_button_->SetBounds(icon_x, icon_y, icon_size, icon_size); // Size the title. - gfx::Rect system_menu_bounds = system_menu_button_->bounds(); - int spacing = d->ShouldShowWindowIcon() ? kWindowIconTitleSpacing : 0; - int title_right = should_show_minmax_buttons_ ? - minimize_button_->x() : close_button_->x(); - int title_left = system_menu_bounds.right() + spacing; - title_bounds_.SetRect(title_left, kTitleTopOffset + top_offset, - std::max(0, static_cast<int>(title_right - system_menu_bounds.right())), - title_font_.height()); - - // Center the icon within the height of the title if the title is taller. - int delta_y = title_bounds_.height() - system_menu_button_->height(); - if (delta_y > 0) { - int new_y = title_bounds_.y() + static_cast<int>(delta_y / 2); - system_menu_button_->SetBounds(system_menu_button_->x(), new_y, - system_menu_button_->width(), - system_menu_button_->height()); - } + int icon_right = icon_x + icon_size; + int title_x = + icon_right + (d->ShouldShowWindowIcon() ? kIconTitleSpacing : 0); + int title_right = (should_show_minmax_buttons_ ? + minimize_button_->x() : close_button_->x()) - kTitleCaptionSpacing; + title_bounds_.SetRect(title_x, + title_top_spacing + ((title_thickness - title_font_.height()) / 2), + std::max(0, title_right - title_x), title_font_.height()); } void DefaultNonClientView::LayoutClientView() { @@ -746,7 +850,9 @@ void DefaultNonClientView::InitClass() { if (!initialized) { active_resources_ = new ActiveWindowResources; inactive_resources_ = new InactiveWindowResources; + title_font_ = win_util::GetWindowTitleFont(); + initialized = true; } } |