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;
320 fPlayPause->SetPlaying();
323 fPlayPause->SetPaused();
326 fPlayPause->SetStopped();
329 if (rate != fCurrentRate)
332 if ( rate < INPUT_RATE_DEFAULT )
341 MediaControlView::SetEnabled(bool enabled)
343 if( ( enabled && fIsEnabled ) ||
344 ( !enabled && !fIsEnabled ) )
346 /* do not redraw if it is not necessary */
352 fSkipBack->SetEnabled( enabled );
353 fPlayPause->SetEnabled( enabled );
354 fSkipForward->SetEnabled( enabled );
355 fStop->SetEnabled( enabled );
356 fMute->SetEnabled( enabled );
357 fVolumeSlider->SetEnabled( enabled );
358 fSeekSlider->SetEnabled( enabled );
359 fRewind->SetEnabled( enabled );
360 fForward->SetEnabled( enabled );
362 fIsEnabled = enabled;
368 MediaControlView::SetAudioEnabled(bool enabled)
370 fMute->SetEnabled(enabled);
371 fVolumeSlider->SetEnabled(enabled);
376 MediaControlView::GetVolume() const
378 return fVolumeSlider->Value();
383 MediaControlView::SetSkippable(bool backward, bool forward)
385 fSkipBack->SetEnabled(backward);
386 fSkipForward->SetEnabled(forward);
391 MediaControlView::SetMuted(bool mute)
393 fVolumeSlider->SetMuted(mute);
398 MediaControlView::_LayoutControls(BRect frame) const
402 // calculate absolutly minimal width
403 float minWidth = fSkipBack->Bounds().Width();
404 // minWidth += fRewind->Bounds().Width();
405 minWidth += fStop->Bounds().Width();
406 minWidth += fPlayPause->Bounds().Width();
407 // minWidth += fForward->Bounds().Width();
408 minWidth += fSkipForward->Bounds().Width();
409 minWidth += fMute->Bounds().Width();
410 minWidth += VOLUME_MIN_WIDTH;
412 // layout time slider and info view
414 fPositionInfo->GetBigPreferredSize( &width, &height );
415 float ratio = width / height;
416 width = r.Height() * ratio;
417 if (frame.Width() - minWidth - MIN_SPACE >= width
418 && frame.Height() >= height)
420 r.right = r.left + width;
421 fPositionInfo->SetMode(PositionInfoView::MODE_BIG);
422 _LayoutControl(fPositionInfo, r, true, true);
423 frame.left = r.right + MIN_SPACE;
425 r.right = frame.right;
426 // r.bottom = r.top + r.Height() / 2.0 - MIN_SPACE / 2.0;
427 r.bottom = r.top + fSeekSlider->Bounds().Height();
428 _LayoutControl(fSeekSlider, r, true);
432 fPositionInfo->GetPreferredSize( &width, &height );
433 fPositionInfo->SetMode(PositionInfoView::MODE_SMALL);
434 fPositionInfo->ResizeTo(width, height);
435 r.bottom = r.top + r.Height() / 2.0 - MIN_SPACE / 2.0;
436 r.right = r.left + fPositionInfo->Bounds().Width();
437 _LayoutControl(fPositionInfo, r, true );
438 r.left = r.right + MIN_SPACE;
439 r.right = frame.right;
440 _LayoutControl(fSeekSlider, r, true);
442 float currentWidth = frame.Width();
443 float space = (currentWidth - minWidth) / 6.0;//8.0;
445 space = MIN_SPACE + (space - MIN_SPACE) / VOLUME_SLIDER_LAYOUT_WEIGHT;
446 // layout controls with "space" inbetween
448 r.top = r.bottom + MIN_SPACE + 1.0;
449 r.bottom = frame.bottom;
451 r.right = r.left + fSkipBack->Bounds().Width();
452 _LayoutControl(fSkipBack, r);
454 // r.left = r.right + space;
455 // r.right = r.left + fRewind->Bounds().Width();
456 // _LayoutControl(fRewind, r);
458 r.left = r.right + space;
459 r.right = r.left + fStop->Bounds().Width();
460 _LayoutControl(fStop, r);
462 r.left = r.right + space;
463 r.right = r.left + fPlayPause->Bounds().Width();
464 _LayoutControl(fPlayPause, r);
466 // r.left = r.right + space;
467 // r.right = r.left + fForward->Bounds().Width();
468 // _LayoutControl(fForward, r);
470 r.left = r.right + space;
471 r.right = r.left + fSkipForward->Bounds().Width();
472 _LayoutControl(fSkipForward, r);
474 r.left = r.right + space + space;
475 r.right = r.left + fMute->Bounds().Width();
476 _LayoutControl(fMute, r);
478 r.left = r.right + SPEAKER_SLIDER_DIST; // keep speaker icon and volume slider attached
479 r.right = frame.right;
480 _LayoutControl(fVolumeSlider, r, true);
485 MediaControlView::_MinFrame() const
487 // add up width of controls along bottom (seek slider will likely adopt)
488 float minWidth = 2 * BORDER_INSET;
489 minWidth += fSkipBack->Bounds().Width() + MIN_SPACE;
490 // minWidth += fRewind->Bounds().Width() + MIN_SPACE;
491 minWidth += fStop->Bounds().Width() + MIN_SPACE;
492 minWidth += fPlayPause->Bounds().Width() + MIN_SPACE;
493 // minWidth += fForward->Bounds().Width() + MIN_SPACE;
494 minWidth += fSkipForward->Bounds().Width() + MIN_SPACE + MIN_SPACE;
495 minWidth += fMute->Bounds().Width() + SPEAKER_SLIDER_DIST;
496 minWidth += VOLUME_MIN_WIDTH;
498 // add up height of seek slider and heighest control on bottom
499 float minHeight = 2 * BORDER_INSET;
500 minHeight += fSeekSlider->Bounds().Height() + MIN_SPACE + MIN_SPACE / 2.0;
501 minHeight += fBottomControlHeight;
502 return BRect(0.0, 0.0, minWidth - 1.0, minHeight - 1.0);
507 MediaControlView::_LayoutControl(BView* view, BRect frame,
508 bool resizeWidth, bool resizeHeight) const
512 frame.top = (frame.top + frame.bottom) / 2.0 - view->Bounds().Height() / 2.0;
514 //center horizontally
515 frame.left = (frame.left + frame.right) / 2.0 - view->Bounds().Width() / 2.0;
516 view->MoveTo(frame.LeftTop());
517 float width = resizeWidth ? frame.Width() : view->Bounds().Width();
518 float height = resizeHeight ? frame.Height() : view->Bounds().Height();
519 if (resizeWidth || resizeHeight)
520 view->ResizeTo(width, height);
525 /*****************************************************************************
527 *****************************************************************************/
528 SeekSlider::SeekSlider( intf_thread_t * _p_intf,
529 BRect frame, const char* name, MediaControlView *owner )
530 : BControl(frame, name, NULL, NULL, B_FOLLOW_NONE,
531 B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE),
536 BFont font(be_plain_font);
541 SeekSlider::~SeekSlider()
545 /*****************************************************************************
546 * VolumeSlider::AttachedToWindow
547 *****************************************************************************/
549 SeekSlider::AttachedToWindow()
551 BControl::AttachedToWindow();
552 SetViewColor(B_TRANSPARENT_32_BIT);
555 /*****************************************************************************
557 *****************************************************************************/
559 SeekSlider::Draw(BRect updateRect)
562 float knobWidth2 = SEEK_SLIDER_KNOB_WIDTH / 2.0;
563 float sliderStart = (r.left + knobWidth2);
564 float sliderEnd = (r.right - knobWidth2);
565 float knobPos = sliderStart
566 + floorf((sliderEnd - sliderStart - 1.0) * Value()
568 // draw both sides (the original from Be doesn't seem
569 // to make a difference for enabled/disabled state)
570 // DrawBitmapAsync(fLeftSideBits, r.LeftTop());
571 // DrawBitmapAsync(fRightSideBits, BPoint(sliderEnd + 1.0, r.top));
572 // colors for the slider area between the two bitmaps
573 rgb_color background = kBackground;//ui_color(B_PANEL_BACKGROUND_COLOR);
574 rgb_color shadow = tint_color(background, B_DARKEN_2_TINT);
575 rgb_color softShadow = tint_color(background, B_DARKEN_1_TINT);
576 rgb_color darkShadow = tint_color(background, B_DARKEN_4_TINT);
577 rgb_color midShadow = tint_color(background, B_DARKEN_3_TINT);
578 rgb_color light = tint_color(background, B_LIGHTEN_MAX_TINT);
579 rgb_color softLight = tint_color(background, B_LIGHTEN_1_TINT);
580 rgb_color green = kSeekGreen;
581 rgb_color greenShadow = kSeekGreenShadow;
582 rgb_color black = kBlack;
583 rgb_color dotGrey = midShadow;
584 rgb_color dotGreen = greenShadow;
586 _StrokeFrame(r, softShadow, softShadow, softLight, softLight);
588 _StrokeFrame(r, black, black, light, light);
593 _StrokeFrame(r, greenShadow, greenShadow, green, green);
596 _StrokeFrame(r, greenShadow, greenShadow, green, green);
602 int32 dotCount = (int32)(r.Width() / 6.0);
604 dotPos.y = r.top + 2.0;
605 SetHighColor(dotGreen);
606 for (int32 i = 0; i < dotCount; i++)
608 dotPos.x = sliderStart + i * 6.0 + 5.0;
609 StrokeLine(dotPos, BPoint(dotPos.x, dotPos.y + 6.0));
614 r.left = knobPos - knobWidth2;
615 r.right = knobPos + knobWidth2;
617 float handleBottomSize = 2.0;
618 float handleArrowSize = 6.0;
621 AddLine(BPoint(r.left, r.top + handleBottomSize),
622 BPoint(r.left, r.top), black);
623 AddLine(BPoint(r.left + 1.0, r.top),
624 BPoint(r.right, r.top), black);
625 AddLine(BPoint(r.right, r.top + 1.0),
626 BPoint(r.right, r.top + handleBottomSize), black);
627 AddLine(BPoint(r.right - 1.0, r.top + handleBottomSize + 1.0),
628 BPoint(knobPos, r.top + handleArrowSize), black);
629 AddLine(BPoint(knobPos - 1.0, r.top + handleArrowSize - 1.0),
630 BPoint(r.left + 1.0, r.top + handleBottomSize + 1.0), black);
632 AddLine(BPoint(r.left, r.bottom),
633 BPoint(r.left, r.bottom - handleBottomSize), black);
634 AddLine(BPoint(r.left + 1.0, r.bottom - handleBottomSize - 1.0),
635 BPoint(knobPos, r.bottom - handleArrowSize), black);
636 AddLine(BPoint(knobPos + 1.0, r.bottom - handleArrowSize + 1.0),
637 BPoint(r.right, r.bottom - handleBottomSize), black);
638 AddLine(BPoint(r.right, r.bottom - handleBottomSize + 1.0),
639 BPoint(r.right, r.bottom), black);
640 AddLine(BPoint(r.right - 1.0, r.bottom),
641 BPoint(r.left + 1.0, r.bottom), black);
643 // inner red light and shadow lines
646 handleArrowSize -= 2.0;
649 AddLine(BPoint(r.left, r.top + handleBottomSize),
650 BPoint(r.left, r.top), kSeekRedLight);
651 AddLine(BPoint(r.left + 1.0, r.top),
652 BPoint(r.right, r.top), kSeekRedLight);
653 AddLine(BPoint(r.right, r.top + 1.0),
654 BPoint(r.right, r.top + handleBottomSize), kSeekRedShadow);
655 AddLine(BPoint(r.right - 1.0, r.top + handleBottomSize + 1.0),
656 BPoint(knobPos, r.top + handleArrowSize), kSeekRedShadow);
657 AddLine(BPoint(knobPos - 1.0, r.top + handleArrowSize - 1.0),
658 BPoint(r.left + 1.0, r.top + handleBottomSize + 1.0), kSeekRedLight);
660 AddLine(BPoint(r.left, r.bottom),
661 BPoint(r.left, r.bottom - handleBottomSize), kSeekRedLight);
662 AddLine(BPoint(r.left + 1.0, r.bottom - handleBottomSize - 1.0),
663 BPoint(knobPos, r.bottom - handleArrowSize), kSeekRedLight);
664 AddLine(BPoint(knobPos + 1.0, r.bottom - handleArrowSize + 1.0),
665 BPoint(r.right, r.bottom - handleBottomSize), kSeekRedShadow);
666 AddLine(BPoint(r.right, r.bottom - handleBottomSize + 1.0),
667 BPoint(r.right, r.bottom), kSeekRedShadow);
668 AddLine(BPoint(r.right - 1.0, r.bottom),
669 BPoint(r.left + 1.0, r.bottom), kSeekRedShadow);
671 // fill rest of handles with red
672 SetHighColor(kSeekRed);
674 handleArrowSize -= 2.0;
676 // upper handle arrow
679 arrow[1].x = r.right;
681 arrow[2].x = knobPos;
682 arrow[2].y = r.top + handleArrowSize;
683 FillPolygon(arrow, 3);
684 // lower handle arrow
686 arrow[0].y = r.bottom;
687 arrow[1].x = r.right;
688 arrow[1].y = r.bottom;
689 arrow[2].x = knobPos;
690 arrow[2].y = r.bottom - handleArrowSize;
691 FillPolygon(arrow, 3);
696 _StrokeFrame(r, darkShadow, darkShadow, darkShadow, darkShadow);
698 _StrokeFrame(r, darkShadow, darkShadow, darkShadow, darkShadow);
700 SetHighColor(darkShadow);
703 float width = floorf(StringWidth(DISABLED_SEEK_MESSAGE));
704 float textPos = r.left + r.Width() / 2.0 - width / 2.0;
705 pattern stripes = {{ 0xc7, 0x8f, 0x1f, 0x3e, 0x7c, 0xf8, 0xf1, 0xe3 }};
706 BRect stripesRect(r);
707 stripesRect.right = textPos - 5.0;
708 FillRect(stripesRect, stripes);
709 stripesRect.left = textPos + width + 3.0;
710 stripesRect.right = r.right;
711 FillRect(stripesRect, stripes);
713 r.left = textPos - 4.0;
714 r.right = textPos + width + 2.0;
716 SetHighColor(shadow);
717 SetLowColor(darkShadow);
720 DrawString(DISABLED_SEEK_MESSAGE, BPoint(textPos, r.top + ceilf(fh.ascent) - 1.0));
724 /*****************************************************************************
725 * SeekSlider::MouseDown
726 *****************************************************************************/
728 SeekSlider::MouseDown(BPoint where)
730 if (IsEnabled() && Bounds().Contains(where))
732 SetValue(_ValueFor(where.x));
734 SetMouseEventMask(B_POINTER_EVENTS, B_LOCK_WINDOW_FOCUS);
738 /*****************************************************************************
739 * SeekSlider::MouseMoved
740 *****************************************************************************/
742 SeekSlider::MouseMoved(BPoint where, uint32 code, const BMessage* dragMessage)
746 SetValue(_ValueFor(where.x));
750 /*****************************************************************************
751 * SeekSlider::MouseUp
752 *****************************************************************************/
754 SeekSlider::MouseUp(BPoint where)
759 input_thread_t * p_input;
760 p_input = (input_thread_t *)
761 vlc_object_find( p_intf, VLC_OBJECT_INPUT, FIND_ANYWHERE );
765 var_SetFloat( p_input, "position",
766 (float) Value() / SEEKSLIDER_RANGE );
767 vlc_object_release( p_input );
772 /*****************************************************************************
773 * SeekSlider::ResizeToPreferred
774 *****************************************************************************/
776 SeekSlider::ResizeToPreferred()
778 float width = 15.0 + StringWidth(DISABLED_SEEK_MESSAGE) + 15.0;
779 ResizeTo(width, 17.0);
782 /*****************************************************************************
783 * SeekSlider::SetPosition
784 *****************************************************************************/
786 SeekSlider::SetPosition(float position)
792 SetValue( SEEKSLIDER_RANGE * position );
798 /*****************************************************************************
799 * SeekSlider::_ValueFor
800 *****************************************************************************/
802 SeekSlider::_ValueFor(float xPos) const
805 float knobWidth2 = SEEK_SLIDER_KNOB_WIDTH / 2.0;
806 float sliderStart = (r.left + knobWidth2);
807 float sliderEnd = (r.right - knobWidth2);
808 int32 value = (int32)(((xPos - sliderStart) * SEEKSLIDER_RANGE)
809 / (sliderEnd - sliderStart - 1.0));
812 if (value > SEEKSLIDER_RANGE)
813 value = SEEKSLIDER_RANGE;
817 /*****************************************************************************
818 * SeekSlider::_StrokeFrame
819 *****************************************************************************/
821 SeekSlider::_StrokeFrame(BRect r, rgb_color left, rgb_color top,
822 rgb_color right, rgb_color bottom)
825 AddLine(BPoint(r.left, r.bottom), BPoint(r.left, r.top), left);
826 AddLine(BPoint(r.left + 1.0, r.top), BPoint(r.right, r.top), top);
827 AddLine(BPoint(r.right, r.top + 1.0), BPoint(r.right, r.bottom), right);
828 AddLine(BPoint(r.right - 1.0, r.bottom), BPoint(r.left + 1.0, r.bottom), bottom);
832 /*****************************************************************************
834 *****************************************************************************/
835 VolumeSlider::VolumeSlider(BRect frame, const char* name, int32 minValue, int32 maxValue,
836 BMessage* message, BHandler* target)
837 : BControl(frame, name, NULL, message, B_FOLLOW_NONE,
838 B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE),
840 fRightSideBits(NULL),
850 BRect r(BPoint(0.0, 0.0), kVolumeSliderBitmapSize);
851 fLeftSideBits = new BBitmap(r, B_CMAP8);
852 fRightSideBits = new BBitmap(r, B_CMAP8);
853 r.Set(0.0, 0.0, kVolumeSliderKnobBitmapSize.x, kVolumeSliderKnobBitmapSize.y);
854 fKnobBits = new BBitmap(r, B_CMAP8);
859 /*****************************************************************************
860 * VolumeSlider destructor
861 *****************************************************************************/
862 VolumeSlider::~VolumeSlider()
864 delete fLeftSideBits;
865 delete fRightSideBits;
869 /*****************************************************************************
870 * VolumeSlider::AttachedToWindow
871 *****************************************************************************/
873 VolumeSlider::AttachedToWindow()
875 BControl::AttachedToWindow();
876 SetViewColor(B_TRANSPARENT_32_BIT);
879 /*****************************************************************************
880 * VolumeSlider::SetValue
881 *****************************************************************************/
883 VolumeSlider::SetValue(int32 value)
885 if (value != Value())
887 BControl::SetValue(value);
892 /*****************************************************************************
893 * VolumeSlider::SetEnabled
894 *****************************************************************************/
896 VolumeSlider::SetEnabled(bool enable)
898 if (enable != IsEnabled())
900 BControl::SetEnabled(enable);
906 /*****************************************************************************
908 *****************************************************************************/
910 VolumeSlider::Draw(BRect updateRect)
915 float sliderSideWidth = kVolumeSliderBitmapWidth;
916 float sliderStart = (r.left + sliderSideWidth);
917 float sliderEnd = (r.right - sliderSideWidth);
918 float knobPos = sliderStart
919 + (sliderEnd - sliderStart - 1.0) * (Value() - fMinValue)
920 / (fMaxValue - fMinValue);
921 // draw both sides (the original from Be doesn't seem
922 // to make a difference for enabled/disabled state)
923 DrawBitmapAsync(fLeftSideBits, r.LeftTop());
924 DrawBitmapAsync(fRightSideBits, BPoint(sliderEnd + 1.0, r.top));
925 // colors for the slider area between the two bitmaps
926 rgb_color background = kBackground;//ui_color(B_PANEL_BACKGROUND_COLOR);
927 rgb_color shadow = tint_color(background, B_DARKEN_2_TINT);
928 rgb_color softShadow = tint_color(background, B_DARKEN_1_TINT);
929 rgb_color darkShadow = tint_color(background, B_DARKEN_4_TINT);
930 rgb_color midShadow = tint_color(background, B_DARKEN_3_TINT);
931 rgb_color light = tint_color(background, B_LIGHTEN_MAX_TINT);
932 rgb_color softLight = tint_color(background, B_LIGHTEN_1_TINT);
933 rgb_color green = kGreen;
934 rgb_color greenShadow = kGreenShadow;
935 rgb_color black = kBlack;
936 rgb_color dotGrey = midShadow;
937 rgb_color dotGreen = greenShadow;
938 // make dimmed version of colors if we're disabled
941 shadow = (rgb_color){ 200, 200, 200, 255 };
942 softShadow = dimmed_color_cmap8(softShadow, background, DIM_LEVEL);
943 darkShadow = dimmed_color_cmap8(darkShadow, background, DIM_LEVEL);
945 light = dimmed_color_cmap8(light, background, DIM_LEVEL);
946 softLight = dimmed_color_cmap8(softLight, background, DIM_LEVEL);
947 green = dimmed_color_cmap8(green, background, DIM_LEVEL);
948 greenShadow = dimmed_color_cmap8(greenShadow, background, DIM_LEVEL);
949 black = dimmed_color_cmap8(black, background, DIM_LEVEL);
954 green = tint_color(kBackground, B_DARKEN_3_TINT);
955 greenShadow = tint_color(kBackground, B_DARKEN_4_TINT);
956 dotGreen = greenShadow;
958 // draw slider edges between bitmaps
960 AddLine(BPoint(sliderStart, r.top),
961 BPoint(sliderEnd, r.top), softShadow);
962 AddLine(BPoint(sliderStart, r.bottom),
963 BPoint(sliderEnd, r.bottom), softLight);
965 AddLine(BPoint(sliderStart, r.top),
966 BPoint(sliderEnd, r.top), black);
967 AddLine(BPoint(sliderStart, r.bottom),
968 BPoint(sliderEnd, r.bottom), light);
970 AddLine(BPoint(sliderStart, r.top),
971 BPoint(knobPos, r.top), greenShadow);
972 AddLine(BPoint(knobPos, r.top),
973 BPoint(sliderEnd, r.top), midShadow);
975 AddLine(BPoint(sliderStart, r.top),
976 BPoint(knobPos, r.top), greenShadow);
978 // fill rest inside of slider
980 r.left = sliderStart;
983 FillRect(r, B_SOLID_HIGH);
984 r.left = knobPos + 1.0;
987 SetHighColor(shadow);
988 FillRect(r, B_SOLID_HIGH);
989 // draw little dots inside
990 int32 dotCount = (int32)((sliderEnd - sliderStart) / 5.0);
992 dotPos.y = r.top + 4.0;
993 for (int32 i = 0; i < dotCount; i++)
995 dotPos.x = sliderStart + i * 5.0 + 4.0;
996 SetHighColor(dotPos.x < knobPos ? dotGreen : dotGrey);
997 StrokeLine(dotPos, BPoint(dotPos.x, dotPos.y + 1.0));
1001 SetDrawingMode(B_OP_OVER); // part of knob is transparent
1002 DrawBitmapAsync(fKnobBits, BPoint(knobPos - kVolumeSliderKnobWidth / 2, r.top));
1006 /*****************************************************************************
1007 * VolumeSlider::MouseDown
1008 *****************************************************************************/
1010 VolumeSlider::MouseDown(BPoint where)
1012 if (Bounds().Contains(where) && IsEnabled())
1015 SetValue(_ValueFor(where.x));
1016 SetMouseEventMask(B_POINTER_EVENTS, B_LOCK_WINDOW_FOCUS);
1020 /*****************************************************************************
1021 * VolumeSlider::MouseMoved
1022 *****************************************************************************/
1024 VolumeSlider::MouseMoved(BPoint where, uint32 transit, const BMessage* dragMessage)
1027 SetValue(_ValueFor(where.x));
1030 /*****************************************************************************
1031 * VolumeSlider::MouseUp
1032 *****************************************************************************/
1034 VolumeSlider::MouseUp(BPoint where)
1040 /*****************************************************************************
1041 * VolumeSlider::IsValid
1042 *****************************************************************************/
1044 VolumeSlider::IsValid() const
1046 return (fLeftSideBits && fLeftSideBits->IsValid()
1047 && fRightSideBits && fRightSideBits->IsValid()
1048 && fKnobBits && fKnobBits->IsValid());
1051 /*****************************************************************************
1052 * VolumeSlider::SetMuted
1053 *****************************************************************************/
1055 VolumeSlider::SetMuted(bool mute)
1065 /*****************************************************************************
1066 * VolumeSlider::_MakeBitmaps
1067 *****************************************************************************/
1069 VolumeSlider::_MakeBitmaps()
1073 // left side of slider
1074 memcpy(fLeftSideBits->Bits(), kVolumeSliderLeftBitmapBits,
1075 fLeftSideBits->BitsLength());
1076 // right side of slider
1077 memcpy(fRightSideBits->Bits(), kVolumeSliderRightBits,
1078 fRightSideBits->BitsLength());
1080 int32 length = fKnobBits->BitsLength();
1081 memcpy(fKnobBits->Bits(), kVolumeSliderKnobBits, length);
1082 uint8* bits = (uint8*)fKnobBits->Bits();
1083 // black was used in the knob to represent transparency
1084 // use screen to get index for the "transarent" color used in the bitmap
1085 BScreen screen(B_MAIN_SCREEN_ID);
1086 uint8 blackIndex = screen.IndexForColor(kBlack);
1087 // replace black index with transparent index
1088 for (int32 i = 0; i < length; i++)
1089 if (bits[i] == blackIndex)
1090 bits[i] = B_TRANSPARENT_MAGIC_CMAP8;
1094 // make ghosted versions of the bitmaps
1095 dim_bitmap(fLeftSideBits, kBackground, DIM_LEVEL);
1096 dim_bitmap(fRightSideBits, kBackground, DIM_LEVEL);
1097 dim_bitmap(fKnobBits, kBackground, DIM_LEVEL);
1101 // replace green color (and shadow) in left slider side
1102 bits = (uint8*)fLeftSideBits->Bits();
1103 length = fLeftSideBits->BitsLength();
1104 uint8 greenIndex = screen.IndexForColor(kGreen);
1105 uint8 greenShadowIndex = screen.IndexForColor(kGreenShadow);
1106 rgb_color shadow = tint_color(kBackground, B_DARKEN_3_TINT);
1107 rgb_color midShadow = tint_color(kBackground, B_DARKEN_4_TINT);
1108 uint8 replaceIndex = screen.IndexForColor(shadow);
1109 uint8 replaceShadowIndex = screen.IndexForColor(midShadow);
1110 for (int32 i = 0; i < length; i++)
1112 if (bits[i] == greenIndex)
1113 bits[i] = replaceIndex;
1114 else if (bits[i] == greenShadowIndex)
1115 bits[i] = replaceShadowIndex;
1121 /*****************************************************************************
1122 * VolumeSlider::_ValueFor
1123 *****************************************************************************/
1125 VolumeSlider::_ValueFor(float xPos) const
1128 float sliderStart = (r.left + kVolumeSliderBitmapWidth);
1129 float sliderEnd = (r.right - kVolumeSliderBitmapWidth);
1130 int32 value = fMinValue + (int32)(((xPos - sliderStart) * (fMaxValue - fMinValue))
1131 / (sliderEnd - sliderStart - 1.0));
1132 if (value < fMinValue)
1134 if (value > fMaxValue)
1139 /*****************************************************************************
1140 * PositionInfoView::PositionInfoView
1141 *****************************************************************************/
1142 PositionInfoView::PositionInfoView( BRect frame, const char* name,
1143 intf_thread_t * p_interface )
1144 : BView( frame, name, B_FOLLOW_NONE,
1145 B_WILL_DRAW | B_PULSE_NEEDED | B_FULL_UPDATE_ON_RESIZE ),
1146 fMode( MODE_SMALL ),
1147 fCurrentFileIndex( -1 ),
1148 fCurrentFileSize( -1 ),
1149 fCurrentTitleIndex( -1 ),
1150 fCurrentTitleSize( -1 ),
1151 fCurrentChapterIndex( -1 ),
1152 fCurrentChapterSize( -1 ),
1154 fTimeString( "-:--:--" ),
1155 fLastPulseUpdate( system_time() ),
1156 fStackedWidthCache( 0.0 ),
1157 fStackedHeightCache( 0.0 )
1159 p_intf = p_interface;
1161 SetViewColor( B_TRANSPARENT_32_BIT );
1162 SetLowColor( kBlack );
1163 SetHighColor( 0, 255, 0, 255 );
1164 SetFontSize( 11.0 );
1167 /*****************************************************************************
1168 * PositionInfoView::~PositionInfoView
1169 *****************************************************************************/
1170 PositionInfoView::~PositionInfoView()
1174 /*****************************************************************************
1175 * PositionInfoView::Draw
1176 *****************************************************************************/
1178 PositionInfoView::Draw( BRect updateRect )
1180 rgb_color background = ui_color( B_PANEL_BACKGROUND_COLOR );
1181 rgb_color shadow = tint_color( background, B_DARKEN_1_TINT );
1182 rgb_color darkShadow = tint_color( background, B_DARKEN_4_TINT );
1183 rgb_color light = tint_color( background, B_LIGHTEN_MAX_TINT );
1184 rgb_color softLight = tint_color( background, B_LIGHTEN_1_TINT );
1186 BRect r( Bounds() );
1187 BeginLineArray( 8 );
1188 AddLine( BPoint( r.left, r.bottom ),
1189 BPoint( r.left, r.top ), shadow );
1190 AddLine( BPoint( r.left + 1.0, r.top ),
1191 BPoint( r.right, r.top ), shadow );
1192 AddLine( BPoint( r.right, r.top + 1.0 ),
1193 BPoint( r.right, r.bottom ), softLight );
1194 AddLine( BPoint( r.right - 1.0, r.bottom ),
1195 BPoint( r.left + 1.0, r.bottom ), softLight );
1196 r.InsetBy( 1.0, 1.0 );
1197 AddLine( BPoint( r.left, r.bottom ),
1198 BPoint( r.left, r.top ), darkShadow );
1199 AddLine( BPoint( r.left + 1.0, r.top ),
1200 BPoint( r.right, r.top ), darkShadow );
1201 AddLine( BPoint( r.right, r.top + 1.0 ),
1202 BPoint( r.right, r.bottom ), light );
1203 AddLine( BPoint( r.right - 1.0, r.bottom ),
1204 BPoint( r.left + 1.0, r.bottom ), light );
1207 r.InsetBy( 1.0, 1.0 );
1208 FillRect( r, B_SOLID_LOW );
1211 GetFontHeight( &fh );
1216 float width = StringWidth( fTimeString.String() );
1217 DrawString( fTimeString.String(),
1218 BPoint( r.left + r.Width() / 2.0 - width / 2.0,
1219 r.top + r.Height() / 2.0 + fh.ascent / 2.0 - 1.0 ) );
1226 BFont smallFont = font;
1227 BFont bigFont = font;
1228 BFont tinyFont = font;
1229 smallFont.SetSize( r.Height() / 5.0 );
1230 bigFont.SetSize( r.Height() / 3.0 );
1231 tinyFont.SetSize( r.Height() / 7.0 );
1232 float timeHeight = r.Height() / 2.5;
1233 float height = ( r.Height() - timeHeight ) / 3.0;
1234 SetFont( &tinyFont );
1235 SetHighColor( 0, 180, 0, 255 );
1236 DrawString( _("File"), BPoint( r.left + 3.0, r.top + height ) );
1237 DrawString( _("Title"), BPoint( r.left + 3.0, r.top + 2.0 * height ) );
1238 DrawString( _("Chapter"), BPoint( r.left + 3.0, r.top + 3.0 * height ) );
1239 SetFont( &smallFont );
1241 SetHighColor( 0, 255, 0, 255 );
1243 _MakeString( helper, fCurrentFileIndex, fCurrentFileSize );
1244 float width = StringWidth( helper.String() );
1245 DrawString( helper.String(), BPoint( r.right - 3.0 - width, r.top + height ) );
1247 _MakeString( helper, fCurrentTitleIndex, fCurrentTitleSize );
1248 width = StringWidth( helper.String() );
1249 DrawString( helper.String(), BPoint( r.right - 3.0 - width, r.top + 2.0 * height ) );
1251 _MakeString( helper, fCurrentChapterIndex, fCurrentChapterSize );
1252 width = StringWidth( helper.String() );
1253 DrawString( helper.String(), BPoint( r.right - 3.0 - width, r.top + 3.0 * height ) );
1255 SetFont( &bigFont );
1256 width = StringWidth( fTimeString.String() );
1257 DrawString( fTimeString.String(),
1258 BPoint( r.left + r.Width() / 2.0 - width / 2.0,
1265 /*****************************************************************************
1266 * PositionInfoView::ResizeToPreferred
1267 *****************************************************************************/
1269 PositionInfoView::ResizeToPreferred()
1271 float width, height;
1272 GetPreferredSize( &width, &height );
1273 ResizeTo( width, height );
1276 /*****************************************************************************
1277 * PositionInfoView::GetPreferredSize
1278 *****************************************************************************/
1280 PositionInfoView::GetPreferredSize( float* width, float* height )
1282 if ( width && height )
1284 *width = 5.0 + ceilf( StringWidth( "0:00:00" ) ) + 5.0;
1286 GetFontHeight( &fh );
1287 *height = 3.0 + ceilf( fh.ascent ) + 3.0;
1288 fStackedWidthCache = *width * 1.2;
1289 fStackedHeightCache = *height * 2.7;
1293 /*****************************************************************************
1294 * PositionInfoView::Pulse
1295 *****************************************************************************/
1297 PositionInfoView::Pulse()
1299 // allow for Pulse frequency to be higher, MediaControlView needs it
1300 bigtime_t now = system_time();
1301 if ( now - fLastPulseUpdate > 900000 )
1305 p_intf->p_sys->p_wrapper->GetPlaylistInfo( index, size );
1306 SetFile( index + 1, size );
1307 p_intf->p_sys->p_wrapper->TitleInfo( index, size );
1308 SetTitle( index, size );
1309 p_intf->p_sys->p_wrapper->ChapterInfo( index, size );
1310 SetChapter( index, size );
1311 SetTime( p_intf->p_sys->p_wrapper->GetTimeAsString() );
1312 fLastPulseUpdate = now;
1317 /*****************************************************************************
1318 * PositionInfoView::GetBigPreferredSize
1319 *****************************************************************************/
1321 PositionInfoView::GetBigPreferredSize( float* width, float* height )
1323 if ( width && height )
1325 *width = fStackedWidthCache;
1326 *height = fStackedHeightCache;
1330 /*****************************************************************************
1331 * PositionInfoView::SetMode
1332 *****************************************************************************/
1334 PositionInfoView::SetMode( uint32 mode )
1336 if ( fMode != mode )
1339 _InvalidateContents();
1343 /*****************************************************************************
1344 * PositionInfoView::SetFile
1345 *****************************************************************************/
1347 PositionInfoView::SetFile( int32 index, int32 size )
1349 if ( fCurrentFileIndex != index || fCurrentFileSize != size )
1351 fCurrentFileIndex = index;
1352 fCurrentFileSize = size;
1353 _InvalidateContents();
1357 /*****************************************************************************
1358 * PositionInfoView::SetTitle
1359 *****************************************************************************/
1361 PositionInfoView::SetTitle( int32 index, int32 size )
1363 if ( fCurrentTitleIndex != index || fCurrentFileSize != size )
1365 fCurrentTitleIndex = index;
1366 fCurrentTitleSize = size;
1367 _InvalidateContents();
1371 /*****************************************************************************
1372 * PositionInfoView::SetChapter
1373 *****************************************************************************/
1375 PositionInfoView::SetChapter( int32 index, int32 size )
1377 if ( fCurrentChapterIndex != index || fCurrentFileSize != size )
1379 fCurrentChapterIndex = index;
1380 fCurrentChapterSize = size;
1381 _InvalidateContents();
1385 /*****************************************************************************
1386 * PositionInfoView::SetTime
1387 *****************************************************************************/
1389 PositionInfoView::SetTime( int32 seconds )
1391 if ( fSeconds != seconds )
1395 int32 minutes = seconds / 60;
1396 int32 hours = minutes / 60;
1397 seconds -= minutes * 60 - hours * 60 * 60;
1398 minutes -= hours * 60;
1399 fTimeString.SetTo( "" );
1400 fTimeString << hours << ":" << minutes << ":" << seconds;
1403 fTimeString.SetTo( "-:--:--" );
1406 _InvalidateContents();
1410 /*****************************************************************************
1411 * PositionInfoView::SetTime
1412 *****************************************************************************/
1414 PositionInfoView::SetTime( const char* string )
1416 fTimeString.SetTo( string );
1417 _InvalidateContents();
1420 /*****************************************************************************
1421 * PositionInfoView::_InvalidateContents
1422 *****************************************************************************/
1424 PositionInfoView::_InvalidateContents( uint32 which )
1426 BRect r( Bounds() );
1427 r.InsetBy( 2.0, 2.0 );
1431 /*****************************************************************************
1432 * PositionInfoView::_InvalidateContents
1433 *****************************************************************************/
1435 PositionInfoView::_MakeString( BString& into, int32 index, int32 maxIndex ) const
1438 if ( index >= 0 && maxIndex >= 0 )
1443 if ( maxIndex >= 0 )