diff options
author | Brecht Van Lommel <brechtvanlommel@gmail.com> | 2018-06-03 14:32:36 +0300 |
---|---|---|
committer | Brecht Van Lommel <brechtvanlommel@gmail.com> | 2018-06-03 22:30:35 +0300 |
commit | d7c2b78822ff20fb78418c43d6badd692fa98784 (patch) | |
tree | c1f8b9a0580afc173dd0829615f74a94a3254589 /source/blender | |
parent | 9b01e7bc27c4a8c8c9f95aa074f458f3e734d23b (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.
Diffstat (limited to 'source/blender')
-rw-r--r-- | source/blender/blenkernel/BKE_blender_version.h | 2 | ||||
-rw-r--r-- | source/blender/blenkernel/BKE_screen.h | 7 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/screen.c | 82 | ||||
-rw-r--r-- | source/blender/blenloader/intern/readfile.c | 17 | ||||
-rw-r--r-- | source/blender/blenloader/intern/writefile.c | 13 | ||||
-rw-r--r-- | source/blender/editors/include/UI_interface.h | 9 | ||||
-rw-r--r-- | source/blender/editors/include/UI_resources.h | 1 | ||||
-rw-r--r-- | source/blender/editors/interface/interface.c | 5 | ||||
-rw-r--r-- | source/blender/editors/interface/interface_panel.c | 259 | ||||
-rw-r--r-- | source/blender/editors/interface/resources.c | 13 | ||||
-rw-r--r-- | source/blender/editors/screen/area.c | 143 | ||||
-rw-r--r-- | source/blender/makesdna/DNA_screen_types.h | 5 | ||||
-rw-r--r-- | source/blender/makesdna/DNA_userdef_types.h | 2 | ||||
-rw-r--r-- | source/blender/makesrna/intern/rna_ui.c | 27 | ||||
-rw-r--r-- | source/blender/makesrna/intern/rna_userdef.c | 4 |
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, ®ion->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", ""); |