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:
Diffstat (limited to 'source/blender/editors/interface/interface_panel.c')
-rw-r--r--source/blender/editors/interface/interface_panel.c1341
1 files changed, 668 insertions, 673 deletions
diff --git a/source/blender/editors/interface/interface_panel.c b/source/blender/editors/interface/interface_panel.c
index 6e2229ce3e3..0d81b43146d 100644
--- a/source/blender/editors/interface/interface_panel.c
+++ b/source/blender/editors/interface/interface_panel.c
@@ -71,14 +71,28 @@
#define ANIMATION_TIME 0.30
#define ANIMATION_INTERVAL 0.02
-#define PNL_LAST_ADDED 1
-#define PNL_ACTIVE 2
-#define PNL_WAS_ACTIVE 4
-#define PNL_ANIM_ALIGN 8
-#define PNL_NEW_ADDED 16
-#define PNL_FIRST 32
-
-/* the state of the mouse position relative to the panel */
+typedef enum uiPanelRuntimeFlag {
+ PANEL_LAST_ADDED = (1 << 0),
+ PANEL_ACTIVE = (1 << 2),
+ PANEL_WAS_ACTIVE = (1 << 3),
+ PANEL_ANIM_ALIGN = (1 << 4),
+ PANEL_NEW_ADDED = (1 << 5),
+ PANEL_SEARCH_FILTER_MATCH = (1 << 7),
+ /**
+ * Use the status set by property search (#PANEL_SEARCH_FILTER_MATCH)
+ * instead of #PNL_CLOSED. Set to true on every property search update.
+ */
+ PANEL_USE_CLOSED_FROM_SEARCH = (1 << 8),
+ /** The Panel was before the start of the current / latest layout pass. */
+ PANEL_WAS_CLOSED = (1 << 9),
+ /**
+ * Set when the panel is being dragged and while it animates back to its aligned
+ * position. Unlike #PANEL_STATE_ANIMATION, this is applied to sub-panels as well.
+ */
+ PANEL_IS_DRAG_DROP = (1 << 10),
+} uiPanelRuntimeFlag;
+
+/* The state of the mouse position relative to the panel. */
typedef enum uiPanelMouseState {
PANEL_MOUSE_OUTSIDE, /** Mouse is not in the panel. */
PANEL_MOUSE_INSIDE_CONTENT, /** Mouse is in the actual panel content. */
@@ -87,8 +101,6 @@ typedef enum uiPanelMouseState {
typedef enum uiHandlePanelState {
PANEL_STATE_DRAG,
- PANEL_STATE_DRAG_SCALE,
- PANEL_STATE_WAIT_UNTAB,
PANEL_STATE_ANIMATION,
PANEL_STATE_EXIT,
} uiHandlePanelState;
@@ -96,25 +108,26 @@ typedef enum uiHandlePanelState {
typedef struct uiHandlePanelData {
uiHandlePanelState state;
- /* animation */
+ /* Animation. */
wmTimer *animtimer;
double starttime;
- /* dragging */
- bool is_drag_drop;
+ /* Dragging. */
int startx, starty;
int startofsx, startofsy;
- int startsizex, startsizey;
float start_cur_xmin, start_cur_ymin;
} uiHandlePanelData;
typedef struct PanelSort {
- Panel *panel, *orig;
+ Panel *panel;
+ int new_offset_x;
+ int new_offset_y;
} PanelSort;
+static void panel_set_expansion_from_list_data(const bContext *C, Panel *panel);
static int get_panel_real_size_y(const Panel *panel);
static void panel_activate_state(const bContext *C, Panel *panel, uiHandlePanelState state);
-static int compare_panel(const void *a1, const void *a2);
+static int compare_panel(const void *a, const void *b);
static bool panel_type_context_poll(ARegion *region,
const PanelType *panel_type,
const char *context);
@@ -125,16 +138,26 @@ static bool panel_type_context_poll(ARegion *region,
/** \name Local Functions
* \{ */
-static void panel_title_color_get(bool show_background, uchar color[4])
+static void panel_title_color_get(const Panel *panel,
+ const bool show_background,
+ const bool region_search_filter_active,
+ uchar r_color[4])
{
- if (show_background) {
- UI_GetThemeColor4ubv(TH_TITLE, color);
- }
- else {
+ if (!show_background) {
/* Use menu colors for floating panels. */
bTheme *btheme = UI_GetTheme();
const uiWidgetColors *wcol = &btheme->tui.wcol_menu_back;
- copy_v4_v4_uchar(color, (const uchar *)wcol->text);
+ copy_v4_v4_uchar(r_color, (const uchar *)wcol->text);
+ return;
+ }
+
+ const bool search_match = UI_panel_matches_search_filter(panel);
+
+ UI_GetThemeColor4ubv(TH_TITLE, r_color);
+ if (region_search_filter_active && !search_match) {
+ r_color[0] *= 0.5;
+ r_color[1] *= 0.5;
+ r_color[2] *= 0.5;
}
}
@@ -145,15 +168,21 @@ static bool panel_active_animation_changed(ListBase *lb,
LISTBASE_FOREACH (Panel *, panel, lb) {
/* Detect panel active flag changes. */
if (!(panel->type && panel->type->parent)) {
- if ((panel->runtime_flag & PNL_WAS_ACTIVE) && !(panel->runtime_flag & PNL_ACTIVE)) {
+ if ((panel->runtime_flag & PANEL_WAS_ACTIVE) && !(panel->runtime_flag & PANEL_ACTIVE)) {
return true;
}
- if (!(panel->runtime_flag & PNL_WAS_ACTIVE) && (panel->runtime_flag & PNL_ACTIVE)) {
+ if (!(panel->runtime_flag & PANEL_WAS_ACTIVE) && (panel->runtime_flag & PANEL_ACTIVE)) {
return true;
}
}
- if ((panel->runtime_flag & PNL_ACTIVE) && !(panel->flag & PNL_CLOSED)) {
+ /* Detect changes in panel expansions. */
+ if ((bool)(panel->runtime_flag & PANEL_WAS_CLOSED) != UI_panel_is_closed(panel)) {
+ *r_panel_animation = panel;
+ return false;
+ }
+
+ if ((panel->runtime_flag & PANEL_ACTIVE) && !UI_panel_is_closed(panel)) {
if (panel_active_animation_changed(&panel->children, r_panel_animation, r_no_animation)) {
return true;
}
@@ -170,7 +199,7 @@ static bool panel_active_animation_changed(ListBase *lb,
*r_no_animation = true;
}
}
- if ((panel->runtime_flag & PNL_ANIM_ALIGN) && !(*r_panel_animation)) {
+ if ((panel->runtime_flag & PANEL_ANIM_ALIGN) && !(*r_panel_animation)) {
*r_panel_animation = panel;
}
}
@@ -178,10 +207,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(const ScrArea *area, const ARegion *region)
{
- *r_panel_animation = NULL;
-
if (area->spacetype == SPACE_PROPERTIES && region->regiontype == RGN_TYPE_WINDOW) {
SpaceProperties *sbuts = area->spacedata.first;
@@ -189,10 +219,15 @@ static bool panels_need_realign(ScrArea *area, ARegion *region, Panel **r_panel_
return true;
}
}
- else if (area->spacetype == SPACE_IMAGE && region->regiontype == RGN_TYPE_PREVIEW) {
- return true;
- }
- else if (area->spacetype == SPACE_FILE && region->regiontype == RGN_TYPE_CHANNELS) {
+
+ return false;
+}
+
+static bool panels_need_realign(const ScrArea *area, ARegion *region, Panel **r_panel_animation)
+{
+ *r_panel_animation = NULL;
+
+ if (properties_space_needs_realign(area, region)) {
return true;
}
@@ -220,22 +255,23 @@ static bool panels_need_realign(ScrArea *area, ARegion *region, Panel **r_panel_
/** \name Functions for Instanced Panels
* \{ */
-static Panel *UI_panel_add_instanced_ex(ARegion *region,
- ListBase *panels,
- PanelType *panel_type,
- PointerRNA *custom_data)
+static Panel *panel_add_instanced(ARegion *region,
+ ListBase *panels,
+ PanelType *panel_type,
+ PointerRNA *custom_data)
{
- Panel *panel = MEM_callocN(sizeof(Panel), "instanced panel");
+ Panel *panel = MEM_callocN(sizeof(Panel), __func__);
panel->type = panel_type;
BLI_strncpy(panel->panelname, panel_type->idname, sizeof(panel->panelname));
panel->runtime.custom_data_ptr = custom_data;
+ panel->runtime_flag |= PANEL_NEW_ADDED;
/* Add the panel's children too. Although they aren't instanced panels, we can still use this
* function to create them, as UI_panel_begin does other things we don't need to do. */
LISTBASE_FOREACH (LinkData *, child, &panel_type->children) {
PanelType *child_type = child->data;
- UI_panel_add_instanced_ex(region, &panel->children, child_type, custom_data);
+ panel_add_instanced(region, &panel->children, child_type, custom_data);
}
/* Make sure the panel is added to the end of the display-order as well. This is needed for
@@ -257,12 +293,13 @@ static Panel *UI_panel_add_instanced_ex(ARegion *region,
}
/**
- * Called in situations where panels need to be added dynamically rather than having only one panel
- * corresponding to each #PanelType.
+ * Called in situations where panels need to be added dynamically rather than
+ * having only one panel corresponding to each #PanelType.
*/
-Panel *UI_panel_add_instanced(ARegion *region,
+Panel *UI_panel_add_instanced(const bContext *C,
+ ARegion *region,
ListBase *panels,
- char *panel_idname,
+ const char *panel_idname,
PointerRNA *custom_data)
{
ARegionType *region_type = region->type;
@@ -275,22 +312,27 @@ Panel *UI_panel_add_instanced(ARegion *region,
return NULL;
}
- return UI_panel_add_instanced_ex(region, panels, panel_type, custom_data);
+ Panel *new_panel = panel_add_instanced(region, panels, panel_type, custom_data);
+
+ /* Do this after #panel_add_instatnced so all sub-panels are added. */
+ panel_set_expansion_from_list_data(C, new_panel);
+
+ return new_panel;
}
/**
- * Find a unique key to append to the #PanelTyype.idname for the lookup to the panel's #uiBlock.
+ * Find a unique key to append to the #PanelType.idname for the lookup to the panel's #uiBlock.
* Needed for instanced panels, where there can be multiple with the same type and identifier.
*/
void UI_list_panel_unique_str(Panel *panel, char *r_name)
{
- /* The panel sortorder will be unique for a specific panel type because the instanced
+ /* The panel sort-order will be unique for a specific panel type because the instanced
* panel list is regenerated for every change in the data order / length. */
snprintf(r_name, INSTANCED_PANEL_UNIQUE_STR_LEN, "%d", panel->sortorder);
}
/**
- * Free a panel and it's children. Custom data is shared by the panel and its children
+ * Free a panel and its children. Custom data is shared by the panel and its children
* and is freed by #UI_panels_free_instanced.
*
* \note The only panels that should need to be deleted at runtime are panels with the
@@ -414,7 +456,7 @@ static void reorder_instanced_panel_list(bContext *C, ARegion *region, Panel *dr
/* Find how many instanced panels with this context string. */
int list_panels_len = 0;
- LISTBASE_FOREACH (Panel *, panel, &region->panels) {
+ LISTBASE_FOREACH (const Panel *, panel, &region->panels) {
if (panel->type) {
if (panel->type->flag & PNL_INSTANCED) {
if (panel_type_context_poll(region, panel->type, context)) {
@@ -425,14 +467,13 @@ static void reorder_instanced_panel_list(bContext *C, ARegion *region, Panel *dr
}
/* Sort the matching instanced panels by their display order. */
- PanelSort *panel_sort = MEM_callocN(list_panels_len * sizeof(*panel_sort), "instancedpanelsort");
+ PanelSort *panel_sort = MEM_callocN(list_panels_len * sizeof(*panel_sort), __func__);
PanelSort *sort_index = panel_sort;
LISTBASE_FOREACH (Panel *, panel, &region->panels) {
if (panel->type) {
if (panel->type->flag & PNL_INSTANCED) {
if (panel_type_context_poll(region, panel->type, context)) {
- sort_index->panel = MEM_dupallocN(panel);
- sort_index->orig = panel;
+ sort_index->panel = panel;
sort_index++;
}
}
@@ -443,16 +484,11 @@ static void reorder_instanced_panel_list(bContext *C, ARegion *region, Panel *dr
/* Find how many of those panels are above this panel. */
int move_to_index = 0;
for (; move_to_index < list_panels_len; move_to_index++) {
- if (panel_sort[move_to_index].orig == drag_panel) {
+ if (panel_sort[move_to_index].panel == drag_panel) {
break;
}
}
- /* Free panel sort array. */
- int i = 0;
- for (sort_index = panel_sort; i < list_panels_len; i++, sort_index++) {
- MEM_freeN(sort_index->panel);
- }
MEM_freeN(panel_sort);
/* Set the bit to tell the interface to instanced the list. */
@@ -463,14 +499,15 @@ static void reorder_instanced_panel_list(bContext *C, ARegion *region, Panel *dr
}
/**
- * Recursive implementation for #UI_panel_set_expand_from_list_data.
+ * Recursive implementation for #panel_set_expansion_from_list_data.
*
* \return Whether the closed flag for the panel or any sub-panels changed.
*/
static bool panel_set_expand_from_list_data_recursive(Panel *panel, short flag, short *flag_index)
{
const bool open = (flag & (1 << *flag_index));
- bool changed = (open == (bool)(panel->flag & PNL_CLOSED));
+ bool changed = (open == UI_panel_is_closed(panel));
+
SET_FLAG_FROM_TEST(panel->flag, !open, PNL_CLOSED);
LISTBASE_FOREACH (Panel *, child, &panel->children) {
@@ -481,11 +518,10 @@ static bool panel_set_expand_from_list_data_recursive(Panel *panel, short flag,
}
/**
- * Set the expansion of the panel and its sub-panels from the flag stored by the list data
- * corresponding to this panel. The flag has expansion stored in each bit in depth first
- * order.
+ * Set the expansion of the panel and its sub-panels from the flag stored in the
+ * corresponding list data. The flag has expansion stored in each bit in depth first order.
*/
-void UI_panel_set_expand_from_list_data(const bContext *C, Panel *panel)
+static void panel_set_expansion_from_list_data(const bContext *C, Panel *panel)
{
BLI_assert(panel->type != NULL);
BLI_assert(panel->type->flag & PNL_INSTANCED);
@@ -504,14 +540,29 @@ void UI_panel_set_expand_from_list_data(const bContext *C, Panel *panel)
}
/**
+ * Set expansion based on the data for instanced panels.
+ */
+static void region_panels_set_expansion_from_list_data(const bContext *C, ARegion *region)
+{
+ LISTBASE_FOREACH (Panel *, panel, &region->panels) {
+ if (panel->runtime_flag & PANEL_ACTIVE) {
+ PanelType *panel_type = panel->type;
+ if (panel_type != NULL && panel->type->flag & PNL_INSTANCED) {
+ panel_set_expansion_from_list_data(C, panel);
+ }
+ }
+ }
+}
+
+/**
* Recursive implementation for #set_panels_list_data_expand_flag.
*/
-static void get_panel_expand_flag(Panel *panel, short *flag, short *flag_index)
+static void get_panel_expand_flag(const Panel *panel, short *flag, short *flag_index)
{
const bool open = !(panel->flag & PNL_CLOSED);
SET_FLAG_FROM_TEST(*flag, open, (1 << *flag_index));
- LISTBASE_FOREACH (Panel *, child, &panel->children) {
+ LISTBASE_FOREACH (const Panel *, child, &panel->children) {
*flag_index = *flag_index + 1;
get_panel_expand_flag(child, flag, flag_index);
}
@@ -519,10 +570,10 @@ static void get_panel_expand_flag(Panel *panel, short *flag, short *flag_index)
/**
* Call the callback to store the panel and sub-panel expansion settings in the list item that
- * corresponds to this panel.
+ * corresponds to each instanced panel.
*
- * \note This needs to iterate through all of the regions panels because the panel with changed
- * expansion could have been the sub-panel of a instanced panel, meaning it might not know
+ * \note This needs to iterate through all of the region's panels because the panel with changed
+ * expansion might have been the sub-panel of an instanced panel, meaning it might not know
* which list item it corresponds to.
*/
static void set_panels_list_data_expand_flag(const bContext *C, const ARegion *region)
@@ -533,9 +584,9 @@ static void set_panels_list_data_expand_flag(const bContext *C, const ARegion *r
continue;
}
- /* Check for #PNL_ACTIVE so we only set the expand flag for active panels. */
- if (panel_type->flag & PNL_INSTANCED && panel->runtime_flag & PNL_ACTIVE) {
- short expand_flag = 0; /* Initialize to quite complaining compiler, value not used. */
+ /* Check for #PANEL_ACTIVE so we only set the expand flag for active panels. */
+ if (panel_type->flag & PNL_INSTANCED && panel->runtime_flag & PANEL_ACTIVE) {
+ short expand_flag;
short flag_index = 0;
get_panel_expand_flag(panel, &expand_flag, &flag_index);
if (panel->type->set_list_data_expand_flag) {
@@ -571,6 +622,18 @@ static bool panel_set_flag_recursive(Panel *panel, int flag, bool value)
return changed;
}
+/**
+ * Set runtime flag state for a panel and its sub-panels.
+ */
+static void panel_set_runtime_flag_recursive(Panel *panel, int flag, bool value)
+{
+ SET_FLAG_FROM_TEST(panel->runtime_flag, value, flag);
+
+ LISTBASE_FOREACH (Panel *, sub_panel, &panel->children) {
+ panel_set_runtime_flag_recursive(sub_panel, flag, value);
+ }
+}
+
static void panels_collapse_all(ARegion *region, const Panel *from_panel)
{
const bool has_category_tabs = UI_panel_category_is_visible(region);
@@ -580,7 +643,7 @@ static void panels_collapse_all(ARegion *region, const Panel *from_panel)
LISTBASE_FOREACH (Panel *, panel, &region->panels) {
PanelType *pt = panel->type;
- /* close panels with headers in the same context */
+ /* Close panels with headers in the same context. */
if (pt && from_pt && !(pt->flag & PNL_NO_HEADER)) {
if (!pt->context[0] || !from_pt->context[0] || STREQ(pt->context, from_pt->context)) {
if ((panel->flag & PNL_PIN) || !category || !pt->category[0] ||
@@ -607,7 +670,7 @@ static bool panel_type_context_poll(ARegion *region,
return false;
}
-Panel *UI_panel_find_by_type(ListBase *lb, PanelType *pt)
+Panel *UI_panel_find_by_type(ListBase *lb, const PanelType *pt)
{
const char *idname = pt->idname;
@@ -630,17 +693,14 @@ Panel *UI_panel_begin(
const char *idname = pt->idname;
const bool newpanel = (panel == NULL);
- if (!newpanel) {
- panel->type = pt;
- }
- else {
- /* new panel */
- panel = MEM_callocN(sizeof(Panel), "new panel");
+ if (newpanel) {
+ panel = MEM_callocN(sizeof(Panel), __func__);
panel->type = pt;
BLI_strncpy(panel->panelname, idname, sizeof(panel->panelname));
if (pt->flag & PNL_DEFAULT_CLOSED) {
panel->flag |= PNL_CLOSED;
+ panel->runtime_flag |= PANEL_WAS_CLOSED;
}
panel->ofsx = 0;
@@ -649,28 +709,23 @@ Panel *UI_panel_begin(
panel->sizey = 0;
panel->blocksizex = 0;
panel->blocksizey = 0;
- panel->runtime_flag |= PNL_NEW_ADDED;
+ panel->runtime_flag |= PANEL_NEW_ADDED;
BLI_addtail(lb, panel);
}
-
- /* 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;
- /* Force update of panels' positions! */
- panel->sizex = 0;
- panel->sizey = 0;
- panel->blocksizex = 0;
- panel->blocksizey = 0;
+ else {
+ /* Panel already exists. */
+ panel->type = pt;
}
+ panel->runtime.block = block;
+
BLI_strncpy(panel->drawname, drawname, sizeof(panel->drawname));
- /* if a new panel is added, we insert it right after the panel
- * that was last added. this way new panels are inserted in the
- * right place between versions */
+ /* If a new panel is added, we insert it right after the panel that was last added.
+ * This way new panels are inserted in the right place between versions. */
for (panel_last = lb->first; panel_last; panel_last = panel_last->next) {
- if (panel_last->runtime_flag & PNL_LAST_ADDED) {
+ if (panel_last->runtime_flag & PANEL_LAST_ADDED) {
BLI_remlink(lb, panel);
BLI_insertlinkafter(lb, panel_last, panel);
break;
@@ -688,19 +743,19 @@ Panel *UI_panel_begin(
}
if (panel_last) {
- panel_last->runtime_flag &= ~PNL_LAST_ADDED;
+ panel_last->runtime_flag &= ~PANEL_LAST_ADDED;
}
- /* assign to block */
+ /* Assign the new panel to the block. */
block->panel = panel;
- panel->runtime_flag |= PNL_ACTIVE | PNL_LAST_ADDED;
+ panel->runtime_flag |= PANEL_ACTIVE | PANEL_LAST_ADDED;
if (region->alignment == RGN_ALIGN_FLOAT) {
UI_block_theme_style_set(block, UI_BLOCK_THEME_STYLE_POPUP);
}
*r_open = false;
- if (panel->flag & PNL_CLOSED) {
+ if (UI_panel_is_closed(panel)) {
return panel;
}
@@ -709,6 +764,47 @@ Panel *UI_panel_begin(
return panel;
}
+/**
+ * Create the panel header button group, used to mark which buttons are part of
+ * panel headers for the panel search process that happens later. This 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);
+}
+
+/**
+ * Finish the button group for the panel header to avoid putting panel body buttons in it.
+ */
+void UI_panel_header_buttons_end(Panel *panel)
+{
+ uiBlock *block = panel->runtime.block;
+
+ /* A button group should always be created in #UI_panel_header_buttons_begin. */
+ BLI_assert(!BLI_listbase_is_empty(&block->button_groups));
+
+ uiButtonGroup *button_group = block->button_groups.last;
+
+ button_group->flag &= ~UI_BUTTON_GROUP_LOCK;
+
+ /* 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_is_single(&block->button_groups) &&
+ BLI_listbase_is_empty(&button_group->buttons)) {
+ button_group->flag &= ~UI_BUTTON_GROUP_PANEL_HEADER;
+ }
+ else {
+ /* Always add a new button group. Although this may result in many empty groups, without it,
+ * new buttons in the panel body not protected with a #ui_block_new_button_group call would
+ * end up in the panel header group. */
+ ui_block_new_button_group(block, 0);
+ }
+}
+
static float panel_region_offset_x_get(const ARegion *region)
{
if (UI_panel_category_is_visible(region)) {
@@ -717,28 +813,29 @@ 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 sub-panel 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 & PNL_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);
}
}
/* Update total panel size. */
- if (panel->runtime_flag & PNL_NEW_ADDED) {
- panel->runtime_flag &= ~PNL_NEW_ADDED;
+ if (panel->runtime_flag & PANEL_NEW_ADDED) {
+ panel->runtime_flag &= ~PANEL_NEW_ADDED;
panel->sizex = width;
panel->sizey = height;
}
@@ -746,32 +843,40 @@ void UI_panel_end(const ARegion *region, uiBlock *block, int width, int height,
const int old_sizex = panel->sizex, old_sizey = panel->sizey;
const int old_region_ofsx = panel->runtime.region_ofsx;
- /* update width/height if non-zero */
+ /* Update width/height if non-zero. */
if (width != 0) {
panel->sizex = width;
}
- if (height != 0 || open) {
+ if (height != 0 || !UI_panel_is_closed(panel)) {
panel->sizey = height;
}
- /* check if we need to do an animation */
+ /* Check if we need to do an animation. */
if (panel->sizex != old_sizex || panel->sizey != old_sizey) {
- panel->runtime_flag |= PNL_ANIM_ALIGN;
+ panel->runtime_flag |= PANEL_ANIM_ALIGN;
panel->ofsy += old_sizey - panel->sizey;
}
panel->runtime.region_ofsx = panel_region_offset_x_get(region);
if (old_region_ofsx != panel->runtime.region_ofsx) {
- panel->runtime_flag |= PNL_ANIM_ALIGN;
+ panel->runtime_flag |= PANEL_ANIM_ALIGN;
}
}
}
+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 sub-panels) 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();
- /* compute bounds and offset */
+ /* Compute bounds and offset. */
ui_block_bounds_calc(block);
const int ofsy = block->panel->sizey - style->panelspace;
@@ -786,34 +891,173 @@ static void ui_offset_panel_block(uiBlock *block)
block->rect.xmin = block->rect.ymin = 0.0;
}
+void ui_panel_tag_search_filter_match(Panel *panel)
+{
+ panel->runtime_flag |= PANEL_SEARCH_FILTER_MATCH;
+}
+
+static void panel_matches_search_filter_recursive(const Panel *panel, bool *filter_matches)
+{
+ *filter_matches |= panel->runtime_flag & PANEL_SEARCH_FILTER_MATCH;
+
+ /* If the panel has no match we need to make sure that its children are too. */
+ if (!*filter_matches) {
+ LISTBASE_FOREACH (const Panel *, child_panel, &panel->children) {
+ panel_matches_search_filter_recursive(child_panel, filter_matches);
+ }
+ }
+}
+
+/**
+ * Find whether a panel or any of its sub-panels contain a property that matches the search filter,
+ * depending on the search process running in #UI_block_apply_search_filter earlier.
+ */
+bool UI_panel_matches_search_filter(const Panel *panel)
+{
+ bool search_filter_matches = false;
+ panel_matches_search_filter_recursive(panel, &search_filter_matches);
+ return search_filter_matches;
+}
+
+/**
+ * Set the flag telling the panel to use its search result status for its expansion.
+ */
+static void panel_set_expansion_from_seach_filter_recursive(const bContext *C,
+ Panel *panel,
+ const bool use_search_closed)
+{
+ /* This has to run on inactive panels that may not have a type,
+ * but we can prevent running on header-less panels in some cases. */
+ if (panel->type == NULL || !(panel->type->flag & PNL_NO_HEADER)) {
+ SET_FLAG_FROM_TEST(panel->runtime_flag, use_search_closed, PANEL_USE_CLOSED_FROM_SEARCH);
+ }
+
+ LISTBASE_FOREACH (Panel *, child_panel, &panel->children) {
+ /* Don't check if the sub-panel is active, otherwise the
+ * expansion won't be reset when the parent is closed. */
+ panel_set_expansion_from_seach_filter_recursive(C, child_panel, use_search_closed);
+ }
+}
+
+/**
+ * Set the flag telling every panel to override its expansion with its search result status.
+ */
+static void region_panels_set_expansion_from_seach_filter(const bContext *C,
+ ARegion *region,
+ const bool use_search_closed)
+{
+ LISTBASE_FOREACH (Panel *, panel, &region->panels) {
+ /* Don't check if the panel is active, otherwise the expansion won't
+ * be correct when switching back to tab after exiting search. */
+ panel_set_expansion_from_seach_filter_recursive(C, panel, use_search_closed);
+ }
+ set_panels_list_data_expand_flag(C, region);
+}
+
+/**
+ * Hide buttons in invisible layouts, which are created because buttons must be
+ * added for all panels in order to search, 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 && UI_panel_is_closed(parent_panel)) {
+ /* 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 (UI_panel_is_closed(panel)) {
+ /* If sub-panels have no search results but the parent panel does, then the parent panel open
+ * and the sub-panels 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) {
+ BLI_assert(panel->runtime.block != NULL);
+ panel_remove_invisible_layouts_recursive(panel, NULL);
+ }
+ }
+}
+
+/**
+ * Get the panel's expansion state, taking into account
+ * expansion set from property search if it applies.
+ */
+bool UI_panel_is_closed(const Panel *panel)
+{
+ /* Header-less panels can never be closed, otherwise they could disappear. */
+ if (panel->type && panel->type->flag & PNL_NO_HEADER) {
+ return false;
+ }
+
+ if (panel->runtime_flag & PANEL_USE_CLOSED_FROM_SEARCH) {
+ return !UI_panel_matches_search_filter(panel);
+ }
+
+ return panel->flag & PNL_CLOSED;
+}
+
+bool UI_panel_is_active(const Panel *panel)
+{
+ return panel->runtime_flag & PANEL_ACTIVE;
+}
+
/** \} */
/* -------------------------------------------------------------------- */
/** \name Drawing
* \{ */
-/* triangle 'icon' for panel header */
-void UI_draw_icon_tri(float x, float y, char dir, const float color[4])
+/**
+ * Draw panels, selected (panels currently being dragged) on top.
+ */
+void UI_panels_draw(const bContext *C, ARegion *region)
{
- const float f3 = 0.05 * U.widget_unit;
- const float f5 = 0.15 * U.widget_unit;
- const float f7 = 0.25 * U.widget_unit;
-
- if (dir == 'h') {
- UI_draw_anti_tria(x - f3, y - f5, x - f3, y + f5, x + f7, y, color);
- }
- else if (dir == 't') {
- UI_draw_anti_tria(x - f5, y - f7, x + f5, y - f7, x, y + f3, color);
+ /* Draw in reverse order, because #uiBlocks are added in reverse order
+ * and we need child panels to draw on top. */
+ LISTBASE_FOREACH_BACKWARD (uiBlock *, block, &region->uiblocks) {
+ if (block->active && block->panel && !UI_panel_is_dragging(block->panel) &&
+ !UI_block_is_search_only(block)) {
+ UI_block_draw(C, block);
+ }
}
- else { /* 'v' = vertical, down */
- UI_draw_anti_tria(x - f5, y + f3, x + f5, y + f3, x, y - f7, color);
+
+ LISTBASE_FOREACH_BACKWARD (uiBlock *, block, &region->uiblocks) {
+ if (block->active && block->panel && UI_panel_is_dragging(block->panel) &&
+ !UI_block_is_search_only(block)) {
+ UI_block_draw(C, block);
+ }
}
}
-#define PNL_ICON UI_UNIT_X /* could be UI_UNIT_Y too */
+#define PNL_ICON UI_UNIT_X /* Could be UI_UNIT_Y too. */
/* For button layout next to label. */
-void UI_panel_label_offset(uiBlock *block, int *r_x, int *r_y)
+void UI_panel_label_offset(const uiBlock *block, int *r_x, int *r_y)
{
Panel *panel = block->panel;
const bool is_subpanel = (panel->type && panel->type->parent);
@@ -829,18 +1073,19 @@ void UI_panel_label_offset(uiBlock *block, int *r_x, int *r_y)
static void ui_draw_aligned_panel_header(const uiStyle *style,
const uiBlock *block,
const rcti *rect,
- const bool show_background)
+ const bool show_background,
+ const bool region_search_filter_active)
{
const Panel *panel = block->panel;
const bool is_subpanel = (panel->type && panel->type->parent);
const uiFontStyle *fontstyle = (is_subpanel) ? &style->widgetlabel : &style->paneltitle;
- /* + 0.001f to avoid flirting with float inaccuracy */
+ /* + 0.001f to avoid flirting with float inaccuracy .*/
const int pnl_icons = (panel->labelofs + (1.1f * PNL_ICON)) / block->aspect + 0.001f;
- /* draw text label */
+ /* Draw text labels. */
uchar col_title[4];
- panel_title_color_get(show_background, col_title);
+ panel_title_color_get(panel, show_background, region_search_filter_active, col_title);
col_title[3] = 255;
rcti hrect = *rect;
@@ -856,13 +1101,14 @@ static void ui_draw_aligned_panel_header(const uiStyle *style,
}
/**
- * Panel integrated in buttons-window, tool/property lists etc
+ * Draw a panel integrated in buttons-window, tool/property lists etc.
*/
void ui_draw_aligned_panel(const uiStyle *style,
const uiBlock *block,
const rcti *rect,
const bool show_pin,
- const bool show_background)
+ const bool show_background,
+ const bool region_search_filter_active)
{
const Panel *panel = block->panel;
float color[4];
@@ -903,12 +1149,12 @@ void ui_draw_aligned_panel(const uiStyle *style,
/* Expand the top a tiny bit to give header buttons equal size above and below. */
rcti box_rect = {rect->xmin,
rect->xmax,
- (panel->flag & PNL_CLOSED) ? headrect.ymin : rect->ymin,
+ UI_panel_is_closed(panel) ? headrect.ymin : rect->ymin,
headrect.ymax + U.pixelsize};
ui_draw_box_opaque(&box_rect, UI_CNR_ALL);
/* Mimic the border between aligned box widgets for the bottom of the header. */
- if (!(panel->flag & PNL_CLOSED)) {
+ if (!UI_panel_is_closed(panel)) {
immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
GPU_blend(GPU_BLEND_ALPHA);
@@ -936,8 +1182,8 @@ void ui_draw_aligned_panel(const uiStyle *style,
immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
GPU_blend(GPU_BLEND_ALPHA);
- /* draw with background color */
- immUniformThemeColor(TH_PANEL_HEADER);
+ /* Draw with background color. */
+ immUniformThemeColor(UI_panel_matches_search_filter(panel) ? TH_MATCH : TH_PANEL_HEADER);
immRectf(pos, minx, headrect.ymin, rect->xmax, y);
immBegin(GPU_PRIM_LINES, 4);
@@ -957,7 +1203,7 @@ void ui_draw_aligned_panel(const uiStyle *style,
/* draw optional pin icon */
if (show_pin && (block->panel->flag & PNL_PIN)) {
uchar col_title[4];
- panel_title_color_get(show_background, col_title);
+ panel_title_color_get(panel, show_background, region_search_filter_active, col_title);
GPU_blend(GPU_BLEND_ALPHA);
UI_icon_draw_ex(headrect.xmax - ((PNL_ICON * 2.2f) / block->aspect),
@@ -971,12 +1217,13 @@ void ui_draw_aligned_panel(const uiStyle *style,
GPU_blend(GPU_BLEND_NONE);
}
- /* horizontal title */
+ /* Draw the title. */
rcti titlerect = headrect;
if (is_subpanel) {
titlerect.xmin += (0.7f * UI_UNIT_X) / block->aspect + 0.001f;
}
- ui_draw_aligned_panel_header(style, block, &titlerect, show_background);
+ ui_draw_aligned_panel_header(
+ style, block, &titlerect, show_background, region_search_filter_active);
if (show_drag) {
/* Make `itemrect` smaller. */
@@ -1004,7 +1251,7 @@ void ui_draw_aligned_panel(const uiStyle *style,
}
/* Draw panel backdrop. */
- if (!(panel->flag & PNL_CLOSED)) {
+ if (!UI_panel_is_closed(panel)) {
/* in some occasions, draw a border */
if (panel->flag & PNL_SELECT && !is_subpanel) {
float radius;
@@ -1062,7 +1309,7 @@ void ui_draw_aligned_panel(const uiStyle *style,
immUnbindProgram();
}
- /* draw collapse icon */
+ /* Draw collapse icon. */
{
rctf itemrect = {.xmin = titlerect.xmin,
.xmax = itemrect.xmin + BLI_rcti_size_y(&titlerect),
@@ -1071,12 +1318,12 @@ void ui_draw_aligned_panel(const uiStyle *style,
BLI_rctf_scale(&itemrect, 0.25f);
uchar col_title[4];
- panel_title_color_get(show_background, col_title);
+ panel_title_color_get(panel, show_background, region_search_filter_active, col_title);
float tria_color[4];
rgb_uchar_to_float(tria_color, col_title);
tria_color[3] = 1.0f;
- if (panel->flag & PNL_CLOSED) {
+ if (UI_panel_is_closed(panel)) {
ui_draw_anti_tria_rect(&itemrect, 'h', tria_color);
}
else {
@@ -1091,137 +1338,14 @@ void ui_draw_aligned_panel(const uiStyle *style,
/** \name Category Drawing (Tabs)
* \{ */
-static void imm_buf_append(
- float vbuf[][2], uchar cbuf[][3], float x, float y, const uchar col[3], int *index)
-{
- ARRAY_SET_ITEMS(vbuf[*index], x, y);
- ARRAY_SET_ITEMS(cbuf[*index], UNPACK3(col));
- (*index)++;
-}
-
-/* based on UI_draw_roundbox, check on making a version which allows us to skip some sides */
-static void ui_panel_category_draw_tab(bool filled,
- float minx,
- float miny,
- float maxx,
- float maxy,
- float rad,
- const int roundboxtype,
- const bool use_highlight,
- const bool use_shadow,
- const bool use_flip_x,
- const uchar highlight_fade[3],
- const uchar col[3])
-{
- float vec[4][2] = {{0.195, 0.02}, {0.55, 0.169}, {0.831, 0.45}, {0.98, 0.805}};
-
- /* Multiply `vec` by radius. */
- for (int a = 0; a < 4; a++) {
- mul_v2_fl(vec[a], rad);
- }
-
- uint vert_len = 0;
- if (use_highlight) {
- vert_len += (roundboxtype & UI_CNR_TOP_RIGHT) ? 6 : 1;
- vert_len += (roundboxtype & UI_CNR_TOP_LEFT) ? 6 : 1;
- }
- if (use_highlight && !use_shadow) {
- vert_len++;
- }
- else {
- vert_len += (roundboxtype & UI_CNR_BOTTOM_RIGHT) ? 6 : 1;
- vert_len += (roundboxtype & UI_CNR_BOTTOM_LEFT) ? 6 : 1;
- }
- /* Maximum size. */
- float vbuf[24][2];
- uchar cbuf[24][3];
- int buf_index = 0;
-
- /* start with corner right-top */
- if (use_highlight) {
- if (roundboxtype & UI_CNR_TOP_RIGHT) {
- imm_buf_append(vbuf, cbuf, maxx, maxy - rad, col, &buf_index);
- for (int a = 0; a < 4; a++) {
- imm_buf_append(vbuf, cbuf, maxx - vec[a][1], maxy - rad + vec[a][0], col, &buf_index);
- }
- imm_buf_append(vbuf, cbuf, maxx - rad, maxy, col, &buf_index);
- }
- else {
- imm_buf_append(vbuf, cbuf, maxx, maxy, col, &buf_index);
- }
-
- /* corner left-top */
- if (roundboxtype & UI_CNR_TOP_LEFT) {
- imm_buf_append(vbuf, cbuf, minx + rad, maxy, col, &buf_index);
- for (int a = 0; a < 4; a++) {
- imm_buf_append(vbuf, cbuf, minx + rad - vec[a][0], maxy - vec[a][1], col, &buf_index);
- }
- imm_buf_append(vbuf, cbuf, minx, maxy - rad, col, &buf_index);
- }
- else {
- imm_buf_append(vbuf, cbuf, minx, maxy, col, &buf_index);
- }
- }
-
- if (use_highlight && !use_shadow) {
- imm_buf_append(
- vbuf, cbuf, minx, miny + rad, highlight_fade ? col : highlight_fade, &buf_index);
- }
- else {
- /* corner left-bottom */
- if (roundboxtype & UI_CNR_BOTTOM_LEFT) {
- imm_buf_append(vbuf, cbuf, minx, miny + rad, col, &buf_index);
- for (int a = 0; a < 4; a++) {
- imm_buf_append(vbuf, cbuf, minx + vec[a][1], miny + rad - vec[a][0], col, &buf_index);
- }
- imm_buf_append(vbuf, cbuf, minx + rad, miny, col, &buf_index);
- }
- else {
- imm_buf_append(vbuf, cbuf, minx, miny, col, &buf_index);
- }
-
- /* corner right-bottom */
- if (roundboxtype & UI_CNR_BOTTOM_RIGHT) {
- imm_buf_append(vbuf, cbuf, maxx - rad, miny, col, &buf_index);
- for (int a = 0; a < 4; a++) {
- imm_buf_append(vbuf, cbuf, maxx - rad + vec[a][0], miny + vec[a][1], col, &buf_index);
- }
- imm_buf_append(vbuf, cbuf, maxx, miny + rad, col, &buf_index);
- }
- else {
- imm_buf_append(vbuf, cbuf, maxx, miny, col, &buf_index);
- }
- }
-
- if (use_flip_x) {
- const float midx = (minx + maxx) / 2.0f;
- for (int i = 0; i < buf_index; i++) {
- vbuf[i][0] = midx - (vbuf[i][0] - midx);
- }
- }
-
- GPUVertFormat *format = immVertexFormat();
- const uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- uint color = GPU_vertformat_attr_add(
- format, "color", GPU_COMP_U8, 3, GPU_FETCH_INT_TO_FLOAT_UNIT);
-
- immBindBuiltinProgram(GPU_SHADER_2D_SMOOTH_COLOR);
- immBegin(filled ? GPU_PRIM_TRI_FAN : GPU_PRIM_LINE_STRIP, vert_len);
- for (int i = 0; i < buf_index; i++) {
- immAttr3ubv(color, cbuf[i]);
- immVertex2fv(pos, vbuf[i]);
- }
- immEnd();
- immUnbindProgram();
-}
+#define TABS_PADDING_BETWEEN_FACTOR 4.0f
+#define TABS_PADDING_TEXT_FACTOR 6.0f
/**
- * Draw vertical tabs on the left side of the region,
- * one tab per category.
+ * Draw vertical tabs on the left side of the region, one tab per category.
*/
void UI_panel_category_draw_all(ARegion *region, const char *category_id_active)
{
- /* no tab outlines for */
// #define USE_FLAT_INACTIVE
const bool is_left = RGN_ALIGN_ENUM_FROM_MASK(region->alignment != RGN_ALIGN_RIGHT);
View2D *v2d = &region->v2d;
@@ -1231,60 +1355,50 @@ void UI_panel_category_draw_all(ARegion *region, const char *category_id_active)
short fstyle_points = fstyle->points;
const float aspect = ((uiBlock *)region->uiblocks.first)->aspect;
const float zoom = 1.0f / aspect;
- const int px = max_ii(1, round_fl_to_int(U.pixelsize));
- const int px_x_sign = is_left ? px : -px;
+ const int px = U.pixelsize;
const int category_tabs_width = round_fl_to_int(UI_PANEL_CATEGORY_MARGIN_WIDTH * zoom);
const float dpi_fac = UI_DPI_FAC;
- /* padding of tabs around text */
- const int tab_v_pad_text = round_fl_to_int((2 + ((px * 3) * dpi_fac)) * zoom);
- /* padding between tabs */
- const int tab_v_pad = round_fl_to_int((4 + (2 * px * dpi_fac)) * zoom);
- const float tab_curve_radius = ((px * 3) * dpi_fac) * zoom;
- /* We flip the tab drawing, so always use these flags. */
- const int roundboxtype = UI_CNR_TOP_LEFT | UI_CNR_BOTTOM_LEFT;
+ /* Padding of tabs around text. */
+ const int tab_v_pad_text = round_fl_to_int(TABS_PADDING_TEXT_FACTOR * dpi_fac * zoom) + 2 * px;
+ /* Padding between tabs. */
+ const int tab_v_pad = round_fl_to_int(TABS_PADDING_BETWEEN_FACTOR * dpi_fac * zoom);
+ bTheme *btheme = UI_GetTheme();
+ const float tab_curve_radius = btheme->tui.wcol_tab.roundness * U.widget_unit * zoom;
+ const int roundboxtype = is_left ? (UI_CNR_TOP_LEFT | UI_CNR_BOTTOM_LEFT) :
+ (UI_CNR_TOP_RIGHT | UI_CNR_BOTTOM_RIGHT);
bool is_alpha;
bool do_scaletabs = false;
#ifdef USE_FLAT_INACTIVE
bool is_active_prev = false;
#endif
float scaletabs = 1.0f;
- /* same for all tabs */
- /* intentionally don't scale by 'px' */
+ /* Same for all tabs. */
+ /* Intentionally don't scale by 'px'. */
const int rct_xmin = is_left ? v2d->mask.xmin + 3 : (v2d->mask.xmax - category_tabs_width);
const int rct_xmax = is_left ? v2d->mask.xmin + category_tabs_width : (v2d->mask.xmax - 3);
const int text_v_ofs = (rct_xmax - rct_xmin) * 0.3f;
int y_ofs = tab_v_pad;
- /* Primary theme colors */
+ /* Primary theme colors. */
uchar theme_col_back[4];
uchar theme_col_text[3];
uchar theme_col_text_hi[3];
- /* Tab colors */
+ /* Tab colors. */
uchar theme_col_tab_bg[4];
- uchar theme_col_tab_active[3];
- uchar theme_col_tab_inactive[3];
-
- /* Secondary theme colors */
- uchar theme_col_tab_outline[3];
- uchar theme_col_tab_divider[3]; /* line that divides tabs from the main region */
- uchar theme_col_tab_highlight[3];
- uchar theme_col_tab_highlight_inactive[3];
+ float theme_col_tab_active[4];
+ float theme_col_tab_inactive[4];
+ float theme_col_tab_outline[4];
UI_GetThemeColor4ubv(TH_BACK, theme_col_back);
UI_GetThemeColor3ubv(TH_TEXT, theme_col_text);
UI_GetThemeColor3ubv(TH_TEXT_HI, theme_col_text_hi);
UI_GetThemeColor4ubv(TH_TAB_BACK, theme_col_tab_bg);
- UI_GetThemeColor3ubv(TH_TAB_ACTIVE, theme_col_tab_active);
- UI_GetThemeColor3ubv(TH_TAB_INACTIVE, theme_col_tab_inactive);
- UI_GetThemeColor3ubv(TH_TAB_OUTLINE, theme_col_tab_outline);
-
- interp_v3_v3v3_uchar(theme_col_tab_divider, theme_col_back, theme_col_tab_outline, 0.3f);
- interp_v3_v3v3_uchar(theme_col_tab_highlight, theme_col_back, theme_col_text_hi, 0.2f);
- interp_v3_v3v3_uchar(
- theme_col_tab_highlight_inactive, theme_col_tab_inactive, theme_col_text_hi, 0.12f);
+ UI_GetThemeColor4fv(TH_TAB_ACTIVE, theme_col_tab_active);
+ UI_GetThemeColor4fv(TH_TAB_INACTIVE, theme_col_tab_inactive);
+ UI_GetThemeColor4fv(TH_TAB_OUTLINE, theme_col_tab_outline);
is_alpha = (region->overlap && (theme_col_back[3] != 255));
@@ -1306,7 +1420,6 @@ void UI_panel_category_draw_all(ARegion *region, const char *category_id_active)
/* Calculate tab rectangle and check if we need to scale down. */
LISTBASE_FOREACH (PanelCategoryDyn *, pc_dyn, &region->panels_category) {
-
rcti *rct = &pc_dyn->rect;
const char *category_id = pc_dyn->idname;
const char *category_id_draw = IFACE_(category_id);
@@ -1333,14 +1446,14 @@ void UI_panel_category_draw_all(ARegion *region, const char *category_id_active)
do_scaletabs = true;
}
- /* begin drawing */
+ /* Begin drawing. */
GPU_line_smooth(true);
uint pos = GPU_vertformat_attr_add(
immVertexFormat(), "pos", GPU_COMP_I32, 2, GPU_FETCH_INT_TO_FLOAT);
immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
- /* draw the background */
+ /* Draw the background. */
if (is_alpha) {
GPU_blend(GPU_BLEND_ALPHA);
immUniformColor4ubv(theme_col_tab_bg);
@@ -1364,11 +1477,6 @@ void UI_panel_category_draw_all(ARegion *region, const char *category_id_active)
immUnbindProgram();
- const int divider_xmin = is_left ? (v2d->mask.xmin + (category_tabs_width - px)) :
- (v2d->mask.xmax - category_tabs_width) + px;
- const int divider_xmax = is_left ? (v2d->mask.xmin + category_tabs_width) :
- (v2d->mask.xmax - (category_tabs_width + px)) + px;
-
LISTBASE_FOREACH (PanelCategoryDyn *, pc_dyn, &region->panels_category) {
const rcti *rct = &pc_dyn->rect;
const char *category_id = pc_dyn->idname;
@@ -1384,110 +1492,72 @@ void UI_panel_category_draw_all(ARegion *region, const char *category_id_active)
GPU_blend(GPU_BLEND_ALPHA);
#ifdef USE_FLAT_INACTIVE
+ /* Draw line between inactive tabs. */
+ if (is_active == false && is_active_prev == false && pc_dyn->prev) {
+ pos = GPU_vertformat_attr_add(
+ immVertexFormat(), "pos", GPU_COMP_I32, 2, GPU_FETCH_INT_TO_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immUniformColor3fvAlpha(theme_col_tab_outline, 0.3f);
+ immRecti(pos,
+ is_left ? v2d->mask.xmin + (category_tabs_width / 5) :
+ v2d->mask.xmax - (category_tabs_width / 5),
+ rct->ymax + px,
+ is_left ? (v2d->mask.xmin + category_tabs_width) - (category_tabs_width / 5) :
+ (v2d->mask.xmax - category_tabs_width) + (category_tabs_width / 5),
+ rct->ymax + (px * 3));
+ immUnbindProgram();
+ }
+
+ is_active_prev = is_active;
+
if (is_active)
#endif
{
- const bool use_flip_x = !is_left;
- ui_panel_category_draw_tab(true,
- rct->xmin,
- rct->ymin,
- rct->xmax,
- rct->ymax,
- tab_curve_radius - px,
- roundboxtype,
- true,
- true,
- use_flip_x,
- NULL,
- is_active ? theme_col_tab_active : theme_col_tab_inactive);
-
- /* Tab outline */
- ui_panel_category_draw_tab(false,
- rct->xmin - px_x_sign,
- rct->ymin - px,
- rct->xmax - px_x_sign,
- rct->ymax + px,
- tab_curve_radius,
- roundboxtype,
- true,
- true,
- use_flip_x,
- NULL,
- theme_col_tab_outline);
-
- /* Tab highlight (3d look) */
- ui_panel_category_draw_tab(false,
- rct->xmin,
- rct->ymin,
- rct->xmax,
- rct->ymax,
- tab_curve_radius,
- roundboxtype,
- true,
- false,
- use_flip_x,
- is_active ? theme_col_back : theme_col_tab_inactive,
- is_active ? theme_col_tab_highlight :
- theme_col_tab_highlight_inactive);
- }
-
- /* Tab black-line. */
- if (!is_active) {
+ /* Draw filled rectangle and outline for tab. */
+ UI_draw_roundbox_corner_set(roundboxtype);
+ UI_draw_roundbox_4fv(true,
+ rct->xmin,
+ rct->ymin,
+ rct->xmax,
+ rct->ymax,
+ tab_curve_radius,
+ is_active ? theme_col_tab_active : theme_col_tab_inactive);
+ UI_draw_roundbox_4fv(false,
+ rct->xmin,
+ rct->ymin,
+ rct->xmax,
+ rct->ymax,
+ tab_curve_radius,
+ theme_col_tab_outline);
+
+ /* Disguise the outline on one side to join the tab to the panel. */
pos = GPU_vertformat_attr_add(
immVertexFormat(), "pos", GPU_COMP_I32, 2, GPU_FETCH_INT_TO_FLOAT);
immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
- immUniformColor3ubv(theme_col_tab_divider);
- immRecti(pos, divider_xmin, rct->ymin - tab_v_pad, divider_xmax, rct->ymax + tab_v_pad);
+ immUniformColor4fv(is_active ? theme_col_tab_active : theme_col_tab_inactive);
+ immRecti(pos,
+ is_left ? rct->xmax - px : rct->xmin,
+ rct->ymin + px,
+ is_left ? rct->xmax : rct->xmin + px,
+ rct->ymax - px);
immUnbindProgram();
}
+ /* Tab titles. */
+
if (do_scaletabs) {
category_draw_len = BLF_width_to_strlen(
fontid, category_id_draw, category_draw_len, category_width, NULL);
}
BLF_position(fontid, rct->xmax - text_v_ofs, rct->ymin + tab_v_pad_text, 0.0f);
-
- /* Tab titles. */
-
- /* Draw white shadow to give text more depth. */
BLF_color3ubv(fontid, theme_col_text);
-
- /* Main tab title. */
BLF_draw(fontid, category_id_draw, category_draw_len);
GPU_blend(GPU_BLEND_NONE);
- /* Tab black-line remaining (last tab). */
- pos = GPU_vertformat_attr_add(
- immVertexFormat(), "pos", GPU_COMP_I32, 2, GPU_FETCH_INT_TO_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
- if (pc_dyn->prev == NULL) {
- immUniformColor3ubv(theme_col_tab_divider);
- immRecti(pos, divider_xmin, rct->ymax + px, divider_xmax, v2d->mask.ymax);
- }
- if (pc_dyn->next == NULL) {
- immUniformColor3ubv(theme_col_tab_divider);
- immRecti(pos, divider_xmin, 0, divider_xmax, rct->ymin);
- }
-
-#ifdef USE_FLAT_INACTIVE
- /* Draw line between inactive tabs. */
- if (is_active == false && is_active_prev == false && pc_dyn->prev) {
- immUniformColor3ubv(theme_col_tab_divider);
- immRecti(pos,
- v2d->mask.xmin + (category_tabs_width / 5),
- rct->ymax + px,
- (v2d->mask.xmin + category_tabs_width) - (category_tabs_width / 5),
- rct->ymax + (px * 3));
- }
-
- is_active_prev = is_active;
-#endif
- immUnbindProgram();
-
- /* not essential, but allows events to be handled right up until the region edge [#38171] */
+ /* Not essential, but allows events to be handled right up to the region edge (T38171). */
if (is_left) {
pc_dyn->rect.xmin = v2d->mask.xmin;
}
@@ -1503,10 +1573,11 @@ void UI_panel_category_draw_all(ARegion *region, const char *category_id_active)
if (fstyle->kerning == 1) {
BLF_disable(fstyle->uifont_id, BLF_KERNING_DEFAULT);
}
-
-#undef USE_FLAT_INACTIVE
}
+#undef TABS_PADDING_BETWEEN_FACTOR
+#undef TABS_PADDING_TEXT_FACTOR
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -1524,7 +1595,7 @@ static int get_panel_size_y(const Panel *panel)
static int get_panel_real_size_y(const Panel *panel)
{
- const int sizey = (panel->flag & PNL_CLOSED) ? 0 : panel->sizey;
+ const int sizey = UI_panel_is_closed(panel) ? 0 : panel->sizey;
if (panel->type && (panel->type->flag & PNL_NO_HEADER)) {
return sizey;
@@ -1544,70 +1615,67 @@ int UI_panel_size_y(const Panel *panel)
*/
static int get_panel_real_ofsy(Panel *panel)
{
- if (panel->flag & PNL_CLOSED) {
+ if (UI_panel_is_closed(panel)) {
return panel->ofsy + panel->sizey;
}
return panel->ofsy;
}
-bool UI_panel_is_dragging(const struct Panel *panel)
+bool UI_panel_is_dragging(const Panel *panel)
{
- uiHandlePanelData *data = panel->activedata;
- if (!data) {
- return false;
- }
-
- return data->is_drag_drop;
+ return panel->runtime_flag & PANEL_IS_DRAG_DROP;
}
/**
- * \note about sorting;
- * the #Panel.sortorder has a lower value for new panels being added.
+ * \note about sorting:
+ * The #Panel.sortorder has a lower value for new panels being added.
* however, that only works to insert a single panel, when more new panels get
* added the coordinates of existing panels and the previously stored to-be-inserted
- * panels do not match for sorting
+ * panels do not match for sorting.
*/
-static int find_highest_panel(const void *a1, const void *a2)
+static int find_highest_panel(const void *a, const void *b)
{
- const PanelSort *ps1 = a1, *ps2 = a2;
+ const Panel *panel_a = ((PanelSort *)a)->panel;
+ const Panel *panel_b = ((PanelSort *)b)->panel;
- /* stick uppermost header-less panels to the top of the region -
- * prevent them from being sorted (multiple header-less panels have to be sorted though) */
- if (ps1->panel->type->flag & PNL_NO_HEADER && ps2->panel->type->flag & PNL_NO_HEADER) {
+ /* Stick uppermost header-less panels to the top of the region -
+ * prevent them from being sorted (multiple header-less panels have to be sorted though). */
+ if (panel_a->type->flag & PNL_NO_HEADER && panel_b->type->flag & PNL_NO_HEADER) {
/* Skip and check for `ofsy` and #Panel.sortorder below. */
}
- if (ps1->panel->type->flag & PNL_NO_HEADER) {
+ if (panel_a->type->flag & PNL_NO_HEADER) {
return -1;
}
- if (ps2->panel->type->flag & PNL_NO_HEADER) {
+ if (panel_b->type->flag & PNL_NO_HEADER) {
return 1;
}
- if (ps1->panel->ofsy + ps1->panel->sizey < ps2->panel->ofsy + ps2->panel->sizey) {
+ if (panel_a->ofsy + panel_a->sizey < panel_b->ofsy + panel_b->sizey) {
return 1;
}
- if (ps1->panel->ofsy + ps1->panel->sizey > ps2->panel->ofsy + ps2->panel->sizey) {
+ if (panel_a->ofsy + panel_a->sizey > panel_b->ofsy + panel_b->sizey) {
return -1;
}
- if (ps1->panel->sortorder > ps2->panel->sortorder) {
+ if (panel_a->sortorder > panel_b->sortorder) {
return 1;
}
- if (ps1->panel->sortorder < ps2->panel->sortorder) {
+ if (panel_a->sortorder < panel_b->sortorder) {
return -1;
}
return 0;
}
-static int compare_panel(const void *a1, const void *a2)
+static int compare_panel(const void *a, const void *b)
{
- const PanelSort *ps1 = a1, *ps2 = a2;
+ const Panel *panel_a = ((PanelSort *)a)->panel;
+ const Panel *panel_b = ((PanelSort *)b)->panel;
- if (ps1->panel->sortorder > ps2->panel->sortorder) {
+ if (panel_a->sortorder > panel_b->sortorder) {
return 1;
}
- if (ps1->panel->sortorder < ps2->panel->sortorder) {
+ if (panel_a->sortorder < panel_b->sortorder) {
return -1;
}
@@ -1620,7 +1688,7 @@ static void align_sub_panels(Panel *panel)
int ofsy = panel->ofsy + panel->sizey - panel->blocksizey;
LISTBASE_FOREACH (Panel *, pachild, &panel->children) {
- if (pachild->runtime_flag & PNL_ACTIVE) {
+ if (pachild->runtime_flag & PANEL_ACTIVE) {
pachild->ofsx = panel->ofsx;
pachild->ofsy = ofsy - get_panel_size_y(pachild);
ofsy -= get_panel_real_size_y(pachild);
@@ -1632,104 +1700,103 @@ static void align_sub_panels(Panel *panel)
}
}
-/* this doesn't draw */
-/* returns 1 when it did something */
-static bool uiAlignPanelStep(ARegion *region, const float fac, const bool drag)
+/**
+ * Calculate the position and order of panels as they are opened, closed, and dragged.
+ */
+static bool uiAlignPanelStep(ARegion *region, const float factor, const bool drag)
{
- /* count active, not tabbed panels */
- int tot = 0;
+ /* Count active panels. */
+ int active_panels_len = 0;
LISTBASE_FOREACH (Panel *, panel, &region->panels) {
- if (panel->runtime_flag & PNL_ACTIVE) {
- tot++;
+ if (panel->runtime_flag & PANEL_ACTIVE) {
+ /* These panels should have types since they are currently displayed to the user. */
+ BLI_assert(panel->type != NULL);
+ active_panels_len++;
}
}
-
- if (tot == 0) {
- return 0;
+ if (active_panels_len == 0) {
+ return false;
}
- /* sort panels */
- PanelSort *panelsort = MEM_callocN(tot * sizeof(PanelSort), "panelsort");
-
- PanelSort *ps = panelsort;
- LISTBASE_FOREACH (Panel *, panel, &region->panels) {
- if (panel->runtime_flag & PNL_ACTIVE) {
- ps->panel = MEM_dupallocN(panel);
- ps->orig = panel;
- ps++;
+ /* Sort panels. */
+ PanelSort *panel_sort = MEM_mallocN(sizeof(PanelSort) * active_panels_len, __func__);
+ {
+ PanelSort *ps = panel_sort;
+ LISTBASE_FOREACH (Panel *, panel, &region->panels) {
+ if (panel->runtime_flag & PANEL_ACTIVE) {
+ ps->panel = panel;
+ ps++;
+ }
}
}
if (drag) {
- /* While we are dragging, we sort on location and update #Panel.sortorder. */
- qsort(panelsort, tot, sizeof(PanelSort), find_highest_panel);
-
- int i;
- for (ps = panelsort, i = 0; i < tot; i++, ps++) {
- ps->orig->sortorder = i;
+ /* While dragging, sort based on location and update #Panel.sortorder. */
+ qsort(panel_sort, active_panels_len, sizeof(PanelSort), find_highest_panel);
+ for (int i = 0; i < active_panels_len; i++) {
+ panel_sort[i].panel->sortorder = i;
}
}
else {
/* Otherwise use #Panel.sortorder. */
- qsort(panelsort, tot, sizeof(PanelSort), compare_panel);
+ qsort(panel_sort, active_panels_len, sizeof(PanelSort), compare_panel);
}
- /* No smart other default start location! This keeps switching f5/f6/etc compatible. */
- ps = panelsort;
- ps->panel->runtime.region_ofsx = panel_region_offset_x_get(region);
- ps->panel->ofsx = 0;
- ps->panel->ofsy = -get_panel_size_y(ps->panel);
- ps->panel->ofsx += ps->panel->runtime.region_ofsx;
-
- for (int i = 0; i < tot - 1; i++, ps++) {
- PanelSort *psnext = ps + 1;
+ /* X offset. */
+ const int region_offset_x = panel_region_offset_x_get(region);
+ for (int i = 0; i < active_panels_len; i++) {
+ PanelSort *ps = &panel_sort[i];
+ const bool use_box = ps->panel->type->flag & PNL_DRAW_BOX;
+ ps->panel->runtime.region_ofsx = region_offset_x;
+ ps->new_offset_x = region_offset_x + ((use_box) ? UI_PANEL_BOX_STYLE_MARGIN : 0);
+ }
- const bool use_box = ps->panel->type && ps->panel->type->flag & PNL_DRAW_BOX;
- const bool use_box_next = psnext->panel->type && psnext->panel->type->flag & PNL_DRAW_BOX;
- psnext->panel->ofsx = ps->panel->ofsx;
- psnext->panel->ofsy = get_panel_real_ofsy(ps->panel) - get_panel_size_y(psnext->panel);
+ /* Y offset. */
+ for (int i = 0, y = 0; i < active_panels_len; i++) {
+ PanelSort *ps = &panel_sort[i];
+ y -= get_panel_real_size_y(ps->panel);
- /* Extra margin for box style panels. */
- ps->panel->ofsx += (use_box) ? UI_PANEL_BOX_STYLE_MARGIN : 0.0f;
- if (use_box || use_box_next) {
- psnext->panel->ofsy -= UI_PANEL_BOX_STYLE_MARGIN;
+ const bool use_box = ps->panel->type->flag & PNL_DRAW_BOX;
+ if (use_box) {
+ y -= UI_PANEL_BOX_STYLE_MARGIN;
+ }
+ ps->new_offset_y = y;
+ /* The header still draws offset by the size of closed panels, so apply the offset here. */
+ if (UI_panel_is_closed(ps->panel)) {
+ panel_sort[i].new_offset_y -= ps->panel->sizey;
}
- }
- /* Extra margin for the last panel if it's a box-style panel. */
- if (panelsort[tot - 1].panel->type && panelsort[tot - 1].panel->type->flag & PNL_DRAW_BOX) {
- panelsort[tot - 1].panel->ofsx += UI_PANEL_BOX_STYLE_MARGIN;
}
- /* we interpolate */
+ /* Interpolate based on the input factor. */
bool changed = false;
- ps = panelsort;
- for (int i = 0; i < tot; i++, ps++) {
- if ((ps->panel->flag & PNL_SELECT) == 0) {
- if ((ps->orig->ofsx != ps->panel->ofsx) || (ps->orig->ofsy != ps->panel->ofsy)) {
- ps->orig->ofsx = round_fl_to_int(fac * (float)ps->panel->ofsx +
- (1.0f - fac) * (float)ps->orig->ofsx);
- ps->orig->ofsy = round_fl_to_int(fac * (float)ps->panel->ofsy +
- (1.0f - fac) * (float)ps->orig->ofsy);
- changed = true;
- }
+ for (int i = 0; i < active_panels_len; i++) {
+ PanelSort *ps = &panel_sort[i];
+ if (ps->panel->flag & PNL_SELECT) {
+ continue;
+ }
+
+ if (ps->new_offset_x != ps->panel->ofsx) {
+ const float x = interpf((float)ps->new_offset_x, (float)ps->panel->ofsx, factor);
+ ps->panel->ofsx = round_fl_to_int(x);
+ changed = true;
+ }
+ if (ps->new_offset_y != ps->panel->ofsy) {
+ const float y = interpf((float)ps->new_offset_y, (float)ps->panel->ofsy, factor);
+ ps->panel->ofsy = round_fl_to_int(y);
+ changed = true;
}
}
- /* set locations for tabbed and sub panels */
+ /* Set locations for tabbed and sub panels. */
LISTBASE_FOREACH (Panel *, panel, &region->panels) {
- if (panel->runtime_flag & PNL_ACTIVE) {
+ if (panel->runtime_flag & PANEL_ACTIVE) {
if (panel->children.first) {
align_sub_panels(panel);
}
}
}
- /* Free `panelsort` array. */
- int i;
- for (ps = panelsort, i = 0; i < tot; i++, ps++) {
- MEM_freeN(ps->panel);
- }
- MEM_freeN(panelsort);
+ MEM_freeN(panel_sort);
return changed;
}
@@ -1739,9 +1806,9 @@ static void ui_panels_size(ARegion *region, int *r_x, int *r_y)
int sizex = 0;
int sizey = 0;
- /* compute size taken up by panels, for setting in view2d */
+ /* Compute size taken up by panels, for setting in view2d. */
LISTBASE_FOREACH (Panel *, panel, &region->panels) {
- if (panel->runtime_flag & PNL_ACTIVE) {
+ if (panel->runtime_flag & PANEL_ACTIVE) {
const int pa_sizex = panel->ofsx + panel->sizex;
const int pa_sizey = get_panel_real_ofsy(panel);
@@ -1769,7 +1836,7 @@ static void ui_do_animate(bContext *C, Panel *panel)
float fac = (PIL_check_seconds_timer() - data->starttime) / ANIMATION_TIME;
fac = min_ff(sqrtf(fac), 1.0f);
- /* for max 1 second, interpolate positions */
+ /* For max 1 second, interpolate positions. */
if (uiAlignPanelStep(region, fac, false)) {
ED_region_tag_redraw(region);
}
@@ -1778,53 +1845,75 @@ static void ui_do_animate(bContext *C, Panel *panel)
}
if (fac >= 1.0f) {
- /* Store before data is freed. */
- const bool is_drag_drop = data->is_drag_drop;
-
- panel_activate_state(C, panel, PANEL_STATE_EXIT);
- if (is_drag_drop) {
- /* Note: doing this in #panel_activate_state would require removing `const` for context in
- * many other places. */
+ if (UI_panel_is_dragging(panel)) {
+ /* Note: doing this in #panel_activate_state would require
+ * removing `const` for context in many other places. */
reorder_instanced_panel_list(C, region, panel);
}
+
+ panel_activate_state(C, panel, PANEL_STATE_EXIT);
return;
}
}
-static void panel_list_clear_active(ListBase *lb)
+static void panels_layout_begin_clear_flags(ListBase *lb)
{
- /* set all panels as inactive, so that at the end we know
- * which ones were used */
LISTBASE_FOREACH (Panel *, panel, lb) {
- if (panel->runtime_flag & PNL_ACTIVE) {
- panel->runtime_flag = PNL_WAS_ACTIVE;
- }
- else {
- panel->runtime_flag = 0;
- }
+ /* Flags to copy over to the next layout pass. */
+ const short flag_copy = PANEL_USE_CLOSED_FROM_SEARCH | PANEL_IS_DRAG_DROP;
+
+ const bool was_active = panel->runtime_flag & PANEL_ACTIVE;
+ const bool was_closed = UI_panel_is_closed(panel);
+ panel->runtime_flag &= flag_copy;
+ SET_FLAG_FROM_TEST(panel->runtime_flag, was_active, PANEL_WAS_ACTIVE);
+ SET_FLAG_FROM_TEST(panel->runtime_flag, was_closed, PANEL_WAS_CLOSED);
- panel_list_clear_active(&panel->children);
+ panels_layout_begin_clear_flags(&panel->children);
}
}
void UI_panels_begin(const bContext *UNUSED(C), ARegion *region)
{
- panel_list_clear_active(&region->panels);
+ /* Set all panels as inactive, so that at the end we know which ones were used. Also
+ * clear other flags so we know later that their values were set for the current redraw. */
+ panels_layout_begin_clear_flags(&region->panels);
}
-/* only draws blocks with panels */
void UI_panels_end(const bContext *C, ARegion *region, int *r_x, int *r_y)
{
ScrArea *area = CTX_wm_area(C);
- /* offset contents */
+ region_panels_set_expansion_from_list_data(C, region);
+
+ const bool region_search_filter_active = region->flag & RGN_FLAG_SEARCH_FILTER_ACTIVE;
+
+ if (properties_space_needs_realign(area, region)) {
+ region_panels_set_expansion_from_seach_filter(C, region, region_search_filter_active);
+ }
+ else if (region->flag & RGN_FLAG_SEARCH_FILTER_UPDATE) {
+ region_panels_set_expansion_from_seach_filter(C, region, region_search_filter_active);
+ }
+
+ if (region->flag & RGN_FLAG_SEARCH_FILTER_ACTIVE) {
+ /* 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);
+ }
+ }
+
+ /* Offset contents. */
LISTBASE_FOREACH (uiBlock *, block, &region->uiblocks) {
if (block->active && block->panel) {
ui_offset_panel_block(block);
}
}
- /* re-align, possibly with animation */
+ /* Re-align, possibly with animation. */
Panel *panel;
if (panels_need_realign(area, region, &panel)) {
if (panel) {
@@ -1835,57 +1924,10 @@ void UI_panels_end(const bContext *C, ARegion *region, int *r_x, int *r_y)
}
}
- /* tag first panel */
- Panel *panel_first = NULL;
- LISTBASE_FOREACH (uiBlock *, block, &region->uiblocks) {
- if (block->active && block->panel) {
- if (!panel_first || block->panel->sortorder < panel_first->sortorder) {
- panel_first = block->panel;
- }
- }
- }
-
- if (panel_first) {
- panel_first->runtime_flag |= PNL_FIRST;
- }
-
- /* compute size taken up by panel */
+ /* Compute size taken up by panels. */
ui_panels_size(region, r_x, r_y);
}
-void UI_panels_draw(const bContext *C, ARegion *region)
-{
- /* Draw panels, selected on top. Also in reverse order, because
- * UI blocks are added in reverse order and we need child panels
- * to draw on top. */
- LISTBASE_FOREACH_BACKWARD (uiBlock *, block, &region->uiblocks) {
- if (block->active && block->panel && !(block->panel->flag & PNL_SELECT)) {
- UI_block_draw(C, block);
- }
- }
-
- LISTBASE_FOREACH_BACKWARD (uiBlock *, block, &region->uiblocks) {
- if (block->active && block->panel && (block->panel->flag & PNL_SELECT)) {
- UI_block_draw(C, block);
- }
- }
-}
-
-void UI_panels_scale(ARegion *region, float new_width)
-{
- LISTBASE_FOREACH (uiBlock *, block, &region->uiblocks) {
- if (block->panel) {
- const float fac = new_width / (float)block->panel->sizex;
- block->panel->sizex = new_width;
-
- LISTBASE_FOREACH (uiBut *, but, &block->buttons) {
- but->rect.xmin *= fac;
- but->rect.xmax *= fac;
- }
- }
- }
-}
-
/** \} */
/* -------------------------------------------------------------------- */
@@ -1909,28 +1951,13 @@ static void ui_do_drag(const bContext *C, const wmEvent *event, Panel *panel)
dx *= BLI_rctf_size_x(&region->v2d.cur) / (float)BLI_rcti_size_x(&region->winrct);
dy *= BLI_rctf_size_y(&region->v2d.cur) / (float)BLI_rcti_size_y(&region->winrct);
- if (data->state == PANEL_STATE_DRAG_SCALE) {
- panel->sizex = MAX2(data->startsizex + dx, UI_PANEL_MINX);
-
- if (data->startsizey - dy < UI_PANEL_MINY) {
- dy = -UI_PANEL_MINY + data->startsizey;
- }
-
- panel->sizey = data->startsizey - dy;
- panel->ofsy = data->startofsy + dy;
- }
- else {
- /* reset the panel snapping, to allow dragging away from snapped edges */
- panel->snap = PNL_SNAP_NONE;
-
- /* Add the movement of the view due to edge scrolling while dragging. */
- dx += ((float)region->v2d.cur.xmin - data->start_cur_xmin);
- dy += ((float)region->v2d.cur.ymin - data->start_cur_ymin);
- panel->ofsx = data->startofsx + round_fl_to_int(dx);
- panel->ofsy = data->startofsy + round_fl_to_int(dy);
+ /* Add the movement of the view due to edge scrolling while dragging. */
+ dx += ((float)region->v2d.cur.xmin - data->start_cur_xmin);
+ dy += ((float)region->v2d.cur.ymin - data->start_cur_ymin);
+ panel->ofsx = data->startofsx + round_fl_to_int(dx);
+ panel->ofsy = data->startofsy + round_fl_to_int(dy);
- uiAlignPanelStep(region, 0.2f, true);
- }
+ uiAlignPanelStep(region, 0.2f, true);
ED_region_tag_redraw(region);
}
@@ -1955,7 +1982,7 @@ static uiPanelMouseState ui_panel_mouse_state_get(const uiBlock *block,
return PANEL_MOUSE_INSIDE_HEADER;
}
- if (!(panel->flag & PNL_CLOSED)) {
+ if (!UI_panel_is_closed(panel)) {
if (IN_RANGE((float)my, block->rect.ymin, block->rect.ymax + PNL_HEADER)) {
return PANEL_MOUSE_INSIDE_CONTENT;
}
@@ -1991,10 +2018,10 @@ static void ui_panel_drag_collapse(const bContext *C,
}
const int oldflag = panel->flag;
- /* lock axis */
+ /* Lock axis. */
xy_b_block[0] = dragcol_data->xy_init[0];
- /* use cursor coords in block space */
+ /* Use cursor coords in block space. */
ui_window_to_block_fl(region, block, &xy_a_block[0], &xy_a_block[1]);
ui_window_to_block_fl(region, block, &xy_b_block[0], &xy_b_block[1]);
@@ -2003,12 +2030,13 @@ static void ui_panel_drag_collapse(const bContext *C,
rect.ymin = rect.ymax;
rect.ymax = rect.ymin + PNL_HEADER;
- /* touch all panels between last mouse coord and the current one */
+ /* Touch all panels between last mouse coordinate and the current one. */
if (BLI_rctf_isect_segment(&rect, xy_a_block, xy_b_block)) {
/* Force panel to open or close. */
+ panel->runtime_flag &= ~PANEL_USE_CLOSED_FROM_SEARCH;
SET_FLAG_FROM_TEST(panel->flag, dragcol_data->was_first_open, PNL_CLOSED);
- /* if panel->flag has changed this means a panel was opened/closed here */
+ /* If panel->flag has changed this means a panel was opened/closed here. */
if (panel->flag != oldflag) {
panel_activate_state(C, panel, PANEL_STATE_ANIMATION);
}
@@ -2019,9 +2047,10 @@ static void ui_panel_drag_collapse(const bContext *C,
}
/**
- * Panel drag-collapse (modal handler)
- * Clicking and dragging over panels toggles their collapse state based on the panel that was first
- * dragged over. If it was open all affected panels incl the initial one are closed and vice versa.
+ * Panel drag-collapse (modal handler).
+ * Clicking and dragging over panels toggles their collapse state based on the panel
+ * that was first dragged over. If it was open all affected panels including the initial
+ * one are closed and vice versa.
*/
static int ui_panel_drag_collapse_handler(bContext *C, const wmEvent *event, void *userdata)
{
@@ -2037,7 +2066,7 @@ static int ui_panel_drag_collapse_handler(bContext *C, const wmEvent *event, voi
break;
case LEFTMOUSE:
if (event->val == KM_RELEASE) {
- /* done! */
+ /* Done! */
WM_event_remove_ui_handler(&win->modalhandlers,
ui_panel_drag_collapse_handler,
ui_panel_drag_collapse_handler_remove,
@@ -2045,7 +2074,7 @@ static int ui_panel_drag_collapse_handler(bContext *C, const wmEvent *event, voi
true);
ui_panel_drag_collapse_handler_remove(C, dragcol_data);
}
- /* don't let any left-mouse event fall through! */
+ /* Don't let any left-mouse event fall through! */
retval = WM_UI_HANDLER_BREAK;
break;
}
@@ -2077,9 +2106,9 @@ static void ui_panel_drag_collapse_handler_add(const bContext *C, const bool was
* \param mx: The mouse x coordinate, in panel space.
*/
static void ui_handle_panel_header(const bContext *C,
- uiBlock *block,
+ const uiBlock *block,
const int mx,
- short int event_type,
+ const int event_type,
const short ctrl,
const short shift)
{
@@ -2113,7 +2142,7 @@ static void ui_handle_panel_header(const bContext *C,
if (ELEM(event_type, EVT_RETKEY, EVT_PADENTER, EVT_AKEY) || mx < expansion_area_xmax) {
if (ctrl && !is_subpanel) {
/* For parent panels, collapse all other panels or toggle children. */
- if (panel->flag & PNL_CLOSED || BLI_listbase_is_empty(&panel->children)) {
+ if (UI_panel_is_closed(panel) || BLI_listbase_is_empty(&panel->children)) {
panels_collapse_all(region, panel);
/* Reset the view - we don't want to display a view without content. */
@@ -2124,32 +2153,15 @@ static void ui_handle_panel_header(const bContext *C,
* of the sub-panels (based on the expansion of the first sub-panel). */
Panel *first_child = panel->children.first;
BLI_assert(first_child != NULL);
- panel_set_flag_recursive(panel, PNL_CLOSED, !(first_child->flag & PNL_CLOSED));
+ panel_set_flag_recursive(panel, PNL_CLOSED, !UI_panel_is_closed(first_child));
panel->flag |= PNL_CLOSED;
}
}
- if (panel->flag & PNL_CLOSED) {
- panel->flag &= ~PNL_CLOSED;
- /* Snap back up so full panel aligns with screen edge. */
- if (panel->snap & PNL_SNAP_BOTTOM) {
- panel->ofsy = 0;
- }
-
- if (event_type == LEFTMOUSE) {
- ui_panel_drag_collapse_handler_add(C, false);
- }
- }
- else {
- /* Snap down to bottom screen edge. */
- panel->flag |= PNL_CLOSED;
- if (panel->snap & PNL_SNAP_BOTTOM) {
- panel->ofsy = -panel->sizey;
- }
+ SET_FLAG_FROM_TEST(panel->flag, !UI_panel_is_closed(panel), PNL_CLOSED);
- if (event_type == LEFTMOUSE) {
- ui_panel_drag_collapse_handler_add(C, true);
- }
+ if (event_type == LEFTMOUSE) {
+ ui_panel_drag_collapse_handler_add(C, UI_panel_is_closed(panel));
}
set_panels_list_data_expand_flag(C, region);
@@ -2181,12 +2193,12 @@ static void ui_handle_panel_header(const bContext *C,
bool UI_panel_category_is_visible(const ARegion *region)
{
- /* more than one */
+ /* Check for more than one category. */
return region->panels_category.first &&
region->panels_category.first != region->panels_category.last;
}
-PanelCategoryDyn *UI_panel_category_find(ARegion *region, const char *idname)
+PanelCategoryDyn *UI_panel_category_find(const ARegion *region, const char *idname)
{
return BLI_findstring(&region->panels_category, idname, offsetof(PanelCategoryDyn, idname));
}
@@ -2218,9 +2230,9 @@ static void ui_panel_category_active_set(ARegion *region, const char *idname, bo
BLI_addhead(lb, pc_act);
}
- /* Validate all active panels, we could do this on load,
- * they are harmless - but we should remove somewhere.
- * (add-ons could define own and gather cruft over time). */
+ /* Validate all active panels. We could do this on load, they are harmless -
+ * but we should remove them somewhere.
+ * (Add-ons could define panels and gather cruft over time). */
{
PanelCategoryStack *pc_act_next;
/* intentionally skip first */
@@ -2267,10 +2279,10 @@ const char *UI_panel_category_active_get(ARegion *region, bool set_fallback)
return NULL;
}
-PanelCategoryDyn *UI_panel_category_find_mouse_over_ex(ARegion *region, const int x, const int y)
+static PanelCategoryDyn *panel_categories_find_mouse_over(ARegion *region, const wmEvent *event)
{
LISTBASE_FOREACH (PanelCategoryDyn *, ptd, &region->panels_category) {
- if (BLI_rcti_isect_pt(&ptd->rect, x, y)) {
+ if (BLI_rcti_isect_pt(&ptd->rect, event->mval[0], event->mval[1])) {
return ptd;
}
}
@@ -2278,11 +2290,6 @@ PanelCategoryDyn *UI_panel_category_find_mouse_over_ex(ARegion *region, const in
return NULL;
}
-PanelCategoryDyn *UI_panel_category_find_mouse_over(ARegion *region, const wmEvent *event)
-{
- return UI_panel_category_find_mouse_over_ex(region, event->mval[0], event->mval[1]);
-}
-
void UI_panel_category_add(ARegion *region, const char *name)
{
PanelCategoryDyn *pc_dyn = MEM_callocN(sizeof(*pc_dyn), __func__);
@@ -2290,7 +2297,7 @@ void UI_panel_category_add(ARegion *region, const char *name)
BLI_strncpy(pc_dyn->idname, name, sizeof(pc_dyn->idname));
- /* 'pc_dyn->rect' must be set on draw */
+ /* 'pc_dyn->rect' must be set on draw. */
}
void UI_panel_category_clear_all(ARegion *region)
@@ -2308,14 +2315,13 @@ static int ui_handle_panel_category_cycling(const wmEvent *event,
(event->mval[0] < ((PanelCategoryDyn *)region->panels_category.first)->rect.xmax) :
(event->mval[0] > ((PanelCategoryDyn *)region->panels_category.first)->rect.xmin));
- /* if mouse is inside non-tab region, ctrl key is required */
+ /* If mouse is inside non-tab region, ctrl key is required. */
if (is_mousewheel && !event->ctrl && !inside_tabregion) {
return WM_UI_HANDLER_CONTINUE;
}
if (active_but && ui_but_supports_cycling(active_but)) {
- /* skip - exception to make cycling buttons
- * using ctrl+mousewheel work in tabbed regions */
+ /* Skip - exception to make cycling buttons using ctrl+mousewheel work in tabbed regions. */
}
else {
const char *category = UI_panel_category_active_get(region, false);
@@ -2323,22 +2329,21 @@ static int ui_handle_panel_category_cycling(const wmEvent *event,
PanelCategoryDyn *pc_dyn = UI_panel_category_find(region, category);
if (LIKELY(pc_dyn)) {
if (is_mousewheel) {
- /* we can probably get rid of this and only allow ctrl+tabbing */
+ /* We can probably get rid of this and only allow ctrl-tabbing. */
pc_dyn = (event->type == WHEELDOWNMOUSE) ? pc_dyn->next : pc_dyn->prev;
}
else {
const bool backwards = event->shift;
pc_dyn = backwards ? pc_dyn->prev : pc_dyn->next;
if (!pc_dyn) {
- /* proper cyclic behavior,
- * back to first/last category (only used for ctrl+tab) */
+ /* Proper cyclic behavior, back to first/last category (only used for ctrl+tab). */
pc_dyn = backwards ? region->panels_category.last : region->panels_category.first;
}
}
if (pc_dyn) {
- /* intentionally don't reset scroll in this case,
- * this allows for quick browsing between tabs */
+ /* Intentionally don't reset scroll in this case,
+ * allowing for quick browsing between tabs. */
UI_panel_category_active_set(region, pc_dyn->idname);
ED_region_tag_redraw(region);
}
@@ -2380,7 +2385,7 @@ int ui_handler_panel_region(bContext *C,
/* Handle category tabs. */
if (UI_panel_category_is_visible(region)) {
if (event->type == LEFTMOUSE) {
- PanelCategoryDyn *pc_dyn = UI_panel_category_find_mouse_over(region, event);
+ PanelCategoryDyn *pc_dyn = panel_categories_find_mouse_over(region, event);
if (pc_dyn) {
UI_panel_category_active_set(region, pc_dyn->idname);
ED_region_tag_redraw(region);
@@ -2420,9 +2425,14 @@ int ui_handler_panel_region(bContext *C,
const uiPanelMouseState mouse_state = ui_panel_mouse_state_get(block, panel, mx, my);
- /* The panel collapse / expand key "A" is special as it takes priority over
- * active button handling. */
- if (ELEM(mouse_state, PANEL_MOUSE_INSIDE_CONTENT, PANEL_MOUSE_INSIDE_HEADER)) {
+ if (mouse_state != PANEL_MOUSE_OUTSIDE) {
+ /* Mark panels that have been interacted with so their expansion
+ * doesn't reset when property search finishes. */
+ SET_FLAG_FROM_TEST(panel->flag, UI_panel_is_closed(panel), PNL_CLOSED);
+ panel->runtime_flag &= ~PANEL_USE_CLOSED_FROM_SEARCH;
+
+ /* The panel collapse / expand key "A" is special as it takes priority over
+ * active button handling. */
if (event->type == EVT_AKEY && !IS_EVENT_MOD(event, shift, ctrl, alt, oskey)) {
retval = WM_UI_HANDLER_BREAK;
ui_handle_panel_header(C, block, mx, event->type, event->ctrl, event->shift);
@@ -2517,13 +2527,13 @@ PointerRNA *UI_region_panel_custom_data_under_cursor(const bContext *C, const wm
/** \name Window Level Modal Panel Interaction
* \{ */
-/* note, this is modal handler and should not swallow events for animation */
+/* Note, this is modal handler and should not swallow events for animation. */
static int ui_handler_panel(bContext *C, const wmEvent *event, void *userdata)
{
Panel *panel = userdata;
uiHandlePanelData *data = panel->activedata;
- /* verify if we can stop */
+ /* Verify if we can stop. */
if (event->type == LEFTMOUSE && event->val == KM_RELEASE) {
panel_activate_state(C, panel, PANEL_STATE_ANIMATION);
}
@@ -2556,7 +2566,7 @@ static void ui_handler_remove_panel(bContext *C, void *userdata)
panel_activate_state(C, panel, PANEL_STATE_EXIT);
}
-static void panel_activate_state(const bContext *C, Panel *panel, uiHandlePanelState state)
+static void panel_activate_state(const bContext *C, Panel *panel, const uiHandlePanelState state)
{
uiHandlePanelData *data = panel->activedata;
wmWindow *win = CTX_wm_window(C);
@@ -2566,15 +2576,20 @@ static void panel_activate_state(const bContext *C, Panel *panel, uiHandlePanelS
return;
}
- const bool was_drag_drop = (data && data->state == PANEL_STATE_DRAG);
-
- /* Set selection state for the panel and its sub-panels, which need to know they are selected
- * too so they can be drawn above their parent when it's dragged. */
- if (state == PANEL_STATE_EXIT || state == PANEL_STATE_ANIMATION) {
+ /*
+ * Note on "select" and "drag drop" flags:
+ * First, the panel is "picked up" and both flags are set. Then when the mouse releases
+ * and the panel starts animating to its aligned position, PNL_SELECT is unset. When the
+ * animation finishes, PANEL_IS_DRAG_DROP is cleared. */
+ if (state == PANEL_STATE_DRAG) {
+ panel_set_flag_recursive(panel, PNL_SELECT, true);
+ panel_set_runtime_flag_recursive(panel, PANEL_IS_DRAG_DROP, true);
+ }
+ else if (state == PANEL_STATE_ANIMATION) {
panel_set_flag_recursive(panel, PNL_SELECT, false);
}
- else {
- panel_set_flag_recursive(panel, PNL_SELECT, true);
+ else if (state == PANEL_STATE_EXIT) {
+ panel_set_runtime_flag_recursive(panel, PANEL_IS_DRAG_DROP, false);
}
if (data && data->animtimer) {
@@ -2613,32 +2628,12 @@ static void panel_activate_state(const bContext *C, Panel *panel, uiHandlePanelS
data->starty = win->eventstate->y;
data->startofsx = panel->ofsx;
data->startofsy = panel->ofsy;
- data->startsizex = panel->sizex;
- data->startsizey = panel->sizey;
data->start_cur_xmin = region->v2d.cur.xmin;
data->start_cur_ymin = region->v2d.cur.ymin;
data->starttime = PIL_check_seconds_timer();
-
- /* Remember drag drop state even when animating to the aligned position after dragging. */
- data->is_drag_drop = was_drag_drop;
- if (state == PANEL_STATE_DRAG) {
- data->is_drag_drop = true;
- }
}
ED_region_tag_redraw(region);
}
-PanelType *UI_paneltype_find(int space_id, int region_id, const char *idname)
-{
- SpaceType *st = BKE_spacetype_from_id(space_id);
- if (st) {
- ARegionType *art = BKE_regiontype_from_id(st, region_id);
- if (art) {
- return BLI_findstring(&art->paneltypes, idname, offsetof(PanelType, idname));
- }
- }
- return NULL;
-}
-
/** \} */