| OLD | NEW |
| (Empty) |
| 1 /* | |
| 2 * Copyright (C) 2006, 2007, 2008, 2011 Apple Inc. All rights reserved. | |
| 3 * Copyright (C) 2007-2009 Torch Mobile Inc. | |
| 4 * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). | |
| 5 * | |
| 6 * This library is free software; you can redistribute it and/or | |
| 7 * modify it under the terms of the GNU Library General Public | |
| 8 * License as published by the Free Software Foundation; either | |
| 9 * version 2 of the License, or (at your option) any later version. | |
| 10 * | |
| 11 * This library is distributed in the hope that it will be useful, | |
| 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
| 14 * Library General Public License for more details. | |
| 15 * | |
| 16 * You should have received a copy of the GNU Library General Public License | |
| 17 * along with this library; see the file COPYING.LIB. If not, write to | |
| 18 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, | |
| 19 * Boston, MA 02110-1301, USA. | |
| 20 * | |
| 21 */ | |
| 22 | |
| 23 #include "config.h" | |
| 24 #include "PopupMenuWin.h" | |
| 25 | |
| 26 #include "BitmapInfo.h" | |
| 27 #include "Document.h" | |
| 28 #include "FloatRect.h" | |
| 29 #include "FontSelector.h" | |
| 30 #include "Frame.h" | |
| 31 #include "FrameView.h" | |
| 32 #include "GraphicsContext.h" | |
| 33 #include "HTMLNames.h" | |
| 34 #include "HWndDC.h" | |
| 35 #include "HostWindow.h" | |
| 36 #include "LengthFunctions.h" | |
| 37 #include "Page.h" | |
| 38 #include "PlatformMouseEvent.h" | |
| 39 #include "PlatformScreen.h" | |
| 40 #include "RenderMenuList.h" | |
| 41 #include "RenderTheme.h" | |
| 42 #include "RenderView.h" | |
| 43 #include "Scrollbar.h" | |
| 44 #include "ScrollbarTheme.h" | |
| 45 #include "SimpleFontData.h" | |
| 46 #include "TextRun.h" | |
| 47 #include "WebCoreInstanceHandle.h" | |
| 48 #include "WindowsExtras.h" | |
| 49 | |
| 50 #include <windows.h> | |
| 51 #include <windowsx.h> | |
| 52 #if OS(WINCE) | |
| 53 #include <ResDefCE.h> | |
| 54 #define MAKEPOINTS(l) (*((POINTS FAR *)&(l))) | |
| 55 #endif | |
| 56 | |
| 57 #define HIGH_BIT_MASK_SHORT 0x8000 | |
| 58 | |
| 59 using std::min; | |
| 60 | |
| 61 namespace WebCore { | |
| 62 | |
| 63 using namespace HTMLNames; | |
| 64 | |
| 65 // Default Window animation duration in milliseconds | |
| 66 static const int defaultAnimationDuration = 200; | |
| 67 // Maximum height of a popup window | |
| 68 static const int maxPopupHeight = 320; | |
| 69 | |
| 70 const int optionSpacingMiddle = 1; | |
| 71 const int popupWindowBorderWidth = 1; | |
| 72 | |
| 73 static LPCWSTR kPopupWindowClassName = L"PopupWindowClass"; | |
| 74 | |
| 75 // This is used from within our custom message pump when we want to send a | |
| 76 // message to the web view and not have our message stolen and sent to | |
| 77 // the popup window. | |
| 78 static const UINT WM_HOST_WINDOW_FIRST = WM_USER; | |
| 79 static const UINT WM_HOST_WINDOW_CHAR = WM_USER + WM_CHAR; | |
| 80 static const UINT WM_HOST_WINDOW_MOUSEMOVE = WM_USER + WM_MOUSEMOVE; | |
| 81 | |
| 82 // FIXME: Remove this as soon as practical. | |
| 83 static inline bool isASCIIPrintable(unsigned c) | |
| 84 { | |
| 85 return c >= 0x20 && c <= 0x7E; | |
| 86 } | |
| 87 | |
| 88 static void translatePoint(LPARAM& lParam, HWND from, HWND to) | |
| 89 { | |
| 90 POINT pt; | |
| 91 pt.x = (short)GET_X_LPARAM(lParam); | |
| 92 pt.y = (short)GET_Y_LPARAM(lParam); | |
| 93 ::MapWindowPoints(from, to, &pt, 1); | |
| 94 lParam = MAKELPARAM(pt.x, pt.y); | |
| 95 } | |
| 96 | |
| 97 static FloatRect monitorFromHwnd(HWND hwnd) | |
| 98 { | |
| 99 HMONITOR monitor = MonitorFromWindow(hwnd, MONITOR_DEFAULTTOPRIMARY); | |
| 100 MONITORINFOEX monitorInfo; | |
| 101 monitorInfo.cbSize = sizeof(MONITORINFOEX); | |
| 102 GetMonitorInfo(monitor, &monitorInfo); | |
| 103 return monitorInfo.rcWork; | |
| 104 } | |
| 105 | |
| 106 PopupMenuWin::PopupMenuWin(PopupMenuClient* client) | |
| 107 : m_popupClient(client) | |
| 108 , m_scrollbar(0) | |
| 109 , m_popup(0) | |
| 110 , m_DC(0) | |
| 111 , m_bmp(0) | |
| 112 , m_wasClicked(false) | |
| 113 , m_itemHeight(0) | |
| 114 , m_scrollOffset(0) | |
| 115 , m_wheelDelta(0) | |
| 116 , m_focusedIndex(0) | |
| 117 , m_scrollbarCapturingMouse(false) | |
| 118 , m_showPopup(false) | |
| 119 { | |
| 120 } | |
| 121 | |
| 122 PopupMenuWin::~PopupMenuWin() | |
| 123 { | |
| 124 if (m_bmp) | |
| 125 ::DeleteObject(m_bmp); | |
| 126 if (m_DC) | |
| 127 ::DeleteDC(m_DC); | |
| 128 if (m_popup) | |
| 129 ::DestroyWindow(m_popup); | |
| 130 if (m_scrollbar) | |
| 131 m_scrollbar->setParent(0); | |
| 132 } | |
| 133 | |
| 134 void PopupMenuWin::disconnectClient() | |
| 135 { | |
| 136 m_popupClient = 0; | |
| 137 } | |
| 138 | |
| 139 LPCWSTR PopupMenuWin::popupClassName() | |
| 140 { | |
| 141 return kPopupWindowClassName; | |
| 142 } | |
| 143 | |
| 144 void PopupMenuWin::show(const IntRect& r, FrameView* view, int index) | |
| 145 { | |
| 146 calculatePositionAndSize(r, view); | |
| 147 if (clientRect().isEmpty()) | |
| 148 return; | |
| 149 | |
| 150 HWND hostWindow = view->hostWindow()->platformPageClient(); | |
| 151 | |
| 152 if (!m_scrollbar && visibleItems() < client()->listSize()) { | |
| 153 // We need a scroll bar | |
| 154 m_scrollbar = client()->createScrollbar(this, VerticalScrollbar, SmallSc
rollbar); | |
| 155 m_scrollbar->styleChanged(); | |
| 156 } | |
| 157 | |
| 158 // We need to reposition the popup window to its final coordinates. | |
| 159 // Before calling this, the popup hwnd is currently the size of and at the l
ocation of the menu list client so it needs to be updated. | |
| 160 ::MoveWindow(m_popup, m_windowRect.x(), m_windowRect.y(), m_windowRect.width
(), m_windowRect.height(), false); | |
| 161 | |
| 162 // Determine whether we should animate our popups | |
| 163 // Note: Must use 'BOOL' and 'FALSE' instead of 'bool' and 'false' to avoid
stack corruption with SystemParametersInfo | |
| 164 BOOL shouldAnimate = FALSE; | |
| 165 #if !OS(WINCE) | |
| 166 ::SystemParametersInfo(SPI_GETCOMBOBOXANIMATION, 0, &shouldAnimate, 0); | |
| 167 | |
| 168 if (shouldAnimate) { | |
| 169 RECT viewRect = {0}; | |
| 170 ::GetWindowRect(hostWindow, &viewRect); | |
| 171 if (!::IsRectEmpty(&viewRect)) | |
| 172 ::AnimateWindow(m_popup, defaultAnimationDuration, AW_BLEND); | |
| 173 } else | |
| 174 #endif | |
| 175 ::ShowWindow(m_popup, SW_SHOWNOACTIVATE); | |
| 176 | |
| 177 if (client()) { | |
| 178 int index = client()->selectedIndex(); | |
| 179 if (index >= 0) | |
| 180 setFocusedIndex(index); | |
| 181 } | |
| 182 | |
| 183 m_showPopup = true; | |
| 184 | |
| 185 // Protect the popup menu in case its owner is destroyed while we're running
the message pump. | |
| 186 RefPtr<PopupMenu> protect(this); | |
| 187 | |
| 188 ::SetCapture(hostWindow); | |
| 189 | |
| 190 MSG msg; | |
| 191 HWND activeWindow; | |
| 192 | |
| 193 while (::GetMessage(&msg, 0, 0, 0)) { | |
| 194 switch (msg.message) { | |
| 195 case WM_HOST_WINDOW_MOUSEMOVE: | |
| 196 case WM_HOST_WINDOW_CHAR: | |
| 197 if (msg.hwnd == m_popup) { | |
| 198 // This message should be sent to the host window. | |
| 199 msg.hwnd = hostWindow; | |
| 200 msg.message -= WM_HOST_WINDOW_FIRST; | |
| 201 } | |
| 202 break; | |
| 203 | |
| 204 // Steal mouse messages. | |
| 205 #if !OS(WINCE) | |
| 206 case WM_NCMOUSEMOVE: | |
| 207 case WM_NCLBUTTONDOWN: | |
| 208 case WM_NCLBUTTONUP: | |
| 209 case WM_NCLBUTTONDBLCLK: | |
| 210 case WM_NCRBUTTONDOWN: | |
| 211 case WM_NCRBUTTONUP: | |
| 212 case WM_NCRBUTTONDBLCLK: | |
| 213 case WM_NCMBUTTONDOWN: | |
| 214 case WM_NCMBUTTONUP: | |
| 215 case WM_NCMBUTTONDBLCLK: | |
| 216 #endif | |
| 217 case WM_MOUSEWHEEL: | |
| 218 msg.hwnd = m_popup; | |
| 219 break; | |
| 220 | |
| 221 // These mouse messages use client coordinates so we need to convert
them. | |
| 222 case WM_MOUSEMOVE: | |
| 223 case WM_LBUTTONDOWN: | |
| 224 case WM_LBUTTONUP: | |
| 225 case WM_LBUTTONDBLCLK: | |
| 226 case WM_RBUTTONDOWN: | |
| 227 case WM_RBUTTONUP: | |
| 228 case WM_RBUTTONDBLCLK: | |
| 229 case WM_MBUTTONDOWN: | |
| 230 case WM_MBUTTONUP: | |
| 231 case WM_MBUTTONDBLCLK: { | |
| 232 // Translate the coordinate. | |
| 233 translatePoint(msg.lParam, msg.hwnd, m_popup); | |
| 234 | |
| 235 msg.hwnd = m_popup; | |
| 236 break; | |
| 237 } | |
| 238 | |
| 239 // Steal all keyboard messages. | |
| 240 case WM_KEYDOWN: | |
| 241 case WM_KEYUP: | |
| 242 case WM_CHAR: | |
| 243 case WM_DEADCHAR: | |
| 244 case WM_SYSKEYDOWN: | |
| 245 case WM_SYSKEYUP: | |
| 246 case WM_SYSCHAR: | |
| 247 case WM_SYSDEADCHAR: | |
| 248 msg.hwnd = m_popup; | |
| 249 break; | |
| 250 } | |
| 251 | |
| 252 ::TranslateMessage(&msg); | |
| 253 ::DispatchMessage(&msg); | |
| 254 | |
| 255 if (!m_popupClient) | |
| 256 break; | |
| 257 | |
| 258 if (!m_showPopup) | |
| 259 break; | |
| 260 activeWindow = ::GetActiveWindow(); | |
| 261 if (activeWindow != hostWindow && !::IsChild(activeWindow, hostWindow)) | |
| 262 break; | |
| 263 if (::GetCapture() != hostWindow) | |
| 264 break; | |
| 265 } | |
| 266 | |
| 267 if (::GetCapture() == hostWindow) | |
| 268 ::ReleaseCapture(); | |
| 269 | |
| 270 // We're done, hide the popup if necessary. | |
| 271 hide(); | |
| 272 } | |
| 273 | |
| 274 void PopupMenuWin::hide() | |
| 275 { | |
| 276 if (!m_showPopup) | |
| 277 return; | |
| 278 | |
| 279 m_showPopup = false; | |
| 280 | |
| 281 ::ShowWindow(m_popup, SW_HIDE); | |
| 282 | |
| 283 if (client()) | |
| 284 client()->popupDidHide(); | |
| 285 | |
| 286 // Post a WM_NULL message to wake up the message pump if necessary. | |
| 287 ::PostMessage(m_popup, WM_NULL, 0, 0); | |
| 288 } | |
| 289 | |
| 290 // The screen that the popup is placed on should be whichever one the popup menu
button lies on. | |
| 291 // We fake an hwnd (here we use the popup's hwnd) on top of the button which we
can then use to determine the screen. | |
| 292 // We can then proceed with our final position/size calculations. | |
| 293 void PopupMenuWin::calculatePositionAndSize(const IntRect& r, FrameView* v) | |
| 294 { | |
| 295 // First get the screen coordinates of the popup menu client. | |
| 296 HWND hostWindow = v->hostWindow()->platformPageClient(); | |
| 297 IntRect absoluteBounds = ((RenderMenuList*)m_popupClient)->absoluteBoundingB
oxRect(); | |
| 298 IntRect absoluteScreenCoords(v->contentsToWindow(absoluteBounds.location()),
absoluteBounds.size()); | |
| 299 POINT absoluteLocation(absoluteScreenCoords.location()); | |
| 300 if (!::ClientToScreen(v->hostWindow()->platformPageClient(), &absoluteLocati
on)) | |
| 301 return; | |
| 302 absoluteScreenCoords.setLocation(absoluteLocation); | |
| 303 | |
| 304 // Now set the popup menu's location temporarily to these coordinates so we
can determine which screen the popup should lie on. | |
| 305 // We create or move m_popup as necessary. | |
| 306 if (!m_popup) { | |
| 307 registerClass(); | |
| 308 DWORD exStyle = WS_EX_LTRREADING; | |
| 309 m_popup = ::CreateWindowExW(exStyle, kPopupWindowClassName, L"PopupMenu"
, | |
| 310 WS_POPUP | WS_BORDER, | |
| 311 absoluteScreenCoords.x(), absoluteScreenCoords.y(), absoluteScreenCo
ords.width(), absoluteScreenCoords.height(), | |
| 312 hostWindow, 0, WebCore::instanceHandle(), this); | |
| 313 | |
| 314 if (!m_popup) | |
| 315 return; | |
| 316 } else | |
| 317 ::MoveWindow(m_popup, absoluteScreenCoords.x(), absoluteScreenCoords.y()
, absoluteScreenCoords.width(), absoluteScreenCoords.height(), false); | |
| 318 | |
| 319 FloatRect screen = monitorFromHwnd(m_popup); | |
| 320 | |
| 321 // Now we determine the actual location and measurements of the popup itself
. | |
| 322 // r is in absolute document coordinates, but we want to be in screen coordi
nates. | |
| 323 | |
| 324 // First, move to WebView coordinates | |
| 325 IntRect rScreenCoords(v->contentsToWindow(r.location()), r.size()); | |
| 326 | |
| 327 // Then, translate to screen coordinates | |
| 328 POINT location(rScreenCoords.location()); | |
| 329 if (!::ClientToScreen(v->hostWindow()->platformPageClient(), &location)) | |
| 330 return; | |
| 331 | |
| 332 rScreenCoords.setLocation(location); | |
| 333 | |
| 334 // First, determine the popup's height | |
| 335 int itemCount = client()->listSize(); | |
| 336 m_itemHeight = client()->menuStyle().font().fontMetrics().height() + optionS
pacingMiddle; | |
| 337 int naturalHeight = m_itemHeight * itemCount; | |
| 338 int popupHeight = min(maxPopupHeight, naturalHeight); | |
| 339 // The popup should show an integral number of items (i.e. no partial items
should be visible) | |
| 340 popupHeight -= popupHeight % m_itemHeight; | |
| 341 | |
| 342 // Next determine its width | |
| 343 int popupWidth = 0; | |
| 344 for (int i = 0; i < itemCount; ++i) { | |
| 345 String text = client()->itemText(i); | |
| 346 if (text.isEmpty()) | |
| 347 continue; | |
| 348 | |
| 349 Font itemFont = client()->menuStyle().font(); | |
| 350 if (client()->itemIsLabel(i)) { | |
| 351 FontDescription d = itemFont.fontDescription(); | |
| 352 d.setWeight(d.bolderWeight()); | |
| 353 itemFont = Font(d, itemFont.letterSpacing(), itemFont.wordSpacing())
; | |
| 354 itemFont.update(m_popupClient->fontSelector()); | |
| 355 } | |
| 356 | |
| 357 popupWidth = max(popupWidth, static_cast<int>(ceilf(itemFont.width(TextR
un(text.characters(), text.length()))))); | |
| 358 } | |
| 359 | |
| 360 if (naturalHeight > maxPopupHeight) | |
| 361 // We need room for a scrollbar | |
| 362 popupWidth += ScrollbarTheme::theme()->scrollbarThickness(SmallScrollbar
); | |
| 363 | |
| 364 // Add padding to align the popup text with the <select> text | |
| 365 popupWidth += max<int>(0, client()->clientPaddingRight() - client()->clientI
nsetRight()) + max<int>(0, client()->clientPaddingLeft() - client()->clientInset
Left()); | |
| 366 | |
| 367 // Leave room for the border | |
| 368 popupWidth += 2 * popupWindowBorderWidth; | |
| 369 popupHeight += 2 * popupWindowBorderWidth; | |
| 370 | |
| 371 // The popup should be at least as wide as the control on the page | |
| 372 popupWidth = max(rScreenCoords.width() - client()->clientInsetLeft() - clien
t()->clientInsetRight(), popupWidth); | |
| 373 | |
| 374 // Always left-align items in the popup. This matches popup menus on the ma
c. | |
| 375 int popupX = rScreenCoords.x() + client()->clientInsetLeft(); | |
| 376 | |
| 377 IntRect popupRect(popupX, rScreenCoords.maxY(), popupWidth, popupHeight); | |
| 378 | |
| 379 // Check that we don't go off the screen vertically | |
| 380 if (popupRect.maxY() > screen.height()) { | |
| 381 // The popup will go off the screen, so try placing it above the client | |
| 382 if (rScreenCoords.y() - popupRect.height() < 0) { | |
| 383 // The popup won't fit above, either, so place it whereever's bigger
and resize it to fit | |
| 384 if ((rScreenCoords.y() + rScreenCoords.height() / 2) < (screen.heigh
t() / 2)) { | |
| 385 // Below is bigger | |
| 386 popupRect.setHeight(screen.height() - popupRect.y()); | |
| 387 } else { | |
| 388 // Above is bigger | |
| 389 popupRect.setY(0); | |
| 390 popupRect.setHeight(rScreenCoords.y()); | |
| 391 } | |
| 392 } else { | |
| 393 // The popup fits above, so reposition it | |
| 394 popupRect.setY(rScreenCoords.y() - popupRect.height()); | |
| 395 } | |
| 396 } | |
| 397 | |
| 398 // Check that we don't go off the screen horizontally | |
| 399 if (popupRect.x() + popupRect.width() > screen.width() + screen.x()) | |
| 400 popupRect.setX(screen.x() + screen.width() - popupRect.width()); | |
| 401 if (popupRect.x() < screen.x()) | |
| 402 popupRect.setX(screen.x()); | |
| 403 | |
| 404 m_windowRect = popupRect; | |
| 405 return; | |
| 406 } | |
| 407 | |
| 408 bool PopupMenuWin::setFocusedIndex(int i, bool hotTracking) | |
| 409 { | |
| 410 if (i < 0 || i >= client()->listSize() || i == focusedIndex()) | |
| 411 return false; | |
| 412 | |
| 413 if (!client()->itemIsEnabled(i)) | |
| 414 return false; | |
| 415 | |
| 416 invalidateItem(focusedIndex()); | |
| 417 invalidateItem(i); | |
| 418 | |
| 419 m_focusedIndex = i; | |
| 420 | |
| 421 if (!hotTracking) | |
| 422 client()->setTextFromItem(i); | |
| 423 | |
| 424 if (!scrollToRevealSelection()) | |
| 425 ::UpdateWindow(m_popup); | |
| 426 | |
| 427 return true; | |
| 428 } | |
| 429 | |
| 430 int PopupMenuWin::visibleItems() const | |
| 431 { | |
| 432 return clientRect().height() / m_itemHeight; | |
| 433 } | |
| 434 | |
| 435 int PopupMenuWin::listIndexAtPoint(const IntPoint& point) const | |
| 436 { | |
| 437 return m_scrollOffset + point.y() / m_itemHeight; | |
| 438 } | |
| 439 | |
| 440 int PopupMenuWin::focusedIndex() const | |
| 441 { | |
| 442 return m_focusedIndex; | |
| 443 } | |
| 444 | |
| 445 void PopupMenuWin::focusFirst() | |
| 446 { | |
| 447 if (!client()) | |
| 448 return; | |
| 449 | |
| 450 int size = client()->listSize(); | |
| 451 | |
| 452 for (int i = 0; i < size; ++i) | |
| 453 if (client()->itemIsEnabled(i)) { | |
| 454 setFocusedIndex(i); | |
| 455 break; | |
| 456 } | |
| 457 } | |
| 458 | |
| 459 void PopupMenuWin::focusLast() | |
| 460 { | |
| 461 if (!client()) | |
| 462 return; | |
| 463 | |
| 464 int size = client()->listSize(); | |
| 465 | |
| 466 for (int i = size - 1; i > 0; --i) | |
| 467 if (client()->itemIsEnabled(i)) { | |
| 468 setFocusedIndex(i); | |
| 469 break; | |
| 470 } | |
| 471 } | |
| 472 | |
| 473 bool PopupMenuWin::down(unsigned lines) | |
| 474 { | |
| 475 if (!client()) | |
| 476 return false; | |
| 477 | |
| 478 int size = client()->listSize(); | |
| 479 | |
| 480 int lastSelectableIndex, selectedListIndex; | |
| 481 lastSelectableIndex = selectedListIndex = focusedIndex(); | |
| 482 for (int i = selectedListIndex + 1; i >= 0 && i < size; ++i) | |
| 483 if (client()->itemIsEnabled(i)) { | |
| 484 lastSelectableIndex = i; | |
| 485 if (i >= selectedListIndex + (int)lines) | |
| 486 break; | |
| 487 } | |
| 488 | |
| 489 return setFocusedIndex(lastSelectableIndex); | |
| 490 } | |
| 491 | |
| 492 bool PopupMenuWin::up(unsigned lines) | |
| 493 { | |
| 494 if (!client()) | |
| 495 return false; | |
| 496 | |
| 497 int size = client()->listSize(); | |
| 498 | |
| 499 int lastSelectableIndex, selectedListIndex; | |
| 500 lastSelectableIndex = selectedListIndex = focusedIndex(); | |
| 501 for (int i = selectedListIndex - 1; i >= 0 && i < size; --i) | |
| 502 if (client()->itemIsEnabled(i)) { | |
| 503 lastSelectableIndex = i; | |
| 504 if (i <= selectedListIndex - (int)lines) | |
| 505 break; | |
| 506 } | |
| 507 | |
| 508 return setFocusedIndex(lastSelectableIndex); | |
| 509 } | |
| 510 | |
| 511 void PopupMenuWin::invalidateItem(int index) | |
| 512 { | |
| 513 if (!m_popup) | |
| 514 return; | |
| 515 | |
| 516 IntRect damageRect(clientRect()); | |
| 517 damageRect.setY(m_itemHeight * (index - m_scrollOffset)); | |
| 518 damageRect.setHeight(m_itemHeight); | |
| 519 if (m_scrollbar) | |
| 520 damageRect.setWidth(damageRect.width() - m_scrollbar->frameRect().width(
)); | |
| 521 | |
| 522 RECT r = damageRect; | |
| 523 ::InvalidateRect(m_popup, &r, TRUE); | |
| 524 } | |
| 525 | |
| 526 IntRect PopupMenuWin::clientRect() const | |
| 527 { | |
| 528 IntRect clientRect = m_windowRect; | |
| 529 clientRect.inflate(-popupWindowBorderWidth); | |
| 530 clientRect.setLocation(IntPoint(0, 0)); | |
| 531 return clientRect; | |
| 532 } | |
| 533 | |
| 534 void PopupMenuWin::incrementWheelDelta(int delta) | |
| 535 { | |
| 536 m_wheelDelta += delta; | |
| 537 } | |
| 538 | |
| 539 void PopupMenuWin::reduceWheelDelta(int delta) | |
| 540 { | |
| 541 ASSERT(delta >= 0); | |
| 542 ASSERT(delta <= abs(m_wheelDelta)); | |
| 543 | |
| 544 if (m_wheelDelta > 0) | |
| 545 m_wheelDelta -= delta; | |
| 546 else if (m_wheelDelta < 0) | |
| 547 m_wheelDelta += delta; | |
| 548 else | |
| 549 return; | |
| 550 } | |
| 551 | |
| 552 bool PopupMenuWin::scrollToRevealSelection() | |
| 553 { | |
| 554 if (!m_scrollbar) | |
| 555 return false; | |
| 556 | |
| 557 int index = focusedIndex(); | |
| 558 | |
| 559 if (index < m_scrollOffset) { | |
| 560 ScrollableArea::scrollToOffsetWithoutAnimation(VerticalScrollbar, index)
; | |
| 561 return true; | |
| 562 } | |
| 563 | |
| 564 if (index >= m_scrollOffset + visibleItems()) { | |
| 565 ScrollableArea::scrollToOffsetWithoutAnimation(VerticalScrollbar, index
- visibleItems() + 1); | |
| 566 return true; | |
| 567 } | |
| 568 | |
| 569 return false; | |
| 570 } | |
| 571 | |
| 572 void PopupMenuWin::updateFromElement() | |
| 573 { | |
| 574 if (!m_popup) | |
| 575 return; | |
| 576 | |
| 577 m_focusedIndex = client()->selectedIndex(); | |
| 578 | |
| 579 ::InvalidateRect(m_popup, 0, TRUE); | |
| 580 if (!scrollToRevealSelection()) | |
| 581 ::UpdateWindow(m_popup); | |
| 582 } | |
| 583 | |
| 584 const int separatorPadding = 4; | |
| 585 const int separatorHeight = 1; | |
| 586 void PopupMenuWin::paint(const IntRect& damageRect, HDC hdc) | |
| 587 { | |
| 588 if (!m_popup) | |
| 589 return; | |
| 590 | |
| 591 if (!m_DC) { | |
| 592 m_DC = ::CreateCompatibleDC(HWndDC(m_popup)); | |
| 593 if (!m_DC) | |
| 594 return; | |
| 595 } | |
| 596 | |
| 597 if (m_bmp) { | |
| 598 bool keepBitmap = false; | |
| 599 BITMAP bitmap; | |
| 600 if (GetObject(m_bmp, sizeof(bitmap), &bitmap)) | |
| 601 keepBitmap = bitmap.bmWidth == clientRect().width() | |
| 602 && bitmap.bmHeight == clientRect().height(); | |
| 603 if (!keepBitmap) { | |
| 604 DeleteObject(m_bmp); | |
| 605 m_bmp = 0; | |
| 606 } | |
| 607 } | |
| 608 if (!m_bmp) { | |
| 609 #if OS(WINCE) | |
| 610 BitmapInfo bitmapInfo = BitmapInfo::createBottomUp(clientRect().size(),
BitmapInfo::BitCount16); | |
| 611 #else | |
| 612 BitmapInfo bitmapInfo = BitmapInfo::createBottomUp(clientRect().size()); | |
| 613 #endif | |
| 614 void* pixels = 0; | |
| 615 m_bmp = ::CreateDIBSection(m_DC, &bitmapInfo, DIB_RGB_COLORS, &pixels, 0
, 0); | |
| 616 if (!m_bmp) | |
| 617 return; | |
| 618 | |
| 619 ::SelectObject(m_DC, m_bmp); | |
| 620 } | |
| 621 | |
| 622 GraphicsContext context(m_DC); | |
| 623 | |
| 624 int itemCount = client()->listSize(); | |
| 625 | |
| 626 // listRect is the damageRect translated into the coordinates of the entire
menu list (which is itemCount * m_itemHeight pixels tall) | |
| 627 IntRect listRect = damageRect; | |
| 628 listRect.move(IntSize(0, m_scrollOffset * m_itemHeight)); | |
| 629 | |
| 630 for (int y = listRect.y(); y < listRect.maxY(); y += m_itemHeight) { | |
| 631 int index = y / m_itemHeight; | |
| 632 | |
| 633 Color optionBackgroundColor, optionTextColor; | |
| 634 PopupMenuStyle itemStyle = client()->itemStyle(index); | |
| 635 if (index == focusedIndex()) { | |
| 636 optionBackgroundColor = RenderTheme::defaultTheme()->activeListBoxSe
lectionBackgroundColor(); | |
| 637 optionTextColor = RenderTheme::defaultTheme()->activeListBoxSelectio
nForegroundColor(); | |
| 638 } else { | |
| 639 optionBackgroundColor = itemStyle.backgroundColor(); | |
| 640 optionTextColor = itemStyle.foregroundColor(); | |
| 641 } | |
| 642 | |
| 643 // itemRect is in client coordinates | |
| 644 IntRect itemRect(0, (index - m_scrollOffset) * m_itemHeight, damageRect.
width(), m_itemHeight); | |
| 645 | |
| 646 // Draw the background for this menu item | |
| 647 if (itemStyle.isVisible()) | |
| 648 context.fillRect(itemRect, optionBackgroundColor, ColorSpaceDeviceRG
B); | |
| 649 | |
| 650 if (client()->itemIsSeparator(index)) { | |
| 651 IntRect separatorRect(itemRect.x() + separatorPadding, itemRect.y()
+ (itemRect.height() - separatorHeight) / 2, itemRect.width() - 2 * separatorPad
ding, separatorHeight); | |
| 652 context.fillRect(separatorRect, optionTextColor, ColorSpaceDeviceRGB
); | |
| 653 continue; | |
| 654 } | |
| 655 | |
| 656 String itemText = client()->itemText(index); | |
| 657 | |
| 658 TextDirection direction = (itemText.defaultWritingDirection() == WTF::Un
icode::RightToLeft) ? RTL : LTR; | |
| 659 TextRun textRun(itemText, 0, 0, TextRun::AllowTrailingExpansion, directi
on); | |
| 660 | |
| 661 context.setFillColor(optionTextColor, ColorSpaceDeviceRGB); | |
| 662 | |
| 663 Font itemFont = client()->menuStyle().font(); | |
| 664 if (client()->itemIsLabel(index)) { | |
| 665 FontDescription d = itemFont.fontDescription(); | |
| 666 d.setWeight(d.bolderWeight()); | |
| 667 itemFont = Font(d, itemFont.letterSpacing(), itemFont.wordSpacing())
; | |
| 668 itemFont.update(m_popupClient->fontSelector()); | |
| 669 } | |
| 670 | |
| 671 // Draw the item text | |
| 672 if (itemStyle.isVisible()) { | |
| 673 int textX = max<int>(0, client()->clientPaddingLeft() - client()->cl
ientInsetLeft()); | |
| 674 if (RenderTheme::defaultTheme()->popupOptionSupportsTextIndent() &&
itemStyle.textDirection() == LTR) | |
| 675 textX += minimumIntValueForLength(itemStyle.textIndent(), itemRe
ct.width()); | |
| 676 int textY = itemRect.y() + itemFont.fontMetrics().ascent() + (itemRe
ct.height() - itemFont.fontMetrics().height()) / 2; | |
| 677 context.drawBidiText(itemFont, textRun, IntPoint(textX, textY)); | |
| 678 } | |
| 679 } | |
| 680 | |
| 681 if (m_scrollbar) | |
| 682 m_scrollbar->paint(&context, damageRect); | |
| 683 | |
| 684 HWndDC hWndDC; | |
| 685 HDC localDC = hdc ? hdc : hWndDC.setHWnd(m_popup); | |
| 686 | |
| 687 ::BitBlt(localDC, damageRect.x(), damageRect.y(), damageRect.width(), damage
Rect.height(), m_DC, damageRect.x(), damageRect.y(), SRCCOPY); | |
| 688 } | |
| 689 | |
| 690 int PopupMenuWin::scrollSize(ScrollbarOrientation orientation) const | |
| 691 { | |
| 692 return ((orientation == VerticalScrollbar) && m_scrollbar) ? (m_scrollbar->t
otalSize() - m_scrollbar->visibleSize()) : 0; | |
| 693 } | |
| 694 | |
| 695 int PopupMenuWin::scrollPosition(Scrollbar*) const | |
| 696 { | |
| 697 return m_scrollOffset; | |
| 698 } | |
| 699 | |
| 700 void PopupMenuWin::setScrollOffset(const IntPoint& offset) | |
| 701 { | |
| 702 scrollTo(offset.y()); | |
| 703 } | |
| 704 | |
| 705 void PopupMenuWin::scrollTo(int offset) | |
| 706 { | |
| 707 ASSERT(m_scrollbar); | |
| 708 | |
| 709 if (!m_popup) | |
| 710 return; | |
| 711 | |
| 712 if (m_scrollOffset == offset) | |
| 713 return; | |
| 714 | |
| 715 int scrolledLines = m_scrollOffset - offset; | |
| 716 m_scrollOffset = offset; | |
| 717 | |
| 718 UINT flags = SW_INVALIDATE; | |
| 719 | |
| 720 #ifdef CAN_SET_SMOOTH_SCROLLING_DURATION | |
| 721 BOOL shouldSmoothScroll = FALSE; | |
| 722 ::SystemParametersInfo(SPI_GETLISTBOXSMOOTHSCROLLING, 0, &shouldSmoothScroll
, 0); | |
| 723 if (shouldSmoothScroll) | |
| 724 flags |= MAKEWORD(SW_SMOOTHSCROLL, smoothScrollAnimationDuration); | |
| 725 #endif | |
| 726 | |
| 727 IntRect listRect = clientRect(); | |
| 728 if (m_scrollbar) | |
| 729 listRect.setWidth(listRect.width() - m_scrollbar->frameRect().width()); | |
| 730 RECT r = listRect; | |
| 731 ::ScrollWindowEx(m_popup, 0, scrolledLines * m_itemHeight, &r, 0, 0, 0, flag
s); | |
| 732 if (m_scrollbar) { | |
| 733 r = m_scrollbar->frameRect(); | |
| 734 ::InvalidateRect(m_popup, &r, TRUE); | |
| 735 } | |
| 736 ::UpdateWindow(m_popup); | |
| 737 } | |
| 738 | |
| 739 void PopupMenuWin::invalidateScrollbarRect(Scrollbar* scrollbar, const IntRect&
rect) | |
| 740 { | |
| 741 IntRect scrollRect = rect; | |
| 742 scrollRect.move(scrollbar->x(), scrollbar->y()); | |
| 743 RECT r = scrollRect; | |
| 744 ::InvalidateRect(m_popup, &r, false); | |
| 745 } | |
| 746 | |
| 747 int PopupMenuWin::visibleHeight() const | |
| 748 { | |
| 749 return m_scrollbar ? m_scrollbar->visibleSize() : m_windowRect.height(); | |
| 750 } | |
| 751 | |
| 752 int PopupMenuWin::visibleWidth() const | |
| 753 { | |
| 754 return m_windowRect.width(); | |
| 755 } | |
| 756 | |
| 757 IntSize PopupMenuWin::contentsSize() const | |
| 758 { | |
| 759 return m_windowRect.size(); | |
| 760 } | |
| 761 | |
| 762 bool PopupMenuWin::scrollbarsCanBeActive() const | |
| 763 { | |
| 764 return m_showPopup; | |
| 765 } | |
| 766 | |
| 767 IntRect PopupMenuWin::scrollableAreaBoundingBox() const | |
| 768 { | |
| 769 return m_windowRect; | |
| 770 } | |
| 771 | |
| 772 void PopupMenuWin::registerClass() | |
| 773 { | |
| 774 static bool haveRegisteredWindowClass = false; | |
| 775 | |
| 776 if (haveRegisteredWindowClass) | |
| 777 return; | |
| 778 | |
| 779 #if OS(WINCE) | |
| 780 WNDCLASS wcex; | |
| 781 #else | |
| 782 WNDCLASSEX wcex; | |
| 783 wcex.cbSize = sizeof(WNDCLASSEX); | |
| 784 wcex.hIconSm = 0; | |
| 785 wcex.style = CS_DROPSHADOW; | |
| 786 #endif | |
| 787 | |
| 788 wcex.lpfnWndProc = PopupMenuWndProc; | |
| 789 wcex.cbClsExtra = 0; | |
| 790 wcex.cbWndExtra = sizeof(PopupMenu*); // For the PopupMenu pointer | |
| 791 wcex.hInstance = WebCore::instanceHandle(); | |
| 792 wcex.hIcon = 0; | |
| 793 wcex.hCursor = LoadCursor(0, IDC_ARROW); | |
| 794 wcex.hbrBackground = 0; | |
| 795 wcex.lpszMenuName = 0; | |
| 796 wcex.lpszClassName = kPopupWindowClassName; | |
| 797 | |
| 798 haveRegisteredWindowClass = true; | |
| 799 | |
| 800 #if OS(WINCE) | |
| 801 RegisterClass(&wcex); | |
| 802 #else | |
| 803 RegisterClassEx(&wcex); | |
| 804 #endif | |
| 805 } | |
| 806 | |
| 807 | |
| 808 LRESULT CALLBACK PopupMenuWin::PopupMenuWndProc(HWND hWnd, UINT message, WPARAM
wParam, LPARAM lParam) | |
| 809 { | |
| 810 if (PopupMenuWin* popup = static_cast<PopupMenuWin*>(getWindowPointer(hWnd,
0))) | |
| 811 return popup->wndProc(hWnd, message, wParam, lParam); | |
| 812 | |
| 813 if (message == WM_CREATE) { | |
| 814 LPCREATESTRUCT createStruct = reinterpret_cast<LPCREATESTRUCT>(lParam); | |
| 815 | |
| 816 // Associate the PopupMenu with the window. | |
| 817 setWindowPointer(hWnd, 0, createStruct->lpCreateParams); | |
| 818 return 0; | |
| 819 } | |
| 820 | |
| 821 return ::DefWindowProc(hWnd, message, wParam, lParam); | |
| 822 } | |
| 823 | |
| 824 const int smoothScrollAnimationDuration = 5000; | |
| 825 | |
| 826 LRESULT PopupMenuWin::wndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lPa
ram) | |
| 827 { | |
| 828 LRESULT lResult = 0; | |
| 829 | |
| 830 switch (message) { | |
| 831 #if !OS(WINCE) | |
| 832 case WM_MOUSEACTIVATE: | |
| 833 return MA_NOACTIVATE; | |
| 834 #endif | |
| 835 case WM_SIZE: { | |
| 836 if (!scrollbar()) | |
| 837 break; | |
| 838 | |
| 839 IntSize size(LOWORD(lParam), HIWORD(lParam)); | |
| 840 scrollbar()->setFrameRect(IntRect(size.width() - scrollbar()->width(
), 0, scrollbar()->width(), size.height())); | |
| 841 | |
| 842 int visibleItems = this->visibleItems(); | |
| 843 scrollbar()->setEnabled(visibleItems < client()->listSize()); | |
| 844 scrollbar()->setSteps(1, max(1, visibleItems - 1)); | |
| 845 scrollbar()->setProportion(visibleItems, client()->listSize()); | |
| 846 | |
| 847 break; | |
| 848 } | |
| 849 case WM_SYSKEYDOWN: | |
| 850 case WM_KEYDOWN: { | |
| 851 if (!client()) | |
| 852 break; | |
| 853 | |
| 854 bool altKeyPressed = GetKeyState(VK_MENU) & HIGH_BIT_MASK_SHORT; | |
| 855 bool ctrlKeyPressed = GetKeyState(VK_CONTROL) & HIGH_BIT_MASK_SHORT; | |
| 856 | |
| 857 lResult = 0; | |
| 858 switch (LOWORD(wParam)) { | |
| 859 case VK_F4: { | |
| 860 if (!altKeyPressed && !ctrlKeyPressed) { | |
| 861 int index = focusedIndex(); | |
| 862 ASSERT(index >= 0); | |
| 863 client()->valueChanged(index); | |
| 864 hide(); | |
| 865 } | |
| 866 break; | |
| 867 } | |
| 868 case VK_DOWN: | |
| 869 if (altKeyPressed) { | |
| 870 int index = focusedIndex(); | |
| 871 ASSERT(index >= 0); | |
| 872 client()->valueChanged(index); | |
| 873 hide(); | |
| 874 } else | |
| 875 down(); | |
| 876 break; | |
| 877 case VK_RIGHT: | |
| 878 down(); | |
| 879 break; | |
| 880 case VK_UP: | |
| 881 if (altKeyPressed) { | |
| 882 int index = focusedIndex(); | |
| 883 ASSERT(index >= 0); | |
| 884 client()->valueChanged(index); | |
| 885 hide(); | |
| 886 } else | |
| 887 up(); | |
| 888 break; | |
| 889 case VK_LEFT: | |
| 890 up(); | |
| 891 break; | |
| 892 case VK_HOME: | |
| 893 focusFirst(); | |
| 894 break; | |
| 895 case VK_END: | |
| 896 focusLast(); | |
| 897 break; | |
| 898 case VK_PRIOR: | |
| 899 if (focusedIndex() != scrollOffset()) { | |
| 900 // Set the selection to the first visible item | |
| 901 int firstVisibleItem = scrollOffset(); | |
| 902 up(focusedIndex() - firstVisibleItem); | |
| 903 } else { | |
| 904 // The first visible item is selected, so move the selec
tion back one page | |
| 905 up(visibleItems()); | |
| 906 } | |
| 907 break; | |
| 908 case VK_NEXT: { | |
| 909 int lastVisibleItem = scrollOffset() + visibleItems() - 1; | |
| 910 if (focusedIndex() != lastVisibleItem) { | |
| 911 // Set the selection to the last visible item | |
| 912 down(lastVisibleItem - focusedIndex()); | |
| 913 } else { | |
| 914 // The last visible item is selected, so move the select
ion forward one page | |
| 915 down(visibleItems()); | |
| 916 } | |
| 917 break; | |
| 918 } | |
| 919 case VK_TAB: | |
| 920 ::SendMessage(client()->hostWindow()->platformPageClient(),
message, wParam, lParam); | |
| 921 hide(); | |
| 922 break; | |
| 923 case VK_ESCAPE: | |
| 924 hide(); | |
| 925 break; | |
| 926 default: | |
| 927 if (isASCIIPrintable(wParam)) | |
| 928 // Send the keydown to the WebView so it can be used for
type-to-select. | |
| 929 // Since we know that the virtual key is ASCII printable
, it's OK to convert this to | |
| 930 // a WM_CHAR message. (We don't want to call TranslateMe
ssage because that will post a | |
| 931 // WM_CHAR message that will be stolen and redirected to
the popup HWND. | |
| 932 ::PostMessage(m_popup, WM_HOST_WINDOW_CHAR, wParam, lPar
am); | |
| 933 else | |
| 934 lResult = 1; | |
| 935 break; | |
| 936 } | |
| 937 break; | |
| 938 } | |
| 939 case WM_CHAR: { | |
| 940 if (!client()) | |
| 941 break; | |
| 942 | |
| 943 lResult = 0; | |
| 944 int index; | |
| 945 switch (wParam) { | |
| 946 case 0x0D: // Enter/Return | |
| 947 hide(); | |
| 948 index = focusedIndex(); | |
| 949 ASSERT(index >= 0); | |
| 950 client()->valueChanged(index); | |
| 951 break; | |
| 952 case 0x1B: // Escape | |
| 953 hide(); | |
| 954 break; | |
| 955 case 0x09: // TAB | |
| 956 case 0x08: // Backspace | |
| 957 case 0x0A: // Linefeed | |
| 958 default: // Character | |
| 959 lResult = 1; | |
| 960 break; | |
| 961 } | |
| 962 break; | |
| 963 } | |
| 964 case WM_MOUSEMOVE: { | |
| 965 IntPoint mousePoint(MAKEPOINTS(lParam)); | |
| 966 if (scrollbar()) { | |
| 967 IntRect scrollBarRect = scrollbar()->frameRect(); | |
| 968 if (scrollbarCapturingMouse() || scrollBarRect.contains(mousePoi
nt)) { | |
| 969 // Put the point into coordinates relative to the scroll bar | |
| 970 mousePoint.move(-scrollBarRect.x(), -scrollBarRect.y()); | |
| 971 PlatformMouseEvent event(hWnd, message, wParam, MAKELPARAM(m
ousePoint.x(), mousePoint.y())); | |
| 972 scrollbar()->mouseMoved(event); | |
| 973 break; | |
| 974 } | |
| 975 } | |
| 976 | |
| 977 BOOL shouldHotTrack = FALSE; | |
| 978 #if !OS(WINCE) | |
| 979 ::SystemParametersInfo(SPI_GETHOTTRACKING, 0, &shouldHotTrack, 0); | |
| 980 #endif | |
| 981 | |
| 982 RECT bounds; | |
| 983 GetClientRect(popupHandle(), &bounds); | |
| 984 if (!::PtInRect(&bounds, mousePoint) && !(wParam & MK_LBUTTON) && cl
ient()) { | |
| 985 // When the mouse is not inside the popup menu and the left butt
on isn't down, just | |
| 986 // repost the message to the web view. | |
| 987 | |
| 988 // Translate the coordinate. | |
| 989 translatePoint(lParam, m_popup, client()->hostWindow()->platform
PageClient()); | |
| 990 | |
| 991 ::PostMessage(m_popup, WM_HOST_WINDOW_MOUSEMOVE, wParam, lParam)
; | |
| 992 break; | |
| 993 } | |
| 994 | |
| 995 if ((shouldHotTrack || wParam & MK_LBUTTON) && ::PtInRect(&bounds, m
ousePoint)) | |
| 996 setFocusedIndex(listIndexAtPoint(mousePoint), true); | |
| 997 | |
| 998 break; | |
| 999 } | |
| 1000 case WM_LBUTTONDOWN: { | |
| 1001 IntPoint mousePoint(MAKEPOINTS(lParam)); | |
| 1002 if (scrollbar()) { | |
| 1003 IntRect scrollBarRect = scrollbar()->frameRect(); | |
| 1004 if (scrollBarRect.contains(mousePoint)) { | |
| 1005 // Put the point into coordinates relative to the scroll bar | |
| 1006 mousePoint.move(-scrollBarRect.x(), -scrollBarRect.y()); | |
| 1007 PlatformMouseEvent event(hWnd, message, wParam, MAKELPARAM(m
ousePoint.x(), mousePoint.y())); | |
| 1008 scrollbar()->mouseDown(event); | |
| 1009 setScrollbarCapturingMouse(true); | |
| 1010 break; | |
| 1011 } | |
| 1012 } | |
| 1013 | |
| 1014 // If the mouse is inside the window, update the focused index. Othe
rwise, | |
| 1015 // hide the popup. | |
| 1016 RECT bounds; | |
| 1017 GetClientRect(m_popup, &bounds); | |
| 1018 if (::PtInRect(&bounds, mousePoint)) | |
| 1019 setFocusedIndex(listIndexAtPoint(mousePoint), true); | |
| 1020 else | |
| 1021 hide(); | |
| 1022 break; | |
| 1023 } | |
| 1024 case WM_LBUTTONUP: { | |
| 1025 IntPoint mousePoint(MAKEPOINTS(lParam)); | |
| 1026 if (scrollbar()) { | |
| 1027 IntRect scrollBarRect = scrollbar()->frameRect(); | |
| 1028 if (scrollbarCapturingMouse() || scrollBarRect.contains(mousePoi
nt)) { | |
| 1029 setScrollbarCapturingMouse(false); | |
| 1030 // Put the point into coordinates relative to the scroll bar | |
| 1031 mousePoint.move(-scrollBarRect.x(), -scrollBarRect.y()); | |
| 1032 PlatformMouseEvent event(hWnd, message, wParam, MAKELPARAM(m
ousePoint.x(), mousePoint.y())); | |
| 1033 scrollbar()->mouseUp(event); | |
| 1034 // FIXME: This is a hack to work around Scrollbar not invali
dating correctly when it doesn't have a parent widget | |
| 1035 RECT r = scrollBarRect; | |
| 1036 ::InvalidateRect(popupHandle(), &r, TRUE); | |
| 1037 break; | |
| 1038 } | |
| 1039 } | |
| 1040 // Only hide the popup if the mouse is inside the popup window. | |
| 1041 RECT bounds; | |
| 1042 GetClientRect(popupHandle(), &bounds); | |
| 1043 if (client() && ::PtInRect(&bounds, mousePoint)) { | |
| 1044 hide(); | |
| 1045 int index = focusedIndex(); | |
| 1046 if (index >= 0) | |
| 1047 client()->valueChanged(index); | |
| 1048 } | |
| 1049 break; | |
| 1050 } | |
| 1051 | |
| 1052 case WM_MOUSEWHEEL: { | |
| 1053 if (!scrollbar()) | |
| 1054 break; | |
| 1055 | |
| 1056 int i = 0; | |
| 1057 for (incrementWheelDelta(GET_WHEEL_DELTA_WPARAM(wParam)); abs(wheelD
elta()) >= WHEEL_DELTA; reduceWheelDelta(WHEEL_DELTA)) { | |
| 1058 if (wheelDelta() > 0) | |
| 1059 ++i; | |
| 1060 else | |
| 1061 --i; | |
| 1062 } | |
| 1063 | |
| 1064 ScrollableArea::scroll(i > 0 ? ScrollUp : ScrollDown, ScrollByLine,
abs(i)); | |
| 1065 break; | |
| 1066 } | |
| 1067 | |
| 1068 case WM_PAINT: { | |
| 1069 PAINTSTRUCT paintInfo; | |
| 1070 ::BeginPaint(popupHandle(), &paintInfo); | |
| 1071 paint(paintInfo.rcPaint, paintInfo.hdc); | |
| 1072 ::EndPaint(popupHandle(), &paintInfo); | |
| 1073 lResult = 0; | |
| 1074 break; | |
| 1075 } | |
| 1076 #if !OS(WINCE) | |
| 1077 case WM_PRINTCLIENT: | |
| 1078 paint(clientRect(), (HDC)wParam); | |
| 1079 break; | |
| 1080 #endif | |
| 1081 default: | |
| 1082 lResult = DefWindowProc(hWnd, message, wParam, lParam); | |
| 1083 } | |
| 1084 | |
| 1085 return lResult; | |
| 1086 } | |
| 1087 | |
| 1088 } | |
| OLD | NEW |