blob: 6593977d0bb81719952d919abdbb89c919711a0e [file] [log] [blame]
// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/ui/app_list/app_list_positioner.h"
#include <algorithm>
#include "base/logging.h"
#include "ui/gfx/point.h"
#include "ui/gfx/rect.h"
AppListPositioner::AppListPositioner(const gfx::Display& display,
const gfx::Size& window_size,
int min_distance_from_edge)
: display_(display),
window_size_(window_size),
min_distance_from_edge_(min_distance_from_edge) {}
void AppListPositioner::WorkAreaSubtract(const gfx::Rect& rect) {
gfx::Rect work_area = display_.work_area();
work_area.Subtract(rect);
display_.set_work_area(work_area);
}
void AppListPositioner::WorkAreaInset(int left,
int top,
int right,
int bottom) {
gfx::Rect work_area = display_.work_area();
work_area.Inset(left, top, right, bottom);
display_.set_work_area(work_area);
}
gfx::Point AppListPositioner::GetAnchorPointForScreenCenter() const {
return display_.bounds().CenterPoint();
}
gfx::Point AppListPositioner::GetAnchorPointForScreenCorner(
ScreenCorner corner) const {
const gfx::Rect& screen_rect = display_.bounds();
gfx::Point anchor;
switch (corner) {
case SCREEN_CORNER_TOP_LEFT:
anchor = screen_rect.origin();
break;
case SCREEN_CORNER_TOP_RIGHT:
anchor = screen_rect.top_right();
break;
case SCREEN_CORNER_BOTTOM_LEFT:
anchor = screen_rect.bottom_left();
break;
case SCREEN_CORNER_BOTTOM_RIGHT:
anchor = screen_rect.bottom_right();
break;
default:
NOTREACHED();
anchor = gfx::Point();
}
return ClampAnchorPoint(anchor);
}
gfx::Point AppListPositioner::GetAnchorPointForShelfCorner(
ScreenEdge shelf_edge) const {
const gfx::Rect& screen_rect = display_.bounds();
const gfx::Rect& work_area = display_.work_area();
gfx::Point anchor;
switch (shelf_edge) {
case SCREEN_EDGE_LEFT:
anchor = gfx::Point(work_area.x(), screen_rect.y());
break;
case SCREEN_EDGE_RIGHT:
anchor = gfx::Point(work_area.right(), screen_rect.y());
break;
case SCREEN_EDGE_TOP:
anchor = gfx::Point(screen_rect.x(), work_area.y());
break;
case SCREEN_EDGE_BOTTOM:
anchor = gfx::Point(screen_rect.x(), work_area.bottom());
break;
default:
NOTREACHED();
anchor = gfx::Point();
}
return ClampAnchorPoint(anchor);
}
gfx::Point AppListPositioner::GetAnchorPointForShelfCenter(
ScreenEdge shelf_edge) const {
const gfx::Rect& work_area = display_.work_area();
gfx::Point anchor;
switch (shelf_edge) {
case SCREEN_EDGE_LEFT:
anchor =
gfx::Point(work_area.x(), work_area.y() + work_area.height() / 2);
break;
case SCREEN_EDGE_RIGHT:
anchor =
gfx::Point(work_area.right(), work_area.y() + work_area.height() / 2);
break;
case SCREEN_EDGE_TOP:
anchor = gfx::Point(work_area.x() + work_area.width() / 2, work_area.y());
break;
case SCREEN_EDGE_BOTTOM:
anchor =
gfx::Point(work_area.x() + work_area.width() / 2, work_area.bottom());
break;
default:
NOTREACHED();
anchor = gfx::Point();
}
return ClampAnchorPoint(anchor);
}
gfx::Point AppListPositioner::GetAnchorPointForShelfCursor(
ScreenEdge shelf_edge,
const gfx::Point& cursor) const {
const gfx::Rect& work_area = display_.work_area();
gfx::Point anchor;
switch (shelf_edge) {
case SCREEN_EDGE_LEFT:
anchor = gfx::Point(work_area.x(), cursor.y());
break;
case SCREEN_EDGE_RIGHT:
anchor = gfx::Point(work_area.right(), cursor.y());
break;
case SCREEN_EDGE_TOP:
anchor = gfx::Point(cursor.x(), work_area.y());
break;
case SCREEN_EDGE_BOTTOM:
anchor = gfx::Point(cursor.x(), work_area.bottom());
break;
default:
NOTREACHED();
anchor = gfx::Point();
}
return ClampAnchorPoint(anchor);
}
AppListPositioner::ScreenEdge AppListPositioner::GetShelfEdge(
const gfx::Rect& shelf_rect) const {
const gfx::Rect& screen_rect = display_.bounds();
const gfx::Rect& work_area = display_.work_area();
// If we can't find the shelf, return SCREEN_EDGE_UNKNOWN. If the display
// size is the same as the work area, and does not contain the shelf, either
// the shelf is hidden or on another monitor.
if (work_area == screen_rect && !work_area.Contains(shelf_rect))
return SCREEN_EDGE_UNKNOWN;
// Note: On Windows 8 the work area won't include split windows on the left or
// right, and neither will |shelf_rect|.
if (shelf_rect.x() == work_area.x() &&
shelf_rect.width() == work_area.width()) {
// Shelf is horizontal.
if (shelf_rect.bottom() == screen_rect.bottom())
return SCREEN_EDGE_BOTTOM;
else if (shelf_rect.y() == screen_rect.y())
return SCREEN_EDGE_TOP;
} else if (shelf_rect.y() == work_area.y() &&
shelf_rect.height() == work_area.height()) {
// Shelf is vertical.
if (shelf_rect.x() == screen_rect.x())
return SCREEN_EDGE_LEFT;
else if (shelf_rect.right() == screen_rect.right())
return SCREEN_EDGE_RIGHT;
}
return SCREEN_EDGE_UNKNOWN;
}
int AppListPositioner::GetCursorDistanceFromShelf(
ScreenEdge shelf_edge,
const gfx::Point& cursor) const {
const gfx::Rect& work_area = display_.work_area();
switch (shelf_edge) {
case SCREEN_EDGE_UNKNOWN:
return 0;
case SCREEN_EDGE_LEFT:
return std::max(0, cursor.x() - work_area.x());
case SCREEN_EDGE_RIGHT:
return std::max(0, work_area.right() - cursor.x());
case SCREEN_EDGE_TOP:
return std::max(0, cursor.y() - work_area.y());
case SCREEN_EDGE_BOTTOM:
return std::max(0, work_area.bottom() - cursor.y());
default:
NOTREACHED();
return 0;
}
}
gfx::Point AppListPositioner::ClampAnchorPoint(gfx::Point anchor) const {
gfx::Rect bounds_rect(display_.work_area());
// Anchor the center of the window in a region that prevents the window
// showing outside of the work area.
bounds_rect.Inset(window_size_.width() / 2 + min_distance_from_edge_,
window_size_.height() / 2 + min_distance_from_edge_);
anchor.SetToMax(bounds_rect.origin());
anchor.SetToMin(bounds_rect.bottom_right());
return anchor;
}