forked from franzinc/clim2
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathclim-macros.lisp
122 lines (107 loc) · 5.71 KB
/
clim-macros.lisp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
;;; -*- Mode: Lisp; Syntax: ANSI-Common-Lisp; Package: CLIM-UTILS; Base: 10; Lowercase: Yes -*-
;; See the file LICENSE for the full license governing this code.
;;
(in-package :clim-utils)
;;;"Copyright (c) 1990, 1991, 1992 Symbolics, Inc. All rights reserved.
;;; Portions copyright (c) 1988, 1989, 1990 International Lisp Associates."
(defmacro default-output-stream (stream &optional must-be-variable-macro-name)
`(cond ((member ,stream '(t nil))
(setq ,stream '*standard-output*))
,@(when must-be-variable-macro-name
`(((not (and (symbolp ,stream)
(not (keywordp ,stream))))
(warn "The stream argument to ~S, ~S, is invalid.~@
This argument must be a variable that can be bound to a new stream."
',must-be-variable-macro-name ,stream)
(setq ,stream '*standard-output*))))))
(defmacro default-input-stream (stream &optional must-be-variable-macro-name)
`(cond ((member ,stream '(t nil))
(setq ,stream '*standard-input*))
,@(when must-be-variable-macro-name
`(((not (and (symbolp ,stream)
(not (keywordp ,stream))))
(warn "The stream argument to ~S, ~S, is invalid.~@
This argument must be a variable that can be bound to a new stream."
',must-be-variable-macro-name ,stream)
(setq ,stream '*standard-input*))))))
(defmacro default-query-stream (stream &optional must-be-variable-macro-name)
`(cond ((member ,stream '(t nil))
(setq ,stream '*query-io*))
,@(when must-be-variable-macro-name
`(((not (and (symbolp ,stream)
(not (keywordp ,stream))))
(warn "The stream argument to ~S, ~S, is invalid.~@
This argument must be a variable that can be bound to a new stream."
',must-be-variable-macro-name ,stream)
(setq ,stream '*query-io*))))))
;;; Drawing state macros
(defmacro with-clipping-region ((stream region) &body body)
(default-output-stream stream with-clipping-region)
`(flet ((with-clipping-region-body (,stream) ,@body))
(declare (dynamic-extent #'with-clipping-region-body))
(invoke-with-clipping-region ,stream #'with-clipping-region-body ,region)))
(defmacro with-drawing-options ((medium &rest options) &body body)
(declare (arglist (medium
&key ink clipping-region transformation
line-style line-unit line-thickness line-dashes
line-joint-shape line-cap-shape
text-style text-family text-face text-size)))
#+Genera (declare (zwei:indentation 0 3 1 1))
(default-output-stream medium)
`(flet ((with-drawing-options-body () ,@body))
(declare (dynamic-extent #'with-drawing-options-body))
(invoke-with-drawing-options ,medium #'with-drawing-options-body ,@options)))
(defmacro with-identity-transformation ((medium) &body body)
`(letf-globally (((medium-transformation ,medium) +identity-transformation+))
,@body))
(defmacro with-translation ((medium dx dy) &body body)
`(with-drawing-options (,medium
:transformation (make-translation-transformation ,dx ,dy))
,@body))
(defmacro with-scaling ((medium sx &optional (sy nil sy-p)) &body body)
`(with-drawing-options (,medium
:transformation (let* ((scale-x ,sx)
(scale-y ,(if sy-p sy 'scale-x)))
(make-scaling-transformation scale-x scale-y)))
,@body))
(defmacro with-rotation ((medium angle &optional (origin nil origin-p)) &body body)
`(with-drawing-options (,medium
:transformation (make-rotation-transformation ,angle
,@(if origin-p `(,origin) nil)))
,@body))
;; Establish a local +Y-downward coordinate system at the current cursor position,
;; and execute the body
(defmacro with-local-coordinates ((&optional stream x y) &body body)
(default-output-stream stream with-local-coordinates)
(let ((cx '#:cx) (cy '#:cy)
(tx '#:tx) (ty '#:ty))
`(let ((,cx ,x)
(,cy ,y))
(unless (and ,cx ,cy)
(multiple-value-setq (,cx ,cy) (stream-cursor-position ,stream)))
(multiple-value-bind (,tx ,ty)
(transform-position (medium-transformation ,stream) 0 0)
(with-drawing-options
(,stream :transformation (make-translation-transformation
(- ,cx ,tx) (- ,cy ,ty)))
,@body)))))
;; Establish a local +Y-upward coordinate system at the current cursor position,
;; and execute the body
(defmacro with-first-quadrant-coordinates ((&optional stream x y) &body body)
(default-output-stream stream with-first-quadrant-coordinates)
(let ((cx '#:cx) (cy '#:cy)
(tx '#:tx) (ty '#:ty))
`(let ((,cx ,x)
(,cy ,y))
(unless (and ,cx ,cy)
(multiple-value-setq (,cx ,cy) (stream-cursor-position ,stream)))
(multiple-value-bind (,tx ,ty)
(transform-position (medium-transformation ,stream) 0 0)
(with-drawing-options
;; Don't flip the stream over if we already have
(,stream :transformation (if (silica:medium-+y-upward-p ,stream)
+identity-transformation+
(make-transformation 1 0 0 -1
(- ,cx ,tx) (- ,cy ,ty))))
(letf-globally (((silica:medium-+y-upward-p ,stream) t))
,@body))))))