#include "theme.h"
#include "track.h"
-#define COLOR_W 50
-#define COLOR_H 30
+#define COLOR_W xS(50)
+#define COLOR_H yS(30)
TracerNum::TracerNum(TracerWindow *gui, int x, int y, float output)
- : BC_TumbleTextBox(gui, output, -32767.0f, 32767.0f, x, y, 120)
+ : BC_TumbleTextBox(gui, output, -32767.0f, 32767.0f, x, y, xS(120))
{
this->gui = gui;
set_increment(1);
}
TracerWindow::TracerWindow(Tracer *plugin)
- : PluginClientWindow(plugin, 400, 300, 400, 300, 0)
+ : PluginClientWindow(plugin, xS(460), yS(420), xS(460), yS(420), 0)
{
this->plugin = plugin;
this->title_x = 0; this->point_x = 0;
this->new_point = 0; this->del_point = 0;
this->point_up = 0; this->point_dn = 0;
this->drag = 0; this->draw = 0;
- this->dragging = 0;
+ this->button_no = 0; this->invert = 0;
this->title_r = 0; this->title_s = 0;
- this->radius = 0; this->scale = 0;
+ this->feather = 0; this->radius = 0;
this->last_x = 0; this->last_y = 0;
this->point_list = 0; this->pending_config = 0;
}
void TracerWindow::create_objects()
{
- int x = 10, y = 10;
+ int x = xS(10), y = yS(10);
int margin = plugin->get_theme()->widget_border;
- TracerPoint *pt = plugin->config.points[plugin->config.selected];
+ int hot_point = plugin->selected;
add_subwindow(title_x = new BC_Title(x, y, _("X:")));
int x1 = x + title_x->get_w() + margin;
- point_x = new TracerPointX(this, x1, y, pt->x);
+ TracerPoints &points = plugin->config.points;
+ TracerPoint *pt = hot_point >= 0 && hot_point<points.size() ?
+ points[hot_point] : 0;
+ point_x = new TracerPointX(this, x1, y, !pt ? 0 : pt->x);
point_x->create_objects();
- x1 += point_x->get_w() + margin;
+ x1 += point_x->get_w() + margin + xS(20);
add_subwindow(new_point = new TracerNewPoint(this, plugin, x1, y));
- x1 += new_point->get_w() + margin;
+ x1 += new_point->get_w() + margin + xS(30);
add_subwindow(point_up = new TracerPointUp(this, x1, y));
y += point_x->get_h() + margin;
add_subwindow(title_y = new BC_Title(x, y, _("Y:")));
x1 = x + title_y->get_w() + margin;
- point_y = new TracerPointY(this, x1, y, pt->y);
+ point_y = new TracerPointY(this, x1, y, !pt ? 0 : pt->y);
point_y->create_objects();
- x1 += point_y->get_w() + margin;
+ x1 += point_y->get_w() + margin + xS(20);
add_subwindow(del_point = new TracerDelPoint(this, plugin, x1, y));
- x1 += del_point->get_w() + margin;
+ x1 += del_point->get_w() + margin + xS(30);
add_subwindow(point_dn = new TracerPointDn(this, x1, y));
- y += point_y->get_h() + margin + 10;
+ y += point_y->get_h() + margin + yS(10);
add_subwindow(drag = new TracerDrag(this, x, y));
- if( plugin->config.drag ) {
+ if( plugin->drag ) {
if( !grab(plugin->server->mwindow->cwindow->gui) )
eprintf("drag enabled, but compositor already grabbed\n");
}
- x1 = x + drag->get_w() + margin + 20;
+ x1 = x + drag->get_w() + margin + xS(20);
add_subwindow(draw = new TracerDraw(this, x1, y));
- x1 += draw->get_w() + margin + 20;
+ x1 += draw->get_w() + margin + xS(20);
add_subwindow(fill = new TracerFill(this, x1, y));
- x1 += drag->get_w() + margin + 20;
- add_subwindow(reset = new TracerReset(this, plugin, x1, y+3));
- y += drag->get_h() + margin;
-
- add_subwindow(title_r = new BC_Title(x1=x, y, _("Radius:")));
- x1 += title_r->get_w() + margin;
- add_subwindow(radius = new TracerRadius(this, x1, y, 100));
- x1 += radius->get_w() + margin + 20;
- add_subwindow(title_s = new BC_Title(x1, y, _("Scale:")));
- x1 += title_s->get_w() + margin;
- add_subwindow(scale = new TracerScale(this, x1, y, 100));
- y += radius->get_h() + margin + 20;
+ x1 += drag->get_w() + margin + xS(20);
+ int y1 = y + yS(3);
+ add_subwindow(reset = new TracerReset(this, plugin, x1, y1));
+ y1 += reset->get_h() + margin;
+ add_subwindow(invert = new TracerInvert(this, plugin, x1, y1));
+ y += drag->get_h() + margin + yS(15);
+
+ x1 = x + xS(80);
+ add_subwindow(title_r = new BC_Title(x, y, _("Feather:")));
+ add_subwindow(feather = new TracerFeather(this, x1, y, xS(150)));
+ y += feather->get_h() + margin;
+ add_subwindow(title_s = new BC_Title(x, y, _("Radius:")));
+ add_subwindow(radius = new TracerRadius(this, x1, y, xS(150)));
+ y += radius->get_h() + margin + yS(5);
add_subwindow(point_list = new TracerPointList(this, plugin, x, y));
- point_list->update(plugin->config.selected);
-// y += point_list->get_h() + 10;
-
+ point_list->update(plugin->selected);
+ y += point_list->get_h() + yS(10);
+
+ add_subwindow(new BC_Title(x, y, _(
+ "Btn1: select/drag point\n"
+ "Btn2: drag all points\n"
+ "Btn3: add point on nearest line\n"
+ "Btn3: shift: append point to end\n"
+ "Wheel: rotate, centered on cursor\n"
+ "Wheel: shift: scale, centered on cursor\n")));
show_window(1);
}
MWindow *mwindow = plugin->server->mwindow;
CWindowGUI *cwindow_gui = mwindow->cwindow->gui;
CWindowCanvas *canvas = cwindow_gui->canvas;
- int cx, cy; cwindow_gui->get_relative_cursor(cx, cy);
- cx -= canvas->view_x;
- cy -= canvas->view_y;
-
- if( !dragging ) {
- if( cx < 0 || cx >= canvas->view_w ||
- cy < 0 || cy >= canvas->view_h )
+ int cursor_x, cursor_y;
+ cwindow_gui->get_relative_cursor(cursor_x, cursor_y);
+ cursor_x -= canvas->view_x;
+ cursor_y -= canvas->view_y;
+
+ if( !button_no ) {
+ if( cursor_x < 0 || cursor_x >= canvas->view_w ||
+ cursor_y < 0 || cursor_y >= canvas->view_h )
return 0;
}
switch( event->type ) {
case ButtonPress:
- if( dragging ) return 0;
- dragging = event->xbutton.state & ShiftMask ? -1 : 1;
+ if( button_no ) return 0;
+ button_no = event->xbutton.button;
break;
case ButtonRelease:
- if( !dragging ) return 0;
- dragging = 0;
+ if( !button_no ) return 0;
+ button_no = 0;
return 1;
case MotionNotify:
- if( !dragging ) return 0;
+ if( !button_no ) return 0;
break;
default:
return 0;
}
- float cursor_x = cx, cursor_y = cy;
- canvas->canvas_to_output(mwindow->edl, 0, cursor_x, cursor_y);
- int64_t position = plugin->get_source_position();
- float projector_x, projector_y, projector_z;
- Track *track = plugin->server->plugin->track;
- int track_w = track->track_w, track_h = track->track_h;
- track->automation->get_projector(
- &projector_x, &projector_y, &projector_z,
- position, PLAY_FORWARD);
- projector_x += mwindow->edl->session->output_w / 2;
- projector_y += mwindow->edl->session->output_h / 2;
- float output_x = (cursor_x - projector_x) / projector_z + track_w / 2;
- float output_y = (cursor_y - projector_y) / projector_z + track_h / 2;
- point_x->update((int64_t)(output_x));
- point_y->update((int64_t)(output_y));
+ float output_x = cursor_x, output_y = cursor_y, track_x, track_y;
+ canvas->canvas_to_output(mwindow->edl, 0, output_x, output_y);
+ plugin->output_to_track(output_x, output_y, track_x, track_y);
+ point_x->update((int64_t)track_x);
+ point_y->update((int64_t)track_y);
TracerPoints &points = plugin->config.points;
- if( dragging > 0 ) {
- switch( event->type ) {
- case ButtonPress: {
- int button_no = event->xbutton.button;
- int hot_point = -1;
- if( button_no == RIGHT_BUTTON ) {
- hot_point = plugin->new_point();
- TracerPoint *pt = points[hot_point];
- pt->x = output_x; pt->y = output_y;
- point_list->update(hot_point);
- break;
- }
+ switch( event->type ) {
+ case ButtonPress: {
+ float s = 1.02;
+ float th = M_PI/360.f; // .5 deg per wheel_btn
+ int shift_down = event->xbutton.state & ShiftMask;
+ switch( button_no ) {
+ case WHEEL_DOWN:
+ s = 0.98;
+ th = -th; // fall thru
+ case WHEEL_UP: {
+ // shift_down scale, !shift_down rotate
+ float st = sin(th), ct = cos(th);
int sz = points.size();
- if( hot_point < 0 && sz > 0 ) {
+ for( int i=0; i<sz; ++i ) {
+ TracerPoint *pt = points[i];
+ float px = pt->x - track_x, py = pt->y - track_y;
+ float nx = shift_down ? px*s : px*ct + py*st;
+ float ny = shift_down ? py*s : py*ct - px*st;
+ point_list->set_point(i, PT_X, pt->x = nx + track_x);
+ point_list->set_point(i, PT_Y, pt->y = ny + track_y);
+ }
+ point_list->update(-1);
+ button_no = 0;
+ break; }
+ case RIGHT_BUTTON: {
+ // shift_down adds to end
+ int sz = !shift_down ? points.size() : 0;
+ int k = !shift_down ? -1 : points.size()-1;
+ float mx = FLT_MAX;
+ for( int i=0; i<sz; ++i ) {
+ // pt on line pt[i+0]..pt[i+1] nearest cursor_x,cursor_y
+ TracerPoint *pt0 = points[i+0];
+ TracerPoint *pt1 = i+1<sz ? points[i+1] : points[0];
+ float x0 = pt0->x, y0 = pt0->y;
+ float x1 = pt1->x, y1 = pt1->y;
+ float dx = x1-x0, dy = y1-y0;
+ float rr = dx*dx + dy*dy;
+ if( !rr ) continue;
+ float u = ((x1-track_x)*dx + (y1-track_y)*dy) / rr;
+ if( u < 0 || u > 1 ) continue; // past endpts
+ float x = x0*u + x1*(1-u);
+ float y = y0*u + y1*(1-u);
+ dx = track_x-x; dy = track_y-y;
+ float dd = dx*dx + dy*dy; // d**2 closest approach
+ if( mx > dd ) { mx = dd; k = i; }
+ }
+ TracerPoint *pt = points[sz=plugin->new_point()];
+ int hot_point = k+1;
+ for( int i=sz; i>hot_point; --i ) points[i] = points[i-1];
+ points[hot_point] = pt;
+ pt->x = track_x; pt->y = track_y;
+ point_list->update(hot_point);
+ break; }
+ case LEFT_BUTTON: {
+ int hot_point = -1, sz = points.size();
+ if( sz > 0 ) {
TracerPoint *pt = points[hot_point=0];
- double dist = DISTANCE(output_x,output_y, pt->x,pt->y);
+ double dist = DISTANCE(track_x,track_y, pt->x,pt->y);
for( int i=1; i<sz; ++i ) {
pt = points[i];
- double d = DISTANCE(output_x,output_y, pt->x,pt->y);
+ double d = DISTANCE(track_x,track_y, pt->x,pt->y);
if( d >= dist ) continue;
dist = d; hot_point = i;
}
pt = points[hot_point];
- float px = (pt->x - track_w / 2) * projector_z + projector_x;
- float py = (pt->y - track_h / 2) * projector_z + projector_y;
- dist = DISTANCE(px, py, cursor_x,cursor_y);
+ float cx, cy;
+ plugin->track_to_output(pt->x, pt->y, cx, cy);
+ canvas->output_to_canvas(mwindow->edl, 0, cx, cy);
+ dist = DISTANCE(cursor_x, cursor_y, cx,cy);
if( dist >= HANDLE_W ) hot_point = -1;
}
if( hot_point >= 0 && sz > 0 ) {
TracerPoint *pt = points[hot_point];
- point_list->set_point(hot_point, PT_X, pt->x = output_x);
- point_list->set_point(hot_point, PT_Y, pt->y = output_y);
+ point_list->set_point(hot_point, PT_X, pt->x = track_x);
+ point_list->set_point(hot_point, PT_Y, pt->y = track_y);
point_list->update_list(hot_point);
}
break; }
- case MotionNotify: {
+ }
+ break; }
+ case MotionNotify: {
+ switch( button_no ) {
+ case LEFT_BUTTON: {
int hot_point = point_list->get_selection_number(0, 0);
if( hot_point >= 0 && hot_point < points.size() ) {
TracerPoint *pt = points[hot_point];
- if( pt->x == output_x && pt->y == output_y ) break;
- point_list->set_point(hot_point, PT_X, pt->x = output_x);
- point_list->set_point(hot_point, PT_Y, pt->y = output_y);
+ if( pt->x == track_x && pt->y == track_y ) break;
+ point_list->set_point(hot_point, PT_X, pt->x = track_x);
+ point_list->set_point(hot_point, PT_Y, pt->y = track_y);
point_x->update(pt->x);
point_y->update(pt->y);
point_list->update_list(hot_point);
}
break; }
- }
- }
- else {
- switch( event->type ) {
- case MotionNotify: {
- float dx = output_x - last_x, dy = output_y - last_y;
+ case MIDDLE_BUTTON: {
+ float dx = track_x - last_x, dy = track_y - last_y;
int sz = points.size();
for( int i=0; i<sz; ++i ) {
TracerPoint *pt = points[i];
}
break; }
}
+ break; }
}
- last_x = output_x; last_y = output_y;
+ last_x = track_x; last_y = track_y;
pending_config = 1;
return 1;
}
}
TracerPointList::TracerPointList(TracerWindow *gui, Tracer *plugin, int x, int y)
- : BC_ListBox(x, y, 360, 130, LISTBOX_TEXT)
+ : BC_ListBox(x, y, xS(360), yS(130), LISTBOX_TEXT)
{
this->gui = gui;
this->plugin = plugin;
- titles[PT_X] = _("X"); widths[PT_X] = 90;
- titles[PT_Y] = _("Y"); widths[PT_Y] = 90;
+ titles[PT_X] = _("X"); widths[PT_X] = xS(90);
+ titles[PT_Y] = _("Y"); widths[PT_Y] = yS(90);
}
TracerPointList::~TracerPointList()
{
}
void TracerPointList::update_list(int k)
{
- int xpos = get_xposition(), ypos = get_yposition();
- if( k < 0 ) k = get_selection_number(0, 0);
+ int sz = plugin->config.points.size();
+ if( k < 0 || k >= sz ) k = -1;
+ plugin->selected = k;
update_selection(&cols[0], k);
+ int xpos = get_xposition(), ypos = get_yposition();
BC_ListBox::update(&cols[0], &titles[0],&widths[0],PT_SZ, xpos,ypos,k);
center_selection();
}
if( k >= 0 && k < sz ) {
gui->point_x->update(gui->point_list->cols[PT_X].get(k)->get_text());
gui->point_y->update(gui->point_list->cols[PT_Y].get(k)->get_text());
- plugin->config.selected = k;
}
-
update_list(k);
}
void TracerWindow::update_gui()
{
TracerConfig &config = plugin->config;
- drag->update(config.drag);
+ drag->update(plugin->drag);
draw->update(config.draw);
fill->update(config.fill);
+ feather->update(config.feather);
radius->update(config.radius);
- scale->update(config.scale);
- drag->update(config.drag);
+ invert->update(config.invert);
point_list->update(-1);
}
}
TracerDrag::TracerDrag(TracerWindow *gui, int x, int y)
- : BC_CheckBox(x, y, gui->plugin->config.drag, _("Drag"))
+ : BC_CheckBox(x, y, gui->plugin->drag, _("Drag"))
{
this->gui = gui;
}
}
else
gui->ungrab(cwindow_gui);
- gui->plugin->config.drag = value;
+ gui->plugin->drag = value;
gui->send_configure_change();
return 1;
}
+int TracerWindow::handle_ungrab()
+{
+ CWindowGUI *cwindow_gui = plugin->server->mwindow->cwindow->gui;
+ int ret = ungrab(cwindow_gui);
+ if( ret ) {
+ drag->update(0);
+ plugin->drag = 0;
+ }
+ return ret;
+}
+
TracerDraw::TracerDraw(TracerWindow *gui, int x, int y)
: BC_CheckBox(x, y, gui->plugin->config.draw, _("Draw"))
return 1;
}
-TracerRadius::TracerRadius(TracerWindow *gui, int x, int y, int w)
- : BC_ISlider(x,y,0,w,w, -50,50, gui->plugin->config.radius)
+TracerFeather::TracerFeather(TracerWindow *gui, int x, int y, int w)
+ : BC_ISlider(x,y,0,w,w, -50,50, gui->plugin->config.feather)
{
this->gui = gui;
}
-int TracerRadius::handle_event()
+int TracerFeather::handle_event()
{
- gui->plugin->config.radius = get_value();
+ gui->plugin->config.feather = get_value();
gui->send_configure_change();
return 1;
}
-TracerScale::TracerScale(TracerWindow *gui, int x, int y, int w)
- : BC_FSlider(x,y, 0,w,w, 1.f,10.f, gui->plugin->config.scale)
+TracerRadius::TracerRadius(TracerWindow *gui, int x, int y, int w)
+ : BC_FSlider(x,y, 0,w,w, -5.f,5.f, gui->plugin->config.radius)
{
this->gui = gui;
}
-int TracerScale::handle_event()
+int TracerRadius::handle_event()
{
- gui->plugin->config.scale = get_value();
+ gui->plugin->config.radius = get_value();
gui->send_configure_change();
return 1;
}
TracerNewPoint::TracerNewPoint(TracerWindow *gui, Tracer *plugin, int x, int y)
- : BC_GenericButton(x, y, 80, _("New"))
+ : BC_GenericButton(x, y, xS(100), _("New"))
{
this->gui = gui;
this->plugin = plugin;
}
TracerDelPoint::TracerDelPoint(TracerWindow *gui, Tracer *plugin, int x, int y)
- : BC_GenericButton(x, y, 80, C_("Del"))
+ : BC_GenericButton(x, y, xS(100), C_("Del"))
{
this->gui = gui;
this->plugin = plugin;
TracerPoints &points = plugin->config.points;
if( hot_point >= 0 && hot_point < points.size() ) {
plugin->config.del_point(hot_point);
- if( !points.size() ) plugin->new_point();
- int sz = points.size();
- if( hot_point >= sz && hot_point > 0 ) --hot_point;
- gui->point_list->update(hot_point);
+ gui->point_list->update(--hot_point);
gui->send_configure_change();
}
return 1;
int TracerReset::handle_event()
{
TracerConfig &config = plugin->config;
- config.drag = 0;
- config.draw = 0;
+ if( !plugin->drag ) {
+ MWindow *mwindow = plugin->server->mwindow;
+ CWindowGUI *cwindow_gui = mwindow->cwindow->gui;
+ if( gui->grab(cwindow_gui) )
+ plugin->drag = 1;
+ else
+ gui->drag->flicker(10,50);
+ }
+ config.draw = 1;
config.fill = 0;
- config.radius = 0;
- config.scale = 1;
- config.selected = 0;
+ config.invert = 0;
+ config.feather = 0;
+ config.radius = 1;
+ plugin->selected = -1;
TracerPoints &points = plugin->config.points;
points.remove_all_objects();
- plugin->new_point();
- gui->point_list->update(0);
+ gui->point_list->update(-1);
gui->update_gui();
gui->send_configure_change();
return 1;
}
+TracerInvert::TracerInvert(TracerWindow *gui, Tracer *plugin, int x, int y)
+ : BC_CheckBox(x, y, gui->plugin->config.invert, _("Invert"))
+{
+ this->gui = gui;
+ this->plugin = plugin;
+}
+TracerInvert::~TracerInvert()
+{
+}
+int TracerInvert::handle_event()
+{
+ plugin->config.invert = get_value();
+ gui->send_configure_change();
+ return 1;
+}
+