2018-04-22 17:16:39 +02:00
|
|
|
/*
|
|
|
|
* ***** 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) 2008 Blender Foundation.
|
|
|
|
* All rights reserved.
|
|
|
|
*
|
|
|
|
* Contributor(s): Blender Foundation
|
|
|
|
*
|
|
|
|
* ***** END GPL LICENSE BLOCK *****
|
|
|
|
*/
|
|
|
|
|
|
|
|
/** \file blender/editors/interface/interface_region_popover.c
|
|
|
|
* \ingroup edinterface
|
|
|
|
*
|
|
|
|
* Pop-Over Region
|
|
|
|
*
|
|
|
|
* \note This is very close to 'interface_region_menu_popup.c'
|
|
|
|
*
|
|
|
|
* We could even merge them, however menu logic is already over-loaded.
|
|
|
|
* PopOver's have the following differences.
|
|
|
|
*
|
|
|
|
* - UI is not constrained to a list.
|
|
|
|
* - Pressing a button won't close the pop-over.
|
|
|
|
* - Different draw style (to show this is has different behavior from a menu).
|
2018-04-23 08:09:47 +02:00
|
|
|
* - #PanelType are used instead of #MenuType.
|
2018-04-22 17:16:39 +02:00
|
|
|
* - No menu flipping support.
|
|
|
|
* - No moving the menu to fit the mouse cursor.
|
|
|
|
* - No key accelerators to access menu items
|
|
|
|
* (if we add support they would work differently).
|
|
|
|
* - No arrow key navigation.
|
|
|
|
* - No menu memory.
|
|
|
|
* - No title.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "MEM_guardedalloc.h"
|
|
|
|
|
|
|
|
#include "DNA_userdef_types.h"
|
|
|
|
|
|
|
|
#include "BLI_listbase.h"
|
|
|
|
|
|
|
|
#include "BLI_rect.h"
|
|
|
|
#include "BLI_utildefines.h"
|
|
|
|
|
|
|
|
#include "BKE_context.h"
|
|
|
|
|
|
|
|
#include "WM_api.h"
|
|
|
|
#include "WM_types.h"
|
|
|
|
|
|
|
|
|
|
|
|
#include "UI_interface.h"
|
|
|
|
|
|
|
|
#include "interface_intern.h"
|
|
|
|
#include "interface_regions_intern.h"
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
/** \name Popup Menu with Callback or String
|
|
|
|
* \{ */
|
|
|
|
|
|
|
|
struct uiPopover {
|
|
|
|
uiBlock *block;
|
|
|
|
uiLayout *layout;
|
|
|
|
uiBut *but;
|
|
|
|
|
|
|
|
uiMenuCreateFunc menu_func;
|
|
|
|
void *menu_arg;
|
|
|
|
};
|
|
|
|
|
2018-04-27 19:30:25 +02:00
|
|
|
static void ui_popover_create_block(bContext *C, uiPopover *pup, int opcontext)
|
2018-04-22 17:16:39 +02:00
|
|
|
{
|
2018-04-27 19:30:25 +02:00
|
|
|
uiStyle *style = UI_style_get_dpi();
|
2018-04-22 17:16:39 +02:00
|
|
|
|
2018-04-27 19:30:25 +02:00
|
|
|
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);
|
2018-04-22 17:16:39 +02:00
|
|
|
|
|
|
|
if (pup->but) {
|
2018-04-27 19:30:25 +02:00
|
|
|
if (pup->but->context) {
|
|
|
|
uiLayoutContextCopy(pup->layout, pup->but->context);
|
|
|
|
}
|
2018-04-22 17:16:39 +02:00
|
|
|
}
|
|
|
|
else {
|
2018-04-27 19:30:25 +02:00
|
|
|
/* 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;
|
2018-04-22 17:16:39 +02:00
|
|
|
}
|
2018-04-27 19:30:25 +02:00
|
|
|
}
|
2018-04-22 17:16:39 +02:00
|
|
|
|
2018-04-27 19:30:25 +02:00
|
|
|
static uiBlock *ui_block_func_POPOVER(bContext *C, uiPopupBlockHandle *handle, void *arg_pup)
|
|
|
|
{
|
|
|
|
uiPopover *pup = arg_pup;
|
2018-04-22 17:16:39 +02:00
|
|
|
|
2018-04-27 19:30:25 +02:00
|
|
|
/* 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);
|
2018-04-22 17:16:39 +02:00
|
|
|
|
2018-04-27 19:30:25 +02:00
|
|
|
if (pup->menu_func) {
|
|
|
|
pup->block->handle = handle;
|
|
|
|
pup->menu_func(C, pup->layout, pup->menu_arg);
|
|
|
|
pup->block->handle = NULL;
|
|
|
|
}
|
2018-04-22 17:16:39 +02:00
|
|
|
|
2018-04-27 19:30:25 +02:00
|
|
|
pup->layout = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Setup and resolve UI layout for block. */
|
|
|
|
uiBlock *block = pup->block;
|
|
|
|
int width, height;
|
2018-04-22 22:08:48 +02:00
|
|
|
|
2018-04-27 19:30:25 +02:00
|
|
|
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);
|
2018-04-22 22:08:48 +02:00
|
|
|
UI_block_direction_set(block, UI_DIR_DOWN | UI_DIR_CENTER_X);
|
2018-04-22 17:16:39 +02:00
|
|
|
|
2018-04-22 23:03:08 +02:00
|
|
|
const int block_margin = U.widget_unit / 2;
|
|
|
|
|
2018-04-27 19:30:25 +02:00
|
|
|
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. */
|
2018-04-23 10:02:10 +02:00
|
|
|
int offset[2] = {0, 0}; /* Dummy. */
|
2018-04-22 17:16:39 +02:00
|
|
|
UI_block_flag_enable(block, UI_BLOCK_LOOP);
|
|
|
|
UI_block_direction_set(block, block->direction);
|
2018-04-27 19:30:25 +02:00
|
|
|
block->minbounds = UI_MENU_WIDTH_MIN;
|
2018-04-22 23:03:08 +02:00
|
|
|
UI_block_bounds_set_popup(block, block_margin, offset[0], offset[1]);
|
2018-04-22 17:16:39 +02:00
|
|
|
}
|
|
|
|
|
2018-04-27 19:30:25 +02:00
|
|
|
return block;
|
|
|
|
}
|
2018-04-22 17:16:39 +02:00
|
|
|
|
2018-04-27 19:30:25 +02:00
|
|
|
static void ui_block_free_func_POPOVER(uiPopupBlockHandle *UNUSED(handle), void *arg_pup)
|
|
|
|
{
|
|
|
|
uiPopover *pup = arg_pup;
|
|
|
|
MEM_freeN(pup);
|
2018-04-22 17:16:39 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
uiPopupBlockHandle *ui_popover_panel_create(
|
|
|
|
bContext *C, ARegion *butregion, uiBut *but,
|
|
|
|
uiMenuCreateFunc menu_func, void *arg)
|
|
|
|
{
|
2018-04-27 19:30:25 +02:00
|
|
|
/* Create popover, buttons are created from callback. */
|
|
|
|
uiPopover *pup = MEM_callocN(sizeof(uiPopover), __func__);
|
2018-04-22 17:16:39 +02:00
|
|
|
pup->but = but;
|
|
|
|
pup->menu_func = menu_func;
|
|
|
|
pup->menu_arg = arg;
|
|
|
|
|
2018-04-27 19:30:25 +02:00
|
|
|
/* Create popup block. */
|
|
|
|
uiPopupBlockHandle *handle;
|
2018-04-22 17:16:39 +02:00
|
|
|
handle = ui_popup_block_create(C, butregion, but, NULL, ui_block_func_POPOVER, pup);
|
2018-04-27 19:30:25 +02:00
|
|
|
handle->popup_create_vars.free_func = ui_block_free_func_POPOVER;
|
2018-04-22 17:16:39 +02:00
|
|
|
|
2018-04-27 19:30:25 +02:00
|
|
|
/* Add handlers. If attached to a button, the button will already
|
|
|
|
* add a modal handler and pass on events. */
|
2018-04-22 17:16:39 +02:00
|
|
|
if (!but) {
|
2018-04-27 19:30:25 +02:00
|
|
|
wmWindow *window = CTX_wm_window(C);
|
2018-04-22 17:16:39 +02:00
|
|
|
UI_popup_handlers_add(C, &window->modalhandlers, handle, 0);
|
|
|
|
WM_event_add_mousemove(C);
|
2018-04-27 19:30:25 +02:00
|
|
|
handle->popup = true;
|
2018-04-22 17:16:39 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return handle;
|
|
|
|
}
|
|
|
|
|
|
|
|
/** \} */
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
/** \name Popup Menu API with begin & end
|
|
|
|
* \{ */
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Only return handler, and set optional title.
|
|
|
|
*/
|
2018-04-27 19:30:25 +02:00
|
|
|
uiPopover *UI_popover_begin(bContext *C)
|
2018-04-22 17:16:39 +02:00
|
|
|
{
|
|
|
|
uiPopover *pup = MEM_callocN(sizeof(uiPopover), "popover menu");
|
|
|
|
|
2018-04-27 19:30:25 +02:00
|
|
|
/* Opertor context default same as menus, change if needed. */
|
|
|
|
ui_popover_create_block(C, pup, WM_OP_EXEC_REGION_WIN);
|
2018-04-22 17:16:39 +02:00
|
|
|
|
|
|
|
/* create in advance so we can let buttons point to retval already */
|
|
|
|
pup->block->handle = MEM_callocN(sizeof(uiPopupBlockHandle), "uiPopupBlockHandle");
|
|
|
|
|
|
|
|
return pup;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* set the whole structure to work */
|
|
|
|
void UI_popover_end(bContext *C, uiPopover *pup)
|
|
|
|
{
|
2018-04-27 19:30:25 +02:00
|
|
|
/* Create popup block. No refresh support since the buttons were created
|
|
|
|
* between begin/end and we have no callback to recreate them. */
|
|
|
|
uiPopupBlockHandle *handle;
|
2018-04-22 17:16:39 +02:00
|
|
|
|
2018-04-27 19:30:25 +02:00
|
|
|
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;
|
2018-04-22 17:16:39 +02:00
|
|
|
|
2018-04-27 19:30:25 +02:00
|
|
|
/* Add handlers. */
|
|
|
|
wmWindow *window = CTX_wm_window(C);
|
|
|
|
UI_popup_handlers_add(C, &window->modalhandlers, handle, 0);
|
2018-04-22 17:16:39 +02:00
|
|
|
WM_event_add_mousemove(C);
|
2018-04-27 19:30:25 +02:00
|
|
|
handle->popup = true;
|
2018-04-22 17:16:39 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
uiLayout *UI_popover_layout(uiPopover *pup)
|
|
|
|
{
|
|
|
|
return pup->layout;
|
|
|
|
}
|
|
|
|
|
|
|
|
/** \} */
|
|
|
|
|
2018-04-23 08:09:47 +02:00
|
|
|
/* We may want to support this in future */
|
2018-04-22 17:16:39 +02:00
|
|
|
/* Similar to UI_popup_menu_invoke */
|
|
|
|
// int UI_popover_panel_invoke(bContext *C, const char *idname, ReportList *reports);
|