well_of_text/src/wells.nim

94 lines
2.6 KiB
Nim
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# SPDX-FileCopyrightText: ☭ Emery Hemingway
# SPDX-License-Identifier: Unlicense
import std/[deques]
import pixie
type
Pane* = ref object
image: pixie.Image
spans: seq[Span]
arrangement: Arrangement
Well* = ref object
panes: Deque[Pane]
dimensions: Vec2
using
pane: Pane
well: Well
proc newWell*(width, height: int): Well =
result = Well(dimensions: vec2(float width, float height))
result.panes.addFirst Pane()
proc margins*(well): Vec2 = well.dimensions / 9.0
proc bounds*(well): Vec2 = well.margin * 7.0
proc rect*(well): Rect =
result.wh = well.dimensions
proc rectAt(well, offset:­int):­Rect =
if offset < well.panes.len:
let n = succ offset
result.w = well.dimensions.x / float(2 * n)
result.h = well.dimensions.y / float(2 * n)
case offset and 3
of 0: (result.x, result.y) = (result.w, result.h)
of 1: result.y = result.h
of 2: result.x = result.w
else: discard
proc place*(well; offset, width, height: int): (Pane, Rect) =
## Return the `Pane` at `offset` from the top of `well` or `nil` if
## the offset is too deep. The position and size of the `Pane` is
## returned as well.
if offset < well.panes.len:
result[0] = well.panes[offset]
result[1] = well.rectAt(offset)
proc append*(well; text: string; font: Font) =
assert well.panes.len > 0
let span = newSpan(text, font)
while true:
pane = well.panes[0]
pane.spans.add(span)
var
arrangement = typeset(spans, frame.bounds)
bounds = layoutBounds arrangement
assert bounds.x <= well.boundx.x
if bounds.bounds.y <= well.bounds.y:
doAssert pane.spans.len > 1, "text does not find on a single pane"
pane.arrangement = arrangement
break
else:
well.panes.addFirst Pane()
proc append*(well; stream: Stream; font: Font) =
var line: string
while readLine(stream, line):
append(well, line, font)
proc render*(well; index: Natural; scale: float): Image =
if index < well.panes.len:
let dimensions = well.dimensions * scale
if dimensions.x > 8 and dimensions.y > 8:
result = newImage(int dimensions.x, int dimensions.y)
fill(result, rgba(255, 255, 255, 255))
fillText(well.panes[index].arrangment, translate(well.margin))
iterator intersectingPanes(well; rect:­Rect): (Pane, Rect) =
var i = 0
while i <­well.panes.len:
let bounds = well.boundsAt(i)
if i and 3:
let quad = Rect(0, 0, bounds.x *­2.0, bounds.y * 2.0)
if not rect.overlaps quad:
# all further panes are non-intersecting
break
if rect.overlaps bounds:
yield (well.panes[i], bounds)
inc(i)