3 * Copyright (C) 2014 Adam Williams <broadcast at earthling dot net>
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 #include "automation.h"
22 #include "bcdisplayinfo.h"
25 #include "tracerwindow.h"
28 #include "cwindowgui.h"
30 #include "edlsession.h"
32 #include "mainerror.h"
35 #include "pluginserver.h"
42 TracerNum::TracerNum(TracerWindow *gui, int x, int y, float output)
43 : BC_TumbleTextBox(gui, output, -32767.0f, 32767.0f, x, y, 120)
50 TracerNum::~TracerNum()
54 int TracerPointX::handle_event()
56 if( !TracerNum::handle_event() ) return 0;
57 TracerPointList *point_list = gui->point_list;
58 int hot_point = point_list->get_selection_number(0, 0);
59 TracerPoints &points = gui->plugin->config.points;
60 int sz = points.size();
61 if( hot_point >= 0 && hot_point < sz ) {
62 float v = atof(get_text());
63 points[hot_point]->x = v;
64 point_list->set_point(hot_point, PT_X, v);
66 point_list->update_list(hot_point);
67 gui->send_configure_change();
70 int TracerPointY::handle_event()
72 if( !TracerNum::handle_event() ) return 0;
73 TracerPointList *point_list = gui->point_list;
74 int hot_point = point_list->get_selection_number(0, 0);
75 TracerPoints &points = gui->plugin->config.points;
76 int sz = points.size();
77 if( hot_point >= 0 && hot_point < sz ) {
78 float v = atof(get_text());
79 points[hot_point]->y = v;
80 point_list->set_point(hot_point, PT_Y, v);
82 point_list->update_list(hot_point);
83 gui->send_configure_change();
87 TracerWindow::TracerWindow(Tracer *plugin)
88 : PluginClientWindow(plugin, 400, 300, 400, 300, 0)
90 this->plugin = plugin;
91 this->title_x = 0; this->point_x = 0;
92 this->title_y = 0; this->point_y = 0;
93 this->new_point = 0; this->del_point = 0;
94 this->point_up = 0; this->point_dn = 0;
95 this->drag = 0; this->draw = 0;
97 this->title_r = 0; this->title_s = 0;
98 this->radius = 0; this->scale = 0;
99 this->last_x = 0; this->last_y = 0;
100 this->point_list = 0; this->pending_config = 0;
103 TracerWindow::~TracerWindow()
109 void TracerWindow::create_objects()
112 int margin = plugin->get_theme()->widget_border;
113 TracerPoint *pt = plugin->config.points[plugin->config.selected];
114 add_subwindow(title_x = new BC_Title(x, y, _("X:")));
115 int x1 = x + title_x->get_w() + margin;
116 point_x = new TracerPointX(this, x1, y, pt->x);
117 point_x->create_objects();
118 x1 += point_x->get_w() + margin;
119 add_subwindow(new_point = new TracerNewPoint(this, plugin, x1, y));
120 x1 += new_point->get_w() + margin;
121 add_subwindow(point_up = new TracerPointUp(this, x1, y));
122 y += point_x->get_h() + margin;
123 add_subwindow(title_y = new BC_Title(x, y, _("Y:")));
124 x1 = x + title_y->get_w() + margin;
125 point_y = new TracerPointY(this, x1, y, pt->y);
126 point_y->create_objects();
127 x1 += point_y->get_w() + margin;
128 add_subwindow(del_point = new TracerDelPoint(this, plugin, x1, y));
129 x1 += del_point->get_w() + margin;
130 add_subwindow(point_dn = new TracerPointDn(this, x1, y));
131 y += point_y->get_h() + margin + 10;
133 add_subwindow(drag = new TracerDrag(this, x, y));
134 if( plugin->config.drag ) {
135 if( !grab(plugin->server->mwindow->cwindow->gui) )
136 eprintf("drag enabled, but compositor already grabbed\n");
138 x1 = x + drag->get_w() + margin + 20;
139 add_subwindow(draw = new TracerDraw(this, x1, y));
140 x1 += draw->get_w() + margin + 20;
141 add_subwindow(fill = new TracerFill(this, x1, y));
142 x1 += drag->get_w() + margin + 20;
143 add_subwindow(reset = new TracerReset(this, plugin, x1, y+3));
144 y += drag->get_h() + margin;
146 add_subwindow(title_r = new BC_Title(x1=x, y, _("Radius:")));
147 x1 += title_r->get_w() + margin;
148 add_subwindow(radius = new TracerRadius(this, x1, y, 100));
149 x1 += radius->get_w() + margin + 20;
150 add_subwindow(title_s = new BC_Title(x1, y, _("Scale:")));
151 x1 += title_s->get_w() + margin;
152 add_subwindow(scale = new TracerScale(this, x1, y, 100));
153 y += radius->get_h() + margin + 20;
155 add_subwindow(point_list = new TracerPointList(this, plugin, x, y));
156 point_list->update(plugin->config.selected);
157 // y += point_list->get_h() + 10;
162 void TracerWindow::send_configure_change()
165 plugin->send_configure_change();
168 int TracerWindow::grab_event(XEvent *event)
170 int ret = do_grab_event(event);
171 if( pending_config && !grab_event_count() )
172 send_configure_change();
176 int TracerWindow::do_grab_event(XEvent *event)
178 switch( event->type ) {
179 case ButtonPress: break;
180 case ButtonRelease: break;
181 case MotionNotify: break;
186 MWindow *mwindow = plugin->server->mwindow;
187 CWindowGUI *cwindow_gui = mwindow->cwindow->gui;
188 CWindowCanvas *canvas = cwindow_gui->canvas;
189 int cx, cy; cwindow_gui->get_relative_cursor(cx, cy);
190 cx -= canvas->view_x;
191 cy -= canvas->view_y;
194 if( cx < 0 || cx >= canvas->view_w ||
195 cy < 0 || cy >= canvas->view_h )
199 switch( event->type ) {
201 if( dragging ) return 0;
202 dragging = event->xbutton.state & ShiftMask ? -1 : 1;
205 if( !dragging ) return 0;
209 if( !dragging ) return 0;
215 float cursor_x = cx, cursor_y = cy;
216 canvas->canvas_to_output(mwindow->edl, 0, cursor_x, cursor_y);
217 int64_t position = plugin->get_source_position();
218 float projector_x, projector_y, projector_z;
219 Track *track = plugin->server->plugin->track;
220 int track_w = track->track_w, track_h = track->track_h;
221 track->automation->get_projector(
222 &projector_x, &projector_y, &projector_z,
223 position, PLAY_FORWARD);
224 projector_x += mwindow->edl->session->output_w / 2;
225 projector_y += mwindow->edl->session->output_h / 2;
226 float output_x = (cursor_x - projector_x) / projector_z + track_w / 2;
227 float output_y = (cursor_y - projector_y) / projector_z + track_h / 2;
228 point_x->update((int64_t)(output_x));
229 point_y->update((int64_t)(output_y));
230 TracerPoints &points = plugin->config.points;
233 switch( event->type ) {
235 int button_no = event->xbutton.button;
237 if( button_no == RIGHT_BUTTON ) {
238 hot_point = plugin->new_point();
239 TracerPoint *pt = points[hot_point];
240 pt->x = output_x; pt->y = output_y;
241 point_list->update(hot_point);
244 int sz = points.size();
245 if( hot_point < 0 && sz > 0 ) {
246 TracerPoint *pt = points[hot_point=0];
247 double dist = DISTANCE(output_x,output_y, pt->x,pt->y);
248 for( int i=1; i<sz; ++i ) {
250 double d = DISTANCE(output_x,output_y, pt->x,pt->y);
251 if( d >= dist ) continue;
252 dist = d; hot_point = i;
254 pt = points[hot_point];
255 float px = (pt->x - track_w / 2) * projector_z + projector_x;
256 float py = (pt->y - track_h / 2) * projector_z + projector_y;
257 dist = DISTANCE(px, py, cursor_x,cursor_y);
258 if( dist >= HANDLE_W ) hot_point = -1;
260 if( hot_point >= 0 && sz > 0 ) {
261 TracerPoint *pt = points[hot_point];
262 point_list->set_point(hot_point, PT_X, pt->x = output_x);
263 point_list->set_point(hot_point, PT_Y, pt->y = output_y);
264 point_list->update_list(hot_point);
268 int hot_point = point_list->get_selection_number(0, 0);
269 if( hot_point >= 0 && hot_point < points.size() ) {
270 TracerPoint *pt = points[hot_point];
271 if( pt->x == output_x && pt->y == output_y ) break;
272 point_list->set_point(hot_point, PT_X, pt->x = output_x);
273 point_list->set_point(hot_point, PT_Y, pt->y = output_y);
274 point_x->update(pt->x);
275 point_y->update(pt->y);
276 point_list->update_list(hot_point);
282 switch( event->type ) {
284 float dx = output_x - last_x, dy = output_y - last_y;
285 int sz = points.size();
286 for( int i=0; i<sz; ++i ) {
287 TracerPoint *pt = points[i];
288 point_list->set_point(i, PT_X, pt->x += dx);
289 point_list->set_point(i, PT_Y, pt->y += dy);
291 int hot_point = point_list->get_selection_number(0, 0);
292 if( hot_point >= 0 && hot_point < sz ) {
293 TracerPoint *pt = points[hot_point];
294 point_x->update(pt->x);
295 point_y->update(pt->y);
296 point_list->update_list(hot_point);
302 last_x = output_x; last_y = output_y;
307 void TracerWindow::done_event(int result)
309 ungrab(client->server->mwindow->cwindow->gui);
312 TracerPointList::TracerPointList(TracerWindow *gui, Tracer *plugin, int x, int y)
313 : BC_ListBox(x, y, 360, 130, LISTBOX_TEXT)
316 this->plugin = plugin;
317 titles[PT_X] = _("X"); widths[PT_X] = 90;
318 titles[PT_Y] = _("Y"); widths[PT_Y] = 90;
320 TracerPointList::~TracerPointList()
324 void TracerPointList::clear()
326 for( int i=PT_SZ; --i>=0; )
327 cols[i].remove_all_objects();
330 int TracerPointList::column_resize_event()
332 for( int i=PT_SZ; --i>=0; )
333 widths[i] = get_column_width(i);
337 int TracerPointList::handle_event()
339 int hot_point = get_selection_number(0, 0);
340 const char *x_text = "", *y_text = "";
341 TracerPoints &points = plugin->config.points;
343 int sz = points.size();
344 if( hot_point >= 0 && sz > 0 ) {
345 x_text = gui->point_list->cols[PT_X].get(hot_point)->get_text();
346 y_text = gui->point_list->cols[PT_Y].get(hot_point)->get_text();
348 gui->point_x->update(x_text);
349 gui->point_y->update(y_text);
351 gui->send_configure_change();
355 int TracerPointList::selection_changed()
361 void TracerPointList::new_point(const char *xp, const char *yp)
363 cols[PT_X].append(new BC_ListBoxItem(xp));
364 cols[PT_Y].append(new BC_ListBoxItem(yp));
367 void TracerPointList::del_point(int i)
369 for( int sz1=cols[0].size()-1, c=PT_SZ; --c>=0; )
370 cols[c].remove_object_number(sz1-i);
373 void TracerPointList::set_point(int i, int c, float v)
375 char s[BCSTRLEN]; sprintf(s,"%0.4f",v);
378 void TracerPointList::set_point(int i, int c, const char *cp)
380 cols[c].get(i)->set_text(cp);
383 int TracerPointList::set_selected(int k)
385 TracerPoints &points = plugin->config.points;
386 int sz = points.size();
389 update_selection(&cols[0], k);
392 void TracerPointList::update_list(int k)
394 int xpos = get_xposition(), ypos = get_yposition();
395 if( k < 0 ) k = get_selection_number(0, 0);
396 update_selection(&cols[0], k);
397 BC_ListBox::update(&cols[0], &titles[0],&widths[0],PT_SZ, xpos,ypos,k);
400 void TracerPointList::update(int k)
403 TracerPoints &points = plugin->config.points;
404 int sz = points.size();
405 for( int i=0; i<sz; ++i ) {
406 TracerPoint *pt = points[i];
407 char xtxt[BCSTRLEN]; sprintf(xtxt,"%0.4f", pt->x);
408 char ytxt[BCSTRLEN]; sprintf(ytxt,"%0.4f", pt->y);
409 new_point(xtxt, ytxt);
411 if( k >= 0 && k < sz ) {
412 gui->point_x->update(gui->point_list->cols[PT_X].get(k)->get_text());
413 gui->point_y->update(gui->point_list->cols[PT_Y].get(k)->get_text());
414 plugin->config.selected = k;
420 void TracerWindow::update_gui()
422 TracerConfig &config = plugin->config;
423 drag->update(config.drag);
424 draw->update(config.draw);
425 fill->update(config.fill);
426 radius->update(config.radius);
427 scale->update(config.scale);
428 drag->update(config.drag);
429 point_list->update(-1);
433 TracerPointUp::TracerPointUp(TracerWindow *gui, int x, int y)
434 : BC_GenericButton(x, y, _("Up"))
438 TracerPointUp::~TracerPointUp()
442 int TracerPointUp::handle_event()
444 TracerPoints &points = gui->plugin->config.points;
445 int sz = points.size();
446 int hot_point = gui->point_list->get_selection_number(0, 0);
448 if( sz > 1 && hot_point > 0 ) {
449 TracerPoint *&pt0 = points[hot_point];
450 TracerPoint *&pt1 = points[--hot_point];
451 TracerPoint *t = pt0; pt0 = pt1; pt1 = t;
452 gui->point_list->update(hot_point);
454 gui->send_configure_change();
458 TracerPointDn::TracerPointDn(TracerWindow *gui, int x, int y)
459 : BC_GenericButton(x, y, _("Dn"))
463 TracerPointDn::~TracerPointDn()
467 int TracerPointDn::handle_event()
469 TracerPoints &points = gui->plugin->config.points;
470 int sz = points.size();
471 int hot_point = gui->point_list->get_selection_number(0, 0);
472 if( sz > 1 && hot_point < sz-1 ) {
473 TracerPoint *&pt0 = points[hot_point];
474 TracerPoint *&pt1 = points[++hot_point];
475 TracerPoint *t = pt0; pt0 = pt1; pt1 = t;
476 gui->point_list->update(hot_point);
478 gui->send_configure_change();
482 TracerDrag::TracerDrag(TracerWindow *gui, int x, int y)
483 : BC_CheckBox(x, y, gui->plugin->config.drag, _("Drag"))
487 int TracerDrag::handle_event()
489 CWindowGUI *cwindow_gui = gui->plugin->server->mwindow->cwindow->gui;
490 int value = get_value();
492 if( !gui->grab(cwindow_gui) ) {
498 gui->ungrab(cwindow_gui);
499 gui->plugin->config.drag = value;
500 gui->send_configure_change();
504 TracerDraw::TracerDraw(TracerWindow *gui, int x, int y)
505 : BC_CheckBox(x, y, gui->plugin->config.draw, _("Draw"))
509 int TracerDraw::handle_event()
511 gui->plugin->config.draw = get_value();
512 gui->send_configure_change();
516 TracerFill::TracerFill(TracerWindow *gui, int x, int y)
517 : BC_CheckBox(x, y, gui->plugin->config.fill, _("Fill"))
521 int TracerFill::handle_event()
523 gui->plugin->config.fill = get_value();
524 gui->send_configure_change();
528 TracerRadius::TracerRadius(TracerWindow *gui, int x, int y, int w)
529 : BC_ISlider(x,y,0,w,w, -50,50, gui->plugin->config.radius)
533 int TracerRadius::handle_event()
535 gui->plugin->config.radius = get_value();
536 gui->send_configure_change();
540 TracerScale::TracerScale(TracerWindow *gui, int x, int y, int w)
541 : BC_FSlider(x,y, 0,w,w, 1.f,10.f, gui->plugin->config.scale)
545 int TracerScale::handle_event()
547 gui->plugin->config.scale = get_value();
548 gui->send_configure_change();
552 TracerNewPoint::TracerNewPoint(TracerWindow *gui, Tracer *plugin, int x, int y)
553 : BC_GenericButton(x, y, 80, _("New"))
556 this->plugin = plugin;
558 TracerNewPoint::~TracerNewPoint()
561 int TracerNewPoint::handle_event()
563 int k = plugin->new_point();
564 gui->point_list->update(k);
565 gui->send_configure_change();
569 TracerDelPoint::TracerDelPoint(TracerWindow *gui, Tracer *plugin, int x, int y)
570 : BC_GenericButton(x, y, 80, C_("Del"))
573 this->plugin = plugin;
575 TracerDelPoint::~TracerDelPoint()
578 int TracerDelPoint::handle_event()
580 int hot_point = gui->point_list->get_selection_number(0, 0);
581 TracerPoints &points = plugin->config.points;
582 if( hot_point >= 0 && hot_point < points.size() ) {
583 plugin->config.del_point(hot_point);
584 if( !points.size() ) plugin->new_point();
585 int sz = points.size();
586 if( hot_point >= sz && hot_point > 0 ) --hot_point;
587 gui->point_list->update(hot_point);
588 gui->send_configure_change();
593 TracerReset::TracerReset(TracerWindow *gui, Tracer *plugin, int x, int y)
594 : BC_GenericButton(x, y, _("Reset"))
597 this->plugin = plugin;
599 TracerReset::~TracerReset()
602 int TracerReset::handle_event()
604 TracerConfig &config = plugin->config;
611 TracerPoints &points = plugin->config.points;
612 points.remove_all_objects();
614 gui->point_list->update(0);
616 gui->send_configure_change();