diff options
42 files changed, 1869 insertions, 530 deletions
diff --git a/release/scripts/startup/bl_ui/space_userpref.py b/release/scripts/startup/bl_ui/space_userpref.py index 75381a2356e..7a44689e448 100644 --- a/release/scripts/startup/bl_ui/space_userpref.py +++ b/release/scripts/startup/bl_ui/space_userpref.py @@ -72,7 +72,7 @@ class USERPREF_HT_header(Header): class USERPREF_PT_tabs(Panel): bl_label = "" bl_space_type = 'USER_PREFERENCES' - bl_region_type = 'WINDOW' + bl_region_type = 'TABS' bl_options = {'HIDE_HEADER'} def draw(self, context): @@ -80,7 +80,7 @@ class USERPREF_PT_tabs(Panel): userpref = context.user_preferences - layout.prop(userpref, "active_section", expand=True) + layout.prop_tabs(userpref, "active_section") class USERPREF_MT_interaction_presets(Menu): @@ -625,6 +625,8 @@ class USERPREF_PT_theme(Panel): subsub.active = widget_style.show_shaded subsub.prop(widget_style, "shadetop") subsub.prop(widget_style, "shadedown") + subsub = colsub.column(align=True) + subsub.prop(widget_style, "roundness") layout.separator() @@ -685,6 +687,14 @@ class USERPREF_PT_theme(Panel): col = split.column() ui = theme.user_interface + row = col.row() + subsplit = row.split(percentage=0.47) + subsplit.prop(ui, "interface_style") + + col.separator() + col.separator() + col.separator() + col.label(text="Regular:") self._theme_widget_style(col, ui.wcol_regular) @@ -799,6 +809,7 @@ class USERPREF_PT_theme(Panel): colsub = padding.column() colsub = padding.column() colsub.row().prop(ui, "widget_emboss") + colsub.row().prop(ui, "area_edges") col.separator() col.separator() diff --git a/release/scripts/startup/bl_ui/space_view3d.py b/release/scripts/startup/bl_ui/space_view3d.py index bb0ad001c34..7cca831257a 100644 --- a/release/scripts/startup/bl_ui/space_view3d.py +++ b/release/scripts/startup/bl_ui/space_view3d.py @@ -1345,7 +1345,8 @@ class VIEW3D_MT_object_specials(Menu): props.input_scale = 0.05 props.header_text = "Clip End: %.2f" - layout.separator() + if obj.type in {'CAMERA', 'CURVE', 'FONT', 'EMPTY', 'LAMP'}: + layout.separator() props = layout.operator("object.isolate_type_render") props = layout.operator("object.hide_render_clear_all") diff --git a/source/blender/blenloader/intern/versioning_270.c b/source/blender/blenloader/intern/versioning_270.c index fabef392601..3bf24d3574f 100644 --- a/source/blender/blenloader/intern/versioning_270.c +++ b/source/blender/blenloader/intern/versioning_270.c @@ -868,7 +868,49 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main) } } } + { + bScreen *screen; + for (screen = main->screen.first; screen; screen = screen->id.next) { + ScrArea *sa; + + for (sa = screen->areabase.first; sa; sa = sa->next) { + const char needed_type = (sa->spacetype == SPACE_CLIP) ? RGN_TYPE_PREVIEW : RGN_TYPE_WINDOW; + ARegion *ar = BKE_area_find_region_type(sa, needed_type); + SpaceLink *sl; + + if (ar == NULL) + continue; + + for (sl = sa->spacedata.first; sl; sl = sl->next) { + switch (sl->spacetype) { + case SPACE_TIME: + case SPACE_ACTION: + case SPACE_NLA: + ar->v2d.flag |= V2D_USES_UNITS_HORIZONTAL; + break; + case SPACE_IPO: + case SPACE_SEQ: + ar->v2d.flag |= (V2D_USES_UNITS_HORIZONTAL | V2D_USES_UNITS_VERTICAL); + break; + case SPACE_CLIP: + { + SpaceClip *sc = (SpaceClip *)sl; + if (sc->view == SC_VIEW_DOPESHEET) { + ar->v2d.flag |= V2D_USES_UNITS_HORIZONTAL; + } + else if (sc->view == SC_VIEW_GRAPH) { + ar->v2d.flag |= (V2D_USES_UNITS_HORIZONTAL | V2D_USES_UNITS_VERTICAL); + } + break; + } + default: + break; + } + } + } + } + } { if (!DNA_struct_elem_find(fd->filesdna, "SpaceNode", "float", "backdrop_zoom")) { bScreen *sc; diff --git a/source/blender/blenloader/intern/versioning_defaults.c b/source/blender/blenloader/intern/versioning_defaults.c index 01af11e78d1..c32b3ac51cf 100644 --- a/source/blender/blenloader/intern/versioning_defaults.c +++ b/source/blender/blenloader/intern/versioning_defaults.c @@ -52,6 +52,8 @@ */ void BLO_update_defaults_userpref_blend(void) { + uiStyle *style; + /* defaults from T37518 */ U.uiflag |= USER_ZBUF_CURSOR; @@ -60,6 +62,13 @@ void BLO_update_defaults_userpref_blend(void) U.versions = 1; U.savetime = 2; + + U.dpi = 78; + + for (style = U.uistyles.first; style; style = style->next) { + style->paneltitle.points = style->widgetlabel.points = style->widget.points = 10; + style->paneltitle.shadow = style->widgetlabel.shadow = 0; + } } /** diff --git a/source/blender/editors/armature/pose_group.c b/source/blender/editors/armature/pose_group.c index 4d9df06f33f..465fda71837 100644 --- a/source/blender/editors/armature/pose_group.c +++ b/source/blender/editors/armature/pose_group.c @@ -164,7 +164,9 @@ static int pose_groups_menu_invoke(bContext *C, wmOperator *op, const wmEvent *U */ if (strstr(op->idname, "assign")) { uiItemIntO(layout, "New Group", ICON_NONE, op->idname, "type", 0); - uiItemS(layout); + if (!BLI_listbase_is_empty(&pose->agroups)) { + uiItemS(layout); + } } /* add entries for each group */ diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h index 6320724967c..8125ab4297e 100644 --- a/source/blender/editors/include/UI_interface.h +++ b/source/blender/editors/include/UI_interface.h @@ -135,8 +135,9 @@ enum { /* block->flag bits 14-17 are identical to but->drawflag bits */ -#define UI_BLOCK_LIST_ITEM (1 << 19) -#define UI_BLOCK_RADIAL (1 << 20) +#define UI_BLOCK_LIST_ITEM (1 << 19) +#define UI_BLOCK_RADIAL (1 << 20) +#define UI_BLOCK_HAS_SUBMENU (1 << 21) /* the block has at least one button leading to a submenu */ /* uiPopupBlockHandle->menuretval */ #define UI_RETURN_CANCEL (1 << 0) /* cancel all menus cascading */ @@ -181,13 +182,17 @@ enum { UI_BUT_TIP_FORCE = (1 << 28), /* force show tooltips when holding option/alt if U's USER_TOOLTIPS is off */ UI_BUT_TEXTEDIT_UPDATE = (1 << 29), /* when widget is in textedit mode, update value on each char stroke */ UI_BUT_SEARCH_UNLINK = (1 << 30), /* show unlink for search button */ + UI_BUT_MENU_TITLE = (1 << 31), /* title of a menu - XXX maybe new BTYPE? */ }; #define UI_PANEL_WIDTH 340 #define UI_COMPACT_PANEL_WIDTH 160 +#define UI_PANEL_MARGIN (U.widget_unit * 0.25f) #define UI_PANEL_CATEGORY_MARGIN_WIDTH (U.widget_unit * 1.0f) +#define UI_TAB_REGION_MARGIN_HEIGHT (U.widget_unit * 1.15f) + /* but->drawflag - these flags should only affect how the button is drawn. */ /* Note: currently, these flags _are not passed_ to the widget's state() or draw() functions * (except for the 'align' ones)! @@ -249,6 +254,7 @@ typedef enum { UI_BTYPE_CHECKBOX = (13 << 9), /* similar to toggle, display a 'tick' */ UI_BTYPE_CHECKBOX_N = (14 << 9), UI_BTYPE_COLOR = (15 << 9), + UI_BTYPE_TAB = (16 << 9), UI_BTYPE_SCROLL = (18 << 9), UI_BTYPE_BLOCK = (19 << 9), UI_BTYPE_LABEL = (20 << 9), @@ -634,6 +640,7 @@ int UI_icon_from_report_type(int type); uiBut *uiDefPulldownBut(uiBlock *block, uiBlockCreateFunc func, void *arg, const char *str, int x, int y, short width, short height, const char *tip); uiBut *uiDefMenuBut(uiBlock *block, uiMenuCreateFunc func, void *arg, const char *str, int x, int y, short width, short height, const char *tip); +uiBut *uiDefMenuTitleBut(uiBlock *block, const char *str); uiBut *uiDefIconTextMenuBut(uiBlock *block, uiMenuCreateFunc func, void *arg, int icon, const char *str, int x, int y, short width, short height, const char *tip); uiBut *uiDefIconMenuBut(uiBlock *block, uiMenuCreateFunc func, void *arg, int icon, int x, int y, short width, short height, const char *tip); @@ -961,6 +968,7 @@ void uiItemEnumR_prop(uiLayout *layout, const char *name, int icon, struct Point void uiItemEnumR(uiLayout *layout, const char *name, int icon, struct PointerRNA *ptr, const char *propname, int value); void uiItemEnumR_string(uiLayout *layout, struct PointerRNA *ptr, const char *propname, const char *value, const char *name, int icon); void uiItemsEnumR(uiLayout *layout, struct PointerRNA *ptr, const char *propname); +void uiItemTabsR(uiLayout *layout, struct PointerRNA *ptr, struct PropertyRNA *prop, const char *name, int icon, int alignment, int icon_only); void uiItemPointerR(uiLayout *layout, struct PointerRNA *ptr, const char *propname, struct PointerRNA *searchptr, const char *searchpropname, const char *name, int icon); void uiItemsFullEnumO(uiLayout *layout, const char *opname, const char *propname, struct IDProperty *properties, int context, int flag); diff --git a/source/blender/editors/include/UI_resources.h b/source/blender/editors/include/UI_resources.h index 2b19b6180e5..20115468ef8 100644 --- a/source/blender/editors/include/UI_resources.h +++ b/source/blender/editors/include/UI_resources.h @@ -55,6 +55,9 @@ enum { TH_REDALERT, TH_THEMEUI, + + TH_AREA_EDGES, + // common colors among spaces TH_BACK, diff --git a/source/blender/editors/include/UI_view2d.h b/source/blender/editors/include/UI_view2d.h index 4caacb65f5f..7335233a215 100644 --- a/source/blender/editors/include/UI_view2d.h +++ b/source/blender/editors/include/UI_view2d.h @@ -103,8 +103,10 @@ enum eView2D_Gridlines { /* ------ Defines for Scrollers ----- */ /* scroller area */ -#define V2D_SCROLL_HEIGHT (0.85f * U.widget_unit) -#define V2D_SCROLL_WIDTH (0.85f * U.widget_unit) +#define V2D_SCROLL_HEIGHT (0.50f * U.widget_unit) +#define V2D_SCROLL_WIDTH (0.50f * U.widget_unit) +#define V2D_SCROLL_HEIGHT_TEXT (0.85f * U.widget_unit) +#define V2D_SCROLL_WIDTH_TEXT (0.85f * U.widget_unit) /* scroller 'handles' hotspot radius for mouse */ #define V2D_SCROLLER_HANDLE_SIZE (0.6f * U.widget_unit) diff --git a/source/blender/editors/interface/interface.c b/source/blender/editors/interface/interface.c index 1fccf0fb2d0..0ee4a30d005 100644 --- a/source/blender/editors/interface/interface.c +++ b/source/blender/editors/interface/interface.c @@ -161,6 +161,13 @@ void ui_block_to_window_rctf(const ARegion *ar, uiBlock *block, rctf *rct_dst, c ui_block_to_window_fl(ar, block, &rct_dst->xmax, &rct_dst->ymax); } +void ui_block_to_window_rcti(const ARegion *ar, uiBlock *block, rcti *rct_dst, const rcti *rct_src) +{ + *rct_dst = *rct_src; + ui_block_to_window(ar, block, &rct_dst->xmin, &rct_dst->ymin); + ui_block_to_window(ar, block, &rct_dst->xmax, &rct_dst->ymax); +} + void ui_window_to_block_fl(const ARegion *ar, uiBlock *block, float *x, float *y) /* for mouse cursor */ { float a, b, c, d, e, f, px, py; @@ -1327,6 +1334,42 @@ static void ui_but_to_pixelrect(rcti *rect, const ARegion *ar, uiBlock *block, u BLI_rcti_translate(rect, -ar->winrct.xmin, -ar->winrct.ymin); } +/* project a rcti to pixels in regionspace */ +void ui_rcti_to_pixelrect(const ARegion *ar, uiBlock *block, rcti *rct_dst, const rcti *rct_src) +{ + rcti rect; + + ui_block_to_window_rcti(ar, block, &rect, rct_src); + + rect.xmin -= ar->winrct.xmin; + rect.ymin -= ar->winrct.ymin; + rect.xmax -= ar->winrct.xmin; + rect.ymax -= ar->winrct.ymin; + + rct_dst->xmin = iroundf(rect.xmin); + rct_dst->ymin = iroundf(rect.ymin); + rct_dst->xmax = iroundf(rect.xmax); + rct_dst->ymax = iroundf(rect.ymax); +} + +/* project a rctf to pixels in regionspace */ +void ui_rctf_to_pixelrect(const ARegion *ar, uiBlock *block, rctf *rct_dst, const rctf *rct_src) +{ + rctf rect; + + ui_block_to_window_rctf(ar, block, &rect, rct_src); + + rect.xmin -= ar->winrct.xmin; + rect.ymin -= ar->winrct.ymin; + rect.xmax -= ar->winrct.xmin; + rect.ymax -= ar->winrct.ymin; + + rct_dst->xmin = floorf(rect.xmin); + rct_dst->ymin = floorf(rect.ymin); + rct_dst->xmax = floorf(rect.xmax); + rct_dst->ymax = floorf(rect.ymax); +} + /* uses local copy of style, to scale things down, and allow widgets to change stuff */ void UI_block_draw(const bContext *C, uiBlock *block) { @@ -1448,6 +1491,7 @@ int ui_but_is_pushed_ex(uiBut *but, double *value) break; case UI_BTYPE_ROW: case UI_BTYPE_LISTROW: + case UI_BTYPE_TAB: UI_GET_BUT_VALUE_INIT(but, *value); /* support for rna enum buts */ if (but->rnaprop && (RNA_property_flag(but->rnaprop) & PROP_ENUM_FLAG)) { @@ -2273,6 +2317,12 @@ static void ui_but_string_set_internal(uiBut *but, const char *str, size_t str_l memcpy(but->str, str, str_len); } +static void ui_but_submenu_enable(uiBlock *block, uiBut *but) +{ + but->flag |= UI_BUT_ICON_SUBMENU; + block->flag |= UI_BLOCK_HAS_SUBMENU; +} + static void ui_but_string_free_internal(uiBut *but) { if (but->str) { @@ -2564,6 +2614,10 @@ static void ui_but_free(const bContext *C, uiBut *but) MEM_freeN(but->dragpoin); } + if ((BLI_listbase_is_empty(&but->subbuts)) == false) { + BLI_freelistN(&but->subbuts); + } + BLI_assert(UI_butstore_is_registered(but->block, but) == false); MEM_freeN(but); @@ -2973,6 +3027,9 @@ static void ui_block_align_calc_but(uiBut *first, short nr) /* note; how it uses 'flag' in loop below (either set it, or OR it) is confusing */ for (but = first, prev = NULL; but && but->alignnr == nr; prev = but, but = but->next) { + if (but->type == UI_BTYPE_TAB) + continue; + next = but->next; if (next && next->alignnr != nr) next = NULL; @@ -3154,6 +3211,25 @@ void ui_block_cm_to_display_space_range(uiBlock *block, float *min, float *max) *max = max_fff(UNPACK3(pixel)); } +static uiSubBut *ui_def_subbut( + uiBut *but, const int type, + uiSubButAlign alignment, + const int width, const int height) +{ + uiSubBut *sbut = MEM_callocN(sizeof(uiSubBut), "uiSubBut"); + + sbut->type = type; + sbut->align = alignment; + sbut->width = width; + sbut->height = height; + + /* sbut->rect is calculated later */ + + BLI_addtail(&but->subbuts, sbut); + + return sbut; +} + /** * \brief ui_def_but is the function that draws many button types * @@ -3268,6 +3344,13 @@ static uiBut *ui_def_but( } } + if (but->type == UI_BTYPE_NUM) { + const int sbut_width = MIN2(width / 3, height); + + ui_def_subbut(but, UI_SBUT_TYPE_VAL_DECREASE, UI_SBUT_ALIGN_LEFT, sbut_width, height); + ui_def_subbut(but, UI_SBUT_TYPE_VAL_INCREASE, UI_SBUT_ALIGN_RIGHT, sbut_width, height); + } + /* keep track of UI_interface.h */ if (ELEM(but->type, UI_BTYPE_BLOCK, UI_BTYPE_BUT, UI_BTYPE_LABEL, @@ -3306,7 +3389,7 @@ void ui_def_but_icon(uiBut *but, const int icon, const int flag) but->flag |= flag; if (but->str && but->str[0]) { - but->drawflag |= UI_BUT_ICON_LEFT; + but->drawflag |= (UI_BUT_ICON_LEFT | UI_BUT_TEXT_LEFT); } } @@ -3369,9 +3452,7 @@ static void ui_def_but_rna__menu(bContext *UNUSED(C), uiLayout *layout, void *bu rows++; /* Title */ - uiDefBut(block, UI_BTYPE_LABEL, 0, RNA_property_ui_name(but->rnaprop), - 0, 0, UI_UNIT_X * 5, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, ""); - uiItemS(layout); + uiDefMenuTitleBut(block, RNA_property_ui_name(but->rnaprop)); /* note, item_array[...] is reversed on access */ @@ -3577,7 +3658,7 @@ static uiBut *ui_def_but_rna( } if ((type == UI_BTYPE_MENU) && (but->dt == UI_EMBOSS_PULLDOWN)) { - but->flag |= UI_BUT_ICON_SUBMENU; + ui_but_submenu_enable(block, but); } if (!RNA_property_editable(&but->rnapoin, prop)) { @@ -4310,6 +4391,17 @@ uiBut *uiDefMenuBut(uiBlock *block, uiMenuCreateFunc func, void *arg, const char return but; } +uiBut *uiDefMenuTitleBut(uiBlock *block, const char *str) +{ + uiBut *but = ui_def_but(block, UI_BTYPE_LABEL, 0, str, 0, 0, UI_MENU_TITLE_WIDTH, UI_MENU_TITLE_HEIGHT, + NULL, 0.0, 0.0, 0.0, 0.0, ""); + but->flag |= UI_BUT_MENU_TITLE; + + ui_but_update(but); + + return but; +} + uiBut *uiDefIconTextMenuBut(uiBlock *block, uiMenuCreateFunc func, void *arg, int icon, const char *str, int x, int y, short width, short height, const char *tip) { uiBut *but = ui_def_but(block, UI_BTYPE_PULLDOWN, 0, str, x, y, width, height, arg, 0.0, 0.0, 0.0, 0.0, tip); @@ -4317,7 +4409,7 @@ uiBut *uiDefIconTextMenuBut(uiBlock *block, uiMenuCreateFunc func, void *arg, in ui_def_but_icon(but, icon, UI_HAS_ICON); but->drawflag |= UI_BUT_ICON_LEFT; - but->flag |= UI_BUT_ICON_SUBMENU; + ui_but_submenu_enable(block, but); but->menu_create_func = func; ui_but_update(but); @@ -4349,7 +4441,7 @@ uiBut *uiDefIconTextBlockBut(uiBlock *block, uiBlockCreateFunc func, void *arg, but->drawflag |= UI_BUT_ICON_LEFT; } but->flag |= UI_HAS_ICON; - but->flag |= UI_BUT_ICON_SUBMENU; + ui_but_submenu_enable(block, but); but->block_create_func = func; ui_but_update(but); diff --git a/source/blender/editors/interface/interface_draw.c b/source/blender/editors/interface/interface_draw.c index 66140742e26..968b3ea1934 100644 --- a/source/blender/editors/interface/interface_draw.c +++ b/source/blender/editors/interface/interface_draw.c @@ -403,6 +403,93 @@ void UI_draw_text_underline(int pos_x, int pos_y, int len, int height) /* ************** SPECIAL BUTTON DRAWING FUNCTIONS ************* */ +void ui_draw_but_TAB_outline(rcti *rect, float rad, int roundboxtype, unsigned char highlight[3], + unsigned char highlight_fade[3]) +{ + float vec[4][2] = { + {0.195, 0.02}, + {0.55, 0.169}, + {0.831, 0.45}, + {0.98, 0.805}, + }; + int a; + /* the 1px offset makes sure its inside the button, because it doesn't draw nicely outside */ + int minx = rect->xmin + 1, maxx = rect->xmax - 1; + int miny = rect->ymin + 1, maxy = rect->ymax - 1; + + /* mult */ + for (a = 0; a < 4; a++) { + mul_v2_fl(vec[a], rad); + } + + glEnable(GL_LINE_SMOOTH); + glEnable(GL_BLEND); + glShadeModel(GL_SMOOTH); + glBegin(GL_LINE_STRIP); + + glColor3ubv(highlight); + + /*start with corner left-top*/ + if (roundboxtype & UI_CNR_TOP_LEFT) { + glVertex2f(minx, maxy - rad); + for (a = 0; a < 4; a++) { + glVertex2f(minx + vec[a][1], maxy - rad + vec[a][0]); + } + glVertex2f(minx + rad, maxy); + } + else { + glVertex2f(minx, maxy); + } + + /* corner right-top */ + if (roundboxtype & UI_CNR_TOP_RIGHT) { + glVertex2f(maxx - rad, maxy); + for (a = 0; a < 4; a++) { + glVertex2f(maxx - rad + vec[a][0], maxy - vec[a][1]); + } + glVertex2f(maxx, maxy - rad); + } + else { + glVertex2f(maxx, maxy); + } + + glColor3ubv(highlight_fade); + + /* corner right-bottom */ + if (roundboxtype & UI_CNR_BOTTOM_RIGHT) { + glVertex2f(maxx, miny + rad); + for (a = 0; a < 4; a++) { + glVertex2f(maxx - vec[a][1], miny + rad - vec[a][0]); + } + glVertex2f(maxx - rad, miny); + } + else { + glVertex2f(maxx, miny); + } + + /* corner left-bottom */ + if (roundboxtype & UI_CNR_BOTTOM_LEFT) { + glVertex2f(minx + rad, miny); + for (a = 0; a < 4; a++) { + glVertex2f(minx + rad - vec[a][0], miny + vec[a][1]); + } + glVertex2f(minx, miny + rad); + } + else { + glVertex2f(minx, miny); + } + + glColor3ubv(highlight); + + /* back to corner left-top */ + glVertex2f(minx, roundboxtype & UI_CNR_TOP_LEFT ? maxy - rad : maxy); + + glEnd(); + glShadeModel(GL_FLAT); + glDisable(GL_BLEND); + glDisable(GL_LINE_SMOOTH); +} + void ui_draw_but_IMAGE(ARegion *UNUSED(ar), uiBut *but, uiWidgetColors *UNUSED(wcol), const rcti *rect) { #ifdef WITH_HEADLESS diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c index 010bb8b37f1..b2688619e7a 100644 --- a/source/blender/editors/interface/interface_handlers.c +++ b/source/blender/editors/interface/interface_handlers.c @@ -384,6 +384,7 @@ static bool ui_but_contains_pt(uiBut *but, float mx, float my); static bool ui_but_contains_point_px(ARegion *ar, uiBut *but, int x, int y); static uiBut *ui_but_find_mouse_over_ex(ARegion *ar, const int x, const int y, const bool labeledit); static uiBut *ui_but_find_mouse_over(ARegion *ar, const wmEvent *event); +static uiSubBut *ui_subbut_find_mouse_over(const ARegion *ar, const uiBut *but, const int mouse_xy[2]); static void button_activate_init(bContext *C, ARegion *ar, uiBut *but, uiButtonActivateType type); static void button_activate_state(bContext *C, uiBut *but, uiHandleButtonState state); static void button_activate_exit( @@ -2055,6 +2056,7 @@ static void ui_apply_but(bContext *C, uiBlock *block, uiBut *but, uiHandleButton break; case UI_BTYPE_ROW: case UI_BTYPE_LISTROW: + case UI_BTYPE_TAB: ui_apply_but_ROW(C, block, but, data); break; case UI_BTYPE_SCROLL: @@ -3726,6 +3728,17 @@ static int ui_do_but_KEYEVT(bContext *C, uiBut *but, uiHandleButtonData *data, c return WM_UI_HANDLER_CONTINUE; } +static int ui_do_but_TAB(bContext *C, uiBut *but, uiHandleButtonData *data, const wmEvent *event) { + if (data->state == BUTTON_STATE_HIGHLIGHT) { + if (ELEM(event->type, LEFTMOUSE, PADENTER, RETKEY) && event->val == KM_RELEASE) { + button_activate_state(C, but, BUTTON_STATE_EXIT); + return WM_UI_HANDLER_CONTINUE; + } + } + + return WM_UI_HANDLER_CONTINUE; +} + static int ui_do_but_TEX(bContext *C, uiBlock *block, uiBut *but, uiHandleButtonData *data, const wmEvent *event) { if (data->state == BUTTON_STATE_HIGHLIGHT) { @@ -4266,68 +4279,8 @@ static int ui_do_but_NUM(bContext *C, uiBlock *block, uiBut *but, uiHandleButton } if (click) { - /* we can click on the side arrows to increment/decrement, - * or click inside to edit the value directly */ - float tempf, softmin, softmax; - float handlewidth; - int temp; - - softmin = but->softmin; - softmax = but->softmax; - - handlewidth = min_ff(BLI_rctf_size_x(&but->rect) / 3, BLI_rctf_size_y(&but->rect)); - - if (!ui_but_is_float(but)) { - if (mx < (but->rect.xmin + handlewidth)) { - button_activate_state(C, but, BUTTON_STATE_NUM_EDITING); - - temp = (int)data->value - 1; - if (temp >= softmin && temp <= softmax) - data->value = (double)temp; - else - data->cancel = true; - - button_activate_state(C, but, BUTTON_STATE_EXIT); - } - else if (mx > (but->rect.xmax - handlewidth)) { - button_activate_state(C, but, BUTTON_STATE_NUM_EDITING); - - temp = (int)data->value + 1; - if (temp >= softmin && temp <= softmax) - data->value = (double)temp; - else - data->cancel = true; - - button_activate_state(C, but, BUTTON_STATE_EXIT); - } - else { - button_activate_state(C, but, BUTTON_STATE_TEXT_EDITING); - } - } - else { - if (mx < (but->rect.xmin + handlewidth)) { - button_activate_state(C, but, BUTTON_STATE_NUM_EDITING); - - tempf = (float)data->value - (UI_PRECISION_FLOAT_SCALE * but->a1); - if (tempf < softmin) tempf = softmin; - data->value = tempf; - - button_activate_state(C, but, BUTTON_STATE_EXIT); - } - else if (mx > but->rect.xmax - handlewidth) { - button_activate_state(C, but, BUTTON_STATE_NUM_EDITING); - - tempf = (float)data->value + (UI_PRECISION_FLOAT_SCALE * but->a1); - if (tempf > softmax) tempf = softmax; - data->value = tempf; - - button_activate_state(C, but, BUTTON_STATE_EXIT); - } - else { - button_activate_state(C, but, BUTTON_STATE_TEXT_EDITING); - } - } - + /* start textediting - clicking to increase/decrease numbers is handled via sub-buttons */ + button_activate_state(C, but, BUTTON_STATE_TEXT_EDITING); retval = WM_UI_HANDLER_BREAK; } @@ -4337,6 +4290,40 @@ static int ui_do_but_NUM(bContext *C, uiBlock *block, uiBut *but, uiHandleButton return retval; } +static int ui_do_subbut_NUM(bContext *C, uiBut *but, const uiSubBut *sbut, const wmEvent *event) +{ + uiHandleButtonData *data = but->active; + const float softmin = but->softmin; + const float softmax = but->softmax; + const bool is_float = ui_but_is_float(but); + const bool increase = (sbut->type == UI_SBUT_TYPE_VAL_INCREASE); + float tempf; + int temp; + + if (event->type != LEFTMOUSE || event->val != KM_RELEASE || data->dragchange) + return WM_UI_HANDLER_CONTINUE; + + button_activate_state(C, but, BUTTON_STATE_NUM_EDITING); + + if (is_float) { + tempf = (float)data->value + (increase ? 0.01f : -0.01f) * but->a1; + CLAMP(tempf, softmin, softmax); + data->value = tempf; + } + else { + temp = (int)data->value + (increase ? 1 : -1); + if (IN_RANGE_INCL(temp, softmin, softmax)) + data->value = (double)temp; + else + data->cancel = true; + } + + button_activate_state(C, but, BUTTON_STATE_EXIT); + + /* always break */ + return WM_UI_HANDLER_BREAK; +} + static bool ui_numedit_but_SLI( uiBut *but, uiHandleButtonData *data, int mx, const bool is_horizontal, @@ -6502,6 +6489,7 @@ static bool ui_but_menu(bContext *C, uiBut *but) uiPopupMenu *pup; uiLayout *layout; bool is_array, is_array_component; + bool is_first_item = true; /* will the next added item be the first menu entry? */ uiStringInfo label = {BUT_GET_LABEL, NULL}; /* if ((but->rnapoin.data && but->rnaprop) == 0 && but->optype == NULL)*/ @@ -6524,6 +6512,9 @@ static bool ui_but_menu(bContext *C, uiBut *but) uiLayoutSetOperatorContext(layout, WM_OP_INVOKE_DEFAULT); + /* adds a separator if it wouldn't be the first item (after title) */ +#define ADD_SEPARATOR_CONDITIONAL if (is_first_item == false) uiItemS(layout); + if (but->rnapoin.data && but->rnaprop) { PointerRNA *ptr = &but->rnapoin; PropertyRNA *prop = but->rnaprop; @@ -6563,7 +6554,7 @@ static bool ui_but_menu(bContext *C, uiBut *but) /* keyframe settings */ uiItemS(layout); - + is_first_item = false; } else if (but->flag & UI_BUT_DRIVEN) { /* pass */ @@ -6579,6 +6570,8 @@ static bool ui_but_menu(bContext *C, uiBut *but) uiItemBooleanO(layout, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Insert Keyframe"), ICON_NONE, "ANIM_OT_keyframe_insert_button", "all", 1); } + + is_first_item = false; } if ((but->flag & UI_BUT_ANIMATED) && (but->rnapoin.type != &RNA_NlaStrip)) { @@ -6592,11 +6585,13 @@ static bool ui_but_menu(bContext *C, uiBut *but) uiItemBooleanO(layout, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Clear Keyframes"), ICON_NONE, "ANIM_OT_keyframe_clear_button", "all", 1); } + + is_first_item = false; } /* Drivers */ if (but->flag & UI_BUT_DRIVEN) { - uiItemS(layout); + ADD_SEPARATOR_CONDITIONAL if (is_array_component) { uiItemBooleanO(layout, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Delete Drivers"), @@ -6615,12 +6610,14 @@ static bool ui_but_menu(bContext *C, uiBut *but) uiItemO(layout, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Paste Driver"), ICON_NONE, "ANIM_OT_paste_driver_button"); } + + is_first_item = false; } else if (but->flag & (UI_BUT_ANIMATED_KEY | UI_BUT_ANIMATED)) { /* pass */ } else if (is_anim) { - uiItemS(layout); + ADD_SEPARATOR_CONDITIONAL if (is_array_component) { uiItemBooleanO(layout, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Add Drivers"), @@ -6637,12 +6634,14 @@ static bool ui_but_menu(bContext *C, uiBut *but) uiItemO(layout, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Paste Driver"), ICON_NONE, "ANIM_OT_paste_driver_button"); } + + is_first_item = false; } /* Keying Sets */ /* TODO: check on modifyability of Keying Set when doing this */ if (is_anim) { - uiItemS(layout); + ADD_SEPARATOR_CONDITIONAL if (is_array_component) { uiItemBooleanO(layout, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Add All to Keying Set"), @@ -6658,10 +6657,12 @@ static bool ui_but_menu(bContext *C, uiBut *but) uiItemO(layout, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Remove from Keying Set"), ICON_NONE, "ANIM_OT_keyingset_button_remove"); } + + is_first_item = false; } - - uiItemS(layout); - + + ADD_SEPARATOR_CONDITIONAL + /* Property Operators */ /* Copy Property Value @@ -6729,6 +6730,8 @@ static bool ui_but_menu(bContext *C, uiBut *but) "please use User Preferences otherwise")); UI_but_flag_enable(but2, UI_BUT_DISABLED); } + + is_first_item = false; } /* only show 'add' if there's a suitable key map for it to go in */ else if (WM_keymap_guess_opname(C, but->optype->idname)) { @@ -6736,11 +6739,15 @@ static bool ui_but_menu(bContext *C, uiBut *but) CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Add Shortcut"), 0, 0, w, UI_UNIT_Y, NULL, 0, 0, 0, 0, ""); UI_but_func_set(but2, popup_add_shortcut_func, but, NULL); + + is_first_item = false; } - - uiItemS(layout); + + ADD_SEPARATOR_CONDITIONAL } +#undef ADD_SEPARATOR_CONDITIONAL + /* Show header tools for header buttons. */ if (ui_block_is_menu(but->block) == false) { ARegion *ar = CTX_wm_region(C); @@ -6785,8 +6792,33 @@ static bool ui_but_menu(bContext *C, uiBut *but) return true; } +static int ui_do_but_subbut(bContext *C, uiBut *but, uiSubBut *sbut, const wmEvent *event) +{ + int retval = WM_UI_HANDLER_CONTINUE; + + BLI_assert(sbut->is_hovered); + + switch (but->type) { + case UI_BTYPE_NUM: + retval = ui_do_subbut_NUM(C, but, sbut, event); + break; + default: + break; + } + + if (retval == WM_UI_HANDLER_BREAK) { + BLI_assert(ui_but_contains_point_px(CTX_wm_region(C), but, event->x, event->y)); + button_activate_exit(C, but, but->active, true, false); + /* reactivate highlight state */ + button_activate_init(C, CTX_wm_region(C), but, BUTTON_ACTIVATE_OVER); + } + + return retval; +} + static int ui_do_button(bContext *C, uiBlock *block, uiBut *but, const wmEvent *event) { + uiSubBut *sbut; uiHandleButtonData *data; int retval; @@ -6930,6 +6962,16 @@ static int ui_do_button(bContext *C, uiBlock *block, uiBut *but, const wmEvent * } } + sbut = ui_subbut_find_mouse_over(CTX_wm_region(C), but, &event->x); + + if (sbut) { + retval = ui_do_but_subbut(C, but, sbut, event); + + if (retval == WM_UI_HANDLER_BREAK) { + return retval; + } + } + switch (but->type) { case UI_BTYPE_BUT: retval = ui_do_but_BUT(C, but, data, event); @@ -6940,6 +6982,9 @@ static int ui_do_button(bContext *C, uiBlock *block, uiBut *but, const wmEvent * case UI_BTYPE_HOTKEY_EVENT: retval = ui_do_but_HOTKEYEVT(C, but, data, event); break; + case UI_BTYPE_TAB: + retval = ui_do_but_TAB(C, but, data, event); + break; case UI_BTYPE_BUT_TOGGLE: case UI_BTYPE_TOGGLE: case UI_BTYPE_ICON_TOGGLE: @@ -7204,6 +7249,24 @@ uiBut *ui_but_find_active_in_region(ARegion *ar) return NULL; } +uiBut *ui_but_find_activated_tab(const ARegion *ar) +{ + uiBlock *block; + uiBut *but; + + if (ar->regiontype == RGN_TYPE_TABS) { + for (block = ar->uiblocks.first; block; block = block->next) { + for (but = block->buttons.first; but; but = but->next) { + if (but->type == UI_BTYPE_TAB && but->flag & UI_SELECT) { + return but; + } + } + } + } + + return NULL; +} + bool ui_but_is_active(ARegion *ar) { return (ui_but_find_active_in_region(ar) != NULL); @@ -7408,6 +7471,26 @@ static uiBut *ui_but_find_mouse_over(ARegion *ar, const wmEvent *event) } +static uiSubBut *ui_subbut_find_mouse_over(const ARegion *ar, const uiBut *but, const int mouse_xy[2]) +{ + uiSubBut *sbut; + float mx = mouse_xy[0]; + float my = mouse_xy[1]; + + /* XXX (julian) */ +// BLI_assert(ui_but_contains_point_px(ar, but, UNPACK2(mouse_xy))); + + ui_window_to_block_fl(ar, but->block, &mx, &my); + + for (sbut = but->subbuts.first; sbut; sbut = sbut->next) { + if (BLI_rcti_isect_x(&sbut->rect, mx)) { + return sbut; + } + } + return NULL; +} + + static uiBut *ui_list_find_mouse_over_ex(ARegion *ar, int x, int y) { uiBlock *block; @@ -8095,6 +8178,31 @@ static void ui_handle_button_activate(bContext *C, ARegion *ar, uiBut *but, uiBu /************ handle events for an activated button ***********/ +static void ui_handle_but_subbuts(ARegion *ar, const uiBut *but, const int mouse_xy[2]) +{ + uiSubBut *sbut = ui_subbut_find_mouse_over(ar, but, mouse_xy); + bool changed = false; + + if (sbut) { + if (sbut->is_hovered == false) { + sbut->is_hovered = true; + changed = true; + } + } + else { + for (sbut = but->subbuts.first; sbut; sbut = sbut->next) { + if (sbut->is_hovered) { + sbut->is_hovered = false; + changed = true; + } + } + } + + if (changed) { + ED_region_tag_redraw(ar); + } +} + static int ui_handle_button_event(bContext *C, const wmEvent *event, uiBut *but) { uiHandleButtonData *data = but->active; @@ -8141,6 +8249,10 @@ static int ui_handle_button_event(bContext *C, const wmEvent *event, uiBut *but) button_tooltip_timer_reset(C, but); } + if (BLI_listbase_is_empty(&but->subbuts) == false) { + ui_handle_but_subbuts(ar, but, &event->x); + } + break; } case TIMER: @@ -9669,6 +9781,46 @@ static int ui_handle_menus_recursive( /* *************** UI event handlers **************** */ +static int ui_tab_region_handler(bContext *C, const wmEvent *event, ARegion *ar) +{ + ScrArea *sa = CTX_wm_area(C); + + if (ELEM(event->type, WHEELUPMOUSE, WHEELDOWNMOUSE)) { + uiBut *nextbut, *but = NULL; + + if (ar->regiontype == RGN_TYPE_TABS); + else if ((sa->flag & AREA_CONTAINS_TABS) && event->ctrl) + ar = BKE_area_find_region_type(sa, RGN_TYPE_TABS); + else + return WM_UI_HANDLER_CONTINUE; + + but = ui_but_find_activated_tab(ar); + + if (!but) { + WM_event_add_mousemove(C); + return WM_UI_HANDLER_CONTINUE; + } + + if (event->type == WHEELUPMOUSE) { + if (but->next == NULL) + nextbut = but->block->buttons.first; + else + nextbut = but->next; + } + else { + if (but->prev == NULL) + nextbut = but->block->buttons.last; + else + nextbut = but->prev; + } + + ui_handle_button_activate(C, ar, nextbut, BUTTON_ACTIVATE_APPLY); + + return WM_UI_HANDLER_BREAK; + } + return WM_UI_HANDLER_CONTINUE; +} + static int ui_region_handler(bContext *C, const wmEvent *event, void *UNUSED(userdata)) { ARegion *ar; @@ -9689,6 +9841,9 @@ static int ui_region_handler(bContext *C, const wmEvent *event, void *UNUSED(use retval = ui_handler_panel_region(C, event, ar, listbox ? listbox : but); + if (retval == WM_UI_HANDLER_CONTINUE) + retval = ui_tab_region_handler(C, event, ar); + if (retval == WM_UI_HANDLER_CONTINUE && listbox) retval = ui_handle_list_event(C, event, ar, listbox); diff --git a/source/blender/editors/interface/interface_intern.h b/source/blender/editors/interface/interface_intern.h index 99316b1f748..811b3583c5d 100644 --- a/source/blender/editors/interface/interface_intern.h +++ b/source/blender/editors/interface/interface_intern.h @@ -71,6 +71,7 @@ typedef enum { UI_WTYPE_NUMBER, UI_WTYPE_SLIDER, UI_WTYPE_EXEC, + UI_WTYPE_TAB, UI_WTYPE_TOOLTIP, /* strings */ @@ -101,6 +102,11 @@ typedef enum { UI_WTYPE_PROGRESSBAR, } uiWidgetTypeEnum; +/* general menu defines */ +#define UI_MENU_TITLE_WIDTH (short)(UI_UNIT_X * 5.0f) +#define UI_MENU_TITLE_HEIGHT (short)(UI_UNIT_Y * 1.1f) +#define UI_MENU_SUBMENU_PADDING (10 * UI_DPI_FAC) /* some extra padding added to menus containing submenu icons */ + /* menu scrolling */ #define UI_MENU_SCROLL_ARROW 12 #define UI_MENU_SCROLL_MOUSE (UI_MENU_SCROLL_ARROW + 2) @@ -121,6 +127,18 @@ enum { /* warn: rest of uiBut->flag in UI_interface.h */ }; +/* uiSubBut->type */ +typedef enum uiSubButType { + UI_SBUT_TYPE_VAL_DECREASE, + UI_SBUT_TYPE_VAL_INCREASE, +} uiSubButType; + +/* uiSubBut->align */ +typedef enum uiSubButAlign { + UI_SBUT_ALIGN_LEFT, + UI_SBUT_ALIGN_RIGHT, +} uiSubButAlign; + /* some buttons display icons only under special conditions * (e.g. 'x' icon in search menu) - used with ui_but_icon_extra_get */ typedef enum uiButExtraIconType { @@ -204,8 +222,23 @@ typedef struct { ListBase lines; } uiLink; +typedef struct uiSubBut { + struct uiSubBut *next, *prev; + + uiSubButType type; + uiSubButAlign align; /* alignment within but */ + + int width, height; + rcti rect; /* block relative coords */ + + bool is_hovered; /* could be made into flag */ +} uiSubBut; + struct uiBut { struct uiBut *next, *prev; + + ListBase subbuts; + int flag, drawflag; eButType type; eButPointerType pointype; @@ -446,11 +479,14 @@ extern bool ui_block_is_pie_menu(const uiBlock *block) ATTR_WARN_UNUSED_RESULT; extern void ui_block_to_window_fl(const struct ARegion *ar, uiBlock *block, float *x, float *y); extern void ui_block_to_window(const struct ARegion *ar, uiBlock *block, int *x, int *y); extern void ui_block_to_window_rctf(const struct ARegion *ar, uiBlock *block, rctf *rct_dst, const rctf *rct_src); +extern void ui_block_to_window_rcti(const ARegion *ar, uiBlock *block, rcti *rct_dst, const rcti *rct_src); extern void ui_window_to_block_fl(const struct ARegion *ar, uiBlock *block, float *x, float *y); extern void ui_window_to_block(const struct ARegion *ar, uiBlock *block, int *x, int *y); extern void ui_window_to_region(const ARegion *ar, int *x, int *y); extern void ui_region_to_window(const struct ARegion *ar, int *x, int *y); extern void ui_region_winrct_get_no_margin(const struct ARegion *ar, struct rcti *r_rect); +extern void ui_rcti_to_pixelrect(const ARegion *ar, uiBlock *block, rcti *rct_dst, const rcti *rct_src); +extern void ui_rctf_to_pixelrect(const ARegion *ar, uiBlock *block, rctf *rct_dst, const rctf *rct_src); extern double ui_but_value_get(uiBut *but); extern void ui_but_value_set(uiBut *but, double value); @@ -655,6 +691,7 @@ void ui_but_clipboard_free(void); void ui_panel_menu(struct bContext *C, ARegion *ar, Panel *pa); uiBut *ui_but_find_old(uiBlock *block_old, const uiBut *but_new); uiBut *ui_but_find_new(uiBlock *block_old, const uiBut *but_new); +uiBut *ui_but_find_activated_tab(const struct ARegion *ar); #ifdef WITH_INPUT_IME void ui_but_ime_reposition(uiBut *but, int x, int y, bool complete); @@ -671,6 +708,8 @@ void ui_draw_tooltip_background(uiStyle *UNUSED(style), uiBlock *block, rcti *re void ui_draw_search_back(struct uiStyle *style, uiBlock *block, rcti *rect); bool ui_link_bezier_points(const rcti *rect, float coord_array[][2], int resol); void ui_draw_link_bezier(const rcti *rect); +void ui_draw_but_TAB_outline(rcti *rect, float rad, int roundboxtype, unsigned char highlight[3], + unsigned char highlight_fade[3]); extern void ui_draw_but(const struct bContext *C, ARegion *ar, struct uiStyle *style, uiBut *but, rcti *rect); /* theme color init */ diff --git a/source/blender/editors/interface/interface_layout.c b/source/blender/editors/interface/interface_layout.c index 67b4f183c82..593138869a8 100644 --- a/source/blender/editors/interface/interface_layout.c +++ b/source/blender/editors/interface/interface_layout.c @@ -281,12 +281,40 @@ static void ui_item_position(uiItem *item, int x, int y, int w, int h) { if (item->type == ITEM_BUTTON) { uiButtonItem *bitem = (uiButtonItem *)item; + uiBut *but = bitem->but; + + but->rect.xmin = x; + but->rect.ymin = y; + but->rect.xmax = x + w; + but->rect.ymax = y + h; + + /* set subbut sizes */ + if (BLI_listbase_is_empty(&but->subbuts) == false) { + uiSubBut *sbut; + for (sbut = but->subbuts.first; sbut; sbut = sbut->next) { + if (sbut->align == UI_SBUT_ALIGN_LEFT) { + sbut->rect.xmin = but->rect.xmin - 2; /* - 2 looks a bit better */ + sbut->rect.xmax = sbut->rect.xmin + sbut->width; + } + else if (sbut->align == UI_SBUT_ALIGN_RIGHT) { + sbut->rect.xmax = but->rect.xmax + 4; /* + 4 looks a bit better */ + sbut->rect.xmin = but->rect.xmax - sbut->width; + } + else { + BLI_assert(0); + } + sbut->rect.ymin = but->rect.ymin + (U.pixelsize - 1.0f); + sbut->rect.ymax = sbut->rect.ymin + sbut->height; + + if (but->block->panel) { + uiStyle *style = UI_style_get_dpi(); + + sbut->rect.ymin += (but->block->panel->sizey - style->panelspace); + sbut->rect.ymax += (but->block->panel->sizey - style->panelspace); + } + } + } - bitem->but->rect.xmin = x; - bitem->but->rect.ymin = y; - bitem->but->rect.xmax = x + w; - bitem->but->rect.ymax = y + h; - ui_but_update(bitem->but); /* for strlen */ } else { @@ -1465,6 +1493,45 @@ void uiItemsEnumR(uiLayout *layout, struct PointerRNA *ptr, const char *propname * we don't know the context this is called in */ } +void uiItemTabsR(uiLayout *layout, PointerRNA *ptr, PropertyRNA *prop, const char *name, + int icon, int alignment, int icon_only) +{ + uiBlock *block = layout->root->block; + uiBut *but; + EnumPropertyItem *item, *item_array; + int itemw, value, h = UI_UNIT_Y; + bool free; + + RNA_property_enum_items_gettexted(block->evil_C, ptr, prop, &item_array, NULL, &free); + + UI_block_layout_set_current(block, ui_item_local_sublayout(layout, layout, 1)); + + for (item = item_array; item->identifier; item++) { + if (!item->identifier[0]) + continue; + + name = (!name || name[0]) ? item->name : ""; + icon = item->icon; + value = item->value; + itemw = ui_text_icon_width(block->curlayout, icon_only ? "" : name, icon, 0); + + if (icon && name[0] && !icon_only) + but = uiDefIconTextButR_prop(block, UI_BTYPE_TAB, 0, icon, name, 0, 0, itemw, h, ptr, prop, -1, 0, value, -1, -1, NULL); + else if (icon) + but = uiDefIconButR_prop(block, UI_BTYPE_TAB, 0, icon, 0, 0, 1.3f * itemw, h, ptr, prop, -1, 0, value, -1, -1, NULL); + else + but = uiDefButR_prop(block, UI_BTYPE_TAB, 0, name, 0, 0, 0.9f * itemw, h, ptr, prop, -1, 0, value, -1, -1, NULL); + + if (RNA_property_flag(prop) & PROP_ENUM_FLAG) + UI_but_func_set(but, ui_item_enum_expand_handle, but, SET_INT_IN_POINTER(value)); + + but->drawflag |= alignment; + } + + if (free) + MEM_freeN(item_array); +} + /* Pointer RNA button with search */ typedef struct CollItemSearch { diff --git a/source/blender/editors/interface/interface_panel.c b/source/blender/editors/interface/interface_panel.c index 5ee7556a042..d9f4689748f 100644 --- a/source/blender/editors/interface/interface_panel.c +++ b/source/blender/editors/interface/interface_panel.c @@ -427,16 +427,43 @@ void UI_draw_icon_tri(float x, float y, char dir) } } -/* triangle 'icon' inside rect */ -static void ui_draw_tria_rect(const rctf *rect, char dir) +static void ui_draw_tria_rect(const rctf *rect, const bool is_closed) { - if (dir == 'h') { + const float col_tint = 50; + const int px = (int)UI_DPI_FAC; + float col[3]; + + /* XXX ensure contrast */ + UI_GetThemeColorShade3fv(TH_TITLE, col_tint, col); + + /* color for shadow drawing */ + glColor4f(0.0f, 0.0f, 0.0f, 0.3f); + + if (is_closed) { float half = 0.5f * BLI_rctf_size_y(rect); - ui_draw_anti_tria(rect->xmin, rect->ymin, rect->xmin, rect->ymax, rect->xmax, rect->ymin + half); + + /* draw shadow first */ + ui_draw_anti_tria(rect->xmin + px, rect->ymin - px, + rect->xmin + px, rect->ymax - px, + rect->xmax + px, rect->ymin + half - px); + + glColor3fv(col); + ui_draw_anti_tria(rect->xmin, rect->ymin, + rect->xmin, rect->ymax, + rect->xmax, rect->ymin + half); } else { - float half = 0.5f * BLI_rctf_size_x(rect); - ui_draw_anti_tria(rect->xmin, rect->ymax, rect->xmax, rect->ymax, rect->xmin + half, rect->ymin); + float half = 0.5f * BLI_rctf_size_y(rect); + + /* draw shadow first */ + ui_draw_anti_tria(rect->xmin + px, rect->ymax - px, + rect->xmax + px, rect->ymax - px, + rect->xmin + half + px, rect->ymin - px); + + glColor3fv(col); + ui_draw_anti_tria(rect->xmin, rect->ymax, + rect->xmax, rect->ymax, + rect->xmin + half, rect->ymin); } } @@ -462,9 +489,7 @@ static void ui_draw_anti_x(float x1, float y1, float x2, float y2) /* x 'icon' for panel header */ static void ui_draw_x_icon(float x, float y) { - ui_draw_anti_x(x, y, x + 9.375f, y + 9.375f); - } #define PNL_ICON UI_UNIT_X /* could be UI_UNIT_Y too */ @@ -492,86 +517,133 @@ static void ui_draw_panel_scalewidget(const rcti *rect) fdrawline(xmin + dx, ymin + 1, xmax, ymax - dy + 1); glDisable(GL_BLEND); } + static void ui_draw_panel_dragwidget(const rctf *rect) { unsigned char col_back[3], col_high[3], col_dark[3]; - const int col_tint = 84; + const int col_tint = 60; - const int px = (int)U.pixelsize; + const int px = (int)UI_DPI_FAC; const int px_zoom = max_ii(iroundf(BLI_rctf_size_y(rect) / 22.0f), 1); const int box_margin = max_ii(iroundf((float)(px_zoom * 2.0f)), px); const int box_size = max_ii(iroundf((BLI_rctf_size_y(rect) / 8.0f) - px), px); + const int box_rows = 4; const int x_min = rect->xmin; const int y_min = rect->ymin; - const int y_ofs = max_ii(iroundf(BLI_rctf_size_y(rect) / 3.0f), px); - const int x_ofs = y_ofs; - int i_x, i_y; + const int y_ofs = (BLI_rctf_size_y(rect) / box_rows) - (box_margin * 0.5f); + int i; UI_GetThemeColor3ubv(UI_GetThemeValue(TH_PANEL_SHOW_HEADER) ? TH_PANEL_HEADER : TH_PANEL_BACK, col_back); - UI_GetColorPtrShade3ubv(col_back, col_high, col_tint); - UI_GetColorPtrShade3ubv(col_back, col_dark, -col_tint); + UI_GetColorPtrShade3ubv(col_back, col_high, col_tint); + UI_GetColorPtrShade3ubv(col_back, col_dark, -(col_tint * 0.4)); /* draw multiple boxes */ - for (i_x = 0; i_x < 4; i_x++) { - for (i_y = 0; i_y < 2; i_y++) { - const int x_co = (x_min + x_ofs) + (i_x * (box_size + box_margin)); - const int y_co = (y_min + y_ofs) + (i_y * (box_size + box_margin)); - - glColor3ubv(col_dark); - glRectf(x_co - box_size, y_co - px_zoom, x_co, (y_co + box_size) - px_zoom); - glColor3ubv(col_high); - glRectf(x_co - box_size, y_co, x_co, y_co + box_size); - } + for (i = 0; i < box_rows; i++) { + const int y_co = (y_min + y_ofs) + (i * (box_size + box_margin)); + + glColor3ubv(col_dark); + glRectf(x_min - box_size + px_zoom, y_co - px_zoom, x_min + px_zoom, (y_co + box_size) - px_zoom); + glColor3ubv(col_high); + glRectf(x_min - box_size, y_co, x_min, y_co + box_size); } } - -static void ui_draw_aligned_panel_header(uiStyle *style, uiBlock *block, const rcti *rect, char dir) +static void ui_draw_aligned_panel_header( + const uiStyle *style, const uiBlock *block, + const rcti *rect, const char dir) { - Panel *panel = block->panel; - rcti hrect; - int pnl_icons; + const Panel *panel = block->panel; + const int px = (int)UI_DPI_FAC; const char *activename = panel->drawname[0] ? panel->drawname : panel->panelname; + rcti hrect; - /* + 0.001f to avoid flirting with float inaccuracy */ - if (panel->control & UI_PNL_CLOSE) - pnl_icons = (panel->labelofs + 2 * PNL_ICON + 5) / block->aspect + 0.001f; - else - pnl_icons = (panel->labelofs + PNL_ICON + 5) / block->aspect + 0.001f; - /* active tab */ /* draw text label */ UI_ThemeColor(TH_TITLE); - + hrect = *rect; if (dir == 'h') { - hrect.xmin = rect->xmin + pnl_icons; - hrect.ymin += 2.0f / block->aspect; + hrect.xmin = rect->xmin + BLI_rcti_size_y(rect); + hrect.ymin += (2.0f / block->aspect) * px; UI_fontstyle_draw(&style->paneltitle, &hrect, activename); } else { - /* ignore 'pnl_icons', otherwise the text gets offset horizontally - * + 0.001f to avoid flirting with float inaccuracy - */ - hrect.xmin = rect->xmin + (PNL_ICON + 5) / block->aspect + 0.001f; + hrect.xmin = rect->xmin + ((PNL_HEADER - 1) / block->aspect); UI_fontstyle_draw_rotated(&style->paneltitle, &hrect, activename); } } +static void ui_draw_panel_shadow( + const rctf shadowrect, const float aspect, + const float alpha_fac, const bool is_selected) +{ + float alpha_fac_tmp = 0.2f * alpha_fac; + const int px = MAX2(iroundf(UI_DPI_FAC * (1 / aspect)), 1); + short shadow_ofs = is_selected ? 2.0f * px : 1.0f * px; + + glEnable(GL_BLEND); + + if (is_selected) { + /* draw a big soft shadow while dragging */ + UI_draw_box_shadow(alpha_fac * 255, shadowrect.xmin, shadowrect.ymin, shadowrect.xmax, shadowrect.ymax); + } + else { + short i; + + /* draw a soft 2px shadow */ + for (i = 0; i < 2; i++) { + glColor4f(0.0f, 0.0f, 0.0f, alpha_fac_tmp); + + glRectf(shadowrect.xmin + shadow_ofs, shadowrect.ymin - shadow_ofs, + shadowrect.xmax + shadow_ofs, shadowrect.ymax - shadow_ofs); + + shadow_ofs += px; + alpha_fac_tmp *= 0.5f; + } + } + + glDisable(GL_BLEND); +} + +static void panel_boundbox_get( + const uiBlock *block, const Panel *pa, + const rcti *blockrect, const rcti *headrect, + rctf *r_bounds) +{ + const int xmax = (pa->flag & PNL_CLOSEDX) ? (blockrect->xmin + (PNL_HEADER / block->aspect)) : blockrect->xmax; + const int ymin = (pa->flag & PNL_CLOSED) ? headrect->ymin : blockrect->ymin; + + BLI_rctf_init(r_bounds, blockrect->xmin, xmax, ymin, headrect->ymax); +} + /* panel integrated in buttonswindow, tool/property lists etc */ -void ui_draw_aligned_panel(uiStyle *style, uiBlock *block, const rcti *rect, const bool show_pin) +void ui_draw_aligned_panel( + uiStyle *style, uiBlock *block, + const rcti *rect, + const bool show_pin) { Panel *panel = block->panel; + rctf fullrect, itemrect; rcti headrect; - rctf itemrect; int ofsx; + + const bool is_selected = (panel->flag & PNL_SELECT) ? true : false; + const float alpha_fac = is_selected ? 0.7f : 1.0f; + + /* panel states */ + const bool is_inside = ELEM(panel->mouse_state, PANEL_MOUSE_INSIDE_CONTENT, PANEL_MOUSE_INSIDE_HEADER); + const bool is_closed_xy = (panel->flag & PNL_CLOSED) ? true : false; const bool is_closed_x = (panel->flag & PNL_CLOSEDX) ? true : false; const bool is_closed_y = (panel->flag & PNL_CLOSEDY) ? true : false; + /* theme options */ + const bool draw_header = UI_GetThemeValue(TH_PANEL_SHOW_HEADER); + const bool draw_back = UI_GetThemeValue(TH_PANEL_SHOW_BACK); + if (panel->paneltab) return; if (panel->type && (panel->type->flag & PNL_NO_HEADER)) return; @@ -581,20 +653,45 @@ void ui_draw_aligned_panel(uiStyle *style, uiBlock *block, const rcti *rect, con headrect.ymin = headrect.ymax; headrect.ymax = headrect.ymin + floor(PNL_HEADER / block->aspect + 0.001f); + /* set fullrect */ + panel_boundbox_get(block, panel, rect, &headrect, &fullrect); + + if (draw_header == false && is_closed_xy) { + /* skip */ + } + /* draw panel shadow */ + else if (draw_header || draw_back) { + rctf shadowrect = fullrect; + + /* adjust shadowrect for special case: draw background but not header */ + if (draw_back && !draw_header) { + shadowrect.ymax = rect->ymax; + } + + ui_draw_panel_shadow(shadowrect, block->aspect, alpha_fac, is_selected); + } + { float minx = rect->xmin; - float maxx = is_closed_x ? (minx + PNL_HEADER / block->aspect) : rect->xmax; + float maxx = is_closed_x ? (minx + (PNL_HEADER / block->aspect)) : rect->xmax; float y = headrect.ymax; glEnable(GL_BLEND); - if (UI_GetThemeValue(TH_PANEL_SHOW_HEADER)) { - /* draw with background color */ - UI_ThemeColor4(TH_PANEL_HEADER); - glRectf(minx, headrect.ymin + 1, maxx, y); + if (draw_header) { + float col[3]; - fdrawline(minx, y, maxx, y); - fdrawline(minx, y, maxx, y); + if (is_inside) { + /* highlight if mouse is inside */ + UI_GetThemeColorShade3fv(TH_PANEL_HEADER, 7, col); + } + else { + UI_GetThemeColor3fv(TH_PANEL_HEADER, col); + } + + /* draw with background color */ + glColor4f(UNPACK3(col), alpha_fac); + glRectf(minx, headrect.ymin, maxx, y); } else if (!(panel->runtime_flag & PNL_FIRST)) { /* draw embossed separator */ @@ -622,24 +719,24 @@ void ui_draw_aligned_panel(uiStyle *style, uiBlock *block, const rcti *rect, con #endif { glEnable(GL_BLEND); - UI_icon_draw_aspect(headrect.xmax - ((PNL_ICON * 2.2f) / block->aspect), headrect.ymin + (5.0f / block->aspect), + UI_icon_draw_aspect(headrect.xmax - ((PNL_ICON * 1.8f) / block->aspect), headrect.ymin + (5.0f / block->aspect), (panel->flag & PNL_PIN) ? ICON_PINNED : ICON_UNPINNED, (block->aspect / UI_DPI_FAC), 1.0f); glDisable(GL_BLEND); } - /* horizontal title */ if (is_closed_x == false) { + /* horizontal title */ ui_draw_aligned_panel_header(style, block, &headrect, 'h'); - /* 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; + /* drag widget */ + if (is_inside) { + BLI_rctf_rcti_copy(&itemrect, &headrect); + /* itemrect smaller */ + itemrect.xmin = itemrect.xmax - (5.0f / block->aspect); - BLI_rctf_scale(&itemrect, 0.7f); - ui_draw_panel_dragwidget(&itemrect); + ui_draw_panel_dragwidget(&itemrect); + } } /* if the panel is minimized vertically: @@ -654,21 +751,23 @@ void ui_draw_aligned_panel(uiStyle *style, uiBlock *block, const rcti *rect, con } /* an open panel */ else { - /* in some occasions, draw a border */ - if (panel->flag & PNL_SELECT) { - if (panel->control & UI_PNL_SOLID) UI_draw_roundbox_corner_set(UI_CNR_ALL); - else UI_draw_roundbox_corner_set(UI_CNR_NONE); - - UI_ThemeColorShade(TH_BACK, -120); - UI_draw_roundbox_unfilled(0.5f + rect->xmin, 0.5f + rect->ymin, 0.5f + rect->xmax, 0.5f + headrect.ymax + 1, 8); - } - /* panel backdrop */ - if (UI_GetThemeValue(TH_PANEL_SHOW_BACK)) { + if (draw_back) { /* draw with background color */ + float col[3]; + + if (is_inside) { + /* highlight if mouse is inside */ + UI_GetThemeColorShade3fv(TH_PANEL_BACK, 7, col); + } + else { + UI_GetThemeColor3fv(TH_PANEL_BACK, col); + } + glEnable(GL_BLEND); - UI_ThemeColor4(TH_PANEL_BACK); + glColor4f(UNPACK3(col), alpha_fac); glRecti(rect->xmin, rect->ymin, rect->xmax, rect->ymax); + glDisable(GL_BLEND); } if (panel->control & UI_PNL_SCALE) @@ -684,23 +783,14 @@ void ui_draw_aligned_panel(uiStyle *style, uiBlock *block, const rcti *rect, con ofsx = 22; } - /* draw collapse icon */ - UI_ThemeColor(TH_TITLE); - /* itemrect smaller */ - itemrect.xmin = headrect.xmin + 5.0f / block->aspect; + itemrect.xmin = headrect.xmin + (is_closed_x ? (1.0f / block->aspect) : (3.0f / block->aspect)); itemrect.xmax = itemrect.xmin + BLI_rcti_size_y(&headrect); itemrect.ymin = headrect.ymin; itemrect.ymax = headrect.ymax; - BLI_rctf_scale(&itemrect, 0.35f); - if (is_closed_y) - ui_draw_tria_rect(&itemrect, 'h'); - else if (is_closed_x) - ui_draw_tria_rect(&itemrect, 'h'); - else - ui_draw_tria_rect(&itemrect, 'v'); + ui_draw_tria_rect(&itemrect, is_closed_xy); (void)ofsx; } @@ -851,8 +941,10 @@ static bool uiAlignPanelStep(ScrArea *sa, ARegion *ar, const float fac, const bo /* no smart other default start loc! this keeps switching f5/f6/etc compatible */ ps = panelsort; - ps->pa->ofsx = 0; - ps->pa->ofsy = -get_panel_size_y(ps->pa); + ps->pa->ofsx = UI_PANEL_MARGIN; + /* offset first panel, but not for properties editor, there is already some space making this look odd */ + ps->pa->ofsy = -(get_panel_size_y(ps->pa) + ((sa->spacetype == SPACE_BUTS || ar->regiontype == RGN_TYPE_TABS) ? + 0 : UI_PANEL_MARGIN)); if (has_category_tabs) { if (align == BUT_VERTICAL) { @@ -865,10 +957,10 @@ static bool uiAlignPanelStep(ScrArea *sa, ARegion *ar, const float fac, const bo if (align == BUT_VERTICAL) { psnext->pa->ofsx = ps->pa->ofsx; - psnext->pa->ofsy = get_panel_real_ofsy(ps->pa) - get_panel_size_y(psnext->pa); + psnext->pa->ofsy = get_panel_real_ofsy(ps->pa) - get_panel_size_y(psnext->pa) - UI_PANEL_MARGIN; } else { - psnext->pa->ofsx = get_panel_real_ofsx(ps->pa); + psnext->pa->ofsx = get_panel_real_ofsx(ps->pa) + UI_PANEL_MARGIN * 2; psnext->pa->ofsy = ps->pa->ofsy + get_panel_size_y(ps->pa) - get_panel_size_y(psnext->pa); } } @@ -1312,17 +1404,17 @@ static void ui_handle_panel_header(const bContext *C, uiBlock *block, int mx, in int align = panel_aligned(sa, ar), button = 0; rctf rect_drag, rect_pin; - float rect_leftmost; + float collapse_xmax; /* drag and pin rect's */ rect_drag = block->rect; - rect_drag.xmin = block->rect.xmax - (PNL_ICON * 1.5f); + rect_drag.xmin = block->rect.xmax - (PNL_ICON * 0.8f); rect_pin = rect_drag; if (show_pin) { BLI_rctf_translate(&rect_pin, -PNL_ICON, 0.0f); } - rect_leftmost = rect_pin.xmin; + collapse_xmax = rect_pin.xmin; /* mouse coordinates in panel space! */ @@ -1345,7 +1437,7 @@ static void ui_handle_panel_header(const bContext *C, uiBlock *block, int mx, in if (mx <= block->rect.xmax - 8 - PNL_ICON) button = 2; //else if (mx <= block->rect.xmin + 10 + 2 * PNL_ICON + 2) button = 1; } - else if (mx < rect_leftmost) { + else if (mx < collapse_xmax) { button = 1; } @@ -1903,13 +1995,21 @@ int ui_handler_panel_region(bContext *C, const wmEvent *event, ARegion *ar, cons } } + /* do a first iteration over all panels to see if we have one that is already being dragged */ + for (block = ar->uiblocks.last; block; block = block->prev) { + if (block->panel && block->panel->flag & PNL_SELECT) { + /* don't handle any further interaction while a panel + * is dragged (which is handled separately) */ + retval = WM_UI_HANDLER_BREAK; + break; + } + } + if (retval == WM_UI_HANDLER_BREAK) { return retval; } for (block = ar->uiblocks.last; block; block = block->prev) { - uiPanelMouseState mouse_state; - mx = event->x; my = event->y; ui_window_to_block(ar, block, &mx, &my); @@ -1922,10 +2022,22 @@ int ui_handler_panel_region(bContext *C, const wmEvent *event, ARegion *ar, cons if (pa->type && pa->type->flag & PNL_NO_HEADER) /* XXX - accessed freed panels when scripts reload, need to fix. */ continue; - mouse_state = ui_panel_mouse_state_get(block, pa, mx, my); + pa->mouse_state = ui_panel_mouse_state_get(block, pa, mx, my); + + /* some special redrawing (skipped if area is already tagged for redraw) */ + if (event->type == MOUSEMOVE && ar->do_draw == 0) { + int mx_prev = event->prevx; + int my_prev = event->prevy; + + ui_window_to_block(ar, block, &mx_prev, &my_prev); + /* redraw if mouse state has changed for mouse hover feedback */ + if (pa->mouse_state != ui_panel_mouse_state_get(block, pa, mx_prev, my_prev)) { + ED_region_tag_redraw(ar); + } + } /* XXX hardcoded key warning */ - if (ELEM(mouse_state, PANEL_MOUSE_INSIDE_CONTENT, PANEL_MOUSE_INSIDE_HEADER) && event->val == KM_PRESS) { + if (ELEM(pa->mouse_state, PANEL_MOUSE_INSIDE_CONTENT, PANEL_MOUSE_INSIDE_HEADER) && event->val == KM_PRESS) { if (event->type == AKEY && ((event->ctrl + event->oskey + event->shift + event->alt) == 0)) { if (pa->flag & PNL_CLOSEDY) { @@ -1944,13 +2056,13 @@ int ui_handler_panel_region(bContext *C, const wmEvent *event, ARegion *ar, cons if (ui_but_is_active(ar)) continue; - if (ELEM(mouse_state, PANEL_MOUSE_INSIDE_CONTENT, PANEL_MOUSE_INSIDE_HEADER)) { + if (ELEM(pa->mouse_state, PANEL_MOUSE_INSIDE_CONTENT, PANEL_MOUSE_INSIDE_HEADER)) { if (event->val == KM_PRESS) { /* open close on header */ if (ELEM(event->type, RETKEY, PADENTER)) { - if (mouse_state == PANEL_MOUSE_INSIDE_HEADER) { + if (pa->mouse_state == PANEL_MOUSE_INSIDE_HEADER) { ui_handle_panel_header(C, block, mx, my, RETKEY, event->ctrl, event->shift); retval = WM_UI_HANDLER_BREAK; break; @@ -1960,12 +2072,12 @@ int ui_handler_panel_region(bContext *C, const wmEvent *event, ARegion *ar, cons /* all inside clicks should return in break - overlapping/float panels */ retval = WM_UI_HANDLER_BREAK; - if (mouse_state == PANEL_MOUSE_INSIDE_HEADER) { + if (pa->mouse_state == PANEL_MOUSE_INSIDE_HEADER) { ui_handle_panel_header(C, block, mx, my, event->type, event->ctrl, event->shift); retval = WM_UI_HANDLER_BREAK; break; } - else if ((mouse_state == PANEL_MOUSE_INSIDE_SCALE) && !(pa->flag & PNL_CLOSED)) { + else if ((pa->mouse_state == PANEL_MOUSE_INSIDE_SCALE) && !(pa->flag & PNL_CLOSED)) { panel_activate_state(C, pa, PANEL_STATE_DRAG_SCALE); retval = WM_UI_HANDLER_BREAK; break; @@ -1973,7 +2085,7 @@ int ui_handler_panel_region(bContext *C, const wmEvent *event, ARegion *ar, cons } else if (event->type == RIGHTMOUSE) { - if (mouse_state == PANEL_MOUSE_INSIDE_HEADER) { + if (pa->mouse_state == PANEL_MOUSE_INSIDE_HEADER) { ui_panel_menu(C, ar, block->panel); retval = WM_UI_HANDLER_BREAK; break; diff --git a/source/blender/editors/interface/interface_regions.c b/source/blender/editors/interface/interface_regions.c index 40e4da2de94..bfaf03cdce0 100644 --- a/source/blender/editors/interface/interface_regions.c +++ b/source/blender/editors/interface/interface_regions.c @@ -1402,6 +1402,10 @@ static void ui_block_position(wmWindow *window, ARegion *butregion, uiBut *but, for (bt = block->buttons.first; bt; bt = bt->next) { BLI_rctf_union(&block->rect, &bt->rect); + + if (UNLIKELY(block->flag & UI_BLOCK_HAS_SUBMENU)) { + bt->rect.xmax += UI_MENU_SUBMENU_PADDING; + } } } else { @@ -1409,8 +1413,12 @@ static void ui_block_position(wmWindow *window, ARegion *butregion, uiBut *but, block->rect.xmin = block->rect.ymin = 0; block->rect.xmax = block->rect.ymax = 20; } + + if (block->flag & UI_BLOCK_HAS_SUBMENU) { + block->rect.xmax += UI_MENU_SUBMENU_PADDING; + } } - + /* aspect = (float)(BLI_rcti_size_x(&block->rect) + 4);*/ /*UNUSED*/ ui_block_to_window_rctf(butregion, but->block, &block->rect, &block->rect); @@ -1478,35 +1486,41 @@ static void ui_block_position(wmWindow *window, ARegion *butregion, uiBut *but, if (dir2 == UI_DIR_DOWN && down == 0) dir2 = UI_DIR_UP; } - if (dir1 == UI_DIR_LEFT) { - xof = butrct.xmin - block->rect.xmax; - if (dir2 == UI_DIR_UP) yof = butrct.ymin - block->rect.ymin - center - MENU_PADDING; - else yof = butrct.ymax - block->rect.ymax + center + MENU_PADDING; - } - else if (dir1 == UI_DIR_RIGHT) { - xof = butrct.xmax - block->rect.xmin; - if (dir2 == UI_DIR_UP) yof = butrct.ymin - block->rect.ymin - center - MENU_PADDING; - else yof = butrct.ymax - block->rect.ymax + center + MENU_PADDING; - } - else if (dir1 == UI_DIR_UP) { - yof = butrct.ymax - block->rect.ymin; - if (dir2 == UI_DIR_RIGHT) xof = butrct.xmax - block->rect.xmax; - else xof = butrct.xmin - block->rect.xmin; - /* changed direction? */ - if ((dir1 & block->direction) == 0) { - UI_block_order_flip(block); - } - } - else if (dir1 == UI_DIR_DOWN) { - yof = butrct.ymin - block->rect.ymax; - if (dir2 == UI_DIR_RIGHT) xof = butrct.xmax - block->rect.xmax; - else xof = butrct.xmin - block->rect.xmin; - /* changed direction? */ - if ((dir1 & block->direction) == 0) { - UI_block_order_flip(block); - } +#define RECTS_BUT_BLOCK_DIFF(member) (butrct.member - block->rect.member) + + switch (dir1) { + case UI_DIR_LEFT: + xof = butrct.xmin - block->rect.xmax; + if (dir2 == UI_DIR_UP) yof = RECTS_BUT_BLOCK_DIFF(ymin) - center - MENU_PADDING; + else yof = RECTS_BUT_BLOCK_DIFF(ymax) + center + MENU_PADDING; + break; + case UI_DIR_RIGHT: + xof = butrct.xmax - block->rect.xmin; + if (dir2 == UI_DIR_UP) yof = RECTS_BUT_BLOCK_DIFF(ymin) - center - MENU_PADDING; + else yof = RECTS_BUT_BLOCK_DIFF(ymax) + center + MENU_PADDING; + break; + case UI_DIR_UP: + yof = iroundf(butrct.ymax - block->rect.ymin - (2.0f * U.pixelsize)); + if (dir2 == UI_DIR_RIGHT) xof = RECTS_BUT_BLOCK_DIFF(xmax); + else xof = RECTS_BUT_BLOCK_DIFF(xmin); + /* changed direction? */ + if ((dir1 & block->direction) == 0) { + UI_block_order_flip(block); + } + break; + case UI_DIR_DOWN: + yof = iroundf(butrct.ymin - block->rect.ymax + (2.0f * U.pixelsize)); + if (dir2 == UI_DIR_RIGHT) xof = RECTS_BUT_BLOCK_DIFF(xmax); + else xof = RECTS_BUT_BLOCK_DIFF(xmin); + /* changed direction? */ + if ((dir1 & block->direction) == 0) { + UI_block_order_flip(block); + } + break; } +#undef RECTS_BUT_BLOCK_DIFF + /* and now we handle the exception; no space below or to top */ if (top == 0 && down == 0) { if (dir1 == UI_DIR_LEFT || dir1 == UI_DIR_RIGHT) { @@ -2700,14 +2714,15 @@ uiPopupMenu *UI_popup_menu_begin(bContext *C, const char *title, int icon) if (icon) { BLI_snprintf(titlestr, sizeof(titlestr), " %s", title); - uiDefIconTextBut(pup->block, UI_BTYPE_LABEL, 0, icon, titlestr, 0, 0, 200, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, ""); + but = uiDefIconTextBut(pup->block, UI_BTYPE_LABEL, 0, icon, titlestr, 0, 0, + UI_MENU_TITLE_WIDTH, UI_MENU_TITLE_HEIGHT, NULL, + 0.0, 0.0, 0, 0, ""); + but->flag |= UI_BUT_MENU_TITLE; } else { - but = uiDefBut(pup->block, UI_BTYPE_LABEL, 0, title, 0, 0, 200, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, ""); + but = uiDefMenuTitleBut(pup->block, title); but->drawflag = UI_BUT_TEXT_LEFT; } - - uiItemS(pup->layout); } return pup; diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c index 1238b883e9a..e69fbf7fb8f 100644 --- a/source/blender/editors/interface/interface_templates.c +++ b/source/blender/editors/interface/interface_templates.c @@ -79,6 +79,8 @@ #include "UI_interface.h" #include "UI_interface_icons.h" +#include "UI_view2d.h" + #include "interface_intern.h" void UI_template_fix_linking(void) @@ -3122,7 +3124,7 @@ void uiTemplateList( /* add scrollbar */ if (len > layoutdata.visual_items) { col = uiLayoutColumn(row, false); - uiDefButI(block, UI_BTYPE_SCROLL, 0, "", 0, 0, UI_UNIT_X * 0.75, UI_UNIT_Y * dyn_data->visual_height, + uiDefButI(block, UI_BTYPE_SCROLL, 0, "", 0, 0, V2D_SCROLL_WIDTH, UI_UNIT_Y * dyn_data->visual_height, &ui_list->list_scroll, 0, dyn_data->height - dyn_data->visual_height, dyn_data->visual_height, 0, ""); } @@ -3211,7 +3213,7 @@ void uiTemplateList( /* add scrollbar */ if (len > layoutdata.visual_items) { /* col = */ uiLayoutColumn(row, false); - uiDefButI(block, UI_BTYPE_SCROLL, 0, "", 0, 0, UI_UNIT_X * 0.75, UI_UNIT_Y * dyn_data->visual_height, + uiDefButI(block, UI_BTYPE_SCROLL, 0, "", 0, 0, V2D_SCROLL_WIDTH, UI_UNIT_Y * dyn_data->visual_height, &ui_list->list_scroll, 0, dyn_data->height - dyn_data->visual_height, dyn_data->visual_height, 0, ""); } diff --git a/source/blender/editors/interface/interface_widgets.c b/source/blender/editors/interface/interface_widgets.c index 5d37f5c0fcf..008f129904b 100644 --- a/source/blender/editors/interface/interface_widgets.c +++ b/source/blender/editors/interface/interface_widgets.c @@ -44,6 +44,7 @@ #include "BKE_context.h" #include "BKE_curve.h" +#include "BKE_screen.h" #include "RNA_access.h" @@ -64,6 +65,10 @@ /* icons are 80% of height of button (16 pixels inside 20 height) */ #define ICON_SIZE_FROM_BUTRECT(rect) (0.8f * BLI_rcti_size_y(rect)) +/* for checking interface style type */ +#define IFACE_STYLE_IS_CLASSIC (((bTheme *)UI_GetTheme())->tui.interface_style == TH_IFACE_STYLE_CLASSIC) +#define IFACE_STYLE_IS_FLAT (((bTheme *)UI_GetTheme())->tui.interface_style == TH_IFACE_STYLE_FLAT) + /* ************** widget base functions ************** */ /** * - in: roundbox codes for corner types and radius @@ -122,6 +127,7 @@ typedef struct uiWidgetType { void (*state)(struct uiWidgetType *, int state); void (*draw)(uiWidgetColors *, rcti *, int state, int roundboxalign); void (*custom)(uiBut *, uiWidgetColors *, rcti *, int state, int roundboxalign); + void (*subbut_draw)(uiSubBut *, uiWidgetColors *, rcti *, int state, int roundboxalign); void (*text)(uiFontStyle *, uiWidgetColors *, uiBut *, rcti *); } uiWidgetType; @@ -231,6 +237,40 @@ void ui_draw_anti_roundbox(int mode, float minx, float miny, float maxx, float m glDisable(GL_BLEND); } +static void ui_draw_anti_circle(float rad) +{ + float color[4]; + int j; + + glEnable(GL_BLEND); + glGetFloatv(GL_CURRENT_COLOR, color); + color[3] *= 0.125f; + glColor4fv(color); + + for (j = 0; j < WIDGET_AA_JITTER; j++) { + glTranslatef(jit[j][0], jit[j][1], 0.0f); + glutil_draw_filled_arc(0.0f, M_PI * 2.0f, rad, 40); + glTranslatef(-jit[j][0], -jit[j][1], 0.0f); + } + + glDisable(GL_BLEND); +} + +static void ui_draw_anti_circle_rect(const rcti *rect) +{ + const int size_x = BLI_rcti_size_x(rect); + const int size_y = BLI_rcti_size_y(rect); + const float rad = size_y / 2; + + glPushMatrix(); + + /* origin is center of the rect */ + glTranslatef(rect->xmin + size_x / 2, rect->ymin + size_y / 2, 0.0f); + ui_draw_anti_circle(rad); + + glPopMatrix(); +} + static void widget_init(uiWidgetBase *wtb) { wtb->totvert = wtb->halfwayvert = 0; @@ -238,21 +278,38 @@ static void widget_init(uiWidgetBase *wtb) wtb->tria2.tot = 0; wtb->draw_inner = true; - wtb->draw_outline = true; - wtb->draw_emboss = true; wtb->draw_shadedir = true; + + if (IFACE_STYLE_IS_CLASSIC) { + wtb->draw_outline = true; + wtb->draw_emboss = true; + } + else { + BLI_assert(IFACE_STYLE_IS_FLAT); + + /* don't draw outline or emboss by default */ + wtb->draw_outline = false; + wtb->draw_emboss = false; + } } /* helper call, makes shadow rect, with 'sun' above menu, so only shadow to left/right/bottom */ /* return tot */ -static int round_box_shadow_edges(float (*vert)[2], const rcti *rect, float rad, int roundboxalign, float step) +static int round_box_shadow_edges( + float (*vert)[2], const rcti *rect, + float rad, int roundboxalign, float step, + const bool has_outline) { float vec[WIDGET_CURVE_RESOLU][2]; float minx, miny, maxx, maxy; int a, tot = 0; rad += step; - + + if (has_outline == false) { + step -= U.pixelsize; + } + if (2.0f * rad > BLI_rcti_size_y(rect)) rad = 0.5f * BLI_rcti_size_y(rect); @@ -519,6 +576,8 @@ static void widget_draw_tria_ex( tria->index = tris; } +/* number button triangles are now drawn using sub-buttons */ +#if 0 static void widget_num_tria(uiWidgetTrias *tria, const rcti *rect, float triasize, char where) { widget_draw_tria_ex( @@ -526,6 +585,7 @@ static void widget_num_tria(uiWidgetTrias *tria, const rcti *rect, float triasiz num_tria_vert, ARRAY_SIZE(num_tria_vert), num_tria_face, ARRAY_SIZE(num_tria_face)); } +#endif static void widget_scroll_circle(uiWidgetTrias *tria, const rcti *rect, float triasize, char where) { @@ -648,7 +708,7 @@ static void widgetbase_draw(uiWidgetBase *wtb, uiWidgetColors *wcol) /* backdrop non AA */ if (wtb->draw_inner) { - if (wcol->shaded == 0) { + if (wcol->shaded == 0 || IFACE_STYLE_IS_FLAT) { if (wcol->alpha_check) { float inner_v_half[WIDGET_SIZE_MAX][2]; float x_mid = 0.0f; /* used for dumb clamping of values */ @@ -696,11 +756,18 @@ static void widgetbase_draw(uiWidgetBase *wtb, uiWidgetColors *wcol) } else { /* simple fill */ - glColor4ubv((unsigned char *)wcol->inner); + glColor4ub(UNPACK3(wcol->inner), wcol->inner[3] * 0.285f); glEnableClientState(GL_VERTEX_ARRAY); glVertexPointer(2, GL_FLOAT, 0, wtb->inner_v); - glDrawArrays(GL_POLYGON, 0, wtb->totvert); + + /* for each AA step */ + for (j = 0; j < WIDGET_AA_JITTER; j++) { + glTranslatef(jit[j][0], jit[j][1], 0.0f); + glDrawArrays(GL_POLYGON, 0, wtb->totvert); + glTranslatef(-jit[j][0], -jit[j][1], 0.0f); + } + glDisableClientState(GL_VERTEX_ARRAY); } } @@ -904,10 +971,19 @@ static void widget_draw_icon( } if (show_menu_icon) { - xs = rect->xmax - UI_DPI_ICON_SIZE - aspect; + rcti tria; + const int size = (int)(ICON_DEFAULT_HEIGHT / aspect); + + xs = rect->xmax - (UI_MENU_SUBMENU_PADDING * 0.5f); ys = (rect->ymin + rect->ymax - height) / 2.0f; - - UI_icon_draw_aspect(xs, ys, ICON_RIGHTARROW_THIN, aspect, alpha); + + BLI_rcti_init(&tria, xs, xs + size, ys, ys + size); + BLI_rcti_scale(&tria, 0.5f); + + glColor3f(1.0f, 1.0f, 1.0f); + ui_draw_anti_tria(tria.xmin, tria.ymin, + tria.xmax, tria.ymin + BLI_rcti_size_y(&tria) / 2, + tria.xmin, tria.ymax); } glDisable(GL_BLEND); @@ -1503,30 +1579,91 @@ static void widget_draw_text(uiFontStyle *fstyle, uiWidgetColors *wcol, uiBut *b } } +#define WITH_DUMMY_ICON_TEXT_ALIGN + +#ifdef WITH_DUMMY_ICON_TEXT_ALIGN +static bool ui_block_has_real_icon_but(const uiBlock *block) +{ + uiBut *but; + + for (but = block->buttons.first; but; but = but->next) { + if ((but->flag & UI_HAS_ICON) && (but->icon != ICON_BLANK1)) { + return true; + } + } + + return false; +} +#endif + /* draws text and icons for buttons */ static void widget_draw_text_icon(uiFontStyle *fstyle, uiWidgetColors *wcol, uiBut *but, rcti *rect) { - const bool show_menu_icon = ui_but_draw_menu_icon(but); + uiBlock *block = but->block; float alpha = (float)wcol->text[3] / 255.0f; + const int size_y = BLI_rcti_size_y(rect); + int add_y = 0; char password_str[UI_MAX_DRAW_STR]; uiButExtraIconType extra_icon_type; + const bool show_menu_icon = ui_but_draw_menu_icon(but); + const bool is_block_menu = ui_block_is_menu(block); + + ui_but_text_password_hide(password_str, but, false); + /* scale down rect so the text isn't drawn into the + * extra space for added for submenu triangles */ + if (UNLIKELY((is_block_menu == true) && + (block->flag & UI_BLOCK_HAS_SUBMENU) && + (but->type != UI_BTYPE_SEPR_LINE))) + { + rect->xmax -= UI_MENU_SUBMENU_PADDING; + } + + /* add some offset for menu titles to make them centered vertically - ugly but works best */ + if (but->type == UI_BTYPE_LABEL && but->flag & UI_BUT_MENU_TITLE) { + BLI_assert(is_block_menu); + + if (block->direction == UI_DIR_UP || block->flag & UI_BLOCK_POPUP) { + rect->ymin += 2 * (int)(0.2f * UI_UNIT_Y); /* 2 * MENU_PADDING */ + rect->ymin -= 2.0f * U.pixelsize; + } + else if (block->direction == UI_DIR_DOWN) { + rect->ymin -= (int)(0.2f * UI_UNIT_Y); /* MENU_PADDING */ + } + else { + BLI_assert(0); + } + } + /* check for button text label */ if (but->type == UI_BTYPE_MENU && (but->flag & UI_BUT_NODE_LINK)) { rcti temp = *rect; - temp.xmin = rect->xmax - BLI_rcti_size_y(rect) - 1; + temp.xmin = rect->xmax - size_y - 1; widget_draw_icon(but, ICON_LAYER_USED, alpha, &temp, false); } /* If there's an icon too (made with uiDefIconTextBut) then draw the icon * and offset the text label to accommodate it */ +#ifdef WITH_DUMMY_ICON_TEXT_ALIGN + if (ui_block_has_real_icon_but(but->block) == false) { + /* block doesn't have any real icons so we can skip */ + + /* we still want to draw the submenu triangle icon though */ + if (show_menu_icon) { + widget_draw_icon(but, ICON_NONE, alpha, rect, show_menu_icon); + } + } + /* Big previews with optional text label below */ + else if (but->flag & UI_BUT_ICON_PREVIEW && is_block_menu) { +#else /* Big previews with optional text label below */ - if (but->flag & UI_BUT_ICON_PREVIEW && ui_block_is_menu(but->block)) { + if (but->flag & UI_BUT_ICON_PREVIEW && is_block_menu) { +#endif const BIFIconID icon = (but->flag & UI_HAS_ICON) ? but->icon + but->iconadd : ICON_NONE; - int icon_size = BLI_rcti_size_y(rect); + int icon_size = size_y; int text_size = 0; /* This is a bit britle, but avoids adding an 'UI_BUT_HAS_LABEL' flag to but... */ @@ -1547,32 +1684,49 @@ static void widget_draw_text_icon(uiFontStyle *fstyle, uiWidgetColors *wcol, uiB rect->ymax -= icon_size; /* vertically centering text */ - rect->ymin += UI_UNIT_Y / 2; + rect->ymin += (size_y + add_y) / 2; } /* Icons on the left with optional text label on the right */ - else if (but->flag & UI_HAS_ICON || show_menu_icon) { +#ifdef WITH_DUMMY_ICON_TEXT_ALIGN + else if ((but->flag & UI_HAS_ICON) || show_menu_icon) { const BIFIconID icon = (but->flag & UI_HAS_ICON) ? but->icon + but->iconadd : ICON_NONE; const float icon_size = ICON_SIZE_FROM_BUTRECT(rect); /* menu item - add some more padding so menus don't feel cramped. it must * be part of the button so that this area is still clickable */ - if (ui_block_is_menu(but->block)) + if (is_block_menu) rect->xmin += 0.3f * U.widget_unit; widget_draw_icon(but, icon, alpha, rect, show_menu_icon); rect->xmin += icon_size; - /* without this menu keybindings will overlap the arrow icon [#38083] */ - if (show_menu_icon) { - rect->xmax -= icon_size / 2.0f; + } +#else + else if ((but->flag & UI_HAS_ICON) && but->icon != ICON_BLANK1) { + const BIFIconID icon = (but->flag & UI_HAS_ICON) ? but->icon + but->iconadd : ICON_NONE; + const float icon_size = ICON_SIZE_FROM_BUTRECT(rect); + + /* menu item - add some more padding so menus don't feel cramped. it must + * be part of the button so that this area is still clickable */ + if (is_block_menu) { + rect->xmin += 0.3f * U.widget_unit; } + + widget_draw_icon(but, icon, alpha, rect, show_menu_icon); + + rect->xmin += icon_size; } + else if (show_menu_icon) { + const BIFIconID icon = (but->flag & UI_HAS_ICON) ? but->icon + but->iconadd : ICON_NONE; + widget_draw_icon(but, icon, alpha, rect, show_menu_icon); + } +#endif if (but->editstr || (but->drawflag & UI_BUT_TEXT_LEFT)) { - rect->xmin += (UI_TEXT_MARGIN_X * U.widget_unit) / but->block->aspect; + rect->xmin += (UI_TEXT_MARGIN_X * U.widget_unit) / block->aspect; } else if ((but->drawflag & UI_BUT_TEXT_RIGHT)) { - rect->xmax -= (UI_TEXT_MARGIN_X * U.widget_unit) / but->block->aspect; + rect->xmax -= (UI_TEXT_MARGIN_X * U.widget_unit) / block->aspect; } /* unlink icon for this button type */ @@ -1581,7 +1735,7 @@ static void widget_draw_text_icon(uiFontStyle *fstyle, uiWidgetColors *wcol, uiB { rcti temp = *rect; - temp.xmin = temp.xmax - (BLI_rcti_size_y(rect) * 1.08f); + temp.xmin = temp.xmax - (size_y * 1.08f); if (extra_icon_type == UI_BUT_ICONEXTRA_UNLINK) { widget_draw_icon(but, ICON_X, alpha, &temp, false); @@ -1620,9 +1774,13 @@ static void widget_draw_text_icon(uiFontStyle *fstyle, uiWidgetColors *wcol, uiB widget_draw_text(fstyle, wcol, but, rect); ui_but_text_password_hide(password_str, but, true); + + /* if a widget uses font shadow it has to be deactivated now */ + BLF_disable(fstyle->uifont_id, BLF_SHADOW); } #undef UI_TEXT_CLIP_MARGIN +#undef WITH_ICON_TEXT_ALIGNMENT /* *********************** widget types ************************************* */ @@ -1641,26 +1799,32 @@ static struct uiWidgetColors wcol_num = { {25, 25, 25, 255}, {180, 180, 180, 255}, {153, 153, 153, 255}, - {90, 90, 90, 255}, + {90, 90, 90, 160}, {0, 0, 0, 255}, {255, 255, 255, 255}, 1, - -20, 0 + -20, 0, + + 0, /* pad */ + 0.5f }; static struct uiWidgetColors wcol_numslider = { {25, 25, 25, 255}, {180, 180, 180, 255}, {153, 153, 153, 255}, - {128, 128, 128, 255}, + {140, 140, 140, 255}, {0, 0, 0, 255}, {255, 255, 255, 255}, 1, - -20, 0 + -20, 0, + + 0, /* pad */ + 0.5f }; static struct uiWidgetColors wcol_text = { @@ -1673,7 +1837,10 @@ static struct uiWidgetColors wcol_text = { {255, 255, 255, 255}, 1, - 0, 25 + 0, 25, + + 0, /* pad */ + 0.2f }; static struct uiWidgetColors wcol_option = { @@ -1686,7 +1853,10 @@ static struct uiWidgetColors wcol_option = { {255, 255, 255, 255}, 1, - 15, -15 + 15, -15, + + 0, /* pad */ + 0.35f }; /* button that shows popup */ @@ -1700,7 +1870,10 @@ static struct uiWidgetColors wcol_menu = { {204, 204, 204, 255}, 1, - 15, -15 + 15, -15, + + 0, /* pad */ + 0.2f }; /* button that starts pulldown */ @@ -1714,7 +1887,10 @@ static struct uiWidgetColors wcol_pulldown = { {0, 0, 0, 255}, 0, - 25, -20 + 25, -20, + + 0, /* pad */ + 0.2f }; /* button inside menu */ @@ -1728,21 +1904,27 @@ static struct uiWidgetColors wcol_menu_item = { {0, 0, 0, 255}, 1, - 38, 0 + 38, 0, + + 0, /* pad */ + 0.2f }; /* backdrop menu + title text color */ static struct uiWidgetColors wcol_menu_back = { {0, 0, 0, 255}, - {25, 25, 25, 230}, + {40, 40, 40, 230}, {45, 45, 45, 230}, {100, 100, 100, 255}, - {160, 160, 160, 255}, + {220, 220, 220, 255}, {255, 255, 255, 255}, 0, - 25, -20 + 25, -20, + + 0, /* pad */ + 0.25f }; /* pie menus */ @@ -1756,7 +1938,10 @@ static struct uiWidgetColors wcol_pie_menu = { {255, 255, 255, 255}, 1, - 10, -10 + 10, -10, + + 0, /* pad */ + 0.5f }; @@ -1771,7 +1956,10 @@ static struct uiWidgetColors wcol_tooltip = { {255, 255, 255, 255}, 0, - 25, -20 + 25, -20, + + 0, /* pad */ + 0.2f }; static struct uiWidgetColors wcol_radio = { @@ -1784,11 +1972,14 @@ static struct uiWidgetColors wcol_radio = { {0, 0, 0, 255}, 1, - 15, -15 + 15, -15, + + 0, /* pad */ + 0.2f }; static struct uiWidgetColors wcol_regular = { - {25, 25, 25, 255}, + {40, 40, 40, 255}, {153, 153, 153, 255}, {100, 100, 100, 255}, {25, 25, 25, 255}, @@ -1797,7 +1988,10 @@ static struct uiWidgetColors wcol_regular = { {255, 255, 255, 255}, 0, - 0, 0 + 0, 0, + + 0, /* pad */ + 0.2f }; static struct uiWidgetColors wcol_tool = { @@ -1810,24 +2004,30 @@ static struct uiWidgetColors wcol_tool = { {255, 255, 255, 255}, 1, - 15, -15 + 15, -15, + + 0, /* pad */ + 0.25f }; static struct uiWidgetColors wcol_box = { - {25, 25, 25, 255}, - {128, 128, 128, 255}, - {100, 100, 100, 255}, + {50, 50, 50, 255}, + {140, 140, 140, 255}, + {130, 130, 130, 255}, {25, 25, 25, 255}, {0, 0, 0, 255}, {255, 255, 255, 255}, 0, - 0, 0 + 0, 0, + + 0, /* pad */ + 0.2f }; static struct uiWidgetColors wcol_toggle = { - {25, 25, 25, 255}, + {70, 70, 70, 255}, {153, 153, 153, 255}, {100, 100, 100, 255}, {25, 25, 25, 255}, @@ -1836,20 +2036,26 @@ static struct uiWidgetColors wcol_toggle = { {255, 255, 255, 255}, 0, - 0, 0 + 0, 0, + + 0, /* pad */ + 0.2f }; static struct uiWidgetColors wcol_scroll = { {50, 50, 50, 180}, {80, 80, 80, 180}, {100, 100, 100, 180}, - {128, 128, 128, 255}, + {140, 140, 140, 255}, {0, 0, 0, 255}, {255, 255, 255, 255}, 1, - 5, -5 + 5, -5, + + 0, /* pad */ + 0.5f }; static struct uiWidgetColors wcol_progress = { @@ -1862,7 +2068,10 @@ static struct uiWidgetColors wcol_progress = { {255, 255, 255, 255}, 0, - 0, 0 + 0, 0, + + 0, /* pad */ + 0.2f }; static struct uiWidgetColors wcol_list_item = { @@ -1875,6 +2084,22 @@ static struct uiWidgetColors wcol_list_item = { {0, 0, 0, 255}, 0, + 0, 0, + + 0, /* pad */ + 0.2f +}; + +static struct uiWidgetColors wcol_tab = { + {255, 255, 255, 255}, + {83, 83, 83, 255}, + {114, 114, 114, 255}, + {90, 90, 90, 255}, + + {0, 0, 0, 255}, + {0, 0, 0, 255}, + + 0, 0, 0 }; @@ -1889,7 +2114,10 @@ static struct uiWidgetColors wcol_tmp = { {255, 255, 255, 255}, 0, - 0, 0 + 0, 0, + + 0, /* pad */ + 0.2f }; @@ -1900,6 +2128,7 @@ void ui_widget_color_init(ThemeUI *tui) tui->wcol_tool = wcol_tool; tui->wcol_text = wcol_text; tui->wcol_radio = wcol_radio; + tui->wcol_tab = wcol_tab; tui->wcol_option = wcol_option; tui->wcol_toggle = wcol_toggle; tui->wcol_num = wcol_num; @@ -2129,11 +2358,32 @@ static void widget_state_menu_item(uiWidgetType *wt, int state) } } +static void widget_state_tab(uiWidgetType *wt, int state) +{ + unsigned char col_tab_active[4], col_tab_inactive[4], col_tab_text[3]; + + /* tabs are using special theme colors */ + UI_GetThemeColor4ubv(TH_TAB_ACTIVE, col_tab_active); + UI_GetThemeColor4ubv(TH_TAB_INACTIVE, col_tab_inactive); + UI_GetThemeColor3ubv(TH_TEXT, col_tab_text); /* updates the font color to always match the region color */ + + copy_v3_v3_char(wt->wcol_theme->inner, (char *)col_tab_inactive); + copy_v3_v3_char(wt->wcol_theme->inner_sel, (char *)col_tab_active); + copy_v3_v3_char(wt->wcol_theme->text, (char *)col_tab_text); + + wt->wcol = *(wt->wcol_theme); + + if (state & UI_SELECT) + copy_v4_v4_char(wt->wcol.inner, wt->wcol.inner_sel); + else if (state & UI_ACTIVE) + widget_state_blend(wt->wcol.inner, wt->wcol.inner_sel, 0.2f); +} + /* ************ menu backdrop ************************* */ /* outside of rect, rad to left/bottom/right */ -static void widget_softshadow(const rcti *rect, int roundboxalign, const float radin) +static void widget_softshadow(const rcti *rect, int roundboxalign, const float radin, const bool has_outline) { bTheme *btheme = UI_GetTheme(); uiWidgetBase wtb; @@ -2154,7 +2404,10 @@ static void widget_softshadow(const rcti *rect, int roundboxalign, const float r rect1.ymax -= radout; /* inner part */ - totvert = round_box_shadow_edges(wtb.inner_v, &rect1, radin, roundboxalign & (UI_CNR_BOTTOM_RIGHT | UI_CNR_BOTTOM_LEFT), 0.0f); + totvert = round_box_shadow_edges( + wtb.inner_v, &rect1, radin, + roundboxalign & (UI_CNR_BOTTOM_RIGHT | UI_CNR_BOTTOM_LEFT), + 0.0f, has_outline); /* we draw a number of increasing size alpha quad strips */ alphastep = 3.0f * btheme->tui.menu_shadow_fac / radout; @@ -2164,7 +2417,7 @@ static void widget_softshadow(const rcti *rect, int roundboxalign, const float r for (step = 1; step <= (int)radout; step++) { float expfac = sqrtf(step / radout); - round_box_shadow_edges(wtb.outer_v, &rect1, radin, UI_CNR_ALL, (float)step); + round_box_shadow_edges(wtb.outer_v, &rect1, radin, UI_CNR_ALL, (float)step, has_outline); glColor4f(0.0f, 0.0f, 0.0f, alphastep * (1.0f - expfac)); @@ -2177,34 +2430,104 @@ static void widget_softshadow(const rcti *rect, int roundboxalign, const float r glDisableClientState(GL_VERTEX_ARRAY); } -static void widget_menu_back(uiWidgetColors *wcol, rcti *rect, int flag, int direction) +static void widget_menu_back(uiWidgetColors *wcol, const uiBlock *block, rcti *rect) { uiWidgetBase wtb; + const uiBut *title_but; + rcti rect_title = *rect; int roundboxalign = UI_CNR_ALL; - + int roundbox_cpy = 0; + const bool is_popup = block->flag & UI_BLOCK_POPUP; + widget_init(&wtb); - - /* menu is 2nd level or deeper */ - if (flag & UI_BLOCK_POPUP) { - //rect->ymin -= 4.0; - //rect->ymax += 4.0; + + wtb.draw_emboss = 0; + + /* search a menu title button */ + for (title_but = block->buttons.first; title_but; title_but = title_but->next) { + if (title_but->flag & UI_BUT_MENU_TITLE) { + break; + } } - else if (direction == UI_DIR_DOWN) { - roundboxalign = (UI_CNR_BOTTOM_RIGHT | UI_CNR_BOTTOM_LEFT); - rect->ymin -= 0.1f * U.widget_unit; + + if (is_popup) { + if (title_but) { + rect_title.ymin = title_but->rect.ymin; + } } - else if (direction == UI_DIR_UP) { + else if (block->direction == UI_DIR_UP) { roundboxalign = UI_CNR_TOP_LEFT | UI_CNR_TOP_RIGHT; rect->ymax += 0.1f * U.widget_unit; + + if (title_but) { + /* adjust title rect */ + rect_title.ymin = title_but->rect.ymin; + rect_title.ymax = rect->ymax; + } } - + else if (block->direction == UI_DIR_DOWN) { + roundboxalign = (UI_CNR_BOTTOM_RIGHT | UI_CNR_BOTTOM_LEFT); + rect->ymin -= 0.1f * U.widget_unit; + + if (title_but) { + /* adjust title rect */ + rect_title.ymax = title_but->rect.ymax; + rect_title.ymin = rect->ymin; + } + } + roundbox_cpy = roundboxalign; + glEnable(GL_BLEND); - widget_softshadow(rect, roundboxalign, 0.25f * U.widget_unit); - - round_box_edges(&wtb, roundboxalign, rect, 0.25f * U.widget_unit); + widget_softshadow(rect, roundboxalign, wcol->roundness * U.widget_unit, wtb.draw_outline); + + /* adjust the main rect after shadow drawing to exclude the title rect */ + if (title_but) { + if (block->direction == UI_DIR_UP || is_popup) { + rect->ymax = rect_title.ymin + (int)(2.0f * U.pixelsize); + roundboxalign &= ~(UI_CNR_TOP_LEFT | UI_CNR_TOP_RIGHT); + } + else if (block->direction == UI_DIR_DOWN) { + rect->ymin = rect_title.ymax - (int)(2.0f * U.pixelsize); + roundboxalign &= ~(UI_CNR_BOTTOM_LEFT | UI_CNR_BOTTOM_RIGHT); + } + } + + round_box_edges(&wtb, roundboxalign, rect, wcol->roundness * U.widget_unit); + widgetbase_draw(&wtb, wcol); + + /* draw title rect (in a darker color) */ + if (title_but) { + uiWidgetColors wcol_title = *wcol; + const char tint = -12; + const char inner_title[3] = {UNPACK3_EX(, wcol->inner, + tint)}; /* XXX _util function? */ + + copy_v3_v3_char(wcol_title.inner, inner_title); + + /* invert the temporarily tweaked roundboxalign with + * its earlier value to get the corners we need now */ + roundboxalign ^= roundbox_cpy; + + round_box_edges(&wtb, roundboxalign, &rect_title, wcol->roundness * U.widget_unit); + widgetbase_draw(&wtb, &wcol_title); + } + + glDisable(GL_BLEND); +} + +static void widget_tooltip_back(uiWidgetColors *wcol, rcti *rect, int UNUSED(state), int UNUSED(roundboxalign)) +{ + uiWidgetBase wtb; + + widget_init(&wtb); wtb.draw_emboss = false; + + glEnable(GL_BLEND); + widget_softshadow(rect, UI_CNR_ALL, wcol->roundness * U.widget_unit, wtb.draw_outline); + + round_box_edges(&wtb, UI_CNR_ALL, rect, wcol->roundness * U.widget_unit); + widgetbase_draw(&wtb, wcol); - + glDisable(GL_BLEND); } @@ -2618,46 +2941,43 @@ static void ui_draw_but_HSV_v(uiBut *but, const rcti *rect) /* ************ separator, for menus etc ***************** */ + +#define WIDGET_SEPARATOR_HEIGHT (2.0f * UI_DPI_FAC) + static void ui_draw_separator(const rcti *rect, uiWidgetColors *wcol) { - int y = rect->ymin + BLI_rcti_size_y(rect) / 2 - 1; - unsigned char col[4]; - - col[0] = wcol->text[0]; - col[1] = wcol->text[1]; - col[2] = wcol->text[2]; - col[3] = 30; + int y = rect->ymin + (BLI_rcti_size_y(rect) - WIDGET_SEPARATOR_HEIGHT) / 2; + const unsigned char tint = 30; glEnable(GL_BLEND); - glColor4ubv(col); - sdrawline(rect->xmin, y, rect->xmax, y); + glLineWidth(WIDGET_SEPARATOR_HEIGHT); + glColor4ub(UNPACK3_EX(, wcol->inner, + tint), wcol->inner[3] / 2); + sdrawline(rect->xmin + UI_DPI_FAC, y, rect->xmax, y); + glLineWidth(1); glDisable(GL_BLEND); } +#undef WIDGET_SEPARATOR_HEIGHT + /* ************ button callbacks, draw ***************** */ static void widget_numbut_draw(uiWidgetColors *wcol, rcti *rect, int state, int roundboxalign, bool emboss) { uiWidgetBase wtb; - const float rad = 0.5f * BLI_rcti_size_y(rect); - float textofs = rad * 0.85f; + const int sizey = BLI_rcti_size_y(rect); + const float rad = wcol->roundness * sizey; + float textofs = 0.43f * sizey; if (state & UI_SELECT) SWAP(short, wcol->shadetop, wcol->shadedown); - + widget_init(&wtb); - + if (!emboss) { round_box_edges(&wtb, roundboxalign, rect, rad); } - /* decoration */ - if (!(state & UI_TEXTINPUT)) { - widget_num_tria(&wtb.tria1, rect, 0.6f, 'l'); - widget_num_tria(&wtb.tria2, rect, 0.6f, 'r'); - } - widgetbase_draw(&wtb, wcol); - + if (!(state & UI_TEXTINPUT)) { /* text space */ rect->xmin += textofs; @@ -2678,6 +2998,61 @@ static void widget_numbut_embossn(uiBut *UNUSED(but), uiWidgetColors *wcol, rcti widget_numbut_draw(wcol, rect, state, roundboxalign, true); } +static void widget_numbut_subbut(uiSubBut *sbut, uiWidgetColors *wcol, rcti *rect, int state, int UNUSED(roundboxalign)) +{ + uiWidgetBase wtb; + uiWidgetColors wcol_cpy = *wcol; + int half; + + if ((state & UI_ACTIVE) == 0 || (state & UI_TEXTINPUT)) + return; + + widget_init(&wtb); + + if (sbut->is_hovered) { + rcti circle_rect = *rect; + int origin_x, origin_y; + int size_x, size_y; + + /* smaller version of rect */ + BLI_rcti_scale(&circle_rect, 0.7f); + + size_x = BLI_rcti_size_x(&circle_rect); + size_y = BLI_rcti_size_y(&circle_rect); + origin_x = circle_rect.xmin + (size_x / 2); + origin_y = circle_rect.ymin + (size_y / 2); + + glColor4ub(UNPACK3((unsigned char *)wcol->item), wcol->item[3] * 0.8f); + glPushMatrix(); + glTranslatef(origin_x, origin_y, 0.0f); + + ui_draw_anti_circle(size_y / 2); + + glPopMatrix(); + } + + /* rect smaller */ + BLI_rcti_scale(rect, 0.4f); + /* offset rect a bit - looks better */ + BLI_rcti_translate(rect, (sbut->align == UI_SBUT_ALIGN_LEFT) ? -UI_DPI_FAC : UI_DPI_FAC, 0); + half = iroundf(BLI_rcti_size_y(rect) / 2); + + glColor4ubv((unsigned char *)(sbut->is_hovered ? wcol->inner : wcol_cpy.item)); + glEnable(GL_BLEND); + + if (sbut->type == UI_SBUT_TYPE_VAL_DECREASE) { + ui_draw_anti_tria(rect->xmin, rect->ymin + half, rect->xmax, rect->ymin, rect->xmax, rect->ymax); + } + else if (sbut->type == UI_SBUT_TYPE_VAL_INCREASE) { + ui_draw_anti_tria(rect->xmin, rect->ymin, rect->xmax, rect->ymin + half, rect->xmin, rect->ymax); + } + else { + BLI_assert(0); + } + + glDisable(GL_BLEND); +} + bool ui_link_bezier_points(const rcti *rect, float coord_array[][2], int resol) { float dist, vec[4][2]; @@ -2739,9 +3114,9 @@ void UI_draw_widget_scroll(uiWidgetColors *wcol, const rcti *rect, const rcti *s horizontal = (BLI_rcti_size_x(rect) > BLI_rcti_size_y(rect)); if (horizontal) - rad = 0.5f * BLI_rcti_size_y(rect); + rad = wcol->roundness * BLI_rcti_size_y(rect); else - rad = 0.5f * BLI_rcti_size_x(rect); + rad = wcol->roundness * BLI_rcti_size_x(rect); wtb.draw_shadedir = (horizontal) ? true : false; @@ -2922,7 +3297,7 @@ static void widget_numslider(uiBut *but, uiWidgetColors *wcol, rcti *rect, int s /* backdrop first */ /* fully rounded */ - offs = 0.5f * BLI_rcti_size_y(rect); + offs = wcol->roundness * BLI_rcti_size_y(rect); toffs = offs * 0.75f; round_box_edges(&wtb, roundboxalign, rect, offs); @@ -2974,11 +3349,13 @@ static void widget_numslider(uiBut *but, uiWidgetColors *wcol, rcti *rect, int s if (!(state & UI_SELECT)) SWAP(short, wcol->shadetop, wcol->shadedown); } - + /* outline */ - wtb.draw_outline = true; - wtb.draw_inner = false; - widgetbase_draw(&wtb, wcol); + if (IFACE_STYLE_IS_CLASSIC) { + wtb.draw_outline = true; + wtb.draw_inner = false; + widgetbase_draw(&wtb, wcol); + } /* add space at either side of the button so text aligns with numbuttons (which have arrow icons) */ if (!(state & UI_TEXTINPUT)) { @@ -3012,7 +3389,7 @@ static void widget_swatch(uiBut *but, uiWidgetColors *wcol, rcti *rect, int stat widget_init(&wtb); /* half rounded */ - rad = 0.25f * U.widget_unit; + rad = wcol->roundness * U.widget_unit; round_box_edges(&wtb, roundboxalign, rect, rad); ui_but_v3_get(but, col); @@ -3035,6 +3412,8 @@ static void widget_swatch(uiBut *but, uiWidgetColors *wcol, rcti *rect, int stat rgba_float_to_uchar((unsigned char *)wcol->inner, col); + /* always draw an outline for color buts to prevent them from being invisible */ + wtb.draw_outline = true; wcol->shaded = 0; wcol->alpha_check = (wcol->inner[3] < 255); @@ -3072,7 +3451,7 @@ static void widget_icon_has_anim(uiBut *but, uiWidgetColors *wcol, rcti *rect, i wtb.draw_outline = false; /* rounded */ - rad = 0.5f * BLI_rcti_size_y(rect); + rad = wcol->roundness * BLI_rcti_size_y(rect); round_box_edges(&wtb, UI_CNR_ALL, rect, rad); widgetbase_draw(&wtb, wcol); } @@ -3095,7 +3474,7 @@ static void widget_textbut(uiWidgetColors *wcol, rcti *rect, int state, int roun widget_init(&wtb); /* half rounded */ - rad = 0.2f * U.widget_unit; + rad = wcol->roundness * U.widget_unit; round_box_edges(&wtb, roundboxalign, rect, rad); widgetbase_draw(&wtb, wcol); @@ -3110,7 +3489,7 @@ static void widget_menubut(uiWidgetColors *wcol, rcti *rect, int UNUSED(state), widget_init(&wtb); /* half rounded */ - rad = 0.2f * U.widget_unit; + rad = wcol->roundness * U.widget_unit; round_box_edges(&wtb, roundboxalign, rect, rad); /* decoration */ @@ -3130,7 +3509,7 @@ static void widget_menuiconbut(uiWidgetColors *wcol, rcti *rect, int UNUSED(stat widget_init(&wtb); /* half rounded */ - rad = 0.2f * U.widget_unit; + rad = wcol->roundness * U.widget_unit; round_box_edges(&wtb, roundboxalign, rect, rad); /* decoration */ @@ -3147,7 +3526,7 @@ static void widget_menunodebut(uiWidgetColors *wcol, rcti *rect, int UNUSED(stat widget_init(&wtb); /* half rounded */ - rad = 0.2f * U.widget_unit; + rad = wcol->roundness * U.widget_unit; round_box_edges(&wtb, roundboxalign, rect, rad); wcol->inner[0] = min_ii(wcol->inner[0] + 15, 255); @@ -3166,7 +3545,7 @@ static void widget_pulldownbut(uiWidgetColors *wcol, rcti *rect, int state, int { if (state & UI_ACTIVE) { uiWidgetBase wtb; - const float rad = 0.2f * U.widget_unit; + const float rad = wcol->roundness * U.widget_unit; widget_init(&wtb); @@ -3200,7 +3579,7 @@ static void widget_menu_radial_itembut(uiBut *but, uiWidgetColors *wcol, rcti *r wtb.draw_emboss = false; - rad = 0.5f * BLI_rcti_size_y(rect); + rad = wcol->roundness * BLI_rcti_size_y(rect); round_box_edges(&wtb, UI_CNR_ALL, rect, rad); wcol->inner[3] *= fac; @@ -3216,15 +3595,14 @@ static void widget_menu_radial_itembut(uiBut *but, uiWidgetColors *wcol, rcti *r static void widget_list_itembut(uiWidgetColors *wcol, rcti *rect, int UNUSED(state), int UNUSED(roundboxalign)) { uiWidgetBase wtb; - float rad; + const float rad = wcol->roundness * U.widget_unit; widget_init(&wtb); /* rounded, but no outline */ wtb.draw_outline = false; - rad = 0.2f * U.widget_unit; round_box_edges(&wtb, UI_CNR_ALL, rect, rad); - + widgetbase_draw(&wtb, wcol); } @@ -3232,34 +3610,43 @@ static void widget_optionbut(uiWidgetColors *wcol, rcti *rect, int state, int UN { uiWidgetBase wtb; rcti recttemp = *rect; - float rad; - int delta; - + const bool is_style_flat = IFACE_STYLE_IS_FLAT; + widget_init(&wtb); - + /* square */ recttemp.xmax = recttemp.xmin + BLI_rcti_size_y(&recttemp); - + /* smaller */ - delta = 1 + BLI_rcti_size_y(&recttemp) / 8; - recttemp.xmin += delta; - recttemp.ymin += delta; - recttemp.xmax -= delta; - recttemp.ymax -= delta; - - /* half rounded */ - rad = 0.2f * U.widget_unit; - round_box_edges(&wtb, UI_CNR_ALL, &recttemp, rad); - + BLI_rcti_scale(&recttemp, is_style_flat ? 0.8f : 0.7f); + + if (is_style_flat) { + /* draw circle as inner */ + glColor4ubv((unsigned char *)wcol->inner); + ui_draw_anti_circle_rect(&recttemp); + + /* adjust recttemp for decoration */ + BLI_rcti_translate(&recttemp, -0.1f * U.widget_unit, -0.1f * U.widget_unit); + BLI_rcti_scale(&recttemp, 0.9f); + } + else { + round_box_edges(&wtb, UI_CNR_ALL, &recttemp, 0.2f * U.widget_unit); + } + /* decoration */ if (state & UI_SELECT) { widget_check_trias(&wtb.tria1, &recttemp); } - + + if (is_style_flat) { + /* disable inner as this was already drawn */ + wtb.draw_inner = false; + } widgetbase_draw(&wtb, wcol); - + /* text space */ - rect->xmin += BLI_rcti_size_y(rect) * 0.7 + delta; + rect->xmin += BLI_rcti_size_y(rect) * 0.7f; + rect->ymin += 0.1f * U.widget_unit; } /* labels use Editor theme colors for text */ @@ -3290,7 +3677,7 @@ static void widget_radiobut(uiWidgetColors *wcol, rcti *rect, int UNUSED(state), widget_init(&wtb); /* half rounded */ - rad = 0.2f * U.widget_unit; + rad = wcol->roundness * U.widget_unit; round_box_edges(&wtb, roundboxalign, rect, rad); widgetbase_draw(&wtb, wcol); @@ -3314,9 +3701,10 @@ static void widget_box(uiBut *but, uiWidgetColors *wcol, rcti *rect, int UNUSED( } /* half rounded */ - rad = 0.2f * U.widget_unit; + rad = wcol->roundness * U.widget_unit; round_box_edges(&wtb, roundboxalign, rect, rad); + wtb.draw_outline = true; widgetbase_draw(&wtb, wcol); copy_v3_v3_char(wcol->inner, old_col); @@ -3326,20 +3714,35 @@ static void widget_but(uiWidgetColors *wcol, rcti *rect, int UNUSED(state), int { uiWidgetBase wtb; float rad; - + widget_init(&wtb); - + /* half rounded */ - rad = 0.2f * U.widget_unit; + rad = wcol->roundness * U.widget_unit; round_box_edges(&wtb, roundboxalign, rect, rad); - + + widgetbase_draw(&wtb, wcol); +} + +static void widget_toggle(uiWidgetColors *wcol, rcti *rect, int UNUSED(state), int roundboxalign) +{ + uiWidgetBase wtb; + float rad; + + widget_init(&wtb); + + /* half rounded */ + rad = wcol->roundness * U.widget_unit; + round_box_edges(&wtb, roundboxalign, rect, rad); + + wtb.draw_outline = true; widgetbase_draw(&wtb, wcol); } static void widget_roundbut(uiWidgetColors *wcol, rcti *rect, int UNUSED(state), int roundboxalign) { uiWidgetBase wtb; - const float rad = 0.25f * U.widget_unit; + const float rad = wcol->roundness * U.widget_unit; widget_init(&wtb); @@ -3349,6 +3752,54 @@ static void widget_roundbut(uiWidgetColors *wcol, rcti *rect, int UNUSED(state), widgetbase_draw(&wtb, wcol); } +static void widget_tab(uiBut *but, uiWidgetColors *wcol, rcti *rect, int UNUSED(state), int roundboxalign) +{ + uiWidgetBase wtb; + uiStyle *style = UI_style_get(); + const uiFontStyle *fstyle = &style->widget; + const int px = (max_ii(1, iroundf(U.pixelsize))); + const int fontid = fstyle->uifont_id; + const float aspect = but->block->aspect; + const float zoom = 1.0f / aspect; + const float rad = ((px * 3) * UI_DPI_FAC) * zoom; + bool is_active = but->flag & UI_SELECT; + unsigned char theme_col_tab_highlight[3]; + + /* create outline highlight colors */ + if (is_active) + interp_v3_v3v3_uchar(theme_col_tab_highlight, (unsigned char *)wcol->inner_sel, + (unsigned char *)wcol->outline, 0.2f); + else + interp_v3_v3v3_uchar(theme_col_tab_highlight, (unsigned char *)wcol->inner, + (unsigned char *)wcol->outline, 0.12f); + + widget_init(&wtb); + + /* space between tabs */ + BLI_rcti_resize(rect, BLI_rcti_size_x(rect) - 0.07f * U.dpi, BLI_rcti_size_y(rect)); + BLI_rcti_translate(rect, -(0.3f * U.widget_unit), 0.2f * U.widget_unit); + + /* copy the new rect to the button's rect */ + BLI_rctf_resize(&but->rect, BLI_rcti_size_x(rect), BLI_rcti_size_y(rect)); + BLI_rctf_translate(&but->rect, -(0.3f * U.widget_unit), 0.2f * U.widget_unit); + + /* half rounded */ + round_box_edges(&wtb, roundboxalign, rect, rad); + + /* draw inner */ + wtb.draw_outline = 0; + widgetbase_draw(&wtb, wcol); + + /* draw outline (3d look) */ + ui_draw_but_TAB_outline(rect, rad, roundboxalign, theme_col_tab_highlight, + is_active ? (unsigned char *)wcol->inner_sel : (unsigned char *)wcol->inner); + + /* text shadow */ + BLF_enable(fontid, BLF_SHADOW); + BLF_shadow(fontid, 3, 1.0f, 1.0f, 1.0f, 0.25f); + BLF_shadow_offset(fontid, 0, -1); +} + static void widget_draw_extra_mask(const bContext *C, uiBut *but, uiWidgetType *wt, rcti *rect) { uiWidgetBase wtb; @@ -3403,6 +3854,7 @@ static uiWidgetType *widget_type(uiWidgetTypeEnum type) case UI_WTYPE_TOGGLE: wt.wcol_theme = &btheme->tui.wcol_toggle; + wt.draw = widget_toggle; break; case UI_WTYPE_CHECKBOX: @@ -3418,6 +3870,7 @@ static uiWidgetType *widget_type(uiWidgetTypeEnum type) case UI_WTYPE_NUMBER: wt.wcol_theme = &btheme->tui.wcol_num; wt.draw = widget_numbut; + wt.subbut_draw = widget_numbut_subbut; break; case UI_WTYPE_SLIDER: @@ -3431,9 +3884,15 @@ static uiWidgetType *widget_type(uiWidgetTypeEnum type) wt.draw = widget_roundbut; break; + case UI_WTYPE_TAB: + wt.custom = widget_tab; + wt.wcol_theme = &btheme->tui.wcol_tab; + wt.state = widget_state_tab; + break; + case UI_WTYPE_TOOLTIP: wt.wcol_theme = &btheme->tui.wcol_tooltip; - wt.draw = widget_menu_back; + wt.draw = widget_tooltip_back; break; @@ -3489,7 +3948,6 @@ static uiWidgetType *widget_type(uiWidgetTypeEnum type) case UI_WTYPE_MENU_BACK: wt.wcol_theme = &btheme->tui.wcol_menu_back; - wt.draw = widget_menu_back; break; /* specials */ @@ -3612,14 +4070,14 @@ void ui_draw_but(const bContext *C, ARegion *ar, uiStyle *style, uiBut *but, rct widget_draw_text_icon(&style->widgetlabel, &tui->wcol_menu_back, but, rect); break; case UI_BTYPE_SEPR_LINE: - ui_draw_separator(rect, &tui->wcol_menu_item); + ui_draw_separator(rect, &tui->wcol_menu_back); break; default: wt = widget_type(UI_WTYPE_MENU_ITEM); break; } } - else if (but->dt == UI_EMBOSS_NONE) { + else if (but->dt == UI_EMBOSS_NONE && (but->flag & UI_ACTIVE) == 0) { /* "nothing" */ wt = widget_type(UI_WTYPE_ICON); } @@ -3627,7 +4085,7 @@ void ui_draw_but(const bContext *C, ARegion *ar, uiStyle *style, uiBut *but, rct wt = widget_type(UI_WTYPE_MENU_ITEM_RADIAL); } else { - BLI_assert(but->dt == UI_EMBOSS); + BLI_assert(but->dt == UI_EMBOSS || (but->dt == UI_EMBOSS_NONE && (but->flag & UI_ACTIVE))); switch (but->type) { case UI_BTYPE_LABEL: @@ -3672,7 +4130,11 @@ void ui_draw_but(const bContext *C, ARegion *ar, uiStyle *style, uiBut *but, rct if (but->block->flag & UI_BLOCK_LOOP) wt->wcol_theme = &btheme->tui.wcol_menu_back; break; - + + case UI_BTYPE_TAB: + wt = widget_type(UI_WTYPE_TAB); + break; + case UI_BTYPE_BUT_TOGGLE: case UI_BTYPE_TOGGLE: case UI_BTYPE_TOGGLE_N: @@ -3842,6 +4304,16 @@ void ui_draw_but(const bContext *C, ARegion *ar, uiStyle *style, uiBut *but, rct else if (wt->draw) wt->draw(&wt->wcol, rect, state, roundboxalign); + /* draw sub-buts */ + if (wt->subbut_draw && but->subbuts.first) { + uiSubBut *sbut; + for (sbut = but->subbuts.first; sbut; sbut = sbut->next) { + rcti sbut_rect; + ui_rcti_to_pixelrect(ar, but->block, &sbut_rect, &sbut->rect); + wt->subbut_draw(sbut, &wt->wcol, &sbut_rect, state, roundboxalign); + } + } + if (disabled) glEnable(GL_BLEND); wt->text(fstyle, &wt->wcol, but, rect); @@ -3854,27 +4326,22 @@ void ui_draw_but(const bContext *C, ARegion *ar, uiStyle *style, uiBut *but, rct } } -void ui_draw_menu_back(uiStyle *UNUSED(style), uiBlock *block, rcti *rect) +void ui_draw_menu_back(struct uiStyle *UNUSED(style), uiBlock *block, rcti *rect) { uiWidgetType *wt = widget_type(UI_WTYPE_MENU_BACK); - + wt->state(wt, 0); - if (block) - wt->draw(&wt->wcol, rect, block->flag, block->direction); - else - wt->draw(&wt->wcol, rect, 0, 0); - - if (block) { - if (block->flag & UI_BLOCK_CLIPTOP) { - /* XXX no scaling for UI here yet */ - glColor3ubv((unsigned char *)wt->wcol.text); - UI_draw_icon_tri(BLI_rcti_cent_x(rect), rect->ymax - 8, 't'); - } - if (block->flag & UI_BLOCK_CLIPBOTTOM) { - /* XXX no scaling for UI here yet */ - glColor3ubv((unsigned char *)wt->wcol.text); - UI_draw_icon_tri(BLI_rcti_cent_x(rect), rect->ymin + 10, 'v'); - } + widget_menu_back(&wt->wcol, block, rect); + + if (block->flag & UI_BLOCK_CLIPTOP) { + /* XXX no scaling for UI here yet */ + glColor3ubv((unsigned char *)wt->wcol.text); + UI_draw_icon_tri(BLI_rcti_cent_x(rect), rect->ymax - 8, 't'); + } + if (block->flag & UI_BLOCK_CLIPBOTTOM) { + /* XXX no scaling for UI here yet */ + glColor3ubv((unsigned char *)wt->wcol.text); + UI_draw_icon_tri(BLI_rcti_cent_x(rect), rect->ymin + 10, 'v'); } } @@ -4023,7 +4490,7 @@ void ui_draw_search_back(uiStyle *UNUSED(style), uiBlock *block, rcti *rect) uiWidgetType *wt = widget_type(UI_WTYPE_BOX); glEnable(GL_BLEND); - widget_softshadow(rect, UI_CNR_ALL, 0.25f * U.widget_unit); + widget_softshadow(rect, UI_CNR_ALL, 0.25f * U.widget_unit, IFACE_STYLE_IS_CLASSIC); glDisable(GL_BLEND); wt->state(wt, 0); diff --git a/source/blender/editors/interface/resources.c b/source/blender/editors/interface/resources.c index 4f5285fa2f9..c19cef6fadc 100644 --- a/source/blender/editors/interface/resources.c +++ b/source/blender/editors/interface/resources.c @@ -171,8 +171,12 @@ const unsigned char *UI_ThemeGetColorPtr(bTheme *btheme, int spacetype, int colo } switch (colorid) { + case TH_AREA_EDGES: + cp = btheme->tui.area_edges; + break; + case TH_BACK: - if (theme_regionid == RGN_TYPE_WINDOW) + if (ELEM(theme_regionid, RGN_TYPE_WINDOW, RGN_TYPE_TABS)) cp = ts->back; else if (theme_regionid == RGN_TYPE_CHANNELS) cp = ts->list; @@ -192,7 +196,7 @@ const unsigned char *UI_ThemeGetColorPtr(bTheme *btheme, int spacetype, int colo setting = ts->gradients.show_grad; break; case TH_TEXT: - if (theme_regionid == RGN_TYPE_WINDOW) + if (ELEM(theme_regionid, RGN_TYPE_WINDOW, RGN_TYPE_TABS)) cp = ts->text; else if (theme_regionid == RGN_TYPE_CHANNELS) cp = ts->list_text; @@ -258,13 +262,13 @@ const unsigned char *UI_ThemeGetColorPtr(bTheme *btheme, int spacetype, int colo cp = ts->button_text_hi; break; case TH_TAB_ACTIVE: - cp = ts->tab_active; break; + cp = ts->tabs.tab_active; break; case TH_TAB_INACTIVE: - cp = ts->tab_inactive; break; + cp = ts->tabs.tab_inactive; break; case TH_TAB_BACK: - cp = ts->tab_back; break; + cp = ts->tabs.tab_back; break; case TH_TAB_OUTLINE: - cp = ts->tab_outline; break; + cp = ts->tabs.tab_outline; break; case TH_SHADE1: cp = ts->shade1; break; @@ -846,7 +850,9 @@ void ui_theme_init_default(void) /* UI buttons */ ui_widget_color_init(&btheme->tui); - + + rgba_char_args_set_fl(btheme->tui.area_edges, 0.15f, 0.15f, 0.15f, 1.0f); + btheme->tui.iconfile[0] = 0; btheme->tui.panel.show_back = false; btheme->tui.panel.show_header = false; @@ -2636,6 +2642,55 @@ void init_userdef_do_versions(void) if (!USER_VERSION_ATLEAST(276, 2)) { bTheme *btheme; + ThemeSpace *ts; + + /* interface_widgets.c */ + struct uiWidgetColors wcol_tab = { + {255, 255, 255, 255}, + {83, 83, 83, 255}, /* gets overwritten later */ + {114, 114, 114, 255}, /* gets overwritten later */ + {90, 90, 90, 255}, + + {0, 0, 0, 255}, /* gets overwritten later */ + {0, 0, 0, 255}, + + 0, + 0, 0 + }; + + for (btheme = U.themes.first; btheme; btheme = btheme->next) { + btheme->tui.wcol_tab = wcol_tab; + for (ts = UI_THEMESPACE_START(btheme); ts != UI_THEMESPACE_END(btheme); ts++) { + copy_v4_v4_char(ts->tabs.tab_active, ts->tab_active); + copy_v4_v4_char(ts->tabs.tab_inactive, ts->tab_inactive); + copy_v4_v4_char(ts->tabs.tab_back, ts->tab_back); + copy_v4_v4_char(ts->tabs.tab_outline, ts->tab_outline); + } + } + } + + if (!USER_VERSION_ATLEAST(276, 2)) { + bTheme *btheme; + ThemeSpace *ts; + + for (btheme = U.themes.first; btheme; btheme = btheme->next) { + for (ts = UI_THEMESPACE_START(btheme); ts != UI_THEMESPACE_END(btheme); ts++) { + /* XXX maybe remove show_back/show_header options? */ + ts->panelcolors.show_back = ts->panelcolors.show_header = true; + rgba_char_args_set(ts->panelcolors.back, 128, 128, 128, 255); + rgba_char_args_set(ts->panelcolors.header, 97, 97, 97, 255); + } + + rgba_char_args_set_fl(btheme->tui.area_edges, 0.10f, 0.10f, 0.10f, 1.0f); + + btheme->tui.interface_style = TH_IFACE_STYLE_FLAT; + + ui_widget_color_init(&btheme->tui); + } + } + + if (!USER_VERSION_ATLEAST(276, 2)) { + bTheme *btheme; for (btheme = U.themes.first; btheme; btheme = btheme->next) { rgba_char_args_set_fl(btheme->tui.xaxis, 1.0f, 0.27f, 0.27f, 1.0f); /* red */ rgba_char_args_set_fl(btheme->tui.yaxis, 0.27f, 1.0f, 0.27f, 1.0f); /* green */ diff --git a/source/blender/editors/interface/view2d.c b/source/blender/editors/interface/view2d.c index 9976f42a48a..d966cedc133 100644 --- a/source/blender/editors/interface/view2d.c +++ b/source/blender/editors/interface/view2d.c @@ -152,18 +152,21 @@ static void view2d_masks(View2D *v2d, bool check_scrollers) * - if they overlap, they must not occupy the corners (which are reserved for other widgets) */ if (scroll) { + const int scroll_width = (v2d->flag & V2D_USES_UNITS_VERTICAL) ? V2D_SCROLL_WIDTH_TEXT : V2D_SCROLL_WIDTH; + const int scroll_height = (v2d->flag & V2D_USES_UNITS_HORIZONTAL) ? V2D_SCROLL_HEIGHT_TEXT : V2D_SCROLL_HEIGHT; + /* vertical scroller */ if (scroll & V2D_SCROLL_LEFT) { /* on left-hand edge of region */ v2d->vert = v2d->mask; - v2d->vert.xmax = V2D_SCROLL_WIDTH; + v2d->vert.xmax = scroll_width; v2d->mask.xmin = v2d->vert.xmax + 1; } else if (scroll & V2D_SCROLL_RIGHT) { /* on right-hand edge of region */ v2d->vert = v2d->mask; v2d->vert.xmax++; /* one pixel extra... was leaving a minor gap... */ - v2d->vert.xmin = v2d->vert.xmax - V2D_SCROLL_WIDTH; + v2d->vert.xmin = v2d->vert.xmax - scroll_width; v2d->mask.xmax = v2d->vert.xmin - 1; } @@ -171,13 +174,13 @@ static void view2d_masks(View2D *v2d, bool check_scrollers) if (scroll & (V2D_SCROLL_BOTTOM)) { /* on bottom edge of region */ v2d->hor = v2d->mask; - v2d->hor.ymax = V2D_SCROLL_HEIGHT; + v2d->hor.ymax = scroll_height; v2d->mask.ymin = v2d->hor.ymax + 1; } else if (scroll & V2D_SCROLL_TOP) { /* on upper edge of region */ v2d->hor = v2d->mask; - v2d->hor.ymin = v2d->hor.ymax - V2D_SCROLL_HEIGHT; + v2d->hor.ymin = v2d->hor.ymax - scroll_height; v2d->mask.ymax = v2d->hor.ymin - 1; } @@ -317,8 +320,9 @@ void UI_view2d_region_reinit(View2D *v2d, short type, int winx, int winy) v2d->keeptot = V2D_KEEPTOT_BOUNDS; /* note, scroll is being flipped in ED_region_panels() drawing */ - v2d->scroll |= V2D_SCROLL_HORIZONTAL_HIDE; - v2d->scroll |= V2D_SCROLL_VERTICAL_HIDE; + if ((v2d->scroll & V2D_SCROLL_VERTICAL_HIDE) == 0) { + v2d->scroll |= V2D_SCROLL_RIGHT; + } if (do_init) { float panelzoom = (style) ? style->panelzoom : 1.0f; diff --git a/source/blender/editors/interface/view2d_ops.c b/source/blender/editors/interface/view2d_ops.c index ca1efb82ae9..2ebdf467ceb 100644 --- a/source/blender/editors/interface/view2d_ops.c +++ b/source/blender/editors/interface/view2d_ops.c @@ -166,9 +166,13 @@ static void view_pan_apply_ex(bContext *C, v2dViewPanData *vpd, float dx, float /* validate that view is in valid configuration after this operation */ UI_view2d_curRect_validate(v2d); - - /* request updates to be done... */ - ED_region_tag_redraw(vpd->ar); + + /* request updates to be done (special case: tab region! we need to redraw the complete area here!) */ + if (vpd->ar->regiontype == RGN_TYPE_TABS) + ED_area_tag_redraw(vpd->sa); + else + ED_region_tag_redraw(vpd->ar); + WM_event_add_mousemove(C); UI_view2d_sync(vpd->sc, vpd->sa, v2d, V2D_LOCK_COPY); diff --git a/source/blender/editors/screen/CMakeLists.txt b/source/blender/editors/screen/CMakeLists.txt index ed86ffa5e16..dbbf0653ca4 100644 --- a/source/blender/editors/screen/CMakeLists.txt +++ b/source/blender/editors/screen/CMakeLists.txt @@ -20,6 +20,7 @@ set(INC ../include + ../interface ../../blenfont ../../blenkernel ../../blenlib diff --git a/source/blender/editors/screen/SConscript b/source/blender/editors/screen/SConscript index 5f48894c3e7..4a05ce5915b 100644 --- a/source/blender/editors/screen/SConscript +++ b/source/blender/editors/screen/SConscript @@ -34,6 +34,7 @@ incs = [ env['BF_GLEW_INC'], '#/intern/glew-mx', '../include', + '../interface', '../../blenfont', '../../blenkernel', '../../blenlib', diff --git a/source/blender/editors/screen/area.c b/source/blender/editors/screen/area.c index 43b71af3845..3e0bbd47eda 100644 --- a/source/blender/editors/screen/area.c +++ b/source/blender/editors/screen/area.c @@ -85,33 +85,32 @@ extern void ui_draw_anti_tria(float x1, float y1, float x2, float y2, float x3, static void region_draw_emboss(const ARegion *ar, const rcti *scirct) { rcti rect; - + + if (!ELEM(ar->regiontype, RGN_TYPE_HEADER, RGN_TYPE_TOOL_PROPS)) + return; + /* translate scissor rect to region space */ rect.xmin = scirct->xmin - ar->winrct.xmin; rect.ymin = scirct->ymin - ar->winrct.ymin; rect.xmax = scirct->xmax - ar->winrct.xmin; rect.ymax = scirct->ymax - ar->winrct.ymin; - + /* set transp line */ glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - - /* right */ - glColor4ub(0, 0, 0, 30); - sdrawline(rect.xmax, rect.ymin, rect.xmax, rect.ymax); - + glColor4ub(0, 0, 0, 50); + /* bottom */ - glColor4ub(0, 0, 0, 30); - sdrawline(rect.xmin, rect.ymin, rect.xmax, rect.ymin); - + if (ar->alignment == RGN_ALIGN_TOP) { + sdrawline(rect.xmin, rect.ymin, rect.xmax, rect.ymin); + } /* top */ - glColor4ub(255, 255, 255, 30); - sdrawline(rect.xmin, rect.ymax, rect.xmax, rect.ymax); + else { + /* XXX (julian) */ +// BLI_assert(ar->alignment == RGN_ALIGN_BOTTOM); + sdrawline(rect.xmin, rect.ymax, rect.xmax, rect.ymax); + } - /* left */ - glColor4ub(255, 255, 255, 30); - sdrawline(rect.xmin, rect.ymin, rect.xmin, rect.ymax); - glDisable(GL_BLEND); } @@ -1116,6 +1115,9 @@ static void region_rect_recursive(wmWindow *win, ScrArea *sa, ARegion *ar, rcti if (ar->regiontype == RGN_TYPE_HEADER) { prefsizey = ED_area_headersize(); } + else if (ar->regiontype == RGN_TYPE_TABS) { + prefsizey = UI_TAB_REGION_MARGIN_HEIGHT; + } else if (ar->regiontype == RGN_TYPE_UI && sa->spacetype == SPACE_FILE) { prefsizey = UI_UNIT_Y * 2 + (UI_UNIT_Y / 2); } @@ -1444,6 +1446,11 @@ void ED_area_initialize(wmWindowManager *wm, wmWindow *win, ScrArea *sa) for (ar = sa->regionbase.first; ar; ar = ar->next) ar->type = BKE_regiontype_from_id(sa->type, ar->regiontype); + + if (BKE_area_find_region_type(sa, RGN_TYPE_TABS)) + sa->flag |= AREA_CONTAINS_TABS; + else + sa->flag &= ~AREA_CONTAINS_TABS; /* area sizes */ area_calc_totrct(sa, WM_window_pixels_x(win), WM_window_pixels_y(win)); @@ -1737,7 +1744,8 @@ void ED_region_panels(const bContext *C, ARegion *ar, const char *context, int c Panel *panel; View2D *v2d = &ar->v2d; View2DScrollers *scrollers; - int x, y, xco, yco, w, em, triangle; + int x, y, xco, yco, w, em; + int theme_col_bg = TH_BACK; bool is_context_new = 0; int redo; int scroll; @@ -1759,7 +1767,6 @@ void ED_region_panels(const bContext *C, ARegion *ar, const char *context, int c v2d->keepofs |= V2D_LOCKOFS_X | V2D_KEEPOFS_Y; v2d->keepofs &= ~(V2D_LOCKOFS_Y | V2D_KEEPOFS_X); v2d->scroll &= ~(V2D_SCROLL_BOTTOM); - v2d->scroll |= (V2D_SCROLL_RIGHT); } else { /* for now, allow scrolling in both directions (since layouts are optimized for vertical, @@ -1826,7 +1833,7 @@ void ED_region_panels(const bContext *C, ARegion *ar, const char *context, int c em = (ar->type->prefsizex) ? 10 : 20; } - w -= margin_x; + w -= margin_x + UI_PANEL_MARGIN * 2.0f; /* create panels */ UI_panels_begin(C, ar); @@ -1850,36 +1857,49 @@ void ED_region_panels(const bContext *C, ARegion *ar, const char *context, int c 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)) { + const int ar_x = (int)BLI_rctf_size_x(&ar->v2d.cur); + const int ofs_x = iroundf(MIN2(UI_UNIT_X * 0.6f, ar_x * 0.1f)); + /* using panel->sizex causes too much jittering */ + const int panel_sizex = ar_x - (int)(UI_PANEL_MARGIN * 2.0f); + /* 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); + uiLayout *row; + uiLayout *layout = UI_block_layout( + block, UI_LAYOUT_VERTICAL, UI_LAYOUT_PANEL, + -ofs_x, (UI_UNIT_Y * 1.1f) + style->panelspace, + panel_sizex, 1, 0, style); + + + row = uiLayoutRow(layout, 1); + uiLayoutSetAlignment(row, UI_LAYOUT_ALIGN_RIGHT); + panel->layout = row; 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 layout = UI_LAYOUT_VERTICAL; short panelContext; /* panel context can either be toolbar region or normal panels region */ - if (ar->regiontype == RGN_TYPE_TOOLS) + if (ar->regiontype == RGN_TYPE_TOOLS) { panelContext = UI_LAYOUT_TOOLBAR; - else + } + else if (ar->regiontype == RGN_TYPE_TABS) { + panelContext = UI_LAYOUT_HEADER; + if (sa->spacetype != SPACE_USERPREF) { + layout = UI_LAYOUT_HORIZONTAL; + } + } + else { panelContext = UI_LAYOUT_PANEL; + } panel->layout = UI_block_layout( - block, UI_LAYOUT_VERTICAL, panelContext, + block, layout, panelContext, style->panelspace, 0, w - 2 * style->panelspace, em, 0, style); pt->draw(C, panel); @@ -1935,16 +1955,21 @@ void ED_region_panels(const bContext *C, ARegion *ar, const char *context, int c } /* clear */ + if (ar->regiontype == RGN_TYPE_PREVIEW) + theme_col_bg = TH_PREVIEW_BACK; + else if (ar->regiontype == RGN_TYPE_TABS) + theme_col_bg = TH_TAB_BACK; + if (ar->overlap) { /* view should be in pixelspace */ UI_view2d_view_restore(C); glEnable(GL_BLEND); - UI_ThemeColor4((ar->type->regionid == RGN_TYPE_PREVIEW) ? TH_PREVIEW_BACK : TH_BACK); - glRecti(0, 0, BLI_rcti_size_x(&ar->winrct), BLI_rcti_size_y(&ar->winrct) + 1); + UI_ThemeColor4(theme_col_bg); + glRecti(0, 0, BLI_rcti_size_x(&ar->winrct), BLI_rcti_size_y(&ar->winrct)); glDisable(GL_BLEND); } else { - UI_ThemeClearColor((ar->type->regionid == RGN_TYPE_PREVIEW) ? TH_PREVIEW_BACK : TH_BACK); + UI_ThemeClearColor(theme_col_bg); glClear(GL_COLOR_BUFFER_BIT); } diff --git a/source/blender/editors/screen/screen_edit.c b/source/blender/editors/screen/screen_edit.c index 559c83590ad..f46486601af 100644 --- a/source/blender/editors/screen/screen_edit.c +++ b/source/blender/editors/screen/screen_edit.c @@ -64,6 +64,7 @@ #include "ED_render.h" #include "UI_interface.h" +#include "UI_resources.h" /* XXX actually should be not here... solve later */ #include "wm_subwindow.h" @@ -1011,47 +1012,38 @@ static void scrarea_draw_shape_light(ScrArea *sa, char UNUSED(dir)) glDisable(GL_BLEND); } -static void drawscredge_area_draw(int sizex, int sizey, int x1, int y1, int x2, int y2, int a) +static void drawscredge_area_draw(int sizex, int sizey, int x1, int y1, int x2, int y2) { /* right border area */ if (x2 < sizex - 1) - sdrawline(x2 + a, y1, x2 + a, y2); + sdrawline(x2, y1, x2, y2); /* left border area */ if (x1 > 0) /* otherwise it draws the emboss of window over */ - sdrawline(x1 + a, y1, x1 + a, y2); + sdrawline(x1, y1, x1, y2); /* top border area */ if (y2 < sizey - 1) - sdrawline(x1, y2 + a, x2, y2 + a); + sdrawline(x1, y2, x2, y2); /* bottom border area */ if (y1 > 0) - sdrawline(x1, y1 + a, x2, y1 + a); + sdrawline(x1, y1, x2, y1); } /** screen edges drawing **/ -static void drawscredge_area(ScrArea *sa, int sizex, int sizey, int center) +static void drawscredge_area(ScrArea *sa, int sizex, int sizey) { short x1 = sa->v1->vec.x; short y1 = sa->v1->vec.y; short x2 = sa->v3->vec.x; short y2 = sa->v3->vec.y; - - if (center == 0) { - if (U.pixelsize > 1.0f) { - - glColor3ub(0x50, 0x50, 0x50); - glLineWidth((2.0f * U.pixelsize) - 1); - drawscredge_area_draw(sizex, sizey, x1, y1, x2, y2, 0); - glLineWidth(1.0f); - } - } - else { - glColor3ub(0, 0, 0); - drawscredge_area_draw(sizex, sizey, x1, y1, x2, y2, 0); - } + + glLineWidth(UI_DPI_FAC * 2.0f); + UI_ThemeColor(TH_AREA_EDGES); + drawscredge_area_draw(sizex, sizey, x1, y1, x2, y2); + glLineWidth(1.0f); } /* ****************** EXPORTED API TO OTHER MODULES *************************** */ @@ -1136,10 +1128,8 @@ void ED_screen_draw(wmWindow *win) if (sa->flag & AREA_FLAG_DRAWJOINFROM) sa1 = sa; if (sa->flag & AREA_FLAG_DRAWJOINTO) sa2 = sa; if (sa->flag & (AREA_FLAG_DRAWSPLIT_H | AREA_FLAG_DRAWSPLIT_V)) sa3 = sa; - drawscredge_area(sa, winsize_x, winsize_y, 0); + drawscredge_area(sa, winsize_x, winsize_y); } - for (sa = win->screen->areabase.first; sa; sa = sa->next) - drawscredge_area(sa, winsize_x, winsize_y, 1); /* blended join arrow */ if (sa1 && sa2) { diff --git a/source/blender/editors/space_action/space_action.c b/source/blender/editors/space_action/space_action.c index 5d0b34a2e0c..af16f9cf73a 100644 --- a/source/blender/editors/space_action/space_action.c +++ b/source/blender/editors/space_action/space_action.c @@ -118,7 +118,7 @@ static SpaceLink *action_new(const bContext *C) ar->v2d.keepzoom = V2D_LOCKZOOM_Y; ar->v2d.keepofs = V2D_KEEPOFS_Y; ar->v2d.align = V2D_ALIGN_NO_POS_Y; - ar->v2d.flag = V2D_VIEWSYNC_AREA_VERTICAL; + ar->v2d.flag = (V2D_VIEWSYNC_AREA_VERTICAL | V2D_USES_UNITS_HORIZONTAL); return (SpaceLink *)saction; } diff --git a/source/blender/editors/space_clip/space_clip.c b/source/blender/editors/space_clip/space_clip.c index f119fe23c12..96c7e99c917 100644 --- a/source/blender/editors/space_clip/space_clip.c +++ b/source/blender/editors/space_clip/space_clip.c @@ -104,7 +104,7 @@ static void init_preview_region(const bContext *C, ARegion *ar) ar->v2d.keepzoom = V2D_LOCKZOOM_Y; ar->v2d.keepofs = V2D_KEEPOFS_Y; ar->v2d.align = V2D_ALIGN_NO_POS_Y; - ar->v2d.flag = V2D_VIEWSYNC_AREA_VERTICAL; + ar->v2d.flag = (V2D_VIEWSYNC_AREA_VERTICAL | V2D_USES_UNITS_HORIZONTAL); } else { ar->v2d.tot.xmin = 0.0f; @@ -128,7 +128,7 @@ static void init_preview_region(const bContext *C, ARegion *ar) ar->v2d.keepzoom = 0; ar->v2d.keepofs = 0; ar->v2d.align = 0; - ar->v2d.flag = 0; + ar->v2d.flag = (V2D_USES_UNITS_HORIZONTAL | V2D_USES_UNITS_VERTICAL); ar->v2d.keeptot = 0; } @@ -143,8 +143,8 @@ static void reinit_preview_region(const bContext *C, ARegion *ar) init_preview_region(C, ar); } else { - if (ar->v2d.flag & V2D_VIEWSYNC_AREA_VERTICAL) - init_preview_region(C, ar); + /* XXX check with sergey */ + init_preview_region(C, ar); } } diff --git a/source/blender/editors/space_graph/space_graph.c b/source/blender/editors/space_graph/space_graph.c index 5bbd13fa949..ac2a478ebd2 100644 --- a/source/blender/editors/space_graph/space_graph.c +++ b/source/blender/editors/space_graph/space_graph.c @@ -160,6 +160,7 @@ static SpaceLink *graph_new(const bContext *C) ar->v2d.scroll = (V2D_SCROLL_BOTTOM | V2D_SCROLL_SCALE_HORIZONTAL); ar->v2d.scroll |= (V2D_SCROLL_LEFT | V2D_SCROLL_SCALE_VERTICAL); + ar->v2d.flag |= (V2D_USES_UNITS_HORIZONTAL | V2D_USES_UNITS_VERTICAL); ar->v2d.keeptot = 0; diff --git a/source/blender/editors/space_image/image_buttons.c b/source/blender/editors/space_image/image_buttons.c index 2f87d437033..1ee9a67a7a1 100644 --- a/source/blender/editors/space_image/image_buttons.c +++ b/source/blender/editors/space_image/image_buttons.c @@ -292,9 +292,7 @@ static void ui_imageuser_slot_menu(bContext *UNUSED(C), uiLayout *layout, void * Image *image = image_p; int slot; - uiDefBut(block, UI_BTYPE_LABEL, 0, IFACE_("Slot"), - 0, 0, UI_UNIT_X * 5, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, ""); - uiItemS(layout); + uiDefMenuTitleBut(block, IFACE_("Slot")); slot = IMA_MAX_RENDER_SLOT; while (slot--) { @@ -346,9 +344,7 @@ static void ui_imageuser_layer_menu(bContext *UNUSED(C), uiLayout *layout, void UI_block_layout_set_current(block, layout); uiLayoutColumn(layout, false); - uiDefBut(block, UI_BTYPE_LABEL, 0, IFACE_("Layer"), - 0, 0, UI_UNIT_X * 5, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, ""); - uiItemS(layout); + uiDefMenuTitleBut(block, IFACE_("Layer")); nr = BLI_listbase_count(&rr->layers) - 1; fake_name = ui_imageuser_layer_fake_name(rr); @@ -413,10 +409,7 @@ static void ui_imageuser_pass_menu(bContext *UNUSED(C), uiLayout *layout, void * UI_block_layout_set_current(block, layout); uiLayoutColumn(layout, false); - uiDefBut(block, UI_BTYPE_LABEL, 0, IFACE_("Pass"), - 0, 0, UI_UNIT_X * 5, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, ""); - - uiItemS(layout); + uiDefMenuTitleBut(block, IFACE_("Pass")); nr = 0; fake_name = ui_imageuser_pass_fake_name(rl); @@ -472,10 +465,7 @@ static void ui_imageuser_view_menu_rr(bContext *UNUSED(C), uiLayout *layout, voi UI_block_layout_set_current(block, layout); uiLayoutColumn(layout, false); - uiDefBut(block, UI_BTYPE_LABEL, 0, IFACE_("View"), - 0, 0, UI_UNIT_X * 5, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, ""); - - uiItemS(layout); + uiDefMenuTitleBut(block, IFACE_("View")); nr = (rr ? BLI_listbase_count(&rr->views) : 0) - 1; for (rview = rr ? rr->views.last : NULL; rview; rview = rview->prev, nr--) { @@ -498,10 +488,7 @@ static void ui_imageuser_view_menu_multiview(bContext *UNUSED(C), uiLayout *layo UI_block_layout_set_current(block, layout); uiLayoutColumn(layout, false); - uiDefBut(block, UI_BTYPE_LABEL, 0, IFACE_("View"), - 0, 0, UI_UNIT_X * 5, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, ""); - - uiItemS(layout); + uiDefMenuTitleBut(block, IFACE_("View")); nr = BLI_listbase_count(&image->views) - 1; for (iv = image->views.last; iv; iv = iv->prev, nr--) { diff --git a/source/blender/editors/space_nla/nla_edit.c b/source/blender/editors/space_nla/nla_edit.c index f7673d86f94..29324882736 100644 --- a/source/blender/editors/space_nla/nla_edit.c +++ b/source/blender/editors/space_nla/nla_edit.c @@ -2236,7 +2236,6 @@ static int nla_fmodifier_add_invoke(bContext *C, wmOperator *UNUSED(op), const w /* add entry to add this type of modifier */ uiItemEnumO(layout, "NLA_OT_fmodifier_add", fmi->name, 0, "type", i); } - uiItemS(layout); UI_popup_menu_end(C, pup); diff --git a/source/blender/editors/space_nla/space_nla.c b/source/blender/editors/space_nla/space_nla.c index 9fc7b5d6f8f..08b2c4d0c65 100644 --- a/source/blender/editors/space_nla/space_nla.c +++ b/source/blender/editors/space_nla/space_nla.c @@ -158,7 +158,7 @@ static SpaceLink *nla_new(const bContext *C) ar->v2d.keepzoom = V2D_LOCKZOOM_Y; ar->v2d.keepofs = V2D_KEEPOFS_Y; ar->v2d.align = V2D_ALIGN_NO_POS_Y; - ar->v2d.flag = V2D_VIEWSYNC_AREA_VERTICAL; + ar->v2d.flag = (V2D_VIEWSYNC_AREA_VERTICAL | V2D_USES_UNITS_HORIZONTAL); return (SpaceLink *)snla; } diff --git a/source/blender/editors/space_sequencer/space_sequencer.c b/source/blender/editors/space_sequencer/space_sequencer.c index 05078e30192..242182f7a0e 100644 --- a/source/blender/editors/space_sequencer/space_sequencer.c +++ b/source/blender/editors/space_sequencer/space_sequencer.c @@ -193,6 +193,7 @@ static SpaceLink *sequencer_new(const bContext *C) ar->v2d.keepzoom = 0; ar->v2d.keeptot = 0; ar->v2d.align = V2D_ALIGN_NO_NEG_Y; + ar->v2d.flag |= (V2D_USES_UNITS_HORIZONTAL | V2D_USES_UNITS_VERTICAL); return (SpaceLink *)sseq; } diff --git a/source/blender/editors/space_time/space_time.c b/source/blender/editors/space_time/space_time.c index 9ecea7462ff..da4cfb27965 100644 --- a/source/blender/editors/space_time/space_time.c +++ b/source/blender/editors/space_time/space_time.c @@ -675,6 +675,7 @@ static SpaceLink *time_new(const bContext *C) ar->v2d.align |= V2D_ALIGN_NO_NEG_Y; ar->v2d.keepofs |= V2D_LOCKOFS_Y; ar->v2d.keepzoom |= V2D_LOCKZOOM_Y; + ar->v2d.flag |= V2D_USES_UNITS_HORIZONTAL; return (SpaceLink *)stime; diff --git a/source/blender/editors/space_userpref/space_userpref.c b/source/blender/editors/space_userpref/space_userpref.c index b5a6821d147..fea627a13c3 100644 --- a/source/blender/editors/space_userpref/space_userpref.c +++ b/source/blender/editors/space_userpref/space_userpref.c @@ -44,6 +44,8 @@ #include "ED_screen.h" #include "ED_space_api.h" +#include "UI_view2d.h" + #include "WM_api.h" #include "WM_types.h" @@ -66,6 +68,26 @@ static SpaceLink *userpref_new(const bContext *UNUSED(C)) ar->regiontype = RGN_TYPE_HEADER; ar->alignment = RGN_ALIGN_BOTTOM; + /* tab region */ + ar = MEM_callocN(sizeof(ARegion), "tab region for userpref"); + + BLI_addtail(&spref->regionbase, ar); + ar->regiontype = RGN_TYPE_TABS; + ar->alignment = RGN_ALIGN_TOP; + + { + View2D *v2d = &ar->v2d; + + v2d->keepzoom = (V2D_KEEPASPECT | V2D_LIMITZOOM | V2D_KEEPZOOM); + v2d->minzoom = ar->v2d.maxzoom = 1.0f; + + v2d->align = (V2D_ALIGN_NO_NEG_X | V2D_ALIGN_NO_POS_Y); + v2d->keeptot = V2D_KEEPTOT_STRICT; + + /* no scrollers! */ + v2d->scroll = 0; + } + /* main area */ ar = MEM_callocN(sizeof(ARegion), "main area for userpref"); @@ -125,6 +147,23 @@ static void userpref_keymap(struct wmKeyConfig *UNUSED(keyconf)) } +static void userpref_tab_area_init(wmWindowManager *wm, ARegion *ar) +{ + wmKeyMap *keymap; + + UI_view2d_region_reinit(&ar->v2d, V2D_COMMONVIEW_CUSTOM, ar->winx, ar->winy); + + keymap = WM_keymap_find(wm->defaultconf, "View2D Buttons List", 0, 0); + WM_event_add_keymap_handler(&ar->handlers, keymap); +} + +static void userpref_tab_area_draw(const bContext *C, ARegion *ar) +{ + ED_region_panels(C, ar, NULL, -1, true); + + ar->v2d.keepofs = (V2D_LOCKOFS_Y); +} + /* add handlers, stuff you only do once or on area/region changes */ static void userpref_header_area_init(wmWindowManager *UNUSED(wm), ARegion *ar) { @@ -178,6 +217,15 @@ void ED_spacetype_userpref(void) BLI_addhead(&st->regiontypes, art); + /* regions: tab region*/ + art = MEM_callocN(sizeof(ARegionType), "spacetype userpref region"); + art->regionid = RGN_TYPE_TABS; + art->init = userpref_tab_area_init; + art->draw = userpref_tab_area_draw; + art->keymapflag = ED_KEYMAP_UI; + + BLI_addhead(&st->regiontypes, art); + /* regions: header */ art = MEM_callocN(sizeof(ARegionType), "spacetype userpref region"); art->regionid = RGN_TYPE_HEADER; diff --git a/source/blender/makesdna/DNA_screen_types.h b/source/blender/makesdna/DNA_screen_types.h index 6095a9a8e52..71dd6f4f349 100644 --- a/source/blender/makesdna/DNA_screen_types.h +++ b/source/blender/makesdna/DNA_screen_types.h @@ -103,9 +103,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; - short labelofs, pad; short flag, runtime_flag; - short control; + short mouse_state; /* is mouse inside header/content/...? */ + short control, pad; short snap; int sortorder; /* panels are aligned according to increasing sortorder */ struct Panel *paneltab; /* this panel is tabbed in *paneltab */ @@ -286,6 +286,7 @@ enum { AREA_FLAG_STACKED_FULLSCREEN = (1 << 7), /* update action zones (even if the mouse is not intersecting them) */ AREA_FLAG_ACTIONZONES_UPDATE = (1 << 8), + AREA_CONTAINS_TABS = (1 << 9), }; #define EDGEWIDTH 1 @@ -375,7 +376,8 @@ enum { RGN_TYPE_UI = 4, RGN_TYPE_TOOLS = 5, RGN_TYPE_TOOL_PROPS = 6, - RGN_TYPE_PREVIEW = 7 + RGN_TYPE_PREVIEW = 7, + RGN_TYPE_TABS = 8 }; /* use for function args */ #define RGN_TYPE_ANY -1 diff --git a/source/blender/makesdna/DNA_userdef_types.h b/source/blender/makesdna/DNA_userdef_types.h index 722100e7625..e2c7478f5d3 100644 --- a/source/blender/makesdna/DNA_userdef_types.h +++ b/source/blender/makesdna/DNA_userdef_types.h @@ -129,7 +129,9 @@ typedef struct uiWidgetColors { char text_sel[4]; short shaded; short shadetop, shadedown; - short alpha_check; + short pad; + float roundness; + short alpha_check, pad2; } uiWidgetColors; typedef struct uiWidgetStateColors { @@ -142,6 +144,13 @@ typedef struct uiWidgetStateColors { float blend, pad; } uiWidgetStateColors; +typedef struct uiTabColors { + char tab_active[4]; + char tab_inactive[4]; + char tab_back[4]; + char tab_outline[4]; +} uiTabColors; + typedef struct uiPanelColors { char header[4]; char back[4]; @@ -161,14 +170,20 @@ typedef struct ThemeUI { /* Interface Elements (buttons, menus, icons) */ uiWidgetColors wcol_regular, wcol_tool, wcol_text; uiWidgetColors wcol_radio, wcol_option, wcol_toggle; - uiWidgetColors wcol_num, wcol_numslider; + uiWidgetColors wcol_num, wcol_numslider, wcol_tab; uiWidgetColors wcol_menu, wcol_pulldown, wcol_menu_back, wcol_menu_item, wcol_tooltip; uiWidgetColors wcol_box, wcol_scroll, wcol_progress, wcol_list_item, wcol_pie_menu; uiWidgetStateColors wcol_state; + uiTabColors tab; uiPanelColors panel; /* depricated, but we keep it for do_versions (2.66.1) */ + short interface_style; /* flat/classic - don't confuse with uiStyle */ + short pad2; + + char area_edges[4]; + char widget_emboss[4]; /* fac: 0 - 1 for blend factor, width in pixels */ @@ -200,7 +215,7 @@ typedef struct ThemeSpace { char header_text[4]; char header_text_hi[4]; - /* region tabs */ + /* region tabs - DEPRECATED, use ThemeUI->tab */ char tab_active[4]; char tab_inactive[4]; char tab_back[4]; @@ -223,7 +238,8 @@ typedef struct ThemeSpace { /* char panel_title[4]; unused */ /* char panel_text[4]; unused */ /* char panel_text_hi[4]; unused */ - + + uiTabColors tabs; /* note, cannot use name 'panel' because of DNA mapping old files */ uiPanelColors panelcolors; @@ -903,6 +919,11 @@ typedef enum eOpensubdiv_Computee_Type { USER_OPENSUBDIV_COMPUTE_GLSL_COMPUTE = 6, } eOpensubdiv_Computee_Type; +typedef enum eTheme_InterfaceStyle { + TH_IFACE_STYLE_CLASSIC = 0, + TH_IFACE_STYLE_FLAT = 1, +} eTheme_InterfaceStyle; + #ifdef __cplusplus } #endif diff --git a/source/blender/makesdna/DNA_view2d_types.h b/source/blender/makesdna/DNA_view2d_types.h index 6f2e347c84d..4a019476ee7 100644 --- a/source/blender/makesdna/DNA_view2d_types.h +++ b/source/blender/makesdna/DNA_view2d_types.h @@ -114,6 +114,9 @@ typedef struct View2D { #define V2D_PIXELOFS_Y (1<<3) /* view settings need to be set still... */ #define V2D_IS_INITIALISED (1<<10) + /* for screens that need to draw units on top of the scroller */ +#define V2D_USES_UNITS_VERTICAL (1 << 11) +#define V2D_USES_UNITS_HORIZONTAL (1 << 12) /* scroller flags for View2D (v2d->scroll) */ /* left scrollbar */ diff --git a/source/blender/makesrna/intern/rna_screen.c b/source/blender/makesrna/intern/rna_screen.c index 477a9dbca4f..7fe0fde8774 100644 --- a/source/blender/makesrna/intern/rna_screen.c +++ b/source/blender/makesrna/intern/rna_screen.c @@ -45,6 +45,7 @@ EnumPropertyItem region_type_items[] = { {RGN_TYPE_TOOLS, "TOOLS", 0, "Tools", ""}, {RGN_TYPE_TOOL_PROPS, "TOOL_PROPS", 0, "Tool Properties", ""}, {RGN_TYPE_PREVIEW, "PREVIEW", 0, "Preview", ""}, + {RGN_TYPE_TABS, "TABS", 0, "Tabs", ""}, {0, NULL, 0, NULL, NULL} }; diff --git a/source/blender/makesrna/intern/rna_space.c b/source/blender/makesrna/intern/rna_space.c index ac8b2e9ca15..8a7ef7cfac1 100644 --- a/source/blender/makesrna/intern/rna_space.c +++ b/source/blender/makesrna/intern/rna_space.c @@ -63,28 +63,38 @@ EnumPropertyItem space_type_items[] = { /* empty must be here for python, is skipped for UI */ {SPACE_EMPTY, "EMPTY", ICON_NONE, "Empty", ""}, + + /* Workspaces - for authoring new data directly */ + {0, "", ICON_NONE, "Workspaces", ""}, {SPACE_VIEW3D, "VIEW_3D", ICON_VIEW3D, "3D View", "3D viewport"}, - {0, "", ICON_NONE, NULL, NULL}, + {SPACE_IMAGE, "IMAGE_EDITOR", ICON_IMAGE_COL, "UV/Image Editor", "View and edit images and UV Maps"}, + {SPACE_NODE, "NODE_EDITOR", ICON_NODETREE, "Node Editor", "Editor for node-based shading and compositing tools"}, + {SPACE_SEQ, "SEQUENCE_EDITOR", ICON_SEQUENCE, "Video Sequencer", "Video editing tools"}, + {SPACE_CLIP, "CLIP_EDITOR", ICON_CLIP, "Movie Clip Editor", "Motion tracking tools"}, + + /* animation editors */ + {0, "", ICON_NONE, "Animation", ""}, {SPACE_TIME, "TIMELINE", ICON_TIME, "Timeline", "Timeline and playback controls"}, {SPACE_IPO, "GRAPH_EDITOR", ICON_IPO, "Graph Editor", "Edit drivers and keyframe interpolation"}, {SPACE_ACTION, "DOPESHEET_EDITOR", ICON_ACTION, "Dope Sheet", "Adjust timing of keyframes"}, {SPACE_NLA, "NLA_EDITOR", ICON_NLA, "NLA Editor", "Combine and layer Actions"}, - {0, "", ICON_NONE, NULL, NULL}, - {SPACE_IMAGE, "IMAGE_EDITOR", ICON_IMAGE_COL, "UV/Image Editor", "View and edit images and UV Maps"}, - {SPACE_SEQ, "SEQUENCE_EDITOR", ICON_SEQUENCE, "Video Sequence Editor", "Video editing tools"}, - {SPACE_CLIP, "CLIP_EDITOR", ICON_CLIP, "Movie Clip Editor", "Motion tracking tools"}, + + /* scripting */ + {0, "", ICON_NONE, "Scripting", ""}, {SPACE_TEXT, "TEXT_EDITOR", ICON_TEXT, "Text Editor", "Edit scripts and in-file documentation"}, - {SPACE_NODE, "NODE_EDITOR", ICON_NODETREE, "Node Editor", "Editor for node-based shading and compositing tools"}, {SPACE_LOGIC, "LOGIC_EDITOR", ICON_LOGIC, "Logic Editor", "Game logic editing"}, - {0, "", ICON_NONE, NULL, NULL}, - {SPACE_BUTS, "PROPERTIES", ICON_BUTS, "Properties", "Edit properties of active object and related datablocks"}, + {SPACE_CONSOLE, "CONSOLE", ICON_CONSOLE, "Python Console", "Interactive programmatic console for " + "advanced editing and script development"}, + {SPACE_INFO, "INFO", ICON_INFO, "Info", "Main menu bar and list of error messages " + "(drag down to expand and display)"}, + + /* data */ + {0, "", ICON_NONE, "Data", ""}, {SPACE_OUTLINER, "OUTLINER", ICON_OOPS, "Outliner", "Overview of scene graph and all available datablocks"}, - {SPACE_USERPREF, "USER_PREFERENCES", ICON_PREFERENCES, "User Preferences", "Edit persistent configuration settings"}, - {SPACE_INFO, "INFO", ICON_INFO, "Info", "Main menu bar and list of error messages (drag down to expand and display)"}, - {0, "", ICON_NONE, NULL, NULL}, + {SPACE_BUTS, "PROPERTIES", ICON_BUTS, "Properties", "Edit properties of active object and related datablocks"}, {SPACE_FILE, "FILE_BROWSER", ICON_FILESEL, "File Browser", "Browse for files and assets"}, - {0, "", ICON_NONE, NULL, NULL}, - {SPACE_CONSOLE, "CONSOLE", ICON_CONSOLE, "Python Console", "Interactive programmatic console for advanced editing and script development"}, + {SPACE_USERPREF, "USER_PREFERENCES", ICON_PREFERENCES, "User Preferences", "Edit persistent " + "configuration settings"}, {0, NULL, 0, NULL, NULL} }; diff --git a/source/blender/makesrna/intern/rna_ui_api.c b/source/blender/makesrna/intern/rna_ui_api.c index 81b6a77f683..4bb2e4946a3 100644 --- a/source/blender/makesrna/intern/rna_ui_api.c +++ b/source/blender/makesrna/intern/rna_ui_api.c @@ -125,6 +125,22 @@ static void rna_uiItemR(uiLayout *layout, PointerRNA *ptr, const char *propname, uiItemFullR(layout, ptr, prop, index, 0, flag, name, icon); } +static void rna_uiItemTabsR(uiLayout *layout, PointerRNA *ptr, const char *propname, const char *name, const char *text_ctxt, + int translate, int icon, int alignment, int icon_only) +{ + PropertyRNA *prop = RNA_struct_find_property(ptr, propname); + + if (!prop) { + RNA_warning("property not found: %s.%s", RNA_struct_identifier(ptr->type), propname); + return; + } + + /* Get translated name (label). */ + name = rna_translate_ui_text(name, text_ctxt, NULL, prop, translate); + + uiItemTabsR(layout, ptr, prop, name, icon, alignment, icon_only); +} + static void rna_uiItemMenuEnumR(uiLayout *layout, struct PointerRNA *ptr, const char *propname, const char *name, const char *text_ctxt, int translate, int icon) { @@ -429,6 +445,14 @@ void RNA_api_ui_layout(StructRNA *srna) {0, NULL, 0, NULL, NULL} }; + static EnumPropertyItem tabs_alignment_items[] = { + {UI_BUT_ALIGN_TOP, "TOP", 0, "Top", ""}, + {UI_BUT_ALIGN_DOWN, "DOWN", 0, "Down", ""}, + {UI_BUT_ALIGN_LEFT, "LEFT", 0, "Left", ""}, + {UI_BUT_ALIGN_RIGHT, "RIGHT", 0, "Right", ""}, + {0, NULL, 0, NULL, NULL} + }; + static float node_socket_color_default[] = { 0.0f, 0.0f, 0.0f, 1.0f }; /* simple layout specifiers */ @@ -544,6 +568,14 @@ void RNA_api_ui_layout(StructRNA *srna) RNA_def_property_flag(parm, PROP_REQUIRED); api_ui_item_common(func); + func = RNA_def_function(srna, "prop_tabs", "rna_uiItemTabsR"); + RNA_def_function_ui_description(func, "Item. Exposes an RNA item and draws it as a tab into the layout"); + api_ui_item_rna_common(func); + api_ui_item_common(func); + RNA_def_enum(func, "alignment", tabs_alignment_items, UI_BUT_ALIGN_DOWN, "Alignment", + "The direction to which the tabs will be aligned to"); + RNA_def_boolean(func, "icon_only", false, "", "Draw only icons in tabs, no text"); + func = RNA_def_function(srna, "prop_search", "rna_uiItemPointerR"); api_ui_item_rna_common(func); parm = RNA_def_pointer(func, "search_data", "AnyType", "", "Data from which to take collection to search in"); diff --git a/source/blender/makesrna/intern/rna_userdef.c b/source/blender/makesrna/intern/rna_userdef.c index 76870e5299f..5c88e03efab 100644 --- a/source/blender/makesrna/intern/rna_userdef.c +++ b/source/blender/makesrna/intern/rna_userdef.c @@ -882,6 +882,11 @@ static void rna_def_userdef_theme_ui_wcol(BlenderRNA *brna) RNA_def_property_range(prop, -100, 100); RNA_def_property_ui_text(prop, "Shade Down", ""); RNA_def_property_update(prop, 0, "rna_userdef_update"); + + prop = RNA_def_property(srna, "roundness", PROP_FLOAT, PROP_FACTOR); + RNA_def_property_range(prop, 0.1f, 0.5f); + RNA_def_property_ui_text(prop, "Roundness", ""); + RNA_def_property_update(prop, 0, "rna_userdef_update"); } static void rna_def_userdef_theme_ui_wcol_state(BlenderRNA *brna) @@ -929,6 +934,38 @@ static void rna_def_userdef_theme_ui_wcol_state(BlenderRNA *brna) RNA_def_property_update(prop, 0, "rna_userdef_update"); } +static void rna_def_userdef_theme_ui_tabs(BlenderRNA *brna) +{ + StructRNA *srna; + PropertyRNA *prop; + + srna = RNA_def_struct(brna, "ThemeTabColors", NULL); + RNA_def_struct_sdna(srna, "uiTabColors"); + RNA_def_struct_clear_flag(srna, STRUCT_UNDO); + RNA_def_struct_ui_text(srna, "Theme Tab Color", "Theme settings for tab colors"); + + prop = RNA_def_property(srna, "tab_active", PROP_FLOAT, PROP_COLOR_GAMMA); + RNA_def_property_array(prop, 3); + RNA_def_property_ui_text(prop, "Tab Active", ""); + RNA_def_property_update(prop, 0, "rna_userdef_update"); + + prop = RNA_def_property(srna, "tab_inactive", PROP_FLOAT, PROP_COLOR_GAMMA); + RNA_def_property_array(prop, 3); + RNA_def_property_ui_text(prop, "Tab Inactive", ""); + RNA_def_property_update(prop, 0, "rna_userdef_update"); + + prop = RNA_def_property(srna, "tab_back", PROP_FLOAT, PROP_COLOR_GAMMA); + RNA_def_property_array(prop, 4); + RNA_def_property_ui_text(prop, "Tab Background", ""); + RNA_def_property_update(prop, 0, "rna_userdef_update"); + + prop = RNA_def_property(srna, "tab_outline", PROP_FLOAT, PROP_COLOR_GAMMA); + RNA_def_property_array(prop, 3); + RNA_def_property_ui_text(prop, "Tab Outline", ""); + RNA_def_property_update(prop, 0, "rna_userdef_update"); + +} + static void rna_def_userdef_theme_ui_panel(BlenderRNA *brna) { StructRNA *srna; @@ -940,10 +977,12 @@ static void rna_def_userdef_theme_ui_panel(BlenderRNA *brna) RNA_def_struct_ui_text(srna, "Theme Panel Color", "Theme settings for panel colors"); prop = RNA_def_property(srna, "header", PROP_FLOAT, PROP_COLOR_GAMMA); + RNA_def_property_array(prop, 3); RNA_def_property_ui_text(prop, "Header", ""); RNA_def_property_update(prop, 0, "rna_userdef_update"); prop = RNA_def_property(srna, "back", PROP_FLOAT, PROP_COLOR_GAMMA); + RNA_def_property_array(prop, 3); RNA_def_property_ui_text(prop, "Background", ""); RNA_def_property_update(prop, 0, "rna_userdef_update"); @@ -987,8 +1026,15 @@ static void rna_def_userdef_theme_ui(BlenderRNA *brna) StructRNA *srna; PropertyRNA *prop; + static EnumPropertyItem interface_style_items[] = { + {TH_IFACE_STYLE_CLASSIC, "CLASSIC", 0, "Classic", "Use a classic interface drawing style"}, + {TH_IFACE_STYLE_FLAT, "FLAT", 0, "Flat", "Use a flat interface drawing style"}, + {0, NULL, 0, NULL, NULL} + }; + rna_def_userdef_theme_ui_wcol(brna); rna_def_userdef_theme_ui_wcol_state(brna); + rna_def_userdef_theme_ui_tabs(brna); rna_def_userdef_theme_ui_panel(brna); rna_def_userdef_theme_ui_gradient(brna); @@ -1092,6 +1138,18 @@ static void rna_def_userdef_theme_ui(BlenderRNA *brna) RNA_def_property_ui_text(prop, "State Colors", ""); RNA_def_property_update(prop, 0, "rna_userdef_update"); + prop = RNA_def_property(srna, "interface_style", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "interface_style"); + RNA_def_property_enum_items(prop, interface_style_items); + RNA_def_property_ui_text(prop, "Interface Style", "Adjusts the interface drawing for different styles"); + RNA_def_property_update(prop, 0, "rna_userdef_update"); + + prop = RNA_def_property(srna, "area_edges", PROP_FLOAT, PROP_COLOR_GAMMA); + RNA_def_property_float_sdna(prop, NULL, "area_edges"); + RNA_def_property_array(prop, 3); + RNA_def_property_ui_text(prop, "Area Edges", "Color of the 1px separator between areas"); + RNA_def_property_update(prop, 0, "rna_userdef_update"); + prop = RNA_def_property(srna, "menu_shadow_fac", PROP_FLOAT, PROP_FACTOR); RNA_def_property_ui_text(prop, "Menu Shadow Strength", "Blending factor for menu shadows"); RNA_def_property_range(prop, 0.01f, 1.0f); @@ -1172,6 +1230,12 @@ 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_update"); + /* tabs */ + prop = RNA_def_property(srna, "tabs", PROP_POINTER, PROP_NONE); + RNA_def_property_flag(prop, PROP_NEVER_NULL); + RNA_def_property_ui_text(prop, "Tab Colors", ""); + RNA_def_property_update(prop, 0, "rna_userdef_update"); + /* panel settings */ prop = RNA_def_property(srna, "panelcolors", PROP_POINTER, PROP_NONE); RNA_def_property_flag(prop, PROP_NEVER_NULL); @@ -1199,28 +1263,6 @@ static void rna_def_userdef_theme_space_common(StructRNA *srna) RNA_def_property_array(prop, 3); RNA_def_property_ui_text(prop, "Region Text Highlight", ""); RNA_def_property_update(prop, 0, "rna_userdef_update"); - - /* tabs */ - prop = RNA_def_property(srna, "tab_active", PROP_FLOAT, PROP_COLOR_GAMMA); - RNA_def_property_array(prop, 3); - RNA_def_property_ui_text(prop, "Tab Active", ""); - RNA_def_property_update(prop, 0, "rna_userdef_update"); - - prop = RNA_def_property(srna, "tab_inactive", PROP_FLOAT, PROP_COLOR_GAMMA); - RNA_def_property_array(prop, 3); - RNA_def_property_ui_text(prop, "Tab Inactive", ""); - RNA_def_property_update(prop, 0, "rna_userdef_update"); - - prop = RNA_def_property(srna, "tab_back", PROP_FLOAT, PROP_COLOR_GAMMA); - RNA_def_property_array(prop, 4); - RNA_def_property_ui_text(prop, "Tab Background", ""); - RNA_def_property_update(prop, 0, "rna_userdef_update"); - - prop = RNA_def_property(srna, "tab_outline", PROP_FLOAT, PROP_COLOR_GAMMA); - RNA_def_property_array(prop, 3); - RNA_def_property_ui_text(prop, "Tab Outline", ""); - RNA_def_property_update(prop, 0, "rna_userdef_update"); - /* } */ } diff --git a/source/blender/windowmanager/intern/wm_event_system.c b/source/blender/windowmanager/intern/wm_event_system.c index 58b413c32f2..98f88c9a081 100644 --- a/source/blender/windowmanager/intern/wm_event_system.c +++ b/source/blender/windowmanager/intern/wm_event_system.c @@ -1150,10 +1150,10 @@ static int wm_operator_invoke( ((op->flag & OP_IS_MODAL_GRAB_CURSOR) || (ot->flag & OPTYPE_GRAB_CURSOR)); } - /* exception, cont. grab in header is annoying */ + /* exception, cont. grab in header or tab regions is annoying */ if (wrap) { ARegion *ar = CTX_wm_region(C); - if (ar && ar->regiontype == RGN_TYPE_HEADER) { + if (ar && ELEM(ar->regiontype, RGN_TYPE_HEADER, RGN_TYPE_TABS)) { wrap = false; } } diff --git a/source/blender/windowmanager/intern/wm_init_exit.c b/source/blender/windowmanager/intern/wm_init_exit.c index fec2671edba..a60a2d28acb 100644 --- a/source/blender/windowmanager/intern/wm_init_exit.c +++ b/source/blender/windowmanager/intern/wm_init_exit.c @@ -519,9 +519,6 @@ void WM_exit_ext(bContext *C, const bool do_python) ED_clipboard_posebuf_free(); BKE_node_clipboard_clear(); - /* widgetmaps after freeing blender, so no deleted data get accessed during cleaning up of areas */ - WM_widgetmaptypes_free(); - BLF_exit(); #ifdef WITH_INTERNATIONAL |