| [7325] | 1 | (in-package :easygui)
|
|---|
| 2 |
|
|---|
| [7353] | 3 | ;;; Helper types:
|
|---|
| 4 |
|
|---|
| [7499] | 5 | ;;; point:
|
|---|
| [7325] | 6 | (defclass eg-point ()
|
|---|
| 7 | ((x :initarg :x :reader point-x)
|
|---|
| 8 | (y :initarg :y :reader point-y)))
|
|---|
| 9 |
|
|---|
| 10 | (defun point (x y)
|
|---|
| 11 | (assert (>= x 0))
|
|---|
| 12 | (assert (>= y 0))
|
|---|
| 13 | (make-instance 'eg-point :x x :y y))
|
|---|
| 14 |
|
|---|
| [7499] | 15 | (defmethod print-object ((o eg-point) s)
|
|---|
| 16 | (print-unreadable-object (o s :identity nil :type t)
|
|---|
| 17 | (format s "(~,2,F/~,2,F)" (point-x o) (point-y o))))
|
|---|
| 18 |
|
|---|
| 19 | ;;; range:
|
|---|
| [7347] | 20 | (defclass eg-range ()
|
|---|
| 21 | ((start :initarg :start :reader range-start)
|
|---|
| 22 | (end :initarg :end :reader range-end)))
|
|---|
| 23 |
|
|---|
| 24 | (defun range (start end)
|
|---|
| 25 | (assert (>= end start))
|
|---|
| 26 | (make-instance 'eg-range :start start :end end))
|
|---|
| 27 |
|
|---|
| 28 | (defun range-nsrange (range)
|
|---|
| 29 | (ns:make-ns-range (range-start range) (range-end range)))
|
|---|
| 30 |
|
|---|
| [7353] | 31 | (defclass eg-rectangle ()
|
|---|
| 32 | ((x :initarg :x :reader rectangle-x)
|
|---|
| 33 | (y :initarg :y :reader rectangle-y)
|
|---|
| 34 | (width :initarg :width :reader rectangle-width)
|
|---|
| 35 | (height :initarg :height :reader rectangle-height)))
|
|---|
| 36 |
|
|---|
| 37 | (defun rectangle (x y width height)
|
|---|
| 38 | (assert (>= x 0))
|
|---|
| 39 | (assert (>= y 0))
|
|---|
| 40 | (assert (>= width 0))
|
|---|
| 41 | (assert (>= height 0))
|
|---|
| 42 | (make-instance 'eg-rectangle :x x :y y :width width :height height))
|
|---|
| 43 |
|
|---|
| 44 | (defun rectangle-nsrect (r)
|
|---|
| 45 | (ns:make-ns-rect (rectangle-x r) (rectangle-y r)
|
|---|
| 46 | (rectangle-width r) (rectangle-height r)))
|
|---|
| 47 |
|
|---|
| 48 | (defun nsrect-rectangle (r)
|
|---|
| 49 | (rectangle (ns:ns-rect-x r) (ns:ns-rect-y r)
|
|---|
| 50 | (ns:ns-rect-width r) (ns:ns-rect-height r)))
|
|---|
| 51 |
|
|---|
| [7802] | 52 | ;;; Base class for all Cocoa-based Easygui objects:
|
|---|
| [7325] | 53 | (defclass easy-cocoa-object ()
|
|---|
| [7802] | 54 | ((ref :initarg :cocoa-ref)
|
|---|
| 55 | (ref-valid-p :initform t :accessor cocoa-ref-valid-p)))
|
|---|
| [7325] | 56 |
|
|---|
| [7802] | 57 | (defgeneric cocoa-ref (eg-object)
|
|---|
| 58 | (:method ((eg-object easy-cocoa-object))
|
|---|
| 59 | (if (cocoa-ref-valid-p eg-object)
|
|---|
| 60 | (slot-value eg-object 'ref)
|
|---|
| 61 | (error "Attempting to access an invalidated Cocoa object on ~A!"
|
|---|
| 62 | eg-object))))
|
|---|
| 63 |
|
|---|
| 64 | (defgeneric (setf cocoa-ref) (new eg-object)
|
|---|
| 65 | (:method (new (eg-object easy-cocoa-object))
|
|---|
| 66 | (setf (cocoa-ref-valid-p eg-object) t
|
|---|
| 67 | (slot-value eg-object 'ref) new)))
|
|---|
| 68 |
|
|---|
| [7325] | 69 | (defvar *window-position-default-x* 200)
|
|---|
| 70 | (defvar *window-position-default-y* 200)
|
|---|
| 71 | (defvar *window-size-default-x* 200)
|
|---|
| 72 | (defvar *window-size-default-y* 200)
|
|---|
| 73 |
|
|---|
| 74 | (defun ns-rect-from-points (posn size)
|
|---|
| 75 | (ns:make-ns-rect (point-x posn) (point-y posn)
|
|---|
| 76 | (point-x size) (point-y size)))
|
|---|
| 77 |
|
|---|
| 78 | (defparameter *flag-to-mask-alist*
|
|---|
| 79 | `( ;; (:zoomable-p . #$NSZoomableWindowMask) ; doesn't work
|
|---|
| 80 | (:minimizable-p . ,#$NSMiniaturizableWindowMask)
|
|---|
| 81 | (:resizable-p . ,#$NSResizableWindowMask)
|
|---|
| 82 | (:closable-p . ,#$NSClosableWindowMask)))
|
|---|
| 83 |
|
|---|
| 84 | (defun flag-mask (keyword enabled-p)
|
|---|
| 85 | (if enabled-p
|
|---|
| 86 | (or (cdr (assoc keyword *flag-to-mask-alist*)) 0)
|
|---|
| 87 | 0))
|
|---|
| 88 |
|
|---|
| 89 | (defparameter *key-to-mask-alist*
|
|---|
| 90 | `((:control . ,#$NSControlKeyMask)
|
|---|
| 91 | (:alt . ,#$NSAlternateKeyMask)
|
|---|
| 92 | (:command . ,#$NSCommandKeyMask)))
|
|---|
| 93 |
|
|---|
| 94 | (defun key-mask (keyword)
|
|---|
| 95 | (or (cdr (assoc keyword *key-to-mask-alist*)) 0))
|
|---|
| 96 |
|
|---|
| [7802] | 97 | ;;; Memory management helpers:
|
|---|
| 98 |
|
|---|
| 99 | (defmacro maybe-invalidating-object ((eg-object) &body body)
|
|---|
| 100 | `(if (= 1 (#/retainCount (cocoa-ref ,eg-object)))
|
|---|
| 101 | (multiple-value-prog1 (progn ,@body)
|
|---|
| 102 | (setf (cocoa-ref-valid-p ,eg-object) nil))
|
|---|
| 103 | (progn ,@body)))
|
|---|
| 104 |
|
|---|
| 105 | (defmethod retain-object ((o easy-cocoa-object))
|
|---|
| 106 | (#/retain (cocoa-ref o)))
|
|---|
| 107 |
|
|---|
| 108 | (defmethod release-object ((o easy-cocoa-object))
|
|---|
| 109 | (#/release (cocoa-ref o)))
|
|---|
| 110 |
|
|---|
| 111 | (defmacro retaining-objects ((&rest eg-objects) &body body)
|
|---|
| 112 | "Retains EG-OBJECTS, runs BODY forms and releases them after control
|
|---|
| 113 | has left BODY."
|
|---|
| 114 | (let ((objects (gensym)))
|
|---|
| 115 | `(let ((,objects (list ,@eg-objects)))
|
|---|
| 116 | (mapc #'retain-object ,objects)
|
|---|
| 117 | (unwind-protect (progn ,@body)
|
|---|
| 118 | (mapc #'release-object ,objects)))))
|
|---|
| 119 |
|
|---|
| [7325] | 120 | ;;; debug macro for #/ funcalls:
|
|---|
| 121 |
|
|---|
| [11845] | 122 | (defvar *debug-cocoa-calls* nil)
|
|---|
| 123 | ;; Default changed to NIL by arthur, March 2009
|
|---|
| [7325] | 124 |
|
|---|
| [11845] | 125 | (defparameter *cocoa-pause* nil
|
|---|
| 126 | "When *debug-cocoa-calls* is not NIL, then a numeric value of *cocoa-pause* causes
|
|---|
| 127 | some sleep after every message produced by the DCC macro. Useful if something is
|
|---|
| 128 | causing a crash. During development it happened to me :-(")
|
|---|
| 129 |
|
|---|
| [7325] | 130 | (defmacro dcc (form)
|
|---|
| [11845] | 131 | ;; Trace output identifies process, and may pause: arthur, March 2009
|
|---|
| [7325] | 132 | `(progn
|
|---|
| 133 | (when *debug-cocoa-calls*
|
|---|
| [11845] | 134 | (format *trace-output* "[~a]Calling ~A on ~S~%"
|
|---|
| 135 | (ccl::process-serial-number ccl::*current-process*) ',(first form) (list ,@(rest form)))
|
|---|
| 136 | (when (and *cocoa-pause* (numberp *cocoa-pause*)) (sleep *cocoa-pause*)))
|
|---|
| [7325] | 137 | ,form))
|
|---|
| 138 |
|
|---|
| 139 | ;;; Running things on the main thread:
|
|---|
| 140 |
|
|---|
| 141 | (defclass cocoa-thunk (ns:ns-object)
|
|---|
| 142 | ((thunk :accessor thunk-of))
|
|---|
| 143 | (:metaclass ns:+ns-object))
|
|---|
| 144 |
|
|---|
| 145 | (objc:defmethod (#/run :void) ((self cocoa-thunk))
|
|---|
| 146 | (funcall (thunk-of self)))
|
|---|
| 147 |
|
|---|
| 148 | (defun run-on-main-thread (waitp thunk)
|
|---|
| 149 | (let ((thunk* (make-instance 'cocoa-thunk)))
|
|---|
| 150 | (setf (thunk-of thunk*) thunk)
|
|---|
| 151 | (#/performSelectorOnMainThread:withObject:waitUntilDone:
|
|---|
| 152 | thunk*
|
|---|
| 153 | (@selector #/run)
|
|---|
| 154 | +null-ptr+
|
|---|
| 155 | (not (not waitp)))))
|
|---|
| 156 |
|
|---|
| 157 | (defmacro running-on-main-thread ((&key (waitp t)) &body body)
|
|---|
| [7499] | 158 | `(run-on-main-thread ,waitp (lambda () ,@body)))
|
|---|
| 159 |
|
|---|
| 160 | ;;; Getting views from objc objects:
|
|---|
| 161 |
|
|---|
| [7802] | 162 | (defgeneric easygui-view-of (cocoa-view))
|
|---|