fixes for builder get() procs and cairo

This commit is contained in:
Stefan Salewski 2019-04-27 09:02:37 +02:00
commit 4c93a26d04
7 changed files with 3212 additions and 267 deletions

View file

@ -843,7 +843,10 @@ main()
The following code is a plain Nim version of a drawing demo which I wrote some years ago in Ruby (http://ssalewski.de/PetEd-Demo.html.en). The following code is a plain Nim version of a drawing demo which I wrote some years ago in Ruby (http://ssalewski.de/PetEd-Demo.html.en).
With the latest fix to Nim GTK3 bindings it seems to work fine, but some rewriting for optimized performance With the latest fix to Nim GTK3 bindings it seems to work fine, but some rewriting for optimized performance
may be needed, I have to investigate that. Cairo surface is currently manually freed, because GC may have a too large delay. may be needed, I have to investigate that. Cairo surface is currently manually freed, because GC may have a too large delay.
Later we may use Destructors for that.
You can resize the window and zoom in with the mouse wheel. When zoomed in scroll bars appear. You
can hold the middle mouse button pressed while moving the mouse for panning, and you can press left mouse button
and move the mouse to first draw a selection rectangle and zoom into it when releasing the mouse button.
[[drawingarea.nim]] [[drawingarea.nim]]
[source,nim] [source,nim]
@ -851,46 +854,26 @@ Later we may use Destructors for that.
---- ----
# Plain demo for zooming, panning, scrolling with GTK DrawingArea # Plain demo for zooming, panning, scrolling with GTK DrawingArea
# (c) S. Salewski, 21-DEC-2010 (initial Ruby version) # (c) S. Salewski, 21-DEC-2010 (initial Ruby version)
# Nim version April 2019 -- well first draft :-) # Nim version April 2019
# License MIT # License MIT
# This version of the demo program uses a separate proc paint()
# which allocates a custom surface for buffered drawing.
# That may be not really necessary, for simple drawings doing all
# the drawing in the "draw" call back is easier and faster. But for
# more complicated drawing operations, for example when using a
# background grid, which is a bit larger than the window size and
# is reused when scrolling, a custom surface may be useful.
# And finally that custom surface and custom cairo context is an
# important test for the language bindings.
import gintro/[gtk, gdk, glib, gobject, gio, cairo] import gintro/[gtk, gdk, glib, gobject, gio, cairo]
const const
DataX = 150.0 ZoomFactorMouseWheel = 1.1
DataY = 250.0 ZoomFactorSelectMax = 10 # ignore zooming in tiny selection
DataWidth = 200.0 ZoomNearMousepointer = true # mouse wheel zooming -- to mouse-pointer or center
DataHeight = 120.0 SelectRectCol = [0.0, 0, 1, 0.5] # blue with transparency
# The following two functions are intended to be user defined -- we have still
# to investigate how to do that best.
# bounding box of user data -- x, y, w, h -- top left corner, width, height
proc getWorldExtends(): (float, float, float, float) =
(DataX, DataY, DataWidth, DataHeight) # current extents of our user world
# draw to cairo context
proc drawWorld(cr: cairo.Context) =
cr.setSource(1, 1, 1)
cr.paint
cr.setSource(0, 0, 0)
cr.setLineWidth(2)
cr.rectangle(DataX, DataY, DataWidth, DataHeight)
var i = 10.0
while true:
if min(DataWidth - 2.0 * i, DataHeight - 2.0 * i) <= 0:
break
cr.rectangle(DataX + i, DataY + i, DataWidth - 2.0 * i,
DataHeight - 2.0 * i)
i += 10.0
cr.stroke
const
ZOOM_FACTOR_MOUSE_WHEEL = 1.1
ZOOM_FACTOR_SELECT_MAX = 10 # ignore zooming in tiny selection
ZOOM_NEAR_MOUSEPOINTER = true # mouse wheel zooming -- to mousepointer or center
SELECT_RECT_COL = [0.0, 0, 1, 0.5] # blue with transparency
discard """ discard """
Zooming, scrolling, panning... Zooming, scrolling, panning...
@ -931,6 +914,12 @@ type
proc newPosAdj: PosAdj = proc newPosAdj: PosAdj =
initAdjustment(result, 0, 0, 1, 1, 10, 1) initAdjustment(result, 0, 0, 1, 1, 10, 1)
type
PDA_Data* = object
draw*: proc (cr: Context)
extents*: proc (): tuple[x, y, w, h: float]
windowSize*: tuple[w, h: int]
type type
PDA = ref object of Grid PDA = ref object of Grid
zoomNearMousepointer: bool zoomNearMousepointer: bool
@ -953,6 +942,8 @@ type
lastMousePosY: float lastMousePosY: float
zoomRectX1: float zoomRectX1: float
zoomRectY1: float zoomRectY1: float
drawWorld: proc (cr: Context)
extents: proc (): tuple[x, y, w, h: float]
proc drawingAreaDrawCb(darea: DrawingArea; cr: Context; this: PDA): bool = proc drawingAreaDrawCb(darea: DrawingArea; cr: Context; this: PDA): bool =
if this.surf.isNil: return if this.surf.isNil: return
@ -967,7 +958,8 @@ proc drawingAreaDrawCb(darea: DrawingArea; cr: Context; this: PDA): bool =
cr.setSource(0, 0, 0) cr.setSource(0, 0, 0)
cr.setLineWidth(2) cr.setLineWidth(2)
cr.stroke cr.stroke
return true # TRUE to stop other handlers from being invoked for the event. FALSE to propagate the event further. return SignalEventStopPropagation
#return true # TRUE to stop other handlers from being invoked for the event. FALSE to propagate the event further.
# clamp to correct values, 0 <= value <= (adj.upper - adj.pageSize), block calling onAdjustmentEvent() # clamp to correct values, 0 <= value <= (adj.upper - adj.pageSize), block calling onAdjustmentEvent()
proc updateVal(adj: PosAdj; d: float) = proc updateVal(adj: PosAdj; d: float) =
@ -977,35 +969,30 @@ proc updateVal(adj: PosAdj; d: float) =
proc updateAdjustments(this: PDA; dx, dy: float) = proc updateAdjustments(this: PDA; dx, dy: float) =
this.hadjustment.setUpper(this.darea.allocatedWidth.float * this.userZoom) this.hadjustment.setUpper(this.darea.allocatedWidth.float * this.userZoom)
this.vadjustment.setUpper(this.darea.allocatedHeight.float * this.vadjustment.setUpper(this.darea.allocatedHeight.float * this.userZoom)
this.userZoom)
this.hadjustment.setPageSize(this.darea.allocatedWidth.float) this.hadjustment.setPageSize(this.darea.allocatedWidth.float)
this.vadjustment.setPageSize(this.darea.allocatedHeight.float) this.vadjustment.setPageSize(this.darea.allocatedHeight.float)
updateVal(this.hadjustment, dx) updateVal(this.hadjustment, dx)
updateVal(this.vadjustment, dy) updateVal(this.vadjustment, dy)
# Maybe we should fix this for latest GTK3, see # maybe for optimization we should only allocate a new surface when its size has changed.
# https://developer.gnome.org/gdk3/stable/gdk3-Cairo-Interaction.html
# so use gdk_drawing_context_get_cairo_context ()
# or maybe even better do all drwing from within "draw" callback?
proc paint(this: PDA) = proc paint(this: PDA) =
if this.surf != nil: if this.surf != nil:
cairosurfaceDestroy(this.surf.impl) # we may have to fix that later for automatically destroy destroy(this.surf) # manually destroy surface -- GC would do it for us, but GC is slow...
this.surf = this.darea.window.createSimilarSurface(Content.color, this.surf = this.darea.window.createSimilarSurface(Content.color,
this.darea.allocatedWidth, this.darea.allocatedHeight) this.darea.allocatedWidth, this.darea.allocatedHeight)
let cr = newContext(this.surf) let cr = newContext(this.surf)
cr.translate(this.hadjustment.upper * 0.5 - this.hadjustment.value, # our origin is the center cr.translate(this.hadjustment.upper * 0.5 - this.hadjustment.value, # our origin is the center
this.vadjustment.upper * 0.5 - this.vadjustment.value) this.vadjustment.upper * 0.5 - this.vadjustment.value)
cr.scale(this.fullScale * this.userZoom, this.fullScale * this.userZoom) cr.scale(this.fullScale * this.userZoom, this.fullScale * this.userZoom)
cr.translate(-this.dataX - this.dataWidth * 0.5, cr.translate(-this.dataX - this.dataWidth * 0.5, -this.dataY - this.dataHeight * 0.5)
-this.dataY - this.dataHeight * 0.5) this.drawWorld(cr) # call the user provided drawing function
drawWorld(cr) # call the user provided drawing fonction destroy(cr) # we can also manually destroy the context here, but GC would do it for us
proc dareaConfigureCallback(darea: DrawingArea; event: EventConfigure; proc dareaConfigureCallback(darea: DrawingArea; event: EventConfigure; this: PDA): bool =
this: PDA): bool =
this.updateAdjustments(0, 0) this.updateAdjustments(0, 0)
(this.dataX, this.dataY, this.dataWidth, (this.dataX, this.dataY, this.dataWidth,
this.dataHeight) = getWorldExtends() # query user defined size this.dataHeight) = this.extents() # query user defined size
this.fullScale = min(this.darea.allocatedWidth.float / this.dataWidth, this.fullScale = min(this.darea.allocatedWidth.float / this.dataWidth,
this.darea.allocatedHeight.float / this.dataHeight) this.darea.allocatedHeight.float / this.dataHeight)
this.paint this.paint
@ -1013,8 +1000,7 @@ proc dareaConfigureCallback(darea: DrawingArea; event: EventConfigure;
proc updateAdjustmentsAndPaint(this: PDA; dx, dy: float) = proc updateAdjustmentsAndPaint(this: PDA; dx, dy: float) =
this.updateAdjustments(dx, dy) this.updateAdjustments(dx, dy)
this.paint this.paint
this.darea.queueDrawArea(0, 0, this.darea.allocatedWidth, this.darea.queueDrawArea(0, 0, this.darea.allocatedWidth, this.darea.allocatedHeight)
this.darea.allocatedHeight)
# event coordinates to user space # event coordinates to user space
proc getUserCoordinates(this: PDA; eventX, eventY: float): (float, float) = proc getUserCoordinates(this: PDA; eventX, eventY: float): (float, float) =
@ -1026,16 +1012,13 @@ proc getUserCoordinates(this: PDA; eventX, eventY: float): (float, float) =
proc onMotion(darea: DrawingArea; event: EventMotion; this: PDA): bool = proc onMotion(darea: DrawingArea; event: EventMotion; this: PDA): bool =
let state = getState(event) let state = getState(event)
let (x, y) = event.getCoords let (x, y) = event.getCoords
#(x, y) = this.getUserCoordinates(x, y)
if (state.contains(button1)): # selecting if (state.contains(button1)): # selecting
this.selecting = true this.selecting = true
this.zoomRectX1 = x this.zoomRectX1 = x
this.zoomRectY1 = y this.zoomRectY1 = y
this.darea.queueDrawArea(0, 0, this.darea.allocatedWidth, this.darea.queueDrawArea(0, 0, this.darea.allocatedWidth, this.darea.allocatedHeight)
this.darea.allocatedHeight)
elif button2 in state: # panning elif button2 in state: # panning
this.updateAdjustmentsAndPaint(this.lastMousePosX - x, this.updateAdjustmentsAndPaint(this.lastMousePosX - x, this.lastMousePosY - y)
this.lastMousePosY - y)
this.lastMousePosX = x this.lastMousePosX = x
this.lastMousePosY = y this.lastMousePosY = y
#event.request # request more motion events ? #event.request # request more motion events ?
@ -1048,25 +1031,20 @@ proc scrollEvent(darea: DrawingArea; event: EventScroll; this: PDA): bool =
var d = getScrollDirection(event) var d = getScrollDirection(event)
var (x, y) = event.getCoords var (x, y) = event.getCoords
if d == ScrollDirection.up: if d == ScrollDirection.up:
this.userZoom *= ZOOM_FACTOR_MOUSE_WHEEL this.userZoom *= ZoomFactorMouseWheel
elif d == ScrollDirection.down: elif d == ScrollDirection.down:
this.userZoom /= ZOOM_FACTOR_MOUSE_WHEEL this.userZoom /= ZoomFactorMouseWheel
if (this.userZoom < 1): if (this.userZoom < 1):
this.userZoom = 1 this.userZoom = 1
if this.zoomNearMousepointer: if this.zoomNearMousepointer:
this.updateAdjustmentsAndPaint((this.hadjustment.value + x) * ( this.updateAdjustmentsAndPaint((this.hadjustment.value + x) * (this.userZoom / z0 - 1),
this.userZoom / z0 - 1), (this.vadjustment.value + y) * (this.userZoom / z0 - 1))
(this.vadjustment.value + y) * (
this.userZoom / z0 - 1))
else: # zoom to center else: # zoom to center
this.updateAdjustmentsAndPaint((this.hadjustment.value + this.updateAdjustmentsAndPaint((this.hadjustment.value +
this.darea.allocatedWidth.float * 0.5) * (this.userZoom / z0 - 1), this.darea.allocatedWidth.float * 0.5) * (this.userZoom / z0 - 1),
(this.vadjustment.value + (this.vadjustment.value + this.darea.allocatedHeight.float * 0.5) * (this.userZoom / z0 - 1))
this.darea.allocatedHeight.float * 0.5) * (
this.userZoom / z0 - 1))
proc buttonPressEvent(darea: DrawingArea; event: EventButton; proc buttonPressEvent(darea: DrawingArea; event: EventButton; this: PDA): bool =
this: PDA): bool =
var (x, y) = event.getCoords var (x, y) = event.getCoords
this.lastMousePosX = x this.lastMousePosX = x
this.lastMousePosY = y this.lastMousePosY = y
@ -1077,8 +1055,7 @@ proc buttonPressEvent(darea: DrawingArea; event: EventButton;
echo "User coordinates: ", x, ' ', y, "\n" # to verify getUserCoordinates() echo "User coordinates: ", x, ' ', y, "\n" # to verify getUserCoordinates()
# zoom into selected rectangle and center it # zoom into selected rectangle and center it
proc buttonReleaseEvent(darea: DrawingArea; event: EventButton; proc buttonReleaseEvent(darea: DrawingArea; event: EventButton; this: PDA): bool =
this: PDA): bool =
var (x, y) = event.getCoords var (x, y) = event.getCoords
var b = getButton(event) var b = getButton(event)
if b == 1: if b == 1:
@ -1086,7 +1063,7 @@ proc buttonReleaseEvent(darea: DrawingArea; event: EventButton;
let z1 = min(this.darea.allocatedWidth.float / ( let z1 = min(this.darea.allocatedWidth.float / (
this.lastButtonDownPosX - x).abs, this.darea.allocatedHeight.float / ( this.lastButtonDownPosX - x).abs, this.darea.allocatedHeight.float / (
this.lastButtonDownPosY - y).abs) this.lastButtonDownPosY - y).abs)
if z1 < ZOOM_FACTOR_SELECT_MAX: # else selection rectangle will persist, we may output a message... if z1 < ZoomFactorSelectMax: # else selection rectangle will persist, we may output a message...
this.userZoom *= z1 this.userZoom *= z1
this.updateAdjustmentsAndPaint( this.updateAdjustmentsAndPaint(
((2 * this.hadjustment.value + x + this.lastButtonDownPosX) * z1 - ((2 * this.hadjustment.value + x + this.lastButtonDownPosX) * z1 -
@ -1096,24 +1073,19 @@ proc buttonReleaseEvent(darea: DrawingArea; event: EventButton;
proc onAdjustmentEvent(this: PosAdj; pda: PDA) = proc onAdjustmentEvent(this: PosAdj; pda: PDA) =
pda.paint pda.paint
pda.darea.queueDrawArea(0, 0, pda.darea.allocatedWidth, pda.darea.queueDrawArea(0, 0, pda.darea.allocatedWidth, pda.darea.allocatedHeight)
pda.darea.allocatedHeight)
proc newPDA: PDA = proc newPDA: PDA =
initGrid(result) initGrid(result)
result.zoomNearMousepointer = ZOOM_NEAR_MOUSEPOINTER # mouse wheel zooming result.zoomNearMousepointer = ZoomNearMousepointer # mouse wheel zooming
result.selecting = false
result.userZoom = 1.0 result.userZoom = 1.0
result.surf = nil
result.darea = newDrawingArea() result.darea = newDrawingArea()
result.darea.setHExpand#(true) result.darea.setHExpand
result.darea.setVExpand#(true) result.darea.setVExpand
result.darea.connect("draw", drawingAreaDrawCb, result) result.darea.connect("draw", drawingAreaDrawCb, result)
result.darea.connect("configure-event", dareaConfigureCallback, result) result.darea.connect("configure-event", dareaConfigureCallback, result)
result.darea.addEvents({EventFlag.buttonPress, EventFlag.buttonRelease, result.darea.addEvents({EventFlag.buttonPress, EventFlag.buttonRelease,
EventFlag.scroll, EventFlag.scroll, button1Motion, button2Motion, pointerMotionHint})
EventFlag.button1Motion, EventFlag.button2Motion,
EventFlag.pointerMotionHint})
result.darea.connect("motion-notify-event", onMotion, result) result.darea.connect("motion-notify-event", onMotion, result)
result.darea.connect("scroll_event", scrollEvent, result) result.darea.connect("scroll_event", scrollEvent, result)
result.darea.connect("button_press_event", buttonPressEvent, result) result.darea.connect("button_press_event", buttonPressEvent, result)
@ -1126,25 +1098,98 @@ proc newPDA: PDA =
onAdjustmentEvent, result) onAdjustmentEvent, result)
result.hscrollbar = newScrollbar(Orientation.horizontal, result.hadjustment) result.hscrollbar = newScrollbar(Orientation.horizontal, result.hadjustment)
result.vscrollbar = newScrollbar(Orientation.vertical, result.vadjustment) result.vscrollbar = newScrollbar(Orientation.vertical, result.vadjustment)
result.hscrollbar.setHExpand#(true) result.hscrollbar.setHExpand
result.vscrollbar.setVExpand#(true) result.vscrollbar.setVExpand
result.attach(result.darea, 0, 0, 1, 1) result.attach(result.darea, 0, 0, 1, 1)
result.attach(result.vscrollbar, 1, 0, 1, 1) result.attach(result.vscrollbar, 1, 0, 1, 1)
result.attach(result.hscrollbar, 0, 1, 1, 1) result.attach(result.hscrollbar, 0, 1, 1, 1)
proc appActivate(app: Application) = proc appActivate(app: Application; initData: ref PDA_Data) =
let window = newApplicationWindow(app) let window = newApplicationWindow(app)
window.title = "Drawing example" window.title = "Drawing example"
window.defaultSize = (400, 400) window.defaultSize = (initData.windowSize[0], initData.windowSize[1])
let pda = newPDA() let pda = newPDA()
pda.drawWorld = initData.draw
pda.extents = initData.extents
window.add(pda) window.add(pda)
showAll(window) showAll(window)
proc main = proc newDisplay*(initData: PDA_Data) =
let app = newApplication("org.gtk.example") let app = newApplication("org.gtk.example")
connect(app, "activate", appActivate) var d = new (ref PDA_Data)
d[] = initData
connect(app, "activate", appActivate, d)
discard run(app) discard run(app)
when isMainModule:
const # arbitrary locations for our data
DataX = 150.0
DataY = 250.0
DataWidth = 200.0
DataHeight = 120.0
# we need two user defined functions -- one gives the extent of the graphics,
# and the other does the cairo drawing using a cairo context.
# bounding box of user data -- x, y, w, h -- top left corner, width, height
proc worldExtents(): (float, float, float, float) =
(DataX, DataY, DataWidth, DataHeight) # current extents of our user world
# draw to cairo context
proc drawWorld(cr: cairo.Context) =
cr.setSource(1, 1, 1)
cr.paint
cr.setSource(0, 0, 0)
cr.setLineWidth(2)
var i = 0.0
while true:
if min(DataWidth - 2.0 * i, DataHeight - 2.0 * i) <= 0:
break
cr.rectangle(DataX + i, DataY + i, DataWidth - 2 * i, DataHeight - 2 * i)
i += 10.0
cr.stroke
proc test =
var data: PDA_Data
data.draw = drawWorld
data.extents = worldExtents
data.windowSize = (800, 600)
newDisplay(data)
test()
----
We can use this module as a library easily and get this simple drawing tool with full zoom and scroll support:
[[darea_test.nim]]
[source,nim]
.darea_test.nim
----
import gintro/cairo
import drawingarea
from math import PI
proc extents(): (float, float, float, float) =
(0.0, 0.0, 100.0, 100.0) # ugly float literals
# draw to cairo context
proc draw(cr: cairo.Context) =
cr.setSource(1, 1, 1) # set background color and paint
cr.paint
cr.setSource(0, 0, 0) # forground color
cr.arc(20, 30, 10, 0, 5) # nearly a circle
cr.newSubPath # do not join the two arcs
cr.arc(70, 60, 20, 0, math.PI)
cr.stroke # finally do it
proc main =
var data: PDA_Data
data.draw = draw
data.extents = extents
data.windowSize = (800, 600)
newDisplay(data)
main() main()
---- ----

25
examples/darea_test.nim Normal file
View file

@ -0,0 +1,25 @@
import gintro/cairo
import drawingarea
from math import PI
proc extents(): (float, float, float, float) =
(0.0, 0.0, 100.0, 100.0) # ugly float literals
# draw to cairo context
proc draw(cr: cairo.Context) =
cr.setSource(1, 1, 1) # set background color and paint
cr.paint
cr.setSource(0, 0, 0) # forground color
cr.arc(20, 30, 10, 0, 5) # nearly a circle
cr.newSubPath # do not join the two arcs
cr.arc(70, 60, 20, 0, math.PI)
cr.stroke # finally do it
proc main =
var data: PDA_Data
data.draw = draw
data.extents = extents
data.windowSize = (800, 600)
newDisplay(data)
main()

View file

@ -1,45 +1,25 @@
# Plain demo for zooming, panning, scrolling with GTK DrawingArea # Plain demo for zooming, panning, scrolling with GTK DrawingArea
# (c) S. Salewski, 21-DEC-2010 (initial Ruby version) # (c) S. Salewski, 21-DEC-2010 (initial Ruby version)
# Nim version April 2019 -- well first draft :-) # Nim version April 2019
# License MIT # License MIT
# This version of the demo program uses a separate proc paint()
# which allocates a custom surface for buffered drawing.
# That may be not really necessary, for simple drawings doing all
# the drawing in the "draw" call back is easier and faster. But for
# more complicated drawing operations, for example when using a
# background grid, which is a bit larger than the window size and
# is reused when scrolling, a custom surface may be useful.
# And finally that custom surface and custom cairo context is an
# important test for the language bindings.
import gintro/[gtk, gdk, glib, gobject, gio, cairo] import gintro/[gtk, gdk, glib, gobject, gio, cairo]
const const
DataX = 150.0 ZoomFactorMouseWheel = 1.1
DataY = 250.0 ZoomFactorSelectMax = 10 # ignore zooming in tiny selection
DataWidth = 200.0 ZoomNearMousepointer = true # mouse wheel zooming -- to mouse-pointer or center
DataHeight = 120.0 SelectRectCol = [0.0, 0, 1, 0.5] # blue with transparency
# The following two functions are intended to be user defined -- we have still
# to investigate how to do that best.
# bounding box of user data -- x, y, w, h -- top left corner, width, height
proc getWorldExtends(): (float, float, float, float) =
(DataX, DataY, DataWidth, DataHeight) # current extents of our user world
# draw to cairo context
proc drawWorld(cr: cairo.Context) =
cr.setSource(1, 1, 1)
cr.paint
cr.setSource(0, 0, 0)
cr.setLineWidth(2)
cr.rectangle(DataX, DataY, DataWidth, DataHeight)
var i = 10.0
while true:
if min(DataWidth - 2.0 * i, DataHeight - 2.0 * i) <= 0:
break
cr.rectangle(DataX + i, DataY + i, DataWidth - 2.0 * i,
DataHeight - 2.0 * i)
i += 10.0
cr.stroke
const
ZOOM_FACTOR_MOUSE_WHEEL = 1.1
ZOOM_FACTOR_SELECT_MAX = 10 # ignore zooming in tiny selection
ZOOM_NEAR_MOUSEPOINTER = true # mouse wheel zooming -- to mousepointer or center
SELECT_RECT_COL = [0.0, 0, 1, 0.5] # blue with transparency
discard """ discard """
Zooming, scrolling, panning... Zooming, scrolling, panning...
@ -80,6 +60,12 @@ type
proc newPosAdj: PosAdj = proc newPosAdj: PosAdj =
initAdjustment(result, 0, 0, 1, 1, 10, 1) initAdjustment(result, 0, 0, 1, 1, 10, 1)
type
PDA_Data* = object
draw*: proc (cr: Context)
extents*: proc (): tuple[x, y, w, h: float]
windowSize*: tuple[w, h: int]
type type
PDA = ref object of Grid PDA = ref object of Grid
zoomNearMousepointer: bool zoomNearMousepointer: bool
@ -102,6 +88,8 @@ type
lastMousePosY: float lastMousePosY: float
zoomRectX1: float zoomRectX1: float
zoomRectY1: float zoomRectY1: float
drawWorld: proc (cr: Context)
extents: proc (): tuple[x, y, w, h: float]
proc drawingAreaDrawCb(darea: DrawingArea; cr: Context; this: PDA): bool = proc drawingAreaDrawCb(darea: DrawingArea; cr: Context; this: PDA): bool =
if this.surf.isNil: return if this.surf.isNil: return
@ -116,7 +104,8 @@ proc drawingAreaDrawCb(darea: DrawingArea; cr: Context; this: PDA): bool =
cr.setSource(0, 0, 0) cr.setSource(0, 0, 0)
cr.setLineWidth(2) cr.setLineWidth(2)
cr.stroke cr.stroke
return true # TRUE to stop other handlers from being invoked for the event. FALSE to propagate the event further. return SignalEventStopPropagation
#return true # TRUE to stop other handlers from being invoked for the event. FALSE to propagate the event further.
# clamp to correct values, 0 <= value <= (adj.upper - adj.pageSize), block calling onAdjustmentEvent() # clamp to correct values, 0 <= value <= (adj.upper - adj.pageSize), block calling onAdjustmentEvent()
proc updateVal(adj: PosAdj; d: float) = proc updateVal(adj: PosAdj; d: float) =
@ -126,35 +115,30 @@ proc updateVal(adj: PosAdj; d: float) =
proc updateAdjustments(this: PDA; dx, dy: float) = proc updateAdjustments(this: PDA; dx, dy: float) =
this.hadjustment.setUpper(this.darea.allocatedWidth.float * this.userZoom) this.hadjustment.setUpper(this.darea.allocatedWidth.float * this.userZoom)
this.vadjustment.setUpper(this.darea.allocatedHeight.float * this.vadjustment.setUpper(this.darea.allocatedHeight.float * this.userZoom)
this.userZoom)
this.hadjustment.setPageSize(this.darea.allocatedWidth.float) this.hadjustment.setPageSize(this.darea.allocatedWidth.float)
this.vadjustment.setPageSize(this.darea.allocatedHeight.float) this.vadjustment.setPageSize(this.darea.allocatedHeight.float)
updateVal(this.hadjustment, dx) updateVal(this.hadjustment, dx)
updateVal(this.vadjustment, dy) updateVal(this.vadjustment, dy)
# Maybe we should fix this for latest GTK3, see # maybe for optimization we should only allocate a new surface when its size has changed.
# https://developer.gnome.org/gdk3/stable/gdk3-Cairo-Interaction.html
# so use gdk_drawing_context_get_cairo_context ()
# or maybe even better do all drwing from within "draw" callback?
proc paint(this: PDA) = proc paint(this: PDA) =
if this.surf != nil: if this.surf != nil:
cairosurfaceDestroy(this.surf.impl) # we may have to fix that later for automatically destroy destroy(this.surf) # manually destroy surface -- GC would do it for us, but GC is slow...
this.surf = this.darea.window.createSimilarSurface(Content.color, this.surf = this.darea.window.createSimilarSurface(Content.color,
this.darea.allocatedWidth, this.darea.allocatedHeight) this.darea.allocatedWidth, this.darea.allocatedHeight)
let cr = newContext(this.surf) let cr = newContext(this.surf)
cr.translate(this.hadjustment.upper * 0.5 - this.hadjustment.value, # our origin is the center cr.translate(this.hadjustment.upper * 0.5 - this.hadjustment.value, # our origin is the center
this.vadjustment.upper * 0.5 - this.vadjustment.value) this.vadjustment.upper * 0.5 - this.vadjustment.value)
cr.scale(this.fullScale * this.userZoom, this.fullScale * this.userZoom) cr.scale(this.fullScale * this.userZoom, this.fullScale * this.userZoom)
cr.translate(-this.dataX - this.dataWidth * 0.5, cr.translate(-this.dataX - this.dataWidth * 0.5, -this.dataY - this.dataHeight * 0.5)
-this.dataY - this.dataHeight * 0.5) this.drawWorld(cr) # call the user provided drawing function
drawWorld(cr) # call the user provided drawing fonction destroy(cr) # we can also manually destroy the context here, but GC would do it for us
proc dareaConfigureCallback(darea: DrawingArea; event: EventConfigure; proc dareaConfigureCallback(darea: DrawingArea; event: EventConfigure; this: PDA): bool =
this: PDA): bool =
this.updateAdjustments(0, 0) this.updateAdjustments(0, 0)
(this.dataX, this.dataY, this.dataWidth, (this.dataX, this.dataY, this.dataWidth,
this.dataHeight) = getWorldExtends() # query user defined size this.dataHeight) = this.extents() # query user defined size
this.fullScale = min(this.darea.allocatedWidth.float / this.dataWidth, this.fullScale = min(this.darea.allocatedWidth.float / this.dataWidth,
this.darea.allocatedHeight.float / this.dataHeight) this.darea.allocatedHeight.float / this.dataHeight)
this.paint this.paint
@ -162,8 +146,7 @@ proc dareaConfigureCallback(darea: DrawingArea; event: EventConfigure;
proc updateAdjustmentsAndPaint(this: PDA; dx, dy: float) = proc updateAdjustmentsAndPaint(this: PDA; dx, dy: float) =
this.updateAdjustments(dx, dy) this.updateAdjustments(dx, dy)
this.paint this.paint
this.darea.queueDrawArea(0, 0, this.darea.allocatedWidth, this.darea.queueDrawArea(0, 0, this.darea.allocatedWidth, this.darea.allocatedHeight)
this.darea.allocatedHeight)
# event coordinates to user space # event coordinates to user space
proc getUserCoordinates(this: PDA; eventX, eventY: float): (float, float) = proc getUserCoordinates(this: PDA; eventX, eventY: float): (float, float) =
@ -175,16 +158,13 @@ proc getUserCoordinates(this: PDA; eventX, eventY: float): (float, float) =
proc onMotion(darea: DrawingArea; event: EventMotion; this: PDA): bool = proc onMotion(darea: DrawingArea; event: EventMotion; this: PDA): bool =
let state = getState(event) let state = getState(event)
let (x, y) = event.getCoords let (x, y) = event.getCoords
#(x, y) = this.getUserCoordinates(x, y)
if (state.contains(button1)): # selecting if (state.contains(button1)): # selecting
this.selecting = true this.selecting = true
this.zoomRectX1 = x this.zoomRectX1 = x
this.zoomRectY1 = y this.zoomRectY1 = y
this.darea.queueDrawArea(0, 0, this.darea.allocatedWidth, this.darea.queueDrawArea(0, 0, this.darea.allocatedWidth, this.darea.allocatedHeight)
this.darea.allocatedHeight)
elif button2 in state: # panning elif button2 in state: # panning
this.updateAdjustmentsAndPaint(this.lastMousePosX - x, this.updateAdjustmentsAndPaint(this.lastMousePosX - x, this.lastMousePosY - y)
this.lastMousePosY - y)
this.lastMousePosX = x this.lastMousePosX = x
this.lastMousePosY = y this.lastMousePosY = y
#event.request # request more motion events ? #event.request # request more motion events ?
@ -197,25 +177,20 @@ proc scrollEvent(darea: DrawingArea; event: EventScroll; this: PDA): bool =
var d = getScrollDirection(event) var d = getScrollDirection(event)
var (x, y) = event.getCoords var (x, y) = event.getCoords
if d == ScrollDirection.up: if d == ScrollDirection.up:
this.userZoom *= ZOOM_FACTOR_MOUSE_WHEEL this.userZoom *= ZoomFactorMouseWheel
elif d == ScrollDirection.down: elif d == ScrollDirection.down:
this.userZoom /= ZOOM_FACTOR_MOUSE_WHEEL this.userZoom /= ZoomFactorMouseWheel
if (this.userZoom < 1): if (this.userZoom < 1):
this.userZoom = 1 this.userZoom = 1
if this.zoomNearMousepointer: if this.zoomNearMousepointer:
this.updateAdjustmentsAndPaint((this.hadjustment.value + x) * ( this.updateAdjustmentsAndPaint((this.hadjustment.value + x) * (this.userZoom / z0 - 1),
this.userZoom / z0 - 1), (this.vadjustment.value + y) * (this.userZoom / z0 - 1))
(this.vadjustment.value + y) * (
this.userZoom / z0 - 1))
else: # zoom to center else: # zoom to center
this.updateAdjustmentsAndPaint((this.hadjustment.value + this.updateAdjustmentsAndPaint((this.hadjustment.value +
this.darea.allocatedWidth.float * 0.5) * (this.userZoom / z0 - 1), this.darea.allocatedWidth.float * 0.5) * (this.userZoom / z0 - 1),
(this.vadjustment.value + (this.vadjustment.value + this.darea.allocatedHeight.float * 0.5) * (this.userZoom / z0 - 1))
this.darea.allocatedHeight.float * 0.5) * (
this.userZoom / z0 - 1))
proc buttonPressEvent(darea: DrawingArea; event: EventButton; proc buttonPressEvent(darea: DrawingArea; event: EventButton; this: PDA): bool =
this: PDA): bool =
var (x, y) = event.getCoords var (x, y) = event.getCoords
this.lastMousePosX = x this.lastMousePosX = x
this.lastMousePosY = y this.lastMousePosY = y
@ -226,8 +201,7 @@ proc buttonPressEvent(darea: DrawingArea; event: EventButton;
echo "User coordinates: ", x, ' ', y, "\n" # to verify getUserCoordinates() echo "User coordinates: ", x, ' ', y, "\n" # to verify getUserCoordinates()
# zoom into selected rectangle and center it # zoom into selected rectangle and center it
proc buttonReleaseEvent(darea: DrawingArea; event: EventButton; proc buttonReleaseEvent(darea: DrawingArea; event: EventButton; this: PDA): bool =
this: PDA): bool =
var (x, y) = event.getCoords var (x, y) = event.getCoords
var b = getButton(event) var b = getButton(event)
if b == 1: if b == 1:
@ -235,7 +209,7 @@ proc buttonReleaseEvent(darea: DrawingArea; event: EventButton;
let z1 = min(this.darea.allocatedWidth.float / ( let z1 = min(this.darea.allocatedWidth.float / (
this.lastButtonDownPosX - x).abs, this.darea.allocatedHeight.float / ( this.lastButtonDownPosX - x).abs, this.darea.allocatedHeight.float / (
this.lastButtonDownPosY - y).abs) this.lastButtonDownPosY - y).abs)
if z1 < ZOOM_FACTOR_SELECT_MAX: # else selection rectangle will persist, we may output a message... if z1 < ZoomFactorSelectMax: # else selection rectangle will persist, we may output a message...
this.userZoom *= z1 this.userZoom *= z1
this.updateAdjustmentsAndPaint( this.updateAdjustmentsAndPaint(
((2 * this.hadjustment.value + x + this.lastButtonDownPosX) * z1 - ((2 * this.hadjustment.value + x + this.lastButtonDownPosX) * z1 -
@ -245,24 +219,19 @@ proc buttonReleaseEvent(darea: DrawingArea; event: EventButton;
proc onAdjustmentEvent(this: PosAdj; pda: PDA) = proc onAdjustmentEvent(this: PosAdj; pda: PDA) =
pda.paint pda.paint
pda.darea.queueDrawArea(0, 0, pda.darea.allocatedWidth, pda.darea.queueDrawArea(0, 0, pda.darea.allocatedWidth, pda.darea.allocatedHeight)
pda.darea.allocatedHeight)
proc newPDA: PDA = proc newPDA: PDA =
initGrid(result) initGrid(result)
result.zoomNearMousepointer = ZOOM_NEAR_MOUSEPOINTER # mouse wheel zooming result.zoomNearMousepointer = ZoomNearMousepointer # mouse wheel zooming
result.selecting = false
result.userZoom = 1.0 result.userZoom = 1.0
result.surf = nil
result.darea = newDrawingArea() result.darea = newDrawingArea()
result.darea.setHExpand#(true) result.darea.setHExpand
result.darea.setVExpand#(true) result.darea.setVExpand
result.darea.connect("draw", drawingAreaDrawCb, result) result.darea.connect("draw", drawingAreaDrawCb, result)
result.darea.connect("configure-event", dareaConfigureCallback, result) result.darea.connect("configure-event", dareaConfigureCallback, result)
result.darea.addEvents({EventFlag.buttonPress, EventFlag.buttonRelease, result.darea.addEvents({EventFlag.buttonPress, EventFlag.buttonRelease,
EventFlag.scroll, EventFlag.scroll, button1Motion, button2Motion, pointerMotionHint})
EventFlag.button1Motion, EventFlag.button2Motion,
EventFlag.pointerMotionHint})
result.darea.connect("motion-notify-event", onMotion, result) result.darea.connect("motion-notify-event", onMotion, result)
result.darea.connect("scroll_event", scrollEvent, result) result.darea.connect("scroll_event", scrollEvent, result)
result.darea.connect("button_press_event", buttonPressEvent, result) result.darea.connect("button_press_event", buttonPressEvent, result)
@ -275,23 +244,63 @@ proc newPDA: PDA =
onAdjustmentEvent, result) onAdjustmentEvent, result)
result.hscrollbar = newScrollbar(Orientation.horizontal, result.hadjustment) result.hscrollbar = newScrollbar(Orientation.horizontal, result.hadjustment)
result.vscrollbar = newScrollbar(Orientation.vertical, result.vadjustment) result.vscrollbar = newScrollbar(Orientation.vertical, result.vadjustment)
result.hscrollbar.setHExpand#(true) result.hscrollbar.setHExpand
result.vscrollbar.setVExpand#(true) result.vscrollbar.setVExpand
result.attach(result.darea, 0, 0, 1, 1) result.attach(result.darea, 0, 0, 1, 1)
result.attach(result.vscrollbar, 1, 0, 1, 1) result.attach(result.vscrollbar, 1, 0, 1, 1)
result.attach(result.hscrollbar, 0, 1, 1, 1) result.attach(result.hscrollbar, 0, 1, 1, 1)
proc appActivate(app: Application) = proc appActivate(app: Application; initData: ref PDA_Data) =
let window = newApplicationWindow(app) let window = newApplicationWindow(app)
window.title = "Drawing example" window.title = "Drawing example"
window.defaultSize = (400, 400) window.defaultSize = (initData.windowSize[0], initData.windowSize[1])
let pda = newPDA() let pda = newPDA()
pda.drawWorld = initData.draw
pda.extents = initData.extents
window.add(pda) window.add(pda)
showAll(window) showAll(window)
proc main = proc newDisplay*(initData: PDA_Data) =
let app = newApplication("org.gtk.example") let app = newApplication("org.gtk.example")
connect(app, "activate", appActivate) var d = new (ref PDA_Data)
d[] = initData
connect(app, "activate", appActivate, d)
discard run(app) discard run(app)
main() when isMainModule:
const # arbitrary locations for our data
DataX = 150.0
DataY = 250.0
DataWidth = 200.0
DataHeight = 120.0
# we need two user defined functions -- one gives the extent of the graphics,
# and the other does the cairo drawing using a cairo context.
# bounding box of user data -- x, y, w, h -- top left corner, width, height
proc worldExtents(): (float, float, float, float) =
(DataX, DataY, DataWidth, DataHeight) # current extents of our user world
# draw to cairo context
proc drawWorld(cr: cairo.Context) =
cr.setSource(1, 1, 1)
cr.paint
cr.setSource(0, 0, 0)
cr.setLineWidth(2)
var i = 0.0
while true:
if min(DataWidth - 2.0 * i, DataHeight - 2.0 * i) <= 0:
break
cr.rectangle(DataX + i, DataY + i, DataWidth - 2 * i, DataHeight - 2 * i)
i += 10.0
cr.stroke
proc test =
var data: PDA_Data
data.draw = drawWorld
data.extents = worldExtents
data.windowSize = (800, 600)
newDisplay(data)
test()

View file

@ -1,6 +1,6 @@
# Package # Package
version = "0.4.17" version = "0.4.18"
author = "Stefan Salewski" author = "Stefan Salewski"
description = "High level GObject-Introspection based GTK3 bindings" description = "High level GObject-Introspection based GTK3 bindings"
license = "MIT" license = "MIT"

View file

@ -1,10 +1,12 @@
# this is the high level cairo module for Nim -- based on the low level ngtk3 module, manually tuned. # This is the high level cairo module for Nim -- based on the low level ngtk3 module, manually tuned.
# S. Salewski 2017, cairo 1.15.6 # (c) S. Salewski 2017, cairo 1.15.6
# v0.4.18
# 24-APR-2019
# cairo does not really support gobject introspection and gobject's toggle references. # Cairo does not really support gobject introspection and gobject's toggle references.
# so code for memory management is a bit different compared to other gtk modules. # So code for memory management is a bit different compared to other gtk modules.
# This is the template for creation of new objects: # This was the initial template for creation of new objects :
# proc newImageSurface*(format: Format; width, height: int): Surface = # proc newImageSurface*(format: Format; width, height: int): Surface =
# new(result, surfaceDestroy) # new(result, surfaceDestroy)
@ -12,7 +14,6 @@
# discard cairo_surface_set_user_data(result.impl, NUDK, cast[pointer](result), gcuref) # discard cairo_surface_set_user_data(result.impl, NUDK, cast[pointer](result), gcuref)
# with # with
# proc gcuref(o: pointer) {.cdecl.} = GC_unref(cast[RootRef](o)) # proc gcuref(o: pointer) {.cdecl.} = GC_unref(cast[RootRef](o))
# proc surfaceDestroy*(surface: Surface) = cairo_surface_destroy(surface.impl) # proc surfaceDestroy*(surface: Surface) = cairo_surface_destroy(surface.impl)
@ -24,17 +25,44 @@
# result.impl = cairo_create(target.impl) # result.impl = cairo_create(target.impl)
# discard cairo_set_user_data(result.impl, NUDK, cast[pointer](result), gcuref) # discard cairo_set_user_data(result.impl, NUDK, cast[pointer](result), gcuref)
# we have to call GC_ref() because we store no direct reference to the proxy object. # We have to call GC_ref() because we store no direct reference to the proxy object.
# for this example cairo_create() references the surface. # For this example cairo_create() references the surface.
# when ref count of surface is decreased, maybe because context is destroyed, then gcuref is called # When ref count of surface is decreased, maybe because context is destroyed, then gcuref is called
# which calls GC_unref() on proxy. When there is no other ref to proxy GC can free proxy and surface # which calls GC_unref() on proxy. When there is no other ref to proxy GC can free proxy and surface
# by calling surfaceDestroy(). This works also when surface is newer used for something. # by calling surfaceDestroy(). This works also when surface is newer used for something.
# currently this is still nearly untested! # But there is at least one design flaw:
# one problem may be procs like cairo_surface_create_similar() when called frequently, maybe # When we create for example a surface and GC releases it, then gcunref() is called on it while
# gc_ref() was newer called. When we consider that the cairo context is the only element which
# stores references to other objects, then we can simplify the code to
# proc newImageSurface*(format: Format; width, height: int): Surface =
# new(result, surfaceDestroy)
# result.impl = cairo_image_surface_create(format, width.cint, height.cint)
# with
# proc surfaceDestroy*(surface: Surface) = cairo_surface_destroy(surface.impl)
# and this is the template for refering such an object:
# proc newContext*(target: Surface): Context =
# new(result, destroy)
# GC_ref(target)
# result.impl = cairo_create(target.impl)
# discard cairo_surface_set_user_data(target.impl, NUDK, cast[pointer](target), gcuref)
# with
# proc gcuref(o: pointer) {.cdecl.} = GC_unref(cast[RootRef](o))
# Currently this is all not really tested.
# One problem may be procs like cairo_surface_create_similar() when called frequently, maybe
# for each frame in animations. GC may be too slow in freeing the memory. # for each frame in animations. GC may be too slow in freeing the memory.
# We should try to avoid such usage, or we may add a way to manually free memory. # We should try to avoid such usage, or we may add a way to manually free memory.
# Maybe later destructors can be used? # Maybe later destructors can be used, or newruntime with owned refs?
# Maybe currently the best fix is to allow manually calling destroy() procs, which then ignore
# the later call from GC because impl field is already nil.
# Some procs are marked with label TODO -- because I have no real idea what to do with them # Some procs are marked with label TODO -- because I have no real idea what to do with them
@ -238,7 +266,9 @@ proc setUserData*(cr: Context; key: ptr UserDataKey; userData: pointer; destroy:
proc cairo_destroy*(cr: ptr Context00) {.importc, libcairo.} proc cairo_destroy*(cr: ptr Context00) {.importc, libcairo.}
# #
proc destroy*(cr: Context) = proc destroy*(cr: Context) =
cairo_destroy(cr.impl) if cr != nil and cr.impl != nil:
cairo_destroy(cr.impl)
cr.impl = nil
proc cairo_surface_reference*(surface: ptr Surface00): ptr Surface00 {.importc, libcairo.} proc cairo_surface_reference*(surface: ptr Surface00): ptr Surface00 {.importc, libcairo.}
# #
@ -246,13 +276,22 @@ proc surfaceReference*(surface: Surface): Surface =
discard cairo_surface_reference(surface.impl) discard cairo_surface_reference(surface.impl)
return surface return surface
proc cairo_surface_set_user_data*(surface: ptr Surface00;
key: ptr UserDataKey; userData: pointer; destroy: DestroyFunc00): Status {.importc, libcairo.}
#
proc setUserData*(surface: Surface; key: ptr UserDataKey; userData: pointer; destroy: DestroyFunc00): Status =
cairo_surface_set_user_data(surface.impl, key, userData, destroy)
proc cairo_create*(target: ptr Surface00): ptr Context00 {.importc, libcairo.} proc cairo_create*(target: ptr Surface00): ptr Context00 {.importc, libcairo.}
# #
proc newContext*(target: Surface): Context = proc newContext*(target: Surface): Context =
new(result, destroy) new(result, destroy)
GC_ref(target) GC_ref(target)
result.impl = cairo_create(target.impl) result.impl = cairo_create(target.impl)
discard cairo_set_user_data(result.impl, NUDK, cast[pointer](result), gcuref) discard cairo_surface_set_user_data(target.impl, NUDK, cast[pointer](target), gcuref)
proc cairo_reference*(cr: ptr Context00): ptr Context00 {.importc, libcairo.} proc cairo_reference*(cr: ptr Context00): ptr Context00 {.importc, libcairo.}
# #
@ -1002,6 +1041,7 @@ proc getFontFace*(cr: Context): FontFace =
#assert false # may this happen? #assert false # may this happen?
new(result, fontFaceDestroy) new(result, fontFaceDestroy)
result.impl = h result.impl = h
# TODO check
discard cairo_font_face_set_user_data(result.impl, NUDK, cast[pointer](result), gcuref) discard cairo_font_face_set_user_data(result.impl, NUDK, cast[pointer](result), gcuref)
discard cairo_font_face_reference(result.impl) discard cairo_font_face_reference(result.impl)
else: else:
@ -1234,7 +1274,7 @@ proc cairo_toy_font_face_create*(family: cstring; slant: FontSlant;
proc toyFontFaceCreate*(family: string; slant: FontSlant; weight: FontWeight): FontFace = proc toyFontFaceCreate*(family: string; slant: FontSlant; weight: FontWeight): FontFace =
new(result, fontFaceDestroy) new(result, fontFaceDestroy)
result.impl = cairo_toy_font_face_create(family, slant, weight) result.impl = cairo_toy_font_face_create(family, slant, weight)
discard cairo_font_face_set_user_data(result.impl, NUDK, cast[pointer](result), gcuref) ### discard cairo_font_face_set_user_data(result.impl, NUDK, cast[pointer](result), gcuref)
# returns: The family name. This string is owned by the font face and remains valid as long as the font face is alive (referenced). # returns: The family name. This string is owned by the font face and remains valid as long as the font face is alive (referenced).
proc cairo_toy_font_face_get_family*(fontFace: ptr Font_face00): cstring {.importc, libcairo.} proc cairo_toy_font_face_get_family*(fontFace: ptr Font_face00): cstring {.importc, libcairo.}
@ -1258,7 +1298,7 @@ proc userFontFaceCreate*(): FontFace =
new(result, fontFaceDestroy) new(result, fontFaceDestroy)
result.impl = cairo_user_font_face_create() result.impl = cairo_user_font_face_create()
# there is no cairo_user_font_face_set_user_data() # there is no cairo_user_font_face_set_user_data()
discard cairo_font_face_set_user_data(result.impl, NUDK, cast[pointer](result), gcuref) # discard cairo_font_face_set_user_data(result.impl, NUDK, cast[pointer](result), gcuref)
type type
UserScaledFontInitFunc00* = proc (scaledFont: ptr ScaledFont00; UserScaledFontInitFunc00* = proc (scaledFont: ptr ScaledFont00;
@ -1434,19 +1474,17 @@ proc getMatrix*(cr: Context; matrix: var Matrix) =
proc cairo_surface_destroy*(surface: ptr Surface00) {.importc, libcairo.} proc cairo_surface_destroy*(surface: ptr Surface00) {.importc, libcairo.}
# #
proc surfaceDestroy(surface: Surface) = proc destroy*(surface: Surface) =
cairo_surface_destroy(surface.impl) if surface != nil and surface.impl != nil:
cairo_surface_destroy(surface.impl)
surface.impl = nil
proc cairo_surface_get_user_data*(surface: ptr Surface00; key: ptr UserDataKey): pointer {.importc, libcairo.} proc cairo_surface_get_user_data*(surface: ptr Surface00; key: ptr UserDataKey): pointer {.importc, libcairo.}
# #
proc getUserData*(surface: Surface; key: ptr UserDataKey): pointer = proc getUserData*(surface: Surface; key: ptr UserDataKey): pointer =
cairo_surface_get_user_data(surface.impl, key) cairo_surface_get_user_data(surface.impl, key)
proc cairo_surface_set_user_data*(surface: ptr Surface00;
key: ptr UserDataKey; userData: pointer; destroy: DestroyFunc00): Status {.importc, libcairo.}
#
proc setUserData*(surface: Surface; key: ptr UserDataKey; userData: pointer; destroy: DestroyFunc00): Status =
cairo_surface_set_user_data(surface.impl, key, userData, destroy)
proc cairo_get_target*(cr: ptr Context00): ptr Surface00 {.importc, libcairo.} proc cairo_get_target*(cr: ptr Context00): ptr Surface00 {.importc, libcairo.}
# #
@ -1456,7 +1494,7 @@ proc getTarget*(cr: Context): Surface =
let d = cairo_surface_get_user_data(h, NUDK) let d = cairo_surface_get_user_data(h, NUDK)
if d.isNil: if d.isNil:
assert false # may this happen? assert false # may this happen?
new(result, surfaceDestroy) new(result, destroy)
result.impl = h result.impl = h
discard cairo_surface_set_user_data(result.impl, NUDK, cast[pointer](result), gcuref) discard cairo_surface_set_user_data(result.impl, NUDK, cast[pointer](result), gcuref)
discard cairo_surface_reference(result.impl) discard cairo_surface_reference(result.impl)
@ -1473,10 +1511,10 @@ proc getGroupTarget*(cr: Context): Surface =
let d = cairo_surface_get_user_data(h, NUDK) let d = cairo_surface_get_user_data(h, NUDK)
if d.isNil: if d.isNil:
#assert false # may this happen? #assert false # may this happen?
new(result, surfaceDestroy) new(result, destroy)
result.impl = h result.impl = h
discard cairo_surface_set_user_data(result.impl, NUDK, cast[pointer](result), gcuref) ### discard cairo_surface_set_user_data(result.impl, NUDK, cast[pointer](result), gcuref)
discard cairo_surface_reference(result.impl) ### discard cairo_surface_reference(result.impl)
else: else:
result = cast[Surface](d) result = cast[Surface](d)
assert(result.impl == h) assert(result.impl == h)
@ -1586,17 +1624,17 @@ proc cairo_surface_create_similar*(other: ptr Surface00; content: Content; width
ptr Surface00 {.importc, libcairo.} ptr Surface00 {.importc, libcairo.}
proc createSimilar*(other: Surface; content: Content; width, height: int): Surface = proc createSimilar*(other: Surface; content: Content; width, height: int): Surface =
new(result, surfaceDestroy) new(result, destroy)
result.impl = cairo_surface_create_similar(other.impl, content, width.cint, height.cint) result.impl = cairo_surface_create_similar(other.impl, content, width.cint, height.cint)
discard cairo_surface_set_user_data(result.impl, NUDK, cast[pointer](result), gcuref) ### discard cairo_surface_set_user_data(result.impl, NUDK, cast[pointer](result), gcuref)
proc cairo_surface_create_similar_image*(other: ptr Surface00; format: Format; width, height: cint): proc cairo_surface_create_similar_image*(other: ptr Surface00; format: Format; width, height: cint):
ptr Surface00 {.importc, libcairo.} ptr Surface00 {.importc, libcairo.}
# #
proc createSimilarImage*(other: Surface; format: Format; width, height: int): Surface = proc createSimilarImage*(other: Surface; format: Format; width, height: int): Surface =
new(result, surfaceDestroy) new(result, destroy)
result.impl = cairo_surface_create_similar_image(other.impl, format, width.cint, height.cint) result.impl = cairo_surface_create_similar_image(other.impl, format, width.cint, height.cint)
discard cairo_surface_set_user_data(result.impl, NUDK, cast[pointer](result), gcuref) ### discard cairo_surface_set_user_data(result.impl, NUDK, cast[pointer](result), gcuref)
proc cairo_surface_unmap_image*(surface: ptr Surface00; image: ptr Surface00) {.importc, libcairo.} proc cairo_surface_unmap_image*(surface: ptr Surface00; image: ptr Surface00) {.importc, libcairo.}
# #
@ -1606,7 +1644,7 @@ proc unmapImage*(surface: Surface; image: Surface) =
proc cairo_surface_map_to_image*(surface: ptr Surface00; extents: RectangleInt): ptr Surface00 {.importc, libcairo.} proc cairo_surface_map_to_image*(surface: ptr Surface00; extents: RectangleInt): ptr Surface00 {.importc, libcairo.}
# #
proc mapToImage*(surface: Surface; extents: RectangleInt): Surface = proc mapToImage*(surface: Surface; extents: RectangleInt): Surface =
#new(result, surfaceDestroy) # no idea currently #new(result, destroy) # no idea currently
new(result) new(result)
result.impl = cairo_surface_map_to_image(surface.impl, extents) result.impl = cairo_surface_map_to_image(surface.impl, extents)
@ -1614,9 +1652,9 @@ proc cairo_surface_create_for_rectangle*(target: ptr Surface00; x, y, width, hei
ptr Surface00 {.importc, libcairo.} ptr Surface00 {.importc, libcairo.}
# #
proc surfaceCreateForRectangle*(target: Surface; x, y, width, height: float): Surface = proc surfaceCreateForRectangle*(target: Surface; x, y, width, height: float): Surface =
new(result, surfaceDestroy) new(result, destroy)
result.impl = cairo_surface_create_for_rectangle(target.impl, x.cdouble, y.cdouble, width.cdouble, height.cdouble) result.impl = cairo_surface_create_for_rectangle(target.impl, x.cdouble, y.cdouble, width.cdouble, height.cdouble)
discard cairo_surface_set_user_data(result.impl, NUDK, cast[pointer](result), gcuref) ### discard cairo_surface_set_user_data(result.impl, NUDK, cast[pointer](result), gcuref)
type type
SurfaceObserverMode* {.size: sizeof(cint), pure.} = enum SurfaceObserverMode* {.size: sizeof(cint), pure.} = enum
@ -1627,9 +1665,9 @@ proc cairo_surface_create_observer*(target: ptr Surface00;
mode: SurfaceObserverMode): ptr Surface00 {.importc, libcairo.} mode: SurfaceObserverMode): ptr Surface00 {.importc, libcairo.}
# #
proc createObserver*(target: Surface; mode: SurfaceObserverMode): Surface = proc createObserver*(target: Surface; mode: SurfaceObserverMode): Surface =
new(result, surfaceDestroy) new(result, destroy)
result.impl = cairo_surface_create_observer(target.impl, mode) result.impl = cairo_surface_create_observer(target.impl, mode)
discard cairo_surface_set_user_data(result.impl, NUDK, cast[pointer](result), gcuref) ### discard cairo_surface_set_user_data(result.impl, NUDK, cast[pointer](result), gcuref)
type type
SurfaceObserverCallback00* = proc (observer: ptr Surface00; SurfaceObserverCallback00* = proc (observer: ptr Surface00;
@ -1841,9 +1879,9 @@ proc hasShowTextGlyphs*(surface: Surface): bool =
proc cairo_image_surface_create*(format: Format; width, height: cint): ptr Surface00 {.importc, libcairo.} proc cairo_image_surface_create*(format: Format; width, height: cint): ptr Surface00 {.importc, libcairo.}
# #
proc imageSurfaceCreate*(format: Format; width, height: int): Surface = proc imageSurfaceCreate*(format: Format; width, height: int): Surface =
new(result, surfaceDestroy) new(result, destroy)
result.impl = cairo_image_surface_create(format, width.cint, height.cint) result.impl = cairo_image_surface_create(format, width.cint, height.cint)
discard cairo_surface_set_user_data(result.impl, NUDK, cast[pointer](result), gcuref) ### discard cairo_surface_set_user_data(result.impl, NUDK, cast[pointer](result), gcuref)
proc cairo_format_stride_for_width*(format: Format; width: cint): cint {.importc, libcairo.} proc cairo_format_stride_for_width*(format: Format; width: cint): cint {.importc, libcairo.}
# #
@ -1880,24 +1918,24 @@ when CAIRO_HAS_PNG_FUNCTIONS:
proc cairo_image_surface_create_from_png*(filename: cstring): ptr Surface00 {.importc, libcairo.} proc cairo_image_surface_create_from_png*(filename: cstring): ptr Surface00 {.importc, libcairo.}
proc imageSurfaceCreateFromPng*(filename: string): Surface = proc imageSurfaceCreateFromPng*(filename: string): Surface =
new(result, surfaceDestroy) new(result, destroy)
result.impl = cairo_image_surface_create_from_png(filename) result.impl = cairo_image_surface_create_from_png(filename)
discard cairo_surface_set_user_data(result.impl, NUDK, cast[pointer](result), gcuref) ### discard cairo_surface_set_user_data(result.impl, NUDK, cast[pointer](result), gcuref)
proc cairo_image_surface_create_from_png_stream*(read_func: Read_func00; proc cairo_image_surface_create_from_png_stream*(read_func: Read_func00;
closure: pointer): ptr Surface00 {.importc, libcairo.} closure: pointer): ptr Surface00 {.importc, libcairo.}
# #
proc imageSurfaceCreateFromPngStream*(readFunc: ReadFunc00; closure: pointer): Surface = proc imageSurfaceCreateFromPngStream*(readFunc: ReadFunc00; closure: pointer): Surface =
new(result, surfaceDestroy) new(result, destroy)
result.impl = cairo_image_surface_create_from_png_stream(readFunc, closure) result.impl = cairo_image_surface_create_from_png_stream(readFunc, closure)
discard cairo_surface_set_user_data(result.impl, NUDK, cast[pointer](result), gcuref) ### discard cairo_surface_set_user_data(result.impl, NUDK, cast[pointer](result), gcuref)
proc cairo_recording_surface_create*(content: Content; extents: Rectangle00): ptr Surface00 {.importc, libcairo.} proc cairo_recording_surface_create*(content: Content; extents: Rectangle00): ptr Surface00 {.importc, libcairo.}
# #
proc recordingSurfaceCreate*(content: Content; extents: Rectangle00): Surface = proc recordingSurfaceCreate*(content: Content; extents: Rectangle00): Surface =
new(result, surfaceDestroy) new(result, destroy)
result.impl = cairo_recording_surface_create(content, extents) result.impl = cairo_recording_surface_create(content, extents)
discard cairo_surface_set_user_data(result.impl, NUDK, cast[pointer](result), gcuref) ### discard cairo_surface_set_user_data(result.impl, NUDK, cast[pointer](result), gcuref)
proc cairo_recording_surface_ink_extents*(surface: ptr Surface00; x0, y0, width, height: var cdouble) {.importc, libcairo.} proc cairo_recording_surface_ink_extents*(surface: ptr Surface00; x0, y0, width, height: var cdouble) {.importc, libcairo.}
# #
@ -1943,7 +1981,7 @@ proc cairo_pattern_create_raster_source*(userData: pointer; content: Content; wi
proc patternCreateRasterSource*(userData: pointer; content: Content; width, height: int): Pattern = proc patternCreateRasterSource*(userData: pointer; content: Content; width, height: int): Pattern =
new(result, patternDestroy) new(result, patternDestroy)
result.impl = cairo_pattern_create_raster_source(userData, content, width.cint, height.cint) result.impl = cairo_pattern_create_raster_source(userData, content, width.cint, height.cint)
discard cairo_pattern_set_user_data(result.impl, NUDK, cast[pointer](result), gcuref) ### discard cairo_pattern_set_user_data(result.impl, NUDK, cast[pointer](result), gcuref)
proc cairo_raster_source_pattern_set_callback_data*(pattern: ptr Pattern00; data: pointer) {.importc,libcairo.} proc cairo_raster_source_pattern_set_callback_data*(pattern: ptr Pattern00; data: pointer) {.importc,libcairo.}
# #
@ -2002,42 +2040,42 @@ proc cairo_pattern_create_rgb*(red, green, blue: cdouble): ptr Pattern00 {.impor
proc patternCreateRgb*(red, green, blue: float): Pattern = proc patternCreateRgb*(red, green, blue: float): Pattern =
new(result, patternDestroy) new(result, patternDestroy)
result.impl = cairo_pattern_create_rgb(red.cdouble, green.cdouble, blue.cdouble) result.impl = cairo_pattern_create_rgb(red.cdouble, green.cdouble, blue.cdouble)
discard cairo_pattern_set_user_data(result.impl, NUDK, cast[pointer](result), gcuref) ### discard cairo_pattern_set_user_data(result.impl, NUDK, cast[pointer](result), gcuref)
proc cairo_pattern_create_rgba*(red, green, blue, alpha: cdouble): ptr Pattern00 {.importc, libcairo.} proc cairo_pattern_create_rgba*(red, green, blue, alpha: cdouble): ptr Pattern00 {.importc, libcairo.}
# #
proc patternCreateRgba*(red, green, blue, alpha: float): Pattern = proc patternCreateRgba*(red, green, blue, alpha: float): Pattern =
new(result, patternDestroy) new(result, patternDestroy)
result.impl = cairo_pattern_create_rgba(red.cdouble, green.cdouble, blue.cdouble, alpha.cdouble) result.impl = cairo_pattern_create_rgba(red.cdouble, green.cdouble, blue.cdouble, alpha.cdouble)
discard cairo_pattern_set_user_data(result.impl, NUDK, cast[pointer](result), gcuref) ### discard cairo_pattern_set_user_data(result.impl, NUDK, cast[pointer](result), gcuref)
proc cairo_pattern_create_for_surface*(surface: ptr Surface00): ptr Pattern00 {.importc, libcairo.} proc cairo_pattern_create_for_surface*(surface: ptr Surface00): ptr Pattern00 {.importc, libcairo.}
# #
proc patternCreateForSurface*(surface: Surface): Pattern = proc patternCreateForSurface*(surface: Surface): Pattern =
new(result, patternDestroy) new(result, patternDestroy)
result.impl = cairo_pattern_create_for_surface(surface.impl) result.impl = cairo_pattern_create_for_surface(surface.impl)
discard cairo_pattern_set_user_data(result.impl, NUDK, cast[pointer](result), gcuref) ### discard cairo_pattern_set_user_data(result.impl, NUDK, cast[pointer](result), gcuref)
proc cairo_pattern_create_linear*(x0, y0, x1, y1: cdouble): ptr Pattern00 {.importc, libcairo.} proc cairo_pattern_create_linear*(x0, y0, x1, y1: cdouble): ptr Pattern00 {.importc, libcairo.}
# #
proc patternCreateLinear*(x0, y0, x1, y1: float): Pattern = proc patternCreateLinear*(x0, y0, x1, y1: float): Pattern =
new(result, patternDestroy) new(result, patternDestroy)
result.impl = cairo_pattern_create_linear(x0.cdouble, y0.cdouble, x1.cdouble, y1.cdouble) result.impl = cairo_pattern_create_linear(x0.cdouble, y0.cdouble, x1.cdouble, y1.cdouble)
discard cairo_pattern_set_user_data(result.impl, NUDK, cast[pointer](result), gcuref) ### discard cairo_pattern_set_user_data(result.impl, NUDK, cast[pointer](result), gcuref)
proc cairo_pattern_create_radial*(cx0, cy0, radius0, cx1, cy1, radius1: cdouble): ptr Pattern00 {.importc, libcairo.} proc cairo_pattern_create_radial*(cx0, cy0, radius0, cx1, cy1, radius1: cdouble): ptr Pattern00 {.importc, libcairo.}
# #
proc patternCreateRadial*(cx0, cy0, radius0, cx1, cy1, radius1: float): Pattern = proc patternCreateRadial*(cx0, cy0, radius0, cx1, cy1, radius1: float): Pattern =
new(result, patternDestroy) new(result, patternDestroy)
result.impl = cairo_pattern_create_radial(cx0.cdouble, cy0.cdouble, radius0.cdouble, cx1.cdouble, cy1.cdouble, radius1.cdouble) result.impl = cairo_pattern_create_radial(cx0.cdouble, cy0.cdouble, radius0.cdouble, cx1.cdouble, cy1.cdouble, radius1.cdouble)
discard cairo_pattern_set_user_data(result.impl, NUDK, cast[pointer](result), gcuref) ### discard cairo_pattern_set_user_data(result.impl, NUDK, cast[pointer](result), gcuref)
proc cairo_pattern_create_mesh*(): ptr Pattern00 {.importc, libcairo.} proc cairo_pattern_create_mesh*(): ptr Pattern00 {.importc, libcairo.}
# #
proc patternCreateMesh*(): Pattern = proc patternCreateMesh*(): Pattern =
new(result, patternDestroy) new(result, patternDestroy)
result.impl = cairo_pattern_create_mesh() result.impl = cairo_pattern_create_mesh()
discard cairo_pattern_set_user_data(result.impl, NUDK, cast[pointer](result), gcuref) ### discard cairo_pattern_set_user_data(result.impl, NUDK, cast[pointer](result), gcuref)
proc cairo_pattern_reference*(pattern: ptr Pattern00): ptr Pattern00 {.importc, libcairo.} proc cairo_pattern_reference*(pattern: ptr Pattern00): ptr Pattern00 {.importc, libcairo.}
# #
@ -2166,6 +2204,7 @@ proc getRgba*(pattern: Pattern; red, green, blue, alpha: var float): Status =
blue = blue0.float blue = blue0.float
alpha = alpha0.float alpha = alpha0.float
# TODO this seems to be wrong
proc cairo_pattern_get_surface*(pattern: ptr Pattern00; surface: var ptr Surface00): Status {.importc, libcairo.} proc cairo_pattern_get_surface*(pattern: ptr Pattern00; surface: var ptr Surface00): Status {.importc, libcairo.}
# #
proc getSurface*(pattern: Pattern; surface: var Surface): Status = proc getSurface*(pattern: Pattern; surface: var Surface): Status =
@ -2175,7 +2214,7 @@ proc getSurface*(pattern: Pattern; surface: var Surface): Status =
let d = cairo_surface_get_user_data(h, NUDK) let d = cairo_surface_get_user_data(h, NUDK)
if d.isNil: if d.isNil:
assert false # may this happen? assert false # may this happen?
new(surface, surfaceDestroy) new(surface, destroy)
surface.impl = h surface.impl = h
discard cairo_surface_set_user_data(surface.impl, NUDK, cast[pointer](surface), gcuref) discard cairo_surface_set_user_data(surface.impl, NUDK, cast[pointer](surface), gcuref)
discard cairo_surface_reference(surface.impl) discard cairo_surface_reference(surface.impl)
@ -2324,21 +2363,21 @@ type
proc cairo_region_destroy*(region: ptr Region00) {.importc, libcairo.} proc cairo_region_destroy*(region: ptr Region00) {.importc, libcairo.}
# #
proc regionDestroy*(region: Region) = proc destroy*(region: Region) =
cairo_region_destroy(region.impl) cairo_region_destroy(region.impl)
# there is no cairo_region_set_user_data() # there is no cairo_region_set_user_data()
proc cairo_region_create*(): ptr Region00 {.importc, libcairo.} proc cairo_region_create*(): ptr Region00 {.importc, libcairo.}
# #
proc regionCreate*(): Region = proc regionCreate*(): Region =
new(result, regionDestroy) new(result, destroy)
result.impl = cairo_region_create() result.impl = cairo_region_create()
#discard cairo_region_set_user_data(result.impl, NUDK, cast[pointer](result), gcuref) ### discard cairo_region_set_user_data(result.impl, NUDK, cast[pointer](result), gcuref)
proc cairo_region_create_rectangle*(rectangle: RectangleInt): ptr Region00 {.importc, libcairo.} proc cairo_region_create_rectangle*(rectangle: RectangleInt): ptr Region00 {.importc, libcairo.}
# #
proc regionCreateRectangle*(rectangle: RectangleInt): Region = proc regionCreateRectangle*(rectangle: RectangleInt): Region =
new(result, regionDestroy) new(result, destroy)
result.impl = cairo_region_create_rectangle(rectangle) result.impl = cairo_region_create_rectangle(rectangle)
# TODO # TODO
@ -2348,7 +2387,7 @@ proc cairo_region_create_rectangles*(rects: RectangleInt; count: cint): ptr Regi
proc cairo_region_copy*(original: ptr Region00): ptr Region00 {.importc, libcairo.} proc cairo_region_copy*(original: ptr Region00): ptr Region00 {.importc, libcairo.}
# #
proc regionCopy*(original: Region): Region = proc regionCopy*(original: Region): Region =
new(result, regionDestroy) new(result, destroy)
result.impl = cairo_region_copy(original.impl) result.impl = cairo_region_copy(original.impl)
proc cairo_region_reference*(region: ptr Region00): ptr Region00 {.importc, libcairo.} proc cairo_region_reference*(region: ptr Region00): ptr Region00 {.importc, libcairo.}
@ -2456,17 +2495,17 @@ when CAIRO_HAS_PDF_SURFACE:
importc, libcairo.} importc, libcairo.}
#pong #pong
proc pdfSurfaceCreate*(filename: string; widthInPoints, heightInPoints: float): Surface = proc pdfSurfaceCreate*(filename: string; widthInPoints, heightInPoints: float): Surface =
new(result, surfaceDestroy) new(result, destroy)
result.impl = cairo_pdf_surface_create(filename, widthInPoints.cdouble, heightInPoints.cdouble) result.impl = cairo_pdf_surface_create(filename, widthInPoints.cdouble, heightInPoints.cdouble)
discard cairo_surface_set_user_data(result.impl, NUDK, cast[pointer](result), gcuref) ### discard cairo_surface_set_user_data(result.impl, NUDK, cast[pointer](result), gcuref)
proc cairo_pdf_surface_create_for_stream*(writeFunc: WriteFunc00; proc cairo_pdf_surface_create_for_stream*(writeFunc: WriteFunc00;
closure: pointer; widthInPoints, heightInPoints: cdouble): ptr Surface00 {.importc, libcairo.} closure: pointer; widthInPoints, heightInPoints: cdouble): ptr Surface00 {.importc, libcairo.}
# #
proc pdfSurfaceCreateForStream*(writeFunc: WriteFunc00; closure: pointer; widthInPoints, heightInPoints: float): Surface = proc pdfSurfaceCreateForStream*(writeFunc: WriteFunc00; closure: pointer; widthInPoints, heightInPoints: float): Surface =
new(result, surfaceDestroy) new(result, destroy)
result.impl = cairo_pdf_surface_create_for_stream(writeFunc, closure, widthInPoints.cdouble, heightInPoints.cdouble) result.impl = cairo_pdf_surface_create_for_stream(writeFunc, closure, widthInPoints.cdouble, heightInPoints.cdouble)
discard cairo_surface_set_user_data(result.impl, NUDK, cast[pointer](result), gcuref) ### discard cairo_surface_set_user_data(result.impl, NUDK, cast[pointer](result), gcuref)
proc cairo_pdf_surface_restrict_to_version*(surface: ptr Surface00; proc cairo_pdf_surface_restrict_to_version*(surface: ptr Surface00;
version: PdfVersion) {.importc, libcairo.} version: PdfVersion) {.importc, libcairo.}
@ -2537,17 +2576,17 @@ when CAIRO_HAS_PS_SURFACE:
importc, libcairo.} importc, libcairo.}
# #
proc psSurfaceCreate*(filename: string; widthInPoints, heightInPoints: float): Surface = proc psSurfaceCreate*(filename: string; widthInPoints, heightInPoints: float): Surface =
new(result, surfaceDestroy) new(result, destroy)
result.impl = cairo_ps_surface_create(filename, widthInPoints.cdouble, heightInPoints.cdouble) result.impl = cairo_ps_surface_create(filename, widthInPoints.cdouble, heightInPoints.cdouble)
discard cairo_surface_set_user_data(result.impl, NUDK, cast[pointer](result), gcuref) ### discard cairo_surface_set_user_data(result.impl, NUDK, cast[pointer](result), gcuref)
proc cairo_ps_surface_create_for_stream*(writeFunc: WriteFunc00; closure: pointer; proc cairo_ps_surface_create_for_stream*(writeFunc: WriteFunc00; closure: pointer;
widthInPoints, heightInPoints: cdouble): ptr Surface00 {.importc, libcairo.} widthInPoints, heightInPoints: cdouble): ptr Surface00 {.importc, libcairo.}
# #
proc psSurfaceCreateForStream*(writeFunc: WriteFunc00; closure: pointer; widthInPoints, heightInPoints: float): Surface = proc psSurfaceCreateForStream*(writeFunc: WriteFunc00; closure: pointer; widthInPoints, heightInPoints: float): Surface =
new(result, surfaceDestroy) new(result, destroy)
result.impl = cairo_ps_surface_create_for_stream(writeFunc, closure, widthInPoints.cdouble, heightInPoints.cdouble) result.impl = cairo_ps_surface_create_for_stream(writeFunc, closure, widthInPoints.cdouble, heightInPoints.cdouble)
discard cairo_surface_set_user_data(result.impl, NUDK, cast[pointer](result), gcuref) ### discard cairo_surface_set_user_data(result.impl, NUDK, cast[pointer](result), gcuref)
proc cairo_ps_surface_restrict_to_level*(surface: ptr Surface00; level: PsLevel) {.importc, libcairo.} proc cairo_ps_surface_restrict_to_level*(surface: ptr Surface00; level: PsLevel) {.importc, libcairo.}
# #
@ -2604,17 +2643,17 @@ when CAIRO_HAS_SVG_SURFACE:
importc, libcairo.} importc, libcairo.}
# #
proc svgSurfaceCreate*(filename: string; widthInPoints, heightInPoints: float): Surface = proc svgSurfaceCreate*(filename: string; widthInPoints, heightInPoints: float): Surface =
new(result, surfaceDestroy) new(result, destroy)
result.impl = cairo_svg_surface_create(filename, widthInPoints.cdouble, heightInPoints.cdouble) result.impl = cairo_svg_surface_create(filename, widthInPoints.cdouble, heightInPoints.cdouble)
discard cairo_surface_set_user_data(result.impl, NUDK, cast[pointer](result), gcuref) ### discard cairo_surface_set_user_data(result.impl, NUDK, cast[pointer](result), gcuref)
proc cairo_svg_surface_create_for_stream*(write_func: Write_func00; proc cairo_svg_surface_create_for_stream*(write_func: Write_func00;
closure: pointer; widthInPoints, heightInPoints: cdouble): ptr Surface00 {.importc, libcairo.} closure: pointer; widthInPoints, heightInPoints: cdouble): ptr Surface00 {.importc, libcairo.}
# #
proc svgSurfaceCreateForstream*(writeFunc: WriteFunc00; closure: pointer; widthInPoints, heightInPoints: float): Surface = proc svgSurfaceCreateForstream*(writeFunc: WriteFunc00; closure: pointer; widthInPoints, heightInPoints: float): Surface =
new(result, surfaceDestroy) new(result, destroy)
result.impl = cairo_svg_surface_create_for_stream(writeFunc, closure, widthInPoints.cdouble, heightInPoints.cdouble) result.impl = cairo_svg_surface_create_for_stream(writeFunc, closure, widthInPoints.cdouble, heightInPoints.cdouble)
discard cairo_surface_set_user_data(result.impl, NUDK, cast[pointer](result), gcuref) ### discard cairo_surface_set_user_data(result.impl, NUDK, cast[pointer](result), gcuref)
proc cairo_svg_surface_restrict_to_version*(surface: ptr Surface00; version: SvgVersion) {.importc, libcairo.} proc cairo_svg_surface_restrict_to_version*(surface: ptr Surface00; version: SvgVersion) {.importc, libcairo.}
# #
@ -2638,22 +2677,22 @@ when CAIRO_HAS_XML_SURFACE:
proc xml_create*(filename: string): Device = proc xml_create*(filename: string): Device =
new(result, deviceDestroy) new(result, deviceDestroy)
result.impl = cairo_xml_create(filename) result.impl = cairo_xml_create(filename)
discard cairo_device_set_user_data(result.impl, NUDK, cast[pointer](result), gcuref) ### discard cairo_device_set_user_data(result.impl, NUDK, cast[pointer](result), gcuref)
proc cairo_xml_create_for_stream*(writeFunc: WriteFunc00; closure: pointer): ptr Device00 {.importc, libcairo.} proc cairo_xml_create_for_stream*(writeFunc: WriteFunc00; closure: pointer): ptr Device00 {.importc, libcairo.}
# #
proc xmlCreateForStream*(writeFunc: WriteFunc00; closure: pointer): Device = proc xmlCreateForStream*(writeFunc: WriteFunc00; closure: pointer): Device =
new(result, deviceDestroy) new(result, deviceDestroy)
result.impl = cairo_xml_create_for_stream(writeFunc, closure) result.impl = cairo_xml_create_for_stream(writeFunc, closure)
discard cairo_device_set_user_data(result.impl, NUDK, cast[pointer](result), gcuref) ### discard cairo_device_set_user_data(result.impl, NUDK, cast[pointer](result), gcuref)
proc cairo_xml_surface_create*(xml: ptr Device00; content: Content; width, height: cdouble): ptr Surface00 {. proc cairo_xml_surface_create*(xml: ptr Device00; content: Content; width, height: cdouble): ptr Surface00 {.
importc, libcairo.} importc, libcairo.}
# #
proc xmlSurfaceCreate*(xml: Device; content: Content; width, height: float): Surface = proc xmlSurfaceCreate*(xml: Device; content: Content; width, height: float): Surface =
new(result, surfaceDestroy) new(result, destroy)
result.impl = cairo_xml_surface_create(xml.impl, content, width.cdouble, height.cdouble) result.impl = cairo_xml_surface_create(xml.impl, content, width.cdouble, height.cdouble)
discard cairo_surface_set_user_data(result.impl, NUDK, cast[pointer](result), gcuref) ### discard cairo_surface_set_user_data(result.impl, NUDK, cast[pointer](result), gcuref)
proc cairo_xml_for_recording_surface*(xml: ptr Device00; surface: ptr Surface00): Status {.importc, libcairo.} proc cairo_xml_for_recording_surface*(xml: ptr Device00; surface: ptr Surface00): Status {.importc, libcairo.}
# #
@ -2670,14 +2709,14 @@ when CAIRO_HAS_SCRIPT_SURFACE:
proc scriptCreate*(filename: string): Device = proc scriptCreate*(filename: string): Device =
new(result, deviceDestroy) new(result, deviceDestroy)
result.impl = cairo_script_create(filename) result.impl = cairo_script_create(filename)
discard cairo_device_set_user_data(result.impl, NUDK, cast[pointer](result), gcuref) ### discard cairo_device_set_user_data(result.impl, NUDK, cast[pointer](result), gcuref)
proc cairo_script_create_for_stream*(writeFunc: WriteFunc00; closure: pointer): ptr Device00 {.importc, libcairo.} proc cairo_script_create_for_stream*(writeFunc: WriteFunc00; closure: pointer): ptr Device00 {.importc, libcairo.}
# #
proc scriptCcreateForStream*(writeFunc: WriteFunc00; closure: pointer): Device = proc scriptCreateForStream*(writeFunc: WriteFunc00; closure: pointer): Device =
new(result, deviceDestroy) new(result, deviceDestroy)
result.impl = cairo_script_create_for_stream(writeFunc, closure) result.impl = cairo_script_create_for_stream(writeFunc, closure)
discard cairo_device_set_user_data(result.impl, NUDK, cast[pointer](result), gcuref) ### discard cairo_device_set_user_data(result.impl, NUDK, cast[pointer](result), gcuref)
proc cairo_script_write_comment*(script: ptr Device00; comment: cstring; len: cint) {.importc, libcairo.} proc cairo_script_write_comment*(script: ptr Device00; comment: cstring; len: cint) {.importc, libcairo.}
# #
@ -2698,17 +2737,17 @@ when CAIRO_HAS_SCRIPT_SURFACE:
importc, libcairo.} importc, libcairo.}
# #
proc scriptSurfaceCreate*(script: Device; content: Content; width, height: float): Surface = proc scriptSurfaceCreate*(script: Device; content: Content; width, height: float): Surface =
new(result, surfaceDestroy) new(result, destroy)
result.impl = cairo_script_surface_create(script.impl, content, width.cdouble, height.cdouble) result.impl = cairo_script_surface_create(script.impl, content, width.cdouble, height.cdouble)
discard cairo_surface_set_user_data(result.impl, NUDK, cast[pointer](result), gcuref) ### discard cairo_surface_set_user_data(result.impl, NUDK, cast[pointer](result), gcuref)
proc cairo_script_surface_create_for_target*(script: ptr Device00; proc cairo_script_surface_create_for_target*(script: ptr Device00;
target: ptr Surface00): ptr Surface00 {.importc, libcairo.} target: ptr Surface00): ptr Surface00 {.importc, libcairo.}
# #
proc scriptSurfaceCreateForTarget*(script: Device; target: Surface): Surface = proc scriptSurfaceCreateForTarget*(script: Device; target: Surface): Surface =
new(result, surfaceDestroy) new(result, destroy)
result.impl = cairo_script_surface_create_for_target(script.impl, target.impl) result.impl = cairo_script_surface_create_for_target(script.impl, target.impl)
discard cairo_surface_set_user_data(result.impl, NUDK, cast[pointer](result), gcuref) ### discard cairo_surface_set_user_data(result.impl, NUDK, cast[pointer](result), gcuref)
proc cairo_script_from_recording_surface*(script: ptr Device00; proc cairo_script_from_recording_surface*(script: ptr Device00;
recordingSurface: ptr Surface00): Status {.importc, libcairo.} recordingSurface: ptr Surface00): Status {.importc, libcairo.}
@ -2720,9 +2759,9 @@ when CAIRO_HAS_SKIA_SURFACE:
proc cairo_skia_surface_create*(format: Format; width, height: cint): ptr Surface00 {.importc, libcairo.} proc cairo_skia_surface_create*(format: Format; width, height: cint): ptr Surface00 {.importc, libcairo.}
# #
proc skiaSurfaceCreate*(format: Format; width, height: int): Surface = proc skiaSurfaceCreate*(format: Format; width, height: int): Surface =
new(result, surfaceDestroy) new(result, destroy)
result.impl = cairo_skia_surface_create(format, width.cint, height.cint) result.impl = cairo_skia_surface_create(format, width.cint, height.cint)
discard cairo_surface_set_user_data(result.impl, NUDK, cast[pointer](result), gcuref) ### discard cairo_surface_set_user_data(result.impl, NUDK, cast[pointer](result), gcuref)
#TODO #TODO
proc cairo_skia_surface_create_for_data*(data: ptr cuchar; format: Format; width, height, stride: cint): proc cairo_skia_surface_create_for_data*(data: ptr cuchar; format: Format; width, height, stride: cint):
@ -2762,9 +2801,9 @@ when CAIRO_HAS_TEE_SURFACE:
proc cairo_tee_surface_create*(master: ptr Surface00): ptr Surface00 {.importc, libcairo.} proc cairo_tee_surface_create*(master: ptr Surface00): ptr Surface00 {.importc, libcairo.}
# #
proc teeSurfaceCreate*(master: Surface): Surface = proc teeSurfaceCreate*(master: Surface): Surface =
new(result, surfaceDestroy) new(result, destroy)
result.impl = cairo_tee_surface_create(master.impl) result.impl = cairo_tee_surface_create(master.impl)
discard cairo_surface_set_user_data(result.impl, NUDK, cast[pointer](result), gcuref) ### discard cairo_surface_set_user_data(result.impl, NUDK, cast[pointer](result), gcuref)
proc cairo_tee_surface_add*(surface: ptr Surface00; target: ptr Surface00) {.importc, libcairo.} proc cairo_tee_surface_add*(surface: ptr Surface00; target: ptr Surface00) {.importc, libcairo.}
# #

2785
gintro/oldcairo.nim Normal file

File diff suppressed because it is too large Load diff

View file

@ -1,5 +1,5 @@
# High level gobject-introspection based GTK3 bindings for the Nim programming language # High level gobject-introspection based GTK3 bindings for the Nim programming language
# v 0.4.17 2019-APR-16 # v 0.4.18 2019-APR-27
# (c) S. Salewski 2018 # (c) S. Salewski 2018
# https://wiki.gnome.org/Projects/GObjectIntrospection # https://wiki.gnome.org/Projects/GObjectIntrospection
@ -106,6 +106,7 @@ proc renumber(s: var string; i: int) =
var defaultParameters = newTable[string, string]() var defaultParameters = newTable[string, string]()
var fixedProcNames = newTable[string, string]() var fixedProcNames = newTable[string, string]()
var fixedDestroyNames = newTable[string, string]()
var mangledNames = newTable[string, string]() var mangledNames = newTable[string, string]()
var gdkKeys = newTable[string, seq[string]]() var gdkKeys = newTable[string, seq[string]]()
var allSyms: HashSet[string] var allSyms: HashSet[string]
@ -124,6 +125,11 @@ var delayedMethods: seq[(GIBaseInfo, GIFunctionInfo)]
var classList: seq[GIBaseInfo] var classList: seq[GIBaseInfo]
var ct: CountTable[string] var ct: CountTable[string]
fixedDestroyNames.add("gdk_window_create_similar_surface", "cairo.destroy")
fixedDestroyNames.add("gdk_window_create_similar_image_surface", "cairo.destroy")
fixedDestroyNames.add("gdk_cairo_region_create_from_surface", "cairo.destroy")
fixedDestroyNames.add("gdk_cairo_surface_create_from_pixbuf", "cairo.destroy")
fixedProcNames.add("gtk_button_new_with_label", "newButton") fixedProcNames.add("gtk_button_new_with_label", "newButton")
fixedProcNames.add("pango_font_description_from_string", "newFontDescription") fixedProcNames.add("pango_font_description_from_string", "newFontDescription")
fixedProcNames.add("pango_language_from_string", "languageFromString") fixedProcNames.add("pango_language_from_string", "languageFromString")
@ -722,8 +728,12 @@ proc writeMethod(info: GIBaseInfo; minfo: GIFunctionInfo; genProxy = false) =
freeMe = gStructInfoFindMethod(info, "unref") freeMe = gStructInfoFindMethod(info, "unref")
var freeMeName: string var freeMeName: string
if freeMe == nil: if freeMe == nil:
echo "Caution: No free/unref found for ", ' ', " (", sym, ')' # Mostly missing cairo functions... if fixedDestroyNames.contains(sym):
freeMeName = fixedDestroyNames[sym]
else:
echo "Caution: No free/unref found for ", ' ', " (", sym, ')' # Mostly missing cairo functions...
else: else:
assert not fixedDestroyNames.contains(sym)
freeMeName = $gBaseInfoGetName(freeMe) freeMeName = $gBaseInfoGetName(freeMe)
if sym == "g_closure_new_simple" or sym == "g_closure_new_object": freeMeName = "unref" # TODO GI bug? if sym == "g_closure_new_simple" or sym == "g_closure_new_object": freeMeName = "unref" # TODO GI bug?
assert(gCallableInfoGetCallerOwns(minfo) in {GITransfer.EVERYTHING, GITransfer.NOTHING}) assert(gCallableInfoGetCallerOwns(minfo) in {GITransfer.EVERYTHING, GITransfer.NOTHING})
@ -797,8 +807,16 @@ proc writeMethod(info: GIBaseInfo; minfo: GIFunctionInfo; genProxy = false) =
elif h.endsWith("unref"): elif h.endsWith("unref"):
freeMeName = "unref" freeMeName = "unref"
break break
if fixedDestroyNames.contains(sym):
freeMeName = fixedDestroyNames[sym]
#else:
if freeMeName == "": if freeMeName == "":
# assert false # TODO we have to fix this case manually # assert false # TODO we have to fix this case manually
echo "Caution: No free/unref found for ", ' ', gBaseInfoGetName(iface), " (", sym, ')' echo "Caution: No free/unref found for ", ' ', gBaseInfoGetName(iface), " (", sym, ')'
methodBuffer.writeLine(" new(result)") methodBuffer.writeLine(" new(result)")
else: else:
@ -847,8 +865,17 @@ proc writeMethod(info: GIBaseInfo; minfo: GIFunctionInfo; genProxy = false) =
freeMe = gStructInfoFindMethod(info, "free") freeMe = gStructInfoFindMethod(info, "free")
if freeMe.isNil: if freeMe.isNil:
freeMe = gStructInfoFindMethod(info, "unref") freeMe = gStructInfoFindMethod(info, "unref")
if freeMe == nil: if freeMe == nil:
echo "Caution: No free/unref found for ", ' ', " (", sym, ')' # Mostly missing cairo functions... if fixedDestroyNames.contains(sym):
freeMeName = fixedDestroyNames[sym]
else:
echo "Caution: No free/unref found for ", ' ', " (", sym, ')' # Mostly missing cairo functions...
else: else:
freeMeName = $gBaseInfoGetName(freeMe) freeMeName = $gBaseInfoGetName(freeMe)
let h2 = mangleName(gBaseInfoGetName(arg)) let h2 = mangleName(gBaseInfoGetName(arg))
@ -1907,6 +1934,10 @@ proc main(namespace: string) =
output.writeLine("type\n ColorArray* = pointer") output.writeLine("type\n ColorArray* = pointer")
output.writeLine("type\n Point00Array* = pointer") output.writeLine("type\n Point00Array* = pointer")
elif namespace == "Gtk": elif namespace == "Gtk":
output.writeLine("# https://developer.gnome.org/gtk3/stable/GtkWidget.html#GtkWidget-draw")
output.writeLine("# TRUE to stop other handlers from being invoked for the event. FALSE to propagate the event further.")
output.writeLine("const\n SignalEventStopPropagation* = true")
output.writeLine("const\n SignalEventContinuePropagation* = false")
output.writeLine("type\n TargetEntry00Array* = pointer") output.writeLine("type\n TargetEntry00Array* = pointer")
output.writeLine("type\n AccelGroupEntry00Array* = pointer") output.writeLine("type\n AccelGroupEntry00Array* = pointer")
output.writeLine("type\n BindingArg00Array* = pointer") output.writeLine("type\n BindingArg00Array* = pointer")
@ -2115,10 +2146,21 @@ proc main(namespace: string) =
if i == "": continue if i == "": continue
output.write(""" output.write("""
proc get$1*(builder: Builder; name: string): $1 = proc get$1*(builder: Builder; name: string): $1 =
new result
let gt = g_type_from_name("Gtk$1") let gt = g_type_from_name("Gtk$1")
assert(gt != 0) assert(gt != 0)
result.impl = gtk_builder_get_object(cast[ptr Builder00](builder.impl), name) let gobj = gtk_builder_get_object(cast[ptr Builder00](builder.impl), name)
if g_object_get_qdata(gobj, Quark) != nil:
result = cast[type(result)](g_object_get_qdata(gobj, Quark))
assert(result.impl == gobj)
else:
new(result, finalizeGObject)
result.impl = gobj
#GC_ref(result) # we should not need this for builder, as returned objects are not floating
#discard g_object_ref_sink(result.impl)
g_object_add_toggle_ref(result.impl, toggleNotify, addr(result[]))
#g_object_unref(result.impl)
assert(g_object_get_qdata(result.impl, Quark) == nil)
g_object_set_qdata(result.impl, Quark, addr(result[]))
assert(toBool(g_type_check_instance_is_a(cast[ptr TypeInstance00](result.impl), gt))) assert(toBool(g_type_check_instance_is_a(cast[ptr TypeInstance00](result.impl), gt)))
""" % [i]) """ % [i])
@ -2176,4 +2218,4 @@ o.close()
supmod.close supmod.close
#for i in callerAllocCollector: echo i #for i in callerAllocCollector: echo i
# 1743 lines # 2233 lines