1 /*****************************************************************************
2 * MediaControlView.cpp: beos interface
3 *****************************************************************************
4 * Copyright (C) 1999, 2000, 2001 VideoLAN
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>
34 #include <vlc/input.h>
37 #include <audio_output.h>
40 /* BeOS interface headers */
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")
69 #define SEEKSLIDER_RANGE 2048
75 MSG_SKIP_BACKWARDS = 'skpb',
76 MSG_SKIP_FORWARD = 'skpf',
80 MediaControlView::MediaControlView( intf_thread_t * _p_intf, BRect frame)
81 : BBox(frame, NULL, B_FOLLOW_NONE, B_WILL_DRAW | B_FRAME_EVENTS | B_PULSE_NEEDED,
85 fCurrentRate(INPUT_RATE_DEFAULT),
87 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()) {
208 menuBar->GetPreferredSize(&width, &height);
209 // r.bottom += menuBar->Bounds().Height();
211 // see that our calculated minimal width is not smaller than what
212 // the menubar can be
213 printf("preferred: width: %f, height: %f - width: %f\n", width, height, r.Width());
219 Window()->SetSizeLimits(r.Width(), r.Width() * 1.8, r.Height(), r.Height() * 1.3);
220 if (!Window()->Bounds().Contains(r))
221 Window()->ResizeTo(r.Width(), r.Height());
223 FrameResized(Bounds().Width(), Bounds().Height());
225 // get pulse message every two frames
226 Window()->SetPulseRate(80000);
231 MediaControlView::FrameResized(float width, float height)
234 // make sure we don't leave dirty pixels
235 // (B_FULL_UPDATE_ON_RESIZE == annoying flicker -> this is smarter)
236 if (fOldBounds.Width() < r.Width())
237 Invalidate(BRect(fOldBounds.right, fOldBounds.top + 1.0,
238 fOldBounds.right, fOldBounds.bottom - 1.0));
240 Invalidate(BRect(r.right, r.top + 1.0,
241 r.right, r.bottom - 1.0));
242 if (fOldBounds.Height() < r.Height())
243 Invalidate(BRect(fOldBounds.left + 1.0, fOldBounds.bottom,
244 fOldBounds.right - 1.0, fOldBounds.bottom));
246 Invalidate(BRect(r.left + 1.0, r.bottom,
247 r.right - 1.0, r.bottom));
248 // remember for next time
251 r.InsetBy(BORDER_INSET, BORDER_INSET);
257 MediaControlView::GetPreferredSize(float* width, float* height)
261 BRect r(_MinFrame());
263 *height = r.Height();
269 MediaControlView::MessageReceived(BMessage* message)
271 switch (message->what)
277 case MSG_SKIP_BACKWARDS:
278 Window()->PostMessage(NAVIGATE_PREV);
280 case MSG_SKIP_FORWARD:
281 Window()->PostMessage(NAVIGATE_NEXT);
284 BBox::MessageReceived(message);
291 MediaControlView::Pulse()
293 InterfaceWindow* window = dynamic_cast<InterfaceWindow*>(Window());
294 if (window && window->IsStopped())
295 fPlayPause->SetStopped();
297 unsigned short i_volume;
298 aout_VolumeGet( p_intf, (audio_volume_t*)&i_volume );
299 fVolumeSlider->SetValue( i_volume );
304 MediaControlView::SetProgress( float position )
306 fSeekSlider->SetPosition( position );
311 MediaControlView::SetStatus(int status, int rate)
313 // we need to set the button status periodically
314 // (even if it is the same) to get a blinking button
315 fCurrentStatus = status;
319 fPlayPause->SetPlaying();
322 fPlayPause->SetPaused();
325 fPlayPause->SetStopped();
328 if (rate != fCurrentRate)
331 if ( rate < INPUT_RATE_DEFAULT )
340 MediaControlView::SetEnabled(bool enabled)
342 if( ( enabled && fIsEnabled ) ||
343 ( !enabled && !fIsEnabled ) )
345 /* do not redraw if it is not necessary */
351 fSkipBack->SetEnabled( enabled );
352 fPlayPause->SetEnabled( enabled );
353 fSkipForward->SetEnabled( enabled );
354 fStop->SetEnabled( enabled );
355 fMute->SetEnabled( enabled );
356 fVolumeSlider->SetEnabled( enabled );
357 fSeekSlider->SetEnabled( enabled );
358 fRewind->SetEnabled( enabled );
359 fForward->SetEnabled( enabled );
361 fIsEnabled = enabled;
367 MediaControlView::SetAudioEnabled(bool enabled)
369 fMute->SetEnabled(enabled);
370 fVolumeSlider->SetEnabled(enabled);
375 MediaControlView::GetSeekTo() const
377 return fSeekSlider->Value();
382 MediaControlView::GetVolume() const
384 return fVolumeSlider->Value();
389 MediaControlView::SetSkippable(bool backward, bool forward)
391 fSkipBack->SetEnabled(backward);
392 fSkipForward->SetEnabled(forward);
397 MediaControlView::SetMuted(bool mute)
399 fVolumeSlider->SetMuted(mute);
404 MediaControlView::_LayoutControls(BRect frame) const
408 // calculate absolutly minimal width
409 float minWidth = fSkipBack->Bounds().Width();
410 // minWidth += fRewind->Bounds().Width();
411 minWidth += fStop->Bounds().Width();
412 minWidth += fPlayPause->Bounds().Width();
413 // minWidth += fForward->Bounds().Width();
414 minWidth += fSkipForward->Bounds().Width();
415 minWidth += fMute->Bounds().Width();
416 minWidth += VOLUME_MIN_WIDTH;
418 // layout time slider and info view
420 fPositionInfo->GetBigPreferredSize( &width, &height );
421 float ratio = width / height;
422 width = r.Height() * ratio;
423 if (frame.Width() - minWidth - MIN_SPACE >= width
424 && frame.Height() >= height)
426 r.right = r.left + width;
427 fPositionInfo->SetMode(PositionInfoView::MODE_BIG);
428 _LayoutControl(fPositionInfo, r, true, true);
429 frame.left = r.right + MIN_SPACE;
431 r.right = frame.right;
432 // r.bottom = r.top + r.Height() / 2.0 - MIN_SPACE / 2.0;
433 r.bottom = r.top + fSeekSlider->Bounds().Height();
434 _LayoutControl(fSeekSlider, r, true);
438 fPositionInfo->GetPreferredSize( &width, &height );
439 fPositionInfo->SetMode(PositionInfoView::MODE_SMALL);
440 fPositionInfo->ResizeTo(width, height);
441 r.bottom = r.top + r.Height() / 2.0 - MIN_SPACE / 2.0;
442 r.right = r.left + fPositionInfo->Bounds().Width();
443 _LayoutControl(fPositionInfo, r, true );
444 r.left = r.right + MIN_SPACE;
445 r.right = frame.right;
446 _LayoutControl(fSeekSlider, r, true);
448 float currentWidth = frame.Width();
449 float space = (currentWidth - minWidth) / 6.0;//8.0;
451 space = MIN_SPACE + (space - MIN_SPACE) / VOLUME_SLIDER_LAYOUT_WEIGHT;
452 // layout controls with "space" inbetween
454 r.top = r.bottom + MIN_SPACE + 1.0;
455 r.bottom = frame.bottom;
457 r.right = r.left + fSkipBack->Bounds().Width();
458 _LayoutControl(fSkipBack, r);
460 // r.left = r.right + space;
461 // r.right = r.left + fRewind->Bounds().Width();
462 // _LayoutControl(fRewind, r);
464 r.left = r.right + space;
465 r.right = r.left + fStop->Bounds().Width();
466 _LayoutControl(fStop, r);
468 r.left = r.right + space;
469 r.right = r.left + fPlayPause->Bounds().Width();
470 _LayoutControl(fPlayPause, r);
472 // r.left = r.right + space;
473 // r.right = r.left + fForward->Bounds().Width();
474 // _LayoutControl(fForward, r);
476 r.left = r.right + space;
477 r.right = r.left + fSkipForward->Bounds().Width();
478 _LayoutControl(fSkipForward, r);
480 r.left = r.right + space + space;
481 r.right = r.left + fMute->Bounds().Width();
482 _LayoutControl(fMute, r);
484 r.left = r.right + SPEAKER_SLIDER_DIST; // keep speaker icon and volume slider attached
485 r.right = frame.right;
486 _LayoutControl(fVolumeSlider, r, true);
491 MediaControlView::_MinFrame() const
493 // add up width of controls along bottom (seek slider will likely adopt)
494 float minWidth = 2 * BORDER_INSET;
495 minWidth += fSkipBack->Bounds().Width() + MIN_SPACE;
496 // minWidth += fRewind->Bounds().Width() + MIN_SPACE;
497 minWidth += fStop->Bounds().Width() + MIN_SPACE;
498 minWidth += fPlayPause->Bounds().Width() + MIN_SPACE;
499 // minWidth += fForward->Bounds().Width() + MIN_SPACE;
500 minWidth += fSkipForward->Bounds().Width() + MIN_SPACE + MIN_SPACE;
501 minWidth += fMute->Bounds().Width() + SPEAKER_SLIDER_DIST;
502 minWidth += VOLUME_MIN_WIDTH;
504 // add up height of seek slider and heighest control on bottom
505 float minHeight = 2 * BORDER_INSET;
506 minHeight += fSeekSlider->Bounds().Height() + MIN_SPACE + MIN_SPACE / 2.0;
507 minHeight += fBottomControlHeight;
508 return BRect(0.0, 0.0, minWidth - 1.0, minHeight - 1.0);
513 MediaControlView::_LayoutControl(BView* view, BRect frame,
514 bool resizeWidth, bool resizeHeight) const
518 frame.top = (frame.top + frame.bottom) / 2.0 - view->Bounds().Height() / 2.0;
520 //center horizontally
521 frame.left = (frame.left + frame.right) / 2.0 - view->Bounds().Width() / 2.0;
522 view->MoveTo(frame.LeftTop());
523 float width = resizeWidth ? frame.Width() : view->Bounds().Width();
524 float height = resizeHeight ? frame.Height() : view->Bounds().Height();
525 if (resizeWidth || resizeHeight)
526 view->ResizeTo(width, height);
531 /*****************************************************************************
533 *****************************************************************************/
534 SeekSlider::SeekSlider(BRect frame, const char* name, MediaControlView *owner,
535 int32 minValue, int32 maxValue)
536 : BControl(frame, name, NULL, NULL, B_FOLLOW_NONE,
537 B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE),
543 BFont font(be_plain_font);
548 SeekSlider::~SeekSlider()
553 /*****************************************************************************
554 * VolumeSlider::AttachedToWindow
555 *****************************************************************************/
557 SeekSlider::AttachedToWindow()
559 BControl::AttachedToWindow();
560 SetViewColor(B_TRANSPARENT_32_BIT);
563 /*****************************************************************************
565 *****************************************************************************/
567 SeekSlider::Draw(BRect updateRect)
570 float knobWidth2 = SEEK_SLIDER_KNOB_WIDTH / 2.0;
571 float sliderStart = (r.left + knobWidth2);
572 float sliderEnd = (r.right - knobWidth2);
573 float knobPos = sliderStart
574 + floorf((sliderEnd - sliderStart - 1.0) * (Value() - fMinValue)
575 / (fMaxValue - fMinValue) + 0.5);
576 // draw both sides (the original from Be doesn't seem
577 // to make a difference for enabled/disabled state)
578 // DrawBitmapAsync(fLeftSideBits, r.LeftTop());
579 // DrawBitmapAsync(fRightSideBits, BPoint(sliderEnd + 1.0, r.top));
580 // colors for the slider area between the two bitmaps
581 rgb_color background = kBackground;//ui_color(B_PANEL_BACKGROUND_COLOR);
582 rgb_color shadow = tint_color(background, B_DARKEN_2_TINT);
583 rgb_color softShadow = tint_color(background, B_DARKEN_1_TINT);
584 rgb_color darkShadow = tint_color(background, B_DARKEN_4_TINT);
585 rgb_color midShadow = tint_color(background, B_DARKEN_3_TINT);
586 rgb_color light = tint_color(background, B_LIGHTEN_MAX_TINT);
587 rgb_color softLight = tint_color(background, B_LIGHTEN_1_TINT);
588 rgb_color green = kSeekGreen;
589 rgb_color greenShadow = kSeekGreenShadow;
590 rgb_color black = kBlack;
591 rgb_color dotGrey = midShadow;
592 rgb_color dotGreen = greenShadow;
594 _StrokeFrame(r, softShadow, softShadow, softLight, softLight);
596 _StrokeFrame(r, black, black, light, light);
601 _StrokeFrame(r, greenShadow, greenShadow, green, green);
604 _StrokeFrame(r, greenShadow, greenShadow, green, green);
610 int32 dotCount = (int32)(r.Width() / 6.0);
612 dotPos.y = r.top + 2.0;
613 SetHighColor(dotGreen);
614 for (int32 i = 0; i < dotCount; i++)
616 dotPos.x = sliderStart + i * 6.0 + 5.0;
617 StrokeLine(dotPos, BPoint(dotPos.x, dotPos.y + 6.0));
622 r.left = knobPos - knobWidth2;
623 r.right = knobPos + knobWidth2;
625 float handleBottomSize = 2.0;
626 float handleArrowSize = 6.0;
629 AddLine(BPoint(r.left, r.top + handleBottomSize),
630 BPoint(r.left, r.top), black);
631 AddLine(BPoint(r.left + 1.0, r.top),
632 BPoint(r.right, r.top), black);
633 AddLine(BPoint(r.right, r.top + 1.0),
634 BPoint(r.right, r.top + handleBottomSize), black);
635 AddLine(BPoint(r.right - 1.0, r.top + handleBottomSize + 1.0),
636 BPoint(knobPos, r.top + handleArrowSize), black);
637 AddLine(BPoint(knobPos - 1.0, r.top + handleArrowSize - 1.0),
638 BPoint(r.left + 1.0, r.top + handleBottomSize + 1.0), black);
640 AddLine(BPoint(r.left, r.bottom),
641 BPoint(r.left, r.bottom - handleBottomSize), black);
642 AddLine(BPoint(r.left + 1.0, r.bottom - handleBottomSize - 1.0),
643 BPoint(knobPos, r.bottom - handleArrowSize), black);
644 AddLine(BPoint(knobPos + 1.0, r.bottom - handleArrowSize + 1.0),
645 BPoint(r.right, r.bottom - handleBottomSize), black);
646 AddLine(BPoint(r.right, r.bottom - handleBottomSize + 1.0),
647 BPoint(r.right, r.bottom), black);
648 AddLine(BPoint(r.right - 1.0, r.bottom),
649 BPoint(r.left + 1.0, r.bottom), black);
651 // inner red light and shadow lines
654 handleArrowSize -= 2.0;
657 AddLine(BPoint(r.left, r.top + handleBottomSize),
658 BPoint(r.left, r.top), kSeekRedLight);
659 AddLine(BPoint(r.left + 1.0, r.top),
660 BPoint(r.right, r.top), kSeekRedLight);
661 AddLine(BPoint(r.right, r.top + 1.0),
662 BPoint(r.right, r.top + handleBottomSize), kSeekRedShadow);
663 AddLine(BPoint(r.right - 1.0, r.top + handleBottomSize + 1.0),
664 BPoint(knobPos, r.top + handleArrowSize), kSeekRedShadow);
665 AddLine(BPoint(knobPos - 1.0, r.top + handleArrowSize - 1.0),
666 BPoint(r.left + 1.0, r.top + handleBottomSize + 1.0), kSeekRedLight);
668 AddLine(BPoint(r.left, r.bottom),
669 BPoint(r.left, r.bottom - handleBottomSize), kSeekRedLight);
670 AddLine(BPoint(r.left + 1.0, r.bottom - handleBottomSize - 1.0),
671 BPoint(knobPos, r.bottom - handleArrowSize), kSeekRedLight);
672 AddLine(BPoint(knobPos + 1.0, r.bottom - handleArrowSize + 1.0),
673 BPoint(r.right, r.bottom - handleBottomSize), kSeekRedShadow);
674 AddLine(BPoint(r.right, r.bottom - handleBottomSize + 1.0),
675 BPoint(r.right, r.bottom), kSeekRedShadow);
676 AddLine(BPoint(r.right - 1.0, r.bottom),
677 BPoint(r.left + 1.0, r.bottom), kSeekRedShadow);
679 // fill rest of handles with red
680 SetHighColor(kSeekRed);
682 handleArrowSize -= 2.0;
684 // upper handle arrow
687 arrow[1].x = r.right;
689 arrow[2].x = knobPos;
690 arrow[2].y = r.top + handleArrowSize;
691 FillPolygon(arrow, 3);
692 // lower handle arrow
694 arrow[0].y = r.bottom;
695 arrow[1].x = r.right;
696 arrow[1].y = r.bottom;
697 arrow[2].x = knobPos;
698 arrow[2].y = r.bottom - handleArrowSize;
699 FillPolygon(arrow, 3);
704 _StrokeFrame(r, darkShadow, darkShadow, darkShadow, darkShadow);
706 _StrokeFrame(r, darkShadow, darkShadow, darkShadow, darkShadow);
708 SetHighColor(darkShadow);
711 float width = floorf(StringWidth(DISABLED_SEEK_MESSAGE));
712 float textPos = r.left + r.Width() / 2.0 - width / 2.0;
713 pattern stripes = {{ 0xc7, 0x8f, 0x1f, 0x3e, 0x7c, 0xf8, 0xf1, 0xe3 }};
714 BRect stripesRect(r);
715 stripesRect.right = textPos - 5.0;
716 FillRect(stripesRect, stripes);
717 stripesRect.left = textPos + width + 3.0;
718 stripesRect.right = r.right;
719 FillRect(stripesRect, stripes);
721 r.left = textPos - 4.0;
722 r.right = textPos + width + 2.0;
724 SetHighColor(shadow);
725 SetLowColor(darkShadow);
728 DrawString(DISABLED_SEEK_MESSAGE, BPoint(textPos, r.top + ceilf(fh.ascent) - 1.0));
732 /*****************************************************************************
733 * SeekSlider::MouseDown
734 *****************************************************************************/
736 SeekSlider::MouseDown(BPoint where)
738 if (IsEnabled() && Bounds().Contains(where))
740 SetValue(_ValueFor(where.x));
742 SetMouseEventMask(B_POINTER_EVENTS, B_LOCK_WINDOW_FOCUS);
747 /*****************************************************************************
748 * SeekSlider::MouseMoved
749 *****************************************************************************/
751 SeekSlider::MouseMoved(BPoint where, uint32 code, const BMessage* dragMessage)
755 SetValue(_ValueFor(where.x));
760 /*****************************************************************************
761 * SeekSlider::MouseUp
762 *****************************************************************************/
764 SeekSlider::MouseUp(BPoint where)
773 /*****************************************************************************
774 * SeekSlider::ResizeToPreferred
775 *****************************************************************************/
777 SeekSlider::ResizeToPreferred()
779 float width = 15.0 + StringWidth(DISABLED_SEEK_MESSAGE) + 15.0;
780 ResizeTo(width, 17.0);
783 /*****************************************************************************
784 * SeekSlider::SetPosition
785 *****************************************************************************/
787 SeekSlider::SetPosition(float position)
791 SetValue(fMinValue + (int32)floorf((fMaxValue - fMinValue) * position + 0.5));
796 /*****************************************************************************
797 * SeekSlider::_ValueFor
798 *****************************************************************************/
800 SeekSlider::_ValueFor(float xPos) const
803 float knobWidth2 = SEEK_SLIDER_KNOB_WIDTH / 2.0;
804 float sliderStart = (r.left + knobWidth2);
805 float sliderEnd = (r.right - knobWidth2);
806 int32 value = fMinValue + (int32)(((xPos - sliderStart) * (fMaxValue - fMinValue))
807 / (sliderEnd - sliderStart - 1.0));
808 if (value < fMinValue)
810 if (value > fMaxValue)
815 /*****************************************************************************
816 * SeekSlider::_StrokeFrame
817 *****************************************************************************/
819 SeekSlider::_StrokeFrame(BRect r, rgb_color left, rgb_color top,
820 rgb_color right, rgb_color bottom)
823 AddLine(BPoint(r.left, r.bottom), BPoint(r.left, r.top), left);
824 AddLine(BPoint(r.left + 1.0, r.top), BPoint(r.right, r.top), top);
825 AddLine(BPoint(r.right, r.top + 1.0), BPoint(r.right, r.bottom), right);
826 AddLine(BPoint(r.right - 1.0, r.bottom), BPoint(r.left + 1.0, r.bottom), bottom);
830 /*****************************************************************************
831 * SeekSlider::_BeginSeek
832 *****************************************************************************/
834 SeekSlider::_BeginSeek()
836 fOwner->fScrubSem = create_sem(0, "Vlc::fScrubSem");
837 if (fOwner->fScrubSem >= B_OK)
838 release_sem(fOwner->fScrubSem);
841 /*****************************************************************************
843 *****************************************************************************/
847 if (fOwner->fScrubSem >= B_OK)
848 delete_sem(fOwner->fScrubSem);
849 fOwner->fScrubSem = create_sem(0, "Vlc::fScrubSem");
850 if (fOwner->fScrubSem >= B_OK)
851 release_sem(fOwner->fScrubSem);
854 /*****************************************************************************
855 * SeekSlider::_EndSeek
856 *****************************************************************************/
858 SeekSlider::_EndSeek()
860 if (fOwner->fScrubSem >= B_OK)
861 delete_sem(fOwner->fScrubSem);
862 fOwner->fScrubSem = B_ERROR;
866 /*****************************************************************************
868 *****************************************************************************/
869 VolumeSlider::VolumeSlider(BRect frame, const char* name, int32 minValue, int32 maxValue,
870 BMessage* message, BHandler* target)
871 : BControl(frame, name, NULL, message, B_FOLLOW_NONE,
872 B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE),
874 fRightSideBits(NULL),
884 BRect r(BPoint(0.0, 0.0), kVolumeSliderBitmapSize);
885 fLeftSideBits = new BBitmap(r, B_CMAP8);
886 fRightSideBits = new BBitmap(r, B_CMAP8);
887 r.Set(0.0, 0.0, kVolumeSliderKnobBitmapSize.x, kVolumeSliderKnobBitmapSize.y);
888 fKnobBits = new BBitmap(r, B_CMAP8);
893 /*****************************************************************************
894 * VolumeSlider destructor
895 *****************************************************************************/
896 VolumeSlider::~VolumeSlider()
898 delete fLeftSideBits;
899 delete fRightSideBits;
903 /*****************************************************************************
904 * VolumeSlider::AttachedToWindow
905 *****************************************************************************/
907 VolumeSlider::AttachedToWindow()
909 BControl::AttachedToWindow();
910 SetViewColor(B_TRANSPARENT_32_BIT);
913 /*****************************************************************************
914 * VolumeSlider::SetValue
915 *****************************************************************************/
917 VolumeSlider::SetValue(int32 value)
919 if (value != Value())
921 BControl::SetValue(value);
926 /*****************************************************************************
927 * VolumeSlider::SetEnabled
928 *****************************************************************************/
930 VolumeSlider::SetEnabled(bool enable)
932 if (enable != IsEnabled())
934 BControl::SetEnabled(enable);
940 /*****************************************************************************
942 *****************************************************************************/
944 VolumeSlider::Draw(BRect updateRect)
949 float sliderSideWidth = kVolumeSliderBitmapWidth;
950 float sliderStart = (r.left + sliderSideWidth);
951 float sliderEnd = (r.right - sliderSideWidth);
952 float knobPos = sliderStart
953 + (sliderEnd - sliderStart - 1.0) * (Value() - fMinValue)
954 / (fMaxValue - fMinValue);
955 // draw both sides (the original from Be doesn't seem
956 // to make a difference for enabled/disabled state)
957 DrawBitmapAsync(fLeftSideBits, r.LeftTop());
958 DrawBitmapAsync(fRightSideBits, BPoint(sliderEnd + 1.0, r.top));
959 // colors for the slider area between the two bitmaps
960 rgb_color background = kBackground;//ui_color(B_PANEL_BACKGROUND_COLOR);
961 rgb_color shadow = tint_color(background, B_DARKEN_2_TINT);
962 rgb_color softShadow = tint_color(background, B_DARKEN_1_TINT);
963 rgb_color darkShadow = tint_color(background, B_DARKEN_4_TINT);
964 rgb_color midShadow = tint_color(background, B_DARKEN_3_TINT);
965 rgb_color light = tint_color(background, B_LIGHTEN_MAX_TINT);
966 rgb_color softLight = tint_color(background, B_LIGHTEN_1_TINT);
967 rgb_color green = kGreen;
968 rgb_color greenShadow = kGreenShadow;
969 rgb_color black = kBlack;
970 rgb_color dotGrey = midShadow;
971 rgb_color dotGreen = greenShadow;
972 // make dimmed version of colors if we're disabled
975 shadow = (rgb_color){ 200, 200, 200, 255 };
976 softShadow = dimmed_color_cmap8(softShadow, background, DIM_LEVEL);
977 darkShadow = dimmed_color_cmap8(darkShadow, background, DIM_LEVEL);
979 light = dimmed_color_cmap8(light, background, DIM_LEVEL);
980 softLight = dimmed_color_cmap8(softLight, background, DIM_LEVEL);
981 green = dimmed_color_cmap8(green, background, DIM_LEVEL);
982 greenShadow = dimmed_color_cmap8(greenShadow, background, DIM_LEVEL);
983 black = dimmed_color_cmap8(black, background, DIM_LEVEL);
988 green = tint_color(kBackground, B_DARKEN_3_TINT);
989 greenShadow = tint_color(kBackground, B_DARKEN_4_TINT);
990 dotGreen = greenShadow;
992 // draw slider edges between bitmaps
994 AddLine(BPoint(sliderStart, r.top),
995 BPoint(sliderEnd, r.top), softShadow);
996 AddLine(BPoint(sliderStart, r.bottom),
997 BPoint(sliderEnd, r.bottom), softLight);
999 AddLine(BPoint(sliderStart, r.top),
1000 BPoint(sliderEnd, r.top), black);
1001 AddLine(BPoint(sliderStart, r.bottom),
1002 BPoint(sliderEnd, r.bottom), light);
1004 AddLine(BPoint(sliderStart, r.top),
1005 BPoint(knobPos, r.top), greenShadow);
1006 AddLine(BPoint(knobPos, r.top),
1007 BPoint(sliderEnd, r.top), midShadow);
1009 AddLine(BPoint(sliderStart, r.top),
1010 BPoint(knobPos, r.top), greenShadow);
1012 // fill rest inside of slider
1013 r.InsetBy(0.0, 1.0);
1014 r.left = sliderStart;
1016 SetHighColor(green);
1017 FillRect(r, B_SOLID_HIGH);
1018 r.left = knobPos + 1.0;
1019 r.right = sliderEnd;
1021 SetHighColor(shadow);
1022 FillRect(r, B_SOLID_HIGH);
1023 // draw little dots inside
1024 int32 dotCount = (int32)((sliderEnd - sliderStart) / 5.0);
1026 dotPos.y = r.top + 4.0;
1027 for (int32 i = 0; i < dotCount; i++)
1029 dotPos.x = sliderStart + i * 5.0 + 4.0;
1030 SetHighColor(dotPos.x < knobPos ? dotGreen : dotGrey);
1031 StrokeLine(dotPos, BPoint(dotPos.x, dotPos.y + 1.0));
1035 SetDrawingMode(B_OP_OVER); // part of knob is transparent
1036 DrawBitmapAsync(fKnobBits, BPoint(knobPos - kVolumeSliderKnobWidth / 2, r.top));
1040 /*****************************************************************************
1041 * VolumeSlider::MouseDown
1042 *****************************************************************************/
1044 VolumeSlider::MouseDown(BPoint where)
1046 if (Bounds().Contains(where) && IsEnabled())
1049 SetValue(_ValueFor(where.x));
1050 SetMouseEventMask(B_POINTER_EVENTS, B_LOCK_WINDOW_FOCUS);
1054 /*****************************************************************************
1055 * VolumeSlider::MouseMoved
1056 *****************************************************************************/
1058 VolumeSlider::MouseMoved(BPoint where, uint32 transit, const BMessage* dragMessage)
1061 SetValue(_ValueFor(where.x));
1064 /*****************************************************************************
1065 * VolumeSlider::MouseUp
1066 *****************************************************************************/
1068 VolumeSlider::MouseUp(BPoint where)
1074 /*****************************************************************************
1075 * VolumeSlider::IsValid
1076 *****************************************************************************/
1078 VolumeSlider::IsValid() const
1080 return (fLeftSideBits && fLeftSideBits->IsValid()
1081 && fRightSideBits && fRightSideBits->IsValid()
1082 && fKnobBits && fKnobBits->IsValid());
1085 /*****************************************************************************
1086 * VolumeSlider::SetMuted
1087 *****************************************************************************/
1089 VolumeSlider::SetMuted(bool mute)
1099 /*****************************************************************************
1100 * VolumeSlider::_MakeBitmaps
1101 *****************************************************************************/
1103 VolumeSlider::_MakeBitmaps()
1107 // left side of slider
1108 memcpy(fLeftSideBits->Bits(), kVolumeSliderLeftBitmapBits,
1109 fLeftSideBits->BitsLength());
1110 // right side of slider
1111 memcpy(fRightSideBits->Bits(), kVolumeSliderRightBits,
1112 fRightSideBits->BitsLength());
1114 int32 length = fKnobBits->BitsLength();
1115 memcpy(fKnobBits->Bits(), kVolumeSliderKnobBits, length);
1116 uint8* bits = (uint8*)fKnobBits->Bits();
1117 // black was used in the knob to represent transparency
1118 // use screen to get index for the "transarent" color used in the bitmap
1119 BScreen screen(B_MAIN_SCREEN_ID);
1120 uint8 blackIndex = screen.IndexForColor(kBlack);
1121 // replace black index with transparent index
1122 for (int32 i = 0; i < length; i++)
1123 if (bits[i] == blackIndex)
1124 bits[i] = B_TRANSPARENT_MAGIC_CMAP8;
1128 // make ghosted versions of the bitmaps
1129 dim_bitmap(fLeftSideBits, kBackground, DIM_LEVEL);
1130 dim_bitmap(fRightSideBits, kBackground, DIM_LEVEL);
1131 dim_bitmap(fKnobBits, kBackground, DIM_LEVEL);
1135 // replace green color (and shadow) in left slider side
1136 bits = (uint8*)fLeftSideBits->Bits();
1137 length = fLeftSideBits->BitsLength();
1138 uint8 greenIndex = screen.IndexForColor(kGreen);
1139 uint8 greenShadowIndex = screen.IndexForColor(kGreenShadow);
1140 rgb_color shadow = tint_color(kBackground, B_DARKEN_3_TINT);
1141 rgb_color midShadow = tint_color(kBackground, B_DARKEN_4_TINT);
1142 uint8 replaceIndex = screen.IndexForColor(shadow);
1143 uint8 replaceShadowIndex = screen.IndexForColor(midShadow);
1144 for (int32 i = 0; i < length; i++)
1146 if (bits[i] == greenIndex)
1147 bits[i] = replaceIndex;
1148 else if (bits[i] == greenShadowIndex)
1149 bits[i] = replaceShadowIndex;
1155 /*****************************************************************************
1156 * VolumeSlider::_ValueFor
1157 *****************************************************************************/
1159 VolumeSlider::_ValueFor(float xPos) const
1162 float sliderStart = (r.left + kVolumeSliderBitmapWidth);
1163 float sliderEnd = (r.right - kVolumeSliderBitmapWidth);
1164 int32 value = fMinValue + (int32)(((xPos - sliderStart) * (fMaxValue - fMinValue))
1165 / (sliderEnd - sliderStart - 1.0));
1166 if (value < fMinValue)
1168 if (value > fMaxValue)
1173 /*****************************************************************************
1174 * PositionInfoView::PositionInfoView
1175 *****************************************************************************/
1176 PositionInfoView::PositionInfoView( BRect frame, const char* name,
1177 intf_thread_t * p_interface )
1178 : BView( frame, name, B_FOLLOW_NONE,
1179 B_WILL_DRAW | B_PULSE_NEEDED | B_FULL_UPDATE_ON_RESIZE ),
1180 fMode( MODE_SMALL ),
1181 fCurrentFileIndex( -1 ),
1182 fCurrentFileSize( -1 ),
1183 fCurrentTitleIndex( -1 ),
1184 fCurrentTitleSize( -1 ),
1185 fCurrentChapterIndex( -1 ),
1186 fCurrentChapterSize( -1 ),
1188 fTimeString( "-:--:--" ),
1189 fLastPulseUpdate( system_time() ),
1190 fStackedWidthCache( 0.0 ),
1191 fStackedHeightCache( 0.0 )
1193 p_intf = p_interface;
1195 SetViewColor( B_TRANSPARENT_32_BIT );
1196 SetLowColor( kBlack );
1197 SetHighColor( 0, 255, 0, 255 );
1198 SetFontSize( 11.0 );
1201 /*****************************************************************************
1202 * PositionInfoView::~PositionInfoView
1203 *****************************************************************************/
1204 PositionInfoView::~PositionInfoView()
1208 /*****************************************************************************
1209 * PositionInfoView::Draw
1210 *****************************************************************************/
1212 PositionInfoView::Draw( BRect updateRect )
1214 rgb_color background = ui_color( B_PANEL_BACKGROUND_COLOR );
1215 rgb_color shadow = tint_color( background, B_DARKEN_1_TINT );
1216 rgb_color darkShadow = tint_color( background, B_DARKEN_4_TINT );
1217 rgb_color light = tint_color( background, B_LIGHTEN_MAX_TINT );
1218 rgb_color softLight = tint_color( background, B_LIGHTEN_1_TINT );
1220 BRect r( Bounds() );
1221 BeginLineArray( 8 );
1222 AddLine( BPoint( r.left, r.bottom ),
1223 BPoint( r.left, r.top ), shadow );
1224 AddLine( BPoint( r.left + 1.0, r.top ),
1225 BPoint( r.right, r.top ), shadow );
1226 AddLine( BPoint( r.right, r.top + 1.0 ),
1227 BPoint( r.right, r.bottom ), softLight );
1228 AddLine( BPoint( r.right - 1.0, r.bottom ),
1229 BPoint( r.left + 1.0, r.bottom ), softLight );
1230 r.InsetBy( 1.0, 1.0 );
1231 AddLine( BPoint( r.left, r.bottom ),
1232 BPoint( r.left, r.top ), darkShadow );
1233 AddLine( BPoint( r.left + 1.0, r.top ),
1234 BPoint( r.right, r.top ), darkShadow );
1235 AddLine( BPoint( r.right, r.top + 1.0 ),
1236 BPoint( r.right, r.bottom ), light );
1237 AddLine( BPoint( r.right - 1.0, r.bottom ),
1238 BPoint( r.left + 1.0, r.bottom ), light );
1241 r.InsetBy( 1.0, 1.0 );
1242 FillRect( r, B_SOLID_LOW );
1245 GetFontHeight( &fh );
1250 float width = StringWidth( fTimeString.String() );
1251 DrawString( fTimeString.String(),
1252 BPoint( r.left + r.Width() / 2.0 - width / 2.0,
1253 r.top + r.Height() / 2.0 + fh.ascent / 2.0 - 1.0 ) );
1260 BFont smallFont = font;
1261 BFont bigFont = font;
1262 BFont tinyFont = font;
1263 smallFont.SetSize( r.Height() / 5.0 );
1264 bigFont.SetSize( r.Height() / 3.0 );
1265 tinyFont.SetSize( r.Height() / 7.0 );
1266 float timeHeight = r.Height() / 2.5;
1267 float height = ( r.Height() - timeHeight ) / 3.0;
1268 SetFont( &tinyFont );
1269 SetHighColor( 0, 180, 0, 255 );
1270 DrawString( _("File"), BPoint( r.left + 3.0, r.top + height ) );
1271 DrawString( _("Title"), BPoint( r.left + 3.0, r.top + 2.0 * height ) );
1272 DrawString( _("Chapter"), BPoint( r.left + 3.0, r.top + 3.0 * height ) );
1273 SetFont( &smallFont );
1275 SetHighColor( 0, 255, 0, 255 );
1277 _MakeString( helper, fCurrentFileIndex, fCurrentFileSize );
1278 float width = StringWidth( helper.String() );
1279 DrawString( helper.String(), BPoint( r.right - 3.0 - width, r.top + height ) );
1281 _MakeString( helper, fCurrentTitleIndex, fCurrentTitleSize );
1282 width = StringWidth( helper.String() );
1283 DrawString( helper.String(), BPoint( r.right - 3.0 - width, r.top + 2.0 * height ) );
1285 _MakeString( helper, fCurrentChapterIndex, fCurrentChapterSize );
1286 width = StringWidth( helper.String() );
1287 DrawString( helper.String(), BPoint( r.right - 3.0 - width, r.top + 3.0 * height ) );
1289 SetFont( &bigFont );
1290 width = StringWidth( fTimeString.String() );
1291 DrawString( fTimeString.String(),
1292 BPoint( r.left + r.Width() / 2.0 - width / 2.0,
1299 /*****************************************************************************
1300 * PositionInfoView::ResizeToPreferred
1301 *****************************************************************************/
1303 PositionInfoView::ResizeToPreferred()
1305 float width, height;
1306 GetPreferredSize( &width, &height );
1307 ResizeTo( width, height );
1310 /*****************************************************************************
1311 * PositionInfoView::GetPreferredSize
1312 *****************************************************************************/
1314 PositionInfoView::GetPreferredSize( float* width, float* height )
1316 if ( width && height )
1318 *width = 5.0 + ceilf( StringWidth( "0:00:00" ) ) + 5.0;
1320 GetFontHeight( &fh );
1321 *height = 3.0 + ceilf( fh.ascent ) + 3.0;
1322 fStackedWidthCache = *width * 1.2;
1323 fStackedHeightCache = *height * 2.7;
1327 /*****************************************************************************
1328 * PositionInfoView::Pulse
1329 *****************************************************************************/
1331 PositionInfoView::Pulse()
1333 // allow for Pulse frequency to be higher, MediaControlView needs it
1334 bigtime_t now = system_time();
1335 if ( now - fLastPulseUpdate > 900000 )
1339 p_intf->p_sys->p_wrapper->GetPlaylistInfo( index, size );
1340 SetFile( index + 1, size );
1341 p_intf->p_sys->p_wrapper->TitleInfo( index, size );
1342 SetTitle( index, size );
1343 p_intf->p_sys->p_wrapper->ChapterInfo( index, size );
1344 SetChapter( index, size );
1345 SetTime( p_intf->p_sys->p_wrapper->GetTimeAsString() );
1346 fLastPulseUpdate = now;
1351 /*****************************************************************************
1352 * PositionInfoView::GetBigPreferredSize
1353 *****************************************************************************/
1355 PositionInfoView::GetBigPreferredSize( float* width, float* height )
1357 if ( width && height )
1359 *width = fStackedWidthCache;
1360 *height = fStackedHeightCache;
1364 /*****************************************************************************
1365 * PositionInfoView::SetMode
1366 *****************************************************************************/
1368 PositionInfoView::SetMode( uint32 mode )
1370 if ( fMode != mode )
1373 _InvalidateContents();
1377 /*****************************************************************************
1378 * PositionInfoView::SetFile
1379 *****************************************************************************/
1381 PositionInfoView::SetFile( int32 index, int32 size )
1383 if ( fCurrentFileIndex != index || fCurrentFileSize != size )
1385 fCurrentFileIndex = index;
1386 fCurrentFileSize = size;
1387 _InvalidateContents();
1391 /*****************************************************************************
1392 * PositionInfoView::SetTitle
1393 *****************************************************************************/
1395 PositionInfoView::SetTitle( int32 index, int32 size )
1397 if ( fCurrentTitleIndex != index || fCurrentFileSize != size )
1399 fCurrentTitleIndex = index;
1400 fCurrentTitleSize = size;
1401 _InvalidateContents();
1405 /*****************************************************************************
1406 * PositionInfoView::SetChapter
1407 *****************************************************************************/
1409 PositionInfoView::SetChapter( int32 index, int32 size )
1411 if ( fCurrentChapterIndex != index || fCurrentFileSize != size )
1413 fCurrentChapterIndex = index;
1414 fCurrentChapterSize = size;
1415 _InvalidateContents();
1419 /*****************************************************************************
1420 * PositionInfoView::SetTime
1421 *****************************************************************************/
1423 PositionInfoView::SetTime( int32 seconds )
1425 if ( fSeconds != seconds )
1429 int32 minutes = seconds / 60;
1430 int32 hours = minutes / 60;
1431 seconds -= minutes * 60 - hours * 60 * 60;
1432 minutes -= hours * 60;
1433 fTimeString.SetTo( "" );
1434 fTimeString << hours << ":" << minutes << ":" << seconds;
1437 fTimeString.SetTo( "-:--:--" );
1440 _InvalidateContents();
1444 /*****************************************************************************
1445 * PositionInfoView::SetTime
1446 *****************************************************************************/
1448 PositionInfoView::SetTime( const char* string )
1450 fTimeString.SetTo( string );
1451 _InvalidateContents();
1454 /*****************************************************************************
1455 * PositionInfoView::_InvalidateContents
1456 *****************************************************************************/
1458 PositionInfoView::_InvalidateContents( uint32 which )
1460 BRect r( Bounds() );
1461 r.InsetBy( 2.0, 2.0 );
1465 /*****************************************************************************
1466 * PositionInfoView::_InvalidateContents
1467 *****************************************************************************/
1469 PositionInfoView::_MakeString( BString& into, int32 index, int32 maxIndex ) const
1472 if ( index >= 0 && maxIndex >= 0 )
1477 if ( maxIndex >= 0 )