GUI elements in (Dr) Racket - user-interface

I need some basic stuff for working with the GUI library in Racket.
How do I set the callback function to a button like this:
(define next (new button% [parent frame] [label "Next ->"]))
How do I draw something on a canvas after it's been created like this:
(define canvas (new canvas% [parent frame]
[paint-callback canvasdc]))
(define canvasdc (lambda (canvas dc)
(send dc set-text-foreground "black")
(send dc draw-text "Some title!" 0 0)
))
I would need to draw (rescaled jpegs or, if not able) compound shapes and repaint with something else on every button pressed event

There's an optional callback argument to the button constructor.
See http://docs.racket-lang.org/draw/overview.html. But I'm confused by your question since the code you've posted includes drawing to the canvas. For images, specifically, read-bitmap will read a bitmap from a file; draw-bitmap will draw a bitmap into a DC. You can get it (along with all other drawing to that DC) scaled by calling set-scale. If the DC you're drawing into is a bitmap-dc (I don't think a canvas-dc is, but I am not a Racket expert and could be wrong) then you can do it directly using draw-bitmap-section-smooth.

Related

How to set frame's background in Racket?

How to set frame's background in Racket? I want to change the background color of a window (for usability purposes) while still being able to place other controls in that window (and keep them fully functional).
Currently I don't see a possibility for this. I tried adding a canvas and changing its background color (which works for the canvas itself), but the canvas pushes out other controls due to the GUI toolkit's geometry management.
It would be nice also to have a way to change colors of other controls (buttons, etc.).
I didn't find anything for frame, but color of button, check-box or message can be changed, if you use bitmap in field label in their constructor. You can use some image from your PC or create that bitmap programmatically:
(require racket/gui/base)
(define frame (new frame%
(label "Example")
(width 500)
(height 500)))
(define button-bg (make-object bitmap% 100 50))
(define dc (new bitmap-dc% (bitmap button-bg)))
(send dc set-brush "green" 'solid)
(send dc set-pen "black" 3 'solid)
(send dc draw-rectangle 0 0 100 50)
(send dc draw-text "Click Me!" 20 0)
(define b (new button%
(parent frame)
(label button-bg)))
(send frame show #t)
The GUI is cross platform - and some platforms do not support changing the background color.
https://lists.racket-lang.org/users/archive/2012-February/050626.html

using rectangle to select nodes on top of a zoomable map.in D3

[[This is using d3 v5 ]]
D3.zoom() automatically maps wheel and mouse clicks to operations to zoom a map. I would like to be able to draw a rectangle in the area of the map to select nodes that appear on top of the map. I need to know how to add handlers for mousedown, mousemove, mouseup, so that I can track where the rectangle should be.
I have tried the following, but the mousedown callback is never invoked.
If I remove the .call(zoom), the mousedown callback is invoked, but e is undefined. I can access the event using d3.event, so that is not an issue.
If I move .call(zoom) after the .on(mouse*', cb)` calls, I see the mouse down, but no mouseup and only one mousemove.
I can sort of understand adding the mouse callbacks first, but I don't see why some of them are masked and others are not.
Clearly, I need some help understanding this.
var zoom = d3.zoom()
.scaleExtent([0.1, 10])
.filter(() => !d3.event.ctrlKey) // Don't zoom/pan when ctrl is pressed
.on("zoom", zoomed)
;
container
.call(zoom)
.on('mousedown.zoomrect', e=>console.log('zoom', e))
.on('mouseup.zoomrect', e=>console.log('zoom up', e))
.on('mousemove.zoomrect', e=>console.log('zoom move', e))
;
Locating the nodes in the rectangle is a separate question, but I believe I can handle the projection and transformations.

Racket GUI, drawing text vertically, issues with "angle" argument

I'm using the Racket GUI to write text in the window of my program.
Until now I only needed to draw text horizontally. But now I would also want to write text vertically. I saw in the documentation we can give an "angle" argument when we send the message "draw-text" to the drawing context.
Here's my little function to draw text :
(define (draw-text text fontsize x y color [rotate-angle 0.0])
(when (string? color)
(set! color (send the-color-database find-color color)))
(send bitmap-dc set-font (make-object font% fontsize 'default))
(send bitmap-dc set-text-foreground color)
(send bitmap-dc draw-text text x y [angle rotate-angle])
(update-callback))
But when I call the "draw-text" procedure with example given an angle of 90° (so that the text would be vertically) it doesn't change anything.
It's just displayed as before, horizontally.
Does someone know what's wrong?
It's not clear from the example, but did you remember to convert the 90 degrees into radians? The convention is that 360 degrees is the same as 2pi radians. Or dividing by 360, we get that 1 degree is 2pi/360 radians.
Multiplying by 90, the result is that 90 degrees is 90*2*pi/360 = 180pi/260 = pi/2 ~ 1.5707963267948966. That is, to rotate the text 90 degrees, use 1.5707963267948966 as the rotate-angle.
Also (send bitmap-dc draw-text text x y [angle rotate-angle])
should be
(send bitmap-dc draw-text text x y combine? offset? angle])
For example:
(send bitmap-dc draw-text "A text" 100 100 #t 0 1.570])

Draw an arrow in racket

How to draw an arrow in a frame in racket (DrRacket)? For example between two objects: a circle and a rectangle obtained by:
(send dc draw-ellipse 50 50 30 30) and (send dc draw-rectangle 200 200 30 6)
You can use picts to do such things.
First, you define your picts.
(define pict-a (rectangle 40 40))
(define pict-b (circle 40))
Then you combine them to be able to use rc-find or lc-find, which are the procedures that will help you connect those picts.
(define combined (hc-append 200 pict-a pict-b))
Finally
> (pin-arrows-line 30 combined
pict-a rc-find
pict-b lc-find
#:start-angle (/ pi 11)
#:end-angle (- (/ pi 11))
#:solid? #f)
Will produce this:
You can find more information in the docs! Tell us if that solved your problem!
What kind of arrows?
For simple arrows use draw-line directly.
For bended arrows use draw-spline.
Use a filled triangle as a simple arrow head.
If you need a prettier arrow head shape,
one option is to adapt the arrow shape from MetaPict.
You can find other examples of arrows in MetaPict's documentation.
An example with a non-straight arrow which shows how to draw a state machine with MetaPict.

openGL Texture masking

I am attempting to fill a circle with a series of other images and have those images masked off by the circle. I can see why this isn't working, but I can't come up with a solution as to how to fix it.
My drawing code (using processing) is as follows:
PGraphicsOpenGL pgl = (PGraphicsOpenGL) g; // g may change
// This fixes the overlap issue
gl.glDisable(GL.GL_DEPTH_TEST);
// Turn on the blend mode
gl.glEnable(GL.GL_BLEND);
// Define the blend mode
gl.glBlendFunc(GL.GL_SRC_ALPHA, GL.GL_ONE_MINUS_SRC_ALPHA);
// draw the backgroud
fill(200,200,200);
rect(0, 0, width, height);
// cut out the circle
gl.glBlendFunc(GL.GL_ZERO, GL.GL_ONE_MINUS_SRC_ALPHA);
tint(0,0,0,255);
image(circle, 0, 0);
// draw the circle
gl.glBlendFunc(GL.GL_ONE_MINUS_DST_ALPHA, GL.GL_ONE);
tint(140,0,0,255);
image(circle, 0, 100);
gl.glBlendFunc(GL.GL_ONE_MINUS_DST_ALPHA, GL.GL_ONE);
tint(140,0,140,255);
image(circle, 0, 0);
I have been following the directions at http://bigbucketsoftware.com/2010/10/04/how-to-blend-an-8-bit-slide-to-unlock-widget/ which seem to describe the effect that I want. I have also tried this on iphone with similar results.
Here is what I was expecting to happen, and what happened:
The problem must be with how you treat the transparent region. You could enable GL_ALPHA_TEST.
Or if your pictures stay that simple you can just draw them with triangles.
I can't really help you with the blending code but I have another suggestion that might simplify your drawing logic.
I have used the stencil buffer for something like that. I wanted to draw a disk textured with a linear grating. I didn't want to bother with texture coordinates because an important function was to be able to exactly step through the phases of the grating.
I drew the texture in a big rectangle and afterwards I drew in the stencil a white disk.
http://www.swiftless.com/tutorials/opengl/basic_reflection.html
(let ((cnt 0d0))
(defmethod display ((w window))
;; the complex number z represents amplitude and direction
;; of the grating constant
;; r and psi addresses different points in the back focal plane
;; r=0 will result in z=w0. the system is aligned to illuminate
;; the center of the back focal plane for z=w0.
(let* ((w0 (* 540d0 (exp (complex 0d0 (/ pi 4d0)))))
(r 260d0)
(psi 270d0)
(w (* r (exp (complex 0d0 (* psi (/ pi 180d0))))))
(z (+ w w0)))
(clear-stencil 0)
(clear :color-buffer-bit :stencil-buffer-bit)
(load-identity)
;; http://www.swiftless.com/tutorials/
;; opengl/basic_reflection.html
;; use stencil buffer to cut a disk out of the grating
(color-mask :false :false :false :false)
(depth-mask :false)
(enable :stencil-test)
(stencil-func :always 1 #xffffff)
(stencil-op :replace :replace :replace)
(draw-disk 100d0 (* .5d0 1920) (* .5d0 1080))
;; center on camera 549,365
;; 400 pixels on lcos = 276 pixels on camera (with binning 2)
(color-mask :true :true :true :true)
(depth-mask :false)
(stencil-func :equal 1 #xffffff)
(stencil-op :keep :keep :keep)
;; draw the grating
(disable :depth-test)
(with-pushed-matrix
(translate (* .5 1920) (* .5 1080) 0)
(rotate (* (phase z) 180d0 (/ pi)) 0 0 1)
(translate (* -.5 1920) (* -.5 1080) 0)
(draw *bild*))
(disable :stencil-test)
(enable :depth-test)
(fill-grating *grating* (abs z))
(format t "~a~%" cnt)
(if (< cnt 360d0)
(incf cnt 30d0)
(setf cnt 0d0))
(update *bild*)
(swap-buffers)
(sleep (/ 1d0)) ;; 1 frame per second
(post-redisplay))))

Resources