[Bf-blender-cvs] [c9ed78733cc] blender2.8: UI: fixes for 3D viewport popovers moving / flipping on edits.

Brecht Van Lommel noreply at git.blender.org
Sun May 6 20:16:52 CEST 2018


Commit: c9ed78733cc99296e90434f085651cc83fe0a7d1
Author: Brecht Van Lommel
Date:   Sun May 6 18:08:27 2018 +0200
Branches: blender2.8
https://developer.blender.org/rBc9ed78733cc99296e90434f085651cc83fe0a7d1

UI: fixes for 3D viewport popovers moving / flipping on edits.

* Ensure popover does not change direction or location.
* Open popover towards the relevant editor, like pulldown menus.
* Use a bigger maximum assumed size to deal with some corner cases.
* Do proper 3D viewport header refresh on shading mode changes.

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

M	source/blender/editors/interface/interface_intern.h
M	source/blender/editors/interface/interface_region_popover.c
M	source/blender/editors/interface/interface_region_popup.c
M	source/blender/editors/interface/interface_widgets.c
M	source/blender/editors/space_view3d/space_view3d.c

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

diff --git a/source/blender/editors/interface/interface_intern.h b/source/blender/editors/interface/interface_intern.h
index e6f40d758d1..de2217a3d3e 100644
--- a/source/blender/editors/interface/interface_intern.h
+++ b/source/blender/editors/interface/interface_intern.h
@@ -551,6 +551,7 @@ struct uiPopupBlockHandle {
 	struct uiPopupBlockCreate popup_create_vars;
 	/* true if we can re-create the popup using 'popup_create_vars' */
 	bool can_refresh;
+	bool refresh;
 
 	struct wmTimer *scrolltimer;
 
@@ -572,8 +573,14 @@ struct uiPopupBlockHandle {
 	/* menu direction */
 	int direction;
 
-	/* previous rect for refresh */
+	/* Previous values so we don't resize or reposition on refresh. */
 	rctf prev_block_rect;
+	rctf prev_butrct;
+	short prev_dir1, prev_dir2;
+	int prev_mx, prev_my;
+
+	/* Maximum estimated size to avoid having to reposition on refresh. */
+	float max_size_x, max_size_y;
 
 /* #ifdef USE_DRAG_POPUP */
 	bool is_grab;
diff --git a/source/blender/editors/interface/interface_region_popover.c b/source/blender/editors/interface/interface_region_popover.c
index dea09393504..4dfa9198958 100644
--- a/source/blender/editors/interface/interface_region_popover.c
+++ b/source/blender/editors/interface/interface_region_popover.c
@@ -57,6 +57,8 @@
 
 #include "BKE_context.h"
 
+#include "ED_screen.h"
+
 #include "WM_api.h"
 #include "WM_types.h"
 
@@ -122,7 +124,7 @@ static uiBlock *ui_block_func_POPOVER(bContext *C, uiPopupBlockHandle *handle, v
 
 	UI_block_region_set(block, handle->region);
 	UI_block_layout_resolve(block, &width, &height);
-	UI_block_flag_enable(block, UI_BLOCK_MOVEMOUSE_QUIT | UI_BLOCK_KEEP_OPEN | UI_BLOCK_POPOVER);
+	UI_block_flag_enable(block, UI_BLOCK_MOVEMOUSE_QUIT | UI_BLOCK_KEEP_OPEN | UI_BLOCK_POPOVER | UI_BLOCK_NO_WIN_CLIP);
 	UI_block_direction_set(block, UI_DIR_DOWN | UI_DIR_CENTER_X);
 
 	const int block_margin = U.widget_unit / 2;
@@ -138,13 +140,32 @@ static uiBlock *ui_block_func_POPOVER(bContext *C, uiPopupBlockHandle *handle, v
 			UI_block_direction_set(block, UI_DIR_RIGHT);
 
 		/* Store the button location for positioning the popover arrow hint. */
-		{
+		if (!handle->refresh) {
 			float center[2] = {BLI_rctf_cent_x(&pup->but->rect), BLI_rctf_cent_y(&pup->but->rect)};
 			ui_block_to_window_fl(handle->ctx_region, pup->but->block, &center[0], &center[1]);
 			/* These variables aren't used for popovers, we could add new variables if there is a conflict. */
-			block->mx = (int)center[0];
-			block->my = (int)center[1];
+			handle->prev_mx = block->mx = (int)center[0];
+			handle->prev_my = block->my = (int)center[1];
+		}
+		else {
+			block->mx = handle->prev_mx;
+			block->my = handle->prev_my;
 		}
+
+		/* Prefer popover from header to be positioned into the editor. */
+		if (!slideout) {
+			ScrArea *sa = CTX_wm_area(C);
+			if (sa && ED_area_header_alignment(sa) == RGN_ALIGN_BOTTOM) {
+				ARegion *ar = CTX_wm_region(C);
+				if (ar && ar->regiontype == RGN_TYPE_HEADER) {
+					UI_block_direction_set(block, UI_DIR_UP | UI_DIR_CENTER_X);
+				}
+			}
+		}
+
+		/* Estimated a maximum size so we don't go offscreen for low height
+		 * areas near the bottom of the window on refreshes. */
+		handle->max_size_y = UI_UNIT_Y * 16.0f;
 	}
 	else {
 		/* Not attached to a button. */
diff --git a/source/blender/editors/interface/interface_region_popup.c b/source/blender/editors/interface/interface_region_popup.c
index cc194b41f1b..e971edb95cb 100644
--- a/source/blender/editors/interface/interface_region_popup.c
+++ b/source/blender/editors/interface/interface_region_popup.c
@@ -84,32 +84,38 @@ void ui_popup_translate(bContext *C, ARegion *ar, const int mdiff[2])
 }
 
 /* position block relative to but, result is in window space */
-static void ui_block_position(wmWindow *window, ARegion *butregion, uiBut *but, uiBlock *block)
+static void ui_popup_block_position(wmWindow *window, ARegion *butregion, uiBut *but, uiBlock *block)
 {
-	uiBut *bt;
-	uiSafetyRct *saferct;
+	uiPopupBlockHandle *handle = block->handle;
+
+	/* Compute button position in window coordinates using the source
+	 * button region/block, to position the popup attached to it. */
 	rctf butrct;
-	/*float aspect;*/ /*UNUSED*/
-	int size_x, size_y, offset_x = 0, offset_y = 0;
-	short dir1 = 0, dir2 = 0;
 
-	/* transform to window coordinates, using the source button region/block */
-	ui_block_to_window_rctf(butregion, but->block, &butrct, &but->rect);
+	if (!handle->refresh) {
+		ui_block_to_window_rctf(butregion, but->block, &butrct, &but->rect);
+
+		/* widget_roundbox_set has this correction too, keep in sync */
+		if (but->type != UI_BTYPE_PULLDOWN) {
+			if (but->drawflag & UI_BUT_ALIGN_TOP)
+				butrct.ymax += U.pixelsize;
+			if (but->drawflag & UI_BUT_ALIGN_LEFT)
+				butrct.xmin -= U.pixelsize;
+		}
 
-	/* widget_roundbox_set has this correction too, keep in sync */
-	if (but->type != UI_BTYPE_PULLDOWN) {
-		if (but->drawflag & UI_BUT_ALIGN_TOP)
-			butrct.ymax += U.pixelsize;
-		if (but->drawflag & UI_BUT_ALIGN_LEFT)
-			butrct.xmin -= U.pixelsize;
+		handle->prev_butrct = butrct;
+	}
+	else {
+		/* For refreshes, keep same button position so popup doesn't move. */
+		butrct = handle->prev_butrct;
 	}
 
-	/* calc block rect */
+	/* Compute block size in window space, based on buttons contained in it. */
 	if (block->rect.xmin == 0.0f && block->rect.xmax == 0.0f) {
 		if (block->buttons.first) {
 			BLI_rctf_init_minmax(&block->rect);
 
-			for (bt = block->buttons.first; bt; bt = bt->next) {
+			for (uiBut *bt = block->buttons.first; bt; bt = bt->next) {
 				BLI_rctf_union(&block->rect, &bt->rect);
 			}
 		}
@@ -120,35 +126,34 @@ static void ui_block_position(wmWindow *window, ARegion *butregion, uiBut *but,
 		}
 	}
 
-	/* aspect = (float)(BLI_rcti_size_x(&block->rect) + 4);*/ /*UNUSED*/
 	ui_block_to_window_rctf(butregion, but->block, &block->rect, &block->rect);
 
-	//block->rect.xmin -= 2.0; block->rect.ymin -= 2.0;
-	//block->rect.xmax += 2.0; block->rect.ymax += 2.0;
+	/* Compute direction relative to button, based on available space. */
+	const int size_x = BLI_rctf_size_x(&block->rect) + 0.2f * UI_UNIT_X;  /* 4 for shadow */
+	const int size_y = BLI_rctf_size_y(&block->rect) + 0.2f * UI_UNIT_Y;
+	const int center_x = (block->direction & UI_DIR_CENTER_X) ? size_x / 2 : 0;
+	const int center_y = (block->direction & UI_DIR_CENTER_Y) ? size_y / 2 : 0;
 
-	size_x = BLI_rctf_size_x(&block->rect) + 0.2f * UI_UNIT_X;  /* 4 for shadow */
-	size_y = BLI_rctf_size_y(&block->rect) + 0.2f * UI_UNIT_Y;
-	/* aspect /= (float)size_x;*/ /*UNUSED*/
+	short dir1 = 0, dir2 = 0;
 
-	{
+	if (!handle->refresh) {
 		bool left = 0, right = 0, top = 0, down = 0;
-		// int offscreen;
 
 		const int win_x = WM_window_pixels_x(window);
 		const int win_y = WM_window_pixels_y(window);
-		// wm_window_get_size(window, &win_x, &win_y);
 
-		const int center_x = (block->direction & UI_DIR_CENTER_X) ? size_x / 2 : 0;
-		const int center_y = (block->direction & UI_DIR_CENTER_Y) ? size_y / 2 : 0;
+		/* Take into account maximum size so we don't have to flip on refresh. */
+		const float max_size_x = max_ff(size_x, handle->max_size_x);
+		const float max_size_y = max_ff(size_y, handle->max_size_y);
 
 		/* check if there's space at all */
-		if (butrct.xmin - size_x + center_x > 0.0f) left = 1;
-		if (butrct.xmax + size_x - center_x < win_x) right = 1;
-		if (butrct.ymin - size_y + center_y > 0.0f) down = 1;
-		if (butrct.ymax + size_y - center_y < win_y) top = 1;
+		if (butrct.xmin - max_size_x + center_x > 0.0f) left = 1;
+		if (butrct.xmax + max_size_x - center_x < win_x) right = 1;
+		if (butrct.ymin - max_size_y + center_y > 0.0f) down = 1;
+		if (butrct.ymax + max_size_y - center_y < win_y) top = 1;
 
 		if (top == 0 && down == 0) {
-			if (butrct.ymin - size_y < win_y - butrct.ymax - size_y)
+			if (butrct.ymin - max_size_y < win_y - butrct.ymax - max_size_y)
 				top = 1;
 			else
 				down = 1;
@@ -182,70 +187,57 @@ static void ui_block_position(wmWindow *window, ARegion *butregion, uiBut *but,
 			if (dir2 == UI_DIR_DOWN && down == 0) dir2 = UI_DIR_UP;
 		}
 
-		if (dir1 == UI_DIR_LEFT) {
-			offset_x = butrct.xmin - block->rect.xmax;
-			if (dir2 == UI_DIR_UP) offset_y = butrct.ymin - block->rect.ymin - center_y - MENU_PADDING;
-			else                   offset_y = butrct.ymax - block->rect.ymax + center_y + MENU_PADDING;
-		}
-		else if (dir1 == UI_DIR_RIGHT) {
-			offset_x = butrct.xmax - block->rect.xmin;
-			if (dir2 == UI_DIR_UP) offset_y = butrct.ymin - block->rect.ymin - center_y - MENU_PADDING;
-			else                   offset_y = butrct.ymax - block->rect.ymax + center_y + MENU_PADDING;
-		}
-		else if (dir1 == UI_DIR_UP) {
-			offset_y = butrct.ymax - block->rect.ymin;
-			if (dir2 == UI_DIR_RIGHT) offset_x = butrct.xmax - block->rect.xmax + center_x;
-			else                      offset_x = butrct.xmin - block->rect.xmin - center_x;
-			/* changed direction? */
-			if ((dir1 & block->direction) == 0) {
-				UI_block_order_flip(block);
-			}
-		}
-		else if (dir1 == UI_DIR_DOWN) {
-			offset_y = butrct.ymin - block->rect.ymax;
-			if (dir2 == UI_DIR_RIGHT) offset_x = butrct.xmax - block->rect.xmax + center_x;
-			else                      offset_x = butrct.xmin - block->rect.xmin - center_x;
-			/* changed direction? */
-			if ((dir1 & block->direction) == 0) {
-				UI_block_order_flip(block);
-			}
-		}
+		handle->prev_dir1 = dir1;
+		handle->prev_dir2 = dir2;
+	}
+	else {
+		/* For refreshes, keep same popup direct so popup doesn't move
+		 * to a totally different position while editing in it. */
+		dir1 = handle->prev_dir1;
+		dir2 = handle->prev_dir2;
+	}
 
-		/* Center over popovers for eg. */
-		if (block->direction & UI_DIR_CENTER_X) {
-			offset_x += BLI_rctf_size_x(&butrct) / ((dir2 == UI_DIR_LEFT) ? 2 : - 2);
-		}
+	/* Compute offset based on direction. */
+	int offset_x = 0, offset_y = 0;
 
-		/* and now we handle the exception; no space below or to top */
-		if (top == 0 && down == 0) {
-			if (dir1 == UI_DIR_LEFT || dir1 == UI_DIR_RIGHT) {
-				/* align with bottom of screen */
-				// offset_y = size_y; (not with menu scrolls)
-			}
+	if (dir1 == UI_DIR_LEFT) {
+		offset_x = butrct.xmin - block->rect.xmax;
+		if (di

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list