summaryrefslogtreecommitdiffstats
path: root/ash/ime/candidate_view.cc
diff options
context:
space:
mode:
authormukai@chromium.org <mukai@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-01-15 16:24:24 +0000
committermukai@chromium.org <mukai@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-01-15 16:24:24 +0000
commitbe98edc4db0dfdc9c8b13d715c015f447b5969e2 (patch)
treea2c2a0a67877d7ddf90237c69b95bd58f5f14a2c /ash/ime/candidate_view.cc
parent0a0012f6c1fb0d3896827987b6d9fcccdb51597e (diff)
downloadchromium_src-be98edc4db0dfdc9c8b13d715c015f447b5969e2.zip
chromium_src-be98edc4db0dfdc9c8b13d715c015f447b5969e2.tar.gz
chromium_src-be98edc4db0dfdc9c8b13d715c015f447b5969e2.tar.bz2
Moves IME's views specific code out from chrome/browser/chromeos.
Now UI code of input methods -- candidate window, infolist window, and mode indicator -- is pure views and doesn't need to be in c/b. I chose ash/ime because they are ash-specific UI, but I'm okay to move to another place. Please tell me if you have other ideas. BUG=325813 R=oshima@chromium.org, komatsu@chromium.org TEST=no functional changes, compile succeeds Review URL: https://codereview.chromium.org/132083009 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@244895 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'ash/ime/candidate_view.cc')
-rw-r--r--ash/ime/candidate_view.cc289
1 files changed, 289 insertions, 0 deletions
diff --git a/ash/ime/candidate_view.cc b/ash/ime/candidate_view.cc
new file mode 100644
index 0000000..652998a
--- /dev/null
+++ b/ash/ime/candidate_view.cc
@@ -0,0 +1,289 @@
+// Copyright 2014 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 "ash/ime/candidate_view.h"
+
+#include "ash/ime/candidate_window_constants.h"
+#include "base/strings/utf_string_conversions.h"
+#include "ui/base/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 ash {
+namespace ime {
+
+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(
+ ui::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 == ui::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 == ui::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 == ui::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(
+ ui::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 == ui::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(
+ ui::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,
+ ui::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 == ui::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 ui::CandidateWindow::Entry& entry) {
+ std::string label = entry.label;
+ if (!label.empty() && orientation_ != ui::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_ == ui::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_ == ui::CandidateWindow::VERTICAL ? 4 : 6;
+ gfx::Size size;
+ if (shortcut_label_->visible()) {
+ size = shortcut_label_->GetPreferredSize();
+ size.SetToMax(gfx::Size(shortcut_width_, 0));
+ size.Enlarge(padding_width, 0);
+ }
+ gfx::Size candidate_size = candidate_label_->GetPreferredSize();
+ candidate_size.SetToMax(gfx::Size(candidate_width_, 0));
+ 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 ime
+} // namespace ash