Blender V4.3
screen_geometry.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
13#include "BLI_listbase.h"
14#include "BLI_math_vector.h"
15#include "BLI_rect.h"
16
17#include "BKE_screen.hh"
18
19#include "DNA_screen_types.h"
21
22#include "ED_screen.hh"
23
24#include "MEM_guardedalloc.h"
25
26#include "WM_api.hh"
27
28#include "screen_intern.hh"
29
31{
32 return area->v2->vec.y - area->v1->vec.y + 1;
33}
35{
36 return area->v4->vec.x - area->v1->vec.x + 1;
37}
38
39ScrVert *screen_geom_vertex_add_ex(ScrAreaMap *area_map, short x, short y)
40{
41 ScrVert *sv = static_cast<ScrVert *>(MEM_callocN(sizeof(ScrVert), "addscrvert"));
42 sv->vec.x = x;
43 sv->vec.y = y;
44
45 BLI_addtail(&area_map->vertbase, sv);
46 return sv;
47}
48ScrVert *screen_geom_vertex_add(bScreen *screen, short x, short y)
49{
51}
52
54{
55 ScrEdge *se = static_cast<ScrEdge *>(MEM_callocN(sizeof(ScrEdge), "addscredge"));
56
58 se->v1 = v1;
59 se->v2 = v2;
60
61 BLI_addtail(&area_map->edgebase, se);
62 return se;
63}
68
70{
71 return (se->v1->vec.y == se->v2->vec.y);
72}
73
75 const rcti *bounds_rect,
76 const int mx,
77 const int my)
78{
79 int safety = BORDERPADDING;
80
81 CLAMP_MIN(safety, 2);
82
83 LISTBASE_FOREACH (ScrEdge *, se, &area_map->edgebase) {
85 if ((se->v1->vec.y > bounds_rect->ymin) && (se->v1->vec.y < (bounds_rect->ymax - 1))) {
86 short min, max;
87 min = std::min(se->v1->vec.x, se->v2->vec.x);
88 max = std::max(se->v1->vec.x, se->v2->vec.x);
89
90 if (abs(my - se->v1->vec.y) <= safety && mx >= min && mx <= max) {
91 return se;
92 }
93 }
94 }
95 else {
96 if ((se->v1->vec.x > bounds_rect->xmin) && (se->v1->vec.x < (bounds_rect->xmax - 1))) {
97 short min, max;
98 min = std::min(se->v1->vec.y, se->v2->vec.y);
99 max = std::max(se->v1->vec.y, se->v2->vec.y);
100
101 if (abs(mx - se->v1->vec.x) <= safety && my >= min && my <= max) {
102 return se;
103 }
104 }
105 }
106 }
107
108 return nullptr;
109}
110
112 const bScreen *screen,
113 const int mx,
114 const int my)
115{
116 if (U.app_flag & USER_APP_LOCK_EDGE_RESIZE) {
117 return nullptr;
118 }
119
120 /* Use layout size (screen excluding global areas) for screen-layout area edges */
121 rcti screen_rect;
122 WM_window_screen_rect_calc(win, &screen_rect);
124 AREAMAP_FROM_SCREEN(screen), &screen_rect, mx, my);
125
126 if (!se) {
127 /* Use entire window size (screen including global areas) for global area edges */
128 rcti win_rect;
129 WM_window_rect_calc(win, &win_rect);
130 se = screen_geom_area_map_find_active_scredge(&win->global_areas, &win_rect, mx, my);
131 }
132 return se;
133}
134
140 const bScreen *screen,
141 const rcti *screen_rect)
142{
143
144 const int screen_size_x = BLI_rcti_size_x(screen_rect);
145 const int screen_size_y = BLI_rcti_size_y(screen_rect);
146 bool needs_another_pass = false;
147
148 /* calculate size */
149 float min[2] = {20000.0f, 20000.0f};
150 float max[2] = {0.0f, 0.0f};
151
152 LISTBASE_FOREACH (ScrVert *, sv, &screen->vertbase) {
153 const float fv[2] = {float(sv->vec.x), float(sv->vec.y)};
154 minmax_v2v2_v2(min, max, fv);
155 }
156
157 int screen_size_x_prev = (max[0] - min[0]) + 1;
158 int screen_size_y_prev = (max[1] - min[1]) + 1;
159
160 if (screen_size_x_prev != screen_size_x || screen_size_y_prev != screen_size_y) {
161 const float facx = (float(screen_size_x) - 1) / (float(screen_size_x_prev) - 1);
162 const float facy = (float(screen_size_y) - 1) / (float(screen_size_y_prev) - 1);
163
164 /* make sure it fits! */
165 LISTBASE_FOREACH (ScrVert *, sv, &screen->vertbase) {
166 sv->vec.x = screen_rect->xmin + round_fl_to_short((sv->vec.x - min[0]) * facx);
167 CLAMP(sv->vec.x, screen_rect->xmin, screen_rect->xmax - 1);
168
169 sv->vec.y = screen_rect->ymin + round_fl_to_short((sv->vec.y - min[1]) * facy);
170 CLAMP(sv->vec.y, screen_rect->ymin, screen_rect->ymax - 1);
171 }
172
173 /* test for collapsed areas. This could happen in some blender version... */
174 /* ton: removed option now, it needs Context... */
175
176 int headery = ED_area_headersize() + (U.pixelsize * 2);
177
178 if (facy > 1) {
179 /* Keep timeline small in video edit workspace. */
180 LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
181 if (area->spacetype == SPACE_ACTION && area->v1->vec.y == screen_rect->ymin &&
182 screen_geom_area_height(area) <= headery * facy + 1)
183 {
184 ScrEdge *se = BKE_screen_find_edge(screen, area->v2, area->v3);
185 if (se) {
186 const int yval = area->v1->vec.y + headery - 1;
187
189
190 /* all selected vertices get the right offset */
191 LISTBASE_FOREACH (ScrVert *, sv, &screen->vertbase) {
192 /* if is a collapsed area */
193 if (!ELEM(sv, area->v1, area->v4)) {
194 if (sv->flag) {
195 sv->vec.y = yval;
196 /* Changed size of a area. Run another pass to ensure everything still fits. */
197 needs_another_pass = true;
198 }
199 }
200 }
201 }
202 }
203 }
204 }
205 if (facy < 1) {
206 /* make each window at least ED_area_headersize() high */
207 LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
208 if (screen_geom_area_height(area) < headery) {
209 /* lower edge */
210 ScrEdge *se = BKE_screen_find_edge(screen, area->v4, area->v1);
211 if (se && area->v1 != area->v2) {
212 const int yval = area->v2->vec.y - headery + 1;
213
215
216 /* all selected vertices get the right offset */
217 LISTBASE_FOREACH (ScrVert *, sv, &screen->vertbase) {
218 /* if is not a collapsed area */
219 if (!ELEM(sv, area->v2, area->v3)) {
220 if (sv->flag) {
221 sv->vec.y = yval;
222 /* Changed size of a area. Run another pass to ensure everything still fits. */
223 needs_another_pass = true;
224 }
225 }
226 }
227 }
228 }
229 }
230 }
231 }
232
233 return needs_another_pass;
234}
235
237{
238 rcti window_rect, screen_rect;
239 WM_window_rect_calc(win, &window_rect);
240 WM_window_screen_rect_calc(win, &screen_rect);
241
242 bool needs_another_pass;
243 int max_passes_left = 10; /* Avoids endless loop. Number is rather arbitrary. */
244 do {
245 needs_another_pass = screen_geom_vertices_scale_pass(win, screen, &screen_rect);
246 max_passes_left--;
247 } while (needs_another_pass && (max_passes_left > 0));
248
249 /* Global areas have a fixed size that only changes with the DPI.
250 * Here we ensure that exactly this size is set. */
252 if (area->global->flag & GLOBAL_AREA_IS_HIDDEN) {
253 continue;
254 }
255
256 int height = ED_area_global_size_y(area) - 1;
257
258 if (area->v1->vec.y > window_rect.ymin) {
259 height += U.pixelsize;
260 }
261 if (area->v2->vec.y < (window_rect.ymax - 1)) {
262 height += U.pixelsize;
263 }
264
265 /* width */
266 area->v1->vec.x = area->v2->vec.x = window_rect.xmin;
267 area->v3->vec.x = area->v4->vec.x = window_rect.xmax - 1;
268 /* height */
269 area->v1->vec.y = area->v4->vec.y = window_rect.ymin;
270 area->v2->vec.y = area->v3->vec.y = window_rect.ymax - 1;
271
272 switch (area->global->align) {
274 area->v1->vec.y = area->v4->vec.y = area->v2->vec.y - height;
275 break;
277 area->v2->vec.y = area->v3->vec.y = area->v1->vec.y + height;
278 break;
279 }
280 }
281}
282
284 const rcti *window_rect,
285 const eScreenAxis dir_axis,
286 float fac)
287{
288 const int cur_area_width = screen_geom_area_width(area);
289 const int cur_area_height = screen_geom_area_height(area);
290 const short area_min_x = AREAMINX * UI_SCALE_FAC;
291 const short area_min_y = ED_area_headersize();
292
293 /* area big enough? */
294 if (dir_axis == SCREEN_AXIS_V) {
295 if (cur_area_width <= 2 * area_min_x) {
296 return 0;
297 }
298 }
299 else if (dir_axis == SCREEN_AXIS_H) {
300 if (cur_area_height <= 2 * area_min_y) {
301 return 0;
302 }
303 }
304
305 /* to be sure */
306 CLAMP(fac, 0.0f, 1.0f);
307
308 if (dir_axis == SCREEN_AXIS_H) {
309 short y = area->v1->vec.y + round_fl_to_short(fac * cur_area_height);
310
311 int area_min = area_min_y;
312
313 if (area->v1->vec.y > window_rect->ymin) {
314 area_min += U.pixelsize;
315 }
316 if (area->v2->vec.y < (window_rect->ymax - 1)) {
317 area_min += U.pixelsize;
318 }
319
320 if (y - area->v1->vec.y < area_min) {
321 y = area->v1->vec.y + area_min;
322 }
323 else if (area->v2->vec.y - y < area_min) {
324 y = area->v2->vec.y - area_min;
325 }
326
327 return y;
328 }
329
330 short x = area->v1->vec.x + round_fl_to_short(fac * cur_area_width);
331
332 int area_min = area_min_x;
333
334 if (area->v1->vec.x > window_rect->xmin) {
335 area_min += U.pixelsize;
336 }
337 if (area->v4->vec.x < (window_rect->xmax - 1)) {
338 area_min += U.pixelsize;
339 }
340
341 if (x - area->v1->vec.x < area_min) {
342 x = area->v1->vec.x + area_min;
343 }
344 else if (area->v4->vec.x - x < area_min) {
345 x = area->v4->vec.x - area_min;
346 }
347
348 return x;
349}
350
352{
354
355 /* 'dir_axis' is the direction of EDGE */
356 eScreenAxis dir_axis;
357 if (edge->v1->vec.x == edge->v2->vec.x) {
358 dir_axis = SCREEN_AXIS_V;
359 }
360 else {
361 dir_axis = SCREEN_AXIS_H;
362 }
363
364 ED_screen_verts_iter(win, screen, sv)
365 {
366 sv->flag = 0;
367 }
368
369 edge->v1->flag = 1;
370 edge->v2->flag = 1;
371
372 /* select connected, only in the right direction */
373 bool oneselected = true;
374 while (oneselected) {
375 oneselected = false;
376 LISTBASE_FOREACH (ScrEdge *, se, &screen->edgebase) {
377 if (se->v1->flag + se->v2->flag == 1) {
378 if (dir_axis == SCREEN_AXIS_H) {
379 if (se->v1->vec.y == se->v2->vec.y) {
380 se->v1->flag = se->v2->flag = 1;
381 oneselected = true;
382 }
383 }
384 else if (dir_axis == SCREEN_AXIS_V) {
385 if (se->v1->vec.x == se->v2->vec.x) {
386 se->v1->flag = se->v2->flag = 1;
387 oneselected = true;
388 }
389 }
390 }
391 }
392 }
393}
void BKE_screen_sort_scrvert(ScrVert **v1, ScrVert **v2)
Definition screen.cc:657
ScrEdge * BKE_screen_find_edge(const bScreen *screen, ScrVert *v1, ScrVert *v2)
Definition screen.cc:645
#define LISTBASE_FOREACH(type, var, list)
void BLI_addtail(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:110
MINLINE short round_fl_to_short(float a)
void minmax_v2v2_v2(float min[2], float max[2], const float vec[2])
BLI_INLINE int BLI_rcti_size_y(const struct rcti *rct)
Definition BLI_rect.h:193
BLI_INLINE int BLI_rcti_size_x(const struct rcti *rct)
Definition BLI_rect.h:189
#define CLAMP(a, b, c)
#define ELEM(...)
#define CLAMP_MIN(a, b)
#define AREAMAP_FROM_SCREEN(screen)
#define AREAMINX
@ GLOBAL_AREA_IS_HIDDEN
@ GLOBAL_AREA_ALIGN_BOTTOM
@ GLOBAL_AREA_ALIGN_TOP
@ SPACE_ACTION
#define UI_SCALE_FAC
@ USER_APP_LOCK_EDGE_RESIZE
int ED_area_global_size_y(const ScrArea *area)
Definition area.cc:3677
#define ED_screen_verts_iter(win, screen, vert_name)
Definition ED_screen.hh:284
int ED_area_headersize()
Definition area.cc:3666
Read Guarded memory(de)allocation.
ATTR_WARN_UNUSED_RESULT const BMVert * v2
unsigned int U
Definition btGjkEpa3.h:78
draw_view in_light_buf[] float
void *(* MEM_callocN)(size_t len, const char *str)
Definition mallocn.cc:42
ScrVert * screen_geom_vertex_add(bScreen *screen, short x, short y)
ScrEdge * screen_geom_edge_add_ex(ScrAreaMap *area_map, ScrVert *v1, ScrVert *v2)
ScrVert * screen_geom_vertex_add_ex(ScrAreaMap *area_map, short x, short y)
ScrEdge * screen_geom_area_map_find_active_scredge(const ScrAreaMap *area_map, const rcti *bounds_rect, const int mx, const int my)
ScrEdge * screen_geom_find_active_scredge(const wmWindow *win, const bScreen *screen, const int mx, const int my)
ScrEdge * screen_geom_edge_add(bScreen *screen, ScrVert *v1, ScrVert *v2)
void screen_geom_select_connected_edge(const wmWindow *win, ScrEdge *edge)
bool screen_geom_edge_is_horizontal(ScrEdge *se)
static bool screen_geom_vertices_scale_pass(const wmWindow *win, const bScreen *screen, const rcti *screen_rect)
int screen_geom_area_width(const ScrArea *area)
int screen_geom_area_height(const ScrArea *area)
void screen_geom_vertices_scale(const wmWindow *win, bScreen *screen)
Main screen-layout calculation function.
short screen_geom_find_area_split_point(const ScrArea *area, const rcti *window_rect, const eScreenAxis dir_axis, float fac)
#define BORDERPADDING
eScreenAxis
@ SCREEN_AXIS_V
@ SCREEN_AXIS_H
#define min(a, b)
Definition sort.c:32
ListBase vertbase
ListBase edgebase
ListBase areabase
ScrVert * v1
ScrVert * v2
int ymin
int ymax
int xmin
int xmax
short y
short x
ScrAreaMap global_areas
float max
ccl_device_inline int abs(int x)
Definition util/math.h:120
void WM_window_rect_calc(const wmWindow *win, rcti *r_rect)
void WM_window_screen_rect_calc(const wmWindow *win, rcti *r_rect)
bScreen * WM_window_get_active_screen(const wmWindow *win)