builder.cpp
上传用户:kjfoods
上传日期:2020-07-06
资源大小:29949k
文件大小:39k
源码类别:

midi

开发平台:

Unix_Linux

  1. /*****************************************************************************
  2.  * builder.cpp
  3.  *****************************************************************************
  4.  * Copyright (C) 2003 the VideoLAN team
  5.  * $Id: 7423822f4af4b8cdfe1fa56c8e6f4e1466f98618 $
  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., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
  23.  *****************************************************************************/
  24. #include "builder.hpp"
  25. #include "builder_data.hpp"
  26. #include "interpreter.hpp"
  27. #include "skin_parser.hpp"
  28. #include "../src/file_bitmap.hpp"
  29. #include "../src/os_factory.hpp"
  30. #include "../src/generic_bitmap.hpp"
  31. #include "../src/top_window.hpp"
  32. #include "../src/anchor.hpp"
  33. #include "../src/bitmap_font.hpp"
  34. #include "../src/ft2_font.hpp"
  35. #include "../src/ini_file.hpp"
  36. #include "../src/generic_layout.hpp"
  37. #include "../src/popup.hpp"
  38. #include "../src/theme.hpp"
  39. #include "../src/window_manager.hpp"
  40. #include "../commands/cmd_generic.hpp"
  41. #include "../controls/ctrl_button.hpp"
  42. #include "../controls/ctrl_checkbox.hpp"
  43. #include "../controls/ctrl_image.hpp"
  44. #include "../controls/ctrl_list.hpp"
  45. #include "../controls/ctrl_move.hpp"
  46. #include "../controls/ctrl_resize.hpp"
  47. #include "../controls/ctrl_slider.hpp"
  48. #include "../controls/ctrl_radialslider.hpp"
  49. #include "../controls/ctrl_text.hpp"
  50. #include "../controls/ctrl_tree.hpp"
  51. #include "../controls/ctrl_video.hpp"
  52. #include "../utils/bezier.hpp"
  53. #include "../utils/position.hpp"
  54. #include "../utils/var_bool.hpp"
  55. #include "../utils/var_text.hpp"
  56. #include "vlc_image.h"
  57. Builder::Builder( intf_thread_t *pIntf, const BuilderData &rData,
  58.                   const string &rPath ):
  59.     SkinObject( pIntf ), m_rData( rData ), m_path( rPath ), m_pTheme( NULL )
  60. {
  61.     m_pImageHandler = image_HandlerCreate( pIntf );
  62. }
  63. Builder::~Builder()
  64. {
  65.     if( m_pImageHandler ) image_HandlerDelete( m_pImageHandler );
  66. }
  67. CmdGeneric *Builder::parseAction( const string &rAction )
  68. {
  69.     return Interpreter::instance( getIntf() )->parseAction( rAction, m_pTheme );
  70. }
  71. // Useful macro
  72. #define ADD_OBJECTS( type ) 
  73.     list<BuilderData::type>::const_iterator it##type; 
  74.     for( it##type = m_rData.m_list##type.begin(); 
  75.          it##type != m_rData.m_list##type.end(); it##type++ ) 
  76.     { 
  77.         add##type( *it##type ); 
  78.     }
  79. Theme *Builder::build()
  80. {
  81.     m_pTheme = new Theme( getIntf() );
  82.     if( m_pTheme == NULL )
  83.     {
  84.         return NULL;
  85.     }
  86.     // Create everything from the data in the XML
  87.     ADD_OBJECTS( Theme );
  88.     ADD_OBJECTS( IniFile );
  89.     ADD_OBJECTS( Bitmap );
  90.     ADD_OBJECTS( SubBitmap );
  91.     ADD_OBJECTS( BitmapFont );
  92.     ADD_OBJECTS( Font );
  93.     ADD_OBJECTS( Window );
  94.     // XXX: PopupMenus are created after the windows, so that the Win32Factory
  95.     // (at least) can give a valid window handle to the OSPopup objects
  96.     ADD_OBJECTS( PopupMenu );
  97.     ADD_OBJECTS( Layout );
  98.     ADD_OBJECTS( Panel );
  99.     ADD_OBJECTS( Anchor );
  100.     ADD_OBJECTS( Button );
  101.     ADD_OBJECTS( Checkbox );
  102.     ADD_OBJECTS( Image );
  103.     ADD_OBJECTS( Text );
  104.     ADD_OBJECTS( RadialSlider );
  105.     ADD_OBJECTS( Slider );
  106.     ADD_OBJECTS( List );
  107.     ADD_OBJECTS( Tree );
  108.     ADD_OBJECTS( Video );
  109.     // MenuItems must be created after all the rest, so that the IDs of the
  110.     // other elements exist and can be parsed in the actions
  111.     ADD_OBJECTS( MenuItem );
  112.     ADD_OBJECTS( MenuSeparator );
  113.     return m_pTheme;
  114. }
  115. // Macro to get a bitmap by its ID in the builder
  116. #define GET_BMP( pBmp, id ) 
  117.     if( id != "none" ) 
  118.     { 
  119.         pBmp = m_pTheme->getBitmapById(id); 
  120.         if( pBmp == NULL ) 
  121.         { 
  122.             msg_Err( getIntf(), "unknown bitmap id: %s", id.c_str() ); 
  123.             return; 
  124.         } 
  125.     }
  126. // Macro to get the parent box of a control, given the panel ID
  127. #define GET_BOX( pRect, id, pLayout ) 
  128.     if( id == "none" ) 
  129.         pRect = &pLayout->getRect(); 
  130.     else 
  131.     { 
  132.         const Position *pParent = 
  133.             m_pTheme->getPositionById( rData.m_panelId ); 
  134.         if( pParent == NULL ) 
  135.         { 
  136.             msg_Err( getIntf(), "parent panel could not be found: %s", 
  137.                      rData.m_panelId.c_str() ); 
  138.             return; 
  139.         } 
  140.         pRect = pParent; 
  141.     }
  142. void Builder::addTheme( const BuilderData::Theme &rData )
  143. {
  144.     WindowManager &rManager = m_pTheme->getWindowManager();
  145.     rManager.setMagnetValue( rData.m_magnet );
  146.     rManager.setAlphaValue( rData.m_alpha );
  147.     rManager.setMoveAlphaValue( rData.m_moveAlpha );
  148.     GenericFont *pFont = getFont( rData.m_tooltipfont );
  149.     if( pFont )
  150.     {
  151.         rManager.createTooltip( *pFont );
  152.     }
  153.     else
  154.     {
  155.         msg_Warn( getIntf(), "invalid tooltip font: %s",
  156.                   rData.m_tooltipfont.c_str() );
  157.     }
  158. }
  159. void Builder::addIniFile( const BuilderData::IniFile &rData )
  160. {
  161.     // Parse the INI file
  162.     IniFile iniFile( getIntf(), rData.m_id, getFilePath( rData.m_file ) );
  163.     iniFile.parseFile();
  164. }
  165. void Builder::addBitmap( const BuilderData::Bitmap &rData )
  166. {
  167.     GenericBitmap *pBmp =
  168.         new FileBitmap( getIntf(), m_pImageHandler,
  169.                         getFilePath( rData.m_fileName ), rData.m_alphaColor,
  170.                         rData.m_nbFrames, rData.m_fps );
  171.     if( !pBmp->getData() )
  172.     {
  173.         // Invalid bitmap
  174.         delete pBmp;
  175.         return;
  176.     }
  177.     m_pTheme->m_bitmaps[rData.m_id] = GenericBitmapPtr( pBmp );
  178. }
  179. void Builder::addSubBitmap( const BuilderData::SubBitmap &rData )
  180. {
  181.     if( m_pTheme->m_bitmaps.find( rData.m_id ) != m_pTheme->m_bitmaps.end() )
  182.     {
  183.         msg_Dbg( getIntf(), "bitmap %s already exists", rData.m_id.c_str() );
  184.         return;
  185.     }
  186.     // Get the parent bitmap
  187.     GenericBitmap *pParentBmp = NULL;
  188.     GET_BMP( pParentBmp, rData.m_parent );
  189.     // Copy a region of the parent bitmap to the new one
  190.     BitmapImpl *pBmp =
  191.         new BitmapImpl( getIntf(), rData.m_width, rData.m_height,
  192.                         rData.m_nbFrames, rData.m_fps );
  193.     bool res = pBmp->drawBitmap( *pParentBmp, rData.m_x, rData.m_y, 0, 0,
  194.                                  rData.m_width, rData.m_height );
  195.     if( !res )
  196.     {
  197.         // Invalid sub-bitmap
  198.         delete pBmp;
  199.         msg_Warn( getIntf(), "sub-bitmap %s ignored", rData.m_id.c_str() );
  200.         return;
  201.     }
  202.     m_pTheme->m_bitmaps[rData.m_id] = GenericBitmapPtr( pBmp );
  203. }
  204. void Builder::addBitmapFont( const BuilderData::BitmapFont &rData )
  205. {
  206.     if( m_pTheme->m_fonts.find( rData.m_id ) != m_pTheme->m_fonts.end() )
  207.     {
  208.         msg_Dbg( getIntf(), "font %s already exists", rData.m_id.c_str() );
  209.         return;
  210.     }
  211.     GenericBitmap *pBmp =
  212.         new FileBitmap( getIntf(), m_pImageHandler,
  213.                         getFilePath( rData.m_file ), 0 );
  214.     if( !pBmp->getData() )
  215.     {
  216.         // Invalid bitmap
  217.         delete pBmp;
  218.         return;
  219.     }
  220.     m_pTheme->m_bitmaps[rData.m_id] = GenericBitmapPtr( pBmp );
  221.     GenericFont *pFont = new BitmapFont( getIntf(), *pBmp, rData.m_type );
  222.     if( pFont->init() )
  223.     {
  224.         m_pTheme->m_fonts[rData.m_id] = GenericFontPtr( pFont );
  225.     }
  226.     else
  227.     {
  228.         delete pFont;
  229.     }
  230. }
  231. void Builder::addFont( const BuilderData::Font &rData )
  232. {
  233.     // Try to load the font from the theme directory
  234.     GenericFont *pFont = new FT2Font( getIntf(),
  235.                                       getFilePath( rData.m_fontFile ),
  236.                                       rData.m_size );
  237.     if( pFont->init() )
  238.     {
  239.         m_pTheme->m_fonts[rData.m_id] = GenericFontPtr( pFont );
  240.     }
  241.     else
  242.     {
  243.         delete pFont;
  244.         // Font not found; try in the resource path
  245.         OSFactory *pOSFactory = OSFactory::instance( getIntf() );
  246.         const list<string> &resPath = pOSFactory->getResourcePath();
  247.         const string &sep = pOSFactory->getDirSeparator();
  248.         list<string>::const_iterator it;
  249.         for( it = resPath.begin(); it != resPath.end(); it++ )
  250.         {
  251.             string path = (*it) + sep + "fonts" + sep + rData.m_fontFile;
  252.             pFont = new FT2Font( getIntf(), path, rData.m_size );
  253.             if( pFont->init() )
  254.             {
  255.                 // Font loaded successfully
  256.                 m_pTheme->m_fonts[rData.m_id] = GenericFontPtr( pFont );
  257.                 break;
  258.             }
  259.             else
  260.             {
  261.                 delete pFont;
  262.             }
  263.         }
  264.     }
  265. }
  266. void Builder::addPopupMenu( const BuilderData::PopupMenu &rData )
  267. {
  268.     Popup *pPopup = new Popup( getIntf(), m_pTheme->getWindowManager() );
  269.     m_pTheme->m_popups[rData.m_id] = PopupPtr( pPopup );
  270. }
  271. void Builder::addMenuItem( const BuilderData::MenuItem &rData )
  272. {
  273.     Popup *pPopup = m_pTheme->getPopupById( rData.m_popupId );
  274.     if( pPopup == NULL )
  275.     {
  276.         msg_Err( getIntf(), "unknown popup id: %s", rData.m_popupId.c_str() );
  277.         return;
  278.     }
  279.     CmdGeneric *pCommand = parseAction( rData.m_action );
  280.     if( pCommand == NULL )
  281.     {
  282.         msg_Err( getIntf(), "invalid action: %s", rData.m_action.c_str() );
  283.         return;
  284.     }
  285.     pPopup->addItem( rData.m_label, *pCommand, rData.m_pos );
  286. }
  287. void Builder::addMenuSeparator( const BuilderData::MenuSeparator &rData )
  288. {
  289.     Popup *pPopup = m_pTheme->getPopupById( rData.m_popupId );
  290.     if( pPopup == NULL )
  291.     {
  292.         msg_Err( getIntf(), "unknown popup id: %s", rData.m_popupId.c_str() );
  293.         return;
  294.     }
  295.     pPopup->addSeparator( rData.m_pos );
  296. }
  297. void Builder::addWindow( const BuilderData::Window &rData )
  298. {
  299.     TopWindow *pWin =
  300.         new TopWindow( getIntf(), rData.m_xPos, rData.m_yPos,
  301.                        m_pTheme->getWindowManager(),
  302.                        rData.m_dragDrop, rData.m_playOnDrop,
  303.                        rData.m_visible );
  304.     m_pTheme->m_windows[rData.m_id] = TopWindowPtr( pWin );
  305. }
  306. void Builder::addLayout( const BuilderData::Layout &rData )
  307. {
  308.     TopWindow *pWin = m_pTheme->getWindowById( rData.m_windowId );
  309.     if( pWin == NULL )
  310.     {
  311.         msg_Err( getIntf(), "unknown window id: %s", rData.m_windowId.c_str() );
  312.         return;
  313.     }
  314.     int minWidth = rData.m_minWidth != -1 ? rData.m_minWidth : rData.m_width;
  315.     int maxWidth = rData.m_maxWidth != -1 ? rData.m_maxWidth : rData.m_width;
  316.     int minHeight = rData.m_minHeight != -1 ? rData.m_minHeight :
  317.                     rData.m_height;
  318.     int maxHeight = rData.m_maxHeight != -1 ? rData.m_maxHeight :
  319.                     rData.m_height;
  320.     GenericLayout *pLayout = new GenericLayout( getIntf(), rData.m_width,
  321.                                                 rData.m_height,
  322.                                                 minWidth, maxWidth, minHeight,
  323.                                                 maxHeight );
  324.     m_pTheme->m_layouts[rData.m_id] = GenericLayoutPtr( pLayout );
  325.     // Attach the layout to its window
  326.     m_pTheme->getWindowManager().addLayout( *pWin, *pLayout );
  327. }
  328. void Builder::addAnchor( const BuilderData::Anchor &rData )
  329. {
  330.     GenericLayout *pLayout = m_pTheme->getLayoutById( rData.m_layoutId );
  331.     if( pLayout == NULL )
  332.     {
  333.         msg_Err( getIntf(), "unknown layout id: %s", rData.m_layoutId.c_str() );
  334.         return;
  335.     }
  336.     Bezier *pCurve = getPoints( rData.m_points.c_str() );
  337.     if( pCurve == NULL )
  338.     {
  339.         msg_Err( getIntf(), "invalid format in tag points="%s"",
  340.                  rData.m_points.c_str() );
  341.         return;
  342.     }
  343.     m_pTheme->m_curves.push_back( BezierPtr( pCurve ) );
  344.     // Compute the position of the anchor
  345.     const Position pos = makePosition( rData.m_leftTop, rData.m_leftTop,
  346.                                        rData.m_xPos, rData.m_yPos,
  347.                                        pCurve->getWidth(),
  348.                                        pCurve->getHeight(),
  349.                                        pLayout->getRect() );
  350.     Anchor *pAnc = new Anchor( getIntf(), pos, rData.m_range, rData.m_priority,
  351.                                *pCurve, *pLayout );
  352.     pLayout->addAnchor( pAnc );
  353. }
  354. void Builder::addButton( const BuilderData::Button &rData )
  355. {
  356.     // Get the bitmaps of the button
  357.     GenericBitmap *pBmpUp = NULL;
  358.     GET_BMP( pBmpUp, rData.m_upId );
  359.     GenericBitmap *pBmpDown = pBmpUp;
  360.     GET_BMP( pBmpDown, rData.m_downId );
  361.     GenericBitmap *pBmpOver = pBmpUp;
  362.     GET_BMP( pBmpOver, rData.m_overId );
  363.     GenericLayout *pLayout = m_pTheme->getLayoutById( rData.m_layoutId );
  364.     if( pLayout == NULL )
  365.     {
  366.         msg_Err( getIntf(), "unknown layout id: %s", rData.m_layoutId.c_str() );
  367.         return;
  368.     }
  369.     CmdGeneric *pCommand = parseAction( rData.m_actionId );
  370.     if( pCommand == NULL )
  371.     {
  372.         msg_Err( getIntf(), "invalid action: %s", rData.m_actionId.c_str() );
  373.         return;
  374.     }
  375.     // Get the visibility variable
  376.     // XXX check when it is null
  377.     Interpreter *pInterpreter = Interpreter::instance( getIntf() );
  378.     VarBool *pVisible = pInterpreter->getVarBool( rData.m_visible, m_pTheme );
  379.     CtrlButton *pButton = new CtrlButton( getIntf(), *pBmpUp, *pBmpOver,
  380.         *pBmpDown, *pCommand, UString( getIntf(), rData.m_tooltip.c_str() ),
  381.         UString( getIntf(), rData.m_help.c_str() ), pVisible );
  382.     m_pTheme->m_controls[rData.m_id] = CtrlGenericPtr( pButton );
  383.     // Compute the position of the control
  384.     // XXX (we suppose all the images have the same size...)
  385.     const GenericRect *pRect;
  386.     GET_BOX( pRect, rData.m_panelId , pLayout);
  387.     const Position pos = makePosition( rData.m_leftTop, rData.m_rightBottom,
  388.                                        rData.m_xPos, rData.m_yPos,
  389.                                        pBmpUp->getWidth(),
  390.                                        pBmpUp->getHeight(), *pRect,
  391.                                        rData.m_xKeepRatio, rData.m_yKeepRatio );
  392.     pLayout->addControl( pButton, pos, rData.m_layer );
  393. }
  394. void Builder::addCheckbox( const BuilderData::Checkbox &rData )
  395. {
  396.     // Get the bitmaps of the checkbox
  397.     GenericBitmap *pBmpUp1 = NULL;
  398.     GET_BMP( pBmpUp1, rData.m_up1Id );
  399.     GenericBitmap *pBmpDown1 = pBmpUp1;
  400.     GET_BMP( pBmpDown1, rData.m_down1Id );
  401.     GenericBitmap *pBmpOver1 = pBmpUp1;
  402.     GET_BMP( pBmpOver1, rData.m_over1Id );
  403.     GenericBitmap *pBmpUp2 = NULL;
  404.     GET_BMP( pBmpUp2, rData.m_up2Id );
  405.     GenericBitmap *pBmpDown2 = pBmpUp2;
  406.     GET_BMP( pBmpDown2, rData.m_down2Id );
  407.     GenericBitmap *pBmpOver2 = pBmpUp2;
  408.     GET_BMP( pBmpOver2, rData.m_over2Id );
  409.     GenericLayout *pLayout = m_pTheme->getLayoutById( rData.m_layoutId );
  410.     if( pLayout == NULL )
  411.     {
  412.         msg_Err( getIntf(), "unknown layout id: %s", rData.m_layoutId.c_str() );
  413.         return;
  414.     }
  415.     CmdGeneric *pCommand1 = parseAction( rData.m_action1 );
  416.     if( pCommand1 == NULL )
  417.     {
  418.         msg_Err( getIntf(), "invalid action: %s", rData.m_action1.c_str() );
  419.         return;
  420.     }
  421.     CmdGeneric *pCommand2 = parseAction( rData.m_action2 );
  422.     if( pCommand2 == NULL )
  423.     {
  424.         msg_Err( getIntf(), "invalid action: %s", rData.m_action2.c_str() );
  425.         return;
  426.     }
  427.     // Get the state variable
  428.     Interpreter *pInterpreter = Interpreter::instance( getIntf() );
  429.     VarBool *pVar = pInterpreter->getVarBool( rData.m_state, m_pTheme );
  430.     if( pVar == NULL )
  431.     {
  432.         // TODO: default state
  433.         return;
  434.     }
  435.     // Get the visibility variable
  436.     // XXX check when it is null
  437.     VarBool *pVisible = pInterpreter->getVarBool( rData.m_visible, m_pTheme );
  438.     // Create the control
  439.     CtrlCheckbox *pCheckbox = new CtrlCheckbox( getIntf(), *pBmpUp1,
  440.         *pBmpOver1, *pBmpDown1, *pBmpUp2, *pBmpOver2, *pBmpDown2, *pCommand1,
  441.         *pCommand2, UString( getIntf(), rData.m_tooltip1.c_str() ),
  442.         UString( getIntf(), rData.m_tooltip2.c_str() ), *pVar,
  443.         UString( getIntf(), rData.m_help.c_str() ), pVisible );
  444.     m_pTheme->m_controls[rData.m_id] = CtrlGenericPtr( pCheckbox );
  445.     // Compute the position of the control
  446.     // XXX (we suppose all the images have the same size...)
  447.     const GenericRect *pRect;
  448.     GET_BOX( pRect, rData.m_panelId , pLayout);
  449.     const Position pos = makePosition( rData.m_leftTop, rData.m_rightBottom,
  450.                                        rData.m_xPos, rData.m_yPos,
  451.                                        pBmpUp1->getWidth(),
  452.                                        pBmpUp1->getHeight(), *pRect,
  453.                                        rData.m_xKeepRatio, rData.m_yKeepRatio );
  454.     pLayout->addControl( pCheckbox, pos, rData.m_layer );
  455. }
  456. void Builder::addImage( const BuilderData::Image &rData )
  457. {
  458.     GenericBitmap *pBmp = NULL;
  459.     GET_BMP( pBmp, rData.m_bmpId );
  460.     GenericLayout *pLayout = m_pTheme->getLayoutById( rData.m_layoutId );
  461.     if( pLayout == NULL )
  462.     {
  463.         msg_Err( getIntf(), "unknown layout id: %s", rData.m_layoutId.c_str() );
  464.         return;
  465.     }
  466.     TopWindow *pWindow = m_pTheme->getWindowById( rData.m_windowId );
  467.     if( pWindow == NULL )
  468.     {
  469.         msg_Err( getIntf(), "unknown window id: %s", rData.m_windowId.c_str() );
  470.         return;
  471.     }
  472.     CmdGeneric *pCommand = parseAction( rData.m_action2Id );
  473.     if( pCommand == NULL )
  474.     {
  475.         msg_Err( getIntf(), "invalid action: %s", rData.m_action2Id.c_str() );
  476.         return;
  477.     }
  478.     // Get the visibility variable
  479.     // XXX check when it is null
  480.     Interpreter *pInterpreter = Interpreter::instance( getIntf() );
  481.     VarBool *pVisible = pInterpreter->getVarBool( rData.m_visible, m_pTheme );
  482.     CtrlImage::resize_t resizeMethod =
  483.         (rData.m_resize == "scale" ? CtrlImage::kScale : CtrlImage::kMosaic);
  484.     CtrlImage *pImage = new CtrlImage( getIntf(), *pBmp, *pCommand,
  485.         resizeMethod, UString( getIntf(), rData.m_help.c_str() ), pVisible );
  486.     m_pTheme->m_controls[rData.m_id] = CtrlGenericPtr( pImage );
  487.     // Compute the position of the control
  488.     const GenericRect *pRect;
  489.     GET_BOX( pRect, rData.m_panelId , pLayout);
  490.     const Position pos = makePosition( rData.m_leftTop, rData.m_rightBottom,
  491.                                        rData.m_xPos, rData.m_yPos,
  492.                                        pBmp->getWidth(), pBmp->getHeight(),
  493.                                        *pRect, rData.m_xKeepRatio,
  494.                                        rData.m_yKeepRatio );
  495.     if( rData.m_actionId == "move" )
  496.     {
  497.         CtrlMove *pMove = new CtrlMove( getIntf(), m_pTheme->getWindowManager(),
  498.              *pImage, *pWindow, UString( getIntf(), rData.m_help.c_str() ),
  499.              pVisible );
  500.         m_pTheme->m_controls[rData.m_id + "_move"] = CtrlGenericPtr( pMove );
  501.         pLayout->addControl( pMove, pos, rData.m_layer );
  502.     }
  503.     else if( rData.m_actionId == "resizeS" )
  504.     {
  505.         CtrlResize *pResize = new CtrlResize( getIntf(),
  506.                 m_pTheme->getWindowManager(), *pImage, *pLayout,
  507.                 UString( getIntf(), rData.m_help.c_str() ), pVisible,
  508.                 WindowManager::kResizeS );
  509.         m_pTheme->m_controls[rData.m_id + "_rsz"] = CtrlGenericPtr( pResize );
  510.         pLayout->addControl( pResize, pos, rData.m_layer );
  511.     }
  512.     else if( rData.m_actionId == "resizeE" )
  513.     {
  514.         CtrlResize *pResize = new CtrlResize( getIntf(),
  515.                 m_pTheme->getWindowManager(), *pImage, *pLayout,
  516.                 UString( getIntf(), rData.m_help.c_str() ), pVisible,
  517.                 WindowManager::kResizeE );
  518.         m_pTheme->m_controls[rData.m_id + "_rsz"] = CtrlGenericPtr( pResize );
  519.         pLayout->addControl( pResize, pos, rData.m_layer );
  520.     }
  521.     else if( rData.m_actionId == "resizeSE" )
  522.     {
  523.         CtrlResize *pResize = new CtrlResize( getIntf(),
  524.                 m_pTheme->getWindowManager(), *pImage, *pLayout,
  525.                 UString( getIntf(), rData.m_help.c_str() ), pVisible,
  526.                 WindowManager::kResizeSE );
  527.         m_pTheme->m_controls[rData.m_id + "_rsz"] = CtrlGenericPtr( pResize );
  528.         pLayout->addControl( pResize, pos, rData.m_layer );
  529.     }
  530.     else
  531.     {
  532.         pLayout->addControl( pImage, pos, rData.m_layer );
  533.     }
  534. }
  535. void Builder::addPanel( const BuilderData::Panel &rData )
  536. {
  537.     // This method makes the assumption that the Panels are created in the
  538.     // order of the XML, because each child Panel expects its parent Panel
  539.     // in order to be fully created
  540.     GenericLayout *pLayout = m_pTheme->getLayoutById( rData.m_layoutId );
  541.     if( pLayout == NULL )
  542.     {
  543.         msg_Err( getIntf(), "unknown layout id: %s", rData.m_layoutId.c_str() );
  544.         return;
  545.     }
  546.     const GenericRect *pRect;
  547.     GET_BOX( pRect, rData.m_panelId , pLayout);
  548.     Position *pPos =
  549.         new Position( makePosition( rData.m_leftTop, rData.m_rightBottom,
  550.                                     rData.m_xPos, rData.m_yPos,
  551.                                     rData.m_width, rData.m_height,
  552.                                     *pRect, rData.m_xKeepRatio,
  553.                                     rData.m_yKeepRatio ) );
  554.     m_pTheme->m_positions[rData.m_id] = PositionPtr( pPos );
  555. }
  556. void Builder::addText( const BuilderData::Text &rData )
  557. {
  558.     GenericLayout *pLayout = m_pTheme->getLayoutById( rData.m_layoutId );
  559.     if( pLayout == NULL )
  560.     {
  561.         msg_Err( getIntf(), "unknown layout id: %s", rData.m_layoutId.c_str() );
  562.         return;
  563.     }
  564.     GenericFont *pFont = getFont( rData.m_fontId );
  565.     if( pFont == NULL )
  566.     {
  567.         msg_Err( getIntf(), "unknown font id: %s", rData.m_fontId.c_str() );
  568.         return;
  569.     }
  570.     // Convert the scrolling mode
  571.     CtrlText::Scrolling_t scrolling;
  572.     if( rData.m_scrolling == "auto" )
  573.         scrolling = CtrlText::kAutomatic;
  574.     else if( rData.m_scrolling == "manual" )
  575.         scrolling = CtrlText::kManual;
  576.     else if( rData.m_scrolling == "none" )
  577.         scrolling = CtrlText::kNone;
  578.     else
  579.     {
  580.         msg_Err( getIntf(), "invalid scrolling mode: %s",
  581.                  rData.m_scrolling.c_str() );
  582.         return;
  583.     }
  584.     // Convert the alignment
  585.     CtrlText::Align_t alignment;
  586.     if( rData.m_alignment == "left" )
  587.         alignment = CtrlText::kLeft;
  588.     else if( rData.m_alignment == "center" || rData.m_alignment == "centre" )
  589.         alignment = CtrlText::kCenter;
  590.     else if( rData.m_alignment == "right" )
  591.         alignment = CtrlText::kRight;
  592.     else
  593.     {
  594.         msg_Err( getIntf(), "invalid alignment: %s",
  595.                  rData.m_alignment.c_str() );
  596.         return;
  597.     }
  598.     // Create a text variable
  599.     VarText *pVar = new VarText( getIntf() );
  600.     m_pTheme->m_vars.push_back( VariablePtr( pVar ) );
  601.     // Get the visibility variable
  602.     // XXX check when it is null
  603.     Interpreter *pInterpreter = Interpreter::instance( getIntf() );
  604.     VarBool *pVisible = pInterpreter->getVarBool( rData.m_visible, m_pTheme );
  605.     CtrlText *pText = new CtrlText( getIntf(), *pVar, *pFont,
  606.         UString( getIntf(), rData.m_help.c_str() ), rData.m_color, pVisible,
  607.         scrolling, alignment );
  608.     m_pTheme->m_controls[rData.m_id] = CtrlGenericPtr( pText );
  609.     int height = pFont->getSize();
  610.     // Compute the position of the control
  611.     const GenericRect *pRect;
  612.     GET_BOX( pRect, rData.m_panelId , pLayout);
  613.     const Position pos = makePosition( rData.m_leftTop, rData.m_rightBottom,
  614.                                        rData.m_xPos, rData.m_yPos,
  615.                                        rData.m_width, height, *pRect,
  616.                                        rData.m_xKeepRatio, rData.m_yKeepRatio );
  617.     pLayout->addControl( pText, pos, rData.m_layer );
  618.     // Set the text of the control
  619.     UString msg( getIntf(), rData.m_text.c_str() );
  620.     pVar->set( msg );
  621. }
  622. void Builder::addRadialSlider( const BuilderData::RadialSlider &rData )
  623. {
  624.     // Get the bitmaps of the slider
  625.     GenericBitmap *pSeq = NULL;
  626.     GET_BMP( pSeq, rData.m_sequence );
  627.     GenericLayout *pLayout = m_pTheme->getLayoutById( rData.m_layoutId );
  628.     if( pLayout == NULL )
  629.     {
  630.         msg_Err( getIntf(), "unknown layout id: %s", rData.m_layoutId.c_str() );
  631.         return;
  632.     }
  633.     // Get the variable associated to the slider
  634.     Interpreter *pInterpreter = Interpreter::instance( getIntf() );
  635.     VarPercent *pVar = pInterpreter->getVarPercent( rData.m_value, m_pTheme );
  636.     if( pVar == NULL )
  637.     {
  638.         msg_Err( getIntf(), "unknown slider value: %s", rData.m_value.c_str() );
  639.         return;
  640.     }
  641.     // Get the visibility variable
  642.     // XXX check when it is null
  643.     VarBool *pVisible = pInterpreter->getVarBool( rData.m_visible, m_pTheme );
  644.     // Create the control
  645.     CtrlRadialSlider *pRadial =
  646.         new CtrlRadialSlider( getIntf(), *pSeq, rData.m_nbImages, *pVar,
  647.                               rData.m_minAngle, rData.m_maxAngle,
  648.                               UString( getIntf(), rData.m_help.c_str() ),
  649.                               pVisible );
  650.     m_pTheme->m_controls[rData.m_id] = CtrlGenericPtr( pRadial );
  651.     // XXX: resizing is not supported
  652.     // Compute the position of the control
  653.     const GenericRect *pRect;
  654.     GET_BOX( pRect, rData.m_panelId , pLayout);
  655.     const Position pos = makePosition( rData.m_leftTop, rData.m_rightBottom,
  656.                                        rData.m_xPos, rData.m_yPos,
  657.                                        pSeq->getWidth(),
  658.                                        pSeq->getHeight() / rData.m_nbImages,
  659.                                        *pRect,
  660.                                        rData.m_xKeepRatio, rData.m_yKeepRatio );
  661.     pLayout->addControl( pRadial, pos, rData.m_layer );
  662. }
  663. void Builder::addSlider( const BuilderData::Slider &rData )
  664. {
  665.     // Add the background first, so that we will still have something almost
  666.     // functional if the cursor cannot be created properly (this happens for
  667.     // some winamp2 skins, where the images of the cursor are not always
  668.     // present)
  669.     // Get the bitmaps of the background
  670.     GenericBitmap *pBgImage = NULL;
  671.     if( rData.m_imageId != "none" )
  672.     {
  673.         GET_BMP( pBgImage, rData.m_imageId );
  674.     }
  675.     GenericLayout *pLayout = m_pTheme->getLayoutById( rData.m_layoutId );
  676.     if( pLayout == NULL )
  677.     {
  678.         msg_Err( getIntf(), "unknown layout id: %s", rData.m_layoutId.c_str() );
  679.         return;
  680.     }
  681.     Bezier *pCurve = getPoints( rData.m_points.c_str() );
  682.     if( pCurve == NULL )
  683.     {
  684.         msg_Err( getIntf(), "invalid format in tag points="%s"",
  685.                  rData.m_points.c_str() );
  686.         return;
  687.     }
  688.     m_pTheme->m_curves.push_back( BezierPtr( pCurve ) );
  689.     // Get the visibility variable
  690.     // XXX check when it is null
  691.     Interpreter *pInterpreter = Interpreter::instance( getIntf() );
  692.     VarBool *pVisible = pInterpreter->getVarBool( rData.m_visible, m_pTheme );
  693.     // Get the variable associated to the slider
  694.     VarPercent *pVar = pInterpreter->getVarPercent( rData.m_value, m_pTheme );
  695.     if( pVar == NULL )
  696.     {
  697.         msg_Err( getIntf(), "unknown slider value: %s", rData.m_value.c_str() );
  698.         return;
  699.     }
  700.     // Create the background control
  701.     CtrlSliderBg *pBackground = new CtrlSliderBg( getIntf(),
  702.         *pCurve, *pVar, rData.m_thickness, pBgImage, rData.m_nbHoriz,
  703.         rData.m_nbVert, rData.m_padHoriz, rData.m_padVert,
  704.         pVisible, UString( getIntf(), rData.m_help.c_str() ) );
  705.     m_pTheme->m_controls[rData.m_id + "_bg"] = CtrlGenericPtr( pBackground );
  706.     // Compute the position of the control
  707.     const GenericRect *pRect;
  708.     GET_BOX( pRect, rData.m_panelId , pLayout);
  709.     const Position pos = makePosition( rData.m_leftTop, rData.m_rightBottom,
  710.                                        rData.m_xPos, rData.m_yPos,
  711.                                        pCurve->getWidth(), pCurve->getHeight(),
  712.                                        *pRect,
  713.                                        rData.m_xKeepRatio, rData.m_yKeepRatio );
  714.     pLayout->addControl( pBackground, pos, rData.m_layer );
  715.     // Get the bitmaps of the cursor
  716.     GenericBitmap *pBmpUp = NULL;
  717.     GET_BMP( pBmpUp, rData.m_upId );
  718.     GenericBitmap *pBmpDown = pBmpUp;
  719.     GET_BMP( pBmpDown, rData.m_downId );
  720.     GenericBitmap *pBmpOver = pBmpUp;
  721.     GET_BMP( pBmpOver, rData.m_overId );
  722.     // Create the cursor control
  723.     CtrlSliderCursor *pCursor = new CtrlSliderCursor( getIntf(), *pBmpUp,
  724.         *pBmpOver, *pBmpDown, *pCurve, *pVar, pVisible,
  725.         UString( getIntf(), rData.m_tooltip.c_str() ),
  726.         UString( getIntf(), rData.m_help.c_str() ) );
  727.     m_pTheme->m_controls[rData.m_id] = CtrlGenericPtr( pCursor );
  728.     pLayout->addControl( pCursor, pos, rData.m_layer );
  729.     // Associate the cursor to the background
  730.     pBackground->associateCursor( *pCursor );
  731. }
  732. void Builder::addList( const BuilderData::List &rData )
  733. {
  734.     // Get the background bitmap, if any
  735.     GenericBitmap *pBgBmp = NULL;
  736.     GET_BMP( pBgBmp, rData.m_bgImageId );
  737.     GenericLayout *pLayout = m_pTheme->getLayoutById( rData.m_layoutId );
  738.     if( pLayout == NULL )
  739.     {
  740.         msg_Err( getIntf(), "unknown layout id: %s", rData.m_layoutId.c_str() );
  741.         return;
  742.     }
  743.     GenericFont *pFont = getFont( rData.m_fontId );
  744.     if( pFont == NULL )
  745.     {
  746.         msg_Err( getIntf(), "unknown font id: %s", rData.m_fontId.c_str() );
  747.         return;
  748.     }
  749.     // Get the list variable
  750.     Interpreter *pInterpreter = Interpreter::instance( getIntf() );
  751.     VarList *pVar = pInterpreter->getVarList( rData.m_var, m_pTheme );
  752.     if( pVar == NULL )
  753.     {
  754.         msg_Err( getIntf(), "no such list variable: %s", rData.m_var.c_str() );
  755.         return;
  756.     }
  757.     // Get the visibility variable
  758.     // XXX check when it is null
  759.     VarBool *pVisible = pInterpreter->getVarBool( rData.m_visible, m_pTheme );
  760.     // Get the color values
  761.     uint32_t fgColor = getColor( rData.m_fgColor );
  762.     uint32_t playColor = getColor( rData.m_playColor );
  763.     uint32_t bgColor1 = getColor( rData.m_bgColor1 );
  764.     uint32_t bgColor2 = getColor( rData.m_bgColor2 );
  765.     uint32_t selColor = getColor( rData.m_selColor );
  766.     // Create the list control
  767.     CtrlList *pList = new CtrlList( getIntf(), *pVar, *pFont, pBgBmp,
  768.        fgColor, playColor, bgColor1, bgColor2, selColor,
  769.        UString( getIntf(), rData.m_help.c_str() ), pVisible );
  770.     m_pTheme->m_controls[rData.m_id] = CtrlGenericPtr( pList );
  771.     // Compute the position of the control
  772.     const GenericRect *pRect;
  773.     GET_BOX( pRect, rData.m_panelId , pLayout);
  774.     const Position pos = makePosition( rData.m_leftTop, rData.m_rightBottom,
  775.                                        rData.m_xPos, rData.m_yPos,
  776.                                        rData.m_width, rData.m_height,
  777.                                        *pRect,
  778.                                        rData.m_xKeepRatio, rData.m_yKeepRatio );
  779.     pLayout->addControl( pList, pos, rData.m_layer );
  780. }
  781. void Builder::addTree( const BuilderData::Tree &rData )
  782. {
  783.     // Get the bitmaps, if any
  784.     GenericBitmap *pBgBmp = NULL;
  785.     GenericBitmap *pItemBmp = NULL;
  786.     GenericBitmap *pOpenBmp = NULL;
  787.     GenericBitmap *pClosedBmp = NULL;
  788.     GET_BMP( pBgBmp, rData.m_bgImageId );
  789.     GET_BMP( pItemBmp, rData.m_itemImageId );
  790.     GET_BMP( pOpenBmp, rData.m_openImageId );
  791.     GET_BMP( pClosedBmp, rData.m_closedImageId );
  792.     GenericLayout *pLayout = m_pTheme->getLayoutById( rData.m_layoutId );
  793.     if( pLayout == NULL )
  794.     {
  795.         msg_Err( getIntf(), "unknown layout id: %s", rData.m_layoutId.c_str() );
  796.         return;
  797.     }
  798.     GenericFont *pFont = getFont( rData.m_fontId );
  799.     if( pFont == NULL )
  800.     {
  801.         msg_Err( getIntf(), "unknown font id: %s", rData.m_fontId.c_str() );
  802.         return;
  803.     }
  804.     // Get the list variable
  805.     Interpreter *pInterpreter = Interpreter::instance( getIntf() );
  806.     VarTree *pVar = pInterpreter->getVarTree( rData.m_var, m_pTheme );
  807.     if( pVar == NULL )
  808.     {
  809.         msg_Err( getIntf(), "no such list variable: %s", rData.m_var.c_str() );
  810.         return;
  811.     }
  812.     // Get the visibility variable
  813.     // XXX check when it is null
  814.     VarBool *pVisible = pInterpreter->getVarBool( rData.m_visible, m_pTheme );
  815.     VarBool *pFlat = pInterpreter->getVarBool( rData.m_flat, m_pTheme );
  816.     // Get the color values
  817.     uint32_t fgColor = getColor( rData.m_fgColor );
  818.     uint32_t playColor = getColor( rData.m_playColor );
  819.     uint32_t bgColor1 = getColor( rData.m_bgColor1 );
  820.     uint32_t bgColor2 = getColor( rData.m_bgColor2 );
  821.     uint32_t selColor = getColor( rData.m_selColor );
  822.     // Create the list control
  823.     CtrlTree *pTree = new CtrlTree( getIntf(), *pVar, *pFont, pBgBmp,
  824.        pItemBmp, pOpenBmp, pClosedBmp,
  825.        fgColor, playColor, bgColor1, bgColor2, selColor,
  826.        UString( getIntf(), rData.m_help.c_str() ), pVisible, pFlat );
  827.     m_pTheme->m_controls[rData.m_id] = CtrlGenericPtr( pTree );
  828.     // Compute the position of the control
  829.     const GenericRect *pRect;
  830.     GET_BOX( pRect, rData.m_panelId , pLayout);
  831.     const Position pos = makePosition( rData.m_leftTop, rData.m_rightBottom,
  832.                                        rData.m_xPos, rData.m_yPos,
  833.                                        rData.m_width, rData.m_height,
  834.                                        *pRect,
  835.                                        rData.m_xKeepRatio, rData.m_yKeepRatio );
  836.     pLayout->addControl( pTree, pos, rData.m_layer );
  837. }
  838. void Builder::addVideo( const BuilderData::Video &rData )
  839. {
  840.     GenericLayout *pLayout = m_pTheme->getLayoutById( rData.m_layoutId );
  841.     if( pLayout == NULL )
  842.     {
  843.         msg_Err( getIntf(), "unknown layout id: %s", rData.m_layoutId.c_str() );
  844.         return;
  845.     }
  846.     // Get the visibility variable
  847.     // XXX check when it is null
  848.     Interpreter *pInterpreter = Interpreter::instance( getIntf() );
  849.     VarBool *pVisible = pInterpreter->getVarBool( rData.m_visible, m_pTheme );
  850.     CtrlVideo *pVideo = new CtrlVideo( getIntf(), *pLayout,
  851.         rData.m_autoResize, UString( getIntf(), rData.m_help.c_str() ),
  852.         pVisible );
  853.     m_pTheme->m_controls[rData.m_id] = CtrlGenericPtr( pVideo );
  854.     // Compute the position of the control
  855.     const GenericRect *pRect;
  856.     GET_BOX( pRect, rData.m_panelId , pLayout);
  857.     const Position pos = makePosition( rData.m_leftTop, rData.m_rightBottom,
  858.                                        rData.m_xPos, rData.m_yPos,
  859.                                        rData.m_width, rData.m_height,
  860.                                        *pRect,
  861.                                        rData.m_xKeepRatio, rData.m_yKeepRatio );
  862.     pLayout->addControl( pVideo, pos, rData.m_layer );
  863. }
  864. const Position Builder::makePosition( const string &rLeftTop,
  865.                                       const string &rRightBottom,
  866.                                       int xPos, int yPos, int width,
  867.                                       int height, const GenericRect &rRect,
  868.                                       bool xKeepRatio, bool yKeepRatio ) const
  869. {
  870.     int left = 0, top = 0, right = 0, bottom = 0;
  871.     Position::Ref_t refLeftTop = Position::kLeftTop;
  872.     Position::Ref_t refRightBottom = Position::kLeftTop;
  873.     int boxWidth = rRect.getWidth();
  874.     int boxHeight = rRect.getHeight();
  875.     // Position of the left top corner
  876.     if( rLeftTop == "lefttop" )
  877.     {
  878.         left = xPos;
  879.         top = yPos;
  880.         refLeftTop = Position::kLeftTop;
  881.     }
  882.     else if( rLeftTop == "righttop" )
  883.     {
  884.         left = xPos - boxWidth + 1;
  885.         top = yPos;
  886.         refLeftTop = Position::kRightTop;
  887.     }
  888.     else if( rLeftTop == "leftbottom" )
  889.     {
  890.         left = xPos;
  891.         top = yPos - boxHeight + 1;
  892.         refLeftTop = Position::kLeftBottom;
  893.     }
  894.     else if( rLeftTop == "rightbottom" )
  895.     {
  896.         left = xPos - boxWidth + 1;
  897.         top = yPos - boxHeight + 1;
  898.         refLeftTop = Position::kRightBottom;
  899.     }
  900.     // Position of the right bottom corner
  901.     if( rRightBottom == "lefttop" )
  902.     {
  903.         right = xPos + width - 1;
  904.         bottom = yPos + height - 1;
  905.         refRightBottom = Position::kLeftTop;
  906.     }
  907.     else if( rRightBottom == "righttop" )
  908.     {
  909.         right = xPos + width - boxWidth;
  910.         bottom = yPos + height - 1;
  911.         refRightBottom = Position::kRightTop;
  912.     }
  913.     else if( rRightBottom == "leftbottom" )
  914.     {
  915.         right = xPos + width - 1;
  916.         bottom = yPos + height - boxHeight;
  917.         refRightBottom = Position::kLeftBottom;
  918.     }
  919.     else if( rRightBottom == "rightbottom" )
  920.     {
  921.         right = xPos + width - boxWidth;
  922.         bottom = yPos + height - boxHeight;
  923.         refRightBottom = Position::kRightBottom;
  924.     }
  925.     // In "keep ratio" mode, overwrite the previously computed values with the
  926.     // actual ones
  927.     // XXX: this coupling between makePosition and the Position class should
  928.     // be reduced...
  929.     if( xKeepRatio )
  930.     {
  931.         left = xPos;
  932.         right = xPos + width;
  933.     }
  934.     if( yKeepRatio )
  935.     {
  936.         top = yPos;
  937.         bottom = yPos + height;
  938.     }
  939.     return Position( left, top, right, bottom, rRect, refLeftTop,
  940.                      refRightBottom, xKeepRatio, yKeepRatio );
  941. }
  942. GenericFont *Builder::getFont( const string &fontId )
  943. {
  944.     GenericFont *pFont = m_pTheme->getFontById(fontId);
  945.     if( !pFont && fontId == "defaultfont" )
  946.     {
  947.         // Get the resource path and try to load the default font
  948.         OSFactory *pOSFactory = OSFactory::instance( getIntf() );
  949.         const list<string> &resPath = pOSFactory->getResourcePath();
  950.         const string &sep = pOSFactory->getDirSeparator();
  951.         list<string>::const_iterator it;
  952.         for( it = resPath.begin(); it != resPath.end(); it++ )
  953.         {
  954.             string path = (*it) + sep + "fonts" + sep + "FreeSans.ttf";
  955.             pFont = new FT2Font( getIntf(), path, 12 );
  956.             if( pFont->init() )
  957.             {
  958.                 // Font loaded successfully
  959.                 m_pTheme->m_fonts["defaultfont"] = GenericFontPtr( pFont );
  960.                 break;
  961.             }
  962.             else
  963.             {
  964.                 delete pFont;
  965.                 pFont = NULL;
  966.             }
  967.         }
  968.         if( !pFont )
  969.         {
  970.             msg_Err( getIntf(), "failed to open the default font" );
  971.         }
  972.     }
  973.     return pFont;
  974. }
  975. string Builder::getFilePath( const string &rFileName ) const
  976. {
  977.     OSFactory *pFactory = OSFactory::instance( getIntf() );
  978.     return m_path + pFactory->getDirSeparator() + sFromLocale( rFileName );
  979. }
  980. Bezier *Builder::getPoints( const char *pTag ) const
  981. {
  982.     vector<float> xBez, yBez;
  983.     int x, y, n;
  984.     while( 1 )
  985.     {
  986.         if( sscanf( pTag, "(%d,%d)%n", &x, &y, &n ) < 1 )
  987.         {
  988.             return NULL;
  989.         }
  990.         xBez.push_back( x );
  991.         yBez.push_back( y );
  992.         pTag += n;
  993.         if( *pTag == '' )
  994.         {
  995.             break;
  996.         }
  997.         if( *(pTag++) != ',' )
  998.         {
  999.             return NULL;
  1000.         }
  1001.     }
  1002.     // Create the Bezier curve
  1003.     return new Bezier( getIntf(), xBez, yBez );
  1004. }
  1005. uint32_t Builder::getColor( const string &rVal ) const
  1006. {
  1007.     // Check it the value is a registered constant
  1008.     Interpreter *pInterpreter = Interpreter::instance( getIntf() );
  1009.     string val = pInterpreter->getConstant( rVal );
  1010.     // Convert to an int value
  1011.     return SkinParser::convertColor( val.c_str() );
  1012. }