From 8489b7a622c2e980030415a965f294784a7088a7 Mon Sep 17 00:00:00 2001 From: hedara90 <90hedara@gmail.com> Date: Sat, 7 Jun 2025 05:13:07 +0200 Subject: [PATCH] Added naive line break (#7076) Co-authored-by: Hedara --- include/line_break.h | 3 + src/line_break.c | 133 ++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 135 insertions(+), 1 deletion(-) diff --git a/include/line_break.h b/include/line_break.h index af0d27ff21..12c4603528 100644 --- a/include/line_break.h +++ b/include/line_break.h @@ -32,6 +32,9 @@ u32 CountLineBreaks(u8 *src); void BreakStringAutomatic(u8 *src, u32 maxWidth, u32 screenLines, u8 fontId, enum ToggleScrollPrompt toggleScrollPrompt); void BreakSubStringAutomatic(u8 *src, u32 maxWidth, u32 screenLines, u8 fontId, enum ToggleScrollPrompt toggleScrollPrompt); +void BreakStringNaive(u8 *src, u32 maxWidth, u32 screenLines, u8 fontId, enum ToggleScrollPrompt toggleScrollPrompt); +void BreakSubStringNaive(u8 *src, u32 maxWidth, u32 screenLines, u8 fontId, enum ToggleScrollPrompt toggleScrollPrompt); + bool32 IsWordSplittingChar(const u8 *src, u32 index); u32 GetStringBadness(struct StringLine *stringLines, u32 numLines, u32 maxWidth); void BuildNewString(struct StringLine *stringLines, u32 numLines, u32 maxLines, u8 *str, enum ToggleScrollPrompt toggleScrollPrompt); diff --git a/src/line_break.c b/src/line_break.c index 6684b32375..169d68332b 100644 --- a/src/line_break.c +++ b/src/line_break.c @@ -47,6 +47,137 @@ void BreakStringAutomatic(u8 *src, u32 maxWidth, u32 screenLines, u8 fontId, enu BreakSubStringAutomatic(currSrc, maxWidth, screenLines, fontId, toggleScrollPrompt); } +void BreakStringNaive(u8 *src, u32 maxWidth, u32 screenLines, u8 fontId, enum ToggleScrollPrompt toggleScrollPrompt) +{ + u32 currIndex = 0; + u8 *currSrc = src; + while (src[currIndex] != EOS) + { + if (src[currIndex] == CHAR_PROMPT_CLEAR) + { + u8 replacedChar = src[currIndex + 1]; + src[currIndex + 1] = EOS; + BreakSubStringNaive(currSrc, maxWidth, screenLines, fontId, toggleScrollPrompt); + src[currIndex + 1] = replacedChar; + currSrc = &src[currIndex + 1]; + } + currIndex++; + } + BreakSubStringNaive(currSrc, maxWidth, screenLines, fontId, toggleScrollPrompt); +} + +#define SCROLL_PROMPT_WIDTH 8 +void BreakSubStringNaive(u8 *src, u32 maxWidth, u32 screenLines, u8 fontId, enum ToggleScrollPrompt toggleScrollPrompt) +{ + // If the string already has line breaks, don't interfere with them + if (StringHasManualBreaks(src)) + return; + // Sanity check + if (src[0] == EOS) + return; + u32 numChars = 1; + u32 numWords = 1; + u32 currWordIndex = 0; + u32 currWordLength = 1; + bool32 isPrevCharSplitting = FALSE; + bool32 isCurrCharSplitting; + // Get numbers of chars in string and count words + while (src[numChars] != EOS) + { + isCurrCharSplitting = IsWordSplittingChar(src, numChars); + if (isCurrCharSplitting && !isPrevCharSplitting) + numWords++; + isPrevCharSplitting = isCurrCharSplitting; + numChars++; + } + // Allocate enough space for word data + struct StringWord *allWords = Alloc(numWords*sizeof(struct StringWord)); + + allWords[currWordIndex].startIndex = 0; + allWords[currWordIndex].width = 0; + isPrevCharSplitting = FALSE; + // Fill in word begin index and lengths + for (u32 i = 1; i < numChars; i++) + { + isCurrCharSplitting = IsWordSplittingChar(src, i); + if (isCurrCharSplitting && !isPrevCharSplitting) + { + allWords[currWordIndex].length = currWordLength; + currWordIndex++; + currWordLength = 0; + } + else if (!isCurrCharSplitting && isPrevCharSplitting) + { + allWords[currWordIndex].startIndex = i; + allWords[currWordIndex].width = 0; + currWordLength++; + } + else + { + currWordLength++; + } + isPrevCharSplitting = isCurrCharSplitting; + } + allWords[currWordIndex].length = currWordLength; + + // Fill in individual word widths + for (u32 i = 0; i < numWords; i++) + { + for (u32 j = 0; j < allWords[i].length; j++) + allWords[i].width += GetGlyphWidth(src[allWords[i].startIndex + j], FALSE, fontId); + } + + // Step 1: Does it all fit one one line? Then no break + // Step 2: Try to split across minimum number of lines + u32 spaceWidth = GetGlyphWidth(CHAR_SPACE, FALSE, fontId); + u32 totalWidth = allWords[0].width; + // Calculate total widths without any line breaks + for (u32 i = 1; i < numWords; i++) + totalWidth += allWords[i].width + spaceWidth; + + // If it doesn't fit on 1 line, do line breaks + if (totalWidth > maxWidth) + { + u32 currWidth = 0; + u32 numBreaks = 0; + u32 currWords = 1; + for (u32 wordIndex = 0; wordIndex < numWords; wordIndex++) + { + currWidth += allWords[wordIndex].width; + if (numBreaks == screenLines - 1) + { + if (SCROLL_PROMPT_WIDTH + currWidth + (currWords - 1) * spaceWidth > maxWidth) + { + src[allWords[wordIndex].startIndex - 1] = CHAR_PROMPT_SCROLL; + currWidth = allWords[wordIndex].length; + currWords = 1; + } + else + { + currWords++; + } + } + else + { + if (currWidth + (currWords - 1) * spaceWidth > maxWidth) + { + src[allWords[wordIndex].startIndex - 1] = CHAR_NEWLINE; + currWidth = allWords[wordIndex].width; + currWords = 1; + numBreaks++; + } + else + { + currWords++; + } + } + } + } + + Free(allWords); +} +#undef SCROLL_PROMPT_WIDTH + void BreakSubStringAutomatic(u8 *src, u32 maxWidth, u32 screenLines, u8 fontId, enum ToggleScrollPrompt toggleScrollPrompt) { // If the string already has line breaks, don't interfere with them @@ -109,7 +240,7 @@ void BreakSubStringAutomatic(u8 *src, u32 maxWidth, u32 screenLines, u8 fontId, // Step 1: Does it all fit one one line? Then no break // Step 2: Try to split across minimum number of lines - u32 spaceWidth = GetGlyphWidth(0, FALSE, fontId); + u32 spaceWidth = GetGlyphWidth(CHAR_SPACE, FALSE, fontId); u32 totalWidth = allWords[0].width; // Calculate total widths without any line breaks for (u32 i = 1; i < numWords; i++)