Credit Andrew - fix vorbis audio which was scratchy and ensure aging plugin does...
[goodguy/cinelerra.git] / cinelerra-5.1 / cinelerra / dragcheckbox.C
1 /*
2  * This program is free software; you can redistribute it and/or modify it
3  * under the terms of the GNU General Public License as published
4  * by the Free Software Foundation; either version 2 of the License, or
5  * (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful, but
8  * WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
10  * General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public
13  * License along with this program; if not, write to the Free Software
14  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
15  * USA
16  */
17
18 #include "automation.h"
19 #include "bctoggle.h"
20 #include "canvas.h"
21 #include "cwindow.h"
22 #include "cwindowgui.h"
23 #include "dragcheckbox.h"
24 #include "edl.h"
25 #include "edlsession.h"
26 #include "mwindow.h"
27 #include "theme.h"
28 #include "track.h"
29 #include "vframe.h"
30
31 DragCheckBox::DragCheckBox(MWindow *mwindow,
32         int x, int y, const char *text, int *value,
33         float drag_x, float drag_y, float drag_w, float drag_h)
34  : BC_CheckBox(x, y, value, text)
35 {
36         this->mwindow = mwindow;
37         this->drag_x = drag_x;  this->drag_y = drag_y;
38         this->drag_w = drag_w;  this->drag_h = drag_h;
39         drag_dx = drag_dy = 0;
40         grabbed = 0;
41         dragging = 0;
42         pending = 0;
43 }
44
45 DragCheckBox::~DragCheckBox()
46 {
47         drag_deactivate();
48 }
49
50 int DragCheckBox::get_track_w()
51 {
52         Track *track = get_drag_track();
53         return track ? track->track_w : mwindow->edl->session->output_w;
54 }
55 int DragCheckBox::get_track_h()
56 {
57         Track *track = get_drag_track();
58         return track ? track->track_h : mwindow->edl->session->output_h;
59 }
60
61 void DragCheckBox::create_objects()
62 {
63         if( !drag_w ) drag_w = get_track_w();
64         if( !drag_h ) drag_h = get_track_h();
65         if( get_value() )
66                 drag_activate();
67 }
68
69 int DragCheckBox::handle_event()
70 {
71         int ret = BC_CheckBox::handle_event();
72         if( get_value() ) {
73                 if( drag_activate() ) {
74                         update(*value=0);
75                         flicker(10,50);
76                 }
77         }
78         else
79                 drag_deactivate();
80         return ret;
81 }
82
83 int DragCheckBox::drag_activate()
84 {
85         int ret = 0;
86         if( !grabbed && !(grabbed = grab(mwindow->cwindow->gui)) ) {
87                 ret = 1;
88         }
89         pending = 0;
90         dragging = 0;
91         return ret;
92 }
93
94 void DragCheckBox::drag_deactivate()
95 {
96         if( grabbed ) {
97                 ungrab(mwindow->cwindow->gui);
98                 grabbed = 0;
99         }
100         pending = 0;
101         dragging = 0;
102 }
103
104 int DragCheckBox::handle_ungrab()
105 {
106         drag_deactivate();
107         update(*value = 0);
108         update_gui();
109         return 1;
110 }
111
112 int DragCheckBox::check_pending()
113 {
114         if( pending && !grab_event_count() ) {
115                 pending = 0;
116                 update_gui();
117         }
118         return 0;
119 }
120
121 int DragCheckBox::grab_event(XEvent *event)
122 {
123         switch( event->type ) {
124         case ButtonPress: break;
125         case ButtonRelease: break;
126         case MotionNotify: break;
127         default:
128                 return check_pending();
129         }
130
131         CWindowGUI *cwindow_gui = mwindow->cwindow->gui;
132         CWindowCanvas *canvas = cwindow_gui->canvas;
133         int cx, cy;  cwindow_gui->get_relative_cursor(cx, cy);
134         cx -= mwindow->theme->ccanvas_x;
135         cy -= mwindow->theme->ccanvas_y;
136
137         if( !dragging ) {
138                 if( cx < 0 || cx >= mwindow->theme->ccanvas_w ||
139                     cy < 0 || cy >= mwindow->theme->ccanvas_h )
140                         return check_pending();
141         }
142
143         switch( event->type ) {
144         case ButtonPress:
145                 if( !dragging ) break;
146                 return 1;
147         case ButtonRelease:
148                 if( !dragging ) return check_pending();
149                 dragging = 0;
150                 return 1;
151         case MotionNotify:
152                 if( !dragging ) return check_pending();
153                 break;
154         default:
155                 return check_pending();
156         }
157
158         int track_w = get_track_w(), track_h = get_track_h();
159         if( !drag_w ) drag_w = track_w;
160         if( !drag_h ) drag_h = track_h;
161
162         int64_t position = get_drag_position();
163         float cursor_x = cx, cursor_y = cy;
164         canvas->canvas_to_output(mwindow->edl, 0, cursor_x, cursor_y);
165         float projector_x, projector_y, projector_z;
166         Track *track = get_drag_track();
167         if( track ) {
168                 track->automation->get_projector(
169                         &projector_x, &projector_y, &projector_z,
170                         position, PLAY_FORWARD);
171                 projector_x += mwindow->edl->session->output_w / 2;
172                 projector_y += mwindow->edl->session->output_h / 2;
173                 cursor_x = (cursor_x - projector_x) / projector_z + track_w / 2;
174                 cursor_y = (cursor_y - projector_y) / projector_z + track_h / 2;
175         }
176         float r = MIN(track_w, track_h)/100.f + 2;
177         float x0 = drag_x, x1 = drag_x+(drag_w+1)/2, x2 = drag_x+drag_w;
178         float y0 = drag_y, y1 = drag_y+(drag_h+1)/2, y2 = drag_y+drag_h;
179         if( !dragging ) {  // clockwise
180                      if( fabs(drag_dx = cursor_x-x0) < r &&  // x0,y0
181                          fabs(drag_dy = cursor_y-y0) < r ) dragging = 1;
182                 else if( fabs(drag_dx = cursor_x-x1) < r &&  // x1,y0
183                          fabs(drag_dy = cursor_y-y0) < r ) dragging = 2;
184                 else if( fabs(drag_dx = cursor_x-x2) < r &&  // x2,y0
185                          fabs(drag_dy = cursor_y-y0) < r ) dragging = 3;
186                 else if( fabs(drag_dx = cursor_x-x2) < r &&  // x2,y1
187                          fabs(drag_dy = cursor_y-y1) < r ) dragging = 4;
188                 else if( fabs(drag_dx = cursor_x-x2) < r &&  // x2,y2
189                          fabs(drag_dy = cursor_y-y2) < r ) dragging = 5;
190                 else if( fabs(drag_dx = cursor_x-x1) < r &&  // x1,y2
191                          fabs(drag_dy = cursor_y-y2) < r ) dragging = 6;
192                 else if( fabs(drag_dx = cursor_x-x0) < r &&  // x0,y2
193                          fabs(drag_dy = cursor_y-y2) < r ) dragging = 7;
194                 else if( fabs(drag_dx = cursor_x-x0) < r &&  // x0,y1
195                          fabs(drag_dy = cursor_y-y1) < r ) dragging = 8;
196                 else if( fabs(drag_dx = cursor_x-x1) < r &&  // x1,y1
197                          fabs(drag_dy = cursor_y-y1) < r ) dragging = 9;
198                 else
199                         return 0;
200                 return 1;
201         }
202         int cur_x = cursor_x - drag_dx;
203         int cur_y = cursor_y - drag_dy;
204         switch( dragging ) {
205         case 1: { // x0,y0
206                 float dx = cur_x - x0;
207                 float dy = cur_y - y0;
208                 if( !dx && !dy ) return 1;
209                 if( (drag_w-=dx) < 1 ) drag_w = 1;
210                 if( (drag_h-=dy) < 1 ) drag_h = 1;
211                 drag_x = cur_x;   drag_y = cur_y;
212                 break; }
213         case 2: { // x1,y0
214                 float dy = cur_y - y0;
215                 if( !dy ) return 1;
216                 drag_y = cur_y;
217                 if( (drag_h-=dy) < 1 ) drag_h = 1;
218                 break; }
219         case 3: { // x2,y0
220                 float dx = cur_x - x2;
221                 float dy = cur_y - y0;
222                 if( (drag_w+=dx) < 1 ) drag_w = 1;
223                 if( (drag_h-=dy) < 1 ) drag_h = 1;
224                 drag_y = cur_y;
225                 break; }
226         case 4: { // x2,y1
227                 float dx = cur_x - x2;
228                 if( !dx ) return 1;
229                 if( (drag_w+=dx) < 1 ) drag_w = 1;
230                 break; }
231         case 5: { // x2,y2
232                 float dx = cur_x - x2;
233                 float dy = cur_y - y2;
234                 if( (drag_w+=dx) < 1 ) drag_w = 1;
235                  if( (drag_h+=dy) < 1 ) drag_h = 1;
236                 break; }
237         case 6: { // x1,y2
238                 float dy = cur_y - y2;
239                 if( !dy ) return 1;
240                 if( (drag_h+=dy) < 1 ) drag_h = 1;
241                 break; }
242         case 7: { // x0,y2
243                 float dx = cur_x - x0;
244                 float dy = cur_y - y2;
245                 if( (drag_w-=dx) < 1 ) drag_w = 1;
246                 if( (drag_h+=dy) < 1 ) drag_h = 1;
247                 drag_x = cur_x;
248                 break; }
249         case 8: { // x0,y1
250                 float dx = cur_x - x0;
251                 if( !dx ) return 1;
252                 if( (drag_w-=dx) < 1 ) drag_w = 1;
253                 drag_x = cur_x;
254                 break; }
255         case 9: { // x1,y1
256                 float dx = cur_x - x1;
257                 float dy = cur_y - y1;
258                 if( !dx && !dy ) return 1;
259                 drag_x += dx;
260                 drag_y += dy;
261                 }
262         }
263         if( grab_event_count() )
264                 pending = 1;
265         else if( dragging ) {
266                 pending = 0;
267                 update_gui();
268         }
269         return 1;
270 }
271
272
273 void DragCheckBox::bound()
274 {
275         int trk_w = get_track_w(), trk_h = get_track_h();
276         float x1 = drag_x, x2 = x1 + drag_w;
277         float y1 = drag_y, y2 = y1 + drag_h;
278         bclamp(x1, 0, trk_w);  bclamp(x2, 0, trk_w);
279         bclamp(y1, 0, trk_h);  bclamp(y2, 0, trk_h);
280         if( x1 >= x2 ) { if( x2 > 0 ) x1 = x2-1; else x2 = (x1=0)+1; }
281         if( y1 >= y2 ) { if( x2 > 0 ) y1 = y2-1; else y2 = (y1=0)+1; }
282         drag_x = x1;  drag_y = y1;  drag_w = x2-x1;  drag_h = y2-y1;
283 }
284
285 void DragCheckBox::draw_boundary(VFrame *out,
286         int x, int y, int w, int h)
287 {
288         int iw = out->get_w(), ih = out->get_h();
289         int mr = MIN(iw, ih)/200 + 2, rr = 2*mr;
290         int r2 = (rr+1)/2;
291         int x0 = x-r2, x1 = x+(w+1)/2, x2 = x+w+r2;
292         int y0 = y-r2, y1 = y+(h+1)/2, y2 = y+h+r2;
293         int st = 1;
294         for( int r=2; r<mr; r<<=1 ) st = r;
295         out->set_stiple(st);
296
297         for( int r=mr/2; --r>=0; ) { // bbox
298                 int lft = x+r, rgt = x+w-1-r;
299                 int top = y+r, bot = y+h-1-r;
300                 out->draw_line(lft,top, rgt,top);
301                 out->draw_line(rgt,top, rgt,bot);
302                 out->draw_line(rgt,bot, lft,bot);
303                 out->draw_line(lft,bot, lft,top);
304         }
305
306         for( int r=mr; r<rr; ++r ) { // center
307                 out->draw_smooth(x1-r,y1, x1-r,y1+r, x1,y1+r);
308                 out->draw_smooth(x1,y1+r, x1+r,y1+r, x1+r,y1);
309                 out->draw_smooth(x1+r,y1, x1+r,y1-r, x1,y1-r);
310                 out->draw_smooth(x1,y1-r, x1-r,y1-r, x1-r,y1);
311         }
312
313         for( int r=rr; --r>=0; ) { // edge arrows
314                 out->draw_line(x1-r,y0+r, x1+r,y0+r);
315                 out->draw_line(x2-r,y1-r, x2-r,y1+r);
316                 out->draw_line(x1-r,y2-r, x1+r,y2-r);
317                 out->draw_line(x0+r,y1+r, x0+r,y1-r);
318         }
319         x0 += r2;  y0 += r2;  x2 -= r2;  y2 -= r2;
320         for( int r=2*mr; --r>=0; ) { // corner arrows
321                 out->draw_line(x0,y0+r, x0+r,y0);
322                 out->draw_line(x2,y0+r, x2-r,y0);
323                 out->draw_line(x2,y2-r, x2-r,y2);
324                 out->draw_line(x0,y2-r, x0+r,y2);
325         }
326         out->set_stiple(0);
327 }
328