172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen// Copyright (c) 2011 The Chromium Authors. All rights reserved. 2c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Use of this source code is governed by a BSD-style license that can be 3c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// found in the LICENSE file. 44a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch 54a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch#include "chrome/browser/chromeos/input_method/candidate_window.h" 6c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 7c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include <algorithm> 8c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include <string> 9c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include <vector> 10c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 11c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/logging.h" 12ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "base/memory/scoped_ptr.h" 13c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/observer_list.h" 143345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "base/string_util.h" 153345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "base/stringprintf.h" 16c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/utf_string_conversions.h" 1721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#include "third_party/cros/chromeos_input_method_ui.h" 1872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "ui/gfx/canvas.h" 1972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "ui/gfx/font.h" 20c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "views/controls/label.h" 21c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "views/controls/textfield/textfield.h" 2272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "views/events/event.h" 2372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "views/layout/fill_layout.h" 2472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "views/layout/grid_layout.h" 25c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "views/screen.h" 26c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "views/widget/root_view.h" 27c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "views/widget/widget.h" 28c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "views/widget/widget_gtk.h" 29c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "views/window/non_client_view.h" 30c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "views/window/window.h" 31c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "views/window/window_delegate.h" 32c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 33c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochnamespace { 34c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 35c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Colors used in the candidate window UI. 36c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst SkColor kFrameColor = SkColorSetRGB(0x96, 0x96, 0x96); 37c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst SkColor kShortcutBackgroundColor = SkColorSetARGB(0x10, 0x3, 0x4, 0xf); 38c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst SkColor kSelectedRowBackgroundColor = SkColorSetRGB(0xd1, 0xea, 0xff); 39c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst SkColor kDefaultBackgroundColor = SkColorSetRGB(0xff, 0xff, 0xff); 40c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst SkColor kSelectedRowFrameColor = SkColorSetRGB(0x7f, 0xac, 0xdd); 41c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst SkColor kFooterTopColor = SkColorSetRGB(0xff, 0xff, 0xff); 42c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst SkColor kFooterBottomColor = SkColorSetRGB(0xee, 0xee, 0xee); 43c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst SkColor kShortcutColor = SkColorSetRGB(0x61, 0x61, 0x61); 44c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst SkColor kDisabledShortcutColor = SkColorSetRGB(0xcc, 0xcc, 0xcc); 453345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickconst SkColor kAnnotationColor = SkColorSetRGB(0x88, 0x88, 0x88); 463345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 473345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick// We'll use a bigger font size, so Chinese characters are more readable 483345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick// in the candidate window. 49201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch#if defined(CROS_FONTS_USING_BCI) 50201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdochconst int kFontSizeDelta = 1; 51201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch#else 52201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdochconst int kFontSizeDelta = 2; 53201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch#endif 54c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 55c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// The minimum width of candidate labels in the vertical candidate 56c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// window. We use this value to prevent the candidate window from being 57c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// too narrow when all candidates are short. 58c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst int kMinCandidateLabelWidth = 100; 59c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// The maximum width of candidate labels in the vertical candidate 60c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// window. We use this value to prevent the candidate window from being 61c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// too wide when one of candidates are long. 62c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst int kMaxCandidateLabelWidth = 500; 63c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 643345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick// VerticalCandidateLabel is used for rendering candidate text in 653345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick// the vertical candidate window. 663345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickclass VerticalCandidateLabel : public views::Label { 673345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick virtual ~VerticalCandidateLabel() {} 683345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 693345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // Returns the preferred size, but guarantees that the width has at 703345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // least kMinCandidateLabelWidth pixels. 713345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick virtual gfx::Size GetPreferredSize() { 723345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick gfx::Size size = Label::GetPreferredSize(); 733345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // Hack. +2 is needed to prevent labels from getting elided like 743345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // "abc..." in some cases. TODO(satorux): Figure out why it's 753345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // necessary. 763345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick size.set_width(size.width() + 2); 773345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick if (size.width() < kMinCandidateLabelWidth) { 783345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick size.set_width(kMinCandidateLabelWidth); 793345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick } 803345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick if (size.width() > kMaxCandidateLabelWidth) { 813345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick size.set_width(kMaxCandidateLabelWidth); 823345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick } 833345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick return size; 843345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick } 853345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}; 863345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 87c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Wraps the given view with some padding, and returns it. 88c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochviews::View* WrapWithPadding(views::View* view, const gfx::Insets& insets) { 89c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch views::View* wrapper = new views::View; 90c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Use GridLayout to give some insets inside. 91c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch views::GridLayout* layout = new views::GridLayout(wrapper); 92c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch wrapper->SetLayoutManager(layout); // |wrapper| owns |layout|. 93c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch layout->SetInsets(insets); 94c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 95c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch views::ColumnSet* column_set = layout->AddColumnSet(0); 96c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch column_set->AddColumn( 97c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch views::GridLayout::FILL, views::GridLayout::FILL, 98c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1, views::GridLayout::USE_PREF, 0, 0); 99c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch layout->StartRow(0, 0); 100c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 101c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Add the view contents. 102c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch layout->AddView(view); // |view| is owned by |wraper|, not |layout|. 103c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return wrapper; 104c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 105c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1063345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick// Creates shortcut text from the given index and the orientation. 1073345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickstd::wstring CreateShortcutText(int index, 1083345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick chromeos::InputMethodLookupTable::Orientation orientation) { 1093345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // Choose the character used for the shortcut label. 1103345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick const wchar_t kShortcutCharacters[] = L"1234567890ABCDEF"; 1113345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // The default character should not be used but just in case. 1123345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick wchar_t shortcut_character = L'?'; 1133345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // -1 to exclude the null character at the end. 1143345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick if (index < static_cast<int>(arraysize(kShortcutCharacters) - 1)) { 1153345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick shortcut_character = kShortcutCharacters[index]; 1163345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick } 1173345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 1183345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick std::wstring shortcut_text; 1193345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick if (orientation == chromeos::InputMethodLookupTable::kVertical) { 1203345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick shortcut_text = base::StringPrintf(L"%lc", shortcut_character); 1213345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick } else { 1223345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick shortcut_text = base::StringPrintf(L"%lc.", shortcut_character); 1233345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick } 1243345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 1253345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick return shortcut_text; 1263345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick} 1273345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 1283345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick// Creates the shortcut label, and returns it (never returns NULL). 1293345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick// The label text is not set in this function. 1303345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickviews::Label* CreateShortcutLabel( 1313345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick chromeos::InputMethodLookupTable::Orientation orientation) { 1323345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // Create the shortcut label. The label will be owned by 1333345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // |wrapped_shortcut_label|, hence it's deleted when 1343345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // |wrapped_shortcut_label| is deleted. 1353345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick views::Label* shortcut_label = new views::Label; 1363345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 1373345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick if (orientation == chromeos::InputMethodLookupTable::kVertical) { 1383345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick shortcut_label->SetFont( 1393345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick shortcut_label->font().DeriveFont(kFontSizeDelta, gfx::Font::BOLD)); 1403345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick } else { 1413345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick shortcut_label->SetFont( 1423345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick shortcut_label->font().DeriveFont(kFontSizeDelta)); 1433345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick } 1443345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // TODO(satorux): Maybe we need to use language specific fonts for 1453345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // candidate_label, like Chinese font for Chinese input method? 1463345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick shortcut_label->SetColor(kShortcutColor); 1473345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 1483345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick return shortcut_label; 1493345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick} 1503345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 1513345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick// Wraps the shortcut label, then decorates wrapped shortcut label 1523345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick// and returns it (never returns NULL). 1533345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick// The label text is not set in this function. 1543345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickviews::View* CreateWrappedShortcutLabel(views::Label* shortcut_label, 1553345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick chromeos::InputMethodLookupTable::Orientation orientation) { 1563345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // Wrap it with padding. 1573345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick const gfx::Insets kVerticalShortcutLabelInsets(1, 6, 1, 6); 1583345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick const gfx::Insets kHorizontalShortcutLabelInsets(1, 3, 1, 0); 1593345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick const gfx::Insets insets = 1603345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick (orientation == chromeos::InputMethodLookupTable::kVertical ? 1613345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick kVerticalShortcutLabelInsets : 1623345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick kHorizontalShortcutLabelInsets); 1633345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick views::View* wrapped_shortcut_label = 1643345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick WrapWithPadding(shortcut_label, insets); 1653345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 1663345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // Add decoration based on the orientation. 1673345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick if (orientation == chromeos::InputMethodLookupTable::kVertical) { 1683345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // Set the background color. 1693345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick wrapped_shortcut_label->set_background( 1703345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick views::Background::CreateSolidBackground( 1713345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick kShortcutBackgroundColor)); 1723345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick } 1733345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 1743345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick return wrapped_shortcut_label; 1753345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick} 1763345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 1773345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick// Creates the candidate label, and returns it (never returns NULL). 1783345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick// The label text is not set in this function. 1793345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickviews::Label* CreateCandidateLabel( 1803345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick chromeos::InputMethodLookupTable::Orientation orientation) { 1813345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick views::Label* candidate_label = NULL; 1823345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 1833345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // Create the candidate label. The label will be added to |this| as a 1843345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // child view, hence it's deleted when |this| is deleted. 1853345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick if (orientation == chromeos::InputMethodLookupTable::kVertical) { 1863345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick candidate_label = new VerticalCandidateLabel; 1873345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick } else { 1883345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick candidate_label = new views::Label; 1893345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick } 1903345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 1913345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // Change the font size. 1923345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick candidate_label->SetFont( 1933345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick candidate_label->font().DeriveFont(kFontSizeDelta)); 1943345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick candidate_label->SetHorizontalAlignment(views::Label::ALIGN_LEFT); 1953345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 1963345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick return candidate_label; 1973345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick} 1983345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 1993345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick// Creates the annotation label, and return it (never returns NULL). 2003345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick// The label text is not set in this function. 2013345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickviews::Label* CreateAnnotationLabel( 2023345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick chromeos::InputMethodLookupTable::Orientation orientation) { 2033345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // Create the annotation label. 2043345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick views::Label* annotation_label = new views::Label; 2053345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 2063345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // Change the font size and color. 2073345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick annotation_label->SetFont( 2083345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick annotation_label->font().DeriveFont(kFontSizeDelta)); 2093345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick annotation_label->SetColor(kAnnotationColor); 2103345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick annotation_label->SetHorizontalAlignment(views::Label::ALIGN_LEFT); 2113345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 2123345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick return annotation_label; 2133345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick} 2143345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 2153345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick// Computes shortcut column width. 2163345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickint ComputeShortcutColumnWidth( 2173345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick const chromeos::InputMethodLookupTable& lookup_table) { 2183345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick int shortcut_column_width = 0; 2193345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // Create the shortcut label. The label will be owned by 2203345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // |wrapped_shortcut_label|, hence it's deleted when 2213345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // |wrapped_shortcut_label| is deleted. 2223345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick views::Label* shortcut_label = CreateShortcutLabel(lookup_table.orientation); 2233345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick scoped_ptr<views::View> wrapped_shortcut_label( 2243345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick CreateWrappedShortcutLabel(shortcut_label, lookup_table.orientation)); 2253345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 2263345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // Compute the max width in shortcut labels. 2273345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // We'll create temporary shortcut labels, and choose the largest width. 2283345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick for (int i = 0; i < lookup_table.page_size; ++i) { 2293345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick shortcut_label->SetText( 2303345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick CreateShortcutText(i, lookup_table.orientation)); 2313345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick shortcut_column_width = 2323345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick std::max(shortcut_column_width, 2333345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick wrapped_shortcut_label->GetPreferredSize().width()); 2343345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick } 2353345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 2363345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick return shortcut_column_width; 2373345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick} 2383345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 23921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen// Computes the page index. For instance, if the page size is 9, and the 24021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen// cursor is pointing to 13th candidate, the page index will be 1 (2nd 24121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen// page, as the index is zero-origin). Returns -1 on error. 24221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsenint ComputePageIndex(const chromeos::InputMethodLookupTable& lookup_table) { 24321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen if (lookup_table.page_size > 0) 24421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen return lookup_table.cursor_absolute_index / lookup_table.page_size; 24521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen return -1; 24621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen} 24721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen 2483345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick// Computes candidate column width. 2493345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickint ComputeCandidateColumnWidth( 2503345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick const chromeos::InputMethodLookupTable& lookup_table) { 2513345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick int candidate_column_width = 0; 2523345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick scoped_ptr<views::Label> candidate_label( 2533345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick CreateCandidateLabel(lookup_table.orientation)); 2543345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 2553345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // Compute the start index of |lookup_table_|. 25621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen const int current_page_index = ComputePageIndex(lookup_table); 25721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen if (current_page_index < 0) 25821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen return 0; 2593345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick const size_t start_from = current_page_index * lookup_table.page_size; 2603345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 2613345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // Compute the max width in candidate labels. 2623345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // We'll create temporary candidate labels, and choose the largest width. 263dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen for (size_t i = 0; i + start_from < lookup_table.candidates.size(); ++i) { 2643345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick const size_t index = start_from + i; 2653345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 2663345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick candidate_label->SetText( 2673345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick UTF8ToWide(lookup_table.candidates[index])); 2683345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick candidate_column_width = 2693345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick std::max(candidate_column_width, 2703345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick candidate_label->GetPreferredSize().width()); 2713345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick } 2723345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 2733345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick return candidate_column_width; 2743345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick} 2753345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 2763345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick// Computes annotation column width. 2773345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickint ComputeAnnotationColumnWidth( 2783345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick const chromeos::InputMethodLookupTable& lookup_table) { 2793345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick int annotation_column_width = 0; 2803345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick scoped_ptr<views::Label> annotation_label( 2813345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick CreateAnnotationLabel(lookup_table.orientation)); 2823345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 2833345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // Compute the start index of |lookup_table_|. 28421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen const int current_page_index = ComputePageIndex(lookup_table); 28521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen if (current_page_index < 0) 28621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen return 0; 2873345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick const size_t start_from = current_page_index * lookup_table.page_size; 2883345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 2893345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // Compute max width in annotation labels. 2903345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // We'll create temporary annotation labels, and choose the largest width. 291dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen for (size_t i = 0; i + start_from < lookup_table.annotations.size(); ++i) { 2923345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick const size_t index = start_from + i; 2933345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 2943345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick annotation_label->SetText( 2953345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick UTF8ToWide(lookup_table.annotations[index])); 2963345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick annotation_column_width = 2973345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick std::max(annotation_column_width, 2983345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick annotation_label->GetPreferredSize().width()); 2993345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick } 3003345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 3013345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick return annotation_column_width; 3023345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick} 3033345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 304c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} // namespace 305c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 306c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochnamespace chromeos { 307c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 308c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochclass CandidateView; 309c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 310c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// CandidateWindowView is the main container of the candidate window UI. 311c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochclass CandidateWindowView : public views::View { 312c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch public: 313c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // The object can be monitored by the observer. 314c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch class Observer { 315c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch public: 316c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch virtual ~Observer() {} 317c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // The function is called when a candidate is committed. 318c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // See comments at NotifyCandidateClicke() in chromeos_input_method_ui.h for 319c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // details about the parameters. 320c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch virtual void OnCandidateCommitted(int index, int button, int flag) = 0; 321c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch }; 322c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 323c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch explicit CandidateWindowView(views::Widget* parent_frame); 324c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch virtual ~CandidateWindowView() {} 325c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch void Init(); 326c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 327c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Adds the given observer. The ownership is not transferred. 328c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch void AddObserver(Observer* observer) { 329c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch observers_.AddObserver(observer); 330c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 331c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 332c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Removes the given observer. 333c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch void RemoveObserver(Observer* observer) { 334c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch observers_.RemoveObserver(observer); 335c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 336c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 337c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Selects the candidate specified by the index in the current page 338c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // (zero-origin). Changes the appearance of the selected candidate, 339c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // updates the information in the candidate window as needed. 340c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch void SelectCandidateAt(int index_in_page); 341c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 342c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // The function is called when a candidate is being dragged. From the 343c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // given point, locates the candidate under the mouse cursor, and 344c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // selects it. 345c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch void OnCandidateDragged(const gfx::Point& point); 346c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 347c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Commits the candidate currently being selected. 348c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch void CommitCandidate(); 349c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 35072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // Hides the lookup table. 35172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen void HideLookupTable(); 35272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 353c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Hides the auxiliary text. 354c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch void HideAuxiliaryText(); 355c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 356c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Shows the auxiliary text. 357c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch void ShowAuxiliaryText(); 358c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 359c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Updates the auxiliary text. 360c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch void UpdateAuxiliaryText(const std::string& utf8_text); 361c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 36221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen // Returns true if we should update candidate views in the window. For 36321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen // instance, if we are going to show the same candidates as before, we 36421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen // don't have to update candidate views. This happens when the user just 36521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen // moves the cursor in the same page in the candidate window. 36621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen bool ShouldUpdateCandidateViews( 36721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen const InputMethodLookupTable& old_table, 36821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen const InputMethodLookupTable& new_table); 36921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen 370c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Updates candidates of the candidate window from |lookup_table|. 371c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Candidates are arranged per |orientation|. 372c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch void UpdateCandidates(const InputMethodLookupTable& lookup_table); 373c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 37421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen // Resizes and moves the parent frame. The two actions should be 37521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen // performed consecutively as resizing may require the candidate window 37621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen // to move. For instance, we may need to move the candidate window from 37721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen // below the cursor to above the cursor, if the candidate window becomes 37821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen // too big to be shown near the bottom of the screen. This function 37921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen // needs to be called when the visible contents of the candidate window 38021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen // are modified. 38121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen void ResizeAndMoveParentFrame(); 38221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen 38321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen // Resizes the parent frame per the current contents size. 38421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen // 38521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen // The function is rarely used solely. See comments at 38621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen // ResizeAndMoveParentFrame(). 38721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen void ResizeParentFrame(); 38821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen 38921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen // Moves the candidate window per the current cursor location, and the 39021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen // horizontal offset. 39121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen // 39221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen // The function is rarely used solely. See comments at 39321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen // ResizeAndMoveParentFrame(). 39421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen void MoveParentFrame(); 395c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 396c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Returns the horizontal offset used for placing the vertical candidate 397c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // window so that the first candidate is aligned with the the text being 398c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // converted like: 399c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // 400c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // XXX <- The user is converting XXX 401c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // +-----+ 402c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // |1 XXX| 403c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // |2 YYY| 404c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // |3 ZZZ| 405c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // 406c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Returns 0 if no candidate is present. 407c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int GetHorizontalOffset(); 408c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 40972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // A function to be called when one of the |candidate_views_| receives a mouse 41072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // press event. 41172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen void OnMousePressed(); 41272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // A function to be called when one of the |candidate_views_| receives a mouse 41372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // release event. 41472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen void OnMouseReleased(); 41572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 41621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen void set_cursor_location(const gfx::Rect& cursor_location) { 41721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen cursor_location_ = cursor_location; 41821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen } 41921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen 42021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen const gfx::Rect& cursor_location() const { return cursor_location_; } 42121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen 42221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen protected: 42321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen // Override View::VisibilityChanged() 424ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen virtual void VisibilityChanged(View* starting_from, bool is_visible) OVERRIDE; 42521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen 426dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen // Override View::OnBoundsChanged() 427ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen virtual void OnBoundsChanged(const gfx::Rect& previous_bounds) OVERRIDE; 42821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen 429c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch private: 430c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Initializes the candidate views if needed. 431c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch void MaybeInitializeCandidateViews( 4323345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick const InputMethodLookupTable& lookup_table); 433c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 434c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Creates the footer area, where we show status information. 435c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // For instance, we show a cursor position like 2/19. 436c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch views::View* CreateFooterArea(); 437c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 438c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Creates the header area, where we show auxiliary text. 439c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch views::View* CreateHeaderArea(); 440c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 441c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // The lookup table (candidates). 442c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch InputMethodLookupTable lookup_table_; 443c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 444c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // The index in the current page of the candidate currently being selected. 445c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int selected_candidate_index_in_page_; 446c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 447c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // The observers of the object. 448c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch ObserverList<Observer> observers_; 449c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 450c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // The parent frame. 451c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch views::Widget* parent_frame_; 452c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 453c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Views created in the class will be part of tree of |this|, so these 454c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // child views will be deleted when |this| is deleted. 455c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 456c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // The candidate area is where candidates are rendered. 457c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch views::View* candidate_area_; 458c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // The footer area is where the auxiliary text is shown, if the 459c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // orientation is vertical. Usually the auxiliary text is used for 460c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // showing candidate number information like 2/19. 461c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch views::View* footer_area_; 462c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // We use this when we show something in the footer area. 463c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch scoped_ptr<views::View> footer_area_contents_; 464c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // We use this when we show nothing in the footer area. 465c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch scoped_ptr<views::View> footer_area_place_holder_; 466c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // The header area is where the auxiliary text is shown, if the 467c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // orientation is horizontal. If the auxiliary text is not provided, we 468c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // show nothing. For instance, we show pinyin text like "zhong'guo". 469c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch views::View* header_area_; 470c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // We use this when we show something in the header area. 471c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch scoped_ptr<views::View> header_area_contents_; 472c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // We use this when we show nothing in the header area. 473c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch scoped_ptr<views::View> header_area_place_holder_; 474c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // The candidate views are used for rendering candidates. 475c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch std::vector<CandidateView*> candidate_views_; 476c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // The header label is shown in the header area. 477c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch views::Label* header_label_; 478c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // The footer label is shown in the footer area. 479c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch views::Label* footer_label_; 4803345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 4813345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // Current columns width in |candidate_area_|. 4823345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick int previous_shortcut_column_width_; 4833345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick int previous_candidate_column_width_; 4843345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick int previous_annotation_column_width_; 48521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen 48621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen // The last cursor location. 48721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen gfx::Rect cursor_location_; 48872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 48972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // true if a mouse button is pressed, and is not yet released. 49072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen bool mouse_is_pressed_; 491c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}; 492c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 493c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// CandidateRow renderes a row of a candidate. 494c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochclass CandidateView : public views::View { 495c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch public: 496c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch CandidateView(CandidateWindowView* parent_candidate_window, 497c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int index_in_page, 498c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch InputMethodLookupTable::Orientation orientation); 499c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch virtual ~CandidateView() {} 5003345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // Initializes the candidate view with the given column widths. 5013345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // A width of 0 means that the column is resizable. 5023345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick void Init(int shortcut_column_width, 5033345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick int candidate_column_width, 5043345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick int annotation_column_width); 505c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 506c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Sets candidate text to the given text. 507c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch void SetCandidateText(const std::wstring& text); 508c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 509c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Sets shortcut text to the given text. 510c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch void SetShortcutText(const std::wstring& text); 511c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 5123345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // Sets annotation text to the given text. 5133345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick void SetAnnotationText(const std::wstring& text); 514c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 515c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Selects the candidate row. Changes the appearance to make it look 516c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // like a selected candidate. 517c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch void Select(); 518c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 519c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Unselects the candidate row. Changes the appearance to make it look 520c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // like an unselected candidate. 521c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch void Unselect(); 522c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 523c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Enables or disables the candidate row based on |enabled|. Changes the 524c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // appearance to make it look like unclickable area. 525c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch void SetRowEnabled(bool enabled); 526c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 527c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Returns the relative position of the candidate label. 528c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch gfx::Point GetCandidateLabelPosition() const; 529c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 530c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch private: 531ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // Overridden from View: 532ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen virtual bool OnMousePressed(const views::MouseEvent& event) OVERRIDE; 533ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen virtual bool OnMouseDragged(const views::MouseEvent& event) OVERRIDE; 534ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen virtual void OnMouseReleased(const views::MouseEvent& event) OVERRIDE; 535ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen virtual void OnMouseCaptureLost() OVERRIDE; 536c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 537c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Zero-origin index in the current page. 538c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int index_in_page_; 539c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 540c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // The orientation of the candidate view. 541c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch InputMethodLookupTable::Orientation orientation_; 542c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 543c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // The parent candidate window that contains this view. 544c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch CandidateWindowView* parent_candidate_window_; 545c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 546c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Views created in the class will be part of tree of |this|, so these 547c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // child views will be deleted when |this| is deleted. 548c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 549c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // The shortcut label renders shortcut numbers like 1, 2, and 3. 550c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch views::Label* shortcut_label_; 551c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // The candidate label renders candidates. 552c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch views::Label* candidate_label_; 5533345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // The annotation label renders annotations. 5543345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick views::Label* annotation_label_; 555c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}; 556c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 5574a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch// The implementation of CandidateWindowController. 558c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// CandidateWindowController controls the CandidateWindow. 5594a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdochclass CandidateWindowController::Impl : public CandidateWindowView::Observer { 560c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch public: 5614a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch Impl(); 5624a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch virtual ~Impl(); 5634a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch 5644a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch // Initializes the candidate window. Returns true on success. 5653345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick bool Init(); 566c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 5674a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch private: 568c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // CandidateWindowView::Observer implementation. 569c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch virtual void OnCandidateCommitted(int index, 570c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int button, 571c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int flags); 572c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 573c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Creates the candidate window view. 574c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch void CreateView(); 575c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 576c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // The function is called when |HideAuxiliaryText| signal is received in 577c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // libcros. |input_method_library| is a void pointer to this object. 578c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch static void OnHideAuxiliaryText(void* input_method_library); 579c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 580c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // The function is called when |HideLookupTable| signal is received in 581c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // libcros. |input_method_library| is a void pointer to this object. 582c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch static void OnHideLookupTable(void* input_method_library); 583c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 584c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // The function is called when |SetCursorLocation| signal is received 585c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // in libcros. |input_method_library| is a void pointer to this object. 586c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch static void OnSetCursorLocation(void* input_method_library, 587c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int x, 588c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int y, 589c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int width, 590c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int height); 591c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 592c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // The function is called when |UpdateAuxiliaryText| signal is received 593c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // in libcros. |input_method_library| is a void pointer to this object. 594c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch static void OnUpdateAuxiliaryText(void* input_method_library, 595c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const std::string& utf8_text, 596c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch bool visible); 597c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 598c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // The function is called when |UpdateLookupTable| signal is received 599c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // in libcros. |input_method_library| is a void pointer to this object. 600c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch static void OnUpdateLookupTable(void* input_method_library, 601c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const InputMethodLookupTable& lookup_table); 602c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 6033345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // This function is called by libcros when ibus connects or disconnects. 6043345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // |input_method_library| is a void pointer to this object. 6053345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick static void OnConnectionChange(void* input_method_library, bool connected); 6063345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 607c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // The connection is used for communicating with input method UI logic 608c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // in libcros. 609c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch InputMethodUiStatusConnection* ui_status_connection_; 610c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 611c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // The candidate window view. 612c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch CandidateWindowView* candidate_window_; 613c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 614c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // This is the outer frame of the candidate window view. The frame will 615c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // own |candidate_window_|. 616c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch scoped_ptr<views::Widget> frame_; 617c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}; 618c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 619c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochCandidateView::CandidateView( 620c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch CandidateWindowView* parent_candidate_window, 621c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int index_in_page, 622c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch InputMethodLookupTable::Orientation orientation) 623c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch : index_in_page_(index_in_page), 624c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch orientation_(orientation), 625c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch parent_candidate_window_(parent_candidate_window), 626c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch shortcut_label_(NULL), 6273345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick candidate_label_(NULL), 6283345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick annotation_label_(NULL) { 629c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 630c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 6313345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickvoid CandidateView::Init(int shortcut_column_width, 6323345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick int candidate_column_width, 6333345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick int annotation_column_width) { 634c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch views::GridLayout* layout = new views::GridLayout(this); 635c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch SetLayoutManager(layout); // |this| owns |layout|. 636c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 6373345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // Create Labels. 6383345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick shortcut_label_ = CreateShortcutLabel(orientation_); 639c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch views::View* wrapped_shortcut_label = 6403345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick CreateWrappedShortcutLabel(shortcut_label_, orientation_); 6413345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick candidate_label_ = CreateCandidateLabel(orientation_); 6423345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick annotation_label_ = CreateAnnotationLabel(orientation_); 643c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 6443345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // Initialize the column set with three columns. 6453345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick views::ColumnSet* column_set = layout->AddColumnSet(0); 646c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 6473345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // If orientation is vertical, each column width is fixed. 6483345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // Otherwise the width is resizable. 6493345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick const views::GridLayout::SizeType column_type = 6503345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick orientation_ == InputMethodLookupTable::kVertical ? 6513345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick views::GridLayout::FIXED : views::GridLayout::USE_PREF; 652c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 6533345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick const int padding_column_width = 6543345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick orientation_ == InputMethodLookupTable::kVertical ? 4 : 6; 655c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 6563345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // Set shortcut column type and width. 657c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch column_set->AddColumn(views::GridLayout::FILL, views::GridLayout::FILL, 6583345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 0, column_type, shortcut_column_width, 0); 6593345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick column_set->AddPaddingColumn(0, padding_column_width); 6603345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 6613345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // Set candidate column type and width. 662c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch column_set->AddColumn(views::GridLayout::FILL, views::GridLayout::FILL, 6633345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 0, column_type, candidate_column_width, 0); 6643345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick column_set->AddPaddingColumn(0, padding_column_width); 665c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 6663345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // Set annotation column type and width. 6673345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick column_set->AddColumn(views::GridLayout::FILL, views::GridLayout::FILL, 6683345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 0, column_type, annotation_column_width, 0); 6693345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick column_set->AddPaddingColumn(0, padding_column_width); 6703345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 6713345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // Add the shortcut label, the candidate label, and annotation label. 672c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch layout->StartRow(0, 0); 6733345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // |wrapped_shortcut_label|, |candidate_label_|, and |annotation_label_| 6743345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // will be owned by |this|. 675c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch layout->AddView(wrapped_shortcut_label); 676c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch layout->AddView(candidate_label_); 6773345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick layout->AddView(annotation_label_); 678c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 679c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 680c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid CandidateView::SetCandidateText(const std::wstring& text) { 681c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch candidate_label_->SetText(text); 682c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 683c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 684c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid CandidateView::SetShortcutText(const std::wstring& text) { 685c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch shortcut_label_->SetText(text); 686c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 687c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 6883345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickvoid CandidateView::SetAnnotationText(const std::wstring& text) { 6893345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick annotation_label_->SetText(text); 690c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 691c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 692c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid CandidateView::Select() { 693c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch set_background( 694c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch views::Background::CreateSolidBackground(kSelectedRowBackgroundColor)); 695c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch set_border(views::Border::CreateSolidBorder(1, kSelectedRowFrameColor)); 69621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen // Need to call SchedulePaint() for background and border color changes. 69721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen SchedulePaint(); 698c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 699c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 700c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid CandidateView::Unselect() { 701c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch set_background(NULL); 702c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch set_border(NULL); 70321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen SchedulePaint(); // See comments at Select(). 704c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 705c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 706c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid CandidateView::SetRowEnabled(bool enabled) { 707c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch shortcut_label_->SetColor( 708c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch enabled ? kShortcutColor : kDisabledShortcutColor); 709c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 710c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 711c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochgfx::Point CandidateView::GetCandidateLabelPosition() const { 71272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen return candidate_label_->GetMirroredPosition(); 713c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 714c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 715c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool CandidateView::OnMousePressed(const views::MouseEvent& event) { 71672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen parent_candidate_window_->OnMousePressed(); 717c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Select the candidate. We'll commit the candidate when the mouse 718c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // button is released. 719c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch parent_candidate_window_->SelectCandidateAt(index_in_page_); 720c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Request MouseDraggged and MouseReleased events. 721c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return true; 722c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 723c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 724c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool CandidateView::OnMouseDragged(const views::MouseEvent& event) { 725c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch gfx::Point location_in_candidate_window = event.location(); 726c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch views::View::ConvertPointToView(this, parent_candidate_window_, 727c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch &location_in_candidate_window); 728c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Notify the candidate window that a candidate is now being dragged. 729c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch parent_candidate_window_->OnCandidateDragged(location_in_candidate_window); 730c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Request MouseReleased event. 731c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return true; 732c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 733c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 734ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid CandidateView::OnMouseReleased(const views::MouseEvent& event) { 735ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // Commit the current candidate. 736ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen parent_candidate_window_->CommitCandidate(); 737ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen OnMouseCaptureLost(); 738ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen} 739ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 740ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid CandidateView::OnMouseCaptureLost() { 74172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen parent_candidate_window_->OnMouseReleased(); 742c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 743c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 744c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochCandidateWindowView::CandidateWindowView( 745c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch views::Widget* parent_frame) 74621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen : selected_candidate_index_in_page_(0), 747c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch parent_frame_(parent_frame), 748c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch candidate_area_(NULL), 749c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch footer_area_(NULL), 750c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch header_area_(NULL), 751c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch header_label_(NULL), 7523345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick footer_label_(NULL), 7533345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick previous_shortcut_column_width_(0), 7543345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick previous_candidate_column_width_(0), 75572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen previous_annotation_column_width_(0), 75672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen mouse_is_pressed_(false) { 757c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 758c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 759c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid CandidateWindowView::Init() { 760c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Set the background and the border of the view. 761c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch set_background( 762c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch views::Background::CreateSolidBackground(kDefaultBackgroundColor)); 763c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch set_border(views::Border::CreateSolidBorder(1, kFrameColor)); 764c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 765c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Create the header area. 766c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch header_area_ = CreateHeaderArea(); 767c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Create the candidate area. 768c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch candidate_area_ = new views::View; 769c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Create the footer area. 770c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch footer_area_ = CreateFooterArea(); 771c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 772c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Set the window layout of the view 773c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch views::GridLayout* layout = new views::GridLayout(this); 774c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch SetLayoutManager(layout); // |this| owns layout|. 775c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch views::ColumnSet* column_set = layout->AddColumnSet(0); 776c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch column_set->AddColumn(views::GridLayout::FILL, views::GridLayout::FILL, 777c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 0, views::GridLayout::USE_PREF, 0, 0); 778c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 779c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Add the header area. 780c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch layout->StartRow(0, 0); 781c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch layout->AddView(header_area_); // |header_area_| is owned by |this|. 782c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 783c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Add the candidate area. 784c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch layout->StartRow(0, 0); 785c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch layout->AddView(candidate_area_); // |candidate_area_| is owned by |this|. 786c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 787c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Add the footer area. 788c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch layout->StartRow(0, 0); 789c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch layout->AddView(footer_area_); // |footer_area_| is owned by |this|. 790c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 791c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 79272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenvoid CandidateWindowView::HideLookupTable() { 79372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen if (!mouse_is_pressed_) { 79472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen parent_frame_->Hide(); 79572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen return; 79672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen } 79772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 79872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // We should not hide the |frame_| when a mouse is pressed, so we don't run 79972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // into issues below. 80072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // 80172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // First, in the following scenario, it seems that the Views popup window does 80272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // not release mouse/keyboard grab even after it gets hidden. 80372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // 804ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // 1. create a popup window by views::Widget::CreateWidget() with the 805ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // accept_events flag set to true on the CreateParams. 80672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // 2. press a mouse button on the window. 80772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // 3. before releasing the mouse button, Hide() the window. 80872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // 4. release the button. 80972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // 81072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // And if we embed IME candidate window into Chrome, the window sometimes 81172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // receives an extra 'hide-lookup-table' event before mouse button is 81272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // released: 81372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // 81472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // 1. the candidate window is clicked. 81572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // 2. The mouse click handler in this file, OnMousePressed() in CandidateView, 81672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // is called, and the handler consumes the event by returning true. 81772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // 3. HOWEVER, if the candidate window is embedded into Chrome, the event is 81872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // also sent to Chrome! (problem #1) 81972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // 4. im-ibus.so in Chrome sends 'focus-out' event to ibus-daemon. 82072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // 5. ibus-daemon sends 'hide-lookup-table' event to the candidate window. 82172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // 6. the window is hidden, but the window does not release mouse/keyboard 82272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // grab! (problem #2) 82372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // 7. mouse button is released. 82472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // 8. now all mouse/keyboard events are consumed by the hidden popup, and are 82572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // not sent to Chrome. 82672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // 82772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // TODO(yusukes): investigate why the click event is sent to both candidate 82872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // window and Chrome. http://crosbug.com/11423 82972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // TODO(yusukes): investigate if we could fix Views so it always releases grab 83072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // when a popup window gets hidden. http://crosbug.com/11422 83172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // 83272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen LOG(WARNING) << "Can't hide the table since a mouse button is not released."; 83372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen} 83472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 83572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenvoid CandidateWindowView::OnMousePressed() { 83672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen mouse_is_pressed_ = true; 83772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen} 83872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 83972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenvoid CandidateWindowView::OnMouseReleased() { 84072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen mouse_is_pressed_ = false; 84172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen} 84272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 843c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid CandidateWindowView::HideAuxiliaryText() { 844c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch views::View* target_area = ( 845c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch lookup_table_.orientation == InputMethodLookupTable::kHorizontal ? 846c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch header_area_ : footer_area_); 847c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch views::View* target_place_holder = ( 848c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch lookup_table_.orientation == InputMethodLookupTable::kHorizontal ? 849c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch header_area_place_holder_.get() : 850c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch footer_area_place_holder_.get()); 851c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Put the place holder to the target display area. 852c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch target_area->RemoveAllChildViews(false); // Don't delete child views. 853c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch target_area->AddChildView(target_place_holder); 854c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 855c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 856c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid CandidateWindowView::ShowAuxiliaryText() { 857c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch views::View* target_area = ( 858c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch lookup_table_.orientation == InputMethodLookupTable::kHorizontal ? 859c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch header_area_ : footer_area_); 860c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch views::View* target_contents = ( 861c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch lookup_table_.orientation == InputMethodLookupTable::kHorizontal ? 862c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch header_area_contents_.get() : 863c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch footer_area_contents_.get()); 86421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen 86572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen if (target_contents->parent() != target_area) { 86621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen // If contents not in display area, put it in. 86721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen target_area->RemoveAllChildViews(false); // Don't delete child views. 86821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen target_area->AddChildView(target_contents); 86921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen } 870c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 871c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 872c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid CandidateWindowView::UpdateAuxiliaryText(const std::string& utf8_text) { 873c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch views::Label* target_label = ( 874c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch lookup_table_.orientation == InputMethodLookupTable::kHorizontal ? 875c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch header_label_ : footer_label_); 876c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch target_label->SetText(UTF8ToWide(utf8_text)); 877c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 878c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 87921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsenbool CandidateWindowView::ShouldUpdateCandidateViews( 88021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen const InputMethodLookupTable& old_table, 88121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen const InputMethodLookupTable& new_table) { 88221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen // Check if most table contents are identical. 88321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen if (old_table.page_size == new_table.page_size && 88421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen old_table.orientation == new_table.orientation && 88521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen old_table.candidates == new_table.candidates && 88621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen old_table.labels == new_table.labels && 88721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen old_table.annotations == new_table.annotations && 88821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen // Check if the page indexes are identical. 88921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen ComputePageIndex(old_table) == ComputePageIndex(new_table)) { 89021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen // If all of the conditions are met, we don't have to update candidate 89121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen // views. 89221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen return false; 89321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen } 89421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen return true; 89521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen} 89621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen 897c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid CandidateWindowView::UpdateCandidates( 89821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen const InputMethodLookupTable& new_lookup_table) { 89921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen const bool should_update = ShouldUpdateCandidateViews(lookup_table_, 90021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen new_lookup_table); 90121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen // Updating the candidate views is expensive. We'll skip this if possible. 90221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen if (should_update) { 90321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen // Initialize candidate views if necessary. 90421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen MaybeInitializeCandidateViews(new_lookup_table); 90521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen 90621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen // Compute the index of the current page. 90721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen const int current_page_index = ComputePageIndex(new_lookup_table); 90821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen if (current_page_index < 0) { 90921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen LOG(ERROR) << "Invalid lookup_table: " << new_lookup_table.ToString(); 91021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen return; 911c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 91221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen 91321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen // Update the candidates in the current page. 91421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen const size_t start_from = current_page_index * new_lookup_table.page_size; 91521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen 91621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen // In some cases, engines send empty shortcut labels. For instance, 91721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen // ibus-mozc sends empty labels when they show suggestions. In this 91821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen // case, we should not show shortcut labels. 91921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen const bool no_shortcut_mode = 92021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen (start_from < new_lookup_table.labels.size() && 92121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen new_lookup_table.labels[start_from] == ""); 92221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen for (size_t i = 0; i < candidate_views_.size(); ++i) { 92321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen const size_t index_in_page = i; 92421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen const size_t candidate_index = start_from + index_in_page; 92521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen CandidateView* candidate_view = candidate_views_[index_in_page]; 92621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen // Set the shortcut text. 92721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen if (no_shortcut_mode) { 92821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen candidate_view->SetShortcutText(L""); 92921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen } else { 93021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen // At this moment, we don't use labels sent from engines for UX 93121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen // reasons. First, we want to show shortcut labels in empty rows 93221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen // (ex. show 6, 7, 8, ... in empty rows when the number of 93321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen // candidates is 5). Second, we want to add a period after each 93421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen // shortcut label when the candidate window is horizontal. 93521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen candidate_view->SetShortcutText( 93621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen CreateShortcutText(i, new_lookup_table.orientation)); 93721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen } 93821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen // Set the candidate text. 93921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen if (candidate_index < new_lookup_table.candidates.size() && 94021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen candidate_index < new_lookup_table.annotations.size()) { 94121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen candidate_view->SetCandidateText( 94221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen UTF8ToWide(new_lookup_table.candidates[candidate_index])); 94321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen candidate_view->SetAnnotationText( 94421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen UTF8ToWide(new_lookup_table.annotations[candidate_index])); 94521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen candidate_view->SetRowEnabled(true); 94621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen } else { 94721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen // Disable the empty row. 94821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen candidate_view->SetCandidateText(L""); 94921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen candidate_view->SetAnnotationText(L""); 95021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen candidate_view->SetRowEnabled(false); 95121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen } 952c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 953c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 95421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen // Update the current lookup table. We'll use lookup_table_ from here. 95521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen // Note that SelectCandidateAt() uses lookup_table_. 95621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen lookup_table_ = new_lookup_table; 95721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen 95821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen // Select the current candidate in the page. 95921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen const int current_candidate_in_page = 96021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen lookup_table_.cursor_absolute_index % lookup_table_.page_size; 96121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen SelectCandidateAt(current_candidate_in_page); 962c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 963c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 964c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid CandidateWindowView::MaybeInitializeCandidateViews( 9653345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick const InputMethodLookupTable& lookup_table) { 9663345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick const InputMethodLookupTable::Orientation orientation = 9673345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick lookup_table.orientation; 9683345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick const int page_size = lookup_table.page_size; 9693345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 9703345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // Current column width. 9713345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick int shortcut_column_width = 0; 9723345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick int candidate_column_width = 0; 9733345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick int annotation_column_width = 0; 9743345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 9753345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // If orientation is horizontal, don't need to compute width, 9763345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // because each label is left aligned. 9773345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick if (orientation == InputMethodLookupTable::kVertical) { 9783345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick shortcut_column_width = ComputeShortcutColumnWidth(lookup_table); 9793345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick candidate_column_width = ComputeCandidateColumnWidth(lookup_table); 9803345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick annotation_column_width = ComputeAnnotationColumnWidth(lookup_table); 9813345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick } 9823345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 9833345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // If the requested number of views matches the number of current views, and 9843345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // previous and current column width are same, just reuse these. 98521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen // 98621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen // Note that the early exit logic is not only useful for improving 98721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen // performance, but also necessary for the horizontal candidate window 98821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen // to be redrawn properly. If we get rid of the logic, the horizontal 98921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen // candidate window won't get redrawn properly for some reason when 99021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen // there is no size change. You can test this by removing "return" here 99121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen // and type "ni" with Pinyin input method. 9923345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick if (static_cast<int>(candidate_views_.size()) == page_size && 9933345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick lookup_table_.orientation == orientation && 9943345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick previous_shortcut_column_width_ == shortcut_column_width && 9953345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick previous_candidate_column_width_ == candidate_column_width && 9963345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick previous_annotation_column_width_ == annotation_column_width) { 997c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 998c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 999c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 10003345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // Update the previous column widths. 10013345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick previous_shortcut_column_width_ = shortcut_column_width; 10023345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick previous_candidate_column_width_ = candidate_column_width; 10033345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick previous_annotation_column_width_ = annotation_column_width; 10043345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 1005c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Clear the existing candidate_views if any. 1006c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch for (size_t i = 0; i < candidate_views_.size(); ++i) { 1007c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch candidate_area_->RemoveChildView(candidate_views_[i]); 1008c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 1009c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch candidate_views_.clear(); 1010c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1011c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch views::GridLayout* layout = new views::GridLayout(candidate_area_); 1012c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // |candidate_area_| owns |layout|. 1013c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch candidate_area_->SetLayoutManager(layout); 1014c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Initialize the column set. 1015c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch views::ColumnSet* column_set = layout->AddColumnSet(0); 1016c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (orientation == InputMethodLookupTable::kVertical) { 1017c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch column_set->AddColumn(views::GridLayout::FILL, 1018c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch views::GridLayout::FILL, 1019c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 0, views::GridLayout::USE_PREF, 0, 0); 1020c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } else { 10213345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick for (int i = 0; i < page_size; ++i) { 1022c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch column_set->AddColumn(views::GridLayout::FILL, 1023c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch views::GridLayout::FILL, 1024c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 0, views::GridLayout::USE_PREF, 0, 0); 1025c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 1026c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 1027c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1028c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Set insets so the border of the selected candidate is drawn inside of 1029c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // the border of the main candidate window, but we don't have the inset 1030c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // at the top and the bottom as we have the borders of the header and 1031c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // footer areas. 1032c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const gfx::Insets kCandidateAreaInsets(0, 1, 0, 1); 1033c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch layout->SetInsets(kCandidateAreaInsets.top(), 1034c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch kCandidateAreaInsets.left(), 1035c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch kCandidateAreaInsets.bottom(), 1036c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch kCandidateAreaInsets.right()); 1037c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1038c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Add views to the candidate area. 1039c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (orientation == InputMethodLookupTable::kHorizontal) { 1040c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch layout->StartRow(0, 0); 1041c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 10423345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 10433345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick for (int i = 0; i < page_size; ++i) { 1044c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch CandidateView* candidate_row = new CandidateView(this, i, orientation); 10453345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick candidate_row->Init(shortcut_column_width, 10463345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick candidate_column_width, 10473345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick annotation_column_width); 1048c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch candidate_views_.push_back(candidate_row); 1049c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (orientation == InputMethodLookupTable::kVertical) { 1050c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch layout->StartRow(0, 0); 1051c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 10523345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // |candidate_row| will be owned by |candidate_area_|. 1053c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch layout->AddView(candidate_row); 1054c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 10553345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 10563345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // Compute views size in |layout|. 10573345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // If we don't call this function, GetHorizontalOffset() often 10583345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // returns invalid value (returns 0), then candidate window 105921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen // moves right from the correct position in MoveParentFrame(). 10603345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // TODO(nhiroki): Figure out why it returns invalid value. 10613345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // It seems that the x-position of the candidate labels is not set. 106272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen layout->Layout(candidate_area_); 1063c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 1064c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1065c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochviews::View* CandidateWindowView::CreateHeaderArea() { 1066c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // |header_area_place_holder_| will not be owned by another view. 1067c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // This will be deleted by scoped_ptr. 1068c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // 1069c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // This is because we swap the contents of |header_area_| between 1070c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // |header_area_place_holder_| (to show nothing) and 1071c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // |header_area_contents_| (to show something). In other words, 1072c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // |header_area_| only contains one of the two views hence cannot own 1073c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // the two views at the same time. 1074c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch header_area_place_holder_.reset(new views::View); 1075c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch header_area_place_holder_->set_parent_owned(false); // Won't be owened. 1076c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1077c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // |header_label_| will be owned by |header_area_contents_|. 1078c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch header_label_ = new views::Label; 1079c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch header_label_->SetHorizontalAlignment(views::Label::ALIGN_LEFT); 1080c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1081c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const gfx::Insets kHeaderInsets(2, 2, 2, 4); 1082c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // |header_area_contents_| will not be owned by another view. 1083c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // See a comment at |header_area_place_holder_| for why. 1084c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch header_area_contents_.reset( 1085c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch WrapWithPadding(header_label_, kHeaderInsets)); 1086c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch header_area_contents_->set_parent_owned(false); // Won't be owened. 1087c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch header_area_contents_->set_border( 1088c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch views::Border::CreateSolidBorder(1, kFrameColor)); 1089c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch header_area_contents_->set_background( 1090c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch views::Background::CreateVerticalGradientBackground( 1091c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch kFooterTopColor, 1092c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch kFooterBottomColor)); 1093c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1094c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch views::View* header_area = new views::View; 1095c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch header_area->SetLayoutManager(new views::FillLayout); 1096c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Initialize the header area with the place holder (i.e. show nothing). 1097c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch header_area->AddChildView(header_area_place_holder_.get()); 1098c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return header_area; 1099c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 1100c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1101c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochviews::View* CandidateWindowView::CreateFooterArea() { 1102c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // |footer_area_place_holder_| will not be owned by another view. 1103c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // See also the comment about |header_area_place_holder_| in 1104c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // CreateHeaderArea(). 1105c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch footer_area_place_holder_.reset(new views::View); 1106c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch footer_area_place_holder_->set_parent_owned(false); // Won't be owened. 1107c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1108c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch footer_label_ = new views::Label(); 1109c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch footer_label_->SetHorizontalAlignment(views::Label::ALIGN_RIGHT); 1110c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1111c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const gfx::Insets kFooterInsets(2, 2, 2, 4); 1112c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch footer_area_contents_.reset( 1113c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch WrapWithPadding(footer_label_, kFooterInsets)); 1114c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch footer_area_contents_->set_parent_owned(false); // Won't be owened. 1115c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch footer_area_contents_->set_border( 1116c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch views::Border::CreateSolidBorder(1, kFrameColor)); 1117c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch footer_area_contents_->set_background( 1118c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch views::Background::CreateVerticalGradientBackground( 1119c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch kFooterTopColor, 1120c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch kFooterBottomColor)); 1121c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1122c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch views::View* footer_area = new views::View; 1123c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch footer_area->SetLayoutManager(new views::FillLayout); 1124c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Initialize the footer area with the place holder (i.e. show nothing). 1125c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch footer_area->AddChildView(footer_area_place_holder_.get()); 1126c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return footer_area; 1127c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 1128c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1129c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid CandidateWindowView::SelectCandidateAt(int index_in_page) { 113021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen const int current_page_index = ComputePageIndex(lookup_table_); 113121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen if (current_page_index < 0) { 113221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen LOG(ERROR) << "Invalid lookup_table: " << lookup_table_.ToString(); 113321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen return; 113421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen } 113521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen 113621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen const int cursor_absolute_index = 113721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen lookup_table_.page_size * current_page_index + index_in_page; 1138c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Ignore click on out of range views. 1139c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (cursor_absolute_index < 0 || 1140c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch cursor_absolute_index >= 1141c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch static_cast<int>(lookup_table_.candidates.size())) { 1142c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 1143c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 1144c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 114521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen // Unselect the currently selected candidate. 114621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen candidate_views_[selected_candidate_index_in_page_]->Unselect(); 1147c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Remember the currently selected candidate index in the current page. 1148c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch selected_candidate_index_in_page_ = index_in_page; 1149c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1150c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Select the candidate specified by index_in_page. 1151c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch candidate_views_[index_in_page]->Select(); 1152c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1153c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Update the cursor indexes in the model. 1154c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch lookup_table_.cursor_absolute_index = cursor_absolute_index; 1155c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 1156c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1157c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid CandidateWindowView::OnCandidateDragged( 1158c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const gfx::Point& location) { 1159c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch for (size_t i = 0; i < candidate_views_.size(); ++i) { 1160c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch gfx::Point converted_location = location; 1161c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch views::View::ConvertPointToView(this, candidate_views_[i], 1162c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch &converted_location); 1163c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (candidate_views_[i]->HitTest(converted_location)) { 1164c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch SelectCandidateAt(i); 1165c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch break; 1166c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 1167c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 1168c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 1169c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1170c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid CandidateWindowView::CommitCandidate() { 1171c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // For now, we don't distinguish left and right clicks. 1172c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const int button = 1; // Left button. 1173c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const int key_modifilers = 0; 1174c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch FOR_EACH_OBSERVER(Observer, observers_, 1175c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch OnCandidateCommitted(selected_candidate_index_in_page_, 1176c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch button, 1177c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch key_modifilers)); 1178c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 1179c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 118021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsenvoid CandidateWindowView::ResizeAndMoveParentFrame() { 118121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen ResizeParentFrame(); 118221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen MoveParentFrame(); 118321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen} 118421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen 118521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsenvoid CandidateWindowView::ResizeParentFrame() { 1186c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Resize the parent frame, with the current candidate window size. 1187c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch gfx::Size size = GetPreferredSize(); 1188dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen gfx::Rect bounds = parent_frame_->GetClientAreaScreenBounds(); 118921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen // SetBounds() is not cheap. Only call this when the size is changed. 119021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen if (bounds.size() != size) { 119121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen bounds.set_size(size); 119221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen parent_frame_->SetBounds(bounds); 119321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen } 119421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen} 1195c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 119621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsenvoid CandidateWindowView::MoveParentFrame() { 119721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen const int x = cursor_location_.x(); 119821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen const int y = cursor_location_.y(); 119921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen const int height = cursor_location_.height(); 120021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen const int horizontal_offset = GetHorizontalOffset(); 120121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen 1202dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen gfx::Rect frame_bounds = parent_frame_->GetClientAreaScreenBounds(); 120321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen gfx::Rect screen_bounds = views::Screen::GetMonitorWorkAreaNearestWindow( 120421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen parent_frame_->GetNativeView()); 120521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen 120621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen // The default position. 120721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen frame_bounds.set_x(x + horizontal_offset); 120821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen frame_bounds.set_y(y + height); 120921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen 121021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen // Handle overflow at the left and the top. 121121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen frame_bounds.set_x(std::max(frame_bounds.x(), screen_bounds.x())); 121221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen frame_bounds.set_y(std::max(frame_bounds.y(), screen_bounds.y())); 121321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen 121421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen // Handle overflow at the right. 121521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen const int right_overflow = frame_bounds.right() - screen_bounds.right(); 121621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen if (right_overflow > 0) { 121721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen frame_bounds.set_x(frame_bounds.x() - right_overflow); 121821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen } 121921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen 122021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen // Handle overflow at the bottom. 122121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen const int bottom_overflow = frame_bounds.bottom() - screen_bounds.bottom(); 122221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen if (bottom_overflow > 0) { 122321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen frame_bounds.set_y(frame_bounds.y() - height - frame_bounds.height()); 122421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen } 122521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen 122621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen // Move the window per the cursor location. 122721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen parent_frame_->SetBounds(frame_bounds); 1228c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 1229c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1230c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochint CandidateWindowView::GetHorizontalOffset() { 1231c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Compute the horizontal offset if the lookup table is vertical. 1232c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!candidate_views_.empty() && 1233c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch lookup_table_.orientation == InputMethodLookupTable::kVertical) { 1234c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return - candidate_views_[0]->GetCandidateLabelPosition().x(); 1235c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 1236c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return 0; 1237c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 1238c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 123921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsenvoid CandidateWindowView::VisibilityChanged(View* starting_from, 124021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen bool is_visible) { 124121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen if (is_visible) { 124221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen // If the visibility of candidate window is changed, 124321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen // we should move the frame to the right position. 124421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen MoveParentFrame(); 124521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen } 124621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen} 124721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen 1248ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid CandidateWindowView::OnBoundsChanged(const gfx::Rect& previous_bounds) { 124921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen // If the bounds(size) of candidate window is changed, 125021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen // we should move the frame to the right position. 1251ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen View::OnBoundsChanged(previous_bounds); 125221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen MoveParentFrame(); 125321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen} 1254c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 12554a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdochbool CandidateWindowController::Impl::Init() { 1256c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Initialize the input method UI status connection. 1257c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch InputMethodUiStatusMonitorFunctions functions; 1258c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch functions.hide_auxiliary_text = 12594a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch &CandidateWindowController::Impl::OnHideAuxiliaryText; 1260c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch functions.hide_lookup_table = 12614a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch &CandidateWindowController::Impl::OnHideLookupTable; 1262c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch functions.set_cursor_location = 12634a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch &CandidateWindowController::Impl::OnSetCursorLocation; 1264c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch functions.update_auxiliary_text = 12654a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch &CandidateWindowController::Impl::OnUpdateAuxiliaryText; 1266c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch functions.update_lookup_table = 12674a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch &CandidateWindowController::Impl::OnUpdateLookupTable; 1268c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch ui_status_connection_ = MonitorInputMethodUiStatus(functions, this); 12693345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick if (!ui_status_connection_) { 12703345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick LOG(ERROR) << "MonitorInputMethodUiStatus() failed."; 12713345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick return false; 12723345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick } 12734a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch MonitorInputMethodConnection( 12744a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch ui_status_connection_, 12754a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch &CandidateWindowController::Impl::OnConnectionChange); 1276c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1277c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Create the candidate window view. 1278c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch CreateView(); 12793345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 12803345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick return true; 1281c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 1282c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 12834a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdochvoid CandidateWindowController::Impl::CreateView() { 1284c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Create a non-decorated frame. 1285ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen frame_.reset(views::Widget::CreateWidget( 1286ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen views::Widget::CreateParams(views::Widget::CreateParams::TYPE_POPUP))); 1287c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // The size is initially zero. 1288c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch frame_->Init(NULL, gfx::Rect(0, 0)); 1289c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1290c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Create the candidate window. 1291c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch candidate_window_ = new CandidateWindowView(frame_.get()); 1292c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch candidate_window_->Init(); 1293c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch candidate_window_->AddObserver(this); 1294c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1295c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Put the candidate window view on the frame. The frame is resized 1296c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // later when the candidate window is shown. 1297c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch views::RootView* root_view = frame_->GetRootView(); 1298c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // |root_view| owns the |candidate_window_|, thus |frame_| effectively 1299c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // owns |candidate_window_|. 1300c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch root_view->SetContentsView(candidate_window_); 1301c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 1302c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 13034a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben MurdochCandidateWindowController::Impl::Impl() 1304c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch : ui_status_connection_(NULL), 1305c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch frame_(NULL) { 1306c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 1307c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 13084a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben MurdochCandidateWindowController::Impl::~Impl() { 1309c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch candidate_window_->RemoveObserver(this); 1310c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch chromeos::DisconnectInputMethodUiStatus(ui_status_connection_); 1311c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 1312c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 13134a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdochvoid CandidateWindowController::Impl::OnHideAuxiliaryText( 1314c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch void* input_method_library) { 13154a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch CandidateWindowController::Impl* controller = 13164a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch static_cast<CandidateWindowController::Impl*>(input_method_library); 1317c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1318c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch controller->candidate_window_->HideAuxiliaryText(); 131921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen controller->candidate_window_->ResizeParentFrame(); 1320c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 1321c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 13224a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdochvoid CandidateWindowController::Impl::OnHideLookupTable( 1323c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch void* input_method_library) { 13244a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch CandidateWindowController::Impl* controller = 13254a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch static_cast<CandidateWindowController::Impl*>(input_method_library); 1326c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 132772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen controller->candidate_window_->HideLookupTable(); 1328c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 1329c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 13304a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdochvoid CandidateWindowController::Impl::OnSetCursorLocation( 1331c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch void* input_method_library, 1332c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int x, 1333c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int y, 1334c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int width, 1335c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int height) { 13364a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch CandidateWindowController::Impl* controller = 13374a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch static_cast<CandidateWindowController::Impl*>(input_method_library); 1338c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 13393345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // A workaround for http://crosbug.com/6460. We should ignore very short Y 13403345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // move to prevent the window from shaking up and down. 13413345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick const int kKeepPositionThreshold = 2; // px 134221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen const gfx::Rect& last_location = 134321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen controller->candidate_window_->cursor_location(); 13443345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick const int delta_y = abs(last_location.y() - y); 13453345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick if ((last_location.x() == x) && (delta_y <= kKeepPositionThreshold)) { 13463345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick DLOG(INFO) << "Ignored set_cursor_location signal to prevent window shake"; 13473345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick return; 13483345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick } 13493345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 1350c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Remember the cursor location. 135121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen controller->candidate_window_->set_cursor_location( 135221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen gfx::Rect(x, y, width, height)); 1353c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Move the window per the cursor location. 135421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen controller->candidate_window_->MoveParentFrame(); 1355c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 1356c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 13574a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdochvoid CandidateWindowController::Impl::OnUpdateAuxiliaryText( 1358c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch void* input_method_library, 1359c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const std::string& utf8_text, 1360c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch bool visible) { 13614a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch CandidateWindowController::Impl* controller = 13624a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch static_cast<CandidateWindowController::Impl*>(input_method_library); 1363c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // If it's not visible, hide the auxiliary text and return. 1364c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!visible) { 1365c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch controller->candidate_window_->HideAuxiliaryText(); 1366c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 1367c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 1368c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch controller->candidate_window_->UpdateAuxiliaryText(utf8_text); 1369c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch controller->candidate_window_->ShowAuxiliaryText(); 137021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen controller->candidate_window_->ResizeParentFrame(); 1371c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 1372c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 13734a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdochvoid CandidateWindowController::Impl::OnUpdateLookupTable( 1374c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch void* input_method_library, 1375c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const InputMethodLookupTable& lookup_table) { 13764a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch CandidateWindowController::Impl* controller = 13774a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch static_cast<CandidateWindowController::Impl*>(input_method_library); 1378c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1379c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // If it's not visible, hide the window and return. 1380c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!lookup_table.visible) { 138172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen controller->candidate_window_->HideLookupTable(); 1382c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 1383c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 1384c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1385c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch controller->candidate_window_->UpdateCandidates(lookup_table); 138621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen controller->candidate_window_->ResizeParentFrame(); 1387c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch controller->frame_->Show(); 1388c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 1389c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 13904a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdochvoid CandidateWindowController::Impl::OnCandidateCommitted(int index, 139172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen int button, 139272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen int flags) { 1393c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NotifyCandidateClicked(ui_status_connection_, index, button, flags); 1394c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 1395c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 13964a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdochvoid CandidateWindowController::Impl::OnConnectionChange( 13973345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick void* input_method_library, 13983345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick bool connected) { 13993345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick if (!connected) { 140072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen CandidateWindowController::Impl* controller = 140172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen static_cast<CandidateWindowController::Impl*>(input_method_library); 140272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen controller->candidate_window_->HideLookupTable(); 14033345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick } 14043345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick} 14053345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 1406201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben MurdochCandidateWindowController::CandidateWindowController() 1407201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch : impl_(new CandidateWindowController::Impl) { 14084a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch} 1409c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 14104a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben MurdochCandidateWindowController::~CandidateWindowController() { 14114a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch delete impl_; 14124a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch} 1413c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 14144a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdochbool CandidateWindowController::Init() { 14154a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch return impl_->Init(); 1416c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 14174a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch 14184a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch} // namespace chromeos 1419