Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(573)

Side by Side Diff: ash/launcher/overflow_bubble.cc

Issue 10659003: ash: Add launcher overflow bubble. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: rebase + fix clang Created 8 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « ash/launcher/overflow_bubble.h ('k') | ash/wm/shelf_layout_manager.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright (c) 2012 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 "ash/launcher/overflow_bubble.h"
6
7 #include <algorithm>
8
9 #include "ash/launcher/launcher_types.h"
10 #include "ash/launcher/launcher_view.h"
11 #include "ui/gfx/screen.h"
12 #include "ui/views/bubble/bubble_delegate.h"
13 #include "ui/views/bubble/bubble_frame_view.h"
14
15 namespace ash {
16 namespace internal {
17
18 namespace {
19
20 // This should be the same color as the darkest launcher bar.
21 const SkColor kLauncherColor = SkColorSetARGB(0x80, 0, 0, 0);
22
23 // Max bubble size to screen size ratio.
24 const float kMaxBubbleSizeToScreenRatio = 0.5f;
25
26 // Inner padding in pixels for launcher view inside bubble.
27 const int kPadding = 2;
28
29 // Padding space in pixels between LauncherView's left/top edge to its contents.
30 const int kLauncherViewLeadingInset = 8;
31
32 // Gets arrow location based on shelf alignment.
33 views::BubbleBorder::ArrowLocation GetBubbleArrowLocation(
34 ShelfAlignment shelf_alignment) {
35 switch (shelf_alignment) {
36 case ash::SHELF_ALIGNMENT_BOTTOM:
37 return views::BubbleBorder::BOTTOM_LEFT;
38 case ash::SHELF_ALIGNMENT_LEFT:
39 return views::BubbleBorder::LEFT_TOP;
40 case ash::SHELF_ALIGNMENT_RIGHT:
41 return views::BubbleBorder::RIGHT_TOP;
42 default:
43 NOTREACHED() << "Unknown shelf alignment " << shelf_alignment;
44 return views::BubbleBorder::BOTTOM_LEFT;
45 }
46 }
47
48 ////////////////////////////////////////////////////////////////////////////////
49 // OverflowBubbleView
50 // OverflowBubbleView hosts a LauncherView to display overflown items.
51
52 class OverflowBubbleView : public views::BubbleDelegateView {
53 public:
54 OverflowBubbleView();
55 virtual ~OverflowBubbleView();
56
57 void InitOverflowBubble(LauncherDelegate* delegate,
58 LauncherModel* model,
59 views::View* anchor,
60 ShelfAlignment shelf_alignment,
61 int overflow_start_index);
62
63 private:
64 bool is_horizontal_alignment() const {
65 return shelf_alignment_ == SHELF_ALIGNMENT_BOTTOM;
66 }
67
68 const gfx::Size GetContentsSize() const {
69 return static_cast<views::View*>(launcher_view_)->GetPreferredSize();
70 }
71
72 void ScrollByXOffset(int x_offset);
73 void ScrollByYOffset(int y_offset);
74
75 // views::View overrides:
76 virtual gfx::Size GetPreferredSize() OVERRIDE;
77 virtual void Layout() OVERRIDE;
78 virtual void ChildPreferredSizeChanged(views::View* child) OVERRIDE;
79 virtual bool OnMouseWheel(const views::MouseWheelEvent& event) OVERRIDE;
80 virtual bool OnScrollEvent(const views::ScrollEvent & event) OVERRIDE;
81
82 // views::BubbleDelegate overrides:
83 virtual gfx::Rect GetBubbleBounds() OVERRIDE;
84
85 ShelfAlignment shelf_alignment_;
86 LauncherView* launcher_view_; // Owned by views hierarchy.
87 gfx::Point scroll_offset_;
88
89 DISALLOW_COPY_AND_ASSIGN(OverflowBubbleView);
90 };
91
92 OverflowBubbleView::OverflowBubbleView()
93 : shelf_alignment_(SHELF_ALIGNMENT_BOTTOM),
94 launcher_view_(NULL) {
95 }
96
97 OverflowBubbleView::~OverflowBubbleView() {
98 }
99
100 void OverflowBubbleView::InitOverflowBubble(LauncherDelegate* delegate,
101 LauncherModel* model,
102 views::View* anchor,
103 ShelfAlignment shelf_alignment,
104 int overflow_start_index) {
105 shelf_alignment_ = shelf_alignment;
106
107 // Makes bubble view has a layer and clip its children layers.
108 SetPaintToLayer(true);
109 SetFillsBoundsOpaquely(false);
110 layer()->SetMasksToBounds(true);
111
112 launcher_view_ = new LauncherView(model, delegate, NULL);
113 launcher_view_->set_first_visible_index(overflow_start_index);
114 launcher_view_->set_leading_inset(kLauncherViewLeadingInset);
115 launcher_view_->Init();
116 launcher_view_->SetAlignment(shelf_alignment);
117 AddChildView(launcher_view_);
118
119 set_anchor_view(anchor);
120 set_arrow_location(GetBubbleArrowLocation(shelf_alignment));
121 set_background(NULL);
122 set_color(kLauncherColor);
123 set_margin(kPadding);
124 set_move_with_anchor(true);
125 views::BubbleDelegateView::CreateBubble(this);
126 }
127
128 void OverflowBubbleView::ScrollByXOffset(int x_offset) {
129 const gfx::Rect visible_bounds(GetContentsBounds());
130 const gfx::Size contents_size(GetContentsSize());
131
132 int x = std::min(contents_size.width() - visible_bounds.width(),
133 std::max(0, scroll_offset_.x() + x_offset));
134 scroll_offset_.set_x(x);
135 }
136
137 void OverflowBubbleView::ScrollByYOffset(int y_offset) {
138 const gfx::Rect visible_bounds(GetContentsBounds());
139 const gfx::Size contents_size(GetContentsSize());
140
141 int y = std::min(contents_size.height() - visible_bounds.height(),
142 std::max(0, scroll_offset_.y() + y_offset));
143 scroll_offset_.set_y(y);
144 }
145
146 gfx::Size OverflowBubbleView::GetPreferredSize() {
147 gfx::Size preferred_size = GetContentsSize();
148
149 const gfx::Rect monitor_rect = gfx::Screen::GetDisplayNearestPoint(
150 GetAnchorRect().CenterPoint()).work_area();
151 if (!monitor_rect.IsEmpty()) {
152 if (is_horizontal_alignment()) {
153 preferred_size.set_width(std::min(
154 preferred_size.width(),
155 static_cast<int>(monitor_rect.width() *
156 kMaxBubbleSizeToScreenRatio)));
157 } else {
158 preferred_size.set_height(std::min(
159 preferred_size.height(),
160 static_cast<int>(monitor_rect.height() *
161 kMaxBubbleSizeToScreenRatio)));
162 }
163 }
164
165 return preferred_size;
166 }
167
168 void OverflowBubbleView::Layout() {
169 const gfx::Point origin(-scroll_offset_.x(), -scroll_offset_.y());
170 launcher_view_->SetBoundsRect(gfx::Rect(origin, GetContentsSize()));
171 }
172
173 void OverflowBubbleView::ChildPreferredSizeChanged(views::View* child) {
174 // Ensures |launch_view_| is still visible.
175 ScrollByXOffset(0);
176 ScrollByYOffset(0);
177 Layout();
178
179 SizeToContents();
180 }
181
182 bool OverflowBubbleView::OnMouseWheel(const views::MouseWheelEvent& event) {
183 if (is_horizontal_alignment())
184 ScrollByXOffset(-event.offset());
185 else
186 ScrollByYOffset(-event.offset());
187 Layout();
188
189 return true;
190 }
191
192 bool OverflowBubbleView::OnScrollEvent(const views::ScrollEvent & event) {
193 ScrollByXOffset(-event.x_offset());
194 ScrollByYOffset(-event.y_offset());
195 Layout();
196 return true;
197 }
198
199 gfx::Rect OverflowBubbleView::GetBubbleBounds() {
200 views::BubbleBorder* border = GetBubbleFrameView()->bubble_border();
201 gfx::Insets bubble_insets;
202 border->GetInsets(&bubble_insets);
203
204 const int border_size =
205 views::BubbleBorder::is_arrow_on_horizontal(arrow_location()) ?
206 bubble_insets.left() : bubble_insets.top();
207 const int arrow_offset = border_size + kPadding + kLauncherViewLeadingInset +
208 kLauncherPreferredSize / 2;
209
210 const gfx::Size content_size = GetPreferredSize();
211 border->SetArrowOffset(arrow_offset, content_size);
212
213 const gfx::Rect anchor_rect = GetAnchorRect();
214 gfx::Rect bubble_rect = GetBubbleFrameView()->GetUpdatedWindowBounds(
215 anchor_rect,
216 content_size,
217 false);
218
219 gfx::Rect monitor_rect = gfx::Screen::GetDisplayNearestPoint(
220 anchor_rect.CenterPoint()).work_area();
221
222 int offset = 0;
223 if (views::BubbleBorder::is_arrow_on_horizontal(arrow_location())) {
224 if (bubble_rect.x() < monitor_rect.x())
225 offset = monitor_rect.x() - bubble_rect.x();
226 else if (bubble_rect.right() > monitor_rect.right())
227 offset = monitor_rect.right() - bubble_rect.right();
228
229 bubble_rect.Offset(offset, 0);
230 border->SetArrowOffset(anchor_rect.CenterPoint().x() - bubble_rect.x(),
231 content_size);
232 } else {
233 if (bubble_rect.y() < monitor_rect.y())
234 offset = monitor_rect.y() - bubble_rect.y();
235 else if (bubble_rect.bottom() > monitor_rect.bottom())
236 offset = monitor_rect.bottom() - bubble_rect.bottom();
237
238 bubble_rect.Offset(0, offset);
239 border->SetArrowOffset(anchor_rect.CenterPoint().y() - bubble_rect.y(),
240 content_size);
241 }
242
243 GetBubbleFrameView()->SchedulePaint();
244 return bubble_rect;
245 }
246
247 } // namespace
248
249 OverflowBubble::OverflowBubble()
250 : bubble_(NULL) {
251 }
252
253 OverflowBubble::~OverflowBubble() {
254 Hide();
255 }
256
257 void OverflowBubble::Show(LauncherDelegate* delegate,
258 LauncherModel* model,
259 views::View* anchor,
260 ShelfAlignment shelf_alignment,
261 int overflow_start_index) {
262 Hide();
263
264 OverflowBubbleView* bubble_view = new OverflowBubbleView();
265 bubble_view->InitOverflowBubble(delegate,
266 model,
267 anchor,
268 shelf_alignment,
269 overflow_start_index);
270
271 bubble_ = bubble_view;
272 bubble_->GetWidget()->AddObserver(this);
273 bubble_->GetWidget()->Show();
274 }
275
276 void OverflowBubble::Hide() {
277 if (!IsShowing())
278 return;
279
280 bubble_->GetWidget()->RemoveObserver(this);
281 bubble_->GetWidget()->Close();
282 bubble_ = NULL;
283 }
284
285 void OverflowBubble::OnWidgetClosing(views::Widget* widget) {
286 DCHECK(widget == bubble_->GetWidget());
287 bubble_ = NULL;
288 }
289
290 } // namespace internal
291 } // namespace ash
OLDNEW
« no previous file with comments | « ash/launcher/overflow_bubble.h ('k') | ash/wm/shelf_layout_manager.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698