I made multitude of fixes based on the comments provided online:
[blender.git] / source / blender / editors / space_console / space_console.c
1 /*
2  * $Id$
3  *
4  * ***** BEGIN GPL LICENSE BLOCK *****
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version. 
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19  * 
20  * Contributor(s): Campbell Barton
21  *
22  * ***** END GPL LICENSE BLOCK *****
23  */
24
25 /** \file blender/editors/space_console/space_console.c
26  *  \ingroup spconsole
27  */
28
29 #include <string.h>
30 #include <stdio.h>
31
32 #ifdef WIN32
33 #include "BLI_winstuff.h"
34 #endif
35
36 #include "MEM_guardedalloc.h"
37
38 #include "BLI_blenlib.h"
39 #include "BLI_math.h"
40 #include "BLI_utildefines.h"
41
42 #include "BKE_context.h"
43 #include "BKE_screen.h"
44 #include "BKE_idcode.h"
45
46 #include "ED_space_api.h"
47 #include "ED_screen.h"
48
49 #include "BIF_gl.h"
50
51 #include "RNA_access.h"
52
53 #include "WM_api.h"
54 #include "WM_types.h"
55
56 #include "UI_resources.h"
57 #include "UI_view2d.h"
58
59 #include "console_intern.h"     // own include
60
61 /* ******************** default callbacks for console space ***************** */
62
63 static SpaceLink *console_new(const bContext *UNUSED(C))
64 {
65         ARegion *ar;
66         SpaceConsole *sconsole;
67         
68         sconsole= MEM_callocN(sizeof(SpaceConsole), "initconsole");
69         sconsole->spacetype= SPACE_CONSOLE;
70         
71         sconsole->lheight=      14;
72         
73         /* header */
74         ar= MEM_callocN(sizeof(ARegion), "header for console");
75         
76         BLI_addtail(&sconsole->regionbase, ar);
77         ar->regiontype= RGN_TYPE_HEADER;
78         ar->alignment= RGN_ALIGN_BOTTOM;
79         
80         
81         /* main area */
82         ar= MEM_callocN(sizeof(ARegion), "main area for text");
83         
84         BLI_addtail(&sconsole->regionbase, ar);
85         ar->regiontype= RGN_TYPE_WINDOW;
86         
87         /* keep in sync with info */
88         ar->v2d.scroll |= (V2D_SCROLL_RIGHT);
89         ar->v2d.align |= V2D_ALIGN_NO_NEG_X|V2D_ALIGN_NO_NEG_Y; /* align bottom left */
90         ar->v2d.keepofs |= V2D_LOCKOFS_X;
91         ar->v2d.keepzoom = (V2D_LOCKZOOM_X|V2D_LOCKZOOM_Y|V2D_LIMITZOOM|V2D_KEEPASPECT);
92         ar->v2d.keeptot= V2D_KEEPTOT_BOUNDS;
93         ar->v2d.minzoom= ar->v2d.maxzoom= 1.0f;
94
95         /* for now, aspect ratio should be maintained, and zoom is clamped within sane default limits */
96         //ar->v2d.keepzoom= (V2D_KEEPASPECT|V2D_LIMITZOOM);
97
98         return (SpaceLink *)sconsole;
99 }
100
101 /* not spacelink itself */
102 static void console_free(SpaceLink *sl)
103 {
104         SpaceConsole *sc= (SpaceConsole*) sl;
105         
106         while(sc->scrollback.first)
107                 console_scrollback_free(sc, sc->scrollback.first);
108         
109         while(sc->history.first)
110                 console_history_free(sc, sc->history.first);
111 }
112
113
114 /* spacetype; init callback */
115 static void console_init(struct wmWindowManager *UNUSED(wm), ScrArea *UNUSED(sa))
116 {
117
118 }
119
120 static SpaceLink *console_duplicate(SpaceLink *sl)
121 {
122         SpaceConsole *sconsolen= MEM_dupallocN(sl);
123         
124         /* clear or remove stuff from old */
125         
126         /* TODO - duplicate?, then we also need to duplicate the py namespace */
127         sconsolen->scrollback.first= sconsolen->scrollback.last= NULL;
128         sconsolen->history.first= sconsolen->history.last= NULL;
129         
130         return (SpaceLink *)sconsolen;
131 }
132
133
134
135 /* add handlers, stuff you only do once or on area/region changes */
136 static void console_main_area_init(wmWindowManager *wm, ARegion *ar)
137 {
138         wmKeyMap *keymap;
139         ListBase *lb;
140
141         UI_view2d_region_reinit(&ar->v2d, V2D_COMMONVIEW_CUSTOM, ar->winx, ar->winy);
142
143         /* own keymap */
144         keymap= WM_keymap_find(wm->defaultconf, "Console", SPACE_CONSOLE, 0);
145         WM_event_add_keymap_handler_bb(&ar->handlers, keymap, &ar->v2d.mask, &ar->winrct);
146         
147         /* add drop boxes */
148         lb= WM_dropboxmap_find("Console", SPACE_CONSOLE, RGN_TYPE_WINDOW);
149         
150         WM_event_add_dropbox_handler(&ar->handlers, lb);
151 }
152
153
154 /* ************* dropboxes ************* */
155
156 static int id_drop_poll(bContext *UNUSED(C), wmDrag *drag, wmEvent *UNUSED(event))
157 {
158 //      SpaceConsole *sc= CTX_wm_space_console(C);
159         if(drag->type==WM_DRAG_ID)
160                 return 1;
161         return 0;
162 }
163
164 static void id_drop_copy(wmDrag *drag, wmDropBox *drop)
165 {
166         char text[64];
167         ID *id= drag->poin;
168         char id_esc[(sizeof(id->name) - 2) * 2];
169
170         BLI_strescape(id_esc, id->name+2, sizeof(id_esc));
171
172         BLI_snprintf(text, sizeof(text), "bpy.data.%s[\"%s\"]", BKE_idcode_to_name_plural(GS(id->name)), id_esc);
173
174         /* copy drag path to properties */
175         RNA_string_set(drop->ptr, "text", text);
176 }
177
178 static int path_drop_poll(bContext *UNUSED(C), wmDrag *drag, wmEvent *UNUSED(event))
179 {
180 //    SpaceConsole *sc= CTX_wm_space_console(C);
181         if(drag->type==WM_DRAG_PATH)
182                 return 1;
183         return 0;
184 }
185
186 static void path_drop_copy(wmDrag *drag, wmDropBox *drop)
187 {
188         char pathname[FILE_MAXDIR+FILE_MAXFILE+2];
189         BLI_snprintf(pathname, sizeof(pathname), "\"%s\"", drag->path);
190         RNA_string_set(drop->ptr, "text", pathname);
191 }
192
193
194 /* this region dropbox definition */
195 static void console_dropboxes(void)
196 {
197         ListBase *lb= WM_dropboxmap_find("Console", SPACE_CONSOLE, RGN_TYPE_WINDOW);
198         
199         WM_dropbox_add(lb, "CONSOLE_OT_insert", id_drop_poll, id_drop_copy);
200         WM_dropbox_add(lb, "CONSOLE_OT_insert", path_drop_poll, path_drop_copy);
201 }
202
203 /* ************* end drop *********** */
204
205 static void console_main_area_draw(const bContext *C, ARegion *ar)
206 {
207         /* draw entirely, view changes should be handled here */
208         SpaceConsole *sc= CTX_wm_space_console(C);
209         View2D *v2d= &ar->v2d;
210         View2DScrollers *scrollers;
211
212         if(sc->scrollback.first==NULL)
213                 WM_operator_name_call((bContext *)C, "CONSOLE_OT_banner", WM_OP_EXEC_DEFAULT, NULL);
214
215         /* clear and setup matrix */
216         UI_ThemeClearColor(TH_BACK);
217         glClear(GL_COLOR_BUFFER_BIT);
218
219         /* worlks best with no view2d matrix set */
220         UI_view2d_view_ortho(v2d);
221
222         /* data... */
223
224         console_history_verify(C); /* make sure we have some command line */
225         console_textview_main(sc, ar);
226         
227         /* reset view matrix */
228         UI_view2d_view_restore(C);
229         
230         /* scrollers */
231         scrollers= UI_view2d_scrollers_calc(C, v2d, V2D_ARG_DUMMY, V2D_ARG_DUMMY, V2D_ARG_DUMMY, V2D_GRID_CLAMP);
232         UI_view2d_scrollers_draw(C, v2d, scrollers);
233         UI_view2d_scrollers_free(scrollers);
234 }
235
236 static void console_operatortypes(void)
237 {
238         /* console_ops.c */
239         WM_operatortype_append(CONSOLE_OT_move);
240         WM_operatortype_append(CONSOLE_OT_delete);
241         WM_operatortype_append(CONSOLE_OT_insert);
242         
243         /* for use by python only */
244         WM_operatortype_append(CONSOLE_OT_history_append); 
245         WM_operatortype_append(CONSOLE_OT_scrollback_append);
246         
247         WM_operatortype_append(CONSOLE_OT_clear); 
248         WM_operatortype_append(CONSOLE_OT_history_cycle);
249         WM_operatortype_append(CONSOLE_OT_copy);
250         WM_operatortype_append(CONSOLE_OT_paste);
251         WM_operatortype_append(CONSOLE_OT_select_set);
252 }
253
254 static void console_keymap(struct wmKeyConfig *keyconf)
255 {
256         wmKeyMap *keymap= WM_keymap_find(keyconf, "Console", SPACE_CONSOLE, 0);
257         wmKeyMapItem *kmi;
258         
259 #ifdef __APPLE__
260         RNA_enum_set(WM_keymap_add_item(keymap, "CONSOLE_OT_move", LEFTARROWKEY, KM_PRESS, KM_OSKEY, 0)->ptr, "type", LINE_BEGIN);
261         RNA_enum_set(WM_keymap_add_item(keymap, "CONSOLE_OT_move", RIGHTARROWKEY, KM_PRESS, KM_OSKEY, 0)->ptr, "type", LINE_END);
262 #endif
263
264         RNA_enum_set(WM_keymap_add_item(keymap, "CONSOLE_OT_move", LEFTARROWKEY, KM_PRESS, KM_CTRL, 0)->ptr, "type", PREV_WORD);
265         RNA_enum_set(WM_keymap_add_item(keymap, "CONSOLE_OT_move", RIGHTARROWKEY, KM_PRESS, KM_CTRL, 0)->ptr, "type", NEXT_WORD);
266         
267         RNA_enum_set(WM_keymap_add_item(keymap, "CONSOLE_OT_move", HOMEKEY, KM_PRESS, 0, 0)->ptr, "type", LINE_BEGIN);
268         RNA_enum_set(WM_keymap_add_item(keymap, "CONSOLE_OT_move", ENDKEY, KM_PRESS, 0, 0)->ptr, "type", LINE_END);
269         
270         kmi = WM_keymap_add_item(keymap, "WM_OT_context_cycle_int", WHEELUPMOUSE, KM_PRESS, KM_CTRL, 0);
271         RNA_string_set(kmi->ptr, "data_path", "space_data.font_size");
272         RNA_boolean_set(kmi->ptr, "reverse", 0);
273         
274         kmi = WM_keymap_add_item(keymap, "WM_OT_context_cycle_int", WHEELDOWNMOUSE, KM_PRESS, KM_CTRL, 0);
275         RNA_string_set(kmi->ptr, "data_path", "space_data.font_size");
276         RNA_boolean_set(kmi->ptr, "reverse", 1);
277
278         kmi = WM_keymap_add_item(keymap, "WM_OT_context_cycle_int", PADPLUSKEY, KM_PRESS, KM_CTRL, 0);
279         RNA_string_set(kmi->ptr, "data_path", "space_data.font_size");
280         RNA_boolean_set(kmi->ptr, "reverse", 0);
281         
282         kmi = WM_keymap_add_item(keymap, "WM_OT_context_cycle_int", PADMINUS, KM_PRESS, KM_CTRL, 0);
283         RNA_string_set(kmi->ptr, "data_path", "space_data.font_size");
284         RNA_boolean_set(kmi->ptr, "reverse", 1);
285
286         RNA_enum_set(WM_keymap_add_item(keymap, "CONSOLE_OT_move", LEFTARROWKEY, KM_PRESS, 0, 0)->ptr, "type", PREV_CHAR);
287         RNA_enum_set(WM_keymap_add_item(keymap, "CONSOLE_OT_move", RIGHTARROWKEY, KM_PRESS, 0, 0)->ptr, "type", NEXT_CHAR);
288         
289         RNA_boolean_set(WM_keymap_add_item(keymap, "CONSOLE_OT_history_cycle", UPARROWKEY, KM_PRESS, 0, 0)->ptr, "reverse", 1);
290         WM_keymap_add_item(keymap, "CONSOLE_OT_history_cycle", DOWNARROWKEY, KM_PRESS, 0, 0);
291         
292         /*
293         RNA_enum_set(WM_keymap_add_item(keymap, "CONSOLE_OT_move", LEFTARROWKEY, KM_PRESS, KM_CTRL, 0)->ptr, "type", PREV_WORD);
294         RNA_enum_set(WM_keymap_add_item(keymap, "CONSOLE_OT_move", RIGHTARROWKEY, KM_PRESS, KM_CTRL, 0)->ptr, "type", NEXT_WORD);
295         RNA_enum_set(WM_keymap_add_item(keymap, "CONSOLE_OT_move", UPARROWKEY, KM_PRESS, 0, 0)->ptr, "type", PREV_LINE);
296         RNA_enum_set(WM_keymap_add_item(keymap, "CONSOLE_OT_move", DOWNARROWKEY, KM_PRESS, 0, 0)->ptr, "type", NEXT_LINE);
297         RNA_enum_set(WM_keymap_add_item(keymap, "CONSOLE_OT_move", PAGEUPKEY, KM_PRESS, 0, 0)->ptr, "type", PREV_PAGE);
298         RNA_enum_set(WM_keymap_add_item(keymap, "CONSOLE_OT_move", PAGEDOWNKEY, KM_PRESS, 0, 0)->ptr, "type", NEXT_PAGE);
299
300
301         //RNA_enum_set(WM_keymap_add_item(keymap, "CONSOLE_OT_delete", DELKEY, KM_PRESS, 0, 0)->ptr, "type", DEL_NEXT_CHAR);
302         RNA_enum_set(WM_keymap_add_item(keymap, "CONSOLE_OT_delete", DKEY, KM_PRESS, KM_CTRL, 0)->ptr, "type", DEL_NEXT_CHAR);
303         //RNA_enum_set(WM_keymap_add_item(keymap, "CONSOLE_OT_delete", BACKSPACEKEY, KM_PRESS, 0, 0)->ptr, "type", DEL_PREV_CHAR);
304         RNA_enum_set(WM_keymap_add_item(keymap, "CONSOLE_OT_delete", DELKEY, KM_PRESS, KM_CTRL, 0)->ptr, "type", DEL_NEXT_WORD);
305         RNA_enum_set(WM_keymap_add_item(keymap, "CONSOLE_OT_delete", BACKSPACEKEY, KM_PRESS, KM_CTRL, 0)->ptr, "type", DEL_PREV_WORD);
306         */
307         
308         RNA_enum_set(WM_keymap_add_item(keymap, "CONSOLE_OT_delete", DELKEY, KM_PRESS, 0, 0)->ptr, "type", DEL_NEXT_CHAR);
309         RNA_enum_set(WM_keymap_add_item(keymap, "CONSOLE_OT_delete", BACKSPACEKEY, KM_PRESS, 0, 0)->ptr, "type", DEL_PREV_CHAR);
310         RNA_enum_set(WM_keymap_add_item(keymap, "CONSOLE_OT_delete", BACKSPACEKEY, KM_PRESS, KM_SHIFT, 0)->ptr, "type", DEL_PREV_CHAR);  /* same as above [#26623] */
311
312 #ifdef WITH_PYTHON
313         WM_keymap_add_item(keymap, "CONSOLE_OT_execute", RETKEY, KM_PRESS, 0, 0); /* python operator - space_text.py */
314         WM_keymap_add_item(keymap, "CONSOLE_OT_execute", PADENTER, KM_PRESS, 0, 0);
315         
316         //WM_keymap_add_item(keymap, "CONSOLE_OT_autocomplete", TABKEY, KM_PRESS, 0, 0); /* python operator - space_text.py */
317         WM_keymap_add_item(keymap, "CONSOLE_OT_autocomplete", SPACEKEY, KM_PRESS, KM_CTRL, 0); /* python operator - space_text.py */
318 #endif
319
320         WM_keymap_add_item(keymap, "CONSOLE_OT_copy", CKEY, KM_PRESS, KM_CTRL, 0);
321         WM_keymap_add_item(keymap, "CONSOLE_OT_paste", VKEY, KM_PRESS, KM_CTRL, 0);
322 #ifdef __APPLE__
323         WM_keymap_add_item(keymap, "CONSOLE_OT_copy", CKEY, KM_PRESS, KM_OSKEY, 0);
324         WM_keymap_add_item(keymap, "CONSOLE_OT_paste", VKEY, KM_PRESS, KM_OSKEY, 0);
325 #endif
326         
327         WM_keymap_add_item(keymap, "CONSOLE_OT_select_set", LEFTMOUSE, KM_PRESS, 0, 0);
328
329         RNA_string_set(WM_keymap_add_item(keymap, "CONSOLE_OT_insert", TABKEY, KM_PRESS, 0, 0)->ptr, "text", "\t"); /* fake tabs */
330         WM_keymap_add_item(keymap, "CONSOLE_OT_insert", KM_TEXTINPUT, KM_ANY, KM_ANY, 0); // last!
331 }
332
333 /****************** header region ******************/
334
335 /* add handlers, stuff you only do once or on area/region changes */
336 static void console_header_area_init(wmWindowManager *UNUSED(wm), ARegion *ar)
337 {
338         ED_region_header_init(ar);
339 }
340
341 static void console_header_area_draw(const bContext *C, ARegion *ar)
342 {
343         ED_region_header(C, ar);
344 }
345
346 static void console_main_area_listener(ARegion *ar, wmNotifier *wmn)
347 {
348         // SpaceInfo *sinfo= sa->spacedata.first;
349
350         /* context changes */
351         switch(wmn->category) {
352                 case NC_SPACE:
353                         if(wmn->data == ND_SPACE_CONSOLE) { /* generic redraw request */
354                                 ED_region_tag_redraw(ar);
355                         }
356                         break;
357         }
358 }
359
360 /* only called once, from space/spacetypes.c */
361 void ED_spacetype_console(void)
362 {
363         SpaceType *st= MEM_callocN(sizeof(SpaceType), "spacetype console");
364         ARegionType *art;
365         
366         st->spaceid= SPACE_CONSOLE;
367         strncpy(st->name, "Console", BKE_ST_MAXNAME);
368         
369         st->new= console_new;
370         st->free= console_free;
371         st->init= console_init;
372         st->duplicate= console_duplicate;
373         st->operatortypes= console_operatortypes;
374         st->keymap= console_keymap;
375         st->dropboxes= console_dropboxes;
376         
377         /* regions: main window */
378         art= MEM_callocN(sizeof(ARegionType), "spacetype console region");
379         art->regionid = RGN_TYPE_WINDOW;
380         art->keymapflag= ED_KEYMAP_UI|ED_KEYMAP_VIEW2D;
381
382         art->init= console_main_area_init;
383         art->draw= console_main_area_draw;
384         art->listener= console_main_area_listener;
385         
386         
387
388         BLI_addhead(&st->regiontypes, art);
389         
390         /* regions: header */
391         art= MEM_callocN(sizeof(ARegionType), "spacetype console region");
392         art->regionid = RGN_TYPE_HEADER;
393         art->prefsizey= HEADERY;
394         art->keymapflag= ED_KEYMAP_UI|ED_KEYMAP_VIEW2D|ED_KEYMAP_HEADER;
395         
396         art->init= console_header_area_init;
397         art->draw= console_header_area_draw;
398         
399         BLI_addhead(&st->regiontypes, art);
400
401
402         BKE_spacetype_register(st);
403 }