Cocoa in Racket
Racket provides Objective-C bindings, so the best part here is that we
can use Cocoa in Racket to build a GUI. In fact, racket/gui
on macOS
is based on Cocoa. The following program is relied on some works in
dannypsnl/cocoa.
1. Fundamental
we can use
import-class
to get class from Objective-C.(require ffi/unsafe ffi/unsafe/objc) (import-class NSColor NSBezierPath NSWindow NSApplication NSRect NSView)
we have to disable signal handler
((get-ffi-obj 'signal #f (_fun _int _intptr -> _void)) 2 0)
we setup
app
for global handle, and usecall-with-autorelease
to run main program with autorelease pool.(define app #f) (call-with-autorelease (lambda () (define frame (make-NSRect (make-NSPoint 300 300) (make-NSSize 400 400))) (define mainView (tell (tell MyView alloc) initWithFrame: #:type _NSRect frame)) (set! app (tell NSApplication sharedApplication)) (define win (tell (tell NSWindow alloc) initWithContentRect: #:type _NSRect frame styleMask: #:type _int NSWindowStyleMaskTitled backing: #:type _int NSBackingStoreBuffered defer: NO)) (tell win setTitle: #:type _NSString "test") (tell win setContentView: #:type _id mainView) (tell win makeKeyAndOrderFront: #f) (tell app run)))
2. Example
Finally, we define MyView
by define-objc-class
, this form helps us
define an Objective-C class.
#lang racket/base (require racket/math) (define-cpointer-type _NSNotification) (define-cocoa NSRectFill (_fun _id -> _void)) (define-objc-class MyView NSView () (- _void (drawRect: [_NSRect rect]) (define n 12) (define width 400) (define height 400) (tell (tell NSColor whiteColor) set) (NSRectFill (tell self bounds)) (tell (tell NSColor blackColor) set) (define (x t) (* (add1 (sin t)) width 0.5)) (define (y t) (* (add1 (cos t)) height 0.5)) (for ([f (in-range 0 (* 2 pi) (/ (* 2 pi) n))]) (for ([g (in-range 0 (* 2 pi) (/ (* 2 pi) n))]) (define p1 (make-NSPoint (x f) (y f))) (define p2 (make-NSPoint (x g) (y g))) (tell NSBezierPath strokeLineFromPoint: #:type _NSPoint p1 toPoint: #:type _NSPoint p2)))) (- _void (windowWillClose: [_NSNotification notification]) (tell app terminate: #:type _id self)))