From 6ec86cfa27a438d5ea095364d57f2336e952641a Mon Sep 17 00:00:00 2001 From: Emery Hemingway Date: Sun, 26 Dec 2021 21:54:32 +0100 Subject: [PATCH] test/client: publish SVG as preserves --- src/zua.nim | 147 ++++++++++++++++++++++++++++++++--------------- tests/client.nim | 9 +-- 2 files changed, 107 insertions(+), 49 deletions(-) diff --git a/src/zua.nim b/src/zua.nim index 966f5ea..d0399e5 100644 --- a/src/zua.nim +++ b/src/zua.nim @@ -1,8 +1,8 @@ # SPDX-FileCopyrightText: ☭ 2021 Emery Hemingway # SPDX-License-Identifier: Unlicense -import std/[asyncdispatch, hashes, os, tables] -import preserves +import std/[asyncdispatch, hashes, options, os, tables, xmltree] +import preserves, preserves/parse, preserves/xmlhooks import syndicate, syndicate/[actors, capabilities, dataspaces, patterns, relay], syndicate/protocols/[simpleChatProtocol] @@ -12,13 +12,15 @@ import bumpy, pixie, pixie/fileformats/svg import sdl2 -import svui +import svui, svui/render/xhtml type Svui = svui.Svui[Ref] SdlError = object of CatchableError Attrs = Table[string, Assertion] +func toVec2(p: Point): Vec2 = vec2(float p.x, float p.y) + template check(res: cint) = if res != 0: let msg = $sdl2.getError() @@ -36,10 +38,16 @@ const bmask = uint32 0x00ff0000 type + PaneKind = enum pkSvg, pkXhtml + Pane = ref object - svg: string texture: TexturePtr rect: bumpy.Rect + case kind: PaneKind + of pkSvg: + svg: string + of pkXhtml: + xhtml: Xhtml App = ref object screen: Image @@ -48,39 +56,56 @@ type panes: Table[Hash, Pane] viewPoint: Vec2 zoomFactor: float + typesetting: Typesetting proc newPane(app: App; svg: string): Pane = let (w, h) = app.window.getSize - result = Pane(svg: svg, rect: rect(0, 0, float w, float h)) - try: - var - image = decodeSvg(svg, w, h) - dataPtr = image.data[0].addr - surface = createRGBSurfaceFrom( - dataPtr, cint w, h, cint 32, cint 4*w, - rmask, gmask, bmask, amask) - result.texture = createTextureFromSurface(app.renderer, surface) - destroy surface - #[ - result.texture = createTexture( - app.renderer, - SDL_PIXELFORMAT_ARGB8888, - SDL_TEXTUREACCESS_STREAMING, - w div 2, h div 2) - updateTexture(result.texture, nil, image.data[0].addr, cint 32) - ]# - except Exception as e: - destroyTexture(result.texture) - stderr.writeLine "Failed to render SVG, ", e.msg + result = Pane(kind: pkSvg, svg: svg, rect: rect(0, 0, float w, float h)) + var + image = decodeSvg(svg, w, h) + dataPtr = image.data[0].addr + surface = createRGBSurfaceFrom( + dataPtr, cint w, h, cint 32, cint 4*w, + rmask, gmask, bmask, amask) + result.texture = createTextureFromSurface(app.renderer, surface) + destroy surface + #[ + result.texture = createTexture( + app.renderer, + SDL_PIXELFORMAT_ARGB8888, + SDL_TEXTUREACCESS_STREAMING, + w div 2, h div 2) + updateTexture(result.texture, nil, image.data[0].addr, cint 32) + ]# + +func rect(img: Image): bumpy.Rect = + result.w = float img.width + result.h = float img.height + +proc newPane(app: App; xhtml: Xhtml): Pane = + var + image = render(app.typesetting, xhtml) + dataPtr = image.data[0].addr + surface = createRGBSurfaceFrom( + dataPtr, + cint image.width, cint image.height, + cint 32, cint 4*image.width, + rmask, gmask, bmask, amask) + result = Pane( + kind: pkXhtml, + xhtml: xhtml, + rect: image.rect, + texture: createTextureFromSurface(app.renderer, surface)) + destroy surface + assert(result.rect.w != 0) + assert(result.rect.h != 0) proc newApp(length: cint): App = ## Create a new square plane of `length` pixels. - var wh = vec2(float length, float length) - result = App(zoomFactor: 1.0) + result = App(zoomFactor: 1.0, typesetting: initTypesetting()) discard createWindowAndRenderer( length, length, - SDL_WINDOW_SHOWN, - # SDL_WINDOW_RESIZABLE, + SDL_WINDOW_RESIZABLE, result.window, result.renderer) var info: RendererInfo check getRendererInfo(result.renderer, addr info) @@ -100,7 +125,7 @@ proc redraw(app: App) = (w, h) = app.window.getSize sdlViewPort = rect(-float(w shr 1), -float(h shr 1), float w, float h) viewPort = app.viewPort(sdlViewPort.wh) - app.renderer.setDrawColor(0xff, 0xff, 0xff) + app.renderer.setDrawColor(0x40, 0x40, 0x40) app.renderer.clear() for pane in app.panes.values: if overlaps(viewPort, pane.rect): @@ -108,7 +133,8 @@ proc redraw(app: App) = overlap = viewPort and pane.rect src = rect(overlap.xy - pane.rect.xy, overlap.wh) dst: bumpy.Rect - dst.xy = (overlap.xy - viewPort.xy) * (sdlViewPort.w / viewPort.w) + dst.x = (overlap.x - viewPort.x) * (sdlViewPort.w / viewPort.w) + dst.y = (overlap.y - viewPort.y) * (sdlViewPort.h / viewPort.h) dst.wh = if app.zoomFactor == 1.0: overlap.wh # correct @@ -120,6 +146,10 @@ proc redraw(app: App) = app.renderer.copy(pane.texture, addr sdlSrc, addr sdlDst) app.renderer.present() +proc resize(app: App) = + ## Resize to new dimensions of the SDL window. + redraw(app) + proc zoom(app: App; change: float) = app.zoomFactor = app.zoomFactor * (1.0 + ((1 / 8) * change)) app.redraw() @@ -145,19 +175,46 @@ proc main() = connectUnix(turn, "/run/syndicate/ds", cap) do (turn: var Turn; a: Assertion) -> TurnAction: let ds = unembed a - onPublish(turn, ds, Svui ? {0: drop(), 1: grab()}) do (svg: string): - onRetract: - app.panes.del(hash svg) - app.redraw() - # 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(app, svg) - app.panes[hash svg] = pane - else: - pane.svg = svg - app.redraw() # TODO: wait til end of turn + onPublish(turn, ds, Svui ? {0: drop(), 1: grab()}) do (content: Content): + case content.orKind + of ContentKind.Xhtml: + # content.xhtml + onRetract: + app.panes.del(hash content.xhtml) + app.redraw() + # 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 content.xhtml) + if pane.isNil: + #try: + block: + pane = newPane(app, content.xhtml) + app.panes[hash content.xhtml] = pane + #except: + # let msg = getCurrentExceptionMsg() + # stderr.writeLine "failed to render XHMTL: ", msg + else: + pane.xhtml = content.xhtml + app.redraw() # TODO: wait til end of turn + of ContentKind.Svg: + let xn = preserveTo(toPreserve(content.xhtml), xmltree.XmlNode) + let svg = $(get xn) + onRetract: + app.panes.del(hash svg) + app.redraw() + # 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: + try: + pane = newPane(app, svg) + app.panes[hash svg] = pane + except: + let msg = getCurrentExceptionMsg() + stderr.writeLine "failed to render SVG: ", msg + else: + pane.svg = svg + app.redraw() # TODO: wait til end of turn const sdlTimeout = 500 @@ -174,7 +231,7 @@ proc main() = app.zoom(evt.wheel.y.float) of WindowEvent: if evt.window.event == WindowEvent_Resized: - app.redraw() + app.resize() of MouseMotion: if mousePanning: var xy = vec2(evt.motion.xrel.float, evt.motion.yrel.float) diff --git a/tests/client.nim b/tests/client.nim index 5ff2868..beab1e3 100644 --- a/tests/client.nim +++ b/tests/client.nim @@ -2,7 +2,7 @@ # SPDX-License-Identifier: Unlicense import std/[asyncdispatch, os, parseopt, xmlparser, xmltree] -import preserves +import preserves, preserves/parse, preserves/xmlhooks import syndicate, syndicate/[actors, capabilities, relay] @@ -26,11 +26,12 @@ proc main() = if megs > 1: stderr.writeLine arg, " is ", megs, " MiB, not publishing" else: - let xml = loadXml(arg) + var xml = loadXml(arg) if xml.tag != "svg": stderr.writeLine arg, " not recognized as SVG" - else: - discard publish(turn, ds, Svui(svg: $xml)) + var pr = toPreserve(Svui(), Ref) + pr[1] = toPreserve(xml, Ref) + discard publish(turn, ds, pr) stderr.writeLine "done"