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>
34 #include <vlc/input.h>
37 #include <audio_output.h>
40 /* BeOS interface headers */
42 #include "DrawingTidbits.h"
43 #include "InterfaceWindow.h"
45 #include "TransportButton.h"
46 #include "ListViews.h"
47 #include "MediaControlView.h"
49 #define BORDER_INSET 6.0
51 #define SPEAKER_SLIDER_DIST 6.0
52 #define VOLUME_MIN_WIDTH 70.0
54 #define VOLUME_SLIDER_LAYOUT_WEIGHT 2.0
55 #define SEEK_SLIDER_KNOB_WIDTH 8.0
57 // slider colors are hardcoded here, because that's just
58 // what they currently are within those bitmaps
59 const rgb_color kGreen = (rgb_color){ 152, 203, 152, 255 };
60 const rgb_color kGreenShadow = (rgb_color){ 102, 152, 102, 255 };
61 const rgb_color kBackground = (rgb_color){ 216, 216, 216, 255 };
62 const rgb_color kSeekGreen = (rgb_color){ 171, 221, 161, 255 };
63 const rgb_color kSeekGreenShadow = (rgb_color){ 144, 186, 136, 255 };
64 const rgb_color kSeekRed = (rgb_color){ 255, 0, 0, 255 };
65 const rgb_color kSeekRedLight = (rgb_color){ 255, 152, 152, 255 };
66 const rgb_color kSeekRedShadow = (rgb_color){ 178, 0, 0, 255 };
68 #define DISABLED_SEEK_MESSAGE _("Drop files to play")
69 #define SEEKSLIDER_RANGE 2048
75 MSG_SKIP_BACKWARDS = 'skpb',
76 MSG_SKIP_FORWARD = 'skpf',
80 MediaControlView::MediaControlView( intf_thread_t * _p_intf, BRect frame)
81 : BBox(frame, NULL, B_FOLLOW_NONE, B_WILL_DRAW | B_FRAME_EVENTS | B_PULSE_NEEDED,
84 fCurrentRate(INPUT_RATE_DEFAULT),
86 fBottomControlHeight(0.0),
89 BRect frame(0.0, 0.0, 10.0, 10.0);
92 fSeekSlider = new SeekSlider( p_intf, frame, "seek slider", this );
93 fSeekSlider->SetValue(0);
94 fSeekSlider->ResizeToPreferred();
95 AddChild( fSeekSlider );
99 frame.SetRightBottom(kSkipButtonSize);
100 fBottomControlHeight = kRewindBitmapHeight - 1.0;
101 fSkipBack = new TransportButton(frame, B_EMPTY_STRING,
103 kPressedSkipBackBitmapBits,
104 kDisabledSkipBackBitmapBits,
105 new BMessage(MSG_SKIP_BACKWARDS));
106 AddChild( fSkipBack );
109 frame.SetRightBottom(kPlayButtonSize);
110 if (fBottomControlHeight < kPlayPauseBitmapHeight - 1.0)
111 fBottomControlHeight = kPlayPauseBitmapHeight - 1.0;
112 fPlayPause = new PlayPauseButton(frame, B_EMPTY_STRING,
113 kPlayButtonBitmapBits,
114 kPressedPlayButtonBitmapBits,
115 kDisabledPlayButtonBitmapBits,
116 kPlayingPlayButtonBitmapBits,
117 kPressedPlayingPlayButtonBitmapBits,
118 kPausedPlayButtonBitmapBits,
119 kPressedPausedPlayButtonBitmapBits,
120 new BMessage(START_PLAYBACK));
122 AddChild( fPlayPause );
125 frame.SetRightBottom(kSkipButtonSize);
126 fSkipForward = new TransportButton(frame, B_EMPTY_STRING,
127 kSkipForwardBitmapBits,
128 kPressedSkipForwardBitmapBits,
129 kDisabledSkipForwardBitmapBits,
130 new BMessage(MSG_SKIP_FORWARD));
131 AddChild( fSkipForward );
134 fForward = new TransportButton(frame, B_EMPTY_STRING,
136 kPressedForwardBitmapBits,
137 kDisabledForwardBitmapBits,
138 new BMessage(MSG_FORWARD));
139 // AddChild( fForward );
142 fRewind = new TransportButton(frame, B_EMPTY_STRING,
144 kPressedRewindBitmapBits,
145 kDisabledRewindBitmapBits,
146 new BMessage(MSG_REWIND));
147 // AddChild( fRewind );
150 frame.SetRightBottom(kStopButtonSize);
151 if (fBottomControlHeight < kStopBitmapHeight - 1.0)
152 fBottomControlHeight = kStopBitmapHeight - 1.0;
153 fStop = new TransportButton(frame, B_EMPTY_STRING,
154 kStopButtonBitmapBits,
155 kPressedStopButtonBitmapBits,
156 kDisabledStopButtonBitmapBits,
157 new BMessage(STOP_PLAYBACK));
161 frame.SetRightBottom(kSpeakerButtonSize);
162 if (fBottomControlHeight < kSpeakerIconBitmapHeight - 1.0)
163 fBottomControlHeight = kSpeakerIconBitmapHeight - 1.0;
164 fMute = new TransportButton(frame, B_EMPTY_STRING,
166 kPressedSpeakerIconBits,
168 new BMessage(VOLUME_MUTE));
173 fVolumeSlider = new VolumeSlider(BRect(0.0, 0.0, VOLUME_MIN_WIDTH,
174 kVolumeSliderBitmapHeight - 1.0),
175 "volume slider", 1, AOUT_VOLUME_MAX,
176 new BMessage(VOLUME_CHG));
177 fVolumeSlider->SetValue( config_GetInt( p_intf, "volume" ) );
178 AddChild( fVolumeSlider );
180 // Position Info View
181 fPositionInfo = new PositionInfoView(BRect(0.0, 0.0, 10.0, 10.0), "led",
183 fPositionInfo->ResizeToPreferred();
184 AddChild( fPositionInfo );
188 MediaControlView::~MediaControlView()
194 MediaControlView::AttachedToWindow()
196 // we are now a valid BHandler
197 fRewind->SetTarget(this);
198 fForward->SetTarget(this);
199 fSkipBack->SetTarget(this);
200 fSkipForward->SetTarget(this);
201 fVolumeSlider->SetTarget(Window());
203 BRect r(_MinFrame());
204 if (BMenuBar* menuBar = Window()->KeyMenuBar()) {
206 menuBar->GetPreferredSize(&width, &height);
207 // r.bottom += menuBar->Bounds().Height();
209 // see that our calculated minimal width is not smaller than what
210 // the menubar can be
216 Window()->SetSizeLimits(r.Width(), r.Width() * 1.8, r.Height(), r.Height() * 1.3);
217 if (!Window()->Bounds().Contains(r))
218 Window()->ResizeTo(r.Width(), r.Height());
220 FrameResized(Bounds().Width(), Bounds().Height());
222 // get pulse message every two frames
223 Window()->SetPulseRate(80000);
228 MediaControlView::FrameResized(float width, float height)
231 // make sure we don't leave dirty pixels
232 // (B_FULL_UPDATE_ON_RESIZE == annoying flicker -> this is smarter)
233 if (fOldBounds.Width() < r.Width())
234 Invalidate(BRect(fOldBounds.right, fOldBounds.top + 1.0,
235 fOldBounds.right, fOldBounds.bottom - 1.0));
237 Invalidate(BRect(r.right, r.top + 1.0,
238 r.right, r.bottom - 1.0));
239 if (fOldBounds.Height() < r.Height())
240 Invalidate(BRect(fOldBounds.left + 1.0, fOldBounds.bottom,
241 fOldBounds.right - 1.0, fOldBounds.bottom));
243 Invalidate(BRect(r.left + 1.0, r.bottom,
244 r.right - 1.0, r.bottom));
245 // remember for next time
248 r.InsetBy(BORDER_INSET, BORDER_INSET);
254 MediaControlView::GetPreferredSize(float* width, float* height)
258 BRect r(_MinFrame());
260 *height = r.Height();
266 MediaControlView::MessageReceived(BMessage* message)
268 switch (message->what)
274 case MSG_SKIP_BACKWARDS:
275 Window()->PostMessage(NAVIGATE_PREV);
277 case MSG_SKIP_FORWARD:
278 Window()->PostMessage(NAVIGATE_NEXT);
281 BBox::MessageReceived(message);
288 MediaControlView::Pulse()
290 InterfaceWindow* window = dynamic_cast<InterfaceWindow*>(Window());
291 if (window && window->IsStopped())
292 fPlayPause->SetStopped();
294 unsigned short i_volume;
295 aout_VolumeGet( p_intf, (audio_volume_t*)&i_volume );
296 fVolumeSlider->SetValue( i_volume );
301 MediaControlView::SetProgress( float position )
303 fSeekSlider->SetPosition( position );
308 MediaControlView::SetStatus(int status, int rate)
310 // we need to set the button status periodically
311 // (even if it is the same) to get a blinking button
312 fCurrentStatus = status;
318 fPlayPause->SetPlaying();
321 fPlayPause->SetPaused();
324 fPlayPause->SetStopped();
327 if (rate != fCurrentRate)
330 if ( rate < INPUT_RATE_DEFAULT )
339 MediaControlView::SetEnabled(bool enabled)
341 if( ( enabled && fIsEnabled ) ||
342 ( !enabled && !fIsEnabled ) )
344 /* do not redraw if it is not necessary */
350 fSkipBack->SetEnabled( enabled );
351 fPlayPause->SetEnabled( enabled );
352 fSkipForward->SetEnabled( enabled );
353 fStop->SetEnabled( enabled );
354 fMute->SetEnabled( enabled );
355 fVolumeSlider->SetEnabled( enabled );
356 fSeekSlider->SetEnabled( enabled );
357 fRewind->SetEnabled( enabled );
358 fForward->SetEnabled( enabled );
360 fIsEnabled = enabled;
366 MediaControlView::SetAudioEnabled(bool enabled)
368 fMute->SetEnabled(enabled);
369 fVolumeSlider->SetEnabled(enabled);
374 MediaControlView::GetVolume() const
376 return fVolumeSlider->Value();
381 MediaControlView::SetSkippable(bool backward, bool forward)
383 fSkipBack->SetEnabled(backward);
384 fSkipForward->SetEnabled(forward);
389 MediaControlView::SetMuted(bool mute)
391 fVolumeSlider->SetMuted(mute);
396 MediaControlView::_LayoutControls(BRect frame) const
400 // calculate absolutly minimal width
401 float minWidth = fSkipBack->Bounds().Width();
402 // minWidth += fRewind->Bounds().Width();
403 minWidth += fStop->Bounds().Width();
404 minWidth += fPlayPause->Bounds().Width();
405 // minWidth += fForward->Bounds().Width();
406 minWidth += fSkipForward->Bounds().Width();
407 minWidth += fMute->Bounds().Width();
408 minWidth += VOLUME_MIN_WIDTH;
410 // layout time slider and info view
412 fPositionInfo->GetBigPreferredSize( &width, &height );
413 float ratio = width / height;
414 width = r.Height() * ratio;
415 if (frame.Width() - minWidth - MIN_SPACE >= width
416 && frame.Height() >= height)
418 r.right = r.left + width;
419 fPositionInfo->SetMode(PositionInfoView::MODE_BIG);
420 _LayoutControl(fPositionInfo, r, true, true);
421 frame.left = r.right + MIN_SPACE;
423 r.right = frame.right;
424 // r.bottom = r.top + r.Height() / 2.0 - MIN_SPACE / 2.0;
425 r.bottom = r.top + fSeekSlider->Bounds().Height();
426 _LayoutControl(fSeekSlider, r, true);
430 fPositionInfo->GetPreferredSize( &width, &height );
431 fPositionInfo->SetMode(PositionInfoView::MODE_SMALL);
432 fPositionInfo->ResizeTo(width, height);
433 r.bottom = r.top + r.Height() / 2.0 - MIN_SPACE / 2.0;
434 r.right = r.left + fPositionInfo->Bounds().Width();
435 _LayoutControl(fPositionInfo, r, true );
436 r.left = r.right + MIN_SPACE;
437 r.right = frame.right;
438 _LayoutControl(fSeekSlider, r, true);
440 float currentWidth = frame.Width();
441 float space = (currentWidth - minWidth) / 6.0;//8.0;
443 space = MIN_SPACE + (space - MIN_SPACE) / VOLUME_SLIDER_LAYOUT_WEIGHT;
444 // layout controls with "space" inbetween
446 r.top = r.bottom + MIN_SPACE + 1.0;
447 r.bottom = frame.bottom;
449 r.right = r.left + fSkipBack->Bounds().Width();
450 _LayoutControl(fSkipBack, r);
452 // r.left = r.right + space;
453 // r.right = r.left + fRewind->Bounds().Width();
454 // _LayoutControl(fRewind, r);
456 r.left = r.right + space;
457 r.right = r.left + fStop->Bounds().Width();
458 _LayoutControl(fStop, r);
460 r.left = r.right + space;
461 r.right = r.left + fPlayPause->Bounds().Width();
462 _LayoutControl(fPlayPause, r);
464 // r.left = r.right + space;
465 // r.right = r.left + fForward->Bounds().Width();
466 // _LayoutControl(fForward, r);
468 r.left = r.right + space;
469 r.right = r.left + fSkipForward->Bounds().Width();
470 _LayoutControl(fSkipForward, r);
472 r.left = r.right + space + space;
473 r.right = r.left + fMute->Bounds().Width();
474 _LayoutControl(fMute, r);
476 r.left = r.right + SPEAKER_SLIDER_DIST; // keep speaker icon and volume slider attached
477 r.right = frame.right;
478 _LayoutControl(fVolumeSlider, r, true);
483 MediaControlView::_MinFrame() const
485 // add up width of controls along bottom (seek slider will likely adopt)
486 float minWidth = 2 * BORDER_INSET;
487 minWidth += fSkipBack->Bounds().Width() + MIN_SPACE;
488 // minWidth += fRewind->Bounds().Width() + MIN_SPACE;
489 minWidth += fStop->Bounds().Width() + MIN_SPACE;
490 minWidth += fPlayPause->Bounds().Width() + MIN_SPACE;
491 // minWidth += fForward->Bounds().Width() + MIN_SPACE;
492 minWidth += fSkipForward->Bounds().Width() + MIN_SPACE + MIN_SPACE;
493 minWidth += fMute->Bounds().Width() + SPEAKER_SLIDER_DIST;
494 minWidth += VOLUME_MIN_WIDTH;
496 // add up height of seek slider and heighest control on bottom
497 float minHeight = 2 * BORDER_INSET;
498 minHeight += fSeekSlider->Bounds().Height() + MIN_SPACE + MIN_SPACE / 2.0;
499 minHeight += fBottomControlHeight;
500 return BRect(0.0, 0.0, minWidth - 1.0, minHeight - 1.0);
505 MediaControlView::_LayoutControl(BView* view, BRect frame,
506 bool resizeWidth, bool resizeHeight) const
510 frame.top = (frame.top + frame.bottom) / 2.0 - view->Bounds().Height() / 2.0;
512 //center horizontally
513 frame.left = (frame.left + frame.right) / 2.0 - view->Bounds().Width() / 2.0;
514 view->MoveTo(frame.LeftTop());
515 float width = resizeWidth ? frame.Width() : view->Bounds().Width();
516 float height = resizeHeight ? frame.Height() : view->Bounds().Height();
517 if (resizeWidth || resizeHeight)
518 view->ResizeTo(width, height);
523 /*****************************************************************************
525 *****************************************************************************/
526 SeekSlider::SeekSlider( intf_thread_t * _p_intf,
527 BRect frame, const char* name, MediaControlView *owner )
528 : BControl(frame, name, NULL, NULL, B_FOLLOW_NONE,
529 B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE),
534 BFont font(be_plain_font);
539 SeekSlider::~SeekSlider()
543 /*****************************************************************************
544 * VolumeSlider::AttachedToWindow
545 *****************************************************************************/
547 SeekSlider::AttachedToWindow()
549 BControl::AttachedToWindow();
550 SetViewColor(B_TRANSPARENT_32_BIT);
553 /*****************************************************************************
555 *****************************************************************************/
557 SeekSlider::Draw(BRect updateRect)
560 float knobWidth2 = SEEK_SLIDER_KNOB_WIDTH / 2.0;
561 float sliderStart = (r.left + knobWidth2);
562 float sliderEnd = (r.right - knobWidth2);
563 float knobPos = sliderStart
564 + floorf((sliderEnd - sliderStart - 1.0) * Value()
566 // draw both sides (the original from Be doesn't seem
567 // to make a difference for enabled/disabled state)
568 // DrawBitmapAsync(fLeftSideBits, r.LeftTop());
569 // DrawBitmapAsync(fRightSideBits, BPoint(sliderEnd + 1.0, r.top));
570 // colors for the slider area between the two bitmaps
571 rgb_color background = kBackground;//ui_color(B_PANEL_BACKGROUND_COLOR);
572 rgb_color shadow = tint_color(background, B_DARKEN_2_TINT);
573 rgb_color softShadow = tint_color(background, B_DARKEN_1_TINT);
574 rgb_color darkShadow = tint_color(background, B_DARKEN_4_TINT);
575 rgb_color midShadow = tint_color(background, B_DARKEN_3_TINT);
576 rgb_color light = tint_color(background, B_LIGHTEN_MAX_TINT);
577 rgb_color softLight = tint_color(background, B_LIGHTEN_1_TINT);
578 rgb_color green = kSeekGreen;
579 rgb_color greenShadow = kSeekGreenShadow;
580 rgb_color black = kBlack;
581 rgb_color dotGrey = midShadow;
582 rgb_color dotGreen = greenShadow;
584 _StrokeFrame(r, softShadow, softShadow, softLight, softLight);
586 _StrokeFrame(r, black, black, light, light);
591 _StrokeFrame(r, greenShadow, greenShadow, green, green);
594 _StrokeFrame(r, greenShadow, greenShadow, green, green);
600 int32 dotCount = (int32)(r.Width() / 6.0);
602 dotPos.y = r.top + 2.0;
603 SetHighColor(dotGreen);
604 for (int32 i = 0; i < dotCount; i++)
606 dotPos.x = sliderStart + i * 6.0 + 5.0;
607 StrokeLine(dotPos, BPoint(dotPos.x, dotPos.y + 6.0));
612 r.left = knobPos - knobWidth2;
613 r.right = knobPos + knobWidth2;
615 float handleBottomSize = 2.0;
616 float handleArrowSize = 6.0;
619 AddLine(BPoint(r.left, r.top + handleBottomSize),
620 BPoint(r.left, r.top), black);
621 AddLine(BPoint(r.left + 1.0, r.top),
622 BPoint(r.right, r.top), black);
623 AddLine(BPoint(r.right, r.top + 1.0),
624 BPoint(r.right, r.top + handleBottomSize), black);
625 AddLine(BPoint(r.right - 1.0, r.top + handleBottomSize + 1.0),
626 BPoint(knobPos, r.top + handleArrowSize), black);
627 AddLine(BPoint(knobPos - 1.0, r.top + handleArrowSize - 1.0),
628 BPoint(r.left + 1.0, r.top + handleBottomSize + 1.0), black);
630 AddLine(BPoint(r.left, r.bottom),
631 BPoint(r.left, r.bottom - handleBottomSize), black);
632 AddLine(BPoint(r.left + 1.0, r.bottom - handleBottomSize - 1.0),
633 BPoint(knobPos, r.bottom - handleArrowSize), black);
634 AddLine(BPoint(knobPos + 1.0, r.bottom - handleArrowSize + 1.0),
635 BPoint(r.right, r.bottom - handleBottomSize), black);
636 AddLine(BPoint(r.right, r.bottom - handleBottomSize + 1.0),
637 BPoint(r.right, r.bottom), black);
638 AddLine(BPoint(r.right - 1.0, r.bottom),
639 BPoint(r.left + 1.0, r.bottom), black);
641 // inner red light and shadow lines
644 handleArrowSize -= 2.0;
647 AddLine(BPoint(r.left, r.top + handleBottomSize),
648 BPoint(r.left, r.top), kSeekRedLight);
649 AddLine(BPoint(r.left + 1.0, r.top),
650 BPoint(r.right, r.top), kSeekRedLight);
651 AddLine(BPoint(r.right, r.top + 1.0),
652 BPoint(r.right, r.top + handleBottomSize), kSeekRedShadow);
653 AddLine(BPoint(r.right - 1.0, r.top + handleBottomSize + 1.0),
654 BPoint(knobPos, r.top + handleArrowSize), kSeekRedShadow);
655 AddLine(BPoint(knobPos - 1.0, r.top + handleArrowSize - 1.0),
656 BPoint(r.left + 1.0, r.top + handleBottomSize + 1.0), kSeekRedLight);
658 AddLine(BPoint(r.left, r.bottom),
659 BPoint(r.left, r.bottom - handleBottomSize), kSeekRedLight);
660 AddLine(BPoint(r.left + 1.0, r.bottom - handleBottomSize - 1.0),
661 BPoint(knobPos, r.bottom - handleArrowSize), kSeekRedLight);
662 AddLine(BPoint(knobPos + 1.0, r.bottom - handleArrowSize + 1.0),
663 BPoint(r.right, r.bottom - handleBottomSize), kSeekRedShadow);
664 AddLine(BPoint(r.right, r.bottom - handleBottomSize + 1.0),
665 BPoint(r.right, r.bottom), kSeekRedShadow);
666 AddLine(BPoint(r.right - 1.0, r.bottom),
667 BPoint(r.left + 1.0, r.bottom), kSeekRedShadow);
669 // fill rest of handles with red
670 SetHighColor(kSeekRed);
672 handleArrowSize -= 2.0;
674 // upper handle arrow
677 arrow[1].x = r.right;
679 arrow[2].x = knobPos;
680 arrow[2].y = r.top + handleArrowSize;
681 FillPolygon(arrow, 3);
682 // lower handle arrow
684 arrow[0].y = r.bottom;
685 arrow[1].x = r.right;
686 arrow[1].y = r.bottom;
687 arrow[2].x = knobPos;
688 arrow[2].y = r.bottom - handleArrowSize;
689 FillPolygon(arrow, 3);
694 _StrokeFrame(r, darkShadow, darkShadow, darkShadow, darkShadow);
696 _StrokeFrame(r, darkShadow, darkShadow, darkShadow, darkShadow);
698 SetHighColor(darkShadow);
701 float width = floorf(StringWidth(DISABLED_SEEK_MESSAGE));
702 float textPos = r.left + r.Width() / 2.0 - width / 2.0;
703 pattern stripes = {{ 0xc7, 0x8f, 0x1f, 0x3e, 0x7c, 0xf8, 0xf1, 0xe3 }};
704 BRect stripesRect(r);
705 stripesRect.right = textPos - 5.0;
706 FillRect(stripesRect, stripes);
707 stripesRect.left = textPos + width + 3.0;
708 stripesRect.right = r.right;
709 FillRect(stripesRect, stripes);
711 r.left = textPos - 4.0;
712 r.right = textPos + width + 2.0;
714 SetHighColor(shadow);
715 SetLowColor(darkShadow);
718 DrawString(DISABLED_SEEK_MESSAGE, BPoint(textPos, r.top + ceilf(fh.ascent) - 1.0));
722 /*****************************************************************************
723 * SeekSlider::MouseDown
724 *****************************************************************************/
726 SeekSlider::MouseDown(BPoint where)
728 if (IsEnabled() && Bounds().Contains(where))
730 SetValue(_ValueFor(where.x));
732 SetMouseEventMask(B_POINTER_EVENTS, B_LOCK_WINDOW_FOCUS);
736 /*****************************************************************************
737 * SeekSlider::MouseMoved
738 *****************************************************************************/
740 SeekSlider::MouseMoved(BPoint where, uint32 code, const BMessage* dragMessage)
744 SetValue(_ValueFor(where.x));
748 /*****************************************************************************
749 * SeekSlider::MouseUp
750 *****************************************************************************/
752 SeekSlider::MouseUp(BPoint where)
757 input_thread_t * p_input;
758 p_input = (input_thread_t *)
759 vlc_object_find( p_intf, VLC_OBJECT_INPUT, FIND_ANYWHERE );
763 var_SetFloat( p_input, "position",
764 (float) Value() / SEEKSLIDER_RANGE );
765 vlc_object_release( p_input );
770 /*****************************************************************************
771 * SeekSlider::ResizeToPreferred
772 *****************************************************************************/
774 SeekSlider::ResizeToPreferred()
776 float width = 15.0 + StringWidth(DISABLED_SEEK_MESSAGE) + 15.0;
777 ResizeTo(width, 17.0);
780 /*****************************************************************************
781 * SeekSlider::SetPosition
782 *****************************************************************************/
784 SeekSlider::SetPosition(float position)
790 SetValue( SEEKSLIDER_RANGE * position );
796 /*****************************************************************************
797 * SeekSlider::_ValueFor
798 *****************************************************************************/
800 SeekSlider::_ValueFor(float xPos) const
803 float knobWidth2 = SEEK_SLIDER_KNOB_WIDTH / 2.0;
804 float sliderStart = (r.left + knobWidth2);
805 float sliderEnd = (r.right - knobWidth2);
806 int32 value = (int32)(((xPos - sliderStart) * SEEKSLIDER_RANGE)
807 / (sliderEnd - sliderStart - 1.0));
810 if (value > SEEKSLIDER_RANGE)
811 value = SEEKSLIDER_RANGE;
815 /*****************************************************************************
816 * SeekSlider::_StrokeFrame
817 *****************************************************************************/
819 SeekSlider::_StrokeFrame(BRect r, rgb_color left, rgb_color top,
820 rgb_color right, rgb_color bottom)
823 AddLine(BPoint(r.left, r.bottom), BPoint(r.left, r.top), left);
824 AddLine(BPoint(r.left + 1.0, r.top), BPoint(r.right, r.top), top);
825 AddLine(BPoint(r.right, r.top + 1.0), BPoint(r.right, r.bottom), right);
826 AddLine(BPoint(r.right - 1.0, r.bottom), BPoint(r.left + 1.0, r.bottom), bottom);
830 /*****************************************************************************
832 *****************************************************************************/
833 VolumeSlider::VolumeSlider(BRect frame, const char* name, int32 minValue, int32 maxValue,
834 BMessage* message, BHandler* target)
835 : BControl(frame, name, NULL, message, B_FOLLOW_NONE,
836 B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE),
838 fRightSideBits(NULL),
848 BRect r(BPoint(0.0, 0.0), kVolumeSliderBitmapSize);
849 fLeftSideBits = new BBitmap(r, B_CMAP8);
850 fRightSideBits = new BBitmap(r, B_CMAP8);
851 r.Set(0.0, 0.0, kVolumeSliderKnobBitmapSize.x, kVolumeSliderKnobBitmapSize.y);
852 fKnobBits = new BBitmap(r, B_CMAP8);
857 /*****************************************************************************
858 * VolumeSlider destructor
859 *****************************************************************************/
860 VolumeSlider::~VolumeSlider()
862 delete fLeftSideBits;
863 delete fRightSideBits;
867 /*****************************************************************************
868 * VolumeSlider::AttachedToWindow
869 *****************************************************************************/
871 VolumeSlider::AttachedToWindow()
873 BControl::AttachedToWindow();
874 SetViewColor(B_TRANSPARENT_32_BIT);
877 /*****************************************************************************
878 * VolumeSlider::SetValue
879 *****************************************************************************/
881 VolumeSlider::SetValue(int32 value)
883 if (value != Value())
885 BControl::SetValue(value);
890 /*****************************************************************************
891 * VolumeSlider::SetEnabled
892 *****************************************************************************/
894 VolumeSlider::SetEnabled(bool enable)
896 if (enable != IsEnabled())
898 BControl::SetEnabled(enable);
904 /*****************************************************************************
906 *****************************************************************************/
908 VolumeSlider::Draw(BRect updateRect)
913 float sliderSideWidth = kVolumeSliderBitmapWidth;
914 float sliderStart = (r.left + sliderSideWidth);
915 float sliderEnd = (r.right - sliderSideWidth);
916 float knobPos = sliderStart
917 + (sliderEnd - sliderStart - 1.0) * (Value() - fMinValue)
918 / (fMaxValue - fMinValue);
919 // draw both sides (the original from Be doesn't seem
920 // to make a difference for enabled/disabled state)
921 DrawBitmapAsync(fLeftSideBits, r.LeftTop());
922 DrawBitmapAsync(fRightSideBits, BPoint(sliderEnd + 1.0, r.top));
923 // colors for the slider area between the two bitmaps
924 rgb_color background = kBackground;//ui_color(B_PANEL_BACKGROUND_COLOR);
925 rgb_color shadow = tint_color(background, B_DARKEN_2_TINT);
926 rgb_color softShadow = tint_color(background, B_DARKEN_1_TINT);
927 rgb_color darkShadow = tint_color(background, B_DARKEN_4_TINT);
928 rgb_color midShadow = tint_color(background, B_DARKEN_3_TINT);
929 rgb_color light = tint_color(background, B_LIGHTEN_MAX_TINT);
930 rgb_color softLight = tint_color(background, B_LIGHTEN_1_TINT);
931 rgb_color green = kGreen;
932 rgb_color greenShadow = kGreenShadow;
933 rgb_color black = kBlack;
934 rgb_color dotGrey = midShadow;
935 rgb_color dotGreen = greenShadow;
936 // make dimmed version of colors if we're disabled
939 shadow = (rgb_color){ 200, 200, 200, 255 };
940 softShadow = dimmed_color_cmap8(softShadow, background, DIM_LEVEL);
941 darkShadow = dimmed_color_cmap8(darkShadow, background, DIM_LEVEL);
943 light = dimmed_color_cmap8(light, background, DIM_LEVEL);
944 softLight = dimmed_color_cmap8(softLight, background, DIM_LEVEL);
945 green = dimmed_color_cmap8(green, background, DIM_LEVEL);
946 greenShadow = dimmed_color_cmap8(greenShadow, background, DIM_LEVEL);
947 black = dimmed_color_cmap8(black, background, DIM_LEVEL);
952 green = tint_color(kBackground, B_DARKEN_3_TINT);
953 greenShadow = tint_color(kBackground, B_DARKEN_4_TINT);
954 dotGreen = greenShadow;
956 // draw slider edges between bitmaps
958 AddLine(BPoint(sliderStart, r.top),
959 BPoint(sliderEnd, r.top), softShadow);
960 AddLine(BPoint(sliderStart, r.bottom),
961 BPoint(sliderEnd, r.bottom), softLight);
963 AddLine(BPoint(sliderStart, r.top),
964 BPoint(sliderEnd, r.top), black);
965 AddLine(BPoint(sliderStart, r.bottom),
966 BPoint(sliderEnd, r.bottom), light);
968 AddLine(BPoint(sliderStart, r.top),
969 BPoint(knobPos, r.top), greenShadow);
970 AddLine(BPoint(knobPos, r.top),
971 BPoint(sliderEnd, r.top), midShadow);
973 AddLine(BPoint(sliderStart, r.top),
974 BPoint(knobPos, r.top), greenShadow);
976 // fill rest inside of slider
978 r.left = sliderStart;
981 FillRect(r, B_SOLID_HIGH);
982 r.left = knobPos + 1.0;
985 SetHighColor(shadow);
986 FillRect(r, B_SOLID_HIGH);
987 // draw little dots inside
988 int32 dotCount = (int32)((sliderEnd - sliderStart) / 5.0);
990 dotPos.y = r.top + 4.0;
991 for (int32 i = 0; i < dotCount; i++)
993 dotPos.x = sliderStart + i * 5.0 + 4.0;
994 SetHighColor(dotPos.x < knobPos ? dotGreen : dotGrey);
995 StrokeLine(dotPos, BPoint(dotPos.x, dotPos.y + 1.0));
999 SetDrawingMode(B_OP_OVER); // part of knob is transparent
1000 DrawBitmapAsync(fKnobBits, BPoint(knobPos - kVolumeSliderKnobWidth / 2, r.top));
1004 /*****************************************************************************
1005 * VolumeSlider::MouseDown
1006 *****************************************************************************/
1008 VolumeSlider::MouseDown(BPoint where)
1010 if (Bounds().Contains(where) && IsEnabled())
1013 SetValue(_ValueFor(where.x));
1014 SetMouseEventMask(B_POINTER_EVENTS, B_LOCK_WINDOW_FOCUS);
1018 /*****************************************************************************
1019 * VolumeSlider::MouseMoved
1020 *****************************************************************************/
1022 VolumeSlider::MouseMoved(BPoint where, uint32 transit, const BMessage* dragMessage)
1025 SetValue(_ValueFor(where.x));
1028 /*****************************************************************************
1029 * VolumeSlider::MouseUp
1030 *****************************************************************************/
1032 VolumeSlider::MouseUp(BPoint where)
1038 /*****************************************************************************
1039 * VolumeSlider::IsValid
1040 *****************************************************************************/
1042 VolumeSlider::IsValid() const
1044 return (fLeftSideBits && fLeftSideBits->IsValid()
1045 && fRightSideBits && fRightSideBits->IsValid()
1046 && fKnobBits && fKnobBits->IsValid());
1049 /*****************************************************************************
1050 * VolumeSlider::SetMuted
1051 *****************************************************************************/
1053 VolumeSlider::SetMuted(bool mute)
1063 /*****************************************************************************
1064 * VolumeSlider::_MakeBitmaps
1065 *****************************************************************************/
1067 VolumeSlider::_MakeBitmaps()
1071 // left side of slider
1072 memcpy(fLeftSideBits->Bits(), kVolumeSliderLeftBitmapBits,
1073 fLeftSideBits->BitsLength());
1074 // right side of slider
1075 memcpy(fRightSideBits->Bits(), kVolumeSliderRightBits,
1076 fRightSideBits->BitsLength());
1078 int32 length = fKnobBits->BitsLength();
1079 memcpy(fKnobBits->Bits(), kVolumeSliderKnobBits, length);
1080 uint8* bits = (uint8*)fKnobBits->Bits();
1081 // black was used in the knob to represent transparency
1082 // use screen to get index for the "transarent" color used in the bitmap
1083 BScreen screen(B_MAIN_SCREEN_ID);
1084 uint8 blackIndex = screen.IndexForColor(kBlack);
1085 // replace black index with transparent index
1086 for (int32 i = 0; i < length; i++)
1087 if (bits[i] == blackIndex)
1088 bits[i] = B_TRANSPARENT_MAGIC_CMAP8;
1092 // make ghosted versions of the bitmaps
1093 dim_bitmap(fLeftSideBits, kBackground, DIM_LEVEL);
1094 dim_bitmap(fRightSideBits, kBackground, DIM_LEVEL);
1095 dim_bitmap(fKnobBits, kBackground, DIM_LEVEL);
1099 // replace green color (and shadow) in left slider side
1100 bits = (uint8*)fLeftSideBits->Bits();
1101 length = fLeftSideBits->BitsLength();
1102 uint8 greenIndex = screen.IndexForColor(kGreen);
1103 uint8 greenShadowIndex = screen.IndexForColor(kGreenShadow);
1104 rgb_color shadow = tint_color(kBackground, B_DARKEN_3_TINT);
1105 rgb_color midShadow = tint_color(kBackground, B_DARKEN_4_TINT);
1106 uint8 replaceIndex = screen.IndexForColor(shadow);
1107 uint8 replaceShadowIndex = screen.IndexForColor(midShadow);
1108 for (int32 i = 0; i < length; i++)
1110 if (bits[i] == greenIndex)
1111 bits[i] = replaceIndex;
1112 else if (bits[i] == greenShadowIndex)
1113 bits[i] = replaceShadowIndex;
1119 /*****************************************************************************
1120 * VolumeSlider::_ValueFor
1121 *****************************************************************************/
1123 VolumeSlider::_ValueFor(float xPos) const
1126 float sliderStart = (r.left + kVolumeSliderBitmapWidth);
1127 float sliderEnd = (r.right - kVolumeSliderBitmapWidth);
1128 int32 value = fMinValue + (int32)(((xPos - sliderStart) * (fMaxValue - fMinValue))
1129 / (sliderEnd - sliderStart - 1.0));
1130 if (value < fMinValue)
1132 if (value > fMaxValue)
1137 /*****************************************************************************
1138 * PositionInfoView::PositionInfoView
1139 *****************************************************************************/
1140 PositionInfoView::PositionInfoView( BRect frame, const char* name,
1141 intf_thread_t * p_interface )
1142 : BView( frame, name, B_FOLLOW_NONE,
1143 B_WILL_DRAW | B_PULSE_NEEDED | B_FULL_UPDATE_ON_RESIZE ),
1144 fMode( MODE_SMALL ),
1145 fCurrentFileIndex( -1 ),
1146 fCurrentFileSize( -1 ),
1147 fCurrentTitleIndex( -1 ),
1148 fCurrentTitleSize( -1 ),
1149 fCurrentChapterIndex( -1 ),
1150 fCurrentChapterSize( -1 ),
1152 fTimeString( "-:--:--" ),
1153 fLastPulseUpdate( system_time() ),
1154 fStackedWidthCache( 0.0 ),
1155 fStackedHeightCache( 0.0 )
1157 p_intf = p_interface;
1159 SetViewColor( B_TRANSPARENT_32_BIT );
1160 SetLowColor( kBlack );
1161 SetHighColor( 0, 255, 0, 255 );
1162 SetFontSize( 11.0 );
1165 /*****************************************************************************
1166 * PositionInfoView::~PositionInfoView
1167 *****************************************************************************/
1168 PositionInfoView::~PositionInfoView()
1172 /*****************************************************************************
1173 * PositionInfoView::Draw
1174 *****************************************************************************/
1176 PositionInfoView::Draw( BRect updateRect )
1178 rgb_color background = ui_color( B_PANEL_BACKGROUND_COLOR );
1179 rgb_color shadow = tint_color( background, B_DARKEN_1_TINT );
1180 rgb_color darkShadow = tint_color( background, B_DARKEN_4_TINT );
1181 rgb_color light = tint_color( background, B_LIGHTEN_MAX_TINT );
1182 rgb_color softLight = tint_color( background, B_LIGHTEN_1_TINT );
1184 BRect r( Bounds() );
1185 BeginLineArray( 8 );
1186 AddLine( BPoint( r.left, r.bottom ),
1187 BPoint( r.left, r.top ), shadow );
1188 AddLine( BPoint( r.left + 1.0, r.top ),
1189 BPoint( r.right, r.top ), shadow );
1190 AddLine( BPoint( r.right, r.top + 1.0 ),
1191 BPoint( r.right, r.bottom ), softLight );
1192 AddLine( BPoint( r.right - 1.0, r.bottom ),
1193 BPoint( r.left + 1.0, r.bottom ), softLight );
1194 r.InsetBy( 1.0, 1.0 );
1195 AddLine( BPoint( r.left, r.bottom ),
1196 BPoint( r.left, r.top ), darkShadow );
1197 AddLine( BPoint( r.left + 1.0, r.top ),
1198 BPoint( r.right, r.top ), darkShadow );
1199 AddLine( BPoint( r.right, r.top + 1.0 ),
1200 BPoint( r.right, r.bottom ), light );
1201 AddLine( BPoint( r.right - 1.0, r.bottom ),
1202 BPoint( r.left + 1.0, r.bottom ), light );
1205 r.InsetBy( 1.0, 1.0 );
1206 FillRect( r, B_SOLID_LOW );
1209 GetFontHeight( &fh );
1214 float width = StringWidth( fTimeString.String() );
1215 DrawString( fTimeString.String(),
1216 BPoint( r.left + r.Width() / 2.0 - width / 2.0,
1217 r.top + r.Height() / 2.0 + fh.ascent / 2.0 - 1.0 ) );
1224 BFont smallFont = font;
1225 BFont bigFont = font;
1226 BFont tinyFont = font;
1227 smallFont.SetSize( r.Height() / 5.0 );
1228 bigFont.SetSize( r.Height() / 3.0 );
1229 tinyFont.SetSize( r.Height() / 7.0 );
1230 float timeHeight = r.Height() / 2.5;
1231 float height = ( r.Height() - timeHeight ) / 3.0;
1232 SetFont( &tinyFont );
1233 SetHighColor( 0, 180, 0, 255 );
1234 DrawString( _("File"), BPoint( r.left + 3.0, r.top + height ) );
1235 DrawString( _("Title"), BPoint( r.left + 3.0, r.top + 2.0 * height ) );
1236 DrawString( _("Chapter"), BPoint( r.left + 3.0, r.top + 3.0 * height ) );
1237 SetFont( &smallFont );
1239 SetHighColor( 0, 255, 0, 255 );
1241 _MakeString( helper, fCurrentFileIndex, fCurrentFileSize );
1242 float width = StringWidth( helper.String() );
1243 DrawString( helper.String(), BPoint( r.right - 3.0 - width, r.top + height ) );
1245 _MakeString( helper, fCurrentTitleIndex, fCurrentTitleSize );
1246 width = StringWidth( helper.String() );
1247 DrawString( helper.String(), BPoint( r.right - 3.0 - width, r.top + 2.0 * height ) );
1249 _MakeString( helper, fCurrentChapterIndex, fCurrentChapterSize );
1250 width = StringWidth( helper.String() );
1251 DrawString( helper.String(), BPoint( r.right - 3.0 - width, r.top + 3.0 * height ) );
1253 SetFont( &bigFont );
1254 width = StringWidth( fTimeString.String() );
1255 DrawString( fTimeString.String(),
1256 BPoint( r.left + r.Width() / 2.0 - width / 2.0,
1263 /*****************************************************************************
1264 * PositionInfoView::ResizeToPreferred
1265 *****************************************************************************/
1267 PositionInfoView::ResizeToPreferred()
1269 float width, height;
1270 GetPreferredSize( &width, &height );
1271 ResizeTo( width, height );
1274 /*****************************************************************************
1275 * PositionInfoView::GetPreferredSize
1276 *****************************************************************************/
1278 PositionInfoView::GetPreferredSize( float* width, float* height )
1280 if ( width && height )
1282 *width = 5.0 + ceilf( StringWidth( "0:00:00" ) ) + 5.0;
1284 GetFontHeight( &fh );
1285 *height = 3.0 + ceilf( fh.ascent ) + 3.0;
1286 fStackedWidthCache = *width * 1.2;
1287 fStackedHeightCache = *height * 2.7;
1291 /*****************************************************************************
1292 * PositionInfoView::Pulse
1293 *****************************************************************************/
1295 PositionInfoView::Pulse()
1297 // allow for Pulse frequency to be higher, MediaControlView needs it
1298 bigtime_t now = system_time();
1299 if ( now - fLastPulseUpdate > 900000 )
1303 p_intf->p_sys->p_wrapper->GetPlaylistInfo( index, size );
1304 SetFile( index + 1, size );
1305 p_intf->p_sys->p_wrapper->TitleInfo( index, size );
1306 SetTitle( index, size );
1307 p_intf->p_sys->p_wrapper->ChapterInfo( index, size );
1308 SetChapter( index, size );
1309 SetTime( p_intf->p_sys->p_wrapper->GetTimeAsString() );
1310 fLastPulseUpdate = now;
1315 /*****************************************************************************
1316 * PositionInfoView::GetBigPreferredSize
1317 *****************************************************************************/
1319 PositionInfoView::GetBigPreferredSize( float* width, float* height )
1321 if ( width && height )
1323 *width = fStackedWidthCache;
1324 *height = fStackedHeightCache;
1328 /*****************************************************************************
1329 * PositionInfoView::SetMode
1330 *****************************************************************************/
1332 PositionInfoView::SetMode( uint32 mode )
1334 if ( fMode != mode )
1337 _InvalidateContents();
1341 /*****************************************************************************
1342 * PositionInfoView::SetFile
1343 *****************************************************************************/
1345 PositionInfoView::SetFile( int32 index, int32 size )
1347 if ( fCurrentFileIndex != index || fCurrentFileSize != size )
1349 fCurrentFileIndex = index;
1350 fCurrentFileSize = size;
1351 _InvalidateContents();
1355 /*****************************************************************************
1356 * PositionInfoView::SetTitle
1357 *****************************************************************************/
1359 PositionInfoView::SetTitle( int32 index, int32 size )
1361 if ( fCurrentTitleIndex != index || fCurrentFileSize != size )
1363 fCurrentTitleIndex = index;
1364 fCurrentTitleSize = size;
1365 _InvalidateContents();
1369 /*****************************************************************************
1370 * PositionInfoView::SetChapter
1371 *****************************************************************************/
1373 PositionInfoView::SetChapter( int32 index, int32 size )
1375 if ( fCurrentChapterIndex != index || fCurrentFileSize != size )
1377 fCurrentChapterIndex = index;
1378 fCurrentChapterSize = size;
1379 _InvalidateContents();
1383 /*****************************************************************************
1384 * PositionInfoView::SetTime
1385 *****************************************************************************/
1387 PositionInfoView::SetTime( int32 seconds )
1389 if ( fSeconds != seconds )
1393 int32 minutes = seconds / 60;
1394 int32 hours = minutes / 60;
1395 seconds -= minutes * 60 - hours * 60 * 60;
1396 minutes -= hours * 60;
1397 fTimeString.SetTo( "" );
1398 fTimeString << hours << ":" << minutes << ":" << seconds;
1401 fTimeString.SetTo( "-:--:--" );
1404 _InvalidateContents();
1408 /*****************************************************************************
1409 * PositionInfoView::SetTime
1410 *****************************************************************************/
1412 PositionInfoView::SetTime( const char* string )
1414 fTimeString.SetTo( string );
1415 _InvalidateContents();
1418 /*****************************************************************************
1419 * PositionInfoView::_InvalidateContents
1420 *****************************************************************************/
1422 PositionInfoView::_InvalidateContents( uint32 which )
1424 BRect r( Bounds() );
1425 r.InsetBy( 2.0, 2.0 );
1429 /*****************************************************************************
1430 * PositionInfoView::_InvalidateContents
1431 *****************************************************************************/
1433 PositionInfoView::_MakeString( BString& into, int32 index, int32 maxIndex ) const
1436 if ( index >= 0 && maxIndex >= 0 )
1441 if ( maxIndex >= 0 )