This is a repost from github, but I'd be glad for some insight.
Every time I try to compile my nim program I get the same error. Invalid type: 'proc' in this context 'proc (ui: NimUI, btn: Button)' for proc
I'm trying to implement a simple ui in Nim with sdl2.
Button is an reference object with a field 'action: proc' that is set to a callback proc testOut() during initialization (it just does a simple echo).
The line that the error occurs on is..
handleInput*(ui: NimUI, btn: Button) =
I made the equivalent work for callback types NOT embedded in objects, just not for variables stored on reference objects. I tried using {.closure.} and {.cdecl.} but I'm not 100% on if I'm using those correctly. I've also tried setting the return type.
Everything works if I remove the callback from the type and initialization procedure of button.
Read the docs and I see that I should be using maybe {.cdecl.} or {.procvar.} but I tried both. Docs say to amend the actual procedure I'm passing, but I tried that too, no dice. Didn't add a return type because I'm not returning anything. testOut just to test passing procedures for callbacks.
in testsdl.nim (just using it to stub main() to get everything started)
import nimui
proc main() =
newNimUI("Nimrod UI", 0, 0, 1280, 720)
main()
in nimui.nim
import sdl2
type
SDLException* = object of Exception
Input {.pure.} = enum none, quit
Game = ref object
inputs: array[Input, bool]
renderer: RendererPtr
Element = ref object of RootObj
rect: Rect
NimUI = ref object
title: cstring
x, y, w, h: cint
window: WindowPtr
renderer: RendererPtr
inputs: array[Input, bool]
children: ref seq[Element]
Button = ref object of Element
clicked: bool
hovered: bool
clickAction: proc #problem line
proc testOut() =
echo("onClick triggered!")
discard
proc newGame(renderer: RendererPtr): Game =
new result
result.renderer = renderer
template sdlFailIf*(cond: typed, reason: string) =
if cond: raise SDLException.newException(reason & ", SDL error: " & $getError())
proc toInput(key: Scancode): Input =
case key
of SDL_SCANCODE_Q: Input.quit
else: Input.none
#but here is where the actual issue occurs according to the command line
proc getInput*(ui: NimUI, btn: Button) =
var event = defaultEvent
var xmouse:cint = 0
var ymouse:cint = 0
while pollEvent(event):
case event.kind
of QuitEvent:
ui.inputs[Input.quit] = true
btn.clicked = true
of MouseMotion:
xmouse = event.motion.x
ymouse = event.motion.y
#check if mouse is within the bounding box of the button
if xmouse >= btn.rect.x and xmouse <= btn.rect.x+btn.rect.w and ymouse >= btn.rect.y and ymouse <= btn.rect.y+btn.rect.h:
btn.hovered = true
else:
btn.hovered = false
of MouseButtonDown:
btn.clicked = true
ui.inputs[Input.quit] = true
else:
discard
proc newButton*(x, y, w, h: cint, onclick: proc()): Button =
new(result)
result.clicked = false
result.hovered = false
result.rect = (x, y, w, h)
result.clickAction = onclick
return result
proc render(ui: NimUI, el: Element) =
ui.renderer.setDrawColor(r = 110, g = 132, b = 174) #reset draw color
ui.renderer.clear()
ui.renderer.setDrawColor(r=128, g=128, b=128)
ui.renderer.fillRect(el.rect)
# Show the result on screen
ui.renderer.present()
proc newNimUI*(title: cstring, x, y, w, h: cint) =
var ui = new(NimUI)
ui.title = title
ui.x = x
ui.y = y
ui.w = w
ui.h = h
sdlFailIf(not sdl2.init(INIT_VIDEO or INIT_TIMER or INIT_EVENTS)):
"SDL2 initialization failed"
# defer blocks get called at the end of the procedure, even if an
# exception has been thrown
defer: sdl2.quit()
sdlFailIf(not setHint("SDL_RENDER_SCALE_QUALITY", "2")):
"Linear texture filtering could not be enabled"
ui.window = createWindow(title = title,
x = SDL_WINDOWPOS_CENTERED, y = SDL_WINDOWPOS_CENTERED,
w = w, h = h, flags = SDL_WINDOW_SHOWN)
sdlFailIf ui.window.isNil: "Window could not be created"
defer: ui.window.destroy()
ui.renderer = ui.window.createRenderer(index = -1,
flags = Renderer_Accelerated or Renderer_PresentVsync)
sdlFailIf ui.renderer.isNil: "Renderer could not be created"
defer: ui.renderer.destroy()
# Set the default color to use for drawing
ui.renderer.setDrawColor(r = 110, g = 132, b = 174)
var btn = newButton(64, 64, 196, 64, testOut)
while not ui.inputs[Input.quit]:
ui.boxGetInput(btn)
ui.render(btn)
Gratitude to anyone that can grant some insight into what I'm doing wrong here.
Wow, I really over thought that. Made the change you recommended and it compiles without error.
For the record, whats the difference between a procedural type and a proc type class?
Araq, thanks again for the help.