add vicons
[goodguy/history.git] / cinelerra-5.0 / guicast / vicon.C
1 #include "vicon.h"
2
3 #include "bctimer.h"
4 #include "bcwindow.h"
5 #include "colors.h"
6 #include "keys.h"
7 #include "mutex.h"
8 #include "condition.h"
9
10 VIcon::
11 VIcon(int vw, int vh, double rate)
12 {
13         this->vw = vw;
14         this->vh = vh;
15         this->period = 1000./rate;
16         this->age = 0;
17         this->seq_no = 0;
18         this->in_use = 1;
19 }
20
21 VIcon::
22 ~VIcon()
23 {
24         clear_images();
25 }
26
27 void VIcon::
28 add_image(VFrame *frm, int ww, int hh, int vcmdl)
29 {
30         VFrame *img = new VFrame(ww, hh, vcmdl);
31         img->transfer_from(frm);
32         images.append(img);
33 }
34
35 void VIcon::
36 draw_vframe(BC_WindowBase *wdw, int x, int y)
37 {
38         wdw->draw_vframe(frame(), x,y, vw,vh);
39 }
40
41 VIcon *VIconThread::low_vicon()
42 {
43         if( !t_heap.size() ) return 0;
44         VIcon *vip = t_heap[0];
45         remove_vicon(0);
46         return vip;
47 }
48
49 void VIconThread::remove_vicon(int i)
50 {
51         int sz = t_heap.size();
52         for( int k; (k=2*(i+1)) < sz; i=k ) {
53                 if( t_heap[k]->age > t_heap[k-1]->age ) --k;
54                 t_heap[i] = t_heap[k];
55         }
56         VIcon *last = t_heap[--sz];
57         t_heap.remove_number(sz);
58         double age = last->age;
59         for( int k; i>0 && age<t_heap[k=(i-1)/2]->age; i=k )
60                 t_heap[i] = t_heap[k];
61         t_heap[i] = last;
62 }
63
64
65 VIconThread::
66 VIconThread(BC_WindowBase *wdw, int vw, int vh)
67  : Thread(1, 0, 0)
68 {
69         this->wdw = wdw;
70         this->view_win = 0;  this->vicon = 0;
71         this->cur_view = 0;  this->new_view = 0;
72         this->view_w = vw;   this->view_h = vh;
73         this->viewing = 0;   this->draw_flash = 0;
74         draw_lock = new Condition(0, "VIconThread::draw_lock", 1);
75         timer = new Timer();
76         done = 0;
77         interrupted = 1;
78 }
79
80 VIconThread::
81 ~VIconThread()
82 {
83         stop_drawing();
84         done = 1;
85         draw_lock->unlock();
86         if( Thread::running() ) {
87                 Thread::cancel();
88                 Thread::join();
89         }
90         t_heap.remove_all_objects();
91         delete timer;
92         delete draw_lock;
93 }
94
95 void VIconThread::
96 start_drawing()
97 {
98         wdw->lock_window("VIconThread::stop_drawing");
99         if( interrupted )
100                 draw_lock->unlock();
101         wdw->unlock_window();
102 }
103
104 void VIconThread::
105 stop_drawing()
106 {
107         wdw->lock_window("VIconThread::stop_drawing");
108         interrupted = 1;
109         wdw->unlock_window();
110 }
111
112 int VIconThread::keypress_event(int key)
113 {
114         if( !cur_view ) return 0;
115         if( key != ESC ) return 0;
116         set_view_popup(0);
117         return 1;
118 }
119
120 bool VIconThread::
121 visible(VIcon *vicon, int x, int y)
122 {
123         int y0 = 0;
124         int my = y + vicon->vh;
125         if( my <= y0 ) return false;
126         int y1 = y0 + wdw->get_h();
127         if( y >= y1 ) return false;
128         int x0 = 0;
129         int mx = x + vicon->vw;
130         if( mx <= x0 ) return false;
131         int x1 = x0 + wdw->get_w();
132         if( x >= x1 ) return false;
133         return true;
134 }
135
136 int ViewPopup::keypress_event()
137 {
138         int key = get_keypress();
139         return vt->keypress_event(key);
140 }
141 int ViewPopup::button_press_event()
142 {
143         return vt->keypress_event(ESC);
144 }
145
146 ViewPopup::ViewPopup(VIconThread *vt, VFrame *frame, int x, int y, int w, int h)
147  : BC_Popup(vt->wdw, x, y, w, h, BLACK)
148 {
149         this->vt = vt;
150 }
151
152 ViewPopup::~ViewPopup()
153 {
154         vt->wdw->set_active_subwindow(0);
155 }
156
157 void ViewPopup::draw_vframe(VFrame *frame)
158 {
159         BC_WindowBase::draw_vframe(frame, 0,0, get_w(),get_h());
160 }
161
162 ViewPopup *VIconThread::new_view_window(VFrame *frame)
163 {
164         int wx = viewing->get_vx() - view_w, rx = 0;
165         int wy = viewing->get_vy() - view_h, ry = 0;
166         wdw->get_root_coordinates(wx, wy, &rx, &ry);
167         ViewPopup *vwin = new ViewPopup(this, frame, rx, ry, view_w, view_h);
168         wdw->set_active_subwindow(vwin);
169         return vwin;
170 }
171
172 void VIconThread::
173 reset_images()
174 {
175         for( int i=t_heap.size(); --i>=0; ) t_heap[i]->age = 0;
176         timer->update();
177         img_dirty = win_dirty = 0;
178         draw_flash = 0;
179 }
180
181 void VIconThread::add_vicon(VIcon *vip, double age)
182 {
183         vip->age = age;
184         int i = t_heap.size();  t_heap.append(vip);
185         for( int k; i>0 && age<t_heap[(k=(i-1)/2)]->age; i=k )
186                 t_heap[i] = t_heap[k];
187         t_heap[i] = vip;
188 }
189
190 int VIconThread::del_vicon(VIcon *&vicon)
191 {
192         int i = t_heap.size();
193         while( --i >= 0 && t_heap[i] != vicon );
194         if( i < 0 ) return 0;
195         remove_vicon(i);
196         delete vicon;  vicon = 0;
197         return 1;
198 }
199
200 void VIconThread::set_view_popup(VIcon *vicon)
201 {
202         this->vicon = vicon;
203 }
204
205 int VIconThread::
206 update_view()
207 {
208         if( viewing == vicon && cur_view == new_view ) return 0;
209         wdw->lock_window("VIconThread::update_view");;
210         if( viewing && !vicon ) new_view = 0;
211         if( !viewing && vicon ) new_view = 1;
212         if( cur_view != new_view && !new_view ) vicon = 0;
213         viewing = vicon;  cur_view = new_view;
214         delete view_win;  view_win = 0;
215         if( cur_view ) {
216                 VFrame *frame = viewing->frame();
217                 view_win = new_view_window(frame);
218                 view_win->show_window();
219         }
220         wdw->unlock_window();
221         return 1;
222 }
223
224
225 void VIconThread::
226 draw_images()
227 {
228         for( int i=0; i<t_heap.size(); ++i )
229                 draw(t_heap[i]);
230 }
231
232 void VIconThread::
233 flash()
234 {
235         if( !img_dirty && !win_dirty ) return;
236         if( img_dirty ) wdw->flash();
237         if( win_dirty ) view_win->flash();
238         win_dirty = img_dirty = 0;
239 }
240
241 int VIconThread::
242 draw(VIcon *vicon)
243 {
244         int x = vicon->get_vx(), y = vicon->get_vy();
245         int draw_img = visible(vicon, x, y);
246         int draw_win = view_win && viewing == vicon ? 1 : 0;
247         if( !draw_img && !draw_win ) return 0;
248         if( draw_img ) {
249                 vicon->draw_vframe(wdw, x, y);
250                 img_dirty = 1;
251         }
252         if( draw_win ) {
253                 view_win->draw_vframe(vicon->frame());
254                 win_dirty = 1;
255         }
256         return 1;
257 }
258
259 void VIconThread::
260 run()
261 {
262         while(!done) {
263                 draw_lock->lock("VIconThread::run 0");
264                 if( done ) break;;
265                 wdw->lock_window("BC_WindowBase::run 1");
266                 reset_images();
267                 interrupted = 0;
268                 drawing_started();
269                 while( !interrupted ) {
270                         if( viewing != vicon || cur_view != new_view )
271                                 update_view();
272                         VIcon *next = low_vicon();
273                         if( !next ) break;
274                         if( !next->frame() ) {
275                                 delete next;  next = 0;
276                                 continue;
277                         }
278                         int64_t next_time = next->age;
279                         int64_t this_time = timer->get_difference();
280                         int64_t msec = this_time - next_time;
281                         int count = msec / next->period;
282                         int nfrms = count > 0 ? count : 1;
283                         if( !next->next_frame(nfrms) )
284                                 next->age = this_time + 1000;
285                         add_vicon(next, next->age);
286                         if( msec < 1000 && draw(next) && !draw_flash )
287                                 draw_flash = next_time;
288                         wdw->unlock_window();
289                         msec = next_time - timer->get_difference();
290                         if( msec < 1 ) msec = 1;
291                         while( msec > 0 && !interrupted ) {
292                                 int ms = msec > 100 ? 100 : msec;
293                                 Timer::delay(ms);  msec -= ms;
294                         }
295                         wdw->lock_window("BC_WindowBase::run 2");
296                         if( interrupted ) break;
297                         if( draw_flash ) {
298                                 int64_t msec = timer->get_difference() - draw_flash;
299                                 if( msec < 1000 ) flash();
300                                 draw_flash = 0;
301                         }
302                 }
303                 drawing_stopped();
304                 interrupted = -1;
305                 wdw->unlock_window();
306         }
307 }
308
309 void VIcon::dump(const char *dir)
310 {
311         mkdir(dir,0777);
312         for( int i=0; i<images.size(); ++i ) {
313                 char fn[1024];  sprintf(fn,"%s/img%05d.png",dir,i);
314                 printf("\r%s",fn);
315                 images[i]->write_png(fn);
316         }
317         printf("\n");
318 }
319