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