Fix the menu alignment for the three button menu.
[chromium-blink-merge.git] / ash / ime / candidate_view.cc
blob0cafbe1bb4344130e1d49a4df819a17410577563
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 "ash/ime/candidate_view.h"
7 #include "ash/ime/candidate_window_constants.h"
8 #include "base/strings/utf_string_conversions.h"
9 #include "ui/base/ime/candidate_window.h"
10 #include "ui/gfx/color_utils.h"
11 #include "ui/native_theme/native_theme.h"
12 #include "ui/views/background.h"
13 #include "ui/views/border.h"
14 #include "ui/views/controls/label.h"
15 #include "ui/views/widget/widget.h"
17 namespace ash {
18 namespace ime {
20 namespace {
22 // VerticalCandidateLabel is used for rendering candidate text in
23 // the vertical candidate window.
24 class VerticalCandidateLabel : public views::Label {
25 public:
26 VerticalCandidateLabel() {}
28 private:
29 virtual ~VerticalCandidateLabel() {}
31 // Returns the preferred size, but guarantees that the width has at
32 // least kMinCandidateLabelWidth pixels.
33 virtual 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 DISALLOW_COPY_AND_ASSIGN(VerticalCandidateLabel);
43 // Creates the shortcut label, and returns it (never returns NULL).
44 // The label text is not set in this function.
45 views::Label* CreateShortcutLabel(
46 ui::CandidateWindow::Orientation orientation,
47 const ui::NativeTheme& theme) {
48 // Create the shortcut label. The label will be owned by
49 // |wrapped_shortcut_label|, hence it's deleted when
50 // |wrapped_shortcut_label| is deleted.
51 views::Label* shortcut_label = new views::Label;
53 if (orientation == ui::CandidateWindow::VERTICAL) {
54 shortcut_label->SetFontList(
55 shortcut_label->font_list().Derive(kFontSizeDelta, gfx::Font::BOLD));
56 } else {
57 shortcut_label->SetFontList(
58 shortcut_label->font_list().DeriveWithSizeDelta(kFontSizeDelta));
60 // TODO(satorux): Maybe we need to use language specific fonts for
61 // candidate_label, like Chinese font for Chinese input method?
62 shortcut_label->SetEnabledColor(theme.GetSystemColor(
63 ui::NativeTheme::kColorId_LabelEnabledColor));
64 shortcut_label->SetDisabledColor(theme.GetSystemColor(
65 ui::NativeTheme::kColorId_LabelDisabledColor));
67 // Setup paddings.
68 const gfx::Insets kVerticalShortcutLabelInsets(1, 6, 1, 6);
69 const gfx::Insets kHorizontalShortcutLabelInsets(1, 3, 1, 0);
70 const gfx::Insets insets =
71 (orientation == ui::CandidateWindow::VERTICAL ?
72 kVerticalShortcutLabelInsets :
73 kHorizontalShortcutLabelInsets);
74 shortcut_label->SetBorder(views::Border::CreateEmptyBorder(
75 insets.top(), insets.left(), insets.bottom(), insets.right()));
77 // Add decoration based on the orientation.
78 if (orientation == ui::CandidateWindow::VERTICAL) {
79 // Set the background color.
80 SkColor blackish = color_utils::AlphaBlend(
81 SK_ColorBLACK,
82 theme.GetSystemColor(ui::NativeTheme::kColorId_WindowBackground),
83 0x40);
84 SkColor transparent_blakish = color_utils::AlphaBlend(
85 SK_ColorTRANSPARENT, blackish, 0xE0);
86 shortcut_label->set_background(
87 views::Background::CreateSolidBackground(transparent_blakish));
90 return shortcut_label;
93 // Creates the candidate label, and returns it (never returns NULL).
94 // The label text is not set in this function.
95 views::Label* CreateCandidateLabel(
96 ui::CandidateWindow::Orientation orientation) {
97 views::Label* candidate_label = NULL;
99 // Create the candidate label. The label will be added to |this| as a
100 // child view, hence it's deleted when |this| is deleted.
101 if (orientation == ui::CandidateWindow::VERTICAL) {
102 candidate_label = new VerticalCandidateLabel;
103 } else {
104 candidate_label = new views::Label;
107 // Change the font size.
108 candidate_label->SetFontList(
109 candidate_label->font_list().DeriveWithSizeDelta(kFontSizeDelta));
110 candidate_label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
112 return candidate_label;
115 // Creates the annotation label, and return it (never returns NULL).
116 // The label text is not set in this function.
117 views::Label* CreateAnnotationLabel(
118 ui::CandidateWindow::Orientation orientation,
119 const ui::NativeTheme& theme) {
120 // Create the annotation label.
121 views::Label* annotation_label = new views::Label;
123 // Change the font size and color.
124 annotation_label->SetFontList(
125 annotation_label->font_list().DeriveWithSizeDelta(kFontSizeDelta));
126 annotation_label->SetEnabledColor(theme.GetSystemColor(
127 ui::NativeTheme::kColorId_LabelDisabledColor));
128 annotation_label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
130 return annotation_label;
133 } // namespace
135 CandidateView::CandidateView(
136 views::ButtonListener* listener,
137 ui::CandidateWindow::Orientation orientation)
138 : views::CustomButton(listener),
139 orientation_(orientation),
140 shortcut_label_(NULL),
141 candidate_label_(NULL),
142 annotation_label_(NULL),
143 infolist_icon_(NULL),
144 shortcut_width_(0),
145 candidate_width_(0),
146 highlighted_(false) {
147 SetBorder(views::Border::CreateEmptyBorder(1, 1, 1, 1));
149 const ui::NativeTheme& theme = *GetNativeTheme();
150 shortcut_label_ = CreateShortcutLabel(orientation, theme);
151 candidate_label_ = CreateCandidateLabel(orientation);
152 annotation_label_ = CreateAnnotationLabel(orientation, theme);
154 AddChildView(shortcut_label_);
155 AddChildView(candidate_label_);
156 AddChildView(annotation_label_);
158 if (orientation == ui::CandidateWindow::VERTICAL) {
159 infolist_icon_ = new views::View;
160 infolist_icon_->set_background(
161 views::Background::CreateSolidBackground(theme.GetSystemColor(
162 ui::NativeTheme::kColorId_FocusedBorderColor)));
163 AddChildView(infolist_icon_);
167 void CandidateView::GetPreferredWidths(int* shortcut_width,
168 int* candidate_width) {
169 *shortcut_width = shortcut_label_->GetPreferredSize().width();
170 *candidate_width = candidate_label_->GetPreferredSize().width();
173 void CandidateView::SetWidths(int shortcut_width, int candidate_width) {
174 shortcut_width_ = shortcut_width;
175 shortcut_label_->SetVisible(shortcut_width_ != 0);
176 candidate_width_ = candidate_width;
179 void CandidateView::SetEntry(const ui::CandidateWindow::Entry& entry) {
180 base::string16 label = entry.label;
181 if (!label.empty() && orientation_ != ui::CandidateWindow::VERTICAL)
182 label += base::ASCIIToUTF16(".");
183 shortcut_label_->SetText(label);
184 candidate_label_->SetText(entry.value);
185 annotation_label_->SetText(entry.annotation);
188 void CandidateView::SetInfolistIcon(bool enable) {
189 if (infolist_icon_)
190 infolist_icon_->SetVisible(enable);
191 SchedulePaint();
194 void CandidateView::SetHighlighted(bool highlighted) {
195 if (highlighted_ == highlighted)
196 return;
198 highlighted_ = highlighted;
199 if (highlighted) {
200 ui::NativeTheme* theme = GetNativeTheme();
201 set_background(
202 views::Background::CreateSolidBackground(theme->GetSystemColor(
203 ui::NativeTheme::kColorId_TextfieldSelectionBackgroundFocused)));
204 SetBorder(views::Border::CreateSolidBorder(
206 theme->GetSystemColor(ui::NativeTheme::kColorId_FocusedBorderColor)));
208 // Cancel currently focused one.
209 for (int i = 0; i < parent()->child_count(); ++i) {
210 CandidateView* view =
211 static_cast<CandidateView*>((parent()->child_at(i)));
212 if (view != this)
213 view->SetHighlighted(false);
215 } else {
216 set_background(NULL);
217 SetBorder(views::Border::CreateEmptyBorder(1, 1, 1, 1));
219 SchedulePaint();
222 void CandidateView::StateChanged() {
223 shortcut_label_->SetEnabled(state() != STATE_DISABLED);
224 if (state() == STATE_PRESSED)
225 SetHighlighted(true);
228 bool CandidateView::OnMouseDragged(const ui::MouseEvent& event) {
229 if (!HitTestPoint(event.location())) {
230 // Moves the drag target to the sibling view.
231 gfx::Point location_in_widget(event.location());
232 ConvertPointToWidget(this, &location_in_widget);
233 for (int i = 0; i < parent()->child_count(); ++i) {
234 CandidateView* sibling =
235 static_cast<CandidateView*>(parent()->child_at(i));
236 if (sibling == this)
237 continue;
238 gfx::Point location_in_sibling(location_in_widget);
239 ConvertPointFromWidget(sibling, &location_in_sibling);
240 if (sibling->HitTestPoint(location_in_sibling)) {
241 GetWidget()->GetRootView()->SetMouseHandler(sibling);
242 sibling->SetHighlighted(true);
243 return sibling->OnMouseDragged(ui::MouseEvent(event, this, sibling));
247 return false;
250 return views::CustomButton::OnMouseDragged(event);
253 void CandidateView::Layout() {
254 const int padding_width =
255 orientation_ == ui::CandidateWindow::VERTICAL ? 4 : 6;
256 int x = 0;
257 shortcut_label_->SetBounds(x, 0, shortcut_width_, height());
258 if (shortcut_width_ > 0)
259 x += shortcut_width_ + padding_width;
260 candidate_label_->SetBounds(x, 0, candidate_width_, height());
261 x += candidate_width_ + padding_width;
263 int right = bounds().right();
264 if (infolist_icon_ && infolist_icon_->visible()) {
265 infolist_icon_->SetBounds(
266 right - kInfolistIndicatorIconWidth - kInfolistIndicatorIconPadding,
267 kInfolistIndicatorIconPadding,
268 kInfolistIndicatorIconWidth,
269 height() - kInfolistIndicatorIconPadding * 2);
270 right -= kInfolistIndicatorIconWidth + kInfolistIndicatorIconPadding * 2;
272 annotation_label_->SetBounds(x, 0, right - x, height());
275 gfx::Size CandidateView::GetPreferredSize() const {
276 const int padding_width =
277 orientation_ == ui::CandidateWindow::VERTICAL ? 4 : 6;
278 gfx::Size size;
279 if (shortcut_label_->visible()) {
280 size = shortcut_label_->GetPreferredSize();
281 size.SetToMax(gfx::Size(shortcut_width_, 0));
282 size.Enlarge(padding_width, 0);
284 gfx::Size candidate_size = candidate_label_->GetPreferredSize();
285 candidate_size.SetToMax(gfx::Size(candidate_width_, 0));
286 size.Enlarge(candidate_size.width() + padding_width, 0);
287 size.SetToMax(candidate_size);
288 if (annotation_label_->visible()) {
289 gfx::Size annotation_size = annotation_label_->GetPreferredSize();
290 size.Enlarge(annotation_size.width() + padding_width, 0);
291 size.SetToMax(annotation_size);
294 // Reserves the margin for infolist_icon even if it's not visible.
295 size.Enlarge(
296 kInfolistIndicatorIconWidth + kInfolistIndicatorIconPadding * 2, 0);
297 return size;
300 } // namespace ime
301 } // namespace ash