From fb365709672ad1896ecd0150b21907ea902e05b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stephan=20A=C3=9Fmus?= Date: Mon, 8 May 2006 19:18:19 +0000 Subject: [PATCH] * added a simple seeking slider for Marcus to play with... git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@17371 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- src/apps/mediaplayer/ControllerView.cpp | 9 + src/apps/mediaplayer/ControllerView.h | 1 + src/apps/mediaplayer/Jamfile | 1 + src/apps/mediaplayer/SeekSlider.cpp | 314 ++++++++++++++++++ src/apps/mediaplayer/SeekSlider.h | 52 +++ .../mediaplayer/TransportControlGroup.cpp | 60 +++- src/apps/mediaplayer/TransportControlGroup.h | 5 + 7 files changed, 430 insertions(+), 12 deletions(-) create mode 100644 src/apps/mediaplayer/SeekSlider.cpp create mode 100644 src/apps/mediaplayer/SeekSlider.h diff --git a/src/apps/mediaplayer/ControllerView.cpp b/src/apps/mediaplayer/ControllerView.cpp index f800f08249..6efe6e4075 100644 --- a/src/apps/mediaplayer/ControllerView.cpp +++ b/src/apps/mediaplayer/ControllerView.cpp @@ -136,6 +136,7 @@ void ControllerView::SetVolume(float value) { printf("ControllerView::SetVolume(%.2f)\n", value); + // 0.0 ... 1.0 } @@ -145,3 +146,11 @@ ControllerView::ToggleMute() printf("ControllerView::ToggleMute()\n"); } + +void +ControllerView::SetPosition(float value) +{ + printf("ControllerView::SetPosition(%.2f)\n", value); + // 0.0 ... 1.0 +} + diff --git a/src/apps/mediaplayer/ControllerView.h b/src/apps/mediaplayer/ControllerView.h index 36d4ef59a9..6e125c6235 100644 --- a/src/apps/mediaplayer/ControllerView.h +++ b/src/apps/mediaplayer/ControllerView.h @@ -49,6 +49,7 @@ private: virtual void SkipForward(); virtual void SetVolume(float value); virtual void ToggleMute(); + virtual void SetPosition(float value); private: Controller * fController; diff --git a/src/apps/mediaplayer/Jamfile b/src/apps/mediaplayer/Jamfile index b837c688c5..a126281304 100644 --- a/src/apps/mediaplayer/Jamfile +++ b/src/apps/mediaplayer/Jamfile @@ -14,6 +14,7 @@ Application MediaPlayer : SoundOutput.cpp TransportButton.cpp TransportControlGroup.cpp + SeekSlider.cpp VideoNode.cpp VideoView.cpp VolumeSlider.cpp diff --git a/src/apps/mediaplayer/SeekSlider.cpp b/src/apps/mediaplayer/SeekSlider.cpp new file mode 100644 index 0000000000..89cb03fdee --- /dev/null +++ b/src/apps/mediaplayer/SeekSlider.cpp @@ -0,0 +1,314 @@ +/* + * Copyright 2006, Haiku. + * Distributed under the terms of the MIT License. + * + * Authors: + * Stephan Aßmus + */ + +// NOTE: Based on my code in the BeOS interface for the VLC media player +// that I did during the VLC 0.4.3 - 0.4.6 times. Code not done by me +// removed. -Stephan Aßmus + +#include "SeekSlider.h" + +#include +#include + +#include "DrawingTidbits.h" + + +#define SEEK_SLIDER_KNOB_WIDTH 8.0 + +const rgb_color kSeekGreen = (rgb_color){ 171, 221, 161, 255 }; +const rgb_color kSeekGreenShadow = (rgb_color){ 144, 186, 136, 255 }; +const rgb_color kSeekRed = (rgb_color){ 255, 0, 0, 255 }; +const rgb_color kSeekRedLight = (rgb_color){ 255, 152, 152, 255 }; +const rgb_color kSeekRedShadow = (rgb_color){ 178, 0, 0, 255 }; + +const char* kDisabledSeekMessage = "Drop files to play"; + + +SeekSlider::SeekSlider(BRect frame, const char* name, BMessage* message, + int32 minValue, int32 maxValue) + : BControl(frame, name, NULL, message, B_FOLLOW_NONE, + B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE), + fTracking(false), + fMinValue(minValue), + fMaxValue(maxValue) +{ + BFont font(be_plain_font); + font.SetSize(9.0); + SetFont(&font); +} + + +SeekSlider::~SeekSlider() +{ +} + + +void +SeekSlider::AttachedToWindow() +{ + BControl::AttachedToWindow(); + SetViewColor(B_TRANSPARENT_32_BIT); +} + + +void +SeekSlider::SetValue(int32 value) +{ + if (value == Value()) + return; + + BControl::SetValue(value); + Invoke(); +} + + +void +SeekSlider::Draw(BRect updateRect) +{ + BRect r(Bounds()); + float knobWidth2 = SEEK_SLIDER_KNOB_WIDTH / 2.0; + float sliderStart = (r.left + knobWidth2); + float sliderEnd = (r.right - knobWidth2); + float knobPos = sliderStart + + floorf((sliderEnd - sliderStart - 1.0) * (Value() - fMinValue) + / (fMaxValue - fMinValue) + 0.5); + // draw both sides (the original from Be doesn't seem + // to make a difference for enabled/disabled state) +// DrawBitmapAsync(fLeftSideBits, r.LeftTop()); +// DrawBitmapAsync(fRightSideBits, BPoint(sliderEnd + 1.0, r.top)); + // colors for the slider area between the two bitmaps + rgb_color background = ui_color(B_PANEL_BACKGROUND_COLOR); + rgb_color shadow = tint_color(background, B_DARKEN_2_TINT); + rgb_color softShadow = tint_color(background, B_DARKEN_1_TINT); + rgb_color darkShadow = tint_color(background, B_DARKEN_4_TINT); + rgb_color midShadow = tint_color(background, B_DARKEN_3_TINT); + rgb_color light = tint_color(background, B_LIGHTEN_MAX_TINT); + rgb_color softLight = tint_color(background, B_LIGHTEN_1_TINT); + rgb_color green = kSeekGreen; + rgb_color greenShadow = kSeekGreenShadow; + rgb_color black = kBlack; + rgb_color dotGrey = midShadow; + rgb_color dotGreen = greenShadow; + // draw frame + _StrokeFrame(r, softShadow, softShadow, softLight, softLight); + r.InsetBy(1.0, 1.0); + _StrokeFrame(r, black, black, light, light); + if (IsEnabled()) { + // *** enabled look *** + r.InsetBy(1.0, 1.0); + // inner shadow + _StrokeFrame(r, greenShadow, greenShadow, green, green); + r.top++; + r.left++; + _StrokeFrame(r, greenShadow, greenShadow, green, green); + // inside area + r.InsetBy(1.0, 1.0); + SetHighColor(green); + FillRect(r); + // dots + int32 dotCount = (int32)(r.Width() / 6.0); + BPoint dotPos; + dotPos.y = r.top + 2.0; + SetHighColor(dotGreen); + for (int32 i = 0; i < dotCount; i++) { + dotPos.x = sliderStart + i * 6.0 + 5.0; + StrokeLine(dotPos, BPoint(dotPos.x, dotPos.y + 6.0)); + } + // slider handle + r.top -= 4.0; + r.bottom += 3.0; + r.left = knobPos - knobWidth2; + r.right = knobPos + knobWidth2; + // black outline + float handleBottomSize = 2.0; + float handleArrowSize = 6.0; + BeginLineArray(10); + // upper handle + AddLine(BPoint(r.left, r.top + handleBottomSize), + BPoint(r.left, r.top), black); + AddLine(BPoint(r.left + 1.0, r.top), + BPoint(r.right, r.top), black); + AddLine(BPoint(r.right, r.top + 1.0), + BPoint(r.right, r.top + handleBottomSize), black); + AddLine(BPoint(r.right - 1.0, r.top + handleBottomSize + 1.0), + BPoint(knobPos, r.top + handleArrowSize), black); + AddLine(BPoint(knobPos - 1.0, r.top + handleArrowSize - 1.0), + BPoint(r.left + 1.0, r.top + handleBottomSize + 1.0), black); + // lower handle + AddLine(BPoint(r.left, r.bottom), + BPoint(r.left, r.bottom - handleBottomSize), black); + AddLine(BPoint(r.left + 1.0, r.bottom - handleBottomSize - 1.0), + BPoint(knobPos, r.bottom - handleArrowSize), black); + AddLine(BPoint(knobPos + 1.0, r.bottom - handleArrowSize + 1.0), + BPoint(r.right, r.bottom - handleBottomSize), black); + AddLine(BPoint(r.right, r.bottom - handleBottomSize + 1.0), + BPoint(r.right, r.bottom), black); + AddLine(BPoint(r.right - 1.0, r.bottom), + BPoint(r.left + 1.0, r.bottom), black); + EndLineArray(); + // inner red light and shadow lines + r.InsetBy(1.0, 1.0); + handleBottomSize--; + handleArrowSize -= 2.0; + BeginLineArray(10); + // upper handle + AddLine(BPoint(r.left, r.top + handleBottomSize), + BPoint(r.left, r.top), kSeekRedLight); + AddLine(BPoint(r.left + 1.0, r.top), + BPoint(r.right, r.top), kSeekRedLight); + AddLine(BPoint(r.right, r.top + 1.0), + BPoint(r.right, r.top + handleBottomSize), kSeekRedShadow); + AddLine(BPoint(r.right - 1.0, r.top + handleBottomSize + 1.0), + BPoint(knobPos, r.top + handleArrowSize), kSeekRedShadow); + AddLine(BPoint(knobPos - 1.0, r.top + handleArrowSize - 1.0), + BPoint(r.left + 1.0, r.top + handleBottomSize + 1.0), kSeekRedLight); + // lower handle + AddLine(BPoint(r.left, r.bottom), + BPoint(r.left, r.bottom - handleBottomSize), kSeekRedLight); + AddLine(BPoint(r.left + 1.0, r.bottom - handleBottomSize - 1.0), + BPoint(knobPos, r.bottom - handleArrowSize), kSeekRedLight); + AddLine(BPoint(knobPos + 1.0, r.bottom - handleArrowSize + 1.0), + BPoint(r.right, r.bottom - handleBottomSize), kSeekRedShadow); + AddLine(BPoint(r.right, r.bottom - handleBottomSize + 1.0), + BPoint(r.right, r.bottom), kSeekRedShadow); + AddLine(BPoint(r.right - 1.0, r.bottom), + BPoint(r.left + 1.0, r.bottom), kSeekRedShadow); + EndLineArray(); + // fill rest of handles with red + SetHighColor(kSeekRed); + r.InsetBy(1.0, 1.0); + handleArrowSize -= 2.0; + BPoint arrow[3]; + // upper handle arrow + arrow[0].x = r.left; + arrow[0].y = r.top; + arrow[1].x = r.right; + arrow[1].y = r.top; + arrow[2].x = knobPos; + arrow[2].y = r.top + handleArrowSize; + FillPolygon(arrow, 3); + // lower handle arrow + arrow[0].x = r.left; + arrow[0].y = r.bottom; + arrow[1].x = r.right; + arrow[1].y = r.bottom; + arrow[2].x = knobPos; + arrow[2].y = r.bottom - handleArrowSize; + FillPolygon(arrow, 3); + } else { + // *** disabled look *** + r.InsetBy(1.0, 1.0); + _StrokeFrame(r, darkShadow, darkShadow, darkShadow, darkShadow); + r.InsetBy(1.0, 1.0); + _StrokeFrame(r, darkShadow, darkShadow, darkShadow, darkShadow); + r.InsetBy(1.0, 1.0); + SetHighColor(darkShadow); + SetLowColor(shadow); + // stripes + float width = floorf(StringWidth(kDisabledSeekMessage)); + float textPos = r.left + r.Width() / 2.0 - width / 2.0; + pattern stripes = { { 0xc7, 0x8f, 0x1f, 0x3e, 0x7c, 0xf8, 0xf1, 0xe3 } }; + BRect stripesRect(r); + stripesRect.right = textPos - 5.0; + FillRect(stripesRect, stripes); + stripesRect.left = textPos + width + 3.0; + stripesRect.right = r.right; + FillRect(stripesRect, stripes); + // info text + r.left = textPos - 4.0; + r.right = textPos + width + 2.0; + FillRect(r); + SetHighColor(shadow); + SetLowColor(darkShadow); + font_height fh; + GetFontHeight(&fh); + DrawString(kDisabledSeekMessage, BPoint(textPos, r.top + ceilf(fh.ascent) - 1.0)); + } +} + + +void +SeekSlider::MouseDown(BPoint where) +{ + if (IsEnabled() && Bounds().Contains(where)) { + SetValue(_ValueFor(where.x)); + fTracking = true; + SetMouseEventMask(B_POINTER_EVENTS, B_LOCK_WINDOW_FOCUS); + } +} + + +void +SeekSlider::MouseMoved(BPoint where, uint32 code, const BMessage* dragMessage) +{ + if (fTracking) { + SetValue(_ValueFor(where.x)); + } +} + + +void +SeekSlider::MouseUp(BPoint where) +{ + if (fTracking) { + fTracking = false; + } +} + + + +void +SeekSlider::ResizeToPreferred() +{ + float width = 15.0 + StringWidth(kDisabledSeekMessage) + 15.0; + ResizeTo(width, 17.0); +} + + +void +SeekSlider::SetPosition(float position) +{ + SetValue(fMinValue + (int32)floorf((fMaxValue - fMinValue) * position + 0.5)); +} + + +// #pragma mark - + + +int32 +SeekSlider::_ValueFor(float xPos) const +{ + BRect r(Bounds()); + float knobWidth2 = SEEK_SLIDER_KNOB_WIDTH / 2.0; + float sliderStart = (r.left + knobWidth2); + float sliderEnd = (r.right - knobWidth2); + int32 value = fMinValue + (int32)(((xPos - sliderStart) * (fMaxValue - fMinValue)) + / (sliderEnd - sliderStart - 1.0)); + if (value < fMinValue) + value = fMinValue; + if (value > fMaxValue) + value = fMaxValue; + return value; +} + + +void +SeekSlider::_StrokeFrame(BRect r, rgb_color left, rgb_color top, + rgb_color right, rgb_color bottom) +{ + BeginLineArray(4); + AddLine(BPoint(r.left, r.bottom), BPoint(r.left, r.top), left); + AddLine(BPoint(r.left + 1.0, r.top), BPoint(r.right, r.top), top); + AddLine(BPoint(r.right, r.top + 1.0), BPoint(r.right, r.bottom), right); + AddLine(BPoint(r.right - 1.0, r.bottom), BPoint(r.left + 1.0, r.bottom), bottom); + EndLineArray(); +} + + + + diff --git a/src/apps/mediaplayer/SeekSlider.h b/src/apps/mediaplayer/SeekSlider.h new file mode 100644 index 0000000000..7e4617c828 --- /dev/null +++ b/src/apps/mediaplayer/SeekSlider.h @@ -0,0 +1,52 @@ +/* + * Copyright 2006, Haiku. + * Distributed under the terms of the MIT License. + * + * Authors: + * Stephan Aßmus + */ + +#ifndef SEEK_SLIDER_H +#define SEEK_SLIDER_H + +#include +#include + +class SeekSlider : public BControl { + public: + SeekSlider(BRect frame, + const char* name, + BMessage* message, + int32 minValue, + int32 maxValue); + + virtual ~SeekSlider(); + + // BControl interface + virtual void AttachedToWindow(); + virtual void SetValue(int32 value); + virtual void Draw(BRect updateRect); + virtual void MouseDown(BPoint where); + virtual void MouseMoved(BPoint where, uint32 transit, + const BMessage* dragMessage); + virtual void MouseUp(BPoint where); + virtual void ResizeToPreferred(); + + // SeekSlider + void SetPosition(float position); + +private: + int32 _ValueFor(float x) const; + void _StrokeFrame(BRect frame, + rgb_color left, + rgb_color top, + rgb_color right, + rgb_color bottom); + + bool fTracking; + int32 fMinValue; + int32 fMaxValue; +}; + + +#endif //SEEK_SLIDER_H diff --git a/src/apps/mediaplayer/TransportControlGroup.cpp b/src/apps/mediaplayer/TransportControlGroup.cpp index 62efae5f44..a33a4f809f 100644 --- a/src/apps/mediaplayer/TransportControlGroup.cpp +++ b/src/apps/mediaplayer/TransportControlGroup.cpp @@ -19,9 +19,11 @@ #include "ButtonBitmaps.h" #include "TransportButton.h" +#include "SeekSlider.h" #include "VolumeSlider.h" enum { + MSG_SEEK = 'seek', MSG_PLAY = 'play', MSG_STOP = 'stop', MSG_REWIND = 'rwnd', @@ -38,6 +40,9 @@ enum { #define VOLUME_MIN_WIDTH 70.0 #define VOLUME_SLIDER_LAYOUT_WEIGHT 2.0 +#define kMaxVolume 1024 +#define kMaxSeekPos 65535 + // constructor TransportControlGroup::TransportControlGroup(BRect frame) : BView(frame, "transport control group", @@ -48,7 +53,14 @@ TransportControlGroup::TransportControlGroup(BRect frame) SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR)); BRect frame(0.0, 0.0, 10.0, 10.0); - + + // Seek Slider + fSeekSlider = new SeekSlider(frame, "seek slider", + new BMessage(MSG_SEEK), + 0, kMaxSeekPos); + fSeekSlider->ResizeToPreferred(); + AddChild(fSeekSlider); + // Buttons // Skip Back frame.right = kRewindBitmapWidth - 1; @@ -130,7 +142,7 @@ TransportControlGroup::TransportControlGroup(BRect frame) // Volume Slider fVolumeSlider = new VolumeSlider(BRect(0.0, 0.0, VOLUME_MIN_WIDTH, kVolumeSliderBitmapHeight - 1.0), - "volume slider", 0, 255, + "volume slider", 0, kMaxVolume, new BMessage(MSG_SET_VOLUME)); fVolumeSlider->SetValue(128); AddChild(fVolumeSlider); @@ -148,6 +160,7 @@ TransportControlGroup::AttachedToWindow() SetEnabled(EnabledButtons()); // we are now a valid BHandler + fSeekSlider->SetTarget(this); fVolumeSlider->SetTarget(this); fSkipBack->SetTarget(this); fSkipForward->SetTarget(this); @@ -215,27 +228,38 @@ TransportControlGroup::MessageReceived(BMessage* message) _ToggleMute(); break; + case MSG_SEEK: + _UpdatePosition(); + break; + default: BView::MessageReceived(message); break; } } +// #pragma mark - + // default implementation for the virtuals -uint32 TransportControlGroup::EnabledButtons() { return 0; } -void TransportControlGroup::TogglePlaying() {} -void TransportControlGroup::Stop() {} -void TransportControlGroup::Rewind() {} -void TransportControlGroup::Forward() {} -void TransportControlGroup::SkipBackward() {} -void TransportControlGroup::SkipForward() {} -void TransportControlGroup::SetVolume(float value) {} -void TransportControlGroup::ToggleMute() {} +uint32 TransportControlGroup::EnabledButtons() { return 0; } +void TransportControlGroup::TogglePlaying() {} +void TransportControlGroup::Stop() {} +void TransportControlGroup::Rewind() {} +void TransportControlGroup::Forward() {} +void TransportControlGroup::SkipBackward() {} +void TransportControlGroup::SkipForward() {} +void TransportControlGroup::SetVolume(float value) {} +void TransportControlGroup::ToggleMute() {} +void TransportControlGroup::SetPosition(float value) {} + +// #pragma mark - // SetEnabled void TransportControlGroup::SetEnabled(uint32 buttons) { + fSeekSlider->SetEnabled(buttons & SEEK_ENABLED); + fVolumeSlider->SetEnabled(buttons & VOLUME_ENABLED); fMute->SetEnabled(buttons & VOLUME_ENABLED); @@ -316,13 +340,17 @@ TransportControlGroup::_LayoutControls(BRect frame) const minWidth += fMute->Bounds().Width(); minWidth += VOLUME_MIN_WIDTH; + // layout seek slider + r.bottom = r.top + fSeekSlider->Bounds().Height(); + _LayoutControl(fSeekSlider, r, true); + float currentWidth = frame.Width(); float space = (currentWidth - minWidth) / 6.0; // apply weighting space = MIN_SPACE + (space - MIN_SPACE) / VOLUME_SLIDER_LAYOUT_WEIGHT; // layout controls with "space" inbetween r.left = frame.left; - r.top = r.top + MIN_SPACE; + r.top = r.bottom + MIN_SPACE + 1.0; r.bottom = frame.bottom; // skip back r.right = r.left + fSkipBack->Bounds().Width(); @@ -375,6 +403,7 @@ TransportControlGroup::_MinFrame() const // add up height of seek slider and heighest control on bottom float minHeight = 2 * BORDER_INSET; + minHeight += fSeekSlider->Bounds().Height() + MIN_SPACE + MIN_SPACE / 2.0; minHeight += fBottomControlHeight; return BRect(0.0, 0.0, minWidth - 1.0, minHeight - 1.0); } @@ -455,4 +484,11 @@ TransportControlGroup::_ToggleMute() ToggleMute(); } +// _UpdatePosition +void +TransportControlGroup::_UpdatePosition() +{ + SetPosition((float)(fSeekSlider->Value() / (float)kMaxSeekPos)); +} + diff --git a/src/apps/mediaplayer/TransportControlGroup.h b/src/apps/mediaplayer/TransportControlGroup.h index 99296624c1..0de8b6fcc0 100644 --- a/src/apps/mediaplayer/TransportControlGroup.h +++ b/src/apps/mediaplayer/TransportControlGroup.h @@ -17,6 +17,7 @@ class PlayPauseButton; class TransportButton; +class SeekSlider; class VolumeSlider; enum { @@ -32,6 +33,7 @@ enum { SEEK_FORWARD_ENABLED = 1 << 3, SKIP_FORWARD_ENABLED = 1 << 4, VOLUME_ENABLED = 1 << 5, + SEEK_ENABLED = 1 << 6, }; class TransportControlGroup : public BView { @@ -55,6 +57,7 @@ class TransportControlGroup : public BView { virtual void SkipForward(); virtual void SetVolume(float value); virtual void ToggleMute(); + virtual void SetPosition(float value); void SetEnabled(uint32 whichButtons); @@ -82,7 +85,9 @@ class TransportControlGroup : public BView { void _SkipForward(); void _SetVolume(); void _ToggleMute(); + void _UpdatePosition(); + SeekSlider* fSeekSlider; VolumeSlider* fVolumeSlider;