NS_IMETHODIMP nsSliderFrame::HandlePress(nsPresContext* aPresContext, nsGUIEvent* aEvent, nsEventStatus* aEventStatus) { #ifdef XP_MACOSX // On Mac the option key inverts the scroll-to-here preference. if (((nsMouseEvent *)aEvent)->isAlt != GetScrollToClick()) #else if (((nsMouseEvent *)aEvent)->isShift != GetScrollToClick()) #endif return NS_OK; nsIFrame* thumbFrame = mFrames.FirstChild(); if (!thumbFrame) // display:none? return NS_OK; if (mContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::disabled, nsGkAtoms::_true, eCaseMatters)) return NS_OK; nsRect thumbRect = thumbFrame->GetRect(); nscoord change = 1; nsPoint eventPoint = nsLayoutUtils::GetEventCoordinatesRelativeTo(aEvent, this); if (IsHorizontal() ? eventPoint.x < thumbRect.x : eventPoint.y < thumbRect.y) change = -1; mChange = change; DragThumb(PR_TRUE); mDestinationPoint = eventPoint; StartRepeat(); PageUpDown(change); return NS_OK; }
nsresult nsSliderFrame::MouseDown(nsIDOMEvent* aMouseEvent) { #ifdef DEBUG_SLIDER printf("Begin dragging\n"); #endif if (mContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::disabled, nsGkAtoms::_true, eCaseMatters)) return NS_OK; nsCOMPtr<nsIDOMMouseEvent> mouseEvent(do_QueryInterface(aMouseEvent)); PRUint16 button = 0; mouseEvent->GetButton(&button); if (!(button == 0 || (button == 1 && gMiddlePref))) return NS_OK; PRBool isHorizontal = IsHorizontal(); PRBool scrollToClick = PR_FALSE; #ifndef XP_MACOSX // On Mac there's no scroll-to-here when clicking the thumb mouseEvent->GetShiftKey(&scrollToClick); if (button != 0) { scrollToClick = PR_TRUE; } #endif nsPoint pt = nsLayoutUtils::GetDOMEventCoordinatesRelativeTo(mouseEvent, this); nscoord pos = isHorizontal ? pt.x : pt.y; // If shift click or middle button, first // place the middle of the slider thumb under the click nsCOMPtr<nsIContent> scrollbar; nscoord newpos = pos; if (scrollToClick) { // adjust so that the middle of the thumb is placed under the click nsIFrame* thumbFrame = mFrames.FirstChild(); if (!thumbFrame) { return NS_OK; } nsSize thumbSize = thumbFrame->GetSize(); nscoord thumbLength = isHorizontal ? thumbSize.width : thumbSize.height; newpos -= (thumbLength/2); nsIBox* scrollbarBox = GetScrollbar(); scrollbar = GetContentOfBox(scrollbarBox); } DragThumb(PR_TRUE); if (scrollToClick) { // should aMaySnap be PR_TRUE here? SetCurrentThumbPosition(scrollbar, newpos, PR_FALSE, PR_FALSE, PR_FALSE); } nsIFrame* thumbFrame = mFrames.FirstChild(); if (!thumbFrame) { return NS_OK; } if (isHorizontal) mThumbStart = thumbFrame->GetPosition().x; else mThumbStart = thumbFrame->GetPosition().y; mDragStart = pos - mThumbStart; #ifdef DEBUG_SLIDER printf("Pressed mDragStart=%d\n",mDragStart); #endif return NS_OK; }
NS_IMETHODIMP nsSliderFrame::HandleEvent(nsPresContext* aPresContext, nsGUIEvent* aEvent, nsEventStatus* aEventStatus) { NS_ENSURE_ARG_POINTER(aEventStatus); if (nsEventStatus_eConsumeNoDefault == *aEventStatus) { return NS_OK; } nsIBox* scrollbarBox = GetScrollbar(); nsCOMPtr<nsIContent> scrollbar; scrollbar = GetContentOfBox(scrollbarBox); PRBool isHorizontal = IsHorizontal(); if (isDraggingThumb()) { switch (aEvent->message) { case NS_MOUSE_MOVE: { nsPoint eventPoint = nsLayoutUtils::GetEventCoordinatesRelativeTo(aEvent, this); if (mChange) { // We're in the process of moving the thumb to the mouse, // but the mouse just moved. Make sure to update our // destination point. mDestinationPoint = eventPoint; StopRepeat(); StartRepeat(); break; } nscoord pos = isHorizontal ? eventPoint.x : eventPoint.y; nsIFrame* thumbFrame = mFrames.FirstChild(); if (!thumbFrame) { return NS_OK; } // take our current position and subtract the start location pos -= mDragStart; PRBool isMouseOutsideThumb = PR_FALSE; if (gSnapMultiplier) { nsSize thumbSize = thumbFrame->GetSize(); if (isHorizontal) { // horizontal scrollbar - check if mouse is above or below thumb // XXXbz what about looking at the .y of the thumb's rect? Is that // always zero here? if (eventPoint.y < -gSnapMultiplier * thumbSize.height || eventPoint.y > thumbSize.height + gSnapMultiplier * thumbSize.height) isMouseOutsideThumb = PR_TRUE; } else { // vertical scrollbar - check if mouse is left or right of thumb if (eventPoint.x < -gSnapMultiplier * thumbSize.width || eventPoint.x > thumbSize.width + gSnapMultiplier * thumbSize.width) isMouseOutsideThumb = PR_TRUE; } } if (isMouseOutsideThumb) { SetCurrentThumbPosition(scrollbar, mThumbStart, PR_FALSE, PR_TRUE, PR_FALSE); return NS_OK; } // set it SetCurrentThumbPosition(scrollbar, pos, PR_FALSE, PR_TRUE, PR_TRUE); // with snapping } break; case NS_MOUSE_BUTTON_UP: if (static_cast<nsMouseEvent*>(aEvent)->button == nsMouseEvent::eLeftButton || (static_cast<nsMouseEvent*>(aEvent)->button == nsMouseEvent::eMiddleButton && gMiddlePref)) { // stop capturing AddListener(); DragThumb(PR_FALSE); if (mChange) { StopRepeat(); mChange = 0; } //we MUST call nsFrame HandleEvent for mouse ups to maintain the selection state and capture state. return nsFrame::HandleEvent(aPresContext, aEvent, aEventStatus); } } //return nsFrame::HandleEvent(aPresContext, aEvent, aEventStatus); return NS_OK; } else if ((aEvent->message == NS_MOUSE_BUTTON_DOWN && static_cast<nsMouseEvent*>(aEvent)->button == nsMouseEvent::eLeftButton && #ifdef XP_MACOSX // On Mac the option key inverts the scroll-to-here preference. (static_cast<nsMouseEvent*>(aEvent)->isAlt != GetScrollToClick())) || #else (static_cast<nsMouseEvent*>(aEvent)->isShift != GetScrollToClick())) || #endif (gMiddlePref && aEvent->message == NS_MOUSE_BUTTON_DOWN && static_cast<nsMouseEvent*>(aEvent)->button == nsMouseEvent::eMiddleButton)) { nsPoint eventPoint = nsLayoutUtils::GetEventCoordinatesRelativeTo(aEvent, this); nscoord pos = isHorizontal ? eventPoint.x : eventPoint.y; // adjust so that the middle of the thumb is placed under the click nsIFrame* thumbFrame = mFrames.FirstChild(); if (!thumbFrame) { return NS_OK; } nsSize thumbSize = thumbFrame->GetSize(); nscoord thumbLength = isHorizontal ? thumbSize.width : thumbSize.height; // set it nsWeakFrame weakFrame(this); // should aMaySnap be PR_TRUE here? SetCurrentThumbPosition(scrollbar, pos - thumbLength/2, PR_FALSE, PR_FALSE, PR_FALSE); NS_ENSURE_TRUE(weakFrame.IsAlive(), NS_OK); DragThumb(PR_TRUE); if (isHorizontal) mThumbStart = thumbFrame->GetPosition().x; else mThumbStart = thumbFrame->GetPosition().y; mDragStart = pos - mThumbStart; } // XXX hack until handle release is actually called in nsframe. // if (aEvent->message == NS_MOUSE_EXIT_SYNTH || aEvent->message == NS_MOUSE_RIGHT_BUTTON_UP || aEvent->message == NS_MOUSE_LEFT_BUTTON_UP) // HandleRelease(aPresContext, aEvent, aEventStatus); if (aEvent->message == NS_MOUSE_EXIT_SYNTH && mChange) HandleRelease(aPresContext, aEvent, aEventStatus); return nsFrame::HandleEvent(aPresContext, aEvent, aEventStatus); }
/// @brief Updates the slider when it is the widget of choice /// @param fCursorX Cursor x coordinate, in [0,1] /// @param fCursorY Cursor y coordinate, in [0,1] /// @param bPressed If true, the cursor is pressed /// @param pContext [in-out] User-defined context parameter /// @return A boolean indicating whether the slider is no longer the widget of choice /// @note Tested bool Slider::Update (float fCursorX, float fCursorY, bool bPressed, void * pContext) { ///////////////////////////////////////////////////////////////////////////////// // If the cursor is over the slider, we check three conditions: First, we check // whether the cursor has just entered the slider; if so, we enter the slider. // Second, we check whether the cursor just entered the thumb; if so, we enter // the thumb. Third, we check whether the slider and its thumb are not yet held, // and if there was a press. ///////////////////////////////////////////////////////////////////////////////// if (mStatus[eUnder]) { if (!mStatus[eIn]) Enter(pContext); if (!mStatus[eThumbIn] && mStatus[eThumbUnder]) EnterThumb(pContext); if (bPressed && !(mStatus[eHeld] || mStatus[eThumbHeld])) { /////////////////////////////////////////////////////////////////////// // If the cursor is over the thumb, we grab the thumb; if the thumb is // draggable, we also catch the thumb. /////////////////////////////////////////////////////////////////////// if (mStatus[eThumbUnder]) { GrabThumb(pContext); if (!mStatus[eThumbCannotDrag]) CatchThumb(fCursorX, fCursorY, pContext); } //////////////////////////////////////////////////////////////////////////////// // Otherwise, we grab the slider. If the slider is snappable, we fit the cursor // coordinates to an offset. If the offset varies from the current offset, we // snap the thumb to it. //////////////////////////////////////////////////////////////////////////////// else { Grab(pContext); if (!mStatus[eThumbCannotSnap]) { float fOffset = GetOffset(fCursorX, fCursorY, pContext); if (mOffset - fOffset != 0.0f) SnapThumb(fOffset, pContext); } } } } ///////////////////////////////////////////////////////////////////////////////////// // If the cursor is not over the thumb, but was during the last propagation, then we // leave the thumb. Likewise, we leave the slider if its confinement changes. //////////////////////////////////////////////////////////////////////////////////// if (!mStatus[eThumbUnder] && mStatus[eThumbIn]) LeaveThumb(pContext); if (!mStatus[eUnder] && mStatus[eIn]) Leave(pContext); //////////////////////////////////////////////////////////////////////////////////// // If there is no press, we check whether the thumb or slider is held. In the first // case, we release the thumb if it is caught, and drop the thumb; in the second, // we drop the slider. //////////////////////////////////////////////////////////////////////////////////// if (!bPressed) { assert(!(mStatus[eHeld] && mStatus[eThumbHeld])); if (mStatus[eThumbHeld]) { if (mStatus[eThumbCaught]) ReleaseThumb(pContext); DropThumb(pContext); } else if (mStatus[eHeld]) Drop(pContext); } ////////////////////////////////////////////////////////////////////////////////////// // If the thumb is caught, we check for movement. If there is any, we drag the thumb. ////////////////////////////////////////////////////////////////////////////////////// if (mStatus[eThumbCaught]) { float fOffset = GetOffset(fCursorX, fCursorY, pContext); if (mOffset - fOffset != 0.0f) DragThumb(fOffset, pContext); } ////////////////////////////////////////////////////////////////////////////////////// // Finally, if the cursor is not over the slider and neither the slider nor the thumb // is held, the slider is no longer the widget of choice. ////////////////////////////////////////////////////////////////////////////////////// return !mStatus[eUnder] && !(mStatus[eHeld] || mStatus[eThumbHeld]); }