]> git.sesse.net Git - vlc/blob - modules/gui/skins/src/theme.cpp
* X11 skins now use imlib2 -> you need to bootstrap
[vlc] / modules / gui / skins / src / theme.cpp
1 /*****************************************************************************
2  * theme.cpp: Theme class
3  *****************************************************************************
4  * Copyright (C) 2003 VideoLAN
5  * $Id: theme.cpp,v 1.13 2003/04/29 20:36:56 ipkiss Exp $
6  *
7  * Authors: Olivier Teulière <ipkiss@via.ecp.fr>
8  *          Emmanuel Puig    <karibu@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,
23  * USA.
24  *****************************************************************************/
25
26
27 //--- VLC -------------------------------------------------------------------
28 #include <vlc/intf.h>
29
30 //--- SKIN ------------------------------------------------------------------
31 #include "../os_api.h"
32 #include "window.h"
33 #include "../os_window.h"
34 #include "banks.h"
35 #include "anchor.h"
36 #include "event.h"
37 #include "../os_event.h"
38 #include "../controls/generic.h"
39 #include "theme.h"
40 #include "vlcproc.h"
41 #include "skin_common.h"
42
43
44
45 //---------------------------------------------------------------------------
46 // THEME
47 //---------------------------------------------------------------------------
48 Theme::Theme( intf_thread_t *_p_intf )
49 {
50     p_intf = _p_intf;
51     BmpBank = new BitmapBank( p_intf );
52     FntBank = new FontBank( p_intf );
53     EvtBank = new EventBank( p_intf );
54     OffBank = new OffSetBank( p_intf );
55     ConstructPlaylist = false;
56
57     ShowInTray    = false;
58     ShowInTaskbar = false;
59
60 }
61 //---------------------------------------------------------------------------
62 Theme::~Theme()
63 {
64     // Delete the windows
65     list<SkinWindow *>::const_iterator win;
66     for( win = WindowList.begin(); win != WindowList.end(); win++ )
67     {
68         delete (OSWindow *)(*win);
69     }
70     delete OffBank;
71     delete EvtBank;
72     delete BmpBank;
73     delete FntBank;
74 }
75 //---------------------------------------------------------------------------
76 void Theme::ShowTheme()
77 {
78     // Get parameters form vlcrc config file
79     if( ShowInTray != (bool)config_GetInt( p_intf, "show_in_tray" ) )
80         ChangeTray();
81
82     if( ShowInTaskbar != (bool)config_GetInt( p_intf, "show_in_taskbar" ) )
83         ChangeTaskbar();
84
85     list<SkinWindow *>::const_iterator win;
86     Event *evt1;
87     Event *evt2;
88
89     // Synchronize control to visible aspect
90     for( win = WindowList.begin(); win != WindowList.end(); win++ )
91     {
92         // Synchronize windows visibility
93         if( (*win)->OnStartThemeVisible )
94         {
95             evt1 = (Event *)new OSEvent( p_intf, (*win), WINDOW_OPEN,  1, 0 );
96             evt2 = (Event *)new OSEvent( p_intf, (*win), WINDOW_CLOSE, 0, 0 );
97         }
98         else
99         {
100             evt1 = (Event *)new OSEvent( p_intf, (*win), WINDOW_OPEN,  0, 0 );
101             evt2 = (Event *)new OSEvent( p_intf, (*win), WINDOW_CLOSE, 1, 0 );
102         }
103         evt1->PostSynchroMessage( true );
104         evt2->PostSynchroMessage( true );
105     }
106
107     // Initialize magnetism
108     CheckAnchors();
109
110     // Show windows
111     OSAPI_PostMessage( NULL, VLC_SHOW, 0, 0 );
112 }
113 //---------------------------------------------------------------------------
114 void Theme::CreateSystemMenu()
115 {
116     AddSystemMenu( "Open file...", EvtBank->Get( "open" ) );
117     AddSystemMenu( "Change skin...", EvtBank->Get( "load_skin" ) );
118     AddSystemMenu( "Preferences...", NULL );
119     AddSystemMenu( "SEPARATOR", 0 );
120     AddSystemMenu( "Exit", EvtBank->Get( "quit" ) );
121 }
122 //---------------------------------------------------------------------------
123 void Theme::LoadConfig()
124 {
125     // Get config from vlcrc file
126     char *save = config_GetPsz( p_intf, "skin_config" );
127     if( save == NULL )
128         return;
129
130     // Initialization
131     list<SkinWindow *>::const_iterator win;
132     int i = 0;
133     int x, y, v, scan;
134
135     // Get config for each window
136     for( win = WindowList.begin(); win != WindowList.end(); win++ )
137     {
138         // Get config
139         scan = sscanf( &save[i * 13], "(%4d,%4d,%1d)", &x, &y, &v );
140
141         // If config has the correct number of arguments
142         if( scan > 2 )
143         {
144             (*win)->Move( x, y );
145             (*win)->OnStartThemeVisible = (bool)v;
146         }
147
148         // Next window
149         i++;
150     }
151 }
152 //---------------------------------------------------------------------------
153 void Theme::SaveConfig()
154 {
155     // Initialize char where config is stored
156     char *save  = new char[400];
157     list<SkinWindow *>::const_iterator win;
158     int i = 0;
159     int x, y;
160
161     // Save config of every window
162     for( win = WindowList.begin(); win != WindowList.end(); win++ )
163     {
164         // Print config
165         (*win)->GetPos( x, y );
166         sprintf( &save[i * 13], "(%4d,%4d,%1d)", x, y,
167             (*win)->OnStartThemeVisible );
168         i++;
169     }
170
171     // Save config to file
172     config_PutPsz( p_intf, "skin_config",     save );
173     config_PutInt( p_intf, "show_in_tray",    (int)ShowInTray );
174     config_PutInt( p_intf, "show_in_taskbar", (int)ShowInTaskbar );
175     config_SaveConfigFile( p_intf, "skins" );
176
177     // Free memory
178     delete[] save;
179
180 }
181 //---------------------------------------------------------------------------
182 void Theme::StartTheme( int magnet )
183 {
184     Magnet = magnet;
185 }
186 //---------------------------------------------------------------------------
187 void Theme::InitTheme()
188 {
189     // Initialize the events
190     EvtBank->Init();
191
192     // Initialize the controls
193     InitControls();
194
195     // Initialize the windows
196     InitWindows();
197 }
198 //---------------------------------------------------------------------------
199 void Theme::InitWindows()
200 {
201     for( list<SkinWindow *>::const_iterator win = WindowList.begin();
202          win != WindowList.end(); win++ )
203     {
204         (*win)->Init();
205     }
206 }
207 //---------------------------------------------------------------------------
208 void Theme::InitControls()
209 {
210     for( list<SkinWindow *>::const_iterator win = WindowList.begin();
211          win != WindowList.end(); win++ )
212     {
213         for( unsigned int i = 0; i < (*win)->ControlList.size(); i++ )
214         {
215             (*win)->ControlList[i]->Init();
216         }
217     }
218 }
219 //---------------------------------------------------------------------------
220 SkinWindow * Theme::GetWindow( string name )
221 {
222     for( list<SkinWindow *>::const_iterator win = WindowList.begin();
223          win != WindowList.end(); win++ )
224     {
225         if( name == OSAPI_GetWindowTitle( *win ) )
226         {
227             return (*win);
228         }
229     }
230     return NULL;
231 }
232 //---------------------------------------------------------------------------
233 void Theme::MoveSkin( SkinWindow *wnd, int left, int top )
234 {
235     int x, y, oldx, oldy;
236     SkinWindow *win;
237     list<Anchor *>::const_iterator anc;
238     list<Anchor *>::const_iterator hang;
239     wnd->GetPos( oldx, oldy );
240
241     // Move child windows recursively
242     for( anc = wnd->AnchorList.begin(); anc != wnd->AnchorList.end(); anc++ )
243     {
244         for( hang = (*anc)->HangList.begin(); hang != (*anc)->HangList.end();
245              hang++ )
246         {
247             win = (*hang)->GetParent();
248             // Check that the window hasn't already moved (this avoids
249             // infinite recursion with circular anchoring)
250             if( !win->Moved )
251             {
252                 win->Moved = true;
253                 MoveSkin( win, left, top );
254             }
255         }
256     }
257
258     // Move window
259     wnd->Move( oldx + left, oldy + top );
260 }
261 //---------------------------------------------------------------------------
262 bool Theme::MoveSkinMagnet( SkinWindow *wnd, int left, int top )
263 {
264
265     // If magnetism not activate
266     if( !Magnet )
267     {
268         wnd->Move( left, top );
269         return false;
270     }
271
272     // Screen bounds initialization
273     int NewLeft = left;
274     int NewTop  = top;
275     int Sx, Sy, Wx, Wy;
276     OSAPI_GetScreenSize( Sx, Sy );
277     int width, height;
278     wnd->GetSize( width, height );
279     wnd->GetPos( Wx, Wy );
280
281     // Magnetism with screen bounds
282     if( left < Magnet && left > -Magnet)
283         NewLeft = 0;
284     else if( left + width > Sx - Magnet && left + width < Sx + Magnet )
285         NewLeft = Sx - width;
286     if( top < Magnet && top > -Magnet )
287         NewTop = 0;
288     else if( top + height > Sy - Magnet && top + height < Sy + Magnet )
289         NewTop = Sy - height;
290
291     // Deal with anchors
292     HangToAnchors( wnd, NewLeft, NewTop );
293
294     // All windows can be moved
295     list<SkinWindow *>::const_iterator win;
296     for( win = WindowList.begin(); win != WindowList.end(); win++ )
297         (*win)->Moved = false;
298
299     // Move Window
300     MoveSkin( wnd, NewLeft - Wx, NewTop - Wy );
301
302     return true;
303 }
304 //---------------------------------------------------------------------------
305 void Theme::HangToAnchors( SkinWindow *wnd, int &x, int &y, bool init )
306 {
307     // Magnetism initialization
308     int win_x, win_y, win_anchor_x, win_anchor_y, wnd_anchor_x, wnd_anchor_y;
309     list<SkinWindow *>::const_iterator win;
310     list<Anchor *>::const_iterator win_anchor, wnd_anchor;
311
312     // Parse list of windows
313     for( win = WindowList.begin(); win != WindowList.end(); win++ )
314     {
315         // If window is moved window
316         if( (*win) == wnd )
317             continue;               // Check next window
318
319         // If window is hidden
320         if( !init )
321         {
322             if( (*win)->IsHidden() )
323                 continue;           // Check next window
324         }
325         else
326         {
327             if( !(*win)->OnStartThemeVisible )
328                 continue;           // Check next window
329         }
330
331         // Parse anchor lists
332         for( wnd_anchor  = wnd->AnchorList.begin();
333              wnd_anchor != wnd->AnchorList.end(); wnd_anchor++ )
334         {
335             for( win_anchor  = (*win)->AnchorList.begin();
336                  win_anchor != (*win)->AnchorList.end(); win_anchor++ )
337             {
338                 if( (*wnd_anchor)->GetPriority() <
339                     (*win_anchor)->GetPriority() )
340                 {
341                     // Parent anchor is win and child is wnd !!!
342
343                     if( !(*win_anchor)->Hang( (*wnd_anchor), x, y ) )
344                     {
345                         // If child is in parent list and parent doesn't hang
346                         // child
347                         if( (*win_anchor)->IsInList( (*wnd_anchor) ) )
348                             (*win_anchor)->Remove( (*wnd_anchor) );
349                     }
350                     else
351                     {
352                         // If parent hangs child and child is not yet in list
353                         if( !(*win_anchor)->IsInList( (*wnd_anchor) ) )
354                         {
355                             (*win_anchor)->Add( (*wnd_anchor) );
356                         }
357
358                         // Move window to stick anchor
359                         (*wnd_anchor)->GetPos( wnd_anchor_x, wnd_anchor_y );
360                         (*win_anchor)->GetPos( win_anchor_x, win_anchor_y );
361                         (*win)->GetPos( win_x, win_y );
362
363                         x = win_x + win_anchor_x - wnd_anchor_x;
364                         y = win_y + win_anchor_y - wnd_anchor_y;
365
366                         break;
367                     }
368
369                 }
370                 else if( (*win_anchor)->Hang( (*wnd_anchor), x, y ) )
371                 {
372                     if( !(*wnd_anchor)->IsInList( *win_anchor ) )
373                     {
374                         // Move window to stick anchor
375                         (*wnd_anchor)->GetPos( wnd_anchor_x, wnd_anchor_y );
376                         (*win_anchor)->GetPos( win_anchor_x, win_anchor_y );
377                         (*win)->GetPos( win_x, win_y );
378
379                         x = win_x + win_anchor_x - wnd_anchor_x;
380                         y = win_y + win_anchor_y - wnd_anchor_y;
381                     }
382
383                     break;
384                 }
385             }
386         }
387     }
388 }
389 //---------------------------------------------------------------------------
390 void Theme::CheckAnchors()
391 {
392     list<SkinWindow *>::const_iterator win;
393     int x, y;
394
395     for( win = WindowList.begin(); win != WindowList.end(); win++ )
396     {
397         (*win)->GetPos( x, y );
398         HangToAnchors( (*win), x, y, true );
399         (*win)->Move( x, y );
400     }
401 }
402 //---------------------------------------------------------------------------
403