Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/source
diff options
context:
space:
mode:
authorJulian Eisel <julian@blender.org>2021-10-08 20:56:24 +0300
committerJulian Eisel <julian@blender.org>2021-10-08 21:08:22 +0300
commit17c928e9752372b698a1ed27e243181873aa411e (patch)
tree7a1b088c4c83af65a603b79433b003f3cf344300 /source
parent7bd0de924080571f4c8308dc651b83539d6d22b8 (diff)
UI: Add context menu support for tree-view items
Tree-view items can now easily define their own context menu. This works by overriding the `ui::AbstractTreeViewItem::build_context_menu()` function. See the documentation: https://wiki.blender.org/wiki/Source/Interface/Views#Context_Menus Consistently with the Outliner and File Browser, the right-clicked item also gets activated. This makes sure the correct context is set for the operators and makes it clear to the user which item is operated on. An operator to rename the active item is also added, which is something you'd typically want to put in the context menu as well.
Diffstat (limited to 'source')
-rw-r--r--source/blender/editors/include/UI_interface.h5
-rw-r--r--source/blender/editors/include/UI_tree_view.hh1
-rw-r--r--source/blender/editors/interface/interface_context_menu.c12
-rw-r--r--source/blender/editors/interface/interface_handlers.c8
-rw-r--r--source/blender/editors/interface/interface_intern.h1
-rw-r--r--source/blender/editors/interface/interface_ops.c44
-rw-r--r--source/blender/editors/interface/interface_query.c15
-rw-r--r--source/blender/editors/interface/interface_view.cc10
-rw-r--r--source/blender/editors/interface/tree_view.cc13
9 files changed, 109 insertions, 0 deletions
diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h
index c536eff771d..ddd5e77cbb6 100644
--- a/source/blender/editors/include/UI_interface.h
+++ b/source/blender/editors/include/UI_interface.h
@@ -2783,7 +2783,12 @@ char *UI_tree_view_item_drop_tooltip(const uiTreeViewItemHandle *item,
bool UI_tree_view_item_can_rename(const uiTreeViewItemHandle *item_handle);
void UI_tree_view_item_begin_rename(uiTreeViewItemHandle *item_handle);
+void UI_tree_view_item_context_menu_build(struct bContext *C,
+ const uiTreeViewItemHandle *item,
+ uiLayout *column);
+
uiTreeViewItemHandle *UI_block_tree_view_find_item_at(const struct ARegion *region, int x, int y);
+uiTreeViewItemHandle *UI_block_tree_view_find_active_item(const struct ARegion *region);
#ifdef __cplusplus
}
diff --git a/source/blender/editors/include/UI_tree_view.hh b/source/blender/editors/include/UI_tree_view.hh
index 272439a2ae9..ae85375ed2f 100644
--- a/source/blender/editors/include/UI_tree_view.hh
+++ b/source/blender/editors/include/UI_tree_view.hh
@@ -234,6 +234,7 @@ class AbstractTreeViewItem : public TreeViewItemContainer {
virtual ~AbstractTreeViewItem() = default;
virtual void build_row(uiLayout &row) = 0;
+ virtual void build_context_menu(bContext &C, uiLayout &column) const;
virtual void on_activate();
/**
diff --git a/source/blender/editors/interface/interface_context_menu.c b/source/blender/editors/interface/interface_context_menu.c
index bb9e813ea50..d327124484b 100644
--- a/source/blender/editors/interface/interface_context_menu.c
+++ b/source/blender/editors/interface/interface_context_menu.c
@@ -925,6 +925,18 @@ bool ui_popup_context_menu_for_button(bContext *C, uiBut *but, const wmEvent *ev
}
}
+ {
+ const ARegion *region = CTX_wm_region(C);
+ uiButTreeRow *treerow_but = (uiButTreeRow *)ui_tree_row_find_mouse_over(
+ region, event->x, event->y);
+ 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));
+ uiItemS(layout);
+ }
+ }
+
/* If the button represents an id, it can set the "id" context pointer. */
if (U.experimental.use_extended_asset_browser && ED_asset_can_mark_single_from_context(C)) {
ID *id = CTX_data_pointer_get_type(C, "id", &RNA_ID).data;
diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c
index bf9b37c00fa..e1f8d18ce35 100644
--- a/source/blender/editors/interface/interface_handlers.c
+++ b/source/blender/editors/interface/interface_handlers.c
@@ -7961,6 +7961,14 @@ static int ui_do_button(bContext *C, uiBlock *block, uiBut *but, const wmEvent *
/* handle menu */
if ((event->type == RIGHTMOUSE) && !IS_EVENT_MOD(event, shift, ctrl, alt, oskey) &&
(event->val == KM_PRESS)) {
+ /* For some button types that are typically representing entire sets of data, right-clicking
+ * 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)) {
+ ui_apply_but(C, but->block, but, but->active, true);
+ }
+
/* RMB has two options now */
if (ui_popup_context_menu_for_button(C, but, event)) {
return WM_UI_HANDLER_BREAK;
diff --git a/source/blender/editors/interface/interface_intern.h b/source/blender/editors/interface/interface_intern.h
index e7a728efce1..c7781d65058 100644
--- a/source/blender/editors/interface/interface_intern.h
+++ b/source/blender/editors/interface/interface_intern.h
@@ -1177,6 +1177,7 @@ uiBut *ui_list_row_find_from_index(const struct ARegion *region,
const int index,
uiBut *listbox) ATTR_WARN_UNUSED_RESULT;
uiBut *ui_tree_row_find_mouse_over(const struct ARegion *region, const int x, const int y);
+uiBut *ui_tree_row_find_active(const struct ARegion *region);
typedef bool (*uiButFindPollFn)(const uiBut *but, const void *customdata);
uiBut *ui_but_find_mouse_over_ex(const struct ARegion *region,
diff --git a/source/blender/editors/interface/interface_ops.c b/source/blender/editors/interface/interface_ops.c
index 1fc07bce341..423950d4dbd 100644
--- a/source/blender/editors/interface/interface_ops.c
+++ b/source/blender/editors/interface/interface_ops.c
@@ -1963,6 +1963,49 @@ static void UI_OT_tree_view_drop(wmOperatorType *ot)
/** \} */
/* -------------------------------------------------------------------- */
+/** \name UI Tree-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 own renaming operators
+ * with the same logic as they already have for their #ui::AbstractTreeViewItem::rename() override.
+ *
+ * \{ */
+
+static bool ui_tree_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);
+}
+
+static int ui_tree_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);
+
+ UI_tree_view_item_begin_rename(active_item);
+ ED_region_tag_redraw(region);
+
+ return OPERATOR_FINISHED;
+}
+
+static void UI_OT_tree_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->exec = ui_tree_view_item_rename_exec;
+ ot->poll = ui_tree_view_item_rename_poll;
+ /* Could get a custom tooltip via the `get_description()` callback and another overridable
+ * function of the tree-view. */
+
+ ot->flag = OPTYPE_INTERNAL;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
/** \name Operator & Keymap Registration
* \{ */
@@ -1990,6 +2033,7 @@ 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);
/* external */
WM_operatortype_append(UI_OT_eyedropper_color);
diff --git a/source/blender/editors/interface/interface_query.c b/source/blender/editors/interface/interface_query.c
index 2f6bda3252d..8674f1e435a 100644
--- a/source/blender/editors/interface/interface_query.c
+++ b/source/blender/editors/interface/interface_query.c
@@ -473,6 +473,21 @@ uiBut *ui_tree_row_find_mouse_over(const ARegion *region, const int x, const int
return ui_but_find_mouse_over_ex(region, x, y, false, ui_but_is_treerow, NULL);
}
+static bool ui_but_is_active_treerow(const uiBut *but, const void *customdata)
+{
+ if (!ui_but_is_treerow(but, customdata)) {
+ return false;
+ }
+
+ const uiButTreeRow *treerow_but = (const uiButTreeRow *)but;
+ return UI_tree_view_item_is_active(treerow_but->tree_item);
+}
+
+uiBut *ui_tree_row_find_active(const ARegion *region)
+{
+ return ui_but_find(region, ui_but_is_active_treerow, NULL);
+}
+
/** \} */
/* -------------------------------------------------------------------- */
diff --git a/source/blender/editors/interface/interface_view.cc b/source/blender/editors/interface/interface_view.cc
index 8122b965892..fdd8eb0cc71 100644
--- a/source/blender/editors/interface/interface_view.cc
+++ b/source/blender/editors/interface/interface_view.cc
@@ -94,6 +94,16 @@ uiTreeViewItemHandle *UI_block_tree_view_find_item_at(const ARegion *region,
return tree_row_but->tree_item;
}
+uiTreeViewItemHandle *UI_block_tree_view_find_active_item(const ARegion *region)
+{
+ uiButTreeRow *tree_row_but = (uiButTreeRow *)ui_tree_row_find_active(region);
+ if (!tree_row_but) {
+ return nullptr;
+ }
+
+ return tree_row_but->tree_item;
+}
+
static StringRef ui_block_view_find_idname(const uiBlock &block, const AbstractTreeView &view)
{
/* First get the idname the of the view we're looking for. */
diff --git a/source/blender/editors/interface/tree_view.cc b/source/blender/editors/interface/tree_view.cc
index 3f66810b7f6..3f3a8c5bce5 100644
--- a/source/blender/editors/interface/tree_view.cc
+++ b/source/blender/editors/interface/tree_view.cc
@@ -369,6 +369,11 @@ bool AbstractTreeViewItem::rename(StringRefNull 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 AbstractTreeViewItem &old)
{
is_open_ = old.is_open_;
@@ -707,3 +712,11 @@ 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);
+}