treeform / pixie

Full-featured 2d graphics library for Nim.
MIT License
732 stars 28 forks source link

Request: Text hAlign = JUSTIFY_ALIGN #521

Open IagoBeuller opened 1 year ago

IagoBeuller commented 1 year ago

Would be nice if add this alignment style.

I've made this proc for making this feature for me, it behaves like the Microsoft Word.

import
    pixie,
    unicode

const
    LF = Rune(10)
    NR = Rune(0)

proc justifyArrangement*(arrangement: Arrangement, maxWidth: float32) {.raises: [].} =
  proc right(rect: Rect): float32 = rect.x + rect.w

  let
    runes: ptr = arrangement.runes.addr
    positions: ptr = arrangement.positions.addr
    rects: ptr = arrangement.selectionRects.addr
    lastLineId: int = arrangement.lines.len-1

  var
    rune, lastRune: Rune
    lastWordRuneId: int
    spacesIdx: seq[int]
    incWidth, spaceWidth, lineWidth, xOffset: float32

  for lineId, (start, stop) in arrangement.lines:
    lastRune = runes[stop]

    # This line must not be justified, if it's the last or if the last rune is a breakline char.
    if lineId == lastLineId or lastRune == LF:
      continue

    echo runes[start..stop]
    # Get the spaces indexes of this line to increase their width, and get the line width.
    # Spaces in the end will be pushed away the maxWidth like the Microsoft Word.
    spacesIdx = @[]
    lastRune = NR
    for rId in start..stop:
      rune = runes[rId]
      if not rune.isWhiteSpace():
        if lastRune.isWhiteSpace():
          spacesIdx.add(rId-1)
        lastWordRuneId = rId
      lastRune = rune

    lineWidth = rects[lastWordRuneId].right

    echo "Line spaces: ", spacesIdx.len
    if spacesIdx.len > 0:
      # Get the amount of pixels/units to increase each space width in the middle of the line.
      incWidth = (maxWidth - lineWidth) / spacesIdx.len.float32

      if incWidth > 0:
        spaceWidth = rects[spacesIdx[0]].w + incWidth

        # Adjust the runes X position
        xOffset = 0
        for rId in spacesIdx[0]..stop:
          positions[rId].x += xOffset
          rects[rId].x += xOffset

          if rId in spacesIdx:
            rects[rId].w = spaceWidth
            xOffset += incWidth