Main Page | Modules | Class Hierarchy | Class List | Directories | File List | Class Members | File Members | Related Pages

skin_parser.cpp

00001 /*****************************************************************************
00002  * skin_parser.cpp
00003  *****************************************************************************
00004  * Copyright (C) 2004 the VideoLAN team
00005  * $Id: skin_parser.cpp 12517 2005-09-11 20:03:18Z ipkiss $
00006  *
00007  * Authors: Cyril Deguet     <[email protected]>
00008  *
00009  * This program is free software; you can redistribute it and/or modify
00010  * it under the terms of the GNU General Public License as published by
00011  * the Free Software Foundation; either version 2 of the License, or
00012  * (at your option) any later version.
00013  *
00014  * This program is distributed in the hope that it will be useful,
00015  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00016  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00017  * GNU General Public License for more details.
00018  *
00019  * You should have received a copy of the GNU General Public License
00020  * along with this program; if not, write to the Free Software
00021  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
00022  *****************************************************************************/
00023 
00024 #include "skin_parser.hpp"
00025 #include <math.h>
00026 
00027 SkinParser::SkinParser( intf_thread_t *pIntf, const string &rFileName,
00028                         const string &rPath ):
00029     XMLParser( pIntf, rFileName ), m_xOffset( 0 ), m_yOffset( 0 ),
00030     m_path( rPath )
00031 {
00032 }
00033 
00034 
00035 void SkinParser::handleBeginElement( const string &rName, AttrList_t &attr )
00036 {
00037 #define CheckDefault( a, b ) \
00038     if( attr.find(a) == attr.end() ) attr[strdup(a)] = strdup(b);
00039 #define RequireDefault( a ) \
00040     if( attr.find(a) == attr.end() ) \
00041     { \
00042         msg_Err( getIntf(), "Bad theme (element: %s, missing attribute: %s)", \
00043                  rName.c_str(), a ); \
00044         m_errors = true; return; \
00045     }
00046 
00047     if( rName == "Anchor" )
00048     {
00049         RequireDefault( "priority" );
00050         CheckDefault( "x", "0" );
00051         CheckDefault( "y", "0" );
00052         CheckDefault( "points", "(0,0)" );
00053         CheckDefault( "range", "10" );
00054 
00055         const BuilderData::Anchor anchor( atoi( attr["x"] ) + m_xOffset,
00056                 atoi( attr["y"] ) + m_yOffset, atoi( attr["range"] ),
00057                 atoi( attr["priority"] ), attr["points"], m_curLayoutId );
00058         m_data.m_listAnchor.push_back( anchor );
00059     }
00060 
00061     else if( rName == "Bitmap" )
00062     {
00063         RequireDefault( "id" );
00064         RequireDefault( "file" );
00065         RequireDefault( "alphacolor" );
00066 
00067         const BuilderData::Bitmap bitmap( uniqueId( attr["id"] ),
00068                 convertFileName( attr["file"] ),
00069                 convertColor( attr["alphacolor"] ) );
00070         m_data.m_listBitmap.push_back( bitmap );
00071     }
00072 
00073     else if( rName == "BitmapFont" )
00074     {
00075         RequireDefault( "id" );
00076         RequireDefault( "file" );
00077         CheckDefault( "type", "digits" );
00078 
00079         const BuilderData::BitmapFont font( uniqueId( attr["id"] ),
00080                 convertFileName( attr["file"] ),
00081                 attr["type"] );
00082         m_data.m_listBitmapFont.push_back( font );
00083     }
00084 
00085     else if( rName == "Button" )
00086     {
00087         RequireDefault( "up" );
00088         CheckDefault( "id", "none" );
00089         CheckDefault( "visible", "true" );
00090         CheckDefault( "x", "0" );
00091         CheckDefault( "y", "0" );
00092         CheckDefault( "lefttop", "lefttop" );
00093         CheckDefault( "rightbottom", "lefttop" );
00094         CheckDefault( "down", "none" );
00095         CheckDefault( "over", "none" );
00096         CheckDefault( "action", "none" );
00097         CheckDefault( "tooltiptext", "" );
00098         CheckDefault( "help", "" );
00099 
00100         const BuilderData::Button button( uniqueId( attr["id"] ),
00101                 atoi( attr["x"] ) + m_xOffset, atoi( attr["y"] ) + m_yOffset,
00102                 attr["lefttop"], attr["rightbottom"], attr["visible"],
00103                 attr["up"], attr["down"], attr["over"], attr["action"],
00104                 attr["tooltiptext"], attr["help"],
00105                 m_curLayer, m_curWindowId, m_curLayoutId );
00106         m_curLayer++;
00107         m_data.m_listButton.push_back( button );
00108     }
00109 
00110     else if( rName == "Checkbox" )
00111     {
00112         RequireDefault( "up1" );
00113         RequireDefault( "up2" );
00114         RequireDefault( "state" );
00115         CheckDefault( "id", "none" );
00116         CheckDefault( "visible", "true" );
00117         CheckDefault( "x", "0" );
00118         CheckDefault( "y", "0" );
00119         CheckDefault( "lefttop", "lefttop" );
00120         CheckDefault( "rightbottom", "lefttop" );
00121         CheckDefault( "down1", "none" );
00122         CheckDefault( "over1", "none" );
00123         CheckDefault( "down2", "none" );
00124         CheckDefault( "over2", "none" );
00125         CheckDefault( "action1", "none" );
00126         CheckDefault( "action2", "none" );
00127         CheckDefault( "tooltiptext1", "" );
00128         CheckDefault( "tooltiptext2", "" );
00129         CheckDefault( "help", "" );
00130 
00131         const BuilderData::Checkbox checkbox( uniqueId( attr["id"] ),
00132                 atoi( attr["x"] ) + m_xOffset, atoi( attr["y"] ) + m_yOffset,
00133                 attr["lefttop"], attr["rightbottom"], attr["visible"],
00134                 attr["up1"], attr["down1"], attr["over1"],
00135                 attr["up2"], attr["down2"], attr["over2"], attr["state"],
00136                 attr["action1"], attr["action2"], attr["tooltiptext1"],
00137                 attr["tooltiptext2"], attr["help"], m_curLayer, m_curWindowId,
00138                 m_curLayoutId );
00139         m_curLayer++;
00140         m_data.m_listCheckbox.push_back( checkbox );
00141     }
00142 
00143     else if( rName == "Font" )
00144     {
00145         RequireDefault( "id" );
00146         RequireDefault( "file" );
00147         CheckDefault( "size", "12" );
00148 
00149         const BuilderData::Font fontData( uniqueId( attr["id"] ),
00150                 convertFileName( attr["file"] ),
00151                 atoi( attr["size"] ) );
00152         m_data.m_listFont.push_back( fontData );
00153     }
00154 
00155     else if( rName == "Group" )
00156     {
00157         CheckDefault( "x", "0" );
00158         CheckDefault( "y", "0" );
00159 
00160         m_xOffset += atoi( attr["x"] );
00161         m_yOffset += atoi( attr["y"] );
00162         m_xOffsetList.push_back( atoi( attr["x"] ) );
00163         m_yOffsetList.push_back( atoi( attr["y"] ) );
00164     }
00165 
00166     else if( rName == "Image" )
00167     {
00168         RequireDefault( "image" );
00169         CheckDefault( "id", "none" );
00170         CheckDefault( "visible", "true" );
00171         CheckDefault( "x", "0" );
00172         CheckDefault( "y", "0" );
00173         CheckDefault( "lefttop", "lefttop" );
00174         CheckDefault( "rightbottom", "lefttop" );
00175         CheckDefault( "action", "none" );
00176         CheckDefault( "resize", "mosaic" );
00177         CheckDefault( "help", "" );
00178 
00179         const BuilderData::Image imageData( uniqueId( attr["id"] ),
00180                 atoi( attr["x"] ) + m_xOffset, atoi( attr["y"] ) + m_yOffset,
00181                 attr["lefttop"], attr["rightbottom"], attr["visible"],
00182                 attr["image"], attr["action"], attr["resize"], attr["help"],
00183                 m_curLayer, m_curWindowId, m_curLayoutId );
00184         m_curLayer++;
00185         m_data.m_listImage.push_back( imageData );
00186     }
00187 
00188     else if( rName == "Layout" )
00189     {
00190         RequireDefault( "width" );
00191         RequireDefault( "height" );
00192         CheckDefault( "id", "none" );
00193         CheckDefault( "minwidth", "-1" );
00194         CheckDefault( "maxwidth", "-1" );
00195         CheckDefault( "minheight", "-1" );
00196         CheckDefault( "maxheight", "-1" );
00197 
00198         m_curLayoutId = uniqueId( attr["id"] );
00199         const BuilderData::Layout layout( m_curLayoutId, atoi( attr["width"] ),
00200                 atoi( attr["height"] ), atoi( attr["minwidth"] ),
00201                 atoi( attr["maxwidth"] ), atoi( attr["minheight"] ),
00202                 atoi( attr["maxheight"] ), m_curWindowId );
00203         m_data.m_listLayout.push_back( layout );
00204         m_curLayer = 0;
00205     }
00206 
00207     else if( rName == "Playlist" )
00208     {
00209         RequireDefault( "id" );
00210         RequireDefault( "font" );
00211         CheckDefault( "visible", "true" );
00212         CheckDefault( "x", "0" );
00213         CheckDefault( "y", "0" );
00214         CheckDefault( "width", "0" );
00215         CheckDefault( "height", "0" );
00216         CheckDefault( "lefttop", "lefttop" );
00217         CheckDefault( "rightbottom", "lefttop" );
00218         CheckDefault( "bgimage", "none" );
00219         CheckDefault( "fgcolor", "#000000" );
00220         CheckDefault( "playcolor", "#FF0000" );
00221         CheckDefault( "bgcolor1", "#FFFFFF" );
00222         CheckDefault( "bgcolor2", "#FFFFFF" );
00223         CheckDefault( "selcolor", "#0000FF" );
00224         CheckDefault( "help", "" );
00225 
00226         m_curListId = uniqueId( attr["id"] );
00227         const BuilderData::List listData( m_curListId, atoi( attr["x"] ) +
00228                 m_xOffset, atoi( attr["y"] ) + m_yOffset, attr["visible"],
00229                 atoi( attr["width"]), atoi( attr["height"] ),
00230                 attr["lefttop"], attr["rightbottom"],
00231                 attr["font"], "playlist", attr["bgimage"],
00232                 convertColor( attr["fgcolor"] ),
00233                 convertColor( attr["playcolor"] ),
00234                 convertColor( attr["bgcolor1"] ),
00235                 convertColor( attr["bgcolor2"] ),
00236                 convertColor( attr["selcolor"] ), attr["help"],
00237                 m_curLayer, m_curWindowId, m_curLayoutId );
00238         m_curLayer++;
00239         m_data.m_listList.push_back( listData );
00240     }
00241 
00242     else if( rName == "Playtree" )
00243     {
00244         RequireDefault( "id" );
00245         RequireDefault( "font" );
00246         CheckDefault( "visible", "true" );
00247         CheckDefault( "x", "0" );
00248         CheckDefault( "y", "0" );
00249         CheckDefault( "width", "0" );
00250         CheckDefault( "height", "0" );
00251         CheckDefault( "lefttop", "lefttop" );
00252         CheckDefault( "rightbottom", "lefttop" );
00253         CheckDefault( "bgimage", "none" );
00254         CheckDefault( "itemimage", "none" );
00255         CheckDefault( "openimage", "none" );
00256         CheckDefault( "closedimage", "none" );
00257         CheckDefault( "fgcolor", "#000000" );
00258         CheckDefault( "playcolor", "#FF0000" );
00259         CheckDefault( "bgcolor1", "#FFFFFF" );
00260         CheckDefault( "bgcolor2", "#FFFFFF" );
00261         CheckDefault( "selcolor", "#0000FF" );
00262         CheckDefault( "help", "" );
00263 
00264         m_curTreeId = uniqueId( attr["id"] );
00265         const BuilderData::Tree treeData( m_curTreeId, atoi( attr["x"] ) +
00266                 m_xOffset, atoi( attr["y"] ) + m_yOffset, attr["visible"],
00267                 atoi( attr["width"]), atoi( attr["height"] ),
00268                 attr["lefttop"], attr["rightbottom"],
00269                 attr["font"], "playtree",
00270                 attr["bgimage"], attr["itemimage"],
00271                 attr["openimage"], attr["closedimage"],
00272                 convertColor( attr["fgcolor"] ),
00273                 convertColor( attr["playcolor"] ),
00274                 convertColor( attr["bgcolor1"] ),
00275                 convertColor( attr["bgcolor2"] ),
00276                 convertColor( attr["selcolor"] ), attr["help"],
00277                 m_curLayer, m_curWindowId, m_curLayoutId );
00278         m_curLayer++;
00279         m_data.m_listTree.push_back( treeData );
00280     }
00281 
00282     else if( rName == "RadialSlider" )
00283     {
00284         RequireDefault( "sequence" );
00285         RequireDefault( "nbimages" );
00286         CheckDefault( "id", "none" );
00287         CheckDefault( "visible", "true" );
00288         CheckDefault( "x", "0" );
00289         CheckDefault( "y", "0" );
00290         CheckDefault( "lefttop", "lefttop" );
00291         CheckDefault( "rightbottom", "lefttop" );
00292         CheckDefault( "minangle", "0" );
00293         CheckDefault( "maxangle", "360" );
00294         CheckDefault( "value", "none" );
00295         CheckDefault( "tooltiptext", "" );
00296         CheckDefault( "help", "" );
00297 
00298         const BuilderData::RadialSlider radial( uniqueId( attr["id"] ),
00299                 attr["visible"],
00300                 atoi( attr["x"] ) + m_xOffset, atoi( attr["y"] ) + m_yOffset,
00301                 attr["lefttop"], attr["rightbottom"], attr["sequence"],
00302                 atoi( attr["nbImages"] ), atof( attr["minAngle"] ) * M_PI /180,
00303                 atof( attr["maxAngle"] ) * M_PI / 180, attr["value"],
00304                 attr["tooltiptext"], attr["help"], m_curLayer, m_curWindowId,
00305                 m_curLayoutId );
00306         m_curLayer++;
00307         m_data.m_listRadialSlider.push_back( radial );
00308     }
00309 
00310     else if( rName == "Slider" )
00311     {
00312         RequireDefault( "up" );
00313         RequireDefault( "points" );
00314         CheckDefault( "id", "none" );
00315         CheckDefault( "visible", "true" );
00316         CheckDefault( "x", "0" );
00317         CheckDefault( "y", "0" );
00318         CheckDefault( "width", "0" );
00319         CheckDefault( "height", "0" );
00320         CheckDefault( "lefttop", "lefttop" );
00321         CheckDefault( "rightbottom", "lefttop" );
00322         CheckDefault( "down", "none" );
00323         CheckDefault( "over", "none" );
00324         CheckDefault( "thickness", "10" );
00325         CheckDefault( "value", "none" );
00326         CheckDefault( "tooltiptext", "" );
00327         CheckDefault( "help", "" );
00328 
00329         string newValue = attr["value"];
00330         if( m_curListId != "" )
00331         {
00332             // Slider associated to a list
00333             newValue = "playlist.slider";
00334         }
00335         else if( m_curTreeId != "" )
00336         {
00337             // Slider associated to a tree
00338             newValue = "playtree.slider";
00339         }
00340         const BuilderData::Slider slider( uniqueId( attr["id"] ),
00341                 attr["visible"],
00342                 atoi( attr["x"] ) + m_xOffset, atoi( attr["y"] ) + m_yOffset,
00343                 attr["lefttop"], attr["rightbottom"], attr["up"], attr["down"],
00344                 attr["over"], attr["points"], atoi( attr["thickness"] ),
00345                 newValue, attr["tooltiptext"], attr["help"], m_curLayer,
00346                 m_curWindowId, m_curLayoutId );
00347         m_curLayer++;
00348         m_data.m_listSlider.push_back( slider );
00349     }
00350 
00351     else if( rName == "Text" )
00352     {
00353         RequireDefault( "font" );
00354         CheckDefault( "id", "none" );
00355         CheckDefault( "visible", "true" );
00356         CheckDefault( "x", "0" );
00357         CheckDefault( "y", "0" );
00358         CheckDefault( "text", "" );
00359         CheckDefault( "color", "#000000" );
00360         CheckDefault( "width", "0" );
00361         CheckDefault( "lefttop", "lefttop" );
00362         CheckDefault( "rightbottom", "lefttop" );
00363         CheckDefault( "help", "" );
00364 
00365         const BuilderData::Text textData( uniqueId( attr["id"] ),
00366                 atoi( attr["x"] ) + m_xOffset, atoi( attr["y"] ) + m_yOffset,
00367                 attr["visible"], attr["font"],
00368                 attr["text"], atoi( attr["width"] ),
00369                 attr["lefttop"], attr["rightbottom"],
00370                 convertColor( attr["color"] ), attr["help"], m_curLayer,
00371                 m_curWindowId, m_curLayoutId );
00372         m_curLayer++;
00373         m_data.m_listText.push_back( textData );
00374     }
00375 
00376     else if( rName == "Theme" )
00377     {
00378         RequireDefault( "version" );
00379         CheckDefault( "tooltipfont", "defaultfont" );
00380         CheckDefault( "magnet", "15" );
00381         CheckDefault( "alpha", "255" );
00382         CheckDefault( "movealpha", "255" );
00383 
00384         // Check the version
00385         if( strcmp( attr["version"], SKINS_DTD_VERSION ) )
00386         {
00387             msg_Err( getIntf(), "Bad theme version : %s (you need version %s)",
00388                      attr["version"], SKINS_DTD_VERSION );
00389             m_errors = true;
00390             return;
00391         }
00392         const BuilderData::Theme theme( attr["tooltipfont"],
00393                 atoi( attr["magnet"] ),
00394                 convertInRange( attr["alpha"], 1, 255, "alpha" ),
00395                 convertInRange( attr["movealpha"], 1, 255, "movealpha" ) );
00396         m_data.m_listTheme.push_back( theme );
00397     }
00398 
00399     else if( rName == "ThemeInfo" )
00400     {
00401         msg_Info( getIntf(), "skin: %s  author: %s", attr["name"],
00402                   attr["author"] );
00403     }
00404 
00405     else if( rName == "Video" )
00406     {
00407         CheckDefault( "id", "none" );
00408         CheckDefault( "visible", "true" );
00409         CheckDefault( "x", "0" );
00410         CheckDefault( "y", "0" );
00411         CheckDefault( "width", "0" );
00412         CheckDefault( "height", "0" );
00413         CheckDefault( "lefttop", "lefttop" );
00414         CheckDefault( "rightbottom", "lefttop" );
00415         CheckDefault( "help", "" );
00416 
00417         const BuilderData::Video videoData( uniqueId( attr["id"] ),
00418                 atoi( attr["x"] ) + m_xOffset, atoi( attr["y"] ) + m_yOffset,
00419                 atoi( attr["width"] ), atoi( attr["height" ]),
00420                 attr["lefttop"], attr["rightbottom"],
00421                 attr["visible"], attr["help"], m_curLayer,
00422                 m_curWindowId, m_curLayoutId );
00423         m_curLayer++;
00424         m_data.m_listVideo.push_back( videoData );
00425     }
00426 
00427     else if( rName == "Window" )
00428     {
00429         CheckDefault( "id", "none" );
00430         CheckDefault( "visible", "true" );
00431         CheckDefault( "x", "0" );
00432         CheckDefault( "y", "0" );
00433         CheckDefault( "dragdrop", "true" );
00434         CheckDefault( "playondrop", "true" );
00435 
00436         m_curWindowId = uniqueId( attr["id"] );
00437         const BuilderData::Window window( m_curWindowId,
00438                 atoi( attr["x"] ) + m_xOffset, atoi( attr["y"] ) + m_yOffset,
00439                 convertBoolean( attr["visible"] ),
00440                 convertBoolean( attr["dragdrop"] ),
00441                 convertBoolean( attr["playondrop"] ) );
00442         m_data.m_listWindow.push_back( window );
00443     }
00444 }
00445 
00446 
00447 void SkinParser::handleEndElement( const string &rName )
00448 {
00449     if( rName == "Group" )
00450     {
00451         m_xOffset -= m_xOffsetList.back();
00452         m_yOffset -= m_yOffsetList.back();
00453         m_xOffsetList.pop_back();
00454         m_yOffsetList.pop_back();
00455     }
00456     else if( rName == "Playlist" )
00457     {
00458         m_curListId = "";
00459     }
00460     else if( rName == "Playtree" )
00461     {
00462         m_curTreeId = "";
00463     }
00464 }
00465 
00466 
00467 bool SkinParser::convertBoolean( const char *value ) const
00468 {
00469     return strcmp( value, "true" ) == 0;
00470 }
00471 
00472 
00473 int SkinParser::convertColor( const char *transcolor ) const
00474 {
00475     unsigned long iRed, iGreen, iBlue;
00476     iRed = iGreen = iBlue = 0;
00477     sscanf( transcolor, "#%2lX%2lX%2lX", &iRed, &iGreen, &iBlue );
00478     return ( iRed << 16 | iGreen << 8 | iBlue );
00479 }
00480 
00481 
00482 string SkinParser::convertFileName( const char *fileName ) const
00483 {
00484     return m_path + string( fileName );
00485 }
00486 
00487 
00488 int SkinParser::convertInRange( const char *value, int minValue, int maxValue,
00489                                 const string &rAttribute ) const
00490 {
00491     int intValue = atoi( value );
00492 
00493     if( intValue < minValue )
00494     {
00495         msg_Warn( getIntf(), "Value of \"%s\" attribute (%i) is out of the "
00496                   "expected range [%i, %i], using %i instead",
00497                   rAttribute.c_str(), intValue, minValue, maxValue, minValue );
00498         return minValue;
00499     }
00500     else if( intValue > maxValue )
00501     {
00502         msg_Warn( getIntf(), "Value of \"%s\" attribute (%i) is out of the "
00503                   "expected range [%i, %i], using %i instead",
00504                   rAttribute.c_str(), intValue, minValue, maxValue, maxValue );
00505         return maxValue;
00506     }
00507     else
00508     {
00509         return intValue;
00510     }
00511 }
00512 
00513 
00514 const string SkinParser::generateId() const
00515 {
00516     static int i = 1;
00517 
00518     char genId[5];
00519     snprintf( genId, 4, "%i", i++ );
00520 
00521     string base = "_ReservedId_" + (string)genId;
00522 
00523     return base;
00524 }
00525 
00526 
00527 const string SkinParser::uniqueId( const string &id )
00528 {
00529     string newId;
00530 
00531     if( m_idSet.find( id ) != m_idSet.end() )
00532     {
00533         // The id was already used
00534         if( id != "none" )
00535         {
00536             msg_Warn( getIntf(), "Non unique id: %s", id.c_str() );
00537         }
00538         newId = generateId();
00539     }
00540     else
00541     {
00542         // OK, this is a new id
00543         newId = id;
00544     }
00545 
00546     // Add the id to the set
00547     m_idSet.insert( newId );
00548 
00549     return newId;
00550 }

Generated on Tue Dec 20 10:14:42 2005 for vlc-0.8.4a by  doxygen 1.4.2