1 /*****************************************************************************
2 * MediaControlView.cpp: beos interface
3 *****************************************************************************
4 * Copyright (C) 1999, 2000, 2001 VideoLAN
5 * $Id: MediaControlView.cpp,v 1.18 2003/05/30 17:30:54 titer Exp $
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., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
23 *****************************************************************************/
26 #include <InterfaceKit.h>
35 /* BeOS interface headers */
36 #include "VlcWrapper.h"
38 #include "DrawingTidbits.h"
39 #include "InterfaceWindow.h"
41 #include "TransportButton.h"
42 #include "ListViews.h"
43 #include "MediaControlView.h"
45 #define BORDER_INSET 6.0
47 #define SPEAKER_SLIDER_DIST 6.0
48 #define VOLUME_MIN_WIDTH 70.0
50 #define VOLUME_SLIDER_LAYOUT_WEIGHT 2.0
51 #define SEEK_SLIDER_KNOB_WIDTH 8.0
53 // slider colors are hardcoded here, because that's just
54 // what they currently are within those bitmaps
55 const rgb_color kGreen = (rgb_color){ 152, 203, 152, 255 };
56 const rgb_color kGreenShadow = (rgb_color){ 102, 152, 102, 255 };
57 const rgb_color kBackground = (rgb_color){ 216, 216, 216, 255 };
58 const rgb_color kSeekGreen = (rgb_color){ 171, 221, 161, 255 };
59 const rgb_color kSeekGreenShadow = (rgb_color){ 144, 186, 136, 255 };
60 const rgb_color kSeekRed = (rgb_color){ 255, 0, 0, 255 };
61 const rgb_color kSeekRedLight = (rgb_color){ 255, 152, 152, 255 };
62 const rgb_color kSeekRedShadow = (rgb_color){ 178, 0, 0, 255 };
64 #define DISABLED_SEEK_MESSAGE _("Drop files to play")
70 MSG_SKIP_BACKWARDS = 'skpb',
71 MSG_SKIP_FORWARD = 'skpf',
75 MediaControlView::MediaControlView(BRect frame, intf_thread_t *p_interface)
76 : BBox(frame, NULL, B_FOLLOW_NONE, B_WILL_DRAW | B_FRAME_EVENTS | B_PULSE_NEEDED,
79 fCurrentRate(DEFAULT_RATE),
80 fCurrentStatus(UNDEF_S),
81 fBottomControlHeight(0.0),
86 BRect frame(0.0, 0.0, 10.0, 10.0);
89 fSeekSlider = new SeekSlider( frame, "seek slider", this,
90 0, SEEKSLIDER_RANGE );
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(AOUT_VOLUME_DEFAULT);
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())
203 r.bottom += menuBar->Bounds().Height();
205 Window()->SetSizeLimits(r.Width(), r.Width() * 1.8, r.Height(), r.Height() * 1.3);
206 if (!Window()->Bounds().Contains(r))
207 Window()->ResizeTo(r.Width(), r.Height());
209 FrameResized(Bounds().Width(), Bounds().Height());
211 // get pulse message every two frames
212 Window()->SetPulseRate(80000);
217 MediaControlView::FrameResized(float width, float height)
220 // make sure we don't leave dirty pixels
221 // (B_FULL_UPDATE_ON_RESIZE == annoying flicker -> this is smarter)
222 if (fOldBounds.Width() < r.Width())
223 Invalidate(BRect(fOldBounds.right, fOldBounds.top + 1.0,
224 fOldBounds.right, fOldBounds.bottom - 1.0));
226 Invalidate(BRect(r.right, r.top + 1.0,
227 r.right, r.bottom - 1.0));
228 if (fOldBounds.Height() < r.Height())
229 Invalidate(BRect(fOldBounds.left + 1.0, fOldBounds.bottom,
230 fOldBounds.right - 1.0, fOldBounds.bottom));
232 Invalidate(BRect(r.left + 1.0, r.bottom,
233 r.right - 1.0, r.bottom));
234 // remember for next time
237 r.InsetBy(BORDER_INSET, BORDER_INSET);
243 MediaControlView::GetPreferredSize(float* width, float* height)
247 BRect r(_MinFrame());
249 *height = r.Height();
255 MediaControlView::MessageReceived(BMessage* message)
257 switch (message->what)
263 case MSG_SKIP_BACKWARDS:
264 Window()->PostMessage(NAVIGATE_PREV);
266 case MSG_SKIP_FORWARD:
267 Window()->PostMessage(NAVIGATE_NEXT);
270 BBox::MessageReceived(message);
277 MediaControlView::Pulse()
279 InterfaceWindow* window = dynamic_cast<InterfaceWindow*>(Window());
280 if (window && window->IsStopped())
281 fPlayPause->SetStopped();
286 MediaControlView::SetProgress( float position )
288 fSeekSlider->SetPosition( position );
293 MediaControlView::SetStatus(int status, int rate)
295 // we need to set the button status periodically
296 // (even if it is the same) to get a blinking button
297 fCurrentStatus = status;
304 fPlayPause->SetPlaying();
307 fPlayPause->SetPaused();
312 fPlayPause->SetStopped();
315 if (rate != fCurrentRate)
318 if ( rate < DEFAULT_RATE )
327 MediaControlView::SetEnabled(bool enabled)
329 if( ( enabled && fIsEnabled ) ||
330 ( !enabled && !fIsEnabled ) )
332 /* do not redraw if it is not necessary */
338 fSkipBack->SetEnabled( enabled );
339 fPlayPause->SetEnabled( enabled );
340 fSkipForward->SetEnabled( enabled );
341 fStop->SetEnabled( enabled );
342 fMute->SetEnabled( enabled );
343 fVolumeSlider->SetEnabled( enabled );
344 fSeekSlider->SetEnabled( enabled );
345 fRewind->SetEnabled( enabled );
346 fForward->SetEnabled( enabled );
348 fIsEnabled = enabled;
354 MediaControlView::SetAudioEnabled(bool enabled)
356 fMute->SetEnabled(enabled);
357 fVolumeSlider->SetEnabled(enabled);
362 MediaControlView::GetSeekTo() const
364 return fSeekSlider->Value();
369 MediaControlView::GetVolume() const
371 return fVolumeSlider->Value();
376 MediaControlView::SetSkippable(bool backward, bool forward)
378 fSkipBack->SetEnabled(backward);
379 fSkipForward->SetEnabled(forward);
384 MediaControlView::SetMuted(bool mute)
386 fVolumeSlider->SetMuted(mute);
391 MediaControlView::_LayoutControls(BRect frame) const
395 // calculate absolutly minimal width
396 float minWidth = fSkipBack->Bounds().Width();
397 // minWidth += fRewind->Bounds().Width();
398 minWidth += fStop->Bounds().Width();
399 minWidth += fPlayPause->Bounds().Width();
400 // minWidth += fForward->Bounds().Width();
401 minWidth += fSkipForward->Bounds().Width();
402 minWidth += fMute->Bounds().Width();
403 minWidth += VOLUME_MIN_WIDTH;
405 // layout time slider and info view
407 fPositionInfo->GetBigPreferredSize( &width, &height );
408 float ratio = width / height;
409 width = r.Height() * ratio;
410 if (frame.Width() - minWidth - MIN_SPACE >= width
411 && frame.Height() >= height)
413 r.right = r.left + width;
414 fPositionInfo->SetMode(PositionInfoView::MODE_BIG);
415 _LayoutControl(fPositionInfo, r, true, true);
416 frame.left = r.right + MIN_SPACE;
418 r.right = frame.right;
419 // r.bottom = r.top + r.Height() / 2.0 - MIN_SPACE / 2.0;
420 r.bottom = r.top + fSeekSlider->Bounds().Height();
421 _LayoutControl(fSeekSlider, r, true);
425 fPositionInfo->GetPreferredSize( &width, &height );
426 fPositionInfo->SetMode(PositionInfoView::MODE_SMALL);
427 fPositionInfo->ResizeTo(width, height);
428 r.bottom = r.top + r.Height() / 2.0 - MIN_SPACE / 2.0;
429 r.right = r.left + fPositionInfo->Bounds().Width();
430 _LayoutControl(fPositionInfo, r, true );
431 r.left = r.right + MIN_SPACE;
432 r.right = frame.right;
433 _LayoutControl(fSeekSlider, r, true);
435 float currentWidth = frame.Width();
436 float space = (currentWidth - minWidth) / 6.0;//8.0;
438 space = MIN_SPACE + (space - MIN_SPACE) / VOLUME_SLIDER_LAYOUT_WEIGHT;
439 // layout controls with "space" inbetween
441 r.top = r.bottom + MIN_SPACE + 1.0;
442 r.bottom = frame.bottom;
444 r.right = r.left + fSkipBack->Bounds().Width();
445 _LayoutControl(fSkipBack, r);
447 // r.left = r.right + space;
448 // r.right = r.left + fRewind->Bounds().Width();
449 // _LayoutControl(fRewind, r);
451 r.left = r.right + space;
452 r.right = r.left + fStop->Bounds().Width();
453 _LayoutControl(fStop, r);
455 r.left = r.right + space;
456 r.right = r.left + fPlayPause->Bounds().Width();
457 _LayoutControl(fPlayPause, r);
459 // r.left = r.right + space;
460 // r.right = r.left + fForward->Bounds().Width();
461 // _LayoutControl(fForward, r);
463 r.left = r.right + space;
464 r.right = r.left + fSkipForward->Bounds().Width();
465 _LayoutControl(fSkipForward, r);
467 r.left = r.right + space + space;
468 r.right = r.left + fMute->Bounds().Width();
469 _LayoutControl(fMute, r);
471 r.left = r.right + SPEAKER_SLIDER_DIST; // keep speaker icon and volume slider attached
472 r.right = frame.right;
473 _LayoutControl(fVolumeSlider, r, true);
478 MediaControlView::_MinFrame() const
480 // add up width of controls along bottom (seek slider will likely adopt)
481 float minWidth = 2 * BORDER_INSET;
482 minWidth += fSkipBack->Bounds().Width() + MIN_SPACE;
483 // minWidth += fRewind->Bounds().Width() + MIN_SPACE;
484 minWidth += fStop->Bounds().Width() + MIN_SPACE;
485 minWidth += fPlayPause->Bounds().Width() + MIN_SPACE;
486 // minWidth += fForward->Bounds().Width() + MIN_SPACE;
487 minWidth += fSkipForward->Bounds().Width() + MIN_SPACE + MIN_SPACE;
488 minWidth += fMute->Bounds().Width() + SPEAKER_SLIDER_DIST;
489 minWidth += VOLUME_MIN_WIDTH;
491 // add up height of seek slider and heighest control on bottom
492 float minHeight = 2 * BORDER_INSET;
493 minHeight += fSeekSlider->Bounds().Height() + MIN_SPACE + MIN_SPACE / 2.0;
494 minHeight += fBottomControlHeight;
495 return BRect(0.0, 0.0, minWidth - 1.0, minHeight - 1.0);
500 MediaControlView::_LayoutControl(BView* view, BRect frame,
501 bool resizeWidth, bool resizeHeight) const
505 frame.top = (frame.top + frame.bottom) / 2.0 - view->Bounds().Height() / 2.0;
507 //center horizontally
508 frame.left = (frame.left + frame.right) / 2.0 - view->Bounds().Width() / 2.0;
509 view->MoveTo(frame.LeftTop());
510 float width = resizeWidth ? frame.Width() : view->Bounds().Width();
511 float height = resizeHeight ? frame.Height() : view->Bounds().Height();
512 if (resizeWidth || resizeHeight)
513 view->ResizeTo(width, height);
518 /*****************************************************************************
520 *****************************************************************************/
521 SeekSlider::SeekSlider(BRect frame, const char* name, MediaControlView *owner,
522 int32 minValue, int32 maxValue)
523 : BControl(frame, name, NULL, NULL, B_FOLLOW_NONE,
524 B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE),
530 BFont font(be_plain_font);
535 SeekSlider::~SeekSlider()
540 /*****************************************************************************
541 * VolumeSlider::AttachedToWindow
542 *****************************************************************************/
544 SeekSlider::AttachedToWindow()
546 BControl::AttachedToWindow();
547 SetViewColor(B_TRANSPARENT_32_BIT);
550 /*****************************************************************************
552 *****************************************************************************/
554 SeekSlider::Draw(BRect updateRect)
557 float knobWidth2 = SEEK_SLIDER_KNOB_WIDTH / 2.0;
558 float sliderStart = (r.left + knobWidth2);
559 float sliderEnd = (r.right - knobWidth2);
560 float knobPos = sliderStart
561 + floorf((sliderEnd - sliderStart - 1.0) * (Value() - fMinValue)
562 / (fMaxValue - fMinValue) + 0.5);
563 // draw both sides (the original from Be doesn't seem
564 // to make a difference for enabled/disabled state)
565 // DrawBitmapAsync(fLeftSideBits, r.LeftTop());
566 // DrawBitmapAsync(fRightSideBits, BPoint(sliderEnd + 1.0, r.top));
567 // colors for the slider area between the two bitmaps
568 rgb_color background = kBackground;//ui_color(B_PANEL_BACKGROUND_COLOR);
569 rgb_color shadow = tint_color(background, B_DARKEN_2_TINT);
570 rgb_color softShadow = tint_color(background, B_DARKEN_1_TINT);
571 rgb_color darkShadow = tint_color(background, B_DARKEN_4_TINT);
572 rgb_color midShadow = tint_color(background, B_DARKEN_3_TINT);
573 rgb_color light = tint_color(background, B_LIGHTEN_MAX_TINT);
574 rgb_color softLight = tint_color(background, B_LIGHTEN_1_TINT);
575 rgb_color green = kSeekGreen;
576 rgb_color greenShadow = kSeekGreenShadow;
577 rgb_color black = kBlack;
578 rgb_color dotGrey = midShadow;
579 rgb_color dotGreen = greenShadow;
581 _StrokeFrame(r, softShadow, softShadow, softLight, softLight);
583 _StrokeFrame(r, black, black, light, light);
588 _StrokeFrame(r, greenShadow, greenShadow, green, green);
591 _StrokeFrame(r, greenShadow, greenShadow, green, green);
597 int32 dotCount = (int32)(r.Width() / 6.0);
599 dotPos.y = r.top + 2.0;
600 SetHighColor(dotGreen);
601 for (int32 i = 0; i < dotCount; i++)
603 dotPos.x = sliderStart + i * 6.0 + 5.0;
604 StrokeLine(dotPos, BPoint(dotPos.x, dotPos.y + 6.0));
609 r.left = knobPos - knobWidth2;
610 r.right = knobPos + knobWidth2;
612 float handleBottomSize = 2.0;
613 float handleArrowSize = 6.0;
616 AddLine(BPoint(r.left, r.top + handleBottomSize),
617 BPoint(r.left, r.top), black);
618 AddLine(BPoint(r.left + 1.0, r.top),
619 BPoint(r.right, r.top), black);
620 AddLine(BPoint(r.right, r.top + 1.0),
621 BPoint(r.right, r.top + handleBottomSize), black);
622 AddLine(BPoint(r.right - 1.0, r.top + handleBottomSize + 1.0),
623 BPoint(knobPos, r.top + handleArrowSize), black);
624 AddLine(BPoint(knobPos - 1.0, r.top + handleArrowSize - 1.0),
625 BPoint(r.left + 1.0, r.top + handleBottomSize + 1.0), black);
627 AddLine(BPoint(r.left, r.bottom),
628 BPoint(r.left, r.bottom - handleBottomSize), black);
629 AddLine(BPoint(r.left + 1.0, r.bottom - handleBottomSize - 1.0),
630 BPoint(knobPos, r.bottom - handleArrowSize), black);
631 AddLine(BPoint(knobPos + 1.0, r.bottom - handleArrowSize + 1.0),
632 BPoint(r.right, r.bottom - handleBottomSize), black);
633 AddLine(BPoint(r.right, r.bottom - handleBottomSize + 1.0),
634 BPoint(r.right, r.bottom), black);
635 AddLine(BPoint(r.right - 1.0, r.bottom),
636 BPoint(r.left + 1.0, r.bottom), black);
638 // inner red light and shadow lines
641 handleArrowSize -= 2.0;
644 AddLine(BPoint(r.left, r.top + handleBottomSize),
645 BPoint(r.left, r.top), kSeekRedLight);
646 AddLine(BPoint(r.left + 1.0, r.top),
647 BPoint(r.right, r.top), kSeekRedLight);
648 AddLine(BPoint(r.right, r.top + 1.0),
649 BPoint(r.right, r.top + handleBottomSize), kSeekRedShadow);
650 AddLine(BPoint(r.right - 1.0, r.top + handleBottomSize + 1.0),
651 BPoint(knobPos, r.top + handleArrowSize), kSeekRedShadow);
652 AddLine(BPoint(knobPos - 1.0, r.top + handleArrowSize - 1.0),
653 BPoint(r.left + 1.0, r.top + handleBottomSize + 1.0), kSeekRedLight);
655 AddLine(BPoint(r.left, r.bottom),
656 BPoint(r.left, r.bottom - handleBottomSize), kSeekRedLight);
657 AddLine(BPoint(r.left + 1.0, r.bottom - handleBottomSize - 1.0),
658 BPoint(knobPos, r.bottom - handleArrowSize), kSeekRedLight);
659 AddLine(BPoint(knobPos + 1.0, r.bottom - handleArrowSize + 1.0),
660 BPoint(r.right, r.bottom - handleBottomSize), kSeekRedShadow);
661 AddLine(BPoint(r.right, r.bottom - handleBottomSize + 1.0),
662 BPoint(r.right, r.bottom), kSeekRedShadow);
663 AddLine(BPoint(r.right - 1.0, r.bottom),
664 BPoint(r.left + 1.0, r.bottom), kSeekRedShadow);
666 // fill rest of handles with red
667 SetHighColor(kSeekRed);
669 handleArrowSize -= 2.0;
671 // upper handle arrow
674 arrow[1].x = r.right;
676 arrow[2].x = knobPos;
677 arrow[2].y = r.top + handleArrowSize;
678 FillPolygon(arrow, 3);
679 // lower handle arrow
681 arrow[0].y = r.bottom;
682 arrow[1].x = r.right;
683 arrow[1].y = r.bottom;
684 arrow[2].x = knobPos;
685 arrow[2].y = r.bottom - handleArrowSize;
686 FillPolygon(arrow, 3);
691 _StrokeFrame(r, darkShadow, darkShadow, darkShadow, darkShadow);
693 _StrokeFrame(r, darkShadow, darkShadow, darkShadow, darkShadow);
695 SetHighColor(darkShadow);
698 float width = floorf(StringWidth(DISABLED_SEEK_MESSAGE));
699 float textPos = r.left + r.Width() / 2.0 - width / 2.0;
700 pattern stripes = {{ 0xc7, 0x8f, 0x1f, 0x3e, 0x7c, 0xf8, 0xf1, 0xe3 }};
701 BRect stripesRect(r);
702 stripesRect.right = textPos - 5.0;
703 FillRect(stripesRect, stripes);
704 stripesRect.left = textPos + width + 3.0;
705 stripesRect.right = r.right;
706 FillRect(stripesRect, stripes);
708 r.left = textPos - 4.0;
709 r.right = textPos + width + 2.0;
711 SetHighColor(shadow);
712 SetLowColor(darkShadow);
715 DrawString(DISABLED_SEEK_MESSAGE, BPoint(textPos, r.top + ceilf(fh.ascent) - 1.0));
719 /*****************************************************************************
720 * SeekSlider::MouseDown
721 *****************************************************************************/
723 SeekSlider::MouseDown(BPoint where)
725 if (IsEnabled() && Bounds().Contains(where))
727 SetValue(_ValueFor(where.x));
729 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));
747 /*****************************************************************************
748 * SeekSlider::MouseUp
749 *****************************************************************************/
751 SeekSlider::MouseUp(BPoint where)
760 /*****************************************************************************
761 * SeekSlider::ResizeToPreferred
762 *****************************************************************************/
764 SeekSlider::ResizeToPreferred()
766 float width = 15.0 + StringWidth(DISABLED_SEEK_MESSAGE) + 15.0;
767 ResizeTo(width, 17.0);
770 /*****************************************************************************
771 * SeekSlider::SetPosition
772 *****************************************************************************/
774 SeekSlider::SetPosition(float position)
778 SetValue(fMinValue + (int32)floorf((fMaxValue - fMinValue) * position + 0.5));
783 /*****************************************************************************
784 * SeekSlider::_ValueFor
785 *****************************************************************************/
787 SeekSlider::_ValueFor(float xPos) const
790 float knobWidth2 = SEEK_SLIDER_KNOB_WIDTH / 2.0;
791 float sliderStart = (r.left + knobWidth2);
792 float sliderEnd = (r.right - knobWidth2);
793 int32 value = fMinValue + (int32)(((xPos - sliderStart) * (fMaxValue - fMinValue))
794 / (sliderEnd - sliderStart - 1.0));
795 if (value < fMinValue)
797 if (value > fMaxValue)
802 /*****************************************************************************
803 * SeekSlider::_StrokeFrame
804 *****************************************************************************/
806 SeekSlider::_StrokeFrame(BRect r, rgb_color left, rgb_color top,
807 rgb_color right, rgb_color bottom)
810 AddLine(BPoint(r.left, r.bottom), BPoint(r.left, r.top), left);
811 AddLine(BPoint(r.left + 1.0, r.top), BPoint(r.right, r.top), top);
812 AddLine(BPoint(r.right, r.top + 1.0), BPoint(r.right, r.bottom), right);
813 AddLine(BPoint(r.right - 1.0, r.bottom), BPoint(r.left + 1.0, r.bottom), bottom);
817 /*****************************************************************************
818 * SeekSlider::_BeginSeek
819 *****************************************************************************/
821 SeekSlider::_BeginSeek()
823 fOwner->fScrubSem = create_sem(0, "Vlc::fScrubSem");
824 if (fOwner->fScrubSem >= B_OK)
825 release_sem(fOwner->fScrubSem);
828 /*****************************************************************************
830 *****************************************************************************/
834 if (fOwner->fScrubSem >= B_OK)
835 delete_sem(fOwner->fScrubSem);
836 fOwner->fScrubSem = create_sem(0, "Vlc::fScrubSem");
837 if (fOwner->fScrubSem >= B_OK)
838 release_sem(fOwner->fScrubSem);
841 /*****************************************************************************
842 * SeekSlider::_EndSeek
843 *****************************************************************************/
845 SeekSlider::_EndSeek()
847 if (fOwner->fScrubSem >= B_OK)
848 delete_sem(fOwner->fScrubSem);
849 fOwner->fScrubSem = B_ERROR;
853 /*****************************************************************************
855 *****************************************************************************/
856 VolumeSlider::VolumeSlider(BRect frame, const char* name, int32 minValue, int32 maxValue,
857 BMessage* message, BHandler* target)
858 : BControl(frame, name, NULL, message, B_FOLLOW_NONE,
859 B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE),
861 fRightSideBits(NULL),
871 BRect r(BPoint(0.0, 0.0), kVolumeSliderBitmapSize);
872 fLeftSideBits = new BBitmap(r, B_CMAP8);
873 fRightSideBits = new BBitmap(r, B_CMAP8);
874 r.Set(0.0, 0.0, kVolumeSliderKnobBitmapSize.x, kVolumeSliderKnobBitmapSize.y);
875 fKnobBits = new BBitmap(r, B_CMAP8);
880 /*****************************************************************************
881 * VolumeSlider destructor
882 *****************************************************************************/
883 VolumeSlider::~VolumeSlider()
885 delete fLeftSideBits;
886 delete fRightSideBits;
890 /*****************************************************************************
891 * VolumeSlider::AttachedToWindow
892 *****************************************************************************/
894 VolumeSlider::AttachedToWindow()
896 BControl::AttachedToWindow();
897 SetViewColor(B_TRANSPARENT_32_BIT);
900 /*****************************************************************************
901 * VolumeSlider::SetValue
902 *****************************************************************************/
904 VolumeSlider::SetValue(int32 value)
906 if (value != Value())
908 BControl::SetValue(value);
913 /*****************************************************************************
914 * VolumeSlider::SetEnabled
915 *****************************************************************************/
917 VolumeSlider::SetEnabled(bool enable)
919 if (enable != IsEnabled())
921 BControl::SetEnabled(enable);
927 /*****************************************************************************
929 *****************************************************************************/
931 VolumeSlider::Draw(BRect updateRect)
936 float sliderSideWidth = kVolumeSliderBitmapWidth;
937 float sliderStart = (r.left + sliderSideWidth);
938 float sliderEnd = (r.right - sliderSideWidth);
939 float knobPos = sliderStart
940 + (sliderEnd - sliderStart - 1.0) * (Value() - fMinValue)
941 / (fMaxValue - fMinValue);
942 // draw both sides (the original from Be doesn't seem
943 // to make a difference for enabled/disabled state)
944 DrawBitmapAsync(fLeftSideBits, r.LeftTop());
945 DrawBitmapAsync(fRightSideBits, BPoint(sliderEnd + 1.0, r.top));
946 // colors for the slider area between the two bitmaps
947 rgb_color background = kBackground;//ui_color(B_PANEL_BACKGROUND_COLOR);
948 rgb_color shadow = tint_color(background, B_DARKEN_2_TINT);
949 rgb_color softShadow = tint_color(background, B_DARKEN_1_TINT);
950 rgb_color darkShadow = tint_color(background, B_DARKEN_4_TINT);
951 rgb_color midShadow = tint_color(background, B_DARKEN_3_TINT);
952 rgb_color light = tint_color(background, B_LIGHTEN_MAX_TINT);
953 rgb_color softLight = tint_color(background, B_LIGHTEN_1_TINT);
954 rgb_color green = kGreen;
955 rgb_color greenShadow = kGreenShadow;
956 rgb_color black = kBlack;
957 rgb_color dotGrey = midShadow;
958 rgb_color dotGreen = greenShadow;
959 // make dimmed version of colors if we're disabled
962 shadow = (rgb_color){ 200, 200, 200, 255 };
963 softShadow = dimmed_color_cmap8(softShadow, background, DIM_LEVEL);
964 darkShadow = dimmed_color_cmap8(darkShadow, background, DIM_LEVEL);
966 light = dimmed_color_cmap8(light, background, DIM_LEVEL);
967 softLight = dimmed_color_cmap8(softLight, background, DIM_LEVEL);
968 green = dimmed_color_cmap8(green, background, DIM_LEVEL);
969 greenShadow = dimmed_color_cmap8(greenShadow, background, DIM_LEVEL);
970 black = dimmed_color_cmap8(black, background, DIM_LEVEL);
975 green = tint_color(kBackground, B_DARKEN_3_TINT);
976 greenShadow = tint_color(kBackground, B_DARKEN_4_TINT);
977 dotGreen = greenShadow;
979 // draw slider edges between bitmaps
981 AddLine(BPoint(sliderStart, r.top),
982 BPoint(sliderEnd, r.top), softShadow);
983 AddLine(BPoint(sliderStart, r.bottom),
984 BPoint(sliderEnd, r.bottom), softLight);
986 AddLine(BPoint(sliderStart, r.top),
987 BPoint(sliderEnd, r.top), black);
988 AddLine(BPoint(sliderStart, r.bottom),
989 BPoint(sliderEnd, r.bottom), light);
991 AddLine(BPoint(sliderStart, r.top),
992 BPoint(knobPos, r.top), greenShadow);
993 AddLine(BPoint(knobPos, r.top),
994 BPoint(sliderEnd, r.top), midShadow);
996 AddLine(BPoint(sliderStart, r.top),
997 BPoint(knobPos, r.top), greenShadow);
999 // fill rest inside of slider
1000 r.InsetBy(0.0, 1.0);
1001 r.left = sliderStart;
1003 SetHighColor(green);
1004 FillRect(r, B_SOLID_HIGH);
1005 r.left = knobPos + 1.0;
1006 r.right = sliderEnd;
1008 SetHighColor(shadow);
1009 FillRect(r, B_SOLID_HIGH);
1010 // draw little dots inside
1011 int32 dotCount = (int32)((sliderEnd - sliderStart) / 5.0);
1013 dotPos.y = r.top + 4.0;
1014 for (int32 i = 0; i < dotCount; i++)
1016 dotPos.x = sliderStart + i * 5.0 + 4.0;
1017 SetHighColor(dotPos.x < knobPos ? dotGreen : dotGrey);
1018 StrokeLine(dotPos, BPoint(dotPos.x, dotPos.y + 1.0));
1022 SetDrawingMode(B_OP_OVER); // part of knob is transparent
1023 DrawBitmapAsync(fKnobBits, BPoint(knobPos - kVolumeSliderKnobWidth / 2, r.top));
1027 /*****************************************************************************
1028 * VolumeSlider::MouseDown
1029 *****************************************************************************/
1031 VolumeSlider::MouseDown(BPoint where)
1033 if (Bounds().Contains(where) && IsEnabled())
1036 SetValue(_ValueFor(where.x));
1037 SetMouseEventMask(B_POINTER_EVENTS, B_LOCK_WINDOW_FOCUS);
1041 /*****************************************************************************
1042 * VolumeSlider::MouseMoved
1043 *****************************************************************************/
1045 VolumeSlider::MouseMoved(BPoint where, uint32 transit, const BMessage* dragMessage)
1048 SetValue(_ValueFor(where.x));
1051 /*****************************************************************************
1052 * VolumeSlider::MouseUp
1053 *****************************************************************************/
1055 VolumeSlider::MouseUp(BPoint where)
1061 /*****************************************************************************
1062 * VolumeSlider::IsValid
1063 *****************************************************************************/
1065 VolumeSlider::IsValid() const
1067 return (fLeftSideBits && fLeftSideBits->IsValid()
1068 && fRightSideBits && fRightSideBits->IsValid()
1069 && fKnobBits && fKnobBits->IsValid());
1072 /*****************************************************************************
1073 * VolumeSlider::SetMuted
1074 *****************************************************************************/
1076 VolumeSlider::SetMuted(bool mute)
1086 /*****************************************************************************
1087 * VolumeSlider::_MakeBitmaps
1088 *****************************************************************************/
1090 VolumeSlider::_MakeBitmaps()
1094 // left side of slider
1095 memcpy(fLeftSideBits->Bits(), kVolumeSliderLeftBitmapBits,
1096 fLeftSideBits->BitsLength());
1097 // right side of slider
1098 memcpy(fRightSideBits->Bits(), kVolumeSliderRightBits,
1099 fRightSideBits->BitsLength());
1101 int32 length = fKnobBits->BitsLength();
1102 memcpy(fKnobBits->Bits(), kVolumeSliderKnobBits, length);
1103 uint8* bits = (uint8*)fKnobBits->Bits();
1104 // black was used in the knob to represent transparency
1105 // use screen to get index for the "transarent" color used in the bitmap
1106 BScreen screen(B_MAIN_SCREEN_ID);
1107 uint8 blackIndex = screen.IndexForColor(kBlack);
1108 // replace black index with transparent index
1109 for (int32 i = 0; i < length; i++)
1110 if (bits[i] == blackIndex)
1111 bits[i] = B_TRANSPARENT_MAGIC_CMAP8;
1115 // make ghosted versions of the bitmaps
1116 dim_bitmap(fLeftSideBits, kBackground, DIM_LEVEL);
1117 dim_bitmap(fRightSideBits, kBackground, DIM_LEVEL);
1118 dim_bitmap(fKnobBits, kBackground, DIM_LEVEL);
1122 // replace green color (and shadow) in left slider side
1123 bits = (uint8*)fLeftSideBits->Bits();
1124 length = fLeftSideBits->BitsLength();
1125 uint8 greenIndex = screen.IndexForColor(kGreen);
1126 uint8 greenShadowIndex = screen.IndexForColor(kGreenShadow);
1127 rgb_color shadow = tint_color(kBackground, B_DARKEN_3_TINT);
1128 rgb_color midShadow = tint_color(kBackground, B_DARKEN_4_TINT);
1129 uint8 replaceIndex = screen.IndexForColor(shadow);
1130 uint8 replaceShadowIndex = screen.IndexForColor(midShadow);
1131 for (int32 i = 0; i < length; i++)
1133 if (bits[i] == greenIndex)
1134 bits[i] = replaceIndex;
1135 else if (bits[i] == greenShadowIndex)
1136 bits[i] = replaceShadowIndex;
1142 /*****************************************************************************
1143 * VolumeSlider::_ValueFor
1144 *****************************************************************************/
1146 VolumeSlider::_ValueFor(float xPos) const
1149 float sliderStart = (r.left + kVolumeSliderBitmapWidth);
1150 float sliderEnd = (r.right - kVolumeSliderBitmapWidth);
1151 int32 value = fMinValue + (int32)(((xPos - sliderStart) * (fMaxValue - fMinValue))
1152 / (sliderEnd - sliderStart - 1.0));
1153 if (value < fMinValue)
1155 if (value > fMaxValue)
1160 /*****************************************************************************
1161 * PositionInfoView::PositionInfoView
1162 *****************************************************************************/
1163 PositionInfoView::PositionInfoView( BRect frame, const char* name,
1164 intf_thread_t * p_interface )
1165 : BView( frame, name, B_FOLLOW_NONE,
1166 B_WILL_DRAW | B_PULSE_NEEDED | B_FULL_UPDATE_ON_RESIZE ),
1167 fMode( MODE_SMALL ),
1168 fCurrentFileIndex( -1 ),
1169 fCurrentFileSize( -1 ),
1170 fCurrentTitleIndex( -1 ),
1171 fCurrentTitleSize( -1 ),
1172 fCurrentChapterIndex( -1 ),
1173 fCurrentChapterSize( -1 ),
1175 fTimeString( "-:--:--" ),
1176 fLastPulseUpdate( system_time() ),
1177 fStackedWidthCache( 0.0 ),
1178 fStackedHeightCache( 0.0 )
1180 p_intf = p_interface;
1182 SetViewColor( B_TRANSPARENT_32_BIT );
1183 SetLowColor( kBlack );
1184 SetHighColor( 0, 255, 0, 255 );
1185 SetFontSize( 11.0 );
1188 /*****************************************************************************
1189 * PositionInfoView::~PositionInfoView
1190 *****************************************************************************/
1191 PositionInfoView::~PositionInfoView()
1195 /*****************************************************************************
1196 * PositionInfoView::Draw
1197 *****************************************************************************/
1199 PositionInfoView::Draw( BRect updateRect )
1201 rgb_color background = ui_color( B_PANEL_BACKGROUND_COLOR );
1202 rgb_color shadow = tint_color( background, B_DARKEN_1_TINT );
1203 rgb_color darkShadow = tint_color( background, B_DARKEN_4_TINT );
1204 rgb_color light = tint_color( background, B_LIGHTEN_MAX_TINT );
1205 rgb_color softLight = tint_color( background, B_LIGHTEN_1_TINT );
1207 BRect r( Bounds() );
1208 BeginLineArray( 8 );
1209 AddLine( BPoint( r.left, r.bottom ),
1210 BPoint( r.left, r.top ), shadow );
1211 AddLine( BPoint( r.left + 1.0, r.top ),
1212 BPoint( r.right, r.top ), shadow );
1213 AddLine( BPoint( r.right, r.top + 1.0 ),
1214 BPoint( r.right, r.bottom ), softLight );
1215 AddLine( BPoint( r.right - 1.0, r.bottom ),
1216 BPoint( r.left + 1.0, r.bottom ), softLight );
1217 r.InsetBy( 1.0, 1.0 );
1218 AddLine( BPoint( r.left, r.bottom ),
1219 BPoint( r.left, r.top ), darkShadow );
1220 AddLine( BPoint( r.left + 1.0, r.top ),
1221 BPoint( r.right, r.top ), darkShadow );
1222 AddLine( BPoint( r.right, r.top + 1.0 ),
1223 BPoint( r.right, r.bottom ), light );
1224 AddLine( BPoint( r.right - 1.0, r.bottom ),
1225 BPoint( r.left + 1.0, r.bottom ), light );
1228 r.InsetBy( 1.0, 1.0 );
1229 FillRect( r, B_SOLID_LOW );
1232 GetFontHeight( &fh );
1237 float width = StringWidth( fTimeString.String() );
1238 DrawString( fTimeString.String(),
1239 BPoint( r.left + r.Width() / 2.0 - width / 2.0,
1240 r.top + r.Height() / 2.0 + fh.ascent / 2.0 - 1.0 ) );
1247 BFont smallFont = font;
1248 BFont bigFont = font;
1249 BFont tinyFont = font;
1250 smallFont.SetSize( r.Height() / 5.0 );
1251 bigFont.SetSize( r.Height() / 3.0 );
1252 tinyFont.SetSize( r.Height() / 7.0 );
1253 float timeHeight = r.Height() / 2.5;
1254 float height = ( r.Height() - timeHeight ) / 3.0;
1255 SetFont( &tinyFont );
1256 SetHighColor( 0, 180, 0, 255 );
1257 DrawString( _("File"), BPoint( r.left + 3.0, r.top + height ) );
1258 DrawString( _("Title"), BPoint( r.left + 3.0, r.top + 2.0 * height ) );
1259 DrawString( _("Chapter"), BPoint( r.left + 3.0, r.top + 3.0 * height ) );
1260 SetFont( &smallFont );
1262 SetHighColor( 0, 255, 0, 255 );
1264 _MakeString( helper, fCurrentFileIndex, fCurrentFileSize );
1265 float width = StringWidth( helper.String() );
1266 DrawString( helper.String(), BPoint( r.right - 3.0 - width, r.top + height ) );
1268 _MakeString( helper, fCurrentTitleIndex, fCurrentTitleSize );
1269 width = StringWidth( helper.String() );
1270 DrawString( helper.String(), BPoint( r.right - 3.0 - width, r.top + 2.0 * height ) );
1272 _MakeString( helper, fCurrentChapterIndex, fCurrentChapterSize );
1273 width = StringWidth( helper.String() );
1274 DrawString( helper.String(), BPoint( r.right - 3.0 - width, r.top + 3.0 * height ) );
1276 SetFont( &bigFont );
1277 width = StringWidth( fTimeString.String() );
1278 DrawString( fTimeString.String(),
1279 BPoint( r.left + r.Width() / 2.0 - width / 2.0,
1286 /*****************************************************************************
1287 * PositionInfoView::ResizeToPreferred
1288 *****************************************************************************/
1290 PositionInfoView::ResizeToPreferred()
1292 float width, height;
1293 GetPreferredSize( &width, &height );
1294 ResizeTo( width, height );
1297 /*****************************************************************************
1298 * PositionInfoView::GetPreferredSize
1299 *****************************************************************************/
1301 PositionInfoView::GetPreferredSize( float* width, float* height )
1303 if ( width && height )
1305 *width = 5.0 + ceilf( StringWidth( "0:00:00" ) ) + 5.0;
1307 GetFontHeight( &fh );
1308 *height = 3.0 + ceilf( fh.ascent ) + 3.0;
1309 fStackedWidthCache = *width * 1.2;
1310 fStackedHeightCache = *height * 2.7;
1314 /*****************************************************************************
1315 * PositionInfoView::Pulse
1316 *****************************************************************************/
1318 PositionInfoView::Pulse()
1320 // allow for Pulse frequency to be higher, MediaControlView needs it
1321 bigtime_t now = system_time();
1322 if ( now - fLastPulseUpdate > 900000 )
1325 p_intf->p_sys->p_wrapper->GetPlaylistInfo( index, size );
1326 SetFile( index + 1, size );
1327 p_intf->p_sys->p_wrapper->TitleInfo( index, size );
1328 SetTitle( index, size );
1329 p_intf->p_sys->p_wrapper->ChapterInfo( index, size );
1330 SetChapter( index, size );
1331 SetTime( p_intf->p_sys->p_wrapper->GetTimeAsString() );
1332 fLastPulseUpdate = now;
1336 /*****************************************************************************
1337 * PositionInfoView::GetBigPreferredSize
1338 *****************************************************************************/
1340 PositionInfoView::GetBigPreferredSize( float* width, float* height )
1342 if ( width && height )
1344 *width = fStackedWidthCache;
1345 *height = fStackedHeightCache;
1349 /*****************************************************************************
1350 * PositionInfoView::SetMode
1351 *****************************************************************************/
1353 PositionInfoView::SetMode( uint32 mode )
1355 if ( fMode != mode )
1358 _InvalidateContents();
1362 /*****************************************************************************
1363 * PositionInfoView::SetFile
1364 *****************************************************************************/
1366 PositionInfoView::SetFile( int32 index, int32 size )
1368 if ( fCurrentFileIndex != index || fCurrentFileSize != size )
1370 fCurrentFileIndex = index;
1371 fCurrentFileSize = size;
1372 _InvalidateContents();
1376 /*****************************************************************************
1377 * PositionInfoView::SetTitle
1378 *****************************************************************************/
1380 PositionInfoView::SetTitle( int32 index, int32 size )
1382 if ( fCurrentTitleIndex != index || fCurrentFileSize != size )
1384 fCurrentTitleIndex = index;
1385 fCurrentTitleSize = size;
1386 _InvalidateContents();
1390 /*****************************************************************************
1391 * PositionInfoView::SetChapter
1392 *****************************************************************************/
1394 PositionInfoView::SetChapter( int32 index, int32 size )
1396 if ( fCurrentChapterIndex != index || fCurrentFileSize != size )
1398 fCurrentChapterIndex = index;
1399 fCurrentChapterSize = size;
1400 _InvalidateContents();
1404 /*****************************************************************************
1405 * PositionInfoView::SetTime
1406 *****************************************************************************/
1408 PositionInfoView::SetTime( int32 seconds )
1410 if ( fSeconds != seconds )
1414 int32 minutes = seconds / 60;
1415 int32 hours = minutes / 60;
1416 seconds -= minutes * 60 - hours * 60 * 60;
1417 minutes -= hours * 60;
1418 fTimeString.SetTo( "" );
1419 fTimeString << hours << ":" << minutes << ":" << seconds;
1422 fTimeString.SetTo( "-:--:--" );
1425 _InvalidateContents();
1429 /*****************************************************************************
1430 * PositionInfoView::SetTime
1431 *****************************************************************************/
1433 PositionInfoView::SetTime( const char* string )
1435 fTimeString.SetTo( string );
1436 _InvalidateContents();
1439 /*****************************************************************************
1440 * PositionInfoView::_InvalidateContents
1441 *****************************************************************************/
1443 PositionInfoView::_InvalidateContents( uint32 which )
1445 BRect r( Bounds() );
1446 r.InsetBy( 2.0, 2.0 );
1450 /*****************************************************************************
1451 * PositionInfoView::_InvalidateContents
1452 *****************************************************************************/
1454 PositionInfoView::_MakeString( BString& into, int32 index, int32 maxIndex ) const
1457 if ( index >= 0 && maxIndex >= 0 )
1462 if ( maxIndex >= 0 )