📄 popupmenuwin.cpp
字号:
return; m_focusedIndex = client()->selectedIndex(); ::InvalidateRect(m_popup, 0, TRUE); if (!scrollToRevealSelection()) ::UpdateWindow(m_popup);}bool PopupMenu::itemWritingDirectionIsNatural() { return true; }const int separatorPadding = 4;const int separatorHeight = 1;void PopupMenu::paint(const IntRect& damageRect, HDC hdc){ if (!m_popup) return; if (!m_DC) { m_DC = ::CreateCompatibleDC(::GetDC(m_popup)); if (!m_DC) return; } if (m_bmp) { bool keepBitmap = false; BITMAP bitmap; if (GetObject(m_bmp, sizeof(bitmap), &bitmap)) keepBitmap = bitmap.bmWidth == clientRect().width() && bitmap.bmHeight == clientRect().height(); if (!keepBitmap) { DeleteObject(m_bmp); m_bmp = 0; } } if (!m_bmp) { BITMAPINFO bitmapInfo; bitmapInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); bitmapInfo.bmiHeader.biWidth = clientRect().width(); bitmapInfo.bmiHeader.biHeight = -clientRect().height(); bitmapInfo.bmiHeader.biPlanes = 1; bitmapInfo.bmiHeader.biBitCount = 32; bitmapInfo.bmiHeader.biCompression = BI_RGB; bitmapInfo.bmiHeader.biSizeImage = 0; bitmapInfo.bmiHeader.biXPelsPerMeter = 0; bitmapInfo.bmiHeader.biYPelsPerMeter = 0; bitmapInfo.bmiHeader.biClrUsed = 0; bitmapInfo.bmiHeader.biClrImportant = 0; void* pixels = 0; m_bmp = ::CreateDIBSection(m_DC, &bitmapInfo, DIB_RGB_COLORS, &pixels, 0, 0); if (!m_bmp) return; ::SelectObject(m_DC, m_bmp); } GraphicsContext context(m_DC); int itemCount = client()->listSize(); // listRect is the damageRect translated into the coordinates of the entire menu list (which is itemCount * m_itemHeight pixels tall) IntRect listRect = damageRect; listRect.move(IntSize(0, m_scrollOffset * m_itemHeight)); for (int y = listRect.y(); y < listRect.bottom(); y += m_itemHeight) { int index = y / m_itemHeight; Color optionBackgroundColor, optionTextColor; PopupMenuStyle itemStyle = client()->itemStyle(index); if (index == focusedIndex()) { optionBackgroundColor = theme()->activeListBoxSelectionBackgroundColor(); optionTextColor = theme()->activeListBoxSelectionForegroundColor(); } else { optionBackgroundColor = itemStyle.backgroundColor(); optionTextColor = itemStyle.foregroundColor(); } // itemRect is in client coordinates IntRect itemRect(0, (index - m_scrollOffset) * m_itemHeight, damageRect.width(), m_itemHeight); // Draw the background for this menu item if (itemStyle.isVisible()) context.fillRect(itemRect, optionBackgroundColor); if (client()->itemIsSeparator(index)) { IntRect separatorRect(itemRect.x() + separatorPadding, itemRect.y() + (itemRect.height() - separatorHeight) / 2, itemRect.width() - 2 * separatorPadding, separatorHeight); context.fillRect(separatorRect, optionTextColor); continue; } String itemText = client()->itemText(index); unsigned length = itemText.length(); const UChar* string = itemText.characters(); TextRun textRun(string, length, false, 0, 0, itemText.defaultWritingDirection() == WTF::Unicode::RightToLeft); context.setFillColor(optionTextColor); Font itemFont = client()->menuStyle().font(); if (client()->itemIsLabel(index)) { FontDescription d = itemFont.fontDescription(); d.setWeight(d.bolderWeight()); itemFont = Font(d, itemFont.letterSpacing(), itemFont.wordSpacing()); itemFont.update(m_popupClient->fontSelector()); } // Draw the item text if (itemStyle.isVisible()) { int textX = max(0, client()->clientPaddingLeft() - client()->clientInsetLeft()); int textY = itemRect.y() + itemFont.ascent() + (itemRect.height() - itemFont.height()) / 2; context.drawBidiText(itemFont, textRun, IntPoint(textX, textY)); } } if (m_scrollbar) m_scrollbar->paint(&context, damageRect); if (!hdc) hdc = ::GetDC(m_popup); ::BitBlt(hdc, damageRect.x(), damageRect.y(), damageRect.width(), damageRect.height(), m_DC, damageRect.x(), damageRect.y(), SRCCOPY);}void PopupMenu::valueChanged(Scrollbar* scrollBar){ ASSERT(m_scrollbar); if (!m_popup) return; int offset = scrollBar->value(); if (m_scrollOffset == offset) return; int scrolledLines = m_scrollOffset - offset; m_scrollOffset = offset; UINT flags = SW_INVALIDATE;#ifdef CAN_SET_SMOOTH_SCROLLING_DURATION BOOL shouldSmoothScroll = FALSE; ::SystemParametersInfo(SPI_GETLISTBOXSMOOTHSCROLLING, 0, &shouldSmoothScroll, 0); if (shouldSmoothScroll) flags |= MAKEWORD(SW_SMOOTHSCROLL, smoothScrollAnimationDuration);#endif IntRect listRect = clientRect(); if (m_scrollbar) listRect.setWidth(listRect.width() - m_scrollbar->frameRect().width()); RECT r = listRect; ::ScrollWindowEx(m_popup, 0, scrolledLines * m_itemHeight, &r, 0, 0, 0, flags); if (m_scrollbar) { r = m_scrollbar->frameRect(); ::InvalidateRect(m_popup, &r, TRUE); } ::UpdateWindow(m_popup);}void PopupMenu::invalidateScrollbarRect(Scrollbar* scrollbar, const IntRect& rect){ IntRect scrollRect = rect; scrollRect.move(scrollbar->x(), scrollbar->y()); RECT r = scrollRect; ::InvalidateRect(m_popup, &r, false);}static ATOM registerPopup(){ static bool haveRegisteredWindowClass = false; if (haveRegisteredWindowClass) return true; WNDCLASSEX wcex; wcex.cbSize = sizeof(WNDCLASSEX); wcex.style = 0; wcex.lpfnWndProc = PopupWndProc; wcex.cbClsExtra = 0; wcex.cbWndExtra = sizeof(PopupMenu*); // For the PopupMenu pointer wcex.hInstance = Page::instanceHandle(); wcex.hIcon = 0; wcex.hCursor = LoadCursor(0, IDC_ARROW); wcex.hbrBackground = 0; wcex.lpszMenuName = 0; wcex.lpszClassName = kPopupWindowClassName; wcex.hIconSm = 0; haveRegisteredWindowClass = true; return ::RegisterClassEx(&wcex);}const int smoothScrollAnimationDuration = 5000;static LRESULT CALLBACK PopupWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam){ LRESULT lResult = 0; LONG_PTR longPtr = GetWindowLongPtr(hWnd, 0); PopupMenu* popup = reinterpret_cast<PopupMenu*>(longPtr); switch (message) { case WM_SIZE: if (popup && popup->scrollbar()) { IntSize size(LOWORD(lParam), HIWORD(lParam)); popup->scrollbar()->setFrameRect(IntRect(size.width() - popup->scrollbar()->width(), 0, popup->scrollbar()->width(), size.height())); int visibleItems = popup->visibleItems(); popup->scrollbar()->setEnabled(visibleItems < popup->client()->listSize()); popup->scrollbar()->setSteps(1, max(1, visibleItems - 1)); popup->scrollbar()->setProportion(visibleItems, popup->client()->listSize()); } break; case WM_ACTIVATE: if (popup && popup->client() && wParam == WA_INACTIVE) popup->client()->hidePopup(); break; case WM_KILLFOCUS: if (popup && popup->client() && (HWND)wParam != popup->popupHandle()) // Focus is going elsewhere, so hide popup->client()->hidePopup(); break; case WM_KEYDOWN: if (popup && popup->client()) { lResult = 0; switch (LOWORD(wParam)) { case VK_DOWN: case VK_RIGHT: popup->down(); break; case VK_UP: case VK_LEFT: popup->up(); break; case VK_HOME: popup->focusFirst(); break; case VK_END: popup->focusLast(); break; case VK_PRIOR: if (popup->focusedIndex() != popup->scrollOffset()) { // Set the selection to the first visible item int firstVisibleItem = popup->scrollOffset(); popup->up(popup->focusedIndex() - firstVisibleItem); } else // The first visible item is selected, so move the selection back one page popup->up(popup->visibleItems()); break; case VK_NEXT: if (popup) { int lastVisibleItem = popup->scrollOffset() + popup->visibleItems() - 1; if (popup->focusedIndex() != lastVisibleItem) { // Set the selection to the last visible item popup->down(lastVisibleItem - popup->focusedIndex()); } else // The last visible item is selected, so move the selection forward one page popup->down(popup->visibleItems()); } break; case VK_TAB: ::SendMessage(popup->client()->hostWindow()->platformWindow(), message, wParam, lParam); popup->client()->hidePopup(); break; default: if (isASCIIPrintable(wParam)) // Send the keydown to the WebView so it can be used for type-to-select. ::PostMessage(popup->client()->hostWindow()->platformWindow(), message, wParam, lParam); else lResult = 1; break; } } break; case WM_CHAR: if (popup && popup->client()) { lResult = 0; int index; switch (wParam) { case 0x0D: // Enter/Return popup->client()->hidePopup(); index = popup->focusedIndex(); ASSERT(index >= 0); popup->client()->valueChanged(index); break; case 0x1B: // Escape popup->client()->hidePopup(); break; case 0x09: // TAB case 0x08: // Backspace case 0x0A: // Linefeed default: // Character lResult = 1; break; } } break; case WM_MOUSEMOVE: if (popup) { IntPoint mousePoint(MAKEPOINTS(lParam)); if (popup->scrollbar()) { IntRect scrollBarRect = popup->scrollbar()->frameRect(); if (popup->scrollbarCapturingMouse() || scrollBarRect.contains(mousePoint)) { // Put the point into coordinates relative to the scroll bar mousePoint.move(-scrollBarRect.x(), -scrollBarRect.y()); PlatformMouseEvent event(hWnd, message, wParam, MAKELPARAM(mousePoint.x(), mousePoint.y())); popup->scrollbar()->mouseMoved(event); break; } } BOOL shouldHotTrack = FALSE; ::SystemParametersInfo(SPI_GETHOTTRACKING, 0, &shouldHotTrack, 0); RECT bounds; GetClientRect(popup->popupHandle(), &bounds); if ((shouldHotTrack || wParam & MK_LBUTTON) && ::PtInRect(&bounds, mousePoint)) popup->setFocusedIndex(popup->listIndexAtPoint(mousePoint), true); // Release capture if the left button isn't down, and the mousePoint is outside the popup window. // This way, the WebView will get future mouse events in the rest of the window. if (!(wParam & MK_LBUTTON) && !::PtInRect(&bounds, mousePoint)) { ::ReleaseCapture(); break; } } break; case WM_LBUTTONDOWN: if (popup) { ::SetCapture(popup->popupHandle()); IntPoint mousePoint(MAKEPOINTS(lParam)); if (popup->scrollbar()) { IntRect scrollBarRect = popup->scrollbar()->frameRect(); if (scrollBarRect.contains(mousePoint)) { // Put the point into coordinates relative to the scroll bar mousePoint.move(-scrollBarRect.x(), -scrollBarRect.y()); PlatformMouseEvent event(hWnd, message, wParam, MAKELPARAM(mousePoint.x(), mousePoint.y())); popup->scrollbar()->mouseDown(event); popup->setScrollbarCapturingMouse(true); break; } } popup->setFocusedIndex(popup->listIndexAtPoint(mousePoint), true); } break; case WM_LBUTTONUP: if (popup) { IntPoint mousePoint(MAKEPOINTS(lParam)); if (popup->scrollbar()) { ::ReleaseCapture(); IntRect scrollBarRect = popup->scrollbar()->frameRect(); if (popup->scrollbarCapturingMouse() || scrollBarRect.contains(mousePoint)) { popup->setScrollbarCapturingMouse(false); // Put the point into coordinates relative to the scroll bar mousePoint.move(-scrollBarRect.x(), -scrollBarRect.y()); PlatformMouseEvent event(hWnd, message, wParam, MAKELPARAM(mousePoint.x(), mousePoint.y())); popup->scrollbar()->mouseUp(); // FIXME: This is a hack to work around Scrollbar not invalidating correctly when it doesn't have a parent widget RECT r = scrollBarRect; ::InvalidateRect(popup->popupHandle(), &r, TRUE); break; } } // Only release capture and hide the popup if the mouse is inside the popup window. RECT bounds; GetClientRect(popup->popupHandle(), &bounds); if (popup->client() && ::PtInRect(&bounds, mousePoint)) { ::ReleaseCapture(); popup->client()->hidePopup(); int index = popup->focusedIndex(); if (index >= 0) popup->client()->valueChanged(index); } } break; case WM_MOUSEWHEEL: if (popup && popup->scrollbar()) { int i = 0; for (popup->incrementWheelDelta(GET_WHEEL_DELTA_WPARAM(wParam)); abs(popup->wheelDelta()) >= WHEEL_DELTA; popup->reduceWheelDelta(WHEEL_DELTA)) if (popup->wheelDelta() > 0) ++i; else --i; popup->scrollbar()->scroll(i > 0 ? ScrollUp : ScrollDown, ScrollByLine, abs(i)); } break; case WM_PAINT: if (popup) { PAINTSTRUCT paintInfo; ::BeginPaint(popup->popupHandle(), &paintInfo); popup->paint(paintInfo.rcPaint, paintInfo.hdc); ::EndPaint(popup->popupHandle(), &paintInfo); lResult = 0; } break; case WM_PRINTCLIENT: if (popup) popup->paint(popup->clientRect(), (HDC)wParam); break; default: lResult = DefWindowProc(hWnd, message, wParam, lParam); } return lResult;}}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -