|
Blender
V2.59
|
00001 /* 00002 * ***** BEGIN GPL LICENSE BLOCK ***** 00003 * 00004 * This program is free software; you can redistribute it and/or 00005 * modify it under the terms of the GNU General Public License 00006 * as published by the Free Software Foundation; either version 2 00007 * of the License, or (at your option) any later version. 00008 * 00009 * This program is distributed in the hope that it will be useful, 00010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00012 * GNU General Public License for more details. 00013 * 00014 * You should have received a copy of the GNU General Public License 00015 * along with this program; if not, write to the Free Software Foundation, 00016 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 00017 * 00018 * The Original Code is Copyright (C) 2008 Blender Foundation. 00019 * All rights reserved. 00020 * 00021 * Contributor(s): Blender Foundation 00022 * 00023 * ***** END GPL LICENSE BLOCK ***** 00024 */ 00025 00032 #include <stdarg.h> 00033 #include <stdlib.h> 00034 #include <string.h> 00035 #include <assert.h> 00036 00037 #include "MEM_guardedalloc.h" 00038 00039 #include "DNA_userdef_types.h" 00040 00041 #include "BLI_math.h" 00042 #include "BLI_blenlib.h" 00043 #include "BLI_utildefines.h" 00044 #include "BLI_dynstr.h" 00045 #include "BLI_ghash.h" 00046 00047 #include "BKE_context.h" 00048 #include "BKE_screen.h" 00049 00050 #include "WM_api.h" 00051 #include "WM_types.h" 00052 #include "wm_draw.h" 00053 #include "wm_subwindow.h" 00054 #include "wm_window.h" 00055 00056 #include "RNA_access.h" 00057 00058 #include "BIF_gl.h" 00059 00060 #include "UI_interface.h" 00061 #include "UI_interface_icons.h" 00062 #include "UI_view2d.h" 00063 00064 #include "BLF_api.h" 00065 00066 #include "ED_screen.h" 00067 00068 #include "interface_intern.h" 00069 00070 #define MENU_SEPR_HEIGHT 6 00071 #define B_NOP -1 00072 #define MENU_SHADOW_SIDE 8 00073 #define MENU_SHADOW_BOTTOM 10 00074 #define MENU_TOP 8 00075 00076 /*********************** Menu Data Parsing ********************* */ 00077 00078 typedef struct MenuEntry { 00079 const char *str; 00080 int retval; 00081 int icon; 00082 int sepr; 00083 } MenuEntry; 00084 00085 typedef struct MenuData { 00086 char *instr; 00087 const char *title; 00088 int titleicon; 00089 00090 MenuEntry *items; 00091 int nitems, itemssize; 00092 } MenuData; 00093 00094 static MenuData *menudata_new(char *instr) 00095 { 00096 MenuData *md= MEM_mallocN(sizeof(*md), "MenuData"); 00097 00098 md->instr= instr; 00099 md->title= NULL; 00100 md->titleicon= 0; 00101 md->items= NULL; 00102 md->nitems= md->itemssize= 0; 00103 00104 return md; 00105 } 00106 00107 static void menudata_set_title(MenuData *md, const char *title, int titleicon) 00108 { 00109 if (!md->title) 00110 md->title= title; 00111 if (!md->titleicon) 00112 md->titleicon= titleicon; 00113 } 00114 00115 static void menudata_add_item(MenuData *md, const char *str, int retval, int icon, int sepr) 00116 { 00117 if (md->nitems==md->itemssize) { 00118 int nsize= md->itemssize?(md->itemssize<<1):1; 00119 MenuEntry *oitems= md->items; 00120 00121 md->items= MEM_mallocN(nsize*sizeof(*md->items), "md->items"); 00122 if (oitems) { 00123 memcpy(md->items, oitems, md->nitems*sizeof(*md->items)); 00124 MEM_freeN(oitems); 00125 } 00126 00127 md->itemssize= nsize; 00128 } 00129 00130 md->items[md->nitems].str= str; 00131 md->items[md->nitems].retval= retval; 00132 md->items[md->nitems].icon= icon; 00133 md->items[md->nitems].sepr= sepr; 00134 md->nitems++; 00135 } 00136 00137 static void menudata_free(MenuData *md) 00138 { 00139 MEM_freeN(md->instr); 00140 if (md->items) 00141 MEM_freeN(md->items); 00142 MEM_freeN(md); 00143 } 00144 00158 static MenuData *decompose_menu_string(char *str) 00159 { 00160 char *instr= BLI_strdup(str); 00161 MenuData *md= menudata_new(instr); 00162 const char *nitem= NULL; 00163 char *s= instr; 00164 int nicon=0, nretval= 1, nitem_is_title= 0, nitem_is_sepr= 0; 00165 00166 while (1) { 00167 char c= *s; 00168 00169 if (c=='%') { 00170 if (s[1]=='x') { 00171 nretval= atoi(s+2); 00172 00173 *s= '\0'; 00174 s++; 00175 } else if (s[1]=='t') { 00176 nitem_is_title= 1; 00177 00178 *s= '\0'; 00179 s++; 00180 } else if (s[1]=='l') { 00181 nitem_is_sepr= 1; 00182 if(!nitem) nitem= ""; 00183 00184 *s= '\0'; 00185 s++; 00186 } else if (s[1]=='i') { 00187 nicon= atoi(s+2); 00188 00189 *s= '\0'; 00190 s++; 00191 } 00192 } else if (c=='|' || c == '\n' || c=='\0') { 00193 if (nitem) { 00194 *s= '\0'; 00195 00196 if(nitem_is_title) { 00197 menudata_set_title(md, nitem, nicon); 00198 nitem_is_title= 0; 00199 } 00200 else if(nitem_is_sepr) { 00201 /* prevent separator to get a value */ 00202 menudata_add_item(md, nitem, -1, nicon, 1); 00203 nretval= md->nitems+1; 00204 nitem_is_sepr= 0; 00205 } 00206 else { 00207 menudata_add_item(md, nitem, nretval, nicon, 0); 00208 nretval= md->nitems+1; 00209 } 00210 00211 nitem= NULL; 00212 nicon= 0; 00213 } 00214 00215 if (c=='\0') 00216 break; 00217 } else if (!nitem) 00218 nitem= s; 00219 00220 s++; 00221 } 00222 00223 return md; 00224 } 00225 00226 void ui_set_name_menu(uiBut *but, int value) 00227 { 00228 MenuData *md; 00229 int i; 00230 00231 md= decompose_menu_string(but->str); 00232 for (i=0; i<md->nitems; i++) 00233 if (md->items[i].retval==value) 00234 strcpy(but->drawstr, md->items[i].str); 00235 00236 menudata_free(md); 00237 } 00238 00239 int ui_step_name_menu(uiBut *but, int step) 00240 { 00241 MenuData *md; 00242 int value= ui_get_but_val(but); 00243 int i; 00244 00245 md= decompose_menu_string(but->str); 00246 for (i=0; i<md->nitems; i++) 00247 if (md->items[i].retval==value) 00248 break; 00249 00250 if(step==1) { 00251 /* skip separators */ 00252 for(; i<md->nitems-1; i++) { 00253 if(md->items[i+1].retval != -1) { 00254 value= md->items[i+1].retval; 00255 break; 00256 } 00257 } 00258 } 00259 else { 00260 if(i>0) { 00261 /* skip separators */ 00262 for(; i>0; i--) { 00263 if(md->items[i-1].retval != -1) { 00264 value= md->items[i-1].retval; 00265 break; 00266 } 00267 } 00268 } 00269 } 00270 00271 menudata_free(md); 00272 00273 return value; 00274 } 00275 00276 00277 /******************** Creating Temporary regions ******************/ 00278 00279 static ARegion *ui_add_temporary_region(bScreen *sc) 00280 { 00281 ARegion *ar; 00282 00283 ar= MEM_callocN(sizeof(ARegion), "area region"); 00284 BLI_addtail(&sc->regionbase, ar); 00285 00286 ar->regiontype= RGN_TYPE_TEMPORARY; 00287 ar->alignment= RGN_ALIGN_FLOAT; 00288 00289 return ar; 00290 } 00291 00292 static void ui_remove_temporary_region(bContext *C, bScreen *sc, ARegion *ar) 00293 { 00294 if(CTX_wm_window(C)) 00295 wm_draw_region_clear(CTX_wm_window(C), ar); 00296 00297 ED_region_exit(C, ar); 00298 BKE_area_region_free(NULL, ar); /* NULL: no spacetype */ 00299 BLI_freelinkN(&sc->regionbase, ar); 00300 } 00301 00302 /************************* Creating Tooltips **********************/ 00303 00304 #define MAX_TOOLTIP_LINES 8 00305 00306 typedef struct uiTooltipData { 00307 rcti bbox; 00308 uiFontStyle fstyle; 00309 char lines[MAX_TOOLTIP_LINES][512]; 00310 unsigned int color[MAX_TOOLTIP_LINES]; 00311 int totline; 00312 int toth, spaceh, lineh; 00313 } uiTooltipData; 00314 00315 static void ui_tooltip_region_draw_cb(const bContext *UNUSED(C), ARegion *ar) 00316 { 00317 uiTooltipData *data= ar->regiondata; 00318 rcti bbox= data->bbox; 00319 int a; 00320 00321 ui_draw_menu_back(U.uistyles.first, NULL, &data->bbox); 00322 00323 /* draw text */ 00324 uiStyleFontSet(&data->fstyle); 00325 00326 bbox.ymax= bbox.ymax - 0.5f*((bbox.ymax - bbox.ymin) - data->toth); 00327 bbox.ymin= bbox.ymax - data->lineh; 00328 00329 for(a=0; a<data->totline; a++) { 00330 cpack(data->color[a]); 00331 uiStyleFontDraw(&data->fstyle, &bbox, data->lines[a]); 00332 bbox.ymin -= data->lineh + data->spaceh; 00333 bbox.ymax -= data->lineh + data->spaceh; 00334 } 00335 } 00336 00337 static void ui_tooltip_region_free_cb(ARegion *ar) 00338 { 00339 uiTooltipData *data; 00340 00341 data= ar->regiondata; 00342 MEM_freeN(data); 00343 ar->regiondata= NULL; 00344 } 00345 00346 ARegion *ui_tooltip_create(bContext *C, ARegion *butregion, uiBut *but) 00347 { 00348 uiStyle *style= U.uistyles.first; // XXX pass on as arg 00349 static ARegionType type; 00350 ARegion *ar; 00351 uiTooltipData *data; 00352 IDProperty *prop; 00353 char buf[512]; 00354 float fonth, fontw, aspect= but->block->aspect; 00355 float x1f, x2f, y1f, y2f; 00356 int x1, x2, y1, y2, winx, winy, ofsx, ofsy, w, h, a; 00357 00358 if(but->flag & UI_BUT_NO_TOOLTIP) 00359 return NULL; 00360 00361 /* create tooltip data */ 00362 data= MEM_callocN(sizeof(uiTooltipData), "uiTooltipData"); 00363 00364 /* special case, enum rna buttons only have enum item description, use general enum description too before the spesific one */ 00365 if(but->rnaprop && RNA_property_type(but->rnaprop) == PROP_ENUM) { 00366 const char *descr= RNA_property_description(but->rnaprop); 00367 if(descr && descr[0]) { 00368 BLI_strncpy(data->lines[data->totline], descr, sizeof(data->lines[0])); 00369 data->color[data->totline]= 0xFFFFFF; 00370 data->totline++; 00371 } 00372 00373 if(but->type == ROW) { 00374 EnumPropertyItem *item; 00375 int i, totitem, free; 00376 00377 RNA_property_enum_items(C, &but->rnapoin, but->rnaprop, &item, &totitem, &free); 00378 00379 for(i=0; i<totitem; i++) { 00380 if(item[i].identifier[0] && item[i].value == (int)but->hardmax) { 00381 if(item[i].description[0]) { 00382 BLI_snprintf(data->lines[data->totline], sizeof(data->lines[0]), "%s: %s", item[i].name, item[i].description); 00383 data->color[data->totline]= 0xFFFFFF; 00384 data->totline++; 00385 } 00386 break; 00387 } 00388 } 00389 00390 if(free) 00391 MEM_freeN(item); 00392 } 00393 } 00394 00395 if(but->tip && strlen(but->tip)) { 00396 BLI_strncpy(data->lines[data->totline], but->tip, sizeof(data->lines[0])); 00397 data->color[data->totline]= 0xFFFFFF; 00398 data->totline++; 00399 } 00400 00401 if(but->optype && !(but->block->flag & UI_BLOCK_LOOP)) { 00402 /* operator keymap (not menus, they already have it) */ 00403 prop= (but->opptr)? but->opptr->data: NULL; 00404 00405 if(WM_key_event_operator_string(C, but->optype->idname, but->opcontext, prop, buf, sizeof(buf))) { 00406 BLI_snprintf(data->lines[data->totline], sizeof(data->lines[0]), "Shortcut: %s", buf); 00407 data->color[data->totline]= 0x888888; 00408 data->totline++; 00409 } 00410 } 00411 00412 if(ELEM3(but->type, TEX, IDPOIN, SEARCH_MENU)) { 00413 /* full string */ 00414 ui_get_but_string(but, buf, sizeof(buf)); 00415 if(buf[0]) { 00416 BLI_snprintf(data->lines[data->totline], sizeof(data->lines[0]), "Value: %s", buf); 00417 data->color[data->totline]= 0x888888; 00418 data->totline++; 00419 } 00420 } 00421 00422 if(but->rnaprop) { 00423 int unit_type= uiButGetUnitType(but); 00424 00425 if (unit_type == PROP_UNIT_ROTATION) { 00426 if (RNA_property_type(but->rnaprop) == PROP_FLOAT) { 00427 BLI_snprintf(data->lines[data->totline], sizeof(data->lines[0]), "Radians: %f", RNA_property_float_get_index(&but->rnapoin, but->rnaprop, but->rnaindex)); 00428 data->color[data->totline]= 0x888888; 00429 data->totline++; 00430 } 00431 } 00432 00433 if(but->flag & UI_BUT_DRIVEN) { 00434 if(ui_but_anim_expression_get(but, buf, sizeof(buf))) { 00435 /* expression */ 00436 BLI_snprintf(data->lines[data->totline], sizeof(data->lines[0]), "Expression: %s", buf); 00437 data->color[data->totline]= 0x888888; 00438 data->totline++; 00439 } 00440 } 00441 00442 /* rna info */ 00443 if ((U.flag & USER_TOOLTIPS_PYTHON) == 0) { 00444 BLI_snprintf(data->lines[data->totline], sizeof(data->lines[0]), "Python: %s.%s", RNA_struct_identifier(but->rnapoin.type), RNA_property_identifier(but->rnaprop)); 00445 data->color[data->totline]= 0x888888; 00446 data->totline++; 00447 } 00448 00449 if(but->rnapoin.id.data) { 00450 ID *id= but->rnapoin.id.data; 00451 if(id->lib && id->lib->name) { 00452 BLI_snprintf(data->lines[data->totline], sizeof(data->lines[0]), "Library: %s", id->lib->name); 00453 data->color[data->totline]= 0x888888; 00454 data->totline++; 00455 } 00456 } 00457 } 00458 else if (but->optype) { 00459 PointerRNA *opptr; 00460 char *str; 00461 opptr= uiButGetOperatorPtrRNA(but); /* allocated when needed, the button owns it */ 00462 00463 str= WM_operator_pystring(C, but->optype, opptr, 0); 00464 00465 /* operator info */ 00466 if ((U.flag & USER_TOOLTIPS_PYTHON) == 0) { 00467 BLI_snprintf(data->lines[data->totline], sizeof(data->lines[0]), "Python: %s", str); 00468 data->color[data->totline]= 0x888888; 00469 data->totline++; 00470 } 00471 00472 MEM_freeN(str); 00473 00474 /* second check if we are disabled - why */ 00475 if(but->flag & UI_BUT_DISABLED) { 00476 const char *poll_msg; 00477 CTX_wm_operator_poll_msg_set(C, NULL); 00478 WM_operator_poll_context(C, but->optype, but->opcontext); 00479 poll_msg= CTX_wm_operator_poll_msg_get(C); 00480 if(poll_msg) { 00481 BLI_snprintf(data->lines[data->totline], sizeof(data->lines[0]), "Disabled: %s", poll_msg); 00482 data->color[data->totline]= 0x6666ff; /* alert */ 00483 data->totline++; 00484 } 00485 } 00486 } 00487 else if (ELEM(but->type, MENU, PULLDOWN)) { 00488 if ((U.flag & USER_TOOLTIPS_PYTHON) == 0) { 00489 if(but->menu_create_func && WM_menutype_contains((MenuType *)but->poin)) { 00490 MenuType *mt= (MenuType *)but->poin; 00491 BLI_snprintf(data->lines[data->totline], sizeof(data->lines[0]), "Python: %s", mt->idname); 00492 data->color[data->totline]= 0x888888; 00493 data->totline++; 00494 } 00495 } 00496 00497 } 00498 00499 assert(data->totline < MAX_TOOLTIP_LINES); 00500 00501 if(data->totline == 0) { 00502 MEM_freeN(data); 00503 return NULL; 00504 } 00505 00506 /* create area region */ 00507 ar= ui_add_temporary_region(CTX_wm_screen(C)); 00508 00509 memset(&type, 0, sizeof(ARegionType)); 00510 type.draw= ui_tooltip_region_draw_cb; 00511 type.free= ui_tooltip_region_free_cb; 00512 ar->type= &type; 00513 00514 /* set font, get bb */ 00515 data->fstyle= style->widget; /* copy struct */ 00516 data->fstyle.align= UI_STYLE_TEXT_CENTER; 00517 uiStyleFontSet(&data->fstyle); 00518 00519 /* these defines may need to be tweaked depending on font */ 00520 #define TIP_MARGIN_Y 2 00521 #define TIP_BORDER_X 16.0f 00522 #define TIP_BORDER_Y 6.0f 00523 00524 h= BLF_height_max(data->fstyle.uifont_id); 00525 00526 for(a=0, fontw=0, fonth=0; a<data->totline; a++) { 00527 w= BLF_width(data->fstyle.uifont_id, data->lines[a]); 00528 fontw= MAX2(fontw, w); 00529 fonth += (a == 0)? h: h+TIP_MARGIN_Y; 00530 } 00531 00532 fontw *= aspect; 00533 00534 ar->regiondata= data; 00535 00536 data->toth= fonth; 00537 data->lineh= h; 00538 data->spaceh= TIP_MARGIN_Y; 00539 00540 00541 /* compute position */ 00542 ofsx= (but->block->panel)? but->block->panel->ofsx: 0; 00543 ofsy= (but->block->panel)? but->block->panel->ofsy: 0; 00544 00545 x1f= (but->x1 + but->x2) * 0.5f + ofsx - (TIP_BORDER_X * aspect); 00546 x2f= x1f + fontw + (TIP_BORDER_X * aspect); 00547 y2f= but->y1 + ofsy - (TIP_BORDER_Y * aspect); 00548 y1f= y2f - fonth*aspect - (TIP_BORDER_Y * aspect); 00549 00550 #undef TIP_MARGIN_Y 00551 #undef TIP_BORDER_X 00552 #undef TIP_BORDER_Y 00553 00554 /* copy to int, gets projected if possible too */ 00555 x1= x1f; y1= y1f; x2= x2f; y2= y2f; 00556 00557 if(butregion) { 00558 /* XXX temp, region v2ds can be empty still */ 00559 if(butregion->v2d.cur.xmin != butregion->v2d.cur.xmax) { 00560 UI_view2d_to_region_no_clip(&butregion->v2d, x1f, y1f, &x1, &y1); 00561 UI_view2d_to_region_no_clip(&butregion->v2d, x2f, y2f, &x2, &y2); 00562 } 00563 00564 x1 += butregion->winrct.xmin; 00565 x2 += butregion->winrct.xmin; 00566 y1 += butregion->winrct.ymin; 00567 y2 += butregion->winrct.ymin; 00568 } 00569 00570 wm_window_get_size(CTX_wm_window(C), &winx, &winy); 00571 00572 if(x2 > winx) { 00573 /* super size */ 00574 if(x2 > winx + x1) { 00575 x2= winx; 00576 x1= 0; 00577 } 00578 else { 00579 x1 -= x2-winx; 00580 x2= winx; 00581 } 00582 } 00583 /* ensure at least 5 px above screen bounds 00584 * 25 is just a guess to be above the menu item */ 00585 if(y1 < 5) { 00586 y2 += (-y1) + 30; 00587 y1 = 30; 00588 } 00589 00590 /* widget rect, in region coords */ 00591 data->bbox.xmin= MENU_SHADOW_SIDE; 00592 data->bbox.xmax= x2-x1 + MENU_SHADOW_SIDE; 00593 data->bbox.ymin= MENU_SHADOW_BOTTOM; 00594 data->bbox.ymax= y2-y1 + MENU_SHADOW_BOTTOM; 00595 00596 /* region bigger for shadow */ 00597 ar->winrct.xmin= x1 - MENU_SHADOW_SIDE; 00598 ar->winrct.xmax= x2 + MENU_SHADOW_SIDE; 00599 ar->winrct.ymin= y1 - MENU_SHADOW_BOTTOM; 00600 ar->winrct.ymax= y2 + MENU_TOP; 00601 00602 /* adds subwindow */ 00603 ED_region_init(C, ar); 00604 00605 /* notify change and redraw */ 00606 ED_region_tag_redraw(ar); 00607 00608 return ar; 00609 } 00610 00611 void ui_tooltip_free(bContext *C, ARegion *ar) 00612 { 00613 ui_remove_temporary_region(C, CTX_wm_screen(C), ar); 00614 } 00615 00616 00617 /************************* Creating Search Box **********************/ 00618 00619 struct uiSearchItems { 00620 int maxitem, totitem, maxstrlen; 00621 00622 int offset, offset_i; /* offset for inserting in array */ 00623 int more; /* flag indicating there are more items */ 00624 00625 char **names; 00626 void **pointers; 00627 int *icons; 00628 00629 AutoComplete *autocpl; 00630 void *active; 00631 }; 00632 00633 typedef struct uiSearchboxData { 00634 rcti bbox; 00635 uiFontStyle fstyle; 00636 uiSearchItems items; 00637 int active; /* index in items array */ 00638 int noback; /* when menu opened with enough space for this */ 00639 int preview; /* draw thumbnail previews, rather than list */ 00640 int prv_rows, prv_cols; 00641 } uiSearchboxData; 00642 00643 #define SEARCH_ITEMS 10 00644 00645 /* exported for use by search callbacks */ 00646 /* returns zero if nothing to add */ 00647 int uiSearchItemAdd(uiSearchItems *items, const char *name, void *poin, int iconid) 00648 { 00649 /* hijack for autocomplete */ 00650 if(items->autocpl) { 00651 autocomplete_do_name(items->autocpl, name); 00652 return 1; 00653 } 00654 00655 /* hijack for finding active item */ 00656 if(items->active) { 00657 if(poin==items->active) 00658 items->offset_i= items->totitem; 00659 items->totitem++; 00660 return 1; 00661 } 00662 00663 if(items->totitem>=items->maxitem) { 00664 items->more= 1; 00665 return 0; 00666 } 00667 00668 /* skip first items in list */ 00669 if(items->offset_i > 0) { 00670 items->offset_i--; 00671 return 1; 00672 } 00673 00674 if(items->names) 00675 BLI_strncpy(items->names[items->totitem], name, items->maxstrlen); 00676 if(items->pointers) 00677 items->pointers[items->totitem]= poin; 00678 if(items->icons) 00679 items->icons[items->totitem]= iconid; 00680 00681 items->totitem++; 00682 00683 return 1; 00684 } 00685 00686 int uiSearchBoxhHeight(void) 00687 { 00688 return SEARCH_ITEMS*UI_UNIT_Y + 2*MENU_TOP; 00689 } 00690 00691 /* ar is the search box itself */ 00692 static void ui_searchbox_select(bContext *C, ARegion *ar, uiBut *but, int step) 00693 { 00694 uiSearchboxData *data= ar->regiondata; 00695 00696 /* apply step */ 00697 data->active+= step; 00698 00699 if(data->items.totitem==0) 00700 data->active= 0; 00701 else if(data->active > data->items.totitem) { 00702 if(data->items.more) { 00703 data->items.offset++; 00704 data->active= data->items.totitem; 00705 ui_searchbox_update(C, ar, but, 0); 00706 } 00707 else 00708 data->active= data->items.totitem; 00709 } 00710 else if(data->active < 1) { 00711 if(data->items.offset) { 00712 data->items.offset--; 00713 data->active= 1; 00714 ui_searchbox_update(C, ar, but, 0); 00715 } 00716 else if(data->active < 0) 00717 data->active= 0; 00718 } 00719 00720 ED_region_tag_redraw(ar); 00721 } 00722 00723 static void ui_searchbox_butrect(rcti *rect, uiSearchboxData *data, int itemnr) 00724 { 00725 /* thumbnail preview */ 00726 if (data->preview) { 00727 int buth = (data->bbox.ymax - data->bbox.ymin - 2*MENU_TOP) / data->prv_rows; 00728 int butw = (data->bbox.xmax - data->bbox.xmin) / data->prv_cols; 00729 int row, col; 00730 00731 *rect= data->bbox; 00732 00733 col = itemnr % data->prv_cols; 00734 row = itemnr / data->prv_cols; 00735 00736 rect->xmin += col * butw; 00737 rect->xmax = rect->xmin + butw; 00738 00739 rect->ymax = data->bbox.ymax - MENU_TOP - (row * buth); 00740 rect->ymin = rect->ymax - buth; 00741 } 00742 /* list view */ 00743 else { 00744 int buth= (data->bbox.ymax-data->bbox.ymin - 2*MENU_TOP)/SEARCH_ITEMS; 00745 00746 *rect= data->bbox; 00747 rect->xmin= data->bbox.xmin + 3.0f; 00748 rect->xmax= data->bbox.xmax - 3.0f; 00749 00750 rect->ymax= data->bbox.ymax - MENU_TOP - itemnr*buth; 00751 rect->ymin= rect->ymax - buth; 00752 } 00753 00754 } 00755 00756 /* x and y in screencoords */ 00757 int ui_searchbox_inside(ARegion *ar, int x, int y) 00758 { 00759 uiSearchboxData *data= ar->regiondata; 00760 00761 return(BLI_in_rcti(&data->bbox, x-ar->winrct.xmin, y-ar->winrct.ymin)); 00762 } 00763 00764 /* string validated to be of correct length (but->hardmax) */ 00765 void ui_searchbox_apply(uiBut *but, ARegion *ar) 00766 { 00767 uiSearchboxData *data= ar->regiondata; 00768 00769 but->func_arg2= NULL; 00770 00771 if(data->active) { 00772 char *name= data->items.names[data->active-1]; 00773 char *cpoin= strchr(name, '|'); 00774 00775 if(cpoin) cpoin[0]= 0; 00776 BLI_strncpy(but->editstr, name, data->items.maxstrlen); 00777 if(cpoin) cpoin[0]= '|'; 00778 00779 but->func_arg2= data->items.pointers[data->active-1]; 00780 } 00781 } 00782 00783 void ui_searchbox_event(bContext *C, ARegion *ar, uiBut *but, wmEvent *event) 00784 { 00785 uiSearchboxData *data= ar->regiondata; 00786 00787 switch(event->type) { 00788 case WHEELUPMOUSE: 00789 case UPARROWKEY: 00790 ui_searchbox_select(C, ar, but, -1); 00791 break; 00792 case WHEELDOWNMOUSE: 00793 case DOWNARROWKEY: 00794 ui_searchbox_select(C, ar, but, 1); 00795 break; 00796 case MOUSEMOVE: 00797 if(BLI_in_rcti(&ar->winrct, event->x, event->y)) { 00798 rcti rect; 00799 int a; 00800 00801 for(a=0; a<data->items.totitem; a++) { 00802 ui_searchbox_butrect(&rect, data, a); 00803 if(BLI_in_rcti(&rect, event->x - ar->winrct.xmin, event->y - ar->winrct.ymin)) { 00804 if( data->active!= a+1) { 00805 data->active= a+1; 00806 ui_searchbox_select(C, ar, but, 0); 00807 break; 00808 } 00809 } 00810 } 00811 } 00812 break; 00813 } 00814 } 00815 00816 /* ar is the search box itself */ 00817 void ui_searchbox_update(bContext *C, ARegion *ar, uiBut *but, int reset) 00818 { 00819 uiSearchboxData *data= ar->regiondata; 00820 00821 /* reset vars */ 00822 data->items.totitem= 0; 00823 data->items.more= 0; 00824 if(reset==0) { 00825 data->items.offset_i= data->items.offset; 00826 } 00827 else { 00828 data->items.offset_i= data->items.offset= 0; 00829 data->active= 0; 00830 00831 /* handle active */ 00832 if(but->search_func && but->func_arg2) { 00833 data->items.active= but->func_arg2; 00834 but->search_func(C, but->search_arg, but->editstr, &data->items); 00835 data->items.active= NULL; 00836 00837 /* found active item, calculate real offset by centering it */ 00838 if(data->items.totitem) { 00839 /* first case, begin of list */ 00840 if(data->items.offset_i < data->items.maxitem) { 00841 data->active= data->items.offset_i+1; 00842 data->items.offset_i= 0; 00843 } 00844 else { 00845 /* second case, end of list */ 00846 if(data->items.totitem - data->items.offset_i <= data->items.maxitem) { 00847 data->active= 1 + data->items.offset_i - data->items.totitem + data->items.maxitem; 00848 data->items.offset_i= data->items.totitem - data->items.maxitem; 00849 } 00850 else { 00851 /* center active item */ 00852 data->items.offset_i -= data->items.maxitem/2; 00853 data->active= 1 + data->items.maxitem/2; 00854 } 00855 } 00856 } 00857 data->items.offset= data->items.offset_i; 00858 data->items.totitem= 0; 00859 } 00860 } 00861 00862 /* callback */ 00863 if(but->search_func) 00864 but->search_func(C, but->search_arg, but->editstr, &data->items); 00865 00866 /* handle case where editstr is equal to one of items */ 00867 if(reset && data->active==0) { 00868 int a; 00869 00870 for(a=0; a<data->items.totitem; a++) { 00871 char *cpoin= strchr(data->items.names[a], '|'); 00872 00873 if(cpoin) cpoin[0]= 0; 00874 if(0==strcmp(but->editstr, data->items.names[a])) 00875 data->active= a+1; 00876 if(cpoin) cpoin[0]= '|'; 00877 } 00878 if(data->items.totitem==1 && but->editstr[0]) 00879 data->active= 1; 00880 } 00881 00882 /* validate selected item */ 00883 ui_searchbox_select(C, ar, but, 0); 00884 00885 ED_region_tag_redraw(ar); 00886 } 00887 00888 void ui_searchbox_autocomplete(bContext *C, ARegion *ar, uiBut *but, char *str) 00889 { 00890 uiSearchboxData *data= ar->regiondata; 00891 00892 if(str[0]) { 00893 data->items.autocpl= autocomplete_begin(str, ui_get_but_string_max_length(but)); 00894 00895 but->search_func(C, but->search_arg, but->editstr, &data->items); 00896 00897 autocomplete_end(data->items.autocpl, str); 00898 data->items.autocpl= NULL; 00899 } 00900 } 00901 00902 static void ui_searchbox_region_draw_cb(const bContext *UNUSED(C), ARegion *ar) 00903 { 00904 uiSearchboxData *data= ar->regiondata; 00905 00906 /* pixel space */ 00907 wmOrtho2(-0.01f, ar->winx-0.01f, -0.01f, ar->winy-0.01f); 00908 00909 if(!data->noback) 00910 ui_draw_search_back(NULL, NULL, &data->bbox); /* style not used yet */ 00911 00912 /* draw text */ 00913 if(data->items.totitem) { 00914 rcti rect; 00915 int a; 00916 00917 if (data->preview) { 00918 /* draw items */ 00919 for(a=0; a<data->items.totitem; a++) { 00920 ui_searchbox_butrect(&rect, data, a); 00921 00922 /* widget itself */ 00923 if (data->preview) 00924 ui_draw_preview_item(&data->fstyle, &rect, data->items.names[a], data->items.icons[a], (a+1)==data->active?UI_ACTIVE:0); 00925 else 00926 ui_draw_menu_item(&data->fstyle, &rect, data->items.names[a], data->items.icons[a], (a+1)==data->active?UI_ACTIVE:0); 00927 } 00928 00929 /* indicate more */ 00930 if(data->items.more) { 00931 ui_searchbox_butrect(&rect, data, data->items.maxitem-1); 00932 glEnable(GL_BLEND); 00933 UI_icon_draw(rect.xmax-18, rect.ymin-7, ICON_TRIA_DOWN); 00934 glDisable(GL_BLEND); 00935 } 00936 if(data->items.offset) { 00937 ui_searchbox_butrect(&rect, data, 0); 00938 glEnable(GL_BLEND); 00939 UI_icon_draw(rect.xmin, rect.ymax-9, ICON_TRIA_UP); 00940 glDisable(GL_BLEND); 00941 } 00942 00943 } else { 00944 /* draw items */ 00945 for(a=0; a<data->items.totitem; a++) { 00946 ui_searchbox_butrect(&rect, data, a); 00947 00948 /* widget itself */ 00949 ui_draw_menu_item(&data->fstyle, &rect, data->items.names[a], data->items.icons[a], (a+1)==data->active?UI_ACTIVE:0); 00950 00951 } 00952 /* indicate more */ 00953 if(data->items.more) { 00954 ui_searchbox_butrect(&rect, data, data->items.maxitem-1); 00955 glEnable(GL_BLEND); 00956 UI_icon_draw((rect.xmax-rect.xmin)/2, rect.ymin-9, ICON_TRIA_DOWN); 00957 glDisable(GL_BLEND); 00958 } 00959 if(data->items.offset) { 00960 ui_searchbox_butrect(&rect, data, 0); 00961 glEnable(GL_BLEND); 00962 UI_icon_draw((rect.xmax-rect.xmin)/2, rect.ymax-7, ICON_TRIA_UP); 00963 glDisable(GL_BLEND); 00964 } 00965 } 00966 } 00967 } 00968 00969 static void ui_searchbox_region_free_cb(ARegion *ar) 00970 { 00971 uiSearchboxData *data= ar->regiondata; 00972 int a; 00973 00974 /* free search data */ 00975 for(a=0; a<data->items.maxitem; a++) 00976 MEM_freeN(data->items.names[a]); 00977 MEM_freeN(data->items.names); 00978 MEM_freeN(data->items.pointers); 00979 MEM_freeN(data->items.icons); 00980 00981 MEM_freeN(data); 00982 ar->regiondata= NULL; 00983 } 00984 00985 ARegion *ui_searchbox_create(bContext *C, ARegion *butregion, uiBut *but) 00986 { 00987 uiStyle *style= U.uistyles.first; // XXX pass on as arg 00988 static ARegionType type; 00989 ARegion *ar; 00990 uiSearchboxData *data; 00991 float aspect= but->block->aspect; 00992 float x1f, x2f, y1f, y2f; 00993 int x1, x2, y1, y2, winx, winy, ofsx, ofsy; 00994 00995 /* create area region */ 00996 ar= ui_add_temporary_region(CTX_wm_screen(C)); 00997 00998 memset(&type, 0, sizeof(ARegionType)); 00999 type.draw= ui_searchbox_region_draw_cb; 01000 type.free= ui_searchbox_region_free_cb; 01001 ar->type= &type; 01002 01003 /* create searchbox data */ 01004 data= MEM_callocN(sizeof(uiSearchboxData), "uiSearchboxData"); 01005 01006 /* set font, get bb */ 01007 data->fstyle= style->widget; /* copy struct */ 01008 data->fstyle.align= UI_STYLE_TEXT_CENTER; 01009 ui_fontscale(&data->fstyle.points, aspect); 01010 uiStyleFontSet(&data->fstyle); 01011 01012 ar->regiondata= data; 01013 01014 /* special case, hardcoded feature, not draw backdrop when called from menus, 01015 assume for design that popup already added it */ 01016 if(but->block->flag & UI_BLOCK_LOOP) 01017 data->noback= 1; 01018 01019 if (but->a1 > 0 && but->a2 > 0) { 01020 data->preview = 1; 01021 data->prv_rows = but->a1; 01022 data->prv_cols = but->a2; 01023 } 01024 01025 /* compute position */ 01026 if(but->block->flag & UI_BLOCK_LOOP) { 01027 /* this case is search menu inside other menu */ 01028 /* we copy region size */ 01029 01030 ar->winrct= butregion->winrct; 01031 01032 /* widget rect, in region coords */ 01033 data->bbox.xmin= MENU_SHADOW_SIDE; 01034 data->bbox.xmax= (ar->winrct.xmax-ar->winrct.xmin) - MENU_SHADOW_SIDE; 01035 data->bbox.ymin= MENU_SHADOW_BOTTOM; 01036 data->bbox.ymax= (ar->winrct.ymax-ar->winrct.ymin) - MENU_SHADOW_BOTTOM; 01037 01038 /* check if button is lower half */ 01039 if( but->y2 < (but->block->miny+but->block->maxy)/2 ) { 01040 data->bbox.ymin += (but->y2-but->y1); 01041 } 01042 else { 01043 data->bbox.ymax -= (but->y2-but->y1); 01044 } 01045 } 01046 else { 01047 x1f= but->x1 - 5; /* align text with button */ 01048 x2f= but->x2 + 5; /* symmetrical */ 01049 y2f= but->y1; 01050 y1f= y2f - uiSearchBoxhHeight(); 01051 01052 ofsx= (but->block->panel)? but->block->panel->ofsx: 0; 01053 ofsy= (but->block->panel)? but->block->panel->ofsy: 0; 01054 01055 x1f += ofsx; 01056 x2f += ofsx; 01057 y1f += ofsy; 01058 y2f += ofsy; 01059 01060 /* minimal width */ 01061 if(x2f - x1f < 150) x2f= x1f+150; // XXX arbitrary 01062 01063 /* copy to int, gets projected if possible too */ 01064 x1= x1f; y1= y1f; x2= x2f; y2= y2f; 01065 01066 if(butregion) { 01067 if(butregion->v2d.cur.xmin != butregion->v2d.cur.xmax) { 01068 UI_view2d_to_region_no_clip(&butregion->v2d, x1f, y1f, &x1, &y1); 01069 UI_view2d_to_region_no_clip(&butregion->v2d, x2f, y2f, &x2, &y2); 01070 } 01071 01072 x1 += butregion->winrct.xmin; 01073 x2 += butregion->winrct.xmin; 01074 y1 += butregion->winrct.ymin; 01075 y2 += butregion->winrct.ymin; 01076 } 01077 01078 wm_window_get_size(CTX_wm_window(C), &winx, &winy); 01079 01080 if(x2 > winx) { 01081 /* super size */ 01082 if(x2 > winx + x1) { 01083 x2= winx; 01084 x1= 0; 01085 } 01086 else { 01087 x1 -= x2-winx; 01088 x2= winx; 01089 } 01090 } 01091 if(y1 < 0) { /* XXX butregion NULL check?, there is one above */ 01092 int newy1; 01093 UI_view2d_to_region_no_clip(&butregion->v2d, 0, but->y2 + ofsy, NULL, &newy1); 01094 newy1 += butregion->winrct.ymin; 01095 01096 y2= y2-y1 + newy1; 01097 y1= newy1; 01098 } 01099 01100 /* widget rect, in region coords */ 01101 data->bbox.xmin= MENU_SHADOW_SIDE; 01102 data->bbox.xmax= x2-x1 + MENU_SHADOW_SIDE; 01103 data->bbox.ymin= MENU_SHADOW_BOTTOM; 01104 data->bbox.ymax= y2-y1 + MENU_SHADOW_BOTTOM; 01105 01106 /* region bigger for shadow */ 01107 ar->winrct.xmin= x1 - MENU_SHADOW_SIDE; 01108 ar->winrct.xmax= x2 + MENU_SHADOW_SIDE; 01109 ar->winrct.ymin= y1 - MENU_SHADOW_BOTTOM; 01110 ar->winrct.ymax= y2; 01111 } 01112 01113 /* adds subwindow */ 01114 ED_region_init(C, ar); 01115 01116 /* notify change and redraw */ 01117 ED_region_tag_redraw(ar); 01118 01119 /* prepare search data */ 01120 if (data->preview) { 01121 data->items.maxitem= data->prv_rows * data->prv_cols; 01122 } else { 01123 data->items.maxitem= SEARCH_ITEMS; 01124 } 01125 data->items.maxstrlen= but->hardmax; 01126 data->items.totitem= 0; 01127 data->items.names= MEM_callocN(data->items.maxitem*sizeof(void *), "search names"); 01128 data->items.pointers= MEM_callocN(data->items.maxitem*sizeof(void *), "search pointers"); 01129 data->items.icons= MEM_callocN(data->items.maxitem*sizeof(int), "search icons"); 01130 for(x1=0; x1<data->items.maxitem; x1++) 01131 data->items.names[x1]= MEM_callocN(but->hardmax+1, "search pointers"); 01132 01133 return ar; 01134 } 01135 01136 void ui_searchbox_free(bContext *C, ARegion *ar) 01137 { 01138 ui_remove_temporary_region(C, CTX_wm_screen(C), ar); 01139 } 01140 01141 /* sets red alert if button holds a string it can't find */ 01142 /* XXX weak: search_func adds all partial matches... */ 01143 void ui_but_search_test(uiBut *but) 01144 { 01145 uiSearchItems *items; 01146 int x1; 01147 01148 /* possibly very large lists (such as ID datablocks) only 01149 * only validate string RNA buts (not pointers) */ 01150 if(but->rnaprop && RNA_property_type(but->rnaprop) != PROP_STRING) { 01151 return; 01152 } 01153 01154 items= MEM_callocN(sizeof(uiSearchItems), "search items"); 01155 01156 /* setup search struct */ 01157 items->maxitem= 10; 01158 items->maxstrlen= 256; 01159 items->names= MEM_callocN(items->maxitem*sizeof(void *), "search names"); 01160 for(x1=0; x1<items->maxitem; x1++) 01161 items->names[x1]= MEM_callocN(but->hardmax+1, "search names"); 01162 01163 but->search_func(but->block->evil_C, but->search_arg, but->drawstr, items); 01164 01165 /* only redalert when we are sure of it, this can miss cases when >10 matches */ 01166 if(items->totitem==0) 01167 uiButSetFlag(but, UI_BUT_REDALERT); 01168 else if(items->more==0) { 01169 for(x1= 0; x1<items->totitem; x1++) 01170 if(strcmp(but->drawstr, items->names[x1])==0) 01171 break; 01172 if(x1==items->totitem) 01173 uiButSetFlag(but, UI_BUT_REDALERT); 01174 } 01175 01176 for(x1=0; x1<items->maxitem; x1++) 01177 MEM_freeN(items->names[x1]); 01178 MEM_freeN(items->names); 01179 MEM_freeN(items); 01180 } 01181 01182 01183 /************************* Creating Menu Blocks **********************/ 01184 01185 /* position block relative to but, result is in window space */ 01186 static void ui_block_position(wmWindow *window, ARegion *butregion, uiBut *but, uiBlock *block) 01187 { 01188 uiBut *bt; 01189 uiSafetyRct *saferct; 01190 rctf butrct; 01191 float aspect; 01192 int xsize, ysize, xof=0, yof=0, center; 01193 short dir1= 0, dir2=0; 01194 01195 /* transform to window coordinates, using the source button region/block */ 01196 butrct.xmin= but->x1; butrct.xmax= but->x2; 01197 butrct.ymin= but->y1; butrct.ymax= but->y2; 01198 01199 ui_block_to_window_fl(butregion, but->block, &butrct.xmin, &butrct.ymin); 01200 ui_block_to_window_fl(butregion, but->block, &butrct.xmax, &butrct.ymax); 01201 01202 /* calc block rect */ 01203 if(block->minx == 0.0f && block->maxx == 0.0f) { 01204 if(block->buttons.first) { 01205 block->minx= block->miny= 10000; 01206 block->maxx= block->maxy= -10000; 01207 01208 bt= block->buttons.first; 01209 while(bt) { 01210 if(bt->x1 < block->minx) block->minx= bt->x1; 01211 if(bt->y1 < block->miny) block->miny= bt->y1; 01212 01213 if(bt->x2 > block->maxx) block->maxx= bt->x2; 01214 if(bt->y2 > block->maxy) block->maxy= bt->y2; 01215 01216 bt= bt->next; 01217 } 01218 } 01219 else { 01220 /* we're nice and allow empty blocks too */ 01221 block->minx= block->miny= 0; 01222 block->maxx= block->maxy= 20; 01223 } 01224 } 01225 01226 aspect= (float)(block->maxx - block->minx + 4); 01227 ui_block_to_window_fl(butregion, but->block, &block->minx, &block->miny); 01228 ui_block_to_window_fl(butregion, but->block, &block->maxx, &block->maxy); 01229 01230 //block->minx-= 2.0; block->miny-= 2.0; 01231 //block->maxx+= 2.0; block->maxy+= 2.0; 01232 01233 xsize= block->maxx - block->minx+4; // 4 for shadow 01234 ysize= block->maxy - block->miny+4; 01235 aspect/= (float)xsize; 01236 01237 if(but) { 01238 int left=0, right=0, top=0, down=0; 01239 int winx, winy; 01240 // int offscreen; 01241 01242 wm_window_get_size(window, &winx, &winy); 01243 01244 if(block->direction & UI_CENTER) center= ysize/2; 01245 else center= 0; 01246 01247 /* check if there's space at all */ 01248 if( butrct.xmin-xsize > 0.0f) left= 1; 01249 if( butrct.xmax+xsize < winx) right= 1; 01250 if( butrct.ymin-ysize+center > 0.0f) down= 1; 01251 if( butrct.ymax+ysize-center < winy) top= 1; 01252 01253 if(top==0 && down==0) { 01254 if (butrct.ymin-ysize < winy-butrct.ymax-ysize) 01255 top= 1; 01256 else 01257 down= 1; 01258 } 01259 01260 dir1= block->direction & UI_DIRECTION; 01261 01262 /* secundary directions */ 01263 if(dir1 & (UI_TOP|UI_DOWN)) { 01264 if(dir1 & UI_LEFT) dir2= UI_LEFT; 01265 else if(dir1 & UI_RIGHT) dir2= UI_RIGHT; 01266 dir1 &= (UI_TOP|UI_DOWN); 01267 } 01268 01269 if(dir2==0) if(dir1==UI_LEFT || dir1==UI_RIGHT) dir2= UI_DOWN; 01270 if(dir2==0) if(dir1==UI_TOP || dir1==UI_DOWN) dir2= UI_LEFT; 01271 01272 /* no space at all? dont change */ 01273 if(left || right) { 01274 if(dir1==UI_LEFT && left==0) dir1= UI_RIGHT; 01275 if(dir1==UI_RIGHT && right==0) dir1= UI_LEFT; 01276 /* this is aligning, not append! */ 01277 if(dir2==UI_LEFT && right==0) dir2= UI_RIGHT; 01278 if(dir2==UI_RIGHT && left==0) dir2= UI_LEFT; 01279 } 01280 if(down || top) { 01281 if(dir1==UI_TOP && top==0) dir1= UI_DOWN; 01282 if(dir1==UI_DOWN && down==0) dir1= UI_TOP; 01283 if(dir2==UI_TOP && top==0) dir2= UI_DOWN; 01284 if(dir2==UI_DOWN && down==0) dir2= UI_TOP; 01285 } 01286 01287 if(dir1==UI_LEFT) { 01288 xof= butrct.xmin - block->maxx; 01289 if(dir2==UI_TOP) yof= butrct.ymin - block->miny-center; 01290 else yof= butrct.ymax - block->maxy+center; 01291 } 01292 else if(dir1==UI_RIGHT) { 01293 xof= butrct.xmax - block->minx; 01294 if(dir2==UI_TOP) yof= butrct.ymin - block->miny-center; 01295 else yof= butrct.ymax - block->maxy+center; 01296 } 01297 else if(dir1==UI_TOP) { 01298 yof= butrct.ymax - block->miny; 01299 if(dir2==UI_RIGHT) xof= butrct.xmax - block->maxx; 01300 else xof= butrct.xmin - block->minx; 01301 // changed direction? 01302 if((dir1 & block->direction)==0) { 01303 if(block->direction & UI_SHIFT_FLIPPED) 01304 xof+= dir2==UI_LEFT?25:-25; 01305 uiBlockFlipOrder(block); 01306 } 01307 } 01308 else if(dir1==UI_DOWN) { 01309 yof= butrct.ymin - block->maxy; 01310 if(dir2==UI_RIGHT) xof= butrct.xmax - block->maxx; 01311 else xof= butrct.xmin - block->minx; 01312 // changed direction? 01313 if((dir1 & block->direction)==0) { 01314 if(block->direction & UI_SHIFT_FLIPPED) 01315 xof+= dir2==UI_LEFT?25:-25; 01316 uiBlockFlipOrder(block); 01317 } 01318 } 01319 01320 /* and now we handle the exception; no space below or to top */ 01321 if(top==0 && down==0) { 01322 if(dir1==UI_LEFT || dir1==UI_RIGHT) { 01323 // align with bottom of screen 01324 // yof= ysize; (not with menu scrolls) 01325 } 01326 } 01327 01328 /* or no space left or right */ 01329 if(left==0 && right==0) { 01330 if(dir1==UI_TOP || dir1==UI_DOWN) { 01331 // align with left size of screen 01332 xof= -block->minx+5; 01333 } 01334 } 01335 01336 // apply requested offset in the block 01337 xof += block->xofs/block->aspect; 01338 yof += block->yofs/block->aspect; 01339 #if 0 01340 /* clamp to window bounds, could be made into an option if its ever annoying */ 01341 if( (offscreen= (block->miny+yof)) < 0) yof -= offscreen; /* bottom */ 01342 else if((offscreen= (block->maxy+yof)-winy) > 0) yof -= offscreen; /* top */ 01343 if( (offscreen= (block->minx+xof)) < 0) xof -= offscreen; /* left */ 01344 else if((offscreen= (block->maxx+xof)-winx) > 0) xof -= offscreen; /* right */ 01345 #endif 01346 } 01347 01348 /* apply offset, buttons in window coords */ 01349 01350 for(bt= block->buttons.first; bt; bt= bt->next) { 01351 ui_block_to_window_fl(butregion, but->block, &bt->x1, &bt->y1); 01352 ui_block_to_window_fl(butregion, but->block, &bt->x2, &bt->y2); 01353 01354 bt->x1 += xof; 01355 bt->x2 += xof; 01356 bt->y1 += yof; 01357 bt->y2 += yof; 01358 01359 bt->aspect= 1.0; 01360 // ui_check_but recalculates drawstring size in pixels 01361 ui_check_but(bt); 01362 } 01363 01364 block->minx += xof; 01365 block->miny += yof; 01366 block->maxx += xof; 01367 block->maxy += yof; 01368 01369 /* safety calculus */ 01370 if(but) { 01371 float midx= (butrct.xmin+butrct.xmax)/2.0f; 01372 float midy= (butrct.ymin+butrct.ymax)/2.0f; 01373 01374 /* when you are outside parent button, safety there should be smaller */ 01375 01376 // parent button to left 01377 if( midx < block->minx ) block->safety.xmin= block->minx-3; 01378 else block->safety.xmin= block->minx-40; 01379 // parent button to right 01380 if( midx > block->maxx ) block->safety.xmax= block->maxx+3; 01381 else block->safety.xmax= block->maxx+40; 01382 01383 // parent button on bottom 01384 if( midy < block->miny ) block->safety.ymin= block->miny-3; 01385 else block->safety.ymin= block->miny-40; 01386 // parent button on top 01387 if( midy > block->maxy ) block->safety.ymax= block->maxy+3; 01388 else block->safety.ymax= block->maxy+40; 01389 01390 // exception for switched pulldowns... 01391 if(dir1 && (dir1 & block->direction)==0) { 01392 if(dir2==UI_RIGHT) block->safety.xmax= block->maxx+3; 01393 if(dir2==UI_LEFT) block->safety.xmin= block->minx-3; 01394 } 01395 block->direction= dir1; 01396 } 01397 else { 01398 block->safety.xmin= block->minx-40; 01399 block->safety.ymin= block->miny-40; 01400 block->safety.xmax= block->maxx+40; 01401 block->safety.ymax= block->maxy+40; 01402 } 01403 01404 /* keep a list of these, needed for pulldown menus */ 01405 saferct= MEM_callocN(sizeof(uiSafetyRct), "uiSafetyRct"); 01406 saferct->parent= butrct; 01407 saferct->safety= block->safety; 01408 BLI_freelistN(&block->saferct); 01409 if(but) 01410 BLI_duplicatelist(&block->saferct, &but->block->saferct); 01411 BLI_addhead(&block->saferct, saferct); 01412 } 01413 01414 static void ui_block_region_draw(const bContext *C, ARegion *ar) 01415 { 01416 uiBlock *block; 01417 01418 for(block=ar->uiblocks.first; block; block=block->next) 01419 uiDrawBlock(C, block); 01420 } 01421 01422 static void ui_popup_block_clip(wmWindow *window, uiBlock *block) 01423 { 01424 int winx, winy; 01425 01426 wm_window_get_size(window, &winx, &winy); 01427 01428 if(block->minx < MENU_SHADOW_SIDE) 01429 block->minx= MENU_SHADOW_SIDE; 01430 if(block->maxx > winx-MENU_SHADOW_SIDE) 01431 block->maxx= winx-MENU_SHADOW_SIDE; 01432 01433 if(block->miny < MENU_SHADOW_BOTTOM) 01434 block->miny= MENU_SHADOW_BOTTOM; 01435 if(block->maxy > winy-MENU_TOP) 01436 block->maxy= winy-MENU_TOP; 01437 } 01438 01439 void ui_popup_block_scrolltest(uiBlock *block) 01440 { 01441 uiBut *bt; 01442 01443 block->flag &= ~(UI_BLOCK_CLIPBOTTOM|UI_BLOCK_CLIPTOP); 01444 01445 for(bt= block->buttons.first; bt; bt= bt->next) 01446 bt->flag &= ~UI_SCROLLED; 01447 01448 if(block->buttons.first==block->buttons.last) 01449 return; 01450 01451 /* mark buttons that are outside boundary and the ones next to it for arrow(s) */ 01452 for(bt= block->buttons.first; bt; bt= bt->next) { 01453 if(bt->y1 < block->miny) { 01454 bt->flag |= UI_SCROLLED; 01455 block->flag |= UI_BLOCK_CLIPBOTTOM; 01456 /* make space for arrow */ 01457 if(bt->y2 < block->miny +10) { 01458 if(bt->next && bt->next->y1 > bt->y1) 01459 bt->next->flag |= UI_SCROLLED; 01460 if(bt->prev && bt->prev->y1 > bt->y1) 01461 bt->prev->flag |= UI_SCROLLED; 01462 } 01463 } 01464 if(bt->y2 > block->maxy) { 01465 bt->flag |= UI_SCROLLED; 01466 block->flag |= UI_BLOCK_CLIPTOP; 01467 /* make space for arrow */ 01468 if(bt->y1 > block->maxy -10) { 01469 if(bt->next && bt->next->y2 < bt->y2) 01470 bt->next->flag |= UI_SCROLLED; 01471 if(bt->prev && bt->prev->y2 < bt->y2) 01472 bt->prev->flag |= UI_SCROLLED; 01473 } 01474 } 01475 } 01476 } 01477 01478 uiPopupBlockHandle *ui_popup_block_create(bContext *C, ARegion *butregion, uiBut *but, uiBlockCreateFunc create_func, uiBlockHandleCreateFunc handle_create_func, void *arg) 01479 { 01480 wmWindow *window= CTX_wm_window(C); 01481 static ARegionType type; 01482 ARegion *ar; 01483 uiBlock *block; 01484 uiBut *bt; 01485 uiPopupBlockHandle *handle; 01486 uiSafetyRct *saferct; 01487 01488 /* create handle */ 01489 handle= MEM_callocN(sizeof(uiPopupBlockHandle), "uiPopupBlockHandle"); 01490 01491 /* store context for operator */ 01492 handle->ctx_area= CTX_wm_area(C); 01493 handle->ctx_region= CTX_wm_region(C); 01494 01495 /* create area region */ 01496 ar= ui_add_temporary_region(CTX_wm_screen(C)); 01497 handle->region= ar; 01498 01499 memset(&type, 0, sizeof(ARegionType)); 01500 type.draw= ui_block_region_draw; 01501 ar->type= &type; 01502 01503 UI_add_region_handlers(&ar->handlers); 01504 01505 /* create ui block */ 01506 if(create_func) 01507 block= create_func(C, handle->region, arg); 01508 else 01509 block= handle_create_func(C, handle, arg); 01510 01511 if(block->handle) { 01512 memcpy(block->handle, handle, sizeof(uiPopupBlockHandle)); 01513 MEM_freeN(handle); 01514 handle= block->handle; 01515 } 01516 else 01517 block->handle= handle; 01518 01519 ar->regiondata= handle; 01520 01521 if(!block->endblock) 01522 uiEndBlock(C, block); 01523 01524 /* if this is being created from a button */ 01525 if(but) { 01526 if(ELEM(but->type, BLOCK, PULLDOWN)) 01527 block->xofs = -2; /* for proper alignment */ 01528 01529 /* only used for automatic toolbox, so can set the shift flag */ 01530 if(but->flag & UI_MAKE_TOP) { 01531 block->direction= UI_TOP|UI_SHIFT_FLIPPED; 01532 uiBlockFlipOrder(block); 01533 } 01534 if(but->flag & UI_MAKE_DOWN) block->direction= UI_DOWN|UI_SHIFT_FLIPPED; 01535 if(but->flag & UI_MAKE_LEFT) block->direction |= UI_LEFT; 01536 if(but->flag & UI_MAKE_RIGHT) block->direction |= UI_RIGHT; 01537 01538 ui_block_position(window, butregion, but, block); 01539 } 01540 else { 01541 /* keep a list of these, needed for pulldown menus */ 01542 saferct= MEM_callocN(sizeof(uiSafetyRct), "uiSafetyRct"); 01543 saferct->safety= block->safety; 01544 BLI_addhead(&block->saferct, saferct); 01545 block->flag |= UI_BLOCK_POPUP|UI_BLOCK_NUMSELECT; 01546 } 01547 01548 /* clip block with window boundary */ 01549 ui_popup_block_clip(window, block); 01550 01551 /* the block and buttons were positioned in window space as in 2.4x, now 01552 * these menu blocks are regions so we bring it back to region space. 01553 * additionally we add some padding for the menu shadow or rounded menus */ 01554 ar->winrct.xmin= block->minx - MENU_SHADOW_SIDE; 01555 ar->winrct.xmax= block->maxx + MENU_SHADOW_SIDE; 01556 ar->winrct.ymin= block->miny - MENU_SHADOW_BOTTOM; 01557 ar->winrct.ymax= block->maxy + MENU_TOP; 01558 01559 block->minx -= ar->winrct.xmin; 01560 block->maxx -= ar->winrct.xmin; 01561 block->miny -= ar->winrct.ymin; 01562 block->maxy -= ar->winrct.ymin; 01563 01564 for(bt= block->buttons.first; bt; bt= bt->next) { 01565 bt->x1 -= ar->winrct.xmin; 01566 bt->x2 -= ar->winrct.xmin; 01567 bt->y1 -= ar->winrct.ymin; 01568 bt->y2 -= ar->winrct.ymin; 01569 } 01570 01571 block->flag |= UI_BLOCK_LOOP; 01572 01573 /* adds subwindow */ 01574 ED_region_init(C, ar); 01575 01576 /* checks which buttons are visible, sets flags to prevent draw (do after region init) */ 01577 ui_popup_block_scrolltest(block); 01578 01579 /* get winmat now that we actually have the subwindow */ 01580 wmSubWindowSet(window, ar->swinid); 01581 01582 wm_subwindow_getmatrix(window, ar->swinid, block->winmat); 01583 01584 /* notify change and redraw */ 01585 ED_region_tag_redraw(ar); 01586 01587 return handle; 01588 } 01589 01590 void ui_popup_block_free(bContext *C, uiPopupBlockHandle *handle) 01591 { 01592 ui_remove_temporary_region(C, CTX_wm_screen(C), handle->region); 01593 01594 if(handle->scrolltimer) 01595 WM_event_remove_timer(CTX_wm_manager(C), CTX_wm_window(C), handle->scrolltimer); 01596 01597 MEM_freeN(handle); 01598 } 01599 01600 /***************************** Menu Button ***************************/ 01601 01602 static void ui_block_func_MENUSTR(bContext *UNUSED(C), uiLayout *layout, void *arg_str) 01603 { 01604 uiBlock *block= uiLayoutGetBlock(layout); 01605 uiPopupBlockHandle *handle= block->handle; 01606 uiLayout *split, *column=NULL; 01607 uiBut *bt; 01608 MenuData *md; 01609 MenuEntry *entry; 01610 char *instr= arg_str; 01611 int columns, rows, a, b; 01612 01613 uiBlockSetFlag(block, UI_BLOCK_MOVEMOUSE_QUIT); 01614 01615 /* compute menu data */ 01616 md= decompose_menu_string(instr); 01617 01618 /* columns and row estimation */ 01619 columns= (md->nitems+20)/20; 01620 if(columns<1) 01621 columns= 1; 01622 if(columns>8) 01623 columns= (md->nitems+25)/25; 01624 01625 rows= md->nitems/columns; 01626 if(rows<1) 01627 rows= 1; 01628 while(rows*columns<md->nitems) 01629 rows++; 01630 01631 /* create title */ 01632 if(md->title) { 01633 if(md->titleicon) { 01634 uiItemL(layout, md->title, md->titleicon); 01635 } 01636 else { 01637 uiItemL(layout, md->title, ICON_NONE); 01638 bt= block->buttons.last; 01639 bt->flag= UI_TEXT_LEFT; 01640 } 01641 } 01642 01643 /* inconsistent, but menus with labels do not look good flipped */ 01644 for(a=0, b=0; a<md->nitems; a++, b++) { 01645 entry= &md->items[a]; 01646 01647 if(entry->sepr && entry->str[0]) 01648 block->flag |= UI_BLOCK_NO_FLIP; 01649 } 01650 01651 /* create items */ 01652 split= uiLayoutSplit(layout, 0, 0); 01653 01654 for(a=0, b=0; a<md->nitems; a++, b++) { 01655 if(block->flag & UI_BLOCK_NO_FLIP) 01656 entry= &md->items[a]; 01657 else 01658 entry= &md->items[md->nitems-a-1]; 01659 01660 /* new column on N rows or on separation label */ 01661 if((b % rows == 0) || (entry->sepr && entry->str[0])) { 01662 column= uiLayoutColumn(split, 0); 01663 b= 0; 01664 } 01665 01666 if(entry->sepr) { 01667 uiItemL(column, entry->str, entry->icon); 01668 bt= block->buttons.last; 01669 bt->flag= UI_TEXT_LEFT; 01670 } 01671 else if(entry->icon) { 01672 uiDefIconTextButF(block, BUTM|FLO, B_NOP, entry->icon, entry->str, 0, 0, 01673 UI_UNIT_X*5, UI_UNIT_Y, &handle->retvalue, (float) entry->retval, 0.0, 0, 0, ""); 01674 } 01675 else { 01676 uiDefButF(block, BUTM|FLO, B_NOP, entry->str, 0, 0, 01677 UI_UNIT_X*5, UI_UNIT_X, &handle->retvalue, (float) entry->retval, 0.0, 0, 0, ""); 01678 } 01679 } 01680 01681 menudata_free(md); 01682 } 01683 01684 void ui_block_func_ICONROW(bContext *UNUSED(C), uiLayout *layout, void *arg_but) 01685 { 01686 uiBlock *block= uiLayoutGetBlock(layout); 01687 uiPopupBlockHandle *handle= block->handle; 01688 uiBut *but= arg_but; 01689 int a; 01690 01691 uiBlockSetFlag(block, UI_BLOCK_MOVEMOUSE_QUIT); 01692 01693 for(a=(int)but->hardmin; a<=(int)but->hardmax; a++) 01694 uiDefIconButF(block, BUTM|FLO, B_NOP, but->icon+(a-but->hardmin), 0, 0, UI_UNIT_X*5, UI_UNIT_Y, 01695 &handle->retvalue, (float)a, 0.0, 0, 0, ""); 01696 } 01697 01698 void ui_block_func_ICONTEXTROW(bContext *UNUSED(C), uiLayout *layout, void *arg_but) 01699 { 01700 uiBlock *block= uiLayoutGetBlock(layout); 01701 uiPopupBlockHandle *handle= block->handle; 01702 uiBut *but= arg_but, *bt; 01703 MenuData *md; 01704 MenuEntry *entry; 01705 int a; 01706 01707 uiBlockSetFlag(block, UI_BLOCK_MOVEMOUSE_QUIT); 01708 01709 md= decompose_menu_string(but->str); 01710 01711 /* title */ 01712 if(md->title) { 01713 bt= uiDefBut(block, LABEL, 0, md->title, 0, 0, UI_UNIT_X*5, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, ""); 01714 bt->flag= UI_TEXT_LEFT; 01715 } 01716 01717 /* loop through the menu options and draw them out with icons & text labels */ 01718 for(a=0; a<md->nitems; a++) { 01719 entry= &md->items[md->nitems-a-1]; 01720 01721 if(entry->sepr) 01722 uiItemS(layout); 01723 else 01724 uiDefIconTextButF(block, BUTM|FLO, B_NOP, (short)((but->icon)+(entry->retval-but->hardmin)), entry->str, 01725 0, 0, UI_UNIT_X*5, UI_UNIT_Y, &handle->retvalue, (float) entry->retval, 0.0, 0, 0, ""); 01726 } 01727 01728 menudata_free(md); 01729 } 01730 01731 #if 0 01732 static void ui_warp_pointer(int x, int y) 01733 { 01734 /* XXX 2.50 which function to use for this? */ 01735 /* OSX has very poor mousewarp support, it sends events; 01736 this causes a menu being pressed immediately ... */ 01737 #ifndef __APPLE__ 01738 warp_pointer(x, y); 01739 #endif 01740 } 01741 #endif 01742 01743 /********************* Color Button ****************/ 01744 01745 /* picker sizes S hsize, F full size, D spacer, B button/pallette height */ 01746 #define SPICK 110.0 01747 #define FPICK 180.0 01748 #define DPICK 6.0 01749 #define BPICK 24.0 01750 01751 /* for picker, while editing hsv */ 01752 void ui_set_but_hsv(uiBut *but) 01753 { 01754 float col[3]; 01755 float *hsv= ui_block_hsv_get(but->block); 01756 01757 hsv_to_rgb(hsv[0], hsv[1], hsv[2], col, col+1, col+2); 01758 ui_set_but_vectorf(but, col); 01759 } 01760 01761 /* also used by small picker, be careful with name checks below... */ 01762 static void ui_update_block_buts_rgb(uiBlock *block, float *rgb) 01763 { 01764 uiBut *bt; 01765 float *hsv= ui_block_hsv_get(block); 01766 01767 /* this is to keep the H and S value when V is equal to zero 01768 * and we are working in HSV mode, of course! 01769 */ 01770 rgb_to_hsv_compat(rgb[0], rgb[1], rgb[2], hsv, hsv+1, hsv+2); 01771 01772 // this updates button strings, is hackish... but button pointers are on stack of caller function 01773 for(bt= block->buttons.first; bt; bt= bt->next) { 01774 if (bt->rnaprop) { 01775 01776 ui_set_but_vectorf(bt, rgb); 01777 01778 } 01779 else if(strcmp(bt->str, "Hex: ")==0) { 01780 float rgb_gamma[3]; 01781 double intpart; 01782 char col[16]; 01783 01784 /* Hex code is assumed to be in sRGB space (coming from other applications, web, etc) */ 01785 01786 if (block->color_profile == BLI_PR_NONE) { 01787 copy_v3_v3(rgb_gamma, rgb); 01788 } else { 01789 /* make an sRGB version, for Hex code */ 01790 linearrgb_to_srgb_v3_v3(rgb_gamma, rgb); 01791 } 01792 01793 if (rgb_gamma[0] > 1.0f) rgb_gamma[0] = modf(rgb_gamma[0], &intpart); 01794 if (rgb_gamma[1] > 1.0f) rgb_gamma[1] = modf(rgb_gamma[1], &intpart); 01795 if (rgb_gamma[2] > 1.0f) rgb_gamma[2] = modf(rgb_gamma[2], &intpart); 01796 01797 sprintf(col, "%02X%02X%02X", FTOCHAR(rgb_gamma[0]), FTOCHAR(rgb_gamma[1]), FTOCHAR(rgb_gamma[2])); 01798 01799 strcpy(bt->poin, col); 01800 } 01801 else if(bt->str[1]==' ') { 01802 if(bt->str[0]=='R') { 01803 ui_set_but_val(bt, rgb[0]); 01804 } 01805 else if(bt->str[0]=='G') { 01806 ui_set_but_val(bt, rgb[1]); 01807 } 01808 else if(bt->str[0]=='B') { 01809 ui_set_but_val(bt, rgb[2]); 01810 } 01811 else if(bt->str[0]=='H') { 01812 ui_set_but_val(bt, hsv[0]); 01813 } 01814 else if(bt->str[0]=='S') { 01815 ui_set_but_val(bt, hsv[1]); 01816 } 01817 else if(bt->str[0]=='V') { 01818 ui_set_but_val(bt, hsv[2]); 01819 } 01820 } 01821 01822 ui_check_but(bt); 01823 } 01824 } 01825 01826 static void do_picker_rna_cb(bContext *UNUSED(C), void *bt1, void *UNUSED(arg)) 01827 { 01828 uiBut *but= (uiBut *)bt1; 01829 uiPopupBlockHandle *popup= but->block->handle; 01830 PropertyRNA *prop = but->rnaprop; 01831 PointerRNA ptr = but->rnapoin; 01832 float rgb[4]; 01833 01834 if (prop) { 01835 RNA_property_float_get_array(&ptr, prop, rgb); 01836 ui_update_block_buts_rgb(but->block, rgb); 01837 } 01838 01839 if(popup) 01840 popup->menuretval= UI_RETURN_UPDATE; 01841 } 01842 01843 static void do_hsv_rna_cb(bContext *UNUSED(C), void *bt1, void *UNUSED(arg)) 01844 { 01845 uiBut *but= (uiBut *)bt1; 01846 uiPopupBlockHandle *popup= but->block->handle; 01847 float rgb[3]; 01848 float *hsv= ui_block_hsv_get(but->block); 01849 01850 hsv_to_rgb(hsv[0], hsv[1], hsv[2], rgb, rgb+1, rgb+2); 01851 01852 ui_update_block_buts_rgb(but->block, rgb); 01853 01854 if(popup) 01855 popup->menuretval= UI_RETURN_UPDATE; 01856 } 01857 01858 static void do_hex_rna_cb(bContext *UNUSED(C), void *bt1, void *hexcl) 01859 { 01860 uiBut *but= (uiBut *)bt1; 01861 uiPopupBlockHandle *popup= but->block->handle; 01862 char *hexcol= (char *)hexcl; 01863 float rgb[3]; 01864 01865 hex_to_rgb(hexcol, rgb, rgb+1, rgb+2); 01866 01867 /* Hex code is assumed to be in sRGB space (coming from other applications, web, etc) */ 01868 if (but->block->color_profile != BLI_PR_NONE) { 01869 /* so we need to linearise it for Blender */ 01870 srgb_to_linearrgb_v3_v3(rgb, rgb); 01871 } 01872 01873 ui_update_block_buts_rgb(but->block, rgb); 01874 01875 if(popup) 01876 popup->menuretval= UI_RETURN_UPDATE; 01877 } 01878 01879 static void close_popup_cb(bContext *UNUSED(C), void *bt1, void *UNUSED(arg)) 01880 { 01881 uiBut *but= (uiBut *)bt1; 01882 uiPopupBlockHandle *popup= but->block->handle; 01883 01884 if(popup) 01885 popup->menuretval= UI_RETURN_OK; 01886 } 01887 01888 static void picker_new_hide_reveal(uiBlock *block, short colormode) 01889 { 01890 uiBut *bt; 01891 01892 /* tag buttons */ 01893 for(bt= block->buttons.first; bt; bt= bt->next) { 01894 01895 if (bt->type == LABEL) { 01896 if( bt->str[1]=='G') { 01897 if(colormode==2) bt->flag &= ~UI_HIDDEN; 01898 else bt->flag |= UI_HIDDEN; 01899 } 01900 } 01901 01902 if(bt->type==NUMSLI || bt->type==TEX) { 01903 if( bt->str[1]=='e') { 01904 if(colormode==2) bt->flag &= ~UI_HIDDEN; 01905 else bt->flag |= UI_HIDDEN; 01906 } 01907 else if( ELEM3(bt->str[0], 'R', 'G', 'B')) { 01908 if(colormode==0) bt->flag &= ~UI_HIDDEN; 01909 else bt->flag |= UI_HIDDEN; 01910 } 01911 else if( ELEM3(bt->str[0], 'H', 'S', 'V')) { 01912 if(colormode==1) bt->flag &= ~UI_HIDDEN; 01913 else bt->flag |= UI_HIDDEN; 01914 } 01915 } 01916 } 01917 } 01918 01919 static void do_picker_new_mode_cb(bContext *UNUSED(C), void *bt1, void *UNUSED(arg)) 01920 { 01921 uiBut *bt= bt1; 01922 short colormode= ui_get_but_val(bt); 01923 picker_new_hide_reveal(bt->block, colormode); 01924 } 01925 01926 /* picker sizes S hsize, F full size, D spacer, B button/pallette height */ 01927 #define SPICK1 150.0 01928 #define DPICK1 6.0 01929 01930 #define PICKER_H 150 01931 #define PICKER_W 150 01932 #define PICKER_SPACE 6 01933 #define PICKER_BAR 14 01934 01935 #define PICKER_TOTAL_W (PICKER_W+PICKER_SPACE+PICKER_BAR) 01936 01937 static void circle_picker(uiBlock *block, PointerRNA *ptr, PropertyRNA *prop) 01938 { 01939 uiBut *bt; 01940 01941 /* HS circle */ 01942 bt= uiDefButR_prop(block, HSVCIRCLE, 0, "", 0, 0, PICKER_H, PICKER_W, ptr, prop, 0, 0.0, 0.0, 0, 0, "Color"); 01943 uiButSetFunc(bt, do_picker_rna_cb, bt, NULL); 01944 01945 /* value */ 01946 bt= uiDefButR_prop(block, HSVCUBE, 0, "", PICKER_W+PICKER_SPACE,0,PICKER_BAR,PICKER_H, ptr, prop, 0, 0.0, 0.0, UI_GRAD_V_ALT, 0, "Value"); 01947 uiButSetFunc(bt, do_picker_rna_cb, bt, NULL); 01948 } 01949 01950 01951 static void square_picker(uiBlock *block, PointerRNA *ptr, PropertyRNA *prop, int type) 01952 { 01953 uiBut *bt; 01954 int bartype = type + 3; 01955 01956 /* HS square */ 01957 bt= uiDefButR_prop(block, HSVCUBE, 0, "", 0, PICKER_BAR+PICKER_SPACE, PICKER_TOTAL_W, PICKER_H, ptr, prop, 0, 0.0, 0.0, type, 0, "Color"); 01958 uiButSetFunc(bt, do_picker_rna_cb, bt, NULL); 01959 01960 /* value */ 01961 bt= uiDefButR_prop(block, HSVCUBE, 0, "", 0, 0, PICKER_TOTAL_W, PICKER_BAR, ptr, prop, 0, 0.0, 0.0, bartype, 0, "Value"); 01962 uiButSetFunc(bt, do_picker_rna_cb, bt, NULL); 01963 } 01964 01965 01966 /* a HS circle, V slider, rgb/hsv/hex sliders */ 01967 static void uiBlockPicker(uiBlock *block, float *rgb, PointerRNA *ptr, PropertyRNA *prop) 01968 { 01969 static short colormode= 0; /* temp? 0=rgb, 1=hsv, 2=hex */ 01970 uiBut *bt; 01971 int width, butwidth; 01972 static char tip[50]; 01973 static char hexcol[128]; 01974 float rgb_gamma[3]; 01975 float min, max, step, precision; 01976 float *hsv= ui_block_hsv_get(block); 01977 01978 ui_block_hsv_get(block); 01979 01980 width= PICKER_TOTAL_W; 01981 butwidth = width - UI_UNIT_X - 10; 01982 01983 /* existence of profile means storage is in linear color space, with display correction */ 01984 if (block->color_profile == BLI_PR_NONE) { 01985 sprintf(tip, "Value in Display Color Space"); 01986 copy_v3_v3(rgb_gamma, rgb); 01987 } else { 01988 sprintf(tip, "Value in Linear RGB Color Space"); 01989 /* make an sRGB version, for Hex code */ 01990 linearrgb_to_srgb_v3_v3(rgb_gamma, rgb); 01991 } 01992 01993 /* sneaky way to check for alpha */ 01994 rgb[3]= FLT_MAX; 01995 01996 RNA_property_float_ui_range(ptr, prop, &min, &max, &step, &precision); 01997 RNA_property_float_get_array(ptr, prop, rgb); 01998 01999 switch (U.color_picker_type) { 02000 case USER_CP_CIRCLE: 02001 circle_picker(block, ptr, prop); 02002 break; 02003 case USER_CP_SQUARE_SV: 02004 square_picker(block, ptr, prop, UI_GRAD_SV); 02005 break; 02006 case USER_CP_SQUARE_HS: 02007 square_picker(block, ptr, prop, UI_GRAD_HS); 02008 break; 02009 case USER_CP_SQUARE_HV: 02010 square_picker(block, ptr, prop, UI_GRAD_HV); 02011 break; 02012 } 02013 02014 /* mode */ 02015 uiBlockBeginAlign(block); 02016 bt= uiDefButS(block, ROW, 0, "RGB", 0, -30, width/3, UI_UNIT_Y, &colormode, 0.0, 0.0, 0, 0, ""); 02017 uiButSetFunc(bt, do_picker_new_mode_cb, bt, NULL); 02018 bt= uiDefButS(block, ROW, 0, "HSV", width/3, -30, width/3, UI_UNIT_Y, &colormode, 0.0, 1.0, 0, 0, ""); 02019 uiButSetFunc(bt, do_picker_new_mode_cb, bt, NULL); 02020 bt= uiDefButS(block, ROW, 0, "Hex", 2*width/3, -30, width/3, UI_UNIT_Y, &colormode, 0.0, 2.0, 0, 0, ""); 02021 uiButSetFunc(bt, do_picker_new_mode_cb, bt, NULL); 02022 uiBlockEndAlign(block); 02023 02024 bt= uiDefIconButO(block, BUT, "UI_OT_eyedropper", WM_OP_INVOKE_DEFAULT, ICON_EYEDROPPER, butwidth+10, -60, UI_UNIT_X, UI_UNIT_Y, NULL); 02025 uiButSetFunc(bt, close_popup_cb, bt, NULL); 02026 02027 /* RGB values */ 02028 uiBlockBeginAlign(block); 02029 bt= uiDefButR_prop(block, NUMSLI, 0, "R ", 0, -60, butwidth, UI_UNIT_Y, ptr, prop, 0, 0.0, 0.0, 0, 3, "Red"); 02030 uiButSetFunc(bt, do_picker_rna_cb, bt, NULL); 02031 bt= uiDefButR_prop(block, NUMSLI, 0, "G ", 0, -80, butwidth, UI_UNIT_Y, ptr, prop, 1, 0.0, 0.0, 0, 3, "Green"); 02032 uiButSetFunc(bt, do_picker_rna_cb, bt, NULL); 02033 bt= uiDefButR_prop(block, NUMSLI, 0, "B ", 0, -100, butwidth, UI_UNIT_Y, ptr, prop, 2, 0.0, 0.0, 0, 3, "Blue"); 02034 uiButSetFunc(bt, do_picker_rna_cb, bt, NULL); 02035 02036 // could use uiItemFullR(col, ptr, prop, -1, 0, UI_ITEM_R_EXPAND|UI_ITEM_R_SLIDER, "", ICON_NONE); 02037 // but need to use uiButSetFunc for updating other fake buttons 02038 02039 /* HSV values */ 02040 uiBlockBeginAlign(block); 02041 bt= uiDefButF(block, NUMSLI, 0, "H ", 0, -60, butwidth, UI_UNIT_Y, hsv, 0.0, 1.0, 10, 3, "Hue"); 02042 uiButSetFunc(bt, do_hsv_rna_cb, bt, hsv); 02043 bt= uiDefButF(block, NUMSLI, 0, "S ", 0, -80, butwidth, UI_UNIT_Y, hsv+1, 0.0, 1.0, 10, 3, "Saturation"); 02044 uiButSetFunc(bt, do_hsv_rna_cb, bt, hsv); 02045 bt= uiDefButF(block, NUMSLI, 0, "V ", 0, -100, butwidth, UI_UNIT_Y, hsv+2, 0.0, max, 10, 3, "Value"); 02046 uiButSetFunc(bt, do_hsv_rna_cb, bt, hsv); 02047 uiBlockEndAlign(block); 02048 02049 if(rgb[3] != FLT_MAX) { 02050 bt= uiDefButR_prop(block, NUMSLI, 0, "A ", 0, -120, butwidth, UI_UNIT_Y, ptr, prop, 3, 0.0, 0.0, 0, 0, "Alpha"); 02051 uiButSetFunc(bt, do_picker_rna_cb, bt, NULL); 02052 } 02053 else { 02054 rgb[3]= 1.0f; 02055 } 02056 02057 sprintf(hexcol, "%02X%02X%02X", FTOCHAR(rgb_gamma[0]), FTOCHAR(rgb_gamma[1]), FTOCHAR(rgb_gamma[2])); 02058 02059 bt= uiDefBut(block, TEX, 0, "Hex: ", 0, -60, butwidth, UI_UNIT_Y, hexcol, 0, 8, 0, 0, "Hex triplet for color (#RRGGBB)"); 02060 uiButSetFunc(bt, do_hex_rna_cb, bt, hexcol); 02061 uiDefBut(block, LABEL, 0, "(Gamma Corrected)", 0, -80, butwidth, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, ""); 02062 02063 rgb_to_hsv(rgb[0], rgb[1], rgb[2], hsv, hsv+1, hsv+2); 02064 02065 picker_new_hide_reveal(block, colormode); 02066 } 02067 02068 02069 static int ui_picker_small_wheel_cb(const bContext *UNUSED(C), uiBlock *block, wmEvent *event) 02070 { 02071 float add= 0.0f; 02072 02073 if(event->type==WHEELUPMOUSE) 02074 add= 0.05f; 02075 else if(event->type==WHEELDOWNMOUSE) 02076 add= -0.05f; 02077 02078 if(add!=0.0f) { 02079 uiBut *but; 02080 02081 for(but= block->buttons.first; but; but= but->next) { 02082 if(but->type==HSVCUBE && but->active==NULL) { 02083 uiPopupBlockHandle *popup= block->handle; 02084 float col[3]; 02085 float *hsv= ui_block_hsv_get(block); 02086 02087 ui_get_but_vectorf(but, col); 02088 02089 rgb_to_hsv_compat(col[0], col[1], col[2], hsv, hsv+1, hsv+2); 02090 hsv[2]= CLAMPIS(hsv[2]+add, 0.0f, 1.0f); 02091 hsv_to_rgb(hsv[0], hsv[1], hsv[2], col, col+1, col+2); 02092 02093 ui_set_but_vectorf(but, col); 02094 02095 ui_update_block_buts_rgb(block, col); 02096 if(popup) 02097 popup->menuretval= UI_RETURN_UPDATE; 02098 02099 return 1; 02100 } 02101 } 02102 } 02103 return 0; 02104 } 02105 02106 uiBlock *ui_block_func_COL(bContext *C, uiPopupBlockHandle *handle, void *arg_but) 02107 { 02108 uiBut *but= arg_but; 02109 uiBlock *block; 02110 02111 block= uiBeginBlock(C, handle->region, "colorpicker", UI_EMBOSS); 02112 02113 if (but->rnaprop) { 02114 if (RNA_property_subtype(but->rnaprop) == PROP_COLOR_GAMMA) { 02115 block->color_profile = BLI_PR_NONE; 02116 } 02117 } 02118 02119 uiBlockSetFlag(block, UI_BLOCK_MOVEMOUSE_QUIT); 02120 02121 VECCOPY(handle->retvec, but->editvec); 02122 02123 uiBlockPicker(block, handle->retvec, &but->rnapoin, but->rnaprop); 02124 02125 block->flag= UI_BLOCK_LOOP|UI_BLOCK_REDRAW|UI_BLOCK_KEEP_OPEN|UI_BLOCK_OUT_1; 02126 uiBoundsBlock(block, 10); 02127 02128 block->block_event_func= ui_picker_small_wheel_cb; 02129 02130 /* and lets go */ 02131 block->direction= UI_TOP; 02132 02133 return block; 02134 } 02135 02136 /************************ Popup Menu Memory ****************************/ 02137 02138 static int ui_popup_string_hash(char *str) 02139 { 02140 /* sometimes button contains hotkey, sometimes not, strip for proper compare */ 02141 int hash; 02142 char *delimit= strchr(str, '|'); 02143 02144 if(delimit) *delimit= 0; 02145 hash= BLI_ghashutil_strhash(str); 02146 if(delimit) *delimit= '|'; 02147 02148 return hash; 02149 } 02150 02151 static int ui_popup_menu_hash(char *str) 02152 { 02153 return BLI_ghashutil_strhash(str); 02154 } 02155 02156 /* but == NULL read, otherwise set */ 02157 uiBut *ui_popup_menu_memory(uiBlock *block, uiBut *but) 02158 { 02159 static int mem[256], first=1; 02160 int hash= block->puphash; 02161 02162 if(first) { 02163 /* init */ 02164 memset(mem, -1, sizeof(mem)); 02165 first= 0; 02166 } 02167 02168 if(but) { 02169 /* set */ 02170 mem[hash & 255 ]= ui_popup_string_hash(but->str); 02171 return NULL; 02172 } 02173 else { 02174 /* get */ 02175 for(but=block->buttons.first; but; but=but->next) 02176 if(ui_popup_string_hash(but->str) == mem[hash & 255]) 02177 return but; 02178 02179 return NULL; 02180 } 02181 } 02182 02183 /******************** Popup Menu with callback or string **********************/ 02184 02185 struct uiPopupMenu { 02186 uiBlock *block; 02187 uiLayout *layout; 02188 uiBut *but; 02189 02190 int mx, my, popup, slideout; 02191 int startx, starty, maxrow; 02192 02193 uiMenuCreateFunc menu_func; 02194 void *menu_arg; 02195 }; 02196 02197 static uiBlock *ui_block_func_POPUP(bContext *C, uiPopupBlockHandle *handle, void *arg_pup) 02198 { 02199 uiBlock *block; 02200 uiBut *bt; 02201 ScrArea *sa; 02202 ARegion *ar; 02203 uiPopupMenu *pup= arg_pup; 02204 int offset[2], direction, minwidth, width, height, flip; 02205 02206 if(pup->menu_func) { 02207 pup->block->handle= handle; 02208 pup->menu_func(C, pup->layout, pup->menu_arg); 02209 pup->block->handle= NULL; 02210 } 02211 02212 if(pup->but) { 02213 /* minimum width to enforece */ 02214 minwidth= pup->but->x2 - pup->but->x1; 02215 02216 if(pup->but->type == PULLDOWN || pup->but->menu_create_func) { 02217 direction= UI_DOWN; 02218 flip= 1; 02219 } 02220 else { 02221 direction= UI_TOP; 02222 flip= 0; 02223 } 02224 } 02225 else { 02226 minwidth= 50; 02227 direction= UI_DOWN; 02228 flip= 1; 02229 } 02230 02231 block= pup->block; 02232 02233 /* in some cases we create the block before the region, 02234 so we set it delayed here if necessary */ 02235 if(BLI_findindex(&handle->region->uiblocks, block) == -1) 02236 uiBlockSetRegion(block, handle->region); 02237 02238 block->direction= direction; 02239 02240 uiBlockLayoutResolve(block, &width, &height); 02241 02242 uiBlockSetFlag(block, UI_BLOCK_MOVEMOUSE_QUIT); 02243 02244 if(pup->popup) { 02245 uiBlockSetFlag(block, UI_BLOCK_LOOP|UI_BLOCK_REDRAW|UI_BLOCK_NUMSELECT|UI_BLOCK_RET_1); 02246 uiBlockSetDirection(block, direction); 02247 02248 /* offset the mouse position, possibly based on earlier selection */ 02249 if((block->flag & UI_BLOCK_POPUP_MEMORY) && 02250 (bt= ui_popup_menu_memory(block, NULL))) { 02251 /* position mouse on last clicked item, at 0.8*width of the 02252 button, so it doesn't overlap the text too much, also note 02253 the offset is negative because we are inverse moving the 02254 block to be under the mouse */ 02255 offset[0]= -(bt->x1 + 0.8f*(bt->x2 - bt->x1)); 02256 offset[1]= -(bt->y1 + 0.5f*UI_UNIT_Y); 02257 } 02258 else { 02259 /* position mouse at 0.8*width of the button and below the tile 02260 on the first item */ 02261 offset[0]= 0; 02262 for(bt=block->buttons.first; bt; bt=bt->next) 02263 offset[0]= MIN2(offset[0], -(bt->x1 + 0.8f*(bt->x2 - bt->x1))); 02264 02265 offset[1]= 1.5*UI_UNIT_Y; 02266 } 02267 02268 block->minbounds= minwidth; 02269 uiMenuPopupBoundsBlock(block, 1, offset[0], offset[1]); 02270 } 02271 else { 02272 /* for a header menu we set the direction automatic */ 02273 if(!pup->slideout && flip) { 02274 sa= CTX_wm_area(C); 02275 ar= CTX_wm_region(C); 02276 02277 if(sa && sa->headertype==HEADERDOWN) { 02278 if(ar && ar->regiontype == RGN_TYPE_HEADER) { 02279 uiBlockSetDirection(block, UI_TOP); 02280 uiBlockFlipOrder(block); 02281 } 02282 } 02283 } 02284 02285 block->minbounds= minwidth; 02286 uiTextBoundsBlock(block, 50); 02287 } 02288 02289 /* if menu slides out of other menu, override direction */ 02290 if(pup->slideout) 02291 uiBlockSetDirection(block, UI_RIGHT); 02292 02293 uiEndBlock(C, block); 02294 02295 return pup->block; 02296 } 02297 02298 uiPopupBlockHandle *ui_popup_menu_create(bContext *C, ARegion *butregion, uiBut *but, uiMenuCreateFunc menu_func, void *arg, char *str) 02299 { 02300 wmWindow *window= CTX_wm_window(C); 02301 uiStyle *style= U.uistyles.first; 02302 uiPopupBlockHandle *handle; 02303 uiPopupMenu *pup; 02304 02305 pup= MEM_callocN(sizeof(uiPopupMenu), "menu dummy"); 02306 pup->block= uiBeginBlock(C, NULL, "ui_button_menu_create", UI_EMBOSSP); 02307 pup->layout= uiBlockLayout(pup->block, UI_LAYOUT_VERTICAL, UI_LAYOUT_MENU, 0, 0, 200, 0, style); 02308 pup->slideout= (but && (but->block->flag & UI_BLOCK_LOOP)); 02309 pup->but= but; 02310 uiLayoutSetOperatorContext(pup->layout, WM_OP_INVOKE_REGION_WIN); 02311 02312 if(!but) { 02313 /* no button to start from, means we are a popup */ 02314 pup->mx= window->eventstate->x; 02315 pup->my= window->eventstate->y; 02316 pup->popup= 1; 02317 pup->block->flag |= UI_BLOCK_NO_FLIP; 02318 } 02319 02320 if(str) { 02321 /* menu is created from a string */ 02322 pup->menu_func= ui_block_func_MENUSTR; 02323 pup->menu_arg= str; 02324 } 02325 else { 02326 /* menu is created from a callback */ 02327 pup->menu_func= menu_func; 02328 pup->menu_arg= arg; 02329 } 02330 02331 handle= ui_popup_block_create(C, butregion, but, NULL, ui_block_func_POPUP, pup); 02332 02333 if(!but) { 02334 handle->popup= 1; 02335 02336 UI_add_popup_handlers(C, &window->modalhandlers, handle); 02337 WM_event_add_mousemove(C); 02338 } 02339 02340 MEM_freeN(pup); 02341 02342 return handle; 02343 } 02344 02345 /******************** Popup Menu API with begin and end ***********************/ 02346 02347 /* only return handler, and set optional title */ 02348 uiPopupMenu *uiPupMenuBegin(bContext *C, const char *title, int icon) 02349 { 02350 uiStyle *style= U.uistyles.first; 02351 uiPopupMenu *pup= MEM_callocN(sizeof(uiPopupMenu), "popup menu"); 02352 uiBut *but; 02353 02354 pup->block= uiBeginBlock(C, NULL, "uiPupMenuBegin", UI_EMBOSSP); 02355 pup->block->flag |= UI_BLOCK_POPUP_MEMORY; 02356 pup->block->puphash= ui_popup_menu_hash((char*)title); 02357 pup->layout= uiBlockLayout(pup->block, UI_LAYOUT_VERTICAL, UI_LAYOUT_MENU, 0, 0, 200, 0, style); 02358 uiLayoutSetOperatorContext(pup->layout, WM_OP_EXEC_REGION_WIN); 02359 02360 /* create in advance so we can let buttons point to retval already */ 02361 pup->block->handle= MEM_callocN(sizeof(uiPopupBlockHandle), "uiPopupBlockHandle"); 02362 02363 /* create title button */ 02364 if(title && title[0]) { 02365 char titlestr[256]; 02366 02367 if(icon) { 02368 sprintf(titlestr, " %s", title); 02369 uiDefIconTextBut(pup->block, LABEL, 0, icon, titlestr, 0, 0, 200, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, ""); 02370 } 02371 else { 02372 but= uiDefBut(pup->block, LABEL, 0, title, 0, 0, 200, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, ""); 02373 but->flag= UI_TEXT_LEFT; 02374 } 02375 } 02376 02377 return pup; 02378 } 02379 02380 /* set the whole structure to work */ 02381 void uiPupMenuEnd(bContext *C, uiPopupMenu *pup) 02382 { 02383 wmWindow *window= CTX_wm_window(C); 02384 uiPopupBlockHandle *menu; 02385 02386 pup->popup= 1; 02387 pup->mx= window->eventstate->x; 02388 pup->my= window->eventstate->y; 02389 02390 menu= ui_popup_block_create(C, NULL, NULL, NULL, ui_block_func_POPUP, pup); 02391 menu->popup= 1; 02392 02393 UI_add_popup_handlers(C, &window->modalhandlers, menu); 02394 WM_event_add_mousemove(C); 02395 02396 MEM_freeN(pup); 02397 } 02398 02399 uiLayout *uiPupMenuLayout(uiPopupMenu *pup) 02400 { 02401 return pup->layout; 02402 } 02403 02404 /*************************** Standard Popup Menus ****************************/ 02405 02406 static void operator_name_cb(bContext *C, void *arg, int retval) 02407 { 02408 const char *opname= arg; 02409 02410 if(opname && retval > 0) 02411 WM_operator_name_call(C, opname, WM_OP_EXEC_DEFAULT, NULL); 02412 } 02413 02414 static void operator_cb(bContext *C, void *arg, int retval) 02415 { 02416 wmOperator *op= arg; 02417 02418 if(op && retval > 0) 02419 WM_operator_call(C, op); 02420 else 02421 WM_operator_free(op); 02422 } 02423 02424 static void confirm_cancel_operator(void *opv) 02425 { 02426 WM_operator_free(opv); 02427 } 02428 02429 static void vconfirm_opname(bContext *C, const char *opname, const char *title, const char *itemfmt, va_list ap) 02430 { 02431 uiPopupBlockHandle *handle; 02432 char *s, buf[512]; 02433 02434 s= buf; 02435 if (title) s+= sprintf(s, "%s%%t|", title); 02436 vsnprintf(s, sizeof(buf) - (s - buf), itemfmt, ap); 02437 buf[sizeof(buf) - 1]= '\0'; 02438 02439 handle= ui_popup_menu_create(C, NULL, NULL, NULL, NULL, buf); 02440 02441 handle->popup_func= operator_name_cb; 02442 handle->popup_arg= (void *)opname; 02443 } 02444 02445 static void confirm_operator(bContext *C, wmOperator *op, const char *title, const char *item) 02446 { 02447 uiPopupBlockHandle *handle; 02448 char *s, buf[512]; 02449 02450 s= buf; 02451 if (title) s+= sprintf(s, "%s%%t|%s", title, item); 02452 (void)s; 02453 02454 handle= ui_popup_menu_create(C, NULL, NULL, NULL, NULL, buf); 02455 02456 handle->popup_func= operator_cb; 02457 handle->popup_arg= op; 02458 handle->cancel_func= confirm_cancel_operator; 02459 } 02460 02461 void uiPupMenuOkee(bContext *C, const char *opname, const char *str, ...) 02462 { 02463 va_list ap; 02464 char titlestr[256]; 02465 02466 sprintf(titlestr, "OK? %%i%d", ICON_QUESTION); 02467 02468 va_start(ap, str); 02469 vconfirm_opname(C, opname, titlestr, str, ap); 02470 va_end(ap); 02471 } 02472 02473 void uiPupMenuSaveOver(bContext *C, wmOperator *op, const char *filename) 02474 { 02475 size_t len= strlen(filename); 02476 02477 if(len==0) 02478 return; 02479 02480 if(filename[len-1]=='/' || filename[len-1]=='\\') { 02481 uiPupMenuError(C, "Cannot overwrite a directory"); 02482 WM_operator_free(op); 02483 return; 02484 } 02485 if(BLI_exists(filename)==0) 02486 operator_cb(C, op, 1); 02487 else 02488 confirm_operator(C, op, "Save Over", filename); 02489 } 02490 02491 void uiPupMenuNotice(bContext *C, const char *str, ...) 02492 { 02493 va_list ap; 02494 02495 va_start(ap, str); 02496 vconfirm_opname(C, NULL, NULL, str, ap); 02497 va_end(ap); 02498 } 02499 02500 void uiPupMenuError(bContext *C, const char *str, ...) 02501 { 02502 va_list ap; 02503 char nfmt[256]; 02504 char titlestr[256]; 02505 02506 sprintf(titlestr, "Error %%i%d", ICON_ERROR); 02507 02508 sprintf(nfmt, "%s", str); 02509 02510 va_start(ap, str); 02511 vconfirm_opname(C, NULL, titlestr, nfmt, ap); 02512 va_end(ap); 02513 } 02514 02515 void uiPupMenuReports(bContext *C, ReportList *reports) 02516 { 02517 Report *report; 02518 DynStr *ds; 02519 char *str; 02520 02521 if(!reports || !reports->list.first) 02522 return; 02523 if(!CTX_wm_window(C)) 02524 return; 02525 02526 ds= BLI_dynstr_new(); 02527 02528 for(report=reports->list.first; report; report=report->next) { 02529 if(report->type < reports->printlevel) 02530 ; /* pass */ 02531 else if(report->type >= RPT_ERROR) 02532 BLI_dynstr_appendf(ds, "Error %%i%d%%t|%s", ICON_ERROR, report->message); 02533 else if(report->type >= RPT_WARNING) 02534 BLI_dynstr_appendf(ds, "Warning %%i%d%%t|%s", ICON_ERROR, report->message); 02535 else if(report->type >= RPT_INFO) 02536 BLI_dynstr_appendf(ds, "Info %%i%d%%t|%s", ICON_INFO, report->message); 02537 } 02538 02539 str= BLI_dynstr_get_cstring(ds); 02540 if(str[0] != '\0') 02541 ui_popup_menu_create(C, NULL, NULL, NULL, NULL, str); 02542 MEM_freeN(str); 02543 02544 BLI_dynstr_free(ds); 02545 } 02546 02547 void uiPupMenuInvoke(bContext *C, const char *idname) 02548 { 02549 uiPopupMenu *pup; 02550 uiLayout *layout; 02551 Menu menu; 02552 MenuType *mt= WM_menutype_find(idname, TRUE); 02553 02554 if(mt==NULL) { 02555 printf("uiPupMenuInvoke: named menu \"%s\" not found\n", idname); 02556 return; 02557 } 02558 02559 if(mt->poll && mt->poll(C, mt)==0) 02560 return; 02561 02562 pup= uiPupMenuBegin(C, mt->label, ICON_NONE); 02563 layout= uiPupMenuLayout(pup); 02564 02565 menu.layout= layout; 02566 menu.type= mt; 02567 02568 mt->draw(C, &menu); 02569 02570 uiPupMenuEnd(C, pup); 02571 } 02572 02573 02574 /*************************** Popup Block API **************************/ 02575 02576 void uiPupBlockO(bContext *C, uiBlockCreateFunc func, void *arg, const char *opname, int opcontext) 02577 { 02578 wmWindow *window= CTX_wm_window(C); 02579 uiPopupBlockHandle *handle; 02580 02581 handle= ui_popup_block_create(C, NULL, NULL, func, NULL, arg); 02582 handle->popup= 1; 02583 handle->optype= (opname)? WM_operatortype_find(opname, 0): NULL; 02584 handle->opcontext= opcontext; 02585 02586 UI_add_popup_handlers(C, &window->modalhandlers, handle); 02587 WM_event_add_mousemove(C); 02588 } 02589 02590 void uiPupBlock(bContext *C, uiBlockCreateFunc func, void *arg) 02591 { 02592 uiPupBlockO(C, func, arg, NULL, 0); 02593 } 02594 02595 void uiPupBlockEx(bContext *C, uiBlockCreateFunc func, uiBlockCancelFunc cancel_func, void *arg) 02596 { 02597 wmWindow *window= CTX_wm_window(C); 02598 uiPopupBlockHandle *handle; 02599 02600 handle= ui_popup_block_create(C, NULL, NULL, func, NULL, arg); 02601 handle->popup= 1; 02602 handle->retvalue= 1; 02603 02604 handle->popup_arg= arg; 02605 // handle->popup_func= operator_cb; 02606 handle->cancel_func= cancel_func; 02607 // handle->opcontext= opcontext; 02608 02609 UI_add_popup_handlers(C, &window->modalhandlers, handle); 02610 WM_event_add_mousemove(C); 02611 } 02612 02613 #if 0 /* UNUSED */ 02614 void uiPupBlockOperator(bContext *C, uiBlockCreateFunc func, wmOperator *op, int opcontext) 02615 { 02616 wmWindow *window= CTX_wm_window(C); 02617 uiPopupBlockHandle *handle; 02618 02619 handle= ui_popup_block_create(C, NULL, NULL, func, NULL, op); 02620 handle->popup= 1; 02621 handle->retvalue= 1; 02622 02623 handle->popup_arg= op; 02624 handle->popup_func= operator_cb; 02625 handle->cancel_func= confirm_cancel_operator; 02626 handle->opcontext= opcontext; 02627 02628 UI_add_popup_handlers(C, &window->modalhandlers, handle); 02629 WM_event_add_mousemove(C); 02630 } 02631 #endif 02632 02633 void uiPupBlockClose(bContext *C, uiBlock *block) 02634 { 02635 if(block->handle) { 02636 UI_remove_popup_handlers(&CTX_wm_window(C)->modalhandlers, block->handle); 02637 ui_popup_block_free(C, block->handle); 02638 } 02639 } 02640 02641 float *ui_block_hsv_get(uiBlock *block) 02642 { 02643 return block->_hsv; 02644 }