]> git.sesse.net Git - vlc/blob - modules/gui/beos/MediaControlView.cpp
contrib: fix link flags for live555 on WinCE
[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             fPlayPause->SetPlaying();
320             break;
321         case PAUSE_S:
322             fPlayPause->SetPaused();
323             break;
324         default:
325             fPlayPause->SetStopped();
326             break;
327     }
328     if (rate != fCurrentRate)
329     {
330         fCurrentRate = rate;
331         if ( rate < INPUT_RATE_DEFAULT )
332         {
333             // TODO: ...
334         }
335     }
336 }
337
338 // SetEnabled
339 void
340 MediaControlView::SetEnabled(bool enabled)
341 {
342     if( ( enabled && fIsEnabled ) ||
343         ( !enabled && !fIsEnabled ) )
344     {
345         /* do not redraw if it is not necessary */
346         return;
347     }
348  
349     if( LockLooper() )
350     {
351         fSkipBack->SetEnabled( enabled );
352         fPlayPause->SetEnabled( enabled );
353         fSkipForward->SetEnabled( enabled );
354         fStop->SetEnabled( enabled );
355         fMute->SetEnabled( enabled );
356         fVolumeSlider->SetEnabled( enabled );
357         fSeekSlider->SetEnabled( enabled );
358         fRewind->SetEnabled( enabled );
359         fForward->SetEnabled( enabled );
360         UnlockLooper();
361         fIsEnabled = enabled;
362     }
363 }
364
365 // SetAudioEnabled
366 void
367 MediaControlView::SetAudioEnabled(bool enabled)
368 {
369     fMute->SetEnabled(enabled);
370     fVolumeSlider->SetEnabled(enabled);
371 }
372
373 // GetVolume
374 uint32
375 MediaControlView::GetVolume() const
376 {
377     return fVolumeSlider->Value();
378 }
379
380 // SetSkippable
381 void
382 MediaControlView::SetSkippable(bool backward, bool forward)
383 {
384     fSkipBack->SetEnabled(backward);
385     fSkipForward->SetEnabled(forward);
386 }
387
388 // SetMuted
389 void
390 MediaControlView::SetMuted(bool mute)
391 {
392     fVolumeSlider->SetMuted(mute);
393 }
394
395 // _LayoutControls
396 void
397 MediaControlView::_LayoutControls(BRect frame) const
398 {
399     // seek slider
400     BRect r(frame);
401     // calculate absolutly minimal width
402     float minWidth = fSkipBack->Bounds().Width();
403 //    minWidth += fRewind->Bounds().Width();
404     minWidth += fStop->Bounds().Width();
405     minWidth += fPlayPause->Bounds().Width();
406 //    minWidth += fForward->Bounds().Width();
407     minWidth += fSkipForward->Bounds().Width();
408     minWidth += fMute->Bounds().Width();
409     minWidth += VOLUME_MIN_WIDTH;
410     
411     // layout time slider and info view
412     float width, height;
413     fPositionInfo->GetBigPreferredSize( &width, &height );
414     float ratio = width / height;
415     width = r.Height() * ratio;
416     if (frame.Width() - minWidth - MIN_SPACE >= width
417               && frame.Height() >= height)
418     {
419         r.right = r.left + width;
420         fPositionInfo->SetMode(PositionInfoView::MODE_BIG);
421         _LayoutControl(fPositionInfo, r, true, true);
422         frame.left = r.right + MIN_SPACE;
423         r.left = frame.left;
424         r.right = frame.right;
425     //    r.bottom = r.top + r.Height() / 2.0 - MIN_SPACE / 2.0;
426         r.bottom = r.top + fSeekSlider->Bounds().Height();
427         _LayoutControl(fSeekSlider, r, true);
428     }
429     else
430     {
431         fPositionInfo->GetPreferredSize( &width, &height );
432         fPositionInfo->SetMode(PositionInfoView::MODE_SMALL);
433         fPositionInfo->ResizeTo(width, height);
434         r.bottom = r.top + r.Height() / 2.0 - MIN_SPACE / 2.0;
435         r.right = r.left + fPositionInfo->Bounds().Width();
436         _LayoutControl(fPositionInfo, r, true );
437         r.left = r.right + MIN_SPACE;
438         r.right = frame.right;
439         _LayoutControl(fSeekSlider, r, true);
440     }
441     float currentWidth = frame.Width();
442     float space = (currentWidth - minWidth) / 6.0;//8.0;
443     // apply weighting
444     space = MIN_SPACE + (space - MIN_SPACE) / VOLUME_SLIDER_LAYOUT_WEIGHT;
445     // layout controls with "space" inbetween
446     r.left = frame.left;
447     r.top = r.bottom + MIN_SPACE + 1.0;
448     r.bottom = frame.bottom;
449     // skip back
450     r.right = r.left + fSkipBack->Bounds().Width();
451     _LayoutControl(fSkipBack, r);
452     // rewind
453 //    r.left = r.right + space;
454 //    r.right = r.left + fRewind->Bounds().Width();
455 //    _LayoutControl(fRewind, r);
456     // stop
457     r.left = r.right + space;
458     r.right = r.left + fStop->Bounds().Width();
459     _LayoutControl(fStop, r);
460     // play/pause
461     r.left = r.right + space;
462     r.right = r.left + fPlayPause->Bounds().Width();
463     _LayoutControl(fPlayPause, r);
464     // forward
465 //    r.left = r.right + space;
466 //    r.right = r.left + fForward->Bounds().Width();
467 //    _LayoutControl(fForward, r);
468     // skip forward
469     r.left = r.right + space;
470     r.right = r.left + fSkipForward->Bounds().Width();
471     _LayoutControl(fSkipForward, r);
472     // speaker icon
473     r.left = r.right + space + space;
474     r.right = r.left + fMute->Bounds().Width();
475     _LayoutControl(fMute, r);
476     // volume slider
477     r.left = r.right + SPEAKER_SLIDER_DIST; // keep speaker icon and volume slider attached
478     r.right = frame.right;
479     _LayoutControl(fVolumeSlider, r, true);
480 }
481
482 // _MinFrame
483 BRect
484 MediaControlView::_MinFrame() const
485 {
486     // add up width of controls along bottom (seek slider will likely adopt)
487     float minWidth = 2 * BORDER_INSET;
488     minWidth += fSkipBack->Bounds().Width() + MIN_SPACE;
489 //    minWidth += fRewind->Bounds().Width() + MIN_SPACE;
490     minWidth += fStop->Bounds().Width() + MIN_SPACE;
491     minWidth += fPlayPause->Bounds().Width() + MIN_SPACE;
492 //    minWidth += fForward->Bounds().Width() + MIN_SPACE;
493     minWidth += fSkipForward->Bounds().Width() + MIN_SPACE + MIN_SPACE;
494     minWidth += fMute->Bounds().Width() + SPEAKER_SLIDER_DIST;
495     minWidth += VOLUME_MIN_WIDTH;
496
497     // add up height of seek slider and heighest control on bottom
498     float minHeight = 2 * BORDER_INSET;
499     minHeight += fSeekSlider->Bounds().Height() + MIN_SPACE + MIN_SPACE / 2.0;
500     minHeight += fBottomControlHeight;
501     return BRect(0.0, 0.0, minWidth - 1.0, minHeight - 1.0);
502 }
503
504 // _LayoutControl
505 void
506 MediaControlView::_LayoutControl(BView* view, BRect frame,
507                                  bool resizeWidth, bool resizeHeight) const
508 {
509     if (!resizeHeight)
510         // center vertically
511         frame.top = (frame.top + frame.bottom) / 2.0 - view->Bounds().Height() / 2.0;
512     if (!resizeWidth)
513         //center horizontally
514         frame.left = (frame.left + frame.right) / 2.0 - view->Bounds().Width() / 2.0;
515     view->MoveTo(frame.LeftTop());
516     float width = resizeWidth ? frame.Width() : view->Bounds().Width();
517     float height = resizeHeight ? frame.Height() : view->Bounds().Height();
518     if (resizeWidth || resizeHeight)
519         view->ResizeTo(width, height);
520 }
521
522
523
524 /*****************************************************************************
525  * SeekSlider
526  *****************************************************************************/
527 SeekSlider::SeekSlider( intf_thread_t * _p_intf,
528                         BRect frame, const char* name, MediaControlView *owner )
529     : BControl(frame, name, NULL, NULL, B_FOLLOW_NONE,
530                B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE),
531       p_intf(_p_intf),
532       fOwner(owner),
533       fTracking(false)
534 {
535     BFont font(be_plain_font);
536     font.SetSize(9.0);
537     SetFont(&font);
538 }
539
540 SeekSlider::~SeekSlider()
541 {
542 }
543
544 /*****************************************************************************
545  * VolumeSlider::AttachedToWindow
546  *****************************************************************************/
547 void
548 SeekSlider::AttachedToWindow()
549 {
550     BControl::AttachedToWindow();
551     SetViewColor(B_TRANSPARENT_32_BIT);
552 }
553
554 /*****************************************************************************
555  * VolumeSlider::Draw
556  *****************************************************************************/
557 void
558 SeekSlider::Draw(BRect updateRect)
559 {
560     BRect r(Bounds());
561     float knobWidth2 = SEEK_SLIDER_KNOB_WIDTH / 2.0;
562     float sliderStart = (r.left + knobWidth2);
563     float sliderEnd = (r.right - knobWidth2);
564     float knobPos = sliderStart
565                     + floorf((sliderEnd - sliderStart - 1.0) * Value()
566                     / SEEKSLIDER_RANGE);
567     // draw both sides (the original from Be doesn't seem
568     // to make a difference for enabled/disabled state)
569 //    DrawBitmapAsync(fLeftSideBits, r.LeftTop());
570 //    DrawBitmapAsync(fRightSideBits, BPoint(sliderEnd + 1.0, r.top));
571     // colors for the slider area between the two bitmaps
572     rgb_color background = kBackground;//ui_color(B_PANEL_BACKGROUND_COLOR);
573     rgb_color shadow = tint_color(background, B_DARKEN_2_TINT);
574     rgb_color softShadow = tint_color(background, B_DARKEN_1_TINT);
575     rgb_color darkShadow = tint_color(background, B_DARKEN_4_TINT);
576     rgb_color midShadow = tint_color(background, B_DARKEN_3_TINT);
577     rgb_color light = tint_color(background, B_LIGHTEN_MAX_TINT);
578     rgb_color softLight = tint_color(background, B_LIGHTEN_1_TINT);
579     rgb_color green = kSeekGreen;
580     rgb_color greenShadow = kSeekGreenShadow;
581     rgb_color black = kBlack;
582     rgb_color dotGrey = midShadow;
583     rgb_color dotGreen = greenShadow;
584     // draw frame
585     _StrokeFrame(r, softShadow, softShadow, softLight, softLight);
586     r.InsetBy(1.0, 1.0);
587     _StrokeFrame(r, black, black, light, light);
588     if (IsEnabled())
589     {
590         r.InsetBy(1.0, 1.0);
591         // inner shadow
592         _StrokeFrame(r, greenShadow, greenShadow, green, green);
593         r.top++;
594         r.left++;
595         _StrokeFrame(r, greenShadow, greenShadow, green, green);
596         // inside area
597         r.InsetBy(1.0, 1.0);
598         SetHighColor(green);
599         FillRect(r);
600         // dots
601         int32 dotCount = (int32)(r.Width() / 6.0);
602         BPoint dotPos;
603         dotPos.y = r.top + 2.0;
604         SetHighColor(dotGreen);
605         for (int32 i = 0; i < dotCount; i++)
606         {
607             dotPos.x = sliderStart + i * 6.0 + 5.0;
608             StrokeLine(dotPos, BPoint(dotPos.x, dotPos.y + 6.0));
609         }
610         // slider handle
611         r.top -= 4.0;
612         r.bottom += 3.0;
613         r.left = knobPos - knobWidth2;
614         r.right = knobPos + knobWidth2;
615         // black outline
616         float handleBottomSize = 2.0;
617         float handleArrowSize = 6.0;
618         BeginLineArray(10);
619             // upper handle
620             AddLine(BPoint(r.left, r.top + handleBottomSize),
621                     BPoint(r.left, r.top), black);
622             AddLine(BPoint(r.left + 1.0, r.top),
623                     BPoint(r.right, r.top), black);
624             AddLine(BPoint(r.right, r.top + 1.0),
625                     BPoint(r.right, r.top + handleBottomSize), black);
626             AddLine(BPoint(r.right - 1.0, r.top + handleBottomSize + 1.0),
627                     BPoint(knobPos, r.top + handleArrowSize), black);
628             AddLine(BPoint(knobPos - 1.0, r.top + handleArrowSize - 1.0),
629                     BPoint(r.left + 1.0, r.top + handleBottomSize + 1.0), black);
630             // lower handle
631             AddLine(BPoint(r.left, r.bottom),
632                     BPoint(r.left, r.bottom - handleBottomSize), black);
633             AddLine(BPoint(r.left + 1.0, r.bottom - handleBottomSize - 1.0),
634                     BPoint(knobPos, r.bottom - handleArrowSize), black);
635             AddLine(BPoint(knobPos + 1.0, r.bottom - handleArrowSize + 1.0),
636                     BPoint(r.right, r.bottom - handleBottomSize), black);
637             AddLine(BPoint(r.right, r.bottom - handleBottomSize + 1.0),
638                     BPoint(r.right, r.bottom), black);
639             AddLine(BPoint(r.right - 1.0, r.bottom),
640                     BPoint(r.left + 1.0, r.bottom), black);
641         EndLineArray();
642         // inner red light and shadow lines
643         r.InsetBy(1.0, 1.0);
644         handleBottomSize--;
645         handleArrowSize -= 2.0;
646         BeginLineArray(10);
647             // upper handle
648             AddLine(BPoint(r.left, r.top + handleBottomSize),
649                     BPoint(r.left, r.top), kSeekRedLight);
650             AddLine(BPoint(r.left + 1.0, r.top),
651                     BPoint(r.right, r.top), kSeekRedLight);
652             AddLine(BPoint(r.right, r.top + 1.0),
653                     BPoint(r.right, r.top + handleBottomSize), kSeekRedShadow);
654             AddLine(BPoint(r.right - 1.0, r.top + handleBottomSize + 1.0),
655                     BPoint(knobPos, r.top + handleArrowSize), kSeekRedShadow);
656             AddLine(BPoint(knobPos - 1.0, r.top + handleArrowSize - 1.0),
657                     BPoint(r.left + 1.0, r.top + handleBottomSize + 1.0), kSeekRedLight);
658             // lower handle
659             AddLine(BPoint(r.left, r.bottom),
660                     BPoint(r.left, r.bottom - handleBottomSize), kSeekRedLight);
661             AddLine(BPoint(r.left + 1.0, r.bottom - handleBottomSize - 1.0),
662                     BPoint(knobPos, r.bottom - handleArrowSize), kSeekRedLight);
663             AddLine(BPoint(knobPos + 1.0, r.bottom - handleArrowSize + 1.0),
664                     BPoint(r.right, r.bottom - handleBottomSize), kSeekRedShadow);
665             AddLine(BPoint(r.right, r.bottom - handleBottomSize + 1.0),
666                     BPoint(r.right, r.bottom), kSeekRedShadow);
667             AddLine(BPoint(r.right - 1.0, r.bottom),
668                     BPoint(r.left + 1.0, r.bottom), kSeekRedShadow);
669         EndLineArray();
670         // fill rest of handles with red
671         SetHighColor(kSeekRed);
672         r.InsetBy(1.0, 1.0);
673         handleArrowSize -= 2.0;
674         BPoint arrow[3];
675         // upper handle arrow
676         arrow[0].x = r.left;
677         arrow[0].y = r.top;
678         arrow[1].x = r.right;
679         arrow[1].y = r.top;
680         arrow[2].x = knobPos;
681         arrow[2].y = r.top + handleArrowSize;
682         FillPolygon(arrow, 3);
683         // lower handle arrow
684         arrow[0].x = r.left;
685         arrow[0].y = r.bottom;
686         arrow[1].x = r.right;
687         arrow[1].y = r.bottom;
688         arrow[2].x = knobPos;
689         arrow[2].y = r.bottom - handleArrowSize;
690         FillPolygon(arrow, 3);
691     }
692     else
693     {
694         r.InsetBy(1.0, 1.0);
695         _StrokeFrame(r, darkShadow, darkShadow, darkShadow, darkShadow);
696         r.InsetBy(1.0, 1.0);
697         _StrokeFrame(r, darkShadow, darkShadow, darkShadow, darkShadow);
698         r.InsetBy(1.0, 1.0);
699         SetHighColor(darkShadow);
700         SetLowColor(shadow);
701         // stripes
702         float width = floorf(StringWidth(DISABLED_SEEK_MESSAGE));
703         float textPos = r.left + r.Width() / 2.0 - width / 2.0;
704         pattern stripes = {{ 0xc7, 0x8f, 0x1f, 0x3e, 0x7c, 0xf8, 0xf1, 0xe3 }};
705         BRect stripesRect(r);
706         stripesRect.right = textPos - 5.0;
707         FillRect(stripesRect, stripes);
708         stripesRect.left = textPos + width + 3.0;
709         stripesRect.right = r.right;
710         FillRect(stripesRect, stripes);
711         // info text
712         r.left = textPos - 4.0;
713         r.right = textPos + width + 2.0;
714         FillRect(r);
715         SetHighColor(shadow);
716         SetLowColor(darkShadow);
717         font_height fh;
718         GetFontHeight(&fh);
719         DrawString(DISABLED_SEEK_MESSAGE, BPoint(textPos, r.top + ceilf(fh.ascent) - 1.0));
720     }
721 }
722
723 /*****************************************************************************
724  * SeekSlider::MouseDown
725  *****************************************************************************/
726 void
727 SeekSlider::MouseDown(BPoint where)
728 {
729     if (IsEnabled() && Bounds().Contains(where))
730     {
731         SetValue(_ValueFor(where.x));
732         fTracking = true;
733         SetMouseEventMask(B_POINTER_EVENTS, B_LOCK_WINDOW_FOCUS);
734     }
735 }
736
737 /*****************************************************************************
738  * SeekSlider::MouseMoved
739  *****************************************************************************/
740 void
741 SeekSlider::MouseMoved(BPoint where, uint32 code, const BMessage* dragMessage)
742 {
743     if (fTracking)
744     {
745         SetValue(_ValueFor(where.x));
746     }
747 }
748
749 /*****************************************************************************
750  * SeekSlider::MouseUp
751  *****************************************************************************/
752 void
753 SeekSlider::MouseUp(BPoint where)
754 {
755     if (fTracking)
756     {
757         fTracking = false;
758         input_thread_t * p_input;
759         p_input = (input_thread_t *)
760             vlc_object_find( p_intf, VLC_OBJECT_INPUT, FIND_ANYWHERE );
761
762         if( p_input )
763         {
764             var_SetFloat( p_input, "position",
765                           (float) Value() / SEEKSLIDER_RANGE );
766             vlc_object_release( p_input );
767         }
768     }
769 }
770
771 /*****************************************************************************
772  * SeekSlider::ResizeToPreferred
773  *****************************************************************************/
774 void
775 SeekSlider::ResizeToPreferred()
776 {
777     float width = 15.0 + StringWidth(DISABLED_SEEK_MESSAGE) + 15.0;
778     ResizeTo(width, 17.0);
779 }
780
781 /*****************************************************************************
782  * SeekSlider::SetPosition
783  *****************************************************************************/
784 void
785 SeekSlider::SetPosition(float position)
786 {
787     if ( LockLooper() )
788     {
789         if( !fTracking )
790         {
791             SetValue( SEEKSLIDER_RANGE * position );
792         }
793         UnlockLooper();
794     }
795 }
796
797 /*****************************************************************************
798  * SeekSlider::_ValueFor
799  *****************************************************************************/
800 int32
801 SeekSlider::_ValueFor(float xPos) const
802 {
803     BRect r(Bounds());
804     float knobWidth2 = SEEK_SLIDER_KNOB_WIDTH / 2.0;
805     float sliderStart = (r.left + knobWidth2);
806     float sliderEnd = (r.right - knobWidth2);
807     int32 value =  (int32)(((xPos - sliderStart) * SEEKSLIDER_RANGE)
808                   / (sliderEnd - sliderStart - 1.0));
809     if (value < 0)
810         value = 0;
811     if (value > SEEKSLIDER_RANGE)
812         value = SEEKSLIDER_RANGE;
813     return value;
814 }
815
816 /*****************************************************************************
817  * SeekSlider::_StrokeFrame
818  *****************************************************************************/
819 void
820 SeekSlider::_StrokeFrame(BRect r, rgb_color left, rgb_color top,
821                          rgb_color right, rgb_color bottom)
822 {
823     BeginLineArray(4);
824         AddLine(BPoint(r.left, r.bottom), BPoint(r.left, r.top), left);
825         AddLine(BPoint(r.left + 1.0, r.top), BPoint(r.right, r.top), top);
826         AddLine(BPoint(r.right, r.top + 1.0), BPoint(r.right, r.bottom), right);
827         AddLine(BPoint(r.right - 1.0, r.bottom), BPoint(r.left + 1.0, r.bottom), bottom);
828     EndLineArray();
829 }
830
831 /*****************************************************************************
832  * VolumeSlider
833  *****************************************************************************/
834 VolumeSlider::VolumeSlider(BRect frame, const char* name, int32 minValue, int32 maxValue,
835                            BMessage* message, BHandler* target)
836     : BControl(frame, name, NULL, message, B_FOLLOW_NONE,
837                B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE),
838       fLeftSideBits(NULL),
839       fRightSideBits(NULL),
840       fKnobBits(NULL),
841       fTracking(false),
842       fMuted(false),
843       fMinValue(minValue),
844       fMaxValue(maxValue)
845 {
846     SetTarget(target);
847
848     // create bitmaps
849     BRect r(BPoint(0.0, 0.0), kVolumeSliderBitmapSize);
850     fLeftSideBits = new BBitmap(r, B_CMAP8);
851     fRightSideBits = new BBitmap(r, B_CMAP8);
852     r.Set(0.0, 0.0, kVolumeSliderKnobBitmapSize.x, kVolumeSliderKnobBitmapSize.y);
853     fKnobBits = new BBitmap(r, B_CMAP8);
854
855     _MakeBitmaps();
856 }
857
858 /*****************************************************************************
859  * VolumeSlider destructor
860  *****************************************************************************/
861 VolumeSlider::~VolumeSlider()
862 {
863     delete fLeftSideBits;
864     delete fRightSideBits;
865     delete fKnobBits;
866 }
867
868 /*****************************************************************************
869  * VolumeSlider::AttachedToWindow
870  *****************************************************************************/
871 void
872 VolumeSlider::AttachedToWindow()
873 {
874     BControl::AttachedToWindow();
875     SetViewColor(B_TRANSPARENT_32_BIT);
876 }
877
878 /*****************************************************************************
879  * VolumeSlider::SetValue
880  *****************************************************************************/
881 void
882 VolumeSlider::SetValue(int32 value)
883 {
884     if (value != Value())
885     {
886         BControl::SetValue(value);
887         Invoke();
888     }
889 }
890
891 /*****************************************************************************
892  * VolumeSlider::SetEnabled
893  *****************************************************************************/
894 void
895 VolumeSlider::SetEnabled(bool enable)
896 {
897     if (enable != IsEnabled())
898     {
899         BControl::SetEnabled(enable);
900         _MakeBitmaps();
901         Invalidate();
902     }
903 }
904
905 /*****************************************************************************
906  * VolumeSlider::Draw
907  *****************************************************************************/
908 void
909 VolumeSlider::Draw(BRect updateRect)
910 {
911     if (IsValid())
912     {
913         BRect r(Bounds());
914         float sliderSideWidth = kVolumeSliderBitmapWidth;
915         float sliderStart = (r.left + sliderSideWidth);
916         float sliderEnd = (r.right - sliderSideWidth);
917         float knobPos = sliderStart
918                         + (sliderEnd - sliderStart - 1.0) * (Value() - fMinValue)
919                         / (fMaxValue - fMinValue);
920         // draw both sides (the original from Be doesn't seem
921         // to make a difference for enabled/disabled state)
922         DrawBitmapAsync(fLeftSideBits, r.LeftTop());
923         DrawBitmapAsync(fRightSideBits, BPoint(sliderEnd + 1.0, r.top));
924         // colors for the slider area between the two bitmaps
925         rgb_color background = kBackground;//ui_color(B_PANEL_BACKGROUND_COLOR);
926         rgb_color shadow = tint_color(background, B_DARKEN_2_TINT);
927         rgb_color softShadow = tint_color(background, B_DARKEN_1_TINT);
928         rgb_color darkShadow = tint_color(background, B_DARKEN_4_TINT);
929         rgb_color midShadow = tint_color(background, B_DARKEN_3_TINT);
930         rgb_color light = tint_color(background, B_LIGHTEN_MAX_TINT);
931         rgb_color softLight = tint_color(background, B_LIGHTEN_1_TINT);
932         rgb_color green = kGreen;
933         rgb_color greenShadow = kGreenShadow;
934         rgb_color black = kBlack;
935         rgb_color dotGrey = midShadow;
936         rgb_color dotGreen = greenShadow;
937         // make dimmed version of colors if we're disabled
938         if (!IsEnabled())
939         {
940             shadow = (rgb_color){ 200, 200, 200, 255 };
941             softShadow = dimmed_color_cmap8(softShadow, background, DIM_LEVEL);
942             darkShadow = dimmed_color_cmap8(darkShadow, background, DIM_LEVEL);
943             midShadow = shadow;
944             light = dimmed_color_cmap8(light, background, DIM_LEVEL);
945             softLight = dimmed_color_cmap8(softLight, background, DIM_LEVEL);
946             green = dimmed_color_cmap8(green, background, DIM_LEVEL);
947             greenShadow = dimmed_color_cmap8(greenShadow, background, DIM_LEVEL);
948             black = dimmed_color_cmap8(black, background, DIM_LEVEL);
949             dotGreen = dotGrey;
950         }
951         else if (fMuted)
952         {
953             green = tint_color(kBackground, B_DARKEN_3_TINT);
954             greenShadow = tint_color(kBackground, B_DARKEN_4_TINT);
955             dotGreen = greenShadow;
956         }
957         // draw slider edges between bitmaps
958         BeginLineArray(7);
959             AddLine(BPoint(sliderStart, r.top),
960                     BPoint(sliderEnd, r.top), softShadow);
961             AddLine(BPoint(sliderStart, r.bottom),
962                     BPoint(sliderEnd, r.bottom), softLight);
963             r.InsetBy(0.0, 1.0);
964             AddLine(BPoint(sliderStart, r.top),
965                     BPoint(sliderEnd, r.top), black);
966             AddLine(BPoint(sliderStart, r.bottom),
967                     BPoint(sliderEnd, r.bottom), light);
968             r.top++;
969             AddLine(BPoint(sliderStart, r.top),
970                     BPoint(knobPos, r.top), greenShadow);
971             AddLine(BPoint(knobPos, r.top),
972                     BPoint(sliderEnd, r.top), midShadow);
973             r.top++;
974             AddLine(BPoint(sliderStart, r.top),
975                     BPoint(knobPos, r.top), greenShadow);
976         EndLineArray();
977         // fill rest inside of slider
978         r.InsetBy(0.0, 1.0);
979         r.left = sliderStart;
980         r.right = knobPos;
981         SetHighColor(green);
982         FillRect(r, B_SOLID_HIGH);
983         r.left = knobPos + 1.0;
984         r.right = sliderEnd;
985         r.top -= 1.0;
986         SetHighColor(shadow);
987         FillRect(r, B_SOLID_HIGH);
988         // draw little dots inside
989         int32 dotCount = (int32)((sliderEnd - sliderStart) / 5.0);
990         BPoint dotPos;
991         dotPos.y = r.top + 4.0;
992         for (int32 i = 0; i < dotCount; i++)
993         {
994             dotPos.x = sliderStart + i * 5.0 + 4.0;
995             SetHighColor(dotPos.x < knobPos ? dotGreen : dotGrey);
996             StrokeLine(dotPos, BPoint(dotPos.x, dotPos.y + 1.0));
997         }
998         // draw knob
999         r.top -= 1.0;
1000         SetDrawingMode(B_OP_OVER); // part of knob is transparent
1001         DrawBitmapAsync(fKnobBits, BPoint(knobPos - kVolumeSliderKnobWidth / 2, r.top));
1002     }
1003 }
1004
1005 /*****************************************************************************
1006  * VolumeSlider::MouseDown
1007  *****************************************************************************/
1008 void
1009 VolumeSlider::MouseDown(BPoint where)
1010 {
1011     if (Bounds().Contains(where) && IsEnabled())
1012     {
1013         fTracking = true;
1014         SetValue(_ValueFor(where.x));
1015         SetMouseEventMask(B_POINTER_EVENTS, B_LOCK_WINDOW_FOCUS);
1016     }
1017 }
1018
1019 /*****************************************************************************
1020  * VolumeSlider::MouseMoved
1021  *****************************************************************************/
1022 void
1023 VolumeSlider::MouseMoved(BPoint where, uint32 transit, const BMessage* dragMessage)
1024 {
1025     if (fTracking)
1026         SetValue(_ValueFor(where.x));
1027 }
1028
1029 /*****************************************************************************
1030  * VolumeSlider::MouseUp
1031  *****************************************************************************/
1032 void
1033 VolumeSlider::MouseUp(BPoint where)
1034 {
1035     fTracking = false;
1036 }
1037
1038
1039 /*****************************************************************************
1040  * VolumeSlider::IsValid
1041  *****************************************************************************/
1042 bool
1043 VolumeSlider::IsValid() const
1044 {
1045     return (fLeftSideBits && fLeftSideBits->IsValid()
1046             && fRightSideBits && fRightSideBits->IsValid()
1047             && fKnobBits && fKnobBits->IsValid());
1048 }
1049
1050 /*****************************************************************************
1051  * VolumeSlider::SetMuted
1052  *****************************************************************************/
1053 void
1054 VolumeSlider::SetMuted(bool mute)
1055 {
1056     if (mute != fMuted)
1057     {
1058         fMuted = mute;
1059         _MakeBitmaps();
1060         Invalidate();
1061     }
1062 }
1063
1064 /*****************************************************************************
1065  * VolumeSlider::_MakeBitmaps
1066  *****************************************************************************/
1067 void
1068 VolumeSlider::_MakeBitmaps()
1069 {
1070     if (IsValid())
1071     {
1072         // left side of slider
1073         memcpy(fLeftSideBits->Bits(), kVolumeSliderLeftBitmapBits,
1074                fLeftSideBits->BitsLength());
1075         // right side of slider
1076         memcpy(fRightSideBits->Bits(), kVolumeSliderRightBits,
1077                fRightSideBits->BitsLength());
1078         // slider knob
1079         int32 length = fKnobBits->BitsLength();
1080         memcpy(fKnobBits->Bits(), kVolumeSliderKnobBits, length);
1081         uint8* bits = (uint8*)fKnobBits->Bits();
1082         // black was used in the knob to represent transparency
1083         // use screen to get index for the "transarent" color used in the bitmap
1084         BScreen screen(B_MAIN_SCREEN_ID);
1085         uint8 blackIndex = screen.IndexForColor(kBlack);
1086         // replace black index with transparent index
1087         for (int32 i = 0; i < length; i++)
1088             if (bits[i] == blackIndex)
1089                 bits[i] = B_TRANSPARENT_MAGIC_CMAP8;
1090
1091         if (!IsEnabled())
1092         {
1093             // make ghosted versions of the bitmaps
1094             dim_bitmap(fLeftSideBits, kBackground, DIM_LEVEL);
1095             dim_bitmap(fRightSideBits, kBackground, DIM_LEVEL);
1096             dim_bitmap(fKnobBits, kBackground, DIM_LEVEL);
1097         }
1098         else if (fMuted)
1099         {
1100             // replace green color (and shadow) in left slider side
1101             bits = (uint8*)fLeftSideBits->Bits();
1102             length = fLeftSideBits->BitsLength();
1103             uint8 greenIndex = screen.IndexForColor(kGreen);
1104             uint8 greenShadowIndex = screen.IndexForColor(kGreenShadow);
1105             rgb_color shadow = tint_color(kBackground, B_DARKEN_3_TINT);
1106             rgb_color midShadow = tint_color(kBackground, B_DARKEN_4_TINT);
1107             uint8 replaceIndex = screen.IndexForColor(shadow);
1108             uint8 replaceShadowIndex = screen.IndexForColor(midShadow);
1109             for (int32 i = 0; i < length; i++)
1110             {
1111                 if (bits[i] == greenIndex)
1112                     bits[i] = replaceIndex;
1113                 else if (bits[i] == greenShadowIndex)
1114                     bits[i] = replaceShadowIndex;
1115             }
1116         }
1117     }
1118 }
1119
1120 /*****************************************************************************
1121  * VolumeSlider::_ValueFor
1122  *****************************************************************************/
1123 int32
1124 VolumeSlider::_ValueFor(float xPos) const
1125 {
1126     BRect r(Bounds());
1127     float sliderStart = (r.left + kVolumeSliderBitmapWidth);
1128     float sliderEnd = (r.right - kVolumeSliderBitmapWidth);
1129     int32 value =  fMinValue + (int32)(((xPos - sliderStart) * (fMaxValue - fMinValue))
1130                   / (sliderEnd - sliderStart - 1.0));
1131     if (value < fMinValue)
1132         value = fMinValue;
1133     if (value > fMaxValue)
1134         value = fMaxValue;
1135     return value;
1136 }
1137
1138 /*****************************************************************************
1139  * PositionInfoView::PositionInfoView
1140  *****************************************************************************/
1141 PositionInfoView::PositionInfoView( BRect frame, const char* name,
1142                                     intf_thread_t * p_interface )
1143     : BView( frame, name, B_FOLLOW_NONE,
1144              B_WILL_DRAW | B_PULSE_NEEDED | B_FULL_UPDATE_ON_RESIZE ),
1145       fMode( MODE_SMALL ),
1146       fCurrentFileIndex( -1 ),
1147       fCurrentFileSize( -1 ),
1148       fCurrentTitleIndex( -1 ),
1149       fCurrentTitleSize( -1 ),
1150       fCurrentChapterIndex( -1 ),
1151       fCurrentChapterSize( -1 ),
1152       fSeconds( -1 ),
1153       fTimeString( "-:--:--" ),
1154       fLastPulseUpdate( system_time() ),
1155       fStackedWidthCache( 0.0 ),
1156       fStackedHeightCache( 0.0 )
1157 {
1158     p_intf = p_interface;
1159
1160     SetViewColor( B_TRANSPARENT_32_BIT );
1161     SetLowColor( kBlack );
1162     SetHighColor( 0, 255, 0, 255 );
1163     SetFontSize( 11.0 );
1164 }
1165
1166 /*****************************************************************************
1167  * PositionInfoView::~PositionInfoView
1168  *****************************************************************************/
1169 PositionInfoView::~PositionInfoView()
1170 {
1171 }
1172
1173 /*****************************************************************************
1174  * PositionInfoView::Draw
1175  *****************************************************************************/
1176 void
1177 PositionInfoView::Draw( BRect updateRect )
1178 {
1179     rgb_color background = ui_color( B_PANEL_BACKGROUND_COLOR );
1180     rgb_color shadow = tint_color( background, B_DARKEN_1_TINT );
1181     rgb_color darkShadow = tint_color( background, B_DARKEN_4_TINT );
1182     rgb_color light = tint_color( background, B_LIGHTEN_MAX_TINT );
1183     rgb_color softLight = tint_color( background, B_LIGHTEN_1_TINT );
1184     // frame
1185     BRect r( Bounds() );
1186     BeginLineArray( 8 );
1187         AddLine( BPoint( r.left, r.bottom ),
1188                  BPoint( r.left, r.top ), shadow );
1189         AddLine( BPoint( r.left + 1.0, r.top ),
1190                  BPoint( r.right, r.top ), shadow );
1191         AddLine( BPoint( r.right, r.top + 1.0 ),
1192                  BPoint( r.right, r.bottom ), softLight );
1193         AddLine( BPoint( r.right - 1.0, r.bottom ),
1194                  BPoint( r.left + 1.0, r.bottom ), softLight );
1195         r.InsetBy( 1.0, 1.0 );
1196         AddLine( BPoint( r.left, r.bottom ),
1197                  BPoint( r.left, r.top ), darkShadow );
1198         AddLine( BPoint( r.left + 1.0, r.top ),
1199                  BPoint( r.right, r.top ), darkShadow );
1200         AddLine( BPoint( r.right, r.top + 1.0 ),
1201                  BPoint( r.right, r.bottom ), light );
1202         AddLine( BPoint( r.right - 1.0, r.bottom ),
1203                  BPoint( r.left + 1.0, r.bottom ), light );
1204     EndLineArray();
1205     // background
1206     r.InsetBy( 1.0, 1.0 );
1207     FillRect( r, B_SOLID_LOW );
1208     // contents
1209     font_height fh;
1210     GetFontHeight( &fh );
1211     switch ( fMode )
1212     {
1213         case MODE_SMALL:
1214         {
1215             float width = StringWidth( fTimeString.String() );
1216             DrawString( fTimeString.String(),
1217                         BPoint( r.left + r.Width() / 2.0 - width / 2.0,
1218                                 r.top + r.Height() / 2.0 + fh.ascent / 2.0 - 1.0 ) );
1219             break;
1220         }
1221         case MODE_BIG:
1222         {
1223             BFont font;
1224             GetFont( &font );
1225             BFont smallFont = font;
1226             BFont bigFont = font;
1227             BFont tinyFont = font;
1228             smallFont.SetSize( r.Height() / 5.0 );
1229             bigFont.SetSize( r.Height() / 3.0 );
1230             tinyFont.SetSize( r.Height() / 7.0 );
1231             float timeHeight = r.Height() / 2.5;
1232             float height = ( r.Height() - timeHeight ) / 3.0;
1233             SetFont( &tinyFont );
1234             SetHighColor( 0, 180, 0, 255 );
1235             DrawString( _("File"), BPoint( r.left + 3.0, r.top + height ) );
1236             DrawString( _("Title"), BPoint( r.left + 3.0, r.top + 2.0 * height ) );
1237             DrawString( _("Chapter"), BPoint( r.left + 3.0, r.top + 3.0 * height ) );
1238             SetFont( &smallFont );
1239             BString helper;
1240             SetHighColor( 0, 255, 0, 255 );
1241             // file
1242             _MakeString( helper, fCurrentFileIndex, fCurrentFileSize );
1243             float width = StringWidth( helper.String() );
1244             DrawString( helper.String(), BPoint( r.right - 3.0 - width, r.top + height ) );
1245             // title
1246             _MakeString( helper, fCurrentTitleIndex, fCurrentTitleSize );
1247             width = StringWidth( helper.String() );
1248             DrawString( helper.String(), BPoint( r.right - 3.0 - width, r.top + 2.0 * height ) );
1249             // chapter
1250             _MakeString( helper, fCurrentChapterIndex, fCurrentChapterSize );
1251             width = StringWidth( helper.String() );
1252             DrawString( helper.String(), BPoint( r.right - 3.0 - width, r.top + 3.0 * height ) );
1253             // time
1254             SetFont( &bigFont );
1255             width = StringWidth( fTimeString.String() );
1256             DrawString( fTimeString.String(),
1257                         BPoint( r.left + r.Width() / 2.0 - width / 2.0,
1258                                 r.bottom - 3.0 ) );
1259             break;
1260         }
1261     }
1262 }
1263
1264 /*****************************************************************************
1265  * PositionInfoView::ResizeToPreferred
1266  *****************************************************************************/
1267 void
1268 PositionInfoView::ResizeToPreferred()
1269 {
1270     float width, height;
1271     GetPreferredSize( &width, &height );
1272     ResizeTo( width, height );
1273 }
1274
1275 /*****************************************************************************
1276  * PositionInfoView::GetPreferredSize
1277  *****************************************************************************/
1278 void
1279 PositionInfoView::GetPreferredSize( float* width, float* height )
1280 {
1281     if ( width && height )
1282     {
1283         *width = 5.0 + ceilf( StringWidth( "0:00:00" ) ) + 5.0;
1284         font_height fh;
1285         GetFontHeight( &fh );
1286         *height = 3.0 + ceilf( fh.ascent ) + 3.0;
1287         fStackedWidthCache = *width * 1.2;
1288         fStackedHeightCache = *height * 2.7;
1289     }
1290 }
1291
1292 /*****************************************************************************
1293  * PositionInfoView::Pulse
1294  *****************************************************************************/
1295 void
1296 PositionInfoView::Pulse()
1297 {
1298     // allow for Pulse frequency to be higher, MediaControlView needs it
1299     bigtime_t now = system_time();
1300     if ( now - fLastPulseUpdate > 900000 )
1301     {
1302 #if 0
1303         int32 index, size;
1304         p_intf->p_sys->p_wrapper->GetPlaylistInfo( index, size );
1305         SetFile( index + 1, size );
1306         p_intf->p_sys->p_wrapper->TitleInfo( index, size );
1307         SetTitle( index, size );
1308         p_intf->p_sys->p_wrapper->ChapterInfo( index, size );
1309         SetChapter( index, size );
1310         SetTime( p_intf->p_sys->p_wrapper->GetTimeAsString() );
1311         fLastPulseUpdate = now;
1312 #endif
1313     }
1314 }
1315
1316 /*****************************************************************************
1317  * PositionInfoView::GetBigPreferredSize
1318  *****************************************************************************/
1319 void
1320 PositionInfoView::GetBigPreferredSize( float* width, float* height )
1321 {
1322     if ( width && height )
1323     {
1324         *width = fStackedWidthCache;
1325         *height = fStackedHeightCache;
1326     }
1327 }
1328
1329 /*****************************************************************************
1330  * PositionInfoView::SetMode
1331  *****************************************************************************/
1332 void
1333 PositionInfoView::SetMode( uint32 mode )
1334 {
1335     if ( fMode != mode )
1336     {
1337         fMode = mode;
1338         _InvalidateContents();
1339     }
1340 }
1341
1342 /*****************************************************************************
1343  * PositionInfoView::SetFile
1344  *****************************************************************************/
1345 void
1346 PositionInfoView::SetFile( int32 index, int32 size )
1347 {
1348     if ( fCurrentFileIndex != index || fCurrentFileSize != size )
1349     {
1350         fCurrentFileIndex = index;
1351         fCurrentFileSize = size;
1352         _InvalidateContents();
1353     }
1354 }
1355
1356 /*****************************************************************************
1357  * PositionInfoView::SetTitle
1358  *****************************************************************************/
1359 void
1360 PositionInfoView::SetTitle( int32 index, int32 size )
1361 {
1362     if ( fCurrentTitleIndex != index || fCurrentFileSize != size )
1363     {
1364         fCurrentTitleIndex = index;
1365         fCurrentTitleSize = size;
1366         _InvalidateContents();
1367     }
1368 }
1369
1370 /*****************************************************************************
1371  * PositionInfoView::SetChapter
1372  *****************************************************************************/
1373 void
1374 PositionInfoView::SetChapter( int32 index, int32 size )
1375 {
1376     if ( fCurrentChapterIndex != index || fCurrentFileSize != size )
1377     {
1378         fCurrentChapterIndex = index;
1379         fCurrentChapterSize = size;
1380         _InvalidateContents();
1381     }
1382 }
1383
1384 /*****************************************************************************
1385  * PositionInfoView::SetTime
1386  *****************************************************************************/
1387 void
1388 PositionInfoView::SetTime( int32 seconds )
1389 {
1390     if ( fSeconds != seconds )
1391     {
1392         if ( seconds >= 0 )
1393         {
1394             int32 minutes = seconds / 60;
1395             int32 hours = minutes / 60;
1396             seconds -= minutes * 60 - hours * 60 * 60;
1397             minutes -= hours * 60;
1398             fTimeString.SetTo( "" );
1399             fTimeString << hours << ":" << minutes << ":" << seconds;
1400         }
1401         else
1402             fTimeString.SetTo( "-:--:--" );
1403
1404         fSeconds = seconds;
1405         _InvalidateContents();
1406     }
1407 }
1408
1409 /*****************************************************************************
1410  * PositionInfoView::SetTime
1411  *****************************************************************************/
1412 void
1413 PositionInfoView::SetTime( const char* string )
1414 {
1415     fTimeString.SetTo( string );
1416     _InvalidateContents();
1417 }
1418
1419 /*****************************************************************************
1420  * PositionInfoView::_InvalidateContents
1421  *****************************************************************************/
1422 void
1423 PositionInfoView::_InvalidateContents( uint32 which )
1424 {
1425     BRect r( Bounds() );
1426     r.InsetBy( 2.0, 2.0 );
1427     Invalidate( r );
1428 }
1429
1430 /*****************************************************************************
1431  * PositionInfoView::_InvalidateContents
1432  *****************************************************************************/
1433 void
1434 PositionInfoView::_MakeString( BString& into, int32 index, int32 maxIndex ) const
1435 {
1436     into = "";
1437     if ( index >= 0 && maxIndex >= 0 )
1438         into << index;
1439     else
1440         into << "-";
1441     into << "/";
1442     if ( maxIndex >= 0 )
1443         into << maxIndex;
1444     else
1445         into << "-";
1446 }