[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