Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender/editors/space_spreadsheet/spreadsheet_dataset_draw.cc')
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_dataset_draw.cc277
1 files changed, 277 insertions, 0 deletions
diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_dataset_draw.cc b/source/blender/editors/space_spreadsheet/spreadsheet_dataset_draw.cc
new file mode 100644
index 00000000000..1fa6e47fcdf
--- /dev/null
+++ b/source/blender/editors/space_spreadsheet/spreadsheet_dataset_draw.cc
@@ -0,0 +1,277 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include <array>
+
+#include "DNA_space_types.h"
+#include "DNA_windowmanager_types.h"
+
+#include "BKE_context.h"
+
+#include "BLF_api.h"
+
+#include "BLI_rect.h"
+
+#include "RNA_access.h"
+
+#include "UI_interface.h"
+#include "UI_view2d.h"
+
+#include "WM_types.h"
+
+#include "spreadsheet_dataset_draw.hh"
+#include "spreadsheet_draw.hh"
+#include "spreadsheet_intern.hh"
+
+static int is_component_row_selected(struct uiBut *but, const void *arg)
+{
+ SpaceSpreadsheet *sspreadsheet = (SpaceSpreadsheet *)arg;
+
+ GeometryComponentType component = (GeometryComponentType)UI_but_datasetrow_component_get(but);
+ AttributeDomain domain = (AttributeDomain)UI_but_datasetrow_domain_get(but);
+
+ const bool is_component_selected = (GeometryComponentType)
+ sspreadsheet->geometry_component_type == component;
+ const bool is_domain_selected = (AttributeDomain)sspreadsheet->attribute_domain == domain;
+ bool is_selected = is_component_selected && is_domain_selected;
+
+ if (component == GEO_COMPONENT_TYPE_INSTANCES) {
+ is_selected = is_component_selected;
+ }
+
+ return is_selected;
+}
+
+namespace blender::ed::spreadsheet {
+
+/* -------------------------------------------------------------------- */
+/* Draw Context */
+
+class DatasetDrawContext {
+ std::array<int, 2> mval_;
+
+ public:
+ const SpaceSpreadsheet *sspreadsheet;
+ Object *object_eval;
+ /* Current geometry set, changes per component. */
+ GeometrySet current_geometry_set;
+
+ DatasetDrawContext(const bContext *C);
+
+ GeometrySet geometry_set_from_component(GeometryComponentType component);
+ const std::array<int, 2> &cursor_mval() const;
+};
+
+DatasetDrawContext::DatasetDrawContext(const bContext *C)
+ : sspreadsheet(CTX_wm_space_spreadsheet(C)),
+ object_eval(spreadsheet_get_object_eval(sspreadsheet, CTX_data_depsgraph_pointer(C)))
+{
+ const wmWindow *win = CTX_wm_window(C);
+ const ARegion *region = CTX_wm_region(C);
+ mval_ = {win->eventstate->x - region->winrct.xmin, win->eventstate->y - region->winrct.ymin};
+}
+
+GeometrySet DatasetDrawContext::geometry_set_from_component(GeometryComponentType component)
+{
+ return spreadsheet_get_display_geometry_set(sspreadsheet, object_eval, component);
+}
+
+const std::array<int, 2> &DatasetDrawContext::cursor_mval() const
+{
+ return mval_;
+}
+
+/* -------------------------------------------------------------------- */
+/* Drawer */
+
+DatasetRegionDrawer::DatasetRegionDrawer(const ARegion *region,
+ uiBlock &block,
+ DatasetDrawContext &draw_context)
+ : row_height(UI_UNIT_Y),
+ xmin(region->v2d.cur.xmin),
+ xmax(region->v2d.cur.xmax),
+ block(block),
+ v2d(region->v2d),
+ draw_context(draw_context)
+{
+}
+
+void DatasetRegionDrawer::draw_hierarchy(const DatasetLayoutHierarchy &layout)
+{
+ for (const DatasetComponentLayoutInfo &component : layout.components) {
+ draw_context.current_geometry_set = draw_context.geometry_set_from_component(component.type);
+
+ draw_component_row(component);
+
+ /* Iterate attribute domains, skip unset ones (storage has to be in a enum-based, fixed size
+ * array so uses optionals to support skipping enum values that shouldn't be displayed for a
+ * component). */
+ for (auto &optional_domain : component.attr_domains) {
+ if (!optional_domain) {
+ continue;
+ }
+
+ const DatasetAttrDomainLayoutInfo &domain_info = *optional_domain;
+ draw_attribute_domain_row(component, domain_info);
+ }
+ }
+}
+
+static int element_count_from_component_domain(const GeometrySet &geometry_set,
+ GeometryComponentType component,
+ AttributeDomain domain)
+{
+ if (geometry_set.has_mesh() && component == GEO_COMPONENT_TYPE_MESH) {
+ const MeshComponent *mesh_component = geometry_set.get_component_for_read<MeshComponent>();
+ return mesh_component->attribute_domain_size(domain);
+ }
+
+ if (geometry_set.has_pointcloud() && component == GEO_COMPONENT_TYPE_POINT_CLOUD) {
+ const PointCloudComponent *point_cloud_component =
+ geometry_set.get_component_for_read<PointCloudComponent>();
+ return point_cloud_component->attribute_domain_size(domain);
+ }
+
+ if (geometry_set.has_instances() && component == GEO_COMPONENT_TYPE_INSTANCES) {
+ const InstancesComponent *instances_component =
+ geometry_set.get_component_for_read<InstancesComponent>();
+ return instances_component->instances_amount();
+ }
+
+ if (geometry_set.has_volume() && component == GEO_COMPONENT_TYPE_VOLUME) {
+ const VolumeComponent *volume_component =
+ geometry_set.get_component_for_read<VolumeComponent>();
+ return volume_component->attribute_domain_size(domain);
+ }
+
+ if (geometry_set.has_curve() && component == GEO_COMPONENT_TYPE_CURVE) {
+ const CurveComponent *curve_component = geometry_set.get_component_for_read<CurveComponent>();
+ return curve_component->attribute_domain_size(domain);
+ }
+
+ return 0;
+}
+
+void DatasetRegionDrawer::draw_dataset_row(const int indentation,
+ const GeometryComponentType component,
+ const std::optional<AttributeDomain> domain,
+ BIFIconID icon,
+ const char *label,
+ const bool is_active)
+{
+
+ const float row_height = UI_UNIT_Y;
+ const float padding_x = UI_UNIT_X * 0.25f;
+
+ const rctf rect = {float(xmin) + padding_x,
+ float(xmax) - V2D_SCROLL_HANDLE_WIDTH,
+ ymin_offset - row_height,
+ ymin_offset};
+
+ char element_count[7];
+ BLI_str_format_attribute_domain_size(
+ element_count,
+ domain ? element_count_from_component_domain(
+ draw_context.current_geometry_set, component, *domain) :
+ 0);
+
+ std::string label_and_element_count = label;
+ label_and_element_count += UI_SEP_CHAR;
+ label_and_element_count += element_count;
+
+ uiBut *bt = uiDefIconTextButO(&block,
+ UI_BTYPE_DATASETROW,
+ "SPREADSHEET_OT_change_spreadsheet_data_source",
+ 0,
+ icon,
+ label,
+ rect.xmin,
+ rect.ymin,
+ BLI_rctf_size_x(&rect),
+ BLI_rctf_size_y(&rect),
+ NULL);
+
+ UI_but_datasetrow_indentation_set(bt, indentation);
+
+ if (is_active) {
+ UI_but_hint_drawstr_set(bt, element_count);
+ UI_but_datasetrow_component_set(bt, component);
+ if (domain) {
+ UI_but_datasetrow_domain_set(bt, *domain);
+ }
+ UI_but_func_pushed_state_set(bt, &is_component_row_selected, draw_context.sspreadsheet);
+
+ PointerRNA *but_ptr = UI_but_operator_ptr_get((uiBut *)bt);
+ RNA_int_set(but_ptr, "component_type", component);
+ if (domain) {
+ RNA_int_set(but_ptr, "attribute_domain_type", *domain);
+ }
+ }
+
+ ymin_offset -= row_height;
+}
+
+void DatasetRegionDrawer::draw_component_row(const DatasetComponentLayoutInfo &component_info)
+{
+ if (component_info.type == GEO_COMPONENT_TYPE_INSTANCES) {
+ draw_dataset_row(
+ 0, component_info.type, std::nullopt, component_info.icon, component_info.label, true);
+ }
+ else {
+ draw_dataset_row(
+ 0, component_info.type, std::nullopt, component_info.icon, component_info.label, false);
+ }
+}
+
+void DatasetRegionDrawer::draw_attribute_domain_row(
+ const DatasetComponentLayoutInfo &component_info,
+ const DatasetAttrDomainLayoutInfo &domain_info)
+{
+ draw_dataset_row(
+ 1, component_info.type, domain_info.type, domain_info.icon, domain_info.label, true);
+}
+
+/* -------------------------------------------------------------------- */
+/* Drawer */
+
+void draw_dataset_in_region(const bContext *C, ARegion *region)
+{
+ DatasetDrawContext draw_context{C};
+ if (!draw_context.object_eval) {
+ /* No object means nothing to display. Keep the region empty. */
+ return;
+ }
+
+ uiBlock *block = UI_block_begin(C, region, __func__, UI_EMBOSS);
+
+ DatasetRegionDrawer drawer{region, *block, draw_context};
+
+ /* Start with an offset to align buttons to spreadsheet rows. Use spreadsheet drawing info for
+ * that. */
+ drawer.ymin_offset = -SpreadsheetDrawer().top_row_height + drawer.row_height;
+
+ const DatasetLayoutHierarchy hierarchy = dataset_layout_hierarchy();
+ drawer.draw_hierarchy(hierarchy);
+#ifndef NDEBUG
+ dataset_layout_hierarchy_sanity_check(hierarchy);
+#endif
+
+ UI_block_end(C, block);
+ UI_view2d_totRect_set(&region->v2d, region->winx, abs(drawer.ymin_offset));
+ UI_block_draw(C, block);
+}
+
+} // namespace blender::ed::spreadsheet