no longer need ffmpeg patch0 which was for Termux
[goodguy/cinelerra.git] / cinelerra-5.1 / guicast / bcwindowdraw.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 "bcbitmap.h"
23 #include "bcpixmap.h"
24 #include "bcpopup.h"
25 #include "bcresources.h"
26 #include "bcsignals.h"
27 #include "bcsynchronous.h"
28 #include "bctimer.h"
29 #include "bcwindowbase.h"
30 #include "clip.h"
31 #include "bccolors.h"
32 #include "bctrace.h"
33 #include "cursors.h"
34 #include "fonts.h"
35 #include "vframe.h"
36 #include <string.h>
37 #include <wchar.h>
38 #include <ft2build.h>
39 #include "workarounds.h"
40
41 void BC_WindowBase::copy_area(int x1, int y1, int x2, int y2, int w, int h, BC_Pixmap *pixmap)
42 { BT
43         XCopyArea(top_level->display,
44                 pixmap ? pixmap->opaque_pixmap : this->pixmap->opaque_pixmap,
45                 pixmap ? pixmap->opaque_pixmap : this->pixmap->opaque_pixmap,
46                 top_level->gc, x1, y1, w, h, x2, y2);
47 }
48
49
50 void BC_WindowBase::draw_box(int x, int y, int w, int h, BC_Pixmap *pixmap)
51 { BT
52 //if(x == 0) printf("BC_WindowBase::draw_box %d %d %d %d\n", x, y, w, h);
53         XFillRectangle(top_level->display,
54                 pixmap ? pixmap->opaque_pixmap : this->pixmap->opaque_pixmap,
55                 top_level->gc, x, y, w, h);
56 }
57
58
59 void BC_WindowBase::draw_circle(int x, int y, int w, int h, BC_Pixmap *pixmap)
60 { BT
61         XDrawArc(top_level->display,
62                 pixmap ? pixmap->opaque_pixmap : this->pixmap->opaque_pixmap,
63                 top_level->gc, x, y, (w - 1), (h - 2), 0 * 64, 360 * 64);
64 }
65
66 void BC_WindowBase::draw_arc(int x, int y, int w, int h,
67         int start_angle, int angle_length, BC_Pixmap *pixmap)
68 { BT
69         XDrawArc(top_level->display,
70                 pixmap ? pixmap->opaque_pixmap : this->pixmap->opaque_pixmap,
71                 top_level->gc, x, y, (w - 1), (h - 2), start_angle * 64,
72                 angle_length * 64);
73 }
74
75 void BC_WindowBase::draw_disc(int x, int y, int w, int h, BC_Pixmap *pixmap)
76 { BT
77         XFillArc(top_level->display,
78                 pixmap ? pixmap->opaque_pixmap : this->pixmap->opaque_pixmap,
79                 top_level->gc, x, y, (w - 1), (h - 2), 0 * 64, 360 * 64);
80 }
81
82 void BC_WindowBase::clear_box(int x, int y, int w, int h, BC_Pixmap *pixmap)
83 { BT
84         set_color(bg_color);
85         Pixmap xpixmap = pixmap ? pixmap->opaque_pixmap : this->pixmap->opaque_pixmap;
86         XFillRectangle(top_level->display, xpixmap, top_level->gc, x, y, w, h);
87 }
88
89 void BC_WindowBase::draw_text_line(int x, int y, const char *text, int len,
90         BC_Pixmap *pixmap)
91 {
92 #ifdef HAVE_XFT
93         if( get_resources()->use_xft ) {
94                 draw_xft_text(x, y, text, len, pixmap);
95                 return;
96         }
97 #endif
98  BT
99         Pixmap xpixmap = pixmap ? pixmap->opaque_pixmap : this->pixmap->opaque_pixmap;
100         if( get_resources()->use_fontset ) {
101                 XFontSet fontset = top_level->get_curr_fontset();
102                 if( fontset ) {
103                         XmbDrawString(top_level->display, xpixmap, fontset,
104                                 top_level->gc, x, y, text, len);
105                         return;
106                 }
107
108         }
109 //printf("BC_WindowBase::draw_text 3\n");
110         XDrawString(top_level->display, xpixmap, top_level->gc, x, y, text, len);
111 }
112
113 void BC_WindowBase::draw_text(int x, int y, const char *text, int length,
114         BC_Pixmap *pixmap)
115 {
116         if( length < 0 ) length = strlen(text);
117         //int boldface = top_level->current_font & BOLDFACE;
118         int font = top_level->current_font & 0xff;
119
120         switch(top_level->current_font) {
121         case MEDIUM_7SEGMENT:
122                 for(int i = 0; i < length; i++) {
123                         VFrame *image, **img7seg = get_resources()->medium_7segment;
124                         int ch = text[i];
125                         switch( ch ) {
126                         case '0': case '1': case '2': case '3': case '4':
127                         case '5': case '6': case '7': case '8': case '9':
128                                   image = img7seg[ch-'0'];  break;
129                         case ':': image = img7seg[10];      break;
130                         case '.': image = img7seg[11];      break;
131                         case 'a': case 'b': case 'c':
132                         case 'd': case 'e': case 'f':  ch -= 'a'-'A';
133                         case 'A': case 'B': case 'C':  /* fallthru */
134                         case 'D': case 'E': case 'F':
135                                 image = img7seg[12+ch-'A']; break;
136                                 break;
137                         case '-': image = img7seg[19];      break;
138                         default:
139                         case ' ': image = img7seg[18];      break;
140                         }
141
142                         draw_vframe(image, x, y - image->get_h());
143                         x += image->get_w();
144                 }
145                 break;
146
147         default: {
148                 if(top_level->get_xft_struct(top_level->current_font)) {
149                         draw_xft_text(x, y, text, length, pixmap);
150                         return;
151                 }
152  BT
153                 for(int i = 0, j = 0; i <= length; i++) {
154                         if(text[i] == '\n' || text[i] == 0) {
155                                 if(get_resources()->use_fontset && top_level->get_curr_fontset()) {
156                                         XmbDrawString(top_level->display,
157                                                 pixmap ? pixmap->opaque_pixmap : this->pixmap->opaque_pixmap,
158                                                 top_level->get_curr_fontset(),
159                                                 top_level->gc, x, y, &text[j], i-j);
160                                 }
161                                 else {
162                                         XDrawString(top_level->display,
163                                                 pixmap ? pixmap->opaque_pixmap : this->pixmap->opaque_pixmap,
164                                                 top_level->gc, x, y, &text[j], i-j);
165                                 }
166                                 j = i + 1;
167                                 y += get_text_height(font);
168                         }
169                 }
170                 break; }
171         }
172 }
173
174 void BC_WindowBase::draw_utf8_text(int x, int y,
175         const char *text, int length, BC_Pixmap *pixmap)
176 {
177         if(length < 0) length = strlen(text);
178
179         if(top_level->get_xft_struct(top_level->current_font))
180         {
181                 draw_xft_text(x, y, text, length, pixmap, 1);
182                 return;
183         }
184  BT
185         for(int i = 0, j = 0; i <= length; i++)
186         {
187                 if(text[i] == '\n' || text[i] == 0)
188                 {
189                         if(get_resources()->use_fontset && top_level->get_curr_fontset())
190                         {
191                                 XmbDrawString(top_level->display,
192                                         pixmap ? pixmap->opaque_pixmap : this->pixmap->opaque_pixmap,
193                                         top_level->get_curr_fontset(), top_level->gc,
194                                         x, y, &text[j], i - j);
195                         }
196                         else
197                         {
198                                 XDrawString(top_level->display,
199                                         pixmap ? pixmap->opaque_pixmap : this->pixmap->opaque_pixmap,
200                                         top_level->gc,
201                                         x, y, &text[j], i - j);
202                         }
203
204                         j = i + 1;
205                         y += get_text_height(MEDIUMFONT);
206                 }
207         }
208 }
209
210 void BC_WindowBase::draw_xft_text(int x, int y,
211         const char *text, int length, BC_Pixmap *pixmap, int is_utf8)
212 {
213         int l = length + 1;
214         wchr_t wide_text[l];
215         length = BC_Resources::encode(
216                 is_utf8 ? "UTF8" : BC_Resources::encoding, BC_Resources::wide_encoding,
217                 (char*)text, length, (char*)wide_text, l*sizeof(wchr_t)) / sizeof(wchr_t);
218         draw_xft_text(x, y, wide_text, length, pixmap);
219 }
220
221 void BC_WindowBase::draw_xft_text(int x, int y,
222         const wchr_t *text, int length, BC_Pixmap *pixmap)
223 {
224         int dy = -1;
225         const wchr_t *wsp = text, *wep = wsp + length;
226         int font = top_level->current_font;
227         while( wsp < wep ) {
228                 const wchr_t *wcp = wsp;
229                 while( wcp < wep && *wcp != '\n' ) ++wcp;
230                 int len = wcp - wsp;
231                 if( len > 0 )
232                         draw_single_text(1, font, x, y, wsp, len, pixmap);
233                 if( wcp >= wep ) break;
234                 if( dy < 0 )
235                         dy = get_text_height(font);
236                 y += dy;
237                 wsp = wcp + 1;
238         }
239 }
240
241 void BC_WindowBase::xft_draw_string(XftColor *xft_color, XftFont *xft_font,
242                 int x, int y, const FcChar32 *fc, int len, BC_Pixmap *pixmap)
243 { BT
244         Pixmap draw_pixmap = 0;
245         XftDraw *xft_draw = (XftDraw *)
246                 (pixmap ? pixmap->opaque_xft_draw : this->pixmap->opaque_xft_draw);
247         int src_x = x, src_y = y, src_w = 0, src_h = 0;
248         XGCValues values;
249         XGetGCValues(top_level->display, top_level->gc, GCFunction, &values);
250         if( values.function != GXcopy ) {
251                 XSetFunction(top_level->display, top_level->gc, GXcopy);
252                 XGlyphInfo info;
253                 xftTextExtents32(top_level->display, xft_font, fc, len, &info);
254                 src_w = info.width;  src_h = info.height;
255                 draw_pixmap = XCreatePixmap(top_level->display, top_level->win,
256                         src_w, src_h, top_level->default_depth);
257                 int color = get_color(); set_color(0);
258                 XFillRectangle(top_level->display, draw_pixmap, top_level->gc, 0, 0, src_w, src_h);
259                 set_color(color);
260                 xft_draw = xftDrawCreate(top_level->display, draw_pixmap,
261                            top_level->vis, top_level->cmap);
262                 src_x = info.x;  src_y = info.y;
263         }
264         xftDrawString32(xft_draw, xft_color, xft_font, src_x, src_y, fc, len);
265         if( values.function != GXcopy ) {
266                 XSetFunction(top_level->display, top_level->gc, values.function);
267                 Pixmap xpixmap = pixmap ? pixmap->opaque_pixmap : this->pixmap->opaque_pixmap;
268                 XCopyArea(top_level->display, draw_pixmap, xpixmap,
269                         top_level->gc, 0, 0, src_w, src_h, x, y);
270                 XFreePixmap(top_level->display, draw_pixmap);
271                 xftDrawDestroy(xft_draw);
272         }
273 }
274
275 int BC_WindowBase::get_single_text_width(int font, const wchr_t *text, int length)
276 {
277         return draw_single_text(0, font, 0,0, text, length);
278 }
279
280 int BC_WindowBase::draw_single_text(int draw, int font,
281         int x, int y, const wchr_t *text, int length, BC_Pixmap *pixmap)
282 {
283         if( length < 0 )
284                 length = wstrlen(text);
285         if( !length ) return 0;
286
287         if( !get_resources()->use_xft ) {
288  BT
289                 if( !get_font_struct(font) ) return 0;
290                 XChar2b xtext[length], *xp = xtext;
291                 for( int i=0; i<length; ++i,++xp ) {
292                         xp->byte1 = (unsigned char) (text[i] >> 8);
293                         xp->byte2 = (unsigned char) (text[i] & 0xff);
294                 }
295                 if( draw ) {
296                         XDrawString16(top_level->display,
297                                 pixmap ? pixmap->opaque_pixmap : this->pixmap->opaque_pixmap,
298                                 top_level->gc, x, y, xtext, length);
299                 }
300                 return XTextWidth16(get_font_struct(font), xtext, length);
301         }
302
303 #ifdef HAVE_XFT
304         XftColor xft_color;
305         if( draw ) {
306                 XRenderColor color;
307                 color.red = (top_level->current_color & 0xff0000) >> 16;
308                 color.red |= color.red << 8;
309                 color.green = (top_level->current_color & 0xff00) >> 8;
310                 color.green |= color.green << 8;
311                 color.blue = (top_level->current_color & 0xff);
312                 color.blue |= color.blue << 8;
313                 color.alpha = 0xffff;
314
315                 xftColorAllocValue(top_level->display, top_level->vis, top_level->cmap,
316                         &color, &xft_color);
317         }
318
319         int x0 = x;
320         XftFont *basefont = top_level->get_xft_struct(font);
321         XftFont *curfont = 0, *altfont = 0;
322         const wchr_t *up = text, *ubp = up, *uep = ubp + length;
323
324         while( up < uep ) {
325                 XftFont *xft_font = 0;
326                 if( xftCharExists(top_level->display, basefont, *up) )
327                         xft_font = basefont;
328                 else if( altfont ) {
329                         if( xftCharExists(top_level->display, altfont, *up))
330                                 xft_font = altfont;
331                         else {
332                                 xftFontClose(top_level->display, altfont);
333                                 altfont = 0;
334                         }
335                 }
336                 if( !xft_font ) {
337                         FcPattern *pattern = BC_Resources::find_similar_font(*up, basefont->pattern);
338                         if( pattern != 0 ) {
339                                 double psize = 0;
340                                 fcPatternGetDouble(basefont->pattern, FC_PIXEL_SIZE, 0, &psize);
341                                 fcPatternAddDouble(pattern, FC_PIXEL_SIZE, psize);
342                                 fcPatternDel(pattern, FC_SCALABLE);
343                                 xft_font = altfont = xftFontOpenPattern(top_level->display, pattern);
344                         }
345                 }
346                 if( !xft_font )
347                         xft_font = basefont;
348                 if( xft_font != curfont ) {
349                         if( curfont && up > ubp ) {
350                                 if( draw ) {
351                                         xft_draw_string(&xft_color, curfont, x, y,
352                                                 (const FcChar32*)ubp, up-ubp, pixmap);
353                                 }
354                                 XGlyphInfo extents;
355                                 xftTextExtents32(top_level->display, curfont,
356                                         (const FcChar32*)ubp, up-ubp, &extents);
357                                 x += extents.xOff;
358                         }
359                         ubp = up;  curfont = xft_font;
360                 }
361                 ++up;
362         }
363
364         if( curfont && up > ubp ) {
365                 if( draw ) {
366                         xft_draw_string(&xft_color, curfont, x, y,
367                                 (const FcChar32*)ubp, up-ubp, pixmap);
368                 }
369                 XGlyphInfo extents;
370                 xftTextExtents32(top_level->display, curfont,
371                         (const FcChar32*)ubp, up-ubp, &extents);
372                 x += extents.xOff;
373         }
374
375         if( altfont )
376                 xftFontClose(top_level->display, altfont);
377
378         xftColorFree(top_level->display, top_level->vis, top_level->cmap, &xft_color);
379 #endif
380         return x - x0;
381 }
382
383 void BC_WindowBase::draw_center_text(int x, int y, const char *text, int length)
384 {
385         if(length < 0) length = strlen(text);
386         int w = get_text_width(current_font, text, length);
387         x -= w / 2;
388         draw_text(x, y, text, length);
389 }
390
391 void BC_WindowBase::draw_pix(int x, int y, BC_Pixmap *pixmap)
392 { // draw_pixel, no BT test
393         XDrawPoint(top_level->display,
394                 pixmap ? pixmap->opaque_pixmap : this->pixmap->opaque_pixmap,
395                 top_level->gc, x, y);
396 }
397
398 void BC_WindowBase::draw_line(int x1, int y1, int x2, int y2, BC_Pixmap *pixmap)
399 { BT
400 // Some X drivers can't draw 0 length lines
401         if( x1 == x2 && y1 == y2 ) {
402                 draw_pix(x1, y1, pixmap);
403         }
404         else {
405                 XDrawLine(top_level->display,
406                         pixmap ? pixmap->opaque_pixmap : this->pixmap->opaque_pixmap,
407                         top_level->gc, x1, y1, x2, y2);
408         }
409 }
410
411 void BC_WindowBase::draw_bline(int x1, int y1, int x2, int y2, BC_Pixmap *pixmap)
412 { BT
413 // Short lines are all overhead to hw or sw setup, use bresenhams
414         if( y1 > y2 ) {
415                 int tx = x1;  x1 = x2;  x2 = tx;
416                 int ty = y1;  y1 = y2;  y2 = ty;
417         }
418
419         int x = x1, y = y1;
420         int dx = x2-x1, dy = y2-y1;
421         int dx2 = 2*dx, dy2 = 2*dy;
422         if( dx < 0 ) dx = -dx;
423         int r = dx > dy ? dx : dy, n = r;
424         int dir = 0;
425         if( dx2 < 0 ) dir += 1;
426         if( dy >= dx ) {
427                 if( dx2 >= 0 ) do {     /* +Y, +X */
428                         draw_pix(x, y++, pixmap);
429                         if( (r -= dx2) < 0 ) { r += dy2;  ++x; }
430                 } while( --n >= 0 );
431                 else do {               /* +Y, -X */
432                         draw_pix(x, y++, pixmap);
433                         if( (r += dx2) < 0 ) { r += dy2;  --x; }
434                 } while( --n >= 0 );
435         }
436         else {
437                 if( dx2 >= 0 ) do {     /* +X, +Y */
438                         draw_pix(x++, y, pixmap);
439                         if( (r -= dy2) < 0 ) { r += dx2;  ++y; }
440                 } while( --n >= 0 );
441                 else do {               /* -X, +Y */
442                         draw_pix(x--, y, pixmap);
443                         if( (r -= dy2) < 0 ) { r -= dx2;  ++y; }
444                 } while( --n >= 0 );
445         }
446 }
447
448 void BC_WindowBase::draw_polygon(ArrayList<int> *x, ArrayList<int> *y, BC_Pixmap *pixmap)
449 { BT
450         int npoints = MIN(x->total, y->total);
451         XPoint *points = new XPoint[npoints];
452
453         for( int i=0; i<npoints; ++i ) {
454                 points[i].x = x->values[i];
455                 points[i].y = y->values[i];
456         }
457
458         XDrawLines(top_level->display,
459                 pixmap ? pixmap->opaque_pixmap : this->pixmap->opaque_pixmap,
460                 top_level->gc, points, npoints, CoordModeOrigin);
461
462         delete [] points;
463 }
464
465 void BC_WindowBase::fill_polygon(ArrayList<int> *x, ArrayList<int> *y, BC_Pixmap *pixmap)
466 { BT
467         int npoints = MIN(x->total, y->total);
468         XPoint *points = new XPoint[npoints];
469
470         for( int i=0; i<npoints; ++i ) {
471                 points[i].x = x->values[i];
472                 points[i].y = y->values[i];
473         }
474
475         XFillPolygon(top_level->display,
476                 pixmap ? pixmap->opaque_pixmap : this->pixmap->opaque_pixmap,
477                 top_level->gc, points, npoints, Nonconvex, CoordModeOrigin);
478
479         delete [] points;
480 }
481
482
483 void BC_WindowBase::draw_rectangle(int x, int y, int w, int h)
484 { BT
485         XDrawRectangle(top_level->display,
486                 pixmap->opaque_pixmap, top_level->gc,
487                 x, y, w - 1, h - 1);
488 }
489
490 void BC_WindowBase::draw_3d_border(int x, int y, int w, int h, int is_down)
491 {
492         draw_3d_border(x, y, w, h,
493                 top_level->get_resources()->border_shadow2,
494                 top_level->get_resources()->border_shadow1,
495                 top_level->get_resources()->border_light1,
496                 top_level->get_resources()->border_light2);
497 }
498
499
500 void BC_WindowBase::draw_3d_border(int x, int y, int w, int h,
501         int light1, int light2, int shadow1, int shadow2)
502 {
503         int lx, ly, ux, uy;
504
505         h--; w--;
506
507         lx = x+1;  ly = y+1;
508         ux = x+w-1;  uy = y+h-1;
509
510         set_color(light1);
511         draw_line(x, y, ux, y);
512         draw_line(x, y, x, uy);
513         set_color(light2);
514         draw_line(lx, ly, ux - 1, ly);
515         draw_line(lx, ly, lx, uy - 1);
516
517         set_color(shadow1);
518         draw_line(ux, ly, ux, uy);
519         draw_line(lx, uy, ux, uy);
520         set_color(shadow2);
521         draw_line(x + w, y, x + w, y + h);
522         draw_line(x, y + h, x + w, y + h);
523 }
524
525 void BC_WindowBase::draw_3d_box(int x, int y, int w, int h,
526         int light1, int light2, int middle, int shadow1, int shadow2,
527         BC_Pixmap *pixmap)
528 {
529         int lx, ly, ux, uy;
530
531         h--; w--;
532
533         lx = x+1;  ly = y+1;
534         ux = x+w-1;  uy = y+h-1;
535
536         set_color(middle);
537         draw_box(x, y, w, h, pixmap);
538
539         set_color(light1);
540         draw_line(x, y, ux, y, pixmap);
541         draw_line(x, y, x, uy, pixmap);
542         set_color(light2);
543         draw_line(lx, ly, ux - 1, ly, pixmap);
544         draw_line(lx, ly, lx, uy - 1, pixmap);
545
546         set_color(shadow1);
547         draw_line(ux, ly, ux, uy, pixmap);
548         draw_line(lx, uy, ux, uy, pixmap);
549         set_color(shadow2);
550         draw_line(x + w, y, x + w, y + h, pixmap);
551         draw_line(x, y + h, x + w, y + h, pixmap);
552 }
553
554 void BC_WindowBase::draw_colored_box(int x, int y, int w, int h, int down, int highlighted)
555 {
556         if(!down)
557         {
558                 if(highlighted)
559                         draw_3d_box(x, y, w, h,
560                                 top_level->get_resources()->button_light,
561                                 top_level->get_resources()->button_highlighted,
562                                 top_level->get_resources()->button_highlighted,
563                                 top_level->get_resources()->button_shadow,
564                                 BLACK);
565                 else
566                         draw_3d_box(x, y, w, h,
567                                 top_level->get_resources()->button_light,
568                                 top_level->get_resources()->button_up,
569                                 top_level->get_resources()->button_up,
570                                 top_level->get_resources()->button_shadow,
571                                 BLACK);
572         }
573         else
574         {
575 // need highlighting for toggles
576                 if(highlighted)
577                         draw_3d_box(x, y, w, h,
578                                 top_level->get_resources()->button_shadow,
579                                 BLACK,
580                                 top_level->get_resources()->button_up,
581                                 top_level->get_resources()->button_up,
582                                 top_level->get_resources()->button_light);
583                 else
584                         draw_3d_box(x, y, w, h,
585                                 top_level->get_resources()->button_shadow,
586                                 BLACK,
587                                 top_level->get_resources()->button_down,
588                                 top_level->get_resources()->button_down,
589                                 top_level->get_resources()->button_light);
590         }
591 }
592
593
594 void BC_WindowBase::draw_border(char *text, int x, int y, int w, int h)
595 {
596         int left_indent = xS(20);
597         int lx, ly, ux, uy;
598
599         h--; w--;
600         lx = x + 1;  ly = y + 1;
601         ux = x + w - 1;  uy = y + h - 1;
602
603         set_opaque();
604         if(text && text[0] != 0)
605         {
606                 set_color(BLACK);
607                 set_font(MEDIUMFONT);
608                 draw_text(x + left_indent, y + get_text_height(MEDIUMFONT) / 2, text);
609         }
610
611         set_color(top_level->get_resources()->button_shadow);
612         draw_line(x, y, x + left_indent - xS(5), y);
613         draw_line(x, y, x, uy);
614         draw_line(x + left_indent + xS(5) + get_text_width(MEDIUMFONT, text), y, ux, y);
615         draw_line(x, y, x, uy);
616         draw_line(ux, ly, ux, uy);
617         draw_line(lx, uy, ux, uy);
618         set_color(top_level->get_resources()->button_light);
619         draw_line(lx, ly, x + left_indent - xS(5) - 1, ly);
620         draw_line(lx, ly, lx, uy - 1);
621         draw_line(x + left_indent + xS(5) + get_text_width(MEDIUMFONT, text), ly, ux - 1, ly);
622         draw_line(lx, ly, lx, uy - 1);
623         draw_line(x + w, y, x + w, y + h);
624         draw_line(x, y + h, x + w, y + h);
625 }
626
627 void BC_WindowBase::draw_triangle_down_flat(int x, int y, int w, int h)
628 { BT
629         int x1, y1, x2, y2, x3;
630         XPoint point[3];
631
632         x1 = x+1; x2 = x + w/2; x3 = x+w-1;
633         y1 = y; y2 = y+h-1;
634
635         point[0].x = x2; point[0].y = y2;
636         point[1].x = x3; point[1].y = y1;
637         point[2].x = x1; point[2].y = y1;
638
639         XFillPolygon(top_level->display, pixmap->opaque_pixmap, top_level->gc,
640                 (XPoint *)point, 3, Nonconvex, CoordModeOrigin);
641         draw_line(x1,y1, x3,y1);
642 }
643
644 void BC_WindowBase::draw_triangle_up(int x, int y, int w, int h,
645         int light1, int light2, int middle, int shadow1, int shadow2)
646 { BT
647         int x1, y1, x2, y2, x3;
648         XPoint point[3];
649
650         x1 = x; y1 = y; x2 = x + w / 2;
651         y2 = y + h - 1; x3 = x + w - 1;
652
653 // middle
654         point[0].x = x2; point[0].y = y1; point[1].x = x3;
655         point[1].y = y2; point[2].x = x1; point[2].y = y2;
656
657         set_color(middle);
658         XFillPolygon(top_level->display, pixmap->opaque_pixmap, top_level->gc,
659                 (XPoint *)point, 3, Nonconvex, CoordModeOrigin);
660
661 // bottom and top right
662         set_color(shadow1);
663         draw_line(x3, y2-1, x1, y2-1);
664         draw_line(x2-1, y1, x3-1, y2);
665         set_color(shadow2);
666         draw_line(x3, y2, x1, y2);
667         draw_line(x2, y1, x3, y2);
668
669 // top left
670         set_color(light2);
671         draw_line(x2+1, y1, x1+1, y2);
672         set_color(light1);
673         draw_line(x2, y1, x1, y2);
674 }
675
676 void BC_WindowBase::draw_triangle_down(int x, int y, int w, int h,
677         int light1, int light2, int middle, int shadow1, int shadow2)
678 {
679         int x1, y1, x2, y2, x3;
680         XPoint point[3];
681
682         x1 = x; x2 = x + w / 2; x3 = x + w - 1;
683         y1 = y; y2 = y + h - 1;
684
685         point[0].x = x2; point[0].y = y2; point[1].x = x3;
686         point[1].y = y1; point[2].x = x1; point[2].y = y1;
687
688         set_color(middle);
689         XFillPolygon(top_level->display,
690                 pixmap->opaque_pixmap,
691                 top_level->gc,
692                 (XPoint *)point,
693                 3,
694                 Nonconvex,
695                 CoordModeOrigin);
696
697 // top and bottom left
698         set_color(light2);
699         draw_line(x3-1, y1+1, x1+1, y1+1);
700         draw_line(x1+1, y1, x2+1, y2);
701         set_color(light1);
702         draw_line(x3, y1, x1, y1);
703         draw_line(x1, y1, x2, y2);
704
705 // bottom right
706         set_color(shadow1);
707         draw_line(x3-1, y1, x2-1, y2);
708         set_color(shadow2);
709         draw_line(x3, y1, x2, y2);
710 }
711
712 void BC_WindowBase::draw_triangle_left(int x, int y, int w, int h,
713         int light1, int light2, int middle, int shadow1, int shadow2)
714 { BT
715         int x1, y1, x2, y2, y3;
716         XPoint point[3];
717
718         // draw back arrow
719         y1 = y; x1 = x; y2 = y + h / 2;
720         x2 = x + w - 1; y3 = y + h - 1;
721
722         point[0].x = x1; point[0].y = y2; point[1].x = x2;
723         point[1].y = y1; point[2].x = x2; point[2].y = y3;
724
725         set_color(middle);
726         XFillPolygon(top_level->display,
727                 pixmap->opaque_pixmap,
728                 top_level->gc,
729                 (XPoint *)point,
730                 3,
731                 Nonconvex,
732                 CoordModeOrigin);
733
734 // right and bottom right
735         set_color(shadow1);
736         draw_line(x2-1, y1, x2-1, y3-1);
737         draw_line(x2, y3-1, x1, y2-1);
738         set_color(shadow2);
739         draw_line(x2, y1, x2, y3);
740         draw_line(x2, y3, x1, y2);
741
742 // top left
743         set_color(light1);
744         draw_line(x1, y2, x2, y1);
745         set_color(light2);
746         draw_line(x1, y2+1, x2, y1+1);
747 }
748
749 void BC_WindowBase::draw_triangle_right(int x, int y, int w, int h,
750         int light1, int light2, int middle, int shadow1, int shadow2)
751 { BT
752         int x1, y1, x2, y2, y3;
753         XPoint point[3];
754
755         y1 = y; y2 = y + h / 2; y3 = y + h - 1;
756         x1 = x; x2 = x + w - 1;
757
758         point[0].x = x1; point[0].y = y1; point[1].x = x2;
759         point[1].y = y2; point[2].x = x1; point[2].y = y3;
760
761         set_color(middle);
762         XFillPolygon(top_level->display,
763                 pixmap->opaque_pixmap,
764                 top_level->gc,
765                 (XPoint *)point,
766                 3,
767                 Nonconvex,
768                 CoordModeOrigin);
769
770 // left and top right
771         set_color(light2);
772         draw_line(x1+1, y3, x1+1, y1);
773         draw_line(x1, y1+1, x2, y2+1);
774         set_color(light1);
775         draw_line(x1, y3, x1, y1);
776         draw_line(x1, y1, x2, y2);
777
778 // bottom right
779         set_color(shadow1);
780         draw_line(x2, y2-1, x1, y3-1);
781         set_color(shadow2);
782         draw_line(x2, y2, x1, y3);
783 }
784
785
786 void BC_WindowBase::draw_check(int x, int y)
787 {
788         int xs3 = xS(3), xs4 = xS(4), xs6 = xS(6);
789         int ys1 = yS(1), ys2 = yS(2), ys3 = yS(3), ys4 = yS(4);
790         const int w = xS(15), h = yS(15), yh2 = y + h/2;
791         draw_line(x + xs3, yh2 + 0,   x + xs6,     yh2 + ys2);
792         draw_line(x + xs3, yh2 + ys1, x + xs6,     yh2 + ys3);
793         draw_line(x + xs6, yh2 + ys2, x + w - xs4, yh2 - ys3);
794         draw_line(x + xs3, yh2 + ys2, x + xs6,     yh2 + ys4);
795         draw_line(x + xs6, yh2 + ys2, x + w - xs4, yh2 - ys3);
796         draw_line(x + xs6, yh2 + ys3, x + w - xs4, yh2 - ys2);
797         draw_line(x + xs6, yh2 + ys4, x + w - xs4, yh2 - ys1);
798 }
799
800 void BC_WindowBase::draw_tiles(BC_Pixmap *tile, int origin_x, int origin_y, int x, int y, int w, int h)
801 { BT
802         if( !tile ) {
803                 set_color(bg_color);
804                 draw_box(x, y, w, h);
805         }
806         else {
807                 XSetFillStyle(top_level->display, top_level->gc, FillTiled);
808 // Don't know how slow this is
809                 XSetTile(top_level->display, top_level->gc, tile->get_pixmap());
810                 XSetTSOrigin(top_level->display, top_level->gc, origin_x, origin_y);
811                 draw_box(x, y, w, h);
812                 XSetFillStyle(top_level->display, top_level->gc, FillSolid);
813         }
814 }
815
816 void BC_WindowBase::draw_top_tiles(BC_WindowBase *parent_window, int x, int y, int w, int h)
817 { BT
818         Window tempwin;
819         int origin_x, origin_y;
820         XTranslateCoordinates(top_level->display,
821                 parent_window->win, win,
822                 0, 0, &origin_x, &origin_y, &tempwin);
823         draw_tiles(parent_window->bg_pixmap,
824                 origin_x, origin_y,
825                 x, y, w, h);
826 }
827
828 void BC_WindowBase::draw_top_background(BC_WindowBase *parent_window,
829         int x, int y, int w, int h, BC_Pixmap *pixmap)
830 { BT
831         Window tempwin;
832         int top_x, top_y;
833         XLockDisplay(top_level->display);
834
835         XTranslateCoordinates(top_level->display,
836                 win, parent_window->win,
837                 x, y, &top_x, &top_y, &tempwin);
838
839         XCopyArea(top_level->display,
840                 parent_window->pixmap->opaque_pixmap,
841                 pixmap ? pixmap->opaque_pixmap : this->pixmap->opaque_pixmap,
842                 top_level->gc, top_x, top_y, w, h, x, y);
843
844         XUnlockDisplay(top_level->display);
845 }
846
847 void BC_WindowBase::draw_background(int x, int y, int w, int h)
848 {
849         if( bg_pixmap ) {
850                 draw_tiles(bg_pixmap, 0, 0, x, y, w, h);
851         }
852         else {
853                 clear_box(x, y, w, h);
854         }
855 }
856
857 void BC_WindowBase::draw_bitmap(BC_Bitmap *bitmap, int dont_wait,
858         int dest_x, int dest_y, int dest_w, int dest_h,
859         int src_x, int src_y, int src_w, int src_h,
860         BC_Pixmap *pixmap)
861 { BT
862 // Hide cursor if video enabled
863         update_video_cursor();
864
865 //printf("BC_WindowBase::draw_bitmap %d dest_y=%d\n", __LINE__, dest_y);
866         if( dest_w <= 0 || dest_h <= 0 ) {
867 // Use hardware scaling to canvas dimensions if proper color model.
868                 if( bitmap->get_color_model() == BC_YUV420P ) {
869                         dest_w = w;
870                         dest_h = h;
871                 }
872                 else {
873                         dest_w = bitmap->get_w();
874                         dest_h = bitmap->get_h();
875                 }
876         }
877
878         if( src_w <= 0 || src_h <= 0 ) {
879                 src_w = bitmap->get_w();
880                 src_h = bitmap->get_h();
881         }
882
883         if( video_on ) {
884                 bitmap->write_drawable(win,
885                         top_level->gc, src_x, src_y, src_w, src_h,
886                         dest_x, dest_y, dest_w, dest_h, dont_wait);
887                 top_level->flush();
888         }
889         else {
890                 bitmap->write_drawable(pixmap ? pixmap->opaque_pixmap : this->pixmap->opaque_pixmap,
891                         top_level->gc, dest_x, dest_y, src_x, src_y, dest_w, dest_h, dont_wait);
892         }
893 //printf("BC_WindowBase::draw_bitmap 2\n");
894 }
895
896
897 void BC_WindowBase::draw_pixel(int x, int y, BC_Pixmap *pixmap)
898 { BT
899         XDrawPoint(top_level->display,
900                 pixmap ? pixmap->opaque_pixmap : this->pixmap->opaque_pixmap,
901                 top_level->gc, x, y);
902 }
903
904
905 void BC_WindowBase::draw_pixmap(BC_Pixmap *pixmap,
906         int dest_x, int dest_y, int dest_w, int dest_h,
907         int src_x, int src_y, BC_Pixmap *dst)
908 { BT
909         pixmap->write_drawable(dst ? dst->opaque_pixmap : this->pixmap->opaque_pixmap,
910                         dest_x, dest_y, dest_w, dest_h, src_x, src_y);
911 }
912
913 void BC_WindowBase::draw_vframe(VFrame *frame,
914         int dest_x, int dest_y, int dest_w, int dest_h,
915         int src_x, int src_y, int src_w, int src_h,
916         BC_Pixmap *pixmap)
917 {
918         if(dest_w <= 0) dest_w = frame->get_w() - src_x;
919         if(dest_h <= 0) dest_h = frame->get_h() - src_y;
920         if(src_w <= 0) src_w = frame->get_w() - src_x;
921         if(src_h <= 0) src_h = frame->get_h() - src_y;
922         CLAMP(src_x, 0, frame->get_w() - 1);
923         CLAMP(src_y, 0, frame->get_h() - 1);
924         if(src_x + src_w > frame->get_w()) src_w = frame->get_w() - src_x;
925         if(src_y + src_h > frame->get_h()) src_h = frame->get_h() - src_y;
926
927         if( !temp_bitmap )
928                 temp_bitmap = new BC_Bitmap(this, dest_w, dest_h, get_color_model(), 0);
929         temp_bitmap->match_params(dest_w, dest_h, get_color_model(), 0);
930
931         temp_bitmap->read_frame(frame,
932                 src_x, src_y, src_w, src_h,
933                 0, 0, dest_w, dest_h, bg_color);
934
935         draw_bitmap(temp_bitmap, 0,
936                 dest_x, dest_y, dest_w, dest_h,
937                 0, 0, -1, -1, pixmap);
938 }
939
940 void BC_WindowBase::draw_tooltip(const char *text)
941 {
942         if( !text )
943                 text = tooltip_text;
944         if(tooltip_popup && text)
945         {
946                 int w = tooltip_popup->get_w(), h = tooltip_popup->get_h();
947                 tooltip_popup->set_color(get_resources()->tooltip_bg_color);
948                 tooltip_popup->draw_box(0, 0, w, h);
949                 tooltip_popup->set_color(BLACK);
950                 tooltip_popup->draw_rectangle(0, 0, w, h);
951                 tooltip_popup->set_font(MEDIUMFONT);
952                 tooltip_popup->draw_text(TOOLTIP_MARGIN,
953                         get_text_ascent(MEDIUMFONT) + TOOLTIP_MARGIN,
954                         text);
955         }
956 }
957
958 void BC_WindowBase::slide_left(int distance)
959 { BT
960         if(distance < w)
961         {
962                 XCopyArea(top_level->display,
963                         pixmap->opaque_pixmap,
964                         pixmap->opaque_pixmap,
965                         top_level->gc,
966                         distance,
967                         0,
968                         w - distance,
969                         h,
970                         0,
971                         0);
972         }
973 }
974
975 void BC_WindowBase::slide_right(int distance)
976 { BT
977         if(distance < w)
978         {
979                 XCopyArea(top_level->display,
980                         pixmap->opaque_pixmap, pixmap->opaque_pixmap, top_level->gc,
981                         0, 0, w - distance, h, distance, 0);
982         }
983 }
984
985 void BC_WindowBase::slide_up(int distance)
986 { BT
987         if(distance < h)
988         {
989                 XCopyArea(top_level->display,
990                         pixmap->opaque_pixmap, pixmap->opaque_pixmap, top_level->gc,
991                         0, distance, w, h - distance, 0, 0);
992                 set_color(bg_color);
993                 XFillRectangle(top_level->display, pixmap->opaque_pixmap, top_level->gc,
994                         0, h - distance, w, distance);
995         }
996 }
997
998 void BC_WindowBase::slide_down(int distance)
999 { BT
1000         if(distance < h)
1001         {
1002                 XCopyArea(top_level->display,
1003                         pixmap->opaque_pixmap, pixmap->opaque_pixmap, top_level->gc,
1004                         0, 0, w, h - distance, 0, distance);
1005                 set_color(bg_color);
1006                 XFillRectangle(top_level->display,
1007                         pixmap->opaque_pixmap, top_level->gc,
1008                         0, 0, w, distance);
1009         }
1010 }
1011
1012 // 3 segments in separate pixmaps.  Obsolete.
1013 void BC_WindowBase::draw_3segment(int x, int y, int w, int h,
1014         BC_Pixmap *left_image, BC_Pixmap *mid_image,
1015         BC_Pixmap *right_image, BC_Pixmap *pixmap)
1016 {
1017         if(w <= 0 || h <= 0) return;
1018         int left_boundary = left_image->get_w_fixed();
1019         int right_boundary = w - right_image->get_w_fixed();
1020         for(int i = 0; i < w; )
1021         {
1022                 BC_Pixmap *image;
1023
1024                 if(i < left_boundary)
1025                         image = left_image;
1026                 else
1027                 if(i < right_boundary)
1028                         image = mid_image;
1029                 else
1030                         image = right_image;
1031
1032                 int output_w = image->get_w_fixed();
1033
1034                 if(i < left_boundary)
1035                 {
1036                         if(i + output_w > left_boundary) output_w = left_boundary - i;
1037                 }
1038                 else
1039                 if(i < right_boundary)
1040                 {
1041                         if(i + output_w > right_boundary) output_w = right_boundary - i;
1042                 }
1043                 else
1044                         if(i + output_w > w) output_w = w - i;
1045
1046                 image->write_drawable(pixmap ? pixmap->opaque_pixmap : this->pixmap->opaque_pixmap,
1047                                 x + i, y, output_w, h, 0, 0);
1048                 i += output_w;
1049         }
1050 }
1051 // 3 segments in separate vframes.  Obsolete.
1052 void BC_WindowBase::draw_3segment(int x, int y, int w, int h,
1053         VFrame *left_image, VFrame *mid_image,
1054         VFrame *right_image, BC_Pixmap *pixmap)
1055 {
1056         if(w <= 0 || h <= 0) return;
1057         int left_boundary = left_image->get_w_fixed();
1058         int right_boundary = w - right_image->get_w_fixed();
1059
1060
1061         for(int i = 0; i < w; )
1062         {
1063                 VFrame *image;
1064
1065                 if(i < left_boundary)
1066                         image = left_image;
1067                 else
1068                 if(i < right_boundary)
1069                         image = mid_image;
1070                 else
1071                         image = right_image;
1072
1073                 int output_w = image->get_w_fixed();
1074
1075                 if(i < left_boundary)
1076                 {
1077                         if(i + output_w > left_boundary) output_w = left_boundary - i;
1078                 }
1079                 else
1080                 if(i < right_boundary)
1081                 {
1082                         if(i + output_w > right_boundary) output_w = right_boundary - i;
1083                 }
1084                 else
1085                         if(i + output_w > w) output_w = w - i;
1086
1087                 if(image)
1088                         draw_vframe(image, x + i, y, output_w, h,
1089                                         0, 0, 0, 0, pixmap);
1090
1091                 if(output_w == 0) break;
1092                 i += output_w;
1093         }
1094 }
1095
1096 // Draw all 3 segments in a single vframe for a changing level
1097
1098 // total_x
1099 // <------>
1100 // total_w
1101 //         <------------------------------------------------------------>
1102 // x
1103 // |
1104 // w
1105 // <-------------------------------------------------------------------->
1106 // output
1107 //         |-------------------|----------------------|------------------|
1108
1109
1110 void BC_WindowBase::draw_3segmenth(int x, int y, int w,
1111                 VFrame *image, BC_Pixmap *pixmap)
1112 {
1113         draw_3segmenth(x, y, w, x, w, image, pixmap);
1114 }
1115
1116 void BC_WindowBase::draw_3segmenth(int x, int y, int w,
1117                 int total_x, int total_w, VFrame *image,
1118                 BC_Pixmap *pixmap)
1119 {
1120         if(total_w <= 0 || w <= 0 || h <= 0) return;
1121         int third_image = image->get_w() / 3;
1122         int half_image = image->get_w() / 2;
1123         //int left_boundary = third_image;
1124         //int right_boundary = total_w - third_image;
1125         int left_in_x = 0;
1126         int left_in_w = third_image;
1127         int left_out_x = total_x;
1128         int left_out_w = third_image;
1129         int right_in_x = image->get_w() - third_image;
1130         int right_in_w = third_image;
1131         int right_out_x = total_x + total_w - third_image;
1132         int right_out_w = third_image;
1133         int center_out_x = total_x + third_image;
1134         int center_out_w = total_w - third_image * 2;
1135         //int image_x, image_w;
1136
1137 //printf("BC_WindowBase::draw_3segment 1 left_out_x=%d left_out_w=%d center_out_x=%d center_out_w=%d right_out_x=%d right_out_w=%d\n",
1138 //      left_out_x, left_out_w, center_out_x, center_out_w, right_out_x, right_out_w);
1139
1140         if(left_out_x < x)
1141         {
1142                 left_in_w -= x - left_out_x;
1143                 left_out_w -= x - left_out_x;
1144                 left_in_x += x - left_out_x;
1145                 left_out_x += x - left_out_x;
1146         }
1147
1148         if(left_out_x + left_out_w > x + w)
1149         {
1150                 left_in_w -= (left_out_x + left_out_w) - (x + w);
1151                 left_out_w -= (left_out_x + left_out_w) - (x + w);
1152         }
1153
1154         if(right_out_x < x)
1155         {
1156                 right_in_w -= x - right_out_x;
1157                 right_out_w -= x - right_out_x;
1158                 right_in_x += x - right_out_x;
1159                 right_out_x += x - right_out_x;
1160         }
1161
1162         if(right_out_x + right_out_w > x + w)
1163         {
1164                 right_in_w -= (right_out_x + right_out_w) - (x + w);
1165                 right_out_w -= (right_out_x + right_out_w) - (x + w);
1166         }
1167
1168         if(center_out_x < x)
1169         {
1170                 center_out_w -= x - center_out_x;
1171                 center_out_x += x - center_out_x;
1172         }
1173
1174         if(center_out_x + center_out_w > x + w)
1175         {
1176                 center_out_w -= (center_out_x + center_out_w) - (x + w);
1177         }
1178
1179         if(!temp_bitmap) temp_bitmap = new BC_Bitmap(top_level,
1180                 image->get_w(), image->get_h(),
1181                 get_color_model(), 0);
1182         temp_bitmap->match_params(image->get_w(), image->get_h(),
1183                 get_color_model(), 0);
1184         temp_bitmap->read_frame(image,
1185                 0, 0, image->get_w(), image->get_h(), bg_color);
1186 // src width and height are meaningless in video_off mode
1187 //printf("BC_WindowBase::draw_3segment 2 left_out_x=%d left_out_w=%d center_out_x=%d center_out_w=%d right_out_x=%d right_out_w=%d\n",
1188 //      left_out_x, left_out_w, center_out_x, center_out_w, right_out_x, right_out_w);
1189         if(left_out_w > 0) {
1190                 draw_bitmap(temp_bitmap, 0,
1191                         left_out_x, y, left_out_w, image->get_h(),
1192                         left_in_x, 0, -1, -1, pixmap);
1193         }
1194
1195         if(right_out_w > 0) {
1196                 draw_bitmap(temp_bitmap, 0,
1197                         right_out_x, y, right_out_w, image->get_h(),
1198                         right_in_x, 0, -1, -1, pixmap);
1199         }
1200
1201         for( int pixel = center_out_x;
1202                  pixel < center_out_x + center_out_w;
1203                  pixel += half_image ) {
1204                 int fragment_w = half_image;
1205                 if(fragment_w + pixel > center_out_x + center_out_w)
1206                         fragment_w = (center_out_x + center_out_w) - pixel;
1207
1208 //printf("BC_WindowBase::draw_3segment 2 pixel=%d fragment_w=%d\n", pixel, fragment_w);
1209                 draw_bitmap(temp_bitmap, 0,
1210                         pixel, y, fragment_w, image->get_h(),
1211                         third_image, 0, -1, -1, pixmap);
1212         }
1213
1214 }
1215
1216 void BC_WindowBase::draw_3segmenth(int x, int y, int w, int total_x, int total_w,
1217                 BC_Pixmap *src, BC_Pixmap *dst)
1218 {
1219         if(w <= 0 || total_w <= 0) return;
1220         if(!src) printf("BC_WindowBase::draw_3segmenth src=0\n");
1221         int quarter_src = src->get_w() / 4;
1222         int half_src = src->get_w() / 2;
1223         //int left_boundary = quarter_src;
1224         //int right_boundary = total_w - quarter_src;
1225         int left_in_x = 0;
1226         int left_in_w = quarter_src;
1227         int left_out_x = total_x;
1228         int left_out_w = quarter_src;
1229         int right_in_x = src->get_w() - quarter_src;
1230         int right_in_w = quarter_src;
1231         int right_out_x = total_x + total_w - quarter_src;
1232         int right_out_w = quarter_src;
1233         int center_out_x = total_x + quarter_src;
1234         int center_out_w = total_w - quarter_src * 2;
1235         //int src_x, src_w;
1236
1237 //printf("BC_WindowBase::draw_3segment 1 left_out_x=%d left_out_w=%d center_out_x=%d center_out_w=%d right_out_x=%d right_out_w=%d\n",
1238 //      left_out_x, left_out_w, center_out_x, center_out_w, right_out_x, right_out_w);
1239
1240         if(left_out_x < x)
1241         {
1242                 left_in_w -= x - left_out_x;
1243                 left_out_w -= x - left_out_x;
1244                 left_in_x += x - left_out_x;
1245                 left_out_x += x - left_out_x;
1246         }
1247
1248         if(left_out_x + left_out_w > x + w)
1249         {
1250                 left_in_w -= (left_out_x + left_out_w) - (x + w);
1251                 left_out_w -= (left_out_x + left_out_w) - (x + w);
1252         }
1253
1254         if(right_out_x < x)
1255         {
1256                 right_in_w -= x - right_out_x;
1257                 right_out_w -= x - right_out_x;
1258                 right_in_x += x - right_out_x;
1259                 right_out_x += x - right_out_x;
1260         }
1261
1262         if(right_out_x + right_out_w > x + w)
1263         {
1264                 right_in_w -= (right_out_x + right_out_w) - (x + w);
1265                 right_out_w -= (right_out_x + right_out_w) - (x + w);
1266         }
1267
1268         if(center_out_x < x)
1269         {
1270                 center_out_w -= x - center_out_x;
1271                 center_out_x += x - center_out_x;
1272         }
1273
1274         if(center_out_x + center_out_w > x + w)
1275         {
1276                 center_out_w -= (center_out_x + center_out_w) - (x + w);
1277         }
1278
1279
1280 //printf("BC_WindowBase::draw_3segment 2 left_out_x=%d left_out_w=%d center_out_x=%d center_out_w=%d right_out_x=%d right_out_w=%d\n",
1281 //      left_out_x, left_out_w, center_out_x, center_out_w, right_out_x, right_out_w);
1282         if(left_out_w > 0)
1283                 draw_pixmap(src, left_out_x, y, left_out_w, src->get_h(), left_in_x, 0, dst);
1284
1285         if(right_out_w > 0)
1286                 draw_pixmap(src, right_out_x, y, right_out_w, src->get_h(), right_in_x, 0, dst);
1287
1288         for( int pixel = center_out_x; pixel < center_out_x + center_out_w; pixel += half_src) {
1289                 int fragment_w = half_src;
1290                 if(fragment_w + pixel > center_out_x + center_out_w)
1291                         fragment_w = (center_out_x + center_out_w) - pixel;
1292 //printf("BC_WindowBase::draw_3segment 2 pixel=%d fragment_w=%d\n", pixel, fragment_w);
1293                 draw_pixmap(src, pixel, y, fragment_w, src->get_h(), quarter_src, 0, dst);
1294         }
1295
1296 }
1297
1298
1299 void BC_WindowBase::draw_3segmenth(int x, int y, int w, BC_Pixmap *src, BC_Pixmap *dst)
1300 {
1301         if(w <= 0) return;
1302         int third_image = src->get_w() / 3;
1303         int half_output = w / 2;
1304         //int left_boundary = third_image;
1305         //int right_boundary = w - third_image;
1306         int left_in_x = 0;
1307         int left_in_w = third_image;
1308         int left_out_x = x;
1309         int left_out_w = third_image;
1310         int right_in_x = src->get_w() - third_image;
1311         int right_in_w = third_image;
1312         int right_out_x = x + w - third_image;
1313         int right_out_w = third_image;
1314         //int image_x, image_w;
1315
1316 //printf("BC_WindowBase::draw_3segment 1 left_out_x=%d left_out_w=%d center_out_x=%d center_out_w=%d right_out_x=%d right_out_w=%d\n",
1317 //      left_out_x, left_out_w, center_out_x, center_out_w, right_out_x, right_out_w);
1318
1319         if(left_out_w > half_output)
1320         {
1321                 left_in_w -= left_out_w - half_output;
1322                 left_out_w -= left_out_w - half_output;
1323         }
1324
1325         if(right_out_x < x + half_output)
1326         {
1327                 right_in_w -= x + half_output - right_out_x;
1328                 right_out_w -= x + half_output - right_out_x;
1329                 right_in_x += x + half_output - right_out_x;
1330                 right_out_x += x + half_output - right_out_x;
1331         }
1332
1333 //printf("BC_WindowBase::draw_3segment 2 left_out_x=%d left_out_w=%d center_out_x=%d center_out_w=%d right_out_x=%d right_out_w=%d\n",
1334 //      left_out_x, left_out_w, center_out_x, center_out_w, right_out_x, right_out_w);
1335         if(left_out_w > 0)
1336                 draw_pixmap(src, left_out_x, y, left_out_w, src->get_h(), left_in_x, 0, dst);
1337
1338         if(right_out_w > 0)
1339                 draw_pixmap(src, right_out_x, y, right_out_w, src->get_h(), right_in_x, 0, dst);
1340
1341         for(int pixel = left_out_x + left_out_w; pixel < right_out_x; pixel += third_image) {
1342                 int fragment_w = third_image;
1343                 if(fragment_w + pixel > right_out_x)
1344                         fragment_w = right_out_x - pixel;
1345
1346 //printf("BC_WindowBase::draw_3segment 2 pixel=%d fragment_w=%d\n", pixel, fragment_w);
1347                 draw_pixmap(src, pixel, y, fragment_w, src->get_h(), third_image, 0, dst);
1348         }
1349
1350 }
1351
1352 void BC_WindowBase::draw_3segmentv(int x, int y, int h, VFrame *src, BC_Pixmap *dst)
1353 {
1354         if(h <= 0) return;
1355         int third_image = src->get_h() / 3;
1356         int half_output = h / 2;
1357         //int left_boundary = third_image;
1358         //int right_boundary = h - third_image;
1359         int left_in_y = 0;
1360         int left_in_h = third_image;
1361         int left_out_y = y;
1362         int left_out_h = third_image;
1363         int right_in_y = src->get_h() - third_image;
1364         int right_in_h = third_image;
1365         int right_out_y = y + h - third_image;
1366         int right_out_h = third_image;
1367         //int image_y, image_h;
1368
1369
1370         if(left_out_h > half_output)
1371         {
1372                 left_in_h -= left_out_h - half_output;
1373                 left_out_h -= left_out_h - half_output;
1374         }
1375
1376         if(right_out_y < y + half_output)
1377         {
1378                 right_in_h -= y + half_output - right_out_y;
1379                 right_out_h -= y + half_output - right_out_y;
1380                 right_in_y += y + half_output - right_out_y;
1381                 right_out_y += y + half_output - right_out_y;
1382         }
1383
1384
1385         if(!temp_bitmap) temp_bitmap = new BC_Bitmap(top_level,
1386                 src->get_w(),
1387                 src->get_h(),
1388                 get_color_model(),
1389                 0);
1390         temp_bitmap->match_params(src->get_w(),
1391                 src->get_h(),
1392                 get_color_model(),
1393                 0);
1394         temp_bitmap->read_frame(src,
1395                 0, 0, src->get_w(), src->get_h(), bg_color);
1396
1397
1398         if(left_out_h > 0)
1399         {
1400                 draw_bitmap(temp_bitmap, 0, x, left_out_y,
1401                         src->get_w(), left_out_h, 0, left_in_y,
1402                         -1, -1, dst);
1403         }
1404
1405         if(right_out_h > 0)
1406         {
1407                 draw_bitmap(temp_bitmap, 0, x, right_out_y,
1408                         src->get_w(), right_out_h, 0, right_in_y,
1409                         -1, -1, dst);
1410         }
1411
1412         for(int pixel = left_out_y + left_out_h;
1413                 pixel < right_out_y;
1414                 pixel += third_image)
1415         {
1416                 int fragment_h = third_image;
1417                 if(fragment_h + pixel > right_out_y)
1418                         fragment_h = right_out_y - pixel;
1419
1420 //printf("BC_WindowBase::draw_3segment 2 pixel=%d fragment_w=%d\n", pixel, fragment_w);
1421                 draw_bitmap(temp_bitmap, 0, x, pixel,
1422                         src->get_w(), fragment_h, 0, third_image,
1423                         -1, -1, dst);
1424         }
1425 }
1426
1427 void BC_WindowBase::draw_3segmentv(int x,
1428                 int y,
1429                 int h,
1430                 BC_Pixmap *src,
1431                 BC_Pixmap *dst)
1432 {
1433         if(h <= 0) return;
1434         int third_image = src->get_h() / 3;
1435         int half_output = h / 2;
1436         //int left_boundary = third_image;
1437         //int right_boundary = h - third_image;
1438         int left_in_y = 0;
1439         int left_in_h = third_image;
1440         int left_out_y = y;
1441         int left_out_h = third_image;
1442         int right_in_y = src->get_h() - third_image;
1443         int right_in_h = third_image;
1444         int right_out_y = y + h - third_image;
1445         int right_out_h = third_image;
1446         //int image_y, image_h;
1447
1448
1449         if(left_out_h > half_output)
1450         {
1451                 left_in_h -= left_out_h - half_output;
1452                 left_out_h -= left_out_h - half_output;
1453         }
1454
1455         if(right_out_y < y + half_output)
1456         {
1457                 right_in_h -= y + half_output - right_out_y;
1458                 right_out_h -= y + half_output - right_out_y;
1459                 right_in_y += y + half_output - right_out_y;
1460                 right_out_y += y + half_output - right_out_y;
1461         }
1462
1463         if(left_out_h > 0)
1464                 draw_pixmap(src, x, left_out_y, src->get_w(), left_out_h,
1465                         0, left_in_y, dst);
1466
1467         if(right_out_h > 0)
1468                 draw_pixmap(src, x, right_out_y, src->get_w(), right_out_h,
1469                         0, right_in_y, dst);
1470
1471         for(int pixel = left_out_y + left_out_h; pixel < right_out_y; pixel += third_image) {
1472                 int fragment_h = third_image;
1473                 if(fragment_h + pixel > right_out_y)
1474                         fragment_h = right_out_y - pixel;
1475
1476 //printf("BC_WindowBase::draw_3segment 2 pixel=%d fragment_w=%d\n", pixel, fragment_w);
1477                 draw_pixmap(src, x, pixel, src->get_w(), fragment_h,
1478                         0, third_image, dst);
1479         }
1480 }
1481
1482
1483 void BC_WindowBase::draw_9segment(int x, int y, int w, int h,
1484                 BC_Pixmap *src, BC_Pixmap *dst)
1485 {
1486         if(w <= 0 || h <= 0) return;
1487
1488         int in_x_third = src->get_w() / 3;
1489         int in_y_third = src->get_h() / 3;
1490         int out_x_half = w / 2;
1491         int out_y_half = h / 2;
1492
1493         int in_x1 = 0;
1494         int in_y1 = 0;
1495         int out_x1 = 0;
1496         int out_y1 = 0;
1497         int in_x2 = MIN(in_x_third, out_x_half);
1498         int in_y2 = MIN(in_y_third, out_y_half);
1499         int out_x2 = in_x2;
1500         int out_y2 = in_y2;
1501
1502         int out_x3 = MAX(w - out_x_half, w - in_x_third);
1503         int out_x4 = w;
1504         int in_x3 = src->get_w() - (out_x4 - out_x3);
1505         //int in_x4 = src->get_w();
1506
1507         int out_y3 = MAX(h - out_y_half, h - in_y_third);
1508         int out_y4 = h;
1509         int in_y3 = src->get_h() - (out_y4 - out_y3);
1510         //int in_y4 = src->get_h();
1511
1512 // Segment 1
1513         draw_pixmap(src, x + out_x1, y + out_y1, out_x2 - out_x1, out_y2 - out_y1,
1514                 in_x1, in_y1, dst);
1515
1516 // Segment 2 * n
1517         for(int i = out_x2; i < out_x3; i += in_x3 - in_x2) {
1518                 if(out_x3 - i > 0) {
1519                         int w = MIN(in_x3 - in_x2, out_x3 - i);
1520                         draw_pixmap(src, x + i, y + out_y1, w, out_y2 - out_y1,
1521                                 in_x2, in_y1, dst);
1522                 }
1523         }
1524
1525 // Segment 3
1526         draw_pixmap(src, x + out_x3, y + out_y1, out_x4 - out_x3, out_y2 - out_y1,
1527                 in_x3, in_y1, dst);
1528
1529 // Segment 4 * n
1530         for(int i = out_y2; i < out_y3; i += in_y3 - in_y2)
1531         {
1532                 if(out_y3 - i > 0)
1533                 {
1534                         int h = MIN(in_y3 - in_y2, out_y3 - i);
1535                         draw_pixmap(src, x + out_x1, y + i, out_x2 - out_x1, h,
1536                                 in_x1, in_y2, dst);
1537                 }
1538         }
1539
1540 // Segment 5 * n * n
1541         for(int i = out_y2; i < out_y3; i += in_y3 - in_y2 /* in_y_third */)
1542         {
1543                 if(out_y3 - i > 0)
1544                 {
1545                         int h = MIN(in_y3 - in_y2 /* in_y_third */, out_y3 - i);
1546
1547
1548                         for(int j = out_x2; j < out_x3; j += in_x3 - in_x2 /* in_x_third */)
1549                         {
1550                                 int w = MIN(in_x3 - in_x2 /* in_x_third */, out_x3 - j);
1551                                 if(out_x3 - j > 0)
1552                                         draw_pixmap(src, x + j, y + i, w, h,
1553                                                 in_x2, in_y2, dst);
1554                         }
1555                 }
1556         }
1557
1558 // Segment 6 * n
1559         for(int i = out_y2; i < out_y3; i += in_y3 - in_y2)
1560         {
1561                 if(out_y3 - i > 0)
1562                 {
1563                         int h = MIN(in_y3 - in_y2, out_y3 - i);
1564                         draw_pixmap(src, x + out_x3, y + i, out_x4 - out_x3, h,
1565                                 in_x3, in_y2, dst);
1566                 }
1567         }
1568
1569 // Segment 7
1570         draw_pixmap(src, x + out_x1, y + out_y3, out_x2 - out_x1, out_y4 - out_y3,
1571                 in_x1, in_y3, dst);
1572
1573 // Segment 8 * n
1574         for(int i = out_x2; i < out_x3; i += in_x3 - in_x2)
1575         {
1576                 if(out_x3 - i > 0)
1577                 {
1578                         int w = MIN(in_x3 - in_y2, out_x3 - i);
1579                         draw_pixmap(src, x + i, y + out_y3, w, out_y4 - out_y3,
1580                                 in_x2, in_y3, dst);
1581                 }
1582         }
1583
1584 // Segment 9
1585         draw_pixmap(src, x + out_x3, y + out_y3, out_x4 - out_x3, out_y4 - out_y3,
1586                 in_x3, in_y3, dst);
1587 }
1588
1589
1590 void BC_WindowBase::draw_9segment(int x, int y, int w, int h,
1591                 VFrame *src, BC_Pixmap *dst)
1592 {
1593         if(w <= 0 || h <= 0) return;
1594
1595         int in_x_third = src->get_w() / 3;
1596         int in_y_third = src->get_h() / 3;
1597         int out_x_half = w / 2;
1598         int out_y_half = h / 2;
1599
1600         int in_x1 = 0;
1601         int in_y1 = 0;
1602         int out_x1 = 0;
1603         int out_y1 = 0;
1604         int in_x2 = MIN(in_x_third, out_x_half);
1605         int in_y2 = MIN(in_y_third, out_y_half);
1606         int out_x2 = in_x2;
1607         int out_y2 = in_y2;
1608
1609         int out_x3 = MAX(w - out_x_half, w - in_x_third);
1610         int out_x4 = w;
1611         int in_x3 = src->get_w() - (out_x4 - out_x3);
1612         int in_x4 = src->get_w();
1613
1614         int out_y3 = MAX(h - out_y_half, h - in_y_third);
1615         int out_y4 = h;
1616         int in_y3 = src->get_h() - (out_y4 - out_y3);
1617         int in_y4 = src->get_h();
1618
1619 //printf("PFCFrame::draw_9segment 1 %d %d %d %d\n", out_x1, out_x2, out_x3, out_x4);
1620 //printf("PFCFrame::draw_9segment 2 %d %d %d %d\n", in_x1, in_x2, in_x3, in_x4);
1621 //printf("PFCFrame::draw_9segment 2 %d %d %d %d\n", in_y1, in_y2, in_y3, in_y4);
1622
1623         if(!temp_bitmap) temp_bitmap = new BC_Bitmap(top_level,
1624                 src->get_w(),
1625                 src->get_h(),
1626                 get_color_model(),
1627                 0);
1628         temp_bitmap->match_params(src->get_w(),
1629                 src->get_h(),
1630                 get_color_model(),
1631                 0);
1632         temp_bitmap->read_frame(src,
1633                 0, 0, src->get_w(), src->get_h(), bg_color);
1634
1635 // Segment 1
1636         draw_bitmap(temp_bitmap, 0,
1637                 x + out_x1, y + out_y1, out_x2 - out_x1, out_y2 - out_y1,
1638                 in_x1, in_y1, in_x2 - in_x1, in_y2 - in_y1,
1639                 dst);
1640
1641 // Segment 2 * n
1642         for( int i = out_x2; i < out_x3; i += in_x3 - in_x2 ) {
1643                 if( out_x3 - i > 0 ) {
1644                         int w = MIN(in_x3 - in_x2, out_x3 - i);
1645                         draw_bitmap(temp_bitmap, 0,
1646                                 x + i, y + out_y1, w, out_y2 - out_y1,
1647                                 in_x2, in_y1, w, in_y2 - in_y1,
1648                                 dst);
1649                 }
1650         }
1651
1652 // Segment 3
1653         draw_bitmap(temp_bitmap, 0,
1654                 x + out_x3, y + out_y1, out_x4 - out_x3, out_y2 - out_y1,
1655                 in_x3, in_y1, in_x4 - in_x3, in_y2 - in_y1,
1656                 dst);
1657
1658 // Segment 4 * n
1659         for( int i = out_y2; i < out_y3; i += in_y3 - in_y2 ) {
1660                 if( out_y3 - i > 0 ) {
1661                         int h = MIN(in_y3 - in_y2, out_y3 - i);
1662                         draw_bitmap(temp_bitmap, 0,
1663                                 x + out_x1, y + i, out_x2 - out_x1, h,
1664                                 in_x1, in_y2, in_x2 - in_x1, h,
1665                                 dst);
1666                 }
1667         }
1668
1669 // Segment 5 * n * n
1670         for( int i = out_y2; i < out_y3; i += in_y3 - in_y2 ) {
1671                 if( out_y3 - i > 0 ) {
1672                         int h = MIN(in_y3 - in_y2, out_y3 - i);
1673
1674                         for( int j = out_x2; j < out_x3; j += in_x3 - in_x2 ) {
1675                                 int w = MIN(in_x3 - in_x2, out_x3 - j);
1676                                 if(out_x3 - j > 0)
1677                                         draw_bitmap(temp_bitmap, 0,
1678                                                 x + j, y + i, w, h,
1679                                                 in_x2, in_y2, w, h,
1680                                                 dst);
1681                         }
1682                 }
1683         }
1684
1685 // Segment 6 * n
1686         for( int i = out_y2; i < out_y3; i += in_y_third ) {
1687                 if( out_y3 - i > 0 ) {
1688                         int h = MIN(in_y_third, out_y3 - i);
1689                         draw_bitmap(temp_bitmap, 0,
1690                                 x + out_x3, y + i, out_x4 - out_x3, h,
1691                                 in_x3, in_y2, in_x4 - in_x3, h,
1692                                 dst);
1693                 }
1694         }
1695
1696 // Segment 7
1697         draw_bitmap(temp_bitmap, 0,
1698                 x + out_x1, y + out_y3, out_x2 - out_x1, out_y4 - out_y3,
1699                 in_x1, in_y3, in_x2 - in_x1, in_y4 - in_y3,
1700                 dst);
1701
1702 // Segment 8 * n
1703         for( int i = out_x2; i < out_x3; i += in_x_third ) {
1704                 if( out_x3 - i > 0 ) {
1705                         int w = MIN(in_x_third, out_x3 - i);
1706                         draw_bitmap(temp_bitmap, 0,
1707                                 x + i, y + out_y3, w, out_y4 - out_y3,
1708                                 in_x2, in_y3, w, in_y4 - in_y3,
1709                                 dst);
1710                 }
1711         }
1712
1713 // Segment 9
1714         draw_bitmap(temp_bitmap, 0,
1715                 x + out_x3, y + out_y3, out_x4 - out_x3, out_y4 - out_y3,
1716                 in_x3, in_y3, in_x4 - in_x3, in_y4 - in_y3,
1717                 dst);
1718 }
1719