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