1
1

Compare commits

...

73 Commits

Author SHA1 Message Date
ef11238c74 Merge branch 'master' into property-search-ui 2020-08-11 21:59:16 -04:00
1f768bbe41 Merge branch 'master' into property-search-ui 2020-07-28 17:25:39 -04:00
ce6cf2b475 Property Search: Various cleanups and comment changes 2020-07-28 17:12:09 -04:00
f957e09398 Merge branch 'master' into property-search-ui 2020-07-28 14:25:00 -04:00
d58f361099 Property Search: Remove commented out code 2020-07-28 13:48:36 -04:00
1b391f14fc Property Search: Fixes for other-tab searching
The main change here is not running the search twice for the active tab.
We also check for the panel being active rather than just not filtered.

There are still errors when the tool tab is active, those will be solved
in a future commit.
2020-07-28 12:11:48 -04:00
b4b2185da0 Property Search: Remove debugging information 2020-07-27 16:39:43 -04:00
8f548fd856 Merge branch 'master' into property-search-ui 2020-07-27 16:32:49 -04:00
634bf8e4fc Merge branch 'master' into property-search-ui 2020-07-27 12:34:08 -04:00
af146e7745 Use operator to toggle pin data-block 2020-07-23 12:16:49 -04:00
4b0a94661c Property Search: Clean up some unecessary changes 2020-07-23 11:36:40 -04:00
8eda823dbc Merge branch 'master' into property-search-ui 2020-07-23 11:04:11 -04:00
e40225577b Merge branch 'master' into property-search-ui 2020-07-22 22:28:48 -04:00
d219d0efa1 Property Search: Fix graying out tabs with no results 2020-07-22 15:14:06 -04:00
cc1201dce3 Property Search: Improve debug printing 2020-07-22 12:09:54 -04:00
1afdc92511 Merge branch 'master' into property-search-ui 2020-07-22 11:35:02 -04:00
20ce4a77bd Property Search: Properly filter labels for color buttons 2020-07-20 16:24:39 -04:00
7d3d6ac085 Merge branch 'master' into property-search-ui 2020-07-20 15:45:34 -04:00
304e9a0b9e Merge branch 'master' into property-search-ui 2020-07-10 13:20:49 -04:00
31657ebbbe Property Search: Initial implementation of searching all tabs
The basics should be close to working. The space and necessary context
is duplicated, then the context is switched and that tab is searched.
However, this is still pretty buggy and the enum isn't drawing correctly.
I'm probably not filling the bitfield correctly.

Mainly committing this to get it out there and focus on smaller fixes /
improvements to it.
2020-07-09 16:25:20 -04:00
169ac2805e Property Search: Add search filter active tabs property
I also generalized the tab "adding" code in RNA to make it usable for filling
both the context enum and the active search filter tabs properties. The tab
layout code might need to be extended to add the idea of a custom
highlight property.
2020-07-09 08:45:54 -04:00
c914bff16d Property Search: Fix panels occasionally overlapping 2020-07-08 13:56:55 -04:00
7758bb25e7 Property Search: Fix panels animating when added 2020-07-08 11:52:52 -04:00
94272e8347 Merge branch 'master' into property-search-ui 2020-07-08 11:06:47 -04:00
67d6d1363d Property Search: Properly filter box buttons 2020-07-07 15:27:29 -04:00
b7d47e9892 Property Search: Apply filter to operator buttons 2020-07-07 14:44:30 -04:00
6f5ca857fc Property Search: Move button tagging to separate function 2020-07-07 13:55:34 -04:00
71c6af4d59 Property Search: Solve memory leak 2020-07-07 13:21:23 -04:00
2f68b79fa8 Property Search: Cleanup, remove unrelated changes 2020-07-07 12:24:14 -04:00
98c6349bca Merge branch 'master' into property-search-ui 2020-07-07 11:10:53 -04:00
4c1095d33c Property Search: Support labels and expanded enums 2020-07-07 10:58:06 -04:00
847837c808 Property Search: Support labels and array buttons 2020-07-07 10:48:49 -04:00
16bf1807a1 Merge branch 'master' into property-search-ui 2020-07-07 10:18:44 -04:00
052baecc0d Merge branch 'master' into property-search-ui 2020-07-02 18:11:25 -04:00
34c5245c32 Property Search: Support heading labels 2020-07-01 15:16:44 -04:00
42e5314727 Property Search: Support checkboxes with no headings
Further changes will be needed to keep track of the labels added
for headings.
2020-07-01 15:10:40 -04:00
7137e99ff3 Property Search: Fix some filtered buttons not hidden 2020-07-01 12:35:57 -04:00
f3e409c1bf Property Search: Fix X margin accumulating for box panels 2020-07-01 12:11:14 -04:00
92c201b493 Property Search: Turn off search for add constraints buttons 2020-07-01 11:35:20 -04:00
7955c26f41 Merge branch 'master' into property-search-ui 2020-07-01 11:11:19 -04:00
26450636cd Property Search: Support labels with number buttons 2020-06-30 21:29:04 -04:00
f3b83271e6 Property Search: Support labels with ui_item_with_label
This includes unexpanded enums and "pointer" selection buttons, and
possibly others.

This necessitates changing uiItemL_respect_property_split to return the
label button it creates, which is reasonably anyway as it makes it
consistent with uiItemL_.
2020-06-30 21:17:27 -04:00
136475dca3 Property Search: Refactor to simpler method
This method doesn't try to change the input layouts at all. Instead it
filters out the empty buttons and removes layouts that become empty
after that.

Pointers for labels and decorators have been added to uiBut. They will
be set during the layout building process in future commits. For now
all labels will be removed though.
2020-06-30 18:54:10 -04:00
544ac33b61 Property Search: Always animate panels when filter status changes
This should finally be a proper solution to this problem. Now the last
search filter status is stored and compared to the new one to
activate animation.
2020-06-30 12:07:28 -04:00
263e42a172 Property Search: Filter panel names without case sensitivity 2020-06-30 11:42:44 -04:00
b7938c3768 Merge branch 'master' into property-search-ui 2020-06-30 09:28:26 -04:00
be7a4f4a81 Property Search: Cleaup: Remove unused variable 2020-06-29 17:09:45 -04:00
dbc9f1b0f3 Merge branch 'master' into property-search-ui 2020-06-29 17:08:57 -04:00
f3caadec90 Merge branch 'master' into property-search-ui 2020-06-29 11:29:55 -04:00
11b89dd56c Property Search: Don't remove layouts with search turned off
This mostly fixes panel headers, although they still end up with the same
problems as other layouts, with a minimum column size enforced for some
reason and misplaced labels.
2020-06-26 14:16:44 -04:00
5218fb969f Merge branch 'master' into property-search-ui 2020-06-26 10:16:50 -04:00
411f425973 Merge branch 'master' into property-search-ui 2020-06-26 09:21:29 -04:00
d4b9f41a56 Property Search: Print debug with colors 2020-06-26 09:20:06 -04:00
66ac0448ef Property Search: Improve layout debugging tool
The tool now prints button types as well. Click to drag a panel while a
search is active to print a tree of the layouts, sublayouts, and buttons.
2020-06-25 21:39:05 -04:00
170a40c338 Property Search: Sort filtered panels properly
Instead of just putting the filtered panels at the bottom, or not updating
their search order, we stop increasing the offset while the current panel
is invisible. This way the order is not completely broken if you drag to
reorder a panel while some have been filtered out.
2020-06-25 16:53:18 -04:00
d2c00d1d7f Merge branch 'master' into property-search-ui 2020-06-25 16:17:08 -04:00
cf99c25dbe Merge branch 'master' into property-search-ui 2020-06-25 12:16:26 -04:00
c95d6de3b3 Property Search: Improve interaction with panels 2020-06-19 07:41:12 -04:00
a33720329b Property Search: New method that reuses existing layouts
This method just transforms each layout into a row or a column, without
adding any new layouts at all. There are a few problems with this method
though, the columns have a fixed width for some reason, and it becomes
more difficult to add the label column.
2020-06-18 17:00:38 -04:00
9029c7be19 Merge branch 'master' into property-search-ui 2020-06-18 08:46:53 -04:00
463c4ef39e Property Search: Support aligned rows in search layout 2020-06-17 17:31:22 -04:00
c891ba0086 Property Search: Solve memory leak 2020-06-17 16:31:03 -04:00
09e555142a Merge branch 'master' into property-search-ui 2020-06-17 14:50:08 -04:00
4d5b6409ee Property Search: Expose layout flag to RNA, use for modifiers 2020-06-17 13:15:26 -04:00
712ccc2602 Property Search: Improve interaction with panels
This isn't perfect yet, but the animation is back, and it works much better.
There are still two issues though:
  1. Order doesn't update sometimes while searching / ending search.
  2. Panels are still displayed when empty in some situations.
The solution is probably just adding some more special cases. Possibly
a tag for panel aligning when the search filter is changed to force special
ordering calculations.
2020-06-17 13:14:58 -04:00
85fe4a18e8 Property Search: Various small cleanups 2020-06-17 10:21:38 -04:00
8357b7fe46 Merge branch 'master' into property-search-ui 2020-06-17 09:08:26 -04:00
13b283ca8e Property Search: Make ctrl-F work, and alt-F to clear 2020-06-16 11:54:38 -04:00
723f6e7f53 Merge branch 'master' into property-search-ui 2020-06-16 10:50:35 -04:00
040931a9b2 Merge branch 'master' into property-search-ui 2020-06-12 22:01:59 -04:00
a34c25046b Property Search: Refactor / simplify, and better layout
The single column layout works much better now, as most of the code that
dealt with trying to remove empty layouts has been rewritten. The search
filter code is not a completely separate pass for the sake of simplicity.

Also, toggle buttons have their text replaced with the rna property name.

There branch is far from stable, and there's a tricky memory leak still to
track down as well.
2020-06-12 21:59:07 -04:00
e299727fba Merge branch 'master' into property-search-ui 2020-06-12 10:26:05 -04:00
db76f34ed6 UI: Start towards property search in public branch
This is VERY WIP, but I will continue work in this branch. Implementation
starts with a few things:
  - A pass at the end of the layout system to scan buttons based on a
    search string set by the properties space. Buttons which don't fit
    the filter are removed from the layouts.
  - A pass after the filter to move buttons that are still in layouts
    to a single column "search layout." There is currently a bug with
    this that adds too much space in between items.
  - An attempt to only show panels that haven't been completely
    filtered by the previous two steps. This is quite buggy right now:
    panels don't animate properly and sometimes it fails.
  - An attempt at a keymap item "ctrl-F" to activate the search button.
    "alt-F" should probably clear the button too.
2020-06-11 18:07:24 -04:00
20 changed files with 1091 additions and 218 deletions

View File

@@ -736,6 +736,8 @@ def km_property_editor(_params):
{"properties": [("direction", 'PREV'), ], },),
("screen.space_context_cycle", {"type": 'WHEELDOWNMOUSE', "value": 'PRESS', "ctrl": True},
{"properties": [("direction", 'NEXT'), ], },),
("buttons.start_filter", {"type": 'F', "value": 'PRESS', "ctrl": True}, None),
("buttons.clear_filter", {"type": 'F', "value": 'PRESS', "alt": True}, None),
# Modifier panels
("object.modifier_remove", {"type": 'X', "value": 'PRESS'}, {"properties": [("report", True)]}),
("object.modifier_remove", {"type": 'DEL', "value": 'PRESS'}, {"properties": [("report", True)]}),

View File

@@ -44,6 +44,7 @@ class OBJECT_PT_constraints(ObjectConstraintPanel):
def draw(self, context):
layout = self.layout
layout.use_property_search = False
layout.operator_menu_enum("object.constraint_add", "type", text="Add Object Constraint")
@@ -58,6 +59,7 @@ class BONE_PT_constraints(BoneConstraintPanel):
def draw(self, context):
layout = self.layout
layout.use_property_search = False
layout.operator_menu_enum("pose.constraint_add", "type", text="Add Bone Constraint")

View File

@@ -39,6 +39,7 @@ class DATA_PT_modifiers(ModifierButtonsPanel, Panel):
def draw(self, context):
layout = self.layout
layout.use_property_search = False
layout.operator_menu_enum("object.modifier_add", "type")
layout.template_modifiers()

View File

@@ -23,11 +23,20 @@ from bpy.types import Header, Panel
class PROPERTIES_HT_header(Header):
bl_space_type = 'PROPERTIES'
def draw(self, _context):
def draw(self, context):
layout = self.layout
view = context.space_data
layout.template_header()
layout.separator_spacer()
layout.prop(view, "filter_text", icon='VIEWZOOM', text="")
layout.separator_spacer()
row = layout.row()
row.emboss = 'NONE'
row.operator("buttons.toggle_pin", icon=('PINNED' if view.use_pin_id else 'UNPINNED'), text="")
class PROPERTIES_PT_navigation_bar(Panel):
bl_space_type = 'PROPERTIES'
@@ -42,6 +51,10 @@ class PROPERTIES_PT_navigation_bar(Panel):
layout.scale_x = 1.4
layout.scale_y = 1.4
if view.filter_text:
layout.prop_tabs_enum(view, "context", data_highlight=view,
property_highlight="context_search_filter_active", icon_only=True)
else:
layout.prop_tabs_enum(view, "context", icon_only=True)

View File

@@ -157,6 +157,11 @@ enum {
UI_BLOCK_POPOVER_ONCE = 1 << 22,
/** Always show keymaps, even for non-menus. */
UI_BLOCK_SHOW_SHORTCUT_ALWAYS = 1 << 23,
/** All items have been removed from the block by the search filter. */
UI_BLOCK_FILTERED_EMPTY = 1 << 24,
/** The block is only used during the layout process and will not be drawn,
* for the case of a subpanel of a closed panel. */
UI_BLOCK_SEARCH_ONLY = 1 << 25,
};
/** #uiPopupBlockHandle.menuretval */
@@ -671,6 +676,9 @@ enum {
void UI_block_theme_style_set(uiBlock *block, char theme_style);
char UI_block_emboss_get(uiBlock *block);
void UI_block_emboss_set(uiBlock *block, char emboss);
bool UI_block_has_search_filter(const uiBlock *block);
bool UI_block_is_search_only(const uiBlock *block);
void UI_block_set_search_only(uiBlock *block, bool search_only);
void UI_block_free(const struct bContext *C, uiBlock *block);
void UI_blocklist_free(const struct bContext *C, struct ListBase *lb);
@@ -1685,6 +1693,8 @@ void UI_panels_scale(struct ARegion *region, float new_width);
void UI_panel_label_offset(struct uiBlock *block, int *r_x, int *r_y);
int UI_panel_size_y(const struct Panel *panel);
bool UI_panel_is_dragging(const struct Panel *panel);
bool UI_panel_is_search_filtered(const struct Panel *panel);
bool UI_panel_is_active(const struct Panel *panel);
bool UI_panel_category_is_visible(const struct ARegion *region);
void UI_panel_category_add(struct ARegion *region, const char *name);
@@ -1708,6 +1718,8 @@ struct PointerRNA *UI_region_panel_custom_data_under_cursor(const struct bContex
const struct wmEvent *event);
void UI_panel_custom_data_set(struct Panel *panel, struct PointerRNA *custom_data);
void UI_region_panels_remove_handlers(const struct bContext *C, struct ARegion *region);
/* Polyinstantiated panels for representing a list of data. */
struct Panel *UI_panel_add_instanced(struct ScrArea *area,
struct ARegion *region,
@@ -1894,6 +1906,7 @@ void uiLayoutSetUnitsY(uiLayout *layout, float unit);
void uiLayoutSetEmboss(uiLayout *layout, char emboss);
void uiLayoutSetPropSep(uiLayout *layout, bool is_sep);
void uiLayoutSetPropDecorate(uiLayout *layout, bool is_sep);
void uiLayoutSetPropSearch(uiLayout *layout, bool is_searchable);
int uiLayoutGetLocalDir(const uiLayout *layout);
int uiLayoutGetOperatorContext(uiLayout *layout);
@@ -1913,6 +1926,8 @@ float uiLayoutGetUnitsY(uiLayout *layout);
int uiLayoutGetEmboss(uiLayout *layout);
bool uiLayoutGetPropSep(uiLayout *layout);
bool uiLayoutGetPropDecorate(uiLayout *layout);
bool uiLayoutGetPropSearch(uiLayout *layout);
void uiLayoutRootSetSearchOnly(uiLayout *layout, bool search_only);
/* layout specifiers */
uiLayout *uiLayoutRow(uiLayout *layout, bool align);
@@ -2358,7 +2373,10 @@ uiPropertySplitWrapper uiItemPropertySplitWrapperCreate(uiLayout *parent_layout)
void uiItemL(uiLayout *layout, const char *name, int icon); /* label */
void uiItemL_ex(
uiLayout *layout, const char *name, int icon, const bool highlight, const bool redalert);
uiLayout *uiItemL_respect_property_split(uiLayout *layout, const char *text, int icon);
uiBut *uiItemL_respect_property_split(uiLayout *layout,
const char *text,
int icon,
uiLayout **r_layout);
/* label icon for dragging */
void uiItemLDrag(uiLayout *layout, struct PointerRNA *ptr, const char *name, int icon);
/* menu */
@@ -2410,6 +2428,8 @@ void uiItemTabsEnumR_prop(uiLayout *layout,
struct bContext *C,
struct PointerRNA *ptr,
PropertyRNA *prop,
struct PointerRNA *ptr_highlight,
PropertyRNA *prop_highlight,
bool icon_only);
/* UI Operators */

View File

@@ -3425,12 +3425,20 @@ uiBlock *UI_block_begin(const bContext *C, ARegion *region, const char *name, ch
window = CTX_wm_window(C);
scn = CTX_data_scene(C);
ScrArea *area = CTX_wm_area(C);
block = MEM_callocN(sizeof(uiBlock), "uiBlock");
block->active = 1;
block->emboss = emboss;
block->evil_C = (void *)C; /* XXX */
/* Set the search filter for the properties editor. */
if ((region && region->regiontype == RGN_TYPE_WINDOW) &&
(area && area->spacetype == SPACE_PROPERTIES)) {
SpaceProperties *sbuts = CTX_wm_space_properties(C);
block->search_filter = sbuts->search_string;
}
if (scn) {
/* store display device name, don't lookup for transformations yet
* block could be used for non-color displays where looking up for transformation
@@ -3480,6 +3488,21 @@ void UI_block_theme_style_set(uiBlock *block, char theme_style)
block->theme_style = theme_style;
}
bool UI_block_has_search_filter(const uiBlock *block)
{
return block->search_filter != NULL && block->search_filter[0] != '\0';
}
bool UI_block_is_search_only(const uiBlock *block)
{
return block->flag & UI_BLOCK_SEARCH_ONLY;
}
void UI_block_set_search_only(uiBlock *block, bool search_only)
{
SET_FLAG_FROM_TEST(block->flag, search_only, UI_BLOCK_SEARCH_ONLY);
}
static void ui_but_build_drawstr_float(uiBut *but, double value)
{
size_t slen = 0;

View File

@@ -79,6 +79,7 @@ enum {
UI_HAS_ICON = (1 << 3),
UI_HIDDEN = (1 << 4),
UI_SELECT_DRAW = (1 << 5), /* Display selected, doesn't impact interaction. */
UI_FILTERED = (1 << 12), /* Filtered by the search string, removed if in a layout. */
/* warn: rest of uiBut->flag in UI_interface.h */
};
@@ -273,6 +274,14 @@ struct uiBut {
uiButPushedStateFunc pushed_state_func;
void *pushed_state_arg;
/**
* Used for property search, so that a button's label and decorator can be filtered and
* unfiltered along with it. Due to the sometimes arbitrary nature of these values,
* they aren't always filled.
*/
uiBut *label_but;
uiBut *decorator_but;
/* pointer back */
uiBlock *block;
};
@@ -393,7 +402,7 @@ struct uiBlock {
ListBase butstore; /* UI_butstore_* runtime function */
ListBase layouts;
ListBase layouts; /* Note: Should be called layout_roots. */
struct uiLayout *curlayout;
ListBase contexts;
@@ -488,6 +497,8 @@ struct uiBlock {
*/
char display_device[64];
char *search_filter;
struct PieMenuData pie_data;
};
@@ -777,6 +788,7 @@ extern void ui_draw_aligned_panel(struct uiStyle *style,
const rcti *rect,
const bool show_pin,
const bool show_background);
void ui_panel_set_search_filtered(struct Panel *panel, const bool value);
/* interface_draw.c */
extern void ui_draw_dropshadow(

View File

@@ -85,6 +85,11 @@ typedef struct uiLayoutRoot {
int type;
int opcontext;
/** If true, the root will be removed as part of the property search process.
* Necessary for cases like searching the contents of closed panels, where the
* block-level tag isn't enough because there might be buttons in the header. */
bool search_only;
int emw, emh;
int padding;
@@ -140,6 +145,7 @@ enum {
* Enabled by default, depends on 'UI_ITEM_PROP_SEP'. */
UI_ITEM_PROP_DECORATE = 1 << 5,
UI_ITEM_PROP_DECORATE_NO_PAD = 1 << 6,
UI_ITEM_USE_SEARCH_FILTER = 1 << 7,
};
typedef struct uiButtonItem {
@@ -176,6 +182,8 @@ struct uiLayout {
char emboss;
/** for fixed width or height to avoid UI size changes */
float units[2];
bool property_search_layout_temp_debug;
};
typedef struct uiLayoutItemFlow {
@@ -219,6 +227,8 @@ typedef struct uiLayoutItemRoot {
/** \} */
static uiBut *uiItemL_(uiLayout *layout, const char *name, int icon);
/* -------------------------------------------------------------------- */
/** \name Item
* \{ */
@@ -494,7 +504,8 @@ static void ui_item_array(uiLayout *layout,
int toggle,
bool icon_only,
bool compact,
bool show_text)
bool show_text,
uiBut *label_but)
{
const uiStyle *style = layout->root->style;
uiBut *but;
@@ -656,7 +667,10 @@ static void ui_item_array(uiLayout *layout,
/* special case, boolean array in a menu, this could be used in a more generic way too */
if (ELEM(subtype, PROP_COLOR, PROP_COLOR_GAMMA) && !expand && ELEM(len, 3, 4)) {
uiDefAutoButR(block, ptr, prop, -1, "", ICON_NONE, 0, 0, w, UI_UNIT_Y);
but = uiDefAutoButR(block, ptr, prop, -1, "", ICON_NONE, 0, 0, w, UI_UNIT_Y);
if (label_but != NULL) {
but->label_but = label_but;
}
}
else {
bool *boolarr = NULL;
@@ -704,6 +718,13 @@ static void ui_item_array(uiLayout *layout,
if ((a == 0) && (subtype == PROP_AXISANGLE)) {
UI_but_unit_type_set(but, PROP_UNIT_ROTATION);
}
/* Set the label button for the array item. */
if (label_but != NULL) {
but->label_but = label_but;
label_but = label_but->next;
BLI_assert(label_but != NULL);
}
}
if (boolarr) {
@@ -746,7 +767,8 @@ static void ui_item_enum_expand_elem_exec(uiLayout *layout,
const eButType but_type,
const bool icon_only,
const EnumPropertyItem *item,
const bool is_first)
const bool is_first,
uiBut *label_but)
{
const char *name = (!uiname || uiname[0]) ? item->name : "";
const int icon = item->icon;
@@ -785,6 +807,10 @@ static void ui_item_enum_expand_elem_exec(uiLayout *layout,
if (but_type == UI_BTYPE_TAB) {
but->flag |= UI_BUT_DRAG_LOCK;
}
if (label_but != NULL) {
but->label_but = label_but;
}
}
static void ui_item_enum_expand_exec(uiLayout *layout,
@@ -794,7 +820,8 @@ static void ui_item_enum_expand_exec(uiLayout *layout,
const char *uiname,
const int h,
const eButType but_type,
const bool icon_only)
const bool icon_only,
uiBut *label_but)
{
/* XXX: The way this function currently handles uiname parameter
* is insane and inconsistent with general UI API:
@@ -804,7 +831,8 @@ static void ui_item_enum_expand_exec(uiLayout *layout,
* this doubles the icon_only parameter.
* - we *never* draw (i.e. really use) the enum label uiname, it is just used as a mere flag!
*
* Unfortunately, fixing this implies an API "soft break", so better to defer it for later... :/
* Unfortunately, fixing this implies an API "soft break", so better to defer it for later...
* :/
* - mont29
*/
@@ -870,7 +898,7 @@ static void ui_item_enum_expand_exec(uiLayout *layout,
}
ui_item_enum_expand_elem_exec(
layout, block, ptr, prop, uiname, h, but_type, icon_only, item, is_first);
layout, block, ptr, prop, uiname, h, but_type, icon_only, item, is_first, label_but);
}
UI_block_layout_set_current(block, layout);
@@ -885,25 +913,47 @@ static void ui_item_enum_expand(uiLayout *layout,
PropertyRNA *prop,
const char *uiname,
const int h,
const bool icon_only)
const bool icon_only,
uiBut *label_but)
{
ui_item_enum_expand_exec(layout, block, ptr, prop, uiname, h, UI_BTYPE_ROW, icon_only);
ui_item_enum_expand_exec(
layout, block, ptr, prop, uiname, h, UI_BTYPE_ROW, icon_only, label_but);
}
static void ui_item_enum_expand_tabs(uiLayout *layout,
bContext *C,
uiBlock *block,
PointerRNA *ptr,
PropertyRNA *prop,
PointerRNA *ptr_highlight,
PropertyRNA *prop_highlight,
const char *uiname,
const int h,
const bool icon_only)
{
uiBut *last = block->buttons.last;
ui_item_enum_expand_exec(layout, block, ptr, prop, uiname, h, UI_BTYPE_TAB, icon_only);
ui_item_enum_expand_exec(layout, block, ptr, prop, uiname, h, UI_BTYPE_TAB, icon_only, NULL);
BLI_assert(last != block->buttons.last);
const bool use_custom_highlight = (prop_highlight != NULL);
int custom_highlight_flag = 0; /* Max of 32 tabs. */
if (use_custom_highlight) {
BLI_assert(prop_highlight != NULL);
BLI_assert(RNA_property_flag(prop_highlight) & PROP_ENUM_FLAG);
custom_highlight_flag = RNA_property_enum_get(ptr_highlight, prop_highlight);
}
int i = 0;
for (uiBut *tab = last ? last->next : block->buttons.first; tab; tab = tab->next) {
UI_but_drawflag_enable(tab, ui_but_align_opposite_to_area_align_get(CTX_wm_region(C)));
if (use_custom_highlight) {
if (!(custom_highlight_flag & (1 << i))) {
tab->flag |= UI_BUT_INACTIVE;
}
}
i++;
}
}
@@ -939,10 +989,12 @@ static uiBut *ui_item_with_label(uiLayout *layout,
{
uiLayout *sub = layout;
uiBut *but = NULL;
uiBut *label_but = NULL;
PropertyType type;
PropertySubType subtype;
int prop_but_width = w_hint;
#ifdef UI_PROP_DECORATE
uiBut *decorator_but = NULL;
uiLayout *layout_prop_decorate = NULL;
const bool use_prop_sep = ((layout->item.flag & UI_ITEM_PROP_SEP) != 0);
const bool use_prop_decorate = use_prop_sep && (layout->item.flag & UI_ITEM_PROP_DECORATE) &&
@@ -963,7 +1015,7 @@ static uiBut *ui_item_with_label(uiLayout *layout,
#ifdef UI_PROP_DECORATE
if (name[0]) {
if (use_prop_sep) {
layout_prop_decorate = uiItemL_respect_property_split(layout, name, 0);
label_but = uiItemL_respect_property_split(layout, name, 0, &layout_prop_decorate);
}
else
#endif
@@ -979,7 +1031,8 @@ static uiBut *ui_item_with_label(uiLayout *layout,
else {
w_label = w_hint / 3;
}
uiDefBut(block, UI_BTYPE_LABEL, 0, name, x, y, w_label, h, NULL, 0.0, 0.0, 0, 0, "");
label_but = uiDefBut(
block, UI_BTYPE_LABEL, 0, name, x, y, w_label, h, NULL, 0.0, 0.0, 0, 0, "");
}
}
@@ -1057,10 +1110,15 @@ static uiBut *ui_item_with_label(uiLayout *layout,
#ifdef UI_PROP_DECORATE
/* Only for alignment. */
if (use_prop_decorate) { /* Note that sep flag may have been unset meanwhile. */
uiItemL(layout_prop_decorate ? layout_prop_decorate : sub, NULL, ICON_BLANK1);
decorator_but = uiItemL_(layout_prop_decorate ? layout_prop_decorate : sub, NULL, ICON_BLANK1);
}
#endif /* UI_PROP_DECORATE */
/* Set the button's label and decorator even if they are NULL. They can be changed
* further with the return value of this function anyway. */
but->label_but = label_but;
but->decorator_but = decorator_but;
UI_block_layout_set_current(block, layout);
return but;
}
@@ -1901,28 +1959,34 @@ static uiLayout *ui_layout_heading_find(uiLayout *cur_layout)
return NULL;
}
static void ui_layout_heading_label_add(uiLayout *layout,
/**
* \return The label button added.
*/
static uiBut *ui_layout_heading_label_add(uiLayout *layout,
uiLayout *heading_layout,
bool right_align,
bool respect_prop_split)
{
const int prev_alignment = layout->alignment;
uiBut *label_but = NULL;
if (right_align) {
uiLayoutSetAlignment(layout, UI_LAYOUT_ALIGN_RIGHT);
}
if (respect_prop_split) {
uiItemL_respect_property_split(layout, heading_layout->heading, ICON_NONE);
label_but = uiItemL_respect_property_split(layout, heading_layout->heading, ICON_NONE, NULL);
}
else {
uiItemL(layout, heading_layout->heading, ICON_NONE);
label_but = uiItemL_(layout, heading_layout->heading, ICON_NONE);
}
/* After adding the heading label, we have to mark it somehow as added, so it's not added again
* for other items in this layout. For now just clear it. */
heading_layout->heading[0] = '\0';
layout->alignment = prev_alignment;
return label_but;
}
/**
@@ -1932,8 +1996,8 @@ static void ui_layout_heading_label_add(uiLayout *layout,
*/
static uiLayout *ui_item_prop_split_layout_hack(uiLayout *layout_parent, uiLayout *layout_split)
{
/* Tag item as using property split layout, this is inherited to children so they can get special
* treatment if needed. */
/* Tag item as using property split layout, this is inherited to children so they can get
* special treatment if needed. */
layout_parent->item.flag |= UI_ITEM_INSIDE_PROP_SEP;
if (layout_parent->item.type == ITEM_LAYOUT_ROW) {
@@ -1959,9 +2023,9 @@ void uiItemFullR(uiLayout *layout,
char namestr[UI_MAX_NAME_STR];
const bool use_prop_sep = ((layout->item.flag & UI_ITEM_PROP_SEP) != 0);
const bool inside_prop_sep = ((layout->item.flag & UI_ITEM_INSIDE_PROP_SEP) != 0);
/* Columns can define a heading to insert. If the first item added to a split layout doesn't have
* a label to display in the first column, the heading is inserted there. Otherwise it's inserted
* as a new row before the first item. */
/* Columns can define a heading to insert. If the first item added to a split layout doesn't
* have a label to display in the first column, the heading is inserted there. Otherwise it's
* inserted as a new row before the first item. */
uiLayout *heading_layout = ui_layout_heading_find(layout);
/* Although checkboxes use the split layout, they are an exception and should only place their
* label in the second column, to not make that almost empty.
@@ -2106,6 +2170,10 @@ void uiItemFullR(uiLayout *layout,
}
uiBut *but = NULL;
/* Store the label to assign it to the button afterwards. This is the first
* label button if the item is an array and there are a series of buttons.
* Decorators are assigned as they are built later on. */
uiBut *label_but = NULL;
/* Split the label / property. */
uiLayout *layout_parent = layout;
@@ -2125,13 +2193,13 @@ void uiItemFullR(uiLayout *layout,
layout = uiLayoutColumn(layout_row ? layout_row : layout, true);
layout->space = 0;
if (heading_layout) {
ui_layout_heading_label_add(layout, heading_layout, false, false);
label_but = ui_layout_heading_label_add(layout, heading_layout, false, false);
}
}
else {
uiLayout *layout_split = uiLayoutSplit(
layout_row ? layout_row : layout, UI_ITEM_PROP_SEP_DIVIDE, true);
bool label_added = false;
bool label_added = false; /* HANS-TODO: Replace with checking if label_but == NULL. */
layout_split->space = 0;
uiLayout *layout_sub = uiLayoutColumn(layout_split, true);
layout_sub->space = 0;
@@ -2152,7 +2220,7 @@ void uiItemFullR(uiLayout *layout,
*s++ = str[0];
*s++ = '\0';
}
but = uiDefBut(block,
uiBut *new_label = uiDefBut(block,
UI_BTYPE_LABEL,
0,
use_prefix ? name_with_suffix : str,
@@ -2166,25 +2234,35 @@ void uiItemFullR(uiLayout *layout,
0,
0,
"");
but->drawflag |= UI_BUT_TEXT_RIGHT;
but->drawflag &= ~UI_BUT_TEXT_LEFT;
new_label->drawflag |= UI_BUT_TEXT_RIGHT;
new_label->drawflag &= ~UI_BUT_TEXT_LEFT;
if (a == 0) {
label_but = new_label;
}
label_added = true;
}
}
else {
if (name) {
but = uiDefBut(
label_but = uiDefBut(
block, UI_BTYPE_LABEL, 0, name, 0, 0, w, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, "");
but->drawflag |= UI_BUT_TEXT_RIGHT;
but->drawflag &= ~UI_BUT_TEXT_LEFT;
label_but->drawflag |= UI_BUT_TEXT_RIGHT;
label_but->drawflag &= ~UI_BUT_TEXT_LEFT;
label_added = true;
}
}
if (!label_added && heading_layout) {
ui_layout_heading_label_add(layout_sub, heading_layout, true, false);
label_but = ui_layout_heading_label_add(layout_sub, heading_layout, true, false);
label_added = true;
}
/* Add an empty label button so the empty column isn't removed during property search. */
if (!label_added && !use_prop_sep_split_label) {
label_but = uiItemL_(layout_sub, "", ICON_NONE);
label_added = true;
}
layout_split = ui_item_prop_split_layout_hack(layout_parent, layout_split);
@@ -2227,7 +2305,7 @@ void uiItemFullR(uiLayout *layout,
else if (heading_layout) {
/* Could not add heading to split layout, fallback to inserting it to the layout with the
* heading itself. */
ui_layout_heading_label_add(heading_layout, heading_layout, false, false);
label_but = ui_layout_heading_label_add(heading_layout, heading_layout, false, false);
}
/* array property */
@@ -2254,26 +2332,29 @@ void uiItemFullR(uiLayout *layout,
toggle,
icon_only,
compact,
!use_prop_sep_split_label);
!use_prop_sep_split_label,
label_but);
}
/* enum item */
else if (type == PROP_ENUM && index == RNA_ENUM_VALUE) {
if (icon && name[0] && !icon_only) {
uiDefIconTextButR_prop(
but = uiDefIconTextButR_prop(
block, UI_BTYPE_ROW, 0, icon, name, 0, 0, w, h, ptr, prop, -1, 0, value, -1, -1, NULL);
}
else if (icon) {
uiDefIconButR_prop(
but = uiDefIconButR_prop(
block, UI_BTYPE_ROW, 0, icon, 0, 0, w, h, ptr, prop, -1, 0, value, -1, -1, NULL);
}
else {
uiDefButR_prop(
but = uiDefButR_prop(
block, UI_BTYPE_ROW, 0, name, 0, 0, w, h, ptr, prop, -1, 0, value, -1, -1, NULL);
}
BLI_assert(but != NULL);
but->label_but = label_but;
}
/* expanded enum */
else if (type == PROP_ENUM && expand) {
ui_item_enum_expand(layout, block, ptr, prop, name, h, icon_only);
ui_item_enum_expand(layout, block, ptr, prop, name, h, icon_only, label_but);
}
/* property with separate label */
else if (type == PROP_ENUM || type == PROP_STRING || type == PROP_POINTER) {
@@ -2287,6 +2368,8 @@ void uiItemFullR(uiLayout *layout,
if (layout->activate_init) {
UI_but_flag_enable(but, UI_BUT_ACTIVATE_ON_INIT);
}
BLI_assert(but != NULL);
but->label_but = label_but;
}
/* single button */
else {
@@ -2317,6 +2400,8 @@ void uiItemFullR(uiLayout *layout,
if (layout->activate_init) {
UI_but_flag_enable(but, UI_BUT_ACTIVATE_ON_INIT);
}
but->label_but = label_but;
}
/* The resulting button may have the icon set since boolean button drawing
@@ -2352,13 +2437,16 @@ void uiItemFullR(uiLayout *layout,
/* The icons are set in 'ui_but_anim_flag' */
uiItemDecoratorR_prop(layout_col, ptr_dec, prop_dec, but_decorate->rnaindex);
but = block->buttons.last;
uiBut *decorator = block->buttons.last;
but_decorate->decorator_but = decorator;
/* Order the decorator after the button we decorate, this is used so we can always
* do a quick lookup. */
BLI_remlink(&block->buttons, but);
BLI_insertlinkafter(&block->buttons, but_decorate, but);
but_decorate = but->next;
BLI_remlink(&block->buttons, decorator);
BLI_insertlinkafter(&block->buttons, but_decorate, decorator);
/* Assign decorator to the property's button so that they can be filtered together. */
but_decorate = decorator->next;
}
BLI_assert(ELEM(i, 1, ui_decorate.len));
@@ -3187,29 +3275,43 @@ uiPropertySplitWrapper uiItemPropertySplitWrapperCreate(uiLayout *parent_layout)
return split_wrapper;
}
/*
/**
* Helper to add a label and creates a property split layout if needed.
*
* \param r_layout: Returns a column to put decorators in if property separate is on, otherwise
* returns the original layout.
*/
uiLayout *uiItemL_respect_property_split(uiLayout *layout, const char *text, int icon)
uiBut *uiItemL_respect_property_split(uiLayout *layout,
const char *text,
int icon,
uiLayout **r_layout)
{
uiBut *label_but;
if (layout->item.flag & UI_ITEM_PROP_SEP) {
uiBlock *block = uiLayoutGetBlock(layout);
uiPropertySplitWrapper split_wrapper = uiItemPropertySplitWrapperCreate(layout);
/* Further items added to 'layout' will automatically be added to split_wrapper.property_row */
/* Further items added to 'layout' will automatically be added to split_wrapper.property_row
*/
uiItemL_(split_wrapper.label_column, text, icon);
label_but = uiItemL_(split_wrapper.label_column, text, icon);
UI_block_layout_set_current(block, split_wrapper.property_row);
return split_wrapper.decorate_column;
if (r_layout != NULL) {
*r_layout = split_wrapper.decorate_column;
}
}
else {
char namestr[UI_MAX_NAME_STR];
if (text) {
text = ui_item_name_add_colon(text, namestr);
}
uiItemL_(layout, text, icon);
label_but = uiItemL_(layout, text, icon);
return layout;
if (r_layout != NULL) {
*r_layout = layout;
}
}
return label_but;
}
void uiItemLDrag(uiLayout *layout, PointerRNA *ptr, const char *name, int icon)
@@ -3497,13 +3599,19 @@ void uiItemMenuEnumR(
uiItemMenuEnumR_prop(layout, ptr, prop, name, icon);
}
void uiItemTabsEnumR_prop(
uiLayout *layout, bContext *C, PointerRNA *ptr, PropertyRNA *prop, bool icon_only)
void uiItemTabsEnumR_prop(uiLayout *layout,
bContext *C,
PointerRNA *ptr,
PropertyRNA *prop,
PointerRNA *ptr_highlight,
PropertyRNA *prop_highlight,
bool icon_only)
{
uiBlock *block = layout->root->block;
UI_block_layout_set_current(block, layout);
ui_item_enum_expand_tabs(layout, C, block, ptr, prop, NULL, UI_UNIT_Y, icon_only);
ui_item_enum_expand_tabs(
layout, C, block, ptr, prop, ptr_highlight, prop_highlight, NULL, UI_UNIT_Y, icon_only);
}
/** \} */
@@ -4640,8 +4748,8 @@ static void ui_litem_init_from_parent(uiLayout *litem, uiLayout *layout, int ali
litem->redalert = layout->redalert;
litem->w = layout->w;
litem->emboss = layout->emboss;
litem->item.flag = (layout->item.flag &
(UI_ITEM_PROP_SEP | UI_ITEM_PROP_DECORATE | UI_ITEM_INSIDE_PROP_SEP));
litem->item.flag = (layout->item.flag & (UI_ITEM_PROP_SEP | UI_ITEM_PROP_DECORATE |
UI_ITEM_INSIDE_PROP_SEP | UI_ITEM_USE_SEARCH_FILTER));
if (layout->child_items_layout) {
BLI_addtail(&layout->child_items_layout->items, litem);
@@ -4979,6 +5087,16 @@ void uiLayoutSetPropDecorate(uiLayout *layout, bool is_sep)
SET_FLAG_FROM_TEST(layout->item.flag, is_sep, UI_ITEM_PROP_DECORATE);
}
bool uiLayoutGetPropSearch(uiLayout *layout)
{
return (layout->item.flag & UI_ITEM_USE_SEARCH_FILTER) != 0;
}
void uiLayoutSetPropSearch(uiLayout *layout, bool is_searchable)
{
SET_FLAG_FROM_TEST(layout->item.flag, is_searchable, UI_ITEM_USE_SEARCH_FILTER);
}
bool uiLayoutGetActive(uiLayout *layout)
{
return layout->active;
@@ -5047,6 +5165,435 @@ int uiLayoutGetEmboss(uiLayout *layout)
return layout->emboss;
}
void uiLayoutRootSetSearchOnly(uiLayout *layout, bool search_only)
{
layout->root->search_only = search_only;
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name Block Layout Search Filtering
* \{ */
// #define PROPERTY_SEARCH_USE_TOOLTIPS
// #define PROPERTY_SEARCH_USE_PANEL_LABELS
#define DEBUG_LAYOUT_ROOTS
static void ui_layout_free(uiLayout *layout);
#ifdef DEBUG_LAYOUT_ROOTS
/* clang-format off */
static const char *but_type_string(eButType type) {
switch (type) {
case UI_BTYPE_BUT: return "But";
case UI_BTYPE_ROW: return "Row But";
case UI_BTYPE_TEXT: return "Text";
case UI_BTYPE_MENU: return "Menu";
case UI_BTYPE_BUT_MENU: return "But Menu";
case UI_BTYPE_NUM: return "Number";
case UI_BTYPE_NUM_SLIDER: return "Number Slider";
case UI_BTYPE_TOGGLE: return "Toggle";
case UI_BTYPE_TOGGLE_N: return "Toggle N";
case UI_BTYPE_ICON_TOGGLE: return "Icon Toggle";
case UI_BTYPE_ICON_TOGGLE_N: return "Icon Toggle N";
case UI_BTYPE_BUT_TOGGLE: return "But Toggle";
case UI_BTYPE_CHECKBOX: return "Checkbox";
case UI_BTYPE_CHECKBOX_N: return "Checkbox N";
case UI_BTYPE_COLOR: return "Color";
case UI_BTYPE_TAB: return "Tab";
case UI_BTYPE_POPOVER: return "Popover";
case UI_BTYPE_SCROLL: return "Scroll";
case UI_BTYPE_BLOCK: return "Block";
case UI_BTYPE_LABEL: return "Label";
case UI_BTYPE_KEY_EVENT: return "Key Event";
case UI_BTYPE_HSVCUBE: return "HSV Cube";
case UI_BTYPE_PULLDOWN: return "Pulldown";
case UI_BTYPE_ROUNDBOX: return "Roundbox";
case UI_BTYPE_COLORBAND: return "Colorband";
case UI_BTYPE_UNITVEC: return "Unit Vector";
case UI_BTYPE_CURVE: return "Curve";
case UI_BTYPE_CURVEPROFILE: return "Curve Profile";
case UI_BTYPE_LISTBOX: return "Listbox";
case UI_BTYPE_LISTROW: return "List Row";
case UI_BTYPE_HSVCIRCLE: return "HSV Circle";
case UI_BTYPE_TRACK_PREVIEW: return "Track Preview";
case UI_BTYPE_SEARCH_MENU: return "Search Menu";
case UI_BTYPE_EXTRA: return "Extra";
case UI_BTYPE_HOTKEY_EVENT: return "Hotkey Event";
case UI_BTYPE_IMAGE: return "Image";
case UI_BTYPE_HISTOGRAM: return "Histogram";
case UI_BTYPE_WAVEFORM: return "Waveform";
case UI_BTYPE_VECTORSCOPE: return "Vectorscope";
case UI_BTYPE_PROGRESS_BAR: return "Progress Bar";
case UI_BTYPE_NODE_SOCKET: return "Node Socket";
case UI_BTYPE_SEPR: return "Spacer";
case UI_BTYPE_SEPR_LINE: return "Spacer Line";
case UI_BTYPE_SEPR_SPACER: return "Dynamic Spacer";
case UI_BTYPE_GRIP: return "Grip";
default: return "Unkown Button Type";
}
}
/* clang-format on */
/* Keep order the same as enum above. */
const char *item_type_names[12] = {
"Button", /* ITEM_BUTTON */
"Row", /* ITEM_LAYOUT_ROW */
"Column", /* ITEM_LAYOUT_COLUMN */
"Column Flow", /* ITEM_LAYOUT_COLUMN_FLOW */
"Row Flow", /* ITEM_LAYOUT_ROW_FLOW */
"Grid Flow", /* ITEM_LAYOUT_GRID_FLOW */
"Box", /* ITEM_LAYOUT_BOX */
"Absolute", /* ITEM_LAYOUT_ABSOLUTE */
"Split", /* ITEM_LAYOUT_SPLIT */
"Overlap", /* ITEM_LAYOUT_OVERLAP */
"Radial", /* ITEM_LAYOUT_RADIAL */
"Root", /* ITEM_LAYOUT_ROOT */
};
# define PRINT_DEFAULT "\x1B[0m"
# define PRINT_GREEN "\x1B[32m"
# define PRINT_RED "\x1B[31m"
# define PRINT_WHITE "\x1B[37m"
static void debug_print_button_item(uiButtonItem *button_item)
{
uiBut *but = button_item->but;
if (but == NULL) {
printf("NULL BUT");
return;
}
printf("%s%s%s: ", PRINT_RED, but_type_string(but->type), PRINT_DEFAULT);
if (but->str && but->str[0]) {
printf(but->str);
}
else if (!RNA_pointer_is_null(&but->rnapoin)) {
printf(RNA_property_ui_name(but->rnaprop));
}
}
static void debug_print_layout(uiItem *item, int depth, bool child_items_layout)
{
uiItemType type = item->type;
printf("%s", PRINT_WHITE);
for (int i = 0; i < depth; i++) {
printf("| ");
}
printf("%s", PRINT_DEFAULT);
if (type == ITEM_BUTTON) {
uiButtonItem *button_item = (uiButtonItem *)item;
debug_print_button_item(button_item);
printf("\n");
}
else {
printf("%s%s%s: ", PRINT_GREEN, item_type_names[item->type], PRINT_DEFAULT);
uiLayout *layout = (uiLayout *)item;
printf("%s", PRINT_WHITE);
if (layout->property_search_layout_temp_debug) {
printf("(search layout)");
}
if (child_items_layout) {
printf("(child_items_layout)");
}
printf("%s", PRINT_DEFAULT);
printf("\n");
if (layout->child_items_layout != NULL) {
debug_print_layout((uiItem *)layout->child_items_layout, depth + 1, true);
}
LISTBASE_FOREACH (uiItem *, child_item, &layout->items) {
debug_print_layout(child_item, depth + 1, false);
}
}
}
#endif /* DEBUG_LAYOUT_ROOTS */
static void ui_layout_free_hide_buttons(uiLayout *layout)
{
LISTBASE_FOREACH_MUTABLE (uiItem *, item, &layout->items) {
if (item->type == ITEM_BUTTON) {
uiButtonItem *button_item = (uiButtonItem *)item;
BLI_assert(button_item->but != NULL);
button_item->but->flag |= UI_HIDDEN;
MEM_freeN(item);
}
else {
ui_layout_free_hide_buttons((uiLayout *)item);
}
}
MEM_freeN(layout);
}
static bool ui_button_search_tag(uiBut *but, char *search_filter)
{
if (but->optype != NULL) {
if (BLI_strcasestr(but->optype->name, search_filter)) {
return true;
}
}
if (but->rnaprop != NULL) {
if (BLI_strcasestr(but->str, search_filter)) {
return true;
}
if (BLI_strcasestr(RNA_property_ui_name(but->rnaprop), search_filter)) {
return true;
}
#ifdef PROPERTY_SEARCH_USE_TOOLTIPS
if (BLI_strcasestr(RNA_property_description(but->rnaprop), search_filter)) {
return true;
}
#endif
}
return false;
}
/**
* Tag all buttons with whether they matched the search filter or not.
*
* \note This doesn't actually remove any buttons, and buttons that were tagged might
* not even be removed if they were in a layout with property search turned off.
*/
static void ui_block_search_filter_tag_buttons(uiBlock *block)
{
LISTBASE_FOREACH (uiBut *, but, &block->buttons) {
/* Flag all label buttons, we don't want to re-display them. */
if (but->type == UI_BTYPE_LABEL) {
but->flag |= UI_FILTERED;
}
/* Do the shorter check first, in case the check returns true. */
if (ui_button_search_tag(but, block->search_filter)) {
continue;
}
but->flag |= UI_FILTERED;
}
/* Remove filter from labels and decorators that correspond to un-filtered buttons. */
LISTBASE_FOREACH (uiBut *, but, &block->buttons) {
if ((but->flag & UI_FILTERED) == 0) {
uiBut *label_but = but->label_but;
uiBut *decorator_but = but->decorator_but;
if (label_but != NULL) {
label_but->flag &= ~UI_FILTERED;
}
if (decorator_but != NULL) {
decorator_but->flag &= ~UI_FILTERED;
}
}
}
}
/**
* Recursive implementation for #ui_block_search_filter_clean.
*/
static bool ui_layout_search_clean_recursive(uiLayout *layout)
{
/* Recursively clean sub-layouts. */
bool all_children_empty = true;
LISTBASE_FOREACH_MUTABLE (uiItem *, item, &layout->items) {
/* Deal with buttons after checking children. */
if (item->type == ITEM_BUTTON) {
continue;
}
bool empty = ui_layout_search_clean_recursive((uiLayout *)item);
all_children_empty &= empty;
if (empty) {
BLI_assert(BLI_findindex(&layout->items, item) != -1);
BLI_remlink(&layout->items, item);
MEM_freeN(item);
}
}
/* Remove all search filtered button items. */
bool layout_emptied = uiLayoutGetPropSearch(layout);
if (uiLayoutGetPropSearch(layout)) {
LISTBASE_FOREACH_MUTABLE (uiItem *, item, &layout->items) {
if (item->type == ITEM_BUTTON) {
uiButtonItem *button_item = (uiButtonItem *)item;
uiBut *but = button_item->but;
if (but->flag & UI_FILTERED) {
if (!((but->type == UI_BTYPE_ROUNDBOX) && !all_children_empty)) {
but->flag |= UI_HIDDEN;
BLI_remlink(&layout->items, item);
MEM_freeN(item);
}
}
else {
layout_emptied = false;
}
}
}
}
return layout_emptied && all_children_empty;
}
/**
* Remove buttons on layouts with property search set to true,
* and remove layouts with no buttons and empty child layouts.
*/
static bool ui_block_layout_search_clean(uiBlock *block)
{
bool all_roots_empty = true;
LISTBASE_FOREACH_MUTABLE (uiLayoutRoot *, root, &block->layouts) {
/* Find exceptions to search layout. */
if (root->type == UI_LAYOUT_HEADER) {
continue;
}
bool empty = ui_layout_search_clean_recursive(root->layout);
all_roots_empty &= empty;
/* If the root is empty, make sure it is freed along with all of its sublayouts. */
if (empty) {
BLI_assert(BLI_findindex(&block->layouts, root) != -1);
BLI_remlink(&block->layouts, root);
ui_layout_free_hide_buttons(root->layout);
MEM_freeN(root);
}
}
return all_roots_empty;
}
static void ui_layout_search_replace_labels(uiLayout *layout)
{
LISTBASE_FOREACH_MUTABLE (uiItem *, item, &layout->items) {
if (item->type == ITEM_BUTTON) {
uiButtonItem *button_item = (uiButtonItem *)item;
uiBut *but = button_item->but;
char name[MAX_NAME];
if (but->rnaprop) {
strcpy(name, RNA_property_ui_name(but->rnaprop));
/* Toggle buttons have no outside label and so their text is changed to the RNA name. */
if (ELEM(but->type,
UI_BTYPE_CHECKBOX,
UI_BTYPE_TOGGLE_N,
UI_BTYPE_ICON_TOGGLE_N,
UI_BTYPE_CHECKBOX_N,
UI_BTYPE_LABEL)) {
strcpy(but->str, name);
}
else {
/* Search for the label or heading associated with this button and
* change it to the RNA name. */
uiBut *label_but = but->label_but;
if (label_but != NULL) {
strcpy(label_but->str, name);
}
}
}
}
else {
ui_layout_search_replace_labels((uiLayout *)item);
}
}
}
static void ui_block_replace_labels(uiBlock *block)
{
LISTBASE_FOREACH (uiLayoutRoot *, root, &block->layouts) {
/* Don't rebuild header layouts. */
if (root->type == UI_LAYOUT_HEADER) {
continue;
}
ui_layout_search_replace_labels(root->layout);
}
}
/**
* \return True if the block was emptied by property search and should be removed.
*/
static bool ui_block_search_layout(uiBlock *block)
{
/* Only continue if the block has the search filter set. */
if (!(block->search_filter && block->search_filter[0])) {
return false;
}
#ifdef DEBUG_LAYOUT_ROOTS
if (block->panel && (block->panel->flag & PNL_SELECT)) {
printf("\nBEFORE %s %p\n", block->name, block);
LISTBASE_FOREACH (uiLayoutRoot *, root, &block->layouts) {
debug_print_layout((uiItem *)root->layout, 0, false);
}
}
#endif
/* Also search based on panel labels. */
bool panel_label_matches = false;
#ifdef PROPERTY_SEARCH_USE_PANEL_LABELS
if ((block->panel != NULL) && (block->panel->type != NULL)) {
if (BLI_strcasestr(block->panel->type->label, block->search_filter)) {
panel_label_matches = true;
}
}
#endif
/* Apply search filter. */
if (!panel_label_matches) {
ui_block_search_filter_tag_buttons(block);
}
/* Remove filtered buttons and now-empty layouts. */
bool all_roots_empty = ui_block_layout_search_clean(block);
/* Remove search only layout roots before the next step. */
LISTBASE_FOREACH_MUTABLE (uiLayoutRoot *, root, &block->layouts) {
if (root->search_only) {
ui_layout_free_hide_buttons(root->layout);
BLI_remlink(&block->layouts, root);
MEM_freeN(root);
}
}
/* Replace label button strings with RNA property names. */
if (!all_roots_empty && !UI_block_is_search_only(block)) {
ui_block_replace_labels(block);
}
/* Set empty flags. */
if (UI_block_is_search_only(block)) {
/* Make sure all of the block's buttons are hidden. They might not have
* been hidden if a layout wasn't searched. */
LISTBASE_FOREACH (uiBut *, but, &block->buttons) {
but->flag |= UI_HIDDEN;
}
}
SET_FLAG_FROM_TEST(
block->flag, all_roots_empty || UI_block_is_search_only(block), UI_BLOCK_FILTERED_EMPTY);
if (block->panel != NULL) {
ui_panel_set_search_filtered(block->panel, all_roots_empty);
}
#ifdef DEBUG_LAYOUT_ROOTS
if (block->panel && (block->panel->flag & PNL_SELECT)) {
printf("\nAFTER\n");
LISTBASE_FOREACH (uiLayoutRoot *, root, &block->layouts) {
debug_print_layout((uiItem *)root->layout, 0, false);
}
}
#endif
return all_roots_empty || UI_block_is_search_only(block);
}
/** \} */
/* -------------------------------------------------------------------- */
@@ -5340,7 +5887,7 @@ uiLayout *UI_block_layout(uiBlock *block,
layout->item.type = (type == UI_LAYOUT_VERT_BAR) ? ITEM_LAYOUT_COLUMN : ITEM_LAYOUT_ROOT;
/* Only used when 'UI_ITEM_PROP_SEP' is set. */
layout->item.flag = UI_ITEM_PROP_DECORATE;
layout->item.flag = UI_ITEM_PROP_DECORATE | UI_ITEM_USE_SEARCH_FILTER;
layout->x = x;
layout->y = y;
@@ -5487,6 +6034,8 @@ void UI_block_layout_resolve(uiBlock *block, int *r_x, int *r_y)
block->curlayout = NULL;
ui_block_search_layout(block);
for (root = block->layouts.first; root; root = root->next) {
ui_layout_add_padding_button(root);
@@ -5608,9 +6157,9 @@ static void ui_paneltype_draw_impl(bContext *C, PanelType *pt, uiLayout *layout,
panel->layout = NULL;
}
/* draw_header() is often used to add a checkbox to the header. If we add the label like below
* the label is disconnected from the checkbox, adding a weird looking gap. As workaround, let
* the checkbox add the label instead. */
/* draw_header() is often used to add a checkbox to the header. If we add the label like
* below the label is disconnected from the checkbox, adding a weird looking gap. As
* workaround, let the checkbox add the label instead. */
if (!ui_layout_has_panel_label(row, pt)) {
uiItemL(row, CTX_IFACE_(pt->translation_context, pt->label), ICON_NONE);
}

View File

@@ -69,12 +69,14 @@
#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
#define PNL_LAST_ADDED (1 << 0)
#define PNL_ACTIVE (1 << 1)
#define PNL_WAS_ACTIVE (1 << 2)
#define PNL_ANIM_ALIGN (1 << 3)
#define PNL_NEW_ADDED (1 << 4)
#define PNL_FIRST (1 << 5)
#define PNL_SEARCH_FILTERED (1 << 6)
#define PNL_WAS_SEARCH_FILTERED (1 << 7)
/* only show pin header button for pinned panels */
#define USE_PIN_HIDDEN
@@ -182,6 +184,18 @@ static bool panel_active_animation_changed(ListBase *lb, Panel **pa_animation, b
}
}
/* Detect search filter flag changes */
if ((panel->runtime_flag & PNL_WAS_SEARCH_FILTERED) &&
!(panel->runtime_flag & PNL_SEARCH_FILTERED)) {
*pa_animation = panel;
return false;
}
if (!(panel->runtime_flag & PNL_WAS_SEARCH_FILTERED) &&
(panel->runtime_flag & PNL_SEARCH_FILTERED)) {
*pa_animation = panel;
return false;
}
if ((panel->runtime_flag & PNL_ACTIVE) && !(panel->flag & PNL_CLOSED)) {
if (panel_active_animation_changed(&panel->children, pa_animation, no_animation)) {
return true;
@@ -258,6 +272,7 @@ static Panel *UI_panel_add_instanced_ex(ScrArea *area,
panel->runtime.list_index = list_index;
panel->runtime.custom_data_ptr = custom_data;
panel->runtime_flag |= PNL_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. */
@@ -801,7 +816,7 @@ void UI_panel_end(
/* Compute total panel size including children. */
LISTBASE_FOREACH (Panel *, pachild, &panel->children) {
if (pachild->runtime_flag & PNL_ACTIVE) {
if (pachild->runtime_flag & PNL_ACTIVE && !UI_panel_is_search_filtered(pachild)) {
width = max_ii(width, pachild->sizex);
height += get_panel_real_size_y(pachild);
}
@@ -858,6 +873,45 @@ static void ui_offset_panel_block(uiBlock *block)
block->rect.xmin = block->rect.ymin = 0.0;
}
void ui_panel_set_search_filtered(struct Panel *panel, const bool value)
{
SET_FLAG_FROM_TEST(panel->runtime_flag, value, PNL_SEARCH_FILTERED);
}
static void panel_is_search_filtered_recursive(const Panel *panel, bool *is_search_filtered)
{
*is_search_filtered = *is_search_filtered && (panel->runtime_flag & PNL_SEARCH_FILTERED);
/* If the panel is filtered (removed) we need to check that its children are too. */
if (*is_search_filtered) {
LISTBASE_FOREACH (const Panel *, child_panel, &panel->children) {
panel_is_search_filtered_recursive(child_panel, is_search_filtered);
}
}
}
/**
* Find whether a panel and all of its subpanels have been filtered by property search.
*
* \note We maintain a separate flag for active and search filtered. This prevents the
* search filtering from being too invasive to other code and makes animation of search
* filtered panels possible.
*/
bool UI_panel_is_search_filtered(const Panel *panel)
{
bool is_search_filtered = true;
panel_is_search_filtered_recursive(panel, &is_search_filtered);
return is_search_filtered;
}
/**
* Returns whether a panel is currently active (displayed).
*/
bool UI_panel_is_active(const Panel *panel)
{
return panel->runtime_flag & PNL_ACTIVE;
}
/**************************** drawing *******************************/
/* triangle 'icon' for panel header */
@@ -1330,7 +1384,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 & PNL_ACTIVE && !UI_panel_is_search_filtered(pachild)) {
pachild->ofsx = panel->ofsx;
pachild->ofsy = ofsy - get_panel_size_y(pachild);
ofsy -= get_panel_real_size_y(pachild);
@@ -1411,17 +1465,21 @@ static bool uiAlignPanelStep(ScrArea *area, ARegion *region, const float fac, co
ps->panel->ofsy = -get_panel_size_y(ps->panel);
ps->panel->ofsx += ps->panel->runtime.region_ofsx;
/* Keep track of the last visible panel separately so we don't add space for filtered panels. */
PanelSort *ps_last_visible = ps;
for (a = 0; a < tot - 1; a++, ps++) {
psnext = ps + 1;
if (align == BUT_VERTICAL) {
bool use_box = ps->panel->type && ps->panel->type->flag & PNL_DRAW_BOX;
bool use_box = ps_last_visible->panel->type &&
ps_last_visible->panel->type->flag & PNL_DRAW_BOX;
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);
/* Extra margin for box style panels. */
ps->panel->ofsx += (use_box) ? UI_PANEL_BOX_STYLE_MARGIN : 0.0f;
psnext->panel->ofsx = ps_last_visible->panel->ofsx;
psnext->panel->ofsy = get_panel_real_ofsy(ps_last_visible->panel) -
get_panel_size_y(psnext->panel);
/* Extra Y margin for box style panels. */
if (use_box || use_box_next) {
psnext->panel->ofsy -= UI_PANEL_BOX_STYLE_MARGIN;
}
@@ -1431,10 +1489,20 @@ static bool uiAlignPanelStep(ScrArea *area, ARegion *region, const float fac, co
psnext->panel->ofsy = ps->panel->ofsy + get_panel_size_y(ps->panel) -
get_panel_size_y(psnext->panel);
}
if (!UI_panel_is_search_filtered(psnext->panel)) {
ps_last_visible = psnext;
}
}
/* Extra X margin for box-style panels. */
if (align == BUT_VERTICAL) {
ps = panelsort;
for (a = 0; a < tot; a++, ps++) {
if (ps->panel->type && ps->panel->type->flag & PNL_DRAW_BOX) {
ps->panel->ofsx += UI_PANEL_BOX_STYLE_MARGIN;
}
}
/* 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 */
@@ -1454,7 +1522,7 @@ static bool uiAlignPanelStep(ScrArea *area, ARegion *region, const float fac, co
/* set locations for tabbed and sub panels */
LISTBASE_FOREACH (Panel *, panel, &region->panels) {
if (panel->runtime_flag & PNL_ACTIVE) {
if ((panel->runtime_flag & PNL_ACTIVE) && !UI_panel_is_search_filtered(panel)) {
if (panel->children.first) {
align_sub_panels(panel);
}
@@ -1478,7 +1546,7 @@ static void ui_panels_size(ScrArea *area, ARegion *region, int *r_x, int *r_y)
/* 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 & PNL_ACTIVE && !(panel->runtime_flag & PNL_SEARCH_FILTERED)) {
int pa_sizex, pa_sizey;
if (align == BUT_VERTICAL) {
@@ -1538,13 +1606,21 @@ static void ui_do_animate(bContext *C, Panel *panel)
}
}
/**
* Set all panels as inactive, so that at the end of the panel layout building process
* we know which ones are currently used. Also keep track of whether the panel was filtered
* by property search so we can activate animation later if that changes.
*/
static void panel_list_clear_active(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) {
bool was_search_filtered = panel->runtime_flag & PNL_SEARCH_FILTERED;
panel->runtime_flag = PNL_WAS_ACTIVE;
if (was_search_filtered) {
panel->runtime_flag |= PNL_WAS_SEARCH_FILTERED;
}
}
else {
panel->runtime_flag = 0;
@@ -1600,23 +1676,27 @@ void UI_panels_end(const bContext *C, ARegion *region, int *r_x, int *r_y)
ui_panels_size(area, region, r_x, r_y);
}
/**
* Draw panels, selected on top, but not search filtered panels.
*/
void UI_panels_draw(const bContext *C, ARegion *region)
{
if (region->alignment != RGN_ALIGN_FLOAT) {
UI_ThemeClearColor(TH_BACK);
}
/* 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. */
/* Draw 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)) {
if (block->active && block->panel && !(block->panel->flag & PNL_SELECT) &&
!UI_block_is_search_only(block) && !UI_panel_is_search_filtered(block->panel)) {
UI_block_draw(C, block);
}
}
LISTBASE_FOREACH_BACKWARD (uiBlock *, block, &region->uiblocks) {
if (block->active && block->panel && (block->panel->flag & PNL_SELECT)) {
if (block->active && block->panel && (block->panel->flag & PNL_SELECT) &&
!UI_block_is_search_only(block) && !UI_panel_is_search_filtered(block->panel)) {
UI_block_draw(C, block);
}
}
@@ -2801,6 +2881,13 @@ static void ui_handler_remove_panel(bContext *C, void *userdata)
panel_activate_state(C, panel, PANEL_STATE_EXIT);
}
void UI_region_panels_remove_handlers(const bContext *C, ARegion *region)
{
LISTBASE_FOREACH (Panel *, panel, &region->panels) {
panel_activate_state(C, panel, PANEL_STATE_EXIT);
}
}
static void panel_activate_state(const bContext *C, Panel *panel, uiHandlePanelState state)
{
uiHandlePanelData *data = panel->activedata;
@@ -2828,7 +2915,7 @@ static void panel_activate_state(const bContext *C, Panel *panel, uiHandlePanelS
}
if (state == PANEL_STATE_EXIT) {
MEM_freeN(data);
MEM_SAFE_FREE(data);
panel->activedata = NULL;
WM_event_remove_ui_handler(

View File

@@ -860,7 +860,7 @@ static void template_ID(const bContext *C,
if (text) {
/* Add label resepecting the separated layout property split state. */
uiItemL_respect_property_split(layout, text, ICON_NONE);
uiItemL_respect_property_split(layout, text, ICON_NONE, NULL);
}
if (flag & UI_ID_BROWSE) {

View File

@@ -2365,7 +2365,8 @@ static void ed_panel_draw(const bContext *C,
int w,
int em,
bool vertical,
char *unique_panel_str)
char *unique_panel_str,
bool search_only)
{
const uiStyle *style = UI_style_get_dpi();
@@ -2378,6 +2379,7 @@ static void ed_panel_draw(const bContext *C,
strncat(block_name, unique_panel_str, LIST_PANEL_UNIQUE_STR_LEN);
}
uiBlock *block = UI_block_begin(C, region, block_name, UI_EMBOSS);
UI_block_set_search_only(block, search_only);
bool open;
panel = UI_panel_begin(area, region, lb, block, pt, panel, &open);
@@ -2397,6 +2399,7 @@ static void ed_panel_draw(const bContext *C,
1,
0,
style);
uiLayoutRootSetSearchOnly(panel->layout, search_only);
pt->draw_header_preset(C, panel);
@@ -2420,6 +2423,7 @@ static void ed_panel_draw(const bContext *C,
1,
0,
style);
uiLayoutSetPropSearch(layout, false);
panel->layout = uiLayoutRow(layout, false);
}
/* Regular case: Normal panel with fixed size buttons. */
@@ -2427,6 +2431,7 @@ static void ed_panel_draw(const bContext *C,
panel->layout = UI_block_layout(
block, UI_LAYOUT_HORIZONTAL, UI_LAYOUT_HEADER, labelx, labely, UI_UNIT_Y, 1, 0, style);
}
uiLayoutRootSetSearchOnly(panel->layout, search_only);
pt->draw_header(C, panel);
@@ -2438,7 +2443,7 @@ static void ed_panel_draw(const bContext *C,
panel->labelofs = 0;
}
if (open) {
if (open || UI_block_has_search_filter(block) || search_only) {
short panelContext;
/* panel context can either be toolbar region or normal panels region */
@@ -2462,6 +2467,7 @@ static void ed_panel_draw(const bContext *C,
em,
0,
style);
uiLayoutRootSetSearchOnly(panel->layout, search_only || !open);
pt->draw(C, panel);
@@ -2476,7 +2482,7 @@ static void ed_panel_draw(const bContext *C,
UI_block_end(C, block);
/* Draw child panels. */
if (open) {
if (open || UI_block_has_search_filter(block)) {
LISTBASE_FOREACH (LinkData *, link, &pt->children) {
PanelType *child_pt = link->data;
Panel *child_panel = UI_panel_find_by_type(&panel->children, child_pt);
@@ -2491,7 +2497,8 @@ static void ed_panel_draw(const bContext *C,
w,
em,
vertical,
unique_panel_str);
unique_panel_str,
!open);
}
}
}
@@ -2651,7 +2658,8 @@ void ED_region_panels_layout_ex(const bContext *C,
(pt->flag & PNL_DRAW_BOX) ? w_box_panel : w,
em,
vertical,
NULL);
NULL,
false);
}
/* Draw "polyinstantaited" panels that don't have a 1 to 1 correspondence with their types. */
@@ -2679,7 +2687,8 @@ void ED_region_panels_layout_ex(const bContext *C,
(panel->type->flag & PNL_DRAW_BOX) ? w_box_panel : w,
em,
vertical,
unique_panel_str);
unique_panel_str,
false);
}
}
}

View File

@@ -1101,27 +1101,18 @@ int buttons_context(const bContext *C, const char *member, bContextDataResult *r
/************************* Drawing the Path ************************/
static void pin_cb(bContext *C, void *UNUSED(arg1), void *UNUSED(arg2))
static bool buttons_panel_context_poll(const bContext *C, PanelType *UNUSED(pt))
{
SpaceProperties *sbuts = CTX_wm_space_properties(C);
if (sbuts->flag & SB_PIN_CONTEXT) {
sbuts->pinid = buttons_context_id_path(C);
}
else {
sbuts->pinid = NULL;
}
ED_area_tag_redraw(CTX_wm_area(C));
return sbuts->mainb != BCONTEXT_TOOL;
}
void buttons_context_draw(const bContext *C, uiLayout *layout)
static void buttons_panel_context_draw(const bContext *C, Panel *panel)
{
uiLayout *layout = panel->layout;
SpaceProperties *sbuts = CTX_wm_space_properties(C);
ButsContextPath *path = sbuts->path;
uiLayout *row;
uiBlock *block;
uiBut *but;
PointerRNA *ptr;
char namebuf[128], *name;
int a, icon;
@@ -1182,65 +1173,11 @@ void buttons_context_draw(const bContext *C, uiLayout *layout)
}
}
}
uiItemSpacer(row);
block = uiLayoutGetBlock(row);
UI_block_emboss_set(block, UI_EMBOSS_NONE);
but = uiDefIconButBitC(block,
UI_BTYPE_ICON_TOGGLE,
SB_PIN_CONTEXT,
0,
ICON_UNPINNED,
0,
0,
UI_UNIT_X,
UI_UNIT_Y,
&sbuts->flag,
0,
0,
0,
0,
TIP_("Follow context or keep fixed data-block displayed"));
UI_but_flag_disable(but, UI_BUT_UNDO); /* skip undo on screen buttons */
UI_but_func_set(but, pin_cb, NULL, NULL);
}
#ifdef USE_HEADER_CONTEXT_PATH
static bool buttons_header_context_poll(const bContext *C, HeaderType *UNUSED(ht))
#else
static bool buttons_panel_context_poll(const bContext *C, PanelType *UNUSED(pt))
#endif
{
SpaceProperties *sbuts = CTX_wm_space_properties(C);
return (sbuts->mainb != BCONTEXT_TOOL);
}
#ifdef USE_HEADER_CONTEXT_PATH
static void buttons_header_context_draw(const bContext *C, Header *ptr)
#else
static void buttons_panel_context_draw(const bContext *C, Panel *ptr)
#endif
{
buttons_context_draw(C, ptr->layout);
}
void buttons_context_register(ARegionType *art)
{
#ifdef USE_HEADER_CONTEXT_PATH
HeaderType *ht;
ht = MEM_callocN(sizeof(HeaderType), "spacetype buttons context header");
strcpy(ht->idname, "BUTTONS_HT_context");
ht->space_type = SPACE_PROPERTIES;
ht->region_type = art->regionid;
ht->poll = buttons_header_context_poll;
ht->draw = buttons_header_context_draw;
BLI_addtail(&art->headertypes, ht);
#else
PanelType *pt;
pt = MEM_callocN(sizeof(PanelType), "spacetype buttons panel context");
PanelType *pt = MEM_callocN(sizeof(PanelType), "spacetype buttons panel context");
strcpy(pt->idname, "BUTTONS_PT_context");
strcpy(pt->label, N_("Context")); /* XXX C panels unavailable through RNA bpy.types! */
strcpy(pt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA);
@@ -1248,7 +1185,6 @@ void buttons_context_register(ARegionType *art)
pt->draw = buttons_panel_context_draw;
pt->flag = PNL_NO_HEADER;
BLI_addtail(&art->paneltypes, pt);
#endif
}
ID *buttons_context_id_path(const bContext *C)

View File

@@ -37,9 +37,6 @@ struct bNodeTree;
struct uiLayout;
struct wmOperatorType;
/* Display the context path in the header instead of the main window */
#define USE_HEADER_CONTEXT_PATH
/* context data */
typedef struct ButsContextPath {
@@ -83,7 +80,6 @@ void buttons_context_compute(const struct bContext *C, struct SpaceProperties *s
int buttons_context(const struct bContext *C,
const char *member,
struct bContextDataResult *result);
void buttons_context_draw(const struct bContext *C, struct uiLayout *layout);
void buttons_context_register(struct ARegionType *art);
struct ID *buttons_context_id_path(const struct bContext *C);
@@ -93,6 +89,9 @@ extern const char *buttons_context_dir[]; /* doc access */
void buttons_texture_context_compute(const struct bContext *C, struct SpaceProperties *sbuts);
/* buttons_ops.c */
void BUTTONS_OT_start_filter(struct wmOperatorType *ot);
void BUTTONS_OT_clear_filter(struct wmOperatorType *ot);
void BUTTONS_OT_toggle_pin(struct wmOperatorType *ot);
void BUTTONS_OT_file_browse(struct wmOperatorType *ot);
void BUTTONS_OT_directory_browse(struct wmOperatorType *ot);
void BUTTONS_OT_context_menu(struct wmOperatorType *ot);

View File

@@ -38,6 +38,7 @@
#include "BKE_context.h"
#include "BKE_main.h"
#include "BKE_report.h"
#include "BKE_screen.h"
#include "WM_api.h"
#include "WM_types.h"
@@ -52,6 +53,95 @@
#include "buttons_intern.h" /* own include */
/* -------------------------------------------------------------------- */
/** \name Start / Clear Seach Filter Operators
*
* \note Almost a duplicate of the file browser operator #FILE_OT_start_filter.
* \{ */
static int buttons_start_filter_exec(bContext *C, wmOperator *UNUSED(op))
{
SpaceProperties *space = CTX_wm_space_properties(C);
ScrArea *area = CTX_wm_area(C);
ARegion *region = BKE_area_find_region_type(area, RGN_TYPE_HEADER);
ARegion *region_ctx = CTX_wm_region(C);
CTX_wm_region_set(C, region);
UI_textbutton_activate_rna(C, region, space, "filter_text");
CTX_wm_region_set(C, region_ctx);
return OPERATOR_FINISHED;
}
void BUTTONS_OT_start_filter(struct wmOperatorType *ot)
{
/* Identifiers. */
ot->name = "Filter";
ot->description = "Start entering filter text";
ot->idname = "BUTTONS_OT_start_filter";
/* Callbacks. */
ot->exec = buttons_start_filter_exec;
ot->poll = ED_operator_buttons_active;
}
static int buttons_clear_filter_exec(bContext *C, wmOperator *UNUSED(op))
{
ScrArea *area = CTX_wm_area(C);
SpaceProperties *space = CTX_wm_space_properties(C);
strcpy(space->search_string, "");
ED_area_tag_redraw(area);
return OPERATOR_FINISHED;
}
void BUTTONS_OT_clear_filter(struct wmOperatorType *ot)
{
/* Identifiers. */
ot->name = "Clear Filter";
ot->description = "Clear the search filter";
ot->idname = "BUTTONS_OT_clear_filter";
/* Callbacks. */
ot->exec = buttons_clear_filter_exec;
ot->poll = ED_operator_buttons_active;
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name Pin ID Operator
* \{ */
static int toggle_pin_exec(bContext *C, wmOperator *UNUSED(op))
{
SpaceProperties *sbuts = CTX_wm_space_properties(C);
sbuts->pinid = (sbuts->flag & SB_PIN_CONTEXT) ? NULL : buttons_context_id_path(C);
sbuts->flag ^= SB_PIN_CONTEXT;
ED_area_tag_redraw(CTX_wm_area(C));
return OPERATOR_FINISHED;
}
void BUTTONS_OT_toggle_pin(wmOperatorType *ot)
{
/* Identifiers. */
ot->name = "Toggle Pin ID";
ot->description = "Keep the current data-block displayed";
ot->idname = "BUTTONS_OT_toggle_pin";
/* Callbacks. */
ot->exec = toggle_pin_exec;
ot->poll = ED_operator_buttons_active;
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name Context Menu Operator
* \{ */

View File

@@ -48,6 +48,7 @@
#include "RNA_define.h"
#include "RNA_enum_types.h"
#include "UI_interface.h"
#include "UI_resources.h"
#include "buttons_intern.h" /* own include */
@@ -123,6 +124,7 @@ static SpaceLink *buttons_duplicate(SpaceLink *sl)
/* clear or remove stuff from old */
sbutsn->path = NULL;
sbutsn->texuser = NULL;
strcpy(sbutsn->search_string, "");
return (SpaceLink *)sbutsn;
}
@@ -143,6 +145,7 @@ static void buttons_main_region_init(wmWindowManager *wm, ARegion *region)
*
* \return The total number of items in the array returned.
*/
/* HANS-TODO: Use short for this. */
int ED_buttons_tabs_list(SpaceProperties *sbuts, int *context_tabs_array)
{
int length = 0;
@@ -297,17 +300,86 @@ static void buttons_main_region_layout_properties(const bContext *C,
C, region, &region->type->paneltypes, contexts, sbuts->mainb, vertical, NULL);
}
static void buttons_main_region_layout(const bContext *C, ARegion *region)
static void main_region_layout(const bContext *C, SpaceProperties *sbuts, ARegion *region)
{
/* draw entirely, view changes should be handled here */
SpaceProperties *sbuts = CTX_wm_space_properties(C);
if (sbuts->mainb == BCONTEXT_TOOL) {
ED_view3d_buttons_region_layout_ex(C, region, "Tool");
}
else {
buttons_main_region_layout_properties(C, sbuts, region);
}
}
static void property_search_all_tabs(const bContext *C,
SpaceProperties *sbuts,
ARegion *main_region)
{
sbuts->context_search_filter_active = 0;
/* Duplicate space and region so we don't change any data for this space. */
ScrArea *area_copy = MEM_dupallocN(CTX_wm_area(C));
ARegion *region_copy = BKE_area_region_copy(CTX_wm_area(C)->type, main_region);
BKE_area_region_panels_free(&region_copy->panels);
bContext *C_copy = CTX_copy(C);
CTX_wm_area_set(C_copy, area_copy);
CTX_wm_region_set(C_copy, region_copy);
SpaceProperties *sbuts_copy = MEM_dupallocN(sbuts);
int context_tabs_array[32];
int tabs_tot = ED_buttons_tabs_list(sbuts, context_tabs_array);
/* Loop through the tabs added to the properties editor. */
for (int i = 0; i < tabs_tot; i++) {
if (context_tabs_array[i] == -1) {
continue;
}
/* Run the layout with this tab set active. */
sbuts_copy->mainb = sbuts->mainbo = sbuts_copy->mainbuser = context_tabs_array[i];
/* Run the layout for the actual region if the tab matches to avoid doing it again later on. */
const bool use_actual_region = sbuts->mainb == sbuts_copy->mainb;
if (use_actual_region) {
main_region_layout(C, sbuts, main_region);
}
else {
main_region_layout(C_copy, sbuts_copy, region_copy);
}
/* Store whether this tab has any unfiltered panels left. */
bool has_unfiltered_panel = false;
LISTBASE_FOREACH (
Panel *, panel, use_actual_region ? &main_region->panels : &region_copy->panels) {
has_unfiltered_panel |= !UI_panel_is_search_filtered(panel) && UI_panel_is_active(panel);
}
if (has_unfiltered_panel) {
sbuts->context_search_filter_active |= (1 << i);
}
/* Free data created during the layout process. */
UI_region_panels_remove_handlers(C_copy, region_copy);
BKE_area_region_panels_free(&region_copy->panels);
UI_blocklist_free(C_copy, &region_copy->uiblocks);
}
BKE_area_region_free(CTX_wm_area(C_copy)->type, region_copy);
MEM_freeN(region_copy);
MEM_freeN(sbuts_copy);
MEM_freeN(area_copy);
MEM_freeN(C_copy);
}
static void buttons_main_region_layout(const bContext *C, ARegion *region)
{
/* draw entirely, view changes should be handled here */
SpaceProperties *sbuts = CTX_wm_space_properties(C);
if (sbuts->search_string != NULL && sbuts->search_string[0] != '\0') {
property_search_all_tabs(C, sbuts, region);
}
else {
main_region_layout(C, sbuts, region);
}
sbuts->mainbo = sbuts->mainb;
}
@@ -330,6 +402,9 @@ static void buttons_main_region_listener(wmWindow *UNUSED(win),
static void buttons_operatortypes(void)
{
WM_operatortype_append(BUTTONS_OT_start_filter);
WM_operatortype_append(BUTTONS_OT_clear_filter);
WM_operatortype_append(BUTTONS_OT_toggle_pin);
WM_operatortype_append(BUTTONS_OT_context_menu);
WM_operatortype_append(BUTTONS_OT_file_browse);
WM_operatortype_append(BUTTONS_OT_directory_browse);
@@ -343,14 +418,6 @@ static void buttons_keymap(struct wmKeyConfig *keyconf)
/* add handlers, stuff you only do once or on area/region changes */
static void buttons_header_region_init(wmWindowManager *UNUSED(wm), ARegion *region)
{
#ifdef USE_HEADER_CONTEXT_PATH
/* Reinsert context buttons header-type at the end of the list so it's drawn last. */
HeaderType *context_ht = BLI_findstring(
&region->type->headertypes, "BUTTONS_HT_context", offsetof(HeaderType, idname));
BLI_remlink(&region->type->headertypes, context_ht);
BLI_addtail(&region->type->headertypes, context_ht);
#endif
ED_region_header_init(region);
}
@@ -390,10 +457,6 @@ static void buttons_header_region_message_subscribe(const bContext *UNUSED(C),
if (sbuts->mainb == BCONTEXT_TOOL) {
WM_msg_subscribe_rna_anon_prop(mbus, WorkSpace, tools, &msg_sub_value_region_tag_redraw);
}
#ifdef USE_HEADER_CONTEXT_PATH
WM_msg_subscribe_rna_anon_prop(mbus, SpaceProperties, context, &msg_sub_value_region_tag_redraw);
#endif
}
static void buttons_navigation_bar_region_init(wmWindowManager *wm, ARegion *region)
@@ -727,9 +790,7 @@ void ED_spacetype_buttons(void)
art->draw = ED_region_panels_draw;
art->listener = buttons_main_region_listener;
art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_FRAMES;
#ifndef USE_HEADER_CONTEXT_PATH
buttons_context_register(art);
#endif
BLI_addhead(&st->regiontypes, art);
/* Register the panel types from modifiers. The actual panels are built per modifier rather than
@@ -765,9 +826,6 @@ void ED_spacetype_buttons(void)
art->init = buttons_header_region_init;
art->draw = buttons_header_region_draw;
art->message_subscribe = buttons_header_region_message_subscribe;
#ifdef USE_HEADER_CONTEXT_PATH
buttons_context_register(art);
#endif
BLI_addhead(&st->regiontypes, art);
/* regions: navigation bar */

View File

@@ -423,7 +423,7 @@ static void graph_panel_key_properties(const bContext *C, Panel *panel)
col = uiLayoutColumn(layout, true);
/* keyframe itself */
{
uiItemL_respect_property_split(col, IFACE_("Key Frame"), ICON_NONE);
uiItemL_respect_property_split(col, IFACE_("Key Frame"), ICON_NONE, NULL);
but = uiDefButR(block,
UI_BTYPE_NUM,
B_REDR,
@@ -441,7 +441,7 @@ static void graph_panel_key_properties(const bContext *C, Panel *panel)
-1,
NULL);
uiItemL_respect_property_split(col, IFACE_("Value"), ICON_NONE);
uiItemL_respect_property_split(col, IFACE_("Value"), ICON_NONE, NULL);
but = uiDefButR(block,
UI_BTYPE_NUM,
B_REDR,
@@ -468,7 +468,7 @@ static void graph_panel_key_properties(const bContext *C, Panel *panel)
if ((prevbezt) && (prevbezt->ipo == BEZT_IPO_BEZ)) {
col = uiLayoutColumn(layout, true);
uiItemL_respect_property_split(col, IFACE_("Left Handle Type"), ICON_NONE);
uiItemL_respect_property_split(col, IFACE_("Left Handle Type"), ICON_NONE, NULL);
but = uiDefButR(block,
UI_BTYPE_MENU,
B_REDR,
@@ -487,7 +487,7 @@ static void graph_panel_key_properties(const bContext *C, Panel *panel)
"Type of left handle");
UI_but_func_set(but, graphedit_activekey_handles_cb, fcu, bezt);
uiItemL_respect_property_split(col, IFACE_("Frame"), ICON_NONE);
uiItemL_respect_property_split(col, IFACE_("Frame"), ICON_NONE, NULL);
but = uiDefButR(block,
UI_BTYPE_NUM,
B_REDR,
@@ -506,7 +506,7 @@ static void graph_panel_key_properties(const bContext *C, Panel *panel)
NULL);
UI_but_func_set(but, graphedit_activekey_left_handle_coord_cb, fcu, bezt);
uiItemL_respect_property_split(col, IFACE_("Value"), ICON_NONE);
uiItemL_respect_property_split(col, IFACE_("Value"), ICON_NONE, NULL);
but = uiDefButR(block,
UI_BTYPE_NUM,
B_REDR,
@@ -532,7 +532,7 @@ static void graph_panel_key_properties(const bContext *C, Panel *panel)
/* NOTE: special update callbacks are needed on the coords here due to T39911 */
col = uiLayoutColumn(layout, true);
uiItemL_respect_property_split(col, IFACE_("Right Handle Type"), ICON_NONE);
uiItemL_respect_property_split(col, IFACE_("Right Handle Type"), ICON_NONE, NULL);
but = uiDefButR(block,
UI_BTYPE_MENU,
B_REDR,
@@ -551,7 +551,7 @@ static void graph_panel_key_properties(const bContext *C, Panel *panel)
"Type of right handle");
UI_but_func_set(but, graphedit_activekey_handles_cb, fcu, bezt);
uiItemL_respect_property_split(col, IFACE_("Frame"), ICON_NONE);
uiItemL_respect_property_split(col, IFACE_("Frame"), ICON_NONE, NULL);
but = uiDefButR(block,
UI_BTYPE_NUM,
B_REDR,
@@ -570,7 +570,7 @@ static void graph_panel_key_properties(const bContext *C, Panel *panel)
NULL);
UI_but_func_set(but, graphedit_activekey_right_handle_coord_cb, fcu, bezt);
uiItemL_respect_property_split(col, IFACE_("Value"), ICON_NONE);
uiItemL_respect_property_split(col, IFACE_("Value"), ICON_NONE, NULL);
but = uiDefButR(block,
UI_BTYPE_NUM,
B_REDR,

View File

@@ -147,9 +147,12 @@ typedef struct SpaceProperties {
/** Context tabs. */
short mainb, mainbo, mainbuser;
/** Bitfield flag (in the same order as the tabs) for whether each tab has properties
* that match the search filter. Only valid when #search_string is set. */
int context_search_filter_active;
/** Preview is signal to refresh. */
short preview;
char _pad[5];
char _pad[1];
char flag;
/** Runtime. */
@@ -158,6 +161,9 @@ typedef struct SpaceProperties {
int pathflag, dataicon;
ID *pinid;
/** For filtering properties displayed in the space. */
char search_string[64];
void *texuser;
} SpaceProperties;

View File

@@ -4469,6 +4469,22 @@ static void rna_def_space_properties(BlenderRNA *brna)
prop = RNA_def_property(srna, "use_pin_id", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", SB_PIN_CONTEXT);
RNA_def_property_ui_text(prop, "Pin ID", "Use the pinned context");
/* Property search. */
prop = RNA_def_property(srna, "context_search_filter_active", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_items(prop, buttons_context_items);
RNA_def_property_flag(prop, PROP_ENUM_FLAG);
RNA_def_property_enum_funcs(
prop, NULL, "rna_SpaceProperties_context_set", "rna_SpaceProperties_context_itemf");
RNA_def_property_ui_text(prop, "", "");
RNA_def_property_update(
prop, NC_SPACE | ND_SPACE_PROPERTIES, "rna_SpaceProperties_context_update");
prop = RNA_def_property(srna, "filter_text", PROP_STRING, PROP_NONE);
RNA_def_property_string_sdna(prop, NULL, "search_string");
RNA_def_property_ui_text(prop, "Display Filter", "Live search filtering string");
RNA_def_property_flag(prop, PROP_TEXTEDIT_UPDATE);
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_PROPERTIES, NULL);
}
static void rna_def_space_image(BlenderRNA *brna)

View File

@@ -1151,6 +1151,16 @@ static void rna_UILayout_property_decorate_set(PointerRNA *ptr, bool value)
uiLayoutSetPropDecorate(ptr->data, value);
}
static bool rna_UILayout_property_search_get(PointerRNA *ptr)
{
return uiLayoutGetPropSearch(ptr->data);
}
static void rna_UILayout_property_search_set(PointerRNA *ptr, bool value)
{
uiLayoutSetPropSearch(ptr->data, value);
}
#else /* RNA_RUNTIME */
static void rna_def_ui_layout(BlenderRNA *brna)
@@ -1267,6 +1277,12 @@ static void rna_def_ui_layout(BlenderRNA *brna)
prop = RNA_def_property(srna, "use_property_decorate", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_funcs(
prop, "rna_UILayout_property_decorate_get", "rna_UILayout_property_decorate_set");
prop = RNA_def_property(srna, "use_property_search", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_funcs(
prop, "rna_UILayout_property_search_get", "rna_UILayout_property_search_set");
RNA_def_property_ui_text(
prop, "Use Property Search", "Whether to use the region's property search if available");
}
static void rna_def_panel(BlenderRNA *brna)

View File

@@ -216,8 +216,13 @@ static void rna_uiItemMenuEnumR(uiLayout *layout,
uiItemMenuEnumR_prop(layout, ptr, prop, name, icon);
}
static void rna_uiItemTabsEnumR(
uiLayout *layout, bContext *C, struct PointerRNA *ptr, const char *propname, bool icon_only)
static void rna_uiItemTabsEnumR(uiLayout *layout,
bContext *C,
struct PointerRNA *ptr,
const char *propname,
struct PointerRNA *ptr_highlight,
const char *propname_highlight,
bool icon_only)
{
PropertyRNA *prop = RNA_struct_find_property(ptr, propname);
@@ -230,7 +235,31 @@ static void rna_uiItemTabsEnumR(
return;
}
uiItemTabsEnumR_prop(layout, C, ptr, prop, icon_only);
/* Get the highlight property used to gray out some of the tabs. */
PropertyRNA *prop_highlight = NULL;
if (!RNA_pointer_is_null(ptr_highlight)) {
prop_highlight = RNA_struct_find_property(ptr_highlight, propname_highlight);
if (!prop_highlight) {
RNA_warning("property not found: %s.%s",
RNA_struct_identifier(ptr_highlight->type),
propname_highlight);
return;
}
if (RNA_property_type(prop_highlight) != PROP_ENUM) {
RNA_warning("property is not an enum: %s.%s",
RNA_struct_identifier(ptr_highlight->type),
propname_highlight);
return;
}
if (!(RNA_property_flag(prop_highlight) & PROP_ENUM_FLAG)) {
RNA_warning("property must be a bitfield enum: %s.%s",
RNA_struct_identifier(ptr_highlight->type),
propname_highlight);
return;
}
}
uiItemTabsEnumR_prop(layout, C, ptr, prop, ptr_highlight, prop_highlight, icon_only);
}
static void rna_uiItemEnumR_string(uiLayout *layout,
@@ -920,6 +949,11 @@ void RNA_api_ui_layout(StructRNA *srna)
func = RNA_def_function(srna, "prop_tabs_enum", "rna_uiItemTabsEnumR");
RNA_def_function_flag(func, FUNC_USE_CONTEXT);
api_ui_item_rna_common(func);
parm = RNA_def_pointer(
func, "data_highlight", "AnyType", "", "Data from which to take highlight property");
RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_RNAPTR);
parm = RNA_def_string(
func, "property_highlight", NULL, 0, "", "Identifier of highlight property in data");
RNA_def_boolean(func, "icon_only", false, "", "Draw only icons in tabs, no text");
func = RNA_def_function(srna, "prop_enum", "rna_uiItemEnumR_string");