properties_view.vala 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271
  1. /*
  2. * Copyright (c) 2012-2025 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. // Widgets
  10. private InputResource _prefab;
  11. private Gtk.MenuButton _component_add;
  12. private Gtk.Box _components;
  13. private Gtk.Popover _add_popover;
  14. public static GLib.Menu component_menu(string object_type)
  15. {
  16. GLib.Menu menu = new GLib.Menu();
  17. GLib.MenuItem mi;
  18. mi = new GLib.MenuItem("Remove Component", null);
  19. mi.set_action_and_target_value("app.unit-remove-component", new GLib.Variant.string(object_type));
  20. menu.append_item(mi);
  21. return menu;
  22. }
  23. public UnitView(Database db)
  24. {
  25. base(db);
  26. _order = -1.0;
  27. // Widgets
  28. _prefab = new InputResource(OBJECT_TYPE_UNIT, db);
  29. _prefab._selector.sensitive = false;
  30. // Construct 'add components' button.
  31. GLib.Menu menu_model = new GLib.Menu();
  32. GLib.MenuItem mi;
  33. foreach (var entry in Unit._component_registry.entries) {
  34. mi = new GLib.MenuItem(camel_case(entry.key), null);
  35. mi.set_action_and_target_value("app.unit-add-component"
  36. , new GLib.Variant.string(entry.key)
  37. );
  38. menu_model.append_item(mi);
  39. }
  40. _add_popover = new Gtk.Popover.from_model(null, menu_model);
  41. _component_add = new Gtk.MenuButton();
  42. _component_add.label = "Add Component";
  43. _component_add.set_popover(_add_popover);
  44. _components = new Gtk.Box(Gtk.Orientation.HORIZONTAL, 6);
  45. _components.homogeneous = true;
  46. _components.pack_start(_component_add);
  47. add_row("Prefab", _prefab);
  48. add_row("Components", _components);
  49. }
  50. public override void update()
  51. {
  52. if (_db.has_property(_id, "prefab")) {
  53. _prefab.value = _db.get_property_string(_id, "prefab");
  54. } else {
  55. _prefab.value = "<none>";
  56. }
  57. }
  58. }
  59. public class PropertiesView : Gtk.Box
  60. {
  61. private Database _db;
  62. private Gee.HashMap<string, Expander> _expanders;
  63. private Gee.HashMap<string, bool> _expander_states;
  64. private Gee.HashMap<string, PropertyGrid> _objects;
  65. private Gee.ArrayList<string> _entries;
  66. private Gee.ArrayList<Guid?>? _selection;
  67. // Widgets
  68. private Gtk.Label _nothing_to_show;
  69. private Gtk.Label _unknown_object_type;
  70. private Gtk.Viewport _viewport;
  71. private Gtk.ScrolledWindow _scrolled_window;
  72. private PropertyGridSet _object_view;
  73. private Gtk.Stack _stack;
  74. [CCode (has_target = false)]
  75. public delegate GLib.Menu ContextMenu(string object_type);
  76. public PropertiesView(Database db)
  77. {
  78. Object(orientation: Gtk.Orientation.VERTICAL);
  79. // Data
  80. _db = db;
  81. _expanders = new Gee.HashMap<string, Expander>();
  82. _expander_states = new Gee.HashMap<string, bool>();
  83. _objects = new Gee.HashMap<string, PropertyGrid>();
  84. _entries = new Gee.ArrayList<string>();
  85. _selection = null;
  86. // Widgets
  87. _object_view = new PropertyGridSet();
  88. _object_view.margin_bottom
  89. = _object_view.margin_end
  90. = _object_view.margin_start
  91. = _object_view.margin_top
  92. = 6
  93. ;
  94. _nothing_to_show = new Gtk.Label("Select an object to start editing");
  95. _unknown_object_type = new Gtk.Label("Unknown object type");
  96. _viewport = new Gtk.Viewport(null, null);
  97. _viewport.add(_object_view);
  98. _scrolled_window = new Gtk.ScrolledWindow(null, null);
  99. _scrolled_window.add(_viewport);
  100. _stack = new Gtk.Stack();
  101. _stack.add(_nothing_to_show);
  102. _stack.add(_scrolled_window);
  103. _stack.add(_unknown_object_type);
  104. this.pack_start(_stack);
  105. this.get_style_context().add_class("properties-view");
  106. db._project.project_reset.connect(on_project_reset);
  107. }
  108. public void register_object_type(string object_type, PropertyGrid? cv = null, ContextMenu? context_menu = null)
  109. {
  110. PropertyGrid? grid = cv;
  111. if (grid == null)
  112. grid = new PropertyGrid.from_object_type(StringId64(object_type), _db);
  113. Expander expander = _object_view.add_property_grid(grid, camel_case(object_type));
  114. if (context_menu != null) {
  115. Gtk.GestureMultiPress _controller_click = new Gtk.GestureMultiPress(expander);
  116. _controller_click.set_button(0);
  117. _controller_click.released.connect((n_press, x, y) => {
  118. if (_controller_click.get_current_button() == Gdk.BUTTON_SECONDARY) {
  119. Gtk.Popover menu = new Gtk.Popover.from_model(null, context_menu(object_type));
  120. menu.set_relative_to(expander);
  121. menu.set_pointing_to({ (int)x, (int)y, 1, 1 });
  122. menu.set_position(Gtk.PositionType.BOTTOM);
  123. menu.popup();
  124. }
  125. });
  126. }
  127. _objects[object_type] = grid;
  128. _expanders[object_type] = expander;
  129. _entries.add(object_type);
  130. }
  131. public void show_unit(Guid id)
  132. {
  133. foreach (var type in _entries) {
  134. Expander expander = _expanders[type];
  135. _expander_states[type] = expander.expanded;
  136. }
  137. _stack.set_visible_child(_scrolled_window);
  138. foreach (var type in _entries) {
  139. Expander expander = _expanders[type];
  140. bool was_expanded = _expander_states.has_key(type) ? _expander_states[type] : false;
  141. PropertyGrid cv = _objects[type];
  142. Unit unit = Unit(_db, id);
  143. Guid component_id;
  144. Guid owner_id;
  145. if (unit.has_component_with_owner(out component_id, out owner_id, type) || type == OBJECT_TYPE_UNIT) {
  146. cv._id = id;
  147. cv._component_id = component_id;
  148. cv._visible = true;
  149. cv.update();
  150. if (id == owner_id)
  151. expander.get_style_context().remove_class("inherited");
  152. else
  153. expander.get_style_context().add_class("inherited");
  154. expander.expanded = was_expanded;
  155. } else {
  156. cv._visible = false;
  157. }
  158. }
  159. _object_view._list_box.invalidate_filter();
  160. _object_view._list_box.invalidate_sort();
  161. }
  162. public void show_sound_source(Guid id)
  163. {
  164. foreach (var type in _entries) {
  165. Expander expander = _expanders[type];
  166. _expander_states[type] = expander.expanded;
  167. }
  168. _stack.set_visible_child(_scrolled_window);
  169. foreach (var type in _entries) {
  170. Expander expander = _expanders[type];
  171. PropertyGrid cv = _objects[type];
  172. if (type == OBJECT_TYPE_SOUND_SOURCE) {
  173. bool was_expanded = _expander_states.has_key(type) ? _expander_states[type] : false;
  174. cv._id = id;
  175. cv._visible = true;
  176. cv.update();
  177. expander.show();
  178. expander.expanded = was_expanded;
  179. } else {
  180. cv._visible = false;
  181. }
  182. }
  183. _object_view._list_box.invalidate_filter();
  184. _object_view._list_box.invalidate_sort();
  185. }
  186. public void show_or_hide_properties()
  187. {
  188. if (_selection == null || _selection.size != 1) {
  189. _stack.set_visible_child(_nothing_to_show);
  190. return;
  191. }
  192. Guid id = _selection[_selection.size - 1];
  193. if (!_db.has_object(id))
  194. return;
  195. if (_db.object_type(id) == OBJECT_TYPE_UNIT)
  196. show_unit(id);
  197. else if (_db.object_type(id) == OBJECT_TYPE_SOUND_SOURCE)
  198. show_sound_source(id);
  199. else
  200. _stack.set_visible_child(_unknown_object_type);
  201. }
  202. public void on_selection_changed(Gee.ArrayList<Guid?> selection)
  203. {
  204. _selection = selection;
  205. show_or_hide_properties();
  206. }
  207. public override void map()
  208. {
  209. base.map();
  210. show_or_hide_properties();
  211. }
  212. public void on_project_reset()
  213. {
  214. foreach (var obj in _objects) {
  215. PropertyGrid cv = obj.value;
  216. cv._id = GUID_ZERO;
  217. cv._component_id = GUID_ZERO;
  218. }
  219. }
  220. }
  221. } /* namespace Crown */