* modules/gui/skins/*: compilation fixes for MSVC. Almost working, we just to find...
[vlc.git] / modules / gui / skins / controls / slider.cpp
1 /*****************************************************************************
2  * slider.cpp: Slider control
3  *****************************************************************************
4  * Copyright (C) 2003 VideoLAN
5  * $Id: slider.cpp,v 1.10 2003/05/02 15:53:32 gbazin 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 //--- GENERAL ---------------------------------------------------------------
28 #include <math.h>
29 #include <stdio.h>
30
31 //--- VLC -------------------------------------------------------------------
32 #include <vlc/intf.h>
33
34 //--- SKIN ------------------------------------------------------------------
35 #include "../os_api.h"
36 #include "../src/bitmap.h"
37 #include "../src/bezier.h"
38 #include "../src/banks.h"
39 #include "../src/graphics.h"
40 #include "../os_graphics.h"
41 #include "generic.h"
42 #include "slider.h"
43 #include "../src/event.h"
44 #include "../src/theme.h"
45 #include "../src/window.h"
46 #include "../src/skin_common.h"
47
48
49
50 //---------------------------------------------------------------------------
51 // Control Slider
52 //---------------------------------------------------------------------------
53 ControlSlider::ControlSlider( string id, bool visible, string type,
54     string cursorUp, string cursorDown, double *ptx, double *pty, int nb,
55     string tooltiptext, string help, SkinWindow *Parent )
56     : GenericControl( id, visible, help, Parent )
57 {
58     Type             = type;
59     Left             = 0;
60     Top              = 0;
61     State            = 1;
62     Value            = 0;
63     Selected         = false;
64     Enabled          = false;
65     this->cursorUp   = cursorUp;
66     this->cursorDown = cursorDown;
67     Curve            = new Bezier( ptx, pty, nb );
68     UpdateEvent      = NULL;
69     SliderRange      = SLIDER_RANGE;
70     LastRefreshTime  = OSAPI_GetTime();
71
72     // Tool tip text
73     BaseToolTipText = tooltiptext;
74     FullToolTipText = BaseToolTipText;
75 }
76 //---------------------------------------------------------------------------
77 ControlSlider::~ControlSlider()
78 {
79     delete[] CursorX;
80     delete[] CursorY;
81     delete (OSRegion *)HitRgn;
82 }
83 //---------------------------------------------------------------------------
84 void ControlSlider::Init()
85 {
86     int i;
87     // Get bitmap from list
88     Img    = new (Bitmap *[2]);
89     Img[0] = p_intf->p_sys->p_theme->BmpBank->Get( cursorUp );
90     Img[1] = p_intf->p_sys->p_theme->BmpBank->Get( cursorDown );
91
92     // Get images sizes
93     Img[0]->GetSize( CWidth, CHeight );
94
95     // Computing slider curve : get points
96     MaxValue = Curve->GetNumOfDifferentPoints();
97     CursorX  = new int[MaxValue + 1];
98     CursorY  = new int[MaxValue + 1];
99     Curve->GetDifferentPoints( CursorX, CursorY, -CWidth / 2, -CHeight / 2 );
100
101         // Search for size value
102         Left   = CursorX[0];
103         Top    = CursorY[0];
104         Width  = CursorX[0];
105         Height = CursorY[0];
106         for( i = 1; i <= MaxValue; i++ )
107         {
108             if( CursorX[i] < Left )
109                 Left = CursorX[i];
110             if( CursorY[i] < Top )
111                 Top  = CursorY[i];
112             if( CursorX[i] > Width )
113                 Width = CursorX[i];
114             if( CursorY[i] > Height )
115                 Height  = CursorY[i];
116         }
117         Width  += CWidth  - Left;
118         Height += CHeight - Top;
119
120         // Curve is no more needed so delete it
121         delete Curve;
122
123     // Create Hit Region
124     HitRgn = (SkinRegion *)new OSRegion;
125
126     // Create slider hit region and move cursor inside control
127     for( i = 0; i <= MaxValue; i++ )
128     {
129         HitRgn->AddElipse( CursorX[i], CursorY[i], CWidth, CHeight );
130         CursorX[i] -= Left;
131         CursorY[i] -= Top;
132     }
133
134     // Select type of slider
135     if( Type == "time" )
136     {
137         Enabled = false;
138         UpdateEvent = p_intf->p_sys->p_theme->EvtBank->Get( "time" );
139     }
140     else if( Type == "volume" )
141     {
142         Enabled = true;
143         UpdateEvent = p_intf->p_sys->p_theme->EvtBank->Get( "volume_refresh" );
144     }
145     else
146     {
147         Enabled = false;
148         UpdateEvent = p_intf->p_sys->p_theme->EvtBank->Get( "none" );
149     }
150 }
151 //---------------------------------------------------------------------------
152 bool ControlSlider::ProcessEvent( Event *evt )
153 {
154     unsigned int msg = evt->GetMessage();
155     unsigned int p1  = evt->GetParam1();
156     int          p2  = evt->GetParam2();
157
158     switch( msg )
159     {
160         case CTRL_ENABLED:
161             Enable( (Event*)p1, (bool)p2 );
162             return true;
163
164         case CTRL_SET_SLIDER:
165             if( UpdateEvent->IsEqual( (Event*)p1 ) )
166             {
167                 SetCursorPosition( (long)p2 );
168             }
169             return true;
170
171     }
172     return false;
173 }
174 //---------------------------------------------------------------------------
175 void ControlSlider::MoveRelative( int xOff, int yOff )
176 {
177     Left += xOff;
178     Top  += yOff;
179     HitRgn->Move( xOff, yOff );
180 }
181 //---------------------------------------------------------------------------
182 void ControlSlider::SetCursorPosition( long Pos )
183 {
184     if( Pos < 0 )
185         Pos = 0;
186     if( Pos > SliderRange )
187         Pos = SliderRange;
188
189     if( !Selected )
190     {
191         if( SliderRange == 0 )
192             MoveCursor( 0 );
193         else
194             MoveCursor( Pos * MaxValue / SliderRange );
195     }
196 }
197 //---------------------------------------------------------------------------
198 long ControlSlider::GetCursorPosition()
199 {
200     return SliderRange * Value / MaxValue;
201 }
202 //---------------------------------------------------------------------------
203 void ControlSlider::MoveCursor( int newValue )
204 {
205     int X, Y, W, H;
206     int OldValue = Value;
207     Value = newValue;
208     if( OldValue != Value )
209     {
210         X = (CursorX[Value] > CursorX[OldValue])
211             ? Left + CursorX[OldValue] : Left + CursorX[Value];
212         Y = (CursorY[Value] > CursorY[OldValue])
213             ? Top  + CursorY[OldValue] : Top  + CursorY[Value];
214         W = (CursorX[Value] > CursorX[OldValue])
215             ? CursorX[Value] - CursorX[OldValue] + CWidth
216             : CursorX[OldValue] - CursorX[Value] + CWidth;
217         H = (CursorY[Value] > CursorY[OldValue])
218             ? CursorY[Value] - CursorY[OldValue] + CHeight
219             : CursorY[OldValue] - CursorY[Value] + CHeight;
220         if( 2 * CWidth * CHeight < W * H )
221         {
222             ParentWindow->Refresh( Left + CursorX[OldValue],
223                 Top + CursorY[OldValue], CWidth, CHeight );
224             ParentWindow->Refresh( Left + CursorX[Value],
225                 Top + CursorY[Value], CWidth, CHeight );
226         }
227         else
228         {
229             ParentWindow->Refresh( X, Y, W, H );
230         }
231
232         // Change tooltip
233         if( BaseToolTipText != "none" )
234         {
235             char *percent = new char[6];
236             sprintf( percent, "%i %%", Value * 100 / MaxValue );
237             FullToolTipText = BaseToolTipText + " - " + (string)percent;
238             delete[] percent;
239         }
240     }
241 }
242 //---------------------------------------------------------------------------
243 void ControlSlider::Draw( int x, int y, int w, int h, Graphics *dest )
244 {
245     if( !Visible )
246         return;
247
248     int xI, yI, wI, hI;
249
250     if( GetIntersectRgn( x, y, w, h, Left+CursorX[Value], Top+CursorY[Value],
251                          CWidth, CHeight, xI, yI, wI, hI ) )
252     {
253         Img[1 - State]->DrawBitmap( xI - Left - CursorX[Value],
254             yI - Top - CursorY[Value], wI, hI, xI - x, yI - y, dest );
255     }
256 }
257 //---------------------------------------------------------------------------
258 bool ControlSlider::MouseUp( int x, int y, int button )
259 {
260     State = 1;
261     if( Enabled && Selected )
262     {
263         Selected = false;
264         ParentWindow->Refresh( Left + CursorX[Value],
265             Top + CursorY[Value], CWidth, CHeight );
266         UpdateEvent->SetParam2( GetCursorPosition() );
267         UpdateEvent->SendEvent();
268     }
269     return false;
270 }
271 //---------------------------------------------------------------------------
272 bool ControlSlider::MouseDown( int x, int y, int button )
273 {
274     if( !Enabled )
275         return false;
276
277     // If hit into cursor or indide active slider region
278     if( HitRgn->Hit( x, y ) && button == 1 )
279     {
280         State = 0;
281         Selected = true;
282         ParentWindow->Refresh( Left + CursorX[Value],
283             Top + CursorY[Value], CWidth, CHeight );
284         MoveCursor( FindNearestPoint( x, y ) );
285         UpdateEvent->SetParam2( GetCursorPosition() );
286         UpdateEvent->SendEvent();
287         return true;
288     }
289     return false;
290 }
291 //---------------------------------------------------------------------------
292 bool ControlSlider::MouseMove( int x, int y, int button )
293 {
294     if( !Enabled || !Selected || !button )
295         return false;
296
297     MoveCursor( FindNearestPoint( x, y ) );
298
299     // Refresh value if time ellapsed since last refresh is more than 200 ms
300     int time = OSAPI_GetTime();
301     if( time > LastRefreshTime + 250 )
302     {
303         UpdateEvent->SetParam2( GetCursorPosition() );
304         UpdateEvent->SendEvent();
305         LastRefreshTime = time;
306     }
307     return true;
308 }
309 //---------------------------------------------------------------------------
310 bool ControlSlider::MouseOver( int x, int y )
311 {
312     if( HitRgn->Hit( x, y ) )
313         return true;
314     else
315         return false;
316 }
317 //---------------------------------------------------------------------------
318 bool ControlSlider::MouseScroll( int x, int y, int direction )
319 {
320     if( !Enabled || !MouseOver( x, y ) )
321         return false;
322
323     int val = Value;
324     switch( direction )
325     {
326         case MOUSE_SCROLL_DOWN:
327             if( val > 0 ) val--;
328             break;
329
330         case MOUSE_SCROLL_UP:
331             if( val < MaxValue ) val++;
332             break;
333     }
334
335     MoveCursor( val );
336     UpdateEvent->SetParam2( GetCursorPosition() );
337     UpdateEvent->SendEvent();
338
339     return true;
340 }
341 //---------------------------------------------------------------------------
342 bool ControlSlider::ToolTipTest( int x, int y )
343 {
344     if( MouseOver( x, y ) )
345     {
346         if( BaseToolTipText == "none" )
347         {
348             ParentWindow->ChangeToolTipText( BaseToolTipText );
349         }
350         else
351         {
352             ParentWindow->ChangeToolTipText( FullToolTipText );
353         }
354         return true;
355     }
356     return false;
357 }
358 //---------------------------------------------------------------------------
359 void ControlSlider::ChangeSliderRange( int NewRange )
360 {
361     if( NewRange == SliderRange )
362         return;
363
364     SliderRange = NewRange;
365
366     int Pos = GetCursorPosition();
367     SetCursorPosition( Pos );
368
369 }
370 //---------------------------------------------------------------------------
371 void ControlSlider::Enable( Event *event, bool enabled )
372 {
373     if( !UpdateEvent->IsEqual( event ) )
374         return;
375
376     if( enabled && !Enabled )
377     {
378         Enabled = true;
379         ParentWindow->Refresh( Left, Top, Width, Height );
380     }
381     else if( !enabled && Enabled )
382     {
383         Enabled = false;
384         ParentWindow->Refresh( Left, Top, Width, Height );
385     }
386 }
387 //---------------------------------------------------------------------------
388 int ControlSlider::FindNearestPoint( int x, int y )
389 {
390     int i, wx, wy;
391     double D;
392     double minD = 50;
393     int RefValue = Value;
394     // Move point inside control
395     OSAPI_GetMousePos( x, y );              // This is used to avoid bug with
396                                             // negative values
397     ParentWindow->GetPos( wx, wy );
398     x += -wx - Left - CWidth  / 2;
399     y += -wy - Top  - CHeight / 2;
400
401     // Search nearest point
402     for( i = 0; i <= MaxValue; i++ )
403     {
404         D = sqrt( ( CursorX[i] - x ) * ( CursorX[i] - x ) +
405                   ( CursorY[i] - y ) * ( CursorY[i] - y ) );
406         if( D < minD )
407         {
408             minD = D;
409             RefValue = i;
410         }
411     }
412     return RefValue;
413 }
414 //---------------------------------------------------------------------------
415