| /* |
| * Copyright (c) 2011, Google Inc. All rights reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions are |
| * met: |
| * |
| * * Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * * Redistributions in binary form must reproduce the above |
| * copyright notice, this list of conditions and the following disclaimer |
| * in the documentation and/or other materials provided with the |
| * distribution. |
| * * Neither the name of Google Inc. nor the names of its |
| * contributors may be used to endorse or promote products derived from |
| * this software without specific prior written permission. |
| * |
| * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
| * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| */ |
| |
| #ifndef PopupListBox_h |
| #define PopupListBox_h |
| |
| #include "core/dom/Element.h" |
| #include "platform/scroll/FramelessScrollView.h" |
| #include "platform/text/TextDirection.h" |
| #include "wtf/text/WTFString.h" |
| |
| namespace WebCore { |
| class Font; |
| class GraphicsContext; |
| class IntRect; |
| class PlatformKeyboardEvent; |
| class PlatformMouseEvent; |
| class PlatformGestureEvent; |
| class PlatformTouchEvent; |
| class PlatformWheelEvent; |
| class PopupMenuClient; |
| } |
| |
| namespace blink { |
| |
| typedef unsigned long long TimeStamp; |
| |
| class PopupContent { |
| public: |
| virtual void layout() = 0; |
| virtual void setMaxHeight(int) = 0; |
| virtual void setMaxWidthAndLayout(int) = 0; |
| virtual int popupContentHeight() const = 0; |
| virtual ~PopupContent() { }; |
| }; |
| |
| // A container for the data for each menu item (e.g. represented by <option> |
| // or <optgroup> in a <select> widget) and is used by PopupListBox. |
| struct PopupItem { |
| enum Type { |
| TypeOption, |
| TypeGroup, |
| TypeSeparator |
| }; |
| |
| PopupItem(const String& label, Type type) |
| : label(label) |
| , type(type) |
| , yOffset(0) |
| { |
| } |
| String label; |
| Type type; |
| int yOffset; // y offset of this item, relative to the top of the popup. |
| WebCore::TextDirection textDirection; |
| bool hasTextDirectionOverride; |
| bool enabled; |
| }; |
| |
| // This class uses WebCore code to paint and handle events for a drop-down list |
| // box ("combobox" on Windows). |
| class PopupListBox FINAL : public WebCore::FramelessScrollView, public PopupContent { |
| public: |
| static PassRefPtr<PopupListBox> create(WebCore::PopupMenuClient* client, bool deviceSupportsTouch) |
| { |
| return adoptRef(new PopupListBox(client, deviceSupportsTouch)); |
| } |
| |
| // FramelessScrollView |
| virtual void paint(WebCore::GraphicsContext*, const WebCore::IntRect&) OVERRIDE; |
| virtual bool handleMouseDownEvent(const WebCore::PlatformMouseEvent&) OVERRIDE; |
| virtual bool handleMouseMoveEvent(const WebCore::PlatformMouseEvent&) OVERRIDE; |
| virtual bool handleMouseReleaseEvent(const WebCore::PlatformMouseEvent&) OVERRIDE; |
| virtual bool handleWheelEvent(const WebCore::PlatformWheelEvent&) OVERRIDE; |
| virtual bool handleKeyEvent(const WebCore::PlatformKeyboardEvent&) OVERRIDE; |
| virtual bool handleTouchEvent(const WebCore::PlatformTouchEvent&) OVERRIDE; |
| virtual bool handleGestureEvent(const WebCore::PlatformGestureEvent&) OVERRIDE; |
| |
| // ScrollView |
| virtual WebCore::HostWindow* hostWindow() const OVERRIDE; |
| virtual bool shouldPlaceVerticalScrollbarOnLeft() const OVERRIDE; |
| |
| // PopupListBox methods |
| |
| // Closes the popup |
| void abandon(); |
| |
| // Updates our internal list to match the client. |
| void updateFromElement(); |
| |
| // Frees any allocated resources used in a particular popup session. |
| void clear(); |
| |
| // Sets the index of the option that is displayed in the <select> widget in the page |
| void setOriginalIndex(int); |
| |
| // Gets the index of the item that the user is currently moused over or has |
| // selected with the keyboard. This is not the same as the original index, |
| // since the user has not yet accepted this input. |
| int selectedIndex() const { return m_selectedIndex; } |
| |
| // Moves selection down/up the given number of items, scrolling if necessary. |
| // Positive is down. The resulting index will be clamped to the range |
| // [0, numItems), and non-option items will be skipped. |
| void adjustSelectedIndex(int delta); |
| |
| // Returns the number of items in the list. |
| int numItems() const { return static_cast<int>(m_items.size()); } |
| |
| void setBaseWidth(int width) { m_baseWidth = std::min(m_maxWindowWidth, width); } |
| |
| // Computes the size of widget and children. |
| virtual void layout() OVERRIDE; |
| |
| // Returns whether the popup wants to process events for the passed key. |
| bool isInterestedInEventForKey(int keyCode); |
| |
| // Gets the height of a row. |
| int getRowHeight(int index); |
| |
| virtual void setMaxHeight(int maxHeight) OVERRIDE { m_maxHeight = maxHeight; } |
| |
| void setMaxWidth(int maxWidth) { m_maxWindowWidth = maxWidth; } |
| |
| virtual void setMaxWidthAndLayout(int) OVERRIDE; |
| |
| void disconnectClient() { m_popupClient = 0; } |
| |
| const Vector<PopupItem*>& items() const { return m_items; } |
| |
| virtual int popupContentHeight() const OVERRIDE; |
| |
| static const int defaultMaxHeight; |
| |
| private: |
| friend class PopupContainer; |
| friend class RefCounted<PopupListBox>; |
| |
| PopupListBox(WebCore::PopupMenuClient*, bool deviceSupportsTouch); |
| |
| virtual ~PopupListBox() |
| { |
| clear(); |
| } |
| |
| // Hides the popup. Other classes should not call this. Use abandon instead. |
| void hidePopup(); |
| |
| // Returns true if the selection can be changed to index. |
| // Disabled items, or labels cannot be selected. |
| bool isSelectableItem(int index); |
| |
| // Select an index in the list, scrolling if necessary. |
| void selectIndex(int index); |
| |
| // Accepts the selected index as the value to be displayed in the <select> |
| // widget on the web page, and closes the popup. Returns true if index is |
| // accepted. |
| bool acceptIndex(int index); |
| |
| // Clears the selection (so no row appears selected). |
| void clearSelection(); |
| |
| // Scrolls to reveal the given index. |
| void scrollToRevealRow(int index); |
| void scrollToRevealSelection() { scrollToRevealRow(m_selectedIndex); } |
| |
| // Invalidates the row at the given index. |
| void invalidateRow(int index); |
| |
| // Get the bounds of a row. |
| WebCore::IntRect getRowBounds(int index); |
| |
| // Converts a point to an index of the row the point is over |
| int pointToRowIndex(const WebCore::IntPoint&); |
| |
| // Paint an individual row |
| void paintRow(WebCore::GraphicsContext*, const WebCore::IntRect&, int rowIndex); |
| |
| // Test if the given point is within the bounds of the popup window. |
| bool isPointInBounds(const WebCore::IntPoint&); |
| |
| // Called when the user presses a text key. Does a prefix-search of the items. |
| void typeAheadFind(const WebCore::PlatformKeyboardEvent&); |
| |
| // Returns the font to use for the given row |
| WebCore::Font getRowFont(int index); |
| |
| // Moves the selection down/up one item, taking care of looping back to the |
| // first/last element if m_loopSelectionNavigation is true. |
| void selectPreviousRow(); |
| void selectNextRow(); |
| |
| // If the device is a touch screen we increase the height of menu items |
| // to make it easier to unambiguously touch them. |
| bool m_deviceSupportsTouch; |
| |
| // This is the index of the item marked as "selected" - i.e. displayed in |
| // the widget on the page. |
| int m_originalIndex; |
| |
| // This is the index of the item that the user is hovered over or has |
| // selected using the keyboard in the list. They have not confirmed this |
| // selection by clicking or pressing enter yet however. |
| int m_selectedIndex; |
| |
| // If >= 0, this is the index we should accept if the popup is "abandoned". |
| // This is used for keyboard navigation, where we want the |
| // selection to change immediately, and is only used if the settings |
| // acceptOnAbandon field is true. |
| int m_acceptedIndexOnAbandon; |
| |
| // This is the number of rows visible in the popup. The maximum number |
| // visible at a time is defined as being kMaxVisibleRows. For a scrolled |
| // popup, this can be thought of as the page size in data units. |
| int m_visibleRows; |
| |
| // Our suggested width, not including scrollbar. |
| int m_baseWidth; |
| |
| // The maximum height we can be without being off-screen. |
| int m_maxHeight; |
| |
| // A list of the options contained within the <select> |
| Vector<PopupItem*> m_items; |
| |
| // The <select> PopupMenuClient that opened us. |
| WebCore::PopupMenuClient* m_popupClient; |
| |
| // The scrollbar which has mouse capture. Mouse events go straight to this |
| // if not null. |
| RefPtr<WebCore::Scrollbar> m_capturingScrollbar; |
| |
| // The last scrollbar that the mouse was over. Used for mouseover highlights. |
| RefPtr<WebCore::Scrollbar> m_lastScrollbarUnderMouse; |
| |
| // The string the user has typed so far into the popup. Used for typeAheadFind. |
| String m_typedString; |
| |
| // The char the user has hit repeatedly. Used for typeAheadFind. |
| UChar m_repeatingChar; |
| |
| // The last time the user hit a key. Used for typeAheadFind. |
| TimeStamp m_lastCharTime; |
| |
| // If width exeeds screen width, we have to clip it. |
| int m_maxWindowWidth; |
| |
| // To forward last mouse release event. |
| RefPtrWillBePersistent<WebCore::Element> m_focusedElement; |
| }; |
| |
| } // namespace blink |
| |
| #endif |