UI: Support persistent view state, write tree-view height to files
Adds support for saving some view state persistently and uses this to keep the height of a tree-view, even as the region containing it is hidden, or the file re-loaded. Fixes #129058. Basically the design is to have state stored in the region, so it can be saved to files. Views types (tree-view, grid-view, etc) can decide themselves if they have state to be preserved, and what state that is. If a view wants to preserve state, it's stored in a list inside the region, identified by the view's idname. Limitation is that multiple instances of the same view would share these bits of state, in practice I don't think that's ever an issue. More state can be added to be preserved as needed. Since different kinds of views may require different state, I was thinking we could add ID properties to `uiViewState` even, making it much more dynamic. Pull Request: https://projects.blender.org/blender/blender/pulls/130292
This commit is contained in:
committed by
Julian Eisel
parent
9f0d20c056
commit
f0db870822
@@ -369,6 +369,8 @@ ARegion *BKE_area_region_copy(const SpaceType *st, const ARegion *region)
|
||||
|
||||
BLI_listbase_clear(&newar->ui_previews);
|
||||
BLI_duplicatelist(&newar->ui_previews, ®ion->ui_previews);
|
||||
BLI_listbase_clear(&newar->view_states);
|
||||
BLI_duplicatelist(&newar->view_states, ®ion->view_states);
|
||||
|
||||
return newar;
|
||||
}
|
||||
@@ -610,6 +612,7 @@ void BKE_area_region_free(SpaceType *st, ARegion *region)
|
||||
BLI_freelistN(®ion->ui_previews);
|
||||
BLI_freelistN(®ion->panels_category);
|
||||
BLI_freelistN(®ion->panels_category_active);
|
||||
BLI_freelistN(®ion->view_states);
|
||||
}
|
||||
|
||||
void BKE_screen_area_free(ScrArea *area)
|
||||
@@ -1143,6 +1146,10 @@ static void write_area(BlendWriter *writer, ScrArea *area)
|
||||
LISTBASE_FOREACH (uiPreview *, ui_preview, ®ion->ui_previews) {
|
||||
BLO_write_struct(writer, uiPreview, ui_preview);
|
||||
}
|
||||
|
||||
LISTBASE_FOREACH (uiViewStateLink *, view_state, ®ion->view_states) {
|
||||
BLO_write_struct(writer, uiViewStateLink, view_state);
|
||||
}
|
||||
}
|
||||
|
||||
LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) {
|
||||
@@ -1199,6 +1206,7 @@ static void direct_link_region(BlendDataReader *reader, ARegion *region, int spa
|
||||
BLO_read_struct_list(reader, PanelCategoryStack, ®ion->panels_category_active);
|
||||
|
||||
BLO_read_struct_list(reader, uiList, ®ion->ui_lists);
|
||||
BLO_read_struct_list(reader, uiViewStateLink, ®ion->view_states);
|
||||
|
||||
/* The area's search filter is runtime only, so we need to clear the active flag on read. */
|
||||
/* Clear runtime flags (e.g. search filter is runtime only). */
|
||||
|
||||
@@ -527,8 +527,7 @@ void region_layout(const bContext *C, ARegion *region)
|
||||
0,
|
||||
style);
|
||||
|
||||
build_asset_view(
|
||||
*layout, active_shelf->settings.asset_library_reference, *active_shelf, *C, *region);
|
||||
build_asset_view(*layout, active_shelf->settings.asset_library_reference, *active_shelf, *C);
|
||||
|
||||
int layout_height;
|
||||
UI_block_layout_resolve(block, nullptr, &layout_height);
|
||||
|
||||
@@ -31,8 +31,7 @@ namespace blender::ed::asset::shelf {
|
||||
void build_asset_view(uiLayout &layout,
|
||||
const AssetLibraryReference &library_ref,
|
||||
const AssetShelf &shelf,
|
||||
const bContext &C,
|
||||
const ARegion ®ion);
|
||||
const bContext &C);
|
||||
|
||||
void catalog_selector_panel_register(ARegionType *region_type);
|
||||
void popover_panel_register(ARegionType *region_type);
|
||||
|
||||
@@ -345,8 +345,7 @@ static std::string filter_string_get(const AssetShelf &shelf)
|
||||
void build_asset_view(uiLayout &layout,
|
||||
const AssetLibraryReference &library_ref,
|
||||
const AssetShelf &shelf,
|
||||
const bContext &C,
|
||||
const ARegion ®ion)
|
||||
const bContext &C)
|
||||
{
|
||||
list::storage_fetch(&library_ref, &C);
|
||||
list::previews_fetch(&library_ref, &C);
|
||||
@@ -371,7 +370,7 @@ void build_asset_view(uiLayout &layout,
|
||||
grid_view->set_context_menu_title("Asset Shelf");
|
||||
|
||||
ui::GridViewBuilder builder(*block);
|
||||
builder.build_grid_view(C, *grid_view, region.v2d, layout, filter_string_get(shelf));
|
||||
builder.build_grid_view(C, *grid_view, layout, filter_string_get(shelf));
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------- */
|
||||
|
||||
@@ -215,7 +215,7 @@ static void catalog_selector_panel_draw(const bContext *C, Panel *panel)
|
||||
"asset catalog tree view",
|
||||
std::make_unique<AssetCatalogSelectorTree>(*library, *shelf));
|
||||
tree_view->set_context_menu_title("Catalog");
|
||||
ui::TreeViewBuilder::build_tree_view(*tree_view, *layout);
|
||||
ui::TreeViewBuilder::build_tree_view(*C, *tree_view, *layout);
|
||||
}
|
||||
|
||||
void catalog_selector_panel_register(ARegionType *region_type)
|
||||
|
||||
@@ -155,7 +155,7 @@ class AssetCatalogTreeView : public ui::AbstractTreeView {
|
||||
}
|
||||
};
|
||||
|
||||
static void catalog_tree_draw(uiLayout &layout, AssetShelf &shelf)
|
||||
static void catalog_tree_draw(const bContext &C, uiLayout &layout, AssetShelf &shelf)
|
||||
{
|
||||
const asset_system::AssetLibrary *library = list::library_get_once_available(
|
||||
shelf.settings.asset_library_reference);
|
||||
@@ -169,7 +169,7 @@ static void catalog_tree_draw(uiLayout &layout, AssetShelf &shelf)
|
||||
"asset shelf catalog tree view",
|
||||
std::make_unique<AssetCatalogTreeView>(*library, shelf));
|
||||
|
||||
ui::TreeViewBuilder::build_tree_view(*tree_view, layout);
|
||||
ui::TreeViewBuilder::build_tree_view(C, *tree_view, layout);
|
||||
}
|
||||
|
||||
static AssetShelfType *lookup_type_from_idname_in_context(const bContext *C)
|
||||
@@ -201,8 +201,6 @@ static void popover_panel_draw(const bContext *C, Panel *panel)
|
||||
AssetShelfType *shelf_type = lookup_type_from_idname_in_context(C);
|
||||
BLI_assert_msg(shelf_type != nullptr, "couldn't find asset shelf type from context");
|
||||
|
||||
const ARegion *region = CTX_wm_region_popup(C) ? CTX_wm_region_popup(C) : CTX_wm_region(C);
|
||||
|
||||
uiLayout *layout = panel->layout;
|
||||
uiLayoutSetUnitsX(layout, layout_width_units);
|
||||
|
||||
@@ -222,7 +220,7 @@ static void popover_panel_draw(const bContext *C, Panel *panel)
|
||||
uiLayoutSetUnitsX(catalogs_col, LEFT_COL_WIDTH_UNITS);
|
||||
uiLayoutSetFixedSize(catalogs_col, true);
|
||||
library_selector_draw(C, catalogs_col, *shelf);
|
||||
catalog_tree_draw(*catalogs_col, *shelf);
|
||||
catalog_tree_draw(*C, *catalogs_col, *shelf);
|
||||
|
||||
uiLayout *right_col = uiLayoutColumn(row, false);
|
||||
uiLayout *sub = uiLayoutRow(right_col, false);
|
||||
@@ -241,7 +239,7 @@ static void popover_panel_draw(const bContext *C, Panel *panel)
|
||||
uiLayoutSetUnitsX(asset_view_col, layout_width_units - LEFT_COL_WIDTH_UNITS);
|
||||
uiLayoutSetFixedSize(asset_view_col, true);
|
||||
|
||||
build_asset_view(*asset_view_col, shelf->settings.asset_library_reference, *shelf, *C, *region);
|
||||
build_asset_view(*asset_view_col, shelf->settings.asset_library_reference, *shelf, *C);
|
||||
}
|
||||
|
||||
static bool popover_panel_poll(const bContext *C, PanelType * /*panel_type*/)
|
||||
|
||||
@@ -104,6 +104,20 @@ class AbstractView {
|
||||
virtual bool supports_scrolling() const;
|
||||
virtual void scroll(ViewScrollDirection direction);
|
||||
|
||||
/**
|
||||
* From the current view state, return certain state that will be written to files (stored in
|
||||
* #ARegion.view_states) to preserve it over UI changes and file loading. The state can be
|
||||
* restored using #persistent_state_apply().
|
||||
*
|
||||
* Return an empty value if there's no state to preserve (default implementation).
|
||||
*/
|
||||
virtual std::optional<uiViewState> persistent_state() const;
|
||||
/**
|
||||
* Restore a view state given in \a state, which was created by #persistent_state() for saving in
|
||||
* files, and potentially loaded from a file.
|
||||
*/
|
||||
virtual void persistent_state_apply(const uiViewState &state);
|
||||
|
||||
/**
|
||||
* Makes \a item valid for display in this view. Behavior is undefined for items not registered
|
||||
* with this.
|
||||
|
||||
@@ -172,7 +172,6 @@ class GridViewBuilder {
|
||||
|
||||
void build_grid_view(const bContext &C,
|
||||
AbstractGridView &grid_view,
|
||||
const View2D &v2d,
|
||||
uiLayout &layout,
|
||||
std::optional<StringRef> search_string = {});
|
||||
};
|
||||
|
||||
@@ -273,6 +273,8 @@ void UI_list_filter_and_sort_items(uiList *ui_list,
|
||||
|
||||
/**
|
||||
* Override this for all available view types.
|
||||
* \param idname: Used for restoring persistent state of this view, potentially written to files.
|
||||
* Must not be longer than #BKE_ST_MAXNAME (including 0 terminator).
|
||||
*/
|
||||
blender::ui::AbstractGridView *UI_block_add_view(
|
||||
uiBlock &block,
|
||||
|
||||
@@ -2857,6 +2857,7 @@ void template_asset_shelf_popover(uiLayout &layout,
|
||||
}
|
||||
|
||||
void uiTemplateLightLinkingCollection(uiLayout *layout,
|
||||
bContext *C,
|
||||
uiLayout *context_layout,
|
||||
PointerRNA *ptr,
|
||||
const char *propname);
|
||||
@@ -2864,7 +2865,7 @@ void uiTemplateLightLinkingCollection(uiLayout *layout,
|
||||
void uiTemplateBoneCollectionTree(uiLayout *layout, bContext *C);
|
||||
void uiTemplateGreasePencilLayerTree(uiLayout *layout, bContext *C);
|
||||
|
||||
void uiTemplateNodeTreeInterface(uiLayout *layout, PointerRNA *ptr);
|
||||
void uiTemplateNodeTreeInterface(uiLayout *layout, bContext *C, PointerRNA *ptr);
|
||||
/**
|
||||
* Draw all node buttons and socket default values with the same panel structure used by the node.
|
||||
*/
|
||||
|
||||
@@ -146,6 +146,9 @@ class AbstractTreeView : public AbstractView, public TreeViewItemContainer {
|
||||
protected:
|
||||
virtual void build_tree() = 0;
|
||||
|
||||
std::optional<uiViewState> persistent_state() const override;
|
||||
void persistent_state_apply(const uiViewState &state) override;
|
||||
|
||||
private:
|
||||
void foreach_view_item(FunctionRef<void(AbstractViewItem &)> iter_fn) const final;
|
||||
void update_children_from_old(const AbstractView &old_view) override;
|
||||
@@ -404,7 +407,8 @@ class TreeViewItemDropTarget : public DropTargetInterface {
|
||||
|
||||
class TreeViewBuilder {
|
||||
public:
|
||||
static void build_tree_view(AbstractTreeView &tree_view,
|
||||
static void build_tree_view(const bContext &C,
|
||||
AbstractTreeView &tree_view,
|
||||
uiLayout &layout,
|
||||
std::optional<StringRef> search_string = {},
|
||||
bool add_box = true);
|
||||
|
||||
@@ -2013,7 +2013,7 @@ void UI_block_end_ex(const bContext *C,
|
||||
/* Update bounds of all views in this block. If this block is a panel, this will be done later in
|
||||
* #UI_panels_end(), because buttons are offset there. */
|
||||
if (!block->panel) {
|
||||
ui_block_views_bounds_calc(block);
|
||||
ui_block_views_end(region, block);
|
||||
}
|
||||
|
||||
if (block->rect.xmin == 0.0f && block->rect.xmax == 0.0f) {
|
||||
|
||||
@@ -1609,7 +1609,10 @@ void ui_interface_tag_script_reload_queries();
|
||||
/* interface_view.cc */
|
||||
|
||||
void ui_block_free_views(uiBlock *block);
|
||||
void ui_block_views_bounds_calc(const uiBlock *block);
|
||||
void ui_block_views_end(ARegion *region, const uiBlock *block);
|
||||
void ui_block_view_persistent_state_restore(const ARegion ®ion,
|
||||
const uiBlock &block,
|
||||
blender::ui::AbstractView &view);
|
||||
void ui_block_views_listen(const uiBlock *block, const wmRegionListenerParams *listener_params);
|
||||
void ui_block_views_draw_overlays(const ARegion *region, const uiBlock *block);
|
||||
blender::ui::AbstractView *ui_block_view_find_matching_in_old_block(
|
||||
|
||||
@@ -1944,7 +1944,7 @@ void UI_panels_end(const bContext *C, ARegion *region, int *r_x, int *r_y)
|
||||
|
||||
/* Update bounds for all "views" in this block. Usually this is done in #UI_block_end(), but
|
||||
* that wouldn't work because of the offset applied above. */
|
||||
ui_block_views_bounds_calc(block);
|
||||
ui_block_views_end(region, block);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -476,5 +476,5 @@ void uiTemplateBoneCollectionTree(uiLayout *layout, bContext *C)
|
||||
tree_view->set_context_menu_title("Bone Collection");
|
||||
tree_view->set_default_rows(3);
|
||||
|
||||
ui::TreeViewBuilder::build_tree_view(*tree_view, *layout);
|
||||
ui::TreeViewBuilder::build_tree_view(*C, *tree_view, *layout);
|
||||
}
|
||||
|
||||
@@ -513,5 +513,5 @@ void uiTemplateGreasePencilLayerTree(uiLayout *layout, bContext *C)
|
||||
tree_view->set_context_menu_title("Grease Pencil Layer");
|
||||
tree_view->set_default_rows(6);
|
||||
|
||||
ui::TreeViewBuilder::build_tree_view(*tree_view, *layout);
|
||||
ui::TreeViewBuilder::build_tree_view(*C, *tree_view, *layout);
|
||||
}
|
||||
|
||||
@@ -355,10 +355,8 @@ class CollectionView : public AbstractTreeView {
|
||||
|
||||
} // namespace blender::ui::light_linking
|
||||
|
||||
void uiTemplateLightLinkingCollection(uiLayout *layout,
|
||||
uiLayout *context_layout,
|
||||
PointerRNA *ptr,
|
||||
const char *propname)
|
||||
void uiTemplateLightLinkingCollection(
|
||||
uiLayout *layout, bContext *C, uiLayout *context_layout, PointerRNA *ptr, const char *propname)
|
||||
{
|
||||
if (!ptr->data) {
|
||||
return;
|
||||
@@ -402,5 +400,5 @@ void uiTemplateLightLinkingCollection(uiLayout *layout,
|
||||
tree_view->set_context_menu_title("Light Linking");
|
||||
tree_view->set_default_rows(3);
|
||||
|
||||
blender::ui::TreeViewBuilder::build_tree_view(*tree_view, *layout);
|
||||
blender::ui::TreeViewBuilder::build_tree_view(*C, *tree_view, *layout);
|
||||
}
|
||||
|
||||
@@ -501,7 +501,7 @@ wmDragNodeTreeInterface *NodePanelDropTarget::get_drag_node_tree_declaration(
|
||||
|
||||
} // namespace blender::ui::nodes
|
||||
|
||||
void uiTemplateNodeTreeInterface(uiLayout *layout, PointerRNA *ptr)
|
||||
void uiTemplateNodeTreeInterface(uiLayout *layout, bContext *C, PointerRNA *ptr)
|
||||
{
|
||||
if (!ptr->data) {
|
||||
return;
|
||||
@@ -521,5 +521,5 @@ void uiTemplateNodeTreeInterface(uiLayout *layout, PointerRNA *ptr)
|
||||
tree_view->set_context_menu_title("Node Tree Interface");
|
||||
tree_view->set_default_rows(3);
|
||||
|
||||
blender::ui::TreeViewBuilder::build_tree_view(*tree_view, *layout);
|
||||
blender::ui::TreeViewBuilder::build_tree_view(*C, *tree_view, *layout);
|
||||
}
|
||||
|
||||
@@ -136,6 +136,13 @@ void AbstractView::scroll(ViewScrollDirection /*direction*/)
|
||||
BLI_assert_msg(false, "Unsupported for this view type");
|
||||
}
|
||||
|
||||
std::optional<uiViewState> AbstractView::persistent_state() const
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
void AbstractView::persistent_state_apply(const uiViewState & /*state*/) {}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* ---------------------------------------------------------------------- */
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
#include <optional>
|
||||
#include <stdexcept>
|
||||
|
||||
#include "BKE_context.hh"
|
||||
#include "BKE_icons.h"
|
||||
|
||||
#include "BLI_index_range.hh"
|
||||
@@ -242,7 +243,7 @@ BuildOnlyVisibleButtonsHelper::BuildOnlyVisibleButtonsHelper(
|
||||
const AbstractGridViewItem *force_visible_item)
|
||||
: grid_view_(grid_view), style_(grid_view.get_style()), cols_per_row_(cols_per_row)
|
||||
{
|
||||
if ((v2d.flag & V2D_IS_INIT) && grid_view.get_item_count_filtered()) {
|
||||
if (v2d.flag & V2D_IS_INIT && grid_view.get_item_count_filtered()) {
|
||||
visible_items_range_ = this->get_visible_range(v2d, force_visible_item);
|
||||
}
|
||||
}
|
||||
@@ -452,12 +453,14 @@ GridViewBuilder::GridViewBuilder(uiBlock & /*block*/) {}
|
||||
|
||||
void GridViewBuilder::build_grid_view(const bContext &C,
|
||||
AbstractGridView &grid_view,
|
||||
const View2D &v2d,
|
||||
uiLayout &layout,
|
||||
std::optional<StringRef> search_string)
|
||||
{
|
||||
uiBlock &block = *uiLayoutGetBlock(&layout);
|
||||
|
||||
const ARegion *region = CTX_wm_region_popup(&C) ? CTX_wm_region_popup(&C) : CTX_wm_region(&C);
|
||||
ui_block_view_persistent_state_restore(*region, block, grid_view);
|
||||
|
||||
grid_view.build_items();
|
||||
grid_view.update_from_old(block);
|
||||
grid_view.change_state_delayed();
|
||||
@@ -467,7 +470,7 @@ void GridViewBuilder::build_grid_view(const bContext &C,
|
||||
UI_block_layout_set_current(&block, &layout);
|
||||
|
||||
GridViewLayoutBuilder builder(layout);
|
||||
builder.build_from_view(C, grid_view, v2d);
|
||||
builder.build_from_view(C, grid_view, region->v2d);
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------- */
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
|
||||
#include "BLI_listbase.h"
|
||||
#include "BLI_map.hh"
|
||||
#include "BLI_string.h"
|
||||
|
||||
#include "ED_screen.hh"
|
||||
|
||||
@@ -56,6 +57,8 @@ static T *ui_block_add_view_impl(uiBlock &block,
|
||||
StringRef idname,
|
||||
std::unique_ptr<AbstractView> view)
|
||||
{
|
||||
BLI_assert(idname.size() < int64_t(sizeof(uiViewStateLink::idname)));
|
||||
|
||||
ViewLink *view_link = MEM_new<ViewLink>(__func__);
|
||||
BLI_addtail(&block.views, view_link);
|
||||
|
||||
@@ -126,9 +129,58 @@ void ViewLink::views_bounds_calc(const uiBlock &block)
|
||||
}
|
||||
}
|
||||
|
||||
void ui_block_views_bounds_calc(const uiBlock *block)
|
||||
void ui_block_view_persistent_state_restore(const ARegion ®ion,
|
||||
const uiBlock &block,
|
||||
ui::AbstractView &view)
|
||||
{
|
||||
StringRef idname = [&]() -> StringRef {
|
||||
LISTBASE_FOREACH (ViewLink *, link, &block.views) {
|
||||
if (link->view.get() == &view) {
|
||||
return link->idname;
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}();
|
||||
|
||||
if (idname.is_empty()) {
|
||||
BLI_assert_unreachable();
|
||||
return;
|
||||
}
|
||||
|
||||
LISTBASE_FOREACH (uiViewStateLink *, stored_state, ®ion.view_states) {
|
||||
if (stored_state->idname == idname) {
|
||||
view.persistent_state_apply(stored_state->state);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static uiViewStateLink *ensure_view_state(ARegion ®ion, const ViewLink &link)
|
||||
{
|
||||
LISTBASE_FOREACH (uiViewStateLink *, stored_state, ®ion.view_states) {
|
||||
if (link.idname == stored_state->idname) {
|
||||
return stored_state;
|
||||
}
|
||||
}
|
||||
|
||||
uiViewStateLink *new_state = MEM_cnew<uiViewStateLink>(__func__);
|
||||
link.idname.copy(new_state->idname, sizeof(new_state->idname));
|
||||
BLI_addhead(®ion.view_states, new_state);
|
||||
return new_state;
|
||||
}
|
||||
|
||||
void ui_block_views_end(ARegion *region, const uiBlock *block)
|
||||
{
|
||||
ViewLink::views_bounds_calc(*block);
|
||||
|
||||
if (region && region->regiontype != RGN_TYPE_TEMPORARY) {
|
||||
LISTBASE_FOREACH (const ViewLink *, link, &block->views) {
|
||||
/* Ensure persistent view state storage for writing to files if needed. */
|
||||
if (std::optional<uiViewState> temp_state = link->view->persistent_state()) {
|
||||
uiViewStateLink *state_link = ensure_view_state(*region, *link);
|
||||
state_link->state = *temp_state;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ui_block_views_listen(const uiBlock *block, const wmRegionListenerParams *listener_params)
|
||||
|
||||
@@ -131,6 +131,28 @@ void AbstractTreeView::set_default_rows(int default_rows)
|
||||
custom_height_ = std::make_unique<int>(default_rows * padded_item_height());
|
||||
}
|
||||
|
||||
std::optional<uiViewState> AbstractTreeView::persistent_state() const
|
||||
{
|
||||
if (!custom_height_) {
|
||||
return {};
|
||||
}
|
||||
|
||||
uiViewState state{0};
|
||||
|
||||
if (custom_height_) {
|
||||
state.custom_height = *custom_height_ * UI_INV_SCALE_FAC;
|
||||
}
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
void AbstractTreeView::persistent_state_apply(const uiViewState &state)
|
||||
{
|
||||
if (state.custom_height) {
|
||||
set_default_rows(round_fl_to_int(state.custom_height * UI_SCALE_FAC) / padded_item_height());
|
||||
}
|
||||
}
|
||||
|
||||
int AbstractTreeView::count_visible_descendants(const AbstractTreeViewItem &parent) const
|
||||
{
|
||||
if (parent.is_collapsed()) {
|
||||
@@ -915,13 +937,19 @@ void TreeViewBuilder::ensure_min_rows_items(AbstractTreeView &tree_view)
|
||||
}
|
||||
}
|
||||
|
||||
void TreeViewBuilder::build_tree_view(AbstractTreeView &tree_view,
|
||||
void TreeViewBuilder::build_tree_view(const bContext &C,
|
||||
AbstractTreeView &tree_view,
|
||||
uiLayout &layout,
|
||||
std::optional<StringRef> search_string,
|
||||
const bool add_box)
|
||||
{
|
||||
uiBlock &block = *uiLayoutGetBlock(&layout);
|
||||
|
||||
const ARegion *region = CTX_wm_region_popup(&C) ? CTX_wm_region_popup(&C) : CTX_wm_region(&C);
|
||||
if (region) {
|
||||
ui_block_view_persistent_state_restore(*region, block, tree_view);
|
||||
}
|
||||
|
||||
tree_view.build_tree();
|
||||
tree_view.update_from_old(block);
|
||||
tree_view.change_state_delayed();
|
||||
|
||||
@@ -754,7 +754,8 @@ bool file_is_asset_visible_in_catalog_filter_settings(
|
||||
|
||||
/* ---------------------------------------------------------------------- */
|
||||
|
||||
void file_create_asset_catalog_tree_view_in_layout(asset_system::AssetLibrary *asset_library,
|
||||
void file_create_asset_catalog_tree_view_in_layout(const bContext *C,
|
||||
asset_system::AssetLibrary *asset_library,
|
||||
uiLayout *layout,
|
||||
SpaceFile *space_file,
|
||||
FileAssetSelectParams *params)
|
||||
@@ -769,7 +770,7 @@ void file_create_asset_catalog_tree_view_in_layout(asset_system::AssetLibrary *a
|
||||
std::make_unique<ed::asset_browser::AssetCatalogTreeView>(
|
||||
asset_library, params, *space_file));
|
||||
tree_view->set_context_menu_title("Catalog");
|
||||
ui::TreeViewBuilder::build_tree_view(*tree_view, *layout);
|
||||
ui::TreeViewBuilder::build_tree_view(*C, *tree_view, *layout);
|
||||
}
|
||||
|
||||
} // namespace blender::ed::asset_browser
|
||||
|
||||
@@ -232,7 +232,8 @@ void file_path_to_ui_path(const char *path, char *r_path, int r_path_maxncpy);
|
||||
|
||||
namespace blender::ed::asset_browser {
|
||||
|
||||
void file_create_asset_catalog_tree_view_in_layout(asset_system::AssetLibrary *asset_library,
|
||||
void file_create_asset_catalog_tree_view_in_layout(const bContext *C,
|
||||
asset_system::AssetLibrary *asset_library,
|
||||
uiLayout *layout,
|
||||
SpaceFile *space_file,
|
||||
FileAssetSelectParams *params);
|
||||
|
||||
@@ -255,7 +255,7 @@ static void file_panel_asset_catalog_buttons_draw(const bContext *C, Panel *pane
|
||||
uiItemS(col);
|
||||
|
||||
blender::ed::asset_browser::file_create_asset_catalog_tree_view_in_layout(
|
||||
asset_library, col, sfile, params);
|
||||
C, asset_library, col, sfile, params);
|
||||
}
|
||||
|
||||
void file_tools_region_panels_register(ARegionType *art)
|
||||
|
||||
@@ -728,7 +728,7 @@ void spreadsheet_data_set_panel_draw(const bContext *C, Panel *panel)
|
||||
"Instances Tree View",
|
||||
std::make_unique<GeometryInstancesTreeView>(root_geometry, *C));
|
||||
tree_view->set_context_menu_title("Instance");
|
||||
ui::TreeViewBuilder::build_tree_view(*tree_view, *panel, {}, false);
|
||||
ui::TreeViewBuilder::build_tree_view(*C, *tree_view, *panel, {}, false);
|
||||
}
|
||||
if (uiLayout *panel = uiLayoutPanel(
|
||||
C, layout, "geometry_domain_tree_view", false, IFACE_("Domain")))
|
||||
@@ -740,7 +740,7 @@ void spreadsheet_data_set_panel_draw(const bContext *C, Panel *panel)
|
||||
"Data Set Tree View",
|
||||
std::make_unique<GeometryDataSetTreeView>(std::move(instance_geometry), *C));
|
||||
tree_view->set_context_menu_title("Domain");
|
||||
ui::TreeViewBuilder::build_tree_view(*tree_view, *panel, {}, false);
|
||||
ui::TreeViewBuilder::build_tree_view(*C, *tree_view, *panel, {}, false);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -322,6 +322,31 @@ typedef struct uiList { /* some list UI data need to be saved in file */
|
||||
uiListDyn *dyn_data;
|
||||
} uiList;
|
||||
|
||||
/** See #uiViewStateLink. */
|
||||
typedef struct uiViewState {
|
||||
/**
|
||||
* User set height of the view in unscaled pixels. A value of 0 means no custom height was set
|
||||
* and the default should be used.
|
||||
*/
|
||||
int custom_height;
|
||||
char _pad[4];
|
||||
} uiViewState;
|
||||
|
||||
/**
|
||||
* Persistent storage for some state of views (#ui::AbstractView), for storage in a region. The
|
||||
* view state is matched to the view using the view's idname.
|
||||
*
|
||||
* The actual state is stored in #uiViewState, so views can manage this conveniently without having
|
||||
* to care about the idname and listbase pointers themselves.
|
||||
*/
|
||||
typedef struct uiViewStateLink {
|
||||
struct uiViewStateLink *next, *prev;
|
||||
|
||||
char idname[64]; /* #BKE_ST_MAXNAME */
|
||||
|
||||
uiViewState state;
|
||||
} uiViewStateLink;
|
||||
|
||||
typedef struct TransformOrientation {
|
||||
struct TransformOrientation *next, *prev;
|
||||
/** MAX_NAME. */
|
||||
@@ -512,6 +537,11 @@ typedef struct ARegion {
|
||||
ListBase handlers;
|
||||
/** Panel categories runtime. */
|
||||
ListBase panels_category;
|
||||
/**
|
||||
* Permanent state storage of #ui::AbstractView instances, so hiding regions with views or
|
||||
* loading files remembers the view state.
|
||||
*/
|
||||
ListBase view_states; /* #uiViewStateLink */
|
||||
|
||||
/** Gizmo-map of this region. */
|
||||
struct wmGizmoMap *gizmo_map;
|
||||
|
||||
@@ -2387,6 +2387,7 @@ void RNA_api_ui_layout(StructRNA *srna)
|
||||
srna, "template_light_linking_collection", "uiTemplateLightLinkingCollection");
|
||||
RNA_def_function_ui_description(func,
|
||||
"Visualization of a content of a light linking collection");
|
||||
RNA_def_function_flag(func, FUNC_USE_CONTEXT);
|
||||
parm = RNA_def_pointer(func,
|
||||
"context_layout",
|
||||
"UILayout",
|
||||
@@ -2406,6 +2407,7 @@ void RNA_api_ui_layout(StructRNA *srna)
|
||||
|
||||
func = RNA_def_function(srna, "template_node_tree_interface", "uiTemplateNodeTreeInterface");
|
||||
RNA_def_function_ui_description(func, "Show a node tree interface");
|
||||
RNA_def_function_flag(func, FUNC_USE_CONTEXT);
|
||||
parm = RNA_def_pointer(func,
|
||||
"interface",
|
||||
"NodeTreeInterface",
|
||||
|
||||
Reference in New Issue
Block a user