Refactor: Port spreadsheet data set to UI tree view
This patch removes a bunch of specific code for drawing the spreadsheet data set region, which was an overly specific solution for a generic UI. Nowadays, the UI tree view API used for asset browser catalogs is a much better way to implement this behavior. To make this possible, the tree view API is extended in a few ways. Collapsibility can now be turned off, and whether an item should be active is moved to a separate virtual function. The only visual change is that the items are now drawn in a box, just like the asset catalog. Differential Revision: https://developer.blender.org/D13198
This commit is contained in:
parent
a0780ad625
commit
01df48a983
Notes:
blender-bot
2023-02-14 10:14:07 +01:00
Referenced by issue #94380, UI behavior Inconsistency: Mouse scroll changes scale of spreadsheet panel Referenced by issue #93250, Crash when creating a new object Referenced by issue #92965, Refactor the spreadsheet data set region to use the abstract tree view API
|
@ -400,9 +400,8 @@ typedef enum {
|
|||
/** Resize handle (resize uilist). */
|
||||
UI_BTYPE_GRIP = 57 << 9,
|
||||
UI_BTYPE_DECORATOR = 58 << 9,
|
||||
UI_BTYPE_DATASETROW = 59 << 9,
|
||||
/* An item in a tree view. Parent items may be collapsible. */
|
||||
UI_BTYPE_TREEROW = 60 << 9,
|
||||
UI_BTYPE_TREEROW = 59 << 9,
|
||||
} eButType;
|
||||
|
||||
#define BUTTYPE (63 << 9)
|
||||
|
@ -1676,11 +1675,7 @@ int UI_searchbox_size_x(void);
|
|||
int UI_search_items_find_index(uiSearchItems *items, const char *name);
|
||||
|
||||
void UI_but_hint_drawstr_set(uiBut *but, const char *string);
|
||||
void UI_but_datasetrow_indentation_set(uiBut *but, int indentation);
|
||||
void UI_but_datasetrow_component_set(uiBut *but, uint8_t geometry_component_type);
|
||||
void UI_but_datasetrow_domain_set(uiBut *but, uint8_t attribute_domain);
|
||||
uint8_t UI_but_datasetrow_component_get(uiBut *but);
|
||||
uint8_t UI_but_datasetrow_domain_get(uiBut *but);
|
||||
|
||||
void UI_but_treerow_indentation_set(uiBut *but, int indentation);
|
||||
|
||||
void UI_but_node_link_set(uiBut *but, struct bNodeSocket *socket, const float draw_color[4]);
|
||||
|
|
|
@ -217,15 +217,11 @@ class AbstractTreeViewItem : public TreeViewItemContainer {
|
|||
friend class TreeViewLayoutBuilder;
|
||||
|
||||
public:
|
||||
using IsActiveFn = std::function<bool()>;
|
||||
|
||||
private:
|
||||
bool is_open_ = false;
|
||||
bool is_active_ = false;
|
||||
bool is_renaming_ = false;
|
||||
|
||||
IsActiveFn is_active_fn_;
|
||||
|
||||
protected:
|
||||
/** This label is used for identifying an item (together with its parent's labels). */
|
||||
std::string label_{};
|
||||
|
@ -239,11 +235,6 @@ class AbstractTreeViewItem : public TreeViewItemContainer {
|
|||
virtual void build_context_menu(bContext &C, uiLayout &column) const;
|
||||
|
||||
virtual void on_activate();
|
||||
/**
|
||||
* Set a custom callback to check if this item should be active. There's a version without
|
||||
* arguments for checking if the item is currently in an active state.
|
||||
*/
|
||||
virtual void is_active(IsActiveFn is_active_fn);
|
||||
|
||||
/**
|
||||
* Queries if the tree-view item supports renaming in principle. Renaming may still fail, e.g. if
|
||||
|
@ -329,6 +320,17 @@ class AbstractTreeViewItem : public TreeViewItemContainer {
|
|||
*/
|
||||
void activate();
|
||||
|
||||
/**
|
||||
* If the result is not empty, it controls whether the item should be active or not,
|
||||
* usually depending on the data that the view represents.
|
||||
*/
|
||||
virtual std::optional<bool> should_be_active() const;
|
||||
|
||||
/**
|
||||
* Return whether the item can be collapsed. Used to disable collapsing for items with children.
|
||||
*/
|
||||
virtual bool supports_collapsing() const;
|
||||
|
||||
private:
|
||||
static void rename_button_fn(bContext *, void *, char *);
|
||||
static AbstractTreeViewItem *find_tree_item_from_rename_button(const uiBut &but);
|
||||
|
@ -416,6 +418,7 @@ class AbstractTreeViewItemDropController {
|
|||
*/
|
||||
class BasicTreeViewItem : public AbstractTreeViewItem {
|
||||
public:
|
||||
using IsActiveFn = std::function<bool()>;
|
||||
using ActivateFn = std::function<void(BasicTreeViewItem &new_active)>;
|
||||
BIFIconID icon;
|
||||
|
||||
|
@ -423,7 +426,11 @@ class BasicTreeViewItem : public AbstractTreeViewItem {
|
|||
|
||||
void build_row(uiLayout &row) override;
|
||||
void add_label(uiLayout &layout, StringRefNull label_override = "");
|
||||
void on_activate(ActivateFn fn);
|
||||
void set_on_activate_fn(ActivateFn fn);
|
||||
/**
|
||||
* Set a custom callback to check if this item should be active.
|
||||
*/
|
||||
void set_is_active_fn(IsActiveFn fn);
|
||||
|
||||
protected:
|
||||
/**
|
||||
|
@ -433,9 +440,12 @@ class BasicTreeViewItem : public AbstractTreeViewItem {
|
|||
*/
|
||||
ActivateFn activate_fn_;
|
||||
|
||||
IsActiveFn is_active_fn_;
|
||||
|
||||
private:
|
||||
static void tree_row_click_fn(struct bContext *C, void *arg1, void *arg2);
|
||||
|
||||
std::optional<bool> should_be_active() const override;
|
||||
void on_activate() override;
|
||||
};
|
||||
|
||||
|
|
|
@ -3977,10 +3977,6 @@ static void ui_but_alloc_info(const eButType type,
|
|||
alloc_size = sizeof(uiButCurveProfile);
|
||||
alloc_str = "uiButCurveProfile";
|
||||
break;
|
||||
case UI_BTYPE_DATASETROW:
|
||||
alloc_size = sizeof(uiButDatasetRow);
|
||||
alloc_str = "uiButDatasetRow";
|
||||
break;
|
||||
case UI_BTYPE_TREEROW:
|
||||
alloc_size = sizeof(uiButTreeRow);
|
||||
alloc_str = "uiButTreeRow";
|
||||
|
@ -4183,7 +4179,6 @@ static uiBut *ui_def_but(uiBlock *block,
|
|||
UI_BTYPE_BLOCK,
|
||||
UI_BTYPE_BUT_MENU,
|
||||
UI_BTYPE_SEARCH_MENU,
|
||||
UI_BTYPE_DATASETROW,
|
||||
UI_BTYPE_TREEROW,
|
||||
UI_BTYPE_POPOVER)) {
|
||||
but->drawflag |= (UI_BUT_TEXT_LEFT | UI_BUT_ICON_LEFT);
|
||||
|
@ -6924,15 +6919,6 @@ uiBut *uiDefSearchButO_ptr(uiBlock *block,
|
|||
return but;
|
||||
}
|
||||
|
||||
void UI_but_datasetrow_indentation_set(uiBut *but, int indentation)
|
||||
{
|
||||
uiButDatasetRow *but_dataset = (uiButDatasetRow *)but;
|
||||
BLI_assert(but->type == UI_BTYPE_DATASETROW);
|
||||
|
||||
but_dataset->indentation = indentation;
|
||||
BLI_assert(indentation >= 0);
|
||||
}
|
||||
|
||||
void UI_but_treerow_indentation_set(uiBut *but, int indentation)
|
||||
{
|
||||
uiButTreeRow *but_row = (uiButTreeRow *)but;
|
||||
|
@ -6950,38 +6936,6 @@ void UI_but_hint_drawstr_set(uiBut *but, const char *string)
|
|||
ui_but_add_shortcut(but, string, false);
|
||||
}
|
||||
|
||||
void UI_but_datasetrow_component_set(uiBut *but, uint8_t geometry_component_type)
|
||||
{
|
||||
uiButDatasetRow *but_dataset_row = (uiButDatasetRow *)but;
|
||||
BLI_assert(but->type == UI_BTYPE_DATASETROW);
|
||||
|
||||
but_dataset_row->geometry_component_type = geometry_component_type;
|
||||
}
|
||||
|
||||
void UI_but_datasetrow_domain_set(uiBut *but, uint8_t attribute_domain)
|
||||
{
|
||||
uiButDatasetRow *but_dataset_row = (uiButDatasetRow *)but;
|
||||
BLI_assert(but->type == UI_BTYPE_DATASETROW);
|
||||
|
||||
but_dataset_row->attribute_domain = attribute_domain;
|
||||
}
|
||||
|
||||
uint8_t UI_but_datasetrow_component_get(uiBut *but)
|
||||
{
|
||||
uiButDatasetRow *but_dataset_row = (uiButDatasetRow *)but;
|
||||
BLI_assert(but->type == UI_BTYPE_DATASETROW);
|
||||
|
||||
return but_dataset_row->geometry_component_type;
|
||||
}
|
||||
|
||||
uint8_t UI_but_datasetrow_domain_get(uiBut *but)
|
||||
{
|
||||
uiButDatasetRow *but_dataset_row = (uiButDatasetRow *)but;
|
||||
BLI_assert(but->type == UI_BTYPE_DATASETROW);
|
||||
|
||||
return but_dataset_row->attribute_domain;
|
||||
}
|
||||
|
||||
void UI_but_node_link_set(uiBut *but, bNodeSocket *socket, const float draw_color[4])
|
||||
{
|
||||
but->flag |= UI_BUT_NODE_LINK;
|
||||
|
|
|
@ -2334,9 +2334,6 @@ static void ui_apply_but(
|
|||
case UI_BTYPE_LISTROW:
|
||||
ui_apply_but_LISTROW(C, block, but, data);
|
||||
break;
|
||||
case UI_BTYPE_DATASETROW:
|
||||
ui_apply_but_ROW(C, block, but, data);
|
||||
break;
|
||||
case UI_BTYPE_TAB:
|
||||
ui_apply_but_TAB(C, but, data);
|
||||
break;
|
||||
|
@ -8012,7 +8009,6 @@ static int ui_do_button(bContext *C, uiBlock *block, uiBut *but, const wmEvent *
|
|||
case UI_BTYPE_CHECKBOX:
|
||||
case UI_BTYPE_CHECKBOX_N:
|
||||
case UI_BTYPE_ROW:
|
||||
case UI_BTYPE_DATASETROW:
|
||||
retval = ui_do_but_TOG(C, but, data, event);
|
||||
break;
|
||||
case UI_BTYPE_TREEROW:
|
||||
|
|
|
@ -351,14 +351,6 @@ typedef struct uiButProgressbar {
|
|||
float progress;
|
||||
} uiButProgressbar;
|
||||
|
||||
/** Derived struct for #UI_BTYPE_DATASETROW. */
|
||||
typedef struct uiButDatasetRow {
|
||||
uiBut but;
|
||||
|
||||
uint8_t geometry_component_type;
|
||||
uint8_t attribute_domain;
|
||||
int indentation;
|
||||
} uiButDatasetRow;
|
||||
|
||||
/** Derived struct for #UI_BTYPE_TREEROW. */
|
||||
typedef struct uiButTreeRow {
|
||||
|
|
|
@ -69,7 +69,6 @@ bool ui_but_is_toggle(const uiBut *but)
|
|||
UI_BTYPE_CHECKBOX,
|
||||
UI_BTYPE_CHECKBOX_N,
|
||||
UI_BTYPE_ROW,
|
||||
UI_BTYPE_DATASETROW,
|
||||
UI_BTYPE_TREEROW);
|
||||
}
|
||||
|
||||
|
|
|
@ -114,7 +114,6 @@ typedef enum {
|
|||
UI_WTYPE_LISTITEM,
|
||||
UI_WTYPE_PROGRESSBAR,
|
||||
UI_WTYPE_NODESOCKET,
|
||||
UI_WTYPE_DATASETROW,
|
||||
UI_WTYPE_TREEROW,
|
||||
} uiWidgetTypeEnum;
|
||||
|
||||
|
@ -3675,13 +3674,7 @@ static void widget_treerow(
|
|||
widget_treerow_exec(wcol, rect, state, roundboxalign, tree_row->indentation);
|
||||
}
|
||||
|
||||
static void widget_datasetrow(
|
||||
uiBut *but, uiWidgetColors *wcol, rcti *rect, int state, int roundboxalign)
|
||||
{
|
||||
uiButDatasetRow *dataset_row = (uiButDatasetRow *)but;
|
||||
BLI_assert(but->type == UI_BTYPE_DATASETROW);
|
||||
widget_treerow_exec(wcol, rect, state, roundboxalign, dataset_row->indentation);
|
||||
}
|
||||
|
||||
|
||||
static void widget_nodesocket(
|
||||
uiBut *but, uiWidgetColors *wcol, rcti *rect, int UNUSED(state), int UNUSED(roundboxalign))
|
||||
|
@ -4476,9 +4469,6 @@ static uiWidgetType *widget_type(uiWidgetTypeEnum type)
|
|||
wt.custom = widget_progressbar;
|
||||
break;
|
||||
|
||||
case UI_WTYPE_DATASETROW:
|
||||
wt.custom = widget_datasetrow;
|
||||
break;
|
||||
|
||||
case UI_WTYPE_TREEROW:
|
||||
wt.custom = widget_treerow;
|
||||
|
@ -4811,11 +4801,6 @@ void ui_draw_but(const bContext *C, struct ARegion *region, uiStyle *style, uiBu
|
|||
fstyle = &style->widgetlabel;
|
||||
break;
|
||||
|
||||
case UI_BTYPE_DATASETROW:
|
||||
wt = widget_type(UI_WTYPE_DATASETROW);
|
||||
fstyle = &style->widgetlabel;
|
||||
break;
|
||||
|
||||
case UI_BTYPE_TREEROW:
|
||||
wt = widget_type(UI_WTYPE_TREEROW);
|
||||
fstyle = &style->widgetlabel;
|
||||
|
|
|
@ -350,9 +350,14 @@ void AbstractTreeViewItem::on_activate()
|
|||
/* Do nothing by default. */
|
||||
}
|
||||
|
||||
void AbstractTreeViewItem::is_active(IsActiveFn is_active_fn)
|
||||
std::optional<bool> AbstractTreeViewItem::should_be_active() const
|
||||
{
|
||||
is_active_fn_ = is_active_fn;
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
bool AbstractTreeViewItem::supports_collapsing() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
std::unique_ptr<AbstractTreeViewItemDragController> AbstractTreeViewItem::create_drag_controller()
|
||||
|
@ -504,7 +509,10 @@ void AbstractTreeViewItem::set_collapsed(bool collapsed)
|
|||
|
||||
bool AbstractTreeViewItem::is_collapsible() const
|
||||
{
|
||||
return !children_.is_empty();
|
||||
if (children_.is_empty()) {
|
||||
return false;
|
||||
}
|
||||
return this->supports_collapsing();
|
||||
}
|
||||
|
||||
bool AbstractTreeViewItem::is_renaming() const
|
||||
|
@ -546,7 +554,8 @@ uiButTreeRow *AbstractTreeViewItem::tree_row_button()
|
|||
|
||||
void AbstractTreeViewItem::change_state_delayed()
|
||||
{
|
||||
if (is_active_fn_ && is_active_fn_()) {
|
||||
const std::optional<bool> should_be_active = this->should_be_active();
|
||||
if (should_be_active.has_value() && *should_be_active) {
|
||||
activate();
|
||||
}
|
||||
}
|
||||
|
@ -670,11 +679,24 @@ void BasicTreeViewItem::on_activate()
|
|||
}
|
||||
}
|
||||
|
||||
void BasicTreeViewItem::on_activate(ActivateFn fn)
|
||||
void BasicTreeViewItem::set_on_activate_fn(ActivateFn fn)
|
||||
{
|
||||
activate_fn_ = fn;
|
||||
}
|
||||
|
||||
void BasicTreeViewItem::set_is_active_fn(IsActiveFn is_active_fn)
|
||||
{
|
||||
is_active_fn_ = is_active_fn;
|
||||
}
|
||||
|
||||
std::optional<bool> BasicTreeViewItem::should_be_active() const
|
||||
{
|
||||
if (is_active_fn_) {
|
||||
return is_active_fn_();
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
} // namespace blender::ui
|
||||
|
||||
using namespace blender::ui;
|
||||
|
|
|
@ -191,7 +191,8 @@ ui::BasicTreeViewItem &AssetCatalogTreeView::build_catalog_items_recursive(
|
|||
{
|
||||
ui::BasicTreeViewItem &view_item = view_parent_item.add_tree_item<AssetCatalogTreeViewItem>(
|
||||
&catalog);
|
||||
view_item.is_active([this, &catalog]() { return is_active_catalog(catalog.get_catalog_id()); });
|
||||
view_item.set_is_active_fn(
|
||||
[this, &catalog]() { return is_active_catalog(catalog.get_catalog_id()); });
|
||||
|
||||
catalog.foreach_child([&view_item, this](AssetCatalogTreeItem &child) {
|
||||
build_catalog_items_recursive(view_item, child);
|
||||
|
@ -205,11 +206,11 @@ void AssetCatalogTreeView::add_all_item()
|
|||
|
||||
AssetCatalogTreeViewAllItem &item = add_tree_item<AssetCatalogTreeViewAllItem>(IFACE_("All"),
|
||||
ICON_HOME);
|
||||
item.on_activate([params](ui::BasicTreeViewItem & /*item*/) {
|
||||
item.set_on_activate_fn([params](ui::BasicTreeViewItem & /*item*/) {
|
||||
params->asset_catalog_visibility = FILE_SHOW_ASSETS_ALL_CATALOGS;
|
||||
WM_main_add_notifier(NC_SPACE | ND_SPACE_ASSET_PARAMS, nullptr);
|
||||
});
|
||||
item.is_active(
|
||||
item.set_is_active_fn(
|
||||
[params]() { return params->asset_catalog_visibility == FILE_SHOW_ASSETS_ALL_CATALOGS; });
|
||||
}
|
||||
|
||||
|
@ -220,11 +221,11 @@ void AssetCatalogTreeView::add_unassigned_item()
|
|||
AssetCatalogTreeViewUnassignedItem &item = add_tree_item<AssetCatalogTreeViewUnassignedItem>(
|
||||
IFACE_("Unassigned"), ICON_FILE_HIDDEN);
|
||||
|
||||
item.on_activate([params](ui::BasicTreeViewItem & /*item*/) {
|
||||
item.set_on_activate_fn([params](ui::BasicTreeViewItem & /*item*/) {
|
||||
params->asset_catalog_visibility = FILE_SHOW_ASSETS_WITHOUT_CATALOG;
|
||||
WM_main_add_notifier(NC_SPACE | ND_SPACE_ASSET_PARAMS, nullptr);
|
||||
});
|
||||
item.is_active(
|
||||
item.set_is_active_fn(
|
||||
[params]() { return params->asset_catalog_visibility == FILE_SHOW_ASSETS_WITHOUT_CATALOG; });
|
||||
}
|
||||
|
||||
|
|
|
@ -41,10 +41,10 @@ set(SRC
|
|||
spreadsheet_data_source.cc
|
||||
spreadsheet_data_source_geometry.cc
|
||||
spreadsheet_dataset_draw.cc
|
||||
spreadsheet_dataset_layout.cc
|
||||
spreadsheet_draw.cc
|
||||
spreadsheet_layout.cc
|
||||
spreadsheet_ops.cc
|
||||
spreadsheet_panels.cc
|
||||
spreadsheet_row_filter.cc
|
||||
spreadsheet_row_filter_ui.cc
|
||||
|
||||
|
@ -56,7 +56,6 @@ set(SRC
|
|||
spreadsheet_data_source.hh
|
||||
spreadsheet_data_source_geometry.hh
|
||||
spreadsheet_dataset_draw.hh
|
||||
spreadsheet_dataset_layout.hh
|
||||
spreadsheet_draw.hh
|
||||
spreadsheet_intern.hh
|
||||
spreadsheet_layout.hh
|
||||
|
|
|
@ -41,6 +41,8 @@
|
|||
#include "WM_api.h"
|
||||
#include "WM_types.h"
|
||||
|
||||
#include "BLT_translation.h"
|
||||
|
||||
#include "BLF_api.h"
|
||||
|
||||
#include "spreadsheet_intern.hh"
|
||||
|
@ -591,35 +593,10 @@ static void spreadsheet_dataset_region_listener(const wmRegionListenerParams *pa
|
|||
spreadsheet_header_region_listener(params);
|
||||
}
|
||||
|
||||
static void spreadsheet_dataset_region_init(wmWindowManager *wm, ARegion *region)
|
||||
{
|
||||
region->v2d.scroll |= V2D_SCROLL_RIGHT;
|
||||
region->v2d.scroll &= ~(V2D_SCROLL_LEFT | V2D_SCROLL_TOP | V2D_SCROLL_BOTTOM);
|
||||
region->v2d.scroll |= V2D_SCROLL_HORIZONTAL_HIDE;
|
||||
region->v2d.scroll |= V2D_SCROLL_VERTICAL_HIDE;
|
||||
|
||||
UI_view2d_region_reinit(®ion->v2d, V2D_COMMONVIEW_LIST, region->winx, region->winy);
|
||||
|
||||
wmKeyMap *keymap = WM_keymap_ensure(
|
||||
wm->defaultconf, "Spreadsheet Generic", SPACE_SPREADSHEET, 0);
|
||||
WM_event_add_keymap_handler(®ion->handlers, keymap);
|
||||
}
|
||||
|
||||
static void spreadsheet_dataset_region_draw(const bContext *C, ARegion *region)
|
||||
{
|
||||
spreadsheet_update_context_path(C);
|
||||
|
||||
View2D *v2d = ®ion->v2d;
|
||||
UI_view2d_view_ortho(v2d);
|
||||
UI_ThemeClearColor(TH_BACK);
|
||||
|
||||
draw_dataset_in_region(C, region);
|
||||
|
||||
/* reset view matrix */
|
||||
UI_view2d_view_restore(C);
|
||||
|
||||
/* scrollers */
|
||||
UI_view2d_scrollers_draw(v2d, nullptr);
|
||||
ED_region_panels(C, region);
|
||||
}
|
||||
|
||||
static void spreadsheet_sidebar_init(wmWindowManager *wm, ARegion *region)
|
||||
|
@ -710,11 +687,12 @@ void ED_spacetype_spreadsheet(void)
|
|||
/* regions: channels */
|
||||
art = (ARegionType *)MEM_callocN(sizeof(ARegionType), "spreadsheet dataset region");
|
||||
art->regionid = RGN_TYPE_CHANNELS;
|
||||
art->prefsizex = 200 + V2D_SCROLL_WIDTH;
|
||||
art->prefsizex = 150 + V2D_SCROLL_WIDTH;
|
||||
art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_VIEW2D;
|
||||
art->init = spreadsheet_dataset_region_init;
|
||||
art->init = ED_region_panels_init;
|
||||
art->draw = spreadsheet_dataset_region_draw;
|
||||
art->listener = spreadsheet_dataset_region_listener;
|
||||
blender::ed::spreadsheet::spreadsheet_data_set_region_panels_register(*art);
|
||||
BLI_addhead(&st->regiontypes, art);
|
||||
|
||||
BKE_spacetype_register(st);
|
||||
|
|
|
@ -582,8 +582,7 @@ int VolumeDataSource::tot_rows() const
|
|||
}
|
||||
|
||||
GeometrySet spreadsheet_get_display_geometry_set(const SpaceSpreadsheet *sspreadsheet,
|
||||
Object *object_eval,
|
||||
const GeometryComponentType used_component_type)
|
||||
Object *object_eval)
|
||||
{
|
||||
GeometrySet geometry_set;
|
||||
if (sspreadsheet->object_eval_state == SPREADSHEET_OBJECT_EVAL_STATE_ORIGINAL) {
|
||||
|
@ -615,7 +614,7 @@ GeometrySet spreadsheet_get_display_geometry_set(const SpaceSpreadsheet *sspread
|
|||
}
|
||||
}
|
||||
else {
|
||||
if (used_component_type == GEO_COMPONENT_TYPE_MESH && object_eval->mode == OB_MODE_EDIT) {
|
||||
if (object_eval->mode == OB_MODE_EDIT && object_eval->type == OB_MESH) {
|
||||
Mesh *mesh = BKE_modifier_get_evaluated_mesh_from_evaluated_object(object_eval, false);
|
||||
if (mesh == nullptr) {
|
||||
return geometry_set;
|
||||
|
@ -762,8 +761,7 @@ std::unique_ptr<DataSource> data_source_from_geometry(const bContext *C, Object
|
|||
SpaceSpreadsheet *sspreadsheet = CTX_wm_space_spreadsheet(C);
|
||||
const AttributeDomain domain = (AttributeDomain)sspreadsheet->attribute_domain;
|
||||
const GeometryComponentType component_type = get_display_component_type(C, object_eval);
|
||||
GeometrySet geometry_set = spreadsheet_get_display_geometry_set(
|
||||
sspreadsheet, object_eval, component_type);
|
||||
GeometrySet geometry_set = spreadsheet_get_display_geometry_set(sspreadsheet, object_eval);
|
||||
|
||||
if (!geometry_set.has(component_type)) {
|
||||
return {};
|
||||
|
|
|
@ -14,288 +14,226 @@
|
|||
* 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 "BKE_volume.h"
|
||||
|
||||
#include "BLF_api.h"
|
||||
|
||||
#include "BLI_rect.h"
|
||||
|
||||
#include "RNA_access.h"
|
||||
|
||||
#include "UI_interface.h"
|
||||
#include "UI_view2d.h"
|
||||
#include "UI_interface.hh"
|
||||
#include "UI_tree_view.hh"
|
||||
|
||||
#include "WM_types.h"
|
||||
|
||||
#include "BLT_translation.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_VOLUME) {
|
||||
is_selected = is_component_selected;
|
||||
}
|
||||
|
||||
return is_selected;
|
||||
}
|
||||
|
||||
namespace blender::ed::spreadsheet {
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/* Draw Context */
|
||||
class GeometryDataSetTreeView;
|
||||
|
||||
class DatasetDrawContext {
|
||||
std::array<int, 2> mval_;
|
||||
class GeometryDataSetTreeViewItem : public ui::AbstractTreeViewItem {
|
||||
GeometryComponentType component_type_;
|
||||
std::optional<AttributeDomain> domain_;
|
||||
BIFIconID icon_;
|
||||
|
||||
public:
|
||||
const SpaceSpreadsheet *sspreadsheet;
|
||||
Object *object_eval;
|
||||
/* Current geometry set, changes per component. */
|
||||
GeometrySet current_geometry_set;
|
||||
GeometryDataSetTreeViewItem(GeometryComponentType component_type,
|
||||
StringRef label,
|
||||
BIFIconID icon);
|
||||
GeometryDataSetTreeViewItem(GeometryComponentType component_type,
|
||||
AttributeDomain domain,
|
||||
StringRef label,
|
||||
BIFIconID icon);
|
||||
|
||||
DatasetDrawContext(const bContext *C);
|
||||
void on_activate() override;
|
||||
|
||||
GeometrySet geometry_set_from_component(GeometryComponentType component);
|
||||
const std::array<int, 2> &cursor_mval() const;
|
||||
void build_row(uiLayout &row) override;
|
||||
|
||||
protected:
|
||||
std::optional<bool> should_be_active() const override;
|
||||
bool supports_collapsing() const override;
|
||||
|
||||
private:
|
||||
GeometryDataSetTreeView &get_tree() const;
|
||||
std::optional<int> count() const;
|
||||
};
|
||||
|
||||
DatasetDrawContext::DatasetDrawContext(const bContext *C)
|
||||
: sspreadsheet(CTX_wm_space_spreadsheet(C)),
|
||||
object_eval(spreadsheet_get_object_eval(sspreadsheet, CTX_data_depsgraph_pointer(C)))
|
||||
class GeometryDataSetTreeView : public ui::AbstractTreeView {
|
||||
GeometrySet geometry_set_;
|
||||
const bContext &C_;
|
||||
SpaceSpreadsheet &sspreadsheet_;
|
||||
bScreen &screen_;
|
||||
|
||||
friend class GeometryDataSetTreeViewItem;
|
||||
|
||||
public:
|
||||
GeometryDataSetTreeView(GeometrySet geometry_set, const bContext &C)
|
||||
: geometry_set_(std::move(geometry_set)),
|
||||
C_(C),
|
||||
sspreadsheet_(*CTX_wm_space_spreadsheet(&C)),
|
||||
screen_(*CTX_wm_screen(&C))
|
||||
{
|
||||
}
|
||||
|
||||
void build_tree() override
|
||||
{
|
||||
GeometryDataSetTreeViewItem &mesh = this->add_tree_item<GeometryDataSetTreeViewItem>(
|
||||
GEO_COMPONENT_TYPE_MESH, IFACE_("Mesh"), ICON_MESH_DATA);
|
||||
mesh.add_tree_item<GeometryDataSetTreeViewItem>(
|
||||
GEO_COMPONENT_TYPE_MESH, ATTR_DOMAIN_POINT, IFACE_("Vertex"), ICON_VERTEXSEL);
|
||||
mesh.add_tree_item<GeometryDataSetTreeViewItem>(
|
||||
GEO_COMPONENT_TYPE_MESH, ATTR_DOMAIN_EDGE, IFACE_("Edge"), ICON_EDGESEL);
|
||||
mesh.add_tree_item<GeometryDataSetTreeViewItem>(
|
||||
GEO_COMPONENT_TYPE_MESH, ATTR_DOMAIN_FACE, IFACE_("Face"), ICON_FACESEL);
|
||||
mesh.add_tree_item<GeometryDataSetTreeViewItem>(
|
||||
GEO_COMPONENT_TYPE_MESH, ATTR_DOMAIN_CORNER, IFACE_("Face Corner"), ICON_NODE_CORNER);
|
||||
|
||||
GeometryDataSetTreeViewItem &curve = this->add_tree_item<GeometryDataSetTreeViewItem>(
|
||||
GEO_COMPONENT_TYPE_CURVE, IFACE_("Curve"), ICON_CURVE_DATA);
|
||||
curve.add_tree_item<GeometryDataSetTreeViewItem>(GEO_COMPONENT_TYPE_CURVE,
|
||||
ATTR_DOMAIN_POINT,
|
||||
IFACE_("Control Point"),
|
||||
ICON_CURVE_BEZCIRCLE);
|
||||
curve.add_tree_item<GeometryDataSetTreeViewItem>(
|
||||
GEO_COMPONENT_TYPE_CURVE, ATTR_DOMAIN_CURVE, IFACE_("Spline"), ICON_CURVE_PATH);
|
||||
|
||||
GeometryDataSetTreeViewItem &pointcloud = this->add_tree_item<GeometryDataSetTreeViewItem>(
|
||||
GEO_COMPONENT_TYPE_POINT_CLOUD, IFACE_("Point Cloud"), ICON_POINTCLOUD_DATA);
|
||||
pointcloud.add_tree_item<GeometryDataSetTreeViewItem>(
|
||||
GEO_COMPONENT_TYPE_POINT_CLOUD, ATTR_DOMAIN_POINT, IFACE_("Point"), ICON_PARTICLE_POINT);
|
||||
|
||||
this->add_tree_item<GeometryDataSetTreeViewItem>(
|
||||
GEO_COMPONENT_TYPE_VOLUME, IFACE_("Volume Grids"), ICON_VOLUME_DATA);
|
||||
|
||||
this->add_tree_item<GeometryDataSetTreeViewItem>(
|
||||
GEO_COMPONENT_TYPE_INSTANCES, ATTR_DOMAIN_INSTANCE, IFACE_("Instances"), ICON_EMPTY_AXIS);
|
||||
}
|
||||
};
|
||||
|
||||
GeometryDataSetTreeViewItem::GeometryDataSetTreeViewItem(GeometryComponentType component_type,
|
||||
StringRef label,
|
||||
BIFIconID icon)
|
||||
: component_type_(component_type), domain_(std::nullopt), icon_(icon)
|
||||
{
|
||||
const wmWindow *win = CTX_wm_window(C);
|
||||
const ARegion *region = CTX_wm_region(C);
|
||||
mval_ = {win->eventstate->xy[0] - region->winrct.xmin,
|
||||
win->eventstate->xy[1] - region->winrct.ymin};
|
||||
label_ = label;
|
||||
this->set_collapsed(false);
|
||||
}
|
||||
GeometryDataSetTreeViewItem::GeometryDataSetTreeViewItem(GeometryComponentType component_type,
|
||||
AttributeDomain domain,
|
||||
StringRef label,
|
||||
BIFIconID icon)
|
||||
: component_type_(component_type), domain_(domain), icon_(icon)
|
||||
{
|
||||
label_ = label;
|
||||
}
|
||||
|
||||
GeometrySet DatasetDrawContext::geometry_set_from_component(GeometryComponentType component)
|
||||
void GeometryDataSetTreeViewItem::on_activate()
|
||||
{
|
||||
return spreadsheet_get_display_geometry_set(sspreadsheet, object_eval, component);
|
||||
GeometryDataSetTreeView &tree_view = this->get_tree();
|
||||
bContext &C = const_cast<bContext &>(tree_view.C_);
|
||||
SpaceSpreadsheet &sspreadsheet = tree_view.sspreadsheet_;
|
||||
tree_view.sspreadsheet_.geometry_component_type = component_type_;
|
||||
if (domain_) {
|
||||
tree_view.sspreadsheet_.attribute_domain = *domain_;
|
||||
}
|
||||
PointerRNA ptr;
|
||||
RNA_pointer_create(&tree_view.screen_.id, &RNA_SpaceSpreadsheet, &sspreadsheet, &ptr);
|
||||
RNA_property_update(&C, &ptr, RNA_struct_find_property(&ptr, "attribute_domain"));
|
||||
RNA_property_update(&C, &ptr, RNA_struct_find_property(&ptr, "geometry_component_type"));
|
||||
}
|
||||
|
||||
const std::array<int, 2> &DatasetDrawContext::cursor_mval() const
|
||||
void GeometryDataSetTreeViewItem::build_row(uiLayout &row)
|
||||
{
|
||||
return mval_;
|
||||
uiItemL(&row, label_.c_str(), icon_);
|
||||
|
||||
if (const std::optional<int> count = this->count()) {
|
||||
/* Using the tree row button instead of a separate right aligned button gives padding
|
||||
* to the right side of the number, which it didn't have with the button. */
|
||||
char element_count[7];
|
||||
BLI_str_format_attribute_domain_size(element_count, *count);
|
||||
UI_but_hint_drawstr_set((uiBut *)this->tree_row_button(), element_count);
|
||||
}
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/* 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)
|
||||
std::optional<bool> GeometryDataSetTreeViewItem::should_be_active() const
|
||||
{
|
||||
GeometryDataSetTreeView &tree_view = this->get_tree();
|
||||
SpaceSpreadsheet &sspreadsheet = tree_view.sspreadsheet_;
|
||||
|
||||
if (component_type_ == GEO_COMPONENT_TYPE_VOLUME) {
|
||||
return sspreadsheet.geometry_component_type == component_type_;
|
||||
}
|
||||
|
||||
if (!domain_) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return sspreadsheet.geometry_component_type == component_type_ &&
|
||||
sspreadsheet.attribute_domain == *domain_;
|
||||
}
|
||||
|
||||
void DatasetRegionDrawer::draw_hierarchy(const DatasetLayoutHierarchy &layout)
|
||||
bool GeometryDataSetTreeViewItem::supports_collapsing() const
|
||||
{
|
||||
for (const DatasetComponentLayoutInfo &component : layout.components) {
|
||||
draw_context.current_geometry_set = draw_context.geometry_set_from_component(component.type);
|
||||
return false;
|
||||
}
|
||||
|
||||
draw_component_row(component);
|
||||
GeometryDataSetTreeView &GeometryDataSetTreeViewItem::get_tree() const
|
||||
{
|
||||
return static_cast<GeometryDataSetTreeView &>(this->get_tree_view());
|
||||
}
|
||||
|
||||
/* 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 (const auto &optional_domain : component.attr_domains) {
|
||||
if (!optional_domain) {
|
||||
continue;
|
||||
}
|
||||
std::optional<int> GeometryDataSetTreeViewItem::count() const
|
||||
{
|
||||
GeometryDataSetTreeView &tree_view = this->get_tree();
|
||||
GeometrySet &geometry = tree_view.geometry_set_;
|
||||
|
||||
const DatasetAttrDomainLayoutInfo &domain_info = *optional_domain;
|
||||
draw_attribute_domain_row(component, domain_info);
|
||||
/* Special case for volumes since there is no grid domain. */
|
||||
if (component_type_ == GEO_COMPONENT_TYPE_VOLUME) {
|
||||
if (const Volume *volume = geometry.get_volume_for_read()) {
|
||||
return BKE_volume_num_grids(volume);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int element_count_from_volume(const GeometrySet &geometry_set)
|
||||
{
|
||||
if (const Volume *volume = geometry_set.get_volume_for_read()) {
|
||||
return BKE_volume_num_grids(volume);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
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);
|
||||
return 0;
|
||||
}
|
||||
|
||||
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 (!domain_) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
if (geometry_set.has_instances() && component == GEO_COMPONENT_TYPE_INSTANCES) {
|
||||
const InstancesComponent *instances_component =
|
||||
geometry_set.get_component_for_read<InstancesComponent>();
|
||||
return instances_component->attribute_domain_size(domain);
|
||||
if (const GeometryComponent *component = geometry.get_component_for_read(component_type_)) {
|
||||
return 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)
|
||||
void spreadsheet_data_set_panel_draw(const bContext *C, Panel *panel)
|
||||
{
|
||||
|
||||
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];
|
||||
if (component == GEO_COMPONENT_TYPE_VOLUME) {
|
||||
BLI_str_format_attribute_domain_size(
|
||||
element_count, element_count_from_volume(draw_context.current_geometry_set));
|
||||
}
|
||||
else {
|
||||
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",
|
||||
WM_OP_INVOKE_DEFAULT,
|
||||
icon,
|
||||
label,
|
||||
rect.xmin,
|
||||
rect.ymin,
|
||||
BLI_rctf_size_x(&rect),
|
||||
BLI_rctf_size_y(&rect),
|
||||
nullptr);
|
||||
|
||||
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,
|
||||
ATTR_DOMAIN_INSTANCE,
|
||||
component_info.icon,
|
||||
component_info.label,
|
||||
true);
|
||||
}
|
||||
else if (component_info.type == GEO_COMPONENT_TYPE_VOLUME) {
|
||||
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. */
|
||||
const SpaceSpreadsheet *sspreadsheet = CTX_wm_space_spreadsheet(C);
|
||||
Object *object = spreadsheet_get_object_eval(sspreadsheet, CTX_data_depsgraph_pointer(C));
|
||||
if (!object) {
|
||||
return;
|
||||
}
|
||||
uiLayout *layout = panel->layout;
|
||||
|
||||
uiBlock *block = UI_block_begin(C, region, __func__, UI_EMBOSS);
|
||||
uiBlock *block = uiLayoutGetBlock(layout);
|
||||
|
||||
DatasetRegionDrawer drawer{region, *block, draw_context};
|
||||
UI_block_layout_set_current(block, layout);
|
||||
|
||||
/* 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;
|
||||
ui::AbstractTreeView *tree_view = UI_block_add_view(
|
||||
*block,
|
||||
"Data Set Tree View",
|
||||
std::make_unique<GeometryDataSetTreeView>(
|
||||
spreadsheet_get_display_geometry_set(sspreadsheet, object), *C));
|
||||
|
||||
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(®ion->v2d, region->winx, abs(drawer.ymin_offset));
|
||||
UI_block_draw(C, block);
|
||||
ui::TreeViewBuilder builder(*block);
|
||||
builder.build_tree_view(*tree_view);
|
||||
}
|
||||
|
||||
} // namespace blender::ed::spreadsheet
|
||||
|
|
|
@ -16,49 +16,11 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
|
||||
#include "BKE_geometry_set.hh"
|
||||
#include "UI_interface.h"
|
||||
#include "spreadsheet_dataset_layout.hh"
|
||||
|
||||
struct ARegion;
|
||||
struct View2D;
|
||||
struct Panel;
|
||||
struct bContext;
|
||||
struct uiBlock;
|
||||
|
||||
namespace blender::ed::spreadsheet {
|
||||
|
||||
class DatasetDrawContext;
|
||||
|
||||
class DatasetRegionDrawer {
|
||||
public:
|
||||
const int row_height;
|
||||
float ymin_offset = 0;
|
||||
|
||||
int xmin;
|
||||
int xmax;
|
||||
uiBlock █
|
||||
const View2D &v2d;
|
||||
DatasetDrawContext &draw_context;
|
||||
|
||||
DatasetRegionDrawer(const ARegion *region, uiBlock &block, DatasetDrawContext &draw_context);
|
||||
|
||||
void draw_hierarchy(const DatasetLayoutHierarchy &layout);
|
||||
|
||||
void draw_attribute_domain_row(const DatasetComponentLayoutInfo &component,
|
||||
const DatasetAttrDomainLayoutInfo &domain_info);
|
||||
void draw_component_row(const DatasetComponentLayoutInfo &component_info);
|
||||
|
||||
private:
|
||||
void draw_dataset_row(const int indentation,
|
||||
const GeometryComponentType component,
|
||||
const std::optional<AttributeDomain> domain,
|
||||
const BIFIconID icon,
|
||||
const char *label,
|
||||
const bool is_active);
|
||||
};
|
||||
|
||||
void draw_dataset_in_region(const bContext *C, ARegion *region);
|
||||
void spreadsheet_data_set_panel_draw(const bContext *C, Panel *panel);
|
||||
|
||||
} // namespace blender::ed::spreadsheet
|
||||
|
|
|
@ -1,118 +0,0 @@
|
|||
/*
|
||||
* 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 <optional>
|
||||
|
||||
#include "BLI_span.hh"
|
||||
|
||||
#include "BLT_translation.h"
|
||||
|
||||
#include "spreadsheet_dataset_layout.hh"
|
||||
|
||||
namespace blender::ed::spreadsheet {
|
||||
|
||||
#define ATTR_INFO(type, label, icon) \
|
||||
std::optional<DatasetAttrDomainLayoutInfo> \
|
||||
{ \
|
||||
std::in_place, type, label, icon \
|
||||
}
|
||||
#define ATTR_INFO_NONE(type) \
|
||||
{ \
|
||||
std::nullopt \
|
||||
}
|
||||
|
||||
/**
|
||||
* Definition for the component->attribute-domain hierarchy.
|
||||
* Constructed at compile time.
|
||||
*
|
||||
* \warning Order of attribute-domains matters! It __must__ match the #AttributeDomain
|
||||
* definition and fill gaps with unset optionals (i.e. `std::nullopt`). Would be nice to use
|
||||
* array designators for this (which C++ doesn't support).
|
||||
*/
|
||||
constexpr DatasetComponentLayoutInfo DATASET_layout_hierarchy[] = {
|
||||
{
|
||||
GEO_COMPONENT_TYPE_MESH,
|
||||
N_("Mesh"),
|
||||
ICON_MESH_DATA,
|
||||
{
|
||||
ATTR_INFO(ATTR_DOMAIN_POINT, N_("Vertex"), ICON_VERTEXSEL),
|
||||
ATTR_INFO(ATTR_DOMAIN_EDGE, N_("Edge"), ICON_EDGESEL),
|
||||
ATTR_INFO(ATTR_DOMAIN_FACE, N_("Face"), ICON_FACESEL),
|
||||
ATTR_INFO(ATTR_DOMAIN_CORNER, N_("Face Corner"), ICON_NODE_CORNER),
|
||||
},
|
||||
},
|
||||
{
|
||||
GEO_COMPONENT_TYPE_CURVE,
|
||||
N_("Curves"),
|
||||
ICON_CURVE_DATA,
|
||||
{
|
||||
ATTR_INFO(ATTR_DOMAIN_POINT, N_("Control Point"), ICON_CURVE_BEZCIRCLE),
|
||||
ATTR_INFO_NONE(ATTR_DOMAIN_EDGE),
|
||||
ATTR_INFO_NONE(ATTR_DOMAIN_CORNER),
|
||||
ATTR_INFO_NONE(ATTR_DOMAIN_FACE),
|
||||
ATTR_INFO(ATTR_DOMAIN_CURVE, N_("Spline"), ICON_CURVE_PATH),
|
||||
},
|
||||
},
|
||||
{
|
||||
GEO_COMPONENT_TYPE_POINT_CLOUD,
|
||||
N_("Point Cloud"),
|
||||
ICON_POINTCLOUD_DATA,
|
||||
{
|
||||
ATTR_INFO(ATTR_DOMAIN_POINT, N_("Point"), ICON_PARTICLE_POINT),
|
||||
},
|
||||
},
|
||||
{
|
||||
GEO_COMPONENT_TYPE_VOLUME,
|
||||
N_("Volume Grids"),
|
||||
ICON_VOLUME_DATA,
|
||||
{},
|
||||
},
|
||||
{
|
||||
GEO_COMPONENT_TYPE_INSTANCES,
|
||||
N_("Instances"),
|
||||
ICON_EMPTY_AXIS,
|
||||
{},
|
||||
},
|
||||
};
|
||||
|
||||
#undef ATTR_INFO
|
||||
#undef ATTR_INFO_LABEL
|
||||
|
||||
DatasetLayoutHierarchy dataset_layout_hierarchy()
|
||||
{
|
||||
return DatasetLayoutHierarchy{
|
||||
Span{DATASET_layout_hierarchy, ARRAY_SIZE(DATASET_layout_hierarchy)}};
|
||||
}
|
||||
|
||||
#ifndef NDEBUG
|
||||
/**
|
||||
* Debug-only sanity check for correct attribute domain initialization (order/indices must
|
||||
* match AttributeDomain). This doesn't check for all possible missuses, but should catch the most
|
||||
* likely mistakes.
|
||||
*/
|
||||
void dataset_layout_hierarchy_sanity_check(const DatasetLayoutHierarchy &hierarchy)
|
||||
{
|
||||
for (const DatasetComponentLayoutInfo &component : hierarchy.components) {
|
||||
for (uint i = 0; i < component.attr_domains.size(); i++) {
|
||||
if (component.attr_domains[i]) {
|
||||
BLI_assert(component.attr_domains[i]->type == static_cast<AttributeDomain>(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace blender::ed::spreadsheet
|
|
@ -1,68 +0,0 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include <optional>
|
||||
|
||||
/* Enum definitions... */
|
||||
#include "BKE_attribute.h"
|
||||
#include "BKE_geometry_set.h"
|
||||
|
||||
#include "BLI_span.hh"
|
||||
|
||||
/* More enum definitions... */
|
||||
#include "UI_resources.h"
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace blender::ed::spreadsheet {
|
||||
|
||||
struct DatasetAttrDomainLayoutInfo {
|
||||
AttributeDomain type;
|
||||
const char *label;
|
||||
BIFIconID icon;
|
||||
|
||||
constexpr DatasetAttrDomainLayoutInfo(AttributeDomain type, const char *label, BIFIconID icon)
|
||||
: type(type), label(label), icon(icon)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
struct DatasetComponentLayoutInfo {
|
||||
GeometryComponentType type;
|
||||
const char *label;
|
||||
BIFIconID icon;
|
||||
/** Array of attribute-domains. Has to be fixed size based on #AttributeDomain enum, but not all
|
||||
* values need displaying for all parent components. Hence the optional use. */
|
||||
using AttrDomainArray = std::array<std::optional<DatasetAttrDomainLayoutInfo>, ATTR_DOMAIN_NUM>;
|
||||
const AttrDomainArray attr_domains;
|
||||
};
|
||||
|
||||
struct DatasetLayoutHierarchy {
|
||||
/** The components for display (with layout info like icon and label). Each component stores
|
||||
* the attribute domains it wants to display (also with layout info like icon and label). */
|
||||
const Span<DatasetComponentLayoutInfo> components;
|
||||
};
|
||||
|
||||
DatasetLayoutHierarchy dataset_layout_hierarchy();
|
||||
|
||||
#ifndef NDEBUG
|
||||
void dataset_layout_hierarchy_sanity_check(const DatasetLayoutHierarchy &hierarchy);
|
||||
#endif
|
||||
|
||||
} // namespace blender::ed::spreadsheet
|
|
@ -37,6 +37,7 @@ struct SpaceSpreadsheet_Runtime {
|
|||
};
|
||||
|
||||
struct bContext;
|
||||
struct ARegionType;
|
||||
|
||||
void spreadsheet_operatortypes(void);
|
||||
void spreadsheet_update_context_path(const bContext *C);
|
||||
|
@ -45,6 +46,8 @@ Object *spreadsheet_get_object_eval(const SpaceSpreadsheet *sspreadsheet,
|
|||
|
||||
namespace blender::ed::spreadsheet {
|
||||
GeometrySet spreadsheet_get_display_geometry_set(const SpaceSpreadsheet *sspreadsheet,
|
||||
Object *object_eval,
|
||||
const GeometryComponentType used_component_type);
|
||||
}
|
||||
Object *object_eval);
|
||||
|
||||
void spreadsheet_data_set_region_panels_register(ARegionType ®ion_type);
|
||||
|
||||
} // namespace blender::ed::spreadsheet
|
||||
|
|
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* 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 "BKE_screen.h"
|
||||
|
||||
#include "BLT_translation.h"
|
||||
|
||||
#include "spreadsheet_dataset_draw.hh"
|
||||
#include "spreadsheet_intern.hh"
|
||||
|
||||
namespace blender::ed::spreadsheet {
|
||||
|
||||
void spreadsheet_data_set_region_panels_register(ARegionType ®ion_type)
|
||||
{
|
||||
PanelType *panel_type = (PanelType *)MEM_callocN(sizeof(PanelType), __func__);
|
||||
strcpy(panel_type->idname, "SPREADSHEET_PT_data_set");
|
||||
strcpy(panel_type->label, N_("Data Set"));
|
||||
strcpy(panel_type->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA);
|
||||
panel_type->flag = PANEL_TYPE_NO_HEADER;
|
||||
panel_type->draw = spreadsheet_data_set_panel_draw;
|
||||
BLI_addtail(®ion_type.paneltypes, panel_type);
|
||||
}
|
||||
|
||||
} // namespace blender::ed::spreadsheet
|
Loading…
Reference in New Issue