Blender V4.3
area.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2008 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
8
9#include <cstdio>
10#include <cstring>
11
12#include "MEM_guardedalloc.h"
13
14#include "DNA_userdef_types.h"
15
16#include "BLI_blenlib.h"
17#include "BLI_linklist_stack.h"
18#include "BLI_rand.h"
19#include "BLI_string_utils.hh"
20#include "BLI_utildefines.h"
21
22#include "BKE_context.hh"
23#include "BKE_global.hh"
24#include "BKE_screen.hh"
25#include "BKE_workspace.hh"
26
27#include "RNA_access.hh"
28
29#include "WM_api.hh"
30#include "WM_message.hh"
31#include "WM_toolsystem.hh"
32#include "WM_types.hh"
33
34#include "ED_asset_shelf.hh"
35#include "ED_buttons.hh"
36#include "ED_screen.hh"
37#include "ED_screen_types.hh"
38#include "ED_space_api.hh"
39#include "ED_time_scrub_ui.hh"
40
41#include "GPU_framebuffer.hh"
42#include "GPU_immediate.hh"
43#include "GPU_immediate_util.hh"
44#include "GPU_matrix.hh"
45#include "GPU_state.hh"
46
47#include "BLF_api.hh"
48
49#include "IMB_metadata.hh"
50
51#include "UI_interface.hh"
52#include "UI_interface_icons.hh"
53#include "UI_resources.hh"
54#include "UI_view2d.hh"
55
56#include "screen_intern.hh"
57
66
67/* general area and region code */
68
69static void region_draw_emboss(const ARegion *region, const rcti *scirct, int sides)
70{
71 /* translate scissor rect to region space */
72 rcti rect{};
73 rect.xmin = scirct->xmin - region->winrct.xmin;
74 rect.xmax = scirct->xmax - region->winrct.xmin;
75 rect.ymin = scirct->ymin - region->winrct.ymin;
76 rect.ymax = scirct->ymax - region->winrct.ymin;
77
78 /* Set transparent line. */
80
81 float color[4] = {0.0f, 0.0f, 0.0f, 0.25f};
83
88
90
91 /* right */
92 if (sides & REGION_EMBOSS_RIGHT) {
93 immVertex2f(pos, rect.xmax, rect.ymax);
94 immVertex2f(pos, rect.xmax, rect.ymin);
95 }
96
97 /* bottom */
98 if (sides & REGION_EMBOSS_BOTTOM) {
99 immVertex2f(pos, rect.xmax, rect.ymin);
100 immVertex2f(pos, rect.xmin, rect.ymin);
101 }
102
103 /* left */
104 if (sides & REGION_EMBOSS_LEFT) {
105 immVertex2f(pos, rect.xmin, rect.ymin);
106 immVertex2f(pos, rect.xmin, rect.ymax);
107 }
108
109 /* top */
110 if (sides & REGION_EMBOSS_TOP) {
111 immVertex2f(pos, rect.xmin, rect.ymax);
112 immVertex2f(pos, rect.xmax, rect.ymax);
113 }
114
115 immEnd();
117
119}
120
121void ED_region_pixelspace(const ARegion *region)
122{
125}
126
128{
129 ARegion *region = params->region;
130 const wmNotifier *notifier = params->notifier;
131
132 /* generic notes first */
133 switch (notifier->category) {
134 case NC_WM:
135 if (notifier->data == ND_FILEREAD) {
136 ED_region_tag_redraw(region);
137 }
138 break;
139 case NC_WINDOW:
140 ED_region_tag_redraw(region);
141 break;
142 }
143
144 if (region->type && region->type->listener) {
145 region->type->listener(params);
146 }
147
148 LISTBASE_FOREACH (uiBlock *, block, &region->uiblocks) {
149 UI_block_listen(block, params);
150 }
151
152 LISTBASE_FOREACH (uiList *, list, &region->ui_lists) {
153 if (list->type && list->type->listener) {
154 list->type->listener(list, params);
155 }
156 }
157}
158
160{
161 /* no generic notes? */
162 if (params->area->type && params->area->type->listener) {
163 params->area->type->listener(params);
164 }
165}
166
168{
169 /* no generic notes? */
170 if (area->type && area->type->refresh) {
171 area->type->refresh(C, area);
172 }
173 area->do_refresh = false;
174}
175
179static void area_draw_azone_fullscreen(short /*x1*/, short /*y1*/, short x2, short y2, float alpha)
180{
181 UI_icon_draw_ex(x2 - U.widget_unit,
182 y2 - U.widget_unit,
183 ICON_FULLSCREEN_EXIT,
185 min_ff(alpha, 0.75f),
186 0.0f,
187 nullptr,
188 false,
190}
191
195static void area_draw_azone(short /*x1*/, short /*y1*/, short /*x2*/, short /*y2*/)
196{
197 /* No drawing needed since all corners are action zone, and visually distinguishable. */
198}
199
203static void draw_azone_arrow(float x1, float y1, float x2, float y2, AZEdge edge)
204{
205 const float size = 0.2f * U.widget_unit;
206 const float l = 1.0f; /* arrow length */
207 const float s = 0.25f; /* arrow thickness */
208 const float hl = l / 2.0f;
209 const float points[6][2] = {
210 {0, -hl}, {l, hl}, {l - s, hl + s}, {0, s + s - hl}, {s - l, hl + s}, {-l, hl}};
211 const float center[2] = {(x1 + x2) / 2, (y1 + y2) / 2};
212
213 int axis;
214 int sign;
215 switch (edge) {
217 axis = 0;
218 sign = 1;
219 break;
221 axis = 0;
222 sign = -1;
223 break;
225 axis = 1;
226 sign = 1;
227 break;
229 axis = 1;
230 sign = -1;
231 break;
232 default:
233 BLI_assert(0);
234 return;
235 }
236
239
242 immUniformColor4f(0.8f, 0.8f, 0.8f, 0.4f);
243
245 for (int i = 0; i < 6; i++) {
246 if (axis == 0) {
247 immVertex2f(pos, center[0] + points[i][0] * size, center[1] + points[i][1] * sign * size);
248 }
249 else {
250 immVertex2f(pos, center[0] + points[i][1] * sign * size, center[1] + points[i][0] * size);
251 }
252 }
253 immEnd();
254
257}
258
259static void region_draw_azone_tab_arrow(ScrArea *area, ARegion *region, AZone *az)
260{
262
263 /* add code to draw region hidden as 'too small' */
264 switch (az->edge) {
267 break;
270 break;
273 break;
276 break;
277 }
278
279 /* Workaround for different color spaces between normal areas and the ones using GPUViewports. */
280 float alpha = WM_region_use_viewport(area, region) ? 0.6f : 0.4f;
281 const float color[4] = {0.05f, 0.05f, 0.05f, alpha};
282 rctf rect{};
283 rect.xmin = float(az->x1);
284 rect.xmax = float(az->x2);
285 rect.ymin = float(az->y1);
286 rect.ymax = float(az->y2);
287 UI_draw_roundbox_aa(&rect, true, 4.0f, color);
288
289 draw_azone_arrow(float(az->x1), float(az->y1), float(az->x2), float(az->y2), az->edge);
290}
291
293{
295}
296
297static void region_draw_azones(ScrArea *area, ARegion *region)
298{
299 if (!area) {
300 return;
301 }
302
303 GPU_line_width(1.0f);
305
307 GPU_matrix_translate_2f(-region->winrct.xmin, -region->winrct.ymin);
308
309 LISTBASE_FOREACH (AZone *, az, &area->actionzones) {
310 /* test if action zone is over this region */
311 rcti azrct;
312 BLI_rcti_init(&azrct, az->x1, az->x2, az->y1, az->y2);
313
314 if (BLI_rcti_isect(&region->drawrct, &azrct, nullptr)) {
315 if (az->type == AZONE_AREA) {
316 area_draw_azone(az->x1, az->y1, az->x2, az->y2);
317 }
318 else if (az->type == AZONE_REGION) {
319 if (az->region && !(az->region->flag & RGN_FLAG_POLL_FAILED)) {
320 /* only display tab or icons when the region is hidden */
321 if (az->region->flag & (RGN_FLAG_HIDDEN | RGN_FLAG_TOO_SMALL)) {
322 region_draw_azone_tab_arrow(area, region, az);
323 }
324 }
325 }
326 else if (az->type == AZONE_FULLSCREEN) {
327 if (az->alpha > 0.0f) {
328 area_draw_azone_fullscreen(az->x1, az->y1, az->x2, az->y2, az->alpha);
329 }
330 }
331 }
332 if (!IS_EQF(az->alpha, 0.0f) && ELEM(az->type, AZONE_FULLSCREEN, AZONE_REGION_SCROLL)) {
334 }
335 }
336
338
340}
341
342static void region_draw_status_text(ScrArea * /*area*/, ARegion *region)
343{
344 float header_color[4];
345 UI_GetThemeColor4fv(TH_HEADER, header_color);
346
347 /* Clear the region from the buffer. */
348 GPU_clear_color(0.0f, 0.0f, 0.0f, 0.0f);
349
350 /* Fill with header color. */
351 if (header_color[3] > 0.0f) {
352 const rctf rect = {0.0f, float(region->winx), 0.0f, float(region->winy)};
353 UI_draw_roundbox_4fv(&rect, true, 0.0f, header_color);
354 }
355
356 const int fontid = BLF_set_default();
357 const float x = 12.0f * UI_SCALE_FAC;
358 const float y = 0.4f * UI_UNIT_Y;
360
361 if (header_color[3] < 0.3f) {
362 /* Draw a background behind the text for extra contrast. */
363 const float width = BLF_width(fontid, region->headerstr, BLF_DRAW_STR_DUMMY_MAX);
364 const float pad = 5.0f * UI_SCALE_FAC;
365 const float x1 = x - pad;
366 const float x2 = x + width + pad;
367 const float y1 = 3.0f * UI_SCALE_FAC;
368 const float y2 = region->winy - (4.0f * UI_SCALE_FAC);
369 float color[4] = {0.0f, 0.0f, 0.0f, 0.3f};
372 const rctf rect = {x1, x2, y1, y2};
373 UI_draw_roundbox_4fv(&rect, true, 4.0f * UI_SCALE_FAC, color);
374 }
375
376 UI_FontThemeColor(fontid, TH_TEXT);
377 BLF_position(fontid, x, y, 0.0f);
378 BLF_draw(fontid, region->headerstr, BLF_DRAW_STR_DUMMY_MAX);
379}
380
382 /* Follow wmMsgNotifyFn spec */
383 bContext * /*C*/,
384 wmMsgSubscribeKey * /*msg_key*/,
385 wmMsgSubscribeValue *msg_val)
386{
387 ARegion *region = static_cast<ARegion *>(msg_val->owner);
388 ED_region_tag_redraw(region);
389
390 /* This avoids _many_ situations where header/properties control display settings.
391 * the common case is space properties in the header */
393 while (region && region->prev) {
394 region = region->prev;
395 }
396 for (; region; region = region->next) {
398 ED_region_tag_redraw(region);
399 }
400 }
401 }
402}
403
405 /* Follow wmMsgNotifyFn spec */
406 bContext * /*C*/,
407 wmMsgSubscribeKey * /*msg_key*/,
408 wmMsgSubscribeValue *msg_val)
409{
410 ScrArea *area = static_cast<ScrArea *>(msg_val->user_data);
412}
413
415{
416 wmMsgBus *mbus = params->message_bus;
417 WorkSpace *workspace = params->workspace;
418 ARegion *region = params->region;
419
421 wmMsgSubscribeValue msg_sub_value_region_tag_redraw{};
422 msg_sub_value_region_tag_redraw.owner = region;
423 msg_sub_value_region_tag_redraw.user_data = region;
424 msg_sub_value_region_tag_redraw.notify = ED_region_do_msg_notify_tag_redraw;
426 mbus, &workspace->id, workspace, WorkSpace, tools, &msg_sub_value_region_tag_redraw);
427}
428
430{
431 wmMsgBus *mbus = params->message_bus;
432 WorkSpace *workspace = params->workspace;
433 ARegion *region = params->region;
434
436 const char *panel_category_tool = "Tool";
437 const char *category = UI_panel_category_active_get(region, false);
438
439 bool update_region = false;
440 if (category && STREQ(category, panel_category_tool)) {
441 update_region = true;
442 }
443 else {
444 /* Check if a tool category panel is pinned and visible in another category. */
445 LISTBASE_FOREACH (Panel *, panel, &region->panels) {
446 if (UI_panel_is_active(panel) && panel->flag & PNL_PIN &&
447 STREQ(panel->type->category, panel_category_tool))
448 {
449 update_region = true;
450 break;
451 }
452 }
453 }
454
455 if (update_region) {
456 wmMsgSubscribeValue msg_sub_value_region_tag_redraw{};
457 msg_sub_value_region_tag_redraw.owner = region;
458 msg_sub_value_region_tag_redraw.user_data = region;
459 msg_sub_value_region_tag_redraw.notify = ED_region_do_msg_notify_tag_redraw;
461 mbus, &workspace->id, workspace, WorkSpace, tools, &msg_sub_value_region_tag_redraw);
462 }
463}
464
471static bool area_is_pseudo_minimized(const ScrArea *area)
472{
473 return (area->winx < 3) || (area->winy < 3);
474}
475
477{
478 /* This is optional, only needed for dynamically sized regions. */
479 ScrArea *area = CTX_wm_area(C);
480 ARegionType *at = region->type;
481
482 if (!at->layout) {
483 return;
484 }
485
486 if (at->do_lock || (area && area_is_pseudo_minimized(area))) {
487 return;
488 }
489
490 region->do_draw |= RGN_DRAWING;
491
492 UI_SetTheme(area ? area->spacetype : 0, at->regionid);
493 at->layout(C, region);
494
495 /* Clear temporary update flag. */
497}
498
500{
501 wmWindow *win = CTX_wm_window(C);
502 ScrArea *area = CTX_wm_area(C);
503 ARegionType *at = region->type;
504
505 /* see BKE_spacedata_draw_locks() */
506 if (at->do_lock) {
507 return;
508 }
509
510 region->do_draw |= RGN_DRAWING;
511
512 /* Set viewport, scissor, ortho and region->drawrct. */
513 wmPartialViewport(&region->drawrct, &region->winrct, &region->drawrct);
514
516
517 UI_SetTheme(area ? area->spacetype : 0, at->regionid);
518
519 if (area && area_is_pseudo_minimized(area)) {
521 return;
522 }
523 /* optional header info instead? */
524 if (region->headerstr) {
525 region_draw_status_text(area, region);
526 }
527 else if (at->draw) {
528 at->draw(C, region);
529 }
530
531 /* XXX test: add convention to end regions always in pixel space,
532 * for drawing of borders/gestures etc */
533 ED_region_pixelspace(region);
534
535 /* Remove sRGB override by rebinding the framebuffer. */
536 GPUFrameBuffer *fb = GPU_framebuffer_active_get();
538
540
541 region_draw_azones(area, region);
542
543 /* for debugging unneeded area redraws and partial redraw */
544 if (G.debug_value == 888) {
551 region->drawrct.xmin - region->winrct.xmin,
552 region->drawrct.ymin - region->winrct.ymin,
553 region->drawrct.xmax - region->winrct.xmin,
554 region->drawrct.ymax - region->winrct.ymin);
557 }
558
559 memset(&region->drawrct, 0, sizeof(region->drawrct));
560
562
563 if (area) {
564 const bScreen *screen = WM_window_get_active_screen(win);
565
566 /* Only region emboss for top-bar */
567 if ((screen->state != SCREENFULL) && ED_area_is_global(area)) {
569 }
570 else if ((region->regiontype == RGN_TYPE_WINDOW) && (region->alignment == RGN_ALIGN_QSPLIT)) {
571
572 /* draw separating lines between the quad views */
573
574 float color[4] = {0.0f, 0.0f, 0.0f, 0.8f};
580 GPU_line_width(1.0f);
582 0,
583 0,
584 region->winrct.xmax - region->winrct.xmin + 1,
585 region->winrct.ymax - region->winrct.ymin + 1);
587 }
588 }
589
590 /* We may want to detach message-subscriptions from drawing. */
591 {
592 WorkSpace *workspace = CTX_wm_workspace(C);
595 Scene *scene = CTX_data_scene(C);
596 wmMsgBus *mbus = wm->message_bus;
597 WM_msgbus_clear_by_owner(mbus, region);
598
599 /* Cheat, always subscribe to this space type properties.
600 *
601 * This covers most cases and avoids copy-paste similar code for each space type.
602 */
604 {
605 SpaceLink *sl = static_cast<SpaceLink *>(area->spacedata.first);
606
607 PointerRNA ptr = RNA_pointer_create(&screen->id, &RNA_Space, sl);
608
609 /* All properties for this space type. */
610 wmMsgSubscribeValue msg_sub_value_region_tag_redraw{};
611 msg_sub_value_region_tag_redraw.owner = region;
612 msg_sub_value_region_tag_redraw.user_data = region;
613 msg_sub_value_region_tag_redraw.notify = ED_region_do_msg_notify_tag_redraw;
614 WM_msg_subscribe_rna(mbus, &ptr, nullptr, &msg_sub_value_region_tag_redraw, __func__);
615 }
616
617 wmRegionMessageSubscribeParams message_subscribe_params{};
618 message_subscribe_params.context = C;
619 message_subscribe_params.message_bus = mbus;
620 message_subscribe_params.workspace = workspace;
621 message_subscribe_params.scene = scene;
622 message_subscribe_params.screen = screen;
623 message_subscribe_params.area = area;
624 message_subscribe_params.region = region;
625 ED_region_message_subscribe(&message_subscribe_params);
626 }
627}
628
629/* **********************************
630 * maybe silly, but let's try for now
631 * to keep these tags protected
632 * ********************************** */
633
635{
636 /* don't tag redraw while drawing, it shouldn't happen normally
637 * but python scripts can cause this to happen indirectly */
638 if (region && !(region->do_draw & RGN_DRAWING)) {
639 /* zero region means full region redraw */
641 region->do_draw |= RGN_DRAW;
642 memset(&region->drawrct, 0, sizeof(region->drawrct));
643 }
644}
645
647{
648 if (region) {
650 }
651}
652
654{
655 if (region && !(region->do_draw & (RGN_DRAWING | RGN_DRAW))) {
657 region->do_draw |= RGN_DRAW_NO_REBUILD;
658 memset(&region->drawrct, 0, sizeof(region->drawrct));
659 }
660}
661
663{
664 if (region) {
665 region->do_draw |= RGN_REFRESH_UI;
666 }
667}
668
670{
671 if (region && !(region->do_draw & (RGN_DRAWING | RGN_DRAW))) {
672 if (region->do_draw & RGN_DRAW_PARTIAL) {
673 ED_region_tag_redraw(region);
674 }
675 else {
677 }
678 }
679}
680
681void ED_region_tag_redraw_partial(ARegion *region, const rcti *rct, bool rebuild)
682{
683 if (region && !(region->do_draw & RGN_DRAWING)) {
684 if (region->do_draw & RGN_DRAW_PARTIAL) {
685 /* Partial redraw already set, expand region. */
686 BLI_rcti_union(&region->drawrct, rct);
687 if (rebuild) {
688 region->do_draw &= ~RGN_DRAW_NO_REBUILD;
689 }
690 }
691 else if (region->do_draw & (RGN_DRAW | RGN_DRAW_NO_REBUILD)) {
692 /* Full redraw already requested. */
693 if (rebuild) {
694 region->do_draw &= ~RGN_DRAW_NO_REBUILD;
695 }
696 }
697 else {
698 /* No redraw set yet, set partial region. */
699 region->drawrct = *rct;
700 region->do_draw |= RGN_DRAW_PARTIAL;
701 if (!rebuild) {
702 region->do_draw |= RGN_DRAW_NO_REBUILD;
703 }
704 }
705 }
706}
707
709{
710 if (area) {
711 LISTBASE_FOREACH (ARegion *, region, &area->regionbase) {
712 ED_region_tag_redraw(region);
713 }
714 }
715}
716
718{
719 if (area) {
720 LISTBASE_FOREACH (ARegion *, region, &area->regionbase) {
722 }
723 }
724}
725
726void ED_area_tag_redraw_regiontype(ScrArea *area, int regiontype)
727{
728 if (area) {
729 LISTBASE_FOREACH (ARegion *, region, &area->regionbase) {
730 if (region->regiontype == regiontype) {
731 ED_region_tag_redraw(region);
732 }
733 }
734 }
735}
736
738{
739 if (area) {
740 area->do_refresh = true;
741 }
742}
743
745{
746 if (!area || (area->flag & AREA_FLAG_REGION_SIZE_UPDATE)) {
747 return;
748 }
749
751
752 /* Floating regions don't affect other regions, so the following can be skipped. */
753 if (changed_region->alignment == RGN_ALIGN_FLOAT) {
754 return;
755 }
756
757 /* Tag the following regions for redraw, since the size change of this region may affect the
758 * available space for them. */
759 for (ARegion *following_region = changed_region->next; following_region;
760 following_region = following_region->next)
761 {
762 /* Overlapping and non-overlapping regions don't affect each others space. So layout changes
763 * of one don't require redrawing the other. */
764 if (changed_region->overlap != following_region->overlap) {
765 continue;
766 }
767 /* Floating regions don't affect space of other regions. */
768 if (following_region->alignment == RGN_ALIGN_FLOAT) {
769 continue;
770 }
771 ED_region_tag_redraw(following_region);
772 }
773}
774
775/* *************************************************************** */
776
777const char *ED_area_region_search_filter_get(const ScrArea *area, const ARegion *region)
778{
779 /* Only the properties editor has a search string for now. */
780 if (area->spacetype == SPACE_PROPERTIES) {
781 SpaceProperties *sbuts = static_cast<SpaceProperties *>(area->spacedata.first);
782 if (region->regiontype == RGN_TYPE_WINDOW) {
783 return ED_buttons_search_string_get(sbuts);
784 }
785 }
786
787 return nullptr;
788}
789
791{
793
794 const char *search_filter = ED_area_region_search_filter_get(area, region);
795 SET_FLAG_FROM_TEST(region->flag,
796 region->regiontype == RGN_TYPE_WINDOW && search_filter &&
797 search_filter[0] != '\0',
799}
800
801/* *************************************************************** */
802
803void ED_area_status_text(ScrArea *area, const char *str)
804{
805 /* happens when running transform operators in background mode */
806 if (area == nullptr) {
807 return;
808 }
809
810 ARegion *ar = nullptr;
811
812 LISTBASE_FOREACH (ARegion *, region, &area->regionbase) {
813 if (region->regiontype == RGN_TYPE_HEADER && region->visible) {
814 ar = region;
815 }
816 else if (region->regiontype == RGN_TYPE_TOOL_HEADER && region->visible) {
817 /* Prefer tool header when we also have a header. */
818 ar = region;
819 break;
820 }
821 }
822
823 if (ar) {
824 if (str) {
825 if (ar->headerstr == nullptr) {
826 ar->headerstr = static_cast<char *>(MEM_mallocN(UI_MAX_DRAW_STR, "headerprint"));
827 }
830 }
831 else {
833 }
835 }
836}
837
838/* *************************************************************** */
839
840static void ed_workspace_status_item(WorkSpace *workspace,
841 std::string text,
842 const int icon,
843 const float space_factor = 0.0f,
844 const bool inverted = false)
845{
846 /* Can be nullptr when running operators in background mode. */
847 if (workspace == nullptr) {
848 return;
849 }
850
852 item.text = std::move(text);
853 item.icon = icon;
854 item.space_factor = space_factor;
855 item.inverted = inverted;
856 workspace->runtime->status.append(std::move(item));
857}
858
859static void ed_workspace_status_space(WorkSpace *workspace, const float space_factor)
860{
861 ed_workspace_status_item(workspace, {}, ICON_NONE, space_factor);
862}
863
873
874/* -------------------------------------------------------------------- */
877
878static constexpr float STATUS_AFTER_TEXT = 0.7f;
879static constexpr float STATUS_MOUSE_ICON_PAD = -0.5f;
880
881static void ed_workspace_status_text_item(WorkSpace *workspace, std::string text)
882{
883 if (!text.empty()) {
884 ed_workspace_status_item(workspace, std::move(text), ICON_NONE);
886 }
887}
888
890 const int icon,
891 const bool inverted = false)
892{
893 if (icon) {
894 ed_workspace_status_item(workspace, {}, icon, 0.0f, inverted);
895 if (icon >= ICON_MOUSE_LMB && icon <= ICON_MOUSE_MMB_SCROLL) {
896 /* Negative space after narrow mice icons. */
898 }
899 }
900}
901
903
904/* -------------------------------------------------------------------- */
907
908void WorkspaceStatus::item(std::string text, const int icon1, const int icon2)
909{
910 ed_workspace_status_icon_item(workspace_, icon1);
911 ed_workspace_status_icon_item(workspace_, icon2);
912 ed_workspace_status_text_item(workspace_, std::move(text));
913}
914
915void WorkspaceStatus::range(std::string text, const int icon1, const int icon2)
916{
917 ed_workspace_status_item(workspace_, {}, icon1);
918 ed_workspace_status_item(workspace_, "-", ICON_NONE);
919 ed_workspace_status_space(workspace_, -0.5f);
920 ed_workspace_status_item(workspace_, {}, icon2);
921 ed_workspace_status_text_item(workspace_, std::move(text));
922}
923
924void WorkspaceStatus::item_bool(std::string text,
925 const bool inverted,
926 const int icon1,
927 const int icon2)
928{
929 ed_workspace_status_icon_item(workspace_, icon1, inverted);
930 ed_workspace_status_icon_item(workspace_, icon2, inverted);
931 ed_workspace_status_text_item(workspace_, std::move(text));
932}
933
934void WorkspaceStatus::opmodal(std::string text,
935 const wmOperatorType *ot,
936 const int propvalue,
937 const bool inverted)
938{
939 wmKeyMap *keymap = WM_keymap_active(wm_, ot->modalkeymap);
940 if (keymap) {
941 const wmKeyMapItem *kmi = WM_modalkeymap_find_propvalue(keymap, propvalue);
942 if (kmi) {
943#ifdef WITH_HEADLESS
944 int icon = 0;
945#else
946 int icon = UI_icon_from_event_type(kmi->type, kmi->val);
947#endif
948 if (!ELEM(kmi->shift, KM_NOTHING, KM_ANY)) {
949 ed_workspace_status_item(workspace_, {}, ICON_EVENT_SHIFT, 0.0f, inverted);
950 }
951 if (!ELEM(kmi->ctrl, KM_NOTHING, KM_ANY)) {
952 ed_workspace_status_item(workspace_, {}, ICON_EVENT_CTRL, 0.0f, inverted);
953 }
954 if (!ELEM(kmi->alt, KM_NOTHING, KM_ANY)) {
955 ed_workspace_status_item(workspace_, {}, ICON_EVENT_ALT, 0.0f, inverted);
956 }
957 if (!ELEM(kmi->oskey, KM_NOTHING, KM_ANY)) {
958 ed_workspace_status_item(workspace_, {}, ICON_EVENT_OS, 0.0f, inverted);
959 }
960 ed_workspace_status_icon_item(workspace_, icon, inverted);
961 ed_workspace_status_text_item(workspace_, std::move(text));
962 }
963 }
964}
965
967{
968 WorkspaceStatus status(C);
969 status.item(str ? str : "", ICON_NONE);
970}
971
973
974/* ************************************************************ */
975
976static void area_azone_init(wmWindow *win, const bScreen *screen, ScrArea *area)
977{
978 /* reinitialize entirely, regions and full-screen add azones too */
980
981 if (screen->state != SCREENNORMAL) {
982 return;
983 }
984
985 if (U.app_flag & USER_APP_LOCK_CORNER_SPLIT) {
986 return;
987 }
988
989 if (ED_area_is_global(area)) {
990 return;
991 }
992
993 if (screen->temp) {
994 return;
995 }
996
997 const float coords[4][4] = {
998 /* Bottom-left. */
999 {area->totrct.xmin - U.pixelsize,
1000 area->totrct.ymin - U.pixelsize,
1001 area->totrct.xmin + AZONESPOTW,
1002 area->totrct.ymin + AZONESPOTH},
1003 /* Bottom-right. */
1004 {area->totrct.xmax - AZONESPOTW,
1005 area->totrct.ymin - U.pixelsize,
1006 area->totrct.xmax + U.pixelsize,
1007 area->totrct.ymin + AZONESPOTH},
1008 /* Top-left. */
1009 {area->totrct.xmin - U.pixelsize,
1010 area->totrct.ymax - AZONESPOTH,
1011 area->totrct.xmin + AZONESPOTW,
1012 area->totrct.ymax + U.pixelsize},
1013 /* Top-right. */
1014 {area->totrct.xmax - AZONESPOTW,
1015 area->totrct.ymax - AZONESPOTH,
1016 area->totrct.xmax + U.pixelsize,
1017 area->totrct.ymax + U.pixelsize},
1018 };
1019
1020 for (int i = 0; i < 4; i++) {
1021 /* can't click on bottom corners on OS X, already used for resizing */
1022#ifdef __APPLE__
1023 if (!WM_window_is_fullscreen(win) &&
1024 ((coords[i][0] == 0 && coords[i][1] == 0) ||
1025 (coords[i][0] == WM_window_native_pixel_x(win) && coords[i][1] == 0)))
1026 {
1027 continue;
1028 }
1029#else
1030 (void)win;
1031#endif
1032
1033 /* set area action zones */
1034 AZone *az = (AZone *)MEM_callocN(sizeof(AZone), "actionzone");
1035 BLI_addtail(&(area->actionzones), az);
1036 az->type = AZONE_AREA;
1037 az->x1 = coords[i][0];
1038 az->y1 = coords[i][1];
1039 az->x2 = coords[i][2];
1040 az->y2 = coords[i][3];
1041 BLI_rcti_init(&az->rect, az->x1, az->x2, az->y1, az->y2);
1042 }
1043}
1044
1045static void fullscreen_azone_init(ScrArea *area, ARegion *region)
1046{
1047 if (ED_area_is_global(area) || (region->regiontype != RGN_TYPE_WINDOW)) {
1048 return;
1049 }
1050
1051 AZone *az = (AZone *)MEM_callocN(sizeof(AZone), "fullscreen action zone");
1052 BLI_addtail(&(area->actionzones), az);
1053 az->type = AZONE_FULLSCREEN;
1054 az->region = region;
1055 az->alpha = 0.0f;
1056
1057 if (U.uiflag2 & USER_REGION_OVERLAP) {
1058 const rcti *rect_visible = ED_region_visible_rect(region);
1059 az->x2 = region->winrct.xmin + rect_visible->xmax;
1060 az->y2 = region->winrct.ymin + rect_visible->ymax;
1061 }
1062 else {
1063 az->x2 = region->winrct.xmax;
1064 az->y2 = region->winrct.ymax;
1065 }
1066 az->x1 = az->x2 - AZONEFADEOUT;
1067 az->y1 = az->y2 - AZONEFADEOUT;
1068
1069 BLI_rcti_init(&az->rect, az->x1, az->x2, az->y1, az->y2);
1070}
1071
1077static bool region_background_is_transparent(const ScrArea *area, const ARegion *region)
1078{
1079 /* Ensure the right theme is active, may not be the case on startup, for example. */
1080 bThemeState theme_state;
1081 UI_Theme_Store(&theme_state);
1082 UI_SetTheme(area->spacetype, region->regiontype);
1083
1084 uchar back[4];
1086
1087 UI_Theme_Restore(&theme_state);
1088
1089 return back[3] < 50;
1090}
1091
1092static void region_azone_edge(const ScrArea *area, AZone *az, const ARegion *region)
1093{
1094 const int azonepad_edge = (0.1f * U.widget_unit);
1095
1096 /* If there is no visible region background, users typically expect the #AZone to be closer to
1097 * the content, so move it a bit. */
1098 const int overlap_padding =
1099 /* Header-like regions are usually thin and there's not much padding around them,
1100 * applying an offset would make the edge overlap buttons. */
1102 /* Is the region background transparent? */
1103 region->overlap && region_background_is_transparent(area, region)) ?
1104 /* Note that this is an arbitrary amount that matches nicely with numbers elsewhere. */
1105 int(0.4f * U.widget_unit) :
1106 0;
1107
1108 switch (az->edge) {
1110 az->x1 = region->winrct.xmin;
1111 az->y1 = region->winrct.ymax - azonepad_edge - overlap_padding;
1112 az->x2 = region->winrct.xmax;
1113 az->y2 = region->winrct.ymax + azonepad_edge - overlap_padding;
1114 break;
1116 az->x1 = region->winrct.xmin;
1117 az->y1 = region->winrct.ymin + azonepad_edge + overlap_padding;
1118 az->x2 = region->winrct.xmax;
1119 az->y2 = region->winrct.ymin - azonepad_edge + overlap_padding;
1120 break;
1122 az->x1 = region->winrct.xmin - azonepad_edge + overlap_padding;
1123 az->y1 = region->winrct.ymin;
1124 az->x2 = region->winrct.xmin + azonepad_edge + overlap_padding;
1125 az->y2 = region->winrct.ymax;
1126 break;
1128 az->x1 = region->winrct.xmax + azonepad_edge - overlap_padding;
1129 az->y1 = region->winrct.ymin;
1130 az->x2 = region->winrct.xmax - azonepad_edge - overlap_padding;
1131 az->y2 = region->winrct.ymax;
1132 break;
1133 }
1134 BLI_rcti_init(&az->rect, az->x1, az->x2, az->y1, az->y2);
1135}
1136
1137/* region already made zero sized, in shape of edge */
1138static void region_azone_tab_plus(ScrArea *area, AZone *az, ARegion *region)
1139{
1140 float edge_offset = 1.0f;
1141 const float tab_size_x = 0.7f * U.widget_unit;
1142 const float tab_size_y = 0.4f * U.widget_unit;
1143
1144 switch (az->edge) {
1145 case AE_TOP_TO_BOTTOMRIGHT: {
1146 int add = (region->winrct.ymax == area->totrct.ymin) ? 1 : 0;
1147 az->x1 = region->winrct.xmax - ((edge_offset + 1.0f) * tab_size_x);
1148 az->y1 = region->winrct.ymax - add;
1149 az->x2 = region->winrct.xmax - (edge_offset * tab_size_x);
1150 az->y2 = region->winrct.ymax - add + tab_size_y;
1151 break;
1152 }
1154 az->x1 = region->winrct.xmax - ((edge_offset + 1.0f) * tab_size_x);
1155 az->y1 = region->winrct.ymin - tab_size_y;
1156 az->x2 = region->winrct.xmax - (edge_offset * tab_size_x);
1157 az->y2 = region->winrct.ymin;
1158 break;
1160 az->x1 = region->winrct.xmin - tab_size_y;
1161 az->y1 = region->winrct.ymax - ((edge_offset + 1.0f) * tab_size_x);
1162 az->x2 = region->winrct.xmin;
1163 az->y2 = region->winrct.ymax - (edge_offset * tab_size_x);
1164 break;
1166 az->x1 = region->winrct.xmax;
1167 az->y1 = region->winrct.ymax - ((edge_offset + 1.0f) * tab_size_x);
1168 az->x2 = region->winrct.xmax + tab_size_y;
1169 az->y2 = region->winrct.ymax - (edge_offset * tab_size_x);
1170 break;
1171 }
1172 /* rect needed for mouse pointer test */
1173 BLI_rcti_init(&az->rect, az->x1, az->x2, az->y1, az->y2);
1174}
1175
1176static bool region_azone_edge_poll(const ARegion *region, const bool is_fullscreen)
1177{
1178 if (region->flag & RGN_FLAG_POLL_FAILED) {
1179 return false;
1180 }
1181
1182 /* Don't use edge if the region hides with previous region which is now hidden. See #116196. */
1183 if ((region->alignment & (RGN_SPLIT_PREV | RGN_ALIGN_HIDE_WITH_PREV) && region->prev) &&
1185 {
1186 return false;
1187 }
1188
1189 const bool is_hidden = (region->flag & (RGN_FLAG_HIDDEN | RGN_FLAG_TOO_SMALL));
1190
1191 if (is_hidden && is_fullscreen) {
1192 return false;
1193 }
1194 if (!is_hidden && ELEM(region->regiontype, RGN_TYPE_HEADER, RGN_TYPE_TOOL_HEADER)) {
1195 return false;
1196 }
1197
1198 if (is_hidden && (U.app_flag & USER_APP_HIDE_REGION_TOGGLE)) {
1199 return false;
1200 }
1201
1202 if (!is_hidden && (U.app_flag & USER_APP_LOCK_EDGE_RESIZE)) {
1203 return false;
1204 }
1205
1206 return true;
1207}
1208
1210 ARegion *region,
1211 AZEdge edge,
1212 const bool is_fullscreen)
1213{
1214 const bool is_hidden = (region->flag & (RGN_FLAG_HIDDEN | RGN_FLAG_TOO_SMALL));
1215
1216 if (!region_azone_edge_poll(region, is_fullscreen)) {
1217 return;
1218 }
1219
1220 AZone *az = (AZone *)MEM_callocN(sizeof(AZone), "actionzone");
1221 BLI_addtail(&(area->actionzones), az);
1222 az->type = AZONE_REGION;
1223 az->region = region;
1224 az->edge = edge;
1225
1226 if (is_hidden) {
1227 region_azone_tab_plus(area, az, region);
1228 }
1229 else {
1230 region_azone_edge(area, az, region);
1231 }
1232}
1233
1235 ARegion *region,
1236 AZScrollDirection direction)
1237{
1238 AZone *az = static_cast<AZone *>(MEM_callocN(sizeof(*az), __func__));
1239
1240 BLI_addtail(&area->actionzones, az);
1242 az->region = region;
1243 az->direction = direction;
1244
1245 if (direction == AZ_SCROLL_VERT) {
1246 az->region->v2d.alpha_vert = 0;
1247 }
1248 else if (direction == AZ_SCROLL_HOR) {
1249 az->region->v2d.alpha_hor = 0;
1250 }
1251
1252 /* No need to specify rect for scrollbar az. For intersection we'll test against the area around
1253 * the region's scroller instead, in `area_actionzone_get_rect`. */
1254}
1255
1257{
1258 const View2D *v2d = &region->v2d;
1259
1260 if ((v2d->scroll & V2D_SCROLL_VERTICAL) && ((v2d->scroll & V2D_SCROLL_VERTICAL_HANDLES) == 0)) {
1262 }
1263 if ((v2d->scroll & V2D_SCROLL_HORIZONTAL) &&
1264 ((v2d->scroll & V2D_SCROLL_HORIZONTAL_HANDLES) == 0))
1265 {
1267 }
1268}
1269
1270/* *************************************************************** */
1272 ARegion *region,
1273 const int alignment,
1274 const bool is_fullscreen)
1275{
1276
1277 /* edge code (t b l r) is along which area edge azone will be drawn */
1278 if (alignment == RGN_ALIGN_TOP) {
1279 region_azone_edge_init(area, region, AE_BOTTOM_TO_TOPLEFT, is_fullscreen);
1280 }
1281 else if (alignment == RGN_ALIGN_BOTTOM) {
1282 region_azone_edge_init(area, region, AE_TOP_TO_BOTTOMRIGHT, is_fullscreen);
1283 }
1284 else if (alignment == RGN_ALIGN_RIGHT) {
1285 region_azone_edge_init(area, region, AE_LEFT_TO_TOPRIGHT, is_fullscreen);
1286 }
1287 else if (alignment == RGN_ALIGN_LEFT) {
1288 region_azone_edge_init(area, region, AE_RIGHT_TO_TOPLEFT, is_fullscreen);
1289 }
1290}
1291
1292static void region_azones_add(const bScreen *screen, ScrArea *area, ARegion *region)
1293{
1294 const bool is_fullscreen = screen->state == SCREENFULL;
1295
1296 /* Only display tab or icons when the header region is hidden
1297 * (not the tool header - they overlap). */
1298 if (region->regiontype == RGN_TYPE_TOOL_HEADER) {
1299 return;
1300 }
1301
1302 region_azones_add_edge(area, region, RGN_ALIGN_ENUM_FROM_MASK(region->alignment), is_fullscreen);
1303
1304 /* For a split region also continue the azone edge from the next region if this region is aligned
1305 * with the next */
1306 if ((region->alignment & RGN_SPLIT_PREV) && region->prev) {
1308 area, region, RGN_ALIGN_ENUM_FROM_MASK(region->prev->alignment), is_fullscreen);
1309 }
1310
1311 if (is_fullscreen) {
1312 fullscreen_azone_init(area, region);
1313 }
1314
1315 region_azones_scrollbars_init(area, region);
1316}
1317
1318/* dir is direction to check, not the splitting edge direction! */
1319static int rct_fits(const rcti *rect, const eScreenAxis dir_axis, int size)
1320{
1321 if (dir_axis == SCREEN_AXIS_H) {
1322 return BLI_rcti_size_x(rect) + 1 - size;
1323 }
1324 /* Vertical. */
1325 return BLI_rcti_size_y(rect) + 1 - size;
1326}
1327
1328/* *************************************************************** */
1329
1330/* region should be overlapping */
1331/* function checks if some overlapping region was defined before - on same place */
1332static void region_overlap_fix(ScrArea *area, ARegion *region)
1333{
1334 /* find overlapping previous region on same place */
1335 ARegion *region_iter;
1336 int align1 = 0;
1337 const int align = RGN_ALIGN_ENUM_FROM_MASK(region->alignment);
1338 for (region_iter = region->prev; region_iter; region_iter = region_iter->prev) {
1339 if (region_iter->flag & (RGN_FLAG_POLL_FAILED | RGN_FLAG_HIDDEN)) {
1340 continue;
1341 }
1342 if (!region_iter->overlap || (region_iter->alignment & RGN_SPLIT_PREV)) {
1343 continue;
1344 }
1345
1346 const int align_iter = RGN_ALIGN_ENUM_FROM_MASK(region_iter->alignment);
1347 if (ELEM(align_iter, RGN_ALIGN_FLOAT)) {
1348 continue;
1349 }
1350
1351 align1 = align_iter;
1352 if (BLI_rcti_isect(&region_iter->winrct, &region->winrct, nullptr)) {
1353 if (align1 != align) {
1354 /* Left overlapping right or vice-versa, forbid this! */
1355 region->flag |= RGN_FLAG_TOO_SMALL;
1356 return;
1357 }
1358 /* Else, we have our previous region on same side. */
1359 break;
1360 }
1361 }
1362
1363 /* Guard against flags slipping through that would have to be masked out in usages below. */
1364 BLI_assert(align1 == RGN_ALIGN_ENUM_FROM_MASK(align1));
1365
1366 /* translate or close */
1367 if (region_iter) {
1368 if (align1 == RGN_ALIGN_LEFT) {
1369 if (region->winrct.xmax + region_iter->winx > area->winx - U.widget_unit) {
1370 region->flag |= RGN_FLAG_TOO_SMALL;
1371 return;
1372 }
1373 BLI_rcti_translate(&region->winrct, region_iter->winx, 0);
1374 }
1375 else if (align1 == RGN_ALIGN_RIGHT) {
1376 if (region->winrct.xmin - region_iter->winx < U.widget_unit) {
1377 region->flag |= RGN_FLAG_TOO_SMALL;
1378 return;
1379 }
1380 BLI_rcti_translate(&region->winrct, -region_iter->winx, 0);
1381 }
1382 }
1383
1384 /* At this point, 'region' is in its final position and still open.
1385 * Make a final check it does not overlap any previous 'other side' region. */
1386 for (region_iter = region->prev; region_iter; region_iter = region_iter->prev) {
1387 if (region_iter->flag & (RGN_FLAG_POLL_FAILED | RGN_FLAG_HIDDEN)) {
1388 continue;
1389 }
1390 if (!region_iter->overlap || (region_iter->alignment & RGN_SPLIT_PREV)) {
1391 continue;
1392 }
1393
1394 const int align_iter = RGN_ALIGN_ENUM_FROM_MASK(region_iter->alignment);
1395 if (ELEM(align_iter, RGN_ALIGN_FLOAT)) {
1396 continue;
1397 }
1398
1399 if ((align_iter != align) && BLI_rcti_isect(&region_iter->winrct, &region->winrct, nullptr)) {
1400 /* Left overlapping right or vice-versa, forbid this! */
1401 region->flag |= RGN_FLAG_TOO_SMALL;
1402 return;
1403 }
1404 }
1405}
1406
1407bool ED_region_is_overlap(int spacetype, int regiontype)
1408{
1409 if (regiontype == RGN_TYPE_HUD) {
1410 return true;
1411 }
1412 if (U.uiflag2 & USER_REGION_OVERLAP) {
1413 if (spacetype == SPACE_NODE) {
1414 if (regiontype == RGN_TYPE_TOOLS) {
1415 return true;
1416 }
1417 }
1418 else if (spacetype == SPACE_VIEW3D) {
1419 if (regiontype == RGN_TYPE_HEADER) {
1420 /* Do not treat as overlapped if no transparency. */
1421 bTheme *theme = UI_GetTheme();
1422 return theme->space_view3d.header[3] != 255;
1423 }
1424 if (ELEM(regiontype,
1432 {
1433 return true;
1434 }
1435 }
1436 else if (spacetype == SPACE_IMAGE) {
1437 if (ELEM(regiontype,
1445 {
1446 return true;
1447 }
1448 }
1449 }
1450
1451 return false;
1452}
1453
1455 ScrArea *area, ARegion *region, rcti *remainder, rcti *overlap_remainder, int quad)
1456{
1457 using namespace blender::ed;
1458 rcti *remainder_prev = remainder;
1459
1460 if (region == nullptr) {
1461 return;
1462 }
1463
1464 int prev_winx = region->winx;
1465 int prev_winy = region->winy;
1466
1467 /* no returns in function, winrct gets set in the end again */
1468 BLI_rcti_init(&region->winrct, 0, 0, 0, 0);
1469
1470 /* for test; allow split of previously defined region */
1471 if (region->alignment & RGN_SPLIT_PREV) {
1472 if (region->prev) {
1473 remainder = &region->prev->winrct;
1474 }
1475 }
1476
1477 int alignment = RGN_ALIGN_ENUM_FROM_MASK(region->alignment);
1478
1479 /* set here, assuming userpref switching forces to call this again */
1480 region->overlap = ED_region_is_overlap(area->spacetype, region->regiontype);
1481
1482 /* clear state flags first */
1484 /* user errors */
1485 if ((region->next == nullptr) && !ELEM(alignment, RGN_ALIGN_QSPLIT, RGN_ALIGN_FLOAT)) {
1486 alignment = RGN_ALIGN_NONE;
1487 }
1488
1489 /* If both the #ARegion.sizex/y and the #ARegionType.prefsizex/y are 0, the region is tagged as
1490 * too small, even before the layout for dynamically sized regions is created.
1491 * #wm_draw_window_offscreen() allows the layout to be created despite the #RGN_FLAG_TOO_SMALL
1492 * flag being set. But there may still be regions that don't have a separate #ARegionType.layout
1493 * callback. For those, set a default #ARegionType.prefsizex/y so they can become visible. */
1494 if ((region->flag & RGN_FLAG_DYNAMIC_SIZE) && !(region->type->layout)) {
1495 if ((region->sizex == 0) && (region->type->prefsizex == 0)) {
1496 region->type->prefsizex = AREAMINX;
1497 }
1498 if ((region->sizey == 0) && (region->type->prefsizey == 0)) {
1499 region->type->prefsizey = HEADERY;
1500 }
1501 }
1502
1503 /* `prefsizex/y`, taking into account DPI. */
1504 int prefsizex = UI_SCALE_FAC *
1505 ((region->sizex > 1) ? region->sizex + 0.5f : region->type->prefsizex);
1506 int prefsizey;
1507
1508 if (region->regiontype == RGN_TYPE_HEADER) {
1509 prefsizey = ED_area_headersize();
1510 }
1511 else if (region->regiontype == RGN_TYPE_TOOL_HEADER) {
1512 prefsizey = ED_area_headersize();
1513 }
1514 else if (region->regiontype == RGN_TYPE_FOOTER) {
1515 prefsizey = ED_area_footersize();
1516 }
1517 else if (region->regiontype == RGN_TYPE_ASSET_SHELF) {
1518 prefsizey = region->sizey > 1 ? (UI_SCALE_FAC * (region->sizey + 0.5f)) :
1520 }
1521 else if (region->regiontype == RGN_TYPE_ASSET_SHELF_HEADER) {
1523 }
1524 else if (ED_area_is_global(area)) {
1525 prefsizey = ED_region_global_size_y();
1526 }
1527 else {
1528 prefsizey = UI_SCALE_FAC *
1529 (region->sizey > 1 ? region->sizey + 0.5f : region->type->prefsizey);
1530 }
1531
1532 if (region->flag & (RGN_FLAG_POLL_FAILED | RGN_FLAG_HIDDEN)) {
1533 /* hidden is user flag */
1534 }
1535 else if (alignment == RGN_ALIGN_FLOAT) {
1542 const int size_min[2] = {UI_UNIT_X, UI_UNIT_Y};
1543 rcti overlap_remainder_margin = *overlap_remainder;
1544
1545 BLI_rcti_resize(&overlap_remainder_margin,
1546 max_ii(0, BLI_rcti_size_x(overlap_remainder) - UI_UNIT_X / 2),
1547 max_ii(0, BLI_rcti_size_y(overlap_remainder) - UI_UNIT_Y / 2));
1548 region->winrct.xmin = overlap_remainder_margin.xmin + region->runtime.offset_x;
1549 region->winrct.ymin = overlap_remainder_margin.ymin + region->runtime.offset_y;
1550 region->winrct.xmax = region->winrct.xmin + prefsizex - 1;
1551 region->winrct.ymax = region->winrct.ymin + prefsizey - 1;
1552
1553 BLI_rcti_isect(&region->winrct, &overlap_remainder_margin, &region->winrct);
1554
1555 if (BLI_rcti_size_x(&region->winrct) != prefsizex - 1) {
1556 region->flag |= RGN_FLAG_SIZE_CLAMP_X;
1557 }
1558 if (BLI_rcti_size_y(&region->winrct) != prefsizey - 1) {
1559 region->flag |= RGN_FLAG_SIZE_CLAMP_Y;
1560 }
1561
1562 /* We need to use a test that won't have been previously clamped. */
1563 rcti winrct_test{};
1564 winrct_test.xmin = region->winrct.xmin;
1565 winrct_test.ymin = region->winrct.ymin;
1566 winrct_test.xmax = region->winrct.xmin + size_min[0];
1567 winrct_test.ymax = region->winrct.ymin + size_min[1];
1568
1569 BLI_rcti_isect(&winrct_test, &overlap_remainder_margin, &winrct_test);
1570 if (BLI_rcti_size_x(&winrct_test) < size_min[0] || BLI_rcti_size_y(&winrct_test) < size_min[1])
1571 {
1572 region->flag |= RGN_FLAG_TOO_SMALL;
1573 }
1574 }
1575 else if (rct_fits(remainder, SCREEN_AXIS_V, 1) < 0 || rct_fits(remainder, SCREEN_AXIS_H, 1) < 0)
1576 {
1577 /* remainder is too small for any usage */
1578 region->flag |= RGN_FLAG_TOO_SMALL;
1579 }
1580 else if (alignment == RGN_ALIGN_NONE) {
1581 /* typically last region */
1582 region->winrct = *remainder;
1583 BLI_rcti_init(remainder, 0, 0, 0, 0);
1584 }
1585 else if (ELEM(alignment, RGN_ALIGN_TOP, RGN_ALIGN_BOTTOM)) {
1586 rcti *winrct = (region->overlap) ? overlap_remainder : remainder;
1587
1588 if ((prefsizey == 0) || (rct_fits(winrct, SCREEN_AXIS_V, prefsizey) < 0)) {
1589 region->flag |= RGN_FLAG_TOO_SMALL;
1590 }
1591 else {
1592 int fac = rct_fits(winrct, SCREEN_AXIS_V, prefsizey);
1593
1594 if (fac < 0) {
1595 prefsizey += fac;
1596 }
1597
1598 region->winrct = *winrct;
1599
1600 if (alignment == RGN_ALIGN_TOP) {
1601 region->winrct.ymin = region->winrct.ymax - prefsizey + 1;
1602 winrct->ymax = region->winrct.ymin - 1;
1603 }
1604 else {
1605 region->winrct.ymax = region->winrct.ymin + prefsizey - 1;
1606 winrct->ymin = region->winrct.ymax + 1;
1607 }
1608 BLI_rcti_sanitize(winrct);
1609 }
1610 }
1611 else if (ELEM(alignment, RGN_ALIGN_LEFT, RGN_ALIGN_RIGHT)) {
1612 rcti *winrct = (region->overlap) ? overlap_remainder : remainder;
1613
1614 if ((prefsizex == 0) || (rct_fits(winrct, SCREEN_AXIS_H, prefsizex) < 0)) {
1615 region->flag |= RGN_FLAG_TOO_SMALL;
1616 }
1617 else {
1618 int fac = rct_fits(winrct, SCREEN_AXIS_H, prefsizex);
1619
1620 if (fac < 0) {
1621 prefsizex += fac;
1622 }
1623
1624 region->winrct = *winrct;
1625
1626 if (alignment == RGN_ALIGN_RIGHT) {
1627 region->winrct.xmin = region->winrct.xmax - prefsizex + 1;
1628 winrct->xmax = region->winrct.xmin - 1;
1629 }
1630 else {
1631 region->winrct.xmax = region->winrct.xmin + prefsizex - 1;
1632 winrct->xmin = region->winrct.xmax + 1;
1633 }
1634 BLI_rcti_sanitize(winrct);
1635 }
1636 }
1637 else if (ELEM(alignment, RGN_ALIGN_VSPLIT, RGN_ALIGN_HSPLIT)) {
1638 /* Percentage subdiv. */
1639 region->winrct = *remainder;
1640
1641 if (alignment == RGN_ALIGN_HSPLIT) {
1642 if (rct_fits(remainder, SCREEN_AXIS_H, prefsizex) > 4) {
1643 region->winrct.xmax = BLI_rcti_cent_x(remainder);
1644 remainder->xmin = region->winrct.xmax + 1;
1645 }
1646 else {
1647 BLI_rcti_init(remainder, 0, 0, 0, 0);
1648 }
1649 }
1650 else {
1651 if (rct_fits(remainder, SCREEN_AXIS_V, prefsizey) > 4) {
1652 region->winrct.ymax = BLI_rcti_cent_y(remainder);
1653 remainder->ymin = region->winrct.ymax + 1;
1654 }
1655 else {
1656 BLI_rcti_init(remainder, 0, 0, 0, 0);
1657 }
1658 }
1659 }
1660 else if (alignment == RGN_ALIGN_QSPLIT) {
1661 region->winrct = *remainder;
1662
1663 /* test if there's still 4 regions left */
1664 if (quad == 0) {
1665 ARegion *region_test = region->next;
1666 int count = 1;
1667
1668 while (region_test) {
1669 region_test->alignment = RGN_ALIGN_QSPLIT;
1670 region_test = region_test->next;
1671 count++;
1672 }
1673
1674 if (count != 4) {
1675 /* let's stop adding regions */
1676 BLI_rcti_init(remainder, 0, 0, 0, 0);
1677 if (G.debug & G_DEBUG) {
1678 printf("region quadsplit failed\n");
1679 }
1680 }
1681 else {
1682 quad = 1;
1683 }
1684 }
1685 if (quad) {
1686 if (quad == 1) { /* left bottom */
1687 region->winrct.xmax = BLI_rcti_cent_x(remainder);
1688 region->winrct.ymax = BLI_rcti_cent_y(remainder);
1689 }
1690 else if (quad == 2) { /* left top */
1691 region->winrct.xmax = BLI_rcti_cent_x(remainder);
1692 region->winrct.ymin = BLI_rcti_cent_y(remainder) + 1;
1693 }
1694 else if (quad == 3) { /* right bottom */
1695 region->winrct.xmin = BLI_rcti_cent_x(remainder) + 1;
1696 region->winrct.ymax = BLI_rcti_cent_y(remainder);
1697 }
1698 else { /* right top */
1699 region->winrct.xmin = BLI_rcti_cent_x(remainder) + 1;
1700 region->winrct.ymin = BLI_rcti_cent_y(remainder) + 1;
1701 BLI_rcti_init(remainder, 0, 0, 0, 0);
1702 }
1703
1704 /* Fix any negative dimensions. This can happen when a quad split 3d view gets too small.
1705 * (see #72200). */
1706 BLI_rcti_sanitize(&region->winrct);
1707
1708 quad++;
1709 }
1710 }
1711
1712 /* for speedup */
1713 region->winx = BLI_rcti_size_x(&region->winrct) + 1;
1714 region->winy = BLI_rcti_size_y(&region->winrct) + 1;
1715
1716 /* If region opened normally, we store this for hide/reveal usage. */
1717 /* Prevent rounding errors for UI_SCALE_FAC multiply and divide. */
1718 if (region->winx > 1) {
1719 region->sizex = (region->winx + 0.5f) / UI_SCALE_FAC;
1720 }
1721 if (region->winy > 1) {
1722 region->sizey = (region->winy + 0.5f) / UI_SCALE_FAC;
1723 }
1724
1725 /* exception for multiple overlapping regions on same spot */
1726 if (region->overlap && (alignment != RGN_ALIGN_FLOAT)) {
1727 region_overlap_fix(area, region);
1728 }
1729
1730 /* Set `region->winrct` for action-zones. */
1731 if (region->flag & (RGN_FLAG_HIDDEN | RGN_FLAG_TOO_SMALL)) {
1732 region->winrct = (region->overlap) ? *overlap_remainder : *remainder;
1733
1734 switch (alignment) {
1735 case RGN_ALIGN_TOP:
1736 region->winrct.ymin = region->winrct.ymax;
1737 break;
1738 case RGN_ALIGN_BOTTOM:
1739 region->winrct.ymax = region->winrct.ymin;
1740 break;
1741 case RGN_ALIGN_RIGHT:
1742 region->winrct.xmin = region->winrct.xmax;
1743 break;
1744 case RGN_ALIGN_LEFT:
1745 region->winrct.xmax = region->winrct.xmin;
1746 break;
1747 default:
1748 /* prevent winrct to be valid */
1749 region->winrct.xmax = region->winrct.xmin;
1750 break;
1751 }
1752
1753 /* Size on one axis is now 0, the other axis may still be invalid (negative) though. */
1754 BLI_rcti_sanitize(&region->winrct);
1755 }
1756
1757 /* restore prev-split exception */
1758 if (region->alignment & RGN_SPLIT_PREV) {
1759 if (region->prev) {
1760 remainder = remainder_prev;
1761 region->prev->winx = BLI_rcti_size_x(&region->prev->winrct) + 1;
1762 region->prev->winy = BLI_rcti_size_y(&region->prev->winrct) + 1;
1763 }
1764 }
1765
1766 /* After non-overlapping region, all following overlapping regions
1767 * fit within the remaining space again. */
1768 if (!region->overlap) {
1769 *overlap_remainder = *remainder;
1770 }
1771
1773
1774 region_rect_recursive(area, region->next, remainder, overlap_remainder, quad);
1775
1776 /* Tag for redraw if size changes. */
1777 if (region->winx != prev_winx || region->winy != prev_winy) {
1778 /* 3D View needs a full rebuild in case a progressive render runs. Rest can live with
1779 * no-rebuild (e.g. Outliner) */
1780 if (area->spacetype == SPACE_VIEW3D) {
1781 ED_region_tag_redraw(region);
1782 }
1783 else {
1785 }
1786 }
1787
1788 /* Clear, initialize on demand. */
1789 memset(&region->runtime.visible_rect, 0, sizeof(region->runtime.visible_rect));
1790}
1791
1792static void area_calc_totrct(ScrArea *area, const rcti *window_rect)
1793{
1794 short px = short(U.pixelsize);
1795
1796 area->totrct.xmin = area->v1->vec.x;
1797 area->totrct.xmax = area->v4->vec.x;
1798 area->totrct.ymin = area->v1->vec.y;
1799 area->totrct.ymax = area->v2->vec.y;
1800
1801 /* scale down totrct by 1 pixel on all sides not matching window borders */
1802 if (area->totrct.xmin > window_rect->xmin) {
1803 area->totrct.xmin += px;
1804 }
1805 if (area->totrct.xmax < (window_rect->xmax - 1)) {
1806 area->totrct.xmax -= px;
1807 }
1808 if (area->totrct.ymin > window_rect->ymin) {
1809 area->totrct.ymin += px;
1810 }
1811 if (area->totrct.ymax < (window_rect->ymax - 1)) {
1812 area->totrct.ymax -= px;
1813 }
1814 /* Although the following asserts are correct they lead to a very unstable Blender.
1815 * And the asserts would fail even in 2.7x
1816 * (they were added in 2.8x as part of the top-bar commit).
1817 * For more details see #54864. */
1818#if 0
1819 BLI_assert(area->totrct.xmin >= 0);
1820 BLI_assert(area->totrct.xmax >= 0);
1821 BLI_assert(area->totrct.ymin >= 0);
1822 BLI_assert(area->totrct.ymax >= 0);
1823#endif
1824
1825 /* for speedup */
1826 area->winx = BLI_rcti_size_x(&area->totrct) + 1;
1827 area->winy = BLI_rcti_size_y(&area->totrct) + 1;
1828}
1829
1834{
1835 bool hidden = (region->flag & (RGN_FLAG_POLL_FAILED | RGN_FLAG_HIDDEN | RGN_FLAG_TOO_SMALL)) !=
1836 0;
1837
1838 if ((region->alignment & (RGN_SPLIT_PREV | RGN_ALIGN_HIDE_WITH_PREV)) && region->prev) {
1839 hidden = hidden || (region->prev->flag & (RGN_FLAG_HIDDEN | RGN_FLAG_TOO_SMALL));
1840 }
1841
1842 region->visible = !hidden;
1843}
1844
1845static bool event_in_markers_region(const ARegion *region, const wmEvent *event)
1846{
1847 rcti rect = region->winrct;
1848 rect.ymax = rect.ymin + UI_MARKER_MARGIN_Y;
1849 return BLI_rcti_isect_pt_v(&rect, event->xy);
1850}
1851
1856 wmWindowManager *wm, ScrArea *area, ARegion *region, ListBase *handlers, int flag)
1857{
1858 BLI_assert(region ? (&region->handlers == handlers) : (&area->handlers == handlers));
1859
1860 /* NOTE: add-handler checks if it already exists. */
1861
1862 /* XXX: it would be good to have bound-box checks for some of these. */
1863 if (flag & ED_KEYMAP_UI) {
1864 wmKeyMap *keymap = WM_keymap_ensure(
1865 wm->defaultconf, "User Interface", SPACE_EMPTY, RGN_TYPE_WINDOW);
1866 WM_event_add_keymap_handler(handlers, keymap);
1867
1870
1871 /* user interface widgets */
1872 UI_region_handlers_add(handlers);
1873 }
1874 if (flag & ED_KEYMAP_GIZMO) {
1876 if (region) {
1877 /* Anything else is confusing, only allow this. */
1878 BLI_assert(&region->handlers == handlers);
1879 if (region->gizmo_map == nullptr) {
1881 params.spaceid = area->spacetype;
1882 params.regionid = region->type->regionid;
1884 }
1885 WM_gizmomap_add_handlers(region, region->gizmo_map);
1886 }
1887 }
1888 if (flag & ED_KEYMAP_VIEW2D) {
1889 /* 2d-viewport handling+manipulation */
1890 wmKeyMap *keymap = WM_keymap_ensure(wm->defaultconf, "View2D", SPACE_EMPTY, RGN_TYPE_WINDOW);
1891 WM_event_add_keymap_handler(handlers, keymap);
1892 }
1893 if (flag & ED_KEYMAP_ANIMATION) {
1894 wmKeyMap *keymap;
1895
1896 /* time-markers */
1897 keymap = WM_keymap_ensure(wm->defaultconf, "Markers", SPACE_EMPTY, RGN_TYPE_WINDOW);
1899
1900 /* time-scrub */
1901 keymap = WM_keymap_ensure(wm->defaultconf, "Time Scrub", SPACE_EMPTY, RGN_TYPE_WINDOW);
1903
1904 /* frame changing and timeline operators (for time spaces) */
1905 keymap = WM_keymap_ensure(wm->defaultconf, "Animation", SPACE_EMPTY, RGN_TYPE_WINDOW);
1906 WM_event_add_keymap_handler(handlers, keymap);
1907 }
1908 if (flag & ED_KEYMAP_TOOL) {
1909 if (flag & ED_KEYMAP_GIZMO) {
1912 }
1913 else {
1916 }
1917 }
1918 if (flag & ED_KEYMAP_FRAMES) {
1919 /* frame changing/jumping (for all spaces) */
1920 wmKeyMap *keymap = WM_keymap_ensure(wm->defaultconf, "Frames", SPACE_EMPTY, RGN_TYPE_WINDOW);
1921 WM_event_add_keymap_handler(handlers, keymap);
1922 }
1923 if (flag & ED_KEYMAP_HEADER) {
1924 /* standard keymap for headers regions */
1925 wmKeyMap *keymap = WM_keymap_ensure(
1926 wm->defaultconf, "Region Context Menu", SPACE_EMPTY, RGN_TYPE_WINDOW);
1927 WM_event_add_keymap_handler(handlers, keymap);
1928 }
1929 if (flag & ED_KEYMAP_FOOTER) {
1930 /* standard keymap for footer regions */
1931 wmKeyMap *keymap = WM_keymap_ensure(
1932 wm->defaultconf, "Region Context Menu", SPACE_EMPTY, RGN_TYPE_WINDOW);
1933 WM_event_add_keymap_handler(handlers, keymap);
1934 }
1935 if (flag & ED_KEYMAP_NAVBAR) {
1936 /* standard keymap for Navigation bar regions */
1937 wmKeyMap *keymap = WM_keymap_ensure(
1938 wm->defaultconf, "Region Context Menu", SPACE_EMPTY, RGN_TYPE_WINDOW);
1939 WM_event_add_keymap_handler(&region->handlers, keymap);
1940 }
1942 /* standard keymap for asset shelf regions */
1943 wmKeyMap *keymap = WM_keymap_ensure(
1944 wm->defaultconf, "Asset Shelf", SPACE_EMPTY, RGN_TYPE_WINDOW);
1945 WM_event_add_keymap_handler(&region->handlers, keymap);
1946 }
1947
1948 /* Keep last because of LMB/RMB handling, see: #57527. */
1949 if (flag & ED_KEYMAP_GPENCIL) {
1950 /* grease pencil */
1951 {
1952 wmKeyMap *keymap = WM_keymap_ensure(
1953 wm->defaultconf, "Grease Pencil", SPACE_EMPTY, RGN_TYPE_WINDOW);
1954 WM_event_add_keymap_handler(handlers, keymap);
1955 }
1956 }
1957}
1958
1960{
1961 if (!(area->flag & AREA_FLAG_REGION_SIZE_UPDATE)) {
1962 return;
1963 }
1964 const bScreen *screen = WM_window_get_active_screen(win);
1965
1966 rcti window_rect;
1967 WM_window_rect_calc(win, &window_rect);
1968 area_calc_totrct(area, &window_rect);
1969
1970 /* region rect sizes */
1971 rcti rect = area->totrct;
1972 rcti overlap_rect = rect;
1974 area, static_cast<ARegion *>(area->regionbase.first), &rect, &overlap_rect, 0);
1975
1976 /* Dynamically sized regions may have changed region sizes, so we have to force azone update. */
1977 area_azone_init(win, screen, area);
1978
1979 LISTBASE_FOREACH (ARegion *, region, &area->regionbase) {
1980 if (region->flag & RGN_FLAG_POLL_FAILED) {
1981 continue;
1982 }
1984
1985 /* region size may have changed, init does necessary adjustments */
1986 if (region->type->init) {
1987 region->type->init(wm, region);
1988 }
1989
1990 /* Some AZones use View2D data which is only updated in region init, so call that first! */
1991 region_azones_add(screen, area, region);
1992 }
1993 ED_area_azones_update(area, win->eventstate->xy);
1994
1996}
1997
1999{
2000 return area_getorientation(a, b) != -1;
2001}
2002
2006static void area_init_type_fallback(ScrArea *area, eSpace_Type space_type)
2007{
2008 BLI_assert(area->type == nullptr);
2009 area->spacetype = space_type;
2010 area->type = BKE_spacetype_from_id(area->spacetype);
2011
2012 SpaceLink *sl = nullptr;
2013 LISTBASE_FOREACH (SpaceLink *, sl_iter, &area->spacedata) {
2014 if (sl_iter->spacetype == space_type) {
2015 sl = sl_iter;
2016 break;
2017 }
2018 }
2019 if (sl) {
2020 SpaceLink *sl_old = static_cast<SpaceLink *>(area->spacedata.first);
2021 if (LIKELY(sl != sl_old)) {
2022 BLI_remlink(&area->spacedata, sl);
2023 BLI_addhead(&area->spacedata, sl);
2024
2025 /* swap regions */
2026 sl_old->regionbase = area->regionbase;
2027 area->regionbase = sl->regionbase;
2029 }
2030 }
2031 else {
2032 screen_area_spacelink_add(nullptr, area, space_type);
2033 }
2034}
2035
2037{
2038 area->type = BKE_spacetype_from_id(area->spacetype);
2039
2040 if (area->type == nullptr) {
2042 BLI_assert(area->type != nullptr);
2043 }
2044
2045 LISTBASE_FOREACH (ARegion *, region, &area->regionbase) {
2046 region->type = BKE_regiontype_from_id(area->type, region->regiontype);
2047 /* Invalid region types may be stored in files (e.g. for new files), but they should be handled
2048 * on file read already, see #BKE_screen_area_blend_read_lib(). */
2049 BLI_assert_msg(region->type != nullptr, "Region type not valid for this space type");
2050 }
2051}
2052
2054{
2055 WorkSpace *workspace = WM_window_get_active_workspace(win);
2057 const Scene *scene = WM_window_get_active_scene(win);
2058 ViewLayer *view_layer = WM_window_get_active_view_layer(win);
2059
2060 if (ED_area_is_global(area) && (area->global->flag & GLOBAL_AREA_IS_HIDDEN)) {
2061 return;
2062 }
2063
2064 rcti window_rect;
2065 WM_window_rect_calc(win, &window_rect);
2066
2068
2069 /* area sizes */
2070 area_calc_totrct(area, &window_rect);
2071
2072 /* region rect sizes */
2073 rcti rect = area->totrct;
2074 rcti overlap_rect = rect;
2076 area, static_cast<ARegion *>(area->regionbase.first), &rect, &overlap_rect, 0);
2078
2079 /* default area handlers */
2080 ed_default_handlers(wm, area, nullptr, &area->handlers, area->type->keymapflag);
2081 /* checks spacedata, adds own handlers */
2082 if (area->type->init) {
2083 area->type->init(wm, area);
2084 }
2085
2086 /* clear all azones, add the area triangle widgets */
2087 area_azone_init(win, screen, area);
2088
2089 /* region windows, default and own handlers */
2090 LISTBASE_FOREACH (ARegion *, region, &area->regionbase) {
2092
2093 if (region->visible) {
2094 /* default region handlers */
2095 ed_default_handlers(wm, area, region, &region->handlers, region->type->keymapflag);
2096 /* own handlers */
2097 if (region->type->init) {
2098 region->type->init(wm, region);
2099 }
2100 }
2101 else {
2102 /* prevent uiblocks to run */
2103 UI_blocklist_free(nullptr, region);
2104 }
2105
2106 /* Some AZones use View2D data which is only updated in region init, so call that first! */
2107 region_azones_add(screen, area, region);
2108 }
2109
2110 /* Avoid re-initializing tools while resizing areas & regions. */
2111 if ((G.moving & G_TRANSFORM_WM) == 0) {
2112 if ((1 << area->spacetype) & WM_TOOLSYSTEM_SPACE_MASK) {
2113 if (WM_toolsystem_refresh_screen_area(workspace, scene, view_layer, area) ||
2114 /* When the tool is null it may not be initialized.
2115 * This happens when switching to a new area, see: #126990.
2116 *
2117 * NOTE(@ideasman42): There is a possible down-side here: when refreshing
2118 * tools results in a null value, refreshing won't be skipped here as intended.
2119 * As it happens, spaces that use tools will practically always have a default tool. */
2120 (area->runtime.tool == nullptr))
2121 {
2122 /* Only re-initialize as needed to prevent redundant updates as they
2123 * can cause gizmos to flicker when the flag is set continuously, see: #126525. */
2125 }
2126 }
2127 else {
2128 area->runtime.tool = nullptr;
2129 area->runtime.is_tool_set = true;
2130 }
2131 }
2132}
2133
2135{
2136 area->flag |= AREA_FLAG_OFFSCREEN;
2137 area->type = BKE_spacetype_from_id(area->spacetype);
2138 /* Off screen areas are only ever created at run-time,
2139 * so there is no reason for the type to be unknown. */
2140 BLI_assert(area->type != nullptr);
2141
2142 LISTBASE_FOREACH (ARegion *, region, &area->regionbase) {
2143 region->type = BKE_regiontype_from_id(area->type, region->regiontype);
2144 }
2145}
2146
2148{
2149 ScrArea *area = static_cast<ScrArea *>(MEM_callocN(sizeof(ScrArea), __func__));
2150 area->spacetype = space_type;
2151
2153 area_offscreen_init(area);
2154
2155 return area;
2156}
2157
2159{
2160 if (area->type && area->type->exit) {
2161 area->type->exit(wm, area);
2162 }
2163
2164 LISTBASE_FOREACH (ARegion *, region, &area->regionbase) {
2165 if (region->type && region->type->exit) {
2166 region->type->exit(wm, region);
2167 }
2168
2169 WM_event_modal_handler_region_replace(win, region, nullptr);
2170 WM_draw_region_free(region);
2171 region->visible = false;
2172
2173 MEM_SAFE_FREE(region->headerstr);
2174
2175 if (region->regiontimer) {
2176 WM_event_timer_remove(wm, win, region->regiontimer);
2177 region->regiontimer = nullptr;
2178 }
2179
2180 if (wm->message_bus) {
2181 WM_msgbus_clear_by_owner(wm->message_bus, region);
2182 }
2183 }
2184
2185 WM_event_modal_handler_area_replace(win, area, nullptr);
2186}
2187
2189{
2190 area_offscreen_exit(wm, win, area);
2191
2193 MEM_freeN(area);
2194}
2195
2196static void region_update_rect(ARegion *region)
2197{
2198 region->winx = BLI_rcti_size_x(&region->winrct) + 1;
2199 region->winy = BLI_rcti_size_y(&region->winrct) + 1;
2200
2201 /* v2d mask is used to subtract scrollbars from a 2d view. Needs initialize here. */
2202 BLI_rcti_init(&region->v2d.mask, 0, region->winx - 1, 0, region->winy - 1);
2203}
2204
2206{
2207 region_update_rect(region);
2208}
2209
2211{
2213
2214 /* refresh can be called before window opened */
2216
2217 region_update_rect(region);
2218}
2219
2221{
2222 if (region != nullptr) {
2223 if ((region->gizmo_map != nullptr) && WM_gizmomap_cursor_set(region->gizmo_map, win)) {
2224 return;
2225 }
2226 if (area && region->type && region->type->cursor) {
2227 region->type->cursor(win, area, region);
2228 return;
2229 }
2230 }
2231
2232 if (WM_cursor_set_from_tool(win, area, region)) {
2233 return;
2234 }
2235
2237}
2238
2240 bContext *C, ScrArea *area, ARegion *region, bool is_hidden, bool do_init)
2241{
2242 if (is_hidden) {
2244 /* Needed to close any open pop-overs which would otherwise remain open,
2245 * crashing on attempting to refresh. See: #93410.
2246 *
2247 * When #ED_area_init frees buttons via #UI_blocklist_free a nullptr context
2248 * is passed, causing the free not to remove menus or their handlers. */
2250 }
2251
2252 if (do_init) {
2254 ED_area_tag_redraw(area);
2255 }
2256}
2257
2259{
2260 const bool is_hidden = region->flag & (RGN_FLAG_HIDDEN | RGN_FLAG_POLL_FAILED);
2261 const bool do_init = true;
2262 ED_region_visibility_change_update_ex(C, area, region, is_hidden, do_init);
2263}
2264
2265void region_toggle_hidden(bContext *C, ARegion *region, const bool do_fade)
2266{
2267 ScrArea *area = CTX_wm_area(C);
2268
2269 region->flag ^= RGN_FLAG_HIDDEN;
2270
2271 if (do_fade && region->overlap) {
2272 /* starts a timer, and in end calls the stuff below itself (region_sblend_invoke()) */
2274 }
2275 else {
2277 }
2278}
2279
2281{
2282 region_toggle_hidden(C, region, true);
2283}
2284
2285void ED_area_data_copy(ScrArea *area_dst, ScrArea *area_src, const bool do_free)
2286{
2287 const char spacetype = area_dst->spacetype;
2288 const short flag_copy = HEADER_NO_PULLDOWN;
2289
2290 area_dst->spacetype = area_src->spacetype;
2291 area_dst->type = area_src->type;
2292
2293 area_dst->flag = (area_dst->flag & ~flag_copy) | (area_src->flag & flag_copy);
2294
2295 /* area */
2296 if (do_free) {
2298 }
2299 BKE_spacedata_copylist(&area_dst->spacedata, &area_src->spacedata);
2300
2301 /* NOTE: SPACE_EMPTY is possible on new screens. */
2302
2303 /* regions */
2304 if (do_free) {
2305 SpaceType *st = BKE_spacetype_from_id(spacetype);
2306 LISTBASE_FOREACH (ARegion *, region, &area_dst->regionbase) {
2307 BKE_area_region_free(st, region);
2308 }
2309 BLI_freelistN(&area_dst->regionbase);
2310 }
2311 SpaceType *st = BKE_spacetype_from_id(area_src->spacetype);
2312 LISTBASE_FOREACH (ARegion *, region, &area_src->regionbase) {
2313 ARegion *newar = BKE_area_region_copy(st, region);
2314 BLI_addtail(&area_dst->regionbase, newar);
2315 }
2316}
2317
2318void ED_area_data_swap(ScrArea *area_dst, ScrArea *area_src)
2319{
2320 std::swap(area_dst->spacetype, area_src->spacetype);
2321 std::swap(area_dst->type, area_src->type);
2322
2323 std::swap(area_dst->spacedata, area_src->spacedata);
2324 std::swap(area_dst->regionbase, area_src->regionbase);
2325}
2326
2327/* -------------------------------------------------------------------- */
2330
2339 struct {
2350};
2351
2353{
2354 for (int index = 0; index < RGN_TYPE_NUM; index++) {
2355 r_align_info->by_type[index].alignment = -1;
2356 /* Default to true, when it doesn't exist - it's effectively hidden. */
2357 r_align_info->by_type[index].hidden = true;
2358 }
2359
2360 LISTBASE_FOREACH (ARegion *, region, &area->regionbase) {
2361 if (region->flag & RGN_FLAG_POLL_FAILED) {
2362 continue;
2363 }
2364
2365 const int index = region->regiontype;
2366 if (uint(index) < RGN_TYPE_NUM) {
2367 r_align_info->by_type[index].alignment = RGN_ALIGN_ENUM_FROM_MASK(region->alignment);
2368 r_align_info->by_type[index].hidden = (region->flag & RGN_FLAG_HIDDEN) != 0;
2369 }
2370 }
2371}
2372
2381 const RegionTypeAlignInfo *region_align_info, const short fallback)
2382{
2383 const short header_alignment = region_align_info->by_type[RGN_TYPE_HEADER].alignment;
2384 const short tool_header_alignment = region_align_info->by_type[RGN_TYPE_TOOL_HEADER].alignment;
2385
2386 const bool header_hidden = region_align_info->by_type[RGN_TYPE_HEADER].hidden;
2387 const bool tool_header_hidden = region_align_info->by_type[RGN_TYPE_TOOL_HEADER].hidden;
2388
2389 if ((tool_header_alignment != -1) &&
2390 /* If tool-header is hidden, use header alignment. */
2391 ((tool_header_hidden == false) ||
2392 /* Don't prioritize the tool-header if both are hidden (behave as if both are visible).
2393 * Without this, switching to a space with headers hidden will flip the alignment
2394 * upon switching to a space with visible headers. */
2395 (header_hidden && tool_header_hidden)))
2396 {
2397 return tool_header_alignment;
2398 }
2399 if (header_alignment != -1) {
2400 return header_alignment;
2401 }
2402 return fallback;
2403}
2404
2427static void region_align_info_to_area_for_headers(const RegionTypeAlignInfo *region_align_info_src,
2428 const RegionTypeAlignInfo *region_align_info_dst,
2429 ARegion *region_by_type[RGN_TYPE_NUM])
2430{
2431 /* Abbreviate access. */
2432 const short header_alignment_src = region_align_info_src->by_type[RGN_TYPE_HEADER].alignment;
2433 const short tool_header_alignment_src =
2434 region_align_info_src->by_type[RGN_TYPE_TOOL_HEADER].alignment;
2435
2436 const bool tool_header_hidden_src = region_align_info_src->by_type[RGN_TYPE_TOOL_HEADER].hidden;
2437
2438 const short primary_header_alignment_src = region_alignment_from_header_and_tool_header_state(
2439 region_align_info_src, -1);
2440
2441 /* Neither alignments are usable, don't sync. */
2442 if (primary_header_alignment_src == -1) {
2443 return;
2444 }
2445
2446 const short header_alignment_dst = region_align_info_dst->by_type[RGN_TYPE_HEADER].alignment;
2447 const short tool_header_alignment_dst =
2448 region_align_info_dst->by_type[RGN_TYPE_TOOL_HEADER].alignment;
2449 const short footer_alignment_dst = region_align_info_dst->by_type[RGN_TYPE_FOOTER].alignment;
2450
2451 const bool tool_header_hidden_dst = region_align_info_dst->by_type[RGN_TYPE_TOOL_HEADER].hidden;
2452
2453 /* New synchronized alignments to set (or ignore when left as -1). */
2454 short header_alignment_sync = -1;
2455 short tool_header_alignment_sync = -1;
2456 short footer_alignment_sync = -1;
2457
2458 /* Both source/destination areas have same region configurations regarding headers.
2459 * Simply copy the values. */
2460 if (((header_alignment_src != -1) == (header_alignment_dst != -1)) &&
2461 ((tool_header_alignment_src != -1) == (tool_header_alignment_dst != -1)) &&
2462 (tool_header_hidden_src == tool_header_hidden_dst))
2463 {
2464 if (header_alignment_dst != -1) {
2465 header_alignment_sync = header_alignment_src;
2466 }
2467 if (tool_header_alignment_dst != -1) {
2468 tool_header_alignment_sync = tool_header_alignment_src;
2469 }
2470 }
2471 else {
2472 /* Not an exact match, check the space selector isn't moving. */
2473 const short primary_header_alignment_dst = region_alignment_from_header_and_tool_header_state(
2474 region_align_info_dst, -1);
2475
2476 if (primary_header_alignment_src != primary_header_alignment_dst) {
2477 if ((header_alignment_dst != -1) && (tool_header_alignment_dst != -1)) {
2478 if (header_alignment_dst == tool_header_alignment_dst) {
2479 /* Apply to both. */
2480 tool_header_alignment_sync = primary_header_alignment_src;
2481 header_alignment_sync = primary_header_alignment_src;
2482 }
2483 else {
2484 /* Keep on opposite sides. */
2485 tool_header_alignment_sync = primary_header_alignment_src;
2486 header_alignment_sync = (tool_header_alignment_sync == RGN_ALIGN_BOTTOM) ?
2489 }
2490 }
2491 else {
2492 /* Apply what we can to regions that exist. */
2493 if (header_alignment_dst != -1) {
2494 header_alignment_sync = primary_header_alignment_src;
2495 }
2496 if (tool_header_alignment_dst != -1) {
2497 tool_header_alignment_sync = primary_header_alignment_src;
2498 }
2499 }
2500 }
2501 }
2502
2503 if (footer_alignment_dst != -1) {
2504 if ((header_alignment_dst != -1) && (header_alignment_dst == footer_alignment_dst)) {
2505 /* Apply to both. */
2506 footer_alignment_sync = primary_header_alignment_src;
2507 }
2508 else {
2509 /* Keep on opposite sides. */
2510 footer_alignment_sync = (primary_header_alignment_src == RGN_ALIGN_BOTTOM) ?
2513 }
2514 }
2515
2516 /* Finally apply synchronized flags. */
2517 if (header_alignment_sync != -1) {
2518 ARegion *region = region_by_type[RGN_TYPE_HEADER];
2519 if (region != nullptr) {
2520 region->alignment = RGN_ALIGN_ENUM_FROM_MASK(header_alignment_sync) |
2522 }
2523 }
2524
2525 if (tool_header_alignment_sync != -1) {
2526 ARegion *region = region_by_type[RGN_TYPE_TOOL_HEADER];
2527 if (region != nullptr) {
2528 region->alignment = RGN_ALIGN_ENUM_FROM_MASK(tool_header_alignment_sync) |
2530 }
2531 }
2532
2533 if (footer_alignment_sync != -1) {
2534 ARegion *region = region_by_type[RGN_TYPE_FOOTER];
2535 if (region != nullptr) {
2536 region->alignment = RGN_ALIGN_ENUM_FROM_MASK(footer_alignment_sync) |
2538 }
2539 }
2540}
2541
2543 ScrArea *area, const RegionTypeAlignInfo region_align_info_src[RGN_TYPE_NUM])
2544{
2545 ARegion *region_by_type[RGN_TYPE_NUM] = {nullptr};
2546 LISTBASE_FOREACH (ARegion *, region, &area->regionbase) {
2547 const int index = region->regiontype;
2548 if (uint(index) < RGN_TYPE_NUM) {
2549 region_by_type[index] = region;
2550 }
2551 }
2552
2553 RegionTypeAlignInfo region_align_info_dst;
2554 region_align_info_from_area(area, &region_align_info_dst);
2555
2556 if ((region_by_type[RGN_TYPE_HEADER] != nullptr) ||
2557 (region_by_type[RGN_TYPE_TOOL_HEADER] != nullptr))
2558 {
2560 region_align_info_src, &region_align_info_dst, region_by_type);
2561 }
2562
2563 /* Note that we could support other region types. */
2564}
2565
2567
2568/* *********** Space switching code *********** */
2569
2571{
2572 ScrArea *tmp = static_cast<ScrArea *>(MEM_callocN(sizeof(ScrArea), __func__));
2573 wmWindow *win = CTX_wm_window(C);
2574
2575 ED_area_exit(C, sa1);
2576 ED_area_exit(C, sa2);
2577
2578 ED_area_data_copy(tmp, sa1, false);
2579 ED_area_data_copy(sa1, sa2, true);
2580 ED_area_data_copy(sa2, tmp, true);
2581 ED_area_init(CTX_wm_manager(C), win, sa1);
2582 ED_area_init(CTX_wm_manager(C), win, sa2);
2583
2585 MEM_delete(tmp);
2586
2587 /* tell WM to refresh, cursor types etc */
2589
2590 ED_area_tag_redraw(sa1);
2592 ED_area_tag_redraw(sa2);
2594}
2595
2596void ED_area_newspace(bContext *C, ScrArea *area, int type, const bool skip_region_exit)
2597{
2598 wmWindow *win = CTX_wm_window(C);
2599 SpaceType *st = BKE_spacetype_from_id(type);
2600
2601 if (area->spacetype != type) {
2602 SpaceLink *slold = static_cast<SpaceLink *>(area->spacedata.first);
2603 /* store area->type->exit callback */
2604 void (*area_exit)(wmWindowManager *, ScrArea *) = area->type ? area->type->exit : nullptr;
2605 /* When the user switches between space-types from the type-selector,
2606 * changing the header-type is jarring (especially when using Ctrl-MouseWheel).
2607 *
2608 * However, add-on install for example, forces the header to the top which shouldn't
2609 * be applied back to the previous space type when closing - see: #57724
2610 *
2611 * Newly-created windows won't have any space data, use the alignment
2612 * the space type defaults to in this case instead
2613 * (needed for preferences to have space-type on bottom).
2614 */
2615
2616 bool sync_header_alignment = false;
2617 RegionTypeAlignInfo region_align_info[RGN_TYPE_NUM];
2618 if ((slold != nullptr) && (slold->link_flag & SPACE_FLAG_TYPE_TEMPORARY) == 0) {
2619 region_align_info_from_area(area, region_align_info);
2620 sync_header_alignment = true;
2621 }
2622
2623 /* in some cases (opening temp space) we don't want to
2624 * call area exit callback, so we temporarily unset it */
2625 if (skip_region_exit && area->type) {
2626 area->type->exit = nullptr;
2627 }
2628
2629 ED_area_exit(C, area);
2630
2631 /* restore old area exit callback */
2632 if (skip_region_exit && area->type) {
2633 area->type->exit = area_exit;
2634 }
2635
2636 area->spacetype = type;
2637 area->type = st;
2638
2639 /* If st->create may be called, don't use context until then. The
2640 * area->type->context() callback has changed but data may be invalid
2641 * (e.g. with properties editor) until space-data is properly created */
2642
2643 /* check previously stored space */
2644 SpaceLink *sl = nullptr;
2645 LISTBASE_FOREACH (SpaceLink *, sl_iter, &area->spacedata) {
2646 if (sl_iter->spacetype == type) {
2647 sl = sl_iter;
2648 break;
2649 }
2650 }
2651
2652 /* old spacedata... happened during work on 2.50, remove */
2653 if (sl && BLI_listbase_is_empty(&sl->regionbase)) {
2654 st->free(sl);
2655 BLI_freelinkN(&area->spacedata, sl);
2656 if (slold == sl) {
2657 slold = nullptr;
2658 }
2659 sl = nullptr;
2660 }
2661
2662 if (sl) {
2663 /* swap regions */
2664 slold->regionbase = area->regionbase;
2665 area->regionbase = sl->regionbase;
2667 /* SPACE_FLAG_TYPE_WAS_ACTIVE is only used to go back to a previously active space that is
2668 * overlapped by temporary ones. It's now properly activated, so the flag should be cleared
2669 * at this point. */
2671
2672 /* put in front of list */
2673 BLI_remlink(&area->spacedata, sl);
2674 BLI_addhead(&area->spacedata, sl);
2675 }
2676 else {
2677 /* new space */
2678 if (st) {
2679 /* Don't get scene from context here which may depend on space-data. */
2680 Scene *scene = WM_window_get_active_scene(win);
2681 sl = st->create(area, scene);
2682 BLI_addhead(&area->spacedata, sl);
2683
2684 /* swap regions */
2685 if (slold) {
2686 slold->regionbase = area->regionbase;
2687 }
2688 area->regionbase = sl->regionbase;
2690 }
2691 }
2692
2693 /* Sync header alignment. */
2694 if (sync_header_alignment) {
2695 region_align_info_to_area(area, region_align_info);
2696 }
2697
2698 ED_area_init(CTX_wm_manager(C), win, area);
2699
2700 /* tell WM to refresh, cursor types etc */
2702
2703 /* send space change notifier */
2705
2706 ED_area_tag_refresh(area);
2707 }
2708
2709 /* Set area space subtype if applicable. */
2710 if (st->space_subtype_item_extend != nullptr) {
2711 st->space_subtype_set(area, area->butspacetype_subtype);
2712 }
2713 area->butspacetype_subtype = 0;
2714
2715 if (BLI_listbase_is_single(&CTX_wm_screen(C)->areabase)) {
2716 /* If there is only one area update the window title. */
2718 }
2719
2720 /* also redraw when re-used */
2721 ED_area_tag_redraw(area);
2722}
2723
2725{
2726 SpaceLink *sl = static_cast<SpaceLink *>(area->spacedata.first);
2727
2728 /* First toggle to the next temporary space in the list. */
2729 for (SpaceLink *sl_iter = sl->next; sl_iter; sl_iter = sl_iter->next) {
2730 if (sl_iter->link_flag & SPACE_FLAG_TYPE_TEMPORARY) {
2731 return sl_iter;
2732 }
2733 }
2734
2735 /* No temporary space, find the item marked as last active. */
2736 for (SpaceLink *sl_iter = sl->next; sl_iter; sl_iter = sl_iter->next) {
2737 if (sl_iter->link_flag & SPACE_FLAG_TYPE_WAS_ACTIVE) {
2738 return sl_iter;
2739 }
2740 }
2741
2742 /* If neither is found, we can just return to the regular previous one. */
2743 return sl->next;
2744}
2745
2747{
2748 SpaceLink *sl = static_cast<SpaceLink *>(area->spacedata.first);
2749 SpaceLink *prevspace = sl ? area_get_prevspace(area) : nullptr;
2750
2751 if (prevspace) {
2752 ED_area_newspace(C, area, prevspace->spacetype, false);
2753 /* We've exited the space, so it can't be considered temporary anymore. */
2755 }
2756 else {
2757 /* no change */
2758 return;
2759 }
2760 /* If this is a stacked full-screen, changing to previous area exits it (meaning we're still in a
2761 * full-screen, but not in a stacked one). */
2763
2764 ED_area_tag_redraw(area);
2765
2766 /* send space change notifier */
2768}
2769
2770int ED_area_header_switchbutton(const bContext *C, uiBlock *block, int yco)
2771{
2772 ScrArea *area = CTX_wm_area(C);
2773 bScreen *screen = CTX_wm_screen(C);
2774 int xco = 0.4 * U.widget_unit;
2775
2776 PointerRNA areaptr = RNA_pointer_create(&(screen->id), &RNA_Area, area);
2777
2778 uiDefButR(block,
2780 0,
2781 "",
2782 xco,
2783 yco,
2784 1.6 * U.widget_unit,
2785 U.widget_unit,
2786 &areaptr,
2787 "ui_type",
2788 0,
2789 0.0f,
2790 0.0f,
2791 "");
2792
2793 return xco + 1.7 * U.widget_unit;
2794}
2795
2796/************************ standard UI regions ************************/
2797
2798static ThemeColorID region_background_color_id(const bContext * /*C*/, const ARegion *region)
2799{
2800 switch (region->regiontype) {
2801 case RGN_TYPE_HEADER:
2803 return TH_HEADER;
2804 case RGN_TYPE_PREVIEW:
2805 return TH_PREVIEW_BACK;
2806 default:
2807 return TH_BACK;
2808 }
2809}
2810
2811void ED_region_clear(const bContext *C, const ARegion *region, const int /*ThemeColorID*/ colorid)
2812{
2813 if (region->overlap) {
2814 /* view should be in pixelspace */
2816
2817 float back[4];
2818 UI_GetThemeColor4fv(colorid, back);
2819 GPU_clear_color(back[3] * back[0], back[3] * back[1], back[3] * back[2], back[3]);
2820 }
2821 else {
2822 UI_ThemeClearColor(colorid);
2823 }
2824}
2825
2827{
2828 /* view should be in pixelspace */
2830
2831 GPU_clear_color(0, 0, 0, 0);
2832}
2833
2834BLI_INLINE bool streq_array_any(const char *s, const char *arr[])
2835{
2836 for (uint i = 0; arr[i]; i++) {
2837 if (STREQ(arr[i], s)) {
2838 return true;
2839 }
2840 }
2841 return false;
2842}
2843
2853static void ed_panel_draw(const bContext *C,
2854 ARegion *region,
2855 ListBase *lb,
2856 PanelType *pt,
2857 Panel *panel,
2858 int w,
2859 int em,
2860 char *unique_panel_str,
2861 const char *search_filter,
2862 wmOperatorCallContext op_context)
2863{
2864 const uiStyle *style = UI_style_get_dpi();
2865
2866 /* Draw panel. */
2868 if (unique_panel_str) {
2869 /* Instanced panels should have already been added at this point. */
2870 BLI_string_join(block_name, sizeof(block_name), pt->idname, unique_panel_str);
2871 }
2872 else {
2873 STRNCPY(block_name, pt->idname);
2874 }
2875 uiBlock *block = UI_block_begin(C, region, block_name, UI_EMBOSS);
2876
2877 bool open;
2878 panel = UI_panel_begin(region, lb, block, pt, panel, &open);
2879 panel->runtime->layout_panels.clear();
2880
2881 const bool search_filter_active = search_filter != nullptr && search_filter[0] != '\0';
2882
2883 /* bad fixed values */
2884 int xco, yco, h = 0;
2885 int headerend = w - UI_UNIT_X;
2886
2888 if (pt->draw_header_preset && !(pt->flag & PANEL_TYPE_NO_HEADER)) {
2889 /* for preset menu */
2890 panel->layout = UI_block_layout(block,
2893 0,
2894 (UI_UNIT_Y * 1.1f) + style->panelspace,
2895 UI_UNIT_Y,
2896 1,
2897 0,
2898 style);
2899
2900 uiLayoutSetOperatorContext(panel->layout, op_context);
2901
2902 pt->draw_header_preset(C, panel);
2903
2904 UI_block_apply_search_filter(block, search_filter);
2905 UI_block_layout_resolve(block, &xco, &yco);
2906 UI_block_translate(block, headerend - xco, 0);
2907 panel->layout = nullptr;
2908 }
2909
2910 if (pt->draw_header && !(pt->flag & PANEL_TYPE_NO_HEADER)) {
2911 int labelx, labely;
2912 UI_panel_label_offset(block, &labelx, &labely);
2913
2914 /* Unusual case: Use expanding layout (buttons stretch to available width). */
2915 if (pt->flag & PANEL_TYPE_HEADER_EXPAND) {
2916 uiLayout *layout = UI_block_layout(block,
2919 labelx,
2920 labely,
2921 headerend - 2 * style->panelspace,
2922 1,
2923 0,
2924 style);
2925 panel->layout = uiLayoutRow(layout, false);
2926 }
2927 /* Regular case: Normal panel with fixed size buttons. */
2928 else {
2929 panel->layout = UI_block_layout(
2930 block, UI_LAYOUT_HORIZONTAL, UI_LAYOUT_HEADER, labelx, labely, UI_UNIT_Y, 1, 0, style);
2931 }
2932
2933 uiLayoutSetOperatorContext(panel->layout, op_context);
2934
2935 pt->draw_header(C, panel);
2936
2937 UI_block_apply_search_filter(block, search_filter);
2938 UI_block_layout_resolve(block, &xco, &yco);
2939 panel->labelofs = xco - labelx;
2940 panel->layout = nullptr;
2941 }
2942 else {
2943 panel->labelofs = 0;
2944 }
2946
2947 if (open || search_filter_active) {
2948 short panelContext;
2949
2950 /* panel context can either be toolbar region or normal panels region */
2951 if (pt->flag & PANEL_TYPE_LAYOUT_VERT_BAR) {
2952 panelContext = UI_LAYOUT_VERT_BAR;
2953 }
2954 else if (region->regiontype == RGN_TYPE_TOOLS) {
2955 panelContext = UI_LAYOUT_TOOLBAR;
2956 }
2957 else {
2958 panelContext = UI_LAYOUT_PANEL;
2959 }
2960
2961 panel->layout = UI_block_layout(
2962 block,
2964 panelContext,
2965 (pt->flag & PANEL_TYPE_LAYOUT_VERT_BAR) ? 0 : style->panelspace,
2966 0,
2967 (pt->flag & PANEL_TYPE_LAYOUT_VERT_BAR) ? 0 : w - 2 * style->panelspace,
2968 em,
2969 0,
2970 style);
2971
2972 uiLayoutSetOperatorContext(panel->layout, op_context);
2973
2974 pt->draw(C, panel);
2975
2976 const bool ends_with_layout_panel_header = uiLayoutEndsWithPanelHeader(*panel->layout);
2977
2978 UI_block_apply_search_filter(block, search_filter);
2979 UI_block_layout_resolve(block, &xco, &yco);
2980 panel->layout = nullptr;
2981
2982 if (yco != 0) {
2983 h = -yco;
2984 h += style->panelspace;
2985 if (!ends_with_layout_panel_header) {
2986 /* Last layout panel header ends together with the panel. */
2987 h += style->panelspace;
2988 }
2989 }
2990 }
2991
2992 UI_block_end(C, block);
2993
2994 /* Draw child panels. */
2995 if (open || search_filter_active) {
2996 LISTBASE_FOREACH (LinkData *, link, &pt->children) {
2997 PanelType *child_pt = static_cast<PanelType *>(link->data);
2998 Panel *child_panel = UI_panel_find_by_type(&panel->children, child_pt);
2999
3000 if (child_pt->draw && (!child_pt->poll || child_pt->poll(C, child_pt))) {
3002 region,
3003 &panel->children,
3004 child_pt,
3005 child_panel,
3006 w,
3007 em,
3008 unique_panel_str,
3009 search_filter,
3010 op_context);
3011 }
3012 }
3013 }
3014
3015 UI_panel_end(panel, w, h);
3016}
3017
3021static bool panel_add_check(const bContext *C,
3022 const WorkSpace *workspace,
3023 const char *contexts[],
3024 const char *category_override,
3025 PanelType *panel_type)
3026{
3027 /* Only add top level panels. */
3028 if (panel_type->parent) {
3029 return false;
3030 }
3031 /* Check the category override first. */
3032 if (category_override) {
3033 if (!STREQ(panel_type->category, category_override)) {
3034 return false;
3035 }
3036 }
3037
3038 /* Verify context. */
3039 if (contexts != nullptr && panel_type->context[0]) {
3040 if (!streq_array_any(panel_type->context, contexts)) {
3041 return false;
3042 }
3043 }
3044
3045 /* If we're tagged, only use compatible. */
3046 if (panel_type->owner_id[0]) {
3047 if (!BKE_workspace_owner_id_check(workspace, panel_type->owner_id)) {
3048 return false;
3049 }
3050 }
3051
3052 if (LIKELY(panel_type->draw)) {
3053 if (panel_type->poll && !panel_type->poll(C, panel_type)) {
3054 return false;
3055 }
3056 }
3057
3058 return true;
3059}
3060
3061static bool region_uses_category_tabs(const ScrArea *area, const ARegion *region)
3062{
3063 /* XXX, should use some better check? */
3064 /* For now also has hardcoded check for clip editor until it supports actual toolbar. */
3065 return ((1 << region->regiontype) & RGN_TYPE_HAS_CATEGORY_MASK) ||
3066 (region->regiontype == RGN_TYPE_TOOLS && area->spacetype == SPACE_CLIP);
3067}
3068
3070 LinkNode *panel_types_stack,
3071 bool *use_category_tabs)
3072{
3074
3075 /* gather unique categories */
3076 for (LinkNode *pt_link = panel_types_stack; pt_link; pt_link = pt_link->next) {
3077 PanelType *pt = static_cast<PanelType *>(pt_link->link);
3078 if (pt->category[0]) {
3079 if (!UI_panel_category_find(region, pt->category)) {
3080 UI_panel_category_add(region, pt->category);
3081 }
3082 }
3083 }
3084
3085 if (UI_panel_category_is_visible(region)) {
3086 return UI_panel_category_active_get(region, true);
3087 }
3088
3089 *use_category_tabs = false;
3090 return nullptr;
3091}
3092
3094 const PanelType *panel_type,
3095 const int max_width)
3096{
3097 /* With a background, we want some extra padding. */
3098 return UI_panel_should_show_background(region, panel_type) ?
3099 max_width - UI_PANEL_MARGIN_X * 2.0f :
3100 max_width;
3101}
3102
3104 ARegion *region,
3105 ListBase *paneltypes,
3106 wmOperatorCallContext op_context,
3107 const char *contexts[],
3108 const char *category_override)
3109{
3110 /* collect panels to draw */
3111 WorkSpace *workspace = CTX_wm_workspace(C);
3112 LinkNode *panel_types_stack = nullptr;
3113 LISTBASE_FOREACH_BACKWARD (PanelType *, pt, paneltypes) {
3114 if (panel_add_check(C, workspace, contexts, category_override, pt)) {
3115 BLI_linklist_prepend_alloca(&panel_types_stack, pt);
3116 }
3117 }
3118
3119 region->runtime.category = nullptr;
3120
3121 ScrArea *area = CTX_wm_area(C);
3122 View2D *v2d = &region->v2d;
3123
3124 bool use_category_tabs = (category_override == nullptr) &&
3125 region_uses_category_tabs(area, region);
3126 /* offset panels for small vertical tab area */
3127 const char *category = nullptr;
3128 const int category_tabs_width = UI_PANEL_CATEGORY_MARGIN_WIDTH;
3129 int margin_x = 0;
3130 const bool region_layout_based = region->flag & RGN_FLAG_DYNAMIC_SIZE;
3131 bool update_tot_size = true;
3132
3133 /* only allow scrolling in vertical direction */
3135 v2d->keepofs &= ~(V2D_LOCKOFS_Y | V2D_KEEPOFS_X);
3136 v2d->scroll &= ~V2D_SCROLL_BOTTOM;
3137 v2d->scroll |= V2D_SCROLL_RIGHT;
3138
3139 /* collect categories */
3140 if (use_category_tabs) {
3141 category = region_panels_collect_categories(region, panel_types_stack, &use_category_tabs);
3142 }
3143 if (use_category_tabs) {
3144 margin_x = category_tabs_width;
3145 }
3146
3147 const int max_panel_width = BLI_rctf_size_x(&v2d->cur) - margin_x;
3148 /* Works out to 10 * UI_UNIT_X or 20 * UI_UNIT_X. */
3149 const int em = (region->type->prefsizex) ? 10 : 20;
3150
3151 /* create panels */
3152 UI_panels_begin(C, region);
3153
3154 /* Get search string for property search. */
3155 const char *search_filter = ED_area_region_search_filter_get(area, region);
3156
3157 /* set view2d view matrix - UI_block_begin() stores it */
3159
3160 bool has_instanced_panel = false;
3161 for (LinkNode *pt_link = panel_types_stack; pt_link; pt_link = pt_link->next) {
3162 PanelType *pt = static_cast<PanelType *>(pt_link->link);
3163
3164 if (pt->flag & PANEL_TYPE_INSTANCED) {
3165 has_instanced_panel = true;
3166 continue;
3167 }
3168 Panel *panel = UI_panel_find_by_type(&region->panels, pt);
3169
3170 if (use_category_tabs && pt->category[0] && !STREQ(category, pt->category)) {
3171 if ((panel == nullptr) || ((panel->flag & PNL_PIN) == 0)) {
3172 continue;
3173 }
3174 }
3175 const int width = panel_draw_width_from_max_width_get(region, pt, max_panel_width);
3176
3177 if (panel && UI_panel_is_dragging(panel)) {
3178 /* Prevent View2d.tot rectangle size changes while dragging panels. */
3179 update_tot_size = false;
3180 }
3181
3183 C, region, &region->panels, pt, panel, width, em, nullptr, search_filter, op_context);
3184 }
3185
3186 /* Draw "poly-instantiated" panels that don't have a 1 to 1 correspondence with their types. */
3187 if (has_instanced_panel) {
3188 LISTBASE_FOREACH (Panel *, panel, &region->panels) {
3189 if (panel->type == nullptr) {
3190 continue; /* Some panels don't have a type. */
3191 }
3192 if (!(panel->type->flag & PANEL_TYPE_INSTANCED)) {
3193 continue;
3194 }
3195 if (use_category_tabs && panel->type->category[0] && !STREQ(category, panel->type->category))
3196 {
3197 continue;
3198 }
3199 const int width = panel_draw_width_from_max_width_get(region, panel->type, max_panel_width);
3200
3201 if (UI_panel_is_dragging(panel)) {
3202 /* Prevent View2d.tot rectangle size changes while dragging panels. */
3203 update_tot_size = false;
3204 }
3205
3206 /* Use a unique identifier for instanced panels, otherwise an old block for a different
3207 * panel of the same type might be found. */
3208 char unique_panel_str[INSTANCED_PANEL_UNIQUE_STR_SIZE];
3209 UI_list_panel_unique_str(panel, unique_panel_str);
3211 region,
3212 &region->panels,
3213 panel->type,
3214 panel,
3215 width,
3216 em,
3217 unique_panel_str,
3218 search_filter,
3219 op_context);
3220 }
3221 }
3222
3223 /* align panels and return size */
3224 int x, y;
3225 UI_panels_end(C, region, &x, &y);
3226
3227 /* before setting the view */
3228 if (region_layout_based) {
3229 /* XXX, only single panel support at the moment.
3230 * Can't use x/y values calculated above because they're not using the real height of panels,
3231 * instead they calculate offsets for the next panel to start drawing. */
3232 Panel *panel = static_cast<Panel *>(region->panels.last);
3233 if (panel != nullptr) {
3234 const int size_dyn[2] = {
3235 int(UI_UNIT_X * (UI_panel_is_closed(panel) ? 8 : 14) / UI_SCALE_FAC),
3237 };
3238 /* region size is layout based and needs to be updated */
3239 if ((region->sizex != size_dyn[0]) || (region->sizey != size_dyn[1])) {
3240 region->sizex = size_dyn[0];
3241 region->sizey = size_dyn[1];
3242 ED_area_tag_region_size_update(area, region);
3243 }
3244 y = fabsf(region->sizey * UI_SCALE_FAC - 1);
3245 }
3246 }
3247 else {
3248 /* We always keep the scroll offset -
3249 * so the total view gets increased with the scrolled away part. */
3250 if (v2d->cur.ymax < -FLT_EPSILON) {
3251 /* Clamp to lower view boundary */
3252 if (v2d->tot.ymin < -v2d->winy) {
3253 y = min_ii(y, 0);
3254 }
3255 else {
3256 y = min_ii(y, v2d->cur.ymin);
3257 }
3258 }
3259
3260 y = -y;
3261 }
3262
3264
3265 if (update_tot_size) {
3266 /* this also changes the 'cur' */
3267 UI_view2d_totRect_set(v2d, x, y);
3268 }
3269
3270 if (use_category_tabs) {
3271 region->runtime.category = category;
3272 }
3273}
3274
3276{
3278 C, region, &region->type->paneltypes, WM_OP_INVOKE_REGION_WIN, nullptr, nullptr);
3279}
3280
3282{
3283 View2D *v2d = &region->v2d;
3284
3285 if (region->alignment != RGN_ALIGN_FLOAT) {
3287 C, region, (region->type->regionid == RGN_TYPE_PREVIEW) ? TH_PREVIEW_BACK : TH_BACK);
3288 }
3289
3290 /* reset line width for drawing tabs */
3291 GPU_line_width(1.0f);
3292
3293 /* set the view */
3295
3296 /* View2D matrix might have changed due to dynamic sized regions. */
3298
3299 /* draw panels */
3300 UI_panels_draw(C, region);
3301
3302 /* restore view matrix */
3304
3305 /* Set in layout. */
3306 if (region->runtime.category) {
3308 }
3309
3310 /* scrollers */
3311 bool use_mask = false;
3312 rcti mask;
3313 if (region->runtime.category &&
3316 {
3317 use_mask = true;
3319 mask.xmax -= round_fl_to_int(UI_view2d_scale_get_x(&region->v2d) *
3321 }
3322 bool use_full_hide = false;
3323 if (region->overlap) {
3324 /* Don't always show scrollbars for transparent regions as it's distracting. */
3325 use_full_hide = true;
3326 }
3327 UI_view2d_scrollers_draw_ex(v2d, use_mask ? &mask : nullptr, use_full_hide);
3328}
3329
3331 ARegion *region,
3332 wmOperatorCallContext op_context,
3333 const char *contexts[])
3334{
3335 /* TODO: remove? */
3336 ED_region_panels_layout_ex(C, region, &region->type->paneltypes, op_context, contexts, nullptr);
3337 ED_region_panels_draw(C, region);
3338}
3339
3340void ED_region_panels(const bContext *C, ARegion *region)
3341{
3342 /* TODO: remove? */
3343 ED_region_panels_layout(C, region);
3344 ED_region_panels_draw(C, region);
3345}
3346
3348{
3349 UI_view2d_region_reinit(&region->v2d, V2D_COMMONVIEW_PANELS_UI, region->winx, region->winy);
3350
3351 wmKeyMap *keymap = WM_keymap_ensure(
3352 wm->defaultconf, "View2D Buttons List", SPACE_EMPTY, RGN_TYPE_WINDOW);
3353 WM_event_add_keymap_handler(&region->handlers, keymap);
3354}
3355
3363 ARegion *region,
3364 const uiStyle *style,
3365 Panel *panel,
3366 PanelType *panel_type,
3367 const char *search_filter)
3368{
3369 uiBlock *block = UI_block_begin(C, region, panel_type->idname, UI_EMBOSS);
3370 UI_block_set_search_only(block, true);
3371
3372 /* Skip panels that give meaningless search results. */
3373 if (panel_type->flag & PANEL_TYPE_NO_SEARCH) {
3374 return false;
3375 }
3376
3377 if (panel == nullptr) {
3378 bool open; /* Dummy variable. */
3379 panel = UI_panel_begin(region, &region->panels, block, panel_type, panel, &open);
3380 }
3381
3382 /* Build the layouts. Because they are only used for search,
3383 * they don't need any of the proper style or layout information. */
3384 if (panel->type->draw_header_preset != nullptr) {
3385 panel->layout = UI_block_layout(
3386 block, UI_LAYOUT_HORIZONTAL, UI_LAYOUT_HEADER, 0, 0, 0, 0, 0, style);
3387 panel_type->draw_header_preset(C, panel);
3388 }
3389 if (panel->type->draw_header != nullptr) {
3390 panel->layout = UI_block_layout(
3391 block, UI_LAYOUT_HORIZONTAL, UI_LAYOUT_HEADER, 0, 0, 0, 0, 0, style);
3392 panel_type->draw_header(C, panel);
3393 }
3394 if (LIKELY(panel->type->draw != nullptr)) {
3395 panel->layout = UI_block_layout(
3396 block, UI_LAYOUT_VERTICAL, UI_LAYOUT_PANEL, 0, 0, 0, 0, 0, style);
3397 panel_type->draw(C, panel);
3398 }
3399
3400 UI_block_layout_free(block);
3401
3402 /* We could check after each layout to increase the likelihood of returning early,
3403 * but that probably wouldn't make much of a difference anyway. */
3404 if (UI_block_apply_search_filter(block, search_filter)) {
3405 return true;
3406 }
3407
3408 LISTBASE_FOREACH (LinkData *, link, &panel_type->children) {
3409 PanelType *panel_type_child = static_cast<PanelType *>(link->data);
3410 if (!panel_type_child->poll || panel_type_child->poll(C, panel_type_child)) {
3411 /* Search for the existing child panel here because it might be an instanced
3412 * child panel with a custom data field that will be needed to build the layout. */
3413 Panel *child_panel = UI_panel_find_by_type(&panel->children, panel_type_child);
3414 if (panel_property_search(C, region, style, child_panel, panel_type_child, search_filter)) {
3415 return true;
3416 }
3417 }
3418 }
3419
3420 return false;
3421}
3422
3424 ARegion *region,
3425 ListBase *paneltypes,
3426 const char *contexts[],
3427 const char *category_override)
3428{
3429 ScrArea *area = CTX_wm_area(C);
3430 WorkSpace *workspace = CTX_wm_workspace(C);
3431 const uiStyle *style = UI_style_get_dpi();
3432 const char *search_filter = ED_area_region_search_filter_get(area, region);
3433
3434 LinkNode *panel_types_stack = nullptr;
3435 LISTBASE_FOREACH_BACKWARD (PanelType *, pt, paneltypes) {
3436 if (panel_add_check(C, workspace, contexts, category_override, pt)) {
3437 BLI_linklist_prepend_alloca(&panel_types_stack, pt);
3438 }
3439 }
3440
3441 const char *category = nullptr;
3442 bool use_category_tabs = (category_override == nullptr) &&
3443 region_uses_category_tabs(area, region);
3444 if (use_category_tabs) {
3445 category = region_panels_collect_categories(region, panel_types_stack, &use_category_tabs);
3446 }
3447
3448 /* Run property search for each panel, stopping if a result is found. */
3449 bool has_result = true;
3450 bool has_instanced_panel = false;
3451 for (LinkNode *pt_link = panel_types_stack; pt_link; pt_link = pt_link->next) {
3452 PanelType *panel_type = static_cast<PanelType *>(pt_link->link);
3453 /* Note that these checks are duplicated from #ED_region_panels_layout_ex. */
3454 if (panel_type->flag & PANEL_TYPE_INSTANCED) {
3455 has_instanced_panel = true;
3456 continue;
3457 }
3458
3459 if (use_category_tabs) {
3460 if (panel_type->category[0] && !STREQ(category, panel_type->category)) {
3461 continue;
3462 }
3463 }
3464
3465 /* We start property search with an empty panel list, so there's
3466 * no point in trying to find an existing panel with this type. */
3467 has_result = panel_property_search(C, region, style, nullptr, panel_type, search_filter);
3468 if (has_result) {
3469 break;
3470 }
3471 }
3472
3473 /* Run property search for instanced panels (created in the layout calls of previous panels). */
3474 if (!has_result && has_instanced_panel) {
3475 LISTBASE_FOREACH (Panel *, panel, &region->panels) {
3476 /* Note that these checks are duplicated from #ED_region_panels_layout_ex. */
3477 if (panel->type == nullptr || !(panel->type->flag & PANEL_TYPE_INSTANCED)) {
3478 continue;
3479 }
3480 if (use_category_tabs) {
3481 if (panel->type->category[0] && !STREQ(category, panel->type->category)) {
3482 continue;
3483 }
3484 }
3485
3486 has_result = panel_property_search(C, region, style, panel, panel->type, search_filter);
3487 if (has_result) {
3488 break;
3489 }
3490 }
3491 }
3492
3493 /* Free the panels and blocks, as they are only used for search. */
3494 UI_blocklist_free(C, region);
3495 UI_panels_free_instanced(C, region);
3497
3498 return has_result;
3499}
3500
3507 const wmWindow *win, const ScrArea *area, const ARegion *region, int * /*r_xco*/, int *r_yco)
3508{
3509 /* Don't do corrections at the window borders where the region rectangles are clipped already. */
3510 {
3511 rcti win_rect;
3512 WM_window_rect_calc(win, &win_rect);
3513 if (region->winrct.ymin == win_rect.ymin) {
3514 return;
3515 }
3516 if (region->winrct.ymax == (win_rect.ymax - 1)) {
3517 return;
3518 }
3519 }
3520
3521 if (region->winrct.ymax == area->totrct.ymax) {
3522 *r_yco -= 1;
3523 }
3524}
3525
3527{
3528 const uiStyle *style = UI_style_get_dpi();
3529 bool region_layout_based = region->flag & RGN_FLAG_DYNAMIC_SIZE;
3530
3531 /* Height of buttons and scaling needed to achieve it. */
3532 const int buttony = min_ii(UI_UNIT_Y, region->winy - 2 * UI_SCALE_FAC);
3533 const float buttony_scale = buttony / float(UI_UNIT_Y);
3534
3535 /* Vertically center buttons. */
3536 int xco = UI_HEADER_OFFSET;
3537 int yco = buttony + (region->winy - buttony) / 2;
3538 int maxco = xco;
3539
3541 CTX_wm_window(C), CTX_wm_area(C), region, &xco, &yco);
3542
3543 /* set view2d view matrix for scrolling (without scrollers) */
3544 UI_view2d_view_ortho(&region->v2d);
3545
3546 /* draw all headers types */
3547 LISTBASE_FOREACH (HeaderType *, ht, &region->type->headertypes) {
3548 if (ht->poll && !ht->poll(C, ht)) {
3549 continue;
3550 }
3551
3552 uiBlock *block = UI_block_begin(C, region, ht->idname, UI_EMBOSS);
3553 uiLayout *layout = UI_block_layout(
3554 block, UI_LAYOUT_HORIZONTAL, UI_LAYOUT_HEADER, xco, yco, buttony, 1, 0, style);
3555
3556 if (buttony_scale != 1.0f) {
3557 uiLayoutSetScaleY(layout, buttony_scale);
3558 }
3559
3560 Header header = {nullptr};
3561 if (ht->draw) {
3562 header.type = ht;
3563 header.layout = layout;
3564 ht->draw(C, &header);
3565 if (ht->next) {
3566 uiItemS(layout);
3567 }
3568
3569 /* for view2d */
3570 xco = uiLayoutGetWidth(layout);
3571 if (xco > maxco) {
3572 maxco = xco;
3573 }
3574 }
3575
3576 UI_block_layout_resolve(block, &xco, &yco);
3577
3578 /* for view2d */
3579 if (xco > maxco) {
3580 maxco = xco;
3581 }
3582
3583 int new_sizex = (maxco + UI_HEADER_OFFSET) / UI_SCALE_FAC;
3584
3585 if (region_layout_based && (region->sizex != new_sizex)) {
3586 /* region size is layout based and needs to be updated */
3587 ScrArea *area = CTX_wm_area(C);
3588
3589 region->sizex = new_sizex;
3590 ED_area_tag_region_size_update(area, region);
3591 }
3592
3593 UI_block_end(C, block);
3594
3595 /* In most cases there is only ever one header, it never makes sense to draw more than one
3596 * header in the same region, this results in overlapping buttons, see: #60195. */
3597 break;
3598 }
3599
3600 if (!region_layout_based) {
3601 maxco += UI_HEADER_OFFSET;
3602 }
3603
3604 /* Always as last. */
3605 UI_view2d_totRect_set(&region->v2d, maxco, region->winy);
3606
3607 /* Restore view matrix. */
3609}
3610
3611static void region_draw_blocks_in_view2d(const bContext *C, const ARegion *region)
3612{
3613 UI_view2d_view_ortho(&region->v2d);
3614
3615 /* View2D matrix might have changed due to dynamic sized regions. */
3617
3618 /* draw blocks */
3619 UI_blocklist_draw(C, &region->uiblocks);
3620
3621 /* restore view matrix */
3623}
3624
3626{
3627 /* clear */
3628 ED_region_clear(C, region, region_background_color_id(C, region));
3630}
3631
3633 const ARegion *region,
3634 const uiButtonSectionsAlign align)
3635{
3636 const ThemeColorID bgcolorid = region_background_color_id(C, region);
3637
3638 /* Clear and draw button sections background when using region overlap. Otherwise clear using the
3639 * background color like normal. */
3640 if (region->overlap) {
3642 UI_region_button_sections_draw(region, bgcolorid, align);
3643 }
3644 else {
3645 ED_region_clear(C, region, bgcolorid);
3646 }
3648}
3649
3650void ED_region_header(const bContext *C, ARegion *region)
3651{
3652 /* TODO: remove? */
3653 ED_region_header_layout(C, region);
3654 ED_region_header_draw(C, region);
3655}
3656
3658 ARegion *region,
3659 const uiButtonSectionsAlign align)
3660{
3661 ED_region_header_layout(C, region);
3663}
3664
3666{
3667 UI_view2d_region_reinit(&region->v2d, V2D_COMMONVIEW_HEADER, region->winx, region->winy);
3668}
3669
3671{
3672 /* Accommodate widget and padding. */
3673 return U.widget_unit + int(UI_SCALE_FAC * HEADER_PADDING_Y);
3674}
3675
3677{
3678 return ED_area_headersize();
3679}
3680
3682{
3685}
3687{
3690}
3692{
3695}
3696
3698{
3699 return area->global != nullptr;
3700}
3701
3702ScrArea *ED_area_find_under_cursor(const bContext *C, int spacetype, const int event_xy[2])
3703{
3704 bScreen *screen = CTX_wm_screen(C);
3705 wmWindow *win = CTX_wm_window(C);
3706
3707 ScrArea *area = nullptr;
3708
3709 if (win->parent) {
3710 /* If active window is a child, check itself first. */
3711 area = BKE_screen_find_area_xy(screen, spacetype, event_xy);
3712 }
3713
3714 if (!area) {
3715 /* Check all windows except the active one. */
3716 int event_xy_other[2];
3717 wmWindow *win_other = WM_window_find_under_cursor(win, event_xy, event_xy_other);
3718 if (win_other && win_other != win) {
3719 win = win_other;
3720 screen = WM_window_get_active_screen(win);
3721 area = BKE_screen_find_area_xy(screen, spacetype, event_xy_other);
3722 }
3723 }
3724
3725 if (!area && !win->parent) {
3726 /* If active window is a parent window, check itself last. */
3727 area = BKE_screen_find_area_xy(screen, spacetype, event_xy);
3728 }
3729
3730 return area;
3731}
3732
3734{
3735 ScrArea *global_area = static_cast<ScrArea *>(win->global_areas.areabase.first);
3736
3737 if (!global_area) {
3738 return static_cast<ScrArea *>(screen->areabase.first);
3739 }
3740 if ((global_area->global->flag & GLOBAL_AREA_IS_HIDDEN) == 0) {
3741 return global_area;
3742 }
3743 /* Find next visible area. */
3744 return ED_screen_areas_iter_next(screen, global_area);
3745}
3747{
3748 if (area->global == nullptr) {
3749 return area->next;
3750 }
3751
3752 for (ScrArea *area_iter = area->next; area_iter; area_iter = area_iter->next) {
3753 if ((area_iter->global->flag & GLOBAL_AREA_IS_HIDDEN) == 0) {
3754 return area_iter;
3755 }
3756 }
3757 /* No visible next global area found, start iterating over layout areas. */
3758 return static_cast<ScrArea *>(screen->areabase.first);
3759}
3760
3762{
3763 return ED_area_headersize(); /* same size as header */
3764}
3765
3767 const char *text_array[],
3768 const float fill_color[4],
3769 const bool full_redraw)
3770{
3771 const int header_height = UI_UNIT_Y;
3772 const uiStyle *style = UI_style_get_dpi();
3773 int fontid = style->widget.uifont_id;
3774 int scissor[4];
3775 int num_lines = 0;
3776
3777 /* background box */
3778 rcti rect = *ED_region_visible_rect(region);
3779
3780 /* Needed in case scripts leave the font size at an unexpected value, see: #102213. */
3781 BLF_size(fontid, style->widget.points * UI_SCALE_FAC);
3782
3783 /* Box fill entire width or just around text. */
3784 if (!full_redraw) {
3785 const char **text = &text_array[0];
3786 while (*text) {
3787 rect.xmax = min_ii(rect.xmax,
3788 rect.xmin + BLF_width(fontid, *text, BLF_DRAW_STR_DUMMY_MAX) +
3789 1.2f * U.widget_unit);
3790 text++;
3791 num_lines++;
3792 }
3793 }
3794 /* Just count the line number. */
3795 else {
3796 const char **text = &text_array[0];
3797 while (*text) {
3798 text++;
3799 num_lines++;
3800 }
3801 }
3802
3803 rect.ymin = rect.ymax - header_height * num_lines;
3804
3805 /* setup scissor */
3806 GPU_scissor_get(scissor);
3807 GPU_scissor(rect.xmin, rect.ymin, BLI_rcti_size_x(&rect) + 1, BLI_rcti_size_y(&rect) + 1);
3808
3813 immUniformColor4fv(fill_color);
3814 immRecti(pos, rect.xmin, rect.ymin, rect.xmax + 1, rect.ymax + 1);
3817
3818 /* text */
3820 BLF_clipping(fontid, rect.xmin, rect.ymin, rect.xmax, rect.ymax);
3821 BLF_enable(fontid, BLF_CLIPPING);
3822 int offset = num_lines - 1;
3823 {
3824 const char **text = &text_array[0];
3825 while (*text) {
3826 BLF_position(fontid,
3827 rect.xmin + 0.6f * U.widget_unit,
3828 rect.ymin + 0.3f * U.widget_unit + offset * header_height,
3829 0.0f);
3831 text++;
3832 offset--;
3833 }
3834 }
3835
3836 BLF_disable(fontid, BLF_CLIPPING);
3837
3838 /* restore scissor as it was before */
3839 GPU_scissor(scissor[0], scissor[1], scissor[2], scissor[3]);
3840}
3841
3843 const char *text,
3844 const float fill_color[4],
3845 const bool full_redraw)
3846{
3847 const char *text_array[2] = {text, nullptr};
3848 ED_region_info_draw_multiline(region, text_array, fill_color, full_redraw);
3849}
3850
3854
3855static void metadata_panel_draw_field(const char *field, const char *value, void *ctx_v)
3856{
3858 uiLayout *row = uiLayoutRow(ctx->layout, false);
3859 uiItemL(row, field, ICON_NONE);
3860 uiItemL(row, value, ICON_NONE);
3861}
3862
3864{
3866 ctx.layout = layout;
3868}
3869
3870void ED_region_grid_draw(ARegion *region, float zoomx, float zoomy, float x0, float y0)
3871{
3872 /* the image is located inside (x0, y0), (x0+1, y0+1) as set by view2d */
3873 int x1, y1, x2, y2;
3874 UI_view2d_view_to_region(&region->v2d, x0, y0, &x1, &y1);
3875 UI_view2d_view_to_region(&region->v2d, x0 + 1.0f, y0 + 1.0f, &x2, &y2);
3876
3879
3880 float gridcolor[4];
3881 UI_GetThemeColor4fv(TH_GRID, gridcolor);
3882
3884 /* To fake alpha-blending, color shading is reduced when alpha is nearing 0. */
3885 immUniformThemeColorBlendShade(TH_BACK, TH_GRID, gridcolor[3], 20 * gridcolor[3]);
3886 immRectf(pos, x1, y1, x2, y2);
3888
3889 /* gridsize adapted to zoom level */
3890 float gridsize = 0.5f * (zoomx + zoomy);
3891 float gridstep = 1.0f / 32.0f;
3892 if (gridsize <= 0.0f) {
3893 return;
3894 }
3895
3896 if (gridsize < 1.0f) {
3897 while (gridsize < 1.0f) {
3898 gridsize *= 4.0f;
3899 gridstep *= 4.0f;
3900 }
3901 }
3902 else {
3903 while (gridsize >= 4.0f) {
3904 gridsize /= 4.0f;
3905 gridstep /= 4.0f;
3906 }
3907 }
3908
3909 float blendfac = 0.25f * gridsize - floorf(0.25f * gridsize);
3910 CLAMP(blendfac, 0.0f, 1.0f);
3911
3912 int count_fine = 1.0f / gridstep;
3913 int count_large = 1.0f / (4.0f * gridstep);
3914
3915 if (count_fine > 0) {
3919
3921 immBegin(GPU_PRIM_LINES, 4 * count_fine + 4 * count_large);
3922
3923 float theme_color[3];
3924 UI_GetThemeColorShade3fv(TH_GRID, int(20.0f * (1.0f - blendfac)), theme_color);
3925 float fac = 0.0f;
3926
3927 /* the fine resolution level */
3928 for (int i = 0; i < count_fine; i++) {
3929 immAttr3fv(color, theme_color);
3930 immVertex2f(pos, x1, y1 * (1.0f - fac) + y2 * fac);
3931 immAttr3fv(color, theme_color);
3932 immVertex2f(pos, x2, y1 * (1.0f - fac) + y2 * fac);
3933 immAttr3fv(color, theme_color);
3934 immVertex2f(pos, x1 * (1.0f - fac) + x2 * fac, y1);
3935 immAttr3fv(color, theme_color);
3936 immVertex2f(pos, x1 * (1.0f - fac) + x2 * fac, y2);
3937 fac += gridstep;
3938 }
3939
3940 if (count_large > 0) {
3941 UI_GetThemeColor3fv(TH_GRID, theme_color);
3942 fac = 0.0f;
3943
3944 /* the large resolution level */
3945 for (int i = 0; i < count_large; i++) {
3946 immAttr3fv(color, theme_color);
3947 immVertex2f(pos, x1, y1 * (1.0f - fac) + y2 * fac);
3948 immAttr3fv(color, theme_color);
3949 immVertex2f(pos, x2, y1 * (1.0f - fac) + y2 * fac);
3950 immAttr3fv(color, theme_color);
3951 immVertex2f(pos, x1 * (1.0f - fac) + x2 * fac, y1);
3952 immAttr3fv(color, theme_color);
3953 immVertex2f(pos, x1 * (1.0f - fac) + x2 * fac, y2);
3954 fac += 4.0f * gridstep;
3955 }
3956 }
3957
3958 immEnd();
3960 }
3961}
3962
3963/* If the area has overlapping regions, it returns visible rect for Region *region */
3964/* rect gets returned in local region coordinates */
3965static void region_visible_rect_calc(ARegion *region, rcti *rect)
3966{
3967 ARegion *region_iter = region;
3968
3969 /* allow function to be called without area */
3970 while (region_iter->prev) {
3971 region_iter = region_iter->prev;
3972 }
3973
3974 *rect = region->winrct;
3975
3976 /* check if a region overlaps with the current one */
3977 for (; region_iter; region_iter = region_iter->next) {
3978 if (region != region_iter && region_iter->overlap) {
3979 if (BLI_rcti_isect(rect, &region_iter->winrct, nullptr)) {
3980 int alignment = RGN_ALIGN_ENUM_FROM_MASK(region_iter->alignment);
3981
3982 if (ELEM(alignment, RGN_ALIGN_LEFT, RGN_ALIGN_RIGHT)) {
3983 /* Overlap left, also check 1 pixel offset (2 regions on one side). */
3984 if (abs(rect->xmin - region_iter->winrct.xmin) < 2) {
3985 rect->xmin = region_iter->winrct.xmax;
3986 }
3987
3988 /* Overlap right. */
3989 if (abs(rect->xmax - region_iter->winrct.xmax) < 2) {
3990 rect->xmax = region_iter->winrct.xmin;
3991 }
3992 }
3993 else if (ELEM(alignment, RGN_ALIGN_TOP, RGN_ALIGN_BOTTOM)) {
3994 /* Same logic as above for vertical regions. */
3995 if (abs(rect->ymin - region_iter->winrct.ymin) < 2) {
3996 rect->ymin = region_iter->winrct.ymax;
3997 }
3998 if (abs(rect->ymax - region_iter->winrct.ymax) < 2) {
3999 rect->ymax = region_iter->winrct.ymin;
4000 }
4001 }
4002 else if (alignment == RGN_ALIGN_FLOAT) {
4003 /* Skip floating. */
4004 }
4005 else {
4006 BLI_assert_msg(0, "Region overlap with unknown alignment");
4007 }
4008 }
4009 }
4010 }
4011 BLI_rcti_translate(rect, -region->winrct.xmin, -region->winrct.ymin);
4012}
4013
4015{
4016 rcti *rect = &region->runtime.visible_rect;
4017 if (rect->xmin == 0 && rect->ymin == 0 && rect->xmax == 0 && rect->ymax == 0) {
4018 region_visible_rect_calc(region, rect);
4019 }
4020 return rect;
4021}
4022
4023/* Cache display helpers */
4024
4026{
4027 /* Local coordinate visible rect inside region, to accommodate overlapping ui. */
4028 const rcti *rect_visible = ED_region_visible_rect(region);
4029 const int region_bottom = rect_visible->ymin;
4030
4034 immUniformColor4ub(128, 128, 255, 64);
4035 immRecti(pos, 0, region_bottom, region->winx, region_bottom + 8 * UI_SCALE_FAC);
4037}
4038
4039void ED_region_cache_draw_curfra_label(const int framenr, const float x, const float y)
4040{
4041 const uiStyle *style = UI_style_get();
4042 int fontid = style->widget.uifont_id;
4043 char numstr[32];
4044 float font_dims[2] = {0.0f, 0.0f};
4045
4046 /* frame number */
4047 BLF_size(fontid, 11.0f * UI_SCALE_FAC);
4048 SNPRINTF(numstr, "%d", framenr);
4049
4050 BLF_width_and_height(fontid, numstr, sizeof(numstr), &font_dims[0], &font_dims[1]);
4051
4056 immRecti(pos, x, y, x + font_dims[0] + 6.0f, y + font_dims[1] + 4.0f);
4058
4059 UI_FontThemeColor(fontid, TH_TEXT);
4060 BLF_position(fontid, x + 2.0f, y + 2.0f, 0.0f);
4061 BLF_draw(fontid, numstr, sizeof(numstr));
4062}
4063
4065 ARegion *region, const int num_segments, const int *points, const int sfra, const int efra)
4066{
4067 if (num_segments) {
4068 /* Local coordinate visible rect inside region, to accommodate overlapping ui. */
4069 const rcti *rect_visible = ED_region_visible_rect(region);
4070 const int region_bottom = rect_visible->ymin;
4071
4075 immUniformColor4ub(128, 128, 255, 128);
4076
4077 for (int a = 0; a < num_segments; a++) {
4078 float x1 = float(points[a * 2] - sfra) / (efra - sfra + 1) * region->winx;
4079 float x2 = float(points[a * 2 + 1] - sfra + 1) / (efra - sfra + 1) * region->winx;
4080
4081 immRecti(pos, x1, region_bottom, x2, region_bottom + 8 * UI_SCALE_FAC);
4082 /* TODO(merwin): use primitive restart to draw multiple rects more efficiently */
4083 }
4084
4086 }
4087}
4088
4090{
4091 ARegion *region = params->region;
4092 const bContext *C = params->context;
4093 wmMsgBus *mbus = params->message_bus;
4094
4095 if (region->gizmo_map != nullptr) {
4096 WM_gizmomap_message_subscribe(C, region->gizmo_map, region, mbus);
4097 }
4098
4099 if (!BLI_listbase_is_empty(&region->uiblocks)) {
4100 UI_region_message_subscribe(region, mbus);
4101 }
4102
4103 if (region->type->message_subscribe != nullptr) {
4104 region->type->message_subscribe(params);
4105 }
4106}
4107
4109{
4110 /* Use a larger value because toggling scrollbars can jump in size. */
4111 const int snap_match_threshold = 16;
4112 if (region->type->snap_size != nullptr) {
4113 const int snap_size_x = region->type->snap_size(region, region->sizex, 0);
4114 const int snap_size_y = region->type->snap_size(region, region->sizey, 1);
4115 return (((abs(region->sizex - snap_size_x) <= snap_match_threshold) << 0) |
4116 ((abs(region->sizey - snap_size_y) <= snap_match_threshold) << 1));
4117 }
4118 return 0;
4119}
4120
4121bool ED_region_snap_size_apply(ARegion *region, int snap_flag)
4122{
4123 bool changed = false;
4124 if (region->type->snap_size != nullptr) {
4125 if (snap_flag & (1 << 0)) {
4126 short snap_size = region->type->snap_size(region, region->sizex, 0);
4127 if (snap_size != region->sizex) {
4128 region->sizex = snap_size;
4129 changed = true;
4130 }
4131 }
4132 if (snap_flag & (1 << 1)) {
4133 short snap_size = region->type->snap_size(region, region->sizey, 1);
4134 if (snap_size != region->sizey) {
4135 region->sizey = snap_size;
4136 changed = true;
4137 }
4138 }
4139 }
4140 return changed;
4141}
WorkSpace * CTX_wm_workspace(const bContext *C)
bScreen * CTX_wm_screen(const bContext *C)
ScrArea * CTX_wm_area(const bContext *C)
wmWindow * CTX_wm_window(const bContext *C)
Scene * CTX_data_scene(const bContext *C)
wmWindowManager * CTX_wm_manager(const bContext *C)
@ G_DEBUG
@ G_TRANSFORM_WM
@ PANEL_TYPE_NO_HEADER
@ PANEL_TYPE_INSTANCED
@ PANEL_TYPE_LAYOUT_VERT_BAR
@ PANEL_TYPE_NO_SEARCH
@ PANEL_TYPE_HEADER_EXPAND
void BKE_spacedata_copylist(ListBase *lb_dst, ListBase *lb_src)
Definition screen.cc:388
#define BKE_ST_MAXNAME
Definition BKE_screen.hh:66
void BKE_spacedata_freelist(ListBase *lb)
Definition screen.cc:291
ScrArea ScrArea * BKE_screen_find_area_xy(const bScreen *screen, int spacetype, const int xy[2]) ATTR_NONNULL(1
void BKE_screen_area_free(ScrArea *area)
Definition screen.cc:607
SpaceType * BKE_spacetype_from_id(int spaceid)
Definition screen.cc:243
ARegionType * BKE_regiontype_from_id(const SpaceType *st, int regionid)
Definition screen.cc:253
void BKE_area_region_free(SpaceType *st, ARegion *region)
Definition screen.cc:563
ARegion * BKE_area_region_copy(const SpaceType *st, const ARegion *region)
Definition screen.cc:335
void BKE_area_region_panels_free(ListBase *panels)
Definition screen.cc:551
void BKE_workspace_status_clear(WorkSpace *workspace)
Definition workspace.cc:649
bool BKE_workspace_owner_id_check(const WorkSpace *workspace, const char *owner_id) ATTR_NONNULL()
Definition workspace.cc:536
bScreen * BKE_workspace_active_screen_get(const WorkSpaceInstanceHook *hook) GETTER_ATTRS
Definition workspace.cc:613
@ BLF_CLIPPING
Definition BLF_api.hh:362
int BLF_set_default()
void BLF_size(int fontid, float size)
Definition blf.cc:426
void BLF_clipping(int fontid, int xmin, int ymin, int xmax, int ymax)
Definition blf.cc:881
void BLF_width_and_height(int fontid, const char *str, size_t str_len, float *r_width, float *r_height) ATTR_NONNULL()
Definition blf.cc:778
#define BLF_DRAW_STR_DUMMY_MAX
Definition BLF_api.hh:393
void BLF_disable(int fontid, int option)
Definition blf.cc:321
void BLF_draw(int fontid, const char *str, size_t str_len, ResultBLF *r_info=nullptr) ATTR_NONNULL(2)
Definition blf.cc:568
void BLF_enable(int fontid, int option)
Definition blf.cc:312
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:791
void BLF_position(int fontid, float x, float y, float z)
Definition blf.cc:371
#define BLI_assert(a)
Definition BLI_assert.h:50
#define BLI_assert_msg(a, msg)
Definition BLI_assert.h:57
#define BLI_INLINE
BLI_INLINE bool BLI_listbase_is_empty(const struct ListBase *lb)
void BLI_addhead(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:90
#define LISTBASE_FOREACH(type, var, list)
void BLI_freelinkN(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:269
#define LISTBASE_FOREACH_BACKWARD(type, var, list)
BLI_INLINE void BLI_listbase_clear(struct ListBase *lb)
void void BLI_freelistN(struct ListBase *listbase) ATTR_NONNULL(1)
Definition listbase.cc:496
void void BLI_INLINE bool BLI_listbase_is_single(const struct ListBase *lb)
void BLI_addtail(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:110
void BLI_remlink(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:130
MINLINE int round_fl_to_int(float a)
MINLINE int min_ii(int a, int b)
MINLINE float min_ff(float a, float b)
MINLINE int max_ii(int a, int b)
Random number functions.
float BLI_thread_frand(int thread) ATTR_WARN_UNUSED_RESULT
Definition rand.cc:226
void BLI_rcti_union(struct rcti *rct_a, const struct rcti *rct_b)
bool BLI_rcti_isect_pt_v(const struct rcti *rect, const int xy[2])
BLI_INLINE int BLI_rcti_size_y(const struct rcti *rct)
Definition BLI_rect.h:193
bool BLI_rcti_is_valid(const struct rcti *rect)
void BLI_rcti_translate(struct rcti *rect, int x, int y)
Definition rct.c:560
void BLI_rcti_init(struct rcti *rect, int xmin, int xmax, int ymin, int ymax)
Definition rct.c:418
void BLI_rcti_resize(struct rcti *rect, int x, int y)
Definition rct.c:615
void BLI_rcti_sanitize(struct rcti *rect)
Definition rct.c:450
bool BLI_rcti_isect(const struct rcti *src1, const struct rcti *src2, struct rcti *dest)
BLI_INLINE int BLI_rcti_size_x(const struct rcti *rct)
Definition BLI_rect.h:189
BLI_INLINE int BLI_rcti_cent_y(const struct rcti *rct)
Definition BLI_rect.h:176
BLI_INLINE float BLI_rctf_size_x(const struct rctf *rct)
Definition BLI_rect.h:197
BLI_INLINE int BLI_rcti_cent_x(const struct rcti *rct)
Definition BLI_rect.h:172
void BLI_str_rstrip(char *str) ATTR_NONNULL(1)
Definition string.c:976
#define STRNCPY(dst, src)
Definition BLI_string.h:593
#define SNPRINTF(dst, format,...)
Definition BLI_string.h:597
char * BLI_strncpy(char *__restrict dst, const char *__restrict src, size_t dst_maxncpy) ATTR_NONNULL(1
#define BLI_string_join(...)
unsigned char uchar
unsigned int uint
#define CLAMP(a, b, c)
#define SET_FLAG_FROM_TEST(value, test, flag)
#define ELEM(...)
#define IS_EQF(a, b)
#define STREQ(a, b)
#define LIKELY(x)
#define HEADERY
#define RGN_ALIGN_ENUM_FROM_MASK(align)
@ RGN_ALIGN_HIDE_WITH_PREV
@ RGN_ALIGN_BOTTOM
@ RGN_ALIGN_LEFT
@ RGN_ALIGN_TOP
@ RGN_ALIGN_RIGHT
@ RGN_SPLIT_PREV
@ RGN_ALIGN_HSPLIT
@ RGN_ALIGN_VSPLIT
@ RGN_ALIGN_NONE
@ RGN_ALIGN_FLOAT
@ RGN_ALIGN_QSPLIT
@ RGN_DRAW_NO_REBUILD
@ RGN_DRAW_PARTIAL
@ RGN_DRAWING
@ RGN_DRAW
@ RGN_REFRESH_UI
@ RGN_DRAW_EDITOR_OVERLAYS
@ AREA_FLAG_ACTIVE_TOOL_UPDATE
@ AREA_FLAG_OFFSCREEN
@ AREA_FLAG_REGION_SIZE_UPDATE
@ AREA_FLAG_STACKED_FULLSCREEN
@ AREA_FLAG_ACTIONZONES_UPDATE
@ HEADER_NO_PULLDOWN
#define AREAMINX
@ PNL_PIN
@ RGN_FLAG_SEARCH_FILTER_UPDATE
@ RGN_FLAG_DYNAMIC_SIZE
@ RGN_FLAG_SIZE_CLAMP_X
@ RGN_FLAG_HIDDEN
@ RGN_FLAG_SIZE_CLAMP_Y
@ RGN_FLAG_POLL_FAILED
@ RGN_FLAG_TOO_SMALL
@ RGN_FLAG_SEARCH_FILTER_ACTIVE
@ GLOBAL_AREA_IS_HIDDEN
@ RGN_TYPE_CHANNELS
@ RGN_TYPE_TOOL_HEADER
@ RGN_TYPE_UI
@ RGN_TYPE_ASSET_SHELF_HEADER
@ RGN_TYPE_WINDOW
@ RGN_TYPE_ASSET_SHELF
@ RGN_TYPE_HUD
@ RGN_TYPE_PREVIEW
@ RGN_TYPE_FOOTER
@ RGN_TYPE_HEADER
@ RGN_TYPE_TOOLS
@ RGN_TYPE_TOOL_PROPS
#define RGN_TYPE_HAS_CATEGORY_MASK
#define HEADER_PADDING_Y
#define RGN_TYPE_NUM
#define RGN_TYPE_IS_HEADER_ANY(regiontype)
#define RGN_ALIGN_FLAG_FROM_MASK(align)
@ SCREENFULL
@ SCREENNORMAL
eSpace_Type
@ SPACE_CLIP
@ SPACE_NODE
@ SPACE_PROPERTIES
@ SPACE_EMPTY
@ SPACE_IMAGE
@ SPACE_VIEW3D
@ SPACE_FLAG_TYPE_WAS_ACTIVE
@ SPACE_FLAG_TYPE_TEMPORARY
@ USER_REGION_OVERLAP
#define UI_SCALE_FAC
#define UI_INV_SCALE_FAC
@ USER_APP_HIDE_REGION_TOGGLE
@ USER_APP_LOCK_CORNER_SPLIT
@ USER_APP_LOCK_EDGE_RESIZE
@ V2D_SCROLL_HORIZONTAL
@ V2D_SCROLL_VERTICAL_HANDLES
@ V2D_SCROLL_RIGHT
@ V2D_SCROLL_BOTTOM
@ V2D_SCROLL_HORIZONTAL_HANDLES
@ V2D_SCROLL_VERTICAL
@ V2D_LOCKOFS_X
@ V2D_LOCKOFS_Y
@ V2D_KEEPOFS_Y
@ V2D_KEEPOFS_X
const char * ED_buttons_search_string_get(SpaceProperties *sbuts)
void ED_area_tag_redraw(ScrArea *area)
Definition area.cc:708
@ ED_KEYMAP_NAVBAR
Definition ED_screen.hh:738
@ ED_KEYMAP_ASSET_SHELF
Definition ED_screen.hh:739
@ ED_KEYMAP_UI
Definition ED_screen.hh:729
@ ED_KEYMAP_ANIMATION
Definition ED_screen.hh:733
@ ED_KEYMAP_HEADER
Definition ED_screen.hh:735
@ ED_KEYMAP_TOOL
Definition ED_screen.hh:731
@ ED_KEYMAP_GPENCIL
Definition ED_screen.hh:737
@ ED_KEYMAP_GIZMO
Definition ED_screen.hh:730
@ ED_KEYMAP_VIEW2D
Definition ED_screen.hh:732
@ ED_KEYMAP_FRAMES
Definition ED_screen.hh:734
@ ED_KEYMAP_FOOTER
Definition ED_screen.hh:736
bool ED_area_is_global(const ScrArea *area)
Definition area.cc:3697
void ED_region_visibility_change_update_animated(bContext *C, ScrArea *area, ARegion *region)
void ED_area_exit(bContext *C, ScrArea *area)
AZone * ED_area_azones_update(ScrArea *area, const int mouse_xy[2])
void ED_region_do_msg_notify_tag_redraw(bContext *C, wmMsgSubscribeKey *msg_key, wmMsgSubscribeValue *msg_val)
Definition area.cc:381
AZScrollDirection
@ AZ_SCROLL_HOR
@ AZ_SCROLL_VERT
@ AZONE_REGION
@ AZONE_FULLSCREEN
@ AZONE_REGION_SCROLL
@ AZONE_AREA
@ AE_LEFT_TO_TOPRIGHT
@ AE_RIGHT_TO_TOPLEFT
@ AE_BOTTOM_TO_TOPLEFT
@ AE_TOP_TO_BOTTOMRIGHT
void ED_region_draw_cb_draw(const bContext *C, ARegion *region, int type)
#define REGION_DRAW_POST_PIXEL
GPUFrameBuffer * GPU_framebuffer_active_get()
void GPU_clear_color(float red, float green, float blue, float alpha)
void GPU_framebuffer_bind(GPUFrameBuffer *framebuffer)
void immEnd()
void immUnbindProgram()
void immUniformColor4f(float r, float g, float b, float a)
void immVertex2f(uint attr_id, float x, float y)
void immUniformThemeColor(int color_id)
void immBindBuiltinProgram(eGPUBuiltinShader shader_id)
void immBeginAtMost(GPUPrimType, uint max_vertex_len)
void immUniformColor4ub(unsigned char r, unsigned char g, unsigned char b, unsigned char a)
GPUVertFormat * immVertexFormat()
void immUniformColor4fv(const float rgba[4])
void immUniformThemeColorBlendShade(int color_id1, int color_id2, float fac, int offset)
void immAttr3fv(uint attr_id, const float data[3])
void immBegin(GPUPrimType, uint vertex_len)
void imm_draw_box_wire_2d(uint pos, float x1, float y1, float x2, float y2)
void immRecti(uint pos, int x1, int y1, int x2, int y2)
void immRectf(uint pos, float x1, float y1, float x2, float y2)
void GPU_matrix_identity_set()
void GPU_matrix_push()
void GPU_matrix_pop()
void GPU_matrix_translate_2f(float x, float y)
@ GPU_PRIM_TRI_FAN
@ GPU_PRIM_LINES
@ GPU_SHADER_3D_UNIFORM_COLOR
@ GPU_SHADER_3D_FLAT_COLOR
@ GPU_BLEND_NONE
Definition GPU_state.hh:85
@ GPU_BLEND_ALPHA
Definition GPU_state.hh:87
void GPU_blend(eGPUBlend blend)
Definition gpu_state.cc:42
void GPU_line_width(float width)
Definition gpu_state.cc:161
void GPU_scissor(int x, int y, int width, int height)
Definition gpu_state.cc:188
void GPU_scissor_get(int coords[4])
Definition gpu_state.cc:257
@ GPU_FETCH_FLOAT
@ GPU_FETCH_INT_TO_FLOAT
uint GPU_vertformat_attr_add(GPUVertFormat *, const char *name, GPUVertCompType, uint comp_len, GPUVertFetchMode)
void GPU_vertformat_clear(GPUVertFormat *)
@ GPU_COMP_F32
@ GPU_COMP_I32
void IMB_metadata_foreach(ImBuf *ibuf, IMBMetadataForeachCb callback, void *userdata)
Definition metadata.cc:88
Read Guarded memory(de)allocation.
#define MEM_SAFE_FREE(v)
Group Output data from inside of a node group A color picker Mix two input colors RGB to Convert a color s luminance to a grayscale value Generate a normal vector and a dot product Brightness Control the brightness and contrast of the input color Vector Map input vector components with curves Camera Retrieve information about the camera and how it relates to the current shading point s position Clamp a value between a minimum and a maximum Vector Perform vector math operation Invert Invert a color
#define C
Definition RandGen.cpp:29
void UI_region_button_sections_draw(const ARegion *region, int colorid, uiButtonSectionsAlign align)
void UI_blocklist_update_window_matrix(const bContext *C, const ListBase *lb)
bool UI_panel_is_closed(const Panel *panel)
#define UI_UNIT_Y
void UI_draw_roundbox_4fv(const rctf *rect, bool filled, float rad, const float col[4])
void UI_panel_category_draw_all(ARegion *region, const char *category_id_active)
@ UI_EMBOSS
PanelCategoryDyn * UI_panel_category_find(const ARegion *region, const char *idname)
#define INSTANCED_PANEL_UNIQUE_STR_SIZE
bool UI_block_apply_search_filter(uiBlock *block, const char *search_filter)
void UI_blocklist_free(const bContext *C, ARegion *region)
void uiLayoutSetScaleY(uiLayout *layout, float scale)
void uiItemL(uiLayout *layout, const char *name, int icon)
Panel * UI_panel_find_by_type(ListBase *lb, const PanelType *pt)
void UI_blocklist_update_view_for_buttons(const bContext *C, const ListBase *lb)
void UI_panel_header_buttons_begin(Panel *panel)
void UI_panels_free_instanced(const bContext *C, ARegion *region)
uiLayout * uiLayoutRow(uiLayout *layout, bool align)
uiLayout * UI_block_layout(uiBlock *block, int dir, int type, int x, int y, int size, int em, int padding, const uiStyle *style)
const uiStyle * UI_style_get_dpi()
bool UI_panel_category_is_visible(const ARegion *region)
@ UI_LAYOUT_PANEL
@ UI_LAYOUT_VERT_BAR
@ UI_LAYOUT_TOOLBAR
@ UI_LAYOUT_HEADER
void UI_block_listen(const uiBlock *block, const wmRegionListenerParams *listener_params)
void UI_block_translate(uiBlock *block, float x, float y)
Definition interface.cc:348
uiBlock * UI_block_begin(const bContext *C, ARegion *region, std::string name, eUIEmbossType emboss)
void UI_draw_roundbox_corner_set(int type)
#define UI_PANEL_MARGIN_X
void UI_panels_begin(const bContext *C, ARegion *region)
Panel * UI_panel_begin(ARegion *region, ListBase *lb, uiBlock *block, PanelType *pt, Panel *panel, bool *r_open)
void uiItemS(uiLayout *layout)
int UI_panel_size_y(const Panel *panel)
void UI_panels_end(const bContext *C, ARegion *region, int *r_x, int *r_y)
#define UI_HEADER_OFFSET
void UI_region_message_subscribe(ARegion *region, wmMsgBus *mbus)
bool UI_panel_is_active(const Panel *panel)
const uiStyle * UI_style_get()
bool UI_panel_should_show_background(const ARegion *region, const PanelType *panel_type)
#define UI_MAX_DRAW_STR
@ UI_CNR_BOTTOM_LEFT
@ UI_CNR_BOTTOM_RIGHT
@ UI_CNR_ALL
@ UI_CNR_TOP_LEFT
@ UI_CNR_TOP_RIGHT
void UI_panel_category_clear_all(ARegion *region)
#define UI_PANEL_CATEGORY_MARGIN_WIDTH
void UI_blocklist_free_inactive(const bContext *C, ARegion *region)
int uiLayoutGetWidth(uiLayout *layout)
void UI_blocklist_draw(const bContext *C, const ListBase *lb)
void UI_block_layout_free(uiBlock *block)
void UI_panel_label_offset(const uiBlock *block, int *r_x, int *r_y)
int UI_icon_from_event_type(short event_type, short event_value)
void UI_block_layout_resolve(uiBlock *block, int *r_x, int *r_y)
uiButtonSectionsAlign
void UI_panel_end(Panel *panel, int width, int height)
void UI_panel_header_buttons_end(Panel *panel)
bool UI_panel_is_dragging(const Panel *panel)
void UI_panels_draw(const bContext *C, ARegion *region)
#define UI_UNIT_X
@ UI_BTYPE_MENU
void uiLayoutSetOperatorContext(uiLayout *layout, wmOperatorCallContext opcontext)
void UI_draw_roundbox_aa(const rctf *rect, bool filled, float rad, const float color[4])
void UI_list_panel_unique_str(Panel *panel, char *r_name)
uiBut * uiDefButR(uiBlock *block, int type, int retval, const char *str, int x, int y, short width, short height, PointerRNA *ptr, const char *propname, int index, float min, float max, const char *tip)
void UI_panel_category_add(ARegion *region, const char *name)
void UI_region_handlers_add(ListBase *handlers)
void UI_block_end(const bContext *C, uiBlock *block)
void UI_block_set_search_only(uiBlock *block, bool search_only)
const char * UI_panel_category_active_get(ARegion *region, bool set_fallback)
@ UI_LAYOUT_VERTICAL
@ UI_LAYOUT_HORIZONTAL
void UI_region_free_active_but_all(bContext *C, ARegion *region)
bool uiLayoutEndsWithPanelHeader(const uiLayout &layout)
#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)
void UI_Theme_Store(bThemeState *theme_state)
void UI_Theme_Restore(const bThemeState *theme_state)
void UI_GetThemeColor3fv(int colorid, float col[3])
ThemeColorID
@ TH_HEADER
@ TH_GRID
@ TH_BACK
@ TH_EDITOR_BORDER
@ TH_PREVIEW_BACK
@ TH_CFRAME
@ TH_TEXT
@ TH_TEXT_HI
void UI_GetThemeColorShade3fv(int colorid, int offset, float col[3])
void UI_ThemeClearColor(int colorid)
void UI_GetThemeColor4fv(int colorid, float col[4])
bTheme * UI_GetTheme()
void UI_FontThemeColor(int fontid, int colorid)
void UI_SetTheme(int spacetype, int regionid)
void UI_GetThemeColor4ubv(int colorid, unsigned char col[4])
#define UI_MARKER_MARGIN_Y
Definition UI_view2d.hh:471
void UI_view2d_view_restore(const bContext *C)
Definition view2d.cc:1158
void UI_view2d_region_reinit(View2D *v2d, short type, int winx, int winy)
Definition view2d.cc:212
void UI_view2d_totRect_set(View2D *v2d, int width, int height)
Definition view2d.cc:1032
void UI_view2d_view_ortho(const View2D *v2d)
Definition view2d.cc:1091
void UI_view2d_mask_from_win(const View2D *v2d, rcti *r_mask)
Definition view2d.cc:109
@ V2D_COMMONVIEW_HEADER
Definition UI_view2d.hh:39
@ V2D_COMMONVIEW_PANELS_UI
Definition UI_view2d.hh:41
void UI_view2d_view_to_region(const View2D *v2d, float x, float y, int *r_region_x, int *r_region_y) ATTR_NONNULL()
Definition view2d.cc:1718
void UI_view2d_scrollers_draw_ex(View2D *v2d, const rcti *mask_custom, bool use_full_hide)
Definition view2d.cc:1510
float UI_view2d_scale_get_x(const View2D *v2d)
Definition view2d.cc:1916
#define WM_TOOLSYSTEM_SPACE_MASK
#define NC_WINDOW
Definition WM_types.hh:342
#define ND_FILEREAD
Definition WM_types.hh:379
#define ND_SPACE_CHANGED
Definition WM_types.hh:504
#define NC_WM
Definition WM_types.hh:341
wmOperatorCallContext
Definition WM_types.hh:216
@ WM_OP_INVOKE_REGION_WIN
Definition WM_types.hh:219
@ KM_NOTHING
Definition WM_types.hh:283
@ KM_ANY
Definition WM_types.hh:282
#define NC_SPACE
Definition WM_types.hh:359
ScrArea * ED_screen_areas_iter_next(const bScreen *screen, const ScrArea *area)
Definition area.cc:3746
void ED_area_do_mgs_subscribe_for_tool_header(const wmRegionMessageSubscribeParams *params)
Definition area.cc:414
void ED_area_tag_redraw(ScrArea *area)
Definition area.cc:708
int ED_region_snap_size_test(const ARegion *region)
Definition area.cc:4108
static constexpr float STATUS_MOUSE_ICON_PAD
Definition area.cc:879
bool ED_region_property_search(const bContext *C, ARegion *region, ListBase *paneltypes, const char *contexts[], const char *category_override)
Definition area.cc:3423
void ED_region_tag_refresh_ui(ARegion *region)
Definition area.cc:662
void ED_area_do_mgs_subscribe_for_tool_ui(const wmRegionMessageSubscribeParams *params)
Definition area.cc:429
void ED_region_update_rect(ARegion *region)
Definition area.cc:2205
ScrArea * ED_screen_areas_iter_first(const wmWindow *win, const bScreen *screen)
Definition area.cc:3733
BLI_INLINE bool streq_array_any(const char *s, const char *arr[])
Definition area.cc:2834
static bool panel_add_check(const bContext *C, const WorkSpace *workspace, const char *contexts[], const char *category_override, PanelType *panel_type)
Definition area.cc:3021
void ED_region_cursor_set(wmWindow *win, ScrArea *area, ARegion *region)
Definition area.cc:2220
const char * ED_area_region_search_filter_get(const ScrArea *area, const ARegion *region)
Definition area.cc:777
void ED_region_clear(const bContext *C, const ARegion *region, const int colorid)
Definition area.cc:2811
void ED_region_do_listen(wmRegionListenerParams *params)
Definition area.cc:127
static void region_evaulate_visibility(ARegion *region)
Definition area.cc:1833
int ED_area_global_size_y(const ScrArea *area)
Definition area.cc:3681
void ED_region_search_filter_update(const ScrArea *area, ARegion *region)
Definition area.cc:790
void ED_region_toggle_hidden(bContext *C, ARegion *region)
Definition area.cc:2280
static int panel_draw_width_from_max_width_get(const ARegion *region, const PanelType *panel_type, const int max_width)
Definition area.cc:3093
static void region_draw_blocks_in_view2d(const bContext *C, const ARegion *region)
Definition area.cc:3611
static bool region_uses_category_tabs(const ScrArea *area, const ARegion *region)
Definition area.cc:3061
static SpaceLink * area_get_prevspace(ScrArea *area)
Definition area.cc:2724
static void area_azone_tag_update(ScrArea *area)
Definition area.cc:292
int ED_area_global_min_size_y(const ScrArea *area)
Definition area.cc:3686
RegionEmbossSide
Definition area.cc:58
@ REGION_EMBOSS_BOTTOM
Definition area.cc:61
@ REGION_EMBOSS_ALL
Definition area.cc:63
@ REGION_EMBOSS_TOP
Definition area.cc:60
@ REGION_EMBOSS_LEFT
Definition area.cc:59
@ REGION_EMBOSS_RIGHT
Definition area.cc:62
ScrArea * ED_area_find_under_cursor(const bContext *C, int spacetype, const int event_xy[2])
Definition area.cc:3702
void ED_area_and_region_types_init(ScrArea *area)
Definition area.cc:2036
void ED_region_floating_init(ARegion *region)
Definition area.cc:2210
void ED_area_status_text(ScrArea *area, const char *str)
Definition area.cc:803
static void region_draw_azones(ScrArea *area, ARegion *region)
Definition area.cc:297
void ED_area_tag_redraw_no_rebuild(ScrArea *area)
Definition area.cc:717
int ED_area_global_max_size_y(const ScrArea *area)
Definition area.cc:3691
void ED_region_panels(const bContext *C, ARegion *region)
Definition area.cc:3340
void ED_region_do_msg_notify_tag_redraw(bContext *, wmMsgSubscribeKey *, wmMsgSubscribeValue *msg_val)
Definition area.cc:381
void region_toggle_hidden(bContext *C, ARegion *region, const bool do_fade)
Definition area.cc:2265
static void ed_workspace_status_icon_item(WorkSpace *workspace, const int icon, const bool inverted=false)
Definition area.cc:889
void ED_region_header(const bContext *C, ARegion *region)
Definition area.cc:3650
static void region_overlap_fix(ScrArea *area, ARegion *region)
Definition area.cc:1332
const rcti * ED_region_visible_rect(ARegion *region)
Definition area.cc:4014
static void area_offscreen_exit(wmWindowManager *wm, wmWindow *win, ScrArea *area)
Definition area.cc:2158
static void ed_workspace_status_space(WorkSpace *workspace, const float space_factor)
Definition area.cc:859
void ED_area_do_listen(wmSpaceTypeListenerParams *params)
Definition area.cc:159
static bool panel_property_search(const bContext *C, ARegion *region, const uiStyle *style, Panel *panel, PanelType *panel_type, const char *search_filter)
Definition area.cc:3362
static const char * region_panels_collect_categories(ARegion *region, LinkNode *panel_types_stack, bool *use_category_tabs)
Definition area.cc:3069
void ED_region_cache_draw_cached_segments(ARegion *region, const int num_segments, const int *points, const int sfra, const int efra)
Definition area.cc:4064
static void region_align_info_from_area(ScrArea *area, RegionTypeAlignInfo *r_align_info)
Definition area.cc:2352
void ED_region_header_init(ARegion *region)
Definition area.cc:3665
static constexpr float STATUS_AFTER_TEXT
Definition area.cc:878
void ED_region_header_with_button_sections(const bContext *C, ARegion *region, const uiButtonSectionsAlign align)
Definition area.cc:3657
bool ED_area_is_global(const ScrArea *area)
Definition area.cc:3697
void ED_region_cache_draw_background(ARegion *region)
Definition area.cc:4025
void ED_area_swapspace(bContext *C, ScrArea *sa1, ScrArea *sa2)
Definition area.cc:2570
void ED_region_header_draw_with_button_sections(const bContext *C, const ARegion *region, const uiButtonSectionsAlign align)
Definition area.cc:3632
static void region_draw_emboss(const ARegion *region, const rcti *scirct, int sides)
Definition area.cc:69
static void ed_workspace_status_text_item(WorkSpace *workspace, std::string text)
Definition area.cc:881
void ED_region_pixelspace(const ARegion *region)
Definition area.cc:121
static void area_calc_totrct(ScrArea *area, const rcti *window_rect)
Definition area.cc:1792
void ED_area_offscreen_free(wmWindowManager *wm, wmWindow *win, ScrArea *area)
Definition area.cc:2188
void ED_area_data_copy(ScrArea *area_dst, ScrArea *area_src, const bool do_free)
Definition area.cc:2285
void ED_region_header_draw(const bContext *C, ARegion *region)
Definition area.cc:3625
static void region_azone_edge_init(ScrArea *area, ARegion *region, AZEdge edge, const bool is_fullscreen)
Definition area.cc:1209
void ED_region_tag_redraw_no_rebuild(ARegion *region)
Definition area.cc:653
int ED_area_headersize()
Definition area.cc:3670
ScrArea * ED_area_offscreen_create(wmWindow *win, eSpace_Type space_type)
Definition area.cc:2147
void ED_area_tag_redraw_regiontype(ScrArea *area, int regiontype)
Definition area.cc:726
bool ED_area_has_shared_border(ScrArea *a, ScrArea *b)
Definition area.cc:1998
void ED_region_panels_layout_ex(const bContext *C, ARegion *region, ListBase *paneltypes, wmOperatorCallContext op_context, const char *contexts[], const char *category_override)
Definition area.cc:3103
static void region_azone_edge(const ScrArea *area, AZone *az, const ARegion *region)
Definition area.cc:1092
bool ED_region_snap_size_apply(ARegion *region, int snap_flag)
Definition area.cc:4121
bool ED_region_is_overlap(int spacetype, int regiontype)
Definition area.cc:1407
static void metadata_panel_draw_field(const char *field, const char *value, void *ctx_v)
Definition area.cc:3855
static void area_draw_azone(short, short, short, short)
Corner widgets use for dragging and splitting the view.
Definition area.cc:195
void ED_region_tag_redraw_partial(ARegion *region, const rcti *rct, bool rebuild)
Definition area.cc:681
static void region_azone_scrollbar_init(ScrArea *area, ARegion *region, AZScrollDirection direction)
Definition area.cc:1234
void ED_area_tag_region_size_update(ScrArea *area, ARegion *changed_region)
Definition area.cc:744
static void region_visible_rect_calc(ARegion *region, rcti *rect)
Definition area.cc:3965
static void region_clear_fully_transparent(const bContext *C)
Definition area.cc:2826
static void region_azones_add(const bScreen *screen, ScrArea *area, ARegion *region)
Definition area.cc:1292
void ED_region_visibility_change_update(bContext *C, ScrArea *area, ARegion *region)
Definition area.cc:2258
static void area_azone_init(wmWindow *win, const bScreen *screen, ScrArea *area)
Definition area.cc:976
void ED_region_do_layout(bContext *C, ARegion *region)
Definition area.cc:476
void ED_region_tag_redraw_cursor(ARegion *region)
Definition area.cc:646
void ED_area_newspace(bContext *C, ScrArea *area, int type, const bool skip_region_exit)
Definition area.cc:2596
void ED_region_cache_draw_curfra_label(const int framenr, const float x, const float y)
Definition area.cc:4039
void ED_area_data_swap(ScrArea *area_dst, ScrArea *area_src)
Definition area.cc:2318
static void region_draw_status_text(ScrArea *, ARegion *region)
Definition area.cc:342
static bool region_background_is_transparent(const ScrArea *area, const ARegion *region)
Definition area.cc:1077
void ED_area_update_region_sizes(wmWindowManager *wm, wmWindow *win, ScrArea *area)
Definition area.cc:1959
void ED_area_tag_refresh(ScrArea *area)
Definition area.cc:737
void ED_region_info_draw_multiline(ARegion *region, const char *text_array[], const float fill_color[4], const bool full_redraw)
Definition area.cc:3766
int ED_region_global_size_y()
Definition area.cc:3761
static void region_azone_tab_plus(ScrArea *area, AZone *az, ARegion *region)
Definition area.cc:1138
static void ed_default_handlers(wmWindowManager *wm, ScrArea *area, ARegion *region, ListBase *handlers, int flag)
Definition area.cc:1855
static bool region_azone_edge_poll(const ARegion *region, const bool is_fullscreen)
Definition area.cc:1176
static short region_alignment_from_header_and_tool_header_state(const RegionTypeAlignInfo *region_align_info, const short fallback)
Definition area.cc:2380
void ED_area_do_refresh(bContext *C, ScrArea *area)
Definition area.cc:167
static void region_align_info_to_area_for_headers(const RegionTypeAlignInfo *region_align_info_src, const RegionTypeAlignInfo *region_align_info_dst, ARegion *region_by_type[RGN_TYPE_NUM])
Definition area.cc:2427
void ED_region_panels_layout(const bContext *C, ARegion *region)
Definition area.cc:3275
void ED_region_panels_init(wmWindowManager *wm, ARegion *region)
Definition area.cc:3347
void ED_workspace_status_text(bContext *C, const char *str)
Definition area.cc:966
static void area_init_type_fallback(ScrArea *area, eSpace_Type space_type)
Definition area.cc:2006
void ED_region_image_metadata_panel_draw(ImBuf *ibuf, uiLayout *layout)
Definition area.cc:3863
static bool event_in_markers_region(const ARegion *region, const wmEvent *event)
Definition area.cc:1845
void ED_region_tag_redraw_editor_overlays(ARegion *region)
Definition area.cc:669
static void region_draw_azone_tab_arrow(ScrArea *area, ARegion *region, AZone *az)
Definition area.cc:259
static void region_update_rect(ARegion *region)
Definition area.cc:2196
int ED_area_header_switchbutton(const bContext *C, uiBlock *block, int yco)
Definition area.cc:2770
void ED_region_info_draw(ARegion *region, const char *text, const float fill_color[4], const bool full_redraw)
Definition area.cc:3842
void ED_region_visibility_change_update_ex(bContext *C, ScrArea *area, ARegion *region, bool is_hidden, bool do_init)
Definition area.cc:2239
static void area_offscreen_init(ScrArea *area)
Definition area.cc:2134
void ED_area_do_msg_notify_tag_refresh(bContext *, wmMsgSubscribeKey *, wmMsgSubscribeValue *msg_val)
Definition area.cc:404
static void ed_workspace_status_item(WorkSpace *workspace, std::string text, const int icon, const float space_factor=0.0f, const bool inverted=false)
Definition area.cc:840
void ED_region_do_draw(bContext *C, ARegion *region)
Definition area.cc:499
void ED_region_tag_redraw(ARegion *region)
Definition area.cc:634
static void region_align_info_to_area(ScrArea *area, const RegionTypeAlignInfo region_align_info_src[RGN_TYPE_NUM])
Definition area.cc:2542
void ED_region_message_subscribe(wmRegionMessageSubscribeParams *params)
Definition area.cc:4089
int ED_area_footersize()
Definition area.cc:3676
void ED_region_grid_draw(ARegion *region, float zoomx, float zoomy, float x0, float y0)
Definition area.cc:3870
static ThemeColorID region_background_color_id(const bContext *, const ARegion *region)
Definition area.cc:2798
static void fullscreen_azone_init(ScrArea *area, ARegion *region)
Definition area.cc:1045
void ED_area_prevspace(bContext *C, ScrArea *area)
Definition area.cc:2746
static void layout_coordinates_correct_for_drawable_rect(const wmWindow *win, const ScrArea *area, const ARegion *region, int *, int *r_yco)
Definition area.cc:3506
static void area_draw_azone_fullscreen(short, short, short x2, short y2, float alpha)
Corner widget use for quitting full-screen.
Definition area.cc:179
static bool area_is_pseudo_minimized(const ScrArea *area)
Definition area.cc:471
static void region_rect_recursive(ScrArea *area, ARegion *region, rcti *remainder, rcti *overlap_remainder, int quad)
Definition area.cc:1454
void ED_area_init(wmWindowManager *wm, wmWindow *win, ScrArea *area)
Definition area.cc:2053
void ED_region_panels_ex(const bContext *C, ARegion *region, wmOperatorCallContext op_context, const char *contexts[])
Definition area.cc:3330
static void draw_azone_arrow(float x1, float y1, float x2, float y2, AZEdge edge)
Edge widgets to show hidden panels such as the toolbar and headers.
Definition area.cc:203
static void region_azones_scrollbars_init(ScrArea *area, ARegion *region)
Definition area.cc:1256
static void region_azones_add_edge(ScrArea *area, ARegion *region, const int alignment, const bool is_fullscreen)
Definition area.cc:1271
void ED_region_panels_draw(const bContext *C, ARegion *region)
Definition area.cc:3281
static int rct_fits(const rcti *rect, const eScreenAxis dir_axis, int size)
Definition area.cc:1319
void ED_region_header_layout(const bContext *C, ARegion *region)
Definition area.cc:3526
static void ed_panel_draw(const bContext *C, ARegion *region, ListBase *lb, PanelType *pt, Panel *panel, int w, int em, char *unique_panel_str, const char *search_filter, wmOperatorCallContext op_context)
Definition area.cc:2853
int pad[32 - sizeof(int)]
#define U
ATTR_WARN_UNUSED_RESULT const BMLoop * l
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition btDbvt.cpp:52
SIMD_FORCE_INLINE const btScalar & w() const
Return the w value.
Definition btQuadWord.h:119
void range(std::string text, int icon1, int icon2)
Definition area.cc:915
void item_bool(std::string text, bool inverted, int icon1, int icon2=0)
Definition area.cc:924
WorkspaceStatus(bContext *C)
Definition area.cc:864
void item(std::string text, int icon1, int icon2=0)
Definition area.cc:908
void opmodal(std::string text, const wmOperatorType *ot, int propvalue, bool inverted=false)
Definition area.cc:934
local_group_size(16, 16) .push_constant(Type b
#define printf
#define floorf(x)
#define fabsf(x)
draw_view in_light_buf[] float
draw_view push_constant(Type::INT, "radiance_src") .push_constant(Type capture_info_buf storage_buf(1, Qualifier::READ, "ObjectBounds", "bounds_buf[]") .push_constant(Type draw_view int
#define str(s)
blender::gpu::Batch * quad
BLI_INLINE float fb(float length, float L)
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
int count
format
void *(* MEM_mallocN)(size_t len, const char *str)
Definition mallocn.cc:44
void MEM_freeN(void *vmemh)
Definition mallocn.cc:105
void *(* MEM_callocN)(size_t len, const char *str)
Definition mallocn.cc:42
ccl_device_inline float4 mask(const int4 mask, const float4 a)
#define G(x, y, z)
static void add(blender::Map< std::string, std::string > &messages, Message &msg)
Definition msgfmt.cc:227
PointerRNA RNA_pointer_create(ID *id, StructRNA *type, void *data)
eScreenDir area_getorientation(ScrArea *sa_a, ScrArea *sa_b)
void screen_area_spacelink_add(const Scene *scene, ScrArea *area, eSpace_Type space_type)
#define AZONESPOTW
#define AZONESPOTH
eScreenAxis
@ SCREEN_AXIS_V
@ SCREEN_AXIS_H
#define AZONEFADEOUT
void(* message_subscribe)(const wmRegionMessageSubscribeParams *params)
void(* cursor)(wmWindow *win, ScrArea *area, ARegion *region)
void(* listener)(const wmRegionListenerParams *params)
ListBase headertypes
void(* draw)(const bContext *C, ARegion *region)
void(* layout)(const bContext *C, ARegion *region)
ListBase paneltypes
int(* snap_size)(const ARegion *region, int size, int axis)
const char * category
short do_draw_paintcursor
ARegion_Runtime runtime
struct ARegion * prev
char * headerstr
struct ARegion * next
ListBase panels
ListBase ui_lists
ListBase handlers
struct wmGizmoMap * gizmo_map
struct ARegionType * type
ListBase uiblocks
float alpha
AZEdge edge
ARegion * region
AZScrollDirection direction
uiLayout * layout
HeaderType * type
struct LinkNode * next
void * last
void * first
void(* draw)(const bContext *C, Panel *panel)
char idname[BKE_ST_MAXNAME]
bool(* poll)(const bContext *C, PanelType *pt)
char context[BKE_ST_MAXNAME]
char owner_id[128]
ListBase children
char category[BKE_ST_MAXNAME]
void(* draw_header_preset)(const bContext *C, Panel *panel)
PanelType * parent
void(* draw_header)(const bContext *C, Panel *panel)
LayoutPanels layout_panels
struct PanelType * type
short labelofs
struct Panel_Runtime * runtime
struct uiLayout * layout
ListBase children
struct RegionTypeAlignInfo::@120171350042037242361125204277245336203176340102 by_type[RGN_TYPE_NUM]
ListBase areabase
struct bToolRef * tool
ListBase handlers
ScrVert * v2
ListBase actionzones
ListBase spacedata
short butspacetype_subtype
struct SpaceType * type
ScrArea_Runtime runtime
ScrVert * v1
struct ScrArea * next
ListBase regionbase
ScrGlobalAreaData * global
ScrVert * v4
void(* free)(SpaceLink *sl)
Definition BKE_screen.hh:84
void(* refresh)(const bContext *C, ScrArea *area)
Definition BKE_screen.hh:97
SpaceLink *(* create)(const ScrArea *area, const Scene *scene)
Definition BKE_screen.hh:82
void(* exit)(wmWindowManager *wm, ScrArea *area)
Definition BKE_screen.hh:89
void(* init)(wmWindowManager *wm, ScrArea *area)
Definition BKE_screen.hh:87
void(* space_subtype_item_extend)(bContext *C, EnumPropertyItem **item, int *totitem)
void(* space_subtype_set)(ScrArea *area, int value)
unsigned char header[4]
char alpha_vert
short keepofs
WorkSpaceRuntimeHandle * runtime
ListBase areabase
ThemeSpace space_view3d
float xmax
float xmin
float ymax
float ymin
int ymin
int ymax
int xmin
int xmax
uiFontStyle widget
short y
short x
int xy[2]
Definition WM_types.hh:726
unsigned int data
Definition WM_types.hh:325
unsigned int category
Definition WM_types.hh:325
struct wmMsgBus * message_bus
struct wmWindow * parent
struct wmEvent * eventstate
ScrAreaMap global_areas
struct WorkSpaceInstanceHook * workspace_hook
bool ED_time_scrub_event_in_region(const ARegion *region, const wmEvent *event)
ccl_device_inline int abs(int x)
Definition util/math.h:120
void WM_cursor_set(wmWindow *win, int curs)
bool WM_cursor_set_from_tool(wmWindow *win, const ScrArea *area, const ARegion *region)
@ WM_CURSOR_DEFAULT
Definition wm_cursors.hh:15
ListBase * WM_dropboxmap_find(const char *idname, int spaceid, int regionid)
static ListBase dropboxes
bool WM_region_use_viewport(ScrArea *area, ARegion *region)
Definition wm_draw.cc:556
void WM_draw_region_free(ARegion *region)
Definition wm_draw.cc:1603
wmEventHandler_Dropbox * WM_event_add_dropbox_handler(ListBase *handlers, ListBase *dropboxes)
wmEventHandler_Keymap * WM_event_add_keymap_handler_poll(ListBase *handlers, wmKeyMap *keymap, EventHandlerPoll poll)
wmEventHandler_Keymap * WM_event_add_keymap_handler(ListBase *handlers, wmKeyMap *keymap)
void WM_event_get_keymap_from_toolsystem(wmWindowManager *wm, wmWindow *win, wmEventHandler_Keymap *handler, wmEventHandler_KeymapResult *km_result)
void WM_event_modal_handler_region_replace(wmWindow *win, const ARegion *old_region, ARegion *new_region)
void WM_event_modal_handler_area_replace(wmWindow *win, const ScrArea *old_area, ScrArea *new_area)
void WM_event_add_notifier(const bContext *C, uint type, void *reference)
wmEventHandler_Keymap * WM_event_add_keymap_handler_dynamic(ListBase *handlers, wmEventHandler_KeymapDynamicFn keymap_fn, void *user_data)
ScrArea * WM_window_status_area_find(wmWindow *win, bScreen *screen)
void WM_event_get_keymap_from_toolsystem_with_gizmos(wmWindowManager *wm, wmWindow *win, wmEventHandler_Keymap *handler, wmEventHandler_KeymapResult *km_result)
void WM_event_remove_handlers(bContext *C, ListBase *handlers)
void WM_event_add_mousemove(wmWindow *win)
PointerRNA * ptr
Definition wm_files.cc:4126
wmOperatorType * ot
Definition wm_files.cc:4125
bool WM_gizmomap_cursor_set(const wmGizmoMap *gzmap, wmWindow *win)
void WM_gizmomap_add_handlers(ARegion *region, wmGizmoMap *gzmap)
void WM_gizmomap_message_subscribe(const bContext *C, wmGizmoMap *gzmap, ARegion *region, wmMsgBus *mbus)
wmGizmoMap * WM_gizmomap_new_from_type(const wmGizmoMapType_Params *gzmap_params)
const wmKeyMapItem * WM_modalkeymap_find_propvalue(const wmKeyMap *km, const int propvalue)
wmKeyMap * WM_keymap_active(const wmWindowManager *wm, wmKeyMap *keymap)
wmKeyMap * WM_keymap_ensure(wmKeyConfig *keyconf, const char *idname, int spaceid, int regionid)
Definition wm_keymap.cc:897
void WM_msgbus_clear_by_owner(wmMsgBus *mbus, void *owner)
#define WM_msg_subscribe_rna_prop(mbus, id_, data_, type_, prop_, value)
void WM_msg_subscribe_rna(wmMsgBus *mbus, PointerRNA *ptr, const PropertyRNA *prop, const wmMsgSubscribeValue *msg_val_params, const char *id_repr)
void wmPartialViewport(rcti *drawrct, const rcti *winrct, const rcti *partialrct)
void wmOrtho2_region_pixelspace(const ARegion *region)
bool WM_toolsystem_refresh_screen_area(WorkSpace *workspace, const Scene *scene, ViewLayer *view_layer, ScrArea *area)
bool WM_window_is_fullscreen(const wmWindow *win)
int WM_window_native_pixel_x(const wmWindow *win)
wmWindow * WM_window_find_under_cursor(wmWindow *win, const int event_xy[2], int r_event_xy_other[2])
void WM_window_rect_calc(const wmWindow *win, rcti *r_rect)
ViewLayer * WM_window_get_active_view_layer(const wmWindow *win)
Scene * WM_window_get_active_scene(const wmWindow *win)
void WM_event_timer_remove(wmWindowManager *wm, wmWindow *, wmTimer *timer)
void WM_window_title(wmWindowManager *wm, wmWindow *win, const char *title)
Definition wm_window.cc:485
WorkSpace * WM_window_get_active_workspace(const wmWindow *win)
bScreen * WM_window_get_active_screen(const wmWindow *win)
uint8_t flag
Definition wm_window.cc:138