Blender  V2.93
screen_geometry.c
Go to the documentation of this file.
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  */
16 
25 #include "BLI_listbase.h"
26 #include "BLI_math.h"
27 #include "BLI_rect.h"
28 
29 #include "BKE_screen.h"
30 
31 #include "DNA_screen_types.h"
33 
34 #include "ED_screen.h"
35 
36 #include "MEM_guardedalloc.h"
37 
38 #include "WM_api.h"
39 
40 #include "screen_intern.h"
41 
43 {
44  return area->v2->vec.y - area->v1->vec.y + 1;
45 }
47 {
48  return area->v4->vec.x - area->v1->vec.x + 1;
49 }
50 
51 ScrVert *screen_geom_vertex_add_ex(ScrAreaMap *area_map, short x, short y)
52 {
53  ScrVert *sv = MEM_callocN(sizeof(ScrVert), "addscrvert");
54  sv->vec.x = x;
55  sv->vec.y = y;
56 
57  BLI_addtail(&area_map->vertbase, sv);
58  return sv;
59 }
60 ScrVert *screen_geom_vertex_add(bScreen *screen, short x, short y)
61 {
63 }
64 
66 {
67  ScrEdge *se = MEM_callocN(sizeof(ScrEdge), "addscredge");
68 
70  se->v1 = v1;
71  se->v2 = v2;
72 
73  BLI_addtail(&area_map->edgebase, se);
74  return se;
75 }
77 {
79 }
80 
82 {
83  return (se->v1->vec.y == se->v2->vec.y);
84 }
85 
91  const rcti *bounds_rect,
92  const int mx,
93  const int my)
94 {
95  int safety = BORDERPADDING;
96 
97  CLAMP_MIN(safety, 2);
98 
99  LISTBASE_FOREACH (ScrEdge *, se, &area_map->edgebase) {
101  if ((se->v1->vec.y > bounds_rect->ymin) && (se->v1->vec.y < (bounds_rect->ymax - 1))) {
102  short min, max;
103  min = MIN2(se->v1->vec.x, se->v2->vec.x);
104  max = MAX2(se->v1->vec.x, se->v2->vec.x);
105 
106  if (abs(my - se->v1->vec.y) <= safety && mx >= min && mx <= max) {
107  return se;
108  }
109  }
110  }
111  else {
112  if ((se->v1->vec.x > bounds_rect->xmin) && (se->v1->vec.x < (bounds_rect->xmax - 1))) {
113  short min, max;
114  min = MIN2(se->v1->vec.y, se->v2->vec.y);
115  max = MAX2(se->v1->vec.y, se->v2->vec.y);
116 
117  if (abs(mx - se->v1->vec.x) <= safety && my >= min && my <= max) {
118  return se;
119  }
120  }
121  }
122  }
123 
124  return NULL;
125 }
126 
127 /* need win size to make sure not to include edges along screen edge */
129  const bScreen *screen,
130  const int mx,
131  const int my)
132 {
133  /* Use layout size (screen excluding global areas) for screen-layout area edges */
134  rcti screen_rect;
135  WM_window_screen_rect_calc(win, &screen_rect);
137  AREAMAP_FROM_SCREEN(screen), &screen_rect, mx, my);
138 
139  if (!se) {
140  /* Use entire window size (screen including global areas) for global area edges */
141  rcti win_rect;
142  WM_window_rect_calc(win, &win_rect);
143  se = screen_geom_area_map_find_active_scredge(&win->global_areas, &win_rect, mx, my);
144  }
145  return se;
146 }
147 
153  const bScreen *screen,
154  const rcti *screen_rect)
155 {
156 
157  const int screen_size_x = BLI_rcti_size_x(screen_rect);
158  const int screen_size_y = BLI_rcti_size_y(screen_rect);
159  bool needs_another_pass = false;
160 
161  /* calculate size */
162  float min[2] = {20000.0f, 20000.0f};
163  float max[2] = {0.0f, 0.0f};
164 
165  LISTBASE_FOREACH (ScrVert *, sv, &screen->vertbase) {
166  const float fv[2] = {(float)sv->vec.x, (float)sv->vec.y};
167  minmax_v2v2_v2(min, max, fv);
168  }
169 
170  int screen_size_x_prev = (max[0] - min[0]) + 1;
171  int screen_size_y_prev = (max[1] - min[1]) + 1;
172 
173  if (screen_size_x_prev != screen_size_x || screen_size_y_prev != screen_size_y) {
174  const float facx = ((float)screen_size_x - 1) / ((float)screen_size_x_prev - 1);
175  const float facy = ((float)screen_size_y - 1) / ((float)screen_size_y_prev - 1);
176 
177  /* make sure it fits! */
178  LISTBASE_FOREACH (ScrVert *, sv, &screen->vertbase) {
179  sv->vec.x = screen_rect->xmin + round_fl_to_short((sv->vec.x - min[0]) * facx);
180  CLAMP(sv->vec.x, screen_rect->xmin, screen_rect->xmax - 1);
181 
182  sv->vec.y = screen_rect->ymin + round_fl_to_short((sv->vec.y - min[1]) * facy);
183  CLAMP(sv->vec.y, screen_rect->ymin, screen_rect->ymax - 1);
184  }
185 
186  /* test for collapsed areas. This could happen in some blender version... */
187  /* ton: removed option now, it needs Context... */
188 
189  int headery = ED_area_headersize() + (U.pixelsize * 2);
190 
191  if (facy > 1) {
192  /* Keep timeline small in video edit workspace. */
193  LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
194  if (area->spacetype == SPACE_ACTION && area->v1->vec.y == screen_rect->ymin &&
195  screen_geom_area_height(area) <= headery * facy + 1) {
196  ScrEdge *se = BKE_screen_find_edge(screen, area->v2, area->v3);
197  if (se) {
198  const int yval = area->v1->vec.y + headery - 1;
199 
201 
202  /* all selected vertices get the right offset */
203  LISTBASE_FOREACH (ScrVert *, sv, &screen->vertbase) {
204  /* if is a collapsed area */
205  if (!ELEM(sv, area->v1, area->v4)) {
206  if (sv->flag) {
207  sv->vec.y = yval;
208  /* Changed size of a area. Run another pass to ensure everything still fits. */
209  needs_another_pass = true;
210  }
211  }
212  }
213  }
214  }
215  }
216  }
217  if (facy < 1) {
218  /* make each window at least ED_area_headersize() high */
219  LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
220  if (screen_geom_area_height(area) < headery) {
221  /* lower edge */
222  ScrEdge *se = BKE_screen_find_edge(screen, area->v4, area->v1);
223  if (se && area->v1 != area->v2) {
224  const int yval = area->v2->vec.y - headery + 1;
225 
227 
228  /* all selected vertices get the right offset */
229  LISTBASE_FOREACH (ScrVert *, sv, &screen->vertbase) {
230  /* if is not a collapsed area */
231  if (!ELEM(sv, area->v2, area->v3)) {
232  if (sv->flag) {
233  sv->vec.y = yval;
234  /* Changed size of a area. Run another pass to ensure everything still fits. */
235  needs_another_pass = true;
236  }
237  }
238  }
239  }
240  }
241  }
242  }
243  }
244 
245  return needs_another_pass;
246 }
247 
255 void screen_geom_vertices_scale(const wmWindow *win, bScreen *screen)
256 {
257  rcti window_rect, screen_rect;
258  WM_window_rect_calc(win, &window_rect);
259  WM_window_screen_rect_calc(win, &screen_rect);
260 
261  bool needs_another_pass;
262  int max_passes_left = 10; /* Avoids endless loop. Number is rather arbitrary. */
263  do {
264  needs_another_pass = screen_geom_vertices_scale_pass(win, screen, &screen_rect);
265  max_passes_left--;
266  } while (needs_another_pass && (max_passes_left > 0));
267 
268  /* Global areas have a fixed size that only changes with the DPI.
269  * Here we ensure that exactly this size is set. */
271  if (area->global->flag & GLOBAL_AREA_IS_HIDDEN) {
272  continue;
273  }
274 
275  int height = ED_area_global_size_y(area) - 1;
276 
277  if (area->v1->vec.y > window_rect.ymin) {
278  height += U.pixelsize;
279  }
280  if (area->v2->vec.y < (window_rect.ymax - 1)) {
281  height += U.pixelsize;
282  }
283 
284  /* width */
285  area->v1->vec.x = area->v2->vec.x = window_rect.xmin;
286  area->v3->vec.x = area->v4->vec.x = window_rect.xmax - 1;
287  /* height */
288  area->v1->vec.y = area->v4->vec.y = window_rect.ymin;
289  area->v2->vec.y = area->v3->vec.y = window_rect.ymax - 1;
290 
291  switch (area->global->align) {
293  area->v1->vec.y = area->v4->vec.y = area->v2->vec.y - height;
294  break;
296  area->v2->vec.y = area->v3->vec.y = area->v1->vec.y + height;
297  break;
298  }
299  }
300 }
301 
306  const rcti *window_rect,
307  char dir,
308  float fac)
309 {
310  const int cur_area_width = screen_geom_area_width(area);
311  const int cur_area_height = screen_geom_area_height(area);
312  const short area_min_x = AREAMINX;
313  const short area_min_y = ED_area_headersize();
314 
315  /* area big enough? */
316  if ((dir == 'v') && (cur_area_width <= 2 * area_min_x)) {
317  return 0;
318  }
319  if ((dir == 'h') && (cur_area_height <= 2 * area_min_y)) {
320  return 0;
321  }
322 
323  /* to be sure */
324  CLAMP(fac, 0.0f, 1.0f);
325 
326  if (dir == 'h') {
327  short y = area->v1->vec.y + round_fl_to_short(fac * cur_area_height);
328 
329  int area_min = area_min_y;
330 
331  if (area->v1->vec.y > window_rect->ymin) {
332  area_min += U.pixelsize;
333  }
334  if (area->v2->vec.y < (window_rect->ymax - 1)) {
335  area_min += U.pixelsize;
336  }
337 
338  if (y - area->v1->vec.y < area_min) {
339  y = area->v1->vec.y + area_min;
340  }
341  else if (area->v2->vec.y - y < area_min) {
342  y = area->v2->vec.y - area_min;
343  }
344 
345  return y;
346  }
347 
348  short x = area->v1->vec.x + round_fl_to_short(fac * cur_area_width);
349 
350  int area_min = area_min_x;
351 
352  if (area->v1->vec.x > window_rect->xmin) {
353  area_min += U.pixelsize;
354  }
355  if (area->v4->vec.x < (window_rect->xmax - 1)) {
356  area_min += U.pixelsize;
357  }
358 
359  if (x - area->v1->vec.x < area_min) {
360  x = area->v1->vec.x + area_min;
361  }
362  else if (area->v4->vec.x - x < area_min) {
363  x = area->v4->vec.x - area_min;
364  }
365 
366  return x;
367 }
368 
373 {
374  bScreen *screen = WM_window_get_active_screen(win);
375 
376  /* 'dir' is the direction of EDGE */
377  char dir;
378  if (edge->v1->vec.x == edge->v2->vec.x) {
379  dir = 'v';
380  }
381  else {
382  dir = 'h';
383  }
384 
385  ED_screen_verts_iter(win, screen, sv)
386  {
387  sv->flag = 0;
388  }
389 
390  edge->v1->flag = 1;
391  edge->v2->flag = 1;
392 
393  /* select connected, only in the right direction */
394  bool oneselected = true;
395  while (oneselected) {
396  oneselected = false;
397  LISTBASE_FOREACH (ScrEdge *, se, &screen->edgebase) {
398  if (se->v1->flag + se->v2->flag == 1) {
399  if (dir == 'h') {
400  if (se->v1->vec.y == se->v2->vec.y) {
401  se->v1->flag = se->v2->flag = 1;
402  oneselected = true;
403  }
404  }
405  if (dir == 'v') {
406  if (se->v1->vec.x == se->v2->vec.x) {
407  se->v1->flag = se->v2->flag = 1;
408  oneselected = true;
409  }
410  }
411  }
412  }
413  }
414 }
typedef float(TangentPoint)[2]
struct ScrEdge * BKE_screen_find_edge(const struct bScreen *screen, struct ScrVert *v1, struct ScrVert *v2)
void BKE_screen_sort_scrvert(struct ScrVert **v1, struct ScrVert **v2)
Definition: screen.c:756
#define LISTBASE_FOREACH(type, var, list)
Definition: BLI_listbase.h:172
void BLI_addtail(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition: listbase.c:110
MINLINE short round_fl_to_short(float a)
void minmax_v2v2_v2(float min[2], float max[2], const float vec[2])
Definition: math_vector.c:1043
BLI_INLINE int BLI_rcti_size_y(const struct rcti *rct)
Definition: BLI_rect.h:157
BLI_INLINE int BLI_rcti_size_x(const struct rcti *rct)
Definition: BLI_rect.h:153
#define MAX2(a, b)
#define ELEM(...)
#define MIN2(a, b)
#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
int ED_area_global_size_y(const ScrArea *area)
Definition: area.c:3377
#define ED_screen_verts_iter(win, screen, vert_name)
Definition: ED_screen.h:192
int ED_area_headersize(void)
Definition: area.c:3363
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei height
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint y
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint GLsizei GLsizei GLenum type _GL_VOID_RET _GL_VOID GLsizei GLenum GLenum const void *pixels _GL_VOID_RET _GL_VOID const void *pointer _GL_VOID_RET _GL_VOID GLdouble v _GL_VOID_RET _GL_VOID GLfloat v _GL_VOID_RET _GL_VOID GLint GLint i2 _GL_VOID_RET _GL_VOID GLint j _GL_VOID_RET _GL_VOID GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble GLdouble GLdouble zFar _GL_VOID_RET _GL_UINT GLdouble *equation _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLenum GLfloat *v _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLfloat *values _GL_VOID_RET _GL_VOID GLushort *values _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLenum GLdouble *params _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_BOOL GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLenum GLfloat param _GL_VOID_RET _GL_VOID GLenum GLint param _GL_VOID_RET _GL_VOID GLushort pattern _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint const GLdouble *points _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint GLdouble v1
Read Guarded memory(de)allocation.
Group RGB to Bright Vector Camera CLAMP
ATTR_WARN_UNUSED_RESULT const BMVert * v2
unsigned int U
Definition: btGjkEpa3.h:78
void *(* MEM_callocN)(size_t len, const char *str)
Definition: mallocn.c:45
static void area(int d1, int d2, int e1, int e2, float weights[2])
ScrEdge * screen_geom_area_map_find_active_scredge(const ScrAreaMap *area_map, const rcti *bounds_rect, const int mx, const int my)
short screen_geom_find_area_split_point(const ScrArea *area, const rcti *window_rect, char dir, float fac)
void screen_geom_select_connected_edge(const wmWindow *win, ScrEdge *edge)
bool screen_geom_edge_is_horizontal(ScrEdge *se)
ScrEdge * screen_geom_find_active_scredge(const wmWindow *win, const bScreen *screen, const int mx, const int my)
static bool screen_geom_vertices_scale_pass(const wmWindow *win, const bScreen *screen, const rcti *screen_rect)
ScrEdge * screen_geom_edge_add(bScreen *screen, ScrVert *v1, ScrVert *v2)
ScrVert * screen_geom_vertex_add(bScreen *screen, short x, short y)
int screen_geom_area_width(const ScrArea *area)
ScrEdge * screen_geom_edge_add_ex(ScrAreaMap *area_map, ScrVert *v1, ScrVert *v2)
int screen_geom_area_height(const ScrArea *area)
ScrVert * screen_geom_vertex_add_ex(ScrAreaMap *area_map, short x, short y)
void screen_geom_vertices_scale(const wmWindow *win, bScreen *screen)
Main screen-layout calculation function.
#define BORDERPADDING
Definition: screen_intern.h:40
#define min(a, b)
Definition: sort.c:51
ListBase vertbase
ListBase edgebase
ListBase areabase
ScrVert * v1
ScrVert * v2
ListBase edgebase
ListBase vertbase
ListBase areabase
int ymin
Definition: DNA_vec_types.h:80
int ymax
Definition: DNA_vec_types.h:80
int xmin
Definition: DNA_vec_types.h:79
int xmax
Definition: DNA_vec_types.h:79
short y
Definition: DNA_vec_types.h:34
short x
Definition: DNA_vec_types.h:34
ScrAreaMap global_areas
float max
__forceinline const avxi abs(const avxi &a)
Definition: util_avxi.h:186
bScreen * WM_window_get_active_screen(const wmWindow *win)
Definition: wm_window.c:2372
void WM_window_rect_calc(const wmWindow *win, rcti *r_rect)
Definition: wm_window.c:2146
void WM_window_screen_rect_calc(const wmWindow *win, rcti *r_rect)
Definition: wm_window.c:2154