UI: fix popover menus not refreshing when changing settings.

This commit is contained in:
Brecht Van Lommel 2018-04-27 19:30:25 +02:00
parent a593cc046c
commit a14005c070
Notes: blender-bot 2023-02-14 08:06:35 +01:00
Referenced by commit 2d2f23de10, Fix T55348: Renaming a marker can't cancel
Referenced by issue #55348, Esc while naming marker doesn't work
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;
uiPopover *UI_popover_begin(
struct bContext *C) ATTR_NONNULL();
uiPopover *UI_popover_begin_ex(
struct bContext *C, const char *block_name) ATTR_NONNULL();
uiPopover *UI_popover_begin(struct bContext *C) ATTR_NONNULL();
void UI_popover_end(struct bContext *C, struct 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)
{
if (op && op->type->check && op->type->check(C, op)) {
/* check for popup and re-layout buttons */
ARegion *ar_menu = CTX_wm_menu(C);
if (ar_menu)
ED_region_tag_refresh_ui(ar_menu);
if (op && op->type->check) {
op->type->check(C, op);
}
}
@ -779,7 +776,7 @@ static void ui_apply_but_funcs_after(bContext *C)
if (after.popup_op)
popup_check(C, after.popup_op);
if (after.opptr) {
/* free in advance to avoid leak on exit */
opptr = *after.opptr;
@ -7936,8 +7933,9 @@ static void button_activate_exit(
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_refresh_ui(data->region);
/* clean up button */
if (but->active) {
@ -8589,13 +8587,8 @@ static int ui_handle_list_event(bContext *C, const wmEvent *event, ARegion *ar,
}
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;

View File

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

View File

@ -74,121 +74,115 @@ struct uiPopover {
uiBlock *block;
uiLayout *layout;
uiBut *but;
ARegion *butregion;
int mx, my;
bool popover, slideout;
uiMenuCreateFunc menu_func;
void *menu_arg;
};
static uiBlock *ui_block_func_POPOVER(bContext *C, uiPopupBlockHandle *handle, void *arg_pup)
static void ui_popover_create_block(bContext *C, uiPopover *pup, int opcontext)
{
uiBlock *block;
uiPopover *pup = arg_pup;
int minwidth, width, height;
uiStyle *style = UI_style_get_dpi();
if (pup->menu_func) {
pup->block->handle = handle;
pup->menu_func(C, pup->layout, pup->menu_arg);
pup->block->handle = NULL;
}
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) {
/* minimum width to enforece */
minwidth = BLI_rctf_size_x(&pup->but->rect);
if (pup->but->context) {
uiLayoutContextCopy(pup->layout, pup->but->context);
}
}
else {
minwidth = UI_MENU_WIDTH_MIN;
/* 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)
{
uiPopover *pup = arg_pup;
/* 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) {
pup->block->handle = handle;
pup->menu_func(C, pup->layout, pup->menu_arg);
pup->block->handle = NULL;
}
pup->layout = NULL;
}
block = pup->block;
/* 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);
/* Setup and resolve UI layout for block. */
uiBlock *block = pup->block;
int width, height;
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_direction_set(block, UI_DIR_DOWN | UI_DIR_CENTER_X);
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. */
UI_block_flag_enable(block, UI_BLOCK_LOOP);
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]);
}
else {
/* for a header menu we set the direction automatic */
block->minbounds = minwidth;
UI_block_bounds_set_normal(block, block_margin);
}
/* if menu slides out of other menu, override direction */
if (pup->slideout)
UI_block_direction_set(block, UI_DIR_RIGHT);
return block;
}
return pup->block;
static void ui_block_free_func_POPOVER(uiPopupBlockHandle *UNUSED(handle), void *arg_pup)
{
uiPopover *pup = arg_pup;
MEM_freeN(pup);
}
uiPopupBlockHandle *ui_popover_panel_create(
bContext *C, ARegion *butregion, uiBut *but,
uiMenuCreateFunc menu_func, void *arg)
{
wmWindow *window = CTX_wm_window(C);
uiStyle *style = UI_style_get_dpi();
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;
/* Create popover, buttons are created from callback. */
uiPopover *pup = MEM_callocN(sizeof(uiPopover), __func__);
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_arg = arg;
/* Create popup block. */
uiPopupBlockHandle *handle;
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) {
handle->popup = true;
wmWindow *window = CTX_wm_window(C);
UI_popup_handlers_add(C, &window->modalhandlers, handle, 0);
WM_event_add_mousemove(C);
handle->popup = true;
}
handle->can_refresh = false;
MEM_freeN(pup);
return handle;
}
@ -200,20 +194,13 @@ uiPopupBlockHandle *ui_popover_panel_create(
/**
* 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");
pup->block = UI_block_begin(C, NULL, block_name, 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);
/* Copied from menus, change if needed. */
uiLayoutSetOperatorContext(pup->layout, WM_OP_EXEC_REGION_WIN);
/* Opertor context default same as menus, change if needed. */
ui_popover_create_block(C, pup, WM_OP_EXEC_REGION_WIN);
/* create in advance so we can let buttons point to retval already */
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;
}
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 */
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);
uiPopupBlockHandle *menu;
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);
UI_popup_handlers_add(C, &window->modalhandlers, handle, 0);
WM_event_add_mousemove(C);
menu->can_refresh = false;
MEM_freeN(pup);
handle->popup = true;
}
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;
for (block = ar->uiblocks.first; block; block = block_next) {
block_next = block->next;
if (block->handle->can_refresh) {
handle_ctx_area = block->handle->ctx_area;
handle_ctx_region = block->handle->ctx_region;
uiPopupBlockHandle *handle = block->handle;
if (handle->can_refresh) {
handle_ctx_area = handle->ctx_area;
handle_ctx_region = handle->ctx_region;
if (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) {
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.handle_create_func = handle_create_func;
handle->popup_create_vars.arg = arg;
handle->popup_create_vars.but = but;
handle->popup_create_vars.butregion = but ? butregion : NULL;
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. */
@ -684,6 +690,10 @@ uiPopupBlockHandle *ui_popup_block_create(
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);
MEM_freeN(handle);