⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 popupmenuwin.cpp

📁 linux下开源浏览器WebKit的源码,市面上的很多商用浏览器都是移植自WebKit
💻 CPP
📖 第 1 页 / 共 2 页
字号:
/* * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB.  If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. * */#include "config.h"#include "PopupMenu.h"#include "Document.h"#include "FloatRect.h"#include "FontSelector.h"#include "Frame.h"#include "FrameView.h"#include "GraphicsContext.h"#include "HTMLNames.h"#include "Page.h"#include "PlatformMouseEvent.h"#include "PlatformScreen.h"#include "RenderTheme.h"#include "RenderView.h"#include "Scrollbar.h"#include "ScrollbarTheme.h"#include "SimpleFontData.h"#include <tchar.h>#include <windows.h>using std::min;namespace WebCore {using namespace HTMLNames;// Default Window animation duration in millisecondsstatic const int defaultAnimationDuration = 200;// Maximum height of a popup windowstatic const int maxPopupHeight = 320;const int optionSpacingMiddle = 1;const int popupWindowBorderWidth = 1;static LPCTSTR kPopupWindowClassName = _T("PopupWindowClass");static ATOM registerPopup();static LRESULT CALLBACK PopupWndProc(HWND, UINT, WPARAM, LPARAM);// FIXME: Remove this as soon as practical.static inline bool isASCIIPrintable(unsigned c){    return c >= 0x20 && c <= 0x7E;}PopupMenu::PopupMenu(PopupMenuClient* client)    : m_popupClient(client)    , m_scrollbar(0)    , m_popup(0)    , m_DC(0)    , m_bmp(0)    , m_wasClicked(false)    , m_itemHeight(0)    , m_scrollOffset(0)    , m_wheelDelta(0)    , m_focusedIndex(0)    , m_scrollbarCapturingMouse(false){}PopupMenu::~PopupMenu(){    if (m_bmp)        ::DeleteObject(m_bmp);    if (m_DC)        ::DeleteObject(m_DC);    if (m_popup)        ::DestroyWindow(m_popup);}void PopupMenu::show(const IntRect& r, FrameView* v, int index){    calculatePositionAndSize(r, v);    if (clientRect().isEmpty())        return;    if (!m_popup) {        registerPopup();        DWORD exStyle = WS_EX_LTRREADING;        // Even though we already know our size and location at this point, we pass (0,0,0,0) as our size/location here.        // We need to wait until after the call to ::SetWindowLongPtr to set our size so that in our WM_SIZE handler we can get access to the PopupMenu object        m_popup = ::CreateWindowEx(exStyle, kPopupWindowClassName, _T("PopupMenu"),            WS_POPUP | WS_BORDER,            0, 0, 0, 0,            v->hostWindow()->platformWindow(), 0, 0, 0);        if (!m_popup)            return;        ::SetWindowLongPtr(m_popup, 0, (LONG_PTR)this);    }    if (!m_scrollbar)        if (visibleItems() < client()->listSize()) {            // We need a scroll bar            m_scrollbar = client()->createScrollbar(this, VerticalScrollbar, SmallScrollbar);        }    ::SetWindowPos(m_popup, HWND_TOP, m_windowRect.x(), m_windowRect.y(), m_windowRect.width(), m_windowRect.height(), 0);    // Determine whether we should animate our popups    // Note: Must use 'BOOL' and 'FALSE' instead of 'bool' and 'false' to avoid stack corruption with SystemParametersInfo    BOOL shouldAnimate = FALSE;#ifdef CAN_ANIMATE_TRANSPARENT_WINDOWS_SMOOTHLY    ::SystemParametersInfo(SPI_GETCOMBOBOXANIMATION, 0, &shouldAnimate, 0);#endif    if (shouldAnimate) {        RECT viewRect = {0};        ::GetWindowRect(v->hostWindow()->platformWindow(), &viewRect);        if (!::IsRectEmpty(&viewRect)) {            // Popups should slide into view away from the <select> box            // NOTE: This may have to change for Vista            DWORD slideDirection = (m_windowRect.y() < viewRect.top + v->contentsToWindow(r.location()).y()) ? AW_VER_NEGATIVE : AW_VER_POSITIVE;            ::AnimateWindow(m_popup, defaultAnimationDuration, AW_SLIDE | slideDirection | AW_ACTIVATE);        }    } else        ::ShowWindow(m_popup, SW_SHOWNORMAL);    ::SetCapture(m_popup);    if (client()) {        int index = client()->selectedIndex();        if (index >= 0)            setFocusedIndex(index);    }}void PopupMenu::hide(){    ::ShowWindow(m_popup, SW_HIDE);}const int endOfLinePadding = 2;void PopupMenu::calculatePositionAndSize(const IntRect& r, FrameView* v){    // r is in absolute document coordinates, but we want to be in screen coordinates    // First, move to WebView coordinates    IntRect rScreenCoords(v->contentsToWindow(r.location()), r.size());    // Then, translate to screen coordinates    POINT location(rScreenCoords.location());    if (!::ClientToScreen(v->hostWindow()->platformWindow(), &location))        return;    rScreenCoords.setLocation(location);    // First, determine the popup's height    int itemCount = client()->listSize();    m_itemHeight = client()->menuStyle().font().height() + optionSpacingMiddle;    int naturalHeight = m_itemHeight * itemCount;    int popupHeight = min(maxPopupHeight, naturalHeight);    // The popup should show an integral number of items (i.e. no partial items should be visible)    popupHeight -= popupHeight % m_itemHeight;        // Next determine its width    int popupWidth = 0;    for (int i = 0; i < itemCount; ++i) {        String text = client()->itemText(i);        if (text.isEmpty())            continue;        Font itemFont = client()->menuStyle().font();        if (client()->itemIsLabel(i)) {            FontDescription d = itemFont.fontDescription();            d.setWeight(d.bolderWeight());            itemFont = Font(d, itemFont.letterSpacing(), itemFont.wordSpacing());            itemFont.update(m_popupClient->fontSelector());        }        popupWidth = max(popupWidth, itemFont.width(TextRun(text.characters(), text.length())));    }    if (naturalHeight > maxPopupHeight)        // We need room for a scrollbar        popupWidth += ScrollbarTheme::nativeTheme()->scrollbarThickness(SmallScrollbar);    // Add padding to align the popup text with the <select> text    // Note: We can't add paddingRight() because that value includes the width    // of the dropdown button, so we must use our own endOfLinePadding constant.    popupWidth += max(0, endOfLinePadding - client()->clientInsetRight()) + max(0, client()->clientPaddingLeft() - client()->clientInsetLeft());    // Leave room for the border    popupWidth += 2 * popupWindowBorderWidth;    popupHeight += 2 * popupWindowBorderWidth;    // The popup should be at least as wide as the control on the page    popupWidth = max(rScreenCoords.width() - client()->clientInsetLeft() - client()->clientInsetRight(), popupWidth);    // Always left-align items in the popup.  This matches popup menus on the mac.    int popupX = rScreenCoords.x() + client()->clientInsetLeft();    IntRect popupRect(popupX, rScreenCoords.bottom(), popupWidth, popupHeight);    // The popup needs to stay within the bounds of the screen and not overlap any toolbars    FloatRect screen = screenAvailableRect(v);    // Check that we don't go off the screen vertically    if (popupRect.bottom() > screen.height()) {        // The popup will go off the screen, so try placing it above the client        if (rScreenCoords.y() - popupRect.height() < 0) {            // The popup won't fit above, either, so place it whereever's bigger and resize it to fit            if ((rScreenCoords.y() + rScreenCoords.height() / 2) < (screen.height() / 2)) {                // Below is bigger                popupRect.setHeight(screen.height() - popupRect.y());            } else {                // Above is bigger                popupRect.setY(0);                popupRect.setHeight(rScreenCoords.y());            }        } else {            // The popup fits above, so reposition it            popupRect.setY(rScreenCoords.y() - popupRect.height());        }    }    // Check that we don't go off the screen horizontally    if (popupRect.x() < screen.x()) {        popupRect.setWidth(popupRect.width() - (screen.x() - popupRect.x()));        popupRect.setX(screen.x());    }    m_windowRect = popupRect;    return;}bool PopupMenu::setFocusedIndex(int i, bool hotTracking){    if (i < 0 || i >= client()->listSize() || i == focusedIndex())        return false;    if (!client()->itemIsEnabled(i))        return false;    invalidateItem(focusedIndex());    invalidateItem(i);    m_focusedIndex = i;    if (!hotTracking)        client()->setTextFromItem(i);    if (!scrollToRevealSelection())        ::UpdateWindow(m_popup);    return true;}int PopupMenu::visibleItems() const{    return clientRect().height() / m_itemHeight;}int PopupMenu::listIndexAtPoint(const IntPoint& point) const{    return m_scrollOffset + point.y() / m_itemHeight;}int PopupMenu::focusedIndex() const{    return m_focusedIndex;}void PopupMenu::focusFirst(){    if (!client())        return;    int size = client()->listSize();    for (int i = 0; i < size; ++i)        if (client()->itemIsEnabled(i)) {            setFocusedIndex(i);            break;        }}void PopupMenu::focusLast(){    if (!client())        return;    int size = client()->listSize();    for (int i = size - 1; i > 0; --i)        if (client()->itemIsEnabled(i)) {            setFocusedIndex(i);            break;        }}bool PopupMenu::down(unsigned lines){    if (!client())        return false;    int size = client()->listSize();    int lastSelectableIndex, selectedListIndex;    lastSelectableIndex = selectedListIndex = focusedIndex();    for (int i = selectedListIndex + 1; i >= 0 && i < size; ++i)        if (client()->itemIsEnabled(i)) {            lastSelectableIndex = i;            if (i >= selectedListIndex + (int)lines)                break;        }    return setFocusedIndex(lastSelectableIndex);}bool PopupMenu::up(unsigned lines){    if (!client())        return false;    int size = client()->listSize();    int lastSelectableIndex, selectedListIndex;    lastSelectableIndex = selectedListIndex = focusedIndex();    for (int i = selectedListIndex - 1; i >= 0 && i < size; --i)        if (client()->itemIsEnabled(i)) {            lastSelectableIndex = i;            if (i <= selectedListIndex - (int)lines)                break;        }    return setFocusedIndex(lastSelectableIndex);}void PopupMenu::invalidateItem(int index){    if (!m_popup)        return;    IntRect damageRect(clientRect());    damageRect.setY(m_itemHeight * (index - m_scrollOffset));    damageRect.setHeight(m_itemHeight);    if (m_scrollbar)        damageRect.setWidth(damageRect.width() - m_scrollbar->frameRect().width());    RECT r = damageRect;    ::InvalidateRect(m_popup, &r, TRUE);}IntRect PopupMenu::clientRect() const{    IntRect clientRect = m_windowRect;    clientRect.inflate(-popupWindowBorderWidth);    clientRect.setLocation(IntPoint(0, 0));    return clientRect;}void PopupMenu::incrementWheelDelta(int delta){    m_wheelDelta += delta;}void PopupMenu::reduceWheelDelta(int delta){    ASSERT(delta >= 0);    ASSERT(delta <= abs(m_wheelDelta));    if (m_wheelDelta > 0)        m_wheelDelta -= delta;    else if (m_wheelDelta < 0)        m_wheelDelta += delta;    else        return;}bool PopupMenu::scrollToRevealSelection(){    if (!m_scrollbar)        return false;    int index = focusedIndex();    if (index < m_scrollOffset) {        m_scrollbar->setValue(index);        return true;    }    if (index >= m_scrollOffset + visibleItems()) {        m_scrollbar->setValue(index - visibleItems() + 1);        return true;    }    return false;}void PopupMenu::updateFromElement(){    if (!m_popup)

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -