* tooltips are now updated during scrolling
[vlc.git] / modules / gui / skins / src / window.cpp
1 /*****************************************************************************
2  * window.cpp: Window class
3  *****************************************************************************
4  * Copyright (C) 2003 VideoLAN
5  * $Id: window.cpp,v 1.30 2003/06/17 18:13:18 asmax 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 "anchor.h"
32 #include "../controls/generic.h"
33 #include "window.h"
34 #include "event.h"
35 #include "../os_api.h"
36 #include "graphics.h"
37 #include "../os_graphics.h"
38 #include "banks.h"
39 #include "theme.h"
40 #include "skin_common.h"
41 #include "dialogs.h"
42
43 #include <stdio.h>
44
45
46 //---------------------------------------------------------------------------
47 // Skinable Window
48 //---------------------------------------------------------------------------
49 SkinWindow::SkinWindow( intf_thread_t *_p_intf, int x, int y, bool visible,
50     int transition, int normalalpha, int movealpha, bool dragdrop )
51 {
52     p_intf = _p_intf;
53
54     // Set position parameters
55     Left         = x;
56     Top          = y;
57     Width        = 0;
58     Height       = 0;
59     WindowMoving = false;
60     Moved        = false;
61
62     // Set transparency
63     Transition   = transition;
64     if( Transition < 1 )
65         Transition = 1;
66     NormalAlpha  = normalalpha;
67     MoveAlpha    = movealpha;
68     Alpha        = normalalpha;
69     StartAlpha   = 0;
70     EndAlpha     = 0;
71     StartTime    = 0;
72     EndTime      = 0;
73     Lock         = 0;
74
75     // Visible parameters
76     Image               = NULL;
77     Hidden              = true;
78     Changing            = false;
79     OnStartThemeVisible = visible;
80
81     // Drag & drop
82     DragDrop = dragdrop;
83
84     // ToolTip
85     ToolTipText = "none";
86 }
87 //---------------------------------------------------------------------------
88 SkinWindow::~SkinWindow()
89 {
90     if( Image )
91     {
92         delete Image;
93     }
94     // Destroy the controls
95     for( unsigned int i = 0; i < ControlList.size(); i++ )
96         delete ControlList[i];
97 }
98 //---------------------------------------------------------------------------
99 void SkinWindow::Open()
100 {
101     if( !Hidden )
102         return;
103
104     Changing = true;
105
106 #ifdef WIN32
107     if( Transition && IS_WINNT )
108     {
109         SetTransparency( 0 );
110         OSAPI_PostMessage( this, WINDOW_SHOW, 0, 0 );
111         Fade( NormalAlpha, Transition );
112     }
113     else
114     {
115 #endif
116         OSAPI_PostMessage( this, WINDOW_SHOW, 0, 0 );
117 #ifdef WIN32
118     }
119 #endif
120
121 }
122 //---------------------------------------------------------------------------
123 void SkinWindow::Close()
124 {
125     Changing = true;
126
127 #ifdef WIN32
128     if( Transition && IS_WINNT )
129         Fade( 0, Transition, WINDOW_HIDE );
130     else
131 #endif
132         OSAPI_PostMessage( this, WINDOW_FADE, WINDOW_HIDE, 1242 );
133 }
134 //---------------------------------------------------------------------------
135 void SkinWindow::Show()
136 {
137     Changing = false;
138     Hidden   = false;
139     OSShow( true );
140 }
141 //---------------------------------------------------------------------------
142 void SkinWindow::Hide()
143 {
144     if( Hidden )
145         return;
146
147     Changing = false;
148     Hidden   = true;
149     OSShow( false );
150     OSAPI_PostMessage( NULL, VLC_TEST_ALL_CLOSED, 0, 0 );
151 }
152 //---------------------------------------------------------------------------
153 void SkinWindow::Fade( int To, int Time, unsigned int evt )
154 {
155     // No fading effect on win9x
156 #ifdef WIN32
157     if( IS_WINNT )
158     {
159         StartAlpha = Alpha;
160         EndAlpha   = To;
161         StartTime  = OSAPI_GetTime();
162         EndTime    = StartTime + Time;
163         Lock++;
164
165         OSAPI_PostMessage( this, WINDOW_FADE, evt, Lock );
166     }
167 #endif
168 }
169 //---------------------------------------------------------------------------
170 bool SkinWindow::ProcessEvent( Event *evt )
171 {
172     unsigned int i;
173     unsigned int msg = evt->GetMessage();
174     unsigned int p1  = evt->GetParam1();
175     int          p2  = evt->GetParam2();
176
177     // Send event to control if necessary
178     if( msg > VLC_CONTROL )
179     {
180         for( i = 0; i < ControlList.size(); i++ )
181             ControlList[i]->GenericProcessEvent( evt );
182         return true;
183     }
184
185     // Message processing
186     switch( msg )
187     {
188         case WINDOW_FADE:
189             if( Lock == p2 && ChangeAlpha( OSAPI_GetTime() ) )
190             {
191                 OSAPI_PostMessage( this, WINDOW_FADE, p1, p2 );
192             }
193             else
194             {
195                 OSAPI_PostMessage( this, p1, 0, 0 );
196             }
197             return true;
198
199         case WINDOW_MOVE:
200             WindowManualMoveInit();
201             WindowMoving = true;
202             if( MoveAlpha )
203                 Fade( MoveAlpha, 100 );
204             return true;
205
206         case WINDOW_OPEN:
207             switch( p1 )
208             {
209                 case 0:
210                     Close();
211                     break;
212                 case 1:
213                     Open();
214                     break;
215                 case 2:
216                     if( Hidden )
217                         Open();
218                     else
219                         Close();
220                     break;
221             }
222             return true;
223
224         case WINDOW_CLOSE:
225             switch( p1 )
226             {
227                 case 0:
228                     Open();
229                     break;
230                 case 1:
231                     Close();
232                     break;
233                 case 2:
234                     if( Hidden )
235                         Open();
236                     else
237                         Close();
238                     break;
239             }
240             return true;
241
242         case WINDOW_SHOW:
243             Show();
244             return true;
245
246         case WINDOW_HIDE:
247             Hide();
248             return true;
249
250         case WINDOW_LEAVE:
251             MouseMove( -1, -1, 0 );
252             return true;
253
254         case WINDOW_REFRESH:
255             RefreshAll();
256             return true;
257
258         default:
259             // OS specific messages processing
260             return ProcessOSEvent( evt );
261     }
262 }
263 //---------------------------------------------------------------------------
264 bool SkinWindow::ChangeAlpha( int time )
265 {
266 #ifdef WIN32
267     if( IS_WINNT )
268     {
269         if( time >= EndTime )
270         {
271             if( Lock )
272             {
273                 SetTransparency( EndAlpha );
274                 Lock = 0;
275             }
276             return false;
277         }
278
279         int NewAlpha = StartAlpha + (EndAlpha - StartAlpha) * (time - StartTime)
280             / (EndTime - StartTime);
281         if( NewAlpha != Alpha )
282             SetTransparency( NewAlpha );
283         if( NewAlpha == EndAlpha )
284         {
285             Lock = 0;
286             return false;
287         }
288     }
289 #endif
290     return true;
291 }
292 //---------------------------------------------------------------------------
293 void SkinWindow::RefreshImage( int x, int y, int w, int h )
294 {
295     unsigned int i;
296
297     // Create Bitmap Buffer
298     Graphics *Buffer = (Graphics *)new OSGraphics( p_intf, w, h, this );
299 //    Graphics *Buffer = (Graphics *)new OSGraphics( w, h, this );
300
301     // Draw every control
302     for( i = 0; i < ControlList.size(); i++ )
303         ControlList[i]->Draw( x, y, w, h, Buffer );
304
305     // Copy buffer in Image
306     Image->CopyFrom( x, y, w, h, Buffer, 0, 0, SRC_COPY );
307
308     // Free memory
309     delete Buffer;
310 }
311 //---------------------------------------------------------------------------
312 void SkinWindow::Refresh( int x, int y, int w, int h )
313 {
314     if( Image == NULL )
315         return;
316
317     // Refresh buffer image
318     RefreshImage( x, y, w, h );
319
320     if( Hidden )
321         return;
322
323     // And copy buffer to window
324     RefreshFromImage( x, y, w, h );
325 }
326 //---------------------------------------------------------------------------
327 void SkinWindow::RefreshAll()
328 {
329     Refresh( 0, 0, Width, Height );
330 }
331 //---------------------------------------------------------------------------
332 void SkinWindow::MouseDown( int x, int y, int button )
333 {
334     // Checking event in controls
335     for( int i = ControlList.size() - 1; i >= 0; i-- )
336     {
337         if( ControlList[i]->IsVisible() &&
338             ControlList[i]->MouseDown( x, y, button ) )
339         {
340             msg_Dbg( p_intf, "Mouse down (ID=%s)",
341                      ControlList[i]->GetId().c_str() );
342             break;
343         }
344     }
345 }
346 //---------------------------------------------------------------------------
347 void SkinWindow::MouseMove( int x, int y, int button  )
348 {
349     int i;
350
351     // Move window if selected !
352     if( WindowMoving )
353     {
354         WindowManualMove();
355     }
356
357     // Checking event in controls
358     for( i = ControlList.size() - 1; i >= 0; i-- )
359     {
360         if( ControlList[i]->IsVisible() &&
361             ControlList[i]->MouseMove( x, y, button ) )
362         {
363             break;
364         }
365     }
366
367     // Checking help text
368     for( i = ControlList.size() - 1; i >= 0; i-- )
369     {
370         if( ControlList[i]->IsVisible() && ControlList[i]->MouseOver( x, y ) )
371         {
372             ControlList[i]->SendNewHelpText();
373             break;
374         }
375     }
376
377     // If help text not found, change it to ""
378     if( i == -1 )
379     {
380         p_intf->p_sys->p_theme->EvtBank->Get( "help" )
381             ->PostTextMessage( " " );
382     }
383
384     // Checking for change in Tool Tip
385     for( i = ControlList.size() - 1; i >= 0; i-- )
386     {
387         if( ControlList[i]->IsVisible() &&
388             ControlList[i]->ToolTipTest( x, y ) )
389         {
390             break;
391         }
392     }
393
394     // If no change, delete tooltip text
395     if( i == -1 )
396         ChangeToolTipText( "none" );
397 }
398 //---------------------------------------------------------------------------
399 void SkinWindow::MouseUp( int x, int y, int button )
400 {
401     int i;
402
403     // Move window if selected !
404     if( WindowMoving )
405     {
406         if( MoveAlpha )
407             Fade( NormalAlpha, 100 );
408
409         // Check for magnetism
410         p_intf->p_sys->p_theme->CheckAnchors();
411
412         WindowMoving = false;
413     }
414
415     // Checking event in controls
416     for( i = ControlList.size() - 1; i >= 0; i-- )
417     {
418         if( ControlList[i]->IsVisible() &&
419             ControlList[i]->MouseUp( x, y, button ) )
420         {
421             msg_Dbg( p_intf, "Mouse up (ID=%s)",
422                      ControlList[i]->GetId().c_str() );
423             break;
424         }
425     }
426
427     if( i < 0  && button == MOUSE_RIGHT )
428     {
429         p_intf->p_sys->p_dialogs->ShowPopup();
430     }
431 }
432 //---------------------------------------------------------------------------
433 void SkinWindow::MouseDblClick( int x, int y, int button )
434 {
435     int i;
436
437     // Checking event in controls
438     for( i = ControlList.size() - 1; i >= 0; i-- )
439     {
440         if( ControlList[i]->IsVisible() &&
441             ControlList[i]->MouseDblClick( x, y, button ) )
442         {
443             msg_Dbg( p_intf, "Double click (ID=%s)",
444                      ControlList[i]->GetId().c_str() );
445         }
446     }
447 }
448 //---------------------------------------------------------------------------
449 void SkinWindow::MouseScroll( int x, int y, int direction )
450 {
451     // Checking event in controls
452     for( int i = ControlList.size() - 1; i >= 0; i-- )
453     {
454         if( ControlList[i]->IsVisible() &&
455             ControlList[i]->MouseScroll( x, y, direction ) )
456         {
457             break;
458         }
459     } 
460     
461     // Checking for change in Tool Tip
462     for( int i = ControlList.size() - 1; i >= 0; i-- )
463     {
464         if( ControlList[i]->IsVisible() &&
465             ControlList[i]->ToolTipTest( x, y ) )
466         {
467             break;
468         }
469     }
470
471 }
472 //---------------------------------------------------------------------------
473 void SkinWindow::Init()
474 {
475     // Get size of window
476     ReSize();
477
478     // Refresh Image buffer
479     RefreshImage( 0, 0, Width, Height );
480
481     // Move window as it hasn't been moved yet
482     Move( Left, Top );
483 }
484 //---------------------------------------------------------------------------
485 void SkinWindow::ReSize()
486 {
487     // Initialization
488     unsigned int i;
489     int w    = 0;
490     int h    = 0;
491     int MinX = 10000000;
492     int MinY = 10000000;
493
494     // Search size of window and negative values to move all
495     for( i = 0; i < ControlList.size(); i++ )
496     {
497 #define min(a,b) ((a)<(b))?(a):(b)
498 #define max(a,b) ((a)>(b))?(a):(b)
499         w = max( w, ControlList[i]->GetLeft() + ControlList[i]->GetWidth() );
500         h = max( h, ControlList[i]->GetTop() + ControlList[i]->GetHeight() );
501         MinX = min( MinX, ControlList[i]->GetLeft() );
502         MinY = min( MinY, ControlList[i]->GetTop() );
503 #undef max
504 #undef min
505     }
506
507     // Correct values
508     w = w - MinX;
509     h = h - MinY;
510     if( w <= 0 )
511         w = 1;
512     if( h <= 0 )
513         h = 1;
514
515     // Move window and controls !
516     if( MinX != 0 || MinY != 0 )
517     {
518         Move( Left + MinX, Top + MinY );
519         for( i = 0; i < ControlList.size(); i++ )
520             ControlList[i]->MoveRelative( -MinX, -MinY );
521     }
522
523     // Create buffer image for repainting if size has changed
524     if( w != Width || h != Height )
525     {
526         // Change image buffer
527         if( Image != NULL )
528             delete (OSGraphics *)Image;
529         Image = (Graphics *)new OSGraphics( p_intf, w, h, this );
530
531         Size( w, h );
532     }
533
534 }
535 //---------------------------------------------------------------------------
536 void SkinWindow::GetSize( int &w, int &h )
537 {
538     w = Width;
539     h = Height;
540 }
541 //---------------------------------------------------------------------------
542 void SkinWindow::GetPos( int &x, int &y )
543 {
544     x = Left;
545     y = Top;
546 }
547 //---------------------------------------------------------------------------
548