| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright (c) 2011, Google Inc. All rights reserved. | 2 * Copyright (c) 2011, Google Inc. All rights reserved. |
| 3 * | 3 * |
| 4 * Redistribution and use in source and binary forms, with or without | 4 * Redistribution and use in source and binary forms, with or without |
| 5 * modification, are permitted provided that the following conditions are | 5 * modification, are permitted provided that the following conditions are |
| 6 * met: | 6 * met: |
| 7 * | 7 * |
| 8 * * Redistributions of source code must retain the above copyright | 8 * * Redistributions of source code must retain the above copyright |
| 9 * notice, this list of conditions and the following disclaimer. | 9 * notice, this list of conditions and the following disclaimer. |
| 10 * * Redistributions in binary form must reproduce the above | 10 * * Redistributions in binary form must reproduce the above |
| (...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 66 | 66 |
| 67 using namespace WTF::Unicode; | 67 using namespace WTF::Unicode; |
| 68 | 68 |
| 69 const int PopupListBox::defaultMaxHeight = 500; | 69 const int PopupListBox::defaultMaxHeight = 500; |
| 70 static const int maxVisibleRows = 20; | 70 static const int maxVisibleRows = 20; |
| 71 static const int minEndOfLinePadding = 2; | 71 static const int minEndOfLinePadding = 2; |
| 72 static const TimeStamp typeAheadTimeoutMs = 1000; | 72 static const TimeStamp typeAheadTimeoutMs = 1000; |
| 73 | 73 |
| 74 PopupListBox::PopupListBox(PopupMenuClient* client, bool deviceSupportsTouch, Po
pupContainer* container) | 74 PopupListBox::PopupListBox(PopupMenuClient* client, bool deviceSupportsTouch, Po
pupContainer* container) |
| 75 : m_deviceSupportsTouch(deviceSupportsTouch) | 75 : m_deviceSupportsTouch(deviceSupportsTouch) |
| 76 , m_originalIndex(0) | |
| 77 , m_selectedIndex(0) | 76 , m_selectedIndex(0) |
| 78 , m_acceptedIndexOnAbandon(-1) | |
| 79 , m_visibleRows(0) | 77 , m_visibleRows(0) |
| 80 , m_baseWidth(0) | 78 , m_baseWidth(0) |
| 81 , m_maxHeight(defaultMaxHeight) | 79 , m_maxHeight(defaultMaxHeight) |
| 82 , m_popupClient(client) | 80 , m_popupClient(client) |
| 83 , m_repeatingChar(0) | 81 , m_repeatingChar(0) |
| 84 , m_lastCharTime(0) | 82 , m_lastCharTime(0) |
| 85 , m_maxWindowWidth(std::numeric_limits<int>::max()) | 83 , m_maxWindowWidth(std::numeric_limits<int>::max()) |
| 86 , m_container(container) | 84 , m_container(container) |
| 87 { | 85 { |
| 88 } | 86 } |
| (...skipping 21 matching lines...) Expand all Loading... |
| 110 bool PopupListBox::handleMouseDownEvent(const PlatformMouseEvent& event) | 108 bool PopupListBox::handleMouseDownEvent(const PlatformMouseEvent& event) |
| 111 { | 109 { |
| 112 Scrollbar* scrollbar = scrollbarAtRootFramePoint(event.position()); | 110 Scrollbar* scrollbar = scrollbarAtRootFramePoint(event.position()); |
| 113 if (scrollbar) { | 111 if (scrollbar) { |
| 114 m_capturingScrollbar = scrollbar; | 112 m_capturingScrollbar = scrollbar; |
| 115 m_capturingScrollbar->mouseDown(event); | 113 m_capturingScrollbar->mouseDown(event); |
| 116 return true; | 114 return true; |
| 117 } | 115 } |
| 118 | 116 |
| 119 if (!isPointInBounds(event.position())) | 117 if (!isPointInBounds(event.position())) |
| 120 abandon(); | 118 cancel(); |
| 121 | 119 |
| 122 return true; | 120 return true; |
| 123 } | 121 } |
| 124 | 122 |
| 125 bool PopupListBox::handleMouseMoveEvent(const PlatformMouseEvent& event) | 123 bool PopupListBox::handleMouseMoveEvent(const PlatformMouseEvent& event) |
| 126 { | 124 { |
| 127 if (m_capturingScrollbar) { | 125 if (m_capturingScrollbar) { |
| 128 m_capturingScrollbar->mouseMoved(event); | 126 m_capturingScrollbar->mouseMoved(event); |
| 129 return true; | 127 return true; |
| 130 } | 128 } |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 168 // which is called before dispatchMouseEvent() is called. | 166 // which is called before dispatchMouseEvent() is called. |
| 169 m_focusedElement = nullptr; | 167 m_focusedElement = nullptr; |
| 170 } | 168 } |
| 171 | 169 |
| 172 return true; | 170 return true; |
| 173 } | 171 } |
| 174 | 172 |
| 175 bool PopupListBox::handleWheelEvent(const PlatformWheelEvent& event) | 173 bool PopupListBox::handleWheelEvent(const PlatformWheelEvent& event) |
| 176 { | 174 { |
| 177 if (!isPointInBounds(event.position())) { | 175 if (!isPointInBounds(event.position())) { |
| 178 abandon(); | 176 cancel(); |
| 179 return true; | 177 return true; |
| 180 } | 178 } |
| 181 | 179 |
| 182 ScrollableArea::handleWheelEvent(event); | 180 ScrollableArea::handleWheelEvent(event); |
| 183 return true; | 181 return true; |
| 184 } | 182 } |
| 185 | 183 |
| 186 bool PopupListBox::handleTouchEvent(const PlatformTouchEvent&) | 184 bool PopupListBox::handleTouchEvent(const PlatformTouchEvent&) |
| 187 { | 185 { |
| 188 return false; | 186 return false; |
| (...skipping 16 matching lines...) Expand all Loading... |
| 205 bool PopupListBox::handleKeyEvent(const PlatformKeyboardEvent& event) | 203 bool PopupListBox::handleKeyEvent(const PlatformKeyboardEvent& event) |
| 206 { | 204 { |
| 207 if (event.type() == PlatformEvent::KeyUp) | 205 if (event.type() == PlatformEvent::KeyUp) |
| 208 return true; | 206 return true; |
| 209 | 207 |
| 210 if (!numItems() && event.windowsVirtualKeyCode() != VKEY_ESCAPE) | 208 if (!numItems() && event.windowsVirtualKeyCode() != VKEY_ESCAPE) |
| 211 return true; | 209 return true; |
| 212 | 210 |
| 213 switch (event.windowsVirtualKeyCode()) { | 211 switch (event.windowsVirtualKeyCode()) { |
| 214 case VKEY_ESCAPE: | 212 case VKEY_ESCAPE: |
| 215 abandon(); // may delete this | 213 cancel(); // may delete this |
| 216 return true; | 214 return true; |
| 217 case VKEY_RETURN: | 215 case VKEY_RETURN: |
| 218 if (m_selectedIndex == -1) { | 216 if (m_selectedIndex == -1) { |
| 219 hidePopup(); | 217 hidePopup(); |
| 220 // Don't eat the enter if nothing is selected. | 218 // Don't eat the enter if nothing is selected. |
| 221 return false; | 219 return false; |
| 222 } | 220 } |
| 223 acceptIndex(m_selectedIndex); // may delete this | 221 acceptIndex(m_selectedIndex); // may delete this |
| 224 return true; | 222 return true; |
| 225 case VKEY_UP: | 223 case VKEY_UP: |
| (...skipping 20 matching lines...) Expand all Loading... |
| 246 && isCharacterTypeEvent(event)) | 244 && isCharacterTypeEvent(event)) |
| 247 typeAheadFind(event); | 245 typeAheadFind(event); |
| 248 break; | 246 break; |
| 249 } | 247 } |
| 250 | 248 |
| 251 if (event.altKey() && (event.keyIdentifier() == "Down" || event.keyIdentifie
r() == "Up")) { | 249 if (event.altKey() && (event.keyIdentifier() == "Down" || event.keyIdentifie
r() == "Up")) { |
| 252 hidePopup(); | 250 hidePopup(); |
| 253 return true; | 251 return true; |
| 254 } | 252 } |
| 255 | 253 |
| 256 if (m_originalIndex != m_selectedIndex) { | 254 m_popupClient->provisionalSelectionChanged(m_selectedIndex); |
| 257 // Keyboard events should update the selection immediately (but we don't | |
| 258 // want to fire the onchange event until the popup is closed, to match | |
| 259 // IE). We change the original index so we revert to that when the | |
| 260 // popup is closed. | |
| 261 m_acceptedIndexOnAbandon = m_selectedIndex; | |
| 262 | |
| 263 setOriginalIndex(m_selectedIndex); | |
| 264 m_popupClient->setTextFromItem(m_selectedIndex); | |
| 265 } | |
| 266 if (event.windowsVirtualKeyCode() == VKEY_TAB) { | 255 if (event.windowsVirtualKeyCode() == VKEY_TAB) { |
| 267 // TAB is a special case as it should select the current item if any and | 256 // TAB is a special case as it should select the current item if any and |
| 268 // advance focus. | 257 // advance focus. |
| 269 if (m_selectedIndex >= 0) { | 258 if (m_selectedIndex >= 0) { |
| 270 acceptIndex(m_selectedIndex); // May delete us. | 259 acceptIndex(m_selectedIndex); // May delete us. |
| 271 // Return false so the TAB key event is propagated to the page. | 260 // Return false so the TAB key event is propagated to the page. |
| 272 return false; | 261 return false; |
| 273 } | 262 } |
| 274 // Call abandon() so we honor m_acceptedIndexOnAbandon if set. | 263 cancel(); |
| 275 abandon(); | |
| 276 // Return false so the TAB key event is propagated to the page. | 264 // Return false so the TAB key event is propagated to the page. |
| 277 return false; | 265 return false; |
| 278 } | 266 } |
| 279 | 267 |
| 280 return true; | 268 return true; |
| 281 } | 269 } |
| 282 | 270 |
| 283 HostWindow* PopupListBox::hostWindow() const | 271 HostWindow* PopupListBox::hostWindow() const |
| 284 { | 272 { |
| 285 // Our parent is the root FrameView, so it is the one that has a | 273 // Our parent is the root FrameView, so it is the one that has a |
| (...skipping 205 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 491 FontDescription d = itemFont.fontDescription(); | 479 FontDescription d = itemFont.fontDescription(); |
| 492 d.setWeight(FontWeightBold); | 480 d.setWeight(FontWeightBold); |
| 493 Font font(d); | 481 Font font(d); |
| 494 font.update(nullptr); | 482 font.update(nullptr); |
| 495 return font; | 483 return font; |
| 496 } | 484 } |
| 497 | 485 |
| 498 return itemFont; | 486 return itemFont; |
| 499 } | 487 } |
| 500 | 488 |
| 501 void PopupListBox::abandon() | 489 void PopupListBox::cancel() |
| 502 { | 490 { |
| 503 RefPtrWillBeRawPtr<PopupListBox> protect(this); | 491 RefPtrWillBeRawPtr<PopupListBox> protect(this); |
| 504 | 492 |
| 505 m_selectedIndex = m_originalIndex; | |
| 506 | |
| 507 hidePopup(); | 493 hidePopup(); |
| 508 | 494 |
| 509 if (m_acceptedIndexOnAbandon >= 0) { | 495 if (m_popupClient) |
| 510 if (m_popupClient) | 496 m_popupClient->popupDidCancel(); |
| 511 m_popupClient->valueChanged(m_acceptedIndexOnAbandon); | |
| 512 m_acceptedIndexOnAbandon = -1; | |
| 513 } | |
| 514 } | 497 } |
| 515 | 498 |
| 516 int PopupListBox::pointToRowIndex(const IntPoint& point) | 499 int PopupListBox::pointToRowIndex(const IntPoint& point) |
| 517 { | 500 { |
| 518 int y = scrollY() + point.y(); | 501 int y = scrollY() + point.y(); |
| 519 | 502 |
| 520 // FIXME: binary search if perf matters. | 503 // FIXME: binary search if perf matters. |
| 521 for (int i = 0; i < numItems(); ++i) { | 504 for (int i = 0; i < numItems(); ++i) { |
| 522 if (y < m_items[i]->yOffset) | 505 if (y < m_items[i]->yOffset) |
| 523 return i-1; | 506 return i-1; |
| 524 } | 507 } |
| 525 | 508 |
| 526 // Last item? | 509 // Last item? |
| 527 if (y < contentsSize().height()) | 510 if (y < contentsSize().height()) |
| 528 return m_items.size()-1; | 511 return m_items.size()-1; |
| 529 | 512 |
| 530 return -1; | 513 return -1; |
| 531 } | 514 } |
| 532 | 515 |
| 533 bool PopupListBox::acceptIndex(int index) | 516 bool PopupListBox::acceptIndex(int index) |
| 534 { | 517 { |
| 535 // Clear m_acceptedIndexOnAbandon once user accepts the selected index. | |
| 536 if (m_acceptedIndexOnAbandon >= 0) | |
| 537 m_acceptedIndexOnAbandon = -1; | |
| 538 | |
| 539 if (index >= numItems()) | 518 if (index >= numItems()) |
| 540 return false; | 519 return false; |
| 541 | 520 |
| 542 if (index < 0) { | 521 if (index < 0) { |
| 543 if (m_popupClient) { | 522 if (m_popupClient) { |
| 544 // Enter pressed with no selection, just close the popup. | 523 // Enter pressed with no selection, just close the popup. |
| 545 hidePopup(); | 524 hidePopup(); |
| 546 } | 525 } |
| 547 return false; | 526 return false; |
| 548 } | 527 } |
| (...skipping 23 matching lines...) Expand all Loading... |
| 572 invalidateRow(m_selectedIndex); | 551 invalidateRow(m_selectedIndex); |
| 573 m_selectedIndex = index; | 552 m_selectedIndex = index; |
| 574 invalidateRow(m_selectedIndex); | 553 invalidateRow(m_selectedIndex); |
| 575 | 554 |
| 576 scrollToRevealSelection(); | 555 scrollToRevealSelection(); |
| 577 m_popupClient->selectionChanged(m_selectedIndex); | 556 m_popupClient->selectionChanged(m_selectedIndex); |
| 578 } else if (!isSelectable) | 557 } else if (!isSelectable) |
| 579 clearSelection(); | 558 clearSelection(); |
| 580 } | 559 } |
| 581 | 560 |
| 582 void PopupListBox::setOriginalIndex(int index) | |
| 583 { | |
| 584 m_originalIndex = m_selectedIndex = index; | |
| 585 } | |
| 586 | |
| 587 int PopupListBox::getRowHeight(int index) const | 561 int PopupListBox::getRowHeight(int index) const |
| 588 { | 562 { |
| 589 int minimumHeight = m_deviceSupportsTouch ? optionRowHeightForTouch : minRow
Height; | 563 int minimumHeight = m_deviceSupportsTouch ? optionRowHeightForTouch : minRow
Height; |
| 590 | 564 |
| 591 if (index < 0 || m_popupClient->itemStyle(index).isDisplayNone()) | 565 if (index < 0 || m_popupClient->itemStyle(index).isDisplayNone()) |
| 592 return minimumHeight; | 566 return minimumHeight; |
| 593 | 567 |
| 594 // Separator row height is the same size as itself. | 568 // Separator row height is the same size as itself. |
| 595 if (m_popupClient->itemIsSeparator(index)) | 569 if (m_popupClient->itemIsSeparator(index)) |
| 596 return max(separatorHeight, minimumHeight); | 570 return max(separatorHeight, minimumHeight); |
| (...skipping 129 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 726 else | 700 else |
| 727 type = PopupItem::TypeOption; | 701 type = PopupItem::TypeOption; |
| 728 m_items.append(adoptPtr(new PopupItem(m_popupClient->itemText(i), type))
); | 702 m_items.append(adoptPtr(new PopupItem(m_popupClient->itemText(i), type))
); |
| 729 m_items[i]->enabled = isSelectableItem(i); | 703 m_items[i]->enabled = isSelectableItem(i); |
| 730 PopupMenuStyle style = m_popupClient->itemStyle(i); | 704 PopupMenuStyle style = m_popupClient->itemStyle(i); |
| 731 m_items[i]->textDirection = style.textDirection(); | 705 m_items[i]->textDirection = style.textDirection(); |
| 732 m_items[i]->hasTextDirectionOverride = style.hasTextDirectionOverride(); | 706 m_items[i]->hasTextDirectionOverride = style.hasTextDirectionOverride(); |
| 733 m_items[i]->displayNone = style.isDisplayNone(); | 707 m_items[i]->displayNone = style.isDisplayNone(); |
| 734 } | 708 } |
| 735 | 709 |
| 736 if (m_originalIndex != m_popupClient->selectedIndex() || m_selectedIndex >=
static_cast<int>(m_items.size())) | 710 if (m_selectedIndex >= static_cast<int>(m_items.size())) |
| 737 setOriginalIndex(m_popupClient->selectedIndex()); | 711 m_selectedIndex = m_popupClient->selectedIndex(); |
| 738 | 712 |
| 739 layout(); | 713 layout(); |
| 740 } | 714 } |
| 741 | 715 |
| 742 void PopupListBox::setMaxWidthAndLayout(int maxWidth) | 716 void PopupListBox::setMaxWidthAndLayout(int maxWidth) |
| 743 { | 717 { |
| 744 m_maxWindowWidth = maxWidth; | 718 m_maxWindowWidth = maxWidth; |
| 745 layout(); | 719 layout(); |
| 746 } | 720 } |
| 747 | 721 |
| (...skipping 303 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1051 maximumOffset.clampNegativeToZero(); | 1025 maximumOffset.clampNegativeToZero(); |
| 1052 return maximumOffset; | 1026 return maximumOffset; |
| 1053 } | 1027 } |
| 1054 | 1028 |
| 1055 IntPoint PopupListBox::minimumScrollPosition() const | 1029 IntPoint PopupListBox::minimumScrollPosition() const |
| 1056 { | 1030 { |
| 1057 return IntPoint(-scrollOrigin().x(), -scrollOrigin().y()); | 1031 return IntPoint(-scrollOrigin().x(), -scrollOrigin().y()); |
| 1058 } | 1032 } |
| 1059 | 1033 |
| 1060 } // namespace blink | 1034 } // namespace blink |
| OLD | NEW |