View2D - Another WIP commit
[blender.git] / source / blender / editors / interface / view2d_ops.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) 2008 Blender Foundation.
21  * All rights reserved.
22  * 
23  * Contributor(s): Blender Foundation, Joshua Leung
24  *
25  * ***** END GPL LICENSE BLOCK *****
26  */
27
28 #include <math.h>
29
30 #include "MEM_guardedalloc.h"
31
32 #include "DNA_scene_types.h"
33 #include "DNA_screen_types.h"
34 #include "DNA_space_types.h"
35 #include "DNA_view2d_types.h"
36
37 #include "BKE_global.h"
38 #include "BKE_utildefines.h"
39
40 #include "RNA_access.h"
41 #include "RNA_define.h"
42
43 #include "WM_api.h"
44 #include "WM_types.h"
45
46 #include "BIF_gl.h"
47
48 #include "UI_resources.h"
49 #include "UI_view2d.h"
50
51 /* ********************************************************* */
52 /* VIEW PANNING OPERATOR                                                                 */
53
54 /*      This group of operators come in several forms:
55  *              1) Modal 'dragging' with MMB - where movement of mouse dictates amount to pan view by
56  *              2) Scrollwheel 'steps' - rolling mousewheel by one step moves view by predefined amount
57  *              3) Scroller drag - similar to 1), but only while mouse is still in view
58  *
59  *      In order to make sure this works, each operator must define the following RNA-Operator Props:
60  *              deltax, deltay  - define how much to move view by (relative to zoom-correction factor)
61  */
62
63  /* ------------------ Shared 'core' stuff ---------------------- */
64  
65 /* temp customdata for operator */
66 typedef struct v2dViewPanData {
67         ARegion *region;                /* region we're operating in */
68         View2D *v2d;                    /* view2d we're operating in */
69         
70         float facx, facy;               /* amount to move view relative to zoom */
71         
72                 /* options for version 1 */
73         int startx, starty;             /* mouse x/y values in window when operator was initiated */
74         int lastx, lasty;               /* previous x/y values of mouse in window */
75 } v2dViewPanData;
76  
77 /* initialise panning customdata */
78 static int view_pan_init(bContext *C, wmOperator *op)
79 {
80         v2dViewPanData *vpd;
81         ARegion *ar;
82         View2D *v2d;
83         float winx, winy;
84         
85         /* regions now have v2d-data by default, so check for region */
86         if (C->region == NULL)
87                 return 0;
88         
89         /* set custom-data for operator */
90         vpd= MEM_callocN(sizeof(v2dViewPanData), "v2dViewPanData");
91         op->customdata= vpd;
92         
93         /* set pointers to owners */
94         vpd->region= ar= C->region;
95         vpd->v2d= v2d= &C->region->v2d;
96         
97         /* calculate translation factor - based on size of view */
98         winx= (float)(ar->winrct.xmax - ar->winrct.xmin);
99         winy= (float)(ar->winrct.ymax - ar->winrct.ymin);
100         vpd->facx= (v2d->cur.xmax - v2d->cur.xmin) / winx;
101         vpd->facy= (v2d->cur.ymax - v2d->cur.ymin) / winy;
102         
103         return 1;
104 }
105
106 /* apply transform to view (i.e. adjust 'cur' rect) */
107 static void view_pan_apply(bContext *C, wmOperator *op)
108 {
109         v2dViewPanData *vpd= op->customdata;
110         View2D *v2d= vpd->v2d;
111         float dx, dy;
112         
113         /* calculate amount to move view by */
114         dx= vpd->facx * (float)RNA_int_get(op->ptr, "deltax");
115         dy= vpd->facy * (float)RNA_int_get(op->ptr, "deltay");
116         
117         /* only move view on an axis if change is allowed */
118         if ((v2d->keepofs & V2D_LOCKOFS_X)==0) {
119                 v2d->cur.xmin += dx;
120                 v2d->cur.xmax += dx;
121         }
122         if ((v2d->keepofs & V2D_LOCKOFS_Y)==0) {
123                 v2d->cur.ymin += dy;
124                 v2d->cur.ymax += dy;
125         }
126         
127         /* request updates to be done... */
128         WM_event_add_notifier(C->wm, C->window, 0, WM_NOTE_AREA_REDRAW, 0, NULL);
129         /* XXX: add WM_NOTE_TIME_CHANGED? */
130 }
131
132 /* cleanup temp customdata  */
133 static void view_pan_exit(bContext *C, wmOperator *op)
134 {
135         if (op->customdata) {
136                 MEM_freeN(op->customdata);
137                 op->customdata= NULL;                           
138         }
139
140  
141 /* ------------------ Modal Drag Version (1) ---------------------- */
142
143 /* for 'redo' only, with no user input */
144 static int view_pan_exec(bContext *C, wmOperator *op)
145 {
146         if (!view_pan_init(C, op))
147                 return OPERATOR_CANCELLED;
148         
149         view_pan_apply(C, op);
150         view_pan_exit(C, op);
151         return OPERATOR_FINISHED;
152 }
153
154 /* set up modal operator and relevant settings */
155 static int view_pan_invoke(bContext *C, wmOperator *op, wmEvent *event)
156 {
157         v2dViewPanData *vpd;
158         View2D *v2d;
159         
160         /* set up customdata */
161         if (!view_pan_init(C, op))
162                 return OPERATOR_CANCELLED;
163         
164         vpd= op->customdata;
165         v2d= vpd->v2d;
166         
167         /* set initial settings */
168         vpd->startx= vpd->lastx= event->x;
169         vpd->starty= vpd->lasty= event->y;
170         RNA_int_set(op->ptr, "deltax", 0);
171         RNA_int_set(op->ptr, "deltay", 0);
172         
173 #if 0 // XXX - enable this when cursors are working properly
174         if (v2d->keepofs & V2D_LOCKOFS_X)
175                 WM_set_cursor(C, BC_NS_SCROLLCURSOR);
176         else if (v2d->keepofs & V2D_LOCKOFS_Y)
177                 WM_set_cursor(C, BC_EW_SCROLLCURSOR);
178         else
179                 WM_set_cursor(C, BC_NSEW_SCROLLCURSOR);
180 #endif // XXX - enable this when cursors are working properly
181         
182         /* add temp handler */
183         WM_event_add_modal_handler(&C->window->handlers, op);
184
185         return OPERATOR_RUNNING_MODAL;
186 }
187
188 /* handle user input - calculations of mouse-movement need to be done here, not in the apply callback! */
189 static int view_pan_modal(bContext *C, wmOperator *op, wmEvent *event)
190 {
191         v2dViewPanData *vpd= op->customdata;
192         
193         /* execute the events */
194         switch (event->type) {
195                 case MOUSEMOVE:
196                 {
197                         /* calculate new delta transform, then store mouse-coordinates for next-time */
198                         RNA_int_set(op->ptr, "deltax", (vpd->lastx - event->x));
199                         RNA_int_set(op->ptr, "deltay", (vpd->lasty - event->y));
200                         vpd->lastx= event->x;
201                         vpd->lasty= event->y;
202                         
203                         view_pan_apply(C, op);
204                 }
205                         break;
206                         
207                 case MIDDLEMOUSE:
208                         if (event->val==0) {
209                                 /* calculate overall delta mouse-movement for redo */
210                                 RNA_int_set(op->ptr, "deltax", (vpd->startx - vpd->lastx));
211                                 RNA_int_set(op->ptr, "deltay", (vpd->starty - vpd->lasty));
212                                 
213                                 view_pan_exit(C, op);
214                                 //WM_set_cursor(C, CURSOR_STD);         // XXX - enable this when cursors are working properly  
215                                 WM_event_remove_modal_handler(&C->window->handlers, op);
216                                 
217                                 return OPERATOR_FINISHED;
218                         }
219                         break;
220         }
221
222         return OPERATOR_RUNNING_MODAL;
223 }
224
225 void ED_View2D_OT_view_pan(wmOperatorType *ot)
226 {
227         PropertyRNA *prop;
228         
229         /* identifiers */
230         ot->name= "Pan View";
231         ot->idname= "ED_View2D_OT_view_pan";
232         
233         /* api callbacks */
234         ot->exec= view_pan_exec;
235         ot->invoke= view_pan_invoke;
236         ot->modal= view_pan_modal;
237         
238         /* rna - must keep these in sync with the other operators */
239         prop= RNA_def_property(ot->srna, "deltax", PROP_INT, PROP_NONE);
240         prop= RNA_def_property(ot->srna, "deltay", PROP_INT, PROP_NONE);
241 }
242
243 /* ------------------ Scrollwheel Versions (2) ---------------------- */
244 // XXX should these be unified a bit?
245
246 /* this operator only needs this single callback, where it callsthe view_pan_*() methods */
247 static int view_scrollright_exec(bContext *C, wmOperator *op)
248 {
249         /* initialise default settings (and validate if ok to run) */
250         if (!view_pan_init(C, op))
251                 return OPERATOR_CANCELLED;
252         
253         /* set RNA-Props - only movement in positive x-direction */
254         RNA_int_set(op->ptr, "deltax", 20);
255         RNA_int_set(op->ptr, "deltay", 0);
256         
257         /* apply movement, then we're done */
258         view_pan_apply(C, op);
259         view_pan_exit(C, op);
260         
261         return OPERATOR_FINISHED;
262 }
263
264 void ED_View2D_OT_view_scrollright(wmOperatorType *ot)
265 {
266         PropertyRNA *prop;
267         
268         /* identifiers */
269         ot->name= "Scroll Right";
270         ot->idname= "ED_View2D_OT_view_rightscroll";
271         
272         /* api callbacks */
273         ot->exec= view_scrollright_exec;
274         
275         /* rna - must keep these in sync with the other operators */
276         prop= RNA_def_property(ot->srna, "deltax", PROP_INT, PROP_NONE);
277         prop= RNA_def_property(ot->srna, "deltay", PROP_INT, PROP_NONE);
278 }
279
280
281
282 /* this operator only needs this single callback, where it callsthe view_pan_*() methods */
283 static int view_scrollleft_exec(bContext *C, wmOperator *op)
284 {
285         /* initialise default settings (and validate if ok to run) */
286         if (!view_pan_init(C, op))
287                 return OPERATOR_CANCELLED;
288         
289         /* set RNA-Props - only movement in negative x-direction */
290         RNA_int_set(op->ptr, "deltax", -20);
291         RNA_int_set(op->ptr, "deltay", 0);
292         
293         /* apply movement, then we're done */
294         view_pan_apply(C, op);
295         view_pan_exit(C, op);
296         
297         return OPERATOR_FINISHED;
298 }
299
300 void ED_View2D_OT_view_scrollleft(wmOperatorType *ot)
301 {
302         PropertyRNA *prop;
303         
304         /* identifiers */
305         ot->name= "Scroll Left";
306         ot->idname= "ED_View2D_OT_view_leftscroll";
307         
308         /* api callbacks */
309         ot->exec= view_scrollleft_exec;
310         
311         /* rna - must keep these in sync with the other operators */
312         prop= RNA_def_property(ot->srna, "deltax", PROP_INT, PROP_NONE);
313         prop= RNA_def_property(ot->srna, "deltay", PROP_INT, PROP_NONE);
314 }
315
316
317 /* this operator only needs this single callback, where it callsthe view_pan_*() methods */
318 static int view_scrolldown_exec(bContext *C, wmOperator *op)
319 {
320         /* initialise default settings (and validate if ok to run) */
321         if (!view_pan_init(C, op))
322                 return OPERATOR_CANCELLED;
323         
324         /* set RNA-Props - only movement in positive x-direction */
325         RNA_int_set(op->ptr, "deltax", 0);
326         RNA_int_set(op->ptr, "deltay", -20);
327         
328         /* apply movement, then we're done */
329         view_pan_apply(C, op);
330         view_pan_exit(C, op);
331         
332         return OPERATOR_FINISHED;
333 }
334
335 void ED_View2D_OT_view_scrolldown(wmOperatorType *ot)
336 {
337         PropertyRNA *prop;
338         
339         /* identifiers */
340         ot->name= "Scroll Down";
341         ot->idname= "ED_View2D_OT_view_downscroll";
342         
343         /* api callbacks */
344         ot->exec= view_scrolldown_exec;
345         
346         /* rna - must keep these in sync with the other operators */
347         prop= RNA_def_property(ot->srna, "deltax", PROP_INT, PROP_NONE);
348         prop= RNA_def_property(ot->srna, "deltay", PROP_INT, PROP_NONE);
349 }
350
351
352
353 /* this operator only needs this single callback, where it callsthe view_pan_*() methods */
354 static int view_scrollup_exec(bContext *C, wmOperator *op)
355 {
356         /* initialise default settings (and validate if ok to run) */
357         if (!view_pan_init(C, op))
358                 return OPERATOR_CANCELLED;
359         
360         /* set RNA-Props - only movement in negative x-direction */
361         RNA_int_set(op->ptr, "deltax", 0);
362         RNA_int_set(op->ptr, "deltay", 20);
363         
364         /* apply movement, then we're done */
365         view_pan_apply(C, op);
366         view_pan_exit(C, op);
367         
368         return OPERATOR_FINISHED;
369 }
370
371 void ED_View2D_OT_view_scrollup(wmOperatorType *ot)
372 {
373         PropertyRNA *prop;
374         
375         /* identifiers */
376         ot->name= "Scroll Up";
377         ot->idname= "ED_View2D_OT_view_upscroll";
378         
379         /* api callbacks */
380         ot->exec= view_scrollup_exec;
381         
382         /* rna - must keep these in sync with the other operators */
383         prop= RNA_def_property(ot->srna, "deltax", PROP_INT, PROP_NONE);
384         prop= RNA_def_property(ot->srna, "deltay", PROP_INT, PROP_NONE);
385 }
386
387 /* ********************************************************* */
388 /* Registration */
389
390 void ui_view2d_operatortypes(void)
391 {
392         WM_operatortype_append(ED_View2D_OT_view_pan);
393         
394         WM_operatortype_append(ED_View2D_OT_view_scrollleft);
395         WM_operatortype_append(ED_View2D_OT_view_scrollright);
396         WM_operatortype_append(ED_View2D_OT_view_scrollup);
397         WM_operatortype_append(ED_View2D_OT_view_scrolldown);
398 }
399
400 void UI_view2d_keymap(wmWindowManager *wm)
401 {
402         ui_view2d_operatortypes();
403         
404         /* pan/scroll operators */
405         WM_keymap_add_item(&wm->view2dkeymap, "ED_View2D_OT_view_pan", MIDDLEMOUSE, KM_PRESS, 0, 0);
406         
407         WM_keymap_add_item(&wm->view2dkeymap, "ED_View2D_OT_view_rightscroll", WHEELDOWNMOUSE, KM_PRESS, KM_CTRL, 0);
408         WM_keymap_add_item(&wm->view2dkeymap, "ED_View2D_OT_view_leftscroll", WHEELUPMOUSE, KM_PRESS, KM_CTRL, 0);
409         
410         WM_keymap_add_item(&wm->view2dkeymap, "ED_View2D_OT_view_downscroll", WHEELDOWNMOUSE, KM_PRESS, KM_SHIFT, 0);
411         WM_keymap_add_item(&wm->view2dkeymap, "ED_View2D_OT_view_upscroll", WHEELUPMOUSE, KM_PRESS, KM_SHIFT, 0);
412         
413         /* zoom */
414         
415         /* scrollbars */
416         //WM_keymap_add_item(&wm->view2dkeymap, "ED_V2D_OT_scrollbar_activate", MOUSEMOVE, 0, 0, 0);
417 }
418