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>
33 #include <vlc_interface.h>
36 #include <audio_output.h>
39 /* BeOS interface headers */
41 #include "DrawingTidbits.h"
42 #include "InterfaceWindow.h"
44 #include "TransportButton.h"
45 #include "ListViews.h"
46 #include "MediaControlView.h"
48 #define BORDER_INSET 6.0
50 #define SPEAKER_SLIDER_DIST 6.0
51 #define VOLUME_MIN_WIDTH 70.0
53 #define VOLUME_SLIDER_LAYOUT_WEIGHT 2.0
54 #define SEEK_SLIDER_KNOB_WIDTH 8.0
56 // slider colors are hardcoded here, because that's just
57 // what they currently are within those bitmaps
58 const rgb_color kGreen = (rgb_color){ 152, 203, 152, 255 };
59 const rgb_color kGreenShadow = (rgb_color){ 102, 152, 102, 255 };
60 const rgb_color kBackground = (rgb_color){ 216, 216, 216, 255 };
61 const rgb_color kSeekGreen = (rgb_color){ 171, 221, 161, 255 };
62 const rgb_color kSeekGreenShadow = (rgb_color){ 144, 186, 136, 255 };
63 const rgb_color kSeekRed = (rgb_color){ 255, 0, 0, 255 };
64 const rgb_color kSeekRedLight = (rgb_color){ 255, 152, 152, 255 };
65 const rgb_color kSeekRedShadow = (rgb_color){ 178, 0, 0, 255 };
67 #define DISABLED_SEEK_MESSAGE _("Drop files to play")
68 #define SEEKSLIDER_RANGE 2048
74 MSG_SKIP_BACKWARDS = 'skpb',
75 MSG_SKIP_FORWARD = 'skpf',
79 MediaControlView::MediaControlView( intf_thread_t * _p_intf, BRect frame)
80 : BBox(frame, NULL, B_FOLLOW_NONE, B_WILL_DRAW | B_FRAME_EVENTS | B_PULSE_NEEDED,
83 fCurrentRate(INPUT_RATE_DEFAULT),
85 fBottomControlHeight(0.0),
88 BRect frame(0.0, 0.0, 10.0, 10.0);
91 fSeekSlider = new SeekSlider( p_intf, frame, "seek slider", this );
92 fSeekSlider->SetValue(0);
93 fSeekSlider->ResizeToPreferred();
94 AddChild( fSeekSlider );
98 frame.SetRightBottom(kSkipButtonSize);
99 fBottomControlHeight = kRewindBitmapHeight - 1.0;
100 fSkipBack = new TransportButton(frame, B_EMPTY_STRING,
102 kPressedSkipBackBitmapBits,
103 kDisabledSkipBackBitmapBits,
104 new BMessage(MSG_SKIP_BACKWARDS));
105 AddChild( fSkipBack );
108 frame.SetRightBottom(kPlayButtonSize);
109 if (fBottomControlHeight < kPlayPauseBitmapHeight - 1.0)
110 fBottomControlHeight = kPlayPauseBitmapHeight - 1.0;
111 fPlayPause = new PlayPauseButton(frame, B_EMPTY_STRING,
112 kPlayButtonBitmapBits,
113 kPressedPlayButtonBitmapBits,
114 kDisabledPlayButtonBitmapBits,
115 kPlayingPlayButtonBitmapBits,
116 kPressedPlayingPlayButtonBitmapBits,
117 kPausedPlayButtonBitmapBits,
118 kPressedPausedPlayButtonBitmapBits,
119 new BMessage(START_PLAYBACK));
121 AddChild( fPlayPause );
124 frame.SetRightBottom(kSkipButtonSize);
125 fSkipForward = new TransportButton(frame, B_EMPTY_STRING,
126 kSkipForwardBitmapBits,
127 kPressedSkipForwardBitmapBits,
128 kDisabledSkipForwardBitmapBits,
129 new BMessage(MSG_SKIP_FORWARD));
130 AddChild( fSkipForward );
133 fForward = new TransportButton(frame, B_EMPTY_STRING,
135 kPressedForwardBitmapBits,
136 kDisabledForwardBitmapBits,
137 new BMessage(MSG_FORWARD));
138 // AddChild( fForward );
141 fRewind = new TransportButton(frame, B_EMPTY_STRING,
143 kPressedRewindBitmapBits,
144 kDisabledRewindBitmapBits,
145 new BMessage(MSG_REWIND));
146 // AddChild( fRewind );
149 frame.SetRightBottom(kStopButtonSize);
150 if (fBottomControlHeight < kStopBitmapHeight - 1.0)
151 fBottomControlHeight = kStopBitmapHeight - 1.0;
152 fStop = new TransportButton(frame, B_EMPTY_STRING,
153 kStopButtonBitmapBits,
154 kPressedStopButtonBitmapBits,
155 kDisabledStopButtonBitmapBits,
156 new BMessage(STOP_PLAYBACK));
160 frame.SetRightBottom(kSpeakerButtonSize);
161 if (fBottomControlHeight < kSpeakerIconBitmapHeight - 1.0)
162 fBottomControlHeight = kSpeakerIconBitmapHeight - 1.0;
163 fMute = new TransportButton(frame, B_EMPTY_STRING,
165 kPressedSpeakerIconBits,
167 new BMessage(VOLUME_MUTE));
172 fVolumeSlider = new VolumeSlider(BRect(0.0, 0.0, VOLUME_MIN_WIDTH,
173 kVolumeSliderBitmapHeight - 1.0),
174 "volume slider", 1, AOUT_VOLUME_MAX,
175 new BMessage(VOLUME_CHG));
176 fVolumeSlider->SetValue( config_GetInt( p_intf, "volume" ) );
177 AddChild( fVolumeSlider );
179 // Position Info View
180 fPositionInfo = new PositionInfoView(BRect(0.0, 0.0, 10.0, 10.0), "led",
182 fPositionInfo->ResizeToPreferred();
183 AddChild( fPositionInfo );
187 MediaControlView::~MediaControlView()
193 MediaControlView::AttachedToWindow()
195 // we are now a valid BHandler
196 fRewind->SetTarget(this);
197 fForward->SetTarget(this);
198 fSkipBack->SetTarget(this);
199 fSkipForward->SetTarget(this);
200 fVolumeSlider->SetTarget(Window());
202 BRect r(_MinFrame());
203 if (BMenuBar* menuBar = Window()->KeyMenuBar()) {
205 menuBar->GetPreferredSize(&width, &height);
206 // r.bottom += menuBar->Bounds().Height();
208 // see that our calculated minimal width is not smaller than what
209 // the menubar can be
215 Window()->SetSizeLimits(r.Width(), r.Width() * 1.8, r.Height(), r.Height() * 1.3);
216 if (!Window()->Bounds().Contains(r))
217 Window()->ResizeTo(r.Width(), r.Height());
219 FrameResized(Bounds().Width(), Bounds().Height());
221 // get pulse message every two frames
222 Window()->SetPulseRate(80000);
227 MediaControlView::FrameResized(float width, float height)
230 // make sure we don't leave dirty pixels
231 // (B_FULL_UPDATE_ON_RESIZE == annoying flicker -> this is smarter)
232 if (fOldBounds.Width() < r.Width())
233 Invalidate(BRect(fOldBounds.right, fOldBounds.top + 1.0,
234 fOldBounds.right, fOldBounds.bottom - 1.0));
236 Invalidate(BRect(r.right, r.top + 1.0,
237 r.right, r.bottom - 1.0));
238 if (fOldBounds.Height() < r.Height())
239 Invalidate(BRect(fOldBounds.left + 1.0, fOldBounds.bottom,
240 fOldBounds.right - 1.0, fOldBounds.bottom));
242 Invalidate(BRect(r.left + 1.0, r.bottom,
243 r.right - 1.0, r.bottom));
244 // remember for next time
247 r.InsetBy(BORDER_INSET, BORDER_INSET);
253 MediaControlView::GetPreferredSize(float* width, float* height)
257 BRect r(_MinFrame());
259 *height = r.Height();
265 MediaControlView::MessageReceived(BMessage* message)
267 switch (message->what)
273 case MSG_SKIP_BACKWARDS:
274 Window()->PostMessage(NAVIGATE_PREV);
276 case MSG_SKIP_FORWARD:
277 Window()->PostMessage(NAVIGATE_NEXT);
280 BBox::MessageReceived(message);
287 MediaControlView::Pulse()
289 InterfaceWindow* window = dynamic_cast<InterfaceWindow*>(Window());
290 if (window && window->IsStopped())
291 fPlayPause->SetStopped();
293 unsigned short i_volume;
294 aout_VolumeGet( p_intf, (audio_volume_t*)&i_volume );
295 fVolumeSlider->SetValue( i_volume );
300 MediaControlView::SetProgress( float position )
302 fSeekSlider->SetPosition( position );
307 MediaControlView::SetStatus(int status, int rate)
309 // we need to set the button status periodically
310 // (even if it is the same) to get a blinking button
311 fCurrentStatus = status;
317 fPlayPause->SetPlaying();
320 fPlayPause->SetPaused();
323 fPlayPause->SetStopped();
326 if (rate != fCurrentRate)
329 if ( rate < INPUT_RATE_DEFAULT )
338 MediaControlView::SetEnabled(bool enabled)
340 if( ( enabled && fIsEnabled ) ||
341 ( !enabled && !fIsEnabled ) )
343 /* do not redraw if it is not necessary */
349 fSkipBack->SetEnabled( enabled );
350 fPlayPause->SetEnabled( enabled );
351 fSkipForward->SetEnabled( enabled );
352 fStop->SetEnabled( enabled );
353 fMute->SetEnabled( enabled );
354 fVolumeSlider->SetEnabled( enabled );
355 fSeekSlider->SetEnabled( enabled );
356 fRewind->SetEnabled( enabled );
357 fForward->SetEnabled( enabled );
359 fIsEnabled = enabled;
365 MediaControlView::SetAudioEnabled(bool enabled)
367 fMute->SetEnabled(enabled);
368 fVolumeSlider->SetEnabled(enabled);
373 MediaControlView::GetVolume() const
375 return fVolumeSlider->Value();
380 MediaControlView::SetSkippable(bool backward, bool forward)
382 fSkipBack->SetEnabled(backward);
383 fSkipForward->SetEnabled(forward);
388 MediaControlView::SetMuted(bool mute)
390 fVolumeSlider->SetMuted(mute);
395 MediaControlView::_LayoutControls(BRect frame) const
399 // calculate absolutly minimal width
400 float minWidth = fSkipBack->Bounds().Width();
401 // minWidth += fRewind->Bounds().Width();
402 minWidth += fStop->Bounds().Width();
403 minWidth += fPlayPause->Bounds().Width();
404 // minWidth += fForward->Bounds().Width();
405 minWidth += fSkipForward->Bounds().Width();
406 minWidth += fMute->Bounds().Width();
407 minWidth += VOLUME_MIN_WIDTH;
409 // layout time slider and info view
411 fPositionInfo->GetBigPreferredSize( &width, &height );
412 float ratio = width / height;
413 width = r.Height() * ratio;
414 if (frame.Width() - minWidth - MIN_SPACE >= width
415 && frame.Height() >= height)
417 r.right = r.left + width;
418 fPositionInfo->SetMode(PositionInfoView::MODE_BIG);
419 _LayoutControl(fPositionInfo, r, true, true);
420 frame.left = r.right + MIN_SPACE;
422 r.right = frame.right;
423 // r.bottom = r.top + r.Height() / 2.0 - MIN_SPACE / 2.0;
424 r.bottom = r.top + fSeekSlider->Bounds().Height();
425 _LayoutControl(fSeekSlider, r, true);
429 fPositionInfo->GetPreferredSize( &width, &height );
430 fPositionInfo->SetMode(PositionInfoView::MODE_SMALL);
431 fPositionInfo->ResizeTo(width, height);
432 r.bottom = r.top + r.Height() / 2.0 - MIN_SPACE / 2.0;
433 r.right = r.left + fPositionInfo->Bounds().Width();
434 _LayoutControl(fPositionInfo, r, true );
435 r.left = r.right + MIN_SPACE;
436 r.right = frame.right;
437 _LayoutControl(fSeekSlider, r, true);
439 float currentWidth = frame.Width();
440 float space = (currentWidth - minWidth) / 6.0;//8.0;
442 space = MIN_SPACE + (space - MIN_SPACE) / VOLUME_SLIDER_LAYOUT_WEIGHT;
443 // layout controls with "space" inbetween
445 r.top = r.bottom + MIN_SPACE + 1.0;
446 r.bottom = frame.bottom;
448 r.right = r.left + fSkipBack->Bounds().Width();
449 _LayoutControl(fSkipBack, r);
451 // r.left = r.right + space;
452 // r.right = r.left + fRewind->Bounds().Width();
453 // _LayoutControl(fRewind, r);
455 r.left = r.right + space;
456 r.right = r.left + fStop->Bounds().Width();
457 _LayoutControl(fStop, r);
459 r.left = r.right + space;
460 r.right = r.left + fPlayPause->Bounds().Width();
461 _LayoutControl(fPlayPause, r);
463 // r.left = r.right + space;
464 // r.right = r.left + fForward->Bounds().Width();
465 // _LayoutControl(fForward, r);
467 r.left = r.right + space;
468 r.right = r.left + fSkipForward->Bounds().Width();
469 _LayoutControl(fSkipForward, r);
471 r.left = r.right + space + space;
472 r.right = r.left + fMute->Bounds().Width();
473 _LayoutControl(fMute, r);
475 r.left = r.right + SPEAKER_SLIDER_DIST; // keep speaker icon and volume slider attached
476 r.right = frame.right;
477 _LayoutControl(fVolumeSlider, r, true);
482 MediaControlView::_MinFrame() const
484 // add up width of controls along bottom (seek slider will likely adopt)
485 float minWidth = 2 * BORDER_INSET;
486 minWidth += fSkipBack->Bounds().Width() + MIN_SPACE;
487 // minWidth += fRewind->Bounds().Width() + MIN_SPACE;
488 minWidth += fStop->Bounds().Width() + MIN_SPACE;
489 minWidth += fPlayPause->Bounds().Width() + MIN_SPACE;
490 // minWidth += fForward->Bounds().Width() + MIN_SPACE;
491 minWidth += fSkipForward->Bounds().Width() + MIN_SPACE + MIN_SPACE;
492 minWidth += fMute->Bounds().Width() + SPEAKER_SLIDER_DIST;
493 minWidth += VOLUME_MIN_WIDTH;
495 // add up height of seek slider and heighest control on bottom
496 float minHeight = 2 * BORDER_INSET;
497 minHeight += fSeekSlider->Bounds().Height() + MIN_SPACE + MIN_SPACE / 2.0;
498 minHeight += fBottomControlHeight;
499 return BRect(0.0, 0.0, minWidth - 1.0, minHeight - 1.0);
504 MediaControlView::_LayoutControl(BView* view, BRect frame,
505 bool resizeWidth, bool resizeHeight) const
509 frame.top = (frame.top + frame.bottom) / 2.0 - view->Bounds().Height() / 2.0;
511 //center horizontally
512 frame.left = (frame.left + frame.right) / 2.0 - view->Bounds().Width() / 2.0;
513 view->MoveTo(frame.LeftTop());
514 float width = resizeWidth ? frame.Width() : view->Bounds().Width();
515 float height = resizeHeight ? frame.Height() : view->Bounds().Height();
516 if (resizeWidth || resizeHeight)
517 view->ResizeTo(width, height);
522 /*****************************************************************************
524 *****************************************************************************/
525 SeekSlider::SeekSlider( intf_thread_t * _p_intf,
526 BRect frame, const char* name, MediaControlView *owner )
527 : BControl(frame, name, NULL, NULL, B_FOLLOW_NONE,
528 B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE),
533 BFont font(be_plain_font);
538 SeekSlider::~SeekSlider()
542 /*****************************************************************************
543 * VolumeSlider::AttachedToWindow
544 *****************************************************************************/
546 SeekSlider::AttachedToWindow()
548 BControl::AttachedToWindow();
549 SetViewColor(B_TRANSPARENT_32_BIT);
552 /*****************************************************************************
554 *****************************************************************************/
556 SeekSlider::Draw(BRect updateRect)
559 float knobWidth2 = SEEK_SLIDER_KNOB_WIDTH / 2.0;
560 float sliderStart = (r.left + knobWidth2);
561 float sliderEnd = (r.right - knobWidth2);
562 float knobPos = sliderStart
563 + floorf((sliderEnd - sliderStart - 1.0) * Value()
565 // draw both sides (the original from Be doesn't seem
566 // to make a difference for enabled/disabled state)
567 // DrawBitmapAsync(fLeftSideBits, r.LeftTop());
568 // DrawBitmapAsync(fRightSideBits, BPoint(sliderEnd + 1.0, r.top));
569 // colors for the slider area between the two bitmaps
570 rgb_color background = kBackground;//ui_color(B_PANEL_BACKGROUND_COLOR);
571 rgb_color shadow = tint_color(background, B_DARKEN_2_TINT);
572 rgb_color softShadow = tint_color(background, B_DARKEN_1_TINT);
573 rgb_color darkShadow = tint_color(background, B_DARKEN_4_TINT);
574 rgb_color midShadow = tint_color(background, B_DARKEN_3_TINT);
575 rgb_color light = tint_color(background, B_LIGHTEN_MAX_TINT);
576 rgb_color softLight = tint_color(background, B_LIGHTEN_1_TINT);
577 rgb_color green = kSeekGreen;
578 rgb_color greenShadow = kSeekGreenShadow;
579 rgb_color black = kBlack;
580 rgb_color dotGrey = midShadow;
581 rgb_color dotGreen = greenShadow;
583 _StrokeFrame(r, softShadow, softShadow, softLight, softLight);
585 _StrokeFrame(r, black, black, light, light);
590 _StrokeFrame(r, greenShadow, greenShadow, green, green);
593 _StrokeFrame(r, greenShadow, greenShadow, green, green);
599 int32 dotCount = (int32)(r.Width() / 6.0);
601 dotPos.y = r.top + 2.0;
602 SetHighColor(dotGreen);
603 for (int32 i = 0; i < dotCount; i++)
605 dotPos.x = sliderStart + i * 6.0 + 5.0;
606 StrokeLine(dotPos, BPoint(dotPos.x, dotPos.y + 6.0));
611 r.left = knobPos - knobWidth2;
612 r.right = knobPos + knobWidth2;
614 float handleBottomSize = 2.0;
615 float handleArrowSize = 6.0;
618 AddLine(BPoint(r.left, r.top + handleBottomSize),
619 BPoint(r.left, r.top), black);
620 AddLine(BPoint(r.left + 1.0, r.top),
621 BPoint(r.right, r.top), black);
622 AddLine(BPoint(r.right, r.top + 1.0),
623 BPoint(r.right, r.top + handleBottomSize), black);
624 AddLine(BPoint(r.right - 1.0, r.top + handleBottomSize + 1.0),
625 BPoint(knobPos, r.top + handleArrowSize), black);
626 AddLine(BPoint(knobPos - 1.0, r.top + handleArrowSize - 1.0),
627 BPoint(r.left + 1.0, r.top + handleBottomSize + 1.0), black);
629 AddLine(BPoint(r.left, r.bottom),
630 BPoint(r.left, r.bottom - handleBottomSize), black);
631 AddLine(BPoint(r.left + 1.0, r.bottom - handleBottomSize - 1.0),
632 BPoint(knobPos, r.bottom - handleArrowSize), black);
633 AddLine(BPoint(knobPos + 1.0, r.bottom - handleArrowSize + 1.0),
634 BPoint(r.right, r.bottom - handleBottomSize), black);
635 AddLine(BPoint(r.right, r.bottom - handleBottomSize + 1.0),
636 BPoint(r.right, r.bottom), black);
637 AddLine(BPoint(r.right - 1.0, r.bottom),
638 BPoint(r.left + 1.0, r.bottom), black);
640 // inner red light and shadow lines
643 handleArrowSize -= 2.0;
646 AddLine(BPoint(r.left, r.top + handleBottomSize),
647 BPoint(r.left, r.top), kSeekRedLight);
648 AddLine(BPoint(r.left + 1.0, r.top),
649 BPoint(r.right, r.top), kSeekRedLight);
650 AddLine(BPoint(r.right, r.top + 1.0),
651 BPoint(r.right, r.top + handleBottomSize), kSeekRedShadow);
652 AddLine(BPoint(r.right - 1.0, r.top + handleBottomSize + 1.0),
653 BPoint(knobPos, r.top + handleArrowSize), kSeekRedShadow);
654 AddLine(BPoint(knobPos - 1.0, r.top + handleArrowSize - 1.0),
655 BPoint(r.left + 1.0, r.top + handleBottomSize + 1.0), kSeekRedLight);
657 AddLine(BPoint(r.left, r.bottom),
658 BPoint(r.left, r.bottom - handleBottomSize), kSeekRedLight);
659 AddLine(BPoint(r.left + 1.0, r.bottom - handleBottomSize - 1.0),
660 BPoint(knobPos, r.bottom - handleArrowSize), kSeekRedLight);
661 AddLine(BPoint(knobPos + 1.0, r.bottom - handleArrowSize + 1.0),
662 BPoint(r.right, r.bottom - handleBottomSize), kSeekRedShadow);
663 AddLine(BPoint(r.right, r.bottom - handleBottomSize + 1.0),
664 BPoint(r.right, r.bottom), kSeekRedShadow);
665 AddLine(BPoint(r.right - 1.0, r.bottom),
666 BPoint(r.left + 1.0, r.bottom), kSeekRedShadow);
668 // fill rest of handles with red
669 SetHighColor(kSeekRed);
671 handleArrowSize -= 2.0;
673 // upper handle arrow
676 arrow[1].x = r.right;
678 arrow[2].x = knobPos;
679 arrow[2].y = r.top + handleArrowSize;
680 FillPolygon(arrow, 3);
681 // lower handle arrow
683 arrow[0].y = r.bottom;
684 arrow[1].x = r.right;
685 arrow[1].y = r.bottom;
686 arrow[2].x = knobPos;
687 arrow[2].y = r.bottom - handleArrowSize;
688 FillPolygon(arrow, 3);
693 _StrokeFrame(r, darkShadow, darkShadow, darkShadow, darkShadow);
695 _StrokeFrame(r, darkShadow, darkShadow, darkShadow, darkShadow);
697 SetHighColor(darkShadow);
700 float width = floorf(StringWidth(DISABLED_SEEK_MESSAGE));
701 float textPos = r.left + r.Width() / 2.0 - width / 2.0;
702 pattern stripes = {{ 0xc7, 0x8f, 0x1f, 0x3e, 0x7c, 0xf8, 0xf1, 0xe3 }};
703 BRect stripesRect(r);
704 stripesRect.right = textPos - 5.0;
705 FillRect(stripesRect, stripes);
706 stripesRect.left = textPos + width + 3.0;
707 stripesRect.right = r.right;
708 FillRect(stripesRect, stripes);
710 r.left = textPos - 4.0;
711 r.right = textPos + width + 2.0;
713 SetHighColor(shadow);
714 SetLowColor(darkShadow);
717 DrawString(DISABLED_SEEK_MESSAGE, BPoint(textPos, r.top + ceilf(fh.ascent) - 1.0));
721 /*****************************************************************************
722 * SeekSlider::MouseDown
723 *****************************************************************************/
725 SeekSlider::MouseDown(BPoint where)
727 if (IsEnabled() && Bounds().Contains(where))
729 SetValue(_ValueFor(where.x));
731 SetMouseEventMask(B_POINTER_EVENTS, B_LOCK_WINDOW_FOCUS);
735 /*****************************************************************************
736 * SeekSlider::MouseMoved
737 *****************************************************************************/
739 SeekSlider::MouseMoved(BPoint where, uint32 code, const BMessage* dragMessage)
743 SetValue(_ValueFor(where.x));
747 /*****************************************************************************
748 * SeekSlider::MouseUp
749 *****************************************************************************/
751 SeekSlider::MouseUp(BPoint where)
756 input_thread_t * p_input;
757 p_input = (input_thread_t *)
758 vlc_object_find( p_intf, VLC_OBJECT_INPUT, FIND_ANYWHERE );
762 var_SetFloat( p_input, "position",
763 (float) Value() / SEEKSLIDER_RANGE );
764 vlc_object_release( p_input );
769 /*****************************************************************************
770 * SeekSlider::ResizeToPreferred
771 *****************************************************************************/
773 SeekSlider::ResizeToPreferred()
775 float width = 15.0 + StringWidth(DISABLED_SEEK_MESSAGE) + 15.0;
776 ResizeTo(width, 17.0);
779 /*****************************************************************************
780 * SeekSlider::SetPosition
781 *****************************************************************************/
783 SeekSlider::SetPosition(float position)
789 SetValue( SEEKSLIDER_RANGE * position );
795 /*****************************************************************************
796 * SeekSlider::_ValueFor
797 *****************************************************************************/
799 SeekSlider::_ValueFor(float xPos) const
802 float knobWidth2 = SEEK_SLIDER_KNOB_WIDTH / 2.0;
803 float sliderStart = (r.left + knobWidth2);
804 float sliderEnd = (r.right - knobWidth2);
805 int32 value = (int32)(((xPos - sliderStart) * SEEKSLIDER_RANGE)
806 / (sliderEnd - sliderStart - 1.0));
809 if (value > SEEKSLIDER_RANGE)
810 value = SEEKSLIDER_RANGE;
814 /*****************************************************************************
815 * SeekSlider::_StrokeFrame
816 *****************************************************************************/
818 SeekSlider::_StrokeFrame(BRect r, rgb_color left, rgb_color top,
819 rgb_color right, rgb_color bottom)
822 AddLine(BPoint(r.left, r.bottom), BPoint(r.left, r.top), left);
823 AddLine(BPoint(r.left + 1.0, r.top), BPoint(r.right, r.top), top);
824 AddLine(BPoint(r.right, r.top + 1.0), BPoint(r.right, r.bottom), right);
825 AddLine(BPoint(r.right - 1.0, r.bottom), BPoint(r.left + 1.0, r.bottom), bottom);
829 /*****************************************************************************
831 *****************************************************************************/
832 VolumeSlider::VolumeSlider(BRect frame, const char* name, int32 minValue, int32 maxValue,
833 BMessage* message, BHandler* target)
834 : BControl(frame, name, NULL, message, B_FOLLOW_NONE,
835 B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE),
837 fRightSideBits(NULL),
847 BRect r(BPoint(0.0, 0.0), kVolumeSliderBitmapSize);
848 fLeftSideBits = new BBitmap(r, B_CMAP8);
849 fRightSideBits = new BBitmap(r, B_CMAP8);
850 r.Set(0.0, 0.0, kVolumeSliderKnobBitmapSize.x, kVolumeSliderKnobBitmapSize.y);
851 fKnobBits = new BBitmap(r, B_CMAP8);
856 /*****************************************************************************
857 * VolumeSlider destructor
858 *****************************************************************************/
859 VolumeSlider::~VolumeSlider()
861 delete fLeftSideBits;
862 delete fRightSideBits;
866 /*****************************************************************************
867 * VolumeSlider::AttachedToWindow
868 *****************************************************************************/
870 VolumeSlider::AttachedToWindow()
872 BControl::AttachedToWindow();
873 SetViewColor(B_TRANSPARENT_32_BIT);
876 /*****************************************************************************
877 * VolumeSlider::SetValue
878 *****************************************************************************/
880 VolumeSlider::SetValue(int32 value)
882 if (value != Value())
884 BControl::SetValue(value);
889 /*****************************************************************************
890 * VolumeSlider::SetEnabled
891 *****************************************************************************/
893 VolumeSlider::SetEnabled(bool enable)
895 if (enable != IsEnabled())
897 BControl::SetEnabled(enable);
903 /*****************************************************************************
905 *****************************************************************************/
907 VolumeSlider::Draw(BRect updateRect)
912 float sliderSideWidth = kVolumeSliderBitmapWidth;
913 float sliderStart = (r.left + sliderSideWidth);
914 float sliderEnd = (r.right - sliderSideWidth);
915 float knobPos = sliderStart
916 + (sliderEnd - sliderStart - 1.0) * (Value() - fMinValue)
917 / (fMaxValue - fMinValue);
918 // draw both sides (the original from Be doesn't seem
919 // to make a difference for enabled/disabled state)
920 DrawBitmapAsync(fLeftSideBits, r.LeftTop());
921 DrawBitmapAsync(fRightSideBits, BPoint(sliderEnd + 1.0, r.top));
922 // colors for the slider area between the two bitmaps
923 rgb_color background = kBackground;//ui_color(B_PANEL_BACKGROUND_COLOR);
924 rgb_color shadow = tint_color(background, B_DARKEN_2_TINT);
925 rgb_color softShadow = tint_color(background, B_DARKEN_1_TINT);
926 rgb_color darkShadow = tint_color(background, B_DARKEN_4_TINT);
927 rgb_color midShadow = tint_color(background, B_DARKEN_3_TINT);
928 rgb_color light = tint_color(background, B_LIGHTEN_MAX_TINT);
929 rgb_color softLight = tint_color(background, B_LIGHTEN_1_TINT);
930 rgb_color green = kGreen;
931 rgb_color greenShadow = kGreenShadow;
932 rgb_color black = kBlack;
933 rgb_color dotGrey = midShadow;
934 rgb_color dotGreen = greenShadow;
935 // make dimmed version of colors if we're disabled
938 shadow = (rgb_color){ 200, 200, 200, 255 };
939 softShadow = dimmed_color_cmap8(softShadow, background, DIM_LEVEL);
940 darkShadow = dimmed_color_cmap8(darkShadow, background, DIM_LEVEL);
942 light = dimmed_color_cmap8(light, background, DIM_LEVEL);
943 softLight = dimmed_color_cmap8(softLight, background, DIM_LEVEL);
944 green = dimmed_color_cmap8(green, background, DIM_LEVEL);
945 greenShadow = dimmed_color_cmap8(greenShadow, background, DIM_LEVEL);
946 black = dimmed_color_cmap8(black, background, DIM_LEVEL);
951 green = tint_color(kBackground, B_DARKEN_3_TINT);
952 greenShadow = tint_color(kBackground, B_DARKEN_4_TINT);
953 dotGreen = greenShadow;
955 // draw slider edges between bitmaps
957 AddLine(BPoint(sliderStart, r.top),
958 BPoint(sliderEnd, r.top), softShadow);
959 AddLine(BPoint(sliderStart, r.bottom),
960 BPoint(sliderEnd, r.bottom), softLight);
962 AddLine(BPoint(sliderStart, r.top),
963 BPoint(sliderEnd, r.top), black);
964 AddLine(BPoint(sliderStart, r.bottom),
965 BPoint(sliderEnd, r.bottom), light);
967 AddLine(BPoint(sliderStart, r.top),
968 BPoint(knobPos, r.top), greenShadow);
969 AddLine(BPoint(knobPos, r.top),
970 BPoint(sliderEnd, r.top), midShadow);
972 AddLine(BPoint(sliderStart, r.top),
973 BPoint(knobPos, r.top), greenShadow);
975 // fill rest inside of slider
977 r.left = sliderStart;
980 FillRect(r, B_SOLID_HIGH);
981 r.left = knobPos + 1.0;
984 SetHighColor(shadow);
985 FillRect(r, B_SOLID_HIGH);
986 // draw little dots inside
987 int32 dotCount = (int32)((sliderEnd - sliderStart) / 5.0);
989 dotPos.y = r.top + 4.0;
990 for (int32 i = 0; i < dotCount; i++)
992 dotPos.x = sliderStart + i * 5.0 + 4.0;
993 SetHighColor(dotPos.x < knobPos ? dotGreen : dotGrey);
994 StrokeLine(dotPos, BPoint(dotPos.x, dotPos.y + 1.0));
998 SetDrawingMode(B_OP_OVER); // part of knob is transparent
999 DrawBitmapAsync(fKnobBits, BPoint(knobPos - kVolumeSliderKnobWidth / 2, r.top));
1003 /*****************************************************************************
1004 * VolumeSlider::MouseDown
1005 *****************************************************************************/
1007 VolumeSlider::MouseDown(BPoint where)
1009 if (Bounds().Contains(where) && IsEnabled())
1012 SetValue(_ValueFor(where.x));
1013 SetMouseEventMask(B_POINTER_EVENTS, B_LOCK_WINDOW_FOCUS);
1017 /*****************************************************************************
1018 * VolumeSlider::MouseMoved
1019 *****************************************************************************/
1021 VolumeSlider::MouseMoved(BPoint where, uint32 transit, const BMessage* dragMessage)
1024 SetValue(_ValueFor(where.x));
1027 /*****************************************************************************
1028 * VolumeSlider::MouseUp
1029 *****************************************************************************/
1031 VolumeSlider::MouseUp(BPoint where)
1037 /*****************************************************************************
1038 * VolumeSlider::IsValid
1039 *****************************************************************************/
1041 VolumeSlider::IsValid() const
1043 return (fLeftSideBits && fLeftSideBits->IsValid()
1044 && fRightSideBits && fRightSideBits->IsValid()
1045 && fKnobBits && fKnobBits->IsValid());
1048 /*****************************************************************************
1049 * VolumeSlider::SetMuted
1050 *****************************************************************************/
1052 VolumeSlider::SetMuted(bool mute)
1062 /*****************************************************************************
1063 * VolumeSlider::_MakeBitmaps
1064 *****************************************************************************/
1066 VolumeSlider::_MakeBitmaps()
1070 // left side of slider
1071 memcpy(fLeftSideBits->Bits(), kVolumeSliderLeftBitmapBits,
1072 fLeftSideBits->BitsLength());
1073 // right side of slider
1074 memcpy(fRightSideBits->Bits(), kVolumeSliderRightBits,
1075 fRightSideBits->BitsLength());
1077 int32 length = fKnobBits->BitsLength();
1078 memcpy(fKnobBits->Bits(), kVolumeSliderKnobBits, length);
1079 uint8* bits = (uint8*)fKnobBits->Bits();
1080 // black was used in the knob to represent transparency
1081 // use screen to get index for the "transarent" color used in the bitmap
1082 BScreen screen(B_MAIN_SCREEN_ID);
1083 uint8 blackIndex = screen.IndexForColor(kBlack);
1084 // replace black index with transparent index
1085 for (int32 i = 0; i < length; i++)
1086 if (bits[i] == blackIndex)
1087 bits[i] = B_TRANSPARENT_MAGIC_CMAP8;
1091 // make ghosted versions of the bitmaps
1092 dim_bitmap(fLeftSideBits, kBackground, DIM_LEVEL);
1093 dim_bitmap(fRightSideBits, kBackground, DIM_LEVEL);
1094 dim_bitmap(fKnobBits, kBackground, DIM_LEVEL);
1098 // replace green color (and shadow) in left slider side
1099 bits = (uint8*)fLeftSideBits->Bits();
1100 length = fLeftSideBits->BitsLength();
1101 uint8 greenIndex = screen.IndexForColor(kGreen);
1102 uint8 greenShadowIndex = screen.IndexForColor(kGreenShadow);
1103 rgb_color shadow = tint_color(kBackground, B_DARKEN_3_TINT);
1104 rgb_color midShadow = tint_color(kBackground, B_DARKEN_4_TINT);
1105 uint8 replaceIndex = screen.IndexForColor(shadow);
1106 uint8 replaceShadowIndex = screen.IndexForColor(midShadow);
1107 for (int32 i = 0; i < length; i++)
1109 if (bits[i] == greenIndex)
1110 bits[i] = replaceIndex;
1111 else if (bits[i] == greenShadowIndex)
1112 bits[i] = replaceShadowIndex;
1118 /*****************************************************************************
1119 * VolumeSlider::_ValueFor
1120 *****************************************************************************/
1122 VolumeSlider::_ValueFor(float xPos) const
1125 float sliderStart = (r.left + kVolumeSliderBitmapWidth);
1126 float sliderEnd = (r.right - kVolumeSliderBitmapWidth);
1127 int32 value = fMinValue + (int32)(((xPos - sliderStart) * (fMaxValue - fMinValue))
1128 / (sliderEnd - sliderStart - 1.0));
1129 if (value < fMinValue)
1131 if (value > fMaxValue)
1136 /*****************************************************************************
1137 * PositionInfoView::PositionInfoView
1138 *****************************************************************************/
1139 PositionInfoView::PositionInfoView( BRect frame, const char* name,
1140 intf_thread_t * p_interface )
1141 : BView( frame, name, B_FOLLOW_NONE,
1142 B_WILL_DRAW | B_PULSE_NEEDED | B_FULL_UPDATE_ON_RESIZE ),
1143 fMode( MODE_SMALL ),
1144 fCurrentFileIndex( -1 ),
1145 fCurrentFileSize( -1 ),
1146 fCurrentTitleIndex( -1 ),
1147 fCurrentTitleSize( -1 ),
1148 fCurrentChapterIndex( -1 ),
1149 fCurrentChapterSize( -1 ),
1151 fTimeString( "-:--:--" ),
1152 fLastPulseUpdate( system_time() ),
1153 fStackedWidthCache( 0.0 ),
1154 fStackedHeightCache( 0.0 )
1156 p_intf = p_interface;
1158 SetViewColor( B_TRANSPARENT_32_BIT );
1159 SetLowColor( kBlack );
1160 SetHighColor( 0, 255, 0, 255 );
1161 SetFontSize( 11.0 );
1164 /*****************************************************************************
1165 * PositionInfoView::~PositionInfoView
1166 *****************************************************************************/
1167 PositionInfoView::~PositionInfoView()
1171 /*****************************************************************************
1172 * PositionInfoView::Draw
1173 *****************************************************************************/
1175 PositionInfoView::Draw( BRect updateRect )
1177 rgb_color background = ui_color( B_PANEL_BACKGROUND_COLOR );
1178 rgb_color shadow = tint_color( background, B_DARKEN_1_TINT );
1179 rgb_color darkShadow = tint_color( background, B_DARKEN_4_TINT );
1180 rgb_color light = tint_color( background, B_LIGHTEN_MAX_TINT );
1181 rgb_color softLight = tint_color( background, B_LIGHTEN_1_TINT );
1183 BRect r( Bounds() );
1184 BeginLineArray( 8 );
1185 AddLine( BPoint( r.left, r.bottom ),
1186 BPoint( r.left, r.top ), shadow );
1187 AddLine( BPoint( r.left + 1.0, r.top ),
1188 BPoint( r.right, r.top ), shadow );
1189 AddLine( BPoint( r.right, r.top + 1.0 ),
1190 BPoint( r.right, r.bottom ), softLight );
1191 AddLine( BPoint( r.right - 1.0, r.bottom ),
1192 BPoint( r.left + 1.0, r.bottom ), softLight );
1193 r.InsetBy( 1.0, 1.0 );
1194 AddLine( BPoint( r.left, r.bottom ),
1195 BPoint( r.left, r.top ), darkShadow );
1196 AddLine( BPoint( r.left + 1.0, r.top ),
1197 BPoint( r.right, r.top ), darkShadow );
1198 AddLine( BPoint( r.right, r.top + 1.0 ),
1199 BPoint( r.right, r.bottom ), light );
1200 AddLine( BPoint( r.right - 1.0, r.bottom ),
1201 BPoint( r.left + 1.0, r.bottom ), light );
1204 r.InsetBy( 1.0, 1.0 );
1205 FillRect( r, B_SOLID_LOW );
1208 GetFontHeight( &fh );
1213 float width = StringWidth( fTimeString.String() );
1214 DrawString( fTimeString.String(),
1215 BPoint( r.left + r.Width() / 2.0 - width / 2.0,
1216 r.top + r.Height() / 2.0 + fh.ascent / 2.0 - 1.0 ) );
1223 BFont smallFont = font;
1224 BFont bigFont = font;
1225 BFont tinyFont = font;
1226 smallFont.SetSize( r.Height() / 5.0 );
1227 bigFont.SetSize( r.Height() / 3.0 );
1228 tinyFont.SetSize( r.Height() / 7.0 );
1229 float timeHeight = r.Height() / 2.5;
1230 float height = ( r.Height() - timeHeight ) / 3.0;
1231 SetFont( &tinyFont );
1232 SetHighColor( 0, 180, 0, 255 );
1233 DrawString( _("File"), BPoint( r.left + 3.0, r.top + height ) );
1234 DrawString( _("Title"), BPoint( r.left + 3.0, r.top + 2.0 * height ) );
1235 DrawString( _("Chapter"), BPoint( r.left + 3.0, r.top + 3.0 * height ) );
1236 SetFont( &smallFont );
1238 SetHighColor( 0, 255, 0, 255 );
1240 _MakeString( helper, fCurrentFileIndex, fCurrentFileSize );
1241 float width = StringWidth( helper.String() );
1242 DrawString( helper.String(), BPoint( r.right - 3.0 - width, r.top + height ) );
1244 _MakeString( helper, fCurrentTitleIndex, fCurrentTitleSize );
1245 width = StringWidth( helper.String() );
1246 DrawString( helper.String(), BPoint( r.right - 3.0 - width, r.top + 2.0 * height ) );
1248 _MakeString( helper, fCurrentChapterIndex, fCurrentChapterSize );
1249 width = StringWidth( helper.String() );
1250 DrawString( helper.String(), BPoint( r.right - 3.0 - width, r.top + 3.0 * height ) );
1252 SetFont( &bigFont );
1253 width = StringWidth( fTimeString.String() );
1254 DrawString( fTimeString.String(),
1255 BPoint( r.left + r.Width() / 2.0 - width / 2.0,
1262 /*****************************************************************************
1263 * PositionInfoView::ResizeToPreferred
1264 *****************************************************************************/
1266 PositionInfoView::ResizeToPreferred()
1268 float width, height;
1269 GetPreferredSize( &width, &height );
1270 ResizeTo( width, height );
1273 /*****************************************************************************
1274 * PositionInfoView::GetPreferredSize
1275 *****************************************************************************/
1277 PositionInfoView::GetPreferredSize( float* width, float* height )
1279 if ( width && height )
1281 *width = 5.0 + ceilf( StringWidth( "0:00:00" ) ) + 5.0;
1283 GetFontHeight( &fh );
1284 *height = 3.0 + ceilf( fh.ascent ) + 3.0;
1285 fStackedWidthCache = *width * 1.2;
1286 fStackedHeightCache = *height * 2.7;
1290 /*****************************************************************************
1291 * PositionInfoView::Pulse
1292 *****************************************************************************/
1294 PositionInfoView::Pulse()
1296 // allow for Pulse frequency to be higher, MediaControlView needs it
1297 bigtime_t now = system_time();
1298 if ( now - fLastPulseUpdate > 900000 )
1302 p_intf->p_sys->p_wrapper->GetPlaylistInfo( index, size );
1303 SetFile( index + 1, size );
1304 p_intf->p_sys->p_wrapper->TitleInfo( index, size );
1305 SetTitle( index, size );
1306 p_intf->p_sys->p_wrapper->ChapterInfo( index, size );
1307 SetChapter( index, size );
1308 SetTime( p_intf->p_sys->p_wrapper->GetTimeAsString() );
1309 fLastPulseUpdate = now;
1314 /*****************************************************************************
1315 * PositionInfoView::GetBigPreferredSize
1316 *****************************************************************************/
1318 PositionInfoView::GetBigPreferredSize( float* width, float* height )
1320 if ( width && height )
1322 *width = fStackedWidthCache;
1323 *height = fStackedHeightCache;
1327 /*****************************************************************************
1328 * PositionInfoView::SetMode
1329 *****************************************************************************/
1331 PositionInfoView::SetMode( uint32 mode )
1333 if ( fMode != mode )
1336 _InvalidateContents();
1340 /*****************************************************************************
1341 * PositionInfoView::SetFile
1342 *****************************************************************************/
1344 PositionInfoView::SetFile( int32 index, int32 size )
1346 if ( fCurrentFileIndex != index || fCurrentFileSize != size )
1348 fCurrentFileIndex = index;
1349 fCurrentFileSize = size;
1350 _InvalidateContents();
1354 /*****************************************************************************
1355 * PositionInfoView::SetTitle
1356 *****************************************************************************/
1358 PositionInfoView::SetTitle( int32 index, int32 size )
1360 if ( fCurrentTitleIndex != index || fCurrentFileSize != size )
1362 fCurrentTitleIndex = index;
1363 fCurrentTitleSize = size;
1364 _InvalidateContents();
1368 /*****************************************************************************
1369 * PositionInfoView::SetChapter
1370 *****************************************************************************/
1372 PositionInfoView::SetChapter( int32 index, int32 size )
1374 if ( fCurrentChapterIndex != index || fCurrentFileSize != size )
1376 fCurrentChapterIndex = index;
1377 fCurrentChapterSize = size;
1378 _InvalidateContents();
1382 /*****************************************************************************
1383 * PositionInfoView::SetTime
1384 *****************************************************************************/
1386 PositionInfoView::SetTime( int32 seconds )
1388 if ( fSeconds != seconds )
1392 int32 minutes = seconds / 60;
1393 int32 hours = minutes / 60;
1394 seconds -= minutes * 60 - hours * 60 * 60;
1395 minutes -= hours * 60;
1396 fTimeString.SetTo( "" );
1397 fTimeString << hours << ":" << minutes << ":" << seconds;
1400 fTimeString.SetTo( "-:--:--" );
1403 _InvalidateContents();
1407 /*****************************************************************************
1408 * PositionInfoView::SetTime
1409 *****************************************************************************/
1411 PositionInfoView::SetTime( const char* string )
1413 fTimeString.SetTo( string );
1414 _InvalidateContents();
1417 /*****************************************************************************
1418 * PositionInfoView::_InvalidateContents
1419 *****************************************************************************/
1421 PositionInfoView::_InvalidateContents( uint32 which )
1423 BRect r( Bounds() );
1424 r.InsetBy( 2.0, 2.0 );
1428 /*****************************************************************************
1429 * PositionInfoView::_InvalidateContents
1430 *****************************************************************************/
1432 PositionInfoView::_MakeString( BString& into, int32 index, int32 maxIndex ) const
1435 if ( index >= 0 && maxIndex >= 0 )
1440 if ( maxIndex >= 0 )