diff --git a/source/blender/blenkernel/intern/screen.cc b/source/blender/blenkernel/intern/screen.cc index 034258bcc64..f2f35d2849a 100644 --- a/source/blender/blenkernel/intern/screen.cc +++ b/source/blender/blenkernel/intern/screen.cc @@ -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). */ diff --git a/source/blender/editors/asset/intern/asset_shelf.cc b/source/blender/editors/asset/intern/asset_shelf.cc index dba4fff5228..02169299cc4 100644 --- a/source/blender/editors/asset/intern/asset_shelf.cc +++ b/source/blender/editors/asset/intern/asset_shelf.cc @@ -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); diff --git a/source/blender/editors/asset/intern/asset_shelf.hh b/source/blender/editors/asset/intern/asset_shelf.hh index 402d6bdd517..9f1fde86495 100644 --- a/source/blender/editors/asset/intern/asset_shelf.hh +++ b/source/blender/editors/asset/intern/asset_shelf.hh @@ -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); diff --git a/source/blender/editors/asset/intern/asset_shelf_asset_view.cc b/source/blender/editors/asset/intern/asset_shelf_asset_view.cc index f91410bef67..1454c6adf58 100644 --- a/source/blender/editors/asset/intern/asset_shelf_asset_view.cc +++ b/source/blender/editors/asset/intern/asset_shelf_asset_view.cc @@ -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)); } /* ---------------------------------------------------------------------- */ diff --git a/source/blender/editors/asset/intern/asset_shelf_catalog_selector.cc b/source/blender/editors/asset/intern/asset_shelf_catalog_selector.cc index 07083d6ff7b..e986c722e51 100644 --- a/source/blender/editors/asset/intern/asset_shelf_catalog_selector.cc +++ b/source/blender/editors/asset/intern/asset_shelf_catalog_selector.cc @@ -215,7 +215,7 @@ static void catalog_selector_panel_draw(const bContext *C, Panel *panel) "asset catalog tree view", std::make_unique(*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) diff --git a/source/blender/editors/asset/intern/asset_shelf_popover.cc b/source/blender/editors/asset/intern/asset_shelf_popover.cc index 32a47950ff0..f85363024f3 100644 --- a/source/blender/editors/asset/intern/asset_shelf_popover.cc +++ b/source/blender/editors/asset/intern/asset_shelf_popover.cc @@ -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(*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*/) diff --git a/source/blender/editors/include/UI_abstract_view.hh b/source/blender/editors/include/UI_abstract_view.hh index 4b667e75166..c838b85ad6f 100644 --- a/source/blender/editors/include/UI_abstract_view.hh +++ b/source/blender/editors/include/UI_abstract_view.hh @@ -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 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. diff --git a/source/blender/editors/include/UI_grid_view.hh b/source/blender/editors/include/UI_grid_view.hh index 9112146f443..d0491480f56 100644 --- a/source/blender/editors/include/UI_grid_view.hh +++ b/source/blender/editors/include/UI_grid_view.hh @@ -172,7 +172,6 @@ class GridViewBuilder { void build_grid_view(const bContext &C, AbstractGridView &grid_view, - const View2D &v2d, uiLayout &layout, std::optional search_string = {}); }; diff --git a/source/blender/editors/include/UI_interface.hh b/source/blender/editors/include/UI_interface.hh index 9815f383c3b..728d832ebc0 100644 --- a/source/blender/editors/include/UI_interface.hh +++ b/source/blender/editors/include/UI_interface.hh @@ -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, diff --git a/source/blender/editors/include/UI_interface_c.hh b/source/blender/editors/include/UI_interface_c.hh index 95fac0d3ffd..ee3b1941b6e 100644 --- a/source/blender/editors/include/UI_interface_c.hh +++ b/source/blender/editors/include/UI_interface_c.hh @@ -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. */ diff --git a/source/blender/editors/include/UI_tree_view.hh b/source/blender/editors/include/UI_tree_view.hh index 1f6687b2af4..bcd245ca2db 100644 --- a/source/blender/editors/include/UI_tree_view.hh +++ b/source/blender/editors/include/UI_tree_view.hh @@ -146,6 +146,9 @@ class AbstractTreeView : public AbstractView, public TreeViewItemContainer { protected: virtual void build_tree() = 0; + std::optional persistent_state() const override; + void persistent_state_apply(const uiViewState &state) override; + private: void foreach_view_item(FunctionRef 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 search_string = {}, bool add_box = true); diff --git a/source/blender/editors/interface/interface.cc b/source/blender/editors/interface/interface.cc index bea4c78afee..e625539cc26 100644 --- a/source/blender/editors/interface/interface.cc +++ b/source/blender/editors/interface/interface.cc @@ -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) { diff --git a/source/blender/editors/interface/interface_intern.hh b/source/blender/editors/interface/interface_intern.hh index 97104f9233f..05898e36ac3 100644 --- a/source/blender/editors/interface/interface_intern.hh +++ b/source/blender/editors/interface/interface_intern.hh @@ -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( diff --git a/source/blender/editors/interface/interface_panel.cc b/source/blender/editors/interface/interface_panel.cc index 4d264c5a778..a8a9ace88aa 100644 --- a/source/blender/editors/interface/interface_panel.cc +++ b/source/blender/editors/interface/interface_panel.cc @@ -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); } } diff --git a/source/blender/editors/interface/templates/interface_template_bone_collection_tree.cc b/source/blender/editors/interface/templates/interface_template_bone_collection_tree.cc index b617db70fe7..2aeade96d11 100644 --- a/source/blender/editors/interface/templates/interface_template_bone_collection_tree.cc +++ b/source/blender/editors/interface/templates/interface_template_bone_collection_tree.cc @@ -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); } diff --git a/source/blender/editors/interface/templates/interface_template_grease_pencil_layer_tree.cc b/source/blender/editors/interface/templates/interface_template_grease_pencil_layer_tree.cc index 672d7861da5..dae2d3ed615 100644 --- a/source/blender/editors/interface/templates/interface_template_grease_pencil_layer_tree.cc +++ b/source/blender/editors/interface/templates/interface_template_grease_pencil_layer_tree.cc @@ -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); } diff --git a/source/blender/editors/interface/templates/interface_template_light_linking.cc b/source/blender/editors/interface/templates/interface_template_light_linking.cc index c88e49d54d3..bb2237c1f5b 100644 --- a/source/blender/editors/interface/templates/interface_template_light_linking.cc +++ b/source/blender/editors/interface/templates/interface_template_light_linking.cc @@ -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); } diff --git a/source/blender/editors/interface/templates/interface_template_node_tree_interface.cc b/source/blender/editors/interface/templates/interface_template_node_tree_interface.cc index 474641fb0f5..f33eeb069d7 100644 --- a/source/blender/editors/interface/templates/interface_template_node_tree_interface.cc +++ b/source/blender/editors/interface/templates/interface_template_node_tree_interface.cc @@ -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); } diff --git a/source/blender/editors/interface/views/abstract_view.cc b/source/blender/editors/interface/views/abstract_view.cc index c75b47e00fb..1f840e549bc 100644 --- a/source/blender/editors/interface/views/abstract_view.cc +++ b/source/blender/editors/interface/views/abstract_view.cc @@ -136,6 +136,13 @@ void AbstractView::scroll(ViewScrollDirection /*direction*/) BLI_assert_msg(false, "Unsupported for this view type"); } +std::optional AbstractView::persistent_state() const +{ + return {}; +} + +void AbstractView::persistent_state_apply(const uiViewState & /*state*/) {} + /** \} */ /* ---------------------------------------------------------------------- */ diff --git a/source/blender/editors/interface/views/grid_view.cc b/source/blender/editors/interface/views/grid_view.cc index 60aee315ddd..c91b4573238 100644 --- a/source/blender/editors/interface/views/grid_view.cc +++ b/source/blender/editors/interface/views/grid_view.cc @@ -12,6 +12,7 @@ #include #include +#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 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); } /* ---------------------------------------------------------------------- */ diff --git a/source/blender/editors/interface/views/interface_view.cc b/source/blender/editors/interface/views/interface_view.cc index 097a2198388..154f636d9f7 100644 --- a/source/blender/editors/interface/views/interface_view.cc +++ b/source/blender/editors/interface/views/interface_view.cc @@ -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 view) { + BLI_assert(idname.size() < int64_t(sizeof(uiViewStateLink::idname))); + ViewLink *view_link = MEM_new(__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(__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 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) diff --git a/source/blender/editors/interface/views/tree_view.cc b/source/blender/editors/interface/views/tree_view.cc index a4515d6e793..b00fcd5ea72 100644 --- a/source/blender/editors/interface/views/tree_view.cc +++ b/source/blender/editors/interface/views/tree_view.cc @@ -131,6 +131,28 @@ void AbstractTreeView::set_default_rows(int default_rows) custom_height_ = std::make_unique(default_rows * padded_item_height()); } +std::optional 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 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(); diff --git a/source/blender/editors/space_file/asset_catalog_tree_view.cc b/source/blender/editors/space_file/asset_catalog_tree_view.cc index fb8aae558ca..9ceb4e4f8bb 100644 --- a/source/blender/editors/space_file/asset_catalog_tree_view.cc +++ b/source/blender/editors/space_file/asset_catalog_tree_view.cc @@ -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( 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 diff --git a/source/blender/editors/space_file/file_intern.hh b/source/blender/editors/space_file/file_intern.hh index f2817661a8f..7d5689d5ca5 100644 --- a/source/blender/editors/space_file/file_intern.hh +++ b/source/blender/editors/space_file/file_intern.hh @@ -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); diff --git a/source/blender/editors/space_file/file_panels.cc b/source/blender/editors/space_file/file_panels.cc index 1d88c5682d2..dfafc8b2fcb 100644 --- a/source/blender/editors/space_file/file_panels.cc +++ b/source/blender/editors/space_file/file_panels.cc @@ -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) diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_dataset_draw.cc b/source/blender/editors/space_spreadsheet/spreadsheet_dataset_draw.cc index 3fc0d13980e..2769d0a8d7f 100644 --- a/source/blender/editors/space_spreadsheet/spreadsheet_dataset_draw.cc +++ b/source/blender/editors/space_spreadsheet/spreadsheet_dataset_draw.cc @@ -728,7 +728,7 @@ void spreadsheet_data_set_panel_draw(const bContext *C, Panel *panel) "Instances Tree View", std::make_unique(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(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); } } diff --git a/source/blender/makesdna/DNA_screen_types.h b/source/blender/makesdna/DNA_screen_types.h index 9e52afc309b..3eeb8680030 100644 --- a/source/blender/makesdna/DNA_screen_types.h +++ b/source/blender/makesdna/DNA_screen_types.h @@ -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; diff --git a/source/blender/makesrna/intern/rna_ui_api.cc b/source/blender/makesrna/intern/rna_ui_api.cc index 9112df2afea..f10ce10338d 100644 --- a/source/blender/makesrna/intern/rna_ui_api.cc +++ b/source/blender/makesrna/intern/rna_ui_api.cc @@ -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",