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
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender/editors/interface')
-rw-r--r--source/blender/editors/interface/CMakeLists.txt1
-rw-r--r--source/blender/editors/interface/interface.c3
-rw-r--r--source/blender/editors/interface/interface_context_path.cc85
-rw-r--r--source/blender/editors/interface/interface_draw.c29
-rw-r--r--source/blender/editors/interface/interface_dropboxes.cc39
-rw-r--r--source/blender/editors/interface/interface_handlers.c128
-rw-r--r--source/blender/editors/interface/interface_intern.h2
-rw-r--r--source/blender/editors/interface/interface_layout.c8
-rw-r--r--source/blender/editors/interface/interface_ops.c34
-rw-r--r--source/blender/editors/interface/interface_panel.c2
-rw-r--r--source/blender/editors/interface/interface_style.c31
-rw-r--r--source/blender/editors/interface/interface_template_asset_view.cc1
-rw-r--r--source/blender/editors/interface/interface_template_attribute_search.cc7
-rw-r--r--source/blender/editors/interface/interface_widgets.c56
-rw-r--r--source/blender/editors/interface/resources.c7
-rw-r--r--source/blender/editors/interface/tree_view.cc95
-rw-r--r--source/blender/editors/interface/view2d.c111
-rw-r--r--source/blender/editors/interface/view2d_edge_pan.c11
18 files changed, 473 insertions, 177 deletions
diff --git a/source/blender/editors/interface/CMakeLists.txt b/source/blender/editors/interface/CMakeLists.txt
index b2659f5ed52..84172c7efce 100644
--- a/source/blender/editors/interface/CMakeLists.txt
+++ b/source/blender/editors/interface/CMakeLists.txt
@@ -43,6 +43,7 @@ set(SRC
interface_anim.c
interface_button_group.c
interface_context_menu.c
+ interface_context_path.cc
interface_draw.c
interface_dropboxes.cc
interface_eyedropper.c
diff --git a/source/blender/editors/interface/interface.c b/source/blender/editors/interface/interface.c
index 5068969946a..62c84ed38ff 100644
--- a/source/blender/editors/interface/interface.c
+++ b/source/blender/editors/interface/interface.c
@@ -6231,12 +6231,13 @@ void UI_but_drag_set_id(uiBut *but, ID *id)
void UI_but_drag_set_asset(uiBut *but,
const AssetHandle *asset,
const char *path,
+ struct AssetMetaData *metadata,
int import_type,
int icon,
struct ImBuf *imb,
float scale)
{
- wmDragAsset *asset_drag = WM_drag_create_asset_data(asset, path, import_type);
+ wmDragAsset *asset_drag = WM_drag_create_asset_data(asset, metadata, path, import_type);
/* FIXME: This is temporary evil solution to get scene/viewlayer/etc in the copy callback of the
* #wmDropBox.
diff --git a/source/blender/editors/interface/interface_context_path.cc b/source/blender/editors/interface/interface_context_path.cc
new file mode 100644
index 00000000000..b0f8d186afa
--- /dev/null
+++ b/source/blender/editors/interface/interface_context_path.cc
@@ -0,0 +1,85 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2021 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup edinterface
+ */
+
+#include "BLI_vector.hh"
+
+#include "BKE_screen.h"
+
+#include "RNA_access.h"
+
+#include "ED_screen.h"
+
+#include "UI_interface.h"
+#include "UI_interface.hh"
+#include "UI_resources.h"
+
+#include "WM_api.h"
+
+namespace blender::ui {
+
+void context_path_add_generic(Vector<ContextPathItem> &path,
+ StructRNA &rna_type,
+ void *ptr,
+ const BIFIconID icon_override)
+{
+ /* Add the null check here to make calling functions less verbose. */
+ if (!ptr) {
+ return;
+ }
+
+ PointerRNA rna_ptr;
+ RNA_pointer_create(nullptr, &rna_type, ptr, &rna_ptr);
+ char name[128];
+ RNA_struct_name_get_alloc(&rna_ptr, name, sizeof(name), nullptr);
+
+ /* Use a blank icon by default to check whether to retrieve it automatically from the type. */
+ const BIFIconID icon = icon_override == ICON_NONE ?
+ static_cast<BIFIconID>(RNA_struct_ui_icon(rna_ptr.type)) :
+ icon_override;
+
+ path.append({name, static_cast<int>(icon)});
+}
+
+/* -------------------------------------------------------------------- */
+/** \name Breadcrumb Template
+ * \{ */
+
+void template_breadcrumbs(uiLayout &layout, Span<ContextPathItem> context_path)
+{
+ uiLayout *row = uiLayoutRow(&layout, true);
+ uiLayoutSetAlignment(&layout, UI_LAYOUT_ALIGN_LEFT);
+
+ for (const int i : context_path.index_range()) {
+ uiLayout *sub_row = uiLayoutRow(row, true);
+ uiLayoutSetAlignment(sub_row, UI_LAYOUT_ALIGN_LEFT);
+
+ if (i > 0) {
+ uiItemL(sub_row, "", ICON_RIGHTARROW_THIN);
+ }
+ uiItemL(sub_row, context_path[i].name.c_str(), context_path[i].icon);
+ }
+}
+
+} // namespace blender::ui
+
+/** \} */ \ No newline at end of file
diff --git a/source/blender/editors/interface/interface_draw.c b/source/blender/editors/interface/interface_draw.c
index 6cb0fcd499c..e45a5fc61c6 100644
--- a/source/blender/editors/interface/interface_draw.c
+++ b/source/blender/editors/interface/interface_draw.c
@@ -178,35 +178,6 @@ void UI_draw_roundbox_4fv(const rctf *rect, bool filled, float rad, const float
UI_draw_roundbox_4fv_ex(rect, (filled) ? col : NULL, NULL, 1.0f, col, U.pixelsize, rad);
}
-/* linear horizontal shade within button or in outline */
-/* view2d scrollers use it */
-void UI_draw_roundbox_shade_x(
- const rctf *rect, bool filled, float rad, float shadetop, float shadedown, const float col[4])
-{
- float inner1[4] = {0.0f, 0.0f, 0.0f, 0.0f};
- float inner2[4] = {0.0f, 0.0f, 0.0f, 0.0f};
- float outline[4];
-
- if (filled) {
- inner1[0] = min_ff(1.0f, col[0] + shadetop);
- inner1[1] = min_ff(1.0f, col[1] + shadetop);
- inner1[2] = min_ff(1.0f, col[2] + shadetop);
- inner1[3] = 1.0f;
- inner2[0] = max_ff(0.0f, col[0] + shadedown);
- inner2[1] = max_ff(0.0f, col[1] + shadedown);
- inner2[2] = max_ff(0.0f, col[2] + shadedown);
- inner2[3] = 1.0f;
- }
-
- /* TODO: non-filled box don't have gradients. Just use middle color. */
- outline[0] = clamp_f(col[0] + shadetop + shadedown, 0.0f, 1.0f);
- outline[1] = clamp_f(col[1] + shadetop + shadedown, 0.0f, 1.0f);
- outline[2] = clamp_f(col[2] + shadetop + shadedown, 0.0f, 1.0f);
- outline[3] = clamp_f(col[3] + shadetop + shadedown, 0.0f, 1.0f);
-
- UI_draw_roundbox_4fv_ex(rect, inner1, inner2, 1.0f, outline, U.pixelsize, rad);
-}
-
void UI_draw_text_underline(int pos_x, int pos_y, int len, int height, const float color[4])
{
const int ofs_y = 4 * U.pixelsize;
diff --git a/source/blender/editors/interface/interface_dropboxes.cc b/source/blender/editors/interface/interface_dropboxes.cc
index 62250a34cf4..81a1354cbe7 100644
--- a/source/blender/editors/interface/interface_dropboxes.cc
+++ b/source/blender/editors/interface/interface_dropboxes.cc
@@ -22,6 +22,10 @@
#include "DNA_space_types.h"
+#include "MEM_guardedalloc.h"
+
+#include "RNA_access.h"
+
#include "WM_api.h"
#include "UI_interface.h"
@@ -35,24 +39,43 @@ static bool ui_tree_view_drop_poll(bContext *C, wmDrag *drag, const wmEvent *eve
return false;
}
- return UI_tree_view_item_can_drop(hovered_tree_item, drag);
+ if (drag->free_disabled_info) {
+ MEM_SAFE_FREE(drag->disabled_info);
+ }
+
+ drag->free_disabled_info = false;
+ return UI_tree_view_item_can_drop(hovered_tree_item, drag, &drag->disabled_info);
}
static char *ui_tree_view_drop_tooltip(bContext *C,
wmDrag *drag,
- const wmEvent *event,
+ 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,
- event->xy);
+ const uiTreeViewItemHandle *hovered_tree_item = UI_block_tree_view_find_item_at(region, xy);
if (!hovered_tree_item) {
return nullptr;
}
- return UI_tree_view_item_drop_tooltip(hovered_tree_item, C, drag, event);
+ return UI_tree_view_item_drop_tooltip(hovered_tree_item, drag);
}
+/* ---------------------------------------------------------------------- */
+
+static bool ui_drop_name_poll(struct bContext *C, wmDrag *drag, const wmEvent *UNUSED(event))
+{
+ return UI_but_active_drop_name(C) && (drag->type == WM_DRAG_ID);
+}
+
+static void ui_drop_name_copy(wmDrag *drag, wmDropBox *drop)
+{
+ const ID *id = WM_drag_get_local_ID(drag, 0);
+ RNA_string_set(drop->ptr, "string", id->name + 2);
+}
+
+/* ---------------------------------------------------------------------- */
+
void ED_dropboxes_ui()
{
ListBase *lb = WM_dropboxmap_find("User Interface", SPACE_EMPTY, 0);
@@ -63,4 +86,10 @@ void ED_dropboxes_ui()
nullptr,
nullptr,
ui_tree_view_drop_tooltip);
+ WM_dropbox_add(lb,
+ "UI_OT_drop_name",
+ ui_drop_name_poll,
+ ui_drop_name_copy,
+ WM_drag_free_imported_drag_ID,
+ nullptr);
}
diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c
index 52ab13e5cd0..51ebe5399b3 100644
--- a/source/blender/editors/interface/interface_handlers.c
+++ b/source/blender/editors/interface/interface_handlers.c
@@ -2145,6 +2145,12 @@ 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 {
wmDrag *drag = WM_event_start_drag(
C,
@@ -2437,39 +2443,6 @@ static void ui_apply_but(
/** \} */
/* -------------------------------------------------------------------- */
-/** \name Button Drop Event
- * \{ */
-
-/* only call if event type is EVT_DROP */
-static void ui_but_drop(bContext *C, const wmEvent *event, uiBut *but, uiHandleButtonData *data)
-{
- ListBase *drags = event->customdata; /* drop event type has listbase customdata by default */
-
- LISTBASE_FOREACH (wmDrag *, wmd, drags) {
- /* TODO: asset dropping. */
- if (wmd->type == WM_DRAG_ID) {
- /* align these types with UI_but_active_drop_name */
- if (ELEM(but->type, UI_BTYPE_TEXT, UI_BTYPE_SEARCH_MENU)) {
- ID *id = WM_drag_get_local_ID(wmd, 0);
-
- button_activate_state(C, but, BUTTON_STATE_TEXT_EDITING);
-
- ui_textedit_string_set(but, data, id->name + 2);
-
- if (ELEM(but->type, UI_BTYPE_SEARCH_MENU)) {
- but->changed = true;
- ui_searchbox_update(C, data->searchbox, but, true);
- }
-
- button_activate_state(C, but, BUTTON_STATE_EXIT);
- }
- }
- }
-}
-
-/** \} */
-
-/* -------------------------------------------------------------------- */
/** \name Button Copy & Paste
* \{ */
@@ -2666,15 +2639,9 @@ static void ui_but_copy_text(uiBut *but, char *output, int output_len_max)
static void ui_but_paste_text(bContext *C, uiBut *but, uiHandleButtonData *data, char *buf_paste)
{
- button_activate_state(C, but, BUTTON_STATE_TEXT_EDITING);
- ui_textedit_string_set(but, but->active, buf_paste);
-
- if (but->type == UI_BTYPE_SEARCH_MENU) {
- but->changed = true;
- ui_searchbox_update(C, data->searchbox, but, true);
- }
-
- button_activate_state(C, but, BUTTON_STATE_EXIT);
+ BLI_assert(but->active == data);
+ UNUSED_VARS_NDEBUG(data);
+ ui_but_set_string_interactive(C, but, buf_paste);
}
static void ui_but_copy_colorband(uiBut *but)
@@ -3018,6 +2985,24 @@ void ui_but_text_password_hide(char password_str[UI_MAX_PASSWORD_STR],
/** \name Button Text Selection/Editing
* \{ */
+/**
+ * Use handling code to set a string for the button. Handles the case where the string is set for a
+ * search button while the search menu is open, so the results are updated accordingly.
+ * This is basically the same as pasting the string into the button.
+ */
+void ui_but_set_string_interactive(bContext *C, uiBut *but, const char *value)
+{
+ button_activate_state(C, but, BUTTON_STATE_TEXT_EDITING);
+ ui_textedit_string_set(but, but->active, value);
+
+ if (but->type == UI_BTYPE_SEARCH_MENU && but->active) {
+ but->changed = true;
+ ui_searchbox_update(C, but->active->searchbox, but, true);
+ }
+
+ button_activate_state(C, but, BUTTON_STATE_EXIT);
+}
+
void ui_but_active_string_clear_and_exit(bContext *C, uiBut *but)
{
if (!but->active) {
@@ -4821,19 +4806,33 @@ static int ui_do_but_TREEROW(bContext *C,
if (data->state == BUTTON_STATE_HIGHLIGHT) {
if (event->type == LEFTMOUSE) {
- if (event->val == KM_CLICK) {
- button_activate_state(C, but, BUTTON_STATE_EXIT);
- return WM_UI_HANDLER_BREAK;
- }
- if (event->val == KM_DBL_CLICK) {
- data->cancel = true;
+ 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, 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;
- UI_tree_view_item_begin_rename(tree_row_but->tree_item);
- ED_region_tag_redraw(CTX_wm_region(C));
- return WM_UI_HANDLER_BREAK;
+ case KM_CLICK:
+ button_activate_state(C, but, BUTTON_STATE_EXIT);
+ return WM_UI_HANDLER_BREAK;
+
+ 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;
}
@@ -7929,7 +7928,7 @@ static int ui_do_button(bContext *C, uiBlock *block, uiBut *but, const wmEvent *
/* Only hard-coded stuff here, button interactions with configurable
* keymaps are handled using operators (see #ED_keymap_ui). */
- if ((data->state == BUTTON_STATE_HIGHLIGHT) || (event->type == EVT_DROP)) {
+ if (data->state == BUTTON_STATE_HIGHLIGHT) {
/* handle copy and paste */
bool is_press_ctrl_but_no_shift = event->val == KM_PRESS && IS_EVENT_MOD(event, ctrl, oskey) &&
@@ -7978,11 +7977,6 @@ static int ui_do_button(bContext *C, uiBlock *block, uiBut *but, const wmEvent *
return WM_UI_HANDLER_BREAK;
}
- /* handle drop */
- if (event->type == EVT_DROP) {
- ui_but_drop(C, event, but, data);
- }
-
if ((data->state == BUTTON_STATE_HIGHLIGHT) &&
ELEM(event->type, LEFTMOUSE, EVT_BUT_OPEN, EVT_PADENTER, EVT_RETKEY) &&
(event->val == KM_RELEASE) &&
@@ -10648,7 +10642,8 @@ static int ui_handle_menu_event(bContext *C,
menu->menuretval = UI_RETURN_OUT;
}
}
- else if (saferct && !BLI_rctf_isect_pt(&saferct->parent, (float)event->xy[0], (float)event->xy[1])) {
+ else if (saferct && !BLI_rctf_isect_pt(
+ &saferct->parent, (float)event->xy[0], (float)event->xy[1])) {
if (block->flag & UI_BLOCK_OUT_1) {
menu->menuretval = UI_RETURN_OK;
}
@@ -10779,7 +10774,7 @@ static int ui_handle_menu_event(bContext *C,
}
#endif
- /* Don't handle double click events, rehandle as regular press/release. */
+ /* Don't handle double click events, re-handle as regular press/release. */
if (retval == WM_UI_HANDLER_CONTINUE && event->val == KM_DBL_CLICK) {
return retval;
}
@@ -11695,20 +11690,25 @@ void UI_screen_free_active_but(const bContext *C, bScreen *screen)
}
}
-/* returns true if highlighted button allows drop of names */
-/* called in region context */
-bool UI_but_active_drop_name(bContext *C)
+uiBut *UI_but_active_drop_name_button(const bContext *C)
{
ARegion *region = CTX_wm_region(C);
uiBut *but = ui_region_find_active_but(region);
if (but) {
if (ELEM(but->type, UI_BTYPE_TEXT, UI_BTYPE_SEARCH_MENU)) {
- return true;
+ return but;
}
}
- return false;
+ return NULL;
+}
+
+/* returns true if highlighted button allows drop of names */
+/* called in region context */
+bool UI_but_active_drop_name(const bContext *C)
+{
+ return UI_but_active_drop_name_button(C) != NULL;
}
bool UI_but_active_drop_color(bContext *C)
diff --git a/source/blender/editors/interface/interface_intern.h b/source/blender/editors/interface/interface_intern.h
index 0826157b5e6..f766bb1465f 100644
--- a/source/blender/editors/interface/interface_intern.h
+++ b/source/blender/editors/interface/interface_intern.h
@@ -680,6 +680,7 @@ extern bool ui_but_string_eval_number(struct bContext *C,
extern int ui_but_string_get_max_length(uiBut *but);
/* Clear & exit the active button's string. */
extern void ui_but_active_string_clear_and_exit(struct bContext *C, uiBut *but) ATTR_NONNULL();
+extern void ui_but_set_string_interactive(struct bContext *C, uiBut *but, const char *value);
extern uiBut *ui_but_drag_multi_edit_get(uiBut *but);
void ui_def_but_icon(uiBut *but, const int icon, const int flag);
@@ -1031,7 +1032,6 @@ enum {
struct GPUBatch *ui_batch_roundbox_widget_get(void);
struct GPUBatch *ui_batch_roundbox_shadow_get(void);
-void ui_draw_anti_tria_rect(const rctf *rect, char dir, const float color[4]);
void ui_draw_menu_back(struct uiStyle *style, uiBlock *block, rcti *rect);
void ui_draw_popover_back(struct ARegion *region,
struct uiStyle *style,
diff --git a/source/blender/editors/interface/interface_layout.c b/source/blender/editors/interface/interface_layout.c
index e54b261facd..25ba0e13487 100644
--- a/source/blender/editors/interface/interface_layout.c
+++ b/source/blender/editors/interface/interface_layout.c
@@ -351,12 +351,16 @@ static int ui_text_icon_width_ex(uiLayout *layout,
if (layout->alignment != UI_LAYOUT_ALIGN_EXPAND) {
layout->item.flag |= UI_ITEM_FIXED_SIZE;
}
- const uiFontStyle *fstyle = UI_FSTYLE_WIDGET;
+
float margin = pad_factor->text;
if (icon) {
margin += pad_factor->icon;
}
- return UI_fontstyle_string_width(fstyle, name) + (unit_x * margin);
+
+ const float aspect = layout->root->block->aspect;
+ const uiFontStyle *fstyle = UI_FSTYLE_WIDGET;
+ return UI_fontstyle_string_width_with_block_aspect(fstyle, name, aspect) +
+ (int)ceilf(unit_x * margin);
}
return unit_x * 10;
}
diff --git a/source/blender/editors/interface/interface_ops.c b/source/blender/editors/interface/interface_ops.c
index 1a1d52b0425..c962a1107ae 100644
--- a/source/blender/editors/interface/interface_ops.c
+++ b/source/blender/editors/interface/interface_ops.c
@@ -1864,6 +1864,39 @@ static void UI_OT_drop_color(wmOperatorType *ot)
/** \} */
/* -------------------------------------------------------------------- */
+/** \name Drop Name Operator
+ * \{ */
+
+static int drop_name_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
+{
+ uiBut *but = UI_but_active_drop_name_button(C);
+ char *str = RNA_string_get_alloc(op->ptr, "string", NULL, 0, NULL);
+
+ if (str) {
+ ui_but_set_string_interactive(C, but, str);
+ MEM_freeN(str);
+ }
+
+ return OPERATOR_FINISHED;
+}
+
+static void UI_OT_drop_name(wmOperatorType *ot)
+{
+ ot->name = "Drop Name";
+ ot->idname = "UI_OT_drop_name";
+ ot->description = "Drop name to button";
+
+ ot->poll = ED_operator_regionactive;
+ ot->invoke = drop_name_invoke;
+ ot->flag = OPTYPE_UNDO | OPTYPE_INTERNAL;
+
+ RNA_def_string(
+ ot->srna, "string", NULL, 0, "String", "The string value to drop into the button");
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
/** \name UI List Search Operator
* \{ */
@@ -2025,6 +2058,7 @@ void ED_operatortypes_ui(void)
WM_operatortype_append(UI_OT_copy_to_selected_button);
WM_operatortype_append(UI_OT_jump_to_target_button);
WM_operatortype_append(UI_OT_drop_color);
+ WM_operatortype_append(UI_OT_drop_name);
#ifdef WITH_PYTHON
WM_operatortype_append(UI_OT_editsource);
WM_operatortype_append(UI_OT_edittranslation_init);
diff --git a/source/blender/editors/interface/interface_panel.c b/source/blender/editors/interface/interface_panel.c
index a22351eea7e..072362492d8 100644
--- a/source/blender/editors/interface/interface_panel.c
+++ b/source/blender/editors/interface/interface_panel.c
@@ -1550,7 +1550,7 @@ void UI_panel_category_draw_all(ARegion *region, const char *category_id_active)
}
BLF_position(fontid, rct->xmax - text_v_ofs, rct->ymin + tab_v_pad_text, 0.0f);
- BLF_color3ubv(fontid, theme_col_text);
+ BLF_color3ubv(fontid, is_active ? theme_col_text_hi : theme_col_text);
BLF_draw(fontid, category_id_draw, category_draw_len);
GPU_blend(GPU_BLEND_NONE);
diff --git a/source/blender/editors/interface/interface_style.c b/source/blender/editors/interface/interface_style.c
index 6b1ff92a855..92a9f14c77d 100644
--- a/source/blender/editors/interface/interface_style.c
+++ b/source/blender/editors/interface/interface_style.c
@@ -376,6 +376,37 @@ int UI_fontstyle_string_width(const uiFontStyle *fs, const char *str)
return (int)BLF_width(fs->uifont_id, str, BLF_DRAW_STR_DUMMY_MAX);
}
+/**
+ * Return the width of `str` with the spacing & kerning of `fs` with `aspect`
+ * (representing #uiBlock.aspect) applied.
+ *
+ * When calculating text width, the UI layout logic calculate widths without scale,
+ * only applying scale when drawing. This causes problems for fonts since kerning at
+ * smaller sizes often makes them wider than a scaled down version of the larger text.
+ * Resolve this by calculating the text at the on-screen size,
+ * returning the result scaled back to 1:1. See T92361.
+ */
+int UI_fontstyle_string_width_with_block_aspect(const uiFontStyle *fs,
+ const char *str,
+ const float aspect)
+{
+ uiFontStyle fs_buf;
+ if (aspect != 1.0f) {
+ fs_buf = *fs;
+ ui_fontscale(&fs_buf.points, aspect);
+ fs = &fs_buf;
+ }
+
+ int width = UI_fontstyle_string_width(fs, str);
+
+ if (aspect != 1.0f) {
+ /* While in most cases rounding up isn't important, it can make a difference
+ * with small fonts (3px or less), zooming out in the node-editor for e.g. */
+ width = (int)ceilf(width * aspect);
+ }
+ return width;
+}
+
int UI_fontstyle_height_max(const uiFontStyle *fs)
{
UI_fontstyle_set(fs);
diff --git a/source/blender/editors/interface/interface_template_asset_view.cc b/source/blender/editors/interface/interface_template_asset_view.cc
index f27b37a27de..d3ce7ebc3db 100644
--- a/source/blender/editors/interface/interface_template_asset_view.cc
+++ b/source/blender/editors/interface/interface_template_asset_view.cc
@@ -70,6 +70,7 @@ static void asset_view_item_but_drag_set(uiBut *but,
UI_but_drag_set_asset(but,
asset_handle,
BLI_strdup(blend_path),
+ ED_asset_handle_get_metadata(asset_handle),
FILE_ASSET_IMPORT_APPEND,
ED_asset_handle_get_preview_icon_id(asset_handle),
imbuf,
diff --git a/source/blender/editors/interface/interface_template_attribute_search.cc b/source/blender/editors/interface/interface_template_attribute_search.cc
index 0157d0b66a3..85a6147432b 100644
--- a/source/blender/editors/interface/interface_template_attribute_search.cc
+++ b/source/blender/editors/interface/interface_template_attribute_search.cc
@@ -80,9 +80,10 @@ void attribute_search_add_items(StringRefNull str,
break;
}
}
- if (!contained && is_output) {
+ if (!contained) {
dummy_info.name = str;
- UI_search_item_add(seach_items, str.c_str(), &dummy_info, ICON_ADD, 0, 0);
+ UI_search_item_add(
+ seach_items, str.c_str(), &dummy_info, is_output ? ICON_ADD : ICON_NONE, 0, 0);
}
}
@@ -122,4 +123,4 @@ void attribute_search_add_items(StringRefNull str,
BLI_string_search_free(search);
}
-} // namespace blender::ui \ No newline at end of file
+} // namespace blender::ui
diff --git a/source/blender/editors/interface/interface_widgets.c b/source/blender/editors/interface/interface_widgets.c
index e9acc65ed37..3e9042d29a0 100644
--- a/source/blender/editors/interface/interface_widgets.c
+++ b/source/blender/editors/interface/interface_widgets.c
@@ -518,7 +518,7 @@ GPUBatch *ui_batch_roundbox_shadow_get(void)
/** \name Draw Triangle Arrow
* \{ */
-void UI_draw_anti_tria(
+static void draw_anti_tria(
float x1, float y1, float x2, float y2, float x3, float y3, const float color[4])
{
const float tri_arr[3][2] = {{x1, y1}, {x2, y2}, {x3, y3}};
@@ -559,66 +559,31 @@ void UI_draw_icon_tri(float x, float y, char dir, const float color[4])
const float f7 = 0.25 * U.widget_unit;
if (dir == 'h') {
- UI_draw_anti_tria(x - f3, y - f5, x - f3, y + f5, x + f7, y, color);
+ draw_anti_tria(x - f3, y - f5, x - f3, y + f5, x + f7, y, color);
}
else if (dir == 't') {
- UI_draw_anti_tria(x - f5, y - f7, x + f5, y - f7, x, y + f3, color);
+ draw_anti_tria(x - f5, y - f7, x + f5, y - f7, x, y + f3, color);
}
else { /* 'v' = vertical, down. */
- UI_draw_anti_tria(x - f5, y + f3, x + f5, y + f3, x, y - f7, color);
+ draw_anti_tria(x - f5, y + f3, x + f5, y + f3, x, y - f7, color);
}
}
/* triangle 'icon' inside rect */
-void ui_draw_anti_tria_rect(const rctf *rect, char dir, const float color[4])
+static void draw_anti_tria_rect(const rctf *rect, char dir, const float color[4])
{
if (dir == 'h') {
const float half = 0.5f * BLI_rctf_size_y(rect);
- UI_draw_anti_tria(
+ draw_anti_tria(
rect->xmin, rect->ymin, rect->xmin, rect->ymax, rect->xmax, rect->ymin + half, color);
}
else {
const float half = 0.5f * BLI_rctf_size_x(rect);
- UI_draw_anti_tria(
+ draw_anti_tria(
rect->xmin, rect->ymax, rect->xmax, rect->ymax, rect->xmin + half, rect->ymin, color);
}
}
-void UI_draw_anti_fan(float tri_array[][2], uint length, const float color[4])
-{
- float draw_color[4];
-
- copy_v4_v4(draw_color, color);
- draw_color[3] *= 2.0f / WIDGET_AA_JITTER;
-
- GPU_blend(GPU_BLEND_ALPHA);
-
- const uint pos = GPU_vertformat_attr_add(
- immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
-
- immUniformColor4fv(draw_color);
-
- /* for each AA step */
- for (int j = 0; j < WIDGET_AA_JITTER; j++) {
- immBegin(GPU_PRIM_TRI_FAN, length);
- immVertex2f(pos, tri_array[0][0], tri_array[0][1]);
- immVertex2f(pos, tri_array[1][0], tri_array[1][1]);
-
- /* We jitter only the middle of the fan, the extremes are pinned. */
- for (int i = 2; i < length - 1; i++) {
- immVertex2f(pos, tri_array[i][0] + jit[j][0], tri_array[i][1] + jit[j][1]);
- }
-
- immVertex2f(pos, tri_array[length - 1][0], tri_array[length - 1][1]);
- immEnd();
- }
-
- immUnbindProgram();
-
- GPU_blend(GPU_BLEND_NONE);
-}
-
static void widget_init(uiWidgetBase *wtb)
{
wtb->totvert = wtb->halfwayvert = 0;
@@ -1494,7 +1459,7 @@ static void widget_draw_submenu_tria(const uiBut *but,
GPU_blend(GPU_BLEND_ALPHA);
UI_widgetbase_draw_cache_flush();
GPU_blend(GPU_BLEND_NONE);
- ui_draw_anti_tria_rect(&tria_rect, 'h', col);
+ draw_anti_tria_rect(&tria_rect, 'h', col);
}
static void ui_text_clip_give_prev_off(uiBut *but, const char *str)
@@ -3721,7 +3686,7 @@ static void widget_datasetrow(
static void widget_nodesocket(
uiBut *but, uiWidgetColors *wcol, rcti *rect, int UNUSED(state), int UNUSED(roundboxalign))
{
- const int radi = 5;
+ const int radi = 0.25f * BLI_rcti_size_y(rect);
uiWidgetBase wtb;
widget_init(&wtb);
@@ -4632,6 +4597,9 @@ void ui_draw_but(const bContext *C, struct ARegion *region, uiStyle *style, uiBu
switch (but->type) {
case UI_BTYPE_LABEL:
wt = widget_type(UI_WTYPE_ICON_LABEL);
+ if (!(but->flag & UI_HAS_ICON)) {
+ but->drawflag |= UI_BUT_NO_TEXT_PADDING;
+ }
break;
default:
wt = widget_type(UI_WTYPE_ICON);
diff --git a/source/blender/editors/interface/resources.c b/source/blender/editors/interface/resources.c
index ad7c6332ee9..aece2e58f1e 100644
--- a/source/blender/editors/interface/resources.c
+++ b/source/blender/editors/interface/resources.c
@@ -252,10 +252,11 @@ const uchar *UI_ThemeGetColorPtr(bTheme *btheme, int spacetype, int colorid)
case TH_HEADER_ACTIVE:
cp = ts->header;
+ const int factor = 5;
/* Lighten the header color when editor is active. */
- header_active[0] = cp[0] > 245 ? cp[0] - 10 : cp[0] + 10;
- header_active[1] = cp[1] > 245 ? cp[1] - 10 : cp[1] + 10;
- header_active[2] = cp[2] > 245 ? cp[2] - 10 : cp[2] + 10;
+ header_active[0] = cp[0] > 245 ? cp[0] - factor : cp[0] + factor;
+ header_active[1] = cp[1] > 245 ? cp[1] - factor : cp[1] + factor;
+ header_active[2] = cp[2] > 245 ? cp[2] - factor : cp[2] + factor;
header_active[3] = cp[3];
cp = header_active;
break;
diff --git a/source/blender/editors/interface/tree_view.cc b/source/blender/editors/interface/tree_view.cc
index 88aa362deb5..c08fa51d5a5 100644
--- a/source/blender/editors/interface/tree_view.cc
+++ b/source/blender/editors/interface/tree_view.cc
@@ -29,6 +29,7 @@
#include "UI_interface.h"
+#include "WM_api.h"
#include "WM_types.h"
#include "UI_tree_view.hh"
@@ -354,22 +355,18 @@ void AbstractTreeViewItem::is_active(IsActiveFn is_active_fn)
is_active_fn_ = is_active_fn;
}
-bool AbstractTreeViewItem::on_drop(const wmDrag & /*drag*/)
+std::unique_ptr<AbstractTreeViewItemDragController> AbstractTreeViewItem::create_drag_controller()
+ const
{
- /* Do nothing by default. */
- return false;
-}
-
-bool AbstractTreeViewItem::can_drop(const wmDrag & /*drag*/) const
-{
- return false;
+ /* There's no drag controller (and hence no drag support) by default. */
+ return nullptr;
}
-std::string AbstractTreeViewItem::drop_tooltip(const bContext & /*C*/,
- const wmDrag & /*drag*/,
- const wmEvent & /*event*/) const
+std::unique_ptr<AbstractTreeViewItemDropController> AbstractTreeViewItem::create_drop_controller()
+ const
{
- return TIP_("Drop into/onto tree item");
+ /* There's no drop controller (and hence no drop support) by default. */
+ return nullptr;
}
bool AbstractTreeViewItem::can_rename() const
@@ -553,6 +550,12 @@ void AbstractTreeViewItem::change_state_delayed()
activate();
}
}
+/* ---------------------------------------------------------------------- */
+
+AbstractTreeViewItemDropController::AbstractTreeViewItemDropController(AbstractTreeView &tree_view)
+ : tree_view_(tree_view)
+{
+}
/* ---------------------------------------------------------------------- */
@@ -646,7 +649,18 @@ BasicTreeViewItem::BasicTreeViewItem(StringRef label, BIFIconID icon_) : icon(ic
void BasicTreeViewItem::build_row(uiLayout &row)
{
- uiItemL(&row, label_.c_str(), icon);
+ add_label(row);
+}
+
+void BasicTreeViewItem::add_label(uiLayout &layout, StringRefNull label_override)
+{
+ const StringRefNull label = label_override.is_empty() ? StringRefNull(label_) : label_override;
+
+ /* Some padding for labels without collapse chevron and no icon. Looks weird without. */
+ if (icon == ICON_NONE && !is_collapsible()) {
+ uiItemS_ex(&layout, 0.8f);
+ }
+ uiItemL(&layout, label.c_str(), icon);
}
void BasicTreeViewItem::on_activate()
@@ -680,19 +694,53 @@ bool UI_tree_view_item_matches(const uiTreeViewItemHandle *a_handle,
return a.matches_including_parents(b);
}
-bool UI_tree_view_item_can_drop(const uiTreeViewItemHandle *item_, const wmDrag *drag)
+/**
+ * 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(bContext *C, uiTreeViewItemHandle *item_)
+{
+ const AbstractTreeViewItem &item = reinterpret_cast<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);
+ return true;
+}
+
+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 item.can_drop(*drag);
+ 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);
}
-char *UI_tree_view_item_drop_tooltip(const uiTreeViewItemHandle *item_,
- const bContext *C,
- const wmDrag *drag,
- const wmEvent *event)
+char *UI_tree_view_item_drop_tooltip(const uiTreeViewItemHandle *item_, const wmDrag *drag)
{
const AbstractTreeViewItem &item = reinterpret_cast<const AbstractTreeViewItem &>(*item_);
- return BLI_strdup(item.drop_tooltip(*C, *drag, *event).c_str());
+ const std::unique_ptr<AbstractTreeViewItemDropController> drop_controller =
+ item.create_drop_controller();
+ if (!drop_controller) {
+ return nullptr;
+ }
+
+ return BLI_strdup(drop_controller->drop_tooltip(*drag).c_str());
}
/**
@@ -702,10 +750,13 @@ char *UI_tree_view_item_drop_tooltip(const uiTreeViewItemHandle *item_,
bool UI_tree_view_item_drop_handle(uiTreeViewItemHandle *item_, const ListBase *drags)
{
AbstractTreeViewItem &item = reinterpret_cast<AbstractTreeViewItem &>(*item_);
+ std::unique_ptr<AbstractTreeViewItemDropController> drop_controller =
+ item.create_drop_controller();
+ const char *disabled_hint_dummy = nullptr;
LISTBASE_FOREACH (const wmDrag *, drag, drags) {
- if (item.can_drop(*drag)) {
- return item.on_drop(*drag);
+ if (drop_controller->can_drop(*drag, &disabled_hint_dummy)) {
+ return drop_controller->on_drop(*drag);
}
}
diff --git a/source/blender/editors/interface/view2d.c b/source/blender/editors/interface/view2d.c
index ca96fde9810..eea6512f0f8 100644
--- a/source/blender/editors/interface/view2d.c
+++ b/source/blender/editors/interface/view2d.c
@@ -32,6 +32,7 @@
#include "DNA_userdef_types.h"
#include "BLI_array.h"
+#include "BLI_easing.h"
#include "BLI_link_utils.h"
#include "BLI_listbase.h"
#include "BLI_math.h"
@@ -166,7 +167,7 @@ static void view2d_masks(View2D *v2d, const rcti *mask_scroll)
scroll = view2d_scroll_mapped(v2d->scroll);
- /* scrollers are based off regionsize
+ /* Scrollers are based off region-size:
* - they can only be on one to two edges of the region they define
* - if they overlap, they must not occupy the corners (which are reserved for other widgets)
*/
@@ -1291,6 +1292,114 @@ void UI_view2d_multi_grid_draw(
immUnbindProgram();
}
+static void grid_axis_start_and_count(
+ const float step, const float min, const float max, float *r_start, int *r_count)
+{
+ *r_start = min;
+ if (*r_start < 0.0f) {
+ *r_start += -(float)fmod(min, step);
+ }
+ else {
+ *r_start += step - (float)fabs(fmod(min, step));
+ }
+
+ if (*r_start > max) {
+ *r_count = 0;
+ }
+ else {
+ *r_count = (max - *r_start) / step + 1;
+ }
+}
+
+typedef struct DotGridLevelInfo {
+ /* The factor applied to the #min_step argument. This could be easily computed in runtime,
+ * but seeing it together with the other values is helpful. */
+ float step_factor;
+ /* The normalized zoom level at which the grid level starts to fade in.
+ * At lower zoom levels, the points will not be visible and the level will be skipped. */
+ float fade_in_start_zoom;
+ /* The normalized zoom level at which the grid finishes fading in.
+ * At higher zoom levels, the points will be opaque. */
+ float fade_in_end_zoom;
+} DotGridLevelInfo;
+
+static const DotGridLevelInfo level_info[9] = {
+ {6.4f, -0.1f, 0.01f},
+ {3.2f, 0.0f, 0.025f},
+ {1.6f, 0.025f, 0.15f},
+ {0.8f, 0.05f, 0.2f},
+ {0.4f, 0.1f, 0.25f},
+ {0.2f, 0.125f, 0.3f},
+ {0.1f, 0.25f, 0.5f},
+ {0.05f, 0.7f, 0.9f},
+ {0.025f, 0.6f, 0.9f},
+};
+
+/**
+ * Draw a multi-level grid of dots, with a dynamic number of levels based on the fading.
+ *
+ * \param grid_color_id: The theme color used for the points. Faded dynamically based on zoom.
+ * \param min_step: The base size of the grid. At different zoom levels, the visible grid may have
+ * a larger step size.
+ * \param grid_levels: The maximum grid depth. Larger grid levels will subdivide the grid more.
+ */
+void UI_view2d_dot_grid_draw(const View2D *v2d,
+ const int grid_color_id,
+ const float min_step,
+ const int grid_levels)
+{
+ BLI_assert(grid_levels > 0 && grid_levels < 10);
+ const float zoom_x = (float)(BLI_rcti_size_x(&v2d->mask) + 1) / BLI_rctf_size_x(&v2d->cur);
+ const float zoom_normalized = (zoom_x - v2d->minzoom) / (v2d->maxzoom - v2d->minzoom);
+
+ GPUVertFormat *format = immVertexFormat();
+ const uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ const uint color_id = GPU_vertformat_attr_add(format, "color", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_2D_FLAT_COLOR);
+ GPU_point_size(3.0f * UI_DPI_FAC);
+
+ float color[4];
+ UI_GetThemeColor3fv(grid_color_id, color);
+
+ for (int level = 0; level < grid_levels; level++) {
+ const DotGridLevelInfo *info = &level_info[level];
+ const float step = min_step * info->step_factor * U.widget_unit;
+
+ const float alpha_factor = (zoom_normalized - info->fade_in_start_zoom) /
+ (info->fade_in_end_zoom - info->fade_in_start_zoom);
+ color[3] = clamp_f(BLI_easing_cubic_ease_in_out(alpha_factor, 0.0f, 1.0f, 1.0f), 0.0f, 1.0f);
+ if (color[3] == 0.0f) {
+ break;
+ }
+
+ int count_x;
+ float start_x;
+ grid_axis_start_and_count(step, v2d->cur.xmin, v2d->cur.xmax, &start_x, &count_x);
+ int count_y;
+ float start_y;
+ grid_axis_start_and_count(step, v2d->cur.ymin, v2d->cur.ymax, &start_y, &count_y);
+ if (count_x == 0 || count_y == 0) {
+ continue;
+ }
+
+ immBegin(GPU_PRIM_POINTS, count_x * count_y);
+
+ /* Theoretically drawing on top of lower grid levels could be avoided, but it would also
+ * increase the complexity of this loop, which isn't worth the time at the moment. */
+ for (int i_y = 0; i_y < count_y; i_y++) {
+ const float y = start_y + step * i_y;
+ for (int i_x = 0; i_x < count_x; i_x++) {
+ const float x = start_x + step * i_x;
+ immAttr4fv(color_id, color);
+ immVertex2f(pos, x, y);
+ }
+ }
+
+ immEnd();
+ }
+
+ immUnbindProgram();
+}
/** \} */
/* -------------------------------------------------------------------- */
diff --git a/source/blender/editors/interface/view2d_edge_pan.c b/source/blender/editors/interface/view2d_edge_pan.c
index a49666ebbd3..8d8b9a4fe48 100644
--- a/source/blender/editors/interface/view2d_edge_pan.c
+++ b/source/blender/editors/interface/view2d_edge_pan.c
@@ -92,6 +92,8 @@ void UI_view2d_edge_pan_init(bContext *C,
vpd->delay = delay;
vpd->zoom_influence = zoom_influence;
+ vpd->enabled = false;
+
/* Calculate translation factor, based on size of view. */
const float winx = (float)(BLI_rcti_size_x(&vpd->region->winrct) + 1);
const float winy = (float)(BLI_rcti_size_y(&vpd->region->winrct) + 1);
@@ -227,9 +229,16 @@ void UI_view2d_edge_pan_apply(bContext *C, View2DEdgePanData *vpd, const int xy[
BLI_rcti_pad(&inside_rect, -vpd->inside_pad * U.widget_unit, -vpd->inside_pad * U.widget_unit);
BLI_rcti_pad(&outside_rect, vpd->outside_pad * U.widget_unit, vpd->outside_pad * U.widget_unit);
+ /* Check if we can actually start the edge pan (e.g. adding nodes outside the view will start
+ * disabled). */
+ if (BLI_rcti_isect_pt_v(&inside_rect, xy)) {
+ /* We are inside once, can start. */
+ vpd->enabled = true;
+ }
+
int pan_dir_x = 0;
int pan_dir_y = 0;
- if ((vpd->outside_pad == 0) || BLI_rcti_isect_pt_v(&outside_rect, xy)) {
+ if (vpd->enabled && ((vpd->outside_pad == 0) || BLI_rcti_isect_pt_v(&outside_rect, xy))) {
/* Find whether the mouse is beyond X and Y edges. */
if (xy[0] > inside_rect.xmax) {
pan_dir_x = 1;