1// Copyright (c) 2011 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/tabs/dock_info.h"
6
7#include "base/logging.h"
8#if defined(TOOLKIT_VIEWS)
9#include "chrome/browser/ui/views/tabs/tab.h"
10#else
11#include "chrome/browser/ui/gtk/tabs/tab_gtk.h"
12#endif
13
14namespace {
15
16// Distance in pixels between the hotspot and when the hint should be shown.
17const int kHotSpotDeltaX = 120;
18const int kHotSpotDeltaY = 120;
19
20// Size of the popup window.
21const int kPopupWidth = 70;
22const int kPopupHeight = 70;
23
24}  // namespace
25
26// static
27DockInfo::Factory* DockInfo::factory_ = NULL;
28
29// static
30bool DockInfo::IsCloseToPoint(const gfx::Point& screen_loc,
31                              int x,
32                              int y,
33                              bool* in_enable_area) {
34  int delta_x = abs(x - screen_loc.x());
35  int delta_y = abs(y - screen_loc.y());
36  *in_enable_area = (delta_x < kPopupWidth / 2 && delta_y < kPopupHeight / 2);
37  return *in_enable_area || (delta_x < kHotSpotDeltaX &&
38                             delta_y < kHotSpotDeltaY);
39}
40
41// static
42bool DockInfo::IsCloseToMonitorPoint(const gfx::Point& screen_loc,
43                                     int x,
44                                     int y,
45                                     DockInfo::Type type,
46                                     bool* in_enable_area) {
47  // Because the monitor relative positions are aligned with the edge of the
48  // monitor these need to be handled differently.
49  int delta_x = abs(x - screen_loc.x());
50  int delta_y = abs(y - screen_loc.y());
51
52  int enable_delta_x = kPopupWidth / 2;
53  int enable_delta_y = kPopupHeight / 2;
54  int hot_spot_delta_x = kHotSpotDeltaX;
55  int hot_spot_delta_y = kHotSpotDeltaY;
56
57  switch (type) {
58    case DockInfo::LEFT_HALF:
59    case DockInfo::RIGHT_HALF:
60      enable_delta_x += enable_delta_x;
61      hot_spot_delta_x += hot_spot_delta_x;
62      break;
63
64
65    case DockInfo::MAXIMIZE: {
66      // Make the maximize height smaller than the tab height to avoid showing
67      // the dock indicator when close to maximized browser.
68#if defined(TOOLKIT_VIEWS)
69      hot_spot_delta_y = Tab::GetMinimumUnselectedSize().height() - 1;
70#else
71      hot_spot_delta_y = TabGtk::GetMinimumUnselectedSize().height() - 1;
72#endif
73      enable_delta_y = hot_spot_delta_y / 2;
74      break;
75    }
76    case DockInfo::BOTTOM_HALF:
77      enable_delta_y += enable_delta_y;
78      hot_spot_delta_y += hot_spot_delta_y;
79      break;
80
81    default:
82      NOTREACHED();
83      return false;
84  }
85  *in_enable_area = (delta_x < enable_delta_x && delta_y < enable_delta_y);
86  bool result = (*in_enable_area || (delta_x < hot_spot_delta_x &&
87                                     delta_y < hot_spot_delta_y));
88  if (type != DockInfo::MAXIMIZE)
89    return result;
90
91  // Make the hot spot/enable spot for maximized windows the whole top of the
92  // monitor.
93  int max_delta_y = abs(screen_loc.y() - y);
94  *in_enable_area = (*in_enable_area || (max_delta_y < enable_delta_y));
95  return *in_enable_area || (max_delta_y < hot_spot_delta_y);
96}
97
98// static
99int DockInfo::popup_width() {
100  return kPopupWidth;
101}
102
103// static
104int DockInfo::popup_height() {
105  return kPopupHeight;
106}
107
108bool DockInfo::IsValidForPoint(const gfx::Point& screen_point) {
109  if (type_ == NONE)
110    return false;
111
112  if (window_) {
113    return IsCloseToPoint(screen_point, hot_spot_.x(), hot_spot_.y(),
114                          &in_enable_area_);
115  }
116
117  return monitor_bounds_.Contains(screen_point) &&
118          IsCloseToMonitorPoint(screen_point, hot_spot_.x(),
119                                hot_spot_.y(), type_, &in_enable_area_);
120}
121
122bool DockInfo::GetNewWindowBounds(gfx::Rect* new_window_bounds,
123                                  bool* maximize_new_window) const {
124  if (type_ == NONE || !in_enable_area_)
125    return false;
126
127  gfx::Rect window_bounds;
128  if (window_ && !GetWindowBounds(&window_bounds))
129    return false;
130
131  int half_m_width = (monitor_bounds_.right() - monitor_bounds_.x()) / 2;
132  int half_m_height = (monitor_bounds_.bottom() - monitor_bounds_.y()) / 2;
133
134  *maximize_new_window = false;
135
136  switch (type_) {
137    case LEFT_OF_WINDOW:
138      new_window_bounds->SetRect(monitor_bounds_.x(), window_bounds.y(),
139                                 half_m_width, window_bounds.height());
140      break;
141
142    case RIGHT_OF_WINDOW:
143      new_window_bounds->SetRect(monitor_bounds_.x() + half_m_width,
144                                 window_bounds.y(), half_m_width,
145                                 window_bounds.height());
146      break;
147
148    case TOP_OF_WINDOW:
149      new_window_bounds->SetRect(window_bounds.x(), monitor_bounds_.y(),
150                                 window_bounds.width(), half_m_height);
151      break;
152
153    case BOTTOM_OF_WINDOW:
154      new_window_bounds->SetRect(window_bounds.x(),
155                                 monitor_bounds_.y() + half_m_height,
156                                 window_bounds.width(), half_m_height);
157      break;
158
159    case LEFT_HALF:
160      new_window_bounds->SetRect(monitor_bounds_.x(), monitor_bounds_.y(),
161                                 half_m_width, monitor_bounds_.height());
162      break;
163
164    case RIGHT_HALF:
165      new_window_bounds->SetRect(monitor_bounds_.right() - half_m_width,
166          monitor_bounds_.y(), half_m_width, monitor_bounds_.height());
167      break;
168
169    case BOTTOM_HALF:
170      new_window_bounds->SetRect(monitor_bounds_.x(),
171                                 monitor_bounds_.y() + half_m_height,
172                                 monitor_bounds_.width(), half_m_height);
173      break;
174
175    case MAXIMIZE:
176      *maximize_new_window = true;
177      break;
178
179    default:
180      NOTREACHED();
181  }
182  return true;
183}
184
185void DockInfo::AdjustOtherWindowBounds() const {
186  if (!in_enable_area_)
187    return;
188
189  gfx::Rect window_bounds;
190  if (!window_ || !GetWindowBounds(&window_bounds))
191    return;
192
193  gfx::Rect other_window_bounds;
194  int half_m_width = (monitor_bounds_.right() - monitor_bounds_.x()) / 2;
195  int half_m_height = (monitor_bounds_.bottom() - monitor_bounds_.y()) / 2;
196
197  switch (type_) {
198    case LEFT_OF_WINDOW:
199      other_window_bounds.SetRect(monitor_bounds_.x() + half_m_width,
200                                  window_bounds.y(), half_m_width,
201                                  window_bounds.height());
202      break;
203
204    case RIGHT_OF_WINDOW:
205      other_window_bounds.SetRect(monitor_bounds_.x(), window_bounds.y(),
206                                  half_m_width, window_bounds.height());
207      break;
208
209    case TOP_OF_WINDOW:
210      other_window_bounds.SetRect(window_bounds.x(),
211                                  monitor_bounds_.y() + half_m_height,
212                                  window_bounds.width(), half_m_height);
213      break;
214
215    case BOTTOM_OF_WINDOW:
216      other_window_bounds.SetRect(window_bounds.x(), monitor_bounds_.y(),
217                                  window_bounds.width(), half_m_height);
218      break;
219
220    default:
221      return;
222  }
223
224  SizeOtherWindowTo(other_window_bounds);
225}
226
227gfx::Rect DockInfo::GetPopupRect() const {
228  int x = hot_spot_.x() - popup_width() / 2;
229  int y = hot_spot_.y() - popup_height() / 2;
230  switch (type_) {
231    case LEFT_OF_WINDOW:
232    case RIGHT_OF_WINDOW:
233    case TOP_OF_WINDOW:
234    case BOTTOM_OF_WINDOW: {
235      // Constrain the popup to the monitor's bounds.
236      gfx::Rect ideal_bounds(x, y, popup_width(), popup_height());
237      ideal_bounds = ideal_bounds.AdjustToFit(monitor_bounds_);
238      return ideal_bounds;
239    }
240    case DockInfo::MAXIMIZE:
241      y += popup_height() / 2;
242      break;
243    case DockInfo::LEFT_HALF:
244      x += popup_width() / 2;
245      break;
246    case DockInfo::RIGHT_HALF:
247      x -= popup_width() / 2;
248      break;
249    case DockInfo::BOTTOM_HALF:
250      y -= popup_height() / 2;
251      break;
252
253    default:
254      NOTREACHED();
255  }
256  return gfx::Rect(x, y, popup_width(), popup_height());
257}
258
259bool DockInfo::CheckMonitorPoint(const gfx::Point& screen_loc,
260                                 int x,
261                                 int y,
262                                 Type type) {
263  if (IsCloseToMonitorPoint(screen_loc, x, y, type, &in_enable_area_)) {
264    hot_spot_.SetPoint(x, y);
265    type_ = type;
266    return true;
267  }
268  return false;
269}
270