UI: Port view item features to base class, merge view item button types

No user visible changes expected.

Merges the tree row and grid tile button types, which were mostly doing
the same things. The idea is that there is a button type for
highlighting, as well as supporting general view item features (e.g.
renaming, drag/drop, etc.). So instead there is a view item button type
now. Also ports view item features like renaming, custom context menus,
drag controllers and drop controllers to `ui::AbstractViewItem` (the new
base class for all view items).

This should be quite an improvement because:
- Merges code that was duplicated over view items.
- Mentioned features (renaming, drag & drop, ...) are much easier to
  implement in new view types now. Most of it comes "for free".
- Further features will immediately become availalbe to all views (e.g.
  selection).
- Simplifies APIs, there don't have to be functions for individual view
  item types anymore.
- View item classes are split and thus less overwhelming visually.
- View item buttons now share all code (drawing, handling, etc.)
- We're soon running out of available button types, this commit merges
  two into one.

I was hoping I could do this in multiple smaller commits, but things
were quite intertwined so that would've taken quite some effort.
This commit is contained in:
Julian Eisel 2022-07-19 16:14:42 +02:00
parent 348ec37f52
commit 5bee991132
19 changed files with 809 additions and 864 deletions

View File

@ -3,11 +3,16 @@
/** \file
* \ingroup editorui
*
* Base for all views (UIs to display data sets), supporting common features.
* Base class for all views (UIs to display data sets) and view items, supporting common features.
* https://wiki.blender.org/wiki/Source/Interface/Views
*
* One of the most important responsibilities of the base class is managing reconstruction,
* enabling state that is persistent over reconstructions/redraws.
* enabling state that is persistent over reconstructions/redraws. Other features:
* - Renaming
* - Custom context menus
* - Notifier listening
* - Drag controllers (dragging view items)
* - Drop controllers (dropping onto/into view items)
*/
#pragma once
@ -18,15 +23,25 @@
#include "DNA_defs.h"
#include "BLI_span.hh"
#include "BLI_string_ref.hh"
struct wmNotifier;
struct bContext;
struct uiBlock;
struct uiBut;
struct uiLayout;
struct uiViewItemHandle;
struct wmDrag;
struct wmNotifier;
namespace blender::ui {
class AbstractViewItem;
class AbstractViewItemDropController;
class AbstractViewItemDragController;
class AbstractView {
friend class AbstractViewItem;
bool is_reconstructed_ = false;
/**
* Only one item can be renamed at a time. So rather than giving each item an own rename buffer
@ -43,6 +58,12 @@ class AbstractView {
/** Listen to a notifier, returning true if a redraw is needed. */
virtual bool listen(const wmNotifier &) const;
/**
* Makes \a item valid for display in this view. Behavior is undefined for items not registered
* with this.
*/
void register_item(AbstractViewItem &item);
/** Only one item can be renamed at a time. */
bool is_renaming() const;
/** \return If renaming was started successfully. */
@ -63,7 +84,6 @@ class AbstractView {
* After this, reconstruction is complete (see #is_reconstructed()).
*/
void update_from_old(uiBlock &new_block);
/**
* Check if the view is fully (re-)constructed. That means, both the build function and
* #update_from_old() have finished.
@ -72,15 +92,85 @@ class AbstractView {
};
class AbstractViewItem {
friend class AbstractView;
friend class ViewItemAPIWrapper;
protected:
/**
* The view this item is a part of, and was registered for using #AbstractView::register_item().
* If this wasn't done, the behavior of items is undefined.
*/
AbstractView *view_ = nullptr;
bool is_active_ = false;
bool is_renaming_ = false;
public:
virtual ~AbstractViewItem() = default;
virtual void build_context_menu(bContext &C, uiLayout &column) const;
/**
* Queries if the view item supports renaming in principle. Renaming may still fail, e.g. if
* another item is already being renamed.
*/
virtual bool supports_renaming() const;
/**
* Try renaming the item, or the data it represents. Can assume
* #AbstractViewItem::supports_renaming() returned true. Sub-classes that override this should
* usually call this, unless they have a custom #AbstractViewItem.matches() implementation.
*
* \return True if the renaming was successful.
*/
virtual bool rename(StringRefNull new_name);
/**
* Get the string that should be used for renaming, typically the item's label. This string will
* not be modified, but if the renaming is canceled, the value will be reset to this.
*/
virtual StringRef get_rename_string() const;
/**
* If an item wants to support being dragged, it has to return a drag controller here.
* That is an object implementing #AbstractViewItemDragController.
*/
virtual std::unique_ptr<AbstractViewItemDragController> create_drag_controller() const;
/**
* If an item wants to support dropping data into it, it has to return a drop controller here.
* That is an object implementing #AbstractViewItemDropController.
*
* \note This drop controller may be requested for each event. The view doesn't keep a drop
* controller around currently. So it can not contain persistent state.
*/
virtual std::unique_ptr<AbstractViewItemDropController> create_drop_controller() const;
/** Get the view this item is registered for using #AbstractView::register_item(). */
AbstractView &get_view() const;
/**
* Requires the view to have completed reconstruction, see #is_reconstructed(). Otherwise we
* can't be sure about the item state.
*/
bool is_active() const;
bool is_renaming() const;
void begin_renaming();
void end_renaming();
void rename_apply();
template<typename ToType = AbstractViewItem>
static ToType *from_item_handle(uiViewItemHandle *handle);
protected:
AbstractViewItem() = default;
/**
* Compare this item's identity to \a other to check if they represent the same data.
* Implementations can assume that the types match already (caller must check).
*
* Used to recognize an item from a previous redraw, to be able to keep its state (e.g. active,
* renaming, etc.).
*/
virtual bool matches(const AbstractViewItem &other) const = 0;
/**
* Copy persistent state (e.g. active, selection, etc.) from a matching item of
* the last redraw to this item. If sub-classes introduce more advanced state they should
@ -90,7 +180,101 @@ class AbstractViewItem {
*/
virtual void update_from_old(const AbstractViewItem &old);
void set_view(AbstractView &view);
/**
* Add a text button for renaming the item to \a block. This must be used for the built-in
* renaming to work. This button is meant to appear temporarily. It is removed when renaming is
* done.
*/
void add_rename_button(uiBlock &block);
};
template<typename ToType> ToType *AbstractViewItem::from_item_handle(uiViewItemHandle *handle)
{
static_assert(std::is_base_of<AbstractViewItem, ToType>::value,
"Type must derive from and implement the AbstractViewItem interface");
return dynamic_cast<ToType *>(reinterpret_cast<AbstractViewItem *>(handle));
}
/* ---------------------------------------------------------------------- */
/** \name Drag 'n Drop
* \{ */
/**
* Class to enable dragging a view item. An item can return a drop controller for itself by
* implementing #AbstractViewItem::create_drag_controller().
*/
class AbstractViewItemDragController {
protected:
AbstractView &view_;
public:
AbstractViewItemDragController(AbstractView &view);
virtual ~AbstractViewItemDragController() = default;
virtual int get_drag_type() const = 0;
virtual void *create_drag_data() const = 0;
virtual void on_drag_start();
/** Request the view the item is registered for as type #ViewType. Throws a `std::bad_cast`
* exception if the view is not of the requested type. */
template<class ViewType> inline ViewType &get_view() const;
};
/**
* Class to define the behavior when dropping something onto/into a view item, plus the behavior
* when dragging over this item. An item can return a drop controller for itself via a custom
* implementation of #AbstractViewItem::create_drop_controller().
*/
class AbstractViewItemDropController {
protected:
AbstractView &view_;
public:
AbstractViewItemDropController(AbstractView &view);
virtual ~AbstractViewItemDropController() = default;
/**
* Check if the data dragged with \a drag can be dropped on the item this controller is for.
* \param r_disabled_hint: Return a static string to display to the user, explaining why dropping
* isn't possible on this item. Shouldn't be done too aggressively, e.g.
* don't set this if the drag-type can't be dropped here; only if it can
* but there's another reason it can't be dropped.
* Can assume this is a non-null pointer.
*/
virtual bool can_drop(const wmDrag &drag, const char **r_disabled_hint) const = 0;
/**
* Custom text to display when dragging over a view item. Should explain what happens when
* dropping the data onto this item. Will only be used if #AbstractViewItem::can_drop()
* returns true, so the implementing override doesn't have to check that again.
* The returned value must be a translated string.
*/
virtual std::string drop_tooltip(const wmDrag &drag) const = 0;
/**
* Execute the logic to apply a drop of the data dragged with \a drag onto/into the item this
* controller is for.
*/
virtual bool on_drop(struct bContext *C, const wmDrag &drag) = 0;
/** Request the view the item is registered for as type #ViewType. Throws a `std::bad_cast`
* exception if the view is not of the requested type. */
template<class ViewType> inline ViewType &get_view() const;
};
template<class ViewType> ViewType &AbstractViewItemDragController::get_view() const
{
static_assert(std::is_base_of<AbstractView, ViewType>::value,
"Type must derive from and implement the ui::AbstractView interface");
return dynamic_cast<ViewType &>(view_);
}
template<class ViewType> ViewType &AbstractViewItemDropController::get_view() const
{
static_assert(std::is_base_of<AbstractView, ViewType>::value,
"Type must derive from and implement the ui::AbstractView interface");
return dynamic_cast<ViewType &>(view_);
}
/** \} */
} // namespace blender::ui

View File

@ -19,7 +19,7 @@
struct bContext;
struct PreviewImage;
struct uiBlock;
struct uiButGridTile;
struct uiButViewItem;
struct uiLayout;
struct View2D;
struct wmNotifier;
@ -41,32 +41,22 @@ class AbstractGridViewItem : public AbstractViewItem {
protected:
/** Reference to a string that uniquely identifies this item in the view. */
StringRef identifier_{};
/** Every visible item gets a button of type #UI_BTYPE_GRID_TILE during the layout building. */
uiButGridTile *grid_tile_but_ = nullptr;
/** Every visible item gets a button of type #UI_BTYPE_VIEW_ITEM during the layout building. */
uiButViewItem *view_item_but_ = nullptr;
public:
virtual ~AbstractGridViewItem() = default;
virtual void build_grid_tile(uiLayout &layout) const = 0;
/**
* Compare this item's identifier to \a other to check if they represent the same data.
* Used to recognize an item from a previous redraw, to be able to keep its state (e.g. active,
* renaming, etc.).
*/
bool matches(const AbstractGridViewItem &other) const;
const AbstractGridView &get_view() const;
/**
* Requires the tree to have completed reconstruction, see #is_reconstructed(). Otherwise we
* can't be sure about the item state.
*/
bool is_active() const;
protected:
AbstractGridViewItem(StringRef identifier);
/** See AbstractViewItem::matches(). */
virtual bool matches(const AbstractViewItem &other) const override;
/** Called when the item's state changes from inactive to active. */
virtual void on_activate();
/**

View File

@ -74,10 +74,8 @@ typedef struct uiLayout uiLayout;
typedef struct uiPopupBlockHandle uiPopupBlockHandle;
/* C handle for C++ #ui::AbstractView type. */
typedef struct uiViewHandle uiViewHandle;
/* C handle for C++ #ui::AbstractTreeViewItem type. */
typedef struct uiTreeViewItemHandle uiTreeViewItemHandle;
/* C handle for C++ #ui::AbstractGridViewItem type. */
typedef struct uiGridViewItemHandle uiGridViewItemHandle;
/* C handle for C++ #ui::AbstractViewItem type. */
typedef struct uiViewItemHandle uiViewItemHandle;
/* Defines */
@ -391,10 +389,8 @@ typedef enum {
/** Resize handle (resize uilist). */
UI_BTYPE_GRIP = 57 << 9,
UI_BTYPE_DECORATOR = 58 << 9,
/* An item in a tree view. Parent items may be collapsible. */
UI_BTYPE_TREEROW = 59 << 9,
/* An item in a grid view. */
UI_BTYPE_GRID_TILE = 60 << 9,
/* An item a view (see #ui::AbstractViewItem). */
UI_BTYPE_VIEW_ITEM = 59 << 9,
} eButType;
#define BUTTYPE (63 << 9)
@ -1685,8 +1681,6 @@ int UI_search_items_find_index(uiSearchItems *items, const char *name);
*/
void UI_but_hint_drawstr_set(uiBut *but, const char *string);
void UI_but_treerow_indentation_set(uiBut *but, int indentation);
void UI_but_node_link_set(uiBut *but, struct bNodeSocket *socket, const float draw_color[4]);
void UI_but_number_step_size_set(uiBut *but, float step_size);
@ -3201,45 +3195,44 @@ void UI_interface_tag_script_reload(void);
void UI_block_views_listen(const uiBlock *block,
const struct wmRegionListenerParams *listener_params);
bool UI_grid_view_item_is_active(const uiGridViewItemHandle *item_handle);
bool UI_tree_view_item_is_active(const uiTreeViewItemHandle *item);
bool UI_grid_view_item_matches(const uiGridViewItemHandle *a, const uiGridViewItemHandle *b);
bool UI_tree_view_item_matches(const uiTreeViewItemHandle *a, const uiTreeViewItemHandle *b);
bool UI_view_item_is_active(const uiViewItemHandle *item_handle);
bool UI_view_item_matches(const uiViewItemHandle *a_handle, const uiViewItemHandle *b_handle);
/**
* Attempt to start dragging the tree-item \a item_. This will not work if the tree item doesn't
* support dragging, i.e. it won't create a drag-controller upon request.
* \return True if dragging started successfully, otherwise false.
*/
bool UI_tree_view_item_drag_start(struct bContext *C, uiTreeViewItemHandle *item_);
bool UI_tree_view_item_can_drop(const uiTreeViewItemHandle *item_,
const struct wmDrag *drag,
const char **r_disabled_hint);
char *UI_tree_view_item_drop_tooltip(const uiTreeViewItemHandle *item, const struct wmDrag *drag);
/**
* Let a tree-view item handle a drop event.
* \return True if the drop was handled by the tree-view item.
*/
bool UI_tree_view_item_drop_handle(struct bContext *C,
const uiTreeViewItemHandle *item_,
const struct ListBase *drags);
/**
* Can \a item_handle be renamed right now? Not that this isn't just a mere wrapper around
* #AbstractTreeViewItem::can_rename(). This also checks if there is another item being renamed,
* Can \a item_handle be renamed right now? Note that this isn't just a mere wrapper around
* #AbstractViewItem::supports_renaming(). This also checks if there is another item being renamed,
* and returns false if so.
*/
bool UI_tree_view_item_can_rename(const uiTreeViewItemHandle *item_handle);
void UI_tree_view_item_begin_rename(uiTreeViewItemHandle *item_handle);
bool UI_view_item_can_rename(const uiViewItemHandle *item_handle);
void UI_view_item_begin_rename(uiViewItemHandle *item_handle);
void UI_tree_view_item_context_menu_build(struct bContext *C,
const uiTreeViewItemHandle *item,
uiLayout *column);
void UI_view_item_context_menu_build(struct bContext *C,
const uiViewItemHandle *item_handle,
uiLayout *column);
/**
* \param xy: Coordinate to find a tree-row item at, in window space.
* Attempt to start dragging \a item_. This will not work if the view item doesn't
* support dragging, i.e. if it won't create a drag-controller upon request.
* \return True if dragging started successfully, otherwise false.
*/
uiTreeViewItemHandle *UI_block_tree_view_find_item_at(const struct ARegion *region,
const int xy[2]) ATTR_NONNULL(1, 2);
uiTreeViewItemHandle *UI_block_tree_view_find_active_item(const struct ARegion *region);
bool UI_view_item_drag_start(struct bContext *C, const uiViewItemHandle *item_);
bool UI_view_item_can_drop(const uiViewItemHandle *item_,
const struct wmDrag *drag,
const char **r_disabled_hint);
char *UI_view_item_drop_tooltip(const uiViewItemHandle *item, const struct wmDrag *drag);
/**
* Let a view item handle a drop event.
* \return True if the drop was handled by the view item.
*/
bool UI_view_item_drop_handle(struct bContext *C,
const uiViewItemHandle *item_,
const struct ListBase *drags);
/**
* \param xy: Coordinate to find a view item at, in window space.
*/
uiViewItemHandle *UI_block_view_find_item_at(const struct ARegion *region, const int xy[2])
ATTR_NONNULL();
uiViewItemHandle *UI_block_view_find_active_item(const struct ARegion *region);
#ifdef __cplusplus
}

View File

@ -9,7 +9,6 @@
#pragma once
#include <array>
#include <functional>
#include <memory>
#include <string>
@ -25,18 +24,13 @@
struct bContext;
struct uiBlock;
struct uiBut;
struct uiButTreeRow;
struct uiButViewItem;
struct uiLayout;
struct wmDrag;
struct wmEvent;
struct wmNotifier;
namespace blender::ui {
class AbstractTreeView;
class AbstractTreeViewItem;
class AbstractTreeViewItemDropController;
class AbstractTreeViewItemDragController;
/* ---------------------------------------------------------------------- */
/** \name Tree-View Item Container
@ -161,19 +155,17 @@ class AbstractTreeViewItem : public AbstractViewItem, public TreeViewItemContain
private:
bool is_open_ = false;
bool is_renaming_ = false;
protected:
/** This label is used as the default way to identifying an item within its parent. */
std::string label_{};
/** Every visible item gets a button of type #UI_BTYPE_TREEROW during the layout building. */
uiButTreeRow *tree_row_but_ = nullptr;
/** Every visible item gets a button of type #UI_BTYPE_VIEW_ITEM during the layout building. */
uiButViewItem *view_item_but_ = nullptr;
public:
virtual ~AbstractTreeViewItem() = default;
virtual void build_row(uiLayout &row) = 0;
virtual void build_context_menu(bContext &C, uiLayout &column) const;
AbstractTreeView &get_tree_view() const;
@ -185,11 +177,6 @@ class AbstractTreeViewItem : public AbstractViewItem, public TreeViewItemContain
* can't be sure about the item state.
*/
bool is_collapsed() const;
/**
* Requires the tree to have completed reconstruction, see #is_reconstructed(). Otherwise we
* can't be sure about the item state.
*/
bool is_active() const;
protected:
/**
@ -202,25 +189,19 @@ class AbstractTreeViewItem : public AbstractViewItem, public TreeViewItemContain
*/
virtual std::optional<bool> should_be_active() const;
/**
* Queries if the tree-view item supports renaming in principle. Renaming may still fail, e.g. if
* another item is already being renamed.
*/
virtual bool supports_renaming() const;
/**
* Try renaming the item, or the data it represents. Can assume
* #AbstractTreeViewItem::supports_renaming() returned true. Sub-classes that override this
* should usually call this, unless they have a custom #AbstractTreeViewItem.matches().
*
* \return True if the renaming was successful.
*/
virtual bool rename(StringRefNull new_name);
/** See AbstractViewItem::get_rename_string(). */
virtual StringRef get_rename_string() const override;
/** See AbstractViewItem::rename(). */
virtual bool rename(StringRefNull new_name) override;
/**
* Return whether the item can be collapsed. Used to disable collapsing for items with children.
*/
virtual bool supports_collapsing() const;
/** See #AbstractViewItem::matches(). */
virtual bool matches(const AbstractViewItem &other) const override;
/** See #AbstractViewItem::update_from_old(). */
virtual void update_from_old(const AbstractViewItem &old) override;
@ -230,22 +211,11 @@ class AbstractTreeViewItem : public AbstractViewItem, public TreeViewItemContain
* open/closed, active, etc.). Items are only matched if their parents also match.
* By default this just matches the item's label (if the parents match!). If that isn't
* good enough for a sub-class, that can override it.
*/
virtual bool matches(const AbstractTreeViewItem &other) const;
/**
* If an item wants to support being dragged, it has to return a drag controller here.
* That is an object implementing #AbstractTreeViewItemDragController.
*/
virtual std::unique_ptr<AbstractTreeViewItemDragController> create_drag_controller() const;
/**
* If an item wants to support dropping data into it, it has to return a drop controller here.
* That is an object implementing #AbstractTreeViewItemDropController.
*
* \note This drop controller may be requested for each event. The tree-view doesn't keep a drop
* controller around currently. So it can not contain persistent state.
* TODO #matches_single() is a rather temporary name, used to indicate that this only compares
* the item itself, not the parents. Item matching is expected to change quite a bit anyway.
*/
virtual std::unique_ptr<AbstractTreeViewItemDropController> create_drop_controller() const;
virtual bool matches_single(const AbstractTreeViewItem &other) const;
/**
* Activates this item, deactivates other items, calls the #AbstractTreeViewItem::on_activate()
@ -263,98 +233,30 @@ class AbstractTreeViewItem : public AbstractViewItem, public TreeViewItemContain
*/
bool is_hovered() const;
bool is_collapsible() const;
bool is_renaming() const;
void ensure_parents_uncollapsed();
uiButTreeRow *tree_row_button();
uiButViewItem *view_item_button();
private:
static void rename_button_fn(bContext *, void *, char *);
static AbstractTreeViewItem *find_tree_item_from_rename_button(const uiBut &but);
static void tree_row_click_fn(struct bContext *, void *, void *);
static void collapse_chevron_click_fn(bContext *, void *but_arg1, void *);
static bool is_collapse_chevron_but(const uiBut *but);
/** See #AbstractTreeView::change_state_delayed() */
void change_state_delayed();
void end_renaming();
void add_treerow_button(uiBlock &block);
void add_indent(uiLayout &row) const;
void add_collapse_chevron(uiBlock &block) const;
void add_rename_button(uiLayout &row);
bool matches_including_parents(const AbstractTreeViewItem &other) const;
bool has_active_child() const;
int count_parents() const;
};
/** \} */
/* ---------------------------------------------------------------------- */
/** \name Drag 'n Drop
* \{ */
/**
* Class to enable dragging a tree-item. An item can return a drop controller for itself via a
* custom implementation of #AbstractTreeViewItem::create_drag_controller().
*/
class AbstractTreeViewItemDragController {
protected:
AbstractTreeView &tree_view_;
public:
AbstractTreeViewItemDragController(AbstractTreeView &tree_view);
virtual ~AbstractTreeViewItemDragController() = default;
virtual int get_drag_type() const = 0;
virtual void *create_drag_data() const = 0;
virtual void on_drag_start();
template<class TreeViewType> inline TreeViewType &tree_view() const;
};
/**
* Class to customize the drop behavior of a tree-item, plus the behavior when dragging over this
* item. An item can return a drop controller for itself via a custom implementation of
* #AbstractTreeViewItem::create_drop_controller().
*/
class AbstractTreeViewItemDropController {
protected:
AbstractTreeView &tree_view_;
public:
AbstractTreeViewItemDropController(AbstractTreeView &tree_view);
virtual ~AbstractTreeViewItemDropController() = default;
/**
* Check if the data dragged with \a drag can be dropped on the item this controller is for.
* \param r_disabled_hint: Return a static string to display to the user, explaining why dropping
* isn't possible on this item. Shouldn't be done too aggressively, e.g.
* don't set this if the drag-type can't be dropped here; only if it can
* but there's another reason it can't be dropped.
* Can assume this is a non-null pointer.
*/
virtual bool can_drop(const wmDrag &drag, const char **r_disabled_hint) const = 0;
/**
* Custom text to display when dragging over a tree item. Should explain what happens when
* dropping the data onto this item. Will only be used if #AbstractTreeViewItem::can_drop()
* returns true, so the implementing override doesn't have to check that again.
* The returned value must be a translated string.
*/
virtual std::string drop_tooltip(const wmDrag &drag) const = 0;
/**
* Execute the logic to apply a drop of the data dragged with \a drag onto/into the item this
* controller is for.
*/
virtual bool on_drop(struct bContext *C, const wmDrag &drag) = 0;
template<class TreeViewType> inline TreeViewType &tree_view() const;
};
/** \} */
/* ---------------------------------------------------------------------- */
/** \name Predefined Tree-View Item Types
*
@ -426,18 +328,4 @@ inline ItemT &TreeViewItemContainer::add_tree_item(Args &&...args)
add_tree_item(std::make_unique<ItemT>(std::forward<Args>(args)...)));
}
template<class TreeViewType> TreeViewType &AbstractTreeViewItemDragController::tree_view() const
{
static_assert(std::is_base_of<AbstractTreeView, TreeViewType>::value,
"Type must derive from and implement the AbstractTreeView interface");
return static_cast<TreeViewType &>(tree_view_);
}
template<class TreeViewType> TreeViewType &AbstractTreeViewItemDropController::tree_view() const
{
static_assert(std::is_base_of<AbstractTreeView, TreeViewType>::value,
"Type must derive from and implement the AbstractTreeView interface");
return static_cast<TreeViewType &>(tree_view_);
}
} // namespace blender::ui

View File

@ -10,6 +10,13 @@
namespace blender::ui {
void AbstractView::register_item(AbstractViewItem &item)
{
/* Actually modifies the item, not the view. But for the public API it "feels" a bit nicer to
* have the view base class register the items, rather than setting the view on the item. */
item.view_ = this;
}
/* ---------------------------------------------------------------------- */
/** \name View Reconstruction
* \{ */

View File

@ -4,6 +4,16 @@
* \ingroup edinterface
*/
#include "BKE_context.h"
#include "BLI_listbase.h"
#include "BLI_string.h"
#include "WM_api.h"
#include "UI_interface.h"
#include "interface_intern.h"
#include "UI_abstract_view.hh"
namespace blender::ui {
@ -15,8 +25,349 @@ namespace blender::ui {
void AbstractViewItem::update_from_old(const AbstractViewItem &old)
{
is_active_ = old.is_active_;
is_renaming_ = old.is_renaming_;
}
/** \} */
/* ---------------------------------------------------------------------- */
/** \name Renaming
* \{ */
bool AbstractViewItem::supports_renaming() const
{
/* No renaming by default. */
return false;
}
bool AbstractViewItem::rename(StringRefNull /*new_name*/)
{
/* No renaming by default. */
return false;
}
StringRef AbstractViewItem::get_rename_string() const
{
/* No rename string by default. */
return {};
}
bool AbstractViewItem::is_renaming() const
{
return is_renaming_;
}
void AbstractViewItem::begin_renaming()
{
AbstractView &view = get_view();
if (view.is_renaming() || !supports_renaming()) {
return;
}
if (view.begin_renaming()) {
is_renaming_ = true;
}
StringRef initial_str = get_rename_string();
std::copy(std::begin(initial_str), std::end(initial_str), std::begin(view.get_rename_buffer()));
}
void AbstractViewItem::rename_apply()
{
const AbstractView &view = get_view();
rename(view.get_rename_buffer().data());
end_renaming();
}
void AbstractViewItem::end_renaming()
{
if (!is_renaming()) {
return;
}
is_renaming_ = false;
AbstractView &view = get_view();
view.end_renaming();
}
static AbstractViewItem *find_item_from_rename_button(const uiBut &rename_but)
{
/* A minimal sanity check, can't do much more here. */
BLI_assert(rename_but.type == UI_BTYPE_TEXT && rename_but.poin);
LISTBASE_FOREACH (uiBut *, but, &rename_but.block->buttons) {
if (but->type != UI_BTYPE_VIEW_ITEM) {
continue;
}
uiButViewItem *view_item_but = (uiButViewItem *)but;
AbstractViewItem *item = reinterpret_cast<AbstractViewItem *>(view_item_but->view_item);
const AbstractView &view = item->get_view();
if (item->is_renaming() && (view.get_rename_buffer().data() == rename_but.poin)) {
return item;
}
}
return nullptr;
}
static void rename_button_fn(bContext *UNUSED(C), void *arg, char *UNUSED(origstr))
{
const uiBut *rename_but = static_cast<uiBut *>(arg);
AbstractViewItem *item = find_item_from_rename_button(*rename_but);
BLI_assert(item);
item->rename_apply();
}
void AbstractViewItem::add_rename_button(uiBlock &block)
{
AbstractView &view = get_view();
uiBut *rename_but = uiDefBut(&block,
UI_BTYPE_TEXT,
1,
"",
0,
0,
UI_UNIT_X * 10,
UI_UNIT_Y,
view.get_rename_buffer().data(),
1.0f,
view.get_rename_buffer().size(),
0,
0,
"");
/* Gotta be careful with what's passed to the `arg1` here. Any view data will be freed once the
* callback is executed. */
UI_but_func_rename_set(rename_but, rename_button_fn, rename_but);
UI_but_flag_disable(rename_but, UI_BUT_UNDO);
const bContext *evil_C = reinterpret_cast<bContext *>(block.evil_C);
ARegion *region = CTX_wm_region(evil_C);
/* Returns false if the button was removed. */
if (UI_but_active_only(evil_C, region, &block, rename_but) == false) {
end_renaming();
}
}
/** \} */
/* ---------------------------------------------------------------------- */
/** \name Context Menu
* \{ */
void AbstractViewItem::build_context_menu(bContext & /*C*/, uiLayout & /*column*/) const
{
/* No context menu by default. */
}
/** \} */
/* ---------------------------------------------------------------------- */
/** \name Drag 'n Drop
* \{ */
std::unique_ptr<AbstractViewItemDragController> AbstractViewItem::create_drag_controller() const
{
/* There's no drag controller (and hence no drag support) by default. */
return nullptr;
}
std::unique_ptr<AbstractViewItemDropController> AbstractViewItem::create_drop_controller() const
{
/* There's no drop controller (and hence no drop support) by default. */
return nullptr;
}
AbstractViewItemDragController::AbstractViewItemDragController(AbstractView &view) : view_(view)
{
}
void AbstractViewItemDragController::on_drag_start()
{
/* Do nothing by default. */
}
AbstractViewItemDropController::AbstractViewItemDropController(AbstractView &view) : view_(view)
{
}
/** \} */
/* ---------------------------------------------------------------------- */
/** \name General Getters & Setters
* \{ */
AbstractView &AbstractViewItem::get_view() const
{
if (UNLIKELY(!view_)) {
throw std::runtime_error(
"Invalid state, item must be registered through AbstractView::register_item()");
}
return *view_;
}
bool AbstractViewItem::is_active() const
{
BLI_assert_msg(get_view().is_reconstructed(),
"State can't be queried until reconstruction is completed");
return is_active_;
}
/** \} */
} // namespace blender::ui
/* ---------------------------------------------------------------------- */
/** \name C-API
* \{ */
namespace blender::ui {
/**
* Helper class to provide a higher level public (C-)API. Has access to private/protected view item
* members and ensures some invariants that way.
*/
class ViewItemAPIWrapper {
public:
static bool matches(const AbstractViewItem &a, const AbstractViewItem &b)
{
if (typeid(a) != typeid(b)) {
return false;
}
/* TODO should match the view as well. */
return a.matches(b);
}
static bool can_rename(const AbstractViewItem &item)
{
const AbstractView &view = item.get_view();
return !view.is_renaming() && item.supports_renaming();
}
static bool drag_start(bContext &C, const AbstractViewItem &item)
{
const std::unique_ptr<AbstractViewItemDragController> drag_controller =
item.create_drag_controller();
if (!drag_controller) {
return false;
}
WM_event_start_drag(&C,
ICON_NONE,
drag_controller->get_drag_type(),
drag_controller->create_drag_data(),
0,
WM_DRAG_FREE_DATA);
drag_controller->on_drag_start();
return true;
}
static bool can_drop(const AbstractViewItem &item,
const wmDrag &drag,
const char **r_disabled_hint)
{
const std::unique_ptr<AbstractViewItemDropController> drop_controller =
item.create_drop_controller();
if (!drop_controller) {
return false;
}
return drop_controller->can_drop(drag, r_disabled_hint);
}
static std::string drop_tooltip(const AbstractViewItem &item, const wmDrag &drag)
{
const std::unique_ptr<AbstractViewItemDropController> drop_controller =
item.create_drop_controller();
if (!drop_controller) {
return {};
}
return drop_controller->drop_tooltip(drag);
}
static bool drop_handle(bContext &C, const AbstractViewItem &item, const ListBase &drags)
{
std::unique_ptr<AbstractViewItemDropController> drop_controller =
item.create_drop_controller();
const char *disabled_hint_dummy = nullptr;
LISTBASE_FOREACH (const wmDrag *, drag, &drags) {
if (drop_controller->can_drop(*drag, &disabled_hint_dummy)) {
return drop_controller->on_drop(&C, *drag);
}
}
return false;
}
};
} // namespace blender::ui
using namespace blender::ui;
bool UI_view_item_is_active(const uiViewItemHandle *item_handle)
{
const AbstractViewItem &item = reinterpret_cast<const AbstractViewItem &>(*item_handle);
return item.is_active();
}
bool UI_view_item_matches(const uiViewItemHandle *a_handle, const uiViewItemHandle *b_handle)
{
const AbstractViewItem &a = reinterpret_cast<const AbstractViewItem &>(*a_handle);
const AbstractViewItem &b = reinterpret_cast<const AbstractViewItem &>(*b_handle);
return ViewItemAPIWrapper::matches(a, b);
}
bool UI_view_item_can_rename(const uiViewItemHandle *item_handle)
{
const AbstractViewItem &item = reinterpret_cast<const AbstractViewItem &>(*item_handle);
return ViewItemAPIWrapper::can_rename(item);
}
void UI_view_item_begin_rename(uiViewItemHandle *item_handle)
{
AbstractViewItem &item = reinterpret_cast<AbstractViewItem &>(*item_handle);
item.begin_renaming();
}
void UI_view_item_context_menu_build(bContext *C,
const uiViewItemHandle *item_handle,
uiLayout *column)
{
const AbstractViewItem &item = reinterpret_cast<const AbstractViewItem &>(*item_handle);
item.build_context_menu(*C, *column);
}
bool UI_view_item_drag_start(bContext *C, const uiViewItemHandle *item_)
{
const AbstractViewItem &item = reinterpret_cast<const AbstractViewItem &>(*item_);
return ViewItemAPIWrapper::drag_start(*C, item);
}
bool UI_view_item_can_drop(const uiViewItemHandle *item_,
const wmDrag *drag,
const char **r_disabled_hint)
{
const AbstractViewItem &item = reinterpret_cast<const AbstractViewItem &>(*item_);
return ViewItemAPIWrapper::can_drop(item, *drag, r_disabled_hint);
}
char *UI_view_item_drop_tooltip(const uiViewItemHandle *item_, const wmDrag *drag)
{
const AbstractViewItem &item = reinterpret_cast<const AbstractViewItem &>(*item_);
const std::string tooltip = ViewItemAPIWrapper::drop_tooltip(item, *drag);
return tooltip.empty() ? nullptr : BLI_strdup(tooltip.c_str());
}
bool UI_view_item_drop_handle(bContext *C, const uiViewItemHandle *item_, const ListBase *drags)
{
const AbstractViewItem &item = reinterpret_cast<const AbstractViewItem &>(*item_);
return ViewItemAPIWrapper::drop_handle(*C, item, *drags);
}
/** \} */

View File

@ -95,18 +95,19 @@ AbstractGridViewItem::AbstractGridViewItem(StringRef identifier) : identifier_(i
{
}
bool AbstractGridViewItem::matches(const AbstractGridViewItem &other) const
bool AbstractGridViewItem::matches(const AbstractViewItem &other) const
{
return identifier_ == other.identifier_;
const AbstractGridViewItem &other_grid_item = dynamic_cast<const AbstractGridViewItem &>(other);
return identifier_ == other_grid_item.identifier_;
}
void AbstractGridViewItem::grid_tile_click_fn(struct bContext * /*C*/,
void *but_arg1,
void * /*arg2*/)
{
uiButGridTile *grid_tile_but = (uiButGridTile *)but_arg1;
uiButViewItem *view_item_but = (uiButViewItem *)but_arg1;
AbstractGridViewItem &grid_item = reinterpret_cast<AbstractGridViewItem &>(
*grid_tile_but->view_item);
*view_item_but->view_item);
grid_item.activate();
}
@ -114,8 +115,8 @@ void AbstractGridViewItem::grid_tile_click_fn(struct bContext * /*C*/,
void AbstractGridViewItem::add_grid_tile_button(uiBlock &block)
{
const GridViewStyle &style = get_view().get_style();
grid_tile_but_ = (uiButGridTile *)uiDefBut(&block,
UI_BTYPE_GRID_TILE,
view_item_but_ = (uiButViewItem *)uiDefBut(&block,
UI_BTYPE_VIEW_ITEM,
0,
"",
0,
@ -129,15 +130,8 @@ void AbstractGridViewItem::add_grid_tile_button(uiBlock &block)
0,
"");
grid_tile_but_->view_item = reinterpret_cast<uiGridViewItemHandle *>(this);
UI_but_func_set(&grid_tile_but_->but, grid_tile_click_fn, grid_tile_but_, nullptr);
}
bool AbstractGridViewItem::is_active() const
{
BLI_assert_msg(get_view().is_reconstructed(),
"State can't be queried until reconstruction is completed");
return is_active_;
view_item_but_->view_item = reinterpret_cast<uiViewItemHandle *>(this);
UI_but_func_set(&view_item_but_->but, grid_tile_click_fn, view_item_but_, nullptr);
}
void AbstractGridViewItem::on_activate()
@ -468,24 +462,3 @@ std::optional<bool> PreviewGridItem::should_be_active() const
}
} // namespace blender::ui
using namespace blender::ui;
/* ---------------------------------------------------------------------- */
/* C-API */
using namespace blender::ui;
bool UI_grid_view_item_is_active(const uiGridViewItemHandle *item_handle)
{
const AbstractGridViewItem &item = reinterpret_cast<const AbstractGridViewItem &>(*item_handle);
return item.is_active();
}
bool UI_grid_view_item_matches(const uiGridViewItemHandle *a_handle,
const uiGridViewItemHandle *b_handle)
{
const AbstractGridViewItem &a = reinterpret_cast<const AbstractGridViewItem &>(*a_handle);
const AbstractGridViewItem &b = reinterpret_cast<const AbstractGridViewItem &>(*b_handle);
return a.matches(b);
}

View File

@ -769,20 +769,11 @@ static bool ui_but_equals_old(const uiBut *but, const uiBut *oldbut)
return false;
}
if ((but->type == UI_BTYPE_TREEROW) && (oldbut->type == UI_BTYPE_TREEROW)) {
uiButTreeRow *but_treerow = (uiButTreeRow *)but;
uiButTreeRow *oldbut_treerow = (uiButTreeRow *)oldbut;
if (!but_treerow->tree_item || !oldbut_treerow->tree_item ||
!UI_tree_view_item_matches(but_treerow->tree_item, oldbut_treerow->tree_item)) {
return false;
}
}
if ((but->type == UI_BTYPE_GRID_TILE) && (oldbut->type == UI_BTYPE_GRID_TILE)) {
uiButGridTile *but_gridtile = (uiButGridTile *)but;
uiButGridTile *oldbut_gridtile = (uiButGridTile *)oldbut;
if (!but_gridtile->view_item || !oldbut_gridtile->view_item ||
!UI_grid_view_item_matches(but_gridtile->view_item, oldbut_gridtile->view_item)) {
if ((but->type == UI_BTYPE_VIEW_ITEM) && (oldbut->type == UI_BTYPE_VIEW_ITEM)) {
uiButViewItem *but_item = (uiButViewItem *)but;
uiButViewItem *oldbut_item = (uiButViewItem *)oldbut;
if (!but_item->view_item || !oldbut_item->view_item ||
!UI_view_item_matches(but_item->view_item, oldbut_item->view_item)) {
return false;
}
}
@ -907,16 +898,10 @@ static void ui_but_update_old_active_from_new(uiBut *oldbut, uiBut *but)
progress_oldbut->progress = progress_but->progress;
break;
}
case UI_BTYPE_TREEROW: {
uiButTreeRow *treerow_oldbut = (uiButTreeRow *)oldbut;
uiButTreeRow *treerow_newbut = (uiButTreeRow *)but;
SWAP(uiTreeViewItemHandle *, treerow_newbut->tree_item, treerow_oldbut->tree_item);
break;
}
case UI_BTYPE_GRID_TILE: {
uiButGridTile *gridtile_oldbut = (uiButGridTile *)oldbut;
uiButGridTile *gridtile_newbut = (uiButGridTile *)but;
SWAP(uiGridViewItemHandle *, gridtile_newbut->view_item, gridtile_oldbut->view_item);
case UI_BTYPE_VIEW_ITEM: {
uiButViewItem *view_item_oldbut = (uiButViewItem *)oldbut;
uiButViewItem *view_item_newbut = (uiButViewItem *)but;
SWAP(uiViewItemHandle *, view_item_newbut->view_item, view_item_oldbut->view_item);
break;
}
default:
@ -1013,7 +998,7 @@ static bool ui_but_update_from_old_block(const bContext *C,
/* Stupid special case: The active button may be inside (as in, overlapped on top) a view-item
* button which we also want to keep highlighted then. */
if (ui_but_is_view_item(but)) {
if (but->type == UI_BTYPE_VIEW_ITEM) {
flag_copy |= UI_ACTIVE;
}
@ -2245,21 +2230,12 @@ int ui_but_is_pushed_ex(uiBut *but, double *value)
}
}
break;
case UI_BTYPE_TREEROW: {
uiButTreeRow *tree_row_but = (uiButTreeRow *)but;
case UI_BTYPE_VIEW_ITEM: {
const uiButViewItem *view_item_but = (const uiButViewItem *)but;
is_push = -1;
if (tree_row_but->tree_item) {
is_push = UI_tree_view_item_is_active(tree_row_but->tree_item);
}
break;
}
case UI_BTYPE_GRID_TILE: {
uiButGridTile *grid_tile_but = (uiButGridTile *)but;
is_push = -1;
if (grid_tile_but->view_item) {
is_push = UI_grid_view_item_is_active(grid_tile_but->view_item);
if (view_item_but->view_item) {
is_push = UI_view_item_is_active(view_item_but->view_item);
}
break;
}
@ -4011,17 +3987,13 @@ static void ui_but_alloc_info(const eButType type,
alloc_size = sizeof(uiButCurveProfile);
alloc_str = "uiButCurveProfile";
break;
case UI_BTYPE_TREEROW:
alloc_size = sizeof(uiButTreeRow);
alloc_str = "uiButTreeRow";
break;
case UI_BTYPE_HOTKEY_EVENT:
alloc_size = sizeof(uiButHotkeyEvent);
alloc_str = "uiButHotkeyEvent";
break;
case UI_BTYPE_GRID_TILE:
alloc_size = sizeof(uiButGridTile);
alloc_str = "uiButGridTile";
case UI_BTYPE_VIEW_ITEM:
alloc_size = sizeof(uiButViewItem);
alloc_str = "uiButViewItem";
break;
default:
alloc_size = sizeof(uiBut);
@ -4214,7 +4186,6 @@ static uiBut *ui_def_but(uiBlock *block,
UI_BTYPE_BLOCK,
UI_BTYPE_BUT_MENU,
UI_BTYPE_SEARCH_MENU,
UI_BTYPE_TREEROW,
UI_BTYPE_POPOVER)) {
but->drawflag |= (UI_BUT_TEXT_LEFT | UI_BUT_ICON_LEFT);
}
@ -6469,15 +6440,6 @@ uiBut *uiDefSearchButO_ptr(uiBlock *block,
return but;
}
void UI_but_treerow_indentation_set(uiBut *but, int indentation)
{
uiButTreeRow *but_row = (uiButTreeRow *)but;
BLI_assert(but->type == UI_BTYPE_TREEROW);
but_row->indentation = indentation;
BLI_assert(indentation >= 0);
}
void UI_but_hint_drawstr_set(uiBut *but, const char *string)
{
ui_but_add_shortcut(but, string, false);

View File

@ -927,11 +927,11 @@ bool ui_popup_context_menu_for_button(bContext *C, uiBut *but, const wmEvent *ev
{
const ARegion *region = CTX_wm_menu(C) ? CTX_wm_menu(C) : CTX_wm_region(C);
uiButTreeRow *treerow_but = (uiButTreeRow *)ui_tree_row_find_mouse_over(region, event->xy);
if (treerow_but) {
BLI_assert(treerow_but->but.type == UI_BTYPE_TREEROW);
UI_tree_view_item_context_menu_build(
C, treerow_but->tree_item, uiLayoutColumn(layout, false));
uiButViewItem *view_item_but = (uiButViewItem *)ui_view_item_find_mouse_over(region,
event->xy);
if (view_item_but) {
BLI_assert(view_item_but->but.type == UI_BTYPE_VIEW_ITEM);
UI_view_item_context_menu_build(C, view_item_but->view_item, uiLayoutColumn(layout, false));
uiItemS(layout);
}
}

View File

@ -22,15 +22,14 @@
#include "UI_interface.h"
/* -------------------------------------------------------------------- */
/** \name Tree View Drag/Drop Callbacks
/** \name View Drag/Drop Callbacks
* \{ */
static bool ui_tree_view_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event)
static bool ui_view_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event)
{
const ARegion *region = CTX_wm_region(C);
const uiTreeViewItemHandle *hovered_tree_item = UI_block_tree_view_find_item_at(region,
event->xy);
if (!hovered_tree_item) {
const uiViewItemHandle *hovered_item = UI_block_view_find_item_at(region, event->xy);
if (!hovered_item) {
return false;
}
@ -39,21 +38,21 @@ static bool ui_tree_view_drop_poll(bContext *C, wmDrag *drag, const wmEvent *eve
}
drag->drop_state.free_disabled_info = false;
return UI_tree_view_item_can_drop(hovered_tree_item, drag, &drag->drop_state.disabled_info);
return UI_view_item_can_drop(hovered_item, drag, &drag->drop_state.disabled_info);
}
static char *ui_tree_view_drop_tooltip(bContext *C,
wmDrag *drag,
const int xy[2],
wmDropBox *UNUSED(drop))
static char *ui_view_drop_tooltip(bContext *C,
wmDrag *drag,
const int xy[2],
wmDropBox *UNUSED(drop))
{
const ARegion *region = CTX_wm_region(C);
const uiTreeViewItemHandle *hovered_tree_item = UI_block_tree_view_find_item_at(region, xy);
if (!hovered_tree_item) {
const uiViewItemHandle *hovered_item = UI_block_view_find_item_at(region, xy);
if (!hovered_item) {
return nullptr;
}
return UI_tree_view_item_drop_tooltip(hovered_tree_item, drag);
return UI_view_item_drop_tooltip(hovered_item, drag);
}
/** \} */
@ -140,12 +139,7 @@ void ED_dropboxes_ui()
{
ListBase *lb = WM_dropboxmap_find("User Interface", SPACE_EMPTY, 0);
WM_dropbox_add(lb,
"UI_OT_tree_view_drop",
ui_tree_view_drop_poll,
nullptr,
nullptr,
ui_tree_view_drop_tooltip);
WM_dropbox_add(lb, "UI_OT_view_drop", ui_view_drop_poll, nullptr, nullptr, ui_view_drop_tooltip);
WM_dropbox_add(lb,
"UI_OT_drop_name",
ui_drop_name_poll,

View File

@ -1151,7 +1151,10 @@ static void ui_apply_but_ROW(bContext *C, uiBlock *block, uiBut *but, uiHandleBu
data->applied = true;
}
static void ui_apply_but_TREEROW(bContext *C, uiBlock *block, uiBut *but, uiHandleButtonData *data)
static void ui_apply_but_VIEW_ITEM(bContext *C,
uiBlock *block,
uiBut *but,
uiHandleButtonData *data)
{
if (data->apply_through_extra_icon) {
/* Don't apply this, it would cause unintended tree-row toggling when clicking on extra icons.
@ -2128,10 +2131,10 @@ static bool ui_but_drag_init(bContext *C,
return false;
}
}
else if (but->type == UI_BTYPE_TREEROW) {
uiButTreeRow *tree_row_but = (uiButTreeRow *)but;
if (tree_row_but->tree_item) {
UI_tree_view_item_drag_start(C, tree_row_but->tree_item);
else if (but->type == UI_BTYPE_VIEW_ITEM) {
const uiButViewItem *view_item_but = (uiButViewItem *)but;
if (view_item_but->view_item) {
UI_view_item_drag_start(C, view_item_but->view_item);
}
}
else {
@ -2289,11 +2292,8 @@ static void ui_apply_but(
case UI_BTYPE_ROW:
ui_apply_but_ROW(C, block, but, data);
break;
case UI_BTYPE_GRID_TILE:
ui_apply_but_ROW(C, block, but, data);
break;
case UI_BTYPE_TREEROW:
ui_apply_but_TREEROW(C, block, but, data);
case UI_BTYPE_VIEW_ITEM:
ui_apply_but_VIEW_ITEM(C, block, but, data);
break;
case UI_BTYPE_LISTROW:
ui_apply_but_LISTROW(C, block, but, data);
@ -4764,13 +4764,13 @@ static int ui_do_but_TOG(bContext *C, uiBut *but, uiHandleButtonData *data, cons
return WM_UI_HANDLER_CONTINUE;
}
static int ui_do_but_TREEROW(bContext *C,
uiBut *but,
uiHandleButtonData *data,
const wmEvent *event)
static int ui_do_but_VIEW_ITEM(bContext *C,
uiBut *but,
uiHandleButtonData *data,
const wmEvent *event)
{
uiButTreeRow *tree_row_but = (uiButTreeRow *)but;
BLI_assert(tree_row_but->but.type == UI_BTYPE_TREEROW);
uiButViewItem *view_item_but = (uiButViewItem *)but;
BLI_assert(view_item_but->but.type == UI_BTYPE_VIEW_ITEM);
if (data->state == BUTTON_STATE_HIGHLIGHT) {
if (event->type == LEFTMOUSE) {
@ -4791,48 +4791,7 @@ static int ui_do_but_TREEROW(bContext *C,
case KM_DBL_CLICK:
data->cancel = true;
UI_tree_view_item_begin_rename(tree_row_but->tree_item);
ED_region_tag_redraw(CTX_wm_region(C));
return WM_UI_HANDLER_BREAK;
}
}
}
else if (data->state == BUTTON_STATE_WAIT_DRAG) {
/* Let "default" button handling take care of the drag logic. */
return ui_do_but_EXIT(C, but, data, event);
}
return WM_UI_HANDLER_CONTINUE;
}
static int ui_do_but_GRIDTILE(bContext *C,
uiBut *but,
uiHandleButtonData *data,
const wmEvent *event)
{
BLI_assert(but->type == UI_BTYPE_GRID_TILE);
if (data->state == BUTTON_STATE_HIGHLIGHT) {
if (event->type == LEFTMOUSE) {
switch (event->val) {
case KM_PRESS:
/* Extra icons have priority, don't mess with them. */
if (ui_but_extra_operator_icon_mouse_over_get(but, data->region, event)) {
return WM_UI_HANDLER_BREAK;
}
button_activate_state(C, but, BUTTON_STATE_WAIT_DRAG);
data->dragstartx = event->xy[0];
data->dragstarty = event->xy[1];
return WM_UI_HANDLER_CONTINUE;
case KM_CLICK:
button_activate_state(C, but, BUTTON_STATE_EXIT);
return WM_UI_HANDLER_BREAK;
case KM_DBL_CLICK:
data->cancel = true;
// uiButGridTile *grid_tile_but = (uiButGridTile *)but;
// UI_tree_view_item_begin_rename(grid_tile_but->tree_item);
UI_view_item_begin_rename(view_item_but->view_item);
ED_region_tag_redraw(CTX_wm_region(C));
return WM_UI_HANDLER_BREAK;
}
@ -7980,7 +7939,7 @@ static int ui_do_button(bContext *C, uiBlock *block, uiBut *but, const wmEvent *
* to spawn the context menu should also activate the item. This makes it clear which item
* will be operated on.
* Apply the button immediately, so context menu polls get the right active item. */
if (ELEM(but->type, UI_BTYPE_TREEROW)) {
if (ELEM(but->type, UI_BTYPE_VIEW_ITEM)) {
ui_apply_but(C, but->block, but, but->active, true);
}
@ -8045,11 +8004,8 @@ static int ui_do_button(bContext *C, uiBlock *block, uiBut *but, const wmEvent *
case UI_BTYPE_ROW:
retval = ui_do_but_TOG(C, but, data, event);
break;
case UI_BTYPE_GRID_TILE:
retval = ui_do_but_GRIDTILE(C, but, data, event);
break;
case UI_BTYPE_TREEROW:
retval = ui_do_but_TREEROW(C, but, data, event);
case UI_BTYPE_VIEW_ITEM:
retval = ui_do_but_VIEW_ITEM(C, but, data, event);
break;
case UI_BTYPE_SCROLL:
retval = ui_do_but_SCROLL(C, block, but, data, event);
@ -9725,7 +9681,7 @@ static int ui_handle_view_items_hover(const wmEvent *event, const ARegion *regio
}
LISTBASE_FOREACH (uiBut *, but, &block->buttons) {
if (ui_but_is_view_item(but)) {
if (but->type == UI_BTYPE_VIEW_ITEM) {
but->flag &= ~UI_ACTIVE;
has_view_item = true;
}
@ -9752,7 +9708,7 @@ static int ui_handle_view_item_event(bContext *C,
ARegion *region,
uiBut *view_but)
{
BLI_assert(ui_but_is_view_item(view_but));
BLI_assert(view_but->type == UI_BTYPE_VIEW_ITEM);
if (event->type == LEFTMOUSE) {
/* Will free active button if there already is one. */
ui_handle_button_activate(C, region, view_but, BUTTON_ACTIVATE_OVER);

View File

@ -343,20 +343,12 @@ typedef struct uiButProgressbar {
float progress;
} uiButProgressbar;
/** Derived struct for #UI_BTYPE_TREEROW. */
typedef struct uiButTreeRow {
typedef struct uiButViewItem {
uiBut but;
uiTreeViewItemHandle *tree_item;
int indentation;
} uiButTreeRow;
/** Derived struct for #UI_BTYPE_GRID_TILE. */
typedef struct uiButGridTile {
uiBut but;
uiGridViewItemHandle *view_item;
} uiButGridTile;
/* C-Handle to the view item this button was created for. */
uiViewItemHandle *view_item;
} uiButViewItem;
/** Derived struct for #UI_BTYPE_HSVCUBE. */
typedef struct uiButHSVCube {
@ -1372,7 +1364,6 @@ void ui_but_anim_decorate_update_from_flag(uiButDecorator *but);
bool ui_but_is_editable(const uiBut *but) ATTR_WARN_UNUSED_RESULT;
bool ui_but_is_editable_as_text(const uiBut *but) ATTR_WARN_UNUSED_RESULT;
bool ui_but_is_toggle(const uiBut *but) ATTR_WARN_UNUSED_RESULT;
bool ui_but_is_view_item(const uiBut *but) ATTR_WARN_UNUSED_RESULT;
/**
* Can we mouse over the button or is it hidden/disabled/layout.
* \note ctrl is kind of a hack currently,
@ -1406,9 +1397,7 @@ uiBut *ui_list_row_find_from_index(const struct ARegion *region,
uiBut *listbox) ATTR_WARN_UNUSED_RESULT;
uiBut *ui_view_item_find_mouse_over(const struct ARegion *region, const int xy[2])
ATTR_NONNULL(1, 2);
uiBut *ui_tree_row_find_mouse_over(const struct ARegion *region, const int xy[2])
ATTR_NONNULL(1, 2);
uiBut *ui_tree_row_find_active(const struct ARegion *region);
uiBut *ui_view_item_find_active(const struct ARegion *region);
typedef bool (*uiButFindPollFn)(const uiBut *but, const void *customdata);
/**
@ -1546,8 +1535,8 @@ void ui_block_free_views(struct uiBlock *block);
uiViewHandle *ui_block_view_find_matching_in_old_block(const uiBlock *new_block,
const uiViewHandle *new_view);
uiButTreeRow *ui_block_view_find_treerow_in_old_block(const uiBlock *new_block,
const uiTreeViewItemHandle *new_item_handle);
uiButViewItem *ui_block_view_find_matching_view_item_but_in_old_block(
const uiBlock *new_block, const uiViewItemHandle *new_item_handle);
/* interface_templates.c */

View File

@ -2054,40 +2054,39 @@ static void UI_OT_list_start_filter(wmOperatorType *ot)
/** \name UI Tree-View Drop Operator
* \{ */
static bool ui_tree_view_drop_poll(bContext *C)
static bool ui_view_drop_poll(bContext *C)
{
const wmWindow *win = CTX_wm_window(C);
const ARegion *region = CTX_wm_region(C);
const uiTreeViewItemHandle *hovered_tree_item = UI_block_tree_view_find_item_at(
region, win->eventstate->xy);
const uiViewItemHandle *hovered_item = UI_block_view_find_item_at(region, win->eventstate->xy);
return hovered_tree_item != NULL;
return hovered_item != NULL;
}
static int ui_tree_view_drop_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *event)
static int ui_view_drop_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *event)
{
if (event->custom != EVT_DATA_DRAGDROP) {
return OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH;
}
const ARegion *region = CTX_wm_region(C);
uiTreeViewItemHandle *hovered_tree_item = UI_block_tree_view_find_item_at(region, event->xy);
uiViewItemHandle *hovered_item = UI_block_view_find_item_at(region, event->xy);
if (!UI_tree_view_item_drop_handle(C, hovered_tree_item, event->customdata)) {
if (!UI_view_item_drop_handle(C, hovered_item, event->customdata)) {
return OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH;
}
return OPERATOR_FINISHED;
}
static void UI_OT_tree_view_drop(wmOperatorType *ot)
static void UI_OT_view_drop(wmOperatorType *ot)
{
ot->name = "Tree View drop";
ot->idname = "UI_OT_tree_view_drop";
ot->description = "Drag and drop items onto a tree item";
ot->name = "View drop";
ot->idname = "UI_OT_view_drop";
ot->description = "Drag and drop items onto a data-set item";
ot->invoke = ui_tree_view_drop_invoke;
ot->poll = ui_tree_view_drop_poll;
ot->invoke = ui_view_drop_invoke;
ot->poll = ui_view_drop_poll;
ot->flag = OPTYPE_INTERNAL;
}
@ -2095,43 +2094,42 @@ static void UI_OT_tree_view_drop(wmOperatorType *ot)
/** \} */
/* -------------------------------------------------------------------- */
/** \name UI Tree-View Item Rename Operator
/** \name UI View Item Rename Operator
*
* General purpose renaming operator for tree-views. Thanks to this, to add a rename button to
* context menus for example, tree-view API users don't have to implement their own renaming
* operators with the same logic as they already have for their #ui::AbstractTreeViewItem::rename()
* override.
* General purpose renaming operator for views. Thanks to this, to add a rename button to context
* menus for example, view API users don't have to implement their own renaming operators with the
* same logic as they already have for their #ui::AbstractViewItem::rename() override.
*
* \{ */
static bool ui_tree_view_item_rename_poll(bContext *C)
static bool ui_view_item_rename_poll(bContext *C)
{
const ARegion *region = CTX_wm_region(C);
const uiTreeViewItemHandle *active_item = UI_block_tree_view_find_active_item(region);
return active_item != NULL && UI_tree_view_item_can_rename(active_item);
const uiViewItemHandle *active_item = UI_block_view_find_active_item(region);
return active_item != NULL && UI_view_item_can_rename(active_item);
}
static int ui_tree_view_item_rename_exec(bContext *C, wmOperator *UNUSED(op))
static int ui_view_item_rename_exec(bContext *C, wmOperator *UNUSED(op))
{
ARegion *region = CTX_wm_region(C);
uiTreeViewItemHandle *active_item = UI_block_tree_view_find_active_item(region);
uiViewItemHandle *active_item = UI_block_view_find_active_item(region);
UI_tree_view_item_begin_rename(active_item);
UI_view_item_begin_rename(active_item);
ED_region_tag_redraw(region);
return OPERATOR_FINISHED;
}
static void UI_OT_tree_view_item_rename(wmOperatorType *ot)
static void UI_OT_view_item_rename(wmOperatorType *ot)
{
ot->name = "Rename Tree-View Item";
ot->idname = "UI_OT_tree_view_item_rename";
ot->description = "Rename the active item in the tree";
ot->name = "Rename View Item";
ot->idname = "UI_OT_view_item_rename";
ot->description = "Rename the active item in the data-set view";
ot->exec = ui_tree_view_item_rename_exec;
ot->poll = ui_tree_view_item_rename_poll;
ot->exec = ui_view_item_rename_exec;
ot->poll = ui_view_item_rename_poll;
/* Could get a custom tooltip via the `get_description()` callback and another overridable
* function of the tree-view. */
* function of the view. */
ot->flag = OPTYPE_INTERNAL;
}
@ -2235,8 +2233,8 @@ void ED_operatortypes_ui(void)
WM_operatortype_append(UI_OT_list_start_filter);
WM_operatortype_append(UI_OT_tree_view_drop);
WM_operatortype_append(UI_OT_tree_view_item_rename);
WM_operatortype_append(UI_OT_view_drop);
WM_operatortype_append(UI_OT_view_item_rename);
/* external */
WM_operatortype_append(UI_OT_eyedropper_color);

View File

@ -54,13 +54,7 @@ bool ui_but_is_toggle(const uiBut *but)
UI_BTYPE_TOGGLE_N,
UI_BTYPE_CHECKBOX,
UI_BTYPE_CHECKBOX_N,
UI_BTYPE_ROW,
UI_BTYPE_TREEROW);
}
bool ui_but_is_view_item(const uiBut *but)
{
return ELEM(but->type, UI_BTYPE_TREEROW, UI_BTYPE_GRID_TILE);
UI_BTYPE_ROW);
}
bool ui_but_is_interactive_ex(const uiBut *but, const bool labeledit, const bool for_tooltip)
@ -462,14 +456,9 @@ uiBut *ui_list_row_find_from_index(const ARegion *region, const int index, uiBut
return ui_but_find(region, ui_but_is_listrow_at_index, &data);
}
static bool ui_but_is_treerow(const uiBut *but, const void *UNUSED(customdata))
{
return but->type == UI_BTYPE_TREEROW;
}
static bool ui_but_is_view_item_fn(const uiBut *but, const void *UNUSED(customdata))
{
return ui_but_is_view_item(but);
return but->type == UI_BTYPE_VIEW_ITEM;
}
uiBut *ui_view_item_find_mouse_over(const ARegion *region, const int xy[2])
@ -477,24 +466,19 @@ uiBut *ui_view_item_find_mouse_over(const ARegion *region, const int xy[2])
return ui_but_find_mouse_over_ex(region, xy, false, false, ui_but_is_view_item_fn, nullptr);
}
uiBut *ui_tree_row_find_mouse_over(const ARegion *region, const int xy[2])
static bool ui_but_is_active_view_item(const uiBut *but, const void *UNUSED(customdata))
{
return ui_but_find_mouse_over_ex(region, xy, false, false, ui_but_is_treerow, nullptr);
}
static bool ui_but_is_active_treerow(const uiBut *but, const void *customdata)
{
if (!ui_but_is_treerow(but, customdata)) {
if (but->type != UI_BTYPE_VIEW_ITEM) {
return false;
}
const uiButTreeRow *treerow_but = (const uiButTreeRow *)but;
return UI_tree_view_item_is_active(treerow_but->tree_item);
const uiButViewItem *view_item_but = (const uiButViewItem *)but;
return UI_view_item_is_active(view_item_but->view_item);
}
uiBut *ui_tree_row_find_active(const ARegion *region)
uiBut *ui_view_item_find_active(const ARegion *region)
{
return ui_but_find(region, ui_but_is_active_treerow, nullptr);
return ui_but_find(region, ui_but_is_active_view_item, nullptr);
}
/** \} */

View File

@ -86,24 +86,24 @@ void UI_block_views_listen(const uiBlock *block, const wmRegionListenerParams *l
}
}
uiTreeViewItemHandle *UI_block_tree_view_find_item_at(const ARegion *region, const int xy[2])
uiViewItemHandle *UI_block_view_find_item_at(const ARegion *region, const int xy[2])
{
uiButTreeRow *tree_row_but = (uiButTreeRow *)ui_tree_row_find_mouse_over(region, xy);
if (!tree_row_but) {
uiButViewItem *item_but = (uiButViewItem *)ui_view_item_find_mouse_over(region, xy);
if (!item_but) {
return nullptr;
}
return tree_row_but->tree_item;
return item_but->view_item;
}
uiTreeViewItemHandle *UI_block_tree_view_find_active_item(const ARegion *region)
uiViewItemHandle *UI_block_view_find_active_item(const ARegion *region)
{
uiButTreeRow *tree_row_but = (uiButTreeRow *)ui_tree_row_find_active(region);
if (!tree_row_but) {
uiButViewItem *item_but = (uiButViewItem *)ui_view_item_find_active(region);
if (!item_but) {
return nullptr;
}
return tree_row_but->tree_item;
return item_but->view_item;
}
static StringRef ui_block_view_find_idname(const uiBlock &block, const AbstractView &view)
@ -151,39 +151,38 @@ uiViewHandle *ui_block_view_find_matching_in_old_block(const uiBlock *new_block,
return reinterpret_cast<uiViewHandle *>(old_view);
}
uiButTreeRow *ui_block_view_find_treerow_in_old_block(const uiBlock *new_block,
const uiTreeViewItemHandle *new_item_handle)
uiButViewItem *ui_block_view_find_matching_view_item_but_in_old_block(
const uiBlock *new_block, const uiViewItemHandle *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 AbstractViewItem &new_item = *reinterpret_cast<const AbstractViewItem *>(new_item_handle);
const AbstractView *old_view = ui_block_view_find_matching_in_old_block_impl(
*new_block, new_item.get_tree_view());
*new_block, new_item.get_view());
if (!old_view) {
return nullptr;
}
LISTBASE_FOREACH (uiBut *, old_but, &old_block->buttons) {
if (old_but->type != UI_BTYPE_TREEROW) {
if (old_but->type != UI_BTYPE_VIEW_ITEM) {
continue;
}
uiButTreeRow *old_treerow_but = (uiButTreeRow *)old_but;
if (!old_treerow_but->tree_item) {
uiButViewItem *old_item_but = (uiButViewItem *)old_but;
if (!old_item_but->view_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_view) {
AbstractViewItem &old_item = *reinterpret_cast<AbstractViewItem *>(old_item_but->view_item);
/* Check if the item is from the expected view. */
if (&old_item.get_view() != old_view) {
continue;
}
if (UI_tree_view_item_matches(new_item_handle, old_treerow_but->tree_item)) {
return old_treerow_but;
if (UI_view_item_matches(reinterpret_cast<const uiViewItemHandle *>(&new_item),
reinterpret_cast<const uiViewItemHandle *>(&old_item))) {
return old_item_but;
}
}

View File

@ -104,8 +104,7 @@ typedef enum {
UI_WTYPE_LISTITEM,
UI_WTYPE_PROGRESSBAR,
UI_WTYPE_NODESOCKET,
UI_WTYPE_TREEROW,
UI_WTYPE_GRID_TILE,
UI_WTYPE_VIEW_ITEM,
} uiWidgetTypeEnum;
/**
@ -3672,12 +3671,11 @@ static void widget_progressbar(uiBut *but,
widgetbase_draw(&wtb_bar, wcol);
}
static void widget_treerow_exec(uiWidgetColors *wcol,
rcti *rect,
const uiWidgetStateInfo *state,
int UNUSED(roundboxalign),
int indentation,
const float zoom)
static void widget_view_item(uiWidgetColors *wcol,
rcti *rect,
const uiWidgetStateInfo *state,
int UNUSED(roundboxalign),
const float zoom)
{
uiWidgetBase wtb;
widget_init(&wtb);
@ -3690,31 +3688,6 @@ static void widget_treerow_exec(uiWidgetColors *wcol,
if ((state->but_flag & UI_ACTIVE) || (state->but_flag & UI_SELECT)) {
widgetbase_draw(&wtb, wcol);
}
BLI_rcti_resize(rect, BLI_rcti_size_x(rect) - UI_UNIT_X * indentation, BLI_rcti_size_y(rect));
BLI_rcti_translate(rect, 0.5f * UI_UNIT_X * indentation, 0);
}
static void widget_treerow(uiBut *but,
uiWidgetColors *wcol,
rcti *rect,
const uiWidgetStateInfo *state,
int roundboxalign,
const float zoom)
{
uiButTreeRow *tree_row = (uiButTreeRow *)but;
BLI_assert(but->type == UI_BTYPE_TREEROW);
widget_treerow_exec(wcol, rect, state, roundboxalign, tree_row->indentation, zoom);
}
static void widget_gridtile(uiWidgetColors *wcol,
rcti *rect,
const uiWidgetStateInfo *state,
int roundboxalign,
const float zoom)
{
/* TODO Reuse tree-row drawing. */
widget_treerow_exec(wcol, rect, state, roundboxalign, 0, zoom);
}
static void widget_nodesocket(uiBut *but,
@ -4608,14 +4581,9 @@ static uiWidgetType *widget_type(uiWidgetTypeEnum type)
wt.custom = widget_progressbar;
break;
case UI_WTYPE_TREEROW:
case UI_WTYPE_VIEW_ITEM:
wt.wcol_theme = &btheme->tui.wcol_view_item;
wt.custom = widget_treerow;
break;
case UI_WTYPE_GRID_TILE:
wt.wcol_theme = &btheme->tui.wcol_view_item;
wt.draw = widget_gridtile;
wt.draw = widget_view_item;
break;
case UI_WTYPE_NODESOCKET:
@ -4949,13 +4917,8 @@ void ui_draw_but(const bContext *C, struct ARegion *region, uiStyle *style, uiBu
fstyle = &style->widgetlabel;
break;
case UI_BTYPE_TREEROW:
wt = widget_type(UI_WTYPE_TREEROW);
fstyle = &style->widgetlabel;
break;
case UI_BTYPE_GRID_TILE:
wt = widget_type(UI_WTYPE_GRID_TILE);
case UI_BTYPE_VIEW_ITEM:
wt = widget_type(UI_WTYPE_VIEW_ITEM);
fstyle = &style->widgetlabel;
break;

View File

@ -37,9 +37,11 @@ AbstractTreeViewItem &TreeViewItemContainer::add_tree_item(
if (root_ == nullptr) {
root_ = this;
}
AbstractTreeView &tree_view = static_cast<AbstractTreeView &>(*root_);
AbstractTreeViewItem &added_item = *children_.last();
added_item.root_ = root_;
tree_view.register_item(added_item);
if (root_ != this) {
/* Any item that isn't the root can be assumed to the a #AbstractTreeViewItem. Not entirely
* nice to static_cast this, but well... */
@ -95,7 +97,7 @@ AbstractTreeViewItem *AbstractTreeView::find_matching_child(
const AbstractTreeViewItem &lookup_item, const TreeViewOrItem &items)
{
for (const auto &iter_item : items.children_) {
if (lookup_item.matches(*iter_item)) {
if (lookup_item.matches_single(*iter_item)) {
/* We have a matching item! */
return iter_item.get();
}
@ -118,9 +120,8 @@ void AbstractTreeViewItem::tree_row_click_fn(struct bContext * /*C*/,
void *but_arg1,
void * /*arg2*/)
{
uiButTreeRow *tree_row_but = (uiButTreeRow *)but_arg1;
AbstractTreeViewItem &tree_item = reinterpret_cast<AbstractTreeViewItem &>(
*tree_row_but->tree_item);
uiButViewItem *item_but = (uiButViewItem *)but_arg1;
AbstractTreeViewItem &tree_item = reinterpret_cast<AbstractTreeViewItem &>(*item_but->view_item);
tree_item.activate();
/* Not only activate the item, also show its children. Maybe this should be optional, or
@ -131,11 +132,11 @@ void AbstractTreeViewItem::tree_row_click_fn(struct bContext * /*C*/,
void AbstractTreeViewItem::add_treerow_button(uiBlock &block)
{
/* For some reason a width > (UI_UNIT_X * 2) make the layout system use all available width. */
tree_row_but_ = (uiButTreeRow *)uiDefBut(
&block, UI_BTYPE_TREEROW, 0, "", 0, 0, UI_UNIT_X * 10, UI_UNIT_Y, nullptr, 0, 0, 0, 0, "");
view_item_but_ = (uiButViewItem *)uiDefBut(
&block, UI_BTYPE_VIEW_ITEM, 0, "", 0, 0, UI_UNIT_X * 10, UI_UNIT_Y, nullptr, 0, 0, 0, 0, "");
tree_row_but_->tree_item = reinterpret_cast<uiTreeViewItemHandle *>(this);
UI_but_func_set(&tree_row_but_->but, tree_row_click_fn, tree_row_but_, nullptr);
view_item_but_->view_item = reinterpret_cast<uiViewItemHandle *>(this);
UI_but_func_set(&view_item_but_->but, tree_row_click_fn, view_item_but_, nullptr);
}
void AbstractTreeViewItem::add_indent(uiLayout &row) const
@ -167,10 +168,9 @@ void AbstractTreeViewItem::collapse_chevron_click_fn(struct bContext *C,
const wmWindow *win = CTX_wm_window(C);
const ARegion *region = CTX_wm_region(C);
uiTreeViewItemHandle *hovered_item_handle = UI_block_tree_view_find_item_at(region,
win->eventstate->xy);
AbstractTreeViewItem *hovered_item = reinterpret_cast<AbstractTreeViewItem *>(
hovered_item_handle);
uiViewItemHandle *hovered_item_handle = UI_block_view_find_item_at(region, win->eventstate->xy);
AbstractTreeViewItem *hovered_item = from_item_handle<AbstractTreeViewItem>(hovered_item_handle);
BLI_assert(hovered_item != nullptr);
hovered_item->toggle_collapsed();
@ -204,40 +204,6 @@ void AbstractTreeViewItem::add_collapse_chevron(uiBlock &block) const
BLI_assert(is_collapse_chevron_but(but));
}
AbstractTreeViewItem *AbstractTreeViewItem::find_tree_item_from_rename_button(
const uiBut &rename_but)
{
/* A minimal sanity check, can't do much more here. */
BLI_assert(rename_but.type == UI_BTYPE_TEXT && rename_but.poin);
LISTBASE_FOREACH (uiBut *, but, &rename_but.block->buttons) {
if (but->type != UI_BTYPE_TREEROW) {
continue;
}
uiButTreeRow *tree_row_but = (uiButTreeRow *)but;
AbstractTreeViewItem *item = reinterpret_cast<AbstractTreeViewItem *>(tree_row_but->tree_item);
const AbstractTreeView &tree_view = item->get_tree_view();
if (item->is_renaming() && (tree_view.get_rename_buffer().data() == rename_but.poin)) {
return item;
}
}
return nullptr;
}
void AbstractTreeViewItem::rename_button_fn(bContext *UNUSED(C), void *arg, char *UNUSED(origstr))
{
const uiBut *rename_but = static_cast<uiBut *>(arg);
AbstractTreeViewItem *item = find_tree_item_from_rename_button(*rename_but);
BLI_assert(item);
const AbstractTreeView &tree_view = item->get_tree_view();
item->rename(tree_view.get_rename_buffer().data());
item->end_renaming();
}
void AbstractTreeViewItem::add_rename_button(uiLayout &row)
{
uiBlock *block = uiLayoutGetBlock(&row);
@ -247,33 +213,7 @@ void AbstractTreeViewItem::add_rename_button(uiLayout &row)
/* Enable emboss for the text button. */
UI_block_emboss_set(block, UI_EMBOSS);
AbstractTreeView &tree_view = get_tree_view();
uiBut *rename_but = uiDefBut(block,
UI_BTYPE_TEXT,
1,
"",
0,
0,
UI_UNIT_X * 10,
UI_UNIT_Y,
tree_view.get_rename_buffer().data(),
1.0f,
tree_view.get_rename_buffer().size(),
0,
0,
"");
/* Gotta be careful with what's passed to the `arg1` here. Any tree data will be freed once the
* callback is executed. */
UI_but_func_rename_set(rename_but, AbstractTreeViewItem::rename_button_fn, rename_but);
UI_but_flag_disable(rename_but, UI_BUT_UNDO);
const bContext *evil_C = static_cast<bContext *>(block->evil_C);
ARegion *region = CTX_wm_region(evil_C);
/* Returns false if the button was removed. */
if (UI_but_active_only(evil_C, region, block, rename_but) == false) {
end_renaming();
}
AbstractViewItem::add_rename_button(*block);
UI_block_emboss_set(block, previous_emboss);
UI_block_layout_set_current(block, &row);
@ -306,82 +246,35 @@ bool AbstractTreeViewItem::supports_collapsing() const
return true;
}
std::unique_ptr<AbstractTreeViewItemDragController> AbstractTreeViewItem::create_drag_controller()
const
StringRef AbstractTreeViewItem::get_rename_string() const
{
/* There's no drag controller (and hence no drag support) by default. */
return nullptr;
}
std::unique_ptr<AbstractTreeViewItemDropController> AbstractTreeViewItem::create_drop_controller()
const
{
/* There's no drop controller (and hence no drop support) by default. */
return nullptr;
}
bool AbstractTreeViewItem::supports_renaming() const
{
/* No renaming by default. */
return false;
return label_;
}
bool AbstractTreeViewItem::rename(StringRefNull new_name)
{
/* It is important to update the label after renaming, so #AbstractTreeViewItem::matches()
/* It is important to update the label after renaming, so #AbstractTreeViewItem::matches_single()
* recognizes the item. (It only compares labels by default.) */
label_ = new_name;
return true;
}
void AbstractTreeViewItem::build_context_menu(bContext & /*C*/, uiLayout & /*column*/) const
{
/* No context menu by default. */
}
void AbstractTreeViewItem::update_from_old(const AbstractViewItem &old)
{
AbstractViewItem::update_from_old(old);
const AbstractTreeViewItem &old_tree_item = dynamic_cast<const AbstractTreeViewItem &>(old);
is_open_ = old_tree_item.is_open_;
is_renaming_ = old_tree_item.is_renaming_;
}
bool AbstractTreeViewItem::matches(const AbstractTreeViewItem &other) const
bool AbstractTreeViewItem::matches_single(const AbstractTreeViewItem &other) const
{
return label_ == other.label_;
}
void AbstractTreeViewItem::begin_renaming()
{
AbstractTreeView &tree_view = get_tree_view();
if (tree_view.is_renaming() || !supports_renaming()) {
return;
}
if (tree_view.begin_renaming()) {
is_renaming_ = true;
}
std::copy(std::begin(label_), std::end(label_), std::begin(tree_view.get_rename_buffer()));
}
void AbstractTreeViewItem::end_renaming()
{
if (!is_renaming()) {
return;
}
is_renaming_ = false;
AbstractTreeView &tree_view = get_tree_view();
tree_view.end_renaming();
}
AbstractTreeView &AbstractTreeViewItem::get_tree_view() const
{
return static_cast<AbstractTreeView &>(*root_);
return dynamic_cast<AbstractTreeView &>(get_view());
}
int AbstractTreeViewItem::count_parents() const
@ -417,26 +310,19 @@ void AbstractTreeViewItem::deactivate()
is_active_ = false;
}
bool AbstractTreeViewItem::is_active() const
{
BLI_assert_msg(get_tree_view().is_reconstructed(),
"State can't be queried until reconstruction is completed");
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,
BLI_assert_msg(view_item_but_ != nullptr,
"Hovered state can't be queried before the tree row is being built");
const uiTreeViewItemHandle *this_handle = reinterpret_cast<const uiTreeViewItemHandle *>(this);
const uiViewItemHandle *this_item_handle = reinterpret_cast<const uiViewItemHandle *>(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);
uiButViewItem *old_item_but = ui_block_view_find_matching_view_item_but_in_old_block(
view_item_but_->but.block, this_item_handle);
return old_item_but && (old_item_but->but.flag & UI_ACTIVE);
}
bool AbstractTreeViewItem::is_collapsed() const
@ -464,11 +350,6 @@ bool AbstractTreeViewItem::is_collapsible() const
return this->supports_collapsing();
}
bool AbstractTreeViewItem::is_renaming() const
{
return is_renaming_;
}
void AbstractTreeViewItem::ensure_parents_uncollapsed()
{
for (AbstractTreeViewItem *parent = parent_; parent; parent = parent->parent_) {
@ -476,19 +357,21 @@ void AbstractTreeViewItem::ensure_parents_uncollapsed()
}
}
bool AbstractTreeViewItem::matches_including_parents(const AbstractTreeViewItem &other) const
bool AbstractTreeViewItem::matches(const AbstractViewItem &other) const
{
if (!matches(other)) {
const AbstractTreeViewItem &other_tree_item = dynamic_cast<const AbstractTreeViewItem &>(other);
if (!matches_single(other_tree_item)) {
return false;
}
if (count_parents() != other.count_parents()) {
if (count_parents() != other_tree_item.count_parents()) {
return false;
}
for (AbstractTreeViewItem *parent = parent_, *other_parent = other.parent_;
for (AbstractTreeViewItem *parent = parent_, *other_parent = other_tree_item.parent_;
parent && other_parent;
parent = parent->parent_, other_parent = other_parent->parent_) {
if (!parent->matches(*other_parent)) {
if (!parent->matches_single(*other_parent)) {
return false;
}
}
@ -496,9 +379,9 @@ bool AbstractTreeViewItem::matches_including_parents(const AbstractTreeViewItem
return true;
}
uiButTreeRow *AbstractTreeViewItem::tree_row_button()
uiButViewItem *AbstractTreeViewItem::view_item_button()
{
return tree_row_but_;
return view_item_but_;
}
void AbstractTreeViewItem::change_state_delayed()
@ -511,25 +394,6 @@ void AbstractTreeViewItem::change_state_delayed()
/* ---------------------------------------------------------------------- */
AbstractTreeViewItemDragController::AbstractTreeViewItemDragController(AbstractTreeView &tree_view)
: tree_view_(tree_view)
{
}
void AbstractTreeViewItemDragController::on_drag_start()
{
/* Do nothing by default. */
}
/* ---------------------------------------------------------------------- */
AbstractTreeViewItemDropController::AbstractTreeViewItemDropController(AbstractTreeView &tree_view)
: tree_view_(tree_view)
{
}
/* ---------------------------------------------------------------------- */
class TreeViewLayoutBuilder {
uiBlock &block_;
@ -575,7 +439,7 @@ void TreeViewLayoutBuilder::polish_layout(const uiBlock &block)
UI_but_drawflag_enable(static_cast<uiBut *>(but->next), UI_BUT_NO_TEXT_PADDING);
}
if (but->type == UI_BTYPE_TREEROW) {
if (but->type == UI_BTYPE_VIEW_ITEM) {
break;
}
}
@ -687,154 +551,4 @@ std::optional<bool> BasicTreeViewItem::should_be_active() const
return std::nullopt;
}
/* ---------------------------------------------------------------------- */
/**
* Helper for a public (C-)API, presenting higher level functionality. Has access to internal
* data/functionality (friend of #AbstractTreeViewItem), which is sometimes needed when
* functionality of the API needs to be constructed from multiple internal conditions and/or
* functions that on their own shouldn't be part of the API.
*/
class TreeViewItemAPIWrapper {
public:
static bool matches(const AbstractTreeViewItem &a, const AbstractTreeViewItem &b)
{
/* TODO should match the tree-view as well. */
return a.matches_including_parents(b);
}
static bool drag_start(bContext &C, const AbstractTreeViewItem &item)
{
const std::unique_ptr<AbstractTreeViewItemDragController> drag_controller =
item.create_drag_controller();
if (!drag_controller) {
return false;
}
WM_event_start_drag(&C,
ICON_NONE,
drag_controller->get_drag_type(),
drag_controller->create_drag_data(),
0,
WM_DRAG_FREE_DATA);
drag_controller->on_drag_start();
return true;
}
static bool can_drop(const AbstractTreeViewItem &item,
const wmDrag &drag,
const char **r_disabled_hint)
{
const std::unique_ptr<AbstractTreeViewItemDropController> drop_controller =
item.create_drop_controller();
if (!drop_controller) {
return false;
}
return drop_controller->can_drop(drag, r_disabled_hint);
}
static std::string drop_tooltip(const AbstractTreeViewItem &item, const wmDrag &drag)
{
const std::unique_ptr<AbstractTreeViewItemDropController> drop_controller =
item.create_drop_controller();
if (!drop_controller) {
return {};
}
return drop_controller->drop_tooltip(drag);
}
static bool drop_handle(bContext &C, const AbstractTreeViewItem &item, const ListBase &drags)
{
std::unique_ptr<AbstractTreeViewItemDropController> drop_controller =
item.create_drop_controller();
const char *disabled_hint_dummy = nullptr;
LISTBASE_FOREACH (const wmDrag *, drag, &drags) {
if (drop_controller->can_drop(*drag, &disabled_hint_dummy)) {
return drop_controller->on_drop(&C, *drag);
}
}
return false;
}
static bool can_rename(const AbstractTreeViewItem &item)
{
const AbstractTreeView &tree_view = item.get_tree_view();
return !tree_view.is_renaming() && item.supports_renaming();
}
};
} // namespace blender::ui
/* ---------------------------------------------------------------------- */
/* C-API */
using namespace blender::ui;
bool UI_tree_view_item_is_active(const uiTreeViewItemHandle *item_handle)
{
const AbstractTreeViewItem &item = reinterpret_cast<const AbstractTreeViewItem &>(*item_handle);
return item.is_active();
}
bool UI_tree_view_item_matches(const uiTreeViewItemHandle *a_handle,
const uiTreeViewItemHandle *b_handle)
{
const AbstractTreeViewItem &a = reinterpret_cast<const AbstractTreeViewItem &>(*a_handle);
const AbstractTreeViewItem &b = reinterpret_cast<const AbstractTreeViewItem &>(*b_handle);
return TreeViewItemAPIWrapper::matches(a, b);
}
bool UI_tree_view_item_drag_start(bContext *C, uiTreeViewItemHandle *item_)
{
const AbstractTreeViewItem &item = reinterpret_cast<const AbstractTreeViewItem &>(*item_);
return TreeViewItemAPIWrapper::drag_start(*C, item);
}
bool UI_tree_view_item_can_drop(const uiTreeViewItemHandle *item_,
const wmDrag *drag,
const char **r_disabled_hint)
{
const AbstractTreeViewItem &item = reinterpret_cast<const AbstractTreeViewItem &>(*item_);
return TreeViewItemAPIWrapper::can_drop(item, *drag, r_disabled_hint);
}
char *UI_tree_view_item_drop_tooltip(const uiTreeViewItemHandle *item_, const wmDrag *drag)
{
const AbstractTreeViewItem &item = reinterpret_cast<const AbstractTreeViewItem &>(*item_);
const std::string tooltip = TreeViewItemAPIWrapper::drop_tooltip(item, *drag);
return tooltip.empty() ? nullptr : BLI_strdup(tooltip.c_str());
}
bool UI_tree_view_item_drop_handle(bContext *C,
const uiTreeViewItemHandle *item_,
const ListBase *drags)
{
const AbstractTreeViewItem &item = reinterpret_cast<const AbstractTreeViewItem &>(*item_);
return TreeViewItemAPIWrapper::drop_handle(*C, item, *drags);
}
bool UI_tree_view_item_can_rename(const uiTreeViewItemHandle *item_handle)
{
const AbstractTreeViewItem &item = reinterpret_cast<const AbstractTreeViewItem &>(*item_handle);
return TreeViewItemAPIWrapper::can_rename(item);
}
void UI_tree_view_item_begin_rename(uiTreeViewItemHandle *item_handle)
{
AbstractTreeViewItem &item = reinterpret_cast<AbstractTreeViewItem &>(*item_handle);
item.begin_renaming();
}
void UI_tree_view_item_context_menu_build(bContext *C,
const uiTreeViewItemHandle *item_handle,
uiLayout *column)
{
const AbstractTreeViewItem &item = reinterpret_cast<const AbstractTreeViewItem &>(*item_handle);
item.build_context_menu(*C, *column);
}

View File

@ -86,12 +86,12 @@ class AssetCatalogTreeViewItem : public ui::BasicTreeViewItem {
bool rename(StringRefNull new_name) override;
/** Add drag support for catalog items. */
std::unique_ptr<ui::AbstractTreeViewItemDragController> create_drag_controller() const override;
std::unique_ptr<ui::AbstractViewItemDragController> create_drag_controller() const override;
/** Add dropping support for catalog items. */
std::unique_ptr<ui::AbstractTreeViewItemDropController> create_drop_controller() const override;
std::unique_ptr<ui::AbstractViewItemDropController> create_drop_controller() const override;
};
class AssetCatalogDragController : public ui::AbstractTreeViewItemDragController {
class AssetCatalogDragController : public ui::AbstractViewItemDragController {
AssetCatalogTreeItem &catalog_item_;
public:
@ -103,7 +103,7 @@ class AssetCatalogDragController : public ui::AbstractTreeViewItemDragController
void on_drag_start() override;
};
class AssetCatalogDropController : public ui::AbstractTreeViewItemDropController {
class AssetCatalogDropController : public ui::AbstractViewItemDropController {
AssetCatalogTreeItem &catalog_item_;
public:
@ -142,7 +142,7 @@ class AssetCatalogTreeViewAllItem : public ui::BasicTreeViewItem {
void build_row(uiLayout &row) override;
struct DropController : public ui::AbstractTreeViewItemDropController {
struct DropController : public ui::AbstractViewItemDropController {
DropController(AssetCatalogTreeView &tree_view);
bool can_drop(const wmDrag &drag, const char **r_disabled_hint) const override;
@ -150,13 +150,13 @@ class AssetCatalogTreeViewAllItem : public ui::BasicTreeViewItem {
bool on_drop(struct bContext *C, const wmDrag &drag) override;
};
std::unique_ptr<ui::AbstractTreeViewItemDropController> create_drop_controller() const override;
std::unique_ptr<ui::AbstractViewItemDropController> create_drop_controller() const override;
};
class AssetCatalogTreeViewUnassignedItem : public ui::BasicTreeViewItem {
using BasicTreeViewItem::BasicTreeViewItem;
struct DropController : public ui::AbstractTreeViewItemDropController {
struct DropController : public ui::AbstractViewItemDropController {
DropController(AssetCatalogTreeView &tree_view);
bool can_drop(const wmDrag &drag, const char **r_disabled_hint) const override;
@ -164,7 +164,7 @@ class AssetCatalogTreeViewUnassignedItem : public ui::BasicTreeViewItem {
bool on_drop(struct bContext *C, const wmDrag &drag) override;
};
std::unique_ptr<ui::AbstractTreeViewItemDropController> create_drop_controller() const override;
std::unique_ptr<ui::AbstractViewItemDropController> create_drop_controller() const override;
};
/* ---------------------------------------------------------------------- */
@ -272,11 +272,11 @@ void AssetCatalogTreeViewItem::build_row(uiLayout &row)
return;
}
uiButTreeRow *tree_row_but = tree_row_button();
uiButViewItem *view_item_but = view_item_button();
PointerRNA *props;
props = UI_but_extra_operator_icon_add(
(uiBut *)tree_row_but, "ASSET_OT_catalog_new", WM_OP_INVOKE_DEFAULT, ICON_ADD);
(uiBut *)view_item_but, "ASSET_OT_catalog_new", WM_OP_INVOKE_DEFAULT, ICON_ADD);
RNA_string_set(props, "parent_path", catalog_item_.catalog_path().c_str());
}
@ -305,7 +305,7 @@ void AssetCatalogTreeViewItem::build_context_menu(bContext &C, uiLayout &column)
0,
&props);
RNA_string_set(&props, "catalog_id", catalog_id_str_buffer);
uiItemO(&column, "Rename", ICON_NONE, "UI_OT_tree_view_item_rename");
uiItemO(&column, "Rename", ICON_NONE, "UI_OT_view_item_rename");
/* Doesn't actually exist right now, but could be defined in Python. Reason that this isn't done
* in Python yet is that catalogs are not exposed in BPY, and we'd somehow pass the clicked on
@ -333,14 +333,14 @@ bool AssetCatalogTreeViewItem::rename(StringRefNull new_name)
return true;
}
std::unique_ptr<ui::AbstractTreeViewItemDropController> AssetCatalogTreeViewItem::
std::unique_ptr<ui::AbstractViewItemDropController> AssetCatalogTreeViewItem::
create_drop_controller() const
{
return std::make_unique<AssetCatalogDropController>(
static_cast<AssetCatalogTreeView &>(get_tree_view()), catalog_item_);
}
std::unique_ptr<ui::AbstractTreeViewItemDragController> AssetCatalogTreeViewItem::
std::unique_ptr<ui::AbstractViewItemDragController> AssetCatalogTreeViewItem::
create_drag_controller() const
{
return std::make_unique<AssetCatalogDragController>(
@ -351,7 +351,7 @@ std::unique_ptr<ui::AbstractTreeViewItemDragController> AssetCatalogTreeViewItem
AssetCatalogDropController::AssetCatalogDropController(AssetCatalogTreeView &tree_view,
AssetCatalogTreeItem &catalog_item)
: ui::AbstractTreeViewItemDropController(tree_view), catalog_item_(catalog_item)
: ui::AbstractViewItemDropController(tree_view), catalog_item_(catalog_item)
{
}
@ -422,10 +422,10 @@ bool AssetCatalogDropController::on_drop(struct bContext *C, const wmDrag &drag)
{
if (drag.type == WM_DRAG_ASSET_CATALOG) {
return drop_asset_catalog_into_catalog(
drag, tree_view<AssetCatalogTreeView>(), catalog_item_.get_catalog_id());
drag, get_view<AssetCatalogTreeView>(), catalog_item_.get_catalog_id());
}
return drop_assets_into_catalog(C,
tree_view<AssetCatalogTreeView>(),
get_view<AssetCatalogTreeView>(),
drag,
catalog_item_.get_catalog_id(),
catalog_item_.get_simple_name());
@ -512,14 +512,14 @@ bool AssetCatalogDropController::has_droppable_asset(const wmDrag &drag,
::AssetLibrary &AssetCatalogDropController::get_asset_library() const
{
return *tree_view<AssetCatalogTreeView>().asset_library_;
return *get_view<AssetCatalogTreeView>().asset_library_;
}
/* ---------------------------------------------------------------------- */
AssetCatalogDragController::AssetCatalogDragController(AssetCatalogTreeView &tree_view,
AssetCatalogTreeItem &catalog_item)
: ui::AbstractTreeViewItemDragController(tree_view), catalog_item_(catalog_item)
: ui::AbstractViewItemDragController(tree_view), catalog_item_(catalog_item)
{
}
@ -538,7 +538,7 @@ void *AssetCatalogDragController::create_drag_data() const
void AssetCatalogDragController::on_drag_start()
{
AssetCatalogTreeView &tree_view_ = tree_view<AssetCatalogTreeView>();
AssetCatalogTreeView &tree_view_ = get_view<AssetCatalogTreeView>();
tree_view_.activate_catalog_by_id(catalog_item_.get_catalog_id());
}
@ -551,15 +551,15 @@ void AssetCatalogTreeViewAllItem::build_row(uiLayout &row)
PointerRNA *props;
UI_but_extra_operator_icon_add(
(uiBut *)tree_row_button(), "ASSET_OT_catalogs_save", WM_OP_INVOKE_DEFAULT, ICON_FILE_TICK);
(uiBut *)view_item_button(), "ASSET_OT_catalogs_save", WM_OP_INVOKE_DEFAULT, ICON_FILE_TICK);
props = UI_but_extra_operator_icon_add(
(uiBut *)tree_row_button(), "ASSET_OT_catalog_new", WM_OP_INVOKE_DEFAULT, ICON_ADD);
(uiBut *)view_item_button(), "ASSET_OT_catalog_new", WM_OP_INVOKE_DEFAULT, ICON_ADD);
/* No parent path to use the root level. */
RNA_string_set(props, "parent_path", nullptr);
}
std::unique_ptr<ui::AbstractTreeViewItemDropController> AssetCatalogTreeViewAllItem::
std::unique_ptr<ui::AbstractViewItemDropController> AssetCatalogTreeViewAllItem::
create_drop_controller() const
{
return std::make_unique<AssetCatalogTreeViewAllItem::DropController>(
@ -567,7 +567,7 @@ std::unique_ptr<ui::AbstractTreeViewItemDropController> AssetCatalogTreeViewAllI
}
AssetCatalogTreeViewAllItem::DropController::DropController(AssetCatalogTreeView &tree_view)
: ui::AbstractTreeViewItemDropController(tree_view)
: ui::AbstractViewItemDropController(tree_view)
{
}
@ -579,7 +579,7 @@ bool AssetCatalogTreeViewAllItem::DropController::can_drop(const wmDrag &drag,
}
const AssetCatalog *drag_catalog = AssetCatalogDropController::get_drag_catalog(
drag, *tree_view<AssetCatalogTreeView>().asset_library_);
drag, *get_view<AssetCatalogTreeView>().asset_library_);
if (drag_catalog->path.parent() == "") {
*r_disabled_hint = "Catalog is already placed at the highest level";
return false;
@ -592,7 +592,7 @@ std::string AssetCatalogTreeViewAllItem::DropController::drop_tooltip(const wmDr
{
BLI_assert(drag.type == WM_DRAG_ASSET_CATALOG);
const AssetCatalog *drag_catalog = AssetCatalogDropController::get_drag_catalog(
drag, *tree_view<AssetCatalogTreeView>().asset_library_);
drag, *get_view<AssetCatalogTreeView>().asset_library_);
return std::string(TIP_("Move Catalog")) + " '" + drag_catalog->path.name() + "' " +
TIP_("to the top level of the tree");
@ -604,14 +604,14 @@ bool AssetCatalogTreeViewAllItem::DropController::on_drop(struct bContext *UNUSE
BLI_assert(drag.type == WM_DRAG_ASSET_CATALOG);
return AssetCatalogDropController::drop_asset_catalog_into_catalog(
drag,
tree_view<AssetCatalogTreeView>(),
get_view<AssetCatalogTreeView>(),
/* No value to drop into the root level. */
std::nullopt);
}
/* ---------------------------------------------------------------------- */
std::unique_ptr<ui::AbstractTreeViewItemDropController> AssetCatalogTreeViewUnassignedItem::
std::unique_ptr<ui::AbstractViewItemDropController> AssetCatalogTreeViewUnassignedItem::
create_drop_controller() const
{
return std::make_unique<AssetCatalogTreeViewUnassignedItem::DropController>(
@ -619,7 +619,7 @@ std::unique_ptr<ui::AbstractTreeViewItemDropController> AssetCatalogTreeViewUnas
}
AssetCatalogTreeViewUnassignedItem::DropController::DropController(AssetCatalogTreeView &tree_view)
: ui::AbstractTreeViewItemDropController(tree_view)
: ui::AbstractViewItemDropController(tree_view)
{
}
@ -647,7 +647,7 @@ bool AssetCatalogTreeViewUnassignedItem::DropController::on_drop(struct bContext
{
/* Assign to nil catalog ID. */
return AssetCatalogDropController::drop_assets_into_catalog(
C, tree_view<AssetCatalogTreeView>(), drag, CatalogID{});
C, get_view<AssetCatalogTreeView>(), drag, CatalogID{});
}
} // namespace blender::ed::asset_browser

View File

@ -145,7 +145,7 @@ void GeometryDataSetTreeViewItem::build_row(uiLayout &row)
* to the right side of the number, which it didn't have with the button. */
char element_count[7];
BLI_str_format_decimal_unit(element_count, *count);
UI_but_hint_drawstr_set((uiBut *)this->tree_row_button(), element_count);
UI_but_hint_drawstr_set((uiBut *)this->view_item_button(), element_count);
}
}