1436 lines · 34.0 KB · C
RawDownload
// for finding memory leaks in debug mode with Visual Studio#if defined _DEBUG && defined _MSC_VER#include <crtdbg.h>#endif #include <stdint.h>#include <time.h>#include "ft2_header.h"#include "ft2_config.h"#include "ft2_about.h"#include "ft2_mouse.h"#include "ft2_nibbles.h"#include "ft2_gui.h"#include "ft2_pattern_ed.h"#include "scopes/ft2_scopes.h"#include "ft2_help.h"#include "ft2_sample_ed.h"#include "ft2_inst_ed.h"#include "ft2_diskop.h"#include "ft2_wav_renderer.h"#include "ft2_trim.h"#include "ft2_video.h"#include "ft2_tables.h"#include "ft2_bmp.h"#include "ft2_structs.h" static void releaseMouseStates(void){	mouse.lastUsedObjectID = OBJECT_ID_NONE;	mouse.lastUsedObjectType = OBJECT_NONE;	mouse.leftButtonPressed = false;	mouse.leftButtonReleased = false;	mouse.rightButtonPressed = false;	mouse.rightButtonReleased = false;	mouse.firstTimePressingButton = false;	mouse.buttonCounter = 0;	mouse.lastX = 0;	mouse.lastY = 0;	ui.sampleDataOrLoopDrag = -1;	ui.leftLoopPinMoving = false;	ui.rightLoopPinMoving = false;} void unstuckLastUsedGUIElement(void){	if (mouse.lastUsedObjectID == OBJECT_ID_NONE)	{		/* If last object ID is OBJECT_ID_NONE, check if we moved the		** sample data loop pins, and unstuck them if so		*/ 		if (ui.leftLoopPinMoving)		{			setLeftLoopPinState(false);			ui.leftLoopPinMoving = false;		} 		if (ui.rightLoopPinMoving)		{			setRightLoopPinState(false);			ui.rightLoopPinMoving = false;		} 		releaseMouseStates();		return;	} 	switch (mouse.lastUsedObjectType)	{		default: break; 		case OBJECT_PUSHBUTTON:		{			assert(mouse.lastUsedObjectID >= 0 && mouse.lastUsedObjectID < NUM_PUSHBUTTONS);			pushButton_t *p = &pushButtons[mouse.lastUsedObjectID];			if (p->state == PUSHBUTTON_PRESSED)			{				p->state = PUSHBUTTON_UNPRESSED;				if (p->visible)					drawPushButton(mouse.lastUsedObjectID);			}		}		break; 		case OBJECT_RADIOBUTTON:		{			assert(mouse.lastUsedObjectID >= 0 && mouse.lastUsedObjectID < NUM_RADIOBUTTONS);			radioButton_t *r = &radioButtons[mouse.lastUsedObjectID];			if (r->state == RADIOBUTTON_PRESSED)			{				r->state = RADIOBUTTON_UNCHECKED;				if (r->visible)					drawRadioButton(mouse.lastUsedObjectID);			}		}		break; 		case OBJECT_CHECKBOX:		{			assert(mouse.lastUsedObjectID >= 0 && mouse.lastUsedObjectID < NUM_CHECKBOXES);			checkBox_t *c = &checkBoxes[mouse.lastUsedObjectID];			if (c->state == CHECKBOX_PRESSED)			{				c->state = CHECKBOX_UNPRESSED;				if (c->visible)					drawCheckBox(mouse.lastUsedObjectID);			}		}		break; 		case OBJECT_SCROLLBAR:		{			assert(mouse.lastUsedObjectID >= 0 && mouse.lastUsedObjectID < NUM_SCROLLBARS);			scrollBar_t *s = &scrollBars[mouse.lastUsedObjectID];			if (s->state == SCROLLBAR_PRESSED)			{				s->state = SCROLLBAR_UNPRESSED;				if (s->visible)					drawScrollBar(mouse.lastUsedObjectID);			}		}		break;	} 	releaseMouseStates();} bool setupGUI(void){	// all memory will be NULL-tested and free'd if we return false somewhere in this function 	editor.tmpFilenameU = (UNICHAR *)malloc((PATH_MAX + 1) * sizeof (UNICHAR));	editor.tmpInstrFilenameU = (UNICHAR *)malloc((PATH_MAX + 1) * sizeof (UNICHAR)); 	if (editor.tmpFilenameU == NULL || editor.tmpInstrFilenameU == NULL)		goto setupGUI_OOM; 	editor.tmpFilenameU[0] = 0;	editor.tmpInstrFilenameU[0] = 0; 	// set uninitialized GUI struct entries 	textBox_t *t = &textBoxes[1]; // skip first entry, it's reserved for inputBox())	for (int32_t i = 1; i < NUM_TEXTBOXES; i++, t++)	{		t->visible = false;		t->bufOffset = 0;		t->cursorPos = 0;		t->textPtr = NULL;		t->renderBufW = (9 + 1) * t->maxChars; // 9 = max character/glyph width possible		t->renderBufH = 10; // 10 = max character height possible		t->renderW = t->w - (t->tx * 2); 		t->renderBuf = (uint8_t *)malloc(t->renderBufW * t->renderBufH * sizeof (int8_t));		if (t->renderBuf == NULL)			goto setupGUI_OOM;	} 	pushButton_t *p = pushButtons;	for (int32_t i = 0; i < NUM_PUSHBUTTONS; i++, p++)	{		p->state = 0;		p->visible = false; 		if (i == PB_LOGO || i == PB_BADGE)		{			p->bitmapFlag = true;		}		else		{			p->bitmapFlag = false;			p->bitmapUnpressed = NULL;			p->bitmapPressed = NULL;		}	} 	checkBox_t *c = checkBoxes;	for (int32_t i = 0; i < NUM_CHECKBOXES; i++, c++)	{		c->state = 0;		c->checked = false;		c->visible = false;	} 	radioButton_t *r = radioButtons;	for (int32_t i = 0; i < NUM_RADIOBUTTONS; i++, r++)	{		r->state = 0;		r->visible = false;	} 	scrollBar_t *s = scrollBars;	for (int32_t i = 0; i < NUM_SCROLLBARS; i++, s++)	{		s->visible = false;		s->state = 0;		s->pos = 0;		s->page = 0;		s->end  = 0;		s->thumbX = 0;		s->thumbY = 0;		s->thumbW = 0;		s->thumbH = 0;	} 	setPal16(palTable[config.cfg_StdPalNum], false);	seedAboutScreenRandom((uint32_t)time(NULL));	setupInitialTextBoxPointers();	setInitialTrimFlags();	initializeScrollBars();	setMouseMode(MOUSE_MODE_NORMAL);	updateTextBoxPointers();	drawGUIOnRunTime();	updateSampleEditorSample();	updatePatternWidth();	initFTHelp(); 	return true; setupGUI_OOM:	showErrorMsgBox("Not enough memory!");	return false;} // TEXT ROUTINES // returns full pixel width of a char/glyphuint8_t charWidth(char ch){	return font1Widths[ch & 0x7F];} // returns full pixel width of a char/glyph (big font)uint8_t charWidth16(char ch){	return font2Widths[ch & 0x7F];} // return full pixel width of a text stringuint16_t textWidth(const char *textPtr){	assert(textPtr != NULL); 	uint16_t textWidth = 0;	while (*textPtr != '\0')		textWidth += charWidth(*textPtr++); 	// there will be a pixel spacer at the end of the last char/glyph, remove it	if (textWidth > 0)		textWidth--; 	return textWidth;} uint16_t textNWidth(const char *textPtr, int32_t length){	assert(textPtr != NULL); 	uint16_t textWidth = 0;	for (int32_t i = 0; i < length; i++)	{		const char ch = textPtr[i];		if (ch == '\0')			break; 		textWidth += charWidth(ch);	} 	// there will be a pixel spacer at the end of the last char/glyph, remove it	if (textWidth > 0)		textWidth--; 	return textWidth;} // return full pixel width of a text string (big font)uint16_t textWidth16(const char *textPtr){	assert(textPtr != NULL); 	uint16_t textWidth = 0;	while (*textPtr != '\0')		textWidth += charWidth(*textPtr++); 	// there will be a pixel spacer at the end of the last char/glyph, remove it	if (textWidth > 0)		textWidth--; 	return textWidth;} void textOutTiny(int32_t xPos, int32_t yPos, char *str, uint32_t color) // A..Z/a..z and 0..9{	uint32_t *dstPtr = &video.frameBuffer[(yPos * SCREEN_W) + xPos];	while (*str != '\0')	{		char chr = *str++; 		if (chr >= '0' && chr <= '9')		{			chr -= '0';		}		else if (chr >= 'a' && chr <= 'z')		{			chr -= 'a';			chr += 10;		}		else if (chr >= 'A' && chr <= 'Z')		{			chr -= 'A';			chr += 10;		}		else		{			dstPtr += FONT3_CHAR_W;			continue;		} 		const uint8_t *srcPtr = &bmp.font3[chr * FONT3_CHAR_W];		for (int32_t y = 0; y < FONT3_CHAR_H; y++)		{			for (int32_t x = 0; x < FONT3_CHAR_W; x++)			{#ifdef __arm__				if (srcPtr[x] != 0)					dstPtr[x] = color;#else				// carefully written like this to generate conditional move instructions (font data is hard to predict)				uint32_t tmp = dstPtr[x];				if (srcPtr[x] != 0) tmp = color;				dstPtr[x] = tmp;#endif			} 			srcPtr += FONT3_WIDTH;			dstPtr += SCREEN_W;		} 		dstPtr -= (SCREEN_W * FONT3_CHAR_H) - FONT3_CHAR_W;	}} void textOutTinyOutline(int32_t xPos, int32_t yPos, char *str) // A..Z/a..z and 0..9{	const uint32_t bgColor = video.palette[PAL_BCKGRND];	const uint32_t fgColor = video.palette[PAL_FORGRND]; 	textOutTiny(xPos-1, yPos,   str, bgColor);	textOutTiny(xPos,   yPos-1, str, bgColor);	textOutTiny(xPos+1, yPos,   str, bgColor);	textOutTiny(xPos,   yPos+1, str, bgColor); 	textOutTiny(xPos, yPos, str, fgColor);} void charOut(uint16_t xPos, uint16_t yPos, uint8_t paletteIndex, char chr){	assert(xPos < SCREEN_W && yPos < SCREEN_H); 	chr &= 0x7F; // this is important to get the nordic glyphs in the font	if (chr == ' ')		return; 	const uint32_t pixVal = video.palette[paletteIndex];	const uint8_t *srcPtr = &bmp.font1[chr * FONT1_CHAR_W];	uint32_t *dstPtr = &video.frameBuffer[(yPos * SCREEN_W) + xPos]; 	for (uint32_t y = 0; y < FONT1_CHAR_H; y++)	{		for (uint32_t x = 0; x < FONT1_CHAR_W; x++)		{#ifdef __arm__			if (srcPtr[x] != 0)				dstPtr[x] = pixVal;#else			// carefully written like this to generate conditional move instructions (font data is hard to predict)			uint32_t tmp = dstPtr[x];			if (srcPtr[x] != 0) tmp = pixVal;			dstPtr[x] = tmp;#endif		} 		srcPtr += FONT1_WIDTH;		dstPtr += SCREEN_W;	}} void charOutAlpha(uint16_t xPos, uint16_t yPos, uint8_t paletteIndex, char chr, uint32_t alpha){	assert(xPos < SCREEN_W && yPos < SCREEN_H); 	chr &= 0x7F; // this is important to get the nordic glyphs in the font	if (chr == ' ')		return; 	if (alpha > 65536)		alpha = 65536; 	const uint32_t pixVal = video.palette[paletteIndex];	const uint32_t palNum = paletteIndex << 24;	const uint8_t *srcPtr = &bmp.font1[chr * FONT1_CHAR_W];	uint32_t *dstPtr = &video.frameBuffer[(yPos * SCREEN_W) + xPos]; 	for (int32_t y = 0; y < FONT1_CHAR_H; y++)	{		for (int32_t x = 0; x < FONT1_CHAR_W; x++)		{			const uint32_t srcPixel = srcPtr[x];			if (srcPixel == 0)				continue; 			const uint32_t dstPixel = dstPtr[x]; 			const int32_t srcR = RGB32_R(pixVal);			const int32_t srcG = RGB32_G(pixVal);			const int32_t srcB = RGB32_B(pixVal); 			int32_t dstR = RGB32_R(dstPixel);			int32_t dstG = RGB32_G(dstPixel);			int32_t dstB = RGB32_B(dstPixel); 			dstR = ((dstR * (65536-alpha)) + (srcR * alpha)) >> 16;			dstG = ((dstG * (65536-alpha)) + (srcG * alpha)) >> 16;			dstB = ((dstB * (65536-alpha)) + (srcB * alpha)) >> 16; 			dstPtr[x] = RGB32(dstR, dstG, dstB) | palNum;		} 		srcPtr += FONT1_WIDTH;		dstPtr += SCREEN_W;	}} void charOutBg(uint16_t xPos, uint16_t yPos, uint8_t fgPalette, uint8_t bgPalette, char chr){	assert(xPos < SCREEN_W && yPos < SCREEN_H); 	chr &= 0x7F; // this is important to get the nordic glyphs in the font	if (chr == ' ')		return; 	const uint32_t fg = video.palette[fgPalette];	const uint32_t bg = video.palette[bgPalette]; 	const uint8_t *srcPtr = &bmp.font1[chr * FONT1_CHAR_W];	uint32_t *dstPtr = &video.frameBuffer[(yPos * SCREEN_W) + xPos]; 	for (int32_t y = 0; y < FONT1_CHAR_H; y++)	{		for (int32_t x = 0; x < FONT1_CHAR_W-1; x++)			dstPtr[x] = srcPtr[x] ? fg : bg; // compiles nicely into conditional move instructions 		srcPtr += FONT1_WIDTH;		dstPtr += SCREEN_W;	}} void charOutOutlined(uint16_t x, uint16_t y, uint8_t paletteIndex, char chr){	charOut(x - 1, y,     PAL_BCKGRND, chr);	charOut(x + 1, y,     PAL_BCKGRND, chr);	charOut(x,     y - 1, PAL_BCKGRND, chr);	charOut(x,     y + 1, PAL_BCKGRND, chr); 	charOut(x, y, paletteIndex, chr);} void charOutShadow(uint16_t xPos, uint16_t yPos, uint8_t paletteIndex, uint8_t shadowPaletteIndex, char chr){	assert(xPos < SCREEN_W && yPos < SCREEN_H); 	chr &= 0x7F; // this is important to get the nordic glyphs in the font	if (chr == ' ')		return; 	const uint32_t pixVal1 = video.palette[paletteIndex];	const uint32_t pixVal2 = video.palette[shadowPaletteIndex];	const uint8_t *srcPtr = &bmp.font1[chr * FONT1_CHAR_W];	uint32_t *dstPtr1 = &video.frameBuffer[(yPos * SCREEN_W) + xPos];	uint32_t *dstPtr2 = dstPtr1 + (SCREEN_W+1); 	for (int32_t y = 0; y < FONT1_CHAR_H; y++)	{		for (int32_t x = 0; x < FONT1_CHAR_W; x++)		{#ifdef __arm__			if (srcPtr[x] != 0)			{				dstPtr2[x] = pixVal2;				dstPtr1[x] = pixVal1;			}#else			// carefully written like this to generate conditional move instructions (font data is hard to predict)			uint32_t tmp = dstPtr2[x];			if (srcPtr[x] != 0) tmp = pixVal2;			dstPtr2[x] = tmp; 			tmp = dstPtr1[x];			if (srcPtr[x] != 0) tmp = pixVal1;			dstPtr1[x] = tmp;

Lines 1–500 of 1436.

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t