diff options
author | Brecht Van Lommel <brechtvanlommel@gmail.com> | 2018-05-06 19:08:27 +0300 |
---|---|---|
committer | Brecht Van Lommel <brechtvanlommel@gmail.com> | 2018-05-06 21:14:58 +0300 |
commit | c9ed78733cc99296e90434f085651cc83fe0a7d1 (patch) | |
tree | 1bac611ab7e22dfbbc6b36892ec31141a4bedb41 /source/blender/editors/interface/interface_region_popup.c | |
parent | 16e220c95929365e3e75479018bdbd71b0ad2981 (diff) |
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.
Diffstat (limited to 'source/blender/editors/interface/interface_region_popup.c')
-rw-r--r-- | source/blender/editors/interface/interface_region_popup.c | 182 |
1 files changed, 88 insertions, 94 deletions
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 (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) { + /* TODO: still do */ + UI_block_order_flip(block); } - -#if 0 /* seems redundant and causes issues with blocks inside big regions */ - /* or no space left or right */ - if (left == 0 && right == 0) { - if (dir1 == UI_DIR_UP || dir1 == UI_DIR_DOWN) { - /* align with left size of screen */ - offset_x = -block->rect.xmin + 5; - } + } + 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) { + /* TODO: still do */ + UI_block_order_flip(block); } -#endif - -#if 0 - /* clamp to window bounds, could be made into an option if its ever annoying */ - if ( (offscreen = (block->rect.ymin + offset_y)) < 0) offset_y -= offscreen; /* bottom */ - else if ((offscreen = (block->rect.ymax + offset_y) - winy) > 0) offset_y -= offscreen; /* top */ - if ( (offscreen = (block->rect.xmin + offset_x)) < 0) offset_x -= offscreen; /* left */ - else if ((offscreen = (block->rect.xmax + offset_x) - winx) > 0) offset_x -= offscreen; /* right */ -#endif } - /* apply offset, buttons in window coords */ + /* 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); + } - for (bt = block->buttons.first; bt; bt = bt->next) { + /* Apply offset, buttons in window coords. */ + for (uiBut *bt = block->buttons.first; bt; bt = bt->next) { ui_block_to_window_rctf(butregion, but->block, &bt->rect, &bt->rect); BLI_rctf_translate(&bt->rect, offset_x, offset_y); @@ -256,7 +248,7 @@ static void ui_block_position(wmWindow *window, ARegion *butregion, uiBut *but, BLI_rctf_translate(&block->rect, offset_x, offset_y); - /* safety calculus */ + /* Safety calculus. */ { const float midx = BLI_rctf_cent_x(&butrct); const float midy = BLI_rctf_cent_y(&butrct); @@ -286,7 +278,7 @@ static void ui_block_position(wmWindow *window, ARegion *butregion, uiBut *but, } /* keep a list of these, needed for pulldown menus */ - saferct = MEM_callocN(sizeof(uiSafetyRct), "uiSafetyRct"); + uiSafetyRct *saferct = MEM_callocN(sizeof(uiSafetyRct), "uiSafetyRct"); saferct->parent = butrct; saferct->safety = block->safety; BLI_freelistN(&block->saferct); @@ -481,7 +473,9 @@ uiBlock *ui_popup_block_refresh( uiBlock *block_old = ar->uiblocks.first; uiBlock *block; - BLI_assert(!block_old || handle->can_refresh == true); + handle->refresh = (block_old != NULL); + + BLI_assert(!handle->refresh || handle->can_refresh); #ifdef DEBUG wmEvent *event_back = window->eventstate; @@ -528,7 +522,7 @@ uiBlock *ui_popup_block_refresh( /* if this is being created from a button */ if (but) { block->aspect = but->block->aspect; - ui_block_position(window, butregion, but, block); + ui_popup_block_position(window, butregion, but, block); handle->direction = block->direction; } else { @@ -594,7 +588,7 @@ uiBlock *ui_popup_block_refresh( /* Avoid menu moving down and losing cursor focus by keeping it at * the same height. */ - if (block_old && handle->prev_block_rect.ymax > block->rect.ymax) { + if (handle->refresh && handle->prev_block_rect.ymax > block->rect.ymax) { float offset = handle->prev_block_rect.ymax - block->rect.ymax; ui_block_translate(block, 0, offset); block->rect.ymin = handle->prev_block_rect.ymin; |