diff options
author | Campbell Barton <ideasman42@gmail.com> | 2019-04-17 07:17:24 +0300 |
---|---|---|
committer | Campbell Barton <ideasman42@gmail.com> | 2019-04-17 07:21:24 +0300 |
commit | e12c08e8d170b7ca40f204a5b0423c23a9fbc2c1 (patch) | |
tree | 8cf3453d12edb177a218ef8009357518ec6cab6a /source/blender/editors/interface/interface_align.c | |
parent | b3dabc200a4b0399ec6b81f2ff2730d07b44fcaa (diff) |
ClangFormat: apply to source, most of intern
Apply clang format as proposed in T53211.
For details on usage and instructions for migrating branches
without conflicts, see:
https://wiki.blender.org/wiki/Tools/ClangFormat
Diffstat (limited to 'source/blender/editors/interface/interface_align.c')
-rw-r--r-- | source/blender/editors/interface/interface_align.c | 1152 |
1 files changed, 585 insertions, 567 deletions
diff --git a/source/blender/editors/interface/interface_align.c b/source/blender/editors/interface/interface_align.c index 9e1563e6511..61f9005ce44 100644 --- a/source/blender/editors/interface/interface_align.c +++ b/source/blender/editors/interface/interface_align.c @@ -55,77 +55,87 @@ * but not sure we want to support such exotic cases anyway. */ typedef struct ButAlign { - uiBut *but; + uiBut *but; - /* Neighbor buttons */ - struct ButAlign *neighbors[4]; + /* Neighbor buttons */ + struct ButAlign *neighbors[4]; - /* Pointers to coordinates (rctf values) of the button. */ - float *borders[4]; + /* Pointers to coordinates (rctf values) of the button. */ + float *borders[4]; - /* Distances to the neighbors. */ - float dists[4]; + /* Distances to the neighbors. */ + float dists[4]; - /* Flags, used to mark whether we should 'stitch' - * the corners of this button with its neighbors' ones. */ - char flags[4]; + /* Flags, used to mark whether we should 'stitch' + * the corners of this button with its neighbors' ones. */ + char flags[4]; } ButAlign; /* Side-related enums and flags. */ enum { - /* Sides (used as indices, order is **crucial**, - * this allows us to factorize code in a loop over the four sides). */ - LEFT = 0, - TOP = 1, - RIGHT = 2, - DOWN = 3, - TOTSIDES = 4, - - /* Stitch flags, built from sides values. */ - STITCH_LEFT = 1 << LEFT, - STITCH_TOP = 1 << TOP, - STITCH_RIGHT = 1 << RIGHT, - STITCH_DOWN = 1 << DOWN, + /* Sides (used as indices, order is **crucial**, + * this allows us to factorize code in a loop over the four sides). */ + LEFT = 0, + TOP = 1, + RIGHT = 2, + DOWN = 3, + TOTSIDES = 4, + + /* Stitch flags, built from sides values. */ + STITCH_LEFT = 1 << LEFT, + STITCH_TOP = 1 << TOP, + STITCH_RIGHT = 1 << RIGHT, + STITCH_DOWN = 1 << DOWN, }; /* Mapping between 'our' sides and 'public' UI_BUT_ALIGN flags, order must match enum above. */ -#define SIDE_TO_UI_BUT_ALIGN {UI_BUT_ALIGN_LEFT, UI_BUT_ALIGN_TOP, UI_BUT_ALIGN_RIGHT, UI_BUT_ALIGN_DOWN} +# define SIDE_TO_UI_BUT_ALIGN \ + { \ + UI_BUT_ALIGN_LEFT, UI_BUT_ALIGN_TOP, UI_BUT_ALIGN_RIGHT, UI_BUT_ALIGN_DOWN \ + } /* Given one side, compute the three other ones */ -#define SIDE1(_s) (((_s) + 1) % TOTSIDES) -#define OPPOSITE(_s) (((_s) + 2) % TOTSIDES) -#define SIDE2(_s) (((_s) + 3) % TOTSIDES) +# define SIDE1(_s) (((_s) + 1) % TOTSIDES) +# define OPPOSITE(_s) (((_s) + 2) % TOTSIDES) +# define SIDE2(_s) (((_s) + 3) % TOTSIDES) /* 0: LEFT/RIGHT sides; 1 = TOP/DOWN sides. */ -#define IS_COLUMN(_s) ((_s) % 2) +# define IS_COLUMN(_s) ((_s) % 2) /* Stitch flag from side value. */ -#define STITCH(_s) (1 << (_s)) +# define STITCH(_s) (1 << (_s)) /* Max distance between to buttons for them to be 'mergeable'. */ -#define MAX_DELTA 0.45f * max_ii(UI_UNIT_Y, UI_UNIT_X) +# define MAX_DELTA 0.45f * max_ii(UI_UNIT_Y, UI_UNIT_X) bool ui_but_can_align(const uiBut *but) { - const bool btype_can_align = !ELEM(but->type, UI_BTYPE_LABEL, UI_BTYPE_CHECKBOX, UI_BTYPE_CHECKBOX_N, - UI_BTYPE_TAB, UI_BTYPE_SEPR, UI_BTYPE_SEPR_LINE, UI_BTYPE_SEPR_SPACER); - return (btype_can_align && (BLI_rctf_size_x(&but->rect) > 0.0f) && (BLI_rctf_size_y(&but->rect) > 0.0f)); + const bool btype_can_align = !ELEM(but->type, + UI_BTYPE_LABEL, + UI_BTYPE_CHECKBOX, + UI_BTYPE_CHECKBOX_N, + UI_BTYPE_TAB, + UI_BTYPE_SEPR, + UI_BTYPE_SEPR_LINE, + UI_BTYPE_SEPR_SPACER); + return (btype_can_align && (BLI_rctf_size_x(&but->rect) > 0.0f) && + (BLI_rctf_size_y(&but->rect) > 0.0f)); } int ui_but_align_opposite_to_area_align_get(const ARegion *ar) { - switch (ar->alignment) { - case RGN_ALIGN_TOP: - return UI_BUT_ALIGN_DOWN; - case RGN_ALIGN_BOTTOM: - return UI_BUT_ALIGN_TOP; - case RGN_ALIGN_LEFT: - return UI_BUT_ALIGN_RIGHT; - case RGN_ALIGN_RIGHT: - return UI_BUT_ALIGN_LEFT; - } - - return 0; + switch (ar->alignment) { + case RGN_ALIGN_TOP: + return UI_BUT_ALIGN_DOWN; + case RGN_ALIGN_BOTTOM: + return UI_BUT_ALIGN_TOP; + case RGN_ALIGN_LEFT: + return UI_BUT_ALIGN_RIGHT; + case RGN_ALIGN_RIGHT: + return UI_BUT_ALIGN_LEFT; + } + + return 0; } /** @@ -136,114 +146,115 @@ int ui_but_align_opposite_to_area_align_get(const ARegion *ar) */ static void block_align_proximity_compute(ButAlign *butal, ButAlign *butal_other) { - /* That's the biggest gap between two borders to consider them 'alignable'. */ - const float max_delta = MAX_DELTA; - float delta, delta_side_opp; - int side, side_opp; - - const bool butal_can_align = ui_but_can_align(butal->but); - const bool butal_other_can_align = ui_but_can_align(butal_other->but); - - const bool buts_share[2] = { - /* Sharing same line? */ - !((*butal->borders[DOWN] >= *butal_other->borders[TOP]) || - (*butal->borders[TOP] <= *butal_other->borders[DOWN])), - /* Sharing same column? */ - !((*butal->borders[LEFT] >= *butal_other->borders[RIGHT]) || - (*butal->borders[RIGHT] <= *butal_other->borders[LEFT])), - }; - - /* Early out in case buttons share no column or line, or if none can align... */ - if (!(buts_share[0] || buts_share[1]) || !(butal_can_align || butal_other_can_align)) { - return; - } - - for (side = 0; side < RIGHT; side++) { - /* We are only interested in buttons which share a same line - * (LEFT/RIGHT sides) or column (TOP/DOWN sides). */ - if (buts_share[IS_COLUMN(side)]) { - side_opp = OPPOSITE(side); - - /* We check both opposite sides at once, because with very small buttons, - * delta could be below max_delta for the wrong side - * (that is, in horizontal case, the total width of two buttons can be below max_delta). - * We rely on exact zero value here as an 'already processed' flag, - * so ensure we never actually set a zero value at this stage. - * FLT_MIN is zero-enough for UI position computing. ;) */ - delta = max_ff(fabsf(*butal->borders[side] - *butal_other->borders[side_opp]), FLT_MIN); - delta_side_opp = max_ff(fabsf(*butal->borders[side_opp] - *butal_other->borders[side]), FLT_MIN); - if (delta_side_opp < delta) { - SWAP(int, side, side_opp); - delta = delta_side_opp; - } - - if (delta < max_delta) { - /* We are only interested in neighbors that are - * at least as close as already found ones. */ - if (delta <= butal->dists[side]) { - { - /* We found an as close or closer neighbor. - * If both buttons are alignable, we set them as each other neighbors. - * Else, we have an unalignable one, we need to reset the others matching - * neighbor to NULL if its 'proximity distance' - * is really lower with current one. - * - * NOTE: We cannot only execute that piece of code in case we found a - * **closer** neighbor, due to the limited way we represent neighbors - * (buttons only know **one** neighbor on each side, when they can - * actually have several ones), it would prevent some buttons to be - * properly 'neighborly-initialized'. */ - if (butal_can_align && butal_other_can_align) { - butal->neighbors[side] = butal_other; - butal_other->neighbors[side_opp] = butal; - } - else if (butal_can_align && (delta < butal->dists[side])) { - butal->neighbors[side] = NULL; - } - else if (butal_other_can_align && (delta < butal_other->dists[side_opp])) { - butal_other->neighbors[side_opp] = NULL; - } - butal->dists[side] = butal_other->dists[side_opp] = delta; - } - - if (butal_can_align && butal_other_can_align) { - const int side_s1 = SIDE1(side); - const int side_s2 = SIDE2(side); - - const int stitch = STITCH(side); - const int stitch_opp = STITCH(side_opp); - - if (butal->neighbors[side] == NULL) { - butal->neighbors[side] = butal_other; - } - if (butal_other->neighbors[side_opp] == NULL) { - butal_other->neighbors[side_opp] = butal; - } - - /* We have a pair of neighbors, we have to check whether we - * can stitch their matching corners. - * E.g. if butal_other is on the left of butal (that is, side == LEFT), - * if both TOP (side_s1) coordinates of buttons are close enough, - * we can stitch their upper matching corners, - * and same for DOWN (side_s2) side. */ - delta = fabsf(*butal->borders[side_s1] - *butal_other->borders[side_s1]); - if (delta < max_delta) { - butal->flags[side_s1] |= stitch; - butal_other->flags[side_s1] |= stitch_opp; - } - delta = fabsf(*butal->borders[side_s2] - *butal_other->borders[side_s2]); - if (delta < max_delta) { - butal->flags[side_s2] |= stitch; - butal_other->flags[side_s2] |= stitch_opp; - } - } - } - /* We assume two buttons can only share one side at most - for until - * we have sperical UI... */ - return; - } - } - } + /* That's the biggest gap between two borders to consider them 'alignable'. */ + const float max_delta = MAX_DELTA; + float delta, delta_side_opp; + int side, side_opp; + + const bool butal_can_align = ui_but_can_align(butal->but); + const bool butal_other_can_align = ui_but_can_align(butal_other->but); + + const bool buts_share[2] = { + /* Sharing same line? */ + !((*butal->borders[DOWN] >= *butal_other->borders[TOP]) || + (*butal->borders[TOP] <= *butal_other->borders[DOWN])), + /* Sharing same column? */ + !((*butal->borders[LEFT] >= *butal_other->borders[RIGHT]) || + (*butal->borders[RIGHT] <= *butal_other->borders[LEFT])), + }; + + /* Early out in case buttons share no column or line, or if none can align... */ + if (!(buts_share[0] || buts_share[1]) || !(butal_can_align || butal_other_can_align)) { + return; + } + + for (side = 0; side < RIGHT; side++) { + /* We are only interested in buttons which share a same line + * (LEFT/RIGHT sides) or column (TOP/DOWN sides). */ + if (buts_share[IS_COLUMN(side)]) { + side_opp = OPPOSITE(side); + + /* We check both opposite sides at once, because with very small buttons, + * delta could be below max_delta for the wrong side + * (that is, in horizontal case, the total width of two buttons can be below max_delta). + * We rely on exact zero value here as an 'already processed' flag, + * so ensure we never actually set a zero value at this stage. + * FLT_MIN is zero-enough for UI position computing. ;) */ + delta = max_ff(fabsf(*butal->borders[side] - *butal_other->borders[side_opp]), FLT_MIN); + delta_side_opp = max_ff(fabsf(*butal->borders[side_opp] - *butal_other->borders[side]), + FLT_MIN); + if (delta_side_opp < delta) { + SWAP(int, side, side_opp); + delta = delta_side_opp; + } + + if (delta < max_delta) { + /* We are only interested in neighbors that are + * at least as close as already found ones. */ + if (delta <= butal->dists[side]) { + { + /* We found an as close or closer neighbor. + * If both buttons are alignable, we set them as each other neighbors. + * Else, we have an unalignable one, we need to reset the others matching + * neighbor to NULL if its 'proximity distance' + * is really lower with current one. + * + * NOTE: We cannot only execute that piece of code in case we found a + * **closer** neighbor, due to the limited way we represent neighbors + * (buttons only know **one** neighbor on each side, when they can + * actually have several ones), it would prevent some buttons to be + * properly 'neighborly-initialized'. */ + if (butal_can_align && butal_other_can_align) { + butal->neighbors[side] = butal_other; + butal_other->neighbors[side_opp] = butal; + } + else if (butal_can_align && (delta < butal->dists[side])) { + butal->neighbors[side] = NULL; + } + else if (butal_other_can_align && (delta < butal_other->dists[side_opp])) { + butal_other->neighbors[side_opp] = NULL; + } + butal->dists[side] = butal_other->dists[side_opp] = delta; + } + + if (butal_can_align && butal_other_can_align) { + const int side_s1 = SIDE1(side); + const int side_s2 = SIDE2(side); + + const int stitch = STITCH(side); + const int stitch_opp = STITCH(side_opp); + + if (butal->neighbors[side] == NULL) { + butal->neighbors[side] = butal_other; + } + if (butal_other->neighbors[side_opp] == NULL) { + butal_other->neighbors[side_opp] = butal; + } + + /* We have a pair of neighbors, we have to check whether we + * can stitch their matching corners. + * E.g. if butal_other is on the left of butal (that is, side == LEFT), + * if both TOP (side_s1) coordinates of buttons are close enough, + * we can stitch their upper matching corners, + * and same for DOWN (side_s2) side. */ + delta = fabsf(*butal->borders[side_s1] - *butal_other->borders[side_s1]); + if (delta < max_delta) { + butal->flags[side_s1] |= stitch; + butal_other->flags[side_s1] |= stitch_opp; + } + delta = fabsf(*butal->borders[side_s2] - *butal_other->borders[side_s2]); + if (delta < max_delta) { + butal->flags[side_s2] |= stitch; + butal_other->flags[side_s2] |= stitch_opp; + } + } + } + /* We assume two buttons can only share one side at most - for until + * we have sperical UI... */ + return; + } + } + } } /** @@ -265,47 +276,49 @@ static void block_align_proximity_compute(ButAlign *butal, ButAlign *butal_other * \note To avoid doing this twice, some stitching flags are cleared to break the 'stitching connection' * between neighbors. */ -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 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) { - ButAlign *butal_neighbor; - - const int stitch_s1 = STITCH(side_s1); - const int stitch_s2 = STITCH(side_s2); - - /* We have to check stitching flags on both sides of the stitching, since we only clear one of them flags to break - * any future loop on same 'columns/side' case. - * Also, if butal is spanning over several rows or columns of neighbors, it may have both of its stitching flags - * set, but would not be the case of its immediate neighbor! */ - while ((butal->flags[side] & stitch_s1) && - (butal = butal->neighbors[side_s1]) && - (butal->flags[side] & stitch_s2)) - { - butal_neighbor = butal->neighbors[side]; - - /* If we actually do have a neighbor, we directly set its values accordingly, and clear its matching 'dist' - * to prevent it being set again later... */ - if (butal_neighbor) { - butal->but->drawflag |= align; - butal_neighbor->but->drawflag |= align_opp; - *butal_neighbor->borders[side_opp] = co; - butal_neighbor->dists[side_opp] = 0.0f; - } - /* See definition of UI_BUT_ALIGN_STITCH_LEFT/TOP for reason of this... */ - else if (side == LEFT) { - butal->but->drawflag |= UI_BUT_ALIGN_STITCH_LEFT; - } - else if (side == TOP) { - butal->but->drawflag |= UI_BUT_ALIGN_STITCH_TOP; - } - *butal->borders[side] = co; - butal->dists[side] = 0.0f; - /* Clearing one of the 'flags pair' here is enough to prevent this loop running on - * the same column, side and direction again. */ - butal->flags[side] &= ~stitch_s2; - } + ButAlign *butal_neighbor; + + const int stitch_s1 = STITCH(side_s1); + const int stitch_s2 = STITCH(side_s2); + + /* We have to check stitching flags on both sides of the stitching, since we only clear one of them flags to break + * any future loop on same 'columns/side' case. + * Also, if butal is spanning over several rows or columns of neighbors, it may have both of its stitching flags + * set, but would not be the case of its immediate neighbor! */ + while ((butal->flags[side] & stitch_s1) && (butal = butal->neighbors[side_s1]) && + (butal->flags[side] & stitch_s2)) { + butal_neighbor = butal->neighbors[side]; + + /* If we actually do have a neighbor, we directly set its values accordingly, and clear its matching 'dist' + * to prevent it being set again later... */ + if (butal_neighbor) { + butal->but->drawflag |= align; + butal_neighbor->but->drawflag |= align_opp; + *butal_neighbor->borders[side_opp] = co; + butal_neighbor->dists[side_opp] = 0.0f; + } + /* See definition of UI_BUT_ALIGN_STITCH_LEFT/TOP for reason of this... */ + else if (side == LEFT) { + butal->but->drawflag |= UI_BUT_ALIGN_STITCH_LEFT; + } + else if (side == TOP) { + butal->but->drawflag |= UI_BUT_ALIGN_STITCH_TOP; + } + *butal->borders[side] = co; + butal->dists[side] = 0.0f; + /* Clearing one of the 'flags pair' here is enough to prevent this loop running on + * the same column, side and direction again. */ + butal->flags[side] &= ~stitch_s2; + } } /** @@ -316,61 +329,61 @@ static void block_align_stitch_neighbors( */ static int ui_block_align_butal_cmp(const void *a, const void *b) { - const ButAlign *butal = a; - const ButAlign *butal_other = b; - - /* Sort by align group. */ - if (butal->but->alignnr != butal_other->but->alignnr) { - return butal->but->alignnr - butal_other->but->alignnr; - } - - /* Sort vertically. - * Note that Y of buttons is decreasing (first buttons have higher Y value than later ones). */ - if (*butal->borders[TOP] != *butal_other->borders[TOP]) { - return (*butal_other->borders[TOP] > *butal->borders[TOP]) ? 1 : -1; - } - - /* Sort horizontally. */ - if (*butal->borders[LEFT] != *butal_other->borders[LEFT]) { - return (*butal->borders[LEFT] > *butal_other->borders[LEFT]) ? 1 : -1; - } - - /* XXX We cannot actually assert here, since in some very compressed space cases, - * stupid UI code produces widgets which have the same TOP and LEFT positions... - * We do not care really, - * because this happens when UI is way too small to be usable anyway. */ - /* BLI_assert(0); */ - return 0; + const ButAlign *butal = a; + const ButAlign *butal_other = b; + + /* Sort by align group. */ + if (butal->but->alignnr != butal_other->but->alignnr) { + return butal->but->alignnr - butal_other->but->alignnr; + } + + /* Sort vertically. + * Note that Y of buttons is decreasing (first buttons have higher Y value than later ones). */ + if (*butal->borders[TOP] != *butal_other->borders[TOP]) { + return (*butal_other->borders[TOP] > *butal->borders[TOP]) ? 1 : -1; + } + + /* Sort horizontally. */ + if (*butal->borders[LEFT] != *butal_other->borders[LEFT]) { + return (*butal->borders[LEFT] > *butal_other->borders[LEFT]) ? 1 : -1; + } + + /* XXX We cannot actually assert here, since in some very compressed space cases, + * stupid UI code produces widgets which have the same TOP and LEFT positions... + * We do not care really, + * because this happens when UI is way too small to be usable anyway. */ + /* BLI_assert(0); */ + return 0; } static void ui_block_align_but_to_region(uiBut *but, const ARegion *region) { - rctf *rect = &but->rect; - const float but_width = BLI_rctf_size_x(rect); - const float but_height = BLI_rctf_size_y(rect); - const float outline_px = U.pixelsize; /* This may have to be made more variable. */ - - switch (but->drawflag & UI_BUT_ALIGN) { - case UI_BUT_ALIGN_TOP: - rect->ymax = region->winy + outline_px; - rect->ymin = but->rect.ymax - but_height; - break; - case UI_BUT_ALIGN_DOWN: - rect->ymin = -outline_px; - rect->ymax = rect->ymin + but_height; - break; - case UI_BUT_ALIGN_LEFT: - rect->xmin = -outline_px; - rect->xmax = rect->xmin + but_width; - break; - case UI_BUT_ALIGN_RIGHT: - rect->xmax = region->winx + outline_px; - rect->xmin = rect->xmax - but_width; - break; - default: - BLI_assert(0); - break; - } + rctf *rect = &but->rect; + const float but_width = BLI_rctf_size_x(rect); + const float but_height = BLI_rctf_size_y(rect); + const float outline_px = U.pixelsize; /* This may have to be made more variable. */ + + switch (but->drawflag & UI_BUT_ALIGN) { + case UI_BUT_ALIGN_TOP: + rect->ymax = region->winy + outline_px; + rect->ymin = but->rect.ymax - but_height; + break; + case UI_BUT_ALIGN_DOWN: + rect->ymin = -outline_px; + rect->ymax = rect->ymin + but_height; + break; + case UI_BUT_ALIGN_LEFT: + rect->xmin = -outline_px; + rect->xmax = rect->xmin + but_width; + break; + case UI_BUT_ALIGN_RIGHT: + rect->xmax = region->winx + outline_px; + rect->xmin = rect->xmax - but_width; + break; + default: + BLI_assert(0); + break; + } } /** @@ -381,350 +394,355 @@ static void ui_block_align_but_to_region(uiBut *but, const ARegion *region) */ void ui_block_align_calc(uiBlock *block, const ARegion *region) { - uiBut *but; - int num_buttons = 0; - - const int sides_to_ui_but_align_flags[4] = SIDE_TO_UI_BUT_ALIGN; - - ButAlign *butal_array; - ButAlign *butal, *butal_other; - int side; - int i, j; - - /* First loop: we count number of buttons belonging to an align group, and clear their align flag. - * Tabs get some special treatment here, they get aligned to region border. */ - for (but = block->buttons.first; but; but = but->next) { - /* special case: tabs need to be aligned to a region border, drawflag tells which one */ - if (but->type == UI_BTYPE_TAB) { - ui_block_align_but_to_region(but, region); - } - else { - /* Clear old align flags. */ - but->drawflag &= ~UI_BUT_ALIGN_ALL; - } - - if (but->alignnr != 0) { - num_buttons++; - } - } - - if (num_buttons < 2) { - /* No need to go further if we have nothing to align... */ - return; - } - - butal_array = alloca(sizeof(*butal_array) * (size_t)num_buttons); - memset(butal_array, 0, sizeof(*butal_array) * (size_t)num_buttons); - - /* Second loop: we initialize our ButAlign data for each button. */ - for (but = block->buttons.first, butal = butal_array; but; but = but->next) { - if (but->alignnr != 0) { - butal->but = but; - butal->borders[LEFT] = &but->rect.xmin; - butal->borders[RIGHT] = &but->rect.xmax; - butal->borders[DOWN] = &but->rect.ymin; - butal->borders[TOP] = &but->rect.ymax; - copy_v4_fl(butal->dists, FLT_MAX); - butal++; - } - } - - /* This will give us ButAlign items regrouped by align group, vertical and horizontal location. - * Note that, given how buttons are defined in UI code, - * butal_array shall already be "nearly sorted"... */ - qsort(butal_array, (size_t)num_buttons, sizeof(*butal_array), ui_block_align_butal_cmp); - - /* Third loop: for each pair of buttons in the same align group, - * we compute their potential proximity. Note that each pair is checked only once, and that we - * break early in case we know all remaining pairs will always be too far away. */ - for (i = 0, butal = butal_array; i < num_buttons; i++, butal++) { - const short alignnr = butal->but->alignnr; - - for (j = i + 1, butal_other = &butal_array[i + 1]; j < num_buttons; j++, butal_other++) { - const float max_delta = MAX_DELTA; - - /* Since they are sorted, buttons after current butal can only be of same or higher - * group, and once they are not of same group, we know we can break this sub-loop and - * start checking with next butal. */ - if (butal_other->but->alignnr != alignnr) { - break; - } - - /* Since they are sorted vertically first, buttons after current butal can only be at - * same or lower height, and once they are lower than a given threshold, we know we can - * break this sub-loop and start checking with next butal. */ - if ((*butal->borders[DOWN] - *butal_other->borders[TOP]) > max_delta) { - break; - } - - block_align_proximity_compute(butal, butal_other); - } - } - - /* Fourth loop: we have all our 'aligned' buttons as a 'map' in butal_array. We need to: - * - update their relevant coordinates to stitch them. - * - assign them valid flags. - */ - for (i = 0; i < num_buttons; i++) { - butal = &butal_array[i]; - - for (side = 0; side < TOTSIDES; side++) { - butal_other = butal->neighbors[side]; - - if (butal_other) { - const int side_opp = OPPOSITE(side); - const int side_s1 = SIDE1(side); - const int side_s2 = SIDE2(side); - - const int align = sides_to_ui_but_align_flags[side]; - const int align_opp = sides_to_ui_but_align_flags[side_opp]; - - float co; - - butal->but->drawflag |= align; - butal_other->but->drawflag |= align_opp; - if (butal->dists[side]) { - float *delta = &butal->dists[side]; - - if (*butal->borders[side] < *butal_other->borders[side_opp]) { - *delta *= 0.5f; - } - else { - *delta *= -0.5f; - } - co = (*butal->borders[side] += *delta); - - if (butal_other->dists[side_opp]) { - BLI_assert(butal_other->dists[side_opp] * 0.5f == fabsf(*delta)); - *butal_other->borders[side_opp] = co; - butal_other->dists[side_opp] = 0.0f; - } - *delta = 0.0f; - } - else { - co = *butal->borders[side]; - } - - block_align_stitch_neighbors(butal, side, side_opp, side_s1, side_s2, align, align_opp, co); - block_align_stitch_neighbors(butal, side, side_opp, side_s2, side_s1, align, align_opp, co); - } - } - } + uiBut *but; + int num_buttons = 0; + + const int sides_to_ui_but_align_flags[4] = SIDE_TO_UI_BUT_ALIGN; + + ButAlign *butal_array; + ButAlign *butal, *butal_other; + int side; + int i, j; + + /* First loop: we count number of buttons belonging to an align group, and clear their align flag. + * Tabs get some special treatment here, they get aligned to region border. */ + for (but = block->buttons.first; but; but = but->next) { + /* special case: tabs need to be aligned to a region border, drawflag tells which one */ + if (but->type == UI_BTYPE_TAB) { + ui_block_align_but_to_region(but, region); + } + else { + /* Clear old align flags. */ + but->drawflag &= ~UI_BUT_ALIGN_ALL; + } + + if (but->alignnr != 0) { + num_buttons++; + } + } + + if (num_buttons < 2) { + /* No need to go further if we have nothing to align... */ + return; + } + + butal_array = alloca(sizeof(*butal_array) * (size_t)num_buttons); + memset(butal_array, 0, sizeof(*butal_array) * (size_t)num_buttons); + + /* Second loop: we initialize our ButAlign data for each button. */ + for (but = block->buttons.first, butal = butal_array; but; but = but->next) { + if (but->alignnr != 0) { + butal->but = but; + butal->borders[LEFT] = &but->rect.xmin; + butal->borders[RIGHT] = &but->rect.xmax; + butal->borders[DOWN] = &but->rect.ymin; + butal->borders[TOP] = &but->rect.ymax; + copy_v4_fl(butal->dists, FLT_MAX); + butal++; + } + } + + /* This will give us ButAlign items regrouped by align group, vertical and horizontal location. + * Note that, given how buttons are defined in UI code, + * butal_array shall already be "nearly sorted"... */ + qsort(butal_array, (size_t)num_buttons, sizeof(*butal_array), ui_block_align_butal_cmp); + + /* Third loop: for each pair of buttons in the same align group, + * we compute their potential proximity. Note that each pair is checked only once, and that we + * break early in case we know all remaining pairs will always be too far away. */ + for (i = 0, butal = butal_array; i < num_buttons; i++, butal++) { + const short alignnr = butal->but->alignnr; + + for (j = i + 1, butal_other = &butal_array[i + 1]; j < num_buttons; j++, butal_other++) { + const float max_delta = MAX_DELTA; + + /* Since they are sorted, buttons after current butal can only be of same or higher + * group, and once they are not of same group, we know we can break this sub-loop and + * start checking with next butal. */ + if (butal_other->but->alignnr != alignnr) { + break; + } + + /* Since they are sorted vertically first, buttons after current butal can only be at + * same or lower height, and once they are lower than a given threshold, we know we can + * break this sub-loop and start checking with next butal. */ + if ((*butal->borders[DOWN] - *butal_other->borders[TOP]) > max_delta) { + break; + } + + block_align_proximity_compute(butal, butal_other); + } + } + + /* Fourth loop: we have all our 'aligned' buttons as a 'map' in butal_array. We need to: + * - update their relevant coordinates to stitch them. + * - assign them valid flags. + */ + for (i = 0; i < num_buttons; i++) { + butal = &butal_array[i]; + + for (side = 0; side < TOTSIDES; side++) { + butal_other = butal->neighbors[side]; + + if (butal_other) { + const int side_opp = OPPOSITE(side); + const int side_s1 = SIDE1(side); + const int side_s2 = SIDE2(side); + + const int align = sides_to_ui_but_align_flags[side]; + const int align_opp = sides_to_ui_but_align_flags[side_opp]; + + float co; + + butal->but->drawflag |= align; + butal_other->but->drawflag |= align_opp; + if (butal->dists[side]) { + float *delta = &butal->dists[side]; + + if (*butal->borders[side] < *butal_other->borders[side_opp]) { + *delta *= 0.5f; + } + else { + *delta *= -0.5f; + } + co = (*butal->borders[side] += *delta); + + if (butal_other->dists[side_opp]) { + BLI_assert(butal_other->dists[side_opp] * 0.5f == fabsf(*delta)); + *butal_other->borders[side_opp] = co; + butal_other->dists[side_opp] = 0.0f; + } + *delta = 0.0f; + } + else { + co = *butal->borders[side]; + } + + block_align_stitch_neighbors( + butal, side, side_opp, side_s1, side_s2, align, align_opp, co); + block_align_stitch_neighbors( + butal, side, side_opp, side_s2, side_s1, align, align_opp, co); + } + } + } } -#undef SIDE_TO_UI_BUT_ALIGN -#undef SIDE1 -#undef OPPOSITE -#undef SIDE2 -#undef IS_COLUMN -#undef STITCH -#undef MAX_DELTA +# undef SIDE_TO_UI_BUT_ALIGN +# undef SIDE1 +# undef OPPOSITE +# undef SIDE2 +# undef IS_COLUMN +# undef STITCH +# undef MAX_DELTA #else bool ui_but_can_align(uiBut *but) { - return !ELEM(but->type, UI_BTYPE_LABEL, UI_BTYPE_CHECKBOX, UI_BTYPE_CHECKBOX_N, - UI_BTYPE_SEPR, UI_BTYPE_SEPR_LINE, UI_BTYPE_SEPR_SPACER); + return !ELEM(but->type, + UI_BTYPE_LABEL, + UI_BTYPE_CHECKBOX, + UI_BTYPE_CHECKBOX_N, + UI_BTYPE_SEPR, + UI_BTYPE_SEPR_LINE, + UI_BTYPE_SEPR_SPACER); } static bool buts_are_horiz(uiBut *but1, uiBut *but2) { - float dx, dy; + float dx, dy; - /* simple case which can fail if buttons shift apart - * with proportional layouts, see: [#38602] */ - if ((but1->rect.ymin == but2->rect.ymin) && - (but1->rect.xmin != but2->rect.xmin)) - { - return true; - } + /* simple case which can fail if buttons shift apart + * with proportional layouts, see: [#38602] */ + if ((but1->rect.ymin == but2->rect.ymin) && (but1->rect.xmin != but2->rect.xmin)) { + return true; + } - dx = fabsf(but1->rect.xmax - but2->rect.xmin); - dy = fabsf(but1->rect.ymin - but2->rect.ymax); + dx = fabsf(but1->rect.xmax - but2->rect.xmin); + dy = fabsf(but1->rect.ymin - but2->rect.ymax); - return (dx <= dy); + return (dx <= dy); } static void ui_block_align_calc_but(uiBut *first, short nr) { - uiBut *prev, *but = NULL, *next; - int flag = 0, cols = 0, rows = 0; - - /* auto align */ - - for (but = first; but && but->alignnr == nr; but = but->next) { - if (but->next && but->next->alignnr == nr) { - if (buts_are_horiz(but, but->next)) { - cols++; - } - else { - rows++; - } - } - } - - /* rows == 0: 1 row, cols == 0: 1 column */ - - /* note; how it uses 'flag' in loop below (either set it, or OR it) is confusing */ - for (but = first, prev = NULL; but && but->alignnr == nr; prev = but, but = but->next) { - next = but->next; - if (next && next->alignnr != nr) { - next = NULL; - } - - /* clear old flag */ - but->drawflag &= ~UI_BUT_ALIGN; - - if (flag == 0) { /* first case */ - if (next) { - if (buts_are_horiz(but, next)) { - if (rows == 0) { - flag = UI_BUT_ALIGN_RIGHT; - } - else { - flag = UI_BUT_ALIGN_DOWN | UI_BUT_ALIGN_RIGHT; - } - } - else { - flag = UI_BUT_ALIGN_DOWN; - } - } - } - else if (next == NULL) { /* last case */ - if (prev) { - if (buts_are_horiz(prev, but)) { - if (rows == 0) { - flag = UI_BUT_ALIGN_LEFT; - } - else { - flag = UI_BUT_ALIGN_TOP | UI_BUT_ALIGN_LEFT; - } - } - else { - flag = UI_BUT_ALIGN_TOP; - } - } - } - else if (buts_are_horiz(but, next)) { - /* check if this is already second row */ - if (prev && buts_are_horiz(prev, but) == 0) { - flag &= ~UI_BUT_ALIGN_LEFT; - flag |= UI_BUT_ALIGN_TOP; - /* exception case: bottom row */ - if (rows > 0) { - uiBut *bt = but; - while (bt && bt->alignnr == nr) { - if (bt->next && bt->next->alignnr == nr && buts_are_horiz(bt, bt->next) == 0) { - break; - } - bt = bt->next; - } - if (bt == NULL || bt->alignnr != nr) { - flag = UI_BUT_ALIGN_TOP | UI_BUT_ALIGN_RIGHT; - } - } - } - else { - flag |= UI_BUT_ALIGN_LEFT; - } - } - else { - if (cols == 0) { - flag |= UI_BUT_ALIGN_TOP; - } - else { /* next button switches to new row */ - - if (prev && buts_are_horiz(prev, but)) { - flag |= UI_BUT_ALIGN_LEFT; - } - else { - flag &= ~UI_BUT_ALIGN_LEFT; - flag |= UI_BUT_ALIGN_TOP; - } - - if ((flag & UI_BUT_ALIGN_TOP) == 0) { /* still top row */ - if (prev) { - if (next && buts_are_horiz(but, next)) { - flag = UI_BUT_ALIGN_DOWN | UI_BUT_ALIGN_LEFT | UI_BUT_ALIGN_RIGHT; - } - else { - /* last button in top row */ - flag = UI_BUT_ALIGN_DOWN | UI_BUT_ALIGN_LEFT; - } - } - else { - flag |= UI_BUT_ALIGN_DOWN; - } - } - else { - flag |= UI_BUT_ALIGN_TOP; - } - } - } - - but->drawflag |= flag; - - /* merge coordinates */ - if (prev) { - /* simple cases */ - if (rows == 0) { - but->rect.xmin = (prev->rect.xmax + but->rect.xmin) / 2.0f; - prev->rect.xmax = but->rect.xmin; - } - else if (cols == 0) { - but->rect.ymax = (prev->rect.ymin + but->rect.ymax) / 2.0f; - prev->rect.ymin = but->rect.ymax; - } - else { - if (buts_are_horiz(prev, but)) { - but->rect.xmin = (prev->rect.xmax + but->rect.xmin) / 2.0f; - prev->rect.xmax = but->rect.xmin; - /* copy height too */ - but->rect.ymax = prev->rect.ymax; - } - else if (prev->prev && buts_are_horiz(prev->prev, prev) == 0) { - /* the previous button is a single one in its row */ - but->rect.ymax = (prev->rect.ymin + but->rect.ymax) / 2.0f; - prev->rect.ymin = but->rect.ymax; - - but->rect.xmin = prev->rect.xmin; - if (next && buts_are_horiz(but, next) == 0) { - but->rect.xmax = prev->rect.xmax; - } - } - else { - /* the previous button is not a single one in its row */ - but->rect.ymax = prev->rect.ymin; - } - } - } - } + uiBut *prev, *but = NULL, *next; + int flag = 0, cols = 0, rows = 0; + + /* auto align */ + + for (but = first; but && but->alignnr == nr; but = but->next) { + if (but->next && but->next->alignnr == nr) { + if (buts_are_horiz(but, but->next)) { + cols++; + } + else { + rows++; + } + } + } + + /* rows == 0: 1 row, cols == 0: 1 column */ + + /* note; how it uses 'flag' in loop below (either set it, or OR it) is confusing */ + for (but = first, prev = NULL; but && but->alignnr == nr; prev = but, but = but->next) { + next = but->next; + if (next && next->alignnr != nr) { + next = NULL; + } + + /* clear old flag */ + but->drawflag &= ~UI_BUT_ALIGN; + + if (flag == 0) { /* first case */ + if (next) { + if (buts_are_horiz(but, next)) { + if (rows == 0) { + flag = UI_BUT_ALIGN_RIGHT; + } + else { + flag = UI_BUT_ALIGN_DOWN | UI_BUT_ALIGN_RIGHT; + } + } + else { + flag = UI_BUT_ALIGN_DOWN; + } + } + } + else if (next == NULL) { /* last case */ + if (prev) { + if (buts_are_horiz(prev, but)) { + if (rows == 0) { + flag = UI_BUT_ALIGN_LEFT; + } + else { + flag = UI_BUT_ALIGN_TOP | UI_BUT_ALIGN_LEFT; + } + } + else { + flag = UI_BUT_ALIGN_TOP; + } + } + } + else if (buts_are_horiz(but, next)) { + /* check if this is already second row */ + if (prev && buts_are_horiz(prev, but) == 0) { + flag &= ~UI_BUT_ALIGN_LEFT; + flag |= UI_BUT_ALIGN_TOP; + /* exception case: bottom row */ + if (rows > 0) { + uiBut *bt = but; + while (bt && bt->alignnr == nr) { + if (bt->next && bt->next->alignnr == nr && buts_are_horiz(bt, bt->next) == 0) { + break; + } + bt = bt->next; + } + if (bt == NULL || bt->alignnr != nr) { + flag = UI_BUT_ALIGN_TOP | UI_BUT_ALIGN_RIGHT; + } + } + } + else { + flag |= UI_BUT_ALIGN_LEFT; + } + } + else { + if (cols == 0) { + flag |= UI_BUT_ALIGN_TOP; + } + else { /* next button switches to new row */ + + if (prev && buts_are_horiz(prev, but)) { + flag |= UI_BUT_ALIGN_LEFT; + } + else { + flag &= ~UI_BUT_ALIGN_LEFT; + flag |= UI_BUT_ALIGN_TOP; + } + + if ((flag & UI_BUT_ALIGN_TOP) == 0) { /* still top row */ + if (prev) { + if (next && buts_are_horiz(but, next)) { + flag = UI_BUT_ALIGN_DOWN | UI_BUT_ALIGN_LEFT | UI_BUT_ALIGN_RIGHT; + } + else { + /* last button in top row */ + flag = UI_BUT_ALIGN_DOWN | UI_BUT_ALIGN_LEFT; + } + } + else { + flag |= UI_BUT_ALIGN_DOWN; + } + } + else { + flag |= UI_BUT_ALIGN_TOP; + } + } + } + + but->drawflag |= flag; + + /* merge coordinates */ + if (prev) { + /* simple cases */ + if (rows == 0) { + but->rect.xmin = (prev->rect.xmax + but->rect.xmin) / 2.0f; + prev->rect.xmax = but->rect.xmin; + } + else if (cols == 0) { + but->rect.ymax = (prev->rect.ymin + but->rect.ymax) / 2.0f; + prev->rect.ymin = but->rect.ymax; + } + else { + if (buts_are_horiz(prev, but)) { + but->rect.xmin = (prev->rect.xmax + but->rect.xmin) / 2.0f; + prev->rect.xmax = but->rect.xmin; + /* copy height too */ + but->rect.ymax = prev->rect.ymax; + } + else if (prev->prev && buts_are_horiz(prev->prev, prev) == 0) { + /* the previous button is a single one in its row */ + but->rect.ymax = (prev->rect.ymin + but->rect.ymax) / 2.0f; + prev->rect.ymin = but->rect.ymax; + + but->rect.xmin = prev->rect.xmin; + if (next && buts_are_horiz(but, next) == 0) { + but->rect.xmax = prev->rect.xmax; + } + } + else { + /* the previous button is not a single one in its row */ + but->rect.ymax = prev->rect.ymin; + } + } + } + } } void ui_block_align_calc(uiBlock *block) { - uiBut *but; - short nr; - - /* align buttons with same align nr */ - for (but = block->buttons.first; but; ) { - if (but->alignnr) { - nr = but->alignnr; - ui_block_align_calc_but(but, nr); - - /* skip with same number */ - for (; but && but->alignnr == nr; but = but->next) { - /* pass */ - } - - if (!but) { - break; - } - } - else { - but = but->next; - } - } + uiBut *but; + short nr; + + /* align buttons with same align nr */ + for (but = block->buttons.first; but;) { + if (but->alignnr) { + nr = but->alignnr; + ui_block_align_calc_but(but, nr); + + /* skip with same number */ + for (; but && but->alignnr == nr; but = but->next) { + /* pass */ + } + + if (!but) { + break; + } + } + else { + but = but->next; + } + } } #endif |