X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=modules%2Fgui%2Fskins2%2Fparser%2Fskin_parser.cpp;h=0b56b860eb0fab3e4a7db68dd6e52107088dda0b;hb=e0352f9138f8da06abf7cb621011bbfafda9c803;hp=7d92e8583faac83f76c58bbfc3603f45213a47f3;hpb=4999de8d3c4e95cffb32a2091025d62c17e023a1;p=vlc diff --git a/modules/gui/skins2/parser/skin_parser.cpp b/modules/gui/skins2/parser/skin_parser.cpp index 7d92e8583f..0b56b860eb 100644 --- a/modules/gui/skins2/parser/skin_parser.cpp +++ b/modules/gui/skins2/parser/skin_parser.cpp @@ -1,8 +1,8 @@ /***************************************************************************** * skin_parser.cpp ***************************************************************************** - * Copyright (C) 2004 VideoLAN - * $Id: skin_parser.cpp,v 1.5 2004/03/02 21:45:15 ipkiss Exp $ + * Copyright (C) 2004 the VideoLAN team + * $Id$ * * Authors: Cyril Deguet * @@ -22,51 +22,132 @@ *****************************************************************************/ #include "skin_parser.hpp" +#include "../src/os_factory.hpp" #include -// Current DTD version -#define SKINS_DTD_VERSION "1.99" - - -SkinParser::SkinParser( intf_thread_t *pIntf, const string &rFileName ): - XMLParser( pIntf, rFileName ), m_xOffset( 0 ), m_yOffset( 0 ) +SkinParser::SkinParser( intf_thread_t *pIntf, const string &rFileName, + const string &rPath ): + XMLParser( pIntf, rFileName ), m_xOffset( 0 ), m_yOffset( 0 ), + m_path( rPath ) { } void SkinParser::handleBeginElement( const string &rName, AttrList_t &attr ) { +#define CheckDefault( a, b ) \ + if( attr.find(a) == attr.end() ) attr[strdup(a)] = strdup(b); +#define RequireDefault( a ) \ + if( attr.find(a) == attr.end() ) \ + { \ + msg_Err( getIntf(), "Bad theme (element: %s, missing attribute: %s)", \ + rName.c_str(), a ); \ + m_errors = true; return; \ + } + if( rName == "Anchor" ) { + RequireDefault( "priority" ); + CheckDefault( "x", "0" ); + CheckDefault( "y", "0" ); + CheckDefault( "points", "(0,0)" ); + CheckDefault( "range", "10" ); + const BuilderData::Anchor anchor( atoi( attr["x"] ) + m_xOffset, atoi( attr["y"] ) + m_yOffset, atoi( attr["range"] ), - atoi( attr["priority"] ), attr["points"], m_curWindowId ); + atoi( attr["priority"] ), attr["points"], m_curLayoutId ); m_data.m_listAnchor.push_back( anchor ); } else if( rName == "Bitmap" ) { - const BuilderData::Bitmap bitmap( attr["id"] , attr["file"], - ConvertColor( attr["alphacolor"] ) ); + RequireDefault( "id" ); + RequireDefault( "file" ); + RequireDefault( "alphacolor" ); + + m_curBitmapId = uniqueId( attr["id"] ); + const BuilderData::Bitmap bitmap( m_curBitmapId, + convertFileName( attr["file"] ), + convertColor( attr["alphacolor"] ) ); m_data.m_listBitmap.push_back( bitmap ); } + else if( rName == "SubBitmap" ) + { + RequireDefault( "id" ); + RequireDefault( "x" ); + RequireDefault( "y" ); + RequireDefault( "width" ); + RequireDefault( "height" ); + + const BuilderData::SubBitmap bitmap( uniqueId( attr["id"] ), + m_curBitmapId, atoi( attr["x"] ), atoi( attr["y"] ), + atoi( attr["width"] ), atoi( attr["height"] ) ); + m_data.m_listSubBitmap.push_back( bitmap ); + } + + else if( rName == "BitmapFont" ) + { + RequireDefault( "id" ); + RequireDefault( "file" ); + CheckDefault( "type", "digits" ); + + const BuilderData::BitmapFont font( attr["id"], + convertFileName( attr["file"] ), + attr["type"] ); + m_data.m_listBitmapFont.push_back( font ); + } + else if( rName == "Button" ) { - const BuilderData::Button button( uniqueId( attr["id"] ), atoi( attr["x"] ) + - m_xOffset, atoi( attr["y"] ) + m_yOffset, attr["lefttop"], - attr["rightbottom"], attr["up"], attr["down"], attr["over"], - attr["action"], attr["tooltiptext"], attr["help"], m_curLayer, - m_curWindowId, m_curLayoutId ); + RequireDefault( "up" ); + CheckDefault( "id", "none" ); + CheckDefault( "visible", "true" ); + CheckDefault( "x", "0" ); + CheckDefault( "y", "0" ); + CheckDefault( "lefttop", "lefttop" ); + CheckDefault( "rightbottom", "lefttop" ); + CheckDefault( "down", "none" ); + CheckDefault( "over", "none" ); + CheckDefault( "action", "none" ); + CheckDefault( "tooltiptext", "" ); + CheckDefault( "help", "" ); + + const BuilderData::Button button( uniqueId( attr["id"] ), + atoi( attr["x"] ) + m_xOffset, atoi( attr["y"] ) + m_yOffset, + attr["lefttop"], attr["rightbottom"], attr["visible"], + attr["up"], attr["down"], attr["over"], attr["action"], + attr["tooltiptext"], attr["help"], + m_curLayer, m_curWindowId, m_curLayoutId ); m_curLayer++; m_data.m_listButton.push_back( button ); } - else if( rName == "CheckBox" ) + else if( rName == "Checkbox" ) { - const BuilderData::Checkbox checkbox( uniqueId( attr["id"] ), atoi( attr["x"] ) + - m_xOffset, atoi( attr["y"] ) + m_yOffset, attr["lefttop"], - attr["rightbottom"], attr["up1"], attr["down1"], attr["over1"], + RequireDefault( "up1" ); + RequireDefault( "up2" ); + RequireDefault( "state" ); + CheckDefault( "id", "none" ); + CheckDefault( "visible", "true" ); + CheckDefault( "x", "0" ); + CheckDefault( "y", "0" ); + CheckDefault( "lefttop", "lefttop" ); + CheckDefault( "rightbottom", "lefttop" ); + CheckDefault( "down1", "none" ); + CheckDefault( "over1", "none" ); + CheckDefault( "down2", "none" ); + CheckDefault( "over2", "none" ); + CheckDefault( "action1", "none" ); + CheckDefault( "action2", "none" ); + CheckDefault( "tooltiptext1", "" ); + CheckDefault( "tooltiptext2", "" ); + CheckDefault( "help", "" ); + + const BuilderData::Checkbox checkbox( uniqueId( attr["id"] ), + atoi( attr["x"] ) + m_xOffset, atoi( attr["y"] ) + m_yOffset, + attr["lefttop"], attr["rightbottom"], attr["visible"], + attr["up1"], attr["down1"], attr["over1"], attr["up2"], attr["down2"], attr["over2"], attr["state"], attr["action1"], attr["action2"], attr["tooltiptext1"], attr["tooltiptext2"], attr["help"], m_curLayer, m_curWindowId, @@ -77,13 +158,21 @@ void SkinParser::handleBeginElement( const string &rName, AttrList_t &attr ) else if( rName == "Font" ) { - const BuilderData::Font fontData( attr["id"], attr["font"], + RequireDefault( "id" ); + RequireDefault( "file" ); + CheckDefault( "size", "12" ); + + const BuilderData::Font fontData( uniqueId( attr["id"] ), + convertFileName( attr["file"] ), atoi( attr["size"] ) ); m_data.m_listFont.push_back( fontData ); } else if( rName == "Group" ) { + CheckDefault( "x", "0" ); + CheckDefault( "y", "0" ); + m_xOffset += atoi( attr["x"] ); m_yOffset += atoi( attr["y"] ); m_xOffsetList.push_back( atoi( attr["x"] ) ); @@ -92,17 +181,36 @@ void SkinParser::handleBeginElement( const string &rName, AttrList_t &attr ) else if( rName == "Image" ) { - const BuilderData::Image imageData( uniqueId( attr["id"] ), atoi( attr["x"] ) + - m_xOffset, atoi( attr["y"] ) + m_yOffset, attr["lefttop"], - attr["rightbottom"], ConvertBoolean( attr["visible"] ), - attr["image"], attr["onclick"], attr["help"], m_curLayer, - m_curWindowId, m_curLayoutId ); + RequireDefault( "image" ); + CheckDefault( "id", "none" ); + CheckDefault( "visible", "true" ); + CheckDefault( "x", "0" ); + CheckDefault( "y", "0" ); + CheckDefault( "lefttop", "lefttop" ); + CheckDefault( "rightbottom", "lefttop" ); + CheckDefault( "action", "none" ); + CheckDefault( "resize", "mosaic" ); + CheckDefault( "help", "" ); + + const BuilderData::Image imageData( uniqueId( attr["id"] ), + atoi( attr["x"] ) + m_xOffset, atoi( attr["y"] ) + m_yOffset, + attr["lefttop"], attr["rightbottom"], attr["visible"], + attr["image"], attr["action"], attr["resize"], attr["help"], + m_curLayer, m_curWindowId, m_curLayoutId ); m_curLayer++; m_data.m_listImage.push_back( imageData ); } else if( rName == "Layout" ) { + RequireDefault( "width" ); + RequireDefault( "height" ); + CheckDefault( "id", "none" ); + CheckDefault( "minwidth", "-1" ); + CheckDefault( "maxwidth", "-1" ); + CheckDefault( "minheight", "-1" ); + CheckDefault( "maxheight", "-1" ); + m_curLayoutId = uniqueId( attr["id"] ); const BuilderData::Layout layout( m_curLayoutId, atoi( attr["width"] ), atoi( attr["height"] ), atoi( attr["minwidth"] ), @@ -114,26 +222,100 @@ void SkinParser::handleBeginElement( const string &rName, AttrList_t &attr ) else if( rName == "Playlist" ) { + RequireDefault( "id" ); + RequireDefault( "font" ); + CheckDefault( "visible", "true" ); + CheckDefault( "x", "0" ); + CheckDefault( "y", "0" ); + CheckDefault( "width", "0" ); + CheckDefault( "height", "0" ); + CheckDefault( "lefttop", "lefttop" ); + CheckDefault( "rightbottom", "lefttop" ); + CheckDefault( "bgimage", "none" ); + CheckDefault( "fgcolor", "#000000" ); + CheckDefault( "playcolor", "#FF0000" ); + CheckDefault( "bgcolor1", "#FFFFFF" ); + CheckDefault( "bgcolor2", "#FFFFFF" ); + CheckDefault( "selcolor", "#0000FF" ); + CheckDefault( "help", "" ); + m_curListId = uniqueId( attr["id"] ); const BuilderData::List listData( m_curListId, atoi( attr["x"] ) + - m_xOffset, atoi( attr["y"] ) + m_yOffset, atoi( attr["width"]), - atoi( attr["height"] ), attr["lefttop"], attr["rightbottom"], - attr["font"], attr["var"], ConvertColor( attr["fgcolor"] ), - ConvertColor( attr["playcolor"] ), - ConvertColor( attr["bgcolor1"] ), - ConvertColor( attr["bgcolor2"] ), - ConvertColor( attr["selcolor"] ), attr["help"], + m_xOffset, atoi( attr["y"] ) + m_yOffset, attr["visible"], + atoi( attr["width"]), atoi( attr["height"] ), + attr["lefttop"], attr["rightbottom"], + attr["font"], "playlist", attr["bgimage"], + convertColor( attr["fgcolor"] ), + convertColor( attr["playcolor"] ), + convertColor( attr["bgcolor1"] ), + convertColor( attr["bgcolor2"] ), + convertColor( attr["selcolor"] ), attr["help"], m_curLayer, m_curWindowId, m_curLayoutId ); m_curLayer++; m_data.m_listList.push_back( listData ); } + else if( rName == "Playtree" ) + { + RequireDefault( "id" ); + RequireDefault( "font" ); + CheckDefault( "visible", "true" ); + CheckDefault( "x", "0" ); + CheckDefault( "y", "0" ); + CheckDefault( "width", "0" ); + CheckDefault( "height", "0" ); + CheckDefault( "lefttop", "lefttop" ); + CheckDefault( "rightbottom", "lefttop" ); + CheckDefault( "bgimage", "none" ); + CheckDefault( "itemimage", "none" ); + CheckDefault( "openimage", "none" ); + CheckDefault( "closedimage", "none" ); + CheckDefault( "fgcolor", "#000000" ); + CheckDefault( "playcolor", "#FF0000" ); + CheckDefault( "bgcolor1", "#FFFFFF" ); + CheckDefault( "bgcolor2", "#FFFFFF" ); + CheckDefault( "selcolor", "#0000FF" ); + CheckDefault( "help", "" ); + + m_curTreeId = uniqueId( attr["id"] ); + const BuilderData::Tree treeData( m_curTreeId, atoi( attr["x"] ) + + m_xOffset, atoi( attr["y"] ) + m_yOffset, attr["visible"], + atoi( attr["width"]), atoi( attr["height"] ), + attr["lefttop"], attr["rightbottom"], + attr["font"], "playtree", + attr["bgimage"], attr["itemimage"], + attr["openimage"], attr["closedimage"], + convertColor( attr["fgcolor"] ), + convertColor( attr["playcolor"] ), + convertColor( attr["bgcolor1"] ), + convertColor( attr["bgcolor2"] ), + convertColor( attr["selcolor"] ), attr["help"], + m_curLayer, m_curWindowId, m_curLayoutId ); + m_curLayer++; + m_data.m_listTree.push_back( treeData ); + } + else if( rName == "RadialSlider" ) { - const BuilderData::RadialSlider radial( uniqueId( attr["id"] ), attr["visible"], + RequireDefault( "sequence" ); + RequireDefault( "nbimages" ); + CheckDefault( "id", "none" ); + CheckDefault( "visible", "true" ); + CheckDefault( "x", "0" ); + CheckDefault( "y", "0" ); + CheckDefault( "lefttop", "lefttop" ); + CheckDefault( "rightbottom", "lefttop" ); + CheckDefault( "minangle", "0" ); + CheckDefault( "maxangle", "360" ); + CheckDefault( "value", "none" ); + CheckDefault( "tooltiptext", "" ); + CheckDefault( "help", "" ); + + const BuilderData::RadialSlider radial( uniqueId( attr["id"] ), + attr["visible"], atoi( attr["x"] ) + m_xOffset, atoi( attr["y"] ) + m_yOffset, attr["lefttop"], attr["rightbottom"], attr["sequence"], - atoi( attr["nbImages"] ), atof( attr["minAngle"] ) * M_PI / 180, + atoi( attr["nbImages"] ), atof( attr["minAngle"] ) * M_PI /180, atof( attr["maxAngle"] ) * M_PI / 180, attr["value"], attr["tooltiptext"], attr["help"], m_curLayer, m_curWindowId, m_curLayoutId ); @@ -143,17 +325,43 @@ void SkinParser::handleBeginElement( const string &rName, AttrList_t &attr ) else if( rName == "Slider" ) { + RequireDefault( "up" ); + RequireDefault( "points" ); + CheckDefault( "id", "none" ); + CheckDefault( "visible", "true" ); + CheckDefault( "x", "0" ); + CheckDefault( "y", "0" ); + CheckDefault( "width", "0" ); + CheckDefault( "height", "0" ); + CheckDefault( "lefttop", "lefttop" ); + CheckDefault( "rightbottom", "lefttop" ); + CheckDefault( "down", "none" ); + CheckDefault( "over", "none" ); + CheckDefault( "thickness", "10" ); + CheckDefault( "value", "none" ); + CheckDefault( "background", "none" ); + CheckDefault( "nbimages", "1" ); + CheckDefault( "tooltiptext", "" ); + CheckDefault( "help", "" ); + string newValue = attr["value"]; if( m_curListId != "" ) { // Slider associated to a list newValue = "playlist.slider"; } - const BuilderData::Slider slider( uniqueId( attr["id"] ), attr["visible"], + else if( m_curTreeId != "" ) + { + // Slider associated to a tree + newValue = "playtree.slider"; + } + const BuilderData::Slider slider( uniqueId( attr["id"] ), + attr["visible"], atoi( attr["x"] ) + m_xOffset, atoi( attr["y"] ) + m_yOffset, attr["lefttop"], attr["rightbottom"], attr["up"], attr["down"], attr["over"], attr["points"], atoi( attr["thickness"] ), - newValue, attr["tooltiptext"], attr["help"], m_curLayer, + newValue, attr["background"], atoi( attr["nbimages"] ), + attr["tooltiptext"], attr["help"], m_curLayer, m_curWindowId, m_curLayoutId ); m_curLayer++; m_data.m_listSlider.push_back( slider ); @@ -161,10 +369,24 @@ void SkinParser::handleBeginElement( const string &rName, AttrList_t &attr ) else if( rName == "Text" ) { - const BuilderData::Text textData( uniqueId( attr["id"] ), atoi( attr["x"] ) + - m_xOffset, atoi( attr["y"] ) + m_yOffset, attr["font"], + RequireDefault( "font" ); + CheckDefault( "id", "none" ); + CheckDefault( "visible", "true" ); + CheckDefault( "x", "0" ); + CheckDefault( "y", "0" ); + CheckDefault( "text", "" ); + CheckDefault( "color", "#000000" ); + CheckDefault( "width", "0" ); + CheckDefault( "lefttop", "lefttop" ); + CheckDefault( "rightbottom", "lefttop" ); + CheckDefault( "help", "" ); + + const BuilderData::Text textData( uniqueId( attr["id"] ), + atoi( attr["x"] ) + m_xOffset, atoi( attr["y"] ) + m_yOffset, + attr["visible"], attr["font"], attr["text"], atoi( attr["width"] ), - ConvertColor( attr["color"] ), attr["help"], m_curLayer, + attr["lefttop"], attr["rightbottom"], + convertColor( attr["color"] ), attr["help"], m_curLayer, m_curWindowId, m_curLayoutId ); m_curLayer++; m_data.m_listText.push_back( textData ); @@ -172,6 +394,12 @@ void SkinParser::handleBeginElement( const string &rName, AttrList_t &attr ) else if( rName == "Theme" ) { + RequireDefault( "version" ); + CheckDefault( "tooltipfont", "defaultfont" ); + CheckDefault( "magnet", "15" ); + CheckDefault( "alpha", "255" ); + CheckDefault( "movealpha", "255" ); + // Check the version if( strcmp( attr["version"], SKINS_DTD_VERSION ) ) { @@ -180,26 +408,57 @@ void SkinParser::handleBeginElement( const string &rName, AttrList_t &attr ) m_errors = true; return; } - const BuilderData::Theme theme( atoi( attr["magnet"] ), - atoi( attr["alpha"] ), atoi( attr["movealpha"] ), - atoi( attr["fadetime"] ) ); + const BuilderData::Theme theme( attr["tooltipfont"], + atoi( attr["magnet"] ), + convertInRange( attr["alpha"], 1, 255, "alpha" ), + convertInRange( attr["movealpha"], 1, 255, "movealpha" ) ); m_data.m_listTheme.push_back( theme ); } else if( rName == "ThemeInfo" ) { - msg_Warn( getIntf(), "skin: %s author: %s", attr["name"], + msg_Info( getIntf(), "skin: %s author: %s", attr["name"], attr["author"] ); } + else if( rName == "Video" ) + { + CheckDefault( "id", "none" ); + CheckDefault( "visible", "true" ); + CheckDefault( "x", "0" ); + CheckDefault( "y", "0" ); + CheckDefault( "width", "0" ); + CheckDefault( "height", "0" ); + CheckDefault( "lefttop", "lefttop" ); + CheckDefault( "rightbottom", "lefttop" ); + CheckDefault( "autoresize", "false" ); + CheckDefault( "help", "" ); + + const BuilderData::Video videoData( uniqueId( attr["id"] ), + atoi( attr["x"] ) + m_xOffset, atoi( attr["y"] ) + m_yOffset, + atoi( attr["width"] ), atoi( attr["height" ]), + attr["lefttop"], attr["rightbottom"], + attr["visible"], convertBoolean( attr["autoresize"] ), + attr["help"], m_curLayer, m_curWindowId, m_curLayoutId ); + m_curLayer++; + m_data.m_listVideo.push_back( videoData ); + } + else if( rName == "Window" ) { + CheckDefault( "id", "none" ); + CheckDefault( "visible", "true" ); + CheckDefault( "x", "0" ); + CheckDefault( "y", "0" ); + CheckDefault( "dragdrop", "true" ); + CheckDefault( "playondrop", "true" ); + m_curWindowId = uniqueId( attr["id"] ); const BuilderData::Window window( m_curWindowId, atoi( attr["x"] ) + m_xOffset, atoi( attr["y"] ) + m_yOffset, - ConvertBoolean( attr["visible"] ), - ConvertBoolean( attr["dragdrop"] ), - ConvertBoolean( attr["playondrop"] ) ); + convertBoolean( attr["visible"] ), + convertBoolean( attr["dragdrop"] ), + convertBoolean( attr["playondrop"] ) ); m_data.m_listWindow.push_back( window ); } } @@ -214,21 +473,24 @@ void SkinParser::handleEndElement( const string &rName ) m_xOffsetList.pop_back(); m_yOffsetList.pop_back(); } - else if( rName == "Playlist" ) { m_curListId = ""; } + else if( rName == "Playtree" ) + { + m_curTreeId = ""; + } } -bool SkinParser::ConvertBoolean( const char *value ) const +bool SkinParser::convertBoolean( const char *value ) const { return strcmp( value, "true" ) == 0; } -int SkinParser::ConvertColor( const char *transcolor ) const +int SkinParser::convertColor( const char *transcolor ) const { unsigned long iRed, iGreen, iBlue; iRed = iGreen = iBlue = 0; @@ -236,6 +498,40 @@ int SkinParser::ConvertColor( const char *transcolor ) const return ( iRed << 16 | iGreen << 8 | iBlue ); } + +string SkinParser::convertFileName( const char *fileName ) const +{ + OSFactory *pFactory = OSFactory::instance( getIntf() ); + return m_path + pFactory->getDirSeparator() + string( fileName ); +} + + +int SkinParser::convertInRange( const char *value, int minValue, int maxValue, + const string &rAttribute ) const +{ + int intValue = atoi( value ); + + if( intValue < minValue ) + { + msg_Warn( getIntf(), "Value of \"%s\" attribute (%i) is out of the " + "expected range [%i, %i], using %i instead", + rAttribute.c_str(), intValue, minValue, maxValue, minValue ); + return minValue; + } + else if( intValue > maxValue ) + { + msg_Warn( getIntf(), "Value of \"%s\" attribute (%i) is out of the " + "expected range [%i, %i], using %i instead", + rAttribute.c_str(), intValue, minValue, maxValue, maxValue ); + return maxValue; + } + else + { + return intValue; + } +} + + const string SkinParser::generateId() const { static int i = 1; @@ -273,4 +569,3 @@ const string SkinParser::uniqueId( const string &id ) return newId; } -