Blender V5.0
screen_draw.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
8
9#include "ED_screen.hh"
10#include "ED_screen_types.hh"
11
12#include "GPU_batch_presets.hh"
13#include "GPU_immediate.hh"
14#include "GPU_platform.hh"
15#include "GPU_state.hh"
16
17#include "BKE_global.hh"
18#include "BKE_screen.hh"
19
20#include "BLF_api.hh"
21
22#include "BLI_listbase.h"
23#include "BLI_math_color.h"
24#include "BLI_math_vector.h"
25#include "BLI_rect.h"
26#include "BLI_time.h"
27
28#include "BLT_translation.hh"
29
30#include "WM_api.hh"
31
32#include "UI_interface.hh"
33#include "UI_resources.hh"
34
35#include "screen_intern.hh"
36
37#define CORNER_RESOLUTION 3
38
39static void do_vert_pair(blender::gpu::VertBuf *vbo, uint pos, uint *vidx, int corner, int i)
40{
41 float inter[2];
42 inter[0] = cosf(corner * M_PI_2 + (i * M_PI_2 / (CORNER_RESOLUTION - 1.0f)));
43 inter[1] = sinf(corner * M_PI_2 + (i * M_PI_2 / (CORNER_RESOLUTION - 1.0f)));
44
45 /* Snap point to edge */
46 float div = 1.0f / max_ff(fabsf(inter[0]), fabsf(inter[1]));
47 float exter[2];
48 mul_v2_v2fl(exter, inter, div);
49 exter[0] = roundf(exter[0]);
50 exter[1] = roundf(exter[1]);
51
52 if (i == 0 || i == (CORNER_RESOLUTION - 1)) {
53 copy_v2_v2(inter, exter);
54 }
55
56 /* Small offset to be able to tell inner and outer vertex apart inside the shader.
57 * Edge width is specified in the shader. */
58 mul_v2_fl(inter, 1.0f - 0.0001f);
59 mul_v2_fl(exter, 1.0f);
60
61 GPU_vertbuf_attr_set(vbo, pos, (*vidx)++, inter);
62 GPU_vertbuf_attr_set(vbo, pos, (*vidx)++, exter);
63}
64
65static blender::gpu::Batch *batch_screen_edges_get(int *corner_len)
66{
67 static blender::gpu::Batch *screen_edges_batch = nullptr;
68
69 if (screen_edges_batch == nullptr) {
71 uint pos = GPU_vertformat_attr_add(&format, "pos", blender::gpu::VertAttrType::SFLOAT_32_32);
72
75
76 uint vidx = 0;
77 for (int corner = 0; corner < 4; corner++) {
78 for (int c = 0; c < CORNER_RESOLUTION; c++) {
79 do_vert_pair(vbo, pos, &vidx, corner, c);
80 }
81 }
82 /* close the loop */
83 do_vert_pair(vbo, pos, &vidx, 0, 0);
84
85 screen_edges_batch = GPU_batch_create_ex(GPU_PRIM_TRI_STRIP, vbo, nullptr, GPU_BATCH_OWNS_VBO);
86 gpu_batch_presets_register(screen_edges_batch);
87 }
88
89 if (corner_len) {
90 *corner_len = CORNER_RESOLUTION * 2;
91 }
92 return screen_edges_batch;
93}
94
95#undef CORNER_RESOLUTION
96
100static void drawscredge_area(const ScrArea &area, float edge_thickness)
101{
102 rctf rect;
103 BLI_rctf_rcti_copy(&rect, &area.totrct);
104 BLI_rctf_pad(&rect, edge_thickness, edge_thickness);
105
106 blender::gpu::Batch *batch = batch_screen_edges_get(nullptr);
108 GPU_batch_uniform_4fv(batch, "rect", (float *)&rect);
110}
111
113{
115 screen->do_draw = false;
116
117 if (screen->state != SCREENNORMAL) {
118 return;
119 }
120
121 if (BLI_listbase_is_single(&screen->areabase) && win->global_areas.areabase.first == nullptr) {
122 /* Do not show edges on windows without global areas and with only one editor. */
123 return;
124 }
125
126 ARegion *region = screen->active_region;
127 ScrArea *active_area = nullptr;
128
129 if (region) {
130 /* Find active area from active region. */
131 const int pos[2] = {BLI_rcti_cent_x(&region->winrct), BLI_rcti_cent_y(&region->winrct)};
132 active_area = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, pos);
133 }
134
135 if (!active_area) {
136 LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
137 AZone *zone = ED_area_actionzone_find_xy(area, win->eventstate->xy);
138 /* Get area from action zone, if not scroll-bar. */
139 if (zone && zone->type != AZONE_REGION_SCROLL) {
140 active_area = area;
141 break;
142 }
143 }
144 }
145
146 if (G.moving & G_TRANSFORM_WM) {
147 active_area = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, win->eventstate->xy);
148 /* We don't want an active area when resizing, otherwise outline for active area flickers, see:
149 * #136314. */
150 if (active_area && !BLI_listbase_is_empty(&win->drawcalls)) {
151 active_area = nullptr;
152 }
153 }
154
155 rcti scissor_rect;
156 BLI_rcti_init_minmax(&scissor_rect);
157 LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
158 BLI_rcti_do_minmax_v(&scissor_rect, blender::int2{area->v1->vec.x, area->v1->vec.y});
159 BLI_rcti_do_minmax_v(&scissor_rect, blender::int2{area->v3->vec.x, area->v3->vec.y});
160 }
161
163 /* For some reason, on linux + Intel UHD Graphics 620 the driver
164 * hangs if we don't flush before this. (See #57455) */
165 GPU_flush();
166 }
167
168 GPU_scissor(scissor_rect.xmin,
169 scissor_rect.ymin,
170 BLI_rcti_size_x(&scissor_rect) + 1,
171 BLI_rcti_size_y(&scissor_rect) + 1);
172 GPU_scissor_test(true);
173
174 float col[4];
176
177 const float edge_thickness = float(U.border_width) * UI_SCALE_FAC;
178
179 /* Entire width of the evaluated outline as far as the shader is concerned. */
180 const float shader_scale = edge_thickness + EDITORRADIUS;
181 const float corner_coverage[10] = {
182 0.144f, 0.25f, 0.334f, 0.40f, 0.455, 0.5, 0.538, 0.571, 0.6, 0.625f};
183 const float shader_width = corner_coverage[U.border_width - 1];
184
186
187 int verts_per_corner = 0;
188 blender::gpu::Batch *batch = batch_screen_edges_get(&verts_per_corner);
189
191 GPU_batch_uniform_1i(batch, "cornerLen", verts_per_corner);
192 GPU_batch_uniform_1f(batch, "scale", shader_scale);
193 GPU_batch_uniform_1f(batch, "width", shader_width);
195
196 LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
197 drawscredge_area(*area, edge_thickness);
198 }
199
200 float outline1[4];
201 float outline2[4];
202 rctf bounds;
203 /* Outset by 1/2 pixel, regardless of UI scale or pixel size. #141550. */
204 const float padding = 0.5f;
208 LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
209 BLI_rctf_rcti_copy(&bounds, &area->totrct);
212 nullptr,
213 nullptr,
214 1.0f,
215 (area == active_area) ? outline2 : outline1,
216 U.pixelsize,
218 }
219
221 GPU_scissor_test(false);
222}
223
225 bScreen *screen,
226 eScreenAxis dir_axis,
227 float anim_factor)
228{
229 rctf rect = {SHRT_MAX, SHRT_MIN, SHRT_MAX, SHRT_MIN};
230
231 LISTBASE_FOREACH (const ScrEdge *, edge, &screen->edgebase) {
232 if (edge->v1->editflag && edge->v2->editflag) {
233 if (dir_axis == SCREEN_AXIS_H) {
234 rect.xmin = std::min({rect.xmin, float(edge->v1->vec.x), float(edge->v2->vec.x)});
235 rect.xmax = std::max({rect.xmax, float(edge->v1->vec.x), float(edge->v2->vec.x)});
236 rect.ymin = rect.ymax = float(edge->v1->vec.y);
237 }
238 else {
239 rect.ymin = std::min({rect.ymin, float(edge->v1->vec.y), float(edge->v2->vec.y)});
240 rect.ymax = std::max({rect.ymax, float(edge->v1->vec.y), float(edge->v2->vec.y)});
241 rect.xmin = rect.xmax = float(edge->v1->vec.x);
242 }
243 };
244 }
245
246 rcti window_rect;
247 WM_window_screen_rect_calc(win, &window_rect);
248 const float offset = U.border_width * UI_SCALE_FAC;
249 const float width = std::min(2.0f * offset, 5.0f * UI_SCALE_FAC);
250 if (dir_axis == SCREEN_AXIS_H) {
251 BLI_rctf_pad(&rect, -offset, width);
252 }
253 else {
254 BLI_rctf_pad(&rect, width, -offset);
255 }
256
257 float inner[4] = {1.0f, 1.0f, 1.0f, 0.4f * anim_factor};
258 float outline[4];
260 outline[3] *= anim_factor;
261
264 &rect, inner, nullptr, 1.0f, outline, width - U.pixelsize, 2.5f * UI_SCALE_FAC);
265}
266
268{
269 rctf rect;
270 BLI_rctf_rcti_copy(&rect, &region->winrct);
272
273 switch (region->alignment) {
274 case RGN_ALIGN_RIGHT:
275 rect.xmax = rect.xmin - U.pixelsize;
276 rect.xmin = rect.xmax - (4.0f * U.pixelsize);
277 rect.ymax -= EDITORRADIUS;
278 rect.ymin += EDITORRADIUS;
279 break;
280 case RGN_ALIGN_LEFT:
281 rect.xmin = rect.xmax + U.pixelsize;
282 rect.xmax = rect.xmin + (4.0f * U.pixelsize);
283 rect.ymax -= EDITORRADIUS;
284 rect.ymin += EDITORRADIUS;
285 break;
286 case RGN_ALIGN_TOP:
287 rect.ymax = rect.ymin - U.pixelsize;
288 rect.ymin = rect.ymax - (4.0f * U.pixelsize);
289 rect.xmax -= EDITORRADIUS;
290 rect.xmin += EDITORRADIUS;
291 break;
292 case RGN_ALIGN_BOTTOM:
293 rect.ymin = rect.ymax + U.pixelsize;
294 rect.ymax = rect.ymin + (4.0f * U.pixelsize);
295 rect.xmax -= EDITORRADIUS;
296 rect.xmin += EDITORRADIUS;
297 break;
298 default:
299 return;
300 }
301
302 float inner[4] = {1.0f, 1.0f, 1.0f, 0.4f};
303 float outline[4] = {0.0f, 0.0f, 0.0f, 0.3f};
305 &rect, inner, nullptr, 1.0f, outline, 1.0f * U.pixelsize, 2.5f * UI_SCALE_FAC);
306}
307
309 const wmWindow *win, int x, int y, const ScrArea *source, const std::string &hint)
310{
311 const char *area_name = IFACE_(ED_area_name(source).c_str());
312 const uiFontStyle *fstyle = UI_FSTYLE_TOOLTIP;
313 const bTheme *btheme = UI_GetTheme();
314 const uiWidgetColors *wcol = &btheme->tui.wcol_tooltip;
315 float col_fg[4], col_bg[4];
316 rgba_uchar_to_float(col_fg, wcol->text);
317 rgba_uchar_to_float(col_bg, wcol->inner);
318
319 float scale = fstyle->points * UI_SCALE_FAC / UI_DEFAULT_TOOLTIP_POINTS;
321
322 const float margin = scale * 4.0f;
323 const float icon_width = (scale * ICON_DEFAULT_WIDTH / 1.4f);
324 const float icon_gap = scale * 3.0f;
325 const float line_gap = scale * 5.0f;
326 const int lheight = BLF_height_max(fstyle->uifont_id);
327 const int descent = BLF_descender(fstyle->uifont_id);
328 const float line1_len = BLF_width(fstyle->uifont_id, hint.c_str(), hint.size());
329 const float line2_len = BLF_width(fstyle->uifont_id, area_name, BLF_DRAW_STR_DUMMY_MAX);
330 const float width = margin + std::max(line1_len, line2_len + icon_width + icon_gap) + margin;
331 const float height = margin + lheight + line_gap + lheight + margin;
332
333 /* Position of this hint relative to the mouse position. */
334 const int left = std::min(x + int(5.0f * UI_SCALE_FAC),
335 WM_window_native_pixel_x(win) - int(width));
336 const int top = std::max(y - int(7.0f * UI_SCALE_FAC), int(height));
337
338 rctf rect;
339 rect.xmin = left;
340 rect.xmax = left + width;
341 rect.ymax = top;
342 rect.ymin = top - height;
344 UI_draw_roundbox_4fv(&rect, true, wcol->roundness * U.widget_unit, col_bg);
345
346 UI_icon_draw_ex(left + margin,
347 top - height + margin + (1.0f * scale),
348 ED_area_icon(source),
349 1.4f / scale,
350 1.0f,
351 0.0f,
352 wcol->text,
353 true,
355
357 BLF_color4fv(fstyle->uifont_id, col_fg);
358
359 BLF_position(fstyle->uifont_id, left + margin, top - margin - lheight + (2.0f * scale), 0.0f);
360 BLF_draw(fstyle->uifont_id, hint.c_str(), hint.size());
361
362 BLF_position(fstyle->uifont_id,
363 left + margin + icon_width + icon_gap,
364 top - height + margin - descent,
365 0.0f);
366 BLF_draw(fstyle->uifont_id, area_name, BLF_DRAW_STR_DUMMY_MAX);
367}
368
369static void screen_draw_area_closed(int xmin, int xmax, int ymin, int ymax, float anim_factor)
370{
371 /* Darken the area. */
372 rctf rect = {float(xmin), float(xmax), float(ymin), float(ymax)};
373 float darken[4] = {0.0f, 0.0f, 0.0f, 0.7f * anim_factor};
375 UI_draw_roundbox_4fv_ex(&rect, darken, nullptr, 1.0f, nullptr, U.pixelsize, EDITORRADIUS);
376}
377
379 const wmWindow *win, ScrArea *sa1, ScrArea *sa2, eScreenDir dir, float anim_factor)
380{
381 if (dir == SCREEN_DIR_NONE || !sa2) {
382 /* Darken source if docking. Done here because it might be a different window.
383 * Do not animate this as we don't want to reset every time we change areas. */
385 sa1->totrct.xmin, sa1->totrct.xmax, sa1->totrct.ymin, sa1->totrct.ymax, 1.0f);
386 return;
387 }
388
389 /* Rect of the combined areas. */
390 const bool vertical = SCREEN_DIR_IS_VERTICAL(dir);
391 rctf combined{};
392 combined.xmin = vertical ? std::max(sa1->totrct.xmin, sa2->totrct.xmin) :
393 std::min(sa1->totrct.xmin, sa2->totrct.xmin);
394 combined.xmax = vertical ? std::min(sa1->totrct.xmax, sa2->totrct.xmax) :
395 std::max(sa1->totrct.xmax, sa2->totrct.xmax);
396 combined.ymin = vertical ? std::min(sa1->totrct.ymin, sa2->totrct.ymin) :
397 std::max(sa1->totrct.ymin, sa2->totrct.ymin);
398 combined.ymax = vertical ? std::max(sa1->totrct.ymax, sa2->totrct.ymax) :
399 std::min(sa1->totrct.ymax, sa2->totrct.ymax);
400
401 int offset1;
402 int offset2;
403 area_getoffsets(sa1, sa2, dir, &offset1, &offset2);
404 if (offset1 < 0 || offset2 > 0) {
405 /* Show partial areas that will be closed. */
406 if (vertical) {
407 if (sa1->totrct.xmin < combined.xmin) {
409 sa1->totrct.xmin, combined.xmin, sa1->totrct.ymin, sa1->totrct.ymax, anim_factor);
410 }
411 if (sa2->totrct.xmin < combined.xmin) {
413 sa2->totrct.xmin, combined.xmin, sa2->totrct.ymin, sa2->totrct.ymax, anim_factor);
414 }
415 if (sa1->totrct.xmax > combined.xmax) {
417 combined.xmax, sa1->totrct.xmax, sa1->totrct.ymin, sa1->totrct.ymax, anim_factor);
418 }
419 if (sa2->totrct.xmax > combined.xmax) {
421 combined.xmax, sa2->totrct.xmax, sa2->totrct.ymin, sa2->totrct.ymax, anim_factor);
422 }
423 }
424 else {
425 if (sa1->totrct.ymin < combined.ymin) {
427 sa1->totrct.xmin, sa1->totrct.xmax, sa1->totrct.ymin, combined.ymin, anim_factor);
428 }
429 if (sa2->totrct.ymin < combined.ymin) {
431 sa2->totrct.xmin, sa2->totrct.xmax, sa2->totrct.ymin, combined.ymin, anim_factor);
432 }
433 if (sa1->totrct.ymax > combined.ymax) {
435 sa1->totrct.xmin, sa1->totrct.xmax, combined.ymax, sa1->totrct.ymax, anim_factor);
436 }
437 if (sa2->totrct.ymax > combined.ymax) {
439 sa2->totrct.xmin, sa2->totrct.xmax, combined.ymax, sa2->totrct.ymax, anim_factor);
440 }
441 }
442 }
443
444 /* Outline the combined area. */
446 float outline[4] = {1.0f, 1.0f, 1.0f, 0.4f * anim_factor};
447 float inner[4] = {1.0f, 1.0f, 1.0f, 0.10f * anim_factor};
448 UI_draw_roundbox_4fv_ex(&combined, inner, nullptr, 1.0f, outline, U.pixelsize, EDITORRADIUS);
449
451 win, win->eventstate->xy[0], win->eventstate->xy[1], sa1, IFACE_("Join Areas"));
452}
453
454static void rounded_corners(rctf rect, float color[4], int corners)
455{
458 format, "pos", blender::gpu::VertAttrType::SFLOAT_32_32);
459
460 const float rad = EDITORRADIUS;
461
462 float vec[4][2] = {
463 {0.195, 0.02},
464 {0.55, 0.169},
465 {0.831, 0.45},
466 {0.98, 0.805},
467 };
468 for (int a = 0; a < 4; a++) {
469 mul_v2_fl(vec[a], rad);
470 }
471
473 immUniformColor4fv(color);
474
475 if (corners & UI_CNR_TOP_LEFT) {
477 immVertex2f(pos, rect.xmin - 1, rect.ymax);
478 immVertex2f(pos, rect.xmin, rect.ymax - rad);
479 for (int a = 0; a < 4; a++) {
480 immVertex2f(pos, rect.xmin + vec[a][1], rect.ymax - rad + vec[a][0]);
481 }
482 immVertex2f(pos, rect.xmin + rad, rect.ymax);
483 immEnd();
484 }
485
486 if (corners & UI_CNR_TOP_RIGHT) {
488 immVertex2f(pos, rect.xmax + 1, rect.ymax);
489 immVertex2f(pos, rect.xmax - rad, rect.ymax);
490 for (int a = 0; a < 4; a++) {
491 immVertex2f(pos, rect.xmax - rad + vec[a][0], rect.ymax - vec[a][1]);
492 }
493 immVertex2f(pos, rect.xmax, rect.ymax - rad);
494 immEnd();
495 }
496
497 if (corners & UI_CNR_BOTTOM_RIGHT) {
499 immVertex2f(pos, rect.xmax + 1, rect.ymin);
500 immVertex2f(pos, rect.xmax, rect.ymin + rad);
501 for (int a = 0; a < 4; a++) {
502 immVertex2f(pos, rect.xmax - vec[a][1], rect.ymin + rad - vec[a][0]);
503 }
504 immVertex2f(pos, rect.xmax - rad, rect.ymin);
505 immEnd();
506 }
507
508 if (corners & UI_CNR_BOTTOM_LEFT) {
510 immVertex2f(pos, rect.xmin - 1, rect.ymin);
511 immVertex2f(pos, rect.xmin + rad, rect.ymin);
512 for (int a = 0; a < 4; a++) {
513 immVertex2f(pos, rect.xmin + rad - vec[a][0], rect.ymin + vec[a][1]);
514 }
515 immVertex2f(pos, rect.xmin, rect.ymin + rad);
516 immEnd();
517 }
518
520}
521
523 ScrArea *source,
524 ScrArea *target,
525 AreaDockTarget dock_target,
526 float factor,
527 int x,
528 int y,
529 float anim_factor)
530{
531 if (dock_target == AreaDockTarget::None) {
532 return;
533 }
534
535 float outline[4] = {1.0f, 1.0f, 1.0f, 0.4f * anim_factor};
536 float inner[4] = {1.0f, 1.0f, 1.0f, 0.1f * anim_factor};
537 float border[4];
539 border[3] *= anim_factor;
541 float half_line_width = float(U.border_width) * UI_SCALE_FAC;
542
543 rctf dest;
544 rctf remainder;
545 BLI_rctf_rcti_copy(&dest, &target->totrct);
546 BLI_rctf_rcti_copy(&remainder, &target->totrct);
547
548 float split;
549 int corners = UI_CNR_NONE;
550
551 if (dock_target == AreaDockTarget::Right) {
552 split = std::min(dest.xmin + target->winx * (1.0f - factor),
553 dest.xmax - AREAMINX * UI_SCALE_FAC);
554 dest.xmin = split + half_line_width;
555 remainder.xmax = split - half_line_width;
557 }
558 else if (dock_target == AreaDockTarget::Left) {
559 split = std::max(dest.xmax - target->winx * (1.0f - factor),
560 dest.xmin + AREAMINX * UI_SCALE_FAC);
561 dest.xmax = split - half_line_width;
562 remainder.xmin = split + half_line_width;
564 }
565 else if (dock_target == AreaDockTarget::Top) {
566 split = std::min(dest.ymin + target->winy * (1.0f - factor),
567 dest.ymax - HEADERY * UI_SCALE_FAC);
568 dest.ymin = split + half_line_width;
569 remainder.ymax = split - half_line_width;
571 }
572 else if (dock_target == AreaDockTarget::Bottom) {
573 split = std::max(dest.ymax - target->winy * (1.0f - factor),
574 dest.ymin + HEADERY * UI_SCALE_FAC);
575 dest.ymax = split - half_line_width;
576 remainder.ymin = split + half_line_width;
578 }
579
580 rounded_corners(dest, border, corners);
581 UI_draw_roundbox_4fv_ex(&dest, inner, nullptr, 1.0f, outline, U.pixelsize, EDITORRADIUS);
582
583 if (dock_target != AreaDockTarget::Center) {
584 /* Darken the split position itself. */
586 dest.xmin = split - half_line_width;
587 dest.xmax = split + half_line_width;
588 }
589 else {
590 dest.ymin = split - half_line_width;
591 dest.ymax = split + half_line_width;
592 }
593 UI_draw_roundbox_4fv(&dest, true, 0.0f, border);
594 }
595
597 x,
598 y,
599 source,
600 dock_target == AreaDockTarget::Center ? IFACE_("Replace this area") :
601 IFACE_("Move area here"));
602}
603
604void screen_draw_split_preview(ScrArea *area, const eScreenAxis dir_axis, const float factor)
605{
606 float outline[4] = {1.0f, 1.0f, 1.0f, 0.4f};
607 float inner[4] = {1.0f, 1.0f, 1.0f, 0.10f};
608 float border[4];
611
612 rctf rect;
613 BLI_rctf_rcti_copy(&rect, &area->totrct);
614
615 if (factor < 0.0001 || factor > 0.9999) {
616 /* Highlight the entire area. */
617 UI_draw_roundbox_4fv_ex(&rect, inner, nullptr, 1.0f, outline, U.pixelsize, EDITORRADIUS);
618 return;
619 }
620
621 float x = (1 - factor) * rect.xmin + factor * rect.xmax;
622 float y = (1 - factor) * rect.ymin + factor * rect.ymax;
623 x = std::clamp(x, rect.xmin, rect.xmax);
624 y = std::clamp(y, rect.ymin, rect.ymax);
625 float half_line_width = float(U.border_width) * UI_SCALE_FAC;
626
627 /* Outlined rectangle to left/above split position. */
628 rect.xmax = (dir_axis == SCREEN_AXIS_V) ? x - half_line_width : rect.xmax;
629 rect.ymax = (dir_axis == SCREEN_AXIS_H) ? y - half_line_width : rect.ymax;
630
631 rounded_corners(rect,
632 border,
635 UI_draw_roundbox_4fv_ex(&rect, inner, nullptr, 1.0f, outline, U.pixelsize, EDITORRADIUS);
636
637 /* Outlined rectangle to right/below split position. */
638 if (dir_axis == SCREEN_AXIS_H) {
639 rect.ymin = y + half_line_width;
640 rect.ymax = area->totrct.ymax;
641 }
642 else {
643 rect.xmin = x + half_line_width;
644 rect.xmax = area->totrct.xmax;
645 }
646
647 rounded_corners(rect,
648 border,
651 UI_draw_roundbox_4fv_ex(&rect, inner, nullptr, 1.0f, outline, U.pixelsize, EDITORRADIUS);
652
653 /* Darken the split position itself. */
654 if (dir_axis == SCREEN_AXIS_H) {
655 rect.ymin = y - half_line_width;
656 rect.ymax = y + half_line_width;
657 }
658 else {
659 rect.xmin = x - half_line_width;
660 rect.xmax = x + half_line_width;
661 }
662 UI_draw_roundbox_4fv(&rect, true, 0.0f, border);
663}
664
675
676static void area_animate_highlight_cb(const wmWindow * /*win*/, void *userdata)
677{
678 const AreaAnimateHighlightData *data = static_cast<const AreaAnimateHighlightData *>(userdata);
679
680 double now = BLI_time_now_seconds();
681 if (now > data->end_time) {
682 WM_draw_cb_exit(data->win, data->draw_callback);
684 data = nullptr;
685 return;
686 }
687
688 const float factor = pow((now - data->start_time) / (data->end_time - data->start_time), 2);
689 const bool do_inner = data->inner[3] > 0.0f;
690 const bool do_outline = data->outline[3] > 0.0f;
691
692 float inner_color[4];
693 if (do_inner) {
694 inner_color[0] = data->inner[0];
695 inner_color[1] = data->inner[1];
696 inner_color[2] = data->inner[2];
697 inner_color[3] = (1.0f - factor) * data->inner[3];
698 }
699
700 float outline_color[4];
701 if (do_outline) {
702 outline_color[0] = data->outline[0];
703 outline_color[1] = data->outline[1];
704 outline_color[2] = data->outline[2];
705 outline_color[3] = (1.0f - factor) * data->outline[3];
706 }
707
710 do_inner ? inner_color : nullptr,
711 nullptr,
712 1.0f,
713 do_outline ? outline_color : nullptr,
714 U.pixelsize,
716
717 data->screen->do_refresh = true;
718}
719
721 bScreen *screen,
722 const rcti *rect,
723 float inner[4],
724 float outline[4],
725 float seconds)
726{
727 /* Disabling for now, see #147487. This can cause memory leaks since the
728 * data is only freed when the animation completes, which might not happen
729 * during automated tests. Freeing wmWindow->drawcalls on window close might
730 * be enough, but will have to be investigated. */
731 return;
732
734 "screen_animate_area_highlight");
735 data->win = win;
736 data->screen = screen;
737 BLI_rctf_rcti_copy(&data->rect, rect);
738 if (inner) {
739 copy_v4_v4(data->inner, inner);
740 }
741 if (outline) {
742 copy_v4_v4(data->outline, outline);
743 }
744 data->start_time = BLI_time_now_seconds();
745 data->end_time = data->start_time + seconds;
747}
@ G_TRANSFORM_WM
ScrArea ScrArea * BKE_screen_find_area_xy(const bScreen *screen, int spacetype, const int xy[2]) ATTR_NONNULL(1
void BLF_size(int fontid, float size)
Definition blf.cc:443
int BLF_descender(int fontid) ATTR_WARN_UNUSED_RESULT
Definition blf.cc:872
void BLF_color4fv(int fontid, const float rgba[4])
Definition blf.cc:505
#define BLF_DRAW_STR_DUMMY_MAX
Definition BLF_api.hh:440
void BLF_draw(int fontid, const char *str, size_t str_len, ResultBLF *r_info=nullptr) ATTR_NONNULL(2)
Definition blf.cc:585
float BLF_width(int fontid, const char *str, size_t str_len, ResultBLF *r_info=nullptr) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(2)
Definition blf.cc:802
int BLF_height_max(int fontid) ATTR_WARN_UNUSED_RESULT
Definition blf.cc:850
void BLF_position(int fontid, float x, float y, float z)
Definition blf.cc:388
#define LISTBASE_FOREACH(type, var, list)
BLI_INLINE bool BLI_listbase_is_empty(const ListBase *lb)
void void BLI_INLINE bool BLI_listbase_is_single(const ListBase *lb)
MINLINE float max_ff(float a, float b)
MINLINE void rgba_uchar_to_float(float r_col[4], const unsigned char col_ub[4])
#define M_PI_2
MINLINE void copy_v4_v4(float r[4], const float a[4])
MINLINE void mul_v2_fl(float r[2], float f)
MINLINE void copy_v2_v2(float r[2], const float a[2])
MINLINE void mul_v2_v2fl(float r[2], const float a[2], float f)
BLI_INLINE int BLI_rcti_size_y(const struct rcti *rct)
Definition BLI_rect.h:198
void BLI_rcti_init_minmax(struct rcti *rect)
Definition rct.cc:474
BLI_INLINE int BLI_rcti_size_x(const struct rcti *rct)
Definition BLI_rect.h:194
void BLI_rctf_pad(struct rctf *rect, float pad_x, float pad_y)
Definition rct.cc:637
BLI_INLINE int BLI_rcti_cent_y(const struct rcti *rct)
Definition BLI_rect.h:181
void BLI_rctf_rcti_copy(struct rctf *dst, const struct rcti *src)
void BLI_rcti_do_minmax_v(struct rcti *rect, const int xy[2])
Definition rct.cc:486
BLI_INLINE int BLI_rcti_cent_x(const struct rcti *rct)
Definition BLI_rect.h:177
unsigned int uint
Platform independent time functions.
double BLI_time_now_seconds(void)
Definition time.cc:113
#define ELEM(...)
#define IFACE_(msgid)
#define HEADERY
#define AREAMINX
@ RGN_ALIGN_BOTTOM
@ RGN_ALIGN_LEFT
@ RGN_ALIGN_TOP
@ RGN_ALIGN_RIGHT
@ SCREENNORMAL
#define SPACE_TYPE_ANY
#define UI_SCALE_FAC
int ED_area_icon(const ScrArea *area)
blender::StringRefNull ED_area_name(const ScrArea *area)
@ AZONE_REGION_SCROLL
static void split(const char *text, const char *seps, char ***str, int *count)
#define GPU_batch_uniform_1f(batch, name, x)
Definition GPU_batch.hh:271
void GPU_batch_program_set_builtin(blender::gpu::Batch *batch, GPUBuiltinShader shader_id)
blender::gpu::Batch * GPU_batch_create_ex(GPUPrimType primitive_type, blender::gpu::VertBuf *vertex_buf, blender::gpu::IndexBuf *index_buf, GPUBatchFlag owns_flag)
Definition gpu_batch.cc:51
@ GPU_BATCH_OWNS_VBO
Definition GPU_batch.hh:42
void GPU_batch_draw(blender::gpu::Batch *batch)
#define GPU_batch_uniform_4fv(batch, name, val)
Definition GPU_batch.hh:279
#define GPU_batch_uniform_1i(batch, name, x)
Definition GPU_batch.hh:269
void gpu_batch_presets_register(blender::gpu::Batch *preset_batch)
void immEnd()
void immUnbindProgram()
void immBindBuiltinProgram(GPUBuiltinShader shader_id)
void immVertex2f(uint attr_id, float x, float y)
GPUVertFormat * immVertexFormat()
void immUniformColor4fv(const float rgba[4])
void immBegin(GPUPrimType, uint vertex_len)
@ GPU_DEVICE_INTEL_UHD
@ GPU_DRIVER_ANY
@ GPU_OS_UNIX
bool GPU_type_matches_ex(GPUDeviceType device, GPUOSType os, GPUDriverType driver, GPUBackendType backend)
@ GPU_PRIM_TRI_FAN
@ GPU_PRIM_TRI_STRIP
@ GPU_SHADER_3D_UNIFORM_COLOR
@ GPU_SHADER_2D_AREA_BORDERS
void GPU_flush()
Definition gpu_state.cc:305
void GPU_scissor_test(bool enable)
Definition gpu_state.cc:188
@ GPU_BLEND_NONE
Definition GPU_state.hh:85
@ GPU_BLEND_ALPHA
Definition GPU_state.hh:87
void GPU_blend(GPUBlend blend)
Definition gpu_state.cc:42
void GPU_scissor(int x, int y, int width, int height)
Definition gpu_state.cc:193
static blender::gpu::VertBuf * GPU_vertbuf_create_with_format(const GPUVertFormat &format)
void GPU_vertbuf_attr_set(blender::gpu::VertBuf *, uint a_idx, uint v_idx, const void *data)
void GPU_vertbuf_data_alloc(blender::gpu::VertBuf &verts, uint v_len)
uint GPU_vertformat_attr_add(GPUVertFormat *format, blender::StringRef name, blender::gpu::VertAttrType type)
void UI_draw_roundbox_4fv(const rctf *rect, bool filled, float rad, const float col[4])
void UI_draw_roundbox_4fv_ex(const rctf *rect, const float inner1[4], const float inner2[4], float shade_dir, const float outline[4], float outline_width, float rad)
#define UI_DEFAULT_TOOLTIP_POINTS
void UI_draw_roundbox_corner_set(int type)
#define UI_FSTYLE_TOOLTIP
@ UI_CNR_BOTTOM_LEFT
@ UI_CNR_BOTTOM_RIGHT
@ UI_CNR_ALL
@ UI_CNR_TOP_LEFT
@ UI_CNR_TOP_RIGHT
@ UI_CNR_NONE
#define UI_NO_ICON_OVERLAY_TEXT
void UI_icon_draw_ex(float x, float y, int icon_id, float aspect, float alpha, float desaturate, const uchar mono_color[4], bool mono_border, const IconTextOverlay *text_overlay, const bool inverted=false)
#define ICON_DEFAULT_WIDTH
@ TH_EDITOR_BORDER
@ TH_EDITOR_OUTLINE_ACTIVE
@ TH_EDITOR_OUTLINE
void UI_GetThemeColor4fv(int colorid, float col[4])
bTheme * UI_GetTheme()
#define U
BMesh const char void * data
static btDbvtVolume bounds(btDbvtNode **leaves, int count)
Definition btDbvt.cpp:299
nullptr float
#define roundf(x)
struct @021025263243242147216143265077100330027142264337::@225245033123204053237120173316075113304004012000 batch
uint pos
uint col
uint top
#define pow
uint padding(uint offset, uint alignment)
format
void * MEM_callocN(size_t len, const char *str)
Definition mallocn.cc:118
void MEM_freeN(void *vmemh)
Definition mallocn.cc:113
static int left
#define G(x, y, z)
VecBase< int32_t, 2 > int2
#define fabsf
#define sinf
#define cosf
void screen_draw_region_scale_highlight(ARegion *region)
static void drawscredge_area(const ScrArea &area, float edge_thickness)
Screen edges drawing.
static void rounded_corners(rctf rect, float color[4], int corners)
static void area_animate_highlight_cb(const wmWindow *, void *userdata)
void screen_draw_split_preview(ScrArea *area, const eScreenAxis dir_axis, const float factor)
void screen_draw_move_highlight(const wmWindow *win, bScreen *screen, eScreenAxis dir_axis, float anim_factor)
void ED_screen_draw_edges(wmWindow *win)
#define CORNER_RESOLUTION
void screen_draw_dock_preview(const wmWindow *win, ScrArea *source, ScrArea *target, AreaDockTarget dock_target, float factor, int x, int y, float anim_factor)
static void do_vert_pair(blender::gpu::VertBuf *vbo, uint pos, uint *vidx, int corner, int i)
void screen_animate_area_highlight(wmWindow *win, bScreen *screen, const rcti *rect, float inner[4], float outline[4], float seconds)
static void screen_draw_area_closed(int xmin, int xmax, int ymin, int ymax, float anim_factor)
static void screen_draw_area_drag_tip(const wmWindow *win, int x, int y, const ScrArea *source, const std::string &hint)
void screen_draw_join_highlight(const wmWindow *win, ScrArea *sa1, ScrArea *sa2, eScreenDir dir, float anim_factor)
static blender::gpu::Batch * batch_screen_edges_get(int *corner_len)
void area_getoffsets(ScrArea *sa_a, ScrArea *sa_b, const eScreenDir dir, int *r_offset1, int *r_offset2)
AZone * ED_area_actionzone_find_xy(ScrArea *area, const int xy[2])
eScreenAxis
@ SCREEN_AXIS_V
@ SCREEN_AXIS_H
#define SCREEN_DIR_IS_VERTICAL(dir)
eScreenDir
@ SCREEN_DIR_NONE
#define EDITORRADIUS
AreaDockTarget
void * first
ListBase areabase
uiWidgetColors wcol_tooltip
ListBase edgebase
ListBase areabase
struct ARegion * active_region
ThemeUI tui
float xmax
float xmin
float ymax
float ymin
int ymin
int ymax
int xmin
int xmax
unsigned char inner[4]
unsigned char text[4]
int xy[2]
Definition WM_types.hh:761
struct wmEvent * eventstate
ScrAreaMap global_areas
i
Definition text_draw.cc:230
void * WM_draw_cb_activate(wmWindow *win, void(*draw)(const wmWindow *win, void *customdata), void *customdata)
Definition wm_draw.cc:635
void WM_draw_cb_exit(wmWindow *win, void *handle)
Definition wm_draw.cc:648
int WM_window_native_pixel_x(const wmWindow *win)
void WM_window_screen_rect_calc(const wmWindow *win, rcti *r_rect)
bScreen * WM_window_get_active_screen(const wmWindow *win)