2 * Copyright (C) 2001-2010 Stephan Aßmus. All rights reserved.
3 * Distributed under the terms of the MIT license.
5 * Copyright (C) 1998-1999 Be Incorporated. All rights reseved.
6 * Distributed under the terms of the Be Sample Code license.
18 #include <ControlLook.h>
22 #include <MessageRunner.h>
23 #include <Messenger.h>
24 #include <PopUpMenu.h>
28 #undef B_TRANSLATION_CONTEXT
29 #define B_TRANSLATION_CONTEXT "MediaPlayer-PeakView"
37 MSG_LOCK_PEAKS
= 'lpks'
41 PeakView::PeakView(const char* name
, bool useGlobalPulse
, bool displayLabels
)
43 BView(name
, (useGlobalPulse
? B_PULSE_NEEDED
: 0)
44 | B_WILL_DRAW
| B_FRAME_EVENTS
| B_FULL_UPDATE_ON_RESIZE
),
45 fUseGlobalPulse(useGlobalPulse
),
46 fDisplayLabels(displayLabels
),
57 fPeakNotificationWhat(0)
59 GetFontHeight(&fFontHeight
);
61 SetLowColor(ui_color(B_PANEL_BACKGROUND_COLOR
));
62 SetViewColor(B_TRANSPARENT_COLOR
);
72 delete[] fChannelInfos
;
77 PeakView::MessageReceived(BMessage
* message
)
79 if (message
->what
== fPeakNotificationWhat
) {
81 for (int32 i
= 0; message
->FindFloat("max", i
, &max
) == B_OK
; i
++)
87 switch (message
->what
) {
93 fPeakLocked
= !fPeakLocked
;
97 BView::MessageReceived(message
);
104 PeakView::AttachedToWindow()
106 if (!fUseGlobalPulse
) {
108 BMessage
message(MSG_PULSE
);
109 fPulse
= new BMessageRunner(BMessenger(this), &message
,
116 PeakView::DetachedFromWindow()
124 PeakView::MouseDown(BPoint where
)
127 if (Window()->CurrentMessage()->FindInt32("buttons", &buttons
) < B_OK
)
128 buttons
= B_PRIMARY_MOUSE_BUTTON
;
130 if (buttons
& B_PRIMARY_MOUSE_BUTTON
) {
131 // Reset the overshot flag and set the observed max to the current
133 for (uint32 i
= 0; i
< fChannelCount
; i
++) {
134 fChannelInfos
[i
].last_overshot_time
= -5000000;
135 fChannelInfos
[i
].last_max
= fChannelInfos
[i
].current_max
;
137 } else if (buttons
& B_TERTIARY_MOUSE_BUTTON
) {
138 // Toggle locking of the observed max value.
139 fPeakLocked
= !fPeakLocked
;
141 // Display context menu
142 BPopUpMenu
* menu
= new BPopUpMenu("peak context menu");
143 BMenuItem
* item
= new BMenuItem(B_TRANSLATE("Lock Peaks"),
144 new BMessage(MSG_LOCK_PEAKS
));
145 item
->SetMarked(fPeakLocked
);
147 menu
->SetTargetForItems(this);
149 menu
->SetAsyncAutoDestruct(true);
150 menu
->SetFont(be_plain_font
);
152 where
= ConvertToScreen(where
);
153 bool keepOpen
= false; // ?
155 BRect
mouseRect(where
, where
);
156 mouseRect
.InsetBy(-3.0, -3.0);
157 where
+= BPoint(3.0, 3.0);
158 menu
->Go(where
, true, false, mouseRect
, true);
160 where
+= BPoint(3.0, 3.0);
161 menu
->Go(where
, true, false, true);
168 PeakView::Draw(BRect updateRect
)
170 BRect
r(_BackBitmapFrame());
171 float width
= r
.Width();
172 r
.InsetBy(-2.0, -2.0);
174 be_control_look
->DrawTextControlBorder(this, r
, updateRect
, LowColor());
181 if (fDisplayLabels
) {
184 float y
= Bounds().bottom
;
186 DrawString("0", BPoint(4.0 + width
- StringWidth("0"), y
));
187 DrawString("-6", BPoint(0.477 * width
, y
));
188 DrawString("-12", BPoint(0.227 * width
, y
));
194 PeakView::FrameResized(float width
, float height
)
196 BRect bitmapFrame
= _BackBitmapFrame();
197 _ResizeBackBitmap(bitmapFrame
.IntegerWidth() + 1, fChannelCount
);
208 if (fBackBitmap
== NULL
)
212 for (uint32 i
= 0; i
< fChannelCount
; i
++) {
213 fChannelInfos
[i
].last_max
*= 0.96f
;
214 if (fChannelInfos
[i
].current_max
> fChannelInfos
[i
].last_max
)
215 fChannelInfos
[i
].last_max
= fChannelInfos
[i
].current_max
;
220 for (uint32 i
= 0; i
< fChannelCount
; i
++)
221 fChannelInfos
[i
].current_max
= 0.0f
;
232 float minWidth
= 20 + 4;
233 float minHeight
= 2 * 8 - 1 + 4;
234 if (fDisplayLabels
) {
237 minWidth
= max_c(60.0, minWidth
);
238 minHeight
+= ceilf(fh
.ascent
+ fh
.descent
);
240 return BSize(minWidth
, minHeight
);
245 PeakView::IsValid() const
247 return fBackBitmap
!= NULL
&& fBackBitmap
->IsValid()
248 && fChannelInfos
!= NULL
;
253 PeakView::SetPeakRefreshDelay(bigtime_t delay
)
255 if (fRefreshDelay
== delay
)
258 fRefreshDelay
= delay
;
261 fPulse
->SetInterval(fRefreshDelay
);
266 PeakView::SetPeakNotificationWhat(uint32 what
)
268 fPeakNotificationWhat
= what
;
273 PeakView::SetChannelCount(uint32 channelCount
)
275 if (channelCount
== fChannelCount
)
278 delete[] fChannelInfos
;
279 fChannelInfos
= new(std::nothrow
) ChannelInfo
[channelCount
];
280 if (fChannelInfos
!= NULL
) {
281 fChannelCount
= channelCount
;
282 for (uint32 i
= 0; i
< fChannelCount
; i
++) {
283 fChannelInfos
[i
].current_max
= 0.0f
;
284 fChannelInfos
[i
].last_max
= 0.0f
;
285 fChannelInfos
[i
].last_overshot_time
= -5000000;
287 _ResizeBackBitmap(_BackBitmapFrame().IntegerWidth() + 1,
295 PeakView::SetMax(float max
, uint32 channel
)
297 if (channel
>= fChannelCount
)
300 if (fChannelInfos
[channel
].current_max
< max
)
301 fChannelInfos
[channel
].current_max
= max
;
303 if (fChannelInfos
[channel
].current_max
> 1.0)
304 fChannelInfos
[channel
].last_overshot_time
= system_time();
312 PeakView::_BackBitmapFrame() const
314 BRect frame
= Bounds();
317 frame
.bottom
-= ceilf(fFontHeight
.ascent
+ fFontHeight
.descent
);
323 PeakView::_ResizeBackBitmap(int32 width
, int32 channels
)
325 if (fBackBitmap
!= NULL
) {
326 if (fBackBitmap
->Bounds().IntegerWidth() + 1 == width
327 && fBackBitmap
->Bounds().IntegerHeight() + 1 == channels
) {
335 BRect
bounds(0, 0, width
- 1, channels
- 1);
336 fBackBitmap
= new(std::nothrow
) BBitmap(bounds
, 0, B_RGB32
);
337 if (fBackBitmap
== NULL
|| !fBackBitmap
->IsValid()) {
342 memset(fBackBitmap
->Bits(), 0, fBackBitmap
->BitsLength());
348 PeakView::_UpdateBackBitmap()
353 uint8
* span
= (uint8
*)fBackBitmap
->Bits();
354 uint32 width
= fBackBitmap
->Bounds().IntegerWidth() + 1;
355 for (uint32 i
= 0; i
< fChannelCount
; i
++) {
356 _RenderSpan(span
, width
, fChannelInfos
[i
].current_max
,
357 fChannelInfos
[i
].last_max
,
358 system_time() - fChannelInfos
[i
].last_overshot_time
< 2000000);
359 span
+= fBackBitmap
->BytesPerRow();
365 PeakView:: _RenderSpan(uint8
* span
, uint32 width
, float current
, float peak
,
377 uint8 currentG
= 255;
388 uint8 kFadeFactor
= 100;
390 uint32 evenWidth
= width
- width
% 2;
391 uint32 split
= (uint32
)(current
* (evenWidth
- 1) + 0.5);
393 uint32 last
= (uint32
)(peak
* (evenWidth
- 1) + 0.5);
395 uint32 over
= overshot
? evenWidth
: evenWidth
+ 1;
398 for (uint32 x
= 0; x
< width
; x
+= 2) {
399 uint8 fadedB
= (uint8
)(((int)span
[0] * kFadeFactor
) >> 8);
400 uint8 fadedG
= (uint8
)(((int)span
[1] * kFadeFactor
) >> 8);
401 uint8 fadedR
= (uint8
)(((int)span
[2] * kFadeFactor
) >> 8);
403 span
[0] = max_c(fillB
, fadedB
);
404 span
[1] = max_c(fillG
, fadedG
);
405 span
[2] = max_c(fillR
, fadedR
);
406 } else if (x
== split
) {
410 } else if (x
> split
) {
411 span
[0] = max_c(emptyB
, fadedB
);
412 span
[1] = max_c(emptyG
, fadedG
);
413 span
[2] = max_c(emptyR
, fadedR
);
431 PeakView::_DrawBitmap()
433 SetHighColor(0, 0, 0);
434 BRect bitmapFrame
= _BackBitmapFrame();
435 BRect bitmapRect
= fBackBitmap
->Bounds();
436 bitmapRect
.bottom
= bitmapRect
.top
;
437 float channelHeight
= (bitmapFrame
.Height() + 1) / fChannelCount
;
438 for (uint32 i
= 0; i
< fChannelCount
; i
++) {
439 BRect
viewRect(bitmapFrame
);
440 viewRect
.bottom
= viewRect
.top
;
441 viewRect
.top
+= floorf(i
* channelHeight
+ 0.5);
442 if (i
< fChannelCount
- 1) {
443 viewRect
.bottom
+= floorf((i
+ 1) * channelHeight
+ 0.5) - 2;
444 StrokeLine(BPoint(viewRect
.left
, viewRect
.bottom
+ 1),
445 BPoint(viewRect
.right
, viewRect
.bottom
+ 1));
447 viewRect
.bottom
+= floorf((i
+ 1) * channelHeight
+ 0.5) - 1;
448 DrawBitmapAsync(fBackBitmap
, bitmapRect
, viewRect
);
449 bitmapRect
.OffsetBy(0, 1);