1 /*****************************************************************************
2 * MediaControlView.cpp: beos interface
3 *****************************************************************************
4 * Copyright (C) 1999, 2000, 2001 the VideoLAN team
7 * Authors: Tony Castley <tony@castley.net>
8 * Stephan Aßmus <stippi@yellowbites.com>
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.
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.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
23 *****************************************************************************/
26 #include <InterfaceKit.h>
32 #include <vlc_interface.h>
35 #include <audio_output.h>
38 /* BeOS interface headers */
40 #include "DrawingTidbits.h"
41 #include "InterfaceWindow.h"
43 #include "TransportButton.h"
44 #include "ListViews.h"
45 #include "MediaControlView.h"
47 #define BORDER_INSET 6.0
49 #define SPEAKER_SLIDER_DIST 6.0
50 #define VOLUME_MIN_WIDTH 70.0
52 #define VOLUME_SLIDER_LAYOUT_WEIGHT 2.0
53 #define SEEK_SLIDER_KNOB_WIDTH 8.0
55 // slider colors are hardcoded here, because that's just
56 // what they currently are within those bitmaps
57 const rgb_color kGreen = (rgb_color){ 152, 203, 152, 255 };
58 const rgb_color kGreenShadow = (rgb_color){ 102, 152, 102, 255 };
59 const rgb_color kBackground = (rgb_color){ 216, 216, 216, 255 };
60 const rgb_color kSeekGreen = (rgb_color){ 171, 221, 161, 255 };
61 const rgb_color kSeekGreenShadow = (rgb_color){ 144, 186, 136, 255 };
62 const rgb_color kSeekRed = (rgb_color){ 255, 0, 0, 255 };
63 const rgb_color kSeekRedLight = (rgb_color){ 255, 152, 152, 255 };
64 const rgb_color kSeekRedShadow = (rgb_color){ 178, 0, 0, 255 };
66 #define DISABLED_SEEK_MESSAGE _("Drop files to play")
67 #define SEEKSLIDER_RANGE 2048
73 MSG_SKIP_BACKWARDS = 'skpb',
74 MSG_SKIP_FORWARD = 'skpf',
78 MediaControlView::MediaControlView( intf_thread_t * _p_intf, BRect frame)
79 : BBox(frame, NULL, B_FOLLOW_NONE, B_WILL_DRAW | B_FRAME_EVENTS | B_PULSE_NEEDED,
82 fCurrentRate(INPUT_RATE_DEFAULT),
84 fBottomControlHeight(0.0),
87 BRect frame(0.0, 0.0, 10.0, 10.0);
90 fSeekSlider = new SeekSlider( p_intf, frame, "seek slider", this );
91 fSeekSlider->SetValue(0);
92 fSeekSlider->ResizeToPreferred();
93 AddChild( fSeekSlider );
97 frame.SetRightBottom(kSkipButtonSize);
98 fBottomControlHeight = kRewindBitmapHeight - 1.0;
99 fSkipBack = new TransportButton(frame, B_EMPTY_STRING,
101 kPressedSkipBackBitmapBits,
102 kDisabledSkipBackBitmapBits,
103 new BMessage(MSG_SKIP_BACKWARDS));
104 AddChild( fSkipBack );
107 frame.SetRightBottom(kPlayButtonSize);
108 if (fBottomControlHeight < kPlayPauseBitmapHeight - 1.0)
109 fBottomControlHeight = kPlayPauseBitmapHeight - 1.0;
110 fPlayPause = new PlayPauseButton(frame, B_EMPTY_STRING,
111 kPlayButtonBitmapBits,
112 kPressedPlayButtonBitmapBits,
113 kDisabledPlayButtonBitmapBits,
114 kPlayingPlayButtonBitmapBits,
115 kPressedPlayingPlayButtonBitmapBits,
116 kPausedPlayButtonBitmapBits,
117 kPressedPausedPlayButtonBitmapBits,
118 new BMessage(START_PLAYBACK));
120 AddChild( fPlayPause );
123 frame.SetRightBottom(kSkipButtonSize);
124 fSkipForward = new TransportButton(frame, B_EMPTY_STRING,
125 kSkipForwardBitmapBits,
126 kPressedSkipForwardBitmapBits,
127 kDisabledSkipForwardBitmapBits,
128 new BMessage(MSG_SKIP_FORWARD));
129 AddChild( fSkipForward );
132 fForward = new TransportButton(frame, B_EMPTY_STRING,
134 kPressedForwardBitmapBits,
135 kDisabledForwardBitmapBits,
136 new BMessage(MSG_FORWARD));
137 // AddChild( fForward );
140 fRewind = new TransportButton(frame, B_EMPTY_STRING,
142 kPressedRewindBitmapBits,
143 kDisabledRewindBitmapBits,
144 new BMessage(MSG_REWIND));
145 // AddChild( fRewind );
148 frame.SetRightBottom(kStopButtonSize);
149 if (fBottomControlHeight < kStopBitmapHeight - 1.0)
150 fBottomControlHeight = kStopBitmapHeight - 1.0;
151 fStop = new TransportButton(frame, B_EMPTY_STRING,
152 kStopButtonBitmapBits,
153 kPressedStopButtonBitmapBits,
154 kDisabledStopButtonBitmapBits,
155 new BMessage(STOP_PLAYBACK));
159 frame.SetRightBottom(kSpeakerButtonSize);
160 if (fBottomControlHeight < kSpeakerIconBitmapHeight - 1.0)
161 fBottomControlHeight = kSpeakerIconBitmapHeight - 1.0;
162 fMute = new TransportButton(frame, B_EMPTY_STRING,
164 kPressedSpeakerIconBits,
166 new BMessage(VOLUME_MUTE));
171 fVolumeSlider = new VolumeSlider(BRect(0.0, 0.0, VOLUME_MIN_WIDTH,
172 kVolumeSliderBitmapHeight - 1.0),
173 "volume slider", 1, AOUT_VOLUME_MAX,
174 new BMessage(VOLUME_CHG));
175 fVolumeSlider->SetValue( config_GetInt( p_intf, "volume" ) );
176 AddChild( fVolumeSlider );
178 // Position Info View
179 fPositionInfo = new PositionInfoView(BRect(0.0, 0.0, 10.0, 10.0), "led",
181 fPositionInfo->ResizeToPreferred();
182 AddChild( fPositionInfo );
186 MediaControlView::~MediaControlView()
192 MediaControlView::AttachedToWindow()
194 // we are now a valid BHandler
195 fRewind->SetTarget(this);
196 fForward->SetTarget(this);
197 fSkipBack->SetTarget(this);
198 fSkipForward->SetTarget(this);
199 fVolumeSlider->SetTarget(Window());
201 BRect r(_MinFrame());
202 if (BMenuBar* menuBar = Window()->KeyMenuBar()) {
204 menuBar->GetPreferredSize(&width, &height);
205 // r.bottom += menuBar->Bounds().Height();
207 // see that our calculated minimal width is not smaller than what
208 // the menubar can be
214 Window()->SetSizeLimits(r.Width(), r.Width() * 1.8, r.Height(), r.Height() * 1.3);
215 if (!Window()->Bounds().Contains(r))
216 Window()->ResizeTo(r.Width(), r.Height());
218 FrameResized(Bounds().Width(), Bounds().Height());
220 // get pulse message every two frames
221 Window()->SetPulseRate(80000);
226 MediaControlView::FrameResized(float width, float height)
229 // make sure we don't leave dirty pixels
230 // (B_FULL_UPDATE_ON_RESIZE == annoying flicker -> this is smarter)
231 if (fOldBounds.Width() < r.Width())
232 Invalidate(BRect(fOldBounds.right, fOldBounds.top + 1.0,
233 fOldBounds.right, fOldBounds.bottom - 1.0));
235 Invalidate(BRect(r.right, r.top + 1.0,
236 r.right, r.bottom - 1.0));
237 if (fOldBounds.Height() < r.Height())
238 Invalidate(BRect(fOldBounds.left + 1.0, fOldBounds.bottom,
239 fOldBounds.right - 1.0, fOldBounds.bottom));
241 Invalidate(BRect(r.left + 1.0, r.bottom,
242 r.right - 1.0, r.bottom));
243 // remember for next time
246 r.InsetBy(BORDER_INSET, BORDER_INSET);
252 MediaControlView::GetPreferredSize(float* width, float* height)
256 BRect r(_MinFrame());
258 *height = r.Height();
264 MediaControlView::MessageReceived(BMessage* message)
266 switch (message->what)
272 case MSG_SKIP_BACKWARDS:
273 Window()->PostMessage(NAVIGATE_PREV);
275 case MSG_SKIP_FORWARD:
276 Window()->PostMessage(NAVIGATE_NEXT);
279 BBox::MessageReceived(message);
286 MediaControlView::Pulse()
288 InterfaceWindow* window = dynamic_cast<InterfaceWindow*>(Window());
289 if (window && window->IsStopped())
290 fPlayPause->SetStopped();
292 unsigned short i_volume;
293 aout_VolumeGet( p_intf, (audio_volume_t*)&i_volume );
294 fVolumeSlider->SetValue( i_volume );
299 MediaControlView::SetProgress( float position )
301 fSeekSlider->SetPosition( position );
306 MediaControlView::SetStatus(int status, int rate)
308 // we need to set the button status periodically
309 // (even if it is the same) to get a blinking button
310 fCurrentStatus = status;
316 fPlayPause->SetPlaying();
319 fPlayPause->SetPaused();
322 fPlayPause->SetStopped();
325 if (rate != fCurrentRate)
328 if ( rate < INPUT_RATE_DEFAULT )
337 MediaControlView::SetEnabled(bool enabled)
339 if( ( enabled && fIsEnabled ) ||
340 ( !enabled && !fIsEnabled ) )
342 /* do not redraw if it is not necessary */
348 fSkipBack->SetEnabled( enabled );
349 fPlayPause->SetEnabled( enabled );
350 fSkipForward->SetEnabled( enabled );
351 fStop->SetEnabled( enabled );
352 fMute->SetEnabled( enabled );
353 fVolumeSlider->SetEnabled( enabled );
354 fSeekSlider->SetEnabled( enabled );
355 fRewind->SetEnabled( enabled );
356 fForward->SetEnabled( enabled );
358 fIsEnabled = enabled;
364 MediaControlView::SetAudioEnabled(bool enabled)
366 fMute->SetEnabled(enabled);
367 fVolumeSlider->SetEnabled(enabled);
372 MediaControlView::GetVolume() const
374 return fVolumeSlider->Value();
379 MediaControlView::SetSkippable(bool backward, bool forward)
381 fSkipBack->SetEnabled(backward);
382 fSkipForward->SetEnabled(forward);
387 MediaControlView::SetMuted(bool mute)
389 fVolumeSlider->SetMuted(mute);
394 MediaControlView::_LayoutControls(BRect frame) const
398 // calculate absolutly minimal width
399 float minWidth = fSkipBack->Bounds().Width();
400 // minWidth += fRewind->Bounds().Width();
401 minWidth += fStop->Bounds().Width();
402 minWidth += fPlayPause->Bounds().Width();
403 // minWidth += fForward->Bounds().Width();
404 minWidth += fSkipForward->Bounds().Width();
405 minWidth += fMute->Bounds().Width();
406 minWidth += VOLUME_MIN_WIDTH;
408 // layout time slider and info view
410 fPositionInfo->GetBigPreferredSize( &width, &height );
411 float ratio = width / height;
412 width = r.Height() * ratio;
413 if (frame.Width() - minWidth - MIN_SPACE >= width
414 && frame.Height() >= height)
416 r.right = r.left + width;
417 fPositionInfo->SetMode(PositionInfoView::MODE_BIG);
418 _LayoutControl(fPositionInfo, r, true, true);
419 frame.left = r.right + MIN_SPACE;
421 r.right = frame.right;
422 // r.bottom = r.top + r.Height() / 2.0 - MIN_SPACE / 2.0;
423 r.bottom = r.top + fSeekSlider->Bounds().Height();
424 _LayoutControl(fSeekSlider, r, true);
428 fPositionInfo->GetPreferredSize( &width, &height );
429 fPositionInfo->SetMode(PositionInfoView::MODE_SMALL);
430 fPositionInfo->ResizeTo(width, height);
431 r.bottom = r.top + r.Height() / 2.0 - MIN_SPACE / 2.0;
432 r.right = r.left + fPositionInfo->Bounds().Width();
433 _LayoutControl(fPositionInfo, r, true );
434 r.left = r.right + MIN_SPACE;
435 r.right = frame.right;
436 _LayoutControl(fSeekSlider, r, true);
438 float currentWidth = frame.Width();
439 float space = (currentWidth - minWidth) / 6.0;//8.0;
441 space = MIN_SPACE + (space - MIN_SPACE) / VOLUME_SLIDER_LAYOUT_WEIGHT;
442 // layout controls with "space" inbetween
444 r.top = r.bottom + MIN_SPACE + 1.0;
445 r.bottom = frame.bottom;
447 r.right = r.left + fSkipBack->Bounds().Width();
448 _LayoutControl(fSkipBack, r);
450 // r.left = r.right + space;
451 // r.right = r.left + fRewind->Bounds().Width();
452 // _LayoutControl(fRewind, r);
454 r.left = r.right + space;
455 r.right = r.left + fStop->Bounds().Width();
456 _LayoutControl(fStop, r);
458 r.left = r.right + space;
459 r.right = r.left + fPlayPause->Bounds().Width();
460 _LayoutControl(fPlayPause, r);
462 // r.left = r.right + space;
463 // r.right = r.left + fForward->Bounds().Width();
464 // _LayoutControl(fForward, r);
466 r.left = r.right + space;
467 r.right = r.left + fSkipForward->Bounds().Width();
468 _LayoutControl(fSkipForward, r);
470 r.left = r.right + space + space;
471 r.right = r.left + fMute->Bounds().Width();
472 _LayoutControl(fMute, r);
474 r.left = r.right + SPEAKER_SLIDER_DIST; // keep speaker icon and volume slider attached
475 r.right = frame.right;
476 _LayoutControl(fVolumeSlider, r, true);
481 MediaControlView::_MinFrame() const
483 // add up width of controls along bottom (seek slider will likely adopt)
484 float minWidth = 2 * BORDER_INSET;
485 minWidth += fSkipBack->Bounds().Width() + MIN_SPACE;
486 // minWidth += fRewind->Bounds().Width() + MIN_SPACE;
487 minWidth += fStop->Bounds().Width() + MIN_SPACE;
488 minWidth += fPlayPause->Bounds().Width() + MIN_SPACE;
489 // minWidth += fForward->Bounds().Width() + MIN_SPACE;
490 minWidth += fSkipForward->Bounds().Width() + MIN_SPACE + MIN_SPACE;
491 minWidth += fMute->Bounds().Width() + SPEAKER_SLIDER_DIST;
492 minWidth += VOLUME_MIN_WIDTH;
494 // add up height of seek slider and heighest control on bottom
495 float minHeight = 2 * BORDER_INSET;
496 minHeight += fSeekSlider->Bounds().Height() + MIN_SPACE + MIN_SPACE / 2.0;
497 minHeight += fBottomControlHeight;
498 return BRect(0.0, 0.0, minWidth - 1.0, minHeight - 1.0);
503 MediaControlView::_LayoutControl(BView* view, BRect frame,
504 bool resizeWidth, bool resizeHeight) const
508 frame.top = (frame.top + frame.bottom) / 2.0 - view->Bounds().Height() / 2.0;
510 //center horizontally
511 frame.left = (frame.left + frame.right) / 2.0 - view->Bounds().Width() / 2.0;
512 view->MoveTo(frame.LeftTop());
513 float width = resizeWidth ? frame.Width() : view->Bounds().Width();
514 float height = resizeHeight ? frame.Height() : view->Bounds().Height();
515 if (resizeWidth || resizeHeight)
516 view->ResizeTo(width, height);
521 /*****************************************************************************
523 *****************************************************************************/
524 SeekSlider::SeekSlider( intf_thread_t * _p_intf,
525 BRect frame, const char* name, MediaControlView *owner )
526 : BControl(frame, name, NULL, NULL, B_FOLLOW_NONE,
527 B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE),
532 BFont font(be_plain_font);
537 SeekSlider::~SeekSlider()
541 /*****************************************************************************
542 * VolumeSlider::AttachedToWindow
543 *****************************************************************************/
545 SeekSlider::AttachedToWindow()
547 BControl::AttachedToWindow();
548 SetViewColor(B_TRANSPARENT_32_BIT);
551 /*****************************************************************************
553 *****************************************************************************/
555 SeekSlider::Draw(BRect updateRect)
558 float knobWidth2 = SEEK_SLIDER_KNOB_WIDTH / 2.0;
559 float sliderStart = (r.left + knobWidth2);
560 float sliderEnd = (r.right - knobWidth2);
561 float knobPos = sliderStart
562 + floorf((sliderEnd - sliderStart - 1.0) * Value()
564 // draw both sides (the original from Be doesn't seem
565 // to make a difference for enabled/disabled state)
566 // DrawBitmapAsync(fLeftSideBits, r.LeftTop());
567 // DrawBitmapAsync(fRightSideBits, BPoint(sliderEnd + 1.0, r.top));
568 // colors for the slider area between the two bitmaps
569 rgb_color background = kBackground;//ui_color(B_PANEL_BACKGROUND_COLOR);
570 rgb_color shadow = tint_color(background, B_DARKEN_2_TINT);
571 rgb_color softShadow = tint_color(background, B_DARKEN_1_TINT);
572 rgb_color darkShadow = tint_color(background, B_DARKEN_4_TINT);
573 rgb_color midShadow = tint_color(background, B_DARKEN_3_TINT);
574 rgb_color light = tint_color(background, B_LIGHTEN_MAX_TINT);
575 rgb_color softLight = tint_color(background, B_LIGHTEN_1_TINT);
576 rgb_color green = kSeekGreen;
577 rgb_color greenShadow = kSeekGreenShadow;
578 rgb_color black = kBlack;
579 rgb_color dotGrey = midShadow;
580 rgb_color dotGreen = greenShadow;
582 _StrokeFrame(r, softShadow, softShadow, softLight, softLight);
584 _StrokeFrame(r, black, black, light, light);
589 _StrokeFrame(r, greenShadow, greenShadow, green, green);
592 _StrokeFrame(r, greenShadow, greenShadow, green, green);
598 int32 dotCount = (int32)(r.Width() / 6.0);
600 dotPos.y = r.top + 2.0;
601 SetHighColor(dotGreen);
602 for (int32 i = 0; i < dotCount; i++)
604 dotPos.x = sliderStart + i * 6.0 + 5.0;
605 StrokeLine(dotPos, BPoint(dotPos.x, dotPos.y + 6.0));
610 r.left = knobPos - knobWidth2;
611 r.right = knobPos + knobWidth2;
613 float handleBottomSize = 2.0;
614 float handleArrowSize = 6.0;
617 AddLine(BPoint(r.left, r.top + handleBottomSize),
618 BPoint(r.left, r.top), black);
619 AddLine(BPoint(r.left + 1.0, r.top),
620 BPoint(r.right, r.top), black);
621 AddLine(BPoint(r.right, r.top + 1.0),
622 BPoint(r.right, r.top + handleBottomSize), black);
623 AddLine(BPoint(r.right - 1.0, r.top + handleBottomSize + 1.0),
624 BPoint(knobPos, r.top + handleArrowSize), black);
625 AddLine(BPoint(knobPos - 1.0, r.top + handleArrowSize - 1.0),
626 BPoint(r.left + 1.0, r.top + handleBottomSize + 1.0), black);
628 AddLine(BPoint(r.left, r.bottom),
629 BPoint(r.left, r.bottom - handleBottomSize), black);
630 AddLine(BPoint(r.left + 1.0, r.bottom - handleBottomSize - 1.0),
631 BPoint(knobPos, r.bottom - handleArrowSize), black);
632 AddLine(BPoint(knobPos + 1.0, r.bottom - handleArrowSize + 1.0),
633 BPoint(r.right, r.bottom - handleBottomSize), black);
634 AddLine(BPoint(r.right, r.bottom - handleBottomSize + 1.0),
635 BPoint(r.right, r.bottom), black);
636 AddLine(BPoint(r.right - 1.0, r.bottom),
637 BPoint(r.left + 1.0, r.bottom), black);
639 // inner red light and shadow lines
642 handleArrowSize -= 2.0;
645 AddLine(BPoint(r.left, r.top + handleBottomSize),
646 BPoint(r.left, r.top), kSeekRedLight);
647 AddLine(BPoint(r.left + 1.0, r.top),
648 BPoint(r.right, r.top), kSeekRedLight);
649 AddLine(BPoint(r.right, r.top + 1.0),
650 BPoint(r.right, r.top + handleBottomSize), kSeekRedShadow);
651 AddLine(BPoint(r.right - 1.0, r.top + handleBottomSize + 1.0),
652 BPoint(knobPos, r.top + handleArrowSize), kSeekRedShadow);
653 AddLine(BPoint(knobPos - 1.0, r.top + handleArrowSize - 1.0),
654 BPoint(r.left + 1.0, r.top + handleBottomSize + 1.0), kSeekRedLight);
656 AddLine(BPoint(r.left, r.bottom),
657 BPoint(r.left, r.bottom - handleBottomSize), kSeekRedLight);
658 AddLine(BPoint(r.left + 1.0, r.bottom - handleBottomSize - 1.0),
659 BPoint(knobPos, r.bottom - handleArrowSize), kSeekRedLight);
660 AddLine(BPoint(knobPos + 1.0, r.bottom - handleArrowSize + 1.0),
661 BPoint(r.right, r.bottom - handleBottomSize), kSeekRedShadow);
662 AddLine(BPoint(r.right, r.bottom - handleBottomSize + 1.0),
663 BPoint(r.right, r.bottom), kSeekRedShadow);
664 AddLine(BPoint(r.right - 1.0, r.bottom),
665 BPoint(r.left + 1.0, r.bottom), kSeekRedShadow);
667 // fill rest of handles with red
668 SetHighColor(kSeekRed);
670 handleArrowSize -= 2.0;
672 // upper handle arrow
675 arrow[1].x = r.right;
677 arrow[2].x = knobPos;
678 arrow[2].y = r.top + handleArrowSize;
679 FillPolygon(arrow, 3);
680 // lower handle arrow
682 arrow[0].y = r.bottom;
683 arrow[1].x = r.right;
684 arrow[1].y = r.bottom;
685 arrow[2].x = knobPos;
686 arrow[2].y = r.bottom - handleArrowSize;
687 FillPolygon(arrow, 3);
692 _StrokeFrame(r, darkShadow, darkShadow, darkShadow, darkShadow);
694 _StrokeFrame(r, darkShadow, darkShadow, darkShadow, darkShadow);
696 SetHighColor(darkShadow);
699 float width = floorf(StringWidth(DISABLED_SEEK_MESSAGE));
700 float textPos = r.left + r.Width() / 2.0 - width / 2.0;
701 pattern stripes = {{ 0xc7, 0x8f, 0x1f, 0x3e, 0x7c, 0xf8, 0xf1, 0xe3 }};
702 BRect stripesRect(r);
703 stripesRect.right = textPos - 5.0;
704 FillRect(stripesRect, stripes);
705 stripesRect.left = textPos + width + 3.0;
706 stripesRect.right = r.right;
707 FillRect(stripesRect, stripes);
709 r.left = textPos - 4.0;
710 r.right = textPos + width + 2.0;
712 SetHighColor(shadow);
713 SetLowColor(darkShadow);
716 DrawString(DISABLED_SEEK_MESSAGE, BPoint(textPos, r.top + ceilf(fh.ascent) - 1.0));
720 /*****************************************************************************
721 * SeekSlider::MouseDown
722 *****************************************************************************/
724 SeekSlider::MouseDown(BPoint where)
726 if (IsEnabled() && Bounds().Contains(where))
728 SetValue(_ValueFor(where.x));
730 SetMouseEventMask(B_POINTER_EVENTS, B_LOCK_WINDOW_FOCUS);
734 /*****************************************************************************
735 * SeekSlider::MouseMoved
736 *****************************************************************************/
738 SeekSlider::MouseMoved(BPoint where, uint32 code, const BMessage* dragMessage)
742 SetValue(_ValueFor(where.x));
746 /*****************************************************************************
747 * SeekSlider::MouseUp
748 *****************************************************************************/
750 SeekSlider::MouseUp(BPoint where)
755 input_thread_t * p_input;
756 p_input = (input_thread_t *)
757 vlc_object_find( p_intf, VLC_OBJECT_INPUT, FIND_ANYWHERE );
761 var_SetFloat( p_input, "position",
762 (float) Value() / SEEKSLIDER_RANGE );
763 vlc_object_release( p_input );
768 /*****************************************************************************
769 * SeekSlider::ResizeToPreferred
770 *****************************************************************************/
772 SeekSlider::ResizeToPreferred()
774 float width = 15.0 + StringWidth(DISABLED_SEEK_MESSAGE) + 15.0;
775 ResizeTo(width, 17.0);
778 /*****************************************************************************
779 * SeekSlider::SetPosition
780 *****************************************************************************/
782 SeekSlider::SetPosition(float position)
788 SetValue( SEEKSLIDER_RANGE * position );
794 /*****************************************************************************
795 * SeekSlider::_ValueFor
796 *****************************************************************************/
798 SeekSlider::_ValueFor(float xPos) const
801 float knobWidth2 = SEEK_SLIDER_KNOB_WIDTH / 2.0;
802 float sliderStart = (r.left + knobWidth2);
803 float sliderEnd = (r.right - knobWidth2);
804 int32 value = (int32)(((xPos - sliderStart) * SEEKSLIDER_RANGE)
805 / (sliderEnd - sliderStart - 1.0));
808 if (value > SEEKSLIDER_RANGE)
809 value = SEEKSLIDER_RANGE;
813 /*****************************************************************************
814 * SeekSlider::_StrokeFrame
815 *****************************************************************************/
817 SeekSlider::_StrokeFrame(BRect r, rgb_color left, rgb_color top,
818 rgb_color right, rgb_color bottom)
821 AddLine(BPoint(r.left, r.bottom), BPoint(r.left, r.top), left);
822 AddLine(BPoint(r.left + 1.0, r.top), BPoint(r.right, r.top), top);
823 AddLine(BPoint(r.right, r.top + 1.0), BPoint(r.right, r.bottom), right);
824 AddLine(BPoint(r.right - 1.0, r.bottom), BPoint(r.left + 1.0, r.bottom), bottom);
828 /*****************************************************************************
830 *****************************************************************************/
831 VolumeSlider::VolumeSlider(BRect frame, const char* name, int32 minValue, int32 maxValue,
832 BMessage* message, BHandler* target)
833 : BControl(frame, name, NULL, message, B_FOLLOW_NONE,
834 B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE),
836 fRightSideBits(NULL),
846 BRect r(BPoint(0.0, 0.0), kVolumeSliderBitmapSize);
847 fLeftSideBits = new BBitmap(r, B_CMAP8);
848 fRightSideBits = new BBitmap(r, B_CMAP8);
849 r.Set(0.0, 0.0, kVolumeSliderKnobBitmapSize.x, kVolumeSliderKnobBitmapSize.y);
850 fKnobBits = new BBitmap(r, B_CMAP8);
855 /*****************************************************************************
856 * VolumeSlider destructor
857 *****************************************************************************/
858 VolumeSlider::~VolumeSlider()
860 delete fLeftSideBits;
861 delete fRightSideBits;
865 /*****************************************************************************
866 * VolumeSlider::AttachedToWindow
867 *****************************************************************************/
869 VolumeSlider::AttachedToWindow()
871 BControl::AttachedToWindow();
872 SetViewColor(B_TRANSPARENT_32_BIT);
875 /*****************************************************************************
876 * VolumeSlider::SetValue
877 *****************************************************************************/
879 VolumeSlider::SetValue(int32 value)
881 if (value != Value())
883 BControl::SetValue(value);
888 /*****************************************************************************
889 * VolumeSlider::SetEnabled
890 *****************************************************************************/
892 VolumeSlider::SetEnabled(bool enable)
894 if (enable != IsEnabled())
896 BControl::SetEnabled(enable);
902 /*****************************************************************************
904 *****************************************************************************/
906 VolumeSlider::Draw(BRect updateRect)
911 float sliderSideWidth = kVolumeSliderBitmapWidth;
912 float sliderStart = (r.left + sliderSideWidth);
913 float sliderEnd = (r.right - sliderSideWidth);
914 float knobPos = sliderStart
915 + (sliderEnd - sliderStart - 1.0) * (Value() - fMinValue)
916 / (fMaxValue - fMinValue);
917 // draw both sides (the original from Be doesn't seem
918 // to make a difference for enabled/disabled state)
919 DrawBitmapAsync(fLeftSideBits, r.LeftTop());
920 DrawBitmapAsync(fRightSideBits, BPoint(sliderEnd + 1.0, r.top));
921 // colors for the slider area between the two bitmaps
922 rgb_color background = kBackground;//ui_color(B_PANEL_BACKGROUND_COLOR);
923 rgb_color shadow = tint_color(background, B_DARKEN_2_TINT);
924 rgb_color softShadow = tint_color(background, B_DARKEN_1_TINT);
925 rgb_color darkShadow = tint_color(background, B_DARKEN_4_TINT);
926 rgb_color midShadow = tint_color(background, B_DARKEN_3_TINT);
927 rgb_color light = tint_color(background, B_LIGHTEN_MAX_TINT);
928 rgb_color softLight = tint_color(background, B_LIGHTEN_1_TINT);
929 rgb_color green = kGreen;
930 rgb_color greenShadow = kGreenShadow;
931 rgb_color black = kBlack;
932 rgb_color dotGrey = midShadow;
933 rgb_color dotGreen = greenShadow;
934 // make dimmed version of colors if we're disabled
937 shadow = (rgb_color){ 200, 200, 200, 255 };
938 softShadow = dimmed_color_cmap8(softShadow, background, DIM_LEVEL);
939 darkShadow = dimmed_color_cmap8(darkShadow, background, DIM_LEVEL);
941 light = dimmed_color_cmap8(light, background, DIM_LEVEL);
942 softLight = dimmed_color_cmap8(softLight, background, DIM_LEVEL);
943 green = dimmed_color_cmap8(green, background, DIM_LEVEL);
944 greenShadow = dimmed_color_cmap8(greenShadow, background, DIM_LEVEL);
945 black = dimmed_color_cmap8(black, background, DIM_LEVEL);
950 green = tint_color(kBackground, B_DARKEN_3_TINT);
951 greenShadow = tint_color(kBackground, B_DARKEN_4_TINT);
952 dotGreen = greenShadow;
954 // draw slider edges between bitmaps
956 AddLine(BPoint(sliderStart, r.top),
957 BPoint(sliderEnd, r.top), softShadow);
958 AddLine(BPoint(sliderStart, r.bottom),
959 BPoint(sliderEnd, r.bottom), softLight);
961 AddLine(BPoint(sliderStart, r.top),
962 BPoint(sliderEnd, r.top), black);
963 AddLine(BPoint(sliderStart, r.bottom),
964 BPoint(sliderEnd, r.bottom), light);
966 AddLine(BPoint(sliderStart, r.top),
967 BPoint(knobPos, r.top), greenShadow);
968 AddLine(BPoint(knobPos, r.top),
969 BPoint(sliderEnd, r.top), midShadow);
971 AddLine(BPoint(sliderStart, r.top),
972 BPoint(knobPos, r.top), greenShadow);
974 // fill rest inside of slider
976 r.left = sliderStart;
979 FillRect(r, B_SOLID_HIGH);
980 r.left = knobPos + 1.0;
983 SetHighColor(shadow);
984 FillRect(r, B_SOLID_HIGH);
985 // draw little dots inside
986 int32 dotCount = (int32)((sliderEnd - sliderStart) / 5.0);
988 dotPos.y = r.top + 4.0;
989 for (int32 i = 0; i < dotCount; i++)
991 dotPos.x = sliderStart + i * 5.0 + 4.0;
992 SetHighColor(dotPos.x < knobPos ? dotGreen : dotGrey);
993 StrokeLine(dotPos, BPoint(dotPos.x, dotPos.y + 1.0));
997 SetDrawingMode(B_OP_OVER); // part of knob is transparent
998 DrawBitmapAsync(fKnobBits, BPoint(knobPos - kVolumeSliderKnobWidth / 2, r.top));
1002 /*****************************************************************************
1003 * VolumeSlider::MouseDown
1004 *****************************************************************************/
1006 VolumeSlider::MouseDown(BPoint where)
1008 if (Bounds().Contains(where) && IsEnabled())
1011 SetValue(_ValueFor(where.x));
1012 SetMouseEventMask(B_POINTER_EVENTS, B_LOCK_WINDOW_FOCUS);
1016 /*****************************************************************************
1017 * VolumeSlider::MouseMoved
1018 *****************************************************************************/
1020 VolumeSlider::MouseMoved(BPoint where, uint32 transit, const BMessage* dragMessage)
1023 SetValue(_ValueFor(where.x));
1026 /*****************************************************************************
1027 * VolumeSlider::MouseUp
1028 *****************************************************************************/
1030 VolumeSlider::MouseUp(BPoint where)
1036 /*****************************************************************************
1037 * VolumeSlider::IsValid
1038 *****************************************************************************/
1040 VolumeSlider::IsValid() const
1042 return (fLeftSideBits && fLeftSideBits->IsValid()
1043 && fRightSideBits && fRightSideBits->IsValid()
1044 && fKnobBits && fKnobBits->IsValid());
1047 /*****************************************************************************
1048 * VolumeSlider::SetMuted
1049 *****************************************************************************/
1051 VolumeSlider::SetMuted(bool mute)
1061 /*****************************************************************************
1062 * VolumeSlider::_MakeBitmaps
1063 *****************************************************************************/
1065 VolumeSlider::_MakeBitmaps()
1069 // left side of slider
1070 memcpy(fLeftSideBits->Bits(), kVolumeSliderLeftBitmapBits,
1071 fLeftSideBits->BitsLength());
1072 // right side of slider
1073 memcpy(fRightSideBits->Bits(), kVolumeSliderRightBits,
1074 fRightSideBits->BitsLength());
1076 int32 length = fKnobBits->BitsLength();
1077 memcpy(fKnobBits->Bits(), kVolumeSliderKnobBits, length);
1078 uint8* bits = (uint8*)fKnobBits->Bits();
1079 // black was used in the knob to represent transparency
1080 // use screen to get index for the "transarent" color used in the bitmap
1081 BScreen screen(B_MAIN_SCREEN_ID);
1082 uint8 blackIndex = screen.IndexForColor(kBlack);
1083 // replace black index with transparent index
1084 for (int32 i = 0; i < length; i++)
1085 if (bits[i] == blackIndex)
1086 bits[i] = B_TRANSPARENT_MAGIC_CMAP8;
1090 // make ghosted versions of the bitmaps
1091 dim_bitmap(fLeftSideBits, kBackground, DIM_LEVEL);
1092 dim_bitmap(fRightSideBits, kBackground, DIM_LEVEL);
1093 dim_bitmap(fKnobBits, kBackground, DIM_LEVEL);
1097 // replace green color (and shadow) in left slider side
1098 bits = (uint8*)fLeftSideBits->Bits();
1099 length = fLeftSideBits->BitsLength();
1100 uint8 greenIndex = screen.IndexForColor(kGreen);
1101 uint8 greenShadowIndex = screen.IndexForColor(kGreenShadow);
1102 rgb_color shadow = tint_color(kBackground, B_DARKEN_3_TINT);
1103 rgb_color midShadow = tint_color(kBackground, B_DARKEN_4_TINT);
1104 uint8 replaceIndex = screen.IndexForColor(shadow);
1105 uint8 replaceShadowIndex = screen.IndexForColor(midShadow);
1106 for (int32 i = 0; i < length; i++)
1108 if (bits[i] == greenIndex)
1109 bits[i] = replaceIndex;
1110 else if (bits[i] == greenShadowIndex)
1111 bits[i] = replaceShadowIndex;
1117 /*****************************************************************************
1118 * VolumeSlider::_ValueFor
1119 *****************************************************************************/
1121 VolumeSlider::_ValueFor(float xPos) const
1124 float sliderStart = (r.left + kVolumeSliderBitmapWidth);
1125 float sliderEnd = (r.right - kVolumeSliderBitmapWidth);
1126 int32 value = fMinValue + (int32)(((xPos - sliderStart) * (fMaxValue - fMinValue))
1127 / (sliderEnd - sliderStart - 1.0));
1128 if (value < fMinValue)
1130 if (value > fMaxValue)
1135 /*****************************************************************************
1136 * PositionInfoView::PositionInfoView
1137 *****************************************************************************/
1138 PositionInfoView::PositionInfoView( BRect frame, const char* name,
1139 intf_thread_t * p_interface )
1140 : BView( frame, name, B_FOLLOW_NONE,
1141 B_WILL_DRAW | B_PULSE_NEEDED | B_FULL_UPDATE_ON_RESIZE ),
1142 fMode( MODE_SMALL ),
1143 fCurrentFileIndex( -1 ),
1144 fCurrentFileSize( -1 ),
1145 fCurrentTitleIndex( -1 ),
1146 fCurrentTitleSize( -1 ),
1147 fCurrentChapterIndex( -1 ),
1148 fCurrentChapterSize( -1 ),
1150 fTimeString( "-:--:--" ),
1151 fLastPulseUpdate( system_time() ),
1152 fStackedWidthCache( 0.0 ),
1153 fStackedHeightCache( 0.0 )
1155 p_intf = p_interface;
1157 SetViewColor( B_TRANSPARENT_32_BIT );
1158 SetLowColor( kBlack );
1159 SetHighColor( 0, 255, 0, 255 );
1160 SetFontSize( 11.0 );
1163 /*****************************************************************************
1164 * PositionInfoView::~PositionInfoView
1165 *****************************************************************************/
1166 PositionInfoView::~PositionInfoView()
1170 /*****************************************************************************
1171 * PositionInfoView::Draw
1172 *****************************************************************************/
1174 PositionInfoView::Draw( BRect updateRect )
1176 rgb_color background = ui_color( B_PANEL_BACKGROUND_COLOR );
1177 rgb_color shadow = tint_color( background, B_DARKEN_1_TINT );
1178 rgb_color darkShadow = tint_color( background, B_DARKEN_4_TINT );
1179 rgb_color light = tint_color( background, B_LIGHTEN_MAX_TINT );
1180 rgb_color softLight = tint_color( background, B_LIGHTEN_1_TINT );
1182 BRect r( Bounds() );
1183 BeginLineArray( 8 );
1184 AddLine( BPoint( r.left, r.bottom ),
1185 BPoint( r.left, r.top ), shadow );
1186 AddLine( BPoint( r.left + 1.0, r.top ),
1187 BPoint( r.right, r.top ), shadow );
1188 AddLine( BPoint( r.right, r.top + 1.0 ),
1189 BPoint( r.right, r.bottom ), softLight );
1190 AddLine( BPoint( r.right - 1.0, r.bottom ),
1191 BPoint( r.left + 1.0, r.bottom ), softLight );
1192 r.InsetBy( 1.0, 1.0 );
1193 AddLine( BPoint( r.left, r.bottom ),
1194 BPoint( r.left, r.top ), darkShadow );
1195 AddLine( BPoint( r.left + 1.0, r.top ),
1196 BPoint( r.right, r.top ), darkShadow );
1197 AddLine( BPoint( r.right, r.top + 1.0 ),
1198 BPoint( r.right, r.bottom ), light );
1199 AddLine( BPoint( r.right - 1.0, r.bottom ),
1200 BPoint( r.left + 1.0, r.bottom ), light );
1203 r.InsetBy( 1.0, 1.0 );
1204 FillRect( r, B_SOLID_LOW );
1207 GetFontHeight( &fh );
1212 float width = StringWidth( fTimeString.String() );
1213 DrawString( fTimeString.String(),
1214 BPoint( r.left + r.Width() / 2.0 - width / 2.0,
1215 r.top + r.Height() / 2.0 + fh.ascent / 2.0 - 1.0 ) );
1222 BFont smallFont = font;
1223 BFont bigFont = font;
1224 BFont tinyFont = font;
1225 smallFont.SetSize( r.Height() / 5.0 );
1226 bigFont.SetSize( r.Height() / 3.0 );
1227 tinyFont.SetSize( r.Height() / 7.0 );
1228 float timeHeight = r.Height() / 2.5;
1229 float height = ( r.Height() - timeHeight ) / 3.0;
1230 SetFont( &tinyFont );
1231 SetHighColor( 0, 180, 0, 255 );
1232 DrawString( _("File"), BPoint( r.left + 3.0, r.top + height ) );
1233 DrawString( _("Title"), BPoint( r.left + 3.0, r.top + 2.0 * height ) );
1234 DrawString( _("Chapter"), BPoint( r.left + 3.0, r.top + 3.0 * height ) );
1235 SetFont( &smallFont );
1237 SetHighColor( 0, 255, 0, 255 );
1239 _MakeString( helper, fCurrentFileIndex, fCurrentFileSize );
1240 float width = StringWidth( helper.String() );
1241 DrawString( helper.String(), BPoint( r.right - 3.0 - width, r.top + height ) );
1243 _MakeString( helper, fCurrentTitleIndex, fCurrentTitleSize );
1244 width = StringWidth( helper.String() );
1245 DrawString( helper.String(), BPoint( r.right - 3.0 - width, r.top + 2.0 * height ) );
1247 _MakeString( helper, fCurrentChapterIndex, fCurrentChapterSize );
1248 width = StringWidth( helper.String() );
1249 DrawString( helper.String(), BPoint( r.right - 3.0 - width, r.top + 3.0 * height ) );
1251 SetFont( &bigFont );
1252 width = StringWidth( fTimeString.String() );
1253 DrawString( fTimeString.String(),
1254 BPoint( r.left + r.Width() / 2.0 - width / 2.0,
1261 /*****************************************************************************
1262 * PositionInfoView::ResizeToPreferred
1263 *****************************************************************************/
1265 PositionInfoView::ResizeToPreferred()
1267 float width, height;
1268 GetPreferredSize( &width, &height );
1269 ResizeTo( width, height );
1272 /*****************************************************************************
1273 * PositionInfoView::GetPreferredSize
1274 *****************************************************************************/
1276 PositionInfoView::GetPreferredSize( float* width, float* height )
1278 if ( width && height )
1280 *width = 5.0 + ceilf( StringWidth( "0:00:00" ) ) + 5.0;
1282 GetFontHeight( &fh );
1283 *height = 3.0 + ceilf( fh.ascent ) + 3.0;
1284 fStackedWidthCache = *width * 1.2;
1285 fStackedHeightCache = *height * 2.7;
1289 /*****************************************************************************
1290 * PositionInfoView::Pulse
1291 *****************************************************************************/
1293 PositionInfoView::Pulse()
1295 // allow for Pulse frequency to be higher, MediaControlView needs it
1296 bigtime_t now = system_time();
1297 if ( now - fLastPulseUpdate > 900000 )
1301 p_intf->p_sys->p_wrapper->GetPlaylistInfo( index, size );
1302 SetFile( index + 1, size );
1303 p_intf->p_sys->p_wrapper->TitleInfo( index, size );
1304 SetTitle( index, size );
1305 p_intf->p_sys->p_wrapper->ChapterInfo( index, size );
1306 SetChapter( index, size );
1307 SetTime( p_intf->p_sys->p_wrapper->GetTimeAsString() );
1308 fLastPulseUpdate = now;
1313 /*****************************************************************************
1314 * PositionInfoView::GetBigPreferredSize
1315 *****************************************************************************/
1317 PositionInfoView::GetBigPreferredSize( float* width, float* height )
1319 if ( width && height )
1321 *width = fStackedWidthCache;
1322 *height = fStackedHeightCache;
1326 /*****************************************************************************
1327 * PositionInfoView::SetMode
1328 *****************************************************************************/
1330 PositionInfoView::SetMode( uint32 mode )
1332 if ( fMode != mode )
1335 _InvalidateContents();
1339 /*****************************************************************************
1340 * PositionInfoView::SetFile
1341 *****************************************************************************/
1343 PositionInfoView::SetFile( int32 index, int32 size )
1345 if ( fCurrentFileIndex != index || fCurrentFileSize != size )
1347 fCurrentFileIndex = index;
1348 fCurrentFileSize = size;
1349 _InvalidateContents();
1353 /*****************************************************************************
1354 * PositionInfoView::SetTitle
1355 *****************************************************************************/
1357 PositionInfoView::SetTitle( int32 index, int32 size )
1359 if ( fCurrentTitleIndex != index || fCurrentFileSize != size )
1361 fCurrentTitleIndex = index;
1362 fCurrentTitleSize = size;
1363 _InvalidateContents();
1367 /*****************************************************************************
1368 * PositionInfoView::SetChapter
1369 *****************************************************************************/
1371 PositionInfoView::SetChapter( int32 index, int32 size )
1373 if ( fCurrentChapterIndex != index || fCurrentFileSize != size )
1375 fCurrentChapterIndex = index;
1376 fCurrentChapterSize = size;
1377 _InvalidateContents();
1381 /*****************************************************************************
1382 * PositionInfoView::SetTime
1383 *****************************************************************************/
1385 PositionInfoView::SetTime( int32 seconds )
1387 if ( fSeconds != seconds )
1391 int32 minutes = seconds / 60;
1392 int32 hours = minutes / 60;
1393 seconds -= minutes * 60 - hours * 60 * 60;
1394 minutes -= hours * 60;
1395 fTimeString.SetTo( "" );
1396 fTimeString << hours << ":" << minutes << ":" << seconds;
1399 fTimeString.SetTo( "-:--:--" );
1402 _InvalidateContents();
1406 /*****************************************************************************
1407 * PositionInfoView::SetTime
1408 *****************************************************************************/
1410 PositionInfoView::SetTime( const char* string )
1412 fTimeString.SetTo( string );
1413 _InvalidateContents();
1416 /*****************************************************************************
1417 * PositionInfoView::_InvalidateContents
1418 *****************************************************************************/
1420 PositionInfoView::_InvalidateContents( uint32 which )
1422 BRect r( Bounds() );
1423 r.InsetBy( 2.0, 2.0 );
1427 /*****************************************************************************
1428 * PositionInfoView::_InvalidateContents
1429 *****************************************************************************/
1431 PositionInfoView::_MakeString( BString& into, int32 index, int32 maxIndex ) const
1434 if ( index >= 0 && maxIndex >= 0 )
1439 if ( maxIndex >= 0 )