1 // for finding memory leaks in debug mode with Visual Studio
2 #if defined _DEBUG && defined _MSC_VER
3 #include <crtdbg.h>
4 #endif
5 
6 #include <stdint.h>
7 #include <stdbool.h>
8 #include "ft2_header.h"
9 #include "ft2_gui.h"
10 #include "ft2_config.h"
11 #include "ft2_audio.h"
12 #include "ft2_help.h"
13 #include "ft2_sample_ed.h"
14 #include "ft2_inst_ed.h"
15 #include "ft2_diskop.h"
16 #include "ft2_pattern_ed.h"
17 #include "ft2_audioselector.h"
18 #include "ft2_midi.h"
19 #include "ft2_mouse.h"
20 #include "ft2_video.h"
21 #include "ft2_palette.h"
22 #include "ft2_structs.h"
23 
24 /* Prevent the scrollbar thumbs from being so small that
25 ** it's difficult to use them. In units of pixels.
26 ** Shouldn't be higher than 9!
27 */
28 #define MIN_THUMB_LENGTH 5
29 
30 scrollBar_t scrollBars[NUM_SCROLLBARS] =
31 {
32 	// ------ RESERVED SCROLLBARS ------
33 	{ 0 }, { 0 }, { 0 },
34 
35 	/*
36 	** -- STRUCT INFO: --
37 	**  x         = x position
38 	**  y         = y position
39 	**  w         = width
40 	**  h         = height
41 	**  type      = scrollbar type (vertical/horizontal)
42 	**  style     = scrollbar style (flat/noflat)
43 	** funcOnDown = function to call when pressed
44 	*/
45 
46 	// ------ POSITION EDITOR SCROLLBARS ------
47 	//x,  y,  w,  h,  type,               style                 funcOnDown
48 	{ 55, 15, 18, 21, SCROLLBAR_VERTICAL, SCROLLBAR_THUMB_FLAT, sbPosEdPos },
49 
50 	// ------ INSTRUMENT SWITCHER SCROLLBARS ------
51 	//x,   y,   w,  h,  type,               style                 funcOnDown
52 	{ 566, 112, 18, 28, SCROLLBAR_VERTICAL, SCROLLBAR_THUMB_FLAT, sbSmpBankPos },
53 
54 	// ------ PATTERN VIEWER SCROLLBARS ------
55 	//x,  y,   w,   h,  type,                 style                 funcOnDown
56 	{ 28, 385, 576, 13, SCROLLBAR_HORIZONTAL, SCROLLBAR_THUMB_FLAT, setChannelScrollPos },
57 
58 	// ------ HELP SCREEN SCROLLBARS ------
59 	//x,   y,  w,  h,   type,               style                 funcOnDown
60 	{ 611, 15, 18, 143, SCROLLBAR_VERTICAL, SCROLLBAR_THUMB_FLAT, helpScrollSetPos },
61 
62 	// ------ SAMPLE EDITOR SCROLLBARS ------
63 	//x,  y,   w,   h,  type,                 style                 funcOnDown
64 	{ 26, 331, 580, 13, SCROLLBAR_HORIZONTAL, SCROLLBAR_THUMB_FLAT, scrollSampleData },
65 
66 	// ------ INSTRUMENT EDITOR SCROLLBARS ------
67 	//x,   y,   w,  h,  type,                 style                   funcOnDown
68 	{ 544, 175, 62, 13, SCROLLBAR_HORIZONTAL, SCROLLBAR_THUMB_NOFLAT, setVolumeScroll },
69 	{ 544, 189, 62, 13, SCROLLBAR_HORIZONTAL, SCROLLBAR_THUMB_NOFLAT, setPanningScroll },
70 	{ 544, 203, 62, 13, SCROLLBAR_HORIZONTAL, SCROLLBAR_THUMB_NOFLAT, setFinetuneScroll },
71 	{ 544, 220, 62, 13, SCROLLBAR_HORIZONTAL, SCROLLBAR_THUMB_NOFLAT, setFadeoutScroll },
72 	{ 544, 234, 62, 13, SCROLLBAR_HORIZONTAL, SCROLLBAR_THUMB_NOFLAT, setVibSpeedScroll },
73 	{ 544, 248, 62, 13, SCROLLBAR_HORIZONTAL, SCROLLBAR_THUMB_NOFLAT, setVibDepthScroll },
74 	{ 544, 262, 62, 13, SCROLLBAR_HORIZONTAL, SCROLLBAR_THUMB_NOFLAT, setVibSweepScroll },
75 
76 	// ------ INSTRUMENT EDITOR EXTENSION SCROLLBARS ------
77 	//x,   y,   w,  h,  type,                 style                   funcOnDown
78 	{ 195, 130, 70, 13, SCROLLBAR_HORIZONTAL, SCROLLBAR_THUMB_NOFLAT, sbMidiChPos },
79 	{ 195, 144, 70, 13, SCROLLBAR_HORIZONTAL, SCROLLBAR_THUMB_NOFLAT, sbMidiPrgPos },
80 	{ 195, 158, 70, 13, SCROLLBAR_HORIZONTAL, SCROLLBAR_THUMB_NOFLAT, sbMidiBendPos },
81 
82 	// ------ CONFIG AUDIO SCROLLBARS ------
83 	//x,   y,   w,  h,  type,                 style                   funcOnDown
84 	{ 365,  29, 18, 43, SCROLLBAR_VERTICAL,   SCROLLBAR_THUMB_FLAT,   sbAudOutputSetPos },
85 	{ 365, 116, 18, 21, SCROLLBAR_VERTICAL,   SCROLLBAR_THUMB_FLAT,   sbAudInputSetPos },
86 	{ 529, 132, 79, 13, SCROLLBAR_HORIZONTAL, SCROLLBAR_THUMB_NOFLAT, sbAmp },
87 	{ 529, 158, 79, 13, SCROLLBAR_HORIZONTAL, SCROLLBAR_THUMB_NOFLAT, sbMasterVol },
88 
89 	// ------ CONFIG LAYOUT SCROLLBARS ------
90 	//x,   y,  w,  h,  type,                 style                   funcOnDown
91 	{ 536, 15, 70, 13, SCROLLBAR_HORIZONTAL, SCROLLBAR_THUMB_NOFLAT, sbPalRPos },
92 	{ 536, 29, 70, 13, SCROLLBAR_HORIZONTAL, SCROLLBAR_THUMB_NOFLAT, sbPalGPos },
93 	{ 536, 43, 70, 13, SCROLLBAR_HORIZONTAL, SCROLLBAR_THUMB_NOFLAT, sbPalBPos },
94 	{ 536, 71, 70, 13, SCROLLBAR_HORIZONTAL, SCROLLBAR_THUMB_NOFLAT, sbPalContrastPos },
95 
96 	// ------ CONFIG MISCELLANEOUS SCROLLBARS ------
97 	//x,   y,   w,  h,  type,                 style                   funcOnDown
98 	{ 578, 158, 29, 13, SCROLLBAR_HORIZONTAL, SCROLLBAR_THUMB_NOFLAT, sbMIDISens },
99 
100 #ifdef HAS_MIDI
101 	// ------ CONFIG MIDI SCROLLBARS ------
102 	//x,   y,  w,  h,   type,               style                 funcOnDown
103 	{ 483, 15, 18, 143, SCROLLBAR_VERTICAL, SCROLLBAR_THUMB_FLAT, sbMidiInputSetPos },
104 #endif
105 
106 	// ------ DISK OP. SCROLLBARS ------
107 	//x,   y,  w,  h,   type,               style                 funcOnDown
108 	{ 335, 15, 18, 143, SCROLLBAR_VERTICAL, SCROLLBAR_THUMB_FLAT, sbDiskOpSetPos }
109 };
110 
drawScrollBar(uint16_t scrollBarID)111 void drawScrollBar(uint16_t scrollBarID)
112 {
113 	assert(scrollBarID < NUM_SCROLLBARS);
114 	scrollBar_t *scrollBar = &scrollBars[scrollBarID];
115 	if (!scrollBar->visible)
116 		return;
117 
118 	assert(scrollBar->x < SCREEN_W && scrollBar->y < SCREEN_H && scrollBar->w >= 3 && scrollBar->h >= 3);
119 
120 	int16_t thumbX = scrollBar->thumbX;
121 	int16_t thumbY = scrollBar->thumbY;
122 	int16_t thumbW = scrollBar->thumbW;
123 	int16_t thumbH = scrollBar->thumbH;
124 
125 	// clear scrollbar background (lazy, but sometimes even faster than filling bg gaps)
126 	clearRect(scrollBar->x, scrollBar->y, scrollBar->w, scrollBar->h);
127 
128 	// draw thumb
129 	if (scrollBar->thumbType == SCROLLBAR_THUMB_FLAT)
130 	{
131 		// flat
132 		fillRect(thumbX, thumbY, thumbW, thumbH, PAL_PATTEXT);
133 	}
134 	else
135 	{
136 		// 3D
137 		fillRect(thumbX, thumbY, thumbW, thumbH, PAL_BUTTONS);
138 
139 		if (scrollBar->state == SCROLLBAR_UNPRESSED)
140 		{
141 			// top left corner inner border
142 			hLine(thumbX, thumbY,     thumbW - 1, PAL_BUTTON1);
143 			vLine(thumbX, thumbY + 1, thumbH - 2, PAL_BUTTON1);
144 
145 			// bottom right corner inner border
146 			hLine(thumbX,              thumbY + thumbH - 1, thumbW - 1, PAL_BUTTON2);
147 			vLine(thumbX + thumbW - 1, thumbY,              thumbH,     PAL_BUTTON2);
148 		}
149 		else
150 		{
151 			// top left corner inner border
152 			hLine(thumbX, thumbY,     thumbW,     PAL_BUTTON2);
153 			vLine(thumbX, thumbY + 1, thumbH - 1, PAL_BUTTON2);
154 		}
155 	}
156 }
157 
showScrollBar(uint16_t scrollBarID)158 void showScrollBar(uint16_t scrollBarID)
159 {
160 	assert(scrollBarID < NUM_SCROLLBARS);
161 	scrollBars[scrollBarID].visible = true;
162 	drawScrollBar(scrollBarID);
163 }
164 
hideScrollBar(uint16_t scrollBarID)165 void hideScrollBar(uint16_t scrollBarID)
166 {
167 	assert(scrollBarID < NUM_SCROLLBARS);
168 	scrollBars[scrollBarID].state = 0;
169 	scrollBars[scrollBarID].visible = false;
170 }
171 
setScrollBarThumbCoords(uint16_t scrollBarID)172 static void setScrollBarThumbCoords(uint16_t scrollBarID)
173 {
174 	int16_t thumbX, thumbY, thumbW, thumbH, scrollEnd, realThumbLength;
175 	int32_t tmp32, length, end;
176 	double dTmp;
177 
178 	assert(scrollBarID < NUM_SCROLLBARS);
179 	scrollBar_t *scrollBar = &scrollBars[scrollBarID];
180 
181 	assert(scrollBar->page > 0);
182 
183 	// uninitialized scrollbar, set full thumb length/height
184 	if (scrollBar->end == 0)
185 	{
186 		scrollBar->thumbX = scrollBar->x + 1;
187 		scrollBar->thumbY = scrollBar->y + 1;
188 		scrollBar->thumbW = scrollBar->w - 2;
189 		scrollBar->thumbH = scrollBar->h - 2;
190 		return;
191 	}
192 
193 	if (scrollBar->type == SCROLLBAR_HORIZONTAL)
194 	{
195 		// horizontal scrollbar
196 
197 		thumbY = scrollBar->y + 1;
198 		thumbH = scrollBar->h - 2;
199 		scrollEnd = scrollBar->x + scrollBar->w;
200 
201 		if (scrollBar->thumbType == SCROLLBAR_THUMB_NOFLAT)
202 		{
203 			realThumbLength = 15;
204 
205 			thumbW = realThumbLength;
206 			if (thumbW < MIN_THUMB_LENGTH)
207 				thumbW = MIN_THUMB_LENGTH;
208 
209 			if (scrollBar->end > 0)
210 			{
211 				length = scrollBar->w - realThumbLength;
212 				dTmp = (length / (double)scrollBar->end) * scrollBar->pos;
213 				tmp32 = (int32_t)(dTmp + 0.5);
214 				thumbX = (int16_t)(scrollBar->x + tmp32);
215 			}
216 			else
217 			{
218 				thumbX = scrollBar->x;
219 			}
220 		}
221 		else
222 		{
223 			if (scrollBar->end > 0)
224 			{
225 				dTmp = (scrollBar->w / (double)scrollBar->end) * scrollBar->page;
226 				tmp32 = (int32_t)(dTmp + 0.5);
227 				realThumbLength = (int16_t)CLAMP(tmp32, 1, scrollBar->w);
228 			}
229 			else
230 			{
231 				realThumbLength = 1;
232 			}
233 
234 			thumbW = realThumbLength;
235 			if (thumbW < MIN_THUMB_LENGTH)
236 				thumbW = MIN_THUMB_LENGTH;
237 
238 			if (scrollBar->end > scrollBar->page)
239 			{
240 				length = scrollBar->w - thumbW;
241 				end = scrollBar->end - scrollBar->page;
242 
243 				dTmp = (length / (double)end) * scrollBar->pos;
244 				tmp32 = (int32_t)(dTmp + 0.5);
245 				thumbX = (int16_t)(scrollBar->x + tmp32);
246 			}
247 			else
248 			{
249 				thumbX = scrollBar->x;
250 			}
251 		}
252 
253 		// prevent scrollbar thumb coords from being outside of the scrollbar area
254 		thumbX = CLAMP(thumbX, scrollBar->x, scrollEnd-1);
255 		if (thumbX+thumbW > scrollEnd)
256 			thumbW = scrollEnd - thumbX;
257 	}
258 	else
259 	{
260 		// vertical scrollbar
261 
262 		thumbX = scrollBar->x + 1;
263 		thumbW = scrollBar->w - 2;
264 		scrollEnd = scrollBar->y + scrollBar->h;
265 
266 		if (scrollBar->end > 0)
267 		{
268 			dTmp = (scrollBar->h / (double)scrollBar->end) * scrollBar->page;
269 			tmp32 = (int32_t)(dTmp + 0.5);
270 			realThumbLength = (int16_t)CLAMP(tmp32, 1, scrollBar->h);
271 		}
272 		else
273 		{
274 			realThumbLength = 1;
275 		}
276 
277 		thumbH = realThumbLength;
278 		if (thumbH < MIN_THUMB_LENGTH)
279 			thumbH = MIN_THUMB_LENGTH;
280 
281 		if (scrollBar->end > scrollBar->page)
282 		{
283 			length = scrollBar->h - thumbH;
284 			end = scrollBar->end - scrollBar->page;
285 
286 			dTmp = (length / (double)end) * scrollBar->pos;
287 			tmp32 = (int32_t)(dTmp + 0.5);
288 			thumbY = (int16_t)(scrollBar->y + tmp32);
289 		}
290 		else
291 		{
292 			thumbY = scrollBar->y;
293 		}
294 
295 		// prevent scrollbar thumb coords from being outside of the scrollbar area
296 		thumbY = CLAMP(thumbY, scrollBar->y, scrollEnd - 1);
297 		if (thumbY+thumbH > scrollEnd)
298 			thumbH = scrollEnd - thumbY;
299 	}
300 
301 	// set values now
302 	scrollBar->realThumbLength = realThumbLength;
303 	scrollBar->thumbX = thumbX;
304 	scrollBar->thumbY = thumbY;
305 	scrollBar->thumbW = thumbW;
306 	scrollBar->thumbH = thumbH;
307 }
308 
scrollBarScrollUp(uint16_t scrollBarID,uint32_t amount)309 void scrollBarScrollUp(uint16_t scrollBarID, uint32_t amount)
310 {
311 	assert(scrollBarID < NUM_SCROLLBARS);
312 	scrollBar_t *scrollBar = &scrollBars[scrollBarID];
313 
314 	assert(scrollBar->page > 0 && scrollBar->end > 0);
315 
316 	if (scrollBar->end < scrollBar->page || scrollBar->pos == 0)
317 		return;
318 
319 	if (scrollBar->pos >= amount)
320 		scrollBar->pos -= amount;
321 	else
322 		scrollBar->pos = 0;
323 
324 	setScrollBarThumbCoords(scrollBarID);
325 	drawScrollBar(scrollBarID);
326 
327 	if (scrollBar->callbackFunc != NULL)
328 		scrollBar->callbackFunc(scrollBar->pos);
329 }
330 
scrollBarScrollDown(uint16_t scrollBarID,uint32_t amount)331 void scrollBarScrollDown(uint16_t scrollBarID, uint32_t amount)
332 {
333 	assert(scrollBarID < NUM_SCROLLBARS);
334 	scrollBar_t *scrollBar = &scrollBars[scrollBarID];
335 
336 	assert(scrollBar->page > 0 && scrollBar->end > 0);
337 
338 	if (scrollBar->end < scrollBar->page)
339 		return;
340 
341 	uint32_t endPos = scrollBar->end;
342 	if (scrollBar->thumbType == SCROLLBAR_THUMB_FLAT)
343 	{
344 		if (endPos >= scrollBar->page)
345 			endPos -= scrollBar->page;
346 		else
347 			endPos = 0;
348 	}
349 
350 	// check if we're already at the end
351 	if (scrollBar->pos == endPos)
352 		return;
353 
354 	scrollBar->pos += amount;
355 	if (scrollBar->pos > endPos)
356 		scrollBar->pos = endPos;
357 
358 	setScrollBarThumbCoords(scrollBarID);
359 	drawScrollBar(scrollBarID);
360 
361 	if (scrollBar->callbackFunc != NULL)
362 		scrollBar->callbackFunc(scrollBar->pos);
363 }
364 
scrollBarScrollLeft(uint16_t scrollBarID,uint32_t amount)365 void scrollBarScrollLeft(uint16_t scrollBarID, uint32_t amount)
366 {
367 	scrollBarScrollUp(scrollBarID, amount);
368 }
369 
scrollBarScrollRight(uint16_t scrollBarID,uint32_t amount)370 void scrollBarScrollRight(uint16_t scrollBarID, uint32_t amount)
371 {
372 	scrollBarScrollDown(scrollBarID, amount);
373 }
374 
setScrollBarPos(uint16_t scrollBarID,uint32_t pos,bool triggerCallBack)375 void setScrollBarPos(uint16_t scrollBarID, uint32_t pos, bool triggerCallBack)
376 {
377 	assert(scrollBarID < NUM_SCROLLBARS);
378 	scrollBar_t *scrollBar = &scrollBars[scrollBarID];
379 
380 	if (scrollBar->page == 0)
381 	{
382 		scrollBar->pos = 0;
383 		return;
384 	}
385 
386 	if (scrollBar->end < scrollBar->page || scrollBar->pos == pos)
387 	{
388 		setScrollBarThumbCoords(scrollBarID);
389 		drawScrollBar(scrollBarID);
390 		return;
391 	}
392 
393 	uint32_t endPos = scrollBar->end;
394 	if (scrollBar->thumbType == SCROLLBAR_THUMB_FLAT)
395 	{
396 		if (endPos >= scrollBar->page)
397 			endPos -= scrollBar->page;
398 		else
399 			endPos = 0;
400 	}
401 
402 	scrollBar->pos = pos;
403 	if (scrollBar->pos > endPos)
404 		scrollBar->pos = endPos;
405 
406 	setScrollBarThumbCoords(scrollBarID);
407 	drawScrollBar(scrollBarID);
408 
409 	if (triggerCallBack && scrollBar->callbackFunc != NULL)
410 		scrollBar->callbackFunc(scrollBar->pos);
411 }
412 
getScrollBarPos(uint16_t scrollBarID)413 uint32_t getScrollBarPos(uint16_t scrollBarID)
414 {
415 	assert(scrollBarID < NUM_SCROLLBARS);
416 	return scrollBars[scrollBarID].pos;
417 }
418 
setScrollBarEnd(uint16_t scrollBarID,uint32_t end)419 void setScrollBarEnd(uint16_t scrollBarID, uint32_t end)
420 {
421 	assert(scrollBarID < NUM_SCROLLBARS);
422 	scrollBar_t *scrollBar = &scrollBars[scrollBarID];
423 
424 	if (end < 1)
425 		end = 1;
426 
427 	scrollBar->end = end;
428 
429 	bool setPos = false;
430 	if (scrollBar->pos >= end)
431 	{
432 		scrollBar->pos = end - 1;
433 		setPos = true;
434 	}
435 
436 	if (scrollBar->page > 0)
437 	{
438 		if (setPos)
439 		{
440 			setScrollBarPos(scrollBarID, scrollBar->pos, false);
441 			// this will also call setScrollBarThumbCoords() and drawScrollBar()
442 		}
443 		else
444 		{
445 			setScrollBarThumbCoords(scrollBarID);
446 			drawScrollBar(scrollBarID);
447 		}
448 	}
449 }
450 
setScrollBarPageLength(uint16_t scrollBarID,uint32_t pageLength)451 void setScrollBarPageLength(uint16_t scrollBarID, uint32_t pageLength)
452 {
453 	assert(scrollBarID < NUM_SCROLLBARS);
454 	scrollBar_t *scrollBar = &scrollBars[scrollBarID];
455 
456 	if (pageLength < 1)
457 		pageLength = 1;
458 
459 	scrollBar->page = pageLength;
460 	if (scrollBar->end > 0)
461 	{
462 		setScrollBarPos(scrollBarID, scrollBar->pos, false);
463 		setScrollBarThumbCoords(scrollBarID);
464 		drawScrollBar(scrollBarID);
465 	}
466 }
467 
testScrollBarMouseDown(void)468 bool testScrollBarMouseDown(void)
469 {
470 	uint16_t start, end;
471 	int32_t scrollPos, length;
472 	double dTmp;
473 
474 	if (ui.sysReqShown)
475 	{
476 		// if a system request is open, only test the first three scrollbars (reserved)
477 		start = 0;
478 		end = 3;
479 	}
480 	else
481 	{
482 		start = 3;
483 		end = NUM_SCROLLBARS;
484 	}
485 
486 	const int32_t mx = mouse.x;
487 	const int32_t my = mouse.y;
488 
489 	scrollBar_t *scrollBar = &scrollBars[start];
490 	for (uint16_t i = start; i < end; i++, scrollBar++)
491 	{
492 		if (!scrollBar->visible)
493 			continue;
494 
495 		if (mx >= scrollBar->x && mx < scrollBar->x+scrollBar->w &&
496 		    my >= scrollBar->y && my < scrollBar->y+scrollBar->h)
497 		{
498 			mouse.lastUsedObjectID = i;
499 			mouse.lastUsedObjectType = OBJECT_SCROLLBAR;
500 
501 			// kludge for when a system request is about to open
502 			scrollBar->state = SCROLLBAR_PRESSED;
503 			if (scrollBar->thumbType == SCROLLBAR_THUMB_NOFLAT)
504 				drawScrollBar(mouse.lastUsedObjectType);
505 
506 			if (scrollBar->type == SCROLLBAR_HORIZONTAL)
507 			{
508 				mouse.lastScrollXTmp = mouse.lastScrollX = mx;
509 
510 				if (mx >= scrollBar->thumbX && mx < scrollBar->thumbX+scrollBar->thumbW)
511 				{
512 					mouse.saveMouseX = mouse.lastScrollX - scrollBar->thumbX;
513 				}
514 				else
515 				{
516 					mouse.saveMouseX = scrollBar->thumbW >> 1;
517 
518 					scrollPos = mouse.lastScrollX - scrollBar->x - mouse.saveMouseX;
519 					if (scrollBar->thumbType == SCROLLBAR_THUMB_NOFLAT)
520 					{
521 						dTmp = scrollPos * (scrollBar->w / (double)(scrollBar->w - scrollBar->thumbW));
522 						scrollPos = (int32_t)(dTmp + 0.5);
523 					}
524 
525 					assert(scrollBar->w > 0);
526 					scrollPos = CLAMP(scrollPos, 0, scrollBar->w);
527 
528 					length = scrollBar->w + (scrollBar->realThumbLength - scrollBar->thumbW);
529 					if (length < 1)
530 						length = 1;
531 
532 					dTmp = ((double)scrollPos * scrollBar->end) / length;
533 					scrollPos = (int32_t)(dTmp + 0.5);
534 
535 					setScrollBarPos(mouse.lastUsedObjectID, scrollPos, true);
536 				}
537 			}
538 			else
539 			{
540 				mouse.lastScrollY = my;
541 				if (my >= scrollBar->thumbY && my < scrollBar->thumbY+scrollBar->thumbH)
542 				{
543 					mouse.saveMouseY = mouse.lastScrollY - scrollBar->thumbY;
544 				}
545 				else
546 				{
547 					mouse.saveMouseY = scrollBar->thumbH >> 1;
548 
549 					scrollPos = mouse.lastScrollY - scrollBar->y - mouse.saveMouseY;
550 
551 					assert(scrollBar->h > 0);
552 					scrollPos = CLAMP(scrollPos, 0, scrollBar->h);
553 
554 					length = scrollBar->h + (scrollBar->realThumbLength - scrollBar->thumbH);
555 					if (length < 1)
556 						length = 1;
557 
558 					dTmp = ((double)scrollPos * scrollBar->end) / length;
559 					scrollPos = (int32_t)(dTmp + 0.5);
560 
561 					setScrollBarPos(mouse.lastUsedObjectID, scrollPos, true);
562 				}
563 			}
564 
565 			// objectID can be set to none in scrollbar's callback during setScrollBarPos()
566 			if (mouse.lastUsedObjectID == OBJECT_ID_NONE)
567 				return true;
568 
569 			scrollBar->state = SCROLLBAR_PRESSED;
570 			if (scrollBar->thumbType == SCROLLBAR_THUMB_NOFLAT)
571 				drawScrollBar(mouse.lastUsedObjectID);
572 
573 			return true;
574 		}
575 	}
576 
577 	return false;
578 }
579 
testScrollBarMouseRelease(void)580 void testScrollBarMouseRelease(void)
581 {
582 	if (mouse.lastUsedObjectType != OBJECT_SCROLLBAR || mouse.lastUsedObjectID == OBJECT_ID_NONE)
583 		return;
584 
585 	assert(mouse.lastUsedObjectID < NUM_SCROLLBARS);
586 	scrollBar_t *scrollBar = &scrollBars[mouse.lastUsedObjectID];
587 
588 	if (scrollBar->visible)
589 	{
590 		scrollBar->state = SCROLLBAR_UNPRESSED;
591 		drawScrollBar(mouse.lastUsedObjectID);
592 	}
593 }
594 
handleScrollBarsWhileMouseDown(void)595 void handleScrollBarsWhileMouseDown(void)
596 {
597 	int32_t scrollX, scrollY, length;
598 	double dTmp;
599 
600 	assert(mouse.lastUsedObjectID >= 0 && mouse.lastUsedObjectID < NUM_SCROLLBARS);
601 	scrollBar_t *scrollBar = &scrollBars[mouse.lastUsedObjectID];
602 	if (!scrollBar->visible)
603 		return;
604 
605 	if (scrollBar->type == SCROLLBAR_HORIZONTAL)
606 	{
607 		if (mouse.x != mouse.lastScrollX)
608 		{
609 			mouse.lastScrollX = mouse.x;
610 			scrollX = mouse.lastScrollX - mouse.saveMouseX - scrollBar->x;
611 
612 			if (scrollBar->thumbType == SCROLLBAR_THUMB_NOFLAT)
613 			{
614 				assert(scrollBar->w >= 16);
615 				dTmp = scrollX * (scrollBar->w / (double)(scrollBar->w - scrollBar->thumbW));
616 				scrollX = (int32_t)(dTmp + 0.5);
617 			}
618 
619 			assert(scrollBar->w > 0);
620 			scrollX = CLAMP(scrollX, 0, scrollBar->w);
621 
622 			length = scrollBar->w + (scrollBar->realThumbLength - scrollBar->thumbW);
623 			if (length < 1)
624 				length = 1;
625 
626 			dTmp = ((double)scrollX * scrollBar->end) / length;
627 			scrollX = (int32_t)(dTmp + 0.5);
628 
629 			setScrollBarPos(mouse.lastUsedObjectID, scrollX, true);
630 
631 			if (mouse.lastUsedObjectID != OBJECT_ID_NONE) // this can change in the callback in setScrollBarPos()
632 				drawScrollBar(mouse.lastUsedObjectID);
633 		}
634 	}
635 	else
636 	{
637 		if (mouse.y != mouse.lastScrollY)
638 		{
639 			mouse.lastScrollY = mouse.y;
640 
641 			scrollY = mouse.lastScrollY - mouse.saveMouseY - scrollBar->y;
642 
643 			assert(scrollBar->h > 0);
644 			scrollY = CLAMP(scrollY, 0, scrollBar->h);
645 
646 			length = scrollBar->h + (scrollBar->realThumbLength - scrollBar->thumbH);
647 			if (length < 1)
648 				length = 1;
649 
650 			dTmp = ((double)scrollY * scrollBar->end) / length;
651 			scrollY = (int32_t)(dTmp + 0.5);
652 
653 			setScrollBarPos(mouse.lastUsedObjectID, scrollY, true);
654 
655 			if (mouse.lastUsedObjectID != OBJECT_ID_NONE) // this can change in the callback in setScrollBarPos()
656 				drawScrollBar(mouse.lastUsedObjectID);
657 		}
658 	}
659 }
660 
initializeScrollBars(void)661 void initializeScrollBars(void)
662 {
663 	// pattern editor
664 	setScrollBarPageLength(SB_CHAN_SCROLL, 8);
665 	setScrollBarEnd(SB_CHAN_SCROLL, 8);
666 
667 	// position editor
668 	setScrollBarPageLength(SB_POS_ED, 5);
669 	setScrollBarEnd(SB_POS_ED, 5);
670 
671 	// instrument switcher
672 	setScrollBarPageLength(SB_SAMPLE_LIST, 5);
673 	setScrollBarEnd(SB_SAMPLE_LIST, 16);
674 
675 	// help screen
676 	setScrollBarPageLength(SB_HELP_SCROLL, 15);
677 	setScrollBarEnd(SB_HELP_SCROLL, 1);
678 
679 	// config screen
680 	setScrollBarPageLength(SB_AMP_SCROLL, 1);
681 	setScrollBarEnd(SB_AMP_SCROLL, 31);
682 	setScrollBarPageLength(SB_MASTERVOL_SCROLL, 1);
683 	setScrollBarEnd(SB_MASTERVOL_SCROLL, 256);
684 	setScrollBarPageLength(SB_PAL_R, 1);
685 	setScrollBarEnd(SB_PAL_R, 63);
686 	setScrollBarPageLength(SB_PAL_G, 1);
687 	setScrollBarEnd(SB_PAL_G, 63);
688 	setScrollBarPageLength(SB_PAL_B, 1);
689 	setScrollBarEnd(SB_PAL_B, 63);
690 	setScrollBarPageLength(SB_PAL_CONTRAST, 1);
691 	setScrollBarEnd(SB_PAL_CONTRAST, 100);
692 	setScrollBarPageLength(SB_MIDI_SENS, 1);
693 	setScrollBarEnd(SB_MIDI_SENS, 200);
694 	setScrollBarPageLength(SB_AUDIO_OUTPUT_SCROLL, 6);
695 	setScrollBarEnd(SB_AUDIO_OUTPUT_SCROLL, 1);
696 	setScrollBarPageLength(SB_AUDIO_INPUT_SCROLL, 4);
697 	setScrollBarEnd(SB_AUDIO_INPUT_SCROLL, 1);
698 
699 #ifdef HAS_MIDI
700 	setScrollBarPageLength(SB_MIDI_INPUT_SCROLL, 15);
701 	setScrollBarEnd(SB_MIDI_INPUT_SCROLL, 1);
702 #endif
703 
704 	// disk op.
705 	setScrollBarPageLength(SB_DISKOP_LIST, DISKOP_ENTRY_NUM);
706 	setScrollBarEnd(SB_DISKOP_LIST, 1);
707 
708 	// instrument editor
709 	setScrollBarPageLength(SB_INST_VOL, 1);
710 	setScrollBarEnd(SB_INST_VOL, 64);
711 	setScrollBarPageLength(SB_INST_PAN, 1);
712 	setScrollBarEnd(SB_INST_PAN, 255);
713 	setScrollBarPageLength(SB_INST_FTUNE, 1);
714 	setScrollBarEnd(SB_INST_FTUNE, 255);
715 	setScrollBarPageLength(SB_INST_FADEOUT, 1);
716 	setScrollBarEnd(SB_INST_FADEOUT, 0xFFF);
717 	setScrollBarPageLength(SB_INST_VIBSPEED, 1);
718 	setScrollBarEnd(SB_INST_VIBSPEED, 0x3F);
719 	setScrollBarPageLength(SB_INST_VIBDEPTH, 1);
720 	setScrollBarEnd(SB_INST_VIBDEPTH, 0xF);
721 	setScrollBarPageLength(SB_INST_VIBSWEEP, 1);
722 	setScrollBarEnd(SB_INST_VIBSWEEP, 0xFF);
723 
724 	// instrument editor extension
725 	setScrollBarPageLength(SB_INST_EXT_MIDI_CH, 1);
726 	setScrollBarEnd(SB_INST_EXT_MIDI_CH, 15);
727 	setScrollBarPageLength(SB_INST_EXT_MIDI_PRG, 1);
728 	setScrollBarEnd(SB_INST_EXT_MIDI_PRG, 127);
729 	setScrollBarPageLength(SB_INST_EXT_MIDI_BEND, 1);
730 	setScrollBarEnd(SB_INST_EXT_MIDI_BEND, 36);
731 }
732