summaryrefslogtreecommitdiffstats
path: root/chrome/views
diff options
context:
space:
mode:
Diffstat (limited to 'chrome/views')
-rw-r--r--chrome/views/custom_frame_window.cc281
1 files changed, 117 insertions, 164 deletions
diff --git a/chrome/views/custom_frame_window.cc b/chrome/views/custom_frame_window.cc
index 91dbdd2..76735fd 100644
--- a/chrome/views/custom_frame_window.cc
+++ b/chrome/views/custom_frame_window.cc
@@ -254,13 +254,14 @@ class DefaultNonClientView : public NonClientView,
// Updates the system menu icon button.
void SetWindowIcon(SkBitmap window_icon);
- // Returns the height of the non-client area at the top of the window (the
- // title bar, etc).
- int CalculateContentsTop() 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;
// Paint various sub-components of this view.
- void PaintFrameBorder(ChromeCanvas* canvas);
+ void PaintRestoredFrameBorder(ChromeCanvas* canvas);
void PaintMaximizedFrameBorder(ChromeCanvas* canvas);
+ void PaintTitleBar(ChromeCanvas* canvas);
void PaintClientEdge(ChromeCanvas* canvas);
// Layout various sub-components of this view.
@@ -290,9 +291,6 @@ class DefaultNonClientView : public NonClientView,
Button* system_menu_button_; // Uses the window icon if visible.
bool should_show_minmax_buttons_;
- // The window icon.
- SkBitmap window_icon_;
-
// The window that owns this view.
CustomFrameWindow* container_;
@@ -387,75 +385,58 @@ DefaultNonClientView::~DefaultNonClientView() {
gfx::Rect DefaultNonClientView::CalculateClientAreaBounds(int width,
int height) const {
- int top_margin = CalculateContentsTop();
- return gfx::Rect(kWindowHorizontalBorderSize, top_margin,
- std::max(0, width - (2 * kWindowHorizontalBorderSize)),
- std::max(0, height - top_margin - kWindowVerticalBorderSize));
+ int top_height = NonClientTopBorderHeight();
+ int border_thickness = kWindowHorizontalBorderSize;
+ return gfx::Rect(border_thickness, top_height,
+ std::max(0, width - (2 * border_thickness)),
+ std::max(0, height - top_height - kWindowVerticalBorderSize));
}
gfx::Size DefaultNonClientView::CalculateWindowSizeForClientSize(
int width,
int height) const {
return gfx::Size(width + (2 * kWindowHorizontalBorderSize),
- height + CalculateContentsTop() + kWindowVerticalBorderSize);
+ height + NonClientTopBorderHeight() + kWindowVerticalBorderSize);
}
CPoint DefaultNonClientView::GetSystemMenuPoint() const {
- CPoint system_menu_point(
- system_menu_button_->x(),
+ // TODO(pkasting): This is wrong; Windows native runs the menu at the bottom
+ // of the titlebar, not the bottom of the window icon.
+ CPoint system_menu_point(system_menu_button_->x(),
system_menu_button_->y() + system_menu_button_->height());
MapWindowPoints(container_->GetHWND(), HWND_DESKTOP, &system_menu_point, 1);
return system_menu_point;
}
-// There is a subtle point that needs to be explained regarding the manner in
-// which this function returns the HT* code Windows is expecting:
-//
-// |point| contains the cursor position in this View's coordinate system. If
-// this View uses a right-to-left UI layout, the position represented by
-// |point| will not reflect the UI mirroring because we don't create the
-// container's HWND with WS_EX_LAYOUTRTL. Therefore, whenever the cursor
-// position resides within the boundaries of one of our child Views (for
-// example, the close_button_), we must retrieve the child View bounds such
-// that bound are mirrored if the View uses right-to-left UI layout. This is
-// why this function passes APPLY_MIRRORING_TRANSFORMATION as the |settings|
-// whenever it calls GetBounds().
int DefaultNonClientView::NonClientHitTest(const gfx::Point& point) {
// First see if it's within the grow box area, since that overlaps the client
// bounds.
- int component = container_->client_view()->NonClientHitTest(point);
- if (component != HTNOWHERE)
- return component;
+ int frame_component = container_->client_view()->NonClientHitTest(point);
+ if (frame_component != HTNOWHERE)
+ return frame_component;
// Then see if the point is within any of the window controls.
- gfx::Rect button_bounds =
- close_button_->GetBounds(APPLY_MIRRORING_TRANSFORMATION);
- if (button_bounds.Contains(point))
+ if (close_button_->GetBounds(APPLY_MIRRORING_TRANSFORMATION).Contains(point))
return HTCLOSE;
- button_bounds = restore_button_->GetBounds(APPLY_MIRRORING_TRANSFORMATION);
- if (button_bounds.Contains(point))
+ if (restore_button_->GetBounds(APPLY_MIRRORING_TRANSFORMATION).Contains(
+ point))
return HTMAXBUTTON;
- button_bounds = maximize_button_->GetBounds(APPLY_MIRRORING_TRANSFORMATION);
- if (button_bounds.Contains(point))
+ if (maximize_button_->GetBounds(APPLY_MIRRORING_TRANSFORMATION).Contains(
+ point))
return HTMAXBUTTON;
- button_bounds = minimize_button_->GetBounds(APPLY_MIRRORING_TRANSFORMATION);
- if (button_bounds.Contains(point))
+ if (minimize_button_->GetBounds(APPLY_MIRRORING_TRANSFORMATION).Contains(
+ point))
return HTMINBUTTON;
- button_bounds =
- system_menu_button_->GetBounds(APPLY_MIRRORING_TRANSFORMATION);
- if (button_bounds.Contains(point))
+ if (system_menu_button_->GetBounds(APPLY_MIRRORING_TRANSFORMATION).Contains(
+ point))
return HTSYSMENU;
- component = GetHTComponentForFrame(point, kResizeAreaNorthSize,
+ int window_component = GetHTComponentForFrame(point, kResizeAreaNorthSize,
kResizeAreaSize, kResizeAreaCornerSize,
container_->window_delegate()->CanResize());
- if (component == HTNOWHERE) {
- // Finally fall back to the caption.
- if (bounds().Contains(point))
- component = HTCAPTION;
- // Otherwise, the point is outside the window's bounds.
- }
- return component;
+ // Fall back to the caption if no other component matches.
+ return ((window_component == HTNOWHERE) && bounds().Contains(point)) ?
+ HTCAPTION : window_component;
}
void DefaultNonClientView::GetWindowMask(const gfx::Size& size,
@@ -496,32 +477,24 @@ void DefaultNonClientView::ResetWindowControls() {
// DefaultNonClientView, View overrides:
void DefaultNonClientView::Paint(ChromeCanvas* canvas) {
- if (container_->IsMaximized()) {
+ if (container_->IsMaximized())
PaintMaximizedFrameBorder(canvas);
- } else {
- PaintFrameBorder(canvas);
- }
+ else
+ PaintRestoredFrameBorder(canvas);
+ PaintTitleBar(canvas);
PaintClientEdge(canvas);
-
- WindowDelegate* d = container_->window_delegate();
- if (d->ShouldShowWindowTitle()) {
- canvas->DrawStringInt(d->GetWindowTitle(), title_font_, SK_ColorWHITE,
- title_bounds_.x(), title_bounds_.y(),
- title_bounds_.width(), title_bounds_.height());
- }
}
void DefaultNonClientView::Layout() {
LayoutWindowControls();
LayoutTitleBar();
LayoutClientView();
- SchedulePaint();
}
gfx::Size DefaultNonClientView::GetPreferredSize() {
- gfx::Size prefsize = container_->client_view()->GetPreferredSize();
+ gfx::Size prefsize(container_->client_view()->GetPreferredSize());
prefsize.Enlarge(2 * kWindowHorizontalBorderSize,
- CalculateContentsTop() + kWindowVerticalBorderSize);
+ NonClientTopBorderHeight() + kWindowVerticalBorderSize);
return prefsize;
}
@@ -538,36 +511,25 @@ void DefaultNonClientView::ViewHierarchyChanged(bool is_add,
// DefaultNonClientView, BaseButton::ButtonListener implementation:
void DefaultNonClientView::ButtonPressed(BaseButton* sender) {
- if (sender == close_button_) {
+ if (sender == close_button_)
container_->ExecuteSystemMenuCommand(SC_CLOSE);
- } else if (sender == minimize_button_) {
+ else if (sender == minimize_button_)
container_->ExecuteSystemMenuCommand(SC_MINIMIZE);
- } else if (sender == maximize_button_) {
+ else if (sender == maximize_button_)
container_->ExecuteSystemMenuCommand(SC_MAXIMIZE);
- } else if (sender == restore_button_) {
+ else if (sender == restore_button_)
container_->ExecuteSystemMenuCommand(SC_RESTORE);
- }
}
///////////////////////////////////////////////////////////////////////////////
// DefaultNonClientView, private:
-void DefaultNonClientView::SetWindowIcon(SkBitmap window_icon) {
- // TODO(beng): (Cleanup) remove this persistent cache of the icon when Button
- // takes a SkBitmap rather than SkBitmap*.
- window_icon_ = window_icon;
- system_menu_button_->SetImage(Button::BS_NORMAL, &window_icon);
-}
-
-int DefaultNonClientView::CalculateContentsTop() const {
- if (container_->window_delegate()->ShouldShowWindowTitle())
- return kTitleTopOffset + title_font_.height() + kTitleBottomSpacing;
- return kNoTitleTopSpacing;
+int DefaultNonClientView::NonClientTopBorderHeight() const {
+ return kTitleTopOffset + title_font_.height() + kTitleBottomSpacing;
}
-void DefaultNonClientView::PaintFrameBorder(ChromeCanvas* canvas) {
- SkBitmap* top_left_corner =
- resources()->GetPartBitmap(FRAME_TOP_LEFT_CORNER);
+void DefaultNonClientView::PaintRestoredFrameBorder(ChromeCanvas* canvas) {
+ SkBitmap* top_left_corner = resources()->GetPartBitmap(FRAME_TOP_LEFT_CORNER);
SkBitmap* top_right_corner =
resources()->GetPartBitmap(FRAME_TOP_RIGHT_CORNER);
SkBitmap* top_edge = resources()->GetPartBitmap(FRAME_TOP_EDGE);
@@ -587,10 +549,9 @@ void DefaultNonClientView::PaintFrameBorder(ChromeCanvas* canvas) {
width() - top_right_corner->width(), 0);
// Right.
- int top_stack_height = top_right_corner->height();
canvas->TileImageInt(*right_edge, width() - right_edge->width(),
- top_stack_height, right_edge->width(),
- height() - top_stack_height -
+ top_right_corner->height(), right_edge->width(),
+ height() - top_right_corner->height() -
bottom_right_corner->height());
// Bottom.
@@ -606,23 +567,28 @@ void DefaultNonClientView::PaintFrameBorder(ChromeCanvas* canvas) {
height() - bottom_left_corner->height());
// Left.
- top_stack_height = top_left_corner->height();
- canvas->TileImageInt(*left_edge, 0, top_stack_height, left_edge->width(),
- height() - top_stack_height -
- bottom_left_corner->height());
+ canvas->TileImageInt(*left_edge, 0, top_left_corner->height(),
+ left_edge->width(),
+ height() - top_left_corner->height() - bottom_left_corner->height());
}
void DefaultNonClientView::PaintMaximizedFrameBorder(
ChromeCanvas* canvas) {
SkBitmap* top_edge = resources()->GetPartBitmap(FRAME_TOP_EDGE);
- SkBitmap* bottom_edge =
- resources()->GetPartBitmap(FRAME_BOTTOM_EDGE);
canvas->TileImageInt(*top_edge, 0, 0, width(), top_edge->height());
- canvas->TileImageInt(*bottom_edge, 0, height() - bottom_edge->height(),
- width(), bottom_edge->height());
+}
+
+void DefaultNonClientView::PaintTitleBar(ChromeCanvas* canvas) {
+ WindowDelegate* d = container_->window_delegate();
+ canvas->DrawStringInt(d->GetWindowTitle(), title_font_, SK_ColorWHITE,
+ MirroredLeftPointForRect(title_bounds_), title_bounds_.y(),
+ title_bounds_.width(), title_bounds_.height());
}
void DefaultNonClientView::PaintClientEdge(ChromeCanvas* canvas) {
+ gfx::Rect client_area_bounds = container_->client_view()->bounds();
+ int client_area_top = client_area_bounds.y();
+
SkBitmap* top_left = resources()->GetPartBitmap(FRAME_CLIENT_EDGE_TOP_LEFT);
SkBitmap* top = resources()->GetPartBitmap(FRAME_CLIENT_EDGE_TOP);
SkBitmap* top_right = resources()->GetPartBitmap(FRAME_CLIENT_EDGE_TOP_RIGHT);
@@ -634,19 +600,23 @@ void DefaultNonClientView::PaintClientEdge(ChromeCanvas* canvas) {
resources()->GetPartBitmap(FRAME_CLIENT_EDGE_BOTTOM_LEFT);
SkBitmap* left = resources()->GetPartBitmap(FRAME_CLIENT_EDGE_LEFT);
- gfx::Rect client_area_bounds = container_->client_view()->bounds();
-
+ // Top.
+ // This next calculation is necessary because the top center bitmap is shorter
+ // than the top left and right bitmaps. We need their top edges to line up,
+ // and we need the left and right edges to start below the corners' bottoms.
+ int top_edge_y = client_area_top - top->height();
+ client_area_top = top_edge_y + top_left->height();
canvas->DrawBitmapInt(*top_left, client_area_bounds.x() - top_left->width(),
- client_area_bounds.y() - top->height());
- canvas->TileImageInt(*top, client_area_bounds.x(),
- client_area_bounds.y() - top->height(),
+ top_edge_y);
+ canvas->TileImageInt(*top, client_area_bounds.x(), top_edge_y,
client_area_bounds.width(), top->height());
- canvas->DrawBitmapInt(*top_right, client_area_bounds.right(),
- client_area_bounds.y() - top->height());
- canvas->TileImageInt(*right, client_area_bounds.right(),
- client_area_bounds.y() - top->height() +
- top_right->height(),
+ canvas->DrawBitmapInt(*top_right, client_area_bounds.right(), top_edge_y);
+
+ // Right.
+ canvas->TileImageInt(*right, client_area_bounds.right(), client_area_top,
right->width(), client_area_bounds.height());
+
+ // Bottom.
canvas->DrawBitmapInt(*bottom_right, client_area_bounds.right(),
client_area_bounds.bottom());
canvas->TileImageInt(*bottom, client_area_bounds.x(),
@@ -655,49 +625,47 @@ void DefaultNonClientView::PaintClientEdge(ChromeCanvas* canvas) {
canvas->DrawBitmapInt(*bottom_left,
client_area_bounds.x() - bottom_left->width(),
client_area_bounds.bottom());
+
+ // Left.
canvas->TileImageInt(*left, client_area_bounds.x() - left->width(),
- client_area_bounds.y() - top->height() +
- top_left->height(),
- left->width(), client_area_bounds.height());
+ client_area_top, left->width(), client_area_bounds.height());
}
void DefaultNonClientView::LayoutWindowControls() {
- // TODO(pkasting): This function is almost identical to
- // OpaqueNonClientView::LayoutWindowControls(), they should be combined.
- int top_offset, top_extra_height, right_offset, right_extra_width;
- Button* invisible_button, * visible_button;
- if (container_->IsMaximized()) {
- top_offset = 0;
- top_extra_height = kWindowControlsTopZoomedOffset;
- right_offset = kWindowControlsRightZoomedOffset;
- right_extra_width = right_offset;
- invisible_button = maximize_button_;
- visible_button = restore_button_;
- } else {
- top_offset = kWindowControlsTopOffset;
- top_extra_height = 0;
- right_offset = kWindowControlsRightOffset;
- right_extra_width = 0;
- invisible_button = restore_button_;
- visible_button = maximize_button_;
- }
-
close_button_->SetImageAlignment(Button::ALIGN_LEFT, Button::ALIGN_BOTTOM);
+ // 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;
+ // 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_spacing = is_maximized ?
+ kWindowControlsRightZoomedOffset : kWindowControlsRightOffset;
gfx::Size close_button_size = close_button_->GetPreferredSize();
- close_button_->SetBounds(width() - right_offset - close_button_size.width(),
- top_offset,
+ close_button_->SetBounds(width() - close_button_size.width() - right_spacing,
+ caption_y,
close_button_size.width() + right_extra_width,
close_button_size.height() + top_extra_height);
+ // When the window is restored, we show a maximized button; otherwise, we show
+ // a restore button.
+ bool is_restored = !is_maximized && !container_->IsMinimized();
+ views::Button* invisible_button = is_restored ?
+ restore_button_ : maximize_button_;
invisible_button->SetVisible(false);
+ views::Button* visible_button = is_restored ?
+ maximize_button_ : restore_button_;
FramePartBitmap normal_part, hot_part, pushed_part;
if (should_show_minmax_buttons_) {
visible_button->SetVisible(true);
visible_button->SetImageAlignment(Button::ALIGN_LEFT, Button::ALIGN_BOTTOM);
gfx::Size visible_button_size = visible_button->GetPreferredSize();
visible_button->SetBounds(close_button_->x() - visible_button_size.width(),
- top_offset, visible_button_size.width(),
+ caption_y, visible_button_size.width(),
visible_button_size.height() + top_extra_height);
minimize_button_->SetVisible(true);
@@ -705,7 +673,7 @@ void DefaultNonClientView::LayoutWindowControls() {
Button::ALIGN_BOTTOM);
gfx::Size minimize_button_size = minimize_button_->GetPreferredSize();
minimize_button_->SetBounds(
- visible_button->x() - minimize_button_size.width(), top_offset,
+ visible_button->x() - minimize_button_size.width(), caption_y,
minimize_button_size.width(),
minimize_button_size.height() + top_extra_height);
@@ -747,44 +715,29 @@ void DefaultNonClientView::LayoutTitleBar() {
kWindowIconTopOffset, 0, 0);
}
- // Size the title, if visible.
- if (d->ShouldShowWindowTitle()) {
- 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());
-
- // We draw the custom frame window's title directly rather than using a
- // views::Label child view. Therefore, we have to mirror the title
- // position manually if the View's UI layout is right-to-left. Child Views
- // are automatically mirrored, which means that the parent view doesn't
- // need to manually modify their position depending on the View's UI
- // layout.
- //
- // Mirroring the title's position manually is certainly far from being
- // elegant, but we have no choice (other than changing the
- // DefaultNonClientView subclass to use a ChromeView::Label as a child View
- // instead of drawing the title's text directly on the canvas).
- title_bounds_.set_x(MirroredLeftPointForRect(title_bounds_));
-
- // 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());
- }
+ // 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());
}
}
void DefaultNonClientView::LayoutClientView() {
- gfx::Rect client_bounds = CalculateClientAreaBounds(width(), height());
- container_->client_view()->SetBounds(client_bounds);
+ container_->client_view()->SetBounds(CalculateClientAreaBounds(width(),
+ height()));
}
// static