Blender V5.0
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_utf8.h"
17
18#include "BLT_translation.hh"
19
20#include "UI_interface_c.hh"
22#include "UI_tree_view.hh"
23
24#include "ED_asset_filter.hh"
25#include "ED_asset_list.hh"
26#include "ED_asset_shelf.hh"
27
28#include "RNA_access.hh"
29#include "RNA_prototypes.hh"
30
31#include "WM_api.hh"
32
34
36 public:
38
40 {
42 MEM_delete(shelf);
43 }
44 }
45
47 {
48 static StaticPopupShelves storage;
49 return storage.popup_shelves;
50 }
51};
52
53void type_popup_unlink(const AssetShelfType &shelf_type)
54{
56 if (shelf->type == &shelf_type) {
57 shelf->type = nullptr;
58 }
59 }
60}
61
62static AssetShelf *lookup_shelf_for_popup(const bContext &C, const AssetShelfType &shelf_type)
63{
65
66 for (AssetShelf *shelf : popup_shelves) {
67 if (STREQ(shelf->idname, shelf_type.idname)) {
69 return shelf;
70 }
71 break;
72 }
73 }
74
75 return nullptr;
76}
77
79{
81
82 if (AssetShelf *shelf = lookup_shelf_for_popup(C, shelf_type)) {
83 return shelf;
84 }
85
86 if (type_poll_for_popup(C, &shelf_type)) {
87 AssetShelf *new_shelf = create_shelf_from_type(shelf_type);
89 /* Increased size of previews, to leave more space for the name. */
91 popup_shelves.append(new_shelf);
92 return new_shelf;
93 }
94
95 return nullptr;
96}
97
99{
100 if (AssetShelf *shelf = lookup_shelf_for_popup(C, shelf_type)) {
101 list::storage_fetch(&shelf->settings.asset_library_reference, &C);
102 }
103 else {
105 list::storage_fetch(&library_ref, &C);
106 }
107}
108
110 AssetShelf &shelf_;
111 asset_system::AssetCatalogTree catalog_tree_;
112
113 public:
115 : shelf_(shelf)
116 {
117 catalog_tree_ = build_filtered_catalog_tree(
118 library,
119 shelf_.settings.asset_library_reference,
121 return (!shelf_.type->asset_poll || shelf_.type->asset_poll(shelf_.type, &asset));
122 });
123
124 /* Keep the popup open when clicking to activate a catalog. */
125 this->set_popup_keep_open();
126 }
127
128 void build_tree() override
129 {
130 if (catalog_tree_.is_empty()) {
131 auto &item = this->add_tree_item<ui::BasicTreeViewItem>(RPT_("No applicable assets found"),
132 ICON_INFO);
133 item.disable_interaction();
134 return;
135 }
136
137 auto &all_item = this->add_tree_item<ui::BasicTreeViewItem>(IFACE_("All"));
138 all_item.set_on_activate_fn([this](bContext &C, ui::BasicTreeViewItem &) {
139 settings_set_all_catalog_active(shelf_.settings);
141 });
142 all_item.set_is_active_fn(
143 [this]() { return settings_is_all_catalog_active(shelf_.settings); });
144 all_item.uncollapse_by_default();
145
146 catalog_tree_.foreach_root_item([&, this](
147 const asset_system::AssetCatalogTreeItem &catalog_item) {
148 ui::BasicTreeViewItem &item = this->build_catalog_items_recursive(all_item, catalog_item);
150 });
151 }
152
154 ui::TreeViewOrItem &parent_view_item,
155 const asset_system::AssetCatalogTreeItem &catalog_item) const
156 {
157 ui::BasicTreeViewItem &view_item = parent_view_item.add_tree_item<ui::BasicTreeViewItem>(
158 catalog_item.get_name());
159
160 std::string catalog_path = catalog_item.catalog_path().str();
161 view_item.set_on_activate_fn([this, catalog_path](bContext &C, ui::BasicTreeViewItem &) {
162 settings_set_active_catalog(shelf_.settings, catalog_path);
164 });
165 view_item.set_is_active_fn([this, catalog_path]() {
166 return settings_is_active_catalog(shelf_.settings, catalog_path);
167 });
168
169 const int parent_count = view_item.count_parents() + 1;
170
171 catalog_item.foreach_child([&, this](const asset_system::AssetCatalogTreeItem &child) {
172 ui::BasicTreeViewItem &child_item = build_catalog_items_recursive(view_item, child);
173
174 /* Uncollapse to some level (gives quick access, but don't let the tree get too big). */
175 if (parent_count < 3) {
176 child_item.uncollapse_by_default();
177 }
178 });
179
180 return view_item;
181 }
182};
183
184static void catalog_tree_draw(const bContext &C, uiLayout &layout, AssetShelf &shelf)
185{
187 shelf.settings.asset_library_reference);
188 if (!library) {
189 return;
190 }
191
192 uiBlock *block = layout.block();
194 *block,
195 "asset shelf catalog tree view",
196 std::make_unique<AssetCatalogTreeView>(*library, shelf));
197
198 ui::TreeViewBuilder::build_tree_view(C, *tree_view, layout);
199}
200
202{
203 const std::optional<StringRefNull> idname = CTX_data_string_get(C, "asset_shelf_idname");
204 if (!idname) {
205 return nullptr;
206 }
207 return type_find_from_idname(*idname);
208}
209
210constexpr int LEFT_COL_WIDTH_UNITS = 10;
212
218{
219 const int max_units_x = (WM_window_native_pixel_x(win) / UI_UNIT_X) - 2;
220 return std::min(LEFT_COL_WIDTH_UNITS + RIGHT_COL_WIDTH_UNITS_DEFAULT, max_units_x);
221}
222
223static void popover_panel_draw(const bContext *C, Panel *panel)
224{
225 const wmWindow *win = CTX_wm_window(C);
226 const int layout_width_units = layout_width_units_clamped(win);
228 BLI_assert_msg(shelf_type != nullptr, "couldn't find asset shelf type from context");
229
230 uiLayout *layout = panel->layout;
231 layout->ui_units_x_set(layout_width_units);
232
233 AssetShelf *shelf = get_shelf_for_popup(*C, *shelf_type);
234 if (!shelf) {
236 return;
237 }
238
239 bScreen *screen = CTX_wm_screen(C);
240 PointerRNA library_ref_ptr = RNA_pointer_create_discrete(
241 &screen->id, &RNA_AssetLibraryReference, &shelf->settings.asset_library_reference);
242 layout->context_ptr_set("asset_library_reference", &library_ref_ptr);
243
244 uiLayout *row = &layout->row(false);
245 uiLayout *catalogs_col = &row->column(false);
247 catalogs_col->fixed_size_set(true);
248 library_selector_draw(C, catalogs_col, *shelf);
249 catalog_tree_draw(*C, *catalogs_col, *shelf);
250
251 uiLayout *right_col = &row->column(false);
252 uiLayout *sub = &right_col->row(false);
253 /* Same as file/asset browser header. */
254 PointerRNA shelf_ptr = RNA_pointer_create_discrete(&screen->id, &RNA_AssetShelf, shelf);
255 sub->prop(&shelf_ptr,
256 "search_filter",
257 /* Force the button to be active in a semi-modal state. */
259 "",
260 ICON_VIEWZOOM);
261
262 uiLayout *asset_view_col = &right_col->column(false);
263 BLI_assert((layout_width_units - LEFT_COL_WIDTH_UNITS) > 0);
264 asset_view_col->ui_units_x_set(layout_width_units - LEFT_COL_WIDTH_UNITS);
265 asset_view_col->fixed_size_set(true);
266
267 build_asset_view(*asset_view_col, shelf->settings.asset_library_reference, *shelf, *C);
268}
269
270static bool popover_panel_poll(const bContext *C, PanelType * /*panel_type*/)
271{
273 if (!shelf_type) {
274 return false;
275 }
276
277 return type_poll_for_popup(*C, shelf_type);
278}
279
281{
282 /* Uses global paneltype registry to allow usage as popover. So only register this once (may be
283 * called from multiple spaces). */
284 if (WM_paneltype_find("ASSETSHELF_PT_popover_panel", true)) {
285 return;
286 }
287
288 PanelType *pt = MEM_callocN<PanelType>(__func__);
289 STRNCPY_UTF8(pt->idname, "ASSETSHELF_PT_popover_panel");
290 STRNCPY_UTF8(pt->label, N_("Asset Shelf Panel"));
292 pt->description = N_("Display an asset shelf in a popover panel");
296 /* Move to have first asset item under cursor. */
297 pt->offset_units_xy.x = -(LEFT_COL_WIDTH_UNITS + 1.5f);
298 /* Offset so mouse is below search button, over the first row of assets. */
299 pt->offset_units_xy.y = 2.5f;
300 BLI_addtail(&region_type->paneltypes, pt);
302}
303
304} // 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
#define STRNCPY_UTF8(dst, src)
#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
@ UI_ITEM_R_TEXT_BUT_FORCE_SEMI_MODAL_ACTIVE
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, bool add_box=true)
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
void fixed_size_set(bool fixed_size)
uiBlock * block() const
uiLayout & column(bool align)
void context_ptr_set(blender::StringRef name, const PointerRNA *ptr)
void ui_units_x_set(float width)
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)