Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions config.nims
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
--nimcache:".nimcache/"
--passc:"-Wno-incompatible-function-pointer-types"
--define:useMalloc
--define:release

import std/strutils
import std/os
Expand Down
126 changes: 122 additions & 4 deletions examples/siwin_text.nim
Original file line number Diff line number Diff line change
Expand Up @@ -233,13 +233,45 @@ proc makeRenderTree*(
if rune == Rune(10):
monoLines.inc
let monoHeight = monoLines.float32 * monoLineHeight + monoPad * 2
let invertedLineHeight = uiFont.size * 1.4'f32
let sectionGap = 60.0'f32

let textRect =
rect(innerRect.x, innerRect.y, innerRect.w, innerRect.h - monoHeight - 12'f32)
let monoRect =
rect(innerRect.x, textRect.y + textRect.h + 12'f32, innerRect.w, monoHeight)
proc mirroredInputRect(finalRect: Rect): Rect =
rect(finalRect.x, h - finalRect.y - finalRect.h, finalRect.w, finalRect.h)

let textRect = rect(
innerRect.x,
innerRect.y,
innerRect.w,
innerRect.h - monoHeight - invertedLineHeight * 2.0'f32 - sectionGap * 3.0'f32,
)
let invertedTextRect = rect(
innerRect.x, textRect.y + textRect.h + sectionGap, innerRect.w, invertedLineHeight
)
let mirroredInvertedTextRect = rect(
innerRect.x,
invertedTextRect.y + invertedTextRect.h + sectionGap,
innerRect.w,
invertedLineHeight,
)
let monoRect = rect(
innerRect.x,
mirroredInvertedTextRect.y + mirroredInvertedTextRect.h + sectionGap,
innerRect.w,
monoHeight,
)

let (layout, highlightRange) = buildBodyTextLayout(uiFont, textRect, modeLine)
let invertedText = "Inverted text line (NfInvertY) with selection"
let invertedSelectionRange = findPhraseRange(invertedText, "NfInvertY")
let invertedLayout = typeset(
rect(0, 0, invertedTextRect.w, invertedTextRect.h),
[span(uiFont, rgba(30, 30, 30, 255), invertedText)],
hAlign = Left,
vAlign = Top,
minContent = false,
wrap = false,
)

discard result.addChild(
z,
Expand Down Expand Up @@ -273,6 +305,92 @@ proc makeRenderTree*(
corners: [10.0'f32, 10.0, 10.0, 10.0],
),
)

let invertedGlyphBounds = rect(
invertedTextRect.x + invertedLayout.bounding.x,
invertedTextRect.y + invertedLayout.bounding.y,
invertedLayout.bounding.w,
invertedLayout.bounding.h,
)
let mirroredInvertedGlyphBounds = rect(
mirroredInvertedTextRect.x + invertedLayout.bounding.x,
mirroredInvertedTextRect.y + invertedLayout.bounding.y,
invertedLayout.bounding.w,
invertedLayout.bounding.h,
)
discard result.addChild(
z,
cardIdx,
Fig(
kind: nkRectangle,
childCount: 0,
zlevel: z,
screenBox: invertedGlyphBounds,
fill: clearColor,
stroke: RenderStroke(weight: 1.5, fill: rgba(38, 38, 38, 155).color),
corners: [4.0'f32, 4.0, 4.0, 4.0],
),
)

discard result.addChild(
z,
cardIdx,
Fig(
kind: nkText,
childCount: 0,
zlevel: z,
flags: {NfInvertY, NfSelectText},
screenBox: invertedTextRect,
selectionRange: invertedSelectionRange,
fill: linear(rgba(255, 244, 175, 255), rgba(255, 200, 140, 255), axis = fgaY),
textLayout: invertedLayout,
),
)

discard result.addChild(
z,
cardIdx,
Fig(
kind: nkRectangle,
childCount: 0,
zlevel: z,
screenBox: mirroredInvertedGlyphBounds,
fill: clearColor,
stroke: RenderStroke(weight: 1.5, fill: rgba(42, 96, 168, 170).color),
corners: [4.0'f32, 4.0, 4.0, 4.0],
),
)

let mirroredTransformIdx = result.addChild(
z,
cardIdx,
Fig(
kind: nkTransform,
childCount: 0,
zlevel: z,
transform: TransformStyle(
translation: vec2(0.0'f32, h),
matrix: scale(vec3(1.0'f32, -1.0'f32, 1.0'f32)),
useMatrix: true,
),
),
)

discard result.addChild(
z,
mirroredTransformIdx,
Fig(
kind: nkText,
childCount: 0,
zlevel: z,
flags: {NfInvertY, NfSelectText},
screenBox: mirroredInputRect(mirroredInvertedTextRect),
selectionRange: invertedSelectionRange,
fill: linear(rgba(180, 220, 255, 220), rgba(130, 180, 255, 220), axis = fgaY),
textLayout: invertedLayout,
),
)

let monoColors = [
linear(rgba(236, 238, 245, 255), rgba(182, 214, 255, 255), axis = fgaX),
rgba(255, 210, 160, 255),
Expand Down
126 changes: 122 additions & 4 deletions examples/windy_text.nim
Original file line number Diff line number Diff line change
Expand Up @@ -236,13 +236,45 @@ proc makeRenderTree*(
if rune == Rune(10):
monoLines.inc
let monoHeight = monoLines.float32 * monoLineHeight + monoPad * 2
let invertedLineHeight = uiFont.size * 1.4'f32
let sectionGap = 60.0'f32

let textRect =
rect(innerRect.x, innerRect.y, innerRect.w, innerRect.h - monoHeight - 12'f32)
let monoRect =
rect(innerRect.x, textRect.y + textRect.h + 12'f32, innerRect.w, monoHeight)
proc mirroredInputRect(finalRect: Rect): Rect =
rect(finalRect.x, h - finalRect.y - finalRect.h, finalRect.w, finalRect.h)

let textRect = rect(
innerRect.x,
innerRect.y,
innerRect.w,
innerRect.h - monoHeight - invertedLineHeight * 2.0'f32 - sectionGap * 3.0'f32,
)
let invertedTextRect = rect(
innerRect.x, textRect.y + textRect.h + sectionGap, innerRect.w, invertedLineHeight
)
let mirroredInvertedTextRect = rect(
innerRect.x,
invertedTextRect.y + invertedTextRect.h + sectionGap,
innerRect.w,
invertedLineHeight,
)
let monoRect = rect(
innerRect.x,
mirroredInvertedTextRect.y + mirroredInvertedTextRect.h + sectionGap,
innerRect.w,
monoHeight,
)

let (layout, highlightRange) = buildBodyTextLayout(uiFont, textRect, modeLine)
let invertedText = "Inverted text line (NfInvertY) with selection"
let invertedSelectionRange = findPhraseRange(invertedText, "NfInvertY")
let invertedLayout = typeset(
rect(0, 0, invertedTextRect.w, invertedTextRect.h),
[span(uiFont, rgba(30, 30, 30, 255), invertedText)],
hAlign = Left,
vAlign = Top,
minContent = false,
wrap = false,
)

discard result.addChild(
z,
Expand Down Expand Up @@ -276,6 +308,92 @@ proc makeRenderTree*(
corners: [10.0'f32, 10.0, 10.0, 10.0],
),
)

let invertedGlyphBounds = rect(
invertedTextRect.x + invertedLayout.bounding.x,
invertedTextRect.y + invertedLayout.bounding.y,
invertedLayout.bounding.w,
invertedLayout.bounding.h,
)
let mirroredInvertedGlyphBounds = rect(
mirroredInvertedTextRect.x + invertedLayout.bounding.x,
mirroredInvertedTextRect.y + invertedLayout.bounding.y,
invertedLayout.bounding.w,
invertedLayout.bounding.h,
)
discard result.addChild(
z,
cardIdx,
Fig(
kind: nkRectangle,
childCount: 0,
zlevel: z,
screenBox: invertedGlyphBounds,
fill: clearColor,
stroke: RenderStroke(weight: 1.5, fill: rgba(38, 38, 38, 155).color),
corners: [4.0'f32, 4.0, 4.0, 4.0],
),
)

discard result.addChild(
z,
cardIdx,
Fig(
kind: nkText,
childCount: 0,
zlevel: z,
flags: {NfInvertY, NfSelectText},
screenBox: invertedTextRect,
selectionRange: invertedSelectionRange,
fill: linear(rgba(255, 244, 175, 255), rgba(255, 200, 140, 255), axis = fgaY),
textLayout: invertedLayout,
),
)

discard result.addChild(
z,
cardIdx,
Fig(
kind: nkRectangle,
childCount: 0,
zlevel: z,
screenBox: mirroredInvertedGlyphBounds,
fill: clearColor,
stroke: RenderStroke(weight: 1.5, fill: rgba(42, 96, 168, 170).color),
corners: [4.0'f32, 4.0, 4.0, 4.0],
),
)

let mirroredTransformIdx = result.addChild(
z,
cardIdx,
Fig(
kind: nkTransform,
childCount: 0,
zlevel: z,
transform: TransformStyle(
translation: vec2(0.0'f32, h),
matrix: scale(vec3(1.0'f32, -1.0'f32, 1.0'f32)),
useMatrix: true,
),
),
)

discard result.addChild(
z,
mirroredTransformIdx,
Fig(
kind: nkText,
childCount: 0,
zlevel: z,
flags: {NfInvertY, NfSelectText},
screenBox: mirroredInputRect(mirroredInvertedTextRect),
selectionRange: invertedSelectionRange,
fill: linear(rgba(180, 220, 255, 220), rgba(130, 180, 255, 220), axis = fgaY),
textLayout: invertedLayout,
),
)

let monoColors = [
linear(rgba(236, 238, 245, 255), rgba(182, 214, 255, 255), axis = fgaX),
rgba(255, 210, 160, 255),
Expand Down
2 changes: 1 addition & 1 deletion figdraw.nimble
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
version = "0.22.1"
version = "0.22.2"
author = "Jaremy Creechley"
description = "UI Engine for Nim"
license = "MIT"
Expand Down
27 changes: 6 additions & 21 deletions src/figdraw/figrender.nim
Original file line number Diff line number Diff line change
Expand Up @@ -290,23 +290,14 @@ proc selectionScreenRect*(nodeBox: Rect, selectionRect: Rect): Rect {.inline.} =
)
.scaled()

proc invertScreenRectY*(nodeBox: Rect, screenRect: Rect): Rect {.inline.} =
## Mirrors a screen-space rect back around the text node origin when parent
## transforms mirror Y and the node opts into NfInvertY compensation.
result = screenRect
result.y = nodeBox.y.scaled() * 2.0'f32 - screenRect.y - screenRect.h

proc shouldInvertY(ctx: BackendContext, node: Fig): bool {.inline.} =
NfInvertY in node.flags and ctx.transformMirrorsY()

proc renderText(ctx: BackendContext, node: Fig) {.forbids: [AppMainThreadEff].} =
## Draw characters (glyphs)
let
lcdFiltering = ctx.textLcdFilteringEnabled()
subpixelPositioning = ctx.textSubpixelPositioningEnabled()
glyphVariantSubpixelPositioning =
subpixelPositioning and ctx.textSubpixelGlyphVariantsEnabled()
invertText = ctx.shouldInvertY(node)
invertText = NfInvertY in node.flags

if NfSelectText in node.flags and fillAlphaMax(node.fill) > 0'u8:
let rects = node.textLayout.selectionRects
Expand All @@ -318,7 +309,7 @@ proc renderText(ctx: BackendContext, node: Fig) {.forbids: [AppMainThreadEff].}
for idx in startIdx .. endIdx:
var rect = selectionScreenRect(node.screenBox, rects[idx])
if invertText:
rect = invertScreenRectY(node.screenBox, rect)
rect = rect
if rect.w > 0 and rect.h > 0:
ctx.drawRoundedRectSdf(
rect = rect,
Expand Down Expand Up @@ -362,10 +353,7 @@ proc renderText(ctx: BackendContext, node: Fig) {.forbids: [AppMainThreadEff].}

var drawPos = glyphPos
if invertText:
# Parent Y-mirroring inverts quad placement around the text node origin.
# Compensate by reflecting glyph local Y and subtracting glyph height.
drawPos.y =
node.screenBox.y.scaled() * 2.0'f32 - drawPos.y - glyph.lineHeight.scaled()
drawPos.y = drawPos.y - (glyph.lineHeight.scaled() + glyph.descent) * 0.5'f32

ctx.drawImage(glyphId, drawPos, glyph.fill.gradientColors(), invertText)
if subpixelPositioning:
Expand Down Expand Up @@ -804,21 +792,19 @@ proc renderImage(ctx: BackendContext, node: Fig) =
return
let box = node.screenBox.scaled()
let size = vec2(box.w, box.h)
let invertImage = ctx.shouldInvertY(node)
ctx.drawImage(
node.image.id.Hash,
pos = box.xy,
color = fillCenterColor(node.image.fill),
size = size,
flipY = invertImage,
flipY = NfInvertY in node.flags
)

proc renderMsdfImage(ctx: BackendContext, node: Fig) =
if node.msdfImage.id.int == 0:
return
let box = node.screenBox.scaled()
let size = vec2(box.w, box.h)
let invertImage = ctx.shouldInvertY(node)
let pxRange =
if node.msdfImage.pxRange > 0.0'f32: node.msdfImage.pxRange else: 4.0'f32
let sdThreshold =
Expand All @@ -835,15 +821,14 @@ proc renderMsdfImage(ctx: BackendContext, node: Fig) =
pxRange = pxRange,
sdThreshold = sdThreshold,
strokeWeight = strokeWeight,
flipY = invertImage,
flipY = NfInvertY in node.flags,
)

proc renderMtsdfImage(ctx: BackendContext, node: Fig) =
if node.mtsdfImage.id.int == 0:
return
let box = node.screenBox.scaled()
let size = vec2(box.w, box.h)
let invertImage = ctx.shouldInvertY(node)
let pxRange =
if node.mtsdfImage.pxRange > 0.0'f32: node.mtsdfImage.pxRange else: 4.0'f32
let sdThreshold =
Expand All @@ -860,7 +845,7 @@ proc renderMtsdfImage(ctx: BackendContext, node: Fig) =
pxRange = pxRange,
sdThreshold = sdThreshold,
strokeWeight = strokeWeight,
flipY = invertImage,
flipY = NfInvertY in node.flags
)

proc renderBackdropBlur(ctx: BackendContext, node: Fig) =
Expand Down
Loading