]> git.sesse.net Git - vlc/blob - modules/gui/skins2/src/theme.cpp
skins2: rework theme loader
[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 along
21  * with this program; if not, write to the Free Software Foundation, Inc.,
22  * 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     if( readConfig() == VLC_SUCCESS )
49     {
50         applyConfig();
51     }
52     else
53     {
54         getWindowManager().showAll( true );
55     }
56 }
57
58
59 void Theme::applyConfig()
60 {
61     msg_Dbg( getIntf(), "Apply saved configuration");
62
63     list<save_t>::const_iterator it;
64     for( it = m_saved.begin(); it!= m_saved.end(); ++it )
65     {
66         TopWindow *pWin = (*it).win;
67         GenericLayout *pLayout = (*it).layout;
68         int x = (*it).x;
69         int y = (*it).y;
70         int width = (*it).width;
71         int height = (*it).height;
72
73         // Restore the layout
74         m_windowManager.setActiveLayout( *pWin, *pLayout );
75         if( pLayout->getWidth() != width ||
76             pLayout->getHeight() != height )
77         {
78             m_windowManager.startResize( *pLayout, WindowManager::kResizeSE );
79             m_windowManager.resize( *pLayout, width, height );
80             m_windowManager.stopResize();
81         }
82         // Move the window (which incidentally takes care of the anchoring)
83         m_windowManager.startMove( *pWin );
84         m_windowManager.move( *pWin, x, y );
85         m_windowManager.stopMove();
86     }
87
88     for( it = m_saved.begin(); it != m_saved.end(); ++it )
89     {
90        if( (*it).visible )
91             m_windowManager.show( *((*it).win) );
92     }
93 }
94
95
96 int Theme::readConfig()
97 {
98     msg_Dbg( getIntf(), "reading theme configuration");
99
100     // Get config from vlcrc file
101     char *save = config_GetPsz( getIntf(), "skins2-config" );
102     if( !save || !*save )
103     {
104         free( save );
105         return VLC_EGENERIC;
106     }
107
108     istringstream inStream( save );
109     free( save );
110
111     char sep;
112     string winId, layId;
113     int x, y, width, height, visible;
114     bool somethingVisible = false;
115     while( !inStream.eof() )
116     {
117         stringbuf buf, buf2;
118
119         inStream >> sep;
120         if( sep != '[' )
121             goto invalid;
122
123         inStream >> sep;
124         if( sep != '"' )
125             goto invalid;
126         inStream.get( buf, '"' );
127         winId = buf.str();
128         inStream >> sep;
129
130         inStream >> sep;
131         if( sep != '"' )
132             goto invalid;
133         inStream.get( buf2, '"' );
134         layId = buf2.str();
135         inStream >> sep;
136
137         inStream >> x >> y >> width >> height >> visible >> sep >> ws;
138         if( sep != ']' )
139             goto invalid;
140
141         // Try to find the window and the layout
142         map<string, TopWindowPtr>::const_iterator itWin;
143         map<string, GenericLayoutPtr>::const_iterator itLay;
144         itWin = m_windows.find( winId );
145         itLay = m_layouts.find( layId );
146         if( itWin == m_windows.end() || itLay == m_layouts.end() )
147             goto invalid;
148
149         save_t save;
150         save.win = itWin->second.get();
151         save.layout = itLay->second.get();
152         save.x = x;
153         save.y = y;
154         save.width = width;
155         save.height = height;
156         save.visible = visible;
157
158         m_saved.push_back( save );
159
160         if( visible )
161             somethingVisible = true;
162     }
163
164     if( !somethingVisible )
165         goto invalid;
166
167     return VLC_SUCCESS;
168
169 invalid:
170     msg_Dbg( getIntf(), "invalid config: %s", inStream.str().c_str() );
171     m_saved.clear();
172     return VLC_EGENERIC;
173 }
174
175
176 void Theme::saveConfig()
177 {
178     msg_Dbg( getIntf(), "saving theme configuration");
179
180     map<string, TopWindowPtr>::const_iterator itWin;
181     map<string, GenericLayoutPtr>::const_iterator itLay;
182     ostringstream outStream;
183     for( itWin = m_windows.begin(); itWin != m_windows.end(); itWin++ )
184     {
185         TopWindow *pWin = itWin->second.get();
186
187         // Find the layout id for this window
188         string layoutId;
189         const GenericLayout *pLayout = &pWin->getActiveLayout();
190         for( itLay = m_layouts.begin(); itLay != m_layouts.end(); itLay++ )
191         {
192             if( itLay->second.get() == pLayout )
193             {
194                 layoutId = itLay->first;
195             }
196         }
197
198         outStream << '['
199             << '"' << itWin->first << '"' << ' '
200             << '"' << layoutId << '"' << ' '
201             << pWin->getLeft() << ' ' << pWin->getTop() << ' '
202             << pLayout->getWidth() << ' ' << pLayout->getHeight() << ' '
203             << (pWin->getVisibleVar().get() ? 1 : 0) << ']';
204     }
205
206     // Save config to file
207     config_PutPsz( getIntf(), "skins2-config", outStream.str().c_str() );
208 }
209
210
211 // Takes an ID of the form "id1;id2;id3", and returns the object
212 // corresponding to the first valid ID. If no ID is valid, it returns NULL.
213 // XXX The string handling here probably could be improved.
214 template<class T> typename T::pointer
215 Theme::IDmap<T>::find_first_object( const string &id ) const
216 {
217     string rightPart = id;
218     string::size_type pos;
219     do
220     {
221         pos = rightPart.find( ";" );
222         string leftPart = rightPart.substr( 0, pos );
223
224         typename T::pointer p = find_object( leftPart );
225         if( p ) return p;
226
227         if( pos != string::npos )
228         {
229             rightPart = rightPart.substr( pos, rightPart.size() );
230             rightPart =
231                 rightPart.substr( rightPart.find_first_not_of( " \t;" ),
232                                   rightPart.size() );
233         }
234     }
235     while( pos != string::npos );
236     return NULL;
237 }
238
239 GenericBitmap *Theme::getBitmapById( const string &id ) const
240 {
241     return m_bitmaps.find_first_object( id );
242 }
243
244 GenericFont *Theme::getFontById( const string &id ) const
245 {
246     return m_fonts.find_first_object( id );
247 }
248