📄 popupmenuchromium.cpp
字号:
/* * Copyright (c) 2008, 2009, 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. */#include "config.h"#include "PopupMenuChromium.h"#include "CharacterNames.h"#include "ChromeClientChromium.h"#include "Font.h"#include "FontSelector.h"#include "FrameView.h"#include "Frame.h"#include "FramelessScrollView.h"#include "FramelessScrollViewClient.h"#include "GraphicsContext.h"#include "IntRect.h"#include "KeyboardCodes.h"#include "Page.h"#include "PlatformKeyboardEvent.h"#include "PlatformMouseEvent.h"#include "PlatformScreen.h"#include "PlatformWheelEvent.h"#include "PopupMenu.h"#include "RenderTheme.h"#include "ScrollbarTheme.h"#include "SystemTime.h"#include <wtf/CurrentTime.h>using namespace WTF;using namespace Unicode;using std::min;using std::max;namespace WebCore {typedef unsigned long long TimeStamp;static const int kMaxVisibleRows = 20;static const int kMaxHeight = 500;static const int kBorderSize = 1;static const TimeStamp kTypeAheadTimeoutMs = 1000;// The settings used for the drop down menu.// This is the delegate used if none is provided.static const PopupContainerSettings dropDownSettings = { true, // focusOnShow true, // setTextOnIndexChange true, // acceptOnAbandon false // loopSelectionNavigation};// This class uses WebCore code to paint and handle events for a drop-down list// box ("combobox" on Windows).class PopupListBox : public FramelessScrollView, public RefCounted<PopupListBox> {public: static PassRefPtr<PopupListBox> create(PopupMenuClient* client, const PopupContainerSettings& settings) { return adoptRef(new PopupListBox(client, settings)); } // FramelessScrollView virtual void paint(GraphicsContext*, const IntRect&); virtual bool handleMouseDownEvent(const PlatformMouseEvent&); virtual bool handleMouseMoveEvent(const PlatformMouseEvent&); virtual bool handleMouseReleaseEvent(const PlatformMouseEvent&); virtual bool handleWheelEvent(const PlatformWheelEvent&); virtual bool handleKeyEvent(const PlatformKeyboardEvent&); // ScrollView virtual HostWindow* hostWindow() const; // PopupListBox methods // Shows the popup void showPopup(); // Hides the popup. Do not call this directly: use client->hidePopup(). void hidePopup(); // 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 index); // 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 = width; } // Computes the size of widget and children. void layout(); // Returns whether the popup wants to process events for the passed key. bool isInterestedInEventForKey(int keyCode);private: friend class PopupContainer; friend class RefCounted<PopupListBox>; // A type of List Item enum ListItemType { TypeOption, TypeGroup, TypeSeparator }; // A item (represented by <option> or <optgroup>) in the <select> widget. struct ListItem { ListItem(const String& label, ListItemType type) : label(label.copy()), type(type), y(0) {} String label; ListItemType type; int y; // y offset of this item, relative to the top of the popup. }; PopupListBox(PopupMenuClient* client, const PopupContainerSettings& settings) : m_settings(settings) , m_originalIndex(0) , m_selectedIndex(0) , m_willAcceptOnAbandon(false) , m_visibleRows(0) , m_popupClient(client) , m_repeatingChar(0) , m_lastCharTime(0) { setScrollbarModes(ScrollbarAlwaysOff, ScrollbarAlwaysOff); } ~PopupListBox() { clear(); } void disconnectClient() { m_popupClient = 0; } // Closes the popup void abandon(); // 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. void acceptIndex(int index); // Returns true if the selection can be changed to index. // Disabled items, or labels cannot be selected. bool isSelectableItem(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); // Gets the height of a row. int getRowHeight(int index); // Get the bounds of a row. IntRect getRowBounds(int index); // Converts a point to an index of the row the point is over int pointToRowIndex(const IntPoint&); // Paint an individual row void paintRow(GraphicsContext*, const IntRect&, int rowIndex); // Test if the given point is within the bounds of the popup window. bool isPointInBounds(const IntPoint&); // Called when the user presses a text key. Does a prefix-search of the items. void typeAheadFind(const PlatformKeyboardEvent&); // Returns the font to use for the given row 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(); // The settings that specify the behavior for this Popup window. PopupContainerSettings m_settings; // 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; // True if we should accept the selectedIndex as chosen, even 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. bool m_willAcceptOnAbandon; // 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; // A list of the options contained within the <select> Vector<ListItem*> m_items; // The <select> PopupMenuClient that opened us. PopupMenuClient* m_popupClient; // The scrollbar which has mouse capture. Mouse events go straight to this // if non-NULL. RefPtr<Scrollbar> m_capturingScrollbar; // The last scrollbar that the mouse was over. Used for mouseover highlights. RefPtr<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;};static PlatformMouseEvent constructRelativeMouseEvent(const PlatformMouseEvent& e, FramelessScrollView* parent, FramelessScrollView* child){ IntPoint pos = parent->convertSelfToChild(child, e.pos()); // FIXME: This is a horrible hack since PlatformMouseEvent has no setters for x/y. PlatformMouseEvent relativeEvent = e; IntPoint& relativePos = const_cast<IntPoint&>(relativeEvent.pos()); relativePos.setX(pos.x()); relativePos.setY(pos.y()); return relativeEvent;}static PlatformWheelEvent constructRelativeWheelEvent(const PlatformWheelEvent& e, FramelessScrollView* parent, FramelessScrollView* child){ IntPoint pos = parent->convertSelfToChild(child, e.pos()); // FIXME: This is a horrible hack since PlatformWheelEvent has no setters for x/y. PlatformWheelEvent relativeEvent = e; IntPoint& relativePos = const_cast<IntPoint&>(relativeEvent.pos()); relativePos.setX(pos.x()); relativePos.setY(pos.y()); return relativeEvent;}///////////////////////////////////////////////////////////////////////////////// PopupContainer implementation// staticPassRefPtr<PopupContainer> PopupContainer::create(PopupMenuClient* client, const PopupContainerSettings& settings){ return adoptRef(new PopupContainer(client, settings));}PopupContainer::PopupContainer(PopupMenuClient* client, const PopupContainerSettings& settings) : m_listBox(PopupListBox::create(client, settings)) , m_settings(settings){ setScrollbarModes(ScrollbarAlwaysOff, ScrollbarAlwaysOff);}PopupContainer::~PopupContainer(){ if (m_listBox) removeChild(m_listBox.get());}void PopupContainer::showPopup(FrameView* view){ // Pre-layout, our size matches the <select> dropdown control. int selectHeight = frameRect().height(); // Lay everything out to figure out our preferred size, then tell the view's // WidgetClient about it. It should assign us a client. layout(); ChromeClientChromium* chromeClient = static_cast<ChromeClientChromium*>( view->frame()->page()->chrome()->client()); if (chromeClient) { // If the popup would extend past the bottom of the screen, open upwards // instead. FloatRect screen = screenAvailableRect(view); IntRect widgetRect = chromeClient->windowToScreen(frameRect()); if (widgetRect.bottom() > static_cast<int>(screen.bottom())) widgetRect.move(0, -(widgetRect.height() + selectHeight)); chromeClient->popupOpened(this, widgetRect, m_settings.focusOnShow); } if (!m_listBox->parent()) addChild(m_listBox.get()); // Enable scrollbars after the listbox is inserted into the hierarchy, // so it has a proper WidgetClient. m_listBox->setVerticalScrollbarMode(ScrollbarAuto); m_listBox->scrollToRevealSelection(); invalidate();}void PopupContainer::hidePopup(){ if (client()) client()->popupClosed(this);}void PopupContainer::layout(){ m_listBox->layout(); // Place the listbox within our border. m_listBox->move(kBorderSize, kBorderSize); // Size ourselves to contain listbox + border. resize(m_listBox->width() + kBorderSize * 2, m_listBox->height() + kBorderSize * 2); invalidate();}bool PopupContainer::handleMouseDownEvent(const PlatformMouseEvent& event)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -