|
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 00031 #include <float.h> 00032 #include <limits.h> 00033 #include <math.h> 00034 #include <stdlib.h> 00035 #include <string.h> 00036 #include <ctype.h> 00037 #include <assert.h> 00038 00039 #include "MEM_guardedalloc.h" 00040 00041 #include "DNA_sensor_types.h" 00042 #include "DNA_controller_types.h" 00043 #include "DNA_actuator_types.h" 00044 00045 #include "DNA_object_types.h" 00046 #include "DNA_scene_types.h" 00047 00048 #include "BLI_math.h" 00049 #include "BLI_blenlib.h" 00050 #include "BLI_utildefines.h" 00051 00052 #include "PIL_time.h" 00053 00054 #include "BKE_colortools.h" 00055 #include "BKE_context.h" 00056 #include "BKE_idprop.h" 00057 #include "BKE_report.h" 00058 #include "BKE_texture.h" 00059 #include "BKE_unit.h" 00060 00061 #include "ED_screen.h" 00062 #include "ED_util.h" 00063 #include "ED_keyframing.h" 00064 00065 #include "UI_interface.h" 00066 00067 #include "BLF_api.h" 00068 00069 #include "interface_intern.h" 00070 00071 #include "RNA_access.h" 00072 00073 #include "WM_api.h" 00074 #include "WM_types.h" 00075 00076 /* proto */ 00077 static void ui_add_smart_controller(bContext *C, uiBut *from, uiBut *to); 00078 static void ui_add_link(bContext *C, uiBut *from, uiBut *to); 00079 00080 /***************** structs and defines ****************/ 00081 00082 #define BUTTON_TOOLTIP_DELAY 0.500 00083 #define BUTTON_FLASH_DELAY 0.020 00084 #define MENU_SCROLL_INTERVAL 0.1 00085 #define BUTTON_AUTO_OPEN_THRESH 0.3 00086 #define BUTTON_MOUSE_TOWARDS_THRESH 1.0 00087 00088 typedef enum uiButtonActivateType { 00089 BUTTON_ACTIVATE_OVER, 00090 BUTTON_ACTIVATE, 00091 BUTTON_ACTIVATE_APPLY, 00092 BUTTON_ACTIVATE_TEXT_EDITING, 00093 BUTTON_ACTIVATE_OPEN 00094 } uiButtonActivateType; 00095 00096 typedef enum uiHandleButtonState { 00097 BUTTON_STATE_INIT, 00098 BUTTON_STATE_HIGHLIGHT, 00099 BUTTON_STATE_WAIT_FLASH, 00100 BUTTON_STATE_WAIT_RELEASE, 00101 BUTTON_STATE_WAIT_KEY_EVENT, 00102 BUTTON_STATE_NUM_EDITING, 00103 BUTTON_STATE_TEXT_EDITING, 00104 BUTTON_STATE_TEXT_SELECTING, 00105 BUTTON_STATE_MENU_OPEN, 00106 BUTTON_STATE_WAIT_DRAG, 00107 BUTTON_STATE_EXIT 00108 } uiHandleButtonState; 00109 00110 typedef struct uiHandleButtonData { 00111 wmWindowManager *wm; 00112 wmWindow *window; 00113 ARegion *region; 00114 00115 int interactive; 00116 00117 /* overall state */ 00118 uiHandleButtonState state; 00119 int cancel, escapecancel, retval; 00120 int applied, appliedinteractive; 00121 wmTimer *flashtimer; 00122 00123 /* edited value */ 00124 char *str, *origstr; 00125 double value, origvalue, startvalue; 00126 float vec[3], origvec[3]; 00127 int togdual, togonly; 00128 ColorBand *coba; 00129 00130 /* tooltip */ 00131 ARegion *tooltip; 00132 wmTimer *tooltiptimer; 00133 00134 /* auto open */ 00135 int used_mouse; 00136 wmTimer *autoopentimer; 00137 00138 /* text selection/editing */ 00139 int maxlen, selextend, selstartx; 00140 00141 /* number editing / dragging */ 00142 int draglastx, draglasty; 00143 int dragstartx, dragstarty; 00144 int dragchange, draglock, dragsel; 00145 float dragf, dragfstart; 00146 CBData *dragcbd; 00147 00148 /* menu open (watch uiFreeActiveButtons) */ 00149 uiPopupBlockHandle *menu; 00150 int menuretval; 00151 00152 /* search box (watch uiFreeActiveButtons) */ 00153 ARegion *searchbox; 00154 00155 /* post activate */ 00156 uiButtonActivateType posttype; 00157 uiBut *postbut; 00158 } uiHandleButtonData; 00159 00160 typedef struct uiAfterFunc { 00161 struct uiAfterFunc *next, *prev; 00162 00163 uiButHandleFunc func; 00164 void *func_arg1; 00165 void *func_arg2; 00166 void *func_arg3; 00167 00168 uiButHandleNFunc funcN; 00169 void *func_argN; 00170 00171 uiButHandleRenameFunc rename_func; 00172 void *rename_arg1; 00173 void *rename_orig; 00174 00175 uiBlockHandleFunc handle_func; 00176 void *handle_func_arg; 00177 int retval; 00178 00179 uiMenuHandleFunc butm_func; 00180 void *butm_func_arg; 00181 int a2; 00182 00183 wmOperatorType *optype; 00184 int opcontext; 00185 PointerRNA *opptr; 00186 00187 PointerRNA rnapoin; 00188 PropertyRNA *rnaprop; 00189 00190 bContextStore *context; 00191 00192 char undostr[512]; 00193 00194 int autokey; 00195 } uiAfterFunc; 00196 00197 static int ui_but_contains_pt(uiBut *but, int mx, int my); 00198 static int ui_mouse_inside_button(ARegion *ar, uiBut *but, int x, int y); 00199 static void button_activate_state(bContext *C, uiBut *but, uiHandleButtonState state); 00200 static int ui_handler_region_menu(bContext *C, wmEvent *event, void *userdata); 00201 static void ui_handle_button_activate(bContext *C, ARegion *ar, uiBut *but, uiButtonActivateType type); 00202 static void button_timers_tooltip_remove(bContext *C, uiBut *but); 00203 00204 /* ******************** menu navigation helpers ************** */ 00205 00206 static int ui_but_editable(uiBut *but) 00207 { 00208 return ELEM5(but->type, LABEL, SEPR, ROUNDBOX, LISTBOX, PROGRESSBAR); 00209 } 00210 00211 static uiBut *ui_but_prev(uiBut *but) 00212 { 00213 while(but->prev) { 00214 but= but->prev; 00215 if(!ui_but_editable(but)) return but; 00216 } 00217 return NULL; 00218 } 00219 00220 static uiBut *ui_but_next(uiBut *but) 00221 { 00222 while(but->next) { 00223 but= but->next; 00224 if(!ui_but_editable(but)) return but; 00225 } 00226 return NULL; 00227 } 00228 00229 static uiBut *ui_but_first(uiBlock *block) 00230 { 00231 uiBut *but; 00232 00233 but= block->buttons.first; 00234 while(but) { 00235 if(!ui_but_editable(but)) return but; 00236 but= but->next; 00237 } 00238 return NULL; 00239 } 00240 00241 static uiBut *ui_but_last(uiBlock *block) 00242 { 00243 uiBut *but; 00244 00245 but= block->buttons.last; 00246 while(but) { 00247 if(!ui_but_editable(but)) return but; 00248 but= but->prev; 00249 } 00250 return NULL; 00251 } 00252 00253 static int ui_is_a_warp_but(uiBut *but) 00254 { 00255 if(U.uiflag & USER_CONTINUOUS_MOUSE) 00256 if(ELEM3(but->type, NUM, NUMABS, HSVCIRCLE)) 00257 return TRUE; 00258 00259 return FALSE; 00260 } 00261 00262 /* file selectors are exempt from utf-8 checks */ 00263 static int ui_is_utf8_but(uiBut *but) 00264 { 00265 if (but->rnaprop) { 00266 const int subtype= RNA_property_subtype(but->rnaprop); 00267 return !(ELEM3(subtype, PROP_FILEPATH, PROP_DIRPATH, PROP_FILENAME)); 00268 } 00269 else { 00270 return !(but->flag & UI_BUT_NO_UTF8); 00271 } 00272 } 00273 00274 /* ********************** button apply/revert ************************/ 00275 00276 static ListBase UIAfterFuncs = {NULL, NULL}; 00277 00278 static void ui_apply_but_func(bContext *C, uiBut *but) 00279 { 00280 uiAfterFunc *after; 00281 uiBlock *block= but->block; 00282 00283 /* these functions are postponed and only executed after all other 00284 * handling is done, i.e. menus are closed, in order to avoid conflicts 00285 * with these functions removing the buttons we are working with */ 00286 00287 if(but->func || but->funcN || block->handle_func || but->rename_func || (but->type == BUTM && block->butm_func) || but->optype || but->rnaprop) { 00288 after= MEM_callocN(sizeof(uiAfterFunc), "uiAfterFunc"); 00289 00290 if(but->func && ELEM(but, but->func_arg1, but->func_arg2)) { 00291 /* exception, this will crash due to removed button otherwise */ 00292 but->func(C, but->func_arg1, but->func_arg2); 00293 } 00294 else 00295 after->func= but->func; 00296 00297 after->func_arg1= but->func_arg1; 00298 after->func_arg2= but->func_arg2; 00299 after->func_arg3= but->func_arg3; 00300 00301 after->funcN= but->funcN; 00302 after->func_argN= MEM_dupallocN(but->func_argN); 00303 00304 after->rename_func= but->rename_func; 00305 after->rename_arg1= but->rename_arg1; 00306 after->rename_orig= but->rename_orig; /* needs free! */ 00307 00308 after->handle_func= block->handle_func; 00309 after->handle_func_arg= block->handle_func_arg; 00310 after->retval= but->retval; 00311 00312 if(but->type == BUTM) { 00313 after->butm_func= block->butm_func; 00314 after->butm_func_arg= block->butm_func_arg; 00315 after->a2= but->a2; 00316 } 00317 00318 after->optype= but->optype; 00319 after->opcontext= but->opcontext; 00320 after->opptr= but->opptr; 00321 00322 after->rnapoin= but->rnapoin; 00323 after->rnaprop= but->rnaprop; 00324 00325 if(but->context) 00326 after->context= CTX_store_copy(but->context); 00327 00328 but->optype= NULL; 00329 but->opcontext= 0; 00330 but->opptr= NULL; 00331 00332 BLI_addtail(&UIAfterFuncs, after); 00333 } 00334 } 00335 00336 static void ui_apply_autokey_undo(bContext *C, uiBut *but) 00337 { 00338 Scene *scene= CTX_data_scene(C); 00339 uiAfterFunc *after; 00340 00341 if(but->flag & UI_BUT_UNDO) { 00342 const char *str= NULL; 00343 00344 /* define which string to use for undo */ 00345 if ELEM(but->type, LINK, INLINK) str= "Add button link"; 00346 else if ELEM(but->type, MENU, ICONTEXTROW) str= but->drawstr; 00347 else if(but->drawstr[0]) str= but->drawstr; 00348 else str= but->tip; 00349 00350 /* fallback, else we dont get an undo! */ 00351 if(str == NULL || str[0] == '\0') { 00352 str= "Unknown Action"; 00353 } 00354 00355 /* delayed, after all other funcs run, popups are closed, etc */ 00356 after= MEM_callocN(sizeof(uiAfterFunc), "uiAfterFunc"); 00357 BLI_strncpy(after->undostr, str, sizeof(after->undostr)); 00358 BLI_addtail(&UIAfterFuncs, after); 00359 } 00360 00361 /* try autokey */ 00362 ui_but_anim_autokey(C, but, scene, scene->r.cfra); 00363 } 00364 00365 static void ui_apply_but_funcs_after(bContext *C) 00366 { 00367 uiAfterFunc *afterf, after; 00368 PointerRNA opptr; 00369 ListBase funcs; 00370 00371 /* copy to avoid recursive calls */ 00372 funcs= UIAfterFuncs; 00373 UIAfterFuncs.first= UIAfterFuncs.last= NULL; 00374 00375 for(afterf=funcs.first; afterf; afterf=after.next) { 00376 after= *afterf; /* copy to avoid memleak on exit() */ 00377 BLI_freelinkN(&funcs, afterf); 00378 00379 if(after.context) 00380 CTX_store_set(C, after.context); 00381 00382 if(after.opptr) { 00383 /* free in advance to avoid leak on exit */ 00384 opptr= *after.opptr, 00385 MEM_freeN(after.opptr); 00386 } 00387 00388 if(after.optype) 00389 WM_operator_name_call(C, after.optype->idname, after.opcontext, (after.opptr)? &opptr: NULL); 00390 00391 if(after.opptr) 00392 WM_operator_properties_free(&opptr); 00393 00394 if(after.rnapoin.data) 00395 RNA_property_update(C, &after.rnapoin, after.rnaprop); 00396 00397 if(after.context) { 00398 CTX_store_set(C, NULL); 00399 CTX_store_free(after.context); 00400 } 00401 00402 if(after.func) 00403 after.func(C, after.func_arg1, after.func_arg2); 00404 if(after.funcN) 00405 after.funcN(C, after.func_argN, after.func_arg2); 00406 if(after.func_argN) 00407 MEM_freeN(after.func_argN); 00408 00409 if(after.handle_func) 00410 after.handle_func(C, after.handle_func_arg, after.retval); 00411 if(after.butm_func) 00412 after.butm_func(C, after.butm_func_arg, after.a2); 00413 00414 if(after.rename_func) 00415 after.rename_func(C, after.rename_arg1, after.rename_orig); 00416 if(after.rename_orig) 00417 MEM_freeN(after.rename_orig); 00418 00419 if(after.undostr[0]) 00420 ED_undo_push(C, after.undostr); 00421 } 00422 } 00423 00424 static void ui_apply_but_BUT(bContext *C, uiBut *but, uiHandleButtonData *data) 00425 { 00426 ui_apply_but_func(C, but); 00427 00428 data->retval= but->retval; 00429 data->applied= 1; 00430 } 00431 00432 static void ui_apply_but_BUTM(bContext *C, uiBut *but, uiHandleButtonData *data) 00433 { 00434 ui_set_but_val(but, but->hardmin); 00435 ui_apply_but_func(C, but); 00436 00437 data->retval= but->retval; 00438 data->applied= 1; 00439 } 00440 00441 static void ui_apply_but_BLOCK(bContext *C, uiBut *but, uiHandleButtonData *data) 00442 { 00443 if(ELEM3(but->type, MENU, ICONROW, ICONTEXTROW)) 00444 ui_set_but_val(but, data->value); 00445 00446 ui_check_but(but); 00447 ui_apply_but_func(C, but); 00448 data->retval= but->retval; 00449 data->applied= 1; 00450 } 00451 00452 static void ui_apply_but_TOG(bContext *C, uiBut *but, uiHandleButtonData *data) 00453 { 00454 double value; 00455 int w, lvalue, push; 00456 00457 /* local hack... */ 00458 if(but->type==BUT_TOGDUAL && data->togdual) { 00459 if(but->pointype==SHO) 00460 but->poin += 2; 00461 else if(but->pointype==INT) 00462 but->poin += 4; 00463 } 00464 00465 value= ui_get_but_val(but); 00466 lvalue= (int)value; 00467 00468 if(but->bit) { 00469 w= BTST(lvalue, but->bitnr); 00470 if(w) lvalue = BCLR(lvalue, but->bitnr); 00471 else lvalue = BSET(lvalue, but->bitnr); 00472 00473 if(but->type==TOGR) { 00474 if(!data->togonly) { 00475 lvalue= 1<<(but->bitnr); 00476 00477 ui_set_but_val(but, (double)lvalue); 00478 } 00479 else { 00480 if(lvalue==0) lvalue= 1<<(but->bitnr); 00481 } 00482 } 00483 00484 ui_set_but_val(but, (double)lvalue); 00485 if(but->type==ICONTOG || but->type==ICONTOGN) ui_check_but(but); 00486 } 00487 else { 00488 00489 if(value==0.0) push= 1; 00490 else push= 0; 00491 00492 if(ELEM3(but->type, TOGN, ICONTOGN, OPTIONN)) push= !push; 00493 ui_set_but_val(but, (double)push); 00494 if(but->type==ICONTOG || but->type==ICONTOGN) ui_check_but(but); 00495 } 00496 00497 /* end local hack... */ 00498 if(but->type==BUT_TOGDUAL && data->togdual) { 00499 if(but->pointype==SHO) 00500 but->poin -= 2; 00501 else if(but->pointype==INT) 00502 but->poin -= 4; 00503 } 00504 00505 ui_apply_but_func(C, but); 00506 00507 data->retval= but->retval; 00508 data->applied= 1; 00509 } 00510 00511 static void ui_apply_but_ROW(bContext *C, uiBlock *block, uiBut *but, uiHandleButtonData *data) 00512 { 00513 uiBut *bt; 00514 00515 ui_set_but_val(but, but->hardmax); 00516 00517 /* states of other row buttons */ 00518 for(bt= block->buttons.first; bt; bt= bt->next) 00519 if(bt!=but && bt->poin==but->poin && ELEM(bt->type, ROW, LISTROW)) 00520 ui_check_but(bt); 00521 00522 ui_apply_but_func(C, but); 00523 00524 data->retval= but->retval; 00525 data->applied= 1; 00526 } 00527 00528 static void ui_apply_but_TEX(bContext *C, uiBut *but, uiHandleButtonData *data) 00529 { 00530 if(!data->str) 00531 return; 00532 00533 ui_set_but_string(C, but, data->str); 00534 ui_check_but(but); 00535 00536 /* give butfunc the original text too */ 00537 /* feature used for bone renaming, channels, etc */ 00538 /* afterfunc frees origstr */ 00539 but->rename_orig= data->origstr; 00540 data->origstr= NULL; 00541 ui_apply_but_func(C, but); 00542 00543 data->retval= but->retval; 00544 data->applied= 1; 00545 } 00546 00547 static void ui_apply_but_NUM(bContext *C, uiBut *but, uiHandleButtonData *data) 00548 { 00549 if(data->str) { 00550 if(ui_set_but_string(C, but, data->str)) { 00551 data->value= ui_get_but_val(but); 00552 } 00553 else { 00554 data->cancel= 1; 00555 return; 00556 } 00557 } 00558 else 00559 ui_set_but_val(but, data->value); 00560 00561 ui_check_but(but); 00562 ui_apply_but_func(C, but); 00563 00564 data->retval= but->retval; 00565 data->applied= 1; 00566 } 00567 00568 static void ui_apply_but_TOG3(bContext *C, uiBut *but, uiHandleButtonData *data) 00569 { 00570 if(but->pointype==SHO ) { 00571 short *sp= (short *)but->poin; 00572 00573 if( BTST(sp[1], but->bitnr)) { 00574 sp[1]= BCLR(sp[1], but->bitnr); 00575 sp[0]= BCLR(sp[0], but->bitnr); 00576 } 00577 else if( BTST(sp[0], but->bitnr)) { 00578 sp[1]= BSET(sp[1], but->bitnr); 00579 } else { 00580 sp[0]= BSET(sp[0], but->bitnr); 00581 } 00582 } 00583 else { 00584 if( BTST(*(but->poin+2), but->bitnr)) { 00585 *(but->poin+2)= BCLR(*(but->poin+2), but->bitnr); 00586 *(but->poin)= BCLR(*(but->poin), but->bitnr); 00587 } 00588 else if( BTST(*(but->poin), but->bitnr)) { 00589 *(but->poin+2)= BSET(*(but->poin+2), but->bitnr); 00590 } else { 00591 *(but->poin)= BSET(*(but->poin), but->bitnr); 00592 } 00593 } 00594 00595 ui_check_but(but); 00596 ui_apply_but_func(C, but); 00597 data->retval= but->retval; 00598 data->applied= 1; 00599 } 00600 00601 static void ui_apply_but_VEC(bContext *C, uiBut *but, uiHandleButtonData *data) 00602 { 00603 ui_set_but_vectorf(but, data->vec); 00604 ui_check_but(but); 00605 ui_apply_but_func(C, but); 00606 00607 data->retval= but->retval; 00608 data->applied= 1; 00609 } 00610 00611 static void ui_apply_but_COLORBAND(bContext *C, uiBut *but, uiHandleButtonData *data) 00612 { 00613 ui_apply_but_func(C, but); 00614 data->retval= but->retval; 00615 data->applied= 1; 00616 } 00617 00618 static void ui_apply_but_CURVE(bContext *C, uiBut *but, uiHandleButtonData *data) 00619 { 00620 ui_apply_but_func(C, but); 00621 data->retval= but->retval; 00622 data->applied= 1; 00623 } 00624 00625 static void ui_apply_but_IDPOIN(bContext *C, uiBut *but, uiHandleButtonData *data) 00626 { 00627 ui_set_but_string(C, but, data->str); 00628 ui_check_but(but); 00629 ui_apply_but_func(C, but); 00630 data->retval= but->retval; 00631 data->applied= 1; 00632 } 00633 00634 #ifdef INTERNATIONAL 00635 static void ui_apply_but_CHARTAB(bContext *C, uiBut *but, uiHandleButtonData *data) 00636 { 00637 ui_apply_but_func(C, but); 00638 data->retval= but->retval; 00639 data->applied= 1; 00640 } 00641 #endif 00642 00643 /* ****************** drag drop code *********************** */ 00644 00645 static int ui_but_mouse_inside_icon(uiBut *but, ARegion *ar, wmEvent *event) 00646 { 00647 rcti rect; 00648 int x= event->x, y= event->y; 00649 00650 ui_window_to_block(ar, but->block, &x, &y); 00651 00652 rect.xmin= but->x1; rect.xmax= but->x2; 00653 rect.ymin= but->y1; rect.ymax= but->y2; 00654 00655 if(but->imb); /* use button size itself */ 00656 else if(but->flag & UI_ICON_LEFT) { 00657 rect.xmax= rect.xmin + (rect.ymax-rect.ymin); 00658 } 00659 else { 00660 int delta= (rect.xmax-rect.xmin) - (rect.ymax-rect.ymin); 00661 rect.xmin += delta/2; 00662 rect.xmax -= delta/2; 00663 } 00664 00665 return BLI_in_rcti(&rect, x, y); 00666 } 00667 00668 static int ui_but_start_drag(bContext *C, uiBut *but, uiHandleButtonData *data, wmEvent *event) 00669 { 00670 /* prevent other WM gestures to start while we try to drag */ 00671 WM_gestures_remove(C); 00672 00673 if( ABS(data->dragstartx - event->x) + ABS(data->dragstarty - event->y) > U.dragthreshold ) { 00674 wmDrag *drag; 00675 00676 button_activate_state(C, but, BUTTON_STATE_EXIT); 00677 data->cancel= 1; 00678 00679 drag= WM_event_start_drag(C, but->icon, but->dragtype, but->dragpoin, ui_get_but_val(but)); 00680 if(but->imb) 00681 WM_event_drag_image(drag, but->imb, but->imb_scale, but->x2-but->x1, but->y2-but->y1); 00682 return 1; 00683 } 00684 00685 return 0; 00686 } 00687 00688 /* ********************** linklines *********************** */ 00689 00690 static void ui_delete_active_linkline(uiBlock *block) 00691 { 00692 uiBut *but; 00693 uiLink *link; 00694 uiLinkLine *line, *nline; 00695 int a, b; 00696 00697 but= block->buttons.first; 00698 while(but) { 00699 if(but->type==LINK && but->link) { 00700 line= but->link->lines.first; 00701 while(line) { 00702 00703 nline= line->next; 00704 00705 if(line->flag & UI_SELECT) { 00706 BLI_remlink(&but->link->lines, line); 00707 00708 link= line->from->link; 00709 00710 /* are there more pointers allowed? */ 00711 if(link->ppoin) { 00712 00713 if(*(link->totlink)==1) { 00714 *(link->totlink)= 0; 00715 MEM_freeN(*(link->ppoin)); 00716 *(link->ppoin)= NULL; 00717 } 00718 else { 00719 b= 0; 00720 for(a=0; a< (*(link->totlink)); a++) { 00721 00722 if( (*(link->ppoin))[a] != line->to->poin ) { 00723 (*(link->ppoin))[b]= (*(link->ppoin))[a]; 00724 b++; 00725 } 00726 } 00727 (*(link->totlink))--; 00728 } 00729 } 00730 else { 00731 *(link->poin)= NULL; 00732 } 00733 00734 MEM_freeN(line); 00735 } 00736 line= nline; 00737 } 00738 } 00739 but= but->next; 00740 } 00741 } 00742 00743 00744 static uiLinkLine *ui_is_a_link(uiBut *from, uiBut *to) 00745 { 00746 uiLinkLine *line; 00747 uiLink *link; 00748 00749 link= from->link; 00750 if(link) { 00751 line= link->lines.first; 00752 while(line) { 00753 if(line->from==from && line->to==to) return line; 00754 line= line->next; 00755 } 00756 } 00757 return NULL; 00758 } 00759 00760 /* XXX BAD BAD HACK, fixme later **************** */ 00761 /* Try to add an AND Controller between the sensor and the actuator logic bricks and to connect them all */ 00762 static void ui_add_smart_controller(bContext *C, uiBut *from, uiBut *to) 00763 { 00764 Object *ob= NULL; 00765 bSensor *sens_iter; 00766 bActuator *act_to, *act_iter; 00767 bController *cont; 00768 bController ***sens_from_links; 00769 uiBut *tmp_but; 00770 00771 uiLink *link= from->link; 00772 00773 if(link->ppoin) 00774 sens_from_links= (bController ***)(link->ppoin); 00775 else return; 00776 00777 act_to = (bActuator *)(to->poin); 00778 00779 /* (1) get the object */ 00780 CTX_DATA_BEGIN(C, Object*, ob_iter, selected_editable_objects) { 00781 for (sens_iter= ob_iter->sensors.first; sens_iter; sens_iter= sens_iter->next) 00782 { 00783 if (&(sens_iter->links) == sens_from_links) { 00784 ob= ob_iter; 00785 break; 00786 } 00787 } 00788 if (ob) break; 00789 } CTX_DATA_END; 00790 00791 if(!ob) return; 00792 00793 /* (2) check if the sensor and the actuator are from the same object */ 00794 for (act_iter= ob->actuators.first; act_iter; act_iter= (bActuator *)act_iter->next) { 00795 if (act_iter == act_to) 00796 break; 00797 } 00798 00799 // only works if the sensor and the actuator are from the same object 00800 if(!act_iter) return; 00801 00802 /* (3) add a new controller */ 00803 if (WM_operator_name_call(C, "LOGIC_OT_controller_add", WM_OP_EXEC_DEFAULT, NULL) & OPERATOR_FINISHED) 00804 { 00805 cont = (bController *)ob->controllers.last; 00806 00807 /* (4) link the sensor->controller->actuator */ 00808 tmp_but = MEM_callocN(sizeof(uiBut), "uiBut"); 00809 uiSetButLink(tmp_but, (void **)&cont, (void ***)&(cont->links), &(cont->totlinks), from->link->tocode, (int)to->hardmin); 00810 tmp_but->hardmin= from->link->tocode; 00811 tmp_but->poin= (char *)cont; 00812 00813 tmp_but->type= INLINK; 00814 ui_add_link(C, from, tmp_but); 00815 00816 tmp_but->type= LINK; 00817 ui_add_link(C, tmp_but, to); 00818 00819 /* (5) garbage collection */ 00820 MEM_freeN(tmp_but->link); 00821 MEM_freeN(tmp_but); 00822 } 00823 } 00824 00825 static void ui_add_link(bContext *C, uiBut *from, uiBut *to) 00826 { 00827 /* in 'from' we have to add a link to 'to' */ 00828 uiLink *link; 00829 uiLinkLine *line; 00830 void **oldppoin; 00831 int a; 00832 00833 if( (line= ui_is_a_link(from, to)) ) { 00834 line->flag |= UI_SELECT; 00835 ui_delete_active_linkline(from->block); 00836 return; 00837 } 00838 00839 if (from->type==INLINK && to->type==INLINK) { 00840 return; 00841 } 00842 else if (from->type==LINK && to->type==INLINK) { 00843 if( from->link->tocode != (int)to->hardmin ) { 00844 ui_add_smart_controller(C, from, to); 00845 return; 00846 } 00847 } 00848 else if(from->type==INLINK && to->type==LINK) { 00849 if( to->link->tocode == (int)from->hardmin ) { 00850 return; 00851 } 00852 } 00853 00854 link= from->link; 00855 00856 /* are there more pointers allowed? */ 00857 if(link->ppoin) { 00858 oldppoin= *(link->ppoin); 00859 00860 (*(link->totlink))++; 00861 *(link->ppoin)= MEM_callocN( *(link->totlink)*sizeof(void *), "new link"); 00862 00863 for(a=0; a< (*(link->totlink))-1; a++) { 00864 (*(link->ppoin))[a]= oldppoin[a]; 00865 } 00866 (*(link->ppoin))[a]= to->poin; 00867 00868 if(oldppoin) MEM_freeN(oldppoin); 00869 } 00870 else { 00871 *(link->poin)= to->poin; 00872 } 00873 00874 } 00875 00876 00877 static void ui_apply_but_LINK(bContext *C, uiBut *but, uiHandleButtonData *data) 00878 { 00879 ARegion *ar= CTX_wm_region(C); 00880 uiBut *bt; 00881 00882 for(bt= but->block->buttons.first; bt; bt= bt->next) { 00883 if( ui_mouse_inside_button(ar, bt, but->linkto[0]+ar->winrct.xmin, but->linkto[1]+ar->winrct.ymin) ) 00884 break; 00885 } 00886 if(bt && bt!=but) { 00887 if (!ELEM(bt->type, LINK, INLINK) || !ELEM(but->type, LINK, INLINK)) 00888 return; 00889 00890 if(but->type==LINK) ui_add_link(C, but, bt); 00891 else ui_add_link(C, bt, but); 00892 00893 ui_apply_but_func(C, but); 00894 data->retval= but->retval; 00895 } 00896 data->applied= 1; 00897 } 00898 00899 static void ui_apply_but_IMAGE(bContext *C, uiBut *but, uiHandleButtonData *data) 00900 { 00901 ui_apply_but_func(C, but); 00902 data->retval= but->retval; 00903 data->applied= 1; 00904 } 00905 00906 static void ui_apply_but_HISTOGRAM(bContext *C, uiBut *but, uiHandleButtonData *data) 00907 { 00908 ui_apply_but_func(C, but); 00909 data->retval= but->retval; 00910 data->applied= 1; 00911 } 00912 00913 static void ui_apply_but_WAVEFORM(bContext *C, uiBut *but, uiHandleButtonData *data) 00914 { 00915 ui_apply_but_func(C, but); 00916 data->retval= but->retval; 00917 data->applied= 1; 00918 } 00919 00920 00921 static void ui_apply_button(bContext *C, uiBlock *block, uiBut *but, uiHandleButtonData *data, int interactive) 00922 { 00923 char *editstr; 00924 double *editval; 00925 float *editvec; 00926 ColorBand *editcoba; 00927 CurveMapping *editcumap; 00928 00929 data->retval= 0; 00930 00931 /* if we cancel and have not applied yet, there is nothing to do, 00932 * otherwise we have to restore the original value again */ 00933 if(data->cancel) { 00934 if(!data->applied) 00935 return; 00936 00937 if(data->str) MEM_freeN(data->str); 00938 data->str= data->origstr; 00939 data->origstr= NULL; 00940 data->value= data->origvalue; 00941 data->origvalue= 0.0; 00942 VECCOPY(data->vec, data->origvec); 00943 data->origvec[0]= data->origvec[1]= data->origvec[2]= 0.0f; 00944 } 00945 else { 00946 /* we avoid applying interactive edits a second time 00947 * at the end with the appliedinteractive flag */ 00948 if(interactive) 00949 data->appliedinteractive= 1; 00950 else if(data->appliedinteractive) 00951 return; 00952 } 00953 00954 /* ensures we are writing actual values */ 00955 editstr= but->editstr; 00956 editval= but->editval; 00957 editvec= but->editvec; 00958 editcoba= but->editcoba; 00959 editcumap= but->editcumap; 00960 but->editstr= NULL; 00961 but->editval= NULL; 00962 but->editvec= NULL; 00963 but->editcoba= NULL; 00964 but->editcumap= NULL; 00965 00966 /* handle different types */ 00967 switch(but->type) { 00968 case BUT: 00969 ui_apply_but_BUT(C, but, data); 00970 break; 00971 case TEX: 00972 case SEARCH_MENU: 00973 ui_apply_but_TEX(C, but, data); 00974 break; 00975 case TOGBUT: 00976 case TOG: 00977 case TOGR: 00978 case ICONTOG: 00979 case ICONTOGN: 00980 case TOGN: 00981 case BUT_TOGDUAL: 00982 case OPTION: 00983 case OPTIONN: 00984 ui_apply_but_TOG(C, but, data); 00985 break; 00986 case ROW: 00987 case LISTROW: 00988 ui_apply_but_ROW(C, block, but, data); 00989 break; 00990 case SCROLL: 00991 case NUM: 00992 case NUMABS: 00993 case SLI: 00994 case NUMSLI: 00995 ui_apply_but_NUM(C, but, data); 00996 break; 00997 case HSVSLI: 00998 break; 00999 case TOG3: 01000 ui_apply_but_TOG3(C, but, data); 01001 break; 01002 case MENU: 01003 case ICONROW: 01004 case ICONTEXTROW: 01005 case BLOCK: 01006 case PULLDOWN: 01007 case COL: 01008 ui_apply_but_BLOCK(C, but, data); 01009 break; 01010 case BUTM: 01011 ui_apply_but_BUTM(C, but, data); 01012 break; 01013 case BUT_NORMAL: 01014 case HSVCUBE: 01015 case HSVCIRCLE: 01016 ui_apply_but_VEC(C, but, data); 01017 break; 01018 case BUT_COLORBAND: 01019 ui_apply_but_COLORBAND(C, but, data); 01020 break; 01021 case BUT_CURVE: 01022 ui_apply_but_CURVE(C, but, data); 01023 break; 01024 case IDPOIN: 01025 ui_apply_but_IDPOIN(C, but, data); 01026 break; 01027 #ifdef INTERNATIONAL 01028 case CHARTAB: 01029 ui_apply_but_CHARTAB(C, but, data); 01030 break; 01031 #endif 01032 case KEYEVT: 01033 case HOTKEYEVT: 01034 ui_apply_but_BUT(C, but, data); 01035 break; 01036 case LINK: 01037 case INLINK: 01038 ui_apply_but_LINK(C, but, data); 01039 break; 01040 case BUT_IMAGE: 01041 ui_apply_but_IMAGE(C, but, data); 01042 break; 01043 case HISTOGRAM: 01044 ui_apply_but_HISTOGRAM(C, but, data); 01045 break; 01046 case WAVEFORM: 01047 ui_apply_but_WAVEFORM(C, but, data); 01048 break; 01049 default: 01050 break; 01051 } 01052 01053 but->editstr= editstr; 01054 but->editval= editval; 01055 but->editvec= editvec; 01056 but->editcoba= editcoba; 01057 but->editcumap= editcumap; 01058 } 01059 01060 /* ******************* drop event ******************** */ 01061 01062 /* only call if event type is EVT_DROP */ 01063 static void ui_but_drop(bContext *C, wmEvent *event, uiBut *but, uiHandleButtonData *data) 01064 { 01065 wmDrag *wmd; 01066 ListBase *drags= event->customdata; /* drop event type has listbase customdata by default */ 01067 01068 for(wmd= drags->first; wmd; wmd= wmd->next) { 01069 if(wmd->type==WM_DRAG_ID) { 01070 /* align these types with UI_but_active_drop_name */ 01071 if(ELEM3(but->type, TEX, IDPOIN, SEARCH_MENU)) { 01072 ID *id= (ID *)wmd->poin; 01073 01074 if(but->poin==NULL && but->rnapoin.data==NULL) {} 01075 button_activate_state(C, but, BUTTON_STATE_TEXT_EDITING); 01076 BLI_strncpy(data->str, id->name+2, data->maxlen); 01077 button_activate_state(C, but, BUTTON_STATE_EXIT); 01078 } 01079 } 01080 } 01081 01082 } 01083 01084 /* ******************* copy and paste ******************** */ 01085 01086 /* c = copy, v = paste */ 01087 static void ui_but_copy_paste(bContext *C, uiBut *but, uiHandleButtonData *data, char mode) 01088 { 01089 static ColorBand but_copypaste_coba = {0}; 01090 char buf[UI_MAX_DRAW_STR+1]= {0}; 01091 double val; 01092 01093 if(mode=='v' && but->lock) 01094 return; 01095 01096 if(mode=='v') { 01097 /* extract first line from clipboard in case of multi-line copies */ 01098 char *p, *pbuf= WM_clipboard_text_get(0); 01099 p= pbuf; 01100 if(p) { 01101 int i = 0; 01102 while (*p && *p!='\r' && *p!='\n' && i<UI_MAX_DRAW_STR) { 01103 buf[i++]=*p; 01104 p++; 01105 } 01106 buf[i]= 0; 01107 MEM_freeN(pbuf); 01108 } 01109 } 01110 01111 /* numeric value */ 01112 if ELEM4(but->type, NUM, NUMABS, NUMSLI, HSVSLI) { 01113 01114 if(but->poin==NULL && but->rnapoin.data==NULL); 01115 else if(mode=='c') { 01116 if(ui_is_but_float(but)) 01117 sprintf(buf, "%f", ui_get_but_val(but)); 01118 else 01119 sprintf(buf, "%d", (int)ui_get_but_val(but)); 01120 01121 WM_clipboard_text_set(buf, 0); 01122 } 01123 else { 01124 if (sscanf(buf, " %lf ", &val) == 1) { 01125 button_activate_state(C, but, BUTTON_STATE_NUM_EDITING); 01126 data->value= val; 01127 button_activate_state(C, but, BUTTON_STATE_EXIT); 01128 } 01129 } 01130 } 01131 01132 /* RGB triple */ 01133 else if(but->type==COL) { 01134 float rgb[3]; 01135 01136 if(but->poin==NULL && but->rnapoin.data==NULL); 01137 else if(mode=='c') { 01138 01139 ui_get_but_vectorf(but, rgb); 01140 sprintf(buf, "[%f, %f, %f]", rgb[0], rgb[1], rgb[2]); 01141 WM_clipboard_text_set(buf, 0); 01142 01143 } 01144 else { 01145 if (sscanf(buf, "[%f, %f, %f]", &rgb[0], &rgb[1], &rgb[2]) == 3) { 01146 button_activate_state(C, but, BUTTON_STATE_NUM_EDITING); 01147 ui_set_but_vectorf(but, rgb); 01148 button_activate_state(C, but, BUTTON_STATE_EXIT); 01149 } 01150 } 01151 } 01152 01153 /* text/string and ID data */ 01154 else if(ELEM3(but->type, TEX, IDPOIN, SEARCH_MENU)) { 01155 uiHandleButtonData *active_data= but->active; 01156 01157 if(but->poin==NULL && but->rnapoin.data==NULL); 01158 else if(mode=='c') { 01159 button_activate_state(C, but, BUTTON_STATE_TEXT_EDITING); 01160 BLI_strncpy(buf, active_data->str, UI_MAX_DRAW_STR); 01161 WM_clipboard_text_set(active_data->str, 0); 01162 active_data->cancel= 1; 01163 button_activate_state(C, but, BUTTON_STATE_EXIT); 01164 } 01165 else { 01166 button_activate_state(C, but, BUTTON_STATE_TEXT_EDITING); 01167 BLI_strncpy(active_data->str, buf, active_data->maxlen); 01168 if(but->type == SEARCH_MENU) { 01169 /* else uiSearchboxData.active member is not updated [#26856] */ 01170 ui_searchbox_update(C, data->searchbox, but, 1); 01171 } 01172 button_activate_state(C, but, BUTTON_STATE_EXIT); 01173 } 01174 } 01175 /* colorband (not supported by system clipboard) */ 01176 else if(but->type==BUT_COLORBAND) { 01177 if(mode=='c') { 01178 if(but->poin==NULL) 01179 return; 01180 01181 memcpy(&but_copypaste_coba, but->poin, sizeof(ColorBand)); 01182 } 01183 else { 01184 if(but_copypaste_coba.tot==0) 01185 return; 01186 01187 if(!but->poin) 01188 but->poin= MEM_callocN(sizeof(ColorBand), "colorband"); 01189 01190 button_activate_state(C, but, BUTTON_STATE_NUM_EDITING); 01191 memcpy(data->coba, &but_copypaste_coba, sizeof(ColorBand) ); 01192 button_activate_state(C, but, BUTTON_STATE_EXIT); 01193 } 01194 } 01195 /* operator button (any type) */ 01196 else if (but->optype) { 01197 if(mode=='c') { 01198 PointerRNA *opptr; 01199 char *str; 01200 opptr= uiButGetOperatorPtrRNA(but); /* allocated when needed, the button owns it */ 01201 01202 str= WM_operator_pystring(C, but->optype, opptr, 0); 01203 01204 WM_clipboard_text_set(str, 0); 01205 01206 MEM_freeN(str); 01207 } 01208 } 01209 } 01210 01211 /* ************* in-button text selection/editing ************* */ 01212 01213 /* return 1 if char ch is special character, otherwise return 0 */ 01214 static short test_special_char(char ch) 01215 { 01216 switch(ch) { 01217 case '\\': 01218 case '/': 01219 case '~': 01220 case '!': 01221 case '@': 01222 case '#': 01223 case '$': 01224 case '%': 01225 case '^': 01226 case '&': 01227 case '*': 01228 case '(': 01229 case ')': 01230 case '+': 01231 case '=': 01232 case '{': 01233 case '}': 01234 case '[': 01235 case ']': 01236 case ':': 01237 case ';': 01238 case '\'': 01239 case '\"': 01240 case '<': 01241 case '>': 01242 case ',': 01243 case '.': 01244 case '?': 01245 case '_': 01246 case '-': 01247 case ' ': 01248 return 1; 01249 break; 01250 default: 01251 break; 01252 } 01253 return 0; 01254 } 01255 01256 static int ui_textedit_delete_selection(uiBut *but, uiHandleButtonData *data) 01257 { 01258 char *str= data->str; 01259 int len= strlen(str); 01260 int change= 0; 01261 if(but->selsta != but->selend && len) { 01262 memmove( str+but->selsta, str+but->selend, (len - but->selend) + 1 ); 01263 change= 1; 01264 } 01265 01266 but->pos = but->selend = but->selsta; 01267 return change; 01268 } 01269 01270 /* note, but->block->aspect is used here, when drawing button style is getting scaled too */ 01271 static void ui_textedit_set_cursor_pos(uiBut *but, uiHandleButtonData *data, short x) 01272 { 01273 uiStyle *style= U.uistyles.first; // XXX pass on as arg 01274 uiFontStyle *fstyle = &style->widget; 01275 int startx= but->x1; 01276 char *origstr; 01277 01278 uiStyleFontSet(fstyle); 01279 01280 if (fstyle->kerning==1) /* for BLF_width */ 01281 BLF_enable(fstyle->uifont_id, BLF_KERNING_DEFAULT); 01282 01283 origstr= MEM_callocN(sizeof(char)*data->maxlen, "ui_textedit origstr"); 01284 01285 BLI_strncpy(origstr, but->drawstr, data->maxlen); 01286 01287 /* XXX solve generic */ 01288 if(but->type==NUM || but->type==NUMSLI) 01289 startx += (int)(0.5f*(but->y2 - but->y1)); 01290 else if(ELEM(but->type, TEX, SEARCH_MENU)) { 01291 startx += 5; 01292 if (but->flag & UI_HAS_ICON) 01293 startx += UI_DPI_ICON_SIZE; 01294 } 01295 01296 /* mouse dragged outside the widget to the left */ 01297 if (x < startx && but->ofs > 0) { 01298 int i= but->ofs; 01299 01300 origstr[but->ofs] = 0; 01301 01302 while (i > 0) { 01303 i--; 01304 if (BLF_width(fstyle->uifont_id, origstr+i) > (startx - x)*0.25f) break; // 0.25 == scale factor for less sensitivity 01305 } 01306 but->ofs = i; 01307 but->pos = but->ofs; 01308 } 01309 /* mouse inside the widget */ 01310 else if (x >= startx) { 01311 float aspect= (but->block->aspect); 01312 01313 but->pos= strlen(origstr)-but->ofs; 01314 01315 /* XXX does not take zoom level into account */ 01316 while (startx + aspect*BLF_width(fstyle->uifont_id, origstr+but->ofs) > x) { 01317 if (but->pos <= 0) break; 01318 but->pos--; 01319 origstr[but->pos+but->ofs] = 0; 01320 } 01321 but->pos += but->ofs; 01322 if(but->pos<0) but->pos= 0; 01323 } 01324 01325 if (fstyle->kerning == 1) 01326 BLF_disable(fstyle->uifont_id, BLF_KERNING_DEFAULT); 01327 01328 MEM_freeN(origstr); 01329 } 01330 01331 static void ui_textedit_set_cursor_select(uiBut *but, uiHandleButtonData *data, short x) 01332 { 01333 if (x > data->selstartx) data->selextend = EXTEND_RIGHT; 01334 else if (x < data->selstartx) data->selextend = EXTEND_LEFT; 01335 01336 ui_textedit_set_cursor_pos(but, data, x); 01337 01338 if (data->selextend == EXTEND_RIGHT) but->selend = but->pos; 01339 if (data->selextend == EXTEND_LEFT) but->selsta = but->pos; 01340 01341 ui_check_but(but); 01342 } 01343 01344 static int ui_textedit_type_ascii(uiBut *but, uiHandleButtonData *data, char ascii) 01345 { 01346 char *str; 01347 int len, x, changed= 0; 01348 01349 str= data->str; 01350 len= strlen(str); 01351 01352 if(len-(but->selend - but->selsta)+1 <= data->maxlen) { 01353 /* type over the current selection */ 01354 if ((but->selend - but->selsta) > 0) 01355 changed= ui_textedit_delete_selection(but, data); 01356 01357 len= strlen(str); 01358 if(len+1 < data->maxlen) { 01359 for(x= data->maxlen; x>but->pos; x--) 01360 str[x]= str[x-1]; 01361 str[but->pos]= ascii; 01362 str[len+1]= '\0'; 01363 01364 but->pos++; 01365 changed= 1; 01366 } 01367 } 01368 01369 return changed; 01370 } 01371 01372 static void ui_textedit_move(uiBut *but, uiHandleButtonData *data, int direction, int select, int jump) 01373 { 01374 char *str; 01375 int len; 01376 01377 str= data->str; 01378 len= strlen(str); 01379 01380 if(direction) { /* right*/ 01381 /* if there's a selection */ 01382 if ((but->selend - but->selsta) > 0) { 01383 /* extend the selection based on the first direction taken */ 01384 if(select) { 01385 if (!data->selextend) { 01386 data->selextend = EXTEND_RIGHT; 01387 } 01388 if (data->selextend == EXTEND_RIGHT) { 01389 but->selend++; 01390 if (but->selend > len) but->selend = len; 01391 } else if (data->selextend == EXTEND_LEFT) { 01392 but->selsta++; 01393 /* if the selection start has gone past the end, 01394 * flip them so they're in sync again */ 01395 if (but->selsta == but->selend) { 01396 but->pos = but->selsta; 01397 data->selextend = EXTEND_RIGHT; 01398 } 01399 } 01400 } else { 01401 but->selsta = but->pos = but->selend; 01402 data->selextend = 0; 01403 } 01404 } else { 01405 if(select) { 01406 /* make a selection, starting from the cursor position */ 01407 int tlen; 01408 but->selsta = but->pos; 01409 01410 but->pos++; 01411 if(but->pos > (tlen= strlen(str))) but->pos= tlen; 01412 01413 but->selend = but->pos; 01414 } else if(jump) { 01415 /* jump betweenn special characters (/,\,_,-, etc.), 01416 * look at function test_special_char() for complete 01417 * list of special character, ctr -> */ 01418 while(but->pos < len) { 01419 but->pos++; 01420 if(test_special_char(str[but->pos])) break; 01421 } 01422 } else { 01423 int tlen; 01424 but->pos++; 01425 if(but->pos > (tlen= strlen(str))) but->pos= tlen; 01426 } 01427 } 01428 } 01429 else { /* left */ 01430 /* if there's a selection */ 01431 if ((but->selend - but->selsta) > 0) { 01432 /* extend the selection based on the first direction taken */ 01433 if(select) { 01434 if (!data->selextend) { 01435 data->selextend = EXTEND_LEFT; 01436 } 01437 if (data->selextend == EXTEND_LEFT) { 01438 but->selsta--; 01439 if (but->selsta < 0) but->selsta = 0; 01440 } else if (data->selextend == EXTEND_RIGHT) { 01441 but->selend--; 01442 /* if the selection start has gone past the end, 01443 * flip them so they're in sync again */ 01444 if (but->selsta == but->selend) { 01445 but->pos = but->selsta; 01446 data->selextend = EXTEND_LEFT; 01447 } 01448 } 01449 } else { 01450 but->pos = but->selend = but->selsta; 01451 data->selextend = 0; 01452 } 01453 } else { 01454 if(select) { 01455 /* make a selection, starting from the cursor position */ 01456 but->selend = but->pos; 01457 01458 but->pos--; 01459 if(but->pos<0) but->pos= 0; 01460 01461 but->selsta = but->pos; 01462 } else if(jump) { 01463 /* jump betweenn special characters (/,\,_,-, etc.), 01464 * look at function test_special_char() for complete 01465 * list of special character, ctr -> */ 01466 while(but->pos > 0){ 01467 but->pos--; 01468 if(test_special_char(str[but->pos])) break; 01469 } 01470 } else { 01471 if(but->pos>0) but->pos--; 01472 } 01473 } 01474 } 01475 } 01476 01477 static void ui_textedit_move_end(uiBut *but, uiHandleButtonData *data, int direction, int select) 01478 { 01479 char *str; 01480 01481 str= data->str; 01482 01483 if(direction) { /* right */ 01484 if(select) { 01485 but->selsta = but->pos; 01486 but->selend = strlen(str); 01487 data->selextend = EXTEND_RIGHT; 01488 } else { 01489 but->selsta = but->selend = but->pos= strlen(str); 01490 } 01491 } 01492 else { /* left */ 01493 if(select) { 01494 but->selend = but->pos; 01495 but->selsta = 0; 01496 data->selextend = EXTEND_LEFT; 01497 } else { 01498 but->selsta = but->selend = but->pos= 0; 01499 } 01500 } 01501 } 01502 01503 static int ui_textedit_delete(uiBut *but, uiHandleButtonData *data, int direction, int all) 01504 { 01505 char *str; 01506 int len, x, changed= 0; 01507 01508 str= data->str; 01509 len= strlen(str); 01510 01511 if(all) { 01512 if(len) changed=1; 01513 str[0]= 0; 01514 but->pos= 0; 01515 } 01516 else if(direction) { /* delete */ 01517 if ((but->selend - but->selsta) > 0) { 01518 changed= ui_textedit_delete_selection(but, data); 01519 } 01520 else if(but->pos>=0 && but->pos<len) { 01521 for(x=but->pos; x<len; x++) 01522 str[x]= str[x+1]; 01523 str[len-1]='\0'; 01524 changed= 1; 01525 } 01526 } 01527 else { /* backspace */ 01528 if(len!=0) { 01529 if ((but->selend - but->selsta) > 0) { 01530 changed= ui_textedit_delete_selection(but, data); 01531 } 01532 else if(but->pos>0) { 01533 for(x=but->pos; x<len; x++) 01534 str[x-1]= str[x]; 01535 str[len-1]='\0'; 01536 01537 but->pos--; 01538 changed= 1; 01539 } 01540 } 01541 } 01542 01543 return changed; 01544 } 01545 01546 static int ui_textedit_autocomplete(bContext *C, uiBut *but, uiHandleButtonData *data) 01547 { 01548 char *str; 01549 int changed= 1; 01550 01551 str= data->str; 01552 01553 if(data->searchbox) 01554 ui_searchbox_autocomplete(C, data->searchbox, but, data->str); 01555 else 01556 but->autocomplete_func(C, str, but->autofunc_arg); 01557 01558 but->pos= strlen(str); 01559 but->selsta= but->selend= but->pos; 01560 01561 return changed; 01562 } 01563 01564 static int ui_textedit_copypaste(uiBut *but, uiHandleButtonData *data, int paste, int copy, int cut) 01565 { 01566 char buf[UI_MAX_DRAW_STR]={0}; 01567 char *str, *p, *pbuf; 01568 int len, x, i, changed= 0; 01569 01570 str= data->str; 01571 len= strlen(str); 01572 01573 /* paste */ 01574 if (paste) { 01575 /* extract the first line from the clipboard */ 01576 p = pbuf= WM_clipboard_text_get(0); 01577 01578 if(p && p[0]) { 01579 unsigned int y; 01580 i= 0; 01581 while (*p && *p!='\r' && *p!='\n' && i<UI_MAX_DRAW_STR-1) { 01582 buf[i++]=*p; 01583 p++; 01584 } 01585 buf[i]= 0; 01586 01587 /* paste over the current selection */ 01588 if ((but->selend - but->selsta) > 0) { 01589 ui_textedit_delete_selection(but, data); 01590 len= strlen(str); 01591 } 01592 01593 for (y=0; y<strlen(buf); y++) 01594 { 01595 /* add contents of buffer */ 01596 if(len+1 < data->maxlen) { 01597 for(x= data->maxlen; x>but->pos; x--) 01598 str[x]= str[x-1]; 01599 str[but->pos]= buf[y]; 01600 but->pos++; 01601 len++; 01602 str[len]= '\0'; 01603 } 01604 } 01605 01606 changed= 1; 01607 } 01608 01609 if(pbuf) 01610 MEM_freeN(pbuf); 01611 } 01612 /* cut & copy */ 01613 else if (copy || cut) { 01614 /* copy the contents to the copypaste buffer */ 01615 for(x= but->selsta; x <= but->selend; x++) { 01616 if (x==but->selend) 01617 buf[x] = '\0'; 01618 else 01619 buf[(x - but->selsta)] = str[x]; 01620 } 01621 01622 WM_clipboard_text_set(buf, 0); 01623 01624 /* for cut only, delete the selection afterwards */ 01625 if(cut) 01626 if((but->selend - but->selsta) > 0) 01627 changed= ui_textedit_delete_selection(but, data); 01628 } 01629 01630 return changed; 01631 } 01632 01633 static void ui_textedit_begin(bContext *C, uiBut *but, uiHandleButtonData *data) 01634 { 01635 if(data->str) { 01636 MEM_freeN(data->str); 01637 data->str= NULL; 01638 } 01639 01640 /* retrieve string */ 01641 data->maxlen= ui_get_but_string_max_length(but); 01642 data->str= MEM_callocN(sizeof(char)*data->maxlen + 1, "textedit str"); 01643 ui_get_but_string(but, data->str, data->maxlen); 01644 01645 if(ELEM3(but->type, NUM, NUMABS, NUMSLI)) { 01646 /* XXX: we dont have utf editing yet so for numbers its best to strip out utf chars 01647 * this is so the deg' synbol isnt included in number editing fields: bug 22274 */ 01648 int i; 01649 for(i=0; data->str[i]; i++) { 01650 if(!isascii(data->str[i])) { 01651 /* no stripping actually: just convert to alt name */ 01652 ui_convert_to_unit_alt_name(but, data->str, data->maxlen); 01653 break; 01654 } 01655 } 01656 } 01657 01658 01659 data->origstr= BLI_strdup(data->str); 01660 data->selextend= 0; 01661 data->selstartx= 0; 01662 01663 /* set cursor pos to the end of the text */ 01664 but->editstr= data->str; 01665 but->pos= strlen(data->str); 01666 but->selsta= 0; 01667 but->selend= strlen(data->str); 01668 01669 /* optional searchbox */ 01670 if(but->type==SEARCH_MENU) { 01671 data->searchbox= ui_searchbox_create(C, data->region, but); 01672 ui_searchbox_update(C, data->searchbox, but, 1); /* 1= reset */ 01673 } 01674 01675 ui_check_but(but); 01676 01677 WM_cursor_modal(CTX_wm_window(C), BC_TEXTEDITCURSOR); 01678 } 01679 01680 static void ui_textedit_end(bContext *C, uiBut *but, uiHandleButtonData *data) 01681 { 01682 if(but) { 01683 if(ui_is_utf8_but(but)) { 01684 int strip= BLI_utf8_invalid_strip(but->editstr, strlen(but->editstr)); 01685 /* not a file?, strip non utf-8 chars */ 01686 if(strip) { 01687 /* wont happen often so isnt that annoying to keep it here for a while */ 01688 printf("invalid utf8 - stripped chars %d\n", strip); 01689 } 01690 } 01691 01692 if(data->searchbox) { 01693 if(data->cancel==0) 01694 ui_searchbox_apply(but, data->searchbox); 01695 01696 ui_searchbox_free(C, data->searchbox); 01697 data->searchbox= NULL; 01698 } 01699 01700 but->editstr= NULL; 01701 but->pos= -1; 01702 } 01703 01704 WM_cursor_restore(CTX_wm_window(C)); 01705 } 01706 01707 static void ui_textedit_next_but(uiBlock *block, uiBut *actbut, uiHandleButtonData *data) 01708 { 01709 uiBut *but; 01710 01711 /* label and roundbox can overlap real buttons (backdrops...) */ 01712 if(ELEM4(actbut->type, LABEL, SEPR, ROUNDBOX, LISTBOX)) 01713 return; 01714 01715 for(but= actbut->next; but; but= but->next) { 01716 if(ELEM7(but->type, TEX, NUM, NUMABS, NUMSLI, HSVSLI, IDPOIN, SEARCH_MENU)) { 01717 if(!(but->flag & UI_BUT_DISABLED)) { 01718 data->postbut= but; 01719 data->posttype= BUTTON_ACTIVATE_TEXT_EDITING; 01720 return; 01721 } 01722 } 01723 } 01724 for(but= block->buttons.first; but!=actbut; but= but->next) { 01725 if(ELEM7(but->type, TEX, NUM, NUMABS, NUMSLI, HSVSLI, IDPOIN, SEARCH_MENU)) { 01726 if(!(but->flag & UI_BUT_DISABLED)) { 01727 data->postbut= but; 01728 data->posttype= BUTTON_ACTIVATE_TEXT_EDITING; 01729 return; 01730 } 01731 } 01732 } 01733 } 01734 01735 static void ui_textedit_prev_but(uiBlock *block, uiBut *actbut, uiHandleButtonData *data) 01736 { 01737 uiBut *but; 01738 01739 /* label and roundbox can overlap real buttons (backdrops...) */ 01740 if(ELEM4(actbut->type, LABEL, SEPR, ROUNDBOX, LISTBOX)) 01741 return; 01742 01743 for(but= actbut->prev; but; but= but->prev) { 01744 if(ELEM7(but->type, TEX, NUM, NUMABS, NUMSLI, HSVSLI, IDPOIN, SEARCH_MENU)) { 01745 if(!(but->flag & UI_BUT_DISABLED)) { 01746 data->postbut= but; 01747 data->posttype= BUTTON_ACTIVATE_TEXT_EDITING; 01748 return; 01749 } 01750 } 01751 } 01752 for(but= block->buttons.last; but!=actbut; but= but->prev) { 01753 if(ELEM7(but->type, TEX, NUM, NUMABS, NUMSLI, HSVSLI, IDPOIN, SEARCH_MENU)) { 01754 if(!(but->flag & UI_BUT_DISABLED)) { 01755 data->postbut= but; 01756 data->posttype= BUTTON_ACTIVATE_TEXT_EDITING; 01757 return; 01758 } 01759 } 01760 } 01761 } 01762 01763 01764 static void ui_do_but_textedit(bContext *C, uiBlock *block, uiBut *but, uiHandleButtonData *data, wmEvent *event) 01765 { 01766 int mx, my, changed= 0, inbox=0, update= 0, retval= WM_UI_HANDLER_CONTINUE; 01767 01768 switch(event->type) { 01769 case WHEELUPMOUSE: 01770 case WHEELDOWNMOUSE: 01771 case MOUSEMOVE: 01772 if(data->searchbox) 01773 ui_searchbox_event(C, data->searchbox, but, event); 01774 01775 break; 01776 case RIGHTMOUSE: 01777 case ESCKEY: 01778 data->cancel= 1; 01779 data->escapecancel= 1; 01780 button_activate_state(C, but, BUTTON_STATE_EXIT); 01781 retval= WM_UI_HANDLER_BREAK; 01782 break; 01783 case LEFTMOUSE: { 01784 01785 /* exit on LMB only on RELEASE for searchbox, to mimic other popups, and allow multiple menu levels */ 01786 if(data->searchbox) 01787 inbox= ui_searchbox_inside(data->searchbox, event->x, event->y); 01788 01789 if(event->val==KM_PRESS) { 01790 mx= event->x; 01791 my= event->y; 01792 ui_window_to_block(data->region, block, &mx, &my); 01793 01794 if (ui_but_contains_pt(but, mx, my)) { 01795 ui_textedit_set_cursor_pos(but, data, mx); 01796 but->selsta = but->selend = but->pos; 01797 data->selstartx= mx; 01798 01799 button_activate_state(C, but, BUTTON_STATE_TEXT_SELECTING); 01800 retval= WM_UI_HANDLER_BREAK; 01801 } 01802 else if(inbox==0) { 01803 /* if searchbox, click outside will cancel */ 01804 if(data->searchbox) 01805 data->cancel= data->escapecancel= 1; 01806 button_activate_state(C, but, BUTTON_STATE_EXIT); 01807 retval= WM_UI_HANDLER_BREAK; 01808 } 01809 } 01810 else if(inbox) { 01811 button_activate_state(C, but, BUTTON_STATE_EXIT); 01812 retval= WM_UI_HANDLER_BREAK; 01813 } 01814 break; 01815 } 01816 } 01817 01818 if(event->val==KM_PRESS) { 01819 switch (event->type) { 01820 case VKEY: 01821 case XKEY: 01822 case CKEY: 01823 if(event->ctrl || event->oskey) { 01824 if(event->type == VKEY) 01825 changed= ui_textedit_copypaste(but, data, 1, 0, 0); 01826 else if(event->type == CKEY) 01827 changed= ui_textedit_copypaste(but, data, 0, 1, 0); 01828 else if(event->type == XKEY) 01829 changed= ui_textedit_copypaste(but, data, 0, 0, 1); 01830 01831 retval= WM_UI_HANDLER_BREAK; 01832 } 01833 break; 01834 case RIGHTARROWKEY: 01835 ui_textedit_move(but, data, 1, event->shift, event->ctrl); 01836 retval= WM_UI_HANDLER_BREAK; 01837 break; 01838 case LEFTARROWKEY: 01839 ui_textedit_move(but, data, 0, event->shift, event->ctrl); 01840 retval= WM_UI_HANDLER_BREAK; 01841 break; 01842 case DOWNARROWKEY: 01843 if(data->searchbox) { 01844 ui_searchbox_event(C, data->searchbox, but, event); 01845 break; 01846 } 01847 /* pass on purposedly */ 01848 case ENDKEY: 01849 ui_textedit_move_end(but, data, 1, event->shift); 01850 retval= WM_UI_HANDLER_BREAK; 01851 break; 01852 case UPARROWKEY: 01853 if(data->searchbox) { 01854 ui_searchbox_event(C, data->searchbox, but, event); 01855 break; 01856 } 01857 /* pass on purposedly */ 01858 case HOMEKEY: 01859 ui_textedit_move_end(but, data, 0, event->shift); 01860 retval= WM_UI_HANDLER_BREAK; 01861 break; 01862 case PADENTER: 01863 case RETKEY: 01864 button_activate_state(C, but, BUTTON_STATE_EXIT); 01865 retval= WM_UI_HANDLER_BREAK; 01866 break; 01867 case DELKEY: 01868 changed= ui_textedit_delete(but, data, 1, 0); 01869 retval= WM_UI_HANDLER_BREAK; 01870 break; 01871 01872 case BACKSPACEKEY: 01873 changed= ui_textedit_delete(but, data, 0, event->shift); 01874 retval= WM_UI_HANDLER_BREAK; 01875 break; 01876 01877 case TABKEY: 01878 /* there is a key conflict here, we can't tab with autocomplete */ 01879 if(but->autocomplete_func || data->searchbox) { 01880 changed= ui_textedit_autocomplete(C, but, data); 01881 update= 1; /* do live update for tab key */ 01882 } 01883 /* the hotkey here is not well defined, was G.qual so we check all */ 01884 else if(event->shift || event->ctrl || event->alt || event->oskey) { 01885 ui_textedit_prev_but(block, but, data); 01886 button_activate_state(C, but, BUTTON_STATE_EXIT); 01887 } 01888 else { 01889 ui_textedit_next_but(block, but, data); 01890 button_activate_state(C, but, BUTTON_STATE_EXIT); 01891 } 01892 retval= WM_UI_HANDLER_BREAK; 01893 break; 01894 } 01895 01896 if(event->ascii && (retval == WM_UI_HANDLER_CONTINUE)) { 01897 char ascii = event->ascii; 01898 01899 /* exception that's useful for number buttons, some keyboard 01900 numpads have a comma instead of a period */ 01901 if(ELEM3(but->type, NUM, NUMABS, NUMSLI)) 01902 if(event->type == PADPERIOD && ascii == ',') 01903 ascii = '.'; 01904 01905 changed= ui_textedit_type_ascii(but, data, ascii); 01906 retval= WM_UI_HANDLER_BREAK; 01907 01908 } 01909 /* textbutton with magnifier icon: do live update for search button */ 01910 if(but->icon==ICON_VIEWZOOM) 01911 update= 1; 01912 } 01913 01914 if(changed) { 01915 /* only update when typing for TAB key */ 01916 if(update && data->interactive) ui_apply_button(C, block, but, data, 1); 01917 else ui_check_but(but); 01918 but->changed= TRUE; 01919 01920 if(data->searchbox) 01921 ui_searchbox_update(C, data->searchbox, but, 1); /* 1 = reset */ 01922 } 01923 01924 if(changed || (retval == WM_UI_HANDLER_BREAK)) 01925 ED_region_tag_redraw(data->region); 01926 } 01927 01928 static void ui_do_but_textedit_select(bContext *C, uiBlock *block, uiBut *but, uiHandleButtonData *data, wmEvent *event) 01929 { 01930 int mx, my, retval= WM_UI_HANDLER_CONTINUE; 01931 01932 switch(event->type) { 01933 case MOUSEMOVE: { 01934 mx= event->x; 01935 my= event->y; 01936 ui_window_to_block(data->region, block, &mx, &my); 01937 01938 ui_textedit_set_cursor_select(but, data, mx); 01939 retval= WM_UI_HANDLER_BREAK; 01940 break; 01941 } 01942 case LEFTMOUSE: 01943 if(event->val == KM_RELEASE) 01944 button_activate_state(C, but, BUTTON_STATE_TEXT_EDITING); 01945 retval= WM_UI_HANDLER_BREAK; 01946 break; 01947 } 01948 01949 if(retval == WM_UI_HANDLER_BREAK) { 01950 ui_check_but(but); 01951 ED_region_tag_redraw(data->region); 01952 } 01953 } 01954 01955 /* ************* number editing for various types ************* */ 01956 01957 static void ui_numedit_begin(uiBut *but, uiHandleButtonData *data) 01958 { 01959 float softrange, softmin, softmax; 01960 01961 if(but->type == BUT_CURVE) { 01962 but->editcumap= (CurveMapping*)but->poin; 01963 } 01964 else if(but->type == BUT_COLORBAND) { 01965 data->coba= (ColorBand*)but->poin; 01966 but->editcoba= data->coba; 01967 } 01968 else if(ELEM3(but->type, BUT_NORMAL, HSVCUBE, HSVCIRCLE)) { 01969 ui_get_but_vectorf(but, data->origvec); 01970 VECCOPY(data->vec, data->origvec); 01971 but->editvec= data->vec; 01972 } 01973 else { 01974 data->startvalue= ui_get_but_val(but); 01975 data->origvalue= data->startvalue; 01976 data->value= data->origvalue; 01977 but->editval= &data->value; 01978 01979 softmin= but->softmin; 01980 softmax= but->softmax; 01981 softrange= softmax - softmin; 01982 01983 data->dragfstart= (softrange == 0.0f)? 0.0f: ((float)data->value - softmin)/softrange; 01984 data->dragf= data->dragfstart; 01985 } 01986 01987 data->dragchange= 0; 01988 data->draglock= 1; 01989 } 01990 01991 static void ui_numedit_end(uiBut *but, uiHandleButtonData *data) 01992 { 01993 but->editval= NULL; 01994 but->editvec= NULL; 01995 but->editcoba= NULL; 01996 but->editcumap= NULL; 01997 01998 data->dragstartx= 0; 01999 data->draglastx= 0; 02000 data->dragchange= 0; 02001 data->dragcbd= NULL; 02002 data->dragsel= 0; 02003 } 02004 02005 static void ui_numedit_apply(bContext *C, uiBlock *block, uiBut *but, uiHandleButtonData *data) 02006 { 02007 if(data->interactive) ui_apply_button(C, block, but, data, 1); 02008 else ui_check_but(but); 02009 02010 ED_region_tag_redraw(data->region); 02011 } 02012 02013 /* ****************** menu opening for various types **************** */ 02014 02015 static void ui_blockopen_begin(bContext *C, uiBut *but, uiHandleButtonData *data) 02016 { 02017 uiBlockCreateFunc func= NULL; 02018 uiBlockHandleCreateFunc handlefunc= NULL; 02019 uiMenuCreateFunc menufunc= NULL; 02020 char *menustr= NULL; 02021 void *arg= NULL; 02022 02023 switch(but->type) { 02024 case BLOCK: 02025 case PULLDOWN: 02026 if(but->menu_create_func) { 02027 menufunc= but->menu_create_func; 02028 arg= but->poin; 02029 } 02030 else { 02031 func= but->block_create_func; 02032 arg= but->poin?but->poin:but->func_argN; 02033 } 02034 break; 02035 case MENU: 02036 if(but->menu_create_func) { 02037 menufunc= but->menu_create_func; 02038 arg= but->poin; 02039 } 02040 else { 02041 data->origvalue= ui_get_but_val(but); 02042 data->value= data->origvalue; 02043 but->editval= &data->value; 02044 02045 menustr= but->str; 02046 } 02047 break; 02048 case ICONROW: 02049 menufunc= ui_block_func_ICONROW; 02050 arg= but; 02051 break; 02052 case ICONTEXTROW: 02053 menufunc= ui_block_func_ICONTEXTROW; 02054 arg= but; 02055 break; 02056 case COL: 02057 ui_get_but_vectorf(but, data->origvec); 02058 VECCOPY(data->vec, data->origvec); 02059 but->editvec= data->vec; 02060 02061 handlefunc= ui_block_func_COL; 02062 arg= but; 02063 break; 02064 } 02065 02066 if(func || handlefunc) { 02067 data->menu= ui_popup_block_create(C, data->region, but, func, handlefunc, arg); 02068 if(but->block->handle) 02069 data->menu->popup= but->block->handle->popup; 02070 } 02071 else if(menufunc || menustr) { 02072 data->menu= ui_popup_menu_create(C, data->region, but, menufunc, arg, menustr); 02073 if(but->block->handle) 02074 data->menu->popup= but->block->handle->popup; 02075 } 02076 02077 /* this makes adjacent blocks auto open from now on */ 02078 //if(but->block->auto_open==0) but->block->auto_open= 1; 02079 } 02080 02081 static void ui_blockopen_end(bContext *C, uiBut *but, uiHandleButtonData *data) 02082 { 02083 if(but) { 02084 but->editval= NULL; 02085 but->editvec= NULL; 02086 02087 but->block->auto_open_last= PIL_check_seconds_timer(); 02088 } 02089 02090 if(data->menu) { 02091 ui_popup_block_free(C, data->menu); 02092 data->menu= NULL; 02093 } 02094 } 02095 02096 /* ***************** events for different button types *************** */ 02097 02098 static int ui_do_but_BUT(bContext *C, uiBut *but, uiHandleButtonData *data, wmEvent *event) 02099 { 02100 if(data->state == BUTTON_STATE_HIGHLIGHT) { 02101 if(event->type == LEFTMOUSE && event->val==KM_PRESS) { 02102 button_activate_state(C, but, BUTTON_STATE_WAIT_RELEASE); 02103 return WM_UI_HANDLER_BREAK; 02104 } 02105 else if(event->type == LEFTMOUSE && but->block->handle) { 02106 button_activate_state(C, but, BUTTON_STATE_EXIT); 02107 return WM_UI_HANDLER_BREAK; 02108 } 02109 else if(ELEM(event->type, PADENTER, RETKEY) && event->val==KM_PRESS) { 02110 button_activate_state(C, but, BUTTON_STATE_WAIT_FLASH); 02111 return WM_UI_HANDLER_BREAK; 02112 } 02113 } 02114 else if(data->state == BUTTON_STATE_WAIT_RELEASE) { 02115 if(event->type == LEFTMOUSE && event->val!=KM_PRESS) { 02116 if(!(but->flag & UI_SELECT)) 02117 data->cancel= 1; 02118 button_activate_state(C, but, BUTTON_STATE_EXIT); 02119 return WM_UI_HANDLER_BREAK; 02120 } 02121 } 02122 02123 return WM_UI_HANDLER_CONTINUE; 02124 } 02125 02126 static int ui_do_but_HOTKEYEVT(bContext *C, uiBut *but, uiHandleButtonData *data, wmEvent *event) 02127 { 02128 if(data->state == BUTTON_STATE_HIGHLIGHT) { 02129 if(ELEM3(event->type, LEFTMOUSE, PADENTER, RETKEY) && event->val==KM_PRESS) { 02130 but->drawstr[0]= 0; 02131 but->modifier_key= 0; 02132 button_activate_state(C, but, BUTTON_STATE_WAIT_KEY_EVENT); 02133 return WM_UI_HANDLER_BREAK; 02134 } 02135 } 02136 else if(data->state == BUTTON_STATE_WAIT_KEY_EVENT) { 02137 02138 if(event->type == MOUSEMOVE) 02139 return WM_UI_HANDLER_CONTINUE; 02140 02141 if(event->type == LEFTMOUSE && event->val==KM_PRESS) { 02142 /* only cancel if click outside the button */ 02143 if(ui_mouse_inside_button(but->active->region, but, event->x, event->y) == 0) { 02144 /* data->cancel doesnt work, this button opens immediate */ 02145 if(but->flag & UI_BUT_IMMEDIATE) 02146 ui_set_but_val(but, 0); 02147 else 02148 data->cancel= 1; 02149 button_activate_state(C, but, BUTTON_STATE_EXIT); 02150 return WM_UI_HANDLER_BREAK; 02151 } 02152 } 02153 02154 /* always set */ 02155 but->modifier_key = 0; 02156 if(event->shift) 02157 but->modifier_key |= KM_SHIFT; 02158 if(event->alt) 02159 but->modifier_key |= KM_ALT; 02160 if(event->ctrl) 02161 but->modifier_key |= KM_CTRL; 02162 if(event->oskey) 02163 but->modifier_key |= KM_OSKEY; 02164 02165 ui_check_but(but); 02166 ED_region_tag_redraw(data->region); 02167 02168 if(event->val==KM_PRESS) { 02169 if(ISHOTKEY(event->type)) { 02170 02171 if(WM_key_event_string(event->type)[0]) 02172 ui_set_but_val(but, event->type); 02173 else 02174 data->cancel= 1; 02175 02176 button_activate_state(C, but, BUTTON_STATE_EXIT); 02177 return WM_UI_HANDLER_BREAK; 02178 } 02179 else if(event->type == ESCKEY) { 02180 data->cancel= 1; 02181 data->escapecancel= 1; 02182 button_activate_state(C, but, BUTTON_STATE_EXIT); 02183 } 02184 02185 } 02186 } 02187 02188 return WM_UI_HANDLER_CONTINUE; 02189 } 02190 02191 static int ui_do_but_KEYEVT(bContext *C, uiBut *but, uiHandleButtonData *data, wmEvent *event) 02192 { 02193 if(data->state == BUTTON_STATE_HIGHLIGHT) { 02194 if(ELEM3(event->type, LEFTMOUSE, PADENTER, RETKEY) && event->val==KM_PRESS) { 02195 button_activate_state(C, but, BUTTON_STATE_WAIT_KEY_EVENT); 02196 return WM_UI_HANDLER_BREAK; 02197 } 02198 } 02199 else if(data->state == BUTTON_STATE_WAIT_KEY_EVENT) { 02200 if(event->type == MOUSEMOVE) 02201 return WM_UI_HANDLER_CONTINUE; 02202 02203 if(event->val==KM_PRESS) { 02204 if(WM_key_event_string(event->type)[0]) 02205 ui_set_but_val(but, event->type); 02206 else 02207 data->cancel= 1; 02208 02209 button_activate_state(C, but, BUTTON_STATE_EXIT); 02210 } 02211 } 02212 02213 return WM_UI_HANDLER_CONTINUE; 02214 } 02215 02216 static int ui_do_but_TEX(bContext *C, uiBlock *block, uiBut *but, uiHandleButtonData *data, wmEvent *event) 02217 { 02218 if(data->state == BUTTON_STATE_HIGHLIGHT) { 02219 if(ELEM(event->type, LEFTMOUSE, EVT_BUT_OPEN) && event->val==KM_PRESS) { 02220 if(but->dt == UI_EMBOSSN && !event->ctrl); 02221 else { 02222 button_activate_state(C, but, BUTTON_STATE_TEXT_EDITING); 02223 return WM_UI_HANDLER_BREAK; 02224 } 02225 } 02226 } 02227 else if(data->state == BUTTON_STATE_TEXT_EDITING) { 02228 ui_do_but_textedit(C, block, but, data, event); 02229 return WM_UI_HANDLER_BREAK; 02230 } 02231 else if(data->state == BUTTON_STATE_TEXT_SELECTING) { 02232 ui_do_but_textedit_select(C, block, but, data, event); 02233 return WM_UI_HANDLER_BREAK; 02234 } 02235 02236 return WM_UI_HANDLER_CONTINUE; 02237 } 02238 02239 static int ui_do_but_TOG(bContext *C, uiBut *but, uiHandleButtonData *data, wmEvent *event) 02240 { 02241 if(data->state == BUTTON_STATE_HIGHLIGHT) { 02242 if(ELEM3(event->type, LEFTMOUSE, PADENTER, RETKEY) && event->val==KM_PRESS) { 02243 data->togdual= event->ctrl; 02244 data->togonly= !event->shift; 02245 button_activate_state(C, but, BUTTON_STATE_EXIT); 02246 return WM_UI_HANDLER_BREAK; 02247 } 02248 } 02249 return WM_UI_HANDLER_CONTINUE; 02250 } 02251 02252 static int ui_do_but_EXIT(bContext *C, uiBut *but, uiHandleButtonData *data, wmEvent *event) 02253 { 02254 02255 if(data->state == BUTTON_STATE_HIGHLIGHT) { 02256 02257 /* first handle click on icondrag type button */ 02258 if(event->type==LEFTMOUSE && but->dragpoin) { 02259 if(ui_but_mouse_inside_icon(but, data->region, event)) { 02260 02261 /* tell the button to wait and keep checking further events to 02262 * see if it should start dragging */ 02263 button_activate_state(C, but, BUTTON_STATE_WAIT_DRAG); 02264 data->dragstartx= event->x; 02265 data->dragstarty= event->y; 02266 return WM_UI_HANDLER_CONTINUE; 02267 } 02268 } 02269 02270 if(ELEM3(event->type, LEFTMOUSE, PADENTER, RETKEY) && event->val==KM_PRESS) { 02271 int ret = WM_UI_HANDLER_BREAK; 02272 /* XXX (a bit ugly) Special case handling for filebrowser drag button */ 02273 if(but->dragpoin && but->imb && ui_but_mouse_inside_icon(but, data->region, event)) { 02274 ret = WM_UI_HANDLER_CONTINUE; 02275 } 02276 button_activate_state(C, but, BUTTON_STATE_EXIT); 02277 return ret; 02278 } 02279 } 02280 else if(data->state == BUTTON_STATE_WAIT_DRAG) { 02281 02282 /* this function also ends state */ 02283 if(ui_but_start_drag(C, but, data, event)) { 02284 return WM_UI_HANDLER_BREAK; 02285 } 02286 02287 /* If the mouse has been pressed and released, getting to 02288 * this point without triggering a drag, then clear the 02289 * drag state for this button and continue to pass on the event */ 02290 if(event->type==LEFTMOUSE && event->val==KM_RELEASE) { 02291 button_activate_state(C, but, BUTTON_STATE_EXIT); 02292 return WM_UI_HANDLER_CONTINUE; 02293 } 02294 02295 /* while waiting for a drag to be triggered, always block 02296 * other events from getting handled */ 02297 return WM_UI_HANDLER_BREAK; 02298 } 02299 02300 return WM_UI_HANDLER_CONTINUE; 02301 } 02302 02303 /* var names match ui_numedit_but_NUM */ 02304 static float ui_numedit_apply_snapf(uiBut *but, float tempf, float softmin, float softmax, float softrange, int snap) 02305 { 02306 if(tempf==softmin || tempf==softmax || snap==0) { 02307 /* pass */ 02308 } 02309 else { 02310 float fac= 1.0f; 02311 02312 if(ui_is_but_unit(but)) { 02313 Scene *scene= CTX_data_scene((bContext *)but->block->evil_C); 02314 int unit_type= uiButGetUnitType(but)>>16; 02315 02316 if(bUnit_IsValid(scene->unit.system, unit_type)) { 02317 fac= (float)bUnit_BaseScalar(scene->unit.system, unit_type); 02318 if(ELEM3(unit_type, B_UNIT_LENGTH, B_UNIT_AREA, B_UNIT_VOLUME)) { 02319 fac /= scene->unit.scale_length; 02320 } 02321 } 02322 } 02323 02324 if(fac != 1.0f) { 02325 /* snap in unit-space */ 02326 tempf /= fac; 02327 /* softmin /= fac; */ /* UNUSED */ 02328 /* softmax /= fac; */ /* UNUSED */ 02329 softrange /= fac; 02330 } 02331 02332 if(snap==1) { 02333 if(softrange < 2.10f) tempf= 0.1f*floorf(10.0f*tempf); 02334 else if(softrange < 21.0f) tempf= floorf(tempf); 02335 else tempf= 10.0f*floorf(tempf/10.0f); 02336 } 02337 else if(snap==2) { 02338 if(softrange < 2.10f) tempf= 0.01f*floorf(100.0f*tempf); 02339 else if(softrange < 21.0f) tempf= 0.1f*floorf(10.0f*tempf); 02340 else tempf= floor(tempf); 02341 } 02342 02343 if(fac != 1.0f) 02344 tempf *= fac; 02345 } 02346 02347 return tempf; 02348 } 02349 02350 static float ui_numedit_apply_snap(int temp, float softmin, float softmax, int snap) 02351 { 02352 if(temp==softmin || temp==softmax) 02353 return temp; 02354 02355 switch(snap) { 02356 case 0: 02357 break; 02358 case 1: 02359 temp= 10*(temp/10); 02360 break; 02361 case 2: 02362 temp= 100*(temp/100); 02363 break; 02364 } 02365 02366 return temp; 02367 } 02368 02369 static int ui_numedit_but_NUM(uiBut *but, uiHandleButtonData *data, float fac, int snap, int mx) 02370 { 02371 float deler, tempf, softmin, softmax, softrange; 02372 int lvalue, temp, changed= 0; 02373 02374 if(mx == data->draglastx) 02375 return changed; 02376 02377 /* drag-lock - prevent unwanted scroll adjustments */ 02378 /* change value (now 3) to adjust threshold in pixels */ 02379 if(data->draglock) { 02380 if(abs(mx-data->dragstartx) <= 3) 02381 return changed; 02382 02383 data->draglock= 0; 02384 data->dragstartx= mx; /* ignore mouse movement within drag-lock */ 02385 } 02386 02387 softmin= but->softmin; 02388 softmax= but->softmax; 02389 softrange= softmax - softmin; 02390 02391 if(ui_is_a_warp_but(but)) { 02392 /* Mouse location isn't screen clamped to the screen so use a linear mapping 02393 * 2px == 1-int, or 1px == 1-ClickStep */ 02394 if(ui_is_but_float(but)) { 02395 fac *= 0.01f*but->a1; 02396 tempf = (float)data->startvalue + ((float)(mx - data->dragstartx) * fac); 02397 tempf= ui_numedit_apply_snapf(but, tempf, softmin, softmax, softrange, snap); 02398 02399 #if 1 /* fake moving the click start, nicer for dragging back after passing the limit */ 02400 if(tempf < softmin) { 02401 data->dragstartx -= (softmin-tempf) / fac; 02402 tempf= softmin; 02403 } else if (tempf > softmax) { 02404 data->dragstartx += (tempf-softmax) / fac; 02405 tempf= softmax; 02406 } 02407 #else 02408 CLAMP(tempf, softmin, softmax); 02409 #endif 02410 02411 if(tempf != (float)data->value) { 02412 data->dragchange= 1; 02413 data->value= tempf; 02414 changed= 1; 02415 } 02416 } 02417 else { 02418 if(softrange > 256) fac= 1.0; /* 1px == 1 */ 02419 else if(softrange > 32) fac= 1.0/2.0; /* 2px == 1 */ 02420 else fac= 1.0/16.0; /* 16px == 1? */ 02421 02422 temp= data->startvalue + (((double)mx - data->dragstartx) * (double)fac); 02423 temp= ui_numedit_apply_snap(temp, softmin, softmax, snap); 02424 02425 #if 1 /* fake moving the click start, nicer for dragging back after passing the limit */ 02426 if(temp < softmin) { 02427 data->dragstartx -= (softmin-temp) / fac; 02428 temp= softmin; 02429 } else if (temp > softmax) { 02430 data->dragstartx += (temp-softmax) / fac; 02431 temp= softmax; 02432 } 02433 #else 02434 CLAMP(temp, softmin, softmax); 02435 #endif 02436 02437 if(temp != data->value) { 02438 data->dragchange= 1; 02439 data->value= temp; 02440 changed= 1; 02441 } 02442 } 02443 02444 data->draglastx= mx; 02445 } 02446 else { 02447 /* Use a non-linear mapping of the mouse drag especially for large floats (normal behavior) */ 02448 deler= 500; 02449 if(!ui_is_but_float(but)) { 02450 /* prevent large ranges from getting too out of control */ 02451 if (softrange > 600) deler = powf(softrange, 0.75); 02452 02453 if (softrange < 100) deler= 200.0; 02454 if (softrange < 25) deler= 50.0; 02455 } 02456 deler /= fac; 02457 02458 if(softrange > 11) { 02459 /* non linear change in mouse input- good for high precicsion */ 02460 data->dragf+= (((float)(mx-data->draglastx))/deler) * (fabsf(data->dragstartx-mx)*0.002f); 02461 } else if (softrange > 129) { /* only scale large int buttons */ 02462 /* non linear change in mouse input- good for high precicsionm ints need less fine tuning */ 02463 data->dragf+= (((float)(mx-data->draglastx))/deler) * (fabsf(data->dragstartx-mx)*0.004f); 02464 } else { 02465 /*no scaling */ 02466 data->dragf+= ((float)(mx-data->draglastx))/deler ; 02467 } 02468 02469 CLAMP(data->dragf, 0.0f, 1.0f); 02470 data->draglastx= mx; 02471 tempf= (softmin + data->dragf*softrange); 02472 02473 02474 if(!ui_is_but_float(but)) { 02475 temp= floorf(tempf + 0.5f); 02476 02477 temp= ui_numedit_apply_snap(temp, softmin, softmax, snap); 02478 02479 CLAMP(temp, softmin, softmax); 02480 lvalue= (int)data->value; 02481 02482 if(temp != lvalue) { 02483 data->dragchange= 1; 02484 data->value= (double)temp; 02485 changed= 1; 02486 } 02487 } 02488 else { 02489 temp= 0; 02490 tempf= ui_numedit_apply_snapf(but, tempf, softmin, softmax, softrange, snap); 02491 02492 CLAMP(tempf, softmin, softmax); 02493 02494 if(tempf != (float)data->value) { 02495 data->dragchange= 1; 02496 data->value= tempf; 02497 changed= 1; 02498 } 02499 } 02500 } 02501 02502 02503 return changed; 02504 } 02505 02506 static int ui_do_but_NUM(bContext *C, uiBlock *block, uiBut *but, uiHandleButtonData *data, wmEvent *event) 02507 { 02508 int mx, my; /* mouse location scaled to fit the UI */ 02509 int screen_mx, screen_my; /* mouse location kept at screen pixel coords */ 02510 int click= 0; 02511 int retval= WM_UI_HANDLER_CONTINUE; 02512 02513 mx= screen_mx= event->x; 02514 my= screen_my= event->y; 02515 02516 ui_window_to_block(data->region, block, &mx, &my); 02517 02518 if(data->state == BUTTON_STATE_HIGHLIGHT) { 02519 /* XXX hardcoded keymap check.... */ 02520 if(event->type == WHEELDOWNMOUSE && event->alt) { 02521 mx= but->x1; 02522 click= 1; 02523 } 02524 else if(event->type == WHEELUPMOUSE && event->alt) { 02525 mx= but->x2; 02526 click= 1; 02527 } 02528 else if(event->val==KM_PRESS) { 02529 if(ELEM3(event->type, LEFTMOUSE, PADENTER, RETKEY) && event->ctrl) { 02530 button_activate_state(C, but, BUTTON_STATE_TEXT_EDITING); 02531 retval= WM_UI_HANDLER_BREAK; 02532 } 02533 else if(event->type == LEFTMOUSE) { 02534 data->dragstartx= data->draglastx= ui_is_a_warp_but(but) ? screen_mx:mx; 02535 button_activate_state(C, but, BUTTON_STATE_NUM_EDITING); 02536 retval= WM_UI_HANDLER_BREAK; 02537 } 02538 else if(ELEM(event->type, PADENTER, RETKEY) && event->val==KM_PRESS) 02539 click= 1; 02540 else if (event->type == MINUSKEY && event->val==KM_PRESS) { 02541 button_activate_state(C, but, BUTTON_STATE_NUM_EDITING); 02542 data->value = -data->value; 02543 button_activate_state(C, but, BUTTON_STATE_EXIT); 02544 retval= WM_UI_HANDLER_BREAK; 02545 } 02546 } 02547 02548 } 02549 else if(data->state == BUTTON_STATE_NUM_EDITING) { 02550 if(event->type == ESCKEY) { 02551 data->cancel= 1; 02552 data->escapecancel= 1; 02553 button_activate_state(C, but, BUTTON_STATE_EXIT); 02554 } 02555 else if(event->type == LEFTMOUSE && event->val!=KM_PRESS) { 02556 if(data->dragchange) 02557 button_activate_state(C, but, BUTTON_STATE_EXIT); 02558 else 02559 click= 1; 02560 } 02561 else if(event->type == MOUSEMOVE) { 02562 float fac; 02563 int snap; 02564 02565 fac= 1.0f; 02566 if(event->shift) fac /= 10.0f; 02567 if(event->alt) fac /= 20.0f; 02568 02569 snap= (event->ctrl)? (event->shift)? 2: 1: 0; 02570 02571 if(ui_numedit_but_NUM(but, data, fac, snap, (ui_is_a_warp_but(but) ? screen_mx:mx))) 02572 ui_numedit_apply(C, block, but, data); 02573 } 02574 retval= WM_UI_HANDLER_BREAK; 02575 } 02576 else if(data->state == BUTTON_STATE_TEXT_EDITING) { 02577 ui_do_but_textedit(C, block, but, data, event); 02578 retval= WM_UI_HANDLER_BREAK; 02579 } 02580 else if(data->state == BUTTON_STATE_TEXT_SELECTING) { 02581 ui_do_but_textedit_select(C, block, but, data, event); 02582 retval= WM_UI_HANDLER_BREAK; 02583 } 02584 02585 if(click) { 02586 /* we can click on the side arrows to increment/decrement, 02587 * or click inside to edit the value directly */ 02588 float tempf, softmin, softmax; 02589 int temp; 02590 02591 softmin= but->softmin; 02592 softmax= but->softmax; 02593 02594 if(!ui_is_but_float(but)) { 02595 if(mx < (but->x1 + (but->x2 - but->x1)/3 - 3)) { 02596 button_activate_state(C, but, BUTTON_STATE_NUM_EDITING); 02597 02598 temp= (int)data->value - 1; 02599 if(temp>=softmin && temp<=softmax) 02600 data->value= (double)temp; 02601 else 02602 data->cancel= 1; 02603 02604 button_activate_state(C, but, BUTTON_STATE_EXIT); 02605 } 02606 else if(mx > (but->x1 + (2*(but->x2 - but->x1)/3) + 3)) { 02607 button_activate_state(C, but, BUTTON_STATE_NUM_EDITING); 02608 02609 temp= (int)data->value + 1; 02610 if(temp>=softmin && temp<=softmax) 02611 data->value= (double)temp; 02612 else 02613 data->cancel= 1; 02614 02615 button_activate_state(C, but, BUTTON_STATE_EXIT); 02616 } 02617 else 02618 button_activate_state(C, but, BUTTON_STATE_TEXT_EDITING); 02619 } 02620 else { 02621 if(mx < (but->x1 + (but->x2 - but->x1)/3 - 3)) { 02622 button_activate_state(C, but, BUTTON_STATE_NUM_EDITING); 02623 02624 tempf= (float)data->value - 0.01f * but->a1; 02625 if (tempf < softmin) tempf = softmin; 02626 data->value= tempf; 02627 02628 button_activate_state(C, but, BUTTON_STATE_EXIT); 02629 } 02630 else if(mx > but->x1 + (2*((but->x2 - but->x1)/3) + 3)) { 02631 button_activate_state(C, but, BUTTON_STATE_NUM_EDITING); 02632 02633 tempf= (float)data->value + 0.01f * but->a1; 02634 if (tempf > softmax) tempf = softmax; 02635 data->value= tempf; 02636 02637 button_activate_state(C, but, BUTTON_STATE_EXIT); 02638 } 02639 else 02640 button_activate_state(C, but, BUTTON_STATE_TEXT_EDITING); 02641 } 02642 02643 retval= WM_UI_HANDLER_BREAK; 02644 } 02645 02646 return retval; 02647 } 02648 02649 static int ui_numedit_but_SLI(uiBut *but, uiHandleButtonData *data, int shift, int ctrl, int mx) 02650 { 02651 float deler, f, tempf, softmin, softmax, softrange; 02652 int temp, lvalue, changed= 0; 02653 02654 softmin= but->softmin; 02655 softmax= but->softmax; 02656 softrange= softmax - softmin; 02657 02658 if(but->type==NUMSLI) deler= ((but->x2-but->x1) - 5.0f*but->aspect); 02659 else if(but->type==HSVSLI) deler= ((but->x2-but->x1)/2.0f - 5.0f*but->aspect); 02660 else if(but->type==SCROLL) { 02661 int horizontal= (but->x2 - but->x1 > but->y2 - but->y1); 02662 float size= (horizontal)? (but->x2-but->x1): -(but->y2-but->y1); 02663 deler= size*(but->softmax - but->softmin)/(but->softmax - but->softmin + but->a1); 02664 } 02665 else deler= (but->x2-but->x1- 5.0f*but->aspect); 02666 02667 f= (float)(mx-data->dragstartx)/deler + data->dragfstart; 02668 02669 if(shift) 02670 f= (f-data->dragfstart)/10.0f + data->dragfstart; 02671 02672 CLAMP(f, 0.0f, 1.0f); 02673 tempf= softmin + f*softrange; 02674 temp= floorf(tempf+0.5f); 02675 02676 if(ctrl) { 02677 if(tempf==softmin || tempf==softmax); 02678 else if(ui_is_but_float(but)) { 02679 02680 if(shift) { 02681 if(tempf==softmin || tempf==softmax); 02682 else if(softmax-softmin < 2.10f) tempf= 0.01f * floorf(100.0f*tempf); 02683 else if(softmax-softmin < 21.0f) tempf= 0.1f * floorf(10.0f*tempf); 02684 else tempf= floorf(tempf); 02685 } 02686 else { 02687 if(softmax-softmin < 2.10f) tempf= 0.1f * floorf(10.0f*tempf); 02688 else if(softmax-softmin < 21.0f) tempf= floorf(tempf); 02689 else tempf= 10.0f*floorf(tempf/10.0f); 02690 } 02691 } 02692 else { 02693 temp= 10*(temp/10); 02694 tempf= temp; 02695 } 02696 } 02697 02698 if(!ui_is_but_float(but)) { 02699 lvalue= floor(data->value+0.5); 02700 02701 CLAMP(temp, softmin, softmax); 02702 02703 if(temp != lvalue) { 02704 data->value= temp; 02705 data->dragchange= 1; 02706 changed= 1; 02707 } 02708 } 02709 else { 02710 CLAMP(tempf, softmin, softmax); 02711 02712 if(tempf != (float)data->value) { 02713 data->value= tempf; 02714 data->dragchange= 1; 02715 changed= 1; 02716 } 02717 } 02718 02719 return changed; 02720 } 02721 02722 static int ui_do_but_SLI(bContext *C, uiBlock *block, uiBut *but, uiHandleButtonData *data, wmEvent *event) 02723 { 02724 int mx, my, click= 0; 02725 int retval= WM_UI_HANDLER_CONTINUE; 02726 02727 mx= event->x; 02728 my= event->y; 02729 ui_window_to_block(data->region, block, &mx, &my); 02730 02731 if(data->state == BUTTON_STATE_HIGHLIGHT) { 02732 /* XXX hardcoded keymap check.... */ 02733 if(event->type == WHEELDOWNMOUSE && event->alt) { 02734 mx= but->x1; 02735 click= 2; 02736 } 02737 else if(event->type == WHEELUPMOUSE && event->alt) { 02738 mx= but->x2; 02739 click= 2; 02740 } 02741 else if(event->val==KM_PRESS) { 02742 if(ELEM3(event->type, LEFTMOUSE, PADENTER, RETKEY) && event->ctrl) { 02743 button_activate_state(C, but, BUTTON_STATE_TEXT_EDITING); 02744 retval= WM_UI_HANDLER_BREAK; 02745 } 02746 /* alt-click on sides to get "arrows" like in NUM buttons, and match wheel usage above */ 02747 else if(event->type == LEFTMOUSE && event->alt) { 02748 int halfpos = (but->x1 + but->x2) / 2; 02749 click = 2; 02750 if (mx < halfpos) 02751 mx = but->x1; 02752 else 02753 mx = but->x2; 02754 } 02755 else if(event->type == LEFTMOUSE) { 02756 data->dragstartx= mx; 02757 data->draglastx= mx; 02758 button_activate_state(C, but, BUTTON_STATE_NUM_EDITING); 02759 retval= WM_UI_HANDLER_BREAK; 02760 } 02761 else if(ELEM(event->type, PADENTER, RETKEY) && event->val==KM_PRESS) 02762 click= 1; 02763 else if (event->type == MINUSKEY && event->val==KM_PRESS) { 02764 button_activate_state(C, but, BUTTON_STATE_NUM_EDITING); 02765 data->value = -data->value; 02766 button_activate_state(C, but, BUTTON_STATE_EXIT); 02767 retval= WM_UI_HANDLER_BREAK; 02768 } 02769 } 02770 } 02771 else if(data->state == BUTTON_STATE_NUM_EDITING) { 02772 if(event->type == ESCKEY) { 02773 data->cancel= 1; 02774 data->escapecancel= 1; 02775 button_activate_state(C, but, BUTTON_STATE_EXIT); 02776 } 02777 else if(event->type == LEFTMOUSE && event->val!=KM_PRESS) { 02778 if(data->dragchange) 02779 button_activate_state(C, but, BUTTON_STATE_EXIT); 02780 else 02781 click= 1; 02782 } 02783 else if(event->type == MOUSEMOVE) { 02784 if(ui_numedit_but_SLI(but, data, event->shift, event->ctrl, mx)) 02785 ui_numedit_apply(C, block, but, data); 02786 } 02787 retval= WM_UI_HANDLER_BREAK; 02788 } 02789 else if(data->state == BUTTON_STATE_TEXT_EDITING) { 02790 ui_do_but_textedit(C, block, but, data, event); 02791 retval= WM_UI_HANDLER_BREAK; 02792 } 02793 else if(data->state == BUTTON_STATE_TEXT_SELECTING) { 02794 ui_do_but_textedit_select(C, block, but, data, event); 02795 retval= WM_UI_HANDLER_BREAK; 02796 } 02797 02798 if(click) { 02799 if (click==2) { 02800 /* nudge slider to the left or right */ 02801 float f, tempf, softmin, softmax, softrange; 02802 int temp; 02803 02804 button_activate_state(C, but, BUTTON_STATE_NUM_EDITING); 02805 02806 softmin= but->softmin; 02807 softmax= but->softmax; 02808 softrange= softmax - softmin; 02809 02810 tempf= data->value; 02811 temp= (int)data->value; 02812 02813 #if 0 02814 if(but->type==SLI) { 02815 f= (float)(mx-but->x1)/(but->x2-but->x1); /* same as below */ 02816 } 02817 else 02818 #endif 02819 { 02820 f= (float)(mx- but->x1)/(but->x2-but->x1); 02821 } 02822 02823 f= softmin + f*softrange; 02824 02825 if(!ui_is_but_float(but)) { 02826 if(f<temp) temp--; 02827 else temp++; 02828 02829 if(temp>=softmin && temp<=softmax) 02830 data->value= temp; 02831 else 02832 data->cancel= 1; 02833 } 02834 else { 02835 if(f<tempf) tempf -= 0.01f; 02836 else tempf += 0.01f; 02837 02838 if(tempf>=softmin && tempf<=softmax) 02839 data->value= tempf; 02840 else 02841 data->cancel= 1; 02842 } 02843 02844 button_activate_state(C, but, BUTTON_STATE_EXIT); 02845 retval= WM_UI_HANDLER_BREAK; 02846 } 02847 else { 02848 /* edit the value directly */ 02849 button_activate_state(C, but, BUTTON_STATE_TEXT_EDITING); 02850 retval= WM_UI_HANDLER_BREAK; 02851 } 02852 } 02853 02854 return retval; 02855 } 02856 02857 static int ui_do_but_SCROLL(bContext *C, uiBlock *block, uiBut *but, uiHandleButtonData *data, wmEvent *event) 02858 { 02859 int mx, my /*, click= 0 */; 02860 int retval= WM_UI_HANDLER_CONTINUE; 02861 int horizontal= (but->x2 - but->x1 > but->y2 - but->y1); 02862 02863 mx= event->x; 02864 my= event->y; 02865 ui_window_to_block(data->region, block, &mx, &my); 02866 02867 if(data->state == BUTTON_STATE_HIGHLIGHT) { 02868 if(event->val==KM_PRESS) { 02869 if(event->type == LEFTMOUSE) { 02870 if(horizontal) { 02871 data->dragstartx= mx; 02872 data->draglastx= mx; 02873 } 02874 else { 02875 data->dragstartx= my; 02876 data->draglastx= my; 02877 } 02878 button_activate_state(C, but, BUTTON_STATE_NUM_EDITING); 02879 retval= WM_UI_HANDLER_BREAK; 02880 } 02881 /* UNUSED - otherwise code is ok, add back if needed */ 02882 /* else if(ELEM(event->type, PADENTER, RETKEY) && event->val==KM_PRESS) 02883 click= 1; 02884 */ 02885 } 02886 } 02887 else if(data->state == BUTTON_STATE_NUM_EDITING) { 02888 if(event->type == ESCKEY) { 02889 data->cancel= 1; 02890 data->escapecancel= 1; 02891 button_activate_state(C, but, BUTTON_STATE_EXIT); 02892 } 02893 else if(event->type == LEFTMOUSE && event->val!=KM_PRESS) { 02894 button_activate_state(C, but, BUTTON_STATE_EXIT); 02895 } 02896 else if(event->type == MOUSEMOVE) { 02897 if(ui_numedit_but_SLI(but, data, 0, 0, (horizontal)? mx: my)) 02898 ui_numedit_apply(C, block, but, data); 02899 } 02900 02901 retval= WM_UI_HANDLER_BREAK; 02902 } 02903 02904 return retval; 02905 } 02906 02907 02908 static int ui_do_but_BLOCK(bContext *C, uiBut *but, uiHandleButtonData *data, wmEvent *event) 02909 { 02910 02911 if(data->state == BUTTON_STATE_HIGHLIGHT) { 02912 02913 /* first handle click on icondrag type button */ 02914 if(event->type==LEFTMOUSE && but->dragpoin && event->val==KM_PRESS) { 02915 if(ui_but_mouse_inside_icon(but, data->region, event)) { 02916 button_activate_state(C, but, BUTTON_STATE_WAIT_DRAG); 02917 data->dragstartx= event->x; 02918 data->dragstarty= event->y; 02919 return WM_UI_HANDLER_BREAK; 02920 } 02921 } 02922 02923 /* regular open menu */ 02924 if(ELEM3(event->type, LEFTMOUSE, PADENTER, RETKEY) && event->val==KM_PRESS) { 02925 button_activate_state(C, but, BUTTON_STATE_MENU_OPEN); 02926 return WM_UI_HANDLER_BREAK; 02927 } 02928 else if(ELEM3(but->type, MENU, ICONROW, ICONTEXTROW)) { 02929 02930 if(event->type == WHEELDOWNMOUSE && event->alt) { 02931 data->value= ui_step_name_menu(but, -1); 02932 button_activate_state(C, but, BUTTON_STATE_EXIT); 02933 ui_apply_button(C, but->block, but, data, 1); 02934 return WM_UI_HANDLER_BREAK; 02935 } 02936 else if(event->type == WHEELUPMOUSE && event->alt) { 02937 data->value= ui_step_name_menu(but, 1); 02938 button_activate_state(C, but, BUTTON_STATE_EXIT); 02939 ui_apply_button(C, but->block, but, data, 1); 02940 return WM_UI_HANDLER_BREAK; 02941 } 02942 } 02943 else if(but->type==COL) { 02944 if( ELEM(event->type, WHEELDOWNMOUSE, WHEELUPMOUSE) && event->alt) { 02945 float *hsv= ui_block_hsv_get(but->block); 02946 float col[3]; 02947 02948 ui_get_but_vectorf(but, col); 02949 rgb_to_hsv_compat(col[0], col[1], col[2], hsv, hsv+1, hsv+2); 02950 02951 if(event->type==WHEELDOWNMOUSE) 02952 hsv[2]= CLAMPIS(hsv[2]-0.05f, 0.0f, 1.0f); 02953 else 02954 hsv[2]= CLAMPIS(hsv[2]+0.05f, 0.0f, 1.0f); 02955 02956 hsv_to_rgb(hsv[0], hsv[1], hsv[2], data->vec, data->vec+1, data->vec+2); 02957 ui_set_but_vectorf(but, data->vec); 02958 02959 button_activate_state(C, but, BUTTON_STATE_EXIT); 02960 ui_apply_button(C, but->block, but, data, 1); 02961 return WM_UI_HANDLER_BREAK; 02962 } 02963 } 02964 } 02965 else if(data->state == BUTTON_STATE_WAIT_DRAG) { 02966 02967 /* this function also ends state */ 02968 if(ui_but_start_drag(C, but, data, event)) { 02969 return WM_UI_HANDLER_BREAK; 02970 } 02971 02972 /* outside icon quit, not needed if drag activated */ 02973 if(0==ui_but_mouse_inside_icon(but, data->region, event)) { 02974 button_activate_state(C, but, BUTTON_STATE_EXIT); 02975 data->cancel= 1; 02976 return WM_UI_HANDLER_BREAK; 02977 } 02978 02979 if(event->type==LEFTMOUSE && event->val==KM_RELEASE) { 02980 button_activate_state(C, but, BUTTON_STATE_MENU_OPEN); 02981 return WM_UI_HANDLER_BREAK; 02982 } 02983 02984 } 02985 02986 return WM_UI_HANDLER_CONTINUE; 02987 } 02988 02989 static int ui_numedit_but_NORMAL(uiBut *but, uiHandleButtonData *data, int mx, int my) 02990 { 02991 float dx, dy, rad, radsq, mrad, *fp; 02992 int mdx, mdy, changed= 1; 02993 02994 /* button is presumed square */ 02995 /* if mouse moves outside of sphere, it does negative normal */ 02996 02997 fp= data->origvec; 02998 rad= (but->x2 - but->x1); 02999 radsq= rad*rad; 03000 03001 if(fp[2]>0.0f) { 03002 mdx= (rad*fp[0]); 03003 mdy= (rad*fp[1]); 03004 } 03005 else if(fp[2]> -1.0f) { 03006 mrad= rad/sqrtf(fp[0]*fp[0] + fp[1]*fp[1]); 03007 03008 mdx= 2.0f*mrad*fp[0] - (rad*fp[0]); 03009 mdy= 2.0f*mrad*fp[1] - (rad*fp[1]); 03010 } 03011 else mdx= mdy= 0; 03012 03013 dx= (float)(mx+mdx-data->dragstartx); 03014 dy= (float)(my+mdy-data->dragstarty); 03015 03016 fp= data->vec; 03017 mrad= dx*dx+dy*dy; 03018 if(mrad < radsq) { /* inner circle */ 03019 fp[0]= dx; 03020 fp[1]= dy; 03021 fp[2]= sqrt( radsq-dx*dx-dy*dy ); 03022 } 03023 else { /* outer circle */ 03024 03025 mrad= rad/sqrtf(mrad); // veclen 03026 03027 dx*= (2.0f*mrad - 1.0f); 03028 dy*= (2.0f*mrad - 1.0f); 03029 03030 mrad= dx*dx+dy*dy; 03031 if(mrad < radsq) { 03032 fp[0]= dx; 03033 fp[1]= dy; 03034 fp[2]= -sqrt( radsq-dx*dx-dy*dy ); 03035 } 03036 } 03037 normalize_v3(fp); 03038 03039 data->draglastx= mx; 03040 data->draglasty= my; 03041 03042 return changed; 03043 } 03044 03045 static int ui_do_but_NORMAL(bContext *C, uiBlock *block, uiBut *but, uiHandleButtonData *data, wmEvent *event) 03046 { 03047 int mx, my; 03048 03049 mx= event->x; 03050 my= event->y; 03051 ui_window_to_block(data->region, block, &mx, &my); 03052 03053 if(data->state == BUTTON_STATE_HIGHLIGHT) { 03054 if(event->type==LEFTMOUSE && event->val==KM_PRESS) { 03055 data->dragstartx= mx; 03056 data->dragstarty= my; 03057 data->draglastx= mx; 03058 data->draglasty= my; 03059 button_activate_state(C, but, BUTTON_STATE_NUM_EDITING); 03060 03061 /* also do drag the first time */ 03062 if(ui_numedit_but_NORMAL(but, data, mx, my)) 03063 ui_numedit_apply(C, block, but, data); 03064 03065 return WM_UI_HANDLER_BREAK; 03066 } 03067 } 03068 else if(data->state == BUTTON_STATE_NUM_EDITING) { 03069 if(event->type == MOUSEMOVE) { 03070 if(mx!=data->draglastx || my!=data->draglasty) { 03071 if(ui_numedit_but_NORMAL(but, data, mx, my)) 03072 ui_numedit_apply(C, block, but, data); 03073 } 03074 } 03075 else if(event->type==LEFTMOUSE && event->val!=KM_PRESS) 03076 button_activate_state(C, but, BUTTON_STATE_EXIT); 03077 03078 return WM_UI_HANDLER_BREAK; 03079 } 03080 03081 return WM_UI_HANDLER_CONTINUE; 03082 } 03083 03084 static int ui_numedit_but_HSVCUBE(uiBut *but, uiHandleButtonData *data, int mx, int my) 03085 { 03086 float rgb[3]; 03087 float *hsv= ui_block_hsv_get(but->block); 03088 float x, y; 03089 int changed= 1; 03090 int color_profile = but->block->color_profile; 03091 03092 if (but->rnaprop) { 03093 if (RNA_property_subtype(but->rnaprop) == PROP_COLOR_GAMMA) 03094 color_profile = BLI_PR_NONE; 03095 } 03096 03097 ui_get_but_vectorf(but, rgb); 03098 03099 rgb_to_hsv_compat(rgb[0], rgb[1], rgb[2], hsv, hsv+1, hsv+2); 03100 03101 /* relative position within box */ 03102 x= ((float)mx-but->x1)/(but->x2-but->x1); 03103 y= ((float)my-but->y1)/(but->y2-but->y1); 03104 CLAMP(x, 0.0f, 1.0f); 03105 CLAMP(y, 0.0f, 1.0f); 03106 03107 switch((int)but->a1) { 03108 case UI_GRAD_SV: 03109 hsv[2]= x; 03110 hsv[1]= y; 03111 break; 03112 case UI_GRAD_HV: 03113 hsv[0]= x; 03114 hsv[2]= y; 03115 break; 03116 case UI_GRAD_HS: 03117 hsv[0]= x; 03118 hsv[1]= y; 03119 break; 03120 case UI_GRAD_H: 03121 hsv[0]= x; 03122 break; 03123 case UI_GRAD_S: 03124 hsv[1]= x; 03125 break; 03126 case UI_GRAD_V: 03127 hsv[2]= x; 03128 break; 03129 case UI_GRAD_V_ALT: 03130 /* vertical 'value' strip */ 03131 03132 /* exception only for value strip - use the range set in but->min/max */ 03133 hsv[2] = y * (but->softmax - but->softmin) + but->softmin; 03134 03135 if (color_profile) 03136 hsv[2] = srgb_to_linearrgb(hsv[2]); 03137 03138 if (hsv[2] > but->softmax) 03139 hsv[2] = but->softmax; 03140 break; 03141 default: 03142 assert(!"invalid hsv type"); 03143 } 03144 03145 hsv_to_rgb(hsv[0], hsv[1], hsv[2], rgb, rgb+1, rgb+2); 03146 copy_v3_v3(data->vec, rgb); 03147 03148 data->draglastx= mx; 03149 data->draglasty= my; 03150 03151 return changed; 03152 } 03153 03154 static int ui_do_but_HSVCUBE(bContext *C, uiBlock *block, uiBut *but, uiHandleButtonData *data, wmEvent *event) 03155 { 03156 int mx, my; 03157 03158 mx= event->x; 03159 my= event->y; 03160 ui_window_to_block(data->region, block, &mx, &my); 03161 03162 if(data->state == BUTTON_STATE_HIGHLIGHT) { 03163 if(event->type==LEFTMOUSE && event->val==KM_PRESS) { 03164 data->dragstartx= mx; 03165 data->dragstarty= my; 03166 data->draglastx= mx; 03167 data->draglasty= my; 03168 button_activate_state(C, but, BUTTON_STATE_NUM_EDITING); 03169 03170 /* also do drag the first time */ 03171 if(ui_numedit_but_HSVCUBE(but, data, mx, my)) 03172 ui_numedit_apply(C, block, but, data); 03173 03174 return WM_UI_HANDLER_BREAK; 03175 } 03176 /* XXX hardcoded keymap check.... */ 03177 else if (ELEM(event->type, ZEROKEY, PAD0) && event->val == KM_PRESS) { 03178 if (but->a1==UI_GRAD_V_ALT){ 03179 int len; 03180 03181 /* reset only value */ 03182 03183 len= RNA_property_array_length(&but->rnapoin, but->rnaprop); 03184 if (len >= 3) { 03185 float rgb[3], def_hsv[3]; 03186 float *def; 03187 float *hsv= ui_block_hsv_get(but->block); 03188 def= MEM_callocN(sizeof(float)*len, "reset_defaults - float"); 03189 03190 RNA_property_float_get_default_array(&but->rnapoin, but->rnaprop, def); 03191 rgb_to_hsv(def[0], def[1], def[2], def_hsv, def_hsv+1, def_hsv+2); 03192 03193 ui_get_but_vectorf(but, rgb); 03194 rgb_to_hsv_compat(rgb[0], rgb[1], rgb[2], hsv, hsv+1, hsv+2); 03195 03196 hsv_to_rgb(hsv[0], hsv[1], def_hsv[2], rgb, rgb+1, rgb+2); 03197 ui_set_but_vectorf(but, rgb); 03198 03199 RNA_property_update(C, &but->rnapoin, but->rnaprop); 03200 03201 MEM_freeN(def); 03202 } 03203 return WM_UI_HANDLER_BREAK; 03204 } 03205 } 03206 } 03207 else if(data->state == BUTTON_STATE_NUM_EDITING) { 03208 if(event->type == ESCKEY) { 03209 data->cancel= 1; 03210 data->escapecancel= 1; 03211 button_activate_state(C, but, BUTTON_STATE_EXIT); 03212 } 03213 else if(event->type == MOUSEMOVE) { 03214 if(mx!=data->draglastx || my!=data->draglasty) { 03215 if(ui_numedit_but_HSVCUBE(but, data, mx, my)) 03216 ui_numedit_apply(C, block, but, data); 03217 } 03218 } 03219 else if(event->type==LEFTMOUSE && event->val!=KM_PRESS) 03220 button_activate_state(C, but, BUTTON_STATE_EXIT); 03221 03222 return WM_UI_HANDLER_BREAK; 03223 } 03224 03225 return WM_UI_HANDLER_CONTINUE; 03226 } 03227 03228 static int ui_numedit_but_HSVCIRCLE(uiBut *but, uiHandleButtonData *data, int mx, int my, int shift) 03229 { 03230 rcti rect; 03231 int changed= 1; 03232 float rgb[3]; 03233 float hsv[3]; 03234 03235 rect.xmin= but->x1; rect.xmax= but->x2; 03236 rect.ymin= but->y1; rect.ymax= but->y2; 03237 03238 ui_get_but_vectorf(but, rgb); 03239 copy_v3_v3(hsv, ui_block_hsv_get(but->block)); 03240 rgb_to_hsv_compat(rgb[0], rgb[1], rgb[2], hsv, hsv+1, hsv+2); 03241 03242 /* exception, when using color wheel in 'locked' value state: 03243 * allow choosing a hue for black values, by giving a tiny increment */ 03244 if (but->flag & UI_BUT_COLOR_LOCK) { // lock 03245 if (hsv[2] == 0.f) hsv[2] = 0.0001f; 03246 } 03247 03248 if(U.uiflag & USER_CONTINUOUS_MOUSE) { 03249 float fac= shift ? 0.05f : 1.0f; 03250 /* slow down the mouse, this is fairly picky */ 03251 mx = (data->dragstartx*(1.0f-fac) + mx*fac); 03252 my = (data->dragstarty*(1.0f-fac) + my*fac); 03253 } 03254 03255 ui_hsvcircle_vals_from_pos(hsv, hsv+1, &rect, (float)mx, (float)my); 03256 03257 if(but->flag & UI_BUT_COLOR_CUBIC) 03258 hsv[1]= 1.0f - sqrt3f(1.0f - hsv[1]); 03259 03260 hsv_to_rgb(hsv[0], hsv[1], hsv[2], rgb, rgb+1, rgb+2); 03261 03262 if((but->flag & UI_BUT_VEC_SIZE_LOCK) && (rgb[0] || rgb[1] || rgb[2])) { 03263 normalize_v3(rgb); 03264 mul_v3_fl(rgb, but->a2); 03265 } 03266 03267 ui_set_but_vectorf(but, rgb); 03268 03269 data->draglastx= mx; 03270 data->draglasty= my; 03271 03272 return changed; 03273 } 03274 03275 03276 static int ui_do_but_HSVCIRCLE(bContext *C, uiBlock *block, uiBut *but, uiHandleButtonData *data, wmEvent *event) 03277 { 03278 int mx, my; 03279 03280 mx= event->x; 03281 my= event->y; 03282 ui_window_to_block(data->region, block, &mx, &my); 03283 03284 if(data->state == BUTTON_STATE_HIGHLIGHT) { 03285 if(event->type==LEFTMOUSE && event->val==KM_PRESS) { 03286 data->dragstartx= mx; 03287 data->dragstarty= my; 03288 data->draglastx= mx; 03289 data->draglasty= my; 03290 button_activate_state(C, but, BUTTON_STATE_NUM_EDITING); 03291 03292 /* also do drag the first time */ 03293 if(ui_numedit_but_HSVCIRCLE(but, data, mx, my, event->shift)) 03294 ui_numedit_apply(C, block, but, data); 03295 03296 return WM_UI_HANDLER_BREAK; 03297 } 03298 /* XXX hardcoded keymap check.... */ 03299 else if (ELEM(event->type, ZEROKEY, PAD0) && event->val == KM_PRESS) { 03300 int len; 03301 03302 /* reset only saturation */ 03303 03304 len= RNA_property_array_length(&but->rnapoin, but->rnaprop); 03305 if (len >= 3) { 03306 float rgb[3], def_hsv[3]; 03307 float *def; 03308 float *hsv= ui_block_hsv_get(but->block); 03309 def= MEM_callocN(sizeof(float)*len, "reset_defaults - float"); 03310 03311 RNA_property_float_get_default_array(&but->rnapoin, but->rnaprop, def); 03312 rgb_to_hsv(def[0], def[1], def[2], def_hsv, def_hsv+1, def_hsv+2); 03313 03314 ui_get_but_vectorf(but, rgb); 03315 rgb_to_hsv_compat(rgb[0], rgb[1], rgb[2], hsv, hsv+1, hsv+2); 03316 03317 hsv_to_rgb(hsv[0], def_hsv[1], hsv[2], rgb, rgb+1, rgb+2); 03318 ui_set_but_vectorf(but, rgb); 03319 03320 RNA_property_update(C, &but->rnapoin, but->rnaprop); 03321 03322 MEM_freeN(def); 03323 } 03324 return WM_UI_HANDLER_BREAK; 03325 } 03326 } 03327 else if(data->state == BUTTON_STATE_NUM_EDITING) { 03328 if(event->type == ESCKEY) { 03329 data->cancel= 1; 03330 data->escapecancel= 1; 03331 button_activate_state(C, but, BUTTON_STATE_EXIT); 03332 } 03333 /* XXX hardcoded keymap check.... */ 03334 else if(event->type == WHEELDOWNMOUSE) { 03335 float *hsv= ui_block_hsv_get(but->block); 03336 hsv[2]= CLAMPIS(hsv[2]-0.05f, 0.0f, 1.0f); 03337 ui_set_but_hsv(but); // converts to rgb 03338 ui_numedit_apply(C, block, but, data); 03339 } 03340 else if(event->type == WHEELUPMOUSE) { 03341 float *hsv= ui_block_hsv_get(but->block); 03342 hsv[2]= CLAMPIS(hsv[2]+0.05f, 0.0f, 1.0f); 03343 ui_set_but_hsv(but); // converts to rgb 03344 ui_numedit_apply(C, block, but, data); 03345 } 03346 else if(event->type == MOUSEMOVE) { 03347 if(mx!=data->draglastx || my!=data->draglasty) { 03348 if(ui_numedit_but_HSVCIRCLE(but, data, mx, my, event->shift)) 03349 ui_numedit_apply(C, block, but, data); 03350 } 03351 } 03352 else if(event->type==LEFTMOUSE && event->val!=KM_PRESS) { 03353 button_activate_state(C, but, BUTTON_STATE_EXIT); 03354 } 03355 return WM_UI_HANDLER_BREAK; 03356 } 03357 03358 return WM_UI_HANDLER_CONTINUE; 03359 } 03360 03361 03362 static int verg_colorband(const void *a1, const void *a2) 03363 { 03364 const CBData *x1=a1, *x2=a2; 03365 03366 if( x1->pos > x2->pos ) return 1; 03367 else if( x1->pos < x2->pos) return -1; 03368 return WM_UI_HANDLER_CONTINUE; 03369 } 03370 03371 static void ui_colorband_update(ColorBand *coba) 03372 { 03373 int a; 03374 03375 if(coba->tot<2) return; 03376 03377 for(a=0; a<coba->tot; a++) coba->data[a].cur= a; 03378 qsort(coba->data, coba->tot, sizeof(CBData), verg_colorband); 03379 for(a=0; a<coba->tot; a++) { 03380 if(coba->data[a].cur==coba->cur) { 03381 coba->cur= a; 03382 break; 03383 } 03384 } 03385 } 03386 03387 static int ui_numedit_but_COLORBAND(uiBut *but, uiHandleButtonData *data, int mx) 03388 { 03389 float dx; 03390 int changed= 0; 03391 03392 if(data->draglastx == mx) 03393 return changed; 03394 03395 dx= ((float)(mx - data->draglastx))/(but->x2-but->x1); 03396 data->dragcbd->pos += dx; 03397 CLAMP(data->dragcbd->pos, 0.0f, 1.0f); 03398 03399 ui_colorband_update(data->coba); 03400 data->dragcbd= data->coba->data + data->coba->cur; /* because qsort */ 03401 03402 data->draglastx= mx; 03403 changed= 1; 03404 03405 return changed; 03406 } 03407 03408 static int ui_do_but_COLORBAND(bContext *C, uiBlock *block, uiBut *but, uiHandleButtonData *data, wmEvent *event) 03409 { 03410 ColorBand *coba; 03411 CBData *cbd; 03412 int mx, my, a, xco, mindist= 12; 03413 03414 mx= event->x; 03415 my= event->y; 03416 ui_window_to_block(data->region, block, &mx, &my); 03417 03418 if(data->state == BUTTON_STATE_HIGHLIGHT) { 03419 if(event->type==LEFTMOUSE && event->val==KM_PRESS) { 03420 coba= (ColorBand*)but->poin; 03421 03422 if(event->ctrl) { 03423 /* insert new key on mouse location */ 03424 float pos= ((float)(mx - but->x1))/(but->x2-but->x1); 03425 colorband_element_add(coba, pos); 03426 button_activate_state(C, but, BUTTON_STATE_EXIT); 03427 } 03428 else { 03429 data->dragstartx= mx; 03430 data->dragstarty= my; 03431 data->draglastx= mx; 03432 data->draglasty= my; 03433 03434 /* activate new key when mouse is close */ 03435 for(a=0, cbd= coba->data; a<coba->tot; a++, cbd++) { 03436 xco= but->x1 + (cbd->pos*(but->x2-but->x1)); 03437 xco= ABS(xco-mx); 03438 if(a==coba->cur) xco+= 5; // selected one disadvantage 03439 if(xco<mindist) { 03440 coba->cur= a; 03441 mindist= xco; 03442 } 03443 } 03444 03445 data->dragcbd= coba->data + coba->cur; 03446 button_activate_state(C, but, BUTTON_STATE_NUM_EDITING); 03447 } 03448 03449 return WM_UI_HANDLER_BREAK; 03450 } 03451 } 03452 else if(data->state == BUTTON_STATE_NUM_EDITING) { 03453 if(event->type == MOUSEMOVE) { 03454 if(mx!=data->draglastx || my!=data->draglasty) { 03455 if(ui_numedit_but_COLORBAND(but, data, mx)) 03456 ui_numedit_apply(C, block, but, data); 03457 } 03458 } 03459 else if(event->type==LEFTMOUSE && event->val!=KM_PRESS) 03460 button_activate_state(C, but, BUTTON_STATE_EXIT); 03461 03462 return WM_UI_HANDLER_BREAK; 03463 } 03464 03465 return WM_UI_HANDLER_CONTINUE; 03466 } 03467 03468 static int ui_numedit_but_CURVE(uiBut *but, uiHandleButtonData *data, int snap, int mx, int my) 03469 { 03470 CurveMapping *cumap= (CurveMapping*)but->poin; 03471 CurveMap *cuma= cumap->cm+cumap->cur; 03472 CurveMapPoint *cmp= cuma->curve; 03473 float fx, fy, zoomx, zoomy /*, offsx, offsy */ /* UNUSED */; 03474 int a, changed= 0; 03475 03476 zoomx= (but->x2-but->x1)/(cumap->curr.xmax-cumap->curr.xmin); 03477 zoomy= (but->y2-but->y1)/(cumap->curr.ymax-cumap->curr.ymin); 03478 /* offsx= cumap->curr.xmin; */ 03479 /* offsy= cumap->curr.ymin; */ 03480 03481 if(snap) { 03482 float d[2]; 03483 03484 d[0]= mx - data->dragstartx; 03485 d[1]= my - data->dragstarty; 03486 03487 if(len_v2(d) < 3.0f) 03488 snap= 0; 03489 } 03490 03491 if(data->dragsel != -1) { 03492 int moved_point= 0; /* for ctrl grid, can't use orig coords because of sorting */ 03493 03494 fx= (mx-data->draglastx)/zoomx; 03495 fy= (my-data->draglasty)/zoomy; 03496 for(a=0; a<cuma->totpoint; a++) { 03497 if(cmp[a].flag & SELECT) { 03498 float origx= cmp[a].x, origy= cmp[a].y; 03499 cmp[a].x+= fx; 03500 cmp[a].y+= fy; 03501 if(snap) { 03502 cmp[a].x= 0.125f*floorf(0.5f + 8.0f*cmp[a].x); 03503 cmp[a].y= 0.125f*floorf(0.5f + 8.0f*cmp[a].y); 03504 } 03505 if(cmp[a].x!=origx || cmp[a].y!=origy) 03506 moved_point= 1; 03507 } 03508 } 03509 03510 curvemapping_changed(cumap, 0); /* no remove doubles */ 03511 03512 if(moved_point) { 03513 data->draglastx= mx; 03514 data->draglasty= my; 03515 changed= 1; 03516 } 03517 03518 data->dragchange= 1; /* mark for selection */ 03519 } 03520 else { 03521 fx= (mx-data->draglastx)/zoomx; 03522 fy= (my-data->draglasty)/zoomy; 03523 03524 /* clamp for clip */ 03525 if(cumap->flag & CUMA_DO_CLIP) { 03526 if(cumap->curr.xmin-fx < cumap->clipr.xmin) 03527 fx= cumap->curr.xmin - cumap->clipr.xmin; 03528 else if(cumap->curr.xmax-fx > cumap->clipr.xmax) 03529 fx= cumap->curr.xmax - cumap->clipr.xmax; 03530 if(cumap->curr.ymin-fy < cumap->clipr.ymin) 03531 fy= cumap->curr.ymin - cumap->clipr.ymin; 03532 else if(cumap->curr.ymax-fy > cumap->clipr.ymax) 03533 fy= cumap->curr.ymax - cumap->clipr.ymax; 03534 } 03535 03536 cumap->curr.xmin-=fx; 03537 cumap->curr.ymin-=fy; 03538 cumap->curr.xmax-=fx; 03539 cumap->curr.ymax-=fy; 03540 03541 data->draglastx= mx; 03542 data->draglasty= my; 03543 03544 changed= 1; 03545 } 03546 03547 return changed; 03548 } 03549 03550 static int ui_do_but_CURVE(bContext *C, uiBlock *block, uiBut *but, uiHandleButtonData *data, wmEvent *event) 03551 { 03552 int mx, my, a, changed= 0; 03553 03554 mx= event->x; 03555 my= event->y; 03556 ui_window_to_block(data->region, block, &mx, &my); 03557 03558 if(data->state == BUTTON_STATE_HIGHLIGHT) { 03559 if(event->type==LEFTMOUSE && event->val==KM_PRESS) { 03560 CurveMapping *cumap= (CurveMapping*)but->poin; 03561 CurveMap *cuma= cumap->cm+cumap->cur; 03562 CurveMapPoint *cmp; 03563 float fx, fy, zoomx, zoomy, offsx, offsy; 03564 float dist, mindist= 200.0f; // 14 pixels radius 03565 int sel= -1; 03566 03567 zoomx= (but->x2-but->x1)/(cumap->curr.xmax-cumap->curr.xmin); 03568 zoomy= (but->y2-but->y1)/(cumap->curr.ymax-cumap->curr.ymin); 03569 offsx= cumap->curr.xmin; 03570 offsy= cumap->curr.ymin; 03571 03572 if(event->ctrl) { 03573 fx= ((float)my - but->x1)/zoomx + offsx; 03574 fy= ((float)my - but->y1)/zoomy + offsy; 03575 03576 curvemap_insert(cuma, fx, fy); 03577 curvemapping_changed(cumap, 0); 03578 changed= 1; 03579 } 03580 03581 /* check for selecting of a point */ 03582 cmp= cuma->curve; /* ctrl adds point, new malloc */ 03583 for(a=0; a<cuma->totpoint; a++) { 03584 fx= but->x1 + zoomx*(cmp[a].x-offsx); 03585 fy= but->y1 + zoomy*(cmp[a].y-offsy); 03586 dist= (fx-mx)*(fx-mx) + (fy-my)*(fy-my); 03587 if(dist < mindist) { 03588 sel= a; 03589 mindist= dist; 03590 } 03591 } 03592 03593 if (sel == -1) { 03594 /* if the click didn't select anything, check if it's clicked on the 03595 * curve itself, and if so, add a point */ 03596 fx= ((float)mx - but->x1)/zoomx + offsx; 03597 fy= ((float)my - but->y1)/zoomy + offsy; 03598 03599 cmp= cuma->table; 03600 03601 /* loop through the curve segment table and find what's near the mouse. 03602 * 0.05 is kinda arbitrary, but seems to be what works nicely. */ 03603 for(a=0; a<=CM_TABLE; a++) { 03604 if ( ( fabs(fx - cmp[a].x) < (0.05) ) && ( fabs(fy - cmp[a].y) < (0.05) ) ) { 03605 03606 curvemap_insert(cuma, fx, fy); 03607 curvemapping_changed(cumap, 0); 03608 03609 changed= 1; 03610 03611 /* reset cmp back to the curve points again, rather than drawing segments */ 03612 cmp= cuma->curve; 03613 03614 /* find newly added point and make it 'sel' */ 03615 for(a=0; a<cuma->totpoint; a++) 03616 if(cmp[a].x == fx) 03617 sel = a; 03618 03619 break; 03620 } 03621 } 03622 } 03623 03624 if(sel!= -1) { 03625 /* ok, we move a point */ 03626 /* deselect all if this one is deselect. except if we hold shift */ 03627 if(event->shift==0) { 03628 for(a=0; a<cuma->totpoint; a++) 03629 cmp[a].flag &= ~SELECT; 03630 cmp[sel].flag |= SELECT; 03631 } 03632 else 03633 cmp[sel].flag ^= SELECT; 03634 } 03635 else { 03636 /* move the view */ 03637 data->cancel= 1; 03638 } 03639 03640 data->dragsel= sel; 03641 03642 data->dragstartx= mx; 03643 data->dragstarty= my; 03644 data->draglastx= mx; 03645 data->draglasty= my; 03646 03647 button_activate_state(C, but, BUTTON_STATE_NUM_EDITING); 03648 return WM_UI_HANDLER_BREAK; 03649 } 03650 } 03651 else if(data->state == BUTTON_STATE_NUM_EDITING) { 03652 if(event->type == MOUSEMOVE) { 03653 if(mx!=data->draglastx || my!=data->draglasty) { 03654 if(ui_numedit_but_CURVE(but, data, event->ctrl, mx, my)) 03655 ui_numedit_apply(C, block, but, data); 03656 } 03657 } 03658 else if(event->type==LEFTMOUSE && event->val!=KM_PRESS) { 03659 if(data->dragsel != -1) { 03660 CurveMapping *cumap= (CurveMapping*)but->poin; 03661 CurveMap *cuma= cumap->cm+cumap->cur; 03662 CurveMapPoint *cmp= cuma->curve; 03663 03664 if(!data->dragchange) { 03665 /* deselect all, select one */ 03666 if(event->shift==0) { 03667 for(a=0; a<cuma->totpoint; a++) 03668 cmp[a].flag &= ~SELECT; 03669 cmp[data->dragsel].flag |= SELECT; 03670 } 03671 } 03672 else 03673 curvemapping_changed(cumap, 1); /* remove doubles */ 03674 } 03675 03676 button_activate_state(C, but, BUTTON_STATE_EXIT); 03677 } 03678 03679 return WM_UI_HANDLER_BREAK; 03680 } 03681 03682 /* UNUSED but keep for now */ 03683 (void)changed; 03684 03685 return WM_UI_HANDLER_CONTINUE; 03686 } 03687 03688 static int in_scope_resize_zone(uiBut *but, int UNUSED(x), int y) 03689 { 03690 // bottom corner return (x > but->x2 - SCOPE_RESIZE_PAD) && (y < but->y1 + SCOPE_RESIZE_PAD); 03691 return (y < but->y1 + SCOPE_RESIZE_PAD); 03692 } 03693 03694 static int ui_numedit_but_HISTOGRAM(uiBut *but, uiHandleButtonData *data, int mx, int my) 03695 { 03696 Histogram *hist = (Histogram *)but->poin; 03697 /* rcti rect; */ 03698 int changed= 1; 03699 float /* dx, */ dy, yfac=1.f; /* UNUSED */ 03700 03701 /* rect.xmin= but->x1; rect.xmax= but->x2; */ 03702 /* rect.ymin= but->y1; rect.ymax= but->y2; */ 03703 03704 /* dx = mx - data->draglastx; */ /* UNUSED */ 03705 dy = my - data->draglasty; 03706 03707 03708 if (in_scope_resize_zone(but, data->dragstartx, data->dragstarty)) { 03709 /* resize histogram widget itself */ 03710 hist->height = (but->y2 - but->y1) + (data->dragstarty - my); 03711 } else { 03712 /* scale histogram values */ 03713 yfac = MIN2(powf(hist->ymax, 2.f), 1.f) * 0.5f; 03714 hist->ymax += dy * yfac; 03715 03716 CLAMP(hist->ymax, 1.f, 100.f); 03717 } 03718 03719 data->draglastx= mx; 03720 data->draglasty= my; 03721 03722 return changed; 03723 } 03724 03725 static int ui_do_but_HISTOGRAM(bContext *C, uiBlock *block, uiBut *but, uiHandleButtonData *data, wmEvent *event) 03726 { 03727 int mx, my; 03728 03729 mx= event->x; 03730 my= event->y; 03731 ui_window_to_block(data->region, block, &mx, &my); 03732 03733 if(data->state == BUTTON_STATE_HIGHLIGHT) { 03734 if(event->type==LEFTMOUSE && event->val==KM_PRESS) { 03735 data->dragstartx= mx; 03736 data->dragstarty= my; 03737 data->draglastx= mx; 03738 data->draglasty= my; 03739 button_activate_state(C, but, BUTTON_STATE_NUM_EDITING); 03740 03741 /* also do drag the first time */ 03742 if(ui_numedit_but_HISTOGRAM(but, data, mx, my)) 03743 ui_numedit_apply(C, block, but, data); 03744 03745 return WM_UI_HANDLER_BREAK; 03746 } 03747 /* XXX hardcoded keymap check.... */ 03748 else if (ELEM(event->type, ZEROKEY, PAD0) && event->val == KM_PRESS) { 03749 Histogram *hist = (Histogram *)but->poin; 03750 hist->ymax = 1.f; 03751 03752 button_activate_state(C, but, BUTTON_STATE_EXIT); 03753 return WM_UI_HANDLER_BREAK; 03754 } 03755 } 03756 else if(data->state == BUTTON_STATE_NUM_EDITING) { 03757 if(event->type == ESCKEY) { 03758 data->cancel= 1; 03759 data->escapecancel= 1; 03760 button_activate_state(C, but, BUTTON_STATE_EXIT); 03761 } 03762 else if(event->type == MOUSEMOVE) { 03763 if(mx!=data->draglastx || my!=data->draglasty) { 03764 if(ui_numedit_but_HISTOGRAM(but, data, mx, my)) 03765 ui_numedit_apply(C, block, but, data); 03766 } 03767 } 03768 else if(event->type==LEFTMOUSE && event->val!=KM_PRESS) { 03769 button_activate_state(C, but, BUTTON_STATE_EXIT); 03770 } 03771 return WM_UI_HANDLER_BREAK; 03772 } 03773 03774 return WM_UI_HANDLER_CONTINUE; 03775 } 03776 03777 static int ui_numedit_but_WAVEFORM(uiBut *but, uiHandleButtonData *data, int mx, int my) 03778 { 03779 Scopes *scopes = (Scopes *)but->poin; 03780 /* rcti rect; */ 03781 int changed= 1; 03782 float /* dx, */ dy /* , yfac=1.f */; /* UNUSED */ 03783 03784 /* rect.xmin= but->x1; rect.xmax= but->x2; */ 03785 /* rect.ymin= but->y1; rect.ymax= but->y2; */ 03786 03787 /* dx = mx - data->draglastx; */ /* UNUSED */ 03788 dy = my - data->draglasty; 03789 03790 03791 if (in_scope_resize_zone(but, data->dragstartx, data->dragstarty)) { 03792 /* resize waveform widget itself */ 03793 scopes->wavefrm_height = (but->y2 - but->y1) + (data->dragstarty - my); 03794 } else { 03795 /* scale waveform values */ 03796 /* yfac = scopes->wavefrm_yfac; */ /* UNUSED */ 03797 scopes->wavefrm_yfac += dy/200.0f; 03798 03799 CLAMP(scopes->wavefrm_yfac, 0.5f, 2.f); 03800 } 03801 03802 data->draglastx= mx; 03803 data->draglasty= my; 03804 03805 return changed; 03806 } 03807 03808 static int ui_do_but_WAVEFORM(bContext *C, uiBlock *block, uiBut *but, uiHandleButtonData *data, wmEvent *event) 03809 { 03810 int mx, my; 03811 03812 mx= event->x; 03813 my= event->y; 03814 ui_window_to_block(data->region, block, &mx, &my); 03815 03816 if(data->state == BUTTON_STATE_HIGHLIGHT) { 03817 if(event->type==LEFTMOUSE && event->val==KM_PRESS) { 03818 data->dragstartx= mx; 03819 data->dragstarty= my; 03820 data->draglastx= mx; 03821 data->draglasty= my; 03822 button_activate_state(C, but, BUTTON_STATE_NUM_EDITING); 03823 03824 /* also do drag the first time */ 03825 if(ui_numedit_but_WAVEFORM(but, data, mx, my)) 03826 ui_numedit_apply(C, block, but, data); 03827 03828 return WM_UI_HANDLER_BREAK; 03829 } 03830 /* XXX hardcoded keymap check.... */ 03831 else if (ELEM(event->type, ZEROKEY, PAD0) && event->val == KM_PRESS) { 03832 Scopes *scopes = (Scopes *)but->poin; 03833 scopes->wavefrm_yfac = 1.f; 03834 03835 button_activate_state(C, but, BUTTON_STATE_EXIT); 03836 return WM_UI_HANDLER_BREAK; 03837 } 03838 } 03839 else if(data->state == BUTTON_STATE_NUM_EDITING) { 03840 if(event->type == ESCKEY) { 03841 data->cancel= 1; 03842 data->escapecancel= 1; 03843 button_activate_state(C, but, BUTTON_STATE_EXIT); 03844 } 03845 else if(event->type == MOUSEMOVE) { 03846 if(mx!=data->draglastx || my!=data->draglasty) { 03847 if(ui_numedit_but_WAVEFORM(but, data, mx, my)) 03848 ui_numedit_apply(C, block, but, data); 03849 } 03850 } 03851 else if(event->type==LEFTMOUSE && event->val!=KM_PRESS) { 03852 button_activate_state(C, but, BUTTON_STATE_EXIT); 03853 } 03854 return WM_UI_HANDLER_BREAK; 03855 } 03856 03857 return WM_UI_HANDLER_CONTINUE; 03858 } 03859 03860 static int ui_numedit_but_VECTORSCOPE(uiBut *but, uiHandleButtonData *data, int mx, int my) 03861 { 03862 Scopes *scopes = (Scopes *)but->poin; 03863 /* rcti rect; */ 03864 int changed= 1; 03865 /* float dx, dy; */ 03866 03867 /* rect.xmin= but->x1; rect.xmax= but->x2; */ 03868 /* rect.ymin= but->y1; rect.ymax= but->y2; */ 03869 03870 /* dx = mx - data->draglastx; */ 03871 /* dy = my - data->draglasty; */ 03872 03873 if (in_scope_resize_zone(but, data->dragstartx, data->dragstarty)) { 03874 /* resize vectorscope widget itself */ 03875 scopes->vecscope_height = (but->y2 - but->y1) + (data->dragstarty - my); 03876 } 03877 03878 data->draglastx= mx; 03879 data->draglasty= my; 03880 03881 return changed; 03882 } 03883 03884 static int ui_do_but_VECTORSCOPE(bContext *C, uiBlock *block, uiBut *but, uiHandleButtonData *data, wmEvent *event) 03885 { 03886 int mx, my; 03887 03888 mx= event->x; 03889 my= event->y; 03890 ui_window_to_block(data->region, block, &mx, &my); 03891 03892 if(data->state == BUTTON_STATE_HIGHLIGHT) { 03893 if(event->type==LEFTMOUSE && event->val==KM_PRESS) { 03894 data->dragstartx= mx; 03895 data->dragstarty= my; 03896 data->draglastx= mx; 03897 data->draglasty= my; 03898 button_activate_state(C, but, BUTTON_STATE_NUM_EDITING); 03899 03900 /* also do drag the first time */ 03901 if(ui_numedit_but_VECTORSCOPE(but, data, mx, my)) 03902 ui_numedit_apply(C, block, but, data); 03903 03904 return WM_UI_HANDLER_BREAK; 03905 } 03906 } 03907 else if(data->state == BUTTON_STATE_NUM_EDITING) { 03908 if(event->type == ESCKEY) { 03909 data->cancel= 1; 03910 data->escapecancel= 1; 03911 button_activate_state(C, but, BUTTON_STATE_EXIT); 03912 } 03913 else if(event->type == MOUSEMOVE) { 03914 if(mx!=data->draglastx || my!=data->draglasty) { 03915 if(ui_numedit_but_VECTORSCOPE(but, data, mx, my)) 03916 ui_numedit_apply(C, block, but, data); 03917 } 03918 } 03919 else if(event->type==LEFTMOUSE && event->val!=KM_PRESS) { 03920 button_activate_state(C, but, BUTTON_STATE_EXIT); 03921 } 03922 return WM_UI_HANDLER_BREAK; 03923 } 03924 03925 return WM_UI_HANDLER_CONTINUE; 03926 } 03927 03928 #ifdef INTERNATIONAL 03929 static int ui_do_but_CHARTAB(bContext *UNUSED(C), uiBlock *UNUSED(block), uiBut *UNUSED(but), uiHandleButtonData *UNUSED(data), wmEvent *UNUSED(event)) 03930 { 03931 /* XXX 2.50 bad global and state access */ 03932 #if 0 03933 float sx, sy, ex, ey; 03934 float width, height; 03935 float butw, buth; 03936 int mx, my, x, y, cs, che; 03937 03938 mx= event->x; 03939 my= event->y; 03940 ui_window_to_block(data->region, block, &mx, &my); 03941 03942 if(data->state == BUTTON_STATE_HIGHLIGHT) { 03943 if(ELEM3(event->type, LEFTMOUSE, PADENTER, RETKEY) && event->val==KM_PRESS) { 03944 /* Calculate the size of the button */ 03945 width = abs(but->x2 - but->x1); 03946 height = abs(but->y2 - but->y1); 03947 03948 butw = floor(width / 12); 03949 buth = floor(height / 6); 03950 03951 /* Initialize variables */ 03952 sx = but->x1; 03953 ex = but->x1 + butw; 03954 sy = but->y1 + height - buth; 03955 ey = but->y1 + height; 03956 03957 cs = G.charstart; 03958 03959 /* And the character is */ 03960 x = (int) ((mx / butw) - 0.5); 03961 y = (int) (6 - ((my / buth) - 0.5)); 03962 03963 che = cs + (y*12) + x; 03964 03965 if(che > G.charmax) 03966 che = 0; 03967 03968 if(G.obedit) 03969 { 03970 do_textedit(0,0,che); 03971 } 03972 03973 button_activate_state(C, but, BUTTON_STATE_EXIT); 03974 return WM_UI_HANDLER_BREAK; 03975 } 03976 else if(ELEM(event->type, WHEELUPMOUSE, PAGEUPKEY)) { 03977 for(but= block->buttons.first; but; but= but->next) { 03978 if(but->type == CHARTAB) { 03979 G.charstart = G.charstart - (12*6); 03980 if(G.charstart < 0) 03981 G.charstart = 0; 03982 if(G.charstart < G.charmin) 03983 G.charstart = G.charmin; 03984 ui_draw_but(but); 03985 03986 //Really nasty... to update the num button from the same butblock 03987 for(bt= block->buttons.first; bt; bt= bt->next) 03988 { 03989 if(ELEM(bt->type, NUM, NUMABS)) { 03990 ui_check_but(bt); 03991 ui_draw_but(bt); 03992 } 03993 } 03994 retval=UI_CONT; 03995 break; 03996 } 03997 } 03998 03999 return WM_UI_HANDLER_BREAK; 04000 } 04001 else if(ELEM(event->type, WHEELDOWNMOUSE, PAGEDOWNKEY)) { 04002 for(but= block->buttons.first; but; but= but->next) 04003 { 04004 if(but->type == CHARTAB) 04005 { 04006 G.charstart = G.charstart + (12*6); 04007 if(G.charstart > (0xffff - 12*6)) 04008 G.charstart = 0xffff - (12*6); 04009 if(G.charstart > G.charmax - 12*6) 04010 G.charstart = G.charmax - 12*6; 04011 ui_draw_but(but); 04012 04013 for(bt= block->buttons.first; bt; bt= bt->next) 04014 { 04015 if(ELEM(bt->type, NUM, NUMABS)) { 04016 ui_check_but(bt); 04017 ui_draw_but(bt); 04018 } 04019 } 04020 04021 but->flag |= UI_ACTIVE; 04022 retval=UI_RETURN_OK; 04023 break; 04024 } 04025 } 04026 04027 return WM_UI_HANDLER_BREAK; 04028 } 04029 } 04030 #endif 04031 04032 return WM_UI_HANDLER_CONTINUE; 04033 } 04034 #endif 04035 04036 04037 static int ui_do_but_LINK(bContext *C, uiBut *but, uiHandleButtonData *data, wmEvent *event) 04038 { 04039 VECCOPY2D(but->linkto, event->mval); 04040 04041 if(data->state == BUTTON_STATE_HIGHLIGHT) { 04042 if(event->type == LEFTMOUSE && event->val==KM_PRESS) { 04043 button_activate_state(C, but, BUTTON_STATE_WAIT_RELEASE); 04044 return WM_UI_HANDLER_BREAK; 04045 } 04046 else if(event->type == LEFTMOUSE && but->block->handle) { 04047 button_activate_state(C, but, BUTTON_STATE_EXIT); 04048 return WM_UI_HANDLER_BREAK; 04049 } 04050 } 04051 else if(data->state == BUTTON_STATE_WAIT_RELEASE) { 04052 04053 if(event->type == LEFTMOUSE && event->val!=KM_PRESS) { 04054 if(!(but->flag & UI_SELECT)) 04055 data->cancel= 1; 04056 button_activate_state(C, but, BUTTON_STATE_EXIT); 04057 return WM_UI_HANDLER_BREAK; 04058 } 04059 } 04060 04061 return WM_UI_HANDLER_CONTINUE; 04062 } 04063 04064 static void but_shortcut_name_func(bContext *C, void *arg1, int UNUSED(event)) 04065 { 04066 uiBut *but = (uiBut *)arg1; 04067 04068 if (but->optype) { 04069 char buf[512], *cpoin; 04070 04071 IDProperty *prop= (but->opptr)? but->opptr->data: NULL; 04072 04073 /* complex code to change name of button */ 04074 if(WM_key_event_operator_string(C, but->optype->idname, but->opcontext, prop, buf, sizeof(buf))) { 04075 char *butstr_orig; 04076 04077 // XXX but->str changed... should not, remove the hotkey from it 04078 cpoin= strchr(but->str, '|'); 04079 if(cpoin) *cpoin= 0; 04080 04081 butstr_orig= BLI_strdup(but->str); 04082 BLI_snprintf(but->strdata, sizeof(but->strdata), "%s|%s", butstr_orig, buf); 04083 MEM_freeN(butstr_orig); 04084 but->str= but->strdata; 04085 04086 ui_check_but(but); 04087 } 04088 else { 04089 /* shortcut was removed */ 04090 cpoin= strchr(but->str, '|'); 04091 if(cpoin) *cpoin= 0; 04092 } 04093 } 04094 } 04095 04096 static uiBlock *menu_change_shortcut(bContext *C, ARegion *ar, void *arg) 04097 { 04098 wmWindowManager *wm= CTX_wm_manager(C); 04099 uiBlock *block; 04100 uiBut *but = (uiBut *)arg; 04101 wmKeyMap *km; 04102 wmKeyMapItem *kmi; 04103 PointerRNA ptr; 04104 uiLayout *layout; 04105 uiStyle *style= U.uistyles.first; 04106 IDProperty *prop= (but->opptr)? but->opptr->data: NULL; 04107 int kmi_id = WM_key_event_operator_id(C, but->optype->idname, but->opcontext, prop, 1, &km); 04108 04109 kmi = WM_keymap_item_find_id(km, kmi_id); 04110 04111 RNA_pointer_create(&wm->id, &RNA_KeyMapItem, kmi, &ptr); 04112 04113 block= uiBeginBlock(C, ar, "_popup", UI_EMBOSS); 04114 uiBlockSetHandleFunc(block, but_shortcut_name_func, but); 04115 uiBlockSetFlag(block, UI_BLOCK_MOVEMOUSE_QUIT); 04116 uiBlockSetDirection(block, UI_CENTER); 04117 04118 layout= uiBlockLayout(block, UI_LAYOUT_VERTICAL, UI_LAYOUT_PANEL, 0, 0, 200, 20, style); 04119 04120 uiItemR(layout, &ptr, "type", UI_ITEM_R_FULL_EVENT|UI_ITEM_R_IMMEDIATE, "", ICON_NONE); 04121 04122 uiPopupBoundsBlock(block, 6, -50, 26); 04123 uiEndBlock(C, block); 04124 04125 return block; 04126 } 04127 04128 static uiBlock *menu_add_shortcut(bContext *C, ARegion *ar, void *arg) 04129 { 04130 wmWindowManager *wm= CTX_wm_manager(C); 04131 uiBlock *block; 04132 uiBut *but = (uiBut *)arg; 04133 wmKeyMap *km; 04134 wmKeyMapItem *kmi; 04135 PointerRNA ptr; 04136 uiLayout *layout; 04137 uiStyle *style= U.uistyles.first; 04138 IDProperty *prop= (but->opptr)? but->opptr->data: NULL; 04139 int kmi_id; 04140 04141 /* XXX this guess_opname can potentially return a different keymap than being found on adding later... */ 04142 km = WM_keymap_guess_opname(C, but->optype->idname); 04143 kmi = WM_keymap_add_item(km, but->optype->idname, AKEY, KM_PRESS, 0, 0); 04144 kmi_id = kmi->id; 04145 04146 /* copy properties, prop can be NULL for reset */ 04147 if(prop) 04148 prop= IDP_CopyProperty(prop); 04149 WM_keymap_properties_reset(kmi, prop); 04150 04151 /* update and get pointers again */ 04152 WM_keyconfig_update(wm); 04153 04154 km = WM_keymap_guess_opname(C, but->optype->idname); 04155 kmi = WM_keymap_item_find_id(km, kmi_id); 04156 04157 RNA_pointer_create(&wm->id, &RNA_KeyMapItem, kmi, &ptr); 04158 04159 block= uiBeginBlock(C, ar, "_popup", UI_EMBOSS); 04160 uiBlockSetHandleFunc(block, but_shortcut_name_func, but); 04161 uiBlockSetFlag(block, UI_BLOCK_RET_1); 04162 uiBlockSetDirection(block, UI_CENTER); 04163 04164 layout= uiBlockLayout(block, UI_LAYOUT_VERTICAL, UI_LAYOUT_PANEL, 0, 0, 200, 20, style); 04165 04166 uiItemR(layout, &ptr, "type", UI_ITEM_R_FULL_EVENT|UI_ITEM_R_IMMEDIATE, "", ICON_NONE); 04167 04168 uiPopupBoundsBlock(block, 6, -50, 26); 04169 uiEndBlock(C, block); 04170 04171 return block; 04172 } 04173 04174 static void popup_change_shortcut_func(bContext *C, void *arg1, void *UNUSED(arg2)) 04175 { 04176 uiBut *but = (uiBut *)arg1; 04177 button_timers_tooltip_remove(C, but); 04178 uiPupBlock(C, menu_change_shortcut, but); 04179 } 04180 04181 static void remove_shortcut_func(bContext *C, void *arg1, void *UNUSED(arg2)) 04182 { 04183 uiBut *but = (uiBut *)arg1; 04184 wmKeyMap *km; 04185 wmKeyMapItem *kmi; 04186 IDProperty *prop= (but->opptr)? but->opptr->data: NULL; 04187 int kmi_id = WM_key_event_operator_id(C, but->optype->idname, but->opcontext, prop, 1, &km); 04188 04189 kmi = WM_keymap_item_find_id(km, kmi_id); 04190 WM_keymap_remove_item(km, kmi); 04191 04192 but_shortcut_name_func(C, but, 0); 04193 } 04194 04195 static void popup_add_shortcut_func(bContext *C, void *arg1, void *UNUSED(arg2)) 04196 { 04197 uiBut *but = (uiBut *)arg1; 04198 button_timers_tooltip_remove(C, but); 04199 uiPupBlock(C, menu_add_shortcut, but); 04200 } 04201 04202 04203 static int ui_but_menu(bContext *C, uiBut *but) 04204 { 04205 uiPopupMenu *pup; 04206 uiLayout *layout; 04207 int length; 04208 const char *name; 04209 04210 if((but->rnapoin.data && but->rnaprop)==0 && but->optype==NULL) 04211 return 0; 04212 04213 button_timers_tooltip_remove(C, but); 04214 04215 if(but->rnaprop) 04216 name= RNA_property_ui_name(but->rnaprop); 04217 else if (but->optype) 04218 name= but->optype->name; 04219 else 04220 name= "<needs_name>"; // XXX - should never happen. 04221 04222 pup= uiPupMenuBegin(C, name, ICON_NONE); 04223 layout= uiPupMenuLayout(pup); 04224 04225 uiLayoutSetOperatorContext(layout, WM_OP_INVOKE_DEFAULT); 04226 04227 if(but->rnapoin.data && but->rnaprop) { 04228 short is_anim= RNA_property_animateable(&but->rnapoin, but->rnaprop); 04229 04230 /* second slower test, saved people finding keyframe items in menus when its not possible */ 04231 if(is_anim) 04232 is_anim= RNA_property_path_from_ID_check(&but->rnapoin, but->rnaprop); 04233 04234 length= RNA_property_array_length(&but->rnapoin, but->rnaprop); 04235 04236 /* Keyframes */ 04237 if(but->flag & UI_BUT_ANIMATED_KEY) { 04238 if(length) { 04239 uiItemBooleanO(layout, "Replace Keyframes", ICON_NONE, "ANIM_OT_keyframe_insert_button", "all", 1); 04240 uiItemBooleanO(layout, "Replace Single Keyframe", ICON_NONE, "ANIM_OT_keyframe_insert_button", "all", 0); 04241 uiItemBooleanO(layout, "Delete Keyframes", ICON_NONE, "ANIM_OT_keyframe_delete_button", "all", 1); 04242 uiItemBooleanO(layout, "Delete Single Keyframe", ICON_NONE, "ANIM_OT_keyframe_delete_button", "all", 0); 04243 } 04244 else { 04245 uiItemBooleanO(layout, "Replace Keyframe", ICON_NONE, "ANIM_OT_keyframe_insert_button", "all", 0); 04246 uiItemBooleanO(layout, "Delete Keyframe", ICON_NONE, "ANIM_OT_keyframe_delete_button", "all", 0); 04247 } 04248 } 04249 else if(but->flag & UI_BUT_DRIVEN); 04250 else if(is_anim) { 04251 if(length) { 04252 uiItemBooleanO(layout, "Insert Keyframes", ICON_NONE, "ANIM_OT_keyframe_insert_button", "all", 1); 04253 uiItemBooleanO(layout, "Insert Single Keyframe", ICON_NONE, "ANIM_OT_keyframe_insert_button", "all", 0); 04254 } 04255 else 04256 uiItemBooleanO(layout, "Insert Keyframe", ICON_NONE, "ANIM_OT_keyframe_insert_button", "all", 0); 04257 } 04258 04259 /* Drivers */ 04260 if(but->flag & UI_BUT_DRIVEN) { 04261 uiItemS(layout); 04262 04263 if(length) { 04264 uiItemBooleanO(layout, "Delete Drivers", ICON_NONE, "ANIM_OT_driver_button_remove", "all", 1); 04265 uiItemBooleanO(layout, "Delete Single Driver", ICON_NONE, "ANIM_OT_driver_button_remove", "all", 0); 04266 } 04267 else 04268 uiItemBooleanO(layout, "Delete Driver", ICON_NONE, "ANIM_OT_driver_button_remove", "all", 0); 04269 04270 uiItemO(layout, "Copy Driver", ICON_NONE, "ANIM_OT_copy_driver_button"); 04271 if (ANIM_driver_can_paste()) 04272 uiItemO(layout, "Paste Driver", ICON_NONE, "ANIM_OT_paste_driver_button"); 04273 } 04274 else if(but->flag & (UI_BUT_ANIMATED_KEY|UI_BUT_ANIMATED)); 04275 else if(is_anim) { 04276 uiItemS(layout); 04277 04278 if(length) { 04279 uiItemBooleanO(layout, "Add Drivers", ICON_NONE, "ANIM_OT_driver_button_add", "all", 1); 04280 uiItemBooleanO(layout, "Add Single Driver", ICON_NONE, "ANIM_OT_driver_button_add", "all", 0); 04281 } 04282 else 04283 uiItemBooleanO(layout, "Add Driver", ICON_NONE, "ANIM_OT_driver_button_add", "all", 0); 04284 04285 if (ANIM_driver_can_paste()) 04286 uiItemO(layout, "Paste Driver", ICON_NONE, "ANIM_OT_paste_driver_button"); 04287 } 04288 04289 /* Keying Sets */ 04290 if(is_anim) { 04291 uiItemS(layout); 04292 04293 if(length) { 04294 uiItemBooleanO(layout, "Add All to Keying Set", ICON_NONE, "ANIM_OT_keyingset_button_add", "all", 1); 04295 uiItemBooleanO(layout, "Add Single to Keying Set", ICON_NONE, "ANIM_OT_keyingset_button_add", "all", 0); 04296 uiItemO(layout, "Remove from Keying Set", ICON_NONE, "ANIM_OT_keyingset_button_remove"); 04297 } 04298 else { 04299 uiItemBooleanO(layout, "Add to Keying Set", ICON_NONE, "ANIM_OT_keyingset_button_add", "all", 0); 04300 uiItemO(layout, "Remove from Keying Set", ICON_NONE, "ANIM_OT_keyingset_button_remove"); 04301 } 04302 } 04303 04304 uiItemS(layout); 04305 04306 /* Property Operators */ 04307 04308 //Copy Property Value 04309 //Paste Property Value 04310 04311 if(length) { 04312 uiItemBooleanO(layout, "Reset All to Default Values", ICON_NONE, "UI_OT_reset_default_button", "all", 1); 04313 uiItemBooleanO(layout, "Reset Single to Default Value", ICON_NONE, "UI_OT_reset_default_button", "all", 0); 04314 } 04315 else 04316 uiItemO(layout, "Reset to Default Value", ICON_NONE, "UI_OT_reset_default_button"); 04317 04318 uiItemO(layout, "Copy Data Path", ICON_NONE, "UI_OT_copy_data_path_button"); 04319 uiItemO(layout, "Copy To Selected", ICON_NONE, "UI_OT_copy_to_selected_button"); 04320 04321 uiItemS(layout); 04322 } 04323 04324 /* Operator buttons */ 04325 if(but->optype) { 04326 uiBlock *block = uiLayoutGetBlock(layout); 04327 uiBut *but2; 04328 IDProperty *prop= (but->opptr)? but->opptr->data: NULL; 04329 int w = uiLayoutGetWidth(layout); 04330 wmKeyMap *km; 04331 wmKeyMapItem *kmi= NULL; 04332 int kmi_id= WM_key_event_operator_id(C, but->optype->idname, but->opcontext, prop, 1, &km); 04333 04334 if (kmi_id) 04335 kmi= WM_keymap_item_find_id(km, kmi_id); 04336 04337 /* keyboard shortcuts */ 04338 if ((kmi) && ISKEYBOARD(kmi->type)) { 04339 04340 // would rather use a block but, but gets weirdly positioned... 04341 //uiDefBlockBut(block, menu_change_shortcut, but, "Change Shortcut", 0, 0, uiLayoutGetWidth(layout), UI_UNIT_Y, ""); 04342 04343 but2 = uiDefIconTextBut(block, BUT, 0, 0, "Change Shortcut", 0, 0, w, UI_UNIT_Y, NULL, 0, 0, 0, 0, ""); 04344 uiButSetFunc(but2, popup_change_shortcut_func, but, NULL); 04345 04346 but2 = uiDefIconTextBut(block, BUT, 0, 0, "Remove Shortcut", 0, 0, w, UI_UNIT_Y, NULL, 0, 0, 0, 0, ""); 04347 uiButSetFunc(but2, remove_shortcut_func, but, NULL); 04348 } 04349 /* only show 'add' if there's a suitable key map for it to go in */ 04350 else if (WM_keymap_guess_opname(C, but->optype->idname)) { 04351 but2 = uiDefIconTextBut(block, BUT, 0, 0, "Add Shortcut", 0, 0, w, UI_UNIT_Y, NULL, 0, 0, 0, 0, ""); 04352 uiButSetFunc(but2, popup_add_shortcut_func, but, NULL); 04353 } 04354 04355 uiItemS(layout); 04356 } 04357 04358 04359 { /* Docs */ 04360 char buf[512]; 04361 PointerRNA ptr_props; 04362 04363 if(but->rnapoin.data && but->rnaprop) { 04364 sprintf(buf, "%s.%s", RNA_struct_identifier(but->rnapoin.type), RNA_property_identifier(but->rnaprop)); 04365 04366 WM_operator_properties_create(&ptr_props, "WM_OT_doc_view"); 04367 RNA_string_set(&ptr_props, "doc_id", buf); 04368 uiItemFullO(layout, "WM_OT_doc_view", "View Docs", ICON_NONE, ptr_props.data, WM_OP_EXEC_DEFAULT, 0); 04369 04370 /* XXX inactive option, not for public! */ 04371 /* WM_operator_properties_create(&ptr_props, "WM_OT_doc_edit"); 04372 RNA_string_set(&ptr_props, "doc_id", buf); 04373 RNA_string_set(&ptr_props, "doc_new", RNA_property_description(but->rnaprop)); 04374 04375 uiItemFullO(layout, "WM_OT_doc_edit", "Submit Description", ICON_NONE, ptr_props.data, WM_OP_INVOKE_DEFAULT, 0); 04376 */ 04377 } 04378 else if (but->optype) { 04379 WM_operator_py_idname(buf, but->optype->idname); 04380 04381 WM_operator_properties_create(&ptr_props, "WM_OT_doc_view"); 04382 RNA_string_set(&ptr_props, "doc_id", buf); 04383 uiItemFullO(layout, "WM_OT_doc_view", "View Docs", ICON_NONE, ptr_props.data, WM_OP_EXEC_DEFAULT, 0); 04384 04385 04386 WM_operator_properties_create(&ptr_props, "WM_OT_doc_edit"); 04387 RNA_string_set(&ptr_props, "doc_id", buf); 04388 RNA_string_set(&ptr_props, "doc_new", but->optype->description); 04389 04390 uiItemFullO(layout, "WM_OT_doc_edit", "Submit Description", ICON_NONE, ptr_props.data, WM_OP_INVOKE_DEFAULT, 0); 04391 } 04392 } 04393 04394 uiPupMenuEnd(C, pup); 04395 04396 return 1; 04397 } 04398 04399 static int ui_do_button(bContext *C, uiBlock *block, uiBut *but, wmEvent *event) 04400 { 04401 // Scene *scene= CTX_data_scene(C); 04402 uiHandleButtonData *data; 04403 int retval; 04404 04405 data= but->active; 04406 retval= WM_UI_HANDLER_CONTINUE; 04407 04408 if(but->flag & UI_BUT_DISABLED) 04409 return WM_UI_HANDLER_CONTINUE; 04410 04411 if( (data->state == BUTTON_STATE_HIGHLIGHT) && 04412 /* check prevval because of modal operators [#24016], 04413 * modifier check is to allow Ctrl+C for copy. 04414 * if this causes other problems, remove this check and suffer the bug :) - campbell */ 04415 (event->prevval != KM_PRESS || ISKEYMODIFIER(event->prevtype)) 04416 ) { 04417 /* handle copy-paste */ 04418 if(ELEM(event->type, CKEY, VKEY) && event->val==KM_PRESS && (event->ctrl || event->oskey)) { 04419 ui_but_copy_paste(C, but, data, (event->type == CKEY)? 'c': 'v'); 04420 return WM_UI_HANDLER_BREAK; 04421 } 04422 /* handle drop */ 04423 else if(event->type == EVT_DROP) { 04424 ui_but_drop (C, event, but, data); 04425 } 04426 /* handle keyframing */ 04427 else if(event->type == IKEY && !ELEM3(1, event->ctrl, event->oskey, event->shift) && event->val == KM_PRESS) { 04428 if(event->alt) 04429 ui_but_anim_delete_keyframe(C); 04430 else 04431 ui_but_anim_insert_keyframe(C); 04432 04433 ED_region_tag_redraw(CTX_wm_region(C)); 04434 04435 return WM_UI_HANDLER_BREAK; 04436 } 04437 /* handle drivers */ 04438 else if(event->type == DKEY && !ELEM3(1, event->ctrl, event->oskey, event->shift) && event->val == KM_PRESS) { 04439 if(event->alt) 04440 ui_but_anim_remove_driver(C); 04441 else 04442 ui_but_anim_add_driver(C); 04443 04444 ED_region_tag_redraw(CTX_wm_region(C)); 04445 04446 return WM_UI_HANDLER_BREAK; 04447 } 04448 /* handle keyingsets */ 04449 else if(event->type == KKEY && !ELEM3(1, event->ctrl, event->oskey, event->shift) && event->val == KM_PRESS) { 04450 if(event->alt) 04451 ui_but_anim_remove_keyingset(C); 04452 else 04453 ui_but_anim_add_keyingset(C); 04454 04455 ED_region_tag_redraw(CTX_wm_region(C)); 04456 04457 return WM_UI_HANDLER_BREAK; 04458 } 04459 /* reset to default */ 04460 /* XXX hardcoded keymap check.... */ 04461 else if(ELEM(event->type, DELKEY, PADPERIOD) && event->val == KM_PRESS) { 04462 /* ctrl+del - reset active button; del - reset a whole array*/ 04463 if (!(ELEM3(but->type, HSVCIRCLE, HSVCUBE, HISTOGRAM))) 04464 ui_set_but_default(C, !event->ctrl); 04465 } 04466 /* handle menu */ 04467 else if(event->type == RIGHTMOUSE && event->val == KM_PRESS) { 04468 /* RMB has two options now */ 04469 if (ui_but_menu(C, but)) { 04470 return WM_UI_HANDLER_BREAK; 04471 } 04472 } 04473 } 04474 04475 /* verify if we can edit this button */ 04476 if(ELEM(event->type, LEFTMOUSE, RETKEY)) { 04477 /* this should become disabled button .. */ 04478 if(but->lock) { 04479 if(but->lockstr) { 04480 BKE_report(NULL, RPT_WARNING, but->lockstr); 04481 button_activate_state(C, but, BUTTON_STATE_EXIT); 04482 return WM_UI_HANDLER_BREAK; 04483 } 04484 } 04485 else if(but->pointype && but->poin==NULL) { 04486 /* there's a pointer needed */ 04487 BKE_reportf(NULL, RPT_WARNING, "DoButton pointer error: %s", but->str); 04488 button_activate_state(C, but, BUTTON_STATE_EXIT); 04489 return WM_UI_HANDLER_BREAK; 04490 } 04491 } 04492 04493 switch(but->type) { 04494 case BUT: 04495 retval= ui_do_but_BUT(C, but, data, event); 04496 break; 04497 case KEYEVT: 04498 retval= ui_do_but_KEYEVT(C, but, data, event); 04499 break; 04500 case HOTKEYEVT: 04501 retval= ui_do_but_HOTKEYEVT(C, but, data, event); 04502 break; 04503 case TOGBUT: 04504 case TOG: 04505 case TOGR: 04506 case ICONTOG: 04507 case ICONTOGN: 04508 case TOGN: 04509 case BUT_TOGDUAL: 04510 case OPTION: 04511 case OPTIONN: 04512 retval= ui_do_but_TOG(C, but, data, event); 04513 break; 04514 case SCROLL: 04515 retval= ui_do_but_SCROLL(C, block, but, data, event); 04516 break; 04517 case NUM: 04518 case NUMABS: 04519 retval= ui_do_but_NUM(C, block, but, data, event); 04520 break; 04521 case SLI: 04522 case NUMSLI: 04523 case HSVSLI: 04524 retval= ui_do_but_SLI(C, block, but, data, event); 04525 break; 04526 case ROUNDBOX: 04527 case LISTBOX: 04528 case LABEL: 04529 case TOG3: 04530 case ROW: 04531 case LISTROW: 04532 case BUT_IMAGE: 04533 case PROGRESSBAR: 04534 retval= ui_do_but_EXIT(C, but, data, event); 04535 break; 04536 case HISTOGRAM: 04537 retval= ui_do_but_HISTOGRAM(C, block, but, data, event); 04538 break; 04539 case WAVEFORM: 04540 retval= ui_do_but_WAVEFORM(C, block, but, data, event); 04541 break; 04542 case VECTORSCOPE: 04543 retval= ui_do_but_VECTORSCOPE(C, block, but, data, event); 04544 break; 04545 case TEX: 04546 case IDPOIN: 04547 case SEARCH_MENU: 04548 retval= ui_do_but_TEX(C, block, but, data, event); 04549 break; 04550 case MENU: 04551 case ICONROW: 04552 case ICONTEXTROW: 04553 case BLOCK: 04554 case PULLDOWN: 04555 retval= ui_do_but_BLOCK(C, but, data, event); 04556 break; 04557 case BUTM: 04558 retval= ui_do_but_BUT(C, but, data, event); 04559 break; 04560 case COL: 04561 if(but->a1 == UI_GRAD_V_ALT) // signal to prevent calling up color picker 04562 retval= ui_do_but_EXIT(C, but, data, event); 04563 else 04564 retval= ui_do_but_BLOCK(C, but, data, event); 04565 break; 04566 case BUT_NORMAL: 04567 retval= ui_do_but_NORMAL(C, block, but, data, event); 04568 break; 04569 case BUT_COLORBAND: 04570 retval= ui_do_but_COLORBAND(C, block, but, data, event); 04571 break; 04572 case BUT_CURVE: 04573 retval= ui_do_but_CURVE(C, block, but, data, event); 04574 break; 04575 case HSVCUBE: 04576 retval= ui_do_but_HSVCUBE(C, block, but, data, event); 04577 break; 04578 case HSVCIRCLE: 04579 retval= ui_do_but_HSVCIRCLE(C, block, but, data, event); 04580 break; 04581 #ifdef INTERNATIONAL 04582 case CHARTAB: 04583 retval= ui_do_but_CHARTAB(C, block, but, data, event); 04584 break; 04585 #endif 04586 04587 case LINK: 04588 case INLINK: 04589 retval= ui_do_but_LINK(C, but, data, event); 04590 break; 04591 } 04592 04593 return retval; 04594 } 04595 04596 /* ************************ button utilities *********************** */ 04597 04598 static int ui_but_contains_pt(uiBut *but, int mx, int my) 04599 { 04600 return ((but->x1<mx && but->x2>=mx) && (but->y1<my && but->y2>=my)); 04601 } 04602 04603 static uiBut *ui_but_find_activated(ARegion *ar) 04604 { 04605 uiBlock *block; 04606 uiBut *but; 04607 04608 for(block=ar->uiblocks.first; block; block=block->next) 04609 for(but=block->buttons.first; but; but= but->next) 04610 if(but->active) 04611 return but; 04612 04613 return NULL; 04614 } 04615 04616 int ui_button_is_active(ARegion *ar) 04617 { 04618 return (ui_but_find_activated(ar) != NULL); 04619 } 04620 04621 /* is called by notifier */ 04622 void uiFreeActiveButtons(const bContext *C, bScreen *screen) 04623 { 04624 ScrArea *sa= screen->areabase.first; 04625 04626 for(;sa; sa= sa->next) { 04627 ARegion *ar= sa->regionbase.first; 04628 for(;ar; ar= ar->next) { 04629 uiBut *but= ui_but_find_activated(ar); 04630 if(but) { 04631 uiHandleButtonData *data= but->active; 04632 04633 if(data->menu==NULL && data->searchbox==NULL) 04634 if(data->state == BUTTON_STATE_HIGHLIGHT) 04635 ui_button_active_free(C, but); 04636 } 04637 } 04638 } 04639 } 04640 04641 04642 04643 /* returns TRUE if highlighted button allows drop of names */ 04644 /* called in region context */ 04645 int UI_but_active_drop_name(bContext *C) 04646 { 04647 ARegion *ar= CTX_wm_region(C); 04648 uiBut *but= ui_but_find_activated(ar); 04649 04650 if(but) { 04651 if(ELEM3(but->type, TEX, IDPOIN, SEARCH_MENU)) 04652 return 1; 04653 } 04654 04655 return 0; 04656 } 04657 04658 static void ui_blocks_set_tooltips(ARegion *ar, int enable) 04659 { 04660 uiBlock *block; 04661 04662 if(!ar) 04663 return; 04664 04665 /* we disabled buttons when when they were already shown, and 04666 * re-enable them on mouse move */ 04667 for(block=ar->uiblocks.first; block; block=block->next) 04668 block->tooltipdisabled= !enable; 04669 } 04670 04671 static int ui_mouse_inside_region(ARegion *ar, int x, int y) 04672 { 04673 uiBlock *block; 04674 04675 /* check if the mouse is in the region */ 04676 if(!BLI_in_rcti(&ar->winrct, x, y)) { 04677 for(block=ar->uiblocks.first; block; block=block->next) 04678 block->auto_open= 0; 04679 04680 return 0; 04681 } 04682 04683 /* also, check that with view2d, that the mouse is not over the scrollbars 04684 * NOTE: care is needed here, since the mask rect may include the scrollbars 04685 * even when they are not visible, so we need to make a copy of the mask to 04686 * use to check 04687 */ 04688 if(ar->v2d.mask.xmin!=ar->v2d.mask.xmax) { 04689 View2D *v2d= &ar->v2d; 04690 rcti mask_rct; 04691 int mx, my; 04692 04693 /* convert window coordinates to region coordinates */ 04694 mx= x; 04695 my= y; 04696 ui_window_to_region(ar, &mx, &my); 04697 04698 /* make a copy of the mask rect, and tweak accordingly for hidden scrollbars */ 04699 mask_rct.xmin= v2d->mask.xmin; 04700 mask_rct.xmax= v2d->mask.xmax; 04701 mask_rct.ymin= v2d->mask.ymin; 04702 mask_rct.ymax= v2d->mask.ymax; 04703 04704 if (v2d->scroll & (V2D_SCROLL_VERTICAL_HIDE|V2D_SCROLL_VERTICAL_FULLR)) { 04705 if (v2d->scroll & V2D_SCROLL_LEFT) 04706 mask_rct.xmin= v2d->vert.xmin; 04707 else if (v2d->scroll & V2D_SCROLL_RIGHT) 04708 mask_rct.xmax= v2d->vert.xmax; 04709 } 04710 if (v2d->scroll & (V2D_SCROLL_HORIZONTAL_HIDE|V2D_SCROLL_HORIZONTAL_FULLR)) { 04711 if (v2d->scroll & (V2D_SCROLL_BOTTOM|V2D_SCROLL_BOTTOM_O)) 04712 mask_rct.ymin= v2d->hor.ymin; 04713 else if (v2d->scroll & V2D_SCROLL_TOP) 04714 mask_rct.ymax= v2d->hor.ymax; 04715 } 04716 04717 /* check if in the rect */ 04718 if(!BLI_in_rcti(&mask_rct, mx, my)) 04719 return 0; 04720 } 04721 04722 return 1; 04723 } 04724 04725 static int ui_mouse_inside_button(ARegion *ar, uiBut *but, int x, int y) 04726 { 04727 if(!ui_mouse_inside_region(ar, x, y)) 04728 return 0; 04729 04730 ui_window_to_block(ar, but->block, &x, &y); 04731 04732 if(!ui_but_contains_pt(but, x, y)) 04733 return 0; 04734 04735 return 1; 04736 } 04737 04738 static uiBut *ui_but_find_mouse_over(ARegion *ar, int x, int y) 04739 { 04740 uiBlock *block; 04741 uiBut *but, *butover= NULL; 04742 int mx, my; 04743 04744 // if(!win->active) 04745 // return NULL; 04746 if(!ui_mouse_inside_region(ar, x, y)) 04747 return NULL; 04748 04749 for(block=ar->uiblocks.first; block; block=block->next) { 04750 mx= x; 04751 my= y; 04752 ui_window_to_block(ar, block, &mx, &my); 04753 04754 for(but=block->buttons.first; but; but= but->next) { 04755 /* note, LABEL is included for hilights, this allows drags */ 04756 if(but->type==LABEL && but->dragpoin==NULL) 04757 continue; 04758 if(ELEM3(but->type, ROUNDBOX, SEPR, LISTBOX)) 04759 continue; 04760 if(but->flag & UI_HIDDEN) 04761 continue; 04762 if(but->flag & UI_SCROLLED) 04763 continue; 04764 if(ui_but_contains_pt(but, mx, my)) 04765 butover= but; 04766 } 04767 } 04768 04769 return butover; 04770 } 04771 04772 static uiBut *ui_list_find_mouse_over(ARegion *ar, int x, int y) 04773 { 04774 uiBlock *block; 04775 uiBut *but; 04776 int mx, my; 04777 04778 // if(!win->active) 04779 // return NULL; 04780 if(!ui_mouse_inside_region(ar, x, y)) 04781 return NULL; 04782 04783 for(block=ar->uiblocks.first; block; block=block->next) { 04784 mx= x; 04785 my= y; 04786 ui_window_to_block(ar, block, &mx, &my); 04787 04788 for(but=block->buttons.last; but; but= but->prev) 04789 if(but->type == LISTBOX && ui_but_contains_pt(but, mx, my)) 04790 return but; 04791 } 04792 04793 return NULL; 04794 } 04795 04796 /* ****************** button state handling **************************/ 04797 04798 static int button_modal_state(uiHandleButtonState state) 04799 { 04800 return ELEM6(state, BUTTON_STATE_WAIT_RELEASE, BUTTON_STATE_WAIT_KEY_EVENT, 04801 BUTTON_STATE_NUM_EDITING, BUTTON_STATE_TEXT_EDITING, 04802 BUTTON_STATE_TEXT_SELECTING, BUTTON_STATE_MENU_OPEN); 04803 } 04804 04805 static void button_timers_tooltip_remove(bContext *C, uiBut *but) 04806 { 04807 uiHandleButtonData *data; 04808 04809 data= but->active; 04810 if(data) { 04811 04812 if(data->tooltiptimer) { 04813 WM_event_remove_timer(data->wm, data->window, data->tooltiptimer); 04814 data->tooltiptimer= NULL; 04815 } 04816 if(data->tooltip) { 04817 ui_tooltip_free(C, data->tooltip); 04818 data->tooltip= NULL; 04819 } 04820 04821 if(data->autoopentimer) { 04822 WM_event_remove_timer(data->wm, data->window, data->autoopentimer); 04823 data->autoopentimer= NULL; 04824 } 04825 } 04826 } 04827 04828 static void button_tooltip_timer_reset(bContext *C, uiBut *but) 04829 { 04830 wmWindowManager *wm= CTX_wm_manager(C); 04831 uiHandleButtonData *data; 04832 04833 data= but->active; 04834 04835 if(data->tooltiptimer) { 04836 WM_event_remove_timer(data->wm, data->window, data->tooltiptimer); 04837 data->tooltiptimer= NULL; 04838 } 04839 04840 if(U.flag & USER_TOOLTIPS) 04841 if(!but->block->tooltipdisabled) 04842 if(!wm->drags.first) 04843 data->tooltiptimer= WM_event_add_timer(data->wm, data->window, TIMER, BUTTON_TOOLTIP_DELAY); 04844 } 04845 04846 static void button_activate_state(bContext *C, uiBut *but, uiHandleButtonState state) 04847 { 04848 uiHandleButtonData *data; 04849 04850 data= but->active; 04851 if(data->state == state) 04852 return; 04853 04854 /* highlight has timers for tooltips and auto open */ 04855 if(state == BUTTON_STATE_HIGHLIGHT) { 04856 but->flag &= ~UI_SELECT; 04857 04858 button_tooltip_timer_reset(C, but); 04859 04860 /* automatic open pulldown block timer */ 04861 if(ELEM3(but->type, BLOCK, PULLDOWN, ICONTEXTROW)) { 04862 if(data->used_mouse && !data->autoopentimer) { 04863 int time; 04864 04865 if(but->block->auto_open==2) time= 1; // test for toolbox 04866 else if((but->block->flag & UI_BLOCK_LOOP && but->type != BLOCK) || but->block->auto_open) time= 5*U.menuthreshold2; 04867 else if(U.uiflag & USER_MENUOPENAUTO) time= 5*U.menuthreshold1; 04868 else time= -1; 04869 04870 if(time >= 0) 04871 data->autoopentimer= WM_event_add_timer(data->wm, data->window, TIMER, 0.02*(double)time); 04872 } 04873 } 04874 } 04875 else { 04876 but->flag |= UI_SELECT; 04877 button_timers_tooltip_remove(C, but); 04878 } 04879 04880 /* text editing */ 04881 if(state == BUTTON_STATE_TEXT_EDITING && data->state != BUTTON_STATE_TEXT_SELECTING) 04882 ui_textedit_begin(C, but, data); 04883 else if(data->state == BUTTON_STATE_TEXT_EDITING && state != BUTTON_STATE_TEXT_SELECTING) 04884 ui_textedit_end(C, but, data); 04885 else if(data->state == BUTTON_STATE_TEXT_SELECTING && state != BUTTON_STATE_TEXT_EDITING) 04886 ui_textedit_end(C, but, data); 04887 04888 /* number editing */ 04889 if(state == BUTTON_STATE_NUM_EDITING) { 04890 if(ui_is_a_warp_but(but)) 04891 WM_cursor_grab(CTX_wm_window(C), TRUE, TRUE, NULL); 04892 ui_numedit_begin(but, data); 04893 } else if(data->state == BUTTON_STATE_NUM_EDITING) { 04894 ui_numedit_end(but, data); 04895 if(ui_is_a_warp_but(but)) 04896 WM_cursor_ungrab(CTX_wm_window(C)); 04897 } 04898 /* menu open */ 04899 if(state == BUTTON_STATE_MENU_OPEN) 04900 ui_blockopen_begin(C, but, data); 04901 else if(data->state == BUTTON_STATE_MENU_OPEN) 04902 ui_blockopen_end(C, but, data); 04903 04904 /* add a short delay before exiting, to ensure there is some feedback */ 04905 if(state == BUTTON_STATE_WAIT_FLASH) { 04906 data->flashtimer= WM_event_add_timer(data->wm, data->window, TIMER, BUTTON_FLASH_DELAY); 04907 } 04908 else if(data->flashtimer) { 04909 WM_event_remove_timer(data->wm, data->window, data->flashtimer); 04910 data->flashtimer= NULL; 04911 } 04912 04913 /* add a blocking ui handler at the window handler for blocking, modal states 04914 * but not for popups, because we already have a window level handler*/ 04915 if(!(but->block->handle && but->block->handle->popup)) { 04916 if(button_modal_state(state)) { 04917 if(!button_modal_state(data->state)) 04918 WM_event_add_ui_handler(C, &data->window->modalhandlers, ui_handler_region_menu, NULL, data); 04919 } 04920 else { 04921 if(button_modal_state(data->state)) 04922 WM_event_remove_ui_handler(&data->window->modalhandlers, ui_handler_region_menu, NULL, data, 1); /* 1 = postpone free */ 04923 } 04924 } 04925 04926 /* wait for mousemove to enable drag */ 04927 if(state == BUTTON_STATE_WAIT_DRAG) { 04928 but->flag &= ~UI_SELECT; 04929 } 04930 04931 data->state= state; 04932 04933 if(state != BUTTON_STATE_EXIT) { 04934 /* When objects for eg. are removed, running ui_check_but() 04935 * can access the removed data - so disable update on exit */ 04936 ui_check_but(but); 04937 } 04938 04939 /* redraw */ 04940 ED_region_tag_redraw(data->region); 04941 } 04942 04943 static void button_activate_init(bContext *C, ARegion *ar, uiBut *but, uiButtonActivateType type) 04944 { 04945 uiHandleButtonData *data; 04946 04947 /* setup struct */ 04948 data= MEM_callocN(sizeof(uiHandleButtonData), "uiHandleButtonData"); 04949 data->wm= CTX_wm_manager(C); 04950 data->window= CTX_wm_window(C); 04951 data->region= ar; 04952 if( ELEM(but->type, BUT_CURVE, SEARCH_MENU) ); // XXX curve is temp 04953 else data->interactive= 1; 04954 04955 data->state = BUTTON_STATE_INIT; 04956 04957 /* activate button */ 04958 but->flag |= UI_ACTIVE; 04959 but->active= data; 04960 04961 /* we disable auto_open in the block after a threshold, because we still 04962 * want to allow auto opening adjacent menus even if no button is activated 04963 * in between going over to the other button, but only for a short while */ 04964 if(type == BUTTON_ACTIVATE_OVER && but->block->auto_open) 04965 if(but->block->auto_open_last+BUTTON_AUTO_OPEN_THRESH < PIL_check_seconds_timer()) 04966 but->block->auto_open= 0; 04967 04968 if(type == BUTTON_ACTIVATE_OVER) { 04969 data->used_mouse= 1; 04970 } 04971 button_activate_state(C, but, BUTTON_STATE_HIGHLIGHT); 04972 04973 /* activate right away */ 04974 if(but->flag & UI_BUT_IMMEDIATE) { 04975 if(but->type==HOTKEYEVT) 04976 button_activate_state(C, but, BUTTON_STATE_WAIT_KEY_EVENT); 04977 /* .. more to be added here */ 04978 } 04979 04980 if(type == BUTTON_ACTIVATE_OPEN) { 04981 button_activate_state(C, but, BUTTON_STATE_MENU_OPEN); 04982 04983 /* activate first button in submenu */ 04984 if(data->menu && data->menu->region) { 04985 ARegion *subar= data->menu->region; 04986 uiBlock *subblock= subar->uiblocks.first; 04987 uiBut *subbut; 04988 04989 if(subblock) { 04990 subbut= ui_but_first(subblock); 04991 04992 if(subbut) 04993 ui_handle_button_activate(C, subar, subbut, BUTTON_ACTIVATE); 04994 } 04995 } 04996 } 04997 else if(type == BUTTON_ACTIVATE_TEXT_EDITING) 04998 button_activate_state(C, but, BUTTON_STATE_TEXT_EDITING); 04999 else if(type == BUTTON_ACTIVATE_APPLY) 05000 button_activate_state(C, but, BUTTON_STATE_WAIT_FLASH); 05001 } 05002 05003 static void button_activate_exit(bContext *C, uiHandleButtonData *data, uiBut *but, int mousemove, int onfree) 05004 { 05005 uiBlock *block= but->block; 05006 uiBut *bt; 05007 05008 /* ensure we are in the exit state */ 05009 if(data->state != BUTTON_STATE_EXIT) 05010 button_activate_state(C, but, BUTTON_STATE_EXIT); 05011 05012 /* apply the button action or value */ 05013 if(!onfree) 05014 ui_apply_button(C, block, but, data, 0); 05015 05016 /* if this button is in a menu, this will set the button return 05017 * value to the button value and the menu return value to ok, the 05018 * menu return value will be picked up and the menu will close */ 05019 if(block->handle && !(block->flag & UI_BLOCK_KEEP_OPEN)) { 05020 if(!data->cancel || data->escapecancel) { 05021 uiPopupBlockHandle *menu; 05022 05023 menu= block->handle; 05024 menu->butretval= data->retval; 05025 menu->menuretval= (data->cancel)? UI_RETURN_CANCEL: UI_RETURN_OK; 05026 } 05027 } 05028 05029 if(!onfree && !data->cancel) { 05030 /* autokey & undo push */ 05031 ui_apply_autokey_undo(C, but); 05032 05033 /* popup menu memory */ 05034 if(block->flag & UI_BLOCK_POPUP_MEMORY) 05035 ui_popup_menu_memory(block, but); 05036 } 05037 05038 /* disable tooltips until mousemove + last active flag */ 05039 for(block=data->region->uiblocks.first; block; block=block->next) { 05040 for(bt=block->buttons.first; bt; bt=bt->next) 05041 bt->flag &= ~UI_BUT_LAST_ACTIVE; 05042 05043 block->tooltipdisabled= 1; 05044 } 05045 05046 ui_blocks_set_tooltips(data->region, 0); 05047 05048 /* clean up */ 05049 if(data->str) 05050 MEM_freeN(data->str); 05051 if(data->origstr) 05052 MEM_freeN(data->origstr); 05053 05054 /* redraw (data is but->active!) */ 05055 ED_region_tag_redraw(data->region); 05056 05057 /* clean up button */ 05058 MEM_freeN(but->active); 05059 but->active= NULL; 05060 but->flag &= ~(UI_ACTIVE|UI_SELECT); 05061 but->flag |= UI_BUT_LAST_ACTIVE; 05062 if(!onfree) 05063 ui_check_but(but); 05064 05065 /* adds empty mousemove in queue for re-init handler, in case mouse is 05066 * still over a button. we cannot just check for this ourselfs because 05067 * at this point the mouse may be over a button in another region */ 05068 if(mousemove) 05069 WM_event_add_mousemove(C); 05070 } 05071 05072 void ui_button_active_free(const bContext *C, uiBut *but) 05073 { 05074 uiHandleButtonData *data; 05075 05076 /* this gets called when the button somehow disappears while it is still 05077 * active, this is bad for user interaction, but we need to handle this 05078 * case cleanly anyway in case it happens */ 05079 if(but->active) { 05080 data= but->active; 05081 data->cancel= 1; 05082 button_activate_exit((bContext*)C, data, but, 0, 1); 05083 } 05084 } 05085 05086 /* helper function for insert keyframe, reset to default, etc operators */ 05087 void uiContextActiveProperty(const bContext *C, struct PointerRNA *ptr, struct PropertyRNA **prop, int *index) 05088 { 05089 ARegion *ar= CTX_wm_region(C); 05090 05091 memset(ptr, 0, sizeof(*ptr)); 05092 *prop= NULL; 05093 *index= 0; 05094 05095 while(ar) { 05096 uiBlock *block; 05097 uiBut *but, *activebut= NULL; 05098 05099 /* find active button */ 05100 for(block=ar->uiblocks.first; block; block=block->next) { 05101 for(but=block->buttons.first; but; but= but->next) { 05102 if(but->active) 05103 activebut= but; 05104 else if(!activebut && (but->flag & UI_BUT_LAST_ACTIVE)) 05105 activebut= but; 05106 } 05107 } 05108 05109 if(activebut && activebut->rnapoin.data) { 05110 uiHandleButtonData *data= activebut->active; 05111 05112 /* found RNA button */ 05113 *ptr= activebut->rnapoin; 05114 *prop= activebut->rnaprop; 05115 *index= activebut->rnaindex; 05116 05117 /* recurse into opened menu, like colorpicker case */ 05118 if(data && data->menu && (ar != data->menu->region)) { 05119 ar = data->menu->region; 05120 } 05121 else { 05122 return; 05123 } 05124 } 05125 else { 05126 /* no active button */ 05127 return; 05128 } 05129 } 05130 } 05131 05132 /* helper function for insert keyframe, reset to default, etc operators */ 05133 void uiContextAnimUpdate(const bContext *C) 05134 { 05135 Scene *scene= CTX_data_scene(C); 05136 ARegion *ar= CTX_wm_region(C); 05137 uiBlock *block; 05138 uiBut *but, *activebut; 05139 05140 while(ar) { 05141 /* find active button */ 05142 activebut= NULL; 05143 05144 for(block=ar->uiblocks.first; block; block=block->next) { 05145 for(but=block->buttons.first; but; but= but->next) { 05146 ui_but_anim_flag(but, (scene)? scene->r.cfra: 0.0f); 05147 ED_region_tag_redraw(ar); 05148 05149 if(but->active) 05150 activebut= but; 05151 else if(!activebut && (but->flag & UI_BUT_LAST_ACTIVE)) 05152 activebut= but; 05153 } 05154 } 05155 05156 if(activebut) { 05157 /* always recurse into opened menu, so all buttons update (like colorpicker) */ 05158 uiHandleButtonData *data= activebut->active; 05159 if(data && data->menu) 05160 ar = data->menu->region; 05161 else 05162 return; 05163 } 05164 else { 05165 /* no active button */ 05166 return; 05167 } 05168 } 05169 } 05170 05171 /************** handle activating a button *************/ 05172 05173 static uiBut *uit_but_find_open_event(ARegion *ar, wmEvent *event) 05174 { 05175 uiBlock *block; 05176 uiBut *but; 05177 05178 for(block=ar->uiblocks.first; block; block=block->next) { 05179 for(but=block->buttons.first; but; but= but->next) 05180 if(but==event->customdata) 05181 return but; 05182 } 05183 return NULL; 05184 } 05185 05186 static int ui_handle_button_over(bContext *C, wmEvent *event, ARegion *ar) 05187 { 05188 uiBut *but; 05189 05190 if(event->type == MOUSEMOVE) { 05191 but= ui_but_find_mouse_over(ar, event->x, event->y); 05192 if(but) 05193 button_activate_init(C, ar, but, BUTTON_ACTIVATE_OVER); 05194 } 05195 else if(event->type == EVT_BUT_OPEN) { 05196 but= uit_but_find_open_event(ar, event); 05197 if(but) { 05198 button_activate_init(C, ar, but, BUTTON_ACTIVATE_OVER); 05199 ui_do_button(C, but->block, but, event); 05200 } 05201 } 05202 05203 return WM_UI_HANDLER_CONTINUE; 05204 } 05205 05206 /* exported to interface.c: uiButActiveOnly() */ 05207 void ui_button_activate_do(bContext *C, ARegion *ar, uiBut *but) 05208 { 05209 wmWindow *win= CTX_wm_window(C); 05210 wmEvent event; 05211 05212 button_activate_init(C, ar, but, BUTTON_ACTIVATE_OVER); 05213 05214 event= *(win->eventstate); /* XXX huh huh? make api call */ 05215 event.type= EVT_BUT_OPEN; 05216 event.val= KM_PRESS; 05217 event.customdata= but; 05218 event.customdatafree= FALSE; 05219 05220 ui_do_button(C, but->block, but, &event); 05221 } 05222 05223 static void ui_handle_button_activate(bContext *C, ARegion *ar, uiBut *but, uiButtonActivateType type) 05224 { 05225 uiBut *oldbut; 05226 uiHandleButtonData *data; 05227 05228 oldbut= ui_but_find_activated(ar); 05229 if(oldbut) { 05230 data= oldbut->active; 05231 data->cancel= 1; 05232 button_activate_exit(C, data, oldbut, 0, 0); 05233 } 05234 05235 button_activate_init(C, ar, but, type); 05236 } 05237 05238 /************ handle events for an activated button ***********/ 05239 05240 static int ui_handle_button_event(bContext *C, wmEvent *event, uiBut *but) 05241 { 05242 uiHandleButtonData *data; 05243 uiBlock *block; 05244 ARegion *ar; 05245 uiBut *postbut; 05246 uiButtonActivateType posttype; 05247 int retval; 05248 05249 data= but->active; 05250 block= but->block; 05251 ar= data->region; 05252 05253 retval= WM_UI_HANDLER_CONTINUE; 05254 05255 if(data->state == BUTTON_STATE_HIGHLIGHT) { 05256 switch(event->type) { 05257 case WINDEACTIVATE: 05258 case EVT_BUT_CANCEL: 05259 data->cancel= 1; 05260 button_activate_state(C, but, BUTTON_STATE_EXIT); 05261 retval= WM_UI_HANDLER_CONTINUE; 05262 break; 05263 case MOUSEMOVE: 05264 /* verify if we are still over the button, if not exit */ 05265 if(!ui_mouse_inside_button(ar, but, event->x, event->y)) { 05266 data->cancel= 1; 05267 button_activate_state(C, but, BUTTON_STATE_EXIT); 05268 } 05269 else if(ui_but_find_mouse_over(ar, event->x, event->y) != but) { 05270 data->cancel= 1; 05271 button_activate_state(C, but, BUTTON_STATE_EXIT); 05272 } 05273 else if(event->x!=event->prevx || event->y!=event->prevy) { 05274 /* re-enable tooltip on mouse move */ 05275 ui_blocks_set_tooltips(ar, 1); 05276 button_tooltip_timer_reset(C, but); 05277 } 05278 05279 break; 05280 case TIMER: { 05281 /* handle tooltip timer */ 05282 if(event->customdata == data->tooltiptimer) { 05283 WM_event_remove_timer(data->wm, data->window, data->tooltiptimer); 05284 data->tooltiptimer= NULL; 05285 05286 if(!data->tooltip) 05287 data->tooltip= ui_tooltip_create(C, data->region, but); 05288 } 05289 /* handle menu auto open timer */ 05290 else if(event->customdata == data->autoopentimer) { 05291 WM_event_remove_timer(data->wm, data->window, data->autoopentimer); 05292 data->autoopentimer= NULL; 05293 05294 if(ui_mouse_inside_button(ar, but, event->x, event->y)) 05295 button_activate_state(C, but, BUTTON_STATE_MENU_OPEN); 05296 } 05297 05298 retval= WM_UI_HANDLER_CONTINUE; 05299 break; 05300 case WHEELUPMOUSE: 05301 case WHEELDOWNMOUSE: 05302 case MIDDLEMOUSE: 05303 /* XXX hardcoded keymap check... but anyway, while view changes, tooltips should be removed */ 05304 if(data->tooltiptimer) { 05305 WM_event_remove_timer(data->wm, data->window, data->tooltiptimer); 05306 data->tooltiptimer= NULL; 05307 } 05308 /* pass on purposedly */ 05309 default: 05310 /* handle button type specific events */ 05311 retval= ui_do_button(C, block, but, event); 05312 } 05313 } 05314 } 05315 else if(data->state == BUTTON_STATE_WAIT_RELEASE) { 05316 switch(event->type) { 05317 case WINDEACTIVATE: 05318 data->cancel= 1; 05319 button_activate_state(C, but, BUTTON_STATE_EXIT); 05320 break; 05321 05322 case MOUSEMOVE: 05323 if(ELEM(but->type,LINK, INLINK)) { 05324 but->flag |= UI_SELECT; 05325 ui_do_button(C, block, but, event); 05326 ED_region_tag_redraw(data->region); 05327 } 05328 else { 05329 /* deselect the button when moving the mouse away */ 05330 /* also de-activate for buttons that only show higlights */ 05331 if(ui_mouse_inside_button(ar, but, event->x, event->y)) { 05332 if(!(but->flag & UI_SELECT)) { 05333 but->flag |= (UI_SELECT|UI_ACTIVE); 05334 data->cancel= 0; 05335 ED_region_tag_redraw(data->region); 05336 } 05337 } 05338 else { 05339 if(but->flag & UI_SELECT) { 05340 but->flag &= ~(UI_SELECT|UI_ACTIVE); 05341 data->cancel= 1; 05342 ED_region_tag_redraw(data->region); 05343 } 05344 } 05345 } 05346 break; 05347 default: 05348 /* otherwise catch mouse release event */ 05349 ui_do_button(C, block, but, event); 05350 break; 05351 } 05352 05353 retval= WM_UI_HANDLER_BREAK; 05354 } 05355 else if(data->state == BUTTON_STATE_WAIT_FLASH) { 05356 switch(event->type) { 05357 case TIMER: { 05358 if(event->customdata == data->flashtimer) 05359 button_activate_state(C, but, BUTTON_STATE_EXIT); 05360 } 05361 } 05362 05363 retval= WM_UI_HANDLER_CONTINUE; 05364 } 05365 else if(data->state == BUTTON_STATE_MENU_OPEN) { 05366 /* check for exit because of mouse-over another button */ 05367 switch(event->type) { 05368 case MOUSEMOVE: 05369 05370 if(data->menu && data->menu->region) 05371 if(ui_mouse_inside_region(data->menu->region, event->x, event->y)) 05372 break; 05373 05374 { 05375 uiBut *bt= ui_but_find_mouse_over(ar, event->x, event->y); 05376 05377 if(bt && bt->active != data) { 05378 if(but->type != COL) /* exception */ 05379 data->cancel= 1; 05380 button_activate_state(C, but, BUTTON_STATE_EXIT); 05381 } 05382 break; 05383 } 05384 } 05385 05386 ui_do_button(C, block, but, event); 05387 retval= WM_UI_HANDLER_CONTINUE; 05388 } 05389 else { 05390 retval= ui_do_button(C, block, but, event); 05391 // retval= WM_UI_HANDLER_BREAK; XXX why ? 05392 } 05393 05394 if(data->state == BUTTON_STATE_EXIT) { 05395 postbut= data->postbut; 05396 posttype= data->posttype; 05397 05398 button_activate_exit(C, data, but, (postbut == NULL), 0); 05399 05400 /* for jumping to the next button with tab while text editing */ 05401 if(postbut) 05402 button_activate_init(C, ar, postbut, posttype); 05403 } 05404 05405 return retval; 05406 } 05407 05408 static int ui_handle_list_event(bContext *C, wmEvent *event, ARegion *ar) 05409 { 05410 uiBut *but= ui_list_find_mouse_over(ar, event->x, event->y); 05411 int retval= WM_UI_HANDLER_CONTINUE; 05412 int value, min, max; 05413 05414 if(but && (event->val == KM_PRESS)) { 05415 Panel *pa= but->block->panel; 05416 05417 if(ELEM(event->type, UPARROWKEY, DOWNARROWKEY) || 05418 ((ELEM(event->type, WHEELUPMOUSE, WHEELDOWNMOUSE) && event->alt))) { 05419 /* activate up/down the list */ 05420 value= RNA_property_int_get(&but->rnapoin, but->rnaprop); 05421 05422 if(ELEM(event->type, UPARROWKEY, WHEELUPMOUSE)) 05423 value--; 05424 else 05425 value++; 05426 05427 if(value < pa->list_scroll) 05428 pa->list_scroll= value; 05429 else if(value >= pa->list_scroll+pa->list_size) 05430 pa->list_scroll= value - pa->list_size + 1; 05431 05432 RNA_property_int_range(&but->rnapoin, but->rnaprop, &min, &max); 05433 value= CLAMPIS(value, min, max); 05434 05435 RNA_property_int_set(&but->rnapoin, but->rnaprop, value); 05436 RNA_property_update(C, &but->rnapoin, but->rnaprop); 05437 ED_region_tag_redraw(ar); 05438 05439 retval= WM_UI_HANDLER_BREAK; 05440 } 05441 else if(ELEM(event->type, WHEELUPMOUSE, WHEELDOWNMOUSE) && event->shift) { 05442 /* silly replacement for proper grip */ 05443 if(pa->list_grip_size == 0) 05444 pa->list_grip_size= pa->list_size; 05445 05446 if(event->type == WHEELUPMOUSE) 05447 pa->list_grip_size--; 05448 else 05449 pa->list_grip_size++; 05450 05451 pa->list_grip_size= MAX2(pa->list_grip_size, 1); 05452 05453 ED_region_tag_redraw(ar); 05454 05455 retval= WM_UI_HANDLER_BREAK; 05456 } 05457 else if(ELEM(event->type, WHEELUPMOUSE, WHEELDOWNMOUSE)) { 05458 /* list template will clamp */ 05459 if(event->type == WHEELUPMOUSE) 05460 pa->list_scroll--; 05461 else 05462 pa->list_scroll++; 05463 05464 ED_region_tag_redraw(ar); 05465 05466 retval= WM_UI_HANDLER_BREAK; 05467 } 05468 } 05469 05470 return retval; 05471 } 05472 05473 static void ui_handle_button_return_submenu(bContext *C, wmEvent *event, uiBut *but) 05474 { 05475 uiHandleButtonData *data; 05476 uiPopupBlockHandle *menu; 05477 05478 data= but->active; 05479 menu= data->menu; 05480 05481 /* copy over return values from the closing menu */ 05482 if(menu->menuretval == UI_RETURN_OK || menu->menuretval == UI_RETURN_UPDATE) { 05483 if(but->type == COL) 05484 VECCOPY(data->vec, menu->retvec) 05485 else if(ELEM3(but->type, MENU, ICONROW, ICONTEXTROW)) 05486 data->value= menu->retvalue; 05487 } 05488 05489 if(menu->menuretval == UI_RETURN_UPDATE) { 05490 if(data->interactive) ui_apply_button(C, but->block, but, data, 1); 05491 else ui_check_but(but); 05492 05493 menu->menuretval= 0; 05494 } 05495 05496 /* now change button state or exit, which will close the submenu */ 05497 if(ELEM(menu->menuretval, UI_RETURN_OK, UI_RETURN_CANCEL)) { 05498 if(menu->menuretval != UI_RETURN_OK) 05499 data->cancel= 1; 05500 05501 button_activate_exit(C, data, but, 1, 0); 05502 } 05503 else if(menu->menuretval == UI_RETURN_OUT) { 05504 if(event->type==MOUSEMOVE && ui_mouse_inside_button(data->region, but, event->x, event->y)) { 05505 button_activate_state(C, but, BUTTON_STATE_HIGHLIGHT); 05506 } 05507 else { 05508 if (ISKEYBOARD(event->type)) { 05509 /* keyboard menu hierarchy navigation, going back to previous level */ 05510 but->active->used_mouse= 0; 05511 button_activate_state(C, but, BUTTON_STATE_HIGHLIGHT); 05512 } 05513 else { 05514 data->cancel= 1; 05515 button_activate_exit(C, data, but, 1, 0); 05516 } 05517 } 05518 } 05519 } 05520 05521 /* ************************* menu handling *******************************/ 05522 05523 /* function used to prevent loosing the open menu when using nested pulldowns, 05524 * when moving mouse towards the pulldown menu over other buttons that could 05525 * steal the highlight from the current button, only checks: 05526 * 05527 * - while mouse moves in triangular area defined old mouse position and 05528 * left/right side of new menu 05529 * - only for 1 second 05530 */ 05531 05532 static void ui_mouse_motion_towards_init(uiPopupBlockHandle *menu, int mx, int my, int force) 05533 { 05534 if(!menu->dotowards || force) { 05535 menu->dotowards= 1; 05536 menu->towardsx= mx; 05537 menu->towardsy= my; 05538 05539 if(force) 05540 menu->towardstime= DBL_MAX; /* unlimited time */ 05541 else 05542 menu->towardstime= PIL_check_seconds_timer(); 05543 } 05544 } 05545 05546 static int ui_mouse_motion_towards_check(uiBlock *block, uiPopupBlockHandle *menu, int mx, int my) 05547 { 05548 float p1[2], p2[2], p3[2], p4[2], oldp[2], newp[2]; 05549 int closer; 05550 05551 if(!menu->dotowards) return 0; 05552 05553 /* verify that we are moving towards one of the edges of the 05554 * menu block, in other words, in the triangle formed by the 05555 * initial mouse location and two edge points. */ 05556 p1[0]= block->minx-20; 05557 p1[1]= block->miny-20; 05558 05559 p2[0]= block->maxx+20; 05560 p2[1]= block->miny-20; 05561 05562 p3[0]= block->maxx+20; 05563 p3[1]= block->maxy+20; 05564 05565 p4[0]= block->minx-20; 05566 p4[1]= block->maxy+20; 05567 05568 oldp[0]= menu->towardsx; 05569 oldp[1]= menu->towardsy; 05570 05571 newp[0]= mx; 05572 newp[1]= my; 05573 05574 if(len_v2v2(oldp, newp) < 4.0f) 05575 return menu->dotowards; 05576 05577 closer= 0; 05578 closer |= isect_point_tri_v2(newp, oldp, p1, p2); 05579 closer |= isect_point_tri_v2(newp, oldp, p2, p3); 05580 closer |= isect_point_tri_v2(newp, oldp, p3, p4); 05581 closer |= isect_point_tri_v2(newp, oldp, p4, p1); 05582 05583 if(!closer) 05584 menu->dotowards= 0; 05585 05586 /* 1 second timer */ 05587 if(PIL_check_seconds_timer() - menu->towardstime > BUTTON_MOUSE_TOWARDS_THRESH) 05588 menu->dotowards= 0; 05589 05590 return menu->dotowards; 05591 } 05592 05593 static char ui_menu_scroll_test(uiBlock *block, int my) 05594 { 05595 if(block->flag & (UI_BLOCK_CLIPTOP|UI_BLOCK_CLIPBOTTOM)) { 05596 if(block->flag & UI_BLOCK_CLIPTOP) 05597 if(my > block->maxy-14) 05598 return 't'; 05599 if(block->flag & UI_BLOCK_CLIPBOTTOM) 05600 if(my < block->miny+14) 05601 return 'b'; 05602 } 05603 return 0; 05604 } 05605 05606 static int ui_menu_scroll(ARegion *ar, uiBlock *block, int my) 05607 { 05608 char test= ui_menu_scroll_test(block, my); 05609 05610 if(test) { 05611 uiBut *b1= block->buttons.first; 05612 uiBut *b2= block->buttons.last; 05613 uiBut *bnext; 05614 uiBut *bprev; 05615 int dy= 0; 05616 05617 /* get first and last visible buttons */ 05618 while(b1 && ui_but_next(b1) && (b1->flag & UI_SCROLLED)) 05619 b1= ui_but_next(b1); 05620 while(b2 && ui_but_prev(b2) && (b2->flag & UI_SCROLLED)) 05621 b2= ui_but_prev(b2); 05622 /* skips separators */ 05623 bnext= ui_but_next(b1); 05624 bprev= ui_but_prev(b2); 05625 05626 if(bnext==NULL || bprev==NULL) 05627 return 0; 05628 05629 if(test=='t') { 05630 /* bottom button is first button */ 05631 if(b1->y1 < b2->y1) 05632 dy= bnext->y1 - b1->y1; 05633 /* bottom button is last button */ 05634 else 05635 dy= bprev->y1 - b2->y1; 05636 } 05637 else if(test=='b') { 05638 /* bottom button is first button */ 05639 if(b1->y1 < b2->y1) 05640 dy= b1->y1 - bnext->y1; 05641 /* bottom button is last button */ 05642 else 05643 dy= b2->y1 - bprev->y1; 05644 } 05645 if(dy) { 05646 05647 for(b1= block->buttons.first; b1; b1= b1->next) { 05648 b1->y1 -= dy; 05649 b1->y2 -= dy; 05650 } 05651 /* set flags again */ 05652 ui_popup_block_scrolltest(block); 05653 05654 ED_region_tag_redraw(ar); 05655 05656 return 1; 05657 } 05658 } 05659 05660 return 0; 05661 } 05662 05663 static int ui_handle_menu_event(bContext *C, wmEvent *event, uiPopupBlockHandle *menu, int UNUSED(topmenu)) 05664 { 05665 ARegion *ar; 05666 uiBlock *block; 05667 uiBut *but, *bt; 05668 int inside, act, count, mx, my, retval; 05669 05670 ar= menu->region; 05671 block= ar->uiblocks.first; 05672 05673 act= 0; 05674 retval= WM_UI_HANDLER_CONTINUE; 05675 05676 mx= event->x; 05677 my= event->y; 05678 ui_window_to_block(ar, block, &mx, &my); 05679 05680 /* check if mouse is inside block */ 05681 inside= 0; 05682 if(block->minx <= mx && block->maxx >= mx) 05683 if(block->miny <= my && block->maxy >= my) 05684 inside= 1; 05685 05686 /* if there's an active modal button, don't check events or outside, except for search menu */ 05687 but= ui_but_find_activated(ar); 05688 if(but && button_modal_state(but->active->state) && but->type!=SEARCH_MENU) { 05689 /* if a button is activated modal, always reset the start mouse 05690 * position of the towards mechanism to avoid loosing focus, 05691 * and don't handle events */ 05692 ui_mouse_motion_towards_init(menu, mx, my, 1); 05693 } 05694 else if(event->type == TIMER) { 05695 if(event->customdata == menu->scrolltimer) 05696 ui_menu_scroll(ar, block, my); 05697 } 05698 else { 05699 /* for ui_mouse_motion_towards_block */ 05700 if(event->type == MOUSEMOVE) { 05701 ui_mouse_motion_towards_init(menu, mx, my, 0); 05702 05703 /* add menu scroll timer, if needed */ 05704 if(ui_menu_scroll_test(block, my)) 05705 if(menu->scrolltimer==NULL) 05706 menu->scrolltimer= 05707 WM_event_add_timer(CTX_wm_manager(C), CTX_wm_window(C), TIMER, MENU_SCROLL_INTERVAL); 05708 } 05709 05710 /* first block own event func */ 05711 if(block->block_event_func && block->block_event_func(C, block, event)); 05712 /* events not for active search menu button */ 05713 else if(but==NULL || but->type!=SEARCH_MENU) { 05714 switch(event->type) { 05715 /* closing sublevels of pulldowns */ 05716 case LEFTARROWKEY: 05717 if(event->val==KM_PRESS && (block->flag & UI_BLOCK_LOOP)) 05718 if(BLI_countlist(&block->saferct) > 0) 05719 menu->menuretval= UI_RETURN_OUT; 05720 05721 retval= WM_UI_HANDLER_BREAK; 05722 break; 05723 05724 /* opening sublevels of pulldowns */ 05725 case RIGHTARROWKEY: 05726 if(event->val==KM_PRESS && (block->flag & UI_BLOCK_LOOP)) { 05727 but= ui_but_find_activated(ar); 05728 05729 if(!but) { 05730 /* no item active, we make first active */ 05731 if(block->direction & UI_TOP) but= ui_but_last(block); 05732 else but= ui_but_first(block); 05733 } 05734 05735 if(but && ELEM(but->type, BLOCK, PULLDOWN)) 05736 ui_handle_button_activate(C, ar, but, BUTTON_ACTIVATE_OPEN); 05737 } 05738 05739 retval= WM_UI_HANDLER_BREAK; 05740 break; 05741 05742 case UPARROWKEY: 05743 case DOWNARROWKEY: 05744 case WHEELUPMOUSE: 05745 case WHEELDOWNMOUSE: 05746 /* arrowkeys: only handle for block_loop blocks */ 05747 if(event->alt || event->shift || event->ctrl || event->oskey); 05748 else if(inside || (block->flag & UI_BLOCK_LOOP)) { 05749 if(event->val==KM_PRESS) { 05750 but= ui_but_find_activated(ar); 05751 if(but) { 05752 /* is there a situation where UI_LEFT or UI_RIGHT would also change navigation direction? */ 05753 if( ((ELEM(event->type, DOWNARROWKEY, WHEELDOWNMOUSE)) && (block->direction & UI_DOWN)) || 05754 ((ELEM(event->type, DOWNARROWKEY, WHEELDOWNMOUSE)) && (block->direction & UI_RIGHT)) || 05755 ((ELEM(event->type, UPARROWKEY, WHEELUPMOUSE)) && (block->direction & UI_TOP)) 05756 ) { 05757 /* the following is just a hack - uiBut->type set to BUT and BUTM have there menus built 05758 * opposite ways - this should be changed so that all popup-menus use the same uiBlock->direction */ 05759 if(but->type & BUT) 05760 but= ui_but_next(but); 05761 else 05762 but= ui_but_prev(but); 05763 } 05764 else { 05765 if(but->type & BUT) 05766 but= ui_but_prev(but); 05767 else 05768 but= ui_but_next(but); 05769 } 05770 05771 if(but) 05772 ui_handle_button_activate(C, ar, but, BUTTON_ACTIVATE); 05773 } 05774 05775 if(!but) { 05776 if( ((ELEM(event->type, UPARROWKEY, WHEELUPMOUSE)) && (block->direction & UI_DOWN)) || 05777 ((ELEM(event->type, UPARROWKEY, WHEELUPMOUSE)) && (block->direction & UI_RIGHT)) || 05778 ((ELEM(event->type, DOWNARROWKEY, WHEELDOWNMOUSE)) && (block->direction & UI_TOP)) 05779 ) { 05780 if((bt= ui_but_first(block)) && (bt->type & BUT)) { 05781 bt= ui_but_last(block); 05782 } 05783 else { 05784 /* keep ui_but_first() */ 05785 } 05786 } 05787 else { 05788 if((bt= ui_but_first(block)) && (bt->type & BUT)) { 05789 /* keep ui_but_first() */ 05790 } 05791 else { 05792 bt= ui_but_last(block); 05793 } 05794 } 05795 05796 if(bt) 05797 ui_handle_button_activate(C, ar, bt, BUTTON_ACTIVATE); 05798 } 05799 } 05800 05801 retval= WM_UI_HANDLER_BREAK; 05802 } 05803 05804 break; 05805 05806 case ONEKEY: case PAD1: 05807 act= 1; 05808 case TWOKEY: case PAD2: 05809 if(act==0) act= 2; 05810 case THREEKEY: case PAD3: 05811 if(act==0) act= 3; 05812 case FOURKEY: case PAD4: 05813 if(act==0) act= 4; 05814 case FIVEKEY: case PAD5: 05815 if(act==0) act= 5; 05816 case SIXKEY: case PAD6: 05817 if(act==0) act= 6; 05818 case SEVENKEY: case PAD7: 05819 if(act==0) act= 7; 05820 case EIGHTKEY: case PAD8: 05821 if(act==0) act= 8; 05822 case NINEKEY: case PAD9: 05823 if(act==0) act= 9; 05824 case ZEROKEY: case PAD0: 05825 if(act==0) act= 10; 05826 05827 if((block->flag & UI_BLOCK_NUMSELECT) && event->val==KM_PRESS) { 05828 if(event->alt) act+= 10; 05829 05830 count= 0; 05831 for(but= block->buttons.first; but; but= but->next) { 05832 int doit= 0; 05833 05834 if(but->type!=LABEL && but->type!=SEPR) 05835 count++; 05836 05837 /* exception for rna layer buts */ 05838 if(but->rnapoin.data && but->rnaprop) { 05839 if (ELEM(RNA_property_subtype(but->rnaprop), PROP_LAYER, PROP_LAYER_MEMBER)) { 05840 if (but->rnaindex== act-1) 05841 doit=1; 05842 } 05843 } 05844 /* exception for menus like layer buts, with button aligning they're not drawn in order */ 05845 else if(but->type==TOGR) { 05846 if(but->bitnr==act-1) 05847 doit= 1; 05848 } 05849 else if(count==act) 05850 doit=1; 05851 05852 if(doit) { 05853 ui_handle_button_activate(C, ar, but, BUTTON_ACTIVATE_APPLY); 05854 break; 05855 } 05856 } 05857 05858 retval= WM_UI_HANDLER_BREAK; 05859 } 05860 break; 05861 05862 /* Handle keystrokes on menu items */ 05863 case AKEY: 05864 case BKEY: 05865 case CKEY: 05866 case DKEY: 05867 case EKEY: 05868 case FKEY: 05869 case GKEY: 05870 case HKEY: 05871 case IKEY: 05872 case JKEY: 05873 case KKEY: 05874 case LKEY: 05875 case MKEY: 05876 case NKEY: 05877 case OKEY: 05878 case PKEY: 05879 case QKEY: 05880 case RKEY: 05881 case SKEY: 05882 case TKEY: 05883 case UKEY: 05884 case VKEY: 05885 case WKEY: 05886 case XKEY: 05887 case YKEY: 05888 case ZKEY: 05889 { 05890 if( (event->val == KM_PRESS) && 05891 (event->shift == FALSE) && 05892 (event->ctrl == FALSE) && 05893 (event->oskey == FALSE) 05894 ) { 05895 for(but= block->buttons.first; but; but= but->next) { 05896 05897 if(but->menu_key==event->type) { 05898 if(but->type == BUT) { 05899 /* mainly for operator buttons */ 05900 ui_handle_button_activate(C, ar, but, BUTTON_ACTIVATE_APPLY); 05901 } 05902 else if(ELEM(but->type, BLOCK, PULLDOWN)) { 05903 /* open submenus (like right arrow key) */ 05904 ui_handle_button_activate(C, ar, but, BUTTON_ACTIVATE_OPEN); 05905 } 05906 else if (but->type == MENU) { 05907 /* activate menu items */ 05908 ui_handle_button_activate(C, ar, but, BUTTON_ACTIVATE); 05909 } 05910 else { 05911 printf("Error, but->menu_key type: %d\n", but->type); 05912 } 05913 05914 break; 05915 } 05916 } 05917 05918 retval= WM_UI_HANDLER_BREAK; 05919 } 05920 break; 05921 } 05922 } 05923 } 05924 05925 /* here we check return conditions for menus */ 05926 if(block->flag & UI_BLOCK_LOOP) { 05927 /* if we click outside the block, verify if we clicked on the 05928 * button that opened us, otherwise we need to close */ 05929 if(inside==0) { 05930 uiSafetyRct *saferct= block->saferct.first; 05931 05932 if(ELEM3(event->type, LEFTMOUSE, MIDDLEMOUSE, RIGHTMOUSE) && event->val==KM_PRESS) { 05933 if(saferct && !BLI_in_rctf(&saferct->parent, event->x, event->y)) { 05934 if(block->flag & (UI_BLOCK_OUT_1)) 05935 menu->menuretval= UI_RETURN_OK; 05936 else 05937 menu->menuretval= UI_RETURN_OUT; 05938 } 05939 } 05940 } 05941 05942 if(menu->menuretval); 05943 else if(event->type==ESCKEY && event->val==KM_PRESS) { 05944 /* esc cancels this and all preceding menus */ 05945 menu->menuretval= UI_RETURN_CANCEL; 05946 } 05947 else if(ELEM(event->type, RETKEY, PADENTER) && event->val==KM_PRESS) { 05948 /* enter will always close this block, we let the event 05949 * get handled by the button if it is activated, otherwise we cancel */ 05950 if(!ui_but_find_activated(ar)) 05951 menu->menuretval= UI_RETURN_CANCEL; 05952 } 05953 else { 05954 ui_mouse_motion_towards_check(block, menu, mx, my); 05955 05956 /* check mouse moving outside of the menu */ 05957 if(inside==0 && (block->flag & UI_BLOCK_MOVEMOUSE_QUIT)) { 05958 uiSafetyRct *saferct; 05959 05960 /* check for all parent rects, enables arrowkeys to be used */ 05961 for(saferct=block->saferct.first; saferct; saferct= saferct->next) { 05962 /* for mouse move we only check our own rect, for other 05963 * events we check all preceding block rects too to make 05964 * arrow keys navigation work */ 05965 if(event->type!=MOUSEMOVE || saferct==block->saferct.first) { 05966 if(BLI_in_rctf(&saferct->parent, (float)event->x, (float)event->y)) 05967 break; 05968 if(BLI_in_rctf(&saferct->safety, (float)event->x, (float)event->y)) 05969 break; 05970 } 05971 } 05972 05973 /* strict check, and include the parent rect */ 05974 if(!menu->dotowards && !saferct) { 05975 if(block->flag & (UI_BLOCK_OUT_1)) 05976 menu->menuretval= UI_RETURN_OK; 05977 else 05978 menu->menuretval= UI_RETURN_OUT; 05979 } 05980 else if(menu->dotowards && event->type==MOUSEMOVE) 05981 retval= WM_UI_HANDLER_BREAK; 05982 } 05983 } 05984 } 05985 } 05986 05987 /* if we are didn't handle the event yet, lets pass it on to 05988 * buttons inside this region. disabled inside check .. not sure 05989 * anymore why it was there? but it meant enter didn't work 05990 * for example when mouse was not over submenu */ 05991 if((/*inside &&*/ (!menu->menuretval || menu->menuretval == UI_RETURN_UPDATE) && retval == WM_UI_HANDLER_CONTINUE) || event->type == TIMER) { 05992 but= ui_but_find_activated(ar); 05993 05994 if(but) { 05995 ScrArea *ctx_area= CTX_wm_area(C); 05996 ARegion *ctx_region= CTX_wm_region(C); 05997 05998 if(menu->ctx_area) CTX_wm_area_set(C, menu->ctx_area); 05999 if(menu->ctx_region) CTX_wm_region_set(C, menu->ctx_region); 06000 06001 retval= ui_handle_button_event(C, event, but); 06002 06003 if(menu->ctx_area) CTX_wm_area_set(C, ctx_area); 06004 if(menu->ctx_region) CTX_wm_region_set(C, ctx_region); 06005 } 06006 else 06007 retval= ui_handle_button_over(C, event, ar); 06008 } 06009 06010 /* if we set a menu return value, ensure we continue passing this on to 06011 * lower menus and buttons, so always set continue then, and if we are 06012 * inside the region otherwise, ensure we swallow the event */ 06013 if(menu->menuretval) 06014 return WM_UI_HANDLER_CONTINUE; 06015 else if(inside) 06016 return WM_UI_HANDLER_BREAK; 06017 else 06018 return retval; 06019 } 06020 06021 static int ui_handle_menu_return_submenu(bContext *C, wmEvent *event, uiPopupBlockHandle *menu) 06022 { 06023 ARegion *ar; 06024 uiBut *but; 06025 uiBlock *block; 06026 uiHandleButtonData *data; 06027 uiPopupBlockHandle *submenu; 06028 int mx, my, update; 06029 06030 ar= menu->region; 06031 block= ar->uiblocks.first; 06032 06033 but= ui_but_find_activated(ar); 06034 data= but->active; 06035 submenu= data->menu; 06036 06037 if(submenu->menuretval) { 06038 /* first decide if we want to close our own menu cascading, if 06039 * so pass on the sub menu return value to our own menu handle */ 06040 if(ELEM(submenu->menuretval, UI_RETURN_OK, UI_RETURN_CANCEL)) { 06041 if(!(block->flag & UI_BLOCK_KEEP_OPEN)) { 06042 menu->menuretval= submenu->menuretval; 06043 menu->butretval= data->retval; 06044 } 06045 } 06046 06047 update= (submenu->menuretval == UI_RETURN_UPDATE); 06048 06049 /* now let activated button in this menu exit, which 06050 * will actually close the submenu too */ 06051 ui_handle_button_return_submenu(C, event, but); 06052 06053 if(update) 06054 submenu->menuretval = 0; 06055 } 06056 06057 /* for cases where close does not cascade, allow the user to 06058 * move the mouse back towards the menu without closing */ 06059 mx= event->x; 06060 my= event->y; 06061 ui_window_to_block(ar, block, &mx, &my); 06062 ui_mouse_motion_towards_init(menu, mx, my, 1); 06063 06064 if(menu->menuretval) 06065 return WM_UI_HANDLER_CONTINUE; 06066 else 06067 return WM_UI_HANDLER_BREAK; 06068 } 06069 06070 static int ui_handle_menus_recursive(bContext *C, wmEvent *event, uiPopupBlockHandle *menu) 06071 { 06072 uiBut *but; 06073 uiHandleButtonData *data; 06074 uiPopupBlockHandle *submenu; 06075 int retval= WM_UI_HANDLER_CONTINUE; 06076 06077 /* check if we have a submenu, and handle events for it first */ 06078 but= ui_but_find_activated(menu->region); 06079 data= (but)? but->active: NULL; 06080 submenu= (data)? data->menu: NULL; 06081 06082 if(submenu) 06083 retval= ui_handle_menus_recursive(C, event, submenu); 06084 06085 /* now handle events for our own menu */ 06086 if(retval == WM_UI_HANDLER_CONTINUE || event->type == TIMER) { 06087 if(submenu && submenu->menuretval) 06088 retval= ui_handle_menu_return_submenu(C, event, menu); 06089 else 06090 retval= ui_handle_menu_event(C, event, menu, (submenu == NULL)); 06091 } 06092 06093 return retval; 06094 } 06095 06096 /* *************** UI event handlers **************** */ 06097 06098 static int ui_handler_region(bContext *C, wmEvent *event, void *UNUSED(userdata)) 06099 { 06100 ARegion *ar; 06101 uiBut *but; 06102 int retval; 06103 06104 /* here we handle buttons at the region level, non-modal */ 06105 ar= CTX_wm_region(C); 06106 retval= WM_UI_HANDLER_CONTINUE; 06107 06108 if(ar==NULL) return retval; 06109 if(ar->uiblocks.first==NULL) return retval; 06110 06111 /* either handle events for already activated button or try to activate */ 06112 but= ui_but_find_activated(ar); 06113 06114 retval= ui_handler_panel_region(C, event); 06115 06116 if(retval == WM_UI_HANDLER_CONTINUE) 06117 retval= ui_handle_list_event(C, event, ar); 06118 06119 if(retval == WM_UI_HANDLER_CONTINUE) { 06120 if(but) 06121 retval= ui_handle_button_event(C, event, but); 06122 else 06123 retval= ui_handle_button_over(C, event, ar); 06124 } 06125 06126 /* re-enable tooltips */ 06127 if(event->type == MOUSEMOVE && (event->x!=event->prevx || event->y!=event->prevy)) 06128 ui_blocks_set_tooltips(ar, 1); 06129 06130 /* delayed apply callbacks */ 06131 ui_apply_but_funcs_after(C); 06132 06133 return retval; 06134 } 06135 06136 static void ui_handler_remove_region(bContext *C, void *UNUSED(userdata)) 06137 { 06138 bScreen *sc; 06139 ARegion *ar; 06140 06141 ar= CTX_wm_region(C); 06142 if(ar == NULL) return; 06143 06144 uiFreeBlocks(C, &ar->uiblocks); 06145 06146 sc= CTX_wm_screen(C); 06147 if(sc == NULL) return; 06148 06149 /* delayed apply callbacks, but not for screen level regions, those 06150 * we rather do at the very end after closing them all, which will 06151 * be done in ui_handler_region/window */ 06152 if(BLI_findindex(&sc->regionbase, ar) == -1) 06153 ui_apply_but_funcs_after(C); 06154 } 06155 06156 static int ui_handler_region_menu(bContext *C, wmEvent *event, void *UNUSED(userdata)) 06157 { 06158 ARegion *ar; 06159 uiBut *but; 06160 uiHandleButtonData *data; 06161 int retval; 06162 06163 /* here we handle buttons at the window level, modal, for example 06164 * while number sliding, text editing, or when a menu block is open */ 06165 ar= CTX_wm_menu(C); 06166 if(!ar) 06167 ar= CTX_wm_region(C); 06168 06169 but= ui_but_find_activated(ar); 06170 06171 if(but) { 06172 /* handle activated button events */ 06173 data= but->active; 06174 06175 if(data->state == BUTTON_STATE_MENU_OPEN) { 06176 /* handle events for menus and their buttons recursively, 06177 * this will handle events from the top to the bottom menu */ 06178 retval= ui_handle_menus_recursive(C, event, data->menu); 06179 06180 /* handle events for the activated button */ 06181 if(retval == WM_UI_HANDLER_CONTINUE || event->type == TIMER) { 06182 if(data->menu->menuretval) 06183 ui_handle_button_return_submenu(C, event, but); 06184 else 06185 ui_handle_button_event(C, event, but); 06186 } 06187 } 06188 else { 06189 /* handle events for the activated button */ 06190 ui_handle_button_event(C, event, but); 06191 } 06192 } 06193 06194 /* re-enable tooltips */ 06195 if(event->type == MOUSEMOVE && (event->x!=event->prevx || event->y!=event->prevy)) 06196 ui_blocks_set_tooltips(ar, 1); 06197 06198 /* delayed apply callbacks */ 06199 ui_apply_but_funcs_after(C); 06200 06201 /* we block all events, this is modal interaction */ 06202 return WM_UI_HANDLER_BREAK; 06203 } 06204 06205 /* two types of popups, one with operator + enum, other with regular callbacks */ 06206 static int ui_handler_popup(bContext *C, wmEvent *event, void *userdata) 06207 { 06208 uiPopupBlockHandle *menu= userdata; 06209 06210 ui_handle_menus_recursive(C, event, menu); 06211 06212 /* free if done, does not free handle itself */ 06213 if(menu->menuretval) { 06214 /* copy values, we have to free first (closes region) */ 06215 uiPopupBlockHandle temp= *menu; 06216 06217 ui_popup_block_free(C, menu); 06218 UI_remove_popup_handlers(&CTX_wm_window(C)->modalhandlers, menu); 06219 06220 if(temp.menuretval == UI_RETURN_OK) { 06221 if(temp.popup_func) 06222 temp.popup_func(C, temp.popup_arg, temp.retvalue); 06223 if(temp.optype) 06224 WM_operator_name_call(C, temp.optype->idname, temp.opcontext, NULL); 06225 } 06226 else if(temp.cancel_func) 06227 temp.cancel_func(temp.popup_arg); 06228 } 06229 else { 06230 /* re-enable tooltips */ 06231 if(event->type == MOUSEMOVE && (event->x!=event->prevx || event->y!=event->prevy)) 06232 ui_blocks_set_tooltips(menu->region, 1); 06233 } 06234 06235 /* delayed apply callbacks */ 06236 ui_apply_but_funcs_after(C); 06237 06238 /* we block all events, this is modal interaction */ 06239 return WM_UI_HANDLER_BREAK; 06240 } 06241 06242 static void ui_handler_remove_popup(bContext *C, void *userdata) 06243 { 06244 uiPopupBlockHandle *menu= userdata; 06245 06246 /* free menu block if window is closed for some reason */ 06247 ui_popup_block_free(C, menu); 06248 06249 /* delayed apply callbacks */ 06250 ui_apply_but_funcs_after(C); 06251 } 06252 06253 void UI_add_region_handlers(ListBase *handlers) 06254 { 06255 WM_event_remove_ui_handler(handlers, ui_handler_region, ui_handler_remove_region, NULL, 0); 06256 WM_event_add_ui_handler(NULL, handlers, ui_handler_region, ui_handler_remove_region, NULL); 06257 } 06258 06259 void UI_add_popup_handlers(bContext *C, ListBase *handlers, uiPopupBlockHandle *popup) 06260 { 06261 WM_event_add_ui_handler(C, handlers, ui_handler_popup, ui_handler_remove_popup, popup); 06262 } 06263 06264 void UI_remove_popup_handlers(ListBase *handlers, uiPopupBlockHandle *popup) 06265 { 06266 WM_event_remove_ui_handler(handlers, ui_handler_popup, ui_handler_remove_popup, popup, 0); 06267 } 06268 06269