Styling UI in Racket
Written by Dominik Joe Pantůček on 2019-01-31
racketIt has been quite some time since we have discussed some interesting programming stuff we are doing here at Trustica. And - as you may have guessed - we have encountered quite a few things that needed to be done and apparently no-one has done them before. Read on to see how you can style UI elements in Racket.
Racket[1] is a powerful Scheme[2]-derived language that includes a plethora of utility libraries out of box. One of these libraries - it is better to say: collections[3] - allows you to quickly develop a cross-platform UI applications. It has been a few years now since we started using it for most of our back-end and support GUI software.
The GUI is composed of various widgets[4] but we typically use just the main window[5], plain drawing canvas[6] where we do our work and some action buttons[7]. This time we needed to ensure the text on the buttons is large enough so that it can be read even from a distance. Good thing is that the button widget can be configured to use whatever font you tell it to use:
(define button-font
(send the-font-list find-or-create-font
36 ; Size in pixels
"DejaVu Sans Mono" ; Font face
'default ; Font family
'normal ; Font style (italic...)
'bold)) ; Font weight
(define start-button
(new button%
(parent ...)
(label "Start")
(font button-font)
(callback callback-start)))
Firstly we get a reference to the font[8] structure using a global font list[9] object and secondly we tell the button widget to use it. Trouble is the button widget ignores the font we pass it.
But this is racket, so it is easy to extend any class and change any behavior we want to change. Therefore we create our own styled-button% class:
(define styled-button%
(class button%
(init [(internal-label label)]
[(initial-color color) "black"]
[(internal-font font) normal-control-font])
(define label internal-label)
(define font internal-font)
(super-new [label (make-label label font initial-color)]
[font font])
(define/override (set-label l)
(set! label l)
(super set-label l))
(define/private (make-label label font color)
(cond
[(string? label)
(match-define-values (w h _ _)
(send text-size-dc get-text-extent label font))
(define new-label (make-object bitmap% (exact-ceiling w) (exact-ceiling h) #f #t))
(define dc (new bitmap-dc% [bitmap new-label]))
(send dc erase)
(send dc set-font font)
(send dc set-text-foreground color)
(send dc set-text-mode 'transparent)
(send dc draw-text label 0 0)
new-label]
[else label]))
(define/public (set-color c)
(define new-label (make-label label font c))
(super set-label new-label))))
As you can see, it passes on everything as is to the underlying button% class but in case of text label, it is pre-rendered onto a bitmap[10] canvas. This is actually just a sample code from StackOverflow[11] extended to allow not only color change but also customizing the font.
Using the new styled-button% class is extremely easy:
(define start-button
(new styled-button%
(parent ...)
(label "Start")
(font button-font)
(callback callback-start)))
And as you can see in Picture 1 below, the result looks pretty neat!
Picture 1: Large font in GUI buttons Once again we have proved that Racket is extremely flexible tool - even if you want to do relatively simple things. One can only guess why there are not more people programming in this Scheme-based language.
Hope you share our excitement about the tools we use and stay tuned for more information about Cryptoucan™ soon!
References
-
Wikipedia contributors. (2019, January 16). Scheme (programming language). In Wikipedia, The Free Encyclopedia. Retrieved 07:08, January 31, 2019, from https://en.wikipedia.org/w/index.php?title=Scheme_(programming_language)&oldid=878631642
-
https://stackoverflow.com/questions/48414363/how-to-change-the-color-of-text-in-a-racket-gui-button