OLD | NEW |
---|---|
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/browser/chromeos/input_method/candidate_window.h" | 5 #include "chrome/browser/chromeos/input_method/candidate_window.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 #include <string> | 8 #include <string> |
9 #include <vector> | 9 #include <vector> |
10 | 10 |
(...skipping 218 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
229 shortcut_label->SetText( | 229 shortcut_label->SetText( |
230 CreateShortcutText(i, lookup_table.orientation)); | 230 CreateShortcutText(i, lookup_table.orientation)); |
231 shortcut_column_width = | 231 shortcut_column_width = |
232 std::max(shortcut_column_width, | 232 std::max(shortcut_column_width, |
233 wrapped_shortcut_label->GetPreferredSize().width()); | 233 wrapped_shortcut_label->GetPreferredSize().width()); |
234 } | 234 } |
235 | 235 |
236 return shortcut_column_width; | 236 return shortcut_column_width; |
237 } | 237 } |
238 | 238 |
239 // Computes the page index. For instance, if the page size is 9, and the | |
240 // cursor is pointing to 13th candidate, the page index will be 1 (2nd | |
241 // page, as the index is zero-origin). Returns -1 on error. | |
242 int ComputePageIndex(const chromeos::InputMethodLookupTable& lookup_table) { | |
243 if (lookup_table.page_size > 0) | |
244 return lookup_table.cursor_absolute_index / lookup_table.page_size; | |
245 return -1; | |
246 } | |
247 | |
239 // Computes candidate column width. | 248 // Computes candidate column width. |
240 int ComputeCandidateColumnWidth( | 249 int ComputeCandidateColumnWidth( |
241 const chromeos::InputMethodLookupTable& lookup_table) { | 250 const chromeos::InputMethodLookupTable& lookup_table) { |
242 int candidate_column_width = 0; | 251 int candidate_column_width = 0; |
243 scoped_ptr<views::Label> candidate_label( | 252 scoped_ptr<views::Label> candidate_label( |
244 CreateCandidateLabel(lookup_table.orientation)); | 253 CreateCandidateLabel(lookup_table.orientation)); |
245 | 254 |
246 // Compute the start index of |lookup_table_|. | 255 // Compute the start index of |lookup_table_|. |
247 const int current_page_index = | 256 const int current_page_index = ComputePageIndex(lookup_table); |
248 lookup_table.cursor_absolute_index / lookup_table.page_size; | 257 if (current_page_index < 0) |
258 return 0; | |
249 const size_t start_from = current_page_index * lookup_table.page_size; | 259 const size_t start_from = current_page_index * lookup_table.page_size; |
250 | 260 |
251 // Compute the max width in candidate labels. | 261 // Compute the max width in candidate labels. |
252 // We'll create temporary candidate labels, and choose the largest width. | 262 // We'll create temporary candidate labels, and choose the largest width. |
253 for (size_t i = 0; i < lookup_table.candidates.size(); ++i) { | 263 for (size_t i = 0; i < lookup_table.candidates.size(); ++i) { |
254 const size_t index = start_from + i; | 264 const size_t index = start_from + i; |
255 | 265 |
256 candidate_label->SetText( | 266 candidate_label->SetText( |
257 UTF8ToWide(lookup_table.candidates[index])); | 267 UTF8ToWide(lookup_table.candidates[index])); |
258 candidate_column_width = | 268 candidate_column_width = |
259 std::max(candidate_column_width, | 269 std::max(candidate_column_width, |
260 candidate_label->GetPreferredSize().width()); | 270 candidate_label->GetPreferredSize().width()); |
261 } | 271 } |
262 | 272 |
263 return candidate_column_width; | 273 return candidate_column_width; |
264 } | 274 } |
265 | 275 |
266 // Computes annotation column width. | 276 // Computes annotation column width. |
267 int ComputeAnnotationColumnWidth( | 277 int ComputeAnnotationColumnWidth( |
268 const chromeos::InputMethodLookupTable& lookup_table) { | 278 const chromeos::InputMethodLookupTable& lookup_table) { |
269 int annotation_column_width = 0; | 279 int annotation_column_width = 0; |
270 scoped_ptr<views::Label> annotation_label( | 280 scoped_ptr<views::Label> annotation_label( |
271 CreateAnnotationLabel(lookup_table.orientation)); | 281 CreateAnnotationLabel(lookup_table.orientation)); |
272 | 282 |
273 // Compute the start index of |lookup_table_|. | 283 // Compute the start index of |lookup_table_|. |
274 const int current_page_index = | 284 const int current_page_index = ComputePageIndex(lookup_table); |
275 lookup_table.cursor_absolute_index / lookup_table.page_size; | 285 if (current_page_index < 0) |
286 return 0; | |
276 const size_t start_from = current_page_index * lookup_table.page_size; | 287 const size_t start_from = current_page_index * lookup_table.page_size; |
277 | 288 |
278 // Compute max width in annotation labels. | 289 // Compute max width in annotation labels. |
279 // We'll create temporary annotation labels, and choose the largest width. | 290 // We'll create temporary annotation labels, and choose the largest width. |
280 for (size_t i = 0; i < lookup_table.annotations.size(); ++i) { | 291 for (size_t i = 0; i < lookup_table.annotations.size(); ++i) { |
281 const size_t index = start_from + i; | 292 const size_t index = start_from + i; |
282 | 293 |
283 annotation_label->SetText( | 294 annotation_label->SetText( |
284 UTF8ToWide(lookup_table.annotations[index])); | 295 UTF8ToWide(lookup_table.annotations[index])); |
285 annotation_column_width = | 296 annotation_column_width = |
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
338 | 349 |
339 // Hides the auxiliary text. | 350 // Hides the auxiliary text. |
340 void HideAuxiliaryText(); | 351 void HideAuxiliaryText(); |
341 | 352 |
342 // Shows the auxiliary text. | 353 // Shows the auxiliary text. |
343 void ShowAuxiliaryText(); | 354 void ShowAuxiliaryText(); |
344 | 355 |
345 // Updates the auxiliary text. | 356 // Updates the auxiliary text. |
346 void UpdateAuxiliaryText(const std::string& utf8_text); | 357 void UpdateAuxiliaryText(const std::string& utf8_text); |
347 | 358 |
359 // Returns true if we should update candidate views in the window. For | |
360 // instance, if we are going to show the same candidates as before, we | |
361 // don't have to update candidate views. This happens when the user just | |
362 // moves the cursor in the same page in the candidate window. | |
363 bool ShouldUpdateCandidateViews( | |
364 const InputMethodLookupTable& previous_table, | |
365 const InputMethodLookupTable& current_table); | |
366 | |
348 // Updates candidates of the candidate window from |lookup_table|. | 367 // Updates candidates of the candidate window from |lookup_table|. |
349 // Candidates are arranged per |orientation|. | 368 // Candidates are arranged per |orientation|. |
350 void UpdateCandidates(const InputMethodLookupTable& lookup_table); | 369 void UpdateCandidates(const InputMethodLookupTable& lookup_table); |
351 | 370 |
352 // Resizes the parent frame and schedules painting. This needs to be | 371 // Resizes the parent frame and schedules painting. This needs to be |
353 // called when the visible contents of the candidate window are | 372 // called when the visible contents of the candidate window are |
354 // modified. | 373 // modified. |
355 void ResizeAndSchedulePaint(); | 374 void ResizeAndSchedulePaint(); |
356 | 375 |
357 // Returns the horizontal offset used for placing the vertical candidate | 376 // Returns the horizontal offset used for placing the vertical candidate |
(...skipping 412 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
770 ResizeAndSchedulePaint(); | 789 ResizeAndSchedulePaint(); |
771 } | 790 } |
772 | 791 |
773 void CandidateWindowView::UpdateAuxiliaryText(const std::string& utf8_text) { | 792 void CandidateWindowView::UpdateAuxiliaryText(const std::string& utf8_text) { |
774 views::Label* target_label = ( | 793 views::Label* target_label = ( |
775 lookup_table_.orientation == InputMethodLookupTable::kHorizontal ? | 794 lookup_table_.orientation == InputMethodLookupTable::kHorizontal ? |
776 header_label_ : footer_label_); | 795 header_label_ : footer_label_); |
777 target_label->SetText(UTF8ToWide(utf8_text)); | 796 target_label->SetText(UTF8ToWide(utf8_text)); |
778 } | 797 } |
779 | 798 |
799 bool CandidateWindowView::ShouldUpdateCandidateViews( | |
800 const InputMethodLookupTable& previous_table, | |
801 const InputMethodLookupTable& current_table) { | |
802 // Check if most table contents are identical. | |
803 if (previous_table.page_size == current_table.page_size && | |
804 previous_table.orientation == current_table.orientation && | |
805 previous_table.candidates == current_table.candidates && | |
806 previous_table.labels == current_table.labels && | |
807 previous_table.annotations == current_table.annotations && | |
808 // Check if the page indexes are identical. | |
809 ComputePageIndex(previous_table) == ComputePageIndex(current_table)) { | |
810 // If all of the conditions are met, we don't have to update candidate | |
811 // views. | |
812 return false; | |
813 } | |
814 return true; | |
815 } | |
816 | |
780 void CandidateWindowView::UpdateCandidates( | 817 void CandidateWindowView::UpdateCandidates( |
781 const InputMethodLookupTable& lookup_table) { | 818 const InputMethodLookupTable& lookup_table) { |
782 // Initialize candidate views if necessary. | 819 const bool should_update = ShouldUpdateCandidateViews(lookup_table_, |
783 MaybeInitializeCandidateViews(lookup_table); | 820 lookup_table); |
821 // Updating the candidate views is expensive. We'll skip this if possible. | |
822 if (should_update) { | |
823 // Initialize candidate views if necessary. | |
824 MaybeInitializeCandidateViews(lookup_table); | |
784 | 825 |
785 // In MaybeInitializeCandidateViews(), | 826 // Compute the index of the current page. |
786 // |lookup_table| values and |lookup_table_| values are compared, | 827 if (lookup_table.page_size <= 0) { |
787 // so this substitution is needed after the function. | 828 LOG(ERROR) << "Invalid page size: " << lookup_table.page_size; |
829 return; | |
830 } | |
831 current_page_index_ = | |
832 lookup_table.cursor_absolute_index / lookup_table.page_size; | |
833 | |
834 // Update the candidates in the current page. | |
835 const size_t start_from = current_page_index_ * lookup_table.page_size; | |
836 | |
837 // In some cases, engines send empty shortcut labels. For instance, | |
838 // ibus-mozc sends empty labels when they show suggestions. In this | |
839 // case, we should not show shortcut labels. | |
840 const bool no_shortcut_mode = (start_from < lookup_table.labels.size() && | |
841 lookup_table.labels[start_from] == ""); | |
842 for (size_t i = 0; i < candidate_views_.size(); ++i) { | |
843 const size_t index_in_page = i; | |
844 const size_t candidate_index = start_from + index_in_page; | |
845 CandidateView* candidate_view = candidate_views_[index_in_page]; | |
846 // Set the shortcut text. | |
847 if (no_shortcut_mode) { | |
848 candidate_view->SetShortcutText(L""); | |
849 } else { | |
850 // At this moment, we don't use labels sent from engines for UX | |
851 // reasons. First, we want to show shortcut labels in empty rows | |
852 // (ex. show 6, 7, 8, ... in empty rows when the number of | |
853 // candidates is 5). Second, we want to add a period after each | |
854 // shortcut label when the candidate window is horizontal. | |
855 candidate_view->SetShortcutText( | |
856 CreateShortcutText(i, lookup_table.orientation)); | |
857 } | |
858 // Set the candidate text. | |
859 if (candidate_index < lookup_table.candidates.size() && | |
860 candidate_index < lookup_table.annotations.size()) { | |
861 candidate_view->SetCandidateText( | |
862 UTF8ToWide(lookup_table.candidates[candidate_index])); | |
863 candidate_view->SetAnnotationText( | |
864 UTF8ToWide(lookup_table.annotations[candidate_index])); | |
865 candidate_view->SetRowEnabled(true); | |
866 } else { | |
867 // Disable the empty row. | |
868 candidate_view->SetCandidateText(L""); | |
869 candidate_view->SetAnnotationText(L""); | |
870 candidate_view->SetRowEnabled(false); | |
871 } | |
872 } | |
873 } | |
satorux1
2010/12/01 09:25:32
Hmm, rietveld didn't do a good job for showing dif
| |
788 lookup_table_ = lookup_table; | 874 lookup_table_ = lookup_table; |
789 | 875 |
790 // Compute the index of the current page. | 876 // Select the current candidate in the page. |
791 current_page_index_ = | 877 const int current_candidate_in_page = |
792 lookup_table.cursor_absolute_index / lookup_table.page_size; | |
793 | |
794 // Update the candidates in the current page. | |
795 const size_t start_from = current_page_index_ * lookup_table.page_size; | |
796 | |
797 // In some cases, engines send empty shortcut labels. For instance, | |
798 // ibus-mozc sends empty labels when they show suggestions. In this | |
799 // case, we should not show shortcut labels. | |
800 const bool no_shortcut_mode = (start_from < lookup_table_.labels.size() && | |
801 lookup_table_.labels[start_from] == ""); | |
802 for (size_t i = 0; i < candidate_views_.size(); ++i) { | |
803 const size_t index_in_page = i; | |
804 const size_t candidate_index = start_from + index_in_page; | |
805 CandidateView* candidate_view = candidate_views_[index_in_page]; | |
806 // Set the shortcut text. | |
807 if (no_shortcut_mode) { | |
808 candidate_view->SetShortcutText(L""); | |
809 } else { | |
810 // At this moment, we don't use labels sent from engines for UX | |
811 // reasons. First, we want to show shortcut labels in empty rows | |
812 // (ex. show 6, 7, 8, ... in empty rows when the number of | |
813 // candidates is 5). Second, we want to add a period after each | |
814 // shortcut label when the candidate window is horizontal. | |
815 candidate_view->SetShortcutText( | |
816 CreateShortcutText(i, lookup_table_.orientation)); | |
817 } | |
818 // Set the candidate text. | |
819 if (candidate_index < lookup_table_.candidates.size() && | |
820 candidate_index < lookup_table_.annotations.size()) { | |
821 candidate_view->SetCandidateText( | |
822 UTF8ToWide(lookup_table_.candidates[candidate_index])); | |
823 candidate_view->SetAnnotationText( | |
824 UTF8ToWide(lookup_table_.annotations[candidate_index])); | |
825 candidate_view->SetRowEnabled(true); | |
826 } else { | |
827 // Disable the empty row. | |
828 candidate_view->SetCandidateText(L""); | |
829 candidate_view->SetAnnotationText(L""); | |
830 candidate_view->SetRowEnabled(false); | |
831 } | |
832 } | |
833 | |
834 // Select the first candidate candidate in the page. | |
835 const int first_candidate_in_page = | |
836 lookup_table.cursor_absolute_index % lookup_table.page_size; | 878 lookup_table.cursor_absolute_index % lookup_table.page_size; |
837 SelectCandidateAt(first_candidate_in_page); | 879 SelectCandidateAt(current_candidate_in_page); |
838 } | 880 } |
839 | 881 |
840 void CandidateWindowView::MaybeInitializeCandidateViews( | 882 void CandidateWindowView::MaybeInitializeCandidateViews( |
841 const InputMethodLookupTable& lookup_table) { | 883 const InputMethodLookupTable& lookup_table) { |
842 const InputMethodLookupTable::Orientation orientation = | 884 const InputMethodLookupTable::Orientation orientation = |
843 lookup_table.orientation; | 885 lookup_table.orientation; |
844 const int page_size = lookup_table.page_size; | 886 const int page_size = lookup_table.page_size; |
845 | 887 |
846 // Current column width. | 888 // Current column width. |
847 int shortcut_column_width = 0; | 889 int shortcut_column_width = 0; |
848 int candidate_column_width = 0; | 890 int candidate_column_width = 0; |
849 int annotation_column_width = 0; | 891 int annotation_column_width = 0; |
850 | 892 |
851 // If orientation is horizontal, don't need to compute width, | 893 // If orientation is horizontal, don't need to compute width, |
852 // because each label is left aligned. | 894 // because each label is left aligned. |
853 if (orientation == InputMethodLookupTable::kVertical) { | 895 if (orientation == InputMethodLookupTable::kVertical) { |
854 shortcut_column_width = ComputeShortcutColumnWidth(lookup_table); | 896 shortcut_column_width = ComputeShortcutColumnWidth(lookup_table); |
855 candidate_column_width = ComputeCandidateColumnWidth(lookup_table); | 897 candidate_column_width = ComputeCandidateColumnWidth(lookup_table); |
856 annotation_column_width = ComputeAnnotationColumnWidth(lookup_table); | 898 annotation_column_width = ComputeAnnotationColumnWidth(lookup_table); |
857 } | 899 } |
858 | 900 |
859 // If the requested number of views matches the number of current views, and | 901 // If the requested number of views matches the number of current views, and |
860 // previous and current column width are same, just reuse these. | 902 // previous and current column width are same, just reuse these. |
903 // | |
904 // Note that the early exit logic is not only useful for improving | |
905 // performance, but also necessary for the horizontal candidate window | |
906 // to be redrawn properly. If we get rid of the logic, the horizontal | |
907 // candidate window won't get redrawn properly for some reason when | |
908 // there is no size change. You can test this by removing "return" here | |
909 // and type "ni" with Pinyin input method. | |
861 if (static_cast<int>(candidate_views_.size()) == page_size && | 910 if (static_cast<int>(candidate_views_.size()) == page_size && |
862 lookup_table_.orientation == orientation && | 911 lookup_table_.orientation == orientation && |
863 previous_shortcut_column_width_ == shortcut_column_width && | 912 previous_shortcut_column_width_ == shortcut_column_width && |
864 previous_candidate_column_width_ == candidate_column_width && | 913 previous_candidate_column_width_ == candidate_column_width && |
865 previous_annotation_column_width_ == annotation_column_width) { | 914 previous_annotation_column_width_ == annotation_column_width) { |
866 return; | 915 return; |
867 } | 916 } |
868 | 917 |
869 // Update the previous column widths. | 918 // Update the previous column widths. |
870 previous_shortcut_column_width_ = shortcut_column_width; | 919 previous_shortcut_column_width_ = shortcut_column_width; |
(...skipping 333 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1204 DLOG(INFO) << "Ignored set_cursor_location signal to prevent window shake"; | 1253 DLOG(INFO) << "Ignored set_cursor_location signal to prevent window shake"; |
1205 return; | 1254 return; |
1206 } | 1255 } |
1207 | 1256 |
1208 // Remember the cursor location. | 1257 // Remember the cursor location. |
1209 controller->set_cursor_location(gfx::Rect(x, y, width, height)); | 1258 controller->set_cursor_location(gfx::Rect(x, y, width, height)); |
1210 // Move the window per the cursor location. | 1259 // Move the window per the cursor location. |
1211 controller->MoveCandidateWindow( | 1260 controller->MoveCandidateWindow( |
1212 controller->cursor_location(), | 1261 controller->cursor_location(), |
1213 controller->candidate_window_->GetHorizontalOffset()); | 1262 controller->candidate_window_->GetHorizontalOffset()); |
1214 // The call is needed to ensure that the candidate window is redrawed | 1263 // The call is needed to ensure that the candidate window is redrawn |
1215 // properly after the cursor location is changed. | 1264 // properly after the cursor location is changed. |
1216 controller->candidate_window_->ResizeAndSchedulePaint(); | 1265 controller->candidate_window_->ResizeAndSchedulePaint(); |
1217 } | 1266 } |
1218 | 1267 |
1219 void CandidateWindowController::Impl::OnUpdateAuxiliaryText( | 1268 void CandidateWindowController::Impl::OnUpdateAuxiliaryText( |
1220 void* input_method_library, | 1269 void* input_method_library, |
1221 const std::string& utf8_text, | 1270 const std::string& utf8_text, |
1222 bool visible) { | 1271 bool visible) { |
1223 CandidateWindowController::Impl* controller = | 1272 CandidateWindowController::Impl* controller = |
1224 static_cast<CandidateWindowController::Impl*>(input_method_library); | 1273 static_cast<CandidateWindowController::Impl*>(input_method_library); |
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1281 | 1330 |
1282 CandidateWindowController::~CandidateWindowController() { | 1331 CandidateWindowController::~CandidateWindowController() { |
1283 delete impl_; | 1332 delete impl_; |
1284 } | 1333 } |
1285 | 1334 |
1286 bool CandidateWindowController::Init() { | 1335 bool CandidateWindowController::Init() { |
1287 return impl_->Init(); | 1336 return impl_->Init(); |
1288 } | 1337 } |
1289 | 1338 |
1290 } // namespace chromeos | 1339 } // namespace chromeos |
OLD | NEW |