btrfs: Attempt to fix GCC2 build.
[haiku.git] / src / apps / mediaplayer / interface / TransportControlGroup.cpp
blob3a4c06c8d74820fdaaeb8d66a6c6da67bdd71b04
1 /*
2 * Copyright 2006-2010 Stephan Aßmus <superstippi@gmx.de>
3 * All rights reserved. Distributed under the terms of the MIT License.
4 */
7 // NOTE: Based on my code in the BeOS interface for the VLC media player
8 // that I did during the VLC 0.4.3 - 0.4.6 times. Code not written by me
9 // removed. -Stephan Aßmus
12 #include "TransportControlGroup.h"
14 #include <stdio.h>
15 #include <string.h>
17 #include <Shape.h>
18 #include <SpaceLayoutItem.h>
19 #include <String.h>
20 #include <ToolTipManager.h>
21 #include <Window.h>
23 #include "DurationView.h"
24 #include "PeakView.h"
25 #include "PlaybackState.h"
26 #include "PlayPauseButton.h"
27 #include "PositionToolTip.h"
28 #include "SeekSlider.h"
29 #include "SymbolButton.h"
30 #include "VolumeSlider.h"
32 enum {
33 MSG_SEEK = 'seek',
34 MSG_PLAY = 'play',
35 MSG_STOP = 'stop',
36 MSG_REWIND = 'rwnd',
37 MSG_FORWARD = 'frwd',
38 MSG_SKIP_BACKWARDS = 'skpb',
39 MSG_SKIP_FORWARD = 'skpf',
40 MSG_SET_VOLUME = 'stvl',
41 MSG_SET_MUTE = 'stmt',
42 MSG_DURATION_TOOLTIP = 'msdt'
45 // the range of the volume sliders (in dB)
46 #define kVolumeDbMax 6.0
47 #define kVolumeDbMin -60.0
48 // a power function for non linear sliders
49 #define kVolumeDbExpPositive 1.4 // for dB values > 0
50 #define kVolumeDbExpNegative 1.9 // for dB values < 0
52 #define kVolumeFactor 100
53 #define kPositionFactor 3000
56 TransportControlGroup::TransportControlGroup(BRect frame, bool useSkipButtons,
57 bool usePeakView, bool useWindButtons)
59 BGroupView(B_VERTICAL, 0),
60 fSeekSlider(NULL),
61 fDurationView(NULL),
62 fPositionToolTip(NULL),
63 fPeakView(NULL),
64 fVolumeSlider(NULL),
65 fSkipBack(NULL),
66 fSkipForward(NULL),
67 fRewind(NULL),
68 fForward(NULL),
69 fPlayPause(NULL),
70 fStop(NULL),
71 fMute(NULL),
72 fSymbolScale(1.0f),
73 fLastEnabledButtons(0)
75 // Pick a symbol size based on the current system font size, but make
76 // sure the size is uneven, so the pointy shapes have their middle on
77 // a pixel instead of between two pixels.
78 float symbolHeight = int(be_plain_font->Size() / 1.33) | 1;
80 BGroupView* seekGroup = new BGroupView(B_HORIZONTAL, 0);
81 fSeekLayout = seekGroup->GroupLayout();
82 GroupLayout()->AddView(seekGroup);
84 // Seek slider
85 fSeekSlider = new SeekSlider("seek slider", new BMessage(MSG_SEEK),
86 0, kPositionFactor);
87 fSeekLayout->AddView(fSeekSlider);
89 fPositionToolTip = new PositionToolTip();
90 fSeekSlider->SetToolTip(fPositionToolTip);
92 // Duration view
93 fDurationView = new DurationView("duration view");
94 fSeekLayout->AddView(fDurationView);
96 // Buttons
98 uint32 topBottomBorder = BControlLook::B_TOP_BORDER
99 | BControlLook::B_BOTTOM_BORDER;
101 if (useSkipButtons) {
102 // Skip Back
103 fSkipBack = new SymbolButton(B_EMPTY_STRING,
104 _CreateSkipBackwardsShape(symbolHeight),
105 new BMessage(MSG_SKIP_BACKWARDS),
106 BControlLook::B_LEFT_BORDER | topBottomBorder);
107 // Skip Foward
108 fSkipForward = new SymbolButton(B_EMPTY_STRING,
109 _CreateSkipForwardShape(symbolHeight),
110 new BMessage(MSG_SKIP_FORWARD),
111 BControlLook::B_RIGHT_BORDER | topBottomBorder);
114 if (useWindButtons) {
115 // Rewind
116 fRewind = new SymbolButton(B_EMPTY_STRING,
117 _CreateRewindShape(symbolHeight), new BMessage(MSG_REWIND),
118 useSkipButtons ? topBottomBorder
119 : BControlLook::B_LEFT_BORDER | topBottomBorder);
120 // Forward
121 fForward = new SymbolButton(B_EMPTY_STRING,
122 _CreateForwardShape(symbolHeight), new BMessage(MSG_FORWARD),
123 useSkipButtons ? topBottomBorder
124 : BControlLook::B_RIGHT_BORDER | topBottomBorder);
127 // Play Pause
128 fPlayPause = new PlayPauseButton(B_EMPTY_STRING,
129 _CreatePlayShape(symbolHeight), _CreatePauseShape(symbolHeight),
130 new BMessage(MSG_PLAY), useWindButtons || useSkipButtons
131 ? topBottomBorder
132 : topBottomBorder | BControlLook::B_LEFT_BORDER);
134 // Stop
135 fStop = new SymbolButton(B_EMPTY_STRING,
136 _CreateStopShape(symbolHeight), new BMessage(MSG_STOP),
137 useWindButtons || useSkipButtons ? topBottomBorder
138 : topBottomBorder | BControlLook::B_RIGHT_BORDER);
140 // Mute
141 fMute = new SymbolButton(B_EMPTY_STRING,
142 _CreateSpeakerShape(floorf(symbolHeight * 0.9)),
143 new BMessage(MSG_SET_MUTE), 0);
145 // Volume Slider
146 fVolumeSlider = new VolumeSlider("volume slider",
147 _DbToGain(_ExponentialToLinear(kVolumeDbMin)) * kVolumeFactor,
148 _DbToGain(_ExponentialToLinear(kVolumeDbMax)) * kVolumeFactor,
149 kVolumeFactor, new BMessage(MSG_SET_VOLUME));
150 fVolumeSlider->SetValue(_DbToGain(_ExponentialToLinear(0.0))
151 * kVolumeFactor);
153 // Peak view
154 if (usePeakView)
155 fPeakView = new PeakView("peak view", false, false);
157 // Layout the controls
159 BGroupView* buttonGroup = new BGroupView(B_HORIZONTAL, 0);
160 BGroupLayout* buttonLayout = buttonGroup->GroupLayout();
162 if (fSkipBack != NULL)
163 buttonLayout->AddView(fSkipBack);
164 if (fRewind != NULL)
165 buttonLayout->AddView(fRewind);
166 buttonLayout->AddView(fPlayPause);
167 buttonLayout->AddView(fStop);
168 if (fForward != NULL)
169 buttonLayout->AddView(fForward);
170 if (fSkipForward != NULL)
171 buttonLayout->AddView(fSkipForward);
173 BGroupView* controlGroup = new BGroupView(B_HORIZONTAL, 0);
174 GroupLayout()->AddView(controlGroup);
175 fControlLayout = controlGroup->GroupLayout();
176 fControlLayout->AddView(buttonGroup, 0.6f);
177 fControlLayout->AddItem(BSpaceLayoutItem::CreateHorizontalStrut(5));
178 fControlLayout->AddView(fMute);
179 fControlLayout->AddView(fVolumeSlider);
180 if (fPeakView != NULL)
181 fControlLayout->AddView(fPeakView, 0.6f);
183 // Figure out the visual insets of the slider bounds towards the slider
184 // bar, and use that as insets for the rest of the layout.
185 float inset = fSeekSlider->BarFrame().left;
186 float hInset = inset - fSeekSlider->BarFrame().top;
187 if (hInset < 0.0f)
188 hInset = 0.0f;
190 fSeekLayout->SetInsets(0, hInset, 5, 0);
191 fControlLayout->SetInsets(inset, hInset, inset, inset);
193 BSize size = fControlLayout->MinSize();
194 size.width *= 3;
195 size.height = B_SIZE_UNSET;
196 fControlLayout->SetExplicitMaxSize(size);
197 fControlLayout->SetExplicitAlignment(BAlignment(B_ALIGN_CENTER,
198 B_ALIGN_TOP));
202 TransportControlGroup::~TransportControlGroup()
204 if (!fSeekSlider->IsEnabled())
205 fPositionToolTip->ReleaseReference();
209 void
210 TransportControlGroup::AttachedToWindow()
212 SetEnabled(EnabledButtons());
214 // we are now a valid BHandler
215 fSeekSlider->SetTarget(this);
216 fVolumeSlider->SetTarget(this);
217 if (fSkipBack)
218 fSkipBack->SetTarget(this);
219 if (fSkipForward)
220 fSkipForward->SetTarget(this);
221 if (fRewind)
222 fRewind->SetTarget(this);
223 if (fForward)
224 fForward->SetTarget(this);
225 fPlayPause->SetTarget(this);
226 fStop->SetTarget(this);
227 fMute->SetTarget(this);
231 void
232 TransportControlGroup::GetPreferredSize(float* _width, float* _height)
234 BSize size = GroupLayout()->MinSize();
235 if (_width != NULL)
236 *_width = size.width;
237 if (_height != NULL)
238 *_height = size.height;
242 void
243 TransportControlGroup::MessageReceived(BMessage* message)
245 switch (message->what) {
246 case MSG_PLAY:
247 _TogglePlaying();
248 break;
249 case MSG_STOP:
250 _Stop();
251 break;
253 case MSG_REWIND:
254 _Rewind();
255 break;
256 case MSG_FORWARD:
257 _Forward();
258 break;
260 case MSG_SKIP_BACKWARDS:
261 _SkipBackward();
262 break;
263 case MSG_SKIP_FORWARD:
264 _SkipForward();
265 break;
267 case MSG_SET_VOLUME:
268 _UpdateVolume();
269 break;
270 case MSG_SET_MUTE:
271 _ToggleMute();
272 break;
274 case MSG_SEEK:
275 _UpdatePosition();
276 break;
278 case MSG_DURATION_TOOLTIP:
280 BToolTipManager* manager = BToolTipManager::Manager();
281 BPoint tipPoint;
282 GetMouse(&tipPoint, NULL, false);
283 manager->ShowTip(fPositionToolTip, tipPoint, this);
284 break;
287 default:
288 BView::MessageReceived(message);
289 break;
294 // #pragma mark - default implementation for the virtuals
297 uint32
298 TransportControlGroup::EnabledButtons()
300 return fLastEnabledButtons;
304 void TransportControlGroup::TogglePlaying() {}
305 void TransportControlGroup::Stop() {}
306 void TransportControlGroup::Rewind() {}
307 void TransportControlGroup::Forward() {}
308 void TransportControlGroup::SkipBackward() {}
309 void TransportControlGroup::SkipForward() {}
310 void TransportControlGroup::VolumeChanged(float value) {}
311 void TransportControlGroup::ToggleMute() {}
312 void TransportControlGroup::PositionChanged(float value) {}
315 // #pragma mark -
318 float
319 TransportControlGroup::_LinearToExponential(float dbIn)
321 float db = dbIn;
322 if (db >= 0) {
323 db = db * (pow(fabs(kVolumeDbMax), (1.0 / kVolumeDbExpPositive))
324 / fabs(kVolumeDbMax));
325 db = pow(db, kVolumeDbExpPositive);
326 } else {
327 db = -db;
328 db = db * (pow(fabs(kVolumeDbMin), (1.0 / kVolumeDbExpNegative))
329 / fabs(kVolumeDbMin));
330 db = pow(db, kVolumeDbExpNegative);
331 db = -db;
333 return db;
337 float
338 TransportControlGroup::_ExponentialToLinear(float dbIn)
340 float db = dbIn;
341 if (db >= 0) {
342 db = pow(db, (1.0 / kVolumeDbExpPositive));
343 db = db * (fabs(kVolumeDbMax) / pow(fabs(kVolumeDbMax),
344 (1.0 / kVolumeDbExpPositive)));
345 } else {
346 db = -db;
347 db = pow(db, (1.0 / kVolumeDbExpNegative));
348 db = db * (fabs(kVolumeDbMin) / pow(fabs(kVolumeDbMin),
349 (1.0 / kVolumeDbExpNegative)));
350 db = -db;
352 return db;
356 float
357 TransportControlGroup::_DbToGain(float db)
359 return pow(10.0, db / 20.0);
363 float
364 TransportControlGroup::_GainToDb(float gain)
366 return 20.0 * log10(gain);
370 // #pragma mark -
373 void
374 TransportControlGroup::SetEnabled(uint32 buttons)
376 if (!LockLooper())
377 return;
379 fLastEnabledButtons = buttons;
381 fSeekSlider->SetEnabled(buttons & SEEK_ENABLED);
382 fSeekSlider->SetToolTip((buttons & SEEK_ENABLED) != 0
383 ? fPositionToolTip : NULL);
385 fVolumeSlider->SetEnabled(buttons & VOLUME_ENABLED);
386 fMute->SetEnabled(buttons & VOLUME_ENABLED);
388 if (fSkipBack)
389 fSkipBack->SetEnabled(buttons & SKIP_BACK_ENABLED);
390 if (fSkipForward)
391 fSkipForward->SetEnabled(buttons & SKIP_FORWARD_ENABLED);
392 if (fRewind)
393 fRewind->SetEnabled(buttons & SEEK_BACK_ENABLED);
394 if (fForward)
395 fForward->SetEnabled(buttons & SEEK_FORWARD_ENABLED);
397 fPlayPause->SetEnabled(buttons & PLAYBACK_ENABLED);
398 fStop->SetEnabled(buttons & PLAYBACK_ENABLED);
400 UnlockLooper();
404 // #pragma mark -
407 void
408 TransportControlGroup::SetPlaybackState(uint32 state)
410 if (!LockLooper())
411 return;
413 switch (state) {
414 case PLAYBACK_STATE_PLAYING:
415 fPlayPause->SetPlaying();
416 break;
417 case PLAYBACK_STATE_PAUSED:
418 fPlayPause->SetPaused();
419 break;
420 case PLAYBACK_STATE_STOPPED:
421 fPlayPause->SetStopped();
422 break;
425 UnlockLooper();
429 void
430 TransportControlGroup::SetSkippable(bool backward, bool forward)
432 if (!LockLooper())
433 return;
435 if (fSkipBack)
436 fSkipBack->SetEnabled(backward);
437 if (fSkipForward)
438 fSkipForward->SetEnabled(forward);
440 UnlockLooper();
444 // #pragma mark -
447 void
448 TransportControlGroup::SetAudioEnabled(bool enabled)
450 if (!LockLooper())
451 return;
453 fMute->SetEnabled(enabled);
454 fVolumeSlider->SetEnabled(enabled);
456 UnlockLooper();
460 void
461 TransportControlGroup::SetMuted(bool mute)
463 if (!LockLooper())
464 return;
466 fVolumeSlider->SetMuted(mute);
468 UnlockLooper();
472 void
473 TransportControlGroup::SetVolume(float value)
475 float db = _GainToDb(value);
476 float exponential = _LinearToExponential(db);
477 float gain = _DbToGain(exponential);
478 int32 pos = (int32)(floorf(gain * kVolumeFactor + 0.5));
480 fVolumeSlider->SetValue(pos);
484 void
485 TransportControlGroup::SetAudioChannelCount(int32 count)
487 fPeakView->SetChannelCount(count);
491 void
492 TransportControlGroup::SetPosition(float value, bigtime_t position,
493 bigtime_t duration)
495 fPositionToolTip->Update(position, duration);
496 fDurationView->Update(position, duration);
498 if (fSeekSlider->IsTracking())
499 return;
501 fSeekSlider->SetPosition(value);
505 float
506 TransportControlGroup::Position() const
508 return fSeekSlider->Position();
512 void
513 TransportControlGroup::SetDisabledString(const char* string)
515 fSeekSlider->SetDisabledString(string);
519 void
520 TransportControlGroup::SetSymbolScale(float scale)
522 if (scale == fSymbolScale)
523 return;
525 fSymbolScale = scale;
527 if (fSeekSlider != NULL)
528 fSeekSlider->SetSymbolScale(scale);
529 if (fVolumeSlider != NULL) {
530 fVolumeSlider->SetBarThickness(fVolumeSlider->PreferredBarThickness()
531 * scale);
533 if (fDurationView != NULL)
534 fDurationView->SetSymbolScale(scale);
536 float symbolHeight = int(scale * be_plain_font->Size() / 1.33) | 1;
538 if (fSkipBack != NULL)
539 fSkipBack->SetSymbol(_CreateSkipBackwardsShape(symbolHeight));
540 if (fSkipForward != NULL)
541 fSkipForward->SetSymbol(_CreateSkipForwardShape(symbolHeight));
542 if (fRewind != NULL)
543 fRewind->SetSymbol(_CreateRewindShape(symbolHeight));
544 if (fForward != NULL)
545 fForward->SetSymbol(_CreateForwardShape(symbolHeight));
546 if (fPlayPause != NULL) {
547 fPlayPause->SetSymbols(_CreatePlayShape(symbolHeight),
548 _CreatePauseShape(symbolHeight));
550 if (fStop != NULL)
551 fStop->SetSymbol(_CreateStopShape(symbolHeight));
552 if (fMute != NULL)
553 fMute->SetSymbol(_CreateSpeakerShape(floorf(symbolHeight * 0.9)));
555 // Figure out the visual insets of the slider bounds towards the slider
556 // bar, and use that as insets for the rest of the layout.
557 float barInset = fSeekSlider->BarFrame().left;
558 float inset = barInset * scale;
559 float hInset = inset - fSeekSlider->BarFrame().top;
560 if (hInset < 0.0f)
561 hInset = 0.0f;
563 fSeekLayout->SetInsets(inset - barInset, hInset, inset, 0);
564 fSeekLayout->SetSpacing(inset - barInset);
565 fControlLayout->SetInsets(inset, hInset, inset, inset);
566 fControlLayout->SetSpacing(inset - barInset);
568 ResizeTo(Bounds().Width(), GroupLayout()->MinSize().height);
571 // #pragma mark -
574 void
575 TransportControlGroup::_TogglePlaying()
577 TogglePlaying();
581 void
582 TransportControlGroup::_Stop()
584 fPlayPause->SetStopped();
585 Stop();
589 void
590 TransportControlGroup::_Rewind()
592 Rewind();
596 void
597 TransportControlGroup::_Forward()
599 Forward();
603 void
604 TransportControlGroup::_SkipBackward()
606 SkipBackward();
610 void
611 TransportControlGroup::_SkipForward()
613 SkipForward();
617 void
618 TransportControlGroup::_UpdateVolume()
620 float pos = fVolumeSlider->Value() / (float)kVolumeFactor;
621 float db = _ExponentialToLinear(_GainToDb(pos));
622 float gain = _DbToGain(db);
623 VolumeChanged(gain);
627 void
628 TransportControlGroup::_ToggleMute()
630 fVolumeSlider->SetMuted(!fVolumeSlider->IsMuted());
631 ToggleMute();
635 void
636 TransportControlGroup::_UpdatePosition()
638 PositionChanged(fSeekSlider->Value() / (float)kPositionFactor);
640 BMessage msg(MSG_DURATION_TOOLTIP);
641 Window()->PostMessage(&msg, this);
645 // #pragma mark -
648 BShape*
649 TransportControlGroup::_CreateSkipBackwardsShape(float height) const
651 BShape* shape = new BShape();
653 float stopWidth = ceilf(height / 6);
655 shape->MoveTo(BPoint(-stopWidth, height));
656 shape->LineTo(BPoint(0, height));
657 shape->LineTo(BPoint(0, 0));
658 shape->LineTo(BPoint(-stopWidth, 0));
659 shape->Close();
661 shape->MoveTo(BPoint(0, height / 2));
662 shape->LineTo(BPoint(height, height));
663 shape->LineTo(BPoint(height, 0));
664 shape->Close();
666 shape->MoveTo(BPoint(height, height / 2));
667 shape->LineTo(BPoint(height * 2, height));
668 shape->LineTo(BPoint(height * 2, 0));
669 shape->Close();
671 return shape;
675 BShape*
676 TransportControlGroup::_CreateSkipForwardShape(float height) const
678 BShape* shape = new BShape();
680 shape->MoveTo(BPoint(height, height / 2));
681 shape->LineTo(BPoint(0, height));
682 shape->LineTo(BPoint(0, 0));
683 shape->Close();
685 shape->MoveTo(BPoint(height * 2, height / 2));
686 shape->LineTo(BPoint(height, height));
687 shape->LineTo(BPoint(height, 0));
688 shape->Close();
690 float stopWidth = ceilf(height / 6);
692 shape->MoveTo(BPoint(height * 2, height));
693 shape->LineTo(BPoint(height * 2 + stopWidth, height));
694 shape->LineTo(BPoint(height * 2 + stopWidth, 0));
695 shape->LineTo(BPoint(height * 2, 0));
696 shape->Close();
698 return shape;
702 BShape*
703 TransportControlGroup::_CreateRewindShape(float height) const
705 BShape* shape = new BShape();
707 shape->MoveTo(BPoint(0, height / 2));
708 shape->LineTo(BPoint(height, height));
709 shape->LineTo(BPoint(height, 0));
710 shape->Close();
712 shape->MoveTo(BPoint(height, height / 2));
713 shape->LineTo(BPoint(height * 2, height));
714 shape->LineTo(BPoint(height * 2, 0));
715 shape->Close();
717 return shape;
721 BShape*
722 TransportControlGroup::_CreateForwardShape(float height) const
724 BShape* shape = new BShape();
726 shape->MoveTo(BPoint(height, height / 2));
727 shape->LineTo(BPoint(0, height));
728 shape->LineTo(BPoint(0, 0));
729 shape->Close();
731 shape->MoveTo(BPoint(height * 2, height / 2));
732 shape->LineTo(BPoint(height, height));
733 shape->LineTo(BPoint(height, 0));
734 shape->Close();
736 return shape;
740 BShape*
741 TransportControlGroup::_CreatePlayShape(float height) const
743 BShape* shape = new BShape();
745 float step = floorf(height / 8);
747 shape->MoveTo(BPoint(height + step, height / 2));
748 shape->LineTo(BPoint(-step, height + step));
749 shape->LineTo(BPoint(-step, 0 - step));
750 shape->Close();
752 return shape;
756 BShape*
757 TransportControlGroup::_CreatePauseShape(float height) const
759 BShape* shape = new BShape();
761 float stemWidth = floorf(height / 3);
763 shape->MoveTo(BPoint(0, height));
764 shape->LineTo(BPoint(stemWidth, height));
765 shape->LineTo(BPoint(stemWidth, 0));
766 shape->LineTo(BPoint(0, 0));
767 shape->Close();
769 shape->MoveTo(BPoint(height - stemWidth, height));
770 shape->LineTo(BPoint(height, height));
771 shape->LineTo(BPoint(height, 0));
772 shape->LineTo(BPoint(height - stemWidth, 0));
773 shape->Close();
775 return shape;
779 BShape*
780 TransportControlGroup::_CreateStopShape(float height) const
782 BShape* shape = new BShape();
784 shape->MoveTo(BPoint(0, height));
785 shape->LineTo(BPoint(height, height));
786 shape->LineTo(BPoint(height, 0));
787 shape->LineTo(BPoint(0, 0));
788 shape->Close();
790 return shape;
794 static void
795 add_bow(BShape* shape, float offset, float size, float height, float step)
797 float width = floorf(size * 2 / 3);
798 float outerControlHeight = size * 2 / 3;
799 float outerControlWidth = size / 4;
800 float innerControlHeight = size / 2;
801 float innerControlWidth = size / 5;
802 // left/bottom
803 shape->MoveTo(BPoint(offset, height / 2 + size));
804 // outer bow, to middle
805 shape->BezierTo(
806 BPoint(offset + outerControlWidth, height / 2 + size),
807 BPoint(offset + width, height / 2 + outerControlHeight),
808 BPoint(offset + width, height / 2)
810 // outer bow, to left/top
811 shape->BezierTo(
812 BPoint(offset + width, height / 2 - outerControlHeight),
813 BPoint(offset + outerControlWidth, height / 2 - size),
814 BPoint(offset, height / 2 - size)
816 // inner bow, to middle
817 shape->BezierTo(
818 BPoint(offset + innerControlWidth, height / 2 - size),
819 BPoint(offset + width - step, height / 2 - innerControlHeight),
820 BPoint(offset + width - step, height / 2)
822 // inner bow, back to left/bottom
823 shape->BezierTo(
824 BPoint(offset + width - step, height / 2 + innerControlHeight),
825 BPoint(offset + innerControlWidth, height / 2 + size),
826 BPoint(offset, height / 2 + size)
828 shape->Close();
832 BShape*
833 TransportControlGroup::_CreateSpeakerShape(float height) const
835 BShape* shape = new BShape();
837 float step = floorf(height / 8);
838 float magnetWidth = floorf(height / 5);
839 float chassieWidth = floorf(height / 1.5);
840 float chassieHeight = floorf(height / 4);
842 shape->MoveTo(BPoint(0, height - step));
843 shape->LineTo(BPoint(magnetWidth, height - step));
844 shape->LineTo(BPoint(magnetWidth, height / 2 + chassieHeight));
845 shape->LineTo(BPoint(magnetWidth + chassieWidth - step, height + step));
846 shape->LineTo(BPoint(magnetWidth + chassieWidth, height + step));
847 shape->LineTo(BPoint(magnetWidth + chassieWidth, -step));
848 shape->LineTo(BPoint(magnetWidth + chassieWidth - step, -step));
849 shape->LineTo(BPoint(magnetWidth, height / 2 - chassieHeight));
850 shape->LineTo(BPoint(magnetWidth, step));
851 shape->LineTo(BPoint(0, step));
852 shape->Close();
854 float offset = magnetWidth + chassieWidth + step * 2;
855 add_bow(shape, offset, 3 * step, height, step * 2);
856 offset += step * 2;
857 add_bow(shape, offset, 5 * step, height, step * 2);
858 offset += step * 2;
859 add_bow(shape, offset, 7 * step, height, step * 2);
861 return shape;