Blender V5.0
spreadsheet_dataset_draw.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
5#include <fmt/format.h>
6
7#include "BLI_listbase.h"
8#include "BLI_string.h"
9
10#include "DNA_curves_types.h"
11#include "DNA_mesh_types.h"
13#include "DNA_space_types.h"
15
16#include "BKE_context.hh"
17#include "BKE_curves.hh"
18#include "BKE_grease_pencil.hh"
19#include "BKE_instances.hh"
20#include "BKE_lib_id.hh"
21#include "BKE_volume.hh"
22
23#include "RNA_access.hh"
24#include "RNA_prototypes.hh"
25
27#include "UI_tree_view.hh"
28
29#include "WM_api.hh"
30#include "WM_types.hh"
31
32#include "BLT_translation.hh"
33
34#include "ED_outliner.hh"
35#include "ED_spreadsheet.hh"
36
40
43#include "spreadsheet_intern.hh"
44
46
49
52 std::optional<int> layer_index;
53 std::optional<bke::AttrDomain> domain;
54};
55
57{
58 /* Using the tree row button instead of a separate right aligned button gives padding
59 * to the right side of the number, which it didn't have with the button. */
60 UI_but_hint_drawstr_set(reinterpret_cast<uiBut *>(view_item.view_item_button()), str.c_str());
61}
62
63static void draw_count(ui::AbstractTreeViewItem &view_item, const int count)
64{
66 BLI_str_format_decimal_unit(element_count, count);
67 draw_row_suffix(view_item, element_count);
68}
69
71{
72 switch (domain) {
74 return IFACE_("Vertex");
76 return IFACE_("Edge");
78 return IFACE_("Face");
80 return IFACE_("Face Corner");
81 default:
83 return "";
84 }
85}
86
88{
89 switch (domain) {
91 return IFACE_("Control Point");
93 return IFACE_("Spline");
94 default:
96 return "";
97 }
98}
99
101{
102 switch (domain) {
104 return ICON_VERTEXSEL;
106 return ICON_EDGESEL;
108 return ICON_FACESEL;
110 return ICON_FACE_CORNER;
111 default:
113 return ICON_NONE;
114 }
115}
116
118{
119 switch (domain) {
121 return ICON_CURVE_BEZCIRCLE;
123 return ICON_CURVE_PATH;
124 default:
126 return ICON_NONE;
127 }
128}
129
131 public:
133
134 void get_parent_instance_ids(Vector<SpreadsheetInstanceID> &r_instance_ids) const;
135
136 void on_activate(bContext &C) override;
137
138 std::optional<bool> should_be_active() const override;
139};
140
142 public:
144 {
145 label_ = geometry.name.empty() ? IFACE_("(Geometry)") : geometry.name;
146 }
147
148 void build_row(uiLayout &row) override
149 {
150 row.label(label_, ICON_GEOMETRY_SET);
151 }
152};
153
155 private:
156 const bke::InstanceReference &reference_;
157 int reference_index_;
158 int user_count_;
159
160 public:
162 : reference_(instances.references()[reference_index]), reference_index_(reference_index)
163 {
164 label_ = std::to_string(reference_index);
165 user_count_ = instances.reference_user_counts()[reference_index];
166 }
167
168 void build_row(uiLayout &row) override
169 {
170 const int icon = get_instance_reference_icon(reference_);
171 StringRefNull name = reference_.name();
172 if (name.is_empty()) {
173 name = IFACE_("(Geometry)");
174 }
175 row.label(name, icon);
176 draw_count(*this, user_count_);
177 }
178
179 int reference_index() const
180 {
181 return reference_index_;
182 }
183};
184
186 private:
187 ResourceScope scope_;
188 bke::GeometrySet root_geometry_set_;
189 SpaceSpreadsheet &sspreadsheet_;
190 bScreen &screen_;
191
193
194 public:
196 : root_geometry_set_(std::move(geometry_set)),
197 sspreadsheet_(*CTX_wm_space_spreadsheet(&C)),
198 screen_(*CTX_wm_screen(&C))
199 {
200 }
201
202 void build_tree() override
203 {
204 auto &root_item = this->add_tree_item<RootGeometryViewItem>(root_geometry_set_);
205 root_item.uncollapse_by_default();
206 if (const bke::Instances *instances = root_geometry_set_.get_instances()) {
207 this->build_tree_for_instances(root_item, *instances);
208 }
209 }
210
212 {
213 const Span<bke::InstanceReference> references = instances.references();
214 for (const int reference_i : references.index_range()) {
215 auto &reference_item = parent.add_tree_item<InstanceReferenceViewItem>(instances,
216 reference_i);
217 const bke::InstanceReference &reference = references[reference_i];
218 bke::GeometrySet &reference_geometry = scope_.construct<bke::GeometrySet>();
219 reference.to_geometry_set(reference_geometry);
220 if (const bke::Instances *child_instances = reference_geometry.get_instances()) {
221 this->build_tree_for_instances(reference_item, *child_instances);
222 }
223 }
224 }
225};
226
228 public:
230
231 void on_activate(bContext &C) override;
232
233 std::optional<bool> should_be_active() const override;
234
236 virtual std::optional<GeometryDataIdentifier> get_geometry_data_id() const
237 {
238 return std::nullopt;
239 }
240};
241
243 private:
244 bool has_mesh_;
245
246 public:
247 MeshViewItem(const bool has_mesh) : has_mesh_(has_mesh)
248 {
249 label_ = IFACE_("Mesh");
250 }
251
252 void build_row(uiLayout &row) override
253 {
254 if (!has_mesh_) {
255 row.active_set(false);
256 }
257 row.label(label_, ICON_MESH_DATA);
258 }
259};
260
262 private:
263 const Mesh *mesh_;
264 bke::AttrDomain domain_;
265
266 public:
267 MeshDomainViewItem(const Mesh *mesh, const bke::AttrDomain domain) : mesh_(mesh), domain_(domain)
268 {
270 }
271
272 std::optional<GeometryDataIdentifier> get_geometry_data_id() const override
273 {
274 return GeometryDataIdentifier{bke::GeometryComponent::Type::Mesh, std::nullopt, domain_};
275 }
276
277 void build_row(uiLayout &row) override
278 {
279 const BIFIconID icon = mesh_domain_to_icon(domain_);
280 row.label(label_, icon);
281
282 const int count = mesh_ ? mesh_->attributes().domain_size(domain_) : 0;
283 draw_count(*this, count);
284 }
285};
286
288 private:
289 bool has_curves_;
290
291 public:
292 CurvesViewItem(const bool has_curves) : has_curves_(has_curves)
293 {
294 label_ = IFACE_("Curve");
295 }
296
297 void build_row(uiLayout &row) override
298 {
299 if (!has_curves_) {
300 row.active_set(false);
301 }
302 row.label(label_, ICON_CURVE_DATA);
303 }
304};
305
307 private:
308 const Curves *curves_;
309 bke::AttrDomain domain_;
310
311 public:
313 : curves_(curves), domain_(domain)
314 {
316 }
317
318 std::optional<GeometryDataIdentifier> get_geometry_data_id() const override
319 {
320 return GeometryDataIdentifier{bke::GeometryComponent::Type::Curve, std::nullopt, domain_};
321 }
322
323 void build_row(uiLayout &row) override
324 {
325 const BIFIconID icon = curves_domain_to_icon(domain_);
326 row.label(label_, icon);
327
328 const int count = curves_ ? curves_->geometry.wrap().attributes().domain_size(domain_) : 0;
329 draw_count(*this, count);
330 }
331};
332
334 bool has_grease_pencil_;
335
336 public:
337 GreasePencilViewItem(const bool has_grease_pencil) : has_grease_pencil_(has_grease_pencil)
338 {
339 label_ = IFACE_("Grease Pencil");
340 }
341
342 void build_row(uiLayout &row) override
343 {
344 if (!has_grease_pencil_) {
345 row.active_set(false);
346 }
347 row.label(label_, ICON_OUTLINER_DATA_GREASEPENCIL);
348 }
349};
350
352 private:
353 const GreasePencil *grease_pencil_;
354
355 public:
356 GreasePencilLayersViewItem(const GreasePencil *grease_pencil) : grease_pencil_(grease_pencil)
357 {
358 label_ = IFACE_("Layer");
359 }
360
361 std::optional<GeometryDataIdentifier> get_geometry_data_id() const override
362 {
365 }
366
367 void build_row(uiLayout &row) override
368 {
369 const int count = grease_pencil_ ? grease_pencil_->layers().size() : 0;
370 row.label(label_, ICON_OUTLINER_DATA_GP_LAYER);
371 draw_count(*this, count);
372 }
373};
374
376 private:
377 const bke::greasepencil::Layer &layer_;
378
379 public:
380 GreasePencilLayerViewItem(const GreasePencil &grease_pencil, const int layer_index)
381 : layer_(grease_pencil.layer(layer_index))
382 {
383 label_ = std::to_string(layer_index);
384 }
385
386 void build_row(uiLayout &row) override
387 {
388 StringRefNull name = layer_.name();
389 if (name.is_empty()) {
390 name = IFACE_("(Layer)");
391 }
392 row.label(name, ICON_CURVE_DATA);
393 }
394};
395
397 private:
398 const GreasePencil &grease_pencil_;
399 int layer_index_;
400 bke::AttrDomain domain_;
401
402 public:
404 const int layer_index,
405 const bke::AttrDomain domain)
406 : grease_pencil_(grease_pencil), layer_index_(layer_index), domain_(domain)
407 {
409 }
410
411 std::optional<GeometryDataIdentifier> get_geometry_data_id() const override
412 {
414 bke::GeometryComponent::Type::GreasePencil, layer_index_, domain_};
415 }
416
417 void build_row(uiLayout &row) override
418 {
419 const BIFIconID icon = curves_domain_to_icon(domain_);
420 row.label(label_, icon);
421
422 const bke::greasepencil::Drawing *drawing = grease_pencil_.get_eval_drawing(
423 grease_pencil_.layer(layer_index_));
424 const int count = drawing ? drawing->strokes().attributes().domain_size(domain_) : 0;
425 draw_count(*this, count);
426 }
427};
428
430 private:
431 bool has_pointcloud_;
432
433 public:
434 PointCloudViewItem(const bool has_pointcloud) : has_pointcloud_(has_pointcloud)
435 {
436 label_ = IFACE_("Point Cloud");
437 }
438
439 void build_row(uiLayout &row) override
440 {
441 if (!has_pointcloud_) {
442 row.active_set(false);
443 }
444 row.label(label_, ICON_POINTCLOUD_DATA);
445 }
446};
447
449 private:
450 const PointCloud *pointcloud_;
451
452 public:
454 {
455 label_ = IFACE_("Point");
456 }
457
458 std::optional<GeometryDataIdentifier> get_geometry_data_id() const override
459 {
462 }
463
464 void build_row(uiLayout &row) override
465 {
466 row.label(label_, ICON_POINTCLOUD_POINT);
467 const int count = pointcloud_ ? pointcloud_->totpoint : 0;
468 draw_count(*this, count);
469 }
470};
471
473 private:
474 const Volume *volume_;
475
476 public:
477 VolumeGridsViewItem(const Volume *volume) : volume_(volume)
478 {
479 label_ = IFACE_("Volume Grids");
480 }
481
482 std::optional<GeometryDataIdentifier> get_geometry_data_id() const override
483 {
485 bke::GeometryComponent::Type::Volume, std::nullopt, std::nullopt};
486 }
487
488 void build_row(uiLayout &row) override
489 {
490 if (!volume_) {
491 row.active_set(false);
492 }
493 row.label(label_, ICON_VOLUME_DATA);
494 if (volume_) {
495 draw_count(*this, BKE_volume_num_grids(volume_));
496 }
497 }
498};
499
501 private:
502 const bke::Instances *instances_;
503
504 public:
505 InstancesViewItem(const bke::Instances *instances) : instances_(instances)
506 {
507 label_ = IFACE_("Instances");
508 }
509
510 std::optional<GeometryDataIdentifier> get_geometry_data_id() const override
511 {
514 }
515
516 void build_row(uiLayout &row) override
517 {
518 if (!instances_) {
519 row.active_set(false);
520 }
521 row.label(label_, ICON_EMPTY_AXIS);
522 if (instances_) {
523 draw_count(*this, instances_->instances_num());
524 }
525 }
526};
527
529 private:
530 bke::GeometrySet geometry_set_;
531 SpaceSpreadsheet &sspreadsheet_;
532 bScreen &screen_;
533
534 friend class DataSetViewItem;
535
536 public:
538 : geometry_set_(std::move(geometry_set)),
539 sspreadsheet_(*CTX_wm_space_spreadsheet(&C)),
540 screen_(*CTX_wm_screen(&C))
541 {
542 }
543
544 void build_tree() override
545 {
546 this->build_tree_for_geometry(geometry_set_, *this);
547 }
548
550 {
551 const Mesh *mesh = geometry.get_mesh();
552 this->build_tree_for_mesh(mesh, parent);
553
554 const Curves *curves = geometry.get_curves();
555 this->build_tree_for_curves(curves, parent);
556
557 const GreasePencil *grease_pencil = geometry.get_grease_pencil();
558 this->build_tree_for_grease_pencil(grease_pencil, parent);
559
560 const PointCloud *pointcloud = geometry.get_pointcloud();
561 this->build_tree_for_pointcloud(pointcloud, parent);
562
563 const Volume *volume = geometry.get_volume();
564 this->build_tree_for_volume(volume, parent);
565
566 const bke::Instances *instances = geometry.get_instances();
567 this->build_tree_for_instances(instances, parent);
568 }
569
571 {
572 auto &mesh_item = parent.add_tree_item<MeshViewItem>(mesh != nullptr);
573 mesh_item.uncollapse_by_default();
574 if (!mesh) {
575 return;
576 }
577
578 mesh_item.add_tree_item<MeshDomainViewItem>(mesh, bke::AttrDomain::Point);
582 }
583
585 {
586 auto &curves_item = parent.add_tree_item<CurvesViewItem>(curves != nullptr);
587 curves_item.uncollapse_by_default();
588 if (!curves) {
589 return;
590 }
591
592 curves_item.add_tree_item<CurvesDomainViewItem>(curves, bke::AttrDomain::Point);
594 }
595
598 {
599 auto &grease_pencil_item = parent.add_tree_item<GreasePencilViewItem>(grease_pencil !=
600 nullptr);
601 grease_pencil_item.uncollapse_by_default();
602 if (!grease_pencil) {
603 return;
604 }
605
606 auto &layers_item = grease_pencil_item.add_tree_item<GreasePencilLayersViewItem>(
607 grease_pencil);
608 const Span<const bke::greasepencil::Layer *> layers = grease_pencil->layers();
609 for (const int layer_i : layers.index_range()) {
610 auto &layer_item = layers_item.add_tree_item<GreasePencilLayerViewItem>(*grease_pencil,
611 layer_i);
613 *grease_pencil, layer_i, bke::AttrDomain::Point);
615 *grease_pencil, layer_i, bke::AttrDomain::Curve);
616 }
617 }
618
620 {
621 auto &pointcloud_item = parent.add_tree_item<PointCloudViewItem>(pointcloud != nullptr);
622 pointcloud_item.uncollapse_by_default();
623 if (!pointcloud) {
624 return;
625 }
626
627 pointcloud_item.add_tree_item<PointsViewItem>(pointcloud);
628 }
629
631 {
632 parent.add_tree_item<VolumeGridsViewItem>(volume);
633 }
634
636 {
637 parent.add_tree_item<InstancesViewItem>(instances);
638 }
639};
640
642{
643 return static_cast<GeometryDataSetTreeView &>(this->get_tree_view());
644}
645
650
652 Vector<SpreadsheetInstanceID> &r_instance_ids) const
653{
654 if (const auto *reference_item = dynamic_cast<const InstanceReferenceViewItem *>(this)) {
655 r_instance_ids.append({reference_item->reference_index()});
656 }
657 this->foreach_parent([&](const ui::AbstractTreeViewItem &item) {
658 if (const auto *reference_item = dynamic_cast<const InstanceReferenceViewItem *>(&item)) {
659 r_instance_ids.append({reference_item->reference_index()});
660 }
661 });
662 std::reverse(r_instance_ids.begin(), r_instance_ids.end());
663}
664
666{
667 GeometryInstancesTreeView &tree_view = this->get_tree();
668 SpaceSpreadsheet &sspreadsheet = tree_view.sspreadsheet_;
669
671 this->get_parent_instance_ids(instance_ids);
672 if (sspreadsheet.geometry_id.instance_ids_num != instance_ids.size()) {
673 return false;
674 }
675 for (const int i : instance_ids.index_range()) {
676 const SpreadsheetInstanceID &a = sspreadsheet.geometry_id.instance_ids[i];
677 const SpreadsheetInstanceID &b = instance_ids[i];
678 if (a.reference_index != b.reference_index) {
679 return false;
680 }
681 }
682 return true;
683}
684
686{
688 this->get_parent_instance_ids(instance_ids);
689
691
694 instance_ids.size(), __func__);
695 sspreadsheet.geometry_id.instance_ids_num = instance_ids.size();
697 instance_ids.data(), instance_ids.size(), sspreadsheet.geometry_id.instance_ids);
698
700}
701
703{
704 std::optional<GeometryDataIdentifier> data_id = this->get_geometry_data_id();
705 if (!data_id) {
706 this->foreach_item_recursive([&](const ui::AbstractTreeViewItem &item) {
707 if (data_id) {
708 return;
709 }
710 if (const auto *data_set_view_item = dynamic_cast<const DataSetViewItem *>(&item)) {
711 data_id = data_set_view_item->get_geometry_data_id();
712 }
713 });
714 if (!data_id) {
715 return;
716 }
717 }
718
719 bScreen &screen = *CTX_wm_screen(&C);
721
722 sspreadsheet.geometry_id.geometry_component_type = uint8_t(data_id->component_type);
723 if (data_id->domain) {
724 sspreadsheet.geometry_id.attribute_domain = uint8_t(*data_id->domain);
725 }
726 if (data_id->layer_index) {
727 sspreadsheet.geometry_id.layer_index = *data_id->layer_index;
728 }
729 PointerRNA ptr = RNA_pointer_create_discrete(&screen.id, &RNA_SpaceSpreadsheet, &sspreadsheet);
730 /* These updates also make sure that the attribute domain is set properly based on the
731 * component type. */
732 RNA_property_update(&C, &ptr, RNA_struct_find_property(&ptr, "attribute_domain"));
733 RNA_property_update(&C, &ptr, RNA_struct_find_property(&ptr, "geometry_component_type"));
734}
735
736std::optional<bool> DataSetViewItem::should_be_active() const
737{
738 GeometryDataSetTreeView &tree_view = this->get_tree();
739 SpaceSpreadsheet &sspreadsheet = tree_view.sspreadsheet_;
740
741 const std::optional<GeometryDataIdentifier> data_id = this->get_geometry_data_id();
742 if (!data_id) {
743 return false;
744 }
746 data_id->component_type)
747 {
748 return false;
749 }
750 if (data_id->domain) {
751 if (bke::AttrDomain(sspreadsheet.geometry_id.attribute_domain) != data_id->domain) {
752 return false;
753 }
754 }
755 if (data_id->layer_index) {
756 if (sspreadsheet.geometry_id.layer_index != *data_id->layer_index) {
757 return false;
758 }
759 }
760 return true;
761}
762
764 private:
765 int viewer_path_index_;
766
767 public:
768 ViewerPathTreeViewItem(int viewer_path_index) : viewer_path_index_(viewer_path_index) {}
769
770 void on_activate(bContext &C) override;
771 std::optional<bool> should_be_active() const override;
772};
773
775 const IDViewerPathElem &id_elem_;
776
777 public:
778 IDViewerPathItem(const int viewer_path_index, const IDViewerPathElem &id_elem)
779 : ViewerPathTreeViewItem(viewer_path_index), id_elem_(id_elem)
780 {
781 label_ = id_elem.id ? id_elem.id->name + 2 : IFACE_("No Data-Block");
782 }
783
784 void build_row(uiLayout &row) override
785 {
786 if (id_elem_.id) {
787 const int icon = ED_outliner_icon_from_id(*id_elem_.id);
788 row.label(BKE_id_name(*id_elem_.id), icon);
789 }
790 else {
791 row.label(IFACE_("No Data-Block"), ICON_BLANK1);
792 }
793 }
794};
795
797 const ModifierViewerPathElem &modifier_elem_;
798
799 public:
800 ModifierViewerPathItem(const int viewer_path_index, const ModifierViewerPathElem &modifier_elem)
801 : ViewerPathTreeViewItem(viewer_path_index), modifier_elem_(modifier_elem)
802 {
803 label_ = modifier_elem.base.ui_name;
804 }
805
806 void build_row(uiLayout &row) override
807 {
808 row.label(modifier_elem_.base.ui_name, ICON_MODIFIER);
809 }
810};
811
813 const GroupNodeViewerPathElem &group_node_elem_;
814
815 public:
816 GroupNodeViewerPathItem(const int viewer_path_index,
817 const GroupNodeViewerPathElem &group_node_elem)
818 : ViewerPathTreeViewItem(viewer_path_index), group_node_elem_(group_node_elem)
819 {
820 label_ = group_node_elem.base.ui_name;
821 }
822
823 void build_row(uiLayout &row) override
824 {
825 row.label(group_node_elem_.base.ui_name, ICON_NODE);
826 }
827};
828
830 const ViewerNodeViewerPathElem &viewer_node_elem_;
831
832 public:
833 ViewerNodeViewerPathItem(const int viewer_path_index,
834 const ViewerNodeViewerPathElem &viewer_node_elem)
835 : ViewerPathTreeViewItem(viewer_path_index), viewer_node_elem_(viewer_node_elem)
836 {
837 label_ = viewer_node_elem.base.ui_name;
838 }
839
840 void build_row(uiLayout &row) override
841 {
842 row.label(viewer_node_elem_.base.ui_name, ICON_RESTRICT_VIEW_OFF);
843 }
844};
845
847
848 public:
849 SimulationViewerPathPathItem(const int viewer_path_index,
850 const SimulationZoneViewerPathElem & /*simulation_zone_elem*/)
851 : ViewerPathTreeViewItem(viewer_path_index)
852 {
853 label_ = IFACE_("Simulation");
854 }
855
856 void build_row(uiLayout &row) override
857 {
858 row.label(label_, ICON_BLANK1);
859 }
860};
861
863 private:
864 const RepeatZoneViewerPathElem &repeat_zone_;
865
866 public:
867 RepeatViewerPathItem(const int viewer_path_index, const RepeatZoneViewerPathElem &repeat_zone)
868 : ViewerPathTreeViewItem(viewer_path_index), repeat_zone_(repeat_zone)
869 {
870 label_ = IFACE_("Repeat");
871 }
872
873 void build_row(uiLayout &row) override
874 {
875 row.label(label_, ICON_BLANK1);
876 draw_row_suffix(*this, std::to_string(repeat_zone_.iteration));
877 }
878};
879
881 private:
882 const ForeachGeometryElementZoneViewerPathElem &foreach_geo_elem_zone_;
883
884 public:
886 const int viewer_path_index,
887 const ForeachGeometryElementZoneViewerPathElem &foreach_geo_elem_zone)
888 : ViewerPathTreeViewItem(viewer_path_index), foreach_geo_elem_zone_(foreach_geo_elem_zone)
889 {
890 label_ = IFACE_("For Each Element");
891 }
892
893 void build_row(uiLayout &row) override
894 {
895 row.label(label_, ICON_BLANK1);
896 draw_row_suffix(*this, std::to_string(foreach_geo_elem_zone_.index));
897 }
898};
899
901 public:
902 EvaluteClosureViewerPathItem(const int viewer_path_index,
903 const EvaluateClosureNodeViewerPathElem & /*evalute_closure_elem*/)
904 : ViewerPathTreeViewItem(viewer_path_index)
905 {
906 label_ = IFACE_("Evaluate Closure");
907 }
908
909 void build_row(uiLayout &row) override
910 {
911 row.label(label_, ICON_BLANK1);
912 }
913};
914
916 private:
917 SpaceSpreadsheet &sspreadsheet_;
918 bScreen &screen_;
919
920 friend ViewerPathTreeViewItem;
921
922 public:
924 : sspreadsheet_(*CTX_wm_space_spreadsheet(&C)), screen_(*CTX_wm_screen(&C))
925 {
926 /* This tree view contains only a flat list of items without. */
927 is_flat_ = true;
928 }
929
930 void build_tree() override
931 {
932 const ViewerPath &viewer_path = sspreadsheet_.geometry_id.viewer_path;
933
934 int index;
935 LISTBASE_FOREACH_INDEX (const ViewerPathElem *, elem, &viewer_path.path, index) {
936 if (elem == viewer_path.path.first) {
937 /* The root item is drawn above the tree view already. */
938 continue;
939 }
940 this->add_viewer_path_elem(index, *elem);
941 }
942 }
943
944 void add_viewer_path_elem(const int index, const ViewerPathElem &elem)
945 {
946 switch (ViewerPathElemType(elem.type)) {
949 reinterpret_cast<const IDViewerPathElem &>(elem));
950 break;
951 }
954 index, reinterpret_cast<const ModifierViewerPathElem &>(elem));
955 break;
956 }
959 index, reinterpret_cast<const GroupNodeViewerPathElem &>(elem));
960 break;
961 }
964 index, reinterpret_cast<const ViewerNodeViewerPathElem &>(elem));
965 break;
966 }
969 index, reinterpret_cast<const SimulationZoneViewerPathElem &>(elem));
970 break;
971 }
974 index, reinterpret_cast<const RepeatZoneViewerPathElem &>(elem));
975 break;
976 }
979 index, reinterpret_cast<const ForeachGeometryElementZoneViewerPathElem &>(elem));
980 break;
981 }
984 index, reinterpret_cast<const EvaluateClosureNodeViewerPathElem &>(elem));
985 break;
986 }
987 }
988 }
989};
990
997
999{
1000 /* Can use SpaceSpreadsheet.active_viewer_path_index once selection is used. */
1001 return false;
1002}
1003
1005 public:
1007 {
1009 this->foreach_parent([&](const ui::AbstractTreeViewItem &parent) {
1010 items.append(dynamic_cast<const ViewerDataTreeItem *>(&parent));
1011 });
1012 items.as_mutable_span().reverse();
1013 items.append(this);
1014 return items;
1015 }
1016
1017 void on_activate(bContext &C) override;
1018 std::optional<bool> should_be_active() const override;
1019};
1020
1026
1027 ViewerDataPath() = default;
1029 : viewer_item(table_id.viewer_item_identifier)
1030 {
1031 for (const auto &elem : Span(table_id.bundle_path, table_id.bundle_path_num)) {
1032 this->bundles.append(elem.identifier);
1033 }
1034 this->closure_input_output = SpreadsheetClosureInputOutput(table_id.closure_input_output);
1035 }
1036
1037 explicit ViewerDataPath(const Span<const ViewerDataTreeItem *> tree_items);
1038
1040 {
1041 table_id.viewer_item_identifier = this->viewer_item;
1042 if (table_id.bundle_path) {
1043 for (const int i : IndexRange(table_id.bundle_path_num)) {
1044 MEM_freeN(table_id.bundle_path[i].identifier);
1045 }
1046 MEM_freeN(table_id.bundle_path);
1047 }
1049 __func__);
1050 table_id.bundle_path_num = this->bundles.size();
1051 for (const int i : this->bundles.index_range()) {
1052 table_id.bundle_path[i].identifier = BLI_strdupn(this->bundles[i].data(),
1053 this->bundles[i].size());
1054 }
1055 table_id.closure_input_output = int8_t(this->closure_input_output);
1056 }
1057};
1058
1060 private:
1062
1063 friend ViewerDataPath;
1064
1065 public:
1067 {
1068 label_ = std::to_string(item.identifier);
1069 }
1070
1071 void build_row(uiLayout &row) override
1072 {
1073 row.label(item_.name, ICON_NONE);
1074 }
1075};
1076
1078 friend ViewerDataPath;
1079
1080 public:
1082 {
1083 label_ = key;
1084 }
1085
1086 void build_row(uiLayout &row) override
1087 {
1088 row.label(label_, ICON_NONE);
1089 }
1090};
1091
1093 private:
1095
1096 friend ViewerDataPath;
1097
1098 public:
1100 {
1101 label_ = in_out_ == SPREADSHEET_CLOSURE_INPUT ? IFACE_("Inputs") : IFACE_("Outputs");
1102 }
1103
1104 void build_row(uiLayout &row) override
1105 {
1106 row.label(label_, ICON_NONE);
1107 }
1108};
1109
1111{
1112 for (const ViewerDataTreeItem *item : tree_items) {
1113 if (const auto *viewer_node_item = dynamic_cast<const ViewerNodeItem *>(item)) {
1114 this->viewer_item = viewer_node_item->item_.identifier;
1115 }
1116 else if (const auto *bundle_item = dynamic_cast<const BundleItem *>(item)) {
1117 this->bundles.append(bundle_item->label_);
1118 }
1119 else if (const auto *bundle_item = dynamic_cast<const ClosureInputOutputItem *>(item)) {
1120 this->closure_input_output = bundle_item->in_out_;
1121 }
1122 }
1123}
1124
1126 private:
1127 SpaceSpreadsheet &sspreadsheet_;
1128
1129 friend ViewerDataTreeItem;
1130
1131 public:
1133
1134 void build_tree() override
1135 {
1137 if (!log) {
1138 return;
1139 }
1140 for (const nodes::geo_eval_log::ViewerNodeLog::Item &item : log->items) {
1141 const bke::SocketValueVariant &value = item.value;
1142 auto &child_item = this->add_tree_item<ViewerNodeItem>(item);
1143 this->build_value(child_item, value);
1144 }
1145 }
1146
1148 {
1149 if (!value.is_single()) {
1150 return;
1151 }
1152 const GPointer single_value = value.get_single_ptr();
1153 if (single_value.is_type<nodes::BundlePtr>()) {
1154 const nodes::BundlePtr &bundle_ptr = *single_value.get<nodes::BundlePtr>();
1155 if (bundle_ptr) {
1156 this->build_bundle_children(parent, *bundle_ptr);
1157 }
1158 }
1159 if (single_value.is_type<nodes::ClosurePtr>()) {
1160 const nodes::ClosurePtr &closure_ptr = *single_value.get<nodes::ClosurePtr>();
1161 if (closure_ptr) {
1162 this->build_closure_children(parent, closure_ptr);
1163 }
1164 }
1165 }
1166
1168 {
1169 for (const nodes::Bundle::StoredItem &item : bundle.items()) {
1170 auto &child_item = parent.add_tree_item<BundleItem>(item.key);
1171 const auto *stored_value = std::get_if<nodes::BundleItemSocketValue>(&item.value.value);
1172 if (!stored_value) {
1173 continue;
1174 }
1175 this->build_value(child_item, stored_value->value);
1176 }
1177 }
1178
1180 {
1181 const nodes::ClosureSignature &signature = closure->signature();
1182 if (!signature.inputs.is_empty()) {
1184 }
1185 if (!signature.outputs.is_empty()) {
1187 }
1188 }
1189};
1190
1192{
1193 const auto &tree = static_cast<const ViewerDataTreeView &>(this->get_tree_view());
1194 SpaceSpreadsheet &sspreadsheet = tree.sspreadsheet_;
1195 SpreadsheetTableIDGeometry &table_id = sspreadsheet.geometry_id;
1196 ViewerDataPath(this->items_path()).store(table_id);
1198}
1199
1200std::optional<bool> ViewerDataTreeItem::should_be_active() const
1201{
1202 const auto &tree = static_cast<const ViewerDataTreeView &>(this->get_tree_view());
1203 const SpaceSpreadsheet &sspreadsheet = tree.sspreadsheet_;
1204 const SpreadsheetTableIDGeometry &table_id = sspreadsheet.geometry_id;
1205 return ViewerDataPath(table_id) == ViewerDataPath(this->items_path());
1206}
1207
1209{
1210 layout.label(IFACE_("No Active Context"), ICON_NONE);
1211}
1212
1214{
1216 return false;
1217 }
1218 const ViewerPathElem &last_elem = *static_cast<const ViewerPathElem *>(viewer_path.path.last);
1220}
1221
1222static void draw_viewer_path_panel(const bContext &C, uiLayout &layout)
1223{
1224 uiBlock *block = layout.block();
1226 *block, "Viewer Path", std::make_unique<ViewerPathTreeView>(C));
1227 tree_view->set_context_menu_title("Viewer Path");
1228 ui::TreeViewBuilder::build_tree_view(C, *tree_view, layout, true);
1229}
1230
1231static void draw_viewer_data_panel(const bContext &C, uiLayout &layout)
1232{
1233 uiBlock *block = layout.block();
1235 *block, "Viewer Data", std::make_unique<ViewerDataTreeView>(C));
1236 tree_view->set_context_menu_title("Viewer Data");
1237 ui::TreeViewBuilder::build_tree_view(C, *tree_view, layout, false);
1238}
1239
1240static void draw_context_panel_content(const bContext &C, uiLayout &layout)
1241{
1242 bScreen &screen = *CTX_wm_screen(&C);
1244
1246 ID *root_id = get_current_id(sspreadsheet);
1247 if (!root_id) {
1249 return;
1250 }
1251 if (GS(root_id->name) != ID_OB) {
1253 return;
1254 }
1255
1256 PointerRNA sspreadsheet_ptr = RNA_pointer_create_discrete(
1257 &screen.id, &RNA_SpaceSpreadsheet, sspreadsheet);
1258
1259 layout.prop(&sspreadsheet_ptr, "object_eval_state", UI_ITEM_NONE, "", ICON_NONE);
1260
1263 {
1264 if (uiLayout *panel = layout.panel(&C, "viewer path", true, IFACE_("Viewer Path"))) {
1265 draw_viewer_path_panel(C, *panel);
1266 }
1267 if (uiLayout *panel = layout.panel(&C, "viewer data", true, IFACE_("Viewer Data"))) {
1268 draw_viewer_data_panel(C, *panel);
1269 }
1270 }
1271}
1272
1273static void draw_context_panel(const bContext &C, uiLayout &layout)
1274{
1275 SpaceSpreadsheet &sspreadsheet = *CTX_wm_space_spreadsheet(&C);
1276
1277 PanelLayout context_panel = layout.panel(&C, "context", false);
1278 context_panel.header->emboss_set(ui::EmbossType::None);
1279 if (ID *root_id = get_current_id(&sspreadsheet)) {
1280 std::string label = BKE_id_name(*root_id);
1281 if (!context_panel.body) {
1282 switch (sspreadsheet.geometry_id.object_eval_state) {
1284 label += " (Evaluated)";
1285 break;
1287 label += " (Original)";
1288 break;
1290 label += " (Viewer)";
1291 break;
1292 }
1293 }
1294 context_panel.header->label(label, ICON_OBJECT_DATA);
1295 }
1296 else {
1297 context_panel.header->label(IFACE_("Context"), ICON_NONE);
1298 }
1299 context_panel.header->op("spreadsheet.toggle_pin",
1300 "",
1301 sspreadsheet.flag & SPREADSHEET_FLAG_PINNED ? ICON_PINNED :
1302 ICON_UNPINNED);
1303 if (context_panel.body) {
1304 draw_context_panel_content(C, *context_panel.body);
1305 }
1306}
1307
1309{
1311
1312 uiLayout *layout = panel->layout;
1313 uiBlock *block = layout->block();
1314 ui::block_layout_set_current(block, layout);
1315
1316 draw_context_panel(*C, *layout);
1317
1319 if (!object) {
1320 return;
1321 }
1322
1323 if (const std::optional<bke::GeometrySet> root_geometry = root_geometry_set_get(sspreadsheet,
1324 object))
1325 {
1326 if (uiLayout *panel = layout->panel(C, "instance tree", false, IFACE_("Geometry"))) {
1328 *block,
1329 "Instances Tree View",
1330 std::make_unique<GeometryInstancesTreeView>(*root_geometry, *C));
1331 tree_view->set_context_menu_title("Instance");
1332 ui::TreeViewBuilder::build_tree_view(*C, *tree_view, *panel, false);
1333 }
1334 if (uiLayout *panel = layout->panel(C, "geometry_domain_tree_view", false, IFACE_("Domain"))) {
1336 *root_geometry,
1337 {sspreadsheet->geometry_id.instance_ids, sspreadsheet->geometry_id.instance_ids_num});
1339 *block,
1340 "Data Set Tree View",
1341 std::make_unique<GeometryDataSetTreeView>(std::move(instance_geometry), *C));
1342 tree_view->set_context_menu_title("Domain");
1343 ui::TreeViewBuilder::build_tree_view(*C, *tree_view, *panel, false);
1344 }
1345 }
1346}
1347
1348} // namespace blender::ed::spreadsheet
bScreen * CTX_wm_screen(const bContext *C)
Depsgraph * CTX_data_depsgraph_pointer(const bContext *C)
SpaceSpreadsheet * CTX_wm_space_spreadsheet(const bContext *C)
Low-level operations for curves.
Low-level operations for grease pencil.
const char * BKE_id_name(const ID &id)
Volume data-block.
int BKE_volume_num_grids(const Volume *volume)
#define BLI_assert_unreachable()
Definition BLI_assert.h:93
BLI_INLINE bool BLI_listbase_is_empty(const ListBase *lb)
#define LISTBASE_FOREACH_INDEX(type, var, list, index_var)
char * BLI_strdupn(const char *str, size_t len) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
Definition string.cc:30
#define BLI_STR_FORMAT_INT32_DECIMAL_UNIT_SIZE
Definition BLI_string.h:37
void BLI_str_format_decimal_unit(char dst[BLI_STR_FORMAT_INT32_DECIMAL_UNIT_SIZE], int number_to_format) ATTR_NONNULL(1)
Definition string.cc:1270
#define IFACE_(msgid)
@ ID_OB
@ SPREADSHEET_OBJECT_EVAL_STATE_VIEWER_NODE
@ SPREADSHEET_OBJECT_EVAL_STATE_EVALUATED
@ SPREADSHEET_OBJECT_EVAL_STATE_ORIGINAL
@ SPREADSHEET_FLAG_PINNED
SpreadsheetClosureInputOutput
@ SPREADSHEET_CLOSURE_INPUT
@ SPREADSHEET_CLOSURE_OUTPUT
@ SPREADSHEET_CLOSURE_NONE
@ VIEWER_PATH_ELEM_TYPE_GROUP_NODE
@ VIEWER_PATH_ELEM_TYPE_SIMULATION_ZONE
@ VIEWER_PATH_ELEM_TYPE_FOREACH_GEOMETRY_ELEMENT_ZONE
@ VIEWER_PATH_ELEM_TYPE_VIEWER_NODE
@ VIEWER_PATH_ELEM_TYPE_REPEAT_ZONE
@ VIEWER_PATH_ELEM_TYPE_MODIFIER
@ VIEWER_PATH_ELEM_TYPE_EVALUATE_CLOSURE
@ VIEWER_PATH_ELEM_TYPE_ID
int BIFIconID
Definition ED_asset.hh:28
int ED_outliner_icon_from_id(const ID &id)
#define MEM_SAFE_FREE(v)
#define C
Definition RandGen.cpp:29
blender::ui::AbstractGridView * UI_block_add_view(uiBlock &block, blender::StringRef idname, std::unique_ptr< blender::ui::AbstractGridView > grid_view)
void UI_but_hint_drawstr_set(uiBut *but, const char *string)
#define UI_ITEM_NONE
#define ND_SPACE_SPREADSHEET
Definition WM_types.hh:541
#define NC_SPACE
Definition WM_types.hh:392
BMesh const char void * data
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition btDbvt.cpp:52
const void * get() const
constexpr IndexRange index_range() const
Definition BLI_span.hh:401
int64_t size() const
void append(const T &value)
IndexRange index_range() const
MutableSpan< T > as_mutable_span()
int domain_size(const AttrDomain domain) const
AttributeAccessor attributes() const
Span< InstanceReference > references() const
Definition instances.cc:275
Span< int > reference_user_counts() const
Definition instances.cc:488
const bke::CurvesGeometry & strokes() const
ClosureInputOutputItem(const SpreadsheetClosureInputOutput in_out)
CurvesDomainViewItem(const Curves *curves, const bke::AttrDomain domain)
std::optional< GeometryDataIdentifier > get_geometry_data_id() const override
virtual std::optional< GeometryDataIdentifier > get_geometry_data_id() const
std::optional< bool > should_be_active() const override
EvaluteClosureViewerPathItem(const int viewer_path_index, const EvaluateClosureNodeViewerPathElem &)
ForeachElementViewerPathItem(const int viewer_path_index, const ForeachGeometryElementZoneViewerPathElem &foreach_geo_elem_zone)
void build_tree_for_pointcloud(const PointCloud *pointcloud, ui::TreeViewItemContainer &parent)
void build_tree_for_grease_pencil(const GreasePencil *grease_pencil, ui::TreeViewItemContainer &parent)
GeometryDataSetTreeView(bke::GeometrySet geometry_set, const bContext &C)
void build_tree_for_instances(const bke::Instances *instances, ui::TreeViewItemContainer &parent)
void build_tree_for_curves(const Curves *curves, ui::TreeViewItemContainer &parent)
void build_tree_for_volume(const Volume *volume, ui::TreeViewItemContainer &parent)
void build_tree_for_mesh(const Mesh *mesh, ui::TreeViewItemContainer &parent)
void build_tree_for_geometry(const bke::GeometrySet &geometry, ui::TreeViewItemContainer &parent)
GeometryInstancesTreeView(bke::GeometrySet geometry_set, const bContext &C)
void build_tree_for_instances(ui::TreeViewItemContainer &parent, const bke::Instances &instances)
GreasePencilLayerCurvesDomainViewItem(const GreasePencil &grease_pencil, const int layer_index, const bke::AttrDomain domain)
std::optional< GeometryDataIdentifier > get_geometry_data_id() const override
GreasePencilLayerViewItem(const GreasePencil &grease_pencil, const int layer_index)
std::optional< GeometryDataIdentifier > get_geometry_data_id() const override
GroupNodeViewerPathItem(const int viewer_path_index, const GroupNodeViewerPathElem &group_node_elem)
IDViewerPathItem(const int viewer_path_index, const IDViewerPathElem &id_elem)
InstanceReferenceViewItem(const bke::Instances &instances, const int reference_index)
void get_parent_instance_ids(Vector< SpreadsheetInstanceID > &r_instance_ids) const
std::optional< bool > should_be_active() const override
std::optional< GeometryDataIdentifier > get_geometry_data_id() const override
std::optional< GeometryDataIdentifier > get_geometry_data_id() const override
MeshDomainViewItem(const Mesh *mesh, const bke::AttrDomain domain)
ModifierViewerPathItem(const int viewer_path_index, const ModifierViewerPathElem &modifier_elem)
std::optional< GeometryDataIdentifier > get_geometry_data_id() const override
RepeatViewerPathItem(const int viewer_path_index, const RepeatZoneViewerPathElem &repeat_zone)
SimulationViewerPathPathItem(const int viewer_path_index, const SimulationZoneViewerPathElem &)
std::optional< bool > should_be_active() const override
Vector< const ViewerDataTreeItem * > items_path() const
void build_closure_children(ui::AbstractTreeViewItem &parent, const nodes::ClosurePtr &closure)
void build_bundle_children(ui::AbstractTreeViewItem &parent, const nodes::Bundle &bundle)
void build_value(ui::AbstractTreeViewItem &parent, const bke::SocketValueVariant &value)
ViewerNodeItem(const nodes::geo_eval_log::ViewerNodeLog::Item &item)
ViewerNodeViewerPathItem(const int viewer_path_index, const ViewerNodeViewerPathElem &viewer_node_elem)
std::optional< bool > should_be_active() const override
void add_viewer_path_elem(const int index, const ViewerPathElem &elem)
std::optional< GeometryDataIdentifier > get_geometry_data_id() const override
Span< StoredItem > items() const
CustomIDVectorSet< Item, ItemKeyGetter > inputs
CustomIDVectorSet< Item, ItemKeyGetter > outputs
Abstract base class for defining a customizable tree-view item.
AbstractTreeView & get_tree_view() const
Definition tree_view.cc:644
uiButViewItem * view_item_button() const
void set_context_menu_title(const std::string &title)
static void build_tree_view(const bContext &C, AbstractTreeView &tree_view, uiLayout &layout, bool add_box=true)
ItemT & add_tree_item(Args &&...args)
void foreach_item_recursive(ItemIterFn iter_fn, IterOptions options=IterOptions::None) const
Definition tree_view.cc:74
void foreach_parent(ItemIterFn iter_fn) const
Definition tree_view.cc:94
KDTree_3d * tree
#define str(s)
#define GS(x)
#define log
int count
void * MEM_calloc_arrayN(size_t len, size_t size, const char *str)
Definition mallocn.cc:123
void MEM_freeN(void *vmemh)
Definition mallocn.cc:113
static StringRefNull mesh_domain_to_label(const bke::AttrDomain domain)
static void draw_count(ui::AbstractTreeViewItem &view_item, const int count)
void spreadsheet_data_set_panel_draw(const bContext *C, Panel *panel)
static StringRefNull curves_domain_to_label(const bke::AttrDomain domain)
const nodes::geo_eval_log::ViewerNodeLog * viewer_node_log_lookup(const SpaceSpreadsheet &sspreadsheet)
bke::GeometrySet get_geometry_set_for_instance_ids(const bke::GeometrySet &root_geometry, const Span< SpreadsheetInstanceID > instance_ids)
static void draw_viewer_path_panel(const bContext &C, uiLayout &layout)
static void draw_row_suffix(ui::AbstractTreeViewItem &view_item, const StringRefNull str)
int get_instance_reference_icon(const bke::InstanceReference &reference)
static void draw_viewer_data_panel(const bContext &C, uiLayout &layout)
Object * spreadsheet_get_object_eval(const SpaceSpreadsheet *sspreadsheet, const Depsgraph *depsgraph)
ID * get_current_id(const SpaceSpreadsheet *sspreadsheet)
static bool viewer_path_ends_with_viewer_node(const ViewerPath &viewer_path)
static void draw_context_panel_content(const bContext &C, uiLayout &layout)
static void draw_context_panel_without_context(uiLayout &layout)
std::optional< bke::GeometrySet > root_geometry_set_get(const SpaceSpreadsheet *sspreadsheet, Object *object_eval)
static BIFIconID curves_domain_to_icon(const bke::AttrDomain domain)
static BIFIconID mesh_domain_to_icon(const bke::AttrDomain domain)
static void draw_context_panel(const bContext &C, uiLayout &layout)
ImplicitSharingPtr< Bundle > BundlePtr
ImplicitSharingPtr< Closure > ClosurePtr
void block_layout_set_current(uiBlock *block, uiLayout *layout)
void initialized_copy_n(const T *src, int64_t n, T *dst)
const char * name
PropertyRNA * RNA_struct_find_property(PointerRNA *ptr, const char *identifier)
void RNA_property_update(bContext *C, PointerRNA *ptr, PropertyRNA *prop)
PointerRNA RNA_pointer_create_discrete(ID *id, StructRNA *type, void *data)
Definition DNA_ID.h:414
char name[258]
Definition DNA_ID.h:432
struct uiLayout * layout
SpreadsheetTableIDGeometry geometry_id
SpreadsheetBundlePathElem * bundle_path
SpreadsheetInstanceID * instance_ids
const Instances * get_instances() const
ViewerDataPath(const SpreadsheetTableIDGeometry &table_id)
BLI_STRUCT_EQUALITY_OPERATORS_3(ViewerDataPath, viewer_item, bundles, closure_input_output)
void store(SpreadsheetTableIDGeometry &table_id)
PanelLayout panel(const bContext *C, blender::StringRef idname, bool default_closed)
uiBlock * block() const
void label(blender::StringRef name, int icon)
void active_set(bool active)
void emboss_set(blender::ui::EmbossType emboss)
PointerRNA op(wmOperatorType *ot, std::optional< blender::StringRef > name, int icon, blender::wm::OpCallContext context, eUI_Item_Flag flag)
void prop(PointerRNA *ptr, PropertyRNA *prop, int index, int value, eUI_Item_Flag flag, std::optional< blender::StringRef > name_opt, int icon, std::optional< blender::StringRef > placeholder=std::nullopt)
i
Definition text_draw.cc:230
void WM_main_add_notifier(uint type, void *reference)
PointerRNA * ptr
Definition wm_files.cc:4238