colorpick rework, color popup for titler, color convert fixes
[goodguy/history.git] / cinelerra-5.1 / plugins / titler / titlerwindow.C
1
2 /*
3  * CINELERRA
4  * Copyright (C) 1997-2014 Adam Williams <broadcast at earthling dot net>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  *
20  */
21
22 #include "bcdisplayinfo.h"
23 #include "bcsignals.h"
24 #include "browsebutton.h"
25 #include "clip.h"
26 #include "cstrdup.h"
27 #include "automation.h"
28 #include "cwindow.h"
29 #include "cwindowgui.h"
30 #include "edl.h"
31 #include "edlsession.h"
32 #include "language.h"
33 #include "mwindow.h"
34 #include "plugin.h"
35 #include "pluginserver.h"
36 #include "theme.h"
37 #include "track.h"
38 #include "titlerwindow.h"
39 #include "bcfontentry.h"
40
41 #include <wchar.h>
42
43 static const int timeunit_formats[] =
44 {
45         TIME_HMS,
46         TIME_SECONDS,
47         TIME_HMSF,
48         TIME_SAMPLES,
49         TIME_SAMPLES_HEX,
50         TIME_FRAMES,
51         TIME_FEET_FRAMES
52 };
53
54 TitleWindow::TitleWindow(TitleMain *client)
55  : PluginClientWindow(client,
56         client->config.window_w, client->config.window_h, 100, 100, 1)
57 {
58 //printf("TitleWindow::TitleWindow %d %d %d\n", __LINE__, client->config.window_w, client->config.window_h);
59         this->client = client;
60
61         font_title = 0;
62         font = 0;
63         font_tumbler = 0;
64         x_title = 0; title_x = 0;
65         y_title = 0; title_y = 0;
66         w_title = 0; title_w = 0;
67         h_title = 0; title_h = 0;
68         dropshadow_title = 0; dropshadow = 0;
69         outline_title = 0;    outline = 0;
70         stroker_title = 0;    stroker = 0;
71         style_title = 0;
72         italic = 0;
73         bold = 0;
74         drag = 0;
75         cur_popup = 0;
76         fonts_popup = 0;
77
78         color_x = color_y = 0;
79         outline_color_x = outline_color_y = 0;
80         drag_dx = drag_dy = dragging = 0;
81         cur_ibeam = -1;
82
83         size_title = 0;
84         size = 0;
85         size_tumbler = 0;
86         pitch_title = 0;
87         pitch = 0;
88         encoding_title = 0;
89         encoding = 0;
90         color_button = 0;
91         color_thread = 0;
92         outline_color_button = 0;
93         outline_color_thread = 0;
94         motion_title = 0;
95         motion = 0;
96         line_pitch = 0;
97         loop = 0;
98         fadein_title = 0;
99         fade_in = 0;
100         fadeout_title = 0;
101         fade_out = 0;
102         text_title = 0;
103         text = 0;
104         justify_title = 0;
105         left = 0;  center = 0;  right = 0;
106         top = 0;   mid = 0;     bottom = 0;
107         speed_title = 0;
108         speed = 0;
109         timecode = 0;
110         timecode_format = 0;
111         background = 0;
112         background_path = 0;
113         loop_playback = 0;
114 }
115
116 TitleWindow::~TitleWindow()
117 {
118         ungrab(client->server->mwindow->cwindow->gui);
119         delete fonts_popup;
120         for( int i=0; i<fonts.size(); ++i )
121                 delete fonts[i]->get_icon();
122
123         sizes.remove_all_objects();
124         delete timecode_format;
125         delete color_thread;
126         delete title_x;
127         delete title_y;
128 }
129
130 void TitleWindow::create_objects()
131 {
132         int x = 10, y = 10;
133         int margin = client->get_theme()->widget_border;
134         char string[BCTEXTLEN];
135
136 #define COLOR_W 50
137 #define COLOR_H 30
138         client->build_previews(this);
139
140         sizes.append(new BC_ListBoxItem("8"));
141         sizes.append(new BC_ListBoxItem("9"));
142         sizes.append(new BC_ListBoxItem("10"));
143         sizes.append(new BC_ListBoxItem("11"));
144         sizes.append(new BC_ListBoxItem("12"));
145         sizes.append(new BC_ListBoxItem("13"));
146         sizes.append(new BC_ListBoxItem("14"));
147         sizes.append(new BC_ListBoxItem("16"));
148         sizes.append(new BC_ListBoxItem("18"));
149         sizes.append(new BC_ListBoxItem("20"));
150         sizes.append(new BC_ListBoxItem("22"));
151         sizes.append(new BC_ListBoxItem("24"));
152         sizes.append(new BC_ListBoxItem("26"));
153         sizes.append(new BC_ListBoxItem("28"));
154         sizes.append(new BC_ListBoxItem("32"));
155         sizes.append(new BC_ListBoxItem("36"));
156         sizes.append(new BC_ListBoxItem("40"));
157         sizes.append(new BC_ListBoxItem("48"));
158         sizes.append(new BC_ListBoxItem("56"));
159         sizes.append(new BC_ListBoxItem("64"));
160         sizes.append(new BC_ListBoxItem("72"));
161         sizes.append(new BC_ListBoxItem("100"));
162         sizes.append(new BC_ListBoxItem("128"));
163         sizes.append(new BC_ListBoxItem("256"));
164         sizes.append(new BC_ListBoxItem("512"));
165         sizes.append(new BC_ListBoxItem("1024"));
166
167         paths.append(new BC_ListBoxItem(TitleMain::motion_to_text(NO_MOTION)));
168         paths.append(new BC_ListBoxItem(TitleMain::motion_to_text(BOTTOM_TO_TOP)));
169         paths.append(new BC_ListBoxItem(TitleMain::motion_to_text(TOP_TO_BOTTOM)));
170         paths.append(new BC_ListBoxItem(TitleMain::motion_to_text(RIGHT_TO_LEFT)));
171         paths.append(new BC_ListBoxItem(TitleMain::motion_to_text(LEFT_TO_RIGHT)));
172
173
174
175 // Construct font list
176         ArrayList<BC_FontEntry*> *fontlist = get_resources()->fontlist;
177
178         for( int i=0; i<fontlist->size(); ++i ) {
179                 int exists = 0;
180                 for( int j=0; j<fonts.size(); ++j ) {
181                         if( !strcasecmp(fonts.get(j)->get_text(),
182                                 fontlist->get(i)->displayname) ) {
183                                 exists = 1;
184                                 break;
185                         }
186                 }
187
188                 BC_ListBoxItem *item = 0;
189                 if( !exists ) {
190                         fonts.append(item = new
191                                 BC_ListBoxItem(fontlist->get(i)->displayname));
192                         if( !strcmp(client->config.font, item->get_text()) )
193                                 item->set_selected(1);
194                         if( fontlist->values[i]->image ) {
195                                 VFrame *vframe = fontlist->get(i)->image;
196                                 BC_Pixmap *icon = new BC_Pixmap(this, vframe, PIXMAP_ALPHA);
197                                 item->set_icon(icon);
198                                 item->set_icon_vframe(vframe);
199                         }
200                 }
201         }
202
203 // Sort font list
204         int done = 0;
205         while(!done) {
206                 done = 1;
207                 for( int i=0; i<fonts.size()-1; ++i ) {
208                         if( strcmp(fonts.values[i]->get_text(),
209                                 fonts.values[i + 1]->get_text()) > 0 ) {
210                                 BC_ListBoxItem *temp = fonts.values[i + 1];
211                                 fonts.values[i + 1] = fonts.values[i];
212                                 fonts.values[i] = temp;
213                                 done = 0;
214                         }
215                 }
216         }
217
218         add_tool(font_title = new BC_Title(x, y, _("Font:")));
219         font = new TitleFont(client, this, x, y + font_title->get_h());
220         font->create_objects();
221         x += font->get_w();
222         add_subwindow(font_tumbler = new TitleFontTumble(client, this, x, y+margin));
223         x += font_tumbler->get_w() + margin;
224
225         int x1 = x, y1 = y;
226         add_tool(size_title = new BC_Title(x1, y1+margin, _("Size:")));
227         sprintf(string, "%.2f", client->config.size);
228         x1 += size_title->get_w() + margin;
229         size = new TitleSize(client, this, x1, y1+margin, string);
230         size->create_objects();
231         int x2 = x1 + size->get_w(), y2 = y1 + size->get_h() + margin;
232         add_subwindow(size_tumbler = new TitleSizeTumble(client, this, x2, y1+margin));
233
234         add_tool(pitch_title = new BC_Title(x-5, y2+margin, _("Pitch:")));
235         pitch = new TitlePitch(client, this, x1, y2+margin, &client->config.line_pitch);
236         pitch->create_objects();
237
238         int x3 = x2 + size_tumbler->get_w() + 50;
239         int y3 = pitch->get_y() + pitch->get_h();
240
241         add_tool(style_title = new BC_Title(x=x3, y, _("Style:")));
242         add_tool(italic = new TitleItalic(client, this, x, y + 20));
243         int w1 = italic->get_w();
244         add_tool(bold = new TitleBold(client, this, x, y + 50));
245         if( bold->get_w() > w1 ) w1 = bold->get_w();
246         add_tool(drag = new TitleDrag(client, this, x, y + 80));
247         if( drag->get_w() > w1 ) w1 = drag->get_w();
248         if( client->config.drag )
249                 grab(client->server->mwindow->cwindow->gui);
250
251         x += w1 + margin;
252         add_tool(justify_title = new BC_Title(x, y, _("Justify:")));
253         add_tool(left = new TitleLeft(client, this, x, y + 20));
254         w1 = left->get_w();
255         add_tool(center = new TitleCenter(client, this, x, y + 50));
256         if( center->get_w() > w1 ) w1 = center->get_w();
257         add_tool(right = new TitleRight(client, this, x, y + 80));
258         if( right->get_w() > w1 ) w1 = right->get_w();
259
260         x += w1 + margin;
261         add_tool(top = new TitleTop(client, this, x, y + 20));
262         add_tool(mid = new TitleMid(client, this, x, y + 50));
263         add_tool(bottom= new TitleBottom(client, this, x, y + 80));
264
265         x = margin;
266         y = y3+10;
267
268         w1 = BC_Title::calculate_w(this, _("X:"));
269         if( (x1 = BC_Title::calculate_w(this, _("Y:"))) > w1 ) w1 = x1;
270         if( (x1 = BC_Title::calculate_w(this, _("W:"))) > w1 ) w1 = x1;
271         if( (x1 = BC_Title::calculate_w(this, _("H:"))) > w1 ) w1 = x1;
272         add_tool(x_title = new BC_Title(x1=x, y, _("X:")));
273         x1 += w1;
274         title_x = new TitleX(client, this, x1, y);
275         title_x->create_objects();
276         x1 += title_x->get_w()+margin;
277         add_tool(y_title = new BC_Title(x1, y, _("Y:")));
278         x1 += w1;
279         title_y = new TitleY(client, this, x1, y);
280         title_y->create_objects();
281         x1 += title_y->get_w();
282         y1 = y + title_y->get_h();
283
284         add_tool(w_title = new BC_Title(x1=x, y1, _("W:")));
285         x1 += w1;
286         title_w = new TitleW(client, this, x1, y1);
287         title_w->create_objects();
288         x1 += title_w->get_w()+margin;
289         add_tool(h_title = new BC_Title(x1, y1, _("H:")));
290         x1 += w1;
291         title_h = new TitleH(client, this, x1, y1);
292         title_h->create_objects();
293         x1 += title_h->get_w();
294
295         x = x1+2*margin;
296         add_tool(motion_title = new BC_Title(x1=x, y, _("Motion:")));
297         x1 += motion_title->get_w()+margin;
298         motion = new TitleMotion(client, this, x1, y);
299         motion->create_objects();
300         add_tool(loop = new TitleLoop(client, x, y1));
301         x = margin;    y = y1 + loop->get_h()+20;
302
303         add_tool(dropshadow_title = new BC_Title(x, y, _("Drop shadow:")));
304         w1 = dropshadow_title->get_w();
305         dropshadow = new TitleDropShadow(client, this, x, y + 20);
306         dropshadow->create_objects();
307         if( dropshadow->get_w() > w1 ) w1 = dropshadow->get_w();
308         x += w1 + margin;
309
310         add_tool(fadein_title = new BC_Title(x, y, _("Fade in (sec):")));
311         w1 = fadein_title->get_w();
312         add_tool(fade_in = new TitleFade(client, this, &client->config.fade_in, x, y + 20));
313         if( fade_in->get_w() > w1 ) w1 = fade_in->get_w();
314         x += w1 + margin;
315
316         add_tool(fadeout_title = new BC_Title(x, y, _("Fade out (sec):")));
317         w1 = fadeout_title->get_w();
318         add_tool(fade_out = new TitleFade(client, this, &client->config.fade_out, x, y + 20));
319         if( fade_out->get_w() > w1 ) w1 = fade_out->get_w();
320         x += w1 + margin;
321
322         add_tool(speed_title = new BC_Title(x, y1=y, _("Speed:")));
323         w1 = speed_title->get_w();
324         y += speed_title->get_h() + 5;
325         speed = new TitleSpeed(client, this, x, y);
326         speed->create_objects();
327         if( speed->get_w() > w1 ) w1 = speed->get_w();
328         x += w1 + margin;
329         y2 = y + speed->get_h() + 10;
330
331         color_x = x3;  color_y = y = y1;
332         color_thread = new TitleColorThread(client, this, 0);
333         x1 = color_x + COLOR_W + 2*margin;
334         y1 = color_y + 5;
335         add_tool(color_button = new TitleColorButton(client, this, x1, y1));
336         y += COLOR_H + 5;
337         outline_color_x = x3;  outline_color_y = y;
338         outline_color_thread = new TitleColorThread(client, this, 1);
339         y1 = outline_color_y + 5;
340         add_tool(outline_color_button = new TitleOutlineColorButton(client, this, x1, y1));
341
342         x = 10;  y = y2;
343         add_tool(outline_title = new BC_Title(x, y, _("Outline:")));
344         y1 =  y + outline_title->get_h() + margin;
345         outline = new TitleOutline(client, this, x, y1);
346         outline->create_objects();
347         x += outline->get_w() + 2*margin;
348 #ifdef USE_STOKER
349 // to different to be used
350         add_tool(stroker_title = new BC_Title(x, y, _("Stroker:")));
351         stroker = new TitleStroker(client, this, x, y1);
352         stroker->create_objects();
353         x += stroker->get_w() + margin;
354 #endif
355         y += outline_title->get_h() + margin;
356         add_tool(timecode = new TitleTimecode(client, x1=x, y));
357         x += timecode->get_w() + margin;
358         add_tool(timecode_format = new TitleTimecodeFormat(client, x, y,
359                 Units::print_time_format(client->config.timecode_format, string)));
360         timecode_format->create_objects();
361         y += timecode_format->get_h() + margin;
362
363         x = 10;
364         add_tool(background = new TitleBackground(client, this, x, y));
365         x += background->get_w() + margin;
366         add_tool(background_path = new TitleBackgroundPath(client, this, x, y));
367         x += background_path->get_w() + margin;
368         add_tool(background_browse = new BrowseButton(
369                 client->server->mwindow->theme, this, background_path,
370                 x, y, 0, _("background media"), _("Select background media path")));
371         x += background_browse->get_w() + 3*margin;
372         add_tool(loop_playback = new TitleLoopPlayback(client, x, y));
373         y += loop_playback->get_h() + 10;
374
375         x = 10;
376         add_tool(text_title = new BC_Title(x, y, _("Text:")));
377         y += text_title->get_h() + margin;
378         x = margin;
379         text = new TitleText(client, this, x, y, get_w()-margin - x, get_h() - y - 10);
380         text->create_objects();
381
382         add_tool(cur_popup = new TitleCurPopup(client, this));
383         cur_popup->create_objects();
384         add_tool(fonts_popup = new TitleFontsPopup(client, this));
385         color_popup = new TitleColorPopup(client, this);
386
387         show_window(1);
388         update();
389 }
390
391 int TitleWindow::resize_event(int w, int h)
392 {
393         client->config.window_w = w;
394         client->config.window_h = h;
395
396         clear_box(0, 0, w, h);
397         font_title->reposition_window(font_title->get_x(), font_title->get_y());
398         font->reposition_window(font->get_x(), font->get_y());
399         font_tumbler->reposition_window(font_tumbler->get_x(), font_tumbler->get_y());
400         x_title->reposition_window(x_title->get_x(), x_title->get_y());
401         title_x->reposition_window(title_x->get_x(), title_x->get_y());
402         y_title->reposition_window(y_title->get_x(), y_title->get_y());
403         title_y->reposition_window(title_y->get_x(), title_y->get_y());
404         w_title->reposition_window(w_title->get_x(), w_title->get_y());
405         title_w->reposition_window(title_w->get_x(), title_w->get_y());
406         h_title->reposition_window(h_title->get_x(), h_title->get_y());
407         title_h->reposition_window(title_h->get_x(), title_h->get_y());
408         style_title->reposition_window(style_title->get_x(), style_title->get_y());
409         italic->reposition_window(italic->get_x(), italic->get_y());
410         bold->reposition_window(bold->get_x(), bold->get_y());
411         drag->reposition_window(drag->get_x(), drag->get_y());
412         size_title->reposition_window(size_title->get_x(), size_title->get_y());
413         size->reposition_window(size->get_x(), size->get_y());
414         size_tumbler->reposition_window(size_tumbler->get_x(), size_tumbler->get_y());
415         pitch_title->reposition_window(pitch_title->get_x(), pitch_title->get_y());
416         pitch->reposition_window(pitch->get_x(), pitch->get_y());
417
418         color_button->reposition_window(color_button->get_x(), color_button->get_y());
419         outline_color_button->reposition_window(outline_color_button->get_x(), outline_color_button->get_y());
420         motion_title->reposition_window(motion_title->get_x(), motion_title->get_y());
421         motion->reposition_window(motion->get_x(), motion->get_y());
422         loop->reposition_window(loop->get_x(), loop->get_y());
423         dropshadow_title->reposition_window(dropshadow_title->get_x(), dropshadow_title->get_y());
424         dropshadow->reposition_window(dropshadow->get_x(), dropshadow->get_y());
425         fadein_title->reposition_window(fadein_title->get_x(), fadein_title->get_y());
426         fade_in->reposition_window(fade_in->get_x(), fade_in->get_y());
427         fadeout_title->reposition_window(fadeout_title->get_x(), fadeout_title->get_y());
428         fade_out->reposition_window(fade_out->get_x(), fade_out->get_y());
429         text_title->reposition_window(text_title->get_x(), text_title->get_y());
430         timecode->reposition_window(timecode->get_x(), timecode->get_y());
431         text->reposition_window(text->get_x(), text->get_y(), w - text->get_x() - 10,
432                 BC_TextBox::pixels_to_rows(this, MEDIUMFONT, h - text->get_y() - 10));
433         justify_title->reposition_window(justify_title->get_x(), justify_title->get_y());
434         left->reposition_window(left->get_x(), left->get_y());
435         center->reposition_window(center->get_x(), center->get_y());
436         right->reposition_window(right->get_x(), right->get_y());
437         top->reposition_window(top->get_x(), top->get_y());
438         mid->reposition_window(mid->get_x(), mid->get_y());
439         bottom->reposition_window(bottom->get_x(), bottom->get_y());
440         speed_title->reposition_window(speed_title->get_x(), speed_title->get_y());
441         speed->reposition_window(speed->get_x(), speed->get_y());
442         update_color();
443         flash();
444
445         return 1;
446 }
447
448 int TitleWindow::grab_event(XEvent *event)
449 {
450         switch( event->type ) {
451         case ButtonPress:
452                 if( !dragging ) break;
453                 return 1;
454         case ButtonRelease:
455                 if( !dragging ) return 0;
456                 dragging = 0;
457                 return 1;
458         case MotionNotify:
459                 if( dragging ) break;
460         default:
461                 return 0;
462         }
463         MWindow *mwindow = client->server->mwindow;
464         CWindowGUI *cwindow_gui = mwindow->cwindow->gui;
465         CWindowCanvas *canvas = cwindow_gui->canvas;
466         float cursor_x = canvas->get_canvas()->get_relative_cursor_x();
467         float cursor_y = canvas->get_canvas()->get_relative_cursor_y();
468         canvas->canvas_to_output(mwindow->edl, 0, cursor_x, cursor_y);
469         int64_t position = client->get_source_position();
470         float projector_x, projector_y, projector_z;
471         Track *track = client->server->plugin->track;
472         int track_w = track->track_w, track_h = track->track_h;
473         track->automation->get_projector(
474                 &projector_x, &projector_y, &projector_z,
475                 position, PLAY_FORWARD);
476         projector_x += mwindow->edl->session->output_w / 2;
477         projector_y += mwindow->edl->session->output_h / 2;
478         cursor_x = (cursor_x - projector_x) / projector_z + track_w / 2;
479         cursor_y = (cursor_y - projector_y) / projector_z + track_h / 2;
480         int title_x = client->config.title_x, title_y = client->config.title_y;
481         int title_w = client->config.title_w, title_h = client->config.title_h;
482         if( !title_w ) title_w = track_w;
483         if( !title_h ) title_h = track_h;
484         int r = MIN(track_w, track_h)/100 + 2;
485         int x0 = title_x, x1 = title_x+(title_w+1)/2, x2 = title_x+title_w;
486         int y0 = title_y, y1 = title_y+(title_h+1)/2, y2 = title_y+title_h;
487         int drag_dx = 0, drag_dy = 0;
488         if( !dragging ) {  // clockwise
489                      if( abs(drag_dx = cursor_x-x0) < r &&       // x0,y0
490                          abs(drag_dy = cursor_y-y0) < r ) dragging = 1;
491                 else if( abs(drag_dx = cursor_x-x1) < r &&  // x1,y0
492                          abs(drag_dy = cursor_y-y0) < r ) dragging = 2;
493                 else if( abs(drag_dx = cursor_x-x2) < r &&  // x2,y0
494                          abs(drag_dy = cursor_y-y0) < r ) dragging = 3;
495                 else if( abs(drag_dx = cursor_x-x2) < r &&  // x2,y1
496                          abs(drag_dy = cursor_y-y1) < r ) dragging = 4;
497                 else if( abs(drag_dx = cursor_x-x2) < r &&  // x2,y2
498                          abs(drag_dy = cursor_y-y2) < r ) dragging = 5;
499                 else if( abs(drag_dx = cursor_x-x1) < r &&  // x1,y2
500                          abs(drag_dy = cursor_y-y2) < r ) dragging = 6;
501                 else if( abs(drag_dx = cursor_x-x0) < r &&  // x0,y2
502                          abs(drag_dy = cursor_y-y2) < r ) dragging = 7;
503                 else if( abs(drag_dx = cursor_x-x0) < r &&  // x0,y1
504                          abs(drag_dy = cursor_y-y1) < r ) dragging = 8;
505                 else if( abs(drag_dx = cursor_x-x1) < r &&  // x1,y1
506                          abs(drag_dy = cursor_y-y1) < r ) dragging = 9;
507                         return 0;
508         }
509         switch( dragging ) {
510         case 1: { // x0,y0
511                 int cur_x = cursor_x - drag_dx, dx = cur_x - x0;
512                 int cur_y = cursor_y - drag_dy, dy = cur_y - y0;
513                 if( !dx && !dy ) return 1;
514                 int cur_w = title_w - dx;  if( cur_w < 1 ) cur_w = 1;
515                 int cur_h = title_h - dy;  if( cur_h < 1 ) cur_h = 1;
516                 this->title_x->update((int64_t)(client->config.title_x = cur_x));
517                 this->title_y->update((int64_t)(client->config.title_y = cur_y));
518                 this->title_w->update((int64_t)(client->config.title_w = cur_w));
519                 this->title_h->update((int64_t)(client->config.title_h = cur_h));
520                 break; }
521         case 2: { // x1,y0
522                 int cur_y = cursor_y - drag_dy, dy = cur_y - y0;
523                 if( !dy ) return 1;
524                 int cur_h = title_h - dy;  if( cur_h < 1 ) cur_h = 1;
525                 this->title_y->update((int64_t)(client->config.title_y = cur_y));
526                 this->title_h->update((int64_t)(client->config.title_h = cur_h));
527                 break; }
528         case 3: { // x2,y0
529                 int cur_x = cursor_x - drag_dx, dx = cur_x - x2;
530                 int cur_y = cursor_y - drag_dy, dy = cur_y - y0;
531                 int cur_w = title_w + dx;  if( cur_w < 1 ) cur_w = 1;
532                 int cur_h = title_h - dy;  if( cur_h < 1 ) cur_h = 1;
533                 this->title_w->update((int64_t)(client->config.title_w = cur_w));
534                 this->title_y->update((int64_t)(client->config.title_y = cur_y));
535                 this->title_h->update((int64_t)(client->config.title_h = cur_h));
536                 break; }
537         case 4: { // x2,y1
538                 int cur_x = cursor_x - drag_dx, dx = cur_x - x2;
539                 if( !dx ) return 1;
540                 int cur_w = title_w + dx;  if( cur_w < 1 ) cur_w = 1;
541                 this->title_w->update((int64_t)(client->config.title_w = cur_w));
542                 break; }
543         case 5: { // x2,y2
544                 int cur_x = cursor_x - drag_dx, dx = cur_x - x2;
545                 int cur_y = cursor_y - drag_dy, dy = cur_y - y2;
546                 int cur_w = title_w + dx;  if( cur_w < 1 ) cur_w = 1;
547                 int cur_h = title_h + dy;  if( cur_h < 1 ) cur_h = 1;
548                 this->title_w->update((int64_t)(client->config.title_w = cur_w));
549                 this->title_h->update((int64_t)(client->config.title_h = cur_h));
550                 break; }
551         case 6: { // x1,y2
552                 int cur_y = cursor_y - drag_dy, dy = cur_y - y2;
553                 if( client->config.title_h == cur_y ) return 1;
554                 int cur_h = title_h + dy;  if( cur_h < 1 ) cur_h = 1;
555                 this->title_h->update((int64_t)(client->config.title_h = cur_h));
556                 break; }
557         case 7: { // x0,y2
558                 int cur_x = cursor_x - drag_dx, dx = cur_x - x0;
559                 int cur_y = cursor_y - drag_dy, dy = cur_y - y2;
560                 int cur_w = title_w - dx;  if( cur_w < 1 ) cur_w = 1;
561                 int cur_h = title_h + dy;  if( cur_h < 1 ) cur_h = 1;
562                 this->title_x->update((int64_t)(client->config.title_x = cur_x));
563                 this->title_w->update((int64_t)(client->config.title_w = cur_w));
564                 this->title_h->update((int64_t)(client->config.title_h = cur_h));
565                 break; }
566         case 8: { // x0,y1
567                 int cur_x = cursor_x - drag_dx, dx = cur_x - x0;
568                 if( !dx ) return 1;
569                 int cur_w = title_w - dx;  if( cur_w < 1 ) cur_w = 1;
570                 this->title_x->update((int64_t)(client->config.title_x = cur_x));
571                 this->title_w->update((int64_t)(client->config.title_w = cur_w));
572                 break; }
573         case 9: { // x1,y1
574                 int cur_x = cursor_x - drag_dx, dx = cur_x - x1;
575                 int cur_y = cursor_y - drag_dy, dy = cur_y - y1;
576                 if( title_x == cur_x && title_y == cur_y ) return 1;
577                 this->title_x->update((int64_t)(client->config.title_x += dx));
578                 this->title_y->update((int64_t)(client->config.title_y += dy));
579                 }
580         }
581         client->send_configure_change();
582         return 1;
583 }
584
585 void TitleWindow::previous_font()
586 {
587         int current_font = font->get_number();
588         current_font--;
589         if( current_font < 0 ) current_font = fonts.total - 1;
590
591         if( current_font < 0 || current_font >= fonts.total ) return;
592
593         for( int i=0; i<fonts.total; ++i ) {
594                 fonts.values[i]->set_selected(i == current_font);
595         }
596
597         font->update(fonts.values[current_font]->get_text());
598         strcpy(client->config.font, fonts.values[current_font]->get_text());
599         client->send_configure_change();
600 }
601
602 void  TitleWindow::next_font()
603 {
604         int current_font = font->get_number();
605         current_font++;
606         if( current_font >= fonts.total ) current_font = 0;
607
608         if( current_font < 0 || current_font >= fonts.total ) return;
609
610         for( int i=0; i<fonts.total; ++i ) {
611                 fonts.values[i]->set_selected(i == current_font);
612         }
613
614         font->update(fonts.values[current_font]->get_text());
615         strcpy(client->config.font, fonts.values[current_font]->get_text());
616         client->send_configure_change();
617 }
618
619 int TitleWindow::insert_ibeam(const char *txt, int adv)
620 {
621         int ibeam = cur_ibeam;
622         client->insert_text(txt, ibeam);
623         if( (ibeam += adv) >= client->config.wlen)
624                 ibeam = client->config.wlen;
625         text->wset_selection(-1, -1, ibeam);
626         text->update(client->config.wtext);
627         client->send_configure_change();
628         return 1;
629 }
630
631 void TitleWindow::update_color()
632 {
633 //printf("TitleWindow::update_color %x\n", client->config.color);
634         set_color(client->config.color);
635         draw_box(color_x, color_y, COLOR_W, COLOR_H);
636         flash(color_x, color_y, COLOR_W, COLOR_H);
637         set_color(client->config.outline_color);
638         draw_box(outline_color_x, outline_color_y, COLOR_W, COLOR_H);
639         set_color(BLACK);
640         draw_rectangle(color_x, color_y, COLOR_W, COLOR_H);
641         draw_rectangle(outline_color_x, outline_color_y, COLOR_W, COLOR_H);
642         flash(outline_color_x, outline_color_y, COLOR_W, COLOR_H);
643 }
644
645 void TitleWindow::update_justification()
646 {
647         left->update(client->config.hjustification == JUSTIFY_LEFT);
648         center->update(client->config.hjustification == JUSTIFY_CENTER);
649         right->update(client->config.hjustification == JUSTIFY_RIGHT);
650         top->update(client->config.vjustification == JUSTIFY_TOP);
651         mid->update(client->config.vjustification == JUSTIFY_MID);
652         bottom->update(client->config.vjustification == JUSTIFY_BOTTOM);
653 }
654
655 void TitleWindow::update()
656 {
657         title_x->update((int64_t)client->config.title_x);
658         title_y->update((int64_t)client->config.title_y);
659         title_w->update((int64_t)client->config.title_w);
660         title_h->update((int64_t)client->config.title_h);
661         italic->update(client->config.style & BC_FONT_ITALIC);
662         bold->update(client->config.style & BC_FONT_BOLD);
663         size->update(client->config.size);
664         motion->update(TitleMain::motion_to_text(client->config.motion_strategy));
665         loop->update(client->config.loop);
666         dropshadow->update((int64_t)client->config.dropshadow);
667         fade_in->update((float)client->config.fade_in);
668         fade_out->update((float)client->config.fade_out);
669         font->update(client->config.font);
670         text->update(&client->config.wtext[0]);
671         speed->update(client->config.pixels_per_second);
672         outline->update((int64_t)client->config.outline_size);
673 #ifdef USE_STOKER
674         stroker->update((int64_t)client->config.stroke_width);
675 #endif
676         timecode->update(client->config.timecode);
677         timecode_format->update(client->config.timecode_format);
678         background->update(client->config.background);
679         background_path->update(client->config.background_path);
680         loop_playback->update((int64_t)client->config.loop_playback);
681
682         char string[BCTEXTLEN];
683         for( int i=0; i<lengthof(timeunit_formats); ++i ) {
684                 if( timeunit_formats[i] == client->config.timecode_format ) {
685                         timecode_format->set_text(
686                                 Units::print_time_format(timeunit_formats[i], string));
687                         break;
688                 }
689         }
690         update_justification();
691         update_color();
692 }
693
694
695 TitleFontTumble::TitleFontTumble(TitleMain *client, TitleWindow *window, int x, int y)
696  : BC_Tumbler(x, y)
697 {
698         this->client = client;
699         this->window = window;
700 }
701 int TitleFontTumble::handle_up_event()
702 {
703         window->previous_font();
704         return 1;
705 }
706
707 int TitleFontTumble::handle_down_event()
708 {
709         window->next_font();
710         return 1;
711 }
712
713
714
715 TitleSizeTumble::TitleSizeTumble(TitleMain *client, TitleWindow *window, int x, int y)
716  : BC_Tumbler(x, y)
717 {
718         this->client = client;
719         this->window = window;
720 }
721
722 int TitleSizeTumble::handle_up_event()
723 {
724         int current_index = -1;
725         int current_difference = -1;
726         for( int i=0; i<window->sizes.size(); ++i ) {
727                 int size = atoi(window->sizes.get(i)->get_text());
728                 if( current_index < 0 ||
729                         abs(size - client->config.size) < current_difference ) {
730                         current_index = i;
731                         current_difference = abs(size - client->config.size);
732                 }
733         }
734
735         current_index++;
736         if( current_index >= window->sizes.size() ) current_index = 0;
737
738
739         client->config.size = atoi(window->sizes.get(current_index)->get_text());
740         window->size->update(client->config.size);
741         client->send_configure_change();
742         return 1;
743 }
744
745 int TitleSizeTumble::handle_down_event()
746 {
747         int current_index = -1;
748         int current_difference = -1;
749         for( int i=0; i<window->sizes.size(); ++i ) {
750                 int size = atoi(window->sizes.get(i)->get_text());
751                 if( current_index < 0 ||
752                         abs(size - client->config.size) < current_difference ) {
753                         current_index = i;
754                         current_difference = abs(size - client->config.size);
755                 }
756         }
757
758         current_index--;
759         if( current_index < 0 ) current_index = window->sizes.size() - 1;
760
761
762         client->config.size = atoi(window->sizes.get(current_index)->get_text());
763         window->size->update(client->config.size);
764         client->send_configure_change();
765         return 1;
766 }
767
768 TitleBold::TitleBold(TitleMain *client, TitleWindow *window, int x, int y)
769  : BC_CheckBox(x, y, client->config.style & BC_FONT_BOLD, _("Bold"))
770 {
771         this->client = client;
772         this->window = window;
773 }
774
775 int TitleBold::handle_event()
776 {
777         client->config.style =
778                 (client->config.style & ~BC_FONT_BOLD) |
779                         (get_value() ? BC_FONT_BOLD : 0);
780         client->send_configure_change();
781         return 1;
782 }
783
784 TitleItalic::TitleItalic(TitleMain *client, TitleWindow *window, int x, int y)
785  : BC_CheckBox(x, y, client->config.style & BC_FONT_ITALIC, _("Italic"))
786 {
787         this->client = client;
788         this->window = window;
789 }
790 int TitleItalic::handle_event()
791 {
792         client->config.style =
793                 (client->config.style & ~BC_FONT_ITALIC) |
794                         (get_value() ? BC_FONT_ITALIC : 0);
795         client->send_configure_change();
796         return 1;
797 }
798
799
800
801 TitleSize::TitleSize(TitleMain *client, TitleWindow *window, int x, int y, char *text)
802  : BC_PopupTextBox(window,
803                 &window->sizes,
804                 text,
805                 x,
806                 y,
807                 64,
808                 300)
809 {
810         this->client = client;
811         this->window = window;
812 }
813 TitleSize::~TitleSize()
814 {
815 }
816 int TitleSize::handle_event()
817 {
818         client->config.size = atol(get_text());
819 //printf("TitleSize::handle_event 1 %s\n", get_text());
820         client->send_configure_change();
821         return 1;
822 }
823 void TitleSize::update(int size)
824 {
825         char string[BCTEXTLEN];
826         sprintf(string, "%d", size);
827         BC_PopupTextBox::update(string);
828 }
829
830 TitlePitch::
831 TitlePitch(TitleMain *client, TitleWindow *window, int x, int y, int *value)
832  : BC_TumbleTextBox(window, *value, 0, INT_MAX, x, y, 64)
833 {
834         this->client = client;
835         this->window = window;
836         this->value = value;
837 }
838
839 TitlePitch::
840 ~TitlePitch()
841 {
842 }
843
844 int TitlePitch::handle_event()
845 {
846         *value = atol(get_text());
847         client->send_configure_change();
848         return 1;
849 }
850
851 TitleColorButton::TitleColorButton(TitleMain *client, TitleWindow *window, int x, int y)
852  : BC_GenericButton(x, y, _("Color..."))
853 {
854         this->client = client;
855         this->window = window;
856 }
857 int TitleColorButton::handle_event()
858 {
859         window->color_thread->start_window(client->config.color,
860                 client->config.alpha);
861         return 1;
862 }
863 TitleOutlineColorButton::TitleOutlineColorButton(TitleMain *client, TitleWindow *window, int x, int y)
864  : BC_GenericButton(x, y, _("Outline color..."))
865 {
866         this->client = client;
867         this->window = window;
868 }
869 int TitleOutlineColorButton::handle_event()
870 {
871         window->outline_color_thread->start_window(client->config.outline_color,
872                 client->config.outline_alpha);
873         return 1;
874 }
875
876
877 TitleMotion::TitleMotion(TitleMain *client, TitleWindow *window, int x, int y)
878  : BC_PopupTextBox(window, &window->paths,
879                 client->motion_to_text(client->config.motion_strategy),
880                 x, y, 120, 100)
881 {
882         this->client = client;
883         this->window = window;
884 }
885 int TitleMotion::handle_event()
886 {
887         client->config.motion_strategy = client->text_to_motion(get_text());
888         client->send_configure_change();
889         return 1;
890 }
891
892 TitleLoop::TitleLoop(TitleMain *client, int x, int y)
893  : BC_CheckBox(x, y, client->config.loop, _("Loop"))
894 {
895         this->client = client;
896 }
897 int TitleLoop::handle_event()
898 {
899         client->config.loop = get_value();
900         client->send_configure_change();
901         return 1;
902 }
903 TitleTimecode::TitleTimecode(TitleMain *client, int x, int y)
904  : BC_CheckBox(x, y, client->config.timecode, _("Stamp timecode"))
905 {
906         this->client = client;
907 }
908 int TitleTimecode::handle_event()
909 {
910         client->config.timecode = get_value();
911         client->send_configure_change();
912         return 1;
913 }
914
915 TitleTimecodeFormat::TitleTimecodeFormat(TitleMain *client, int x, int y, const char *text)
916  : BC_PopupMenu(x, y, 100, text, 1)
917 {
918         this->client = client;
919 }
920
921 int TitleTimecodeFormat::handle_event()
922 {
923         client->config.timecode_format = Units::text_to_format(get_text());
924         client->send_configure_change();
925         return 1;
926 }
927
928 void TitleTimecodeFormat::create_objects()
929 {
930         char string[BCTEXTLEN];
931         for( int i=0; i<lengthof(timeunit_formats); ++i ) {
932                 add_item(new BC_MenuItem(
933                         Units::print_time_format(timeunit_formats[i], string)));
934         }
935 }
936
937
938 int TitleTimecodeFormat::update(int timecode_format)
939 {
940         char string[BCTEXTLEN];
941         for( int i=0; i<lengthof(timeunit_formats); ++i ) {
942                 if( timeunit_formats[i] == timecode_format ) {
943                         set_text(Units::print_time_format(timeunit_formats[i], string));
944                         break;
945                 }
946         }
947         return 0;
948 }
949
950 TitleFade::TitleFade(TitleMain *client, TitleWindow *window,
951         double *value, int x, int y)
952  : BC_TextBox(x, y, 80, 1, (float)*value)
953 {
954         this->client = client;
955         this->window = window;
956         this->value = value;
957         set_precision(2);
958 }
959
960 int TitleFade::handle_event()
961 {
962         *value = atof(get_text());
963         client->send_configure_change();
964         return 1;
965 }
966
967 TitleFont::TitleFont(TitleMain *client, TitleWindow *window, int x, int y)
968  : BC_PopupTextBox(window, &window->fonts, client->config.font,
969                 x, y, 200, 500, LISTBOX_ICON_LIST)
970 {
971         this->client = client;
972         this->window = window;
973 }
974 int TitleFont::handle_event()
975 {
976         strcpy(client->config.font, get_text());
977         client->send_configure_change();
978         return 1;
979 }
980
981 TitleText::TitleText(TitleMain *client, TitleWindow *window,
982         int x, int y, int w, int h)
983  : BC_ScrollTextBox(window, x, y, w,
984                 BC_TextBox::pixels_to_rows(window, MEDIUMFONT, h),
985                 client->config.wtext, 8192)
986 {
987         this->client = client;
988         this->window = window;
989 //printf("TitleText::TitleText %s\n", client->config.text);
990 }
991
992 int TitleText::button_press_event()
993 {
994         if( get_buttonpress() == 3 ) {
995                 window->cur_ibeam = get_ibeam_letter();
996                 window->cur_popup->activate_menu();
997                 return 1;
998         }
999         return BC_ScrollTextBox::button_press_event();
1000 }
1001
1002 int TitleText::handle_event()
1003 {
1004         window->fonts_popup->deactivate();
1005         int len =  sizeof(client->config.wtext) / sizeof(wchar_t);
1006         wcsncpy(client->config.wtext, get_wtext(), len);
1007         client->config.wtext[len-1] = 0;
1008         client->config.wlen = wcslen(client->config.wtext);
1009         client->send_configure_change();
1010         return 1;
1011 }
1012
1013
1014 TitleDropShadow::TitleDropShadow(TitleMain *client, TitleWindow *window, int x, int y)
1015  : BC_TumbleTextBox(window, (int64_t)client->config.dropshadow,
1016         (int64_t)-1000, (int64_t)1000, x, y, 70)
1017 {
1018         this->client = client;
1019         this->window = window;
1020 }
1021 int TitleDropShadow::handle_event()
1022 {
1023         client->config.dropshadow = atol(get_text());
1024         client->send_configure_change();
1025         return 1;
1026 }
1027
1028
1029 TitleOutline::TitleOutline(TitleMain *client, TitleWindow *window, int x, int y)
1030  : BC_TumbleTextBox(window, (int64_t)client->config.outline_size,
1031         (int64_t)0, (int64_t)1000, x, y, 70)
1032 {
1033         this->client = client;
1034         this->window = window;
1035 }
1036 int TitleOutline::handle_event()
1037 {
1038         client->config.outline_size = atol(get_text());
1039         client->send_configure_change();
1040         return 1;
1041 }
1042
1043 TitleStroker::TitleStroker(TitleMain *client, TitleWindow *window, int x, int y)
1044  : BC_TumbleTextBox(window, (int64_t)client->config.stroke_width,
1045         (int64_t)0, (int64_t)1000, x, y, 70)
1046 {
1047         this->client = client;
1048         this->window = window;
1049 }
1050 int TitleStroker::handle_event()
1051 {
1052         client->config.stroke_width = atol(get_text());
1053         if( client->config.stroke_width > 1 )
1054                 client->config.style |= BC_FONT_OUTLINE;
1055         else
1056                 client->config.style &= ~BC_FONT_OUTLINE;
1057         client->send_configure_change();
1058         return 1;
1059 }
1060
1061
1062 TitleX::TitleX(TitleMain *client, TitleWindow *window, int x, int y)
1063  : BC_TumbleTextBox(window, (int64_t)client->config.title_x,
1064         (int64_t)-32767, (int64_t)32767, x, y, 50)
1065 {
1066         this->client = client;
1067         this->window = window;
1068 }
1069 int TitleX::handle_event()
1070 {
1071         client->config.title_x = atol(get_text());
1072         client->send_configure_change();
1073         return 1;
1074 }
1075
1076 TitleY::TitleY(TitleMain *client, TitleWindow *window, int x, int y)
1077  : BC_TumbleTextBox(window, (int64_t)client->config.title_y,
1078         (int64_t)-32767, (int64_t)32767, x, y, 50)
1079 {
1080         this->client = client;
1081         this->window = window;
1082 }
1083 int TitleY::handle_event()
1084 {
1085         client->config.title_y = atol(get_text());
1086         client->send_configure_change();
1087         return 1;
1088 }
1089
1090 TitleW::TitleW(TitleMain *client, TitleWindow *window, int x, int y)
1091  : BC_TumbleTextBox(window, (int64_t)client->config.title_w,
1092         (int64_t)0, (int64_t)32767, x, y, 50)
1093 {
1094         this->client = client;
1095         this->window = window;
1096 }
1097 int TitleW::handle_event()
1098 {
1099         client->config.title_w = atol(get_text());
1100         client->send_configure_change();
1101         return 1;
1102 }
1103
1104 TitleH::TitleH(TitleMain *client, TitleWindow *window, int x, int y)
1105  : BC_TumbleTextBox(window, (int64_t)client->config.title_h,
1106         (int64_t)0, (int64_t)32767, x, y, 50)
1107 {
1108         this->client = client;
1109         this->window = window;
1110 }
1111 int TitleH::handle_event()
1112 {
1113         client->config.title_h = atol(get_text());
1114         client->send_configure_change();
1115         return 1;
1116 }
1117
1118 TitleSpeed::TitleSpeed(TitleMain *client, TitleWindow *window, int x, int y)
1119  : BC_TumbleTextBox(window, (float)client->config.pixels_per_second,
1120         (float)0, (float)1000, x, y, 100)
1121 {
1122         this->client = client;
1123         set_precision(2);
1124         set_increment(10);
1125 }
1126
1127
1128 int TitleSpeed::handle_event()
1129 {
1130         client->config.pixels_per_second = atof(get_text());
1131         client->send_configure_change();
1132         return 1;
1133 }
1134
1135
1136 TitleLeft::TitleLeft(TitleMain *client, TitleWindow *window, int x, int y)
1137  : BC_Radial(x, y, client->config.hjustification == JUSTIFY_LEFT, _("Left"))
1138 {
1139         this->client = client;
1140         this->window = window;
1141 }
1142 int TitleLeft::handle_event()
1143 {
1144         client->config.hjustification = JUSTIFY_LEFT;
1145         window->update_justification();
1146         client->send_configure_change();
1147         return 1;
1148 }
1149
1150 TitleCenter::TitleCenter(TitleMain *client, TitleWindow *window, int x, int y)
1151  : BC_Radial(x, y, client->config.hjustification == JUSTIFY_CENTER, _("Center"))
1152 {
1153         this->client = client;
1154         this->window = window;
1155 }
1156 int TitleCenter::handle_event()
1157 {
1158         client->config.hjustification = JUSTIFY_CENTER;
1159         window->update_justification();
1160         client->send_configure_change();
1161         return 1;
1162 }
1163
1164 TitleRight::TitleRight(TitleMain *client, TitleWindow *window, int x, int y)
1165  : BC_Radial(x, y, client->config.hjustification == JUSTIFY_RIGHT, _("Right"))
1166 {
1167         this->client = client;
1168         this->window = window;
1169 }
1170 int TitleRight::handle_event()
1171 {
1172         client->config.hjustification = JUSTIFY_RIGHT;
1173         window->update_justification();
1174         client->send_configure_change();
1175         return 1;
1176 }
1177
1178
1179
1180 TitleTop::TitleTop(TitleMain *client, TitleWindow *window, int x, int y)
1181  : BC_Radial(x, y, client->config.vjustification == JUSTIFY_TOP, _("Top"))
1182 {
1183         this->client = client;
1184         this->window = window;
1185 }
1186 int TitleTop::handle_event()
1187 {
1188         client->config.vjustification = JUSTIFY_TOP;
1189         window->update_justification();
1190         client->send_configure_change();
1191         return 1;
1192 }
1193
1194 TitleMid::TitleMid(TitleMain *client, TitleWindow *window, int x, int y)
1195  : BC_Radial(x, y, client->config.vjustification == JUSTIFY_MID, _("Mid"))
1196 {
1197         this->client = client;
1198         this->window = window;
1199 }
1200 int TitleMid::handle_event()
1201 {
1202         client->config.vjustification = JUSTIFY_MID;
1203         window->update_justification();
1204         client->send_configure_change();
1205         return 1;
1206 }
1207
1208 TitleBottom::TitleBottom(TitleMain *client, TitleWindow *window, int x, int y)
1209  : BC_Radial(x, y, client->config.vjustification == JUSTIFY_BOTTOM, _("Bottom"))
1210 {
1211         this->client = client;
1212         this->window = window;
1213 }
1214 int TitleBottom::handle_event()
1215 {
1216         client->config.vjustification = JUSTIFY_BOTTOM;
1217         window->update_justification();
1218         client->send_configure_change();
1219         return 1;
1220 }
1221
1222
1223
1224 TitleColorThread::TitleColorThread(TitleMain *client, TitleWindow *window, int is_outline)
1225  : ColorThread(1, _("Text Color"))
1226 {
1227         this->client = client;
1228         this->window = window;
1229         this->is_outline = is_outline;
1230 }
1231
1232 int TitleColorThread::handle_new_color(int output, int alpha)
1233 {
1234         if( is_outline ) {
1235                 client->config.outline_color = output;
1236                 client->config.outline_alpha = alpha;
1237         }
1238         else {
1239                 client->config.color = output;
1240                 client->config.alpha = alpha;
1241         }
1242
1243         window->lock_window("TitleColorThread::handle_new_color");
1244         window->update_color();
1245         window->flush();
1246         window->unlock_window();
1247
1248         client->send_configure_change();
1249         return 1;
1250 }
1251
1252 TitleDrag::TitleDrag(TitleMain *client, TitleWindow *window, int x, int y)
1253  : BC_CheckBox(x, y, client->config.drag, _("Drag"))
1254 {
1255         this->client = client;
1256         this->window = window;
1257 }
1258
1259 int TitleDrag::handle_event()
1260 {
1261         int value = get_value();
1262         client->config.drag = value;
1263         if( value )
1264                 window->grab(client->server->mwindow->cwindow->gui);
1265         else
1266                 window->ungrab(client->server->mwindow->cwindow->gui);
1267         client->send_configure_change();
1268         return 1;
1269 }
1270
1271 TitleBackground::TitleBackground(TitleMain *client, TitleWindow *window, int x, int y)
1272  : BC_CheckBox(x, y, client->config.background, _("Background:"))
1273 {
1274         this->client = client;
1275         this->window = window;
1276 }
1277
1278 int TitleBackground::handle_event()
1279 {
1280         client->config.background = get_value();
1281         client->send_configure_change();
1282         return 1;
1283 }
1284
1285 TitleBackgroundPath::TitleBackgroundPath(TitleMain *client, TitleWindow *window, int x, int y)
1286  : BC_TextBox(x, y, 240, 1, client->config.background_path)
1287 {
1288         this->client = client;
1289         this->window = window;
1290 }
1291
1292 int TitleBackgroundPath::handle_event()
1293 {
1294         strncpy(client->config.background_path, get_text(), sizeof(client->config.background_path));
1295         client->send_configure_change();
1296         return 1;
1297 }
1298
1299 TitleLoopPlayback::TitleLoopPlayback(TitleMain *client, int x, int y)
1300  : BC_CheckBox(x, y, client->config.loop_playback, _("Loop playback"))
1301 {
1302         this->client = client;
1303 }
1304 int TitleLoopPlayback::handle_event()
1305 {
1306         client->config.loop_playback = get_value();
1307         client->send_configure_change();
1308         return 1;
1309 }
1310
1311
1312 TitleCurPopup::TitleCurPopup(TitleMain *client, TitleWindow *window)
1313  : BC_PopupMenu(0, 0, 0, "", 0)
1314 {
1315         this->client = client;
1316         this->window = window;
1317 }
1318 int TitleCurPopup::handle_event()
1319 {
1320         return 1;
1321 }
1322 void TitleCurPopup::create_objects()
1323 {
1324         TitleCurItem *cur_item;
1325         TitleCurSubMenu *sub_menu;
1326         add_item(cur_item = new TitleCurItem(this, _("nudge")));
1327         cur_item->add_submenu(sub_menu = new TitleCurSubMenu(cur_item));
1328         sub_menu->add_submenuitem(new TitleCurSubMenuItem(sub_menu,_("nudge dx,dy")));
1329         sub_menu->add_submenuitem(new TitleCurSubMenuItem(sub_menu,_("/nudge")));
1330         add_item(cur_item = new TitleCurItem(this, _("color")));
1331         cur_item->add_submenu(sub_menu = new TitleCurSubMenu(cur_item));
1332         sub_menu->add_submenuitem(new TitleCurSubMenuItem(sub_menu,_("color #")));
1333         sub_menu->add_submenuitem(new TitleCurSubMenuItem(sub_menu,_("color ")));
1334         sub_menu->add_submenuitem(new TitleCurSubMenuItem(sub_menu,_("/color")));
1335         add_item(cur_item = new TitleCurItem(this, _("alpha")));
1336         cur_item->add_submenu(sub_menu = new TitleCurSubMenu(cur_item));
1337         sub_menu->add_submenuitem(new TitleCurSubMenuItem(sub_menu,_("alpha ")));
1338         sub_menu->add_submenuitem(new TitleCurSubMenuItem(sub_menu,_("alpha 0.")));
1339         sub_menu->add_submenuitem(new TitleCurSubMenuItem(sub_menu,_("alpha .5")));
1340         sub_menu->add_submenuitem(new TitleCurSubMenuItem(sub_menu,_("alpha 1.")));
1341         sub_menu->add_submenuitem(new TitleCurSubMenuItem(sub_menu,_("/alpha")));
1342         add_item(cur_item = new TitleCurItem(this, _("font")));
1343         cur_item->add_submenu(sub_menu = new TitleCurSubMenu(cur_item));
1344         sub_menu->add_submenuitem(new TitleCurSubMenuItem(sub_menu,_("font name")));
1345         sub_menu->add_submenuitem(new TitleCurSubMenuItem(sub_menu,_("font ")));
1346         sub_menu->add_submenuitem(new TitleCurSubMenuItem(sub_menu,_("/font")));
1347         add_item(cur_item = new TitleCurItem(this, _("size")));
1348         cur_item->add_submenu(sub_menu = new TitleCurSubMenu(cur_item));
1349         sub_menu->add_submenuitem(new TitleCurSubMenuItem(sub_menu,_("size +")));
1350         sub_menu->add_submenuitem(new TitleCurSubMenuItem(sub_menu,_("size -")));
1351         sub_menu->add_submenuitem(new TitleCurSubMenuItem(sub_menu,_("size ")));
1352         sub_menu->add_submenuitem(new TitleCurSubMenuItem(sub_menu,_("/size")));
1353         add_item(cur_item = new TitleCurItem(this, _("bold")));
1354         cur_item->add_submenu(sub_menu = new TitleCurSubMenu(cur_item));
1355         sub_menu->add_submenuitem(new TitleCurSubMenuItem(sub_menu,_("bold 1")));
1356         sub_menu->add_submenuitem(new TitleCurSubMenuItem(sub_menu,_("bold 0")));
1357         sub_menu->add_submenuitem(new TitleCurSubMenuItem(sub_menu,_("/bold")));
1358         add_item(cur_item = new TitleCurItem(this, _("italic")));
1359         cur_item->add_submenu(sub_menu = new TitleCurSubMenu(cur_item));
1360         sub_menu->add_submenuitem(new TitleCurSubMenuItem(sub_menu,_("italic 1")));
1361         sub_menu->add_submenuitem(new TitleCurSubMenuItem(sub_menu,_("italic 0")));
1362         sub_menu->add_submenuitem(new TitleCurSubMenuItem(sub_menu,_("/italic")));
1363         add_item(cur_item = new TitleCurItem(this, _("caps")));
1364         cur_item->add_submenu(sub_menu = new TitleCurSubMenu(cur_item));
1365         sub_menu->add_submenuitem(new TitleCurSubMenuItem(sub_menu,_("caps 1")));
1366         sub_menu->add_submenuitem(new TitleCurSubMenuItem(sub_menu,_("caps 0")));
1367         sub_menu->add_submenuitem(new TitleCurSubMenuItem(sub_menu,_("caps -1")));
1368         sub_menu->add_submenuitem(new TitleCurSubMenuItem(sub_menu,_("/caps")));
1369         add_item(cur_item = new TitleCurItem(this, _("ul")));
1370         cur_item->add_submenu(sub_menu = new TitleCurSubMenu(cur_item));
1371         sub_menu->add_submenuitem(new TitleCurSubMenuItem(sub_menu,_("ul 1")));
1372         sub_menu->add_submenuitem(new TitleCurSubMenuItem(sub_menu,_("ul 0")));
1373         sub_menu->add_submenuitem(new TitleCurSubMenuItem(sub_menu,_("/ul")));
1374         add_item(cur_item = new TitleCurItem(this, _("blink")));
1375         cur_item->add_submenu(sub_menu = new TitleCurSubMenu(cur_item));
1376         sub_menu->add_submenuitem(new TitleCurSubMenuItem(sub_menu,_("blink 1")));
1377         sub_menu->add_submenuitem(new TitleCurSubMenuItem(sub_menu,_("blink -1")));
1378         sub_menu->add_submenuitem(new TitleCurSubMenuItem(sub_menu,_("blink ")));
1379         sub_menu->add_submenuitem(new TitleCurSubMenuItem(sub_menu,_("blink 0")));
1380         sub_menu->add_submenuitem(new TitleCurSubMenuItem(sub_menu,_("/blink")));
1381         add_item(cur_item = new TitleCurItem(this, _("fixed")));
1382         cur_item->add_submenu(sub_menu = new TitleCurSubMenu(cur_item));
1383         sub_menu->add_submenuitem(new TitleCurSubMenuItem(sub_menu,_("fixed ")));
1384         sub_menu->add_submenuitem(new TitleCurSubMenuItem(sub_menu,_("fixed 20")));
1385         sub_menu->add_submenuitem(new TitleCurSubMenuItem(sub_menu,_("fixed 10")));
1386         sub_menu->add_submenuitem(new TitleCurSubMenuItem(sub_menu,_("fixed 0")));
1387         sub_menu->add_submenuitem(new TitleCurSubMenuItem(sub_menu,_("/fixed")));
1388         add_item(cur_item = new TitleCurItem(this, _("sup")));
1389         cur_item->add_submenu(sub_menu = new TitleCurSubMenu(cur_item));
1390         sub_menu->add_submenuitem(new TitleCurSubMenuItem(sub_menu,_("sup 1")));
1391         sub_menu->add_submenuitem(new TitleCurSubMenuItem(sub_menu,_("sup 0")));
1392         sub_menu->add_submenuitem(new TitleCurSubMenuItem(sub_menu,_("sup -1")));
1393         sub_menu->add_submenuitem(new TitleCurSubMenuItem(sub_menu,_("/sup")));
1394         add_item(cur_item = new TitleCurItem(this, _("png")));
1395         cur_item->add_submenu(sub_menu = new TitleCurSubMenu(cur_item));
1396         sub_menu->add_submenuitem(new TitleCurSubMenuItem(sub_menu,_("png file")));
1397 }
1398
1399 TitleCurItem::TitleCurItem(TitleCurPopup *popup, const char *text)
1400  : BC_MenuItem(text)
1401 {
1402         this->popup = popup;
1403 }
1404 int TitleCurItem::handle_event()
1405 {
1406         return 1;
1407 }
1408
1409 TitleCurSubMenu::TitleCurSubMenu(TitleCurItem *cur_item)
1410 {
1411         this->cur_item = cur_item;
1412 }
1413 TitleCurSubMenu::~TitleCurSubMenu()
1414 {
1415 }
1416
1417 TitleCurSubMenuItem::TitleCurSubMenuItem(TitleCurSubMenu *submenu, const char *text)
1418  : BC_MenuItem(text)
1419 {
1420         this->submenu = submenu;
1421 }
1422 TitleCurSubMenuItem::~TitleCurSubMenuItem()
1423 {
1424 }
1425 int TitleCurSubMenuItem::handle_event()
1426 {
1427         TitleCurPopup *popup = submenu->cur_item->popup;
1428         TitleWindow *window = popup->window;
1429         const char *item_text = get_text();
1430         if( !strcmp(item_text, _("font name")) ) {
1431                 int px, py;
1432                 window->get_pop_cursor_xy(px ,py);
1433                 window->fonts_popup->activate(px, py, 300,200);
1434                 return 1;
1435         }
1436         if( !strcmp(item_text, _("color #")) ) {
1437                 window->color_popup->activate();
1438                 return 1;
1439         }
1440         char txt[BCSTRLEN];
1441         sprintf(txt, "<%s>", item_text);
1442         int adv = strlen(txt);
1443         if( adv > 1 && (txt[1] != '/' && strcmp(txt,_("font"))) ) --adv;
1444         return window->insert_ibeam(txt,adv);
1445 }
1446
1447 TitleFontsPopup::TitleFontsPopup(TitleMain *client, TitleWindow *window)
1448  : BC_ListBox(-1, -1, 1, 1, LISTBOX_ICON_LIST,
1449         &window->fonts, 0, 0, 1, 0, 1)
1450 {
1451         this->client = client;
1452         this->window = window;
1453         set_use_button(0);
1454 }
1455 TitleFontsPopup::~TitleFontsPopup()
1456 {
1457 }
1458
1459 int TitleFontsPopup::handle_event()
1460 {
1461         deactivate();
1462         BC_ListBoxItem *item = get_selection(0, 0);
1463         if( !item ) return 1;
1464         const char *item_text = item->get_text();
1465         char txt[BCTEXTLEN];  sprintf(txt, "<font %s>",item_text);
1466         return window->insert_ibeam(txt, strlen(txt));
1467 }
1468
1469 TitleColorPopup::TitleColorPopup(TitleMain *client, TitleWindow *window)
1470  : ColorThread(0, _("Text Color"))
1471 {
1472         this->client = client;
1473         this->window = window;
1474         this->color_value = client->config.color;
1475 }
1476 TitleColorPopup::~TitleColorPopup()
1477 {
1478 }
1479 int TitleColorPopup::handle_new_color(int output, int alpha)
1480 {
1481         color_value = output;
1482         return 1;
1483 }
1484 int TitleColorPopup::activate()
1485 {
1486         start_window(client->config.color, 255, 1);
1487         return 1;
1488 }
1489 void TitleColorPopup::handle_done_event(int result)
1490 {
1491         if( result ) return;
1492         char txt[BCSTRLEN];  sprintf(txt, "<color #%06x>",color_value);
1493         window->insert_ibeam(txt, strlen(txt));
1494 }
1495