Hello everyone,
I am currently working on a (very early progress) retained-mode UI library using raylib. I might switch to SDL3 later, or try to make a CPU-only rendering engine in the far future.
Right now i'm trying to implement a multi-line text edit widget, that would be as versatile as possible, all while maintaining low memory usage. I So far my structure consists of an "original text" character array, and an array of struct representing wrapped lines.
typedef struct TextBox {
Widget widget;
char* text;
int cursorX; int cursorY;
int offsetX; int offsetY;
TextLine* lines;
int _lineCount;
};
At each resize, the layout is recalculated, and the lines reallocated, which I find really wasteful. However, I didn't come up with another model for text editing yet.
void TextBox_Resize(TextBox* textbox, int w, int h){
textbox->widget.bounds.w = w;
textbox->widget.bounds.h = h;
textbox->_lineCount = 0;
//Estimate text length
int textLength = TextLength(textbox->text); //Raylib function
int totalTextWidth = MeasureText(textbox->text, 12);
int estimatedLineCount = (int)(totalTextWidth / w) + 1;
//Add 1 line to the estimation for each newline
for (int i = 0; i < textLength; i++) {
if (textbox->text[i] == '\n') { estimatedLineCount++; }
}
printf("Estimating %d lines for resize\n", estimatedLineCount);
//free(textbox->lines);
textbox->lines = realloc(textbox->lines, estimatedLineCount * sizeof(TextLine));
Font font = GetFontDefault(); //Will be replaced after
int currentLine = 0;
int lineStart = 0;
int lineEnd = 0;
float currentGlyphWidth = 0;
float totalLineWidth = 0;
// Almost copied from raylib example
for (int i = 0; i < textLength; i++){
//printf("Current byte %d\n", i);
int codepointByteCount = 0;
// Gets UTF8 codepoints instead of simply bytes.
int codepoint = GetCodepoint(&textbox->text[i], &codepointByteCount);
//printf("Got codepoint %d, is %c\n", codepoint, codepoint);
int glyphIndex = GetGlyphIndex(font, codepoint);
//printf("Got index %d\n", index);
// We are advancing more than 1 byte at a time if we get UTF-8 text.
// Since the default font is limited, replace invalid codepoints with
// "?" and keep advancing 1 byte at a time.
if (codepoint == 0x3f) codepointByteCount = 1;
i += (codepointByteCount - 1); // i will advance by itself in next iter, dont accumulate offsets.
currentGlyphWidth = GetGlyphAtlasRec(GetFontDefault(), codepoint).width;
//printf("Glyph width is %f\n", currentGlyphWidth);
totalLineWidth += currentGlyphWidth;
//printf("Total line length is %f\n", totalLineWidth);
// Follow line
lineEnd = i;
if (totalLineWidth >= textbox->widget.bounds.w || codepoint == '\n' || codepoint == 0) {
printf("line is %f pixels wide\n", totalLineWidth);
textbox->lines[currentLine].text = calloc((lineEnd - lineStart), sizeof(char));
textbox->lines[currentLine].text = strncpy(textbox->lines[currentLine].text, textbox->text + lineStart, (lineEnd - lineStart));
// Set last char of text to null
textbox->lines[currentLine].text[lineEnd - lineStart] = '\0';
lineStart = (codepoint == '\n' ? lineEnd + 1 : lineEnd);
totalLineWidth = 0;
} else {
lineStart = lineEnd; lineEnd = textLength;
}
textbox->lines[currentLine].text[lineEnd - lineStart] = '\0';
currentLine++; textbox->_lineCount++;
}
}
Are there any articles / projects with clever approaches to text editing, that keep a low memory footprint ?
Thanks for your advice !