lux/chaos/gui/utils.rkt

135 lines
4.0 KiB
Racket

#lang racket/gui
(require racket/contract/base)
(define nnint? exact-nonnegative-integer?)
(provide
(contract-out
[get-mouse-x/y
(->* ()
()
(values nnint? nnint?))]
[get-display-info
(->* (nnint?)
()
(values nnint? nnint? nnint? nnint?))]
[find-monitor
(->* (nnint? nnint?)
()
(or/c false/c nnint?))]
[find-mouse-monitor
(->* ()
()
(or/c false/c nnint?))]
[find-x/y
(->* ((or/c nnint? (one-of/c 'left 'center 'right))
(or/c nnint? (one-of/c 'top 'center 'bottom)))
(#:width
nnint?
#:height
nnint?
#:monitor
(or/c false/c nnint?))
(values nnint? nnint?))]))
;; Returns the coordinates of the mouse pointer
(define (get-mouse-x/y)
(define-values (pt st)
(get-current-mouse-state))
(values (send pt get-x)
(send pt get-y)))
;; Returns the position x, y and the sizes w, h of the provided display/monitor number
(define (get-display-info disp)
(define-values (-x0 -y0)
(if (= disp 0)
(values 0 0) ; to avoid the bars and menus on first monitor
(get-display-left-top-inset #:monitor disp)))
(define-values (w h)
(get-display-size #:monitor disp))
(values (- -x0) (- -y0) w h))
;; Returns the display/monitor that contains the coordinates x,y, or #f if not found
(define (find-monitor x y)
(define n-disp (get-display-count))
(let loop ([disp 0])
(cond
[(>= disp n-disp) #f]
[else
(define-values (x0 y0 w h)
(get-display-info disp))
(if (and (<= x0 x (+ x0 w))
(<= y0 y (+ y0 h)))
disp
(loop (+ disp 1)))])))
;; Returns the display/monitor number that contains the mouse pointer
(define (find-mouse-monitor)
(define-values (pt st)
(get-current-mouse-state))
(find-monitor (send pt get-x) (send pt get-y)))
;; Returns the position x, y in pixels for where to place a frame of size fr-w, fr-h
;; on the specified monitor. If monitor is #f, then the monitor where the mouse
;; pointer is is used.
;; pos-x: (or/c non-negative-integer? (one-of 'left 'center 'right))
;; pos-y: (or/c non-negative-integer?
(define (find-x/y pos-x pos-y
#:width [fr-w 0]
#:height [fr-h 0]
#:monitor [monitor #f])
(when (and monitor (not (<= 0 monitor (- (get-display-count) 1))))
(error "Invalid monitor number" monitor))
(define disp (or monitor (find-mouse-monitor) 0))
(define-values (disp-x0 disp-y0 disp-w disp-h)
(get-display-info disp))
(define x
(cond [(eq? pos-x 'left)
disp-x0]
[(eq? pos-x 'center)
(+ disp-x0 (quotient (- disp-w fr-w) 2))]
[(eq? pos-x 'right)
(+ disp-x0 disp-w (- fr-w))]
[else (+ disp-x0 pos-x)]))
(define y
(cond [(eq? pos-y 'top)
disp-y0]
[(eq? pos-y 'center)
(+ disp-y0 (quotient (- disp-h fr-h) 2))]
[(eq? pos-y 'bottom)
(+ disp-y0 disp-h (- fr-h))]
[else (+ disp-y0 pos-y)]))
(values x y))
(module+ drracket
(define n-displays (get-display-count))
(for/list ([d (in-range n-displays)])
(define-values (x y)
(get-display-left-top-inset #:monitor d))
(define-values (w h)
(get-display-size #:monitor d))
(list d x y w h))
(define fr
(new frame%
[label "test"]
[width 400]
[height 100]))
(send fr show true)
(for* ([monitor (in-sequences (in-value #f)
(in-range (get-display-count)))]
[xx (in-list '(0 100 300 left center right))]
[yy (in-list '(0 200 400 top center bottom))])
(displayln (list monitor xx yy))
(define-values (x y)
(find-x/y xx yy
#:width (send fr get-width)
#:height (send fr get-height)
#:monitor monitor))
(send fr set-label (format "~a, ~a(~a), ~a(~a)" monitor xx x yy y))
(send fr move x y)
(sleep/yield 0.25))
)