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