PageRenderTime 49ms CodeModel.GetById 24ms RepoModel.GetById 0ms app.codeStats 1ms

/src/transpbuttons.sc

https://bitbucket.org/bunny351/ezd
Scala | 553 lines | 505 code | 48 blank | 0 comment | 5 complexity | 2c7d01252f5044af9700bc931ed570f0 MD5 | raw file
  1. ;;; ezd - easy drawing for X11 displays.
  2. ;;;
  3. ;;; Transparent buttons.
  4. ;* Copyright 1993 Digital Equipment Corporation
  5. ;* All Rights Reserved
  6. ;*
  7. ;* Permission to use, copy, and modify this software and its documentation is
  8. ;* hereby granted only under the following terms and conditions. Both the
  9. ;* above copyright notice and this permission notice must appear in all copies
  10. ;* of the software, derivative works or modified versions, and any portions
  11. ;* thereof, and both notices must appear in supporting documentation.
  12. ;*
  13. ;* Users of this software agree to the terms and conditions set forth herein,
  14. ;* and hereby grant back to Digital a non-exclusive, unrestricted, royalty-free
  15. ;* right and license under any changes, enhancements or extensions made to the
  16. ;* core functions of the software, including but not limited to those affording
  17. ;* compatibility with other hardware or software environments, but excluding
  18. ;* applications which incorporate this software. Users further agree to use
  19. ;* their best efforts to return to Digital any such changes, enhancements or
  20. ;* extensions that they make and inform Digital of noteworthy uses of this
  21. ;* software. Correspondence should be provided to Digital at:
  22. ;*
  23. ;* Director of Licensing
  24. ;* Western Research Laboratory
  25. ;* Digital Equipment Corporation
  26. ;* 250 University Avenue
  27. ;* Palo Alto, California 94301
  28. ;*
  29. ;* This software may be distributed (but not offered for sale or transferred
  30. ;* for compensation) to third parties, provided such third parties agree to
  31. ;* abide by the terms and conditions of this notice.
  32. ;*
  33. ;* THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
  34. ;* WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF
  35. ;* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT
  36. ;* CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
  37. ;* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
  38. ;* PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
  39. ;* ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
  40. ;* SOFTWARE.
  41. (module transpbuttons)
  42. (include "commands.sch")
  43. (include "ginfo.sch")
  44. (include "interact.sch")
  45. (include "events.sch")
  46. (include "match.sch")
  47. (include "ezd.sch")
  48. ;;; The TRANSPARENT-CHECK-BUTTON command makes a "transparent" check button in
  49. ;;; the current drawing. The button is a circle drawn in the foreground color
  50. ;;; (default is black) that is filled with the clear when the value is false,
  51. ;;; or the foreground color when the value is true. The button text is
  52. ;;; written to the right of the button in the foreground color and the
  53. ;;; indicated font (default is the default X font).
  54. ;;;
  55. ;;; When the mouse is not in either the button, or a member of its button set,
  56. ;;; the button is "transparent", i.e. drawn with a stipple. When the mouse is
  57. ;;; in the button or a member of its button set, the buttons are drawn solid.
  58. ;;; When the button is drawn solid, the background color (default is white) is
  59. ;;; used make the button more visible.
  60. ;;;
  61. ;;; The button's value is complemented by clicking the mouse using button 1
  62. ;;; within either the circle or the button text. The button action is taken
  63. ;;; when the button comes up.
  64. ;;;
  65. ;;; If the button is a member of a radio button set, then clicking on it when
  66. ;;; it is set will have no effect. Clicking an unset button will set it and
  67. ;;; clear the set value.
  68. ;;;
  69. ;;; Button information can be accessed via the following attributes.
  70. ;;;
  71. ;;; X
  72. ;;; Y
  73. ;;; WIDTH
  74. ;;; HEIGHT
  75. ;;; ACTION
  76. ;;; TEXT
  77. ;;; FONT
  78. ;;; FOREGROUND
  79. ;;; BACKGROUND
  80. ;;; TRANSPARENT
  81. ;;; VALUE
  82. ;;; RADIO-BUTTON-SET
  83. ;;; BUTTON-SET
  84. ;;;
  85. ;;; ATTRIBUTES
  86. ;;; DELETE-OBJECT
  87. (define (MAKE-TRANSPARENT-CHECK-BUTTON button-name x y width height text
  88. value action opt-foreground opt-background font)
  89. (define FOREGROUND (or opt-foreground 'black))
  90. (define BACKGROUND (or opt-background 'white))
  91. (define DY 2)
  92. (define RADIO-BUTTON-SET '())
  93. (define BUTTON-SET (list button-name))
  94. (define DRAWING-NAME (current-drawing-name))
  95. (define TRANSPARENT #t)
  96. (define READY #f)
  97. (define (ENTER)
  98. (if transparent
  99. (for-each
  100. (lambda (button)
  101. (set-attributes drawing-name button
  102. '(transparent #f)))
  103. button-set)))
  104. (define (EXIT)
  105. (when ready
  106. (set! value (not value))
  107. (set! ready #f)
  108. (draw-button))
  109. (if (or (not (eq? (cadr *user-event-misc*) drawing-name))
  110. (not (memq (caddr *user-event-misc*) button-set)))
  111. (for-each
  112. (lambda (button)
  113. (set-attributes drawing-name button
  114. '(transparent #t)))
  115. button-set)))
  116. (define (BUTTON-DOWN)
  117. (unless (and value (pair? radio-button-set))
  118. (set! ready #t)
  119. (set! value (not value))
  120. (draw-button)))
  121. (define (BUTTON-UP)
  122. (if ready
  123. (let ((drawing *user-event-drawing*))
  124. (set! ready #f)
  125. (ezd '(draw-now))
  126. (set! *user-event-misc* (list value))
  127. (if (procedure? action) (action) (eval action))
  128. (for-each
  129. (lambda (button)
  130. (if (not (eq? button button-name))
  131. (set-attributes drawing button
  132. '(value #f))))
  133. radio-button-set))
  134. (draw-button)))
  135. (define (MOVE-BUTTONS)
  136. (move-transparent-button-set *user-event-drawing* button-set
  137. *user-event-x* *user-event-y*))
  138. (define (DRAW-BUTTON)
  139. (ezd '(save-drawing)
  140. `(set-drawing ,drawing-name)
  141. `(object ,button-name
  142. (fill-rectangle ,x ,y ,width ,height
  143. ,@(if transparent '(clear) `(,background s8b)))
  144. (fill-arc ,x ,y ,(- height dy dy)
  145. ,(- height dy dy) 0 360
  146. ,(if value foreground 'clear)
  147. ,(if transparent 's2 's8b))
  148. (arc ,x ,y ,(- height dy dy) ,(- height dy dy)
  149. 0 360
  150. ,(if transparent 'clear foreground)
  151. dash)
  152. (text ,(+ x height dy dy) ,y ,width ,height left
  153. center ,text ,foreground
  154. ,(if transparent 's8b 's16)
  155. ,@(if font (list font) '())))
  156. '(restore-drawing)))
  157. (define (GETATTRIBUTES)
  158. (map (lambda (a)
  159. (case a
  160. ((X) x)
  161. ((Y) y)
  162. ((WIDTH) width)
  163. ((HEIGHT) height)
  164. ((TEXT) text)
  165. ((ACTION) action)
  166. ((FONT) font)
  167. ((FOREGROUND) foreground)
  168. ((TRANSPARENT) transparent)
  169. ((VALUE) value)
  170. ((BUTTON-SET) button-set)
  171. ((RADIO-BUTTON-SET) radio-button-set)
  172. ((ATTRIBUTES) '(x y width height text action
  173. font foreground
  174. transparent-stipple value
  175. button-set
  176. radio-button-set
  177. attributes delete-object))
  178. (else (ezd-error 'transparent-check-button
  179. "Illegal attribute: ~s" a))))
  180. *user-event-misc*))
  181. (define (OBJECT-LIST? x)
  182. (or (null? x) (and (symbol? (car x)) (object-list? (cdr x)))))
  183. (define (SETATTRIBUTES)
  184. (define DELETE #f)
  185. (define REDRAW #f)
  186. (define DRAWING *user-event-drawing*)
  187. (define (SET-RADIO-BUTTON-SET new-buttons)
  188. (for-each
  189. (lambda (button)
  190. (if (and (not (memq button new-buttons))
  191. (not (eq? button button-name)))
  192. (set-attributes drawing button
  193. '(RADIO-BUTTON-SET-VALUE))))
  194. radio-button-set)
  195. (for-each
  196. (lambda (button)
  197. (if (not (eq? button button-name))
  198. (set-attributes drawing button
  199. `(RADIO-BUTTON-SET-VALUE
  200. ,@new-buttons))))
  201. new-buttons)
  202. (set! radio-button-set new-buttons))
  203. (for-each
  204. (lambda (a)
  205. (cond ((match? (X number?) a)
  206. (set! redraw #t)
  207. (set! x (cadr a)))
  208. ((match? (Y number?) a)
  209. (set! redraw #t)
  210. (set! y (cadr a)))
  211. ((match? (WIDTH positive-number?) a)
  212. (set! redraw #t)
  213. (set! width (cadr a)))
  214. ((match? (HEIGHT positive-number?) a)
  215. (set! redraw #t)
  216. (set! height (cadr a)))
  217. ((match? (TEXT string?) a)
  218. (set! redraw #t)
  219. (set! text (cadr a)))
  220. ((match? (ACTION any?) a)
  221. (set! action (cadr a)))
  222. ((match? (FONT string?) a)
  223. (set! redraw #t)
  224. (set! font (cadr a)))
  225. ((match? (FOREGROUND color?) a)
  226. (set! redraw #t)
  227. (set! foreground (cadr a)))
  228. ((match? (TRANSPARENT boolean?) a)
  229. (set! redraw #t)
  230. (set! transparent (cadr a)))
  231. ((match? (VALUE boolean?) a)
  232. (if (not (equal? value (cadr a)))
  233. (set! redraw #t))
  234. (set! value (cadr a)))
  235. ((and (eq? (car a) 'BUTTON-SET)
  236. (object-list? (cdr a)))
  237. (for-each
  238. (lambda (obj)
  239. (set-attributes drawing-name obj
  240. `(button-set-value ,@(cdr a))))
  241. (append (cdr a) button-set)))
  242. ((eq? (car a) 'BUTTON-SET-VALUE)
  243. (set! button-set (if (memq button-name (cdr a))
  244. (cdr a)
  245. `(,button-name))))
  246. ((and (eq? (car a) 'RADIO-BUTTON-SET)
  247. (object-list? (cdr a)))
  248. (for-each
  249. (lambda (obj)
  250. (set-attributes drawing-name obj
  251. `(radio-button-set-value
  252. ,@(cdr a))))
  253. (append (cdr a) radio-button-set)))
  254. ((eq? (car a) 'RADIO-BUTTON-SET-VALUE)
  255. (set! radio-button-set
  256. (if (memq button-name (cdr a))
  257. (cdr a)
  258. '())))
  259. ((equal? '(DELETE-OBJECT) a)
  260. (set! delete #t))
  261. (else (ezd-error 'transparent-check-button
  262. "Illegal attribute: ~s" a))))
  263. *user-event-misc*)
  264. (if delete
  265. (begin (set-radio-button-set
  266. (remq button-name radio-button-set))
  267. (ezd `(object ,button-name)
  268. `(when ,button-name * #f)))
  269. (if redraw (draw-button))))
  270. (draw-button)
  271. (ezd `(when ,button-name get-attributes ,getattributes)
  272. `(when ,button-name set-attributes ,setattributes)
  273. `(when ,button-name enter ,enter)
  274. `(when ,button-name exit ,exit)
  275. `(when ,button-name button1down ,button-down)
  276. `(when ,button-name button3down ,move-buttons)
  277. `(when ,button-name button1up ,button-up)))
  278. (define-ezd-command
  279. `(transparent-check-button ,symbol? ,number? ,number? ,positive-number?
  280. ,positive-number? ,string? ,boolean?
  281. ,any? (optional ,color?) (optional ,color?) (optional ,string?))
  282. "(transparent-check-button name x y width height text value action [foreground [background]] [\"font\"])"
  283. make-transparent-check-button)
  284. ;;; The TRANSPARENT-PUSH-BUTTON command makes a simple button in the current
  285. ;;; drawing. The button is drawn as a foreground colored (default is black)
  286. ;;; rectangle. The button text is written in the center of the button in the
  287. ;;; foreground color and font (default is X's). If several button text's are
  288. ;;; provided, then each time the button action is taken, the "next" button
  289. ;;; text is displayed.
  290. ;;;
  291. ;;; When the mouse is not in either the button or a member of it's button set,
  292. ;;; the button is "transparent", i.e. drawn with a stipple. When the mouse is
  293. ;;; in it or a member of its button set then it is drawn solid.
  294. ;;;
  295. ;;; When the mouse enters a button with an action not equal to #f, the
  296. ;;; rectangle border solidifies. When mouse button 1 is pressed, the button
  297. ;;; colors are reversed. When button 1 is released, the button action is taken
  298. ;;; and then the button is drawn normally. When the button action is taken,
  299. ;;; the button event type is BUTTON1UP and the miscellaneous information is a
  300. ;;; list containing the button text when the button was pressed and the button
  301. ;;; text that will next be displayed. Note that in order for the button
  302. ;;; action to be taken, the mouse must remain within the button while the
  303. ;;; mouse button is pressed.
  304. ;;;
  305. ;;; Button information can be accessed via the following attributes.
  306. ;;;
  307. ;;; X
  308. ;;; Y
  309. ;;; WIDTH
  310. ;;; HEIGHT
  311. ;;; ACTION
  312. ;;; TEXT
  313. ;;; FONT
  314. ;;; FOREGROUND
  315. ;;; BACKGROUND
  316. ;;; TRANSPARENT
  317. ;;; BUTTON-SET
  318. ;;;
  319. ;;; ATTRIBUTES
  320. ;;; DELETE-OBJECT
  321. (define (MAKE-TRANSPARENT-PUSH-BUTTON button-name x y width height text-list
  322. action opt-foreground opt-background font)
  323. (define FOREGROUND (or opt-foreground 'black))
  324. (define BACKGROUND (or opt-background 'white))
  325. (define DRAWING-NAME (current-drawing-name))
  326. (define BUTTON-SET (list button-name))
  327. (define TRANSPARENT #t)
  328. (define BOLD #f)
  329. (define INVERT #f)
  330. (define TEXTX 0)
  331. (define (ENTER)
  332. (if transparent
  333. (for-each
  334. (lambda (button)
  335. (set-attributes drawing-name button
  336. '(transparent #f)))
  337. button-set))
  338. (if (and action (not *mouse-button1*)) (draw-button #t #f)))
  339. (define (EXIT)
  340. (draw-button #f #f)
  341. (if (or (not (eq? (cadr *user-event-misc*) drawing-name))
  342. (not (memq (caddr *user-event-misc*) button-set)))
  343. (for-each
  344. (lambda (button)
  345. (set-attributes drawing-name button
  346. '(transparent #t)))
  347. button-set)))
  348. (define (BUTTON-DOWN) (if action (draw-button #t #t)))
  349. (define (BUTTON-UP)
  350. (when action
  351. (if invert
  352. (let ((next-textx (modulo (+ 1 textx)
  353. (length text-list))))
  354. (ezd '(draw-now))
  355. (set! *user-event-misc*
  356. (list (list-ref text-list textx)
  357. (list-ref text-list next-textx)))
  358. (if (procedure? action) (action) (eval action))
  359. (set! textx next-textx)))
  360. (draw-button #t #f)))
  361. (define (MOVE-BUTTONS)
  362. (move-transparent-button-set *user-event-drawing* button-set
  363. *user-event-x* *user-event-y*))
  364. (define (DRAW-BUTTON b i)
  365. (set! bold b)
  366. (set! invert i)
  367. (ezd '(save-drawing)
  368. `(set-drawing ,drawing-name)
  369. `(object ,button-name
  370. (fill-rectangle ,x ,y ,width ,height
  371. ,(if transparent
  372. 'clear
  373. (if invert foreground background))
  374. s8b)
  375. (rectangle ,x ,y ,width ,height 0
  376. ,(if transparent 'clear foreground)
  377. ,@(if bold '() '(dash)))
  378. (text ,x ,y ,width ,height center center
  379. ,(list-ref text-list textx)
  380. ,(if invert background foreground)
  381. ,(if transparent 's8b 's16)
  382. ,@(if font (list font) '())))
  383. '(restore-drawing)))
  384. (define (STRING-LIST? x)
  385. (if (null? x)
  386. #f
  387. (let loop ((x x))
  388. (if (pair? x)
  389. (loop (cdr x))
  390. (null? x)))))
  391. (define (GETATTRIBUTES)
  392. (map (lambda (a)
  393. (case a
  394. ((X) x)
  395. ((Y) y)
  396. ((WIDTH) width)
  397. ((HEIGHT) height)
  398. ((TEXT) text-list)
  399. ((ACTION) action)
  400. ((FONT) font)
  401. ((FOREGROUND) foreground)
  402. ((BACKGROUND) background)
  403. ((TRANSPARENT) transparent)
  404. ((BUTTON-SET) button-set)
  405. ((ATTRIBUTES) '(x y width height text action
  406. font foreground background
  407. transparent button-set
  408. attributes delete-object))
  409. (else (ezd-error 'transparent-push-button
  410. "Illegal attribute: ~s" a))))
  411. *user-event-misc*))
  412. (define (OBJECT-LIST? x)
  413. (or (null? x) (and (symbol? (car x)) (object-list? (cdr x)))))
  414. (define (SETATTRIBUTES)
  415. (define (TEXT-LIST? x)
  416. (or (null? x)
  417. (and (string? (car x)) (text-list? (cdr x)))))
  418. (define DELETE #f)
  419. (for-each
  420. (lambda (a)
  421. (cond ((match? (X number?) a)
  422. (set! x (cadr a)))
  423. ((match? (Y number?) a)
  424. (set! y (cadr a)))
  425. ((match? (WIDTH positive-number?) a)
  426. (set! width (cadr a)))
  427. ((match? (HEIGHT positive-number?) a)
  428. (set! height (cadr a)))
  429. ((and (eq? (car a) 'TEXT) (text-list? (cdr a))
  430. (> (length a) 1))
  431. (set! text-list (cdr a)))
  432. ((match? (ACTION any?) a)
  433. (set! action (cadr a)))
  434. ((match? (FONT string?) a)
  435. (set! font (cadr a)))
  436. ((match? (FOREGROUND color?) a)
  437. (set! foreground (cadr a)))
  438. ((match? (BACKGROUND color?) a)
  439. (set! background (cadr a)))
  440. ((match? (TRANSPARENT boolean?) a)
  441. (set! transparent (cadr a)))
  442. ((and (eq? (car a) 'BUTTON-SET)
  443. (object-list? (cdr a)))
  444. (for-each
  445. (lambda (obj)
  446. (set-attributes drawing-name obj
  447. `(button-set-value ,@(cdr a))))
  448. (append (cdr a) button-set)))
  449. ((eq? (car a) 'BUTTON-SET-VALUE)
  450. (set! button-set (if (memq button-name (cdr a))
  451. (cdr a)
  452. `(,button-name))))
  453. ((equal? '(DELETE-OBJECT) a)
  454. (set! delete #t))
  455. (else (ezd-error 'push-button
  456. "Illegal attribute: ~s" a))))
  457. *user-event-misc*)
  458. (if delete
  459. (ezd `(object ,button-name) `(when ,button-name * #f))
  460. (draw-button bold invert)))
  461. (draw-button #f #f)
  462. (ezd `(when ,button-name get-attributes ,getattributes)
  463. `(when ,button-name set-attributes ,setattributes)
  464. `(when ,button-name enter ,enter)
  465. `(when ,button-name exit ,exit)
  466. `(when ,button-name button1down ,button-down)
  467. `(when ,button-name button3down ,move-buttons)
  468. `(when ,button-name button1up ,button-up)))
  469. (define-ezd-command
  470. `(transparent-push-button ,symbol? ,number? ,number? ,positive-number?
  471. ,positive-number? (repeat ,string?) ,any? (optional, color?)
  472. (optional ,color?) (optional ,string?))
  473. "(transparent-push-button name x y width height text ... action [foreground [background]] [\"font\"])"
  474. make-transparent-push-button)
  475. ;;; Transparent buttons are moved by invoking the following "mover". It
  476. ;;; overlays the window with a transparent drawing and then tracks the mouse,
  477. ;;; dragging the button set around as long a mouse button 3 is pressed.
  478. (define (MOVE-TRANSPARENT-BUTTON-SET drawing button-set x y)
  479. (define (ENTER)
  480. (if (not *mouse-button3*) (done)))
  481. (define (EXIT)
  482. (if *mouse-button3* (move-objects) (done)))
  483. (define (DONE)
  484. (ezd '(object __transparent-button-mover__)))
  485. (define (MOVE-OBJECTS)
  486. (let ((dx (- *user-event-x* x))
  487. (dy (- *user-event-y* y)))
  488. (set! x *user-event-x*)
  489. (set! y *user-event-y*)
  490. (for-each
  491. (lambda (obj)
  492. (let ((x (get-attribute drawing obj 'x))
  493. (y (get-attribute drawing obj 'y)))
  494. (set-attributes drawing obj `(x ,(+ x dx))
  495. `(y ,(+ y dy)))))
  496. button-set)
  497. (ezd '(draw-now))))
  498. (ezd `(set-drawing ,drawing)
  499. '(object __transparent-button-mover__
  500. (fill-rectangle 0 0 1000000 1000000 clear))
  501. '(float __transparent-button-mover__)
  502. `(when __transparent-button-mover__ enter ,enter)
  503. `(when __transparent-button-mover__ exit ,exit)
  504. `(when __transparent-button-mover__ button3up ,done)
  505. `(when __transparent-button-mover__ motion ,move-objects)))