Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 /* | 1 /* |
| 2 * Copyright (c) 2008, 2009, Google Inc. All rights reserved. | 2 * Copyright (c) 2008, 2009, Google Inc. All rights reserved. |
| 3 * | 3 * |
| 4 * Redistribution and use in source and binary forms, with or without | 4 * Redistribution and use in source and binary forms, with or without |
| 5 * modification, are permitted provided that the following conditions are | 5 * modification, are permitted provided that the following conditions are |
| 6 * met: | 6 * met: |
| 7 * | 7 * |
| 8 * * Redistributions of source code must retain the above copyright | 8 * * Redistributions of source code must retain the above copyright |
| 9 * notice, this list of conditions and the following disclaimer. | 9 * notice, this list of conditions and the following disclaimer. |
| 10 * * Redistributions in binary form must reproduce the above | 10 * * Redistributions in binary form must reproduce the above |
| (...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 82 virtual bool handleKeyEvent(const PlatformKeyboardEvent&); | 82 virtual bool handleKeyEvent(const PlatformKeyboardEvent&); |
| 83 | 83 |
| 84 // ScrollView | 84 // ScrollView |
| 85 virtual HostWindow* hostWindow() const; | 85 virtual HostWindow* hostWindow() const; |
| 86 | 86 |
| 87 // Widget | 87 // Widget |
| 88 virtual void invalidateRect(const IntRect&); | 88 virtual void invalidateRect(const IntRect&); |
| 89 | 89 |
| 90 // PopupListBox methods | 90 // PopupListBox methods |
| 91 | 91 |
| 92 // Show the popup | 92 // Shows the popup |
| 93 void showPopup(); | 93 void showPopup(); |
| 94 | 94 |
| 95 // Hide the popup. Do not call this directly: use client->hidePopup(). | 95 // Hides the popup. Do not call this directly: use client->hidePopup(). |
| 96 void hidePopup(); | 96 void hidePopup(); |
| 97 | 97 |
| 98 // Update our internal list to match the client. | 98 // Updates our internal list to match the client. |
| 99 void updateFromElement(); | 99 void updateFromElement(); |
| 100 | 100 |
| 101 // Free any allocated resources used in a particular popup session. | 101 // Frees any allocated resources used in a particular popup session. |
| 102 void clear(); | 102 void clear(); |
| 103 | 103 |
| 104 // Set the index of the option that is displayed in the <select> widget in t he page | 104 // Sets the index of the option that is displayed in the <select> widget in the page |
| 105 void setOriginalIndex(int index); | 105 void setOriginalIndex(int index); |
| 106 | 106 |
| 107 // Get the index of the item that the user is currently moused over or has s elected with | 107 // Gets the index of the item that the user is currently moused over or has selected with |
| 108 // the keyboard. This is not the same as the original index, since the user has not yet | 108 // the keyboard. This is not the same as the original index, since the user has not yet |
| 109 // accepted this input. | 109 // accepted this input. |
| 110 int selectedIndex() const { return m_selectedIndex; } | 110 int selectedIndex() const { return m_selectedIndex; } |
| 111 | 111 |
| 112 // Move selection down/up the given number of items, scrolling if necessary. | 112 // Moves selection down/up the given number of items, scrolling if necessary . |
| 113 // Positive is down. The resulting index will be clamped to the range | 113 // Positive is down. The resulting index will be clamped to the range |
| 114 // [0, numItems), and non-option items will be skipped. | 114 // [0, numItems), and non-option items will be skipped. |
| 115 void adjustSelectedIndex(int delta); | 115 void adjustSelectedIndex(int delta); |
| 116 | 116 |
| 117 // Returns the number of items in the list. | 117 // Returns the number of items in the list. |
| 118 int numItems() const { return static_cast<int>(m_items.size()); } | 118 int numItems() const { return static_cast<int>(m_items.size()); } |
| 119 | 119 |
| 120 void setBaseWidth(int width) { m_baseWidth = width; } | 120 void setBaseWidth(int width) { m_baseWidth = width; } |
| 121 | 121 |
| 122 // Compute size of widget and children. | 122 // Computes the size of widget and children. |
| 123 void layout(); | 123 void layout(); |
| 124 | 124 |
| 125 // Returns whether the popup wants to process events for the passed key. | 125 // Returns whether the popup wants to process events for the passed key. |
| 126 bool isInterestedInEventForKey(int keyCode); | 126 bool isInterestedInEventForKey(int keyCode); |
| 127 | 127 |
| 128 // Sets whether the PopupMenuClient should be told to change its text when a | 128 // Sets whether the PopupMenuClient should be told to change its text when a |
| 129 // new item is selected (by using the arrow keys). Default is true. | 129 // new item is selected (by using the arrow keys). Default is true. |
| 130 void setTextOnIndexChange(bool value) { m_setTextOnIndexChange = value; } | 130 void setTextOnIndexChange(bool value) { m_setTextOnIndexChange = value; } |
| 131 | 131 |
| 132 // Sets whether we should accept the selected index when the popup is | 132 // Sets whether we should accept the selected index when the popup is |
| 133 // abandonned. | 133 // abandonned. |
| 134 void setAcceptOnAbandon(bool value) { m_shouldAcceptOnAbandon = value; } | 134 void setAcceptOnAbandon(bool value) { m_shouldAcceptOnAbandon = value; } |
| 135 | 135 |
| 136 // Sets whether pressing the down/up arrow when the last/first row is | |
| 137 // selected clears the selection on the first key press and then selects the | |
| 138 // first/last row on the next key press. If false, the selected row stays | |
| 139 // the last/first row. | |
| 140 void setLoopSelectionNavigation(bool value) { m_loopSelectionNavigation = va lue; } | |
| 141 | |
| 136 private: | 142 private: |
| 137 friend class PopupContainer; | 143 friend class PopupContainer; |
| 138 friend class RefCounted<PopupListBox>; | 144 friend class RefCounted<PopupListBox>; |
| 139 | 145 |
| 140 // A type of List Item | 146 // A type of List Item |
| 141 enum ListItemType { | 147 enum ListItemType { |
| 142 TypeOption, | 148 TypeOption, |
| 143 TypeGroup, | 149 TypeGroup, |
| 144 TypeSeparator | 150 TypeSeparator |
| 145 }; | 151 }; |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 156 PopupListBox(PopupMenuClient* client) | 162 PopupListBox(PopupMenuClient* client) |
| 157 : m_originalIndex(0) | 163 : m_originalIndex(0) |
| 158 , m_selectedIndex(0) | 164 , m_selectedIndex(0) |
| 159 , m_shouldAcceptOnAbandon(true) | 165 , m_shouldAcceptOnAbandon(true) |
| 160 , m_willAcceptOnAbandon(false) | 166 , m_willAcceptOnAbandon(false) |
| 161 , m_visibleRows(0) | 167 , m_visibleRows(0) |
| 162 , m_popupClient(client) | 168 , m_popupClient(client) |
| 163 , m_repeatingChar(0) | 169 , m_repeatingChar(0) |
| 164 , m_lastCharTime(0) | 170 , m_lastCharTime(0) |
| 165 , m_setTextOnIndexChange(true) | 171 , m_setTextOnIndexChange(true) |
| 172 , m_loopSelectionNavigation(false) | |
| 166 { | 173 { |
| 167 setScrollbarModes(ScrollbarAlwaysOff, ScrollbarAlwaysOff); | 174 setScrollbarModes(ScrollbarAlwaysOff, ScrollbarAlwaysOff); |
| 168 } | 175 } |
| 169 | 176 |
| 170 ~PopupListBox() | 177 ~PopupListBox() |
| 171 { | 178 { |
| 172 clear(); | 179 clear(); |
| 173 } | 180 } |
| 174 | 181 |
| 175 void disconnectClient() { m_popupClient = 0; } | 182 void disconnectClient() { m_popupClient = 0; } |
| 176 | 183 |
| 177 // Closes the popup | 184 // Closes the popup |
| 178 void abandon(); | 185 void abandon(); |
| 179 // Select an index in the list, scrolling if necessary. | 186 // Select an index in the list, scrolling if necessary. |
| 180 void selectIndex(int index); | 187 void selectIndex(int index); |
| 181 // Accepts the selected index as the value to be displayed in the <select> w idget on | 188 // Accepts the selected index as the value to be displayed in the <select> w idget on |
| 182 // the web page, and closes the popup. | 189 // the web page, and closes the popup. |
| 183 void acceptIndex(int index); | 190 void acceptIndex(int index); |
| 184 | 191 |
| 185 // Returns true if the selection can be changed to index. | 192 // Returns true if the selection can be changed to index. |
| 186 // Disabled items, or labels cannot be selected. | 193 // Disabled items, or labels cannot be selected. |
| 187 bool isSelectableItem(int index); | 194 bool isSelectableItem(int index); |
| 188 | 195 |
| 196 // Clears the selection (so no row appears selected). | |
| 197 void clearSelection(); | |
| 198 | |
| 189 // Scrolls to reveal the given index. | 199 // Scrolls to reveal the given index. |
| 190 void scrollToRevealRow(int index); | 200 void scrollToRevealRow(int index); |
| 191 void scrollToRevealSelection() { scrollToRevealRow(m_selectedIndex); } | 201 void scrollToRevealSelection() { scrollToRevealRow(m_selectedIndex); } |
| 192 | 202 |
| 193 // Invalidates the row at the given index. | 203 // Invalidates the row at the given index. |
| 194 void invalidateRow(int index); | 204 void invalidateRow(int index); |
| 195 | 205 |
| 196 // Gets the height of a row. | 206 // Gets the height of a row. |
| 197 int getRowHeight(int index); | 207 int getRowHeight(int index); |
| 198 // Get the bounds of a row. | 208 // Get the bounds of a row. |
| 199 IntRect getRowBounds(int index); | 209 IntRect getRowBounds(int index); |
| 200 | 210 |
| 201 // Converts a point to an index of the row the point is over | 211 // Converts a point to an index of the row the point is over |
| 202 int pointToRowIndex(const IntPoint&); | 212 int pointToRowIndex(const IntPoint&); |
| 203 | 213 |
| 204 // Paint an individual row | 214 // Paint an individual row |
| 205 void paintRow(GraphicsContext*, const IntRect&, int rowIndex); | 215 void paintRow(GraphicsContext*, const IntRect&, int rowIndex); |
| 206 | 216 |
| 207 // Test if the given point is within the bounds of the popup window. | 217 // Test if the given point is within the bounds of the popup window. |
| 208 bool isPointInBounds(const IntPoint&); | 218 bool isPointInBounds(const IntPoint&); |
| 209 | 219 |
| 210 // Called when the user presses a text key. Does a prefix-search of the ite ms. | 220 // Called when the user presses a text key. Does a prefix-search of the ite ms. |
| 211 void typeAheadFind(const PlatformKeyboardEvent&); | 221 void typeAheadFind(const PlatformKeyboardEvent&); |
| 212 | 222 |
| 213 // Returns the font to use for the given row | 223 // Returns the font to use for the given row |
| 214 Font getRowFont(int index); | 224 Font getRowFont(int index); |
| 215 | 225 |
| 226 // Moves the selection down/up one item, taking care of looping back to the | |
| 227 // first/last element if m_loopSelectionNavigation is true. | |
| 228 void selectPreviousRow(); | |
| 229 void selectNextRow(); | |
| 230 | |
| 231 | |
| 216 // This is the index of the item marked as "selected" - i.e. displayed in th e widget on the | 232 // This is the index of the item marked as "selected" - i.e. displayed in th e widget on the |
| 217 // page. | 233 // page. |
| 218 int m_originalIndex; | 234 int m_originalIndex; |
| 219 | 235 |
| 220 // This is the index of the item that the user is hovered over or has select ed using the | 236 // This is the index of the item that the user is hovered over or has select ed using the |
| 221 // keyboard in the list. They have not confirmed this selection by clicking or pressing | 237 // keyboard in the list. They have not confirmed this selection by clicking or pressing |
| 222 // enter yet however. | 238 // enter yet however. |
| 223 int m_selectedIndex; | 239 int m_selectedIndex; |
| 224 | 240 |
| 225 // Whether we should accept the selectedIndex as chosen when the popup is | 241 // Whether we should accept the selectedIndex as chosen when the popup is |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 257 // The string the user has typed so far into the popup. Used for typeAheadFi nd. | 273 // The string the user has typed so far into the popup. Used for typeAheadFi nd. |
| 258 String m_typedString; | 274 String m_typedString; |
| 259 | 275 |
| 260 // The char the user has hit repeatedly. Used for typeAheadFind. | 276 // The char the user has hit repeatedly. Used for typeAheadFind. |
| 261 UChar m_repeatingChar; | 277 UChar m_repeatingChar; |
| 262 | 278 |
| 263 // The last time the user hit a key. Used for typeAheadFind. | 279 // The last time the user hit a key. Used for typeAheadFind. |
| 264 TimeStamp m_lastCharTime; | 280 TimeStamp m_lastCharTime; |
| 265 | 281 |
| 266 bool m_setTextOnIndexChange; | 282 bool m_setTextOnIndexChange; |
| 283 | |
| 284 bool m_loopSelectionNavigation; | |
| 267 }; | 285 }; |
| 268 | 286 |
| 269 static PlatformMouseEvent constructRelativeMouseEvent(const PlatformMouseEvent& e, | 287 static PlatformMouseEvent constructRelativeMouseEvent(const PlatformMouseEvent& e, |
| 270 FramelessScrollView* paren t, | 288 FramelessScrollView* paren t, |
| 271 FramelessScrollView* child ) | 289 FramelessScrollView* child ) |
| 272 { | 290 { |
| 273 IntPoint pos = parent->convertSelfToChild(child, e.pos()); | 291 IntPoint pos = parent->convertSelfToChild(child, e.pos()); |
| 274 | 292 |
| 275 // FIXME: This is a horrible hack since PlatformMouseEvent has no setters fo r x/y. | 293 // FIXME: This is a horrible hack since PlatformMouseEvent has no setters fo r x/y. |
| 276 PlatformMouseEvent relativeEvent = e; | 294 PlatformMouseEvent relativeEvent = e; |
| (...skipping 204 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 481 void PopupContainer::setTextOnIndexChange(bool value) | 499 void PopupContainer::setTextOnIndexChange(bool value) |
| 482 { | 500 { |
| 483 listBox()->setTextOnIndexChange(value); | 501 listBox()->setTextOnIndexChange(value); |
| 484 } | 502 } |
| 485 | 503 |
| 486 void PopupContainer::setAcceptOnAbandon(bool value) | 504 void PopupContainer::setAcceptOnAbandon(bool value) |
| 487 { | 505 { |
| 488 listBox()->setAcceptOnAbandon(value); | 506 listBox()->setAcceptOnAbandon(value); |
| 489 } | 507 } |
| 490 | 508 |
| 509 void PopupContainer::setLoopSelectionNavigation(bool value) { | |
| 510 listBox()->setLoopSelectionNavigation(value); | |
| 511 } | |
| 512 | |
| 491 void PopupContainer::refresh() | 513 void PopupContainer::refresh() |
| 492 { | 514 { |
| 493 listBox()->updateFromElement(); | 515 listBox()->updateFromElement(); |
| 494 layout(); | 516 layout(); |
| 495 } | 517 } |
| 496 | 518 |
| 497 /////////////////////////////////////////////////////////////////////////////// | 519 /////////////////////////////////////////////////////////////////////////////// |
| 498 // PopupListBox implementation | 520 // PopupListBox implementation |
| 499 | 521 |
| 500 bool PopupListBox::handleMouseDownEvent(const PlatformMouseEvent& event) | 522 bool PopupListBox::handleMouseDownEvent(const PlatformMouseEvent& event) |
| (...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 592 return true; | 614 return true; |
| 593 | 615 |
| 594 if (numItems() == 0 && event.windowsVirtualKeyCode() != VKEY_ESCAPE) | 616 if (numItems() == 0 && event.windowsVirtualKeyCode() != VKEY_ESCAPE) |
| 595 return true; | 617 return true; |
| 596 | 618 |
| 597 switch (event.windowsVirtualKeyCode()) { | 619 switch (event.windowsVirtualKeyCode()) { |
| 598 case VKEY_ESCAPE: | 620 case VKEY_ESCAPE: |
| 599 abandon(); // may delete this | 621 abandon(); // may delete this |
| 600 return true; | 622 return true; |
| 601 case VKEY_RETURN: | 623 case VKEY_RETURN: |
| 624 if (m_selectedIndex == -1) { | |
| 625 m_popupClient->hidePopup(); | |
| 626 // Don't eat the enter if nothing is selected. | |
|
Matt Perry
2009/01/21 22:38:09
Seems strange to me that the enter would propagate
| |
| 627 return false; | |
| 628 } | |
| 602 acceptIndex(m_selectedIndex); // may delete this | 629 acceptIndex(m_selectedIndex); // may delete this |
| 603 return true; | 630 return true; |
| 604 case VKEY_UP: | 631 case VKEY_UP: |
| 605 adjustSelectedIndex(-1); | 632 selectPreviousRow(); |
| 606 break; | 633 break; |
| 607 case VKEY_DOWN: | 634 case VKEY_DOWN: |
| 608 adjustSelectedIndex(1); | 635 selectNextRow(); |
| 609 break; | 636 break; |
| 610 case VKEY_PRIOR: | 637 case VKEY_PRIOR: |
| 611 adjustSelectedIndex(-m_visibleRows); | 638 adjustSelectedIndex(-m_visibleRows); |
| 612 break; | 639 break; |
| 613 case VKEY_NEXT: | 640 case VKEY_NEXT: |
| 614 adjustSelectedIndex(m_visibleRows); | 641 adjustSelectedIndex(m_visibleRows); |
| 615 break; | 642 break; |
| 616 case VKEY_HOME: | 643 case VKEY_HOME: |
| 617 adjustSelectedIndex(-m_selectedIndex); | 644 adjustSelectedIndex(-m_selectedIndex); |
| 618 break; | 645 break; |
| (...skipping 312 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 931 } else if (rowRect.bottom() > scrollY() + visibleHeight()) { | 958 } else if (rowRect.bottom() > scrollY() + visibleHeight()) { |
| 932 // Row is below current scroll position, scroll down. | 959 // Row is below current scroll position, scroll down. |
| 933 ScrollView::setScrollPosition(IntPoint(0, rowRect.bottom() - visibleHeig ht())); | 960 ScrollView::setScrollPosition(IntPoint(0, rowRect.bottom() - visibleHeig ht())); |
| 934 } | 961 } |
| 935 } | 962 } |
| 936 | 963 |
| 937 bool PopupListBox::isSelectableItem(int index) { | 964 bool PopupListBox::isSelectableItem(int index) { |
| 938 return m_items[index]->type == TypeOption && m_popupClient->itemIsEnabled(in dex); | 965 return m_items[index]->type == TypeOption && m_popupClient->itemIsEnabled(in dex); |
| 939 } | 966 } |
| 940 | 967 |
| 968 void PopupListBox::clearSelection() { | |
| 969 if (m_selectedIndex != -1) { | |
| 970 invalidateRow(m_selectedIndex); | |
| 971 m_selectedIndex = -1; | |
| 972 } | |
| 973 } | |
| 974 | |
| 975 void PopupListBox::selectNextRow() { | |
| 976 if (!m_loopSelectionNavigation || m_selectedIndex != numItems() - 1) { | |
| 977 adjustSelectedIndex(1); | |
| 978 return; | |
| 979 } | |
| 980 | |
| 981 // We are moving past the last item, no row should be selected. | |
| 982 clearSelection(); | |
| 983 } | |
| 984 | |
| 985 void PopupListBox::selectPreviousRow() { | |
| 986 if (!m_loopSelectionNavigation || m_selectedIndex > 0) { | |
| 987 adjustSelectedIndex(-1); | |
| 988 return; | |
| 989 } | |
| 990 | |
| 991 if (m_selectedIndex == 0) { | |
| 992 // We are moving past the first item, clear the selection. | |
| 993 clearSelection(); | |
| 994 return; | |
| 995 } | |
| 996 | |
| 997 // No row are selected, jump to the last item. | |
| 998 selectIndex(numItems() - 1); | |
| 999 scrollToRevealSelection(); | |
| 1000 } | |
| 1001 | |
| 941 void PopupListBox::adjustSelectedIndex(int delta) | 1002 void PopupListBox::adjustSelectedIndex(int delta) |
| 942 { | 1003 { |
| 943 int targetIndex = m_selectedIndex + delta; | 1004 int targetIndex = m_selectedIndex + delta; |
| 944 targetIndex = min(max(targetIndex, 0), numItems() - 1); | 1005 targetIndex = min(max(targetIndex, 0), numItems() - 1); |
| 945 if (!isSelectableItem(targetIndex)) { | 1006 if (!isSelectableItem(targetIndex)) { |
| 946 // We didn't land on an option. Try to find one. | 1007 // We didn't land on an option. Try to find one. |
| 947 // We try to select the closest index to target, prioritizing any in | 1008 // We try to select the closest index to target, prioritizing any in |
| 948 // the range [current, target]. | 1009 // the range [current, target]. |
| 949 | 1010 |
| 950 int dir = delta > 0 ? 1 : -1; | 1011 int dir = delta > 0 ? 1 : -1; |
| (...skipping 159 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1110 { | 1171 { |
| 1111 p.popup->listBox()->updateFromElement(); | 1172 p.popup->listBox()->updateFromElement(); |
| 1112 } | 1173 } |
| 1113 | 1174 |
| 1114 bool PopupMenu::itemWritingDirectionIsNatural() | 1175 bool PopupMenu::itemWritingDirectionIsNatural() |
| 1115 { | 1176 { |
| 1116 return false; | 1177 return false; |
| 1117 } | 1178 } |
| 1118 | 1179 |
| 1119 } // namespace WebCore | 1180 } // namespace WebCore |
| OLD | NEW |