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