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

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBrecht Van Lommel <brechtvanlommel@gmail.com>2018-06-03 14:32:36 +0300
committerBrecht Van Lommel <brechtvanlommel@gmail.com>2018-06-03 22:30:35 +0300
commitd7c2b78822ff20fb78418c43d6badd692fa98784 (patch)
treec1f8b9a0580afc173dd0829615f74a94a3254589
parent9b01e7bc27c4a8c8c9f95aa074f458f3e734d23b (diff)
UI: add subpanel support.
In the Python API, any panel becomes a subpanel by setting bl_parent_id to the name of the parent panel. These subpanels can contain advanced or less commonly used settings.
-rw-r--r--source/blender/blenkernel/BKE_blender_version.h2
-rw-r--r--source/blender/blenkernel/BKE_screen.h7
-rw-r--r--source/blender/blenkernel/intern/screen.c82
-rw-r--r--source/blender/blenloader/intern/readfile.c17
-rw-r--r--source/blender/blenloader/intern/writefile.c13
-rw-r--r--source/blender/editors/include/UI_interface.h9
-rw-r--r--source/blender/editors/include/UI_resources.h1
-rw-r--r--source/blender/editors/interface/interface.c5
-rw-r--r--source/blender/editors/interface/interface_panel.c259
-rw-r--r--source/blender/editors/interface/resources.c13
-rw-r--r--source/blender/editors/screen/area.c143
-rw-r--r--source/blender/makesdna/DNA_screen_types.h5
-rw-r--r--source/blender/makesdna/DNA_userdef_types.h2
-rw-r--r--source/blender/makesrna/intern/rna_ui.c27
-rw-r--r--source/blender/makesrna/intern/rna_userdef.c4
15 files changed, 401 insertions, 188 deletions
diff --git a/source/blender/blenkernel/BKE_blender_version.h b/source/blender/blenkernel/BKE_blender_version.h
index 8befeff498e..a1212322983 100644
--- a/source/blender/blenkernel/BKE_blender_version.h
+++ b/source/blender/blenkernel/BKE_blender_version.h
@@ -28,7 +28,7 @@
* and keep comment above the defines.
* Use STRINGIFY() rather than defining with quotes */
#define BLENDER_VERSION 280
-#define BLENDER_SUBVERSION 16
+#define BLENDER_SUBVERSION 17
/* Several breakages with 270, e.g. constraint deg vs rad */
#define BLENDER_MINVERSION 270
#define BLENDER_MINSUBVERSION 6
diff --git a/source/blender/blenkernel/BKE_screen.h b/source/blender/blenkernel/BKE_screen.h
index f284e633c5e..0b95152ad8e 100644
--- a/source/blender/blenkernel/BKE_screen.h
+++ b/source/blender/blenkernel/BKE_screen.h
@@ -205,7 +205,8 @@ typedef struct PanelType {
char translation_context[BKE_ST_MAXNAME];
char context[BKE_ST_MAXNAME]; /* for buttons window */
char category[BKE_ST_MAXNAME]; /* for category tabs */
- char owner_id[BKE_ST_MAXNAME]; /* for work-spaces to selectively show. */
+ char owner_id[BKE_ST_MAXNAME]; /* for work-spaces to selectively show. */
+ char parent_id[BKE_ST_MAXNAME]; /* parent idname for subpanels */
int space_type;
int region_type;
@@ -218,6 +219,10 @@ typedef struct PanelType {
/* draw entirely, view changes should be handled here */
void (*draw)(const struct bContext *C, struct Panel *pa);
+ /* sub panels */
+ struct PanelType *parent;
+ ListBase children;
+
/* RNA integration */
ExtensionRNA ext;
} PanelType;
diff --git a/source/blender/blenkernel/intern/screen.c b/source/blender/blenkernel/intern/screen.c
index ece68884f5c..8cff10902ef 100644
--- a/source/blender/blenkernel/intern/screen.c
+++ b/source/blender/blenkernel/intern/screen.c
@@ -69,13 +69,19 @@ static void spacetype_free(SpaceType *st)
for (art = st->regiontypes.first; art; art = art->next) {
BLI_freelistN(&art->drawcalls);
- for (pt = art->paneltypes.first; pt; pt = pt->next)
- if (pt->ext.free)
+ for (pt = art->paneltypes.first; pt; pt = pt->next) {
+ if (pt->ext.free) {
pt->ext.free(pt->ext.data);
+ }
+
+ BLI_freelistN(&pt->children);
+ }
- for (ht = art->headertypes.first; ht; ht = ht->next)
- if (ht->ext.free)
+ for (ht = art->headertypes.first; ht; ht = ht->next) {
+ if (ht->ext.free) {
ht->ext.free(ht->ext.data);
+ }
+ }
BLI_freelistN(&art->paneltypes);
BLI_freelistN(&art->headertypes);
@@ -169,10 +175,35 @@ void BKE_spacedata_freelist(ListBase *lb)
BLI_freelistN(lb);
}
+static void panel_list_copy(ListBase *newlb, const ListBase *lb)
+{
+ BLI_listbase_clear(newlb);
+ BLI_duplicatelist(newlb, lb);
+
+ /* copy panel pointers */
+ Panel *newpa = newlb->first;
+ Panel *pa = lb->first;
+ for (; newpa; newpa = newpa->next, pa = pa->next) {
+ newpa->activedata = NULL;
+
+ Panel *newpatab = newlb->first;
+ Panel *patab = lb->first;
+ while (newpatab) {
+ if (newpa->paneltab == patab) {
+ newpa->paneltab = newpatab;
+ break;
+ }
+ newpatab = newpatab->next;
+ patab = patab->next;
+ }
+
+ panel_list_copy(&newpa->children, &pa->children);
+ }
+}
+
ARegion *BKE_area_region_copy(SpaceType *st, ARegion *ar)
{
ARegion *newar = MEM_dupallocN(ar);
- Panel *pa, *newpa, *patab;
newar->prev = newar->next = NULL;
BLI_listbase_clear(&newar->handlers);
@@ -199,25 +230,10 @@ ARegion *BKE_area_region_copy(SpaceType *st, ARegion *ar)
if (ar->v2d.tab_offset)
newar->v2d.tab_offset = MEM_dupallocN(ar->v2d.tab_offset);
- BLI_listbase_clear(&newar->panels);
- BLI_duplicatelist(&newar->panels, &ar->panels);
+ panel_list_copy(&newar->panels, &ar->panels);
BLI_listbase_clear(&newar->ui_previews);
BLI_duplicatelist(&newar->ui_previews, &ar->ui_previews);
-
- /* copy panel pointers */
- for (newpa = newar->panels.first; newpa; newpa = newpa->next) {
- patab = newar->panels.first;
- pa = ar->panels.first;
- while (patab) {
- if (newpa->paneltab == pa) {
- newpa->paneltab = patab;
- break;
- }
- patab = patab->next;
- pa = pa->next;
- }
- }
return newar;
}
@@ -329,6 +345,19 @@ void BKE_region_callback_free_manipulatormap_set(void (*callback)(struct wmManip
region_free_manipulatormap_callback = callback;
}
+static void panel_list_free(ListBase *lb)
+{
+ Panel *pa, *pa_next;
+ for (pa = lb->first; pa; pa = pa_next) {
+ pa_next = pa->next;
+ if (pa->activedata) {
+ MEM_freeN(pa->activedata);
+ }
+ panel_list_free(&pa->children);
+ MEM_freeN(pa);
+ }
+}
+
/* not region itself */
void BKE_area_region_free(SpaceType *st, ARegion *ar)
{
@@ -351,16 +380,7 @@ void BKE_area_region_free(SpaceType *st, ARegion *ar)
ar->v2d.tab_offset = NULL;
}
- if (!BLI_listbase_is_empty(&ar->panels)) {
- Panel *pa, *pa_next;
- for (pa = ar->panels.first; pa; pa = pa_next) {
- pa_next = pa->next;
- if (pa->activedata) {
- MEM_freeN(pa->activedata);
- }
- MEM_freeN(pa);
- }
- }
+ panel_list_free(&ar->panels);
for (uilst = ar->ui_lists.first; uilst; uilst = uilst->next) {
if (uilst->dyn_data) {
diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c
index d2542e977e3..b0a1789eb7e 100644
--- a/source/blender/blenloader/intern/readfile.c
+++ b/source/blender/blenloader/intern/readfile.c
@@ -6396,19 +6396,24 @@ static void direct_link_gpencil(FileData *fd, bGPdata *gpd)
/* *********** READ AREA **************** */
-static void direct_link_region(FileData *fd, ARegion *ar, int spacetype)
+static void direct_link_panel_list(FileData *fd, ListBase *lb)
{
- Panel *pa;
- uiList *ui_list;
-
- link_list(fd, &ar->panels);
+ link_list(fd, lb);
- for (pa = ar->panels.first; pa; pa = pa->next) {
+ for (Panel *pa = lb->first; pa; pa = pa->next) {
pa->paneltab = newdataadr(fd, pa->paneltab);
pa->runtime_flag = 0;
pa->activedata = NULL;
pa->type = NULL;
+ direct_link_panel_list(fd, &pa->children);
}
+}
+
+static void direct_link_region(FileData *fd, ARegion *ar, int spacetype)
+{
+ uiList *ui_list;
+
+ direct_link_panel_list(fd, &ar->panels);
link_list(fd, &ar->panels_category_active);
diff --git a/source/blender/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c
index de1699e24b7..fb7b3e47153 100644
--- a/source/blender/blenloader/intern/writefile.c
+++ b/source/blender/blenloader/intern/writefile.c
@@ -2762,14 +2762,19 @@ static void write_soops(WriteData *wd, SpaceOops *so)
}
}
+static void write_panel_list(WriteData *wd, ListBase *lb)
+{
+ for (Panel *pa = lb->first; pa; pa = pa->next) {
+ writestruct(wd, DATA, Panel, 1, pa);
+ write_panel_list(wd, &pa->children);
+ }
+}
+
static void write_area_regions(WriteData *wd, ScrArea *area)
{
for (ARegion *region = area->regionbase.first; region; region = region->next) {
write_region(wd, region, area->spacetype);
-
- for (Panel *pa = region->panels.first; pa; pa = pa->next) {
- writestruct(wd, DATA, Panel, 1, pa);
- }
+ write_panel_list(wd, &region->panels);
for (PanelCategoryStack *pc_act = region->panels_category_active.first; pc_act; pc_act = pc_act->next) {
writestruct(wd, DATA, PanelCategoryStack, 1, pc_act);
diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h
index 5779d6410a8..dc9de9f275f 100644
--- a/source/blender/editors/include/UI_interface.h
+++ b/source/blender/editors/include/UI_interface.h
@@ -491,8 +491,6 @@ void UI_blocklist_update_window_matrix(const struct bContext *C, const struct Li
void UI_blocklist_draw(const struct bContext *C, const struct ListBase *lb);
void UI_block_update_from_old(const struct bContext *C, struct uiBlock *block);
-uiBlock *UI_block_find_in_region(const char *name, struct ARegion *ar);
-
void UI_block_emboss_set(uiBlock *block, char dt);
void UI_block_free(const struct bContext *C, uiBlock *block);
@@ -824,9 +822,10 @@ void UI_panels_begin(const struct bContext *C, struct ARegion *ar);
void UI_panels_end(const struct bContext *C, struct ARegion *ar, int *x, int *y);
void UI_panels_draw(const struct bContext *C, struct ARegion *ar);
-struct Panel *UI_panel_find_by_type(struct ARegion *ar, struct PanelType *pt);
-struct Panel *UI_panel_begin(struct ScrArea *sa, struct ARegion *ar, uiBlock *block,
- struct PanelType *pt, struct Panel *pa, bool *r_open);
+struct Panel *UI_panel_find_by_type(struct ListBase *lb, struct PanelType *pt);
+struct Panel *UI_panel_begin(struct ScrArea *sa, struct ARegion *ar, struct ListBase *lb,
+ uiBlock *block, struct PanelType *pt, struct Panel *pa,
+ bool *r_open);
void UI_panel_end(uiBlock *block, int width, int height);
void UI_panels_scale(struct ARegion *ar, float new_width);
diff --git a/source/blender/editors/include/UI_resources.h b/source/blender/editors/include/UI_resources.h
index b89a57b02d1..f47daf1a963 100644
--- a/source/blender/editors/include/UI_resources.h
+++ b/source/blender/editors/include/UI_resources.h
@@ -74,6 +74,7 @@ typedef enum ThemeColorID {
/* panels */
TH_PANEL_HEADER,
TH_PANEL_BACK,
+ TH_PANEL_SUB_BACK,
TH_PANEL_SHOW_HEADER,
TH_PANEL_SHOW_BACK,
diff --git a/source/blender/editors/interface/interface.c b/source/blender/editors/interface/interface.c
index a9995001659..6cb667cb9a8 100644
--- a/source/blender/editors/interface/interface.c
+++ b/source/blender/editors/interface/interface.c
@@ -2814,11 +2814,6 @@ uiBlock *UI_block_begin(const bContext *C, ARegion *region, const char *name, sh
return block;
}
-uiBlock *UI_block_find_in_region(const char *name, ARegion *ar)
-{
- return BLI_findstring(&ar->uiblocks, name, offsetof(uiBlock, name));
-}
-
void UI_block_emboss_set(uiBlock *block, char dt)
{
block->dt = dt;
diff --git a/source/blender/editors/interface/interface_panel.c b/source/blender/editors/interface/interface_panel.c
index 5711f76e3e9..3847aa72519 100644
--- a/source/blender/editors/interface/interface_panel.c
+++ b/source/blender/editors/interface/interface_panel.c
@@ -110,6 +110,7 @@ typedef struct uiHandlePanelData {
int startsizex, startsizey;
} uiHandlePanelData;
+static int get_panel_real_size_y(Panel *pa);
static void panel_activate_state(const bContext *C, Panel *pa, uiHandlePanelState state);
/*********************** space specific code ************************/
@@ -133,45 +134,80 @@ static int panel_aligned(ScrArea *sa, ARegion *ar)
return 0;
}
-static int panels_re_align(ScrArea *sa, ARegion *ar, Panel **r_pa)
+static bool panel_active_animation_changed(ListBase *lb, Panel **pa_animation, bool *no_animation)
{
- Panel *pa;
- int active = 0;
+ for (Panel *pa = lb->first; pa; pa = pa->next) {
+ /* Detect panel active flag changes. */
+ if (!(pa->type && pa->type->parent)) {
+ if ((pa->runtime_flag & PNL_WAS_ACTIVE) && !(pa->runtime_flag & PNL_ACTIVE)) {
+ return true;
+ }
+ if (!(pa->runtime_flag & PNL_WAS_ACTIVE) && (pa->runtime_flag & PNL_ACTIVE)) {
+ return true;
+ }
+ }
- *r_pa = NULL;
+ if ((pa->runtime_flag & PNL_ACTIVE) && !(pa->flag & PNL_CLOSED)) {
+ if (panel_active_animation_changed(&pa->children, pa_animation, no_animation)) {
+ return true;
+ }
+ }
+
+ /* Detect animation. */
+ if (pa->activedata) {
+ uiHandlePanelData *data = pa->activedata;
+ if (data->state == PANEL_STATE_ANIMATION) {
+ *pa_animation = pa;
+ }
+ else {
+ /* Don't animate while handling other interaction. */
+ *no_animation = true;
+ }
+ }
+ if ((pa->runtime_flag & PNL_ANIM_ALIGN) && !(*pa_animation)) {
+ *pa_animation = pa;
+ }
+ }
+
+ return false;
+}
+
+static bool panels_need_realign(ScrArea *sa, ARegion *ar, Panel **pa_animate)
+{
+ *pa_animate = NULL;
if (sa->spacetype == SPACE_BUTS && ar->regiontype == RGN_TYPE_WINDOW) {
SpaceButs *sbuts = sa->spacedata.first;
- if (sbuts->align)
- if (sbuts->re_align || sbuts->mainbo != sbuts->mainb)
- return 1;
+ if (sbuts->align) {
+ if (sbuts->re_align || sbuts->mainbo != sbuts->mainb) {
+ return true;
+ }
+ }
+ }
+ else if (sa->spacetype == SPACE_IMAGE && ar->regiontype == RGN_TYPE_PREVIEW) {
+ return true;
+ }
+ else if (sa->spacetype == SPACE_FILE && ar->regiontype == RGN_TYPE_CHANNELS) {
+ return true;
}
- else if (sa->spacetype == SPACE_IMAGE && ar->regiontype == RGN_TYPE_PREVIEW)
- return 1;
- else if (sa->spacetype == SPACE_FILE && ar->regiontype == RGN_TYPE_CHANNELS)
- return 1;
- /* in case panel is added or disappears */
- for (pa = ar->panels.first; pa; pa = pa->next) {
- if ((pa->runtime_flag & PNL_WAS_ACTIVE) && !(pa->runtime_flag & PNL_ACTIVE))
- return 1;
- if (!(pa->runtime_flag & PNL_WAS_ACTIVE) && (pa->runtime_flag & PNL_ACTIVE))
- return 1;
- if (pa->activedata)
- active = 1;
+ /* Detect if a panel was added or removed. */
+ Panel *pa_animation = NULL;
+ bool no_animation = false;
+ if (panel_active_animation_changed(&ar->panels, &pa_animation, &no_animation)) {
+ return true;
}
- /* in case we need to do an animation (size changes) */
- for (pa = ar->panels.first; pa; pa = pa->next) {
- if (pa->runtime_flag & PNL_ANIM_ALIGN) {
- if (!active)
- *r_pa = pa;
- return 1;
+ /* Detect panel marked for animation, if we're not already animating. */
+ if (pa_animation) {
+ if (!no_animation) {
+ *pa_animate = pa_animation;
}
+ return true;
}
- return 0;
+ return false;
}
/****************************** panels ******************************/
@@ -215,14 +251,14 @@ static void ui_panel_copy_offset(Panel *pa, Panel *papar)
*/
/* #define UI_USE_PANELTAB */
-Panel *UI_panel_find_by_type(ARegion *ar, PanelType *pt)
+Panel *UI_panel_find_by_type(ListBase *lb, PanelType *pt)
{
Panel *pa;
const char *idname = pt->idname;
#ifdef UI_USE_PANELTAB
const char *tabname = pt->idname;
- for (pa = ar->panels.first; pa; pa = pa->next) {
+ for (pa = lb->first; pa; pa = pa->next) {
if (STREQLEN(pa->panelname, idname, sizeof(pa->panelname))) {
if (STREQLEN(pa->tabname, tabname, sizeof(pa->tabname))) {
return pa;
@@ -230,7 +266,7 @@ Panel *UI_panel_find_by_type(ARegion *ar, PanelType *pt)
}
}
#else
- for (pa = ar->panels.first; pa; pa = pa->next) {
+ for (pa = lb->first; pa; pa = pa->next) {
if (STREQLEN(pa->panelname, idname, sizeof(pa->panelname))) {
return pa;
}
@@ -243,7 +279,7 @@ Panel *UI_panel_find_by_type(ARegion *ar, PanelType *pt)
/**
* \note \a pa should be return value from #UI_panel_find_by_type and can be NULL.
*/
-Panel *UI_panel_begin(ScrArea *sa, ARegion *ar, uiBlock *block, PanelType *pt, Panel *pa, bool *r_open)
+Panel *UI_panel_begin(ScrArea *sa, ARegion *ar, ListBase *lb, uiBlock *block, PanelType *pt, Panel *pa, bool *r_open)
{
Panel *palast, *panext;
const char *drawname = CTX_IFACE_(pt->translation_context, pt->label);
@@ -275,9 +311,11 @@ Panel *UI_panel_begin(ScrArea *sa, ARegion *ar, uiBlock *block, PanelType *pt, P
pa->ofsy = 0;
pa->sizex = 0;
pa->sizey = 0;
+ pa->blocksizex = 0;
+ pa->blocksizey = 0;
pa->runtime_flag |= PNL_NEW_ADDED;
- BLI_addtail(&ar->panels, pa);
+ BLI_addtail(lb, pa);
#ifdef UI_USE_PANELTAB
BLI_strncpy(pa->tabname, tabname, sizeof(pa->tabname));
@@ -285,7 +323,7 @@ Panel *UI_panel_begin(ScrArea *sa, ARegion *ar, uiBlock *block, PanelType *pt, P
/* make new Panel tabbed? */
if (hookname) {
Panel *patab;
- for (patab = ar->panels.first; patab; patab = patab->next) {
+ for (patab = lb->first; patab; patab = patab->next) {
if ((patab->runtime_flag & PNL_ACTIVE) && patab->paneltab == NULL) {
if (STREQLEN(hookname, patab->panelname, sizeof(patab->panelname))) {
if (STREQLEN(tabname, patab->tabname, sizeof(patab->tabname))) {
@@ -308,6 +346,8 @@ Panel *UI_panel_begin(ScrArea *sa, ARegion *ar, uiBlock *block, PanelType *pt, P
/* Force update of panels' positions! */
pa->sizex = 0;
pa->sizey = 0;
+ pa->blocksizex = 0;
+ pa->blocksizey = 0;
}
BLI_strncpy(pa->drawname, drawname, sizeof(pa->drawname));
@@ -315,14 +355,18 @@ Panel *UI_panel_begin(ScrArea *sa, ARegion *ar, uiBlock *block, PanelType *pt, P
/* if a new panel is added, we insert it right after the panel
* that was last added. this way new panels are inserted in the
* right place between versions */
- for (palast = ar->panels.first; palast; palast = palast->next)
- if (palast->runtime_flag & PNL_LAST_ADDED)
+ for (palast = lb->first; palast; palast = palast->next) {
+ if (palast->runtime_flag & PNL_LAST_ADDED) {
+ BLI_remlink(lb, pa);
+ BLI_insertlinkafter(lb, palast, pa);
break;
+ }
+ }
if (newpanel) {
pa->sortorder = (palast) ? palast->sortorder + 1 : 0;
- for (panext = ar->panels.first; panext; panext = panext->next)
+ for (panext = lb->first; panext; panext = panext->next)
if (panext != pa && panext->sortorder >= pa->sortorder)
panext->sortorder++;
}
@@ -348,6 +392,19 @@ void UI_panel_end(uiBlock *block, int width, int height)
{
Panel *pa = block->panel;
+ /* Set panel size excluding children. */
+ pa->blocksizex = width;
+ pa->blocksizey = height;
+
+ /* Compute total panel size including children. */
+ for (Panel *pachild = pa->children.first; pachild; pachild = pachild->next) {
+ if (pachild->runtime_flag & PNL_ACTIVE) {
+ width = max_ii(width, pachild->sizex);
+ height += get_panel_real_size_y(pachild);
+ }
+ }
+
+ /* Update total panel size. */
if (pa->runtime_flag & PNL_NEW_ADDED) {
pa->runtime_flag &= ~PNL_NEW_ADDED;
pa->sizex = width;
@@ -372,15 +429,13 @@ void UI_panel_end(uiBlock *block, int width, int height)
static void ui_offset_panel_block(uiBlock *block)
{
uiStyle *style = UI_style_get_dpi();
- uiBut *but;
- int ofsy;
/* compute bounds and offset */
ui_block_bounds_calc(block);
- ofsy = block->panel->sizey - style->panelspace;
+ int ofsy = block->panel->sizey - style->panelspace;
- for (but = block->buttons.first; but; but = but->next) {
+ for (uiBut *but = block->buttons.first; but; but = but->next) {
but->rect.ymin += ofsy;
but->rect.ymax += ofsy;
}
@@ -600,6 +655,8 @@ void ui_draw_aligned_panel(uiStyle *style, uiBlock *block, const rcti *rect, con
float color[4];
const bool is_closed_x = (panel->flag & PNL_CLOSEDX) ? true : false;
const bool is_closed_y = (panel->flag & PNL_CLOSEDY) ? true : false;
+ const bool is_subpanel = (panel->type && panel->type->parent);
+ const bool show_drag = !is_subpanel;
if (panel->paneltab) return;
if (panel->type && (panel->type->flag & PNL_NO_HEADER)) return;
@@ -613,7 +670,7 @@ void ui_draw_aligned_panel(uiStyle *style, uiBlock *block, const rcti *rect, con
unsigned int pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
- {
+ if (!is_subpanel) {
float minx = rect->xmin;
float maxx = is_closed_x ? (minx + PNL_HEADER / block->aspect) : rect->xmax;
float y = headrect.ymax;
@@ -681,25 +738,28 @@ void ui_draw_aligned_panel(uiStyle *style, uiBlock *block, const rcti *rect, con
/* horizontal title */
if (is_closed_x == false) {
- unsigned int col;
ui_draw_aligned_panel_header(style, block, &headrect, 'h');
- Gwn_VertFormat *format = immVertexFormat();
- pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
- col = GWN_vertformat_attr_add(format, "color", GWN_COMP_F32, 4, GWN_FETCH_FLOAT);
-
- /* itemrect smaller */
- itemrect.xmax = headrect.xmax - 5.0f / block->aspect;
- itemrect.xmin = itemrect.xmax - BLI_rcti_size_y(&headrect);
- itemrect.ymin = headrect.ymin;
- itemrect.ymax = headrect.ymax;
-
- BLI_rctf_scale(&itemrect, 0.7f);
- immBindBuiltinProgram(GPU_SHADER_2D_FLAT_COLOR);
- ui_draw_panel_dragwidget(pos, col, &itemrect);
- immUnbindProgram();
- /* Restore format for the following draws. */
- pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
+ if (show_drag) {
+ unsigned int col;
+ Gwn_VertFormat *format = immVertexFormat();
+ pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
+ col = GWN_vertformat_attr_add(format, "color", GWN_COMP_F32, 4, GWN_FETCH_FLOAT);
+
+ /* itemrect smaller */
+ itemrect.xmax = headrect.xmax - 5.0f / block->aspect;
+ itemrect.xmin = itemrect.xmax - BLI_rcti_size_y(&headrect);
+ itemrect.ymin = headrect.ymin;
+ itemrect.ymax = headrect.ymax;
+
+ BLI_rctf_scale(&itemrect, 0.7f);
+ immBindBuiltinProgram(GPU_SHADER_2D_FLAT_COLOR);
+ ui_draw_panel_dragwidget(pos, col, &itemrect);
+ immUnbindProgram();
+
+ /* Restore format for the following draws. */
+ pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
+ }
}
/* if the panel is minimized vertically:
@@ -727,8 +787,12 @@ void ui_draw_aligned_panel(uiStyle *style, uiBlock *block, const rcti *rect, con
immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
/* panel backdrop */
- if (UI_GetThemeValue(TH_PANEL_SHOW_BACK)) {
- /* draw with background color */
+ if (is_subpanel) {
+ glEnable(GL_BLEND);
+ immUniformThemeColor(TH_PANEL_SUB_BACK);
+ immRectf(pos, rect->xmin, rect->ymin, rect->xmax, rect->ymax);
+ }
+ else if (UI_GetThemeValue(TH_PANEL_SHOW_BACK)) {
glEnable(GL_BLEND);
immUniformThemeColor(TH_PANEL_BACK);
immRectf(pos, rect->xmin, rect->ymin, rect->xmax, rect->ymax);
@@ -786,6 +850,16 @@ static int get_panel_size_y(Panel *pa)
return PNL_HEADER + pa->sizey;
}
+static int get_panel_real_size_y(Panel *pa)
+{
+ int sizey = (pa->flag & PNL_CLOSED) ? 0 : pa->sizey;
+
+ if (pa->type && (pa->type->flag & PNL_NO_HEADER))
+ return sizey;
+
+ return PNL_HEADER + sizey;
+}
+
/* this function is needed because uiBlock and Panel itself don't
* change sizey or location when closed */
static int get_panel_real_ofsy(Panel *pa)
@@ -858,6 +932,24 @@ static int compare_panel(const void *a1, const void *a2)
return 0;
}
+static void align_sub_panels(Panel *pa)
+{
+ /* Position sub panels. */
+ int ofsy = get_panel_real_ofsy(pa) + pa->sizey - pa->blocksizey;
+
+ for (Panel *pachild = pa->children.first; pachild; pachild = pachild->next) {
+ if (pachild->runtime_flag & PNL_ACTIVE) {
+ pachild->ofsx = pa->ofsx;
+ pachild->ofsy = ofsy - get_panel_size_y(pachild);
+ ofsy -= get_panel_real_size_y(pachild);
+
+ if (pachild->children.first) {
+ align_sub_panels(pachild);
+ }
+ }
+ }
+}
+
/* this doesnt draw */
/* returns 1 when it did something */
static bool uiAlignPanelStep(ScrArea *sa, ARegion *ar, const float fac, const bool drag)
@@ -949,10 +1041,17 @@ static bool uiAlignPanelStep(ScrArea *sa, ARegion *ar, const float fac, const bo
}
}
- /* copy locations to tabs */
- for (pa = ar->panels.first; pa; pa = pa->next)
- if (pa->paneltab && (pa->runtime_flag & PNL_ACTIVE))
- ui_panel_copy_offset(pa, pa->paneltab);
+ /* set locations for tabbed and sub panels */
+ for (pa = ar->panels.first; pa; pa = pa->next) {
+ if (pa->runtime_flag & PNL_ACTIVE) {
+ if (pa->paneltab) {
+ ui_panel_copy_offset(pa, pa->paneltab);
+ }
+ if (pa->children.first) {
+ align_sub_panels(pa);
+ }
+ }
+ }
/* free panelsort array */
for (ps = panelsort, a = 0; a < tot; a++, ps++) {
@@ -1022,20 +1121,27 @@ static void ui_do_animate(const bContext *C, Panel *panel)
}
}
-void UI_panels_begin(const bContext *UNUSED(C), ARegion *ar)
+static void panel_list_clear_active(ListBase *lb)
{
- Panel *pa;
-
/* set all panels as inactive, so that at the end we know
* which ones were used */
- for (pa = ar->panels.first; pa; pa = pa->next) {
- if (pa->runtime_flag & PNL_ACTIVE)
+ for (Panel *pa = lb->first; pa; pa = pa->next) {
+ if (pa->runtime_flag & PNL_ACTIVE) {
pa->runtime_flag = PNL_WAS_ACTIVE;
- else
+ }
+ else {
pa->runtime_flag = 0;
+ }
+
+ panel_list_clear_active(&pa->children);
}
}
+void UI_panels_begin(const bContext *UNUSED(C), ARegion *ar)
+{
+ panel_list_clear_active(&ar->panels);
+}
+
/* only draws blocks with panels */
void UI_panels_end(const bContext *C, ARegion *ar, int *x, int *y)
{
@@ -1074,8 +1180,7 @@ void UI_panels_end(const bContext *C, ARegion *ar, int *x, int *y)
}
/* re-align, possibly with animation */
- if (panels_re_align(sa, ar, &pa)) {
- /* XXX code never gets here... PNL_ANIM_ALIGN flag is never set */
+ if (panels_need_realign(sa, ar, &pa)) {
if (pa)
panel_activate_state(C, pa, PANEL_STATE_ANIMATION);
else
@@ -1102,14 +1207,16 @@ void UI_panels_draw(const bContext *C, ARegion *ar)
UI_ThemeClearColor(TH_BACK);
- /* draw panels, selected on top */
- for (block = ar->uiblocks.first; block; block = block->next) {
+ /* 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. */
+ for (block = ar->uiblocks.last; block; block = block->prev) {
if (block->active && block->panel && !(block->panel->flag & PNL_SELECT)) {
UI_block_draw(C, block);
}
}
- for (block = ar->uiblocks.first; block; block = block->next) {
+ for (block = ar->uiblocks.last; block; block = block->prev) {
if (block->active && block->panel && (block->panel->flag & PNL_SELECT)) {
UI_block_draw(C, block);
}
@@ -1371,6 +1478,8 @@ static void ui_handle_panel_header(const bContext *C, uiBlock *block, int mx, in
#else
const bool show_pin = UI_panel_category_is_visible(ar);
#endif
+ const bool is_subpanel = (block->panel->type && block->panel->type->parent);
+ const bool show_drag = !is_subpanel;
int align = panel_aligned(sa, ar), button = 0;
@@ -1465,7 +1574,7 @@ static void ui_handle_panel_header(const bContext *C, uiBlock *block, int mx, in
else
ED_region_tag_redraw(ar);
}
- else if (BLI_rctf_isect_x(&rect_drag, mx)) {
+ else if (show_drag && BLI_rctf_isect_x(&rect_drag, mx)) {
panel_activate_state(C, block->panel, PANEL_STATE_DRAG);
}
else if (show_pin && BLI_rctf_isect_x(&rect_pin, mx)) {
diff --git a/source/blender/editors/interface/resources.c b/source/blender/editors/interface/resources.c
index 8e5bf8f0323..1bfb050563d 100644
--- a/source/blender/editors/interface/resources.c
+++ b/source/blender/editors/interface/resources.c
@@ -254,6 +254,8 @@ const unsigned char *UI_ThemeGetColorPtr(bTheme *btheme, int spacetype, int colo
cp = ts->panelcolors.header; break;
case TH_PANEL_BACK:
cp = ts->panelcolors.back; break;
+ case TH_PANEL_SUB_BACK:
+ cp = ts->panelcolors.sub_back; break;
case TH_PANEL_SHOW_HEADER:
cp = &setting;
setting = ts->panelcolors.show_header;
@@ -821,6 +823,7 @@ static void ui_theme_init_new_do(ThemeSpace *ts)
ts->panelcolors.show_header = false;
rgba_char_args_set(ts->panelcolors.back, 114, 114, 114, 128);
rgba_char_args_set(ts->panelcolors.header, 0, 0, 0, 25);
+ rgba_char_args_set(ts->panelcolors.sub_back, 0, 0, 0, 25);
rgba_char_args_set(ts->button, 145, 145, 145, 245);
rgba_char_args_set(ts->button_title, 0, 0, 0, 255);
@@ -3022,6 +3025,16 @@ void init_userdef_do_versions(void)
}
}
+ if (!USER_VERSION_ATLEAST(280, 17)) {
+ for (bTheme *btheme = U.themes.first; btheme; btheme = btheme->next) {
+ ThemeSpace *ts;
+
+ for (ts = UI_THEMESPACE_START(btheme); ts != UI_THEMESPACE_END(btheme); ts++) {
+ rgba_char_args_set(ts->panelcolors.sub_back, 0, 0, 0, 25);
+ }
+ }
+ }
+
/**
* Include next version bump.
*/
diff --git a/source/blender/editors/screen/area.c b/source/blender/editors/screen/area.c
index 2491c9f57de..b295d3a0fed 100644
--- a/source/blender/editors/screen/area.c
+++ b/source/blender/editors/screen/area.c
@@ -1806,6 +1806,84 @@ BLI_INLINE bool streq_array_any(const char *s, const char *arr[])
return false;
}
+static void ed_panel_draw(const bContext *C,
+ ScrArea *sa,
+ ARegion *ar,
+ ListBase *lb,
+ PanelType *pt,
+ Panel *panel,
+ int w,
+ int em,
+ bool vertical)
+{
+ uiStyle *style = UI_style_get_dpi();
+
+ /* draw panel */
+ uiBlock *block = UI_block_begin(C, ar, pt->idname, UI_EMBOSS);
+
+ bool open;
+ panel = UI_panel_begin(sa, ar, lb, block, pt, panel, &open);
+
+ /* bad fixed values */
+ int triangle = (int)(UI_UNIT_Y * 1.1f);
+ int xco, yco, h = 0;
+
+ if (pt->draw_header && !(pt->flag & PNL_NO_HEADER) && (open || vertical)) {
+ /* for enabled buttons */
+ panel->layout = UI_block_layout(
+ block, UI_LAYOUT_HORIZONTAL, UI_LAYOUT_HEADER,
+ triangle, (UI_UNIT_Y * 1.1f) + style->panelspace, UI_UNIT_Y, 1, 0, style);
+
+ pt->draw_header(C, panel);
+
+ UI_block_layout_resolve(block, &xco, &yco);
+ panel->labelofs = xco - triangle;
+ panel->layout = NULL;
+ }
+ else {
+ panel->labelofs = 0;
+ }
+
+ if (open) {
+ short panelContext;
+
+ /* panel context can either be toolbar region or normal panels region */
+ if (ar->regiontype == RGN_TYPE_TOOLS)
+ panelContext = UI_LAYOUT_TOOLBAR;
+ else
+ panelContext = UI_LAYOUT_PANEL;
+
+ panel->layout = UI_block_layout(
+ block, UI_LAYOUT_VERTICAL, panelContext,
+ style->panelspace, 0, w - 2 * style->panelspace, em, 0, style);
+
+ pt->draw(C, panel);
+
+ UI_block_layout_resolve(block, &xco, &yco);
+ panel->layout = NULL;
+
+ if (yco != 0) {
+ h = -yco + 2 * style->panelspace;
+ }
+ }
+
+ UI_block_end(C, block);
+
+ /* Draw child panels. */
+ if (open) {
+ for (LinkData *link = pt->children.first; link; link = link->next) {
+ 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, sa, ar, &panel->children, child_pt, child_panel, w, em, vertical);
+ }
+ }
+ }
+
+ UI_panel_end(block, w, h);
+}
+
/**
* \param contexts: A NULL terminated array of context strings to match against.
* Matching against any of these strings will draw the panel.
@@ -1815,13 +1893,10 @@ void ED_region_panels(const bContext *C, ARegion *ar, const char *contexts[], in
{
const WorkSpace *workspace = CTX_wm_workspace(C);
ScrArea *sa = CTX_wm_area(C);
- uiStyle *style = UI_style_get_dpi();
- uiBlock *block;
PanelType *pt;
- Panel *panel;
View2D *v2d = &ar->v2d;
View2DScrollers *scrollers;
- int x, y, xco, yco, w, em, triangle;
+ int x, y, w, em;
bool is_context_new = 0;
int scroll;
@@ -1859,6 +1934,11 @@ void ED_region_panels(const bContext *C, ARegion *ar, const char *contexts[], in
/* collect panels to draw */
for (pt = ar->type->paneltypes.last; pt; pt = pt->prev) {
+ /* Only draw top level panels. */
+ if (pt->parent) {
+ continue;
+ }
+
/* verify context */
if (contexts && pt->context[0] && !streq_array_any(pt->context, contexts)) {
continue;
@@ -1920,9 +2000,7 @@ void ED_region_panels(const bContext *C, ARegion *ar, const char *contexts[], in
BLI_SMALLSTACK_ITER_BEGIN(pt_stack, pt)
{
- bool open;
-
- panel = UI_panel_find_by_type(ar, pt);
+ Panel *panel = UI_panel_find_by_type(&ar->panels, pt);
if (use_category_tabs && pt->category[0] && !STREQ(category, pt->category)) {
if ((panel == NULL) || ((panel->flag & PNL_PIN) == 0)) {
@@ -1930,56 +2008,7 @@ void ED_region_panels(const bContext *C, ARegion *ar, const char *contexts[], in
}
}
- /* draw panel */
- block = UI_block_begin(C, ar, pt->idname, UI_EMBOSS);
- panel = UI_panel_begin(sa, ar, block, pt, panel, &open);
-
- /* bad fixed values */
- triangle = (int)(UI_UNIT_Y * 1.1f);
-
- if (pt->draw_header && !(pt->flag & PNL_NO_HEADER) && (open || vertical)) {
- /* for enabled buttons */
- panel->layout = UI_block_layout(
- block, UI_LAYOUT_HORIZONTAL, UI_LAYOUT_HEADER,
- triangle, (UI_UNIT_Y * 1.1f) + style->panelspace, UI_UNIT_Y, 1, 0, style);
-
- pt->draw_header(C, panel);
-
- UI_block_layout_resolve(block, &xco, &yco);
- panel->labelofs = xco - triangle;
- panel->layout = NULL;
- }
- else {
- panel->labelofs = 0;
- }
-
- if (open) {
- short panelContext;
-
- /* panel context can either be toolbar region or normal panels region */
- if (ar->regiontype == RGN_TYPE_TOOLS)
- panelContext = UI_LAYOUT_TOOLBAR;
- else
- panelContext = UI_LAYOUT_PANEL;
-
- panel->layout = UI_block_layout(
- block, UI_LAYOUT_VERTICAL, panelContext,
- style->panelspace, 0, w - 2 * style->panelspace, em, 0, style);
-
- pt->draw(C, panel);
-
- UI_block_layout_resolve(block, &xco, &yco);
- panel->layout = NULL;
-
- yco -= 2 * style->panelspace;
- UI_panel_end(block, w, -yco);
- }
- else {
- yco = 0;
- UI_panel_end(block, w, 0);
- }
-
- UI_block_end(C, block);
+ ed_panel_draw(C, sa, ar, &ar->panels, pt, panel, w, em, vertical);
}
BLI_SMALLSTACK_ITER_END;
diff --git a/source/blender/makesdna/DNA_screen_types.h b/source/blender/makesdna/DNA_screen_types.h
index 7849c05e48b..9213893ae66 100644
--- a/source/blender/makesdna/DNA_screen_types.h
+++ b/source/blender/makesdna/DNA_screen_types.h
@@ -121,7 +121,9 @@ typedef struct Panel { /* the part from uiBlock that needs saved in file */
char panelname[64], tabname[64]; /* defined as UI_MAX_NAME_STR */
char drawname[64]; /* panelname is identifier for restoring location */
- int ofsx, ofsy, sizex, sizey;
+ int ofsx, ofsy; /* offset within the region */
+ int sizex, sizey; /* panel size including children */
+ int blocksizex, blocksizey; /* panel size excluding children */
short labelofs, pad;
short flag, runtime_flag;
short control;
@@ -129,6 +131,7 @@ typedef struct Panel { /* the part from uiBlock that needs saved in file */
int sortorder; /* panels are aligned according to increasing sortorder */
struct Panel *paneltab; /* this panel is tabbed in *paneltab */
void *activedata; /* runtime for panel manipulation */
+ ListBase children; /* sub panels */
} Panel;
diff --git a/source/blender/makesdna/DNA_userdef_types.h b/source/blender/makesdna/DNA_userdef_types.h
index 9817d44c96b..468436668b7 100644
--- a/source/blender/makesdna/DNA_userdef_types.h
+++ b/source/blender/makesdna/DNA_userdef_types.h
@@ -150,9 +150,9 @@ typedef struct uiWidgetStateColors {
typedef struct uiPanelColors {
char header[4];
char back[4];
+ char sub_back[4];
short show_header;
short show_back;
- int pad;
} uiPanelColors;
typedef struct uiGradientColors {
diff --git a/source/blender/makesrna/intern/rna_ui.c b/source/blender/makesrna/intern/rna_ui.c
index 173eaf56f0c..354fa43367e 100644
--- a/source/blender/makesrna/intern/rna_ui.c
+++ b/source/blender/makesrna/intern/rna_ui.c
@@ -179,6 +179,12 @@ static void rna_Panel_unregister(Main *UNUSED(bmain), StructRNA *type)
RNA_struct_free_extension(type, &pt->ext);
RNA_struct_free(&BLENDER_RNA, type);
+ if (pt->parent) {
+ LinkData *link = BLI_findptr(&pt->parent->children, pt, offsetof(LinkData, data));
+ BLI_freelinkN(&pt->parent->children, link);
+ }
+
+ BLI_freelistN(&pt->children);
BLI_freelinkN(&art->paneltypes, pt);
/* update while blender is running */
@@ -190,7 +196,7 @@ static StructRNA *rna_Panel_register(
StructValidateFunc validate, StructCallbackFunc call, StructFreeFunc free)
{
ARegionType *art;
- PanelType *pt, dummypt = {NULL};
+ PanelType *pt, *parent = NULL, dummypt = {NULL};
Panel dummypanel = {NULL};
PointerRNA dummyptr;
int have_function[3];
@@ -229,6 +235,10 @@ static StructRNA *rna_Panel_register(
BLI_freelinkN(&art->paneltypes, pt);
break;
}
+
+ if (dummypt.parent_id[0] && STREQ(pt->idname, dummypt.parent_id)) {
+ parent = pt;
+ }
}
if (!RNA_struct_available_or_report(reports, dummypt.idname)) {
return NULL;
@@ -236,6 +246,11 @@ static StructRNA *rna_Panel_register(
if (!RNA_struct_bl_idname_ok_or_report(reports, dummypt.idname, "_PT_")) {
return NULL;
}
+ if (dummypt.parent_id[0] && !parent) {
+ BKE_reportf(reports, RPT_ERROR, "Registering panel class: parent '%s' for '%s' not found",
+ dummypt.parent_id, dummypt.idname);
+ return NULL;
+ }
/* create a new panel type */
pt = MEM_callocN(sizeof(PanelType), "python buttons panel");
@@ -267,6 +282,11 @@ static StructRNA *rna_Panel_register(
else
BLI_addtail(&art->paneltypes, pt);
+ if (parent) {
+ pt->parent = parent;
+ BLI_addtail(&parent->children, BLI_genericNodeN(pt));
+ }
+
{
const char *owner_id = RNA_struct_state_owner_get();
if (owner_id) {
@@ -1102,6 +1122,11 @@ static void rna_def_panel(BlenderRNA *brna)
RNA_def_property_flag(prop, PROP_REGISTER_OPTIONAL | PROP_ENUM_FLAG);
RNA_def_property_ui_text(prop, "Options", "Options for this panel type");
+ prop = RNA_def_property(srna, "bl_parent_id", PROP_STRING, PROP_NONE);
+ RNA_def_property_string_sdna(prop, NULL, "type->parent_id");
+ RNA_def_property_flag(prop, PROP_REGISTER_OPTIONAL);
+ RNA_def_property_ui_text(prop, "Parent ID Name", "If this is set, the panel becomes a subpanel");
+
prop = RNA_def_property(srna, "use_pin", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", PNL_PIN);
RNA_def_property_ui_text(prop, "Pin", "");
diff --git a/source/blender/makesrna/intern/rna_userdef.c b/source/blender/makesrna/intern/rna_userdef.c
index fef4cc3ed8e..fc7a0ca6301 100644
--- a/source/blender/makesrna/intern/rna_userdef.c
+++ b/source/blender/makesrna/intern/rna_userdef.c
@@ -902,6 +902,10 @@ static void rna_def_userdef_theme_ui_panel(BlenderRNA *brna)
prop = RNA_def_property(srna, "back", PROP_FLOAT, PROP_COLOR_GAMMA);
RNA_def_property_ui_text(prop, "Background", "");
RNA_def_property_update(prop, 0, "rna_userdef_update");
+
+ prop = RNA_def_property(srna, "sub_back", PROP_FLOAT, PROP_COLOR_GAMMA);
+ RNA_def_property_ui_text(prop, "Sub Background", "");
+ RNA_def_property_update(prop, 0, "rna_userdef_update");
prop = RNA_def_property(srna, "show_header", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_ui_text(prop, "Show Header", "");