Blender V4.3
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
9#include "asset_shelf.hh"
10
11#include "BKE_screen.hh"
12
13#include "BLI_string.h"
14
15#include "BLT_translation.hh"
16
17#include "UI_interface_c.hh"
18#include "UI_tree_view.hh"
19
20#include "ED_asset_filter.hh"
21#include "ED_asset_list.hh"
22#include "ED_asset_shelf.hh"
23
24#include "RNA_access.hh"
25#include "RNA_prototypes.hh"
26
27#include "WM_api.hh"
28
30
32 public:
34
36 {
37 for (AssetShelf *shelf : popup_shelves) {
38 MEM_delete(shelf);
39 }
40 }
41
43 {
44 static StaticPopupShelves storage;
45 return storage.popup_shelves;
46 }
47};
48
49void type_popup_unlink(const AssetShelfType &shelf_type)
50{
52 if (shelf->type == &shelf_type) {
53 shelf->type = nullptr;
54 }
55 }
56}
57
59{
61
62 for (AssetShelf *shelf : popup_shelves) {
63 if (STREQ(shelf->idname, shelf_type.idname)) {
65 return shelf;
66 }
67 break;
68 }
69 }
70
71 if (type_poll_for_popup(C, &shelf_type)) {
72 AssetShelf *new_shelf = create_shelf_from_type(shelf_type);
74 /* Increased size of previews, to leave more space for the name. */
76 popup_shelves.append(new_shelf);
77 return new_shelf;
78 }
79
80 return nullptr;
81}
82
84 AssetShelf &shelf_;
86
87 public:
89 : shelf_(shelf)
90 {
91 catalog_tree_ = build_filtered_catalog_tree(
92 library,
94 [this](const asset_system::AssetRepresentation &asset) {
95 return (!shelf_.type->asset_poll || shelf_.type->asset_poll(shelf_.type, &asset));
96 });
97
98 /* Keep the popup open when clicking to activate a catalog. */
99 this->set_popup_keep_open();
100 }
101
102 void build_tree() override
103 {
104 if (catalog_tree_.is_empty()) {
105 auto &item = this->add_tree_item<ui::BasicTreeViewItem>(RPT_("No applicable assets found"),
106 ICON_INFO);
107 item.disable_interaction();
108 return;
109 }
110
111 auto &all_item = this->add_tree_item<ui::BasicTreeViewItem>(IFACE_("All"));
112 all_item.set_on_activate_fn([this](bContext &C, ui::BasicTreeViewItem &) {
115 });
116 all_item.set_is_active_fn(
117 [this]() { return settings_is_all_catalog_active(shelf_.settings); });
118 all_item.uncollapse_by_default();
119
120 catalog_tree_.foreach_root_item([&, this](
121 const asset_system::AssetCatalogTreeItem &catalog_item) {
122 ui::BasicTreeViewItem &item = this->build_catalog_items_recursive(all_item, catalog_item);
124 });
125 }
126
128 ui::TreeViewOrItem &parent_view_item,
129 const asset_system::AssetCatalogTreeItem &catalog_item) const
130 {
131 ui::BasicTreeViewItem &view_item = parent_view_item.add_tree_item<ui::BasicTreeViewItem>(
132 catalog_item.get_name());
133
134 std::string catalog_path = catalog_item.catalog_path().str();
135 view_item.set_on_activate_fn([this, catalog_path](bContext &C, ui::BasicTreeViewItem &) {
136 settings_set_active_catalog(shelf_.settings, catalog_path);
138 });
139 view_item.set_is_active_fn([this, catalog_path]() {
140 return settings_is_active_catalog(shelf_.settings, catalog_path);
141 });
142
143 const int parent_count = view_item.count_parents() + 1;
144
145 catalog_item.foreach_child([&, this](const asset_system::AssetCatalogTreeItem &child) {
146 ui::BasicTreeViewItem &child_item = build_catalog_items_recursive(view_item, child);
147
148 /* Uncollapse to some level (gives quick access, but don't let the tree get too big). */
149 if (parent_count < 3) {
150 child_item.uncollapse_by_default();
151 }
152 });
153
154 return view_item;
155 }
156};
157
158static void catalog_tree_draw(uiLayout &layout, AssetShelf &shelf)
159{
162 if (!library) {
163 return;
164 }
165
166 uiBlock *block = uiLayoutGetBlock(&layout);
168 *block,
169 "asset shelf catalog tree view",
170 std::make_unique<AssetCatalogTreeView>(*library, shelf));
171
172 ui::TreeViewBuilder::build_tree_view(*tree_view, layout);
173}
174
176{
177 const std::optional<StringRefNull> idname = CTX_data_string_get(C, "asset_shelf_idname");
178 if (!idname) {
179 return nullptr;
180 }
181 return type_find_from_idname(*idname);
182}
183
184constexpr int LEFT_COL_WIDTH_UNITS = 10;
186
192{
193 const int max_units_x = (WM_window_native_pixel_x(win) / UI_UNIT_X) - 2;
194 return std::min(LEFT_COL_WIDTH_UNITS + RIGHT_COL_WIDTH_UNITS_DEFAULT, max_units_x);
195}
196
197static void popover_panel_draw(const bContext *C, Panel *panel)
198{
199 const wmWindow *win = CTX_wm_window(C);
200 const int layout_width_units = layout_width_units_clamped(win);
202 BLI_assert_msg(shelf_type != nullptr, "couldn't find asset shelf type from context");
203
205
206 uiLayout *layout = panel->layout;
207 uiLayoutSetUnitsX(layout, layout_width_units);
208
209 AssetShelf *shelf = get_shelf_for_popup(*C, *shelf_type);
210 if (!shelf) {
212 return;
213 }
214
215 bScreen *screen = CTX_wm_screen(C);
216 PointerRNA library_ref_ptr = RNA_pointer_create(
217 &screen->id, &RNA_AssetLibraryReference, &shelf->settings.asset_library_reference);
218 uiLayoutSetContextPointer(layout, "asset_library_reference", &library_ref_ptr);
219
220 uiLayout *row = uiLayoutRow(layout, false);
221 uiLayout *catalogs_col = uiLayoutColumn(row, false);
223 uiLayoutSetFixedSize(catalogs_col, true);
224 library_selector_draw(C, catalogs_col, *shelf);
225 catalog_tree_draw(*catalogs_col, *shelf);
226
227 uiLayout *right_col = uiLayoutColumn(row, false);
228 uiLayout *sub = uiLayoutRow(right_col, false);
229 /* Same as file/asset browser header. */
230 PointerRNA shelf_ptr = RNA_pointer_create(&screen->id, &RNA_AssetShelf, shelf);
231 uiItemR(sub,
232 &shelf_ptr,
233 "search_filter",
234 /* Force the button to be active in a semi-modal state. */
236 "",
237 ICON_VIEWZOOM);
238
239 uiLayout *asset_view_col = uiLayoutColumn(right_col, false);
240 BLI_assert((layout_width_units - LEFT_COL_WIDTH_UNITS) > 0);
241 uiLayoutSetUnitsX(asset_view_col, layout_width_units - LEFT_COL_WIDTH_UNITS);
242 uiLayoutSetFixedSize(asset_view_col, true);
243
244 build_asset_view(*asset_view_col, shelf->settings.asset_library_reference, *shelf, *C, *region);
245}
246
247static bool popover_panel_poll(const bContext *C, PanelType * /*panel_type*/)
248{
250 if (!shelf_type) {
251 return false;
252 }
253
254 return type_poll_for_popup(*C, shelf_type);
255}
256
258{
259 /* Uses global paneltype registry to allow usage as popover. So only register this once (may be
260 * called from multiple spaces). */
261 if (WM_paneltype_find("ASSETSHELF_PT_popover_panel", true)) {
262 return;
263 }
264
265 PanelType *pt = MEM_cnew<PanelType>(__func__);
266 STRNCPY(pt->idname, "ASSETSHELF_PT_popover_panel");
267 STRNCPY(pt->label, N_("Asset Shelf Panel"));
269 pt->description = N_("Display an asset shelf in a popover panel");
273 /* Move to have first asset item under cursor. */
274 pt->offset_units_xy.x = -(LEFT_COL_WIDTH_UNITS + 1.5f);
275 /* Offset so mouse is below search button, over the first row of assets. */
276 pt->offset_units_xy.y = 2.5f;
277 BLI_addtail(&region_type->paneltypes, pt);
279}
280
281} // namespace blender::ed::asset::shelf
bScreen * CTX_wm_screen(const bContext *C)
ARegion * CTX_wm_region_popup(const bContext *C)
wmWindow * CTX_wm_window(const bContext *C)
ARegion * CTX_wm_region(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:97
#define BLI_assert(a)
Definition BLI_assert.h:50
#define BLI_assert_msg(a, msg)
Definition BLI_assert.h:57
void BLI_addtail(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:110
#define STRNCPY(dst, src)
Definition BLI_string.h:593
#define STREQ(a, b)
#define RPT_(msgid)
#define IFACE_(msgid)
#define BLT_I18NCONTEXT_DEFAULT_BPYRNA
@ ASSETSHELF_SHOW_NAMES
blender::ui::AbstractGridView * UI_block_add_view(uiBlock &block, blender::StringRef idname, std::unique_ptr< blender::ui::AbstractGridView > grid_view)
void uiLayoutSetFixedSize(uiLayout *layout, bool fixed_size)
uiBlock * uiLayoutGetBlock(uiLayout *layout)
uiLayout * uiLayoutRow(uiLayout *layout, bool align)
void uiLayoutSetUnitsX(uiLayout *layout, float unit)
uiLayout * uiLayoutColumn(uiLayout *layout, bool align)
#define UI_UNIT_X
void uiItemR(uiLayout *layout, PointerRNA *ptr, const char *propname, eUI_Item_Flag flag, const char *name, int icon)
@ UI_ITEM_R_TEXT_BUT_FORCE_SEMI_MODAL_ACTIVE
void uiLayoutSetContextPointer(uiLayout *layout, const char *name, PointerRNA *ptr)
void append(const T &value)
void foreach_child(ItemIterFn callback) const
void foreach_root_item(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)
Definition tree_view.cc:970
void set_on_activate_fn(ActivateFn fn)
Definition tree_view.cc:965
static void build_tree_view(AbstractTreeView &tree_view, uiLayout &layout, std::optional< StringRef > search_string={}, bool add_box=true)
Definition tree_view.cc:918
ItemT & add_tree_item(Args &&...args)
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(const StringRef idname)
static AssetShelfType * lookup_type_from_idname_in_context(const bContext *C)
void build_asset_view(uiLayout &layout, const AssetLibraryReference &library_ref, const AssetShelf &shelf, const bContext &C, const ARegion &region)
bool settings_is_all_catalog_active(const AssetShelfSettings &settings)
AssetShelf * create_shelf_from_type(AssetShelfType &type)
static void catalog_tree_draw(uiLayout &layout, AssetShelf &shelf)
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 *)
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 settings_set_active_catalog(AssetShelfSettings &settings, const asset_system::AssetCatalogPath &path)
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)
PointerRNA RNA_pointer_create(ID *id, StructRNA *type, void *data)
ListBase paneltypes
AssetLibraryReference asset_library_reference
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
#define N_(msgid)
bool WM_paneltype_add(PanelType *pt)
PanelType * WM_paneltype_find(const char *idname, bool quiet)
int WM_window_native_pixel_x(const wmWindow *win)