Docs: doxygen file descriptions for BLF, GPU and WM
[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  * Gestures (cursor motions) creating, evaluating and drawing, shared between operators.
31  */
32
33 #include "DNA_screen_types.h"
34 #include "DNA_vec_types.h"
35 #include "DNA_userdef_types.h"
36 #include "DNA_windowmanager_types.h"
37
38 #include "MEM_guardedalloc.h"
39
40 #include "BLI_blenlib.h"
41 #include "BLI_math.h"
42 #include "BLI_utildefines.h"
43 #include "BLI_lasso.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, const 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,
78                   WM_GESTURE_CIRCLE, WM_GESTURE_STRAIGHTLINE))
79         {
80                 rcti *rect = MEM_callocN(sizeof(rcti), "gesture rect new");
81                 
82                 gesture->customdata = rect;
83                 rect->xmin = event->x - sx;
84                 rect->ymin = event->y - sy;
85                 if (type == WM_GESTURE_CIRCLE) {
86 #ifdef GESTURE_MEMORY
87                         rect->xmax = circle_select_size;
88 #else
89                         rect->xmax = 25;    // XXX temp
90 #endif
91                 }
92                 else {
93                         rect->xmax = event->x - sx;
94                         rect->ymax = event->y - sy;
95                 }
96         }
97         else if (ELEM(type, WM_GESTURE_LINES, WM_GESTURE_LASSO)) {
98                 short *lasso;
99                 gesture->customdata = lasso = MEM_callocN(2 * sizeof(short) * WM_LASSO_MIN_POINTS, "lasso points");
100                 lasso[0] = event->x - sx;
101                 lasso[1] = event->y - sy;
102                 gesture->points = 1;
103                 gesture->size = WM_LASSO_MIN_POINTS;
104         }
105         
106         return gesture;
107 }
108
109 void WM_gesture_end(bContext *C, wmGesture *gesture)
110 {
111         wmWindow *win = CTX_wm_window(C);
112         
113         if (win->tweak == gesture)
114                 win->tweak = NULL;
115         BLI_remlink(&win->gesture, gesture);
116         MEM_freeN(gesture->customdata);
117         if (gesture->userdata) {
118                 MEM_freeN(gesture->userdata);
119         }
120         MEM_freeN(gesture);
121 }
122
123 void WM_gestures_remove(bContext *C)
124 {
125         wmWindow *win = CTX_wm_window(C);
126         
127         while (win->gesture.first)
128                 WM_gesture_end(C, win->gesture.first);
129 }
130
131
132 /* tweak and line gestures */
133 int wm_gesture_evaluate(wmGesture *gesture)
134 {
135         if (gesture->type == WM_GESTURE_TWEAK) {
136                 rcti *rect = gesture->customdata;
137                 int dx = BLI_rcti_size_x(rect);
138                 int dy = BLI_rcti_size_y(rect);
139                 if (abs(dx) + abs(dy) > U.tweak_threshold) {
140                         int theta = iroundf(4.0f * atan2f((float)dy, (float)dx) / (float)M_PI);
141                         int val = EVT_GESTURE_W;
142
143                         if (theta == 0) val = EVT_GESTURE_E;
144                         else if (theta == 1) val = EVT_GESTURE_NE;
145                         else if (theta == 2) val = EVT_GESTURE_N;
146                         else if (theta == 3) val = EVT_GESTURE_NW;
147                         else if (theta == -1) val = EVT_GESTURE_SE;
148                         else if (theta == -2) val = EVT_GESTURE_S;
149                         else if (theta == -3) val = EVT_GESTURE_SW;
150                         
151 #if 0
152                         /* debug */
153                         if (val == 1) printf("tweak north\n");
154                         if (val == 2) printf("tweak north-east\n");
155                         if (val == 3) printf("tweak east\n");
156                         if (val == 4) printf("tweak south-east\n");
157                         if (val == 5) printf("tweak south\n");
158                         if (val == 6) printf("tweak south-west\n");
159                         if (val == 7) printf("tweak west\n");
160                         if (val == 8) printf("tweak north-west\n");
161 #endif
162                         return val;
163                 }
164         }
165         return 0;
166 }
167
168
169 /* ******************* gesture draw ******************* */
170
171 static void wm_gesture_draw_rect(wmGesture *gt)
172 {
173         rcti *rect = (rcti *)gt->customdata;
174         
175         glEnable(GL_BLEND);
176         glColor4f(1.0, 1.0, 1.0, 0.05);
177         glBegin(GL_QUADS);
178         glVertex2s(rect->xmax, rect->ymin);
179         glVertex2s(rect->xmax, rect->ymax);
180         glVertex2s(rect->xmin, rect->ymax);
181         glVertex2s(rect->xmin, rect->ymin);
182         glEnd();
183         glDisable(GL_BLEND);
184         
185         glEnable(GL_LINE_STIPPLE);
186         glColor3ub(96, 96, 96);
187         glLineStipple(1, 0xCCCC);
188         sdrawbox(rect->xmin, rect->ymin, rect->xmax, rect->ymax);
189         glColor3ub(255, 255, 255);
190         glLineStipple(1, 0x3333);
191         sdrawbox(rect->xmin, rect->ymin, rect->xmax, rect->ymax);
192         glDisable(GL_LINE_STIPPLE);
193 }
194
195 static void wm_gesture_draw_line(wmGesture *gt)
196 {
197         rcti *rect = (rcti *)gt->customdata;
198         
199         glEnable(GL_LINE_STIPPLE);
200         glColor3ub(96, 96, 96);
201         glLineStipple(1, 0xAAAA);
202         sdrawline(rect->xmin, rect->ymin, rect->xmax, rect->ymax);
203         glColor3ub(255, 255, 255);
204         glLineStipple(1, 0x5555);
205         sdrawline(rect->xmin, rect->ymin, rect->xmax, rect->ymax);
206
207         glDisable(GL_LINE_STIPPLE);
208         
209 }
210
211 static void wm_gesture_draw_circle(wmGesture *gt)
212 {
213         rcti *rect = (rcti *)gt->customdata;
214
215         glTranslatef((float)rect->xmin, (float)rect->ymin, 0.0f);
216
217         glEnable(GL_BLEND);
218         glColor4f(1.0, 1.0, 1.0, 0.05);
219         glutil_draw_filled_arc(0.0, M_PI * 2.0, rect->xmax, 40);
220         glDisable(GL_BLEND);
221         
222         glEnable(GL_LINE_STIPPLE);
223         glColor3ub(96, 96, 96);
224         glLineStipple(1, 0xAAAA);
225         glutil_draw_lined_arc(0.0, M_PI * 2.0, rect->xmax, 40);
226         glColor3ub(255, 255, 255);
227         glLineStipple(1, 0x5555);
228         glutil_draw_lined_arc(0.0, M_PI * 2.0, rect->xmax, 40);
229         
230         glDisable(GL_LINE_STIPPLE);
231         glTranslatef(-rect->xmin, -rect->ymin, 0.0f);
232         
233 }
234
235 struct LassoFillData {
236         unsigned int *px;
237         int width;
238 };
239
240 static void draw_filled_lasso_px_cb(int x, int y, void *user_data)
241 {
242         struct LassoFillData *data = user_data;
243         unsigned char *col = (unsigned char *)&(data->px[(y * data->width) + x]);
244         col[0] = col[1] = col[2] = 0xff;
245         col[3] = 0x10;
246 }
247
248 static void draw_filled_lasso(wmWindow *win, wmGesture *gt)
249 {
250         short *lasso = (short *)gt->customdata;
251         const int tot = gt->points;
252         int (*moves)[2] = MEM_mallocN(sizeof(*moves) * (tot + 1), __func__);
253         int i;
254         rcti rect;
255         rcti rect_win;
256
257         for (i = 0; i < tot; i++, lasso += 2) {
258                 moves[i][0] = lasso[0];
259                 moves[i][1] = lasso[1];
260         }
261
262         BLI_lasso_boundbox(&rect, (const int (*)[2])moves, tot);
263
264         wm_subwindow_getrect(win, gt->swinid, &rect_win);
265         BLI_rcti_translate(&rect, rect_win.xmin, rect_win.ymin);
266         BLI_rcti_isect(&rect_win, &rect, &rect);
267         BLI_rcti_translate(&rect, -rect_win.xmin, -rect_win.ymin);
268
269         /* highly unlikely this will fail, but could crash if (tot == 0) */
270         if (BLI_rcti_is_empty(&rect) == false) {
271                 const int w = BLI_rcti_size_x(&rect);
272                 const int h = BLI_rcti_size_y(&rect);
273                 unsigned int *pixel_buf = MEM_callocN(sizeof(*pixel_buf) * w * h, __func__);
274                 struct LassoFillData lasso_fill_data = {pixel_buf, w};
275
276                 fill_poly_v2i_n(
277                        rect.xmin, rect.ymin, rect.xmax, rect.ymax,
278                        (const int (*)[2])moves, tot,
279                        draw_filled_lasso_px_cb, &lasso_fill_data);
280
281                 glEnable(GL_BLEND);
282                 // glColor4f(1.0, 1.0, 1.0, 0.05);
283
284                 glRasterPos2f(rect.xmin, rect.ymin);
285
286                 glDrawPixels(w, h, GL_RGBA, GL_UNSIGNED_BYTE, pixel_buf);
287
288                 glDisable(GL_BLEND);
289                 MEM_freeN(pixel_buf);
290         }
291
292         MEM_freeN(moves);
293 }
294
295
296 static void wm_gesture_draw_lasso(wmWindow *win, wmGesture *gt, bool filled)
297 {
298         short *lasso = (short *)gt->customdata;
299         int i;
300
301         if (filled) {
302                 draw_filled_lasso(win, gt);
303         }
304
305         glEnable(GL_LINE_STIPPLE);
306         glColor3ub(96, 96, 96);
307         glLineStipple(1, 0xAAAA);
308         glBegin(GL_LINE_STRIP);
309         for (i = 0; i < gt->points; i++, lasso += 2)
310                 glVertex2sv(lasso);
311         if (gt->type == WM_GESTURE_LASSO)
312                 glVertex2sv((short *)gt->customdata);
313         glEnd();
314         
315         glColor3ub(255, 255, 255);
316         glLineStipple(1, 0x5555);
317         glBegin(GL_LINE_STRIP);
318         lasso = (short *)gt->customdata;
319         for (i = 0; i < gt->points; i++, lasso += 2)
320                 glVertex2sv(lasso);
321         if (gt->type == WM_GESTURE_LASSO)
322                 glVertex2sv((short *)gt->customdata);
323         glEnd();
324         
325         glDisable(GL_LINE_STIPPLE);
326         
327 }
328
329 static void wm_gesture_draw_cross(wmWindow *win, wmGesture *gt)
330 {
331         rcti *rect = (rcti *)gt->customdata;
332         const int winsize_x = WM_window_pixels_x(win);
333         const int winsize_y = WM_window_pixels_y(win);
334
335         glEnable(GL_LINE_STIPPLE);
336         glColor3ub(96, 96, 96);
337         glLineStipple(1, 0xCCCC);
338         sdrawline(rect->xmin - winsize_x, rect->ymin, rect->xmin + winsize_x, rect->ymin);
339         sdrawline(rect->xmin, rect->ymin - winsize_y, rect->xmin, rect->ymin + winsize_y);
340         
341         glColor3ub(255, 255, 255);
342         glLineStipple(1, 0x3333);
343         sdrawline(rect->xmin - winsize_x, rect->ymin, rect->xmin + winsize_x, rect->ymin);
344         sdrawline(rect->xmin, rect->ymin - winsize_y, rect->xmin, rect->ymin + winsize_y);
345         glDisable(GL_LINE_STIPPLE);
346 }
347
348 /* called in wm_draw.c */
349 void wm_gesture_draw(wmWindow *win)
350 {
351         wmGesture *gt = (wmGesture *)win->gesture.first;
352         
353         for (; gt; gt = gt->next) {
354                 /* all in subwindow space */
355                 wmSubWindowSet(win, gt->swinid);
356                 
357                 if (gt->type == WM_GESTURE_RECT)
358                         wm_gesture_draw_rect(gt);
359 //              else if (gt->type == WM_GESTURE_TWEAK)
360 //                      wm_gesture_draw_line(gt);
361                 else if (gt->type == WM_GESTURE_CIRCLE)
362                         wm_gesture_draw_circle(gt);
363                 else if (gt->type == WM_GESTURE_CROSS_RECT) {
364                         if (gt->mode == 1)
365                                 wm_gesture_draw_rect(gt);
366                         else
367                                 wm_gesture_draw_cross(win, gt);
368                 }
369                 else if (gt->type == WM_GESTURE_LINES)
370                         wm_gesture_draw_lasso(win, gt, false);
371                 else if (gt->type == WM_GESTURE_LASSO)
372                         wm_gesture_draw_lasso(win, gt, true);
373                 else if (gt->type == WM_GESTURE_STRAIGHTLINE)
374                         wm_gesture_draw_line(gt);
375         }
376 }
377
378 void wm_gesture_tag_redraw(bContext *C)
379 {
380         wmWindow *win = CTX_wm_window(C);
381         bScreen *screen = CTX_wm_screen(C);
382         ARegion *ar = CTX_wm_region(C);
383         
384         if (screen)
385                 screen->do_draw_gesture = TRUE;
386
387         wm_tag_redraw_overlay(win, ar);
388 }