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