add binfolder path relative filters, fix gbrp color model, vwdw timebar tweaks, title...
[goodguy/history.git] / cinelerra-5.1 / plugins / titler / titlerwindow.C
index 2c92d8f35b3ffc9d3cb27bfd55fdb8db1ce5747c..175101185fa8e8301fe99a84264caa158bcd0361 100644 (file)
@@ -20,6 +20,7 @@
  */
 
 #include "bcdisplayinfo.h"
+#include "bcdialog.h"
 #include "bcsignals.h"
 #include "browsebutton.h"
 #include "clip.h"
 #include "automation.h"
 #include "cwindow.h"
 #include "cwindowgui.h"
+#include "dragcheckbox.h"
 #include "edl.h"
 #include "edlsession.h"
+#include "keys.h"
 #include "language.h"
+#include "mainerror.h"
 #include "mwindow.h"
+#include "mwindowgui.h"
 #include "plugin.h"
 #include "pluginserver.h"
 #include "theme.h"
@@ -38,8 +43,6 @@
 #include "titlerwindow.h"
 #include "bcfontentry.h"
 
-#include <wchar.h>
-
 static const int timeunit_formats[] =
 {
        TIME_HMS,
@@ -101,6 +104,8 @@ TitleWindow::TitleWindow(TitleMain *client)
        fade_out = 0;
        text_title = 0;
        text = 0;
+       text_chars = 0;
+       text_bfrsz = 0;
        justify_title = 0;
        left = 0;  center = 0;  right = 0;
        top = 0;   mid = 0;     bottom = 0;
@@ -111,12 +116,22 @@ TitleWindow::TitleWindow(TitleMain *client)
        background = 0;
        background_path = 0;
        loop_playback = 0;
+       pending_config = 0;
+}
+
+void TitleWindow::done_event(int result)
+{
+       drag->drag_deactivate();
+       color_thread->close_window();
+       outline_color_thread->close_window();
+       color_popup->close_window();
+       png_popup->close_window();
 }
 
 TitleWindow::~TitleWindow()
 {
-       ungrab(client->server->mwindow->cwindow->gui);
-       delete fonts_popup;
+       delete color_popup;
+       delete png_popup;
        for( int i=0; i<fonts.size(); ++i )
                delete fonts[i]->get_icon();
 
@@ -218,6 +233,7 @@ void TitleWindow::create_objects()
        add_tool(font_title = new BC_Title(x, y, _("Font:")));
        font = new TitleFont(client, this, x, y + font_title->get_h());
        font->create_objects();
+       font->set_show_query(1);
        x += font->get_w();
        add_subwindow(font_tumbler = new TitleFontTumble(client, this, x, y+margin));
        x += font_tumbler->get_w() + margin;
@@ -243,13 +259,20 @@ void TitleWindow::create_objects()
        int w1 = italic->get_w();
        add_tool(bold = new TitleBold(client, this, x, y + 50));
        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 )
-               grab(client->server->mwindow->cwindow->gui);
+       if( client->config.drag ) {
+               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));
@@ -297,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:")));
@@ -319,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();
@@ -345,17 +368,16 @@ void TitleWindow::create_objects()
        outline = new TitleOutline(client, this, x, y1);
        outline->create_objects();
        x += outline->get_w() + 2*margin;
-#ifdef USE_STOKER
-// to different to be used
+#ifdef USE_STROKER
        add_tool(stroker_title = new BC_Title(x, y, _("Stroker:")));
        stroker = new TitleStroker(client, this, x, y1);
        stroker->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;
@@ -367,13 +389,19 @@ void TitleWindow::create_objects()
        x += background_path->get_w() + margin;
        add_tool(background_browse = new BrowseButton(
                client->server->mwindow->theme, this, background_path,
-               x, y, 0, _("background media"), _("Select background media 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;
        add_tool(text_title = new BC_Title(x, y, _("Text:")));
+       x += text_title->get_w() + 20;
+       int wid = BC_Title::calculate_w(this,"0")*10;
+       add_tool(text_chars = new TitleTextChars(x,y,wid));
+       x += text_chars->get_w() + 20;
+       add_tool(text_bfrsz = new TitleTextBfrSz(x,y,wid));
+
        y += text_title->get_h() + margin;
        x = margin;
        text = new TitleText(client, this, x, y, get_w()-margin - x, get_h() - y - 10);
@@ -382,6 +410,8 @@ void TitleWindow::create_objects()
        add_tool(cur_popup = new TitleCurPopup(client, this));
        cur_popup->create_objects();
        add_tool(fonts_popup = new TitleFontsPopup(client, this));
+       color_popup = new TitleColorPopup(client, this);
+       png_popup = new TitlePngPopup(client, this);
 
        show_window(1);
        update();
@@ -408,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());
@@ -444,141 +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:
-               if( !dragging ) break;
-               return 1;
-       case ButtonRelease:
-               if( !dragging ) return 0;
-               dragging = 0;
-               return 1;
-       case MotionNotify:
-               if( dragging ) break;
-       default:
-               return 0;
-       }
-       MWindow *mwindow = client->server->mwindow;
-       CWindowGUI *cwindow_gui = mwindow->cwindow->gui;
-       CWindowCanvas *canvas = cwindow_gui->canvas;
-       float cursor_x = canvas->get_canvas()->get_relative_cursor_x();
-       float cursor_y = canvas->get_canvas()->get_relative_cursor_y();
-       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()
@@ -595,7 +502,8 @@ void TitleWindow::previous_font()
 
        font->update(fonts.values[current_font]->get_text());
        strcpy(client->config.font, fonts.values[current_font]->get_text());
-       client->send_configure_change();
+       check_style(client->config.font,1);
+       send_configure_change();
 }
 
 void  TitleWindow::next_font()
@@ -612,18 +520,25 @@ void  TitleWindow::next_font()
 
        font->update(fonts.values[current_font]->get_text());
        strcpy(client->config.font, fonts.values[current_font]->get_text());
-       client->send_configure_change();
+       check_style(client->config.font,1);
+       send_configure_change();
 }
 
-int TitleWindow::insert_ibeam(const char *txt, int adv)
+int TitleWindow::insert_ibeam(const char *txt, int ofs)
 {
        int ibeam = cur_ibeam;
-       client->insert_text(txt, ibeam);
+       int ilen = strlen(txt)+1;
+       wchar_t wtxt[ilen];
+       int len = BC_Resources::encode(client->config.encoding, BC_Resources::wide_encoding,
+               (char*)txt,ilen, (char *)wtxt,ilen*sizeof(wtxt[0])) / sizeof(wchar_t);
+       client->insert_text(wtxt, ibeam);
+       while( len > 0 && !wtxt[len] ) --len;
+       int adv = len+1 + ofs;
        if( (ibeam += adv) >= client->config.wlen)
                ibeam = client->config.wlen;
        text->wset_selection(-1, -1, ibeam);
        text->update(client->config.wtext);
-       client->send_configure_change();
+       send_configure_change();
        return 1;
 }
 
@@ -651,6 +566,14 @@ void TitleWindow::update_justification()
        bottom->update(client->config.vjustification == JUSTIFY_BOTTOM);
 }
 
+void TitleWindow::update_stats()
+{
+       text_chars->update(client->config.wlen);
+       int len = MESSAGESIZE - BCTEXTLEN - strlen(text->get_text()) - 1;
+       if( len < 0 ) len = 0;
+       text_bfrsz->update(len);
+}
+
 void TitleWindow::update()
 {
        title_x->update((int64_t)client->config.title_x);
@@ -659,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);
@@ -666,10 +590,11 @@ void TitleWindow::update()
        fade_in->update((float)client->config.fade_in);
        fade_out->update((float)client->config.fade_out);
        font->update(client->config.font);
+       check_style(client->config.font,0);
        text->update(&client->config.wtext[0]);
        speed->update(client->config.pixels_per_second);
        outline->update((int64_t)client->config.outline_size);
-#ifdef USE_STOKER
+#ifdef USE_STROKER
        stroker->update((int64_t)client->config.stroke_width);
 #endif
        timecode->update(client->config.timecode);
@@ -687,6 +612,7 @@ void TitleWindow::update()
                }
        }
        update_justification();
+       update_stats();
        update_color();
 }
 
@@ -710,7 +636,6 @@ int TitleFontTumble::handle_down_event()
 }
 
 
-
 TitleSizeTumble::TitleSizeTumble(TitleMain *client, TitleWindow *window, int x, int y)
  : BC_Tumbler(x, y)
 {
@@ -737,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;
 }
 
@@ -760,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;
 }
 
@@ -776,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;
 }
 
@@ -791,20 +732,14 @@ 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;
 }
 
 
 
 TitleSize::TitleSize(TitleMain *client, TitleWindow *window, int x, int y, char *text)
- : BC_PopupTextBox(window,
-               &window->sizes,
-               text,
-               x,
-               y,
-               64,
-               300)
+ : BC_PopupTextBox(window, &window->sizes, text, x, y, 64, 300)
 {
        this->client = client;
        this->window = window;
@@ -816,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)
@@ -843,12 +778,12 @@ TitlePitch::
 int TitlePitch::handle_event()
 {
        *value = atol(get_text());
-       client->send_configure_change();
+       window->send_configure_change();
        return 1;
 }
 
 TitleColorButton::TitleColorButton(TitleMain *client, TitleWindow *window, int x, int y)
- : BC_GenericButton(x, y, _("Color..."))
+ : BC_GenericButton(x, y, _("Text Color..."))
 {
        this->client = client;
        this->window = window;
@@ -884,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()
 {
@@ -911,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;
 }
 
@@ -959,13 +898,44 @@ TitleFade::TitleFade(TitleMain *client, TitleWindow *window,
 int TitleFade::handle_event()
 {
        *value = atof(get_text());
-       client->send_configure_change();
+       window->send_configure_change();
        return 1;
 }
 
+void TitleWindow::check_style(const char *font_name, int update)
+{
+       BC_FontEntry *font_nrm = TitleMain::get_font(font_name, 0);
+       BC_FontEntry *font_itl = TitleMain::get_font(font_name, BC_FONT_ITALIC);
+       BC_FontEntry *font_bld = TitleMain::get_font(font_name, BC_FONT_BOLD);
+       BC_FontEntry *font_bit = TitleMain::get_font(font_name, BC_FONT_ITALIC | BC_FONT_BOLD);
+       int has_norm = font_nrm != 0 ? 1 : 0;
+       int has_ital = font_itl != 0 || font_bit != 0 ? 1 : 0;
+       int has_bold = font_bld != 0 || font_bit != 0 ? 1 : 0;
+       if( bold->get_value() ) {
+               if( !has_bold ) bold->update(0);
+       }
+       else {
+               if( !has_norm && has_bold ) bold->update(1);
+       }
+       if( italic->get_value() ) {
+               if( !has_ital ) italic->update(0);
+       }
+       else {
+               if( !has_norm && has_ital ) italic->update(1);
+       }
+       if( has_norm && has_bold ) bold->enable();   else bold->disable();
+       if( has_norm && has_ital ) italic->enable(); else italic->disable();
+       if( update ) {
+               int style = stroker && atof(stroker->get_text()) ? BC_FONT_OUTLINE : 0;
+               if( bold->get_value() ) style |= BC_FONT_BOLD;
+               if( italic->get_value() ) style |= BC_FONT_ITALIC;
+               client->config.style = style;
+       }
+}
+
 TitleFont::TitleFont(TitleMain *client, TitleWindow *window, int x, int y)
  : BC_PopupTextBox(window, &window->fonts, client->config.font,
-               x, y, 200, 500, LISTBOX_ICON_LIST)
+               x, y, 240, 300, LISTBOX_ICON_LIST)
 {
        this->client = client;
        this->window = window;
@@ -973,7 +943,8 @@ TitleFont::TitleFont(TitleMain *client, TitleWindow *window, int x, int y)
 int TitleFont::handle_event()
 {
        strcpy(client->config.font, get_text());
-       client->send_configure_change();
+       window->check_style(client->config.font, 1);
+       window->send_configure_change();
        return 1;
 }
 
@@ -1001,18 +972,58 @@ int TitleText::button_press_event()
 int TitleText::handle_event()
 {
        window->fonts_popup->deactivate();
+       int text_len = strlen(get_text());
+       int avail = MESSAGESIZE - BCTEXTLEN;
+       if( text_len >= avail ) { // back off last utf8 char
+               char text[2*sizeof(client->config.wtext)];
+               strcpy(text, get_text());
+               text_len = avail;
+               while( text_len > 0 && (text[text_len-1] & 0xc0) == 0x80 )
+                       text[--text_len] = 0;
+               if( text_len > 0 )
+                       text[--text_len] = 0;
+               update(text);
+       }
        int len =  sizeof(client->config.wtext) / sizeof(wchar_t);
        wcsncpy(client->config.wtext, get_wtext(), len);
        client->config.wtext[len-1] = 0;
        client->config.wlen = wcslen(client->config.wtext);
-       client->send_configure_change();
+       window->update_stats();
+       window->send_configure_change();
        return 1;
 }
+TitleTextChars::TitleTextChars(int x, int y, int w)
+ : BC_Title(x, y, "", MEDIUMFONT, -1, 0, w)
+{
+}
+TitleTextChars::~TitleTextChars()
+{
+}
+int TitleTextChars::update(int n)
+{
+       char text[BCSTRLEN];
+       sprintf(text, _("chars: %d  "),n);
+       return BC_Title::update(text, 0);
+}
+
+TitleTextBfrSz::TitleTextBfrSz(int x, int y, int w)
+ : BC_Title(x, y, "", MEDIUMFONT, -1, 0, w)
+{
+}
+TitleTextBfrSz::~TitleTextBfrSz()
+{
+}
+int TitleTextBfrSz::update(int n)
+{
+       char text[BCSTRLEN];
+       sprintf(text, _("bfrsz: %d  "),n);
+       return BC_Title::update(text, 0);
+}
 
 
 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;
@@ -1020,75 +1031,80 @@ 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()
 {
-       client->config.stroke_width = atol(get_text());
-       if( client->config.stroke_width > 1 )
+       client->config.stroke_width = atof(get_text());
+       if( client->config.stroke_width )
                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;
@@ -1096,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;
@@ -1110,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);
 }
@@ -1127,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;
 }
 
@@ -1142,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;
 }
 
@@ -1156,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;
 }
 
@@ -1170,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;
 }
 
@@ -1186,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;
 }
 
@@ -1200,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;
 }
 
@@ -1214,14 +1231,14 @@ int TitleBottom::handle_event()
 {
        client->config.vjustification = JUSTIFY_BOTTOM;
        window->update_justification();
-       client->send_configure_change();
+       window->send_configure_change();
        return 1;
 }
 
 
 
 TitleColorThread::TitleColorThread(TitleMain *client, TitleWindow *window, int is_outline)
- : ColorThread(1)
+ : ColorPicker(1, is_outline? _("Outline Color") : _("Text Color"))
 {
        this->client = client;
        this->window = window;
@@ -1244,27 +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();
-       client->config.drag = value;
-       if( value )
-               window->grab(client->server->mwindow->cwindow->gui);
-       else
-               window->ungrab(client->server->mwindow->cwindow->gui);
-       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)
@@ -1277,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;
 }
 
@@ -1291,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;
 }
 
@@ -1318,79 +1356,96 @@ int TitleCurPopup::handle_event()
 {
        return 1;
 }
+
+void TitleCurSubMenu::add_subitemx(int popup_type, va_list ap, const char *fmt)
+{
+       char item[BCSTRLEN];
+       vsnprintf(item, sizeof(item)-1, fmt, ap);
+       item[sizeof(item)-1] = 0;
+       add_submenuitem(new TitleCurSubMenuItem(this, item, popup_type));
+}
+
 void TitleCurPopup::create_objects()
 {
        TitleCurItem *cur_item;
        TitleCurSubMenu *sub_menu;
-       add_item(cur_item = new TitleCurItem(this, _("nudge")));
+       char *item;
+       add_item(cur_item = new TitleCurItem(this, item = _(KW_NUDGE)));
+       cur_item->add_submenu(sub_menu = new TitleCurSubMenu(cur_item));
+       sub_menu->add_subitem("%s dx,dy",item);
+       sub_menu->add_subitem("/%s",item);
+       add_item(cur_item = new TitleCurItem(this, item = _(KW_COLOR)));
        cur_item->add_submenu(sub_menu = new TitleCurSubMenu(cur_item));
-       sub_menu->add_submenuitem(new TitleCurSubMenuItem(sub_menu,_("nudge dx,dy")));
-       sub_menu->add_submenuitem(new TitleCurSubMenuItem(sub_menu,_("/nudge")));
-       add_item(cur_item = new TitleCurItem(this, _("color")));
+       sub_menu->add_subitem(POPUP_COLOR,"%s %s",item,_("#"));
+       sub_menu->add_subitem("%s ",item);
+       sub_menu->add_subitem("/%s",item);
+       add_item(cur_item = new TitleCurItem(this, item = _(KW_ALPHA)));
        cur_item->add_submenu(sub_menu = new TitleCurSubMenu(cur_item));
-       sub_menu->add_submenuitem(new TitleCurSubMenuItem(sub_menu,_("color #")));
-       sub_menu->add_submenuitem(new TitleCurSubMenuItem(sub_menu,_("/color")));
-       add_item(cur_item = new TitleCurItem(this, _("alpha")));
+       sub_menu->add_subitem("%s ",item);
+       sub_menu->add_subitem("%s 0.",item);
+       sub_menu->add_subitem("%s .5",item);
+       sub_menu->add_subitem("%s 1.",item);
+       sub_menu->add_subitem("/%s",item);
+       add_item(cur_item = new TitleCurItem(this, item = _(KW_FONT)));
        cur_item->add_submenu(sub_menu = new TitleCurSubMenu(cur_item));
-       sub_menu->add_submenuitem(new TitleCurSubMenuItem(sub_menu,_("alpha ")));
-       sub_menu->add_submenuitem(new TitleCurSubMenuItem(sub_menu,_("alpha 0.")));
-       sub_menu->add_submenuitem(new TitleCurSubMenuItem(sub_menu,_("alpha .5")));
-       sub_menu->add_submenuitem(new TitleCurSubMenuItem(sub_menu,_("alpha 1.")));
-       sub_menu->add_submenuitem(new TitleCurSubMenuItem(sub_menu,_("/alpha")));
-       add_item(cur_item = new TitleCurItem(this, _("font")));
+       sub_menu->add_subitem(POPUP_FONT,"%s %s",item, _("name"));
+       sub_menu->add_subitem(POPUP_OFFSET, "%s ",item);
+       sub_menu->add_subitem("/%s",item);
+       add_item(cur_item = new TitleCurItem(this, item = _(KW_SIZE)));
        cur_item->add_submenu(sub_menu = new TitleCurSubMenu(cur_item));
-       sub_menu->add_submenuitem(new TitleCurSubMenuItem(sub_menu,_("font name")));
-       sub_menu->add_submenuitem(new TitleCurSubMenuItem(sub_menu,_("/font")));
-       add_item(cur_item = new TitleCurItem(this, _("size")));
+       sub_menu->add_subitem("%s +",item);
+       sub_menu->add_subitem("%s -",item);
+       sub_menu->add_subitem("%s ",item);
+       sub_menu->add_subitem("/%s",item);
+       add_item(cur_item = new TitleCurItem(this, item = _(KW_BOLD)));
        cur_item->add_submenu(sub_menu = new TitleCurSubMenu(cur_item));
-       sub_menu->add_submenuitem(new TitleCurSubMenuItem(sub_menu,_("size +")));
-       sub_menu->add_submenuitem(new TitleCurSubMenuItem(sub_menu,_("size -")));
-       sub_menu->add_submenuitem(new TitleCurSubMenuItem(sub_menu,_("size ")));
-       sub_menu->add_submenuitem(new TitleCurSubMenuItem(sub_menu,_("/size")));
-       add_item(cur_item = new TitleCurItem(this, _("bold")));
+       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_ITALIC)));
        cur_item->add_submenu(sub_menu = new TitleCurSubMenu(cur_item));
-       sub_menu->add_submenuitem(new TitleCurSubMenuItem(sub_menu,_("bold 1")));
-       sub_menu->add_submenuitem(new TitleCurSubMenuItem(sub_menu,_("bold 0")));
-       sub_menu->add_submenuitem(new TitleCurSubMenuItem(sub_menu,_("/bold")));
-       add_item(cur_item = new TitleCurItem(this, _("italic")));
+       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_CAPS)));
        cur_item->add_submenu(sub_menu = new TitleCurSubMenu(cur_item));
-       sub_menu->add_submenuitem(new TitleCurSubMenuItem(sub_menu,_("italic 1")));
-       sub_menu->add_submenuitem(new TitleCurSubMenuItem(sub_menu,_("italic 0")));
-       sub_menu->add_submenuitem(new TitleCurSubMenuItem(sub_menu,_("/italic")));
-       add_item(cur_item = new TitleCurItem(this, _("caps")));
+       sub_menu->add_subitem("%s 1",item);
+       sub_menu->add_subitem("%s 0",item);
+       sub_menu->add_subitem("%s -1",item);
+       sub_menu->add_subitem("/%s",item);
+       add_item(cur_item = new TitleCurItem(this, item = _(KW_UL)));
        cur_item->add_submenu(sub_menu = new TitleCurSubMenu(cur_item));
-       sub_menu->add_submenuitem(new TitleCurSubMenuItem(sub_menu,_("caps 1")));
-       sub_menu->add_submenuitem(new TitleCurSubMenuItem(sub_menu,_("caps 0")));
-       sub_menu->add_submenuitem(new TitleCurSubMenuItem(sub_menu,_("caps -1")));
-       sub_menu->add_submenuitem(new TitleCurSubMenuItem(sub_menu,_("/caps")));
-       add_item(cur_item = new TitleCurItem(this, _("ul")));
+       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_BLINK)));
        cur_item->add_submenu(sub_menu = new TitleCurSubMenu(cur_item));
-       sub_menu->add_submenuitem(new TitleCurSubMenuItem(sub_menu,_("ul 1")));
-       sub_menu->add_submenuitem(new TitleCurSubMenuItem(sub_menu,_("ul 0")));
-       sub_menu->add_submenuitem(new TitleCurSubMenuItem(sub_menu,_("/ul")));
-       add_item(cur_item = new TitleCurItem(this, _("blink")));
+       sub_menu->add_subitem("%s 1",item);
+       sub_menu->add_subitem("%s -1",item);
+       sub_menu->add_subitem("%s ",item);
+       sub_menu->add_subitem("%s 0",item);
+       sub_menu->add_subitem("/%s",item);
+       add_item(cur_item = new TitleCurItem(this, item = _(KW_FIXED)));
        cur_item->add_submenu(sub_menu = new TitleCurSubMenu(cur_item));
-       sub_menu->add_submenuitem(new TitleCurSubMenuItem(sub_menu,_("blink 1")));
-       sub_menu->add_submenuitem(new TitleCurSubMenuItem(sub_menu,_("blink -1")));
-       sub_menu->add_submenuitem(new TitleCurSubMenuItem(sub_menu,_("blink ")));
-       sub_menu->add_submenuitem(new TitleCurSubMenuItem(sub_menu,_("blink 0")));
-       sub_menu->add_submenuitem(new TitleCurSubMenuItem(sub_menu,_("/blink")));
-       add_item(cur_item = new TitleCurItem(this, _("fixed")));
+       sub_menu->add_subitem("%s ",item);
+       sub_menu->add_subitem("%s 20",item);
+       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_submenuitem(new TitleCurSubMenuItem(sub_menu,_("fixed ")));
-       sub_menu->add_submenuitem(new TitleCurSubMenuItem(sub_menu,_("fixed 20")));
-       sub_menu->add_submenuitem(new TitleCurSubMenuItem(sub_menu,_("fixed 10")));
-       sub_menu->add_submenuitem(new TitleCurSubMenuItem(sub_menu,_("fixed 0")));
-       sub_menu->add_submenuitem(new TitleCurSubMenuItem(sub_menu,_("/fixed")));
-       add_item(cur_item = new TitleCurItem(this, _("sup")));
+       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_submenuitem(new TitleCurSubMenuItem(sub_menu,_("sup 1")));
-       sub_menu->add_submenuitem(new TitleCurSubMenuItem(sub_menu,_("sup 0")));
-       sub_menu->add_submenuitem(new TitleCurSubMenuItem(sub_menu,_("sup -1")));
-       sub_menu->add_submenuitem(new TitleCurSubMenuItem(sub_menu,_("/sup")));
-       add_item(cur_item = new TitleCurItem(this, _("png")));
+       sub_menu->add_subitem("%s 1",item);
+       sub_menu->add_subitem("%s 0",item);
+       sub_menu->add_subitem("%s -1",item);
+       sub_menu->add_subitem("/%s",item);
+       add_item(cur_item = new TitleCurItem(this, item = _(KW_PNG)));
        cur_item->add_submenu(sub_menu = new TitleCurSubMenu(cur_item));
-       sub_menu->add_submenuitem(new TitleCurSubMenuItem(sub_menu,_("png file")));
+       sub_menu->add_subitem(POPUP_PNG,"%s %s", item, _("file"));
 }
 
 TitleCurItem::TitleCurItem(TitleCurPopup *popup, const char *text)
@@ -1411,10 +1466,11 @@ TitleCurSubMenu::~TitleCurSubMenu()
 {
 }
 
-TitleCurSubMenuItem::TitleCurSubMenuItem(TitleCurSubMenu *submenu, const char *text)
+TitleCurSubMenuItem::TitleCurSubMenuItem(TitleCurSubMenu *submenu, const char *text, int popup_type)
  : BC_MenuItem(text)
 {
        this->submenu = submenu;
+       this->popup_type = popup_type;
 }
 TitleCurSubMenuItem::~TitleCurSubMenuItem()
 {
@@ -1424,20 +1480,26 @@ int TitleCurSubMenuItem::handle_event()
        TitleCurPopup *popup = submenu->cur_item->popup;
        TitleWindow *window = popup->window;
        const char *item_text = get_text();
-       if( !strcmp(item_text, _("font")) ) {
-               int w = 300, h = 200;
-               int x = window->get_abs_cursor_x(0) - w + 10;
-               int y = window->get_abs_cursor_y(0) - 20;
-               if( x < 2 ) x = 2;
-               if( y < 2 ) y = 2;
-               window->fonts_popup->activate(x, y, w,h);
-               return 1;
+       int ofs = *item_text == '/' ? 0 : -1;
+       switch( popup_type ) {
+       case POPUP_FONT: {
+               int px, py;
+               window->get_pop_cursor(px ,py);
+               window->fonts_popup->activate(px, py, 300,200);
+               return 1; }
+       case POPUP_COLOR: {
+               window->color_popup->activate();
+               return 1; }
+       case POPUP_PNG: {
+               window->png_popup->activate();
+               return 1; }
+       case POPUP_OFFSET:
+               ofs = -1;
+               break;
        }
        char txt[BCSTRLEN];
        sprintf(txt, "<%s>", item_text);
-       int adv = strlen(txt);
-       if( adv > 1 && (txt[1] != '/' && strcmp(txt,_("font"))) ) --adv;
-       return window->insert_ibeam(txt,adv);
+       return window->insert_ibeam(txt, ofs);
 }
 
 TitleFontsPopup::TitleFontsPopup(TitleMain *client, TitleWindow *window)
@@ -1447,10 +1509,23 @@ TitleFontsPopup::TitleFontsPopup(TitleMain *client, TitleWindow *window)
        this->client = client;
        this->window = window;
        set_use_button(0);
+       set_show_query(1);
 }
 TitleFontsPopup::~TitleFontsPopup()
 {
 }
+int TitleFontsPopup::keypress_event()
+{
+       switch( get_keypress() ) {
+       case ESC:
+       case DELETE:
+               deactivate();
+               return 1;
+       default:
+               break;
+       }
+       return BC_ListBox::keypress_event();
+}
 
 int TitleFontsPopup::handle_event()
 {
@@ -1458,10 +1533,72 @@ int TitleFontsPopup::handle_event()
        BC_ListBoxItem *item = get_selection(0, 0);
        if( !item ) return 1;
        const char *item_text = item->get_text();
-       char txt[BCTEXTLEN];
-       sprintf(txt, "<font %s>",item_text);
-       int adv = strlen(txt);
-       int ret = window->insert_ibeam(txt, adv);
-       return ret;
+       char txt[BCTEXTLEN];  sprintf(txt, "<%s %s>", _(KW_FONT), item_text);
+       return window->insert_ibeam(txt);
+}
+
+TitleColorPopup::TitleColorPopup(TitleMain *client, TitleWindow *window)
+ : ColorPicker(0, _("Color"))
+{
+       this->client = client;
+       this->window = window;
+       this->color_value = client->config.color;
+}
+TitleColorPopup::~TitleColorPopup()
+{
+}
+int TitleColorPopup::handle_new_color(int output, int alpha)
+{
+       color_value = output;
+       return 1;
+}
+int TitleColorPopup::activate()
+{
+       start_window(client->config.color, 255, 1);
+       return 1;
+}
+void TitleColorPopup::handle_done_event(int result)
+{
+       if( result ) return;
+       char txt[BCSTRLEN];  sprintf(txt, "<%s #%06x>", _(KW_COLOR), color_value);
+       window->insert_ibeam(txt);
+}
+
+TitlePngPopup::TitlePngPopup(TitleMain *client, TitleWindow *window)
+ : BC_DialogThread()
+{
+       this->client = client;
+       this->window = window;
+}
+
+TitlePngPopup::~TitlePngPopup()
+{
+       close_window();
+}
+
+void TitlePngPopup::handle_done_event(int result)
+{
+       if( result ) return;
+       BrowseButtonWindow *gui = (BrowseButtonWindow *)get_gui();
+       const char *path = gui->get_submitted_path();
+       char txt[BCSTRLEN];  sprintf(txt, "<%s %s>", _(KW_PNG), path);
+       window->insert_ibeam(txt);
+}
+
+BC_Window *TitlePngPopup::new_gui()
+{
+       MWindow *mwindow = client->server->mwindow;
+       int x, y;  mwindow->gui->get_abs_cursor(x, y);
+
+       BC_Window *gui = new BrowseButtonWindow(mwindow->theme,
+               x-25, y-100, window, "", _("Png file"), _("Png path"), 0);
+       gui->create_objects();
+       return gui;
+}
+
+int TitlePngPopup::activate()
+{
+       BC_DialogThread::start();
+       return 1;
 }