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