]> git.sesse.net Git - vlc/blob - modules/gui/skins2/parser/interpreter.cpp
2b0d208a5bc7ae17e1180f6fc70e5201217f65e2
[vlc] / modules / gui / skins2 / parser / interpreter.cpp
1 /*****************************************************************************
2  * interpreter.cpp
3  *****************************************************************************
4  * Copyright (C) 2003 VideoLAN
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., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
23  *****************************************************************************/
24
25 #include "interpreter.hpp"
26 #include "expr_evaluator.hpp"
27 #include "../commands/cmd_playlist.hpp"
28 #include "../commands/cmd_dialogs.hpp"
29 #include "../commands/cmd_dummy.hpp"
30 #include "../commands/cmd_layout.hpp"
31 #include "../commands/cmd_quit.hpp"
32 #include "../commands/cmd_minimize.hpp"
33 #include "../commands/cmd_input.hpp"
34 #include "../commands/cmd_fullscreen.hpp"
35 #include "../commands/cmd_on_top.hpp"
36 #include "../commands/cmd_show_window.hpp"
37 #include "../src/theme.hpp"
38 #include "../src/var_manager.hpp"
39 #include "../src/vlcproc.hpp"
40
41
42 Interpreter::Interpreter( intf_thread_t *pIntf ): SkinObject( pIntf )
43 {
44     /// Create the generic commands
45 #define REGISTER_CMD( name, cmd ) \
46     m_commandMap[name] = CmdGenericPtr( new cmd( getIntf() ) );
47
48     REGISTER_CMD( "none", CmdDummy )
49     REGISTER_CMD( "dialogs.changeSkin()", CmdDlgChangeSkin )
50     REGISTER_CMD( "dialogs.fileSimple()", CmdDlgFileSimple )
51     REGISTER_CMD( "dialogs.file()", CmdDlgFile )
52     REGISTER_CMD( "dialogs.disc()", CmdDlgDisc )
53     REGISTER_CMD( "dialogs.net()", CmdDlgNet )
54     REGISTER_CMD( "dialogs.messages()", CmdDlgMessages )
55     REGISTER_CMD( "dialogs.prefs()", CmdDlgPrefs )
56     REGISTER_CMD( "dialogs.fileInfo()", CmdDlgFileInfo )
57     REGISTER_CMD( "dialogs.popup()", CmdDlgShowPopupMenu )
58     REGISTER_CMD( "playlist.load()", CmdDlgPlaylistLoad )
59     REGISTER_CMD( "playlist.save()", CmdDlgPlaylistSave )
60     REGISTER_CMD( "playlist.add()", CmdDlgAdd )
61     VarList &rVar = VlcProc::instance( getIntf() )->getPlaylistVar();
62     m_commandMap["playlist.del()"] =
63         CmdGenericPtr( new CmdPlaylistDel( getIntf(), rVar ) );
64     REGISTER_CMD( "playlist.next()", CmdPlaylistNext )
65     REGISTER_CMD( "playlist.previous()", CmdPlaylistPrevious )
66     REGISTER_CMD( "playlist.sort()", CmdPlaylistSort )
67     m_commandMap["playlist.setRandom(true)"] =
68         CmdGenericPtr( new CmdPlaylistRandom( getIntf(), true ) );
69     m_commandMap["playlist.setRandom(false)"] =
70         CmdGenericPtr( new CmdPlaylistRandom( getIntf(), false ) );
71     m_commandMap["playlist.setLoop(true)"] =
72         CmdGenericPtr( new CmdPlaylistLoop( getIntf(), true ) );
73     m_commandMap["playlist.setLoop(false)"] =
74         CmdGenericPtr( new CmdPlaylistLoop( getIntf(), false ) );
75     m_commandMap["playlist.setRepeat(true)"] =
76         CmdGenericPtr( new CmdPlaylistRepeat( getIntf(), true ) );
77     m_commandMap["playlist.setRepeat(false)"] =
78         CmdGenericPtr( new CmdPlaylistRepeat( getIntf(), false ) );
79     REGISTER_CMD( "vlc.fullscreen()", CmdFullscreen )
80     REGISTER_CMD( "vlc.play()", CmdPlay )
81     REGISTER_CMD( "vlc.pause()", CmdPause )
82     REGISTER_CMD( "vlc.stop()", CmdStop )
83     REGISTER_CMD( "vlc.faster()", CmdFaster )
84     REGISTER_CMD( "vlc.slower()", CmdSlower )
85     REGISTER_CMD( "vlc.mute()", CmdMute )
86     REGISTER_CMD( "vlc.minimize()", CmdMinimize )
87     REGISTER_CMD( "vlc.onTop()", CmdOnTop )
88     REGISTER_CMD( "vlc.quit()", CmdQuit )
89
90     // Register the constant bool variables in the var manager
91     VarManager *pVarManager = VarManager::instance( getIntf() );
92     VarBool *pVarTrue = new VarBoolTrue( getIntf() );
93     pVarManager->registerVar( VariablePtr( pVarTrue ), "true" );
94     VarBool *pVarFalse = new VarBoolFalse( getIntf() );
95     pVarManager->registerVar( VariablePtr( pVarFalse ), "false" );
96 }
97
98
99 Interpreter *Interpreter::instance( intf_thread_t *pIntf )
100 {
101     if( ! pIntf->p_sys->p_interpreter )
102     {
103         Interpreter *pInterpreter;
104         pInterpreter = new Interpreter( pIntf );
105         if( pInterpreter )
106         {
107             pIntf->p_sys->p_interpreter = pInterpreter;
108         }
109     }
110     return pIntf->p_sys->p_interpreter;
111 }
112
113
114 void Interpreter::destroy( intf_thread_t *pIntf )
115 {
116     if( pIntf->p_sys->p_interpreter )
117     {
118         delete pIntf->p_sys->p_interpreter;
119         pIntf->p_sys->p_interpreter = NULL;
120     }
121 }
122
123
124 CmdGeneric *Interpreter::parseAction( const string &rAction, Theme *pTheme )
125 {
126     // Try to find the command in the global command map
127     if( m_commandMap.find( rAction ) != m_commandMap.end() )
128     {
129         return m_commandMap[rAction].get();
130     }
131
132     CmdGeneric *pCommand = NULL;
133
134     if( rAction.find( ".setLayout(" ) != string::npos )
135     {
136         int leftPos = rAction.find( ".setLayout(" );
137         string windowId = rAction.substr( 0, leftPos );
138         // 11 is the size of ".setLayout("
139         int rightPos = rAction.find( ")", windowId.size() + 11 );
140         string layoutId = rAction.substr( windowId.size() + 11,
141                                           rightPos - (windowId.size() + 11) );
142         pCommand = new CmdLayout( getIntf(), windowId, layoutId );
143     }
144     else if( rAction.find( ".show()" ) != string::npos )
145     {
146         int leftPos = rAction.find( ".show()" );
147         string windowId = rAction.substr( 0, leftPos );
148         TopWindow *pWin = pTheme->getWindowById( windowId );
149         if( pWin )
150         {
151             pCommand = new CmdShowWindow( getIntf(), pTheme->getWindowManager(),
152                                           *pWin );
153         }
154         else
155         {
156             msg_Err( getIntf(), "Unknown window (%s)", windowId.c_str() );
157         }
158     }
159     else if( rAction.find( ".hide()" ) != string::npos )
160     {
161         int leftPos = rAction.find( ".hide()" );
162         string windowId = rAction.substr( 0, leftPos );
163         TopWindow *pWin = pTheme->getWindowById( windowId );
164         if( pWin )
165         {
166             pCommand = new CmdHideWindow( getIntf(), pTheme->getWindowManager(),
167                                           *pWin );
168         }
169         else
170         {
171             msg_Err( getIntf(), "Unknown window (%s)", windowId.c_str() );
172         }
173     }
174
175     if( pCommand )
176     {
177         // Add the command in the pool
178         pTheme->m_commands.push_back( CmdGenericPtr( pCommand ) );
179     }
180
181     return pCommand;
182 }
183
184
185 VarBool *Interpreter::getVarBool( const string &rName, Theme *pTheme )
186 {
187     VarManager *pVarManager = VarManager::instance( getIntf() );
188
189     // Convert the expression into Reverse Polish Notation
190     ExprEvaluator evaluator( getIntf() );
191     evaluator.parse( rName );
192
193     list<VarBool*> varStack;
194
195     // Get the first token from the RPN stack
196     string token = evaluator.getToken();
197     while( !token.empty() )
198     {
199         if( token == "and" )
200         {
201             // Get the 2 last variables on the stack
202             if( varStack.empty() )
203             {
204                 msg_Err( getIntf(), "Invalid boolean expression: %s",
205                          rName.c_str());
206                 return NULL;
207             }
208             VarBool *pVar1 = varStack.back();
209             varStack.pop_back();
210             if( varStack.empty() )
211             {
212                 msg_Err( getIntf(), "Invalid boolean expression: %s",
213                          rName.c_str());
214                 return NULL;
215             }
216             VarBool *pVar2 = varStack.back();
217             varStack.pop_back();
218
219             // Create a composite boolean variable
220             VarBool *pNewVar = new VarBoolAndBool( getIntf(), *pVar1, *pVar2 );
221             varStack.push_back( pNewVar );
222             // Register this variable in the manager
223             pVarManager->registerVar( VariablePtr( pNewVar ) );
224         }
225         else if( token == "or" )
226         {
227             // Get the 2 last variables on the stack
228             if( varStack.empty() )
229             {
230                 msg_Err( getIntf(), "Invalid boolean expression: %s",
231                          rName.c_str());
232                 return NULL;
233             }
234             VarBool *pVar1 = varStack.back();
235             varStack.pop_back();
236             if( varStack.empty() )
237             {
238                 msg_Err( getIntf(), "Invalid boolean expression: %s",
239                          rName.c_str());
240                 return NULL;
241             }
242             VarBool *pVar2 = varStack.back();
243             varStack.pop_back();
244
245             // Create a composite boolean variable
246             VarBool *pNewVar = new VarBoolOrBool( getIntf(), *pVar1, *pVar2 );
247             varStack.push_back( pNewVar );
248             // Register this variable in the manager
249             pVarManager->registerVar( VariablePtr( pNewVar ) );
250         }
251         else if( token == "not" )
252         {
253             // Get the last variable on the stack
254             if( varStack.empty() )
255             {
256                 msg_Err( getIntf(), "Invalid boolean expression: %s",
257                          rName.c_str());
258                 return NULL;
259             }
260             VarBool *pVar = varStack.back();
261             varStack.pop_back();
262
263             // Create a composite boolean variable
264             VarBool *pNewVar = new VarNotBool( getIntf(), *pVar );
265             varStack.push_back( pNewVar );
266             // Register this variable in the manager
267             pVarManager->registerVar( VariablePtr( pNewVar ) );
268         }
269         else if( token.find( ".isVisible" ) != string::npos )
270         {
271             int leftPos = token.find( ".isVisible" );
272             string windowId = token.substr( 0, leftPos );
273             TopWindow *pWin = pTheme->getWindowById( windowId );
274             if( pWin )
275             {
276                 // Push the visibility variable on the stack
277                 varStack.push_back( &pWin->getVisibleVar() );
278             }
279             else
280             {
281                 msg_Err( getIntf(), "Unknown window (%s)", windowId.c_str() );
282                 return NULL;
283             }
284         }
285         else
286         {
287             // Try to get the variable from the variable manager
288             VarBool *pVar = (VarBool*)pVarManager->getVar( token, "bool" );
289             if( !pVar )
290             {
291                 msg_Err( getIntf(), "Cannot resolve boolean variable: %s",
292                          token.c_str());
293                 return NULL;
294             }
295             varStack.push_back( pVar );
296         }
297         // Get the first token from the RPN stack
298         token = evaluator.getToken();
299     }
300
301     // The stack should contain a single variable
302     if( varStack.size() != 1 )
303     {
304         msg_Err( getIntf(), "Invalid boolean expression: %s", rName.c_str() );
305         return NULL;
306     }
307     return varStack.back();
308 }
309
310
311 VarPercent *Interpreter::getVarPercent( const string &rName, Theme *pTheme )
312 {
313     // Try to get the variable from the variable manager
314     VarManager *pVarManager = VarManager::instance( getIntf() );
315     VarPercent *pVar = (VarPercent*)pVarManager->getVar( rName, "percent" );
316     return pVar;
317 }
318
319
320 VarList *Interpreter::getVarList( const string &rName, Theme *pTheme )
321 {
322     // Try to get the variable from the variable manager
323     VarManager *pVarManager = VarManager::instance( getIntf() );
324     VarList *pVar = (VarList*)pVarManager->getVar( rName, "list" );
325     return pVar;
326 }
327