Blender V5.0
space_spreadsheet.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 <cstring>
6#include <fmt/format.h>
7
8#include "BLI_listbase.h"
9#include "BLI_string.h"
10#include "BLI_string_utf8.h"
11
12#include "BKE_screen.hh"
13#include "BKE_viewer_path.hh"
14
15#include "ED_screen.hh"
16#include "ED_space_api.hh"
17#include "ED_spreadsheet.hh"
18#include "ED_viewer_path.hh"
19
20#include "DNA_scene_types.h"
21#include "DNA_screen_types.h"
22#include "DNA_space_types.h"
23
24#include "MEM_guardedalloc.h"
25
26#include "UI_interface.hh"
28#include "UI_resources.hh"
29#include "UI_view2d.hh"
30
31#include "BLO_read_write.hh"
32
34
35#include "WM_api.hh"
36#include "WM_types.hh"
37
38#include "BLT_translation.hh"
39
40#include "BLF_api.hh"
41
42#include "spreadsheet_column.hh"
44#include "spreadsheet_intern.hh"
45#include "spreadsheet_layout.hh"
48#include "spreadsheet_table.hh"
49
50#include <sstream>
51
53
54static SpaceLink *spreadsheet_create(const ScrArea * /*area*/, const Scene * /*scene*/)
55{
56 SpaceSpreadsheet *spreadsheet_space = MEM_callocN<SpaceSpreadsheet>("spreadsheet space");
57 spreadsheet_space->spacetype = SPACE_SPREADSHEET;
58
60 spreadsheet_space->filter_flag = SPREADSHEET_FILTER_ENABLE;
61
62 {
63 /* Header. */
64 ARegion *region = BKE_area_region_new();
65 BLI_addtail(&spreadsheet_space->regionbase, region);
68 }
69
70 {
71 /* Footer. */
72 ARegion *region = BKE_area_region_new();
73 BLI_addtail(&spreadsheet_space->regionbase, region);
76 }
77
78 {
79 /* Dataset Region */
80 ARegion *region = BKE_area_region_new();
81 BLI_addtail(&spreadsheet_space->regionbase, region);
82 region->regiontype = RGN_TYPE_TOOLS;
83 region->alignment = RGN_ALIGN_LEFT;
84 }
85
86 {
87 /* Properties region. */
88 ARegion *region = BKE_area_region_new();
89 BLI_addtail(&spreadsheet_space->regionbase, region);
90 region->regiontype = RGN_TYPE_UI;
91 region->alignment = RGN_ALIGN_RIGHT;
92 region->flag = RGN_FLAG_HIDDEN;
93 }
94
95 {
96 /* Main window. */
97 ARegion *region = BKE_area_region_new();
98 BLI_addtail(&spreadsheet_space->regionbase, region);
100 }
101
102 return (SpaceLink *)spreadsheet_space;
103}
104
106{
107 SpaceSpreadsheet *sspreadsheet = (SpaceSpreadsheet *)sl;
108
109 MEM_delete(sspreadsheet->runtime);
110
111 LISTBASE_FOREACH_MUTABLE (SpreadsheetRowFilter *, row_filter, &sspreadsheet->row_filters) {
112 spreadsheet_row_filter_free(row_filter);
113 }
114 for (const int i : IndexRange(sspreadsheet->num_tables)) {
115 spreadsheet_table_free(sspreadsheet->tables[i]);
116 }
117 MEM_SAFE_FREE(sspreadsheet->tables);
119}
120
121static void spreadsheet_init(wmWindowManager * /*wm*/, ScrArea *area)
122{
123 SpaceSpreadsheet *sspreadsheet = (SpaceSpreadsheet *)area->spacedata.first;
124 if (sspreadsheet->runtime == nullptr) {
125 sspreadsheet->runtime = MEM_new<SpaceSpreadsheet_Runtime>(__func__);
126 }
127}
128
130{
131 const SpaceSpreadsheet *sspreadsheet_old = (SpaceSpreadsheet *)sl;
132 SpaceSpreadsheet *sspreadsheet_new = (SpaceSpreadsheet *)MEM_dupallocN(sspreadsheet_old);
133 if (sspreadsheet_old->runtime) {
134 sspreadsheet_new->runtime = MEM_new<SpaceSpreadsheet_Runtime>(__func__,
135 *sspreadsheet_old->runtime);
136 }
137 else {
138 sspreadsheet_new->runtime = MEM_new<SpaceSpreadsheet_Runtime>(__func__);
139 }
140
141 BLI_listbase_clear(&sspreadsheet_new->row_filters);
142 LISTBASE_FOREACH (const SpreadsheetRowFilter *, src_filter, &sspreadsheet_old->row_filters) {
143 SpreadsheetRowFilter *new_filter = spreadsheet_row_filter_copy(src_filter);
144 BLI_addtail(&sspreadsheet_new->row_filters, new_filter);
145 }
146 sspreadsheet_new->num_tables = sspreadsheet_old->num_tables;
147 sspreadsheet_new->tables = MEM_calloc_arrayN<SpreadsheetTable *>(sspreadsheet_old->num_tables,
148 __func__);
149 for (const int i : IndexRange(sspreadsheet_old->num_tables)) {
150 sspreadsheet_new->tables[i] = spreadsheet_table_copy(*sspreadsheet_old->tables[i]);
151 }
152
154 sspreadsheet_old->geometry_id);
155 return (SpaceLink *)sspreadsheet_new;
156}
157
158static void spreadsheet_keymap(wmKeyConfig *keyconf)
159{
160 /* Entire editor only. */
161 WM_keymap_ensure(keyconf, "Spreadsheet Generic", SPACE_SPREADSHEET, RGN_TYPE_WINDOW);
162}
163
164static void spreadsheet_id_remap(ScrArea * /*area*/,
165 SpaceLink *slink,
166 const blender::bke::id::IDRemapper &mappings)
167{
168 SpaceSpreadsheet *sspreadsheet = (SpaceSpreadsheet *)slink;
169 spreadsheet_table_id_remap_id(sspreadsheet->geometry_id.base, mappings);
170 for (const int i : IndexRange(sspreadsheet->num_tables)) {
171 spreadsheet_table_remap_id(*sspreadsheet->tables[i], mappings);
172 }
173}
174
176{
177 SpaceSpreadsheet *sspreadsheet = reinterpret_cast<SpaceSpreadsheet *>(space_link);
179 for (const int i : IndexRange(sspreadsheet->num_tables)) {
180 spreadsheet_table_foreach_id(*sspreadsheet->tables[i], data);
181 }
182}
183
185{
191 region->v2d.minzoom = region->v2d.maxzoom = 1.0f;
192
193 UI_view2d_region_reinit(&region->v2d, V2D_COMMONVIEW_LIST, region->winx, region->winy);
194
196
197 {
198 wmKeyMap *keymap = WM_keymap_ensure(
199 wm->runtime->defaultconf, "View2D Buttons List", SPACE_EMPTY, RGN_TYPE_WINDOW);
200 WM_event_add_keymap_handler(&region->runtime->handlers, keymap);
201 }
202 {
203 wmKeyMap *keymap = WM_keymap_ensure(
204 wm->runtime->defaultconf, "Spreadsheet Generic", SPACE_SPREADSHEET, RGN_TYPE_WINDOW);
205 WM_event_add_keymap_handler(&region->runtime->handlers, keymap);
206 }
207}
208
209ID *get_current_id(const SpaceSpreadsheet *sspreadsheet)
210{
212 return nullptr;
213 }
214 ViewerPathElem *root_context = static_cast<ViewerPathElem *>(
215 sspreadsheet->geometry_id.viewer_path.path.first);
216 if (root_context->type != VIEWER_PATH_ELEM_TYPE_ID) {
217 return nullptr;
218 }
219 IDViewerPathElem *id_elem = reinterpret_cast<IDViewerPathElem *>(root_context);
220 return id_elem->id;
221}
222
223static void view_active_object(const bContext *C, SpaceSpreadsheet *sspreadsheet)
224{
227 if (ob == nullptr) {
228 return;
229 }
231 id_elem->id = &ob->id;
232 BLI_addtail(&sspreadsheet->geometry_id.viewer_path.path, id_elem);
234}
235
237{
239
241 Object *active_object = CTX_data_active_object(C);
243 sspreadsheet->geometry_id.viewer_path);
247 if (sspreadsheet->flag & SPREADSHEET_FLAG_PINNED) {
248 if (context_object == nullptr) {
249 /* Object is not available anymore, so clear the pinning. */
250 sspreadsheet->flag &= ~SPREADSHEET_FLAG_PINNED;
251 }
252 else {
253 /* The object is still pinned, do nothing. */
254 break;
255 }
256 }
257 else {
258 if (active_object != context_object) {
259 /* The active object has changed, so view the new active object. */
260 view_active_object(C, sspreadsheet);
261 }
262 else {
263 /* Nothing changed. */
264 break;
265 }
266 }
267 break;
268 }
270 WorkSpace *workspace = CTX_wm_workspace(C);
271 if (sspreadsheet->flag & SPREADSHEET_FLAG_PINNED) {
272 const std::optional<ViewerPathForGeometryNodesViewer> parsed_path =
274 sspreadsheet->geometry_id.viewer_path);
275 if (parsed_path.has_value()) {
277 /* The pinned path is still valid, do nothing. */
278 break;
279 }
280 /* The pinned path does not exist anymore, clear pinning. */
281 sspreadsheet->flag &= ~SPREADSHEET_FLAG_PINNED;
282 }
283 else {
284 /* Unknown pinned path, clear pinning. */
285 sspreadsheet->flag &= ~SPREADSHEET_FLAG_PINNED;
286 }
287 }
288 /* Now try to update the viewer path from the workspace. */
289 const std::optional<ViewerPathForGeometryNodesViewer> workspace_parsed_path =
291 if (workspace_parsed_path.has_value()) {
293 &workspace->viewer_path,
295 {
296 /* Nothing changed. */
297 break;
298 }
299 /* Update the viewer path from the workspace. */
301 BKE_viewer_path_copy(&sspreadsheet->geometry_id.viewer_path, &workspace->viewer_path);
302 }
303 else {
304 /* No active viewer node, change back to showing evaluated active object. */
306 view_active_object(C, sspreadsheet);
307 }
308
309 break;
310 }
311 }
312}
313
315 const Depsgraph *depsgraph)
316{
317 ID *used_id = get_current_id(sspreadsheet);
318 if (used_id == nullptr) {
319 return nullptr;
320 }
321 const ID_Type id_type = GS(used_id->name);
322 if (id_type != ID_OB) {
323 return nullptr;
324 }
325 Object *object_orig = (Object *)used_id;
326 if (!ELEM(object_orig->type,
327 OB_MESH,
329 OB_VOLUME,
331 OB_FONT,
332 OB_CURVES,
334 {
335 return nullptr;
336 }
337
338 Object *object_eval = DEG_get_evaluated(depsgraph, object_orig);
339 if (object_eval == nullptr) {
340 return nullptr;
341 }
342
343 return object_eval;
344}
345
346std::unique_ptr<DataSource> get_data_source(const bContext &C)
347{
350
351 Object *object_eval = spreadsheet_get_object_eval(sspreadsheet, depsgraph);
352 if (object_eval) {
353 return data_source_from_geometry(&C, object_eval);
354 }
355 return {};
356}
357
359{
360 return &sspreadsheet.geometry_id.base;
361}
362
364{
365 return const_cast<SpreadsheetTable *>(
366 get_active_table(const_cast<const SpaceSpreadsheet &>(sspreadsheet)));
367}
368
370{
371 const SpreadsheetTableID *active_table_id = get_active_table_id(sspreadsheet);
372 if (!active_table_id) {
373 return nullptr;
374 }
375 return spreadsheet_table_find(sspreadsheet, *active_table_id);
376}
377
378static int get_index_column_width(const int tot_rows)
379{
380 const int fontid = BLF_default();
381 BLF_size(fontid, UI_style_get_dpi()->widget.points * UI_SCALE_FAC);
382 return std::to_string(std::max(0, tot_rows - 1)).size() * BLF_width(fontid, "0", 1) +
383 UI_UNIT_X * 0.75;
384}
385
386static void update_visible_columns(SpreadsheetTable &table, DataSource &data_source)
387{
390 for (SpreadsheetColumn *column : Span{table.columns, table.num_columns}) {
391 if (handled_columns.add(*column->id)) {
392 const bool has_data = data_source.get_column_values(*column->id) != nullptr;
394 new_columns.append(column);
395 }
396 }
397
398 data_source.foreach_default_column_ids(
399 [&](const SpreadsheetColumnID &column_id, const bool is_extra) {
400 if (handled_columns.contains(column_id)) {
401 return;
402 }
403 std::unique_ptr<ColumnValues> values = data_source.get_column_values(column_id);
404 if (!values) {
405 return;
406 }
407 table.column_use_clock++;
409 if (is_extra) {
410 new_columns.insert(0, column);
411 }
412 else {
413 new_columns.append(column);
414 }
415 handled_columns.add(*column->id);
416 });
417
418 if (Span(table.columns, table.num_columns) == new_columns.as_span()) {
419 /* Nothing changed. */
420 return;
421 }
422
423 /* Update last used times of the columns to support garbage collection. */
424 for (SpreadsheetColumn *column : new_columns) {
425 const bool clock_was_reset = table.column_use_clock < column->last_used;
426 if (clock_was_reset || column->is_available()) {
427 column->last_used = table.column_use_clock;
428 }
429 }
430
431 /* Update the stored column pointers. */
432 MEM_SAFE_FREE(table.columns);
433 table.columns = MEM_calloc_arrayN<SpreadsheetColumn *>(new_columns.size(), __func__);
434 table.num_columns = new_columns.size();
435 std::copy_n(new_columns.begin(), new_columns.size(), table.columns);
436
437 /* Remove columns that have not been used for a while when there are too many. */
439}
440
441static void spreadsheet_main_region_draw(const bContext *C, ARegion *region)
442{
445
446 std::unique_ptr<DataSource> data_source = get_data_source(*C);
447 if (!data_source) {
448 data_source = std::make_unique<DataSource>();
449 }
450
451 const SpreadsheetTableID *active_table_id = get_active_table_id(*sspreadsheet);
452 SpreadsheetTable *table = spreadsheet_table_find(*sspreadsheet, *active_table_id);
453 if (!table) {
454 spreadsheet_table_remove_unused(*sspreadsheet);
455 table = spreadsheet_table_new(spreadsheet_table_id_copy(*active_table_id));
456 spreadsheet_table_add(*sspreadsheet, table);
457 }
458 if (table) {
459 /* Move to the front of the tables list to make it cheaper to find the table in future. */
460 spreadsheet_table_move_to_front(*sspreadsheet, *table);
461 }
462
463 /* Update the last used time on the table. */
464 if (table->last_used < sspreadsheet->table_use_clock || sspreadsheet->table_use_clock == 0) {
465 sspreadsheet->table_use_clock++;
466 /* Handle clock overflow by just resetting all clocks. */
467 if (sspreadsheet->table_use_clock == 0) {
468 for (SpreadsheetTable *table : Span(sspreadsheet->tables, sspreadsheet->num_tables)) {
469 table->last_used = sspreadsheet->table_use_clock;
470 }
471 }
472 table->last_used = sspreadsheet->table_use_clock;
473 }
474
475 update_visible_columns(*table, *data_source);
476
477 SpreadsheetLayout spreadsheet_layout;
478 ResourceScope scope;
479
480 const int tot_rows = data_source->tot_rows();
481 spreadsheet_layout.index_column_width = get_index_column_width(tot_rows);
482
483 int x = spreadsheet_layout.index_column_width;
484
485 for (SpreadsheetColumn *column : Span{table->columns, table->num_columns}) {
486 std::unique_ptr<ColumnValues> values_ptr = data_source->get_column_values(*column->id);
487 if (!values_ptr) {
488 continue;
489 }
490 const ColumnValues *values = scope.add(std::move(values_ptr));
491 const eSpreadsheetColumnValueType column_type = values->type();
492
493 if (column->width <= 0.0f || column_type != column->data_type) {
494 column->width = values->fit_column_width_px(100) / SPREADSHEET_WIDTH_UNIT;
495 }
496 const int width_in_pixels = column->width * SPREADSHEET_WIDTH_UNIT;
497 spreadsheet_layout.columns.append({values, width_in_pixels});
498
499 column->runtime->left_x = x;
500 x += width_in_pixels;
501 column->runtime->right_x = x;
502
503 spreadsheet_column_assign_runtime_data(column, column_type, values->name());
504 }
505
506 spreadsheet_layout.row_indices = spreadsheet_filter_rows(
507 *sspreadsheet, spreadsheet_layout, *data_source, scope);
508
509 sspreadsheet->runtime->tot_columns = spreadsheet_layout.columns.size();
510 sspreadsheet->runtime->tot_rows = tot_rows;
511 sspreadsheet->runtime->visible_rows = spreadsheet_layout.row_indices.size();
512
513 std::unique_ptr<SpreadsheetDrawer> drawer = spreadsheet_drawer_from_layout(spreadsheet_layout);
514 draw_spreadsheet_in_region(C, region, *drawer);
515
516 sspreadsheet->runtime->top_row_height = drawer->top_row_height;
517 sspreadsheet->runtime->left_column_width = drawer->left_column_width;
518
519 rcti mask;
520 UI_view2d_mask_from_win(&region->v2d, &mask);
521 mask.ymax -= sspreadsheet->runtime->top_row_height;
523
524 /* Tag other regions for redraw, because the main region updates data for them. */
526 ED_region_tag_redraw(footer);
528 ED_region_tag_redraw(sidebar);
529}
530
532{
533 ARegion *region = params->region;
534 const wmNotifier *wmn = params->notifier;
535 SpaceSpreadsheet *sspreadsheet = static_cast<SpaceSpreadsheet *>(params->area->spacedata.first);
536
537 switch (wmn->category) {
538 case NC_SCENE: {
539 switch (wmn->data) {
540 case ND_MODE:
541 case ND_FRAME:
542 case ND_OB_ACTIVE: {
543 ED_region_tag_redraw(region);
544 break;
545 }
546 }
547 break;
548 }
549 case NC_OBJECT: {
550 ED_region_tag_redraw(region);
551 break;
552 }
553 case NC_SPACE: {
554 if (wmn->data == ND_SPACE_SPREADSHEET) {
555 ED_region_tag_redraw(region);
556 }
557 break;
558 }
559 case NC_TEXTURE:
560 case NC_GEOM: {
561 ED_region_tag_redraw(region);
562 break;
563 }
564 case NC_GPENCIL: {
565 ED_region_tag_redraw(region);
566 break;
567 }
568 case NC_VIEWER_PATH: {
570 {
571 ED_region_tag_redraw(region);
572 }
573 break;
574 }
575 }
576}
577
579{
580 ED_region_header_init(region);
581}
582
584{
586 ED_region_header(C, region);
587}
588
589static void spreadsheet_header_region_free(ARegion * /*region*/) {}
590
592{
593 ARegion *region = params->region;
594 const wmNotifier *wmn = params->notifier;
595 SpaceSpreadsheet *sspreadsheet = static_cast<SpaceSpreadsheet *>(params->area->spacedata.first);
596
597 switch (wmn->category) {
598 case NC_SCENE: {
599 switch (wmn->data) {
600 case ND_MODE:
601 case ND_OB_ACTIVE: {
602 ED_region_tag_redraw(region);
603 break;
604 }
605 }
606 break;
607 }
608 case NC_OBJECT: {
609 ED_region_tag_redraw(region);
610 break;
611 }
612 case NC_SPACE: {
613 if (wmn->data == ND_SPACE_SPREADSHEET) {
614 ED_region_tag_redraw(region);
615 }
616 break;
617 }
618 case NC_GEOM: {
619 ED_region_tag_redraw(region);
620 break;
621 }
622 case NC_GPENCIL: {
623 ED_region_tag_redraw(region);
624 break;
625 }
626 case NC_VIEWER_PATH: {
628 {
629 ED_region_tag_redraw(region);
630 }
631 break;
632 }
633 }
634}
635
637{
638 ED_region_header_init(region);
639}
640
642{
644 SpaceSpreadsheet_Runtime *runtime = sspreadsheet->runtime;
645 std::stringstream ss;
646 ss << IFACE_("Rows:") << " ";
647 if (runtime->visible_rows != runtime->tot_rows) {
648 char visible_rows_str[BLI_STR_FORMAT_INT32_GROUPED_SIZE];
649 BLI_str_format_int_grouped(visible_rows_str, runtime->visible_rows);
650 ss << visible_rows_str << " / ";
651 }
652 char tot_rows_str[BLI_STR_FORMAT_INT32_GROUPED_SIZE];
653 BLI_str_format_int_grouped(tot_rows_str, runtime->tot_rows);
654 ss << tot_rows_str << " | " << IFACE_("Columns:") << " " << runtime->tot_columns;
655 std::string stats_str = ss.str();
656
658
659 uiBlock *block = UI_block_begin(C, region, __func__, ui::EmbossType::Emboss);
660 const uiStyle *style = UI_style_get_dpi();
661 uiLayout &layout = ui::block_layout(block,
665 region->winy - (region->winy - UI_UNIT_Y) / 2.0f,
666 region->winx,
667 1,
668 0,
669 style);
670 layout.separator_spacer();
672 layout.label(stats_str, ICON_NONE);
674 UI_block_align_end(block);
675 UI_block_end(C, block);
676 UI_block_draw(C, block);
677}
678
679static void spreadsheet_footer_region_free(ARegion * /*region*/) {}
680
682
684{
685 ARegion *region = params->region;
686 const wmNotifier *wmn = params->notifier;
687
688 switch (wmn->category) {
689 case NC_SCENE: {
690 switch (wmn->data) {
691 case ND_FRAME:
692 ED_region_tag_redraw(region);
693 break;
694 }
695 break;
696 }
697 case NC_TEXTURE:
698 ED_region_tag_redraw(region);
699 break;
700 }
701
703}
704
706{
708 ED_region_panels(C, region);
709}
710
712{
713 UI_panel_category_active_set_default(region, "Filters");
714 ED_region_panels_init(wm, region);
715
716 wmKeyMap *keymap = WM_keymap_ensure(
717 wm->runtime->defaultconf, "Spreadsheet Generic", SPACE_SPREADSHEET, RGN_TYPE_WINDOW);
718 WM_event_add_keymap_handler(&region->runtime->handlers, keymap);
719}
720
721static void spreadsheet_right_region_free(ARegion * /*region*/) {}
722
724
726{
727 SpaceSpreadsheet *sspreadsheet = (SpaceSpreadsheet *)sl;
728
729 sspreadsheet->runtime = nullptr;
731 LISTBASE_FOREACH (SpreadsheetRowFilter *, row_filter, &sspreadsheet->row_filters) {
732 BLO_read_string(reader, &row_filter->value_string);
733 }
734
736 reader, sspreadsheet->num_tables, reinterpret_cast<void **>(&sspreadsheet->tables));
737 for (const int i : IndexRange(sspreadsheet->num_tables)) {
738 BLO_read_struct(reader, SpreadsheetTable, &sspreadsheet->tables[i]);
739 spreadsheet_table_blend_read(reader, sspreadsheet->tables[i]);
740 }
741
742 spreadsheet_table_id_blend_read(reader, &sspreadsheet->geometry_id.base);
743}
744
746{
748 SpaceSpreadsheet *sspreadsheet = (SpaceSpreadsheet *)sl;
749
750 LISTBASE_FOREACH (SpreadsheetRowFilter *, row_filter, &sspreadsheet->row_filters) {
751 BLO_write_struct(writer, SpreadsheetRowFilter, row_filter);
752 BLO_write_string(writer, row_filter->value_string);
753 }
754
755 BLO_write_pointer_array(writer, sspreadsheet->num_tables, sspreadsheet->tables);
756 for (const int i : IndexRange(sspreadsheet->num_tables)) {
757 spreadsheet_table_blend_write(writer, sspreadsheet->tables[i]);
758 }
759
761}
762
763static void spreadsheet_cursor(wmWindow *win, ScrArea *area, ARegion *region)
764{
765 SpaceSpreadsheet &sspreadsheet = *static_cast<SpaceSpreadsheet *>(area->spacedata.first);
766
767 const int2 cursor_re{win->eventstate->xy[0] - region->winrct.xmin,
768 win->eventstate->xy[1] - region->winrct.ymin};
769 if (find_hovered_column_header_edge(sspreadsheet, *region, cursor_re)) {
771 return;
772 }
773 if (find_hovered_column_header(sspreadsheet, *region, cursor_re)) {
775 return;
776 }
778}
779
781{
782 std::unique_ptr<SpaceType> st = std::make_unique<SpaceType>();
783 ARegionType *art;
784
785 st->spaceid = SPACE_SPREADSHEET;
786 STRNCPY_UTF8(st->name, "Spreadsheet");
787
788 st->create = spreadsheet_create;
789 st->free = spreadsheet_free;
790 st->init = spreadsheet_init;
791 st->duplicate = spreadsheet_duplicate;
792 st->operatortypes = spreadsheet_operatortypes;
793 st->keymap = spreadsheet_keymap;
794 st->id_remap = spreadsheet_id_remap;
795 st->foreach_id = spreadsheet_foreach_id;
796 st->blend_read_data = spreadsheet_blend_read_data;
797 st->blend_read_after_liblink = nullptr;
798 st->blend_write = spreadsheet_blend_write;
799
800 /* regions: main window */
801 art = MEM_callocN<ARegionType>("spacetype spreadsheet region");
805
810 art->event_cursor = true;
811 BLI_addhead(&st->regiontypes, art);
812
813 /* regions: header */
814 art = MEM_callocN<ARegionType>("spacetype spreadsheet header region");
816 art->prefsizey = HEADERY;
817 art->keymapflag = 0;
820
825 BLI_addhead(&st->regiontypes, art);
826
827 /* regions: footer */
828 art = MEM_callocN<ARegionType>("spacetype spreadsheet footer region");
830 art->prefsizey = HEADERY;
831 art->keymapflag = 0;
834
839 BLI_addhead(&st->regiontypes, art);
840
841 /* regions: right panel buttons */
842 art = MEM_callocN<ARegionType>("spacetype spreadsheet right region");
843 art->regionid = RGN_TYPE_UI;
847
853 BLI_addhead(&st->regiontypes, art);
854
856
857 /* regions: channels */
858 art = MEM_callocN<ARegionType>("spreadsheet dataset region");
860 art->prefsizex = 150 + V2D_SCROLL_WIDTH;
867 BLI_addhead(&st->regiontypes, art);
868
869 BKE_spacetype_register(std::move(st));
870}
871
872} // namespace blender::ed::spreadsheet
WorkSpace * CTX_wm_workspace(const bContext *C)
ScrArea * CTX_wm_area(const bContext *C)
Depsgraph * CTX_data_depsgraph_pointer(const bContext *C)
Object * CTX_data_active_object(const bContext *C)
SpaceSpreadsheet * CTX_wm_space_spreadsheet(const bContext *C)
void BKE_spacetype_register(std::unique_ptr< SpaceType > st)
Definition screen.cc:282
ARegion * BKE_area_region_new()
Definition screen.cc:387
ARegion * BKE_area_find_region_type(const ScrArea *area, int region_type)
Definition screen.cc:846
@ REGION_DRAW_LOCK_ALL
void BKE_viewer_path_copy(ViewerPath *dst, const ViewerPath *src)
@ VIEWER_PATH_EQUAL_FLAG_CONSIDER_UI_NAME
void BKE_viewer_path_clear(ViewerPath *viewer_path)
IDViewerPathElem * BKE_viewer_path_elem_new_id()
bool BKE_viewer_path_equal(const ViewerPath *a, const ViewerPath *b, ViewerPathEqualFlag flag=ViewerPathEqualFlag(0))
void BLF_size(int fontid, float size)
Definition blf.cc:443
int BLF_default()
float BLF_width(int fontid, const char *str, size_t str_len, ResultBLF *r_info=nullptr) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(2)
Definition blf.cc:802
#define LISTBASE_FOREACH(type, var, list)
BLI_INLINE void BLI_listbase_clear(ListBase *lb)
BLI_INLINE bool BLI_listbase_is_empty(const ListBase *lb)
#define LISTBASE_FOREACH_MUTABLE(type, var, list)
void BLI_addtail(ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:111
void BLI_addhead(ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:91
size_t BLI_str_format_int_grouped(char dst[BLI_STR_FORMAT_INT32_GROUPED_SIZE], int num) ATTR_NONNULL(1)
Definition string.cc:1171
#define BLI_STR_FORMAT_INT32_GROUPED_SIZE
Definition BLI_string.h:28
#define STRNCPY_UTF8(dst, src)
#define SET_FLAG_FROM_TEST(value, test, flag)
#define ELEM(...)
#define BLO_write_struct(writer, struct_name, data_ptr)
void BLO_read_string(BlendDataReader *reader, char **ptr_p)
Definition readfile.cc:5828
void BLO_write_string(BlendWriter *writer, const char *data_ptr)
#define BLO_read_struct_list(reader, struct_name, list)
#define BLO_read_struct(reader, struct_name, ptr_p)
void BLO_write_pointer_array(BlendWriter *writer, int64_t num, const void *data_ptr)
void BLO_read_pointer_array(BlendDataReader *reader, int64_t array_size, void **ptr_p)
Definition readfile.cc:5880
#define IFACE_(msgid)
T * DEG_get_evaluated(const Depsgraph *depsgraph, T *id)
ID_Type
@ ID_OB
@ OB_FONT
@ OB_GREASE_PENCIL
@ OB_MESH
@ OB_POINTCLOUD
@ OB_VOLUME
@ OB_CURVES_LEGACY
@ OB_CURVES
#define HEADERY
@ RGN_ALIGN_BOTTOM
@ RGN_ALIGN_LEFT
@ RGN_ALIGN_TOP
@ RGN_ALIGN_RIGHT
@ RGN_TYPE_UI
@ RGN_TYPE_WINDOW
@ RGN_TYPE_FOOTER
@ RGN_TYPE_HEADER
@ RGN_TYPE_TOOLS
@ RGN_FLAG_HIDDEN
@ RGN_FLAG_INDICATE_OVERFLOW
@ SPREADSHEET_TABLE_ID_TYPE_GEOMETRY
@ SPACE_SPREADSHEET
@ SPACE_EMPTY
@ SPREADSHEET_COLUMN_FLAG_UNAVAILABLE
@ SPREADSHEET_FILTER_ENABLE
eSpaceSpreadsheet_ObjectEvalState
@ SPREADSHEET_OBJECT_EVAL_STATE_VIEWER_NODE
@ SPREADSHEET_OBJECT_EVAL_STATE_EVALUATED
@ SPREADSHEET_OBJECT_EVAL_STATE_ORIGINAL
eSpreadsheetColumnValueType
#define SPREADSHEET_WIDTH_UNIT
@ SPREADSHEET_FLAG_PINNED
#define UI_SCALE_FAC
@ USER_HEADER_BOTTOM
@ V2D_KEEPTOT_STRICT
@ V2D_LIMITZOOM
@ V2D_LOCKZOOM_X
@ V2D_KEEPASPECT
@ V2D_LOCKZOOM_Y
@ V2D_SCROLL_HORIZONTAL_HIDE
@ V2D_SCROLL_VERTICAL_HIDE
@ V2D_SCROLL_RIGHT
@ V2D_SCROLL_BOTTOM
@ V2D_ALIGN_NO_NEG_X
@ V2D_ALIGN_NO_POS_Y
@ VIEWER_PATH_ELEM_TYPE_ID
void ED_area_tag_redraw(ScrArea *area)
Definition area.cc:693
void ED_region_panels(const bContext *C, ARegion *region)
Definition area.cc:3609
void ED_region_header(const bContext *C, ARegion *region)
Definition area.cc:3935
void ED_region_header_init(ARegion *region)
Definition area.cc:3950
void ED_region_panels_layout(const bContext *C, ARegion *region)
Definition area.cc:3519
void ED_region_panels_init(wmWindowManager *wm, ARegion *region)
Definition area.cc:3616
void ED_region_tag_redraw(ARegion *region)
Definition area.cc:618
@ ED_KEYMAP_UI
Definition ED_screen.hh:758
@ ED_KEYMAP_HEADER
Definition ED_screen.hh:764
@ ED_KEYMAP_VIEW2D
Definition ED_screen.hh:761
@ ED_KEYMAP_FRAMES
Definition ED_screen.hh:763
void ED_region_panels_draw(const bContext *C, ARegion *region)
Definition area.cc:3529
void ED_region_draw_overflow_indication(const ScrArea *area, ARegion *region, rcti *mask=nullptr)
Definition area.cc:3417
Read Guarded memory(de)allocation.
#define MEM_SAFE_FREE(v)
#define C
Definition RandGen.cpp:29
#define UI_UNIT_Y
#define UI_SIDEBAR_PANEL_WIDTH
uiBlock * UI_block_begin(const bContext *C, ARegion *region, std::string name, blender::ui::EmbossType emboss)
const uiStyle * UI_style_get_dpi()
#define UI_HEADER_OFFSET
void UI_block_draw(const bContext *C, uiBlock *block)
void UI_panel_category_active_set_default(ARegion *region, const char *idname)
#define UI_UNIT_X
void UI_block_end(const bContext *C, uiBlock *block)
void UI_block_align_end(uiBlock *block)
@ TH_BACK
void UI_ThemeClearColor(int colorid)
#define V2D_SCROLL_WIDTH
Definition UI_view2d.hh:54
void UI_view2d_region_reinit(View2D *v2d, short type, int winx, int winy)
Definition view2d.cc:221
void UI_view2d_mask_from_win(const View2D *v2d, rcti *r_mask)
Definition view2d.cc:109
@ V2D_COMMONVIEW_LIST
Definition UI_view2d.hh:35
#define NC_GEOM
Definition WM_types.hh:393
#define ND_OB_ACTIVE
Definition WM_types.hh:440
#define NC_VIEWER_PATH
Definition WM_types.hh:406
#define ND_MODE
Definition WM_types.hh:445
#define NC_SCENE
Definition WM_types.hh:378
#define ND_FRAME
Definition WM_types.hh:434
#define NC_GPENCIL
Definition WM_types.hh:399
#define NC_TEXTURE
Definition WM_types.hh:381
#define ND_SPACE_SPREADSHEET
Definition WM_types.hh:541
#define NC_OBJECT
Definition WM_types.hh:379
#define NC_SPACE
Definition WM_types.hh:392
#define U
BMesh const char void * data
BPy_StructRNA * depsgraph
T * add(std::unique_ptr< T > resource)
bool contains(const Key &key) const
Definition BLI_set.hh:310
bool add(const Key &key)
Definition BLI_set.hh:248
int64_t size() const
void append(const T &value)
void insert(const int64_t insert_index, const T &value)
Span< T > as_span() const
eSpreadsheetColumnValueType type() const
float fit_column_width_px(const std::optional< int64_t > &max_sample_size=std::nullopt) const
virtual void foreach_default_column_ids(FunctionRef< void(const SpreadsheetColumnID &, bool is_extra)>) const
virtual std::unique_ptr< ColumnValues > get_column_values(const SpreadsheetColumnID &) const
#define GS(x)
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
void * MEM_calloc_arrayN(size_t len, size_t size, const char *str)
Definition mallocn.cc:123
void * MEM_callocN(size_t len, const char *str)
Definition mallocn.cc:118
void * MEM_dupallocN(const void *vmemh)
Definition mallocn.cc:143
ccl_device_inline float2 mask(const MaskType mask, const float2 a)
SpreadsheetColumn * spreadsheet_column_new(SpreadsheetColumnID *column_id)
static void spreadsheet_header_region_free(ARegion *)
static void spreadsheet_foreach_id(SpaceLink *space_link, LibraryForeachIDData *data)
static void spreadsheet_free(SpaceLink *sl)
const SpreadsheetTableID * get_active_table_id(const SpaceSpreadsheet &sspreadsheet)
void spreadsheet_table_move_to_front(SpaceSpreadsheet &sspreadsheet, SpreadsheetTable &table)
static void spreadsheet_header_region_init(wmWindowManager *, ARegion *region)
void spreadsheet_table_blend_write(BlendWriter *writer, const SpreadsheetTable *table)
IndexMask spreadsheet_filter_rows(const SpaceSpreadsheet &sspreadsheet, const SpreadsheetLayout &spreadsheet_layout, const DataSource &data_source, ResourceScope &scope)
void draw_spreadsheet_in_region(const bContext *C, ARegion *region, const SpreadsheetDrawer &drawer)
void spreadsheet_table_blend_read(BlendDataReader *reader, SpreadsheetTable *table)
SpreadsheetRowFilter * spreadsheet_row_filter_copy(const SpreadsheetRowFilter *src_row_filter)
static void spreadsheet_footer_region_free(ARegion *)
static void spreadsheet_right_region_free(ARegion *)
static SpaceLink * spreadsheet_create(const ScrArea *, const Scene *)
static void spreadsheet_sidebar_init(wmWindowManager *wm, ARegion *region)
static void spreadsheet_keymap(wmKeyConfig *keyconf)
static void update_visible_columns(SpreadsheetTable &table, DataSource &data_source)
static void spreadsheet_init(wmWindowManager *, ScrArea *area)
void spreadsheet_table_remove_unused(SpaceSpreadsheet &sspreadsheet)
void spreadsheet_table_id_free_content(SpreadsheetTableID *table_id)
std::unique_ptr< DataSource > data_source_from_geometry(const bContext *C, Object *object_eval)
static SpaceLink * spreadsheet_duplicate(SpaceLink *sl)
SpreadsheetTableID * spreadsheet_table_id_copy(const SpreadsheetTableID &src_table_id)
void spreadsheet_table_id_copy_content_geometry(SpreadsheetTableIDGeometry &dst, const SpreadsheetTableIDGeometry &src)
static void spreadsheet_main_region_draw(const bContext *C, ARegion *region)
void spreadsheet_table_id_blend_write_content_geometry(BlendWriter *writer, const SpreadsheetTableIDGeometry *table_id)
std::unique_ptr< DataSource > get_data_source(const bContext &C)
static void spreadsheet_main_region_init(wmWindowManager *wm, ARegion *region)
void spreadsheet_table_id_blend_read(BlendDataReader *reader, SpreadsheetTableID *table_id)
void spreadsheet_table_remove_unused_columns(SpreadsheetTable &table)
void spreadsheet_table_id_foreach_id(SpreadsheetTableID &table_id, LibraryForeachIDData *data)
static void spreadsheet_footer_region_draw(const bContext *C, ARegion *region)
Object * spreadsheet_get_object_eval(const SpaceSpreadsheet *sspreadsheet, const Depsgraph *depsgraph)
SpreadsheetTable * spreadsheet_table_new(SpreadsheetTableID *table_id)
ID * get_current_id(const SpaceSpreadsheet *sspreadsheet)
static void spreadsheet_footer_region_init(wmWindowManager *, ARegion *region)
SpreadsheetColumn * find_hovered_column_header(SpaceSpreadsheet &sspreadsheet, ARegion &region, const int2 &cursor_re)
static void spreadsheet_footer_region_listener(const wmRegionListenerParams *)
std::unique_ptr< SpreadsheetDrawer > spreadsheet_drawer_from_layout(const SpreadsheetLayout &spreadsheet_layout)
static void view_active_object(const bContext *C, SpaceSpreadsheet *sspreadsheet)
static void spreadsheet_dataset_region_listener(const wmRegionListenerParams *params)
void spreadsheet_table_free(SpreadsheetTable *table)
static void spreadsheet_blend_read_data(BlendDataReader *reader, SpaceLink *sl)
static void spreadsheet_header_region_draw(const bContext *C, ARegion *region)
static int get_index_column_width(const int tot_rows)
void spreadsheet_row_filter_free(SpreadsheetRowFilter *row_filter)
static void spreadsheet_blend_write(BlendWriter *writer, SpaceLink *sl)
static void spreadsheet_update_context(const bContext *C)
void spreadsheet_table_foreach_id(SpreadsheetTable &table, LibraryForeachIDData *data)
SpreadsheetColumn * find_hovered_column_header_edge(SpaceSpreadsheet &sspreadsheet, ARegion &region, const int2 &cursor_re)
void spreadsheet_column_assign_runtime_data(SpreadsheetColumn *column, const eSpreadsheetColumnValueType data_type, const StringRefNull display_name)
void spreadsheet_data_set_region_panels_register(ARegionType &region_type)
SpreadsheetTable * get_active_table(SpaceSpreadsheet &sspreadsheet)
static void spreadsheet_header_region_listener(const wmRegionListenerParams *params)
static void spreadsheet_cursor(wmWindow *win, ScrArea *area, ARegion *region)
SpreadsheetColumnID * spreadsheet_column_id_copy(const SpreadsheetColumnID *src_column_id)
SpreadsheetTable * spreadsheet_table_copy(const SpreadsheetTable &src_table)
void spreadsheet_table_remap_id(SpreadsheetTable &table, const bke::id::IDRemapper &mappings)
static void spreadsheet_dataset_region_draw(const bContext *C, ARegion *region)
void register_row_filter_panels(ARegionType &region_type)
void spreadsheet_table_id_remap_id(SpreadsheetTableID &table_id, const bke::id::IDRemapper &mappings)
SpreadsheetTable * spreadsheet_table_find(SpaceSpreadsheet &sspreadsheet, const SpreadsheetTableID &table_id)
static void spreadsheet_id_remap(ScrArea *, SpaceLink *slink, const blender::bke::id::IDRemapper &mappings)
void spreadsheet_table_add(SpaceSpreadsheet &sspreadsheet, SpreadsheetTable *table)
static void spreadsheet_main_region_listener(const wmRegionListenerParams *params)
static void spreadsheet_right_region_listener(const wmRegionListenerParams *)
Object * parse_object_only(const ViewerPath &viewer_path)
std::optional< ViewerPathForGeometryNodesViewer > parse_geometry_nodes_viewer(const ViewerPath &viewer_path)
bool exists_geometry_nodes_viewer(const ViewerPathForGeometryNodesViewer &parsed_viewer_path)
int2 block_layout_resolve(uiBlock *block)
uiLayout & block_layout(uiBlock *block, LayoutDirection direction, LayoutType type, int x, int y, int size, int em, int padding, const uiStyle *style)
VecBase< int32_t, 2 > int2
void(* free)(ARegion *)
void(* cursor)(wmWindow *win, ScrArea *area, ARegion *region)
void(* listener)(const wmRegionListenerParams *params)
void(* draw)(const bContext *C, ARegion *region)
void(* layout)(const bContext *C, ARegion *region)
short event_cursor
void(* init)(wmWindowManager *wm, ARegion *region)
ARegionRuntimeHandle * runtime
Definition DNA_ID.h:414
char name[258]
Definition DNA_ID.h:432
void * first
ListBase spacedata
SpreadsheetTableIDGeometry geometry_id
SpreadsheetTable ** tables
SpaceSpreadsheet_Runtime * runtime
SpreadsheetColumnID * id
SpreadsheetColumn ** columns
float minzoom
short keeptot
short keepzoom
float maxzoom
ViewerPath viewer_path
int ymin
int xmin
void alignment_set(blender::ui::LayoutAlign alignment)
void separator_spacer()
void label(blender::StringRef name, int icon)
int xy[2]
Definition WM_types.hh:761
unsigned int data
Definition WM_types.hh:358
unsigned int category
Definition WM_types.hh:358
struct wmEvent * eventstate
i
Definition text_draw.cc:230
void WM_cursor_set(wmWindow *win, int curs)
@ WM_CURSOR_HAND
Definition wm_cursors.hh:22
@ WM_CURSOR_DEFAULT
Definition wm_cursors.hh:15
@ WM_CURSOR_X_MOVE
Definition wm_cursors.hh:39
wmEventHandler_Keymap * WM_event_add_keymap_handler(ListBase *handlers, wmKeyMap *keymap)
wmKeyMap * WM_keymap_ensure(wmKeyConfig *keyconf, const char *idname, int spaceid, int regionid)
Definition wm_keymap.cc:895