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