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