Fix T82417: Panels draw below others while animating after drag

This adds a new runtime flag for panels that is set during the entire
drag and animation operation. The flag is set recursively so that
sub-panels know to draw on top too.

Note that this also replaces most of the fixes in 1960b8a361 and
8e08d80e52 (D7462) with a more "built-in" solution.
This commit is contained in:
Hans Goudey 2020-11-04 18:02:27 -06:00
parent 6c3849ea08
commit 86bdc959a3
Notes: blender-bot 2023-02-14 08:58:01 +01:00
Referenced by issue #82431, Not able to resize sculpting brushes toolshelf using pen tablet.
Referenced by issue #82417, Panels draw below others during animation after dragging
1 changed files with 39 additions and 31 deletions

View File

@ -85,6 +85,11 @@ typedef enum uiPanelRuntimeFlag {
PANEL_USE_CLOSED_FROM_SEARCH = (1 << 8),
/** The Panel was before the start of the current / latest layout pass. */
PANEL_WAS_CLOSED = (1 << 9),
/**
* Set when the panel is being dragged and while it animates back to its aligned
* position. Unlike #PANEL_STATE_ANIMATION, this is applied to sub-panels as well.
*/
PANEL_IS_DRAG_DROP = (1 << 10),
} uiPanelRuntimeFlag;
/* The state of the mouse position relative to the panel. */
@ -108,7 +113,6 @@ typedef struct uiHandlePanelData {
double starttime;
/* Dragging. */
bool is_drag_drop;
int startx, starty;
int startofsx, startofsy;
float start_cur_xmin, start_cur_ymin;
@ -618,6 +622,18 @@ static bool panel_set_flag_recursive(Panel *panel, int flag, bool value)
return changed;
}
/**
* Set runtime flag state for a panel and its sub-panels.
*/
static void panel_set_runtime_flag_recursive(Panel *panel, int flag, bool value)
{
SET_FLAG_FROM_TEST(panel->runtime_flag, value, flag);
LISTBASE_FOREACH (Panel *, sub_panel, &panel->children) {
panel_set_runtime_flag_recursive(sub_panel, flag, value);
}
}
static void panels_collapse_all(ARegion *region, const Panel *from_panel)
{
const bool has_category_tabs = UI_panel_category_is_visible(region);
@ -1024,14 +1040,14 @@ void UI_panels_draw(const bContext *C, ARegion *region)
/* Draw in reverse order, because #uiBlocks are added in reverse order
* and we need child panels to draw on top. */
LISTBASE_FOREACH_BACKWARD (uiBlock *, block, &region->uiblocks) {
if (block->active && block->panel && !(block->panel->flag & PNL_SELECT) &&
if (block->active && block->panel && !UI_panel_is_dragging(block->panel) &&
!UI_block_is_search_only(block)) {
UI_block_draw(C, block);
}
}
LISTBASE_FOREACH_BACKWARD (uiBlock *, block, &region->uiblocks) {
if (block->active && block->panel && (block->panel->flag & PNL_SELECT) &&
if (block->active && block->panel && UI_panel_is_dragging(block->panel) &&
!UI_block_is_search_only(block)) {
UI_block_draw(C, block);
}
@ -1605,14 +1621,9 @@ static int get_panel_real_ofsy(Panel *panel)
return panel->ofsy;
}
bool UI_panel_is_dragging(const struct Panel *panel)
bool UI_panel_is_dragging(const Panel *panel)
{
uiHandlePanelData *data = panel->activedata;
if (!data) {
return false;
}
return data->is_drag_drop;
return panel->runtime_flag & PANEL_IS_DRAG_DROP;
}
/**
@ -1834,15 +1845,13 @@ static void ui_do_animate(bContext *C, Panel *panel)
}
if (fac >= 1.0f) {
/* Store before data is freed. */
const bool is_drag_drop = data->is_drag_drop;
panel_activate_state(C, panel, PANEL_STATE_EXIT);
if (is_drag_drop) {
/* Note: doing this in #panel_activate_state would require removing `const` for context in
* many other places. */
if (UI_panel_is_dragging(panel)) {
/* Note: doing this in #panel_activate_state would require
* removing `const` for context in many other places. */
reorder_instanced_panel_list(C, region, panel);
}
panel_activate_state(C, panel, PANEL_STATE_EXIT);
return;
}
}
@ -1851,7 +1860,7 @@ static void panels_layout_begin_clear_flags(ListBase *lb)
{
LISTBASE_FOREACH (Panel *, panel, lb) {
/* Flags to copy over to the next layout pass. */
const short flag_copy = PANEL_USE_CLOSED_FROM_SEARCH;
const short flag_copy = PANEL_USE_CLOSED_FROM_SEARCH | PANEL_IS_DRAG_DROP;
const bool was_active = panel->runtime_flag & PANEL_ACTIVE;
const bool was_closed = UI_panel_is_closed(panel);
@ -2567,15 +2576,20 @@ static void panel_activate_state(const bContext *C, Panel *panel, uiHandlePanelS
return;
}
const bool was_drag_drop = (data && data->state == PANEL_STATE_DRAG);
/* Set selection state for the panel and its sub-panels, which need to know they are selected
* too so they can be drawn above their parent when it's dragged. */
if (state == PANEL_STATE_EXIT || state == PANEL_STATE_ANIMATION) {
/*
* Note on "select" and "drag drop" flags:
* First, the panel is "picked up" and both flags are set. Then when the mouse releases
* and the panel starts animating to its aligned position, PNL_SELECT is unset. When the
* animation finishes, PANEL_IS_DRAG_DROP is cleared. */
if (state == PANEL_STATE_DRAG) {
panel_set_flag_recursive(panel, PNL_SELECT, true);
panel_set_runtime_flag_recursive(panel, PANEL_IS_DRAG_DROP, true);
}
else if (state == PANEL_STATE_ANIMATION) {
panel_set_flag_recursive(panel, PNL_SELECT, false);
}
else {
panel_set_flag_recursive(panel, PNL_SELECT, true);
else if (state == PANEL_STATE_EXIT) {
panel_set_runtime_flag_recursive(panel, PANEL_IS_DRAG_DROP, false);
}
if (data && data->animtimer) {
@ -2617,12 +2631,6 @@ static void panel_activate_state(const bContext *C, Panel *panel, uiHandlePanelS
data->start_cur_xmin = region->v2d.cur.xmin;
data->start_cur_ymin = region->v2d.cur.ymin;
data->starttime = PIL_check_seconds_timer();
/* Remember drag drop state even when animating to the aligned position after dragging. */
data->is_drag_drop = was_drag_drop;
if (state == PANEL_STATE_DRAG) {
data->is_drag_drop = true;
}
}
ED_region_tag_redraw(region);