UI: Refactor how dragging onto text buttons works, fixing issues

There was a bunch of special handling to support dropping data-blocks onto
string or search-menu buttons, to change the value of these. This refactor
makes that case use the normal drop-box design, where an operator is executed
on drop that gets input properties set by the drop-box. This should also make
it easier to add support for dragging assets into these buttons.

In addition this fixes an issue: Two tooltips were shown when dragging assets
over text buttons. None should be shown, because this isn't supported.
This commit is contained in:
Julian Eisel 2021-10-27 15:50:14 +02:00
parent 0d8f1414a2
commit b73993bcc9
6 changed files with 93 additions and 59 deletions

View File

@ -788,7 +788,8 @@ void UI_but_drag_set_value(uiBut *but);
void UI_but_drag_set_image(
uiBut *but, const char *path, int icon, struct ImBuf *imb, float scale, const bool use_free);
bool UI_but_active_drop_name(struct bContext *C);
uiBut *UI_but_active_drop_name_button(const struct bContext *C);
bool UI_but_active_drop_name(const struct bContext *C);
bool UI_but_active_drop_color(struct bContext *C);
void UI_but_flag_enable(uiBut *but, int flag);

View File

@ -24,6 +24,8 @@
#include "MEM_guardedalloc.h"
#include "RNA_access.h"
#include "WM_api.h"
#include "UI_interface.h"
@ -59,6 +61,21 @@ static char *ui_tree_view_drop_tooltip(bContext *C,
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);
@ -69,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);
}

View File

@ -2442,39 +2442,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
* \{ */
@ -2672,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)
@ -3024,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) {
@ -7949,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) &&
@ -7998,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) &&
@ -11716,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)

View File

@ -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);

View File

@ -1863,6 +1863,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);

View File

@ -821,10 +821,7 @@ static void wm_drag_draw_tooltip(bContext *C, wmWindow *win, wmDrag *drag, const
const char *tooltip = NULL;
bool free_tooltip = false;
if (UI_but_active_drop_name(C)) {
tooltip = IFACE_("Paste name");
}
else if (drag->active_dropbox) {
if (drag->active_dropbox) {
tooltip = dropbox_tooltip(C, drag, xy, drag->active_dropbox);
free_tooltip = true;
}
@ -907,7 +904,6 @@ void wm_drags_draw(bContext *C, wmWindow *win)
xy[1] = win->eventstate->xy[1];
}
/* Set a region. It is used in the `UI_but_active_drop_name`. */
bScreen *screen = CTX_wm_screen(C);
ScrArea *area = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, UNPACK2(xy));
ARegion *region = BKE_area_find_region_xy(area, RGN_TYPE_ANY, UNPACK2(xy));