* Playtree start. Basic functionalities work. Still needs a lot of
[vlc.git] / modules / gui / skins2 / parser / builder.cpp
1 /*****************************************************************************
2  * builder.cpp
3  *****************************************************************************
4  * Copyright (C) 2003 the VideoLAN team
5  * $Id$
6  *
7  * Authors: Cyril Deguet     <asmax@via.ecp.fr>
8  *          Olivier Teulière <ipkiss@via.ecp.fr>
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
23  *****************************************************************************/
24
25 #include <string.h>
26 #include "builder.hpp"
27 #include "builder_data.hpp"
28 #include "interpreter.hpp"
29 #include "../src/png_bitmap.hpp"
30 #include "../src/os_factory.hpp"
31 #include "../src/generic_bitmap.hpp"
32 #include "../src/top_window.hpp"
33 #include "../src/anchor.hpp"
34 #include "../src/bitmap_font.hpp"
35 #include "../src/ft2_font.hpp"
36 #include "../src/theme.hpp"
37 #include "../controls/ctrl_button.hpp"
38 #include "../controls/ctrl_checkbox.hpp"
39 #include "../controls/ctrl_image.hpp"
40 #include "../controls/ctrl_list.hpp"
41 #include "../controls/ctrl_move.hpp"
42 #include "../controls/ctrl_resize.hpp"
43 #include "../controls/ctrl_slider.hpp"
44 #include "../controls/ctrl_radialslider.hpp"
45 #include "../controls/ctrl_text.hpp"
46 #include "../controls/ctrl_tree.hpp"
47 #include "../controls/ctrl_video.hpp"
48 #include "../utils/position.hpp"
49 #include "../utils/var_bool.hpp"
50 #include "../utils/var_text.hpp"
51
52 #include "vlc_image.h"
53
54
55 Builder::Builder( intf_thread_t *pIntf, const BuilderData &rData ):
56     SkinObject( pIntf ), m_rData( rData ), m_pTheme( NULL )
57 {
58     m_pImageHandler = image_HandlerCreate( pIntf );
59 }
60
61 Builder::~Builder()
62 {
63     if( m_pImageHandler ) image_HandlerDelete( m_pImageHandler );
64 }
65
66 CmdGeneric *Builder::parseAction( const string &rAction )
67 {
68     return Interpreter::instance( getIntf() )->parseAction( rAction, m_pTheme );
69 }
70
71
72 // Useful macro
73 #define ADD_OBJECTS( type ) \
74     list<BuilderData::type>::const_iterator it##type; \
75     for( it##type = m_rData.m_list##type.begin(); \
76          it##type != m_rData.m_list##type.end(); it##type++ ) \
77     { \
78         add##type( *it##type ); \
79     }
80
81
82 Theme *Builder::build()
83 {
84     m_pTheme = new Theme( getIntf() );
85     if( m_pTheme == NULL )
86     {
87         return NULL;
88     }
89
90     // Create everything from the data in the XML
91     ADD_OBJECTS( Theme );
92     ADD_OBJECTS( Bitmap );
93     ADD_OBJECTS( BitmapFont );
94     ADD_OBJECTS( Font );
95     ADD_OBJECTS( Window );
96     ADD_OBJECTS( Layout );
97     ADD_OBJECTS( Anchor );
98     ADD_OBJECTS( Button );
99     ADD_OBJECTS( Checkbox );
100     ADD_OBJECTS( Image );
101     ADD_OBJECTS( Text );
102     ADD_OBJECTS( RadialSlider );
103     ADD_OBJECTS( Slider );
104     ADD_OBJECTS( List );
105     ADD_OBJECTS( Tree );
106     ADD_OBJECTS( Video );
107
108     return m_pTheme;
109 }
110
111
112 // Macro to get a bitmap by its ID in the builder
113 #define GET_BMP( pBmp, id ) \
114     if( id != "none" ) \
115     { \
116         pBmp = m_pTheme->getBitmapById(id); \
117         if( pBmp == NULL ) \
118         { \
119             msg_Err( getIntf(), "unknown bitmap id: %s", id.c_str() ); \
120             return; \
121         } \
122     }
123
124 void Builder::addTheme( const BuilderData::Theme &rData )
125 {
126     WindowManager &rManager = m_pTheme->getWindowManager();
127     rManager.setMagnetValue( rData.m_magnet );
128     rManager.setAlphaValue( rData.m_alpha );
129     rManager.setMoveAlphaValue( rData.m_moveAlpha );
130     GenericFont *pFont = getFont( rData.m_tooltipfont );
131     if( pFont )
132     {
133         rManager.createTooltip( *pFont );
134     }
135     else
136     {
137         msg_Warn( getIntf(), "Invalid tooltip font: %s",
138                   rData.m_tooltipfont.c_str() );
139     }
140 }
141
142
143 void Builder::addBitmap( const BuilderData::Bitmap &rData )
144 {
145     GenericBitmap *pBmp =
146         new PngBitmap( getIntf(), m_pImageHandler,
147                        rData.m_fileName, rData.m_alphaColor );
148     m_pTheme->m_bitmaps[rData.m_id] = GenericBitmapPtr( pBmp );
149 }
150
151
152 void Builder::addBitmapFont( const BuilderData::BitmapFont &rData )
153 {
154     GenericBitmap *pBmp =
155         new PngBitmap( getIntf(), m_pImageHandler, rData.m_file, 0 );
156     m_pTheme->m_bitmaps[rData.m_id] = GenericBitmapPtr( pBmp );
157
158     GenericFont *pFont = new BitmapFont( getIntf(), *pBmp, rData.m_type );
159     if( pFont->init() )
160     {
161         m_pTheme->m_fonts[rData.m_id] = GenericFontPtr( pFont );
162     }
163     else
164     {
165         delete pFont;
166     }
167 }
168
169
170 void Builder::addFont( const BuilderData::Font &rData )
171 {
172     GenericFont *pFont = new FT2Font( getIntf(), rData.m_fontFile,
173                                       rData.m_size );
174     if( pFont->init() )
175     {
176         m_pTheme->m_fonts[rData.m_id] = GenericFontPtr( pFont );
177     }
178     else
179     {
180         delete pFont;
181     }
182 }
183
184
185 void Builder::addWindow( const BuilderData::Window &rData )
186 {
187     TopWindow *pWin =
188         new TopWindow( getIntf(), rData.m_xPos, rData.m_yPos,
189                            m_pTheme->getWindowManager(),
190                            rData.m_dragDrop, rData.m_playOnDrop );
191
192     m_pTheme->m_windows[rData.m_id] = TopWindowPtr( pWin );
193 }
194
195
196 void Builder::addLayout( const BuilderData::Layout &rData )
197 {
198     TopWindow *pWin = m_pTheme->getWindowById(rData.m_windowId);
199     if( pWin == NULL )
200     {
201         msg_Err( getIntf(), "unknown window id: %s", rData.m_windowId.c_str() );
202         return;
203     }
204
205     int minWidth = rData.m_minWidth != -1 ? rData.m_minWidth : rData.m_width;
206     int maxWidth = rData.m_maxWidth != -1 ? rData.m_maxWidth : rData.m_width;
207     int minHeight = rData.m_minHeight != -1 ? rData.m_minHeight :
208                     rData.m_height;
209     int maxHeight = rData.m_maxHeight != -1 ? rData.m_maxHeight :
210                     rData.m_height;
211     GenericLayout *pLayout = new GenericLayout( getIntf(), rData.m_width,
212                                                 rData.m_height,
213                                                 minWidth, maxWidth, minHeight,
214                                                 maxHeight );
215     m_pTheme->m_layouts[rData.m_id] = GenericLayoutPtr( pLayout );
216
217     // Attach the layout to its window
218     m_pTheme->getWindowManager().addLayout( *pWin, *pLayout );
219 }
220
221
222 void Builder::addAnchor( const BuilderData::Anchor &rData )
223 {
224     GenericLayout *pLayout = m_pTheme->getLayoutById(rData.m_layoutId);
225     if( pLayout == NULL )
226     {
227         msg_Err( getIntf(), "unknown layout id: %s", rData.m_layoutId.c_str() );
228         return;
229     }
230
231     Bezier *pCurve = getPoints( rData.m_points.c_str() );
232     if( pCurve == NULL )
233     {
234         msg_Err( getIntf(), "Invalid format in tag points=\"%s\"",
235                  rData.m_points.c_str() );
236         return;
237     }
238     m_pTheme->m_curves.push_back( BezierPtr( pCurve ) );
239
240     Anchor *pAnc = new Anchor( getIntf(), rData.m_xPos, rData.m_yPos,
241                                rData.m_range, rData.m_priority,
242                                *pCurve, *pLayout );
243     pLayout->addAnchor( pAnc );
244 }
245
246
247 void Builder::addButton( const BuilderData::Button &rData )
248 {
249     // Get the bitmaps of the button
250     GenericBitmap *pBmpUp = NULL;
251     GET_BMP( pBmpUp, rData.m_upId );
252
253     GenericBitmap *pBmpDown = pBmpUp;
254     GET_BMP( pBmpDown, rData.m_downId );
255
256     GenericBitmap *pBmpOver = pBmpUp;
257     GET_BMP( pBmpOver, rData.m_overId );
258
259     GenericLayout *pLayout = m_pTheme->getLayoutById(rData.m_layoutId);
260     if( pLayout == NULL )
261     {
262         msg_Err( getIntf(), "unknown layout id: %s", rData.m_layoutId.c_str() );
263         return;
264     }
265
266     CmdGeneric *pCommand = parseAction( rData.m_actionId );
267     if( pCommand == NULL )
268     {
269         msg_Err( getIntf(), "Invalid action: %s", rData.m_actionId.c_str() );
270         return;
271     }
272
273     // Get the visibility variable
274     // XXX check when it is null
275     Interpreter *pInterpreter = Interpreter::instance( getIntf() );
276     VarBool *pVisible = pInterpreter->getVarBool( rData.m_visible, m_pTheme );
277
278     CtrlButton *pButton = new CtrlButton( getIntf(), *pBmpUp, *pBmpOver,
279         *pBmpDown, *pCommand, UString( getIntf(), rData.m_tooltip.c_str() ),
280         UString( getIntf(), rData.m_help.c_str() ), pVisible );
281
282     // Compute the position of the control
283     // XXX (we suppose all the images have the same size...)
284     const Position pos = makePosition( rData.m_leftTop, rData.m_rightBottom,
285                                        rData.m_xPos, rData.m_yPos,
286                                        pBmpUp->getWidth(),
287                                        pBmpUp->getHeight(), *pLayout );
288
289     pLayout->addControl( pButton, pos, rData.m_layer );
290
291     m_pTheme->m_controls[rData.m_id] = CtrlGenericPtr( pButton );
292 }
293
294
295 void Builder::addCheckbox( const BuilderData::Checkbox &rData )
296 {
297     // Get the bitmaps of the checkbox
298     GenericBitmap *pBmpUp1 = NULL;
299     GET_BMP( pBmpUp1, rData.m_up1Id );
300
301     GenericBitmap *pBmpDown1 = pBmpUp1;
302     GET_BMP( pBmpDown1, rData.m_down1Id );
303
304     GenericBitmap *pBmpOver1 = pBmpUp1;
305     GET_BMP( pBmpOver1, rData.m_over1Id );
306
307     GenericBitmap *pBmpUp2 = NULL;
308     GET_BMP( pBmpUp2, rData.m_up2Id );
309
310     GenericBitmap *pBmpDown2 = pBmpUp2;
311     GET_BMP( pBmpDown2, rData.m_down2Id );
312
313     GenericBitmap *pBmpOver2 = pBmpUp2;
314     GET_BMP( pBmpOver2, rData.m_over2Id );
315
316     GenericLayout *pLayout = m_pTheme->getLayoutById(rData.m_layoutId);
317     if( pLayout == NULL )
318     {
319         msg_Err( getIntf(), "unknown layout id: %s", rData.m_layoutId.c_str() );
320         return;
321     }
322
323     CmdGeneric *pCommand1 = parseAction( rData.m_action1 );
324     if( pCommand1 == NULL )
325     {
326         msg_Err( getIntf(), "Invalid action: %s", rData.m_action1.c_str() );
327         return;
328     }
329
330     CmdGeneric *pCommand2 = parseAction( rData.m_action2 );
331     if( pCommand2 == NULL )
332     {
333         msg_Err( getIntf(), "Invalid action: %s", rData.m_action2.c_str() );
334         return;
335     }
336
337     // Get the state variable
338     Interpreter *pInterpreter = Interpreter::instance( getIntf() );
339     VarBool *pVar = pInterpreter->getVarBool( rData.m_state, m_pTheme );
340     if( pVar == NULL )
341     {
342         // TODO: default state
343         return;
344     }
345
346     // Get the visibility variable
347     // XXX check when it is null
348     VarBool *pVisible = pInterpreter->getVarBool( rData.m_visible, m_pTheme );
349
350     // Create the control
351     CtrlCheckbox *pCheckbox = new CtrlCheckbox( getIntf(), *pBmpUp1,
352         *pBmpOver1, *pBmpDown1, *pBmpUp2, *pBmpOver2, *pBmpDown2, *pCommand1,
353         *pCommand2, UString( getIntf(), rData.m_tooltip1.c_str() ),
354         UString( getIntf(), rData.m_tooltip2.c_str() ), *pVar,
355         UString( getIntf(), rData.m_help.c_str() ), pVisible );
356
357     // Compute the position of the control
358     // XXX (we suppose all the images have the same size...)
359     const Position pos = makePosition( rData.m_leftTop, rData.m_rightBottom,
360                                        rData.m_xPos, rData.m_yPos,
361                                        pBmpUp1->getWidth(),
362                                        pBmpUp1->getHeight(), *pLayout );
363
364     pLayout->addControl( pCheckbox, pos, rData.m_layer );
365
366     m_pTheme->m_controls[rData.m_id] = CtrlGenericPtr( pCheckbox );
367 }
368
369
370 void Builder::addImage( const BuilderData::Image &rData )
371 {
372     GenericBitmap *pBmp = NULL;
373     GET_BMP( pBmp, rData.m_bmpId );
374
375     GenericLayout *pLayout = m_pTheme->getLayoutById(rData.m_layoutId);
376     if( pLayout == NULL )
377     {
378         msg_Err( getIntf(), "unknown layout id: %s", rData.m_layoutId.c_str() );
379         return;
380     }
381
382     TopWindow *pWindow = m_pTheme->getWindowById(rData.m_windowId);
383     if( pWindow == NULL )
384     {
385         msg_Err( getIntf(), "unknown window id: %s", rData.m_windowId.c_str() );
386         return;
387     }
388
389     // Get the visibility variable
390     // XXX check when it is null
391     Interpreter *pInterpreter = Interpreter::instance( getIntf() );
392     VarBool *pVisible = pInterpreter->getVarBool( rData.m_visible, m_pTheme );
393
394     CtrlImage::resize_t resizeMethod =
395         (rData.m_resize == "scale" ? CtrlImage::kScale : CtrlImage::kMosaic);
396     CtrlImage *pImage = new CtrlImage( getIntf(), *pBmp, resizeMethod,
397         UString( getIntf(), rData.m_help.c_str() ), pVisible );
398
399     // Compute the position of the control
400     const Position pos = makePosition( rData.m_leftTop, rData.m_rightBottom,
401                                        rData.m_xPos,
402                                        rData.m_yPos, pBmp->getWidth(),
403                                        pBmp->getHeight(), *pLayout );
404
405     // XXX: test to be changed! XXX
406     if( rData.m_actionId == "move" )
407     {
408         CtrlMove *pMove = new CtrlMove( getIntf(), m_pTheme->getWindowManager(),
409              *pImage, *pWindow, UString( getIntf(), rData.m_help.c_str() ),
410              NULL);
411         pLayout->addControl( pMove, pos, rData.m_layer );
412     }
413     else if( rData.m_actionId == "resizeSE" )
414     {
415         CtrlResize *pResize = new CtrlResize( getIntf(), *pImage, *pLayout,
416                 UString( getIntf(), rData.m_help.c_str() ), NULL );
417         pLayout->addControl( pResize, pos, rData.m_layer );
418     }
419     else
420     {
421         pLayout->addControl( pImage, pos, rData.m_layer );
422     }
423
424     m_pTheme->m_controls[rData.m_id] = CtrlGenericPtr( pImage );
425 }
426
427
428 void Builder::addText( const BuilderData::Text &rData )
429 {
430     GenericLayout *pLayout = m_pTheme->getLayoutById(rData.m_layoutId);
431     if( pLayout == NULL )
432     {
433         msg_Err( getIntf(), "unknown layout id: %s", rData.m_layoutId.c_str() );
434         return;
435     }
436
437     GenericFont *pFont = getFont( rData.m_fontId );
438     if( pFont == NULL )
439     {
440         msg_Err( getIntf(), "Unknown font id: %s", rData.m_fontId.c_str() );
441         return;
442     }
443
444     // Create a text variable
445     VarText *pVar = new VarText( getIntf() );
446     UString msg( getIntf(), rData.m_text.c_str() );
447     pVar->set( msg );
448     m_pTheme->m_vars.push_back( VariablePtr( pVar ) );
449
450     // Get the visibility variable
451     // XXX check when it is null
452     Interpreter *pInterpreter = Interpreter::instance( getIntf() );
453     VarBool *pVisible = pInterpreter->getVarBool( rData.m_visible, m_pTheme );
454
455     CtrlText *pText = new CtrlText( getIntf(), *pVar, *pFont,
456         UString( getIntf(), rData.m_help.c_str() ), rData.m_color, pVisible );
457
458     int height = pFont->getSize();
459
460     // Compute the position of the control
461     const Position pos = makePosition( rData.m_leftTop, rData.m_rightBottom,
462                                        rData.m_xPos, rData.m_yPos,
463                                        rData.m_width, height,
464                                        *pLayout );
465
466     pLayout->addControl( pText, pos, rData.m_layer );
467
468     m_pTheme->m_controls[rData.m_id] = CtrlGenericPtr( pText );
469 }
470
471
472 void Builder::addRadialSlider( const BuilderData::RadialSlider &rData )
473 {
474     // Get the bitmaps of the slider
475     GenericBitmap *pSeq = NULL;
476     GET_BMP( pSeq, rData.m_sequence );
477
478     GenericLayout *pLayout = m_pTheme->getLayoutById(rData.m_layoutId);
479     if( pLayout == NULL )
480     {
481         msg_Err( getIntf(), "unknown layout id: %s", rData.m_layoutId.c_str() );
482         return;
483     }
484
485     // Get the variable associated to the slider
486     Interpreter *pInterpreter = Interpreter::instance( getIntf() );
487     VarPercent *pVar = pInterpreter->getVarPercent( rData.m_value, m_pTheme );
488     if( pVar == NULL )
489     {
490         msg_Err( getIntf(), "Unknown slider value: %s", rData.m_value.c_str() );
491         return;
492     }
493
494     // Get the visibility variable
495     // XXX check when it is null
496     VarBool *pVisible = pInterpreter->getVarBool( rData.m_visible, m_pTheme );
497
498     // Create the control
499     CtrlRadialSlider *pRadial =
500         new CtrlRadialSlider( getIntf(), *pSeq, rData.m_nbImages, *pVar,
501                               rData.m_minAngle, rData.m_maxAngle,
502                               UString( getIntf(), rData.m_help.c_str() ),
503                               pVisible );
504
505     // XXX: resizing is not supported
506     // Compute the position of the control
507     const Position pos =
508         makePosition( rData.m_leftTop, rData.m_rightBottom, rData.m_xPos,
509                       rData.m_yPos, pSeq->getWidth(),
510                       pSeq->getHeight() / rData.m_nbImages, *pLayout );
511
512     pLayout->addControl( pRadial, pos, rData.m_layer );
513
514     m_pTheme->m_controls[rData.m_id] = CtrlGenericPtr( pRadial );
515 }
516
517
518 void Builder::addSlider( const BuilderData::Slider &rData )
519 {
520     // Get the bitmaps of the slider
521     GenericBitmap *pBmpUp = NULL;
522     GET_BMP( pBmpUp, rData.m_upId );
523
524     GenericBitmap *pBmpDown = pBmpUp;
525     GET_BMP( pBmpDown, rData.m_downId );
526
527     GenericBitmap *pBmpOver = pBmpUp;
528     GET_BMP( pBmpOver, rData.m_overId );
529
530     GenericLayout *pLayout = m_pTheme->getLayoutById(rData.m_layoutId);
531     if( pLayout == NULL )
532     {
533         msg_Err( getIntf(), "unknown layout id: %s", rData.m_layoutId.c_str() );
534         return;
535     }
536
537     Bezier *pCurve = getPoints( rData.m_points.c_str() );
538     if( pCurve == NULL )
539     {
540         msg_Err( getIntf(), "Invalid format in tag points=\"%s\"",
541                  rData.m_points.c_str() );
542         return;
543     }
544     m_pTheme->m_curves.push_back( BezierPtr( pCurve ) );
545
546     // Get the visibility variable
547     // XXX check when it is null
548     Interpreter *pInterpreter = Interpreter::instance( getIntf() );
549     VarBool *pVisible = pInterpreter->getVarBool( rData.m_visible, m_pTheme );
550
551     // Get the variable associated to the slider
552     VarPercent *pVar = pInterpreter->getVarPercent( rData.m_value, m_pTheme );
553     if( pVar == NULL )
554     {
555         msg_Err( getIntf(), "Unknown slider value: %s", rData.m_value.c_str() );
556         return;
557     }
558
559     // Create the cursor and background controls
560     CtrlSliderCursor *pCursor = new CtrlSliderCursor( getIntf(), *pBmpUp,
561         *pBmpOver, *pBmpDown, *pCurve, *pVar, pVisible,
562         UString( getIntf(), rData.m_tooltip.c_str() ),
563         UString( getIntf(), rData.m_help.c_str() ) );
564
565     CtrlSliderBg *pBackground = new CtrlSliderBg( getIntf(), *pCursor,
566         *pCurve, *pVar, rData.m_thickness, pVisible,
567         UString( getIntf(), rData.m_help.c_str() ) );
568
569     // Compute the position of the control
570     const Position pos = makePosition( rData.m_leftTop, rData.m_rightBottom,
571                                        rData.m_xPos, rData.m_yPos,
572                                        pCurve->getWidth(), pCurve->getHeight(),
573                                        *pLayout );
574
575     pLayout->addControl( pBackground, pos, rData.m_layer );
576     pLayout->addControl( pCursor, pos, rData.m_layer );
577
578     m_pTheme->m_controls[rData.m_id] = CtrlGenericPtr( pCursor );
579     m_pTheme->m_controls[rData.m_id + "_bg"] = CtrlGenericPtr( pBackground );
580 }
581
582
583 void Builder::addList( const BuilderData::List &rData )
584 {
585     // Get the background bitmap, if any
586     GenericBitmap *pBgBmp = NULL;
587     GET_BMP( pBgBmp, rData.m_bgImageId );
588
589     GenericLayout *pLayout = m_pTheme->getLayoutById(rData.m_layoutId);
590     if( pLayout == NULL )
591     {
592         msg_Err( getIntf(), "unknown layout id: %s", rData.m_layoutId.c_str() );
593         return;
594     }
595
596     GenericFont *pFont = getFont( rData.m_fontId );
597     if( pFont == NULL )
598     {
599         msg_Err( getIntf(), "Unknown font id: %s", rData.m_fontId.c_str() );
600         return;
601     }
602
603     // Get the list variable
604     Interpreter *pInterpreter = Interpreter::instance( getIntf() );
605     VarList *pVar = pInterpreter->getVarList( rData.m_var, m_pTheme );
606     if( pVar == NULL )
607     {
608         msg_Err( getIntf(), "No such list variable: %s", rData.m_var.c_str() );
609         return;
610     }
611
612     // Get the visibility variable
613     // XXX check when it is null
614     VarBool *pVisible = pInterpreter->getVarBool( rData.m_visible, m_pTheme );
615
616     // Create the list control
617     CtrlList *pList = new CtrlList( getIntf(), *pVar, *pFont, pBgBmp,
618        rData.m_fgColor, rData.m_playColor, rData.m_bgColor1,
619        rData.m_bgColor2, rData.m_selColor,
620        UString( getIntf(), rData.m_help.c_str() ), pVisible );
621
622     // Compute the position of the control
623     const Position pos = makePosition( rData.m_leftTop, rData.m_rightBottom,
624                                        rData.m_xPos, rData.m_yPos,
625                                        rData.m_width, rData.m_height,
626                                        *pLayout );
627
628     pLayout->addControl( pList, pos, rData.m_layer );
629
630     m_pTheme->m_controls[rData.m_id] = CtrlGenericPtr( pList );
631 }
632
633 void Builder::addTree( const BuilderData::Tree &rData )
634 {
635     // Get the bitmaps, if any
636     GenericBitmap *pBgBmp = NULL;
637     GenericBitmap *pItemBmp = NULL;
638     GenericBitmap *pOpenBmp = NULL;
639     GenericBitmap *pClosedBmp = NULL;
640     GET_BMP( pBgBmp, rData.m_bgImageId );
641     GET_BMP( pItemBmp, rData.m_itemImageId );
642     GET_BMP( pOpenBmp, rData.m_openImageId );
643     GET_BMP( pClosedBmp, rData.m_closedImageId );
644
645     GenericLayout *pLayout = m_pTheme->getLayoutById(rData.m_layoutId);
646     if( pLayout == NULL )
647     {
648         msg_Err( getIntf(), "unknown layout id: %s", rData.m_layoutId.c_str() );
649         return;
650     }
651
652     GenericFont *pFont = getFont( rData.m_fontId );
653     if( pFont == NULL )
654     {
655         msg_Err( getIntf(), "Unknown font id: %s", rData.m_fontId.c_str() );
656         return;
657     }
658
659     // Get the list variable
660     Interpreter *pInterpreter = Interpreter::instance( getIntf() );
661     VarTree *pVar = pInterpreter->getVarTree( rData.m_var, m_pTheme );
662     if( pVar == NULL )
663     {
664         msg_Err( getIntf(), "No such list variable: %s", rData.m_var.c_str() );
665         return;
666     }
667
668     // Get the visibility variable
669     // XXX check when it is null
670     VarBool *pVisible = pInterpreter->getVarBool( rData.m_visible, m_pTheme );
671
672     // Create the list control
673     CtrlTree *pTree = new CtrlTree( getIntf(), *pVar, *pFont, pBgBmp,
674        pItemBmp, pOpenBmp, pClosedBmp,
675        rData.m_fgColor, rData.m_playColor, rData.m_bgColor1,
676        rData.m_bgColor2, rData.m_selColor,
677        UString( getIntf(), rData.m_help.c_str() ), pVisible );
678
679     // Compute the position of the control
680     const Position pos = makePosition( rData.m_leftTop, rData.m_rightBottom,
681                                        rData.m_xPos, rData.m_yPos,
682                                        rData.m_width, rData.m_height,
683                                        *pLayout );
684
685     pLayout->addControl( pTree, pos, rData.m_layer );
686
687     m_pTheme->m_controls[rData.m_id] = CtrlGenericPtr( pTree );
688 }
689
690 void Builder::addVideo( const BuilderData::Video &rData )
691 {
692     GenericLayout *pLayout = m_pTheme->getLayoutById(rData.m_layoutId);
693     if( pLayout == NULL )
694     {
695         msg_Err( getIntf(), "unknown layout id: %s", rData.m_layoutId.c_str() );
696         return;
697     }
698
699     // Get the visibility variable
700     // XXX check when it is null
701     Interpreter *pInterpreter = Interpreter::instance( getIntf() );
702     VarBool *pVisible = pInterpreter->getVarBool( rData.m_visible, m_pTheme );
703
704     CtrlVideo *pVideo = new CtrlVideo( getIntf(),
705         UString( getIntf(), rData.m_help.c_str() ), pVisible );
706
707     // Compute the position of the control
708     const Position pos = makePosition( rData.m_leftTop, rData.m_rightBottom,
709                                        rData.m_xPos, rData.m_yPos,
710                                        rData.m_width, rData.m_height,
711                                        *pLayout );
712
713     pLayout->addControl( pVideo, pos, rData.m_layer );
714
715     m_pTheme->m_controls[rData.m_id] = CtrlGenericPtr( pVideo );
716 }
717
718
719 const Position Builder::makePosition( const string &rLeftTop,
720                                       const string &rRightBottom,
721                                       int xPos, int yPos, int width,
722                                       int height, const Box &rBox ) const
723 {
724     int left = 0, top = 0, right = 0, bottom = 0;
725     Position::Ref_t refLeftTop = Position::kLeftTop;
726     Position::Ref_t refRightBottom = Position::kLeftTop;
727
728     int boxWidth = rBox.getWidth();
729     int boxHeight = rBox.getHeight();
730
731     // Position of the left top corner
732     if( rLeftTop == "lefttop" )
733     {
734         left = xPos;
735         top = yPos;
736         refLeftTop = Position::kLeftTop;
737     }
738     else if( rLeftTop == "righttop" )
739     {
740         left = xPos - boxWidth + 1;
741         top = yPos;
742         refLeftTop = Position::kRightTop;
743     }
744     else if( rLeftTop == "leftbottom" )
745     {
746         left = xPos;
747         top = yPos - boxHeight + 1;
748         refLeftTop = Position::kLeftBottom;
749     }
750     else if( rLeftTop == "rightbottom" )
751     {
752         left = xPos - boxWidth + 1;
753         top = yPos - boxHeight + 1;
754         refLeftTop = Position::kRightBottom;
755     }
756
757     // Position of the right bottom corner
758     if( rRightBottom == "lefttop" )
759     {
760         right = xPos + width - 1;
761         bottom = yPos + height - 1;
762         refRightBottom = Position::kLeftTop;
763     }
764     else if( rRightBottom == "righttop" )
765     {
766         right = xPos + width - boxWidth;
767         bottom = yPos + height - 1;
768         refRightBottom = Position::kRightTop;
769     }
770     else if( rRightBottom == "leftbottom" )
771     {
772         right = xPos + width - 1;
773         bottom = yPos + height - boxHeight;
774         refRightBottom = Position::kLeftBottom;
775     }
776     else if( rRightBottom == "rightbottom" )
777     {
778         right = xPos + width - boxWidth;
779         bottom = yPos + height - boxHeight;
780         refRightBottom = Position::kRightBottom;
781     }
782
783     return Position( left, top, right, bottom, rBox, refLeftTop,
784                      refRightBottom );
785 }
786
787
788 GenericFont *Builder::getFont( const string &fontId )
789 {
790     GenericFont *pFont = m_pTheme->getFontById(fontId);
791     if( !pFont && fontId == "defaultfont" )
792     {
793         // Get the resource path and try to load the default font
794         OSFactory *pOSFactory = OSFactory::instance( getIntf() );
795         const list<string> &resPath = pOSFactory->getResourcePath();
796         const string &sep = pOSFactory->getDirSeparator();
797
798         list<string>::const_iterator it;
799         for( it = resPath.begin(); it != resPath.end(); it++ )
800         {
801             string path = (*it) + sep + "fonts" + sep + "FreeSans.ttf";
802             pFont = new FT2Font( getIntf(), path, 12 );
803             if( pFont->init() )
804             {
805                 // Font loaded successfully
806                 m_pTheme->m_fonts["defaultfont"] = GenericFontPtr( pFont );
807                 break;
808             }
809             else
810             {
811                 delete pFont;
812                 pFont = NULL;
813             }
814         }
815         if( !pFont )
816         {
817             msg_Err( getIntf(), "Failed to open the default font" );
818         }
819     }
820     return pFont;
821 }
822
823
824 Bezier *Builder::getPoints( const char *pTag ) const
825 {
826     vector<float> xBez, yBez;
827     int x, y, n;
828     while( 1 )
829     {
830         if( sscanf( pTag, "(%d,%d)%n", &x, &y, &n ) < 1 )
831         {
832             return NULL;
833         }
834 #if 0
835         if( x < 0 || y < 0 )
836         {
837             msg_Err( getIntf(),
838                      "Slider points cannot have negative coordinates!" );
839             return NULL;
840         }
841 #endif
842         xBez.push_back( x );
843         yBez.push_back( y );
844         pTag += n;
845         if( *pTag == '\0' )
846         {
847             break;
848         }
849         if( *(pTag++) != ',' )
850         {
851             return NULL;
852         }
853     }
854
855     // Create the Bezier curve
856     return new Bezier( getIntf(), xBez, yBez );
857 }
858