Add drag-resize to uiTemplatePreview (mat/tex/etc. preview widget).
authorBastien Montagne <montagne29@wanadoo.fr>
Wed, 2 Apr 2014 10:59:48 +0000 (12:59 +0200)
committerBastien Montagne <montagne29@wanadoo.fr>
Wed, 2 Apr 2014 11:03:11 +0000 (13:03 +0200)
This is done by adding a new button type, GRIP, similar to other numbuttons
(scroll, slider, ...), which here controls the preview height.

Then, we add a new DNA struct to be able to save that height in Blend files
(note I choose not to use Panel struct for this, because we would then have the
same limitation we used to have with uiLists, only one preview per panel
and no preview outside panel).

This implies a change to template_preview UI RNA/py API (each preview needs an ID),
but this is backward compatible, as by default datablock type will be used if no ID is
given (which means e.g. all material previews with no ID will have same height).

Reviewers: brecht

Reviewed By: brecht

Differential Revision: https://developer.blender.org/D342

source/blender/blenkernel/intern/screen.c
source/blender/blenloader/intern/readfile.c
source/blender/blenloader/intern/writefile.c
source/blender/editors/include/UI_interface.h
source/blender/editors/interface/interface.c
source/blender/editors/interface/interface_handlers.c
source/blender/editors/interface/interface_templates.c
source/blender/editors/interface/interface_widgets.c
source/blender/makesdna/DNA_screen_types.h
source/blender/makesrna/intern/rna_ui_api.c
source/blenderplayer/bad_level_call_stubs/stubs.c

index f471580547c15fb6977d80f1a5ed780a83a3346c..ef5507a649fab8b1b2e8af4fc3c3356f0e15dc2d 100644 (file)
@@ -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);
 }
index 13827f833e0fa8c0c5643027a28d071d69fd28d8..bcbfdc7801385c4a724d202e4a41086a755041d0 100644 (file)
@@ -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;
index 6c4fac6064622a8717543340dc06514a5b2f70a1..894868948f9ea81031c4a69191fc29c7a3215302 100644 (file)
@@ -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;
index 2177b066c1fd05aac66dc0052e5e6ce5c37cedb8..7eb39fd4b3c98a3c95eb9995c231801b9c7a8445 100644 (file)
@@ -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);
index 530f529f34540bc504391711d25cc394757bfe57..8a4233a97b0b626525cebc7148d387abab13f709 100644 (file)
@@ -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;
 
index e7c9900c32568c9ae98a763b61b384b5e1579015..c911e0d9ac96afc97541f70cc9d775ce1593be3a 100644 (file)
@@ -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);
index a4937514a9d8b8f22dc818105a5dd99c11be997b..9fd8acce3eec6fefd854510b514385e4b3685bc8 100644 (file)
@@ -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)) {
index 5f970e4ef3a4e22bee482cc466781810513a7cd7..ff74928963651ebeb5d61f80e5b22ea88bcb03c8 100644 (file)
@@ -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;
index beb230e467c4ad04fb005b1c835b17188fb0040f..f676399ac1ba793e6b490dfe27fb48d8e751c714 100644 (file)
@@ -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 */
        
index 7f9b5eb88504d6292ce0294cbe87bc625cdf66cc..3cdff730b000908362173a4dfeeb558966c25dc5 100644 (file)
@@ -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");
index 619624b01b5d150c4247323b997b5c713185f8c9..2c3e4677837258973f0a7a5d68e85ab40ee59bce 100644 (file)
@@ -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