• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2011, Google Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are
6  * met:
7  *
8  *     * Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  *     * Redistributions in binary form must reproduce the above
11  * copyright notice, this list of conditions and the following disclaimer
12  * in the documentation and/or other materials provided with the
13  * distribution.
14  *     * Neither the name of Google Inc. nor the names of its
15  * contributors may be used to endorse or promote products derived from
16  * this software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  */
30 
31 #ifndef PopupListBox_h
32 #define PopupListBox_h
33 
34 #include "core/dom/Element.h"
35 #include "platform/scroll/FramelessScrollView.h"
36 #include "platform/text/TextDirection.h"
37 #include "wtf/text/WTFString.h"
38 
39 namespace WebCore {
40 
41 typedef unsigned long long TimeStamp;
42 
43 class Font;
44 class GraphicsContext;
45 class IntRect;
46 class PlatformKeyboardEvent;
47 class PlatformMouseEvent;
48 class PlatformGestureEvent;
49 class PlatformTouchEvent;
50 class PlatformWheelEvent;
51 class PopupMenuClient;
52 
53 struct PopupContainerSettings {
54     // Whether the PopupMenuClient should be told to change its text when a
55     // new item is selected by using the arrow keys.
56     bool setTextOnIndexChange;
57 
58     // Whether the selection should be accepted when the popup menu is
59     // closed (through ESC being pressed or the focus going away).
60     // Note that when TAB is pressed, the selection is always accepted
61     // regardless of this setting.
62     bool acceptOnAbandon;
63 
64     // Whether we should move the selection to the first/last item when
65     // the user presses down/up arrow keys and the last/first item is
66     // selected.
67     bool loopSelectionNavigation;
68 
69     // Whether we should restrict the width of the PopupListBox or not.
70     // Autocomplete popups are restricted, combo-boxes (select tags) aren't.
71     bool restrictWidthOfListBox;
72 
73     // If the device is a touch screen we increase the height of menu items
74     // to make it easier to unambiguously touch them.
75     bool deviceSupportsTouch;
76 };
77 
78 class PopupContent {
79 public:
80     virtual void layout() = 0;
81     virtual void setMaxHeight(int) = 0;
82     virtual void setMaxWidthAndLayout(int) = 0;
83     virtual int popupContentHeight() const = 0;
~PopupContent()84     virtual ~PopupContent() { };
85 };
86 
87 // A container for the data for each menu item (e.g. represented by <option>
88 // or <optgroup> in a <select> widget) and is used by PopupListBox.
89 struct PopupItem {
90     enum Type {
91         TypeOption,
92         TypeGroup,
93         TypeSeparator
94     };
95 
PopupItemPopupItem96     PopupItem(const String& label, Type type)
97         : label(label)
98         , type(type)
99         , yOffset(0)
100     {
101     }
102     String label;
103     Type type;
104     int yOffset; // y offset of this item, relative to the top of the popup.
105     TextDirection textDirection;
106     bool hasTextDirectionOverride;
107     bool enabled;
108 };
109 
110 // This class uses WebCore code to paint and handle events for a drop-down list
111 // box ("combobox" on Windows).
112 class PopupListBox : public FramelessScrollView, public PopupContent {
113 public:
create(PopupMenuClient * client,const PopupContainerSettings & settings)114     static PassRefPtr<PopupListBox> create(PopupMenuClient* client, const PopupContainerSettings& settings)
115     {
116         return adoptRef(new PopupListBox(client, settings));
117     }
118 
119     // FramelessScrollView
120     virtual void paint(GraphicsContext*, const IntRect&) OVERRIDE;
121     virtual bool handleMouseDownEvent(const PlatformMouseEvent&) OVERRIDE;
122     virtual bool handleMouseMoveEvent(const PlatformMouseEvent&) OVERRIDE;
123     virtual bool handleMouseReleaseEvent(const PlatformMouseEvent&) OVERRIDE;
124     virtual bool handleWheelEvent(const PlatformWheelEvent&) OVERRIDE;
125     virtual bool handleKeyEvent(const PlatformKeyboardEvent&) OVERRIDE;
126     virtual bool handleTouchEvent(const PlatformTouchEvent&) OVERRIDE;
127     virtual bool handleGestureEvent(const PlatformGestureEvent&) OVERRIDE;
128 
129     // ScrollView
130     virtual HostWindow* hostWindow() const OVERRIDE;
131     virtual bool shouldPlaceVerticalScrollbarOnLeft() const OVERRIDE;
132 
133     // PopupListBox methods
134 
135     // Closes the popup
136     void abandon();
137 
138     // Updates our internal list to match the client.
139     void updateFromElement();
140 
141     // Frees any allocated resources used in a particular popup session.
142     void clear();
143 
144     // Sets the index of the option that is displayed in the <select> widget in the page
145     void setOriginalIndex(int);
146 
147     // Gets the index of the item that the user is currently moused over or has
148     // selected with the keyboard. This is not the same as the original index,
149     // since the user has not yet accepted this input.
selectedIndex()150     int selectedIndex() const { return m_selectedIndex; }
151 
152     // Moves selection down/up the given number of items, scrolling if necessary.
153     // Positive is down. The resulting index will be clamped to the range
154     // [0, numItems), and non-option items will be skipped.
155     void adjustSelectedIndex(int delta);
156 
157     // Returns the number of items in the list.
numItems()158     int numItems() const { return static_cast<int>(m_items.size()); }
159 
setBaseWidth(int width)160     void setBaseWidth(int width) { m_baseWidth = std::min(m_maxWindowWidth, width); }
161 
162     // Computes the size of widget and children.
163     virtual void layout() OVERRIDE;
164 
165     // Returns whether the popup wants to process events for the passed key.
166     bool isInterestedInEventForKey(int keyCode);
167 
168     // Gets the height of a row.
169     int getRowHeight(int index);
170 
setMaxHeight(int maxHeight)171     virtual void setMaxHeight(int maxHeight) OVERRIDE { m_maxHeight = maxHeight; }
172 
setMaxWidth(int maxWidth)173     void setMaxWidth(int maxWidth) { m_maxWindowWidth = maxWidth; }
174 
175     virtual void setMaxWidthAndLayout(int) OVERRIDE;
176 
disconnectClient()177     void disconnectClient() { m_popupClient = 0; }
178 
items()179     const Vector<PopupItem*>& items() const { return m_items; }
180 
181     virtual int popupContentHeight() const OVERRIDE;
182 
183     static const int defaultMaxHeight;
184 
185 private:
186     friend class PopupContainer;
187     friend class RefCounted<PopupListBox>;
188 
189     PopupListBox(PopupMenuClient*, const PopupContainerSettings&);
190 
~PopupListBox()191     virtual ~PopupListBox()
192     {
193         clear();
194     }
195 
196     // Hides the popup. Other classes should not call this. Use abandon instead.
197     void hidePopup();
198 
199     // Returns true if the selection can be changed to index.
200     // Disabled items, or labels cannot be selected.
201     bool isSelectableItem(int index);
202 
203     // Select an index in the list, scrolling if necessary.
204     void selectIndex(int index);
205 
206     // Accepts the selected index as the value to be displayed in the <select>
207     // widget on the web page, and closes the popup. Returns true if index is
208     // accepted.
209     bool acceptIndex(int index);
210 
211     // Clears the selection (so no row appears selected).
212     void clearSelection();
213 
214     // Scrolls to reveal the given index.
215     void scrollToRevealRow(int index);
scrollToRevealSelection()216     void scrollToRevealSelection() { scrollToRevealRow(m_selectedIndex); }
217 
218     // Invalidates the row at the given index.
219     void invalidateRow(int index);
220 
221     // Get the bounds of a row.
222     IntRect getRowBounds(int index);
223 
224     // Converts a point to an index of the row the point is over
225     int pointToRowIndex(const IntPoint&);
226 
227     // Paint an individual row
228     void paintRow(GraphicsContext*, const IntRect&, int rowIndex);
229 
230     // Test if the given point is within the bounds of the popup window.
231     bool isPointInBounds(const IntPoint&);
232 
233     // Called when the user presses a text key. Does a prefix-search of the items.
234     void typeAheadFind(const PlatformKeyboardEvent&);
235 
236     // Returns the font to use for the given row
237     Font getRowFont(int index);
238 
239     // Moves the selection down/up one item, taking care of looping back to the
240     // first/last element if m_loopSelectionNavigation is true.
241     void selectPreviousRow();
242     void selectNextRow();
243 
244     // The settings that specify the behavior for this Popup window.
245     PopupContainerSettings m_settings;
246 
247     // This is the index of the item marked as "selected" - i.e. displayed in
248     // the widget on the page.
249     int m_originalIndex;
250 
251     // This is the index of the item that the user is hovered over or has
252     // selected using the keyboard in the list. They have not confirmed this
253     // selection by clicking or pressing enter yet however.
254     int m_selectedIndex;
255 
256     // If >= 0, this is the index we should accept if the popup is "abandoned".
257     // This is used for keyboard navigation, where we want the
258     // selection to change immediately, and is only used if the settings
259     // acceptOnAbandon field is true.
260     int m_acceptedIndexOnAbandon;
261 
262     // This is the number of rows visible in the popup. The maximum number
263     // visible at a time is defined as being kMaxVisibleRows. For a scrolled
264     // popup, this can be thought of as the page size in data units.
265     int m_visibleRows;
266 
267     // Our suggested width, not including scrollbar.
268     int m_baseWidth;
269 
270     // The maximum height we can be without being off-screen.
271     int m_maxHeight;
272 
273     // A list of the options contained within the <select>
274     Vector<PopupItem*> m_items;
275 
276     // The <select> PopupMenuClient that opened us.
277     PopupMenuClient* m_popupClient;
278 
279     // The scrollbar which has mouse capture. Mouse events go straight to this
280     // if not null.
281     RefPtr<Scrollbar> m_capturingScrollbar;
282 
283     // The last scrollbar that the mouse was over. Used for mouseover highlights.
284     RefPtr<Scrollbar> m_lastScrollbarUnderMouse;
285 
286     // The string the user has typed so far into the popup. Used for typeAheadFind.
287     String m_typedString;
288 
289     // The char the user has hit repeatedly. Used for typeAheadFind.
290     UChar m_repeatingChar;
291 
292     // The last time the user hit a key. Used for typeAheadFind.
293     TimeStamp m_lastCharTime;
294 
295     // If width exeeds screen width, we have to clip it.
296     int m_maxWindowWidth;
297 
298     // To forward last mouse release event.
299     RefPtr<Element> m_focusedElement;
300 };
301 
302 } // namespace WebCore
303 
304 #endif
305