object_view.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263
  1. /**************************************************************************/
  2. /* object_view.cpp */
  3. /**************************************************************************/
  4. /* This file is part of: */
  5. /* GODOT ENGINE */
  6. /* https://godotengine.org */
  7. /**************************************************************************/
  8. /* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
  9. /* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
  10. /* */
  11. /* Permission is hereby granted, free of charge, to any person obtaining */
  12. /* a copy of this software and associated documentation files (the */
  13. /* "Software"), to deal in the Software without restriction, including */
  14. /* without limitation the rights to use, copy, modify, merge, publish, */
  15. /* distribute, sublicense, and/or sell copies of the Software, and to */
  16. /* permit persons to whom the Software is furnished to do so, subject to */
  17. /* the following conditions: */
  18. /* */
  19. /* The above copyright notice and this permission notice shall be */
  20. /* included in all copies or substantial portions of the Software. */
  21. /* */
  22. /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
  23. /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
  24. /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
  25. /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
  26. /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
  27. /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
  28. /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
  29. /**************************************************************************/
  30. #include "object_view.h"
  31. #include "editor/editor_node.h"
  32. #include "editor/themes/editor_scale.h"
  33. #include "scene/gui/rich_text_label.h"
  34. #include "scene/gui/split_container.h"
  35. SnapshotObjectView::SnapshotObjectView() {
  36. set_name(TTRC("Objects"));
  37. }
  38. void SnapshotObjectView::show_snapshot(GameStateSnapshot *p_data, GameStateSnapshot *p_diff_data) {
  39. SnapshotView::show_snapshot(p_data, p_diff_data);
  40. item_data_map.clear();
  41. data_item_map.clear();
  42. set_v_size_flags(SizeFlags::SIZE_EXPAND_FILL);
  43. set_h_size_flags(SizeFlags::SIZE_EXPAND_FILL);
  44. objects_view = memnew(HSplitContainer);
  45. add_child(objects_view);
  46. objects_view->set_anchors_preset(LayoutPreset::PRESET_FULL_RECT);
  47. VBoxContainer *object_column = memnew(VBoxContainer);
  48. object_column->set_anchors_preset(LayoutPreset::PRESET_FULL_RECT);
  49. objects_view->add_child(object_column);
  50. object_column->set_h_size_flags(SizeFlags::SIZE_EXPAND_FILL);
  51. object_column->set_v_size_flags(SizeFlags::SIZE_EXPAND_FILL);
  52. object_list = memnew(Tree);
  53. filter_bar = memnew(TreeSortAndFilterBar(object_list, TTRC("Filter Objects")));
  54. object_column->add_child(filter_bar);
  55. int sort_idx = 0;
  56. if (diff_data) {
  57. filter_bar->add_sort_option(TTRC("Snapshot"), TreeSortAndFilterBar::SortType::ALPHA_SORT, sort_idx++);
  58. }
  59. filter_bar->add_sort_option(TTRC("Class"), TreeSortAndFilterBar::SortType::ALPHA_SORT, sort_idx++);
  60. filter_bar->add_sort_option(TTRC("Name"), TreeSortAndFilterBar::SortType::ALPHA_SORT, sort_idx++);
  61. filter_bar->add_sort_option(TTRC("Inbound References"), TreeSortAndFilterBar::SortType::NUMERIC_SORT, sort_idx++);
  62. TreeSortAndFilterBar::SortOptionIndexes default_sort = filter_bar->add_sort_option(
  63. TTRC("Outbound References"), TreeSortAndFilterBar::SortType::NUMERIC_SORT, sort_idx++);
  64. // Tree of objects.
  65. object_list->set_select_mode(Tree::SelectMode::SELECT_ROW);
  66. object_list->set_custom_minimum_size(Size2(200, 0) * EDSCALE);
  67. object_list->set_hide_folding(false);
  68. object_column->add_child(object_list);
  69. object_list->set_hide_root(true);
  70. object_list->set_columns(diff_data ? 5 : 4);
  71. object_list->set_column_titles_visible(true);
  72. object_list->set_theme_type_variation("TreeSecondary");
  73. int offset = 0;
  74. if (diff_data) {
  75. object_list->set_column_title(0, TTRC("Snapshot"));
  76. object_list->set_column_expand(0, false);
  77. object_list->set_column_title_tooltip_text(0, "A: " + snapshot_data->name + ", B: " + diff_data->name);
  78. offset++;
  79. }
  80. object_list->set_column_title(offset + 0, TTRC("Class"));
  81. object_list->set_column_expand(offset + 0, true);
  82. object_list->set_column_title_tooltip_text(offset + 0, TTRC("Object's class"));
  83. object_list->set_column_title(offset + 1, TTRC("Object"));
  84. object_list->set_column_expand(offset + 1, true);
  85. object_list->set_column_expand_ratio(offset + 1, 2);
  86. object_list->set_column_title_tooltip_text(offset + 1, TTRC("Object's name"));
  87. object_list->set_column_title(offset + 2, TTRC("In"));
  88. object_list->set_column_expand(offset + 2, false);
  89. object_list->set_column_clip_content(offset + 2, false);
  90. object_list->set_column_title_tooltip_text(offset + 2, TTRC("Number of inbound references"));
  91. object_list->set_column_custom_minimum_width(offset + 2, 30 * EDSCALE);
  92. object_list->set_column_title(offset + 3, TTRC("Out"));
  93. object_list->set_column_expand(offset + 3, false);
  94. object_list->set_column_clip_content(offset + 3, false);
  95. object_list->set_column_title_tooltip_text(offset + 3, TTRC("Number of outbound references"));
  96. object_list->set_column_custom_minimum_width(offset + 2, 30 * EDSCALE);
  97. object_list->connect(SceneStringName(item_selected), callable_mp(this, &SnapshotObjectView::_object_selected));
  98. object_list->set_h_size_flags(SizeFlags::SIZE_EXPAND_FILL);
  99. object_list->set_v_size_flags(SizeFlags::SIZE_EXPAND_FILL);
  100. object_details = memnew(VBoxContainer);
  101. object_details->set_custom_minimum_size(Size2(200, 0) * EDSCALE);
  102. objects_view->add_child(object_details);
  103. object_details->set_h_size_flags(SizeFlags::SIZE_EXPAND_FILL);
  104. object_details->set_v_size_flags(SizeFlags::SIZE_EXPAND_FILL);
  105. object_list->create_item();
  106. _insert_data(snapshot_data, TTRC("A"));
  107. if (diff_data) {
  108. _insert_data(diff_data, TTRC("B"));
  109. }
  110. filter_bar->select_sort(default_sort.descending);
  111. filter_bar->apply();
  112. object_list->set_selected(object_list->get_root()->get_first_child());
  113. // Expand the left panel as wide as we can. Passing `INT_MAX` or any very large int will have the opposite effect
  114. // and shrink the left panel as small as it can go. So, pass an int we know is larger than the current panel, but not
  115. // 'very' large (whatever that exact number is).
  116. objects_view->set_split_offset(get_viewport_rect().size.x);
  117. }
  118. void SnapshotObjectView::_insert_data(GameStateSnapshot *p_snapshot, const String &p_name) {
  119. for (const KeyValue<ObjectID, SnapshotDataObject *> &pair : p_snapshot->objects) {
  120. TreeItem *item = object_list->create_item(object_list->get_root());
  121. int offset = 0;
  122. if (diff_data) {
  123. item->set_text(0, p_name);
  124. item->set_tooltip_text(0, p_snapshot->name);
  125. item->set_auto_translate_mode(0, AUTO_TRANSLATE_MODE_DISABLED);
  126. offset = 1;
  127. }
  128. item->set_auto_translate_mode(offset + 0, AUTO_TRANSLATE_MODE_DISABLED);
  129. item->set_auto_translate_mode(offset + 1, AUTO_TRANSLATE_MODE_DISABLED);
  130. item->set_text(offset + 0, pair.value->type_name);
  131. item->set_text(offset + 1, pair.value->get_name());
  132. item->set_text(offset + 2, String::num_uint64(pair.value->inbound_references.size()));
  133. item->set_text(offset + 3, String::num_uint64(pair.value->outbound_references.size()));
  134. item_data_map[item] = pair.value;
  135. data_item_map[pair.value] = item;
  136. }
  137. }
  138. void SnapshotObjectView::_object_selected() {
  139. reference_item_map.clear();
  140. for (int i = 0; i < object_details->get_child_count(); i++) {
  141. object_details->get_child(i)->queue_free();
  142. }
  143. SnapshotDataObject *d = item_data_map[object_list->get_selected()];
  144. EditorNode::get_singleton()->push_item(static_cast<Object *>(d));
  145. DarkPanelContainer *object_panel = memnew(DarkPanelContainer);
  146. VBoxContainer *object_panel_content = memnew(VBoxContainer);
  147. object_panel_content->set_v_size_flags(SizeFlags::SIZE_EXPAND_FILL);
  148. object_panel_content->set_h_size_flags(SizeFlags::SIZE_EXPAND_FILL);
  149. object_details->add_child(object_panel);
  150. object_panel->add_child(object_panel_content);
  151. object_panel_content->add_child(memnew(SpanningHeader(d->get_name())));
  152. ScrollContainer *properties_scroll = memnew(ScrollContainer);
  153. properties_scroll->set_horizontal_scroll_mode(ScrollContainer::SCROLL_MODE_DISABLED);
  154. properties_scroll->set_vertical_scroll_mode(ScrollContainer::SCROLL_MODE_AUTO);
  155. properties_scroll->set_v_size_flags(SizeFlags::SIZE_EXPAND_FILL);
  156. properties_scroll->set_h_size_flags(SizeFlags::SIZE_EXPAND_FILL);
  157. object_panel_content->add_child(properties_scroll);
  158. VBoxContainer *properties_container = memnew(VBoxContainer);
  159. properties_container->set_h_size_flags(SizeFlags::SIZE_EXPAND_FILL);
  160. properties_scroll->add_child(properties_container);
  161. properties_container->add_theme_constant_override("separation", 8);
  162. inbound_tree = _make_references_list(properties_container, TTRC("Inbound References"), TTRC("Source"), TTRC("Other object referencing this object"), TTRC("Property"), TTRC("Property of other object referencing this object"));
  163. inbound_tree->connect(SceneStringName(item_selected), callable_mp(this, &SnapshotObjectView::_reference_selected).bind(inbound_tree));
  164. TreeItem *ib_root = inbound_tree->create_item();
  165. for (const KeyValue<String, ObjectID> &ob : d->inbound_references) {
  166. TreeItem *i = inbound_tree->create_item(ib_root);
  167. i->set_auto_translate_mode(0, AUTO_TRANSLATE_MODE_DISABLED);
  168. i->set_auto_translate_mode(1, AUTO_TRANSLATE_MODE_DISABLED);
  169. SnapshotDataObject *target = d->snapshot->objects[ob.value];
  170. i->set_text(0, target->get_name());
  171. i->set_text(1, ob.key);
  172. reference_item_map[i] = data_item_map[target];
  173. }
  174. outbound_tree = _make_references_list(properties_container, TTRC("Outbound References"), TTRC("Property"), TTRC("Property of this object referencing other object"), TTRC("Target"), TTRC("Other object being referenced"));
  175. outbound_tree->connect(SceneStringName(item_selected), callable_mp(this, &SnapshotObjectView::_reference_selected).bind(outbound_tree));
  176. TreeItem *ob_root = outbound_tree->create_item();
  177. for (const KeyValue<String, ObjectID> &ob : d->outbound_references) {
  178. TreeItem *i = outbound_tree->create_item(ob_root);
  179. i->set_auto_translate_mode(0, AUTO_TRANSLATE_MODE_DISABLED);
  180. i->set_auto_translate_mode(1, AUTO_TRANSLATE_MODE_DISABLED);
  181. SnapshotDataObject *target = d->snapshot->objects[ob.value];
  182. i->set_text(0, ob.key);
  183. i->set_text(1, target->get_name());
  184. reference_item_map[i] = data_item_map[target];
  185. }
  186. }
  187. void SnapshotObjectView::_reference_selected(Tree *p_source_tree) {
  188. TreeItem *ref_item = p_source_tree->get_selected();
  189. Tree *other_tree = p_source_tree == inbound_tree ? outbound_tree : inbound_tree;
  190. other_tree->deselect_all();
  191. TreeItem *other = reference_item_map[ref_item];
  192. if (other) {
  193. if (!other->is_visible()) {
  194. // Clear the filter if we can't see the node we just chose.
  195. filter_bar->clear_filter();
  196. }
  197. other->get_tree()->deselect_all();
  198. other->get_tree()->set_selected(other);
  199. other->get_tree()->ensure_cursor_is_visible();
  200. }
  201. }
  202. Tree *SnapshotObjectView::_make_references_list(Control *p_container, const String &p_name, const String &p_col_1, const String &p_col_1_tooltip, const String &p_col_2, const String &p_col_2_tooltip) {
  203. VBoxContainer *vbox = memnew(VBoxContainer);
  204. vbox->set_h_size_flags(SizeFlags::SIZE_EXPAND_FILL);
  205. vbox->set_v_size_flags(SizeFlags::SIZE_EXPAND_FILL);
  206. vbox->add_theme_constant_override("separation", 4);
  207. p_container->add_child(vbox);
  208. vbox->set_custom_minimum_size(Vector2(300, 0) * EDSCALE);
  209. RichTextLabel *lbl = memnew(RichTextLabel("[center]" + p_name + "[center]"));
  210. lbl->set_fit_content(true);
  211. lbl->set_use_bbcode(true);
  212. vbox->add_child(lbl);
  213. Tree *tree = memnew(Tree);
  214. tree->set_hide_folding(true);
  215. vbox->add_child(tree);
  216. tree->set_select_mode(Tree::SelectMode::SELECT_ROW);
  217. tree->set_hide_root(true);
  218. tree->set_columns(2);
  219. tree->set_column_titles_visible(true);
  220. tree->set_column_title(0, p_col_1);
  221. tree->set_column_expand(0, true);
  222. tree->set_column_title_tooltip_text(0, p_col_1_tooltip);
  223. tree->set_column_clip_content(0, false);
  224. tree->set_column_title(1, p_col_2);
  225. tree->set_column_expand(1, true);
  226. tree->set_column_clip_content(1, false);
  227. tree->set_column_title_tooltip_text(1, p_col_2_tooltip);
  228. tree->set_v_scroll_enabled(false);
  229. tree->set_h_size_flags(SizeFlags::SIZE_EXPAND_FILL);
  230. return tree;
  231. }