properties_view.vala 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259
  1. /*
  2. * Copyright (c) 2012-2026 Daniele Bartolini et al.
  3. * SPDX-License-Identifier: GPL-3.0-or-later
  4. */
  5. namespace Crown
  6. {
  7. public class UnitView : PropertyGrid
  8. {
  9. public InputResource _prefab;
  10. public Gtk.Button _open_prefab;
  11. public Gtk.MenuButton _component_add;
  12. public Gtk.Box _components;
  13. public Gtk.Popover _add_popover;
  14. public const GLib.ActionEntry[] actions =
  15. {
  16. { "add-component", on_add_component, "s", null },
  17. };
  18. public void on_add_component(GLib.SimpleAction action, GLib.Variant? param)
  19. {
  20. string component_type = param.get_string();
  21. Guid unit_id = _id;
  22. Unit unit = Unit(_db, unit_id);
  23. Gee.ArrayList<Guid?> components_added = new Gee.ArrayList<Guid?>();
  24. unit.add_component_type_dependencies(ref components_added, component_type);
  25. _db.add_restore_point((int)ActionType.CREATE_OBJECTS, components_added.to_array());
  26. }
  27. public UnitView(Database db)
  28. {
  29. base(db);
  30. _action_group.add_action_entries(actions, this);
  31. _order = -1.0;
  32. // Widgets
  33. _prefab = new InputResource(OBJECT_TYPE_UNIT, db);
  34. _prefab._selector.sensitive = false;
  35. _open_prefab = new Gtk.Button.with_label("Open Prefab");
  36. _open_prefab.sensitive = false;
  37. _open_prefab.clicked.connect(on_open_prefab_clicked);
  38. // Construct 'add components' button.
  39. GLib.Menu menu_model = new GLib.Menu();
  40. GLib.MenuItem mi;
  41. foreach (var entry in Unit._component_registry.entries) {
  42. mi = new GLib.MenuItem(camel_case(entry.key), null);
  43. mi.set_action_and_target_value("object.add-component"
  44. , new GLib.Variant.string(entry.key)
  45. );
  46. menu_model.append_item(mi);
  47. }
  48. _add_popover = new Gtk.Popover.from_model(null, menu_model);
  49. _component_add = new Gtk.MenuButton();
  50. _component_add.label = "Add Component";
  51. _component_add.set_popover(_add_popover);
  52. _components = new Gtk.Box(Gtk.Orientation.HORIZONTAL, 6);
  53. _components.homogeneous = true;
  54. _components.pack_start(_component_add);
  55. add_row("Prefab", _prefab);
  56. add_row("Prefab", _open_prefab);
  57. add_row("Components", _components);
  58. }
  59. public override void read_properties()
  60. {
  61. string? prefab = _db.get_resource(_id, "prefab");
  62. _prefab.value = prefab;
  63. _open_prefab.sensitive = prefab != null;
  64. }
  65. public void on_open_prefab_clicked()
  66. {
  67. GLib.Application.get_default().activate_action("open-unit", new GLib.Variant.string(_prefab.value));
  68. }
  69. }
  70. public class PropertiesView : Gtk.Box
  71. {
  72. public const string NOTHING_TO_SHOW = "nothing-to-show";
  73. public const string UNKNOWN_OBJECT_TYPE = "unknown-object-type";
  74. public const string PROPERTIES = "properties";
  75. public DatabaseEditor _database_editor;
  76. public Database _database;
  77. public Gee.HashMap<string, bool> _expander_states;
  78. public Gee.HashMap<string, PropertyGrid> _objects;
  79. public Gtk.Viewport _viewport;
  80. public Gtk.ScrolledWindow _scrolled_window;
  81. public PropertyGridSet _object_view;
  82. public Gtk.Stack _stack;
  83. public PropertiesView(DatabaseEditor database_editor)
  84. {
  85. Object(orientation: Gtk.Orientation.VERTICAL);
  86. // Data
  87. _database_editor = database_editor;
  88. _database_editor.selection_changed.connect(on_database_selection_changed);
  89. _database = database_editor._database;
  90. _expander_states = new Gee.HashMap<string, bool>();
  91. _objects = new Gee.HashMap<string, PropertyGrid>();
  92. // Widgets
  93. _object_view = new PropertyGridSet();
  94. _object_view.margin_bottom
  95. = _object_view.margin_end
  96. = _object_view.margin_start
  97. = _object_view.margin_top
  98. = 6
  99. ;
  100. _viewport = new Gtk.Viewport(null, null);
  101. _viewport.add(_object_view);
  102. _scrolled_window = new Gtk.ScrolledWindow(null, null);
  103. _scrolled_window.add(_viewport);
  104. _stack = new Gtk.Stack();
  105. _stack.add_named(new Gtk.Label("Select an object to start editing"), NOTHING_TO_SHOW);
  106. _stack.add_named(new Gtk.Label("Unknown object type"), UNKNOWN_OBJECT_TYPE);
  107. _stack.add_named(_scrolled_window, PROPERTIES);
  108. this.pack_start(_stack);
  109. this.get_style_context().add_class("properties-view");
  110. _database._project.project_reset.connect(on_project_reset);
  111. }
  112. public void register_object_type(string object_type, PropertyGrid? cv = null)
  113. {
  114. PropertyGrid? grid = cv;
  115. if (grid == null)
  116. grid = new PropertyGrid.from_object_type(StringId64(object_type), _database);
  117. _object_view.add_property_grid(grid, camel_case(object_type));
  118. _objects[object_type] = grid;
  119. }
  120. public void show_unit(Guid id)
  121. {
  122. foreach (var entry in _objects)
  123. _expander_states[entry.key] = entry.value._expander.expanded;
  124. _stack.set_visible_child_name(PROPERTIES);
  125. foreach (var entry in _objects) {
  126. string type = entry.key;
  127. PropertyGrid cv = entry.value;
  128. bool was_expanded = _expander_states.has_key(type) ? _expander_states[type] : false;
  129. Unit unit = Unit(_database, id);
  130. Guid component_id;
  131. if (unit.has_component(out component_id, type) || type == OBJECT_TYPE_UNIT) {
  132. cv._id = id;
  133. cv._component_id = component_id;
  134. cv._visible = true;
  135. cv.read_properties();
  136. if (component_id != GUID_ZERO) {
  137. if (id == _database.owner(component_id))
  138. cv._expander.get_style_context().remove_class("inherited");
  139. else
  140. cv._expander.get_style_context().add_class("inherited");
  141. }
  142. cv._expander.expanded = was_expanded;
  143. } else {
  144. cv._visible = false;
  145. }
  146. }
  147. _object_view._list_box.invalidate_filter();
  148. _object_view._list_box.invalidate_sort();
  149. }
  150. public void show_sound_source(Guid id)
  151. {
  152. foreach (var entry in _objects)
  153. _expander_states[entry.key] = entry.value._expander.expanded;
  154. _stack.set_visible_child_name(PROPERTIES);
  155. foreach (var entry in _objects) {
  156. string type = entry.key;
  157. PropertyGrid cv = entry.value;
  158. if (type == OBJECT_TYPE_SOUND_SOURCE) {
  159. bool was_expanded = _expander_states.has_key(type) ? _expander_states[type] : false;
  160. cv._id = id;
  161. cv._visible = true;
  162. cv.read_properties();
  163. cv._expander.show();
  164. cv._expander.expanded = was_expanded;
  165. } else {
  166. cv._visible = false;
  167. }
  168. }
  169. _object_view._list_box.invalidate_filter();
  170. _object_view._list_box.invalidate_sort();
  171. }
  172. public void set_objects(Guid?[] objects)
  173. {
  174. if (objects.length == 0) {
  175. _stack.set_visible_child_name(NOTHING_TO_SHOW);
  176. return;
  177. }
  178. Guid id = objects[objects.length - 1];
  179. if (!_database.has_object(id) || !_database.is_alive(id))
  180. return;
  181. if (_database.object_type(id) == OBJECT_TYPE_UNIT)
  182. show_unit(id);
  183. else if (_database.object_type(id) == OBJECT_TYPE_SOUND_SOURCE)
  184. show_sound_source(id);
  185. else
  186. _stack.set_visible_child_name(UNKNOWN_OBJECT_TYPE);
  187. }
  188. public void on_project_reset()
  189. {
  190. foreach (var obj in _objects) {
  191. PropertyGrid cv = obj.value;
  192. cv._id = GUID_ZERO;
  193. cv._component_id = GUID_ZERO;
  194. }
  195. }
  196. public void on_database_selection_changed()
  197. {
  198. Gee.ArrayList<Guid?> selection = _database_editor._selection;
  199. if (selection.size == 0)
  200. set_objects({ GUID_ZERO });
  201. else
  202. set_objects({ selection.last() });
  203. }
  204. }
  205. } /* namespace Crown */