Blender  V3.3
interface_align.c
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later
2  * Copyright 2015 Blender Foundation. All rights reserved. */
3 
8 #include "DNA_screen_types.h"
9 #include "DNA_userdef_types.h"
10 
11 #include "BLI_listbase.h"
12 #include "BLI_math.h"
13 #include "BLI_rect.h"
14 
15 #include "UI_interface.h"
16 
17 #include "interface_intern.h"
18 
19 #include "MEM_guardedalloc.h"
20 
21 #ifdef USE_UIBUT_SPATIAL_ALIGN
22 
44 typedef struct ButAlign {
46 
47  /* Neighbor buttons */
48  struct ButAlign *neighbors[4];
49 
50  /* Pointers to coordinates (rctf values) of the button. */
51  float *borders[4];
52 
53  /* Distances to the neighbors. */
54  float dists[4];
55 
56  /* Flags, used to mark whether we should 'stitch'
57  * the corners of this button with its neighbors' ones. */
58  char flags[4];
60 
61 /* Side-related enums and flags. */
62 enum {
63  /* Sides (used as indices, order is **crucial**,
64  * this allows us to factorize code in a loop over the four sides). */
65  LEFT = 0,
66  TOP = 1,
67  RIGHT = 2,
68  DOWN = 3,
69  TOTSIDES = 4,
70 
71  /* Stitch flags, built from sides values. */
72  STITCH_LEFT = 1 << LEFT,
73  STITCH_TOP = 1 << TOP,
75  STITCH_DOWN = 1 << DOWN,
76 };
77 
78 /* Mapping between 'our' sides and 'public' UI_BUT_ALIGN flags, order must match enum above. */
79 # define SIDE_TO_UI_BUT_ALIGN \
80  { \
81  UI_BUT_ALIGN_LEFT, UI_BUT_ALIGN_TOP, UI_BUT_ALIGN_RIGHT, UI_BUT_ALIGN_DOWN \
82  }
83 
84 /* Given one side, compute the three other ones */
85 # define SIDE1(_s) (((_s) + 1) % TOTSIDES)
86 # define OPPOSITE(_s) (((_s) + 2) % TOTSIDES)
87 # define SIDE2(_s) (((_s) + 3) % TOTSIDES)
88 
89 /* 0: LEFT/RIGHT sides; 1 = TOP/DOWN sides. */
90 # define IS_COLUMN(_s) ((_s) % 2)
91 
92 /* Stitch flag from side value. */
93 # define STITCH(_s) (1 << (_s))
94 
95 /* Max distance between to buttons for them to be 'mergeable'. */
96 # define MAX_DELTA 0.45f * max_ii(UI_UNIT_Y, UI_UNIT_X)
97 
99 {
100  const bool btype_can_align = !ELEM(but->type,
104  UI_BTYPE_TAB,
108  return (btype_can_align && (BLI_rctf_size_x(&but->rect) > 0.0f) &&
109  (BLI_rctf_size_y(&but->rect) > 0.0f));
110 }
111 
119 static void block_align_proximity_compute(ButAlign *butal, ButAlign *butal_other)
120 {
121  /* That's the biggest gap between two borders to consider them 'alignable'. */
122  const float max_delta = MAX_DELTA;
123  float delta, delta_side_opp;
124  int side, side_opp;
125 
126  const bool butal_can_align = ui_but_can_align(butal->but);
127  const bool butal_other_can_align = ui_but_can_align(butal_other->but);
128 
129  const bool buts_share[2] = {
130  /* Sharing same line? */
131  !((*butal->borders[DOWN] >= *butal_other->borders[TOP]) ||
132  (*butal->borders[TOP] <= *butal_other->borders[DOWN])),
133  /* Sharing same column? */
134  !((*butal->borders[LEFT] >= *butal_other->borders[RIGHT]) ||
135  (*butal->borders[RIGHT] <= *butal_other->borders[LEFT])),
136  };
137 
138  /* Early out in case buttons share no column or line, or if none can align... */
139  if (!(buts_share[0] || buts_share[1]) || !(butal_can_align || butal_other_can_align)) {
140  return;
141  }
142 
143  for (side = 0; side < RIGHT; side++) {
144  /* We are only interested in buttons which share a same line
145  * (LEFT/RIGHT sides) or column (TOP/DOWN sides). */
146  if (buts_share[IS_COLUMN(side)]) {
147  side_opp = OPPOSITE(side);
148 
149  /* We check both opposite sides at once, because with very small buttons,
150  * delta could be below max_delta for the wrong side
151  * (that is, in horizontal case, the total width of two buttons can be below max_delta).
152  * We rely on exact zero value here as an 'already processed' flag,
153  * so ensure we never actually set a zero value at this stage.
154  * FLT_MIN is zero-enough for UI position computing. ;) */
155  delta = max_ff(fabsf(*butal->borders[side] - *butal_other->borders[side_opp]), FLT_MIN);
156  delta_side_opp = max_ff(fabsf(*butal->borders[side_opp] - *butal_other->borders[side]),
157  FLT_MIN);
158  if (delta_side_opp < delta) {
159  SWAP(int, side, side_opp);
160  delta = delta_side_opp;
161  }
162 
163  if (delta < max_delta) {
164  /* We are only interested in neighbors that are
165  * at least as close as already found ones. */
166  if (delta <= butal->dists[side]) {
167  {
168  /* We found an as close or closer neighbor.
169  * If both buttons are alignable, we set them as each other neighbors.
170  * Else, we have an unalignable one, we need to reset the others matching
171  * neighbor to NULL if its 'proximity distance'
172  * is really lower with current one.
173  *
174  * NOTE: We cannot only execute that piece of code in case we found a
175  * **closer** neighbor, due to the limited way we represent neighbors
176  * (buttons only know **one** neighbor on each side, when they can
177  * actually have several ones), it would prevent some buttons to be
178  * properly 'neighborly-initialized'. */
179  if (butal_can_align && butal_other_can_align) {
180  butal->neighbors[side] = butal_other;
181  butal_other->neighbors[side_opp] = butal;
182  }
183  else if (butal_can_align && (delta < butal->dists[side])) {
184  butal->neighbors[side] = NULL;
185  }
186  else if (butal_other_can_align && (delta < butal_other->dists[side_opp])) {
187  butal_other->neighbors[side_opp] = NULL;
188  }
189  butal->dists[side] = butal_other->dists[side_opp] = delta;
190  }
191 
192  if (butal_can_align && butal_other_can_align) {
193  const int side_s1 = SIDE1(side);
194  const int side_s2 = SIDE2(side);
195 
196  const int stitch = STITCH(side);
197  const int stitch_opp = STITCH(side_opp);
198 
199  if (butal->neighbors[side] == NULL) {
200  butal->neighbors[side] = butal_other;
201  }
202  if (butal_other->neighbors[side_opp] == NULL) {
203  butal_other->neighbors[side_opp] = butal;
204  }
205 
206  /* We have a pair of neighbors, we have to check whether we
207  * can stitch their matching corners.
208  * E.g. if butal_other is on the left of butal (that is, side == LEFT),
209  * if both TOP (side_s1) coordinates of buttons are close enough,
210  * we can stitch their upper matching corners,
211  * and same for DOWN (side_s2) side. */
212  delta = fabsf(*butal->borders[side_s1] - *butal_other->borders[side_s1]);
213  if (delta < max_delta) {
214  butal->flags[side_s1] |= stitch;
215  butal_other->flags[side_s1] |= stitch_opp;
216  }
217  delta = fabsf(*butal->borders[side_s2] - *butal_other->borders[side_s2]);
218  if (delta < max_delta) {
219  butal->flags[side_s2] |= stitch;
220  butal_other->flags[side_s2] |= stitch_opp;
221  }
222  }
223  }
224  /* We assume two buttons can only share one side at most - for until
225  * we have spherical UI. */
226  return;
227  }
228  }
229  }
230 }
231 
254  const int side,
255  const int side_opp,
256  const int side_s1,
257  const int side_s2,
258  const int align,
259  const int align_opp,
260  const float co)
261 {
262  ButAlign *butal_neighbor;
263 
264  const int stitch_s1 = STITCH(side_s1);
265  const int stitch_s2 = STITCH(side_s2);
266 
267  /* We have to check stitching flags on both sides of the stitching,
268  * since we only clear one of them flags to break any future loop on same 'columns/side' case.
269  * Also, if butal is spanning over several rows or columns of neighbors,
270  * it may have both of its stitching flags
271  * set, but would not be the case of its immediate neighbor! */
272  while ((butal->flags[side] & stitch_s1) && (butal = butal->neighbors[side_s1]) &&
273  (butal->flags[side] & stitch_s2)) {
274  butal_neighbor = butal->neighbors[side];
275 
276  /* If we actually do have a neighbor, we directly set its values accordingly,
277  * and clear its matching 'dist' to prevent it being set again later... */
278  if (butal_neighbor) {
279  butal->but->drawflag |= align;
280  butal_neighbor->but->drawflag |= align_opp;
281  *butal_neighbor->borders[side_opp] = co;
282  butal_neighbor->dists[side_opp] = 0.0f;
283  }
284  /* See definition of UI_BUT_ALIGN_STITCH_LEFT/TOP for reason of this... */
285  else if (side == LEFT) {
287  }
288  else if (side == TOP) {
290  }
291  *butal->borders[side] = co;
292  butal->dists[side] = 0.0f;
293  /* Clearing one of the 'flags pair' here is enough to prevent this loop running on
294  * the same column, side and direction again. */
295  butal->flags[side] &= ~stitch_s2;
296  }
297 }
298 
305 static int ui_block_align_butal_cmp(const void *a, const void *b)
306 {
307  const ButAlign *butal = a;
308  const ButAlign *butal_other = b;
309 
310  /* Sort by align group. */
311  if (butal->but->alignnr != butal_other->but->alignnr) {
312  return butal->but->alignnr - butal_other->but->alignnr;
313  }
314 
315  /* Sort vertically.
316  * Note that Y of buttons is decreasing (first buttons have higher Y value than later ones). */
317  if (*butal->borders[TOP] != *butal_other->borders[TOP]) {
318  return (*butal_other->borders[TOP] > *butal->borders[TOP]) ? 1 : -1;
319  }
320 
321  /* Sort horizontally. */
322  if (*butal->borders[LEFT] != *butal_other->borders[LEFT]) {
323  return (*butal->borders[LEFT] > *butal_other->borders[LEFT]) ? 1 : -1;
324  }
325 
326  /* XXX We cannot actually assert here, since in some very compressed space cases,
327  * stupid UI code produces widgets which have the same TOP and LEFT positions...
328  * We do not care really,
329  * because this happens when UI is way too small to be usable anyway. */
330  // BLI_assert(0);
331  return 0;
332 }
333 
334 static void ui_block_align_but_to_region(uiBut *but, const ARegion *region)
335 {
336  rctf *rect = &but->rect;
337  const float but_width = BLI_rctf_size_x(rect);
338  const float but_height = BLI_rctf_size_y(rect);
339  const float outline_px = U.pixelsize; /* This may have to be made more variable. */
340 
341  switch (but->drawflag & UI_BUT_ALIGN) {
342  case UI_BUT_ALIGN_TOP:
343  rect->ymax = region->winy + outline_px;
344  rect->ymin = but->rect.ymax - but_height;
345  break;
346  case UI_BUT_ALIGN_DOWN:
347  rect->ymin = -outline_px;
348  rect->ymax = rect->ymin + but_height;
349  break;
350  case UI_BUT_ALIGN_LEFT:
351  rect->xmin = -outline_px;
352  rect->xmax = rect->xmin + but_width;
353  break;
354  case UI_BUT_ALIGN_RIGHT:
355  rect->xmax = region->winx + outline_px;
356  rect->xmin = rect->xmax - but_width;
357  break;
358  default:
359  /* Tabs may be shown in unaligned regions too, they just appear as regular buttons then. */
360  break;
361  }
362 }
363 
364 void ui_block_align_calc(uiBlock *block, const ARegion *region)
365 {
366  int num_buttons = 0;
367 
368  const int sides_to_ui_but_align_flags[4] = SIDE_TO_UI_BUT_ALIGN;
369 
370  ButAlign *butal_array;
371  ButAlign *butal, *butal_other;
372  int side;
373 
374  /* First loop: we count number of buttons belonging to an align group,
375  * and clear their align flag.
376  * Tabs get some special treatment here, they get aligned to region border. */
377  LISTBASE_FOREACH (uiBut *, but, &block->buttons) {
378  /* special case: tabs need to be aligned to a region border, drawflag tells which one */
379  if (but->type == UI_BTYPE_TAB) {
381  }
382  else {
383  /* Clear old align flags. */
385  }
386 
387  if (but->alignnr != 0) {
388  num_buttons++;
389  }
390  }
391 
392  if (num_buttons < 2) {
393  /* No need to go further if we have nothing to align... */
394  return;
395  }
396 
397  /* Note that this is typically less than ~20, and almost always under ~100.
398  * Even so, we can't ensure this value won't exceed available stack memory.
399  * Fallback to allocation instead of using #alloca, see: T78636. */
400  ButAlign butal_array_buf[256];
401  if (num_buttons <= ARRAY_SIZE(butal_array_buf)) {
402  butal_array = butal_array_buf;
403  }
404  else {
405  butal_array = MEM_mallocN(sizeof(*butal_array) * num_buttons, __func__);
406  }
407  memset(butal_array, 0, sizeof(*butal_array) * (size_t)num_buttons);
408 
409  /* Second loop: we initialize our ButAlign data for each button. */
410  butal = butal_array;
411  LISTBASE_FOREACH (uiBut *, but, &block->buttons) {
412  if (but->alignnr != 0) {
413  butal->but = but;
414  butal->borders[LEFT] = &but->rect.xmin;
415  butal->borders[RIGHT] = &but->rect.xmax;
416  butal->borders[DOWN] = &but->rect.ymin;
417  butal->borders[TOP] = &but->rect.ymax;
418  copy_v4_fl(butal->dists, FLT_MAX);
419  butal++;
420  }
421  }
422 
423  /* This will give us ButAlign items regrouped by align group, vertical and horizontal location.
424  * Note that, given how buttons are defined in UI code,
425  * butal_array shall already be "nearly sorted"... */
426  qsort(butal_array, (size_t)num_buttons, sizeof(*butal_array), ui_block_align_butal_cmp);
427 
428  /* Third loop: for each pair of buttons in the same align group,
429  * we compute their potential proximity. Note that each pair is checked only once, and that we
430  * break early in case we know all remaining pairs will always be too far away. */
431  int i;
432  for (i = 0, butal = butal_array; i < num_buttons; i++, butal++) {
433  const short alignnr = butal->but->alignnr;
434 
435  int j;
436  for (j = i + 1, butal_other = &butal_array[i + 1]; j < num_buttons; j++, butal_other++) {
437  const float max_delta = MAX_DELTA;
438 
439  /* Since they are sorted, buttons after current butal can only be of same or higher
440  * group, and once they are not of same group, we know we can break this sub-loop and
441  * start checking with next butal. */
442  if (butal_other->but->alignnr != alignnr) {
443  break;
444  }
445 
446  /* Since they are sorted vertically first, buttons after current butal can only be at
447  * same or lower height, and once they are lower than a given threshold, we know we can
448  * break this sub-loop and start checking with next butal. */
449  if ((*butal->borders[DOWN] - *butal_other->borders[TOP]) > max_delta) {
450  break;
451  }
452 
453  block_align_proximity_compute(butal, butal_other);
454  }
455  }
456 
457  /* Fourth loop: we have all our 'aligned' buttons as a 'map' in butal_array. We need to:
458  * - update their relevant coordinates to stitch them.
459  * - assign them valid flags.
460  */
461  for (i = 0; i < num_buttons; i++) {
462  butal = &butal_array[i];
463 
464  for (side = 0; side < TOTSIDES; side++) {
465  butal_other = butal->neighbors[side];
466 
467  if (butal_other) {
468  const int side_opp = OPPOSITE(side);
469  const int side_s1 = SIDE1(side);
470  const int side_s2 = SIDE2(side);
471 
472  const int align = sides_to_ui_but_align_flags[side];
473  const int align_opp = sides_to_ui_but_align_flags[side_opp];
474 
475  float co;
476 
477  butal->but->drawflag |= align;
478  butal_other->but->drawflag |= align_opp;
479  if (!IS_EQF(butal->dists[side], 0.0f)) {
480  float *delta = &butal->dists[side];
481 
482  if (*butal->borders[side] < *butal_other->borders[side_opp]) {
483  *delta *= 0.5f;
484  }
485  else {
486  *delta *= -0.5f;
487  }
488  co = (*butal->borders[side] += *delta);
489 
490  if (!IS_EQF(butal_other->dists[side_opp], 0.0f)) {
491  BLI_assert(butal_other->dists[side_opp] * 0.5f == fabsf(*delta));
492  *butal_other->borders[side_opp] = co;
493  butal_other->dists[side_opp] = 0.0f;
494  }
495  *delta = 0.0f;
496  }
497  else {
498  co = *butal->borders[side];
499  }
500 
502  butal, side, side_opp, side_s1, side_s2, align, align_opp, co);
504  butal, side, side_opp, side_s2, side_s1, align, align_opp, co);
505  }
506  }
507  }
508  if (butal_array_buf != butal_array) {
509  MEM_freeN(butal_array);
510  }
511 }
512 
513 # undef SIDE_TO_UI_BUT_ALIGN
514 # undef SIDE1
515 # undef OPPOSITE
516 # undef SIDE2
517 # undef IS_COLUMN
518 # undef STITCH
519 # undef MAX_DELTA
520 
521 #else /* !USE_UIBUT_SPATIAL_ALIGN */
522 
523 bool ui_but_can_align(const uiBut *but)
524 {
525  return !ELEM(but->type,
532 }
533 
534 static bool buts_are_horiz(uiBut *but1, uiBut *but2)
535 {
536  float dx, dy;
537 
538  /* simple case which can fail if buttons shift apart
539  * with proportional layouts, see: T38602. */
540  if ((but1->rect.ymin == but2->rect.ymin) && (but1->rect.xmin != but2->rect.xmin)) {
541  return true;
542  }
543 
544  dx = fabsf(but1->rect.xmax - but2->rect.xmin);
545  dy = fabsf(but1->rect.ymin - but2->rect.ymax);
546 
547  return (dx <= dy);
548 }
549 
550 static void ui_block_align_calc_but(uiBut *first, short nr)
551 {
552  uiBut *prev, *but = NULL, *next;
553  int flag = 0, cols = 0, rows = 0;
554 
555  /* auto align */
556 
557  for (but = first; but && but->alignnr == nr; but = but->next) {
558  if (but->next && but->next->alignnr == nr) {
559  if (buts_are_horiz(but, but->next)) {
560  cols++;
561  }
562  else {
563  rows++;
564  }
565  }
566  }
567 
568  /* rows == 0: 1 row, cols == 0: 1 column */
569 
570  /* NOTE: manipulation of 'flag' in the loop below is confusing.
571  * In some cases it's assigned, other times OR is used. */
572  for (but = first, prev = NULL; but && but->alignnr == nr; prev = but, but = but->next) {
573  next = but->next;
574  if (next && next->alignnr != nr) {
575  next = NULL;
576  }
577 
578  /* clear old flag */
580 
581  if (flag == 0) { /* first case */
582  if (next) {
583  if (buts_are_horiz(but, next)) {
584  if (rows == 0) {
585  flag = UI_BUT_ALIGN_RIGHT;
586  }
587  else {
589  }
590  }
591  else {
592  flag = UI_BUT_ALIGN_DOWN;
593  }
594  }
595  }
596  else if (next == NULL) { /* last case */
597  if (prev) {
598  if (buts_are_horiz(prev, but)) {
599  if (rows == 0) {
600  flag = UI_BUT_ALIGN_LEFT;
601  }
602  else {
604  }
605  }
606  else {
607  flag = UI_BUT_ALIGN_TOP;
608  }
609  }
610  }
611  else if (buts_are_horiz(but, next)) {
612  /* check if this is already second row */
613  if (prev && buts_are_horiz(prev, but) == 0) {
614  flag &= ~UI_BUT_ALIGN_LEFT;
615  flag |= UI_BUT_ALIGN_TOP;
616  /* exception case: bottom row */
617  if (rows > 0) {
618  uiBut *bt = but;
619  while (bt && bt->alignnr == nr) {
620  if (bt->next && bt->next->alignnr == nr && buts_are_horiz(bt, bt->next) == 0) {
621  break;
622  }
623  bt = bt->next;
624  }
625  if (bt == NULL || bt->alignnr != nr) {
627  }
628  }
629  }
630  else {
631  flag |= UI_BUT_ALIGN_LEFT;
632  }
633  }
634  else {
635  if (cols == 0) {
636  flag |= UI_BUT_ALIGN_TOP;
637  }
638  else { /* next button switches to new row */
639 
640  if (prev && buts_are_horiz(prev, but)) {
641  flag |= UI_BUT_ALIGN_LEFT;
642  }
643  else {
644  flag &= ~UI_BUT_ALIGN_LEFT;
645  flag |= UI_BUT_ALIGN_TOP;
646  }
647 
648  if ((flag & UI_BUT_ALIGN_TOP) == 0) { /* still top row */
649  if (prev) {
650  if (next && buts_are_horiz(but, next)) {
652  }
653  else {
654  /* last button in top row */
656  }
657  }
658  else {
659  flag |= UI_BUT_ALIGN_DOWN;
660  }
661  }
662  else {
663  flag |= UI_BUT_ALIGN_TOP;
664  }
665  }
666  }
667 
668  but->drawflag |= flag;
669 
670  /* merge coordinates */
671  if (prev) {
672  /* simple cases */
673  if (rows == 0) {
674  but->rect.xmin = (prev->rect.xmax + but->rect.xmin) / 2.0f;
675  prev->rect.xmax = but->rect.xmin;
676  }
677  else if (cols == 0) {
678  but->rect.ymax = (prev->rect.ymin + but->rect.ymax) / 2.0f;
679  prev->rect.ymin = but->rect.ymax;
680  }
681  else {
682  if (buts_are_horiz(prev, but)) {
683  but->rect.xmin = (prev->rect.xmax + but->rect.xmin) / 2.0f;
684  prev->rect.xmax = but->rect.xmin;
685  /* copy height too */
686  but->rect.ymax = prev->rect.ymax;
687  }
688  else if (prev->prev && buts_are_horiz(prev->prev, prev) == 0) {
689  /* the previous button is a single one in its row */
690  but->rect.ymax = (prev->rect.ymin + but->rect.ymax) / 2.0f;
691  prev->rect.ymin = but->rect.ymax;
692 
693  but->rect.xmin = prev->rect.xmin;
694  if (next && buts_are_horiz(but, next) == 0) {
695  but->rect.xmax = prev->rect.xmax;
696  }
697  }
698  else {
699  /* the previous button is not a single one in its row */
700  but->rect.ymax = prev->rect.ymin;
701  }
702  }
703  }
704  }
705 }
706 
707 void ui_block_align_calc(uiBlock *block, const struct ARegion *UNUSED(region))
708 {
709  short nr;
710 
711  /* align buttons with same align nr */
712  LISTBASE_FOREACH (uiBut *, but, &block->buttons) {
713  if (but->alignnr) {
714  nr = but->alignnr;
715  ui_block_align_calc_but(but, nr);
716 
717  /* skip with same number */
718  for (; but && but->alignnr == nr; but = but->next) {
719  /* pass */
720  }
721 
722  if (!but) {
723  break;
724  }
725  }
726  else {
727  but = but->next;
728  }
729  }
730 }
731 
732 #endif /* !USE_UIBUT_SPATIAL_ALIGN */
733 
735 {
736  const ARegion *align_region = (region->alignment & RGN_SPLIT_PREV && region->prev) ?
737  region->prev :
738  region;
739 
740  switch (RGN_ALIGN_ENUM_FROM_MASK(align_region->alignment)) {
741  case RGN_ALIGN_TOP:
742  return UI_BUT_ALIGN_DOWN;
743  case RGN_ALIGN_BOTTOM:
744  return UI_BUT_ALIGN_TOP;
745  case RGN_ALIGN_LEFT:
746  return UI_BUT_ALIGN_RIGHT;
747  case RGN_ALIGN_RIGHT:
748  return UI_BUT_ALIGN_LEFT;
749  }
750 
751  return 0;
752 }
#define BLI_assert(a)
Definition: BLI_assert.h:46
#define LISTBASE_FOREACH(type, var, list)
Definition: BLI_listbase.h:336
MINLINE float max_ff(float a, float b)
MINLINE void copy_v4_fl(float r[4], float f)
BLI_INLINE float BLI_rctf_size_x(const struct rctf *rct)
Definition: BLI_rect.h:194
BLI_INLINE float BLI_rctf_size_y(const struct rctf *rct)
Definition: BLI_rect.h:198
#define ARRAY_SIZE(arr)
#define SWAP(type, a, b)
#define UNUSED(x)
#define ELEM(...)
#define IS_EQF(a, b)
#define RGN_ALIGN_ENUM_FROM_MASK(align)
@ RGN_ALIGN_BOTTOM
@ RGN_ALIGN_LEFT
@ RGN_ALIGN_TOP
@ RGN_ALIGN_RIGHT
@ RGN_SPLIT_PREV
Read Guarded memory(de)allocation.
@ UI_BUT_ALIGN_ALL
Definition: UI_interface.h:283
@ UI_BUT_ALIGN_DOWN
Definition: UI_interface.h:272
@ UI_BUT_ALIGN_TOP
Definition: UI_interface.h:269
@ UI_BUT_ALIGN
Definition: UI_interface.h:273
@ UI_BUT_ALIGN_STITCH_TOP
Definition: UI_interface.h:281
@ UI_BUT_ALIGN_STITCH_LEFT
Definition: UI_interface.h:282
@ UI_BUT_ALIGN_RIGHT
Definition: UI_interface.h:271
@ UI_BUT_ALIGN_LEFT
Definition: UI_interface.h:270
@ UI_BTYPE_TAB
Definition: UI_interface.h:350
@ UI_BTYPE_SEPR_SPACER
Definition: UI_interface.h:388
@ UI_BTYPE_LABEL
Definition: UI_interface.h:354
@ UI_BTYPE_SEPR_LINE
Definition: UI_interface.h:386
@ UI_BTYPE_CHECKBOX_N
Definition: UI_interface.h:348
@ UI_BTYPE_SEPR
Definition: UI_interface.h:385
@ UI_BTYPE_CHECKBOX
Definition: UI_interface.h:347
unsigned int U
Definition: btGjkEpa3.h:78
#define IS_COLUMN(_s)
#define MAX_DELTA
bool ui_but_can_align(const uiBut *but)
static void block_align_stitch_neighbors(ButAlign *butal, const int side, const int side_opp, const int side_s1, const int side_s2, const int align, const int align_opp, const float co)
static void ui_block_align_but_to_region(uiBut *but, const ARegion *region)
int ui_but_align_opposite_to_area_align_get(const ARegion *region)
static void block_align_proximity_compute(ButAlign *butal, ButAlign *butal_other)
struct ButAlign ButAlign
@ TOP
@ STITCH_DOWN
@ STITCH_RIGHT
@ STITCH_LEFT
@ STITCH_TOP
@ DOWN
@ TOTSIDES
@ LEFT
@ RIGHT
static int ui_block_align_butal_cmp(const void *a, const void *b)
#define SIDE_TO_UI_BUT_ALIGN
#define SIDE2(_s)
#define STITCH(_s)
#define SIDE1(_s)
#define OPPOSITE(_s)
void ui_block_align_calc(uiBlock *block, const ARegion *region)
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:27
void *(* MEM_mallocN)(size_t len, const char *str)
Definition: mallocn.c:33
static ulong * next
#define fabsf(x)
Definition: metal/compat.h:219
static unsigned a[3]
Definition: RandGen.cpp:78
SymEdge< T > * prev(const SymEdge< T > *se)
Definition: delaunay_2d.cc:105
static const pxr::TfToken b("b", pxr::TfToken::Immortal)
struct ARegion * prev
short alignment
uiBut * but
struct ButAlign * neighbors[4]
float dists[4]
char flags[4]
float * borders[4]
float xmax
Definition: DNA_vec_types.h:69
float xmin
Definition: DNA_vec_types.h:69
float ymax
Definition: DNA_vec_types.h:70
float ymin
Definition: DNA_vec_types.h:70
ListBase buttons
struct uiBut * next
eButType type
short alignnr