Mail with GUI
Sunday, April 17, 2011
One of the examples that is used to demonstrate Factor to new users is sending an e-mail. Using the smtp vocabulary, all you need to send an email is:
IN: scratchpad <email>
{ "jane@foobar.com" } >>to
"Up for lunch?" >>subject
"At Tracy's." >>body
send-email
Note: you might need to configure your SMTP settings before this works.
with-ui
That’s nice, but wouldn’t it be neat if we could use the UI to build a compose window that can send emails in a more graphical manner? Perhaps something like this:
We’re going to use words from several vocabularies:
USING: accessors arrays colors.constants kernel smtp ui
ui.commands ui.gadgets ui.gadgets.borders ui.gadgets.buttons
ui.gadgets.editors ui.gadgets.labels ui.gadgets.scrollers
ui.gadgets.tracks ui.pens.solid ;
We define a type of track layout that holds editor gadgets for each of the fields we need to receive input for. We will set the “To:” field to have focus first when the window is displayed.
TUPLE: mail-gadget < track to subject body ;
M: mail-gadget focusable-child* to>> ;
We build the UI using words that layout each of the main features:
: <to> ( mail -- gadget )
to>> "To:" label-on-left ;
: <subject> ( mail -- gadget )
subject>> "Subject:" label-on-left ;
: <body> ( mail -- gadget )
body>> <scroller> COLOR: gray <solid> >>boundary ;
Using the command framework, we can create commands for “Send” and “Cancel” and configure it so a toolbar could be created automatically.
: com-send ( mail -- )
<email>
over to>> editor-string 1array >>to
over subject>> editor-string >>subject
over body>> editor-string >>body
send-email close-window ;
: com-cancel ( mail -- )
close-window ;
mail-gadget "toolbar" f {
{ f com-send }
{ f com-cancel }
} define-command-map
Finally, we make a word that creates our mail gadget:
: <mail-gadget> ( -- gadget )
vertical mail-gadget new-track
1 >>fill
{ 10 10 } >>gap
<editor> >>to
<editor> >>subject
<multiline-editor>
10 >>min-rows
60 >>min-cols
>>body
dup <to f track-add
dup <subject> f track-add
dup <body> 1 track-add
dup <toolbar> f track-add ;
And a simple word to open the gadget in a new “compose” window (with a 5-pixel border for aesthetic reasons):
: open-compose-window ( -- )
<mail-gadget>
{ 5 5 } <border> { 1 1 } >>fill
"Compose" open-window ;
Bonus
You can even print the mail gadget out in the Listener to see how it looks. Note: it’s fully functional, so be careful clicking those buttons!
Some things we could do to improve this simple example:
- Implement TAB support to move easily between fields.
- Popup error dialog if not all fields are filled out properly.
- Better align the “To:” and “Subject:” text fields.
- Support multiple “To:” addresses.
- Prompt “Are you sure?” before closing the window when clicking “Cancel”.
- Don’t close the Listener when clicking buttons (with “
gadget.
”).
The code for this is on my GitHub.