Home | History | Annotate | Download | only in app_list
      1 // Copyright 2013 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "chrome/browser/ui/app_list/app_list_positioner.h"
      6 
      7 #include <algorithm>
      8 
      9 #include "base/logging.h"
     10 #include "ui/gfx/point.h"
     11 #include "ui/gfx/rect.h"
     12 
     13 AppListPositioner::AppListPositioner(const gfx::Display& display,
     14                                      const gfx::Size& window_size,
     15                                      int min_distance_from_edge)
     16     : display_(display),
     17       window_size_(window_size),
     18       min_distance_from_edge_(min_distance_from_edge) {}
     19 
     20 void AppListPositioner::WorkAreaSubtract(const gfx::Rect& rect) {
     21   gfx::Rect work_area = display_.work_area();
     22   work_area.Subtract(rect);
     23   display_.set_work_area(work_area);
     24 }
     25 
     26 void AppListPositioner::WorkAreaInset(int left,
     27                                       int top,
     28                                       int right,
     29                                       int bottom) {
     30   gfx::Rect work_area = display_.work_area();
     31   work_area.Inset(left, top, right, bottom);
     32   display_.set_work_area(work_area);
     33 }
     34 
     35 gfx::Point AppListPositioner::GetAnchorPointForScreenCenter() const {
     36   return display_.bounds().CenterPoint();
     37 }
     38 
     39 gfx::Point AppListPositioner::GetAnchorPointForScreenCorner(
     40     ScreenCorner corner) const {
     41   const gfx::Rect& screen_rect = display_.bounds();
     42   gfx::Point anchor;
     43   switch (corner) {
     44     case SCREEN_CORNER_TOP_LEFT:
     45       anchor = screen_rect.origin();
     46       break;
     47     case SCREEN_CORNER_TOP_RIGHT:
     48       anchor = screen_rect.top_right();
     49       break;
     50     case SCREEN_CORNER_BOTTOM_LEFT:
     51       anchor = screen_rect.bottom_left();
     52       break;
     53     case SCREEN_CORNER_BOTTOM_RIGHT:
     54       anchor = screen_rect.bottom_right();
     55       break;
     56     default:
     57       NOTREACHED();
     58       anchor = gfx::Point();
     59   }
     60   return ClampAnchorPoint(anchor);
     61 }
     62 
     63 gfx::Point AppListPositioner::GetAnchorPointForShelfCorner(
     64     ScreenEdge shelf_edge) const {
     65   const gfx::Rect& screen_rect = display_.bounds();
     66   const gfx::Rect& work_area = display_.work_area();
     67   gfx::Point anchor;
     68   switch (shelf_edge) {
     69     case SCREEN_EDGE_LEFT:
     70       anchor = gfx::Point(work_area.x(), screen_rect.y());
     71       break;
     72     case SCREEN_EDGE_RIGHT:
     73       anchor = gfx::Point(work_area.right(), screen_rect.y());
     74       break;
     75     case SCREEN_EDGE_TOP:
     76       anchor = gfx::Point(screen_rect.x(), work_area.y());
     77       break;
     78     case SCREEN_EDGE_BOTTOM:
     79       anchor = gfx::Point(screen_rect.x(), work_area.bottom());
     80       break;
     81     default:
     82       NOTREACHED();
     83       anchor = gfx::Point();
     84   }
     85   return ClampAnchorPoint(anchor);
     86 }
     87 
     88 gfx::Point AppListPositioner::GetAnchorPointForShelfCenter(
     89     ScreenEdge shelf_edge) const {
     90   const gfx::Rect& work_area = display_.work_area();
     91   gfx::Point anchor;
     92   switch (shelf_edge) {
     93     case SCREEN_EDGE_LEFT:
     94       anchor =
     95           gfx::Point(work_area.x(), work_area.y() + work_area.height() / 2);
     96       break;
     97     case SCREEN_EDGE_RIGHT:
     98       anchor =
     99           gfx::Point(work_area.right(), work_area.y() + work_area.height() / 2);
    100       break;
    101     case SCREEN_EDGE_TOP:
    102       anchor = gfx::Point(work_area.x() + work_area.width() / 2, work_area.y());
    103       break;
    104     case SCREEN_EDGE_BOTTOM:
    105       anchor =
    106           gfx::Point(work_area.x() + work_area.width() / 2, work_area.bottom());
    107       break;
    108     default:
    109       NOTREACHED();
    110       anchor = gfx::Point();
    111   }
    112   return ClampAnchorPoint(anchor);
    113 }
    114 
    115 gfx::Point AppListPositioner::GetAnchorPointForShelfCursor(
    116     ScreenEdge shelf_edge,
    117     const gfx::Point& cursor) const {
    118   const gfx::Rect& work_area = display_.work_area();
    119   gfx::Point anchor;
    120   switch (shelf_edge) {
    121     case SCREEN_EDGE_LEFT:
    122       anchor = gfx::Point(work_area.x(), cursor.y());
    123       break;
    124     case SCREEN_EDGE_RIGHT:
    125       anchor = gfx::Point(work_area.right(), cursor.y());
    126       break;
    127     case SCREEN_EDGE_TOP:
    128       anchor = gfx::Point(cursor.x(), work_area.y());
    129       break;
    130     case SCREEN_EDGE_BOTTOM:
    131       anchor = gfx::Point(cursor.x(), work_area.bottom());
    132       break;
    133     default:
    134       NOTREACHED();
    135       anchor = gfx::Point();
    136   }
    137   return ClampAnchorPoint(anchor);
    138 }
    139 
    140 AppListPositioner::ScreenEdge AppListPositioner::GetShelfEdge(
    141     const gfx::Rect& shelf_rect) const {
    142   const gfx::Rect& screen_rect = display_.bounds();
    143   const gfx::Rect& work_area = display_.work_area();
    144 
    145   // If we can't find the shelf, return SCREEN_EDGE_UNKNOWN. If the display
    146   // size is the same as the work area, and does not contain the shelf, either
    147   // the shelf is hidden or on another monitor.
    148   if (work_area == screen_rect && !work_area.Contains(shelf_rect))
    149     return SCREEN_EDGE_UNKNOWN;
    150 
    151   // Note: On Windows 8 the work area won't include split windows on the left or
    152   // right, and neither will |shelf_rect|.
    153   if (shelf_rect.x() == work_area.x() &&
    154       shelf_rect.width() == work_area.width()) {
    155     // Shelf is horizontal.
    156     if (shelf_rect.bottom() == screen_rect.bottom())
    157       return SCREEN_EDGE_BOTTOM;
    158     else if (shelf_rect.y() == screen_rect.y())
    159       return SCREEN_EDGE_TOP;
    160   } else if (shelf_rect.y() == work_area.y() &&
    161              shelf_rect.height() == work_area.height()) {
    162     // Shelf is vertical.
    163     if (shelf_rect.x() == screen_rect.x())
    164       return SCREEN_EDGE_LEFT;
    165     else if (shelf_rect.right() == screen_rect.right())
    166       return SCREEN_EDGE_RIGHT;
    167   }
    168 
    169   return SCREEN_EDGE_UNKNOWN;
    170 }
    171 
    172 int AppListPositioner::GetCursorDistanceFromShelf(
    173     ScreenEdge shelf_edge,
    174     const gfx::Point& cursor) const {
    175   const gfx::Rect& work_area = display_.work_area();
    176   switch (shelf_edge) {
    177     case SCREEN_EDGE_UNKNOWN:
    178       return 0;
    179     case SCREEN_EDGE_LEFT:
    180       return std::max(0, cursor.x() - work_area.x());
    181     case SCREEN_EDGE_RIGHT:
    182       return std::max(0, work_area.right() - cursor.x());
    183     case SCREEN_EDGE_TOP:
    184       return std::max(0, cursor.y() - work_area.y());
    185     case SCREEN_EDGE_BOTTOM:
    186       return std::max(0, work_area.bottom() - cursor.y());
    187     default:
    188       NOTREACHED();
    189       return 0;
    190   }
    191 }
    192 
    193 gfx::Point AppListPositioner::ClampAnchorPoint(gfx::Point anchor) const {
    194   gfx::Rect bounds_rect(display_.work_area());
    195 
    196   // Anchor the center of the window in a region that prevents the window
    197   // showing outside of the work area.
    198   bounds_rect.Inset(window_size_.width() / 2 + min_distance_from_edge_,
    199                     window_size_.height() / 2 + min_distance_from_edge_);
    200 
    201   anchor.SetToMax(bounds_rect.origin());
    202   anchor.SetToMin(bounds_rect.bottom_right());
    203   return anchor;
    204 }
    205