Blender V4.5
asset_shelf_popover.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2024 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
8
9#include "AS_asset_library.hh"
10
11#include "asset_shelf.hh"
12
13#include "BKE_screen.hh"
14
15#include "BLI_listbase.h"
16#include "BLI_string.h"
17
18#include "BLT_translation.hh"
19
20#include "UI_interface_c.hh"
21#include "UI_tree_view.hh"
22
23#include "ED_asset_filter.hh"
24#include "ED_asset_list.hh"
25#include "ED_asset_shelf.hh"
26
27#include "RNA_access.hh"
28#include "RNA_prototypes.hh"
29
30#include "WM_api.hh"
31
33
35 public:
37
39 {
41 MEM_delete(shelf);
42 }
43 }
44
46 {
47 static StaticPopupShelves storage;
48 return storage.popup_shelves;
49 }
50};
51
52void type_popup_unlink(const AssetShelfType &shelf_type)
53{
55 if (shelf->type == &shelf_type) {
56 shelf->type = nullptr;
57 }
58 }
59}
60
61static AssetShelf *lookup_shelf_for_popup(const bContext &C, const AssetShelfType &shelf_type)
62{
64
65 for (AssetShelf *shelf : popup_shelves) {
66 if (STREQ(shelf->idname, shelf_type.idname)) {
68 return shelf;
69 }
70 break;
71 }
72 }
73
74 return nullptr;
75}
76
78{
80
81 if (AssetShelf *shelf = lookup_shelf_for_popup(C, shelf_type)) {
82 return shelf;
83 }
84
85 if (type_poll_for_popup(C, &shelf_type)) {
86 AssetShelf *new_shelf = create_shelf_from_type(shelf_type);
88 /* Increased size of previews, to leave more space for the name. */
90 popup_shelves.append(new_shelf);
91 return new_shelf;
92 }
93
94 return nullptr;
95}
96
98{
99 if (AssetShelf *shelf = lookup_shelf_for_popup(C, shelf_type)) {
100 list::storage_fetch(&shelf->settings.asset_library_reference, &C);
101 }
102 else {
104 list::storage_fetch(&library_ref, &C);
105 }
106}
107
109 AssetShelf &shelf_;
110 asset_system::AssetCatalogTree catalog_tree_;
111
112 public:
114 : shelf_(shelf)
115 {
116 catalog_tree_ = build_filtered_catalog_tree(
117 library,
118 shelf_.settings.asset_library_reference,
120 return (!shelf_.type->asset_poll || shelf_.type->asset_poll(shelf_.type, &asset));
121 });
122
123 /* Keep the popup open when clicking to activate a catalog. */
124 this->set_popup_keep_open();
125 }
126
127 void build_tree() override
128 {
129 if (catalog_tree_.is_empty()) {
130 auto &item = this->add_tree_item<ui::BasicTreeViewItem>(RPT_("No applicable assets found"),
131 ICON_INFO);
132 item.disable_interaction();
133 return;
134 }
135
136 auto &all_item = this->add_tree_item<ui::BasicTreeViewItem>(IFACE_("All"));
137 all_item.set_on_activate_fn([this](bContext &C, ui::BasicTreeViewItem &) {
138 settings_set_all_catalog_active(shelf_.settings);
140 });
141 all_item.set_is_active_fn(
142 [this]() { return settings_is_all_catalog_active(shelf_.settings); });
143 all_item.uncollapse_by_default();
144
145 catalog_tree_.foreach_root_item([&, this](
146 const asset_system::AssetCatalogTreeItem &catalog_item) {
147 ui::BasicTreeViewItem &item = this->build_catalog_items_recursive(all_item, catalog_item);
149 });
150 }
151
153 ui::TreeViewOrItem &parent_view_item,
154 const asset_system::AssetCatalogTreeItem &catalog_item) const
155 {
156 ui::BasicTreeViewItem &view_item = parent_view_item.add_tree_item<ui::BasicTreeViewItem>(
157 catalog_item.get_name());
158
159 std::string catalog_path = catalog_item.catalog_path().str();
160 view_item.set_on_activate_fn([this, catalog_path](bContext &C, ui::BasicTreeViewItem &) {
161 settings_set_active_catalog(shelf_.settings, catalog_path);
163 });
164 view_item.set_is_active_fn([this, catalog_path]() {
165 return settings_is_active_catalog(shelf_.settings, catalog_path);
166 });
167
168 const int parent_count = view_item.count_parents() + 1;
169
170 catalog_item.foreach_child([&, this](const asset_system::AssetCatalogTreeItem &child) {
171 ui::BasicTreeViewItem &child_item = build_catalog_items_recursive(view_item, child);
172
173 /* Uncollapse to some level (gives quick access, but don't let the tree get too big). */
174 if (parent_count < 3) {
175 child_item.uncollapse_by_default();
176 }
177 });
178
179 return view_item;
180 }
181};
182
183static void catalog_tree_draw(const bContext &C, uiLayout &layout, AssetShelf &shelf)
184{
186 shelf.settings.asset_library_reference);
187 if (!library) {
188 return;
189 }
190
191 uiBlock *block = uiLayoutGetBlock(&layout);
193 *block,
194 "asset shelf catalog tree view",
195 std::make_unique<AssetCatalogTreeView>(*library, shelf));
196
197 ui::TreeViewBuilder::build_tree_view(C, *tree_view, layout);
198}
199
201{
202 const std::optional<StringRefNull> idname = CTX_data_string_get(C, "asset_shelf_idname");
203 if (!idname) {
204 return nullptr;
205 }
206 return type_find_from_idname(*idname);
207}
208
209constexpr int LEFT_COL_WIDTH_UNITS = 10;
211
217{
218 const int max_units_x = (WM_window_native_pixel_x(win) / UI_UNIT_X) - 2;
219 return std::min(LEFT_COL_WIDTH_UNITS + RIGHT_COL_WIDTH_UNITS_DEFAULT, max_units_x);
220}
221
222static void popover_panel_draw(const bContext *C, Panel *panel)
223{
224 const wmWindow *win = CTX_wm_window(C);
225 const int layout_width_units = layout_width_units_clamped(win);
227 BLI_assert_msg(shelf_type != nullptr, "couldn't find asset shelf type from context");
228
229 uiLayout *layout = panel->layout;
230 uiLayoutSetUnitsX(layout, layout_width_units);
231
232 AssetShelf *shelf = get_shelf_for_popup(*C, *shelf_type);
233 if (!shelf) {
235 return;
236 }
237
238 bScreen *screen = CTX_wm_screen(C);
239 PointerRNA library_ref_ptr = RNA_pointer_create_discrete(
240 &screen->id, &RNA_AssetLibraryReference, &shelf->settings.asset_library_reference);
241 uiLayoutSetContextPointer(layout, "asset_library_reference", &library_ref_ptr);
242
243 uiLayout *row = &layout->row(false);
244 uiLayout *catalogs_col = &row->column(false);
246 uiLayoutSetFixedSize(catalogs_col, true);
247 library_selector_draw(C, catalogs_col, *shelf);
248 catalog_tree_draw(*C, *catalogs_col, *shelf);
249
250 uiLayout *right_col = &row->column(false);
251 uiLayout *sub = &right_col->row(false);
252 /* Same as file/asset browser header. */
253 PointerRNA shelf_ptr = RNA_pointer_create_discrete(&screen->id, &RNA_AssetShelf, shelf);
254 sub->prop(&shelf_ptr,
255 "search_filter",
256 /* Force the button to be active in a semi-modal state. */
258 "",
259 ICON_VIEWZOOM);
260
261 uiLayout *asset_view_col = &right_col->column(false);
262 BLI_assert((layout_width_units - LEFT_COL_WIDTH_UNITS) > 0);
263 uiLayoutSetUnitsX(asset_view_col, layout_width_units - LEFT_COL_WIDTH_UNITS);
264 uiLayoutSetFixedSize(asset_view_col, true);
265
266 build_asset_view(*asset_view_col, shelf->settings.asset_library_reference, *shelf, *C);
267}
268
269static bool popover_panel_poll(const bContext *C, PanelType * /*panel_type*/)
270{
272 if (!shelf_type) {
273 return false;
274 }
275
276 return type_poll_for_popup(*C, shelf_type);
277}
278
280{
281 /* Uses global paneltype registry to allow usage as popover. So only register this once (may be
282 * called from multiple spaces). */
283 if (WM_paneltype_find("ASSETSHELF_PT_popover_panel", true)) {
284 return;
285 }
286
287 PanelType *pt = MEM_callocN<PanelType>(__func__);
288 STRNCPY(pt->idname, "ASSETSHELF_PT_popover_panel");
289 STRNCPY(pt->label, N_("Asset Shelf Panel"));
291 pt->description = N_("Display an asset shelf in a popover panel");
295 /* Move to have first asset item under cursor. */
296 pt->offset_units_xy.x = -(LEFT_COL_WIDTH_UNITS + 1.5f);
297 /* Offset so mouse is below search button, over the first row of assets. */
298 pt->offset_units_xy.y = 2.5f;
299 BLI_addtail(&region_type->paneltypes, pt);
301}
302
303} // namespace blender::ed::asset::shelf
bScreen * CTX_wm_screen(const bContext *C)
wmWindow * CTX_wm_window(const bContext *C)
std::optional< blender::StringRefNull > CTX_data_string_get(const bContext *C, const char *member)
#define ASSET_SHELF_PREVIEW_SIZE_DEFAULT
#define BLI_assert_unreachable()
Definition BLI_assert.h:93
#define BLI_assert(a)
Definition BLI_assert.h:46
#define BLI_assert_msg(a, msg)
Definition BLI_assert.h:53
void BLI_addtail(ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:111
char * STRNCPY(char(&dst)[N], const char *src)
Definition BLI_string.h:688
#define STREQ(a, b)
#define RPT_(msgid)
#define IFACE_(msgid)
#define BLT_I18NCONTEXT_DEFAULT_BPYRNA
@ ASSETSHELF_SHOW_NAMES
#define C
Definition RandGen.cpp:29
blender::ui::AbstractGridView * UI_block_add_view(uiBlock &block, blender::StringRef idname, std::unique_ptr< blender::ui::AbstractGridView > grid_view)
#define UI_UNIT_X
void uiLayoutSetContextPointer(uiLayout *layout, blender::StringRef name, PointerRNA *ptr)
@ UI_ITEM_R_TEXT_BUT_FORCE_SEMI_MODAL_ACTIVE
void uiLayoutSetFixedSize(uiLayout *layout, bool fixed_size)
uiBlock * uiLayoutGetBlock(uiLayout *layout)
void uiLayoutSetUnitsX(uiLayout *layout, float unit)
void append(const T &value)
void foreach_child(ItemIterFn callback) const
AssetCatalogTreeView(const asset_system::AssetLibrary &library, AssetShelf &shelf)
ui::BasicTreeViewItem & build_catalog_items_recursive(ui::TreeViewOrItem &parent_view_item, const asset_system::AssetCatalogTreeItem &catalog_item) const
void set_is_active_fn(IsActiveFn is_active_fn)
void set_on_activate_fn(ActivateFn fn)
static void build_tree_view(const bContext &C, AbstractTreeView &tree_view, uiLayout &layout, std::optional< StringRef > search_string={}, bool add_box=true)
Definition tree_view.cc:980
ItemT & add_tree_item(Args &&...args)
void * MEM_callocN(size_t len, const char *str)
Definition mallocn.cc:118
AssetLibraryReference all_library_reference()
void storage_fetch(const AssetLibraryReference *library_reference, const bContext *C)
asset_system::AssetLibrary * library_get_once_available(const AssetLibraryReference &library_reference)
void asset_reading_region_listen_fn(const wmRegionListenerParams *params)
static void popover_panel_draw(const bContext *C, Panel *panel)
static AssetShelf * get_shelf_for_popup(const bContext &C, AssetShelfType &shelf_type)
AssetShelfType * type_find_from_idname(StringRef idname)
static AssetShelfType * lookup_type_from_idname_in_context(const bContext *C)
bool settings_is_all_catalog_active(const AssetShelfSettings &settings)
AssetShelf * create_shelf_from_type(AssetShelfType &type)
void type_popup_unlink(const AssetShelfType &shelf_type)
void popover_panel_register(ARegionType *region_type)
void library_selector_draw(const bContext *C, uiLayout *layout, AssetShelf &shelf)
static int layout_width_units_clamped(const wmWindow *win)
void settings_set_all_catalog_active(AssetShelfSettings &settings)
static bool popover_panel_poll(const bContext *C, PanelType *)
static AssetShelf * lookup_shelf_for_popup(const bContext &C, const AssetShelfType &shelf_type)
AssetShelfType * ensure_shelf_has_type(AssetShelf &shelf)
bool settings_is_active_catalog(const AssetShelfSettings &settings, const asset_system::AssetCatalogPath &path)
void send_redraw_notifier(const bContext &C)
bool type_poll_for_popup(const bContext &C, const AssetShelfType *shelf_type)
void ensure_asset_library_fetched(const bContext &C, const AssetShelfType &shelf_type)
void settings_set_active_catalog(AssetShelfSettings &settings, const asset_system::AssetCatalogPath &path)
void build_asset_view(uiLayout &layout, const AssetLibraryReference &library_ref, const AssetShelf &shelf, const bContext &C)
static void catalog_tree_draw(const bContext &C, uiLayout &layout, AssetShelf &shelf)
asset_system::AssetCatalogTree build_filtered_catalog_tree(const asset_system::AssetLibrary &library, const AssetLibraryReference &library_ref, blender::FunctionRef< bool(const asset_system::AssetRepresentation &)> is_asset_visible_fn)
TreeViewItemContainer TreeViewOrItem
PointerRNA RNA_pointer_create_discrete(ID *id, StructRNA *type, void *data)
ListBase paneltypes
char idname[BKE_ST_MAXNAME]
AssetShelfSettings settings
void(* draw)(const bContext *C, Panel *panel)
char idname[BKE_ST_MAXNAME]
bool(* poll)(const bContext *C, PanelType *pt)
void(* listener)(const wmRegionListenerParams *params)
char translation_context[BKE_ST_MAXNAME]
blender::float2 offset_units_xy
char label[BKE_ST_MAXNAME]
const char * description
struct uiLayout * layout
uiLayout & column(bool align)
uiLayout & row(bool align)
void prop(PointerRNA *ptr, PropertyRNA *prop, int index, int value, eUI_Item_Flag flag, std::optional< blender::StringRef > name_opt, int icon, std::optional< blender::StringRef > placeholder=std::nullopt)
#define N_(msgid)
bool WM_paneltype_add(PanelType *pt)
PanelType * WM_paneltype_find(const StringRef idname, bool quiet)
int WM_window_native_pixel_x(const wmWindow *win)