Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / ui / chromeos / ime / candidate_view.cc
blobdb90b6fc89ea89a5aadaf997b8dd3d0e12a9fc34
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.
5 #include "base/strings/utf_string_conversions.h"
6 #include "ui/base/ime/candidate_window.h"
7 #include "ui/chromeos/ime/candidate_view.h"
8 #include "ui/chromeos/ime/candidate_window_constants.h"
9 #include "ui/gfx/color_utils.h"
10 #include "ui/native_theme/native_theme.h"
11 #include "ui/views/background.h"
12 #include "ui/views/border.h"
13 #include "ui/views/controls/label.h"
14 #include "ui/views/widget/widget.h"
16 namespace ui {
17 namespace ime {
19 namespace {
21 // VerticalCandidateLabel is used for rendering candidate text in
22 // the vertical candidate window.
23 class VerticalCandidateLabel : public views::Label {
24 public:
25 VerticalCandidateLabel() {}
27 private:
28 ~VerticalCandidateLabel() override {}
30 // views::Label:
31 // Returns the preferred size, but guarantees that the width has at
32 // least kMinCandidateLabelWidth pixels.
33 gfx::Size GetPreferredSize() const override {
34 gfx::Size size = Label::GetPreferredSize();
35 size.SetToMax(gfx::Size(kMinCandidateLabelWidth, 0));
36 size.SetToMin(gfx::Size(kMaxCandidateLabelWidth, size.height()));
37 return size;
40 const char* GetClassName() const override { return "VerticalCandidateLabel"; }
42 DISALLOW_COPY_AND_ASSIGN(VerticalCandidateLabel);
45 // Creates the shortcut label, and returns it (never returns NULL).
46 // The label text is not set in this function.
47 views::Label* CreateShortcutLabel(
48 ui::CandidateWindow::Orientation orientation,
49 const ui::NativeTheme& theme) {
50 // Create the shortcut label. The label will be owned by
51 // |wrapped_shortcut_label|, hence it's deleted when
52 // |wrapped_shortcut_label| is deleted.
53 views::Label* shortcut_label = new views::Label;
55 if (orientation == ui::CandidateWindow::VERTICAL) {
56 shortcut_label->SetFontList(
57 shortcut_label->font_list().Derive(kFontSizeDelta, gfx::Font::BOLD));
58 } else {
59 shortcut_label->SetFontList(
60 shortcut_label->font_list().DeriveWithSizeDelta(kFontSizeDelta));
62 // TODO(satorux): Maybe we need to use language specific fonts for
63 // candidate_label, like Chinese font for Chinese input method?
64 shortcut_label->SetEnabledColor(theme.GetSystemColor(
65 ui::NativeTheme::kColorId_LabelEnabledColor));
66 shortcut_label->SetDisabledColor(theme.GetSystemColor(
67 ui::NativeTheme::kColorId_LabelDisabledColor));
69 // Setup paddings.
70 const gfx::Insets kVerticalShortcutLabelInsets(1, 6, 1, 6);
71 const gfx::Insets kHorizontalShortcutLabelInsets(1, 3, 1, 0);
72 const gfx::Insets insets =
73 (orientation == ui::CandidateWindow::VERTICAL ?
74 kVerticalShortcutLabelInsets :
75 kHorizontalShortcutLabelInsets);
76 shortcut_label->SetBorder(views::Border::CreateEmptyBorder(
77 insets.top(), insets.left(), insets.bottom(), insets.right()));
79 // Add decoration based on the orientation.
80 if (orientation == ui::CandidateWindow::VERTICAL) {
81 // Set the background color.
82 SkColor blackish = color_utils::AlphaBlend(
83 SK_ColorBLACK,
84 theme.GetSystemColor(ui::NativeTheme::kColorId_WindowBackground),
85 0x40);
86 SkColor transparent_blakish = color_utils::AlphaBlend(
87 SK_ColorTRANSPARENT, blackish, 0xE0);
88 shortcut_label->set_background(
89 views::Background::CreateSolidBackground(transparent_blakish));
91 shortcut_label->SetElideBehavior(gfx::NO_ELIDE);
93 return shortcut_label;
96 // Creates the candidate label, and returns it (never returns NULL).
97 // The label text is not set in this function.
98 views::Label* CreateCandidateLabel(
99 ui::CandidateWindow::Orientation orientation) {
100 views::Label* candidate_label = NULL;
102 // Create the candidate label. The label will be added to |this| as a
103 // child view, hence it's deleted when |this| is deleted.
104 if (orientation == ui::CandidateWindow::VERTICAL) {
105 candidate_label = new VerticalCandidateLabel;
106 } else {
107 candidate_label = new views::Label;
110 // Change the font size.
111 candidate_label->SetFontList(
112 candidate_label->font_list().DeriveWithSizeDelta(kFontSizeDelta));
113 candidate_label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
114 candidate_label->SetElideBehavior(gfx::NO_ELIDE);
116 return candidate_label;
119 // Creates the annotation label, and return it (never returns NULL).
120 // The label text is not set in this function.
121 views::Label* CreateAnnotationLabel(
122 ui::CandidateWindow::Orientation orientation,
123 const ui::NativeTheme& theme) {
124 // Create the annotation label.
125 views::Label* annotation_label = new views::Label;
127 // Change the font size and color.
128 annotation_label->SetFontList(
129 annotation_label->font_list().DeriveWithSizeDelta(kFontSizeDelta));
130 annotation_label->SetEnabledColor(theme.GetSystemColor(
131 ui::NativeTheme::kColorId_LabelDisabledColor));
132 annotation_label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
133 annotation_label->SetElideBehavior(gfx::NO_ELIDE);
135 return annotation_label;
138 } // namespace
140 CandidateView::CandidateView(
141 views::ButtonListener* listener,
142 ui::CandidateWindow::Orientation orientation)
143 : views::CustomButton(listener),
144 orientation_(orientation),
145 shortcut_label_(NULL),
146 candidate_label_(NULL),
147 annotation_label_(NULL),
148 infolist_icon_(NULL),
149 shortcut_width_(0),
150 candidate_width_(0),
151 highlighted_(false) {
152 SetBorder(views::Border::CreateEmptyBorder(1, 1, 1, 1));
154 const ui::NativeTheme& theme = *GetNativeTheme();
155 shortcut_label_ = CreateShortcutLabel(orientation, theme);
156 candidate_label_ = CreateCandidateLabel(orientation);
157 annotation_label_ = CreateAnnotationLabel(orientation, theme);
159 AddChildView(shortcut_label_);
160 AddChildView(candidate_label_);
161 AddChildView(annotation_label_);
163 if (orientation == ui::CandidateWindow::VERTICAL) {
164 infolist_icon_ = new views::View;
165 infolist_icon_->set_background(
166 views::Background::CreateSolidBackground(theme.GetSystemColor(
167 ui::NativeTheme::kColorId_FocusedBorderColor)));
168 AddChildView(infolist_icon_);
172 void CandidateView::GetPreferredWidths(int* shortcut_width,
173 int* candidate_width) {
174 *shortcut_width = shortcut_label_->GetPreferredSize().width();
175 *candidate_width = candidate_label_->GetPreferredSize().width();
178 void CandidateView::SetWidths(int shortcut_width, int candidate_width) {
179 shortcut_width_ = shortcut_width;
180 shortcut_label_->SetVisible(shortcut_width_ != 0);
181 candidate_width_ = candidate_width;
184 void CandidateView::SetEntry(const ui::CandidateWindow::Entry& entry) {
185 base::string16 label = entry.label;
186 if (!label.empty() && orientation_ != ui::CandidateWindow::VERTICAL)
187 label += base::ASCIIToUTF16(".");
188 shortcut_label_->SetText(label);
189 candidate_label_->SetText(entry.value);
190 annotation_label_->SetText(entry.annotation);
193 void CandidateView::SetInfolistIcon(bool enable) {
194 if (infolist_icon_)
195 infolist_icon_->SetVisible(enable);
196 SchedulePaint();
199 void CandidateView::SetHighlighted(bool highlighted) {
200 if (highlighted_ == highlighted)
201 return;
203 highlighted_ = highlighted;
204 if (highlighted) {
205 ui::NativeTheme* theme = GetNativeTheme();
206 set_background(
207 views::Background::CreateSolidBackground(theme->GetSystemColor(
208 ui::NativeTheme::kColorId_TextfieldSelectionBackgroundFocused)));
209 SetBorder(views::Border::CreateSolidBorder(
211 theme->GetSystemColor(ui::NativeTheme::kColorId_FocusedBorderColor)));
213 // Cancel currently focused one.
214 for (int i = 0; i < parent()->child_count(); ++i) {
215 CandidateView* view =
216 static_cast<CandidateView*>((parent()->child_at(i)));
217 if (view != this)
218 view->SetHighlighted(false);
220 } else {
221 set_background(NULL);
222 SetBorder(views::Border::CreateEmptyBorder(1, 1, 1, 1));
224 SchedulePaint();
227 void CandidateView::StateChanged() {
228 shortcut_label_->SetEnabled(state() != STATE_DISABLED);
229 if (state() == STATE_PRESSED)
230 SetHighlighted(true);
233 const char* CandidateView::GetClassName() const {
234 return "CandidateView";
237 bool CandidateView::OnMouseDragged(const ui::MouseEvent& event) {
238 if (!HitTestPoint(event.location())) {
239 // Moves the drag target to the sibling view.
240 gfx::Point location_in_widget(event.location());
241 ConvertPointToWidget(this, &location_in_widget);
242 for (int i = 0; i < parent()->child_count(); ++i) {
243 CandidateView* sibling =
244 static_cast<CandidateView*>(parent()->child_at(i));
245 if (sibling == this)
246 continue;
247 gfx::Point location_in_sibling(location_in_widget);
248 ConvertPointFromWidget(sibling, &location_in_sibling);
249 if (sibling->HitTestPoint(location_in_sibling)) {
250 GetWidget()->GetRootView()->SetMouseHandler(sibling);
251 sibling->SetHighlighted(true);
252 return sibling->OnMouseDragged(ui::MouseEvent(event, this, sibling));
256 return false;
259 return views::CustomButton::OnMouseDragged(event);
262 void CandidateView::Layout() {
263 const int padding_width =
264 orientation_ == ui::CandidateWindow::VERTICAL ? 4 : 6;
265 int x = 0;
266 shortcut_label_->SetBounds(x, 0, shortcut_width_, height());
267 if (shortcut_width_ > 0)
268 x += shortcut_width_ + padding_width;
269 candidate_label_->SetBounds(x, 0, candidate_width_, height());
270 x += candidate_width_ + padding_width;
272 int right = bounds().right();
273 if (infolist_icon_ && infolist_icon_->visible()) {
274 infolist_icon_->SetBounds(
275 right - kInfolistIndicatorIconWidth - kInfolistIndicatorIconPadding,
276 kInfolistIndicatorIconPadding,
277 kInfolistIndicatorIconWidth,
278 height() - kInfolistIndicatorIconPadding * 2);
279 right -= kInfolistIndicatorIconWidth + kInfolistIndicatorIconPadding * 2;
281 annotation_label_->SetBounds(x, 0, right - x, height());
284 gfx::Size CandidateView::GetPreferredSize() const {
285 const int padding_width =
286 orientation_ == ui::CandidateWindow::VERTICAL ? 4 : 6;
287 gfx::Size size;
288 if (shortcut_label_->visible()) {
289 size = shortcut_label_->GetPreferredSize();
290 size.SetToMax(gfx::Size(shortcut_width_, 0));
291 size.Enlarge(padding_width, 0);
293 gfx::Size candidate_size = candidate_label_->GetPreferredSize();
294 candidate_size.SetToMax(gfx::Size(candidate_width_, 0));
295 size.Enlarge(candidate_size.width() + padding_width, 0);
296 size.SetToMax(candidate_size);
297 if (annotation_label_->visible()) {
298 gfx::Size annotation_size = annotation_label_->GetPreferredSize();
299 size.Enlarge(annotation_size.width() + padding_width, 0);
300 size.SetToMax(annotation_size);
303 // Reserves the margin for infolist_icon even if it's not visible.
304 size.Enlarge(
305 kInfolistIndicatorIconWidth + kInfolistIndicatorIconPadding * 2, 0);
306 return size;
309 } // namespace ime
310 } // namespace ui