Cleanup: trailing space for windowmanager
[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_bitmap_draw_2d.h"
41 #include "BLI_blenlib.h"
42 #include "BLI_math.h"
43 #include "BLI_utildefines.h"
44 #include "BLI_lasso_2d.h"
45
46 #include "BKE_context.h"
47
48
49 #include "WM_api.h"
50 #include "WM_types.h"
51
52 #include "wm.h"
53 #include "wm_subwindow.h"
54 #include "wm_draw.h"
55 #include "GPU_basic_shader.h"
56
57
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         gesture->userdata_free = true;   /* Free if userdata is set. */
75         gesture->modal_state = GESTURE_MODAL_NOP;
76
77         wm_subwindow_origin_get(window, gesture->swinid, &sx, &sy);
78
79         if (ELEM(type, WM_GESTURE_RECT, WM_GESTURE_CROSS_RECT, WM_GESTURE_TWEAK,
80                   WM_GESTURE_CIRCLE, WM_GESTURE_STRAIGHTLINE))
81         {
82                 rcti *rect = MEM_callocN(sizeof(rcti), "gesture rect new");
83
84                 gesture->customdata = rect;
85                 rect->xmin = event->x - sx;
86                 rect->ymin = event->y - sy;
87                 if (type == WM_GESTURE_CIRCLE) {
88                         /* caller is responsible for initializing 'xmax' to radius. */
89                 }
90                 else {
91                         rect->xmax = event->x - sx;
92                         rect->ymax = event->y - sy;
93                 }
94         }
95         else if (ELEM(type, WM_GESTURE_LINES, WM_GESTURE_LASSO)) {
96                 short *lasso;
97                 gesture->points_alloc = 1024;
98                 gesture->customdata = lasso = MEM_mallocN(sizeof(short[2]) * gesture->points_alloc, "lasso points");
99                 lasso[0] = event->x - sx;
100                 lasso[1] = event->y - sy;
101                 gesture->points = 1;
102         }
103
104         return gesture;
105 }
106
107 void WM_gesture_end(bContext *C, wmGesture *gesture)
108 {
109         wmWindow *win = CTX_wm_window(C);
110
111         if (win->tweak == gesture)
112                 win->tweak = NULL;
113         BLI_remlink(&win->gesture, gesture);
114         MEM_freeN(gesture->customdata);
115         if (gesture->userdata && gesture->userdata_free) {
116                 MEM_freeN(gesture->userdata);
117         }
118         MEM_freeN(gesture);
119 }
120
121 void WM_gestures_remove(bContext *C)
122 {
123         wmWindow *win = CTX_wm_window(C);
124
125         while (win->gesture.first)
126                 WM_gesture_end(C, win->gesture.first);
127 }
128
129
130 /* tweak and line gestures */
131 int wm_gesture_evaluate(wmGesture *gesture)
132 {
133         if (gesture->type == WM_GESTURE_TWEAK) {
134                 rcti *rect = gesture->customdata;
135                 int dx = BLI_rcti_size_x(rect);
136                 int dy = BLI_rcti_size_y(rect);
137                 if (abs(dx) + abs(dy) > U.tweak_threshold) {
138                         int theta = round_fl_to_int(4.0f * atan2f((float)dy, (float)dx) / (float)M_PI);
139                         int val = EVT_GESTURE_W;
140
141                         if (theta == 0) val = EVT_GESTURE_E;
142                         else if (theta == 1) val = EVT_GESTURE_NE;
143                         else if (theta == 2) val = EVT_GESTURE_N;
144                         else if (theta == 3) val = EVT_GESTURE_NW;
145                         else if (theta == -1) val = EVT_GESTURE_SE;
146                         else if (theta == -2) val = EVT_GESTURE_S;
147                         else if (theta == -3) val = EVT_GESTURE_SW;
148
149 #if 0
150                         /* debug */
151                         if (val == 1) printf("tweak north\n");
152                         if (val == 2) printf("tweak north-east\n");
153                         if (val == 3) printf("tweak east\n");
154                         if (val == 4) printf("tweak south-east\n");
155                         if (val == 5) printf("tweak south\n");
156                         if (val == 6) printf("tweak south-west\n");
157                         if (val == 7) printf("tweak west\n");
158                         if (val == 8) printf("tweak north-west\n");
159 #endif
160                         return val;
161                 }
162         }
163         return 0;
164 }
165
166
167 /* ******************* gesture draw ******************* */
168
169 static void wm_gesture_draw_rect(wmGesture *gt)
170 {
171         rcti *rect = (rcti *)gt->customdata;
172
173         glEnable(GL_BLEND);
174         glColor4f(1.0, 1.0, 1.0, 0.05);
175         glBegin(GL_QUADS);
176         glVertex2s(rect->xmax, rect->ymin);
177         glVertex2s(rect->xmax, rect->ymax);
178         glVertex2s(rect->xmin, rect->ymax);
179         glVertex2s(rect->xmin, rect->ymin);
180         glEnd();
181         glDisable(GL_BLEND);
182
183         GPU_basic_shader_bind(GPU_SHADER_LINE | GPU_SHADER_STIPPLE | GPU_SHADER_USE_COLOR);
184         glColor3ub(96, 96, 96);
185         GPU_basic_shader_line_stipple(1, 0xCCCC);
186         sdrawbox(rect->xmin, rect->ymin, rect->xmax, rect->ymax);
187         glColor3ub(255, 255, 255);
188         GPU_basic_shader_line_stipple(1, 0x3333);
189         sdrawbox(rect->xmin, rect->ymin, rect->xmax, rect->ymax);
190         GPU_basic_shader_bind(GPU_SHADER_USE_COLOR);
191 }
192
193 static void wm_gesture_draw_line(wmGesture *gt)
194 {
195         rcti *rect = (rcti *)gt->customdata;
196
197         GPU_basic_shader_bind(GPU_SHADER_LINE | GPU_SHADER_STIPPLE);
198         glColor3ub(96, 96, 96);
199         GPU_basic_shader_line_stipple(1, 0xAAAA);
200         sdrawline(rect->xmin, rect->ymin, rect->xmax, rect->ymax);
201         glColor3ub(255, 255, 255);
202         GPU_basic_shader_line_stipple(1, 0x5555);
203         sdrawline(rect->xmin, rect->ymin, rect->xmax, rect->ymax);
204
205         GPU_basic_shader_bind(GPU_SHADER_USE_COLOR);
206
207 }
208
209 static void wm_gesture_draw_circle(wmGesture *gt)
210 {
211         rcti *rect = (rcti *)gt->customdata;
212
213         glTranslatef((float)rect->xmin, (float)rect->ymin, 0.0f);
214
215         glEnable(GL_BLEND);
216         glColor4f(1.0, 1.0, 1.0, 0.05);
217         glutil_draw_filled_arc(0.0, M_PI * 2.0, rect->xmax, 40);
218         glDisable(GL_BLEND);
219
220         // for USE_GLSL works bad because of no relation between lines
221         GPU_basic_shader_bind(GPU_SHADER_LINE | GPU_SHADER_STIPPLE | GPU_SHADER_USE_COLOR);
222         glColor3ub(96, 96, 96);
223         GPU_basic_shader_line_stipple(1, 0xAAAA);
224         glutil_draw_lined_arc(0.0, M_PI * 2.0, rect->xmax, 40);
225         glColor3ub(255, 255, 255);
226         GPU_basic_shader_line_stipple(1, 0x5555);
227         glutil_draw_lined_arc(0.0, M_PI * 2.0, rect->xmax, 40);
228
229         GPU_basic_shader_bind(GPU_SHADER_USE_COLOR);
230         glTranslatef(-rect->xmin, -rect->ymin, 0.0f);
231
232 }
233
234 struct LassoFillData {
235         unsigned char *px;
236         int width;
237 };
238
239 static void draw_filled_lasso_px_cb(int x, int x_end, int y, void *user_data)
240 {
241         struct LassoFillData *data = user_data;
242         unsigned char *col = &(data->px[(y * data->width) + x]);
243         memset(col, 0x10, x_end - x);
244 }
245
246 static void draw_filled_lasso(wmWindow *win, wmGesture *gt)
247 {
248         const short *lasso = (short *)gt->customdata;
249         const int tot = gt->points;
250         int (*moves)[2] = MEM_mallocN(sizeof(*moves) * (tot + 1), __func__);
251         int i;
252         rcti rect;
253         rcti rect_win;
254
255         for (i = 0; i < tot; i++, lasso += 2) {
256                 moves[i][0] = lasso[0];
257                 moves[i][1] = lasso[1];
258         }
259
260         BLI_lasso_boundbox(&rect, (const int (*)[2])moves, tot);
261
262         wm_subwindow_rect_get(win, gt->swinid, &rect_win);
263         BLI_rcti_translate(&rect, rect_win.xmin, rect_win.ymin);
264         BLI_rcti_isect(&rect_win, &rect, &rect);
265         BLI_rcti_translate(&rect, -rect_win.xmin, -rect_win.ymin);
266
267         /* highly unlikely this will fail, but could crash if (tot == 0) */
268         if (BLI_rcti_is_empty(&rect) == false) {
269                 const int w = BLI_rcti_size_x(&rect);
270                 const int h = BLI_rcti_size_y(&rect);
271                 unsigned char *pixel_buf = MEM_callocN(sizeof(*pixel_buf) * w * h, __func__);
272                 struct LassoFillData lasso_fill_data = {pixel_buf, w};
273
274                 BLI_bitmap_draw_2d_poly_v2i_n(
275                        rect.xmin, rect.ymin, rect.xmax, rect.ymax,
276                        (const int (*)[2])moves, tot,
277                        draw_filled_lasso_px_cb, &lasso_fill_data);
278
279                 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
280
281                 glColor4f(1, 1, 1, 1);
282                 glPixelTransferf(GL_RED_BIAS, 1);
283                 glPixelTransferf(GL_GREEN_BIAS, 1);
284                 glPixelTransferf(GL_BLUE_BIAS, 1);
285
286                 GPU_basic_shader_bind(GPU_SHADER_TEXTURE_2D | GPU_SHADER_USE_COLOR);
287
288                 glEnable(GL_BLEND);
289                 glaDrawPixelsTex(rect.xmin, rect.ymin, w, h, GL_ALPHA, GL_UNSIGNED_BYTE, GL_NEAREST, pixel_buf);
290                 glDisable(GL_BLEND);
291
292                 GPU_basic_shader_bind(GPU_SHADER_USE_COLOR);
293
294                 glPixelTransferf(GL_RED_BIAS, 0);
295                 glPixelTransferf(GL_GREEN_BIAS, 0);
296                 glPixelTransferf(GL_BLUE_BIAS, 0);
297
298                 glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
299
300                 MEM_freeN(pixel_buf);
301         }
302
303         MEM_freeN(moves);
304 }
305
306
307 static void wm_gesture_draw_lasso(wmWindow *win, wmGesture *gt, bool filled)
308 {
309         const short *lasso = (short *)gt->customdata;
310         int i;
311
312         if (filled) {
313                 draw_filled_lasso(win, gt);
314         }
315
316         // for USE_GLSL can't check this yet
317         GPU_basic_shader_bind(GPU_SHADER_LINE | GPU_SHADER_STIPPLE | GPU_SHADER_USE_COLOR);
318         glColor3ub(96, 96, 96);
319         GPU_basic_shader_line_stipple(1, 0xAAAA);
320         glBegin(GL_LINE_STRIP);
321         for (i = 0; i < gt->points; i++, lasso += 2)
322                 glVertex2sv(lasso);
323         if (gt->type == WM_GESTURE_LASSO)
324                 glVertex2sv((short *)gt->customdata);
325         glEnd();
326
327         glColor3ub(255, 255, 255);
328         GPU_basic_shader_line_stipple(1, 0x5555);
329         glBegin(GL_LINE_STRIP);
330         lasso = (short *)gt->customdata;
331         for (i = 0; i < gt->points; i++, lasso += 2)
332                 glVertex2sv(lasso);
333         if (gt->type == WM_GESTURE_LASSO)
334                 glVertex2sv((short *)gt->customdata);
335         glEnd();
336
337         GPU_basic_shader_bind(GPU_SHADER_USE_COLOR);
338
339 }
340
341 static void wm_gesture_draw_cross(wmWindow *win, wmGesture *gt)
342 {
343         rcti *rect = (rcti *)gt->customdata;
344         const int winsize_x = WM_window_pixels_x(win);
345         const int winsize_y = WM_window_pixels_y(win);
346
347         GPU_basic_shader_bind(GPU_SHADER_LINE | GPU_SHADER_STIPPLE | GPU_SHADER_USE_COLOR);
348         glColor3ub(96, 96, 96);
349         GPU_basic_shader_line_stipple(1, 0xCCCC);
350         sdrawline(rect->xmin - winsize_x, rect->ymin, rect->xmin + winsize_x, rect->ymin);
351         sdrawline(rect->xmin, rect->ymin - winsize_y, rect->xmin, rect->ymin + winsize_y);
352
353         glColor3ub(255, 255, 255);
354         GPU_basic_shader_line_stipple(1, 0x3333);
355         sdrawline(rect->xmin - winsize_x, rect->ymin, rect->xmin + winsize_x, rect->ymin);
356         sdrawline(rect->xmin, rect->ymin - winsize_y, rect->xmin, rect->ymin + winsize_y);
357         GPU_basic_shader_bind(GPU_SHADER_USE_COLOR);
358 }
359
360 /* called in wm_draw.c */
361 void wm_gesture_draw(wmWindow *win)
362 {
363         wmGesture *gt = (wmGesture *)win->gesture.first;
364
365         GPU_basic_shader_line_width(1);
366         for (; gt; gt = gt->next) {
367                 /* all in subwindow space */
368                 wmSubWindowSet(win, gt->swinid);
369
370                 if (gt->type == WM_GESTURE_RECT)
371                         wm_gesture_draw_rect(gt);
372 //              else if (gt->type == WM_GESTURE_TWEAK)
373 //                      wm_gesture_draw_line(gt);
374                 else if (gt->type == WM_GESTURE_CIRCLE)
375                         wm_gesture_draw_circle(gt);
376                 else if (gt->type == WM_GESTURE_CROSS_RECT) {
377                         if (gt->is_active) {
378                                 wm_gesture_draw_rect(gt);
379                         }
380                         else {
381                                 wm_gesture_draw_cross(win, gt);
382                         }
383                 }
384                 else if (gt->type == WM_GESTURE_LINES)
385                         wm_gesture_draw_lasso(win, gt, false);
386                 else if (gt->type == WM_GESTURE_LASSO)
387                         wm_gesture_draw_lasso(win, gt, true);
388                 else if (gt->type == WM_GESTURE_STRAIGHTLINE)
389                         wm_gesture_draw_line(gt);
390         }
391 }
392
393 void wm_gesture_tag_redraw(bContext *C)
394 {
395         wmWindow *win = CTX_wm_window(C);
396         bScreen *screen = CTX_wm_screen(C);
397         ARegion *ar = CTX_wm_region(C);
398
399         if (screen)
400                 screen->do_draw_gesture = true;
401
402         wm_tag_redraw_overlay(win, ar);
403 }