754831e89a8704a41e41d9f6798082222be0db16
[blender.git] / source / blender / python / api2_2x / Window.c
1 /* 
2  *
3  * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License
7  * as published by the Free Software Foundation; either version 2
8  * of the License, or (at your option) any later version. The Blender
9  * Foundation also sells licenses for use in proprietary software under
10  * the Blender License.  See http://www.blender.org/BL/ for information
11  * about this.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software Foundation,
20  * Inc., 59 Temple Place - Suite 330, Boston, MA        02111-1307, USA.
21  *
22  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
23  * All rights reserved.
24  *
25  * This is a new part of Blender.
26  *
27  * Contributor(s): Willian P. Germano
28  *
29  * ***** END GPL/BL DUAL LICENSE BLOCK *****
30 */
31
32 #include <Python.h>
33 #include <stdio.h>
34
35 #include <blendef.h> /* OBACT */
36 #include <BDR_editobject.h> /* enter / leave editmode */
37 #include <BKE_global.h>
38 #include <BKE_library.h>
39 #include <BKE_object.h> /* for during_script() */
40 #include <BKE_scene.h> /* scene_find_camera() */
41 #include <BIF_usiblender.h>
42 #include <BIF_mywindow.h>
43 #include <BSE_headerbuttons.h>
44 #include <BSE_filesel.h>
45 #include <BIF_screen.h>
46 #include <BIF_space.h>
47 #include <BIF_drawtext.h>
48 #include <BIF_spacetypes.h>
49 #include <mydevice.h>
50 #include <DNA_view3d_types.h>
51 #include <DNA_screen_types.h>
52 #include <DNA_space_types.h>
53 #include <DNA_text_types.h>
54 #include <DNA_vec_types.h> /* for rcti struct */
55
56 #include "gen_utils.h"
57 #include "modules.h"
58 #include "matrix.h"
59 #include "vector.h"
60 #include "constant.h"
61
62
63 /* See Draw.c */
64 extern int EXPP_disable_force_draw;
65
66 /* Callback used by the file and image selector access functions */
67 static PyObject *(*EXPP_FS_PyCallback)(PyObject *arg) = NULL;
68
69 /*****************************************************************************/
70 /* Python API function prototypes for the Window module.                                                                                 */
71 /*****************************************************************************/
72 PyObject *M_Window_Redraw (PyObject *self, PyObject *args);
73 static PyObject *M_Window_RedrawAll (PyObject *self, PyObject *args);
74 static PyObject *M_Window_QRedrawAll (PyObject *self, PyObject *args);
75 static PyObject *M_Window_DrawProgressBar (PyObject *self, PyObject *args);
76 static PyObject *M_Window_GetCursorPos (PyObject *self);
77 static PyObject *M_Window_SetCursorPos (PyObject *self, PyObject *args);
78 static PyObject *M_Window_WaitCursor (PyObject *self, PyObject *args);
79 static PyObject *M_Window_GetViewVector (PyObject *self);
80 static PyObject *M_Window_GetViewQuat (PyObject *self);
81 static PyObject *M_Window_SetViewQuat (PyObject *self, PyObject *args);
82 static PyObject *M_Window_GetViewOffset (PyObject *self);
83 static PyObject *M_Window_SetViewOffset (PyObject *self, PyObject *args);
84 static PyObject *M_Window_GetViewMatrix (PyObject *self);
85 static PyObject *M_Window_FileSelector (PyObject *self, PyObject *args);
86 static PyObject *M_Window_ImageSelector (PyObject *self, PyObject *args);
87 static PyObject *M_Window_EditMode (PyObject *self, PyObject *args);
88 static PyObject *M_Window_ViewLayer (PyObject *self, PyObject *args);
89 static PyObject *M_Window_CameraView (PyObject *self, PyObject *args);
90 static PyObject *M_Window_QTest (PyObject *self);
91 static PyObject *M_Window_QRead (PyObject *self);
92 static PyObject *M_Window_QAdd (PyObject *self, PyObject *args);
93 static PyObject *M_Window_QHandle (PyObject *self, PyObject *args);
94 static PyObject *M_Window_GetMouseCoords (PyObject *self);
95 static PyObject *M_Window_SetMouseCoords (PyObject *self, PyObject *args);
96 static PyObject *M_Window_GetMouseButtons (PyObject *self);
97 static PyObject *M_Window_GetKeyQualifiers (PyObject *self);
98 static PyObject *M_Window_SetKeyQualifiers (PyObject *self, PyObject *args);
99 static PyObject *M_Window_GetAreaSize (PyObject *self);
100 static PyObject *M_Window_GetAreaID (PyObject *self);
101 static PyObject *M_Window_GetScreenSize (PyObject *self);
102 static PyObject *M_Window_GetScreens (PyObject *self);
103 static PyObject *M_Window_SetScreen (PyObject *self, PyObject *args);
104 static PyObject *M_Window_GetScreenInfo (PyObject *self, PyObject *args,
105         PyObject *kwords);
106
107 /*****************************************************************************/
108 /* The following string definitions are used for documentation strings.                  */
109 /* In Python these will be written to the console when doing a                                                   */
110 /* Blender.Window.__doc__                                                                                                                                                                                                                */
111 /*****************************************************************************/
112 static char M_Window_doc[] =
113 "The Blender Window module\n\n";
114
115 static char M_Window_Redraw_doc[] =
116 "() - Force a redraw of a specific Window Type (see Window.Types)";
117
118 static char M_Window_RedrawAll_doc[] =
119 "() - Redraw all windows";
120
121 static char M_Window_QRedrawAll_doc[] =
122 "() - Redraw all windows by queue event";
123
124 static char M_Window_FileSelector_doc[] =
125 "(callback [, title, filename]) - Open a file selector window.\n\
126 The selected file name is used as argument to a function callback f(name)\n\
127 that you must provide. 'title' is optional and defaults to 'SELECT FILE'.\n\
128 'filename' is optional and defaults to Blender.Get('filename').\n\n\
129 Example:\n\n\
130 import Blender\n\n\
131 def my_function(filename):\n\
132         print 'The selected file was: ', filename\n\n\
133 Blender.Window.FileSelector(my_function, 'SAVE FILE')\n";
134
135 static char M_Window_ImageSelector_doc[] =
136 "(callback [, title, filename]) - Open an image selector window.\n\
137 The selected file name is used as argument to a function callback f(name)\n\
138 that you must provide. 'title' is optional and defaults to 'SELECT IMAGE'.\n\
139 'filename' is optional and defaults to Blender.Get('filename').\n\n\
140 Example:\n\n\
141 import Blender\n\n\
142 def my_function(filename):\n\
143         print 'The selected image file was: ', filename\n\n\
144 Blender.Window.ImageSelector(my_function, 'LOAD IMAGE')\n";
145
146 static char M_Window_DrawProgressBar_doc[] =
147 "(done, text) - Draw a progress bar.\n\
148 'done' is a float value <= 1.0, 'text' contains info about what is\n\
149 currently being done.";
150
151 static char M_Window_GetCursorPos_doc[] =
152 "() - Get the current 3d cursor position as a list of three floats.";
153
154 static char M_Window_SetCursorPos_doc[] =
155 "([f,f,f]) - Set the current 3d cursor position from a list of three floats.";
156
157 static char M_Window_WaitCursor_doc[] =
158 "(bool) - Set cursor to wait mode (nonzero bool) or normal mode (0).";
159
160 static char M_Window_GetViewVector_doc[] =
161 "() - Get the current 3d view vector as a list of three floats [x,y,z].";
162
163 static char M_Window_GetViewMatrix_doc[] =
164 "() - Get the current 3d view matrix.";
165
166 static char M_Window_EditMode_doc[] =
167 "() - Get the current status -- 0: not in edit mode; 1: in edit mode.\n\
168 (status) - if 1: enter edit mode; if 0: leave edit mode.\n\
169 Returns the current status.  This function is mostly useful to leave\n\
170 edit mode before applying changes to a mesh (otherwise the changes will\n\
171 be lost) and then returning to it upon leaving.";
172
173 static char M_Window_ViewLayer_doc[] =
174 "(layers = []) - Get/set active layers in all 3d View windows.\n\
175 () - Make no changes, only return currently visible layers.\n\
176 (layers = []) - a list of integers, each in the range [1, 20].\n\
177 This function returns the currently visible layers as a list of ints.";
178
179 static char M_Window_GetViewQuat_doc[] =
180 "() - Get the current VIEW3D view quaternion values.";
181
182 static char M_Window_SetViewQuat_doc[] =
183 "(quat) - Set the current VIEW3D view quaternion values.\n\
184 (quat) - [f,f,f,f] or f,f,f,f: the new float values.";
185
186 static char M_Window_GetViewOffset_doc[] =
187 "() - Get the current VIEW3D view offset values.";
188
189 static char M_Window_SetViewOffset_doc[] =
190 "(ofs) - Set the current VIEW3D view offset values.\n\
191 (ofs) - [f,f,f] or f,f,f: the new float values.";
192
193 static char M_Window_CameraView_doc[] =
194 "(camtov3d = 0) - Set the current VIEW3D view to the active camera's view.\n\
195 (camtov3d = 0) - bool: if nonzero it's the camera that gets positioned at the\n\
196 current view, instead of the view being changed to that of the camera.\n\n\
197 If no camera is the active object, the active camera for the current scene\n\
198 is used.";
199
200 static char M_Window_QTest_doc[] =
201 "() - Check if there are pending events in the event queue.";
202
203 static char M_Window_QRead_doc[] =
204 "() - Get the next pending event from the event queue.\n\
205 This function returns a list [event, val], where:\n\
206 event - int: the key or mouse event (see Blender.Draw module);\n\
207 val - int: if 1 it's a key or mouse button press, if 0 a release.  For\n\
208         mouse movement events 'val' returns the new coordinates in x or y.";
209
210 static char M_Window_QAdd_doc[] =
211 "(win, evt, val, after = 0) - Add an event to some window's event queue.\n\
212 (win) - int: the win id, see Blender.Window.GetScreenInfo();\n\
213 (evt) - int: the event number, see events in Blender.Draw;\n\
214 (val) - bool: 1 for a key press, 0 for a release;\n\
215 (after) - bool: if 1 the event is put after the current queue and added later.";
216
217 static char M_Window_QHandle_doc[] =
218 "(win) - Process all events for the given window (area) now.\n\
219 (win) - int: the window id, see Blender.Window.GetScreenInfo().\n\n\
220 See Blender.Window.QAdd() for how to send events to a particular window.";
221
222 static char M_Window_GetMouseCoords_doc[] =
223 "() - Get mouse pointer's current screen coordinates.";
224
225 static char M_Window_SetMouseCoords_doc[] =
226 "(x, y) - Set mouse pointer's current screen coordinates.\n\
227 (x,y) - ints ([x, y] also accepted): the new x, y coordinates.";
228
229 static char M_Window_GetMouseButtons_doc[] =
230 "() - Get the current mouse button state (see Blender.Draw.LEFTMOUSE, etc).";
231
232 static char M_Window_GetKeyQualifiers_doc[] =
233 "() - Get the current qualifier keys state.\n\
234 An int is returned: or'ed combination of values in Blender.Window.Qual's dict.";
235
236 static char M_Window_SetKeyQualifiers_doc[] =
237 "(qual) - Fake qualifier keys state.\n\
238 (qual) - int: an or'ed combination of the values in Blender.Window.Qual dict.\n\
239 Note: remember to reset to 0 after handling the related event (see QAdd()).";
240
241 static char M_Window_GetAreaID_doc[] =
242 "() - Get the current window's (area) ID.";
243
244 static char M_Window_GetAreaSize_doc[] =
245 "() - Get the current window's (area) size as [width, height].";
246
247 static char M_Window_GetScreenSize_doc[] =
248 "() - Get the screen's size as [width, height].";
249
250 static char M_Window_GetScreens_doc[] =
251 "() - Get a list with the names of all available screens.";
252
253 static char M_Window_SetScreen_doc[] =
254 "(name) - Set current screen to the one with the given 'name'.";
255
256 static char M_Window_GetScreenInfo_doc[] =
257 "(type = -1, rect = 'win', screen = None)\n\
258 - Get info about the the areas in the current screen setup.\n\
259 (type = -1) - int: the space type (Blender.Window.Types) to restrict the\n\
260         results to, all if -1;\n\
261 (rect = 'win') - str: the rectangle of interest.  This defines if the corner\n\
262         coordinates returned will refer to:\n\
263         - the whole area: 'total';\n\
264         - only the header: 'header';\n\
265         - only the window content (default): 'win'.\n\
266 (screen = None) - str: the screen name, current if not given.\n\n\
267 A list of dictionaries (one for each area) is returned.\n\
268 Each dictionary has keys:\n\
269 'vertices': [xmin, ymin, xmax, ymax] area corners;\n\
270 'win': window type, see Blender.Window.Types dict;\n\
271 'id': area's id.";
272
273 /*****************************************************************************/
274 /* Python method structure definition for Blender.Window module:                                                 */
275 /*****************************************************************************/
276 struct PyMethodDef M_Window_methods[] = {
277         {"Redraw",               M_Window_Redraw,                       METH_VARARGS, M_Window_Redraw_doc},
278         {"RedrawAll",  M_Window_RedrawAll,      METH_VARARGS, M_Window_RedrawAll_doc},
279         {"QRedrawAll", M_Window_QRedrawAll, METH_VARARGS, M_Window_QRedrawAll_doc},
280         {"FileSelector", M_Window_FileSelector, METH_VARARGS,
281                 M_Window_FileSelector_doc},
282         {"ImageSelector", (PyCFunction)M_Window_ImageSelector, METH_VARARGS,
283                 M_Window_ImageSelector_doc},
284         {"DrawProgressBar", M_Window_DrawProgressBar,  METH_VARARGS,
285                 M_Window_DrawProgressBar_doc},
286         {"drawProgressBar", M_Window_DrawProgressBar,  METH_VARARGS,
287                 M_Window_DrawProgressBar_doc},
288         {"GetCursorPos", (PyCFunction)M_Window_GetCursorPos,    METH_NOARGS,
289                 M_Window_GetCursorPos_doc},
290         {"SetCursorPos", M_Window_SetCursorPos,  METH_VARARGS,
291                 M_Window_SetCursorPos_doc},
292         {"WaitCursor", M_Window_WaitCursor,  METH_VARARGS,
293                 M_Window_WaitCursor_doc},
294         {"GetViewVector", (PyCFunction)M_Window_GetViewVector,  METH_NOARGS,
295                 M_Window_GetViewVector_doc},
296         {"GetViewQuat", (PyCFunction)M_Window_GetViewQuat,      METH_NOARGS,
297                 M_Window_GetViewQuat_doc},
298         {"SetViewQuat", (PyCFunction)M_Window_SetViewQuat,      METH_VARARGS,
299                 M_Window_SetViewQuat_doc},
300         {"GetViewOffset", (PyCFunction)M_Window_GetViewOffset,  METH_NOARGS,
301                 M_Window_GetViewOffset_doc},
302         {"SetViewOffset", (PyCFunction)M_Window_SetViewOffset,  METH_VARARGS,
303                 M_Window_SetViewOffset_doc},
304         {"GetViewMatrix", (PyCFunction)M_Window_GetViewMatrix,  METH_NOARGS,
305                 M_Window_GetViewMatrix_doc},
306         {"EditMode", (PyCFunction)M_Window_EditMode,    METH_VARARGS,
307                 M_Window_EditMode_doc},
308         {"ViewLayer", (PyCFunction)M_Window_ViewLayer,  METH_VARARGS,
309                 M_Window_ViewLayer_doc},
310         {"CameraView", (PyCFunction)M_Window_CameraView,        METH_VARARGS,
311                 M_Window_CameraView_doc},
312         {"QTest", (PyCFunction)M_Window_QTest,  METH_NOARGS,
313                 M_Window_QTest_doc},
314         {"QRead", (PyCFunction)M_Window_QRead,  METH_NOARGS,
315                 M_Window_QRead_doc},
316         {"QAdd", (PyCFunction)M_Window_QAdd,    METH_VARARGS,
317                 M_Window_QAdd_doc},
318         {"QHandle", (PyCFunction)M_Window_QHandle,      METH_VARARGS,
319                 M_Window_QHandle_doc},
320         {"GetMouseCoords", (PyCFunction)M_Window_GetMouseCoords, METH_NOARGS,
321                 M_Window_GetMouseCoords_doc},
322         {"SetMouseCoords", (PyCFunction)M_Window_SetMouseCoords, METH_VARARGS,
323                 M_Window_SetMouseCoords_doc},
324         {"GetMouseButtons", (PyCFunction)M_Window_GetMouseButtons, METH_NOARGS,
325                 M_Window_GetMouseButtons_doc},
326         {"GetKeyQualifiers", (PyCFunction)M_Window_GetKeyQualifiers, METH_NOARGS,
327                 M_Window_GetKeyQualifiers_doc},
328         {"SetKeyQualifiers", (PyCFunction)M_Window_SetKeyQualifiers, METH_VARARGS,
329                 M_Window_SetKeyQualifiers_doc},
330         {"GetAreaSize", (PyCFunction)M_Window_GetAreaSize, METH_NOARGS,
331                 M_Window_GetAreaSize_doc},
332         {"GetAreaID", (PyCFunction)M_Window_GetAreaID, METH_NOARGS,
333                 M_Window_GetAreaID_doc},
334         {"GetScreenSize", (PyCFunction)M_Window_GetScreenSize, METH_NOARGS,
335                 M_Window_GetScreenSize_doc},
336         {"GetScreens", (PyCFunction)M_Window_GetScreens, METH_NOARGS,
337                 M_Window_GetScreens_doc},
338         {"SetScreen", (PyCFunction)M_Window_SetScreen, METH_VARARGS,
339                 M_Window_SetScreen_doc},
340         {"GetScreenInfo", (PyCFunction)M_Window_GetScreenInfo,
341                 METH_VARARGS | METH_KEYWORDS, M_Window_GetScreenInfo_doc},
342         {NULL, NULL, 0, NULL}
343 };
344
345 /*****************************************************************************/
346 /* Function:                                                    M_Window_Redraw                                                                                                                                          */
347 /* Python equivalent:                   Blender.Window.Redraw                                                                                                                    */
348 /*****************************************************************************/
349 /* not static so py_slider_update in Draw.[ch] can use it */
350 PyObject *M_Window_Redraw(PyObject *self, PyObject *args)
351
352         ScrArea *tempsa, *sa;
353         SpaceText *st;
354         int wintype = SPACE_VIEW3D;
355         short redraw_all = 0;
356
357         if (!PyArg_ParseTuple(args, "|i", &wintype))
358                 return (EXPP_ReturnPyObjError (PyExc_AttributeError,
359                                                 "expected int argument (or nothing)"));
360
361         if (wintype < 0)
362                 redraw_all = 1;
363
364         if (!during_script()) {
365                 tempsa= curarea;
366                 sa = G.curscreen->areabase.first;
367
368                 while (sa) {
369
370                         if (sa->spacetype == wintype || redraw_all) {
371                                 if (sa->spacetype == SPACE_TEXT) {
372                                         st = sa->spacedata.first;
373                                         if (st->text->flags & TXT_FOLLOW) /* follow cursor display */
374                                                 pop_space_text(st);
375
376                                         // XXX making a test: Jul 07, 2004.
377                                         // we don't need to prevent text win redraws anymore,
378                                         // since now there's a scripts space instead.
379                                         //if (EXPP_disable_force_draw) { /* defined in Draw.[ch] ... */
380                                         //      scrarea_queue_redraw(sa);
381                                         }
382
383                                 //} else {
384                                         scrarea_do_windraw(sa);
385                                         if (sa->headwin) scrarea_do_headdraw(sa);
386                                 //}
387                         }
388
389                         sa= sa->next;
390                 }
391
392                 if (curarea != tempsa) areawinset (tempsa->win);
393
394                 if (curarea) { /* is null if Blender is in bg mode */
395                         if (curarea->headwin) scrarea_do_headdraw (curarea);
396                         screen_swapbuffers();
397                 }
398         }
399
400         Py_INCREF(Py_None);
401         return Py_None;
402 }
403
404 /*****************************************************************************/
405 /* Function:                                                    M_Window_RedrawAll                                                                                                                               */
406 /* Python equivalent:                   Blender.Window.RedrawAll                                                                                                         */
407 /*****************************************************************************/
408 static PyObject *M_Window_RedrawAll(PyObject *self, PyObject *args)
409 {
410         return M_Window_Redraw(self, Py_BuildValue("(i)", -1));
411 }
412
413 /*****************************************************************************/
414 /* Function:                                                    M_Window_QRedrawAll                                                                                                                              */
415 /* Python equivalent:                   Blender.Window.QRedrawAll                                                                                                        */
416 /*****************************************************************************/
417 static PyObject *M_Window_QRedrawAll(PyObject *self, PyObject *args)
418 {
419         allqueue(REDRAWALL, 0);
420
421         Py_INCREF(Py_None);
422         return Py_None;
423 }
424
425 /*****************************************************************************/
426 /* Function:                                                    M_Window_FileSelector                                                                                                                    */
427 /* Python equivalent:                   Blender.Window.FileSelector                                                                                              */
428 /*****************************************************************************/
429
430 /* This is the callback to "activate_fileselect" below.  It receives the
431  * selected filename and (using it as argument) calls the Python callback
432  * provided by the script writer and stored in EXPP_FS_PyCallback. */
433
434 static void getSelectedFile(char *name)
435 {
436         if (!EXPP_FS_PyCallback) return;
437
438         PyObject_CallFunction((PyObject *)EXPP_FS_PyCallback, "s", name);
439
440         EXPP_FS_PyCallback = NULL;
441
442         return;
443 }
444
445 static PyObject *M_Window_FileSelector(PyObject *self, PyObject *args)
446 {
447         char *title = "SELECT FILE";
448         char *filename = G.sce;
449         SpaceScript *sc;
450         Script *script = G.main->script.last;
451         int startspace = 0;
452
453         if (!PyArg_ParseTuple(args, "O!|ss",
454                         &PyFunction_Type, &EXPP_FS_PyCallback, &title, &filename))
455                 return EXPP_ReturnPyObjError (PyExc_AttributeError,
456                 "\nexpected a callback function (and optionally one or two strings) "
457                 "as argument(s)");
458
459 /* trick: we move to a spacescript because then the fileselector will properly
460  * unset our SCRIPT_FILESEL flag when the user chooses a file or cancels the
461  * selection.  This is necessary because when a user cancels, the
462  * getSelectedFile function above doesn't get called and so couldn't unset the
463  * flag. */
464         startspace = curarea->spacetype;
465         if (startspace != SPACE_SCRIPT) newspace (curarea, SPACE_SCRIPT);
466
467         sc = curarea->spacedata.first;
468
469         /* did we get the right script? */
470         if (!(script->flags & SCRIPT_RUNNING)) {
471                 /* if not running, then we were already on a SpaceScript space, executing
472                  * a registered callback -- aka: this script has a gui */
473                 script = sc->script; /* this is the right script */
474         }
475         else { /* still running, use the trick */
476                 script->lastspace = startspace;
477                 sc->script = script;
478         }
479
480         script->flags |= SCRIPT_FILESEL;
481
482         activate_fileselect(FILE_BLENDER, title, filename, getSelectedFile);
483
484         Py_INCREF(Py_None);
485         return Py_None;
486 }
487
488 static PyObject *M_Window_ImageSelector(PyObject *self, PyObject *args)
489 {
490         char *title = "SELECT IMAGE";
491         char *filename = G.sce;
492         SpaceScript *sc;
493         Script *script = G.main->script.last;
494         int startspace = 0;
495
496         if (!PyArg_ParseTuple(args, "O!|ss",
497                         &PyFunction_Type, &EXPP_FS_PyCallback, &title, &filename))
498                 return (EXPP_ReturnPyObjError (PyExc_AttributeError,
499                 "\nexpected a callback function (and optionally one or two strings) "
500                 "as argument(s)"));
501
502 /* trick: we move to a spacescript because then the fileselector will properly
503  * unset our SCRIPT_FILESEL flag when the user chooses a file or cancels the
504  * selection.  This is necessary because when a user cancels, the
505  * getSelectedFile function above doesn't get called and so couldn't unset the
506  * flag. */
507         startspace = curarea->spacetype;
508         if (startspace != SPACE_SCRIPT) newspace (curarea, SPACE_SCRIPT);
509
510         sc = curarea->spacedata.first;
511
512         /* did we get the right script? */
513         if (!(script->flags & SCRIPT_RUNNING)) {
514                 /* if not running, then we're on a SpaceScript space, executing a
515                  * registered callback -- aka: this script has a gui */
516                 SpaceScript *sc = curarea->spacedata.first;
517                 script = sc->script; /* this is the right script */
518         }
519         else { /* still running, use the trick */
520                 script->lastspace = startspace;
521                 sc->script = script;
522         }
523
524         script->flags |= SCRIPT_FILESEL; /* same flag as filesel */
525
526         activate_imageselect(FILE_BLENDER, title, filename, getSelectedFile);
527
528         Py_INCREF(Py_None);
529         return Py_None;
530 }
531
532 /*****************************************************************************/
533 /* Function:                                                    M_Window_DrawProgressBar                                                                                                         */
534 /* Python equivalent:                   Blender.Window.DrawProgressBar                                                                           */
535 /*****************************************************************************/
536 static PyObject *M_Window_DrawProgressBar(PyObject *self, PyObject *args)
537 {
538         float done;
539         char *info = NULL;
540         int retval = 0;
541
542         if(!PyArg_ParseTuple(args, "fs", &done, &info))
543                 return (EXPP_ReturnPyObjError (PyExc_AttributeError,
544                                                 "expected a float and a string as arguments"));
545
546         if (!G.background) retval = progress_bar(done, info);
547
548         return Py_BuildValue("i", retval);
549 }
550
551 /*****************************************************************************/
552 /* Function:                                                    M_Window_GetCursorPos                                                                                                                    */
553 /* Python equivalent:                   Blender.Window.GetCursorPos                                                                                              */
554 /*****************************************************************************/
555 static PyObject *M_Window_GetCursorPos(PyObject *self)
556 {
557         float *cursor = NULL;
558         PyObject *pylist;
559
560         if (G.vd && G.vd->localview)
561                 cursor = G.vd->cursor;
562         else cursor = G.scene->cursor;
563
564         pylist = Py_BuildValue("[fff]", cursor[0], cursor[1], cursor[2]);
565
566         if (!pylist)
567                 return (EXPP_ReturnPyObjError (PyExc_MemoryError,
568                                                 "GetCursorPos: couldn't create pylist"));
569
570         return pylist;
571 }
572
573 /*****************************************************************************/
574 /* Function:                                                    M_Window_SetCursorPos                                                                                                                    */
575 /* Python equivalent:                   Blender.Window.SetCursorPos                                                                                              */
576 /*****************************************************************************/
577 static PyObject *M_Window_SetCursorPos(PyObject *self, PyObject *args)
578 {
579         int ok = 0;
580         float val[3];
581
582         if (PyObject_Length (args) == 3)
583                 ok = PyArg_ParseTuple (args, "fff", &val[0], &val[1], &val[2]);
584         else
585                 ok = PyArg_ParseTuple(args, "(fff)", &val[0], &val[1], &val[2]);
586
587         if (!ok)
588                 return EXPP_ReturnPyObjError (PyExc_TypeError,
589                                                                         "expected [f,f,f] or f,f,f as arguments");
590
591         if (G.vd && G.vd->localview) {
592                 G.vd->cursor[0] = val[0];
593                 G.vd->cursor[1] = val[1];
594                 G.vd->cursor[2] = val[2];
595         }
596         else {
597                 G.scene->cursor[0] = val[0];
598                 G.scene->cursor[1] = val[1];
599                 G.scene->cursor[2] = val[2];
600         }
601
602         Py_INCREF (Py_None);
603         return Py_None;
604 }
605
606 static PyObject *M_Window_WaitCursor(PyObject *self, PyObject *args)
607 {
608         int bool;
609
610         if (!PyArg_ParseTuple(args, "i", &bool))
611                 return EXPP_ReturnPyObjError (PyExc_TypeError,
612                         "expected bool (0 or 1) or nothing as argument");
613
614         waitcursor(bool); /* nonzero bool sets, zero unsets */
615
616         return EXPP_incr_ret(Py_None);
617 }
618
619 /*****************************************************************************/
620 /* Function:                                                    M_Window_GetViewVector                                                                                                           */
621 /* Python equivalent:                   Blender.Window.GetViewVector                                                                                     */
622 /*****************************************************************************/
623 static PyObject *M_Window_GetViewVector(PyObject *self)
624 {
625         float *vec = NULL;
626         PyObject *pylist;
627
628         if (!G.vd) {
629                 Py_INCREF (Py_None);
630                 return Py_None;
631         }
632
633         vec = G.vd->viewinv[2];
634
635         pylist = Py_BuildValue("[fff]", vec[0], vec[1], vec[2]);
636
637         if (!pylist)
638                 return (EXPP_ReturnPyObjError (PyExc_MemoryError,
639                                                 "GetViewVector: couldn't create pylist"));
640
641         return pylist;
642 }
643
644 static PyObject *M_Window_GetViewQuat(PyObject *self)
645 {
646         float *vec = NULL;
647         PyObject *pylist;
648
649         if (!G.vd) {
650                 Py_INCREF (Py_None);
651                 return Py_None;
652         }
653
654         vec = G.vd->viewquat;
655
656         pylist = Py_BuildValue("[ffff]", vec[0], vec[1], vec[2], vec[3]);
657
658         if (!pylist)
659                 return (EXPP_ReturnPyObjError (PyExc_MemoryError,
660                                                 "GetViewQuat: couldn't create pylist"));
661
662         return pylist;
663 }
664
665 static PyObject *M_Window_SetViewQuat(PyObject *self, PyObject *args)
666 {
667         int ok = 0;
668         float val[4];
669         float *vec;
670
671         if (!G.vd) {
672                 Py_INCREF (Py_None);
673                 return Py_None;
674         }
675
676         if (PyObject_Length (args) == 4)
677                 ok = PyArg_ParseTuple (args, "ffff", &val[0], &val[1], &val[2], &val[3]);
678         else
679                 ok = PyArg_ParseTuple(args, "(ffff)", &val[0], &val[1], &val[2], &val[3]);
680
681         if (!ok)
682                 return EXPP_ReturnPyObjError (PyExc_TypeError,
683                                                                         "expected [f,f,f,f] or f,f,f,f as arguments");
684
685         G.vd->viewquat[0] = val[0];
686         G.vd->viewquat[1] = val[1];
687         G.vd->viewquat[2] = val[2];
688         G.vd->viewquat[3] = val[3];
689
690         return EXPP_incr_ret (Py_None);
691 }
692
693 static PyObject *M_Window_GetViewOffset(PyObject *self)
694 {
695         float *vec = NULL;
696         PyObject *pylist;
697
698         if (!G.vd) {
699                 Py_INCREF (Py_None);
700                 return Py_None;
701         }
702
703         vec = G.vd->ofs;
704
705         pylist = Py_BuildValue("[fff]", vec[0], vec[1], vec[2]);
706
707         if (!pylist)
708                 return (EXPP_ReturnPyObjError (PyExc_MemoryError,
709                                                 "GetViewQuat: couldn't create pylist"));
710
711         return pylist;
712 }
713
714 static PyObject *M_Window_SetViewOffset(PyObject *self, PyObject *args)
715 {
716         int ok = 0;
717         float val[3];
718         float *vec;
719
720         if (!G.vd) {
721                 Py_INCREF (Py_None);
722                 return Py_None;
723         }
724
725         if (PyObject_Length (args) == 3)
726                 ok = PyArg_ParseTuple (args, "fff", &val[0], &val[1], &val[2]);
727         else
728                 ok = PyArg_ParseTuple(args, "(fff)", &val[0], &val[1], &val[2]);
729
730         if (!ok)
731                 return EXPP_ReturnPyObjError (PyExc_TypeError,
732                                                                         "expected [f,f,f] or f,f,f as arguments");
733
734         G.vd->ofs[0] = val[0];
735         G.vd->ofs[1] = val[1];
736         G.vd->ofs[2] = val[2];
737
738         return EXPP_incr_ret (Py_None);
739 }
740
741
742 /*****************************************************************************/
743 /* Function:                                                    M_Window_GetViewMatrix                                                                                                           */
744 /* Python equivalent:                   Blender.Window.GetViewMatrix                                                                                     */
745 /*****************************************************************************/
746 static PyObject *M_Window_GetViewMatrix(PyObject *self)
747 {
748         PyObject *viewmat;
749
750         if (!G.vd) {
751                 Py_INCREF (Py_None);
752                 return Py_None;
753         }
754
755         viewmat = (PyObject*)newMatrixObject((float*)G.vd->viewmat, 4, 4);
756
757         if (!viewmat)
758                 return EXPP_ReturnPyObjError (PyExc_MemoryError,
759                                                 "GetViewMatrix: couldn't create matrix pyobject");
760
761         return viewmat;
762 }
763
764 static PyObject *M_Window_EditMode(PyObject *self, PyObject *args)
765 {
766         short status = -1;
767
768         if (!PyArg_ParseTuple(args, "|h", &status))
769                 return EXPP_ReturnPyObjError (PyExc_TypeError,
770                         "expected nothing or an int (bool) as argument");
771
772         if (status >= 0) {
773                 if (status) {
774                                 if (!G.obedit) enter_editmode();
775                 }
776                 else if (G.obedit) exit_editmode(1);
777         }
778
779         return Py_BuildValue("h", G.obedit?1:0);
780 }
781
782 static PyObject *M_Window_ViewLayer(PyObject *self, PyObject *args)
783 {
784         PyObject *item = NULL;
785         PyObject *list = NULL, *resl = NULL;
786         int val, i, bit = 0, layer = 0;
787
788         if (!PyArg_ParseTuple(args, "|O!", &PyList_Type, &list))
789                 return EXPP_ReturnPyObjError (PyExc_TypeError,
790                         "expected nothing or a list of ints as argument");
791
792         if (list) {
793                 for (i = 0; i < PyList_Size(list); i++) {
794                         item = PyList_GetItem(list, i);
795                         if (!PyInt_Check(item))
796                                 return EXPP_ReturnPyObjError (PyExc_AttributeError,
797                                         "list must contain only integer numbers");
798
799                         val = (int)PyInt_AsLong(item);
800                         if (val < 1 || val > 20)
801                                 return EXPP_ReturnPyObjError (PyExc_AttributeError,
802                                         "layer values must be in the range [1, 20]");
803
804                         layer |= 1<<(val-1);
805                 }
806                 G.vd->lay = layer;
807
808                 while (bit < 20) {
809                         val = 1<<bit;
810                         if (layer & val) {
811                                 G.vd->layact = val;
812                                 break;
813                         }
814                         bit++;
815                 }
816         }
817                 
818         resl = PyList_New(0);
819         if (!resl)
820                 return (EXPP_ReturnPyObjError (PyExc_MemoryError,
821                         "couldn't create pylist!"));
822
823         layer = G.vd->lay;
824
825         bit = 0;
826         while (bit < 20) {
827                 val = 1<<bit;
828                 if (layer & val) {
829                         item = Py_BuildValue("i", bit + 1);
830                         PyList_Append(resl, item);
831                         Py_DECREF(item);
832                 }
833                 bit++;
834         }
835
836         return resl;
837 }
838
839 static PyObject *M_Window_CameraView(PyObject *self, PyObject *args)
840 {
841         short camtov3d = 0;
842         void setcameratoview3d(void); /* view.c, used in toets.c */
843
844         if (!PyArg_ParseTuple(args, "|i", &camtov3d))
845                 return EXPP_ReturnPyObjError (PyExc_TypeError,
846                         "expected an int (from Window.Views) as argument");
847
848         if (!G.vd)
849                 return EXPP_ReturnPyObjError (PyExc_RuntimeError,
850                         "View3d not available!");
851
852         if (!G.vd->camera) {
853                 if (BASACT && OBACT->type == OB_CAMERA) G.vd->camera = OBACT;
854                 else G.vd->camera = scene_find_camera(G.scene);
855                 handle_view3d_lock();
856         }
857
858         G.vd->persp = 2;
859         G.vd->view = 0;
860
861         if (camtov3d) setcameratoview3d();
862
863         return EXPP_incr_ret(Py_None);
864 }
865
866 static PyObject *M_Window_QTest(PyObject *self)
867 {
868         return Py_BuildValue("h", qtest());
869 }
870
871 static PyObject *M_Window_QRead(PyObject *self)
872 {
873         short val = 0;
874         unsigned short event;
875
876         event = extern_qread(&val);
877
878         return Py_BuildValue("ii", event, val);
879 }
880
881 static PyObject *M_Window_QAdd(PyObject *self, PyObject *args)
882 {
883         short win;
884         short evt; /* unsigned, we check below */
885         short val;
886         short after = 0;
887
888         if (!PyArg_ParseTuple(args, "hhh|h", &win, &evt, &val, &after))
889                 return EXPP_ReturnPyObjError (PyExc_TypeError,
890                         "expected three or four ints as arguments");
891
892         if (evt < 0) /* evt is unsigned short */
893                 return EXPP_ReturnPyObjError (PyExc_AttributeError,
894                         "event value must be a positive int, check events in Blender.Draw");
895
896         if (after) addafterqueue(win, evt, val);
897         else addqueue(win, evt, val);
898
899         return EXPP_incr_ret(Py_None);
900 }
901
902 static PyObject *M_Window_QHandle(PyObject *self, PyObject *args)
903 {
904         short win;
905         ScrArea *sa = curarea;
906         ScrArea *oldsa = NULL;
907
908         if (!PyArg_ParseTuple(args, "h", &win))
909                 return EXPP_ReturnPyObjError (PyExc_TypeError,
910                         "expected an int as argument");
911
912         while (sa) {
913                 if (sa->win == win) break;
914                 sa = sa->next;
915         }
916
917         if (sa) {
918                 BWinEvent evt;
919                 short do_redraw = 0, do_change = 0;
920
921                 if(sa != curarea || sa->win != mywinget()) {
922                         oldsa = curarea;
923                         areawinset(sa->win);
924                         set_g_activearea(sa);
925                 }
926                 while(bwin_qread(sa->win, &evt)) {
927                         if(evt.event == REDRAW) {
928                                 do_redraw = 1;
929                         }
930                         else if(evt.event == CHANGED) {
931                                 sa->win_swap = 0;
932                                 do_change = 1;
933                                 do_redraw = 1;
934                         }
935                         else {
936                                 scrarea_do_winhandle(sa, &evt);
937                         }
938                 }
939         }
940
941         if (oldsa) {
942                 areawinset(oldsa->win);
943                 set_g_activearea(oldsa);
944         }
945
946         return EXPP_incr_ret(Py_None);
947 }
948
949 static PyObject *M_Window_GetMouseCoords(PyObject *self)
950 {
951         short mval[2];
952
953         getmouse(mval);
954         
955         return Py_BuildValue("hh", mval[0], mval[1]);
956 }
957
958 static PyObject *M_Window_SetMouseCoords(PyObject *self, PyObject *args)
959 {
960         int ok, x, y;
961
962         if (!G.curscreen)
963                 return EXPP_ReturnPyObjError (PyExc_RuntimeError,
964                         "no current screen to retrieve info from!");
965         
966         x = G.curscreen->sizex / 2;
967         y = G.curscreen->sizey / 2;
968
969         if (PyObject_Length(args) == 2)
970                 ok = PyArg_ParseTuple(args, "hh", &x, &y);
971         else
972                 ok = PyArg_ParseTuple(args, "|(hh)", &x, &y);
973
974         if (!ok)
975                 return EXPP_ReturnPyObjError (PyExc_TypeError,
976                         "expected [i, i] or i,i as arguments (or nothing).");
977
978         warp_pointer(x, y);
979
980         return EXPP_incr_ret(Py_None);
981 }
982
983 static PyObject *M_Window_GetMouseButtons(PyObject *self)
984 {
985         short mbut = get_mbut();
986         
987         return Py_BuildValue("h", mbut);
988 }
989
990 static PyObject *M_Window_GetKeyQualifiers(PyObject *self)
991 {
992         short qual = get_qual();
993
994         return Py_BuildValue("h", qual);
995 }
996
997 static PyObject *M_Window_SetKeyQualifiers(PyObject *self, PyObject *args)
998 {
999         short qual = 0;
1000
1001         if (!PyArg_ParseTuple(args, "|h", &qual))
1002                 return EXPP_ReturnPyObjError (PyExc_TypeError,
1003                         "expected nothing or an int (or'ed flags) as argument");
1004
1005         if (qual < 0)
1006                 return EXPP_ReturnPyObjError (PyExc_AttributeError,
1007                         "value must be a positive int, check Blender.Window.Qual");
1008
1009         G.qual = qual;
1010
1011         return Py_BuildValue("h", qual);        
1012 }
1013
1014 static PyObject *M_Window_GetAreaSize(PyObject *self)
1015 {
1016         ScrArea *sa = curarea;
1017
1018         if (!sa) return EXPP_incr_ret(Py_None);
1019
1020         return Py_BuildValue("hh", sa->winx, sa->winy);
1021 }
1022
1023 static PyObject *M_Window_GetAreaID(PyObject *self)
1024 {
1025         ScrArea *sa = curarea;
1026
1027         if (!sa) return EXPP_incr_ret(Py_None);
1028
1029         return Py_BuildValue("h", sa->win);
1030 }
1031
1032 static PyObject *M_Window_GetScreenSize(PyObject *self)
1033 {
1034         bScreen *scr = G.curscreen;
1035
1036         if (!scr) return EXPP_incr_ret(Py_None);
1037
1038         return Py_BuildValue("hh", scr->sizex, scr->sizey);
1039 }
1040
1041
1042 static PyObject *M_Window_SetScreen(PyObject *self, PyObject *args)
1043 {
1044         bScreen *scr = G.main->screen.first;
1045         char *name = NULL;
1046
1047         if (!PyArg_ParseTuple(args, "s", &name))
1048                 return EXPP_ReturnPyObjError (PyExc_TypeError,
1049                         "expected string as argument");
1050
1051         while (scr) {
1052                 if (!strcmp(scr->id.name+2, name)) {
1053                         setscreen(scr);
1054                         break;
1055                 }
1056                 scr = scr->id.next;
1057         }
1058
1059         if (!scr)
1060                 return EXPP_ReturnPyObjError (PyExc_AttributeError,
1061                         "no such screen, check Window.GetScreens() for valid names.");
1062
1063         return EXPP_incr_ret(Py_None);
1064 }
1065
1066 static PyObject *M_Window_GetScreens(PyObject *self)
1067 {
1068         bScreen *scr = G.main->screen.first;
1069         PyObject *list = PyList_New(0);
1070         PyObject *str = NULL;
1071
1072         if (!list)
1073                 return EXPP_ReturnPyObjError (PyExc_MemoryError,
1074                         "couldn't create py list!");
1075
1076         while (scr) {
1077                 str = PyString_FromString(scr->id.name+2);
1078
1079                 if (!str) {
1080                         Py_DECREF(list);
1081                         return EXPP_ReturnPyObjError (PyExc_MemoryError,
1082                                 "couldn't create py string!");
1083                 }
1084
1085                 PyList_Append(list, str); /* incref's str */
1086                 Py_DECREF(str);
1087
1088                 scr = scr->id.next;
1089         }
1090
1091         return list;    
1092 }
1093
1094 static PyObject *M_Window_GetScreenInfo(PyObject *self, PyObject *args,
1095         PyObject *kwords)
1096 {
1097         ScrArea *sa = G.curscreen->areabase.first;
1098         bScreen *scr = G.main->screen.first;
1099         PyObject *item, *list;
1100         rcti *rct;
1101         int type = -1;
1102         char *rect = "win";
1103         char *screen = "";
1104         static char *kwlist[] = {"type", "rect", "screen", NULL};
1105         int rctype = 0;
1106
1107         if (!PyArg_ParseTupleAndKeywords(args, kwords, "|iss", kwlist, &type,
1108                         &rect, &screen))
1109                 return EXPP_ReturnPyObjError (PyExc_TypeError,
1110                         "expected nothing or an int and two strings as arguments");
1111
1112         if (!strcmp(rect, "win"))
1113                 rctype = 0;
1114         else if (!strcmp(rect, "total"))
1115                 rctype = 1;
1116         else if (!strcmp(rect, "header"))
1117                 rctype = 2;
1118         else
1119                 return EXPP_ReturnPyObjError (PyExc_AttributeError,
1120                         "requested invalid type for area rectangle coordinates.");
1121
1122         list = PyList_New(0);
1123
1124         if (screen && screen[0] != '\0') {
1125                 while (scr) {
1126                         if (!strcmp(scr->id.name+2, screen)) {
1127                                 sa = scr->areabase.first;
1128                                 break;
1129                         }
1130                         scr = scr->id.next;
1131                 }
1132         }
1133
1134         if (!scr) {
1135                 Py_DECREF(list);
1136                 return EXPP_ReturnPyObjError (PyExc_AttributeError,
1137                         "no such screen, see existing ones with Window.GetScreens.");
1138         }
1139         
1140         while (sa) {
1141                 if (type != -1 && sa->spacetype != type) {
1142                         sa = sa->next;
1143                         continue;
1144                 }
1145
1146                 switch (rctype) {
1147                         case 0:
1148                                 rct = &sa->winrct;
1149                                 break;
1150                         case 1:
1151                                 rct = &sa->totrct;
1152                                 break;
1153                         case 2:
1154                         default:
1155                                 rct = &sa->headrct;
1156                 }
1157
1158                 item = Py_BuildValue("{s:[h,h,h,h],s:h,s:h}",
1159                         "vertices", rct->xmin, rct->ymin, rct->xmax, rct->ymax,
1160                         "type", (short)sa->spacetype, "id", (short)sa->win);
1161                 PyList_Append(list, item);
1162                 Py_DECREF(item);
1163
1164                 sa = sa->next;
1165         }
1166
1167         return list;
1168 }
1169
1170 /*****************************************************************************/
1171 /* Function:                                                    Window_Init                                                                                                                                                              */
1172 /*****************************************************************************/
1173 PyObject *Window_Init (void)
1174 {
1175         PyObject        *submodule, *Types, *Qual;
1176
1177         submodule = Py_InitModule3("Blender.Window", M_Window_methods, M_Window_doc);
1178
1179         Types = M_constant_New();
1180         Qual = M_constant_New();
1181
1182         if (Types) {
1183                 BPy_constant *d = (BPy_constant *)Types;
1184
1185                 constant_insert(d, "VIEW3D", PyInt_FromLong(SPACE_VIEW3D));
1186                 constant_insert(d, "IPO", PyInt_FromLong(SPACE_IPO));
1187                 constant_insert(d, "OOPS", PyInt_FromLong(SPACE_OOPS));
1188                 constant_insert(d, "BUTS", PyInt_FromLong(SPACE_BUTS));
1189                 constant_insert(d, "FILE", PyInt_FromLong(SPACE_FILE));
1190                 constant_insert(d, "IMAGE", PyInt_FromLong(SPACE_IMAGE));
1191                 constant_insert(d, "INFO", PyInt_FromLong(SPACE_INFO));
1192                 constant_insert(d, "SEQ", PyInt_FromLong(SPACE_SEQ));
1193                 constant_insert(d, "IMASEL", PyInt_FromLong(SPACE_IMASEL));
1194                 constant_insert(d, "SOUND", PyInt_FromLong(SPACE_SOUND));
1195                 constant_insert(d, "ACTION", PyInt_FromLong(SPACE_ACTION));
1196                 constant_insert(d, "TEXT", PyInt_FromLong(SPACE_TEXT));
1197                 constant_insert(d, "NLA", PyInt_FromLong(SPACE_NLA));
1198                 constant_insert(d, "SCRIPT", PyInt_FromLong(SPACE_SCRIPT));
1199
1200                 PyModule_AddObject(submodule, "Types", Types);
1201         }
1202
1203         if (Qual) {
1204                 BPy_constant *d = (BPy_constant *)Qual;
1205
1206                 constant_insert(d, "LALT", PyInt_FromLong(L_ALTKEY));
1207                 constant_insert(d, "RALT", PyInt_FromLong(R_ALTKEY));
1208                 constant_insert(d, "ALT", PyInt_FromLong(LR_ALTKEY));
1209                 constant_insert(d, "LCTRL", PyInt_FromLong(L_CTRLKEY));
1210                 constant_insert(d, "RCTRL", PyInt_FromLong(R_CTRLKEY));
1211                 constant_insert(d, "CTRL", PyInt_FromLong(LR_CTRLKEY));
1212                 constant_insert(d, "LSHIFT", PyInt_FromLong(L_SHIFTKEY));
1213                 constant_insert(d, "RSHIFT", PyInt_FromLong(R_SHIFTKEY));
1214                 constant_insert(d, "SHIFT", PyInt_FromLong(LR_SHIFTKEY));
1215
1216                 PyModule_AddObject(submodule, "Qual", Qual);
1217         }
1218
1219         return submodule;
1220 }
1221