2.5
[blender.git] / source / blender / windowmanager / intern / wm_operators.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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
19  *
20  * The Original Code is Copyright (C) 2007 Blender Foundation.
21  * All rights reserved.
22  *
23  * 
24  * Contributor(s): Blender Foundation
25  *
26  * ***** END GPL LICENSE BLOCK *****
27  */
28
29 #include <string.h>
30
31 #include "DNA_ID.h"
32 #include "DNA_screen_types.h"
33 #include "DNA_windowmanager_types.h"
34
35 #include "MEM_guardedalloc.h"
36
37 #include "BLI_blenlib.h"
38
39 #include "BKE_blender.h"
40 #include "BKE_global.h"
41 #include "BKE_idprop.h"
42 #include "BKE_library.h"
43 #include "BKE_main.h"
44 #include "BKE_utildefines.h"
45
46 #include "RNA_access.h"
47 #include "RNA_define.h"
48
49 #include "UI_interface.h"
50
51 #include "WM_api.h"
52 #include "WM_types.h"
53
54 #include "wm.h"
55 #include "wm_window.h"
56 #include "wm_subwindow.h"
57 #include "wm_event_system.h"
58
59 static ListBase global_ops= {NULL, NULL};
60
61 /* ************ operator API, exported ********** */
62
63 wmOperatorType *WM_operatortype_find(const char *idname)
64 {
65         wmOperatorType *ot;
66         
67         for(ot= global_ops.first; ot; ot= ot->next) {
68                 if(strncmp(ot->idname, idname, OP_MAX_TYPENAME)==0)
69                    return ot;
70         }
71         printf("search for unknown operator %s\n", idname);
72         return NULL;
73 }
74
75 /* all ops in 1 list (for time being... needs evaluation later) */
76 void WM_operatortype_append(void (*opfunc)(wmOperatorType*))
77 {
78         wmOperatorType *ot;
79         
80         ot= MEM_callocN(sizeof(wmOperatorType), "operatortype");
81         ot->srna= RNA_def_struct(&BLENDER_RNA, "", "Operator", "");
82         opfunc(ot);
83         RNA_def_struct_identifier(ot->srna, ot->idname, ot->name);
84         BLI_addtail(&global_ops, ot);
85 }
86
87 /* ************ default op callbacks, exported *********** */
88
89 int WM_operator_confirm(bContext *C, wmOperator *op, wmEvent *event)
90 {
91 //      if(okee(op->type->name)) {
92 //              return op->type->exec(C, op);
93 //      }
94         return 0;
95 }
96 int WM_operator_winactive(bContext *C)
97 {
98         if(C->window==NULL) return 0;
99         return 1;
100 }
101
102 /* ************ window / screen operator definitions ************** */
103
104 static void WM_OT_window_duplicate(wmOperatorType *ot)
105 {
106         ot->name= "Duplicate Window";
107         ot->idname= "WM_OT_window_duplicate";
108         
109         ot->invoke= NULL; //WM_operator_confirm;
110         ot->exec= wm_window_duplicate_op;
111         ot->poll= WM_operator_winactive;
112 }
113
114 static void WM_OT_save_homefile(wmOperatorType *ot)
115 {
116         ot->name= "Save User Settings";
117         ot->idname= "WM_OT_save_homefile";
118         
119         ot->invoke= NULL; //WM_operator_confirm;
120         ot->exec= WM_write_homefile;
121         ot->poll= WM_operator_winactive;
122         
123         ot->flag= OPTYPE_REGISTER;
124 }
125
126 static void WM_OT_window_fullscreen_toggle(wmOperatorType *ot)
127 {
128     ot->name= "Toggle Fullscreen";
129     ot->idname= "WM_OT_window_fullscreen_toggle";
130
131     ot->invoke= NULL;
132     ot->exec= wm_window_fullscreen_toggle_op;
133     ot->poll= WM_operator_winactive;
134 }
135
136 static void WM_OT_exit_blender(wmOperatorType *ot)
137 {
138         ot->name= "Exit Blender";
139         ot->idname= "WM_OT_exit_blender";
140
141         ot->invoke= NULL; /* do confirm stuff */
142         ot->exec= wm_exit_blender_op;
143         ot->poll= WM_operator_winactive;
144 }
145
146 static int exit_okee_blender_invoke(bContext *C, wmOperator *op, wmEvent *event)
147 {
148         okee_operator(C, "WM_OT_exit_blender", "Quit Blender");
149
150         return OPERATOR_FINISHED;
151 }
152
153 static void WM_OT_exit_okee_blender(wmOperatorType *ot)
154 {
155         ot->name= "Exit Blender";
156         ot->idname= "WM_OT_exit_okee_blender";
157
158         ot->invoke= exit_okee_blender_invoke;
159         ot->poll= WM_operator_winactive;
160 }
161
162 /* ************ window gesture operator-callback definitions ************** */
163 /*
164  * These are default callbacks for use in operators requiring gesture input
165  */
166
167 /* **************** Border gesture *************** */
168
169 /* Border gesture has two types:
170    1) WM_GESTURE_CROSS_RECT: starts a cross, on mouse click it changes to border 
171    2) WM_GESTURE_RECT: starts immediate as a border, on mouse click or release it ends
172
173    It stores 4 values (xmin, xmax, ymin, ymax) and event it ended with (event_type)
174 */
175
176 static void border_select_apply(bContext *C, wmOperator *op, int event_type)
177 {
178         wmGesture *gesture= op->customdata;
179         rcti *rect= gesture->customdata;
180         
181         if(rect->xmin > rect->xmax)
182                 SWAP(int, rect->xmin, rect->xmax);
183         if(rect->ymin > rect->ymax)
184                 SWAP(int, rect->ymin, rect->ymax);
185         
186         /* operator arguments and storage. */
187         RNA_int_set(op->ptr, "xmin", rect->xmin);
188         RNA_int_set(op->ptr, "ymin", rect->ymin);
189         RNA_int_set(op->ptr, "xmax", rect->xmax);
190         RNA_int_set(op->ptr, "ymax", rect->ymax);
191         
192         RNA_int_set(op->ptr, "event_type", event_type);
193         
194         op->type->exec(C, op);
195 }
196
197 static void border_select_end(bContext *C, wmOperator *op)
198 {
199         wmGesture *gesture= op->customdata;
200         
201         WM_gesture_end(C, gesture);     /* frees gesture itself, and unregisters from window */
202         op->customdata= NULL;
203
204         ED_area_tag_redraw(C->area);
205         
206 }
207
208 int WM_border_select_invoke(bContext *C, wmOperator *op, wmEvent *event)
209 {
210         op->customdata= WM_gesture_new(C, event, WM_GESTURE_CROSS_RECT);
211
212         /* add modal handler */
213         WM_event_add_modal_handler(C, &C->window->handlers, op);
214         
215         WM_event_add_notifier(C, WM_NOTE_GESTURE_REDRAW, 0, NULL);
216
217         return OPERATOR_RUNNING_MODAL;
218 }
219
220 int WM_border_select_modal(bContext *C, wmOperator *op, wmEvent *event)
221 {
222         wmGesture *gesture= op->customdata;
223         rcti *rect= gesture->customdata;
224         int sx, sy;
225         
226         switch(event->type) {
227                 case MOUSEMOVE:
228                         
229                         wm_subwindow_getorigin(C->window, gesture->swinid, &sx, &sy);
230                         
231                         if(gesture->type==WM_GESTURE_CROSS_RECT && gesture->mode==0) {
232                                 rect->xmin= rect->xmax= event->x - sx;
233                                 rect->ymin= rect->ymax= event->y - sy;
234                         }
235                         else {
236                                 rect->xmax= event->x - sx;
237                                 rect->ymax= event->y - sy;
238                         }
239                         
240                         WM_event_add_notifier(C, WM_NOTE_GESTURE_REDRAW, 0, NULL);
241
242                         break;
243                         
244                 case LEFTMOUSE:
245                 case MIDDLEMOUSE:
246                 case RIGHTMOUSE:
247                         if(event->val==1) {
248                                 if(gesture->type==WM_GESTURE_CROSS_RECT && gesture->mode==0) {
249                                         gesture->mode= 1;
250                                         WM_event_add_notifier(C, WM_NOTE_GESTURE_REDRAW, 0, NULL);
251                                 }
252                         }
253                         else {
254                                 border_select_apply(C, op, event->type);
255                                 border_select_end(C, op);
256                                 return OPERATOR_FINISHED;
257                         }
258                         break;
259                 case ESCKEY:
260                         border_select_end(C, op);
261                         return OPERATOR_CANCELLED;
262         }
263         return OPERATOR_RUNNING_MODAL;
264 }
265
266 /* **************** Tweak gesture *************** */
267
268 static int tweak_gesture_invoke(bContext *C, wmOperator *op, wmEvent *event)
269 {
270         op->customdata= WM_gesture_new(C, event, WM_GESTURE_TWEAK);
271         
272         /* add modal handler */
273         WM_event_add_modal_handler(C, &C->window->handlers, op);
274         
275         WM_event_add_notifier(C, WM_NOTE_GESTURE_REDRAW, 0, NULL);
276         
277         return OPERATOR_RUNNING_MODAL;
278 }
279
280 static void tweak_gesture_end(bContext *C, wmOperator *op)
281 {
282         wmGesture *gesture= op->customdata;
283         
284         WM_gesture_end(C, gesture);     /* frees gesture itself, and unregisters from window */
285         op->customdata= NULL;
286
287         ED_area_tag_redraw(C->area);
288         
289 }
290
291 static int tweak_gesture_modal(bContext *C, wmOperator *op, wmEvent *event)
292 {
293         wmGesture *gesture= op->customdata;
294         rcti *rect= gesture->customdata;
295         int sx, sy, val;
296         
297         switch(event->type) {
298                 case MOUSEMOVE:
299                         
300                         wm_subwindow_getorigin(C->window, gesture->swinid, &sx, &sy);
301                         
302                         rect->xmax= event->x - sx;
303                         rect->ymax= event->y - sy;
304                         
305                         if((val= wm_gesture_evaluate(C, gesture))) {
306                                 wmEvent event;
307                                         
308                                 event= *(C->window->eventstate);
309                                 if(gesture->event_type==LEFTMOUSE)
310                                         event.type= EVT_TWEAK_L;
311                                 else if(gesture->event_type==RIGHTMOUSE)
312                                         event.type= EVT_TWEAK_R;
313                                 else
314                                         event.type= EVT_TWEAK_M;
315                                 event.val= val;
316                                 /* mouse coords! */
317                                 wm_event_add(C->window, &event);
318                                 
319                                 tweak_gesture_end(C, op);
320                                 return OPERATOR_FINISHED;
321                         }
322                         else
323                                 WM_event_add_notifier(C, WM_NOTE_GESTURE_REDRAW, 0, NULL);
324                         
325                         break;
326                         
327                 case LEFTMOUSE:
328                 case RIGHTMOUSE:
329                 case MIDDLEMOUSE:
330                         if(gesture->event_type==event->type) {
331                                 wm_gesture_evaluate(C, gesture);
332                                 tweak_gesture_end(C, op);
333                                 return OPERATOR_FINISHED;
334                         }
335                         break;
336         }
337         return OPERATOR_RUNNING_MODAL;
338 }
339
340 void WM_OT_tweak_gesture(wmOperatorType *ot)
341 {
342         ot->name= "Tweak Gesture";
343         ot->idname= "WM_OT_tweak_gesture";
344         
345         ot->invoke= tweak_gesture_invoke;
346         ot->modal= tweak_gesture_modal;
347
348         ot->poll= WM_operator_winactive;
349 }
350
351
352 /* ******************************************************* */
353  
354 /* called on initialize WM_exit() */
355 void wm_operatortype_free(void)
356 {
357         BLI_freelistN(&global_ops);
358 }
359
360 /* called on initialize WM_init() */
361 void wm_operatortype_init(void)
362 {
363         WM_operatortype_append(WM_OT_window_duplicate);
364         WM_operatortype_append(WM_OT_save_homefile);
365         WM_operatortype_append(WM_OT_window_fullscreen_toggle);
366         WM_operatortype_append(WM_OT_exit_blender);
367         WM_operatortype_append(WM_OT_exit_okee_blender);
368         WM_operatortype_append(WM_OT_tweak_gesture);
369 }
370
371 /* default keymap for windows and screens, only call once per WM */
372 void wm_window_keymap(wmWindowManager *wm)
373 {
374         ListBase *keymap= WM_keymap_listbase(wm, "Window", 0, 0);
375         
376         /* note, this doesn't replace existing keymap items */
377         WM_keymap_verify_item(keymap, "WM_OT_window_duplicate", AKEY, KM_PRESS, KM_CTRL|KM_ALT, 0);
378         WM_keymap_verify_item(keymap, "WM_OT_save_homefile", UKEY, KM_PRESS, KM_CTRL, 0);
379         WM_keymap_verify_item(keymap, "WM_OT_window_fullscreen_toggle", FKEY, KM_PRESS, 0, 0);
380         WM_keymap_verify_item(keymap, "WM_OT_exit_okee_blender", QKEY, KM_PRESS, KM_CTRL, 0);
381 }
382