xref: /haiku/src/apps/soundrecorder/TrackSlider.cpp (revision fef6144999c2fa611f59ee6ffe6dd7999501385c)
1 /*
2  * Copyright 2005, Jérôme Duval. All rights reserved.
3  * Distributed under the terms of the MIT License.
4  *
5  * Inspired by SoundCapture from Be newsletter (Media Kit Basics: Consumers and Producers)
6  */
7 
8 #include <stdio.h>
9 
10 #include "TrackSlider.h"
11 #include "icon_button.h"
12 
13 TrackSlider::TrackSlider(BRect rect, const char *title, BMessage *msg, uint32 resizeFlags)
14 	: BControl(rect, "slider", NULL, msg, resizeFlags, B_WILL_DRAW | B_FRAME_EVENTS),
15 	leftBitmap(BRect(BPoint(0,0), kLeftRightTrackSliderSize), B_CMAP8),
16 	rightBitmap(BRect(BPoint(0,0), kLeftRightTrackSliderSize), B_CMAP8),
17 	leftThumbBitmap(BRect(0, 0, kLeftRightThumbWidth - 1, kLeftRightThumbHeight - 1), B_CMAP8),
18 	rightThumbBitmap(BRect(0, 0, kLeftRightThumbWidth - 1, kLeftRightThumbHeight - 1), B_CMAP8),
19 	fLeftTime(0), fRightTime(1000000), fMainTime(0), fTotalTime(1000000),
20 	fLeftTracking(false), fRightTracking(false), fMainTracking(false)
21 {
22 	fFont.SetSize(8.0);
23 	fFont.SetFlags(B_DISABLE_ANTIALIASING);
24 
25 	int32 numFamilies = count_font_families();
26 	for (int32 i = 0; i < numFamilies; i++ ) {
27 		font_family family;
28 		uint32 flags;
29 		if ((get_font_family(i, &family, &flags) == B_OK)
30 			&& (strcmp(family, "Baskerville") == 0)) {
31 			fFont.SetFamilyAndFace(family, B_REGULAR_FACE);
32 			break;
33 		}
34 	}
35 	leftBitmap.SetBits(kLeftTrackSliderBits, kLeftRightTrackSliderWidth * kLeftRightTrackSliderHeight, 0, B_CMAP8);
36 	rightBitmap.SetBits(kRightTrackSliderBits, kLeftRightTrackSliderWidth * kLeftRightTrackSliderHeight, 0, B_CMAP8);
37 	leftThumbBitmap.SetBits(kLeftThumbBits, kLeftRightThumbWidth * kLeftRightThumbHeight, 0, B_CMAP8);
38 	rightThumbBitmap.SetBits(kRightThumbBits, kLeftRightThumbWidth * kLeftRightThumbHeight, 0, B_CMAP8);
39 
40 	fRight = Bounds().right - kLeftRightTrackSliderWidth;
41 	if (fTotalTime == 0) {
42 		fLeftX = 14;
43 		fRightX = fRight;
44 		fPositionX = 15;
45 	} else {
46 		fLeftX = 14 + (fRight - 15) * ((double)fLeftTime / fTotalTime);
47 		fRightX = 15 + (fRight - 16) * ((double)fRightTime / fTotalTime);
48 		fPositionX = 15 + (fRight - 14) * ((double)fMainTime / fTotalTime);
49 	}
50 }
51 
52 
53 TrackSlider::~TrackSlider()
54 {
55 
56 }
57 
58 
59 void
60 TrackSlider::AttachedToWindow()
61 {
62 	BControl::AttachedToWindow();
63 	SetViewColor(B_TRANSPARENT_COLOR);
64 }
65 
66 
67 #define SLIDER_BASE 10
68 
69 void
70 TrackSlider::Draw(BRect updateRect)
71 {
72 	SetHighColor(189,186,189);
73 	StrokeLine(BPoint(11,SLIDER_BASE+1), BPoint(fRight,SLIDER_BASE+1));
74 	SetHighColor(0,0,0);
75 	StrokeLine(BPoint(11,SLIDER_BASE+2), BPoint(fRight,SLIDER_BASE+2));
76 	SetHighColor(255,255,255);
77 	StrokeLine(BPoint(11,SLIDER_BASE+17), BPoint(fRight,SLIDER_BASE+17));
78 	SetHighColor(231,227,231);
79 	StrokeLine(BPoint(11,SLIDER_BASE+18), BPoint(fRight,SLIDER_BASE+18));
80 
81 	SetDrawingMode(B_OP_OVER);
82 
83 	SetHighColor(216,216,216);
84 	FillRect(BRect(0,1,fPositionX < 18 ? 18 : fPositionX-26,SLIDER_BASE));
85 	FillRect(BRect(fPositionX < 18 ? 65 : fPositionX > fRight - 3 ? fRight : fPositionX+26,0,Bounds().right,SLIDER_BASE));
86 	FillRect(BRect(0,0,Bounds().right,0));
87 	FillRect(BRect(0,SLIDER_BASE+18,Bounds().right,SLIDER_BASE+21));
88 	FillRect(BRect(0,0,10,SLIDER_BASE+21));
89 	FillRect(BRect(Bounds().right - 10,0,Bounds().right,SLIDER_BASE+21));
90 
91 	SetLowColor(HighColor());
92 
93 	BPoint leftPoint(5,SLIDER_BASE+1);
94 	DrawBitmapAsync(&leftBitmap, BRect(BPoint(0,0), kLeftRightTrackSliderSize - BPoint(5,0)),
95 		BRect(leftPoint, leftPoint+kLeftRightTrackSliderSize-BPoint(5,0)));
96 	BPoint rightPoint(fRight + 1,SLIDER_BASE+1);
97 	DrawBitmapAsync(&rightBitmap, BRect(BPoint(5,0), kLeftRightTrackSliderSize),
98 		BRect(rightPoint, rightPoint+kLeftRightTrackSliderSize-BPoint(5,0)));
99 
100 	SetHighColor(153,153,153);
101 	FillRect(BRect(11,SLIDER_BASE+3,fLeftX-9,SLIDER_BASE+16));
102 	FillRect(BRect(fRightX+9,SLIDER_BASE+3,fRight,SLIDER_BASE+16));
103 	if (fLeftX>19) {
104 		StrokeLine(BPoint(fLeftX-9,SLIDER_BASE+3),BPoint(fLeftX-6,SLIDER_BASE+3));
105 		StrokeLine(BPoint(fLeftX-9,SLIDER_BASE+4),BPoint(fLeftX-7,SLIDER_BASE+4));
106 		StrokeLine(BPoint(fLeftX-9,SLIDER_BASE+5),BPoint(fLeftX-8,SLIDER_BASE+5));
107 		StrokeLine(BPoint(fLeftX-9,SLIDER_BASE+16),BPoint(fLeftX-6,SLIDER_BASE+16));
108 		StrokeLine(BPoint(fLeftX-9,SLIDER_BASE+15),BPoint(fLeftX-7,SLIDER_BASE+15));
109 		StrokeLine(BPoint(fLeftX-9,SLIDER_BASE+14),BPoint(fLeftX-8,SLIDER_BASE+14));
110 	}
111 	if (fRightX < fRight - 5) {
112 		StrokeLine(BPoint(fRightX+5,SLIDER_BASE+3),BPoint(fRightX+8,SLIDER_BASE+3));
113 		StrokeLine(BPoint(fRightX+7,SLIDER_BASE+4),BPoint(fRightX+8,SLIDER_BASE+4));
114 		StrokeLine(BPoint(fRightX+8,SLIDER_BASE+5),BPoint(fRightX+8,SLIDER_BASE+6));
115 		StrokeLine(BPoint(fRightX+8,SLIDER_BASE+13),BPoint(fRightX+8,SLIDER_BASE+14));
116 		StrokeLine(BPoint(fRightX+5,SLIDER_BASE+16),BPoint(fRightX+8,SLIDER_BASE+16));
117 		StrokeLine(BPoint(fRightX+7,SLIDER_BASE+15),BPoint(fRightX+8,SLIDER_BASE+15));
118 	}
119 	SetHighColor(144,186,136);
120 	FillRect(BRect(fLeftX+1,SLIDER_BASE+3,fRightX,SLIDER_BASE+4));
121 	FillRect(BRect(fLeftX+1,SLIDER_BASE+5,fLeftX+2,SLIDER_BASE+16));
122 	SetHighColor(171,221,161);
123 	FillRect(BRect(fLeftX+3,SLIDER_BASE+5,fRightX,SLIDER_BASE+16));
124 
125 	int i = 17;
126 	int j = 18;
127 	SetHighColor(128,128,128);
128 	for (; i<fLeftX-9; i+=6) {
129 		StrokeLine(BPoint(i,SLIDER_BASE+7), BPoint(i,SLIDER_BASE+13));
130 	}
131 	SetHighColor(179,179,179);
132 	for (; j<fLeftX-9; j+=6) {
133 		StrokeLine(BPoint(j,SLIDER_BASE+7), BPoint(j,SLIDER_BASE+13));
134 	}
135 
136 	while (i<=fLeftX)
137 		i+=6;
138 	while (j<=fLeftX)
139 		j+=6;
140 
141 	SetHighColor(144,186,136);
142 	for (; i<=fRightX; i+=6) {
143 		StrokeLine(BPoint(i,SLIDER_BASE+7), BPoint(i,SLIDER_BASE+13));
144 	}
145 	SetHighColor(189,244,178);
146 	for (; j<=fRightX; j+=6) {
147 		StrokeLine(BPoint(j,SLIDER_BASE+7), BPoint(j,SLIDER_BASE+13));
148 	}
149 
150 	while (i<=fRightX+9)
151 		i+=6;
152 	while (j<=fRightX+9)
153 		j+=6;
154 
155 	SetHighColor(128,128,128);
156 	for (; i<=fRight + 1; i+=6) {
157 		StrokeLine(BPoint(i,SLIDER_BASE+7), BPoint(i,SLIDER_BASE+13));
158 	}
159 	SetHighColor(179,179,179);
160 	for (; j<=fRight + 1; j+=6) {
161 		StrokeLine(BPoint(j,SLIDER_BASE+7), BPoint(j,SLIDER_BASE+13));
162 	}
163 
164 	SetLowColor(HighColor());
165 
166 	BPoint leftThumbPoint(fLeftX-8,SLIDER_BASE+3);
167 	DrawBitmapAsync(&leftThumbBitmap, BRect(BPoint(0,0), kLeftRightThumbSize - BPoint(7,0)),
168 		BRect(leftThumbPoint, leftThumbPoint+kLeftRightThumbSize-BPoint(7,0)));
169 
170 	BPoint rightThumbPoint(fRightX,SLIDER_BASE+3);
171 	DrawBitmapAsync(&rightThumbBitmap, BRect(BPoint(6,0), kLeftRightThumbSize),
172 		BRect(rightThumbPoint, rightThumbPoint+kLeftRightThumbSize-BPoint(6,0)));
173 
174 	rgb_color black = {0,0,0};
175 	rgb_color rose = {255,152,152};
176 	rgb_color red = {255,0,0};
177 	rgb_color bordeau = {178,0,0};
178 	rgb_color white = {255,255,255};
179 
180 	DrawCounter(fMainTime, fPositionX, fMainTracking);
181 	if (fLeftTracking)
182 		DrawCounter(fLeftTime, fLeftX, fLeftTracking);
183 	else if (fRightTracking)
184 		DrawCounter(fRightTime, fRightX, fRightTracking);
185 
186 	BeginLineArray(30);
187 	AddLine(BPoint(fPositionX,SLIDER_BASE+7), BPoint(fPositionX-4,SLIDER_BASE+3), black);
188 	AddLine(BPoint(fPositionX-4,SLIDER_BASE+3), BPoint(fPositionX-4,SLIDER_BASE+1), black);
189 	AddLine(BPoint(fPositionX-4,SLIDER_BASE+1), BPoint(fPositionX+4,SLIDER_BASE+1), black);
190 	AddLine(BPoint(fPositionX+4,SLIDER_BASE+1), BPoint(fPositionX+4,SLIDER_BASE+3), black);
191 	AddLine(BPoint(fPositionX+4,SLIDER_BASE+3), BPoint(fPositionX,SLIDER_BASE+7), black);
192 
193 
194 	AddLine(BPoint(fPositionX-3,SLIDER_BASE+2), BPoint(fPositionX+3,SLIDER_BASE+2), rose);
195 	AddLine(BPoint(fPositionX-3,SLIDER_BASE+3), BPoint(fPositionX-1,SLIDER_BASE+5), rose);
196 
197 	AddLine(BPoint(fPositionX-2,SLIDER_BASE+3), BPoint(fPositionX+2,SLIDER_BASE+3), red);
198 	AddLine(BPoint(fPositionX-1,SLIDER_BASE+4), BPoint(fPositionX+1,SLIDER_BASE+4), red);
199 	AddLine(BPoint(fPositionX,SLIDER_BASE+5), BPoint(fPositionX,SLIDER_BASE+5), red);
200 
201 	AddLine(BPoint(fPositionX,SLIDER_BASE+6), BPoint(fPositionX+3,SLIDER_BASE+3), bordeau);
202 
203 	AddLine(BPoint(fPositionX,SLIDER_BASE+12), BPoint(fPositionX-4,SLIDER_BASE+16), black);
204 	AddLine(BPoint(fPositionX-4,SLIDER_BASE+16), BPoint(fPositionX-4,SLIDER_BASE+17), black);
205 	AddLine(BPoint(fPositionX-4,SLIDER_BASE+17), BPoint(fPositionX+4,SLIDER_BASE+17), black);
206 	AddLine(BPoint(fPositionX+4,SLIDER_BASE+17), BPoint(fPositionX+4,SLIDER_BASE+16), black);
207 	AddLine(BPoint(fPositionX+4,SLIDER_BASE+16), BPoint(fPositionX,SLIDER_BASE+12), black);
208 	AddLine(BPoint(fPositionX-4,SLIDER_BASE+18), BPoint(fPositionX+4,SLIDER_BASE+18), white);
209 
210 	AddLine(BPoint(fPositionX-3,SLIDER_BASE+16), BPoint(fPositionX,SLIDER_BASE+13), rose);
211 
212 	AddLine(BPoint(fPositionX-2,SLIDER_BASE+16), BPoint(fPositionX+2,SLIDER_BASE+16), red);
213 	AddLine(BPoint(fPositionX-1,SLIDER_BASE+15), BPoint(fPositionX+1,SLIDER_BASE+15), red);
214 	AddLine(BPoint(fPositionX,SLIDER_BASE+14), BPoint(fPositionX,SLIDER_BASE+14), red);
215 
216 	AddLine(BPoint(fPositionX+1,SLIDER_BASE+14), BPoint(fPositionX+3,SLIDER_BASE+16), bordeau);
217 
218 	EndLineArray();
219 
220 
221 
222 	Flush();
223 }
224 
225 
226 void
227 TrackSlider::DrawCounter(bigtime_t timestamp, float position, bool isTracking)
228 {
229 	// timecounter
230 
231 	rgb_color gray = {128,128,128};
232 	rgb_color blue = {0,0,140};
233 	rgb_color blue2 = {146,146,214};
234 	rgb_color white = {255,255,255};
235 
236 	float counterX = position;
237 	if (counterX < 39)
238 		counterX = 39;
239 	if (counterX > fRight - 23)
240 		counterX = fRight - 23;
241 	BeginLineArray(30);
242 	if (!isTracking) {
243 		AddLine(BPoint(counterX-24,SLIDER_BASE+1), BPoint(counterX+24,SLIDER_BASE+1), gray);
244 		AddLine(BPoint(counterX+25,SLIDER_BASE+1), BPoint(counterX+25,SLIDER_BASE-8), gray);
245 		AddLine(BPoint(counterX-25,SLIDER_BASE+1), BPoint(counterX-25,SLIDER_BASE-9), white);
246 		AddLine(BPoint(counterX-24,SLIDER_BASE-9), BPoint(counterX+25,SLIDER_BASE-9), white);
247 		SetHighColor(216,216,216);
248 	} else {
249 		AddLine(BPoint(counterX-24,SLIDER_BASE+1), BPoint(counterX+24,SLIDER_BASE+1), blue);
250 		AddLine(BPoint(counterX+25,SLIDER_BASE+1), BPoint(counterX+25,SLIDER_BASE-9), blue2);
251 		AddLine(BPoint(counterX-25,SLIDER_BASE+1), BPoint(counterX-25,SLIDER_BASE-9), blue2);
252 		AddLine(BPoint(counterX-24,SLIDER_BASE-9), BPoint(counterX+24,SLIDER_BASE-9), blue2);
253 		SetHighColor(48,48,241);
254 	}
255 	EndLineArray();
256 	FillRect(BRect(counterX-24,SLIDER_BASE-8,counterX+24,SLIDER_BASE));
257 
258 	SetDrawingMode(B_OP_COPY);
259 	if (isTracking)
260 		SetHighColor(255,255,255);
261 	else
262 		SetHighColor(0,0,0);
263 	SetLowColor(ViewColor());
264 
265 	SetFont(&fFont);
266 	char string[12];
267 	TimeToString(timestamp, string);
268 	DrawString(string, BPoint(counterX-22, SLIDER_BASE-1));
269 
270 }
271 
272 
273 void
274 TrackSlider::MouseMoved(BPoint point, uint32 transit, const BMessage *message)
275 {
276 	if (!IsTracking())
277 		return;
278 
279 	uint32 mouseButtons;
280 	BPoint where;
281 	GetMouse(&where, &mouseButtons, true);
282 
283 	// button not pressed, exit
284 	if (! (mouseButtons & B_PRIMARY_MOUSE_BUTTON)) {
285 		Invoke();
286 		SetTracking(false);
287 	}
288 
289 	UpdatePosition(point);
290 }
291 
292 
293 void
294 TrackSlider::MouseDown(BPoint point)
295 {
296 	if (!Bounds().InsetBySelf(2,2).Contains(point))
297 		return;
298 
299 	UpdatePosition(point);
300 	SetTracking(true);
301 	SetMouseEventMask(B_POINTER_EVENTS, B_NO_POINTER_HISTORY| B_LOCK_WINDOW_FOCUS);
302 }
303 
304 
305 void
306 TrackSlider::MouseUp(BPoint point)
307 {
308 	if (!IsTracking())
309 		return;
310 	if (Bounds().InsetBySelf(2,2).Contains(point)) {
311 		UpdatePosition(point);
312 	}
313 
314 	fLeftTracking = fRightTracking = fMainTracking = false;
315 
316 	Invoke();
317 	SetTracking(false);
318 	Draw(Bounds());
319 	Flush();
320 }
321 
322 
323 void
324 TrackSlider::UpdatePosition(BPoint point)
325 {
326 	BRect leftRect(fLeftX-9, SLIDER_BASE+3, fLeftX, SLIDER_BASE+16);
327 	BRect rightRect(fRightX, SLIDER_BASE+3, fRightX+9, SLIDER_BASE+16);
328 
329 	if (!(fRightTracking || fMainTracking) && (fLeftTracking || ((point.x < fPositionX-4) && leftRect.Contains(point)))) {
330 		if (!IsTracking())
331 			fLastX = point.x - fLeftX;
332 		fLeftX = MIN(MAX(point.x - fLastX, 15), fRight);
333 		fLeftTime = (bigtime_t)(MAX(MIN((fLeftX - 15) / (fRight - 14),1), 0) * fTotalTime);
334 		fLeftTracking = true;
335 
336 		BMessage msg = *Message();
337 		msg.AddInt64("left", fLeftTime);
338 
339 		if (fPositionX < fLeftX) {
340 			fPositionX = fLeftX + 1;
341 			fMainTime = fLeftTime;
342 			msg.AddInt64("main", fMainTime);
343 			if (fRightX < fPositionX) {
344 				fRightX = fPositionX;
345 				fRightTime = fMainTime;
346 				msg.AddInt64("right", fRightTime);
347 			}
348 		}
349 
350 		Invoke(&msg);
351 
352 		//printf("fLeftPos : %Ld\n", fLeftTime);
353 	} else if (!fMainTracking && (fRightTracking || ((point.x > fPositionX+4) && rightRect.Contains(point)))) {
354 		if (!IsTracking())
355 			fLastX = point.x - fRightX;
356 		fRightX = MIN(MAX(point.x - fLastX, 15), fRight);
357 		fRightTime = (bigtime_t)(MAX(MIN((fRightX - 15) / (fRight - 14),1), 0) * fTotalTime);
358 		fRightTracking = true;
359 
360 		BMessage msg = *Message();
361 		msg.AddInt64("right", fRightTime);
362 
363 		if (fPositionX > fRightX) {
364 			fPositionX = fRightX;
365 			fMainTime = fRightTime;
366 			msg.AddInt64("main", fMainTime);
367 			if (fLeftX > fPositionX) {
368 				fLeftX = fPositionX - 1;
369 				fLeftTime = fMainTime;
370 				msg.AddInt64("left", fLeftTime);
371 			}
372 		}
373 
374 		Invoke(&msg);
375 
376 		//printf("fRightPos : %Ld\n", fRightTime);
377 	} else {
378 		fPositionX = MIN(MAX(point.x, 15), fRight);
379 		fMainTime = (bigtime_t)(MAX(MIN((fPositionX - 15) / (fRight - 14),1), 0) * fTotalTime);
380 		fMainTracking = true;
381 
382 		BMessage msg = *Message();
383 		msg.AddInt64("main", fMainTime);
384 
385 		if (fRightX < fPositionX) {
386 			fRightX = fPositionX;
387 			fRightTime = fMainTime;
388 			msg.AddInt64("right", fRightTime);
389 		} else if (fLeftX > fPositionX) {
390 			fLeftX = fPositionX - 1;
391 			fLeftTime = fMainTime;
392 			msg.AddInt64("left", fLeftTime);
393 		}
394 
395 		Invoke(&msg);
396 		//printf("fPosition : %Ld\n", fMainTime);
397 	}
398 	Draw(Bounds());
399 	Flush();
400 }
401 
402 
403 void
404 TrackSlider::TimeToString(bigtime_t timestamp, char *string)
405 {
406 	uint32 hours = timestamp / 3600000000LL;
407 	timestamp -= hours * 3600000000LL;
408 	uint32 minutes = timestamp / 60000000LL;
409 	timestamp -= minutes * 60000000LL;
410 	uint32 seconds = timestamp / 1000000LL;
411 	timestamp -= seconds * 1000000LL;
412 	uint32 centiseconds = timestamp / 10000LL;
413 	sprintf(string, "%02ld:%02ld:%02ld:%02ld", hours, minutes, seconds, centiseconds);
414 
415 }
416 
417 
418 void
419 TrackSlider::SetMainTime(bigtime_t timestamp, bool reset)
420 {
421 	fMainTime = timestamp;
422 	fPositionX = 15 + (fRight - 14) * ((double)fMainTime / fTotalTime);
423 	if (reset) {
424 		fRightTime = fTotalTime;
425 		fLeftTime = 0;
426 		fLeftX = 14 + (fRight - 15) * ((double)fLeftTime / fTotalTime);
427 		fRightX = 15 + (fRight - 16) * ((double)fRightTime / fTotalTime);
428 	}
429 	Invalidate();
430 }
431 
432 void
433 TrackSlider::SetTotalTime(bigtime_t timestamp, bool reset)
434 {
435 	fTotalTime = timestamp;
436 	if (reset) {
437 		fMainTime = 0;
438 		fRightTime = fTotalTime;
439 		fLeftTime = 0;
440 	}
441 	fPositionX = 15 + (fRight - 14) * ((double)fMainTime / fTotalTime);
442 	fLeftX = 14 + (fRight - 15) * ((double)fLeftTime / fTotalTime);
443 	fRightX = 15 + (fRight - 16) * ((double)fRightTime / fTotalTime);
444 	Invalidate();
445 }
446 
447 
448 void
449 TrackSlider::ResetMainTime()
450 {
451 	fMainTime = fLeftTime;
452 	fPositionX = 15 + (fRight - 14) * ((double)fMainTime / fTotalTime);
453 	Invalidate();
454 }
455 
456 
457 void
458 TrackSlider::FrameResized(float width, float height)
459 {
460 	fRight = Bounds().right - kLeftRightTrackSliderWidth;
461 	fPositionX = 15 + (fRight - 14) * ((double)fMainTime / fTotalTime);
462 	fLeftX = 14 + (fRight - 15) * ((double)fLeftTime / fTotalTime);
463 	fRightX = 15 + (fRight - 16) * ((double)fRightTime / fTotalTime);
464 	Invalidate();
465 }
466