Add drag-resize to uiTemplatePreview (mat/tex/etc. preview widget).

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
This commit is contained in:
Bastien Montagne 2014-04-02 12:59:48 +02:00
parent 11ee2d8b97
commit 4faef1e10c
11 changed files with 127 additions and 8 deletions

@ -308,6 +308,7 @@ void BKE_area_region_free(SpaceType *st, ARegion *ar)
} }
} }
BLI_freelistN(&ar->ui_lists); BLI_freelistN(&ar->ui_lists);
BLI_freelistN(&ar->ui_previews);
BLI_freelistN(&ar->panels_category); BLI_freelistN(&ar->panels_category);
BLI_freelistN(&ar->panels_category_active); BLI_freelistN(&ar->panels_category_active);
} }

@ -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); IDP_DirectLinkGroup_OrFree(&ui_list->properties, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd);
} }
link_list(fd, &ar->ui_previews);
if (spacetype == SPACE_EMPTY) { if (spacetype == SPACE_EMPTY) {
/* unkown space type, don't leak regiondata */ /* unkown space type, don't leak regiondata */
ar->regiondata = NULL; ar->regiondata = NULL;

@ -2487,6 +2487,7 @@ static void write_screens(WriteData *wd, ListBase *scrbase)
SpaceLink *sl; SpaceLink *sl;
Panel *pa; Panel *pa;
uiList *ui_list; uiList *ui_list;
uiPreview *ui_preview;
PanelCategoryStack *pc_act; PanelCategoryStack *pc_act;
ARegion *ar; 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) for (ui_list = ar->ui_lists.first; ui_list; ui_list = ui_list->next)
write_uilist(wd, ui_list); 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; sl= sa->spacedata.first;

@ -270,6 +270,7 @@ typedef enum {
SEARCH_MENU_UNLINK = (52 << 9), SEARCH_MENU_UNLINK = (52 << 9),
NODESOCKET = (53 << 9), NODESOCKET = (53 << 9),
SEPRLINE = (54 << 9), SEPRLINE = (54 << 9),
GRIP = (55 << 9),
} eButType; } eButType;
#define BUTTYPE (63 << 9) #define BUTTYPE (63 << 9)
@ -832,7 +833,8 @@ void uiTemplatePathBuilder(uiLayout *layout, struct PointerRNA *ptr, const char
struct PointerRNA *root_ptr, const char *text); struct PointerRNA *root_ptr, const char *text);
uiLayout *uiTemplateModifier(uiLayout *layout, struct bContext *C, struct PointerRNA *ptr); uiLayout *uiTemplateModifier(uiLayout *layout, struct bContext *C, struct PointerRNA *ptr);
uiLayout *uiTemplateConstraint(uiLayout *layout, 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 uiTemplateColorRamp(uiLayout *layout, struct PointerRNA *ptr, const char *propname, int expand);
void uiTemplateIconView(uiLayout *layout, struct PointerRNA *ptr, const char *propname); void uiTemplateIconView(uiLayout *layout, struct PointerRNA *ptr, const char *propname);
void uiTemplateHistogram(uiLayout *layout, struct PointerRNA *ptr, const char *propname); void uiTemplateHistogram(uiLayout *layout, struct PointerRNA *ptr, const char *propname);

@ -2994,7 +2994,7 @@ static uiBut *ui_def_but(uiBlock *block, int type, int retval, const char *str,
} }
/* keep track of UI_interface.h */ /* 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 if (but->type >= SEARCH_MENU) {}
else but->flag |= UI_BUT_UNDO; else but->flag |= UI_BUT_UNDO;

@ -1567,6 +1567,7 @@ static void ui_apply_button(bContext *C, uiBlock *block, uiBut *but, uiHandleBut
ui_apply_but_ROW(C, block, but, data); ui_apply_but_ROW(C, block, but, data);
break; break;
case SCROLL: case SCROLL:
case GRIP:
case NUM: case NUM:
case NUMSLI: case NUMSLI:
ui_apply_but_NUM(C, but, data); 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; 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) static int ui_do_but_LISTROW(bContext *C, uiBut *but, uiHandleButtonData *data, const wmEvent *event)
{ {
if (data->state == BUTTON_STATE_HIGHLIGHT) { 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: case SCROLL:
retval = ui_do_but_SCROLL(C, block, but, data, event); retval = ui_do_but_SCROLL(C, block, but, data, event);
break; break;
case GRIP:
retval = ui_do_but_GRIP(C, block, but, data, event);
break;
case NUM: case NUM:
retval = ui_do_but_NUM(C, block, but, data, event); retval = ui_do_but_NUM(C, block, but, data, event);
break; 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); button_activate_state(C, but, BUTTON_STATE_TEXT_EDITING);
else if (type == BUTTON_ACTIVATE_APPLY) else if (type == BUTTON_ACTIVATE_APPLY)
button_activate_state(C, but, BUTTON_STATE_WAIT_FLASH); 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, 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; uiBlock *block = but->block;
uiBut *bt; uiBut *bt;
if (but->type == GRIP) {
WM_cursor_modal_restore(data->window);
}
/* ensure we are in the exit state */ /* ensure we are in the exit state */
if (data->state != BUTTON_STATE_EXIT) if (data->state != BUTTON_STATE_EXIT)
button_activate_state(C, but, BUTTON_STATE_EXIT); button_activate_state(C, but, BUTTON_STATE_EXIT);

@ -55,6 +55,7 @@
#include "BKE_displist.h" #include "BKE_displist.h"
#include "BKE_dynamicpaint.h" #include "BKE_dynamicpaint.h"
#include "BKE_global.h" #include "BKE_global.h"
#include "BKE_idcode.h"
#include "BKE_library.h" #include "BKE_library.h"
#include "BKE_main.h" #include "BKE_main.h"
#include "BKE_material.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; uiLayout *row, *col;
uiBlock *block; uiBlock *block;
uiPreview *ui_preview = NULL;
ARegion *ar;
Material *ma = NULL; Material *ma = NULL;
Tex *tex = (Tex *)id; Tex *tex = (Tex *)id;
ID *pid, *pparent; ID *pid, *pparent;
@ -1301,6 +1306,8 @@ void uiTemplatePreview(uiLayout *layout, ID *id, int show_buttons, ID *parent, M
PointerRNA material_ptr; PointerRNA material_ptr;
PointerRNA texture_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)) { 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"); RNA_warning("Expected ID of type material, texture, lamp or world");
return; return;
@ -1326,6 +1333,30 @@ 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 */ /* layout */
block = uiLayoutGetBlock(layout); block = uiLayoutGetBlock(layout);
row = uiLayoutRow(layout, false); row = uiLayoutRow(layout, false);
@ -1333,10 +1364,13 @@ void uiTemplatePreview(uiLayout *layout, ID *id, int show_buttons, ID *parent, M
uiLayoutSetKeepAspect(col, true); uiLayoutSetKeepAspect(col, true);
/* add preview */ /* 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); uiBlockSetDrawExtraFunc(block, ED_preview_draw, pparent, slot);
uiBlockSetHandleFunc(block, do_preview_buttons, NULL); 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 */ /* add buttons */
if (pid && show_buttons) { if (pid && show_buttons) {
if (GS(pid->name) == ID_MA || (pparent && GS(pparent->name) == ID_MA)) { if (GS(pid->name) == ID_MA || (pparent && GS(pparent->name) == ID_MA)) {

@ -3552,6 +3552,10 @@ void ui_draw_but(const bContext *C, ARegion *ar, uiStyle *style, uiBut *but, rct
wt = widget_type(UI_WTYPE_SCROLL); wt = widget_type(UI_WTYPE_SCROLL);
break; break;
case GRIP:
wt = widget_type(UI_WTYPE_ICON);
break;
case TRACKPREVIEW: case TRACKPREVIEW:
ui_draw_but_TRACKPREVIEW(ar, but, &tui->wcol_regular, rect); ui_draw_but_TRACKPREVIEW(ar, but, &tui->wcol_regular, rect);
break; break;

@ -186,6 +186,14 @@ typedef struct uiList { /* some list UI data need to be saved in file
uiListDyn *dyn_data; uiListDyn *dyn_data;
} uiList; } 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 { typedef struct ScrArea {
struct ScrArea *next, *prev; struct ScrArea *next, *prev;
@ -241,6 +249,7 @@ typedef struct ARegion {
ListBase panels; /* Panel */ ListBase panels; /* Panel */
ListBase panels_category_active; /* Stack of panel categories */ ListBase panels_category_active; /* Stack of panel categories */
ListBase ui_lists; /* uiList */ ListBase ui_lists; /* uiList */
ListBase ui_previews; /* uiPreview */
ListBase handlers; /* wmEventHandler */ ListBase handlers; /* wmEventHandler */
ListBase panels_category; /* Panel categories runtime */ ListBase panels_category; /* Panel categories runtime */

@ -683,12 +683,16 @@ void RNA_api_ui_layout(StructRNA *srna)
RNA_def_function_return(func, parm); RNA_def_function_return(func, parm);
func = RNA_def_function(srna, "template_preview", "uiTemplatePreview"); 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"); parm = RNA_def_pointer(func, "id", "ID", "", "ID datablock");
RNA_def_property_flag(parm, PROP_REQUIRED); RNA_def_property_flag(parm, PROP_REQUIRED);
RNA_def_boolean(func, "show_buttons", true, "", "Show preview buttons?"); RNA_def_boolean(func, "show_buttons", true, "", "Show preview buttons?");
RNA_def_pointer(func, "parent", "ID", "", "ID datablock"); RNA_def_pointer(func, "parent", "ID", "", "ID datablock");
RNA_def_pointer(func, "slot", "TextureSlot", "", "Texture slot"); 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"); 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"); RNA_def_function_ui_description(func, "Item. A curve mapping widget used for e.g falloff curves for lamps");

@ -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 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 *uiTemplateModifier(uiLayout *layout, struct bContext *C, struct PointerRNA *ptr) RET_NULL
struct uiLayout *uiTemplateConstraint(struct uiLayout *layout, 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 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 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 void uiTemplateColorRamp(uiLayout *layout, struct PointerRNA *ptr, const char *propname, int expand) RET_NONE