[Bf-blender-cvs] [3d39b98] master: New uialign code, based on 2D positions of widgets.

Bastien Montagne noreply at git.blender.org
Fri Nov 6 18:55:15 CET 2015


Commit: 3d39b98f94a6cd3d4445226dd04d5ba3261bf10b
Author: Bastien Montagne
Date:   Fri Nov 6 18:39:56 2015 +0100
Branches: master
https://developer.blender.org/rB3d39b98f94a6cd3d4445226dd04d5ba3261bf10b

New uialign code, based on 2D positions of widgets.

This new code fixes a tons of issues with previous one, which basically was epic-failing
in many non-basic cases (especially mixed columns and rows with column-dominant layout).

It basically no more relies over order of buttons declaration in the uiBlock, instead it
finds and stores spatial neighbors and uses that data to compute needed stitching.
See code comments for details.

New code seems to be roughly ten times slower than old one (for complex grouped layouts),
that is, about a few microsecconds per alignment group - this remains reasonable.

Also, ui-align code becomming rather big in itself, it was separated in
own new `interface_align.c` file.

Reviewers: campbellbarton, severin

Reviewed By: campbellbarton, severin

Differential Revision: https://developer.blender.org/D1573

===================================================================

M	source/blender/editors/include/UI_interface.h
M	source/blender/editors/interface/CMakeLists.txt
M	source/blender/editors/interface/interface.c
A	source/blender/editors/interface/interface_align.c
M	source/blender/editors/interface/interface_intern.h
M	source/blender/editors/interface/interface_layout.c
M	source/blender/editors/interface/interface_widgets.c

===================================================================

diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h
index ba3e3a6..4237e76 100644
--- a/source/blender/editors/include/UI_interface.h
+++ b/source/blender/editors/include/UI_interface.h
@@ -203,6 +203,12 @@ enum {
 	UI_BUT_ALIGN_RIGHT       = (1 << 16),
 	UI_BUT_ALIGN_DOWN        = (1 << 17),
 	UI_BUT_ALIGN             = (UI_BUT_ALIGN_TOP | UI_BUT_ALIGN_LEFT | UI_BUT_ALIGN_RIGHT | UI_BUT_ALIGN_DOWN),
+
+	/* Warning - HACK! Needed for buttons which are not TOP/LEFT aligned, but have some top/left corner stitched to some
+	 *                 other TOP/LEFT-aligned button, because of 'corrective' hack in widget_roundbox_set()... */
+	UI_BUT_ALIGN_STITCH_TOP  = (1 << 18),
+	UI_BUT_ALIGN_STITCH_LEFT = (1 << 19),
+	UI_BUT_ALIGN_ALL         = (UI_BUT_ALIGN | UI_BUT_ALIGN_STITCH_TOP | UI_BUT_ALIGN_STITCH_LEFT),
 };
 
 /* scale fixed button widths by this to account for DPI */
diff --git a/source/blender/editors/interface/CMakeLists.txt b/source/blender/editors/interface/CMakeLists.txt
index 3efb492..c57f8d5 100644
--- a/source/blender/editors/interface/CMakeLists.txt
+++ b/source/blender/editors/interface/CMakeLists.txt
@@ -40,6 +40,7 @@ set(INC_SYS
 
 set(SRC
 	interface.c
+	interface_align.c
 	interface_anim.c
 	interface_draw.c
 	interface_eyedropper.c
diff --git a/source/blender/editors/interface/interface.c b/source/blender/editors/interface/interface.c
index 28e1f54..1f0d105 100644
--- a/source/blender/editors/interface/interface.c
+++ b/source/blender/editors/interface/interface.c
@@ -2926,200 +2926,11 @@ void UI_block_align_begin(uiBlock *block)
 	/* buttons declared after this call will get this align nr */ // XXX flag?
 }
 
-static bool buts_are_horiz(uiBut *but1, uiBut *but2)
-{
-	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;
-	}
-
-	dx = fabsf(but1->rect.xmax - but2->rect.xmin);
-	dy = fabsf(but1->rect.ymin - but2->rect.ymax);
-	
-	return (dx <= dy);
-}
-
 void UI_block_align_end(uiBlock *block)
 {
 	block->flag &= ~UI_BUT_ALIGN;  /* all 4 flags */
 }
 
-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 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) {  /* stil 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;
-		}
-	}
-}
-
 struct ColorManagedDisplay *ui_block_cm_display_get(uiBlock *block)
 {
 	return IMB_colormanagement_display_get_named(block->display_device);
diff --git a/source/blender/editors/interface/interface_align.c b/source/blender/editors/interface/interface_align.c
new file mode 100644
index 0000000..4c0c12e
--- /dev/null
+++ b/source/blender/editors/interface/interface_align.c
@@ -0,0 +1,631 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2015 by Blender Foundation.
+ * All rights reserved.
+ *
+ * Contributor(s): Blender Foundation 2002-2008, full recode.
+ *                 Bastien Montagne 2015, full recode.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/editors/interface/interface_align.c
+ *  \ingroup edinterface
+ */
+
+#include "DNA_screen_types.h"
+#include "DNA_userdef_types.h"
+
+#include "BLI_alloca.h"
+#include "BLI_math.h"
+
+#include "UI_interface.h"
+
+#include "interface_intern.h"
+
+#ifdef USE_UIBUT_SPATIAL_ALIGN
+
+/**
+ * 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, which is rather lucky!
+ *
+ *       <pre>
+ *       +-----------+-----------+
+ *       |   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.
+ *       +-----------------------+
+ *       </pre>
+ *
+ *       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 ButAlign *neighbors[4];
+
+	/* Pointers to coordinates (rctf values) of the button. */
+	float *borders[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];
+} 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,
+};
+
+/* Mapping between 'our' sides and 'public' UI_BUT_ALIGN flags, order m

@@ Diff output truncated at 10240 characters. @@




More information about the Bf-blender-cvs mailing list