]> git.sesse.net Git - vlc/blob - modules/gui/beos/MediaControlView.cpp
4e6b21c6d93a5ffc6394a83da257b7fbd80665cb
[vlc] / modules / gui / beos / MediaControlView.cpp
1 /*****************************************************************************
2  * MediaControlView.cpp: beos interface
3  *****************************************************************************
4  * Copyright (C) 1999, 2000, 2001 the VideoLAN team
5  * $Id$
6  *
7  * Authors: Tony Castley <tony@castley.net>
8  *          Stephan Aßmus <stippi@yellowbites.com>
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., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
23  *****************************************************************************/
24
25 /* System headers */
26 #include <InterfaceKit.h>
27 #include <AppKit.h>
28 #include <String.h>
29
30 /* VLC headers */
31 #include <vlc/vlc.h>
32 #include <vlc_interface.h>
33 extern "C"
34 {
35   #include <audio_output.h>
36 }
37
38 /* BeOS interface headers */
39 #include "Bitmaps.h"
40 #include "DrawingTidbits.h"
41 #include "InterfaceWindow.h"
42 #include "MsgVals.h"
43 #include "TransportButton.h"
44 #include "ListViews.h"
45 #include "MediaControlView.h"
46
47 #define BORDER_INSET 6.0
48 #define MIN_SPACE 4.0
49 #define SPEAKER_SLIDER_DIST 6.0
50 #define VOLUME_MIN_WIDTH 70.0
51 #define DIM_LEVEL 0.4
52 #define VOLUME_SLIDER_LAYOUT_WEIGHT 2.0
53 #define SEEK_SLIDER_KNOB_WIDTH 8.0
54
55 // slider colors are hardcoded here, because that's just
56 // what they currently are within those bitmaps
57 const rgb_color kGreen = (rgb_color){ 152, 203, 152, 255 };
58 const rgb_color kGreenShadow = (rgb_color){ 102, 152, 102, 255 };
59 const rgb_color kBackground = (rgb_color){ 216, 216, 216, 255 };
60 const rgb_color kSeekGreen = (rgb_color){ 171, 221, 161, 255 };
61 const rgb_color kSeekGreenShadow = (rgb_color){ 144, 186, 136, 255 };
62 const rgb_color kSeekRed = (rgb_color){ 255, 0, 0, 255 };
63 const rgb_color kSeekRedLight = (rgb_color){ 255, 152, 152, 255 };
64 const rgb_color kSeekRedShadow = (rgb_color){ 178, 0, 0, 255 };
65
66 #define DISABLED_SEEK_MESSAGE _("Drop files to play")
67 #define SEEKSLIDER_RANGE 2048
68
69 enum
70 {
71         MSG_REWIND                              = 'rwnd',
72         MSG_FORWARD                             = 'frwd',
73         MSG_SKIP_BACKWARDS              = 'skpb',
74         MSG_SKIP_FORWARD                = 'skpf',
75 };
76
77 // constructor
78 MediaControlView::MediaControlView( intf_thread_t * _p_intf, BRect frame)
79         : BBox(frame, NULL, B_FOLLOW_NONE, B_WILL_DRAW | B_FRAME_EVENTS | B_PULSE_NEEDED,
80                    B_PLAIN_BORDER),
81       p_intf( _p_intf ),
82       fCurrentRate(INPUT_RATE_DEFAULT),
83       fCurrentStatus(-1),
84       fBottomControlHeight(0.0),
85       fIsEnabled( true )
86 {
87         BRect frame(0.0, 0.0, 10.0, 10.0);
88         
89     // Seek Slider
90     fSeekSlider = new SeekSlider( p_intf, frame, "seek slider", this );
91     fSeekSlider->SetValue(0);
92     fSeekSlider->ResizeToPreferred();
93     AddChild( fSeekSlider );
94
95     // Buttons
96     // Skip Back
97     frame.SetRightBottom(kSkipButtonSize);
98         fBottomControlHeight = kRewindBitmapHeight - 1.0;
99     fSkipBack = new TransportButton(frame, B_EMPTY_STRING,
100                                     kSkipBackBitmapBits,
101                                     kPressedSkipBackBitmapBits,
102                                     kDisabledSkipBackBitmapBits,
103                                     new BMessage(MSG_SKIP_BACKWARDS));
104     AddChild( fSkipBack );
105
106         // Play Pause
107     frame.SetRightBottom(kPlayButtonSize);
108         if (fBottomControlHeight < kPlayPauseBitmapHeight - 1.0)
109                 fBottomControlHeight = kPlayPauseBitmapHeight - 1.0;
110     fPlayPause = new PlayPauseButton(frame, B_EMPTY_STRING,
111                                      kPlayButtonBitmapBits,
112                                      kPressedPlayButtonBitmapBits,
113                                      kDisabledPlayButtonBitmapBits,
114                                      kPlayingPlayButtonBitmapBits,
115                                      kPressedPlayingPlayButtonBitmapBits,
116                                      kPausedPlayButtonBitmapBits,
117                                      kPressedPausedPlayButtonBitmapBits,
118                                      new BMessage(START_PLAYBACK));
119
120     AddChild( fPlayPause );
121
122     // Skip Foward
123     frame.SetRightBottom(kSkipButtonSize);
124     fSkipForward = new TransportButton(frame, B_EMPTY_STRING,
125                                        kSkipForwardBitmapBits,
126                                        kPressedSkipForwardBitmapBits,
127                                        kDisabledSkipForwardBitmapBits,
128                                        new BMessage(MSG_SKIP_FORWARD));
129     AddChild( fSkipForward );
130
131         // Forward
132         fForward = new TransportButton(frame, B_EMPTY_STRING,
133                                                                    kForwardBitmapBits,
134                                                                    kPressedForwardBitmapBits,
135                                                                    kDisabledForwardBitmapBits,
136                                                                    new BMessage(MSG_FORWARD));
137 //      AddChild( fForward );
138
139         // Rewind
140         fRewind = new TransportButton(frame, B_EMPTY_STRING,
141                                                                   kRewindBitmapBits,
142                                                                   kPressedRewindBitmapBits,
143                                                                   kDisabledRewindBitmapBits,
144                                                                   new BMessage(MSG_REWIND));
145 //      AddChild( fRewind );
146
147     // Stop
148     frame.SetRightBottom(kStopButtonSize);
149         if (fBottomControlHeight < kStopBitmapHeight - 1.0)
150                 fBottomControlHeight = kStopBitmapHeight - 1.0;
151     fStop = new TransportButton(frame, B_EMPTY_STRING,
152                                 kStopButtonBitmapBits,
153                                 kPressedStopButtonBitmapBits,
154                                 kDisabledStopButtonBitmapBits,
155                                 new BMessage(STOP_PLAYBACK));
156         AddChild( fStop );
157
158         // Mute
159     frame.SetRightBottom(kSpeakerButtonSize);
160         if (fBottomControlHeight < kSpeakerIconBitmapHeight - 1.0)
161                 fBottomControlHeight = kSpeakerIconBitmapHeight - 1.0;
162     fMute = new TransportButton(frame, B_EMPTY_STRING,
163                                 kSpeakerIconBits,
164                                 kPressedSpeakerIconBits,
165                                 kSpeakerIconBits,
166                                 new BMessage(VOLUME_MUTE));
167
168         AddChild( fMute );
169
170     // Volume Slider
171         fVolumeSlider = new VolumeSlider(BRect(0.0, 0.0, VOLUME_MIN_WIDTH,
172                                                                                    kVolumeSliderBitmapHeight - 1.0),
173                                                                          "volume slider", 1, AOUT_VOLUME_MAX,
174                                                                          new BMessage(VOLUME_CHG));
175         fVolumeSlider->SetValue( config_GetInt( p_intf, "volume" ) );
176         AddChild( fVolumeSlider );
177         
178         // Position Info View
179     fPositionInfo = new PositionInfoView(BRect(0.0, 0.0, 10.0, 10.0), "led",
180                                          p_intf);
181     fPositionInfo->ResizeToPreferred();
182     AddChild( fPositionInfo );
183 }
184
185 // destructor
186 MediaControlView::~MediaControlView()
187 {
188 }
189
190 // AttachedToWindow
191 void
192 MediaControlView::AttachedToWindow()
193 {
194         // we are now a valid BHandler
195         fRewind->SetTarget(this);
196         fForward->SetTarget(this);
197         fSkipBack->SetTarget(this);
198         fSkipForward->SetTarget(this);
199         fVolumeSlider->SetTarget(Window());
200
201         BRect r(_MinFrame());
202         if (BMenuBar* menuBar = Window()->KeyMenuBar()) {
203                 float width, height;
204                 menuBar->GetPreferredSize(&width, &height);
205 //              r.bottom += menuBar->Bounds().Height();
206                 r.bottom += height;
207                 // see that our calculated minimal width is not smaller than what
208                 // the menubar can be
209                 width -= r.Width();
210                 if (width > 0.0)
211                         r.right += width;
212         }
213
214         Window()->SetSizeLimits(r.Width(), r.Width() * 1.8, r.Height(), r.Height() * 1.3);
215         if (!Window()->Bounds().Contains(r))
216                 Window()->ResizeTo(r.Width(), r.Height());
217         else
218                 FrameResized(Bounds().Width(), Bounds().Height());
219
220         // get pulse message every two frames
221         Window()->SetPulseRate(80000);
222 }
223
224 // FrameResized
225 void
226 MediaControlView::FrameResized(float width, float height)
227 {
228         BRect r(Bounds());
229         // make sure we don't leave dirty pixels
230         // (B_FULL_UPDATE_ON_RESIZE == annoying flicker -> this is smarter)
231         if (fOldBounds.Width() < r.Width())
232                 Invalidate(BRect(fOldBounds.right, fOldBounds.top + 1.0,
233                                                  fOldBounds.right, fOldBounds.bottom - 1.0));
234         else
235                 Invalidate(BRect(r.right, r.top + 1.0,
236                                                  r.right, r.bottom - 1.0));
237         if (fOldBounds.Height() < r.Height())
238                 Invalidate(BRect(fOldBounds.left + 1.0, fOldBounds.bottom,
239                                                  fOldBounds.right - 1.0, fOldBounds.bottom));
240         else
241                 Invalidate(BRect(r.left + 1.0, r.bottom,
242                                                  r.right - 1.0, r.bottom));
243         // remember for next time
244         fOldBounds = r;
245         // layout controls
246         r.InsetBy(BORDER_INSET, BORDER_INSET);
247         _LayoutControls(r);
248 }
249
250 // GetPreferredSize
251 void
252 MediaControlView::GetPreferredSize(float* width, float* height)
253 {
254         if (width && height)
255         {
256                 BRect r(_MinFrame());
257                 *width = r.Width();
258                 *height = r.Height();
259         }
260 }
261
262 // MessageReceived
263 void
264 MediaControlView::MessageReceived(BMessage* message)
265 {
266         switch (message->what)
267         {
268                 case MSG_REWIND:
269                         break;
270                 case MSG_FORWARD:
271                         break;
272                 case MSG_SKIP_BACKWARDS:
273                         Window()->PostMessage(NAVIGATE_PREV);
274                         break;
275                 case MSG_SKIP_FORWARD:
276                         Window()->PostMessage(NAVIGATE_NEXT);
277                         break;
278                 default:
279                     BBox::MessageReceived(message);
280                     break;
281         }
282 }
283
284 // Pulse
285 void
286 MediaControlView::Pulse()
287 {
288         InterfaceWindow* window = dynamic_cast<InterfaceWindow*>(Window());
289         if (window && window->IsStopped())
290                         fPlayPause->SetStopped();
291
292     unsigned short i_volume;
293     aout_VolumeGet( p_intf, (audio_volume_t*)&i_volume );
294     fVolumeSlider->SetValue( i_volume );
295 }
296
297 // SetProgress
298 void
299 MediaControlView::SetProgress( float position )
300 {
301         fSeekSlider->SetPosition( position );
302 }
303
304 // SetStatus
305 void
306 MediaControlView::SetStatus(int status, int rate)
307 {
308         // we need to set the button status periodically
309         // (even if it is the same) to get a blinking button
310         fCurrentStatus = status;
311     switch( status )
312     {
313         case PLAYING_S:
314         case OPENNING_S:
315         case BUFFERING_S:
316             fPlayPause->SetPlaying();
317             break;
318         case PAUSE_S:
319             fPlayPause->SetPaused();
320             break;
321         default:
322             fPlayPause->SetStopped();
323             break;
324     }
325         if (rate != fCurrentRate)
326         {
327                 fCurrentRate = rate;
328             if ( rate < INPUT_RATE_DEFAULT )
329             {
330                 // TODO: ...
331             }
332         }
333 }
334
335 // SetEnabled
336 void
337 MediaControlView::SetEnabled(bool enabled)
338 {
339     if( ( enabled && fIsEnabled ) ||
340         ( !enabled && !fIsEnabled ) )
341     {
342         /* do not redraw if it is not necessary */
343         return;
344     }
345     
346         if( LockLooper() )
347         {
348                 fSkipBack->SetEnabled( enabled );
349                 fPlayPause->SetEnabled( enabled );
350                 fSkipForward->SetEnabled( enabled );
351                 fStop->SetEnabled( enabled );
352                 fMute->SetEnabled( enabled );
353                 fVolumeSlider->SetEnabled( enabled );
354                 fSeekSlider->SetEnabled( enabled );
355                 fRewind->SetEnabled( enabled );
356                 fForward->SetEnabled( enabled );
357                 UnlockLooper();
358                 fIsEnabled = enabled;
359         }
360 }
361
362 // SetAudioEnabled
363 void
364 MediaControlView::SetAudioEnabled(bool enabled)
365 {
366         fMute->SetEnabled(enabled);
367         fVolumeSlider->SetEnabled(enabled);
368 }
369
370 // GetVolume
371 uint32
372 MediaControlView::GetVolume() const
373 {
374         return fVolumeSlider->Value();
375 }
376
377 // SetSkippable
378 void
379 MediaControlView::SetSkippable(bool backward, bool forward)
380 {
381         fSkipBack->SetEnabled(backward);
382         fSkipForward->SetEnabled(forward);
383 }
384
385 // SetMuted
386 void
387 MediaControlView::SetMuted(bool mute)
388 {
389         fVolumeSlider->SetMuted(mute);
390 }
391
392 // _LayoutControls
393 void
394 MediaControlView::_LayoutControls(BRect frame) const
395 {
396         // seek slider
397         BRect r(frame);
398         // calculate absolutly minimal width
399         float minWidth = fSkipBack->Bounds().Width();
400 //      minWidth += fRewind->Bounds().Width();
401         minWidth += fStop->Bounds().Width();
402         minWidth += fPlayPause->Bounds().Width();
403 //      minWidth += fForward->Bounds().Width();
404         minWidth += fSkipForward->Bounds().Width();
405         minWidth += fMute->Bounds().Width();
406         minWidth += VOLUME_MIN_WIDTH;
407         
408         // layout time slider and info view
409     float width, height;
410     fPositionInfo->GetBigPreferredSize( &width, &height );
411     float ratio = width / height;
412     width = r.Height() * ratio;
413     if (frame.Width() - minWidth - MIN_SPACE >= width
414               && frame.Height() >= height)
415     {
416         r.right = r.left + width;
417         fPositionInfo->SetMode(PositionInfoView::MODE_BIG);
418         _LayoutControl(fPositionInfo, r, true, true);
419         frame.left = r.right + MIN_SPACE;
420         r.left = frame.left;
421         r.right = frame.right;
422     //    r.bottom = r.top + r.Height() / 2.0 - MIN_SPACE / 2.0;
423         r.bottom = r.top + fSeekSlider->Bounds().Height();
424         _LayoutControl(fSeekSlider, r, true);
425     }
426     else
427     {
428         fPositionInfo->GetPreferredSize( &width, &height );
429         fPositionInfo->SetMode(PositionInfoView::MODE_SMALL);
430         fPositionInfo->ResizeTo(width, height);
431         r.bottom = r.top + r.Height() / 2.0 - MIN_SPACE / 2.0;
432         r.right = r.left + fPositionInfo->Bounds().Width();
433         _LayoutControl(fPositionInfo, r, true );
434         r.left = r.right + MIN_SPACE;
435         r.right = frame.right;
436         _LayoutControl(fSeekSlider, r, true);
437     }
438         float currentWidth = frame.Width();
439         float space = (currentWidth - minWidth) / 6.0;//8.0;
440         // apply weighting
441         space = MIN_SPACE + (space - MIN_SPACE) / VOLUME_SLIDER_LAYOUT_WEIGHT;
442         // layout controls with "space" inbetween
443         r.left = frame.left;
444         r.top = r.bottom + MIN_SPACE + 1.0;
445         r.bottom = frame.bottom;
446         // skip back
447         r.right = r.left + fSkipBack->Bounds().Width();
448         _LayoutControl(fSkipBack, r);
449         // rewind
450 //      r.left = r.right + space;
451 //      r.right = r.left + fRewind->Bounds().Width();
452 //      _LayoutControl(fRewind, r);
453         // stop
454         r.left = r.right + space;
455         r.right = r.left + fStop->Bounds().Width();
456         _LayoutControl(fStop, r);
457         // play/pause
458         r.left = r.right + space;
459         r.right = r.left + fPlayPause->Bounds().Width();
460         _LayoutControl(fPlayPause, r);
461         // forward
462 //      r.left = r.right + space;
463 //      r.right = r.left + fForward->Bounds().Width();
464 //      _LayoutControl(fForward, r);
465         // skip forward
466         r.left = r.right + space;
467         r.right = r.left + fSkipForward->Bounds().Width();
468         _LayoutControl(fSkipForward, r);
469         // speaker icon
470         r.left = r.right + space + space;
471         r.right = r.left + fMute->Bounds().Width();
472         _LayoutControl(fMute, r);
473         // volume slider
474         r.left = r.right + SPEAKER_SLIDER_DIST; // keep speaker icon and volume slider attached
475         r.right = frame.right;
476         _LayoutControl(fVolumeSlider, r, true);
477 }
478
479 // _MinFrame
480 BRect           
481 MediaControlView::_MinFrame() const
482 {
483         // add up width of controls along bottom (seek slider will likely adopt)
484         float minWidth = 2 * BORDER_INSET;
485         minWidth += fSkipBack->Bounds().Width() + MIN_SPACE;
486 //      minWidth += fRewind->Bounds().Width() + MIN_SPACE;
487         minWidth += fStop->Bounds().Width() + MIN_SPACE;
488         minWidth += fPlayPause->Bounds().Width() + MIN_SPACE;
489 //      minWidth += fForward->Bounds().Width() + MIN_SPACE;
490         minWidth += fSkipForward->Bounds().Width() + MIN_SPACE + MIN_SPACE;
491         minWidth += fMute->Bounds().Width() + SPEAKER_SLIDER_DIST;
492         minWidth += VOLUME_MIN_WIDTH;
493
494         // add up height of seek slider and heighest control on bottom
495         float minHeight = 2 * BORDER_INSET;
496         minHeight += fSeekSlider->Bounds().Height() + MIN_SPACE + MIN_SPACE / 2.0;
497         minHeight += fBottomControlHeight;
498         return BRect(0.0, 0.0, minWidth - 1.0, minHeight - 1.0);
499 }
500
501 // _LayoutControl
502 void
503 MediaControlView::_LayoutControl(BView* view, BRect frame,
504                                  bool resizeWidth, bool resizeHeight) const
505 {
506     if (!resizeHeight)
507             // center vertically
508             frame.top = (frame.top + frame.bottom) / 2.0 - view->Bounds().Height() / 2.0;
509         if (!resizeWidth)
510             //center horizontally
511                 frame.left = (frame.left + frame.right) / 2.0 - view->Bounds().Width() / 2.0;
512         view->MoveTo(frame.LeftTop());
513         float width = resizeWidth ? frame.Width() : view->Bounds().Width();
514         float height = resizeHeight ? frame.Height() : view->Bounds().Height();
515     if (resizeWidth || resizeHeight)
516         view->ResizeTo(width, height);
517 }
518
519
520
521 /*****************************************************************************
522  * SeekSlider
523  *****************************************************************************/
524 SeekSlider::SeekSlider( intf_thread_t * _p_intf,
525                         BRect frame, const char* name, MediaControlView *owner )
526         : BControl(frame, name, NULL, NULL, B_FOLLOW_NONE,
527                            B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE),
528           p_intf(_p_intf),
529           fOwner(owner),
530           fTracking(false)
531 {
532         BFont font(be_plain_font);
533         font.SetSize(9.0);
534         SetFont(&font);
535 }
536
537 SeekSlider::~SeekSlider()
538 {
539 }
540
541 /*****************************************************************************
542  * VolumeSlider::AttachedToWindow
543  *****************************************************************************/
544 void
545 SeekSlider::AttachedToWindow()
546 {
547         BControl::AttachedToWindow();
548         SetViewColor(B_TRANSPARENT_32_BIT);
549 }
550
551 /*****************************************************************************
552  * VolumeSlider::Draw
553  *****************************************************************************/
554 void
555 SeekSlider::Draw(BRect updateRect)
556 {
557         BRect r(Bounds());
558         float knobWidth2 = SEEK_SLIDER_KNOB_WIDTH / 2.0;
559         float sliderStart = (r.left + knobWidth2);
560         float sliderEnd = (r.right - knobWidth2);
561         float knobPos = sliderStart
562                                         + floorf((sliderEnd - sliderStart - 1.0) * Value()
563                                         / SEEKSLIDER_RANGE);
564         // draw both sides (the original from Be doesn't seem
565         // to make a difference for enabled/disabled state)
566 //      DrawBitmapAsync(fLeftSideBits, r.LeftTop());
567 //      DrawBitmapAsync(fRightSideBits, BPoint(sliderEnd + 1.0, r.top));
568         // colors for the slider area between the two bitmaps
569         rgb_color background = kBackground;//ui_color(B_PANEL_BACKGROUND_COLOR);
570         rgb_color shadow = tint_color(background, B_DARKEN_2_TINT);
571         rgb_color softShadow = tint_color(background, B_DARKEN_1_TINT);
572         rgb_color darkShadow = tint_color(background, B_DARKEN_4_TINT);
573         rgb_color midShadow = tint_color(background, B_DARKEN_3_TINT);
574         rgb_color light = tint_color(background, B_LIGHTEN_MAX_TINT);
575         rgb_color softLight = tint_color(background, B_LIGHTEN_1_TINT);
576         rgb_color green = kSeekGreen;
577         rgb_color greenShadow = kSeekGreenShadow;
578         rgb_color black = kBlack;
579         rgb_color dotGrey = midShadow;
580         rgb_color dotGreen = greenShadow;
581         // draw frame
582         _StrokeFrame(r, softShadow, softShadow, softLight, softLight);
583         r.InsetBy(1.0, 1.0);
584         _StrokeFrame(r, black, black, light, light);
585         if (IsEnabled())
586         {
587                 r.InsetBy(1.0, 1.0);
588                 // inner shadow
589                 _StrokeFrame(r, greenShadow, greenShadow, green, green);
590                 r.top++;
591                 r.left++;
592                 _StrokeFrame(r, greenShadow, greenShadow, green, green);
593                 // inside area
594                 r.InsetBy(1.0, 1.0);
595                 SetHighColor(green);
596                 FillRect(r);
597                 // dots
598                 int32 dotCount = (int32)(r.Width() / 6.0);
599                 BPoint dotPos;
600                 dotPos.y = r.top + 2.0;
601                 SetHighColor(dotGreen);
602                 for (int32 i = 0; i < dotCount; i++)
603                 {
604                         dotPos.x = sliderStart + i * 6.0 + 5.0;
605                         StrokeLine(dotPos, BPoint(dotPos.x, dotPos.y + 6.0));
606                 }
607                 // slider handle
608                 r.top -= 4.0;
609                 r.bottom += 3.0;
610                 r.left = knobPos - knobWidth2;
611                 r.right = knobPos + knobWidth2;
612                 // black outline
613                 float handleBottomSize = 2.0;
614                 float handleArrowSize = 6.0;
615                 BeginLineArray(10);
616                         // upper handle
617                         AddLine(BPoint(r.left, r.top + handleBottomSize),
618                                         BPoint(r.left, r.top), black);
619                         AddLine(BPoint(r.left + 1.0, r.top),
620                                         BPoint(r.right, r.top), black);
621                         AddLine(BPoint(r.right, r.top + 1.0),
622                                         BPoint(r.right, r.top + handleBottomSize), black);
623                         AddLine(BPoint(r.right - 1.0, r.top + handleBottomSize + 1.0),
624                                         BPoint(knobPos, r.top + handleArrowSize), black);
625                         AddLine(BPoint(knobPos - 1.0, r.top + handleArrowSize - 1.0),
626                                         BPoint(r.left + 1.0, r.top + handleBottomSize + 1.0), black);
627                         // lower handle
628                         AddLine(BPoint(r.left, r.bottom),
629                                         BPoint(r.left, r.bottom - handleBottomSize), black);
630                         AddLine(BPoint(r.left + 1.0, r.bottom - handleBottomSize - 1.0),
631                                         BPoint(knobPos, r.bottom - handleArrowSize), black);
632                         AddLine(BPoint(knobPos + 1.0, r.bottom - handleArrowSize + 1.0),
633                                         BPoint(r.right, r.bottom - handleBottomSize), black);
634                         AddLine(BPoint(r.right, r.bottom - handleBottomSize + 1.0),
635                                         BPoint(r.right, r.bottom), black);
636                         AddLine(BPoint(r.right - 1.0, r.bottom),
637                                         BPoint(r.left + 1.0, r.bottom), black);
638                 EndLineArray();
639                 // inner red light and shadow lines
640                 r.InsetBy(1.0, 1.0);
641                 handleBottomSize--;
642                 handleArrowSize -= 2.0;
643                 BeginLineArray(10);
644                         // upper handle
645                         AddLine(BPoint(r.left, r.top + handleBottomSize),
646                                         BPoint(r.left, r.top), kSeekRedLight);
647                         AddLine(BPoint(r.left + 1.0, r.top),
648                                         BPoint(r.right, r.top), kSeekRedLight);
649                         AddLine(BPoint(r.right, r.top + 1.0),
650                                         BPoint(r.right, r.top + handleBottomSize), kSeekRedShadow);
651                         AddLine(BPoint(r.right - 1.0, r.top + handleBottomSize + 1.0),
652                                         BPoint(knobPos, r.top + handleArrowSize), kSeekRedShadow);
653                         AddLine(BPoint(knobPos - 1.0, r.top + handleArrowSize - 1.0),
654                                         BPoint(r.left + 1.0, r.top + handleBottomSize + 1.0), kSeekRedLight);
655                         // lower handle
656                         AddLine(BPoint(r.left, r.bottom),
657                                         BPoint(r.left, r.bottom - handleBottomSize), kSeekRedLight);
658                         AddLine(BPoint(r.left + 1.0, r.bottom - handleBottomSize - 1.0),
659                                         BPoint(knobPos, r.bottom - handleArrowSize), kSeekRedLight);
660                         AddLine(BPoint(knobPos + 1.0, r.bottom - handleArrowSize + 1.0),
661                                         BPoint(r.right, r.bottom - handleBottomSize), kSeekRedShadow);
662                         AddLine(BPoint(r.right, r.bottom - handleBottomSize + 1.0),
663                                         BPoint(r.right, r.bottom), kSeekRedShadow);
664                         AddLine(BPoint(r.right - 1.0, r.bottom),
665                                         BPoint(r.left + 1.0, r.bottom), kSeekRedShadow);
666                 EndLineArray();
667                 // fill rest of handles with red
668                 SetHighColor(kSeekRed);
669                 r.InsetBy(1.0, 1.0);
670                 handleArrowSize -= 2.0;
671                 BPoint arrow[3];
672                 // upper handle arrow
673                 arrow[0].x = r.left;
674                 arrow[0].y = r.top;
675                 arrow[1].x = r.right;
676                 arrow[1].y = r.top;
677                 arrow[2].x = knobPos;
678                 arrow[2].y = r.top + handleArrowSize;
679                 FillPolygon(arrow, 3);
680                 // lower handle arrow
681                 arrow[0].x = r.left;
682                 arrow[0].y = r.bottom;
683                 arrow[1].x = r.right;
684                 arrow[1].y = r.bottom;
685                 arrow[2].x = knobPos;
686                 arrow[2].y = r.bottom - handleArrowSize;
687                 FillPolygon(arrow, 3);
688         }
689         else
690         {
691                 r.InsetBy(1.0, 1.0);
692                 _StrokeFrame(r, darkShadow, darkShadow, darkShadow, darkShadow);
693                 r.InsetBy(1.0, 1.0);
694                 _StrokeFrame(r, darkShadow, darkShadow, darkShadow, darkShadow);
695                 r.InsetBy(1.0, 1.0);
696                 SetHighColor(darkShadow);
697                 SetLowColor(shadow);
698                 // stripes
699                 float width = floorf(StringWidth(DISABLED_SEEK_MESSAGE));
700                 float textPos = r.left + r.Width() / 2.0 - width / 2.0;
701                 pattern stripes = {{ 0xc7, 0x8f, 0x1f, 0x3e, 0x7c, 0xf8, 0xf1, 0xe3 }};
702                 BRect stripesRect(r);
703                 stripesRect.right = textPos - 5.0;
704                 FillRect(stripesRect, stripes);
705                 stripesRect.left = textPos + width + 3.0;
706                 stripesRect.right = r.right;
707                 FillRect(stripesRect, stripes);
708                 // info text
709                 r.left = textPos - 4.0;
710                 r.right = textPos + width + 2.0;
711                 FillRect(r);
712                 SetHighColor(shadow);
713                 SetLowColor(darkShadow);
714                 font_height fh;
715                 GetFontHeight(&fh);
716                 DrawString(DISABLED_SEEK_MESSAGE, BPoint(textPos, r.top + ceilf(fh.ascent) - 1.0));
717         }
718 }
719
720 /*****************************************************************************
721  * SeekSlider::MouseDown
722  *****************************************************************************/
723 void
724 SeekSlider::MouseDown(BPoint where)
725 {
726         if (IsEnabled() && Bounds().Contains(where))
727         {
728                 SetValue(_ValueFor(where.x));
729                 fTracking = true;
730                 SetMouseEventMask(B_POINTER_EVENTS, B_LOCK_WINDOW_FOCUS);
731         }
732 }
733
734 /*****************************************************************************
735  * SeekSlider::MouseMoved
736  *****************************************************************************/
737 void
738 SeekSlider::MouseMoved(BPoint where, uint32 code, const BMessage* dragMessage)
739 {
740         if (fTracking)
741         {
742                 SetValue(_ValueFor(where.x));
743         }
744 }
745
746 /*****************************************************************************
747  * SeekSlider::MouseUp
748  *****************************************************************************/
749 void
750 SeekSlider::MouseUp(BPoint where)
751 {
752         if (fTracking)
753         {
754                 fTracking = false;
755                 input_thread_t * p_input;
756                 p_input = (input_thread_t *)
757             vlc_object_find( p_intf, VLC_OBJECT_INPUT, FIND_ANYWHERE );
758
759         if( p_input )
760         {
761                     var_SetFloat( p_input, "position",
762                                   (float) Value() / SEEKSLIDER_RANGE );
763                     vlc_object_release( p_input );
764                 }
765         }
766 }
767
768 /*****************************************************************************
769  * SeekSlider::ResizeToPreferred
770  *****************************************************************************/
771 void
772 SeekSlider::ResizeToPreferred()
773 {
774         float width = 15.0 + StringWidth(DISABLED_SEEK_MESSAGE) + 15.0;
775         ResizeTo(width, 17.0);
776 }
777
778 /*****************************************************************************
779  * SeekSlider::SetPosition
780  *****************************************************************************/
781 void
782 SeekSlider::SetPosition(float position)
783 {
784         if ( LockLooper() )
785         {
786             if( !fTracking )
787             {
788                     SetValue( SEEKSLIDER_RANGE * position );
789                 }
790                 UnlockLooper();
791         }
792 }
793
794 /*****************************************************************************
795  * SeekSlider::_ValueFor
796  *****************************************************************************/
797 int32
798 SeekSlider::_ValueFor(float xPos) const
799 {
800         BRect r(Bounds());
801         float knobWidth2 = SEEK_SLIDER_KNOB_WIDTH / 2.0;
802         float sliderStart = (r.left + knobWidth2);
803         float sliderEnd = (r.right - knobWidth2);
804         int32 value =  (int32)(((xPos - sliderStart) * SEEKSLIDER_RANGE)
805                                   / (sliderEnd - sliderStart - 1.0));
806         if (value < 0)
807                 value = 0;
808         if (value > SEEKSLIDER_RANGE)
809                 value = SEEKSLIDER_RANGE;
810         return value;
811 }
812
813 /*****************************************************************************
814  * SeekSlider::_StrokeFrame
815  *****************************************************************************/
816 void
817 SeekSlider::_StrokeFrame(BRect r, rgb_color left, rgb_color top,
818                                                  rgb_color right, rgb_color bottom)
819 {
820         BeginLineArray(4);
821                 AddLine(BPoint(r.left, r.bottom), BPoint(r.left, r.top), left);
822                 AddLine(BPoint(r.left + 1.0, r.top), BPoint(r.right, r.top), top);
823                 AddLine(BPoint(r.right, r.top + 1.0), BPoint(r.right, r.bottom), right);
824                 AddLine(BPoint(r.right - 1.0, r.bottom), BPoint(r.left + 1.0, r.bottom), bottom);
825         EndLineArray();
826 }
827
828 /*****************************************************************************
829  * VolumeSlider
830  *****************************************************************************/
831 VolumeSlider::VolumeSlider(BRect frame, const char* name, int32 minValue, int32 maxValue,
832                                                    BMessage* message, BHandler* target)
833         : BControl(frame, name, NULL, message, B_FOLLOW_NONE,
834                            B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE),
835           fLeftSideBits(NULL),
836           fRightSideBits(NULL),
837           fKnobBits(NULL),
838           fTracking(false),
839           fMuted(false),
840           fMinValue(minValue),
841           fMaxValue(maxValue)
842 {
843         SetTarget(target);
844
845         // create bitmaps
846         BRect r(BPoint(0.0, 0.0), kVolumeSliderBitmapSize);
847         fLeftSideBits = new BBitmap(r, B_CMAP8);
848         fRightSideBits = new BBitmap(r, B_CMAP8);
849         r.Set(0.0, 0.0, kVolumeSliderKnobBitmapSize.x, kVolumeSliderKnobBitmapSize.y);
850         fKnobBits = new BBitmap(r, B_CMAP8);
851
852         _MakeBitmaps();
853 }
854
855 /*****************************************************************************
856  * VolumeSlider destructor
857  *****************************************************************************/
858 VolumeSlider::~VolumeSlider()
859 {
860         delete fLeftSideBits;
861         delete fRightSideBits;
862         delete fKnobBits;
863 }
864
865 /*****************************************************************************
866  * VolumeSlider::AttachedToWindow
867  *****************************************************************************/
868 void
869 VolumeSlider::AttachedToWindow()
870 {
871         BControl::AttachedToWindow();
872         SetViewColor(B_TRANSPARENT_32_BIT);
873 }
874
875 /*****************************************************************************
876  * VolumeSlider::SetValue
877  *****************************************************************************/
878 void
879 VolumeSlider::SetValue(int32 value)
880 {
881         if (value != Value())
882         {
883                 BControl::SetValue(value);
884                 Invoke();
885         }
886 }
887
888 /*****************************************************************************
889  * VolumeSlider::SetEnabled
890  *****************************************************************************/
891 void
892 VolumeSlider::SetEnabled(bool enable)
893 {
894         if (enable != IsEnabled())
895         {
896                 BControl::SetEnabled(enable);
897                 _MakeBitmaps();
898                 Invalidate();
899         }
900 }
901
902 /*****************************************************************************
903  * VolumeSlider::Draw
904  *****************************************************************************/
905 void
906 VolumeSlider::Draw(BRect updateRect)
907 {
908         if (IsValid())
909         {
910                 BRect r(Bounds());
911                 float sliderSideWidth = kVolumeSliderBitmapWidth;
912                 float sliderStart = (r.left + sliderSideWidth);
913                 float sliderEnd = (r.right - sliderSideWidth);
914                 float knobPos = sliderStart
915                                                 + (sliderEnd - sliderStart - 1.0) * (Value() - fMinValue)
916                                                 / (fMaxValue - fMinValue);
917                 // draw both sides (the original from Be doesn't seem
918                 // to make a difference for enabled/disabled state)
919                 DrawBitmapAsync(fLeftSideBits, r.LeftTop());
920                 DrawBitmapAsync(fRightSideBits, BPoint(sliderEnd + 1.0, r.top));
921                 // colors for the slider area between the two bitmaps
922                 rgb_color background = kBackground;//ui_color(B_PANEL_BACKGROUND_COLOR);
923                 rgb_color shadow = tint_color(background, B_DARKEN_2_TINT);
924                 rgb_color softShadow = tint_color(background, B_DARKEN_1_TINT);
925                 rgb_color darkShadow = tint_color(background, B_DARKEN_4_TINT);
926                 rgb_color midShadow = tint_color(background, B_DARKEN_3_TINT);
927                 rgb_color light = tint_color(background, B_LIGHTEN_MAX_TINT);
928                 rgb_color softLight = tint_color(background, B_LIGHTEN_1_TINT);
929                 rgb_color green = kGreen;
930                 rgb_color greenShadow = kGreenShadow;
931                 rgb_color black = kBlack;
932                 rgb_color dotGrey = midShadow;
933                 rgb_color dotGreen = greenShadow;
934                 // make dimmed version of colors if we're disabled
935                 if (!IsEnabled())
936                 {
937                         shadow = (rgb_color){ 200, 200, 200, 255 };
938                         softShadow = dimmed_color_cmap8(softShadow, background, DIM_LEVEL);
939                         darkShadow = dimmed_color_cmap8(darkShadow, background, DIM_LEVEL);
940                         midShadow = shadow;
941                         light = dimmed_color_cmap8(light, background, DIM_LEVEL);
942                         softLight = dimmed_color_cmap8(softLight, background, DIM_LEVEL);
943                         green = dimmed_color_cmap8(green, background, DIM_LEVEL);
944                         greenShadow = dimmed_color_cmap8(greenShadow, background, DIM_LEVEL);
945                         black = dimmed_color_cmap8(black, background, DIM_LEVEL);
946                         dotGreen = dotGrey;
947                 }
948                 else if (fMuted)
949                 {
950                         green = tint_color(kBackground, B_DARKEN_3_TINT);
951                         greenShadow = tint_color(kBackground, B_DARKEN_4_TINT);
952                         dotGreen = greenShadow;
953                 }
954                 // draw slider edges between bitmaps
955                 BeginLineArray(7);
956                         AddLine(BPoint(sliderStart, r.top),
957                                         BPoint(sliderEnd, r.top), softShadow);
958                         AddLine(BPoint(sliderStart, r.bottom),
959                                         BPoint(sliderEnd, r.bottom), softLight);
960                         r.InsetBy(0.0, 1.0);
961                         AddLine(BPoint(sliderStart, r.top),
962                                         BPoint(sliderEnd, r.top), black);
963                         AddLine(BPoint(sliderStart, r.bottom),
964                                         BPoint(sliderEnd, r.bottom), light);
965                         r.top++;
966                         AddLine(BPoint(sliderStart, r.top),
967                                         BPoint(knobPos, r.top), greenShadow);
968                         AddLine(BPoint(knobPos, r.top),
969                                         BPoint(sliderEnd, r.top), midShadow);
970                         r.top++;
971                         AddLine(BPoint(sliderStart, r.top),
972                                         BPoint(knobPos, r.top), greenShadow);
973                 EndLineArray();
974                 // fill rest inside of slider
975                 r.InsetBy(0.0, 1.0);
976                 r.left = sliderStart;
977                 r.right = knobPos;
978                 SetHighColor(green);
979                 FillRect(r, B_SOLID_HIGH);
980                 r.left = knobPos + 1.0;
981                 r.right = sliderEnd;
982                 r.top -= 1.0;
983                 SetHighColor(shadow);
984                 FillRect(r, B_SOLID_HIGH);
985                 // draw little dots inside
986                 int32 dotCount = (int32)((sliderEnd - sliderStart) / 5.0);
987                 BPoint dotPos;
988                 dotPos.y = r.top + 4.0;
989                 for (int32 i = 0; i < dotCount; i++)
990                 {
991                         dotPos.x = sliderStart + i * 5.0 + 4.0;
992                         SetHighColor(dotPos.x < knobPos ? dotGreen : dotGrey);
993                         StrokeLine(dotPos, BPoint(dotPos.x, dotPos.y + 1.0));
994                 }
995                 // draw knob
996                 r.top -= 1.0;
997                 SetDrawingMode(B_OP_OVER); // part of knob is transparent
998                 DrawBitmapAsync(fKnobBits, BPoint(knobPos - kVolumeSliderKnobWidth / 2, r.top));
999         }
1000 }
1001
1002 /*****************************************************************************
1003  * VolumeSlider::MouseDown
1004  *****************************************************************************/
1005 void
1006 VolumeSlider::MouseDown(BPoint where)
1007 {
1008         if (Bounds().Contains(where) && IsEnabled())
1009         {
1010                 fTracking = true;
1011                 SetValue(_ValueFor(where.x));
1012                 SetMouseEventMask(B_POINTER_EVENTS, B_LOCK_WINDOW_FOCUS);
1013         }
1014 }
1015
1016 /*****************************************************************************
1017  * VolumeSlider::MouseMoved
1018  *****************************************************************************/
1019 void
1020 VolumeSlider::MouseMoved(BPoint where, uint32 transit, const BMessage* dragMessage)
1021 {
1022         if (fTracking)
1023                 SetValue(_ValueFor(where.x));
1024 }
1025
1026 /*****************************************************************************
1027  * VolumeSlider::MouseUp
1028  *****************************************************************************/
1029 void
1030 VolumeSlider::MouseUp(BPoint where)
1031 {
1032         fTracking = false;
1033 }
1034
1035
1036 /*****************************************************************************
1037  * VolumeSlider::IsValid
1038  *****************************************************************************/
1039 bool
1040 VolumeSlider::IsValid() const
1041 {
1042         return (fLeftSideBits && fLeftSideBits->IsValid()
1043                         && fRightSideBits && fRightSideBits->IsValid()
1044                         && fKnobBits && fKnobBits->IsValid());
1045 }
1046
1047 /*****************************************************************************
1048  * VolumeSlider::SetMuted
1049  *****************************************************************************/
1050 void
1051 VolumeSlider::SetMuted(bool mute)
1052 {
1053         if (mute != fMuted)
1054         {
1055                 fMuted = mute;
1056                 _MakeBitmaps();
1057                 Invalidate();
1058         }
1059 }
1060
1061 /*****************************************************************************
1062  * VolumeSlider::_MakeBitmaps
1063  *****************************************************************************/
1064 void
1065 VolumeSlider::_MakeBitmaps()
1066 {
1067         if (IsValid())
1068         {
1069                 // left side of slider
1070                 memcpy(fLeftSideBits->Bits(), kVolumeSliderLeftBitmapBits,
1071                            fLeftSideBits->BitsLength());
1072                 // right side of slider
1073                 memcpy(fRightSideBits->Bits(), kVolumeSliderRightBits,
1074                            fRightSideBits->BitsLength());
1075                 // slider knob
1076                 int32 length = fKnobBits->BitsLength();
1077                 memcpy(fKnobBits->Bits(), kVolumeSliderKnobBits, length);
1078                 uint8* bits = (uint8*)fKnobBits->Bits();
1079                 // black was used in the knob to represent transparency
1080                 // use screen to get index for the "transarent" color used in the bitmap
1081                 BScreen screen(B_MAIN_SCREEN_ID);
1082                 uint8 blackIndex = screen.IndexForColor(kBlack);
1083                 // replace black index with transparent index
1084                 for (int32 i = 0; i < length; i++)
1085                         if (bits[i] == blackIndex)
1086                                 bits[i] = B_TRANSPARENT_MAGIC_CMAP8;
1087
1088                 if (!IsEnabled())
1089                 {
1090                         // make ghosted versions of the bitmaps
1091                         dim_bitmap(fLeftSideBits, kBackground, DIM_LEVEL);
1092                         dim_bitmap(fRightSideBits, kBackground, DIM_LEVEL);
1093                         dim_bitmap(fKnobBits, kBackground, DIM_LEVEL);
1094                 }
1095                 else if (fMuted)
1096                 {
1097                         // replace green color (and shadow) in left slider side
1098                         bits = (uint8*)fLeftSideBits->Bits();
1099                         length = fLeftSideBits->BitsLength();
1100                         uint8 greenIndex = screen.IndexForColor(kGreen);
1101                         uint8 greenShadowIndex = screen.IndexForColor(kGreenShadow);
1102                         rgb_color shadow = tint_color(kBackground, B_DARKEN_3_TINT);
1103                         rgb_color midShadow = tint_color(kBackground, B_DARKEN_4_TINT);
1104                         uint8 replaceIndex = screen.IndexForColor(shadow);
1105                         uint8 replaceShadowIndex = screen.IndexForColor(midShadow);
1106                         for (int32 i = 0; i < length; i++)
1107                         {
1108                                 if (bits[i] == greenIndex)
1109                                         bits[i] = replaceIndex;
1110                                 else if (bits[i] == greenShadowIndex)
1111                                         bits[i] = replaceShadowIndex;
1112                         }
1113                 }
1114         }
1115 }
1116
1117 /*****************************************************************************
1118  * VolumeSlider::_ValueFor
1119  *****************************************************************************/
1120 int32
1121 VolumeSlider::_ValueFor(float xPos) const
1122 {
1123         BRect r(Bounds());
1124         float sliderStart = (r.left + kVolumeSliderBitmapWidth);
1125         float sliderEnd = (r.right - kVolumeSliderBitmapWidth);
1126         int32 value =  fMinValue + (int32)(((xPos - sliderStart) * (fMaxValue - fMinValue))
1127                                   / (sliderEnd - sliderStart - 1.0));
1128         if (value < fMinValue)
1129                 value = fMinValue;
1130         if (value > fMaxValue)
1131                 value = fMaxValue;
1132         return value;
1133 }
1134
1135 /*****************************************************************************
1136  * PositionInfoView::PositionInfoView
1137  *****************************************************************************/
1138 PositionInfoView::PositionInfoView( BRect frame, const char* name,
1139                                     intf_thread_t * p_interface )
1140         : BView( frame, name, B_FOLLOW_NONE,
1141                          B_WILL_DRAW | B_PULSE_NEEDED | B_FULL_UPDATE_ON_RESIZE ),
1142           fMode( MODE_SMALL ),
1143           fCurrentFileIndex( -1 ),
1144           fCurrentFileSize( -1 ),
1145           fCurrentTitleIndex( -1 ),
1146           fCurrentTitleSize( -1 ),
1147           fCurrentChapterIndex( -1 ),
1148           fCurrentChapterSize( -1 ),
1149           fSeconds( -1 ),
1150           fTimeString( "-:--:--" ),
1151           fLastPulseUpdate( system_time() ),
1152           fStackedWidthCache( 0.0 ),
1153           fStackedHeightCache( 0.0 )
1154 {
1155     p_intf = p_interface;
1156
1157         SetViewColor( B_TRANSPARENT_32_BIT );
1158         SetLowColor( kBlack );
1159         SetHighColor( 0, 255, 0, 255 );
1160         SetFontSize( 11.0 );
1161 }
1162
1163 /*****************************************************************************
1164  * PositionInfoView::~PositionInfoView
1165  *****************************************************************************/
1166 PositionInfoView::~PositionInfoView()
1167 {
1168 }
1169
1170 /*****************************************************************************
1171  * PositionInfoView::Draw
1172  *****************************************************************************/
1173 void
1174 PositionInfoView::Draw( BRect updateRect )
1175 {
1176         rgb_color background = ui_color( B_PANEL_BACKGROUND_COLOR );
1177         rgb_color shadow = tint_color( background, B_DARKEN_1_TINT );
1178         rgb_color darkShadow = tint_color( background, B_DARKEN_4_TINT );
1179         rgb_color light = tint_color( background, B_LIGHTEN_MAX_TINT );
1180         rgb_color softLight = tint_color( background, B_LIGHTEN_1_TINT );
1181         // frame
1182         BRect r( Bounds() );
1183         BeginLineArray( 8 );
1184                 AddLine( BPoint( r.left, r.bottom ),
1185                                  BPoint( r.left, r.top ), shadow );
1186                 AddLine( BPoint( r.left + 1.0, r.top ),
1187                                  BPoint( r.right, r.top ), shadow );
1188                 AddLine( BPoint( r.right, r.top + 1.0 ),
1189                                  BPoint( r.right, r.bottom ), softLight );
1190                 AddLine( BPoint( r.right - 1.0, r.bottom ),
1191                                  BPoint( r.left + 1.0, r.bottom ), softLight );
1192                 r.InsetBy( 1.0, 1.0 );
1193                 AddLine( BPoint( r.left, r.bottom ),
1194                                  BPoint( r.left, r.top ), darkShadow );
1195                 AddLine( BPoint( r.left + 1.0, r.top ),
1196                                  BPoint( r.right, r.top ), darkShadow );
1197                 AddLine( BPoint( r.right, r.top + 1.0 ),
1198                                  BPoint( r.right, r.bottom ), light );
1199                 AddLine( BPoint( r.right - 1.0, r.bottom ),
1200                                  BPoint( r.left + 1.0, r.bottom ), light );
1201         EndLineArray();
1202         // background
1203         r.InsetBy( 1.0, 1.0 );
1204         FillRect( r, B_SOLID_LOW );
1205         // contents
1206         font_height fh;
1207         GetFontHeight( &fh );
1208         switch ( fMode )
1209         {
1210                 case MODE_SMALL:
1211                 {
1212                         float width = StringWidth( fTimeString.String() );
1213                         DrawString( fTimeString.String(),
1214                                                 BPoint( r.left + r.Width() / 2.0 - width / 2.0,
1215                                                                 r.top + r.Height() / 2.0 + fh.ascent / 2.0 - 1.0 ) );
1216                         break;
1217                 }
1218                 case MODE_BIG:
1219                 {
1220                         BFont font;
1221                         GetFont( &font );
1222                         BFont smallFont = font;
1223                         BFont bigFont = font;
1224                         BFont tinyFont = font;
1225                         smallFont.SetSize( r.Height() / 5.0 );
1226                         bigFont.SetSize( r.Height() / 3.0 );
1227                         tinyFont.SetSize( r.Height() / 7.0 );
1228                         float timeHeight = r.Height() / 2.5;
1229                         float height = ( r.Height() - timeHeight ) / 3.0;
1230                         SetFont( &tinyFont );
1231                         SetHighColor( 0, 180, 0, 255 );
1232                         DrawString( _("File"), BPoint( r.left + 3.0, r.top + height ) );
1233                         DrawString( _("Title"), BPoint( r.left + 3.0, r.top + 2.0 * height ) );
1234                         DrawString( _("Chapter"), BPoint( r.left + 3.0, r.top + 3.0 * height ) );
1235                         SetFont( &smallFont );
1236                         BString helper;
1237                         SetHighColor( 0, 255, 0, 255 );
1238                         // file
1239                         _MakeString( helper, fCurrentFileIndex, fCurrentFileSize );
1240                         float width = StringWidth( helper.String() );
1241                         DrawString( helper.String(), BPoint( r.right - 3.0 - width, r.top + height ) );
1242                         // title
1243                         _MakeString( helper, fCurrentTitleIndex, fCurrentTitleSize );
1244                         width = StringWidth( helper.String() );
1245                         DrawString( helper.String(), BPoint( r.right - 3.0 - width, r.top + 2.0 * height ) );
1246                         // chapter
1247                         _MakeString( helper, fCurrentChapterIndex, fCurrentChapterSize );
1248                         width = StringWidth( helper.String() );
1249                         DrawString( helper.String(), BPoint( r.right - 3.0 - width, r.top + 3.0 * height ) );
1250                         // time
1251                         SetFont( &bigFont );
1252                         width = StringWidth( fTimeString.String() );
1253                         DrawString( fTimeString.String(),
1254                                                 BPoint( r.left + r.Width() / 2.0 - width / 2.0,
1255                                                                 r.bottom - 3.0 ) );
1256                         break;
1257                 }
1258         }
1259 }
1260
1261 /*****************************************************************************
1262  * PositionInfoView::ResizeToPreferred
1263  *****************************************************************************/
1264 void
1265 PositionInfoView::ResizeToPreferred()
1266 {
1267         float width, height;
1268         GetPreferredSize( &width, &height );
1269         ResizeTo( width, height );
1270 }
1271
1272 /*****************************************************************************
1273  * PositionInfoView::GetPreferredSize
1274  *****************************************************************************/
1275 void
1276 PositionInfoView::GetPreferredSize( float* width, float* height )
1277 {
1278         if ( width && height )
1279         {
1280                 *width = 5.0 + ceilf( StringWidth( "0:00:00" ) ) + 5.0;
1281                 font_height fh;
1282                 GetFontHeight( &fh );
1283                 *height = 3.0 + ceilf( fh.ascent ) + 3.0;
1284                 fStackedWidthCache = *width * 1.2;
1285                 fStackedHeightCache = *height * 2.7;
1286         }
1287 }
1288
1289 /*****************************************************************************
1290  * PositionInfoView::Pulse
1291  *****************************************************************************/
1292 void
1293 PositionInfoView::Pulse()
1294 {
1295         // allow for Pulse frequency to be higher, MediaControlView needs it
1296         bigtime_t now = system_time();
1297         if ( now - fLastPulseUpdate > 900000 )
1298         {
1299 #if 0
1300                 int32 index, size;
1301                 p_intf->p_sys->p_wrapper->GetPlaylistInfo( index, size );
1302                 SetFile( index + 1, size );
1303                 p_intf->p_sys->p_wrapper->TitleInfo( index, size );
1304                 SetTitle( index, size );
1305                 p_intf->p_sys->p_wrapper->ChapterInfo( index, size );
1306                 SetChapter( index, size );
1307                 SetTime( p_intf->p_sys->p_wrapper->GetTimeAsString() );
1308                 fLastPulseUpdate = now;
1309 #endif
1310         }
1311 }
1312
1313 /*****************************************************************************
1314  * PositionInfoView::GetBigPreferredSize
1315  *****************************************************************************/
1316 void
1317 PositionInfoView::GetBigPreferredSize( float* width, float* height )
1318 {
1319         if ( width && height )
1320         {
1321                 *width = fStackedWidthCache;
1322                 *height = fStackedHeightCache;
1323         }
1324 }
1325
1326 /*****************************************************************************
1327  * PositionInfoView::SetMode
1328  *****************************************************************************/
1329 void
1330 PositionInfoView::SetMode( uint32 mode )
1331 {
1332         if ( fMode != mode )
1333         {
1334                 fMode = mode;
1335                 _InvalidateContents();
1336         }
1337 }
1338
1339 /*****************************************************************************
1340  * PositionInfoView::SetFile
1341  *****************************************************************************/
1342 void
1343 PositionInfoView::SetFile( int32 index, int32 size )
1344 {
1345         if ( fCurrentFileIndex != index || fCurrentFileSize != size )
1346         {
1347                 fCurrentFileIndex = index;
1348                 fCurrentFileSize = size;
1349                 _InvalidateContents();
1350         }
1351 }
1352
1353 /*****************************************************************************
1354  * PositionInfoView::SetTitle
1355  *****************************************************************************/
1356 void
1357 PositionInfoView::SetTitle( int32 index, int32 size )
1358 {
1359         if ( fCurrentTitleIndex != index || fCurrentFileSize != size )
1360         {
1361                 fCurrentTitleIndex = index;
1362                 fCurrentTitleSize = size;
1363                 _InvalidateContents();
1364         }
1365 }
1366
1367 /*****************************************************************************
1368  * PositionInfoView::SetChapter
1369  *****************************************************************************/
1370 void
1371 PositionInfoView::SetChapter( int32 index, int32 size )
1372 {
1373         if ( fCurrentChapterIndex != index || fCurrentFileSize != size )
1374         {
1375                 fCurrentChapterIndex = index;
1376                 fCurrentChapterSize = size;
1377                 _InvalidateContents();
1378         }
1379 }
1380
1381 /*****************************************************************************
1382  * PositionInfoView::SetTime
1383  *****************************************************************************/
1384 void
1385 PositionInfoView::SetTime( int32 seconds )
1386 {
1387         if ( fSeconds != seconds )
1388         {
1389                 if ( seconds >= 0 )
1390                 {
1391                         int32 minutes = seconds / 60;
1392                         int32 hours = minutes / 60;
1393                         seconds -= minutes * 60 - hours * 60 * 60;
1394                         minutes -= hours * 60;
1395                         fTimeString.SetTo( "" );
1396                         fTimeString << hours << ":" << minutes << ":" << seconds;
1397                 }
1398                 else
1399                         fTimeString.SetTo( "-:--:--" );
1400
1401                 fSeconds = seconds;
1402                 _InvalidateContents();
1403         }
1404 }
1405
1406 /*****************************************************************************
1407  * PositionInfoView::SetTime
1408  *****************************************************************************/
1409 void
1410 PositionInfoView::SetTime( const char* string )
1411 {
1412         fTimeString.SetTo( string );
1413         _InvalidateContents();
1414 }
1415
1416 /*****************************************************************************
1417  * PositionInfoView::_InvalidateContents
1418  *****************************************************************************/
1419 void
1420 PositionInfoView::_InvalidateContents( uint32 which )
1421 {
1422         BRect r( Bounds() );
1423         r.InsetBy( 2.0, 2.0 );
1424         Invalidate( r );
1425 }
1426
1427 /*****************************************************************************
1428  * PositionInfoView::_InvalidateContents
1429  *****************************************************************************/
1430 void
1431 PositionInfoView::_MakeString( BString& into, int32 index, int32 maxIndex ) const
1432 {
1433         into = "";
1434         if ( index >= 0 && maxIndex >= 0 )
1435                 into << index;
1436         else
1437                 into << "-";
1438         into << "/";
1439         if ( maxIndex >= 0 )
1440                 into << maxIndex;
1441         else
1442                 into << "-";
1443 }