Index: chrome/browser/chromeos/input_method/candidate_view.cc |
diff --git a/chrome/browser/chromeos/input_method/candidate_view.cc b/chrome/browser/chromeos/input_method/candidate_view.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..ab898d478aa6aab4ddd6a0c65a04facae700b515 |
--- /dev/null |
+++ b/chrome/browser/chromeos/input_method/candidate_view.cc |
@@ -0,0 +1,286 @@ |
+// Copyright 2013 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#include "chrome/browser/chromeos/input_method/candidate_view.h" |
+ |
+#include "base/strings/utf_string_conversions.h" |
+#include "chrome/browser/chromeos/input_method/candidate_window_constants.h" |
+#include "chromeos/ime/candidate_window.h" |
+#include "ui/gfx/color_utils.h" |
+#include "ui/native_theme/native_theme.h" |
+#include "ui/views/background.h" |
+#include "ui/views/border.h" |
+#include "ui/views/controls/label.h" |
+#include "ui/views/widget/widget.h" |
+ |
+namespace chromeos { |
+namespace input_method { |
+ |
+namespace { |
+ |
+// VerticalCandidateLabel is used for rendering candidate text in |
+// the vertical candidate window. |
+class VerticalCandidateLabel : public views::Label { |
+ public: |
+ VerticalCandidateLabel() {} |
+ |
+ private: |
+ virtual ~VerticalCandidateLabel() {} |
+ |
+ // Returns the preferred size, but guarantees that the width has at |
+ // least kMinCandidateLabelWidth pixels. |
+ virtual gfx::Size GetPreferredSize() OVERRIDE { |
+ gfx::Size size = Label::GetPreferredSize(); |
+ size.SetToMax(gfx::Size(kMinCandidateLabelWidth, 0)); |
+ size.SetToMin(gfx::Size(kMaxCandidateLabelWidth, size.height())); |
+ return size; |
+ } |
+ |
+ DISALLOW_COPY_AND_ASSIGN(VerticalCandidateLabel); |
+}; |
+ |
+// Creates the shortcut label, and returns it (never returns NULL). |
+// The label text is not set in this function. |
+views::Label* CreateShortcutLabel( |
+ CandidateWindow::Orientation orientation, |
+ const ui::NativeTheme& theme) { |
+ // Create the shortcut label. The label will be owned by |
+ // |wrapped_shortcut_label|, hence it's deleted when |
+ // |wrapped_shortcut_label| is deleted. |
+ views::Label* shortcut_label = new views::Label; |
+ |
+ if (orientation == CandidateWindow::VERTICAL) { |
+ shortcut_label->SetFontList( |
+ shortcut_label->font_list().DeriveFontListWithSizeDeltaAndStyle( |
+ kFontSizeDelta, gfx::Font::BOLD)); |
+ } else { |
+ shortcut_label->SetFontList( |
+ shortcut_label->font_list().DeriveFontListWithSizeDelta( |
+ kFontSizeDelta)); |
+ } |
+ // TODO(satorux): Maybe we need to use language specific fonts for |
+ // candidate_label, like Chinese font for Chinese input method? |
+ shortcut_label->SetEnabledColor(theme.GetSystemColor( |
+ ui::NativeTheme::kColorId_LabelEnabledColor)); |
+ shortcut_label->SetDisabledColor(theme.GetSystemColor( |
+ ui::NativeTheme::kColorId_LabelDisabledColor)); |
+ |
+ // Setup paddings. |
+ const gfx::Insets kVerticalShortcutLabelInsets(1, 6, 1, 6); |
+ const gfx::Insets kHorizontalShortcutLabelInsets(1, 3, 1, 0); |
+ const gfx::Insets insets = |
+ (orientation == CandidateWindow::VERTICAL ? |
+ kVerticalShortcutLabelInsets : |
+ kHorizontalShortcutLabelInsets); |
+ shortcut_label->set_border(views::Border::CreateEmptyBorder( |
+ insets.top(), insets.left(), insets.bottom(), insets.right())); |
+ |
+ // Add decoration based on the orientation. |
+ if (orientation == CandidateWindow::VERTICAL) { |
+ // Set the background color. |
+ SkColor blackish = color_utils::AlphaBlend( |
+ SK_ColorBLACK, |
+ theme.GetSystemColor(ui::NativeTheme::kColorId_WindowBackground), |
+ 0x40); |
+ SkColor transparent_blakish = color_utils::AlphaBlend( |
+ SK_ColorTRANSPARENT, blackish, 0xE0); |
+ shortcut_label->set_background( |
+ views::Background::CreateSolidBackground(transparent_blakish)); |
+ } |
+ |
+ return shortcut_label; |
+} |
+ |
+// Creates the candidate label, and returns it (never returns NULL). |
+// The label text is not set in this function. |
+views::Label* CreateCandidateLabel( |
+ CandidateWindow::Orientation orientation) { |
+ views::Label* candidate_label = NULL; |
+ |
+ // Create the candidate label. The label will be added to |this| as a |
+ // child view, hence it's deleted when |this| is deleted. |
+ if (orientation == CandidateWindow::VERTICAL) { |
+ candidate_label = new VerticalCandidateLabel; |
+ } else { |
+ candidate_label = new views::Label; |
+ } |
+ |
+ // Change the font size. |
+ candidate_label->SetFontList( |
+ candidate_label->font_list().DeriveFontListWithSizeDelta(kFontSizeDelta)); |
+ candidate_label->SetHorizontalAlignment(gfx::ALIGN_LEFT); |
+ |
+ return candidate_label; |
+} |
+ |
+// Creates the annotation label, and return it (never returns NULL). |
+// The label text is not set in this function. |
+views::Label* CreateAnnotationLabel( |
+ CandidateWindow::Orientation orientation, const ui::NativeTheme& theme) { |
+ // Create the annotation label. |
+ views::Label* annotation_label = new views::Label; |
+ |
+ // Change the font size and color. |
+ annotation_label->SetFontList( |
+ annotation_label->font_list().DeriveFontListWithSizeDelta( |
+ kFontSizeDelta)); |
+ annotation_label->SetEnabledColor(theme.GetSystemColor( |
+ ui::NativeTheme::kColorId_LabelDisabledColor)); |
+ annotation_label->SetHorizontalAlignment(gfx::ALIGN_LEFT); |
+ |
+ return annotation_label; |
+} |
+ |
+} // namespace |
+ |
+CandidateView::CandidateView( |
+ views::ButtonListener* listener, |
+ CandidateWindow::Orientation orientation) |
+ : views::CustomButton(listener), |
+ orientation_(orientation), |
+ shortcut_label_(NULL), |
+ candidate_label_(NULL), |
+ annotation_label_(NULL), |
+ infolist_icon_(NULL) { |
+ set_border(views::Border::CreateEmptyBorder(1, 1, 1, 1)); |
+ |
+ const ui::NativeTheme& theme = *GetNativeTheme(); |
+ shortcut_label_ = CreateShortcutLabel(orientation, theme); |
+ candidate_label_ = CreateCandidateLabel(orientation); |
+ annotation_label_ = CreateAnnotationLabel(orientation, theme); |
+ |
+ AddChildView(shortcut_label_); |
+ AddChildView(candidate_label_); |
+ AddChildView(annotation_label_); |
+ |
+ if (orientation == CandidateWindow::VERTICAL) { |
+ infolist_icon_ = new views::View; |
+ infolist_icon_->set_background( |
+ views::Background::CreateSolidBackground(theme.GetSystemColor( |
+ ui::NativeTheme::kColorId_FocusedBorderColor))); |
+ AddChildView(infolist_icon_); |
+ } |
+} |
+ |
+void CandidateView::GetPreferredWidths(int* shortcut_width, |
+ int* candidate_width) { |
+ *shortcut_width = shortcut_label_->GetPreferredSize().width(); |
+ *candidate_width = candidate_label_->GetPreferredSize().width(); |
+} |
+ |
+void CandidateView::SetWidths(int shortcut_width, int candidate_width) { |
+ shortcut_width_ = shortcut_width; |
+ shortcut_label_->SetVisible(shortcut_width_ != 0); |
+ candidate_width_ = candidate_width; |
+} |
+ |
+void CandidateView::SetEntry(const CandidateWindow::Entry& entry) { |
+ std::string label = entry.label; |
+ if (!label.empty() && orientation_ != CandidateWindow::VERTICAL) |
+ label += '.'; |
+ shortcut_label_->SetText(base::UTF8ToUTF16(label)); |
+ candidate_label_->SetText(base::UTF8ToUTF16(entry.value)); |
+ annotation_label_->SetText(base::UTF8ToUTF16(entry.annotation)); |
+} |
+ |
+void CandidateView::SetInfolistIcon(bool enable) { |
+ if (infolist_icon_) |
+ infolist_icon_->SetVisible(enable); |
+ SchedulePaint(); |
+} |
+ |
+void CandidateView::StateChanged() { |
+ shortcut_label_->SetEnabled(state() != STATE_DISABLED); |
+ if (state() == STATE_PRESSED) { |
+ ui::NativeTheme* theme = GetNativeTheme(); |
+ set_background( |
+ views::Background::CreateSolidBackground(theme->GetSystemColor( |
+ ui::NativeTheme::kColorId_TextfieldSelectionBackgroundFocused))); |
+ set_border(views::Border::CreateSolidBorder( |
+ 1, theme->GetSystemColor( |
+ ui::NativeTheme::kColorId_FocusedBorderColor))); |
+ |
+ // Cancel currently focused one. |
+ for (int i = 0; i < parent()->child_count(); ++i) { |
+ CandidateView* view = |
+ static_cast<CandidateView*>((parent()->child_at(i))); |
+ if (view != this && view->state() == STATE_PRESSED) |
+ view->SetState(STATE_NORMAL); |
+ } |
+ } else { |
+ set_background(NULL); |
+ set_border(views::Border::CreateEmptyBorder(1, 1, 1, 1)); |
+ } |
+} |
+ |
+bool CandidateView::OnMouseDragged(const ui::MouseEvent& event) { |
+ if (!HitTestPoint(event.location())) { |
+ // Moves the drag target to the sibling view. |
+ gfx::Point location_in_widget(event.location()); |
+ ConvertPointToWidget(this, &location_in_widget); |
+ for (int i = 0; i < parent()->child_count(); ++i) { |
+ views::View* sibling = parent()->child_at(i); |
+ if (sibling == this) |
+ continue; |
+ gfx::Point location_in_sibling(location_in_widget); |
+ ConvertPointFromWidget(sibling, &location_in_sibling); |
+ if (sibling->HitTestPoint(location_in_sibling)) { |
+ GetWidget()->GetRootView()->SetMouseHandler(sibling); |
+ return sibling->OnMouseDragged(event); |
+ } |
+ } |
+ |
+ return false; |
+ } |
+ |
+ return views::CustomButton::OnMouseDragged(event); |
+} |
+ |
+void CandidateView::Layout() { |
+ const int padding_width = |
+ orientation_ == CandidateWindow::VERTICAL ? 4 : 6; |
+ int x = 0; |
+ shortcut_label_->SetBounds(x, 0, shortcut_width_, height()); |
+ if (shortcut_width_ > 0) |
+ x += shortcut_width_ + padding_width; |
+ candidate_label_->SetBounds(x, 0, candidate_width_, height()); |
+ x += candidate_width_ + padding_width; |
+ |
+ int right = bounds().right(); |
+ if (infolist_icon_ && infolist_icon_->visible()) { |
+ infolist_icon_->SetBounds( |
+ right - kInfolistIndicatorIconWidth - kInfolistIndicatorIconPadding, |
+ kInfolistIndicatorIconPadding, |
+ kInfolistIndicatorIconWidth, |
+ height() - kInfolistIndicatorIconPadding * 2); |
+ right -= kInfolistIndicatorIconWidth + kInfolistIndicatorIconPadding * 2; |
+ } |
+ annotation_label_->SetBounds(x, 0, right - x, height()); |
+} |
+ |
+gfx::Size CandidateView::GetPreferredSize() { |
+ const int padding_width = |
+ orientation_ == CandidateWindow::VERTICAL ? 4 : 6; |
+ gfx::Size size; |
+ if (shortcut_label_->visible()) { |
+ size = shortcut_label_->GetPreferredSize(); |
+ size.Enlarge(padding_width, 0); |
+ } |
+ gfx::Size candidate_size = candidate_label_->GetPreferredSize(); |
+ size.Enlarge(candidate_size.width() + padding_width, 0); |
+ size.SetToMax(candidate_size); |
+ if (annotation_label_->visible()) { |
+ gfx::Size annotation_size = annotation_label_->GetPreferredSize(); |
+ size.Enlarge(annotation_size.width() + padding_width, 0); |
+ size.SetToMax(annotation_size); |
+ } |
+ |
+ // Reserves the margin for infolist_icon even if it's not visible. |
+ size.Enlarge( |
+ kInfolistIndicatorIconWidth + kInfolistIndicatorIconPadding * 2, 0); |
+ return size; |
+} |
+ |
+} // namespace input_method |
+} // namespace chromeos |