Compare commits
211 Commits
temp-gpu-u
...
property-s
Author | SHA1 | Date | |
---|---|---|---|
e13e8d727a | |||
adaf9947b1 | |||
b037801f5e | |||
fd89ef4d2f | |||
572ce24f7e | |||
2c2d30df60 | |||
4fbc49ff4b | |||
d9b0afcf19 | |||
742b8d2ca1 | |||
dcfbee5c80 | |||
d8420767d3 | |||
a90b701ab3 | |||
18d384ffaf | |||
601d323d96 | |||
0106127364 | |||
360549b31b | |||
530183b60a | |||
dabed53d12 | |||
97212d6258 | |||
ca3cc95f3d | |||
3eae5f71d1 | |||
d23036e510 | |||
98d4da32dd | |||
a67067253b | |||
d3dd76789c | |||
43533f4269 | |||
cd35233ea7 | |||
6c1f3b40c6 | |||
94aa5c0dd6 | |||
2dd0161860 | |||
11f0dd4951 | |||
1496526dce | |||
3eaca73753 | |||
8f6740b275 | |||
f9dd47475a | |||
7b714a9897 | |||
d78a5f022d | |||
b57cd0e359 | |||
cf877d717c | |||
5c329ba2b5 | |||
245cb6e972 | |||
68a5d4c56d | |||
bc730e4ae6 | |||
7ce4911a71 | |||
3c52c75af2 | |||
28f13a5697 | |||
9a2d04677a | |||
3c26181cd9 | |||
537daa5dd4 | |||
5c5d022649 | |||
86993444a0 | |||
a8eb263678 | |||
e9c9f7d5c4 | |||
6ebc8278de | |||
5545d83315 | |||
2f22d6aa7c | |||
bbacf94c69 | |||
eabba50141 | |||
a444b38fa3 | |||
9ba5d0e4b1 | |||
099d603e7b | |||
b7b5227640 | |||
3069c4a3f7 | |||
afe0213bca | |||
2baec9e65f | |||
055d3fbe2f | |||
83eacc0352 | |||
4baf63ab73 | |||
46db0d65bd | |||
4e636376ca | |||
deabcf00f2 | |||
8679b24b91 | |||
36b3364ef3 | |||
d53e093b3e | |||
01d17c525c | |||
01d292f151 | |||
9d06994229 | |||
049eb2f33a | |||
79c5b90040 | |||
5b7a534211 | |||
b89e8b71f9 | |||
e56e34ddd1 | |||
09217fc22d | |||
66f5008b33 | |||
1b5f355af8 | |||
f4c8b81595 | |||
9a60f5cf93 | |||
417fa6765e | |||
3860e8bfeb | |||
59fcb799ca | |||
3dc7c4fa83 | |||
3551b8c83e | |||
4a4e36ff9b | |||
44dcc742c6 | |||
863ea6a32c | |||
58488c08b8 | |||
6a76eeaced | |||
f3197de265 | |||
a3f61ade7a | |||
407f8f5a4e | |||
e2f3455956 | |||
27ce07a010 | |||
e9489757ea | |||
27f3f3d8a7 | |||
69be090944 | |||
ca0d4d90c6 | |||
277e03c6bd | |||
c335173a78 | |||
6d2069f348 | |||
293405b653 | |||
0c4a9085f8 | |||
fbcedf96cb | |||
d17e2e8101 | |||
caa79adffb | |||
612b19f4e7 | |||
171090c489 | |||
31ef82b2cf | |||
3eea67e8c5 | |||
a22a8cdeeb | |||
abe6bd2bd2 | |||
ce6270d24d | |||
f8c386a331 | |||
7d6562d280 | |||
dcc3211650 | |||
c8dfe0800d | |||
b9c4e5bd23 | |||
904e7830e1 | |||
629c8344c4 | |||
1ea46cd039 | |||
f2c8935295 | |||
95fabb12cb | |||
b02e8e3504 | |||
1836a97958 | |||
99862a72b1 | |||
aa3a053f31 | |||
ba2eef2f6f | |||
fff7a29861 | |||
68df739bb1 | |||
1f768bbe41 | |||
ce6cf2b475 | |||
f957e09398 | |||
d58f361099 | |||
1b391f14fc | |||
b4b2185da0 | |||
8f548fd856 | |||
634bf8e4fc | |||
6776607913 | |||
af146e7745 | |||
4b0a94661c | |||
8eda823dbc | |||
e40225577b | |||
d219d0efa1 | |||
cc1201dce3 | |||
1afdc92511 | |||
20ce4a77bd | |||
7d3d6ac085 | |||
304e9a0b9e | |||
31657ebbbe | |||
169ac2805e | |||
c914bff16d | |||
7758bb25e7 | |||
94272e8347 | |||
67d6d1363d | |||
b7d47e9892 | |||
6f5ca857fc | |||
71c6af4d59 | |||
2f68b79fa8 | |||
98c6349bca | |||
4c1095d33c | |||
847837c808 | |||
16bf1807a1 | |||
052baecc0d | |||
34c5245c32 | |||
42e5314727 | |||
7137e99ff3 | |||
f3e409c1bf | |||
92c201b493 | |||
7955c26f41 | |||
26450636cd | |||
f3b83271e6 | |||
136475dca3 | |||
544ac33b61 | |||
263e42a172 | |||
b7938c3768 | |||
be7a4f4a81 | |||
dbc9f1b0f3 | |||
f3caadec90 | |||
11b89dd56c | |||
5218fb969f | |||
411f425973 | |||
d4b9f41a56 | |||
66ac0448ef | |||
170a40c338 | |||
d2c00d1d7f | |||
cf99c25dbe | |||
c95d6de3b3 | |||
a33720329b | |||
9029c7be19 | |||
463c4ef39e | |||
c891ba0086 | |||
09e555142a | |||
4d5b6409ee | |||
712ccc2602 | |||
85fe4a18e8 | |||
8357b7fe46 | |||
13b283ca8e | |||
723f6e7f53 | |||
040931a9b2 | |||
a34c25046b | |||
e299727fba | |||
db76f34ed6 |
@@ -269,6 +269,7 @@ const bTheme U_theme_default = {
|
||||
.header = RGBA(0x424242ff),
|
||||
.header_text = RGBA(0xeeeeeeff),
|
||||
.header_text_hi = RGBA(0xffffffff),
|
||||
.search_match_color = RGBA(0x5680c2ff),
|
||||
.tab_active = RGBA(0x4b4b4bff),
|
||||
.tab_inactive = RGBA(0x2b2b2bff),
|
||||
.tab_back = RGBA(0x232323ff),
|
||||
|
@@ -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)]}),
|
||||
|
@@ -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, "search_filter", 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,7 +51,11 @@ class PROPERTIES_PT_navigation_bar(Panel):
|
||||
|
||||
layout.scale_x = 1.4
|
||||
layout.scale_y = 1.4
|
||||
layout.prop_tabs_enum(view, "context", icon_only=True)
|
||||
if view.search_filter:
|
||||
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)
|
||||
|
||||
|
||||
classes = (
|
||||
|
@@ -4924,6 +4924,9 @@ static void direct_link_region(BlendDataReader *reader, ARegion *region, int spa
|
||||
|
||||
BLO_read_list(reader, ®ion->ui_lists);
|
||||
|
||||
/* The area's search filter is runtime only, so we need to clear the active flag on read. */
|
||||
region->flag &= ~RGN_FLAG_SEARCH_FILTER_ACTIVE;
|
||||
|
||||
LISTBASE_FOREACH (uiList *, ui_list, ®ion->ui_lists) {
|
||||
ui_list->type = NULL;
|
||||
ui_list->dyn_data = NULL;
|
||||
@@ -5164,6 +5167,7 @@ static void direct_link_area(BlendDataReader *reader, ScrArea *area)
|
||||
sbuts->texuser = NULL;
|
||||
sbuts->mainbo = sbuts->mainb;
|
||||
sbuts->mainbuser = sbuts->mainb;
|
||||
memset(&sbuts->runtime, 0x0, sizeof(sbuts->runtime));
|
||||
}
|
||||
else if (sl->spacetype == SPACE_CONSOLE) {
|
||||
SpaceConsole *sconsole = (SpaceConsole *)sl;
|
||||
|
@@ -228,6 +228,7 @@ static void do_versions_theme(const UserDef *userdef, bTheme *btheme)
|
||||
*/
|
||||
{
|
||||
/* Keep this block, even when empty. */
|
||||
FROM_DEFAULT_V4_UCHAR(space_properties.search_match_color);
|
||||
|
||||
/* The new defaults for the file browser theme are the same as
|
||||
* the outliner's, and it's less disruptive to just copy them. */
|
||||
|
@@ -80,6 +80,9 @@ void ED_region_tag_redraw_no_rebuild(struct ARegion *region);
|
||||
void ED_region_tag_refresh_ui(struct ARegion *region);
|
||||
void ED_region_tag_redraw_editor_overlays(struct ARegion *region);
|
||||
|
||||
void ED_region_search_filter_update(const struct ScrArea *area, struct ARegion *region);
|
||||
const char *ED_area_search_filter_get(const struct ScrArea *area, const struct ARegion *region);
|
||||
|
||||
void ED_region_panels_init(struct wmWindowManager *wm, struct ARegion *region);
|
||||
void ED_region_panels_ex(const struct bContext *C, struct ARegion *region, const char *contexts[]);
|
||||
void ED_region_panels(const struct bContext *C, struct ARegion *region);
|
||||
@@ -88,6 +91,11 @@ void ED_region_panels_layout_ex(const struct bContext *C,
|
||||
struct ListBase *paneltypes,
|
||||
const char *contexts[],
|
||||
const char *category_override);
|
||||
bool ED_region_property_search(const struct bContext *C,
|
||||
struct ARegion *region,
|
||||
struct ListBase *paneltypes,
|
||||
const char *contexts[],
|
||||
const char *category_override);
|
||||
|
||||
void ED_region_panels_layout(const struct bContext *C, struct ARegion *region);
|
||||
void ED_region_panels_draw(const struct bContext *C, struct ARegion *region);
|
||||
|
@@ -157,6 +157,9 @@ enum {
|
||||
UI_BLOCK_POPOVER_ONCE = 1 << 22,
|
||||
/** Always show keymaps, even for non-menus. */
|
||||
UI_BLOCK_SHOW_SHORTCUT_ALWAYS = 1 << 23,
|
||||
/** The block is only used during the search process and will not be drawn.
|
||||
* Currently just for the case of a closed panel's subpanel (and its subpanels). */
|
||||
UI_BLOCK_SEARCH_ONLY = 1 << 25,
|
||||
};
|
||||
|
||||
/** #uiPopupBlockHandle.menuretval */
|
||||
@@ -671,6 +674,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_is_search_only(const uiBlock *block);
|
||||
void UI_block_set_search_only(uiBlock *block, bool search_only);
|
||||
void UI_block_set_search_filter(uiBlock *block, const char *search_filter);
|
||||
|
||||
void UI_block_free(const struct bContext *C, uiBlock *block);
|
||||
void UI_blocklist_free(const struct bContext *C, struct ListBase *lb);
|
||||
@@ -1684,6 +1690,9 @@ 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_matches_search_filter(const struct Panel *panel);
|
||||
bool UI_panel_is_active(const struct Panel *panel);
|
||||
void UI_panels_set_expansion_from_seach_filter(const struct bContext *C, struct ARegion *region);
|
||||
|
||||
bool UI_panel_category_is_visible(const struct ARegion *region);
|
||||
void UI_panel_category_add(struct ARegion *region, const char *name);
|
||||
@@ -1862,6 +1871,8 @@ uiLayout *UI_block_layout(uiBlock *block,
|
||||
void UI_block_layout_set_current(uiBlock *block, uiLayout *layout);
|
||||
void UI_block_layout_resolve(uiBlock *block, int *r_x, int *r_y);
|
||||
|
||||
bool UI_block_apply_search_filter(uiBlock *block);
|
||||
|
||||
void UI_region_message_subscribe(struct ARegion *region, struct wmMsgBus *mbus);
|
||||
|
||||
uiBlock *uiLayoutGetBlock(uiLayout *layout);
|
||||
@@ -1914,6 +1925,7 @@ float uiLayoutGetUnitsY(uiLayout *layout);
|
||||
int uiLayoutGetEmboss(uiLayout *layout);
|
||||
bool uiLayoutGetPropSep(uiLayout *layout);
|
||||
bool uiLayoutGetPropDecorate(uiLayout *layout);
|
||||
void uiLayoutRootSetSearchOnly(uiLayout *layout, bool search_only);
|
||||
|
||||
/* layout specifiers */
|
||||
uiLayout *uiLayoutRow(uiLayout *layout, bool align);
|
||||
@@ -2414,6 +2426,8 @@ void uiItemTabsEnumR_prop(uiLayout *layout,
|
||||
struct bContext *C,
|
||||
struct PointerRNA *ptr,
|
||||
PropertyRNA *prop,
|
||||
struct PointerRNA *ptr_highlight,
|
||||
PropertyRNA *prop_highlight,
|
||||
bool icon_only);
|
||||
|
||||
/* Only for testing, inspecting layouts. */
|
||||
|
@@ -67,6 +67,7 @@ typedef enum ThemeColorID {
|
||||
TH_HEADERDESEL,
|
||||
TH_HEADER_TEXT,
|
||||
TH_HEADER_TEXT_HI,
|
||||
TH_SEARCH_MATCH,
|
||||
|
||||
/* panels */
|
||||
TH_PANEL_HEADER,
|
||||
|
@@ -1959,8 +1959,12 @@ void UI_block_draw(const bContext *C, uiBlock *block)
|
||||
}
|
||||
}
|
||||
}
|
||||
ui_draw_aligned_panel(
|
||||
&style, block, &rect, UI_panel_category_is_visible(region), show_background);
|
||||
ui_draw_aligned_panel(&style,
|
||||
block,
|
||||
&rect,
|
||||
UI_panel_category_is_visible(region),
|
||||
show_background,
|
||||
region->flag & RGN_FLAG_SEARCH_FILTER_ACTIVE);
|
||||
}
|
||||
|
||||
BLF_batch_draw_begin();
|
||||
@@ -3505,6 +3509,21 @@ void UI_block_theme_style_set(uiBlock *block, char theme_style)
|
||||
block->theme_style = theme_style;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
void UI_block_set_search_filter(uiBlock *block, const char *search_filter)
|
||||
{
|
||||
block->search_filter = search_filter;
|
||||
}
|
||||
|
||||
static void ui_but_build_drawstr_float(uiBut *but, double value)
|
||||
{
|
||||
size_t slen = 0;
|
||||
@@ -3907,6 +3926,7 @@ uiBut *ui_but_change_type(uiBut *but, eButType new_type)
|
||||
const bool found_layout = ui_layout_replace_but_ptr(but->layout, old_but_ptr, but);
|
||||
BLI_assert(found_layout);
|
||||
UNUSED_VARS_NDEBUG(found_layout);
|
||||
ui_button_group_replace_but_ptr(but->layout, old_but_ptr, but);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -81,6 +81,11 @@ enum {
|
||||
UI_HAS_ICON = (1 << 3),
|
||||
UI_HIDDEN = (1 << 4),
|
||||
UI_SELECT_DRAW = (1 << 5), /* Display selected, doesn't impact interaction. */
|
||||
/**
|
||||
* The button matches the search filter. When property search is active, this
|
||||
* is used to determine which items to keep enabled and which to disable.
|
||||
*/
|
||||
UI_SEARCH_FILTER_MATCHES = (1 << 12),
|
||||
/* warn: rest of uiBut->flag in UI_interface.h */
|
||||
};
|
||||
|
||||
@@ -422,7 +427,7 @@ struct uiBlock {
|
||||
|
||||
ListBase butstore; /* UI_butstore_* runtime function */
|
||||
|
||||
ListBase layouts;
|
||||
ListBase layouts; /* Note: Should be called layout_roots. */
|
||||
struct uiLayout *curlayout;
|
||||
|
||||
ListBase contexts;
|
||||
@@ -517,6 +522,12 @@ struct uiBlock {
|
||||
*/
|
||||
char display_device[64];
|
||||
|
||||
/**
|
||||
* Pointer to the space's property search string.
|
||||
* The block doesn't allocate this or change it.
|
||||
*/
|
||||
const char *search_filter;
|
||||
|
||||
struct PieMenuData pie_data;
|
||||
};
|
||||
|
||||
@@ -805,7 +816,9 @@ extern void ui_draw_aligned_panel(const struct 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);
|
||||
void ui_panel_set_search_filter_match(struct Panel *panel, const bool value);
|
||||
|
||||
/* interface_draw.c */
|
||||
extern void ui_draw_dropshadow(
|
||||
@@ -994,6 +1007,7 @@ void ui_resources_free(void);
|
||||
/* interface_layout.c */
|
||||
void ui_layout_add_but(uiLayout *layout, uiBut *but);
|
||||
bool ui_layout_replace_but_ptr(uiLayout *layout, const void *old_but_ptr, uiBut *new_but);
|
||||
void ui_button_group_replace_but_ptr(uiLayout *root, const void *old_but_ptr, uiBut *new_but);
|
||||
uiBut *ui_but_add_search(uiBut *but,
|
||||
PointerRNA *ptr,
|
||||
PropertyRNA *prop,
|
||||
|
@@ -80,12 +80,32 @@
|
||||
|
||||
/* uiLayoutRoot */
|
||||
|
||||
/**
|
||||
* A group of button references, used by property search to keep track of sets of buttons that
|
||||
* should be searched together. For example, in property split layouts number buttons and their
|
||||
* labels (and even their decorators) are separate buttons, but they must be searched and
|
||||
* highlighted together.
|
||||
*/
|
||||
typedef struct uiButtonGroup {
|
||||
void *next, *prev;
|
||||
ListBase buttons; /* #LinkData with #uiBut data field. */
|
||||
} uiButtonGroup;
|
||||
|
||||
typedef struct uiLayoutRoot {
|
||||
struct uiLayoutRoot *next, *prev;
|
||||
|
||||
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;
|
||||
|
||||
ListBase button_groups; /* #uiButtonGroup. */
|
||||
|
||||
int emw, emh;
|
||||
int padding;
|
||||
|
||||
@@ -414,6 +434,59 @@ static void ui_item_move(uiItem *item, int delta_xmin, int delta_xmax)
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Button Groups
|
||||
* \{ */
|
||||
|
||||
/**
|
||||
* Every function that adds a set of buttons must create another group,
|
||||
* then #ui_def_but adds buttons to the current group (the last).
|
||||
*/
|
||||
static void layout_root_new_button_group(uiLayoutRoot *root)
|
||||
{
|
||||
uiButtonGroup *new_group = MEM_mallocN(sizeof(uiButtonGroup), __func__);
|
||||
BLI_listbase_clear(&new_group->buttons);
|
||||
BLI_addtail(&root->button_groups, new_group);
|
||||
}
|
||||
|
||||
static void button_group_add_but(uiLayoutRoot *root, uiBut *but)
|
||||
{
|
||||
BLI_assert(root != NULL);
|
||||
|
||||
uiButtonGroup *current_button_group = root->button_groups.last;
|
||||
BLI_assert(current_button_group != NULL);
|
||||
|
||||
/* We can't use the button directly because adding it to
|
||||
* this list would mess with its prev and next pointers. */
|
||||
LinkData *button_link = MEM_mallocN(sizeof(LinkData), __func__);
|
||||
button_link->data = but;
|
||||
BLI_addtail(¤t_button_group->buttons, button_link);
|
||||
}
|
||||
|
||||
static void button_group_free(uiButtonGroup *button_group)
|
||||
{
|
||||
BLI_freelistN(&button_group->buttons);
|
||||
MEM_freeN(button_group);
|
||||
}
|
||||
|
||||
/* This function should be removed whenever #ui_layout_replace_but_ptr is removed. */
|
||||
void ui_button_group_replace_but_ptr(uiLayout *layout, const void *old_but_ptr, uiBut *new_but)
|
||||
{
|
||||
LISTBASE_FOREACH (uiButtonGroup *, button_group, &layout->root->button_groups) {
|
||||
LISTBASE_FOREACH (LinkData *, link, &button_group->buttons) {
|
||||
if (link->data == old_but_ptr) {
|
||||
link->data = new_but;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* The button should be in a group. */
|
||||
BLI_assert(false);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Special RNA Items
|
||||
* \{ */
|
||||
@@ -901,6 +974,8 @@ static void ui_item_enum_expand_tabs(uiLayout *layout,
|
||||
uiBlock *block,
|
||||
PointerRNA *ptr,
|
||||
PropertyRNA *prop,
|
||||
PointerRNA *ptr_highlight,
|
||||
PropertyRNA *prop_highlight,
|
||||
const char *uiname,
|
||||
const int h,
|
||||
const bool icon_only)
|
||||
@@ -909,8 +984,26 @@ static void ui_item_enum_expand_tabs(uiLayout *layout,
|
||||
|
||||
ui_item_enum_expand_exec(layout, block, ptr, prop, uiname, h, UI_BTYPE_TAB, icon_only);
|
||||
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++;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1988,6 +2081,7 @@ void uiItemFullR(uiLayout *layout,
|
||||
#endif /* UI_PROP_DECORATE */
|
||||
|
||||
UI_block_layout_set_current(block, layout);
|
||||
layout_root_new_button_group(layout->root);
|
||||
|
||||
/* retrieve info */
|
||||
const PropertyType type = RNA_property_type(prop);
|
||||
@@ -2738,6 +2832,8 @@ void uiItemPointerR_prop(uiLayout *layout,
|
||||
char namestr[UI_MAX_NAME_STR];
|
||||
const bool use_prop_sep = ((layout->item.flag & UI_ITEM_PROP_SEP) != 0);
|
||||
|
||||
layout_root_new_button_group(layout->root);
|
||||
|
||||
type = RNA_property_type(prop);
|
||||
if (!ELEM(type, PROP_POINTER, PROP_STRING, PROP_ENUM)) {
|
||||
RNA_warning("Property %s.%s must be a pointer, string or enum",
|
||||
@@ -2843,6 +2939,7 @@ static uiBut *ui_item_menu(uiLayout *layout,
|
||||
int w, h;
|
||||
|
||||
UI_block_layout_set_current(block, layout);
|
||||
layout_root_new_button_group(layout->root);
|
||||
|
||||
if (!name) {
|
||||
name = "";
|
||||
@@ -3110,6 +3207,7 @@ static uiBut *uiItemL_(uiLayout *layout, const char *name, int icon)
|
||||
int w;
|
||||
|
||||
UI_block_layout_set_current(block, layout);
|
||||
layout_root_new_button_group(layout->root);
|
||||
|
||||
if (!name) {
|
||||
name = "";
|
||||
@@ -3496,13 +3594,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);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
@@ -5031,6 +5135,205 @@ int uiLayoutGetEmboss(uiLayout *layout)
|
||||
return layout->emboss;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tags the layout root as search only, meaning the search process will run, but not the rest of
|
||||
* the layout process. Use in situations where part of the block's contents normally wouldn't be
|
||||
* drawn, but must be searched anyway, like the contents of closed panels with headers.
|
||||
*/
|
||||
void uiLayoutRootSetSearchOnly(uiLayout *layout, bool search_only)
|
||||
{
|
||||
layout->root->search_only = search_only;
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Block Layout Search Filtering
|
||||
* \{ */
|
||||
|
||||
static void layout_root_free(uiLayoutRoot *root);
|
||||
|
||||
// #define PROPERTY_SEARCH_USE_TOOLTIPS
|
||||
|
||||
static bool block_search_panel_label_matches(const uiBlock *block)
|
||||
{
|
||||
if ((block->panel != NULL) && (block->panel->type != NULL)) {
|
||||
if (BLI_strcasestr(block->panel->type->label, block->search_filter)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Buttons for search only layouts (closed panel subpanels) have still been added from the
|
||||
* layout functions, but they need to be hidden. Theoretically they could be removed too.
|
||||
*/
|
||||
static void layout_free_and_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 {
|
||||
layout_free_and_hide_buttons((uiLayout *)item);
|
||||
}
|
||||
}
|
||||
|
||||
MEM_freeN(layout);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove layouts used only for search and hide their buttons.
|
||||
*/
|
||||
static void block_search_remove_search_only_roots(uiBlock *block)
|
||||
{
|
||||
LISTBASE_FOREACH_MUTABLE (uiLayoutRoot *, root, &block->layouts) {
|
||||
if (root->search_only) {
|
||||
layout_free_and_hide_buttons(root->layout);
|
||||
BLI_remlink(&block->layouts, root);
|
||||
layout_root_free(root);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if a button or the data / operator it represents matches the search filter.
|
||||
*/
|
||||
static bool button_matches_search_filter(uiBut *but, const char *search_filter)
|
||||
{
|
||||
/* Do the shorter checks first for performance reasons. */
|
||||
if (BLI_strcasestr(but->str, search_filter)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (but->optype != NULL) {
|
||||
if (BLI_strcasestr(but->optype->name, search_filter)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (but->rnaprop != NULL) {
|
||||
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
|
||||
|
||||
/* Search through labels of enum property items if they are in a dropdown menu.
|
||||
* Unfortunately we have no context here so we cannot search through RNA enums
|
||||
* with dynamic entries (or "itemf" functions) which require context. */
|
||||
if (but->type == UI_BTYPE_MENU) {
|
||||
PointerRNA *ptr = &but->rnapoin;
|
||||
PropertyRNA *enum_prop = but->rnaprop;
|
||||
|
||||
int items_len;
|
||||
const EnumPropertyItem *items_array = NULL;
|
||||
bool free;
|
||||
RNA_property_enum_items_gettexted(NULL, ptr, enum_prop, &items_array, &items_len, &free);
|
||||
|
||||
if (items_array == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i = 0; i < items_len; i++) {
|
||||
if (BLI_strcasestr(items_array[i].name, search_filter)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (free) {
|
||||
MEM_freeN((EnumPropertyItem *)items_array);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test for a search result within the a specific button group.
|
||||
*/
|
||||
static bool button_group_has_search_match(uiButtonGroup *button_group, const char *search_filter)
|
||||
{
|
||||
LISTBASE_FOREACH (LinkData *, link, &button_group->buttons) {
|
||||
uiBut *but = link->data;
|
||||
if (button_matches_search_filter(but, search_filter)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply the search filter, tagging all buttons with whether they match or not.
|
||||
* Tag every button in the group as a search match if any button matches.
|
||||
*
|
||||
* \note It would be great to return early here if we found a match, but because
|
||||
* the results could be visible we have to continue searching the entire block.
|
||||
*
|
||||
* \return Whether the block has any search results.
|
||||
*/
|
||||
static bool block_search_filter_tag_buttons(uiBlock *block)
|
||||
{
|
||||
bool has_result = false;
|
||||
LISTBASE_FOREACH (uiLayoutRoot *, root, &block->layouts) {
|
||||
LISTBASE_FOREACH (uiButtonGroup *, button_group, &root->button_groups) {
|
||||
if (button_group_has_search_match(button_group, block->search_filter)) {
|
||||
LISTBASE_FOREACH (LinkData *, link, &button_group->buttons) {
|
||||
uiBut *but = link->data;
|
||||
but->flag |= UI_SEARCH_FILTER_MATCHES;
|
||||
}
|
||||
has_result = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return has_result;
|
||||
}
|
||||
|
||||
static void block_search_deactivate_buttons(uiBlock *block)
|
||||
{
|
||||
LISTBASE_FOREACH (uiBut *, but, &block->buttons) {
|
||||
if (!(but->flag & UI_SEARCH_FILTER_MATCHES)) {
|
||||
but->flag |= UI_BUT_INACTIVE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply property search behavior, setting panel flags and deactivating buttons that don't match.
|
||||
*
|
||||
* \note Must be run before #UI_block_layout_resolve.
|
||||
*/
|
||||
bool UI_block_apply_search_filter(uiBlock *block)
|
||||
{
|
||||
if (!(block->search_filter && block->search_filter[0])) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const bool panel_label_matches = block_search_panel_label_matches(block);
|
||||
|
||||
const bool has_result = panel_label_matches ? true : block_search_filter_tag_buttons(block);
|
||||
|
||||
block_search_remove_search_only_roots(block);
|
||||
|
||||
if (block->panel != NULL) {
|
||||
ui_panel_set_search_filter_match(block->panel, has_result);
|
||||
}
|
||||
|
||||
if (!panel_label_matches) {
|
||||
block_search_deactivate_buttons(block);
|
||||
}
|
||||
|
||||
return has_result;
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
@@ -5275,6 +5578,14 @@ static void ui_layout_free(uiLayout *layout)
|
||||
MEM_freeN(layout);
|
||||
}
|
||||
|
||||
static void layout_root_free(uiLayoutRoot *root)
|
||||
{
|
||||
LISTBASE_FOREACH_MUTABLE (uiButtonGroup *, button_group, &root->button_groups) {
|
||||
button_group_free(button_group);
|
||||
}
|
||||
MEM_freeN(root);
|
||||
}
|
||||
|
||||
static void ui_layout_add_padding_button(uiLayoutRoot *root)
|
||||
{
|
||||
if (root->padding) {
|
||||
@@ -5309,6 +5620,9 @@ uiLayout *UI_block_layout(uiBlock *block,
|
||||
root->padding = padding;
|
||||
root->opcontext = WM_OP_INVOKE_REGION_WIN;
|
||||
|
||||
BLI_listbase_clear(&root->button_groups);
|
||||
layout_root_new_button_group(root);
|
||||
|
||||
layout = MEM_callocN(sizeof(uiLayout), "uiLayout");
|
||||
layout->item.type = (type == UI_LAYOUT_VERT_BAR) ? ITEM_LAYOUT_COLUMN : ITEM_LAYOUT_ROOT;
|
||||
|
||||
@@ -5393,6 +5707,8 @@ void ui_layout_add_but(uiLayout *layout, uiBut *but)
|
||||
if (layout->emboss != UI_EMBOSS_UNDEFINED) {
|
||||
but->emboss = layout->emboss;
|
||||
}
|
||||
|
||||
button_group_add_but(layout->root, but);
|
||||
}
|
||||
|
||||
bool ui_layout_replace_but_ptr(uiLayout *layout, const void *old_but_ptr, uiBut *new_but)
|
||||
@@ -5458,15 +5774,19 @@ void UI_block_layout_resolve(uiBlock *block, int *r_x, int *r_y)
|
||||
|
||||
block->curlayout = NULL;
|
||||
|
||||
LISTBASE_FOREACH (uiLayoutRoot *, root, &block->layouts) {
|
||||
LISTBASE_FOREACH_MUTABLE (uiLayoutRoot *, root, &block->layouts) {
|
||||
/* Seach only roots should be removed by #UI_block_apply_search_filter. */
|
||||
BLI_assert(!root->search_only);
|
||||
|
||||
ui_layout_add_padding_button(root);
|
||||
|
||||
/* NULL in advance so we don't interfere when adding button */
|
||||
ui_layout_end(block, root->layout, r_x, r_y);
|
||||
ui_layout_free(root->layout);
|
||||
layout_root_free(root);
|
||||
}
|
||||
|
||||
BLI_freelistN(&block->layouts);
|
||||
BLI_listbase_clear(&block->layouts);
|
||||
|
||||
/* XXX silly trick, interface_templates.c doesn't get linked
|
||||
* because it's not used by other files in this module? */
|
||||
|
@@ -77,6 +77,7 @@
|
||||
#define PNL_ANIM_ALIGN 8
|
||||
#define PNL_NEW_ADDED 16
|
||||
#define PNL_FIRST 32
|
||||
#define PNL_SEARCH_FILTER_MATCHES 64
|
||||
|
||||
/* the state of the mouse position relative to the panel */
|
||||
typedef enum uiPanelMouseState {
|
||||
@@ -125,16 +126,32 @@ 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 use_search_color,
|
||||
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);
|
||||
|
||||
if (region_search_filter_active && use_search_color && search_match) {
|
||||
UI_GetThemeColor4ubv(TH_SEARCH_MATCH, r_color);
|
||||
}
|
||||
else {
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -230,6 +247,7 @@ static Panel *UI_panel_add_instanced_ex(ARegion *region,
|
||||
BLI_strncpy(panel->panelname, panel_type->idname, sizeof(panel->panelname));
|
||||
|
||||
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. */
|
||||
@@ -786,6 +804,72 @@ static void ui_offset_panel_block(uiBlock *block)
|
||||
block->rect.xmin = block->rect.ymin = 0.0;
|
||||
}
|
||||
|
||||
void ui_panel_set_search_filter_match(struct Panel *panel, const bool value)
|
||||
{
|
||||
SET_FLAG_FROM_TEST(panel->runtime_flag, value, PNL_SEARCH_FILTER_MATCHES);
|
||||
}
|
||||
|
||||
static void panel_matches_search_filter_recursive(const Panel *panel, bool *filter_matches)
|
||||
{
|
||||
*filter_matches |= panel->runtime_flag & PNL_SEARCH_FILTER_MATCHES;
|
||||
|
||||
/* If the panel is filtered (removed) we need to check 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 subpanels contain a property that matches the search filter.
|
||||
*/
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether a panel is currently active (displayed).
|
||||
*/
|
||||
bool UI_panel_is_active(const Panel *panel)
|
||||
{
|
||||
return panel->runtime_flag & PNL_ACTIVE;
|
||||
}
|
||||
|
||||
static void panel_set_expansion_from_seach_filter_recursive(const bContext *C, Panel *panel)
|
||||
{
|
||||
short start_flag = panel->flag;
|
||||
SET_FLAG_FROM_TEST(panel->flag, !UI_panel_matches_search_filter(panel), PNL_CLOSED);
|
||||
if (start_flag != panel->flag) {
|
||||
panel_activate_state(C, panel, PANEL_STATE_ANIMATION);
|
||||
}
|
||||
|
||||
/* If the panel is filtered (removed) we need to check that its children are too. */
|
||||
LISTBASE_FOREACH (Panel *, child_panel, &panel->children) {
|
||||
if (panel->type == NULL || (panel->type->flag & PNL_NO_HEADER)) {
|
||||
continue;
|
||||
}
|
||||
panel_set_expansion_from_seach_filter_recursive(C, child_panel);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Uses the panel's search filter flag to set its expansion,
|
||||
* activating animation if it was closed or opened.
|
||||
*/
|
||||
void UI_panels_set_expansion_from_seach_filter(const bContext *C, ARegion *region)
|
||||
{
|
||||
LISTBASE_FOREACH (Panel *, panel, ®ion->panels) {
|
||||
if (panel->type == NULL || (panel->type->flag & PNL_NO_HEADER)) {
|
||||
continue;
|
||||
}
|
||||
panel_set_expansion_from_seach_filter_recursive(C, panel);
|
||||
}
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
@@ -829,7 +913,8 @@ 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);
|
||||
@@ -840,7 +925,8 @@ static void ui_draw_aligned_panel_header(const uiStyle *style,
|
||||
|
||||
/* draw text label */
|
||||
uchar col_title[4];
|
||||
panel_title_color_get(show_background, col_title);
|
||||
panel_title_color_get(
|
||||
panel, show_background, is_subpanel, region_search_filter_active, col_title);
|
||||
col_title[3] = 255;
|
||||
|
||||
rcti hrect = *rect;
|
||||
@@ -862,7 +948,8 @@ 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];
|
||||
@@ -937,7 +1024,8 @@ void ui_draw_aligned_panel(const uiStyle *style,
|
||||
GPU_blend(GPU_BLEND_ALPHA);
|
||||
|
||||
/* draw with background color */
|
||||
immUniformThemeColor(TH_PANEL_HEADER);
|
||||
immUniformThemeColor(UI_panel_matches_search_filter(panel) ? TH_SEARCH_MATCH :
|
||||
TH_PANEL_HEADER);
|
||||
immRectf(pos, minx, headrect.ymin, rect->xmax, y);
|
||||
|
||||
immBegin(GPU_PRIM_LINES, 4);
|
||||
@@ -957,7 +1045,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, false, region_search_filter_active, col_title);
|
||||
|
||||
GPU_blend(GPU_BLEND_ALPHA);
|
||||
UI_icon_draw_ex(headrect.xmax - ((PNL_ICON * 2.2f) / block->aspect),
|
||||
@@ -976,7 +1064,8 @@ void ui_draw_aligned_panel(const uiStyle *style,
|
||||
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. */
|
||||
@@ -1030,8 +1119,8 @@ void ui_draw_aligned_panel(const uiStyle *style,
|
||||
immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
|
||||
GPU_blend(GPU_BLEND_ALPHA);
|
||||
|
||||
/* Draw panel backdrop if it wasn't already been drawn by the single opaque round box earlier.
|
||||
* Note: Sub-panels blend with panels, so they can't be opaque. */
|
||||
/* Draw panel backdrop if it wasn't already been drawn by the single opaque round box
|
||||
* earlier. Note: Sub-panels blend with panels, so they can't be opaque. */
|
||||
if (show_background && !(draw_box_style && !is_subpanel)) {
|
||||
/* Draw the bottom sub-panels. */
|
||||
if (draw_box_style) {
|
||||
@@ -1071,7 +1160,7 @@ 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, false, region_search_filter_active, col_title);
|
||||
float tria_color[4];
|
||||
rgb_uchar_to_float(tria_color, col_title);
|
||||
tria_color[3] = 1.0f;
|
||||
@@ -1859,13 +1948,15 @@ void UI_panels_draw(const bContext *C, ARegion *region)
|
||||
* UI blocks are added in reverse order and we need child panels
|
||||
* to draw on top. */
|
||||
LISTBASE_FOREACH_BACKWARD (uiBlock *, block, ®ion->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_block_draw(C, block);
|
||||
}
|
||||
}
|
||||
|
||||
LISTBASE_FOREACH_BACKWARD (uiBlock *, block, ®ion->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_block_draw(C, block);
|
||||
}
|
||||
}
|
||||
|
@@ -261,6 +261,9 @@ const uchar *UI_ThemeGetColorPtr(bTheme *btheme, int spacetype, int colorid)
|
||||
case TH_HEADER_TEXT_HI:
|
||||
cp = ts->header_text_hi;
|
||||
break;
|
||||
case TH_SEARCH_MATCH:
|
||||
cp = ts->search_match_color;
|
||||
break;
|
||||
|
||||
case TH_PANEL_HEADER:
|
||||
cp = ts->panelcolors.header;
|
||||
|
@@ -492,6 +492,9 @@ void ED_region_do_layout(bContext *C, ARegion *region)
|
||||
|
||||
UI_SetTheme(area ? area->spacetype : 0, at->regionid);
|
||||
at->layout(C, region);
|
||||
|
||||
/* Clear temporary update flag. */
|
||||
region->flag &= ~RGN_FLAG_SEARCH_FILTER_UPDATE;
|
||||
}
|
||||
|
||||
/* only exported for WM */
|
||||
@@ -736,6 +739,34 @@ void ED_area_tag_refresh(ScrArea *area)
|
||||
|
||||
/* *************************************************************** */
|
||||
|
||||
/**
|
||||
* Returns the search string if the space type supports property search.
|
||||
*/
|
||||
const char *ED_area_search_filter_get(const ScrArea *area, const ARegion *region)
|
||||
{
|
||||
/* Only the properties editor has a search string for now. */
|
||||
if (area->spacetype == SPACE_PROPERTIES) {
|
||||
SpaceProperties *sbuts = area->spacedata.first;
|
||||
if (region->regiontype == RGN_TYPE_WINDOW) {
|
||||
return sbuts->runtime->search_string;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void ED_region_search_filter_update(const ScrArea *area, ARegion *region)
|
||||
{
|
||||
region->flag |= RGN_FLAG_SEARCH_FILTER_UPDATE;
|
||||
|
||||
const char *search_filter = ED_area_search_filter_get(area, region);
|
||||
SET_FLAG_FROM_TEST(region->flag,
|
||||
region->regiontype == RGN_TYPE_WINDOW && search_filter[0] != '\0',
|
||||
RGN_FLAG_SEARCH_FILTER_ACTIVE);
|
||||
}
|
||||
|
||||
/* *************************************************************** */
|
||||
|
||||
/* use NULL to disable it */
|
||||
void ED_area_status_text(ScrArea *area, const char *str)
|
||||
{
|
||||
@@ -2558,7 +2589,9 @@ static void ed_panel_draw(const bContext *C,
|
||||
Panel *panel,
|
||||
int w,
|
||||
int em,
|
||||
char *unique_panel_str)
|
||||
char *unique_panel_str,
|
||||
const char *search_filter,
|
||||
bool search_only)
|
||||
{
|
||||
const uiStyle *style = UI_style_get_dpi();
|
||||
|
||||
@@ -2571,10 +2604,14 @@ static void ed_panel_draw(const bContext *C,
|
||||
strncat(block_name, unique_panel_str, INSTANCED_PANEL_UNIQUE_STR_LEN);
|
||||
}
|
||||
uiBlock *block = UI_block_begin(C, region, block_name, UI_EMBOSS);
|
||||
UI_block_set_search_filter(block, search_filter);
|
||||
UI_block_set_search_only(block, search_only);
|
||||
|
||||
bool open;
|
||||
panel = UI_panel_begin(region, lb, block, pt, panel, &open);
|
||||
|
||||
const bool search_filter_active = search_filter != NULL && search_filter[0] != '\0';
|
||||
|
||||
/* bad fixed values */
|
||||
int xco, yco, h = 0;
|
||||
int headerend = w - UI_UNIT_X;
|
||||
@@ -2590,9 +2627,11 @@ static void ed_panel_draw(const bContext *C,
|
||||
1,
|
||||
0,
|
||||
style);
|
||||
uiLayoutRootSetSearchOnly(panel->layout, search_only);
|
||||
|
||||
pt->draw_header_preset(C, panel);
|
||||
|
||||
UI_block_apply_search_filter(block);
|
||||
UI_block_layout_resolve(block, &xco, &yco);
|
||||
UI_block_translate(block, headerend - xco, 0);
|
||||
panel->layout = NULL;
|
||||
@@ -2620,9 +2659,11 @@ 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);
|
||||
|
||||
UI_block_apply_search_filter(block);
|
||||
UI_block_layout_resolve(block, &xco, &yco);
|
||||
panel->labelofs = xco - labelx;
|
||||
panel->layout = NULL;
|
||||
@@ -2631,7 +2672,7 @@ static void ed_panel_draw(const bContext *C,
|
||||
panel->labelofs = 0;
|
||||
}
|
||||
|
||||
if (open) {
|
||||
if (open || search_filter_active) {
|
||||
short panelContext;
|
||||
|
||||
/* panel context can either be toolbar region or normal panels region */
|
||||
@@ -2655,9 +2696,11 @@ static void ed_panel_draw(const bContext *C,
|
||||
em,
|
||||
0,
|
||||
style);
|
||||
uiLayoutRootSetSearchOnly(panel->layout, search_only || !open);
|
||||
|
||||
pt->draw(C, panel);
|
||||
|
||||
UI_block_apply_search_filter(block);
|
||||
UI_block_layout_resolve(block, &xco, &yco);
|
||||
panel->layout = NULL;
|
||||
|
||||
@@ -2669,13 +2712,21 @@ static void ed_panel_draw(const bContext *C,
|
||||
UI_block_end(C, block);
|
||||
|
||||
/* Draw child panels. */
|
||||
if (open) {
|
||||
if (open || search_filter_active) {
|
||||
LISTBASE_FOREACH (LinkData *, link, &pt->children) {
|
||||
PanelType *child_pt = link->data;
|
||||
Panel *child_panel = UI_panel_find_by_type(&panel->children, child_pt);
|
||||
|
||||
if (child_pt->draw && (!child_pt->poll || child_pt->poll(C, child_pt))) {
|
||||
ed_panel_draw(C, region, &panel->children, child_pt, child_panel, w, em, unique_panel_str);
|
||||
ed_panel_draw(C,
|
||||
region,
|
||||
&panel->children,
|
||||
child_pt,
|
||||
child_panel,
|
||||
w,
|
||||
em,
|
||||
unique_panel_str,
|
||||
search_filter,
|
||||
!open);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2683,6 +2734,81 @@ static void ed_panel_draw(const bContext *C,
|
||||
UI_panel_end(region, block, w, h, open);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether a panel should be added to the region's panel layout.
|
||||
*/
|
||||
static bool panel_add_check(const bContext *C,
|
||||
const WorkSpace *workspace,
|
||||
const char *contexts[],
|
||||
const char *category_override,
|
||||
PanelType *panel_type)
|
||||
{
|
||||
/* Only add top level panels. */
|
||||
if (panel_type->parent) {
|
||||
return false;
|
||||
}
|
||||
/* Check the category override first. */
|
||||
if (category_override) {
|
||||
if (!STREQ(panel_type->category, category_override)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/* Verify context. */
|
||||
if (contexts != NULL && panel_type->context[0]) {
|
||||
if (!streq_array_any(panel_type->context, contexts)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/* If we're tagged, only use compatible. */
|
||||
if (panel_type->owner_id[0]) {
|
||||
if (!BKE_workspace_owner_id_check(workspace, panel_type->owner_id)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (LIKELY(panel_type->draw)) {
|
||||
if (panel_type->poll && !panel_type->poll(C, panel_type)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool region_uses_category_tabs(const ScrArea *area, const ARegion *region)
|
||||
{
|
||||
/* XXX, should use some better check? */
|
||||
/* For now also has hardcoded check for clip editor until it supports actual toolbar. */
|
||||
return ((1 << region->regiontype) & RGN_TYPE_HAS_CATEGORY_MASK) ||
|
||||
(region->regiontype == RGN_TYPE_TOOLS && area->spacetype == SPACE_CLIP);
|
||||
}
|
||||
|
||||
static const char *region_panels_collect_categories(ARegion *region,
|
||||
LinkNode *panel_types_stack,
|
||||
bool *use_category_tabs)
|
||||
{
|
||||
UI_panel_category_clear_all(region);
|
||||
|
||||
/* gather unique categories */
|
||||
for (LinkNode *pt_link = panel_types_stack; pt_link; pt_link = pt_link->next) {
|
||||
PanelType *pt = pt_link->link;
|
||||
if (pt->category[0]) {
|
||||
if (!UI_panel_category_find(region, pt->category)) {
|
||||
UI_panel_category_add(region, pt->category);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (UI_panel_category_is_visible(region)) {
|
||||
return UI_panel_category_active_get(region, true);
|
||||
}
|
||||
|
||||
*use_category_tabs = false;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* \param contexts: A NULL terminated array of context strings to match against.
|
||||
* Matching against any of these strings will draw the panel.
|
||||
@@ -2698,29 +2824,7 @@ void ED_region_panels_layout_ex(const bContext *C,
|
||||
WorkSpace *workspace = CTX_wm_workspace(C);
|
||||
LinkNode *panel_types_stack = NULL;
|
||||
LISTBASE_FOREACH_BACKWARD (PanelType *, pt, paneltypes) {
|
||||
/* Only draw top level panels. */
|
||||
if (pt->parent) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (category_override) {
|
||||
if (!STREQ(pt->category, category_override)) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
/* verify context */
|
||||
if (contexts && pt->context[0] && !streq_array_any(pt->context, contexts)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* If we're tagged, only use compatible. */
|
||||
if (pt->owner_id[0] && BKE_workspace_owner_id_check(workspace, pt->owner_id) == false) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* draw panel */
|
||||
if (pt->draw && (!pt->poll || pt->poll(C, pt))) {
|
||||
if (panel_add_check(C, workspace, contexts, category_override, pt)) {
|
||||
BLI_linklist_prepend_alloca(&panel_types_stack, pt);
|
||||
}
|
||||
}
|
||||
@@ -2731,12 +2835,7 @@ void ED_region_panels_layout_ex(const bContext *C,
|
||||
View2D *v2d = ®ion->v2d;
|
||||
int x, y, w, em;
|
||||
|
||||
/* XXX, should use some better check? */
|
||||
/* For now also has hardcoded check for clip editor until it supports actual toolbar. */
|
||||
bool use_category_tabs = (category_override == NULL) &&
|
||||
((((1 << region->regiontype) & RGN_TYPE_HAS_CATEGORY_MASK) ||
|
||||
(region->regiontype == RGN_TYPE_TOOLS &&
|
||||
area->spacetype == SPACE_CLIP)));
|
||||
bool use_category_tabs = (category_override == NULL) && region_uses_category_tabs(area, region);
|
||||
/* offset panels for small vertical tab area */
|
||||
const char *category = NULL;
|
||||
const int category_tabs_width = UI_PANEL_CATEGORY_MARGIN_WIDTH;
|
||||
@@ -2752,25 +2851,10 @@ void ED_region_panels_layout_ex(const bContext *C,
|
||||
|
||||
/* collect categories */
|
||||
if (use_category_tabs) {
|
||||
UI_panel_category_clear_all(region);
|
||||
|
||||
/* gather unique categories */
|
||||
for (LinkNode *pt_link = panel_types_stack; pt_link; pt_link = pt_link->next) {
|
||||
PanelType *pt = pt_link->link;
|
||||
if (pt->category[0]) {
|
||||
if (!UI_panel_category_find(region, pt->category)) {
|
||||
UI_panel_category_add(region, pt->category);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!UI_panel_category_is_visible(region)) {
|
||||
use_category_tabs = false;
|
||||
}
|
||||
else {
|
||||
category = UI_panel_category_active_get(region, true);
|
||||
margin_x = category_tabs_width;
|
||||
}
|
||||
category = region_panels_collect_categories(region, panel_types_stack, &use_category_tabs);
|
||||
}
|
||||
if (use_category_tabs) {
|
||||
margin_x = category_tabs_width;
|
||||
}
|
||||
|
||||
w = BLI_rctf_size_x(&v2d->cur);
|
||||
@@ -2782,6 +2866,9 @@ void ED_region_panels_layout_ex(const bContext *C,
|
||||
/* create panels */
|
||||
UI_panels_begin(C, region);
|
||||
|
||||
/* Get search string for property search. */
|
||||
const char *search_filter = ED_area_search_filter_get(area, region);
|
||||
|
||||
/* set view2d view matrix - UI_block_begin() stores it */
|
||||
UI_view2d_view_ortho(v2d);
|
||||
|
||||
@@ -2813,7 +2900,9 @@ void ED_region_panels_layout_ex(const bContext *C,
|
||||
panel,
|
||||
(pt->flag & PNL_DRAW_BOX) ? w_box_panel : w,
|
||||
em,
|
||||
NULL);
|
||||
NULL,
|
||||
search_filter,
|
||||
false);
|
||||
}
|
||||
|
||||
/* Draw "polyinstantaited" panels that don't have a 1 to 1 correspondence with their types. */
|
||||
@@ -2846,7 +2935,17 @@ void ED_region_panels_layout_ex(const bContext *C,
|
||||
panel,
|
||||
(panel->type->flag & PNL_DRAW_BOX) ? w_box_panel : w,
|
||||
em,
|
||||
unique_panel_str);
|
||||
unique_panel_str,
|
||||
search_filter,
|
||||
false);
|
||||
}
|
||||
}
|
||||
|
||||
/* Update panel expansion based on property search results. */
|
||||
if (region->flag & RGN_FLAG_SEARCH_FILTER_UPDATE) {
|
||||
/* Don't use the last update from the deactivation, or all the panels will be left closed. */
|
||||
if (region->flag & RGN_FLAG_SEARCH_FILTER_ACTIVE) {
|
||||
UI_panels_set_expansion_from_seach_filter(C, region);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2969,6 +3068,144 @@ void ED_region_panels_init(wmWindowManager *wm, ARegion *region)
|
||||
WM_event_add_keymap_handler(®ion->handlers, keymap);
|
||||
}
|
||||
|
||||
static bool panel_property_search(const bContext *C,
|
||||
ARegion *region,
|
||||
const uiStyle *style,
|
||||
Panel *panel,
|
||||
PanelType *panel_type,
|
||||
const char *search_filter)
|
||||
{
|
||||
uiBlock *block = UI_block_begin(C, region, panel_type->idname, UI_EMBOSS);
|
||||
UI_block_set_search_only(block, true);
|
||||
UI_block_set_search_filter(block, search_filter);
|
||||
|
||||
if (panel == NULL) {
|
||||
bool open;
|
||||
panel = UI_panel_begin(region, ®ion->panels, block, panel_type, panel, &open);
|
||||
}
|
||||
|
||||
/* Build the layouts. Because they are only used for search,
|
||||
* they don't need any of the proper style or layout information. */
|
||||
if (panel->type->draw_header_preset != NULL) {
|
||||
panel->layout = UI_block_layout(
|
||||
block, UI_LAYOUT_HORIZONTAL, UI_LAYOUT_HEADER, 0, 0, 0, 0, 0, style);
|
||||
uiLayoutRootSetSearchOnly(panel->layout, true);
|
||||
panel_type->draw_header_preset(C, panel);
|
||||
}
|
||||
if (panel->type->draw_header != NULL) {
|
||||
panel->layout = UI_block_layout(
|
||||
block, UI_LAYOUT_HORIZONTAL, UI_LAYOUT_HEADER, 0, 0, 0, 0, 0, style);
|
||||
uiLayoutRootSetSearchOnly(panel->layout, true);
|
||||
panel_type->draw_header(C, panel);
|
||||
}
|
||||
if (LIKELY(panel->type->draw != NULL)) {
|
||||
panel->layout = UI_block_layout(
|
||||
block, UI_LAYOUT_VERTICAL, UI_LAYOUT_PANEL, 0, 0, 0, 0, 0, style);
|
||||
uiLayoutRootSetSearchOnly(panel->layout, true);
|
||||
panel_type->draw(C, panel);
|
||||
}
|
||||
|
||||
/* We could check after each layout to increase the likelyhood of returning early,
|
||||
* but that probably wouldn't make much of a difference anyway. */
|
||||
if (UI_block_apply_search_filter(block)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
LISTBASE_FOREACH (LinkData *, link, &panel_type->children) {
|
||||
PanelType *panel_type_child = link->data;
|
||||
if (LIKELY(panel->type->draw != NULL)) {
|
||||
if (!panel_type_child->poll || panel_type_child->poll(C, panel_type_child)) {
|
||||
/* Search for the existing child panel here because it might be an instanced
|
||||
* child panel with a custom data field that will be needed to build the layout. */
|
||||
Panel *child_panel = UI_panel_find_by_type(&panel->children, panel_type_child);
|
||||
if (panel_property_search(
|
||||
C, region, style, child_panel, panel_type_child, search_filter)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ED_region_property_search(const bContext *C,
|
||||
ARegion *region,
|
||||
ListBase *paneltypes,
|
||||
const char *contexts[],
|
||||
const char *category_override)
|
||||
{
|
||||
ScrArea *area = CTX_wm_area(C);
|
||||
WorkSpace *workspace = CTX_wm_workspace(C);
|
||||
const uiStyle *style = UI_style_get_dpi();
|
||||
const char *search_filter = ED_area_search_filter_get(area, region);
|
||||
|
||||
LinkNode *panel_types_stack = NULL;
|
||||
LISTBASE_FOREACH_BACKWARD (PanelType *, pt, paneltypes) {
|
||||
if (panel_add_check(C, workspace, contexts, category_override, pt)) {
|
||||
BLI_linklist_prepend_alloca(&panel_types_stack, pt);
|
||||
}
|
||||
}
|
||||
|
||||
const char *category = NULL;
|
||||
bool use_category_tabs = (category_override == NULL) && region_uses_category_tabs(area, region);
|
||||
if (use_category_tabs) {
|
||||
category = region_panels_collect_categories(region, panel_types_stack, &use_category_tabs);
|
||||
}
|
||||
|
||||
/* Run property search for each panel, stopping if a result is found. */
|
||||
bool has_result = true;
|
||||
bool has_instanced_panel = false;
|
||||
for (LinkNode *pt_link = panel_types_stack; pt_link; pt_link = pt_link->next) {
|
||||
PanelType *panel_type = pt_link->link;
|
||||
/* Note that these checks are duplicated from #ED_region_panels_layout_ex. */
|
||||
if (panel_type->flag & PNL_INSTANCED) {
|
||||
has_instanced_panel = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (use_category_tabs) {
|
||||
if (panel_type->category[0] && !STREQ(category, panel_type->category)) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
/* We start property search with an empty panel list, so there's
|
||||
* no point in trying to find an existing panel with this type. */
|
||||
has_result = panel_property_search(C, region, style, NULL, panel_type, search_filter);
|
||||
if (has_result) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Run property search for instanced panels (created in the layout calls of previous panels). */
|
||||
if (!has_result && has_instanced_panel) {
|
||||
LISTBASE_FOREACH (Panel *, panel, ®ion->panels) {
|
||||
/* Note that these checks are duplicated from #ED_region_panels_layout_ex. */
|
||||
if (panel->type == NULL || !(panel->type->flag & PNL_INSTANCED)) {
|
||||
continue;
|
||||
}
|
||||
if (use_category_tabs) {
|
||||
if (panel->type->category[0] && !STREQ(category, panel->type->category)) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
has_result = panel_property_search(C, region, style, panel, panel->type, search_filter);
|
||||
if (has_result) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Free the panels and blocks, as they are only used for search. */
|
||||
UI_blocklist_free(C, ®ion->uiblocks);
|
||||
UI_panels_free_instanced(C, region);
|
||||
BKE_area_region_panels_free(®ion->panels);
|
||||
|
||||
return has_result;
|
||||
}
|
||||
|
||||
void ED_region_header_layout(const bContext *C, ARegion *region)
|
||||
{
|
||||
const uiStyle *style = UI_style_get_dpi();
|
||||
|
@@ -1115,11 +1115,18 @@ int buttons_context(const bContext *C, const char *member, bContextDataResult *r
|
||||
|
||||
/************************* Drawing the Path ************************/
|
||||
|
||||
void buttons_context_draw(const bContext *C, uiLayout *layout)
|
||||
static bool buttons_panel_context_poll(const bContext *C, PanelType *UNUSED(pt))
|
||||
{
|
||||
SpaceProperties *sbuts = CTX_wm_space_properties(C);
|
||||
return sbuts->mainb != BCONTEXT_TOOL;
|
||||
}
|
||||
|
||||
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, *sub;
|
||||
uiLayout *row;
|
||||
PointerRNA *ptr;
|
||||
char namebuf[128], *name;
|
||||
int a, icon;
|
||||
@@ -1180,52 +1187,11 @@ void buttons_context_draw(const bContext *C, uiLayout *layout)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uiItemSpacer(row);
|
||||
|
||||
sub = uiLayoutRow(row, false);
|
||||
uiLayoutSetEmboss(sub, UI_EMBOSS_NONE);
|
||||
uiItemO(sub,
|
||||
"",
|
||||
(sbuts->flag & SB_PIN_CONTEXT) ? ICON_PINNED : ICON_UNPINNED,
|
||||
"BUTTONS_OT_toggle_pin");
|
||||
}
|
||||
|
||||
#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);
|
||||
@@ -1233,7 +1199,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)
|
||||
|
@@ -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,8 @@ 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);
|
||||
|
@@ -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,65 @@
|
||||
|
||||
#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, "search_filter");
|
||||
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))
|
||||
{
|
||||
SpaceProperties *space = CTX_wm_space_properties(C);
|
||||
|
||||
space->runtime->search_string[0] = '\0';
|
||||
|
||||
ScrArea *area = CTX_wm_area(C);
|
||||
ED_region_search_filter_update(area, CTX_wm_region(C));
|
||||
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
|
||||
* \{ */
|
||||
|
@@ -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 */
|
||||
@@ -109,20 +110,29 @@ static void buttons_free(SpaceLink *sl)
|
||||
BLI_freelistN(&ct->users);
|
||||
MEM_freeN(ct);
|
||||
}
|
||||
|
||||
MEM_SAFE_FREE(sbuts->runtime);
|
||||
}
|
||||
|
||||
/* spacetype; init callback */
|
||||
static void buttons_init(struct wmWindowManager *UNUSED(wm), ScrArea *UNUSED(area))
|
||||
static void buttons_init(struct wmWindowManager *UNUSED(wm), ScrArea *area)
|
||||
{
|
||||
SpaceProperties *sbuts = (SpaceProperties *)area->spacedata.first;
|
||||
|
||||
sbuts->runtime = MEM_mallocN(sizeof(SpaceProperties_Runtime), __func__);
|
||||
sbuts->runtime->search_string[0] = '\0';
|
||||
}
|
||||
|
||||
static SpaceLink *buttons_duplicate(SpaceLink *sl)
|
||||
{
|
||||
SpaceProperties *sfile_old = (SpaceProperties *)sl;
|
||||
SpaceProperties *sbutsn = MEM_dupallocN(sl);
|
||||
|
||||
/* clear or remove stuff from old */
|
||||
sbutsn->path = NULL;
|
||||
sbutsn->texuser = NULL;
|
||||
sbutsn->runtime = MEM_dupallocN(sfile_old->runtime);
|
||||
sbutsn->runtime->search_string[0] = '\0';
|
||||
|
||||
return (SpaceLink *)sbutsn;
|
||||
}
|
||||
@@ -143,6 +153,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;
|
||||
@@ -230,71 +241,146 @@ int ED_buttons_tabs_list(SpaceProperties *sbuts, int *context_tabs_array)
|
||||
return length;
|
||||
}
|
||||
|
||||
static const char *buttons_main_region_context_string(const short mainb)
|
||||
{
|
||||
switch (mainb) {
|
||||
case BCONTEXT_SCENE:
|
||||
return "scene";
|
||||
case BCONTEXT_RENDER:
|
||||
return "render";
|
||||
case BCONTEXT_OUTPUT:
|
||||
return "output";
|
||||
case BCONTEXT_VIEW_LAYER:
|
||||
return "view_layer";
|
||||
case BCONTEXT_WORLD:
|
||||
return "world";
|
||||
case BCONTEXT_OBJECT:
|
||||
return "object";
|
||||
case BCONTEXT_DATA:
|
||||
return "data";
|
||||
case BCONTEXT_MATERIAL:
|
||||
return "material";
|
||||
case BCONTEXT_TEXTURE:
|
||||
return "texture";
|
||||
case BCONTEXT_PARTICLE:
|
||||
return "particle";
|
||||
case BCONTEXT_PHYSICS:
|
||||
return "physics";
|
||||
case BCONTEXT_BONE:
|
||||
return "bone";
|
||||
case BCONTEXT_MODIFIER:
|
||||
return "modifier";
|
||||
case BCONTEXT_SHADERFX:
|
||||
return "shaderfx";
|
||||
case BCONTEXT_CONSTRAINT:
|
||||
return "constraint";
|
||||
case BCONTEXT_BONE_CONSTRAINT:
|
||||
return "bone_constraint";
|
||||
case BCONTEXT_TOOL:
|
||||
return "tool";
|
||||
}
|
||||
|
||||
/* All the cases should be handled. */
|
||||
BLI_assert(false);
|
||||
return "";
|
||||
}
|
||||
|
||||
static void buttons_main_region_layout_properties(const bContext *C,
|
||||
SpaceProperties *sbuts,
|
||||
ARegion *region)
|
||||
{
|
||||
buttons_context_compute(C, sbuts);
|
||||
|
||||
const char *contexts[2] = {NULL, NULL};
|
||||
|
||||
switch (sbuts->mainb) {
|
||||
case BCONTEXT_SCENE:
|
||||
contexts[0] = "scene";
|
||||
break;
|
||||
case BCONTEXT_RENDER:
|
||||
contexts[0] = "render";
|
||||
break;
|
||||
case BCONTEXT_OUTPUT:
|
||||
contexts[0] = "output";
|
||||
break;
|
||||
case BCONTEXT_VIEW_LAYER:
|
||||
contexts[0] = "view_layer";
|
||||
break;
|
||||
case BCONTEXT_WORLD:
|
||||
contexts[0] = "world";
|
||||
break;
|
||||
case BCONTEXT_OBJECT:
|
||||
contexts[0] = "object";
|
||||
break;
|
||||
case BCONTEXT_DATA:
|
||||
contexts[0] = "data";
|
||||
break;
|
||||
case BCONTEXT_MATERIAL:
|
||||
contexts[0] = "material";
|
||||
break;
|
||||
case BCONTEXT_TEXTURE:
|
||||
contexts[0] = "texture";
|
||||
break;
|
||||
case BCONTEXT_PARTICLE:
|
||||
contexts[0] = "particle";
|
||||
break;
|
||||
case BCONTEXT_PHYSICS:
|
||||
contexts[0] = "physics";
|
||||
break;
|
||||
case BCONTEXT_BONE:
|
||||
contexts[0] = "bone";
|
||||
break;
|
||||
case BCONTEXT_MODIFIER:
|
||||
contexts[0] = "modifier";
|
||||
break;
|
||||
case BCONTEXT_SHADERFX:
|
||||
contexts[0] = "shaderfx";
|
||||
break;
|
||||
case BCONTEXT_CONSTRAINT:
|
||||
contexts[0] = "constraint";
|
||||
break;
|
||||
case BCONTEXT_BONE_CONSTRAINT:
|
||||
contexts[0] = "bone_constraint";
|
||||
break;
|
||||
case BCONTEXT_TOOL:
|
||||
contexts[0] = "tool";
|
||||
break;
|
||||
}
|
||||
const char *contexts[2] = {buttons_main_region_context_string(sbuts->mainb), NULL};
|
||||
|
||||
ED_region_panels_layout_ex(C, region, ®ion->type->paneltypes, contexts, NULL);
|
||||
}
|
||||
|
||||
static bool property_search_for_context(const bContext *C, ARegion *region, SpaceProperties *sbuts)
|
||||
{
|
||||
const char *contexts[2] = {buttons_main_region_context_string(sbuts->mainb), NULL};
|
||||
|
||||
if (sbuts->mainb == BCONTEXT_TOOL) {
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
buttons_context_compute(C, sbuts);
|
||||
return ED_region_property_search(C, region, ®ion->type->paneltypes, contexts, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
static void property_search_move_to_next_tab_with_results(SpaceProperties *sbuts,
|
||||
const int *context_tabs_array,
|
||||
const int tabs_len)
|
||||
{
|
||||
int current_tab_index = 0;
|
||||
for (int i = 0; i < tabs_len; i++) {
|
||||
if (sbuts->mainb == context_tabs_array[i]) {
|
||||
current_tab_index = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Try the tabs after the current tab. */
|
||||
for (int i = current_tab_index; i < tabs_len; i++) {
|
||||
if (sbuts->runtime->context_search_filter_active & (1 << i)) {
|
||||
sbuts->mainbuser = context_tabs_array[i];
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* Try the tabs before the current tab. */
|
||||
for (int i = 0; i < current_tab_index; i++) {
|
||||
if (sbuts->runtime->context_search_filter_active & (1 << i)) {
|
||||
sbuts->mainbuser = context_tabs_array[i];
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void property_search_all_tabs(const bContext *C,
|
||||
SpaceProperties *sbuts,
|
||||
ARegion *main_region,
|
||||
const int *context_tabs_array,
|
||||
const int tabs_len)
|
||||
{
|
||||
sbuts->runtime->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(area_copy->type, main_region);
|
||||
BKE_area_region_panels_free(®ion_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);
|
||||
|
||||
/* Loop through the tabs added to the properties editor. */
|
||||
for (int i = 0; i < tabs_len; i++) {
|
||||
/* -1 corresponds to a spacer. */
|
||||
if (context_tabs_array[i] == -1) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Handle search for the current tab later in the normal layout pass. */
|
||||
if (context_tabs_array[i] == sbuts->mainb) {
|
||||
continue;
|
||||
}
|
||||
|
||||
sbuts_copy->mainb = sbuts_copy->mainbo = sbuts_copy->mainbuser = context_tabs_array[i];
|
||||
|
||||
SET_FLAG_FROM_TEST(sbuts->runtime->context_search_filter_active,
|
||||
property_search_for_context(C_copy, region_copy, sbuts_copy),
|
||||
(1 << i));
|
||||
}
|
||||
|
||||
BKE_area_region_free(area_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 */
|
||||
@@ -307,6 +393,42 @@ static void buttons_main_region_layout(const bContext *C, ARegion *region)
|
||||
buttons_main_region_layout_properties(C, sbuts, region);
|
||||
}
|
||||
|
||||
if (region->flag & RGN_FLAG_SEARCH_FILTER_ACTIVE) {
|
||||
int context_tabs_array[32];
|
||||
int tabs_len = ED_buttons_tabs_list(sbuts, context_tabs_array);
|
||||
|
||||
property_search_all_tabs(C, sbuts, region, context_tabs_array, tabs_len);
|
||||
|
||||
/* Check whether the current tab has a search match. */
|
||||
bool current_tab_has_search_match = false;
|
||||
LISTBASE_FOREACH (Panel *, panel, ®ion->panels) {
|
||||
if (UI_panel_is_active(panel) && UI_panel_matches_search_filter(panel)) {
|
||||
current_tab_has_search_match = true;
|
||||
}
|
||||
}
|
||||
|
||||
/* Find which index in the list the current tab corresponds to. */
|
||||
int current_tab_index = -1;
|
||||
for (int i = 0; i < tabs_len; i++) {
|
||||
if (context_tabs_array[i] == sbuts->mainb) {
|
||||
current_tab_index = i;
|
||||
}
|
||||
}
|
||||
BLI_assert(current_tab_index != -1);
|
||||
|
||||
/* Update the tab search match flag for the current tab. */
|
||||
SET_FLAG_FROM_TEST(sbuts->runtime->context_search_filter_active,
|
||||
current_tab_has_search_match,
|
||||
(1 << current_tab_index));
|
||||
|
||||
/* Move to the next tab with a result */
|
||||
if (!current_tab_has_search_match) {
|
||||
if (region->flag & RGN_FLAG_SEARCH_FILTER_UPDATE) {
|
||||
property_search_move_to_next_tab_with_results(sbuts, context_tabs_array, tabs_len);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sbuts->mainbo = sbuts->mainb;
|
||||
}
|
||||
|
||||
@@ -328,6 +450,8 @@ 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);
|
||||
@@ -342,14 +466,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(
|
||||
®ion->type->headertypes, "BUTTONS_HT_context", offsetof(HeaderType, idname));
|
||||
BLI_remlink(®ion->type->headertypes, context_ht);
|
||||
BLI_addtail(®ion->type->headertypes, context_ht);
|
||||
#endif
|
||||
|
||||
ED_region_header_init(region);
|
||||
}
|
||||
|
||||
@@ -389,10 +505,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)
|
||||
@@ -726,9 +838,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
|
||||
@@ -764,9 +874,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 */
|
||||
|
@@ -687,6 +687,14 @@ enum {
|
||||
/** When the user sets the region is hidden,
|
||||
* needed for floating regions that may be hidden for other reasons. */
|
||||
RGN_FLAG_HIDDEN_BY_USER = (1 << 7),
|
||||
/** Property search filter is active. */
|
||||
RGN_FLAG_SEARCH_FILTER_ACTIVE = (1 << 8),
|
||||
/**
|
||||
* Update the expansion of the region's panels and switch contexts. Only Set
|
||||
* temporarily when the search filter is updated so that interactions are still
|
||||
* interactive, cleared at the end of the region's layout pass.
|
||||
*/
|
||||
RGN_FLAG_SEARCH_FILTER_UPDATE = (1 << 9),
|
||||
};
|
||||
|
||||
/** #ARegion.do_draw */
|
||||
|
@@ -129,6 +129,18 @@ typedef enum eSpaceInfo_RptMask {
|
||||
/** \name Properties Editor
|
||||
* \{ */
|
||||
|
||||
typedef struct SpaceProperties_Runtime {
|
||||
/** For filtering properties displayed in the space. Length defined as UI_MAX_NAME_STR. */
|
||||
char search_string[128];
|
||||
/**
|
||||
* 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;
|
||||
|
||||
char _pad[4];
|
||||
} SpaceProperties_Runtime;
|
||||
|
||||
/* Properties Editor */
|
||||
typedef struct SpaceProperties {
|
||||
SpaceLink *next, *prev;
|
||||
@@ -159,6 +171,9 @@ typedef struct SpaceProperties {
|
||||
ID *pinid;
|
||||
|
||||
void *texuser;
|
||||
|
||||
/* Doesn't necessarily need to be a pointer, but runtime structs are still written to files. */
|
||||
SpaceProperties_Runtime *runtime;
|
||||
} SpaceProperties;
|
||||
|
||||
/* button defines (deprecated) */
|
||||
|
@@ -264,6 +264,9 @@ typedef struct ThemeSpace {
|
||||
/* note, cannot use name 'panel' because of DNA mapping old files */
|
||||
uiPanelColors panelcolors;
|
||||
|
||||
unsigned char search_match_color[4];
|
||||
char _pad2[4];
|
||||
|
||||
unsigned char shade1[4];
|
||||
unsigned char shade2[4];
|
||||
|
||||
|
@@ -1817,6 +1817,17 @@ static void rna_SpaceProperties_context_update(Main *UNUSED(bmain),
|
||||
}
|
||||
}
|
||||
|
||||
static void rna_SpaceProperties_search_filter_update(struct bContext *C,
|
||||
struct PointerRNA *UNUSED(ptr))
|
||||
{
|
||||
ScrArea *area = CTX_wm_area(C);
|
||||
|
||||
/* Update the search filter flag for the main region with the panels. */
|
||||
ARegion *main_region = BKE_area_find_region_type(area, RGN_TYPE_WINDOW);
|
||||
BLI_assert(main_region != NULL);
|
||||
ED_region_search_filter_update(area, main_region);
|
||||
}
|
||||
|
||||
/* Space Console */
|
||||
static void rna_ConsoleLine_body_get(PointerRNA *ptr, char *value)
|
||||
{
|
||||
@@ -4482,6 +4493,25 @@ 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_sdna(prop, NULL, "runtime->context_search_filter_active");
|
||||
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, "search_filter", PROP_STRING, PROP_NONE);
|
||||
RNA_def_property_string_sdna(prop, NULL, "runtime->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_flag(prop, PROP_CONTEXT_UPDATE);
|
||||
RNA_def_property_update(
|
||||
prop, NC_SPACE | ND_SPACE_PROPERTIES, "rna_SpaceProperties_search_filter_update");
|
||||
}
|
||||
|
||||
static void rna_def_space_image(BlenderRNA *brna)
|
||||
|
@@ -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");
|
||||
|
@@ -1718,6 +1718,11 @@ static void rna_def_userdef_theme_space_common(StructRNA *srna)
|
||||
RNA_def_property_ui_text(prop, "Header Text Highlight", "");
|
||||
RNA_def_property_update(prop, 0, "rna_userdef_theme_update");
|
||||
|
||||
prop = RNA_def_property(srna, "search_match_color", PROP_FLOAT, PROP_COLOR_GAMMA);
|
||||
RNA_def_property_array(prop, 3);
|
||||
RNA_def_property_ui_text(prop, "Search Match Color", "");
|
||||
RNA_def_property_update(prop, 0, "rna_userdef_theme_update");
|
||||
|
||||
/* panel settings */
|
||||
prop = RNA_def_property(srna, "panelcolors", PROP_POINTER, PROP_NONE);
|
||||
RNA_def_property_flag(prop, PROP_NEVER_NULL);
|
||||
|
Reference in New Issue
Block a user