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