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>
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()) {
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;
321 fPlayPause->SetPlaying();
324 fPlayPause->SetPaused();
328 fPlayPause->SetStopped();
331 if (rate != fCurrentRate)
334 if ( rate < DEFAULT_RATE )
343 MediaControlView::SetEnabled(bool enabled)
345 if( ( enabled && fIsEnabled ) ||
346 ( !enabled && !fIsEnabled ) )
348 /* do not redraw if it is not necessary */
354 fSkipBack->SetEnabled( enabled );
355 fPlayPause->SetEnabled( enabled );
356 fSkipForward->SetEnabled( enabled );
357 fStop->SetEnabled( enabled );
358 fMute->SetEnabled( enabled );
359 fVolumeSlider->SetEnabled( enabled );
360 fSeekSlider->SetEnabled( enabled );
361 fRewind->SetEnabled( enabled );
362 fForward->SetEnabled( enabled );
364 fIsEnabled = enabled;
370 MediaControlView::SetAudioEnabled(bool enabled)
372 fMute->SetEnabled(enabled);
373 fVolumeSlider->SetEnabled(enabled);
378 MediaControlView::GetSeekTo() const
380 return fSeekSlider->Value();
385 MediaControlView::GetVolume() const
387 return fVolumeSlider->Value();
392 MediaControlView::SetSkippable(bool backward, bool forward)
394 fSkipBack->SetEnabled(backward);
395 fSkipForward->SetEnabled(forward);
400 MediaControlView::SetMuted(bool mute)
402 fVolumeSlider->SetMuted(mute);
407 MediaControlView::_LayoutControls(BRect frame) const
411 // calculate absolutly minimal width
412 float minWidth = fSkipBack->Bounds().Width();
413 // minWidth += fRewind->Bounds().Width();
414 minWidth += fStop->Bounds().Width();
415 minWidth += fPlayPause->Bounds().Width();
416 // minWidth += fForward->Bounds().Width();
417 minWidth += fSkipForward->Bounds().Width();
418 minWidth += fMute->Bounds().Width();
419 minWidth += VOLUME_MIN_WIDTH;
421 // layout time slider and info view
423 fPositionInfo->GetBigPreferredSize( &width, &height );
424 float ratio = width / height;
425 width = r.Height() * ratio;
426 if (frame.Width() - minWidth - MIN_SPACE >= width
427 && frame.Height() >= height)
429 r.right = r.left + width;
430 fPositionInfo->SetMode(PositionInfoView::MODE_BIG);
431 _LayoutControl(fPositionInfo, r, true, true);
432 frame.left = r.right + MIN_SPACE;
434 r.right = frame.right;
435 // r.bottom = r.top + r.Height() / 2.0 - MIN_SPACE / 2.0;
436 r.bottom = r.top + fSeekSlider->Bounds().Height();
437 _LayoutControl(fSeekSlider, r, true);
441 fPositionInfo->GetPreferredSize( &width, &height );
442 fPositionInfo->SetMode(PositionInfoView::MODE_SMALL);
443 fPositionInfo->ResizeTo(width, height);
444 r.bottom = r.top + r.Height() / 2.0 - MIN_SPACE / 2.0;
445 r.right = r.left + fPositionInfo->Bounds().Width();
446 _LayoutControl(fPositionInfo, r, true );
447 r.left = r.right + MIN_SPACE;
448 r.right = frame.right;
449 _LayoutControl(fSeekSlider, r, true);
451 float currentWidth = frame.Width();
452 float space = (currentWidth - minWidth) / 6.0;//8.0;
454 space = MIN_SPACE + (space - MIN_SPACE) / VOLUME_SLIDER_LAYOUT_WEIGHT;
455 // layout controls with "space" inbetween
457 r.top = r.bottom + MIN_SPACE + 1.0;
458 r.bottom = frame.bottom;
460 r.right = r.left + fSkipBack->Bounds().Width();
461 _LayoutControl(fSkipBack, r);
463 // r.left = r.right + space;
464 // r.right = r.left + fRewind->Bounds().Width();
465 // _LayoutControl(fRewind, r);
467 r.left = r.right + space;
468 r.right = r.left + fStop->Bounds().Width();
469 _LayoutControl(fStop, r);
471 r.left = r.right + space;
472 r.right = r.left + fPlayPause->Bounds().Width();
473 _LayoutControl(fPlayPause, r);
475 // r.left = r.right + space;
476 // r.right = r.left + fForward->Bounds().Width();
477 // _LayoutControl(fForward, r);
479 r.left = r.right + space;
480 r.right = r.left + fSkipForward->Bounds().Width();
481 _LayoutControl(fSkipForward, r);
483 r.left = r.right + space + space;
484 r.right = r.left + fMute->Bounds().Width();
485 _LayoutControl(fMute, r);
487 r.left = r.right + SPEAKER_SLIDER_DIST; // keep speaker icon and volume slider attached
488 r.right = frame.right;
489 _LayoutControl(fVolumeSlider, r, true);
494 MediaControlView::_MinFrame() const
496 // add up width of controls along bottom (seek slider will likely adopt)
497 float minWidth = 2 * BORDER_INSET;
498 minWidth += fSkipBack->Bounds().Width() + MIN_SPACE;
499 // minWidth += fRewind->Bounds().Width() + MIN_SPACE;
500 minWidth += fStop->Bounds().Width() + MIN_SPACE;
501 minWidth += fPlayPause->Bounds().Width() + MIN_SPACE;
502 // minWidth += fForward->Bounds().Width() + MIN_SPACE;
503 minWidth += fSkipForward->Bounds().Width() + MIN_SPACE + MIN_SPACE;
504 minWidth += fMute->Bounds().Width() + SPEAKER_SLIDER_DIST;
505 minWidth += VOLUME_MIN_WIDTH;
507 // add up height of seek slider and heighest control on bottom
508 float minHeight = 2 * BORDER_INSET;
509 minHeight += fSeekSlider->Bounds().Height() + MIN_SPACE + MIN_SPACE / 2.0;
510 minHeight += fBottomControlHeight;
511 return BRect(0.0, 0.0, minWidth - 1.0, minHeight - 1.0);
516 MediaControlView::_LayoutControl(BView* view, BRect frame,
517 bool resizeWidth, bool resizeHeight) const
521 frame.top = (frame.top + frame.bottom) / 2.0 - view->Bounds().Height() / 2.0;
523 //center horizontally
524 frame.left = (frame.left + frame.right) / 2.0 - view->Bounds().Width() / 2.0;
525 view->MoveTo(frame.LeftTop());
526 float width = resizeWidth ? frame.Width() : view->Bounds().Width();
527 float height = resizeHeight ? frame.Height() : view->Bounds().Height();
528 if (resizeWidth || resizeHeight)
529 view->ResizeTo(width, height);
534 /*****************************************************************************
536 *****************************************************************************/
537 SeekSlider::SeekSlider(BRect frame, const char* name, MediaControlView *owner,
538 int32 minValue, int32 maxValue)
539 : BControl(frame, name, NULL, NULL, B_FOLLOW_NONE,
540 B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE),
546 BFont font(be_plain_font);
551 SeekSlider::~SeekSlider()
556 /*****************************************************************************
557 * VolumeSlider::AttachedToWindow
558 *****************************************************************************/
560 SeekSlider::AttachedToWindow()
562 BControl::AttachedToWindow();
563 SetViewColor(B_TRANSPARENT_32_BIT);
566 /*****************************************************************************
568 *****************************************************************************/
570 SeekSlider::Draw(BRect updateRect)
573 float knobWidth2 = SEEK_SLIDER_KNOB_WIDTH / 2.0;
574 float sliderStart = (r.left + knobWidth2);
575 float sliderEnd = (r.right - knobWidth2);
576 float knobPos = sliderStart
577 + floorf((sliderEnd - sliderStart - 1.0) * (Value() - fMinValue)
578 / (fMaxValue - fMinValue) + 0.5);
579 // draw both sides (the original from Be doesn't seem
580 // to make a difference for enabled/disabled state)
581 // DrawBitmapAsync(fLeftSideBits, r.LeftTop());
582 // DrawBitmapAsync(fRightSideBits, BPoint(sliderEnd + 1.0, r.top));
583 // colors for the slider area between the two bitmaps
584 rgb_color background = kBackground;//ui_color(B_PANEL_BACKGROUND_COLOR);
585 rgb_color shadow = tint_color(background, B_DARKEN_2_TINT);
586 rgb_color softShadow = tint_color(background, B_DARKEN_1_TINT);
587 rgb_color darkShadow = tint_color(background, B_DARKEN_4_TINT);
588 rgb_color midShadow = tint_color(background, B_DARKEN_3_TINT);
589 rgb_color light = tint_color(background, B_LIGHTEN_MAX_TINT);
590 rgb_color softLight = tint_color(background, B_LIGHTEN_1_TINT);
591 rgb_color green = kSeekGreen;
592 rgb_color greenShadow = kSeekGreenShadow;
593 rgb_color black = kBlack;
594 rgb_color dotGrey = midShadow;
595 rgb_color dotGreen = greenShadow;
597 _StrokeFrame(r, softShadow, softShadow, softLight, softLight);
599 _StrokeFrame(r, black, black, light, light);
604 _StrokeFrame(r, greenShadow, greenShadow, green, green);
607 _StrokeFrame(r, greenShadow, greenShadow, green, green);
613 int32 dotCount = (int32)(r.Width() / 6.0);
615 dotPos.y = r.top + 2.0;
616 SetHighColor(dotGreen);
617 for (int32 i = 0; i < dotCount; i++)
619 dotPos.x = sliderStart + i * 6.0 + 5.0;
620 StrokeLine(dotPos, BPoint(dotPos.x, dotPos.y + 6.0));
625 r.left = knobPos - knobWidth2;
626 r.right = knobPos + knobWidth2;
628 float handleBottomSize = 2.0;
629 float handleArrowSize = 6.0;
632 AddLine(BPoint(r.left, r.top + handleBottomSize),
633 BPoint(r.left, r.top), black);
634 AddLine(BPoint(r.left + 1.0, r.top),
635 BPoint(r.right, r.top), black);
636 AddLine(BPoint(r.right, r.top + 1.0),
637 BPoint(r.right, r.top + handleBottomSize), black);
638 AddLine(BPoint(r.right - 1.0, r.top + handleBottomSize + 1.0),
639 BPoint(knobPos, r.top + handleArrowSize), black);
640 AddLine(BPoint(knobPos - 1.0, r.top + handleArrowSize - 1.0),
641 BPoint(r.left + 1.0, r.top + handleBottomSize + 1.0), black);
643 AddLine(BPoint(r.left, r.bottom),
644 BPoint(r.left, r.bottom - handleBottomSize), black);
645 AddLine(BPoint(r.left + 1.0, r.bottom - handleBottomSize - 1.0),
646 BPoint(knobPos, r.bottom - handleArrowSize), black);
647 AddLine(BPoint(knobPos + 1.0, r.bottom - handleArrowSize + 1.0),
648 BPoint(r.right, r.bottom - handleBottomSize), black);
649 AddLine(BPoint(r.right, r.bottom - handleBottomSize + 1.0),
650 BPoint(r.right, r.bottom), black);
651 AddLine(BPoint(r.right - 1.0, r.bottom),
652 BPoint(r.left + 1.0, r.bottom), black);
654 // inner red light and shadow lines
657 handleArrowSize -= 2.0;
660 AddLine(BPoint(r.left, r.top + handleBottomSize),
661 BPoint(r.left, r.top), kSeekRedLight);
662 AddLine(BPoint(r.left + 1.0, r.top),
663 BPoint(r.right, r.top), kSeekRedLight);
664 AddLine(BPoint(r.right, r.top + 1.0),
665 BPoint(r.right, r.top + handleBottomSize), kSeekRedShadow);
666 AddLine(BPoint(r.right - 1.0, r.top + handleBottomSize + 1.0),
667 BPoint(knobPos, r.top + handleArrowSize), kSeekRedShadow);
668 AddLine(BPoint(knobPos - 1.0, r.top + handleArrowSize - 1.0),
669 BPoint(r.left + 1.0, r.top + handleBottomSize + 1.0), kSeekRedLight);
671 AddLine(BPoint(r.left, r.bottom),
672 BPoint(r.left, r.bottom - handleBottomSize), kSeekRedLight);
673 AddLine(BPoint(r.left + 1.0, r.bottom - handleBottomSize - 1.0),
674 BPoint(knobPos, r.bottom - handleArrowSize), kSeekRedLight);
675 AddLine(BPoint(knobPos + 1.0, r.bottom - handleArrowSize + 1.0),
676 BPoint(r.right, r.bottom - handleBottomSize), kSeekRedShadow);
677 AddLine(BPoint(r.right, r.bottom - handleBottomSize + 1.0),
678 BPoint(r.right, r.bottom), kSeekRedShadow);
679 AddLine(BPoint(r.right - 1.0, r.bottom),
680 BPoint(r.left + 1.0, r.bottom), kSeekRedShadow);
682 // fill rest of handles with red
683 SetHighColor(kSeekRed);
685 handleArrowSize -= 2.0;
687 // upper handle arrow
690 arrow[1].x = r.right;
692 arrow[2].x = knobPos;
693 arrow[2].y = r.top + handleArrowSize;
694 FillPolygon(arrow, 3);
695 // lower handle arrow
697 arrow[0].y = r.bottom;
698 arrow[1].x = r.right;
699 arrow[1].y = r.bottom;
700 arrow[2].x = knobPos;
701 arrow[2].y = r.bottom - handleArrowSize;
702 FillPolygon(arrow, 3);
707 _StrokeFrame(r, darkShadow, darkShadow, darkShadow, darkShadow);
709 _StrokeFrame(r, darkShadow, darkShadow, darkShadow, darkShadow);
711 SetHighColor(darkShadow);
714 float width = floorf(StringWidth(DISABLED_SEEK_MESSAGE));
715 float textPos = r.left + r.Width() / 2.0 - width / 2.0;
716 pattern stripes = {{ 0xc7, 0x8f, 0x1f, 0x3e, 0x7c, 0xf8, 0xf1, 0xe3 }};
717 BRect stripesRect(r);
718 stripesRect.right = textPos - 5.0;
719 FillRect(stripesRect, stripes);
720 stripesRect.left = textPos + width + 3.0;
721 stripesRect.right = r.right;
722 FillRect(stripesRect, stripes);
724 r.left = textPos - 4.0;
725 r.right = textPos + width + 2.0;
727 SetHighColor(shadow);
728 SetLowColor(darkShadow);
731 DrawString(DISABLED_SEEK_MESSAGE, BPoint(textPos, r.top + ceilf(fh.ascent) - 1.0));
735 /*****************************************************************************
736 * SeekSlider::MouseDown
737 *****************************************************************************/
739 SeekSlider::MouseDown(BPoint where)
741 if (IsEnabled() && Bounds().Contains(where))
743 SetValue(_ValueFor(where.x));
745 SetMouseEventMask(B_POINTER_EVENTS, B_LOCK_WINDOW_FOCUS);
750 /*****************************************************************************
751 * SeekSlider::MouseMoved
752 *****************************************************************************/
754 SeekSlider::MouseMoved(BPoint where, uint32 code, const BMessage* dragMessage)
758 SetValue(_ValueFor(where.x));
763 /*****************************************************************************
764 * SeekSlider::MouseUp
765 *****************************************************************************/
767 SeekSlider::MouseUp(BPoint where)
776 /*****************************************************************************
777 * SeekSlider::ResizeToPreferred
778 *****************************************************************************/
780 SeekSlider::ResizeToPreferred()
782 float width = 15.0 + StringWidth(DISABLED_SEEK_MESSAGE) + 15.0;
783 ResizeTo(width, 17.0);
786 /*****************************************************************************
787 * SeekSlider::SetPosition
788 *****************************************************************************/
790 SeekSlider::SetPosition(float position)
794 SetValue(fMinValue + (int32)floorf((fMaxValue - fMinValue) * position + 0.5));
799 /*****************************************************************************
800 * SeekSlider::_ValueFor
801 *****************************************************************************/
803 SeekSlider::_ValueFor(float xPos) const
806 float knobWidth2 = SEEK_SLIDER_KNOB_WIDTH / 2.0;
807 float sliderStart = (r.left + knobWidth2);
808 float sliderEnd = (r.right - knobWidth2);
809 int32 value = fMinValue + (int32)(((xPos - sliderStart) * (fMaxValue - fMinValue))
810 / (sliderEnd - sliderStart - 1.0));
811 if (value < fMinValue)
813 if (value > fMaxValue)
818 /*****************************************************************************
819 * SeekSlider::_StrokeFrame
820 *****************************************************************************/
822 SeekSlider::_StrokeFrame(BRect r, rgb_color left, rgb_color top,
823 rgb_color right, rgb_color bottom)
826 AddLine(BPoint(r.left, r.bottom), BPoint(r.left, r.top), left);
827 AddLine(BPoint(r.left + 1.0, r.top), BPoint(r.right, r.top), top);
828 AddLine(BPoint(r.right, r.top + 1.0), BPoint(r.right, r.bottom), right);
829 AddLine(BPoint(r.right - 1.0, r.bottom), BPoint(r.left + 1.0, r.bottom), bottom);
833 /*****************************************************************************
834 * SeekSlider::_BeginSeek
835 *****************************************************************************/
837 SeekSlider::_BeginSeek()
839 fOwner->fScrubSem = create_sem(0, "Vlc::fScrubSem");
840 if (fOwner->fScrubSem >= B_OK)
841 release_sem(fOwner->fScrubSem);
844 /*****************************************************************************
846 *****************************************************************************/
850 if (fOwner->fScrubSem >= B_OK)
851 delete_sem(fOwner->fScrubSem);
852 fOwner->fScrubSem = create_sem(0, "Vlc::fScrubSem");
853 if (fOwner->fScrubSem >= B_OK)
854 release_sem(fOwner->fScrubSem);
857 /*****************************************************************************
858 * SeekSlider::_EndSeek
859 *****************************************************************************/
861 SeekSlider::_EndSeek()
863 if (fOwner->fScrubSem >= B_OK)
864 delete_sem(fOwner->fScrubSem);
865 fOwner->fScrubSem = B_ERROR;
869 /*****************************************************************************
871 *****************************************************************************/
872 VolumeSlider::VolumeSlider(BRect frame, const char* name, int32 minValue, int32 maxValue,
873 BMessage* message, BHandler* target)
874 : BControl(frame, name, NULL, message, B_FOLLOW_NONE,
875 B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE),
877 fRightSideBits(NULL),
887 BRect r(BPoint(0.0, 0.0), kVolumeSliderBitmapSize);
888 fLeftSideBits = new BBitmap(r, B_CMAP8);
889 fRightSideBits = new BBitmap(r, B_CMAP8);
890 r.Set(0.0, 0.0, kVolumeSliderKnobBitmapSize.x, kVolumeSliderKnobBitmapSize.y);
891 fKnobBits = new BBitmap(r, B_CMAP8);
896 /*****************************************************************************
897 * VolumeSlider destructor
898 *****************************************************************************/
899 VolumeSlider::~VolumeSlider()
901 delete fLeftSideBits;
902 delete fRightSideBits;
906 /*****************************************************************************
907 * VolumeSlider::AttachedToWindow
908 *****************************************************************************/
910 VolumeSlider::AttachedToWindow()
912 BControl::AttachedToWindow();
913 SetViewColor(B_TRANSPARENT_32_BIT);
916 /*****************************************************************************
917 * VolumeSlider::SetValue
918 *****************************************************************************/
920 VolumeSlider::SetValue(int32 value)
922 if (value != Value())
924 BControl::SetValue(value);
929 /*****************************************************************************
930 * VolumeSlider::SetEnabled
931 *****************************************************************************/
933 VolumeSlider::SetEnabled(bool enable)
935 if (enable != IsEnabled())
937 BControl::SetEnabled(enable);
943 /*****************************************************************************
945 *****************************************************************************/
947 VolumeSlider::Draw(BRect updateRect)
952 float sliderSideWidth = kVolumeSliderBitmapWidth;
953 float sliderStart = (r.left + sliderSideWidth);
954 float sliderEnd = (r.right - sliderSideWidth);
955 float knobPos = sliderStart
956 + (sliderEnd - sliderStart - 1.0) * (Value() - fMinValue)
957 / (fMaxValue - fMinValue);
958 // draw both sides (the original from Be doesn't seem
959 // to make a difference for enabled/disabled state)
960 DrawBitmapAsync(fLeftSideBits, r.LeftTop());
961 DrawBitmapAsync(fRightSideBits, BPoint(sliderEnd + 1.0, r.top));
962 // colors for the slider area between the two bitmaps
963 rgb_color background = kBackground;//ui_color(B_PANEL_BACKGROUND_COLOR);
964 rgb_color shadow = tint_color(background, B_DARKEN_2_TINT);
965 rgb_color softShadow = tint_color(background, B_DARKEN_1_TINT);
966 rgb_color darkShadow = tint_color(background, B_DARKEN_4_TINT);
967 rgb_color midShadow = tint_color(background, B_DARKEN_3_TINT);
968 rgb_color light = tint_color(background, B_LIGHTEN_MAX_TINT);
969 rgb_color softLight = tint_color(background, B_LIGHTEN_1_TINT);
970 rgb_color green = kGreen;
971 rgb_color greenShadow = kGreenShadow;
972 rgb_color black = kBlack;
973 rgb_color dotGrey = midShadow;
974 rgb_color dotGreen = greenShadow;
975 // make dimmed version of colors if we're disabled
978 shadow = (rgb_color){ 200, 200, 200, 255 };
979 softShadow = dimmed_color_cmap8(softShadow, background, DIM_LEVEL);
980 darkShadow = dimmed_color_cmap8(darkShadow, background, DIM_LEVEL);
982 light = dimmed_color_cmap8(light, background, DIM_LEVEL);
983 softLight = dimmed_color_cmap8(softLight, background, DIM_LEVEL);
984 green = dimmed_color_cmap8(green, background, DIM_LEVEL);
985 greenShadow = dimmed_color_cmap8(greenShadow, background, DIM_LEVEL);
986 black = dimmed_color_cmap8(black, background, DIM_LEVEL);
991 green = tint_color(kBackground, B_DARKEN_3_TINT);
992 greenShadow = tint_color(kBackground, B_DARKEN_4_TINT);
993 dotGreen = greenShadow;
995 // draw slider edges between bitmaps
997 AddLine(BPoint(sliderStart, r.top),
998 BPoint(sliderEnd, r.top), softShadow);
999 AddLine(BPoint(sliderStart, r.bottom),
1000 BPoint(sliderEnd, r.bottom), softLight);
1001 r.InsetBy(0.0, 1.0);
1002 AddLine(BPoint(sliderStart, r.top),
1003 BPoint(sliderEnd, r.top), black);
1004 AddLine(BPoint(sliderStart, r.bottom),
1005 BPoint(sliderEnd, r.bottom), light);
1007 AddLine(BPoint(sliderStart, r.top),
1008 BPoint(knobPos, r.top), greenShadow);
1009 AddLine(BPoint(knobPos, r.top),
1010 BPoint(sliderEnd, r.top), midShadow);
1012 AddLine(BPoint(sliderStart, r.top),
1013 BPoint(knobPos, r.top), greenShadow);
1015 // fill rest inside of slider
1016 r.InsetBy(0.0, 1.0);
1017 r.left = sliderStart;
1019 SetHighColor(green);
1020 FillRect(r, B_SOLID_HIGH);
1021 r.left = knobPos + 1.0;
1022 r.right = sliderEnd;
1024 SetHighColor(shadow);
1025 FillRect(r, B_SOLID_HIGH);
1026 // draw little dots inside
1027 int32 dotCount = (int32)((sliderEnd - sliderStart) / 5.0);
1029 dotPos.y = r.top + 4.0;
1030 for (int32 i = 0; i < dotCount; i++)
1032 dotPos.x = sliderStart + i * 5.0 + 4.0;
1033 SetHighColor(dotPos.x < knobPos ? dotGreen : dotGrey);
1034 StrokeLine(dotPos, BPoint(dotPos.x, dotPos.y + 1.0));
1038 SetDrawingMode(B_OP_OVER); // part of knob is transparent
1039 DrawBitmapAsync(fKnobBits, BPoint(knobPos - kVolumeSliderKnobWidth / 2, r.top));
1043 /*****************************************************************************
1044 * VolumeSlider::MouseDown
1045 *****************************************************************************/
1047 VolumeSlider::MouseDown(BPoint where)
1049 if (Bounds().Contains(where) && IsEnabled())
1052 SetValue(_ValueFor(where.x));
1053 SetMouseEventMask(B_POINTER_EVENTS, B_LOCK_WINDOW_FOCUS);
1057 /*****************************************************************************
1058 * VolumeSlider::MouseMoved
1059 *****************************************************************************/
1061 VolumeSlider::MouseMoved(BPoint where, uint32 transit, const BMessage* dragMessage)
1064 SetValue(_ValueFor(where.x));
1067 /*****************************************************************************
1068 * VolumeSlider::MouseUp
1069 *****************************************************************************/
1071 VolumeSlider::MouseUp(BPoint where)
1077 /*****************************************************************************
1078 * VolumeSlider::IsValid
1079 *****************************************************************************/
1081 VolumeSlider::IsValid() const
1083 return (fLeftSideBits && fLeftSideBits->IsValid()
1084 && fRightSideBits && fRightSideBits->IsValid()
1085 && fKnobBits && fKnobBits->IsValid());
1088 /*****************************************************************************
1089 * VolumeSlider::SetMuted
1090 *****************************************************************************/
1092 VolumeSlider::SetMuted(bool mute)
1102 /*****************************************************************************
1103 * VolumeSlider::_MakeBitmaps
1104 *****************************************************************************/
1106 VolumeSlider::_MakeBitmaps()
1110 // left side of slider
1111 memcpy(fLeftSideBits->Bits(), kVolumeSliderLeftBitmapBits,
1112 fLeftSideBits->BitsLength());
1113 // right side of slider
1114 memcpy(fRightSideBits->Bits(), kVolumeSliderRightBits,
1115 fRightSideBits->BitsLength());
1117 int32 length = fKnobBits->BitsLength();
1118 memcpy(fKnobBits->Bits(), kVolumeSliderKnobBits, length);
1119 uint8* bits = (uint8*)fKnobBits->Bits();
1120 // black was used in the knob to represent transparency
1121 // use screen to get index for the "transarent" color used in the bitmap
1122 BScreen screen(B_MAIN_SCREEN_ID);
1123 uint8 blackIndex = screen.IndexForColor(kBlack);
1124 // replace black index with transparent index
1125 for (int32 i = 0; i < length; i++)
1126 if (bits[i] == blackIndex)
1127 bits[i] = B_TRANSPARENT_MAGIC_CMAP8;
1131 // make ghosted versions of the bitmaps
1132 dim_bitmap(fLeftSideBits, kBackground, DIM_LEVEL);
1133 dim_bitmap(fRightSideBits, kBackground, DIM_LEVEL);
1134 dim_bitmap(fKnobBits, kBackground, DIM_LEVEL);
1138 // replace green color (and shadow) in left slider side
1139 bits = (uint8*)fLeftSideBits->Bits();
1140 length = fLeftSideBits->BitsLength();
1141 uint8 greenIndex = screen.IndexForColor(kGreen);
1142 uint8 greenShadowIndex = screen.IndexForColor(kGreenShadow);
1143 rgb_color shadow = tint_color(kBackground, B_DARKEN_3_TINT);
1144 rgb_color midShadow = tint_color(kBackground, B_DARKEN_4_TINT);
1145 uint8 replaceIndex = screen.IndexForColor(shadow);
1146 uint8 replaceShadowIndex = screen.IndexForColor(midShadow);
1147 for (int32 i = 0; i < length; i++)
1149 if (bits[i] == greenIndex)
1150 bits[i] = replaceIndex;
1151 else if (bits[i] == greenShadowIndex)
1152 bits[i] = replaceShadowIndex;
1158 /*****************************************************************************
1159 * VolumeSlider::_ValueFor
1160 *****************************************************************************/
1162 VolumeSlider::_ValueFor(float xPos) const
1165 float sliderStart = (r.left + kVolumeSliderBitmapWidth);
1166 float sliderEnd = (r.right - kVolumeSliderBitmapWidth);
1167 int32 value = fMinValue + (int32)(((xPos - sliderStart) * (fMaxValue - fMinValue))
1168 / (sliderEnd - sliderStart - 1.0));
1169 if (value < fMinValue)
1171 if (value > fMaxValue)
1176 /*****************************************************************************
1177 * PositionInfoView::PositionInfoView
1178 *****************************************************************************/
1179 PositionInfoView::PositionInfoView( BRect frame, const char* name,
1180 intf_thread_t * p_interface )
1181 : BView( frame, name, B_FOLLOW_NONE,
1182 B_WILL_DRAW | B_PULSE_NEEDED | B_FULL_UPDATE_ON_RESIZE ),
1183 fMode( MODE_SMALL ),
1184 fCurrentFileIndex( -1 ),
1185 fCurrentFileSize( -1 ),
1186 fCurrentTitleIndex( -1 ),
1187 fCurrentTitleSize( -1 ),
1188 fCurrentChapterIndex( -1 ),
1189 fCurrentChapterSize( -1 ),
1191 fTimeString( "-:--:--" ),
1192 fLastPulseUpdate( system_time() ),
1193 fStackedWidthCache( 0.0 ),
1194 fStackedHeightCache( 0.0 )
1196 p_intf = p_interface;
1198 SetViewColor( B_TRANSPARENT_32_BIT );
1199 SetLowColor( kBlack );
1200 SetHighColor( 0, 255, 0, 255 );
1201 SetFontSize( 11.0 );
1204 /*****************************************************************************
1205 * PositionInfoView::~PositionInfoView
1206 *****************************************************************************/
1207 PositionInfoView::~PositionInfoView()
1211 /*****************************************************************************
1212 * PositionInfoView::Draw
1213 *****************************************************************************/
1215 PositionInfoView::Draw( BRect updateRect )
1217 rgb_color background = ui_color( B_PANEL_BACKGROUND_COLOR );
1218 rgb_color shadow = tint_color( background, B_DARKEN_1_TINT );
1219 rgb_color darkShadow = tint_color( background, B_DARKEN_4_TINT );
1220 rgb_color light = tint_color( background, B_LIGHTEN_MAX_TINT );
1221 rgb_color softLight = tint_color( background, B_LIGHTEN_1_TINT );
1223 BRect r( Bounds() );
1224 BeginLineArray( 8 );
1225 AddLine( BPoint( r.left, r.bottom ),
1226 BPoint( r.left, r.top ), shadow );
1227 AddLine( BPoint( r.left + 1.0, r.top ),
1228 BPoint( r.right, r.top ), shadow );
1229 AddLine( BPoint( r.right, r.top + 1.0 ),
1230 BPoint( r.right, r.bottom ), softLight );
1231 AddLine( BPoint( r.right - 1.0, r.bottom ),
1232 BPoint( r.left + 1.0, r.bottom ), softLight );
1233 r.InsetBy( 1.0, 1.0 );
1234 AddLine( BPoint( r.left, r.bottom ),
1235 BPoint( r.left, r.top ), darkShadow );
1236 AddLine( BPoint( r.left + 1.0, r.top ),
1237 BPoint( r.right, r.top ), darkShadow );
1238 AddLine( BPoint( r.right, r.top + 1.0 ),
1239 BPoint( r.right, r.bottom ), light );
1240 AddLine( BPoint( r.right - 1.0, r.bottom ),
1241 BPoint( r.left + 1.0, r.bottom ), light );
1244 r.InsetBy( 1.0, 1.0 );
1245 FillRect( r, B_SOLID_LOW );
1248 GetFontHeight( &fh );
1253 float width = StringWidth( fTimeString.String() );
1254 DrawString( fTimeString.String(),
1255 BPoint( r.left + r.Width() / 2.0 - width / 2.0,
1256 r.top + r.Height() / 2.0 + fh.ascent / 2.0 - 1.0 ) );
1263 BFont smallFont = font;
1264 BFont bigFont = font;
1265 BFont tinyFont = font;
1266 smallFont.SetSize( r.Height() / 5.0 );
1267 bigFont.SetSize( r.Height() / 3.0 );
1268 tinyFont.SetSize( r.Height() / 7.0 );
1269 float timeHeight = r.Height() / 2.5;
1270 float height = ( r.Height() - timeHeight ) / 3.0;
1271 SetFont( &tinyFont );
1272 SetHighColor( 0, 180, 0, 255 );
1273 DrawString( _("File"), BPoint( r.left + 3.0, r.top + height ) );
1274 DrawString( _("Title"), BPoint( r.left + 3.0, r.top + 2.0 * height ) );
1275 DrawString( _("Chapter"), BPoint( r.left + 3.0, r.top + 3.0 * height ) );
1276 SetFont( &smallFont );
1278 SetHighColor( 0, 255, 0, 255 );
1280 _MakeString( helper, fCurrentFileIndex, fCurrentFileSize );
1281 float width = StringWidth( helper.String() );
1282 DrawString( helper.String(), BPoint( r.right - 3.0 - width, r.top + height ) );
1284 _MakeString( helper, fCurrentTitleIndex, fCurrentTitleSize );
1285 width = StringWidth( helper.String() );
1286 DrawString( helper.String(), BPoint( r.right - 3.0 - width, r.top + 2.0 * height ) );
1288 _MakeString( helper, fCurrentChapterIndex, fCurrentChapterSize );
1289 width = StringWidth( helper.String() );
1290 DrawString( helper.String(), BPoint( r.right - 3.0 - width, r.top + 3.0 * height ) );
1292 SetFont( &bigFont );
1293 width = StringWidth( fTimeString.String() );
1294 DrawString( fTimeString.String(),
1295 BPoint( r.left + r.Width() / 2.0 - width / 2.0,
1302 /*****************************************************************************
1303 * PositionInfoView::ResizeToPreferred
1304 *****************************************************************************/
1306 PositionInfoView::ResizeToPreferred()
1308 float width, height;
1309 GetPreferredSize( &width, &height );
1310 ResizeTo( width, height );
1313 /*****************************************************************************
1314 * PositionInfoView::GetPreferredSize
1315 *****************************************************************************/
1317 PositionInfoView::GetPreferredSize( float* width, float* height )
1319 if ( width && height )
1321 *width = 5.0 + ceilf( StringWidth( "0:00:00" ) ) + 5.0;
1323 GetFontHeight( &fh );
1324 *height = 3.0 + ceilf( fh.ascent ) + 3.0;
1325 fStackedWidthCache = *width * 1.2;
1326 fStackedHeightCache = *height * 2.7;
1330 /*****************************************************************************
1331 * PositionInfoView::Pulse
1332 *****************************************************************************/
1334 PositionInfoView::Pulse()
1336 // allow for Pulse frequency to be higher, MediaControlView needs it
1337 bigtime_t now = system_time();
1338 if ( now - fLastPulseUpdate > 900000 )
1341 p_intf->p_sys->p_wrapper->GetPlaylistInfo( index, size );
1342 SetFile( index + 1, size );
1343 p_intf->p_sys->p_wrapper->TitleInfo( index, size );
1344 SetTitle( index, size );
1345 p_intf->p_sys->p_wrapper->ChapterInfo( index, size );
1346 SetChapter( index, size );
1347 SetTime( p_intf->p_sys->p_wrapper->GetTimeAsString() );
1348 fLastPulseUpdate = now;
1352 /*****************************************************************************
1353 * PositionInfoView::GetBigPreferredSize
1354 *****************************************************************************/
1356 PositionInfoView::GetBigPreferredSize( float* width, float* height )
1358 if ( width && height )
1360 *width = fStackedWidthCache;
1361 *height = fStackedHeightCache;
1365 /*****************************************************************************
1366 * PositionInfoView::SetMode
1367 *****************************************************************************/
1369 PositionInfoView::SetMode( uint32 mode )
1371 if ( fMode != mode )
1374 _InvalidateContents();
1378 /*****************************************************************************
1379 * PositionInfoView::SetFile
1380 *****************************************************************************/
1382 PositionInfoView::SetFile( int32 index, int32 size )
1384 if ( fCurrentFileIndex != index || fCurrentFileSize != size )
1386 fCurrentFileIndex = index;
1387 fCurrentFileSize = size;
1388 _InvalidateContents();
1392 /*****************************************************************************
1393 * PositionInfoView::SetTitle
1394 *****************************************************************************/
1396 PositionInfoView::SetTitle( int32 index, int32 size )
1398 if ( fCurrentTitleIndex != index || fCurrentFileSize != size )
1400 fCurrentTitleIndex = index;
1401 fCurrentTitleSize = size;
1402 _InvalidateContents();
1406 /*****************************************************************************
1407 * PositionInfoView::SetChapter
1408 *****************************************************************************/
1410 PositionInfoView::SetChapter( int32 index, int32 size )
1412 if ( fCurrentChapterIndex != index || fCurrentFileSize != size )
1414 fCurrentChapterIndex = index;
1415 fCurrentChapterSize = size;
1416 _InvalidateContents();
1420 /*****************************************************************************
1421 * PositionInfoView::SetTime
1422 *****************************************************************************/
1424 PositionInfoView::SetTime( int32 seconds )
1426 if ( fSeconds != seconds )
1430 int32 minutes = seconds / 60;
1431 int32 hours = minutes / 60;
1432 seconds -= minutes * 60 - hours * 60 * 60;
1433 minutes -= hours * 60;
1434 fTimeString.SetTo( "" );
1435 fTimeString << hours << ":" << minutes << ":" << seconds;
1438 fTimeString.SetTo( "-:--:--" );
1441 _InvalidateContents();
1445 /*****************************************************************************
1446 * PositionInfoView::SetTime
1447 *****************************************************************************/
1449 PositionInfoView::SetTime( const char* string )
1451 fTimeString.SetTo( string );
1452 _InvalidateContents();
1455 /*****************************************************************************
1456 * PositionInfoView::_InvalidateContents
1457 *****************************************************************************/
1459 PositionInfoView::_InvalidateContents( uint32 which )
1461 BRect r( Bounds() );
1462 r.InsetBy( 2.0, 2.0 );
1466 /*****************************************************************************
1467 * PositionInfoView::_InvalidateContents
1468 *****************************************************************************/
1470 PositionInfoView::_MakeString( BString& into, int32 index, int32 maxIndex ) const
1473 if ( index >= 0 && maxIndex >= 0 )
1478 if ( maxIndex >= 0 )