Text widgets
Some of the widgets included in EWS are able to show text. In this chapter we will show some of them, and use the occassion to introduce a few new components of EWS.
In the same way that EWS does not have a predefined look for buttons
or mouse pointers, EWS does not have a predefined look for text. Text is
shown using fonts, which are objects of type FONT
. This class
is actually deferred, allowing specific implementations; some of them
may be tied to a display type. Note that the structur is similar to what
you have with IMAGE
.
At the moment the only kind of font implemented for the SDL backend is
a class called SDL_BITMAP_FONT
(An implementation of TrueType
fonts will be added later). These are variable-spacing, bitmapped fonts.
The bitmap can have smooth borders (working as antialiasing), and textures
(is not necessarily monochrome).
Bitmap fonts can be loaded from image files; the image file should contain all the glyphs from ASCII 33 onwards (up to ASCII 128 if you want; international text is not supported yet). The glyphs are separated by magenta pixels at the top row of the image (where magenta is 100% red, 0% green, 100% blue, completely opaque). This is a magnified piece of a font, showing the first few characters (this is not an actual font, just a screenshot of the gimp show the font with zoom):
Note the magenta lines at the top marking the limits of each glyph. You can use one or more magenta pixels to mark glyph separations. Note that the areas below magenta pixels are ignored, if you want to add spacing to the font add transparent space at the sides of the glyph but outside the magenta separators. By the way, the font should have a transparent background (using a GIF or PNG image) to mix properly with the text background; in the screenshot the background is shown as black. (Just if you're wondering, this font format came from JEGL, a set of Eiffel-SDL bindings that I used as a starting point for the library).
A few fonts are included with the demos.
The following code is from two of the included themos; one of them show labels and the other shows text entries:
Source: font_test.e
class FONT_TEST inherit TEXT_CONSTANTS create make feature {NONE} -- Creation d: SDL_DISPLAY c: MOUSE_POINTER new_img (fn: STRING): IMAGE is do create {SDL_IMAGE}Result.make_from_file (fn) end make is local font2: FONT rect: RECTANGLE label: LABEL multi: MULTILINE_LABEL w1: WINDOW_IMAGE marq: HORZ_MARQUEE do -- Init video create {SDL_DISPLAY}d.make (640,480, 16, false) -- Raw Writing - d.set_default_font (create {SDL_BITMAP_FONT}.make ("small_font.png")) create {SDL_BITMAP_FONT}font2.make ("white_font.png") -- Labels rect.set_with_size(5, 420, 190, 50) create label.make(d.root, rect, "Hi! I'm a label") label.set_bg (create {SDL_SOLID_IMAGE}.make (label.width, label.height, 30, 40, 50)) rect.set_with_size(200, 420, 235, 50) create label.make(d.root, rect, "I'm right-bottom aligned with a border") label.set_bg (create {SDL_SOLID_IMAGE}.make (label.width, label.height, 30, 90, 100)) label.set_h_alignment (horz_align_right) label.set_v_alignment (vert_align_bottom) label.set_border_width (4) rect.set_with_size(445, 420, 190, 50) create label.make(d.root, rect, "My own font") label.set_bg (create {SDL_SOLID_IMAGE}.make (label.width, label.height, 100, 200, 50)) label.set_font (font2) rect.set_with_size(480, 390, 40, 20) create label.make(d.root, rect, "I'm too big for my boots") label.set_bg (create {SDL_SOLID_IMAGE}.make (label.width, label.height, 80, 80, 80)) -- Multiline label rect.set_with_size (20, 20, 100, 120) create multi.make (d.root, rect, "This is a very long text that must be splitted over several lines to be displayed.%NLuckily, we have a multiline label to do that") multi.set_h_alignment (0.5) -- Rectangles (background for the marquee too) create w1.make (d.root, 300, 200, create {SDL_SOLID_IMAGE}.make (100, 100, 200,0,0)) create w1.make (d.root, 400, 200, create {SDL_SOLID_IMAGE}.make (150, 100, 0,0,200)) -- Marquee rect.set_with_size(350, 250, 150, 20) create marq.make(d.root, rect, "Hello. I am a Horizontal Marquee. Horizontal Marquees make your life easier allowing you to show extremely long texts in drastically short spaces, with almost no effort. Make you life easier today. Enjoy your own Horizontal Marquee.") -- Make pointer create c.make (new_img ("cursor1.png"), 6, 4) -- Set Pointer d.root.set_pointer (c) -- Main loop d.set_timer_interval (100) d.do_event_loop d.close end end -- class FONT_TEST
I won't explain code similar to the previous examples (display
initialization, cursor setting, new_img
wrapper, etc.)
You might note that this class inherits from TEXT_CONSTANTS
this is an utility class defining several text alignment constants, as you
might check seeing its short form.
Let's take a look at:
d.set_default_font (create {SDL_BITMAP_FONT}.make ("small_font.png"))
Note that this creates a new SDL_BITMAP_FONT
, the
argument is an image file formatted as explained above. You can download
the font file small_font.png to check
it out (I'm not including font images in this document, they are too
wide). It is also included in the EWS distribution. This new created font
is passed to the set_default_font
routine of the display.
This default font will be used for widgets that don't have set another
specific font.
We now then create a different font and attach it to font2
using the file white_font.png.
create {SDL_BITMAP_FONT}font2.make ("white_font.png")
With that done, we can now add some text widgets:
-- Labels rect.set_with_size(5, 420, 190, 50) create label.make(d.root, rect, "Hi! I'm a label") label.set_bg (create {SDL_SOLID_IMAGE}.make (label.width, label.height, 30, 40, 50))
A new EWS class is used here, RECTANGLE
.
RECTANGLE
is an expanded class representing rectangles with
the sides parallel to the screen. It is used all over EWS (internals and
interface) to represent positions and sizes. It is not a graphic
element; it is used for geometry. If you check the short form of this
class you will se that it has a lot of operations but all of them are
quite obvious. Get used to RECTANGLE
manipulation because you will be
doing a lot of it while programming EWS.
The first line in the last code block shown configures the rectangle
rect
at position (5,420), with width 190 and height 50. After
that, a new LABEL
is created at the display root, using the
position and size given in the rectangle, and with the greeting message
"Hi, I'm a label!". Labels are simple widgets that show a
text message. They have no behaviour, but you will see that they have lots
of features to control their presentation. The above code-block shows one
of them: set_bg
, which takes an image that will be used as
background behind the label. Otherwise, the label lets you see what is behind
it.
In this case we are also introducing a new kind of IMAGE
implemented in the SDL driver, which is SDL_SOLID_IMAGE
.
This image is a solid rectangular color block; the first two arguments
of its creation call are the image size, and the remaining three the
red, green, and blue color components.
30,40,50 is a dark blue
color like the background of this text
rect.set_with_size(200, 420, 235, 50) create label.make(d.root, rect, "I'm right-bottom aligned with a border") label.set_bg (create {SDL_SOLID_IMAGE}.make (label.width, label.height, 30, 90, 100)) label.set_h_alignment (horz_align_right) label.set_v_alignment (vert_align_bottom) label.set_border_width (4)
Here we create a new label and attach it to label
.
Again, we use a
background color, but a different one. Besides we set the label
alignment to the bottom right of the label rectangle. Note that the
label text, depending on the font and what is written, may be bigger or
smaller than the label window. Usually the text is horizontally and
vertically centered, but the set_h_alignment
and
set_v_alignment
features allow you to change that. You can
also reserve a small space from the border of the window calling
set_border_width
; in this case the label will hava a 4
pixel border separting it from the bottom right corner.
rect.set_with_size(445, 420, 190, 50) create label.make(d.root, rect, "My own font") label.set_bg (create {SDL_SOLID_IMAGE}.make (label.width, label.height, 100, 200, 50)) label.set_font (font2)
Here we have yet another label, using font2
instead of the
default font.
rect.set_with_size(480, 390, 40, 20) create label.make(d.root, rect, "I'm too big for my boots") label.set_bg (create {SDL_SOLID_IMAGE}.make (label.width, label.height, 80, 80, 80))
This label shows what happens when the rectangle is too small. The text will be clipped to fit inside the window.
-- Multiline label rect.set_with_size (20, 20, 100, 120) create multi.make (d.root, rect, "This is a very long text that must be splitted over several lines to be displayed.%NLuckily, we have a multiline label to do that") multi.set_h_alignment (0.5)
This code block shows a slightly different widget, the
MULTILINE_LABEL
. It allows showing long pieces of text by
splitting them in new lines. It also handles newline ( '%N') characters
properly. Note that the rectangle assigned above is taller, and the alignment
is set to centered. By default it splits lines at word boundaries, but you
can change that using set_wordwrap
.
-- Rectangles (background for the marquee too) create w1.make (d.root, 300, 200, create {SDL_SOLID_IMAGE}.make (100, 100, 200,0,0)) create w1.make (d.root, 400, 200, create {SDL_SOLID_IMAGE}.make (150, 100, 0,0,200)) -- Marquee rect.set_with_size(350, 250, 150, 20) create marq.make(d.root, rect, "Hello. I am a Horizontal Marquee. Horizontal Marquees make your life easier allowing you to show extremely long texts in drastically short spaces, with almost no effort. Make you life easier today. Enjoy your own Horizontal Marquee.")
The first two lines here create a blue window and a red window, side
by side; they will be used to show text without background over them.
The next widget created is a variant of label, the
HORZ_MARQUEE
. This widget shows its text scrolling from
right to left, so you will be able to read the whole text even when the
window is smaller than the text. It is not to use frequently, but it is
interesting to give a first glimpse at EWS animation capabilities. You
will not that the message does not scroll unless you also include this
line:
d.set_timer_interval (100)
This enables an internal timer of the display, which generate events periodically, allowing you to synchronize timed widgets. The timer is set here at a 100ms interval. You can play around with the interval to see the marquee scroll at different rates. Note that most systems don't have enough resolution to set this value under 10 milliseconds reliably.
The above application, when running, looks like this:
We will see here shortly another of the included examples:
Source: entry_test.e
class ENTRY_TEST create make feature {NONE} -- Creation d: DISPLAY e1, e2: TEXT_ENTRY new_img (fn: STRING): IMAGE is do create {SDL_IMAGE}Result.make_from_file (fn) end make is local r: RECTANGLE c: MOUSE_POINTER sdl: SDL i: IMAGE w: WINDOW f: SDL_BITMAP_FONT do -- Init video create {SDL_DISPLAY}d.make (640,480, 16, False) -- Set Pointer create c.make (new_img ("cursor1.png"), 6, 4) d.root.set_pointer (c) -- Background create {SDL_IMAGE}i.make_from_file ("entry.png") create {WINDOW_IMAGE}w.make (d.root, 20, 20, i) create {WINDOW_IMAGE}w.make (d.root, 20, 50, i) create f.make ("default_font.png") r.set_with_size (20, 20, 124, 24) create e1.make (d.root, r) e1.set_font (f) e1.set_border_size (5) r.set_with_size (20, 50, 124, 24) create e2.make (d.root, r) e2.set_font (f) e2.set_border_size (5) e1.set_next_in_tab_order (e2) e1.set_default_action(agent e2.grab) e2.set_next_in_tab_order (e1) e2.set_default_action(agent print_contents) sdl.enable_keyboard_repeat (250, 50) e1.grab -- Main loop d.do_event_loop d.close rescue if d /= Void then d.close end end print_contents is do print (e1.text + "%N") print (e2.text + "%N%N") end end -- class ENTRY_TEST
You should be able now to read most of this code and understand what it does. Let's jump to the interesting part:
r.set_with_size (20, 20, 124, 24) create e1.make (d.root, r) e1.set_font (f) e1.set_border_size (5) r.set_with_size (20, 50, 124, 24) create e2.make (d.root, r) e2.set_font (f) e2.set_border_size (5)
This attachs to e1
and e2
new instances
of TEXT_ENTRY
. This widget looks a lot like a label, but you
can edit its text. It has some operations similar to label, like
set_font
and set_border_size
. It has a few
extra interesting operations:
e1.set_next_in_tab_order (e2) e1.set_default_action(agent e2.grab)
The text entry is one of the widgets that can get "focus". Having focus means that it will get the keyboard input. If you run the example you will note that clicking on one of the two entries moves the text cursor to the entries. That is because the entry behavior is programmed to grab the focus when being clicked. Other way to switch focus is to tab-cycle between the widgets (i.e., pressing the tab key repeatedly). To make that work, you need to define the sequence of widgets that will cycle pressing the TAB key. The first line is doing exactly that.
A way to forcefully set the focus on a widget is to call the procedure
grab
. grab
is defined in WINDOW
,
and makes the window to take the focus.
The procedure set_default_action
of entries allows you
to assign an action that will be called when pressing the Enter key while
the focus is in the entry. So, the code above configures e1
to
give the focus to e2
when pressing Enter (you probably have seen
this behaviour in some username/password dialogs).
e2.set_next_in_tab_order (e1) e2.set_default_action(agent print_contents)
Here we can see that pressing TAB with focus in e2
will
send the focus back to e1
, while pressing Enter on
e2
will call to print_contents
. This last
procedure was defined in our example in the following way:
print_contents is do print (e1.text + "%N") print (e2.text + "%N%N") end
You can see that you can retrieve the content of the entries calling
their function text
. You can also modify the text in any text
widget calling set_text
(not shown in this example).
You can also see that the example calls:
e1.grab
This is to set the focus on the first entry at the beginning; otherwise you should have to click one entry before being able to write.
This finishes our tutorial on using widgets. Working with other kinds
of widgets is similar to what was shown in the previous chapter and this
one. Take some time to read the short form of the widget classes
(installed as widgets/*.e
) on your installation directory,
and the examples included with the documentation (installed at
/usr/share/doc/ews/test). The examples cover all the widget kinds.
After this, we will move to explaining EWS at a lower level, which will allow us to design our oun windows/widgets.
Previous | Table of contents | Next |