UI: Area Maintenance Post Op Transitions

While performance area maintenance operations (split, join, docking)
some areas get highlighted and some are shown darkened to indicate they
will be removed. This PR just adds transitions AFTER completion that
eases out this highlighting. Make it less jarring and a little easier
to follow what happens.

Pull Request: https://projects.blender.org/blender/blender/pulls/140628
This commit is contained in:
Harley Acheson
2025-06-20 03:31:16 +02:00
committed by Harley Acheson
parent fe0fe0a5ed
commit c793bfda23
5 changed files with 146 additions and 1 deletions

View File

@@ -22,6 +22,7 @@
#include "BLI_listbase.h"
#include "BLI_math_vector.h"
#include "BLI_rect.h"
#include "BLI_time.h"
#include "BLT_translation.hh"
@@ -667,3 +668,81 @@ void screen_draw_split_preview(ScrArea *area, const eScreenAxis dir_axis, const
}
UI_draw_roundbox_4fv(&rect, true, 0.0f, border);
}
struct AreaAnimateHighlightData {
wmWindow *win;
bScreen *screen;
rctf rect;
float inner[4];
float outline[4];
double start_time;
double end_time;
void *draw_callback;
};
static void area_animate_highlight_cb(const wmWindow * /*win*/, void *userdata)
{
const AreaAnimateHighlightData *data = static_cast<const AreaAnimateHighlightData *>(userdata);
double now = BLI_time_now_seconds();
if (now > data->end_time) {
WM_draw_cb_exit(data->win, data->draw_callback);
MEM_freeN(const_cast<AreaAnimateHighlightData *>(data));
data = nullptr;
return;
}
const float factor = pow((now - data->start_time) / (data->end_time - data->start_time), 2);
const bool do_inner = data->inner[3] > 0.0f;
const bool do_outline = data->outline[3] > 0.0f;
float inner_color[4];
if (do_inner) {
inner_color[0] = data->inner[0];
inner_color[1] = data->inner[1];
inner_color[2] = data->inner[2];
inner_color[3] = (1.0f - factor) * data->inner[3];
}
float outline_color[4];
if (do_outline) {
outline_color[0] = data->outline[0];
outline_color[1] = data->outline[1];
outline_color[2] = data->outline[2];
outline_color[3] = (1.0f - factor) * data->outline[3];
}
UI_draw_roundbox_corner_set(UI_CNR_ALL);
UI_draw_roundbox_4fv_ex(&data->rect,
do_inner ? inner_color : nullptr,
nullptr,
1.0f,
do_outline ? outline_color : nullptr,
U.pixelsize,
EDITORRADIUS);
data->screen->do_refresh = true;
}
void screen_animate_area_highlight(wmWindow *win,
bScreen *screen,
const rcti *rect,
float inner[4],
float outline[4],
float seconds)
{
AreaAnimateHighlightData *data = MEM_callocN<AreaAnimateHighlightData>(
"screen_animate_area_highlight");
data->win = win;
data->screen = screen;
BLI_rctf_rcti_copy(&data->rect, rect);
if (inner) {
copy_v4_v4(data->inner, inner);
}
if (outline) {
copy_v4_v4(data->outline, outline);
}
data->start_time = BLI_time_now_seconds();
data->end_time = data->start_time + seconds;
data->draw_callback = WM_draw_cb_activate(win, area_animate_highlight_cb, data);
}

View File

@@ -564,7 +564,18 @@ static bool screen_area_join_ex(bContext *C,
if (close_all_remainders || offset1 < 0 || offset2 > 0) {
/* Close both if trimming `sa1`. */
float inner[4] = {0.0f, 0.0f, 0.0f, 0.7f};
if (side1) {
rcti rect = {side1->v1->vec.x, side1->v3->vec.x, side1->v1->vec.y, side1->v3->vec.y};
screen_animate_area_highlight(
CTX_wm_window(C), CTX_wm_screen(C), &rect, inner, nullptr, AREA_CLOSE_FADEOUT);
}
screen_area_close(C, reports, screen, side1);
if (side2) {
rcti rect = {side2->v1->vec.x, side2->v3->vec.x, side2->v1->vec.y, side2->v3->vec.y};
screen_animate_area_highlight(
CTX_wm_window(C), CTX_wm_screen(C), &rect, inner, nullptr, AREA_CLOSE_FADEOUT);
}
screen_area_close(C, reports, screen, side2);
}
else {

View File

@@ -80,6 +80,11 @@ enum class AreaDockTarget {
/* Less expansion needed for global edges. */
#define BORDERPADDING_GLOBAL (3.0f * UI_SCALE_FAC)
#define AREA_CLOSE_FADEOUT 0.22f /* seconds */
#define AREA_DOCK_FADEOUT 0.20f /* seconds */
#define AREA_JOIN_FADEOUT 0.15f /* seconds */
#define AREA_SPLIT_FADEOUT 0.15f /* seconds */
/* `area.cc` */
/**
@@ -112,6 +117,13 @@ void screen_draw_move_highlight(const wmWindow *win, bScreen *screen, eScreenAxi
void screen_draw_region_scale_highlight(ARegion *region);
void screen_animate_area_highlight(wmWindow *win,
bScreen *screen,
const rcti *rect,
float inner[4],
float outline[4],
float seconds);
/* `screen_edit.cc` */
/**

View File

@@ -1583,6 +1583,10 @@ static wmOperatorStatus area_close_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
float inner[4] = {0.0f, 0.0f, 0.0f, 0.7f};
screen_animate_area_highlight(
CTX_wm_window(C), CTX_wm_screen(C), &area->totrct, inner, nullptr, AREA_CLOSE_FADEOUT);
if (!screen_area_close(C, op->reports, screen, area)) {
BKE_report(op->reports, RPT_ERROR, "Unable to close area");
return OPERATOR_CANCELLED;
@@ -2597,6 +2601,14 @@ static wmOperatorStatus area_split_modal(bContext *C, wmOperator *op, const wmEv
case LEFTMOUSE:
if (sd->previewmode) {
float inner[4] = {1.0f, 1.0f, 1.0f, 0.1f};
float outline[4] = {1.0f, 1.0f, 1.0f, 0.3f};
screen_animate_area_highlight(CTX_wm_window(C),
CTX_wm_screen(C),
&sd->sarea->totrct,
inner,
outline,
AREA_SPLIT_FADEOUT);
area_split_apply(C, op);
area_split_exit(C, op);
return OPERATOR_FINISHED;
@@ -3819,6 +3831,22 @@ static bool area_join_apply(bContext *C, wmOperator *op)
bScreen *screen = CTX_wm_screen(C);
/* Rect of the combined areas. */
const bool vertical = SCREEN_DIR_IS_VERTICAL(jd->dir);
rcti combined{};
combined.xmin = vertical ? std::max(jd->sa1->totrct.xmin, jd->sa2->totrct.xmin) :
std::min(jd->sa1->totrct.xmin, jd->sa2->totrct.xmin);
combined.xmax = vertical ? std::min(jd->sa1->totrct.xmax, jd->sa2->totrct.xmax) :
std::max(jd->sa1->totrct.xmax, jd->sa2->totrct.xmax);
combined.ymin = vertical ? std::min(jd->sa1->totrct.ymin, jd->sa2->totrct.ymin) :
std::max(jd->sa1->totrct.ymin, jd->sa2->totrct.ymin);
combined.ymax = vertical ? std::max(jd->sa1->totrct.ymax, jd->sa2->totrct.ymax) :
std::min(jd->sa1->totrct.ymax, jd->sa2->totrct.ymax);
float inner[4] = {1.0f, 1.0f, 1.0f, 0.1f};
float outline[4] = {1.0f, 1.0f, 1.0f, 0.3f};
screen_animate_area_highlight(
CTX_wm_window(C), screen, &combined, inner, outline, AREA_JOIN_FADEOUT);
if (!screen_area_join(C, op->reports, screen, jd->sa1, jd->sa2)) {
return false;
}
@@ -3971,6 +3999,13 @@ void static area_docking_apply(bContext *C, wmOperator *op)
return;
}
float inner[4] = {1.0f, 1.0f, 1.0f, 0.15f};
float outline[4] = {1.0f, 1.0f, 1.0f, 0.4f};
jd->sa2->flag |= AREA_FLAG_REGION_SIZE_UPDATE;
ED_area_update_region_sizes(CTX_wm_manager(C), jd->win2, jd->sa2);
screen_animate_area_highlight(
jd->win2, CTX_wm_screen(C), &jd->sa2->totrct, inner, outline, AREA_DOCK_FADEOUT);
if (!aligned_neighbors || !screen_area_join(C, op->reports, CTX_wm_screen(C), jd->sa1, jd->sa2))
{
ED_area_swapspace(C, jd->sa2, jd->sa1);
@@ -3984,6 +4019,9 @@ void static area_docking_apply(bContext *C, wmOperator *op)
WM_window_get_active_screen(jd->win2)->active_region = nullptr;
}
else {
float inner[4] = {0.0f, 0.0f, 0.0f, 0.7f};
screen_animate_area_highlight(
jd->win1, CTX_wm_screen(C), &jd->sa1->totrct, inner, nullptr, AREA_CLOSE_FADEOUT);
screen_area_close(C, op->reports, CTX_wm_screen(C), jd->sa1);
}
}
@@ -4416,6 +4454,10 @@ static wmOperatorStatus area_join_modal(bContext *C, wmOperator *op, const wmEve
else if (jd->sa1 && jd->sa1 == jd->sa2) {
/* Same area so split. */
if (area_split_allowed(jd->sa1, jd->split_dir) && jd->split_fac > 0.0001) {
float inner[4] = {1.0f, 1.0f, 1.0f, 0.1f};
float outline[4] = {1.0f, 1.0f, 1.0f, 0.3f};
screen_animate_area_highlight(
jd->win1, CTX_wm_screen(C), &jd->sa1->totrct, inner, outline, AREA_SPLIT_FADEOUT);
jd->sa2 = area_split(jd->win2,
WM_window_get_active_screen(jd->win1),
jd->sa1,

View File

@@ -632,7 +632,8 @@ void WM_draw_cb_exit(wmWindow *win, void *handle)
static void wm_draw_callbacks(wmWindow *win)
{
LISTBASE_FOREACH (WindowDrawCB *, wdc, &win->drawcalls) {
/* Allow callbacks to remove themselves. */
LISTBASE_FOREACH_MUTABLE (WindowDrawCB *, wdc, &win->drawcalls) {
wdc->draw(win, wdc->customdata);
}
}