| 34 | } |
| 35 | |
| 36 | void FMjEditorStyle::Initialize() |
| 37 | { |
| 38 | if (StyleInstance.IsValid()) |
| 39 | return; |
| 40 | |
| 41 | StyleInstance = MakeShareable(new FSlateStyleSet(GetStyleSetName())); |
| 42 | |
| 43 | // Resolve the plugin's Resources directory for custom icon PNGs |
| 44 | FString PluginBaseDir = FPaths::Combine( |
| 45 | FPaths::ProjectPluginsDir(), TEXT("UnrealRoboticsLab")); |
| 46 | FString IconsDir = PluginBaseDir / TEXT("Resources") / TEXT("Icons"); |
| 47 | |
| 48 | StyleInstance->SetContentRoot(IconsDir); |
| 49 | |
| 50 | // Icon size for component tree |
| 51 | const FVector2D IconSize(16.0f, 16.0f); |
| 52 | |
| 53 | // Helper lambda: register icon if PNG exists, otherwise use an existing engine brush |
| 54 | auto RegisterIcon = [&](const FName& PropertyName, const FString& PngName, const FName& FallbackBrush) { |
| 55 | FString PngPath = IconsDir / PngName; |
| 56 | if (FPaths::FileExists(PngPath)) |
| 57 | { |
| 58 | StyleInstance->Set(PropertyName, new FSlateImageBrush(PngPath, IconSize)); |
| 59 | } |
| 60 | else |
| 61 | { |
| 62 | // Copy the existing brush from the engine's style set |
| 63 | const FSlateBrush* Existing = FAppStyle::Get().GetBrush(FallbackBrush); |
| 64 | if (Existing && Existing != FAppStyle::GetNoBrush()) |
| 65 | { |
| 66 | StyleInstance->Set(PropertyName, new FSlateBrush(*Existing)); |
| 67 | } |
| 68 | } |
| 69 | }; |
| 70 | |
| 71 | // Register class icons for each MuJoCo component type. |
| 72 | // UE looks for "ClassIcon.<ClassName>" in registered style sets. |
| 73 | // If custom PNGs are placed in Resources/Icons/, they will be used. |
| 74 | // Otherwise, built-in editor icons serve as placeholders. |
| 75 | RegisterIcon("ClassIcon.MjBody", TEXT("MjBody.png"), "ClassIcon.SceneComponent"); |
| 76 | RegisterIcon("ClassIcon.MjWorldBody", TEXT("MjWorldBody.png"), "ClassIcon.SceneComponent"); |
| 77 | RegisterIcon("ClassIcon.MjGeom", TEXT("MjGeom.png"), "ClassIcon.StaticMeshComponent"); |
| 78 | RegisterIcon("ClassIcon.MjBox", TEXT("MjBox.png"), "ClassIcon.StaticMeshComponent"); |
| 79 | RegisterIcon("ClassIcon.MjSphere", TEXT("MjSphere.png"), "ClassIcon.StaticMeshComponent"); |
| 80 | RegisterIcon("ClassIcon.MjCylinder", TEXT("MjCylinder.png"), "ClassIcon.StaticMeshComponent"); |
| 81 | RegisterIcon("ClassIcon.MjCapsule", TEXT("MjCapsule.png"), "ClassIcon.StaticMeshComponent"); |
| 82 | RegisterIcon("ClassIcon.MjMeshGeom", TEXT("MjMeshGeom.png"), "ClassIcon.StaticMeshComponent"); |
| 83 | RegisterIcon("ClassIcon.MjFlexcomp", TEXT("MjFlexcomp.png"), "ClassIcon.SkeletalMeshComponent"); |
| 84 | RegisterIcon("ClassIcon.MjHingeJoint", TEXT("MjHingeJoint.png"), "ClassIcon.PhysicsConstraintComponent"); |
| 85 | RegisterIcon("ClassIcon.MjSlideJoint", TEXT("MjSlideJoint.png"), "ClassIcon.PhysicsConstraintComponent"); |
| 86 | RegisterIcon("ClassIcon.MjBallJoint", TEXT("MjBallJoint.png"), "ClassIcon.PhysicsConstraintComponent"); |
| 87 | RegisterIcon("ClassIcon.MjFreeJoint", TEXT("MjFreeJoint.png"), "ClassIcon.PhysicsConstraintComponent"); |
| 88 | RegisterIcon("ClassIcon.MjJoint", TEXT("MjJoint.png"), "ClassIcon.PhysicsConstraintComponent"); |
| 89 | RegisterIcon("ClassIcon.MjSensor", TEXT("MjSensor.png"), "ClassIcon.SphereComponent"); |
| 90 | RegisterIcon("ClassIcon.MjActuator", TEXT("MjActuator.png"), "ClassIcon.MovementComponent"); |
| 91 | RegisterIcon("ClassIcon.MjDefault", TEXT("MjDefault.png"), "ClassIcon.BlueprintCore"); |
| 92 | RegisterIcon("ClassIcon.MjSite", TEXT("MjSite.png"), "ClassIcon.TargetPoint"); |
| 93 | RegisterIcon("ClassIcon.MjTendon", TEXT("MjTendon.png"), "ClassIcon.CableComponent"); |