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