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