Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/source
diff options
context:
space:
mode:
authorBastien Montagne <montagne29@wanadoo.fr>2013-08-27 19:27:41 +0400
committerBastien Montagne <montagne29@wanadoo.fr>2013-08-27 19:27:41 +0400
commit6b51c274149d854f57f2f1865578942a87e78869 (patch)
treefa73ee4d1547729da976226a0d7723f2c73c2ab0 /source
parent07aaf4a90a906f5e1f7681db6f1067e286ffe568 (diff)
uiLists enhacements: dragresize and better GRID layout.
Many thanks to Brecht for the review! * You can now drag-resize uiLists (in default or grid layouts). ** Note about "default" size: when you drag below minimal size of the uiList, it will automatically reset to automatic sizing (i.e. size between rows and maxrows, depending on the number of items to show). This often means (e.g. in Materials list with many mat slots) that the list will grow again to maxrows! * Grid uiLists now have a customizable number of columns (previously it was a fixed value of 9), and they will respect the rows/maxrows settings as well (i.e. show a scrollbar when needed), instead of growing indefinitly!
Diffstat (limited to 'source')
-rw-r--r--source/blender/blenkernel/intern/screen.c8
-rw-r--r--source/blender/blenloader/intern/readfile.c1
-rw-r--r--source/blender/editors/include/UI_interface.h2
-rw-r--r--source/blender/editors/interface/interface_handlers.c251
-rw-r--r--source/blender/editors/interface/interface_layout.c9
-rw-r--r--source/blender/editors/interface/interface_templates.c168
-rw-r--r--source/blender/editors/space_node/drawnode.c6
-rw-r--r--source/blender/editors/space_node/node_buttons.c6
-rw-r--r--source/blender/makesdna/DNA_screen_types.h39
-rw-r--r--source/blender/makesrna/intern/rna_ui_api.c5
-rw-r--r--source/blenderplayer/bad_level_call_stubs/stubs.c2
11 files changed, 366 insertions, 131 deletions
diff --git a/source/blender/blenkernel/intern/screen.c b/source/blender/blenkernel/intern/screen.c
index fe2f52d79fd..924cdff798d 100644
--- a/source/blender/blenkernel/intern/screen.c
+++ b/source/blender/blenkernel/intern/screen.c
@@ -267,6 +267,8 @@ void BKE_spacedata_draw_locks(int set)
/* not region itself */
void BKE_area_region_free(SpaceType *st, ARegion *ar)
{
+ uiList *uilst;
+
if (st) {
ARegionType *art = BKE_regiontype_from_id(st, ar->regiontype);
@@ -285,6 +287,12 @@ void BKE_area_region_free(SpaceType *st, ARegion *ar)
}
BLI_freelistN(&ar->panels);
+
+ for (uilst = ar->ui_lists.first; uilst; uilst = uilst->next) {
+ if (uilst->dyn_data) {
+ MEM_freeN(uilst->dyn_data);
+ }
+ }
BLI_freelistN(&ar->ui_lists);
}
diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c
index bab015d2a81..ff44bcc4cfe 100644
--- a/source/blender/blenloader/intern/readfile.c
+++ b/source/blender/blenloader/intern/readfile.c
@@ -6127,6 +6127,7 @@ static void direct_link_region(FileData *fd, ARegion *ar, int spacetype)
for (ui_list = ar->ui_lists.first; ui_list; ui_list = ui_list->next) {
ui_list->type = NULL;
+ ui_list->dyn_data = NULL;
}
if (spacetype == SPACE_EMPTY) {
diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h
index 9a9cab9b46c..5712b64ae8f 100644
--- a/source/blender/editors/include/UI_interface.h
+++ b/source/blender/editors/include/UI_interface.h
@@ -845,7 +845,7 @@ void uiTemplateNodeSocket(uiLayout *layout, struct bContext *C, float *color);
#define UI_UL_DEFAULT_CLASS_NAME "UI_UL_list"
void uiTemplateList(uiLayout *layout, struct bContext *C, const char *listtype_name, const char *list_id,
struct PointerRNA *dataptr, const char *propname, struct PointerRNA *active_dataptr,
- const char *active_propname, int rows, int maxrows, int layout_type);
+ const char *active_propname, int rows, int maxrows, int layout_type, int columns);
void uiTemplateNodeLink(uiLayout *layout, struct bNodeTree *ntree, struct bNode *node, struct bNodeSocket *input);
void uiTemplateNodeView(uiLayout *layout, struct bContext *C, struct bNodeTree *ntree, struct bNode *node, struct bNodeSocket *input);
void uiTemplateTextureUser(uiLayout *layout, struct bContext *C);
diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c
index f9ee2b67e6b..c0c8367eb8c 100644
--- a/source/blender/editors/interface/interface_handlers.c
+++ b/source/blender/editors/interface/interface_handlers.c
@@ -170,6 +170,7 @@ typedef struct uiHandleButtonData {
/* coords are Window/uiBlock relative (depends on the button) */
int draglastx, draglasty;
int dragstartx, dragstarty;
+ int draglastvalue;
bool dragchange, draglock;
int dragsel;
float dragf, dragfstart;
@@ -3406,6 +3407,87 @@ static int ui_do_but_SCROLL(bContext *C, uiBlock *block, uiBut *but, uiHandleBut
return retval;
}
+static int ui_do_but_LISTBOX(bContext *C, uiBlock *block, uiBut *but, uiHandleButtonData *data, const wmEvent *event)
+{
+ uiList *ui_list = but->custom_data;
+ int *size = (int *)but->poin;
+ int mx, my;
+ int retval = WM_UI_HANDLER_CONTINUE;
+
+ mx = event->x;
+ my = event->y;
+ ui_window_to_block(data->region, block, &mx, &my);
+
+ if (data->state == BUTTON_STATE_NUM_EDITING) {
+ if (event->type == ESCKEY) {
+ data->cancel = true;
+ data->escapecancel = true;
+ *size = (int)data->origvalue;
+ button_activate_state(C, but, BUTTON_STATE_EXIT);
+ ED_region_tag_redraw(data->region);
+ }
+ else if (event->type == LEFTMOUSE && event->val != KM_PRESS) {
+ button_activate_state(C, but, BUTTON_STATE_EXIT);
+ ED_region_tag_redraw(data->region);
+ }
+ else if (event->type == MOUSEMOVE) {
+ /* If we switched from dragged to auto size, suspend shrinking dragging and set dragstarty to a temp
+ * refpoint.
+ */
+ if (data->draglastvalue > 0 && *size == 0) {
+ data->draglastvalue = *size;
+ data->draglasty = data->dragstarty;
+ data->dragstarty = my;
+ }
+ else {
+ int delta = -(my - data->dragstarty);
+ /* Number of rows to show/hide, UI_UNIT_Y should work nice in most cases. */
+ delta /= UI_UNIT_Y;
+
+ /* If we are not in autosize mode, default behavior... */
+ if (*size > 0 && delta != 0) {
+ /* Note: In case some items of the list would draw more than UI_UNIT_Y height, we only grow from one
+ * item at a time, to avoid instability!
+ */
+ delta = delta / abs(delta);
+ /* We can't use ui_numedit_apply()... */
+ /* list template will clamp, but we do not want to reach 0 aka autosize mode!. */
+ *size = max_ii(*size + delta, 1);
+
+ /* Used to detect switch to/from autosize mode. */
+ data->draglastvalue = *size;
+
+ data->dragchange = true;
+ data->applied = data->applied_interactive = true;
+
+ ui_list->flag |= UILST_SCROLL_TO_ACTIVE_ITEM;
+ ED_region_tag_redraw(data->region);
+ }
+ /* If we are leaving autosize mode (growing dragging), restore to minimal size. */
+ else if (delta > 0) {
+ /* We can't use ui_numedit_apply()... */
+ *size = ui_list->dyn_data->visual_height_min;
+
+ /* Restore real dragstarty value! */
+ data->dragstarty = data->draglasty;
+
+ /* Used to detect switch to/from autosize mode. */
+ data->draglastvalue = *size;
+
+ data->dragchange = true;
+ data->applied = data->applied_interactive = true;
+
+ ui_list->flag |= UILST_SCROLL_TO_ACTIVE_ITEM;
+ ED_region_tag_redraw(data->region);
+ }
+ }
+ }
+
+ retval = WM_UI_HANDLER_BREAK;
+ }
+
+ return retval;
+}
static int ui_do_but_BLOCK(bContext *C, uiBut *but, uiHandleButtonData *data, const wmEvent *event)
{
@@ -5367,8 +5449,10 @@ static int ui_do_button(bContext *C, uiBlock *block, uiBut *but, const wmEvent *
case NUMSLI:
retval = ui_do_but_SLI(C, block, but, data, event);
break;
- case ROUNDBOX:
case LISTBOX:
+ retval = ui_do_but_LISTBOX(C, block, but, data, event);
+ break;
+ case ROUNDBOX:
case LABEL:
case LISTLABEL:
case ROW:
@@ -5622,8 +5706,6 @@ static uiBut *ui_list_find_mouse_over(ARegion *ar, int x, int y)
uiBut *but;
int mx, my;
-// if (!win->active)
-// return NULL;
if (!ui_mouse_inside_region(ar, x, y))
return NULL;
@@ -5768,7 +5850,7 @@ static void button_activate_state(bContext *C, uiBut *but, uiHandleButtonState s
WM_cursor_grab_disable(data->window, NULL);
}
#else
- WM_cursor_grab_disable(data->window, );
+ WM_cursor_grab_disable(data->window, NULL);
#endif
}
}
@@ -6423,90 +6505,125 @@ static int ui_handle_button_event(bContext *C, const wmEvent *event, uiBut *but)
static int ui_handle_list_event(bContext *C, const wmEvent *event, ARegion *ar)
{
- uiBut *but = ui_list_find_mouse_over(ar, event->x, event->y);
+ uiBut *but, *dragbut;
+ uiList *ui_list;
+ uiListDyn *dyn_data;
int retval = WM_UI_HANDLER_CONTINUE;
int type = event->type, val = event->val;
+ int mx, my;
+ bool is_over_dragbut = false;
- if (but) {
- uiList *ui_list = but->custom_data;
+ but = ui_list_find_mouse_over(ar, event->x, event->y);
+ if (!but) {
+ return retval;
+ }
- if (ui_list) {
-
- /* convert pan to scrollwheel */
- if (type == MOUSEPAN) {
- ui_pan_to_scroll(event, &type, &val);
-
- /* if type still is mousepan, we call it handled, since delta-y accumulate */
- /* also see wm_event_system.c do_wheel_ui hack */
- if (type == MOUSEPAN)
- retval = WM_UI_HANDLER_BREAK;
- }
-
- if (val == KM_PRESS) {
-
- if (ELEM(type, UPARROWKEY, DOWNARROWKEY) ||
- ((ELEM(type, WHEELUPMOUSE, WHEELDOWNMOUSE) && event->alt)))
- {
- const int value_orig = RNA_property_int_get(&but->rnapoin, but->rnaprop);
- int value, min, max;
+ ui_list = but->custom_data;
+ if (!ui_list || !ui_list->dyn_data) {
+ return retval;
+ }
+ dyn_data = ui_list->dyn_data;
- /* activate up/down the list */
- value = value_orig;
+ mx = event->x;
+ my = event->y;
+ ui_window_to_block(ar, but->block, &mx, &my);
- if (ELEM(type, UPARROWKEY, WHEELUPMOUSE))
- value--;
- else
- value++;
+ /* Find our "dragging" button. */
+ for (dragbut = but->block->buttons.first; dragbut; dragbut = dragbut->next) {
+ if (dragbut->poin == (void *)ui_list) {
+ break;
+ }
+ }
+ if (dragbut && dragbut == ui_but_find_mouse_over(ar, event->x, event->y)) {
+ is_over_dragbut = true;
+ }
- CLAMP(value, 0, ui_list->list_last_len - 1);
+ if (is_over_dragbut && type == LEFTMOUSE && val == KM_PRESS) {
+ uiHandleButtonData *data;
+ int *size = (int *)but->poin;
- if (value < ui_list->list_scroll)
- ui_list->list_scroll = value;
- else if (value >= ui_list->list_scroll + ui_list->list_size)
- ui_list->list_scroll = value - ui_list->list_size + 1;
+ ui_handle_button_activate(C, ar, but, BUTTON_ACTIVATE);
+ button_activate_state(C, but, BUTTON_STATE_INIT);
- RNA_property_int_range(&but->rnapoin, but->rnaprop, &min, &max);
- value = CLAMPIS(value, min, max);
+ data = but->active;
+ data->dragstarty = my;
- if (value != value_orig) {
- RNA_property_int_set(&but->rnapoin, but->rnaprop, value);
- RNA_property_update(C, &but->rnapoin, but->rnaprop);
+ button_activate_state(C, but, BUTTON_STATE_NUM_EDITING);
- ui_apply_undo(but);
- ED_region_tag_redraw(ar);
- }
+ /* Again, have to override values set by ui_numedit_begin, because our listbox button also has a rnapoin... */
+ *size = data->origvalue = (double)dyn_data->visual_height;
- retval = WM_UI_HANDLER_BREAK;
+ retval = WM_UI_HANDLER_BREAK;
+ }
+ else {
+ /* convert pan to scrollwheel */
+ if (type == MOUSEPAN) {
+ ui_pan_to_scroll(event, &type, &val);
+
+ /* if type still is mousepan, we call it handled, since delta-y accumulate */
+ /* also see wm_event_system.c do_wheel_ui hack */
+ if (type == MOUSEPAN)
+ retval = WM_UI_HANDLER_BREAK;
+ }
+
+ if (val == KM_PRESS) {
+ if (ELEM(type, UPARROWKEY, DOWNARROWKEY) ||
+ ((ELEM(type, WHEELUPMOUSE, WHEELDOWNMOUSE) && event->alt)))
+ {
+ const int value_orig = RNA_property_int_get(&but->rnapoin, but->rnaprop);
+ int value, min, max;
+
+ /* activate up/down the list */
+ value = value_orig;
+
+ if (ELEM(type, UPARROWKEY, WHEELUPMOUSE))
+ value--;
+ else
+ value++;
+
+ CLAMP(value, 0, dyn_data->items_len - 1);
+
+ RNA_property_int_range(&but->rnapoin, but->rnaprop, &min, &max);
+ CLAMP(value, min, max);
+
+ if (value != value_orig) {
+ RNA_property_int_set(&but->rnapoin, but->rnaprop, value);
+ RNA_property_update(C, &but->rnapoin, but->rnaprop);
+
+ ui_apply_undo(but);
+
+ ui_list->flag |= UILST_SCROLL_TO_ACTIVE_ITEM;
+ ED_region_tag_redraw(ar);
}
- else if (ELEM(type, WHEELUPMOUSE, WHEELDOWNMOUSE) && event->shift) {
- /* silly replacement for proper grip */
- if (ui_list->list_grip_size == 0)
- ui_list->list_grip_size = ui_list->list_size;
+ retval = WM_UI_HANDLER_BREAK;
+ }
+ else if (ELEM(type, WHEELUPMOUSE, WHEELDOWNMOUSE) && event->shift) {
+ /* We now have proper grip, but keep this anyway! */
+ if (ui_list->list_grip == 0)
+ ui_list->list_grip = dyn_data->visual_height;
+ /* list template will clamp */
+ if (type == WHEELUPMOUSE)
+ ui_list->list_grip--;
+ else
+ ui_list->list_grip++;
+
+ ui_list->flag |= UILST_SCROLL_TO_ACTIVE_ITEM;
+ ED_region_tag_redraw(ar);
+ retval = WM_UI_HANDLER_BREAK;
+ }
+ else if (ELEM(type, WHEELUPMOUSE, WHEELDOWNMOUSE)) {
+ if (dyn_data->height > dyn_data->visual_height) {
+ /* list template will clamp */
if (type == WHEELUPMOUSE)
- ui_list->list_grip_size--;
+ ui_list->list_scroll--;
else
- ui_list->list_grip_size++;
-
- ui_list->list_grip_size = MAX2(ui_list->list_grip_size, 1);
+ ui_list->list_scroll++;
ED_region_tag_redraw(ar);
retval = WM_UI_HANDLER_BREAK;
}
- else if (ELEM(type, WHEELUPMOUSE, WHEELDOWNMOUSE)) {
- if (ui_list->list_last_len > ui_list->list_size) {
- /* list template will clamp */
- if (type == WHEELUPMOUSE)
- ui_list->list_scroll--;
- else
- ui_list->list_scroll++;
-
- ED_region_tag_redraw(ar);
-
- retval = WM_UI_HANDLER_BREAK;
- }
- }
}
}
}
diff --git a/source/blender/editors/interface/interface_layout.c b/source/blender/editors/interface/interface_layout.c
index 7ff7c279dcd..ce9b0db6b14 100644
--- a/source/blender/editors/interface/interface_layout.c
+++ b/source/blender/editors/interface/interface_layout.c
@@ -2432,6 +2432,15 @@ uiLayout *uiLayoutListBox(uiLayout *layout, uiList *ui_list, PointerRNA *ptr, Pr
but->rnapoin = *actptr;
but->rnaprop = actprop;
+ /* Resizing data. */
+ /* Note: we can't use usual "num button" value handling, as it only tries rnapoin when it is non-NULL... :/
+ * So just setting but->poin, not but->pointype.
+ */
+ but->poin = (void *)&ui_list->list_grip;
+ but->hardmin = but->softmin = 0.0f;
+ but->hardmax = but->softmax = 1000.0f; /* Should be more than enough! */
+ but->a1 = 0.0f;
+
/* only for the undo string */
if (but->flag & UI_BUT_UNDO) {
but->tip = RNA_property_description(actprop);
diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c
index 451c38ded2d..5ffb47c4df0 100644
--- a/source/blender/editors/interface/interface_templates.c
+++ b/source/blender/editors/interface/interface_templates.c
@@ -2497,30 +2497,89 @@ static void uilist_draw_item_default(struct uiList *ui_list, struct bContext *UN
}
}
+typedef struct {
+ int visual_items; /* Visual number of items (i.e. number of items we have room to display). */
+ int start_idx; /* Index of first item to display. */
+ int end_idx; /* Index of last item to display + 1. */
+} uiListLayoutdata;
+
+static void prepare_list(uiList *ui_list, int len, int activei, int rows, int maxrows, int columns,
+ uiListLayoutdata *layoutdata)
+{
+ uiListDyn *dyn_data = ui_list->dyn_data;
+ int activei_row, max_scroll;
+
+ /* default rows */
+ if (rows == 0)
+ rows = 5;
+ dyn_data->visual_height_min = rows;
+ if (maxrows == 0)
+ maxrows = 5;
+ if (columns == 0)
+ columns = 9;
+ if (ui_list->list_grip >= rows)
+ maxrows = rows = ui_list->list_grip;
+ else
+ ui_list->list_grip = 0; /* Reset to auto-size mode. */
+
+ if (columns > 1) {
+ dyn_data->height = (int)ceil((double)len / (double)columns);
+ activei_row = (int)floor((double)activei / (double)columns);
+ }
+ else {
+ dyn_data->height = len;
+ activei_row = activei;
+ }
+
+ /* Expand size if needed and possible. */
+ if ((ui_list->list_grip == 0) && (rows != maxrows) && (dyn_data->height > rows)) {
+ rows = min_ii(dyn_data->height, maxrows);
+ }
+
+ /* If list length changes or list is tagged to check this, and active is out of view, scroll to it .*/
+ if (ui_list->list_last_len != len || ui_list->flag & UILST_SCROLL_TO_ACTIVE_ITEM) {
+ if (activei_row < ui_list->list_scroll) {
+ ui_list->list_scroll = activei_row;
+ }
+ else if (activei_row >= ui_list->list_scroll + rows) {
+ ui_list->list_scroll = activei_row - rows + 1;
+ }
+ ui_list->flag &= ~UILST_SCROLL_TO_ACTIVE_ITEM;
+ }
+
+ max_scroll = max_ii(0, dyn_data->height - rows);
+ CLAMP(ui_list->list_scroll, 0, max_scroll);
+ ui_list->list_last_len = len;
+ dyn_data->visual_height = rows;
+ layoutdata->visual_items = rows * columns;
+ layoutdata->start_idx = ui_list->list_scroll * columns;
+ layoutdata->end_idx = min_ii(layoutdata->start_idx + rows * columns, len);
+}
+
void uiTemplateList(uiLayout *layout, bContext *C, const char *listtype_name, const char *list_id,
PointerRNA *dataptr, const char *propname, PointerRNA *active_dataptr,
- const char *active_propname, int rows, int maxrows, int layout_type)
+ const char *active_propname, int rows, int maxrows, int layout_type, int columns)
{
uiListType *ui_list_type;
uiList *ui_list = NULL;
+ uiListDyn *dyn_data;
ARegion *ar;
uiListDrawItemFunc draw_item;
PropertyRNA *prop = NULL, *activeprop;
PropertyType type, activetype;
StructRNA *ptype;
- uiLayout *box, *row, *col, *sub, *overlap;
+ uiLayout *glob = NULL, *box, *row, *col, *subrow, *sub, *overlap;
uiBlock *block, *subblock;
uiBut *but;
+ uiListLayoutdata layoutdata;
char ui_list_id[UI_MAX_NAME_STR];
char numstr[32];
int rnaicon = ICON_NONE, icon = ICON_NONE;
int i = 0, activei = 0;
int len = 0;
- int items;
int found;
- int min, max;
/* validate arguments */
/* Forbid default UI_UL_DEFAULT_CLASS_NAME list class without a custom list_id! */
@@ -2592,54 +2651,39 @@ void uiTemplateList(uiLayout *layout, bContext *C, const char *listtype_name, co
ui_list = BLI_findstring(&ar->ui_lists, ui_list_id, offsetof(uiList, list_id));
if (!ui_list) {
- ui_list = MEM_callocN(sizeof(uiList), __func__);
+ ui_list = MEM_callocN(sizeof(uiList), AT);
BLI_strncpy(ui_list->list_id, ui_list_id, sizeof(ui_list->list_id));
BLI_addtail(&ar->ui_lists, ui_list);
}
+ if (!ui_list->dyn_data) {
+ ui_list->dyn_data = MEM_callocN(sizeof(uiListDyn), AT);
+ }
+ dyn_data = ui_list->dyn_data;
+
/* Because we can't actually pass type across save&load... */
ui_list->type = ui_list_type;
ui_list->layout_type = layout_type;
+ if (dataptr->data && prop)
+ dyn_data->items_len = dyn_data->items_shown = len = RNA_property_collection_length(dataptr, prop);
+
switch (layout_type) {
case UILST_LAYOUT_DEFAULT:
- /* default rows */
- if (rows == 0)
- rows = 5;
- if (maxrows == 0)
- maxrows = 5;
- if (ui_list->list_grip_size != 0)
- rows = ui_list->list_grip_size;
-
/* layout */
box = uiLayoutListBox(layout, ui_list, dataptr, prop, active_dataptr, activeprop);
- row = uiLayoutRow(box, FALSE);
+ glob = uiLayoutColumn(box, TRUE);
+ row = uiLayoutRow(glob, FALSE);
col = uiLayoutColumn(row, TRUE);
/* init numbers */
- RNA_property_int_range(active_dataptr, activeprop, &min, &max);
-
- if (prop)
- len = RNA_property_collection_length(dataptr, prop);
- items = CLAMPIS(len, rows, MAX2(rows, maxrows));
-
- /* if list length changes and active is out of view, scroll to it */
- if ((ui_list->list_last_len != len) &&
- (activei < ui_list->list_scroll || activei >= ui_list->list_scroll + items))
- {
- ui_list->list_scroll = activei;
- }
-
- ui_list->list_scroll = min_ii(ui_list->list_scroll, len - items);
- ui_list->list_scroll = max_ii(ui_list->list_scroll, 0);
- ui_list->list_size = items;
- ui_list->list_last_len = len;
+ prepare_list(ui_list, len, activei, rows, maxrows, 1, &layoutdata);
if (dataptr->data && prop) {
/* create list items */
RNA_PROP_BEGIN (dataptr, itemptr, prop)
{
- if (i >= ui_list->list_scroll && i < ui_list->list_scroll + items) {
+ if (i >= layoutdata.start_idx && i < layoutdata.end_idx) {
subblock = uiLayoutGetBlock(col);
overlap = uiLayoutOverlap(col);
@@ -2672,17 +2716,16 @@ void uiTemplateList(uiLayout *layout, bContext *C, const char *listtype_name, co
}
/* add dummy buttons to fill space */
- while (i < ui_list->list_scroll + items) {
- if (i >= ui_list->list_scroll)
- uiItemL(col, "", ICON_NONE);
- i++;
+ for (; i < layoutdata.start_idx + layoutdata.visual_items; i++) {
+ uiItemL(col, "", ICON_NONE);
}
/* add scrollbar */
- if (len > items) {
+ if (len > layoutdata.visual_items) {
col = uiLayoutColumn(row, FALSE);
- uiDefButI(block, SCROLL, 0, "", 0, 0, UI_UNIT_X * 0.75, UI_UNIT_Y * items, &ui_list->list_scroll,
- 0, len - items, items, 0, "");
+ uiDefButI(block, SCROLL, 0, "", 0, 0, UI_UNIT_X * 0.75, UI_UNIT_Y * dyn_data->visual_height,
+ &ui_list->list_scroll, 0, dyn_data->height - dyn_data->visual_height,
+ dyn_data->visual_height, 0, "");
}
break;
case UILST_LAYOUT_COMPACT:
@@ -2719,19 +2762,24 @@ void uiTemplateList(uiLayout *layout, bContext *C, const char *listtype_name, co
break;
case UILST_LAYOUT_GRID:
box = uiLayoutListBox(layout, ui_list, dataptr, prop, active_dataptr, activeprop);
- col = uiLayoutColumn(box, TRUE);
- row = uiLayoutRow(col, FALSE);
+ glob = uiLayoutColumn(box, TRUE);
+ row = uiLayoutRow(glob, FALSE);
+ col = uiLayoutColumn(row, TRUE);
+ subrow = NULL; /* Quite gcc warning! */
+
+ prepare_list(ui_list, len, activei, rows, maxrows, columns, &layoutdata);
if (dataptr->data && prop) {
/* create list items */
RNA_PROP_BEGIN (dataptr, itemptr, prop)
{
+ if (i >= layoutdata.start_idx && i < layoutdata.end_idx) {
/* create button */
- if (!(i % 9))
- row = uiLayoutRow(col, FALSE);
+ if (!(i % columns))
+ subrow = uiLayoutRow(col, FALSE);
- subblock = uiLayoutGetBlock(row);
- overlap = uiLayoutOverlap(row);
+ subblock = uiLayoutGetBlock(subrow);
+ overlap = uiLayoutOverlap(subrow);
uiBlockSetFlag(subblock, UI_BLOCK_LIST_ITEM);
@@ -2753,13 +2801,41 @@ void uiTemplateList(uiLayout *layout, bContext *C, const char *listtype_name, co
}
uiBlockClearFlag(subblock, UI_BLOCK_LIST_ITEM);
-
+ }
i++;
}
RNA_PROP_END;
}
+
+ /* add dummy buttons to fill space */
+ for (; i < layoutdata.start_idx + layoutdata.visual_items; i++) {
+ if (!(i % columns)) {
+ subrow = uiLayoutRow(col, FALSE);
+ }
+ uiItemL(subrow, "", ICON_NONE);
+ }
+
+ /* add scrollbar */
+ if (len > layoutdata.visual_items) {
+ col = uiLayoutColumn(row, FALSE);
+ uiDefButI(block, SCROLL, 0, "", 0, 0, UI_UNIT_X * 0.75, UI_UNIT_Y * dyn_data->visual_height,
+ &ui_list->list_scroll, 0, dyn_data->height - dyn_data->visual_height,
+ dyn_data->visual_height, 0, "");
+ }
break;
}
+
+ if (glob) {
+ row = uiLayoutRow(glob, TRUE);
+ subblock = uiLayoutGetBlock(row);
+ uiBlockSetEmboss(subblock, UI_EMBOSSN);
+
+ but = uiDefIconBut(subblock, BUT, 0, ICON_GRIP, 0, 0, UI_UNIT_X * 10.0f, UI_UNIT_Y * 0.4f, ui_list,
+ 0.0, 0.0, 0, -1, "");
+ uiButClearFlag(but, UI_BUT_UNDO); /* skip undo on screen buttons */
+
+ uiBlockSetEmboss(subblock, UI_EMBOSS);
+ }
}
/************************* Operator Search Template **************************/
diff --git a/source/blender/editors/space_node/drawnode.c b/source/blender/editors/space_node/drawnode.c
index a011657ce51..d00d1e61b0d 100644
--- a/source/blender/editors/space_node/drawnode.c
+++ b/source/blender/editors/space_node/drawnode.c
@@ -1628,12 +1628,14 @@ static void node_composit_buts_file_output_details(uiLayout *layout, bContext *C
active_index = RNA_int_get(ptr, "active_input_index");
/* using different collection properties if multilayer format is enabled */
if (multilayer) {
- uiTemplateList(col, C, "UI_UL_list", "file_output_node", ptr, "layer_slots", ptr, "active_input_index", 0, 0, 0);
+ uiTemplateList(col, C, "UI_UL_list", "file_output_node", ptr, "layer_slots", ptr, "active_input_index",
+ 0, 0, 0, 0);
RNA_property_collection_lookup_int(ptr, RNA_struct_find_property(ptr, "layer_slots"),
active_index, &active_input_ptr);
}
else {
- uiTemplateList(col, C, "UI_UL_list", "file_output_node", ptr, "file_slots", ptr, "active_input_index", 0, 0, 0);
+ uiTemplateList(col, C, "UI_UL_list", "file_output_node", ptr, "file_slots", ptr, "active_input_index",
+ 0, 0, 0, 0);
RNA_property_collection_lookup_int(ptr, RNA_struct_find_property(ptr, "file_slots"),
active_index, &active_input_ptr);
}
diff --git a/source/blender/editors/space_node/node_buttons.c b/source/blender/editors/space_node/node_buttons.c
index f95e895bef2..53b373e728e 100644
--- a/source/blender/editors/space_node/node_buttons.c
+++ b/source/blender/editors/space_node/node_buttons.c
@@ -145,13 +145,15 @@ static void node_tree_interface_panel(const bContext *C, Panel *pa)
split = uiLayoutRow(row, TRUE);
col = uiLayoutColumn(split, TRUE);
uiItemL(col, IFACE_("Inputs:"), ICON_NONE);
- uiTemplateList(col, (bContext *)C, "NODE_UL_interface_sockets", "inputs", &ptr, "inputs", &ptr, "active_input", 0, 0, 0);
+ uiTemplateList(col, (bContext *)C, "NODE_UL_interface_sockets", "inputs", &ptr, "inputs", &ptr, "active_input",
+ 0, 0, 0, 0);
opptr = uiItemFullO(col, "NODE_OT_tree_socket_add", "", ICON_PLUS, NULL, WM_OP_EXEC_DEFAULT, UI_ITEM_O_RETURN_PROPS);
RNA_enum_set(&opptr, "in_out", SOCK_IN);
col = uiLayoutColumn(split, TRUE);
uiItemL(col, IFACE_("Outputs:"), ICON_NONE);
- uiTemplateList(col, (bContext *)C, "NODE_UL_interface_sockets", "outputs", &ptr, "outputs", &ptr, "active_output", 0, 0, 0);
+ uiTemplateList(col, (bContext *)C, "NODE_UL_interface_sockets", "outputs", &ptr, "outputs", &ptr, "active_output",
+ 0, 0, 0, 0);
opptr = uiItemFullO(col, "NODE_OT_tree_socket_add", "", ICON_PLUS, NULL, WM_OP_EXEC_DEFAULT, UI_ITEM_O_RETURN_PROPS);
RNA_enum_set(&opptr, "in_out", SOCK_OUT);
diff --git a/source/blender/makesdna/DNA_screen_types.h b/source/blender/makesdna/DNA_screen_types.h
index 9d840ad13e8..c15deaeb137 100644
--- a/source/blender/makesdna/DNA_screen_types.h
+++ b/source/blender/makesdna/DNA_screen_types.h
@@ -112,22 +112,36 @@ typedef struct Panel { /* the part from uiBlock that needs saved in file */
void *activedata; /* runtime for panel manipulation */
} Panel;
-typedef struct uiList { /* some list UI data need to be saved in file */
+/* uiList dynamic data... */
+/* These two Lines with # tell makesdna this struct can be excluded. */
+#
+#
+typedef struct uiListDyn {
+ int height; /* Number of rows needed to draw all elements. */
+ int visual_height; /* Actual visual height of the list (in rows). */
+ int visual_height_min; /* Minimal visual height of the list (in rows). */
+
+ int items_len; /* Number of items in collection. */
+ int items_shown; /* Number of items actually visible after filtering. */
+} uiListDyn;
+
+typedef struct uiList { /* some list UI data need to be saved in file */
struct uiList *next, *prev;
- struct uiListType *type; /* runtime */
- void *padp;
+ struct uiListType *type; /* runtime */
- char list_id[64]; /* defined as UI_MAX_NAME_STR */
+ char list_id[64]; /* defined as UI_MAX_NAME_STR */
- int layout_type; /* How items are layedout in the list */
- int padi;
+ int layout_type; /* How items are layedout in the list */
+ int flag;
int list_scroll;
- int list_size;
+ int list_grip;
int list_last_len;
- int list_grip_size;
-/* char list_search[64]; */
+ int padi1;
+
+ /* Dynamic data (runtime). */
+ uiListDyn *dyn_data;
} uiList;
typedef struct ScrArea {
@@ -232,13 +246,18 @@ typedef struct ARegion {
#define PNL_DEFAULT_CLOSED 1
#define PNL_NO_HEADER 2
-/* uilist layout_type */
+/* uiList layout_type */
enum {
UILST_LAYOUT_DEFAULT = 0,
UILST_LAYOUT_COMPACT = 1,
UILST_LAYOUT_GRID = 2,
};
+/* uiList flag */
+enum {
+ UILST_SCROLL_TO_ACTIVE_ITEM = 1 << 0, /* Scroll list to make active item visible. */
+};
+
/* regiontype, first two are the default set */
/* Do NOT change order, append on end. Types are hardcoded needed */
enum {
diff --git a/source/blender/makesrna/intern/rna_ui_api.c b/source/blender/makesrna/intern/rna_ui_api.c
index 7b90a78811f..d79a40aa615 100644
--- a/source/blender/makesrna/intern/rna_ui_api.c
+++ b/source/blender/makesrna/intern/rna_ui_api.c
@@ -796,9 +796,10 @@ void RNA_api_ui_layout(StructRNA *srna)
parm = RNA_def_string(func, "active_propname", "", 0, "",
"Identifier of the integer property in active_data, index of the active item");
RNA_def_property_flag(parm, PROP_REQUIRED);
- RNA_def_int(func, "rows", 5, 0, INT_MAX, "", "Number of rows to display", 0, INT_MAX);
- RNA_def_int(func, "maxrows", 5, 0, INT_MAX, "", "Maximum number of rows to display", 0, INT_MAX);
+ RNA_def_int(func, "rows", 5, 0, INT_MAX, "", "Default and minimum number of rows to display", 0, INT_MAX);
+ RNA_def_int(func, "maxrows", 5, 0, INT_MAX, "", "Default maximum number of rows to display", 0, INT_MAX);
RNA_def_enum(func, "type", uilist_layout_type_items, UILST_LAYOUT_DEFAULT, "Type", "Type of layout to use");
+ RNA_def_int(func, "columns", 9, 0, INT_MAX, "", "Number of items to display per row, for GRID layout", 0, INT_MAX);
func = RNA_def_function(srna, "template_running_jobs", "uiTemplateRunningJobs");
RNA_def_function_flag(func, FUNC_USE_CONTEXT);
diff --git a/source/blenderplayer/bad_level_call_stubs/stubs.c b/source/blenderplayer/bad_level_call_stubs/stubs.c
index 21502492c05..65d2437a4bb 100644
--- a/source/blenderplayer/bad_level_call_stubs/stubs.c
+++ b/source/blenderplayer/bad_level_call_stubs/stubs.c
@@ -458,7 +458,7 @@ void uiTemplateLayers(struct uiLayout *layout, struct PointerRNA *ptr, char *pro
void uiTemplateImageLayers(struct uiLayout *layout, struct bContext *C, struct Image *ima, struct ImageUser *iuser) {STUB_ASSERT(0);}
void uiTemplateList(struct uiLayout *layout, struct bContext *C, const char *listtype_name, const char *list_id,
PointerRNA *dataptr, const char *propname, PointerRNA *active_dataptr,
- const char *active_propname, int rows, int maxrows, int layout_type) {STUB_ASSERT(0);}
+ const char *active_propname, int rows, int maxrows, int layout_type, int columns) {STUB_ASSERT(0);}
void uiTemplateRunningJobs(struct uiLayout *layout, struct bContext *C) {STUB_ASSERT(0);}
void uiTemplateOperatorSearch(struct uiLayout *layout) {STUB_ASSERT(0);}
void uiTemplateHeader3D(struct uiLayout *layout, struct bContext *C) {STUB_ASSERT(0);}