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 |