mirror of
https://github.com/videolan/vlc.git
synced 2024-12-02 22:33:27 +08:00
* winamp2.xml: added the Equalizer and Playlist windows.
Now it starts to really look cool ;-) * builder.cpp: look for fonts in the resource path if the font file cannot be found in the theme itself * ctrl_slider.cpp: fixed the hack for winamp: the bar images are separated by 2 rows, not 3...
This commit is contained in:
parent
0e6a1c1e65
commit
85fad441ea
@ -387,9 +387,9 @@ void CtrlSliderBg::draw( OSGraphics &rImage, int xDest, int yDest )
|
||||
if( m_pImgSeq )
|
||||
{
|
||||
// Draw the background image
|
||||
// XXX the "-3" is a hack for winamp skins...
|
||||
// XXX the "-2" is a hack for winamp skins...
|
||||
rImage.drawGraphics( *m_pImgSeq, 0, m_position * m_bgHeight,
|
||||
xDest, yDest, m_bgWidth, m_bgHeight - 3);
|
||||
xDest, yDest, m_bgWidth, m_bgHeight - 2);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -52,8 +52,9 @@
|
||||
#include "vlc_image.h"
|
||||
|
||||
|
||||
Builder::Builder( intf_thread_t *pIntf, const BuilderData &rData ):
|
||||
SkinObject( pIntf ), m_rData( rData ), m_pTheme( NULL )
|
||||
Builder::Builder( intf_thread_t *pIntf, const BuilderData &rData,
|
||||
const string &rPath ):
|
||||
SkinObject( pIntf ), m_rData( rData ), m_path( rPath ), m_pTheme( NULL )
|
||||
{
|
||||
m_pImageHandler = image_HandlerCreate( pIntf );
|
||||
}
|
||||
@ -145,7 +146,7 @@ void Builder::addBitmap( const BuilderData::Bitmap &rData )
|
||||
{
|
||||
GenericBitmap *pBmp =
|
||||
new FileBitmap( getIntf(), m_pImageHandler,
|
||||
rData.m_fileName, rData.m_alphaColor );
|
||||
getFilePath( rData.m_fileName ), rData.m_alphaColor );
|
||||
if( !pBmp->getData() )
|
||||
{
|
||||
// Invalid bitmap
|
||||
@ -181,7 +182,8 @@ void Builder::addSubBitmap( const BuilderData::SubBitmap &rData )
|
||||
void Builder::addBitmapFont( const BuilderData::BitmapFont &rData )
|
||||
{
|
||||
GenericBitmap *pBmp =
|
||||
new FileBitmap( getIntf(), m_pImageHandler, rData.m_file, 0 );
|
||||
new FileBitmap( getIntf(), m_pImageHandler,
|
||||
getFilePath( rData.m_file ), 0 );
|
||||
if( !pBmp->getData() )
|
||||
{
|
||||
// Invalid bitmap
|
||||
@ -205,7 +207,9 @@ void Builder::addBitmapFont( const BuilderData::BitmapFont &rData )
|
||||
|
||||
void Builder::addFont( const BuilderData::Font &rData )
|
||||
{
|
||||
GenericFont *pFont = new FT2Font( getIntf(), rData.m_fontFile,
|
||||
// Try to load the font from the theme directory
|
||||
GenericFont *pFont = new FT2Font( getIntf(),
|
||||
getFilePath( rData.m_fontFile ),
|
||||
rData.m_size );
|
||||
if( pFont->init() )
|
||||
{
|
||||
@ -214,6 +218,28 @@ void Builder::addFont( const BuilderData::Font &rData )
|
||||
else
|
||||
{
|
||||
delete pFont;
|
||||
|
||||
// Font not found; try in the resource path
|
||||
OSFactory *pOSFactory = OSFactory::instance( getIntf() );
|
||||
const list<string> &resPath = pOSFactory->getResourcePath();
|
||||
const string &sep = pOSFactory->getDirSeparator();
|
||||
|
||||
list<string>::const_iterator it;
|
||||
for( it = resPath.begin(); it != resPath.end(); it++ )
|
||||
{
|
||||
string path = (*it) + sep + "fonts" + sep + rData.m_fontFile;
|
||||
pFont = new FT2Font( getIntf(), path, rData.m_size );
|
||||
if( pFont->init() )
|
||||
{
|
||||
// Font loaded successfully
|
||||
m_pTheme->m_fonts[rData.m_id] = GenericFontPtr( pFont );
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
delete pFont;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -865,6 +891,14 @@ GenericFont *Builder::getFont( const string &fontId )
|
||||
}
|
||||
|
||||
|
||||
string Builder::getFilePath( const string &rFileName ) const
|
||||
{
|
||||
OSFactory *pFactory = OSFactory::instance( getIntf() );
|
||||
return m_path + pFactory->getDirSeparator() + rFileName;
|
||||
}
|
||||
|
||||
|
||||
|
||||
Bezier *Builder::getPoints( const char *pTag ) const
|
||||
{
|
||||
vector<float> xBez, yBez;
|
||||
|
@ -46,7 +46,8 @@ class Theme;
|
||||
class Builder: public SkinObject
|
||||
{
|
||||
public:
|
||||
Builder( intf_thread_t *pIntf, const BuilderData &rData );
|
||||
Builder( intf_thread_t *pIntf, const BuilderData &rData,
|
||||
const string &rPath );
|
||||
virtual ~Builder();
|
||||
|
||||
/// Create a Theme object, ready to use.
|
||||
@ -59,6 +60,8 @@ class Builder: public SkinObject
|
||||
private:
|
||||
/// Data from the XML
|
||||
const BuilderData &m_rData;
|
||||
/// Path of the theme
|
||||
const string m_path;
|
||||
|
||||
/// Theme under construction
|
||||
Theme *m_pTheme;
|
||||
@ -87,6 +90,9 @@ class Builder: public SkinObject
|
||||
int xPos, int yPos, int width, int height,
|
||||
const Box &rBox ) const;
|
||||
|
||||
// Build the full path of a file
|
||||
string getFilePath( const string &fileName ) const;
|
||||
|
||||
/// Get a font from its id
|
||||
GenericFont *getFont( const string &fontId );
|
||||
|
||||
|
@ -27,8 +27,8 @@
|
||||
|
||||
SkinParser::SkinParser( intf_thread_t *pIntf, const string &rFileName,
|
||||
const string &rPath, bool useDTD, BuilderData *pData ):
|
||||
XMLParser( pIntf, rFileName, useDTD ), m_pData(pData),
|
||||
m_ownData(pData == NULL), m_xOffset( 0 ), m_yOffset( 0 ), m_path( rPath )
|
||||
XMLParser( pIntf, rFileName, useDTD ), m_path( rPath), m_pData(pData),
|
||||
m_ownData(pData == NULL), m_xOffset( 0 ), m_yOffset( 0 )
|
||||
{
|
||||
// Make sure the data is allocated
|
||||
if( m_pData == NULL )
|
||||
@ -62,12 +62,13 @@ void SkinParser::handleBeginElement( const string &rName, AttrList_t &attr )
|
||||
if( rName == "Include" )
|
||||
{
|
||||
RequireDefault( "file" );
|
||||
msg_Dbg( getIntf(), "Opening included XML file: %s",
|
||||
convertFileName( attr["file"] ).c_str() );
|
||||
|
||||
OSFactory *pFactory = OSFactory::instance( getIntf() );
|
||||
string fullPath = m_path + pFactory->getDirSeparator() + attr["file"];
|
||||
msg_Dbg( getIntf(), "Opening included XML file: %s", fullPath.c_str() );
|
||||
// FIXME: We do not use the DTD to validate the included XML file,
|
||||
// as the parser seems to dislike it otherwise...
|
||||
SkinParser subParser( getIntf(), convertFileName( attr["file"] ),
|
||||
m_path, false, m_pData );
|
||||
SkinParser subParser( getIntf(), fullPath.c_str(), false, m_pData );
|
||||
subParser.parse();
|
||||
}
|
||||
|
||||
@ -93,8 +94,7 @@ void SkinParser::handleBeginElement( const string &rName, AttrList_t &attr )
|
||||
|
||||
m_curBitmapId = uniqueId( attr["id"] );
|
||||
const BuilderData::Bitmap bitmap( m_curBitmapId,
|
||||
convertFileName( attr["file"] ),
|
||||
convertColor( attr["alphacolor"] ) );
|
||||
attr["file"], convertColor( attr["alphacolor"] ) );
|
||||
m_pData->m_listBitmap.push_back( bitmap );
|
||||
}
|
||||
|
||||
@ -119,8 +119,7 @@ void SkinParser::handleBeginElement( const string &rName, AttrList_t &attr )
|
||||
CheckDefault( "type", "digits" );
|
||||
|
||||
const BuilderData::BitmapFont font( attr["id"],
|
||||
convertFileName( attr["file"] ),
|
||||
attr["type"] );
|
||||
attr["file"], attr["type"] );
|
||||
m_pData->m_listBitmapFont.push_back( font );
|
||||
}
|
||||
|
||||
@ -189,8 +188,7 @@ void SkinParser::handleBeginElement( const string &rName, AttrList_t &attr )
|
||||
CheckDefault( "size", "12" );
|
||||
|
||||
const BuilderData::Font fontData( uniqueId( attr["id"] ),
|
||||
convertFileName( attr["file"] ),
|
||||
atoi( attr["size"] ) );
|
||||
attr["file"], atoi( attr["size"] ) );
|
||||
m_pData->m_listFont.push_back( fontData );
|
||||
}
|
||||
|
||||
@ -525,13 +523,6 @@ int SkinParser::convertColor( const char *transcolor ) const
|
||||
}
|
||||
|
||||
|
||||
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
|
||||
{
|
||||
|
@ -41,6 +41,8 @@ class SkinParser: public XMLParser
|
||||
const BuilderData &getData() const { return *m_pData; }
|
||||
|
||||
private:
|
||||
/// Path of the theme
|
||||
const string m_path;
|
||||
/// Container for mapping data from the XML
|
||||
BuilderData *m_pData;
|
||||
/// Indicate whether the class owns the data
|
||||
@ -58,8 +60,6 @@ class SkinParser: public XMLParser
|
||||
int m_curLayer;
|
||||
/// Set of used id
|
||||
set<string> m_idSet;
|
||||
/// Path of the XML file being parsed
|
||||
const string m_path;
|
||||
|
||||
/// Callbacks
|
||||
virtual void handleBeginElement( const string &rName,
|
||||
@ -70,7 +70,6 @@ class SkinParser: public XMLParser
|
||||
//@{
|
||||
bool convertBoolean( const char *value ) const;
|
||||
int convertColor( const char *transcolor ) const;
|
||||
string convertFileName( const char *fileName ) const;
|
||||
/// Transform to int, and check that it is in the given range (if not,
|
||||
/// the closest range boundary will be used)
|
||||
int convertInRange( const char *value, int minValue, int maxValue,
|
||||
|
@ -200,7 +200,7 @@ bool ThemeLoader::extractFileInZip( unzFile file, const string &rootDir )
|
||||
|
||||
// Convert the file name to lower case, because some winamp skins
|
||||
// use the wrong case...
|
||||
for( int i=0; i< strlen( filenameInZip ); i++)
|
||||
for( size_t i=0; i< strlen( filenameInZip ); i++)
|
||||
{
|
||||
filenameInZip[i] = tolower( filenameInZip[i] );
|
||||
}
|
||||
@ -359,7 +359,7 @@ bool ThemeLoader::parse( const string &path, const string &xmlFile )
|
||||
}
|
||||
|
||||
// Build and store the theme
|
||||
Builder builder( getIntf(), parser.getData() );
|
||||
Builder builder( getIntf(), parser.getData(), path );
|
||||
getIntf()->p_sys->p_theme = builder.build();
|
||||
|
||||
return true;
|
||||
|
@ -78,6 +78,7 @@ DIST_skins2 = \
|
||||
skins2/default.vlt \
|
||||
\
|
||||
skins2/fonts/FreeSans.ttf \
|
||||
skins2/fonts/FreeSansBold.ttf \
|
||||
skins2/skin.dtd \
|
||||
skins2/skin.catalog \
|
||||
skins2/winamp2.xml \
|
||||
|
BIN
share/skins2/fonts/FreeSansBold.ttf
Normal file
BIN
share/skins2/fonts/FreeSansBold.ttf
Normal file
Binary file not shown.
@ -18,12 +18,28 @@
|
||||
<SubBitmap id="eject_up" x="114" y="0" width="22" height="16" />
|
||||
<SubBitmap id="eject_down" x="114" y="16" width="22" height="16" />
|
||||
</Bitmap>
|
||||
<Bitmap id="eqmain" file="eqmain.bmp" alphacolor="#FF0000">
|
||||
<SubBitmap id="eq_bg" x="0" y="0" width="275" height="116" />
|
||||
</Bitmap>
|
||||
<Bitmap id="pledit" file="pledit.bmp" alphacolor="#FF0000">
|
||||
<SubBitmap id="pl_upleft_focus" x="0" y="0" width="25" height="20" />
|
||||
<SubBitmap id="pl_title_focus" x="26" y="0" width="100" height="20" />
|
||||
<SubBitmap id="pl_up_focus" x="127" y="0" width="25" height="20" />
|
||||
<SubBitmap id="pl_upright_focus" x="153" y="0" width="25" height="20" />
|
||||
<SubBitmap id="pl_left" x="0" y="42" width="25" height="29" />
|
||||
<SubBitmap id="pl_right" x="26" y="42" width="25" height="29" />
|
||||
<SubBitmap id="pl_slider_up" x="52" y="53" width="8" height="18" />
|
||||
<SubBitmap id="pl_slider_down" x="61" y="53" width="8" height="18" />
|
||||
<SubBitmap id="pl_downleft" x="0" y="72" width="125" height="38" />
|
||||
<SubBitmap id="pl_downright" x="126" y="72" width="150" height="38" />
|
||||
</Bitmap>
|
||||
<Bitmap id="posbar" file="posbar.bmp" alphacolor="#FF0000" >
|
||||
<SubBitmap id="time_bg" x="0" y="0" width="248" height="10" />
|
||||
<SubBitmap id="time_up" x="248" y="0" width="29" height="10" />
|
||||
<SubBitmap id="time_down" x="278" y="0" width="29" height="10" />
|
||||
</Bitmap>
|
||||
<Bitmap id="titlebar" file="titlebar.bmp" alphacolor="#FF0000" >
|
||||
<SubBitmap id="title_focus" x="27" y="0" width="275" height="14" />
|
||||
<SubBitmap id="quit_up" x="18" y="0" width="9" height="9" />
|
||||
<SubBitmap id="quit_down" x="18" y="9" width="9" height="9" />
|
||||
</Bitmap>
|
||||
@ -36,36 +52,92 @@
|
||||
<SubBitmap id="noshuffle_down" x="28" y="15" width="47" height="15" />
|
||||
<SubBitmap id="shuffle_up" x="28" y="30" width="47" height="15" />
|
||||
<SubBitmap id="shuffle_down" x="28" y="45" width="47" height="15" />
|
||||
<SubBitmap id="eqoff_up" x="0" y="61" width="23" height="12" />
|
||||
<SubBitmap id="eqon_up" x="0" y="73" width="23" height="12" />
|
||||
<SubBitmap id="ploff_up" x="23" y="61" width="23" height="12" />
|
||||
<SubBitmap id="plon_up" x="23" y="73" width="23" height="12" />
|
||||
<SubBitmap id="eqoff_down" x="46" y="61" width="23" height="12" />
|
||||
<SubBitmap id="eqon_down" x="46" y="73" width="23" height="12" />
|
||||
<SubBitmap id="ploff_down" x="69" y="61" width="23" height="12" />
|
||||
<SubBitmap id="plon_down" x="69" y="73" width="23" height="12" />
|
||||
</Bitmap>
|
||||
<Bitmap id="volume" file="volume.bmp" alphacolor="#FF0000">
|
||||
<SubBitmap id="volume_bg" x="0" y="0" width="68" height="420" />
|
||||
<SubBitmap id="volume_up" x="15" y="422" width="14" height="11" />
|
||||
<SubBitmap id="volume_down" x="0" y="422" width="14" height="11" />
|
||||
</Bitmap>
|
||||
<Font id="playlist_font" file="FreeSansBold.ttf" size="11"/>
|
||||
<BitmapFont id="digits_font" file="numbers.bmp" type="digits"/>
|
||||
<BitmapFont id="digits_font" file="nums_ex.bmp" type="digits"/>
|
||||
<BitmapFont id="text_font" file="text.bmp" type="text"/>
|
||||
|
||||
<Window id="mainWindow" x="400" y="50">
|
||||
<Layout id="bigLayout" width="275" height="116">
|
||||
<Window id="main_window" x="100" y="100">
|
||||
<Layout id="big_layout" width="275" height="116">
|
||||
<Group x="0" y="0">
|
||||
<Anchor x="0" y="116" priority="100" range="15" />
|
||||
<Anchor x="275" y="116" priority="90" range="15" />
|
||||
<Anchor x="20" y="116" points="(0,0),(235,0)" priority="80" range="15" />
|
||||
<Image x="0" y="0" image="main" action="move" />
|
||||
<Image x="0" y="0" image="title_focus" action="move" />
|
||||
<Text font="digits_font" x="30" y="26" width="75" text="$T"/>
|
||||
<Text font="text_font" x="111" y="27" width="155" text="$N"/>
|
||||
<Slider value="volume" x="107" y="57" up="volume_up" down="volume_down" points="(7,6),(58,6)" background="volume_bg" nbimages="28" tooltiptext="Volume: $V%" />
|
||||
<Image x="16" y="72" image="time_bg"/>
|
||||
<Slider value="time" up="time_up" down="time_down" points="(30,78),(250,78)" thickness="5" tooltiptext="Time: $T"/>
|
||||
<Button x="263" y="3" up="quit_up" down="quit_down" over="quit_up" action="vlc.quit()" tooltiptext="Quit" />
|
||||
<Button x="16" y="88" up="previous_up" down="previous_down" action="playlist.previous()" tooltiptext="Previous" />
|
||||
<Button x="39" y="88" up="play_up" down="play_down" action="vlc.play()" tooltiptext="Play" />
|
||||
<Button x="62" y="88" up="pause_up" down="pause_down" action="vlc.pause()" tooltiptext="Pause" />
|
||||
<Button x="85" y="88" up="stop_up" down="stop_down" action="vlc.stop()" tooltiptext="Stop" />
|
||||
<Button x="108" y="88" up="next_up" down="next_down" action="playlist.next()" tooltiptext="Next" />
|
||||
<Button x="136" y="89" up="eject_up" down="eject_down" action="dialogs.fileSimple()" tooltiptext="Open" />
|
||||
<Checkbox x="164" y="89" up1="noshuffle_up" down1="noshuffle_down" up2="shuffle_up" down2="shuffle_down" state="playlist.isRandom" action1="playlist.setRandom(true)" action2="playlist.setRandom(false)" tooltiptext1="Shuffle" tooltiptext2="Shuffle"/>
|
||||
<Checkbox x="210" y="89" up1="noloop_up" down1="noloop_down" up2="loop_up" down2="loop_down" state="playlist.isLoop" action1="playlist.setLoop(true)" action2="playlist.setLoop(false)" tooltiptext1="Loop" tooltiptext2="Loop"/>
|
||||
<Slider value="time" x="29" y="77" up="time_up" down="time_down" points="(0,0),(220,0)" thickness="5" tooltiptext="Time: $T"/>
|
||||
<Button x="263" y="3" up="quit_up" down="quit_down" over="quit_up" action="vlc.quit()" tooltiptext="Quit" />
|
||||
<Button x="16" y="88" up="previous_up" down="previous_down" action="playlist.previous()" tooltiptext="Previous" />
|
||||
<Button x="39" y="88" up="play_up" down="play_down" action="vlc.play()" tooltiptext="Play" />
|
||||
<Button x="62" y="88" up="pause_up" down="pause_down" action="vlc.pause()" tooltiptext="Pause" />
|
||||
<Button x="85" y="88" up="stop_up" down="stop_down" action="vlc.stop()" tooltiptext="Stop" />
|
||||
<Button x="108" y="88" up="next_up" down="next_down" action="playlist.next()" tooltiptext="Next" />
|
||||
<Button x="136" y="89" up="eject_up" down="eject_down" action="dialogs.fileSimple()" tooltiptext="Open" />
|
||||
<Checkbox x="164" y="89" up1="noshuffle_up" down1="noshuffle_down" up2="shuffle_up" down2="shuffle_down" state="playlist.isRandom" action1="playlist.setRandom(true)" action2="playlist.setRandom(false)" tooltiptext1="Shuffle" tooltiptext2="Shuffle"/>
|
||||
<Checkbox x="210" y="89" up1="noloop_up" down1="noloop_down" up2="loop_up" down2="loop_down" state="playlist.isLoop" action1="playlist.setLoop(true)" action2="playlist.setLoop(false)" tooltiptext1="Loop" tooltiptext2="Loop"/>
|
||||
<Checkbox x="219" y="58" up1="eqoff_up" down1="eqoff_down" up2="eqon_up" down2="eqon_down" state="equalizer_window.isVisible" action1="equalizer_window.show()" action2="equalizer_window.hide()" tooltiptext1="Show equalizer" tooltiptext2="Hide equalizer"/>
|
||||
<Checkbox x="242" y="58" up1="ploff_up" down1="ploff_down" up2="plon_up" down2="plon_down" state="playlist_window.isVisible" action1="playlist_window.show()" action2="playlist_window.hide()" tooltiptext1="Show playlist" tooltiptext2="Hide playlist"/>
|
||||
</Group>
|
||||
</Layout>
|
||||
</Window>
|
||||
|
||||
<Window id="equalizer_window" x="100" y="216">
|
||||
<Layout width="275" height="116">
|
||||
<Group x="0" y="0">
|
||||
<Anchor x="0" y="0" priority="70" range="15" />
|
||||
<Anchor x="275" y="0" priority="60" range="15" />
|
||||
<Anchor x="0" y="116" priority="50" range="15" />
|
||||
<Anchor x="275" y="116" priority="40" range="15" />
|
||||
<Anchor x="20" y="116" points="(0,0),(235,0)" priority="30" range="15" />
|
||||
<Image x="0" y="0" image="eq_bg" action="move" />
|
||||
</Group>
|
||||
</Layout>
|
||||
</Window>
|
||||
|
||||
<Window id="playlist_window" x="100" y="332">
|
||||
<Layout width="275" height="116">
|
||||
<Group x="0" y="0">
|
||||
<Anchor x="0" y="0" priority="20" range="15" />
|
||||
<Anchor x="275" y="0" priority="10" range="15" />
|
||||
<Image x="0" y="0" image="pl_upleft_focus" action="move" />
|
||||
<Image x="25" y="0" image="pl_up_focus" action="move" />
|
||||
<Image x="50" y="0" image="pl_up_focus" action="move" />
|
||||
<Image x="75" y="0" image="pl_up_focus" action="move" />
|
||||
<Image x="87" y="0" image="pl_title_focus" action="move" />
|
||||
<Image x="187" y="0" image="pl_up_focus" action="move" />
|
||||
<Image x="200" y="0" image="pl_up_focus" action="move" />
|
||||
<Image x="225" y="0" image="pl_up_focus" action="move" />
|
||||
<Image x="250" y="0" image="pl_upright_focus" action="move" />
|
||||
<Image x="0" y="20" image="pl_left" action="move" />
|
||||
<Image x="250" y="20" image="pl_right" action="move" />
|
||||
<Image x="0" y="49" image="pl_left" action="move" />
|
||||
<Image x="250" y="49" image="pl_right" action="move" />
|
||||
<Image x="0" y="78" image="pl_downleft" action="move" />
|
||||
<Image x="125" y="78" image="pl_downright" action="move" />
|
||||
<Playlist id="playlist" x="10" y="20" width="240" height="58" lefttop="lefttop" rightbottom="rightbottom" font="playlist_font" fgcolor="#dfdfff" playcolor="#ffffff" bgcolor1="#000000" bgcolor2="#000000" selcolor="#202020" >
|
||||
<Slider id="playlist_slider" x="264" y="28" lefttop="righttop" rightbottom="rightbottom" up="pl_slider_up" down="pl_slider_down" points="(0,40),(0,0)"/>
|
||||
</Playlist>
|
||||
</Group>
|
||||
</Layout>
|
||||
</Window>
|
||||
|
||||
|
||||
</Theme>
|
||||
|
Loading…
Reference in New Issue
Block a user