Blender V4.3
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
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.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
29#include "UI_interface.hh"
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/* -------------------------------------------------------------------- */
44 short regionid;
45};
46
47static bool last_redo_poll(const bContext *C, short region_type)
48{
50 if (op == nullptr) {
51 return false;
52 }
53
54 bool success = false;
55 {
56 /* Make sure that we are using the same region type as the original
57 * operator call. Otherwise we would be polling the operator with the
58 * wrong context.
59 */
60 ScrArea *area = CTX_wm_area(C);
61 ARegion *region_op = (region_type != -1) ? BKE_area_find_region_type(area, region_type) :
62 nullptr;
63 ARegion *region_prev = CTX_wm_region(C);
64 CTX_wm_region_set((bContext *)C, region_op);
65
66 if (WM_operator_repeat_check(C, op) && WM_operator_ui_poll(op->type, op->ptr)) {
67 success = WM_operator_poll((bContext *)C, op->type);
68 }
69 CTX_wm_region_set((bContext *)C, region_prev);
70 }
71 return success;
72}
73
74static void hud_region_hide(ARegion *region)
75{
76 region->flag |= RGN_FLAG_HIDDEN;
77 /* Avoids setting 'AREA_FLAG_REGION_SIZE_UPDATE'
78 * since other regions don't depend on this. */
79 BLI_rcti_init(&region->winrct, 0, 0, 0, 0);
80}
81
84/* -------------------------------------------------------------------- */
88static bool hud_panel_operator_redo_poll(const bContext *C, PanelType * /*pt*/)
89{
90 ScrArea *area = CTX_wm_area(C);
92 if (region != nullptr) {
93 HudRegionData *hrd = static_cast<HudRegionData *>(region->regiondata);
94 if (hrd != nullptr) {
95 return last_redo_poll(C, hrd->regionid);
96 }
97 }
98 return false;
99}
100
102{
104 const std::string opname = WM_operatortype_name(op->type, op->ptr);
105 UI_panel_drawname_set(panel, opname);
106}
107
108static void hud_panel_operator_redo_draw(const bContext *C, Panel *panel)
109{
111 if (op == nullptr) {
112 return;
113 }
114 if (!WM_operator_check_ui_enabled(C, op->type->name)) {
115 uiLayoutSetEnabled(panel->layout, false);
116 }
117 uiLayout *col = uiLayoutColumn(panel->layout, false);
119}
120
121static void hud_panels_register(ARegionType *art, int space_type, int region_type)
122{
123 PanelType *pt = MEM_cnew<PanelType>(__func__);
124 STRNCPY(pt->idname, "OPERATOR_PT_redo");
125 STRNCPY(pt->label, N_("Redo"));
130 pt->space_type = space_type;
131 pt->region_type = region_type;
133 BLI_addtail(&art->paneltypes, pt);
134}
135
138/* -------------------------------------------------------------------- */
142static void hud_region_init(wmWindowManager *wm, ARegion *region)
143{
144 ED_region_panels_init(wm, region);
145
146 /* Reset zoom from panels init because we don't want zoom allowed for redo panel. */
147 region->v2d.maxzoom = 1.0f;
148 region->v2d.minzoom = 1.0f;
149
150 UI_region_handlers_add(&region->handlers);
151 region->flag |= RGN_FLAG_TEMP_REGIONDATA;
152}
153
154static void hud_region_free(ARegion *region)
155{
156 MEM_SAFE_FREE(region->regiondata);
157}
158
159static void hud_region_layout(const bContext *C, ARegion *region)
160{
161 HudRegionData *hrd = static_cast<HudRegionData *>(region->regiondata);
162 if (hrd == nullptr || !last_redo_poll(C, hrd->regionid)) {
163 ED_region_tag_redraw(region);
164 hud_region_hide(region);
165 return;
166 }
167
168 ScrArea *area = CTX_wm_area(C);
169 const int size_y = region->sizey;
170
171 ED_region_panels_layout(C, region);
172
173 if (region->panels.first &&
174 ((area->flag & AREA_FLAG_REGION_SIZE_UPDATE) || (region->sizey != size_y)))
175 {
176 int winx_new = UI_SCALE_FAC * (region->sizex + 0.5f);
177 int winy_new = UI_SCALE_FAC * (region->sizey + 0.5f);
178 View2D *v2d = &region->v2d;
179
180 if (region->flag & RGN_FLAG_SIZE_CLAMP_X) {
181 CLAMP_MAX(winx_new, region->winx);
182 }
183 if (region->flag & RGN_FLAG_SIZE_CLAMP_Y) {
184 CLAMP_MAX(winy_new, region->winy);
185 }
186
187 region->winx = winx_new;
188 region->winy = winy_new;
189
190 region->winrct.xmax = (region->winrct.xmin + region->winx) - 1;
191 region->winrct.ymax = (region->winrct.ymin + region->winy) - 1;
192
193 UI_view2d_region_reinit(v2d, V2D_COMMONVIEW_LIST, region->winx, region->winy);
194
195 /* Weak, but needed to avoid glitches, especially with hi-dpi
196 * (where resizing the view glitches often).
197 * Fortunately this only happens occasionally. */
198 ED_region_panels_layout(C, region);
199 }
200
201 /* restore view matrix */
203}
204
205static void hud_region_draw(const bContext *C, ARegion *region)
206{
207 UI_view2d_view_ortho(&region->v2d);
209 GPU_clear_color(0.0f, 0.0f, 0.0f, 0.0f);
210
211 if ((region->flag & RGN_FLAG_HIDDEN) == 0) {
212 rcti reset_rect = {};
213 reset_rect.xmax = region->winx;
214 reset_rect.ymax = region->winy;
215 ui_draw_menu_back(nullptr, nullptr, &reset_rect);
216 ED_region_panels_draw(C, region);
217 }
218}
219
221{
222 ARegionType *art = MEM_cnew<ARegionType>(__func__);
223 art->regionid = RGN_TYPE_HUD;
226 art->draw = hud_region_draw;
227 art->init = hud_region_init;
228 art->free = hud_region_free;
229
230 /* We need to indicate a preferred size to avoid false `RGN_FLAG_TOO_SMALL`
231 * the first time the region is created. */
232 art->prefsizex = AREAMINX;
233 art->prefsizey = HEADERY;
234
235 hud_panels_register(art, space_type, art->regionid);
236
237 art->lock = 1; /* can become flag, see BKE_spacedata_draw_locks */
238 return art;
239}
240
242{
243 ARegion *region = MEM_cnew<ARegion>(__func__);
245 if (region_win) {
246 BLI_insertlinkbefore(&area->regionbase, region_win, region);
247 }
248 else {
249 BLI_addtail(&area->regionbase, region);
250 }
251 region->regiontype = RGN_TYPE_HUD;
252 region->alignment = RGN_ALIGN_FLOAT;
253 region->overlap = true;
254 region->flag |= RGN_FLAG_DYNAMIC_SIZE;
255
256 return region;
257}
258
260{
261 LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
263 LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
264 if (area != area_keep) {
265 LISTBASE_FOREACH (ARegion *, region, &area->regionbase) {
266 if (region->regiontype == RGN_TYPE_HUD) {
267 if ((region->flag & RGN_FLAG_HIDDEN) == 0) {
268 hud_region_hide(region);
269 ED_region_tag_redraw(region);
270 ED_area_tag_redraw(area);
271 }
272 }
273 }
274 }
275 }
276 }
277}
278
280{
282 ED_area_type_hud_clear(wm, area);
283
285 if (art == nullptr) {
286 return;
287 }
288
290
291 if (region && (region->flag & RGN_FLAG_HIDDEN_BY_USER)) {
292 /* The region is intentionally hidden by the user, don't show it. */
293 hud_region_hide(region);
294 return;
295 }
296
297 bool init = false;
298 const bool was_hidden = region == nullptr || region->visible == false;
299 ARegion *region_op = CTX_wm_region(C);
300 BLI_assert((region_op == nullptr) || (region_op->regiontype != RGN_TYPE_HUD));
301 if (!last_redo_poll(C, region_op ? region_op->regiontype : -1)) {
302 if (region) {
303 ED_region_tag_redraw(region);
304 hud_region_hide(region);
305 }
306 return;
307 }
308
309 if (region == nullptr) {
310 init = true;
311 region = hud_region_add(area);
312 region->type = art;
313 }
314
315 /* Let 'ED_area_update_region_sizes' do the work of placing the region.
316 * Otherwise we could set the 'region->winrct' & 'region->winx/winy' here. */
317 if (init) {
318 ED_area_tag_region_size_update(area, region);
319 }
320 else {
321 if (region->flag & RGN_FLAG_HIDDEN) {
322 /* Also forces recalculating HUD size in hud_region_layout(). */
323 ED_area_tag_region_size_update(area, region);
324 }
325 region->flag &= ~RGN_FLAG_HIDDEN;
326 }
327
328 {
329 HudRegionData *hrd = static_cast<HudRegionData *>(region->regiondata);
330 if (hrd == nullptr) {
331 hrd = MEM_cnew<HudRegionData>(__func__);
332 region->regiondata = hrd;
333 }
334 if (region_op) {
335 hrd->regionid = region_op->regiontype;
336 }
337 else {
338 hrd->regionid = -1;
339 }
340 }
341
342 if (init) {
343 /* This is needed or 'winrct' will be invalid. */
344 wmWindow *win = CTX_wm_window(C);
345 ED_area_update_region_sizes(wm, win, area);
346 }
347
349 ED_region_tag_redraw(region);
350
351 /* We need to update/initialize the runtime offsets. */
353 if (region_win) {
354 float x, y;
355
356 UI_view2d_scroller_size_get(&region_win->v2d, true, &x, &y);
357 region->runtime.offset_x = x;
358 region->runtime.offset_y = y;
359 }
360
361 /* Reset zoom level (not well supported). */
362 rctf reset_rect = {};
363 reset_rect.xmax = region->winx;
364 reset_rect.ymax = region->winy;
365 region->v2d.cur = region->v2d.tot = reset_rect;
366 region->v2d.minzoom = 1.0f;
367 region->v2d.maxzoom = 1.0f;
368
369 region->visible = !(region->flag & RGN_FLAG_HIDDEN);
370
371 /* We shouldn't need to do this every time :S */
372 /* XXX, this is evil! - it also makes the menu show on first draw. :( */
373 if (region->visible) {
374 ARegion *region_prev = CTX_wm_region(C);
375 CTX_wm_region_set((bContext *)C, region);
376 hud_region_layout(C, region);
377 if (was_hidden) {
378 region->winx = region->v2d.winx;
379 region->winy = region->v2d.winy;
380 region->v2d.cur = region->v2d.tot = reset_rect;
381 }
382 CTX_wm_region_set((bContext *)C, region_prev);
383 }
384
385 region->visible = !((region->flag & RGN_FLAG_HIDDEN) || (region->flag & RGN_FLAG_TOO_SMALL));
386}
387
389{
390 BLI_assert(hud_region->regiontype == RGN_TYPE_HUD);
391 HudRegionData *hrd = static_cast<HudRegionData *>(hud_region->regiondata);
392
393 if (hrd->regionid == -1) {
394 return nullptr;
395 }
396
397 return BKE_area_find_region_type(area, hrd->regionid);
398}
399
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)
ARegionType * BKE_regiontype_from_id(const SpaceType *st, int regionid)
Definition screen.cc:253
ARegion * BKE_area_find_region_type(const ScrArea *area, int region_type)
Definition screen.cc:815
@ PANEL_TYPE_DEFAULT_CLOSED
#define BLI_assert(a)
Definition BLI_assert.h:50
#define LISTBASE_FOREACH(type, var, list)
void BLI_addtail(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:110
void BLI_insertlinkbefore(struct ListBase *listbase, void *vnextlink, void *vnewlink) ATTR_NONNULL(1)
Definition listbase.cc:370
void BLI_rcti_init(struct rcti *rect, int xmin, int xmax, int ymin, int ymax)
Definition rct.c:418
#define STRNCPY(dst, src)
Definition BLI_string.h:593
#define CLAMP_MAX(a, c)
#define BLT_I18NCONTEXT_DEFAULT_BPYRNA
#define HEADERY
@ AREA_FLAG_REGION_SIZE_UPDATE
@ RGN_ALIGN_FLOAT
#define AREAMINX
@ 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:708
void ED_region_floating_init(ARegion *region)
Definition area.cc:2206
void ED_area_tag_region_size_update(ScrArea *area, ARegion *changed_region)
Definition area.cc:744
void ED_area_update_region_sizes(wmWindowManager *wm, wmWindow *win, ScrArea *area)
Definition area.cc:1959
void ED_region_panels_layout(const bContext *C, ARegion *region)
Definition area.cc:3271
void ED_region_panels_init(wmWindowManager *wm, ARegion *region)
Definition area.cc:3343
void ED_region_tag_redraw(ARegion *region)
Definition area.cc:634
@ ED_KEYMAP_UI
Definition ED_screen.hh:725
@ ED_KEYMAP_VIEW2D
Definition ED_screen.hh:728
void ED_region_panels_draw(const bContext *C, ARegion *region)
Definition area.cc:3277
void GPU_clear_color(float red, float green, float blue, float alpha)
Read Guarded memory(de)allocation.
#define MEM_SAFE_FREE(v)
void uiLayoutSetEnabled(uiLayout *layout, bool enabled)
void UI_panel_drawname_set(Panel *panel, blender::StringRef name)
void uiTemplateOperatorRedoProperties(uiLayout *layout, const bContext *C)
uiLayout * uiLayoutColumn(uiLayout *layout, bool align)
void UI_region_handlers_add(ListBase *handlers)
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_view_ortho(const View2D *v2d)
Definition view2d.cc:1091
void UI_view2d_scroller_size_get(const View2D *v2d, bool mapped, float *r_x, float *r_y)
Definition view2d.cc:1882
@ V2D_COMMONVIEW_LIST
Definition UI_view2d.hh:35
void init()
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 * 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 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 bool last_redo_poll(const bContext *C, short region_type)
static void hud_panel_operator_redo_draw(const bContext *C, Panel *panel)
void ED_area_type_hud_ensure(bContext *C, ScrArea *area)
void(* free)(ARegion *)
void(* draw)(const bContext *C, ARegion *region)
void(* layout)(const bContext *C, ARegion *region)
ListBase paneltypes
void(* init)(wmWindowManager *wm, ARegion *region)
void * regiondata
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
float xmax
float ymax
int ymax
int xmax
const char * name
Definition WM_types.hh:990
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)