From 3dcc31d7021f8f147ec14760e6e5f266e863bcb1 Mon Sep 17 00:00:00 2001 From: Marius Andra Date: Wed, 24 Apr 2024 01:39:57 +0200 Subject: [PATCH] text overflow --- frameos/src/apps/text/app.nim | 84 +++++++++++++++++++++---------- frameos/src/apps/text/config.json | 10 ++++ 2 files changed, 68 insertions(+), 26 deletions(-) diff --git a/frameos/src/apps/text/app.nim b/frameos/src/apps/text/app.nim index df69b6b2..203b1083 100644 --- a/frameos/src/apps/text/app.nim +++ b/frameos/src/apps/text/app.nim @@ -1,4 +1,4 @@ -import pixie, options +import pixie, options, json, strformat import frameos/types import frameos/utils/font @@ -14,6 +14,7 @@ type fontSize*: float borderColor*: Color borderWidth*: int + overflow*: string RenderData* = object text*: string @@ -57,30 +58,61 @@ proc `==`(obj1, obj2: RenderData): bool = obj1.fontSize == obj2.fontSize and obj1.borderColor == obj2.borderColor and obj1.borderWidth == obj2.borderWidth -proc generateTypeset(typeface: Typeface, renderData: RenderData, +proc generateTypeset(self: App, typeface: Typeface, renderData: RenderData, border: bool): Arrangement = - - let font = if border: - newFont(typeface, renderData.fontSize, renderData.borderColor) - else: - newFont(typeface, renderData.fontSize, renderData.fontColor) - - let hAlign = case renderData.position: - of "top-right", "center-right", "bottom-right": RightAlign - of "top-left", "center-left", "bottom-left": LeftAlign - else: CenterAlign - let vAlign = case renderData.position: - of "top-left", "top-center", "top-right": TopAlign - of "bottom-left", "bottom-center", "bottom-right": BottomAlign - else: MiddleAlign - - result = typeset( - spans = [newSpan(renderData.text, font)], - bounds = vec2(renderData.width.toFloat() - 2 * renderData.padding, - renderData.height.toFloat() - 2 * renderData.padding), - hAlign = hAlign, - vAlign = vAlign, - ) + let + hAlign = case renderData.position: + of "top-right", "center-right", "bottom-right": RightAlign + of "top-left", "center-left", "bottom-left": LeftAlign + else: CenterAlign + vAlign = case renderData.position: + of "top-left", "top-center", "top-right": TopAlign + of "bottom-left", "bottom-center", "bottom-right": BottomAlign + else: MiddleAlign + color = if border: renderData.borderColor else: renderData.fontColor + width = renderData.width.toFloat() - 2 * renderData.padding + height = renderData.height.toFloat() - 2 * renderData.padding + bounds = vec2(width, height) + font = newFont(typeface, renderData.fontSize, color) + + if self.appConfig.overflow == "visible": + return typeset([newSpan(renderData.text, font)], bounds, hAlign, vAlign) + + else: # "fit-bounds" + var tooBigFontSize = 0.0 + var tooSmallFontSize = 0.0 + var loopIndex = 0 + while loopIndex < 100: + loopIndex += 1 + result = typeset([newSpan(renderData.text, font)], bounds, hAlign, vAlign) + let bounds = layoutBounds(result) + + # if the text is too big, shrink the font size + if bounds.y > height: + if font.size < 2: + break + + # try to get closer based on the ratio + tooBigFontSize = font.size + if tooSmallFontSize > 0.0: + font.size = (tooBigFontSize + tooSmallFontSize) / 2 + else: + font.size = tooBigFontSize / 2 + continue + + # we're in bounds, and on the first run (text was never too big), so return + elif tooBigFontSize == 0.0: + break + + # the text is too small, and was once too big + else: + if height - bounds.y < 1: + break + tooSmallFontSize = font.size + if tooBigFontSize - tooSmallFontSize < 0.5: + break + font.size = (tooBigFontSize + tooSmallFontSize) / 2 + continue proc run*(self: App, context: ExecutionContext) = let renderData = RenderData( @@ -97,11 +129,11 @@ proc run*(self: App, context: ExecutionContext) = let cacheMatch = self.cachedRender.isSome and self.cachedRender.get().renderData == renderData let textTypeset = if cacheMatch: self.cachedRender.get().typeset - else: generateTypeset(self.typeface, renderData, false) + else: self.generateTypeset(self.typeface, renderData, false) let borderTypeset = if renderData.borderWidth > 0: if cacheMatch: self.cachedRender.get().borderTypeset - else: some(generateTypeset(self.typeface, renderData, true)) + else: some(self.generateTypeset(self.typeface, renderData, true)) else: none(Arrangement) if not cacheMatch: diff --git a/frameos/src/apps/text/config.json b/frameos/src/apps/text/config.json index b553fd2b..cbf9cbb5 100644 --- a/frameos/src/apps/text/config.json +++ b/frameos/src/apps/text/config.json @@ -86,6 +86,16 @@ "required": true, "label": "Border width", "placeholder": "1" + }, + { + "name": "overflow", + "type": "select", + "options": [ + "fit-bounds", + "visible" + ], + "value": "fit-bounds", + "label": "Overflow" } ] }