ffmpeg filter memory leak, cursor hopper fix, added leaker.C, misc fixes
[goodguy/history.git] / cinelerra-5.1 / plugins / titler / titlerwindow.C
index ef89eb8ddd28a93a1d2ff23af2270109bfaa1c70..9bd8cfe7ee45ec5d4bd6700bfa9342dea87b5551 100644 (file)
@@ -20,7 +20,9 @@
  */
 
 #include "bcdisplayinfo.h"
+#include "bcdialog.h"
 #include "bcsignals.h"
+#include "browsebutton.h"
 #include "clip.h"
 #include "cstrdup.h"
 #include "automation.h"
 #include "cwindowgui.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"
@@ -37,8 +42,6 @@
 #include "titlerwindow.h"
 #include "bcfontentry.h"
 
-#include <wchar.h>
-
 static const int timeunit_formats[] =
 {
        TIME_HMS,
@@ -56,49 +59,79 @@ TitleWindow::TitleWindow(TitleMain *client)
 {
 //printf("TitleWindow::TitleWindow %d %d %d\n", __LINE__, client->config.window_w, client->config.window_h);
        this->client = client;
+
+       font_title = 0;
+       font = 0;
        font_tumbler = 0;
-       justify_title = 0;
+       x_title = 0; title_x = 0;
+       y_title = 0; title_y = 0;
+       w_title = 0; title_w = 0;
+       h_title = 0; title_h = 0;
+       dropshadow_title = 0; dropshadow = 0;
+       outline_title = 0;    outline = 0;
+       stroker_title = 0;    stroker = 0;
        style_title = 0;
+       italic = 0;
+       bold = 0;
+       drag = 0;
+       cur_popup = 0;
+       fonts_popup = 0;
+
+       color_x = color_y = 0;
+       outline_color_x = outline_color_y = 0;
+       drag_dx = drag_dy = dragging = 0;
+       cur_ibeam = -1;
+
        size_title = 0;
+       size = 0;
+       size_tumbler = 0;
+       pitch_title = 0;
+       pitch = 0;
+       encoding_title = 0;
+       encoding = 0;
+       color_button = 0;
+       color_thread = 0;
+       outline_color_button = 0;
+       outline_color_thread = 0;
        motion_title = 0;
-       speed_title = 0;
-       font_title = 0;
-       fadeout_title = 0;
+       motion = 0;
+       line_pitch = 0;
+       loop = 0;
        fadein_title = 0;
-       dropshadow_title = 0;
+       fade_in = 0;
+       fadeout_title = 0;
+       fade_out = 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;
+       text_chars = 0;
+       text_bfrsz = 0;
+       justify_title = 0;
+       left = 0;  center = 0;  right = 0;
+       top = 0;   mid = 0;     bottom = 0;
+       speed_title = 0;
+       speed = 0;
        timecode = 0;
-       bold = 0;
-       italic = 0;
-       dragging = 0;
-       fade_in = 0;
-       fade_out = 0;
-       color_button = 0;
-       color_x = color_y = 0;
-       color_thread = 0;
+       timecode_format = 0;
        background = 0;
        background_path = 0;
-       cur_ibeam = -1;
+       loop_playback = 0;
 }
 
-TitleWindow::~TitleWindow()
+void TitleWindow::done_event(int result)
 {
        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();
-       }
+       color_thread->close_window();
+       outline_color_thread->close_window();
+       color_popup->close_window();
+       png_popup->close_window();
+}
+
+TitleWindow::~TitleWindow()
+{
+       delete color_popup;
+       delete png_popup;
+       for( int i=0; i<fonts.size(); ++i )
+               delete fonts[i]->get_icon();
 
        sizes.remove_all_objects();
        delete timecode_format;
@@ -198,6 +231,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;
@@ -223,10 +257,13 @@ 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));
        if( drag->get_w() > w1 ) w1 = drag->get_w();
-       if( client->config.drag )
-               grab(client->server->mwindow->cwindow->gui);
+       if( client->config.drag ) {
+               if( !grab(client->server->mwindow->cwindow->gui) )
+                       eprintf("drag enabled, but compositor already grabbed\n");
+       }
 
        x += w1 + margin;
        add_tool(justify_title = new BC_Title(x, y, _("Justify:")));
@@ -325,8 +362,7 @@ 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();
@@ -344,12 +380,22 @@ void TitleWindow::create_objects()
        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;
+       x += background_path->get_w() + margin;
+       add_tool(background_browse = new BrowseButton(
+               client->server->mwindow->theme, this, background_path,
+               x, y, "", _("background media"), _("Select background media path")));
+       x += background_browse->get_w() + 3*margin;
        add_tool(loop_playback = new TitleLoopPlayback(client, x, y));
        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);
@@ -357,9 +403,12 @@ 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);
 
-       update();
        show_window(1);
+       update();
 }
 
 int TitleWindow::resize_event(int w, int h)
@@ -421,6 +470,25 @@ int TitleWindow::resize_event(int w, int h)
 
 int TitleWindow::grab_event(XEvent *event)
 {
+       switch( event->type ) {
+       case ButtonPress: break;
+       case ButtonRelease: break;
+       case MotionNotify: break;
+       default: return 0;
+       }
+
+       MWindow *mwindow = client->server->mwindow;
+       CWindowGUI *cwindow_gui = mwindow->cwindow->gui;
+       CWindowCanvas *canvas = cwindow_gui->canvas;
+       int cx, cy;  cwindow_gui->get_relative_cursor_xy(cx, cy);
+       cx -= mwindow->theme->ccanvas_x;
+       cy -= mwindow->theme->ccanvas_y;
+
+       if( !dragging ) {
+               if( cx < 0 || cx >= mwindow->theme->ccanvas_w ) return 0;
+               if( cy < 0 || cy >= mwindow->theme->ccanvas_h ) return 0;
+       }
+
        switch( event->type ) {
        case ButtonPress:
                if( !dragging ) break;
@@ -430,15 +498,13 @@ int TitleWindow::grab_event(XEvent *event)
                dragging = 0;
                return 1;
        case MotionNotify:
-               if( dragging ) break;
+               if( !dragging ) return 0;
+               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();
+
+       float cursor_x = cx, cursor_y = cy;
        canvas->canvas_to_output(mwindow->edl, 0, cursor_x, cursor_y);
        int64_t position = client->get_source_position();
        float projector_x, projector_y, projector_z;
@@ -460,7 +526,7 @@ int TitleWindow::grab_event(XEvent *event)
        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
+                    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;
@@ -570,6 +636,7 @@ void TitleWindow::previous_font()
 
        font->update(fonts.values[current_font]->get_text());
        strcpy(client->config.font, fonts.values[current_font]->get_text());
+       check_style(client->config.font,1);
        client->send_configure_change();
 }
 
@@ -587,10 +654,27 @@ void  TitleWindow::next_font()
 
        font->update(fonts.values[current_font]->get_text());
        strcpy(client->config.font, fonts.values[current_font]->get_text());
+       check_style(client->config.font,1);
        client->send_configure_change();
 }
 
-
+int TitleWindow::insert_ibeam(const char *txt, int ofs)
+{
+       int ibeam = cur_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();
+       return 1;
+}
 
 void TitleWindow::update_color()
 {
@@ -616,6 +700,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);
@@ -631,10 +723,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);
@@ -652,6 +745,7 @@ void TitleWindow::update()
                }
        }
        update_justification();
+       update_stats();
        update_color();
 }
 
@@ -763,13 +857,7 @@ int TitleItalic::handle_event()
 
 
 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;
@@ -813,7 +901,7 @@ int TitlePitch::handle_event()
 }
 
 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;
@@ -928,9 +1016,40 @@ int TitleFade::handle_event()
        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;
@@ -938,6 +1057,7 @@ TitleFont::TitleFont(TitleMain *client, TitleWindow *window, int x, int y)
 int TitleFont::handle_event()
 {
        strcpy(client->config.font, get_text());
+       window->check_style(client->config.font, 1);
        client->send_configure_change();
        return 1;
 }
@@ -965,13 +1085,54 @@ 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);
+       window->update_stats();
        client->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)
@@ -1003,6 +1164,7 @@ 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)
@@ -1012,8 +1174,8 @@ TitleStroker::TitleStroker(TitleMain *client, TitleWindow *window, int x, int y)
 }
 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;
@@ -1185,7 +1347,7 @@ int TitleBottom::handle_event()
 
 
 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;
@@ -1222,11 +1384,16 @@ TitleDrag::TitleDrag(TitleMain *client, TitleWindow *window, int x, int y)
 int TitleDrag::handle_event()
 {
        int value = get_value();
-       client->config.drag = value;
-       if( value )
-               window->grab(client->server->mwindow->cwindow->gui);
+       CWindowGUI *cwindow_gui = client->server->mwindow->cwindow->gui;
+       if( value ) {
+               if( !window->grab(cwindow_gui) ) {
+                       update(value = 0);
+                       flicker(10,50);
+               }
+       }
        else
-               window->ungrab(client->server->mwindow->cwindow->gui);
+               window->ungrab(cwindow_gui);
+       client->config.drag = value;
        client->send_configure_change();
        return 1;
 }
@@ -1280,61 +1447,93 @@ TitleCurPopup::TitleCurPopup(TitleMain *client, TitleWindow *window)
 }
 int TitleCurPopup::handle_event()
 {
-printf("cur popup\n");
        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_submenuitem(new TitleCurSubMenuItem(sub_menu,"nudge"));
-       sub_menu->add_submenuitem(new TitleCurSubMenuItem(sub_menu,"/nudge"));
-       add_item(cur_item = new TitleCurItem(this, "color"));
+       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,"color"));
-       sub_menu->add_submenuitem(new TitleCurSubMenuItem(sub_menu,"/color"));
-       add_item(cur_item = new TitleCurItem(this, "alpha"));
+       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,"alpha"));
-       sub_menu->add_submenuitem(new TitleCurSubMenuItem(sub_menu,"/alpha"));
-       add_item(cur_item = new TitleCurItem(this, "font"));
+       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,"font"));
-       sub_menu->add_submenuitem(new TitleCurSubMenuItem(sub_menu,"/font"));
-       add_item(cur_item = new TitleCurItem(this, "size"));
+       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,"size"));
-       sub_menu->add_submenuitem(new TitleCurSubMenuItem(sub_menu,"/size"));
-       add_item(cur_item = new TitleCurItem(this, "bold"));
+       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,"bold"));
-       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_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"));
+       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,"caps"));
-       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 -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,"ul"));
-       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 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,"blink"));
-       sub_menu->add_submenuitem(new TitleCurSubMenuItem(sub_menu,"/blink"));
-       add_item(cur_item = new TitleCurItem(this, "fixed"));
+       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,"fixed"));
-       sub_menu->add_submenuitem(new TitleCurSubMenuItem(sub_menu,"/fixed"));
-       add_item(cur_item = new TitleCurItem(this, "sup"));
+       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_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"));
+       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_subitem(POPUP_PNG,"%s %s", item, _("file"));
 }
 
 TitleCurItem::TitleCurItem(TitleCurPopup *popup, const char *text)
@@ -1355,44 +1554,139 @@ 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()
 {
 }
 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];
+       TitleCurPopup *popup = submenu->cur_item->popup;
+       TitleWindow *window = popup->window;
+       const char *item_text = get_text();
+       int ofs = *item_text == '/' ? 0 : -1;
+       switch( popup_type ) {
+       case POPUP_FONT: {
+               int px, py;
+               window->get_pop_cursor_xy(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;
        }
-       for( int i=ibeam_letter, j=0; j<ilen; ++i,++j ) {
-               if( i >= wsize ) break;
-               wtext[i] = id[j];
+       char txt[BCSTRLEN];
+       sprintf(txt, "<%s>", item_text);
+       return window->insert_ibeam(txt, ofs);
+}
+
+TitleFontsPopup::TitleFontsPopup(TitleMain *client, TitleWindow *window)
+ : BC_ListBox(-1, -1, 1, 1, LISTBOX_ICON_LIST,
+       &window->fonts, 0, 0, 1, 0, 1)
+{
+       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();
+}
 
-       if( (wlen+=ilen) > wsize ) wlen = wsize;
-       wtext[wlen] = 0;
-       window->text->update(wtext);
-       client->config.wlen = wlen;
-       client->send_configure_change();
+int TitleFontsPopup::handle_event()
+{
+       deactivate();
+       BC_ListBoxItem *item = get_selection(0, 0);
+       if( !item ) return 1;
+       const char *item_text = item->get_text();
+       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_xy(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;
+}