UI: fix popover menus not refreshing when changing settings.

This commit is contained in:
2018-04-27 19:30:25 +02:00
parent a593cc046c
commit a14005c070
5 changed files with 105 additions and 140 deletions

View File

@@ -422,10 +422,7 @@ void UI_popup_menu_but_set(uiPopupMenu *pup, struct ARegion *butregion, uiBut *b
typedef struct uiPopover uiPopover; typedef struct uiPopover uiPopover;
uiPopover *UI_popover_begin( uiPopover *UI_popover_begin(struct bContext *C) ATTR_NONNULL();
struct bContext *C) ATTR_NONNULL();
uiPopover *UI_popover_begin_ex(
struct bContext *C, const char *block_name) ATTR_NONNULL();
void UI_popover_end(struct bContext *C, struct uiPopover *head); void UI_popover_end(struct bContext *C, struct uiPopover *head);
struct uiLayout *UI_popover_layout(uiPopover *head); struct uiLayout *UI_popover_layout(uiPopover *head);

View File

@@ -635,11 +635,8 @@ PointerRNA *ui_handle_afterfunc_add_operator(wmOperatorType *ot, int opcontext,
static void popup_check(bContext *C, wmOperator *op) static void popup_check(bContext *C, wmOperator *op)
{ {
if (op && op->type->check && op->type->check(C, op)) { if (op && op->type->check) {
/* check for popup and re-layout buttons */ op->type->check(C, op);
ARegion *ar_menu = CTX_wm_menu(C);
if (ar_menu)
ED_region_tag_refresh_ui(ar_menu);
} }
} }
@@ -7936,8 +7933,9 @@ static void button_activate_exit(
WM_cursor_modal_restore(data->window); WM_cursor_modal_restore(data->window);
} }
/* redraw (data is but->active!) */ /* redraw and refresh (for popups) */
ED_region_tag_redraw(data->region); ED_region_tag_redraw(data->region);
ED_region_tag_refresh_ui(data->region);
/* clean up button */ /* clean up button */
if (but->active) { if (but->active) {
@@ -8589,13 +8587,8 @@ static int ui_handle_list_event(bContext *C, const wmEvent *event, ARegion *ar,
} }
if (redraw) { if (redraw) {
if (listbox->block->flag & UI_BLOCK_POPUP) {
/* popups need special refreshing */
ED_region_tag_refresh_ui(ar);
}
else {
ED_region_tag_redraw(ar); ED_region_tag_redraw(ar);
} ED_region_tag_refresh_ui(ar);
} }
return retval; return retval;

View File

@@ -519,16 +519,19 @@ struct uiKeyNavLock {
}; };
typedef uiBlock * (*uiBlockHandleCreateFunc)(struct bContext *C, struct uiPopupBlockHandle *handle, void *arg1); typedef uiBlock * (*uiBlockHandleCreateFunc)(struct bContext *C, struct uiPopupBlockHandle *handle, void *arg1);
typedef void (*uiBlockHandleFreeFunc)(struct uiPopupBlockHandle *handle, void *arg1);
struct uiPopupBlockCreate { struct uiPopupBlockCreate {
uiBlockCreateFunc create_func; uiBlockCreateFunc create_func;
uiBlockHandleCreateFunc handle_create_func; uiBlockHandleCreateFunc handle_create_func;
uiBlockHandleFreeFunc free_func;
void *arg; void *arg;
int event_xy[2]; int event_xy[2];
/* when popup is initialized from a button */ /* when popup is initialized from a button */
ARegion *butregion; ARegion *butregion;
uiBut *but;
}; };
struct uiPopupBlockHandle { struct uiPopupBlockHandle {

View File

@@ -74,20 +74,42 @@ struct uiPopover {
uiBlock *block; uiBlock *block;
uiLayout *layout; uiLayout *layout;
uiBut *but; uiBut *but;
ARegion *butregion;
int mx, my;
bool popover, slideout;
uiMenuCreateFunc menu_func; uiMenuCreateFunc menu_func;
void *menu_arg; void *menu_arg;
}; };
static void ui_popover_create_block(bContext *C, uiPopover *pup, int opcontext)
{
uiStyle *style = UI_style_get_dpi();
pup->block = UI_block_begin(C, NULL, __func__, UI_EMBOSS);
pup->layout = UI_block_layout(
pup->block, UI_LAYOUT_VERTICAL, UI_LAYOUT_PANEL, 0, 0,
U.widget_unit * UI_POPOVER_WIDTH_UNITS, 0, MENU_PADDING, style);
uiLayoutSetOperatorContext(pup->layout, opcontext);
if (pup->but) {
if (pup->but->context) {
uiLayoutContextCopy(pup->layout, pup->but->context);
}
}
else {
/* Some enums reversing is strange, currently we have no good way to
* reverse some enum's but not others, so reverse all so the first menu
* items are always close to the mouse cursor. */
pup->block->flag |= UI_BLOCK_NO_FLIP;
}
}
static uiBlock *ui_block_func_POPOVER(bContext *C, uiPopupBlockHandle *handle, void *arg_pup) static uiBlock *ui_block_func_POPOVER(bContext *C, uiPopupBlockHandle *handle, void *arg_pup)
{ {
uiBlock *block;
uiPopover *pup = arg_pup; uiPopover *pup = arg_pup;
int minwidth, width, height;
/* Create UI block and layout now if it wasn't done between begin/end. */
if (!pup->layout) {
ui_popover_create_block(C, pup, WM_OP_INVOKE_REGION_WIN);
if (pup->menu_func) { if (pup->menu_func) {
pup->block->handle = handle; pup->block->handle = handle;
@@ -95,100 +117,72 @@ static uiBlock *ui_block_func_POPOVER(bContext *C, uiPopupBlockHandle *handle, v
pup->block->handle = NULL; pup->block->handle = NULL;
} }
if (pup->but) { pup->layout = NULL;
/* minimum width to enforece */
minwidth = BLI_rctf_size_x(&pup->but->rect);
}
else {
minwidth = UI_MENU_WIDTH_MIN;
} }
block = pup->block; /* Setup and resolve UI layout for block. */
uiBlock *block = pup->block;
int width, height;
/* in some cases we create the block before the region,
* so we set it delayed here if necessary */
if (BLI_findindex(&handle->region->uiblocks, block) == -1)
UI_block_region_set(block, handle->region); UI_block_region_set(block, handle->region);
UI_block_layout_resolve(block, &width, &height); 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_direction_set(block, UI_DIR_DOWN | UI_DIR_CENTER_X); UI_block_direction_set(block, UI_DIR_DOWN | UI_DIR_CENTER_X);
const int block_margin = U.widget_unit / 2; const int block_margin = U.widget_unit / 2;
if (pup->popover) { if (pup->but) {
/* For a header menu we set the direction automatic. */
block->minbounds = BLI_rctf_size_x(&pup->but->rect);
UI_block_bounds_set_normal(block, block_margin);
/* If menu slides out of other menu, override direction. */
bool slideout = false; //ui_block_is_menu(pup->but->block);
if (slideout)
UI_block_direction_set(block, UI_DIR_RIGHT);
}
else {
/* Not attached to a button. */
int offset[2] = {0, 0}; /* Dummy. */ int offset[2] = {0, 0}; /* Dummy. */
UI_block_flag_enable(block, UI_BLOCK_LOOP); UI_block_flag_enable(block, UI_BLOCK_LOOP);
UI_block_direction_set(block, block->direction); UI_block_direction_set(block, block->direction);
block->minbounds = minwidth; block->minbounds = UI_MENU_WIDTH_MIN;
UI_block_bounds_set_popup(block, block_margin, offset[0], offset[1]); UI_block_bounds_set_popup(block, block_margin, offset[0], offset[1]);
} }
else {
/* for a header menu we set the direction automatic */ return block;
block->minbounds = minwidth;
UI_block_bounds_set_normal(block, block_margin);
} }
/* if menu slides out of other menu, override direction */ static void ui_block_free_func_POPOVER(uiPopupBlockHandle *UNUSED(handle), void *arg_pup)
if (pup->slideout) {
UI_block_direction_set(block, UI_DIR_RIGHT); uiPopover *pup = arg_pup;
MEM_freeN(pup);
return pup->block;
} }
uiPopupBlockHandle *ui_popover_panel_create( uiPopupBlockHandle *ui_popover_panel_create(
bContext *C, ARegion *butregion, uiBut *but, bContext *C, ARegion *butregion, uiBut *but,
uiMenuCreateFunc menu_func, void *arg) uiMenuCreateFunc menu_func, void *arg)
{ {
wmWindow *window = CTX_wm_window(C); /* Create popover, buttons are created from callback. */
uiStyle *style = UI_style_get_dpi(); uiPopover *pup = MEM_callocN(sizeof(uiPopover), __func__);
uiPopupBlockHandle *handle;
uiPopover *pup;
pup = MEM_callocN(sizeof(uiPopover), __func__);
pup->block = UI_block_begin(C, NULL, __func__, UI_EMBOSS);
UI_block_emboss_set(pup->block, UI_EMBOSS);
pup->layout = UI_block_layout(
pup->block, UI_LAYOUT_VERTICAL, UI_LAYOUT_PANEL, 0, 0,
U.widget_unit * UI_POPOVER_WIDTH_UNITS, 0, MENU_PADDING, style);
pup->slideout = false; // but ? ui_block_is_menu(but->block) : false;
pup->but = but; pup->but = but;
uiLayoutSetOperatorContext(pup->layout, WM_OP_INVOKE_REGION_WIN);
if (!but) {
/* no button to start from, means we are a popover */
pup->mx = window->eventstate->x;
pup->my = window->eventstate->y;
pup->popover = true;
pup->block->flag |= UI_BLOCK_NO_FLIP;
}
/* some enums reversing is strange, currently we have no good way to
* reverse some enum's but not others, so reverse all so the first menu
* items are always close to the mouse cursor */
else {
if (but->context) {
uiLayoutContextCopy(pup->layout, but->context);
}
}
/* menu is created from a callback */
pup->menu_func = menu_func; pup->menu_func = menu_func;
pup->menu_arg = arg; pup->menu_arg = arg;
/* Create popup block. */
uiPopupBlockHandle *handle;
handle = ui_popup_block_create(C, butregion, but, NULL, ui_block_func_POPOVER, pup); handle = ui_popup_block_create(C, butregion, but, NULL, ui_block_func_POPOVER, pup);
handle->popup_create_vars.free_func = ui_block_free_func_POPOVER;
/* Add handlers. If attached to a button, the button will already
* add a modal handler and pass on events. */
if (!but) { if (!but) {
handle->popup = true; wmWindow *window = CTX_wm_window(C);
UI_popup_handlers_add(C, &window->modalhandlers, handle, 0); UI_popup_handlers_add(C, &window->modalhandlers, handle, 0);
WM_event_add_mousemove(C); WM_event_add_mousemove(C);
handle->popup = true;
} }
handle->can_refresh = false;
MEM_freeN(pup);
return handle; return handle;
} }
@@ -200,20 +194,13 @@ uiPopupBlockHandle *ui_popover_panel_create(
/** /**
* Only return handler, and set optional title. * Only return handler, and set optional title.
* \param block_name: Assigned to uiBlock.name (useful info for debugging).
*/ */
uiPopover *UI_popover_begin_ex(bContext *C, const char *block_name) uiPopover *UI_popover_begin(bContext *C)
{ {
uiStyle *style = UI_style_get_dpi();
uiPopover *pup = MEM_callocN(sizeof(uiPopover), "popover menu"); uiPopover *pup = MEM_callocN(sizeof(uiPopover), "popover menu");
pup->block = UI_block_begin(C, NULL, block_name, UI_EMBOSS); /* Opertor context default same as menus, change if needed. */
pup->layout = UI_block_layout( ui_popover_create_block(C, pup, WM_OP_EXEC_REGION_WIN);
pup->block, UI_LAYOUT_VERTICAL, UI_LAYOUT_PANEL, 0, 0,
U.widget_unit * UI_POPOVER_WIDTH_UNITS, 0, MENU_PADDING, style);
/* Copied from menus, change if needed. */
uiLayoutSetOperatorContext(pup->layout, WM_OP_EXEC_REGION_WIN);
/* create in advance so we can let buttons point to retval already */ /* create in advance so we can let buttons point to retval already */
pup->block->handle = MEM_callocN(sizeof(uiPopupBlockHandle), "uiPopupBlockHandle"); pup->block->handle = MEM_callocN(sizeof(uiPopupBlockHandle), "uiPopupBlockHandle");
@@ -221,47 +208,22 @@ uiPopover *UI_popover_begin_ex(bContext *C, const char *block_name)
return pup; return pup;
} }
uiPopover *UI_popover_begin(bContext *C)
{
return UI_popover_begin_ex(C, __func__);
}
/**
* Setting the button makes the popover open from the button instead of the cursor.
*/
#if 0
void UI_popover_panel_but_set(uiPopover *pup, struct ARegion *butregion, uiBut *but)
{
pup->but = but;
pup->butregion = butregion;
}
#endif
/* set the whole structure to work */ /* set the whole structure to work */
void UI_popover_end(bContext *C, uiPopover *pup) void UI_popover_end(bContext *C, uiPopover *pup)
{ {
/* Create popup block. No refresh support since the buttons were created
* between begin/end and we have no callback to recreate them. */
uiPopupBlockHandle *handle;
handle = ui_popup_block_create(C, NULL, NULL, NULL, ui_block_func_POPOVER, pup);
handle->popup_create_vars.free_func = ui_block_free_func_POPOVER;
handle->can_refresh = false;
/* Add handlers. */
wmWindow *window = CTX_wm_window(C); wmWindow *window = CTX_wm_window(C);
uiPopupBlockHandle *menu; UI_popup_handlers_add(C, &window->modalhandlers, handle, 0);
uiBut *but = NULL;
ARegion *butregion = NULL;
pup->popover = true;
pup->mx = window->eventstate->x;
pup->my = window->eventstate->y;
if (pup->but) {
but = pup->but;
butregion = pup->butregion;
}
menu = ui_popup_block_create(C, butregion, but, NULL, ui_block_func_POPOVER, pup);
menu->popup = true;
UI_popup_handlers_add(C, &window->modalhandlers, menu, 0);
WM_event_add_mousemove(C); WM_event_add_mousemove(C);
handle->popup = true;
menu->can_refresh = false;
MEM_freeN(pup);
} }
uiLayout *UI_popover_layout(uiPopover *pup) uiLayout *UI_popover_layout(uiPopover *pup)

View File

@@ -314,9 +314,11 @@ static void ui_block_region_refresh(const bContext *C, ARegion *ar)
ar->do_draw &= ~RGN_DRAW_REFRESH_UI; ar->do_draw &= ~RGN_DRAW_REFRESH_UI;
for (block = ar->uiblocks.first; block; block = block_next) { for (block = ar->uiblocks.first; block; block = block_next) {
block_next = block->next; block_next = block->next;
if (block->handle->can_refresh) { uiPopupBlockHandle *handle = block->handle;
handle_ctx_area = block->handle->ctx_area;
handle_ctx_region = block->handle->ctx_region; if (handle->can_refresh) {
handle_ctx_area = handle->ctx_area;
handle_ctx_region = handle->ctx_region;
if (handle_ctx_area) { if (handle_ctx_area) {
CTX_wm_area_set((bContext *)C, handle_ctx_area); CTX_wm_area_set((bContext *)C, handle_ctx_area);
@@ -324,7 +326,10 @@ static void ui_block_region_refresh(const bContext *C, ARegion *ar)
if (handle_ctx_region) { if (handle_ctx_region) {
CTX_wm_region_set((bContext *)C, handle_ctx_region); CTX_wm_region_set((bContext *)C, handle_ctx_region);
} }
ui_popup_block_refresh((bContext *)C, block->handle, NULL, NULL);
uiBut *but = handle->popup_create_vars.but;
ARegion *butregion = handle->popup_create_vars.butregion;
ui_popup_block_refresh((bContext *)C, handle, butregion, but);
} }
} }
} }
@@ -654,6 +659,7 @@ uiPopupBlockHandle *ui_popup_block_create(
handle->popup_create_vars.create_func = create_func; handle->popup_create_vars.create_func = create_func;
handle->popup_create_vars.handle_create_func = handle_create_func; handle->popup_create_vars.handle_create_func = handle_create_func;
handle->popup_create_vars.arg = arg; handle->popup_create_vars.arg = arg;
handle->popup_create_vars.but = but;
handle->popup_create_vars.butregion = but ? butregion : NULL; handle->popup_create_vars.butregion = but ? butregion : NULL;
copy_v2_v2_int(handle->popup_create_vars.event_xy, &window->eventstate->x); copy_v2_v2_int(handle->popup_create_vars.event_xy, &window->eventstate->x);
/* caller may free vars used to create this popup, in that case this variable should be disabled. */ /* caller may free vars used to create this popup, in that case this variable should be disabled. */
@@ -684,6 +690,10 @@ uiPopupBlockHandle *ui_popup_block_create(
void ui_popup_block_free(bContext *C, uiPopupBlockHandle *handle) void ui_popup_block_free(bContext *C, uiPopupBlockHandle *handle)
{ {
if (handle->popup_create_vars.free_func) {
handle->popup_create_vars.free_func(handle, handle->popup_create_vars.arg);
}
ui_popup_block_remove(C, handle); ui_popup_block_remove(C, handle);
MEM_freeN(handle); MEM_freeN(handle);