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 "crikeywindow.h"
28 #include "cwindowgui.h"
30 #include "edlsession.h"
32 #include "mainerror.h"
35 #include "pluginserver.h"
42 CriKeyNum::CriKeyNum(CriKeyWindow *gui, int x, int y, float output)
43 : BC_TumbleTextBox(gui, output, -32767.0f, 32767.0f, x, y, 120)
50 CriKeyNum::~CriKeyNum()
54 int CriKeyPointX::handle_event()
56 if( !CriKeyNum::handle_event() ) return 0;
57 CriKeyPoints *points = gui->points;
58 int hot_point = points->get_selection_number(0, 0);
59 if( hot_point >= 0 && hot_point < gui->plugin->config.points.size() ) {
60 float v = atof(get_text());
61 gui->plugin->config.points[hot_point]->x = v;
62 points->set_point(hot_point, PT_X, v);
64 points->update_list();
65 gui->send_configure_change();
68 int CriKeyPointY::handle_event()
70 if( !CriKeyNum::handle_event() ) return 0;
71 CriKeyPoints *points = gui->points;
72 int hot_point = points->get_selection_number(0, 0);
73 if( hot_point >= 0 && hot_point < gui->plugin->config.points.size() ) {
74 float v = atof(get_text());
75 gui->plugin->config.points[hot_point]->y = v;
76 points->set_point(hot_point, PT_Y, v);
78 points->update_list();
79 gui->send_configure_change();
83 int CriKeyDrawModeItem::handle_event()
85 ((CriKeyDrawMode *)get_popup_menu())->update(id);
88 CriKeyDrawMode::CriKeyDrawMode(CriKeyWindow *gui, int x, int y)
89 : BC_PopupMenu(x, y, 100, "", 1)
92 draw_modes[DRAW_ALPHA] = _("Alpha");
93 draw_modes[DRAW_EDGE] = _("Edge");
94 draw_modes[DRAW_MASK] = _("Mask");
97 void CriKeyDrawMode::create_objects()
99 for( int i=0; i<DRAW_MODES; ++i )
100 add_item(new CriKeyDrawModeItem(draw_modes[i], i));
101 update(gui->plugin->config.draw_mode, 0);
103 void CriKeyDrawMode::update(int mode, int send)
105 if( this->mode == mode ) return;
107 set_text(draw_modes[mode]);
108 gui->plugin->config.draw_mode = mode;
109 if( send ) gui->send_configure_change();
112 CriKeyColorButton::CriKeyColorButton(CriKeyWindow *gui, int x, int y)
113 : BC_GenericButton(x, y, _("Color"))
117 int CriKeyColorButton::handle_event()
119 gui->start_color_thread();
123 CriKeyColorPicker::CriKeyColorPicker(CriKeyColorButton *color_button)
124 : ColorPicker(0, _("Color"))
126 this->color_button = color_button;
129 void CriKeyColorPicker::start(int color)
131 orig_color = this->color = color;
132 start_window(color, 0, 1);
135 void CriKeyColorPicker::handle_done_event(int result)
137 if( result ) color = orig_color;
138 CriKeyWindow *gui = color_button->gui;
139 gui->lock_window("CriKeyColorPicker::handle_done_event");
140 gui->update_color(color);
141 gui->plugin->config.color = color;
142 gui->send_configure_change();
143 gui->unlock_window();
146 int CriKeyColorPicker::handle_new_color(int color, int alpha)
148 CriKeyWindow *gui = color_button->gui;
149 gui->lock_window("CriKeyColorPicker::handle_new_color");
150 gui->update_color(this->color = color);
152 gui->plugin->config.color = color;
153 gui->send_configure_change();
154 gui->unlock_window();
159 void CriKeyWindow::start_color_thread()
163 color_picker = new CriKeyColorPicker(color_button);
164 color_picker->start(plugin->config.color);
165 lock_window("CriKeyWindow::start_color_thread");
169 CriKeyWindow::CriKeyWindow(CriKey *plugin)
170 : PluginClientWindow(plugin, 380, 360, 380, 360, 0)
172 this->plugin = plugin;
173 this->color_button = 0;
174 this->color_picker = 0;
175 this->title_x = 0; this->point_x = 0;
176 this->title_y = 0; this->point_y = 0;
177 this->new_point = 0; this->del_point = 0;
178 this->point_up = 0; this->point_dn = 0;
179 this->drag = 0; this->dragging = 0;
180 this->last_x = 0; this->last_y = 0;
181 this->points = 0; this->cur_point = 0;
182 this->pending_config = 0;
185 CriKeyWindow::~CriKeyWindow()
191 void CriKeyWindow::create_objects()
194 int margin = plugin->get_theme()->widget_border;
196 add_subwindow(title = new BC_Title(x, y, _("Threshold:")));
197 y += title->get_h() + margin;
198 add_subwindow(threshold = new CriKeyThreshold(this, x, y, get_w() - x * 2));
199 y += threshold->get_h() + margin;
200 add_subwindow(color_button = new CriKeyColorButton(this, x, y));
201 int x1 = x + color_button->get_w() + margin;
202 color_x = x1; color_y = y;
203 update_color(plugin->config.color);
204 y += COLOR_H + 10 + margin ;
205 add_subwindow(title = new BC_Title(x, y+5, _("Draw mode:")));
206 x1 = x + title->get_w() + 10 + margin;
207 add_subwindow(draw_mode = new CriKeyDrawMode(this, x1, y));
208 draw_mode->create_objects();
209 y += draw_mode->get_h() + 10 + margin;
211 CriKeyPoint *pt = plugin->config.points[plugin->config.selected];
212 add_subwindow(title_x = new BC_Title(x, y, _("X:")));
213 x1 = x + title_x->get_w() + margin;
214 point_x = new CriKeyPointX(this, x1, y, pt->x);
215 point_x->create_objects();
216 x1 += point_x->get_w() + margin;
217 add_subwindow(new_point = new CriKeyNewPoint(this, plugin, x1, y));
218 x1 += new_point->get_w() + margin;
219 add_subwindow(point_up = new CriKeyPointUp(this, x1, y));
220 y += point_x->get_h() + margin;
221 add_subwindow(title_y = new BC_Title(x, y, _("Y:")));
222 x1 = x + title_y->get_w() + margin;
223 point_y = new CriKeyPointY(this, x1, y, pt->y);
224 point_y->create_objects();
225 x1 += point_y->get_w() + margin;
226 add_subwindow(del_point = new CriKeyDelPoint(this, plugin, x1, y));
227 x1 += del_point->get_w() + margin;
228 add_subwindow(point_dn = new CriKeyPointDn(this, x1, y));
229 y += point_y->get_h() + margin + 10;
231 add_subwindow(drag = new CriKeyDrag(this, x, y));
232 if( plugin->config.drag ) {
233 if( !grab(plugin->server->mwindow->cwindow->gui) )
234 eprintf("drag enabled, but compositor already grabbed\n");
237 x1 = x + drag->get_w() + margin + 20;
238 add_subwindow(cur_point = new CriKeyCurPoint(this, plugin, x1, y+3));
239 cur_point->update(plugin->config.selected);
240 y += drag->get_h() + margin;
241 add_subwindow(points = new CriKeyPoints(this, plugin, x, y));
242 points->update(plugin->config.selected);
247 void CriKeyWindow::send_configure_change()
250 plugin->send_configure_change();
252 int CriKeyWindow::check_configure_change(int ret)
254 if( pending_config && !grab_event_count() )
255 send_configure_change();
259 int CriKeyWindow::grab_event(XEvent *event)
261 switch( event->type ) {
262 case ButtonPress: break;
263 case ButtonRelease: break;
264 case MotionNotify: break;
266 return check_configure_change(0);
269 MWindow *mwindow = plugin->server->mwindow;
270 CWindowGUI *cwindow_gui = mwindow->cwindow->gui;
271 CWindowCanvas *canvas = cwindow_gui->canvas;
272 int cx, cy; cwindow_gui->get_relative_cursor(cx, cy);
273 cx -= mwindow->theme->ccanvas_x;
274 cy -= mwindow->theme->ccanvas_y;
277 if( cx < 0 || cx >= mwindow->theme->ccanvas_w ||
278 cy < 0 || cy >= mwindow->theme->ccanvas_h )
279 return check_configure_change(0);
282 switch( event->type ) {
284 if( dragging ) return check_configure_change(0);
285 dragging = event->xbutton.state & ShiftMask ? -1 : 1;
288 if( !dragging ) return check_configure_change(0);
292 if( !dragging ) return check_configure_change(0);
295 return check_configure_change(0);
298 float cursor_x = cx, cursor_y = cy;
299 canvas->canvas_to_output(mwindow->edl, 0, cursor_x, cursor_y);
300 int64_t position = plugin->get_source_position();
301 float projector_x, projector_y, projector_z;
302 Track *track = plugin->server->plugin->track;
303 int track_w = track->track_w, track_h = track->track_h;
304 track->automation->get_projector(
305 &projector_x, &projector_y, &projector_z,
306 position, PLAY_FORWARD);
307 projector_x += mwindow->edl->session->output_w / 2;
308 projector_y += mwindow->edl->session->output_h / 2;
309 float output_x = (cursor_x - projector_x) / projector_z + track_w / 2;
310 float output_y = (cursor_y - projector_y) / projector_z + track_h / 2;
311 point_x->update((int64_t)(output_x));
312 point_y->update((int64_t)(output_y));
315 switch( event->type ) {
318 int n = plugin->config.points.size();
320 CriKeyPoint *pt = plugin->config.points[hot_point=0];
321 double dist = DISTANCE(output_x,output_y, pt->x,pt->y);
322 for( int i=1; i<n; ++i ) {
323 pt = plugin->config.points[i];
324 double d = DISTANCE(output_x,output_y, pt->x,pt->y);
325 if( d >= dist ) continue;
326 dist = d; hot_point = i;
329 if( hot_point >= 0 ) {
330 CriKeyPoint *pt = plugin->config.points[hot_point];
331 if( pt->x == output_x && pt->y == output_y ) break;
332 points->set_point(hot_point, PT_X, pt->x = output_x);
333 points->set_point(hot_point, PT_Y, pt->y = output_y);
334 plugin->config.selected = hot_point;
335 points->set_selected(hot_point);
336 points->update_list();
340 int hot_point = points->get_selection_number(0, 0);
341 if( hot_point >= 0 && hot_point < plugin->config.points.size() ) {
342 CriKeyPoint *pt = plugin->config.points[hot_point];
343 if( pt->x == output_x && pt->y == output_y ) break;
344 points->set_point(hot_point, PT_X, pt->x = output_x);
345 points->set_point(hot_point, PT_Y, pt->y = output_y);
346 point_x->update(pt->x);
347 point_y->update(pt->y);
348 points->update_list();
354 switch( event->type ) {
356 float dx = output_x - last_x, dy = output_y - last_y;
357 int n = plugin->config.points.size();
358 for( int i=0; i<n; ++i ) {
359 CriKeyPoint *pt = plugin->config.points[i];
360 points->set_point(i, PT_X, pt->x += dx);
361 points->set_point(i, PT_Y, pt->y += dy);
363 int hot_point = points->get_selection_number(0, 0);
364 if( hot_point >= 0 && hot_point < n ) {
365 CriKeyPoint *pt = plugin->config.points[hot_point];
366 point_x->update(pt->x);
367 point_y->update(pt->y);
368 points->update_list();
374 last_x = output_x; last_y = output_y;
375 if( !grab_event_count() )
376 send_configure_change();
382 void CriKeyWindow::done_event(int result)
384 ungrab(client->server->mwindow->cwindow->gui);
385 if( color_picker ) color_picker->close_window();
388 CriKeyPoints::CriKeyPoints(CriKeyWindow *gui, CriKey *plugin, int x, int y)
389 : BC_ListBox(x, y, 360, 130, LISTBOX_TEXT)
392 this->plugin = plugin;
393 titles[PT_E] = _("E"); widths[PT_E] = 40;
394 titles[PT_X] = _("X"); widths[PT_X] = 120;
395 titles[PT_Y] = _("Y"); widths[PT_Y] = 120;
396 titles[PT_T] = _("Tag"); widths[PT_T] = 60;
398 CriKeyPoints::~CriKeyPoints()
402 void CriKeyPoints::clear()
404 for( int i=PT_SZ; --i>=0; )
405 cols[i].remove_all_objects();
408 int CriKeyPoints::column_resize_event()
410 for( int i=PT_SZ; --i>=0; )
411 widths[i] = get_column_width(i);
415 int CriKeyPoints::handle_event()
417 int hot_point = get_selection_number(0, 0);
418 const char *x_text = "", *y_text = "";
419 if( hot_point >= 0 && hot_point < plugin->config.points.size() ) {
420 if( get_cursor_x() < widths[0] ) {
421 plugin->config.points[hot_point]->e =
422 !plugin->config.points[hot_point]->e;
424 x_text = gui->points->cols[PT_X].get(hot_point)->get_text();
425 y_text = gui->points->cols[PT_Y].get(hot_point)->get_text();
429 gui->point_x->update(x_text);
430 gui->point_y->update(y_text);
431 plugin->config.selected = hot_point;
433 gui->send_configure_change();
437 int CriKeyPoints::selection_changed()
443 void CriKeyPoints::new_point(const char *ep, const char *xp, const char *yp, const char *tp)
445 cols[PT_E].append(new BC_ListBoxItem(ep));
446 cols[PT_X].append(new BC_ListBoxItem(xp));
447 cols[PT_Y].append(new BC_ListBoxItem(yp));
448 cols[PT_T].append(new BC_ListBoxItem(tp));
451 void CriKeyPoints::del_point(int i)
453 for( int n=cols[0].size()-1, c=PT_SZ; --c>=0; )
454 cols[c].remove_object_number(n-i);
457 void CriKeyPoints::set_point(int i, int c, float v)
459 char s[BCSTRLEN]; sprintf(s,"%0.4f",v);
462 void CriKeyPoints::set_point(int i, int c, const char *cp)
464 cols[c].get(i)->set_text(cp);
467 int CriKeyPoints::set_selected(int k)
469 int sz = gui->plugin->config.points.size();
472 int n = gui->points->get_selection_number(0, 0);
474 for( int i=0; i<PT_SZ; ++i )
475 cols[i].get(n)->set_selected(0);
477 for( int i=0; i<PT_SZ; ++i )
478 cols[i].get(k)->set_selected(1);
479 gui->cur_point->update(k);
482 void CriKeyPoints::update_list()
484 int xpos = get_xposition(), ypos = get_xposition();
485 int k = get_selection_number(0, 0);
486 BC_ListBox::update(&cols[0], &titles[0],&widths[0],PT_SZ, xpos,ypos,k);
488 void CriKeyPoints::update(int k)
490 if( k < 0 ) k = get_selection_number(0, 0);
491 gui->cur_point->update(k);
492 int xpos = get_xposition(), ypos = get_xposition();
495 ArrayList<CriKeyPoint*> &points = plugin->config.points;
496 int n = points.size();
497 for( int i=0; i<n; ++i ) {
498 CriKeyPoint *pt = points[i];
499 char etxt[BCSTRLEN]; sprintf(etxt,"%s", pt->e ? "*" : "");
500 char xtxt[BCSTRLEN]; sprintf(xtxt,"%0.4f", pt->x);
501 char ytxt[BCSTRLEN]; sprintf(ytxt,"%0.4f", pt->y);
502 char ttxt[BCSTRLEN]; sprintf(ttxt,"%d", pt->t);
503 new_point(etxt, xtxt, ytxt, ttxt);
506 for( int i=PT_SZ; --i>=0; )
507 cols[i].get(k)->set_selected(1);
508 gui->point_x->update(gui->points->cols[PT_X].get(k)->get_text());
509 gui->point_y->update(gui->points->cols[PT_Y].get(k)->get_text());
512 BC_ListBox::update(&cols[0], &titles[0],&widths[0],PT_SZ, xpos,ypos,k);
515 void CriKeyWindow::update_color(int color)
518 draw_box(color_x, color_y, COLOR_W, COLOR_H);
520 draw_rectangle(color_x, color_y, COLOR_W, COLOR_H);
521 flash(color_x, color_y, COLOR_W, COLOR_H);
524 void CriKeyWindow::update_gui()
526 draw_mode->update(plugin->config.draw_mode);
527 update_color(plugin->config.color);
528 threshold->update(plugin->config.threshold);
529 cur_point->update(plugin->config.selected);
530 drag->update(plugin->config.drag);
531 points->update(plugin->config.selected);
535 CriKeyThreshold::CriKeyThreshold(CriKeyWindow *gui, int x, int y, int w)
536 : BC_FSlider(x, y, 0, w, w, 0, 1, gui->plugin->config.threshold, 0)
539 set_precision(0.005);
542 int CriKeyThreshold::handle_event()
544 float v = get_value();
545 gui->plugin->config.threshold = v;
546 gui->send_configure_change();
551 CriKeyPointUp::CriKeyPointUp(CriKeyWindow *gui, int x, int y)
552 : BC_GenericButton(x, y, _("Up"))
556 CriKeyPointUp::~CriKeyPointUp()
560 int CriKeyPointUp::handle_event()
562 int n = gui->plugin->config.points.size();
563 int hot_point = gui->points->get_selection_number(0, 0);
565 if( n > 1 && hot_point > 0 ) {
566 CriKeyPoint *&pt0 = gui->plugin->config.points[hot_point];
567 CriKeyPoint *&pt1 = gui->plugin->config.points[--hot_point];
568 CriKeyPoint *t = pt0; pt0 = pt1; pt1 = t;
569 gui->plugin->config.selected = hot_point;
570 gui->points->update(hot_point);
572 gui->send_configure_change();
576 CriKeyPointDn::CriKeyPointDn(CriKeyWindow *gui, int x, int y)
577 : BC_GenericButton(x, y, _("Dn"))
581 CriKeyPointDn::~CriKeyPointDn()
585 int CriKeyPointDn::handle_event()
587 int n = gui->plugin->config.points.size();
588 int hot_point = gui->points->get_selection_number(0, 0);
589 if( n > 1 && hot_point < n-1 ) {
590 CriKeyPoint *&pt0 = gui->plugin->config.points[hot_point];
591 CriKeyPoint *&pt1 = gui->plugin->config.points[++hot_point];
592 CriKeyPoint *t = pt0; pt0 = pt1; pt1 = t;
593 gui->plugin->config.selected = hot_point;
594 gui->points->update(hot_point);
596 gui->send_configure_change();
600 CriKeyDrag::CriKeyDrag(CriKeyWindow *gui, int x, int y)
601 : BC_CheckBox(x, y, gui->plugin->config.drag, _("Drag"))
605 int CriKeyDrag::handle_event()
607 CWindowGUI *cwindow_gui = gui->plugin->server->mwindow->cwindow->gui;
608 int value = get_value();
610 if( !gui->grab(cwindow_gui) ) {
616 gui->ungrab(cwindow_gui);
617 gui->plugin->config.drag = value;
618 gui->send_configure_change();
622 CriKeyNewPoint::CriKeyNewPoint(CriKeyWindow *gui, CriKey *plugin, int x, int y)
623 : BC_GenericButton(x, y, 80, _("New"))
626 this->plugin = plugin;
628 CriKeyNewPoint::~CriKeyNewPoint()
631 int CriKeyNewPoint::handle_event()
633 int k = plugin->new_point();
634 gui->points->update(k);
635 gui->send_configure_change();
639 CriKeyDelPoint::CriKeyDelPoint(CriKeyWindow *gui, CriKey *plugin, int x, int y)
640 : BC_GenericButton(x, y, 80, C_("Del"))
643 this->plugin = plugin;
645 CriKeyDelPoint::~CriKeyDelPoint()
648 int CriKeyDelPoint::handle_event()
650 int hot_point = gui->points->get_selection_number(0, 0);
651 if( hot_point >= 0 && hot_point < gui->plugin->config.points.size() ) {
652 plugin->config.del_point(hot_point);
653 if( !plugin->config.points.size() ) plugin->new_point();
654 int n = gui->plugin->config.points.size();
655 if( hot_point >= n && hot_point > 0 ) --hot_point;
656 gui->plugin->config.selected = hot_point;
657 gui->points->update(hot_point);
658 gui->send_configure_change();
663 CriKeyCurPoint::CriKeyCurPoint(CriKeyWindow *gui, CriKey *plugin, int x, int y)
667 this->plugin = plugin;
669 CriKeyCurPoint::~CriKeyCurPoint()
672 void CriKeyCurPoint::update(int n)
674 char string[BCSTRLEN];
675 sprintf(string, _("Selected: %d "), n);
676 BC_Title::update(string);