UI: Support layout panels in dialog popups #119519
|
@ -712,6 +712,21 @@ int UI_popup_menu_invoke(bContext *C, const char *idname, ReportList *reports) A
|
|||
* E.g. WM might need to do this for exiting files correctly.
|
||||
*/
|
||||
void UI_popup_menu_retval_set(const uiBlock *block, int retval, bool enable);
|
||||
/**
|
||||
guishe marked this conversation as resolved
Outdated
|
||||
* Set a dummy panel in the popup `block` to support using layout panels, the panel is linked
|
||||
* to the popup `region` so layout panels state can be persistent until the popup is closed.
|
||||
*/
|
||||
void UI_popup_dummy_panel_set(ARegion *region, uiBlock *block);
|
||||
/** Toggles layout panel open state and returns the new state. */
|
||||
bool UI_layout_panel_toggle_open(const bContext *C, struct LayoutPanelHeader *header);
|
||||
void UI_panel_drag_collapse_handler_add(const bContext *C, const bool was_open);
|
||||
LayoutPanelHeader *UI_layout_panel_header_under_mouse(const Panel &panel, const int my);
|
||||
/** Apply scroll to layout panels when the main panel is used in popups. */
|
||||
void UI_layout_panel_popup_scroll_apply(Panel *panel, const float dy);
|
||||
void UI_draw_layout_panels_backdrop(const ARegion *region,
|
||||
const Panel *panel,
|
||||
const float radius,
|
||||
float subpanel_backcolor[4]);
|
||||
/**
|
||||
* Setting the button makes the popup open from the button instead of the cursor.
|
||||
*/
|
||||
|
|
|
@ -2096,6 +2096,15 @@ void UI_block_draw(const bContext *C, uiBlock *block)
|
|||
UI_panel_should_show_background(region, block->panel->type),
|
||||
region->flag & RGN_FLAG_SEARCH_FILTER_ACTIVE);
|
||||
}
|
||||
/* Shared layout panel backdrop style between redo region and popups. */
|
||||
guishe marked this conversation as resolved
Outdated
Jacques Lucke
commented
Comment style, same below. Comment style, same below.
|
||||
if (block->panel && ELEM(region->regiontype, RGN_TYPE_HUD, RGN_TYPE_TEMPORARY)) {
|
||||
/* TODO: Add as theme color. */
|
||||
guishe marked this conversation as resolved
Outdated
Jacques Lucke
commented
Comment style. Comment style.
|
||||
float subpanel_backcolor[4]{0.2f, 0.3f, 0.33f, 0.05f};
|
||||
const bTheme *btheme = UI_GetTheme();
|
||||
const float aspect = block->panel->runtime->block->aspect;
|
||||
const float radius = btheme->tui.panel_roundness * U.widget_unit * 0.5f / aspect;
|
||||
UI_draw_layout_panels_backdrop(region, block->panel, radius, subpanel_backcolor);
|
||||
}
|
||||
|
||||
BLF_batch_draw_begin();
|
||||
UI_icon_draw_cache_begin();
|
||||
|
|
|
@ -55,6 +55,7 @@
|
|||
#include "ED_undo.hh"
|
||||
|
||||
#include "UI_interface.hh"
|
||||
#include "UI_interface_c.hh"
|
||||
#include "UI_string_search.hh"
|
||||
|
||||
#include "BLF_api.hh"
|
||||
|
@ -10124,6 +10125,8 @@ static void ui_menu_scroll_apply_offset_y(ARegion *region, uiBlock *block, float
|
|||
|
||||
/* remember scroll offset for refreshes */
|
||||
block->handle->scrolloffset += dy;
|
||||
/* Apply popup scroll delta to layout panels too. */
|
||||
UI_layout_panel_popup_scroll_apply(block->panel, dy);
|
||||
|
||||
/* apply scroll offset */
|
||||
LISTBASE_FOREACH (uiBut *, bt, &block->buttons) {
|
||||
|
@ -11428,6 +11431,25 @@ static int ui_handle_menus_recursive(bContext *C,
|
|||
C, event, submenu, level + 1, is_parent_inside || inside, is_menu, false);
|
||||
}
|
||||
}
|
||||
else if (event->val == KM_PRESS && event->type == LEFTMOUSE) {
|
||||
LISTBASE_FOREACH (uiBlock *, block, &menu->region->uiblocks) {
|
||||
if (block->panel) {
|
||||
int mx = event->xy[0];
|
||||
int my = event->xy[1];
|
||||
ui_window_to_block(menu->region, block, &mx, &my);
|
||||
if (!IN_RANGE(float(mx), block->rect.xmin, block->rect.xmax)) {
|
||||
break;
|
||||
}
|
||||
LayoutPanelHeader *header = UI_layout_panel_header_under_mouse(*block->panel, my);
|
||||
if (header) {
|
||||
ED_region_tag_redraw(menu->region);
|
||||
ED_region_tag_refresh_ui(menu->region);
|
||||
UI_panel_drag_collapse_handler_add(C, !UI_layout_panel_toggle_open(C, header));
|
||||
retval = WM_UI_HANDLER_BREAK;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* now handle events for our own menu */
|
||||
if (retval == WM_UI_HANDLER_CONTINUE || event->type == TIMER) {
|
||||
|
|
|
@ -38,6 +38,7 @@
|
|||
#include "ED_screen.hh"
|
||||
|
||||
#include "UI_interface.hh"
|
||||
#include "UI_interface_c.hh"
|
||||
#include "UI_interface_icons.hh"
|
||||
#include "UI_resources.hh"
|
||||
#include "UI_view2d.hh"
|
||||
|
@ -1162,6 +1163,36 @@ static int layout_panel_y_offset()
|
|||
return UI_style_get_dpi()->panelspace;
|
||||
}
|
||||
|
||||
void UI_draw_layout_panels_backdrop(const ARegion *region,
|
||||
const Panel *panel,
|
||||
const float radius,
|
||||
float subpanel_backcolor[4])
|
||||
{
|
||||
/* Draw backdrops for layout panels. */
|
||||
for (const LayoutPanelBody &body : panel->runtime->layout_panels.bodies) {
|
||||
|
||||
rctf panel_blockspace = panel->runtime->block->rect;
|
||||
panel_blockspace.ymax = panel->runtime->block->rect.ymax + body.end_y;
|
||||
panel_blockspace.ymin = panel->runtime->block->rect.ymax + body.start_y;
|
||||
BLI_rctf_translate(&panel_blockspace, 0, -layout_panel_y_offset());
|
||||
|
||||
/* If the layout panel is at the end of the root panel, it's bottom corners are rounded. */
|
||||
const bool is_main_panel_end = panel_blockspace.ymin - panel->runtime->block->rect.ymin < 10;
|
||||
if (is_main_panel_end) {
|
||||
panel_blockspace.ymin = panel->runtime->block->rect.ymin;
|
||||
UI_draw_roundbox_corner_set(UI_CNR_BOTTOM_RIGHT | UI_CNR_BOTTOM_LEFT);
|
||||
}
|
||||
else {
|
||||
UI_draw_roundbox_corner_set(UI_CNR_NONE);
|
||||
}
|
||||
|
||||
rcti panel_pixelspace = ui_to_pixelrect(region, panel->runtime->block, &panel_blockspace);
|
||||
rctf panel_pixelspacef;
|
||||
BLI_rctf_rcti_copy(&panel_pixelspacef, &panel_pixelspace);
|
||||
UI_draw_roundbox_4fv(&panel_pixelspacef, true, radius, subpanel_backcolor);
|
||||
}
|
||||
}
|
||||
|
||||
static void panel_draw_aligned_backdrop(const ARegion *region,
|
||||
const Panel *panel,
|
||||
const rcti *rect,
|
||||
|
@ -1200,31 +1231,9 @@ static void panel_draw_aligned_backdrop(const ARegion *region,
|
|||
box_rect.ymax = rect->ymax;
|
||||
UI_draw_roundbox_4fv(&box_rect, true, radius, panel_backcolor);
|
||||
|
||||
/* Draw backdrops for layout panels. */
|
||||
for (const LayoutPanelBody &body : panel->runtime->layout_panels.bodies) {
|
||||
float subpanel_backcolor[4];
|
||||
UI_GetThemeColor4fv(TH_PANEL_SUB_BACK, subpanel_backcolor);
|
||||
|
||||
rctf panel_blockspace = panel->runtime->block->rect;
|
||||
panel_blockspace.ymax = panel->runtime->block->rect.ymax + body.end_y;
|
||||
panel_blockspace.ymin = panel->runtime->block->rect.ymax + body.start_y;
|
||||
BLI_rctf_translate(&panel_blockspace, 0, -layout_panel_y_offset());
|
||||
|
||||
/* If the layout panel is at the end of the root panel, it's bottom corners are rounded. */
|
||||
const bool is_main_panel_end = panel_blockspace.ymin - panel->runtime->block->rect.ymin < 10;
|
||||
if (is_main_panel_end) {
|
||||
panel_blockspace.ymin = panel->runtime->block->rect.ymin;
|
||||
UI_draw_roundbox_corner_set(UI_CNR_BOTTOM_RIGHT | UI_CNR_BOTTOM_LEFT);
|
||||
}
|
||||
else {
|
||||
UI_draw_roundbox_corner_set(UI_CNR_NONE);
|
||||
}
|
||||
|
||||
rcti panel_pixelspace = ui_to_pixelrect(region, panel->runtime->block, &panel_blockspace);
|
||||
rctf panel_pixelspacef;
|
||||
BLI_rctf_rcti_copy(&panel_pixelspacef, &panel_pixelspace);
|
||||
UI_draw_roundbox_4fv(&panel_pixelspacef, true, radius, subpanel_backcolor);
|
||||
}
|
||||
float subpanel_backcolor[4];
|
||||
UI_GetThemeColor4fv(TH_PANEL_SUB_BACK, subpanel_backcolor);
|
||||
UI_draw_layout_panels_backdrop(region, panel, radius, subpanel_backcolor);
|
||||
}
|
||||
|
||||
/* Panel header backdrops for non sub-panels. */
|
||||
|
@ -1931,7 +1940,7 @@ static void ui_do_drag(const bContext *C, const wmEvent *event, Panel *panel)
|
|||
/** \name Region Level Panel Interaction
|
||||
* \{ */
|
||||
|
||||
static LayoutPanelHeader *get_layout_panel_header_under_mouse(const Panel &panel, const int my)
|
||||
LayoutPanelHeader *UI_layout_panel_header_under_mouse(const Panel &panel, const int my)
|
||||
{
|
||||
for (LayoutPanelHeader &header : panel.runtime->layout_panels.headers) {
|
||||
if (IN_RANGE(float(my - panel.runtime->block->rect.ymax + layout_panel_y_offset()),
|
||||
|
@ -1956,7 +1965,7 @@ static uiPanelMouseState ui_panel_mouse_state_get(const uiBlock *block,
|
|||
if (IN_RANGE(float(my), block->rect.ymax, block->rect.ymax + PNL_HEADER)) {
|
||||
return PANEL_MOUSE_INSIDE_HEADER;
|
||||
}
|
||||
if (get_layout_panel_header_under_mouse(*panel, my) != nullptr) {
|
||||
if (UI_layout_panel_header_under_mouse(*panel, my) != nullptr) {
|
||||
return PANEL_MOUSE_INSIDE_LAYOUT_PANEL_HEADER;
|
||||
}
|
||||
|
||||
|
@ -1984,8 +1993,10 @@ static void ui_panel_drag_collapse(const bContext *C,
|
|||
const uiPanelDragCollapseHandle *dragcol_data,
|
||||
const int xy_dst[2])
|
||||
{
|
||||
ARegion *region = CTX_wm_region(C);
|
||||
|
||||
ARegion *region = CTX_wm_menu(C);
|
||||
if (!region) {
|
||||
region = CTX_wm_region(C);
|
||||
}
|
||||
LISTBASE_FOREACH (uiBlock *, block, ®ion->uiblocks) {
|
||||
float xy_a_block[2] = {float(dragcol_data->xy_init[0]), float(dragcol_data->xy_init[1])};
|
||||
float xy_b_block[2] = {float(xy_dst[0]), float(xy_dst[1])};
|
||||
|
@ -2015,6 +2026,7 @@ static void ui_panel_drag_collapse(const bContext *C,
|
|||
&header.open_owner_ptr,
|
||||
RNA_struct_find_property(&header.open_owner_ptr, header.open_prop_name.c_str()));
|
||||
ED_region_tag_redraw(region);
|
||||
ED_region_tag_refresh_ui(region);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2080,7 +2092,7 @@ static int ui_panel_drag_collapse_handler(bContext *C, const wmEvent *event, voi
|
|||
return retval;
|
||||
}
|
||||
|
||||
static void ui_panel_drag_collapse_handler_add(const bContext *C, const bool was_open)
|
||||
void UI_panel_drag_collapse_handler_add(const bContext *C, const bool was_open)
|
||||
{
|
||||
wmWindow *win = CTX_wm_window(C);
|
||||
const wmEvent *event = win->eventstate;
|
||||
|
@ -2097,32 +2109,32 @@ static void ui_panel_drag_collapse_handler_add(const bContext *C, const bool was
|
|||
eWM_EventHandlerFlag(0));
|
||||
}
|
||||
|
||||
bool UI_layout_panel_toggle_open(const bContext *C, LayoutPanelHeader *header)
|
||||
{
|
||||
const bool is_open = RNA_boolean_get(&header->open_owner_ptr, header->open_prop_name.c_str());
|
||||
RNA_boolean_set(&header->open_owner_ptr, header->open_prop_name.c_str(), !is_open);
|
||||
RNA_property_update(
|
||||
const_cast<bContext *>(C),
|
||||
&header->open_owner_ptr,
|
||||
RNA_struct_find_property(&header->open_owner_ptr, header->open_prop_name.c_str()));
|
||||
return !is_open;
|
||||
}
|
||||
|
||||
static void ui_handle_layout_panel_header(
|
||||
const bContext *C, const uiBlock *block, const int /*mx*/, const int my, const int event_type)
|
||||
{
|
||||
Panel *panel = block->panel;
|
||||
BLI_assert(panel->type != nullptr);
|
||||
|
||||
LayoutPanelHeader *header = get_layout_panel_header_under_mouse(*panel, my);
|
||||
LayoutPanelHeader *header = UI_layout_panel_header_under_mouse(*panel, my);
|
||||
if (header == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
const bool is_open = RNA_boolean_get(&header->open_owner_ptr, header->open_prop_name.c_str());
|
||||
if (is_open) {
|
||||
RNA_boolean_set(&header->open_owner_ptr, header->open_prop_name.c_str(), false);
|
||||
}
|
||||
else {
|
||||
RNA_boolean_set(&header->open_owner_ptr, header->open_prop_name.c_str(), true);
|
||||
}
|
||||
RNA_property_update(
|
||||
const_cast<bContext *>(C),
|
||||
&header->open_owner_ptr,
|
||||
RNA_struct_find_property(&header->open_owner_ptr, header->open_prop_name.c_str()));
|
||||
const bool new_state = UI_layout_panel_toggle_open(C, header);
|
||||
ED_region_tag_redraw(CTX_wm_region(C));
|
||||
|
||||
if (event_type == LEFTMOUSE) {
|
||||
ui_panel_drag_collapse_handler_add(C, is_open);
|
||||
UI_panel_drag_collapse_handler_add(C, !new_state);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2188,7 +2200,7 @@ static void ui_handle_panel_header(const bContext *C,
|
|||
SET_FLAG_FROM_TEST(panel->flag, !UI_panel_is_closed(panel), PNL_CLOSED);
|
||||
|
||||
if (event_type == LEFTMOUSE) {
|
||||
ui_panel_drag_collapse_handler_add(C, UI_panel_is_closed(panel));
|
||||
UI_panel_drag_collapse_handler_add(C, UI_panel_is_closed(panel));
|
||||
}
|
||||
|
||||
/* Set panel custom data (modifier) active when expanding sub-panels, but not top-level
|
||||
|
|
|
@ -576,6 +576,38 @@ static void ui_popup_block_remove(bContext *C, uiPopupBlockHandle *handle)
|
|||
}
|
||||
}
|
||||
|
||||
void UI_layout_panel_popup_scroll_apply(Panel *panel, const float dy)
|
||||
{
|
||||
if (!panel || dy == 0.0f) {
|
||||
return;
|
||||
}
|
||||
for (LayoutPanelBody &body : panel->runtime->layout_panels.bodies) {
|
||||
body.start_y += dy;
|
||||
body.end_y += dy;
|
||||
}
|
||||
for (LayoutPanelHeader &headcer : panel->runtime->layout_panels.headers) {
|
||||
headcer.start_y += dy;
|
||||
headcer.end_y += dy;
|
||||
}
|
||||
}
|
||||
|
||||
void UI_popup_dummy_panel_set(ARegion *region, uiBlock *block)
|
||||
{
|
||||
Panel *&panel = region->runtime.popup_block_panel;
|
||||
if (!panel) {
|
||||
/* Dummy popup panel type. */
|
||||
static PanelType panel_type = []() {
|
||||
PanelType type{};
|
||||
type.flag = PANEL_TYPE_NO_HEADER;
|
||||
return type;
|
||||
}();
|
||||
panel = BKE_panel_new(&panel_type);
|
||||
}
|
||||
panel->runtime->layout_panels.clear();
|
||||
block->panel = panel;
|
||||
panel->runtime->block = block;
|
||||
guishe marked this conversation as resolved
Outdated
Jacques Lucke
commented
Use Use `make format` (even better, configure [clang format](https://developer.blender.org/docs/handbook/tooling/clangformat/) to run on every save)
|
||||
}
|
||||
|
||||
uiBlock *ui_popup_block_refresh(bContext *C,
|
||||
uiPopupBlockHandle *handle,
|
||||
ARegion *butregion,
|
||||
|
@ -753,7 +785,14 @@ uiBlock *ui_popup_block_refresh(bContext *C,
|
|||
region->winrct.ymax = block->rect.ymax + UI_POPUP_MENU_TOP;
|
||||
|
||||
UI_block_translate(block, -region->winrct.xmin, -region->winrct.ymin);
|
||||
/* Popups can change size, fix scroll offset if a panel was closed. */
|
||||
float ymin = FLT_MAX;
|
||||
LISTBASE_FOREACH (uiBut *, bt, &block->buttons) {
|
||||
ymin = min_ff(ymin, bt->rect.ymin);
|
||||
}
|
||||
|
||||
handle->scrolloffset = std::clamp<float>(
|
||||
handle->scrolloffset, 0.0f, std::max<float>(block->rect.ymin - ymin, 0.0f));
|
||||
/* apply scroll offset */
|
||||
if (handle->scrolloffset != 0.0f) {
|
||||
LISTBASE_FOREACH (uiBut *, bt, &block->buttons) {
|
||||
|
@ -762,6 +801,8 @@ uiBlock *ui_popup_block_refresh(bContext *C,
|
|||
}
|
||||
}
|
||||
}
|
||||
/* Apply popup scroll offset to layout panels. */
|
||||
UI_layout_panel_popup_scroll_apply(block->panel, handle->scrolloffset);
|
||||
|
||||
if (block_old) {
|
||||
block->oldblock = block_old;
|
||||
|
@ -875,6 +916,10 @@ void ui_popup_block_free(bContext *C, uiPopupBlockHandle *handle)
|
|||
handle->popup_create_vars.arg_free(handle->popup_create_vars.arg);
|
||||
}
|
||||
|
||||
if (handle->region->runtime.popup_block_panel) {
|
||||
BKE_panel_free(handle->region->runtime.popup_block_panel);
|
||||
}
|
||||
|
||||
guishe marked this conversation as resolved
Jacques Lucke
commented
I get a crash when closing the splash screen here. I get a crash when closing the splash screen here.
This code might have to come before `ui_popup_block_remove` above.
|
||||
ui_popup_block_remove(C, handle);
|
||||
|
||||
MEM_freeN(handle);
|
||||
|
|
|
@ -454,6 +454,9 @@ typedef struct ARegion_Runtime {
|
|||
|
||||
/** Maps #uiBlock::name to uiBlock for faster lookups. */
|
||||
struct GHash *block_name_map;
|
||||
|
||||
/* Dummy panel used in popups so they can support layout panels. */
|
||||
Panel *popup_block_panel;
|
||||
} ARegion_Runtime;
|
||||
|
||||
typedef struct ARegion {
|
||||
|
|
|
@ -1391,6 +1391,7 @@ static uiBlock *wm_block_create_redo(bContext *C, ARegion *region, void *arg_op)
|
|||
BLI_assert(op->type->flag & OPTYPE_REGISTER);
|
||||
|
||||
UI_block_func_handle_set(block, wm_block_redo_cb, arg_op);
|
||||
UI_popup_dummy_panel_set(region, block);
|
||||
uiLayout *layout = UI_block_layout(
|
||||
block, UI_LAYOUT_VERTICAL, UI_LAYOUT_PANEL, 0, 0, width, UI_UNIT_Y, 0, style);
|
||||
|
||||
|
@ -1476,6 +1477,7 @@ static uiBlock *wm_block_dialog_create(bContext *C, ARegion *region, void *user_
|
|||
uiBlock *block = UI_block_begin(C, region, __func__, UI_EMBOSS);
|
||||
UI_block_flag_disable(block, UI_BLOCK_LOOP);
|
||||
UI_block_theme_style_set(block, UI_BLOCK_THEME_STYLE_POPUP);
|
||||
UI_popup_dummy_panel_set(region, block);
|
||||
|
||||
if (data->mouse_move_quit) {
|
||||
UI_block_flag_enable(block, UI_BLOCK_MOVEMOUSE_QUIT);
|
||||
|
|
Loading…
Reference in New Issue
Add comment to this function.