Blender V2.61 - r43446
|
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 * Contributor(s): Campbell Barton 00019 * 00020 * ***** END GPL LICENSE BLOCK ***** 00021 */ 00022 00028 #include <stdlib.h> 00029 #include <string.h> 00030 #include <ctype.h> /* ispunct */ 00031 #include <sys/stat.h> 00032 00033 #include "MEM_guardedalloc.h" 00034 00035 #include "DNA_userdef_types.h" 00036 00037 #include "BLI_blenlib.h" 00038 #include "BLI_dynstr.h" 00039 #include "BLI_utildefines.h" 00040 00041 #include "BKE_context.h" 00042 #include "BKE_text.h" /* only for character utility funcs */ 00043 00044 #include "WM_api.h" 00045 #include "WM_types.h" 00046 00047 #include "UI_view2d.h" 00048 #include "ED_screen.h" 00049 00050 #include "RNA_access.h" 00051 #include "RNA_define.h" 00052 00053 #include "console_intern.h" 00054 00055 /* so when we type - the view scrolls to the bottom */ 00056 static void console_scroll_bottom(ARegion *ar) 00057 { 00058 View2D *v2d= &ar->v2d; 00059 v2d->cur.ymin = 0.0; 00060 v2d->cur.ymax =(float)v2d->winy; 00061 } 00062 00063 static void console_textview_update_rect(SpaceConsole *sc, ARegion *ar) 00064 { 00065 View2D *v2d= &ar->v2d; 00066 00067 UI_view2d_totRect_set(v2d, ar->winx-1, console_textview_height(sc, ar)); 00068 } 00069 00070 static void console_select_offset(SpaceConsole *sc, const int offset) 00071 { 00072 sc->sel_start += offset; 00073 sc->sel_end += offset; 00074 } 00075 00076 void console_history_free(SpaceConsole *sc, ConsoleLine *cl) 00077 { 00078 BLI_remlink(&sc->history, cl); 00079 MEM_freeN(cl->line); 00080 MEM_freeN(cl); 00081 } 00082 void console_scrollback_free(SpaceConsole *sc, ConsoleLine *cl) 00083 { 00084 BLI_remlink(&sc->scrollback, cl); 00085 MEM_freeN(cl->line); 00086 MEM_freeN(cl); 00087 } 00088 00089 static void console_scrollback_limit(SpaceConsole *sc) 00090 { 00091 int tot; 00092 00093 if (U.scrollback < 32) U.scrollback= 256; // XXX - save in user defaults 00094 00095 for(tot= BLI_countlist(&sc->scrollback); tot > U.scrollback; tot--) 00096 console_scrollback_free(sc, sc->scrollback.first); 00097 } 00098 00099 static ConsoleLine * console_history_find(SpaceConsole *sc, const char *str, ConsoleLine *cl_ignore) 00100 { 00101 ConsoleLine *cl; 00102 00103 for(cl= sc->history.last; cl; cl= cl->prev) { 00104 if (cl==cl_ignore) 00105 continue; 00106 00107 if(strcmp(str, cl->line)==0) 00108 return cl; 00109 } 00110 00111 return NULL; 00112 } 00113 00114 /* return 0 if no change made, clamps the range */ 00115 static int console_line_cursor_set(ConsoleLine *cl, int cursor) 00116 { 00117 int cursor_new; 00118 00119 if(cursor < 0) cursor_new= 0; 00120 else if(cursor > cl->len) cursor_new= cl->len; 00121 else cursor_new= cursor; 00122 00123 if(cursor_new == cl->cursor) 00124 return 0; 00125 00126 cl->cursor= cursor_new; 00127 return 1; 00128 } 00129 00130 static char cursor_char(ConsoleLine *cl) 00131 { 00132 /* assume cursor is clamped */ 00133 return cl->line[cl->cursor]; 00134 } 00135 00136 static char cursor_char_prev(ConsoleLine *cl) 00137 { 00138 /* assume cursor is clamped */ 00139 if(cl->cursor <= 0) 00140 return '\0'; 00141 00142 return cl->line[cl->cursor-1]; 00143 } 00144 00145 #if 0 // XXX unused 00146 static char cursor_char_next(ConsoleLine *cl) 00147 { 00148 /* assume cursor is clamped */ 00149 if(cl->cursor + 1 >= cl->len) 00150 return '\0'; 00151 00152 return cl->line[cl->cursor+1]; 00153 } 00154 00155 static void console_lb_debug__internal(ListBase *lb) 00156 { 00157 ConsoleLine *cl; 00158 00159 printf("%d: ", BLI_countlist(lb)); 00160 for(cl= lb->first; cl; cl= cl->next) 00161 printf("<%s> ", cl->line); 00162 printf("\n"); 00163 00164 } 00165 00166 static void console_history_debug(const bContext *C) 00167 { 00168 SpaceConsole *sc= CTX_wm_space_console(C); 00169 00170 00171 console_lb_debug__internal(&sc->history); 00172 } 00173 #endif 00174 00175 static ConsoleLine *console_lb_add__internal(ListBase *lb, ConsoleLine *from) 00176 { 00177 ConsoleLine *ci= MEM_callocN(sizeof(ConsoleLine), "ConsoleLine Add"); 00178 00179 if(from) { 00180 ci->line= BLI_strdup(from->line); 00181 ci->len= strlen(ci->line); 00182 ci->len_alloc= ci->len; 00183 00184 ci->cursor= from->cursor; 00185 ci->type= from->type; 00186 } else { 00187 ci->line= MEM_callocN(64, "console-in-line"); 00188 ci->len_alloc= 64; 00189 ci->len= 0; 00190 } 00191 00192 BLI_addtail(lb, ci); 00193 return ci; 00194 } 00195 00196 static ConsoleLine *console_history_add(const bContext *C, ConsoleLine *from) 00197 { 00198 SpaceConsole *sc= CTX_wm_space_console(C); 00199 00200 return console_lb_add__internal(&sc->history, from); 00201 } 00202 00203 #if 0 /* may use later ? */ 00204 static ConsoleLine *console_scrollback_add(const bContext *C, ConsoleLine *from) 00205 { 00206 SpaceConsole *sc= CTX_wm_space_console(C); 00207 00208 return console_lb_add__internal(&sc->scrollback, from); 00209 } 00210 #endif 00211 00212 static ConsoleLine *console_lb_add_str__internal(ListBase *lb, char *str, int own) 00213 { 00214 ConsoleLine *ci= MEM_callocN(sizeof(ConsoleLine), "ConsoleLine Add"); 00215 if(own) ci->line= str; 00216 else ci->line= BLI_strdup(str); 00217 00218 ci->len = ci->len_alloc = strlen(str); 00219 00220 BLI_addtail(lb, ci); 00221 return ci; 00222 } 00223 ConsoleLine *console_history_add_str(SpaceConsole *sc, char *str, int own) 00224 { 00225 return console_lb_add_str__internal(&sc->history, str, own); 00226 } 00227 ConsoleLine *console_scrollback_add_str(SpaceConsole *sc, char *str, int own) 00228 { 00229 ConsoleLine *ci= console_lb_add_str__internal(&sc->scrollback, str, own); 00230 console_select_offset(sc, ci->len + 1); 00231 return ci; 00232 } 00233 00234 ConsoleLine *console_history_verify(const bContext *C) 00235 { 00236 SpaceConsole *sc= CTX_wm_space_console(C); 00237 ConsoleLine *ci= sc->history.last; 00238 if(ci==NULL) 00239 ci= console_history_add(C, NULL); 00240 00241 return ci; 00242 } 00243 00244 00245 static void console_line_verify_length(ConsoleLine *ci, int len) 00246 { 00247 /* resize the buffer if needed */ 00248 if(len >= ci->len_alloc) { 00249 int new_len= len * 2; /* new length */ 00250 char *new_line= MEM_callocN(new_len, "console line"); 00251 memcpy(new_line, ci->line, ci->len); 00252 MEM_freeN(ci->line); 00253 00254 ci->line= new_line; 00255 ci->len_alloc= new_len; 00256 } 00257 } 00258 00259 static int console_line_insert(ConsoleLine *ci, char *str) 00260 { 00261 int len = strlen(str); 00262 00263 if(len>0 && str[len-1]=='\n') {/* stop new lines being pasted at the end of lines */ 00264 str[len-1]= '\0'; 00265 len--; 00266 } 00267 00268 if(len==0) 00269 return 0; 00270 00271 console_line_verify_length(ci, len + ci->len); 00272 00273 memmove(ci->line+ci->cursor+len, ci->line+ci->cursor, (ci->len - ci->cursor)+1); 00274 memcpy(ci->line+ci->cursor, str, len); 00275 00276 ci->len += len; 00277 ci->cursor += len; 00278 00279 return len; 00280 } 00281 00282 /* static funcs for text editing */ 00283 00284 /* similar to the text editor, with some not used. keep compatible */ 00285 static EnumPropertyItem console_move_type_items[]= { 00286 {LINE_BEGIN, "LINE_BEGIN", 0, "Line Begin", ""}, 00287 {LINE_END, "LINE_END", 0, "Line End", ""}, 00288 {PREV_CHAR, "PREVIOUS_CHARACTER", 0, "Previous Character", ""}, 00289 {NEXT_CHAR, "NEXT_CHARACTER", 0, "Next Character", ""}, 00290 {PREV_WORD, "PREVIOUS_WORD", 0, "Previous Word", ""}, 00291 {NEXT_WORD, "NEXT_WORD", 0, "Next Word", ""}, 00292 {0, NULL, 0, NULL, NULL}}; 00293 00294 static int console_move_exec(bContext *C, wmOperator *op) 00295 { 00296 ConsoleLine *ci= console_history_verify(C); 00297 00298 int type= RNA_enum_get(op->ptr, "type"); 00299 int done= 0; 00300 00301 switch(type) { 00302 case LINE_BEGIN: 00303 done= console_line_cursor_set(ci, 0); 00304 break; 00305 case LINE_END: 00306 done= console_line_cursor_set(ci, INT_MAX); 00307 break; 00308 case PREV_CHAR: 00309 done= console_line_cursor_set(ci, ci->cursor-1); 00310 break; 00311 case NEXT_CHAR: 00312 done= console_line_cursor_set(ci, ci->cursor+1); 00313 break; 00314 00315 /* - if the character is a delimiter then skip delimiters (including white space) 00316 * - when jump over the word */ 00317 case PREV_WORD: 00318 while(text_check_delim(cursor_char_prev(ci))) 00319 if(console_line_cursor_set(ci, ci->cursor-1)==FALSE) 00320 break; 00321 00322 while(text_check_delim(cursor_char_prev(ci))==FALSE) 00323 if(console_line_cursor_set(ci, ci->cursor-1)==FALSE) 00324 break; 00325 00326 /* This isnt used for NEXT_WORD because when going back 00327 * its more useful to have the cursor directly after a word then whitespace */ 00328 while(text_check_whitespace(cursor_char_prev(ci))==TRUE) 00329 if(console_line_cursor_set(ci, ci->cursor-1)==FALSE) 00330 break; 00331 00332 done= 1; /* assume changed */ 00333 break; 00334 case NEXT_WORD: 00335 while(text_check_delim(cursor_char(ci))==TRUE) 00336 if (console_line_cursor_set(ci, ci->cursor+1)==FALSE) 00337 break; 00338 00339 while(text_check_delim(cursor_char(ci))==FALSE) 00340 if (console_line_cursor_set(ci, ci->cursor+1)==FALSE) 00341 break; 00342 00343 done= 1; /* assume changed */ 00344 break; 00345 } 00346 00347 if(done) { 00348 ScrArea *sa= CTX_wm_area(C); 00349 ARegion *ar= CTX_wm_region(C); 00350 00351 ED_area_tag_redraw(sa); 00352 console_scroll_bottom(ar); 00353 } 00354 00355 00356 return OPERATOR_FINISHED; 00357 } 00358 00359 void CONSOLE_OT_move(wmOperatorType *ot) 00360 { 00361 /* identifiers */ 00362 ot->name= "Move Cursor"; 00363 ot->description= "Move cursor position"; 00364 ot->idname= "CONSOLE_OT_move"; 00365 00366 /* api callbacks */ 00367 ot->exec= console_move_exec; 00368 ot->poll= ED_operator_console_active; 00369 00370 /* properties */ 00371 RNA_def_enum(ot->srna, "type", console_move_type_items, LINE_BEGIN, "Type", "Where to move cursor to"); 00372 } 00373 00374 #define TAB_LENGTH 4 00375 static int console_insert_exec(bContext *C, wmOperator *op) 00376 { 00377 SpaceConsole *sc= CTX_wm_space_console(C); 00378 ARegion *ar= CTX_wm_region(C); 00379 ConsoleLine *ci= console_history_verify(C); 00380 char *str= RNA_string_get_alloc(op->ptr, "text", NULL, 0); 00381 int len; 00382 00383 // XXX, alligned tab key hack 00384 if(str[0]=='\t' && str[1]=='\0') { 00385 len= TAB_LENGTH - (ci->cursor % TAB_LENGTH); 00386 MEM_freeN(str); 00387 str= MEM_mallocN(len + 1, "insert_exec"); 00388 memset(str, ' ', len); 00389 str[len]= '\0'; 00390 } 00391 00392 len= console_line_insert(ci, str); 00393 00394 MEM_freeN(str); 00395 00396 if(len==0) { 00397 return OPERATOR_CANCELLED; 00398 } 00399 else { 00400 console_select_offset(sc, len); 00401 } 00402 00403 console_textview_update_rect(sc, ar); 00404 ED_area_tag_redraw(CTX_wm_area(C)); 00405 00406 console_scroll_bottom(ar); 00407 00408 return OPERATOR_FINISHED; 00409 } 00410 00411 static int console_insert_invoke(bContext *C, wmOperator *op, wmEvent *event) 00412 { 00413 // if(!RNA_struct_property_is_set(op->ptr, "text")) { /* always set from keymap XXX */ 00414 if(!RNA_string_length(op->ptr, "text")) { 00415 /* if alt/ctrl/super are pressed pass through */ 00416 if(event->ctrl || event->oskey) { 00417 return OPERATOR_PASS_THROUGH; 00418 } 00419 else { 00420 char str[2]; 00421 str[0]= event->ascii; 00422 str[1]= '\0'; 00423 00424 RNA_string_set(op->ptr, "text", str); 00425 } 00426 } 00427 return console_insert_exec(C, op); 00428 } 00429 00430 void CONSOLE_OT_insert(wmOperatorType *ot) 00431 { 00432 /* identifiers */ 00433 ot->name= "Insert"; 00434 ot->description= "Insert text at cursor position"; 00435 ot->idname= "CONSOLE_OT_insert"; 00436 00437 /* api callbacks */ 00438 ot->exec= console_insert_exec; 00439 ot->invoke= console_insert_invoke; 00440 ot->poll= ED_operator_console_active; 00441 00442 /* properties */ 00443 RNA_def_string(ot->srna, "text", "", 0, "Text", "Text to insert at the cursor position"); 00444 } 00445 00446 00447 static EnumPropertyItem console_delete_type_items[]= { 00448 {DEL_NEXT_CHAR, "NEXT_CHARACTER", 0, "Next Character", ""}, 00449 {DEL_PREV_CHAR, "PREVIOUS_CHARACTER", 0, "Previous Character", ""}, 00450 // {DEL_NEXT_WORD, "NEXT_WORD", 0, "Next Word", ""}, 00451 // {DEL_PREV_WORD, "PREVIOUS_WORD", 0, "Previous Word", ""}, 00452 {0, NULL, 0, NULL, NULL}}; 00453 00454 static int console_delete_exec(bContext *C, wmOperator *op) 00455 { 00456 SpaceConsole *sc= CTX_wm_space_console(C); 00457 ARegion *ar= CTX_wm_region(C); 00458 ConsoleLine *ci= console_history_verify(C); 00459 00460 const short type= RNA_enum_get(op->ptr, "type"); 00461 int done = 0; 00462 00463 if(ci->len==0) { 00464 return OPERATOR_CANCELLED; 00465 } 00466 00467 switch(type) { 00468 case DEL_NEXT_CHAR: 00469 if(ci->cursor < ci->len) { 00470 memmove(ci->line + ci->cursor, ci->line + ci->cursor+1, (ci->len - ci->cursor)+1); 00471 ci->len--; 00472 done= 1; 00473 } 00474 break; 00475 case DEL_PREV_CHAR: 00476 if(ci->cursor > 0) { 00477 ci->cursor--; /* same as above */ 00478 memmove(ci->line + ci->cursor, ci->line + ci->cursor+1, (ci->len - ci->cursor)+1); 00479 ci->len--; 00480 done= 1; 00481 } 00482 break; 00483 } 00484 00485 if(!done) { 00486 return OPERATOR_CANCELLED; 00487 } 00488 else { 00489 console_select_offset(sc, -1); 00490 } 00491 00492 console_textview_update_rect(sc, ar); 00493 ED_area_tag_redraw(CTX_wm_area(C)); 00494 00495 console_scroll_bottom(ar); 00496 00497 return OPERATOR_FINISHED; 00498 } 00499 00500 00501 void CONSOLE_OT_delete(wmOperatorType *ot) 00502 { 00503 /* identifiers */ 00504 ot->name= "Delete"; 00505 ot->description= "Delete text by cursor position"; 00506 ot->idname= "CONSOLE_OT_delete"; 00507 00508 /* api callbacks */ 00509 ot->exec= console_delete_exec; 00510 ot->poll= ED_operator_console_active; 00511 00512 /* properties */ 00513 RNA_def_enum(ot->srna, "type", console_delete_type_items, DEL_NEXT_CHAR, "Type", "Which part of the text to delete"); 00514 } 00515 00516 00517 /* the python exec operator uses this */ 00518 static int console_clear_exec(bContext *C, wmOperator *op) 00519 { 00520 SpaceConsole *sc= CTX_wm_space_console(C); 00521 ARegion *ar= CTX_wm_region(C); 00522 00523 short scrollback= RNA_boolean_get(op->ptr, "scrollback"); 00524 short history= RNA_boolean_get(op->ptr, "history"); 00525 00526 /*ConsoleLine *ci= */ console_history_verify(C); 00527 00528 if(scrollback) { /* last item in mistory */ 00529 while(sc->scrollback.first) 00530 console_scrollback_free(sc, sc->scrollback.first); 00531 } 00532 00533 if(history) { 00534 while(sc->history.first) 00535 console_history_free(sc, sc->history.first); 00536 } 00537 00538 console_textview_update_rect(sc, ar); 00539 ED_area_tag_redraw(CTX_wm_area(C)); 00540 00541 return OPERATOR_FINISHED; 00542 } 00543 00544 void CONSOLE_OT_clear(wmOperatorType *ot) 00545 { 00546 /* identifiers */ 00547 ot->name= "Clear"; 00548 ot->description= "Clear text by type"; 00549 ot->idname= "CONSOLE_OT_clear"; 00550 00551 /* api callbacks */ 00552 ot->exec= console_clear_exec; 00553 ot->poll= ED_operator_console_active; 00554 00555 /* properties */ 00556 RNA_def_boolean(ot->srna, "scrollback", 1, "Scrollback", "Clear the scrollback history"); 00557 RNA_def_boolean(ot->srna, "history", 0, "History", "Clear the command history"); 00558 } 00559 00560 00561 00562 /* the python exec operator uses this */ 00563 static int console_history_cycle_exec(bContext *C, wmOperator *op) 00564 { 00565 SpaceConsole *sc= CTX_wm_space_console(C); 00566 ARegion *ar= CTX_wm_region(C); 00567 00568 ConsoleLine *ci= console_history_verify(C); /* TODO - stupid, just prevernts crashes when no command line */ 00569 short reverse= RNA_boolean_get(op->ptr, "reverse"); /* assumes down, reverse is up */ 00570 int prev_len= ci->len; 00571 00572 /* keep a copy of the line above so when history is cycled 00573 * this is the only function that needs to know about the double-up */ 00574 if(ci->prev) { 00575 ConsoleLine *ci_prev= (ConsoleLine *)ci->prev; 00576 00577 if(strcmp(ci->line, ci_prev->line)==0) 00578 console_history_free(sc, ci_prev); 00579 } 00580 00581 if(reverse) { /* last item in mistory */ 00582 ci= sc->history.last; 00583 BLI_remlink(&sc->history, ci); 00584 BLI_addhead(&sc->history, ci); 00585 } 00586 else { 00587 ci= sc->history.first; 00588 BLI_remlink(&sc->history, ci); 00589 BLI_addtail(&sc->history, ci); 00590 } 00591 00592 { /* add a duplicate of the new arg and remove all other instances */ 00593 ConsoleLine *cl; 00594 while((cl= console_history_find(sc, ci->line, ci))) 00595 console_history_free(sc, cl); 00596 00597 console_history_add(C, (ConsoleLine *)sc->history.last); 00598 } 00599 00600 ci= sc->history.last; 00601 console_select_offset(sc, ci->len - prev_len); 00602 00603 /* could be wrapped so update scroll rect */ 00604 console_textview_update_rect(sc, ar); 00605 ED_area_tag_redraw(CTX_wm_area(C)); 00606 00607 console_scroll_bottom(ar); 00608 00609 return OPERATOR_FINISHED; 00610 } 00611 00612 void CONSOLE_OT_history_cycle(wmOperatorType *ot) 00613 { 00614 /* identifiers */ 00615 ot->name= "History Cycle"; 00616 ot->description= "Cycle through history"; 00617 ot->idname= "CONSOLE_OT_history_cycle"; 00618 00619 /* api callbacks */ 00620 ot->exec= console_history_cycle_exec; 00621 ot->poll= ED_operator_console_active; 00622 00623 /* properties */ 00624 RNA_def_boolean(ot->srna, "reverse", 0, "Reverse", "Reverse cycle history"); 00625 } 00626 00627 00628 /* the python exec operator uses this */ 00629 static int console_history_append_exec(bContext *C, wmOperator *op) 00630 { 00631 SpaceConsole *sc= CTX_wm_space_console(C); 00632 ARegion *ar= CTX_wm_region(C); 00633 ScrArea *sa= CTX_wm_area(C); 00634 ConsoleLine *ci= console_history_verify(C); 00635 char *str= RNA_string_get_alloc(op->ptr, "text", NULL, 0); /* own this text in the new line, dont free */ 00636 int cursor= RNA_int_get(op->ptr, "current_character"); 00637 short rem_dupes= RNA_boolean_get(op->ptr, "remove_duplicates"); 00638 int prev_len= ci->len; 00639 00640 if(rem_dupes) { 00641 ConsoleLine *cl; 00642 00643 while((cl= console_history_find(sc, ci->line, ci))) 00644 console_history_free(sc, cl); 00645 00646 if(strcmp(str, ci->line)==0) { 00647 MEM_freeN(str); 00648 return OPERATOR_FINISHED; 00649 } 00650 } 00651 00652 ci= console_history_add_str(sc, str, 1); /* own the string */ 00653 console_select_offset(sc, ci->len - prev_len); 00654 console_line_cursor_set(ci, cursor); 00655 00656 ED_area_tag_redraw(sa); 00657 00658 /* when calling render modally this can be NULL when calling: 00659 * bpy.ops.render.render('INVOKE_DEFAULT') */ 00660 if (ar) { 00661 console_scroll_bottom(ar); 00662 } 00663 00664 return OPERATOR_FINISHED; 00665 } 00666 00667 void CONSOLE_OT_history_append(wmOperatorType *ot) 00668 { 00669 /* identifiers */ 00670 ot->name= "History Append"; 00671 ot->description= "Append history at cursor position"; 00672 ot->idname= "CONSOLE_OT_history_append"; 00673 00674 /* api callbacks */ 00675 ot->exec= console_history_append_exec; 00676 ot->poll= ED_operator_console_active; 00677 00678 /* properties */ 00679 RNA_def_string(ot->srna, "text", "", 0, "Text", "Text to insert at the cursor position"); 00680 RNA_def_int(ot->srna, "current_character", 0, 0, INT_MAX, "Cursor", "The index of the cursor", 0, 10000); 00681 RNA_def_boolean(ot->srna, "remove_duplicates", 0, "Remove Duplicates", "Remove duplicate items in the history"); 00682 } 00683 00684 00685 /* the python exec operator uses this */ 00686 static int console_scrollback_append_exec(bContext *C, wmOperator *op) 00687 { 00688 SpaceConsole *sc= CTX_wm_space_console(C); 00689 ARegion *ar= CTX_wm_region(C); 00690 ConsoleLine *ci; 00691 00692 char *str= RNA_string_get_alloc(op->ptr, "text", NULL, 0); /* own this text in the new line, dont free */ 00693 int type= RNA_enum_get(op->ptr, "type"); 00694 00695 console_history_verify(C); 00696 00697 ci= console_scrollback_add_str(sc, str, 1); /* own the string */ 00698 ci->type= type; 00699 00700 console_scrollback_limit(sc); 00701 00702 /* 'ar' can be null depending on the operator that runs 00703 * rendering with invoke default for eg causes this */ 00704 if(ar) { 00705 console_textview_update_rect(sc, ar); 00706 } 00707 00708 ED_area_tag_redraw(CTX_wm_area(C)); 00709 00710 return OPERATOR_FINISHED; 00711 } 00712 00713 void CONSOLE_OT_scrollback_append(wmOperatorType *ot) 00714 { 00715 /* defined in DNA_space_types.h */ 00716 static EnumPropertyItem console_line_type_items[] = { 00717 {CONSOLE_LINE_OUTPUT, "OUTPUT", 0, "Output", ""}, 00718 {CONSOLE_LINE_INPUT, "INPUT", 0, "Input", ""}, 00719 {CONSOLE_LINE_INFO, "INFO", 0, "Information", ""}, 00720 {CONSOLE_LINE_ERROR, "ERROR", 0, "Error", ""}, 00721 {0, NULL, 0, NULL, NULL}}; 00722 00723 /* identifiers */ 00724 ot->name= "Scrollback Append"; 00725 ot->description= "Append scrollback text by type"; 00726 ot->idname= "CONSOLE_OT_scrollback_append"; 00727 00728 /* api callbacks */ 00729 ot->exec= console_scrollback_append_exec; 00730 ot->poll= ED_operator_console_active; 00731 00732 /* properties */ 00733 RNA_def_string(ot->srna, "text", "", 0, "Text", "Text to insert at the cursor position"); 00734 RNA_def_enum(ot->srna, "type", console_line_type_items, CONSOLE_LINE_OUTPUT, "Type", "Console output type"); 00735 } 00736 00737 00738 static int console_copy_exec(bContext *C, wmOperator *UNUSED(op)) 00739 { 00740 SpaceConsole *sc= CTX_wm_space_console(C); 00741 00742 DynStr *buf_dyn= BLI_dynstr_new(); 00743 char *buf_str; 00744 00745 ConsoleLine *cl; 00746 int sel[2]; 00747 int offset= 0; 00748 00749 ConsoleLine cl_dummy= {NULL}; 00750 00751 #if 0 00752 /* copy whole file */ 00753 for(cl= sc->scrollback.first; cl; cl= cl->next) { 00754 BLI_dynstr_append(buf_dyn, cl->line); 00755 BLI_dynstr_append(buf_dyn, "\n"); 00756 } 00757 #endif 00758 00759 if(sc->sel_start == sc->sel_end) 00760 return OPERATOR_CANCELLED; 00761 00762 console_scrollback_prompt_begin(sc, &cl_dummy); 00763 00764 for(cl= sc->scrollback.first; cl; cl= cl->next) { 00765 offset += cl->len + 1; 00766 } 00767 00768 if(offset==0) { 00769 console_scrollback_prompt_end(sc, &cl_dummy); 00770 return OPERATOR_CANCELLED; 00771 } 00772 00773 offset -= 1; 00774 sel[0]= offset - sc->sel_end; 00775 sel[1]= offset - sc->sel_start; 00776 00777 for(cl= sc->scrollback.first; cl; cl= cl->next) { 00778 if(sel[0] <= cl->len && sel[1] >= 0) { 00779 int sta= MAX2(sel[0], 0); 00780 int end= MIN2(sel[1], cl->len); 00781 00782 if(BLI_dynstr_get_len(buf_dyn)) 00783 BLI_dynstr_append(buf_dyn, "\n"); 00784 00785 BLI_dynstr_nappend(buf_dyn, cl->line + sta, end - sta); 00786 } 00787 00788 sel[0] -= cl->len + 1; 00789 sel[1] -= cl->len + 1; 00790 } 00791 00792 buf_str= BLI_dynstr_get_cstring(buf_dyn); 00793 00794 BLI_dynstr_free(buf_dyn); 00795 WM_clipboard_text_set(buf_str, 0); 00796 00797 MEM_freeN(buf_str); 00798 00799 console_scrollback_prompt_end(sc, &cl_dummy); 00800 00801 return OPERATOR_FINISHED; 00802 } 00803 00804 void CONSOLE_OT_copy(wmOperatorType *ot) 00805 { 00806 /* identifiers */ 00807 ot->name= "Copy to Clipboard"; 00808 ot->description= "Copy selected text to clipboard"; 00809 ot->idname= "CONSOLE_OT_copy"; 00810 00811 /* api callbacks */ 00812 ot->poll= ED_operator_console_active; 00813 ot->exec= console_copy_exec; 00814 00815 /* properties */ 00816 } 00817 00818 static int console_paste_exec(bContext *C, wmOperator *UNUSED(op)) 00819 { 00820 SpaceConsole *sc= CTX_wm_space_console(C); 00821 ARegion *ar= CTX_wm_region(C); 00822 ConsoleLine *ci= console_history_verify(C); 00823 00824 char *buf_str= WM_clipboard_text_get(0); 00825 char *buf_step, *buf_next; 00826 00827 if(buf_str==NULL) 00828 return OPERATOR_CANCELLED; 00829 00830 buf_step= buf_str; 00831 00832 while((buf_next=buf_step) && buf_next[0] != '\0') { 00833 buf_step= strchr(buf_next, '\n'); 00834 if(buf_step) { 00835 *buf_step= '\0'; 00836 buf_step++; 00837 } 00838 00839 if(buf_next != buf_str) { 00840 WM_operator_name_call(C, "CONSOLE_OT_execute", WM_OP_EXEC_DEFAULT, NULL); 00841 ci= console_history_verify(C); 00842 } 00843 00844 console_select_offset(sc, console_line_insert(ci, buf_next)); 00845 } 00846 00847 MEM_freeN(buf_str); 00848 00849 console_textview_update_rect(sc, ar); 00850 ED_area_tag_redraw(CTX_wm_area(C)); 00851 00852 console_scroll_bottom(ar); 00853 00854 return OPERATOR_FINISHED; 00855 } 00856 00857 void CONSOLE_OT_paste(wmOperatorType *ot) 00858 { 00859 /* identifiers */ 00860 ot->name= "Paste from Clipboard"; 00861 ot->description= "Paste text from clipboard"; 00862 ot->idname= "CONSOLE_OT_paste"; 00863 00864 /* api callbacks */ 00865 ot->poll= ED_operator_console_active; 00866 ot->exec= console_paste_exec; 00867 00868 /* properties */ 00869 } 00870 00871 typedef struct SetConsoleCursor { 00872 int sel_old[2]; 00873 int sel_init; 00874 } SetConsoleCursor; 00875 00876 // TODO, cursor placement without selection 00877 static void console_cursor_set_to_pos(SpaceConsole *sc, ARegion *ar, SetConsoleCursor *scu, int mval[2], int UNUSED(sel)) 00878 { 00879 int pos; 00880 pos= console_char_pick(sc, ar, mval); 00881 00882 if(scu->sel_init == INT_MAX) { 00883 scu->sel_init= pos; 00884 sc->sel_start = sc->sel_end = pos; 00885 return; 00886 } 00887 00888 if (pos < scu->sel_init) { 00889 sc->sel_start = pos; 00890 sc->sel_end = scu->sel_init; 00891 } 00892 else if (pos > sc->sel_start) { 00893 sc->sel_start = scu->sel_init; 00894 sc->sel_end = pos; 00895 } 00896 else { 00897 sc->sel_start = sc->sel_end = pos; 00898 } 00899 } 00900 00901 static void console_modal_select_apply(bContext *C, wmOperator *op, wmEvent *event) 00902 { 00903 SpaceConsole *sc= CTX_wm_space_console(C); 00904 ARegion *ar= CTX_wm_region(C); 00905 SetConsoleCursor *scu= op->customdata; 00906 int mval[2]; 00907 int sel_prev[2]; 00908 00909 mval[0]= event->mval[0]; 00910 mval[1]= event->mval[1]; 00911 00912 sel_prev[0]= sc->sel_start; 00913 sel_prev[1]= sc->sel_end; 00914 00915 console_cursor_set_to_pos(sc, ar, scu, mval, TRUE); 00916 00917 /* only redraw if the selection changed */ 00918 if(sel_prev[0] != sc->sel_start || sel_prev[1] != sc->sel_end) { 00919 ED_area_tag_redraw(CTX_wm_area(C)); 00920 } 00921 } 00922 00923 static void console_cursor_set_exit(bContext *UNUSED(C), wmOperator *op) 00924 { 00925 // SpaceConsole *sc= CTX_wm_space_console(C); 00926 SetConsoleCursor *scu= op->customdata; 00927 00928 /* 00929 if(txt_has_sel(text)) { 00930 buffer = txt_sel_to_buf(text); 00931 WM_clipboard_text_set(buffer, 1); 00932 MEM_freeN(buffer); 00933 }*/ 00934 00935 MEM_freeN(scu); 00936 } 00937 00938 static int console_modal_select_invoke(bContext *C, wmOperator *op, wmEvent *event) 00939 { 00940 SpaceConsole *sc= CTX_wm_space_console(C); 00941 // ARegion *ar= CTX_wm_region(C); 00942 SetConsoleCursor *scu; 00943 00944 op->customdata= MEM_callocN(sizeof(SetConsoleCursor), "SetConsoleCursor"); 00945 scu= op->customdata; 00946 00947 scu->sel_old[0]= sc->sel_start; 00948 scu->sel_old[1]= sc->sel_end; 00949 00950 scu->sel_init = INT_MAX; 00951 00952 WM_event_add_modal_handler(C, op); 00953 00954 console_modal_select_apply(C, op, event); 00955 00956 return OPERATOR_RUNNING_MODAL; 00957 } 00958 00959 static int console_modal_select(bContext *C, wmOperator *op, wmEvent *event) 00960 { 00961 switch(event->type) { 00962 case LEFTMOUSE: 00963 case MIDDLEMOUSE: 00964 case RIGHTMOUSE: 00965 console_cursor_set_exit(C, op); 00966 return OPERATOR_FINISHED; 00967 case MOUSEMOVE: 00968 console_modal_select_apply(C, op, event); 00969 break; 00970 } 00971 00972 return OPERATOR_RUNNING_MODAL; 00973 } 00974 00975 static int console_modal_select_cancel(bContext *C, wmOperator *op) 00976 { 00977 console_cursor_set_exit(C, op); 00978 return OPERATOR_FINISHED; 00979 } 00980 00981 void CONSOLE_OT_select_set(wmOperatorType *ot) 00982 { 00983 /* identifiers */ 00984 ot->name= "Set Selection"; 00985 ot->idname= "CONSOLE_OT_select_set"; 00986 ot->description= "Set the console selection"; 00987 00988 /* api callbacks */ 00989 ot->invoke= console_modal_select_invoke; 00990 ot->modal= console_modal_select; 00991 ot->cancel= console_modal_select_cancel; 00992 ot->poll= ED_operator_console_active; 00993 }