Files
BallisticsDocs/Source/EasyBallisticsEditor/Private/EBJsonImportExportTool.cpp
T
2025-07-03 02:41:49 -07:00

596 lines
26 KiB
C++

// Copyright 2016 Mookie. All Rights Reserved.
#include "EBJsonImportExportTool.h"
#include "Widgets/Layout/SBorder.h"
#include "Widgets/Layout/SBox.h"
#include "Widgets/Layout/SScrollBox.h"
#include "Widgets/Text/STextBlock.h"
#include "Widgets/Input/SButton.h"
#include "Widgets/Layout/SUniformGridPanel.h"
#include "Framework/Application/SlateApplication.h"
#include "DesktopPlatformModule.h"
#include "Json.h"
#include "Engine/Engine.h"
#include "AssetToolsModule.h"
#include "ContentBrowserModule.h"
#include "IContentBrowserSingleton.h"
#include "Framework/Docking/TabManager.h"
#include "WorkspaceMenuStructure.h"
#include "WorkspaceMenuStructureModule.h"
#include "ToolMenus.h"
#include "HAL/IConsoleManager.h"
const FName FEBJsonImportExportTool::ImportExportTabName("EBJsonImportExport");
// Console command to open the tool
static FAutoConsoleCommand OpenJsonToolCommand(
TEXT("EasyBallistics.OpenJsonTool"),
TEXT("Opens the EasyBallistics JSON Import/Export tool"),
FConsoleCommandDelegate::CreateStatic(&FEBJsonImportExportTool::OpenImportExportWindow)
);
void SEBJsonImportExportTool::Construct(const FArguments& InArgs)
{
ChildSlot
[
SNew(SBorder)
.BorderImage(FAppStyle::GetBrush("ToolPanel.GroupBorder"))
[
SNew(SScrollBox)
+ SScrollBox::Slot()
[
SNew(SBox)
.Padding(10.0f)
[
SNew(SVerticalBox)
// Title
+ SVerticalBox::Slot()
.AutoHeight()
.Padding(0, 0, 0, 20)
[
SNew(STextBlock)
.Text(FText::FromString("EasyBallistics JSON Import/Export Tool"))
.Font(FCoreStyle::GetDefaultFontStyle("Bold", 16))
.Justification(ETextJustify::Center)
]
// Bullet Properties Section
+ SVerticalBox::Slot()
.AutoHeight()
.Padding(0, 0, 0, 15)
[
SNew(SBorder)
.BorderImage(FAppStyle::GetBrush("DetailsView.CategoryTop"))
.Padding(10)
[
SNew(SVerticalBox)
+ SVerticalBox::Slot()
.AutoHeight()
[
SNew(STextBlock)
.Text(FText::FromString("Bullet Properties"))
.Font(FCoreStyle::GetDefaultFontStyle("Bold", 14))
]
+ SVerticalBox::Slot()
.AutoHeight()
.Padding(0, 10, 0, 0)
[
SNew(SUniformGridPanel)
.SlotPadding(5)
+ SUniformGridPanel::Slot(0, 0)
[
SNew(SButton)
.Text(FText::FromString("Export Bullet Properties"))
.OnClicked(this, &SEBJsonImportExportTool::OnExportBulletPropertiesClicked)
]
+ SUniformGridPanel::Slot(1, 0)
[
SNew(SButton)
.Text(FText::FromString("Import Bullet Properties"))
.OnClicked(this, &SEBJsonImportExportTool::OnImportBulletPropertiesClicked)
]
]
]
]
// Material Response Section
+ SVerticalBox::Slot()
.AutoHeight()
.Padding(0, 0, 0, 15)
[
SNew(SBorder)
.BorderImage(FAppStyle::GetBrush("DetailsView.CategoryTop"))
.Padding(10)
[
SNew(SVerticalBox)
+ SVerticalBox::Slot()
.AutoHeight()
[
SNew(STextBlock)
.Text(FText::FromString("Material Response Maps"))
.Font(FCoreStyle::GetDefaultFontStyle("Bold", 14))
]
+ SVerticalBox::Slot()
.AutoHeight()
.Padding(0, 10, 0, 0)
[
SNew(SUniformGridPanel)
.SlotPadding(5)
+ SUniformGridPanel::Slot(0, 0)
[
SNew(SButton)
.Text(FText::FromString("Export Material Response"))
.OnClicked(this, &SEBJsonImportExportTool::OnExportMaterialResponseClicked)
]
+ SUniformGridPanel::Slot(1, 0)
[
SNew(SButton)
.Text(FText::FromString("Import Material Response"))
.OnClicked(this, &SEBJsonImportExportTool::OnImportMaterialResponseClicked)
]
]
]
]
// Status Section
+ SVerticalBox::Slot()
.AutoHeight()
.Padding(0, 20, 0, 0)
[
SNew(SBorder)
.BorderImage(FAppStyle::GetBrush("DetailsView.CategoryBottom"))
.Padding(10)
[
SAssignNew(StatusText, STextBlock)
.Text(FText::FromString("Ready"))
.AutoWrapText(true)
]
]
]
]
]
];
}
FReply SEBJsonImportExportTool::OnExportBulletPropertiesClicked()
{
FString Filename;
if (SaveFileDialog("Export Bullet Properties", "", "JSON Files (*.json)|*.json", Filename))
{
// For demo purposes, create default bullet properties
FMathematicalBulletProperties DefaultProperties;
TSharedPtr<FJsonObject> JsonObject = BulletPropertiesToJson(DefaultProperties);
FString OutputString;
TSharedRef<TJsonWriter<>> Writer = TJsonWriterFactory<>::Create(&OutputString);
FJsonSerializer::Serialize(JsonObject.ToSharedRef(), Writer);
if (FFileHelper::SaveStringToFile(OutputString, *Filename))
{
UpdateStatus(FString::Printf(TEXT("Successfully exported bullet properties to: %s"), *Filename));
}
else
{
UpdateStatus(TEXT("Failed to save bullet properties file."));
}
}
return FReply::Handled();
}
FReply SEBJsonImportExportTool::OnImportBulletPropertiesClicked()
{
FString Filename;
if (OpenFileDialog("Import Bullet Properties", "", "JSON Files (*.json)|*.json", Filename))
{
FString FileContent;
if (FFileHelper::LoadFileToString(FileContent, *Filename))
{
TSharedPtr<FJsonObject> JsonObject;
TSharedRef<TJsonReader<>> Reader = TJsonReaderFactory<>::Create(FileContent);
if (FJsonSerializer::Deserialize(Reader, JsonObject) && JsonObject.IsValid())
{
FMathematicalBulletProperties ImportedProperties;
if (JsonToBulletProperties(JsonObject, ImportedProperties))
{
UpdateStatus(FString::Printf(TEXT("Successfully imported bullet properties from: %s"), *Filename));
// Here you would typically create a new asset or update an existing one
}
else
{
UpdateStatus(TEXT("Failed to parse bullet properties from JSON."));
}
}
else
{
UpdateStatus(TEXT("Failed to parse JSON file."));
}
}
else
{
UpdateStatus(TEXT("Failed to load file."));
}
}
return FReply::Handled();
}
FReply SEBJsonImportExportTool::OnExportMaterialResponseClicked()
{
FString Filename;
if (SaveFileDialog("Export Material Response", "", "JSON Files (*.json)|*.json", Filename))
{
// For demo purposes, create default material response
FEBMaterialResponseMapEntry DefaultEntry;
TSharedPtr<FJsonObject> JsonObject = MaterialResponseToJson(DefaultEntry);
FString OutputString;
TSharedRef<TJsonWriter<>> Writer = TJsonWriterFactory<>::Create(&OutputString);
FJsonSerializer::Serialize(JsonObject.ToSharedRef(), Writer);
if (FFileHelper::SaveStringToFile(OutputString, *Filename))
{
UpdateStatus(FString::Printf(TEXT("Successfully exported material response to: %s"), *Filename));
}
else
{
UpdateStatus(TEXT("Failed to save material response file."));
}
}
return FReply::Handled();
}
FReply SEBJsonImportExportTool::OnImportMaterialResponseClicked()
{
FString Filename;
if (OpenFileDialog("Import Material Response", "", "JSON Files (*.json)|*.json", Filename))
{
FString FileContent;
if (FFileHelper::LoadFileToString(FileContent, *Filename))
{
TSharedPtr<FJsonObject> JsonObject;
TSharedRef<TJsonReader<>> Reader = TJsonReaderFactory<>::Create(FileContent);
if (FJsonSerializer::Deserialize(Reader, JsonObject) && JsonObject.IsValid())
{
FEBMaterialResponseMapEntry ImportedEntry;
if (JsonToMaterialResponse(JsonObject, ImportedEntry))
{
UpdateStatus(FString::Printf(TEXT("Successfully imported material response from: %s"), *Filename));
// Here you would typically create a new asset or update an existing one
}
else
{
UpdateStatus(TEXT("Failed to parse material response from JSON."));
}
}
else
{
UpdateStatus(TEXT("Failed to parse JSON file."));
}
}
else
{
UpdateStatus(TEXT("Failed to load file."));
}
}
return FReply::Handled();
}
bool SEBJsonImportExportTool::OpenFileDialog(const FString& DialogTitle, const FString& DefaultPath, const FString& FileTypes, FString& OutFilename)
{
IDesktopPlatform* DesktopPlatform = FDesktopPlatformModule::Get();
if (DesktopPlatform)
{
TArray<FString> OutFilenames;
bool bOpened = DesktopPlatform->OpenFileDialog(
FSlateApplication::Get().FindBestParentWindowHandleForDialogs(nullptr),
DialogTitle,
DefaultPath,
TEXT(""),
FileTypes,
EFileDialogFlags::None,
OutFilenames
);
if (bOpened && OutFilenames.Num() > 0)
{
OutFilename = OutFilenames[0];
return true;
}
}
return false;
}
bool SEBJsonImportExportTool::SaveFileDialog(const FString& DialogTitle, const FString& DefaultPath, const FString& FileTypes, FString& OutFilename)
{
IDesktopPlatform* DesktopPlatform = FDesktopPlatformModule::Get();
if (DesktopPlatform)
{
TArray<FString> OutFilenames;
bool bOpened = DesktopPlatform->SaveFileDialog(
FSlateApplication::Get().FindBestParentWindowHandleForDialogs(nullptr),
DialogTitle,
DefaultPath,
TEXT(""),
FileTypes,
EFileDialogFlags::None,
OutFilenames
);
if (bOpened && OutFilenames.Num() > 0)
{
OutFilename = OutFilenames[0];
return true;
}
}
return false;
}
TSharedPtr<FJsonObject> SEBJsonImportExportTool::BulletPropertiesToJson(const FMathematicalBulletProperties& Properties)
{
TSharedPtr<FJsonObject> JsonObject = MakeShareable(new FJsonObject);
// Basic Properties
JsonObject->SetNumberField("GrainWeight", Properties.GrainWeight);
JsonObject->SetNumberField("DiameterInches", Properties.DiameterInches);
JsonObject->SetNumberField("LengthInches", Properties.LengthInches);
JsonObject->SetNumberField("BulletType", static_cast<int32>(Properties.BulletType));
JsonObject->SetNumberField("BulletMaterial", static_cast<int32>(Properties.BulletMaterial));
// Ballistics
JsonObject->SetNumberField("BallisticCoefficientG1", Properties.BallisticCoefficientG1);
JsonObject->SetNumberField("BallisticCoefficientG7", Properties.BallisticCoefficientG7);
JsonObject->SetBoolField("UseG7Model", Properties.UseG7Model);
JsonObject->SetNumberField("SectionalDensity", Properties.SectionalDensity);
// Penetration
JsonObject->SetNumberField("BulletHardness", Properties.BulletHardness);
JsonObject->SetNumberField("PenetrationEnergyThreshold", Properties.PenetrationEnergyThreshold);
JsonObject->SetNumberField("ExpansionVelocityThreshold", Properties.ExpansionVelocityThreshold);
JsonObject->SetNumberField("MaxExpansionMultiplier", Properties.MaxExpansionMultiplier);
return JsonObject;
}
bool SEBJsonImportExportTool::JsonToBulletProperties(const TSharedPtr<FJsonObject>& JsonObject, FMathematicalBulletProperties& OutProperties)
{
if (!JsonObject.IsValid())
{
return false;
}
// Basic Properties
OutProperties.GrainWeight = JsonObject->GetNumberField(TEXT("GrainWeight"));
OutProperties.DiameterInches = JsonObject->GetNumberField(TEXT("DiameterInches"));
OutProperties.LengthInches = JsonObject->GetNumberField(TEXT("LengthInches"));
OutProperties.BulletType = static_cast<EBulletType>(JsonObject->GetIntegerField(TEXT("BulletType")));
OutProperties.BulletMaterial = static_cast<EBulletMaterial>(JsonObject->GetIntegerField(TEXT("BulletMaterial")));
// Ballistics
OutProperties.BallisticCoefficientG1 = JsonObject->GetNumberField(TEXT("BallisticCoefficientG1"));
OutProperties.BallisticCoefficientG7 = JsonObject->GetNumberField(TEXT("BallisticCoefficientG7"));
OutProperties.UseG7Model = JsonObject->GetBoolField(TEXT("UseG7Model"));
OutProperties.SectionalDensity = JsonObject->GetNumberField(TEXT("SectionalDensity"));
// Penetration
OutProperties.BulletHardness = JsonObject->GetNumberField(TEXT("BulletHardness"));
OutProperties.PenetrationEnergyThreshold = JsonObject->GetNumberField(TEXT("PenetrationEnergyThreshold"));
OutProperties.ExpansionVelocityThreshold = JsonObject->GetNumberField(TEXT("ExpansionVelocityThreshold"));
OutProperties.MaxExpansionMultiplier = JsonObject->GetNumberField(TEXT("MaxExpansionMultiplier"));
return true;
}
TSharedPtr<FJsonObject> SEBJsonImportExportTool::MaterialResponseToJson(const FEBMaterialResponseMapEntry& Entry)
{
TSharedPtr<FJsonObject> JsonObject = MakeShareable(new FJsonObject);
// Artistic Properties
JsonObject->SetNumberField("PenTraceType", static_cast<int32>(Entry.PenTraceType));
JsonObject->SetBoolField("NeverPenetrate", Entry.NeverPenetrate);
JsonObject->SetNumberField("PenetrationDepthMultiplier", Entry.PenetrationDepthMultiplier);
JsonObject->SetNumberField("PenetrationNormalization", Entry.PenetrationNormalization);
JsonObject->SetNumberField("PenetrationNormalizationGrazing", Entry.PenetrationNormalizationGrazing);
JsonObject->SetNumberField("PenetrationEntryAngleSpread", Entry.PenetrationEntryAngleSpread);
JsonObject->SetNumberField("PenetrationExitAngleSpread", Entry.PenetrationExitAngleSpread);
JsonObject->SetBoolField("NeverRicochet", Entry.NeverRicochet);
JsonObject->SetNumberField("RicochetProbabilityMultiplier", Entry.RicochetProbabilityMultiplier);
JsonObject->SetNumberField("RicochetRestitution", Entry.RicochetRestitution);
JsonObject->SetNumberField("RicochetRestitutionInfluence", Entry.RicochetRestitutionInfluence);
JsonObject->SetNumberField("RicochetFriction", Entry.RicochetFriction);
JsonObject->SetNumberField("RicochetFrictionInfluence", Entry.RicochetFrictionInfluence);
JsonObject->SetNumberField("RicochetSpread", Entry.RicochetSpread);
// Spalling Properties
JsonObject->SetBoolField("EnableSpalling", Entry.EnableSpalling);
JsonObject->SetNumberField("SpallVelocityThreshold", Entry.SpallVelocityThreshold);
JsonObject->SetNumberField("SpallFragmentCount", Entry.SpallFragmentCount);
JsonObject->SetNumberField("SpallSpreadAngle", Entry.SpallSpreadAngle);
JsonObject->SetNumberField("SpallVelocityMultiplier", Entry.SpallVelocityMultiplier);
JsonObject->SetNumberField("SpallMassMultiplier", Entry.SpallMassMultiplier);
// Mathematical Properties
JsonObject->SetBoolField("UseMathematicalProperties", Entry.UseMathematicalProperties);
if (Entry.UseMathematicalProperties)
{
TSharedPtr<FJsonObject> MathProps = MaterialPropertiesToJson(Entry.MathematicalProperties);
JsonObject->SetObjectField("MathematicalProperties", MathProps);
}
return JsonObject;
}
bool SEBJsonImportExportTool::JsonToMaterialResponse(const TSharedPtr<FJsonObject>& JsonObject, FEBMaterialResponseMapEntry& OutEntry)
{
if (!JsonObject.IsValid())
{
return false;
}
// Artistic Properties
OutEntry.PenTraceType = static_cast<EPenTraceType>(JsonObject->GetIntegerField(TEXT("PenTraceType")));
OutEntry.NeverPenetrate = JsonObject->GetBoolField(TEXT("NeverPenetrate"));
OutEntry.PenetrationDepthMultiplier = JsonObject->GetNumberField(TEXT("PenetrationDepthMultiplier"));
OutEntry.PenetrationNormalization = JsonObject->GetNumberField(TEXT("PenetrationNormalization"));
OutEntry.PenetrationNormalizationGrazing = JsonObject->GetNumberField(TEXT("PenetrationNormalizationGrazing"));
OutEntry.PenetrationEntryAngleSpread = JsonObject->GetNumberField(TEXT("PenetrationEntryAngleSpread"));
OutEntry.PenetrationExitAngleSpread = JsonObject->GetNumberField(TEXT("PenetrationExitAngleSpread"));
OutEntry.NeverRicochet = JsonObject->GetBoolField(TEXT("NeverRicochet"));
OutEntry.RicochetProbabilityMultiplier = JsonObject->GetNumberField(TEXT("RicochetProbabilityMultiplier"));
OutEntry.RicochetRestitution = JsonObject->GetNumberField(TEXT("RicochetRestitution"));
OutEntry.RicochetRestitutionInfluence = JsonObject->GetNumberField(TEXT("RicochetRestitutionInfluence"));
OutEntry.RicochetFriction = JsonObject->GetNumberField(TEXT("RicochetFriction"));
OutEntry.RicochetFrictionInfluence = JsonObject->GetNumberField(TEXT("RicochetFrictionInfluence"));
OutEntry.RicochetSpread = JsonObject->GetNumberField(TEXT("RicochetSpread"));
// Spalling Properties
OutEntry.EnableSpalling = JsonObject->GetBoolField(TEXT("EnableSpalling"));
OutEntry.SpallVelocityThreshold = JsonObject->GetNumberField(TEXT("SpallVelocityThreshold"));
OutEntry.SpallFragmentCount = JsonObject->GetIntegerField(TEXT("SpallFragmentCount"));
OutEntry.SpallSpreadAngle = JsonObject->GetNumberField(TEXT("SpallSpreadAngle"));
OutEntry.SpallVelocityMultiplier = JsonObject->GetNumberField(TEXT("SpallVelocityMultiplier"));
OutEntry.SpallMassMultiplier = JsonObject->GetNumberField(TEXT("SpallMassMultiplier"));
// Mathematical Properties
OutEntry.UseMathematicalProperties = JsonObject->GetBoolField(TEXT("UseMathematicalProperties"));
if (OutEntry.UseMathematicalProperties)
{
const TSharedPtr<FJsonObject>* MathPropsPtr;
if (JsonObject->TryGetObjectField(TEXT("MathematicalProperties"), MathPropsPtr))
{
JsonToMaterialProperties(*MathPropsPtr, OutEntry.MathematicalProperties);
}
}
return true;
}
TSharedPtr<FJsonObject> SEBJsonImportExportTool::MaterialPropertiesToJson(const FMathematicalMaterialProperties& Properties)
{
TSharedPtr<FJsonObject> JsonObject = MakeShareable(new FJsonObject);
// Material Properties
JsonObject->SetNumberField("DensityGPerCm3", Properties.DensityGPerCm3);
JsonObject->SetNumberField("MaterialHardness", Properties.MaterialHardness);
JsonObject->SetNumberField("TensileStrengthMPa", Properties.TensileStrengthMPa);
JsonObject->SetNumberField("YieldStrengthMPa", Properties.YieldStrengthMPa);
JsonObject->SetNumberField("ElasticModulusGPa", Properties.ElasticModulusGPa);
// Ballistic Properties
JsonObject->SetNumberField("BallisticLimitVelocity", Properties.BallisticLimitVelocity);
JsonObject->SetNumberField("PerforationCoefficient", Properties.PerforationCoefficient);
JsonObject->SetNumberField("EnergyAbsorptionCoefficient", Properties.EnergyAbsorptionCoefficient);
// Spalling Properties
JsonObject->SetBoolField("EnableMathematicalSpalling", Properties.EnableMathematicalSpalling);
JsonObject->SetNumberField("SpallStrengthMPa", Properties.SpallStrengthMPa);
JsonObject->SetNumberField("CriticalStressFactor", Properties.CriticalStressFactor);
JsonObject->SetNumberField("FragmentVelocityEfficiency", Properties.FragmentVelocityEfficiency);
JsonObject->SetNumberField("AverageFragmentMassRatio", Properties.AverageFragmentMassRatio);
JsonObject->SetNumberField("FragmentSizeExponent", Properties.FragmentSizeExponent);
JsonObject->SetNumberField("MaxFragmentDensity", Properties.MaxFragmentDensity);
return JsonObject;
}
bool SEBJsonImportExportTool::JsonToMaterialProperties(const TSharedPtr<FJsonObject>& JsonObject, FMathematicalMaterialProperties& OutProperties)
{
if (!JsonObject.IsValid())
{
return false;
}
// Material Properties
OutProperties.DensityGPerCm3 = JsonObject->GetNumberField(TEXT("DensityGPerCm3"));
OutProperties.MaterialHardness = JsonObject->GetNumberField(TEXT("MaterialHardness"));
OutProperties.TensileStrengthMPa = JsonObject->GetNumberField(TEXT("TensileStrengthMPa"));
OutProperties.YieldStrengthMPa = JsonObject->GetNumberField(TEXT("YieldStrengthMPa"));
OutProperties.ElasticModulusGPa = JsonObject->GetNumberField(TEXT("ElasticModulusGPa"));
// Ballistic Properties
OutProperties.BallisticLimitVelocity = JsonObject->GetNumberField(TEXT("BallisticLimitVelocity"));
OutProperties.PerforationCoefficient = JsonObject->GetNumberField(TEXT("PerforationCoefficient"));
OutProperties.EnergyAbsorptionCoefficient = JsonObject->GetNumberField(TEXT("EnergyAbsorptionCoefficient"));
// Spalling Properties
OutProperties.EnableMathematicalSpalling = JsonObject->GetBoolField(TEXT("EnableMathematicalSpalling"));
OutProperties.SpallStrengthMPa = JsonObject->GetNumberField(TEXT("SpallStrengthMPa"));
OutProperties.CriticalStressFactor = JsonObject->GetNumberField(TEXT("CriticalStressFactor"));
OutProperties.FragmentVelocityEfficiency = JsonObject->GetNumberField(TEXT("FragmentVelocityEfficiency"));
OutProperties.AverageFragmentMassRatio = JsonObject->GetNumberField(TEXT("AverageFragmentMassRatio"));
OutProperties.FragmentSizeExponent = JsonObject->GetNumberField(TEXT("FragmentSizeExponent"));
OutProperties.MaxFragmentDensity = JsonObject->GetNumberField(TEXT("MaxFragmentDensity"));
return true;
}
void SEBJsonImportExportTool::UpdateStatus(const FString& Message)
{
if (StatusText.IsValid())
{
StatusText->SetText(FText::FromString(Message));
}
}
// FEBJsonImportExportTool implementation
void FEBJsonImportExportTool::RegisterMenus()
{
// Register the tab spawner
FGlobalTabmanager::Get()->RegisterNomadTabSpawner(ImportExportTabName, FOnSpawnTab::CreateStatic(&FEBJsonImportExportTool::OnSpawnImportExportTab))
.SetDisplayName(NSLOCTEXT("EasyBallisticsEditor", "ImportExportTabTitle", "Ballistics JSON Import/Export"))
.SetMenuType(ETabSpawnerMenuType::Hidden);
// Add to main menu bar under Tools
UToolMenus* ToolMenus = UToolMenus::Get();
{
UToolMenu* MainMenu = UToolMenus::Get()->ExtendMenu("LevelEditor.MainMenu.Tools");
{
FToolMenuSection& Section = MainMenu->FindOrAddSection("Programming");
Section.AddMenuEntry(
"OpenEBJsonImportExport",
NSLOCTEXT("EasyBallisticsEditor", "OpenEBJsonImportExport", "Ballistics JSON Import/Export"),
NSLOCTEXT("EasyBallisticsEditor", "OpenEBJsonImportExportTooltip", "Open the Ballistics JSON Import/Export tool"),
FSlateIcon(),
FUIAction(FExecuteAction::CreateStatic(&FEBJsonImportExportTool::OpenImportExportWindow))
);
}
}
}
void FEBJsonImportExportTool::OpenImportExportWindow()
{
// Ensure the tab spawner is registered
if (!FGlobalTabmanager::Get()->HasTabSpawner(ImportExportTabName))
{
FGlobalTabmanager::Get()->RegisterNomadTabSpawner(ImportExportTabName, FOnSpawnTab::CreateStatic(&FEBJsonImportExportTool::OnSpawnImportExportTab))
.SetDisplayName(NSLOCTEXT("EasyBallisticsEditor", "ImportExportTabTitle", "Ballistics JSON Import/Export"))
.SetMenuType(ETabSpawnerMenuType::Hidden);
}
FGlobalTabmanager::Get()->TryInvokeTab(ImportExportTabName);
}
void FEBJsonImportExportTool::UnregisterMenus()
{
if (FGlobalTabmanager::Get()->HasTabSpawner(ImportExportTabName))
{
FGlobalTabmanager::Get()->UnregisterNomadTabSpawner(ImportExportTabName);
}
}
TSharedRef<SDockTab> FEBJsonImportExportTool::OnSpawnImportExportTab(const FSpawnTabArgs& SpawnTabArgs)
{
return SNew(SDockTab)
.TabRole(ETabRole::NomadTab)
[
SNew(SEBJsonImportExportTool)
];
}