void Flickable::handleMouseRelease(QMouseEvent *event) { // qDebug() << "+ " << __PRETTY_FUNCTION__; event->ignore(); if (event->button() != Qt::LeftButton) return; if (d->ignoreList.removeAll(event)) return; QPoint delta; switch (d->state) { case FlickablePrivate::Pressed: d->state = FlickablePrivate::Steady; if (d->target) { QMouseEvent *event1 = new QMouseEvent(QEvent::MouseButtonPress, d->pressPos, Qt::LeftButton, Qt::LeftButton, Qt::NoModifier); QMouseEvent *event2 = new QMouseEvent(*event); d->ignoreList << event1; d->ignoreList << event2; QApplication::postEvent(d->target, event1); QApplication::postEvent(d->target, event2); } event->accept(); break; case FlickablePrivate::ManualScroll: event->accept(); delta = event->pos() - d->pressPos; if (d->timeStamp.elapsed() > 100) { d->timeStamp = QTime::currentTime(); d->speed = delta - d->delta; d->delta = delta; } d->offset = scrollOffset(); d->pressPos = event->pos(); if (d->speed == QPoint(0, 0)) { d->state = FlickablePrivate::Steady; } else { d->speed /= 4; d->state = FlickablePrivate::AutoScroll; d->ticker->start(20); } break; case FlickablePrivate::Stop: event->accept(); d->state = FlickablePrivate::Steady; d->offset = scrollOffset(); break; default: break; } }
void ScrollView::wheelEvent(PlatformWheelEvent& e) { // Determine how much we want to scroll. If we can move at all, we will accept the event. IntSize maxScrollDelta = maximumScroll(); if ((e.deltaX() < 0 && maxScrollDelta.width() > 0) || (e.deltaX() > 0 && scrollOffset().width() > 0) || (e.deltaY() < 0 && maxScrollDelta.height() > 0) || (e.deltaY() > 0 && scrollOffset().height() > 0)) { e.accept(); scrollBy(-e.deltaX() * LINE_STEP, -e.deltaY() * LINE_STEP); } }
/* * The following is assumed: * (hadj && vadj) || (!hadj && !vadj) */ void ScrollView::setGtkAdjustments(GtkAdjustment* hadj, GtkAdjustment* vadj, bool resetValues) { ASSERT(!hadj == !vadj); m_horizontalAdjustment = hadj; m_verticalAdjustment = vadj; // Reset the adjustments to a sane default if (m_horizontalAdjustment) { ScrollbarGtk* hScrollbar = reinterpret_cast<ScrollbarGtk*>(horizontalScrollbar()); if (hScrollbar) hScrollbar->attachAdjustment(m_horizontalAdjustment); ScrollbarGtk* vScrollbar = reinterpret_cast<ScrollbarGtk*>(verticalScrollbar()); if (vScrollbar) vScrollbar->attachAdjustment(m_verticalAdjustment); // We used to reset everything to 0 here, but when page cache // is enabled we reuse FrameViews that are cached. Since their // size is not going to change when being restored, (which is // what would cause the upper limit in the adjusments to be // set in the normal case), we make sure they are up-to-date // here. This is needed for the parent scrolling widget to be // able to report correct values. m_horizontalAdjustment->lower = 0; m_horizontalAdjustment->upper = resetValues ? 0 : frameRect().width(); m_horizontalAdjustment->value = resetValues ? 0 : scrollOffset().width(); gtk_adjustment_changed(m_horizontalAdjustment); gtk_adjustment_value_changed(m_horizontalAdjustment); m_verticalAdjustment->lower = 0; m_verticalAdjustment->upper = resetValues ? 0 : frameRect().height(); m_verticalAdjustment->value = resetValues ? 0 : scrollOffset().height(); gtk_adjustment_changed(m_verticalAdjustment); gtk_adjustment_value_changed(m_verticalAdjustment); } else { ScrollbarGtk* hScrollbar = reinterpret_cast<ScrollbarGtk*>(horizontalScrollbar()); if (hScrollbar) hScrollbar->detachAdjustment(); ScrollbarGtk* vScrollbar = reinterpret_cast<ScrollbarGtk*>(verticalScrollbar()); if (vScrollbar) vScrollbar->detachAdjustment(); } /* reconsider having a scrollbar */ setHasVerticalScrollbar(false); setHasHorizontalScrollbar(false); }
void Flickable::handleMousePress(QMouseEvent *event) { // qDebug() << "+ " << __PRETTY_FUNCTION__; event->ignore(); if (event->button() != Qt::LeftButton) return; if (d->ignoreList.removeAll(event)) return; switch (d->state) { case FlickablePrivate::Steady: case FlickablePrivate::Stop: event->accept(); d->state = FlickablePrivate::Pressed; d->pressPos = event->pos(); break; case FlickablePrivate::AutoScroll: event->accept(); d->state = FlickablePrivate::Stop; d->speed = QPoint(0, 0); d->pressPos = event->pos(); d->offset = scrollOffset(); d->ticker->stop(); break; default: break; } }
IntPoint ScrollView::convertSelfToChild(const Widget* child, const IntPoint& point) const { IntPoint newPoint = point; if (child != m_data->m_hBar && child != m_data->m_vBar) newPoint = point + scrollOffset(); return Widget::convertSelfToChild(child, newPoint); }
void FlickScroll::timerEvent(QTimerEvent *event) { int count = 0; QHashIterator<QWebView*, FlickData*> item(flickScroll_pm->flickData); while(item.hasNext()) { item.next(); //moves the pointer forward FlickData *data = item.value(); //if moving manually, adjust the speed based on //the difference of the new cursor position from the old one if(data->state == FlickData::ManualScroll) { count++; data->speed = QCursor::pos() - data->dragPos; data->dragPos = QCursor::pos(); } else if(data->state == FlickData::AutoScroll) { count++; data->speed = deaccelerate(data->speed); QPoint p = scrollOffset(data->widget); setScrollOffSet(data->widget, p - data->speed); scrollCustom(data->widget, data->speed.y()); //printf("autoscroll %d\n", data->speed.y()); if(data->speed == QPoint(0,0)) data->state = FlickData::Steady; } } if(!count) flickScroll_pm->ticker.stop(); QObject::timerEvent(event); }
void CacheSpaceScene::validateItemsCacheImpl() const { Q_ASSERT(m_itemsCacheInvalid); if (m_scene->count() == 0) { clearItemsCache(); m_itemsCacheInvalid = false; return; } auto_value<bool> inUse(m_cacheIsInUse, true); QRect cacheRect(scrollOffset(), window().size()); QPoint origin = originPos(); int count = m_scene->count(); auto it = m_items.begin(); QVector<SharedPtr<CacheItem>> newItems; for (int id(0); id < count; ++id) { if (!cacheRect.intersects(m_scene->itemRect(ID(id)))) continue; SharedPtr<CacheItem> newItem; while ((it != m_items.end()) && (index((*it)->id) <= id)) { if (index((*it)->id) == id) { (*it)->correctRectangles(m_scrollDelta); newItem = *it; break; } ++it; } if (newItem.isNull()) { newItem = createCacheItem(ID(id)); // correct rectangle newItem->rect.translate(origin); } newItems.append(newItem); } m_items.swap(newItems); // clear offset m_scrollDelta = QPoint(0, 0); m_sizeDelta = QSize(0, 0); // mark items as valid m_itemsCacheInvalid = false; }
AffineTransform SVGSVGElement::localCoordinateSpaceTransform( SVGElement::CTMScope mode) const { AffineTransform viewBoxTransform; if (!hasEmptyViewBox()) { FloatSize size = currentViewportSize(); viewBoxTransform = viewBoxToViewTransform(size.width(), size.height()); } AffineTransform transform; if (!isOutermostSVGSVGElement()) { SVGLengthContext lengthContext(this); transform.translate(m_x->currentValue()->value(lengthContext), m_y->currentValue()->value(lengthContext)); } else if (mode == SVGElement::ScreenScope) { if (LayoutObject* layoutObject = this->layoutObject()) { FloatPoint location; float zoomFactor = 1; // At the SVG/HTML boundary (aka LayoutSVGRoot), we apply the // localToBorderBoxTransform to map an element from SVG viewport // coordinates to CSS box coordinates. LayoutSVGRoot's localToAbsolute // method expects CSS box coordinates. We also need to adjust for the // zoom level factored into CSS coordinates (bug #96361). if (layoutObject->isSVGRoot()) { location = toLayoutSVGRoot(layoutObject) ->localToBorderBoxTransform() .mapPoint(location); zoomFactor = 1 / layoutObject->style()->effectiveZoom(); } // Translate in our CSS parent coordinate space // FIXME: This doesn't work correctly with CSS transforms. location = layoutObject->localToAbsolute(location, UseTransforms); location.scale(zoomFactor, zoomFactor); // Be careful here! localToBorderBoxTransform() included the x/y offset // coming from the viewBoxToViewTransform(), so we have to subtract it // here (original cause of bug #27183) transform.translate(location.x() - viewBoxTransform.e(), location.y() - viewBoxTransform.f()); // Respect scroll offset. if (FrameView* view = document().view()) { LayoutSize scrollOffset(view->getScrollOffset()); scrollOffset.scale(zoomFactor); transform.translate(-scrollOffset.width(), -scrollOffset.height()); } } } return transform.multiply(viewBoxTransform); }
void Flickable::tick() { if (d->state == FlickablePrivate:: AutoScroll) { d->speed = deaccelerate(d->speed); setScrollOffset(d->offset - d->speed); d->offset = scrollOffset(); if (d->speed == QPoint(0, 0)) { d->state = FlickablePrivate::Steady; d->ticker->stop(); } } else { d->ticker->stop(); } }
void RenderLayerScrollableArea::setScrollOffset(const IntPoint& newScrollOffset) { // Ensure that the dimensions will be computed if they need to be (for overflow:hidden blocks). if (m_scrollDimensionsDirty) computeScrollDimensions(); if (scrollOffset() == toIntSize(newScrollOffset)) return; setScrollOffset(toIntSize(newScrollOffset)); LocalFrame* frame = box().frame(); ASSERT(frame); RefPtr<FrameView> frameView = box().frameView(); TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"), "ScrollLayer", "data", InspectorScrollLayerEvent::data(&box())); const RenderLayerModelObject* paintInvalidationContainer = box().containerForPaintInvalidation(); // Update the positions of our child layers (if needed as only fixed layers should be impacted by a scroll). // We don't update compositing layers, because we need to do a deep update from the compositing ancestor. if (!frameView->isInPerformLayout()) { // If we're in the middle of layout, we'll just update layers once layout has finished. layer()->clipper().clearClipRectsIncludingDescendants(); box().setPreviousPaintInvalidationRect(box().boundsRectForPaintInvalidation(paintInvalidationContainer)); updateCompositingLayersAfterScroll(); } // The caret rect needs to be invalidated after scrolling frame->selection().setCaretRectNeedsUpdate(); FloatQuad quadForFakeMouseMoveEvent = FloatQuad(layer()->renderer()->previousPaintInvalidationRect()); quadForFakeMouseMoveEvent = paintInvalidationContainer->localToAbsoluteQuad(quadForFakeMouseMoveEvent); frame->eventHandler().dispatchFakeMouseMoveEventSoonInQuad(quadForFakeMouseMoveEvent); // For querying RenderLayer::compositingState() // This code appears correct, since scrolling outside of layout happens during activities that do not dirty compositing state. DisableCompositingQueryAsserts disabler; if (box().frameView()->isInPerformLayout()) box().setShouldDoFullPaintInvalidation(true); else box().invalidatePaintUsingContainer(paintInvalidationContainer, layer()->renderer()->previousPaintInvalidationRect(), InvalidationScroll); // Schedule the scroll DOM event. if (box().node()) box().node()->document().enqueueScrollEventForNode(box().node()); }
// Translate local snap coordinates into snap container's scrolling content // coordinate space. static Vector<FloatPoint> localToContainerSnapCoordinates( const LayoutBox& containerBox, const LayoutBox& snapArea) { Vector<FloatPoint> result; LayoutPoint scrollOffset(containerBox.scrollLeft(), containerBox.scrollTop()); const Vector<LengthPoint>& snapCoordinates = snapArea.style()->scrollSnapCoordinate(); for (auto& coordinate : snapCoordinates) { FloatPoint localPoint = floatPointForLengthPoint(coordinate, FloatSize(snapArea.size())); FloatPoint containerPoint = snapArea.localToAncestorPoint(localPoint, &containerBox); containerPoint.moveBy(scrollOffset); result.append(containerPoint); } return result; }
void ScrollView::setHorizontalAdjustment(GtkAdjustment* hadj, bool resetValues) { ASSERT(!parent() || !hadj); if (parent()) return; m_horizontalAdjustment = hadj; if (!m_horizontalAdjustment) { MainFrameScrollbarGtk* hScrollbar = reinterpret_cast<MainFrameScrollbarGtk*>(horizontalScrollbar()); if (hScrollbar) hScrollbar->detachAdjustment(); return; } // We may be lacking scrollbars when returning to a cached // page, this kicks the page to recreate the scrollbars. setHasHorizontalScrollbar(true); MainFrameScrollbarGtk* hScrollbar = reinterpret_cast<MainFrameScrollbarGtk*>(horizontalScrollbar()); hScrollbar->attachAdjustment(m_horizontalAdjustment.get()); // We used to reset everything to 0 here, but when page cache // is enabled we reuse FrameViews that are cached. Since their // size is not going to change when being restored, (which is // what would cause the upper limit in the adjusments to be // set in the normal case), we make sure they are up-to-date // here. This is needed for the parent scrolling widget to be // able to report correct values. int horizontalPageStep = max(max<int>(frameRect().width() * Scrollbar::minFractionToStepWhenPaging(), frameRect().width() - Scrollbar::maxOverlapBetweenPages()), 1); gtk_adjustment_configure(m_horizontalAdjustment.get(), resetValues ? 0 : scrollOffset().width(), 0, resetValues ? 0 : contentsSize().width(), resetValues ? 0 : Scrollbar::pixelsPerLineStep(), resetValues ? 0 : horizontalPageStep, resetValues ? 0 : frameRect().width()); }
void ScrollView::setScrollbarModes(ScrollbarMode horizontalMode, ScrollbarMode verticalMode, bool horizontalLock, bool verticalLock) { // FIXME: Restructure the ScrollView abstraction so that we do not have to // copy this verbatim from ScrollView.cpp. Until then, we should make sure this // is kept in sync. bool needsUpdate = false; if (horizontalMode != horizontalScrollbarMode() && !m_horizontalScrollbarLock) { m_horizontalScrollbarMode = horizontalMode; needsUpdate = true; } if (verticalMode != verticalScrollbarMode() && !m_verticalScrollbarLock) { m_verticalScrollbarMode = verticalMode; needsUpdate = true; } if (horizontalLock) setHorizontalScrollbarLock(); if (verticalLock) setVerticalScrollbarLock(); if (needsUpdate) updateScrollbars(scrollOffset()); // We don't need to report policy changes on ScrollView's unless this // one has an adjustment attached and it is a main frame. if (!m_horizontalAdjustment || parent() || !isFrameView()) return; // For frames that do have adjustments attached, we want to report // policy changes, so that they may be applied to the widget to // which the WebView's container (e.g. GtkScrolledWindow). if (hostWindow()) hostWindow()->scrollbarsModeDidChange(); }
void ScrollView::setScrollbarModes(ScrollbarMode horizontalMode, ScrollbarMode verticalMode, bool, bool) { if (horizontalMode == m_horizontalScrollbarMode && verticalMode == m_verticalScrollbarMode) return; m_horizontalScrollbarMode = horizontalMode; m_verticalScrollbarMode = verticalMode; // We don't really care about reporting policy changes on frames // that have no adjustments attached to them. if (!m_horizontalAdjustment) { updateScrollbars(scrollOffset()); return; } if (!isFrameView()) return; // For frames that do have adjustments attached, we want to report // policy changes, so that they may be applied to the widget to // which the WebView has been added, for instance. if (hostWindow()) hostWindow()->scrollbarsModeDidChange(); }
void BListView::KeyDown(const char* bytes, int32 numBytes) { bool extend = fListType == B_MULTIPLE_SELECTION_LIST && (modifiers() & B_SHIFT_KEY) != 0; switch (bytes[0]) { case B_UP_ARROW: { if (fFirstSelected == -1) { // if nothing is selected yet, always select the first item Select(0); } else { if (fAnchorIndex > 0) { if (!extend || fAnchorIndex <= fFirstSelected) Select(fAnchorIndex - 1, extend); else Deselect(fAnchorIndex--); } } ScrollToSelection(); break; } case B_DOWN_ARROW: { if (fFirstSelected == -1) { // if nothing is selected yet, always select the first item Select(0); } else { if (fAnchorIndex < CountItems() - 1) { if (!extend || fAnchorIndex >= fLastSelected) Select(fAnchorIndex + 1, extend); else Deselect(fAnchorIndex++); } } ScrollToSelection(); break; } case B_HOME: if (extend) { Select(0, fAnchorIndex, true); fAnchorIndex = 0; } else Select(0, false); ScrollToSelection(); break; case B_END: if (extend) { Select(fAnchorIndex, CountItems() - 1, true); fAnchorIndex = CountItems() - 1; } else Select(CountItems() - 1, false); ScrollToSelection(); break; case B_PAGE_UP: { BPoint scrollOffset(LeftTop()); scrollOffset.y = max_c(0, scrollOffset.y - Bounds().Height()); ScrollTo(scrollOffset); break; } case B_PAGE_DOWN: { BPoint scrollOffset(LeftTop()); if (BListItem* item = LastItem()) { scrollOffset.y += Bounds().Height(); scrollOffset.y = min_c(item->Bottom() - Bounds().Height(), scrollOffset.y); } ScrollTo(scrollOffset); break; } case B_RETURN: case B_SPACE: Invoke(); break; default: BView::KeyDown(bytes, numBytes); } }
bool FlickScroll::eventFilter(QObject *object, QEvent *event) { if(!object->isWidgetType()) return false; QEvent::Type type = event->type(); if(type != QEvent::MouseButtonPress && type != QEvent::MouseButtonRelease && type != QEvent::MouseMove) return false; //dynamic_cast ensures that event is only a derived event of type QMouseEvent QMouseEvent *mouseEvent = dynamic_cast<QMouseEvent *> (event); if(!mouseEvent || mouseEvent->modifiers() != Qt::NoModifier) return false; //check if QObject is a QWebView, get flickdata, //return if there are ignored events QWebView *webView = dynamic_cast<QWebView *>(object); FlickData * data = flickScroll_pm->flickData.value(webView); if(!webView || !data || data->ignored.removeAll(event)) return false; //go through the mouse event state machine bool consumed = false; // mouse events consumed switch(data->state) { //if mouse is pressed during steady state, goto pressed, cache the position // cache the offset. case FlickData::Steady: if (mouseEvent->type() == QEvent::MouseButtonPress && mouseEvent->buttons() == Qt::LeftButton) { printf("State = Steady, MouseButtonPress\n"); consumed = true; data->state = FlickData::Pressed; data->pressPos = mouseEvent->pos(); data->offset = scrollOffset(webView); data->extJS_offset = mouseEvent->pos().y(); } break; case FlickData::Pressed: //if the mouse is released during pressed state, goto steady state, //add button press and release to ignored events to restimulate button push/release if(mouseEvent->type() == QEvent::MouseButtonRelease) { printf("State = Pressed, MouseButtonRelease\n"); consumed = true; data->state = FlickData::Steady; fakeMouseEvent(mouseEvent, data, object); } //user is manually scrolling. //set the state, set the drag position. if ticker is not active, start it. else if(mouseEvent->type() == QEvent::MouseMove) { printf("State = Pressed, MouseMove\n"); consumed = true; data->state = FlickData::ManualScroll; data->dragPos = QCursor::pos(); //from cursor for accuracy if(!flickScroll_pm->ticker.isActive()) flickScroll_pm->ticker.start(20, this); } break; //if manually scrolling, update the delta // set the new scrolloffset, by adjusting the previous one with delta //if the mouse is released, let it auto scroll case FlickData::ManualScroll: if(mouseEvent->type() == QEvent::MouseMove) { printf("State = ManualScroll, MouseMove\n"); consumed = true; QPoint delta = mouseEvent->pos() - data->pressPos; setScrollOffSet(data->widget, data->offset - delta); scrollCustom(webView, mouseEvent->pos().y() - data->extJS_offset); data->extJS_offset = mouseEvent->pos().y(); } if(mouseEvent->type() == QEvent::MouseButtonRelease && !checkMouseSteadiness(mouseEvent->pos(), data->pressPos )) { printf("State = ManualScroll, MouseButtonRelease\n"); consumed = true; data->state = FlickData::AutoScroll; } else if(mouseEvent->type() == QEvent::MouseButtonRelease) { printf("State = ManualScroll, MouseButtonRelease, reverting to steady\n"); consumed = true; data->state = FlickData::Steady; fakeMouseEvent(mouseEvent, data, object); } break; case FlickData::AutoScroll: /* if the mouse is clicked while auto scrolling, we want to stop. reset all states. */ if(mouseEvent->type() == QEvent::MouseButtonPress) { printf("State = AutoScroll, MouseButtonPress\n"); consumed=true; data->state = FlickData::Stop; data->speed = QPoint(0,0); data->extJS_offset = 0; data->pressPos = mouseEvent->pos(); data->offset = scrollOffset(data->widget); } if(mouseEvent->type() == QEvent::MouseButtonRelease) { printf("State = AutoScroll, MouseButtonRelease\n"); consumed = true; data->state = FlickData::Steady; data->speed = QPoint(0,0); } break; case FlickData::Stop: if(mouseEvent->type() == QEvent::MouseButtonRelease) { printf("State = Stop, MouseButtonRelease\n"); consumed = true; data->state = FlickData::Steady; } if(mouseEvent->type() == QEvent::MouseMove) { printf("State = Stop, MouseMove\n"); consumed = true; data->state = FlickData::ManualScroll; data->dragPos = QCursor::pos(); if(!flickScroll_pm->ticker.isActive()) flickScroll_pm->ticker.start(20, this); } break; default: break; } return consumed; }
IntSize ScrollView::maximumScroll() const { IntSize delta = (IntSize(contentsWidth(), contentsHeight()) - IntSize(visibleWidth(), visibleHeight())) - scrollOffset(); delta.clampNegativeToZero(); return delta; }
IntPoint ScrollView::windowToContents(const IntPoint& windowPoint) const { IntPoint viewPoint = convertFromContainingWindow(windowPoint); return viewPoint + scrollOffset(); }
IntPoint ScrollView::windowToContents(const IntPoint& point) const { return point + scrollOffset(); }
IntPoint ScrollView::contentsToWindow(const IntPoint& point) const { return point - scrollOffset(); }
IntPoint ScrollView::contentsToWindow(const IntPoint& contentsPoint) const { IntPoint viewPoint = contentsPoint - scrollOffset(); return convertToContainingWindow(viewPoint); }
int ScrollView::contentsY() const { return scrollOffset().height(); }
void BListView::KeyDown(const char* bytes, int32 numBytes) { bool extend = fListType == B_MULTIPLE_SELECTION_LIST && (modifiers() & B_SHIFT_KEY) != 0; if (fFirstSelected == -1 && (bytes[0] == B_UP_ARROW || bytes[0] == B_DOWN_ARROW)) { // nothing is selected yet, select the first enabled item int32 lastItem = CountItems() - 1; for (int32 i = 0; i <= lastItem; i++) { if (ItemAt(i)->IsEnabled()) { Select(i); break; } } return; } switch (bytes[0]) { case B_UP_ARROW: { if (fAnchorIndex > 0) { if (!extend || fAnchorIndex <= fFirstSelected) { for (int32 i = 1; fAnchorIndex - i >= 0; i++) { if (ItemAt(fAnchorIndex - i)->IsEnabled()) { // Select the previous enabled item Select(fAnchorIndex - i, extend); break; } } } else { Deselect(fAnchorIndex); do fAnchorIndex--; while (fAnchorIndex > 0 && !ItemAt(fAnchorIndex)->IsEnabled()); } } ScrollToSelection(); break; } case B_DOWN_ARROW: { int32 lastItem = CountItems() - 1; if (fAnchorIndex < lastItem) { if (!extend || fAnchorIndex >= fLastSelected) { for (int32 i = 1; fAnchorIndex + i <= lastItem; i++) { if (ItemAt(fAnchorIndex + i)->IsEnabled()) { // Select the next enabled item Select(fAnchorIndex + i, extend); break; } } } else { Deselect(fAnchorIndex); do fAnchorIndex++; while (fAnchorIndex < lastItem && !ItemAt(fAnchorIndex)->IsEnabled()); } } ScrollToSelection(); break; } case B_HOME: if (extend) { Select(0, fAnchorIndex, true); fAnchorIndex = 0; } else { // select the first enabled item int32 lastItem = CountItems() - 1; for (int32 i = 0; i <= lastItem; i++) { if (ItemAt(i)->IsEnabled()) { Select(i, false); break; } } } ScrollToSelection(); break; case B_END: if (extend) { Select(fAnchorIndex, CountItems() - 1, true); fAnchorIndex = CountItems() - 1; } else { // select the last enabled item for (int32 i = CountItems() - 1; i >= 0; i--) { if (ItemAt(i)->IsEnabled()) { Select(i, false); break; } } } ScrollToSelection(); break; case B_PAGE_UP: { BPoint scrollOffset(LeftTop()); scrollOffset.y = std::max(0.0f, scrollOffset.y - Bounds().Height()); ScrollTo(scrollOffset); break; } case B_PAGE_DOWN: { BPoint scrollOffset(LeftTop()); if (BListItem* item = LastItem()) { scrollOffset.y += Bounds().Height(); scrollOffset.y = std::min(item->Bottom() - Bounds().Height(), scrollOffset.y); } ScrollTo(scrollOffset); break; } case B_RETURN: case B_SPACE: Invoke(); break; default: BView::KeyDown(bytes, numBytes); } }
LRESULT WebPopupMenuProxyWin::onKeyDown(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam, bool& handled) { handled = true; LRESULT lResult = 0; switch (LOWORD(wParam)) { case VK_DOWN: case VK_RIGHT: down(); break; case VK_UP: case VK_LEFT: up(); break; case VK_HOME: focusFirst(); break; case VK_END: focusLast(); break; case VK_PRIOR: if (focusedIndex() != scrollOffset()) { // Set the selection to the first visible item int firstVisibleItem = scrollOffset(); up(focusedIndex() - firstVisibleItem); } else { // The first visible item is selected, so move the selection back one page up(visibleItems()); } break; case VK_NEXT: { int lastVisibleItem = scrollOffset() + visibleItems() - 1; if (focusedIndex() != lastVisibleItem) { // Set the selection to the last visible item down(lastVisibleItem - focusedIndex()); } else { // The last visible item is selected, so move the selection forward one page down(visibleItems()); } break; } case VK_TAB: ::SendMessage(m_webView->window(), message, wParam, lParam); hide(); break; case VK_ESCAPE: hide(); break; default: if (isASCIIPrintable(wParam)) { // Send the keydown to the WebView so it can be used for type-to-select. // Since we know that the virtual key is ASCII printable, it's OK to convert this to // a WM_CHAR message. (We don't want to call TranslateMessage because that will post a // WM_CHAR message that will be stolen and redirected to the popup HWND. ::PostMessage(m_popup, WM_HOST_WINDOW_CHAR, wParam, lParam); } else lResult = 1; break; } return lResult; }
int ScrollView::contentsX() const { return scrollOffset().width(); }