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