Hi all,<br><br>I needed a GUI container that allows the contained components to choose where they are placed in the container. i.e. A container that doesn't try to stretch and re-'place' its containees, instead letting the containees figure out where they want to be. <br>
<br>I was surprised that this particular container/containee use-case wasn't readily available in Racket (since it is 'the' fundamental layout elsewhere), so I implemented a version and post it here in case it is useful to others. (If I'm going about it wrong, then please do let me know.)<br>
<br>Cheers,<br><br>Kieron.<br><br>p.s. I notice the canvas border is actually painted only on the top and left (see capture-self-placeable). Should the border also be painted on the bottom and right?<br><br>****<br><br>#lang racket/gui<br>
<br>; Specify in an interface the methods that a containee needs to make it self-placeable.<br>(define self-placeable-containee<%><br> (interface () <br> get-preferred-x get-preferred-y get-preferred-x-y <br> set-preferred-x set-preferred-y set-preferred-x-y))<br>
<br>; Define in a mixin the default implementations for a self-placeable containee.<br>(define (self-placeable-containee%% %)<br> (class* % (self-placeable-containee<%>)<br> (super-new)<br> <br> (define preferred-x 0)<br>
(define preferred-y 0)<br> <br> (define/public (get-preferred-x) <br> preferred-x)<br> (define/public (get-preferred-y) <br> preferred-y)<br> (define/public (get-preferred-x-y) <br> (values preferred-x preferred-y))<br>
<br> (define/public (set-preferred-x x)<br> (set! preferred-x x))<br> (define/public (set-preferred-y y)<br> (set! preferred-y y))<br> (define/public (set-preferred-x-y x y)<br> (set! preferred-x x)<br>
(set! preferred-y y))<br> ))<br><br>; Define a custom container panel that can place the self-placeable containees.<br>(define placer-panel%<br> (class panel%<br> (inherit get-children min-width min-height)<br>
<br> (super-new)<br><br> ; container-size is called with each child's dimensions and strechability,<br> ; and returns the container's required minimum dimensions.<br> ; In this case, the containee size's are ignored, <br>
; and the container's (previously set) minimum width and height are returned. <br> [define/override (container-size containee-sizes)<br>; (printf "container-size:~a\n" containee-sizes)<br> (values (min-width) (min-height))]<br>
<br> ; place-children is called with each child's dimensions and strechability, <br> ; and returns each child's location and dimensions.<br> ; In this case, each containee is simply asked where it wants to be (previously set).<br>
; No adustments are made to a containee's size so as to use any empty space in the container.<br> ; i.e. A containee's strechability is ignored, and each containee remains the (previously set) minimum width and height.<br>
[define/override (place-children containee-sizes container-width container-height)<br>; (printf "place-children:~a\n" containee-sizes)<br> (map (lambda (containee-size containee) <br> (let*-values ([(min-width min-height h-stretch? v-stretch?)<br>
(apply values containee-size)]<br> [(x y)<br> (send containee get-preferred-x-y)]<br> )<br> (list x y min-width min-height)))<br>
containee-sizes<br> (get-children))]<br> ))<br><br>(define self-placeable-canvas%<br> (class (self-placeable-containee%% canvas%) <br> (inherit set-preferred-x-y)<br> (init x y)<br> (super-new)<br>
(set-preferred-x-y x y)<br> ))<br><br>(define frame-1 (new frame%<br> [label "Self Placeable Containees"]<br> [x 30]<br> [y 30]<br> [min-width 800]<br>
[min-height 600]))<br><br>(define panel-1 (new placer-panel%<br> [parent frame-1]<br> ))<br><br>(define canvas-1 (new self-placeable-canvas%<br> [parent panel-1]<br>
[style (list 'border)]<br> [x 25] <br> [y 25]<br> [min-width 500]<br> [min-height 75]))<br><br>(define canvas-2 (new self-placeable-canvas%<br>
[parent panel-1]<br> [style (list 'border)]<br> [x 275] <br> [y 275]<br> [min-width 100]<br> [min-height 100]))<br>
<br>(define canvas-3 (new self-placeable-canvas%<br> [parent panel-1]<br> [style (list 'border)]<br> [x 600] <br> [y 125]<br> [min-width 100]<br>
[min-height 400]))<br><br>(send frame-1 show #t)<br><br>