DrRacket: How to smoothly draw large bitmap on canvas - user-interface

(require racket/draw
mred)
(define bitmap-canvas%
(class canvas%
(init-field [bitmap #f])
(inherit get-dc)
(define/override (on-paint)
(send (get-dc) draw-bitmap bitmap 0 0))
(define/public (set-bitmap! new-bitmap)
(displayln "setting bitmap")
(set! bitmap new-bitmap))
(super-new)))
(define bitmap (read-bitmap
"some-stringPath-to-bitmap-source"))
(define f (new frame% [label "foo"] [width 100] [height 100]))
(define the-canvas (new bitmap-canvas% [parent f] [bitmap bitmap] [min-width 500] [min-height 500]))
(send f show #t)
I have to above code to show a bitmap within a Canvas, contained in a Frame. However, when the bitmap has large dimensions, (1200x900) for example, you cannot see all of it. How can I adapt the code so that the entire bitmap is scaled to fit in the canvas?
Thanks

Related

Racket GUI Toolkit: How to embed a link

Say we have a frame
(define my-frame (new frame% [parent #f] [label "test"]))
and a message, that should link to google.
(new message%
[parent my-frame]
[label "https://www.google.com"])
(send my-frame show #t)
The above does not work. How does one embed a link in the Racket GUI toolkit?
You can use the button, but I guess that isn't link-like so you don't want it, the following code shows how to use editor clickback to create a link-like text.
(require net/sendurl)
(define f (new frame% [parent #f]
[label "test"]
[width 300]
[height 300]))
(define editor (new text%))
(new editor-canvas% [parent f]
[editor editor])
(define t "https://www.google.com")
(send editor insert t)
(send editor set-clickback 0 (string-length t)
(λ (text start end)
(send-url t)))
(send* f
[show #t]
[center])

How to add an Image on a Frame in the Racket GUI Toolkit?

How can one add an image (for example png) onto a frame% object?
#lang racket
(define my-frame (new frame%))
;want to add an image to my-frame
Use a canvas.
(define my-frame (new frame%
[label "Example"]
[width 300]
[height 300]))
(new canvas%
[parent my-frame]
[paint-callback
(λ (canvas dc)
(send dc draw-bitmap (read-bitmap "/path/to/image.png") 0 0))])
(send my-frame show #t)

GUI component layout in Racket/Scheme

I am using following code for a small GUI program:
#lang racket/gui
(define ff (new frame%
[label "Adjust widths"]
[height 100]
[width 300]))
(new message% [parent ff][label "testing"])
(new text-field% [parent ff][label "tf1"])
(new text-field% [parent ff][label "tf2- a long prompt"])
(new text-field% [parent ff][label "tf3 "])
(new text-field% [parent ff][label "tf4 "])
(send ff show #t)
However, I am not able to get desired layout:
How can I get above layout. I see text-field and other components have min-width and stretchable-width. Which if these is default and which is actual is not clear to me. How can I fix the width of text-field? Should I use table-panel package for this? Thanks for your help.
Edit: I checked https://docs.racket-lang.org/gui/windowing-overview.html?q=gui and also tried different options such as [min-width 50] and [stretchable width #f] but apparently it is not possible to fix the size of text-field to a particular value.
One possibility is to first set the labels to the one of maximum width, then change them to the desired label. This works for me at least.
#lang racket/gui
(define ff (new frame%
[label "Adjust widths"]
[height 100]
[width 300]))
(new message% [parent ff][label "testing"])
(define strings
'("tf1" "tf2- a long prompt" "tf3" "tf4"))
(define str-max (argmax string-length strings))
(define txt-fields
(for/list ([str (in-list strings)])
(new text-field% [parent ff] [label str-max])))
(for ([tf (in-list txt-fields)]
[str (in-list strings)])
(send tf set-label str))
(send ff show #t)
Since fonts may not have a fixed width, you may want to use underscores for the string of maximum length.
Another possibility is to get rid of the text-field's label altogether by passing #f as argument and make your own using a message% for which you can actually control the width with min-width. You may need to put the message and the text-field in a horizontal-panel%.

How do I place GUI panels?

I'm doing a game project in Racket and I'm stuck on the graphical part. I want to create a frame like this:
There game-canvas is where I wanna load my game (game not mentioned in my code), the grey area is supposed to contain nothing (only grey colour) and the buttons are supposed to be used for the game (no callback procedures for the buttons at the moment.)
My code:
#lang racket/gui
(define *our-frame*
(new frame%
[width 600]
[height 800]
[x 1000]
[y 100]
[label "Label"]
[style '(no-resize-border)]
))
(define *game-panel*
(new vertical-panel%
[parent *our-frame*]
[style '(border)]
[alignment '(left center)]
))
(define *button-panel*
(new vertical-panel%
[parent *our-frame*]
[style '(border)]
[alignment '(right bottom)]
))
(define *game-button*
(new button%
[parent *button-panel*]
[label "Pause"]
[min-width 200]
[min-height 100]
))
(define *new-game-button*
(new button%
[parent *button-panel*]
[label "New Game"]
[min-width 200]
[min-height 100]
))
(send *our-frame* show #T)
This code will generate a frame with (at least what it looks like) two horizontal panels with the two buttons in the bottom right corner. How can I fix this so it appears as my picture? I've tried to change the alignment on the panels but nothing good came from that... Proberly something easy to fix but it's the first time I do graphical coding so I blame that...
Appreciates all answers!
EDIT:
In the code my button1 and button2 equals to Pause and New Game
A frame will stack panels on top of each other.
Therefore we need to make a row of two columns: a left column and a right column.
In the left column we put the game canvas and in the right we put your panel that has the buttons.
After adding the row, and the left/right columns one needs to adjust
the parent clauses so everything ends up in the right places.
#lang racket/gui
(define *our-frame*
(new frame%
[width 600]
[height 800]
[x 1000]
[y 100]
[label "Label"]
[style '(no-resize-border)]
))
(define *row*
(new horizontal-panel%
[parent *our-frame*]
[style '(border)]))
(define *left-column*
(new horizontal-panel%
[parent *row*]
[style '(border)]))
(define *right-column*
(new horizontal-panel%
[parent *row*]
[style '(border)]))
(define *game-panel*
(new vertical-panel%
[parent *left-column*]
[style '(border)]
[alignment '(left center)]
))
(define *button-panel*
(new vertical-panel%
[parent *right-column*]
[style '(border)]
[alignment '(right bottom)]
))
(define *game-button*
(new button%
[parent *button-panel*]
[label "Pause"]
[min-width 200]
[min-height 100]
))
(define *new-game-button*
(new button%
[parent *button-panel*]
[label "New Game"]
[min-width 200]
[min-height 100]
))
(send *our-frame* show #T)

scheme/racket: canvas manipulation

1) As title says, the objects i draw disappear when i resize the window, but the rectangle stays as is.
2) The origin starts from the top left, but i wish for it to be at the bottom left.
3) I couldn't find any zoom functions, other than in the plot library so if i wish to implement such a thing, one option would to be "zooming" in by drawing bigger objects and refreshing the canvas instead?
(define top-frame (new frame%
[label "KR"]
[width 500]
[height 500]))
;Make a frame by instantiating the frame% class
(define image (pict->bitmap (rectangle 50 50)))
(define canvas (new canvas%
[parent top-frame]
[paint-callback (lambda (canvas dc)
(send dc draw-bitmap image 0 0))]))
(define drawer (send canvas get-dc))
(send top-frame show #t)
; Show the frame by calling its show method
(define (draw-object x)
(sleep/yield 0.1)
(case (first x)
[("LINE") (send drawer draw-line
(second x) (third x)
(fourth x) (fifth x))]
[("CIRCLE") (send drawer draw-bitmap (pict->bitmap (circle (round (fourth x)))) (round (second x)) (round (third x)))]
[("POINT") (send drawer draw-point (round (second x)) (round (third x)))]
[else "Not drawing anything!"]))
(draw-object (find-specific-values (third list-of-objects)))
(map draw-object (map find-specific-values list-of-objects))
ad 1) "...the objects i draw disappear when i resize the window, ..."
When you resize a window the system needs to redraw the contents of the window. A redraw event is issued, and eventually the Racket GUI layer will call the paint-callback. Therefore: Make a function that does all the drawing. Call it from the paint-callback. See similar question here: https://stackoverflow.com/a/16086594/23567
ad 2) One option is to make a coordinate transformation in the drawing context. See set-transformation in the docs for dc<%>. It's someething like this:
(send dc set-transformation
(vector (trans->vector t)
0 0 ; x and y origin
1 -1 ; x and y scale
0)))
The -1 for the y-scale will flip the y-axis. You might want to move the origin.
ad 3) Zooming can be done by changing the x and y scale, and then redrawing.
You can try the scales to 1/2 -1/2 .

Resources