(module graph-editor mzscheme
(require (lib "class.ss")
(lib "mred.ss" "mred")
(lib "list.ss")
)
(define tab-width 10)
(define tab-height 10)
(define node-width 60)
(define node-height 25)
(define node-buffer 5)
(define node-color (make-object color% 91 91 184))
(define white-color (make-object color% "white"))
(provide line%)
(define line%
(class object%
(init-field
(source #f) (target #f) (editor #f)
)
(define data #f)
(public get-data)
(define (get-data)
data
)
(public set-data)
(define (set-data dat)
(set! data dat)
)
(define visible? #f)
(public is-shown?)
(define (is-shown?)
visible?
)
(public get-source)
(define (get-source)
source
)
(public get-target)
(define (get-target)
target
)
(define (draw show?)
(set! visible? show?)
(let
((dc (send editor get-dc))
(src-type (send source get-type))
(dst-type (send target get-type))
)
(if show?
(send dc set-pen "black" 1 'solid)
(send dc set-pen "white" 1 'solid)
)
(let-values
(((sx sy) (send source get-position))
((tx ty) (send target get-position))
)
(cond
((equal? src-type 'out) (set! sy (+ sy tab-height -1)))
((equal? src-type 'in) (set! sy (- sy tab-height))))
(cond
((equal? dst-type 'out) (set! ty (+ ty tab-height -1)))
((equal? dst-type 'in) (set! ty (- ty tab-height))))
(send dc draw-line sx sy tx ty)
)
)
)
(public show)
(define (show)
(draw #t)
)
(public hide)
(define (hide)
(draw #f)
)
(super-new)
)
)
(provide tab%)
(define tab%
(class object%
(init-field
(x 0) (y 0)
(type #f) (node #f)
(editor #f)
)
(define visible? #f)
(define lines '())
(public line-add)
(define (line-add line)
(set! lines (cons line lines))
)
(public line-del)
(define (line-del line)
(set! lines (remove line lines))
)
(public get-lines)
(define (get-lines)
(if (and (equal? type 'in)
(> (length lines) 1))
(error "too many lines connected to an in tab")
)
lines
)
(public connected?)
(define (connected?)
(if (> (length lines) 0)
#t #f
)
)
(public is-shown?)
(define (is-shown?)
visible?
)
(public get-type)
(define (get-type)
type
)
(public get-node)
(define (get-node)
node
)
(public x-set!)
(define (x-set! cx)
(set! x cx)
)
(public y-set!)
(define (y-set! cy)
(set! y cy)
)
(public get-position)
(define (get-position)
(values x y)
)
(public get-line-position)
(define (get-line-position)
(if (equal? type 'in)
(values x (- y tab-height))
(values x (+ y tab-height -1))
)
)
(define (draw show?)
(set! visible? show?)
(let
((dc (send editor get-dc)))
(if show?
(send dc set-pen "black" 1 'solid)
(send dc set-pen "white" 1 'solid)
)
(send dc set-brush node-color 'solid)
(cond
((equal? type 'in)
(send dc draw-rectangle
(- x (* tab-width 0.5)) (+ (- y tab-height) 0)
tab-width tab-height)
(send dc set-pen "white" 1 'solid)
(send dc draw-line
(- x (* tab-width 0.5))
(+ (- y tab-height) 0)
(- x (* tab-width 0.5))
(+ (- y tab-height) tab-height))
(send dc draw-line
(- x (* tab-width 0.5))
(+ (- y tab-height) 0)
(+ (- x (* tab-width 0.5)) tab-width)
(+ (- y tab-height) 0))
)
((equal? type 'out)
(send dc draw-rectangle
(- x (* tab-width 0.5)) (- y 0)
tab-width tab-height)
(send dc set-pen "white" 1 'solid)
(send dc draw-line
(- x (* tab-width 0.5)) (- y 0)
(- x (* tab-width 0.5)) (+ y tab-height))
(send dc draw-line
(- x (* tab-width 0.5)) (- y 0)
(+ (- x (* tab-width 0.5)) tab-width) (- y 0))
)
)
(for-each
(lambda (lin)
(if show?
(send lin show)
(send lin hide)
)
)
lines
)
)
)
(public show)
(define (show)
(draw #t)
)
(public hide)
(define (hide)
(draw #f)
)
(public on-mouse)
(define (on-mouse etype cx cy)
(cond
((member etype '(left-down left-up))
(cond
((and (equal? type 'in)
(<= (- x (* tab-width 0.5)) cx (+ x (* tab-width 0.5)))
(<= (- y tab-height) cy y))
this
)
((and (equal? type 'out)
(<= (- x (* tab-width 0.5)) cx (+ x (* tab-width 0.5)))
(<= y cy (+ y tab-height)))
this
)
(else #f)
)
)
(else #f)
)
)
(super-new)
)
)
(provide node%)
(define node%
(class object%
(init-field
(id #f) (name #f) (x 0) (y 0) (editor #f)
(style '())
)
(define tab-in (make-hash-table 'equal))
(define tab-out (make-hash-table 'equal))
(define width 0)
(define height 0)
(define offset 5)
(define visible? #f)
(define data #f)
(public get-data)
(define (get-data)
data
)
(public set-data)
(define (set-data dat)
(set! data dat)
)
(public get-id)
(define (get-id)
id
)
(public get-name)
(define (get-name)
name
)
(public set-name)
(define (set-name str)
(hide #f)
(set! name str)
(set! width (get-real-width))
(show #f)
(send editor layout id)
)
(public get-x)
(define (get-x)
x
)
(public get-y)
(define (get-y)
y
)
(public get-style)
(define (get-style)
style
)
(public is-shown?)
(define (is-shown?)
visible?
)
(define (get-real-width)
(let
((dc (send editor get-dc)))
(let-values
(((tw th td ta) (send dc
get-text-extent
name
#f
#f 0)))
(max 70 (+ (* offset 2) tw))
)
)
)
(define (get-real-height)
(let
((dc (send editor get-dc)))
(let-values
(((tw th td ta) (send dc
get-text-extent
name
#f
#f 0)))
(max 30 (+ (* offset 2) ta td th))
)
)
)
(public x-set!)
(define (x-set! cx)
(set! x cx)
(let*
((n (- (hash-table-count tab-in) 1))
(req-width (* (+ n n 3) tab-width))
(left (* (- width req-width) 0.5))
(sx (+ (- x (* width 0.5)) left (* 1.5 tab-width)))
)
(do ((i 0 (+ i 1))) ((= i (hash-table-count tab-in)))
(let
((tab (hash-table-get tab-in i)))
(send tab x-set! sx)
(set! sx (+ sx (* 2 tab-width)))
)
)
)
(let*
((n (- (hash-table-count tab-out) 1))
(req-width (* (+ n n 3) tab-width))
(left (* (- width req-width) 0.5))
(sx (+ (- x (* width 0.5)) left (* 1.5 tab-width)))
)
(do ((i 0 (+ i 1))) ((= i (hash-table-count tab-out)))
(let
((tab (hash-table-get tab-out i)))
(send tab x-set! sx)
(set! sx (+ sx (* 2 tab-width)))
)
)
)
)
(public y-set!)
(define (y-set! cy)
(set! y cy)
(do ((i 0 (+ i 1))) ((= i (hash-table-count tab-in)))
(let
((tab (hash-table-get tab-in i)))
(send tab y-set! (- y (/ height 2.0)))
)
)
(do ((i 0 (+ i 1))) ((= i (hash-table-count tab-out)))
(let
((tab (hash-table-get tab-out i)))
(send tab y-set! (+ y (/ height 2.0)))
)
)
)
(public get-position)
(define (get-position)
(values x y)
)
(public get-size)
(define (get-size)
(values width height)
)
(public tab-in-count)
(define (tab-in-count)
(hash-table-count tab-in)
)
(public tab-out-count)
(define (tab-out-count)
(hash-table-count tab-out)
)
(public tab-in-ref)
(define (tab-in-ref i)
(if (>= i 0)
(hash-table-get tab-in i #f)
)
)
(public tab-out-ref)
(define (tab-out-ref i)
(if (>= i 0)
(hash-table-get tab-out i #f)
)
)
(public tab-in-connected?)
(define (tab-in-connected?)
(tab-connected? tab-in)
)
(public tab-out-connected?)
(define (tab-out-connected?)
(tab-connected? tab-out)
)
(define (tab-connected? tab-list)
(let
((connected? #f)
(n (hash-table-count tab-list))
)
(do ((i 0 (+ i 1))) ((or connected? (= i n)))
(set! connected? (or connected?
(send (hash-table-get tab-list i #f) connected?)))
)
connected?
)
)
(public tab-in-decr)
(define (tab-in-decr)
(tab-decr tab-in 'in)
)
(public tab-out-decr)
(define (tab-out-decr)
(tab-decr tab-out 'out)
)
(define (tab-decr tab-list type)
(let*
((n (hash-table-count tab-list)))
(if (> n 0)
(let
((last (hash-table-get tab-list (- n 1))))
(if (not (send last connected?))
(let
((n (- n 1))
(ni (hash-table-count tab-in))
(no (hash-table-count tab-out))
(max-width #f)
(req-width (* (+ n n 0) tab-width))
)
(hide #f)
(hash-table-remove! tab-list n)
(if (equal? type 'in)
(set! max-width (max (* (- (+ ni ni) 1) tab-width)
(* (+ (+ no no) 1) tab-width)))
(set! max-width (max (* (+ (+ ni ni) 1) tab-width)
(* (- (+ no no) 1) tab-width)))
)
(set! width (max (get-real-width) max-width))
(let*
((left (* (- width req-width) 0.5))
(sx (+ (- x (* width 0.5)) left (* 2 tab-width)))
)
(do ((i 0 (+ i 1))) ((= i n))
(let
((tab (hash-table-get tab-list i)))
(send tab x-set! sx)
(set! sx (+ sx (* 2 tab-width)))
)
)
)
(show #f)
(send editor on-paint)
)
)
)
)
)
)
(public tab-in-incr)
(define (tab-in-incr)
(tab-incr tab-in 'in)
)
(public tab-out-incr)
(define (tab-out-incr)
(tab-incr tab-out 'out)
)
(define (tab-incr tab-list type)
(hide #f)
(let*
((n (hash-table-count tab-list))
(ni (hash-table-count tab-in))
(no (hash-table-count tab-out))
(max-width #f)
(req-width (* (+ n n 3) tab-width))
)
(if (equal? type 'in)
(set! max-width (max (* (+ ni ni 3) tab-width)
(* (+ no no 1) tab-width)))
(set! max-width (max (* (+ ni ni 1) tab-width)
(* (+ no no 3) tab-width)))
)
(set! width (max (get-real-width) max-width))
(let*
((left (* (- width req-width) 0.5))
(sx (+ (- x (* width 0.5)) left (* 1.5 tab-width)))
)
(do ((i 0 (+ i 1))) ((= i n))
(let
((tab (hash-table-get tab-list i)))
(send tab x-set! sx)
(set! sx (+ sx (* 2 tab-width)))
)
)
(let
((tab (make-object tab%
sx
(if (equal? type 'in)
(- y (/ height 2.0))
(+ y (/ height 2.0))
)
type this editor)))
(hash-table-put! tab-list n tab)
)
)
(show #f)
(send editor layout id)
)
)
(define (draw show? selected?)
(set! visible? show?)
(let
((dc (send editor get-dc))
(color #f)
)
(if (and show? selected?)
(set! color (make-object color% 240 240 240))
(set! color (get-panel-background))
)
(send dc set-pen color 1 'solid)
(send dc set-brush color 'solid)
(send dc draw-rectangle
(- x (/ width 2.0))
(- y (/ height 2.0) tab-height)
width
(+ height tab-height tab-height))
(if show?
(send dc set-pen "black" 1 'solid)
(send dc set-pen "white" 1 'solid)
)
(send dc set-brush node-color 'solid)
(send dc draw-rectangle
(- x (/ width 2.0))
(- y (/ height 2.0))
width
height)
(send dc set-pen "white" 1 'solid)
(send dc draw-line
(- x (/ width 2.0))
(- y (/ height 2.0))
(- x (/ width 2.0))
(+ (- y (/ height 2.0)) height))
(send dc draw-line
(- x (/ width 2.0))
(- y (/ height 2.0))
(+ (- x (/ width 2.0)) width)
(- y (/ height 2.0)))
(if show?
(let-values
(((tw th td ta) (send dc
get-text-extent
name
#f
#f 0)))
(send dc set-text-foreground white-color)
(send dc draw-text name
(- x (* tw 0.5)) (- y (* (+ th ta) 0.5))
#f 0 0)
)
)
)
(do ((i 0 (+ i 1))) ((= i (hash-table-count tab-in)))
(let
((tab (hash-table-get tab-in i)))
(if show?
(send tab show)
(send tab hide)
)
)
)
(do ((i 0 (+ i 1))) ((= i (hash-table-count tab-out)))
(let
((tab (hash-table-get tab-out i)))
(if show?
(send tab show)
(send tab hide)
)
)
)
)
(public show)
(define (show selected?)
(draw #t selected?)
)
(public hide)
(define (hide selected?)
(draw #f selected?)
)
(public on-mouse)
(define (on-mouse type cx cy)
(cond
((member type '(left-down left-up))
(cond
((and (<= (- x (* width 0.5)) cx (+ x (* width 0.5)))
(<= (- y (* height 0.5)) cy (+ y (* height 0.5))))
this
)
(else
(let
((found? #f)
(n-in (hash-table-count tab-in))
(n-out (hash-table-count tab-out))
)
(do ((i 0 (+ i 1))) ((or found? (= i n-in)))
(set! found? (send (hash-table-get tab-in i #f) on-mouse type cx cy))
)
(do ((i 0 (+ i 1))) ((or found? (= i n-out)))
(set! found? (send (hash-table-get tab-out i #f) on-mouse type cx cy))
)
found?
)
)
)
)
(else #f)
)
)
(super-new)
(set! width (get-real-width))
(set! height (get-real-height))
(if (not (member 'no-input style))
(hash-table-put! tab-in
(hash-table-count tab-in)
(make-object tab%
x (- y (/ height 2.0))
'in this editor)))
(if (not (member 'no-output style))
(hash-table-put! tab-out
(hash-table-count tab-out)
(make-object tab%
x (+ y (/ height 2.0))
'out this editor)))
)
)
(provide graph-editor%)
(define graph-editor%
(class canvas%
(init-field
(callback #f)
(font #f)
)
(unless (or (not callback)
(procedure-arity-includes? callback 2))
(raise-type-error 'graph-editor%
"procedure of arity 2"
callback)
)
(unless (or (not font)
(is-a? font font%))
(raise-type-error 'graph-editor%
"fond%"
font)
)
(if (not font)
(set! font normal-control-font)
)
(define bitmap #f)
(define b-dc #f)
(define bitmap-width 0)
(define bitmap-height 0)
(define x-offset 0)
(define y-offset 0)
(define vertical-scroll-step 20)
(define horizontal-scroll-step 20)
(define/override (get-dc)
b-dc
)
(define selected-node #f)
(define nodes (make-hash-table 'equal))
(define max-id 0)
(public get-selected)
(define (get-selected)
selected-node
)
(define (distance x1 y1 x2 y2)
(let
((dx (- x2 x1))
(dy (- y2 y1)))
(sqrt (+ (* dx dx) (* dy dy)))
)
)
(define (is-inside? x1 y1 x2 y2 x y)
(and (<= (min x1 x2) x (max x1 x2))
(<= (min y1 y2) y (max y1 y2)))
)
(define (overlap? x1 y1 w1 h1
x2 y2 w2 h2)
(let
((halfw1 (* 0.5 w1))
(halfh1 (* 0.5 h1))
(halfw2 (* 0.5 w2))
(halfh2 (* 0.5 h2))
)
(or (is-inside? (- x2 halfw2) (- y2 halfh2) (+ x2 halfw2) (+ y2 halfh2)
(- x1 halfw1) (- y1 halfh1))
(is-inside? (- x2 halfw2) (- y2 halfh2) (+ x2 halfw2) (+ y2 halfh2)
(+ x1 halfw1) (- y1 halfh1))
(is-inside? (- x2 halfw2) (- y2 halfh2) (+ x2 halfw2) (+ y2 halfh2)
(+ x1 halfw1) (+ y1 halfh1))
(is-inside? (- x2 halfw2) (- y2 halfh2) (+ x2 halfw2) (+ y2 halfh2)
(- x1 halfw1) (+ y1 halfh1))
(is-inside? (- x1 halfw1) (- y1 halfh1) (+ x1 halfw1) (+ y1 halfh1)
(- x2 halfw2) (- y2 halfh2))
(is-inside? (- x1 halfw1) (- y1 halfh1) (+ x1 halfw1) (+ y1 halfh1)
(+ x2 halfw2) (- y2 halfh2))
(is-inside? (- x1 halfw1) (- y1 halfh1) (+ x1 halfw1) (+ y1 halfh1)
(+ x2 halfw2) (+ y2 halfh2))
(is-inside? (- x1 halfw1) (- y1 halfh1) (+ x1 halfw1) (+ y1 halfh1)
(- x2 halfw2) (+ y2 halfh2))
)
)
)
(define (layout-aux id)
(let ((ok? #t)
(n max-id)
(anode (hash-table-get nodes id #f)))
(do ((i 0 (+ i 1))) ((or anode (= i n)))
(set! id i)
(set! anode (hash-table-get nodes id #f))
)
(if anode
(let-values
(((ax ay) (send anode get-position))
((aw ah) (send anode get-size)))
(do ((j 0 (+ j 1))) ((= j n))
(if (not (= j id))
(let
((bnode (hash-table-get nodes j #f)))
(if bnode
(let-values
(((bx by) (send bnode get-position))
((bw bh) (send bnode get-size))
)
(if (overlap? ax ay aw (+ ah tab-height tab-height)
bx by bw (+ bh tab-height tab-height))
(begin
(send bnode x-set! (+ ax (+ (* aw 0.55) (* bw 0.55)) node-buffer))
(layout-aux j))))))))))))
(public layout)
(define (layout id)
(layout-aux id)
(update-bitmap)
(on-paint)
)
(public clear)
(define (clear)
(let
((allowed? (if callback (callback 'before-clear #f) #t)))
(if allowed?
(begin
(set! nodes (make-hash-table 'equal))
(layout #f)
(if callback
(callback 'after-clear #f)
)
)
)
)
)
(public node-add)
(define (node-add name x y style)
(let
((allowed? (if callback (callback 'before-node-add name) #t)))
(if allowed?
(let*
((id max-id)
(node (new node%
(id id) (name name)
(x x) (y y)
(editor this) (style style))))
(hash-table-put! nodes id node)
(set! max-id (+ max-id 1))
(let-values
(((w h) (send node get-size)))
(if (< x 0)
(send node x-set! (* w 0.5))
)
(if (< y 0)
(send node y-set! (* 0.5 (+ h tab-height tab-height)))
)
)
(layout id)
(if callback
(callback 'after-node-add node)
)
node
)
#f
)
)
)
(public node-del)
(define (node-del node)
(if (and (not (send node tab-in-connected?))
(not (send node tab-out-connected?)))
(let
((allowed? (if callback (callback 'before-node-del node) #t)))
(if allowed?
(let*
((id (send node get-id)))
(hash-table-remove! nodes id)
(set! selected-node #f)
(layout #f)
(if callback
(callback 'after-node-del id)
)
)
)
)
)
)
(public node-get-by-name)
(define (node-get-by-name name)
(let ((ok? #f)
(n max-id))
(do ((i 0 (+ i 1))) ((or ok? (= i n)))
(let ((node (hash-table-get nodes i #f)))
(if (and node
(equal? (send node get-name) name))
(set! ok? node))))
ok?
)
)
(public node-for-each)
(define (node-for-each func)
(hash-table-for-each
nodes
func
)
)
(public node-del!)
(define (node-del! node)
(let
((ni (send node tab-in-count))
(no (send node tab-out-count)))
(do ((i 0 (+ i 1))) ((= i ni))
(let ((tab (send node tab-in-ref i)))
(if (send tab connected?)
(for-each
(lambda (line)
(let
((src (send line get-source))
(dst (send line get-target)))
(line-del line src dst)))
(send tab get-lines)))))
(do ((i 0 (+ i 1))) ((= i no))
(let ((tab (send node tab-out-ref i)))
(if (send tab connected?)
(for-each
(lambda (line)
(let
((src (send line get-source))
(dst (send line get-target)))
(line-del line src dst)))
(send tab get-lines)))))
(node-del node)
)
)
(public line-add)
(define (line-add src-tab dst-tab)
(let
((allowed? (if callback (callback 'before-line-add (list src-tab dst-tab)) #t)))
(if allowed?
(let
((line (make-object line% src-tab dst-tab this))
)
(send src-tab line-add line)
(send dst-tab line-add line)
(send line show)
(if callback
(callback 'after-line-add line)
)
(on-paint)
line
)
#f
)
)
)
(define (line-del line src-tab dst-tab)
(let
((allowed? (if callback (callback 'before-line-del (list src-tab dst-tab)) #t)))
(if allowed?
(let*
(
)
(send src-tab line-del line)
(send dst-tab line-del line)
(send line hide)
(if callback
(callback 'after-line-del #f)
)
(on-paint)
)
)
)
)
(define (get-real-width)
(let
((width 0))
(hash-table-for-each
nodes
(lambda (idx node)
(let-values
(((x y) (send node get-position))
((w h) (send node get-size)))
(set! width (max width (+ x (* w 0.5))))
)
)
)
(inexact->exact (round width))
)
)
(define (get-real-height)
(let
((height 0))
(hash-table-for-each
nodes
(lambda (idx node)
(let-values
(((x y) (send node get-position))
((w h) (send node get-size)))
(set! height (max height (+ y (* (+ h tab-height tab-height) 0.5))))
)
)
)
(inexact->exact (round height))
)
)
(define (update-bitmap)
(update-scroll-bars)
(let-values (((width height) (send this get-virtual-size)))
(let*
((w (max (get-real-width) width 1))
(h (max (get-real-height) height 1)))
(if (or (not bitmap)
(> w bitmap-width)
(> h bitmap-height))
(let*
((n (round (max (/ w 1000) (/ h 1000))))
(size (* (+ n 1) 1000)))
(set! bitmap (make-object bitmap% size size #f))
(set! b-dc (instantiate bitmap-dc% (bitmap)))
(set! bitmap-width size)
(set! bitmap-height size)
(on-paint)
)
)
)
)
)
(define (update-scroll-bars)
(let
((horizontal? #f) (vertical? #f))
(send this show-scrollbars #f #f)
(let-values (((width height) (send this get-virtual-size)))
(send this set-scroll-range 'vertical (max 0 (- (get-real-height) height)))
(if (= 0 (send this get-scroll-range 'vertical))
(set! y-offset 0)
(begin
(send this show-scrollbars #f #t)
(set! vertical? #t)
)
)
)
(let-values (((width height) (send this get-virtual-size)))
(send this set-scroll-range 'horizontal (max 0 (- (get-real-width) width)))
(if (= 0 (send this get-scroll-range 'horizontal))
(set! x-offset 0)
(begin
(send this show-scrollbars #t vertical?)
(set! horizontal? #t)
)
)
)
(let-values (((width height) (send this get-virtual-size)))
(send this set-scroll-range 'vertical (max 0 (- (get-real-height) height)))
(if (= 0 (send this get-scroll-range 'vertical))
(set! y-offset 0)
(send this show-scrollbars horizontal? vertical?)
)
(send this set-scroll-page 'horizontal (max 1 width))
(send this set-scroll-page 'vertical (max 1 (- height vertical-scroll-step)))
)
)
)
(define/override (on-scroll scroll-event)
(case (send scroll-event get-direction)
((vertical)
(let ((type (send scroll-event get-event-type)))
(cond
((eq? type 'line-down)
(let-values (((width height) (send this get-virtual-size)))
(send this set-scroll-pos 'vertical
(min (+ (send this get-scroll-pos 'vertical) vertical-scroll-step -1)
(send this get-scroll-range 'vertical)))
(set! y-offset (min (+ y-offset vertical-scroll-step)
(send this get-scroll-range 'vertical)))))
((eq? type 'line-up)
(send this set-scroll-pos 'vertical
(max (- (send this get-scroll-pos 'vertical) vertical-scroll-step -1) 0))
(set! y-offset (max (- y-offset vertical-scroll-step) 0)))
(else (set! y-offset (send scroll-event get-position))))))
((horizontal)
(let ((type (send scroll-event get-event-type)))
(cond
((eq? type 'line-down)
(let-values (((width height) (send this get-virtual-size)))
(send this set-scroll-pos 'horizontal
(min (+ (send this get-scroll-pos 'horizontal) horizontal-scroll-step -1)
(send this get-scroll-range 'horizontal)))
(set! x-offset (min (+ x-offset horizontal-scroll-step)
(send this get-scroll-range 'horizontal)))))
((eq? type 'line-up)
(send this set-scroll-pos 'horizontal
(max (- (send this get-scroll-pos 'horizontal) horizontal-scroll-step -1) 0))
(set! x-offset (max (- x-offset horizontal-scroll-step) 0)))
(else (set! x-offset (send scroll-event get-position)))))))
(let
((dc (super get-dc)))
(send dc draw-bitmap bitmap (- x-offset) (- y-offset))
)
)
(define/override (on-size width height)
(update-bitmap)
)
(define (refresh)
(if (send bitmap ok?)
(let
((dc (super get-dc)))
(send dc draw-bitmap bitmap (- x-offset) (- y-offset))
)
)
)
(define/override (on-paint)
(let
((dc (get-dc))
(n max-id)
)
(send dc set-background (get-panel-background))
(send dc clear)
(do ((i 0 (+ i 1))) ((= i n))
(let
((node (hash-table-get nodes i #f)))
(if node
(if (equal? node selected-node)
(send node show #t)
(send node show #f)
)
)
)
)
)
(refresh)
)
(define/override (on-subwindow-char widget event)
(let
((key (send event get-key-code))
(ctrl (send event get-control-down))
)
(cond
((equal? key #\rubout)
(let
((node selected-node))
(if (and node
(not (send node tab-in-connected?))
(not (send node tab-out-connected?)))
(node-del node)
)
)
)
)
)
)
(define clicked #f)
(define px #f)
(define py #f)
(define (find-clicked type x y)
(let
((obj #f))
(hash-table-for-each
nodes
(lambda (name node)
(let
((selected (send node on-mouse type x y)))
(cond
((is-a? selected node%)
(set! obj selected)
)
((is-a? selected tab%)
(set! obj selected)
)
)
)
)
)
obj
)
)
(define/override (on-event event)
(send this focus)
(let
((type (send event get-event-type))
(x (+ (send event get-x) x-offset))
(y (+ (send event get-y) y-offset))
)
(cond
((equal? type 'left-down)
(set! clicked (find-clicked type x y))
(if (not clicked)
(begin
(if selected-node
(begin
(if callback
(callback 'deselect selected-node)
)
(send selected-node show #f)
(refresh)
)
)
(set! selected-node #f)
)
)
)
((and (equal? type 'motion)
clicked
(is-a? clicked tab%)
(equal? (send clicked get-type) 'out))
(let-values
(((sx sy) (send clicked get-line-position)))
(let
((dc (get-dc)))
(send dc set-pen "black" 1 'xor)
(if (and px py)
(send dc draw-line sx sy px py)
)
(send dc draw-line sx sy x y)
(refresh)
(set! px x)
(set! py y)
)
)
)
((and (equal? type 'left-up)
clicked
(is-a? clicked tab%)
(equal? (send clicked get-type) 'out))
(let
((dest (find-clicked type x y)))
(if (and dest
(is-a? dest tab%)
(equal? (send dest get-type) 'in)
)
(if (not (send dest connected?))
(line-add clicked dest)
(message-box "Error" "Tab is already connected" #f '(ok stop))
)
)
)
(on-paint)
(set! clicked #f)
(set! px #f)
(set! py #f)
)
((and (equal? type 'motion)
clicked
(is-a? clicked tab%)
(equal? (send clicked get-type) 'in)
(send clicked connected?))
(let*
((line (car (send clicked get-lines)))
(src (send line get-source)))
(send line hide)
(let-values
(((sx sy) (send src get-line-position)))
(let
((dc (get-dc)))
(send dc set-pen "black" 1 'xor)
(if (and px py)
(send dc draw-line sx sy px py)
)
(send dc draw-line sx sy x y)
(refresh)
(set! px x)
(set! py y)
)
)
)
)
((and (equal? type 'left-up)
clicked
(is-a? clicked tab%)
(equal? (send clicked get-type) 'in)
(send clicked connected?))
(let*
((line (car (send clicked get-lines)))
(src (send line get-source))
(dst (send line get-target))
)
(let
((new-dst (find-clicked type x y)))
(cond
((equal? new-dst dst)
(send line show)
)
((and new-dst
(is-a? new-dst tab%)
(equal? (send new-dst get-type) 'in))
(line-del line src dst)
(line-add src new-dst)
)
(else
(line-del line src dst)
)
)
)
(on-paint)
(set! clicked #f)
(set! px #f)
(set! py #f)
)
)
((and (equal? type 'motion)
clicked
(is-a? clicked node%))
(if (send clicked is-shown?)
(send clicked hide #f)
)
(let-values
(((sw sh) (send clicked get-size)))
(let
((dc (get-dc)))
(send dc set-pen "black" 1 'xor)
(send dc set-brush "black" 'xor)
(if (and px py)
(send dc draw-rectangle
(- px (* sw 0.5)) (- py (* sh 0.5))
sw sh)
)
(send dc draw-rectangle
(- x (* sw 0.5)) (- y (* sh 0.5))
sw sh)
(refresh)
(set! px x)
(set! py y)
)
)
)
((and (equal? type 'left-up)
clicked
(is-a? clicked node%))
(if (and px py)
(let-values
(((w h) (send clicked get-size)))
(if (< x 0)
(send clicked x-set! (* w 0.5))
(send clicked x-set! x)
)
(if (< y 0)
(send clicked y-set! (* 0.5 (+ h tab-height tab-height)))
(send clicked y-set! y)
)
(layout (send clicked get-id))
)
)
(send clicked show #t)
(set! selected-node clicked)
(if callback
(callback 'select selected-node)
)
(on-paint)
(set! clicked #f)
(set! px #f)
(set! py #f)
)
)
)
)
(super-new (style '(vscroll hscroll border)))
(update-bitmap)
(send (send this get-dc) set-font font)
)
)
)