[Bf-blender-cvs] [c9cebbc] ui-align-rework: Huge cleanup, renaming and comments.
Bastien Montagne
noreply at git.blender.org
Thu Oct 22 16:32:24 CEST 2015
Commit: c9cebbcb118a10d57ae4aad6f21b935453851f80
Author: Bastien Montagne
Date: Thu Oct 22 09:22:13 2015 +0200
Branches: ui-align-rework
https://developer.blender.org/rBc9cebbcb118a10d57ae4aad6f21b935453851f80
Huge cleanup, renaming and comments.
Also fixed a few (logical) issues in code.
===================================================================
M source/blender/editors/interface/interface.c
===================================================================
diff --git a/source/blender/editors/interface/interface.c b/source/blender/editors/interface/interface.c
index 4e04810..019a939 100644
--- a/source/blender/editors/interface/interface.c
+++ b/source/blender/editors/interface/interface.c
@@ -2939,11 +2939,26 @@ void UI_block_align_end(uiBlock *block)
}
#ifdef NEW_ALIGN_CODE
-typedef struct uiButAlign {
+
+/**
+ * This struct stores a (simplified) 2D representation of all buttons of a same align group, with their
+ * immediate neighbors (if found), and needed value to compute 'stitching' of aligned buttons.
+ *
+ * \note This simplistic struct cannot fully represent complex layouts where buttons share some 'align space' with
+ * several others (see schema below), we'd need linked list and more complex code to handle that.
+ * However, looks like we can do without that for now, wich is rather lucky!
+ * +-----------+-----------+
+ * | BUT 1 | BUT 2 | BUT 3 has two 'top' neighbors...
+ * |-----------------------| => In practice, we only store one of BUT 1 or 2 (which ones is not
+ * | BUT 3 | really deterministic), and assume the other stores a ref to BUT 3.
+ * +-----------------------+
+ * This will probably not work in all possible cases, but not sure we want to support such exotic cases anyway.
+ */
+typedef struct ButAlign {
uiBut *but;
/* Neighbor buttons */
- struct uiButAlign *neighbors[4];
+ struct ButAlign *neighbors[4];
/* Pointers to coordinates (rctf values) of the button. */
float *borders[4];
@@ -2953,163 +2968,213 @@ typedef struct uiButAlign {
/* Flags, used to mark whether we should 'stitch' the corners of this button with its neighbors' ones. */
char flags[4];
-} uiButAlign;
+} 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,
+ /* Stict flags, built from sides values. */
STITCH_LEFT = 1 << LEFT,
STITCH_TOP = 1 << TOP,
STITCH_RIGHT = 1 << RIGHT,
STITCH_DOWN = 1 << DOWN,
};
-#define OPPOSITE(_s) (((_s) + 2) % 4)
-#define SIDE1(_s) (((_s) + 1) % 4)
-#define SIDE2(_s) (((_s) + 3) % 4)
+/* 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 STITCH(_s) (1 << ((_s) + 4))
+/* 0: LEFT/RIGHT sides; 1 = TOP/DOWN sides. */
+#define IS_COLUMN(_s) ((_s) % 2)
+
+/* Stich flag from side value. */
+#define STITCH(_s) (1 << (_s))
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);
}
-static int get_but_align_flag(const int i) {
- switch (i) {
- case LEFT:
- return UI_BUT_ALIGN_LEFT;
- case TOP:
- return UI_BUT_ALIGN_TOP;
- case RIGHT:
- return UI_BUT_ALIGN_RIGHT;
- case DOWN:
- return UI_BUT_ALIGN_DOWN;
- default:
- BLI_assert(0);
- return 0;
- }
-}
-
-/* Only the shortest diff (if below acceptable limits) is set, other pointers are set to NULL. */
-static void buts_proximity_compute(uiButAlign *but1, uiButAlign *but2)
+/**
+ * This function chacks a pair of buttons (assumed in a same align group), and if they are neighbors,
+ * set needed data accordingly.
+ *
+ * \note It is designed to be called in total random order of buttons.
+ */
+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 = 0.45f * max_ii(UI_UNIT_Y, UI_UNIT_X);
float delta;
- int i;
+ int side;
const bool buts_share[2] = {
/* Sharing same line? */
- !((*but1->borders[DOWN] >= *but2->borders[TOP]) || (*but1->borders[TOP] <= *but2->borders[DOWN])),
+ !((*butal->borders[DOWN] >= *butal_other->borders[TOP]) ||
+ (*butal->borders[TOP] <= *butal_other->borders[DOWN])),
/* Sharing same column? */
- !((*but1->borders[LEFT] >= *but2->borders[RIGHT]) || (*but1->borders[RIGHT] <= *but2->borders[LEFT])),
+ !((*butal->borders[LEFT] >= *butal_other->borders[RIGHT]) ||
+ (*butal->borders[RIGHT] <= *butal_other->borders[LEFT])),
};
- for (i = 0; i < 4; i++) {
- const int i_share = i % 2;
-
- if (buts_share[i_share]) {
- const int i_opp = OPPOSITE(i);
+ for (side = 0; side < TOTSIDES; 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)]) {
+ const int side_opp = OPPOSITE(side);
/* 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(*but1->borders[i] - *but2->borders[i_opp]), FLT_MIN);
+ delta = max_ff(fabsf(*butal->borders[side] - *butal_other->borders[side_opp]), FLT_MIN);
if (delta < max_delta) {
- if (delta <= but1->dists[i]) {
- const bool but1_can_align = ui_but_can_align(but1->but);
- const bool but2_can_align = ui_but_can_align(but2->but);
-
- if (!(but1_can_align || but2_can_align)) {
- continue;
- }
-
- if ((but1_can_align && (delta < but1->dists[i])) || (delta < but2->dists[i])) {
- if (but1_can_align && but2_can_align) {
- but1->neighbors[i] = but2;
- but2->neighbors[i_opp] = but1;
+ /* We are only interested in neighbors that are at least as close as already found ones. */
+ if ((delta <= butal->dists[side]) || (delta < butal_other->dists[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);
+
+ if ((delta < butal->dists[side]) || (delta < butal_other->dists[side_opp])) {
+ /* We found a 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 other's matching neighbor to NULL
+ * if its 'proximity distance' is really lower with current one. */
+ if (butal_can_align && butal_other_can_align) {
+ butal->neighbors[side] = butal_other;
+ butal_other->neighbors[side_opp] = butal;
}
- else if (but1_can_align) {
- but1->neighbors[i] = NULL;
+ else if (butal_can_align && (delta < butal->dists[side])) {
+ butal->neighbors[side] = NULL;
}
- else /* if (but2_can_align) */ {
- but2->neighbors[i_opp] = NULL;
+ else if (butal_other_can_align && (delta < butal_other->dists[side_opp])) {
+ butal_other->neighbors[side_opp] = NULL;
}
- but1->dists[i] = but2->dists[i_opp] = delta;
+ butal->dists[side] = butal_other->dists[side_opp] = delta;
}
- if (but1_can_align && but2_can_align) {
- const int i_s1 = SIDE1(i);
- const int i_s2 = SIDE2(i);
+ if (butal_can_align && butal_other_can_align) {
+ const int side_s1 = SIDE1(side);
+ const int side_s2 = SIDE2(side);
- const int stitch = STITCH(i);
- const int stitch_opp = STITCH(i_opp);
+ 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;
+ }
- delta = fabsf(*but1->borders[i_s1] - *but2->borders[i_s1]);
+ /* 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) {
- but1->flags[i_s1] |= stitch;
- but2->flags[i_s1] |= stitch_opp;
+ butal->flags[side_s1] |= stitch;
+ butal_other->flags[side_s1] |= stitch_opp;
}
- delta = fabsf(*but1->borders[i_s2] - *but2->borders[i_s2]);
+ delta = fabsf(*butal->borders[side_s2] - *butal_other->borders[side_s2]);
if (delta < max_delta) {
- but1->flags[i_s2] |= stitch;
- but2->flags[i_s2] |= stitch_opp;
+ 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;
}
}
}
}
-static void align_stitch_neighbors(
- uiButAlign *butal,
- const int i, const int i_opp, const int i_s1, const int i_s2,
+/**
+ * This function takes care of case described in this schema:
+ * +-----------+-----------+
+ * | BUT 1 | BUT 2 |
+ * |-----------------------+
+ * | BUT 3 |
+ * +-----------+
+ * Here, BUT 3 RIGHT side would not get 'dragged' to align with BUT 1 RIGHT side, since BUT 3 has not RIGHT neighbor.
+ * So, this function, when called with BUT 1, will 'walk' the whole column in side_s1 direction (TOP or DOWN when
+ * called for RIGHT side), and force buttons like BUT 3 to align as needed, if BUT 1 and BUT 3 were detected as needing
+ * top-right corner stitching in block_align_proximity_compute() step.
+ *
+ * \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)
{
- uiButAlign *butal_neighbor;
+ ButAlign *butal_neighbor;
+
+ const int stitch_s1 = STITCH(side_s1);
+ const int stitch_s2 = STITCH(side_s2);
// printf("%s (%d) (%f, %f)\n", butal->but->st
@@ Diff output truncated at 10240 characters. @@
More information about the Bf-blender-cvs
mailing list