152 lines
4.0 KiB
Nim
152 lines
4.0 KiB
Nim
|
# SPDX-FileCopyrightText: ☭ 2021 Emery Hemingway
|
||
|
# SPDX-License-Identifier: Unlicense
|
||
|
|
||
|
import std/[asyncdispatch, hashes, os, strutils, tables, xmlparser, xmltree]
|
||
|
import preserves, preserves/parse
|
||
|
import syndicate,
|
||
|
syndicate/[actors, capabilities, dataspaces, patterns, relay],
|
||
|
syndicate/protocols/[simpleChatProtocol]
|
||
|
|
||
|
import nimsvg
|
||
|
import pixie, pixie/fileformats/svg
|
||
|
|
||
|
import math, sdl2, sdl2/gfx
|
||
|
|
||
|
import ./zua/protocol
|
||
|
|
||
|
const
|
||
|
rmask = uint32 0x000000ff
|
||
|
gmask = uint32 0x0000ff00
|
||
|
bmask = uint32 0x00ff0000
|
||
|
amask = uint32 0xff000000
|
||
|
|
||
|
type
|
||
|
Pane = ref object
|
||
|
svg: string
|
||
|
image: Image
|
||
|
|
||
|
type
|
||
|
App = ref object
|
||
|
screen: Image
|
||
|
# ctx: Context
|
||
|
window: WindowPtr
|
||
|
renderer: RendererPtr
|
||
|
surface: SurfacePtr
|
||
|
texture: TexturePtr
|
||
|
panes: Table[Hash, Pane]
|
||
|
|
||
|
proc newPane(svg: string): Pane =
|
||
|
Pane(svg: svg)
|
||
|
|
||
|
proc newApp(width, height: int): App =
|
||
|
new result
|
||
|
discard createWindowAndRenderer(
|
||
|
cint width, cint height,
|
||
|
SDL_WINDOW_RESIZABLE,
|
||
|
result.window, result.renderer)
|
||
|
|
||
|
proc equalDimensions(a, b: Image): bool =
|
||
|
a.width == b.width and a.height == b.height
|
||
|
|
||
|
proc update(app: App; pane: Pane) =
|
||
|
try:
|
||
|
assert(not app.screen.isNil)
|
||
|
pane.image = decodeSvg(pane.svg) # , app.screen.width, app.screen.height)
|
||
|
# TODO: determine the width and height from zoom level
|
||
|
draw(app.screen, pane.image)
|
||
|
except Exception as e:
|
||
|
stderr.writeLine "Failed to render SVG, ", e.msg
|
||
|
|
||
|
proc update(app: App) =
|
||
|
let (w, h) = app.window.getSize
|
||
|
if app.screen.isNil or app.screen.width != w or app.screen.height != h:
|
||
|
app.screen = newImage(w, h)
|
||
|
app.screen.fill(rgba(255, 255, 255, 255))
|
||
|
for pane in app.panes.values:
|
||
|
app.update(pane)
|
||
|
|
||
|
var dataPtr = app.screen.data[0].addr
|
||
|
var mainSurface = createRGBSurfaceFrom(
|
||
|
dataPtr, cint w, cint h, cint 32, cint 4*w,
|
||
|
rmask, gmask, bmask, amask)
|
||
|
var mainTexture = app.renderer.createTextureFromSurface(mainSurface)
|
||
|
destroy(mainSurface)
|
||
|
|
||
|
app.renderer.clear()
|
||
|
app.renderer.copy(mainTexture, nil, nil)
|
||
|
destroy(mainTexture)
|
||
|
|
||
|
app.renderer.present()
|
||
|
|
||
|
discard sdl2.init(INIT_TIMER or INIT_VIDEO or INIT_EVENTS)
|
||
|
|
||
|
const svgTextSimple = """
|
||
|
<?xml version="1.0" standalone="no"?>
|
||
|
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
|
||
|
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||
|
<svg width="10cm" height="3cm" viewBox="0 0 1000 300"
|
||
|
xmlns="http://www.w3.org/2000/svg" version="1.1">
|
||
|
<desc>Example text01 - 'Hello, out there' in blue</desc>
|
||
|
<text x="250" y="150"
|
||
|
font-family="Verdana" font-size="55" fill="blue" >
|
||
|
Hello, out there
|
||
|
</text>
|
||
|
<!-- Show outline of canvas using 'rect' element -->
|
||
|
<rect x="1" y="1" width="998" height="298"
|
||
|
fill="none" stroke="blue" stroke-width="2" />
|
||
|
</svg>
|
||
|
"""
|
||
|
|
||
|
proc main() =
|
||
|
let app = newApp(1024, 768)
|
||
|
app.update()
|
||
|
|
||
|
let cap = mint()
|
||
|
|
||
|
asyncCheck runActor("chat") do (turn: var Turn):
|
||
|
|
||
|
connectUnix(turn, "/run/syndicate/ds", cap) do (turn: var Turn; a: Assertion) -> TurnAction:
|
||
|
let ds = unembed a
|
||
|
|
||
|
onPublish(turn, ds, protocol.Pane ? {0: `?*`()}) do (svg: string):
|
||
|
echo "an SVG was published"
|
||
|
onRetract:
|
||
|
echo "an SVG was retracted"
|
||
|
app.panes.del(hash svg)
|
||
|
app.update()
|
||
|
# TODO: keep dead panes around until they are cleaned up.
|
||
|
# If something crashes then the last state should be visable.
|
||
|
var pane = app.panes.getOrDefault(hash svg)
|
||
|
if pane.isNil:
|
||
|
pane = newPane(svg)
|
||
|
app.panes[hash svg] = pane
|
||
|
else:
|
||
|
pane.svg = svg
|
||
|
app.update(pane)
|
||
|
app.update() # TODO: wait til end of turn
|
||
|
|
||
|
var
|
||
|
svgHandle: Handle
|
||
|
groups: Table[Hash, Nodes]
|
||
|
|
||
|
const
|
||
|
sdlTimeout = 500
|
||
|
asyncPollTimeout = 500
|
||
|
|
||
|
var evt = sdl2.defaultEvent
|
||
|
asyncdispatch.poll(0)
|
||
|
while true:
|
||
|
# TODO asyncdispatch.poll(0) or make an SDL event thread
|
||
|
if not waitEventTimeout(evt, sdlTimeout):
|
||
|
asyncdispatch.poll(0)
|
||
|
else:
|
||
|
case evt.kind
|
||
|
of QuitEvent:
|
||
|
quit(0)
|
||
|
of WindowEvent:
|
||
|
if evt.window.event == WindowEvent_Resized:
|
||
|
app.update()
|
||
|
else: discard
|
||
|
|
||
|
main()
|