94 lines
2.6 KiB
Nim
94 lines
2.6 KiB
Nim
|
# 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)
|