• 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 class Font;
41 class GraphicsContext;
42 class IntRect;
43 class PlatformKeyboardEvent;
44 class PlatformMouseEvent;
45 class PlatformGestureEvent;
46 class PlatformTouchEvent;
47 class PlatformWheelEvent;
48 class PopupMenuClient;
49 }
50 
51 namespace blink {
52 
53 typedef unsigned long long TimeStamp;
54 
55 class PopupContent {
56 public:
57     virtual void layout() = 0;
58     virtual void setMaxHeight(int) = 0;
59     virtual void setMaxWidthAndLayout(int) = 0;
60     virtual int popupContentHeight() const = 0;
~PopupContent()61     virtual ~PopupContent() { };
62 };
63 
64 // A container for the data for each menu item (e.g. represented by <option>
65 // or <optgroup> in a <select> widget) and is used by PopupListBox.
66 struct PopupItem {
67     enum Type {
68         TypeOption,
69         TypeGroup,
70         TypeSeparator
71     };
72 
PopupItemPopupItem73     PopupItem(const String& label, Type type)
74         : label(label)
75         , type(type)
76         , yOffset(0)
77     {
78     }
79     String label;
80     Type type;
81     int yOffset; // y offset of this item, relative to the top of the popup.
82     WebCore::TextDirection textDirection;
83     bool hasTextDirectionOverride;
84     bool enabled;
85 };
86 
87 // This class uses WebCore code to paint and handle events for a drop-down list
88 // box ("combobox" on Windows).
89 class PopupListBox FINAL : public WebCore::FramelessScrollView, public PopupContent {
90 public:
create(WebCore::PopupMenuClient * client,bool deviceSupportsTouch)91     static PassRefPtr<PopupListBox> create(WebCore::PopupMenuClient* client, bool deviceSupportsTouch)
92     {
93         return adoptRef(new PopupListBox(client, deviceSupportsTouch));
94     }
95 
96     // FramelessScrollView
97     virtual void paint(WebCore::GraphicsContext*, const WebCore::IntRect&) OVERRIDE;
98     virtual bool handleMouseDownEvent(const WebCore::PlatformMouseEvent&) OVERRIDE;
99     virtual bool handleMouseMoveEvent(const WebCore::PlatformMouseEvent&) OVERRIDE;
100     virtual bool handleMouseReleaseEvent(const WebCore::PlatformMouseEvent&) OVERRIDE;
101     virtual bool handleWheelEvent(const WebCore::PlatformWheelEvent&) OVERRIDE;
102     virtual bool handleKeyEvent(const WebCore::PlatformKeyboardEvent&) OVERRIDE;
103     virtual bool handleTouchEvent(const WebCore::PlatformTouchEvent&) OVERRIDE;
104     virtual bool handleGestureEvent(const WebCore::PlatformGestureEvent&) OVERRIDE;
105 
106     // ScrollView
107     virtual WebCore::HostWindow* hostWindow() const OVERRIDE;
108     virtual bool shouldPlaceVerticalScrollbarOnLeft() const OVERRIDE;
109 
110     // PopupListBox methods
111 
112     // Closes the popup
113     void abandon();
114 
115     // Updates our internal list to match the client.
116     void updateFromElement();
117 
118     // Frees any allocated resources used in a particular popup session.
119     void clear();
120 
121     // Sets the index of the option that is displayed in the <select> widget in the page
122     void setOriginalIndex(int);
123 
124     // Gets the index of the item that the user is currently moused over or has
125     // selected with the keyboard. This is not the same as the original index,
126     // since the user has not yet accepted this input.
selectedIndex()127     int selectedIndex() const { return m_selectedIndex; }
128 
129     // Moves selection down/up the given number of items, scrolling if necessary.
130     // Positive is down. The resulting index will be clamped to the range
131     // [0, numItems), and non-option items will be skipped.
132     void adjustSelectedIndex(int delta);
133 
134     // Returns the number of items in the list.
numItems()135     int numItems() const { return static_cast<int>(m_items.size()); }
136 
setBaseWidth(int width)137     void setBaseWidth(int width) { m_baseWidth = std::min(m_maxWindowWidth, width); }
138 
139     // Computes the size of widget and children.
140     virtual void layout() OVERRIDE;
141 
142     // Returns whether the popup wants to process events for the passed key.
143     bool isInterestedInEventForKey(int keyCode);
144 
145     // Gets the height of a row.
146     int getRowHeight(int index);
147 
setMaxHeight(int maxHeight)148     virtual void setMaxHeight(int maxHeight) OVERRIDE { m_maxHeight = maxHeight; }
149 
setMaxWidth(int maxWidth)150     void setMaxWidth(int maxWidth) { m_maxWindowWidth = maxWidth; }
151 
152     virtual void setMaxWidthAndLayout(int) OVERRIDE;
153 
disconnectClient()154     void disconnectClient() { m_popupClient = 0; }
155 
items()156     const Vector<PopupItem*>& items() const { return m_items; }
157 
158     virtual int popupContentHeight() const OVERRIDE;
159 
160     static const int defaultMaxHeight;
161 
162 private:
163     friend class PopupContainer;
164     friend class RefCounted<PopupListBox>;
165 
166     PopupListBox(WebCore::PopupMenuClient*, bool deviceSupportsTouch);
167 
~PopupListBox()168     virtual ~PopupListBox()
169     {
170         clear();
171     }
172 
173     // Hides the popup. Other classes should not call this. Use abandon instead.
174     void hidePopup();
175 
176     // Returns true if the selection can be changed to index.
177     // Disabled items, or labels cannot be selected.
178     bool isSelectableItem(int index);
179 
180     // Select an index in the list, scrolling if necessary.
181     void selectIndex(int index);
182 
183     // Accepts the selected index as the value to be displayed in the <select>
184     // widget on the web page, and closes the popup. Returns true if index is
185     // accepted.
186     bool acceptIndex(int index);
187 
188     // Clears the selection (so no row appears selected).
189     void clearSelection();
190 
191     // Scrolls to reveal the given index.
192     void scrollToRevealRow(int index);
scrollToRevealSelection()193     void scrollToRevealSelection() { scrollToRevealRow(m_selectedIndex); }
194 
195     // Invalidates the row at the given index.
196     void invalidateRow(int index);
197 
198     // Get the bounds of a row.
199     WebCore::IntRect getRowBounds(int index);
200 
201     // Converts a point to an index of the row the point is over
202     int pointToRowIndex(const WebCore::IntPoint&);
203 
204     // Paint an individual row
205     void paintRow(WebCore::GraphicsContext*, const WebCore::IntRect&, int rowIndex);
206 
207     // Test if the given point is within the bounds of the popup window.
208     bool isPointInBounds(const WebCore::IntPoint&);
209 
210     // Called when the user presses a text key. Does a prefix-search of the items.
211     void typeAheadFind(const WebCore::PlatformKeyboardEvent&);
212 
213     // Returns the font to use for the given row
214     WebCore::Font getRowFont(int index);
215 
216     // Moves the selection down/up one item, taking care of looping back to the
217     // first/last element if m_loopSelectionNavigation is true.
218     void selectPreviousRow();
219     void selectNextRow();
220 
221     // If the device is a touch screen we increase the height of menu items
222     // to make it easier to unambiguously touch them.
223     bool m_deviceSupportsTouch;
224 
225     // This is the index of the item marked as "selected" - i.e. displayed in
226     // the widget on the page.
227     int m_originalIndex;
228 
229     // This is the index of the item that the user is hovered over or has
230     // selected using the keyboard in the list. They have not confirmed this
231     // selection by clicking or pressing enter yet however.
232     int m_selectedIndex;
233 
234     // If >= 0, this is the index we should accept if the popup is "abandoned".
235     // This is used for keyboard navigation, where we want the
236     // selection to change immediately, and is only used if the settings
237     // acceptOnAbandon field is true.
238     int m_acceptedIndexOnAbandon;
239 
240     // This is the number of rows visible in the popup. The maximum number
241     // visible at a time is defined as being kMaxVisibleRows. For a scrolled
242     // popup, this can be thought of as the page size in data units.
243     int m_visibleRows;
244 
245     // Our suggested width, not including scrollbar.
246     int m_baseWidth;
247 
248     // The maximum height we can be without being off-screen.
249     int m_maxHeight;
250 
251     // A list of the options contained within the <select>
252     Vector<PopupItem*> m_items;
253 
254     // The <select> PopupMenuClient that opened us.
255     WebCore::PopupMenuClient* m_popupClient;
256 
257     // The scrollbar which has mouse capture. Mouse events go straight to this
258     // if not null.
259     RefPtr<WebCore::Scrollbar> m_capturingScrollbar;
260 
261     // The last scrollbar that the mouse was over. Used for mouseover highlights.
262     RefPtr<WebCore::Scrollbar> m_lastScrollbarUnderMouse;
263 
264     // The string the user has typed so far into the popup. Used for typeAheadFind.
265     String m_typedString;
266 
267     // The char the user has hit repeatedly. Used for typeAheadFind.
268     UChar m_repeatingChar;
269 
270     // The last time the user hit a key. Used for typeAheadFind.
271     TimeStamp m_lastCharTime;
272 
273     // If width exeeds screen width, we have to clip it.
274     int m_maxWindowWidth;
275 
276     // To forward last mouse release event.
277     RefPtrWillBePersistent<WebCore::Element> m_focusedElement;
278 };
279 
280 } // namespace blink
281 
282 #endif
283