FReply FSequencerEditTool_Movement::OnMouseMove(SWidget& OwnerWidget, const FGeometry& MyGeometry, const FPointerEvent& MouseEvent)
{
	if (DelayedDrag.IsSet())
	{
		const FVirtualTrackArea VirtualTrackArea = SequencerWidget.Pin()->GetVirtualTrackArea();

		FReply Reply = FReply::Handled();

		if (DelayedDrag->IsDragging())
		{
			// If we're already dragging, just update the drag op if it exists
			if (DragOperation.IsValid())
			{
				DragOperation->OnDrag(MouseEvent, MyGeometry.AbsoluteToLocal(MouseEvent.GetScreenSpacePosition()), VirtualTrackArea);
			}
		}
		// Otherwise we can attempt a new drag
		else if (DelayedDrag->AttemptDragStart(MouseEvent))
		{
			DragOperation = CreateDrag();

			if (DragOperation.IsValid())
			{
				DragOperation->OnBeginDrag(MouseEvent, DelayedDrag->GetInitialPosition(), VirtualTrackArea);

				// Steal the capture, as we're now the authoritative widget in charge of a mouse-drag operation
				Reply.CaptureMouse(OwnerWidget.AsShared());
			}
		}

		return Reply;
	}
	return FReply::Unhandled();
}
FReply FSequencerTimeSliderController::OnMouseButtonDown( SWidget& WidgetOwner, const FGeometry& MyGeometry, const FPointerEvent& MouseEvent )
{
	bool bHandleLeftMouseButton = MouseEvent.GetEffectingButton() == EKeys::LeftMouseButton;
	bool bHandleRightMouseButton = MouseEvent.GetEffectingButton() == EKeys::RightMouseButton && TimeSliderArgs.AllowZoom;
	
	DistanceDragged = 0;

	FScrubRangeToScreen RangeToScreen( TimeSliderArgs.ViewRange.Get(), MyGeometry.Size );
	MouseDownRange[0] = RangeToScreen.LocalXToInput(MyGeometry.AbsoluteToLocal(MouseEvent.GetLastScreenSpacePosition()).X);
	MouseDownRange[1] = MouseDownRange[0];

	if ( bHandleLeftMouseButton )
	{
		return FReply::Handled().CaptureMouse( WidgetOwner.AsShared() ).PreventThrottling();
	}
	else if ( bHandleRightMouseButton )
	{
		// Always capture mouse if we left or right click on the widget
		return FReply::Handled().CaptureMouse( WidgetOwner.AsShared() );
	}

	return FReply::Unhandled();
}
FReply FVisualLoggerTimeSliderController::OnMouseButtonDown( SWidget& WidgetOwner, const FGeometry& MyGeometry, const FPointerEvent& MouseEvent )
{
	bool bHandleLeftMouseButton = MouseEvent.GetEffectingButton() == EKeys::LeftMouseButton;
	bool bHandleRightMouseButton = MouseEvent.GetEffectingButton() == EKeys::RightMouseButton && TimeSliderArgs.AllowZoom;
	
	DistanceDragged = 0;

	if ( bHandleLeftMouseButton )
	{
		// Always capture mouse if we left or right click on the widget
		FScrubRangeToScreen RangeToScreen(TimeSliderArgs.ViewRange.Get(), MyGeometry.Size);
		FVector2D CursorPos = MyGeometry.AbsoluteToLocal(MouseEvent.GetLastScreenSpacePosition());
		float NewValue = RangeToScreen.LocalXToInput(CursorPos.X);

		CommitScrubPosition(NewValue, /*bIsScrubbing=*/false);
		return FReply::Handled().CaptureMouse( WidgetOwner.AsShared() ).PreventThrottling();
	}
	else if ( bHandleRightMouseButton )
	{
		return FReply::Handled().CaptureMouse(WidgetOwner.AsShared());
	}

	return FReply::Unhandled();
}
FReply FVisualLoggerTimeSliderController::OnMouseButtonUp( SWidget& WidgetOwner, const FGeometry& MyGeometry, const FPointerEvent& MouseEvent )
{
	bool bHandleLeftMouseButton = MouseEvent.GetEffectingButton() == EKeys::LeftMouseButton && WidgetOwner.HasMouseCapture();
	bool bHandleRightMouseButton = MouseEvent.GetEffectingButton() == EKeys::RightMouseButton && WidgetOwner.HasMouseCapture() && TimeSliderArgs.AllowZoom ;
	
	if ( bHandleRightMouseButton )
	{
		if (!bPanning)
		{
			// return unhandled in case our parent wants to use our right mouse button to open a context menu
			return FReply::Unhandled().ReleaseMouseCapture();
		}
		
		bPanning = false;
		FReply::Handled().CaptureMouse(WidgetOwner.AsShared()).UseHighPrecisionMouseMovement(WidgetOwner.AsShared());

		return FReply::Handled().ReleaseMouseCapture();
	}
	else if ( bHandleLeftMouseButton )
	{
		if( bDraggingScrubber )
		{
			TimeSliderArgs.OnEndScrubberMovement.ExecuteIfBound();
		}
		else
		{
			FScrubRangeToScreen RangeToScreen( TimeSliderArgs.ViewRange.Get(), MyGeometry.Size );
			FVector2D CursorPos = MyGeometry.AbsoluteToLocal(MouseEvent.GetLastScreenSpacePosition());
			float NewValue = RangeToScreen.LocalXToInput(CursorPos.X);

			CommitScrubPosition( NewValue, /*bIsScrubbing=*/false );
		}

		bDraggingScrubber = false;
		return FReply::Handled().ReleaseMouseCapture();

	}

	return FReply::Unhandled();
}
Ejemplo n.º 5
0
/*
   Layout Language

   \return Layout pointer or zero if error generated.
*/
QLayout* ur_qtLayout( UThread* ut, LayoutInfo& parent, const UCell* blkC )
{
    CBParser cbp;
    UBlockIter bi;
    LayoutInfo lo;
    const UCell* val;
    const UCell* setWord = 0;
    QWidget* wid = 0;
    int match;


    ur_blkSlice( ut, &bi, blkC );

    cbp_beginParse( ut, &cbp, bi.it, bi.end, qEnv.layoutRules );
    while( (match = cbp_matchRule( &cbp )) > -1 )
    {
        switch( match )
        {
            case LD_HBOX:
            case LD_VBOX:
            {
                wid = 0;

                lo.grid = 0;
                lo.box  = new QBoxLayout( (match == LD_HBOX) ? 
                                          QBoxLayout::LeftToRight :
                                          QBoxLayout::TopToBottom );
                if( parent.layout() )
                    parent.addLayout( lo.box );

                val = cbp.values + 1;
                //TODO: Handle error.
                ur_qtLayout( ut, lo, val );
            }
                break;

            case LD_LABEL:
            {
                QString txt;
                if( ! getString( ut, cbp.values + 1, txt ) )
                    return 0;

                MAKE_WIDGET( SLabel )
                pw->setText( txt );
            }
                break;

            case LD_BUTTON:
            {
                MAKE_WIDGET( SButton )
                pw->setText( qstring( cbp.values + 1 ) );
                pw->setBlock( cbp.values + 2 );
            }
                break;

            case LD_CHECKBOX:
            {
                MAKE_WIDGET( SCheck )
                pw->setText( qstring( cbp.values + 1 ) );
            }
                break;

            case LD_SPIN_BOX:
            {
                MAKE_WIDGET( SSpinBox )
                pw->setRange( ur_int( cbp.values + 1 ),
                              ur_int( cbp.values + 2 ) );
            }
                break;

            case LD_COMBO:
            {
                MAKE_WIDGET( SCombo )

                val = cbp.values + 1;
                if( ur_is(val, UT_GETWORD) )
                {
                    if( ! (val = ur_wordCell( ut, val )) )
                        return 0;
                }

                if( ur_is(val, UT_BLOCK) )
                {
                    UBlockIter bi2;
                    ur_blkSlice( ut, &bi2, val ); 
                    ur_foreach( bi2 )
                    {
                        if( ur_is(bi2.it, UT_STRING) )
                            pw->addItem( qstring( bi2.it ) );
                    }
                }
                else
                {
                    pw->addItem( qstring( val ) );
                }
            }
                break;

            case LD_SPACER:
                if( ! parent.box )
                    goto no_layout;

                parent.box->addStretch( 1 );
                break;

            case LD_SPACE:
                if( ! parent.box )
                    goto no_layout;

                val = cbp.values + 1;
                parent.box->addSpacing( ur_int(val) );
                break;

            case LD_TAB:
            {
                MAKE_WIDGET( STabWidget )

                if( ! tabWidgetBlock( ut, pw, cbp.values + 1 ) )
                    return 0;
            }
                break;

            case LD_TIP:
                if( wid )
                    wid->setToolTip( qstring(cbp.values + 1) );
                break;

            case LD_TITLE:
                if( qEnv.curWidget )
                {
                    QString str;
                    if( ! getString( ut, cbp.values + 1, str ) )
                        return 0;
                    qEnv.curWidget->setWindowTitle( str );
                }
                break;

            case LD_RESIZE:
                if( qEnv.curWidget )
                {
                    val = cbp.values + 1;
                    qEnv.curWidget->resize( val->coord.n[0], val->coord.n[1] );
                }
                break;

            case LD_LINE_EDIT_STR:
            case LD_LINE_EDIT:
            {
                MAKE_WIDGET( SLineEdit )

                if( match == LD_LINE_EDIT_STR )
                    pw->setText( qstring( cbp.values + 1 ) );
            }
                break;

            case LD_LIST:
            {
                const UCell* hdr = cbp.values + 1;
                if( ur_is(hdr, UT_GETWORD) )
                {
                    if( ! (hdr = ur_wordCell( ut, hdr )) )
                        return 0;
                }

                val = cbp.values + 2;
                if( ur_is(val, UT_GETWORD) )
                {
                    if( ! (val = ur_wordCell( ut, val )) )
                        return 0;
                }

                MAKE_WIDGET( STreeView )
                pw->setRootIsDecorated( false );
                pw->setModel( new UTreeModel( pw, hdr, val ) );
            }
                break;

            case LD_TEXT_EDIT_STR:
            case LD_TEXT_EDIT:
            {
                MAKE_WIDGET( STextEdit )

                if( match == LD_TEXT_EDIT_STR )
                {
                    QString str;
                    if( ! getString( ut, cbp.values + 1, str ) )
                        return 0;
                    if( str[0] == '<' )
                        pw->setHtml( str );
                    else
                        pw->setPlainText( str );
                }
            }
                break;

            case LD_GROUP:
            case LD_GROUP_CHECKABLE:
            {
                MAKE_WIDGET( SGroup )

                val = cbp.values + 1;
                if( match == LD_GROUP_CHECKABLE )
                {
                    const UCell* enabled;
                    if( ! (enabled = ur_wordCell( ut, val )) )
                        return 0;

                    pw->setCheckable( true );
                    pw->setChecked( ur_isTrue( enabled ) );
                    ++val;
                }

                pw->setTitle( qstring( val ) );
                ++val;

                LayoutInfo lo2;
                QLayout* lr2 = ur_qtLayout(ut, lo2, val);
                if( ! lr2 )
                    return 0;
                pw->setLayout( lr2 );
            }
                break;

            case LD_READ_ONLY:
                if( wid )
                {
                    QTextEdit* tedit = qobject_cast<QTextEdit*>( wid );
                    if( tedit )
                        tedit->setReadOnly( true );
                }
                break;

            case LD_ON_EVENT:
                if( qEnv.curWidget )
                {
                    SWidget* sw = qobject_cast<SWidget*>( qEnv.curWidget );
                    if( sw )
                        sw->setEventBlock( cbp.values + 1 );
                }
                break;

            case LD_STRING:
                if( wid )
                {
                    SCombo* combo = qobject_cast<SCombo*>( wid );
                    if( combo )
                    {
                        combo->addItem( qstring( cbp.values ) );
                        break;
                    }

                    QTextEdit* texted = qobject_cast<QTextEdit*>( wid );
                    if( texted )
                    {
                        QString str;
                        cellToQString( cbp.values, str );
                        if( str[0] == '<' )
                            texted->setHtml( str );
                        else
                            texted->setPlainText( str );
                    }
                }
                break;

            case LD_BLOCK:
                if( wid )
                {
                    SCombo* combo = qobject_cast<SCombo*>( wid );
                    if( combo )
                    {
                        combo->setBlock( cbp.values );
                        break;
                    }
                    STreeView* tree = qobject_cast<STreeView*>( wid );
                    if( tree )
                    {
                        tree->setBlock( cbp.values );
                        break;
                    }
                }
                break;

            case LD_SET_WORD:
                setWord = cbp.values;
                break;

            case LD_GRID:
                val = cbp.values + 1;

                wid = 0;

                lo.box     = 0;
                lo.grid    = new QGridLayout;
                lo.columns = ur_int(val);
                lo.colN    = 0;
                lo.rowN    = 0;

                if( parent.layout() )
                    parent.addLayout( lo.grid );

                ++val;
                //TODO: Handle error.
                ur_qtLayout( ut, lo, val );
                break;

            case LD_PROGRESS:
            {
                MAKE_WIDGET( SProgress )
                pw->setRange( 0, ur_int(cbp.values+1) );
            }
                break;

            case LD_WEIGHT:
                if( parent.box && wid )
                {
                    parent.box->setStretchFactor(wid, ur_int(cbp.values+1));
                }
                break;
        }
    }
FReply FSequencerTimeSliderController::OnMouseMove( SWidget& WidgetOwner, const FGeometry& MyGeometry, const FPointerEvent& MouseEvent )
{
	if ( WidgetOwner.HasMouseCapture() )
	{
		if (MouseEvent.IsMouseButtonDown( EKeys::RightMouseButton ))
		{
			if (!bPanning)
			{
				DistanceDragged += FMath::Abs( MouseEvent.GetCursorDelta().X );
				if ( DistanceDragged > FSlateApplication::Get().GetDragTriggerDistance() )
				{
					bPanning = true;
				}
			}
			else
			{
				TRange<float> LocalViewRange = TimeSliderArgs.ViewRange.Get();
				float LocalViewRangeMin = LocalViewRange.GetLowerBoundValue();
				float LocalViewRangeMax = LocalViewRange.GetUpperBoundValue();

				FScrubRangeToScreen ScaleInfo( LocalViewRange, MyGeometry.Size );
				FVector2D ScreenDelta = MouseEvent.GetCursorDelta();
				FVector2D InputDelta;
				InputDelta.X = ScreenDelta.X/ScaleInfo.PixelsPerInput;

				float NewViewOutputMin = LocalViewRangeMin - InputDelta.X;
				float NewViewOutputMax = LocalViewRangeMax - InputDelta.X;

				ClampViewRange(NewViewOutputMin, NewViewOutputMax);
				SetViewRange(NewViewOutputMin, NewViewOutputMax, EViewRangeInterpolation::Immediate);
			}
		}
		else if (MouseEvent.IsMouseButtonDown( EKeys::LeftMouseButton ))
		{
			TRange<float> LocalViewRange = TimeSliderArgs.ViewRange.Get();
			DistanceDragged += FMath::Abs( MouseEvent.GetCursorDelta().X );

			if ( MouseDragType == DRAG_NONE )
			{
				if ( DistanceDragged > FSlateApplication::Get().GetDragTriggerDistance() )
				{
					FScrubRangeToScreen RangeToScreen(LocalViewRange, MyGeometry.Size);
					const float ScrubPosition = TimeSliderArgs.ScrubPosition.Get();

					TRange<float> PlaybackRange = TimeSliderArgs.PlaybackRange.Get();
					float LocalMouseDownPos = RangeToScreen.InputToLocalX(MouseDownRange[0]);

					// Favor dragging the end position
					if (HitTestPlaybackEnd(RangeToScreen, PlaybackRange, LocalMouseDownPos, ScrubPosition))
					{
						MouseDragType = DRAG_END_RANGE;
						TimeSliderArgs.OnBeginPlaybackRangeDrag.ExecuteIfBound();
					}
					else if (HitTestPlaybackStart(RangeToScreen, PlaybackRange, LocalMouseDownPos, ScrubPosition))
					{
						MouseDragType = DRAG_START_RANGE;
						TimeSliderArgs.OnBeginPlaybackRangeDrag.ExecuteIfBound();
					}
					else if (FSlateApplication::Get().GetModifierKeys().AreModifersDown(EModifierKey::Control))
					{
						MouseDragType = DRAG_SETTING_RANGE;
					}
					else
					{
						MouseDragType = DRAG_SCRUBBING_TIME;
						TimeSliderArgs.OnBeginScrubberMovement.ExecuteIfBound();
					}
				}
			}
			else
			{
				FScrubRangeToScreen RangeToScreen( TimeSliderArgs.ViewRange.Get(), MyGeometry.Size );
				FVector2D CursorPos = MyGeometry.AbsoluteToLocal( MouseEvent.GetLastScreenSpacePosition() );
				float NewValue = RangeToScreen.LocalXToInput( CursorPos.X );


				// Set the start range time?
				if (MouseDragType == DRAG_START_RANGE)
				{
					if (TimeSliderArgs.Settings->GetIsSnapEnabled())
					{
						NewValue = TimeSliderArgs.Settings->SnapTimeToInterval(NewValue);
					}

					SetPlaybackRangeStart(NewValue);
				}
				// Set the end range time?
				else if(MouseDragType == DRAG_END_RANGE)
				{
					if (TimeSliderArgs.Settings->GetIsSnapEnabled())
					{
						NewValue = TimeSliderArgs.Settings->SnapTimeToInterval(NewValue);
					}
					
					SetPlaybackRangeEnd(NewValue);
				}
				else if (MouseDragType == DRAG_SCRUBBING_TIME)
				{
					if ( TimeSliderArgs.Settings->GetIsSnapEnabled() && TimeSliderArgs.Settings->GetSnapPlayTimeToInterval() )
					{
						NewValue = TimeSliderArgs.Settings->SnapTimeToInterval(NewValue);
					}
					
					// Delegate responsibility for clamping to the current viewrange to the client
					CommitScrubPosition( NewValue, /*bIsScrubbing=*/true );
				}
				else if (MouseDragType == DRAG_SETTING_RANGE)
				{
					MouseDownRange[1] = NewValue;
				}
			}
		}
		return FReply::Handled();
	}

	return FReply::Unhandled();
}
FReply FSequencerTimeSliderController::OnMouseButtonUp( SWidget& WidgetOwner, const FGeometry& MyGeometry, const FPointerEvent& MouseEvent )
{
	bool bHandleLeftMouseButton = MouseEvent.GetEffectingButton() == EKeys::LeftMouseButton && WidgetOwner.HasMouseCapture();
	bool bHandleRightMouseButton = MouseEvent.GetEffectingButton() == EKeys::RightMouseButton && WidgetOwner.HasMouseCapture() && TimeSliderArgs.AllowZoom ;

	if ( bHandleRightMouseButton )
	{
		if (!bPanning)
		{
			// Open a context menu if allowed
			if (ContextMenuSupression == 0 && TimeSliderArgs.PlaybackRange.IsSet())
			{
				FScrubRangeToScreen RangeToScreen( TimeSliderArgs.ViewRange.Get(), MyGeometry.Size );
				FVector2D CursorPos = MyGeometry.AbsoluteToLocal( MouseEvent.GetScreenSpacePosition() );

				float MouseValue = RangeToScreen.LocalXToInput( CursorPos.X );
				if (TimeSliderArgs.Settings->GetIsSnapEnabled())
				{
					MouseValue = TimeSliderArgs.Settings->SnapTimeToInterval(MouseValue);
				}

				TSharedRef<SWidget> MenuContent = OpenSetPlaybackRangeMenu(MouseValue);
				FSlateApplication::Get().PushMenu(
					WidgetOwner.AsShared(),
					MouseEvent.GetEventPath() != nullptr ? *MouseEvent.GetEventPath() : FWidgetPath(),
					MenuContent,
					MouseEvent.GetScreenSpacePosition(),
					FPopupTransitionEffect( FPopupTransitionEffect::ContextMenu )
					);

				return FReply::Handled().SetUserFocus(MenuContent, EFocusCause::SetDirectly).ReleaseMouseCapture();
			}

			// return unhandled in case our parent wants to use our right mouse button to open a context menu
			return FReply::Unhandled().ReleaseMouseCapture();
		}
		
		bPanning = false;
		
		return FReply::Handled().ReleaseMouseCapture();
	}
	else if ( bHandleLeftMouseButton )
	{
		if (MouseDragType == DRAG_START_RANGE)
		{
			TimeSliderArgs.OnEndPlaybackRangeDrag.ExecuteIfBound();
		}
		// Set the end range time?
		else if (MouseDragType == DRAG_END_RANGE)
		{
			TimeSliderArgs.OnEndPlaybackRangeDrag.ExecuteIfBound();
		}
		else if (MouseDragType == DRAG_SETTING_RANGE)
		{
			FScrubRangeToScreen RangeToScreen( TimeSliderArgs.ViewRange.Get(), MyGeometry.Size );
			FVector2D CursorPos = MyGeometry.AbsoluteToLocal(MouseEvent.GetLastScreenSpacePosition());
			float NewValue = RangeToScreen.LocalXToInput(CursorPos.X);

			if ( TimeSliderArgs.Settings->GetIsSnapEnabled() )
			{
				NewValue = TimeSliderArgs.Settings->SnapTimeToInterval(NewValue);
			}

			float DownValue = MouseDownRange[0];
				
			if ( TimeSliderArgs.Settings->GetIsSnapEnabled() )
			{
				DownValue = TimeSliderArgs.Settings->SnapTimeToInterval(DownValue);
			}

			// Zoom in
			if (NewValue > DownValue)
			{
				// push the current value onto the stack
				RangeStack.Add(FVector2D(TimeSliderArgs.ViewRange.Get().GetLowerBoundValue(), TimeSliderArgs.ViewRange.Get().GetUpperBoundValue()));
			}
			// Zoom out
			else if (RangeStack.Num())
			{
				// pop the stack
				FVector2D LastRange = RangeStack.Pop();
				DownValue = LastRange[0];
				NewValue = LastRange[1];
			}

			TimeSliderArgs.OnViewRangeChanged.ExecuteIfBound(TRange<float>(DownValue, NewValue), EViewRangeInterpolation::Immediate);
					
			if( !TimeSliderArgs.ViewRange.IsBound() )
			{	
				// The output is not bound to a delegate so we'll manage the value ourselves
				TimeSliderArgs.ViewRange.Set( TRange<float>( DownValue, NewValue ) );
			}
		}
		else
		{
			TimeSliderArgs.OnEndScrubberMovement.ExecuteIfBound();

			FScrubRangeToScreen RangeToScreen( TimeSliderArgs.ViewRange.Get(), MyGeometry.Size );
			FVector2D CursorPos = MyGeometry.AbsoluteToLocal(MouseEvent.GetLastScreenSpacePosition());
			float NewValue = RangeToScreen.LocalXToInput(CursorPos.X);

			if ( TimeSliderArgs.Settings->GetIsSnapEnabled() && TimeSliderArgs.Settings->GetSnapPlayTimeToInterval() )
			{
				NewValue = TimeSliderArgs.Settings->SnapTimeToInterval(NewValue);
			}
			
			CommitScrubPosition( NewValue, /*bIsScrubbing=*/false );
		}

		MouseDragType = DRAG_NONE;
		return FReply::Handled().ReleaseMouseCapture();

	}

	return FReply::Unhandled();
}
Ejemplo n.º 8
0
int32 SWidget::Paint(const FPaintArgs& Args, const FGeometry& AllottedGeometry, const FSlateRect& MyClippingRect, FSlateWindowElementList& OutDrawElements, int32 LayerId, const FWidgetStyle& InWidgetStyle, bool bParentEnabled) const
{
	INC_DWORD_STAT(STAT_SlateNumPaintedWidgets);
	SLATE_CYCLE_COUNTER_SCOPE_CUSTOM_DETAILED(SLATE_STATS_DETAIL_LEVEL_MED, GSlateOnPaint, GetType());

	// Save the current layout cache we're associated with (if any)
	LayoutCache = Args.GetLayoutCache();

	// Record if we're part of a volatility pass, this is critical for ensuring we don't report a child
	// of a volatile widget as non-volatile, causing the invalidation panel to do work that's not required.
	bInheritedVolatility = Args.IsVolatilityPass();

	// If this paint pass is to cache off our geometry, but we're a volatile widget,
	// record this widget as volatile in the draw elements so that we get our own tick/paint 
	// pass later when the layout cache draws.
	if ( Args.IsCaching() && IsVolatile() )
	{
		const int32 VolatileLayerId = LayerId + 1;
		OutDrawElements.QueueVolatilePainting(
			FSlateWindowElementList::FVolatilePaint(SharedThis(this), Args, AllottedGeometry, MyClippingRect, VolatileLayerId, InWidgetStyle, bParentEnabled));

		return VolatileLayerId;
	}

	if ( bFoldTick && bCanTick )
	{
		FGeometry TickGeometry = AllottedGeometry;
		TickGeometry.AppendTransform( FSlateLayoutTransform(Args.GetWindowToDesktopTransform()) );

		SWidget* MutableThis = const_cast<SWidget*>(this);
		MutableThis->ExecuteActiveTimers( Args.GetCurrentTime(), Args.GetDeltaTime() );
		MutableThis->Tick( TickGeometry, Args.GetCurrentTime(), Args.GetDeltaTime() );
	}

	// Record hit test geometry, but only if we're not caching.
	const FPaintArgs UpdatedArgs = Args.RecordHittestGeometry(this, AllottedGeometry, MyClippingRect);

	// Paint the geometry of this widget.
	int32 NewLayerID = OnPaint(UpdatedArgs, AllottedGeometry, MyClippingRect, OutDrawElements, LayerId, InWidgetStyle, bParentEnabled);

	// Check if we need to show the keyboard focus ring, this is only necessary if the widget could be focused.
	if ( bCanSupportFocus && SupportsKeyboardFocus() )
	{
		bool bShowUserFocus = FSlateApplicationBase::Get().ShowUserFocus(SharedThis(this));
		if (bShowUserFocus)
		{
			const FSlateBrush* BrushResource = GetFocusBrush();

			if (BrushResource != nullptr)
			{
				FSlateDrawElement::MakeBox(
					OutDrawElements,
					NewLayerID,
					AllottedGeometry.ToPaintGeometry(),
					BrushResource,
					MyClippingRect,
					ESlateDrawEffect::None,
					BrushResource->GetTint(InWidgetStyle)
					);
			}
		}
	}

	return NewLayerID;
}
FReply FVisualLoggerTimeSliderController::OnMouseMove( SWidget& WidgetOwner, const FGeometry& MyGeometry, const FPointerEvent& MouseEvent )
{
	if ( WidgetOwner.HasMouseCapture() )
	{
		if (MouseEvent.IsMouseButtonDown(EKeys::RightMouseButton))
		{
			if (!bPanning)
			{
				DistanceDragged += FMath::Abs( MouseEvent.GetCursorDelta().X );
				if ( DistanceDragged > FSlateApplication::Get().GetDragTriggerDistance() )
				{
					FReply::Handled().CaptureMouse(WidgetOwner.AsShared()).UseHighPrecisionMouseMovement(WidgetOwner.AsShared());
					SoftwareCursorPosition = MyGeometry.AbsoluteToLocal(MouseEvent.GetLastScreenSpacePosition());
					bPanning = true;
				}
			}
			else
			{
				SoftwareCursorPosition = MyGeometry.AbsoluteToLocal(MouseEvent.GetLastScreenSpacePosition());

				TRange<float> LocalViewRange = TimeSliderArgs.ViewRange.Get();
				float LocalViewRangeMin = LocalViewRange.GetLowerBoundValue();
				float LocalViewRangeMax = LocalViewRange.GetUpperBoundValue();

				FScrubRangeToScreen ScaleInfo( LocalViewRange, MyGeometry.Size );
				FVector2D ScreenDelta = MouseEvent.GetCursorDelta();
				FVector2D InputDelta;
				InputDelta.X = ScreenDelta.X/ScaleInfo.PixelsPerInput;

				float NewViewOutputMin = LocalViewRangeMin - InputDelta.X;
				float NewViewOutputMax = LocalViewRangeMax - InputDelta.X;

				float LocalClampMin = TimeSliderArgs.ClampRange.Get().GetLowerBoundValue();
				float LocalClampMax = TimeSliderArgs.ClampRange.Get().GetUpperBoundValue();

				// Clamp the range
				if ( NewViewOutputMin < LocalClampMin )
				{
					NewViewOutputMin = LocalClampMin;
				}
			
				if ( NewViewOutputMax > LocalClampMax )
				{
					NewViewOutputMax = LocalClampMax;
				}

				TimeSliderArgs.OnViewRangeChanged.ExecuteIfBound(TRange<float>(NewViewOutputMin, NewViewOutputMax), EViewRangeInterpolation::Immediate);
				if (Scrollbar.IsValid())
				{
					float InOffsetFraction = (NewViewOutputMin - LocalClampMin) / (LocalClampMax - LocalClampMin);
					float InThumbSizeFraction = (NewViewOutputMax - NewViewOutputMin) / (LocalClampMax - LocalClampMin);
					Scrollbar->SetState(InOffsetFraction, InThumbSizeFraction);
				}

				if( !TimeSliderArgs.ViewRange.IsBound() )
				{	
					// The  output is not bound to a delegate so we'll manage the value ourselves
					TimeSliderArgs.ViewRange.Set( TRange<float>( NewViewOutputMin, NewViewOutputMax ) );
				}
			}
		}
		else if (MouseEvent.IsMouseButtonDown( EKeys::LeftMouseButton ))
		{
			if ( !bDraggingScrubber )
			{
				DistanceDragged += FMath::Abs( MouseEvent.GetCursorDelta().X );
				if ( DistanceDragged > 0/*FSlateApplication::Get().GetDragTriggerDistance()*/ )
				{
					bDraggingScrubber = true;
					TimeSliderArgs.OnBeginScrubberMovement.ExecuteIfBound();
				}
			}
			else
			{
				FScrubRangeToScreen RangeToScreen( TimeSliderArgs.ViewRange.Get(), MyGeometry.Size );
				FVector2D CursorPos = MyGeometry.AbsoluteToLocal( MouseEvent.GetLastScreenSpacePosition() );
				float NewValue = RangeToScreen.LocalXToInput( CursorPos.X );

				float LocalClampMin = TimeSliderArgs.ClampRange.Get().GetLowerBoundValue();
				float LocalClampMax = TimeSliderArgs.ClampRange.Get().GetUpperBoundValue();

				if (NewValue < LocalClampMin)
				{
					NewValue = LocalClampMin;
				}

				if (NewValue > LocalClampMax)
				{
					NewValue = LocalClampMax;
				}

				CommitScrubPosition(NewValue, /*bIsScrubbing=*/true);
			}
		}
		return FReply::Handled();
	}

	return FReply::Unhandled();
}