ft2-clone

Fasttracker 2 clone
Log | Files | Refs | README | LICENSE

ft2_scrollbars.c (20629B)


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