1201 lines · 24.9 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 <stdbool.h>#include "ft2_header.h"#include "ft2_gui.h"#include "ft2_video.h"#include "ft2_config.h"#include "ft2_diskop.h"#include "ft2_keyboard.h"#include "ft2_mouse.h"#include "ft2_bmp.h"#include "ft2_structs.h" textBox_t textBoxes[NUM_TEXTBOXES] ={	// ------ RESERVED TEXTBOXES ------	{ 0 }, 	/*	** -- STRUCT INFO: --	**  x    = x position	**  y    = y position	**  w    = width	**  h    = height	**  tx   = left padding for text	**  ty   = top padding for text	**  maxc = max characters in box string	**  rmb  = can only be triggered with right mouse button (f.ex. tracker instrument texts)	**  cmc  = change mouse cursor when hovering over it	*/ 	// ------ INSTRUMENT/SAMPLE/SONG NAME TEXTBOXES ------	// x,   y,   w,   h,  tx,ty, maxc,       rmb,   cmc	{  446,   5, 140,  10, 1, 0, 22,         true,  false },	{  446,  16, 140,  10, 1, 0, 22,         true,  false },	{  446,  27, 140,  10, 1, 0, 22,         true,  false },	{  446,  38, 140,  10, 1, 0, 22,         true,  false },	{  446,  49, 140,  10, 1, 0, 22,         true,  false },	{  446,  60, 140,  10, 1, 0, 22,         true,  false },	{  446,  71, 140,  10, 1, 0, 22,         true,  false },	{  446,  82, 140,  10, 1, 0, 22,         true,  false },	{  446,  99, 116,  10, 1, 0, 22,         true,  false },	{  446, 110, 116,  10, 1, 0, 22,         true,  false },	{  446, 121, 116,  10, 1, 0, 22,         true,  false },	{  446, 132, 116,  10, 1, 0, 22,         true,  false },	{  446, 143, 116,  10, 1, 0, 22,         true,  false },	{  424, 158, 160,  12, 2, 1, 20,         false, true  }, 	// ------ DISK OP. TEXTBOXES ------	// x,   y,   w,   h,  tx,ty, maxc,       rmb,   cmc	{   31, 158, 134,  12, 2, 1, PATH_MAX,   false, true }, 	// ------ CONFIG TEXTBOXES ------	// x,   y,   w,   h,  tx,ty, maxc,       rmb,   cmc	{ 486,   16, 143,  12, 2, 1, 80,         false, true },	{ 486,   31, 143,  12, 2, 1, 80,         false, true },	{ 486,   46, 143,  12, 2, 1, 80,         false, true },	{ 486,   61, 143,  12, 2, 1, 80,         false, true },	{ 486,   76, 143,  12, 2, 1, 80,         false, true }}; static int16_t markX1, markX2;static uint16_t oldCursorPos;static int32_t oldMouseX; static void moveTextCursorLeft(int16_t i, bool updateTextBox);static void moveTextCursorRight(int16_t i, bool updateTextBox); static void setSongModifiedFlagIfNeeded(void) // called during keystrokes in text boxes{	if (mouse.lastEditBox == TB_SONG_NAME ||	   (mouse.lastEditBox >= TB_INST1 && mouse.lastEditBox <= TB_INST8) ||	   (mouse.lastEditBox >= TB_SAMP1 && mouse.lastEditBox <= TB_SAMP5))	{		setSongModifiedFlag();	}} bool textIsMarked(void){	if (markX1 == markX2)		return false; 	return true;} static void removeTextMarking(void){	markX1 = 0;	markX2 = 0;} static int16_t getTextMarkStart(void){	if (markX2 < markX1)		return markX2; 	return markX1;} static int16_t getTextMarkEnd(void){	if (markX1 > markX2)		return markX1; 	return markX2;} static int16_t getTextLength(textBox_t *t, uint16_t offset){	uint16_t i; 	if (t->textPtr == NULL || offset >= t->maxChars)		return 0; 	// count number of characters in text	for (i = offset; i < t->maxChars; i++)	{		if (t->textPtr[i] == '\0')			break;	} 	i -= offset; // i now contains string length	assert(i <= t->maxChars); 	return i;} static void deleteMarkedText(textBox_t *t){	if (!textIsMarked())		return; 	const int16_t start = getTextMarkStart();	const int16_t end = getTextMarkEnd(); 	assert(start < t->maxChars && end <= t->maxChars); 	// calculate pixel width of string to delete	int32_t deleteTextWidth = 0;	for (int32_t i = start; i < end; i++)		deleteTextWidth += charWidth(t->textPtr[i]); 	// copy markEnd part to markStart, and add null termination	const int32_t length = (int32_t)strlen(&t->textPtr[end]);	if (length > 0)		memcpy(&t->textPtr[start], &t->textPtr[end], length);	t->textPtr[start+length] = '\0'; 	// scroll buffer offset to the left if we are scrolled	if (t->bufOffset >= deleteTextWidth)		t->bufOffset -= deleteTextWidth;	else		t->bufOffset = 0; 	// set text cursor to markStart	t->cursorPos = start; 	setSongModifiedFlagIfNeeded();} static void setCursorToMarkStart(textBox_t *t){	if (!textIsMarked())		return; 	const int16_t start = getTextMarkStart();	assert(start < t->maxChars);	t->cursorPos = start; 	int32_t startXPos = 0;	for (int32_t i = 0; i < start; i++)	{		const char ch = t->textPtr[i];		if (ch == '\0')			break; 		startXPos += charWidth(ch);	} 	// change buffer offset, if needed	if (startXPos < t->bufOffset)		t->bufOffset = startXPos;} static void setCursorToMarkEnd(textBox_t *t){	if (!textIsMarked())		return; 	const int16_t end = getTextMarkEnd();	assert(end <= t->maxChars);	t->cursorPos = end; 	int32_t endXPos = 0;	for (int32_t i = 0; i < end; i++)	{		const char ch = t->textPtr[i];		if (ch == '\0')			break; 		endXPos += charWidth(ch);	} 	// change buffer offset, if needed	if (endXPos > t->bufOffset+t->renderW)		t->bufOffset = endXPos - t->renderW;} static void copyMarkedText(textBox_t *t){	if (!textIsMarked())		return; 	const int32_t start = getTextMarkStart();	const int32_t end = getTextMarkEnd(); 	assert(start < t->maxChars && end <= t->maxChars); 	const int32_t length = end - start;	if (length < 1)		return; 	/* Change mark-end character to NUL so that we	** we only copy the marked section of the string.	** There's always room for a NUL at the end of	** the text box string, so this is safe.	**/	const char oldChar = t->textPtr[end];	t->textPtr[end] = '\0'; 	char *utf8Text = cp437ToUtf8(&t->textPtr[start]);	if (utf8Text != NULL)	{		SDL_SetClipboardText(utf8Text);		free(utf8Text);	} 	t->textPtr[end] = oldChar; // set back original character} static void cutMarkedText(textBox_t *t){	if (!textIsMarked())		return; 	copyMarkedText(t);	deleteMarkedText(t);	removeTextMarking(); 	drawTextBox(mouse.lastEditBox);} static void pasteText(textBox_t *t){	char *endPart; 	if (!SDL_HasClipboardText())		return; 	// if we've marked text, delete it and remove text marking	if (textIsMarked())	{		deleteMarkedText(t);		removeTextMarking();	} 	if (t->cursorPos >= t->maxChars)		return; 	const int32_t textLength = getTextLength(t, 0); 	const int32_t roomLeft = t->maxChars - textLength;	if (roomLeft <= 0)		return; // no more room! 	char *copiedTextUtf8 = SDL_GetClipboardText(); 	char *copiedText = utf8ToCp437(copiedTextUtf8, true);	if (copiedText == NULL)		return; 	int32_t copiedTextLength = (int32_t)strlen(copiedText);	if (copiedTextLength > roomLeft)		copiedTextLength = roomLeft; 	const uint16_t endOffset = t->cursorPos;	endPart = NULL; // prevent false compiler warning 	const int32_t endPartLength = getTextLength(t, endOffset);	if (endPartLength > 0)	{		endPart = (char *)malloc(endPartLength+1);		if (endPart == NULL)		{			free(copiedText);			okBox(0, "System message", "Not enough memory!");			return;		}	} 	// make a copy of end data	if (endPartLength > 0)	{		memcpy(endPart, &t->textPtr[endOffset], endPartLength);		endPart[endPartLength] = '\0';	} 	// paste copied data	memcpy(&t->textPtr[endOffset], copiedText, copiedTextLength);	t->textPtr[endOffset+copiedTextLength] = '\0';	free(copiedText); 	// append end data	if (endPartLength > 0)	{		strcat(&t->textPtr[endOffset+copiedTextLength], endPart);		free(endPart);	} 	for (int32_t i = 0; i < copiedTextLength; i++)		moveTextCursorRight(mouse.lastEditBox, TEXTBOX_NO_UPDATE); 	drawTextBox(mouse.lastEditBox); 	setSongModifiedFlagIfNeeded();} void exitTextEditing(void){	if (!editor.editTextFlag)		return; 	if (mouse.lastEditBox >= 0 && mouse.lastEditBox < NUM_TEXTBOXES)	{		textBoxes[mouse.lastEditBox].bufOffset = 0;		removeTextMarking();		drawTextBox(mouse.lastEditBox);	} 	if (mouse.lastEditBox == TB_DISKOP_FILENAME && getDiskOpItem() == DISKOP_ITEM_MODULE)	{		updateCurrSongFilename(); // for window title		updateWindowTitle(true);	} 	keyb.ignoreCurrKeyUp = true; // prevent a note being played (on enter key)	editor.editTextFlag = false; 	hideSprite(SPRITE_TEXT_CURSOR);	SDL_StopTextInput();} static int16_t cursorPosToX(textBox_t *t){	assert(t->textPtr != NULL); 	int32_t x = -1; // cursor starts one pixel before character	for (int16_t i = 0; i < t->cursorPos; i++)		x += charWidth(t->textPtr[i]); 	x -= t->bufOffset; // subtract by buffer offset to get real X position	return (int16_t)x;} int16_t getTextCursorX(textBox_t *t){	return t->x + t->tx + cursorPosToX(t);} int16_t getTextCursorY(textBox_t *t){	return t->y + t->ty;} static void scrollTextBufferLeft(textBox_t *t){	// scroll buffer and clamp	t->bufOffset -= TEXT_SCROLL_VALUE;	if (t->bufOffset < 0)		t->bufOffset = 0;} static void scrollTextBufferRight(textBox_t *t, uint16_t numCharsInText){	assert(numCharsInText <= t->maxChars); 	// get end of text position	int32_t textEnd = 0;	for (uint16_t j = 0; j < numCharsInText; j++)		textEnd += charWidth(t->textPtr[j]); 	// subtract by text box width and clamp to 0	textEnd -= t->renderW;	if (textEnd < 0)		textEnd = 0; 	// scroll buffer and clamp	t->bufOffset += TEXT_SCROLL_VALUE;	if (t->bufOffset > textEnd)		t->bufOffset = textEnd;} static void moveTextCursorToMouseX(uint16_t textBoxID){	int16_t i; 	textBox_t *t = &textBoxes[textBoxID];	if ((mouse.x == t->x && t->bufOffset == 0) || t->textPtr == NULL || t->textPtr[0] == '\0')	{		t->cursorPos = 0;		return;	} 	int16_t numChars = getTextLength(t, 0); 	// find out what character we are clicking at, and set cursor to that character	const int32_t mx = t->bufOffset + mouse.x;	int32_t tx = (t->x + t->tx) - 1;	int32_t cw = -1; 	for (i = 0; i < numChars; i++)	{		cw = charWidth(t->textPtr[i]);		const int32_t tx2 = tx + cw; 		if (mx >= tx && mx < tx2)		{			t->cursorPos = i;			break;		} 		tx += cw;	} 	// set to last character if we clicked outside the end of the text	if (i == numChars && mx >= tx)		t->cursorPos = numChars; 	if (cw != -1)	{		const int16_t cursorPos = cursorPosToX(t); 		// scroll buffer to the right if needed		if (cursorPos+cw > t->renderW)			scrollTextBufferRight(t, numChars); 		// scroll buffer to the left if needed		else if (cursorPos < 0-1)			scrollTextBufferLeft(t);	} 	editor.textCursorBlinkCounter = 0;} static void textOutBuf(uint8_t *dstBuffer, uint32_t dstWidth, uint8_t paletteIndex, char *text, uint32_t maxTextLen){	assert(text != NULL);	if (*text == '\0')		return; // empty string 	uint16_t currX = 0;	for (uint32_t i = 0; i < maxTextLen; i++)	{		const char chr = *text++ & 0x7F;		if (chr == '\0')			break; 		if (chr != ' ')		{			const uint8_t *srcPtr = &bmp.font1[chr * FONT1_CHAR_W];			uint8_t *dstPtr = &dstBuffer[currX]; 			for (uint32_t y = 0; y < FONT1_CHAR_H; y++)			{				for (uint32_t x = 0; x < FONT1_CHAR_W; x++)				{					if (srcPtr[x])						dstPtr[x] = paletteIndex;				} 				srcPtr += FONT1_WIDTH;				dstPtr += dstWidth;			}		} 		currX += charWidth(chr);	}}  // a lot of filling here, but textboxes are small so no problem...void drawTextBox(uint16_t textBoxID){	int8_t cw;	uint8_t pal; 

Lines 1–500 of 1201.

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