1 /*****************************************************************************
2 * MediaControlView.cpp: beos interface
3 *****************************************************************************
4 * Copyright (C) 1999, 2000, 2001 VideoLAN
5 * $Id: MediaControlView.cpp,v 1.21 2003/12/28 01:49:12 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>
36 #include <audio_output.h>
39 /* BeOS interface headers */
40 #include "VlcWrapper.h"
42 #include "DrawingTidbits.h"
43 #include "InterfaceWindow.h"
45 #include "TransportButton.h"
46 #include "ListViews.h"
47 #include "MediaControlView.h"
49 #define BORDER_INSET 6.0
51 #define SPEAKER_SLIDER_DIST 6.0
52 #define VOLUME_MIN_WIDTH 70.0
54 #define VOLUME_SLIDER_LAYOUT_WEIGHT 2.0
55 #define SEEK_SLIDER_KNOB_WIDTH 8.0
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 };
68 #define DISABLED_SEEK_MESSAGE _("Drop files to play")
74 MSG_SKIP_BACKWARDS = 'skpb',
75 MSG_SKIP_FORWARD = 'skpf',
79 MediaControlView::MediaControlView(BRect frame, intf_thread_t *p_interface)
80 : BBox(frame, NULL, B_FOLLOW_NONE, B_WILL_DRAW | B_FRAME_EVENTS | B_PULSE_NEEDED,
83 fCurrentRate(DEFAULT_RATE),
84 fCurrentStatus(UNDEF_S),
85 fBottomControlHeight(0.0),
90 BRect frame(0.0, 0.0, 10.0, 10.0);
93 fSeekSlider = new SeekSlider( frame, "seek slider", this,
94 0, SEEKSLIDER_RANGE );
95 fSeekSlider->SetValue(0);
96 fSeekSlider->ResizeToPreferred();
97 AddChild( fSeekSlider );
101 frame.SetRightBottom(kSkipButtonSize);
102 fBottomControlHeight = kRewindBitmapHeight - 1.0;
103 fSkipBack = new TransportButton(frame, B_EMPTY_STRING,
105 kPressedSkipBackBitmapBits,
106 kDisabledSkipBackBitmapBits,
107 new BMessage(MSG_SKIP_BACKWARDS));
108 AddChild( fSkipBack );
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));
124 AddChild( fPlayPause );
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 );
136 fForward = new TransportButton(frame, B_EMPTY_STRING,
138 kPressedForwardBitmapBits,
139 kDisabledForwardBitmapBits,
140 new BMessage(MSG_FORWARD));
141 // AddChild( fForward );
144 fRewind = new TransportButton(frame, B_EMPTY_STRING,
146 kPressedRewindBitmapBits,
147 kDisabledRewindBitmapBits,
148 new BMessage(MSG_REWIND));
149 // AddChild( fRewind );
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));
163 frame.SetRightBottom(kSpeakerButtonSize);
164 if (fBottomControlHeight < kSpeakerIconBitmapHeight - 1.0)
165 fBottomControlHeight = kSpeakerIconBitmapHeight - 1.0;
166 fMute = new TransportButton(frame, B_EMPTY_STRING,
168 kPressedSpeakerIconBits,
170 new BMessage(VOLUME_MUTE));
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 );
182 // Position Info View
183 fPositionInfo = new PositionInfoView(BRect(0.0, 0.0, 10.0, 10.0), "led",
185 fPositionInfo->ResizeToPreferred();
186 AddChild( fPositionInfo );
190 MediaControlView::~MediaControlView()
196 MediaControlView::AttachedToWindow()
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());
205 BRect r(_MinFrame());
206 if (BMenuBar* menuBar = Window()->KeyMenuBar())
207 r.bottom += menuBar->Bounds().Height();
209 Window()->SetSizeLimits(r.Width(), r.Width() * 1.8, r.Height(), r.Height() * 1.3);
210 if (!Window()->Bounds().Contains(r))
211 Window()->ResizeTo(r.Width(), r.Height());
213 FrameResized(Bounds().Width(), Bounds().Height());
215 // get pulse message every two frames
216 Window()->SetPulseRate(80000);
221 MediaControlView::FrameResized(float width, float height)
224 // make sure we don't leave dirty pixels
225 // (B_FULL_UPDATE_ON_RESIZE == annoying flicker -> this is smarter)
226 if (fOldBounds.Width() < r.Width())
227 Invalidate(BRect(fOldBounds.right, fOldBounds.top + 1.0,
228 fOldBounds.right, fOldBounds.bottom - 1.0));
230 Invalidate(BRect(r.right, r.top + 1.0,
231 r.right, r.bottom - 1.0));
232 if (fOldBounds.Height() < r.Height())
233 Invalidate(BRect(fOldBounds.left + 1.0, fOldBounds.bottom,
234 fOldBounds.right - 1.0, fOldBounds.bottom));
236 Invalidate(BRect(r.left + 1.0, r.bottom,
237 r.right - 1.0, r.bottom));
238 // remember for next time
241 r.InsetBy(BORDER_INSET, BORDER_INSET);
247 MediaControlView::GetPreferredSize(float* width, float* height)
251 BRect r(_MinFrame());
253 *height = r.Height();
259 MediaControlView::MessageReceived(BMessage* message)
261 switch (message->what)
267 case MSG_SKIP_BACKWARDS:
268 Window()->PostMessage(NAVIGATE_PREV);
270 case MSG_SKIP_FORWARD:
271 Window()->PostMessage(NAVIGATE_NEXT);
274 BBox::MessageReceived(message);
281 MediaControlView::Pulse()
283 InterfaceWindow* window = dynamic_cast<InterfaceWindow*>(Window());
284 if (window && window->IsStopped())
285 fPlayPause->SetStopped();
287 unsigned short i_volume;
288 aout_VolumeGet( p_intf, (audio_volume_t*)&i_volume );
289 fVolumeSlider->SetValue( i_volume );
294 MediaControlView::SetProgress( float position )
296 fSeekSlider->SetPosition( position );
301 MediaControlView::SetStatus(int status, int rate)
303 // we need to set the button status periodically
304 // (even if it is the same) to get a blinking button
305 fCurrentStatus = status;
311 fPlayPause->SetPlaying();
314 fPlayPause->SetPaused();
318 fPlayPause->SetStopped();
321 if (rate != fCurrentRate)
324 if ( rate < DEFAULT_RATE )
333 MediaControlView::SetEnabled(bool enabled)
335 if( ( enabled && fIsEnabled ) ||
336 ( !enabled && !fIsEnabled ) )
338 /* do not redraw if it is not necessary */
344 fSkipBack->SetEnabled( enabled );
345 fPlayPause->SetEnabled( enabled );
346 fSkipForward->SetEnabled( enabled );
347 fStop->SetEnabled( enabled );
348 fMute->SetEnabled( enabled );
349 fVolumeSlider->SetEnabled( enabled );
350 fSeekSlider->SetEnabled( enabled );
351 fRewind->SetEnabled( enabled );
352 fForward->SetEnabled( enabled );
354 fIsEnabled = enabled;
360 MediaControlView::SetAudioEnabled(bool enabled)
362 fMute->SetEnabled(enabled);
363 fVolumeSlider->SetEnabled(enabled);
368 MediaControlView::GetSeekTo() const
370 return fSeekSlider->Value();
375 MediaControlView::GetVolume() const
377 return fVolumeSlider->Value();
382 MediaControlView::SetSkippable(bool backward, bool forward)
384 fSkipBack->SetEnabled(backward);
385 fSkipForward->SetEnabled(forward);
390 MediaControlView::SetMuted(bool mute)
392 fVolumeSlider->SetMuted(mute);
397 MediaControlView::_LayoutControls(BRect frame) const
401 // calculate absolutly minimal width
402 float minWidth = fSkipBack->Bounds().Width();
403 // minWidth += fRewind->Bounds().Width();
404 minWidth += fStop->Bounds().Width();
405 minWidth += fPlayPause->Bounds().Width();
406 // minWidth += fForward->Bounds().Width();
407 minWidth += fSkipForward->Bounds().Width();
408 minWidth += fMute->Bounds().Width();
409 minWidth += VOLUME_MIN_WIDTH;
411 // layout time slider and info view
413 fPositionInfo->GetBigPreferredSize( &width, &height );
414 float ratio = width / height;
415 width = r.Height() * ratio;
416 if (frame.Width() - minWidth - MIN_SPACE >= width
417 && frame.Height() >= height)
419 r.right = r.left + width;
420 fPositionInfo->SetMode(PositionInfoView::MODE_BIG);
421 _LayoutControl(fPositionInfo, r, true, true);
422 frame.left = r.right + MIN_SPACE;
424 r.right = frame.right;
425 // r.bottom = r.top + r.Height() / 2.0 - MIN_SPACE / 2.0;
426 r.bottom = r.top + fSeekSlider->Bounds().Height();
427 _LayoutControl(fSeekSlider, r, true);
431 fPositionInfo->GetPreferredSize( &width, &height );
432 fPositionInfo->SetMode(PositionInfoView::MODE_SMALL);
433 fPositionInfo->ResizeTo(width, height);
434 r.bottom = r.top + r.Height() / 2.0 - MIN_SPACE / 2.0;
435 r.right = r.left + fPositionInfo->Bounds().Width();
436 _LayoutControl(fPositionInfo, r, true );
437 r.left = r.right + MIN_SPACE;
438 r.right = frame.right;
439 _LayoutControl(fSeekSlider, r, true);
441 float currentWidth = frame.Width();
442 float space = (currentWidth - minWidth) / 6.0;//8.0;
444 space = MIN_SPACE + (space - MIN_SPACE) / VOLUME_SLIDER_LAYOUT_WEIGHT;
445 // layout controls with "space" inbetween
447 r.top = r.bottom + MIN_SPACE + 1.0;
448 r.bottom = frame.bottom;
450 r.right = r.left + fSkipBack->Bounds().Width();
451 _LayoutControl(fSkipBack, r);
453 // r.left = r.right + space;
454 // r.right = r.left + fRewind->Bounds().Width();
455 // _LayoutControl(fRewind, r);
457 r.left = r.right + space;
458 r.right = r.left + fStop->Bounds().Width();
459 _LayoutControl(fStop, r);
461 r.left = r.right + space;
462 r.right = r.left + fPlayPause->Bounds().Width();
463 _LayoutControl(fPlayPause, r);
465 // r.left = r.right + space;
466 // r.right = r.left + fForward->Bounds().Width();
467 // _LayoutControl(fForward, r);
469 r.left = r.right + space;
470 r.right = r.left + fSkipForward->Bounds().Width();
471 _LayoutControl(fSkipForward, r);
473 r.left = r.right + space + space;
474 r.right = r.left + fMute->Bounds().Width();
475 _LayoutControl(fMute, r);
477 r.left = r.right + SPEAKER_SLIDER_DIST; // keep speaker icon and volume slider attached
478 r.right = frame.right;
479 _LayoutControl(fVolumeSlider, r, true);
484 MediaControlView::_MinFrame() const
486 // add up width of controls along bottom (seek slider will likely adopt)
487 float minWidth = 2 * BORDER_INSET;
488 minWidth += fSkipBack->Bounds().Width() + MIN_SPACE;
489 // minWidth += fRewind->Bounds().Width() + MIN_SPACE;
490 minWidth += fStop->Bounds().Width() + MIN_SPACE;
491 minWidth += fPlayPause->Bounds().Width() + MIN_SPACE;
492 // minWidth += fForward->Bounds().Width() + MIN_SPACE;
493 minWidth += fSkipForward->Bounds().Width() + MIN_SPACE + MIN_SPACE;
494 minWidth += fMute->Bounds().Width() + SPEAKER_SLIDER_DIST;
495 minWidth += VOLUME_MIN_WIDTH;
497 // add up height of seek slider and heighest control on bottom
498 float minHeight = 2 * BORDER_INSET;
499 minHeight += fSeekSlider->Bounds().Height() + MIN_SPACE + MIN_SPACE / 2.0;
500 minHeight += fBottomControlHeight;
501 return BRect(0.0, 0.0, minWidth - 1.0, minHeight - 1.0);
506 MediaControlView::_LayoutControl(BView* view, BRect frame,
507 bool resizeWidth, bool resizeHeight) const
511 frame.top = (frame.top + frame.bottom) / 2.0 - view->Bounds().Height() / 2.0;
513 //center horizontally
514 frame.left = (frame.left + frame.right) / 2.0 - view->Bounds().Width() / 2.0;
515 view->MoveTo(frame.LeftTop());
516 float width = resizeWidth ? frame.Width() : view->Bounds().Width();
517 float height = resizeHeight ? frame.Height() : view->Bounds().Height();
518 if (resizeWidth || resizeHeight)
519 view->ResizeTo(width, height);
524 /*****************************************************************************
526 *****************************************************************************/
527 SeekSlider::SeekSlider(BRect frame, const char* name, MediaControlView *owner,
528 int32 minValue, int32 maxValue)
529 : BControl(frame, name, NULL, NULL, B_FOLLOW_NONE,
530 B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE),
536 BFont font(be_plain_font);
541 SeekSlider::~SeekSlider()
546 /*****************************************************************************
547 * VolumeSlider::AttachedToWindow
548 *****************************************************************************/
550 SeekSlider::AttachedToWindow()
552 BControl::AttachedToWindow();
553 SetViewColor(B_TRANSPARENT_32_BIT);
556 /*****************************************************************************
558 *****************************************************************************/
560 SeekSlider::Draw(BRect updateRect)
563 float knobWidth2 = SEEK_SLIDER_KNOB_WIDTH / 2.0;
564 float sliderStart = (r.left + knobWidth2);
565 float sliderEnd = (r.right - knobWidth2);
566 float knobPos = sliderStart
567 + floorf((sliderEnd - sliderStart - 1.0) * (Value() - fMinValue)
568 / (fMaxValue - fMinValue) + 0.5);
569 // draw both sides (the original from Be doesn't seem
570 // to make a difference for enabled/disabled state)
571 // DrawBitmapAsync(fLeftSideBits, r.LeftTop());
572 // DrawBitmapAsync(fRightSideBits, BPoint(sliderEnd + 1.0, r.top));
573 // colors for the slider area between the two bitmaps
574 rgb_color background = kBackground;//ui_color(B_PANEL_BACKGROUND_COLOR);
575 rgb_color shadow = tint_color(background, B_DARKEN_2_TINT);
576 rgb_color softShadow = tint_color(background, B_DARKEN_1_TINT);
577 rgb_color darkShadow = tint_color(background, B_DARKEN_4_TINT);
578 rgb_color midShadow = tint_color(background, B_DARKEN_3_TINT);
579 rgb_color light = tint_color(background, B_LIGHTEN_MAX_TINT);
580 rgb_color softLight = tint_color(background, B_LIGHTEN_1_TINT);
581 rgb_color green = kSeekGreen;
582 rgb_color greenShadow = kSeekGreenShadow;
583 rgb_color black = kBlack;
584 rgb_color dotGrey = midShadow;
585 rgb_color dotGreen = greenShadow;
587 _StrokeFrame(r, softShadow, softShadow, softLight, softLight);
589 _StrokeFrame(r, black, black, light, light);
594 _StrokeFrame(r, greenShadow, greenShadow, green, green);
597 _StrokeFrame(r, greenShadow, greenShadow, green, green);
603 int32 dotCount = (int32)(r.Width() / 6.0);
605 dotPos.y = r.top + 2.0;
606 SetHighColor(dotGreen);
607 for (int32 i = 0; i < dotCount; i++)
609 dotPos.x = sliderStart + i * 6.0 + 5.0;
610 StrokeLine(dotPos, BPoint(dotPos.x, dotPos.y + 6.0));
615 r.left = knobPos - knobWidth2;
616 r.right = knobPos + knobWidth2;
618 float handleBottomSize = 2.0;
619 float handleArrowSize = 6.0;
622 AddLine(BPoint(r.left, r.top + handleBottomSize),
623 BPoint(r.left, r.top), black);
624 AddLine(BPoint(r.left + 1.0, r.top),
625 BPoint(r.right, r.top), black);
626 AddLine(BPoint(r.right, r.top + 1.0),
627 BPoint(r.right, r.top + handleBottomSize), black);
628 AddLine(BPoint(r.right - 1.0, r.top + handleBottomSize + 1.0),
629 BPoint(knobPos, r.top + handleArrowSize), black);
630 AddLine(BPoint(knobPos - 1.0, r.top + handleArrowSize - 1.0),
631 BPoint(r.left + 1.0, r.top + handleBottomSize + 1.0), black);
633 AddLine(BPoint(r.left, r.bottom),
634 BPoint(r.left, r.bottom - handleBottomSize), black);
635 AddLine(BPoint(r.left + 1.0, r.bottom - handleBottomSize - 1.0),
636 BPoint(knobPos, r.bottom - handleArrowSize), black);
637 AddLine(BPoint(knobPos + 1.0, r.bottom - handleArrowSize + 1.0),
638 BPoint(r.right, r.bottom - handleBottomSize), black);
639 AddLine(BPoint(r.right, r.bottom - handleBottomSize + 1.0),
640 BPoint(r.right, r.bottom), black);
641 AddLine(BPoint(r.right - 1.0, r.bottom),
642 BPoint(r.left + 1.0, r.bottom), black);
644 // inner red light and shadow lines
647 handleArrowSize -= 2.0;
650 AddLine(BPoint(r.left, r.top + handleBottomSize),
651 BPoint(r.left, r.top), kSeekRedLight);
652 AddLine(BPoint(r.left + 1.0, r.top),
653 BPoint(r.right, r.top), kSeekRedLight);
654 AddLine(BPoint(r.right, r.top + 1.0),
655 BPoint(r.right, r.top + handleBottomSize), kSeekRedShadow);
656 AddLine(BPoint(r.right - 1.0, r.top + handleBottomSize + 1.0),
657 BPoint(knobPos, r.top + handleArrowSize), kSeekRedShadow);
658 AddLine(BPoint(knobPos - 1.0, r.top + handleArrowSize - 1.0),
659 BPoint(r.left + 1.0, r.top + handleBottomSize + 1.0), kSeekRedLight);
661 AddLine(BPoint(r.left, r.bottom),
662 BPoint(r.left, r.bottom - handleBottomSize), kSeekRedLight);
663 AddLine(BPoint(r.left + 1.0, r.bottom - handleBottomSize - 1.0),
664 BPoint(knobPos, r.bottom - handleArrowSize), kSeekRedLight);
665 AddLine(BPoint(knobPos + 1.0, r.bottom - handleArrowSize + 1.0),
666 BPoint(r.right, r.bottom - handleBottomSize), kSeekRedShadow);
667 AddLine(BPoint(r.right, r.bottom - handleBottomSize + 1.0),
668 BPoint(r.right, r.bottom), kSeekRedShadow);
669 AddLine(BPoint(r.right - 1.0, r.bottom),
670 BPoint(r.left + 1.0, r.bottom), kSeekRedShadow);
672 // fill rest of handles with red
673 SetHighColor(kSeekRed);
675 handleArrowSize -= 2.0;
677 // upper handle arrow
680 arrow[1].x = r.right;
682 arrow[2].x = knobPos;
683 arrow[2].y = r.top + handleArrowSize;
684 FillPolygon(arrow, 3);
685 // lower handle arrow
687 arrow[0].y = r.bottom;
688 arrow[1].x = r.right;
689 arrow[1].y = r.bottom;
690 arrow[2].x = knobPos;
691 arrow[2].y = r.bottom - handleArrowSize;
692 FillPolygon(arrow, 3);
697 _StrokeFrame(r, darkShadow, darkShadow, darkShadow, darkShadow);
699 _StrokeFrame(r, darkShadow, darkShadow, darkShadow, darkShadow);
701 SetHighColor(darkShadow);
704 float width = floorf(StringWidth(DISABLED_SEEK_MESSAGE));
705 float textPos = r.left + r.Width() / 2.0 - width / 2.0;
706 pattern stripes = {{ 0xc7, 0x8f, 0x1f, 0x3e, 0x7c, 0xf8, 0xf1, 0xe3 }};
707 BRect stripesRect(r);
708 stripesRect.right = textPos - 5.0;
709 FillRect(stripesRect, stripes);
710 stripesRect.left = textPos + width + 3.0;
711 stripesRect.right = r.right;
712 FillRect(stripesRect, stripes);
714 r.left = textPos - 4.0;
715 r.right = textPos + width + 2.0;
717 SetHighColor(shadow);
718 SetLowColor(darkShadow);
721 DrawString(DISABLED_SEEK_MESSAGE, BPoint(textPos, r.top + ceilf(fh.ascent) - 1.0));
725 /*****************************************************************************
726 * SeekSlider::MouseDown
727 *****************************************************************************/
729 SeekSlider::MouseDown(BPoint where)
731 if (IsEnabled() && Bounds().Contains(where))
733 SetValue(_ValueFor(where.x));
735 SetMouseEventMask(B_POINTER_EVENTS, B_LOCK_WINDOW_FOCUS);
740 /*****************************************************************************
741 * SeekSlider::MouseMoved
742 *****************************************************************************/
744 SeekSlider::MouseMoved(BPoint where, uint32 code, const BMessage* dragMessage)
748 SetValue(_ValueFor(where.x));
753 /*****************************************************************************
754 * SeekSlider::MouseUp
755 *****************************************************************************/
757 SeekSlider::MouseUp(BPoint where)
766 /*****************************************************************************
767 * SeekSlider::ResizeToPreferred
768 *****************************************************************************/
770 SeekSlider::ResizeToPreferred()
772 float width = 15.0 + StringWidth(DISABLED_SEEK_MESSAGE) + 15.0;
773 ResizeTo(width, 17.0);
776 /*****************************************************************************
777 * SeekSlider::SetPosition
778 *****************************************************************************/
780 SeekSlider::SetPosition(float position)
784 SetValue(fMinValue + (int32)floorf((fMaxValue - fMinValue) * position + 0.5));
789 /*****************************************************************************
790 * SeekSlider::_ValueFor
791 *****************************************************************************/
793 SeekSlider::_ValueFor(float xPos) const
796 float knobWidth2 = SEEK_SLIDER_KNOB_WIDTH / 2.0;
797 float sliderStart = (r.left + knobWidth2);
798 float sliderEnd = (r.right - knobWidth2);
799 int32 value = fMinValue + (int32)(((xPos - sliderStart) * (fMaxValue - fMinValue))
800 / (sliderEnd - sliderStart - 1.0));
801 if (value < fMinValue)
803 if (value > fMaxValue)
808 /*****************************************************************************
809 * SeekSlider::_StrokeFrame
810 *****************************************************************************/
812 SeekSlider::_StrokeFrame(BRect r, rgb_color left, rgb_color top,
813 rgb_color right, rgb_color bottom)
816 AddLine(BPoint(r.left, r.bottom), BPoint(r.left, r.top), left);
817 AddLine(BPoint(r.left + 1.0, r.top), BPoint(r.right, r.top), top);
818 AddLine(BPoint(r.right, r.top + 1.0), BPoint(r.right, r.bottom), right);
819 AddLine(BPoint(r.right - 1.0, r.bottom), BPoint(r.left + 1.0, r.bottom), bottom);
823 /*****************************************************************************
824 * SeekSlider::_BeginSeek
825 *****************************************************************************/
827 SeekSlider::_BeginSeek()
829 fOwner->fScrubSem = create_sem(0, "Vlc::fScrubSem");
830 if (fOwner->fScrubSem >= B_OK)
831 release_sem(fOwner->fScrubSem);
834 /*****************************************************************************
836 *****************************************************************************/
840 if (fOwner->fScrubSem >= B_OK)
841 delete_sem(fOwner->fScrubSem);
842 fOwner->fScrubSem = create_sem(0, "Vlc::fScrubSem");
843 if (fOwner->fScrubSem >= B_OK)
844 release_sem(fOwner->fScrubSem);
847 /*****************************************************************************
848 * SeekSlider::_EndSeek
849 *****************************************************************************/
851 SeekSlider::_EndSeek()
853 if (fOwner->fScrubSem >= B_OK)
854 delete_sem(fOwner->fScrubSem);
855 fOwner->fScrubSem = B_ERROR;
859 /*****************************************************************************
861 *****************************************************************************/
862 VolumeSlider::VolumeSlider(BRect frame, const char* name, int32 minValue, int32 maxValue,
863 BMessage* message, BHandler* target)
864 : BControl(frame, name, NULL, message, B_FOLLOW_NONE,
865 B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE),
867 fRightSideBits(NULL),
877 BRect r(BPoint(0.0, 0.0), kVolumeSliderBitmapSize);
878 fLeftSideBits = new BBitmap(r, B_CMAP8);
879 fRightSideBits = new BBitmap(r, B_CMAP8);
880 r.Set(0.0, 0.0, kVolumeSliderKnobBitmapSize.x, kVolumeSliderKnobBitmapSize.y);
881 fKnobBits = new BBitmap(r, B_CMAP8);
886 /*****************************************************************************
887 * VolumeSlider destructor
888 *****************************************************************************/
889 VolumeSlider::~VolumeSlider()
891 delete fLeftSideBits;
892 delete fRightSideBits;
896 /*****************************************************************************
897 * VolumeSlider::AttachedToWindow
898 *****************************************************************************/
900 VolumeSlider::AttachedToWindow()
902 BControl::AttachedToWindow();
903 SetViewColor(B_TRANSPARENT_32_BIT);
906 /*****************************************************************************
907 * VolumeSlider::SetValue
908 *****************************************************************************/
910 VolumeSlider::SetValue(int32 value)
912 if (value != Value())
914 BControl::SetValue(value);
919 /*****************************************************************************
920 * VolumeSlider::SetEnabled
921 *****************************************************************************/
923 VolumeSlider::SetEnabled(bool enable)
925 if (enable != IsEnabled())
927 BControl::SetEnabled(enable);
933 /*****************************************************************************
935 *****************************************************************************/
937 VolumeSlider::Draw(BRect updateRect)
942 float sliderSideWidth = kVolumeSliderBitmapWidth;
943 float sliderStart = (r.left + sliderSideWidth);
944 float sliderEnd = (r.right - sliderSideWidth);
945 float knobPos = sliderStart
946 + (sliderEnd - sliderStart - 1.0) * (Value() - fMinValue)
947 / (fMaxValue - fMinValue);
948 // draw both sides (the original from Be doesn't seem
949 // to make a difference for enabled/disabled state)
950 DrawBitmapAsync(fLeftSideBits, r.LeftTop());
951 DrawBitmapAsync(fRightSideBits, BPoint(sliderEnd + 1.0, r.top));
952 // colors for the slider area between the two bitmaps
953 rgb_color background = kBackground;//ui_color(B_PANEL_BACKGROUND_COLOR);
954 rgb_color shadow = tint_color(background, B_DARKEN_2_TINT);
955 rgb_color softShadow = tint_color(background, B_DARKEN_1_TINT);
956 rgb_color darkShadow = tint_color(background, B_DARKEN_4_TINT);
957 rgb_color midShadow = tint_color(background, B_DARKEN_3_TINT);
958 rgb_color light = tint_color(background, B_LIGHTEN_MAX_TINT);
959 rgb_color softLight = tint_color(background, B_LIGHTEN_1_TINT);
960 rgb_color green = kGreen;
961 rgb_color greenShadow = kGreenShadow;
962 rgb_color black = kBlack;
963 rgb_color dotGrey = midShadow;
964 rgb_color dotGreen = greenShadow;
965 // make dimmed version of colors if we're disabled
968 shadow = (rgb_color){ 200, 200, 200, 255 };
969 softShadow = dimmed_color_cmap8(softShadow, background, DIM_LEVEL);
970 darkShadow = dimmed_color_cmap8(darkShadow, background, DIM_LEVEL);
972 light = dimmed_color_cmap8(light, background, DIM_LEVEL);
973 softLight = dimmed_color_cmap8(softLight, background, DIM_LEVEL);
974 green = dimmed_color_cmap8(green, background, DIM_LEVEL);
975 greenShadow = dimmed_color_cmap8(greenShadow, background, DIM_LEVEL);
976 black = dimmed_color_cmap8(black, background, DIM_LEVEL);
981 green = tint_color(kBackground, B_DARKEN_3_TINT);
982 greenShadow = tint_color(kBackground, B_DARKEN_4_TINT);
983 dotGreen = greenShadow;
985 // draw slider edges between bitmaps
987 AddLine(BPoint(sliderStart, r.top),
988 BPoint(sliderEnd, r.top), softShadow);
989 AddLine(BPoint(sliderStart, r.bottom),
990 BPoint(sliderEnd, r.bottom), softLight);
992 AddLine(BPoint(sliderStart, r.top),
993 BPoint(sliderEnd, r.top), black);
994 AddLine(BPoint(sliderStart, r.bottom),
995 BPoint(sliderEnd, r.bottom), light);
997 AddLine(BPoint(sliderStart, r.top),
998 BPoint(knobPos, r.top), greenShadow);
999 AddLine(BPoint(knobPos, r.top),
1000 BPoint(sliderEnd, r.top), midShadow);
1002 AddLine(BPoint(sliderStart, r.top),
1003 BPoint(knobPos, r.top), greenShadow);
1005 // fill rest inside of slider
1006 r.InsetBy(0.0, 1.0);
1007 r.left = sliderStart;
1009 SetHighColor(green);
1010 FillRect(r, B_SOLID_HIGH);
1011 r.left = knobPos + 1.0;
1012 r.right = sliderEnd;
1014 SetHighColor(shadow);
1015 FillRect(r, B_SOLID_HIGH);
1016 // draw little dots inside
1017 int32 dotCount = (int32)((sliderEnd - sliderStart) / 5.0);
1019 dotPos.y = r.top + 4.0;
1020 for (int32 i = 0; i < dotCount; i++)
1022 dotPos.x = sliderStart + i * 5.0 + 4.0;
1023 SetHighColor(dotPos.x < knobPos ? dotGreen : dotGrey);
1024 StrokeLine(dotPos, BPoint(dotPos.x, dotPos.y + 1.0));
1028 SetDrawingMode(B_OP_OVER); // part of knob is transparent
1029 DrawBitmapAsync(fKnobBits, BPoint(knobPos - kVolumeSliderKnobWidth / 2, r.top));
1033 /*****************************************************************************
1034 * VolumeSlider::MouseDown
1035 *****************************************************************************/
1037 VolumeSlider::MouseDown(BPoint where)
1039 if (Bounds().Contains(where) && IsEnabled())
1042 SetValue(_ValueFor(where.x));
1043 SetMouseEventMask(B_POINTER_EVENTS, B_LOCK_WINDOW_FOCUS);
1047 /*****************************************************************************
1048 * VolumeSlider::MouseMoved
1049 *****************************************************************************/
1051 VolumeSlider::MouseMoved(BPoint where, uint32 transit, const BMessage* dragMessage)
1054 SetValue(_ValueFor(where.x));
1057 /*****************************************************************************
1058 * VolumeSlider::MouseUp
1059 *****************************************************************************/
1061 VolumeSlider::MouseUp(BPoint where)
1067 /*****************************************************************************
1068 * VolumeSlider::IsValid
1069 *****************************************************************************/
1071 VolumeSlider::IsValid() const
1073 return (fLeftSideBits && fLeftSideBits->IsValid()
1074 && fRightSideBits && fRightSideBits->IsValid()
1075 && fKnobBits && fKnobBits->IsValid());
1078 /*****************************************************************************
1079 * VolumeSlider::SetMuted
1080 *****************************************************************************/
1082 VolumeSlider::SetMuted(bool mute)
1092 /*****************************************************************************
1093 * VolumeSlider::_MakeBitmaps
1094 *****************************************************************************/
1096 VolumeSlider::_MakeBitmaps()
1100 // left side of slider
1101 memcpy(fLeftSideBits->Bits(), kVolumeSliderLeftBitmapBits,
1102 fLeftSideBits->BitsLength());
1103 // right side of slider
1104 memcpy(fRightSideBits->Bits(), kVolumeSliderRightBits,
1105 fRightSideBits->BitsLength());
1107 int32 length = fKnobBits->BitsLength();
1108 memcpy(fKnobBits->Bits(), kVolumeSliderKnobBits, length);
1109 uint8* bits = (uint8*)fKnobBits->Bits();
1110 // black was used in the knob to represent transparency
1111 // use screen to get index for the "transarent" color used in the bitmap
1112 BScreen screen(B_MAIN_SCREEN_ID);
1113 uint8 blackIndex = screen.IndexForColor(kBlack);
1114 // replace black index with transparent index
1115 for (int32 i = 0; i < length; i++)
1116 if (bits[i] == blackIndex)
1117 bits[i] = B_TRANSPARENT_MAGIC_CMAP8;
1121 // make ghosted versions of the bitmaps
1122 dim_bitmap(fLeftSideBits, kBackground, DIM_LEVEL);
1123 dim_bitmap(fRightSideBits, kBackground, DIM_LEVEL);
1124 dim_bitmap(fKnobBits, kBackground, DIM_LEVEL);
1128 // replace green color (and shadow) in left slider side
1129 bits = (uint8*)fLeftSideBits->Bits();
1130 length = fLeftSideBits->BitsLength();
1131 uint8 greenIndex = screen.IndexForColor(kGreen);
1132 uint8 greenShadowIndex = screen.IndexForColor(kGreenShadow);
1133 rgb_color shadow = tint_color(kBackground, B_DARKEN_3_TINT);
1134 rgb_color midShadow = tint_color(kBackground, B_DARKEN_4_TINT);
1135 uint8 replaceIndex = screen.IndexForColor(shadow);
1136 uint8 replaceShadowIndex = screen.IndexForColor(midShadow);
1137 for (int32 i = 0; i < length; i++)
1139 if (bits[i] == greenIndex)
1140 bits[i] = replaceIndex;
1141 else if (bits[i] == greenShadowIndex)
1142 bits[i] = replaceShadowIndex;
1148 /*****************************************************************************
1149 * VolumeSlider::_ValueFor
1150 *****************************************************************************/
1152 VolumeSlider::_ValueFor(float xPos) const
1155 float sliderStart = (r.left + kVolumeSliderBitmapWidth);
1156 float sliderEnd = (r.right - kVolumeSliderBitmapWidth);
1157 int32 value = fMinValue + (int32)(((xPos - sliderStart) * (fMaxValue - fMinValue))
1158 / (sliderEnd - sliderStart - 1.0));
1159 if (value < fMinValue)
1161 if (value > fMaxValue)
1166 /*****************************************************************************
1167 * PositionInfoView::PositionInfoView
1168 *****************************************************************************/
1169 PositionInfoView::PositionInfoView( BRect frame, const char* name,
1170 intf_thread_t * p_interface )
1171 : BView( frame, name, B_FOLLOW_NONE,
1172 B_WILL_DRAW | B_PULSE_NEEDED | B_FULL_UPDATE_ON_RESIZE ),
1173 fMode( MODE_SMALL ),
1174 fCurrentFileIndex( -1 ),
1175 fCurrentFileSize( -1 ),
1176 fCurrentTitleIndex( -1 ),
1177 fCurrentTitleSize( -1 ),
1178 fCurrentChapterIndex( -1 ),
1179 fCurrentChapterSize( -1 ),
1181 fTimeString( "-:--:--" ),
1182 fLastPulseUpdate( system_time() ),
1183 fStackedWidthCache( 0.0 ),
1184 fStackedHeightCache( 0.0 )
1186 p_intf = p_interface;
1188 SetViewColor( B_TRANSPARENT_32_BIT );
1189 SetLowColor( kBlack );
1190 SetHighColor( 0, 255, 0, 255 );
1191 SetFontSize( 11.0 );
1194 /*****************************************************************************
1195 * PositionInfoView::~PositionInfoView
1196 *****************************************************************************/
1197 PositionInfoView::~PositionInfoView()
1201 /*****************************************************************************
1202 * PositionInfoView::Draw
1203 *****************************************************************************/
1205 PositionInfoView::Draw( BRect updateRect )
1207 rgb_color background = ui_color( B_PANEL_BACKGROUND_COLOR );
1208 rgb_color shadow = tint_color( background, B_DARKEN_1_TINT );
1209 rgb_color darkShadow = tint_color( background, B_DARKEN_4_TINT );
1210 rgb_color light = tint_color( background, B_LIGHTEN_MAX_TINT );
1211 rgb_color softLight = tint_color( background, B_LIGHTEN_1_TINT );
1213 BRect r( Bounds() );
1214 BeginLineArray( 8 );
1215 AddLine( BPoint( r.left, r.bottom ),
1216 BPoint( r.left, r.top ), shadow );
1217 AddLine( BPoint( r.left + 1.0, r.top ),
1218 BPoint( r.right, r.top ), shadow );
1219 AddLine( BPoint( r.right, r.top + 1.0 ),
1220 BPoint( r.right, r.bottom ), softLight );
1221 AddLine( BPoint( r.right - 1.0, r.bottom ),
1222 BPoint( r.left + 1.0, r.bottom ), softLight );
1223 r.InsetBy( 1.0, 1.0 );
1224 AddLine( BPoint( r.left, r.bottom ),
1225 BPoint( r.left, r.top ), darkShadow );
1226 AddLine( BPoint( r.left + 1.0, r.top ),
1227 BPoint( r.right, r.top ), darkShadow );
1228 AddLine( BPoint( r.right, r.top + 1.0 ),
1229 BPoint( r.right, r.bottom ), light );
1230 AddLine( BPoint( r.right - 1.0, r.bottom ),
1231 BPoint( r.left + 1.0, r.bottom ), light );
1234 r.InsetBy( 1.0, 1.0 );
1235 FillRect( r, B_SOLID_LOW );
1238 GetFontHeight( &fh );
1243 float width = StringWidth( fTimeString.String() );
1244 DrawString( fTimeString.String(),
1245 BPoint( r.left + r.Width() / 2.0 - width / 2.0,
1246 r.top + r.Height() / 2.0 + fh.ascent / 2.0 - 1.0 ) );
1253 BFont smallFont = font;
1254 BFont bigFont = font;
1255 BFont tinyFont = font;
1256 smallFont.SetSize( r.Height() / 5.0 );
1257 bigFont.SetSize( r.Height() / 3.0 );
1258 tinyFont.SetSize( r.Height() / 7.0 );
1259 float timeHeight = r.Height() / 2.5;
1260 float height = ( r.Height() - timeHeight ) / 3.0;
1261 SetFont( &tinyFont );
1262 SetHighColor( 0, 180, 0, 255 );
1263 DrawString( _("File"), BPoint( r.left + 3.0, r.top + height ) );
1264 DrawString( _("Title"), BPoint( r.left + 3.0, r.top + 2.0 * height ) );
1265 DrawString( _("Chapter"), BPoint( r.left + 3.0, r.top + 3.0 * height ) );
1266 SetFont( &smallFont );
1268 SetHighColor( 0, 255, 0, 255 );
1270 _MakeString( helper, fCurrentFileIndex, fCurrentFileSize );
1271 float width = StringWidth( helper.String() );
1272 DrawString( helper.String(), BPoint( r.right - 3.0 - width, r.top + height ) );
1274 _MakeString( helper, fCurrentTitleIndex, fCurrentTitleSize );
1275 width = StringWidth( helper.String() );
1276 DrawString( helper.String(), BPoint( r.right - 3.0 - width, r.top + 2.0 * height ) );
1278 _MakeString( helper, fCurrentChapterIndex, fCurrentChapterSize );
1279 width = StringWidth( helper.String() );
1280 DrawString( helper.String(), BPoint( r.right - 3.0 - width, r.top + 3.0 * height ) );
1282 SetFont( &bigFont );
1283 width = StringWidth( fTimeString.String() );
1284 DrawString( fTimeString.String(),
1285 BPoint( r.left + r.Width() / 2.0 - width / 2.0,
1292 /*****************************************************************************
1293 * PositionInfoView::ResizeToPreferred
1294 *****************************************************************************/
1296 PositionInfoView::ResizeToPreferred()
1298 float width, height;
1299 GetPreferredSize( &width, &height );
1300 ResizeTo( width, height );
1303 /*****************************************************************************
1304 * PositionInfoView::GetPreferredSize
1305 *****************************************************************************/
1307 PositionInfoView::GetPreferredSize( float* width, float* height )
1309 if ( width && height )
1311 *width = 5.0 + ceilf( StringWidth( "0:00:00" ) ) + 5.0;
1313 GetFontHeight( &fh );
1314 *height = 3.0 + ceilf( fh.ascent ) + 3.0;
1315 fStackedWidthCache = *width * 1.2;
1316 fStackedHeightCache = *height * 2.7;
1320 /*****************************************************************************
1321 * PositionInfoView::Pulse
1322 *****************************************************************************/
1324 PositionInfoView::Pulse()
1326 // allow for Pulse frequency to be higher, MediaControlView needs it
1327 bigtime_t now = system_time();
1328 if ( now - fLastPulseUpdate > 900000 )
1331 p_intf->p_sys->p_wrapper->GetPlaylistInfo( index, size );
1332 SetFile( index + 1, size );
1333 p_intf->p_sys->p_wrapper->TitleInfo( index, size );
1334 SetTitle( index, size );
1335 p_intf->p_sys->p_wrapper->ChapterInfo( index, size );
1336 SetChapter( index, size );
1337 SetTime( p_intf->p_sys->p_wrapper->GetTimeAsString() );
1338 fLastPulseUpdate = now;
1342 /*****************************************************************************
1343 * PositionInfoView::GetBigPreferredSize
1344 *****************************************************************************/
1346 PositionInfoView::GetBigPreferredSize( float* width, float* height )
1348 if ( width && height )
1350 *width = fStackedWidthCache;
1351 *height = fStackedHeightCache;
1355 /*****************************************************************************
1356 * PositionInfoView::SetMode
1357 *****************************************************************************/
1359 PositionInfoView::SetMode( uint32 mode )
1361 if ( fMode != mode )
1364 _InvalidateContents();
1368 /*****************************************************************************
1369 * PositionInfoView::SetFile
1370 *****************************************************************************/
1372 PositionInfoView::SetFile( int32 index, int32 size )
1374 if ( fCurrentFileIndex != index || fCurrentFileSize != size )
1376 fCurrentFileIndex = index;
1377 fCurrentFileSize = size;
1378 _InvalidateContents();
1382 /*****************************************************************************
1383 * PositionInfoView::SetTitle
1384 *****************************************************************************/
1386 PositionInfoView::SetTitle( int32 index, int32 size )
1388 if ( fCurrentTitleIndex != index || fCurrentFileSize != size )
1390 fCurrentTitleIndex = index;
1391 fCurrentTitleSize = size;
1392 _InvalidateContents();
1396 /*****************************************************************************
1397 * PositionInfoView::SetChapter
1398 *****************************************************************************/
1400 PositionInfoView::SetChapter( int32 index, int32 size )
1402 if ( fCurrentChapterIndex != index || fCurrentFileSize != size )
1404 fCurrentChapterIndex = index;
1405 fCurrentChapterSize = size;
1406 _InvalidateContents();
1410 /*****************************************************************************
1411 * PositionInfoView::SetTime
1412 *****************************************************************************/
1414 PositionInfoView::SetTime( int32 seconds )
1416 if ( fSeconds != seconds )
1420 int32 minutes = seconds / 60;
1421 int32 hours = minutes / 60;
1422 seconds -= minutes * 60 - hours * 60 * 60;
1423 minutes -= hours * 60;
1424 fTimeString.SetTo( "" );
1425 fTimeString << hours << ":" << minutes << ":" << seconds;
1428 fTimeString.SetTo( "-:--:--" );
1431 _InvalidateContents();
1435 /*****************************************************************************
1436 * PositionInfoView::SetTime
1437 *****************************************************************************/
1439 PositionInfoView::SetTime( const char* string )
1441 fTimeString.SetTo( string );
1442 _InvalidateContents();
1445 /*****************************************************************************
1446 * PositionInfoView::_InvalidateContents
1447 *****************************************************************************/
1449 PositionInfoView::_InvalidateContents( uint32 which )
1451 BRect r( Bounds() );
1452 r.InsetBy( 2.0, 2.0 );
1456 /*****************************************************************************
1457 * PositionInfoView::_InvalidateContents
1458 *****************************************************************************/
1460 PositionInfoView::_MakeString( BString& into, int32 index, int32 maxIndex ) const
1463 if ( index >= 0 && maxIndex >= 0 )
1468 if ( maxIndex >= 0 )