Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHans Goudey <h.goudey@me.com>2020-10-03 19:25:13 +0300
committerHans Goudey <h.goudey@me.com>2020-10-03 19:25:13 +0300
commitcb6234fccf7dfd3e09555cac18357427d802be1d (patch)
tree7d7b97232f84b0cce218e7b8635032ed67875eb5 /source/blender/editors/interface/interface_panel.c
parent724370b2f9727c007b911c036183b844dbc2ab59 (diff)
Property Search: Set panel expansion when tab changes
This commit makes the panel expansion set based on the search results when the active tab in the properties editor changes. The multi-tab search patch (D8859) actually doesn't handle this because it uses a different code path. This feature uncovered a subtle but fairly significant issue with the implementation of property search (More details in T81113). Basically, the search needed multiple redraws to properly display the expansion of panels based on the search results. Because there is no animation of panel expansion when switching tabs, the problem was exposed only now. With this commit, hiding of "search only" buttons and panel size calculation happens in a single final step of the panel layout pass. The "search only" layout root flag is removed. Instead every button inside a panel header is in a single "uiButtonGroup" marked with a specific "in header" flag, an idea which could be generalized in the future. Differential Revision: https://developer.blender.org/D9006
Diffstat (limited to 'source/blender/editors/interface/interface_panel.c')
-rw-r--r--source/blender/editors/interface/interface_panel.c178
1 files changed, 151 insertions, 27 deletions
diff --git a/source/blender/editors/interface/interface_panel.c b/source/blender/editors/interface/interface_panel.c
index 974e2c62ab2..f50975760f1 100644
--- a/source/blender/editors/interface/interface_panel.c
+++ b/source/blender/editors/interface/interface_panel.c
@@ -193,10 +193,11 @@ static bool panel_active_animation_changed(ListBase *lb,
return false;
}
-static bool panels_need_realign(ScrArea *area, ARegion *region, Panel **r_panel_animation)
+/**
+ * \return True if the properties editor switch tabs since the last layout pass.
+ */
+static bool properties_space_needs_realign(ScrArea *area, ARegion *region)
{
- *r_panel_animation = NULL;
-
if (area->spacetype == SPACE_PROPERTIES && region->regiontype == RGN_TYPE_WINDOW) {
SpaceProperties *sbuts = area->spacedata.first;
@@ -205,6 +206,17 @@ static bool panels_need_realign(ScrArea *area, ARegion *region, Panel **r_panel_
}
}
+ return false;
+}
+
+static bool panels_need_realign(ScrArea *area, ARegion *region, Panel **r_panel_animation)
+{
+ *r_panel_animation = NULL;
+
+ if (properties_space_needs_realign(area, region)) {
+ return true;
+ }
+
/* Detect if a panel was added or removed. */
Panel *panel_animation = NULL;
bool no_animation = false;
@@ -678,6 +690,8 @@ Panel *UI_panel_begin(
panel->type = pt;
}
+ panel->runtime.block = block;
+
/* Do not allow closed panels without headers! Else user could get "disappeared" UI! */
if ((pt->flag & PNL_NO_HEADER) && (panel->flag & PNL_CLOSED)) {
panel->flag &= ~PNL_CLOSED;
@@ -732,6 +746,41 @@ Panel *UI_panel_begin(
return panel;
}
+/**
+ * Create the panel header button group, used to mark which buttons are part of
+ * panel headers for later panel search handling. Should be called before adding
+ * buttons for the panel's header layout.
+ */
+void UI_panel_header_buttons_begin(Panel *panel)
+{
+ uiBlock *block = panel->runtime.block;
+
+ ui_block_new_button_group(block, UI_BUTTON_GROUP_LOCK | UI_BUTTON_GROUP_PANEL_HEADER);
+}
+
+/**
+ * Allow new button groups to be created after the header group.
+ */
+void UI_panel_header_buttons_end(Panel *panel)
+{
+ uiBlock *block = panel->runtime.block;
+
+ /* There should always be the button group created in #UI_panel_header_buttons_begin. */
+ BLI_assert(!BLI_listbase_is_empty(&block->button_groups));
+
+ uiButtonGroup *button_group = block->button_groups.last;
+
+ /* Repurpose the first "header" button group if it is empty, in case the first button added to
+ * the panel doesn't add a new group (if the button is created directly rather than through an
+ * interface layout call). */
+ if (BLI_listbase_count(&block->button_groups) == 1 &&
+ BLI_listbase_is_empty(&button_group->buttons)) {
+ button_group->flag &= ~UI_BUTTON_GROUP_PANEL_HEADER;
+ }
+
+ button_group->flag &= ~UI_BUTTON_GROUP_LOCK;
+}
+
static float panel_region_offset_x_get(const ARegion *region)
{
if (UI_panel_category_is_visible(region)) {
@@ -740,22 +789,23 @@ static float panel_region_offset_x_get(const ARegion *region)
}
}
- return 0;
+ return 0.0f;
}
-void UI_panel_end(const ARegion *region, uiBlock *block, int width, int height, bool open)
+/**
+ * Starting from the "block size" set in #UI_panel_end, calculate the full size
+ * of the panel including the subpanel headers and buttons.
+ */
+static void panel_calculate_size_recursive(ARegion *region, Panel *panel)
{
- Panel *panel = block->panel;
-
- /* Set panel size excluding children. */
- panel->blocksizex = width;
- panel->blocksizey = height;
+ int width = panel->blocksizex;
+ int height = panel->blocksizey;
- /* Compute total panel size including children. */
- LISTBASE_FOREACH (Panel *, pachild, &panel->children) {
- if (pachild->runtime_flag & PANEL_ACTIVE) {
- width = max_ii(width, pachild->sizex);
- height += get_panel_real_size_y(pachild);
+ LISTBASE_FOREACH (Panel *, child_panel, &panel->children) {
+ if (child_panel->runtime_flag & PANEL_ACTIVE) {
+ panel_calculate_size_recursive(region, child_panel);
+ width = max_ii(width, child_panel->sizex);
+ height += get_panel_real_size_y(child_panel);
}
}
@@ -773,7 +823,7 @@ void UI_panel_end(const ARegion *region, uiBlock *block, int width, int height,
if (width != 0) {
panel->sizex = width;
}
- if (height != 0 || open) {
+ if (height != 0 || !(panel->flag & PNL_CLOSED)) {
panel->sizey = height;
}
@@ -790,6 +840,14 @@ void UI_panel_end(const ARegion *region, uiBlock *block, int width, int height,
}
}
+void UI_panel_end(Panel *panel, int width, int height)
+{
+ /* Store the size of the buttons layout in the panel. The actual panel size
+ * (including subpanels) is calculated in #UI_panels_end. */
+ panel->blocksizex = width;
+ panel->blocksizey = height;
+}
+
static void ui_offset_panel_block(uiBlock *block)
{
const uiStyle *style = UI_style_get_dpi();
@@ -840,12 +898,14 @@ bool UI_panel_matches_search_filter(const Panel *panel)
/**
* Expands a panel if it was tagged as having a result by property search, otherwise collapses it.
*/
-static void panel_set_expansion_from_seach_filter_recursive(const bContext *C, Panel *panel)
+static void panel_set_expansion_from_seach_filter_recursive(const bContext *C,
+ Panel *panel,
+ const bool use_animation)
{
if (!(panel->type->flag & PNL_NO_HEADER)) {
short start_flag = panel->flag;
SET_FLAG_FROM_TEST(panel->flag, !UI_panel_matches_search_filter(panel), PNL_CLOSED);
- if (start_flag != panel->flag) {
+ if (use_animation && start_flag != panel->flag) {
panel_activate_state(C, panel, PANEL_STATE_ANIMATION);
}
}
@@ -853,7 +913,7 @@ static void panel_set_expansion_from_seach_filter_recursive(const bContext *C, P
/* If the panel is filtered (removed) we need to check that its children are too. */
LISTBASE_FOREACH (Panel *, child_panel, &panel->children) {
if (child_panel->runtime_flag & PANEL_ACTIVE) {
- panel_set_expansion_from_seach_filter_recursive(C, child_panel);
+ panel_set_expansion_from_seach_filter_recursive(C, child_panel, use_animation);
}
}
}
@@ -862,11 +922,63 @@ static void panel_set_expansion_from_seach_filter_recursive(const bContext *C, P
* Uses the panel's search filter flag to set its expansion, activating animation if it was closed
* or opened. Note that this can't be set too often, or manual interaction becomes impossible.
*/
-void UI_panels_set_expansion_from_seach_filter(const bContext *C, ARegion *region)
+static void region_panels_set_expansion_from_seach_filter(const bContext *C,
+ ARegion *region,
+ const bool use_animation)
+{
+ LISTBASE_FOREACH (Panel *, panel, &region->panels) {
+ if (panel->runtime_flag & PANEL_ACTIVE) {
+ panel_set_expansion_from_seach_filter_recursive(C, panel, use_animation);
+ }
+ }
+ set_panels_list_data_expand_flag(C, region);
+}
+
+/**
+ * Hide buttons in invisible layouts, which are created because in order to search,
+ * buttons must be added for all panels, even panels that will end up closed.
+ */
+static void panel_remove_invisible_layouts_recursive(Panel *panel, const Panel *parent_panel)
+{
+ uiBlock *block = panel->runtime.block;
+ BLI_assert(block != NULL);
+ BLI_assert(block->active);
+ if (parent_panel != NULL && parent_panel->flag & PNL_CLOSED) {
+ /* The parent panel is closed, so this panel can be completely removed. */
+ UI_block_set_search_only(block, true);
+ LISTBASE_FOREACH (uiBut *, but, &block->buttons) {
+ but->flag |= UI_HIDDEN;
+ }
+ }
+ else if (panel->flag & PNL_CLOSED) {
+ /* If subpanels have no search results but the parent panel does, then the parent panel open
+ * and the subpanels will close. In that case there must be a way to hide the buttons in the
+ * panel but keep the header buttons. */
+ LISTBASE_FOREACH (uiButtonGroup *, button_group, &block->button_groups) {
+ if (button_group->flag & UI_BUTTON_GROUP_PANEL_HEADER) {
+ continue;
+ }
+ LISTBASE_FOREACH (LinkData *, link, &button_group->buttons) {
+ uiBut *but = link->data;
+ but->flag |= UI_HIDDEN;
+ }
+ }
+ }
+
+ LISTBASE_FOREACH (Panel *, child_panel, &panel->children) {
+ if (child_panel->runtime_flag & PANEL_ACTIVE) {
+ BLI_assert(child_panel->runtime.block != NULL);
+ panel_remove_invisible_layouts_recursive(child_panel, panel);
+ }
+ }
+}
+
+static void region_panels_remove_invisible_layouts(ARegion *region)
{
LISTBASE_FOREACH (Panel *, panel, &region->panels) {
if (panel->runtime_flag & PANEL_ACTIVE) {
- panel_set_expansion_from_seach_filter_recursive(C, panel);
+ BLI_assert(panel->runtime.block != NULL);
+ panel_remove_invisible_layouts_recursive(panel, NULL);
}
}
}
@@ -1933,12 +2045,24 @@ void UI_panels_end(const bContext *C, ARegion *region, int *r_x, int *r_y)
region_panels_set_expansion_from_list_data(C, region);
- /* Update panel expansion based on property search results. */
- if (region->flag & RGN_FLAG_SEARCH_FILTER_UPDATE) {
- /* Don't use the last update from the deactivation, or all the panels will be left closed. */
- if (region->flag & RGN_FLAG_SEARCH_FILTER_ACTIVE) {
- UI_panels_set_expansion_from_seach_filter(C, region);
- set_panels_list_data_expand_flag(C, region);
+ if (region->flag & RGN_FLAG_SEARCH_FILTER_ACTIVE) {
+ /* Update panel expansion based on property search results. Keep this inside the check
+ * for an active search filter, or all panels will be left closed when a search ends. */
+ if (region->flag & RGN_FLAG_SEARCH_FILTER_UPDATE) {
+ region_panels_set_expansion_from_seach_filter(C, region, true);
+ }
+ else if (properties_space_needs_realign(area, region)) {
+ region_panels_set_expansion_from_seach_filter(C, region, false);
+ }
+
+ /* Clean up the extra panels and buttons created for searching. */
+ region_panels_remove_invisible_layouts(region);
+ }
+
+ LISTBASE_FOREACH (Panel *, panel, &region->panels) {
+ if (panel->runtime_flag & PANEL_ACTIVE) {
+ BLI_assert(panel->runtime.block != NULL);
+ panel_calculate_size_recursive(region, panel);
}
}