4fb8751de69253423452fdb55063748adec902e1
[blender.git] / source / blender / windowmanager / intern / wm_gesture.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * The Original Code is Copyright (C) 2008 Blender Foundation.
19  * All rights reserved.
20  *
21  *
22  * Contributor(s): Blender Foundation
23  *
24  * ***** END GPL LICENSE BLOCK *****
25  */
26
27 /** \file blender/windowmanager/intern/wm_gesture.c
28  *  \ingroup wm
29  */
30
31
32 #include "DNA_screen_types.h"
33 #include "DNA_vec_types.h"
34 #include "DNA_userdef_types.h"
35 #include "DNA_windowmanager_types.h"
36
37 #include "MEM_guardedalloc.h"
38
39 #include "BLI_blenlib.h"
40 #include "BLI_editVert.h"       /* lasso tessellation */
41 #include "BLI_math.h"
42 #include "BLI_scanfill.h"       /* lasso tessellation */
43 #include "BLI_utildefines.h"
44
45 #include "BKE_context.h"
46
47
48 #include "WM_api.h"
49 #include "WM_types.h"
50
51 #include "wm.h"
52 #include "wm_event_system.h"
53 #include "wm_subwindow.h"
54 #include "wm_draw.h"
55
56
57 #include "BIF_gl.h"
58 #include "BIF_glutil.h"
59
60
61 /* context checked on having screen, window and area */
62 wmGesture *WM_gesture_new(bContext *C, wmEvent *event, int type)
63 {
64         wmGesture *gesture= MEM_callocN(sizeof(wmGesture), "new gesture");
65         wmWindow *window= CTX_wm_window(C);
66         ARegion *ar= CTX_wm_region(C);
67         int sx, sy;
68         
69         BLI_addtail(&window->gesture, gesture);
70         
71         gesture->type= type;
72         gesture->event_type= event->type;
73         gesture->swinid= ar->swinid;    /* means only in area-region context! */
74         
75         wm_subwindow_getorigin(window, gesture->swinid, &sx, &sy);
76         
77         if( ELEM5(type, WM_GESTURE_RECT, WM_GESTURE_CROSS_RECT, WM_GESTURE_TWEAK, WM_GESTURE_CIRCLE, WM_GESTURE_STRAIGHTLINE)) {
78                 rcti *rect= MEM_callocN(sizeof(rcti), "gesture rect new");
79                 
80                 gesture->customdata= rect;
81                 rect->xmin= event->x - sx;
82                 rect->ymin= event->y - sy;
83                 if(type==WM_GESTURE_CIRCLE) {
84 #ifdef GESTURE_MEMORY
85                         rect->xmax= circle_select_size;
86 #else
87                         rect->xmax= 25; // XXX temp
88 #endif
89                 } else {
90                         rect->xmax= event->x - sx;
91                         rect->ymax= event->y - sy;
92                 }
93         }
94         else if (ELEM(type, WM_GESTURE_LINES, WM_GESTURE_LASSO)) {
95                 short *lasso;
96                 gesture->customdata= lasso= MEM_callocN(2*sizeof(short)*WM_LASSO_MIN_POINTS, "lasso points");
97                 lasso[0] = event->x - sx;
98                 lasso[1] = event->y - sy;
99                 gesture->points= 1;
100                 gesture->size = WM_LASSO_MIN_POINTS;
101         }
102         
103         return gesture;
104 }
105
106 void WM_gesture_end(bContext *C, wmGesture *gesture)
107 {
108         wmWindow *win= CTX_wm_window(C);
109         
110         if(win->tweak==gesture)
111                 win->tweak= NULL;
112         BLI_remlink(&win->gesture, gesture);
113         MEM_freeN(gesture->customdata);
114         MEM_freeN(gesture);
115 }
116
117 void WM_gestures_remove(bContext *C)
118 {
119         wmWindow *win= CTX_wm_window(C);
120         
121         while(win->gesture.first)
122                 WM_gesture_end(C, win->gesture.first);
123 }
124
125
126 /* tweak and line gestures */
127 int wm_gesture_evaluate(wmGesture *gesture)
128 {
129         if(gesture->type==WM_GESTURE_TWEAK) {
130                 rcti *rect= gesture->customdata;
131                 int dx= rect->xmax - rect->xmin;
132                 int dy= rect->ymax - rect->ymin;
133                 if(ABS(dx)+ABS(dy) > U.tweak_threshold) {
134                         int theta= (int)floor(4.0f*atan2f((float)dy, (float)dx)/(float)M_PI + 0.5f);
135                         int val= EVT_GESTURE_W;
136                         
137                         if(theta==0) val= EVT_GESTURE_E;
138                         else if(theta==1) val= EVT_GESTURE_NE;
139                         else if(theta==2) val= EVT_GESTURE_N;
140                         else if(theta==3) val= EVT_GESTURE_NW;
141                         else if(theta==-1) val= EVT_GESTURE_SE;
142                         else if(theta==-2) val= EVT_GESTURE_S;
143                         else if(theta==-3) val= EVT_GESTURE_SW;
144                         
145 #if 0
146                         /* debug */
147                         if(val==1) printf("tweak north\n");
148                         if(val==2) printf("tweak north-east\n");
149                         if(val==3) printf("tweak east\n");
150                         if(val==4) printf("tweak south-east\n");
151                         if(val==5) printf("tweak south\n");
152                         if(val==6) printf("tweak south-west\n");
153                         if(val==7) printf("tweak west\n");
154                         if(val==8) printf("tweak north-west\n");
155 #endif                  
156                         return val;
157                 }
158         }
159         return 0;
160 }
161
162
163 /* ******************* gesture draw ******************* */
164
165 static void wm_gesture_draw_rect(wmGesture *gt)
166 {
167         rcti *rect= (rcti *)gt->customdata;
168         
169         glEnable(GL_BLEND);
170         glColor4f(1.0, 1.0, 1.0, 0.05);
171         glBegin(GL_QUADS);
172         glVertex2s(rect->xmax, rect->ymin);
173         glVertex2s(rect->xmax, rect->ymax);
174         glVertex2s(rect->xmin, rect->ymax);
175         glVertex2s(rect->xmin, rect->ymin);
176         glEnd();
177         glDisable(GL_BLEND);
178         
179         glEnable(GL_LINE_STIPPLE);
180         glColor3ub(96, 96, 96);
181         glLineStipple(1, 0xCCCC);
182         sdrawbox(rect->xmin, rect->ymin, rect->xmax, rect->ymax);
183         glColor3ub(255, 255, 255);
184         glLineStipple(1, 0x3333);
185         sdrawbox(rect->xmin, rect->ymin, rect->xmax, rect->ymax);
186         glDisable(GL_LINE_STIPPLE);
187 }
188
189 static void wm_gesture_draw_line(wmGesture *gt)
190 {
191         rcti *rect= (rcti *)gt->customdata;
192         
193         glEnable(GL_LINE_STIPPLE);
194         glColor3ub(96, 96, 96);
195         glLineStipple(1, 0xAAAA);
196         sdrawline(rect->xmin, rect->ymin, rect->xmax, rect->ymax);
197         glColor3ub(255, 255, 255);
198         glLineStipple(1, 0x5555);
199         sdrawline(rect->xmin, rect->ymin, rect->xmax, rect->ymax);
200
201         glDisable(GL_LINE_STIPPLE);
202         
203 }
204
205 static void wm_gesture_draw_circle(wmGesture *gt)
206 {
207         rcti *rect= (rcti *)gt->customdata;
208
209         glTranslatef((float)rect->xmin, (float)rect->ymin, 0.0f);
210
211         glEnable(GL_BLEND);
212         glColor4f(1.0, 1.0, 1.0, 0.05);
213         glutil_draw_filled_arc(0.0, M_PI*2.0, rect->xmax, 40);
214         glDisable(GL_BLEND);
215         
216         glEnable(GL_LINE_STIPPLE);
217         glColor3ub(96, 96, 96);
218         glLineStipple(1, 0xAAAA);
219         glutil_draw_lined_arc(0.0, M_PI*2.0, rect->xmax, 40);
220         glColor3ub(255, 255, 255);
221         glLineStipple(1, 0x5555);
222         glutil_draw_lined_arc(0.0, M_PI*2.0, rect->xmax, 40);
223         
224         glDisable(GL_LINE_STIPPLE);
225         glTranslatef((float)-rect->xmin, (float)-rect->ymin, 0.0f);
226         
227 }
228
229 static void draw_filled_lasso(wmGesture *gt)
230 {
231         EditVert *v=NULL, *lastv=NULL, *firstv=NULL;
232         /* EditEdge *e; */ /* UNUSED */
233         EditFace *efa;
234         short *lasso= (short *)gt->customdata;
235         int i;
236         
237         for (i=0; i<gt->points; i++, lasso+=2) {
238                 float co[3];
239
240                 co[0]= (float)lasso[0];
241                 co[1]= (float)lasso[1];
242                 co[2]= 0.0f;
243
244                 v = BLI_addfillvert(co);
245                 if (lastv)
246                         /* e = */ /* UNUSED */ BLI_addfilledge(lastv, v);
247                 lastv = v;
248                 if (firstv==NULL) firstv = v;
249         }
250         
251         /* highly unlikely this will fail, but could crash if (gt->points == 0) */
252         if(firstv) {
253                 BLI_addfilledge(firstv, v);
254                 BLI_edgefill(0);
255         
256                 glEnable(GL_BLEND);
257                 glColor4f(1.0, 1.0, 1.0, 0.05);
258                 glBegin(GL_TRIANGLES);
259                 for (efa = fillfacebase.first; efa; efa=efa->next) {
260                         glVertex2fv(efa->v1->co);
261                         glVertex2fv(efa->v2->co);
262                         glVertex2fv(efa->v3->co);
263                 }
264                 glEnd();
265                 glDisable(GL_BLEND);
266         
267                 BLI_end_edgefill();
268         }
269 }
270
271 static void wm_gesture_draw_lasso(wmGesture *gt)
272 {
273         short *lasso= (short *)gt->customdata;
274         int i;
275
276         draw_filled_lasso(gt);
277         
278         glEnable(GL_LINE_STIPPLE);
279         glColor3ub(96, 96, 96);
280         glLineStipple(1, 0xAAAA);
281         glBegin(GL_LINE_STRIP);
282         for(i=0; i<gt->points; i++, lasso+=2)
283                 glVertex2sv(lasso);
284         if(gt->type==WM_GESTURE_LASSO)
285                 glVertex2sv((short *)gt->customdata);
286         glEnd();
287         
288         glColor3ub(255, 255, 255);
289         glLineStipple(1, 0x5555);
290         glBegin(GL_LINE_STRIP);
291         lasso= (short *)gt->customdata;
292         for(i=0; i<gt->points; i++, lasso+=2)
293                 glVertex2sv(lasso);
294         if(gt->type==WM_GESTURE_LASSO)
295                 glVertex2sv((short *)gt->customdata);
296         glEnd();
297         
298         glDisable(GL_LINE_STIPPLE);
299         
300 }
301
302 static void wm_gesture_draw_cross(wmWindow *win, wmGesture *gt)
303 {
304         rcti *rect= (rcti *)gt->customdata;
305         
306         glEnable(GL_LINE_STIPPLE);
307         glColor3ub(96, 96, 96);
308         glLineStipple(1, 0xCCCC);
309         sdrawline(rect->xmin - win->sizex, rect->ymin, rect->xmin + win->sizex, rect->ymin);
310         sdrawline(rect->xmin, rect->ymin - win->sizey, rect->xmin, rect->ymin + win->sizey);
311         
312         glColor3ub(255, 255, 255);
313         glLineStipple(1, 0x3333);
314         sdrawline(rect->xmin - win->sizex, rect->ymin, rect->xmin + win->sizex, rect->ymin);
315         sdrawline(rect->xmin, rect->ymin - win->sizey, rect->xmin, rect->ymin + win->sizey);
316         glDisable(GL_LINE_STIPPLE);
317 }
318
319 /* called in wm_draw.c */
320 void wm_gesture_draw(wmWindow *win)
321 {
322         wmGesture *gt= (wmGesture *)win->gesture.first;
323         
324         for(; gt; gt= gt->next) {
325                 /* all in subwindow space */
326                 wmSubWindowSet(win, gt->swinid);
327                 
328                 if(gt->type==WM_GESTURE_RECT)
329                         wm_gesture_draw_rect(gt);
330 //              else if(gt->type==WM_GESTURE_TWEAK)
331 //                      wm_gesture_draw_line(gt);
332                 else if(gt->type==WM_GESTURE_CIRCLE)
333                         wm_gesture_draw_circle(gt);
334                 else if(gt->type==WM_GESTURE_CROSS_RECT) {
335                         if(gt->mode==1)
336                                 wm_gesture_draw_rect(gt);
337                         else
338                                 wm_gesture_draw_cross(win, gt);
339                 }
340                 else if(gt->type==WM_GESTURE_LINES) 
341                         wm_gesture_draw_lasso(gt);
342                 else if(gt->type==WM_GESTURE_LASSO) 
343                         wm_gesture_draw_lasso(gt);
344                 else if(gt->type==WM_GESTURE_STRAIGHTLINE)
345                         wm_gesture_draw_line(gt);
346         }
347 }
348
349 void wm_gesture_tag_redraw(bContext *C)
350 {
351         wmWindow *win= CTX_wm_window(C);
352         bScreen *screen= CTX_wm_screen(C);
353         ARegion *ar= CTX_wm_region(C);
354         
355         if(screen)
356                 screen->do_draw_gesture= 1;
357
358         wm_tag_redraw_overlay(win, ar);
359 }