#include "MatrixInputWidget.h" #include "SlateOptMacros.h" #include "Widgets/Layout/SUniformGridPanel.h" #include "Widgets/Text/STextBlock.h" #include "Widgets/Input/SButton.h" #include "Widgets/Layout/SBox.h" #include "Widgets/Layout/SScrollBox.h" #include "Styling/AppStyle.h" BEGIN_SLATE_FUNCTION_BUILD_OPTIMIZATION void SMatrixInputWidget::Construct(const FArguments& InArgs) { Matrix = InArgs._Matrix; OnMatrixChanged = InArgs._OnMatrixChanged; // Create a grid panel for the matrix elements GridPanel = SNew(SGridPanel); // Create numeric entry boxes for each matrix element NumericEntryBoxes.SetNum(16); // 4x4 matrix // Add labels for rows and columns for (int32 Col = 0; Col < 4; ++Col) { GridPanel->AddSlot(Col + 1, 0) [ SNew(STextBlock) .Text(FText::Format(FText::FromString("Column {0}"), FText::AsNumber(Col))) .Margin(FMargin(5.0f)) ]; } for (int32 Row = 0; Row < 4; ++Row) { GridPanel->AddSlot(0, Row + 1) [ SNew(STextBlock) .Text(FText::Format(FText::FromString("Row {0}"), FText::AsNumber(Row))) .Margin(FMargin(5.0f)) ]; } // Add numeric entry boxes for each matrix element for (int32 Row = 0; Row < 4; ++Row) { for (int32 Col = 0; Col < 4; ++Col) { TSharedPtr> NumericEntryBox = CreateMatrixElementWidget(Row, Col); NumericEntryBoxes[Row * 4 + Col] = NumericEntryBox; GridPanel->AddSlot(Col + 1, Row + 1) [ SNew(SBox) .WidthOverride(80.0f) .Padding(FMargin(2.0f)) [ NumericEntryBox.ToSharedRef() ] ]; } } // Create buttons for common operations TSharedPtr ButtonPanel = SNew(SUniformGridPanel) .SlotPadding(FMargin(2.0f)); ButtonPanel->AddSlot(0, 0) [ SNew(SButton) .Text(FText::FromString("Reset to Identity")) .ToolTipText(FText::FromString("Reset the matrix to identity")) .OnClicked(FOnClicked::CreateLambda([this]() { ResetToIdentity(); return FReply::Handled(); })) ]; ButtonPanel->AddSlot(1, 0) [ SNew(SButton) .Text(FText::FromString("Set from Rotation")) .ToolTipText(FText::FromString("Set the matrix from rotation values (degrees)")) .OnClicked(FOnClicked::CreateLambda([this]() { SetFromEulerAngles(0.0f, 0.0f, 0.0f); return FReply::Handled(); })) ]; ButtonPanel->AddSlot(2, 0) [ SNew(SButton) .Text(FText::FromString("Set from Translation")) .ToolTipText(FText::FromString("Set the matrix from translation values")) .OnClicked(FOnClicked::CreateLambda([this]() { SetFromTranslation(FVector::ZeroVector); return FReply::Handled(); })) ]; // Main widget layout ChildSlot [ SNew(SVerticalBox) + SVerticalBox::Slot() .AutoHeight() .Padding(5.0f) [ SNew(STextBlock) .Text(FText::FromString("Matrix Input")) .Font(FCoreStyle::GetDefaultFontStyle("Bold", 14)) ] + SVerticalBox::Slot() .FillHeight(1.0f) .Padding(5.0f) [ SNew(SScrollBox) + SScrollBox::Slot() [ GridPanel.ToSharedRef() ] ] + SVerticalBox::Slot() .AutoHeight() .Padding(5.0f) [ ButtonPanel.ToSharedRef() ] ]; // Update the UI with the initial matrix value UpdateUI(); } void SMatrixInputWidget::SetMatrix(const FMatrix& InMatrix) { Matrix = InMatrix; UpdateUI(); // Notify listeners of the change if (OnMatrixChanged.IsBound()) { OnMatrixChanged.Execute(Matrix); } } FMatrix SMatrixInputWidget::GetMatrix() const { return Matrix; } void SMatrixInputWidget::ResetToIdentity() { SetMatrix(FMatrix::Identity); } void SMatrixInputWidget::SetFromEulerAngles(float Roll, float Pitch, float Yaw) { FRotator Rotator(Pitch, Yaw, Roll); FMatrix RotationMatrix = FRotationMatrix::Make(Rotator); SetMatrix(RotationMatrix); } void SMatrixInputWidget::SetFromTranslation(const FVector& Translation) { FMatrix TranslationMatrix = FMatrix::Identity; TranslationMatrix.SetOrigin(Translation); SetMatrix(TranslationMatrix); } void SMatrixInputWidget::SetFromTransform(const FTransform& Transform) { SetMatrix(Transform.ToMatrixWithScale()); } TSharedPtr> SMatrixInputWidget::CreateMatrixElementWidget(int32 Row, int32 Col) { return SNew(SNumericEntryBox) .Value_Lambda([this, Row, Col]() -> float { return Matrix.M[Row][Col]; }) .OnValueChanged(SNumericEntryBox::FOnValueChanged::CreateSP(this, &SMatrixInputWidget::OnMatrixElementChanged, Row, Col)) .AllowSpin(true) .Delta(0.1f) .MinValue(-10000.0f) .MaxValue(10000.0f) .MinSliderValue(-10.0f) .MaxSliderValue(10.0f); } void SMatrixInputWidget::OnMatrixElementChanged(float NewValue, int32 Row, int32 Col) { // Update the matrix element Matrix.M[Row][Col] = NewValue; // Notify listeners of the change if (OnMatrixChanged.IsBound()) { OnMatrixChanged.Execute(Matrix); } } void SMatrixInputWidget::UpdateUI() { // Update each numeric entry box with the current matrix values for (int32 Row = 0; Row < 4; ++Row) { for (int32 Col = 0; Col < 4; ++Col) { int32 Index = Row * 4 + Col; if (NumericEntryBoxes.IsValidIndex(Index) && NumericEntryBoxes[Index].IsValid()) { // In UE5.5.4, we need to rebuild the grid panel to update the value NumericEntryBoxes[Index] = CreateMatrixElementWidget(Row, Col); } } } } END_SLATE_FUNCTION_BUILD_OPTIMIZATION