;;; scgamewidgets.scm - a scheme game library (needs scx-0.2 or scheme48-fb) ;;; ;;; Copyright (c) 2011-2012 Johan Ceuppens ;;; ;;; All rights reserved. ;;; ;;; Redistribution and use in source and binary forms, with or without ;;; modification, are permitted provided that the following conditions ;;; are met: ;;; 1. Redistributions of source code must retain the above copyright ;;; notice, this list of conditions and the following disclaimer. ;;; 2. Redistributions in binary form must reproduce the above copyright ;;; notice, this list of conditions and the following disclaimer in the ;;; documentation and/or other materials provided with the distribution. ;;; 3. The name of the authors may not be used to endorse or promote products ;;; derived from this software without specific prior written permission. ;;; ;;; THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR ;;; IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES ;;; OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ;;; IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, ;;; INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT ;;; NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ;;; DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ;;; THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ;;; (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF ;;; THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. (load "scgame.scm") ;; for inits see scgame.scm ;; FIXME refactor and cleanup ;; widget tree (define (make-widget-tree) '()) (define (make-widget-tree-leaf widget) (delay widget)) (define (widget-leaf? n) (and (widget? n)(not (list? n)))) (define (make-widget-tree-node widgetlist) (delay widgetlist)) (define (widget-node? n) (and (not (widget? n))(list? n))) (define (widget-tree-add! tree n) (set! tree (append tree (list n)))) (define (widget-node-add! node n) (set! node (append node (list n)))) ;; throws backwards inner widget (define (widget-node-collide? node x y) (define (frec l) (cond ((null? l) #f) ((list? (car l)) (frec (car l))) ((and (widget? (car l)) (>= x (((car l)'get-x))) (<= x (+ (((car l)'get-x)))(((car l)'get-w))) (>= y (((car l)'get-y))) (<= y (+ (((car l)'get-y)))(((car l)'get-h)))) (car l)) (else (frec (cdr l))))) (if (widget-node? node) (for-each frec (force node)) #f)) (define (widget-leaf-collide? leaf x y) (if (widget-leaf? leaf) (cond ((and (widget? leaf) (>= x ((leaf 'get-x))) (<= x (+ ((leaf 'get-x)))((leaf 'get-w))) (>= y ((leaf 'get-y))) (<= y (+ ((leaf 'get-y)))((leaf 'get-h)))) #t)) #f)) ;; widgets (define (make-scgame-widget) (define (draw) (display-msg "widget - draw - subclass responsability")) (define (widget?) #t) (define (get-x) (display-msg "widget - get-x - subclass responsability") 0) (define (get-y) (display-msg "widget - get-y - subclass responsability") 0) (define (get-w) (display-msg "widget - get-w - subclass responsability") 0) (define (get-h) (display-msg "widget - get-h - subclass responsability") 0) (lambda (msg) (cond ((eq? msg 'draw) draw) ((eq? msg 'widget?) widget?) (else (display-msg "subclass responsability"))))) (define (make-button-widget xx yy) (let ((widget (make-scgame-widget)) (image #f) ;; pixel array (pressed-image #f) ;; pixel array (pressed #f) (x xx) (y yy) (width 0) (height 0)) (define (get-x) x) (define (get-y) y) (define (get-w) w) (define (get-h) h) (define (set-image win filename) (set! image (((make-scimage2)'load-image) win filename)) (let ((wh (vector-ref (list->vector image) 1))) (set! width (car wh)) (set! height (cadr wh)) )) (define (set-pressed-image win filename) (set! pressed-image (((make-scimage2)'load-image) win filename)) (let ((wh (vector-ref (list->vector image) 1))) (set! width (car wh)) (set! height (cadr wh)) )) (define (draw-pressed-image dpy win gc) (init-sync-x-events dpy) (map-window dpy win) (draw-points dpy win gc (* width height) 0 0 (/ width 2) (/ height 2))) ;; NOTE : you can remap a button (image) to a new window win if you like (define (draw-image dpy win gc) (init-sync-x-events dpy) (map-window dpy win) (draw-points dpy win gc (* width height) 0 0 (/ width 2) (/ height 2))) (define (draw-points dpy win gc count x y) (if (zero? (modulo count 100)) (display-flush dpy)) (if (not (zero? count)) (let ((xf (floor (* (+ 1.2 x) width))) ; These lines center the picture (yf (floor (* (+ 0.5 y) height)))) (draw-point dpy win gc (inexact->exact xf) (inexact->exact yf)) (draw-points dpy win gc ;; FIXME1 (- count 1) (- (* y (+ 1 (sin (* 0.7 x)))) (* 1.2 (sqrt (abs x)))) (- 0.21 x) width height)))) (define (draw) (if pressed (draw-image) (draw-pressed-image)) (map-window dpy win)) (define (press!) (press-button dpy win gc) (set! pressed #t)) (define (release!) (release-button dpy win gc) (set! pressed #f)) (lambda (msg) (cond ((eq? 'set-image) set-image) ((eq? 'set-pressed-image) set-pressed-image) ((eq? 'press!) press!) ((eq? 'release!) release!) ((eq? get-x) get-x) ((eq? get-y) get-y) ((eq? get-w) get-w) ((eq? get-h) get-h) ((eq? draw) draw) (widget msg) )))) ;; This is the main loop you call on your window's ;; widget tree (see above) (define (widget-tree-eventloop widget-tree) (let ((mousex 0) (mousey 0)) (init-sync-x-events dpy) (map-window dpy win) (call-with-event-channel dpy win (event-mask button-press) (lambda (channel) ;; FIXME calibrate at 10 times or using nanosleep (let loop () (if (let ((e (receive channel))) (cond ((motion-event? e) (set! mousex (motion-event-x)) (set! mousey (motion-event-y))) ((button-press-event? e) (let ((widget (widget-node-collide? widget-tree mousex mouse))) ((widget 'press!)))) ((button-release-event? e) (let ((widget (widget-node-collide? widget-tree mousex mouse))) ((widget 'press!)))) (else #f)))) (loop))))))