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