Skip to content

Commit

Permalink
tools: add/remove components
Browse files Browse the repository at this point in the history
Fixes: #179
  • Loading branch information
dbartolini committed Oct 30, 2024
1 parent ec55951 commit 9560bca
Show file tree
Hide file tree
Showing 4 changed files with 493 additions and 77 deletions.
8 changes: 6 additions & 2 deletions tools/level_editor/action_type.vala
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,9 @@ public enum ActionType
SET_ACTOR,
SET_SCRIPT,
SET_ANIMATION_STATE_MACHINE,
SET_SOUND
SET_SOUND,
UNIT_ADD_COMPONENT,
UNIT_REMOVE_COMPONENT
}

public const string ActionNames[] =
Expand All @@ -42,7 +44,9 @@ public const string ActionNames[] =
"Set Actor Parameter",
"Set Script Parameter",
"Set Animation State Machine Parameter",
"Set Sound Parameter"
"Set Sound Parameter",
"Add Unit Component",
"Remove Unit Component"
};

public enum ActionTypeFlags
Expand Down
87 changes: 87 additions & 0 deletions tools/level_editor/level_editor.vala
Original file line number Diff line number Diff line change
Expand Up @@ -572,6 +572,12 @@ public class LevelEditorApplication : Gtk.Application
{ "create-package-windows", on_create_package_windows, "(sis)", null }
};

private const GLib.ActionEntry[] action_entries_unit =
{
{ "unit-add-component", on_unit_add_component, "s", null },
{ "unit-remove-component", on_unit_remove_component, "s", null }
};

// Command line options
private string? _source_dir = null;
private string _level_resource = "";
Expand Down Expand Up @@ -760,6 +766,7 @@ public class LevelEditorApplication : Gtk.Application
this.add_action_entries(action_entries_help, this);
this.add_action_entries(action_entries_project, this);
this.add_action_entries(action_entries_package, this);
this.add_action_entries(action_entries_unit, this);

_tool_place_accels = this.get_accels_for_action("app.tool(0)");
_tool_move_accels = this.get_accels_for_action("app.tool(1)");
Expand Down Expand Up @@ -851,6 +858,17 @@ public class LevelEditorApplication : Gtk.Application

_project_store = new ProjectStore(_project);

// Register component types.
Unit.register_component_type(OBJECT_TYPE_TRANSFORM, "");
Unit.register_component_type(OBJECT_TYPE_LIGHT, OBJECT_TYPE_TRANSFORM);
Unit.register_component_type(OBJECT_TYPE_CAMERA, OBJECT_TYPE_TRANSFORM);
Unit.register_component_type(OBJECT_TYPE_MESH_RENDERER, OBJECT_TYPE_TRANSFORM);
Unit.register_component_type(OBJECT_TYPE_SPRITE_RENDERER, OBJECT_TYPE_TRANSFORM);
Unit.register_component_type(OBJECT_TYPE_COLLIDER, OBJECT_TYPE_TRANSFORM);
Unit.register_component_type(OBJECT_TYPE_ACTOR, OBJECT_TYPE_TRANSFORM);
Unit.register_component_type(OBJECT_TYPE_SCRIPT, "");
Unit.register_component_type(OBJECT_TYPE_ANIMATION_STATE_MACHINE, "");

// Widgets
_combo = new Gtk.ComboBoxText();
_combo.append("editor", "Editor");
Expand Down Expand Up @@ -1431,11 +1449,13 @@ public class LevelEditorApplication : Gtk.Application
case ActionType.SPAWN_UNIT:
case ActionType.SPAWN_SOUND:
case ActionType.DUPLICATE_OBJECTS:
case ActionType.UNIT_ADD_COMPONENT:
if ((flags & ActionTypeFlags.FROM_SERVER) == 0)
on_objects_created(data);
break;

case ActionType.DESTROY_OBJECTS:
case ActionType.UNIT_REMOVE_COMPONENT:
if ((flags & ActionTypeFlags.FROM_SERVER) == 0)
on_objects_destroyed(data);
break;
Expand Down Expand Up @@ -1474,13 +1494,15 @@ public class LevelEditorApplication : Gtk.Application
case ActionType.SPAWN_UNIT:
case ActionType.SPAWN_SOUND:
case ActionType.DUPLICATE_OBJECTS:
case ActionType.UNIT_ADD_COMPONENT:
if (undo)
on_objects_destroyed(data);
else
on_objects_created(data);
break;

case ActionType.DESTROY_OBJECTS:
case ActionType.UNIT_REMOVE_COMPONENT:
if (undo)
on_objects_created(data);
else
Expand Down Expand Up @@ -2372,6 +2394,9 @@ public class LevelEditorApplication : Gtk.Application
_data_compiler.compile.end(res);
});
}

// FIXME: hack to force PropertiesView to update.
_level.selection_changed(_level._selection);
}

private void on_preferences(GLib.SimpleAction action, GLib.Variant? param)
Expand Down Expand Up @@ -3832,6 +3857,68 @@ public class LevelEditorApplication : Gtk.Application
logi("Done: #FILE(%s)".printf(package_path));
}

private void on_unit_add_component(GLib.SimpleAction action, GLib.Variant? param)
{
if (param == null)
return;

string component_type = param.get_string();
Guid unit_id = _level._selection.last();
Unit unit = new Unit(_database, unit_id);
ArrayList<Guid?> components_added = new ArrayList<Guid?>();
components_added.add(unit_id);
unit.add_component_type_dependencies(ref components_added, component_type);

_database.add_restore_point((int)ActionType.UNIT_ADD_COMPONENT, components_added.to_array());
}

private void on_unit_remove_component(GLib.SimpleAction action, GLib.Variant? param)
{
if (param == null)
return;

string component_type = param.get_string();
Guid unit_id = _level._selection.last();
Unit unit = new Unit(_database, unit_id);

Guid component_id;
if (!unit.has_component(out component_id, component_type))
return;

Gee.ArrayList<unowned string> dependents = new Gee.ArrayList<unowned string>();
// Do not remove if any other component needs us.
foreach (var entry in Unit._component_registry.entries) {
Guid dummy;
if (!unit.has_component(out dummy, entry.key))
continue;

string[] component_type_dependencies = ((string)entry.value).split(", ");
if (component_type in component_type_dependencies)
dependents.add(entry.key);
}

if (dependents.size > 0) {
StringBuilder sb = new StringBuilder();
sb.append("Cannot remove %s due to the following dependencies:\n\n".printf(component_type));
foreach (var item in dependents)
sb.append("%s\n".printf(item));

Gtk.MessageDialog md = new Gtk.MessageDialog(this.active_window
, DialogFlags.MODAL
, MessageType.WARNING
, Gtk.ButtonsType.OK
, sb.str
);
md.set_default_response(ResponseType.OK);

md.run();
md.destroy();
return;
} else {
unit.remove_component_type(component_type);
}
}

public void set_autosave_timer(uint minutes)
{
if (_save_timer_id > 0)
Expand Down
98 changes: 88 additions & 10 deletions tools/level_editor/properties_view.vala
Original file line number Diff line number Diff line change
Expand Up @@ -757,17 +757,79 @@ public class AnimationStateMachine : PropertyGrid
public class UnitView : PropertyGrid
{
// Widgets
private ProjectStore _store;
private ResourceChooserButton _prefab;
private Gtk.MenuButton _component_add;
private Gtk.Box _components;
private Gtk.Popover _add_popover;

private void on_add_component_clicked(Gtk.Button button)
{
Gtk.Application app = ((Gtk.Window)this.get_toplevel()).application;
app.activate_action("unit-add-component", new GLib.Variant.string(button.label));

_add_popover.hide();
}

public static Gtk.Menu component_menu(string object_type)
{
Gtk.Menu menu = new Gtk.Menu();
Gtk.MenuItem mi;

mi = new Gtk.MenuItem.with_label("Remove Component");
mi.activate.connect(() => {
GLib.Application.get_default().activate_action("unit-remove-component", new GLib.Variant.string(object_type));
});
menu.add(mi);

return menu;
}

public UnitView(Database db, ProjectStore store)
{
base(db);

_store = store;

// Widgets
_prefab = new ResourceChooserButton(store, "unit");
_prefab._selector.sensitive = false;

// List of component types.
const string components[] =
{
OBJECT_TYPE_TRANSFORM,
OBJECT_TYPE_LIGHT,
OBJECT_TYPE_CAMERA,
OBJECT_TYPE_MESH_RENDERER,
OBJECT_TYPE_SPRITE_RENDERER,
OBJECT_TYPE_COLLIDER,
OBJECT_TYPE_ACTOR,
OBJECT_TYPE_SCRIPT,
OBJECT_TYPE_ANIMATION_STATE_MACHINE
};

Gtk.Box add_box = new Gtk.Box(Gtk.Orientation.VERTICAL, 0);
for (int cc = 0; cc < components.length; ++cc) {
Gtk.Button mb;
mb = new Gtk.Button.with_label(components[cc]);
mb.clicked.connect(on_add_component_clicked);
add_box.pack_start(mb);
}
add_box.show_all();
_add_popover = new Gtk.Popover(null);
_add_popover.add(add_box);

_component_add = new Gtk.MenuButton();
_component_add.label = "Add Component";
_component_add.set_popover(_add_popover);

_components = new Gtk.Box(Gtk.Orientation.HORIZONTAL, 6);
_components.homogeneous = true;
_components.pack_start(_component_add);

add_row("Prefab", _prefab);
add_row("Components", _components);
}

public override void update()
Expand Down Expand Up @@ -889,6 +951,9 @@ public class PropertiesView : Gtk.Bin
private PropertyGridSet _object_view;
private Gtk.Stack _stack;

[CCode (has_target = false)]
public delegate Gtk.Menu ContextMenu(string object_type);

public PropertiesView(Database db, ProjectStore store)
{
// Data
Expand All @@ -905,15 +970,15 @@ public class PropertiesView : Gtk.Bin

// Unit
register_object_type("Unit", "name", 0, new UnitView(_db, store));
register_object_type("Transform", OBJECT_TYPE_TRANSFORM, 0, new TransformPropertyGrid(_db));
register_object_type("Light", OBJECT_TYPE_LIGHT, 1, new LightPropertyGrid(_db));
register_object_type("Camera", OBJECT_TYPE_CAMERA, 2, new CameraPropertyGrid(_db));
register_object_type("Mesh Renderer", OBJECT_TYPE_MESH_RENDERER, 3, new MeshRendererPropertyGrid(_db, store));
register_object_type("Sprite Renderer", OBJECT_TYPE_SPRITE_RENDERER, 3, new SpriteRendererPropertyGrid(_db, store));
register_object_type("Collider", OBJECT_TYPE_COLLIDER, 3, new ColliderPropertyGrid(_db, store));
register_object_type("Actor", OBJECT_TYPE_ACTOR, 3, new ActorPropertyGrid(_db, store._project));
register_object_type("Script", OBJECT_TYPE_SCRIPT, 3, new ScriptPropertyGrid(_db, store));
register_object_type("Animation State Machine", OBJECT_TYPE_ANIMATION_STATE_MACHINE, 3, new AnimationStateMachine(_db, store));
register_object_type("Transform", OBJECT_TYPE_TRANSFORM, 0, new TransformPropertyGrid(_db), UnitView.component_menu);
register_object_type("Light", OBJECT_TYPE_LIGHT, 1, new LightPropertyGrid(_db), UnitView.component_menu);
register_object_type("Camera", OBJECT_TYPE_CAMERA, 2, new CameraPropertyGrid(_db), UnitView.component_menu);
register_object_type("Mesh Renderer", OBJECT_TYPE_MESH_RENDERER, 3, new MeshRendererPropertyGrid(_db, store), UnitView.component_menu);
register_object_type("Sprite Renderer", OBJECT_TYPE_SPRITE_RENDERER, 3, new SpriteRendererPropertyGrid(_db, store), UnitView.component_menu);
register_object_type("Collider", OBJECT_TYPE_COLLIDER, 3, new ColliderPropertyGrid(_db, store), UnitView.component_menu);
register_object_type("Actor", OBJECT_TYPE_ACTOR, 3, new ActorPropertyGrid(_db, store._project), UnitView.component_menu);
register_object_type("Script", OBJECT_TYPE_SCRIPT, 3, new ScriptPropertyGrid(_db, store), UnitView.component_menu);
register_object_type("Animation State Machine", OBJECT_TYPE_ANIMATION_STATE_MACHINE, 3, new AnimationStateMachine(_db, store), UnitView.component_menu);

// Sound
register_object_type("Transform", "sound_transform", 0, new SoundTransformView(_db));
Expand All @@ -939,9 +1004,22 @@ public class PropertiesView : Gtk.Bin
store._project.project_reset.connect(on_project_reset);
}

private void register_object_type(string label, string object_type, int position, PropertyGrid cv)
private void register_object_type(string label, string object_type, int position, PropertyGrid cv, ContextMenu? action = null)
{
Gtk.Expander expander = _object_view.add_property_grid(cv, label);
if (action != null) {
expander.button_release_event.connect((ev) => {
if (ev.button == Gdk.BUTTON_SECONDARY) {
Gtk.Menu menu = action(object_type);
menu.show_all();
menu.popup_at_pointer(ev);
return Gdk.EVENT_STOP;
}

return Gdk.EVENT_PROPAGATE;
});
}

_objects[object_type] = cv;
_expanders[object_type] = expander;
_entries.add({ object_type, position });
Expand Down
Loading

0 comments on commit 9560bca

Please sign in to comment.