diff options
author | Campbell Barton <ideasman42@gmail.com> | 2017-11-03 12:26:35 +0300 |
---|---|---|
committer | Campbell Barton <ideasman42@gmail.com> | 2017-11-03 12:57:09 +0300 |
commit | 2a87bd89951204a5dd15b60ba86cbba72fc3b088 (patch) | |
tree | d4eaa0a5bab4f6ca0da0b3d1c0fa8fa8272c0f6a /source/blender/editors/interface/interface_region_search.c | |
parent | d19d094ca9bb4f05b0f95c9f168340050864f103 (diff) |
Cleanup: split interface_regions.c
Each region type is quite separate and file was getting too big.
Diffstat (limited to 'source/blender/editors/interface/interface_region_search.c')
-rw-r--r-- | source/blender/editors/interface/interface_region_search.c | 800 |
1 files changed, 800 insertions, 0 deletions
diff --git a/source/blender/editors/interface/interface_region_search.c b/source/blender/editors/interface/interface_region_search.c new file mode 100644 index 00000000000..c9d313a4bab --- /dev/null +++ b/source/blender/editors/interface/interface_region_search.c @@ -0,0 +1,800 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2008 Blender Foundation. + * All rights reserved. + * + * Contributor(s): Blender Foundation + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/editors/interface/interface_region_search.c + * \ingroup edinterface + * + * Search Box Region & Interaction + */ + +#include <stdarg.h> +#include <stdlib.h> +#include <string.h> +#include <assert.h> + +#include "MEM_guardedalloc.h" + +#include "DNA_userdef_types.h" + +#include "BLI_math.h" + +#include "BLI_string.h" +#include "BLI_rect.h" +#include "BLI_utildefines.h" + +#include "BKE_context.h" +#include "BKE_screen.h" + +#include "WM_api.h" +#include "WM_types.h" + +#include "RNA_access.h" + +#include "BIF_gl.h" + +#include "UI_interface.h" +#include "UI_interface_icons.h" +#include "UI_view2d.h" + +#include "BLT_translation.h" + +#include "ED_screen.h" + +#include "interface_intern.h" +#include "interface_regions_intern.h" + +#define MENU_BORDER (int)(0.3f * U.widget_unit) + +/* -------------------------------------------------------------------- */ +/** \name Search Box Creation + * \{ */ + +struct uiSearchItems { + int maxitem, totitem, maxstrlen; + + int offset, offset_i; /* offset for inserting in array */ + int more; /* flag indicating there are more items */ + + char **names; + void **pointers; + int *icons; + + AutoComplete *autocpl; + void *active; +}; + +typedef struct uiSearchboxData { + rcti bbox; + uiFontStyle fstyle; + uiSearchItems items; + int active; /* index in items array */ + bool noback; /* when menu opened with enough space for this */ + bool preview; /* draw thumbnail previews, rather than list */ + bool use_sep; /* use the UI_SEP_CHAR char for splitting shortcuts (good for operators, bad for data) */ + int prv_rows, prv_cols; +} uiSearchboxData; + +#define SEARCH_ITEMS 10 + +/* exported for use by search callbacks */ +/* returns zero if nothing to add */ +bool UI_search_item_add(uiSearchItems *items, const char *name, void *poin, int iconid) +{ + /* hijack for autocomplete */ + if (items->autocpl) { + UI_autocomplete_update_name(items->autocpl, name); + return true; + } + + /* hijack for finding active item */ + if (items->active) { + if (poin == items->active) + items->offset_i = items->totitem; + items->totitem++; + return true; + } + + if (items->totitem >= items->maxitem) { + items->more = 1; + return false; + } + + /* skip first items in list */ + if (items->offset_i > 0) { + items->offset_i--; + return true; + } + + if (items->names) + BLI_strncpy(items->names[items->totitem], name, items->maxstrlen); + if (items->pointers) + items->pointers[items->totitem] = poin; + if (items->icons) + items->icons[items->totitem] = iconid; + + items->totitem++; + + return true; +} + +int UI_searchbox_size_y(void) +{ + return SEARCH_ITEMS * UI_UNIT_Y + 2 * UI_POPUP_MENU_TOP; +} + +int UI_searchbox_size_x(void) +{ + return 12 * UI_UNIT_X; +} + +int UI_search_items_find_index(uiSearchItems *items, const char *name) +{ + int i; + for (i = 0; i < items->totitem; i++) { + if (STREQ(name, items->names[i])) { + return i; + } + } + return -1; +} + +/* ar is the search box itself */ +static void ui_searchbox_select(bContext *C, ARegion *ar, uiBut *but, int step) +{ + uiSearchboxData *data = ar->regiondata; + + /* apply step */ + data->active += step; + + if (data->items.totitem == 0) { + data->active = -1; + } + else if (data->active >= data->items.totitem) { + if (data->items.more) { + data->items.offset++; + data->active = data->items.totitem - 1; + ui_searchbox_update(C, ar, but, false); + } + else { + data->active = data->items.totitem - 1; + } + } + else if (data->active < 0) { + if (data->items.offset) { + data->items.offset--; + data->active = 0; + ui_searchbox_update(C, ar, but, false); + } + else { + /* only let users step into an 'unset' state for unlink buttons */ + data->active = (but->flag & UI_BUT_VALUE_CLEAR) ? -1 : 0; + } + } + + ED_region_tag_redraw(ar); +} + +static void ui_searchbox_butrect(rcti *r_rect, uiSearchboxData *data, int itemnr) +{ + /* thumbnail preview */ + if (data->preview) { + int butw = (BLI_rcti_size_x(&data->bbox) - 2 * MENU_BORDER) / data->prv_cols; + int buth = (BLI_rcti_size_y(&data->bbox) - 2 * MENU_BORDER) / data->prv_rows; + int row, col; + + *r_rect = data->bbox; + + col = itemnr % data->prv_cols; + row = itemnr / data->prv_cols; + + r_rect->xmin += MENU_BORDER + (col * butw); + r_rect->xmax = r_rect->xmin + butw; + + r_rect->ymax -= MENU_BORDER + (row * buth); + r_rect->ymin = r_rect->ymax - buth; + } + /* list view */ + else { + int buth = (BLI_rcti_size_y(&data->bbox) - 2 * UI_POPUP_MENU_TOP) / SEARCH_ITEMS; + + *r_rect = data->bbox; + r_rect->xmin = data->bbox.xmin + 3.0f; + r_rect->xmax = data->bbox.xmax - 3.0f; + + r_rect->ymax = data->bbox.ymax - UI_POPUP_MENU_TOP - itemnr * buth; + r_rect->ymin = r_rect->ymax - buth; + } + +} + +int ui_searchbox_find_index(ARegion *ar, const char *name) +{ + uiSearchboxData *data = ar->regiondata; + return UI_search_items_find_index(&data->items, name); +} + +/* x and y in screencoords */ +bool ui_searchbox_inside(ARegion *ar, int x, int y) +{ + uiSearchboxData *data = ar->regiondata; + + return BLI_rcti_isect_pt(&data->bbox, x - ar->winrct.xmin, y - ar->winrct.ymin); +} + +/* string validated to be of correct length (but->hardmax) */ +bool ui_searchbox_apply(uiBut *but, ARegion *ar) +{ + uiSearchboxData *data = ar->regiondata; + + but->func_arg2 = NULL; + + if (data->active != -1) { + const char *name = data->items.names[data->active]; + const char *name_sep = data->use_sep ? strrchr(name, UI_SEP_CHAR) : NULL; + + BLI_strncpy(but->editstr, name, name_sep ? (name_sep - name) : data->items.maxstrlen); + + but->func_arg2 = data->items.pointers[data->active]; + + return true; + } + else if (but->flag & UI_BUT_VALUE_CLEAR) { + /* It is valid for _VALUE_CLEAR flavor to have no active element (it's a valid way to unlink). */ + but->editstr[0] = '\0'; + + return true; + } + else { + return false; + } +} + +void ui_searchbox_event(bContext *C, ARegion *ar, uiBut *but, const wmEvent *event) +{ + uiSearchboxData *data = ar->regiondata; + int type = event->type, val = event->val; + + if (type == MOUSEPAN) + ui_pan_to_scroll(event, &type, &val); + + switch (type) { + case WHEELUPMOUSE: + case UPARROWKEY: + ui_searchbox_select(C, ar, but, -1); + break; + case WHEELDOWNMOUSE: + case DOWNARROWKEY: + ui_searchbox_select(C, ar, but, 1); + break; + case MOUSEMOVE: + if (BLI_rcti_isect_pt(&ar->winrct, event->x, event->y)) { + rcti rect; + int a; + + for (a = 0; a < data->items.totitem; a++) { + ui_searchbox_butrect(&rect, data, a); + if (BLI_rcti_isect_pt(&rect, event->x - ar->winrct.xmin, event->y - ar->winrct.ymin)) { + if (data->active != a) { + data->active = a; + ui_searchbox_select(C, ar, but, 0); + break; + } + } + } + } + break; + } +} + +/* ar is the search box itself */ +void ui_searchbox_update(bContext *C, ARegion *ar, uiBut *but, const bool reset) +{ + uiSearchboxData *data = ar->regiondata; + + /* reset vars */ + data->items.totitem = 0; + data->items.more = 0; + if (reset == false) { + data->items.offset_i = data->items.offset; + } + else { + data->items.offset_i = data->items.offset = 0; + data->active = -1; + + /* handle active */ + if (but->search_func && but->func_arg2) { + data->items.active = but->func_arg2; + but->search_func(C, but->search_arg, but->editstr, &data->items); + data->items.active = NULL; + + /* found active item, calculate real offset by centering it */ + if (data->items.totitem) { + /* first case, begin of list */ + if (data->items.offset_i < data->items.maxitem) { + data->active = data->items.offset_i; + data->items.offset_i = 0; + } + else { + /* second case, end of list */ + if (data->items.totitem - data->items.offset_i <= data->items.maxitem) { + data->active = data->items.offset_i - data->items.totitem + data->items.maxitem; + data->items.offset_i = data->items.totitem - data->items.maxitem; + } + else { + /* center active item */ + data->items.offset_i -= data->items.maxitem / 2; + data->active = data->items.maxitem / 2; + } + } + } + data->items.offset = data->items.offset_i; + data->items.totitem = 0; + } + } + + /* callback */ + if (but->search_func) + but->search_func(C, but->search_arg, but->editstr, &data->items); + + /* handle case where editstr is equal to one of items */ + if (reset && data->active == -1) { + int a; + + for (a = 0; a < data->items.totitem; a++) { + const char *name = data->items.names[a]; + const char *name_sep = data->use_sep ? strrchr(name, UI_SEP_CHAR) : NULL; + if (STREQLEN(but->editstr, name, name_sep ? (name_sep - name) : data->items.maxstrlen)) { + data->active = a; + break; + } + } + if (data->items.totitem == 1 && but->editstr[0]) + data->active = 0; + } + + /* validate selected item */ + ui_searchbox_select(C, ar, but, 0); + + ED_region_tag_redraw(ar); +} + +int ui_searchbox_autocomplete(bContext *C, ARegion *ar, uiBut *but, char *str) +{ + uiSearchboxData *data = ar->regiondata; + int match = AUTOCOMPLETE_NO_MATCH; + + if (str[0]) { + data->items.autocpl = UI_autocomplete_begin(str, ui_but_string_get_max_length(but)); + + but->search_func(C, but->search_arg, but->editstr, &data->items); + + match = UI_autocomplete_end(data->items.autocpl, str); + data->items.autocpl = NULL; + } + + return match; +} + +static void ui_searchbox_region_draw_cb(const bContext *UNUSED(C), ARegion *ar) +{ + uiSearchboxData *data = ar->regiondata; + + /* pixel space */ + wmOrtho2_region_pixelspace(ar); + + if (data->noback == false) + ui_draw_search_back(NULL, NULL, &data->bbox); /* style not used yet */ + + /* draw text */ + if (data->items.totitem) { + rcti rect; + int a; + + if (data->preview) { + /* draw items */ + for (a = 0; a < data->items.totitem; a++) { + ui_searchbox_butrect(&rect, data, a); + + /* widget itself */ + ui_draw_preview_item(&data->fstyle, &rect, data->items.names[a], data->items.icons[a], + (a == data->active) ? UI_ACTIVE : 0); + } + + /* indicate more */ + if (data->items.more) { + ui_searchbox_butrect(&rect, data, data->items.maxitem - 1); + glEnable(GL_BLEND); + UI_icon_draw(rect.xmax - 18, rect.ymin - 7, ICON_TRIA_DOWN); + glDisable(GL_BLEND); + } + if (data->items.offset) { + ui_searchbox_butrect(&rect, data, 0); + glEnable(GL_BLEND); + UI_icon_draw(rect.xmin, rect.ymax - 9, ICON_TRIA_UP); + glDisable(GL_BLEND); + } + + } + else { + /* draw items */ + for (a = 0; a < data->items.totitem; a++) { + ui_searchbox_butrect(&rect, data, a); + + /* widget itself */ + ui_draw_menu_item(&data->fstyle, &rect, data->items.names[a], data->items.icons[a], + (a == data->active) ? UI_ACTIVE : 0, data->use_sep); + + } + /* indicate more */ + if (data->items.more) { + ui_searchbox_butrect(&rect, data, data->items.maxitem - 1); + glEnable(GL_BLEND); + UI_icon_draw((BLI_rcti_size_x(&rect)) / 2, rect.ymin - 9, ICON_TRIA_DOWN); + glDisable(GL_BLEND); + } + if (data->items.offset) { + ui_searchbox_butrect(&rect, data, 0); + glEnable(GL_BLEND); + UI_icon_draw((BLI_rcti_size_x(&rect)) / 2, rect.ymax - 7, ICON_TRIA_UP); + glDisable(GL_BLEND); + } + } + } +} + +static void ui_searchbox_region_free_cb(ARegion *ar) +{ + uiSearchboxData *data = ar->regiondata; + int a; + + /* free search data */ + for (a = 0; a < data->items.maxitem; a++) { + MEM_freeN(data->items.names[a]); + } + MEM_freeN(data->items.names); + MEM_freeN(data->items.pointers); + MEM_freeN(data->items.icons); + + MEM_freeN(data); + ar->regiondata = NULL; +} + +ARegion *ui_searchbox_create_generic(bContext *C, ARegion *butregion, uiBut *but) +{ + wmWindow *win = CTX_wm_window(C); + uiStyle *style = UI_style_get(); + static ARegionType type; + ARegion *ar; + uiSearchboxData *data; + float aspect = but->block->aspect; + rctf rect_fl; + rcti rect_i; + const int margin = UI_POPUP_MARGIN; + int winx /*, winy */, ofsx, ofsy; + int i; + + /* create area region */ + ar = ui_region_temp_add(CTX_wm_screen(C)); + + memset(&type, 0, sizeof(ARegionType)); + type.draw = ui_searchbox_region_draw_cb; + type.free = ui_searchbox_region_free_cb; + type.regionid = RGN_TYPE_TEMPORARY; + ar->type = &type; + + /* create searchbox data */ + data = MEM_callocN(sizeof(uiSearchboxData), "uiSearchboxData"); + + /* set font, get bb */ + data->fstyle = style->widget; /* copy struct */ + data->fstyle.align = UI_STYLE_TEXT_CENTER; + ui_fontscale(&data->fstyle.points, aspect); + UI_fontstyle_set(&data->fstyle); + + ar->regiondata = data; + + /* special case, hardcoded feature, not draw backdrop when called from menus, + * assume for design that popup already added it */ + if (but->block->flag & UI_BLOCK_SEARCH_MENU) + data->noback = true; + + if (but->a1 > 0 && but->a2 > 0) { + data->preview = true; + data->prv_rows = but->a1; + data->prv_cols = but->a2; + } + + /* only show key shortcuts when needed (not rna buttons) [#36699] */ + if (but->rnaprop == NULL) { + data->use_sep = true; + } + + /* compute position */ + if (but->block->flag & UI_BLOCK_SEARCH_MENU) { + const int search_but_h = BLI_rctf_size_y(&but->rect) + 10; + /* this case is search menu inside other menu */ + /* we copy region size */ + + ar->winrct = butregion->winrct; + + /* widget rect, in region coords */ + data->bbox.xmin = margin; + data->bbox.xmax = BLI_rcti_size_x(&ar->winrct) - margin; + data->bbox.ymin = margin; + data->bbox.ymax = BLI_rcti_size_y(&ar->winrct) - margin; + + /* check if button is lower half */ + if (but->rect.ymax < BLI_rctf_cent_y(&but->block->rect)) { + data->bbox.ymin += search_but_h; + } + else { + data->bbox.ymax -= search_but_h; + } + } + else { + const int searchbox_width = UI_searchbox_size_x(); + + rect_fl.xmin = but->rect.xmin - 5; /* align text with button */ + rect_fl.xmax = but->rect.xmax + 5; /* symmetrical */ + rect_fl.ymax = but->rect.ymin; + rect_fl.ymin = rect_fl.ymax - UI_searchbox_size_y(); + + ofsx = (but->block->panel) ? but->block->panel->ofsx : 0; + ofsy = (but->block->panel) ? but->block->panel->ofsy : 0; + + BLI_rctf_translate(&rect_fl, ofsx, ofsy); + + /* minimal width */ + if (BLI_rctf_size_x(&rect_fl) < searchbox_width) { + rect_fl.xmax = rect_fl.xmin + searchbox_width; + } + + /* copy to int, gets projected if possible too */ + BLI_rcti_rctf_copy(&rect_i, &rect_fl); + + if (butregion->v2d.cur.xmin != butregion->v2d.cur.xmax) { + UI_view2d_view_to_region_rcti(&butregion->v2d, &rect_fl, &rect_i); + } + + BLI_rcti_translate(&rect_i, butregion->winrct.xmin, butregion->winrct.ymin); + + winx = WM_window_pixels_x(win); + // winy = WM_window_pixels_y(win); /* UNUSED */ + //wm_window_get_size(win, &winx, &winy); + + if (rect_i.xmax > winx) { + /* super size */ + if (rect_i.xmax > winx + rect_i.xmin) { + rect_i.xmax = winx; + rect_i.xmin = 0; + } + else { + rect_i.xmin -= rect_i.xmax - winx; + rect_i.xmax = winx; + } + } + + if (rect_i.ymin < 0) { + int newy1 = but->rect.ymax + ofsy; + + if (butregion->v2d.cur.xmin != butregion->v2d.cur.xmax) + newy1 = UI_view2d_view_to_region_y(&butregion->v2d, newy1); + + newy1 += butregion->winrct.ymin; + + rect_i.ymax = BLI_rcti_size_y(&rect_i) + newy1; + rect_i.ymin = newy1; + } + + /* widget rect, in region coords */ + data->bbox.xmin = margin; + data->bbox.xmax = BLI_rcti_size_x(&rect_i) + margin; + data->bbox.ymin = margin; + data->bbox.ymax = BLI_rcti_size_y(&rect_i) + margin; + + /* region bigger for shadow */ + ar->winrct.xmin = rect_i.xmin - margin; + ar->winrct.xmax = rect_i.xmax + margin; + ar->winrct.ymin = rect_i.ymin - margin; + ar->winrct.ymax = rect_i.ymax; + } + + /* adds subwindow */ + ED_region_init(C, ar); + + /* notify change and redraw */ + ED_region_tag_redraw(ar); + + /* prepare search data */ + if (data->preview) { + data->items.maxitem = data->prv_rows * data->prv_cols; + } + else { + data->items.maxitem = SEARCH_ITEMS; + } + data->items.maxstrlen = but->hardmax; + data->items.totitem = 0; + data->items.names = MEM_callocN(data->items.maxitem * sizeof(void *), "search names"); + data->items.pointers = MEM_callocN(data->items.maxitem * sizeof(void *), "search pointers"); + data->items.icons = MEM_callocN(data->items.maxitem * sizeof(int), "search icons"); + for (i = 0; i < data->items.maxitem; i++) + data->items.names[i] = MEM_callocN(but->hardmax + 1, "search pointers"); + + return ar; +} + +/** + * Similar to Python's `str.title` except... + * + * - we know words are upper case and ascii only. + * - '_' are replaces by spaces. + */ +static void str_tolower_titlecaps_ascii(char *str, const size_t len) +{ + size_t i; + bool prev_delim = true; + + for (i = 0; (i < len) && str[i]; i++) { + if (str[i] >= 'A' && str[i] <= 'Z') { + if (prev_delim == false) { + str[i] += 'a' - 'A'; + } + } + else if (str[i] == '_') { + str[i] = ' '; + } + + prev_delim = ELEM(str[i], ' ') || (str[i] >= '0' && str[i] <= '9'); + } + +} + +static void ui_searchbox_region_draw_cb__operator(const bContext *UNUSED(C), ARegion *ar) +{ + uiSearchboxData *data = ar->regiondata; + + /* pixel space */ + wmOrtho2_region_pixelspace(ar); + + if (data->noback == false) + ui_draw_search_back(NULL, NULL, &data->bbox); /* style not used yet */ + + /* draw text */ + if (data->items.totitem) { + rcti rect; + int a; + + /* draw items */ + for (a = 0; a < data->items.totitem; a++) { + rcti rect_pre, rect_post; + ui_searchbox_butrect(&rect, data, a); + + rect_pre = rect; + rect_post = rect; + + rect_pre.xmax = rect_post.xmin = rect.xmin + ((rect.xmax - rect.xmin) / 4); + + /* widget itself */ + /* NOTE: i18n messages extracting tool does the same, please keep it in sync. */ + { + wmOperatorType *ot = data->items.pointers[a]; + + int state = (a == data->active) ? UI_ACTIVE : 0; + char text_pre[128]; + char *text_pre_p = strstr(ot->idname, "_OT_"); + if (text_pre_p == NULL) { + text_pre[0] = '\0'; + } + else { + int text_pre_len; + text_pre_p += 1; + text_pre_len = BLI_strncpy_rlen( + text_pre, ot->idname, min_ii(sizeof(text_pre), text_pre_p - ot->idname)); + text_pre[text_pre_len] = ':'; + text_pre[text_pre_len + 1] = '\0'; + str_tolower_titlecaps_ascii(text_pre, sizeof(text_pre)); + } + + rect_pre.xmax += 4; /* sneaky, avoid showing ugly margin */ + ui_draw_menu_item(&data->fstyle, &rect_pre, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, text_pre), + data->items.icons[a], state, false); + ui_draw_menu_item(&data->fstyle, &rect_post, data->items.names[a], 0, state, data->use_sep); + } + + } + /* indicate more */ + if (data->items.more) { + ui_searchbox_butrect(&rect, data, data->items.maxitem - 1); + glEnable(GL_BLEND); + UI_icon_draw((BLI_rcti_size_x(&rect)) / 2, rect.ymin - 9, ICON_TRIA_DOWN); + glDisable(GL_BLEND); + } + if (data->items.offset) { + ui_searchbox_butrect(&rect, data, 0); + glEnable(GL_BLEND); + UI_icon_draw((BLI_rcti_size_x(&rect)) / 2, rect.ymax - 7, ICON_TRIA_UP); + glDisable(GL_BLEND); + } + } +} + +ARegion *ui_searchbox_create_operator(bContext *C, ARegion *butregion, uiBut *but) +{ + ARegion *ar; + + ar = ui_searchbox_create_generic(C, butregion, but); + + ar->type->draw = ui_searchbox_region_draw_cb__operator; + + return ar; +} + +void ui_searchbox_free(bContext *C, ARegion *ar) +{ + ui_region_temp_remove(C, CTX_wm_screen(C), ar); +} + +/* sets red alert if button holds a string it can't find */ +/* XXX weak: search_func adds all partial matches... */ +void ui_but_search_refresh(uiBut *but) +{ + uiSearchItems *items; + int x1; + + /* possibly very large lists (such as ID datablocks) only + * only validate string RNA buts (not pointers) */ + if (but->rnaprop && RNA_property_type(but->rnaprop) != PROP_STRING) { + return; + } + + items = MEM_callocN(sizeof(uiSearchItems), "search items"); + + /* setup search struct */ + items->maxitem = 10; + items->maxstrlen = 256; + items->names = MEM_callocN(items->maxitem * sizeof(void *), "search names"); + for (x1 = 0; x1 < items->maxitem; x1++) + items->names[x1] = MEM_callocN(but->hardmax + 1, "search names"); + + but->search_func(but->block->evil_C, but->search_arg, but->drawstr, items); + + /* only redalert when we are sure of it, this can miss cases when >10 matches */ + if (items->totitem == 0) { + UI_but_flag_enable(but, UI_BUT_REDALERT); + } + else if (items->more == 0) { + if (UI_search_items_find_index(items, but->drawstr) == -1) { + UI_but_flag_enable(but, UI_BUT_REDALERT); + } + } + + for (x1 = 0; x1 < items->maxitem; x1++) { + MEM_freeN(items->names[x1]); + } + MEM_freeN(items->names); + MEM_freeN(items); +} + +/** \} */ |