]> git.sesse.net Git - vlc/blob - modules/gui/skins2/src/theme.cpp
* skins2:
[vlc] / modules / gui / skins2 / src / theme.cpp
1 /*****************************************************************************
2  * theme.cpp
3  *****************************************************************************
4  * Copyright (C) 2003 the VideoLAN team
5  * $Id$
6  *
7  * Authors: Cyril Deguet     <asmax@via.ecp.fr>
8  *          Olivier Teulière <ipkiss@via.ecp.fr>
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
23  *****************************************************************************/
24
25 #include "theme.hpp"
26 #include "top_window.hpp"
27 #include <sstream>
28
29
30 Theme::~Theme()
31 {
32     // Be sure things are destroyed in the right order (XXX check)
33     m_layouts.clear();
34     m_controls.clear();
35     m_windows.clear();
36     m_bitmaps.clear();
37     m_fonts.clear();
38     m_commands.clear();
39     m_vars.clear();
40     m_curves.clear();
41 }
42
43
44 void Theme::loadConfig()
45 {
46     msg_Dbg( getIntf(), "loading theme configuration");
47
48     // Get config from vlcrc file
49     char *save = config_GetPsz( getIntf(), "skins2-config" );
50     if( !save ) return;
51
52     // Is there an existing config?
53     if( !strcmp( save, "" ) )
54     {
55         // Show the windows as indicated by the XML file
56         m_windowManager.showAll( true );
57         return;
58     }
59
60     istringstream inStream(save);
61     free( save );
62
63     char sep;
64     string winId, layId;
65     int x, y, width, height, visible;
66     bool somethingVisible = false;
67     while( !inStream.eof() )
68     {
69         inStream >> sep;
70         if( sep != '[' ) goto invalid;
71         inStream >> winId >> layId >> x >> y >> width >> height >> visible >> sep >> ws;
72         if( sep != ']' ) goto invalid;
73
74         // Try to find the window and the layout
75         map<string, TopWindowPtr>::const_iterator itWin;
76         map<string, GenericLayoutPtr>::const_iterator itLay;
77         itWin = m_windows.find( winId );
78         itLay = m_layouts.find( layId );
79         if( itWin == m_windows.end() || itLay == m_layouts.end() )
80         {
81             goto invalid;
82         }
83         TopWindow *pWin = itWin->second.get();
84         GenericLayout *pLayout = itLay->second.get();
85
86         // Restore the layout
87         m_windowManager.setActiveLayout( *pWin, *pLayout );
88         if( pLayout->getWidth() != width ||
89             pLayout->getHeight() != height )
90         {
91             // XXX FIXME XXX: big kludge
92             // As resizing a hidden window causes some trouble (at least on
93             // Windows), first show the window off screen, resize it, and
94             // hide it again.
95             // This has to be investigated more deeply!
96             m_windowManager.startMove( *pWin );
97             m_windowManager.move( *pWin, -width - pLayout->getWidth(), 0);
98             m_windowManager.stopMove();
99             m_windowManager.show( *pWin );
100             m_windowManager.startResize( *pLayout, WindowManager::kResizeSE );
101             m_windowManager.resize( *pLayout, width, height );
102             m_windowManager.stopResize();
103             m_windowManager.hide( *pWin );
104         }
105         // Move the window (which incidentally takes care of the anchoring)
106         m_windowManager.startMove( *pWin );
107         m_windowManager.move( *pWin, x, y );
108         m_windowManager.stopMove();
109         if( visible )
110         {
111             somethingVisible = true;
112             m_windowManager.show( *pWin );
113         }
114     }
115
116     if( !somethingVisible )
117     {
118         goto invalid;
119     }
120     return;
121
122 invalid:
123     msg_Warn( getIntf(), "invalid config: %s", inStream.str().c_str() );
124     // Restore the visibility defined in the theme
125     m_windowManager.showAll( true );
126 }
127
128
129 void Theme::saveConfig()
130 {
131     msg_Dbg( getIntf(), "saving theme configuration");
132
133     map<string, TopWindowPtr>::const_iterator itWin;
134     map<string, GenericLayoutPtr>::const_iterator itLay;
135     ostringstream outStream;
136     for( itWin = m_windows.begin(); itWin != m_windows.end(); itWin++ )
137     {
138         TopWindow *pWin = itWin->second.get();
139
140         // Find the layout id for this window
141         string layoutId;
142         const GenericLayout *pLayout = &pWin->getActiveLayout();
143         for( itLay = m_layouts.begin(); itLay != m_layouts.end(); itLay++ )
144         {
145             if( itLay->second.get() == pLayout )
146             {
147                 layoutId = itLay->first;
148             }
149         }
150
151         outStream << '[' << itWin->first << ' ' << layoutId << ' '
152             << pWin->getLeft() << ' ' << pWin->getTop() << ' '
153             << pLayout->getWidth() << ' ' << pLayout->getHeight() << ' '
154             << (pWin->getVisibleVar().get() ? 1 : 0) << ']';
155     }
156
157     // Save config to file
158     config_PutPsz( getIntf(), "skins2-config", outStream.str().c_str() );
159 }
160
161
162 // Useful macro
163 #define FIND_OBJECT( mapData, mapName ) \
164     map<string, mapData>::const_iterator it; \
165     it = mapName.find( id ); \
166     if( it == mapName.end() ) \
167     { \
168         return NULL; \
169     } \
170     return (*it).second.get();
171
172 // This macro takes an ID of the form "id1;id2;id3", and returns the object
173 // corresponding to the first valid ID. If no ID is valid, it returns NULL.
174 // XXX: should we use a template method instead?
175 #define FIND_FIRST_OBJECT( mapDataPtr, mapName ) \
176     string rightPart = id; \
177     string::size_type pos; \
178     do \
179     { \
180         pos = rightPart.find( ";" ); \
181         string leftPart = rightPart.substr( 0, pos ); \
182         map<string, mapDataPtr>::const_iterator it = mapName.find( leftPart ); \
183         if( it != mapName.end() ) \
184         { \
185             return (*it).second.get(); \
186             break; \
187         } \
188  \
189         if( pos != string::npos ) \
190         { \
191             rightPart = rightPart.substr( pos, rightPart.size() ); \
192             rightPart = \
193                 rightPart.substr( rightPart.find_first_not_of( " \t;" ), \
194                                   rightPart.size() ); \
195         } \
196     } \
197     while( pos != string::npos ); \
198     return NULL;
199
200 GenericBitmap *Theme::getBitmapById( const string &id ) const
201 {
202     FIND_FIRST_OBJECT( GenericBitmapPtr, m_bitmaps );
203 }
204
205 GenericFont *Theme::getFontById( const string &id ) const
206 {
207     FIND_FIRST_OBJECT( GenericFontPtr, m_fonts );
208 }
209
210 Popup *Theme::getPopupById( const string &id ) const
211 {
212     FIND_OBJECT( PopupPtr, m_popups );
213 }
214
215 TopWindow *Theme::getWindowById( const string &id ) const
216 {
217     FIND_OBJECT( TopWindowPtr, m_windows );
218 }
219
220 GenericLayout *Theme::getLayoutById( const string &id ) const
221 {
222     FIND_OBJECT( GenericLayoutPtr, m_layouts );
223 }
224
225 CtrlGeneric *Theme::getControlById( const string &id ) const
226 {
227     FIND_OBJECT( CtrlGenericPtr, m_controls );
228 }
229
230 Position *Theme::getPositionById( const string &id ) const
231 {
232     FIND_OBJECT( PositionPtr, m_positions );
233 }
234
235