1 /*****************************************************************************
2 * MediaControlView.cpp: beos interface
3 *****************************************************************************
4 * Copyright (C) 1999, 2000, 2001 VideoLAN
5 * $Id: MediaControlView.cpp,v 1.5 2002/10/28 19:42:24 titer Exp $
7 * Authors: Tony Castley <tony@castley.net>
8 * Stephan Aßmus <stippi@yellowbites.com>
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
23 *****************************************************************************/
26 #include <InterfaceKit.h>
35 /* BeOS interface headers */
36 #include "VlcWrapper.h"
38 #include "DrawingTidbits.h"
39 #include "InterfaceWindow.h"
41 #include "TransportButton.h"
42 #include "ListViews.h"
43 #include "MediaControlView.h"
45 #define BORDER_INSET 6.0
47 #define SPEAKER_SLIDER_DIST 6.0
48 #define VOLUME_MIN_WIDTH 70.0
50 #define VOLUME_SLIDER_LAYOUT_WEIGHT 2.0
51 #define SEEK_SLIDER_KNOB_WIDTH 8.0
53 // slider colors are hardcoded here, because that's just
54 // what they currently are within those bitmaps
55 const rgb_color kGreen = (rgb_color){ 152, 203, 152, 255 };
56 const rgb_color kGreenShadow = (rgb_color){ 102, 152, 102, 255 };
57 const rgb_color kBackground = (rgb_color){ 216, 216, 216, 255 };
58 const rgb_color kSeekGreen = (rgb_color){ 171, 221, 161, 255 };
59 const rgb_color kSeekGreenShadow = (rgb_color){ 144, 186, 136, 255 };
60 const rgb_color kSeekRed = (rgb_color){ 255, 0, 0, 255 };
61 const rgb_color kSeekRedLight = (rgb_color){ 255, 152, 152, 255 };
62 const rgb_color kSeekRedShadow = (rgb_color){ 178, 0, 0, 255 };
64 const char* kDisabledSeekMessage = "Drop files to play";
70 MSG_SKIP_BACKWARDS = 'skpb',
71 MSG_SKIP_FORWARD = 'skpf',
75 MediaControlView::MediaControlView(BRect frame, intf_thread_t *p_interface)
76 : BBox(frame, NULL, B_FOLLOW_NONE, B_WILL_DRAW | B_FRAME_EVENTS | B_PULSE_NEEDED,
79 fCurrentRate(DEFAULT_RATE),
80 fCurrentStatus(UNDEF_S),
81 fBottomControlHeight(0.0)
85 BRect frame(0.0, 0.0, 10.0, 10.0);
88 fSeekSlider = new SeekSlider(frame, "seek slider", this,
89 0, SEEKSLIDER_RANGE - 1);
90 fSeekSlider->SetValue(0);
91 fSeekSlider->ResizeToPreferred();
92 AddChild( fSeekSlider );
96 frame.SetRightBottom(kSkipButtonSize);
97 fBottomControlHeight = kRewindBitmapHeight - 1.0;
98 fSkipBack = new TransportButton(frame, B_EMPTY_STRING,
100 kPressedSkipBackBitmapBits,
101 kDisabledSkipBackBitmapBits,
102 new BMessage(MSG_SKIP_BACKWARDS));
103 AddChild( fSkipBack );
106 frame.SetRightBottom(kPlayButtonSize);
107 if (fBottomControlHeight < kPlayPauseBitmapHeight - 1.0)
108 fBottomControlHeight = kPlayPauseBitmapHeight - 1.0;
109 fPlayPause = new PlayPauseButton(frame, B_EMPTY_STRING,
110 kPlayButtonBitmapBits,
111 kPressedPlayButtonBitmapBits,
112 kDisabledPlayButtonBitmapBits,
113 kPlayingPlayButtonBitmapBits,
114 kPressedPlayingPlayButtonBitmapBits,
115 kPausedPlayButtonBitmapBits,
116 kPressedPausedPlayButtonBitmapBits,
117 new BMessage(START_PLAYBACK));
119 AddChild( fPlayPause );
122 frame.SetRightBottom(kSkipButtonSize);
123 fSkipForward = new TransportButton(frame, B_EMPTY_STRING,
124 kSkipForwardBitmapBits,
125 kPressedSkipForwardBitmapBits,
126 kDisabledSkipForwardBitmapBits,
127 new BMessage(MSG_SKIP_FORWARD));
128 AddChild( fSkipForward );
131 fForward = new TransportButton(frame, B_EMPTY_STRING,
133 kPressedForwardBitmapBits,
134 kDisabledForwardBitmapBits,
135 new BMessage(MSG_FORWARD));
136 // AddChild( fForward );
139 fRewind = new TransportButton(frame, B_EMPTY_STRING,
141 kPressedRewindBitmapBits,
142 kDisabledRewindBitmapBits,
143 new BMessage(MSG_REWIND));
144 // AddChild( fRewind );
147 frame.SetRightBottom(kStopButtonSize);
148 if (fBottomControlHeight < kStopBitmapHeight - 1.0)
149 fBottomControlHeight = kStopBitmapHeight - 1.0;
150 fStop = new TransportButton(frame, B_EMPTY_STRING,
151 kStopButtonBitmapBits,
152 kPressedStopButtonBitmapBits,
153 kDisabledStopButtonBitmapBits,
154 new BMessage(STOP_PLAYBACK));
158 frame.SetRightBottom(kSpeakerButtonSize);
159 if (fBottomControlHeight < kSpeakerIconBitmapHeight - 1.0)
160 fBottomControlHeight = kSpeakerIconBitmapHeight - 1.0;
161 fMute = new TransportButton(frame, B_EMPTY_STRING,
163 kPressedSpeakerIconBits,
165 new BMessage(VOLUME_MUTE));
170 fVolumeSlider = new VolumeSlider(BRect(0.0, 0.0, VOLUME_MIN_WIDTH,
171 kVolumeSliderBitmapHeight - 1.0),
172 "volume slider", 1, AOUT_VOLUME_MAX,
173 new BMessage(VOLUME_CHG));
174 fVolumeSlider->SetValue(AOUT_VOLUME_DEFAULT);
175 AddChild( fVolumeSlider );
177 // Position Info View
178 fPositionInfo = new PositionInfoView(BRect(0.0, 0.0, 10.0, 10.0), "led",
180 fPositionInfo->ResizeToPreferred();
181 AddChild( fPositionInfo );
185 MediaControlView::~MediaControlView()
191 MediaControlView::AttachedToWindow()
193 // we are now a valid BHandler
194 fRewind->SetTarget(this);
195 fForward->SetTarget(this);
196 fSkipBack->SetTarget(this);
197 fSkipForward->SetTarget(this);
198 fVolumeSlider->SetTarget(Window());
200 BRect r(_MinFrame());
201 if (BMenuBar* menuBar = Window()->KeyMenuBar())
202 r.bottom += menuBar->Bounds().Height();
204 Window()->SetSizeLimits(r.Width(), r.Width() * 1.8, r.Height(), r.Height() * 1.3);
205 if (!Window()->Bounds().Contains(r))
206 Window()->ResizeTo(r.Width(), r.Height());
208 FrameResized(Bounds().Width(), Bounds().Height());
210 // get pulse message every two frames
211 Window()->SetPulseRate(80000);
216 MediaControlView::FrameResized(float width, float height)
219 // make sure we don't leave dirty pixels
220 // (B_FULL_UPDATE_ON_RESIZE == annoying flicker -> this is smarter)
221 if (fOldBounds.Width() < r.Width())
222 Invalidate(BRect(fOldBounds.right, fOldBounds.top + 1.0,
223 fOldBounds.right, fOldBounds.bottom - 1.0));
225 Invalidate(BRect(r.right, r.top + 1.0,
226 r.right, r.bottom - 1.0));
227 if (fOldBounds.Height() < r.Height())
228 Invalidate(BRect(fOldBounds.left + 1.0, fOldBounds.bottom,
229 fOldBounds.right - 1.0, fOldBounds.bottom));
231 Invalidate(BRect(r.left + 1.0, r.bottom,
232 r.right - 1.0, r.bottom));
233 // remember for next time
236 r.InsetBy(BORDER_INSET, BORDER_INSET);
242 MediaControlView::GetPreferredSize(float* width, float* height)
246 BRect r(_MinFrame());
248 *height = r.Height();
254 MediaControlView::MessageReceived(BMessage* message)
256 switch (message->what)
262 case MSG_SKIP_BACKWARDS:
263 Window()->PostMessage(NAVIGATE_PREV);
265 case MSG_SKIP_FORWARD:
266 Window()->PostMessage(NAVIGATE_NEXT);
269 BBox::MessageReceived(message);
276 MediaControlView::Pulse()
278 InterfaceWindow* window = dynamic_cast<InterfaceWindow*>(Window());
279 if (window && window->IsStopped())
280 fPlayPause->SetStopped();
285 MediaControlView::SetProgress(uint64 seek, uint64 size)
287 fSeekSlider->SetPosition((float)seek / (float)size);
292 MediaControlView::SetStatus(int status, int rate)
294 // we need to set the button status periodically
295 // (even if it is the same) to get a blinking button
296 fCurrentStatus = status;
303 fPlayPause->SetPlaying();
306 fPlayPause->SetPaused();
311 fPlayPause->SetStopped();
314 if (rate != fCurrentRate)
317 if ( rate < DEFAULT_RATE )
326 MediaControlView::SetEnabled(bool enabled)
328 fSkipBack->SetEnabled(enabled);
329 fPlayPause->SetEnabled(enabled);
330 fSkipForward->SetEnabled(enabled);
331 fStop->SetEnabled(enabled);
332 fMute->SetEnabled(enabled);
333 fVolumeSlider->SetEnabled(enabled);
334 fSeekSlider->SetEnabled(enabled);
335 fRewind->SetEnabled(enabled);
336 fForward->SetEnabled(enabled);
341 MediaControlView::SetAudioEnabled(bool enabled)
343 fMute->SetEnabled(enabled);
344 fVolumeSlider->SetEnabled(enabled);
349 MediaControlView::GetSeekTo() const
351 return fSeekSlider->Value();
356 MediaControlView::GetVolume() const
358 return fVolumeSlider->Value();
363 MediaControlView::SetSkippable(bool backward, bool forward)
365 fSkipBack->SetEnabled(backward);
366 fSkipForward->SetEnabled(forward);
371 MediaControlView::SetMuted(bool mute)
373 fVolumeSlider->SetMuted(mute);
378 MediaControlView::_LayoutControls(BRect frame) const
382 // calculate absolutly minimal width
383 float minWidth = fSkipBack->Bounds().Width();
384 // minWidth += fRewind->Bounds().Width();
385 minWidth += fStop->Bounds().Width();
386 minWidth += fPlayPause->Bounds().Width();
387 // minWidth += fForward->Bounds().Width();
388 minWidth += fSkipForward->Bounds().Width();
389 minWidth += fMute->Bounds().Width();
390 minWidth += VOLUME_MIN_WIDTH;
392 // layout time slider and info view
394 fPositionInfo->GetBigPreferredSize( &width, &height );
395 float ratio = width / height;
396 width = r.Height() * ratio;
397 if (frame.Width() - minWidth - MIN_SPACE >= width
398 && frame.Height() >= height)
400 r.right = r.left + width;
401 fPositionInfo->SetMode(PositionInfoView::MODE_BIG);
402 _LayoutControl(fPositionInfo, r, true, true);
403 frame.left = r.right + MIN_SPACE;
405 r.right = frame.right;
406 // r.bottom = r.top + r.Height() / 2.0 - MIN_SPACE / 2.0;
407 r.bottom = r.top + fSeekSlider->Bounds().Height();
408 _LayoutControl(fSeekSlider, r, true);
412 fPositionInfo->GetPreferredSize( &width, &height );
413 fPositionInfo->SetMode(PositionInfoView::MODE_SMALL);
414 fPositionInfo->ResizeTo(width, height);
415 r.bottom = r.top + r.Height() / 2.0 - MIN_SPACE / 2.0;
416 r.right = r.left + fPositionInfo->Bounds().Width();
417 _LayoutControl(fPositionInfo, r, true );
418 r.left = r.right + MIN_SPACE;
419 r.right = frame.right;
420 _LayoutControl(fSeekSlider, r, true);
422 float currentWidth = frame.Width();
423 float space = (currentWidth - minWidth) / 6.0;//8.0;
425 space = MIN_SPACE + (space - MIN_SPACE) / VOLUME_SLIDER_LAYOUT_WEIGHT;
426 // layout controls with "space" inbetween
428 r.top = r.bottom + MIN_SPACE + 1.0;
429 r.bottom = frame.bottom;
431 r.right = r.left + fSkipBack->Bounds().Width();
432 _LayoutControl(fSkipBack, r);
434 // r.left = r.right + space;
435 // r.right = r.left + fRewind->Bounds().Width();
436 // _LayoutControl(fRewind, r);
438 r.left = r.right + space;
439 r.right = r.left + fStop->Bounds().Width();
440 _LayoutControl(fStop, r);
442 r.left = r.right + space;
443 r.right = r.left + fPlayPause->Bounds().Width();
444 _LayoutControl(fPlayPause, r);
446 // r.left = r.right + space;
447 // r.right = r.left + fForward->Bounds().Width();
448 // _LayoutControl(fForward, r);
450 r.left = r.right + space;
451 r.right = r.left + fSkipForward->Bounds().Width();
452 _LayoutControl(fSkipForward, r);
454 r.left = r.right + space + space;
455 r.right = r.left + fMute->Bounds().Width();
456 _LayoutControl(fMute, r);
458 r.left = r.right + SPEAKER_SLIDER_DIST; // keep speaker icon and volume slider attached
459 r.right = frame.right;
460 _LayoutControl(fVolumeSlider, r, true);
465 MediaControlView::_MinFrame() const
467 // add up width of controls along bottom (seek slider will likely adopt)
468 float minWidth = 2 * BORDER_INSET;
469 minWidth += fSkipBack->Bounds().Width() + MIN_SPACE;
470 // minWidth += fRewind->Bounds().Width() + MIN_SPACE;
471 minWidth += fStop->Bounds().Width() + MIN_SPACE;
472 minWidth += fPlayPause->Bounds().Width() + MIN_SPACE;
473 // minWidth += fForward->Bounds().Width() + MIN_SPACE;
474 minWidth += fSkipForward->Bounds().Width() + MIN_SPACE + MIN_SPACE;
475 minWidth += fMute->Bounds().Width() + SPEAKER_SLIDER_DIST;
476 minWidth += VOLUME_MIN_WIDTH;
478 // add up height of seek slider and heighest control on bottom
479 float minHeight = 2 * BORDER_INSET;
480 minHeight += fSeekSlider->Bounds().Height() + MIN_SPACE + MIN_SPACE / 2.0;
481 minHeight += fBottomControlHeight;
482 return BRect(0.0, 0.0, minWidth - 1.0, minHeight - 1.0);
487 MediaControlView::_LayoutControl(BView* view, BRect frame,
488 bool resizeWidth, bool resizeHeight) const
492 frame.top = (frame.top + frame.bottom) / 2.0 - view->Bounds().Height() / 2.0;
494 //center horizontally
495 frame.left = (frame.left + frame.right) / 2.0 - view->Bounds().Width() / 2.0;
496 view->MoveTo(frame.LeftTop());
497 float width = resizeWidth ? frame.Width() : view->Bounds().Width();
498 float height = resizeHeight ? frame.Height() : view->Bounds().Height();
499 if (resizeWidth || resizeHeight)
500 view->ResizeTo(width, height);
505 /*****************************************************************************
507 *****************************************************************************/
508 SeekSlider::SeekSlider(BRect frame, const char* name, MediaControlView *owner,
509 int32 minValue, int32 maxValue)
510 : BControl(frame, name, NULL, NULL, B_FOLLOW_NONE,
511 B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE),
517 BFont font(be_plain_font);
522 SeekSlider::~SeekSlider()
527 /*****************************************************************************
528 * VolumeSlider::AttachedToWindow
529 *****************************************************************************/
531 SeekSlider::AttachedToWindow()
533 BControl::AttachedToWindow();
534 SetViewColor(B_TRANSPARENT_32_BIT);
537 /*****************************************************************************
539 *****************************************************************************/
541 SeekSlider::Draw(BRect updateRect)
544 float knobWidth2 = SEEK_SLIDER_KNOB_WIDTH / 2.0;
545 float sliderStart = (r.left + knobWidth2);
546 float sliderEnd = (r.right - knobWidth2);
547 float knobPos = sliderStart
548 + floorf((sliderEnd - sliderStart - 1.0) * (Value() - fMinValue)
549 / (fMaxValue - fMinValue) + 0.5);
550 // draw both sides (the original from Be doesn't seem
551 // to make a difference for enabled/disabled state)
552 // DrawBitmapAsync(fLeftSideBits, r.LeftTop());
553 // DrawBitmapAsync(fRightSideBits, BPoint(sliderEnd + 1.0, r.top));
554 // colors for the slider area between the two bitmaps
555 rgb_color background = kBackground;//ui_color(B_PANEL_BACKGROUND_COLOR);
556 rgb_color shadow = tint_color(background, B_DARKEN_2_TINT);
557 rgb_color softShadow = tint_color(background, B_DARKEN_1_TINT);
558 rgb_color darkShadow = tint_color(background, B_DARKEN_4_TINT);
559 rgb_color midShadow = tint_color(background, B_DARKEN_3_TINT);
560 rgb_color light = tint_color(background, B_LIGHTEN_MAX_TINT);
561 rgb_color softLight = tint_color(background, B_LIGHTEN_1_TINT);
562 rgb_color green = kSeekGreen;
563 rgb_color greenShadow = kSeekGreenShadow;
564 rgb_color black = kBlack;
565 rgb_color dotGrey = midShadow;
566 rgb_color dotGreen = greenShadow;
568 _StrokeFrame(r, softShadow, softShadow, softLight, softLight);
570 _StrokeFrame(r, black, black, light, light);
575 _StrokeFrame(r, greenShadow, greenShadow, green, green);
578 _StrokeFrame(r, greenShadow, greenShadow, green, green);
584 int32 dotCount = (int32)(r.Width() / 6.0);
586 dotPos.y = r.top + 2.0;
587 SetHighColor(dotGreen);
588 for (int32 i = 0; i < dotCount; i++)
590 dotPos.x = sliderStart + i * 6.0 + 5.0;
591 StrokeLine(dotPos, BPoint(dotPos.x, dotPos.y + 6.0));
596 r.left = knobPos - knobWidth2;
597 r.right = knobPos + knobWidth2;
599 float handleBottomSize = 2.0;
600 float handleArrowSize = 6.0;
603 AddLine(BPoint(r.left, r.top + handleBottomSize),
604 BPoint(r.left, r.top), black);
605 AddLine(BPoint(r.left + 1.0, r.top),
606 BPoint(r.right, r.top), black);
607 AddLine(BPoint(r.right, r.top + 1.0),
608 BPoint(r.right, r.top + handleBottomSize), black);
609 AddLine(BPoint(r.right - 1.0, r.top + handleBottomSize + 1.0),
610 BPoint(knobPos, r.top + handleArrowSize), black);
611 AddLine(BPoint(knobPos - 1.0, r.top + handleArrowSize - 1.0),
612 BPoint(r.left + 1.0, r.top + handleBottomSize + 1.0), black);
614 AddLine(BPoint(r.left, r.bottom),
615 BPoint(r.left, r.bottom - handleBottomSize), black);
616 AddLine(BPoint(r.left + 1.0, r.bottom - handleBottomSize - 1.0),
617 BPoint(knobPos, r.bottom - handleArrowSize), black);
618 AddLine(BPoint(knobPos + 1.0, r.bottom - handleArrowSize + 1.0),
619 BPoint(r.right, r.bottom - handleBottomSize), black);
620 AddLine(BPoint(r.right, r.bottom - handleBottomSize + 1.0),
621 BPoint(r.right, r.bottom), black);
622 AddLine(BPoint(r.right - 1.0, r.bottom),
623 BPoint(r.left + 1.0, r.bottom), black);
625 // inner red light and shadow lines
628 handleArrowSize -= 2.0;
631 AddLine(BPoint(r.left, r.top + handleBottomSize),
632 BPoint(r.left, r.top), kSeekRedLight);
633 AddLine(BPoint(r.left + 1.0, r.top),
634 BPoint(r.right, r.top), kSeekRedLight);
635 AddLine(BPoint(r.right, r.top + 1.0),
636 BPoint(r.right, r.top + handleBottomSize), kSeekRedShadow);
637 AddLine(BPoint(r.right - 1.0, r.top + handleBottomSize + 1.0),
638 BPoint(knobPos, r.top + handleArrowSize), kSeekRedShadow);
639 AddLine(BPoint(knobPos - 1.0, r.top + handleArrowSize - 1.0),
640 BPoint(r.left + 1.0, r.top + handleBottomSize + 1.0), kSeekRedLight);
642 AddLine(BPoint(r.left, r.bottom),
643 BPoint(r.left, r.bottom - handleBottomSize), kSeekRedLight);
644 AddLine(BPoint(r.left + 1.0, r.bottom - handleBottomSize - 1.0),
645 BPoint(knobPos, r.bottom - handleArrowSize), kSeekRedLight);
646 AddLine(BPoint(knobPos + 1.0, r.bottom - handleArrowSize + 1.0),
647 BPoint(r.right, r.bottom - handleBottomSize), kSeekRedShadow);
648 AddLine(BPoint(r.right, r.bottom - handleBottomSize + 1.0),
649 BPoint(r.right, r.bottom), kSeekRedShadow);
650 AddLine(BPoint(r.right - 1.0, r.bottom),
651 BPoint(r.left + 1.0, r.bottom), kSeekRedShadow);
653 // fill rest of handles with red
654 SetHighColor(kSeekRed);
656 handleArrowSize -= 2.0;
658 // upper handle arrow
661 arrow[1].x = r.right;
663 arrow[2].x = knobPos;
664 arrow[2].y = r.top + handleArrowSize;
665 FillPolygon(arrow, 3);
666 // lower handle arrow
668 arrow[0].y = r.bottom;
669 arrow[1].x = r.right;
670 arrow[1].y = r.bottom;
671 arrow[2].x = knobPos;
672 arrow[2].y = r.bottom - handleArrowSize;
673 FillPolygon(arrow, 3);
678 _StrokeFrame(r, darkShadow, darkShadow, darkShadow, darkShadow);
680 _StrokeFrame(r, darkShadow, darkShadow, darkShadow, darkShadow);
682 SetHighColor(darkShadow);
685 float width = floorf(StringWidth(kDisabledSeekMessage));
686 float textPos = r.left + r.Width() / 2.0 - width / 2.0;
687 pattern stripes = { 0xc7, 0x8f, 0x1f, 0x3e, 0x7c, 0xf8, 0xf1, 0xe3 };
688 BRect stripesRect(r);
689 stripesRect.right = textPos - 5.0;
690 FillRect(stripesRect, stripes);
691 stripesRect.left = textPos + width + 3.0;
692 stripesRect.right = r.right;
693 FillRect(stripesRect, stripes);
695 r.left = textPos - 4.0;
696 r.right = textPos + width + 2.0;
698 SetHighColor(shadow);
699 SetLowColor(darkShadow);
702 DrawString(kDisabledSeekMessage, BPoint(textPos, r.top + ceilf(fh.ascent) - 1.0));
706 /*****************************************************************************
707 * SeekSlider::MouseDown
708 *****************************************************************************/
710 SeekSlider::MouseDown(BPoint where)
712 if (IsEnabled() && Bounds().Contains(where))
714 SetValue(_ValueFor(where.x));
716 SetMouseEventMask(B_POINTER_EVENTS, B_LOCK_WINDOW_FOCUS);
721 /*****************************************************************************
722 * SeekSlider::MouseMoved
723 *****************************************************************************/
725 SeekSlider::MouseMoved(BPoint where, uint32 code, const BMessage* dragMessage)
729 SetValue(_ValueFor(where.x));
734 /*****************************************************************************
735 * SeekSlider::MouseUp
736 *****************************************************************************/
738 SeekSlider::MouseUp(BPoint where)
747 /*****************************************************************************
748 * SeekSlider::ResizeToPreferred
749 *****************************************************************************/
751 SeekSlider::ResizeToPreferred()
753 float width = 15.0 + StringWidth(kDisabledSeekMessage) + 15.0;
754 ResizeTo(width, 17.0);
757 /*****************************************************************************
758 * SeekSlider::SetPosition
759 *****************************************************************************/
761 SeekSlider::SetPosition(float position)
763 SetValue(fMinValue + (int32)floorf((fMaxValue - fMinValue) * position + 0.5));
766 /*****************************************************************************
767 * SeekSlider::_ValueFor
768 *****************************************************************************/
770 SeekSlider::_ValueFor(float xPos) const
773 float knobWidth2 = SEEK_SLIDER_KNOB_WIDTH / 2.0;
774 float sliderStart = (r.left + knobWidth2);
775 float sliderEnd = (r.right - knobWidth2);
776 int32 value = fMinValue + (int32)(((xPos - sliderStart) * (fMaxValue - fMinValue))
777 / (sliderEnd - sliderStart - 1.0));
778 if (value < fMinValue)
780 if (value > fMaxValue)
785 /*****************************************************************************
786 * SeekSlider::_StrokeFrame
787 *****************************************************************************/
789 SeekSlider::_StrokeFrame(BRect r, rgb_color left, rgb_color top,
790 rgb_color right, rgb_color bottom)
793 AddLine(BPoint(r.left, r.bottom), BPoint(r.left, r.top), left);
794 AddLine(BPoint(r.left + 1.0, r.top), BPoint(r.right, r.top), top);
795 AddLine(BPoint(r.right, r.top + 1.0), BPoint(r.right, r.bottom), right);
796 AddLine(BPoint(r.right - 1.0, r.bottom), BPoint(r.left + 1.0, r.bottom), bottom);
800 /*****************************************************************************
801 * SeekSlider::_BeginSeek
802 *****************************************************************************/
804 SeekSlider::_BeginSeek()
806 fOwner->fScrubSem = create_sem(0, "Vlc::fScrubSem");
807 if (fOwner->fScrubSem >= B_OK)
808 release_sem(fOwner->fScrubSem);
811 /*****************************************************************************
813 *****************************************************************************/
817 if (fOwner->fScrubSem >= B_OK)
818 delete_sem(fOwner->fScrubSem);
819 fOwner->fScrubSem = create_sem(0, "Vlc::fScrubSem");
820 if (fOwner->fScrubSem >= B_OK)
821 release_sem(fOwner->fScrubSem);
824 /*****************************************************************************
825 * SeekSlider::_EndSeek
826 *****************************************************************************/
828 SeekSlider::_EndSeek()
830 if (fOwner->fScrubSem >= B_OK)
831 delete_sem(fOwner->fScrubSem);
832 fOwner->fScrubSem = B_ERROR;
836 /*****************************************************************************
838 *****************************************************************************/
839 VolumeSlider::VolumeSlider(BRect frame, const char* name, int32 minValue, int32 maxValue,
840 BMessage* message, BHandler* target)
841 : BControl(frame, name, NULL, message, B_FOLLOW_NONE,
842 B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE),
844 fRightSideBits(NULL),
854 BRect r(BPoint(0.0, 0.0), kVolumeSliderBitmapSize);
855 fLeftSideBits = new BBitmap(r, B_CMAP8);
856 fRightSideBits = new BBitmap(r, B_CMAP8);
857 r.Set(0.0, 0.0, kVolumeSliderKnobBitmapSize.x, kVolumeSliderKnobBitmapSize.y);
858 fKnobBits = new BBitmap(r, B_CMAP8);
863 /*****************************************************************************
864 * VolumeSlider destructor
865 *****************************************************************************/
866 VolumeSlider::~VolumeSlider()
868 delete fLeftSideBits;
869 delete fRightSideBits;
873 /*****************************************************************************
874 * VolumeSlider::AttachedToWindow
875 *****************************************************************************/
877 VolumeSlider::AttachedToWindow()
879 BControl::AttachedToWindow();
880 SetViewColor(B_TRANSPARENT_32_BIT);
883 /*****************************************************************************
884 * VolumeSlider::SetValue
885 *****************************************************************************/
887 VolumeSlider::SetValue(int32 value)
889 if (value != Value())
891 BControl::SetValue(value);
896 /*****************************************************************************
897 * VolumeSlider::SetEnabled
898 *****************************************************************************/
900 VolumeSlider::SetEnabled(bool enable)
902 if (enable != IsEnabled())
904 BControl::SetEnabled(enable);
910 /*****************************************************************************
912 *****************************************************************************/
914 VolumeSlider::Draw(BRect updateRect)
919 float sliderSideWidth = kVolumeSliderBitmapWidth;
920 float sliderStart = (r.left + sliderSideWidth);
921 float sliderEnd = (r.right - sliderSideWidth);
922 float knobPos = sliderStart
923 + (sliderEnd - sliderStart - 1.0) * (Value() - fMinValue)
924 / (fMaxValue - fMinValue);
925 // draw both sides (the original from Be doesn't seem
926 // to make a difference for enabled/disabled state)
927 DrawBitmapAsync(fLeftSideBits, r.LeftTop());
928 DrawBitmapAsync(fRightSideBits, BPoint(sliderEnd + 1.0, r.top));
929 // colors for the slider area between the two bitmaps
930 rgb_color background = kBackground;//ui_color(B_PANEL_BACKGROUND_COLOR);
931 rgb_color shadow = tint_color(background, B_DARKEN_2_TINT);
932 rgb_color softShadow = tint_color(background, B_DARKEN_1_TINT);
933 rgb_color darkShadow = tint_color(background, B_DARKEN_4_TINT);
934 rgb_color midShadow = tint_color(background, B_DARKEN_3_TINT);
935 rgb_color light = tint_color(background, B_LIGHTEN_MAX_TINT);
936 rgb_color softLight = tint_color(background, B_LIGHTEN_1_TINT);
937 rgb_color green = kGreen;
938 rgb_color greenShadow = kGreenShadow;
939 rgb_color black = kBlack;
940 rgb_color dotGrey = midShadow;
941 rgb_color dotGreen = greenShadow;
942 // make dimmed version of colors if we're disabled
945 shadow = (rgb_color){ 200, 200, 200, 255 };
946 softShadow = dimmed_color_cmap8(softShadow, background, DIM_LEVEL);
947 darkShadow = dimmed_color_cmap8(darkShadow, background, DIM_LEVEL);
949 light = dimmed_color_cmap8(light, background, DIM_LEVEL);
950 softLight = dimmed_color_cmap8(softLight, background, DIM_LEVEL);
951 green = dimmed_color_cmap8(green, background, DIM_LEVEL);
952 greenShadow = dimmed_color_cmap8(greenShadow, background, DIM_LEVEL);
953 black = dimmed_color_cmap8(black, background, DIM_LEVEL);
958 green = tint_color(kBackground, B_DARKEN_3_TINT);
959 greenShadow = tint_color(kBackground, B_DARKEN_4_TINT);
960 dotGreen = greenShadow;
962 // draw slider edges between bitmaps
964 AddLine(BPoint(sliderStart, r.top),
965 BPoint(sliderEnd, r.top), softShadow);
966 AddLine(BPoint(sliderStart, r.bottom),
967 BPoint(sliderEnd, r.bottom), softLight);
969 AddLine(BPoint(sliderStart, r.top),
970 BPoint(sliderEnd, r.top), black);
971 AddLine(BPoint(sliderStart, r.bottom),
972 BPoint(sliderEnd, r.bottom), light);
974 AddLine(BPoint(sliderStart, r.top),
975 BPoint(knobPos, r.top), greenShadow);
976 AddLine(BPoint(knobPos, r.top),
977 BPoint(sliderEnd, r.top), midShadow);
979 AddLine(BPoint(sliderStart, r.top),
980 BPoint(knobPos, r.top), greenShadow);
982 // fill rest inside of slider
984 r.left = sliderStart;
987 FillRect(r, B_SOLID_HIGH);
988 r.left = knobPos + 1.0;
991 SetHighColor(shadow);
992 FillRect(r, B_SOLID_HIGH);
993 // draw little dots inside
994 int32 dotCount = (int32)((sliderEnd - sliderStart) / 5.0);
996 dotPos.y = r.top + 4.0;
997 for (int32 i = 0; i < dotCount; i++)
999 dotPos.x = sliderStart + i * 5.0 + 4.0;
1000 SetHighColor(dotPos.x < knobPos ? dotGreen : dotGrey);
1001 StrokeLine(dotPos, BPoint(dotPos.x, dotPos.y + 1.0));
1005 SetDrawingMode(B_OP_OVER); // part of knob is transparent
1006 DrawBitmapAsync(fKnobBits, BPoint(knobPos - kVolumeSliderKnobWidth / 2, r.top));
1009 fprintf(stderr, "VolumeSlider::Draw() - Error: no valid bitmaps!");
1012 /*****************************************************************************
1013 * VolumeSlider::MouseDown
1014 *****************************************************************************/
1016 VolumeSlider::MouseDown(BPoint where)
1018 if (Bounds().Contains(where) && IsEnabled())
1021 SetValue(_ValueFor(where.x));
1022 SetMouseEventMask(B_POINTER_EVENTS, B_LOCK_WINDOW_FOCUS);
1026 /*****************************************************************************
1027 * VolumeSlider::MouseMoved
1028 *****************************************************************************/
1030 VolumeSlider::MouseMoved(BPoint where, uint32 transit, const BMessage* dragMessage)
1033 SetValue(_ValueFor(where.x));
1036 /*****************************************************************************
1037 * VolumeSlider::MouseUp
1038 *****************************************************************************/
1040 VolumeSlider::MouseUp(BPoint where)
1046 /*****************************************************************************
1047 * VolumeSlider::IsValid
1048 *****************************************************************************/
1050 VolumeSlider::IsValid() const
1052 return (fLeftSideBits && fLeftSideBits->IsValid()
1053 && fRightSideBits && fRightSideBits->IsValid()
1054 && fKnobBits && fKnobBits->IsValid());
1057 /*****************************************************************************
1058 * VolumeSlider::SetMuted
1059 *****************************************************************************/
1061 VolumeSlider::SetMuted(bool mute)
1071 /*****************************************************************************
1072 * VolumeSlider::_MakeBitmaps
1073 *****************************************************************************/
1075 VolumeSlider::_MakeBitmaps()
1079 // left side of slider
1080 memcpy(fLeftSideBits->Bits(), kVolumeSliderLeftBitmapBits,
1081 fLeftSideBits->BitsLength());
1082 // right side of slider
1083 memcpy(fRightSideBits->Bits(), kVolumeSliderRightBits,
1084 fRightSideBits->BitsLength());
1086 int32 length = fKnobBits->BitsLength();
1087 memcpy(fKnobBits->Bits(), kVolumeSliderKnobBits, length);
1088 uint8* bits = (uint8*)fKnobBits->Bits();
1089 // black was used in the knob to represent transparency
1090 // use screen to get index for the "transarent" color used in the bitmap
1091 BScreen screen(B_MAIN_SCREEN_ID);
1092 uint8 blackIndex = screen.IndexForColor(kBlack);
1093 // replace black index with transparent index
1094 for (int32 i = 0; i < length; i++)
1095 if (bits[i] == blackIndex)
1096 bits[i] = B_TRANSPARENT_MAGIC_CMAP8;
1100 // make ghosted versions of the bitmaps
1101 dim_bitmap(fLeftSideBits, kBackground, DIM_LEVEL);
1102 dim_bitmap(fRightSideBits, kBackground, DIM_LEVEL);
1103 dim_bitmap(fKnobBits, kBackground, DIM_LEVEL);
1107 // replace green color (and shadow) in left slider side
1108 bits = (uint8*)fLeftSideBits->Bits();
1109 length = fLeftSideBits->BitsLength();
1110 uint8 greenIndex = screen.IndexForColor(kGreen);
1111 uint8 greenShadowIndex = screen.IndexForColor(kGreenShadow);
1112 rgb_color shadow = tint_color(kBackground, B_DARKEN_3_TINT);
1113 rgb_color midShadow = tint_color(kBackground, B_DARKEN_4_TINT);
1114 uint8 replaceIndex = screen.IndexForColor(shadow);
1115 uint8 replaceShadowIndex = screen.IndexForColor(midShadow);
1116 for (int32 i = 0; i < length; i++)
1118 if (bits[i] == greenIndex)
1119 bits[i] = replaceIndex;
1120 else if (bits[i] == greenShadowIndex)
1121 bits[i] = replaceShadowIndex;
1127 /*****************************************************************************
1128 * VolumeSlider::_ValueFor
1129 *****************************************************************************/
1131 VolumeSlider::_ValueFor(float xPos) const
1134 float sliderStart = (r.left + kVolumeSliderBitmapWidth);
1135 float sliderEnd = (r.right - kVolumeSliderBitmapWidth);
1136 int32 value = fMinValue + (int32)(((xPos - sliderStart) * (fMaxValue - fMinValue))
1137 / (sliderEnd - sliderStart - 1.0));
1138 if (value < fMinValue)
1140 if (value > fMaxValue)
1145 /*****************************************************************************
1146 * PositionInfoView::PositionInfoView
1147 *****************************************************************************/
1148 PositionInfoView::PositionInfoView( BRect frame, const char* name,
1149 intf_thread_t * p_interface )
1150 : BView( frame, name, B_FOLLOW_NONE,
1151 B_WILL_DRAW | B_PULSE_NEEDED | B_FULL_UPDATE_ON_RESIZE ),
1152 fMode( MODE_SMALL ),
1153 fCurrentFileIndex( -1 ),
1154 fCurrentFileSize( -1 ),
1155 fCurrentTitleIndex( -1 ),
1156 fCurrentTitleSize( -1 ),
1157 fCurrentChapterIndex( -1 ),
1158 fCurrentChapterSize( -1 ),
1160 fTimeString( "-:--:--" ),
1161 fLastPulseUpdate( system_time() ),
1162 fStackedWidthCache( 0.0 ),
1163 fStackedHeightCache( 0.0 )
1165 p_intf = p_interface;
1167 SetViewColor( B_TRANSPARENT_32_BIT );
1168 SetLowColor( kBlack );
1169 SetHighColor( 0, 255, 0, 255 );
1170 SetFontSize( 11.0 );
1173 /*****************************************************************************
1174 * PositionInfoView::~PositionInfoView
1175 *****************************************************************************/
1176 PositionInfoView::~PositionInfoView()
1180 /*****************************************************************************
1181 * PositionInfoView::Draw
1182 *****************************************************************************/
1184 PositionInfoView::Draw( BRect updateRect )
1186 rgb_color background = ui_color( B_PANEL_BACKGROUND_COLOR );
1187 rgb_color shadow = tint_color( background, B_DARKEN_1_TINT );
1188 rgb_color darkShadow = tint_color( background, B_DARKEN_4_TINT );
1189 rgb_color light = tint_color( background, B_LIGHTEN_MAX_TINT );
1190 rgb_color softLight = tint_color( background, B_LIGHTEN_1_TINT );
1192 BRect r( Bounds() );
1193 BeginLineArray( 8 );
1194 AddLine( BPoint( r.left, r.bottom ),
1195 BPoint( r.left, r.top ), shadow );
1196 AddLine( BPoint( r.left + 1.0, r.top ),
1197 BPoint( r.right, r.top ), shadow );
1198 AddLine( BPoint( r.right, r.top + 1.0 ),
1199 BPoint( r.right, r.bottom ), softLight );
1200 AddLine( BPoint( r.right - 1.0, r.bottom ),
1201 BPoint( r.left + 1.0, r.bottom ), softLight );
1202 r.InsetBy( 1.0, 1.0 );
1203 AddLine( BPoint( r.left, r.bottom ),
1204 BPoint( r.left, r.top ), darkShadow );
1205 AddLine( BPoint( r.left + 1.0, r.top ),
1206 BPoint( r.right, r.top ), darkShadow );
1207 AddLine( BPoint( r.right, r.top + 1.0 ),
1208 BPoint( r.right, r.bottom ), light );
1209 AddLine( BPoint( r.right - 1.0, r.bottom ),
1210 BPoint( r.left + 1.0, r.bottom ), light );
1213 r.InsetBy( 1.0, 1.0 );
1214 FillRect( r, B_SOLID_LOW );
1217 GetFontHeight( &fh );
1222 float width = StringWidth( fTimeString.String() );
1223 DrawString( fTimeString.String(),
1224 BPoint( r.left + r.Width() / 2.0 - width / 2.0,
1225 r.top + r.Height() / 2.0 + fh.ascent / 2.0 - 1.0 ) );
1232 BFont smallFont = font;
1233 BFont bigFont = font;
1234 BFont tinyFont = font;
1235 smallFont.SetSize( r.Height() / 5.0 );
1236 bigFont.SetSize( r.Height() / 3.0 );
1237 tinyFont.SetSize( r.Height() / 7.0 );
1238 float timeHeight = r.Height() / 2.5;
1239 float height = ( r.Height() - timeHeight ) / 3.0;
1240 SetFont( &tinyFont );
1241 SetHighColor( 0, 180, 0, 255 );
1242 DrawString( "File", BPoint( r.left + 3.0, r.top + height ) );
1243 DrawString( "Title", BPoint( r.left + 3.0, r.top + 2.0 * height ) );
1244 DrawString( "Chapter", BPoint( r.left + 3.0, r.top + 3.0 * height ) );
1245 SetFont( &smallFont );
1247 SetHighColor( 0, 255, 0, 255 );
1249 _MakeString( helper, fCurrentFileIndex, fCurrentFileSize );
1250 float width = StringWidth( helper.String() );
1251 DrawString( helper.String(), BPoint( r.right - 3.0 - width, r.top + height ) );
1253 _MakeString( helper, fCurrentTitleIndex, fCurrentTitleSize );
1254 width = StringWidth( helper.String() );
1255 DrawString( helper.String(), BPoint( r.right - 3.0 - width, r.top + 2.0 * height ) );
1257 _MakeString( helper, fCurrentChapterIndex, fCurrentChapterSize );
1258 width = StringWidth( helper.String() );
1259 DrawString( helper.String(), BPoint( r.right - 3.0 - width, r.top + 3.0 * height ) );
1261 SetFont( &bigFont );
1262 width = StringWidth( fTimeString.String() );
1263 DrawString( fTimeString.String(),
1264 BPoint( r.left + r.Width() / 2.0 - width / 2.0,
1271 /*****************************************************************************
1272 * PositionInfoView::ResizeToPreferred
1273 *****************************************************************************/
1275 PositionInfoView::ResizeToPreferred()
1277 float width, height;
1278 GetPreferredSize( &width, &height );
1279 ResizeTo( width, height );
1282 /*****************************************************************************
1283 * PositionInfoView::GetPreferredSize
1284 *****************************************************************************/
1286 PositionInfoView::GetPreferredSize( float* width, float* height )
1288 if ( width && height )
1290 *width = 5.0 + ceilf( StringWidth( "0:00:00" ) ) + 5.0;
1292 GetFontHeight( &fh );
1293 *height = 3.0 + ceilf( fh.ascent ) + 3.0;
1294 fStackedWidthCache = *width * 1.2;
1295 fStackedHeightCache = *height * 2.7;
1299 /*****************************************************************************
1300 * PositionInfoView::Pulse
1301 *****************************************************************************/
1303 PositionInfoView::Pulse()
1305 // allow for Pulse frequency to be higher, MediaControlView needs it
1306 bigtime_t now = system_time();
1307 if ( now - fLastPulseUpdate > 900000 )
1310 p_intf->p_sys->p_vlc_wrapper->getPlaylistInfo( index, size );
1311 SetFile( index, size );
1312 p_intf->p_sys->p_vlc_wrapper->getTitleInfo( index, size );
1313 SetTitle( index, size );
1314 p_intf->p_sys->p_vlc_wrapper->getChapterInfo( index, size );
1315 SetChapter( index, size );
1316 SetTime( p_intf->p_sys->p_vlc_wrapper->getTimeAsString() );
1317 fLastPulseUpdate = now;
1321 /*****************************************************************************
1322 * PositionInfoView::GetBigPreferredSize
1323 *****************************************************************************/
1325 PositionInfoView::GetBigPreferredSize( float* width, float* height )
1327 if ( width && height )
1329 *width = fStackedWidthCache;
1330 *height = fStackedHeightCache;
1334 /*****************************************************************************
1335 * PositionInfoView::SetMode
1336 *****************************************************************************/
1338 PositionInfoView::SetMode( uint32 mode )
1340 if ( fMode != mode )
1343 _InvalidateContents();
1347 /*****************************************************************************
1348 * PositionInfoView::SetFile
1349 *****************************************************************************/
1351 PositionInfoView::SetFile( int32 index, int32 size )
1353 if ( fCurrentFileIndex != index || fCurrentFileSize != size )
1355 fCurrentFileIndex = index;
1356 fCurrentFileSize = size;
1357 _InvalidateContents();
1361 /*****************************************************************************
1362 * PositionInfoView::SetTitle
1363 *****************************************************************************/
1365 PositionInfoView::SetTitle( int32 index, int32 size )
1367 if ( fCurrentTitleIndex != index || fCurrentFileSize != size )
1369 fCurrentTitleIndex = index;
1370 fCurrentTitleSize = size;
1371 _InvalidateContents();
1375 /*****************************************************************************
1376 * PositionInfoView::SetChapter
1377 *****************************************************************************/
1379 PositionInfoView::SetChapter( int32 index, int32 size )
1381 if ( fCurrentChapterIndex != index || fCurrentFileSize != size )
1383 fCurrentChapterIndex = index;
1384 fCurrentChapterSize = size;
1385 _InvalidateContents();
1389 /*****************************************************************************
1390 * PositionInfoView::SetTime
1391 *****************************************************************************/
1393 PositionInfoView::SetTime( int32 seconds )
1395 if ( fSeconds != seconds )
1399 int32 minutes = seconds / 60;
1400 int32 hours = minutes / 60;
1401 seconds -= minutes * 60 - hours * 60 * 60;
1402 minutes -= hours * 60;
1403 fTimeString.SetTo( "" );
1404 fTimeString << hours << ":" << minutes << ":" << seconds;
1407 fTimeString.SetTo( "-:--:--" );
1410 _InvalidateContents();
1414 /*****************************************************************************
1415 * PositionInfoView::SetTime
1416 *****************************************************************************/
1418 PositionInfoView::SetTime( const char* string )
1420 fTimeString.SetTo( string );
1421 _InvalidateContents();
1424 /*****************************************************************************
1425 * PositionInfoView::_InvalidateContents
1426 *****************************************************************************/
1428 PositionInfoView::_InvalidateContents( uint32 which )
1430 BRect r( Bounds() );
1431 r.InsetBy( 2.0, 2.0 );
1435 /*****************************************************************************
1436 * PositionInfoView::_InvalidateContents
1437 *****************************************************************************/
1439 PositionInfoView::_MakeString( BString& into, int32 index, int32 maxIndex ) const