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