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