15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/chromeos/input_method/candidate_window_view.h"
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <string>
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ash/shell.h"
9868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/utf_string_conversions.h"
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/chromeos/input_method/candidate_view.h"
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/chromeos/input_method/candidate_window_constants.h"
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/chromeos/input_method/hidable_area.h"
132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chromeos/dbus/ibus/ibus_lookup_table.h"
147dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch#include "ui/gfx/color_utils.h"
157dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch#include "ui/native_theme/native_theme.h"
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/views/controls/label.h"
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/views/layout/grid_layout.h"
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/views/widget/widget.h"
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace chromeos {
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace input_method {
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// VerticalCandidateLabel is used for rendering candidate text in
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// the vertical candidate window.
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class VerticalCandidateLabel : public views::Label {
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  VerticalCandidateLabel() {}
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual ~VerticalCandidateLabel() {}
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Returns the preferred size, but guarantees that the width has at
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // least kMinCandidateLabelWidth pixels.
352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual gfx::Size GetPreferredSize() OVERRIDE {
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    gfx::Size size = Label::GetPreferredSize();
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Hack. +2 is needed to prevent labels from getting elided like
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // "abc..." in some cases. TODO(satorux): Figure out why it's
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // necessary.
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    size.set_width(size.width() + 2);
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (size.width() < kMinCandidateLabelWidth) {
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      size.set_width(kMinCandidateLabelWidth);
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (size.width() > kMaxCandidateLabelWidth) {
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      size.set_width(kMaxCandidateLabelWidth);
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return size;
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(VerticalCandidateLabel);
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Wraps the given view with some padding, and returns it.
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)views::View* WrapWithPadding(views::View* view, const gfx::Insets& insets) {
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  views::View* wrapper = new views::View;
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Use GridLayout to give some insets inside.
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  views::GridLayout* layout = new views::GridLayout(wrapper);
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  wrapper->SetLayoutManager(layout);  // |wrapper| owns |layout|.
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  layout->SetInsets(insets);
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  views::ColumnSet* column_set = layout->AddColumnSet(0);
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  column_set->AddColumn(
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      views::GridLayout::FILL, views::GridLayout::FILL,
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      1, views::GridLayout::USE_PREF, 0, 0);
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  layout->StartRow(0, 0);
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Add the view contents.
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  layout->AddView(view);  // |view| is owned by |wraper|, not |layout|.
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return wrapper;
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Creates shortcut text from the given index and the orientation.
732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)string16 CreateShortcutText(size_t index, const IBusLookupTable& table) {
742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (index >= table.candidates().size())
752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return UTF8ToUTF16("");
762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::string shortcut_text = table.candidates()[index].label;
772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!shortcut_text.empty() &&
782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      table.orientation() != IBusLookupTable::VERTICAL)
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    shortcut_text += '.';
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return UTF8ToUTF16(shortcut_text);
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Creates the shortcut label, and returns it (never returns NULL).
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The label text is not set in this function.
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)views::Label* CreateShortcutLabel(
867dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    IBusLookupTable::Orientation orientation, const ui::NativeTheme& theme) {
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Create the shortcut label. The label will be owned by
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // |wrapped_shortcut_label|, hence it's deleted when
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // |wrapped_shortcut_label| is deleted.
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  views::Label* shortcut_label = new views::Label;
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (orientation == IBusLookupTable::VERTICAL) {
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    shortcut_label->SetFont(
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        shortcut_label->font().DeriveFont(kFontSizeDelta, gfx::Font::BOLD));
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    shortcut_label->SetFont(
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        shortcut_label->font().DeriveFont(kFontSizeDelta));
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TODO(satorux): Maybe we need to use language specific fonts for
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // candidate_label, like Chinese font for Chinese input method?
1017dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  shortcut_label->SetEnabledColor(theme.GetSystemColor(
1027dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      ui::NativeTheme::kColorId_LabelEnabledColor));
1037dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  shortcut_label->SetDisabledColor(theme.GetSystemColor(
1047dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      ui::NativeTheme::kColorId_LabelDisabledColor));
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return shortcut_label;
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Wraps the shortcut label, then decorates wrapped shortcut label
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// and returns it (never returns NULL).
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The label text is not set in this function.
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)views::View* CreateWrappedShortcutLabel(
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    views::Label* shortcut_label,
1147dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    IBusLookupTable::Orientation orientation,
1157dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    const ui::NativeTheme& theme) {
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Wrap it with padding.
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const gfx::Insets kVerticalShortcutLabelInsets(1, 6, 1, 6);
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const gfx::Insets kHorizontalShortcutLabelInsets(1, 3, 1, 0);
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const gfx::Insets insets =
1202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      (orientation == IBusLookupTable::VERTICAL ?
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       kVerticalShortcutLabelInsets :
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       kHorizontalShortcutLabelInsets);
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  views::View* wrapped_shortcut_label =
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      WrapWithPadding(shortcut_label, insets);
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Add decoration based on the orientation.
1272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (orientation == IBusLookupTable::VERTICAL) {
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Set the background color.
1297dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    SkColor blackish = color_utils::AlphaBlend(
1307dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        SK_ColorBLACK,
1317dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        theme.GetSystemColor(ui::NativeTheme::kColorId_WindowBackground),
1327dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        0x40);
1337dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    SkColor transparent_blakish = color_utils::AlphaBlend(
1347dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        SK_ColorTRANSPARENT, blackish, 0xE0);
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    wrapped_shortcut_label->set_background(
1367dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        views::Background::CreateSolidBackground(transparent_blakish));
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    shortcut_label->SetBackgroundColor(
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        wrapped_shortcut_label->background()->get_color());
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return wrapped_shortcut_label;
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Creates the candidate label, and returns it (never returns NULL).
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The label text is not set in this function.
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)views::Label* CreateCandidateLabel(
1472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    IBusLookupTable::Orientation orientation) {
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  views::Label* candidate_label = NULL;
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Create the candidate label. The label will be added to |this| as a
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // child view, hence it's deleted when |this| is deleted.
1522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (orientation == IBusLookupTable::VERTICAL) {
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    candidate_label = new VerticalCandidateLabel;
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    candidate_label = new views::Label;
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Change the font size.
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  candidate_label->SetFont(
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      candidate_label->font().DeriveFont(kFontSizeDelta));
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  candidate_label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return candidate_label;
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Creates the annotation label, and return it (never returns NULL).
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The label text is not set in this function.
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)views::Label* CreateAnnotationLabel(
1697dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    IBusLookupTable::Orientation orientation, const ui::NativeTheme& theme) {
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Create the annotation label.
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  views::Label* annotation_label = new views::Label;
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Change the font size and color.
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  annotation_label->SetFont(
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      annotation_label->font().DeriveFont(kFontSizeDelta));
1767dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  annotation_label->SetEnabledColor(theme.GetSystemColor(
1777dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      ui::NativeTheme::kColorId_LabelDisabledColor));
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  annotation_label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return annotation_label;
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Computes shortcut column size.
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)gfx::Size ComputeShortcutColumnSize(
1857dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    const IBusLookupTable& lookup_table,
1867dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    const ui::NativeTheme& theme) {
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int shortcut_column_width = 0;
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int shortcut_column_height = 0;
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Create the shortcut label. The label will be owned by
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // |wrapped_shortcut_label|, hence it's deleted when
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // |wrapped_shortcut_label| is deleted.
1922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  views::Label* shortcut_label = CreateShortcutLabel(
1937dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      lookup_table.orientation(), theme);
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<views::View> wrapped_shortcut_label(
1957dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      CreateWrappedShortcutLabel(shortcut_label,
1967dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                                 lookup_table.orientation(),
1977dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                                 theme));
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Compute the max width and height in shortcut labels.
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We'll create temporary shortcut labels, and choose the largest width and
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // height.
2022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (size_t i = 0; i < lookup_table.page_size(); ++i) {
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    shortcut_label->SetText(CreateShortcutText(i, lookup_table));
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    gfx::Size text_size = wrapped_shortcut_label->GetPreferredSize();
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    shortcut_column_width = std::max(shortcut_column_width, text_size.width());
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    shortcut_column_height = std::max(shortcut_column_height,
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                      text_size.height());
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return gfx::Size(shortcut_column_width, shortcut_column_height);
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Computes the page index. For instance, if the page size is 9, and the
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// cursor is pointing to 13th candidate, the page index will be 1 (2nd
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// page, as the index is zero-origin). Returns -1 on error.
2162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)int ComputePageIndex(const IBusLookupTable& lookup_table) {
2172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (lookup_table.page_size() > 0)
2182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return lookup_table.cursor_position() / lookup_table.page_size();
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return -1;
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Computes candidate column size.
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)gfx::Size ComputeCandidateColumnSize(
2242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const IBusLookupTable& lookup_table) {
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int candidate_column_width = 0;
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int candidate_column_height = 0;
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<views::Label> candidate_label(
2282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      CreateCandidateLabel(lookup_table.orientation()));
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Compute the start index of |lookup_table_|.
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const int current_page_index = ComputePageIndex(lookup_table);
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (current_page_index < 0)
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return gfx::Size(0, 0);
2342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  const size_t start_from = current_page_index * lookup_table.page_size();
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Compute the max width and height in candidate labels.
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We'll create temporary candidate labels, and choose the largest width and
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // height.
2392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (size_t i = 0; i + start_from < lookup_table.candidates().size(); ++i) {
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const size_t index = start_from + i;
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    candidate_label->SetText(
2432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        UTF8ToUTF16(lookup_table.candidates()[index].value));
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    gfx::Size text_size = candidate_label->GetPreferredSize();
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    candidate_column_width = std::max(candidate_column_width,
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                      text_size.width());
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    candidate_column_height = std::max(candidate_column_height,
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                       text_size.height());
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return gfx::Size(candidate_column_width, candidate_column_height);
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Computes annotation column size.
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)gfx::Size ComputeAnnotationColumnSize(
2567dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    const IBusLookupTable& lookup_table, const ui::NativeTheme& theme) {
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int annotation_column_width = 0;
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int annotation_column_height = 0;
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<views::Label> annotation_label(
2607dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      CreateAnnotationLabel(lookup_table.orientation(), theme));
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Compute the start index of |lookup_table_|.
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const int current_page_index = ComputePageIndex(lookup_table);
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (current_page_index < 0)
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return gfx::Size(0, 0);
2662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  const size_t start_from = current_page_index * lookup_table.page_size();
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Compute max width and height in annotation labels.
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We'll create temporary annotation labels, and choose the largest width and
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // height.
2712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (size_t i = 0; i + start_from < lookup_table.candidates().size(); ++i) {
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const size_t index = start_from + i;
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    annotation_label->SetText(
2752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        UTF8ToUTF16(lookup_table.candidates()[index].annotation));
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    gfx::Size text_size = annotation_label->GetPreferredSize();
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    annotation_column_width = std::max(annotation_column_width,
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                       text_size.width());
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    annotation_column_height = std::max(annotation_column_height,
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                        text_size.height());
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return gfx::Size(annotation_column_width, annotation_column_height);
2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// InformationTextArea is a HidableArea having a single Label in it.
2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class InformationTextArea : public HidableArea {
2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Specify the alignment and initialize the control.
2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  InformationTextArea(gfx::HorizontalAlignment align, int minWidth)
2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      : minWidth_(minWidth) {
2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    label_ = new views::Label;
2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    label_->SetHorizontalAlignment(align);
2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const gfx::Insets kInsets(2, 2, 2, 4);
2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    views::View* contents = WrapWithPadding(label_, kInsets);
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SetContents(contents);
3007dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    contents->set_border(views::Border::CreateSolidBorder(
3017dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        1,
3027dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        GetNativeTheme()->GetSystemColor(
3037dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch            ui::NativeTheme::kColorId_MenuBorderColor)));
3047dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    contents->set_background(views::Background::CreateSolidBackground(
3057dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        color_utils::AlphaBlend(SK_ColorBLACK,
3067dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                                GetNativeTheme()->GetSystemColor(
3077dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                                    ui::NativeTheme::kColorId_WindowBackground),
3087dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                                0x10)));
3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    label_->SetBackgroundColor(contents->background()->get_color());
3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Set the displayed text.
3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void SetText(const std::string& utf8_text) {
3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    label_->SetText(UTF8ToUTF16(utf8_text));
3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) protected:
3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual gfx::Size GetPreferredSize() OVERRIDE {
3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    gfx::Size size = HidableArea::GetPreferredSize();
3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Hack. +2 is needed as the same reason as in VerticalCandidateLabel
3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    size.set_width(size.width() + 2);
3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (size.width() < minWidth_) {
3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      size.set_width(minWidth_);
3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return size;
3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  views::Label* label_;
3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int minWidth_;
3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(InformationTextArea);
3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)CandidateView::CandidateView(
3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    CandidateWindowView* parent_candidate_window,
3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int index_in_page,
3382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    IBusLookupTable::Orientation orientation)
3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : index_in_page_(index_in_page),
3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      orientation_(orientation),
3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      parent_candidate_window_(parent_candidate_window),
3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      shortcut_label_(NULL),
3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      candidate_label_(NULL),
3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      annotation_label_(NULL),
3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      infolist_icon_(NULL),
3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      infolist_icon_enabled_(false) {
3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void CandidateView::Init(int shortcut_column_width,
3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         int candidate_column_width,
3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         int annotation_column_width,
3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         int column_height) {
3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  views::GridLayout* layout = new views::GridLayout(this);
3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SetLayoutManager(layout);  // |this| owns |layout|.
3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Create Labels.
3577dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  const ui::NativeTheme& theme = *GetNativeTheme();
3587dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  shortcut_label_ = CreateShortcutLabel(orientation_, theme);
3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  views::View* wrapped_shortcut_label =
3607dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      CreateWrappedShortcutLabel(shortcut_label_, orientation_, theme);
3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  candidate_label_ = CreateCandidateLabel(orientation_);
3627dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  annotation_label_ = CreateAnnotationLabel(orientation_, theme);
3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Initialize the column set with three columns.
3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  views::ColumnSet* column_set = layout->AddColumnSet(0);
3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If orientation is vertical, each column width is fixed.
3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Otherwise the width is resizable.
3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const views::GridLayout::SizeType column_type =
3702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      orientation_ == IBusLookupTable::VERTICAL ?
3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          views::GridLayout::FIXED : views::GridLayout::USE_PREF;
3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const int padding_column_width =
3742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      orientation_ == IBusLookupTable::VERTICAL ? 4 : 6;
3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Set shortcut column type and width.
3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  column_set->AddColumn(views::GridLayout::FILL, views::GridLayout::FILL,
3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        0, column_type, shortcut_column_width, 0);
3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  column_set->AddPaddingColumn(0, padding_column_width);
3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Set candidate column type and width.
3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  column_set->AddColumn(views::GridLayout::FILL, views::GridLayout::FILL,
3832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                        1, views::GridLayout::USE_PREF, 0,
3842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                        orientation_ == IBusLookupTable::VERTICAL ?
3852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                        candidate_column_width : 0);
3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  column_set->AddPaddingColumn(0, padding_column_width);
3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Set annotation column type and width.
3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  column_set->AddColumn(views::GridLayout::FILL, views::GridLayout::FILL,
3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        0, column_type, annotation_column_width, 0);
3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (orientation_ == IBusLookupTable::VERTICAL) {
3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    column_set->AddPaddingColumn(0, 1);
3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    column_set->AddColumn(views::GridLayout::FILL, views::GridLayout::FILL, 0,
3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                          views::GridLayout::FIXED, kInfolistIndicatorIconWidth,
3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                          0);
3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    column_set->AddPaddingColumn(0, 2);
3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    column_set->AddPaddingColumn(0, padding_column_width);
4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Add the shortcut label, the candidate label, and annotation label.
4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  layout->StartRow(0, 0);
4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // |wrapped_shortcut_label|, |candidate_label_|, and |annotation_label_|
4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // will be owned by |this|.
4065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  layout->AddView(wrapped_shortcut_label,
4075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  1,  // Column span.
4085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  1,  // Row span.
4095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  views::GridLayout::FILL,  // Horizontal alignment.
4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  views::GridLayout::FILL,  // Vertical alignment.
4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  -1,  // Preferred width, not specified.
4125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  column_height);  // Preferred height.
4135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  layout->AddView(candidate_label_,
4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  1,  // Column span.
4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  1,  // Row span.
4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  views::GridLayout::FILL,  // Horizontal alignment.
4175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  views::GridLayout::FILL,  // Vertical alignment.
4185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  -1,  // Preferred width, not specified.
4195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  column_height);  // Preferred height.
4205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  layout->AddView(annotation_label_,
4215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  1,  // Column span.
4225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  1,  // Row span.
4235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  views::GridLayout::FILL,  // Horizontal alignment.
4245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  views::GridLayout::FILL,  // Vertical alignemnt.
4255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  -1,  // Preferred width, not specified.
4265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  column_height);  // Preferred height.
4272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (orientation_ == IBusLookupTable::VERTICAL) {
4285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    infolist_icon_ = new views::View;
4295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    views::View* infolist_icon_wrapper = new views::View;
4305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    views::GridLayout* infolist_icon_layout =
4315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        new views::GridLayout(infolist_icon_wrapper);
4325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // |infolist_icon_layout| is owned by |infolist_icon_wrapper|.
4335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    infolist_icon_wrapper->SetLayoutManager(infolist_icon_layout);
4345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    infolist_icon_layout->AddColumnSet(0)->AddColumn(
4355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        views::GridLayout::FILL, views::GridLayout::FILL,
4365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        0, views::GridLayout::FIXED, kInfolistIndicatorIconWidth, 0);
4375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    infolist_icon_layout->AddPaddingRow(0, kInfolistIndicatorIconPadding);
4385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    infolist_icon_layout->StartRow(1.0, 0);  // infolist_icon_ is resizable.
4395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // |infolist_icon_| is owned by |infolist_icon_wrapper|.
4405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    infolist_icon_layout->AddView(infolist_icon_);
4415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    infolist_icon_layout->AddPaddingRow(0, kInfolistIndicatorIconPadding);
4425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // |infolist_icon_wrapper| is owned by |this|.
4435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    layout->AddView(infolist_icon_wrapper);
4445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UpdateLabelBackgroundColors();
4465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void CandidateView::SetCandidateText(const string16& text) {
4495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  candidate_label_->SetText(text);
4505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void CandidateView::SetShortcutText(const string16& text) {
4535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  shortcut_label_->SetText(text);
4545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void CandidateView::SetAnnotationText(const string16& text) {
4575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  annotation_label_->SetText(text);
4585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void CandidateView::SetInfolistIcon(bool enable) {
4615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!infolist_icon_ || (infolist_icon_enabled_ == enable))
4625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
4635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  infolist_icon_enabled_ = enable;
4647dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  infolist_icon_->set_background(
4657dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      enable ?
4667dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      views::Background::CreateSolidBackground(GetNativeTheme()->GetSystemColor(
4677dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch          ui::NativeTheme::kColorId_FocusedBorderColor)) :
4687dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      NULL);
4695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UpdateLabelBackgroundColors();
4705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SchedulePaint();
4715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void CandidateView::Select() {
4745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  set_background(
4757dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      views::Background::CreateSolidBackground(GetNativeTheme()->GetSystemColor(
4767dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch          ui::NativeTheme::kColorId_TextfieldSelectionBackgroundFocused)));
4777dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  set_border(views::Border::CreateSolidBorder(
4787dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      1, GetNativeTheme()->GetSystemColor(
4797dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch          ui::NativeTheme::kColorId_FocusedBorderColor)));
4805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UpdateLabelBackgroundColors();
4815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Need to call SchedulePaint() for background and border color changes.
4825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SchedulePaint();
4835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void CandidateView::Unselect() {
4865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  set_background(NULL);
4875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  set_border(NULL);
4885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UpdateLabelBackgroundColors();
4895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SchedulePaint();  // See comments at Select().
4905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void CandidateView::SetRowEnabled(bool enabled) {
4935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  shortcut_label_->SetEnabled(enabled);
4945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)gfx::Point CandidateView::GetCandidateLabelPosition() const {
4975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return candidate_label_->GetMirroredPosition();
4985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool CandidateView::OnMousePressed(const ui::MouseEvent& event) {
5012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // TODO(kinaba): On Windows and MacOS, candidate windows typically commits a
5022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // candidate at OnMouseReleased event. We have chosen OnMousePressed here for
5032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // working around several obstacle rising from views implementation over GTK.
5042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // See: http://crosbug.com/11423#c11. Since we have moved from GTK to Aura,
5052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // the reasoning should have became obsolete. We might want to reconsider
5062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // implementing mouse-up selection.
5072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  SelectCandidateAt(event.location());
5082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return false;
5092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
5105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void CandidateView::OnGestureEvent(ui::GestureEvent* event) {
5122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (event->type() == ui::ET_GESTURE_TAP) {
5132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    SelectCandidateAt(event->location());
5142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    event->SetHandled();
5152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
5162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
5172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  View::OnGestureEvent(event);
5182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
5192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void CandidateView::SelectCandidateAt(const gfx::Point& location) {
5212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  gfx::Point location_in_candidate_window = location;
5225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  views::View::ConvertPointToTarget(this, parent_candidate_window_,
5235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                    &location_in_candidate_window);
5245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  parent_candidate_window_->OnCandidatePressed(location_in_candidate_window);
5255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  parent_candidate_window_->CommitCandidate();
5265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void CandidateView::UpdateLabelBackgroundColors() {
5295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SkColor color = background() ?
5307dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      background()->get_color() :
5317dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      GetNativeTheme()->GetSystemColor(
5327dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch          ui::NativeTheme::kColorId_WindowBackground);
5332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (orientation_ != IBusLookupTable::VERTICAL)
5345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    shortcut_label_->SetBackgroundColor(color);
5355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  candidate_label_->SetBackgroundColor(color);
5365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  annotation_label_->SetBackgroundColor(color);
5375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)CandidateWindowView::CandidateWindowView(views::Widget* parent_frame)
540c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    : selected_candidate_index_in_page_(-1),
5415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      parent_frame_(parent_frame),
5425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      preedit_area_(NULL),
5435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      header_area_(NULL),
5445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      candidate_area_(NULL),
5455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      footer_area_(NULL),
5465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      previous_shortcut_column_size_(0, 0),
5475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      previous_candidate_column_size_(0, 0),
5485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      previous_annotation_column_size_(0, 0),
5495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      should_show_at_composition_head_(false),
5505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      should_show_upper_side_(false),
5515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      was_candidate_window_open_(false) {
5525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)CandidateWindowView::~CandidateWindowView() {
5555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void CandidateWindowView::Init() {
5585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Set the background and the border of the view.
5595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  set_background(
5607dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      views::Background::CreateSolidBackground(GetNativeTheme()->GetSystemColor(
5617dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch          ui::NativeTheme::kColorId_WindowBackground)));
5627dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  set_border(views::Border::CreateSolidBorder(
5637dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      1, GetNativeTheme()->GetSystemColor(
5647dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch          ui::NativeTheme::kColorId_MenuBorderColor)));
5655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Create areas.
5675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  preedit_area_ = new InformationTextArea(gfx::ALIGN_LEFT,
5685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                          kMinPreeditAreaWidth);
5695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  header_area_ = new InformationTextArea(gfx::ALIGN_LEFT, 0);
5705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  candidate_area_ = new HidableArea;
5715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  candidate_area_->SetContents(new views::View);
5725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  footer_area_ = new InformationTextArea(gfx::ALIGN_RIGHT, 0);
5735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Set the window layout of the view
5755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  views::GridLayout* layout = new views::GridLayout(this);
5765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SetLayoutManager(layout);  // |this| owns |layout|.
5775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  views::ColumnSet* column_set = layout->AddColumnSet(0);
5785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  column_set->AddColumn(views::GridLayout::FILL, views::GridLayout::FILL,
5795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        0, views::GridLayout::USE_PREF, 0, 0);
5805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Add the preedit area
5825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  layout->StartRow(0, 0);
5835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  layout->AddView(preedit_area_);  // |preedit_area_| is owned by |this|.
5845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Add the header area.
5865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  layout->StartRow(0, 0);
5875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  layout->AddView(header_area_);  // |header_area_| is owned by |this|.
5885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Add the candidate area.
5905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  layout->StartRow(0, 0);
5915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  layout->AddView(candidate_area_);  // |candidate_area_| is owned by |this|.
5925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Add the footer area.
5945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  layout->StartRow(0, 0);
5955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  layout->AddView(footer_area_);  // |footer_area_| is owned by |this|.
5965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void CandidateWindowView::HideAll() {
5995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  parent_frame_->Hide();
6005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  NotifyIfCandidateWindowOpenedOrClosed();
6015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void CandidateWindowView::UpdateParentArea() {
6045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (candidate_area_->IsShown() ||
6055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      header_area_->IsShown() ||
6065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      footer_area_->IsShown() ||
6075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      preedit_area_->IsShown()) {
6085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ResizeAndMoveParentFrame();
6095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    parent_frame_->Show();
6105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
6115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    parent_frame_->Hide();
6125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  NotifyIfCandidateWindowOpenedOrClosed();
6145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void CandidateWindowView::HideLookupTable() {
6175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  candidate_area_->Hide();
6185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UpdateParentArea();
6195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void CandidateWindowView::HideAuxiliaryText() {
6225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  header_area_->Hide();
6235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  footer_area_->Hide();
6245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UpdateParentArea();
6255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void CandidateWindowView::ShowAuxiliaryText() {
6285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If candidate_area is not shown, shows auxiliary text at header_area.
6295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We expect both header_area_ and footer_area_ contain same value.
6305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!candidate_area_->IsShown()) {
6315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    header_area_->Show();
6325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    footer_area_->Hide();
6335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
6345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // If candidate_area is shown, shows auxiliary text with orientation.
6352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (lookup_table_.orientation() == IBusLookupTable::HORIZONTAL) {
6365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      header_area_->Show();
6375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      footer_area_->Hide();
6385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
6395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      footer_area_->Show();
6405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      header_area_->Hide();
6415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
6425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UpdateParentArea();
6445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void CandidateWindowView::UpdateAuxiliaryText(const std::string& utf8_text) {
6475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  header_area_->SetText(utf8_text);
6485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  footer_area_->SetText(utf8_text);
6495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ShowAuxiliaryText();
6505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void CandidateWindowView::HidePreeditText() {
6535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  preedit_area_->Hide();
6545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UpdateParentArea();
6555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void CandidateWindowView::ShowPreeditText() {
6585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  preedit_area_->Show();
6595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UpdateParentArea();
6605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void CandidateWindowView::UpdatePreeditText(const std::string& utf8_text) {
6635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  preedit_area_->SetText(utf8_text);
6645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void CandidateWindowView::ShowLookupTable() {
6675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!candidate_area_->IsShown())
6685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    should_show_upper_side_ = false;
6695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  candidate_area_->Show();
6705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UpdateParentArea();
6715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void CandidateWindowView::NotifyIfCandidateWindowOpenedOrClosed() {
6745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool is_open = IsCandidateWindowOpen();
6755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!was_candidate_window_open_ && is_open) {
6765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    FOR_EACH_OBSERVER(Observer, observers_, OnCandidateWindowOpened());
6775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else if (was_candidate_window_open_ && !is_open) {
6785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    FOR_EACH_OBSERVER(Observer, observers_, OnCandidateWindowClosed());
6795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  was_candidate_window_open_ = is_open;
6815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool CandidateWindowView::ShouldUpdateCandidateViews(
6842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const IBusLookupTable& old_table,
6852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const IBusLookupTable& new_table) {
6862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return !old_table.IsEqual(new_table);
6875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void CandidateWindowView::UpdateCandidates(
6902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const IBusLookupTable& new_lookup_table) {
6915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const bool should_update = ShouldUpdateCandidateViews(lookup_table_,
6925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                        new_lookup_table);
6935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Updating the candidate views is expensive. We'll skip this if possible.
6945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (should_update) {
6955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Initialize candidate views if necessary.
6965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    MaybeInitializeCandidateViews(new_lookup_table);
6975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    should_show_at_composition_head_
6992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        = new_lookup_table.show_window_at_composition();
7005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Compute the index of the current page.
7015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const int current_page_index = ComputePageIndex(new_lookup_table);
7025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (current_page_index < 0) {
7035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return;
7045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
7055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Update the candidates in the current page.
7072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const size_t start_from = current_page_index * new_lookup_table.page_size();
7085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // In some cases, engines send empty shortcut labels. For instance,
7105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // ibus-mozc sends empty labels when they show suggestions. In this
7115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // case, we should not show shortcut labels.
7122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    bool no_shortcut_mode = true;
7132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    for (size_t i = 0; i < new_lookup_table.candidates().size(); ++i) {
7142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if (!new_lookup_table.candidates()[i].label.empty()) {
7152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        no_shortcut_mode = false;
7162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        break;
7172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      }
7182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
7192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
7205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for (size_t i = 0; i < candidate_views_.size(); ++i) {
7215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      const size_t index_in_page = i;
7225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      const size_t candidate_index = start_from + index_in_page;
7235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      CandidateView* candidate_view = candidate_views_[index_in_page];
7245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Set the shortcut text.
7255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (no_shortcut_mode) {
7265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        candidate_view->SetShortcutText(string16());
7275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      } else {
7285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // At this moment, we don't use labels sent from engines for UX
7295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // reasons. First, we want to show shortcut labels in empty rows
7305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // (ex. show 6, 7, 8, ... in empty rows when the number of
7315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // candidates is 5). Second, we want to add a period after each
7325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // shortcut label when the candidate window is horizontal.
7335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        candidate_view->SetShortcutText(
7345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            CreateShortcutText(i, new_lookup_table));
7355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
7365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Set the candidate text.
7372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)       if (candidate_index < new_lookup_table.candidates().size()) {
7382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)         const IBusLookupTable::Entry& entry =
7392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)             new_lookup_table.candidates()[candidate_index];
7402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)         candidate_view->SetCandidateText(UTF8ToUTF16(entry.value));
7412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)         candidate_view->SetAnnotationText(UTF8ToUTF16(entry.annotation));
7422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)         candidate_view->SetRowEnabled(true);
7432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)         candidate_view->SetInfolistIcon(!entry.description_title.empty());
7445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      } else {
7455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // Disable the empty row.
7465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        candidate_view->SetCandidateText(string16());
7475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        candidate_view->SetAnnotationText(string16());
7485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        candidate_view->SetRowEnabled(false);
7495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        candidate_view->SetInfolistIcon(false);
7505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
7515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
7525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
7535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Update the current lookup table. We'll use lookup_table_ from here.
7545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Note that SelectCandidateAt() uses lookup_table_.
7552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  lookup_table_.CopyFrom(new_lookup_table);
7565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Select the current candidate in the page.
758c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (lookup_table_.is_cursor_visible()) {
759c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if (lookup_table_.page_size()) {
760c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      const int current_candidate_in_page =
761c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          lookup_table_.cursor_position() % lookup_table_.page_size();
762c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      SelectCandidateAt(current_candidate_in_page);
763c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    }
764c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  } else {
765c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // Unselect the currently selected candidate.
766c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if (0 <= selected_candidate_index_in_page_ &&
767c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        static_cast<size_t>(selected_candidate_index_in_page_) <
768c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        candidate_views_.size()) {
769c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      candidate_views_[selected_candidate_index_in_page_]->Unselect();
770c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      selected_candidate_index_in_page_ = -1;
771c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    }
772c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
7735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void CandidateWindowView::MaybeInitializeCandidateViews(
7762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const IBusLookupTable& lookup_table) {
7772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  const IBusLookupTable::Orientation orientation =
7782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      lookup_table.orientation();
7792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  const int page_size = lookup_table.page_size();
7805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  views::View* candidate_area_contents = candidate_area_->contents();
7815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Current column width.
7835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gfx::Size shortcut_column_size(0, 0);
7845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gfx::Size candidate_column_size(0,0);
7855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gfx::Size annotation_column_size(0, 0);
7865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If orientation is horizontal, don't need to compute width,
7885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // because each label is left aligned.
7892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (orientation == IBusLookupTable::VERTICAL) {
7907dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    const ui::NativeTheme& theme = *GetNativeTheme();
7917dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    shortcut_column_size = ComputeShortcutColumnSize(lookup_table, theme);
7925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    candidate_column_size = ComputeCandidateColumnSize(lookup_table);
7937dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    annotation_column_size = ComputeAnnotationColumnSize(lookup_table, theme);
7945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
7955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If the requested number of views matches the number of current views, and
7975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // previous and current column width are same, just reuse these.
7985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //
7995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Note that the early exit logic is not only useful for improving
8005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // performance, but also necessary for the horizontal candidate window
8015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // to be redrawn properly. If we get rid of the logic, the horizontal
8025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // candidate window won't get redrawn properly for some reason when
8035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // there is no size change. You can test this by removing "return" here
8045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // and type "ni" with Pinyin input method.
8055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (static_cast<int>(candidate_views_.size()) == page_size &&
8062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      lookup_table_.orientation() == orientation &&
8075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      previous_shortcut_column_size_ == shortcut_column_size &&
8085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      previous_candidate_column_size_ == candidate_column_size &&
8095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      previous_annotation_column_size_ == annotation_column_size) {
8105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
8115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
8125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Update the previous column widths.
8145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  previous_shortcut_column_size_ = shortcut_column_size;
8155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  previous_candidate_column_size_ = candidate_column_size;
8165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  previous_annotation_column_size_ = annotation_column_size;
8175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Clear the existing candidate_views if any.
8195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < candidate_views_.size(); ++i) {
8205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    candidate_area_contents->RemoveChildView(candidate_views_[i]);
8215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Delete the view after getting out the current message loop iteration.
82290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    base::MessageLoop::current()->DeleteSoon(FROM_HERE, candidate_views_[i]);
8235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
8245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  candidate_views_.clear();
8252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  selected_candidate_index_in_page_ = -1;  // Invalidates the index.
8265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  views::GridLayout* layout = new views::GridLayout(candidate_area_contents);
8285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // |candidate_area_contents| owns |layout|.
8295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  candidate_area_contents->SetLayoutManager(layout);
8305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Initialize the column set.
8315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  views::ColumnSet* column_set = layout->AddColumnSet(0);
8322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (orientation == IBusLookupTable::VERTICAL) {
8335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    column_set->AddColumn(views::GridLayout::FILL,
8345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                          views::GridLayout::FILL,
8352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                          1, views::GridLayout::USE_PREF, 0, 0);
8365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
8375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for (int i = 0; i < page_size; ++i) {
8385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      column_set->AddColumn(views::GridLayout::FILL,
8395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            views::GridLayout::FILL,
8405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            0, views::GridLayout::USE_PREF, 0, 0);
8415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
8425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
8435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Set insets so the border of the selected candidate is drawn inside of
8455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // the border of the main candidate window, but we don't have the inset
8465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // at the top and the bottom as we have the borders of the header and
8475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // footer areas.
8485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const gfx::Insets kCandidateAreaInsets(0, 1, 0, 1);
8495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  layout->SetInsets(kCandidateAreaInsets.top(),
8505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    kCandidateAreaInsets.left(),
8515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    kCandidateAreaInsets.bottom(),
8525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    kCandidateAreaInsets.right());
8535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Use maximum height for all rows in candidate area.
8555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const int kColumnHeight = std::max(shortcut_column_size.height(),
8565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                     std::max(candidate_column_size.height(),
8575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                              annotation_column_size.height()));
8585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Add views to the candidate area.
8602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (orientation == IBusLookupTable::HORIZONTAL) {
8615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    layout->StartRow(0, 0);
8625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
8635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (int i = 0; i < page_size; ++i) {
8655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    CandidateView* candidate_row = new CandidateView(this, i, orientation);
8665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    candidate_row->Init(shortcut_column_size.width(),
8675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        candidate_column_size.width(),
8685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        annotation_column_size.width(),
8695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        kColumnHeight);
8705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    candidate_views_.push_back(candidate_row);
8712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (orientation == IBusLookupTable::VERTICAL) {
8725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      layout->StartRow(0, 0);
8735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
8745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // |candidate_row| will be owned by |candidate_area_contents|.
8755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    layout->AddView(candidate_row,
8765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    1,  // Column span.
8775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    1,  // Row span.
8782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                    // Horizontal alignment.
8792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                    orientation == IBusLookupTable::VERTICAL ?
8802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                    views::GridLayout::FILL : views::GridLayout::CENTER,
8815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    views::GridLayout::CENTER,  // Vertical alignment.
8825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    -1,  // Preferred width, not specified.
8835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    kColumnHeight);  // Preferred height.
8845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
8855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Compute views size in |layout|.
8875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If we don't call this function, GetHorizontalOffset() often
8885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // returns invalid value (returns 0), then candidate window
8895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // moves right from the correct position in ResizeAndMoveParentFrame().
8905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TODO(nhiroki): Figure out why it returns invalid value.
8915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // It seems that the x-position of the candidate labels is not set.
8925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  layout->Layout(candidate_area_contents);
8935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
8945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool CandidateWindowView::IsCandidateWindowOpen() const {
8965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return !should_show_at_composition_head_ &&
8975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      candidate_area_->visible() && candidate_area_->IsShown();
8985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
8995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void CandidateWindowView::SelectCandidateAt(int index_in_page) {
9015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const int current_page_index = ComputePageIndex(lookup_table_);
9025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (current_page_index < 0) {
9035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
9045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
9055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const int cursor_absolute_index =
9072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      lookup_table_.page_size() * current_page_index + index_in_page;
9085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Ignore click on out of range views.
9095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (cursor_absolute_index < 0 ||
9102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      lookup_table_.candidates().size() <=
9112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      static_cast<size_t>(cursor_absolute_index)) {
9125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
9135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
9145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Unselect the currently selected candidate.
9162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (0 <= selected_candidate_index_in_page_ &&
9172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      static_cast<size_t>(selected_candidate_index_in_page_) <
9182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      candidate_views_.size()) {
9192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    candidate_views_[selected_candidate_index_in_page_]->Unselect();
9202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
9215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Remember the currently selected candidate index in the current page.
9225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  selected_candidate_index_in_page_ = index_in_page;
9235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Select the candidate specified by index_in_page.
9255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  candidate_views_[index_in_page]->Select();
9265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Update the cursor indexes in the model.
9282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  lookup_table_.set_cursor_position(cursor_absolute_index);
9295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void CandidateWindowView::OnCandidatePressed(
9325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const gfx::Point& location) {
9335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < candidate_views_.size(); ++i) {
9345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    gfx::Point converted_location = location;
9355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    views::View::ConvertPointToTarget(this, candidate_views_[i],
9365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                      &converted_location);
9375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (candidate_views_[i]->HitTestPoint(converted_location)) {
9385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      SelectCandidateAt(i);
9395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
9405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
9415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
9425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void CandidateWindowView::CommitCandidate() {
945c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (!(0 <= selected_candidate_index_in_page_ &&
946c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        static_cast<size_t>(selected_candidate_index_in_page_) <
947c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        candidate_views_.size())) {
948c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return;  // Out of range, do nothing.
949c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
950c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
9515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // For now, we don't distinguish left and right clicks.
9525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const int button = 1;  // Left button.
9535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const int key_modifilers = 0;
9545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  FOR_EACH_OBSERVER(Observer, observers_,
9555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    OnCandidateCommitted(selected_candidate_index_in_page_,
9565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                         button,
9575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                         key_modifilers));
9585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void CandidateWindowView::ResizeAndMoveParentFrame() {
9615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If rendering operation comes from mozc-engine, uses mozc specific location,
9625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // otherwise lookup table is shown under the cursor.
9635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const int x = should_show_at_composition_head_?
9645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      composition_head_location_.x() : cursor_location_.x();
9655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // To avoid lookup-table overlapping, uses maximum y-position of mozc specific
9665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // location and cursor location, because mozc-engine does not consider about
9675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // multi-line composition.
9685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const int y = should_show_at_composition_head_?
9695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      std::max(composition_head_location_.y(), cursor_location_.y()) :
9705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      cursor_location_.y();
9715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const int height = cursor_location_.height();
9725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const int horizontal_offset = GetHorizontalOffset();
9735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gfx::Rect old_bounds = parent_frame_->GetClientAreaBoundsInScreen();
9755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gfx::Rect screen_bounds = ash::Shell::GetScreen()->GetDisplayMatching(
9765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      cursor_location_).work_area();
9775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The size.
9785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gfx::Rect frame_bounds = old_bounds;
9795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  frame_bounds.set_size(GetPreferredSize());
9805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The default position.
9825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  frame_bounds.set_x(x + horizontal_offset);
9835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  frame_bounds.set_y(y + height);
9845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Handle overflow at the left and the top.
9865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  frame_bounds.set_x(std::max(frame_bounds.x(), screen_bounds.x()));
9875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  frame_bounds.set_y(std::max(frame_bounds.y(), screen_bounds.y()));
9885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Handle overflow at the right.
9905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const int right_overflow = frame_bounds.right() - screen_bounds.right();
9915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (right_overflow > 0) {
9925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    frame_bounds.set_x(frame_bounds.x() - right_overflow);
9935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
9945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Handle overflow at the bottom.
9965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const int bottom_overflow = frame_bounds.bottom() - screen_bounds.bottom();
9975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // To avoid flickering window position, the candidate window should be shown
9995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // on upper side of composition string if it was shown there.
10005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (should_show_upper_side_ || bottom_overflow > 0) {
10015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    frame_bounds.set_y(frame_bounds.y() - height - frame_bounds.height());
10025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    should_show_upper_side_ = true;
10035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
10045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TODO(nona): check top_overflow here.
10065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Move the window per the cursor location.
10085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // SetBounds() is not cheap. Only call this when it is really changed.
10095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (frame_bounds != old_bounds)
10105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    parent_frame_->SetBounds(frame_bounds);
10115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
10125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int CandidateWindowView::GetHorizontalOffset() {
10145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Compute the horizontal offset if the lookup table is vertical.
10155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!candidate_views_.empty() &&
10162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      lookup_table_.orientation() == IBusLookupTable::VERTICAL) {
10175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return - candidate_views_[0]->GetCandidateLabelPosition().x();
10185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
10195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return 0;
10205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
10215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void CandidateWindowView::VisibilityChanged(View* starting_from,
10235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                            bool is_visible) {
10245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (is_visible) {
10255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // If the visibility of candidate window is changed,
10265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // we should move the frame to the right position.
10275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ResizeAndMoveParentFrame();
10285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
10295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
10305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void CandidateWindowView::OnBoundsChanged(const gfx::Rect& previous_bounds) {
10325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If the bounds(size) of candidate window is changed,
10335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // we should move the frame to the right position.
10345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  View::OnBoundsChanged(previous_bounds);
10355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ResizeAndMoveParentFrame();
10365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
10375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace input_method
10395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace chromeos
1040