OLD | NEW |
| (Empty) |
1 // Copyright 2014 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/ime/infolist_window.h" | |
6 | |
7 #include <string> | |
8 #include <vector> | |
9 | |
10 #include "ash/ime/candidate_window_constants.h" | |
11 #include "base/logging.h" | |
12 #include "grit/ash_strings.h" | |
13 #include "ui/base/l10n/l10n_util.h" | |
14 #include "ui/gfx/color_utils.h" | |
15 #include "ui/native_theme/native_theme.h" | |
16 #include "ui/views/background.h" | |
17 #include "ui/views/border.h" | |
18 #include "ui/views/bubble/bubble_border.h" | |
19 #include "ui/views/bubble/bubble_frame_view.h" | |
20 #include "ui/views/controls/label.h" | |
21 #include "ui/views/layout/box_layout.h" | |
22 #include "ui/views/widget/widget.h" | |
23 #include "ui/wm/core/window_animations.h" | |
24 | |
25 namespace ash { | |
26 namespace ime { | |
27 | |
28 namespace { | |
29 // The width of an info-list. | |
30 const int kInfolistEntryWidth = 200; | |
31 | |
32 // The milliseconds of the delay to show the infolist window. | |
33 const int kInfolistShowDelayMilliSeconds = 500; | |
34 // The milliseconds of the delay to hide the infolist window. | |
35 const int kInfolistHideDelayMilliSeconds = 500; | |
36 | |
37 /////////////////////////////////////////////////////////////////////////////// | |
38 // InfolistBorder | |
39 // The BubbleBorder subclass to draw the border and determine its position. | |
40 class InfolistBorder : public views::BubbleBorder { | |
41 public: | |
42 InfolistBorder(); | |
43 ~InfolistBorder() override; | |
44 | |
45 // views::BubbleBorder implementation. | |
46 gfx::Rect GetBounds(const gfx::Rect& anchor_rect, | |
47 const gfx::Size& contents_size) const override; | |
48 gfx::Insets GetInsets() const override; | |
49 | |
50 private: | |
51 DISALLOW_COPY_AND_ASSIGN(InfolistBorder); | |
52 }; | |
53 | |
54 InfolistBorder::InfolistBorder() | |
55 : views::BubbleBorder(views::BubbleBorder::LEFT_CENTER, | |
56 views::BubbleBorder::NO_SHADOW, | |
57 SK_ColorTRANSPARENT) { | |
58 set_paint_arrow(views::BubbleBorder::PAINT_NONE); | |
59 } | |
60 | |
61 InfolistBorder::~InfolistBorder() {} | |
62 | |
63 gfx::Rect InfolistBorder::GetBounds(const gfx::Rect& anchor_rect, | |
64 const gfx::Size& contents_size) const { | |
65 gfx::Rect bounds(contents_size); | |
66 bounds.set_x(is_arrow_on_left(arrow()) ? | |
67 anchor_rect.right() : anchor_rect.x() - contents_size.width()); | |
68 // InfolistBorder modifies the vertical position based on the arrow offset | |
69 // although it doesn't draw the arrow. The arrow offset is the half of | |
70 // |contents_size| by default but can be modified through the off-screen logic | |
71 // in BubbleFrameView. | |
72 bounds.set_y(anchor_rect.y() + contents_size.height() / 2 - | |
73 GetArrowOffset(contents_size)); | |
74 return bounds; | |
75 } | |
76 | |
77 gfx::Insets InfolistBorder::GetInsets() const { | |
78 // This has to be specified and return empty insets to place the infolist | |
79 // window without the gap. | |
80 return gfx::Insets(); | |
81 } | |
82 | |
83 } // namespace | |
84 | |
85 // InfolistRow renderes a row of a infolist. | |
86 class InfolistEntryView : public views::View { | |
87 public: | |
88 InfolistEntryView(const ui::InfolistEntry& entry, | |
89 const gfx::FontList& title_font_list, | |
90 const gfx::FontList& description_font_list); | |
91 ~InfolistEntryView() override; | |
92 | |
93 void SetEntry(const ui::InfolistEntry& entry); | |
94 | |
95 private: | |
96 // views::View implementation. | |
97 gfx::Size GetPreferredSize() const override; | |
98 | |
99 void UpdateBackground(); | |
100 | |
101 ui::InfolistEntry entry_; | |
102 | |
103 // The title label. Owned by views hierarchy. | |
104 views::Label* title_label_; | |
105 | |
106 // The description label. Owned by views hierarchy. | |
107 views::Label* description_label_; | |
108 | |
109 DISALLOW_COPY_AND_ASSIGN(InfolistEntryView); | |
110 }; | |
111 | |
112 InfolistEntryView::InfolistEntryView(const ui::InfolistEntry& entry, | |
113 const gfx::FontList& title_font_list, | |
114 const gfx::FontList& description_font_list) | |
115 : entry_(entry) { | |
116 SetLayoutManager(new views::BoxLayout(views::BoxLayout::kVertical, 0, 0, 0)); | |
117 | |
118 title_label_ = new views::Label(entry.title, title_font_list); | |
119 title_label_->SetPosition(gfx::Point(0, 0)); | |
120 title_label_->SetHorizontalAlignment(gfx::ALIGN_LEFT); | |
121 title_label_->SetBorder(views::Border::CreateEmptyBorder(4, 7, 2, 4)); | |
122 | |
123 description_label_ = new views::Label(entry.body, description_font_list); | |
124 description_label_->SetPosition(gfx::Point(0, 0)); | |
125 description_label_->SetHorizontalAlignment(gfx::ALIGN_LEFT); | |
126 description_label_->SetMultiLine(true); | |
127 description_label_->SizeToFit(kInfolistEntryWidth); | |
128 description_label_->SetBorder(views::Border::CreateEmptyBorder(2, 17, 4, 4)); | |
129 AddChildView(title_label_); | |
130 AddChildView(description_label_); | |
131 UpdateBackground(); | |
132 } | |
133 | |
134 InfolistEntryView::~InfolistEntryView() {} | |
135 | |
136 void InfolistEntryView::SetEntry(const ui::InfolistEntry& entry) { | |
137 if (entry_ == entry) | |
138 return; | |
139 | |
140 entry_ = entry; | |
141 title_label_->SetText(entry_.title); | |
142 description_label_->SetText(entry_.body); | |
143 UpdateBackground(); | |
144 } | |
145 | |
146 gfx::Size InfolistEntryView::GetPreferredSize() const { | |
147 return gfx::Size(kInfolistEntryWidth, GetHeightForWidth(kInfolistEntryWidth)); | |
148 } | |
149 | |
150 void InfolistEntryView::UpdateBackground() { | |
151 if (entry_.highlighted) { | |
152 set_background( | |
153 views::Background::CreateSolidBackground(GetNativeTheme()->GetSystemColor( | |
154 ui::NativeTheme::kColorId_TextfieldSelectionBackgroundFocused))); | |
155 SetBorder(views::Border::CreateSolidBorder( | |
156 1, | |
157 GetNativeTheme()->GetSystemColor( | |
158 ui::NativeTheme::kColorId_FocusedBorderColor))); | |
159 } else { | |
160 set_background(NULL); | |
161 SetBorder(views::Border::CreateEmptyBorder(1, 1, 1, 1)); | |
162 } | |
163 SchedulePaint(); | |
164 } | |
165 | |
166 /////////////////////////////////////////////////////////////////////////////// | |
167 // InfolistWindow | |
168 | |
169 InfolistWindow::InfolistWindow(views::View* candidate_window, | |
170 const std::vector<ui::InfolistEntry>& entries) | |
171 : views::BubbleDelegateView(candidate_window, views::BubbleBorder::NONE), | |
172 title_font_list_(gfx::Font(kJapaneseFontName, kFontSizeDelta + 15)), | |
173 description_font_list_(gfx::Font(kJapaneseFontName, | |
174 kFontSizeDelta + 11)) { | |
175 set_can_activate(false); | |
176 set_accept_events(false); | |
177 set_margins(gfx::Insets()); | |
178 | |
179 set_background( | |
180 views::Background::CreateSolidBackground(GetNativeTheme()->GetSystemColor( | |
181 ui::NativeTheme::kColorId_WindowBackground))); | |
182 SetBorder(views::Border::CreateSolidBorder( | |
183 1, | |
184 GetNativeTheme()->GetSystemColor( | |
185 ui::NativeTheme::kColorId_MenuBorderColor))); | |
186 | |
187 SetLayoutManager(new views::BoxLayout(views::BoxLayout::kVertical, 0, 0, 0)); | |
188 | |
189 views::Label* caption_label = new views::Label( | |
190 l10n_util::GetStringUTF16(IDS_ASH_IME_INFOLIST_WINDOW_TITLE)); | |
191 caption_label->SetHorizontalAlignment(gfx::ALIGN_LEFT); | |
192 caption_label->SetEnabledColor(GetNativeTheme()->GetSystemColor( | |
193 ui::NativeTheme::kColorId_LabelEnabledColor)); | |
194 caption_label->SetBorder(views::Border::CreateEmptyBorder(2, 2, 2, 2)); | |
195 caption_label->set_background(views::Background::CreateSolidBackground( | |
196 color_utils::AlphaBlend(SK_ColorBLACK, | |
197 GetNativeTheme()->GetSystemColor( | |
198 ui::NativeTheme::kColorId_WindowBackground), | |
199 0x10))); | |
200 | |
201 AddChildView(caption_label); | |
202 | |
203 for (size_t i = 0; i < entries.size(); ++i) { | |
204 entry_views_.push_back(new InfolistEntryView( | |
205 entries[i], title_font_list_, description_font_list_)); | |
206 AddChildView(entry_views_.back()); | |
207 } | |
208 } | |
209 | |
210 InfolistWindow::~InfolistWindow() { | |
211 } | |
212 | |
213 void InfolistWindow::InitWidget() { | |
214 views::Widget* widget = views::BubbleDelegateView::CreateBubble(this); | |
215 wm::SetWindowVisibilityAnimationType( | |
216 widget->GetNativeView(), | |
217 wm::WINDOW_VISIBILITY_ANIMATION_TYPE_FADE); | |
218 | |
219 // BubbleFrameView will be initialized through CreateBubble. | |
220 GetBubbleFrameView()->SetBubbleBorder( | |
221 scoped_ptr<views::BubbleBorder>(new InfolistBorder())); | |
222 SizeToContents(); | |
223 } | |
224 | |
225 void InfolistWindow::Relayout(const std::vector<ui::InfolistEntry>& entries) { | |
226 size_t i = 0; | |
227 for (; i < entries.size(); ++i) { | |
228 if (i < entry_views_.size()) { | |
229 entry_views_[i]->SetEntry(entries[i]); | |
230 } else { | |
231 InfolistEntryView* new_entry = new InfolistEntryView( | |
232 entries[i], title_font_list_, description_font_list_); | |
233 AddChildView(new_entry); | |
234 entry_views_.push_back(new_entry); | |
235 } | |
236 } | |
237 | |
238 if (i < entry_views_.size()) { | |
239 for (; i < entry_views_.size(); ++i) | |
240 delete entry_views_[i]; | |
241 entry_views_.resize(entries.size()); | |
242 } | |
243 | |
244 Layout(); | |
245 GetBubbleFrameView()->bubble_border()->set_arrow_offset(0); | |
246 SizeToContents(); | |
247 } | |
248 | |
249 void InfolistWindow::ShowWithDelay() { | |
250 show_hide_timer_.Start( | |
251 FROM_HERE, | |
252 base::TimeDelta::FromMilliseconds(kInfolistShowDelayMilliSeconds), | |
253 GetWidget(), | |
254 &views::Widget::Show); | |
255 } | |
256 | |
257 void InfolistWindow::HideWithDelay() { | |
258 show_hide_timer_.Start( | |
259 FROM_HERE, | |
260 base::TimeDelta::FromMilliseconds(kInfolistHideDelayMilliSeconds), | |
261 GetWidget(), | |
262 &views::Widget::Close); | |
263 } | |
264 | |
265 void InfolistWindow::ShowImmediately() { | |
266 show_hide_timer_.Stop(); | |
267 GetWidget()->Show(); | |
268 } | |
269 | |
270 void InfolistWindow::HideImmediately() { | |
271 show_hide_timer_.Stop(); | |
272 GetWidget()->Close(); | |
273 } | |
274 | |
275 void InfolistWindow::WindowClosing() { | |
276 show_hide_timer_.Stop(); | |
277 } | |
278 | |
279 } // namespace ime | |
280 } // namespace ash | |
OLD | NEW |