#lang scheme/base
(require scheme/gui/base
         scheme/class
         scheme/runtime-path
         (for-syntax scheme/base))
(provide close-icon%)

(define-runtime-path icon-path '(lib "close.png" "icons"))
  
(define icon 'icon-not-yet-init)
(define mask1 'mask-not-yet-init)
(define mask2 'mask-not-yet-init)
(define mask3 'mask-not-yet-init)

(define (init-masks)
  (define (for-each/b bytes r g b)
    (let loop ([i 0])
      (when (< i (bytes-length bytes))
        (bytes-set! bytes (+ i 1) (r (bytes-ref bytes (+ i 1))))
        (bytes-set! bytes (+ i 2) (g (bytes-ref bytes (+ i 2))))
        (bytes-set! bytes (+ i 3) (b (bytes-ref bytes (+ i 3))))
        (loop (+ i 4)))))
  
  (define stupid-internal-define-syntax1
    (set! icon (make-object bitmap% icon-path 'png/mask)))
  (define stupid-internal-define-syntax2
    (set! mask1 (send icon get-loaded-mask)))
  
  (define bytes (make-bytes (* (send icon get-width) (send icon get-width) 4)))
  (define bdc (make-object bitmap-dc% mask1))
  
  (set! mask2 (make-object bitmap% (send mask1 get-width) (send mask1 get-height)))
  (set! mask3 (make-object bitmap% (send mask1 get-width) (send mask1 get-height)))
  
  (send bdc get-argb-pixels 0 0 (send mask1 get-width) (send mask1 get-height) bytes)
  (send bdc set-bitmap mask2)
  (for-each/b bytes 
              (λ (x) (- 255 (floor (* (- 255 x) 2/3))))
              values
              values)
  (send bdc set-argb-pixels 0 0 (send mask1 get-width) (send mask1 get-height) bytes)
  
  (send bdc set-bitmap mask1)
  (send bdc get-argb-pixels 0 0 (send mask1 get-width) (send mask1 get-height) bytes)
  (send bdc set-bitmap mask3)
  (for-each/b bytes 
              (λ (x) (- 255 (floor (* (- 255 x) 1/4))))
              values
              values)
  (send bdc set-argb-pixels 0 0 (send mask1 get-width) (send mask1 get-height) bytes)
  
  (send bdc set-bitmap #f))

(define close-icon%
  (class canvas%
    (inherit get-dc min-width min-height stretchable-width stretchable-height
             get-client-size refresh)
    (init-field [callback void]
                [bg-color #f])
    (init [horizontal-pad 4]
          [vertical-pad 4])
    (init-masks)
    
    (define mouse-in? #f)
    (define mouse-down? #f)
    
    (define/override (on-event evt)
      (cond
        [(send evt leaving?)
         (set! mouse-in? #f)
         (refresh)]
        [(send evt entering?)
         (set! mouse-in? #t)
         (refresh)]
        [(send evt button-down?)
         (set! mouse-down? #t)
         (refresh)]
        [(send evt button-up?)
         (set! mouse-down? #f)
         (refresh)
         (when mouse-in? 
           (callback))]
        [(send evt moving?)
         (let ([new-mouse-in?
                (and (<= (send evt get-x)
                         (send icon get-width))
                     (<= (send evt get-y)
                         (send icon get-height)))])
           (unless (equal? new-mouse-in? mouse-in?)
             (set! mouse-in? new-mouse-in?)
             (refresh)))]))
    
    (define/override (on-paint)
      (let ([dc (get-dc)])
        (let-values ([(cw ch) (get-client-size)])
          (when bg-color
            (send dc set-brush bg-color 'solid)
            (send dc set-pen bg-color 1 'transparent)
            (let-values ([(w h) (get-client-size)])
              (send dc draw-rectangle 0 0 w h)))
          (send dc draw-bitmap icon 
                (- (/ cw 2) (/ (send icon get-width) 2))
                (- (/ ch 2) (/ (send icon get-height) 2))
                'solid
                (send the-color-database find-color "black")
                (cond
                  [(and mouse-in?
                        mouse-down?)
                   mask3]
                  [(and mouse-in?
                        (not mouse-down?))
                   mask2]
                  [else
                   mask1])))))
    
    (super-new [style '(transparent)])
    (min-width (+ horizontal-pad horizontal-pad (send icon get-width)))
    (min-height (+ vertical-pad vertical-pad (send icon get-height)))
    (stretchable-width #f)
    (stretchable-height #f)))

#;
(begin
  (define f (new frame% [label "test"]))
  (define c (new close-icon% [parent f] [callback (λ () (printf "hi\n"))]))
  (define gb (new grow-box-spacer-pane% [parent f]))
  (send f show #t))
