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:
( 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.
very nice!
ReplyDelete