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 */
41 #include "VlcWrapper.h"
43 #include "DrawingTidbits.h"
44 #include "InterfaceWindow.h"
46 #include "TransportButton.h"
47 #include "ListViews.h"
48 #include "MediaControlView.h"
50 #define BORDER_INSET 6.0
52 #define SPEAKER_SLIDER_DIST 6.0
53 #define VOLUME_MIN_WIDTH 70.0
55 #define VOLUME_SLIDER_LAYOUT_WEIGHT 2.0
56 #define SEEK_SLIDER_KNOB_WIDTH 8.0
58 // slider colors are hardcoded here, because that's just
59 // what they currently are within those bitmaps
60 const rgb_color kGreen = (rgb_color){ 152, 203, 152, 255 };
61 const rgb_color kGreenShadow = (rgb_color){ 102, 152, 102, 255 };
62 const rgb_color kBackground = (rgb_color){ 216, 216, 216, 255 };
63 const rgb_color kSeekGreen = (rgb_color){ 171, 221, 161, 255 };
64 const rgb_color kSeekGreenShadow = (rgb_color){ 144, 186, 136, 255 };
65 const rgb_color kSeekRed = (rgb_color){ 255, 0, 0, 255 };
66 const rgb_color kSeekRedLight = (rgb_color){ 255, 152, 152, 255 };
67 const rgb_color kSeekRedShadow = (rgb_color){ 178, 0, 0, 255 };
69 #define DISABLED_SEEK_MESSAGE _("Drop files to play")
75 MSG_SKIP_BACKWARDS = 'skpb',
76 MSG_SKIP_FORWARD = 'skpf',
80 MediaControlView::MediaControlView(BRect frame, intf_thread_t *p_interface)
81 : BBox(frame, NULL, B_FOLLOW_NONE, B_WILL_DRAW | B_FRAME_EVENTS | B_PULSE_NEEDED,
84 fCurrentRate(INPUT_RATE_DEFAULT),
86 fBottomControlHeight(0.0),
91 BRect frame(0.0, 0.0, 10.0, 10.0);
94 fSeekSlider = new SeekSlider( frame, "seek slider", this,
95 0, SEEKSLIDER_RANGE );
96 fSeekSlider->SetValue(0);
97 fSeekSlider->ResizeToPreferred();
98 AddChild( fSeekSlider );
102 frame.SetRightBottom(kSkipButtonSize);
103 fBottomControlHeight = kRewindBitmapHeight - 1.0;
104 fSkipBack = new TransportButton(frame, B_EMPTY_STRING,
106 kPressedSkipBackBitmapBits,
107 kDisabledSkipBackBitmapBits,
108 new BMessage(MSG_SKIP_BACKWARDS));
109 AddChild( fSkipBack );
112 frame.SetRightBottom(kPlayButtonSize);
113 if (fBottomControlHeight < kPlayPauseBitmapHeight - 1.0)
114 fBottomControlHeight = kPlayPauseBitmapHeight - 1.0;
115 fPlayPause = new PlayPauseButton(frame, B_EMPTY_STRING,
116 kPlayButtonBitmapBits,
117 kPressedPlayButtonBitmapBits,
118 kDisabledPlayButtonBitmapBits,
119 kPlayingPlayButtonBitmapBits,
120 kPressedPlayingPlayButtonBitmapBits,
121 kPausedPlayButtonBitmapBits,
122 kPressedPausedPlayButtonBitmapBits,
123 new BMessage(START_PLAYBACK));
125 AddChild( fPlayPause );
128 frame.SetRightBottom(kSkipButtonSize);
129 fSkipForward = new TransportButton(frame, B_EMPTY_STRING,
130 kSkipForwardBitmapBits,
131 kPressedSkipForwardBitmapBits,
132 kDisabledSkipForwardBitmapBits,
133 new BMessage(MSG_SKIP_FORWARD));
134 AddChild( fSkipForward );
137 fForward = new TransportButton(frame, B_EMPTY_STRING,
139 kPressedForwardBitmapBits,
140 kDisabledForwardBitmapBits,
141 new BMessage(MSG_FORWARD));
142 // AddChild( fForward );
145 fRewind = new TransportButton(frame, B_EMPTY_STRING,
147 kPressedRewindBitmapBits,
148 kDisabledRewindBitmapBits,
149 new BMessage(MSG_REWIND));
150 // AddChild( fRewind );
153 frame.SetRightBottom(kStopButtonSize);
154 if (fBottomControlHeight < kStopBitmapHeight - 1.0)
155 fBottomControlHeight = kStopBitmapHeight - 1.0;
156 fStop = new TransportButton(frame, B_EMPTY_STRING,
157 kStopButtonBitmapBits,
158 kPressedStopButtonBitmapBits,
159 kDisabledStopButtonBitmapBits,
160 new BMessage(STOP_PLAYBACK));
164 frame.SetRightBottom(kSpeakerButtonSize);
165 if (fBottomControlHeight < kSpeakerIconBitmapHeight - 1.0)
166 fBottomControlHeight = kSpeakerIconBitmapHeight - 1.0;
167 fMute = new TransportButton(frame, B_EMPTY_STRING,
169 kPressedSpeakerIconBits,
171 new BMessage(VOLUME_MUTE));
176 fVolumeSlider = new VolumeSlider(BRect(0.0, 0.0, VOLUME_MIN_WIDTH,
177 kVolumeSliderBitmapHeight - 1.0),
178 "volume slider", 1, AOUT_VOLUME_MAX,
179 new BMessage(VOLUME_CHG));
180 fVolumeSlider->SetValue( config_GetInt( p_intf, "volume" ) );
181 AddChild( fVolumeSlider );
183 // Position Info View
184 fPositionInfo = new PositionInfoView(BRect(0.0, 0.0, 10.0, 10.0), "led",
186 fPositionInfo->ResizeToPreferred();
187 AddChild( fPositionInfo );
191 MediaControlView::~MediaControlView()
197 MediaControlView::AttachedToWindow()
199 // we are now a valid BHandler
200 fRewind->SetTarget(this);
201 fForward->SetTarget(this);
202 fSkipBack->SetTarget(this);
203 fSkipForward->SetTarget(this);
204 fVolumeSlider->SetTarget(Window());
206 BRect r(_MinFrame());
207 if (BMenuBar* menuBar = Window()->KeyMenuBar()) {
209 menuBar->GetPreferredSize(&width, &height);
210 // r.bottom += menuBar->Bounds().Height();
212 // see that our calculated minimal width is not smaller than what
213 // the menubar can be
214 printf("preferred: width: %f, height: %f - width: %f\n", width, height, r.Width());
220 Window()->SetSizeLimits(r.Width(), r.Width() * 1.8, r.Height(), r.Height() * 1.3);
221 if (!Window()->Bounds().Contains(r))
222 Window()->ResizeTo(r.Width(), r.Height());
224 FrameResized(Bounds().Width(), Bounds().Height());
226 // get pulse message every two frames
227 Window()->SetPulseRate(80000);
232 MediaControlView::FrameResized(float width, float height)
235 // make sure we don't leave dirty pixels
236 // (B_FULL_UPDATE_ON_RESIZE == annoying flicker -> this is smarter)
237 if (fOldBounds.Width() < r.Width())
238 Invalidate(BRect(fOldBounds.right, fOldBounds.top + 1.0,
239 fOldBounds.right, fOldBounds.bottom - 1.0));
241 Invalidate(BRect(r.right, r.top + 1.0,
242 r.right, r.bottom - 1.0));
243 if (fOldBounds.Height() < r.Height())
244 Invalidate(BRect(fOldBounds.left + 1.0, fOldBounds.bottom,
245 fOldBounds.right - 1.0, fOldBounds.bottom));
247 Invalidate(BRect(r.left + 1.0, r.bottom,
248 r.right - 1.0, r.bottom));
249 // remember for next time
252 r.InsetBy(BORDER_INSET, BORDER_INSET);
258 MediaControlView::GetPreferredSize(float* width, float* height)
262 BRect r(_MinFrame());
264 *height = r.Height();
270 MediaControlView::MessageReceived(BMessage* message)
272 switch (message->what)
278 case MSG_SKIP_BACKWARDS:
279 Window()->PostMessage(NAVIGATE_PREV);
281 case MSG_SKIP_FORWARD:
282 Window()->PostMessage(NAVIGATE_NEXT);
285 BBox::MessageReceived(message);
292 MediaControlView::Pulse()
294 InterfaceWindow* window = dynamic_cast<InterfaceWindow*>(Window());
295 if (window && window->IsStopped())
296 fPlayPause->SetStopped();
298 unsigned short i_volume;
299 aout_VolumeGet( p_intf, (audio_volume_t*)&i_volume );
300 fVolumeSlider->SetValue( i_volume );
305 MediaControlView::SetProgress( float position )
307 fSeekSlider->SetPosition( position );
312 MediaControlView::SetStatus(int status, int rate)
314 // we need to set the button status periodically
315 // (even if it is the same) to get a blinking button
316 fCurrentStatus = status;
320 fPlayPause->SetPlaying();
323 fPlayPause->SetPaused();
326 fPlayPause->SetStopped();
329 if (rate != fCurrentRate)
332 if ( rate < INPUT_RATE_DEFAULT )
341 MediaControlView::SetEnabled(bool enabled)
343 if( ( enabled && fIsEnabled ) ||
344 ( !enabled && !fIsEnabled ) )
346 /* do not redraw if it is not necessary */
352 fSkipBack->SetEnabled( enabled );
353 fPlayPause->SetEnabled( enabled );
354 fSkipForward->SetEnabled( enabled );
355 fStop->SetEnabled( enabled );
356 fMute->SetEnabled( enabled );
357 fVolumeSlider->SetEnabled( enabled );
358 fSeekSlider->SetEnabled( enabled );
359 fRewind->SetEnabled( enabled );
360 fForward->SetEnabled( enabled );
362 fIsEnabled = enabled;
368 MediaControlView::SetAudioEnabled(bool enabled)
370 fMute->SetEnabled(enabled);
371 fVolumeSlider->SetEnabled(enabled);
376 MediaControlView::GetSeekTo() const
378 return fSeekSlider->Value();
383 MediaControlView::GetVolume() const
385 return fVolumeSlider->Value();
390 MediaControlView::SetSkippable(bool backward, bool forward)
392 fSkipBack->SetEnabled(backward);
393 fSkipForward->SetEnabled(forward);
398 MediaControlView::SetMuted(bool mute)
400 fVolumeSlider->SetMuted(mute);
405 MediaControlView::_LayoutControls(BRect frame) const
409 // calculate absolutly minimal width
410 float minWidth = fSkipBack->Bounds().Width();
411 // minWidth += fRewind->Bounds().Width();
412 minWidth += fStop->Bounds().Width();
413 minWidth += fPlayPause->Bounds().Width();
414 // minWidth += fForward->Bounds().Width();
415 minWidth += fSkipForward->Bounds().Width();
416 minWidth += fMute->Bounds().Width();
417 minWidth += VOLUME_MIN_WIDTH;
419 // layout time slider and info view
421 fPositionInfo->GetBigPreferredSize( &width, &height );
422 float ratio = width / height;
423 width = r.Height() * ratio;
424 if (frame.Width() - minWidth - MIN_SPACE >= width
425 && frame.Height() >= height)
427 r.right = r.left + width;
428 fPositionInfo->SetMode(PositionInfoView::MODE_BIG);
429 _LayoutControl(fPositionInfo, r, true, true);
430 frame.left = r.right + MIN_SPACE;
432 r.right = frame.right;
433 // r.bottom = r.top + r.Height() / 2.0 - MIN_SPACE / 2.0;
434 r.bottom = r.top + fSeekSlider->Bounds().Height();
435 _LayoutControl(fSeekSlider, r, true);
439 fPositionInfo->GetPreferredSize( &width, &height );
440 fPositionInfo->SetMode(PositionInfoView::MODE_SMALL);
441 fPositionInfo->ResizeTo(width, height);
442 r.bottom = r.top + r.Height() / 2.0 - MIN_SPACE / 2.0;
443 r.right = r.left + fPositionInfo->Bounds().Width();
444 _LayoutControl(fPositionInfo, r, true );
445 r.left = r.right + MIN_SPACE;
446 r.right = frame.right;
447 _LayoutControl(fSeekSlider, r, true);
449 float currentWidth = frame.Width();
450 float space = (currentWidth - minWidth) / 6.0;//8.0;
452 space = MIN_SPACE + (space - MIN_SPACE) / VOLUME_SLIDER_LAYOUT_WEIGHT;
453 // layout controls with "space" inbetween
455 r.top = r.bottom + MIN_SPACE + 1.0;
456 r.bottom = frame.bottom;
458 r.right = r.left + fSkipBack->Bounds().Width();
459 _LayoutControl(fSkipBack, r);
461 // r.left = r.right + space;
462 // r.right = r.left + fRewind->Bounds().Width();
463 // _LayoutControl(fRewind, r);
465 r.left = r.right + space;
466 r.right = r.left + fStop->Bounds().Width();
467 _LayoutControl(fStop, r);
469 r.left = r.right + space;
470 r.right = r.left + fPlayPause->Bounds().Width();
471 _LayoutControl(fPlayPause, r);
473 // r.left = r.right + space;
474 // r.right = r.left + fForward->Bounds().Width();
475 // _LayoutControl(fForward, r);
477 r.left = r.right + space;
478 r.right = r.left + fSkipForward->Bounds().Width();
479 _LayoutControl(fSkipForward, r);
481 r.left = r.right + space + space;
482 r.right = r.left + fMute->Bounds().Width();
483 _LayoutControl(fMute, r);
485 r.left = r.right + SPEAKER_SLIDER_DIST; // keep speaker icon and volume slider attached
486 r.right = frame.right;
487 _LayoutControl(fVolumeSlider, r, true);
492 MediaControlView::_MinFrame() const
494 // add up width of controls along bottom (seek slider will likely adopt)
495 float minWidth = 2 * BORDER_INSET;
496 minWidth += fSkipBack->Bounds().Width() + MIN_SPACE;
497 // minWidth += fRewind->Bounds().Width() + MIN_SPACE;
498 minWidth += fStop->Bounds().Width() + MIN_SPACE;
499 minWidth += fPlayPause->Bounds().Width() + MIN_SPACE;
500 // minWidth += fForward->Bounds().Width() + MIN_SPACE;
501 minWidth += fSkipForward->Bounds().Width() + MIN_SPACE + MIN_SPACE;
502 minWidth += fMute->Bounds().Width() + SPEAKER_SLIDER_DIST;
503 minWidth += VOLUME_MIN_WIDTH;
505 // add up height of seek slider and heighest control on bottom
506 float minHeight = 2 * BORDER_INSET;
507 minHeight += fSeekSlider->Bounds().Height() + MIN_SPACE + MIN_SPACE / 2.0;
508 minHeight += fBottomControlHeight;
509 return BRect(0.0, 0.0, minWidth - 1.0, minHeight - 1.0);
514 MediaControlView::_LayoutControl(BView* view, BRect frame,
515 bool resizeWidth, bool resizeHeight) const
519 frame.top = (frame.top + frame.bottom) / 2.0 - view->Bounds().Height() / 2.0;
521 //center horizontally
522 frame.left = (frame.left + frame.right) / 2.0 - view->Bounds().Width() / 2.0;
523 view->MoveTo(frame.LeftTop());
524 float width = resizeWidth ? frame.Width() : view->Bounds().Width();
525 float height = resizeHeight ? frame.Height() : view->Bounds().Height();
526 if (resizeWidth || resizeHeight)
527 view->ResizeTo(width, height);
532 /*****************************************************************************
534 *****************************************************************************/
535 SeekSlider::SeekSlider(BRect frame, const char* name, MediaControlView *owner,
536 int32 minValue, int32 maxValue)
537 : BControl(frame, name, NULL, NULL, B_FOLLOW_NONE,
538 B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE),
544 BFont font(be_plain_font);
549 SeekSlider::~SeekSlider()
554 /*****************************************************************************
555 * VolumeSlider::AttachedToWindow
556 *****************************************************************************/
558 SeekSlider::AttachedToWindow()
560 BControl::AttachedToWindow();
561 SetViewColor(B_TRANSPARENT_32_BIT);
564 /*****************************************************************************
566 *****************************************************************************/
568 SeekSlider::Draw(BRect updateRect)
571 float knobWidth2 = SEEK_SLIDER_KNOB_WIDTH / 2.0;
572 float sliderStart = (r.left + knobWidth2);
573 float sliderEnd = (r.right - knobWidth2);
574 float knobPos = sliderStart
575 + floorf((sliderEnd - sliderStart - 1.0) * (Value() - fMinValue)
576 / (fMaxValue - fMinValue) + 0.5);
577 // draw both sides (the original from Be doesn't seem
578 // to make a difference for enabled/disabled state)
579 // DrawBitmapAsync(fLeftSideBits, r.LeftTop());
580 // DrawBitmapAsync(fRightSideBits, BPoint(sliderEnd + 1.0, r.top));
581 // colors for the slider area between the two bitmaps
582 rgb_color background = kBackground;//ui_color(B_PANEL_BACKGROUND_COLOR);
583 rgb_color shadow = tint_color(background, B_DARKEN_2_TINT);
584 rgb_color softShadow = tint_color(background, B_DARKEN_1_TINT);
585 rgb_color darkShadow = tint_color(background, B_DARKEN_4_TINT);
586 rgb_color midShadow = tint_color(background, B_DARKEN_3_TINT);
587 rgb_color light = tint_color(background, B_LIGHTEN_MAX_TINT);
588 rgb_color softLight = tint_color(background, B_LIGHTEN_1_TINT);
589 rgb_color green = kSeekGreen;
590 rgb_color greenShadow = kSeekGreenShadow;
591 rgb_color black = kBlack;
592 rgb_color dotGrey = midShadow;
593 rgb_color dotGreen = greenShadow;
595 _StrokeFrame(r, softShadow, softShadow, softLight, softLight);
597 _StrokeFrame(r, black, black, light, light);
602 _StrokeFrame(r, greenShadow, greenShadow, green, green);
605 _StrokeFrame(r, greenShadow, greenShadow, green, green);
611 int32 dotCount = (int32)(r.Width() / 6.0);
613 dotPos.y = r.top + 2.0;
614 SetHighColor(dotGreen);
615 for (int32 i = 0; i < dotCount; i++)
617 dotPos.x = sliderStart + i * 6.0 + 5.0;
618 StrokeLine(dotPos, BPoint(dotPos.x, dotPos.y + 6.0));
623 r.left = knobPos - knobWidth2;
624 r.right = knobPos + knobWidth2;
626 float handleBottomSize = 2.0;
627 float handleArrowSize = 6.0;
630 AddLine(BPoint(r.left, r.top + handleBottomSize),
631 BPoint(r.left, r.top), black);
632 AddLine(BPoint(r.left + 1.0, r.top),
633 BPoint(r.right, r.top), black);
634 AddLine(BPoint(r.right, r.top + 1.0),
635 BPoint(r.right, r.top + handleBottomSize), black);
636 AddLine(BPoint(r.right - 1.0, r.top + handleBottomSize + 1.0),
637 BPoint(knobPos, r.top + handleArrowSize), black);
638 AddLine(BPoint(knobPos - 1.0, r.top + handleArrowSize - 1.0),
639 BPoint(r.left + 1.0, r.top + handleBottomSize + 1.0), black);
641 AddLine(BPoint(r.left, r.bottom),
642 BPoint(r.left, r.bottom - handleBottomSize), black);
643 AddLine(BPoint(r.left + 1.0, r.bottom - handleBottomSize - 1.0),
644 BPoint(knobPos, r.bottom - handleArrowSize), black);
645 AddLine(BPoint(knobPos + 1.0, r.bottom - handleArrowSize + 1.0),
646 BPoint(r.right, r.bottom - handleBottomSize), black);
647 AddLine(BPoint(r.right, r.bottom - handleBottomSize + 1.0),
648 BPoint(r.right, r.bottom), black);
649 AddLine(BPoint(r.right - 1.0, r.bottom),
650 BPoint(r.left + 1.0, r.bottom), black);
652 // inner red light and shadow lines
655 handleArrowSize -= 2.0;
658 AddLine(BPoint(r.left, r.top + handleBottomSize),
659 BPoint(r.left, r.top), kSeekRedLight);
660 AddLine(BPoint(r.left + 1.0, r.top),
661 BPoint(r.right, r.top), kSeekRedLight);
662 AddLine(BPoint(r.right, r.top + 1.0),
663 BPoint(r.right, r.top + handleBottomSize), kSeekRedShadow);
664 AddLine(BPoint(r.right - 1.0, r.top + handleBottomSize + 1.0),
665 BPoint(knobPos, r.top + handleArrowSize), kSeekRedShadow);
666 AddLine(BPoint(knobPos - 1.0, r.top + handleArrowSize - 1.0),
667 BPoint(r.left + 1.0, r.top + handleBottomSize + 1.0), kSeekRedLight);
669 AddLine(BPoint(r.left, r.bottom),
670 BPoint(r.left, r.bottom - handleBottomSize), kSeekRedLight);
671 AddLine(BPoint(r.left + 1.0, r.bottom - handleBottomSize - 1.0),
672 BPoint(knobPos, r.bottom - handleArrowSize), kSeekRedLight);
673 AddLine(BPoint(knobPos + 1.0, r.bottom - handleArrowSize + 1.0),
674 BPoint(r.right, r.bottom - handleBottomSize), kSeekRedShadow);
675 AddLine(BPoint(r.right, r.bottom - handleBottomSize + 1.0),
676 BPoint(r.right, r.bottom), kSeekRedShadow);
677 AddLine(BPoint(r.right - 1.0, r.bottom),
678 BPoint(r.left + 1.0, r.bottom), kSeekRedShadow);
680 // fill rest of handles with red
681 SetHighColor(kSeekRed);
683 handleArrowSize -= 2.0;
685 // upper handle arrow
688 arrow[1].x = r.right;
690 arrow[2].x = knobPos;
691 arrow[2].y = r.top + handleArrowSize;
692 FillPolygon(arrow, 3);
693 // lower handle arrow
695 arrow[0].y = r.bottom;
696 arrow[1].x = r.right;
697 arrow[1].y = r.bottom;
698 arrow[2].x = knobPos;
699 arrow[2].y = r.bottom - handleArrowSize;
700 FillPolygon(arrow, 3);
705 _StrokeFrame(r, darkShadow, darkShadow, darkShadow, darkShadow);
707 _StrokeFrame(r, darkShadow, darkShadow, darkShadow, darkShadow);
709 SetHighColor(darkShadow);
712 float width = floorf(StringWidth(DISABLED_SEEK_MESSAGE));
713 float textPos = r.left + r.Width() / 2.0 - width / 2.0;
714 pattern stripes = {{ 0xc7, 0x8f, 0x1f, 0x3e, 0x7c, 0xf8, 0xf1, 0xe3 }};
715 BRect stripesRect(r);
716 stripesRect.right = textPos - 5.0;
717 FillRect(stripesRect, stripes);
718 stripesRect.left = textPos + width + 3.0;
719 stripesRect.right = r.right;
720 FillRect(stripesRect, stripes);
722 r.left = textPos - 4.0;
723 r.right = textPos + width + 2.0;
725 SetHighColor(shadow);
726 SetLowColor(darkShadow);
729 DrawString(DISABLED_SEEK_MESSAGE, BPoint(textPos, r.top + ceilf(fh.ascent) - 1.0));
733 /*****************************************************************************
734 * SeekSlider::MouseDown
735 *****************************************************************************/
737 SeekSlider::MouseDown(BPoint where)
739 if (IsEnabled() && Bounds().Contains(where))
741 SetValue(_ValueFor(where.x));
743 SetMouseEventMask(B_POINTER_EVENTS, B_LOCK_WINDOW_FOCUS);
748 /*****************************************************************************
749 * SeekSlider::MouseMoved
750 *****************************************************************************/
752 SeekSlider::MouseMoved(BPoint where, uint32 code, const BMessage* dragMessage)
756 SetValue(_ValueFor(where.x));
761 /*****************************************************************************
762 * SeekSlider::MouseUp
763 *****************************************************************************/
765 SeekSlider::MouseUp(BPoint where)
774 /*****************************************************************************
775 * SeekSlider::ResizeToPreferred
776 *****************************************************************************/
778 SeekSlider::ResizeToPreferred()
780 float width = 15.0 + StringWidth(DISABLED_SEEK_MESSAGE) + 15.0;
781 ResizeTo(width, 17.0);
784 /*****************************************************************************
785 * SeekSlider::SetPosition
786 *****************************************************************************/
788 SeekSlider::SetPosition(float position)
792 SetValue(fMinValue + (int32)floorf((fMaxValue - fMinValue) * position + 0.5));
797 /*****************************************************************************
798 * SeekSlider::_ValueFor
799 *****************************************************************************/
801 SeekSlider::_ValueFor(float xPos) const
804 float knobWidth2 = SEEK_SLIDER_KNOB_WIDTH / 2.0;
805 float sliderStart = (r.left + knobWidth2);
806 float sliderEnd = (r.right - knobWidth2);
807 int32 value = fMinValue + (int32)(((xPos - sliderStart) * (fMaxValue - fMinValue))
808 / (sliderEnd - sliderStart - 1.0));
809 if (value < fMinValue)
811 if (value > fMaxValue)
816 /*****************************************************************************
817 * SeekSlider::_StrokeFrame
818 *****************************************************************************/
820 SeekSlider::_StrokeFrame(BRect r, rgb_color left, rgb_color top,
821 rgb_color right, rgb_color bottom)
824 AddLine(BPoint(r.left, r.bottom), BPoint(r.left, r.top), left);
825 AddLine(BPoint(r.left + 1.0, r.top), BPoint(r.right, r.top), top);
826 AddLine(BPoint(r.right, r.top + 1.0), BPoint(r.right, r.bottom), right);
827 AddLine(BPoint(r.right - 1.0, r.bottom), BPoint(r.left + 1.0, r.bottom), bottom);
831 /*****************************************************************************
832 * SeekSlider::_BeginSeek
833 *****************************************************************************/
835 SeekSlider::_BeginSeek()
837 fOwner->fScrubSem = create_sem(0, "Vlc::fScrubSem");
838 if (fOwner->fScrubSem >= B_OK)
839 release_sem(fOwner->fScrubSem);
842 /*****************************************************************************
844 *****************************************************************************/
848 if (fOwner->fScrubSem >= B_OK)
849 delete_sem(fOwner->fScrubSem);
850 fOwner->fScrubSem = create_sem(0, "Vlc::fScrubSem");
851 if (fOwner->fScrubSem >= B_OK)
852 release_sem(fOwner->fScrubSem);
855 /*****************************************************************************
856 * SeekSlider::_EndSeek
857 *****************************************************************************/
859 SeekSlider::_EndSeek()
861 if (fOwner->fScrubSem >= B_OK)
862 delete_sem(fOwner->fScrubSem);
863 fOwner->fScrubSem = B_ERROR;
867 /*****************************************************************************
869 *****************************************************************************/
870 VolumeSlider::VolumeSlider(BRect frame, const char* name, int32 minValue, int32 maxValue,
871 BMessage* message, BHandler* target)
872 : BControl(frame, name, NULL, message, B_FOLLOW_NONE,
873 B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE),
875 fRightSideBits(NULL),
885 BRect r(BPoint(0.0, 0.0), kVolumeSliderBitmapSize);
886 fLeftSideBits = new BBitmap(r, B_CMAP8);
887 fRightSideBits = new BBitmap(r, B_CMAP8);
888 r.Set(0.0, 0.0, kVolumeSliderKnobBitmapSize.x, kVolumeSliderKnobBitmapSize.y);
889 fKnobBits = new BBitmap(r, B_CMAP8);
894 /*****************************************************************************
895 * VolumeSlider destructor
896 *****************************************************************************/
897 VolumeSlider::~VolumeSlider()
899 delete fLeftSideBits;
900 delete fRightSideBits;
904 /*****************************************************************************
905 * VolumeSlider::AttachedToWindow
906 *****************************************************************************/
908 VolumeSlider::AttachedToWindow()
910 BControl::AttachedToWindow();
911 SetViewColor(B_TRANSPARENT_32_BIT);
914 /*****************************************************************************
915 * VolumeSlider::SetValue
916 *****************************************************************************/
918 VolumeSlider::SetValue(int32 value)
920 if (value != Value())
922 BControl::SetValue(value);
927 /*****************************************************************************
928 * VolumeSlider::SetEnabled
929 *****************************************************************************/
931 VolumeSlider::SetEnabled(bool enable)
933 if (enable != IsEnabled())
935 BControl::SetEnabled(enable);
941 /*****************************************************************************
943 *****************************************************************************/
945 VolumeSlider::Draw(BRect updateRect)
950 float sliderSideWidth = kVolumeSliderBitmapWidth;
951 float sliderStart = (r.left + sliderSideWidth);
952 float sliderEnd = (r.right - sliderSideWidth);
953 float knobPos = sliderStart
954 + (sliderEnd - sliderStart - 1.0) * (Value() - fMinValue)
955 / (fMaxValue - fMinValue);
956 // draw both sides (the original from Be doesn't seem
957 // to make a difference for enabled/disabled state)
958 DrawBitmapAsync(fLeftSideBits, r.LeftTop());
959 DrawBitmapAsync(fRightSideBits, BPoint(sliderEnd + 1.0, r.top));
960 // colors for the slider area between the two bitmaps
961 rgb_color background = kBackground;//ui_color(B_PANEL_BACKGROUND_COLOR);
962 rgb_color shadow = tint_color(background, B_DARKEN_2_TINT);
963 rgb_color softShadow = tint_color(background, B_DARKEN_1_TINT);
964 rgb_color darkShadow = tint_color(background, B_DARKEN_4_TINT);
965 rgb_color midShadow = tint_color(background, B_DARKEN_3_TINT);
966 rgb_color light = tint_color(background, B_LIGHTEN_MAX_TINT);
967 rgb_color softLight = tint_color(background, B_LIGHTEN_1_TINT);
968 rgb_color green = kGreen;
969 rgb_color greenShadow = kGreenShadow;
970 rgb_color black = kBlack;
971 rgb_color dotGrey = midShadow;
972 rgb_color dotGreen = greenShadow;
973 // make dimmed version of colors if we're disabled
976 shadow = (rgb_color){ 200, 200, 200, 255 };
977 softShadow = dimmed_color_cmap8(softShadow, background, DIM_LEVEL);
978 darkShadow = dimmed_color_cmap8(darkShadow, background, DIM_LEVEL);
980 light = dimmed_color_cmap8(light, background, DIM_LEVEL);
981 softLight = dimmed_color_cmap8(softLight, background, DIM_LEVEL);
982 green = dimmed_color_cmap8(green, background, DIM_LEVEL);
983 greenShadow = dimmed_color_cmap8(greenShadow, background, DIM_LEVEL);
984 black = dimmed_color_cmap8(black, background, DIM_LEVEL);
989 green = tint_color(kBackground, B_DARKEN_3_TINT);
990 greenShadow = tint_color(kBackground, B_DARKEN_4_TINT);
991 dotGreen = greenShadow;
993 // draw slider edges between bitmaps
995 AddLine(BPoint(sliderStart, r.top),
996 BPoint(sliderEnd, r.top), softShadow);
997 AddLine(BPoint(sliderStart, r.bottom),
998 BPoint(sliderEnd, r.bottom), softLight);
1000 AddLine(BPoint(sliderStart, r.top),
1001 BPoint(sliderEnd, r.top), black);
1002 AddLine(BPoint(sliderStart, r.bottom),
1003 BPoint(sliderEnd, r.bottom), light);
1005 AddLine(BPoint(sliderStart, r.top),
1006 BPoint(knobPos, r.top), greenShadow);
1007 AddLine(BPoint(knobPos, r.top),
1008 BPoint(sliderEnd, r.top), midShadow);
1010 AddLine(BPoint(sliderStart, r.top),
1011 BPoint(knobPos, r.top), greenShadow);
1013 // fill rest inside of slider
1014 r.InsetBy(0.0, 1.0);
1015 r.left = sliderStart;
1017 SetHighColor(green);
1018 FillRect(r, B_SOLID_HIGH);
1019 r.left = knobPos + 1.0;
1020 r.right = sliderEnd;
1022 SetHighColor(shadow);
1023 FillRect(r, B_SOLID_HIGH);
1024 // draw little dots inside
1025 int32 dotCount = (int32)((sliderEnd - sliderStart) / 5.0);
1027 dotPos.y = r.top + 4.0;
1028 for (int32 i = 0; i < dotCount; i++)
1030 dotPos.x = sliderStart + i * 5.0 + 4.0;
1031 SetHighColor(dotPos.x < knobPos ? dotGreen : dotGrey);
1032 StrokeLine(dotPos, BPoint(dotPos.x, dotPos.y + 1.0));
1036 SetDrawingMode(B_OP_OVER); // part of knob is transparent
1037 DrawBitmapAsync(fKnobBits, BPoint(knobPos - kVolumeSliderKnobWidth / 2, r.top));
1041 /*****************************************************************************
1042 * VolumeSlider::MouseDown
1043 *****************************************************************************/
1045 VolumeSlider::MouseDown(BPoint where)
1047 if (Bounds().Contains(where) && IsEnabled())
1050 SetValue(_ValueFor(where.x));
1051 SetMouseEventMask(B_POINTER_EVENTS, B_LOCK_WINDOW_FOCUS);
1055 /*****************************************************************************
1056 * VolumeSlider::MouseMoved
1057 *****************************************************************************/
1059 VolumeSlider::MouseMoved(BPoint where, uint32 transit, const BMessage* dragMessage)
1062 SetValue(_ValueFor(where.x));
1065 /*****************************************************************************
1066 * VolumeSlider::MouseUp
1067 *****************************************************************************/
1069 VolumeSlider::MouseUp(BPoint where)
1075 /*****************************************************************************
1076 * VolumeSlider::IsValid
1077 *****************************************************************************/
1079 VolumeSlider::IsValid() const
1081 return (fLeftSideBits && fLeftSideBits->IsValid()
1082 && fRightSideBits && fRightSideBits->IsValid()
1083 && fKnobBits && fKnobBits->IsValid());
1086 /*****************************************************************************
1087 * VolumeSlider::SetMuted
1088 *****************************************************************************/
1090 VolumeSlider::SetMuted(bool mute)
1100 /*****************************************************************************
1101 * VolumeSlider::_MakeBitmaps
1102 *****************************************************************************/
1104 VolumeSlider::_MakeBitmaps()
1108 // left side of slider
1109 memcpy(fLeftSideBits->Bits(), kVolumeSliderLeftBitmapBits,
1110 fLeftSideBits->BitsLength());
1111 // right side of slider
1112 memcpy(fRightSideBits->Bits(), kVolumeSliderRightBits,
1113 fRightSideBits->BitsLength());
1115 int32 length = fKnobBits->BitsLength();
1116 memcpy(fKnobBits->Bits(), kVolumeSliderKnobBits, length);
1117 uint8* bits = (uint8*)fKnobBits->Bits();
1118 // black was used in the knob to represent transparency
1119 // use screen to get index for the "transarent" color used in the bitmap
1120 BScreen screen(B_MAIN_SCREEN_ID);
1121 uint8 blackIndex = screen.IndexForColor(kBlack);
1122 // replace black index with transparent index
1123 for (int32 i = 0; i < length; i++)
1124 if (bits[i] == blackIndex)
1125 bits[i] = B_TRANSPARENT_MAGIC_CMAP8;
1129 // make ghosted versions of the bitmaps
1130 dim_bitmap(fLeftSideBits, kBackground, DIM_LEVEL);
1131 dim_bitmap(fRightSideBits, kBackground, DIM_LEVEL);
1132 dim_bitmap(fKnobBits, kBackground, DIM_LEVEL);
1136 // replace green color (and shadow) in left slider side
1137 bits = (uint8*)fLeftSideBits->Bits();
1138 length = fLeftSideBits->BitsLength();
1139 uint8 greenIndex = screen.IndexForColor(kGreen);
1140 uint8 greenShadowIndex = screen.IndexForColor(kGreenShadow);
1141 rgb_color shadow = tint_color(kBackground, B_DARKEN_3_TINT);
1142 rgb_color midShadow = tint_color(kBackground, B_DARKEN_4_TINT);
1143 uint8 replaceIndex = screen.IndexForColor(shadow);
1144 uint8 replaceShadowIndex = screen.IndexForColor(midShadow);
1145 for (int32 i = 0; i < length; i++)
1147 if (bits[i] == greenIndex)
1148 bits[i] = replaceIndex;
1149 else if (bits[i] == greenShadowIndex)
1150 bits[i] = replaceShadowIndex;
1156 /*****************************************************************************
1157 * VolumeSlider::_ValueFor
1158 *****************************************************************************/
1160 VolumeSlider::_ValueFor(float xPos) const
1163 float sliderStart = (r.left + kVolumeSliderBitmapWidth);
1164 float sliderEnd = (r.right - kVolumeSliderBitmapWidth);
1165 int32 value = fMinValue + (int32)(((xPos - sliderStart) * (fMaxValue - fMinValue))
1166 / (sliderEnd - sliderStart - 1.0));
1167 if (value < fMinValue)
1169 if (value > fMaxValue)
1174 /*****************************************************************************
1175 * PositionInfoView::PositionInfoView
1176 *****************************************************************************/
1177 PositionInfoView::PositionInfoView( BRect frame, const char* name,
1178 intf_thread_t * p_interface )
1179 : BView( frame, name, B_FOLLOW_NONE,
1180 B_WILL_DRAW | B_PULSE_NEEDED | B_FULL_UPDATE_ON_RESIZE ),
1181 fMode( MODE_SMALL ),
1182 fCurrentFileIndex( -1 ),
1183 fCurrentFileSize( -1 ),
1184 fCurrentTitleIndex( -1 ),
1185 fCurrentTitleSize( -1 ),
1186 fCurrentChapterIndex( -1 ),
1187 fCurrentChapterSize( -1 ),
1189 fTimeString( "-:--:--" ),
1190 fLastPulseUpdate( system_time() ),
1191 fStackedWidthCache( 0.0 ),
1192 fStackedHeightCache( 0.0 )
1194 p_intf = p_interface;
1196 SetViewColor( B_TRANSPARENT_32_BIT );
1197 SetLowColor( kBlack );
1198 SetHighColor( 0, 255, 0, 255 );
1199 SetFontSize( 11.0 );
1202 /*****************************************************************************
1203 * PositionInfoView::~PositionInfoView
1204 *****************************************************************************/
1205 PositionInfoView::~PositionInfoView()
1209 /*****************************************************************************
1210 * PositionInfoView::Draw
1211 *****************************************************************************/
1213 PositionInfoView::Draw( BRect updateRect )
1215 rgb_color background = ui_color( B_PANEL_BACKGROUND_COLOR );
1216 rgb_color shadow = tint_color( background, B_DARKEN_1_TINT );
1217 rgb_color darkShadow = tint_color( background, B_DARKEN_4_TINT );
1218 rgb_color light = tint_color( background, B_LIGHTEN_MAX_TINT );
1219 rgb_color softLight = tint_color( background, B_LIGHTEN_1_TINT );
1221 BRect r( Bounds() );
1222 BeginLineArray( 8 );
1223 AddLine( BPoint( r.left, r.bottom ),
1224 BPoint( r.left, r.top ), shadow );
1225 AddLine( BPoint( r.left + 1.0, r.top ),
1226 BPoint( r.right, r.top ), shadow );
1227 AddLine( BPoint( r.right, r.top + 1.0 ),
1228 BPoint( r.right, r.bottom ), softLight );
1229 AddLine( BPoint( r.right - 1.0, r.bottom ),
1230 BPoint( r.left + 1.0, r.bottom ), softLight );
1231 r.InsetBy( 1.0, 1.0 );
1232 AddLine( BPoint( r.left, r.bottom ),
1233 BPoint( r.left, r.top ), darkShadow );
1234 AddLine( BPoint( r.left + 1.0, r.top ),
1235 BPoint( r.right, r.top ), darkShadow );
1236 AddLine( BPoint( r.right, r.top + 1.0 ),
1237 BPoint( r.right, r.bottom ), light );
1238 AddLine( BPoint( r.right - 1.0, r.bottom ),
1239 BPoint( r.left + 1.0, r.bottom ), light );
1242 r.InsetBy( 1.0, 1.0 );
1243 FillRect( r, B_SOLID_LOW );
1246 GetFontHeight( &fh );
1251 float width = StringWidth( fTimeString.String() );
1252 DrawString( fTimeString.String(),
1253 BPoint( r.left + r.Width() / 2.0 - width / 2.0,
1254 r.top + r.Height() / 2.0 + fh.ascent / 2.0 - 1.0 ) );
1261 BFont smallFont = font;
1262 BFont bigFont = font;
1263 BFont tinyFont = font;
1264 smallFont.SetSize( r.Height() / 5.0 );
1265 bigFont.SetSize( r.Height() / 3.0 );
1266 tinyFont.SetSize( r.Height() / 7.0 );
1267 float timeHeight = r.Height() / 2.5;
1268 float height = ( r.Height() - timeHeight ) / 3.0;
1269 SetFont( &tinyFont );
1270 SetHighColor( 0, 180, 0, 255 );
1271 DrawString( _("File"), BPoint( r.left + 3.0, r.top + height ) );
1272 DrawString( _("Title"), BPoint( r.left + 3.0, r.top + 2.0 * height ) );
1273 DrawString( _("Chapter"), BPoint( r.left + 3.0, r.top + 3.0 * height ) );
1274 SetFont( &smallFont );
1276 SetHighColor( 0, 255, 0, 255 );
1278 _MakeString( helper, fCurrentFileIndex, fCurrentFileSize );
1279 float width = StringWidth( helper.String() );
1280 DrawString( helper.String(), BPoint( r.right - 3.0 - width, r.top + height ) );
1282 _MakeString( helper, fCurrentTitleIndex, fCurrentTitleSize );
1283 width = StringWidth( helper.String() );
1284 DrawString( helper.String(), BPoint( r.right - 3.0 - width, r.top + 2.0 * height ) );
1286 _MakeString( helper, fCurrentChapterIndex, fCurrentChapterSize );
1287 width = StringWidth( helper.String() );
1288 DrawString( helper.String(), BPoint( r.right - 3.0 - width, r.top + 3.0 * height ) );
1290 SetFont( &bigFont );
1291 width = StringWidth( fTimeString.String() );
1292 DrawString( fTimeString.String(),
1293 BPoint( r.left + r.Width() / 2.0 - width / 2.0,
1300 /*****************************************************************************
1301 * PositionInfoView::ResizeToPreferred
1302 *****************************************************************************/
1304 PositionInfoView::ResizeToPreferred()
1306 float width, height;
1307 GetPreferredSize( &width, &height );
1308 ResizeTo( width, height );
1311 /*****************************************************************************
1312 * PositionInfoView::GetPreferredSize
1313 *****************************************************************************/
1315 PositionInfoView::GetPreferredSize( float* width, float* height )
1317 if ( width && height )
1319 *width = 5.0 + ceilf( StringWidth( "0:00:00" ) ) + 5.0;
1321 GetFontHeight( &fh );
1322 *height = 3.0 + ceilf( fh.ascent ) + 3.0;
1323 fStackedWidthCache = *width * 1.2;
1324 fStackedHeightCache = *height * 2.7;
1328 /*****************************************************************************
1329 * PositionInfoView::Pulse
1330 *****************************************************************************/
1332 PositionInfoView::Pulse()
1334 // allow for Pulse frequency to be higher, MediaControlView needs it
1335 bigtime_t now = system_time();
1336 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;
1350 /*****************************************************************************
1351 * PositionInfoView::GetBigPreferredSize
1352 *****************************************************************************/
1354 PositionInfoView::GetBigPreferredSize( float* width, float* height )
1356 if ( width && height )
1358 *width = fStackedWidthCache;
1359 *height = fStackedHeightCache;
1363 /*****************************************************************************
1364 * PositionInfoView::SetMode
1365 *****************************************************************************/
1367 PositionInfoView::SetMode( uint32 mode )
1369 if ( fMode != mode )
1372 _InvalidateContents();
1376 /*****************************************************************************
1377 * PositionInfoView::SetFile
1378 *****************************************************************************/
1380 PositionInfoView::SetFile( int32 index, int32 size )
1382 if ( fCurrentFileIndex != index || fCurrentFileSize != size )
1384 fCurrentFileIndex = index;
1385 fCurrentFileSize = size;
1386 _InvalidateContents();
1390 /*****************************************************************************
1391 * PositionInfoView::SetTitle
1392 *****************************************************************************/
1394 PositionInfoView::SetTitle( int32 index, int32 size )
1396 if ( fCurrentTitleIndex != index || fCurrentFileSize != size )
1398 fCurrentTitleIndex = index;
1399 fCurrentTitleSize = size;
1400 _InvalidateContents();
1404 /*****************************************************************************
1405 * PositionInfoView::SetChapter
1406 *****************************************************************************/
1408 PositionInfoView::SetChapter( int32 index, int32 size )
1410 if ( fCurrentChapterIndex != index || fCurrentFileSize != size )
1412 fCurrentChapterIndex = index;
1413 fCurrentChapterSize = size;
1414 _InvalidateContents();
1418 /*****************************************************************************
1419 * PositionInfoView::SetTime
1420 *****************************************************************************/
1422 PositionInfoView::SetTime( int32 seconds )
1424 if ( fSeconds != seconds )
1428 int32 minutes = seconds / 60;
1429 int32 hours = minutes / 60;
1430 seconds -= minutes * 60 - hours * 60 * 60;
1431 minutes -= hours * 60;
1432 fTimeString.SetTo( "" );
1433 fTimeString << hours << ":" << minutes << ":" << seconds;
1436 fTimeString.SetTo( "-:--:--" );
1439 _InvalidateContents();
1443 /*****************************************************************************
1444 * PositionInfoView::SetTime
1445 *****************************************************************************/
1447 PositionInfoView::SetTime( const char* string )
1449 fTimeString.SetTo( string );
1450 _InvalidateContents();
1453 /*****************************************************************************
1454 * PositionInfoView::_InvalidateContents
1455 *****************************************************************************/
1457 PositionInfoView::_InvalidateContents( uint32 which )
1459 BRect r( Bounds() );
1460 r.InsetBy( 2.0, 2.0 );
1464 /*****************************************************************************
1465 * PositionInfoView::_InvalidateContents
1466 *****************************************************************************/
1468 PositionInfoView::_MakeString( BString& into, int32 index, int32 maxIndex ) const
1471 if ( index >= 0 && maxIndex >= 0 )
1476 if ( maxIndex >= 0 )