add dragcheckbox, fix transition plugin title, sams opencv icons, drop libipp in...
[goodguy/history.git] / cinelerra-5.1 / plugins / titler / titlerwindow.C
index c816d607954de7140e4fd817f1b2c96dddfc49de..1fc0a1e5bf230efe3e7af444a6a51b95a6d8614b 100644 (file)
@@ -28,6 +28,7 @@
 #include "automation.h"
 #include "cwindow.h"
 #include "cwindowgui.h"
+#include "dragcheckbox.h"
 #include "edl.h"
 #include "edlsession.h"
 #include "keys.h"
@@ -115,11 +116,12 @@ TitleWindow::TitleWindow(TitleMain *client)
        background = 0;
        background_path = 0;
        loop_playback = 0;
+       pending_config = 0;
 }
 
 void TitleWindow::done_event(int result)
 {
-       ungrab(client->server->mwindow->cwindow->gui);
+       drag->drag_deactivate();
        color_thread->close_window();
        outline_color_thread->close_window();
        color_popup->close_window();
@@ -259,14 +261,18 @@ void TitleWindow::create_objects()
        if( bold->get_w() > w1 ) w1 = bold->get_w();
 
        add_tool(drag = new TitleDrag(client, this, x, y + 80));
+       drag->create_objects();
        if( drag->get_w() > w1 ) w1 = drag->get_w();
        if( client->config.drag ) {
-               if( !grab(client->server->mwindow->cwindow->gui) )
+               if( drag->drag_activate() )
                        eprintf("drag enabled, but compositor already grabbed\n");
        }
 
+       add_tool(alias = new TitleAlias(client, this, x, y+110));
+       if( alias->get_w() > w1 ) w1 = drag->get_w();
+
        x += w1 + margin;
-       add_tool(justify_title = new BC_Title(x, y, _("Justify:")));
+       add_tool(justify_title = new BC_Title(x+50, y, _("Justify:")));
        add_tool(left = new TitleLeft(client, this, x, y + 20));
        w1 = left->get_w();
        add_tool(center = new TitleCenter(client, this, x, y + 50));
@@ -314,7 +320,7 @@ void TitleWindow::create_objects()
        x1 += motion_title->get_w()+margin;
        motion = new TitleMotion(client, this, x1, y);
        motion->create_objects();
-       add_tool(loop = new TitleLoop(client, x, y1));
+       add_tool(loop = new TitleLoop(client, this, x, y1));
        x = margin;    y = y1 + loop->get_h()+20;
 
        add_tool(dropshadow_title = new BC_Title(x, y, _("Drop shadow:")));
@@ -336,9 +342,9 @@ void TitleWindow::create_objects()
        if( fade_out->get_w() > w1 ) w1 = fade_out->get_w();
        x += w1 + margin;
 
-       add_tool(speed_title = new BC_Title(x, y1=y, _("Speed:")));
+       add_tool(speed_title = new BC_Title(x, y, _("Speed:")));
        w1 = speed_title->get_w();
-       y += speed_title->get_h() + 5;
+       y += speed_title->get_h() + 5;  y1 = y;
        speed = new TitleSpeed(client, this, x, y);
        speed->create_objects();
        if( speed->get_w() > w1 ) w1 = speed->get_w();
@@ -369,9 +375,9 @@ void TitleWindow::create_objects()
        x += stroker->get_w() + margin;
 #endif
        y += outline_title->get_h() + margin;
-       add_tool(timecode = new TitleTimecode(client, x1=x, y));
+       add_tool(timecode = new TitleTimecode(client, this, x1=x, y));
        x += timecode->get_w() + margin;
-       add_tool(timecode_format = new TitleTimecodeFormat(client, x, y,
+       add_tool(timecode_format = new TitleTimecodeFormat(client, this, x, y,
                Units::print_time_format(client->config.timecode_format, string)));
        timecode_format->create_objects();
        y += timecode_format->get_h() + margin;
@@ -385,7 +391,7 @@ void TitleWindow::create_objects()
                client->server->mwindow->theme, this, background_path,
                x, y, "", _("background media"), _("Select background media path")));
        x += background_browse->get_w() + 3*margin;
-       add_tool(loop_playback = new TitleLoopPlayback(client, x, y));
+       add_tool(loop_playback = new TitleLoopPlayback(client, this, x, y));
        y += loop_playback->get_h() + 10;
 
        x = 10;
@@ -432,6 +438,7 @@ int TitleWindow::resize_event(int w, int h)
        italic->reposition_window(italic->get_x(), italic->get_y());
        bold->reposition_window(bold->get_x(), bold->get_y());
        drag->reposition_window(drag->get_x(), drag->get_y());
+       alias->reposition_window(alias->get_x(), alias->get_y());
        size_title->reposition_window(size_title->get_x(), size_title->get_y());
        size->reposition_window(size->get_x(), size->get_y());
        size_tumbler->reposition_window(size_tumbler->get_x(), size_tumbler->get_y());
@@ -468,158 +475,17 @@ int TitleWindow::resize_event(int w, int h)
        return 1;
 }
 
-int TitleWindow::grab_event(XEvent *event)
+void TitleWindow::update_drag()
+{
+       drag->drag_x = client->config.title_x;
+       drag->drag_y = client->config.title_y;
+       drag->drag_w = client->config.title_w;
+       drag->drag_h = client->config.title_h;
+       send_configure_change();
+}
+void TitleWindow::send_configure_change()
 {
-       switch( event->type ) {
-       case ButtonPress: break;
-       case ButtonRelease: break;
-       case MotionNotify: break;
-       default: return 0;
-       }
-
-       MWindow *mwindow = client->server->mwindow;
-       CWindowGUI *cwindow_gui = mwindow->cwindow->gui;
-       CWindowCanvas *canvas = cwindow_gui->canvas;
-       int cx, cy;  cwindow_gui->get_relative_cursor(cx, cy);
-       cx -= mwindow->theme->ccanvas_x;
-       cy -= mwindow->theme->ccanvas_y;
-
-       if( !dragging ) {
-               if( cx < 0 || cx >= mwindow->theme->ccanvas_w ) return 0;
-               if( cy < 0 || cy >= mwindow->theme->ccanvas_h ) return 0;
-       }
-
-       switch( event->type ) {
-       case ButtonPress:
-               if( !dragging ) break;
-               return 1;
-       case ButtonRelease:
-               if( !dragging ) return 0;
-               dragging = 0;
-               return 1;
-       case MotionNotify:
-               if( !dragging ) 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 = client->get_source_position();
-       float projector_x, projector_y, projector_z;
-       Track *track = client->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;
-       cursor_x = (cursor_x - projector_x) / projector_z + track_w / 2;
-       cursor_y = (cursor_y - projector_y) / projector_z + track_h / 2;
-       int title_x = client->config.title_x, title_y = client->config.title_y;
-       int title_w = client->config.title_w, title_h = client->config.title_h;
-       if( !title_w ) title_w = track_w;
-       if( !title_h ) title_h = track_h;
-       int r = MIN(track_w, track_h)/100 + 2;
-       int x0 = title_x, x1 = title_x+(title_w+1)/2, x2 = title_x+title_w;
-       int y0 = title_y, y1 = title_y+(title_h+1)/2, y2 = title_y+title_h;
-       int drag_dx = 0, drag_dy = 0;
-       if( !dragging ) {  // clockwise
-                    if( abs(drag_dx = cursor_x-x0) < r &&  // x0,y0
-                        abs(drag_dy = cursor_y-y0) < r ) dragging = 1;
-               else if( abs(drag_dx = cursor_x-x1) < r &&  // x1,y0
-                        abs(drag_dy = cursor_y-y0) < r ) dragging = 2;
-               else if( abs(drag_dx = cursor_x-x2) < r &&  // x2,y0
-                        abs(drag_dy = cursor_y-y0) < r ) dragging = 3;
-               else if( abs(drag_dx = cursor_x-x2) < r &&  // x2,y1
-                        abs(drag_dy = cursor_y-y1) < r ) dragging = 4;
-               else if( abs(drag_dx = cursor_x-x2) < r &&  // x2,y2
-                        abs(drag_dy = cursor_y-y2) < r ) dragging = 5;
-               else if( abs(drag_dx = cursor_x-x1) < r &&  // x1,y2
-                        abs(drag_dy = cursor_y-y2) < r ) dragging = 6;
-               else if( abs(drag_dx = cursor_x-x0) < r &&  // x0,y2
-                        abs(drag_dy = cursor_y-y2) < r ) dragging = 7;
-               else if( abs(drag_dx = cursor_x-x0) < r &&  // x0,y1
-                        abs(drag_dy = cursor_y-y1) < r ) dragging = 8;
-               else if( abs(drag_dx = cursor_x-x1) < r &&  // x1,y1
-                        abs(drag_dy = cursor_y-y1) < r ) dragging = 9;
-                       return 0;
-       }
-       switch( dragging ) {
-       case 1: { // x0,y0
-               int cur_x = cursor_x - drag_dx, dx = cur_x - x0;
-               int cur_y = cursor_y - drag_dy, dy = cur_y - y0;
-               if( !dx && !dy ) return 1;
-               int cur_w = title_w - dx;  if( cur_w < 1 ) cur_w = 1;
-               int cur_h = title_h - dy;  if( cur_h < 1 ) cur_h = 1;
-               this->title_x->update((int64_t)(client->config.title_x = cur_x));
-               this->title_y->update((int64_t)(client->config.title_y = cur_y));
-               this->title_w->update((int64_t)(client->config.title_w = cur_w));
-               this->title_h->update((int64_t)(client->config.title_h = cur_h));
-               break; }
-       case 2: { // x1,y0
-               int cur_y = cursor_y - drag_dy, dy = cur_y - y0;
-               if( !dy ) return 1;
-               int cur_h = title_h - dy;  if( cur_h < 1 ) cur_h = 1;
-               this->title_y->update((int64_t)(client->config.title_y = cur_y));
-               this->title_h->update((int64_t)(client->config.title_h = cur_h));
-               break; }
-       case 3: { // x2,y0
-               int cur_x = cursor_x - drag_dx, dx = cur_x - x2;
-               int cur_y = cursor_y - drag_dy, dy = cur_y - y0;
-               int cur_w = title_w + dx;  if( cur_w < 1 ) cur_w = 1;
-               int cur_h = title_h - dy;  if( cur_h < 1 ) cur_h = 1;
-               this->title_w->update((int64_t)(client->config.title_w = cur_w));
-               this->title_y->update((int64_t)(client->config.title_y = cur_y));
-               this->title_h->update((int64_t)(client->config.title_h = cur_h));
-               break; }
-       case 4: { // x2,y1
-               int cur_x = cursor_x - drag_dx, dx = cur_x - x2;
-               if( !dx ) return 1;
-               int cur_w = title_w + dx;  if( cur_w < 1 ) cur_w = 1;
-               this->title_w->update((int64_t)(client->config.title_w = cur_w));
-               break; }
-       case 5: { // x2,y2
-               int cur_x = cursor_x - drag_dx, dx = cur_x - x2;
-               int cur_y = cursor_y - drag_dy, dy = cur_y - y2;
-               int cur_w = title_w + dx;  if( cur_w < 1 ) cur_w = 1;
-               int cur_h = title_h + dy;  if( cur_h < 1 ) cur_h = 1;
-               this->title_w->update((int64_t)(client->config.title_w = cur_w));
-               this->title_h->update((int64_t)(client->config.title_h = cur_h));
-               break; }
-       case 6: { // x1,y2
-               int cur_y = cursor_y - drag_dy, dy = cur_y - y2;
-               if( client->config.title_h == cur_y ) return 1;
-               int cur_h = title_h + dy;  if( cur_h < 1 ) cur_h = 1;
-               this->title_h->update((int64_t)(client->config.title_h = cur_h));
-               break; }
-       case 7: { // x0,y2
-               int cur_x = cursor_x - drag_dx, dx = cur_x - x0;
-               int cur_y = cursor_y - drag_dy, dy = cur_y - y2;
-               int cur_w = title_w - dx;  if( cur_w < 1 ) cur_w = 1;
-               int cur_h = title_h + dy;  if( cur_h < 1 ) cur_h = 1;
-               this->title_x->update((int64_t)(client->config.title_x = cur_x));
-               this->title_w->update((int64_t)(client->config.title_w = cur_w));
-               this->title_h->update((int64_t)(client->config.title_h = cur_h));
-               break; }
-       case 8: { // x0,y1
-               int cur_x = cursor_x - drag_dx, dx = cur_x - x0;
-               if( !dx ) return 1;
-               int cur_w = title_w - dx;  if( cur_w < 1 ) cur_w = 1;
-               this->title_x->update((int64_t)(client->config.title_x = cur_x));
-               this->title_w->update((int64_t)(client->config.title_w = cur_w));
-               break; }
-       case 9: { // x1,y1
-               int cur_x = cursor_x - drag_dx, dx = cur_x - x1;
-               int cur_y = cursor_y - drag_dy, dy = cur_y - y1;
-               if( title_x == cur_x && title_y == cur_y ) return 1;
-               this->title_x->update((int64_t)(client->config.title_x += dx));
-               this->title_y->update((int64_t)(client->config.title_y += dy));
-               }
-       }
        client->send_configure_change();
-       return 1;
 }
 
 void TitleWindow::previous_font()
@@ -637,7 +503,7 @@ void TitleWindow::previous_font()
        font->update(fonts.values[current_font]->get_text());
        strcpy(client->config.font, fonts.values[current_font]->get_text());
        check_style(client->config.font,1);
-       client->send_configure_change();
+       send_configure_change();
 }
 
 void  TitleWindow::next_font()
@@ -655,7 +521,7 @@ void  TitleWindow::next_font()
        font->update(fonts.values[current_font]->get_text());
        strcpy(client->config.font, fonts.values[current_font]->get_text());
        check_style(client->config.font,1);
-       client->send_configure_change();
+       send_configure_change();
 }
 
 int TitleWindow::insert_ibeam(const char *txt, int ofs)
@@ -672,7 +538,7 @@ int TitleWindow::insert_ibeam(const char *txt, int ofs)
                ibeam = client->config.wlen;
        text->wset_selection(-1, -1, ibeam);
        text->update(client->config.wtext);
-       client->send_configure_change();
+       send_configure_change();
        return 1;
 }
 
@@ -716,6 +582,7 @@ void TitleWindow::update()
        title_h->update((int64_t)client->config.title_h);
        italic->update(client->config.style & BC_FONT_ITALIC);
        bold->update(client->config.style & BC_FONT_BOLD);
+       alias->update(client->config.style & FONT_ALIAS);
        size->update(client->config.size);
        motion->update(TitleMain::motion_to_text(client->config.motion_strategy));
        loop->update(client->config.loop);
@@ -769,7 +636,6 @@ int TitleFontTumble::handle_down_event()
 }
 
 
-
 TitleSizeTumble::TitleSizeTumble(TitleMain *client, TitleWindow *window, int x, int y)
  : BC_Tumbler(x, y)
 {
@@ -796,7 +662,7 @@ int TitleSizeTumble::handle_up_event()
 
        client->config.size = atoi(window->sizes.get(current_index)->get_text());
        window->size->update(client->config.size);
-       client->send_configure_change();
+       window->send_configure_change();
        return 1;
 }
 
@@ -819,7 +685,23 @@ int TitleSizeTumble::handle_down_event()
 
        client->config.size = atoi(window->sizes.get(current_index)->get_text());
        window->size->update(client->config.size);
-       client->send_configure_change();
+       window->send_configure_change();
+       return 1;
+}
+
+TitleAlias::TitleAlias(TitleMain *client, TitleWindow *window, int x, int y)
+ : BC_CheckBox(x, y, client->config.style & FONT_ALIAS, _("Smooth"))
+{
+       this->client = client;
+       this->window = window;
+}
+
+int TitleAlias::handle_event()
+{
+       client->config.style =
+               (client->config.style & ~FONT_ALIAS) |
+                       (get_value() ? FONT_ALIAS : 0);
+       window->send_configure_change();
        return 1;
 }
 
@@ -835,7 +717,7 @@ int TitleBold::handle_event()
        client->config.style =
                (client->config.style & ~BC_FONT_BOLD) |
                        (get_value() ? BC_FONT_BOLD : 0);
-       client->send_configure_change();
+       window->send_configure_change();
        return 1;
 }
 
@@ -850,7 +732,7 @@ int TitleItalic::handle_event()
        client->config.style =
                (client->config.style & ~BC_FONT_ITALIC) |
                        (get_value() ? BC_FONT_ITALIC : 0);
-       client->send_configure_change();
+       window->send_configure_change();
        return 1;
 }
 
@@ -869,7 +751,7 @@ int TitleSize::handle_event()
 {
        client->config.size = atol(get_text());
 //printf("TitleSize::handle_event 1 %s\n", get_text());
-       client->send_configure_change();
+       window->send_configure_change();
        return 1;
 }
 void TitleSize::update(int size)
@@ -896,7 +778,7 @@ TitlePitch::
 int TitlePitch::handle_event()
 {
        *value = atol(get_text());
-       client->send_configure_change();
+       window->send_configure_change();
        return 1;
 }
 
@@ -937,25 +819,27 @@ TitleMotion::TitleMotion(TitleMain *client, TitleWindow *window, int x, int y)
 int TitleMotion::handle_event()
 {
        client->config.motion_strategy = client->text_to_motion(get_text());
-       client->send_configure_change();
+       window->send_configure_change();
        return 1;
 }
 
-TitleLoop::TitleLoop(TitleMain *client, int x, int y)
+TitleLoop::TitleLoop(TitleMain *client, TitleWindow *window, int x, int y)
  : BC_CheckBox(x, y, client->config.loop, _("Loop"))
 {
        this->client = client;
+       this->window = window;
 }
 int TitleLoop::handle_event()
 {
        client->config.loop = get_value();
-       client->send_configure_change();
+       window->send_configure_change();
        return 1;
 }
-TitleTimecode::TitleTimecode(TitleMain *client, int x, int y)
+TitleTimecode::TitleTimecode(TitleMain *client, TitleWindow *window, int x, int y)
  : BC_CheckBox(x, y, client->config.timecode, _("Stamp timecode"))
 {
        this->client = client;
+       this->window = window;
 }
 int TitleTimecode::handle_event()
 {
@@ -964,16 +848,18 @@ int TitleTimecode::handle_event()
        return 1;
 }
 
-TitleTimecodeFormat::TitleTimecodeFormat(TitleMain *client, int x, int y, const char *text)
+TitleTimecodeFormat::TitleTimecodeFormat(TitleMain *client, TitleWindow *window,
+               int x, int y, const char *text)
  : BC_PopupMenu(x, y, 100, text, 1)
 {
        this->client = client;
+       this->window = window;
 }
 
 int TitleTimecodeFormat::handle_event()
 {
        client->config.timecode_format = Units::text_to_format(get_text());
-       client->send_configure_change();
+       window->send_configure_change();
        return 1;
 }
 
@@ -1012,7 +898,7 @@ TitleFade::TitleFade(TitleMain *client, TitleWindow *window,
 int TitleFade::handle_event()
 {
        *value = atof(get_text());
-       client->send_configure_change();
+       window->send_configure_change();
        return 1;
 }
 
@@ -1058,7 +944,7 @@ int TitleFont::handle_event()
 {
        strcpy(client->config.font, get_text());
        window->check_style(client->config.font, 1);
-       client->send_configure_change();
+       window->send_configure_change();
        return 1;
 }
 
@@ -1103,7 +989,7 @@ int TitleText::handle_event()
        client->config.wtext[len-1] = 0;
        client->config.wlen = wcslen(client->config.wtext);
        window->update_stats();
-       client->send_configure_change();
+       window->send_configure_change();
        return 1;
 }
 TitleTextChars::TitleTextChars(int x, int y, int w)
@@ -1136,8 +1022,8 @@ int TitleTextBfrSz::update(int n)
 
 
 TitleDropShadow::TitleDropShadow(TitleMain *client, TitleWindow *window, int x, int y)
- : BC_TumbleTextBox(window, (int64_t)client->config.dropshadow,
-       (int64_t)-1000, (int64_t)1000, x, y, 70)
+ : BC_TumbleTextBox(window, client->config.dropshadow,
+               -1000, 1000, x, y, 70)
 {
        this->client = client;
        this->window = window;
@@ -1145,32 +1031,34 @@ TitleDropShadow::TitleDropShadow(TitleMain *client, TitleWindow *window, int x,
 int TitleDropShadow::handle_event()
 {
        client->config.dropshadow = atol(get_text());
-       client->send_configure_change();
+       window->send_configure_change();
        return 1;
 }
 
 
 TitleOutline::TitleOutline(TitleMain *client, TitleWindow *window, int x, int y)
- : BC_TumbleTextBox(window, (int64_t)client->config.outline_size,
-       (int64_t)0, (int64_t)1000, x, y, 70)
+ : BC_TumbleTextBox(window, client->config.outline_size,
+               0.f, 1000.f, x, y, 70)
 {
        this->client = client;
        this->window = window;
+       set_precision(1);
 }
 int TitleOutline::handle_event()
 {
-       client->config.outline_size = atol(get_text());
-       client->send_configure_change();
+       client->config.outline_size = atof(get_text());
+       window->send_configure_change();
        return 1;
 }
 
 
 TitleStroker::TitleStroker(TitleMain *client, TitleWindow *window, int x, int y)
- : BC_TumbleTextBox(window, (int64_t)client->config.stroke_width,
-       (int64_t)0, (int64_t)1000, x, y, 70)
+ : BC_TumbleTextBox(window, client->config.stroke_width,
+               0.f, 1000.f, x, y, 70)
 {
        this->client = client;
        this->window = window;
+       set_precision(1);
 }
 int TitleStroker::handle_event()
 {
@@ -1179,42 +1067,44 @@ int TitleStroker::handle_event()
                client->config.style |= BC_FONT_OUTLINE;
        else
                client->config.style &= ~BC_FONT_OUTLINE;
-       client->send_configure_change();
+       window->send_configure_change();
        return 1;
 }
 
 
 TitleX::TitleX(TitleMain *client, TitleWindow *window, int x, int y)
- : BC_TumbleTextBox(window, (int64_t)client->config.title_x,
-       (int64_t)-32767, (int64_t)32767, x, y, 50)
+ : BC_TumbleTextBox(window, client->config.title_x,
+               -32767.f, 32767.f, x, y, 50)
 {
        this->client = client;
        this->window = window;
+       set_precision(1);
 }
 int TitleX::handle_event()
 {
-       client->config.title_x = atol(get_text());
-       client->send_configure_change();
+       client->config.title_x = atof(get_text());
+       window->update_drag();
        return 1;
 }
 
 TitleY::TitleY(TitleMain *client, TitleWindow *window, int x, int y)
- : BC_TumbleTextBox(window, (int64_t)client->config.title_y,
-       (int64_t)-32767, (int64_t)32767, x, y, 50)
+ : BC_TumbleTextBox(window, client->config.title_y,
+               -32767.f, 32767.f, x, y, 50)
 {
        this->client = client;
        this->window = window;
+       set_precision(1);
 }
 int TitleY::handle_event()
 {
-       client->config.title_y = atol(get_text());
-       client->send_configure_change();
+       client->config.title_y = atof(get_text());
+       window->update_drag();
        return 1;
 }
 
 TitleW::TitleW(TitleMain *client, TitleWindow *window, int x, int y)
- : BC_TumbleTextBox(window, (int64_t)client->config.title_w,
-       (int64_t)0, (int64_t)32767, x, y, 50)
+ : BC_TumbleTextBox(window, client->config.title_w,
+               0, 32767, x, y, 50)
 {
        this->client = client;
        this->window = window;
@@ -1222,13 +1112,13 @@ TitleW::TitleW(TitleMain *client, TitleWindow *window, int x, int y)
 int TitleW::handle_event()
 {
        client->config.title_w = atol(get_text());
-       client->send_configure_change();
+       window->update_drag();
        return 1;
 }
 
 TitleH::TitleH(TitleMain *client, TitleWindow *window, int x, int y)
- : BC_TumbleTextBox(window, (int64_t)client->config.title_h,
-       (int64_t)0, (int64_t)32767, x, y, 50)
+ : BC_TumbleTextBox(window, client->config.title_h,
+               0, 32767, x, y, 50)
 {
        this->client = client;
        this->window = window;
@@ -1236,15 +1126,16 @@ TitleH::TitleH(TitleMain *client, TitleWindow *window, int x, int y)
 int TitleH::handle_event()
 {
        client->config.title_h = atol(get_text());
-       client->send_configure_change();
+       window->update_drag();
        return 1;
 }
 
 TitleSpeed::TitleSpeed(TitleMain *client, TitleWindow *window, int x, int y)
- : BC_TumbleTextBox(window, (float)client->config.pixels_per_second,
-       (float)0, (float)1000, x, y, 100)
+ : BC_TumbleTextBox(window, client->config.pixels_per_second,
+               0.f, 1000.f, x, y, 100)
 {
        this->client = client;
+       this->window = window;
        set_precision(2);
        set_increment(10);
 }
@@ -1253,7 +1144,7 @@ TitleSpeed::TitleSpeed(TitleMain *client, TitleWindow *window, int x, int y)
 int TitleSpeed::handle_event()
 {
        client->config.pixels_per_second = atof(get_text());
-       client->send_configure_change();
+       window->send_configure_change();
        return 1;
 }
 
@@ -1268,7 +1159,7 @@ int TitleLeft::handle_event()
 {
        client->config.hjustification = JUSTIFY_LEFT;
        window->update_justification();
-       client->send_configure_change();
+       window->send_configure_change();
        return 1;
 }
 
@@ -1282,7 +1173,7 @@ int TitleCenter::handle_event()
 {
        client->config.hjustification = JUSTIFY_CENTER;
        window->update_justification();
-       client->send_configure_change();
+       window->send_configure_change();
        return 1;
 }
 
@@ -1296,7 +1187,7 @@ int TitleRight::handle_event()
 {
        client->config.hjustification = JUSTIFY_RIGHT;
        window->update_justification();
-       client->send_configure_change();
+       window->send_configure_change();
        return 1;
 }
 
@@ -1312,7 +1203,7 @@ int TitleTop::handle_event()
 {
        client->config.vjustification = JUSTIFY_TOP;
        window->update_justification();
-       client->send_configure_change();
+       window->send_configure_change();
        return 1;
 }
 
@@ -1326,7 +1217,7 @@ int TitleMid::handle_event()
 {
        client->config.vjustification = JUSTIFY_MID;
        window->update_justification();
-       client->send_configure_change();
+       window->send_configure_change();
        return 1;
 }
 
@@ -1340,7 +1231,7 @@ int TitleBottom::handle_event()
 {
        client->config.vjustification = JUSTIFY_BOTTOM;
        window->update_justification();
-       client->send_configure_change();
+       window->send_configure_change();
        return 1;
 }
 
@@ -1370,32 +1261,47 @@ int TitleColorThread::handle_new_color(int output, int alpha)
        window->flush();
        window->unlock_window();
 
-       client->send_configure_change();
+       window->send_configure_change();
        return 1;
 }
 
 TitleDrag::TitleDrag(TitleMain *client, TitleWindow *window, int x, int y)
- : BC_CheckBox(x, y, client->config.drag, _("Drag"))
+ : DragCheckBox(client->server->mwindow, x, y, _("Drag"), &client->config.drag,
+               client->config.title_x, client->config.title_y,
+               client->config.title_w, client->config.title_h)
 {
        this->client = client;
        this->window = window;
 }
 
+Track *TitleDrag::get_drag_track()
+{
+       return client->server->plugin->track;
+}
+int64_t TitleDrag::get_drag_position()
+{
+       return client->get_source_position();
+}
+
+void TitleDrag::update_gui()
+{
+       client->config.drag = get_value();
+       client->config.title_x = drag_x;
+       client->config.title_y = drag_y;
+       client->config.title_w = drag_w+0.5;
+       client->config.title_h = drag_h+0.5;
+       window->title_x->update((float)client->config.title_x);
+       window->title_y->update((float)client->config.title_y);
+       window->title_w->update((int64_t)client->config.title_w);
+       window->title_h->update((int64_t)client->config.title_h);
+       window->send_configure_change();
+}
+
 int TitleDrag::handle_event()
 {
-       int value = get_value();
-       CWindowGUI *cwindow_gui = client->server->mwindow->cwindow->gui;
-       if( value ) {
-               if( !window->grab(cwindow_gui) ) {
-                       update(value = 0);
-                       flicker(10,50);
-               }
-       }
-       else
-               window->ungrab(cwindow_gui);
-       client->config.drag = value;
-       client->send_configure_change();
-       return 1;
+       int ret = DragCheckBox::handle_event();
+       window->send_configure_change();
+       return ret;
 }
 
 TitleBackground::TitleBackground(TitleMain *client, TitleWindow *window, int x, int y)
@@ -1408,7 +1314,7 @@ TitleBackground::TitleBackground(TitleMain *client, TitleWindow *window, int x,
 int TitleBackground::handle_event()
 {
        client->config.background = get_value();
-       client->send_configure_change();
+       window->send_configure_change();
        return 1;
 }
 
@@ -1422,19 +1328,20 @@ TitleBackgroundPath::TitleBackgroundPath(TitleMain *client, TitleWindow *window,
 int TitleBackgroundPath::handle_event()
 {
        strncpy(client->config.background_path, get_text(), sizeof(client->config.background_path));
-       client->send_configure_change();
+       window->send_configure_change();
        return 1;
 }
 
-TitleLoopPlayback::TitleLoopPlayback(TitleMain *client, int x, int y)
+TitleLoopPlayback::TitleLoopPlayback(TitleMain *client, TitleWindow *window, int x, int y)
  : BC_CheckBox(x, y, client->config.loop_playback, _("Loop playback"))
 {
        this->client = client;
+       this->window = window;
 }
 int TitleLoopPlayback::handle_event()
 {
        client->config.loop_playback = get_value();
-       client->send_configure_change();
+       window->send_configure_change();
        return 1;
 }
 
@@ -1525,6 +1432,11 @@ void TitleCurPopup::create_objects()
        sub_menu->add_subitem("%s 10",item);
        sub_menu->add_subitem("%s 0",item);
        sub_menu->add_subitem("/%s",item);
+       add_item(cur_item = new TitleCurItem(this, item = KW_ALIAS));
+       cur_item->add_submenu(sub_menu = new TitleCurSubMenu(cur_item));
+       sub_menu->add_subitem("%s 1",item);
+       sub_menu->add_subitem("%s 0",item);
+       sub_menu->add_subitem("/%s",item);
        add_item(cur_item = new TitleCurItem(this, item = KW_SUP));
        cur_item->add_submenu(sub_menu = new TitleCurSubMenu(cur_item));
        sub_menu->add_subitem("%s 1",item);