/*
* Copyright 2005, Jérôme Duval. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Inspired by SoundCapture from Be newsletter (Media Kit Basics: Consumers
* and Producers)
*/
#include <stdio.h>
#include <string.h>
#include <Screen.h>
#include "TrackSlider.h"
#include "icon_button.h"
TrackSlider::TrackSlider(BRect rect, const char *title, BMessage *msg,
uint32 resizeFlags)
:
BControl(rect, "slider", NULL, msg, resizeFlags, B_WILL_DRAW
| B_FRAME_EVENTS),
fLeftTime(0),
fRightTime(1000000),
fMainTime(0),
fTotalTime(1000000),
fLeftTracking(false),
fRightTracking(false),
fMainTracking(false),
fBitmap(NULL),
fBitmapView(NULL)
{
fFont.SetSize(8.0);
fFont.SetFlags(B_DISABLE_ANTIALIASING);
int32 numFamilies = count_font_families();
for (int32 i = 0; i < numFamilies; i++ ) {
font_family family;
uint32 flags;
if ((get_font_family(i, &family, &flags) == B_OK)
&& (strcmp(family, "Baskerville") == 0)) {
fFont.SetFamilyAndFace(family, B_REGULAR_FACE);
break;
}
}
}
TrackSlider::~TrackSlider()
{
delete fBitmap;
}
void
TrackSlider::AttachedToWindow()
{
BControl::AttachedToWindow();
SetViewColor(B_TRANSPARENT_COLOR);
_InitBitmap();
_RenderBitmap();
}
void
TrackSlider::_InitBitmap()
{
if (fBitmapView) {
fBitmap->RemoveChild(fBitmapView);
delete fBitmapView;
}
if (fBitmap)
delete fBitmap;
BRect rect = Bounds();
fBitmap = new BBitmap(rect, BScreen().ColorSpace(), true);
fBitmapView = new SliderOffscreenView(rect.OffsetToSelf(B_ORIGIN), "bitmapView");
fBitmap->AddChild(fBitmapView);
fBitmapView->fRight = Bounds().right - kLeftRightTrackSliderWidth;
if (fTotalTime == 0) {
fBitmapView->fLeftX = 14;
fBitmapView->fRightX = fBitmapView->fRight;
fBitmapView->fPositionX = 15;
} else {
fBitmapView->fLeftX = 14 + (fBitmapView->fRight - 15)
* ((double)fLeftTime / fTotalTime);
fBitmapView->fRightX = 15 + (fBitmapView->fRight - 16)
* ((double)fRightTime / fTotalTime);
fBitmapView->fPositionX = 15 + (fBitmapView->fRight - 14)
* ((double)fMainTime / fTotalTime);
}
}
#define SLIDER_BASE 10
void
TrackSlider::_RenderBitmap()
{
/* rendering */
if (fBitmap->Lock()) {
fBitmapView->DrawX();
fBitmap->Unlock();
}
}
void
TrackSlider::Draw(BRect updateRect)
{
DrawBitmapAsync(fBitmap, BPoint(0,0));
_DrawCounter(fMainTime, fBitmapView->fPositionX, fMainTracking);
if (fLeftTracking)
_DrawCounter(fLeftTime, fBitmapView->fLeftX, fLeftTracking);
else if (fRightTracking)
_DrawCounter(fRightTime, fBitmapView->fRightX, fRightTracking);
_DrawMarker(fBitmapView->fPositionX);
Sync();
}
void
TrackSlider::_DrawCounter(bigtime_t timestamp, float position, bool isTracking)
{
// timecounter
rgb_color gray = {128,128,128};
rgb_color blue = {0,0,140};
rgb_color blue2 = {146,146,214};
rgb_color white = {255,255,255};
char string[12];
_TimeToString(timestamp, string);
int32 halfwidth = ((int32)fFont.StringWidth(string)) / 2;
float counterX = position;
if (counterX < 39)
counterX = 39;
if (counterX > fBitmapView->fRight - 23)
counterX = fBitmapView->fRight - 23;
BeginLineArray(4);
if (!isTracking) {
AddLine(BPoint(counterX-halfwidth-3,SLIDER_BASE+1),
BPoint(counterX+halfwidth+3,SLIDER_BASE+1), gray);
AddLine(BPoint(counterX+halfwidth+4,SLIDER_BASE+1),
BPoint(counterX+halfwidth+4,SLIDER_BASE-8), gray);
AddLine(BPoint(counterX-halfwidth-4,SLIDER_BASE+1),
BPoint(counterX-halfwidth-4,SLIDER_BASE-9), white);
AddLine(BPoint(counterX-halfwidth-3,SLIDER_BASE-9),
BPoint(counterX+halfwidth+4,SLIDER_BASE-9), white);
SetHighColor(216,216,216);
} else {
AddLine(BPoint(counterX-halfwidth-3,SLIDER_BASE+1),
BPoint(counterX+halfwidth+3,SLIDER_BASE+1), blue);
AddLine(BPoint(counterX+halfwidth+4,SLIDER_BASE+1),
BPoint(counterX+halfwidth+4,SLIDER_BASE-9), blue2);
AddLine(BPoint(counterX-halfwidth-4,SLIDER_BASE+1),
BPoint(counterX-halfwidth-4,SLIDER_BASE-9), blue2);
AddLine(BPoint(counterX-halfwidth-3,SLIDER_BASE-9),
BPoint(counterX+halfwidth+3,SLIDER_BASE-9), blue2);
SetHighColor(48,48,241);
}
EndLineArray();
FillRect(BRect(counterX-halfwidth-3,SLIDER_BASE-8,counterX+halfwidth+3,
SLIDER_BASE));
#ifdef __HAIKU__
SetDrawingMode(B_OP_OVER);
#else
SetDrawingMode(B_OP_COPY);
#endif
if (isTracking)
SetHighColor(255,255,255);
else
SetHighColor(0,0,0);
SetLowColor(ViewColor());
SetFont(&fFont);
DrawString(string, BPoint(counterX-halfwidth, SLIDER_BASE-1));
}
void
TrackSlider::_DrawMarker(float position)
{
rgb_color black = {0,0,0};
rgb_color rose = {255,152,152};
rgb_color red = {255,0,0};
rgb_color bordeau = {178,0,0};
rgb_color white = {255,255,255};
BeginLineArray(30);
AddLine(BPoint(position,SLIDER_BASE+7), BPoint(position-4,SLIDER_BASE+3),
black);
AddLine(BPoint(position-4,SLIDER_BASE+3), BPoint(position-4,SLIDER_BASE+1),
black);
AddLine(BPoint(position-4,SLIDER_BASE+1), BPoint(position+4,SLIDER_BASE+1),
black);
AddLine(BPoint(position+4,SLIDER_BASE+1), BPoint(position+4,SLIDER_BASE+3),
black);
AddLine(BPoint(position+4,SLIDER_BASE+3), BPoint(position,SLIDER_BASE+7),
black);
AddLine(BPoint(position-3,SLIDER_BASE+2), BPoint(position+3,SLIDER_BASE+2),
rose);
AddLine(BPoint(position-3,SLIDER_BASE+3), BPoint(position-1,SLIDER_BASE+5),
rose);
AddLine(BPoint(position-2,SLIDER_BASE+3), BPoint(position+2,SLIDER_BASE+3),
red);
AddLine(BPoint(position-1,SLIDER_BASE+4), BPoint(position+1,SLIDER_BASE+4),
red);
AddLine(BPoint(position,SLIDER_BASE+5), BPoint(position,SLIDER_BASE+5),
red);
AddLine(BPoint(position,SLIDER_BASE+6), BPoint(position+3,SLIDER_BASE+3),
bordeau);
AddLine(BPoint(position,SLIDER_BASE+12), BPoint(position-4,SLIDER_BASE+16),
black);
AddLine(BPoint(position-4,SLIDER_BASE+16), BPoint(position-4,
SLIDER_BASE+17), black);
AddLine(BPoint(position-4,SLIDER_BASE+17), BPoint(position+4,
SLIDER_BASE+17), black);
AddLine(BPoint(position+4,SLIDER_BASE+17), BPoint(position+4,
SLIDER_BASE+16), black);
AddLine(BPoint(position+4,SLIDER_BASE+16), BPoint(position,SLIDER_BASE+12),
black);
AddLine(BPoint(position-4,SLIDER_BASE+18), BPoint(position+4,
SLIDER_BASE+18), white);
AddLine(BPoint(position-3,SLIDER_BASE+16), BPoint(position,SLIDER_BASE+13),
rose);
AddLine(BPoint(position-2,SLIDER_BASE+16), BPoint(position+2,
SLIDER_BASE+16), red);
AddLine(BPoint(position-1,SLIDER_BASE+15), BPoint(position+1,
SLIDER_BASE+15), red);
AddLine(BPoint(position,SLIDER_BASE+14), BPoint(position,
SLIDER_BASE+14), red);
AddLine(BPoint(position+1,SLIDER_BASE+14), BPoint(position+3,
SLIDER_BASE+16), bordeau);
EndLineArray();
}
void
TrackSlider::MouseMoved(BPoint point, uint32 transit, const BMessage *message)
{
if (!IsTracking())
return;
uint32 mouseButtons;
BPoint where;
GetMouse(&where, &mouseButtons, true);
// button not pressed, exit
if (! (mouseButtons & B_PRIMARY_MOUSE_BUTTON)) {
Invoke();
SetTracking(false);
}
_UpdatePosition(point);
}
void
TrackSlider::MouseDown(BPoint point)
{
if (!Bounds().InsetBySelf(2,2).Contains(point))
return;
_UpdatePosition(point);
SetTracking(true);
SetMouseEventMask(B_POINTER_EVENTS, B_NO_POINTER_HISTORY
| B_LOCK_WINDOW_FOCUS);
}
void
TrackSlider::MouseUp(BPoint point)
{
if (!IsTracking())
return;
if (Bounds().InsetBySelf(2,2).Contains(point)) {
_UpdatePosition(point);
}
fLeftTracking = fRightTracking = fMainTracking = false;
Invoke();
SetTracking(false);
Draw(Bounds());
Flush();
}
void
TrackSlider::_UpdatePosition(BPoint point)
{
BRect leftRect(fBitmapView->fLeftX-9, SLIDER_BASE+3, fBitmapView->fLeftX,
SLIDER_BASE+16);
BRect rightRect(fBitmapView->fRightX, SLIDER_BASE+3,
fBitmapView->fRightX+9, SLIDER_BASE+16);
if (!(fRightTracking || fMainTracking) && (fLeftTracking
|| ((point.x < fBitmapView->fPositionX-4) && leftRect.Contains(point)))) {
if (!IsTracking())
fBitmapView->fLastX = point.x - fBitmapView->fLeftX;
fBitmapView->fLeftX = MIN(MAX(point.x - fBitmapView->fLastX, 15),
fBitmapView->fRight);
fLeftTime = (bigtime_t)(MAX(MIN((fBitmapView->fLeftX - 15)
/ (fBitmapView->fRight - 14),1), 0) * fTotalTime);
fLeftTracking = true;
BMessage msg = *Message();
msg.AddInt64("left", fLeftTime);
if (fBitmapView->fPositionX < fBitmapView->fLeftX) {
fBitmapView->fPositionX = fBitmapView->fLeftX + 1;
fMainTime = fLeftTime;
msg.AddInt64("main", fMainTime);
if (fBitmapView->fRightX < fBitmapView->fPositionX) {
fBitmapView->fRightX = fBitmapView->fPositionX;
fRightTime = fMainTime;
msg.AddInt64("right", fRightTime);
}
}
Invoke(&msg);
_RenderBitmap();
//printf("fLeftPos : %Ld\n", fLeftTime);
} else if (!fMainTracking && (fRightTracking
|| ((point.x > fBitmapView->fPositionX+4)
&& rightRect.Contains(point)))) {
if (!IsTracking())
fBitmapView->fLastX = point.x - fBitmapView->fRightX;
fBitmapView->fRightX = MIN(MAX(point.x - fBitmapView->fLastX, 15),
fBitmapView->fRight);
fRightTime = (bigtime_t)(MAX(MIN((fBitmapView->fRightX - 15)
/ (fBitmapView->fRight - 14),1), 0) * fTotalTime);
fRightTracking = true;
BMessage msg = *Message();
msg.AddInt64("right", fRightTime);
if (fBitmapView->fPositionX > fBitmapView->fRightX) {
fBitmapView->fPositionX = fBitmapView->fRightX;
fMainTime = fRightTime;
msg.AddInt64("main", fMainTime);
if (fBitmapView->fLeftX > fBitmapView->fPositionX) {
fBitmapView->fLeftX = fBitmapView->fPositionX - 1;
fLeftTime = fMainTime;
msg.AddInt64("left", fLeftTime);
}
}
Invoke(&msg);
_RenderBitmap();
//printf("fRightPos : %Ld\n", fRightTime);
} else {
fBitmapView->fPositionX = MIN(MAX(point.x, 15), fBitmapView->fRight);
fMainTime = (bigtime_t)(MAX(MIN((fBitmapView->fPositionX - 15)
/ (fBitmapView->fRight - 14),1), 0) * fTotalTime);
fMainTracking = true;
BMessage msg = *Message();
msg.AddInt64("main", fMainTime);
if (fBitmapView->fRightX < fBitmapView->fPositionX) {
fBitmapView->fRightX = fBitmapView->fPositionX;
fRightTime = fMainTime;
msg.AddInt64("right", fRightTime);
_RenderBitmap();
} else if (fBitmapView->fLeftX > fBitmapView->fPositionX) {
fBitmapView->fLeftX = fBitmapView->fPositionX - 1;
fLeftTime = fMainTime;
msg.AddInt64("left", fLeftTime);
_RenderBitmap();
}
Invoke(&msg);
//printf("fPosition : %Ld\n", fMainTime);
}
Draw(Bounds());
Flush();
}
void
TrackSlider::_TimeToString(bigtime_t timestamp, char *string)
{
uint32 hours = timestamp / 3600000000LL;
timestamp -= hours * 3600000000LL;
uint32 minutes = timestamp / 60000000LL;
timestamp -= minutes * 60000000LL;
uint32 seconds = timestamp / 1000000LL;
timestamp -= seconds * 1000000LL;
uint32 centiseconds = timestamp / 10000LL;
sprintf(string, "%02" B_PRId32 ":%02" B_PRId32 ":%02" B_PRId32 ":%02"
B_PRId32, hours, minutes, seconds, centiseconds);
}
void
TrackSlider::SetMainTime(bigtime_t timestamp, bool reset)
{
fMainTime = timestamp;
fBitmapView->fPositionX = 15 + (fBitmapView->fRight - 14)
* ((double)fMainTime / fTotalTime);
if (reset) {
fRightTime = fTotalTime;
fLeftTime = 0;
fBitmapView->fLeftX = 14 + (fBitmapView->fRight - 15)
* ((double)fLeftTime / fTotalTime);
fBitmapView->fRightX = 15 + (fBitmapView->fRight - 16)
* ((double)fRightTime / fTotalTime);
_RenderBitmap();
}
Invalidate();
}
void
TrackSlider::SetTotalTime(bigtime_t timestamp, bool reset)
{
fTotalTime = timestamp;
if (reset) {
fMainTime = 0;
fRightTime = fTotalTime;
fLeftTime = 0;
}
fBitmapView->fPositionX = 15 + (fBitmapView->fRight - 14)
* ((double)fMainTime / fTotalTime);
fBitmapView->fLeftX = 14 + (fBitmapView->fRight - 15)
* ((double)fLeftTime / fTotalTime);
fBitmapView->fRightX = 15 + (fBitmapView->fRight - 16)
* ((double)fRightTime / fTotalTime);
_RenderBitmap();
Invalidate();
}
void
TrackSlider::ResetMainTime()
{
fMainTime = fLeftTime;
fBitmapView->fPositionX = 15 + (fBitmapView->fRight - 14)
* ((double)fMainTime / fTotalTime);
Invalidate();
}
void
TrackSlider::FrameResized(float width, float height)
{
fBitmapView->fRight = Bounds().right - kLeftRightTrackSliderWidth;
fBitmapView->fPositionX = 15 + (fBitmapView->fRight - 14)
* ((double)fMainTime / fTotalTime);
_InitBitmap();
fBitmapView->fLeftX = 14 + (fBitmapView->fRight - 15)
* ((double)fLeftTime / fTotalTime);
fBitmapView->fRightX = 15 + (fBitmapView->fRight - 16)
* ((double)fRightTime / fTotalTime);
_RenderBitmap();
Invalidate();
}
SliderOffscreenView::SliderOffscreenView(BRect frame, const char *name)
: BView(frame, name, B_FOLLOW_LEFT | B_FOLLOW_TOP, B_WILL_DRAW),
leftBitmap(BRect(BPoint(0,0), kLeftRightTrackSliderSize), B_CMAP8),
rightBitmap(BRect(BPoint(0,0), kLeftRightTrackSliderSize), B_CMAP8),
leftThumbBitmap(BRect(0, 0, kLeftRightThumbWidth - 1,
kLeftRightThumbHeight - 1), B_CMAP8),
rightThumbBitmap(BRect(0, 0, kLeftRightThumbWidth - 1,
kLeftRightThumbHeight - 1), B_CMAP8)
{
leftBitmap.SetBits(kLeftTrackSliderBits,
kLeftRightTrackSliderWidth * kLeftRightTrackSliderHeight, 0, B_CMAP8);
rightBitmap.SetBits(kRightTrackSliderBits,
kLeftRightTrackSliderWidth * kLeftRightTrackSliderHeight, 0, B_CMAP8);
leftThumbBitmap.SetBits(kLeftThumbBits,
kLeftRightThumbWidth * kLeftRightThumbHeight, 0, B_CMAP8);
rightThumbBitmap.SetBits(kRightThumbBits,
kLeftRightThumbWidth * kLeftRightThumbHeight, 0, B_CMAP8);
}
SliderOffscreenView::~SliderOffscreenView()
{
}
void
SliderOffscreenView::DrawX()
{
SetHighColor(ui_color(B_PANEL_BACKGROUND_COLOR));
FillRect(Bounds());
SetHighColor(189, 186, 189);
StrokeLine(BPoint(11, SLIDER_BASE + 1), BPoint(fRight, SLIDER_BASE + 1));
SetHighColor(0, 0, 0);
StrokeLine(BPoint(11, SLIDER_BASE + 2), BPoint(fRight, SLIDER_BASE + 2));
SetHighColor(255, 255, 255);
StrokeLine(BPoint(11, SLIDER_BASE + 17), BPoint(fRight, SLIDER_BASE + 17));
SetHighColor(231, 227, 231);
StrokeLine(BPoint(11, SLIDER_BASE + 18), BPoint(fRight, SLIDER_BASE + 18));
SetDrawingMode(B_OP_OVER);
SetLowColor(HighColor());
BPoint leftPoint(5, SLIDER_BASE + 1);
DrawBitmapAsync(&leftBitmap, BRect(BPoint(0, 0),
kLeftRightTrackSliderSize - BPoint(5, 0)),
BRect(leftPoint, leftPoint + kLeftRightTrackSliderSize - BPoint(5, 0)));
BPoint rightPoint(fRight + 1, SLIDER_BASE + 1);
DrawBitmapAsync(&rightBitmap, BRect(BPoint(5, 0), kLeftRightTrackSliderSize),
BRect(rightPoint, rightPoint + kLeftRightTrackSliderSize-BPoint(5, 0)));
SetHighColor(153, 153, 153);
FillRect(BRect(11, SLIDER_BASE + 3, fLeftX - 9, SLIDER_BASE + 16));
FillRect(BRect(fRightX + 9, SLIDER_BASE + 3, fRight, SLIDER_BASE + 16));
if (fLeftX > 19) {
StrokeLine(BPoint(fLeftX - 9, SLIDER_BASE + 3), BPoint(fLeftX - 6,
SLIDER_BASE + 3));
StrokeLine(BPoint(fLeftX - 9, SLIDER_BASE + 4), BPoint(fLeftX - 7,
SLIDER_BASE + 4));
StrokeLine(BPoint(fLeftX - 9, SLIDER_BASE + 5), BPoint(fLeftX - 8,
SLIDER_BASE + 5));
StrokeLine(BPoint(fLeftX - 9, SLIDER_BASE + 16), BPoint(fLeftX - 6,
SLIDER_BASE + 16));
StrokeLine(BPoint(fLeftX - 9, SLIDER_BASE + 15), BPoint(fLeftX - 7,
SLIDER_BASE + 15));
StrokeLine(BPoint(fLeftX - 9, SLIDER_BASE + 14), BPoint(fLeftX - 8,
SLIDER_BASE + 14));
}
if (fRightX < fRight - 5) {
StrokeLine(BPoint(fRightX + 5, SLIDER_BASE + 3), BPoint(fRightX + 8,
SLIDER_BASE + 3));
StrokeLine(BPoint(fRightX + 7, SLIDER_BASE + 4), BPoint(fRightX + 8,
SLIDER_BASE + 4));
StrokeLine(BPoint(fRightX + 8, SLIDER_BASE + 5), BPoint(fRightX + 8,
SLIDER_BASE + 6));
StrokeLine(BPoint(fRightX + 8, SLIDER_BASE + 13), BPoint(fRightX + 8,
SLIDER_BASE + 14));
StrokeLine(BPoint(fRightX + 5, SLIDER_BASE + 16), BPoint(fRightX + 8,
SLIDER_BASE + 16));
StrokeLine(BPoint(fRightX + 7, SLIDER_BASE + 15), BPoint(fRightX + 8,
SLIDER_BASE + 15));
}
SetHighColor(144, 186, 136);
FillRect(BRect(fLeftX + 1, SLIDER_BASE + 3, fRightX, SLIDER_BASE + 4));
FillRect(BRect(fLeftX + 1, SLIDER_BASE + 5, fLeftX + 2, SLIDER_BASE + 16));
SetHighColor(171, 221, 161);
FillRect(BRect(fLeftX + 3, SLIDER_BASE + 5, fRightX, SLIDER_BASE + 16));
int i = 17;
int j = 18;
SetHighColor(128, 128, 128);
for (; i < fLeftX - 9; i += 6) {
StrokeLine(BPoint(i, SLIDER_BASE + 7), BPoint(i, SLIDER_BASE + 13));
}
SetHighColor(179, 179, 179);
for (; j < fLeftX - 9; j += 6) {
StrokeLine(BPoint(j, SLIDER_BASE + 7), BPoint(j, SLIDER_BASE + 13));
}
while (i <= fLeftX)
i += 6;
while (j <= fLeftX)
j += 6;
SetHighColor(144, 186, 136);
for (; i <= fRightX; i += 6) {
StrokeLine(BPoint(i, SLIDER_BASE + 7), BPoint(i, SLIDER_BASE + 13));
}
SetHighColor(189, 244, 178);
for (; j <= fRightX; j += 6) {
StrokeLine(BPoint(j, SLIDER_BASE + 7), BPoint(j, SLIDER_BASE + 13));
}
while (i <= fRightX + 9)
i += 6;
while (j <= fRightX + 9)
j += 6;
SetHighColor(128, 128, 128);
for (; i <= fRight + 1; i += 6) {
StrokeLine(BPoint(i, SLIDER_BASE + 7), BPoint(i, SLIDER_BASE + 13));
}
SetHighColor(179, 179, 179);
for (; j <= fRight + 1; j += 6) {
StrokeLine(BPoint(j, SLIDER_BASE + 7), BPoint(j, SLIDER_BASE + 13));
}
SetLowColor(HighColor());
BPoint leftThumbPoint(fLeftX - 8, SLIDER_BASE + 3);
DrawBitmapAsync(&leftThumbBitmap, BRect(BPoint(0, 0),
kLeftRightThumbSize - BPoint(7, 0)),
BRect(leftThumbPoint, leftThumbPoint
+ kLeftRightThumbSize - BPoint(7, 0)));
BPoint rightThumbPoint(fRightX, SLIDER_BASE + 3);
DrawBitmapAsync(&rightThumbBitmap, BRect(BPoint(6, 0),
kLeftRightThumbSize),
BRect(rightThumbPoint, rightThumbPoint
+ kLeftRightThumbSize-BPoint(6, 0)));
Sync();
}
↑ V595 The 'fBitmap' pointer was utilized before it was verified against nullptr. Check lines: 68, 71.
↑ V730 Not all members of a class are initialized inside the constructor. Consider inspecting: fRight, fLeftX, fRightX, fPositionX, fLastX.