How to set frame's background in Racket? - user-interface

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

Related

How to use the DXGI flip model in a Direct2D windowed app?

I have a Win32 non-game windowed app that uses a Direct2D device context/HWND render target to draw a window. Currently it uses a DXGI swap chain with the DXGI_SWAP_EFFECT_DISCARD swap effect.
Microsoft recommends using the new flip model swap effects, either DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL or DXGI_SWAP_EFFECT_FLIP_DISCARD. I'm interested in using them primarily because they would allow me to specify a list of dirty rects when calling Present1(), which should improve performance/power usage.
Simply changing the SwapEffect to either of the new flip model values produces a weird (but actually expected) result of drawing a black window each second frame, with artifacts of the previous frames visible onscreen.
So the question is: is it possible to use the new flip model swap effects in this situation, and if yes, how should things be set up?
Given that the app needs to draw the dirty rects into an otherwise valid buffer, it seems that a correct approach would involve maintaining two buffers with essentially the same content (one to draw into, and one to give to the DWM for composition), so not sure if it would be possible to achieve any performance gains this way in an app that doesn't redraw each frame completely. But perhaps I'm missing something important.
The swap chain is currently set up as follows:
swapChainDesc.Width = ...;
swapChainDesc.Height = ...;
swapChainDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
swapChainDesc.Stereo = false;
swapChainDesc.SampleDesc.Count = 1;
swapChainDesc.SampleDesc.Quality = 0;
swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
swapChainDesc.BufferCount = 1;
swapChainDesc.Scaling = DXGI_SCALING_STRETCH;
swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
swapChainDesc.AlphaMode = DXGI_ALPHA_MODE_UNSPECIFIED;
swapChainDesc.Flags = 0;
EDIT 1
It turns out that DXGI_SWAP_EFFECT_DISCARD forces BufferCount to 1, so my initial value of 2 was somewhat misleading, as only one buffer is used. Source (3rd comment).
Also the docs for DXGI_SWAP_EFFECT say that UWP apps are forced into the flip model, so this should be a solvable problem.
There are two good ways to do it.
The first way is a little heavier on energy usage. You can draw your contents into an intermediate buffer/render texture, and copy it to swapchain just before every present. That way you can only actually render the parts that changed in your intermediate buffer, and not care about what the state of the swapchain is.
The second way is more complicated, but can yield optimal energy usage. Instead of using intermediate buffer and drawing only what changes since the last frame there, you draw directly into the swapchain buffer. For this to work correctly, you need to redraw not what changes between current and last frame, but between current and (current - BufferCount) frame. For instance:
Frame 1 - you draw a green rectancle at (200 x 200) with dimensions of (150 x 150). The dirty region is entire frame because it's the first frame.
Frame 2 - you draw a blue rectangle at (250 x 250) with dimensions of (50 x 50). The dirty region is (250, 250, 300, 300).
Frame 3 - you draw a red rectangle at (225 x 225) with dimensions of (50 x 50). The dirty region is (225, 225, 50, 50).
If your buffer count is 2, that means when you draw frame 3, you need to not only redraw the dirty region of (225, 225, 50, 50), but also the dirty region of (250, 250, 300, 300).

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))))

GUI elements in (Dr) Racket

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.

Resources