FGradientStopMark SColorGradientEditor::AddStop( const FVector2D& Position, const FGeometry& MyGeometry, bool bColorStop ) { FScopedTransaction AddStopTrans( LOCTEXT("AddGradientStop", "Add Gradient Stop") ); CurveOwner->ModifyOwner(); FTrackScaleInfo ScaleInfo(ViewMinInput.Get(), ViewMaxInput.Get(), 0.0f, 1.0f, MyGeometry.Size); FVector2D LocalPos = MyGeometry.AbsoluteToLocal( Position ); float NewStopTime = ScaleInfo.LocalXToInput( LocalPos.X ); TArray<FRichCurveEditInfo> Curves = CurveOwner->GetCurves(); FGradientStopMark NewStop; NewStop.Time = NewStopTime; if( bColorStop ) { FRichCurve* RedCurve = Curves[0].CurveToEdit; FRichCurve* GreenCurve = Curves[1].CurveToEdit; FRichCurve* BlueCurve = Curves[2].CurveToEdit; NewStop.RedKeyHandle = RedCurve->AddKey( NewStopTime, LastModifiedColor.R ); NewStop.GreenKeyHandle = GreenCurve->AddKey( NewStopTime, LastModifiedColor.G ); NewStop.BlueKeyHandle = BlueCurve->AddKey( NewStopTime, LastModifiedColor.B ); } else { FRichCurve* AlphaCurve = Curves[3].CurveToEdit; NewStop.AlphaKeyHandle = AlphaCurve->AddKey( NewStopTime, LastModifiedColor.A ); } return NewStop; }
FReply SColorGradientEditor::OnMouseMove( const FGeometry& MyGeometry, const FPointerEvent& MouseEvent ) { if( HasMouseCapture() && IsEditingEnabled.Get() == true ) { DistanceDragged += FMath::Abs( MouseEvent.GetCursorDelta().X ); if( MouseEvent.IsMouseButtonDown( EKeys::LeftMouseButton ) && SelectedStop.IsValid( *CurveOwner ) ) { const float DragThresholdDist = 5.0f; if( !bDraggingStop ) { if( DistanceDragged >= DragThresholdDist ) { // Start a transaction, we just started dragging a stop bDraggingStop = true; GEditor->BeginTransaction( LOCTEXT("MoveGradientStop", "Move Gradient Stop") ); CurveOwner->ModifyOwner(); } return FReply::Handled(); } else { // Already dragging a stop, move it FTrackScaleInfo ScaleInfo(ViewMinInput.Get(), ViewMaxInput.Get(), 0.0f, 1.0f, MyGeometry.Size); float MouseTime = ScaleInfo.LocalXToInput( MyGeometry.AbsoluteToLocal( MouseEvent.GetScreenSpacePosition() ).X ); MoveStop( SelectedStop, MouseTime ); return FReply::Handled(); } } } return FReply::Unhandled(); }
int32 SAnimCurveEd::OnPaint(const FPaintArgs& Args, const FGeometry& AllottedGeometry, const FSlateRect& MyClippingRect, FSlateWindowElementList& OutDrawElements, int32 LayerId, const FWidgetStyle& InWidgetStyle, bool bParentEnabled) const { int32 NewLayerId = SCurveEditor::OnPaint(Args, AllottedGeometry, MyClippingRect, OutDrawElements, LayerId, InWidgetStyle, bParentEnabled) + 1; float Value = 0.f; if(OnGetScrubValue.IsBound()) { Value = OnGetScrubValue.Execute(); } FPaintGeometry MyGeometry = AllottedGeometry.ToPaintGeometry(); // scale info FTrackScaleInfo ScaleInfo(ViewMinInput.Get(), ViewMaxInput.Get(), 0.f, 0.f, AllottedGeometry.Size); float XPos = ScaleInfo.InputToLocalX(Value); TArray<FVector2D> LinePoints; LinePoints.Add(FVector2D(XPos-1, 0.f)); LinePoints.Add(FVector2D(XPos+1, AllottedGeometry.Size.Y)); FSlateDrawElement::MakeLines( OutDrawElements, NewLayerId, MyGeometry, LinePoints, MyClippingRect, ESlateDrawEffect::None, FLinearColor::Red ); // now draw scrub with new layer ID + 1; return NewLayerId; }
Sprite::Sprite(void) : ActionManager(&(AVTexture2D::m_vPosition), &m_angle, &m_scale, &m_Color.a) { m_scale = ScaleInfo(1.f, 1.f); m_angle = AV_DI(0); m_anchorPoint = D3DXVECTOR2( 0.0f, 0.0f ); m_isUse = true; }
FVector2D STrackNode::GetOffsetRelativeToParent(const FGeometry& AllottedGeometry) const { FTrackScaleInfo ScaleInfo(ViewInputMin.Get(), ViewInputMax.Get(), 0, 0, AllottedGeometry.Size); if(bCenterOnPosition) { FVector2D Size = GetSizeRelativeToParent(AllottedGeometry); return FVector2D( ScaleInfo.InputToLocalX(DataStartPos.Get()) - (Size.X/2.f) , 0); } return FVector2D( ScaleInfo.InputToLocalX(DataStartPos.Get()) , 0); }
FGradientStopMark SColorGradientEditor::GetGradientStopAtPoint( const FVector2D& MousePos, const FGeometry& MyGeometry ) { FGeometry ColorMarkAreaGeometry = GetColorMarkAreaGeometry( MyGeometry ); FGeometry AlphaMarkAreaGeometry = GetAlphaMarkAreaGeometry( MyGeometry ); FTrackScaleInfo ScaleInfo(ViewMinInput.Get(), ViewMaxInput.Get(), 0.0f, 1.0f, MyGeometry.Size); if( ColorMarkAreaGeometry.IsUnderLocation( MousePos ) || AlphaMarkAreaGeometry.IsUnderLocation( MousePos ) ) { TArray<FGradientStopMark> ColorMarks; TArray<FGradientStopMark> AlphaMarks; GetGradientStopMarks( ColorMarks, AlphaMarks ); // See if any color stops are under the mouse for( int32 ColorIndex = 0; ColorIndex < ColorMarks.Num(); ++ColorIndex ) { const FGradientStopMark& Mark = ColorMarks[ColorIndex]; // Convert the time to a screen coordinate float XVal = ScaleInfo.InputToLocalX( Mark.Time ); if( XVal >= 0 ) { FGeometry MarkGeometry = ColorMarkAreaGeometry.MakeChild( FVector2D( XVal-HandleRect.Left, HandleRect.Top ), FVector2D( HandleRect.Right, HandleRect.Bottom ) ); if( MarkGeometry.IsUnderLocation( MousePos ) ) { return Mark; } } } // See if any color stops are under the mouse for( int32 ColorIndex = 0; ColorIndex < AlphaMarks.Num(); ++ColorIndex ) { const FGradientStopMark& Mark = AlphaMarks[ColorIndex]; float XVal = ScaleInfo.InputToLocalX( Mark.Time ); if( XVal >= 0 ) { FGeometry MarkGeometry = AlphaMarkAreaGeometry.MakeChild( FVector2D( XVal-HandleRect.Left, HandleRect.Top ), FVector2D( HandleRect.Right, HandleRect.Bottom ) ); if( MarkGeometry.IsUnderLocation( MousePos ) ) { return Mark; } } } } return FGradientStopMark(); }
FVector2D STrackNode::GetSizeRelativeToParent(const FGeometry& AllottedGeometry) const { if(DataLength.Get() > 0.f) { // Scale us by data size FTrackScaleInfo ScaleInfo(ViewInputMin.Get(), ViewInputMax.Get(), 0, 0, AllottedGeometry.Size); return FVector2D( ScaleInfo.InputToLocalX(ViewInputMin.Get() + DataLength.Get()) , STrackDefaultHeight); } else { // Use default hardcoded "knob" size return FVector2D(NodeHandleWidth, NodeHandleHeight); } }
FReply SAnimTrackPanel::OnMouseMove( const FGeometry& InMyGeometry, const FPointerEvent& InMouseEvent ) { const bool bRightMouseButtonDown = InMouseEvent.IsMouseButtonDown(EKeys::RightMouseButton); // When mouse moves, if we are moving a key, update its 'input' position if(bRightMouseButtonDown) { if( !bPanning ) { PanningDistance += FMath::Abs(InMouseEvent.GetCursorDelta().X); if ( PanningDistance > FSlateApplication::Get().GetDragTriggerDistance() ) { bPanning = true; UE_LOG(LogAnimation, Log, TEXT("MouseMove (Capturing Mouse) %d, %0.5f"), bPanning, PanningDistance); return FReply::Handled().CaptureMouse(SharedThis(this)); } } else { FTrackScaleInfo ScaleInfo(ViewInputMin.Get(), ViewInputMax.Get(), 0.f, 0.f, InMyGeometry.Size); FVector2D ScreenDelta = InMouseEvent.GetCursorDelta(); FVector2D InputDelta; InputDelta.X = ScreenDelta.X/ScaleInfo.PixelsPerInput; InputDelta.Y = -ScreenDelta.Y/ScaleInfo.PixelsPerOutput; float NewViewInputMin = ViewInputMin.Get() - InputDelta.X; float NewViewInputMax = ViewInputMax.Get() - InputDelta.X; // we'd like to keep the range if outside when panning if ( NewViewInputMin < InputMin.Get() ) { NewViewInputMin = InputMin.Get(); NewViewInputMax = ScaleInfo.ViewInputRange; } else if ( NewViewInputMax > InputMax.Get() ) { NewViewInputMax = InputMax.Get(); NewViewInputMin = NewViewInputMax - ScaleInfo.ViewInputRange; } OnSetInputViewRange.Execute(NewViewInputMin, NewViewInputMax); UE_LOG(LogAnimation, Log, TEXT("MouseMove (Panning) %0.2f, %0.2f"), ViewInputMin.Get(), ViewInputMax.Get()); return FReply::Handled(); } } return FReply::Unhandled(); }
void ScrollWindow::show() { if (_visible) { return; } if (_screenItem == nullptr) { CelInfo32 celInfo; celInfo.type = kCelTypeMem; celInfo.bitmap = _bitmap; _screenItem = new ScreenItem(_plane, celInfo, _position, ScaleInfo()); } Plane *plane = g_sci->_gfxFrameout->getPlanes().findByObject(_plane); if (plane == nullptr) { error("[ScrollWindow::show]: Plane %04x:%04x not found", PRINT_REG(_plane)); } plane->_screenItemList.add(_screenItem); _visible = true; }
void SAnimTrackPanel::PanInputViewRange(int32 ScreenDelta, FVector2D ScreenViewSize) { FTrackScaleInfo ScaleInfo(ViewInputMin.Get(), ViewInputMax.Get(), 0.f, 0.f, ScreenViewSize); float InputDeltaX = ScreenDelta/ScaleInfo.PixelsPerInput; float NewViewInputMin = ViewInputMin.Get() + InputDeltaX; float NewViewInputMax = ViewInputMax.Get() + InputDeltaX; // we'd like to keep the range if outside when panning float SequenceLength = GetSequenceLength(); if ( NewViewInputMin < 0.f ) { NewViewInputMin = 0.f; NewViewInputMax = ScaleInfo.ViewInputRange; } else if ( NewViewInputMax >SequenceLength ) { NewViewInputMax = SequenceLength; NewViewInputMin = NewViewInputMax - ScaleInfo.ViewInputRange; } OnSetInputViewRange.Execute(NewViewInputMin, NewViewInputMax); }
FReply FVisualLoggerTimeSliderController::OnMouseMove( TSharedRef<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).UseHighPrecisionMouseMovement(WidgetOwner); 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, false); 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(); }
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(); }
void STimingTrack::OnArrangeChildren(const FGeometry& AllottedGeometry, FArrangedChildren& ArrangedChildren) const { // To make this track look nice and have no overlapping nodes we're going to // treat this as a 1D collision problem and build/resolve islands until everything // is nicely resolved (or until we hit an upper limit as it can't be solved) // Helper holding info about a single node struct NodeData { NodeData(TSharedRef<STrackNode>& NodeRef, const FGeometry& Geometry) : Node(NodeRef) { // Separation of the nodes on the track const float NodeSeparation = 3.0f; Node->CacheTrackGeometry(Geometry); FVector2D Offset = Node->GetOffsetRelativeToParent(Geometry); FVector2D Size = Node->GetSizeRelativeToParent(Geometry); Offset.Y += (Geometry.GetLocalSize().Y - Size.Y) * 0.5f; ActualRect = FBox2D(Offset, Offset + Size); QueryRect = FBox2D(Offset - FVector2D(NodeSeparation, 0.0f), Offset + Size + FVector2D(NodeSeparation, 0.0f)); } TSharedRef<STrackNode> Node; // The node widget FBox2D ActualRect; // The actual render rect of the widget FBox2D QueryRect; // An expanded rect used to detect collisions }; // Helper holding list of overlapping nodes struct NodeIsland { TArray<NodeData*> Nodes; }; int32 NumNodes = TrackNodes.Num(); TArray<NodeData> SortedNodeData; SortedNodeData.Reserve(NumNodes); // List of collision islands TArray<NodeIsland> Islands; // Scaling info to translate between local positions and data values FTrackScaleInfo ScaleInfo(ViewInputMin.Get(), ViewInputMax.Get(), 0, 0, AllottedGeometry.Size); for(int32 TrackIndex = 0; TrackIndex < NumNodes; ++TrackIndex) { TSharedRef<STrackNode> TrackNode = (TrackNodes[TrackIndex]); SortedNodeData.Add(NodeData(TrackNode, AllottedGeometry)); } const static int32 MaxRetries = 5; int32 Retries = 0; bool bResolved = true; while(bResolved && Retries < MaxRetries) { ++Retries; bResolved = false; for(int32 NodeIdx = 0; NodeIdx < NumNodes; ++NodeIdx) { NodeData& CurrentNode = SortedNodeData[NodeIdx]; // Island generation NodeIsland* CurrentIsland = nullptr; CurrentIsland = &Islands[Islands.AddZeroed()]; int32 Direction = -1; int32 Next = NodeIdx + 1; int32 HighestNode = NodeIdx; FBox2D& CurrentRect = CurrentNode.ActualRect; FBox2D CurrentQueryRect = CurrentNode.QueryRect; CurrentIsland->Nodes.Add(&CurrentNode); // Walk Nodes while(Next >= 0 && Next < NumNodes) { NodeData& NextNode = SortedNodeData[Next]; FBox2D& NextRect = NextNode.ActualRect; FBox2D& NextQueryRect = NextNode.QueryRect; if(NextQueryRect.Intersect(CurrentQueryRect)) { // Add to island CurrentIsland->Nodes.Add(&NextNode); HighestNode = Next; // Expand the current query CurrentQueryRect.Max = NextQueryRect.Max; } else { // No island, next node break; } ++Next; } // Skip processed nodes (those already in islands) NodeIdx = HighestNode; } // Separation of the nodes on the track const float NodeSeparation = 3.0f; for(NodeIsland& Island : Islands) { if(Island.Nodes.Num() == 1) { // Keep single nodes on the data track range but skip everything else FBox2D& NodeBox = Island.Nodes[0]->ActualRect; FBox2D& NodeQueryRect = Island.Nodes[0]->QueryRect; float Offset = 0.0f; float Begin = ScaleInfo.LocalXToInput(NodeBox.Min.X); float End = ScaleInfo.LocalXToInput(NodeBox.Max.X); if(Begin < 0) { Offset = ScaleInfo.InputToLocalX(-Begin); } else if(End > TrackMaxValue.Get()) { Offset = ScaleInfo.InputToLocalX(TrackMaxValue.Get() - End); } if(Offset != 0.0f) { NodeBox.Min.X += Offset; NodeBox.Max.X += Offset; NodeQueryRect.Min.X = NodeBox.Min.X - NodeSeparation; NodeQueryRect.Max.X = NodeBox.Max.X + NodeSeparation; } continue; } bResolved = true; // Island resolution int32 NumIslandNodes = Island.Nodes.Num(); float Width = FMath::Max<float>((NumIslandNodes - 1), 0.0f) * NodeSeparation; float Centre = 0.0f; for(NodeData* Node : Island.Nodes) { Width += Node->ActualRect.GetSize().X; Centre += Node->ActualRect.GetCenter().X; } Centre /= NumIslandNodes; // Make sure the group stays on the track float Begin = Centre - Width / 2.0f; float WidthAsInput = Width / ScaleInfo.PixelsPerInput; float BeginAsInput = FMath::Clamp(ScaleInfo.LocalXToInput(Begin), 0.0f, TrackMaxValue.Get() - WidthAsInput); Begin = ScaleInfo.InputToLocalX(BeginAsInput); for(int32 NodeIdx = 0 ; NodeIdx < NumIslandNodes ; ++NodeIdx) { FBox2D& NodeBox = Island.Nodes[NodeIdx]->ActualRect; float NodeWidth = NodeBox.GetSize().X; float SeparationOffset = NodeIdx * NodeSeparation; float PositionOffset = 0.0f; for(int32 PositionNodeIdx = 0 ; PositionNodeIdx < NodeIdx ; ++PositionNodeIdx) { PositionOffset += Island.Nodes[PositionNodeIdx]->ActualRect.GetSize().X; } FBox2D& OriginalRect = Island.Nodes[NodeIdx]->ActualRect; OriginalRect.Min.X = Begin + PositionOffset + SeparationOffset; OriginalRect.Max.X = OriginalRect.Min.X + NodeWidth; // Alter Query rect for next pass FBox2D& NodeQueryRect = Island.Nodes[NodeIdx]->QueryRect; NodeQueryRect.Min = OriginalRect.Min - FVector2D(NodeSeparation, 0.0f); NodeQueryRect.Max = OriginalRect.Max + FVector2D(NodeSeparation, 0.0f); } } } for(int32 TrackIndex = 0; TrackIndex < NumNodes; ++TrackIndex) { TSharedRef<STrackNode> TrackNode = (SortedNodeData[TrackIndex].Node); if(TrackNode->IsBeingDragged()) { continue; } FBox2D& Rect = SortedNodeData[TrackIndex].ActualRect; ArrangedChildren.AddWidget(AllottedGeometry.MakeChild(TrackNode, Rect.Min, Rect.GetSize())); } }
FReply FSequencerTimeSliderController::OnMouseMove( TSharedRef<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; SetViewRange(NewViewOutputMin, NewViewOutputMax, EViewRangeInterpolation::Immediate); } } else if (MouseEvent.IsMouseButtonDown( EKeys::LeftMouseButton )) { if ( !bDraggingScrubber ) { DistanceDragged += FMath::Abs( MouseEvent.GetCursorDelta().X ); if ( DistanceDragged > 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 ); const USequencerSettings* Settings = GetDefault<USequencerSettings>(); if ( Settings->GetIsSnapEnabled() && Settings->GetSnapPlayTimeToInterval() ) { NewValue = Settings->SnapTimeToInterval(NewValue); } CommitScrubPosition( NewValue, /*bIsScrubbing=*/true ); } } return FReply::Handled(); } return FReply::Unhandled(); }
/** Returns Local cordinate X to Data (Time, etc) */ float STrack::LocalToDataX( float Input, const FGeometry& MyGeometry ) const { FTrackScaleInfo ScaleInfo(ViewInputMin.Get(), ViewInputMax.Get(), 0, 0, MyGeometry.Size); return ScaleInfo.LocalXToInput(Input); }
/** Returns Data (Time, etc) to Local cordinate X */ float STrack::DataToLocalX( float Data, const FGeometry& MyGeometry ) const { FTrackScaleInfo ScaleInfo(ViewInputMin.Get(), ViewInputMax.Get(), 0, 0, MyGeometry.Size); return ScaleInfo.InputToLocalX(Data); }
reg_t GfxControls32::kernelEditText(const reg_t controlObject) { SegManager *segMan = _segMan; TextEditor editor; reg_t textObject = readSelector(_segMan, controlObject, SELECTOR(text)); editor.text = _segMan->getString(textObject); editor.foreColor = readSelectorValue(_segMan, controlObject, SELECTOR(fore)); editor.backColor = readSelectorValue(_segMan, controlObject, SELECTOR(back)); editor.skipColor = readSelectorValue(_segMan, controlObject, SELECTOR(skip)); editor.fontId = readSelectorValue(_segMan, controlObject, SELECTOR(font)); editor.maxLength = readSelectorValue(_segMan, controlObject, SELECTOR(width)); editor.bitmap = readSelector(_segMan, controlObject, SELECTOR(bitmap)); editor.cursorCharPosition = 0; editor.cursorIsDrawn = false; editor.borderColor = readSelectorValue(_segMan, controlObject, SELECTOR(borderColor)); reg_t titleObject = readSelector(_segMan, controlObject, SELECTOR(title)); int16 titleHeight = 0; GuiResourceId titleFontId = readSelectorValue(_segMan, controlObject, SELECTOR(titleFont)); if (!titleObject.isNull()) { GfxFont *titleFont = _gfxCache->getFont(titleFontId); titleHeight += _gfxText32->scaleUpHeight(titleFont->getHeight()) + 1; if (editor.borderColor != -1) { titleHeight += 2; } } int16 width = 0; int16 height = titleHeight; GfxFont *editorFont = _gfxCache->getFont(editor.fontId); height += _gfxText32->scaleUpHeight(editorFont->getHeight()) + 1; _gfxText32->setFont(editor.fontId); int16 emSize = _gfxText32->getCharWidth('M', true); width += editor.maxLength * emSize + 1; if (editor.borderColor != -1) { width += 4; height += 2; } Common::Rect editorPlaneRect(width, height); editorPlaneRect.translate(readSelectorValue(_segMan, controlObject, SELECTOR(x)), readSelectorValue(_segMan, controlObject, SELECTOR(y))); reg_t planeObj = readSelector(_segMan, controlObject, SELECTOR(plane)); Plane *sourcePlane = g_sci->_gfxFrameout->getVisiblePlanes().findByObject(planeObj); if (sourcePlane == nullptr) { sourcePlane = g_sci->_gfxFrameout->getPlanes().findByObject(planeObj); if (sourcePlane == nullptr) { error("Could not find plane %04x:%04x", PRINT_REG(planeObj)); } } editorPlaneRect.translate(sourcePlane->_gameRect.left, sourcePlane->_gameRect.top); editor.textRect = Common::Rect(2, titleHeight + 2, width - 1, height - 1); editor.width = width; if (editor.bitmap.isNull()) { TextAlign alignment = (TextAlign)readSelectorValue(_segMan, controlObject, SELECTOR(mode)); if (titleObject.isNull()) { bool dimmed = readSelectorValue(_segMan, controlObject, SELECTOR(dimmed)); editor.bitmap = _gfxText32->createFontBitmap(width, height, editor.textRect, editor.text, editor.foreColor, editor.backColor, editor.skipColor, editor.fontId, alignment, editor.borderColor, dimmed, true, false); } else { error("Titled bitmaps are not known to be used by any game. Please submit a bug report with details about the game you were playing and what you were doing that triggered this error. Thanks!"); } } drawCursor(editor); Plane *plane = new Plane(editorPlaneRect, kPlanePicTransparent); plane->changePic(); g_sci->_gfxFrameout->addPlane(*plane); CelInfo32 celInfo; celInfo.type = kCelTypeMem; celInfo.bitmap = editor.bitmap; ScreenItem *screenItem = new ScreenItem(plane->_object, celInfo, Common::Point(), ScaleInfo()); plane->_screenItemList.add(screenItem); // frameOut must be called after the screen item is // created, and before it is updated at the end of the // event loop, otherwise it has both created and updated // flags set which crashes the engine (it runs updates // before creations) g_sci->_gfxFrameout->frameOut(true); EventManager *eventManager = g_sci->getEventManager(); bool clearTextOnInput = true; bool textChanged = false; for (;;) { // We peek here because the last event needs to be allowed to // dispatch a second time to the normal event handling system. // In the actual engine, the event is always consumed and then // the last event just gets posted back to the event manager for // reprocessing, but instead, we only remove the event from the // queue *after* we have determined it is not a defocusing event const SciEvent event = eventManager->getSciEvent(SCI_EVENT_ANY | SCI_EVENT_PEEK); bool focused = true; // Original engine did not have a QUIT event but we have to handle it if (event.type == SCI_EVENT_QUIT) { focused = false; break; } else if (event.type == SCI_EVENT_MOUSE_PRESS && !editorPlaneRect.contains(event.mousePosSci)) { focused = false; } else if (event.type == SCI_EVENT_KEYBOARD) { switch (event.character) { case SCI_KEY_ESC: case SCI_KEY_UP: case SCI_KEY_DOWN: case SCI_KEY_TAB: case SCI_KEY_SHIFT_TAB: case SCI_KEY_ENTER: focused = false; break; } } if (!focused) { break; } // Consume the event now that we know it is not one of the // defocusing events above if (event.type != SCI_EVENT_NONE) eventManager->getSciEvent(SCI_EVENT_ANY); // NOTE: In the original engine, the font and bitmap were // reset here on each iteration through the loop, but it // doesn't seem like this should be necessary since // control is not yielded back to the VM until input is // received, which means there is nothing that could modify // the GfxText32's state with a different font in the // meantime bool shouldDeleteChar = false; bool shouldRedrawText = false; uint16 lastCursorPosition = editor.cursorCharPosition; if (event.type == SCI_EVENT_KEYBOARD) { switch (event.character) { case SCI_KEY_LEFT: clearTextOnInput = false; if (editor.cursorCharPosition > 0) { --editor.cursorCharPosition; } break; case SCI_KEY_RIGHT: clearTextOnInput = false; if (editor.cursorCharPosition < editor.text.size()) { ++editor.cursorCharPosition; } break; case SCI_KEY_HOME: clearTextOnInput = false; editor.cursorCharPosition = 0; break; case SCI_KEY_END: clearTextOnInput = false; editor.cursorCharPosition = editor.text.size(); break; case SCI_KEY_INSERT: clearTextOnInput = false; // Redrawing also changes the cursor rect to // reflect the new insertion mode shouldRedrawText = true; _overwriteMode = !_overwriteMode; break; case SCI_KEY_DELETE: clearTextOnInput = false; if (editor.cursorCharPosition < editor.text.size()) { shouldDeleteChar = true; } break; case SCI_KEY_BACKSPACE: clearTextOnInput = false; shouldDeleteChar = true; if (editor.cursorCharPosition > 0) { --editor.cursorCharPosition; } break; case SCI_KEY_ETX: editor.text.clear(); editor.cursorCharPosition = 0; shouldRedrawText = true; break; default: { if (event.character >= 20 && event.character < 257) { if (clearTextOnInput) { clearTextOnInput = false; editor.text.clear(); } if ( (_overwriteMode && editor.cursorCharPosition < editor.maxLength) || (editor.text.size() < editor.maxLength && _gfxText32->getCharWidth(event.character, true) + _gfxText32->getStringWidth(editor.text) < editor.textRect.width()) ) { if (_overwriteMode && editor.cursorCharPosition < editor.text.size()) { editor.text.setChar(event.character, editor.cursorCharPosition); } else { editor.text.insertChar(event.character, editor.cursorCharPosition); } ++editor.cursorCharPosition; shouldRedrawText = true; } } } } } if (shouldDeleteChar) { shouldRedrawText = true; if (editor.cursorCharPosition < editor.text.size()) { editor.text.deleteChar(editor.cursorCharPosition); } } if (shouldRedrawText) { eraseCursor(editor); _gfxText32->erase(editor.textRect, true); _gfxText32->drawTextBox(editor.text); drawCursor(editor); textChanged = true; screenItem->_updated = g_sci->_gfxFrameout->getScreenCount(); } else if (editor.cursorCharPosition != lastCursorPosition) { eraseCursor(editor); drawCursor(editor); screenItem->_updated = g_sci->_gfxFrameout->getScreenCount(); } else { flashCursor(editor); screenItem->_updated = g_sci->_gfxFrameout->getScreenCount(); } g_sci->_gfxFrameout->frameOut(true); g_sci->getSciDebugger()->onFrame(); g_sci->_gfxFrameout->throttle(); } g_sci->_gfxFrameout->deletePlane(*plane); if (readSelectorValue(segMan, controlObject, SELECTOR(frameOut))) { g_sci->_gfxFrameout->frameOut(true); } _segMan->freeBitmap(editor.bitmap); if (textChanged) { editor.text.trim(); SciArray &string = *_segMan->lookupArray(textObject); string.fromString(editor.text); } return make_reg(0, textChanged); }
FReply FSequencerTimeSliderController::OnMouseMove( TSharedRef<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().GetDragTriggerDistnace() ) { 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; TOptional<float> LocalClampMin = TimeSliderArgs.ClampMin.Get(); TOptional<float> LocalClampMax = TimeSliderArgs.ClampMax.Get(); // Clamp the range if clamp values are set if ( LocalClampMin.IsSet() && NewViewOutputMin < LocalClampMin.GetValue() ) { NewViewOutputMin = LocalClampMin.GetValue(); } if ( LocalClampMax.IsSet() && NewViewOutputMax > LocalClampMax.GetValue() ) { NewViewOutputMax = LocalClampMax.GetValue(); } TimeSliderArgs.OnViewRangeChanged.ExecuteIfBound(TRange<float>(NewViewOutputMin, NewViewOutputMax)); 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 > FSlateApplication::Get().GetDragTriggerDistnace() ) { 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 ); const USequencerSnapSettings* SnapSettings = GetDefault<USequencerSnapSettings>(); if ( SnapSettings->GetIsSnapEnabled() && SnapSettings->GetSnapPlayTimeToInterval() ) { NewValue = SnapSettings->SnapToInterval(NewValue); } CommitScrubPosition( NewValue, /*bIsScrubbing=*/true ); } } return FReply::Handled(); } return FReply::Unhandled(); }
FReply SScrubWidget::OnMouseMove( const FGeometry& MyGeometry, const FPointerEvent& MouseEvent ) { // Bar Dragging if(DraggingBar) { // Update bar if we are dragging FVector2D CursorPos = MyGeometry.AbsoluteToLocal( MouseEvent.GetScreenSpacePosition() ); FTrackScaleInfo ScaleInfo(ViewInputMin.Get(), ViewInputMax.Get(), 0.f, 0.f, MyGeometry.Size); float NewDataPos = FMath::Clamp( ScaleInfo.LocalXToInput(CursorPos.X), ViewInputMin.Get(), ViewInputMax.Get() ); OnBarDrag.ExecuteIfBound(DraggableBarIndex, NewDataPos); } else { // Update what bar we are hovering over FVector2D CursorPos = MyGeometry.AbsoluteToLocal(MouseEvent.GetScreenSpacePosition()); FTrackScaleInfo ScaleInfo(ViewInputMin.Get(), ViewInputMax.Get(), 0.f, 0.f, MyGeometry.Size); DraggableBarIndex = INDEX_NONE; if ( DraggableBars.IsBound() ) { const TArray<float>& DraggableBarsVal = DraggableBars.Get(); for ( int32 I=0; I < DraggableBarsVal.Num(); I++ ) { if( FMath::Abs( ScaleInfo.InputToLocalX(DraggableBarsVal[I]) - CursorPos.X ) < 10 ) { DraggableBarIndex = I; break; } } } } if ( this->HasMouseCapture() ) { if (MouseEvent.IsMouseButtonDown( EKeys::RightMouseButton ) && bPanning) { FTrackScaleInfo ScaleInfo(ViewInputMin.Get(), ViewInputMax.Get(), 0.f, 0.f, MyGeometry.Size); FVector2D ScreenDelta = MouseEvent.GetCursorDelta(); float InputDeltaX = ScreenDelta.X/ScaleInfo.PixelsPerInput; bMouseMovedDuringPanning |= !ScreenDelta.IsNearlyZero(0.001f); float NewViewInputMin = ViewInputMin.Get() - InputDeltaX; float NewViewInputMax = ViewInputMax.Get() - InputDeltaX; // we'd like to keep the range if outside when panning if ( NewViewInputMin < 0.f ) { NewViewInputMin = 0.f; NewViewInputMax = ScaleInfo.ViewInputRange; } else if ( NewViewInputMax > SequenceLength.Get() ) { NewViewInputMax = SequenceLength.Get(); NewViewInputMin = NewViewInputMax - ScaleInfo.ViewInputRange; } OnSetInputViewRange.ExecuteIfBound(NewViewInputMin, NewViewInputMax); } else if (!bDragging) { DistanceDragged += FMath::Abs(MouseEvent.GetCursorDelta().X); if ( DistanceDragged > FSlateApplication::Get().GetDragTriggerDistance() ) { bDragging = true; } if( bDragging ) { OnBeginSliderMovement.ExecuteIfBound(); } } else if (bDragging) { FTrackScaleInfo TimeScaleInfo(ViewInputMin.Get(), ViewInputMax.Get(), 0.f, 0.f, MyGeometry.Size); FVector2D CursorPos = MyGeometry.AbsoluteToLocal(MouseEvent.GetLastScreenSpacePosition()); float NewValue = TimeScaleInfo.LocalXToInput(CursorPos.X); CommitValue( NewValue, true, false ); } return FReply::Handled(); } return FReply::Unhandled(); }
int32 SColorGradientEditor::OnPaint( const FPaintArgs& Args, const FGeometry& AllottedGeometry, const FSlateRect& MyClippingRect, FSlateWindowElementList& OutDrawElements, int32 LayerId, const FWidgetStyle& InWidgetStyle, bool bParentEnabled ) const { const TSharedRef< FSlateFontMeasure > FontMeasureService = FSlateApplication::Get().GetRenderer()->GetFontMeasureService(); if( CurveOwner ) { // Split the geometry into areas for stops and the gradient FGeometry ColorMarkAreaGeometry = GetColorMarkAreaGeometry( AllottedGeometry ); FGeometry AlphaMarkAreaGeometry = GetAlphaMarkAreaGeometry( AllottedGeometry ); FGeometry GradientAreaGeometry = AllottedGeometry.MakeChild( FVector2D(0.0f, 16.0f), FVector2D( AllottedGeometry.Size.X, AllottedGeometry.Size.Y - 30.0f ) ); bool bEnabled = ShouldBeEnabled( bParentEnabled ); ESlateDrawEffect::Type DrawEffects = bEnabled ? ESlateDrawEffect::None : ESlateDrawEffect::DisabledEffect; // Pixel to value input converter FTrackScaleInfo ScaleInfo(ViewMinInput.Get(), ViewMaxInput.Get(), 0.0f, 1.0f, GradientAreaGeometry.Size); // The start and end location in slate units of the area to draw int32 Start = 0; int32 Finish = FMath::TruncToInt( AllottedGeometry.Size.X ); TArray<FSlateGradientStop> Stops; // If no alpha keys are available, treat the curve as being completely opaque for drawing purposes bool bHasAnyAlphaKeys = CurveOwner->HasAnyAlphaKeys(); // If any transpareny (A < 1) is found, we'll draw a checkerboard to visualize the color with alpha bool bHasTransparency = false; // Sample the curve every 2 units. THe curve could be non-linear so sampling at each stop would display an incorrect gradient for( int32 CurrentStep = Start; CurrentStep < Finish; CurrentStep+=2 ) { // Figure out the time from the current screen unit float Time = ScaleInfo.LocalXToInput(CurrentStep); // Sample the curve FLinearColor Color = CurveOwner->GetLinearColorValue( Time ); if( !bHasAnyAlphaKeys ) { // Only show alpha if there is at least one key. For some curves, alpha may not be important Color.A = 1.0f; bHasTransparency = false; } else { bHasTransparency |= (Color.A < 1.0f); } Stops.Add( FSlateGradientStop( FVector2D( CurrentStep, 0.0f ), Color ) ); } if( Stops.Num() > 0 ) { if( bHasTransparency ) { // Draw a checkerboard behind there is any transparency visible FSlateDrawElement::MakeBox ( OutDrawElements, LayerId, GradientAreaGeometry.ToPaintGeometry(), FEditorStyle::GetBrush("Checkerboard"), MyClippingRect, DrawEffects ); } // Draw the color gradient FSlateDrawElement::MakeGradient ( OutDrawElements, LayerId, GradientAreaGeometry.ToPaintGeometry(), Stops, Orient_Vertical, MyClippingRect, DrawEffects, false ); } // Get actual editable stop marks TArray<FGradientStopMark> ColorMarks; TArray<FGradientStopMark> AlphaMarks; GetGradientStopMarks( ColorMarks, AlphaMarks ); // Draw each color stop for( int32 ColorIndex = 0; ColorIndex < ColorMarks.Num(); ++ColorIndex ) { const FGradientStopMark& Mark = ColorMarks[ColorIndex]; float XVal = ScaleInfo.InputToLocalX( Mark.Time ); // Dont draw stops which are not visible if( XVal >= 0 && XVal <= ColorMarkAreaGeometry.Size.X ) { FLinearColor Color = CurveOwner->GetLinearColorValue( Mark.Time ); Color.A = 1.0f; DrawGradientStopMark( Mark, ColorMarkAreaGeometry, XVal, Color, OutDrawElements, LayerId, MyClippingRect, DrawEffects, true, InWidgetStyle ); } } // Draw each alpha stop for( int32 ColorIndex = 0; ColorIndex < AlphaMarks.Num(); ++ColorIndex ) { const FGradientStopMark& Mark = AlphaMarks[ColorIndex]; float XVal = ScaleInfo.InputToLocalX( Mark.Time ); // Dont draw stops which are not visible if( XVal >= 0 && XVal <= AlphaMarkAreaGeometry.Size.X ) { float Alpha = CurveOwner->GetLinearColorValue( Mark.Time ).A; DrawGradientStopMark( Mark, AlphaMarkAreaGeometry, XVal, FLinearColor( Alpha, Alpha, Alpha, 1.0f ), OutDrawElements, LayerId, MyClippingRect, DrawEffects, false, InWidgetStyle ); } } // Draw some hint messages about how to add stops if no stops exist if( ColorMarks.Num() == 0 && AlphaMarks.Num() == 0 && IsEditingEnabled.Get() == true ) { static FString GradientColorMessage( LOCTEXT("ClickToAddColorStop", "Click in this area add color stops").ToString() ); static FString GradientAlphaMessage( LOCTEXT("ClickToAddAlphaStop", "Click in this area add opacity stops").ToString() ); // Draw the text centered in the color region { FVector2D StringSize = FontMeasureService->Measure( GradientColorMessage, FSlateFontInfo( FPaths::EngineContentDir() / TEXT("Slate/Fonts/Roboto-Regular.ttf"), 8 ) ); FPaintGeometry PaintGeom = ColorMarkAreaGeometry.ToPaintGeometry(FSlateLayoutTransform(FVector2D((ColorMarkAreaGeometry.Size.X - StringSize.X) * 0.5f, 1.0f))); FSlateDrawElement::MakeText ( OutDrawElements, LayerId, PaintGeom, GradientColorMessage, FSlateFontInfo( FPaths::EngineContentDir() / TEXT("Slate/Fonts/Roboto-Regular.ttf"), 8 ), MyClippingRect, DrawEffects, FLinearColor( .5f, .5f, .5f, .85f ) ); } // Draw the text centered in the alpha region { FVector2D StringSize = FontMeasureService->Measure( GradientAlphaMessage, FSlateFontInfo( FPaths::EngineContentDir() / TEXT("Slate/Fonts/Roboto-Regular.ttf"), 8 ) ); FPaintGeometry PaintGeom = AlphaMarkAreaGeometry.ToPaintGeometry(FSlateLayoutTransform(FVector2D((AlphaMarkAreaGeometry.Size.X - StringSize.X) * 0.5f, 1.0f))); FSlateDrawElement::MakeText ( OutDrawElements, LayerId, PaintGeom, GradientAlphaMessage, FSlateFontInfo( FPaths::EngineContentDir() / TEXT("Slate/Fonts/Roboto-Regular.ttf"), 8 ), MyClippingRect, DrawEffects, FLinearColor( .5f, .5f, .5f, .85f ) ); } } } return LayerId; }