diff --git a/source/blender/blenkernel/intern/screen.c b/source/blender/blenkernel/intern/screen.c index f471580547c..ef5507a649f 100644 --- a/source/blender/blenkernel/intern/screen.c +++ b/source/blender/blenkernel/intern/screen.c @@ -308,6 +308,7 @@ void BKE_area_region_free(SpaceType *st, ARegion *ar) } } BLI_freelistN(&ar->ui_lists); + BLI_freelistN(&ar->ui_previews); BLI_freelistN(&ar->panels_category); BLI_freelistN(&ar->panels_category_active); } diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index 13827f833e0..bcbfdc78013 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -6168,6 +6168,8 @@ static void direct_link_region(FileData *fd, ARegion *ar, int spacetype) IDP_DirectLinkGroup_OrFree(&ui_list->properties, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd); } + link_list(fd, &ar->ui_previews); + if (spacetype == SPACE_EMPTY) { /* unkown space type, don't leak regiondata */ ar->regiondata = NULL; diff --git a/source/blender/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c index 6c4fac60646..894868948f9 100644 --- a/source/blender/blenloader/intern/writefile.c +++ b/source/blender/blenloader/intern/writefile.c @@ -2487,6 +2487,7 @@ static void write_screens(WriteData *wd, ListBase *scrbase) SpaceLink *sl; Panel *pa; uiList *ui_list; + uiPreview *ui_preview; PanelCategoryStack *pc_act; ARegion *ar; @@ -2503,6 +2504,9 @@ static void write_screens(WriteData *wd, ListBase *scrbase) for (ui_list = ar->ui_lists.first; ui_list; ui_list = ui_list->next) write_uilist(wd, ui_list); + + for (ui_preview = ar->ui_previews.first; ui_preview; ui_preview = ui_preview->next) + writestruct(wd, DATA, "uiPreview", 1, ui_preview); } sl= sa->spacedata.first; diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h index 2177b066c1f..7eb39fd4b3c 100644 --- a/source/blender/editors/include/UI_interface.h +++ b/source/blender/editors/include/UI_interface.h @@ -270,6 +270,7 @@ typedef enum { SEARCH_MENU_UNLINK = (52 << 9), NODESOCKET = (53 << 9), SEPRLINE = (54 << 9), + GRIP = (55 << 9), } eButType; #define BUTTYPE (63 << 9) @@ -832,7 +833,8 @@ void uiTemplatePathBuilder(uiLayout *layout, struct PointerRNA *ptr, const char struct PointerRNA *root_ptr, const char *text); uiLayout *uiTemplateModifier(uiLayout *layout, struct bContext *C, struct PointerRNA *ptr); uiLayout *uiTemplateConstraint(uiLayout *layout, struct PointerRNA *ptr); -void uiTemplatePreview(uiLayout *layout, struct ID *id, int show_buttons, struct ID *parent, struct MTex *slot); +void uiTemplatePreview(uiLayout *layout, struct bContext *C, struct ID *id, int show_buttons, struct ID *parent, + struct MTex *slot, const char *preview_id); void uiTemplateColorRamp(uiLayout *layout, struct PointerRNA *ptr, const char *propname, int expand); void uiTemplateIconView(uiLayout *layout, struct PointerRNA *ptr, const char *propname); void uiTemplateHistogram(uiLayout *layout, struct PointerRNA *ptr, const char *propname); diff --git a/source/blender/editors/interface/interface.c b/source/blender/editors/interface/interface.c index 530f529f345..8a4233a97b0 100644 --- a/source/blender/editors/interface/interface.c +++ b/source/blender/editors/interface/interface.c @@ -2994,7 +2994,7 @@ static uiBut *ui_def_but(uiBlock *block, int type, int retval, const char *str, } /* keep track of UI_interface.h */ - if (ELEM10(but->type, BLOCK, BUT, LABEL, PULLDOWN, ROUNDBOX, LISTBOX, BUTM, SCROLL, SEPR, SEPRLINE)) {} + if (ELEM11(but->type, BLOCK, BUT, LABEL, PULLDOWN, ROUNDBOX, LISTBOX, BUTM, SCROLL, SEPR, SEPRLINE, GRIP)) {} else if (but->type >= SEARCH_MENU) {} else but->flag |= UI_BUT_UNDO; diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c index e7c9900c325..c911e0d9ac9 100644 --- a/source/blender/editors/interface/interface_handlers.c +++ b/source/blender/editors/interface/interface_handlers.c @@ -1567,6 +1567,7 @@ static void ui_apply_button(bContext *C, uiBlock *block, uiBut *but, uiHandleBut ui_apply_but_ROW(C, block, but, data); break; case SCROLL: + case GRIP: case NUM: case NUMSLI: ui_apply_but_NUM(C, but, data); @@ -3935,6 +3936,51 @@ static int ui_do_but_SCROLL(bContext *C, uiBlock *block, uiBut *but, uiHandleBut return retval; } +static int ui_do_but_GRIP(bContext *C, uiBlock *block, uiBut *but, uiHandleButtonData *data, const wmEvent *event) +{ + int mx, my; + int retval = WM_UI_HANDLER_CONTINUE; + const bool horizontal = (BLI_rctf_size_x(&but->rect) < BLI_rctf_size_y(&but->rect)); + + mx = event->x; + my = event->y; + ui_window_to_block(data->region, block, &mx, &my); + + if (data->state == BUTTON_STATE_HIGHLIGHT) { + if (event->val == KM_PRESS) { + if (event->type == LEFTMOUSE) { + data->dragstartx = event->x; + data->dragstarty = event->y; + button_activate_state(C, but, BUTTON_STATE_NUM_EDITING); + retval = WM_UI_HANDLER_BREAK; + } + } + } + else if (data->state == BUTTON_STATE_NUM_EDITING) { + if (event->type == ESCKEY) { + if (event->val == KM_PRESS) { + data->cancel = true; + data->escapecancel = true; + button_activate_state(C, but, BUTTON_STATE_EXIT); + } + } + else if (event->type == LEFTMOUSE && event->val != KM_PRESS) { + button_activate_state(C, but, BUTTON_STATE_EXIT); + } + else if (event->type == MOUSEMOVE) { + int dragstartx = data->dragstartx; + int dragstarty = data->dragstarty; + ui_window_to_block(data->region, block, &dragstartx, &dragstarty); + data->value = data->origvalue + (horizontal ? mx - dragstartx : dragstarty - my); + ui_numedit_apply(C, block, but, data); + } + + retval = WM_UI_HANDLER_BREAK; + } + + return retval; +} + static int ui_do_but_LISTROW(bContext *C, uiBut *but, uiHandleButtonData *data, const wmEvent *event) { if (data->state == BUTTON_STATE_HIGHLIGHT) { @@ -6192,6 +6238,9 @@ static int ui_do_button(bContext *C, uiBlock *block, uiBut *but, const wmEvent * case SCROLL: retval = ui_do_but_SCROLL(C, block, but, data, event); break; + case GRIP: + retval = ui_do_but_GRIP(C, block, but, data, event); + break; case NUM: retval = ui_do_but_NUM(C, block, but, data, event); break; @@ -6819,6 +6868,11 @@ static void button_activate_init(bContext *C, ARegion *ar, uiBut *but, uiButtonA button_activate_state(C, but, BUTTON_STATE_TEXT_EDITING); else if (type == BUTTON_ACTIVATE_APPLY) button_activate_state(C, but, BUTTON_STATE_WAIT_FLASH); + + if (but->type == GRIP) { + const bool horizontal = (BLI_rctf_size_x(&but->rect) < BLI_rctf_size_y(&but->rect)); + WM_cursor_modal_set(data->window, horizontal ? BC_EW_ARROWCURSOR : BC_NS_ARROWCURSOR); + } } static void button_activate_exit(bContext *C, uiBut *but, uiHandleButtonData *data, @@ -6827,6 +6881,10 @@ static void button_activate_exit(bContext *C, uiBut *but, uiHandleButtonData *da uiBlock *block = but->block; uiBut *bt; + if (but->type == GRIP) { + WM_cursor_modal_restore(data->window); + } + /* ensure we are in the exit state */ if (data->state != BUTTON_STATE_EXIT) button_activate_state(C, but, BUTTON_STATE_EXIT); diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c index a4937514a9d..9fd8acce3ee 100644 --- a/source/blender/editors/interface/interface_templates.c +++ b/source/blender/editors/interface/interface_templates.c @@ -55,6 +55,7 @@ #include "BKE_displist.h" #include "BKE_dynamicpaint.h" #include "BKE_global.h" +#include "BKE_idcode.h" #include "BKE_library.h" #include "BKE_main.h" #include "BKE_material.h" @@ -1290,10 +1291,14 @@ static void do_preview_buttons(bContext *C, void *arg, int event) } } -void uiTemplatePreview(uiLayout *layout, ID *id, int show_buttons, ID *parent, MTex *slot) +void uiTemplatePreview(uiLayout *layout, bContext *C, ID *id, int show_buttons, ID *parent, MTex *slot, + const char *preview_id) { uiLayout *row, *col; uiBlock *block; + uiPreview *ui_preview = NULL; + ARegion *ar; + Material *ma = NULL; Tex *tex = (Tex *)id; ID *pid, *pparent; @@ -1301,6 +1306,8 @@ void uiTemplatePreview(uiLayout *layout, ID *id, int show_buttons, ID *parent, M PointerRNA material_ptr; PointerRNA texture_ptr; + char _preview_id[UI_MAX_NAME_STR]; + if (id && !ELEM4(GS(id->name), ID_MA, ID_TE, ID_WO, ID_LA)) { RNA_warning("Expected ID of type material, texture, lamp or world"); return; @@ -1326,17 +1333,44 @@ void uiTemplatePreview(uiLayout *layout, ID *id, int show_buttons, ID *parent, M } } + if (!preview_id || (preview_id[0] == '\0')) { + /* If no identifier given, generate one from ID type. */ + BLI_snprintf(_preview_id, UI_MAX_NAME_STR, "uiPreview_%s", BKE_idcode_to_name(GS(id->name))); + preview_id = _preview_id; + } + + /* Find or add the uiPreview to the current Region. */ + ar = CTX_wm_region(C); + ui_preview = BLI_findstring(&ar->ui_previews, preview_id, offsetof(uiPreview, preview_id)); + + if (!ui_preview) { + ui_preview = MEM_callocN(sizeof(uiPreview), "uiPreview"); + BLI_strncpy(ui_preview->preview_id, preview_id, sizeof(ui_preview->preview_id)); + ui_preview->height = (short)(UI_UNIT_Y * 5.6f); + BLI_addtail(&ar->ui_previews, ui_preview); + } + + if (ui_preview->height < UI_UNIT_Y) { + ui_preview->height = UI_UNIT_Y; + } + else if (ui_preview->height > UI_UNIT_Y * 50) { /* Rather high upper limit, yet not insane! */ + ui_preview->height = UI_UNIT_Y * 50; + } + /* layout */ block = uiLayoutGetBlock(layout); row = uiLayoutRow(layout, false); col = uiLayoutColumn(row, false); uiLayoutSetKeepAspect(col, true); - + /* add preview */ - uiDefBut(block, BUT_EXTRA, 0, "", 0, 0, UI_UNIT_X * 6, UI_UNIT_Y * 6, pid, 0.0, 0.0, 0, 0, ""); + uiDefBut(block, BUT_EXTRA, 0, "", 0, 0, UI_UNIT_X * 10, ui_preview->height, pid, 0.0, 0.0, 0, 0, ""); uiBlockSetDrawExtraFunc(block, ED_preview_draw, pparent, slot); uiBlockSetHandleFunc(block, do_preview_buttons, NULL); - + + uiDefIconButS(block, GRIP, 0, ICON_GRIP, 0, 0, UI_UNIT_X * 10, (short)(UI_UNIT_Y * 0.3f), &ui_preview->height, + UI_UNIT_Y, UI_UNIT_Y * 50.0f, 0.0f, 0.0f, ""); + /* add buttons */ if (pid && show_buttons) { if (GS(pid->name) == ID_MA || (pparent && GS(pparent->name) == ID_MA)) { diff --git a/source/blender/editors/interface/interface_widgets.c b/source/blender/editors/interface/interface_widgets.c index 5f970e4ef3a..ff749289636 100644 --- a/source/blender/editors/interface/interface_widgets.c +++ b/source/blender/editors/interface/interface_widgets.c @@ -3552,6 +3552,10 @@ void ui_draw_but(const bContext *C, ARegion *ar, uiStyle *style, uiBut *but, rct wt = widget_type(UI_WTYPE_SCROLL); break; + case GRIP: + wt = widget_type(UI_WTYPE_ICON); + break; + case TRACKPREVIEW: ui_draw_but_TRACKPREVIEW(ar, but, &tui->wcol_regular, rect); break; diff --git a/source/blender/makesdna/DNA_screen_types.h b/source/blender/makesdna/DNA_screen_types.h index beb230e467c..f676399ac1b 100644 --- a/source/blender/makesdna/DNA_screen_types.h +++ b/source/blender/makesdna/DNA_screen_types.h @@ -186,6 +186,14 @@ typedef struct uiList { /* some list UI data need to be saved in file uiListDyn *dyn_data; } uiList; +typedef struct uiPreview { /* some preview UI data need to be saved in file */ + struct uiPreview *next, *prev; + + char preview_id[64]; /* defined as UI_MAX_NAME_STR */ + short height; + short pad1[3]; +} uiPreview; + typedef struct ScrArea { struct ScrArea *next, *prev; @@ -241,6 +249,7 @@ typedef struct ARegion { ListBase panels; /* Panel */ ListBase panels_category_active; /* Stack of panel categories */ ListBase ui_lists; /* uiList */ + ListBase ui_previews; /* uiPreview */ ListBase handlers; /* wmEventHandler */ ListBase panels_category; /* Panel categories runtime */ diff --git a/source/blender/makesrna/intern/rna_ui_api.c b/source/blender/makesrna/intern/rna_ui_api.c index 7f9b5eb8850..3cdff730b00 100644 --- a/source/blender/makesrna/intern/rna_ui_api.c +++ b/source/blender/makesrna/intern/rna_ui_api.c @@ -683,12 +683,16 @@ void RNA_api_ui_layout(StructRNA *srna) RNA_def_function_return(func, parm); func = RNA_def_function(srna, "template_preview", "uiTemplatePreview"); - RNA_def_function_ui_description(func, "Item. A preview window for materials, textures, lamps, etc"); + RNA_def_function_ui_description(func, "Item. A preview window for materials, textures, lamps or worlds"); + RNA_def_function_flag(func, FUNC_USE_CONTEXT); parm = RNA_def_pointer(func, "id", "ID", "", "ID datablock"); RNA_def_property_flag(parm, PROP_REQUIRED); RNA_def_boolean(func, "show_buttons", true, "", "Show preview buttons?"); RNA_def_pointer(func, "parent", "ID", "", "ID datablock"); RNA_def_pointer(func, "slot", "TextureSlot", "", "Texture slot"); + RNA_def_string(func, "preview_id", NULL, 0, "", + "Identifier of this preview widget, if not set the ID type will be used " + "(i.e. all previews of materials without explicit ID will have the same size...)"); func = RNA_def_function(srna, "template_curve_mapping", "uiTemplateCurveMapping"); RNA_def_function_ui_description(func, "Item. A curve mapping widget used for e.g falloff curves for lamps"); diff --git a/source/blenderplayer/bad_level_call_stubs/stubs.c b/source/blenderplayer/bad_level_call_stubs/stubs.c index 619624b01b5..2c3e4677837 100644 --- a/source/blenderplayer/bad_level_call_stubs/stubs.c +++ b/source/blenderplayer/bad_level_call_stubs/stubs.c @@ -521,7 +521,8 @@ void uiTemplateHeader(struct uiLayout *layout, struct bContext *C) RET_NONE void uiTemplateID(uiLayout *layout, struct bContext *C, struct PointerRNA *ptr, const char *propname, const char *newop, const char *openop, const char *unlinkop) RET_NONE struct uiLayout *uiTemplateModifier(uiLayout *layout, struct bContext *C, struct PointerRNA *ptr) RET_NULL struct uiLayout *uiTemplateConstraint(struct uiLayout *layout, struct PointerRNA *ptr) RET_NULL -void uiTemplatePreview(struct uiLayout *layout, struct ID *id, int show_buttons, struct ID *parent, struct MTex *slot) RET_NONE +void uiTemplatePreview(struct uiLayout *layout, struct bContext *C, struct ID *id, int show_buttons, struct ID *parent, + struct MTex *slot, const char *preview_id) RET_NONE void uiTemplateIDPreview(uiLayout *layout, struct bContext *C, struct PointerRNA *ptr, const char *propname, const char *newop, const char *openop, const char *unlinkop, int rows, int cols) RET_NONE void uiTemplateCurveMapping(uiLayout *layout, struct PointerRNA *ptr, const char *propname, int type, int levels, int brush) RET_NONE void uiTemplateColorRamp(uiLayout *layout, struct PointerRNA *ptr, const char *propname, int expand) RET_NONE