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