1 /*****************************************************************************
2 * MediaControlView.cpp: beos interface
3 *****************************************************************************
4 * Copyright (C) 1999, 2000, 2001 the VideoLAN team
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., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
23 *****************************************************************************/
26 #include <InterfaceKit.h>
35 #include <vlc_common.h>
36 #include <vlc_interface.h>
39 #include <audio_output.h>
42 /* BeOS interface headers */
44 #include "DrawingTidbits.h"
45 #include "InterfaceWindow.h"
47 #include "TransportButton.h"
48 #include "ListViews.h"
49 #include "MediaControlView.h"
51 #define BORDER_INSET 6.0
53 #define SPEAKER_SLIDER_DIST 6.0
54 #define VOLUME_MIN_WIDTH 70.0
56 #define VOLUME_SLIDER_LAYOUT_WEIGHT 2.0
57 #define SEEK_SLIDER_KNOB_WIDTH 8.0
59 // slider colors are hardcoded here, because that's just
60 // what they currently are within those bitmaps
61 const rgb_color kGreen = (rgb_color){ 152, 203, 152, 255 };
62 const rgb_color kGreenShadow = (rgb_color){ 102, 152, 102, 255 };
63 const rgb_color kBackground = (rgb_color){ 216, 216, 216, 255 };
64 const rgb_color kSeekGreen = (rgb_color){ 171, 221, 161, 255 };
65 const rgb_color kSeekGreenShadow = (rgb_color){ 144, 186, 136, 255 };
66 const rgb_color kSeekRed = (rgb_color){ 255, 0, 0, 255 };
67 const rgb_color kSeekRedLight = (rgb_color){ 255, 152, 152, 255 };
68 const rgb_color kSeekRedShadow = (rgb_color){ 178, 0, 0, 255 };
70 #define DISABLED_SEEK_MESSAGE _("Drop files to play")
71 #define SEEKSLIDER_RANGE 2048
77 MSG_SKIP_BACKWARDS = 'skpb',
78 MSG_SKIP_FORWARD = 'skpf',
82 MediaControlView::MediaControlView( intf_thread_t * _p_intf, BRect frame)
83 : BBox(frame, NULL, B_FOLLOW_NONE, B_WILL_DRAW | B_FRAME_EVENTS | B_PULSE_NEEDED,
86 fCurrentRate(INPUT_RATE_DEFAULT),
88 fBottomControlHeight(0.0),
91 BRect frame(0.0, 0.0, 10.0, 10.0);
94 fSeekSlider = new SeekSlider( p_intf, frame, "seek slider", this );
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
218 Window()->SetSizeLimits(r.Width(), r.Width() * 1.8, r.Height(), r.Height() * 1.3);
219 if (!Window()->Bounds().Contains(r))
220 Window()->ResizeTo(r.Width(), r.Height());
222 FrameResized(Bounds().Width(), Bounds().Height());
224 // get pulse message every two frames
225 Window()->SetPulseRate(80000);
230 MediaControlView::FrameResized(float width, float height)
233 // make sure we don't leave dirty pixels
234 // (B_FULL_UPDATE_ON_RESIZE == annoying flicker -> this is smarter)
235 if (fOldBounds.Width() < r.Width())
236 Invalidate(BRect(fOldBounds.right, fOldBounds.top + 1.0,
237 fOldBounds.right, fOldBounds.bottom - 1.0));
239 Invalidate(BRect(r.right, r.top + 1.0,
240 r.right, r.bottom - 1.0));
241 if (fOldBounds.Height() < r.Height())
242 Invalidate(BRect(fOldBounds.left + 1.0, fOldBounds.bottom,
243 fOldBounds.right - 1.0, fOldBounds.bottom));
245 Invalidate(BRect(r.left + 1.0, r.bottom,
246 r.right - 1.0, r.bottom));
247 // remember for next time
250 r.InsetBy(BORDER_INSET, BORDER_INSET);
256 MediaControlView::GetPreferredSize(float* width, float* height)
260 BRect r(_MinFrame());
262 *height = r.Height();
268 MediaControlView::MessageReceived(BMessage* message)
270 switch (message->what)
276 case MSG_SKIP_BACKWARDS:
277 Window()->PostMessage(NAVIGATE_PREV);
279 case MSG_SKIP_FORWARD:
280 Window()->PostMessage(NAVIGATE_NEXT);
283 BBox::MessageReceived(message);
290 MediaControlView::Pulse()
292 InterfaceWindow* window = dynamic_cast<InterfaceWindow*>(Window());
293 if (window && window->IsStopped())
294 fPlayPause->SetStopped();
296 unsigned short i_volume;
297 aout_VolumeGet( p_intf, (audio_volume_t*)&i_volume );
298 fVolumeSlider->SetValue( i_volume );
303 MediaControlView::SetProgress( float position )
305 fSeekSlider->SetPosition( position );
310 MediaControlView::SetStatus(int status, int rate)
312 // we need to set the button status periodically
313 // (even if it is the same) to get a blinking button
314 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::GetVolume() const
377 return fVolumeSlider->Value();
382 MediaControlView::SetSkippable(bool backward, bool forward)
384 fSkipBack->SetEnabled(backward);
385 fSkipForward->SetEnabled(forward);
390 MediaControlView::SetMuted(bool mute)
392 fVolumeSlider->SetMuted(mute);
397 MediaControlView::_LayoutControls(BRect frame) const
401 // calculate absolutly minimal width
402 float minWidth = fSkipBack->Bounds().Width();
403 // minWidth += fRewind->Bounds().Width();
404 minWidth += fStop->Bounds().Width();
405 minWidth += fPlayPause->Bounds().Width();
406 // minWidth += fForward->Bounds().Width();
407 minWidth += fSkipForward->Bounds().Width();
408 minWidth += fMute->Bounds().Width();
409 minWidth += VOLUME_MIN_WIDTH;
411 // layout time slider and info view
413 fPositionInfo->GetBigPreferredSize( &width, &height );
414 float ratio = width / height;
415 width = r.Height() * ratio;
416 if (frame.Width() - minWidth - MIN_SPACE >= width
417 && frame.Height() >= height)
419 r.right = r.left + width;
420 fPositionInfo->SetMode(PositionInfoView::MODE_BIG);
421 _LayoutControl(fPositionInfo, r, true, true);
422 frame.left = r.right + MIN_SPACE;
424 r.right = frame.right;
425 // r.bottom = r.top + r.Height() / 2.0 - MIN_SPACE / 2.0;
426 r.bottom = r.top + fSeekSlider->Bounds().Height();
427 _LayoutControl(fSeekSlider, r, true);
431 fPositionInfo->GetPreferredSize( &width, &height );
432 fPositionInfo->SetMode(PositionInfoView::MODE_SMALL);
433 fPositionInfo->ResizeTo(width, height);
434 r.bottom = r.top + r.Height() / 2.0 - MIN_SPACE / 2.0;
435 r.right = r.left + fPositionInfo->Bounds().Width();
436 _LayoutControl(fPositionInfo, r, true );
437 r.left = r.right + MIN_SPACE;
438 r.right = frame.right;
439 _LayoutControl(fSeekSlider, r, true);
441 float currentWidth = frame.Width();
442 float space = (currentWidth - minWidth) / 6.0;//8.0;
444 space = MIN_SPACE + (space - MIN_SPACE) / VOLUME_SLIDER_LAYOUT_WEIGHT;
445 // layout controls with "space" inbetween
447 r.top = r.bottom + MIN_SPACE + 1.0;
448 r.bottom = frame.bottom;
450 r.right = r.left + fSkipBack->Bounds().Width();
451 _LayoutControl(fSkipBack, r);
453 // r.left = r.right + space;
454 // r.right = r.left + fRewind->Bounds().Width();
455 // _LayoutControl(fRewind, r);
457 r.left = r.right + space;
458 r.right = r.left + fStop->Bounds().Width();
459 _LayoutControl(fStop, r);
461 r.left = r.right + space;
462 r.right = r.left + fPlayPause->Bounds().Width();
463 _LayoutControl(fPlayPause, r);
465 // r.left = r.right + space;
466 // r.right = r.left + fForward->Bounds().Width();
467 // _LayoutControl(fForward, r);
469 r.left = r.right + space;
470 r.right = r.left + fSkipForward->Bounds().Width();
471 _LayoutControl(fSkipForward, r);
473 r.left = r.right + space + space;
474 r.right = r.left + fMute->Bounds().Width();
475 _LayoutControl(fMute, r);
477 r.left = r.right + SPEAKER_SLIDER_DIST; // keep speaker icon and volume slider attached
478 r.right = frame.right;
479 _LayoutControl(fVolumeSlider, r, true);
484 MediaControlView::_MinFrame() const
486 // add up width of controls along bottom (seek slider will likely adopt)
487 float minWidth = 2 * BORDER_INSET;
488 minWidth += fSkipBack->Bounds().Width() + MIN_SPACE;
489 // minWidth += fRewind->Bounds().Width() + MIN_SPACE;
490 minWidth += fStop->Bounds().Width() + MIN_SPACE;
491 minWidth += fPlayPause->Bounds().Width() + MIN_SPACE;
492 // minWidth += fForward->Bounds().Width() + MIN_SPACE;
493 minWidth += fSkipForward->Bounds().Width() + MIN_SPACE + MIN_SPACE;
494 minWidth += fMute->Bounds().Width() + SPEAKER_SLIDER_DIST;
495 minWidth += VOLUME_MIN_WIDTH;
497 // add up height of seek slider and heighest control on bottom
498 float minHeight = 2 * BORDER_INSET;
499 minHeight += fSeekSlider->Bounds().Height() + MIN_SPACE + MIN_SPACE / 2.0;
500 minHeight += fBottomControlHeight;
501 return BRect(0.0, 0.0, minWidth - 1.0, minHeight - 1.0);
506 MediaControlView::_LayoutControl(BView* view, BRect frame,
507 bool resizeWidth, bool resizeHeight) const
511 frame.top = (frame.top + frame.bottom) / 2.0 - view->Bounds().Height() / 2.0;
513 //center horizontally
514 frame.left = (frame.left + frame.right) / 2.0 - view->Bounds().Width() / 2.0;
515 view->MoveTo(frame.LeftTop());
516 float width = resizeWidth ? frame.Width() : view->Bounds().Width();
517 float height = resizeHeight ? frame.Height() : view->Bounds().Height();
518 if (resizeWidth || resizeHeight)
519 view->ResizeTo(width, height);
524 /*****************************************************************************
526 *****************************************************************************/
527 SeekSlider::SeekSlider( intf_thread_t * _p_intf,
528 BRect frame, const char* name, MediaControlView *owner )
529 : BControl(frame, name, NULL, NULL, B_FOLLOW_NONE,
530 B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE),
535 BFont font(be_plain_font);
540 SeekSlider::~SeekSlider()
544 /*****************************************************************************
545 * VolumeSlider::AttachedToWindow
546 *****************************************************************************/
548 SeekSlider::AttachedToWindow()
550 BControl::AttachedToWindow();
551 SetViewColor(B_TRANSPARENT_32_BIT);
554 /*****************************************************************************
556 *****************************************************************************/
558 SeekSlider::Draw(BRect updateRect)
561 float knobWidth2 = SEEK_SLIDER_KNOB_WIDTH / 2.0;
562 float sliderStart = (r.left + knobWidth2);
563 float sliderEnd = (r.right - knobWidth2);
564 float knobPos = sliderStart
565 + floorf((sliderEnd - sliderStart - 1.0) * Value()
567 // draw both sides (the original from Be doesn't seem
568 // to make a difference for enabled/disabled state)
569 // DrawBitmapAsync(fLeftSideBits, r.LeftTop());
570 // DrawBitmapAsync(fRightSideBits, BPoint(sliderEnd + 1.0, r.top));
571 // colors for the slider area between the two bitmaps
572 rgb_color background = kBackground;//ui_color(B_PANEL_BACKGROUND_COLOR);
573 rgb_color shadow = tint_color(background, B_DARKEN_2_TINT);
574 rgb_color softShadow = tint_color(background, B_DARKEN_1_TINT);
575 rgb_color darkShadow = tint_color(background, B_DARKEN_4_TINT);
576 rgb_color midShadow = tint_color(background, B_DARKEN_3_TINT);
577 rgb_color light = tint_color(background, B_LIGHTEN_MAX_TINT);
578 rgb_color softLight = tint_color(background, B_LIGHTEN_1_TINT);
579 rgb_color green = kSeekGreen;
580 rgb_color greenShadow = kSeekGreenShadow;
581 rgb_color black = kBlack;
582 rgb_color dotGrey = midShadow;
583 rgb_color dotGreen = greenShadow;
585 _StrokeFrame(r, softShadow, softShadow, softLight, softLight);
587 _StrokeFrame(r, black, black, light, light);
592 _StrokeFrame(r, greenShadow, greenShadow, green, green);
595 _StrokeFrame(r, greenShadow, greenShadow, green, green);
601 int32 dotCount = (int32)(r.Width() / 6.0);
603 dotPos.y = r.top + 2.0;
604 SetHighColor(dotGreen);
605 for (int32 i = 0; i < dotCount; i++)
607 dotPos.x = sliderStart + i * 6.0 + 5.0;
608 StrokeLine(dotPos, BPoint(dotPos.x, dotPos.y + 6.0));
613 r.left = knobPos - knobWidth2;
614 r.right = knobPos + knobWidth2;
616 float handleBottomSize = 2.0;
617 float handleArrowSize = 6.0;
620 AddLine(BPoint(r.left, r.top + handleBottomSize),
621 BPoint(r.left, r.top), black);
622 AddLine(BPoint(r.left + 1.0, r.top),
623 BPoint(r.right, r.top), black);
624 AddLine(BPoint(r.right, r.top + 1.0),
625 BPoint(r.right, r.top + handleBottomSize), black);
626 AddLine(BPoint(r.right - 1.0, r.top + handleBottomSize + 1.0),
627 BPoint(knobPos, r.top + handleArrowSize), black);
628 AddLine(BPoint(knobPos - 1.0, r.top + handleArrowSize - 1.0),
629 BPoint(r.left + 1.0, r.top + handleBottomSize + 1.0), black);
631 AddLine(BPoint(r.left, r.bottom),
632 BPoint(r.left, r.bottom - handleBottomSize), black);
633 AddLine(BPoint(r.left + 1.0, r.bottom - handleBottomSize - 1.0),
634 BPoint(knobPos, r.bottom - handleArrowSize), black);
635 AddLine(BPoint(knobPos + 1.0, r.bottom - handleArrowSize + 1.0),
636 BPoint(r.right, r.bottom - handleBottomSize), black);
637 AddLine(BPoint(r.right, r.bottom - handleBottomSize + 1.0),
638 BPoint(r.right, r.bottom), black);
639 AddLine(BPoint(r.right - 1.0, r.bottom),
640 BPoint(r.left + 1.0, r.bottom), black);
642 // inner red light and shadow lines
645 handleArrowSize -= 2.0;
648 AddLine(BPoint(r.left, r.top + handleBottomSize),
649 BPoint(r.left, r.top), kSeekRedLight);
650 AddLine(BPoint(r.left + 1.0, r.top),
651 BPoint(r.right, r.top), kSeekRedLight);
652 AddLine(BPoint(r.right, r.top + 1.0),
653 BPoint(r.right, r.top + handleBottomSize), kSeekRedShadow);
654 AddLine(BPoint(r.right - 1.0, r.top + handleBottomSize + 1.0),
655 BPoint(knobPos, r.top + handleArrowSize), kSeekRedShadow);
656 AddLine(BPoint(knobPos - 1.0, r.top + handleArrowSize - 1.0),
657 BPoint(r.left + 1.0, r.top + handleBottomSize + 1.0), kSeekRedLight);
659 AddLine(BPoint(r.left, r.bottom),
660 BPoint(r.left, r.bottom - handleBottomSize), kSeekRedLight);
661 AddLine(BPoint(r.left + 1.0, r.bottom - handleBottomSize - 1.0),
662 BPoint(knobPos, r.bottom - handleArrowSize), kSeekRedLight);
663 AddLine(BPoint(knobPos + 1.0, r.bottom - handleArrowSize + 1.0),
664 BPoint(r.right, r.bottom - handleBottomSize), kSeekRedShadow);
665 AddLine(BPoint(r.right, r.bottom - handleBottomSize + 1.0),
666 BPoint(r.right, r.bottom), kSeekRedShadow);
667 AddLine(BPoint(r.right - 1.0, r.bottom),
668 BPoint(r.left + 1.0, r.bottom), kSeekRedShadow);
670 // fill rest of handles with red
671 SetHighColor(kSeekRed);
673 handleArrowSize -= 2.0;
675 // upper handle arrow
678 arrow[1].x = r.right;
680 arrow[2].x = knobPos;
681 arrow[2].y = r.top + handleArrowSize;
682 FillPolygon(arrow, 3);
683 // lower handle arrow
685 arrow[0].y = r.bottom;
686 arrow[1].x = r.right;
687 arrow[1].y = r.bottom;
688 arrow[2].x = knobPos;
689 arrow[2].y = r.bottom - handleArrowSize;
690 FillPolygon(arrow, 3);
695 _StrokeFrame(r, darkShadow, darkShadow, darkShadow, darkShadow);
697 _StrokeFrame(r, darkShadow, darkShadow, darkShadow, darkShadow);
699 SetHighColor(darkShadow);
702 float width = floorf(StringWidth(DISABLED_SEEK_MESSAGE));
703 float textPos = r.left + r.Width() / 2.0 - width / 2.0;
704 pattern stripes = {{ 0xc7, 0x8f, 0x1f, 0x3e, 0x7c, 0xf8, 0xf1, 0xe3 }};
705 BRect stripesRect(r);
706 stripesRect.right = textPos - 5.0;
707 FillRect(stripesRect, stripes);
708 stripesRect.left = textPos + width + 3.0;
709 stripesRect.right = r.right;
710 FillRect(stripesRect, stripes);
712 r.left = textPos - 4.0;
713 r.right = textPos + width + 2.0;
715 SetHighColor(shadow);
716 SetLowColor(darkShadow);
719 DrawString(DISABLED_SEEK_MESSAGE, BPoint(textPos, r.top + ceilf(fh.ascent) - 1.0));
723 /*****************************************************************************
724 * SeekSlider::MouseDown
725 *****************************************************************************/
727 SeekSlider::MouseDown(BPoint where)
729 if (IsEnabled() && Bounds().Contains(where))
731 SetValue(_ValueFor(where.x));
733 SetMouseEventMask(B_POINTER_EVENTS, B_LOCK_WINDOW_FOCUS);
737 /*****************************************************************************
738 * SeekSlider::MouseMoved
739 *****************************************************************************/
741 SeekSlider::MouseMoved(BPoint where, uint32 code, const BMessage* dragMessage)
745 SetValue(_ValueFor(where.x));
749 /*****************************************************************************
750 * SeekSlider::MouseUp
751 *****************************************************************************/
753 SeekSlider::MouseUp(BPoint where)
758 input_thread_t * p_input;
759 p_input = (input_thread_t *)
760 vlc_object_find( p_intf, VLC_OBJECT_INPUT, FIND_ANYWHERE );
764 var_SetFloat( p_input, "position",
765 (float) Value() / SEEKSLIDER_RANGE );
766 vlc_object_release( p_input );
771 /*****************************************************************************
772 * SeekSlider::ResizeToPreferred
773 *****************************************************************************/
775 SeekSlider::ResizeToPreferred()
777 float width = 15.0 + StringWidth(DISABLED_SEEK_MESSAGE) + 15.0;
778 ResizeTo(width, 17.0);
781 /*****************************************************************************
782 * SeekSlider::SetPosition
783 *****************************************************************************/
785 SeekSlider::SetPosition(float position)
791 SetValue( SEEKSLIDER_RANGE * position );
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 = (int32)(((xPos - sliderStart) * SEEKSLIDER_RANGE)
808 / (sliderEnd - sliderStart - 1.0));
811 if (value > SEEKSLIDER_RANGE)
812 value = SEEKSLIDER_RANGE;
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 /*****************************************************************************
833 *****************************************************************************/
834 VolumeSlider::VolumeSlider(BRect frame, const char* name, int32 minValue, int32 maxValue,
835 BMessage* message, BHandler* target)
836 : BControl(frame, name, NULL, message, B_FOLLOW_NONE,
837 B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE),
839 fRightSideBits(NULL),
849 BRect r(BPoint(0.0, 0.0), kVolumeSliderBitmapSize);
850 fLeftSideBits = new BBitmap(r, B_CMAP8);
851 fRightSideBits = new BBitmap(r, B_CMAP8);
852 r.Set(0.0, 0.0, kVolumeSliderKnobBitmapSize.x, kVolumeSliderKnobBitmapSize.y);
853 fKnobBits = new BBitmap(r, B_CMAP8);
858 /*****************************************************************************
859 * VolumeSlider destructor
860 *****************************************************************************/
861 VolumeSlider::~VolumeSlider()
863 delete fLeftSideBits;
864 delete fRightSideBits;
868 /*****************************************************************************
869 * VolumeSlider::AttachedToWindow
870 *****************************************************************************/
872 VolumeSlider::AttachedToWindow()
874 BControl::AttachedToWindow();
875 SetViewColor(B_TRANSPARENT_32_BIT);
878 /*****************************************************************************
879 * VolumeSlider::SetValue
880 *****************************************************************************/
882 VolumeSlider::SetValue(int32 value)
884 if (value != Value())
886 BControl::SetValue(value);
891 /*****************************************************************************
892 * VolumeSlider::SetEnabled
893 *****************************************************************************/
895 VolumeSlider::SetEnabled(bool enable)
897 if (enable != IsEnabled())
899 BControl::SetEnabled(enable);
905 /*****************************************************************************
907 *****************************************************************************/
909 VolumeSlider::Draw(BRect updateRect)
914 float sliderSideWidth = kVolumeSliderBitmapWidth;
915 float sliderStart = (r.left + sliderSideWidth);
916 float sliderEnd = (r.right - sliderSideWidth);
917 float knobPos = sliderStart
918 + (sliderEnd - sliderStart - 1.0) * (Value() - fMinValue)
919 / (fMaxValue - fMinValue);
920 // draw both sides (the original from Be doesn't seem
921 // to make a difference for enabled/disabled state)
922 DrawBitmapAsync(fLeftSideBits, r.LeftTop());
923 DrawBitmapAsync(fRightSideBits, BPoint(sliderEnd + 1.0, r.top));
924 // colors for the slider area between the two bitmaps
925 rgb_color background = kBackground;//ui_color(B_PANEL_BACKGROUND_COLOR);
926 rgb_color shadow = tint_color(background, B_DARKEN_2_TINT);
927 rgb_color softShadow = tint_color(background, B_DARKEN_1_TINT);
928 rgb_color darkShadow = tint_color(background, B_DARKEN_4_TINT);
929 rgb_color midShadow = tint_color(background, B_DARKEN_3_TINT);
930 rgb_color light = tint_color(background, B_LIGHTEN_MAX_TINT);
931 rgb_color softLight = tint_color(background, B_LIGHTEN_1_TINT);
932 rgb_color green = kGreen;
933 rgb_color greenShadow = kGreenShadow;
934 rgb_color black = kBlack;
935 rgb_color dotGrey = midShadow;
936 rgb_color dotGreen = greenShadow;
937 // make dimmed version of colors if we're disabled
940 shadow = (rgb_color){ 200, 200, 200, 255 };
941 softShadow = dimmed_color_cmap8(softShadow, background, DIM_LEVEL);
942 darkShadow = dimmed_color_cmap8(darkShadow, background, DIM_LEVEL);
944 light = dimmed_color_cmap8(light, background, DIM_LEVEL);
945 softLight = dimmed_color_cmap8(softLight, background, DIM_LEVEL);
946 green = dimmed_color_cmap8(green, background, DIM_LEVEL);
947 greenShadow = dimmed_color_cmap8(greenShadow, background, DIM_LEVEL);
948 black = dimmed_color_cmap8(black, background, DIM_LEVEL);
953 green = tint_color(kBackground, B_DARKEN_3_TINT);
954 greenShadow = tint_color(kBackground, B_DARKEN_4_TINT);
955 dotGreen = greenShadow;
957 // draw slider edges between bitmaps
959 AddLine(BPoint(sliderStart, r.top),
960 BPoint(sliderEnd, r.top), softShadow);
961 AddLine(BPoint(sliderStart, r.bottom),
962 BPoint(sliderEnd, r.bottom), softLight);
964 AddLine(BPoint(sliderStart, r.top),
965 BPoint(sliderEnd, r.top), black);
966 AddLine(BPoint(sliderStart, r.bottom),
967 BPoint(sliderEnd, r.bottom), light);
969 AddLine(BPoint(sliderStart, r.top),
970 BPoint(knobPos, r.top), greenShadow);
971 AddLine(BPoint(knobPos, r.top),
972 BPoint(sliderEnd, r.top), midShadow);
974 AddLine(BPoint(sliderStart, r.top),
975 BPoint(knobPos, r.top), greenShadow);
977 // fill rest inside of slider
979 r.left = sliderStart;
982 FillRect(r, B_SOLID_HIGH);
983 r.left = knobPos + 1.0;
986 SetHighColor(shadow);
987 FillRect(r, B_SOLID_HIGH);
988 // draw little dots inside
989 int32 dotCount = (int32)((sliderEnd - sliderStart) / 5.0);
991 dotPos.y = r.top + 4.0;
992 for (int32 i = 0; i < dotCount; i++)
994 dotPos.x = sliderStart + i * 5.0 + 4.0;
995 SetHighColor(dotPos.x < knobPos ? dotGreen : dotGrey);
996 StrokeLine(dotPos, BPoint(dotPos.x, dotPos.y + 1.0));
1000 SetDrawingMode(B_OP_OVER); // part of knob is transparent
1001 DrawBitmapAsync(fKnobBits, BPoint(knobPos - kVolumeSliderKnobWidth / 2, r.top));
1005 /*****************************************************************************
1006 * VolumeSlider::MouseDown
1007 *****************************************************************************/
1009 VolumeSlider::MouseDown(BPoint where)
1011 if (Bounds().Contains(where) && IsEnabled())
1014 SetValue(_ValueFor(where.x));
1015 SetMouseEventMask(B_POINTER_EVENTS, B_LOCK_WINDOW_FOCUS);
1019 /*****************************************************************************
1020 * VolumeSlider::MouseMoved
1021 *****************************************************************************/
1023 VolumeSlider::MouseMoved(BPoint where, uint32 transit, const BMessage* dragMessage)
1026 SetValue(_ValueFor(where.x));
1029 /*****************************************************************************
1030 * VolumeSlider::MouseUp
1031 *****************************************************************************/
1033 VolumeSlider::MouseUp(BPoint where)
1039 /*****************************************************************************
1040 * VolumeSlider::IsValid
1041 *****************************************************************************/
1043 VolumeSlider::IsValid() const
1045 return (fLeftSideBits && fLeftSideBits->IsValid()
1046 && fRightSideBits && fRightSideBits->IsValid()
1047 && fKnobBits && fKnobBits->IsValid());
1050 /*****************************************************************************
1051 * VolumeSlider::SetMuted
1052 *****************************************************************************/
1054 VolumeSlider::SetMuted(bool mute)
1064 /*****************************************************************************
1065 * VolumeSlider::_MakeBitmaps
1066 *****************************************************************************/
1068 VolumeSlider::_MakeBitmaps()
1072 // left side of slider
1073 memcpy(fLeftSideBits->Bits(), kVolumeSliderLeftBitmapBits,
1074 fLeftSideBits->BitsLength());
1075 // right side of slider
1076 memcpy(fRightSideBits->Bits(), kVolumeSliderRightBits,
1077 fRightSideBits->BitsLength());
1079 int32 length = fKnobBits->BitsLength();
1080 memcpy(fKnobBits->Bits(), kVolumeSliderKnobBits, length);
1081 uint8* bits = (uint8*)fKnobBits->Bits();
1082 // black was used in the knob to represent transparency
1083 // use screen to get index for the "transarent" color used in the bitmap
1084 BScreen screen(B_MAIN_SCREEN_ID);
1085 uint8 blackIndex = screen.IndexForColor(kBlack);
1086 // replace black index with transparent index
1087 for (int32 i = 0; i < length; i++)
1088 if (bits[i] == blackIndex)
1089 bits[i] = B_TRANSPARENT_MAGIC_CMAP8;
1093 // make ghosted versions of the bitmaps
1094 dim_bitmap(fLeftSideBits, kBackground, DIM_LEVEL);
1095 dim_bitmap(fRightSideBits, kBackground, DIM_LEVEL);
1096 dim_bitmap(fKnobBits, kBackground, DIM_LEVEL);
1100 // replace green color (and shadow) in left slider side
1101 bits = (uint8*)fLeftSideBits->Bits();
1102 length = fLeftSideBits->BitsLength();
1103 uint8 greenIndex = screen.IndexForColor(kGreen);
1104 uint8 greenShadowIndex = screen.IndexForColor(kGreenShadow);
1105 rgb_color shadow = tint_color(kBackground, B_DARKEN_3_TINT);
1106 rgb_color midShadow = tint_color(kBackground, B_DARKEN_4_TINT);
1107 uint8 replaceIndex = screen.IndexForColor(shadow);
1108 uint8 replaceShadowIndex = screen.IndexForColor(midShadow);
1109 for (int32 i = 0; i < length; i++)
1111 if (bits[i] == greenIndex)
1112 bits[i] = replaceIndex;
1113 else if (bits[i] == greenShadowIndex)
1114 bits[i] = replaceShadowIndex;
1120 /*****************************************************************************
1121 * VolumeSlider::_ValueFor
1122 *****************************************************************************/
1124 VolumeSlider::_ValueFor(float xPos) const
1127 float sliderStart = (r.left + kVolumeSliderBitmapWidth);
1128 float sliderEnd = (r.right - kVolumeSliderBitmapWidth);
1129 int32 value = fMinValue + (int32)(((xPos - sliderStart) * (fMaxValue - fMinValue))
1130 / (sliderEnd - sliderStart - 1.0));
1131 if (value < fMinValue)
1133 if (value > fMaxValue)
1138 /*****************************************************************************
1139 * PositionInfoView::PositionInfoView
1140 *****************************************************************************/
1141 PositionInfoView::PositionInfoView( BRect frame, const char* name,
1142 intf_thread_t * p_interface )
1143 : BView( frame, name, B_FOLLOW_NONE,
1144 B_WILL_DRAW | B_PULSE_NEEDED | B_FULL_UPDATE_ON_RESIZE ),
1145 fMode( MODE_SMALL ),
1146 fCurrentFileIndex( -1 ),
1147 fCurrentFileSize( -1 ),
1148 fCurrentTitleIndex( -1 ),
1149 fCurrentTitleSize( -1 ),
1150 fCurrentChapterIndex( -1 ),
1151 fCurrentChapterSize( -1 ),
1153 fTimeString( "-:--:--" ),
1154 fLastPulseUpdate( system_time() ),
1155 fStackedWidthCache( 0.0 ),
1156 fStackedHeightCache( 0.0 )
1158 p_intf = p_interface;
1160 SetViewColor( B_TRANSPARENT_32_BIT );
1161 SetLowColor( kBlack );
1162 SetHighColor( 0, 255, 0, 255 );
1163 SetFontSize( 11.0 );
1166 /*****************************************************************************
1167 * PositionInfoView::~PositionInfoView
1168 *****************************************************************************/
1169 PositionInfoView::~PositionInfoView()
1173 /*****************************************************************************
1174 * PositionInfoView::Draw
1175 *****************************************************************************/
1177 PositionInfoView::Draw( BRect updateRect )
1179 rgb_color background = ui_color( B_PANEL_BACKGROUND_COLOR );
1180 rgb_color shadow = tint_color( background, B_DARKEN_1_TINT );
1181 rgb_color darkShadow = tint_color( background, B_DARKEN_4_TINT );
1182 rgb_color light = tint_color( background, B_LIGHTEN_MAX_TINT );
1183 rgb_color softLight = tint_color( background, B_LIGHTEN_1_TINT );
1185 BRect r( Bounds() );
1186 BeginLineArray( 8 );
1187 AddLine( BPoint( r.left, r.bottom ),
1188 BPoint( r.left, r.top ), shadow );
1189 AddLine( BPoint( r.left + 1.0, r.top ),
1190 BPoint( r.right, r.top ), shadow );
1191 AddLine( BPoint( r.right, r.top + 1.0 ),
1192 BPoint( r.right, r.bottom ), softLight );
1193 AddLine( BPoint( r.right - 1.0, r.bottom ),
1194 BPoint( r.left + 1.0, r.bottom ), softLight );
1195 r.InsetBy( 1.0, 1.0 );
1196 AddLine( BPoint( r.left, r.bottom ),
1197 BPoint( r.left, r.top ), darkShadow );
1198 AddLine( BPoint( r.left + 1.0, r.top ),
1199 BPoint( r.right, r.top ), darkShadow );
1200 AddLine( BPoint( r.right, r.top + 1.0 ),
1201 BPoint( r.right, r.bottom ), light );
1202 AddLine( BPoint( r.right - 1.0, r.bottom ),
1203 BPoint( r.left + 1.0, r.bottom ), light );
1206 r.InsetBy( 1.0, 1.0 );
1207 FillRect( r, B_SOLID_LOW );
1210 GetFontHeight( &fh );
1215 float width = StringWidth( fTimeString.String() );
1216 DrawString( fTimeString.String(),
1217 BPoint( r.left + r.Width() / 2.0 - width / 2.0,
1218 r.top + r.Height() / 2.0 + fh.ascent / 2.0 - 1.0 ) );
1225 BFont smallFont = font;
1226 BFont bigFont = font;
1227 BFont tinyFont = font;
1228 smallFont.SetSize( r.Height() / 5.0 );
1229 bigFont.SetSize( r.Height() / 3.0 );
1230 tinyFont.SetSize( r.Height() / 7.0 );
1231 float timeHeight = r.Height() / 2.5;
1232 float height = ( r.Height() - timeHeight ) / 3.0;
1233 SetFont( &tinyFont );
1234 SetHighColor( 0, 180, 0, 255 );
1235 DrawString( _("File"), BPoint( r.left + 3.0, r.top + height ) );
1236 DrawString( _("Title"), BPoint( r.left + 3.0, r.top + 2.0 * height ) );
1237 DrawString( _("Chapter"), BPoint( r.left + 3.0, r.top + 3.0 * height ) );
1238 SetFont( &smallFont );
1240 SetHighColor( 0, 255, 0, 255 );
1242 _MakeString( helper, fCurrentFileIndex, fCurrentFileSize );
1243 float width = StringWidth( helper.String() );
1244 DrawString( helper.String(), BPoint( r.right - 3.0 - width, r.top + height ) );
1246 _MakeString( helper, fCurrentTitleIndex, fCurrentTitleSize );
1247 width = StringWidth( helper.String() );
1248 DrawString( helper.String(), BPoint( r.right - 3.0 - width, r.top + 2.0 * height ) );
1250 _MakeString( helper, fCurrentChapterIndex, fCurrentChapterSize );
1251 width = StringWidth( helper.String() );
1252 DrawString( helper.String(), BPoint( r.right - 3.0 - width, r.top + 3.0 * height ) );
1254 SetFont( &bigFont );
1255 width = StringWidth( fTimeString.String() );
1256 DrawString( fTimeString.String(),
1257 BPoint( r.left + r.Width() / 2.0 - width / 2.0,
1264 /*****************************************************************************
1265 * PositionInfoView::ResizeToPreferred
1266 *****************************************************************************/
1268 PositionInfoView::ResizeToPreferred()
1270 float width, height;
1271 GetPreferredSize( &width, &height );
1272 ResizeTo( width, height );
1275 /*****************************************************************************
1276 * PositionInfoView::GetPreferredSize
1277 *****************************************************************************/
1279 PositionInfoView::GetPreferredSize( float* width, float* height )
1281 if ( width && height )
1283 *width = 5.0 + ceilf( StringWidth( "0:00:00" ) ) + 5.0;
1285 GetFontHeight( &fh );
1286 *height = 3.0 + ceilf( fh.ascent ) + 3.0;
1287 fStackedWidthCache = *width * 1.2;
1288 fStackedHeightCache = *height * 2.7;
1292 /*****************************************************************************
1293 * PositionInfoView::Pulse
1294 *****************************************************************************/
1296 PositionInfoView::Pulse()
1298 // allow for Pulse frequency to be higher, MediaControlView needs it
1299 bigtime_t now = system_time();
1300 if ( now - fLastPulseUpdate > 900000 )
1304 p_intf->p_sys->p_wrapper->GetPlaylistInfo( index, size );
1305 SetFile( index + 1, size );
1306 p_intf->p_sys->p_wrapper->TitleInfo( index, size );
1307 SetTitle( index, size );
1308 p_intf->p_sys->p_wrapper->ChapterInfo( index, size );
1309 SetChapter( index, size );
1310 SetTime( p_intf->p_sys->p_wrapper->GetTimeAsString() );
1311 fLastPulseUpdate = now;
1316 /*****************************************************************************
1317 * PositionInfoView::GetBigPreferredSize
1318 *****************************************************************************/
1320 PositionInfoView::GetBigPreferredSize( float* width, float* height )
1322 if ( width && height )
1324 *width = fStackedWidthCache;
1325 *height = fStackedHeightCache;
1329 /*****************************************************************************
1330 * PositionInfoView::SetMode
1331 *****************************************************************************/
1333 PositionInfoView::SetMode( uint32 mode )
1335 if ( fMode != mode )
1338 _InvalidateContents();
1342 /*****************************************************************************
1343 * PositionInfoView::SetFile
1344 *****************************************************************************/
1346 PositionInfoView::SetFile( int32 index, int32 size )
1348 if ( fCurrentFileIndex != index || fCurrentFileSize != size )
1350 fCurrentFileIndex = index;
1351 fCurrentFileSize = size;
1352 _InvalidateContents();
1356 /*****************************************************************************
1357 * PositionInfoView::SetTitle
1358 *****************************************************************************/
1360 PositionInfoView::SetTitle( int32 index, int32 size )
1362 if ( fCurrentTitleIndex != index || fCurrentFileSize != size )
1364 fCurrentTitleIndex = index;
1365 fCurrentTitleSize = size;
1366 _InvalidateContents();
1370 /*****************************************************************************
1371 * PositionInfoView::SetChapter
1372 *****************************************************************************/
1374 PositionInfoView::SetChapter( int32 index, int32 size )
1376 if ( fCurrentChapterIndex != index || fCurrentFileSize != size )
1378 fCurrentChapterIndex = index;
1379 fCurrentChapterSize = size;
1380 _InvalidateContents();
1384 /*****************************************************************************
1385 * PositionInfoView::SetTime
1386 *****************************************************************************/
1388 PositionInfoView::SetTime( int32 seconds )
1390 if ( fSeconds != seconds )
1394 int32 minutes = seconds / 60;
1395 int32 hours = minutes / 60;
1396 seconds -= minutes * 60 - hours * 60 * 60;
1397 minutes -= hours * 60;
1398 fTimeString.SetTo( "" );
1399 fTimeString << hours << ":" << minutes << ":" << seconds;
1402 fTimeString.SetTo( "-:--:--" );
1405 _InvalidateContents();
1409 /*****************************************************************************
1410 * PositionInfoView::SetTime
1411 *****************************************************************************/
1413 PositionInfoView::SetTime( const char* string )
1415 fTimeString.SetTo( string );
1416 _InvalidateContents();
1419 /*****************************************************************************
1420 * PositionInfoView::_InvalidateContents
1421 *****************************************************************************/
1423 PositionInfoView::_InvalidateContents( uint32 which )
1425 BRect r( Bounds() );
1426 r.InsetBy( 2.0, 2.0 );
1430 /*****************************************************************************
1431 * PositionInfoView::_InvalidateContents
1432 *****************************************************************************/
1434 PositionInfoView::_MakeString( BString& into, int32 index, int32 maxIndex ) const
1437 if ( index >= 0 && maxIndex >= 0 )
1442 if ( maxIndex >= 0 )