Blender V5.0
interface_region_hud.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
10
11#include <cstring>
12
13#include "MEM_guardedalloc.h"
14
15#include "DNA_screen_types.h"
16#include "DNA_userdef_types.h"
17
18#include "BLI_listbase.h"
19#include "BLI_rect.h"
20#include "BLI_string_utf8.h"
21#include "BLI_utildefines.h"
22
23#include "BKE_context.hh"
24#include "BKE_screen.hh"
25
26#include "WM_api.hh"
27#include "WM_types.hh"
28
30#include "UI_view2d.hh"
31
32#include "BLT_translation.hh"
33
34#include "ED_screen.hh"
35
36#include "GPU_framebuffer.hh"
37#include "interface_intern.hh"
38
39/* -------------------------------------------------------------------- */
42
46static int area_calc_region_type_index(const ScrArea *area, const ARegion *region)
47{
48 const int region_type = region->regiontype;
49 int index = 0;
50 LISTBASE_FOREACH (const ARegion *, region_iter, &area->regionbase) {
51 if (region_iter->regiontype != region_type) {
52 continue;
53 }
54 if (region_iter == region) {
55 return index;
56 }
57 index += 1;
58 }
59
60 /* Bad input as the `region` was not found in the `area`,
61 * -1 causes the first to be returned. */
63 return -1;
64}
65
70 const short region_type,
71 int index_hint)
72{
73 ARegion *region_match_type = nullptr;
74 /* Any negative values can return the first match. */
75 index_hint = std::max(0, index_hint);
76 int index = 0;
77 LISTBASE_FOREACH (ARegion *, region, &area->regionbase) {
78 if (region->regiontype != region_type) {
79 continue;
80 }
81 if (index == index_hint) {
82 region_match_type = region;
83 break;
84 }
85 if (region_match_type == nullptr) {
86 region_match_type = region;
87 }
88 index += 1;
89 }
90 return region_match_type;
91}
92
105
106static bool last_redo_poll(const bContext *C, short region_type, int region_index_hint)
107{
109 if (op == nullptr) {
110 return false;
111 }
112
113 bool success = false;
114 {
115 /* Make sure that we are using the same region type as the original
116 * operator call. Otherwise we would be polling the operator with the
117 * wrong context.
118 */
119 ScrArea *area = CTX_wm_area(C);
120 ARegion *region_op = (region_type != -1) ? area_find_region_by_type_and_index_hint(
121 area, region_type, region_index_hint) :
122 nullptr;
123 ARegion *region_prev = CTX_wm_region(C);
124 CTX_wm_region_set((bContext *)C, region_op);
125
126 if (WM_operator_repeat_check(C, op) && WM_operator_ui_poll(op->type, op->ptr)) {
127 success = WM_operator_poll((bContext *)C, op->type);
128 }
129 CTX_wm_region_set((bContext *)C, region_prev);
130 }
131 return success;
132}
133
134static void hud_region_hide(ARegion *region)
135{
136 region->flag |= RGN_FLAG_HIDDEN;
137 /* Avoids setting 'AREA_FLAG_REGION_SIZE_UPDATE'
138 * since other regions don't depend on this. */
139 BLI_rcti_init(&region->winrct, 0, 0, 0, 0);
140}
141
143
144/* -------------------------------------------------------------------- */
147
149{
150 ScrArea *area = CTX_wm_area(C);
152 if (region != nullptr) {
153 HudRegionData *hrd = static_cast<HudRegionData *>(region->regiondata);
154 if (hrd != nullptr) {
155 return last_redo_poll(C, hrd->regionid, hrd->region_index_hint);
156 }
157 }
158 return false;
159}
160
162{
164 const std::string opname = WM_operatortype_name(op->type, op->ptr);
165 UI_panel_drawname_set(panel, opname);
166}
167
168static void hud_panel_operator_redo_draw(const bContext *C, Panel *panel)
169{
171 if (op == nullptr) {
172 return;
173 }
175 panel->layout->enabled_set(false);
176 }
177 uiLayout *col = &panel->layout->column(false);
179}
180
181static void hud_panels_register(ARegionType *art, int space_type, int region_type)
182{
183 PanelType *pt = MEM_callocN<PanelType>(__func__);
184 STRNCPY_UTF8(pt->idname, "OPERATOR_PT_redo");
185 STRNCPY_UTF8(pt->label, N_("Redo"));
190 pt->space_type = space_type;
191 pt->region_type = region_type;
193 BLI_addtail(&art->paneltypes, pt);
194}
195
197
198/* -------------------------------------------------------------------- */
201
202static void hud_region_init(wmWindowManager *wm, ARegion *region)
203{
204 ED_region_panels_init(wm, region);
205
206 /* Reset zoom from panels init because we don't want zoom allowed for redo panel. */
207 region->v2d.maxzoom = 1.0f;
208 region->v2d.minzoom = 1.0f;
209
210 UI_region_handlers_add(&region->runtime->handlers);
212}
213
214static void hud_region_free(ARegion *region)
215{
216 MEM_SAFE_FREE(region->regiondata);
217}
218
219static void hud_region_layout(const bContext *C, ARegion *region)
220{
221 HudRegionData *hrd = static_cast<HudRegionData *>(region->regiondata);
222 if (hrd == nullptr || !last_redo_poll(C, hrd->regionid, hrd->region_index_hint)) {
223 ED_region_tag_redraw(region);
224 hud_region_hide(region);
225 return;
226 }
227
228 ScrArea *area = CTX_wm_area(C);
229 const int size_y = region->sizey;
230
231 ED_region_panels_layout(C, region);
232
233 if (region->panels.first &&
234 ((area->flag & AREA_FLAG_REGION_SIZE_UPDATE) || (region->sizey != size_y)))
235 {
236 int winx_new = UI_SCALE_FAC * (region->sizex + 0.5f);
237 int winy_new = UI_SCALE_FAC * (region->sizey + 0.5f);
238 View2D *v2d = &region->v2d;
239
240 if (region->flag & RGN_FLAG_SIZE_CLAMP_X) {
241 CLAMP_MAX(winx_new, region->winx);
242 }
243 if (region->flag & RGN_FLAG_SIZE_CLAMP_Y) {
244 CLAMP_MAX(winy_new, region->winy);
245 }
246
247 region->winx = winx_new;
248 region->winy = winy_new;
249
250 region->winrct.xmax = (region->winrct.xmin + region->winx) - 1;
251 region->winrct.ymax = (region->winrct.ymin + region->winy) - 1;
252
254
255 /* Weak, but needed to avoid glitches, especially with hi-dpi
256 * (where resizing the view glitches often).
257 * Fortunately this only happens occasionally. */
258 ED_region_panels_layout(C, region);
259 }
260
261 /* restore view matrix */
263}
264
265static void hud_region_draw(const bContext *C, ARegion *region)
266{
267 UI_view2d_view_ortho(&region->v2d);
269 GPU_clear_color(0.0f, 0.0f, 0.0f, 0.0f);
270
271 if ((region->flag & RGN_FLAG_HIDDEN) == 0) {
272 rcti reset_rect = {};
273 reset_rect.xmax = region->winx;
274 reset_rect.ymax = region->winy;
275 ui_draw_menu_back(nullptr, nullptr, &reset_rect);
276 ED_region_panels_draw(C, region);
277 }
278}
279
281{
282 ARegion *region = params->region;
283 const wmNotifier *wmn = params->notifier;
284
285 switch (wmn->category) {
286 case NC_WM:
287 if (wmn->data == ND_HISTORY) {
288 ED_region_tag_redraw(region);
289 }
290 break;
291 }
292}
293
295{
296 ARegionType *art = MEM_callocN<ARegionType>(__func__);
297 art->regionid = RGN_TYPE_HUD;
301 art->draw = hud_region_draw;
302 art->init = hud_region_init;
303 art->free = hud_region_free;
304
305 /* We need to indicate a preferred size to avoid false `RGN_FLAG_TOO_SMALL`
306 * the first time the region is created. */
307 art->prefsizex = AREAMINX;
308 art->prefsizey = HEADERY;
309
310 hud_panels_register(art, space_type, art->regionid);
311
313 return art;
314}
315
317{
318 ARegion *region = BKE_area_region_new();
320 if (region_win) {
321 BLI_insertlinkbefore(&area->regionbase, region_win, region);
322 }
323 else {
324 BLI_addtail(&area->regionbase, region);
325 }
326 region->regiontype = RGN_TYPE_HUD;
327 region->alignment = RGN_ALIGN_FLOAT;
328 region->overlap = true;
329 region->flag |= RGN_FLAG_DYNAMIC_SIZE;
330
331 return region;
332}
333
335{
336 LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
338 LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
339 if (area != area_keep) {
340 LISTBASE_FOREACH (ARegion *, region, &area->regionbase) {
341 if (region->regiontype == RGN_TYPE_HUD) {
342 if ((region->flag & RGN_FLAG_HIDDEN) == 0) {
343 hud_region_hide(region);
344 ED_region_tag_redraw(region);
345 ED_area_tag_redraw(area);
346 }
347 }
348 }
349 }
350 }
351 }
352}
353
355{
357 ED_area_type_hud_clear(wm, area);
358
360 if (art == nullptr) {
361 return;
362 }
363
365
366 if (region && (region->flag & RGN_FLAG_HIDDEN_BY_USER)) {
367 /* The region is intentionally hidden by the user, don't show it. */
368 hud_region_hide(region);
369 return;
370 }
371
372 bool init = false;
373 const bool was_hidden = region == nullptr || region->runtime->visible == false;
374 ARegion *region_op = CTX_wm_region(C);
375 BLI_assert((region_op == nullptr) || (region_op->regiontype != RGN_TYPE_HUD));
376 const int region_index_hint = region_op ? area_calc_region_type_index(area, region_op) : -1;
377 if (!last_redo_poll(C, region_op ? region_op->regiontype : -1, region_index_hint)) {
378 if (region) {
379 ED_region_tag_redraw(region);
380 hud_region_hide(region);
381 }
382 return;
383 }
384
385 if (region == nullptr) {
386 init = true;
387 region = hud_region_add(area);
388 region->runtime->type = art;
389 }
390
391 /* Let 'ED_area_update_region_sizes' do the work of placing the region.
392 * Otherwise we could set the 'region->winrct' & 'region->winx/winy' here. */
393 if (init) {
394 ED_area_tag_region_size_update(area, region);
395 }
396 else {
397 if (region->flag & RGN_FLAG_HIDDEN) {
398 /* Also forces recalculating HUD size in hud_region_layout(). */
399 ED_area_tag_region_size_update(area, region);
400 }
401 region->flag &= ~RGN_FLAG_HIDDEN;
402 }
403
404 {
405 HudRegionData *hrd = static_cast<HudRegionData *>(region->regiondata);
406 if (hrd == nullptr) {
407 hrd = MEM_callocN<HudRegionData>(__func__);
408 region->regiondata = hrd;
409 }
410 if (region_op) {
411 hrd->regionid = region_op->regiontype;
412 hrd->region_index_hint = region_index_hint;
413 }
414 else {
415 hrd->regionid = -1;
416 hrd->region_index_hint = -1;
417 }
418 }
419
420 if (init) {
421 /* This is needed or 'winrct' will be invalid. */
422 wmWindow *win = CTX_wm_window(C);
423 ED_area_update_region_sizes(wm, win, area);
424 }
425
427 ED_region_tag_redraw(region);
428
429 /* We need to update/initialize the runtime offsets. */
431 if (region_win) {
432 float x, y;
433
434 UI_view2d_scroller_size_get(&region_win->v2d, true, &x, &y);
435 region->runtime->offset_x = x;
436 region->runtime->offset_y = y;
437 }
438
439 /* Reset zoom level (not well supported). */
440 rctf reset_rect = {};
441 reset_rect.xmax = region->winx;
442 reset_rect.ymax = region->winy;
443 region->v2d.cur = region->v2d.tot = reset_rect;
444 region->v2d.minzoom = 1.0f;
445 region->v2d.maxzoom = 1.0f;
446
447 region->runtime->visible = !(region->flag & RGN_FLAG_HIDDEN);
448
449 /* We shouldn't need to do this every time :S */
450 /* XXX, this is evil! - it also makes the menu show on first draw. :( */
451 if (region->runtime->visible) {
452 ARegion *region_prev = CTX_wm_region(C);
453 CTX_wm_region_set(C, region);
454 hud_region_layout(C, region);
455 if (was_hidden) {
456 region->winx = region->v2d.winx;
457 region->winy = region->v2d.winy;
458 region->v2d.cur = region->v2d.tot = reset_rect;
459 }
460 CTX_wm_region_set(C, region_prev);
461 }
462
463 region->runtime->visible = !((region->flag & RGN_FLAG_HIDDEN) ||
464 (region->flag & RGN_FLAG_TOO_SMALL));
465}
466
468{
469 BLI_assert(hud_region->regiontype == RGN_TYPE_HUD);
470 HudRegionData *hrd = static_cast<HudRegionData *>(hud_region->regiondata);
471
472 if (hrd->regionid == -1) {
473 return nullptr;
474 }
475
477}
478
ScrArea * CTX_wm_area(const bContext *C)
wmWindow * CTX_wm_window(const bContext *C)
void CTX_wm_region_set(bContext *C, ARegion *region)
ARegion * CTX_wm_region(const bContext *C)
wmWindowManager * CTX_wm_manager(const bContext *C)
ARegion * BKE_area_region_new()
Definition screen.cc:387
ARegionType * BKE_regiontype_from_id(const SpaceType *st, int regionid)
Definition screen.cc:267
@ PANEL_TYPE_DEFAULT_CLOSED
ARegion * BKE_area_find_region_type(const ScrArea *area, int region_type)
Definition screen.cc:846
@ REGION_DRAW_LOCK_ALL
#define BLI_assert_unreachable()
Definition BLI_assert.h:93
#define BLI_assert(a)
Definition BLI_assert.h:46
#define LISTBASE_FOREACH(type, var, list)
void BLI_addtail(ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:111
void BLI_insertlinkbefore(ListBase *listbase, void *vnextlink, void *vnewlink) ATTR_NONNULL(1)
Definition listbase.cc:371
void BLI_rcti_init(struct rcti *rect, int xmin, int xmax, int ymin, int ymax)
Definition rct.cc:414
#define STRNCPY_UTF8(dst, src)
#define CLAMP_MAX(a, c)
#define BLT_I18NCONTEXT_DEFAULT_BPYRNA
#define HEADERY
@ AREA_FLAG_REGION_SIZE_UPDATE
#define AREAMINX
@ RGN_ALIGN_FLOAT
@ RGN_TYPE_WINDOW
@ RGN_TYPE_HUD
@ RGN_FLAG_DYNAMIC_SIZE
@ RGN_FLAG_SIZE_CLAMP_X
@ RGN_FLAG_HIDDEN
@ RGN_FLAG_SIZE_CLAMP_Y
@ RGN_FLAG_TOO_SMALL
@ RGN_FLAG_TEMP_REGIONDATA
@ RGN_FLAG_HIDDEN_BY_USER
#define UI_SCALE_FAC
void ED_area_tag_redraw(ScrArea *area)
Definition area.cc:693
void ED_region_floating_init(ARegion *region)
Definition area.cc:2301
void ED_area_tag_region_size_update(ScrArea *area, ARegion *changed_region)
Definition area.cc:729
void ED_area_update_region_sizes(wmWindowManager *wm, wmWindow *win, ScrArea *area)
Definition area.cc:2046
void ED_region_panels_layout(const bContext *C, ARegion *region)
Definition area.cc:3519
void ED_region_panels_init(wmWindowManager *wm, ARegion *region)
Definition area.cc:3616
void ED_region_tag_redraw(ARegion *region)
Definition area.cc:618
@ ED_KEYMAP_UI
Definition ED_screen.hh:758
@ ED_KEYMAP_VIEW2D
Definition ED_screen.hh:761
void ED_region_panels_draw(const bContext *C, ARegion *region)
Definition area.cc:3529
void GPU_clear_color(float red, float green, float blue, float alpha)
Read Guarded memory(de)allocation.
#define MEM_SAFE_FREE(v)
#define C
Definition RandGen.cpp:29
void UI_panel_drawname_set(Panel *panel, blender::StringRef name)
void uiTemplateOperatorRedoProperties(uiLayout *layout, const bContext *C)
void UI_region_handlers_add(ListBase *handlers)
void UI_view2d_view_restore(const bContext *C)
Definition view2d.cc:1162
void UI_view2d_region_reinit(View2D *v2d, short type, int winx, int winy)
Definition view2d.cc:221
void UI_view2d_view_ortho(const View2D *v2d)
Definition view2d.cc:1095
void UI_view2d_scroller_size_get(const View2D *v2d, bool mapped, float *r_x, float *r_y)
Definition view2d.cc:1887
@ V2D_COMMONVIEW_LIST
Definition UI_view2d.hh:35
#define NC_WM
Definition WM_types.hh:374
#define ND_HISTORY
Definition WM_types.hh:415
uint col
void ui_draw_menu_back(uiStyle *style, uiBlock *block, const rcti *rect)
ARegionType * ED_area_type_hud(int space_type)
static void hud_region_draw(const bContext *C, ARegion *region)
ARegion * ED_area_type_hud_redo_region_find(const ScrArea *area, const ARegion *hud_region)
static void hud_panels_register(ARegionType *art, int space_type, int region_type)
static ARegion * area_find_region_by_type_and_index_hint(const ScrArea *area, const short region_type, int index_hint)
static int area_calc_region_type_index(const ScrArea *area, const ARegion *region)
static void hud_region_listener(const wmRegionListenerParams *params)
static ARegion * hud_region_add(ScrArea *area)
static void hud_region_layout(const bContext *C, ARegion *region)
static bool hud_panel_operator_redo_poll(const bContext *C, PanelType *)
static bool last_redo_poll(const bContext *C, short region_type, int region_index_hint)
static void hud_region_free(ARegion *region)
static void hud_region_hide(ARegion *region)
static void hud_region_init(wmWindowManager *wm, ARegion *region)
void ED_area_type_hud_clear(wmWindowManager *wm, ScrArea *area_keep)
static void hud_panel_operator_redo_draw_header(const bContext *C, Panel *panel)
static void hud_panel_operator_redo_draw(const bContext *C, Panel *panel)
void ED_area_type_hud_ensure(bContext *C, ScrArea *area)
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
void * MEM_callocN(size_t len, const char *str)
Definition mallocn.cc:118
static void init(bNodeTree *, bNode *node)
void(* free)(ARegion *)
void(* listener)(const wmRegionListenerParams *params)
void(* draw)(const bContext *C, ARegion *region)
void(* layout)(const bContext *C, ARegion *region)
ListBase paneltypes
void(* init)(wmWindowManager *wm, ARegion *region)
void * regiondata
ARegionRuntimeHandle * runtime
ListBase panels
void * first
void(* draw)(const bContext *C, Panel *panel)
short region_type
char idname[BKE_ST_MAXNAME]
bool(* poll)(const bContext *C, PanelType *pt)
short space_type
char translation_context[BKE_ST_MAXNAME]
char label[BKE_ST_MAXNAME]
void(* draw_header)(const bContext *C, Panel *panel)
struct uiLayout * layout
struct SpaceType * type
ListBase regionbase
float minzoom
float maxzoom
ListBase areabase
float xmax
float ymax
int ymin
int ymax
int xmin
int xmax
uiLayout & column(bool align)
void enabled_set(bool enabled)
unsigned int data
Definition WM_types.hh:358
unsigned int category
Definition WM_types.hh:358
const char * name
Definition WM_types.hh:1033
struct wmOperatorType * type
struct PointerRNA * ptr
#define N_(msgid)
bool WM_operator_ui_poll(wmOperatorType *ot, PointerRNA *ptr)
bool WM_operator_poll(bContext *C, wmOperatorType *ot)
bool WM_operator_repeat_check(const bContext *, wmOperator *op)
std::string WM_operatortype_name(wmOperatorType *ot, PointerRNA *properties)
bool WM_operator_check_ui_enabled(const bContext *C, const char *idname)
wmOperator * WM_operator_last_redo(const bContext *C)
void wmOrtho2_region_pixelspace(const ARegion *region)
bScreen * WM_window_get_active_screen(const wmWindow *win)