From 8a59ea33d0177fe80ebdc87fcf94e7bda8be1982 Mon Sep 17 00:00:00 2001 From: Stefan Salewski Date: Sun, 14 Apr 2019 12:56:38 +0200 Subject: [PATCH] various fixes --- README.adoc | 87 +++++------ examples/drawingarea.nim | 297 +++++++++++++++++++++++++++++++++++ gintro.nimble | 2 +- gintro/gimpl.nim | 4 +- tests/gen.nim | 328 ++++++++++++++++++++++++++++++++++++++- 5 files changed, 668 insertions(+), 50 deletions(-) create mode 100644 examples/drawingarea.nim diff --git a/README.adoc b/README.adoc index f3afd07..af6ba0a 100644 --- a/README.adoc +++ b/README.adoc @@ -841,14 +841,13 @@ main() == A more advanced example for cairo drawing with zooming, panning, scrolling 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 bingings it seems to work fine, but some rewriting for optimized performance -may be needed, I have to investigate that. +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. +Later we may use Destructors for that. -NOTE: The latest needed gintro patch is not yet available, I will provide it soon... - -[[cairo2.nim]] +[[drawingarea.nim]] [source,nim] -.cairo2.nim +.drawingarea.nim ---- # Plain demo for zooming, panning, scrolling with GTK DrawingArea # (c) S. Salewski, 21-DEC-2010 (initial Ruby version) @@ -879,7 +878,7 @@ proc drawWorld(cr: cairo.Context) = cr.rectangle(DataX, DataY, DataWidth, DataHeight) var i = 10.0 while true: - if [DataWidth - 2.0 * i, DataHeight - 2.0 * i].min <= 0: + 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) @@ -933,7 +932,7 @@ proc newPosAdj: PosAdj = initAdjustment(result, 0, 0, 1, 1, 10, 1) type - PDA = ref object of Table + PDA = ref object of Grid zoomNearMousepointer: bool selecting: bool userZoom: float @@ -973,7 +972,7 @@ proc drawingAreaDrawCb(darea: DrawingArea; cr: Context; this: PDA): bool = # clamp to correct values, 0 <= value <= (adj.upper - adj.pageSize), block calling onAdjustmentEvent() proc updateVal(adj: PosAdj; d: float) = adj.signalHandlerBlock(adj.handlerID) - adj.setValue([0.0, [adj.value + d, adj.upper - adj.pageSize].min].max) + adj.setValue(max(0.0, min(adj.value + d, adj.upper - adj.pageSize))) adj.signalHandlerUnblock(adj.handlerID) proc updateAdjustments(this: PDA; dx, dy: float) = @@ -991,7 +990,7 @@ proc updateAdjustments(this: PDA; dx, dy: float) = # or maybe even better do all drwing from within "draw" callback? proc paint(this: PDA) = if this.surf != nil: - cairosurfaceDestroy(this.surf.impl) # we may have to fix that later for automatically destroy + cairosurfaceDestroy(this.surf.impl) # we may have to fix that later for automatically destroy this.surf = this.darea.window.createSimilarSurface(Content.color, this.darea.allocatedWidth, this.darea.allocatedHeight) let cr = newContext(this.surf) @@ -1007,8 +1006,8 @@ proc dareaConfigureCallback(darea: DrawingArea; event: EventConfigure; this.updateAdjustments(0, 0) (this.dataX, this.dataY, this.dataWidth, this.dataHeight) = getWorldExtends() # query user defined size - this.fullScale = [this.darea.allocatedWidth.float / this.dataWidth, - this.darea.allocatedHeight.float / this.dataHeight].min + this.fullScale = min(this.darea.allocatedWidth.float / this.dataWidth, + this.darea.allocatedHeight.float / this.dataHeight) this.paint proc updateAdjustmentsAndPaint(this: PDA; dx, dy: float) = @@ -1017,11 +1016,17 @@ proc updateAdjustmentsAndPaint(this: PDA; dx, dy: float) = this.darea.queueDrawArea(0, 0, this.darea.allocatedWidth, this.darea.allocatedHeight) +# event coordinates to user space +proc getUserCoordinates(this: PDA; eventX, eventY: float): (float, float) = + ((eventX - this.hadjustment.upper * 0.5 + this.hadjustment.value) / ( + this.fullScale * this.userZoom) + this.dataX + this.dataWidth * 0.5, + (eventY - this.vadjustment.upper * 0.5 + this.vadjustment.value) / ( + this.fullScale * this.userZoom) + this.dataY + this.dataHeight * 0.5) + proc onMotion(darea: DrawingArea; event: EventMotion; this: PDA): bool = - var state: ModifierType - discard event.state(state) - var x, y: float - discard event.getCoords(x, y) + let state = getState(event) + let (x, y) = event.getCoords + #(x, y) = this.getUserCoordinates(x, y) if (state.contains(button1)): # selecting this.selecting = true this.zoomRectX1 = x @@ -1040,10 +1045,8 @@ proc onMotion(darea: DrawingArea; event: EventMotion; this: PDA): bool = # is the relative movement caused by zooming proc scrollEvent(darea: DrawingArea; event: EventScroll; this: PDA): bool = let z0 = this.userZoom - var d: ScrollDirection - discard scrollDirection(event, d) - var x, y: float - discard event.getCoords(x, y) + var d = getScrollDirection(event) + var (x, y) = event.getCoords if d == ScrollDirection.up: this.userZoom *= ZOOM_FACTOR_MOUSE_WHEEL elif d == ScrollDirection.down: @@ -1059,38 +1062,30 @@ proc scrollEvent(darea: DrawingArea; event: EventScroll; this: PDA): bool = this.updateAdjustmentsAndPaint((this.hadjustment.value + this.darea.allocatedWidth.float * 0.5) * (this.userZoom / z0 - 1), (this.vadjustment.value + - this.darea.allocatedHeight.float * 0.5) * (this.userZoom / z0 - 1)) - -# event coordinates to user space -proc getUserCoordinates(this: PDA; eventX, eventY: float): (float, float) = - ((eventX - this.hadjustment.upper * 0.5 + this.hadjustment.value) / ( - this.fullScale * this.userZoom) + this.dataX + this.dataWidth * 0.5, - (eventY - this.vadjustment.upper * 0.5 + this.vadjustment.value) / ( - this.fullScale * this.userZoom) + this.dataY + this.dataHeight * 0.5) + this.darea.allocatedHeight.float * 0.5) * ( + this.userZoom / z0 - 1)) proc buttonPressEvent(darea: DrawingArea; event: EventButton; this: PDA): bool = - var x, y: float - discard event.getCoords(x, y) - (x, y) = this.getUserCoordinates(x, y) - echo "User coordinates: ", x, ' ', y, "\n" # to verify getUserCoordinates() + var (x, y) = event.getCoords this.lastMousePosX = x this.lastMousePosY = y this.lastButtonDownPosX = x this.lastButtonDownPosY = y + echo "buttonPressEvent", x, " ", y + (x, y) = this.getUserCoordinates(x, y) + echo "User coordinates: ", x, ' ', y, "\n" # to verify getUserCoordinates() # zoom into selected rectangle and center it proc buttonReleaseEvent(darea: DrawingArea; event: EventButton; this: PDA): bool = - var x, y: float - discard event.getCoords(x, y) - var b: int - discard button(event, b) + var (x, y) = event.getCoords + var b = getButton(event) if b == 1: this.selecting = false - let z1 = [this.darea.allocatedWidth.float / ( + let z1 = min(this.darea.allocatedWidth.float / ( this.lastButtonDownPosX - x).abs, this.darea.allocatedHeight.float / ( - this.lastButtonDownPosY - y).abs].min + this.lastButtonDownPosY - y).abs) if z1 < ZOOM_FACTOR_SELECT_MAX: # else selection rectangle will persist, we may output a message... this.userZoom *= z1 this.updateAdjustmentsAndPaint( @@ -1105,13 +1100,14 @@ proc onAdjustmentEvent(this: PosAdj; pda: PDA) = pda.darea.allocatedHeight) proc newPDA: PDA = - initTable(result, 2, 2, false) + initGrid(result) result.zoomNearMousepointer = ZOOM_NEAR_MOUSEPOINTER # mouse wheel zooming result.selecting = false result.userZoom = 1.0 result.surf = nil result.darea = newDrawingArea() - + result.darea.setHExpand#(true) + result.darea.setVExpand#(true) result.darea.connect("draw", drawingAreaDrawCb, result) result.darea.connect("configure-event", dareaConfigureCallback, result) result.darea.addEvents({EventFlag.buttonPress, EventFlag.buttonRelease, @@ -1130,12 +1126,11 @@ proc newPDA: PDA = onAdjustmentEvent, result) result.hscrollbar = newScrollbar(Orientation.horizontal, result.hadjustment) result.vscrollbar = newScrollbar(Orientation.vertical, result.vadjustment) - result.attach(result.darea, 0, 1, 0, 1, {AttachFlag.expand, AttachFlag.fill}, { - AttachFlag.expand, AttachFlag.fill}, 0, 0) - result.attach(result.hscrollbar, 0, 1, 1, 2, {AttachFlag.expand, - AttachFlag.fill}, {}, 0, 0) - result.attach(result.vscrollbar, 1, 2, 0, 1, {}, {AttachFlag.expand, - AttachFlag.fill}, 0, 0) + result.hscrollbar.setHExpand#(true) + result.vscrollbar.setVExpand#(true) + result.attach(result.darea, 0, 0, 1, 1) + result.attach(result.vscrollbar, 1, 0, 1, 1) + result.attach(result.hscrollbar, 0, 1, 1, 1) proc appActivate(app: Application) = let window = newApplicationWindow(app) diff --git a/examples/drawingarea.nim b/examples/drawingarea.nim new file mode 100644 index 0000000..f7d6620 --- /dev/null +++ b/examples/drawingarea.nim @@ -0,0 +1,297 @@ +# Plain demo for zooming, panning, scrolling with GTK DrawingArea +# (c) S. Salewski, 21-DEC-2010 (initial Ruby version) +# Nim version April 2019 -- well first draft :-) +# License MIT + +import gintro/[gtk, gdk, glib, gobject, gio, cairo] + +const + DataX = 150.0 + DataY = 250.0 + DataWidth = 200.0 + DataHeight = 120.0 + +# 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 """ +Zooming, scrolling, panning... + +|-------------------------| +|<-------- A ------------>| +| | +| |---------------| | +| | <---- a ----->| | +| | visible | | +| |---------------| | +| | +| | +|-------------------------| + +a is the visible, zoomed in area == darea.allocatedWidth +A is the total data range +A/a == userZoom >= 1 +For horizontal adjustment we use +hadjustment.setUpper(darea.allocatedWidth * userZoom) == A +hadjustment.setPageSize(darea.allocatedWidth) == a +So hadjustment.value == left side of visible area + +Initially, we set userZoom = 1, scale our data to fit into darea.allocatedWidth +and translate the origin of our data to (0, 0) + +Zooming: Mouse wheel or selecting a rectangle with left mouse button pressed +Scrolling: Scrollbars +Panning: Moving mouse while middle mouse button pressed +""" + +# drawing area and scroll bars in 2x2 table (PDA == Plain Drawing Area) + +type + PosAdj = ref object of Adjustment + handlerID: uint64 + +proc newPosAdj: PosAdj = + initAdjustment(result, 0, 0, 1, 1, 10, 1) + +type + PDA = ref object of Grid + zoomNearMousepointer: bool + selecting: bool + userZoom: float + surf: Surface + darea: DrawingArea + hadjustment: PosAdj + vadjustment: PosAdj + hscrollbar: Scrollbar + vscrollbar: Scrollbar + fullScale: float + dataX: float + dataY: float + dataWidth: float + dataHeight: float + lastButtonDownPosX: float + lastButtonDownPosY: float + lastMousePosX: float + lastMousePosY: float + zoomRectX1: float + zoomRectY1: float + +proc drawingAreaDrawCb(darea: DrawingArea; cr: Context; this: PDA): bool = + if this.surf.isNil: return + cr.setSource(patternCreateForSurface(this.surf)) + cr.paint + if this.selecting: + cr.rectangle(this.lastButtonDownPosX, this.lastButtonDownPosY, + this.zoomRectX1 - this.lastButtonDownPosX, + this.zoomRectY1 - this.lastButtonDownPosY) + cr.setSource(0, 0, 1, 0.5) # SELECT_RECT_COL) # 0, 0, 1, 0.5 + cr.fillPreserve + cr.setSource(0, 0, 0) + cr.setLineWidth(2) + cr.stroke + 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() +proc updateVal(adj: PosAdj; d: float) = + adj.signalHandlerBlock(adj.handlerID) + adj.setValue(max(0.0, min(adj.value + d, adj.upper - adj.pageSize))) + adj.signalHandlerUnblock(adj.handlerID) + +proc updateAdjustments(this: PDA; dx, dy: float) = + this.hadjustment.setUpper(this.darea.allocatedWidth.float * this.userZoom) + this.vadjustment.setUpper(this.darea.allocatedHeight.float * + this.userZoom) + this.hadjustment.setPageSize(this.darea.allocatedWidth.float) + this.vadjustment.setPageSize(this.darea.allocatedHeight.float) + updateVal(this.hadjustment, dx) + updateVal(this.vadjustment, dy) + +# Maybe we should fix this for latest GTK3, see +# 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) = + if this.surf != nil: + cairosurfaceDestroy(this.surf.impl) # we may have to fix that later for automatically destroy + this.surf = this.darea.window.createSimilarSurface(Content.color, + this.darea.allocatedWidth, this.darea.allocatedHeight) + let cr = newContext(this.surf) + cr.translate(this.hadjustment.upper * 0.5 - this.hadjustment.value, # our origin is the center + this.vadjustment.upper * 0.5 - this.vadjustment.value) + cr.scale(this.fullScale * this.userZoom, this.fullScale * this.userZoom) + cr.translate(-this.dataX - this.dataWidth * 0.5, + -this.dataY - this.dataHeight * 0.5) + drawWorld(cr) # call the user provided drawing fonction + +proc dareaConfigureCallback(darea: DrawingArea; event: EventConfigure; + this: PDA): bool = + this.updateAdjustments(0, 0) + (this.dataX, this.dataY, this.dataWidth, + this.dataHeight) = getWorldExtends() # query user defined size + this.fullScale = min(this.darea.allocatedWidth.float / this.dataWidth, + this.darea.allocatedHeight.float / this.dataHeight) + this.paint + +proc updateAdjustmentsAndPaint(this: PDA; dx, dy: float) = + this.updateAdjustments(dx, dy) + this.paint + this.darea.queueDrawArea(0, 0, this.darea.allocatedWidth, + this.darea.allocatedHeight) + +# event coordinates to user space +proc getUserCoordinates(this: PDA; eventX, eventY: float): (float, float) = + ((eventX - this.hadjustment.upper * 0.5 + this.hadjustment.value) / ( + this.fullScale * this.userZoom) + this.dataX + this.dataWidth * 0.5, + (eventY - this.vadjustment.upper * 0.5 + this.vadjustment.value) / ( + this.fullScale * this.userZoom) + this.dataY + this.dataHeight * 0.5) + +proc onMotion(darea: DrawingArea; event: EventMotion; this: PDA): bool = + let state = getState(event) + let (x, y) = event.getCoords + #(x, y) = this.getUserCoordinates(x, y) + if (state.contains(button1)): # selecting + this.selecting = true + this.zoomRectX1 = x + this.zoomRectY1 = y + this.darea.queueDrawArea(0, 0, this.darea.allocatedWidth, + this.darea.allocatedHeight) + elif button2 in state: # panning + this.updateAdjustmentsAndPaint(this.lastMousePosX - x, + this.lastMousePosY - y) + this.lastMousePosX = x + this.lastMousePosY = y + #event.request # request more motion events ? + +# zooming with mouse wheel -- data near mouse pointer should not move if possible! +# hadjustment.value + event.x is the position in our zoomed_in world, (userZoom / z0 - 1) +# is the relative movement caused by zooming +proc scrollEvent(darea: DrawingArea; event: EventScroll; this: PDA): bool = + let z0 = this.userZoom + var d = getScrollDirection(event) + var (x, y) = event.getCoords + if d == ScrollDirection.up: + this.userZoom *= ZOOM_FACTOR_MOUSE_WHEEL + elif d == ScrollDirection.down: + this.userZoom /= ZOOM_FACTOR_MOUSE_WHEEL + if (this.userZoom < 1): + this.userZoom = 1 + if this.zoomNearMousepointer: + this.updateAdjustmentsAndPaint((this.hadjustment.value + x) * ( + this.userZoom / z0 - 1), + (this.vadjustment.value + y) * ( + this.userZoom / z0 - 1)) + else: # zoom to center + this.updateAdjustmentsAndPaint((this.hadjustment.value + + this.darea.allocatedWidth.float * 0.5) * (this.userZoom / z0 - 1), + (this.vadjustment.value + + this.darea.allocatedHeight.float * 0.5) * ( + this.userZoom / z0 - 1)) + +proc buttonPressEvent(darea: DrawingArea; event: EventButton; + this: PDA): bool = + var (x, y) = event.getCoords + this.lastMousePosX = x + this.lastMousePosY = y + this.lastButtonDownPosX = x + this.lastButtonDownPosY = y + echo "buttonPressEvent", x, " ", y + (x, y) = this.getUserCoordinates(x, y) + echo "User coordinates: ", x, ' ', y, "\n" # to verify getUserCoordinates() + +# zoom into selected rectangle and center it +proc buttonReleaseEvent(darea: DrawingArea; event: EventButton; + this: PDA): bool = + var (x, y) = event.getCoords + var b = getButton(event) + if b == 1: + this.selecting = false + let z1 = min(this.darea.allocatedWidth.float / ( + this.lastButtonDownPosX - x).abs, this.darea.allocatedHeight.float / ( + this.lastButtonDownPosY - y).abs) + if z1 < ZOOM_FACTOR_SELECT_MAX: # else selection rectangle will persist, we may output a message... + this.userZoom *= z1 + this.updateAdjustmentsAndPaint( + ((2 * this.hadjustment.value + x + this.lastButtonDownPosX) * z1 - + this.darea.allocatedWidth.float) * 0.5 - this.hadjustment.value, + ((2 * this.vadjustment.value + y + this.lastButtonDownPosY) * z1 - + this.darea.allocatedHeight.float) * 0.5 - this.vadjustment.value) + +proc onAdjustmentEvent(this: PosAdj; pda: PDA) = + pda.paint + pda.darea.queueDrawArea(0, 0, pda.darea.allocatedWidth, + pda.darea.allocatedHeight) + +proc newPDA: PDA = + initGrid(result) + result.zoomNearMousepointer = ZOOM_NEAR_MOUSEPOINTER # mouse wheel zooming + result.selecting = false + result.userZoom = 1.0 + result.surf = nil + result.darea = newDrawingArea() + result.darea.setHExpand#(true) + result.darea.setVExpand#(true) + result.darea.connect("draw", drawingAreaDrawCb, result) + result.darea.connect("configure-event", dareaConfigureCallback, result) + result.darea.addEvents({EventFlag.buttonPress, EventFlag.buttonRelease, + EventFlag.scroll, + EventFlag.button1Motion, EventFlag.button2Motion, + EventFlag.pointerMotionHint}) + result.darea.connect("motion-notify-event", onMotion, result) + result.darea.connect("scroll_event", scrollEvent, result) + result.darea.connect("button_press_event", buttonPressEvent, result) + result.darea.connect("button_release_event", buttonReleaseEvent, result) + result.hadjustment = newPosAdj() + result.hadjustment.handlerID = result.hadjustment.connect("value-changed", + onAdjustmentEvent, result) + result.vadjustment = newPosAdj() + result.vadjustment.handlerID = result.vadjustment.connect("value-changed", + onAdjustmentEvent, result) + result.hscrollbar = newScrollbar(Orientation.horizontal, result.hadjustment) + result.vscrollbar = newScrollbar(Orientation.vertical, result.vadjustment) + result.hscrollbar.setHExpand#(true) + result.vscrollbar.setVExpand#(true) + result.attach(result.darea, 0, 0, 1, 1) + result.attach(result.vscrollbar, 1, 0, 1, 1) + result.attach(result.hscrollbar, 0, 1, 1, 1) + +proc appActivate(app: Application) = + let window = newApplicationWindow(app) + window.title = "Drawing example" + window.defaultSize = (400, 400) + let pda = newPDA() + window.add(pda) + showAll(window) + +proc main = + let app = newApplication("org.gtk.example") + connect(app, "activate", appActivate) + discard run(app) + +main() diff --git a/gintro.nimble b/gintro.nimble index 40e2cfc..396e65b 100644 --- a/gintro.nimble +++ b/gintro.nimble @@ -1,6 +1,6 @@ # Package -version = "0.4.11" +version = "0.4.12" author = "Stefan Salewski" description = "High level GObject-Introspection based GTK3 bindings" license = "MIT" diff --git a/gintro/gimpl.nim b/gintro/gimpl.nim index 02c09f8..fcd64c5 100644 --- a/gintro/gimpl.nim +++ b/gintro/gimpl.nim @@ -145,7 +145,7 @@ proc $1$2 {.cdecl.} = r1s.add(resu & "\n") all = all.replace(")", "; data: pointer)") r1s = r1s % [$procNameCdecl, all, $p, wts, ats] - echo r1s + #echo r1s result = parseStmt(r1s) if not ignoreArg.boolVal: ahl = ahl.replace(")", "; arg: " & ats & ")") @@ -175,7 +175,7 @@ proc $1(self: $2; p: proc $3; a: $4): culong {.discardable.} = sc$5(self, $6, cast[pointer](ar[])) $1($7, $8, $9) """ % [$procName, wts, ahl, ats, signalName, $procNameCdecl, $(widget.toStrLit), $p, $(arg.toStrLit)] - echo r2s + #echo r2s result.add(parseStmt(r2s)) template connect*(widget: gobject.Object; signal: string; p: typed; arg: typed): untyped = diff --git a/tests/gen.nim b/tests/gen.nim index 7557f6f..ef3becf 100644 --- a/tests/gen.nim +++ b/tests/gen.nim @@ -1,5 +1,5 @@ # High level gobject-introspection based GTK3 bindings for the Nim programming language -# v 0.4.12 2019-APR-11 +# v 0.4.12 2019-APR-14 # (c) S. Salewski 2018 # https://wiki.gnome.org/Projects/GObjectIntrospection @@ -460,6 +460,12 @@ proc genP(info: GICallableInfo; genProxy = false; binfo: GIBaseInfo = nil): (str if genProxy and (str == "string" or str == "cstring") and mayBeNil: # v0.4.11 #str.add(" = nil") str.add(" = \"\"") + if genProxy and m == 0: + if sym.contains("_set_") and str == "bool": + #echo "TTTTTTTTTT", sym + str.add(" = true") + + if genProxy and isProxyCandidate(t) and mayBeNil: #if not str.contains("|") and (gArgInfoGetDirection(arg) == GIDirection.OUT or gArgInfoGetDirection(arg) == GIDirection.INOUT): # str.add(" = cast[" & str & "](nil)") @@ -573,6 +579,15 @@ proc writeMethod(info: GIBaseInfo; minfo: GIFunctionInfo; genProxy = false) = var ret2 = gCallableInfoGetReturnType(minfo) #var ret22 = gCallableInfoGetReturnType(minfo) for run in 0 .. 1: + + #if run == 0: + # if asym.startsWith("set"): + # if gCallableInfoGetNArgs(minfo) == 1 or (gCallableInfoIsMethod(minfo) and gCallableInfoGetNArgs(minfo) == 2): + # echo "XXXXXXXXXX", asym, " ", gCallableInfoGetNArgs(minfo) + + + + if run == 1: #if not (asym != "errorQuark" and asym != "getPlugin" and asym != "quark"): continue @@ -589,6 +604,10 @@ proc writeMethod(info: GIBaseInfo; minfo: GIFunctionInfo; genProxy = false) = asym = asym[3 .. ^1] asym[0] = asym[0].toLowerAscii if asym.startsWith("set"): + #if plist.contains(" = true"): + #echo "ZZZZZZ ", plist, " ", arglist + plist = plist.replace(": bool = true", ": bool") + asym = asym[3 .. ^1] asym[0] = asym[0].toLowerAscii asym = '`' & asym & '=' & '`' @@ -601,12 +620,18 @@ proc writeMethod(info: GIBaseInfo; minfo: GIFunctionInfo; genProxy = false) = if gBaseInfoGetType(iface) == GIInfoType.Object and gBaseInfoGetName(iface) != "ParamSpec": isGObject = true (plist, arglist, replist) = genP(mInfo, true, info) + if asym[^2] == '=': + plist = plist.replace(": bool = true", ": bool") if (gFunctionInfoGetFlags(mInfo).int and GIFunctionInfoFlags.IS_CONSTRUCTOR.int) != 0: if info != nil: asym = asym.replace("new", "new" & manglename(gBaseInfoGetName(info))) if fixedProcNames.contains(sym): asym = fixedProcNames[sym] for i in 0 .. 1: + + #if i > 0 and isGObject: + # echo "XYZAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA ", asym + var hhh = "\nproc " & asym & EM & plist if i > 0: let semi = if hhh.contains("()"): "" else: "; " @@ -1401,6 +1426,237 @@ proc processInfo(i: GIBaseInfo) = writeConst(i) else: assert(false) + +# Gtk objects builder may provide. Only for Gtk module, so Gtk prefix is assume. +# Other objects loke gtkSourceView are separated! +# This a guessed list, so it may be inaccurate. +const GtkBuilderObjects = """ + +AboutDialog +AccelLabel +ActionBar +ActionGroup +Alignment +AppChooserButton +AppChooserDialog +AppChooserWidget +Application +ApplicationWindow +Arrow +AspectFrame +Assistant +Box +Builder +Button +ButtonBox +Calendar +CellAreaBox +CellView +CheckButton +CheckMenuItem +ColorButton +ColorChooserDialog +ColorChooserWidget +ColorSelectionDialog +ComboBox +ComboBoxText +Dialog +DrawingArea +Entry +EntryCompletion +EventBox +Expander +FileChooserButton +FileChooserNative +FileChooserWidget +FileFilter +Fixed +FlowBox +FontButton +FontChooserDialog +FontChooserWidget +FontSelection +FontSelectionDialog +Frame +GLArea +Grid +HandleBox +HBox +HButtonBox +HeaderBar +HPaned +HScale +HScrollbar +HSeparator +IconView +ImageMenuItem +InfoBar +Invisible +Label +Layout +LevelBar +LinkButton +ListBox +ListBoxRow +ListStore +LockButton +Menu +MenuBar +MenuButton +MenuItem +MenuToolButton +ModelButton +Notebook +OffscreenWindow +Overlay +Paned +PlacesSidebar +Popover +PopoverMenu +ProgressBar +RadioButton +RadioMenuItem +RadioToolButton +RecentChooserMenu +RecentChooserWidget +RecentManager +Revealer +Scale +ScaleButton +Scrollbar +ScrolledWindow +SearchBar +SearchEntry +Separator +SeparatorMenuItem +SeparatorToolItem +ShortcutLabel +SizeGroup +SpinButton +Spinner +Stack +StackSidebar +StackSwitcher +Statusbar +Style +Switch +Table +TearoffMenuItem +TextView +ToggleButton +ToggleToolButton +Toolbar +ToolButton +ToolItem +ToolItemGroup +ToolPalette +TreeStore +TreeView +TreeViewColumn +VBox +VButtonBox +Viewport +VolumeButton +VPaned +VScrollbar +VSeparator +Window + +""" + +const GTK_SOURCE_EPI = """ + +proc getView(builder: Builder; name: string): View = + new result + let gt = g_type_from_name("GSource") + assert(gt != 0) + result.impl = gtk_builder_get_object(cast[ptr Builder00](builder.impl), name) + assert(toBool(g_type_check_instance_is_a(cast[ptr TypeInstance00](result.impl), gt))) + +proc completionContextGetType*(): GType {.importc: "gtk_source_completion_context_get_type", libprag.} + +proc completionProviderGetType*(): GType {.importc: "gtk_source_completion_provider_get_type", libprag.} + +proc completionWordsGetType*(): GType {.importc: "gtk_source_completion_words_get_type", libprag.} + +proc bufferGetType*(): GType {.importc: "gtk_source_buffer_get_type", libprag.} + +proc completionGetType*(): GType {.importc: "gtk_source_completion_get_type", libprag.} + +proc completionInfoGetType*(): GType {.importc: "gtk_source_completion_info_get_type", libprag.} + +proc completionItemGetType*(): GType {.importc: "gtk_source_completion_item_get_type", libprag.} + +proc completionProposalGetType*(): GType {.importc: "gtk_source_completion_proposal_get_type", libprag.} + +proc encodingGetType*(): GType {.importc: "gtk_source_encoding_get_type", libprag.} + +proc fileGetType*(): GType {.importc: "gtk_source_file_get_type", libprag.} + +proc fileLoaderGetType*(): GType {.importc: "gtk_source_file_loader_get_type", libprag.} + +proc fileSaverGetType*(): GType {.importc: "gtk_source_file_saver_get_type", libprag.} + +proc gutterGetType*(): GType {.importc: "gtk_source_gutter_get_type", libprag.} + +proc gutterRendererGetType*(): GType {.importc: "gtk_source_gutter_renderer_get_type", libprag.} + +proc gutterRendererTextGetType*(): GType {.importc: "gtk_source_gutter_renderer_text_get_type", libprag.} + +proc gutterRendererPixbufGetType*(): GType {.importc: "gtk_source_gutter_renderer_pixbuf_get_type", libprag.} + +proc languageGetType*(): GType {.importc: "gtk_source_language_get_type", libprag.} + +proc languageManagerGetType*(): GType {.importc: "gtk_source_language_manager_get_type", libprag.} + +proc viewGetType*(): GType {.importc: "gtk_source_view_get_type", libprag.} + +proc mapGetType*(): GType {.importc: "gtk_source_map_get_type", libprag.} + +proc markGetType*(): GType {.importc: "gtk_source_mark_get_type", libprag.} + +proc markAttributesGetType*(): GType {.importc: "gtk_source_mark_attributes_get_type", libprag.} + +proc printCompositorGetType*(): GType {.importc: "gtk_source_print_compositor_get_type", libprag.} + +proc regionGetType*(): GType {.importc: "gtk_source_region_get_type", libprag.} + +proc searchContextGetType*(): GType {.importc: "gtk_source_search_context_get_type", libprag.} + +proc searchSettingsGetType*(): GType {.importc: "gtk_source_search_settings_get_type", libprag.} + +proc spaceDrawerGetType*(): GType {.importc: "gtk_source_space_drawer_get_type", libprag.} + +proc styleGetType*(): GType {.importc: "gtk_source_style_get_type", libprag.} + +proc styleSchemeGetType*(): GType {.importc: "gtk_source_style_scheme_get_type", libprag.} + +proc styleSchemeChooserGetType*(): GType {.importc: "gtk_source_style_scheme_chooser_get_type", libprag.} + +proc styleSchemeChooserButtonGetType*(): GType {.importc: "gtk_source_style_scheme_chooser_button_get_type", libprag.} + +proc styleSchemeChooserWidgetGetType*(): GType {.importc: "gtk_source_style_scheme_chooser_widget_get_type", libprag.} + +proc styleSchemeManagerGetType*(): GType {.importc: "gtk_source_style_scheme_manager_get_type", libprag.} + +proc tagGetType*(): GType {.importc: "gtk_source_tag_get_type", libprag.} + +proc undoManagerGetType*(): GType {.importc: "gtk_source_undo_manager_get_type", libprag.} + +proc completionWordsProposalGetType*(): GType {.importc: "gtk_source_completion_words_proposal_get_type", libprag.} + +proc completionWordsLibraryGetType*(): GType {.importc: "gtk_source_completion_words_library_get_type", libprag.} + +proc completionWordsBufferGetType*(): GType {.importc: "gtk_source_completion_words_buffer_get_type", libprag.} + +# register the GObject types so builder can use them, see +# https://mail.gnome.org/archives/gtk-list/2015-March/msg00016.html +discard viewGetType() +discard completionInfoGetType() +discard styleSchemeChooserButtonGetType() + +""" + const GDK_EPI = """ proc gdk_window_invalidate_nilrect(self: ptr Window00; rect: ptr Rectangle; invalidateChildren: gboolean) {. @@ -1419,6 +1675,60 @@ proc fixednewCursorFromName*(display: Display; name: string): Cursor = #assert(g_object_get_qdata(result.impl, Quark) == nil) g_object_set_qdata(result.impl, Quark, addr(result[])) +proc getAngle*(self: SomeEvent; event2: SomeEvent): cdouble = + if not toBool(gdk_events_get_angle(cast[ptr Event00](self.impl), cast[ptr Event00](event2.impl), result)): + raise newException(Defect, "Events do not support getAngle().") + +proc getCenter*(self: SomeEvent; event2: SomeEvent): (cdouble, cdouble) = + if not toBool(gdk_events_get_center(cast[ptr Event00](self.impl), cast[ptr Event00](event2.impl), result[0], result[1])): + raise newException(Defect, "Events do not support getCenter().") + +proc getDistance*(self: SomeEvent; event2: SomeEvent): cdouble = + if not toBool(gdk_events_get_distance(cast[ptr Event00](self.impl), cast[ptr Event00](event2.impl), result)): + raise newException(Defect, "Events do not support getDistance().") + +proc getAxis*(self: SomeEvent; axisUse: AxisUse): cdouble = + if not toBool(gdk_event_get_axis(cast[ptr Event00](self.impl), axisUse, result)): + raise newException(Defect, "Event does not support getAxis().") + +proc getButton*(self: SomeEvent): int = + var button: uint32 + if not toBool(gdk_event_get_button(cast[ptr Event00](self.impl), button)): + raise newException(Defect, "Event don't has a button field.") + return int(button) + +proc getClickCount*(self: SomeEvent): int = + var clickCount_00: uint32 + if not toBool(gdk_event_get_click_count(cast[ptr Event00](self.impl), clickCount_00)): + raise newException(Defect, "Event does not support getClickCount().") + return int(clickCount_00) + +proc getCoords*(self: SomeEvent): (cdouble, cdouble) = + if not toBool(gdk_event_get_coords(cast[ptr Event00](self.impl), result[0], result[1])): + raise newException(Defect, "This event don't has a coordinate field.") + +proc getKeyval*(self: SomeEvent): int = + var keyval_00 = uint32 + if not toBool(gdk_event_get_keyval(cast[ptr Event00](self.impl), keyval_00)): + raise newException(Defect, "This event don't has a keyval field.") + return int(keyval_00) + +proc getRootCoords*(self: SomeEvent): (cdouble, cdouble) = + if not toBool(gdk_event_get_root_coords(cast[ptr Event00](self.impl), result[0], result[1])): + raise newException(Defect, "This event don't has a rootCoordinate field.") + +proc getScrollDeltas*(self: SomeEvent): (cdouble, cdouble) = + if not toBool(gdk_event_get_scroll_deltas(cast[ptr Event00](self.impl), result[0], result[1])): + raise newException(Defect, "This event don't has a scrollDeltas field.") + +proc getScrollDirection*(self: SomeEvent): ScrollDirection = + if not toBool(gdk_event_get_scroll_direction(cast[ptr Event00](self.impl), result)): + raise newException(Defect, "Event don't has a scrollDirection field.") + +proc getState*(self: SomeEvent): ModifierType = + if not toBool(gdk_event_get_state(cast[ptr Event00](self.impl), result)): + raise newException(Defect, "Event don't has a state field.") + """ const GIO_EPI = """ @@ -1801,12 +2111,28 @@ proc main(namespace: string) = if namespace == "Gtk": output.write(GTK_EPI) + for i in GtkBuilderObjects.split: + if i == "": continue + output.write(""" +proc get$1*(builder: Builder; name: string): $1 = + new result + let gt = g_type_from_name("Gtk$1") + assert(gt != 0) + result.impl = gtk_builder_get_object(cast[ptr Builder00](builder.impl), name) + assert(toBool(g_type_check_instance_is_a(cast[ptr TypeInstance00](result.impl), gt))) + +""" % [i]) + output.write("") + if namespace == "Gio": output.write(GIO_EPI) if namespace == "Gdk": output.write(GDK_EPI) + if namespace == "GtkSource": + output.write(GTK_SOURCE_EPI) + output.flush var o = open("nim_gi" / (namespace.toLowerAscii) & ".nim", fmWrite) o.write(output.data)