613 lines
23 KiB
Rust
613 lines
23 KiB
Rust
use super::*;
|
|
|
|
pub(super) fn clear_asset_drag(world: &mut World) {
|
|
if let Some(mut assets) = world.get_resource_mut::<EditorAssets>() {
|
|
assets.clear_drag();
|
|
}
|
|
}
|
|
|
|
pub(super) fn primitive_editor_ui(world: &mut World, ui: &mut egui::Ui, entity: Entity) {
|
|
let material_candidates = brush_face_material_ref_candidates(world);
|
|
let material_drop_candidate = world
|
|
.get_resource::<EditorAssets>()
|
|
.and_then(|assets| assets.dragging_selection().cloned())
|
|
.and_then(|selection| {
|
|
asset_ref_candidate_from_selection(world, &selection, AssetRefCandidateKind::Material)
|
|
});
|
|
let invalid_material_drop =
|
|
material_drop_invalid_reason(world, material_drop_candidate.is_some());
|
|
let Some(mut primitive) = world.get::<Primitive>(entity).cloned() else {
|
|
return;
|
|
};
|
|
let original = primitive.clone();
|
|
let mut changed = false;
|
|
let mut accepted_drop = false;
|
|
let mut options =
|
|
ComponentCardOptions::removable(COMPONENT_PRIMITIVE, "Primitive", icons::CUBE);
|
|
options.summary = "Shape · Size · Materials";
|
|
let card = component_card_context(world, entity, options);
|
|
let card_response = component_card(ui, &card, |ui| {
|
|
property_row(ui, "Shape", |ui| {
|
|
ui.horizontal_wrapped(|ui| {
|
|
for (label, shape) in [
|
|
("Box", PrimitiveShape::Box),
|
|
("Sphere", PrimitiveShape::Sphere),
|
|
("Ramp", PrimitiveShape::Ramp),
|
|
] {
|
|
changed |= ui
|
|
.selectable_value(&mut primitive.shape, shape, label)
|
|
.changed();
|
|
}
|
|
});
|
|
});
|
|
property_row(ui, "Size X", |ui| {
|
|
changed |= ui
|
|
.add(egui::Slider::new(&mut primitive.size.x, 0.1..=1000.0))
|
|
.changed();
|
|
});
|
|
property_row(ui, "Size Y", |ui| {
|
|
changed |= ui
|
|
.add(egui::Slider::new(&mut primitive.size.y, 0.1..=1000.0))
|
|
.changed();
|
|
});
|
|
property_row(ui, "Size Z", |ui| {
|
|
changed |= ui
|
|
.add(egui::Slider::new(&mut primitive.size.z, 0.1..=1000.0))
|
|
.changed();
|
|
});
|
|
ui.add_space(8.0);
|
|
let materials = crate::ui::materials::MaterialsSectionViewModel {
|
|
slot_ids: vec![primitive.surface.id.0.clone()],
|
|
};
|
|
let widget = crate::ui::materials::materials_section(ui, &materials, |ui| {
|
|
material_slot_widget_ui(
|
|
world,
|
|
ui,
|
|
entity,
|
|
&mut primitive.surface,
|
|
&material_candidates,
|
|
material_drop_candidate.as_ref(),
|
|
invalid_material_drop,
|
|
)
|
|
});
|
|
changed |= widget.changed;
|
|
accepted_drop |= widget.accepted_drop;
|
|
});
|
|
apply_component_card_response(world, entity, card_response);
|
|
if accepted_drop {
|
|
clear_asset_drag(world);
|
|
}
|
|
if changed && primitive != original {
|
|
set_primitive_with_history(world, entity, primitive);
|
|
}
|
|
}
|
|
|
|
pub(super) fn light_editor_ui(world: &mut World, ui: &mut egui::Ui, entity: Entity) {
|
|
let Some(mut light) = world.get::<LightDesc>(entity).cloned() else {
|
|
return;
|
|
};
|
|
let _original = light.clone();
|
|
let mut changed = false;
|
|
let card = component_card_context(
|
|
world,
|
|
entity,
|
|
ComponentCardOptions::removable(COMPONENT_LIGHT_DESC, "Light", icons::LIGHTBULB),
|
|
);
|
|
let card_response = component_card(ui, &card, |ui| {
|
|
property_row(ui, "Kind", |ui| {
|
|
ui.horizontal_wrapped(|ui| {
|
|
for (label, kind) in [
|
|
("Point", AuthoringLightKind::Point),
|
|
("Spot", AuthoringLightKind::Spot),
|
|
("Directional", AuthoringLightKind::Directional),
|
|
] {
|
|
if ui.selectable_label(light.kind == kind, label).clicked() {
|
|
let color = light.color;
|
|
light = LightDesc {
|
|
color,
|
|
..LightDesc::for_kind(kind)
|
|
};
|
|
changed = true;
|
|
}
|
|
}
|
|
});
|
|
});
|
|
let solari_disabled = solari_disables_local_light(world, &light);
|
|
if solari_disabled {
|
|
ui.colored_label(
|
|
egui::Color32::from_rgb(255, 180, 100),
|
|
"Point and spot lights are disabled while Solari is active. Use a directional light or emissive material, or switch GI to Forward.",
|
|
);
|
|
}
|
|
ui.add_enabled_ui(!solari_disabled, |ui| {
|
|
let mut color = [light.color.r, light.color.g, light.color.b, light.color.a];
|
|
property_row(ui, "Color", |ui| {
|
|
if ui.color_edit_button_rgba_unmultiplied(&mut color).changed() {
|
|
light.color = ColorDesc {
|
|
r: color[0],
|
|
g: color[1],
|
|
b: color[2],
|
|
a: color[3],
|
|
};
|
|
changed = true;
|
|
}
|
|
});
|
|
let intensity_label = match light.kind {
|
|
AuthoringLightKind::Directional => "Intensity (lux)",
|
|
_ => "Intensity (lumens)",
|
|
};
|
|
let intensity_max = match light.kind {
|
|
AuthoringLightKind::Directional => AUTHORING_DIRECTIONAL_LUX_MAX,
|
|
_ => AUTHORING_POINT_SPOT_LUMENS_MAX,
|
|
};
|
|
property_row(ui, intensity_label, |ui| {
|
|
ui.horizontal_wrapped(|ui| {
|
|
if ui
|
|
.add(
|
|
egui::Slider::new(&mut light.intensity, 0.0..=intensity_max)
|
|
.show_value(false),
|
|
)
|
|
.changed()
|
|
{
|
|
changed = true;
|
|
}
|
|
if ui
|
|
.add_sized(
|
|
[fit_width(ui, 72.0, 120.0), 20.0],
|
|
egui::DragValue::new(&mut light.intensity)
|
|
.range(0.0..=intensity_max)
|
|
.speed(intensity_max * 0.001),
|
|
)
|
|
.changed()
|
|
{
|
|
changed = true;
|
|
}
|
|
});
|
|
});
|
|
if matches!(
|
|
light.kind,
|
|
AuthoringLightKind::Point | AuthoringLightKind::Spot
|
|
) {
|
|
property_row(ui, "Range (m)", |ui| {
|
|
changed |= ui
|
|
.add(egui::Slider::new(&mut light.range, 0.0..=100.0))
|
|
.changed();
|
|
});
|
|
}
|
|
if matches!(light.kind, AuthoringLightKind::Spot) {
|
|
property_row(ui, "Inner angle", |ui| {
|
|
changed |= ui
|
|
.add(egui::Slider::new(&mut light.inner_angle_deg, 1.0..=80.0))
|
|
.changed();
|
|
});
|
|
property_row(ui, "Outer angle", |ui| {
|
|
changed |= ui
|
|
.add(egui::Slider::new(&mut light.outer_angle_deg, 1.0..=90.0))
|
|
.changed();
|
|
});
|
|
}
|
|
property_row(ui, "Shadows", |ui| {
|
|
changed |= ui.checkbox(&mut light.shadows, "Cast shadows").changed();
|
|
});
|
|
if matches!(light.kind, AuthoringLightKind::Directional) {
|
|
ui.small("Controls project sun while this directional exists.");
|
|
}
|
|
});
|
|
});
|
|
apply_component_card_response(world, entity, card_response);
|
|
if changed {
|
|
set_light_with_history(world, entity, light);
|
|
}
|
|
}
|
|
|
|
pub(super) fn solari_disables_local_light(world: &World, light: &LightDesc) -> bool {
|
|
matches!(
|
|
light.kind,
|
|
AuthoringLightKind::Point | AuthoringLightKind::Spot
|
|
) && world
|
|
.get_resource::<settings::ActiveCameraRenderProfile>()
|
|
.is_some_and(|profile| profile.gi_path == settings::GiPath::SolariDeferred)
|
|
&& world
|
|
.get_resource::<settings::RenderingCapabilities>()
|
|
.is_some_and(|caps| caps.rt_supported)
|
|
}
|
|
|
|
pub(super) fn rigid_body_editor_ui(world: &mut World, ui: &mut egui::Ui, entity: Entity) {
|
|
let Some(mut body) = world.get::<RigidBodyDesc>(entity).copied() else {
|
|
return;
|
|
};
|
|
let original = body;
|
|
let mut changed = false;
|
|
let card = component_card_context(
|
|
world,
|
|
entity,
|
|
ComponentCardOptions::removable(COMPONENT_RIGID_BODY_DESC, "Rigid Body", icons::SPHERE),
|
|
);
|
|
let card_response = component_card(ui, &card, |ui| {
|
|
property_row(ui, "Body", |ui| {
|
|
ui.horizontal_wrapped(|ui| {
|
|
for (label, kind) in [
|
|
("Static", AuthoringRigidBody::Static),
|
|
("Kinematic", AuthoringRigidBody::Kinematic),
|
|
("Dynamic", AuthoringRigidBody::Dynamic),
|
|
] {
|
|
changed |= ui.selectable_value(&mut body.body, kind, label).changed();
|
|
}
|
|
});
|
|
});
|
|
});
|
|
apply_component_card_response(world, entity, card_response);
|
|
if changed && body != original {
|
|
set_rigid_body_with_history(world, entity, body);
|
|
}
|
|
}
|
|
|
|
pub(super) fn collider_editor_ui(world: &mut World, ui: &mut egui::Ui, entity: Entity) {
|
|
let mesh_candidates = static_mesh_asset_ref_candidates(world, AssetRefCandidateKind::Mesh);
|
|
let diagnostic_entry = diagnose_collider(world, entity);
|
|
let Some(mut collider) = world.get::<ColliderDesc>(entity).cloned() else {
|
|
return;
|
|
};
|
|
let original = collider.clone();
|
|
let mut changed = false;
|
|
let renderer_meshes: Vec<EditorAssetRef> = world
|
|
.get::<StaticMeshRenderer>(entity)
|
|
.map(|renderer| {
|
|
renderer
|
|
.slots
|
|
.iter()
|
|
.map(|slot| slot.mesh.clone())
|
|
.collect()
|
|
})
|
|
.unwrap_or_default();
|
|
|
|
let card = component_card_context(
|
|
world,
|
|
entity,
|
|
ComponentCardOptions::removable(COMPONENT_COLLIDER_DESC, "Collider", icons::SELECTION),
|
|
);
|
|
let card_response = component_card(ui, &card, |ui| {
|
|
if let Some(entry) = diagnostic_entry.as_ref() {
|
|
let (label, color) = match entry.overlay_status {
|
|
ColliderOverlayStatus::Valid => ("Ready", egui::Color32::from_rgb(112, 210, 144)),
|
|
ColliderOverlayStatus::Trigger => {
|
|
("Trigger", egui::Color32::from_rgb(86, 195, 235))
|
|
}
|
|
ColliderOverlayStatus::Disabled => {
|
|
("Disabled", egui::Color32::from_rgb(143, 151, 163))
|
|
}
|
|
ColliderOverlayStatus::Warning => {
|
|
("Warning", egui::Color32::from_rgb(242, 173, 72))
|
|
}
|
|
ColliderOverlayStatus::Error => ("Invalid", egui::Color32::from_rgb(244, 91, 99)),
|
|
};
|
|
ui.horizontal_wrapped(|ui| {
|
|
ui.colored_label(color, egui::RichText::new(label).strong());
|
|
ui.label(egui::RichText::new(entry.shape_label).color(TEXT_DIM));
|
|
if entry.runtime_ready {
|
|
ui.label(egui::RichText::new("Hydrated").color(TEXT_MUTED).small());
|
|
}
|
|
});
|
|
for diagnostic in &entry.diagnostics {
|
|
let color = match diagnostic.severity {
|
|
ColliderDiagnosticSeverity::Info => TEXT_MUTED,
|
|
ColliderDiagnosticSeverity::Warning => egui::Color32::from_rgb(242, 173, 72),
|
|
ColliderDiagnosticSeverity::Error => egui::Color32::from_rgb(244, 91, 99),
|
|
};
|
|
ui.label(
|
|
egui::RichText::new(&diagnostic.message)
|
|
.color(color)
|
|
.small(),
|
|
);
|
|
ui.label(
|
|
egui::RichText::new(&diagnostic.repair)
|
|
.color(TEXT_MUTED)
|
|
.small(),
|
|
);
|
|
}
|
|
if entry.highest_severity() == Some(ColliderDiagnosticSeverity::Error)
|
|
&& ui.small_button("Reset shape").clicked()
|
|
{
|
|
collider.shape = ColliderShapeDesc::default();
|
|
collider.enabled = true;
|
|
changed = true;
|
|
}
|
|
ui.add_space(2.0);
|
|
}
|
|
property_row(ui, "Mode", |ui| {
|
|
changed |= ui.checkbox(&mut collider.enabled, "Enabled").changed();
|
|
changed |= ui.checkbox(&mut collider.is_trigger, "Trigger").changed();
|
|
});
|
|
property_row(ui, "Shape", |ui| {
|
|
let mut shape_kind = collider_shape_kind(&collider.shape);
|
|
egui::ComboBox::from_id_salt(("collider_shape_kind", entity))
|
|
.selected_text(shape_kind)
|
|
.show_ui(ui, |ui| {
|
|
for label in ["Box", "Sphere", "Capsule", "Static Mesh"] {
|
|
if ui.selectable_label(shape_kind == label, label).clicked() {
|
|
shape_kind = label;
|
|
}
|
|
}
|
|
});
|
|
if shape_kind != collider_shape_kind(&collider.shape) {
|
|
collider.shape =
|
|
convert_collider_shape(&collider.shape, shape_kind, renderer_meshes.clone());
|
|
changed = true;
|
|
}
|
|
});
|
|
|
|
match &mut collider.shape {
|
|
ColliderShapeDesc::Cuboid {
|
|
x_length,
|
|
y_length,
|
|
z_length,
|
|
} => {
|
|
changed |= dimension_drag(ui, "X", x_length);
|
|
changed |= dimension_drag(ui, "Y", y_length);
|
|
changed |= dimension_drag(ui, "Z", z_length);
|
|
}
|
|
ColliderShapeDesc::Sphere { radius } => {
|
|
changed |= dimension_drag(ui, "Radius", radius);
|
|
}
|
|
ColliderShapeDesc::Capsule { radius, height } => {
|
|
changed |= dimension_drag(ui, "Radius", radius);
|
|
changed |= dimension_drag(ui, "Height", height);
|
|
}
|
|
ColliderShapeDesc::StaticMesh { meshes, .. } => {
|
|
if meshes.is_empty() {
|
|
ui.label(egui::RichText::new("No mesh collider sources").color(TEXT_DIM));
|
|
}
|
|
for mesh in meshes.iter_mut() {
|
|
let mesh_response = asset_selector_row(
|
|
ui,
|
|
"Mesh",
|
|
icons::CUBE,
|
|
Some(mesh),
|
|
None,
|
|
false,
|
|
&mesh_candidates,
|
|
None,
|
|
None,
|
|
AssetSelectorActions::Full,
|
|
);
|
|
if let Some(selected) = mesh_response.selected {
|
|
*mesh = selected;
|
|
changed = true;
|
|
}
|
|
if mesh_response.locate {
|
|
locate_asset_ref(world, Some(mesh), &mesh_candidates);
|
|
}
|
|
}
|
|
if !renderer_meshes.is_empty() && ui.button("Use renderer meshes").clicked() {
|
|
*meshes = renderer_meshes.clone();
|
|
changed = true;
|
|
}
|
|
}
|
|
}
|
|
});
|
|
apply_component_card_response(world, entity, card_response);
|
|
|
|
if changed && collider != original {
|
|
set_collider_with_history(world, entity, collider);
|
|
}
|
|
}
|
|
|
|
pub(super) fn collider_shape_kind(shape: &ColliderShapeDesc) -> &'static str {
|
|
match shape {
|
|
ColliderShapeDesc::Cuboid { .. } => "Box",
|
|
ColliderShapeDesc::Sphere { .. } => "Sphere",
|
|
ColliderShapeDesc::Capsule { .. } => "Capsule",
|
|
ColliderShapeDesc::StaticMesh { .. } => "Static Mesh",
|
|
}
|
|
}
|
|
|
|
pub(super) fn convert_collider_shape(
|
|
previous: &ColliderShapeDesc,
|
|
shape_kind: &str,
|
|
renderer_meshes: Vec<EditorAssetRef>,
|
|
) -> ColliderShapeDesc {
|
|
let dimensions = match previous {
|
|
ColliderShapeDesc::Cuboid {
|
|
x_length,
|
|
y_length,
|
|
z_length,
|
|
} => Vec3::new(*x_length, *y_length, *z_length),
|
|
ColliderShapeDesc::Sphere { radius } => Vec3::splat(*radius * 2.0),
|
|
ColliderShapeDesc::Capsule { radius, height } => {
|
|
Vec3::new(*radius * 2.0, *height, *radius * 2.0)
|
|
}
|
|
ColliderShapeDesc::StaticMesh { .. } => Vec3::ONE,
|
|
}
|
|
.max(Vec3::splat(0.001));
|
|
|
|
match shape_kind {
|
|
"Sphere" => ColliderShapeDesc::Sphere {
|
|
radius: dimensions.max_element() * 0.5,
|
|
},
|
|
"Capsule" => ColliderShapeDesc::Capsule {
|
|
radius: dimensions.x.max(dimensions.z) * 0.5,
|
|
height: dimensions.y,
|
|
},
|
|
"Static Mesh" => ColliderShapeDesc::static_mesh(renderer_meshes),
|
|
_ => ColliderShapeDesc::Cuboid {
|
|
x_length: dimensions.x,
|
|
y_length: dimensions.y,
|
|
z_length: dimensions.z,
|
|
},
|
|
}
|
|
}
|
|
|
|
pub(super) fn dimension_drag(ui: &mut egui::Ui, label: &str, value: &mut f32) -> bool {
|
|
property_row(ui, label, |ui| {
|
|
ui.add_sized(
|
|
[fit_width(ui, 72.0, 120.0), 20.0],
|
|
egui::DragValue::new(value)
|
|
.range(0.001..=10_000.0)
|
|
.speed(0.05)
|
|
.min_decimals(2)
|
|
.max_decimals(3),
|
|
)
|
|
.changed()
|
|
})
|
|
}
|
|
|
|
pub(super) fn physics_editor_ui(world: &mut World, ui: &mut egui::Ui, entity: Entity) {
|
|
let Some(mut body) = world.get::<PhysicsBody>(entity).cloned() else {
|
|
return;
|
|
};
|
|
let _original = body.clone();
|
|
let mut changed = false;
|
|
let card = component_card_context(
|
|
world,
|
|
entity,
|
|
ComponentCardOptions::removable(COMPONENT_PHYSICS_BODY, "Physics", icons::SPHERE),
|
|
);
|
|
let card_response = component_card(ui, &card, |ui| {
|
|
property_row(ui, "Body", |ui| {
|
|
ui.horizontal_wrapped(|ui| {
|
|
for (label, kind) in [
|
|
("Static", AuthoringRigidBody::Static),
|
|
("Kinematic", AuthoringRigidBody::Kinematic),
|
|
("Dynamic", AuthoringRigidBody::Dynamic),
|
|
] {
|
|
if ui.selectable_label(body.body == kind, label).clicked() {
|
|
body.body = kind;
|
|
changed = true;
|
|
}
|
|
}
|
|
});
|
|
});
|
|
});
|
|
apply_component_card_response(world, entity, card_response);
|
|
if changed {
|
|
set_physics_with_history(world, entity, body);
|
|
}
|
|
}
|
|
|
|
pub(super) fn player_spawn_ui(world: &mut World, ui: &mut egui::Ui, entity: Entity) {
|
|
if world.get::<PlayerSpawn>(entity).is_none() {
|
|
return;
|
|
}
|
|
let card = component_card_context(
|
|
world,
|
|
entity,
|
|
ComponentCardOptions::removable(
|
|
COMPONENT_PLAYER_SPAWN,
|
|
"Player Spawn",
|
|
icons::PERSON_SIMPLE_RUN,
|
|
),
|
|
);
|
|
let card_response = component_card(ui, &card, |ui| {
|
|
ui.label(
|
|
egui::RichText::new("Uses this actor transform as a player start.").color(TEXT_DIM),
|
|
);
|
|
});
|
|
apply_component_card_response(world, entity, card_response);
|
|
}
|
|
|
|
pub(super) fn weapon_spawn_ui(world: &mut World, ui: &mut egui::Ui, entity: Entity) {
|
|
let Some(mut spawn) = world.get::<WeaponSpawn>(entity).cloned() else {
|
|
return;
|
|
};
|
|
let card = component_card_context(
|
|
world,
|
|
entity,
|
|
ComponentCardOptions::removable(COMPONENT_WEAPON_SPAWN, "Weapon Spawn", icons::CROSSHAIR),
|
|
);
|
|
let card_response = component_card(ui, &card, |ui| {
|
|
property_row(ui, "Weapon ID", |ui| {
|
|
ui.add_sized(
|
|
[text_field_width(ui), 20.0],
|
|
egui::TextEdit::singleline(&mut spawn.weapon_id),
|
|
);
|
|
});
|
|
});
|
|
apply_component_card_response(world, entity, card_response);
|
|
if let Ok(mut e) = world.get_entity_mut(entity) {
|
|
e.insert(spawn);
|
|
}
|
|
}
|
|
|
|
pub(super) fn trigger_volume_ui(world: &mut World, ui: &mut egui::Ui, entity: Entity) {
|
|
let Some(mut trigger) = world.get::<TriggerVolume>(entity).cloned() else {
|
|
return;
|
|
};
|
|
let card = component_card_context(
|
|
world,
|
|
entity,
|
|
ComponentCardOptions::removable(
|
|
COMPONENT_TRIGGER_VOLUME,
|
|
"Trigger Volume",
|
|
icons::SELECTION,
|
|
),
|
|
);
|
|
let card_response = component_card(ui, &card, |ui| {
|
|
property_row(ui, "Event", |ui| {
|
|
ui.add_sized(
|
|
[text_field_width(ui), 20.0],
|
|
egui::TextEdit::singleline(&mut trigger.event_name),
|
|
);
|
|
});
|
|
property_row(ui, "Half X", |ui| {
|
|
ui.add(egui::Slider::new(&mut trigger.half_extents.x, 0.1..=50.0));
|
|
});
|
|
property_row(ui, "Half Y", |ui| {
|
|
ui.add(egui::Slider::new(&mut trigger.half_extents.y, 0.1..=50.0));
|
|
});
|
|
property_row(ui, "Half Z", |ui| {
|
|
ui.add(egui::Slider::new(&mut trigger.half_extents.z, 0.1..=50.0));
|
|
});
|
|
});
|
|
apply_component_card_response(world, entity, card_response);
|
|
if let Ok(mut e) = world.get_entity_mut(entity) {
|
|
e.insert(trigger);
|
|
}
|
|
}
|
|
|
|
pub(super) fn team_spawn_ui(world: &mut World, ui: &mut egui::Ui, entity: Entity) {
|
|
let Some(mut spawn) = world.get::<TeamSpawn>(entity).cloned() else {
|
|
return;
|
|
};
|
|
let card = component_card_context(
|
|
world,
|
|
entity,
|
|
ComponentCardOptions::removable(COMPONENT_TEAM_SPAWN, "Team Spawn", icons::FLAG),
|
|
);
|
|
let card_response = component_card(ui, &card, |ui| {
|
|
property_row(ui, "Team", |ui| {
|
|
ui.add(egui::Slider::new(&mut spawn.team_id, 0..=8));
|
|
});
|
|
});
|
|
apply_component_card_response(world, entity, card_response);
|
|
if let Ok(mut e) = world.get_entity_mut(entity) {
|
|
e.insert(spawn);
|
|
}
|
|
}
|
|
|
|
pub(super) fn objective_ui(world: &mut World, ui: &mut egui::Ui, entity: Entity) {
|
|
let Some(mut marker) = world.get::<ObjectiveMarker>(entity).cloned() else {
|
|
return;
|
|
};
|
|
let card = component_card_context(
|
|
world,
|
|
entity,
|
|
ComponentCardOptions::removable(COMPONENT_OBJECTIVE_MARKER, "Objective", icons::TARGET),
|
|
);
|
|
let card_response = component_card(ui, &card, |ui| {
|
|
property_row(ui, "Objective ID", |ui| {
|
|
ui.add_sized(
|
|
[text_field_width(ui), 20.0],
|
|
egui::TextEdit::singleline(&mut marker.objective_id),
|
|
);
|
|
});
|
|
});
|
|
apply_component_card_response(world, entity, card_response);
|
|
if let Ok(mut e) = world.get_entity_mut(entity) {
|
|
e.insert(marker);
|
|
}
|
|
}
|
|
|
|
pub(super) fn prefab_instance_ui(world: &mut World, ui: &mut egui::Ui, entity: Entity) {
|
|
crate::assets::prefab_overrides::prefab_instance_inspector_ui(world, ui, entity);
|
|
}
|