| 
									
										
										
										
											2017-11-03 20:26:35 +11:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  * 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. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-18 08:08:12 +11:00
										 |  |  | /** \file
 | 
					
						
							|  |  |  |  * \ingroup edinterface | 
					
						
							| 
									
										
										
										
											2017-11-03 20:26:35 +11:00
										 |  |  |  * | 
					
						
							|  |  |  |  * Search Box Region & Interaction | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-19 09:33:03 +01:00
										 |  |  | #include <assert.h>
 | 
					
						
							| 
									
										
										
										
											2017-11-03 20:26:35 +11:00
										 |  |  | #include <stdarg.h>
 | 
					
						
							|  |  |  | #include <stdlib.h>
 | 
					
						
							|  |  |  | #include <string.h>
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-14 18:46:13 +10:00
										 |  |  | #include "DNA_ID.h"
 | 
					
						
							| 
									
										
										
										
											2017-11-03 20:26:35 +11:00
										 |  |  | #include "MEM_guardedalloc.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "DNA_userdef_types.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "BLI_math.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "BLI_rect.h"
 | 
					
						
							| 
									
										
										
										
											2020-03-19 09:33:03 +01:00
										 |  |  | #include "BLI_string.h"
 | 
					
						
							| 
									
										
										
										
											2017-11-03 20:26:35 +11:00
										 |  |  | #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 "UI_interface.h"
 | 
					
						
							|  |  |  | #include "UI_interface_icons.h"
 | 
					
						
							|  |  |  | #include "UI_view2d.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "BLT_translation.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "ED_screen.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-19 09:33:03 +01:00
										 |  |  | #include "GPU_state.h"
 | 
					
						
							| 
									
										
										
										
											2017-11-03 20:26:35 +11:00
										 |  |  | #include "interface_intern.h"
 | 
					
						
							|  |  |  | #include "interface_regions_intern.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  | #define MENU_BORDER (int)(0.3f * U.widget_unit)
 | 
					
						
							| 
									
										
										
										
											2017-11-03 20:26:35 +11:00
										 |  |  | 
 | 
					
						
							|  |  |  | /* -------------------------------------------------------------------- */ | 
					
						
							|  |  |  | /** \name Search Box Creation
 | 
					
						
							|  |  |  |  * \{ */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | struct uiSearchItems { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   int maxitem, totitem, maxstrlen; | 
					
						
							| 
									
										
										
										
											2017-11-03 20:26:35 +11:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   int offset, offset_i; /* offset for inserting in array */ | 
					
						
							|  |  |  |   int more;             /* flag indicating there are more items */ | 
					
						
							| 
									
										
										
										
											2017-11-03 20:26:35 +11:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   char **names; | 
					
						
							|  |  |  |   void **pointers; | 
					
						
							|  |  |  |   int *icons; | 
					
						
							| 
									
										
										
										
											2020-03-24 11:34:18 +11:00
										 |  |  |   int *states; | 
					
						
							| 
									
										
										
										
											2017-11-03 20:26:35 +11:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   AutoComplete *autocpl; | 
					
						
							|  |  |  |   void *active; | 
					
						
							| 
									
										
										
										
											2017-11-03 20:26:35 +11:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | typedef struct uiSearchboxData { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   rcti bbox; | 
					
						
							|  |  |  |   uiFontStyle fstyle; | 
					
						
							|  |  |  |   uiSearchItems items; | 
					
						
							|  |  |  |   /** index in items array */ | 
					
						
							|  |  |  |   int active; | 
					
						
							|  |  |  |   /** when menu opened with enough space for this */ | 
					
						
							|  |  |  |   bool noback; | 
					
						
							|  |  |  |   /** draw thumbnail previews, rather than list */ | 
					
						
							|  |  |  |   bool preview; | 
					
						
							| 
									
										
										
										
											2020-04-14 18:46:13 +10:00
										 |  |  |   /** Use the #UI_SEP_CHAR char for splitting shortcuts (good for operators, bad for data). */ | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   bool use_sep; | 
					
						
							|  |  |  |   int prv_rows, prv_cols; | 
					
						
							| 
									
										
										
										
											2020-04-14 18:46:13 +10:00
										 |  |  |   /**
 | 
					
						
							|  |  |  |    * Show the active icon and text after the last instance of this string. | 
					
						
							|  |  |  |    * Used so we can show leading text to menu items less prominently (not related to 'use_sep'). | 
					
						
							|  |  |  |    */ | 
					
						
							|  |  |  |   const char *sep_string; | 
					
						
							| 
									
										
										
										
											2017-11-03 20:26:35 +11:00
										 |  |  | } uiSearchboxData; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  | #define SEARCH_ITEMS 10
 | 
					
						
							| 
									
										
										
										
											2017-11-03 20:26:35 +11:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-24 11:34:18 +11:00
										 |  |  | /**
 | 
					
						
							|  |  |  |  * Public function exported for functions that use #UI_BTYPE_SEARCH_MENU. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * \param items: Stores the items. | 
					
						
							|  |  |  |  * \param name: Text to display for the item. | 
					
						
							|  |  |  |  * \param poin: Opaque pointer (for use by the caller). | 
					
						
							|  |  |  |  * \param iconid: The icon, #ICON_NONE for no icon. | 
					
						
							|  |  |  |  * \param state: The buttons state flag, compatible with #uiBut.flag, | 
					
						
							|  |  |  |  * typically #UI_BUT_DISABLED / #UI_BUT_INACTIVE. | 
					
						
							|  |  |  |  * \return false if there is nothing to add. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | bool UI_search_item_add(uiSearchItems *items, const char *name, void *poin, int iconid, int state) | 
					
						
							| 
									
										
										
										
											2017-11-03 20:26:35 +11:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   /* 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; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-24 11:34:18 +11:00
										 |  |  |   /* Limit flags that can be set so flags such as 'UI_SELECT' aren't accidentally set
 | 
					
						
							|  |  |  |    * which will cause problems, add others as needed. */ | 
					
						
							|  |  |  |   BLI_assert((state & ~(UI_BUT_DISABLED | UI_BUT_INACTIVE | UI_BUT_REDALERT)) == 0); | 
					
						
							|  |  |  |   if (items->states) { | 
					
						
							|  |  |  |     items->states[items->totitem] = state; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   items->totitem++; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return true; | 
					
						
							| 
									
										
										
										
											2017-11-03 20:26:35 +11:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int UI_searchbox_size_y(void) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   return SEARCH_ITEMS * UI_UNIT_Y + 2 * UI_POPUP_MENU_TOP; | 
					
						
							| 
									
										
										
										
											2017-11-03 20:26:35 +11:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int UI_searchbox_size_x(void) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   return 12 * UI_UNIT_X; | 
					
						
							| 
									
										
										
										
											2017-11-03 20:26:35 +11:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int UI_search_items_find_index(uiSearchItems *items, const char *name) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   int i; | 
					
						
							|  |  |  |   for (i = 0; i < items->totitem; i++) { | 
					
						
							|  |  |  |     if (STREQ(name, items->names[i])) { | 
					
						
							|  |  |  |       return i; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   return -1; | 
					
						
							| 
									
										
										
										
											2017-11-03 20:26:35 +11:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-06 16:56:42 +01:00
										 |  |  | /* region is the search box itself */ | 
					
						
							|  |  |  | static void ui_searchbox_select(bContext *C, ARegion *region, uiBut *but, int step) | 
					
						
							| 
									
										
										
										
											2017-11-03 20:26:35 +11:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2020-03-06 16:56:42 +01:00
										 |  |  |   uiSearchboxData *data = region->regiondata; | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |   /* 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; | 
					
						
							| 
									
										
										
										
											2020-03-06 16:56:42 +01:00
										 |  |  |       ui_searchbox_update(C, region, but, false); | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     } | 
					
						
							|  |  |  |     else { | 
					
						
							|  |  |  |       data->active = data->items.totitem - 1; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   else if (data->active < 0) { | 
					
						
							|  |  |  |     if (data->items.offset) { | 
					
						
							|  |  |  |       data->items.offset--; | 
					
						
							|  |  |  |       data->active = 0; | 
					
						
							| 
									
										
										
										
											2020-03-06 16:56:42 +01:00
										 |  |  |       ui_searchbox_update(C, region, but, false); | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     } | 
					
						
							|  |  |  |     else { | 
					
						
							|  |  |  |       /* only let users step into an 'unset' state for unlink buttons */ | 
					
						
							|  |  |  |       data->active = (but->flag & UI_BUT_VALUE_CLEAR) ? -1 : 0; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-06 16:56:42 +01:00
										 |  |  |   ED_region_tag_redraw(region); | 
					
						
							| 
									
										
										
										
											2017-11-03 20:26:35 +11:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void ui_searchbox_butrect(rcti *r_rect, uiSearchboxData *data, int itemnr) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   /* 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; | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2017-11-03 20:26:35 +11:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-06 16:56:42 +01:00
										 |  |  | int ui_searchbox_find_index(ARegion *region, const char *name) | 
					
						
							| 
									
										
										
										
											2017-11-03 20:26:35 +11:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2020-03-06 16:56:42 +01:00
										 |  |  |   uiSearchboxData *data = region->regiondata; | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   return UI_search_items_find_index(&data->items, name); | 
					
						
							| 
									
										
										
										
											2017-11-03 20:26:35 +11:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* x and y in screencoords */ | 
					
						
							| 
									
										
										
										
											2020-03-06 16:56:42 +01:00
										 |  |  | bool ui_searchbox_inside(ARegion *region, int x, int y) | 
					
						
							| 
									
										
										
										
											2017-11-03 20:26:35 +11:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2020-03-06 16:56:42 +01:00
										 |  |  |   uiSearchboxData *data = region->regiondata; | 
					
						
							| 
									
										
										
										
											2017-11-03 20:26:35 +11:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-06 16:56:42 +01:00
										 |  |  |   return BLI_rcti_isect_pt(&data->bbox, x - region->winrct.xmin, y - region->winrct.ymin); | 
					
						
							| 
									
										
										
										
											2017-11-03 20:26:35 +11:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* string validated to be of correct length (but->hardmax) */ | 
					
						
							| 
									
										
										
										
											2020-03-06 16:56:42 +01:00
										 |  |  | bool ui_searchbox_apply(uiBut *but, ARegion *region) | 
					
						
							| 
									
										
										
										
											2017-11-03 20:26:35 +11:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2020-03-06 16:56:42 +01:00
										 |  |  |   uiSearchboxData *data = region->regiondata; | 
					
						
							| 
									
										
										
										
											2017-11-03 20:26:35 +11:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   but->func_arg2 = NULL; | 
					
						
							| 
									
										
										
										
											2017-11-03 20:26:35 +11:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   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; | 
					
						
							| 
									
										
										
										
											2017-11-03 20:26:35 +11:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     BLI_strncpy(but->editstr, name, name_sep ? (name_sep - name) : data->items.maxstrlen); | 
					
						
							| 
									
										
										
										
											2017-11-03 20:26:35 +11:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     but->func_arg2 = data->items.pointers[data->active]; | 
					
						
							| 
									
										
										
										
											2017-11-03 20:26:35 +11:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     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'; | 
					
						
							| 
									
										
										
										
											2017-11-03 20:26:35 +11:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     return true; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   else { | 
					
						
							|  |  |  |     return false; | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2017-11-03 20:26:35 +11:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-06 16:56:42 +01:00
										 |  |  | void ui_searchbox_event(bContext *C, ARegion *region, uiBut *but, const wmEvent *event) | 
					
						
							| 
									
										
										
										
											2017-11-03 20:26:35 +11:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2020-03-06 16:56:42 +01:00
										 |  |  |   uiSearchboxData *data = region->regiondata; | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   int type = event->type, val = event->val; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (type == MOUSEPAN) { | 
					
						
							|  |  |  |     ui_pan_to_scroll(event, &type, &val); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   switch (type) { | 
					
						
							|  |  |  |     case WHEELUPMOUSE: | 
					
						
							| 
									
										
										
										
											2020-03-18 10:38:37 -06:00
										 |  |  |     case EVT_UPARROWKEY: | 
					
						
							| 
									
										
										
										
											2020-03-06 16:56:42 +01:00
										 |  |  |       ui_searchbox_select(C, region, but, -1); | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |       break; | 
					
						
							|  |  |  |     case WHEELDOWNMOUSE: | 
					
						
							| 
									
										
										
										
											2020-03-18 10:38:37 -06:00
										 |  |  |     case EVT_DOWNARROWKEY: | 
					
						
							| 
									
										
										
										
											2020-03-06 16:56:42 +01:00
										 |  |  |       ui_searchbox_select(C, region, but, 1); | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |       break; | 
					
						
							|  |  |  |     case MOUSEMOVE: | 
					
						
							| 
									
										
										
										
											2020-03-06 16:56:42 +01:00
										 |  |  |       if (BLI_rcti_isect_pt(®ion->winrct, event->x, event->y)) { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |         rcti rect; | 
					
						
							|  |  |  |         int a; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         for (a = 0; a < data->items.totitem; a++) { | 
					
						
							|  |  |  |           ui_searchbox_butrect(&rect, data, a); | 
					
						
							| 
									
										
										
										
											2020-03-06 16:56:42 +01:00
										 |  |  |           if (BLI_rcti_isect_pt( | 
					
						
							|  |  |  |                   &rect, event->x - region->winrct.xmin, event->y - region->winrct.ymin)) { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |             if (data->active != a) { | 
					
						
							|  |  |  |               data->active = a; | 
					
						
							| 
									
										
										
										
											2020-03-06 16:56:42 +01:00
										 |  |  |               ui_searchbox_select(C, region, but, 0); | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |               break; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       break; | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2017-11-03 20:26:35 +11:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-06 16:56:42 +01:00
										 |  |  | /* region is the search box itself */ | 
					
						
							|  |  |  | void ui_searchbox_update(bContext *C, ARegion *region, uiBut *but, const bool reset) | 
					
						
							| 
									
										
										
										
											2017-11-03 20:26:35 +11:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2020-03-06 16:56:42 +01:00
										 |  |  |   uiSearchboxData *data = region->regiondata; | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |   /* 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 */ | 
					
						
							| 
									
										
										
										
											2020-05-07 23:16:05 +10:00
										 |  |  |     if (but->search->update_fn && but->func_arg2) { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |       data->items.active = but->func_arg2; | 
					
						
							| 
									
										
										
										
											2020-05-07 23:16:05 +10:00
										 |  |  |       but->search->update_fn(C, but->search->arg, but->editstr, &data->items); | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |       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 */ | 
					
						
							| 
									
										
										
										
											2020-05-07 23:16:05 +10:00
										 |  |  |   if (but->search->update_fn) { | 
					
						
							|  |  |  |     but->search->update_fn(C, but->search->arg, but->editstr, &data->items); | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /* 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 */ | 
					
						
							| 
									
										
										
										
											2020-03-06 16:56:42 +01:00
										 |  |  |   ui_searchbox_select(C, region, but, 0); | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-06 16:56:42 +01:00
										 |  |  |   ED_region_tag_redraw(region); | 
					
						
							| 
									
										
										
										
											2017-11-03 20:26:35 +11:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-06 16:56:42 +01:00
										 |  |  | int ui_searchbox_autocomplete(bContext *C, ARegion *region, uiBut *but, char *str) | 
					
						
							| 
									
										
										
										
											2017-11-03 20:26:35 +11:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2020-03-06 16:56:42 +01:00
										 |  |  |   uiSearchboxData *data = region->regiondata; | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   int match = AUTOCOMPLETE_NO_MATCH; | 
					
						
							| 
									
										
										
										
											2017-11-03 20:26:35 +11:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   if (str[0]) { | 
					
						
							|  |  |  |     data->items.autocpl = UI_autocomplete_begin(str, ui_but_string_get_max_length(but)); | 
					
						
							| 
									
										
										
										
											2017-11-03 20:26:35 +11:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-07 23:16:05 +10:00
										 |  |  |     but->search->update_fn(C, but->search->arg, but->editstr, &data->items); | 
					
						
							| 
									
										
										
										
											2017-11-03 20:26:35 +11:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     match = UI_autocomplete_end(data->items.autocpl, str); | 
					
						
							|  |  |  |     data->items.autocpl = NULL; | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2017-11-03 20:26:35 +11:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   return match; | 
					
						
							| 
									
										
										
										
											2017-11-03 20:26:35 +11:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-06 16:56:42 +01:00
										 |  |  | static void ui_searchbox_region_draw_cb(const bContext *C, ARegion *region) | 
					
						
							| 
									
										
										
										
											2017-11-03 20:26:35 +11:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2020-03-06 16:56:42 +01:00
										 |  |  |   uiSearchboxData *data = region->regiondata; | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |   /* pixel space */ | 
					
						
							| 
									
										
										
										
											2020-03-06 16:56:42 +01:00
										 |  |  |   wmOrtho2_region_pixelspace(region); | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |   if (data->noback == false) { | 
					
						
							|  |  |  |     ui_draw_widget_menu_back(&data->bbox, true); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /* draw text */ | 
					
						
							|  |  |  |   if (data->items.totitem) { | 
					
						
							|  |  |  |     rcti rect; | 
					
						
							|  |  |  |     int a; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (data->preview) { | 
					
						
							|  |  |  |       /* draw items */ | 
					
						
							|  |  |  |       for (a = 0; a < data->items.totitem; a++) { | 
					
						
							| 
									
										
										
										
											2020-03-24 11:34:18 +11:00
										 |  |  |         const int state = ((a == data->active) ? UI_ACTIVE : 0) | data->items.states[a]; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |         /* ensure icon is up-to-date */ | 
					
						
							|  |  |  |         ui_icon_ensure_deferred(C, data->items.icons[a], data->preview); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         ui_searchbox_butrect(&rect, data, a); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         /* widget itself */ | 
					
						
							| 
									
										
										
										
											2020-03-24 11:34:18 +11:00
										 |  |  |         ui_draw_preview_item( | 
					
						
							|  |  |  |             &data->fstyle, &rect, data->items.names[a], data->items.icons[a], state); | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       /* indicate more */ | 
					
						
							|  |  |  |       if (data->items.more) { | 
					
						
							|  |  |  |         ui_searchbox_butrect(&rect, data, data->items.maxitem - 1); | 
					
						
							|  |  |  |         GPU_blend(true); | 
					
						
							|  |  |  |         UI_icon_draw(rect.xmax - 18, rect.ymin - 7, ICON_TRIA_DOWN); | 
					
						
							|  |  |  |         GPU_blend(false); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       if (data->items.offset) { | 
					
						
							|  |  |  |         ui_searchbox_butrect(&rect, data, 0); | 
					
						
							|  |  |  |         GPU_blend(true); | 
					
						
							|  |  |  |         UI_icon_draw(rect.xmin, rect.ymax - 9, ICON_TRIA_UP); | 
					
						
							|  |  |  |         GPU_blend(false); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else { | 
					
						
							| 
									
										
										
										
											2020-04-14 18:46:13 +10:00
										 |  |  |       const int search_sep_len = data->sep_string ? strlen(data->sep_string) : 0; | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |       /* draw items */ | 
					
						
							|  |  |  |       for (a = 0; a < data->items.totitem; a++) { | 
					
						
							| 
									
										
										
										
											2020-03-24 11:34:18 +11:00
										 |  |  |         const int state = ((a == data->active) ? UI_ACTIVE : 0) | data->items.states[a]; | 
					
						
							| 
									
										
										
										
											2020-04-14 18:46:13 +10:00
										 |  |  |         char *name = data->items.names[a]; | 
					
						
							|  |  |  |         int icon = data->items.icons[a]; | 
					
						
							|  |  |  |         char *name_sep_test = NULL; | 
					
						
							| 
									
										
										
										
											2020-03-24 11:34:18 +11:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |         ui_searchbox_butrect(&rect, data, a); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         /* widget itself */ | 
					
						
							| 
									
										
										
										
											2020-04-14 18:46:13 +10:00
										 |  |  |         if ((search_sep_len == 0) || | 
					
						
							|  |  |  |             !(name_sep_test = strstr(data->items.names[a], data->sep_string))) { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           /* Simple menu item. */ | 
					
						
							|  |  |  |           ui_draw_menu_item(&data->fstyle, &rect, name, icon, state, data->use_sep, NULL); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         else { | 
					
						
							|  |  |  |           /* Split menu item, faded text before the separator. */ | 
					
						
							|  |  |  |           char *name_sep = NULL; | 
					
						
							|  |  |  |           do { | 
					
						
							|  |  |  |             name_sep = name_sep_test; | 
					
						
							|  |  |  |             name_sep_test = strstr(name_sep + search_sep_len, data->sep_string); | 
					
						
							|  |  |  |           } while (name_sep_test != NULL); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           name_sep += search_sep_len; | 
					
						
							|  |  |  |           const char name_sep_prev = *name_sep; | 
					
						
							|  |  |  |           *name_sep = '\0'; | 
					
						
							|  |  |  |           int name_width = 0; | 
					
						
							|  |  |  |           ui_draw_menu_item( | 
					
						
							|  |  |  |               &data->fstyle, &rect, name, 0, state | UI_BUT_INACTIVE, false, &name_width); | 
					
						
							|  |  |  |           *name_sep = name_sep_prev; | 
					
						
							|  |  |  |           rect.xmin += name_width; | 
					
						
							|  |  |  |           rect.xmin += UI_UNIT_X / 4; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           if (icon == ICON_BLANK1) { | 
					
						
							|  |  |  |             icon = ICON_NONE; | 
					
						
							|  |  |  |             rect.xmin -= UI_DPI_ICON_SIZE / 4; | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           /* The previous menu item draws the active selection. */ | 
					
						
							|  |  |  |           ui_draw_menu_item( | 
					
						
							|  |  |  |               &data->fstyle, &rect, name_sep, icon, state & ~UI_ACTIVE, data->use_sep, NULL); | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |       } | 
					
						
							|  |  |  |       /* indicate more */ | 
					
						
							|  |  |  |       if (data->items.more) { | 
					
						
							|  |  |  |         ui_searchbox_butrect(&rect, data, data->items.maxitem - 1); | 
					
						
							|  |  |  |         GPU_blend(true); | 
					
						
							|  |  |  |         UI_icon_draw((BLI_rcti_size_x(&rect)) / 2, rect.ymin - 9, ICON_TRIA_DOWN); | 
					
						
							|  |  |  |         GPU_blend(false); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       if (data->items.offset) { | 
					
						
							|  |  |  |         ui_searchbox_butrect(&rect, data, 0); | 
					
						
							|  |  |  |         GPU_blend(true); | 
					
						
							|  |  |  |         UI_icon_draw((BLI_rcti_size_x(&rect)) / 2, rect.ymax - 7, ICON_TRIA_UP); | 
					
						
							|  |  |  |         GPU_blend(false); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2017-11-03 20:26:35 +11:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-06 16:56:42 +01:00
										 |  |  | static void ui_searchbox_region_free_cb(ARegion *region) | 
					
						
							| 
									
										
										
										
											2017-11-03 20:26:35 +11:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2020-03-06 16:56:42 +01:00
										 |  |  |   uiSearchboxData *data = region->regiondata; | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   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); | 
					
						
							| 
									
										
										
										
											2020-03-24 11:34:18 +11:00
										 |  |  |   MEM_freeN(data->items.states); | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |   MEM_freeN(data); | 
					
						
							| 
									
										
										
										
											2020-03-06 16:56:42 +01:00
										 |  |  |   region->regiondata = NULL; | 
					
						
							| 
									
										
										
										
											2017-11-03 20:26:35 +11:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ARegion *ui_searchbox_create_generic(bContext *C, ARegion *butregion, uiBut *but) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   wmWindow *win = CTX_wm_window(C); | 
					
						
							| 
									
										
										
										
											2020-03-15 17:32:25 +11:00
										 |  |  |   const uiStyle *style = UI_style_get(); | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   static ARegionType type; | 
					
						
							| 
									
										
										
										
											2020-03-06 16:56:42 +01:00
										 |  |  |   ARegion *region; | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   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 */ | 
					
						
							| 
									
										
										
										
											2020-03-06 16:56:42 +01:00
										 |  |  |   region = ui_region_temp_add(CTX_wm_screen(C)); | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |   memset(&type, 0, sizeof(ARegionType)); | 
					
						
							|  |  |  |   type.draw = ui_searchbox_region_draw_cb; | 
					
						
							|  |  |  |   type.free = ui_searchbox_region_free_cb; | 
					
						
							|  |  |  |   type.regionid = RGN_TYPE_TEMPORARY; | 
					
						
							| 
									
										
										
										
											2020-03-06 16:56:42 +01:00
										 |  |  |   region->type = &type; | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |   /* create searchbox data */ | 
					
						
							|  |  |  |   data = MEM_callocN(sizeof(uiSearchboxData), "uiSearchboxData"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /* set font, get bb */ | 
					
						
							|  |  |  |   data->fstyle = style->widget; /* copy struct */ | 
					
						
							|  |  |  |   ui_fontscale(&data->fstyle.points, aspect); | 
					
						
							|  |  |  |   UI_fontstyle_set(&data->fstyle); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-06 16:56:42 +01:00
										 |  |  |   region->regiondata = data; | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |   /* 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; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 08:44:38 +02:00
										 |  |  |   /* Only show key shortcuts when needed (checking RNA prop pointer is useless here, a lot of
 | 
					
						
							|  |  |  |    * buttons are about data without having that pointer defined, let's rather try with optype!). | 
					
						
							|  |  |  |    * One can also enforce that behavior by setting | 
					
						
							|  |  |  |    * UI_BUT_HAS_SHORTCUT drawflag of search button. */ | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   if (but->optype != NULL || (but->drawflag & UI_BUT_HAS_SHORTCUT) != 0) { | 
					
						
							|  |  |  |     data->use_sep = true; | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2020-05-07 23:16:05 +10:00
										 |  |  |   data->sep_string = but->search->sep_string; | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |   /* 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 */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-06 16:56:42 +01:00
										 |  |  |     region->winrct = butregion->winrct; | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     /* widget rect, in region coords */ | 
					
						
							|  |  |  |     data->bbox.xmin = margin; | 
					
						
							| 
									
										
										
										
											2020-03-06 16:56:42 +01:00
										 |  |  |     data->bbox.xmax = BLI_rcti_size_x(®ion->winrct) - margin; | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |     data->bbox.ymin = margin; | 
					
						
							| 
									
										
										
										
											2020-03-06 16:56:42 +01:00
										 |  |  |     data->bbox.ymax = BLI_rcti_size_y(®ion->winrct) - margin; | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     /* 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 */
 | 
					
						
							| 
									
										
										
										
											2019-05-01 11:09:22 +10:00
										 |  |  |     // wm_window_get_size(win, &winx, &winy);
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     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 */ | 
					
						
							| 
									
										
										
										
											2020-03-06 16:56:42 +01:00
										 |  |  |     region->winrct.xmin = rect_i.xmin - margin; | 
					
						
							|  |  |  |     region->winrct.xmax = rect_i.xmax + margin; | 
					
						
							|  |  |  |     region->winrct.ymin = rect_i.ymin - margin; | 
					
						
							|  |  |  |     region->winrct.ymax = rect_i.ymax; | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /* adds subwindow */ | 
					
						
							| 
									
										
										
										
											2020-03-06 16:56:42 +01:00
										 |  |  |   ED_region_floating_initialize(region); | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |   /* notify change and redraw */ | 
					
						
							| 
									
										
										
										
											2020-03-06 16:56:42 +01:00
										 |  |  |   ED_region_tag_redraw(region); | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |   /* 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"); | 
					
						
							| 
									
										
										
										
											2020-03-24 11:34:18 +11:00
										 |  |  |   data->items.states = MEM_callocN(data->items.maxitem * sizeof(int), "search flags"); | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   for (i = 0; i < data->items.maxitem; i++) { | 
					
						
							|  |  |  |     data->items.names[i] = MEM_callocN(but->hardmax + 1, "search pointers"); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-06 16:56:42 +01:00
										 |  |  |   return region; | 
					
						
							| 
									
										
										
										
											2017-11-03 20:26:35 +11:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /**
 | 
					
						
							|  |  |  |  * 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) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   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'); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2017-11-03 20:26:35 +11:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-06 16:56:42 +01:00
										 |  |  | static void ui_searchbox_region_draw_cb__operator(const bContext *UNUSED(C), ARegion *region) | 
					
						
							| 
									
										
										
										
											2017-11-03 20:26:35 +11:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2020-03-06 16:56:42 +01:00
										 |  |  |   uiSearchboxData *data = region->regiondata; | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |   /* pixel space */ | 
					
						
							| 
									
										
										
										
											2020-03-06 16:56:42 +01:00
										 |  |  |   wmOrtho2_region_pixelspace(region); | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |   if (data->noback == false) { | 
					
						
							|  |  |  |     ui_draw_widget_menu_back(&data->bbox, true); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /* 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. */ | 
					
						
							|  |  |  |       { | 
					
						
							| 
									
										
										
										
											2020-03-24 11:34:18 +11:00
										 |  |  |         const int state = ((a == data->active) ? UI_ACTIVE : 0) | data->items.states[a]; | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-24 11:34:18 +11:00
										 |  |  |         wmOperatorType *ot = data->items.pointers[a]; | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |         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, | 
					
						
							| 
									
										
										
										
											2020-04-14 18:46:13 +10:00
										 |  |  |                           false, | 
					
						
							|  |  |  |                           NULL); | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |         ui_draw_menu_item( | 
					
						
							| 
									
										
										
										
											2020-04-14 18:46:13 +10:00
										 |  |  |             &data->fstyle, &rect_post, data->items.names[a], 0, state, data->use_sep, NULL); | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     /* indicate more */ | 
					
						
							|  |  |  |     if (data->items.more) { | 
					
						
							|  |  |  |       ui_searchbox_butrect(&rect, data, data->items.maxitem - 1); | 
					
						
							|  |  |  |       GPU_blend(true); | 
					
						
							|  |  |  |       UI_icon_draw((BLI_rcti_size_x(&rect)) / 2, rect.ymin - 9, ICON_TRIA_DOWN); | 
					
						
							|  |  |  |       GPU_blend(false); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (data->items.offset) { | 
					
						
							|  |  |  |       ui_searchbox_butrect(&rect, data, 0); | 
					
						
							|  |  |  |       GPU_blend(true); | 
					
						
							|  |  |  |       UI_icon_draw((BLI_rcti_size_x(&rect)) / 2, rect.ymax - 7, ICON_TRIA_UP); | 
					
						
							|  |  |  |       GPU_blend(false); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2017-11-03 20:26:35 +11:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ARegion *ui_searchbox_create_operator(bContext *C, ARegion *butregion, uiBut *but) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2020-03-06 16:56:42 +01:00
										 |  |  |   ARegion *region; | 
					
						
							| 
									
										
										
										
											2017-11-03 20:26:35 +11:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   UI_but_drawflag_enable(but, UI_BUT_HAS_SHORTCUT); | 
					
						
							| 
									
										
										
										
											2020-03-06 16:56:42 +01:00
										 |  |  |   region = ui_searchbox_create_generic(C, butregion, but); | 
					
						
							| 
									
										
										
										
											2017-11-03 20:26:35 +11:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-06 16:56:42 +01:00
										 |  |  |   region->type->draw = ui_searchbox_region_draw_cb__operator; | 
					
						
							| 
									
										
										
										
											2017-11-03 20:26:35 +11:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-06 16:56:42 +01:00
										 |  |  |   return region; | 
					
						
							| 
									
										
										
										
											2017-11-03 20:26:35 +11:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-06 16:56:42 +01:00
										 |  |  | void ui_searchbox_free(bContext *C, ARegion *region) | 
					
						
							| 
									
										
										
										
											2017-11-03 20:26:35 +11:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2020-03-06 16:56:42 +01:00
										 |  |  |   ui_region_temp_remove(C, CTX_wm_screen(C), region); | 
					
						
							| 
									
										
										
										
											2017-11-03 20:26:35 +11:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-24 11:34:18 +11:00
										 |  |  | static void ui_searchbox_region_draw_cb__menu(const bContext *UNUSED(C), ARegion *UNUSED(region)) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   /* Currently unused. */ | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ARegion *ui_searchbox_create_menu(bContext *C, ARegion *butregion, uiBut *but) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   ARegion *region; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   UI_but_drawflag_enable(but, UI_BUT_HAS_SHORTCUT); | 
					
						
							|  |  |  |   region = ui_searchbox_create_generic(C, butregion, but); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (false) { | 
					
						
							|  |  |  |     region->type->draw = ui_searchbox_region_draw_cb__menu; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return region; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-11-03 20:26:35 +11:00
										 |  |  | /* 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) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  |   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"); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-07 23:16:05 +10:00
										 |  |  |   but->search->update_fn(but->block->evil_C, but->search->arg, but->drawstr, items); | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |   /* 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); | 
					
						
							| 
									
										
										
										
											2017-11-03 20:26:35 +11:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /** \} */ |