Asset Browser: Show catalog add & delete icons on mouse hover (only)

Now the icons to add or delete catalogs are only shown when mouse hovering a
catalog item in the tree. This is convenient for quick creation of catalogs,
and doesn't require activating a catalog to edit it first.

Determining if a tree item is hovered isn't trivial actually. The UI tree-view
code has to find the matching tree-row button in the previous layout to do so,
since the new layout isn't calculated yet.
This commit is contained in:
Julian Eisel 2021-10-06 16:29:10 +02:00
parent 536109b4ec
commit 75fbf6f17e
5 changed files with 79 additions and 10 deletions

View File

@ -185,6 +185,7 @@ class AbstractTreeView : public TreeViewItemContainer {
const TreeViewItemContainer &old_items);
static AbstractTreeViewItem *find_matching_child(const AbstractTreeViewItem &lookup_item,
const TreeViewItemContainer &items);
/**
* Items may want to do additional work when state changes. But these state changes can only be
* reliably detected after the tree has completed reconstruction (see #is_reconstructed()). So
@ -290,6 +291,12 @@ class AbstractTreeViewItem : public TreeViewItemContainer {
* can't be sure about the item state.
*/
bool is_active() const;
/**
* Can be called from the #AbstractTreeViewItem::build_row() implementation, but not earlier. The
* hovered state can't be queried reliably otherwise.
* Note that this does a linear lookup in the old block, so isn't too great performance-wise.
*/
bool is_hovered() const;
void toggle_collapsed();
/**
* Requires the tree to have completed reconstruction, see #is_reconstructed(). Otherwise we

View File

@ -1293,6 +1293,8 @@ void ui_interface_tag_script_reload_queries(void);
void ui_block_free_views(struct uiBlock *block);
uiTreeViewHandle *ui_block_view_find_matching_in_old_block(const uiBlock *new_block,
const uiTreeViewHandle *new_view);
uiButTreeRow *ui_block_view_find_treerow_in_old_block(const uiBlock *new_block,
const uiTreeViewItemHandle *new_item_handle);
#ifdef __cplusplus
}

View File

@ -106,26 +106,71 @@ static StringRef ui_block_view_find_idname(const uiBlock &block, const AbstractT
return {};
}
uiTreeViewHandle *ui_block_view_find_matching_in_old_block(const uiBlock *new_block,
const uiTreeViewHandle *new_view_handle)
static AbstractTreeView *ui_block_view_find_matching_in_old_block(const uiBlock &new_block,
const AbstractTreeView &new_view)
{
const AbstractTreeView &needle_view = reinterpret_cast<const AbstractTreeView &>(
*new_view_handle);
uiBlock *old_block = new_block->oldblock;
uiBlock *old_block = new_block.oldblock;
if (!old_block) {
return nullptr;
}
StringRef idname = ui_block_view_find_idname(*new_block, needle_view);
StringRef idname = ui_block_view_find_idname(new_block, new_view);
if (idname.is_empty()) {
return nullptr;
}
LISTBASE_FOREACH (ViewLink *, old_view_link, &old_block->views) {
if (old_view_link->idname == idname) {
return reinterpret_cast<uiTreeViewHandle *>(
get_view_from_link<AbstractTreeView>(*old_view_link));
return get_view_from_link<AbstractTreeView>(*old_view_link);
}
}
return nullptr;
}
uiTreeViewHandle *ui_block_view_find_matching_in_old_block(const uiBlock *new_block,
const uiTreeViewHandle *new_view_handle)
{
BLI_assert(new_block && new_view_handle);
const AbstractTreeView &new_view = reinterpret_cast<const AbstractTreeView &>(*new_view_handle);
AbstractTreeView *old_view = ui_block_view_find_matching_in_old_block(*new_block, new_view);
return reinterpret_cast<uiTreeViewHandle *>(old_view);
}
uiButTreeRow *ui_block_view_find_treerow_in_old_block(const uiBlock *new_block,
const uiTreeViewItemHandle *new_item_handle)
{
uiBlock *old_block = new_block->oldblock;
if (!old_block) {
return nullptr;
}
const AbstractTreeViewItem &new_item = *reinterpret_cast<const AbstractTreeViewItem *>(
new_item_handle);
const AbstractTreeView *old_tree_view = ui_block_view_find_matching_in_old_block(
*new_block, new_item.get_tree_view());
if (!old_tree_view) {
return nullptr;
}
LISTBASE_FOREACH (uiBut *, old_but, &old_block->buttons) {
if (old_but->type != UI_BTYPE_TREEROW) {
continue;
}
uiButTreeRow *old_treerow_but = (uiButTreeRow *)old_but;
if (!old_treerow_but->tree_item) {
continue;
}
AbstractTreeViewItem &old_item = *reinterpret_cast<AbstractTreeViewItem *>(
old_treerow_but->tree_item);
/* Check if the row is from the expected tree-view. */
if (&old_item.get_tree_view() != old_tree_view) {
continue;
}
if (UI_tree_view_item_matches(new_item_handle, old_treerow_but->tree_item)) {
return old_treerow_but;
}
}

View File

@ -385,6 +385,21 @@ bool AbstractTreeViewItem::is_active() const
return is_active_;
}
bool AbstractTreeViewItem::is_hovered() const
{
BLI_assert_msg(get_tree_view().is_reconstructed(),
"State can't be queried until reconstruction is completed");
BLI_assert_msg(tree_row_but_ != nullptr,
"Hovered state can't be queried before the tree row is being built");
const uiTreeViewItemHandle *this_handle = reinterpret_cast<const uiTreeViewItemHandle *>(this);
/* The new layout hasn't finished construction yet, so the final state of the button is unknown.
* Get the matching button from the previous redraw instead. */
uiButTreeRow *old_treerow_but = ui_block_view_find_treerow_in_old_block(tree_row_but_->but.block,
this_handle);
return old_treerow_but && (old_treerow_but->but.flag & UI_ACTIVE);
}
bool AbstractTreeViewItem::is_collapsed() const
{
BLI_assert_msg(get_tree_view().is_reconstructed(),

View File

@ -219,7 +219,7 @@ void AssetCatalogTreeViewItem::build_row(uiLayout &row)
{
ui::BasicTreeViewItem::build_row(row);
if (!is_active()) {
if (!is_hovered()) {
return;
}