Skip to content
Snippets Groups Projects
Select Git revision
  • 3baf0639dfd854c6996dd7630c2660b275050fb2
  • 5.4 default protected
  • 5.5
  • dev/5.5
  • dev/5.4
  • dev/5.3_downgrade
  • feature/experimenttime_hack
  • 5.3 protected
  • _IntenSelect5.3
  • IntenSelect5.3
  • 4.27 protected
  • 4.26 protected
  • 5.0 protected
  • 4.22 protected
  • 4.21 protected
  • UE5.4-2024.1
  • UE5.4-2024.1-rc1
  • UE5.3-2023.1-rc3
  • UE5.3-2023.1-rc2
  • UE5.3-2023.1-rc
20 results

CollisionHandlingMovement.cpp

Blame
  • SDasherWidget.cpp 13.64 KiB
    #include "SDasherWidget.h"
    #include "SlateOptMacros.h"
    #include "Styling/CoreStyle.h"
    #include "Brushes/SlateColorBrush.h"
    #include "Rendering/DrawElements.h"
    #include "DasherInterface.h"
    
    #include "Components/SlateWrapperTypes.h"
    
    BEGIN_SLATE_FUNCTION_BUILD_OPTIMIZATION
    
    
    // ++ This is needed in order to use the localization macro LOCTEXT
    #define LOCTEXT_NAMESPACE "SStandardSlateWidget"
    
    //Set the state if we're in the editor or not.
    void SDasherWidget::SetEditor(bool EditorState)
    {
    	IsEditor = EditorState;
    }
    
    //Event Handlers
    //Mouse position saved for mouse Input
    FReply SDasherWidget::HandleMouseMoveEvent(const FGeometry& Geometry, const FPointerEvent& MouseEvent)
    {
    	if (CurrentlyUsingVectorInput) return FReply::Unhandled();
    	//The mouse event only contains the Screen Space Position
    	CursorPosition = Geometry.AbsoluteToLocal(MouseEvent.GetScreenSpacePosition());
    	return FReply::Handled();
    }
    
    FReply SDasherWidget::HandleMouseDownEvent(const FGeometry& Geometry, const FPointerEvent& MouseEvent)
    {
    	if (CurrentlyUsingVectorInput)
    	{
    		CurrentlyUsingVectorInput = false;
    		return FReply::Handled().LockMouseToWidget(AsShared());
    	}
    	DasherMainInterface->KeyDown(FDateTime::Now().GetSecond() + FDateTime::Now().GetMillisecond(), 100); //100 is the keycode for LMB
    	MouseDownListeners.ExecuteIfBound();
    	return FReply::Handled().LockMouseToWidget(AsShared());
    }
    
    FReply SDasherWidget::HandleMouseUpEvent(const FGeometry& Geometry, const FPointerEvent& MouseEvent)
    {
    	if (CurrentlyUsingVectorInput)
    	{
    		CurrentlyUsingVectorInput = false;
    		return FReply::Handled().ReleaseMouseLock();
    	}
    	DasherMainInterface->KeyUp(FDateTime::Now().GetSecond() + FDateTime::Now().GetMillisecond(), 100); //100 is the keycode for LMB
        MouseUpListeners.ExecuteIfBound();
    	return FReply::Handled().ReleaseMouseLock();
    }
    
    FReply SDasherWidget::HandleMouseDoubleClickEvent(const FGeometry& Geometry, const FPointerEvent& MouseEvent)
    {
    	if(CurrentlyUsingVectorInput)
    	{
    		CurrentlyUsingVectorInput = false;
    		return FReply::Handled();
    	}
    	DasherMainInterface->KeyUp(FDateTime::Now().GetSecond() + FDateTime::Now().GetMillisecond(), 100); //100 is the keycode for LMB
    	return FReply::Handled();
    }
    
    //Set in the HandleMouseMoveEvent or via Set InputVector
    //See tick for geometry things that could be use to modify this.
    FVector2D SDasherWidget::GetCursorPosition()
    {
    	return CursorPosition;
    }
    
    bool SDasherWidget::GetScreenCoords(screenint& iX, screenint& iY, Dasher::CDasherView* pView)
    {
    	const FVector2D Position = GetCursorPosition();
    	
    	iX = Position.X;
    	iY = Position.Y;
    
    	return true;
    }
    
    void SDasherWidget::InputVector(const FVector2D InputVector)
    {
    	if (!CurrentlyUsingVectorInput) return;
    	CursorPosition = DasherMainInterface->ConvertDasher2Screen(Dasher::CDasherModel::ORIGIN_X, Dasher::CDasherModel::ORIGIN_Y)
    					+ InputVector * FVector2D(1.0f,-1.0f) * (GetHeight() / 2);
    }
    
    void SDasherWidget::InputButton(bool Pressed)
    {
    	CurrentlyUsingVectorInput = true;
    	if(Pressed)
    	{
    		DasherMainInterface->KeyDown(FDateTime::Now().GetSecond() + FDateTime::Now().GetMillisecond(), 100); //100 is the keycode for LMB	
    	}
    	else {
    		DasherMainInterface->KeyUp(FDateTime::Now().GetSecond() + FDateTime::Now().GetMillisecond(), 100); //100 is the keycode for LMB
    	}
    }
    
    //The construction of the Dasher Widget, Dasher parameters are set here, a function to set them outside is not provided, but can be easily implemented
    void SDasherWidget::Construct(const FArguments& InArgs)
    {	
    	//Initial resize, needed for setup
    	Width = InArgs._width;
    	Height = InArgs._height;
    	resize(Width, Height);
    
    	//initialize the font measuring service.
    	FontMeasureService = FSlateApplication::Get().GetRenderer()->GetFontMeasureService();
    
    	//Setting up Dasher
    	static Dasher::XMLErrorDisplay display;
        Dasher::XmlSettingsStore* Settings = new Dasher::XmlSettingsStore("Settings.xml", &display); //Gets deleted somewhere else
        Settings->Load();
    	Settings->Save();
        DasherMainInterface = MakeShared<Dasher::DasherInterface>(Settings);
    	DasherMainInterface->SetDefaultInputDevice(this);
    	//change dasher parameters
    	DasherMainInterface->SetBoolParameter(BP_AUTO_SPEEDCONTROL, false);  //Auto Speed Control
    	DasherMainInterface->SetLongParameter(LP_DASHER_FONTSIZE, 18);	
    	DasherMainInterface->SetLongParameter(LP_MAX_BITRATE, 400);			//Maximum Speed
    	//DasherMainInterface->SetStringParameter(SP_INPUT_FILTER, "Stylus Control");	//On Hold
    	DasherMainInterface->SetStringParameter(SP_ALPHABET_ID, "German without punctuation");
    	DasherMainInterface->SetLongParameter(LP_MIN_NODE_SIZE, 15);
    
    	DasherMainInterface->SetScreen(this);
    	DasherMainInterface->SetBuffer(0);
    
    	DasherMainInterface->SetCharEnteredCallback([this](FString Char, FString Buffer){CharacterEntered.ExecuteIfBound(Char, Buffer);});
    	DasherMainInterface->SetCharDeletedCallback([this](FString Char, FString Buffer){CharacterDeleted.ExecuteIfBound(Char, Buffer);});
    
    	//Set up the Event Handlers for Mouse Movement etc.
    	SetOnMouseMove(FPointerEventHandler::CreateLambda([this](const FGeometry& Geometry, const FPointerEvent& MouseEvent) {return HandleMouseMoveEvent(Geometry, MouseEvent) ; }));
    	SetOnMouseButtonDown(FPointerEventHandler::CreateLambda([this](const FGeometry& Geometry, const FPointerEvent& MouseEvent) {return HandleMouseDownEvent(Geometry, MouseEvent); }));
    	SetOnMouseButtonUp(FPointerEventHandler::CreateLambda([this](const FGeometry& Geometry, const FPointerEvent& MouseEvent) {return HandleMouseUpEvent(Geometry, MouseEvent); }));
    	SetOnMouseDoubleClick(FPointerEventHandler::CreateLambda([this](const FGeometry& Geometry, const FPointerEvent& MouseEvent) {return HandleMouseDoubleClickEvent(Geometry, MouseEvent); })); //We treat a double click of the mouse as a lift of the mouse button.
        //You could add Slate Code here for child slots etc.
    }
    
    void SDasherWidget::SetBoolParamter(FString ParameterName, bool Value)
    {
    	for(Dasher::Settings::bp_table Setting : Dasher::Settings::boolparamtable)
    	{
    		if(FString(Setting.regName).Compare(ParameterName, ESearchCase::IgnoreCase))
    		{
    			DasherMainInterface->SetBoolParameter(Setting.key, Value);
    			return;
    		}
    	}
    }
    
    void SDasherWidget::SetLongParamter(FString ParameterName, int64 Value)
    {
    	for(Dasher::Settings::bp_table Setting : Dasher::Settings::boolparamtable)
    	{
    		if(FString(Setting.regName).Compare(ParameterName, ESearchCase::IgnoreCase))
    		{
    			DasherMainInterface->SetLongParameter(Setting.key, Value);
    			return;
    		}
    	}
    }
    
    void SDasherWidget::SetStringParamter(FString ParameterName, FString Value)
    {
    	for(Dasher::Settings::bp_table Setting : Dasher::Settings::boolparamtable)
    	{
    		if(FString(Setting.regName).Compare(ParameterName, ESearchCase::IgnoreCase))
    		{
    			DasherMainInterface->SetStringParameter(Setting.key, TCHAR_TO_UTF8(*Value));
    			return;
    		}
    	}
    }
    
    //Set the colour Scheme for dasher
    void SDasherWidget::SetColourScheme(const Dasher::CColourIO::ColourInfo* pcolours) {
    	ColorPalette = pcolours;
    }
    
    //paints our stuff, then lets compoundwidget (super::) draw its stuff
    //This draws from bottom to top rectangles->lines->labels, this is enough for our use, but for more complex scenarios a proper layering system might have to be implemented
    int32 SDasherWidget::OnPaint(const FPaintArgs& Args, const FGeometry& AllottedGeometry, const FSlateRect& MyClippingRect, FSlateWindowElementList& OutDrawElements, int32 LayerId, const FWidgetStyle& InWidgetStyle, bool bParentEnabled) const
    {
    	//this doesn't draw anything red, we just need a brush. Could probably find a better "empty" brush
    	auto MyBrush = FSlateColorBrush(FColor::Red);
    
    	FFilledRect* RectObject;
    	FWriting* WritingObject;
    	FPolyLine* LineObject;
    	FVector2D Size;
    	FString Text;
    	FSlateFontInfo Font;
    
    	TArray<TUniquePtr<DasherDrawGeometry>>& GeometryBuffer = *FrontBuffer;
    	for(TUniquePtr<DasherDrawGeometry>& GeneralObject : GeometryBuffer) {
    		switch(GeneralObject->Type)
    		{
    			case Rectangle:
    				RectObject = static_cast<FFilledRect*>(GeneralObject.Get());
    				Size = {FMath::Abs(RectObject->top.X - RectObject->bottom.X), FMath::Abs(RectObject->top.Y - RectObject->bottom.Y)};
    				FSlateDrawElement::MakeBox(OutDrawElements, LayerId++, AllottedGeometry.ToPaintGeometry(Size, FSlateLayoutTransform(1, RectObject->top)), &MyBrush, ESlateDrawEffect::None, RectObject->color); //actually adds the box to the geometry
    				break;
    			case Writing:
    				WritingObject = static_cast<FWriting*>(GeneralObject.Get());
    				Text = FString(UTF8_TO_TCHAR(WritingObject->label->m_strText.c_str()));
    
    		        Font = FCoreStyle::GetDefaultFontStyle("Roboto", WritingObject->size, FFontOutlineSettings::NoOutline); //get the font
    				FSlateDrawElement::MakeText(OutDrawElements, LayerId++, AllottedGeometry.ToPaintGeometry(FSlateLayoutTransform(1, FVector2D(WritingObject->pos.X, WritingObject->pos.Y))), Text , Font, ESlateDrawEffect::None, WritingObject->color);
    				break;
    			case PolyLine:
    				LineObject = static_cast<FPolyLine*>(GeneralObject.Get());
    				FSlateDrawElement::MakeLines(OutDrawElements, LayerId++, AllottedGeometry.ToPaintGeometry(), LineObject->points, ESlateDrawEffect::None, LineObject->color, true, LineObject->linewidth);
    				break;
    			default: break;
    		}
    	}
    
    	return SCompoundWidget::OnPaint(Args, AllottedGeometry, MyClippingRect, OutDrawElements, LayerId, InWidgetStyle,  bParentEnabled); //call the parent onPaint
    }
    
    //The tick function, we tick dasher in it and update the screen size for dasher
    void SDasherWidget::Tick(const FGeometry& AllotedGeometry, const double InCurrentTime, const float InDeltaTime) {
    	//don't tick in the editor
    	if (!IsEditor) {
    		SCompoundWidget::Tick(AllotedGeometry, InCurrentTime, InDeltaTime);
    
    		DasherMainInterface->Tick(static_cast<unsigned long>(InCurrentTime * 1000.0)); //we need to provide ticks in milliseconds
    
    
    		//This probably doesn't have to be done every tick, but it does not seem to have a huge hit on performance
            const FGeometry Geometry = GetTickSpaceGeometry();
            const FIntPoint AbsoluteSize = Geometry.Size.IntPoint();
    		if (Width != AbsoluteSize.X || Height != AbsoluteSize.Y) {
    			Width = AbsoluteSize.X;
    			Height = AbsoluteSize.Y;
    			resize(Width, Height);
    			//tell dasher we resized the screen, but only if there's actually a screen
    			if (Width && Height) DasherMainInterface->ScreenResized(this);
    		};
    	}
    }
    
    std::pair<SDasherWidget::screenint, SDasherWidget::screenint> SDasherWidget::TextSize(CDasherScreen::Label* Label, unsigned Size)
    {
    	const FSlateFontInfo Font = FCoreStyle::GetDefaultFontStyle("Roboto", Size, FFontOutlineSettings::NoOutline); //get the font
    	const FVector2D TextSize = FontMeasureService->Measure(FString(UTF8_TO_TCHAR(Label->m_strText.c_str())), Font, 1); //get the real size of the text, using the fontmeasuring service
    	return {static_cast<screenint>(TextSize.X), static_cast<screenint>(TextSize.Y)};
    }
    
    //Double Buffers are rotated here.
    void SDasherWidget::Display() {
    	std::swap(FrontBuffer, BackBuffer);
    	BackBuffer->Empty();
    }
    
    
    //Functions for Drawing
    void SDasherWidget::DrawRectangle(Dasher::screenint x1, Dasher::screenint y1, Dasher::screenint x2, Dasher::screenint y2, int colour, int iOutlineColour, int iThickness)
    {
    	const FVector2D Top(x1, y1);
    	const FVector2D Bottom(x2, y2);
    	
    	FLinearColor RectColor;
    
    	if (ColorPalette) {
    		RectColor = FLinearColor(ColorPalette->Colors[colour].Red/255.0, ColorPalette->Colors[colour].Green / 255.0, ColorPalette->Colors[colour].Blue / 255.0);
    	}
    	else {
    		RectColor = FLinearColor::Blue;
    	}
    	
    	BackBuffer->Add(MakeUnique<FFilledRect>(Top, Bottom, RectColor));
    }
    
    void SDasherWidget::DrawString(CDasherScreen::Label* lab, screenint x1, screenint y1, unsigned int iSize, int colour) {
    	const FVector2D Pos(x1, y1);
    
    	FLinearColor TextColor;
    
    	if (ColorPalette) {
    		TextColor = FLinearColor(ColorPalette->Colors[colour].Red / 255.0, ColorPalette->Colors[colour].Green / 255.0, ColorPalette->Colors[colour].Blue / 255.0);
    	}
    	else {
    		TextColor = FLinearColor::Black;
    	}
    	
    	BackBuffer->Add(MakeUnique<FWriting>(lab, Pos, static_cast<int>(iSize), TextColor));
    }
    
    void SDasherWidget::Polyline(CDasherScreen::point* points, int number, int iwidth, int colour) {
    	
    	FLinearColor LinearColor;
    
    	if (ColorPalette) {
    		LinearColor = FLinearColor(ColorPalette->Colors[colour].Red / 255.0, ColorPalette->Colors[colour].Green / 255.0, ColorPalette->Colors[colour].Blue / 255.0);
    	}
    	else {
    		LinearColor = FLinearColor::Blue;
    	}
    
    	TArray<FVector2D> PointArray;
    	for (int i = 0; i < number; i++) {
    		FVector2D Point(points[i].x, points[i].y);
    		PointArray.Add(Point);
    	}
    	
    	BackBuffer->Add(MakeUnique<FPolyLine>(PointArray, static_cast<float>(iwidth), LinearColor));
    }
    
    //techincally polygons are just multiple polylines. Dasher doesn't actually draw polygons in our case.
    void SDasherWidget::Polygon(CDasherScreen::point* points, int number, int fillcolour, int outlinecolour, int iwidth) {
    	FLinearColor LinearColor;
    
    	if (ColorPalette) {
    		LinearColor = FLinearColor(ColorPalette->Colors[outlinecolour].Red / 255.0, ColorPalette->Colors[outlinecolour].Green / 255.0, ColorPalette->Colors[outlinecolour].Blue / 255.0);
    	}
    	else {
    		LinearColor = FLinearColor::Blue;
    	}
    
    	TArray<FVector2D> PointArray;
    	for (int i = 0; i < number; i++) {
    		FVector2D Point(points[i].x, points[i].y);
    		PointArray.Add(Point);
    	}
    	PointArray.Add(FVector2D(points[0].x, points[0].y));
    
    	BackBuffer->Add(MakeUnique<FPolyLine>(PointArray, static_cast<float>(iwidth), LinearColor));
    }
    
    //We pass through the contents of the dasher buffer
    FString SDasherWidget::GetBuffer() const
    {
    	return DasherMainInterface->GetBuffer();
    }
    
    void SDasherWidget::ResetBuffer()
    {
    	DasherMainInterface->ResetBuffer();
    }
    
    void SDasherWidget::StartTraining(FString PathToTextFile)
    {
    	DasherMainInterface->ImportTrainingFile(TCHAR_TO_UTF8(*FPaths::ConvertRelativePathToFull(PathToTextFile)));
    }
    
    // ++ We need to undefine this namespace after we finish creating the Slate widget
    #undef LOCTEXT_NAMESPACE
    
    END_SLATE_FUNCTION_BUILD_OPTIMIZATION