titler rework, some code cleanup and fixes
[goodguy/history.git] / cinelerra-5.1 / plugins / titler / titlerwindow.C
similarity index 50%
rename from cinelerra-5.1/plugins/titler/titlewindow.C
rename to cinelerra-5.1/plugins/titler/titlerwindow.C
index 1a537ba67a4bb378d4efd888696ecb3832a9aaed..ef89eb8ddd28a93a1d2ff23af2270109bfaa1c70 100644 (file)
 
 #include "bcdisplayinfo.h"
 #include "bcsignals.h"
+#include "clip.h"
 #include "cstrdup.h"
+#include "automation.h"
+#include "cwindow.h"
+#include "cwindowgui.h"
+#include "edl.h"
+#include "edlsession.h"
 #include "language.h"
+#include "mwindow.h"
+#include "plugin.h"
+#include "pluginserver.h"
 #include "theme.h"
-#include "titlewindow.h"
+#include "track.h"
+#include "titlerwindow.h"
 #include "bcfontentry.h"
 
 #include <wchar.h>
@@ -42,11 +52,7 @@ static const int timeunit_formats[] =
 
 TitleWindow::TitleWindow(TitleMain *client)
  : PluginClientWindow(client,
-       client->config.window_w,
-       client->config.window_h,
-       100,
-       100,
-       1)
+       client->config.window_w, client->config.window_h, 100, 100, 1)
 {
 //printf("TitleWindow::TitleWindow %d %d %d\n", __LINE__, client->config.window_w, client->config.window_h);
        this->client = client;
@@ -54,49 +60,42 @@ TitleWindow::TitleWindow(TitleMain *client)
        justify_title = 0;
        style_title = 0;
        size_title = 0;
-       title_y = 0;
-       bottom = 0;
-       size = 0;
-       loop = 0;
-       title_x = 0;
-       dropshadow = 0;
-       motion = 0;
+       motion_title = 0;
+       speed_title = 0;
+       font_title = 0;
+       fadeout_title = 0;
+       fadein_title = 0;
        dropshadow_title = 0;
+       text_title = 0;
+
+       font = 0;  size = 0;
+       title_x = 0; title_y = 0;
+       x_title = 0; y_title = 0;
+       title_w = 0; title_h = 0;
+       w_title = 0; h_title = 0;
+       top = 0;  mid = 0;    bottom = 0;
+       left = 0; center = 0; right = 0;
+       loop = 0; motion = 0; speed = 0;
+       dropshadow = 0;
        text = 0;
        timecode = 0;
-       fade_in = 0;
-       encoding_title = 0;
-       x_title = 0;
        bold = 0;
-       color_y = 0;
-       speed = 0;
-       center = 0;
        italic = 0;
-       text_title = 0;
-       motion_title = 0;
-       fadeout_title = 0;
-       font_title = 0;
-       fadein_title = 0;
+       dragging = 0;
+       fade_in = 0;
        fade_out = 0;
        color_button = 0;
-       left = 0;
-       speed_title = 0;
-       top = 0;
-       font = 0;
-       right = 0;
-       color_x = 0;
-       color_y = 0;
-       y_title = 0;
+       color_x = color_y = 0;
        color_thread = 0;
-       mid = 0;
-       encoding_title = 0;
-       encoding = 0;
+       background = 0;
+       background_path = 0;
+       cur_ibeam = -1;
 }
 
 TitleWindow::~TitleWindow()
 {
-       for(int j = 0; j < fonts.size(); j++)
-       {
+       ungrab(client->server->mwindow->cwindow->gui);
+       for( int j=0; j<fonts.size(); ++j ) {
 // delete the pixmaps but not the vframes since they're static
                delete fonts.get(j)->get_icon();
        }
@@ -104,9 +103,6 @@ TitleWindow::~TitleWindow()
        sizes.remove_all_objects();
        delete timecode_format;
        delete color_thread;
-#ifdef USE_OUTLINE
-       delete color_stroke_thread;
-#endif
        delete title_x;
        delete title_y;
 }
@@ -121,25 +117,6 @@ void TitleWindow::create_objects()
 #define COLOR_H 30
        client->build_previews(this);
 
-       encodings.append(new BC_ListBoxItem("ISO8859-1"));
-       encodings.append(new BC_ListBoxItem("ISO8859-2"));
-       encodings.append(new BC_ListBoxItem("ISO8859-3"));
-       encodings.append(new BC_ListBoxItem("ISO8859-4"));
-       encodings.append(new BC_ListBoxItem("ISO8859-5"));
-       encodings.append(new BC_ListBoxItem("ISO8859-6"));
-       encodings.append(new BC_ListBoxItem("ISO8859-7"));
-       encodings.append(new BC_ListBoxItem("ISO8859-8"));
-       encodings.append(new BC_ListBoxItem("ISO8859-9"));
-       encodings.append(new BC_ListBoxItem("ISO8859-10"));
-       encodings.append(new BC_ListBoxItem("ISO8859-11"));
-       encodings.append(new BC_ListBoxItem("ISO8859-12"));
-       encodings.append(new BC_ListBoxItem("ISO8859-13"));
-       encodings.append(new BC_ListBoxItem("ISO8859-14"));
-       encodings.append(new BC_ListBoxItem("ISO8859-15"));
-       encodings.append(new BC_ListBoxItem("KOI8"));
-       encodings.append(new BC_ListBoxItem("UTF-8"));
-
-
        sizes.append(new BC_ListBoxItem("8"));
        sizes.append(new BC_ListBoxItem("9"));
        sizes.append(new BC_ListBoxItem("10"));
@@ -178,24 +155,23 @@ void TitleWindow::create_objects()
 // Construct font list
        ArrayList<BC_FontEntry*> *fontlist = get_resources()->fontlist;
 
-       for(int i = 0; i < fontlist->size(); i++) {
+       for( int i=0; i<fontlist->size(); ++i ) {
                int exists = 0;
-               for(int j = 0; j < fonts.size(); j++) {
-                       if(!strcasecmp(fonts.get(j)->get_text(),
-                               fontlist->get(i)->displayname)) {
+               for( int j=0; j<fonts.size(); ++j ) {
+                       if( !strcasecmp(fonts.get(j)->get_text(),
+                               fontlist->get(i)->displayname) ) {
                                exists = 1;
                                break;
                        }
                }
 
                BC_ListBoxItem *item = 0;
-               if(!exists) {
+               if( !exists ) {
                        fonts.append(item = new
                                BC_ListBoxItem(fontlist->get(i)->displayname));
-                       if(!strcmp(client->config.font, item->get_text()))
+                       if( !strcmp(client->config.font, item->get_text()) )
                                item->set_selected(1);
-                       if(fontlist->values[i]->image)
-                       {
+                       if( fontlist->values[i]->image ) {
                                VFrame *vframe = fontlist->get(i)->image;
                                BC_Pixmap *icon = new BC_Pixmap(this, vframe, PIXMAP_ALPHA);
                                item->set_icon(icon);
@@ -208,9 +184,9 @@ void TitleWindow::create_objects()
        int done = 0;
        while(!done) {
                done = 1;
-               for(int i = 0; i < fonts.size() - 1; i++) {
-                       if(strcmp(fonts.values[i]->get_text(),
-                               fonts.values[i + 1]->get_text()) > 0) {
+               for( int i=0; i<fonts.size()-1; ++i ) {
+                       if( strcmp(fonts.values[i]->get_text(),
+                               fonts.values[i + 1]->get_text()) > 0 ) {
                                BC_ListBoxItem *temp = fonts.values[i + 1];
                                fonts.values[i + 1] = fonts.values[i];
                                fonts.values[i] = temp;
@@ -223,34 +199,36 @@ void TitleWindow::create_objects()
        font = new TitleFont(client, this, x, y + font_title->get_h());
        font->create_objects();
        x += font->get_w();
-       add_subwindow(font_tumbler = new TitleFontTumble(client, this, x, y+10));
+       add_subwindow(font_tumbler = new TitleFontTumble(client, this, x, y+margin));
        x += font_tumbler->get_w() + margin;
 
        int x1 = x, y1 = y;
-       add_tool(size_title = new BC_Title(x1, y1+10, _("Size:")));
-       sprintf(string, "%d", client->config.size);
+       add_tool(size_title = new BC_Title(x1, y1+margin, _("Size:")));
+       sprintf(string, "%.2f", client->config.size);
        x1 += size_title->get_w() + margin;
-       size = new TitleSize(client, this, x1, y1+10, string);
+       size = new TitleSize(client, this, x1, y1+margin, string);
        size->create_objects();
        int x2 = x1 + size->get_w(), y2 = y1 + size->get_h() + margin;
-       add_subwindow(size_tumbler = new TitleSizeTumble(client, this, x2, y1+10));
+       add_subwindow(size_tumbler = new TitleSizeTumble(client, this, x2, y1+margin));
 
-       add_tool(pitch_title = new BC_Title(x-5, y2+10, _("Pitch:")));
-       pitch = new TitlePitch(client, this, x1, y2+10, &client->config.line_pitch);
+       add_tool(pitch_title = new BC_Title(x-5, y2+margin, _("Pitch:")));
+       pitch = new TitlePitch(client, this, x1, y2+margin, &client->config.line_pitch);
        pitch->create_objects();
-       x = x2 + size_tumbler->get_w() + margin;
+
+       int x3 = x2 + size_tumbler->get_w() + 50;
        int y3 = pitch->get_y() + pitch->get_h();
 
-       add_tool(style_title = new BC_Title(x, y, _("Style:")));
+       add_tool(style_title = new BC_Title(x=x3, y, _("Style:")));
        add_tool(italic = new TitleItalic(client, this, x, y + 20));
        int w1 = italic->get_w();
        add_tool(bold = new TitleBold(client, this, x, y + 50));
        if( bold->get_w() > w1 ) w1 = bold->get_w();
-#ifdef USE_OUTLINE
-       add_tool(stroke = new TitleStroke(client, this, x, y + 80));
-       if( stroke->get_w() > w1 ) w1 = stroke->get_w();
-#endif
-       x += w1 + 10;
+       add_tool(drag = new TitleDrag(client, this, x, y + 80));
+       if( drag->get_w() > w1 ) w1 = drag->get_w();
+       if( client->config.drag )
+               grab(client->server->mwindow->cwindow->gui);
+
+       x += w1 + margin;
        add_tool(justify_title = new BC_Title(x, y, _("Justify:")));
        add_tool(left = new TitleLeft(client, this, x, y + 20));
        w1 = left->get_w();
@@ -259,109 +237,128 @@ void TitleWindow::create_objects()
        add_tool(right = new TitleRight(client, this, x, y + 80));
        if( right->get_w() > w1 ) w1 = right->get_w();
 
-       x += w1 + 10;
+       x += w1 + margin;
        add_tool(top = new TitleTop(client, this, x, y + 20));
        add_tool(mid = new TitleMid(client, this, x, y + 50));
        add_tool(bottom= new TitleBottom(client, this, x, y + 80));
 
-       x = 10;
-       y = y3;
+       x = margin;
+       y = y3+10;
 
-       add_tool(x_title = new BC_Title(x, y, _("X:")));
-       title_x = new TitleX(client, this, x, y + 20);
+       w1 = BC_Title::calculate_w(this, _("X:"));
+       if( (x1 = BC_Title::calculate_w(this, _("Y:"))) > w1 ) w1 = x1;
+       if( (x1 = BC_Title::calculate_w(this, _("W:"))) > w1 ) w1 = x1;
+       if( (x1 = BC_Title::calculate_w(this, _("H:"))) > w1 ) w1 = x1;
+       add_tool(x_title = new BC_Title(x1=x, y, _("X:")));
+       x1 += w1;
+       title_x = new TitleX(client, this, x1, y);
        title_x->create_objects();
-       x += 90;
-
-       add_tool(y_title = new BC_Title(x, y, _("Y:")));
-       title_y = new TitleY(client, this, x, y + 20);
+       x1 += title_x->get_w()+margin;
+       add_tool(y_title = new BC_Title(x1, y, _("Y:")));
+       x1 += w1;
+       title_y = new TitleY(client, this, x1, y);
        title_y->create_objects();
-       x += 90;
-
-       add_tool(motion_title = new BC_Title(x, y, _("Motion type:")));
-
-       motion = new TitleMotion(client, this, x, y + 20);
+       x1 += title_y->get_w();
+       y1 = y + title_y->get_h();
+
+       add_tool(w_title = new BC_Title(x1=x, y1, _("W:")));
+       x1 += w1;
+       title_w = new TitleW(client, this, x1, y1);
+       title_w->create_objects();
+       x1 += title_w->get_w()+margin;
+       add_tool(h_title = new BC_Title(x1, y1, _("H:")));
+       x1 += w1;
+       title_h = new TitleH(client, this, x1, y1);
+       title_h->create_objects();
+       x1 += title_h->get_w();
+
+       x = x1+2*margin;
+       add_tool(motion_title = new BC_Title(x1=x, y, _("Motion:")));
+       x1 += motion_title->get_w()+margin;
+       motion = new TitleMotion(client, this, x1, y);
        motion->create_objects();
-       x += 150;
-
-       add_tool(loop = new TitleLoop(client, x, y + 20));
-
-       x = 10;
-       y += 50;
+       add_tool(loop = new TitleLoop(client, x, y1));
+       x = margin;    y = y1 + loop->get_h()+20;
 
        add_tool(dropshadow_title = new BC_Title(x, y, _("Drop shadow:")));
        w1 = dropshadow_title->get_w();
        dropshadow = new TitleDropShadow(client, this, x, y + 20);
        dropshadow->create_objects();
        if( dropshadow->get_w() > w1 ) w1 = dropshadow->get_w();
-       x += w1 + 10;
+       x += w1 + margin;
 
        add_tool(fadein_title = new BC_Title(x, y, _("Fade in (sec):")));
        w1 = fadein_title->get_w();
        add_tool(fade_in = new TitleFade(client, this, &client->config.fade_in, x, y + 20));
        if( fade_in->get_w() > w1 ) w1 = fade_in->get_w();
-       x += w1 + 10;
+       x += w1 + margin;
 
        add_tool(fadeout_title = new BC_Title(x, y, _("Fade out (sec):")));
        w1 = fadeout_title->get_w();
        add_tool(fade_out = new TitleFade(client, this, &client->config.fade_out, x, y + 20));
        if( fade_out->get_w() > w1 ) w1 = fade_out->get_w();
-       x += w1 + 10;
+       x += w1 + margin;
 
-       add_tool(speed_title = new BC_Title(x, y, _("Speed:")));
+       add_tool(speed_title = new BC_Title(x, y1=y, _("Speed:")));
        w1 = speed_title->get_w();
-       speed = new TitleSpeed(client, this, x, y + 20);
+       y += speed_title->get_h() + 5;
+       speed = new TitleSpeed(client, this, x, y);
        speed->create_objects();
        if( speed->get_w() > w1 ) w1 = speed->get_w();
-       x += w1 + 10;
+       x += w1 + margin;
+       y2 = y + speed->get_h() + 10;
 
-       color_x = x;
-       color_y = y + 16;
-       x += COLOR_W + 5;
-       add_tool(color_button = new TitleColorButton(client, this, x, y + 16, 0));
-       x += color_button->get_w() + 5;
+       color_x = x3;  color_y = y = y1;
        color_thread = new TitleColorThread(client, this, 0);
-
-       x = color_x;
-       y += 50;
-
-       outline_color_x = x;
-       outline_color_y = y + 20;
-       x += COLOR_W + 5;
-       add_tool(outline_color_button = new TitleColorButton(client, this, x, y + 20, 1));
-       x += outline_color_button->get_w();
+       x1 = color_x + COLOR_W + 2*margin;
+       y1 = color_y + 5;
+       add_tool(color_button = new TitleColorButton(client, this, x1, y1));
+       y += COLOR_H + 5;
+       outline_color_x = x3;  outline_color_y = y;
        outline_color_thread = new TitleColorThread(client, this, 1);
+       y1 = outline_color_y + 5;
+       add_tool(outline_color_button = new TitleOutlineColorButton(client, this, x1, y1));
 
-       x = 10;
-//     y += 50;
-
+       x = 10;  y = y2;
        add_tool(outline_title = new BC_Title(x, y, _("Outline:")));
-       outline = new TitleOutline(client, this, x, y + outline_title->get_h() + margin);
+       y1 =  y + outline_title->get_h() + margin;
+       outline = new TitleOutline(client, this, x, y1);
        outline->create_objects();
-       x += outline->get_w() + margin;
-
-#ifndef X_HAVE_UTF8_STRING
-       add_tool(encoding_title = new BC_Title(x, y + 3, _("Encoding:")));
-       encoding = new TitleEncoding(client, this, x, y + encoding_title->get_h() + margin);
-       encoding->create_objects();
-       x += 100;
+       x += outline->get_w() + 2*margin;
+#ifdef USE_STOKER
+// to different to be used
+       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, x, y));
+       add_tool(timecode = new TitleTimecode(client, x1=x, y));
        x += timecode->get_w() + margin;
-
        add_tool(timecode_format = new TitleTimecodeFormat(client, x, y,
                Units::print_time_format(client->config.timecode_format, string)));
        timecode_format->create_objects();
-       x = 10;
        y += timecode_format->get_h() + margin;
 
-       add_tool(text_title = new BC_Title(x, y + 3, _("Text:")));
+       x = 10;
+       add_tool(background = new TitleBackground(client, this, x, y));
+       x += background->get_w() + margin;
+       add_tool(background_path = new TitleBackgroundPath(client, this, x, y));
+       x += background_path->get_w() + 2*margin;
+       add_tool(loop_playback = new TitleLoopPlayback(client, x, y));
+       y += loop_playback->get_h() + 10;
+
+       x = 10;
+       add_tool(text_title = new BC_Title(x, y, _("Text:")));
        y += text_title->get_h() + margin;
-       text = new TitleText(client, this, x, y, get_w() - x - 10, get_h() - y - 50);
+       x = margin;
+       text = new TitleText(client, this, x, y, get_w()-margin - x, get_h() - y - 10);
        text->create_objects();
-       update();
 
+       add_tool(cur_popup = new TitleCurPopup(client, this));
+       cur_popup->create_objects();
+
+       update();
        show_window(1);
 }
 
@@ -378,26 +375,21 @@ int TitleWindow::resize_event(int w, int h)
        title_x->reposition_window(title_x->get_x(), title_x->get_y());
        y_title->reposition_window(y_title->get_x(), y_title->get_y());
        title_y->reposition_window(title_y->get_x(), title_y->get_y());
+       w_title->reposition_window(w_title->get_x(), w_title->get_y());
+       title_w->reposition_window(title_w->get_x(), title_w->get_y());
+       h_title->reposition_window(h_title->get_x(), h_title->get_y());
+       title_h->reposition_window(title_h->get_x(), title_h->get_y());
        style_title->reposition_window(style_title->get_x(), style_title->get_y());
        italic->reposition_window(italic->get_x(), italic->get_y());
        bold->reposition_window(bold->get_x(), bold->get_y());
-#ifdef USE_OUTLINE
-       stroke->reposition_window(stroke->get_x(), stroke->get_y());
-#endif
+       drag->reposition_window(drag->get_x(), drag->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());
        pitch_title->reposition_window(pitch_title->get_x(), pitch_title->get_y());
        pitch->reposition_window(pitch->get_x(), pitch->get_y());
 
-#ifndef X_HAVE_UTF8_STRING
-       encoding->reposition_window(encoding->get_x(), encoding->get_y());
-#endif
-
        color_button->reposition_window(color_button->get_x(), color_button->get_y());
-#ifdef USE_OUTLINE
-       color_stroke_button->reposition_window(color_stroke_button->get_x(), color_stroke_button->get_y());
-#endif
        outline_color_button->reposition_window(outline_color_button->get_x(), outline_color_button->get_y());
        motion_title->reposition_window(motion_title->get_x(), motion_title->get_y());
        motion->reposition_window(motion->get_x(), motion->get_y());
@@ -409,19 +401,9 @@ int TitleWindow::resize_event(int w, int h)
        fadeout_title->reposition_window(fadeout_title->get_x(), fadeout_title->get_y());
        fade_out->reposition_window(fade_out->get_x(), fade_out->get_y());
        text_title->reposition_window(text_title->get_x(), text_title->get_y());
-#ifdef USE_OUTLINE
-       stroke_width->reposition_window(stroke_width->get_x(), stroke_width->get_y());
-       strokewidth_title->reposition_window(strokewidth_title->get_x(), strokewidth_title->get_y());
-#endif
        timecode->reposition_window(timecode->get_x(), timecode->get_y());
-
-       text->reposition_window(text->get_x(),
-               text->get_y(),
-               w - text->get_x() - 10,
+       text->reposition_window(text->get_x(), text->get_y(), w - text->get_x() - 10,
                BC_TextBox::pixels_to_rows(this, MEDIUMFONT, h - text->get_y() - 10));
-
-
-
        justify_title->reposition_window(justify_title->get_x(), justify_title->get_y());
        left->reposition_window(left->get_x(), left->get_y());
        center->reposition_window(center->get_x(), center->get_y());
@@ -437,17 +419,152 @@ int TitleWindow::resize_event(int w, int h)
        return 1;
 }
 
+int TitleWindow::grab_event(XEvent *event)
+{
+       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()
 {
        int current_font = font->get_number();
        current_font--;
-       if(current_font < 0) current_font = fonts.total - 1;
+       if( current_font < 0 ) current_font = fonts.total - 1;
 
-       if(current_font < 0 || current_font >= fonts.total) return;
+       if( current_font < 0 || current_font >= fonts.total ) return;
 
-       for(int i = 0; i < fonts.total; i++)
-       {
+       for( int i=0; i<fonts.total; ++i ) {
                fonts.values[i]->set_selected(i == current_font);
        }
 
@@ -460,12 +577,11 @@ void  TitleWindow::next_font()
 {
        int current_font = font->get_number();
        current_font++;
-       if(current_font >= fonts.total) current_font = 0;
+       if( current_font >= fonts.total ) current_font = 0;
 
-       if(current_font < 0 || current_font >= fonts.total) return;
+       if( current_font < 0 || current_font >= fonts.total ) return;
 
-       for(int i = 0; i < fonts.total; i++)
-       {
+       for( int i=0; i<fonts.total; ++i ) {
                fonts.values[i]->set_selected(i == current_font);
        }
 
@@ -502,36 +618,34 @@ void TitleWindow::update_justification()
 
 void TitleWindow::update()
 {
-       title_x->update((int64_t)client->config.x);
-       title_y->update((int64_t)client->config.y);
+       title_x->update((int64_t)client->config.title_x);
+       title_y->update((int64_t)client->config.title_y);
+       title_w->update((int64_t)client->config.title_w);
+       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);
-#ifdef USE_OUTLINE
-       stroke->update(client->config.style & BC_FONT_OUTLINE);
-#endif
        size->update(client->config.size);
-#ifndef X_HAVE_UTF8_STRING
-       encoding->update(client->config.encoding);
-#endif
        motion->update(TitleMain::motion_to_text(client->config.motion_strategy));
        loop->update(client->config.loop);
-       dropshadow->update((float)client->config.dropshadow);
+       dropshadow->update((int64_t)client->config.dropshadow);
        fade_in->update((float)client->config.fade_in);
        fade_out->update((float)client->config.fade_out);
-#ifdef USE_OUTLINE
-       stroke_width->update((float)client->config.stroke_width);
-#endif
        font->update(client->config.font);
        text->update(&client->config.wtext[0]);
        speed->update(client->config.pixels_per_second);
        outline->update((int64_t)client->config.outline_size);
+#ifdef USE_STOKER
+       stroker->update((int64_t)client->config.stroke_width);
+#endif
        timecode->update(client->config.timecode);
        timecode_format->update(client->config.timecode_format);
+       background->update(client->config.background);
+       background_path->update(client->config.background_path);
+       loop_playback->update((int64_t)client->config.loop_playback);
 
        char string[BCTEXTLEN];
-       for(int i = 0; i < lengthof(timeunit_formats); i++) {
-               if(timeunit_formats[i] == client->config.timecode_format)
-               {
+       for( int i=0; i<lengthof(timeunit_formats); ++i ) {
+               if( timeunit_formats[i] == client->config.timecode_format ) {
                        timecode_format->set_text(
                                Units::print_time_format(timeunit_formats[i], string));
                        break;
@@ -573,19 +687,17 @@ int TitleSizeTumble::handle_up_event()
 {
        int current_index = -1;
        int current_difference = -1;
-       for(int i = 0; i < window->sizes.size(); i++)
-       {
+       for( int i=0; i<window->sizes.size(); ++i ) {
                int size = atoi(window->sizes.get(i)->get_text());
-               if(current_index < 0 ||
-                       abs(size - client->config.size) < current_difference)
-               {
+               if( current_index < 0 ||
+                       abs(size - client->config.size) < current_difference ) {
                        current_index = i;
                        current_difference = abs(size - client->config.size);
                }
        }
 
        current_index++;
-       if(current_index >= window->sizes.size()) current_index = 0;
+       if( current_index >= window->sizes.size() ) current_index = 0;
 
 
        client->config.size = atoi(window->sizes.get(current_index)->get_text());
@@ -598,19 +710,17 @@ int TitleSizeTumble::handle_down_event()
 {
        int current_index = -1;
        int current_difference = -1;
-       for(int i = 0; i < window->sizes.size(); i++)
-       {
+       for( int i=0; i<window->sizes.size(); ++i ) {
                int size = atoi(window->sizes.get(i)->get_text());
-               if(current_index < 0 ||
-                       abs(size - client->config.size) < current_difference)
-               {
+               if( current_index < 0 ||
+                       abs(size - client->config.size) < current_difference ) {
                        current_index = i;
                        current_difference = abs(size - client->config.size);
                }
        }
 
        current_index--;
-       if(current_index < 0) current_index = window->sizes.size() - 1;
+       if( current_index < 0 ) current_index = window->sizes.size() - 1;
 
 
        client->config.size = atoi(window->sizes.get(current_index)->get_text());
@@ -684,7 +794,6 @@ void TitleSize::update(int size)
 TitlePitch::
 TitlePitch(TitleMain *client, TitleWindow *window, int x, int y, int *value)
  : BC_TumbleTextBox(window, *value, 0, INT_MAX, x, y, 64)
-
 {
        this->client = client;
        this->window = window;
@@ -698,41 +807,41 @@ TitlePitch::
 
 int TitlePitch::handle_event()
 {
-       *value = atof(get_text());
+       *value = atol(get_text());
        client->send_configure_change();
        return 1;
 }
 
-TitleColorButton::TitleColorButton(TitleMain *client,
-       TitleWindow *window,
-       int x,
-       int y,
-       int is_outline)
- : BC_GenericButton(x, y, is_outline ? _("Outline color...") : _("Color..."))
+TitleColorButton::TitleColorButton(TitleMain *client, TitleWindow *window, int x, int y)
+ : BC_GenericButton(x, y, _("Color..."))
 {
        this->client = client;
        this->window = window;
-       this->is_outline = is_outline;
 }
 int TitleColorButton::handle_event()
 {
-       if(is_outline)
-               window->outline_color_thread->start_window(client->config.outline_color,
-                       client->config.outline_alpha);
-       else
-               window->color_thread->start_window(client->config.color,
-                       client->config.alpha);
+       window->color_thread->start_window(client->config.color,
+               client->config.alpha);
+       return 1;
+}
+TitleOutlineColorButton::TitleOutlineColorButton(TitleMain *client, TitleWindow *window, int x, int y)
+ : BC_GenericButton(x, y, _("Outline color..."))
+{
+       this->client = client;
+       this->window = window;
+}
+int TitleOutlineColorButton::handle_event()
+{
+       window->outline_color_thread->start_window(client->config.outline_color,
+               client->config.outline_alpha);
        return 1;
 }
 
+
 TitleMotion::TitleMotion(TitleMain *client, TitleWindow *window, int x, int y)
- : BC_PopupTextBox(window,
-               &window->paths,
+ : BC_PopupTextBox(window, &window->paths,
                client->motion_to_text(client->config.motion_strategy),
-               x,
-               y,
-               120,
-               100)
+               x, y, 120, 100)
 {
        this->client = client;
        this->window = window;
@@ -783,7 +892,7 @@ int TitleTimecodeFormat::handle_event()
 void TitleTimecodeFormat::create_objects()
 {
        char string[BCTEXTLEN];
-       for(int i = 0; i < lengthof(timeunit_formats); i++) {
+       for( int i=0; i<lengthof(timeunit_formats); ++i ) {
                add_item(new BC_MenuItem(
                        Units::print_time_format(timeunit_formats[i], string)));
        }
@@ -793,9 +902,8 @@ void TitleTimecodeFormat::create_objects()
 int TitleTimecodeFormat::update(int timecode_format)
 {
        char string[BCTEXTLEN];
-       for(int i = 0; i < lengthof(timeunit_formats); i++) {
-               if(timeunit_formats[i] == timecode_format)
-               {
+       for( int i=0; i<lengthof(timeunit_formats); ++i ) {
+               if( timeunit_formats[i] == timecode_format ) {
                        set_text(Units::print_time_format(timeunit_formats[i], string));
                        break;
                }
@@ -803,16 +911,14 @@ int TitleTimecodeFormat::update(int timecode_format)
        return 0;
 }
 
-TitleFade::TitleFade(TitleMain *client,
-       TitleWindow *window,
-       double *value,
-       int x,
-       int y)
- : BC_TextBox(x, y, 90, 1, (float)*value)
+TitleFade::TitleFade(TitleMain *client, TitleWindow *window,
+       double *value, int x, int y)
+ : BC_TextBox(x, y, 80, 1, (float)*value)
 {
        this->client = client;
        this->window = window;
        this->value = value;
+       set_precision(2);
 }
 
 int TitleFade::handle_event()
@@ -823,14 +929,8 @@ int TitleFade::handle_event()
 }
 
 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)
+ : BC_PopupTextBox(window, &window->fonts, client->config.font,
+               x, y, 200, 500, LISTBOX_ICON_LIST)
 {
        this->client = client;
        this->window = window;
@@ -842,8 +942,8 @@ int TitleFont::handle_event()
        return 1;
 }
 
-TitleText::TitleText(TitleMain *client,
-       TitleWindow *window, int x, int y, int w, int h)
+TitleText::TitleText(TitleMain *client, TitleWindow *window,
+       int x, int y, int w, int h)
  : BC_ScrollTextBox(window, x, y, w,
                BC_TextBox::pixels_to_rows(window, MEDIUMFONT, h),
                client->config.wtext, 8192)
@@ -853,6 +953,16 @@ TitleText::TitleText(TitleMain *client,
 //printf("TitleText::TitleText %s\n", client->config.text);
 }
 
+int TitleText::button_press_event()
+{
+       if( get_buttonpress() == 3 ) {
+               window->cur_ibeam = get_ibeam_letter();
+               window->cur_popup->activate_menu();
+               return 1;
+       }
+       return BC_ScrollTextBox::button_press_event();
+}
+
 int TitleText::handle_event()
 {
        int len =  sizeof(client->config.wtext) / sizeof(wchar_t);
@@ -865,13 +975,8 @@ int TitleText::handle_event()
 
 
 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, (int64_t)client->config.dropshadow,
+       (int64_t)-1000, (int64_t)1000, x, y, 70)
 {
        this->client = client;
        this->window = window;
@@ -885,13 +990,8 @@ int TitleDropShadow::handle_event()
 
 
 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, (int64_t)client->config.outline_size,
+       (int64_t)0, (int64_t)1000, x, y, 70)
 {
        this->client = client;
        this->window = window;
@@ -903,78 +1003,88 @@ int TitleOutline::handle_event()
        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)
+{
+       this->client = client;
+       this->window = window;
+}
+int TitleStroker::handle_event()
+{
+       client->config.stroke_width = atol(get_text());
+       if( client->config.stroke_width > 1 )
+               client->config.style |= BC_FONT_OUTLINE;
+       else
+               client->config.style &= ~BC_FONT_OUTLINE;
+       client->send_configure_change();
+       return 1;
+}
+
 
 TitleX::TitleX(TitleMain *client, TitleWindow *window, int x, int y)
- : BC_TumbleTextBox(window,
-       (int64_t)client->config.x,
-       (int64_t)-2048,
-       (int64_t)2048,
-       x,
-       y,
-       60)
+ : BC_TumbleTextBox(window, (int64_t)client->config.title_x,
+       (int64_t)-32767, (int64_t)32767, x, y, 50)
 {
        this->client = client;
        this->window = window;
 }
 int TitleX::handle_event()
 {
-       client->config.x = atol(get_text());
+       client->config.title_x = atol(get_text());
        client->send_configure_change();
        return 1;
 }
 
 TitleY::TitleY(TitleMain *client, TitleWindow *window, int x, int y)
- : BC_TumbleTextBox(window,
-       (int64_t)client->config.y,
-       (int64_t)-2048,
-       (int64_t)2048,
-       x,
-       y,
-       60)
+ : BC_TumbleTextBox(window, (int64_t)client->config.title_y,
+       (int64_t)-32767, (int64_t)32767, x, y, 50)
 {
        this->client = client;
        this->window = window;
 }
 int TitleY::handle_event()
 {
-       client->config.y = atol(get_text());
+       client->config.title_y = atol(get_text());
        client->send_configure_change();
        return 1;
 }
 
-TitleStrokeW::TitleStrokeW(TitleMain *client,
-       TitleWindow *window,
-       int x,
-       int y)
- : BC_TumbleTextBox(window,
-       (float)client->config.stroke_width,
-       (float)-2048,
-       (float)2048,
-       x,
-       y,
-       60)
+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)
 {
        this->client = client;
        this->window = window;
 }
-int TitleStrokeW::handle_event()
+int TitleW::handle_event()
 {
-       client->config.stroke_width = atof(get_text());
+       client->config.title_w = atol(get_text());
        client->send_configure_change();
        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)
+{
+       this->client = client;
+       this->window = window;
+}
+int TitleH::handle_event()
+{
+       client->config.title_h = atol(get_text());
+       client->send_configure_change();
+       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,
-       70)
+ : BC_TumbleTextBox(window, (float)client->config.pixels_per_second,
+       (float)0, (float)1000, x, y, 100)
 {
        this->client = client;
+       set_precision(2);
+       set_increment(10);
 }
 
 
@@ -986,11 +1096,6 @@ int TitleSpeed::handle_event()
 }
 
 
-
-
-
-
-
 TitleLeft::TitleLeft(TitleMain *client, TitleWindow *window, int x, int y)
  : BC_Radial(x, y, client->config.hjustification == JUSTIFY_LEFT, _("Left"))
 {
@@ -1089,13 +1194,11 @@ TitleColorThread::TitleColorThread(TitleMain *client, TitleWindow *window, int i
 
 int TitleColorThread::handle_new_color(int output, int alpha)
 {
-       if(is_outline)
-       {
+       if( is_outline ) {
                client->config.outline_color = output;
                client->config.outline_alpha = alpha;
        }
-       else
-       {
+       else {
                client->config.color = output;
                client->config.alpha = alpha;
        }
@@ -1106,22 +1209,190 @@ int TitleColorThread::handle_new_color(int output, int alpha)
        window->unlock_window();
 
        client->send_configure_change();
+       return 1;
+}
 
+TitleDrag::TitleDrag(TitleMain *client, TitleWindow *window, int x, int y)
+ : BC_CheckBox(x, y, client->config.drag, _("Drag"))
+{
+       this->client = client;
+       this->window = window;
+}
 
+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;
 }
-TitleColorStrokeThread::TitleColorStrokeThread(TitleMain *client, TitleWindow *window)
- : ColorThread()
+
+TitleBackground::TitleBackground(TitleMain *client, TitleWindow *window, int x, int y)
+ : BC_CheckBox(x, y, client->config.background, _("Background:"))
 {
        this->client = client;
        this->window = window;
 }
 
-int TitleColorStrokeThread::handle_event(int output)
+int TitleBackground::handle_event()
 {
-       client->config.color_stroke = output;
-       window->update_color();
-       window->flush();
+       client->config.background = get_value();
+       client->send_configure_change();
+       return 1;
+}
+
+TitleBackgroundPath::TitleBackgroundPath(TitleMain *client, TitleWindow *window, int x, int y)
+ : BC_TextBox(x, y, 240, 1, client->config.background_path)
+{
+       this->client = client;
+       this->window = window;
+}
+
+int TitleBackgroundPath::handle_event()
+{
+       strncpy(client->config.background_path, get_text(), sizeof(client->config.background_path));
        client->send_configure_change();
        return 1;
 }
+
+TitleLoopPlayback::TitleLoopPlayback(TitleMain *client, int x, int y)
+ : BC_CheckBox(x, y, client->config.loop_playback, _("Loop playback"))
+{
+       this->client = client;
+}
+int TitleLoopPlayback::handle_event()
+{
+       client->config.loop_playback = get_value();
+       client->send_configure_change();
+       return 1;
+}
+
+
+TitleCurPopup::TitleCurPopup(TitleMain *client, TitleWindow *window)
+ : BC_PopupMenu(0, 0, 0, "", 0)
+{
+       this->client = client;
+       this->window = window;
+}
+int TitleCurPopup::handle_event()
+{
+printf("cur popup\n");
+       return 1;
+}
+void TitleCurPopup::create_objects()
+{
+       TitleCurItem *cur_item;
+       TitleCurSubMenu *sub_menu;
+       add_item(cur_item = new TitleCurItem(this, "nudge"));
+       cur_item->add_submenu(sub_menu = new TitleCurSubMenu(cur_item));
+       sub_menu->add_submenuitem(new TitleCurSubMenuItem(sub_menu,"nudge"));
+       sub_menu->add_submenuitem(new TitleCurSubMenuItem(sub_menu,"/nudge"));
+       add_item(cur_item = new TitleCurItem(this, "color"));
+       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"));
+       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"));
+       add_item(cur_item = new TitleCurItem(this, "font"));
+       cur_item->add_submenu(sub_menu = new TitleCurSubMenu(cur_item));
+       sub_menu->add_submenuitem(new TitleCurSubMenuItem(sub_menu,"font"));
+       sub_menu->add_submenuitem(new TitleCurSubMenuItem(sub_menu,"/font"));
+       add_item(cur_item = new TitleCurItem(this, "size"));
+       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"));
+       add_item(cur_item = new TitleCurItem(this, "bold"));
+       cur_item->add_submenu(sub_menu = new TitleCurSubMenu(cur_item));
+       sub_menu->add_submenuitem(new TitleCurSubMenuItem(sub_menu,"bold"));
+       sub_menu->add_submenuitem(new TitleCurSubMenuItem(sub_menu,"/bold"));
+       add_item(cur_item = new TitleCurItem(this, "italic"));
+       cur_item->add_submenu(sub_menu = new TitleCurSubMenu(cur_item));
+       sub_menu->add_submenuitem(new TitleCurSubMenuItem(sub_menu,"italic"));
+       sub_menu->add_submenuitem(new TitleCurSubMenuItem(sub_menu,"/italic"));
+       add_item(cur_item = new TitleCurItem(this, "caps"));
+       cur_item->add_submenu(sub_menu = new TitleCurSubMenu(cur_item));
+       sub_menu->add_submenuitem(new TitleCurSubMenuItem(sub_menu,"caps"));
+       sub_menu->add_submenuitem(new TitleCurSubMenuItem(sub_menu,"/caps"));
+       add_item(cur_item = new TitleCurItem(this, "ul"));
+       cur_item->add_submenu(sub_menu = new TitleCurSubMenu(cur_item));
+       sub_menu->add_submenuitem(new TitleCurSubMenuItem(sub_menu,"ul"));
+       sub_menu->add_submenuitem(new TitleCurSubMenuItem(sub_menu,"/ul"));
+       add_item(cur_item = new TitleCurItem(this, "blink"));
+       cur_item->add_submenu(sub_menu = new TitleCurSubMenu(cur_item));
+       sub_menu->add_submenuitem(new TitleCurSubMenuItem(sub_menu,"blink"));
+       sub_menu->add_submenuitem(new TitleCurSubMenuItem(sub_menu,"/blink"));
+       add_item(cur_item = new TitleCurItem(this, "fixed"));
+       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"));
+       add_item(cur_item = new TitleCurItem(this, "sup"));
+       cur_item->add_submenu(sub_menu = new TitleCurSubMenu(cur_item));
+       sub_menu->add_submenuitem(new TitleCurSubMenuItem(sub_menu,"sup"));
+       sub_menu->add_submenuitem(new TitleCurSubMenuItem(sub_menu,"/sup"));
+}
+
+TitleCurItem::TitleCurItem(TitleCurPopup *popup, const char *text)
+ : BC_MenuItem(text)
+{
+       this->popup = popup;
+}
+int TitleCurItem::handle_event()
+{
+       return 1;
+}
+
+TitleCurSubMenu::TitleCurSubMenu(TitleCurItem *cur_item)
+{
+       this->cur_item = cur_item;
+}
+TitleCurSubMenu::~TitleCurSubMenu()
+{
+}
+
+TitleCurSubMenuItem::TitleCurSubMenuItem(TitleCurSubMenu *submenu, const char *text)
+ : BC_MenuItem(text)
+{
+       this->submenu = submenu;
+}
+TitleCurSubMenuItem::~TitleCurSubMenuItem()
+{
+}
+int TitleCurSubMenuItem::handle_event()
+{
+       char id[BCSTRLEN];
+       sprintf(id, "<%s>",get_text());
+       int ilen = strlen(id);
+       TitleMain *client = submenu->cur_item->popup->client;
+       TitleWindow *window = submenu->cur_item->popup->window;
+
+       wchar_t *wtext = client->config.wtext;
+       int wsize = sizeof(client->config.wtext)-1;
+       int wlen = client->config.wlen;
+       int ibeam_letter = window->cur_ibeam;
+       if( ibeam_letter < 0 ) ibeam_letter = 0;
+       if( ibeam_letter > wlen ) ibeam_letter = wlen;
+
+       for( int i=wlen-1, j=wlen+ilen-1; i>=ibeam_letter; --i,--j ) {
+               if( j >= wsize ) continue;
+               wtext[j] = wtext[i];
+       }
+       for( int i=ibeam_letter, j=0; j<ilen; ++i,++j ) {
+               if( i >= wsize ) break;
+               wtext[i] = id[j];
+       }
+
+       if( (wlen+=ilen) > wsize ) wlen = wsize;
+       wtext[wlen] = 0;
+       window->text->update(wtext);
+       client->config.wlen = wlen;
+       client->send_configure_change();
+       return 1;
+}
+
+