More Related Content
Similar to Graphical User Interface Development with Eqela
Similar to Graphical User Interface Development with Eqela (20)
More from jobandesther (7)
Graphical User Interface Development with Eqela
- 3. Copyright © 2014 Job and Esther Technologies
Graphical user interface
development with Eqela
- 4. Copyright © 2014 Job and Esther Technologies
General approach
Widgets
Reusable user interface elements or components
Provide one or both of the following:
− Draws something graphically on the screen
− Reacts to user input, such as mouse pointer events, touch
events, and/or keyboard events
Represent rectangular areas on the screen, the basic
parameters of which are the x/y coordinates, width and
height
Are by default transparent, and can thus represent any
kind of shape (not just rectangles)
- 5. Copyright © 2014 Job and Esther Technologies
General approach
Widget hierarchies
The way to combine widgets together to form a complete user
interface is through means of adding widgets as children of
other widgets.
Example:
Container widget
(dark gray box)
Text box
(search)
Button
(OK)
Button
(Cancel) Child widgets
Parent/root widget
User interface
- 6. Copyright © 2014 Job and Esther Technologies
General approach
Rendering model
Displaying the visual representation of the widget is
called rendering
The Eqela framework calls the render() method of the
root widget to draw a part (or all) of a screen
- 7. Copyright © 2014 Job and Esther Technologies
General approach
Input events
Pointer events for mouse-based devices
− “pointer-enter”, “pointer-leave”, “pointer-move”, etc.
Touch events for touch-based devices
− An event signifying that a press on the screen was started, the finger was
moved, released, etc.
Keyboard events for devices with a keyboard, and/or key
presses performed on a virtual on-screen keyboard
Incoming pointer/touch events will always be sent to the root
widget of the application.
For keyboard events, the focused widget will be the one to
automatically receive any keyboard events.
- 8. Copyright © 2014 Job and Esther Technologies
General approach
Application windows
In other GUI frameworks, there is
a concept of a “window” that is
used as the top level container for
UI elements.
In Eqela,there is no requirement of
a “window”, but all UI elements
are widgets.
− An Eqela GUI app, the main
application class is a widget.
− The main “window” is an instance of
a widget.
- 9. Copyright © 2014 Job and Esther Technologies
Common concepts
Colors
Represented by com.eqela.libgui.Color class
Color components: red, green, blue, and alpha
Represented as double precision floating point
numbers.
Eqela GUI framework does not make any
determination as to how many colors would be
available.
− No limitation by Eqela
− Limitations will come from the underlying platform and
hardware
- 10. Copyright © 2014 Job and Esther Technologies
Color information can be supplied to the framework in
two ways:
− As a string with a double-digit hex-coded value for each
component.
− Color components can also be supplied directly as four
double-precision floating point numbers.
Common ways:
var mycolor1 = Color.instance("#FF0000"); // construct a red color
var mycolor2 = Color.instance(null);
mycolor2.parse("#FF0000"); // equivalent to above
var mycolor3 = Color.instance_double(1.0, 0.0, 0.0, 1.0); // red also
var mycolor4 = Color.instance("#000000").set_r(1.0); // red
var str1 = mycolor1.to_string(); // returns "#FF0000FF"
var str2 = mycolor1.to_rgb_string(); // returns "#FF0000"
- 11. Copyright © 2014 Job and Esther Technologies
Common concepts
Fonts and text
General approach
− Eqela uses the system fonts through the native APIs, and
does not introduce any new fonts or font libraries in itself.
− Any font information supplied to Eqela will relate to the font
database of the underlying operating system or platform.
Font objects
− com.eqela.libgui.Font
Describes the name, size and style of the font to be used.
− Constructing a Font object can be done as follows:
var myfont = Font.instance("bold 10mm Arial"); // bold, 1cm high arial
var defaultfont = Font.instance(); // default font
var largefont = Font.instance("50mm"); // 5cm high default face
- 12. Copyright © 2014 Job and Esther Technologies
Font objects
− The components can be a combination of the following:
Size information (in “mm” or “px”)
Font face/family name (eg. “Arial”)
Font style (eg. “bold” or “italic”)
− The Font object instance is not the font itself, but a
description of it
− If the specific font is not available, then the closest match
will end up displayed
Text layouts
− Drawing of text is done through an assistance mechanism
referred to as a text layout.
Text is laid out first, and the layouts are then passed to the rendering
API
- 13. Copyright © 2014 Job and Esther Technologies
Text layouts
− To create a text layout, the for_properties() static method in
the com.eqela.libgui.TextLayout class must be used.
− Requires three parameters:
A com.eqela.libgui.TextProperties class instance
A com.eqela.libgui.Frame class instance
A DPI value
− Example of creating a simple text layout:
var layout = TextLayout.for_properties(TextProperties.instance()
.set_text("This is my text")
.set_font(Font.instance("10mm"))
.set_color(Color.instance("#FF0000")), get_frame(), get_dpi());
- 14. Copyright © 2014 Job and Esther Technologies
Common concepts
Images
General approach
− The Eqela framework does not requires for images to be of
any specific format
− Precise format support is platform dependent: All platforms
support at least PNG and JPG
− Eqela utilizes the functionalities offered by the underlying
platform for imaging support where possible.
- 15. Copyright © 2014 Job and Esther Technologies
Reading images from files
− Reading of an image from a file is done with the read_file()
method:
* As long as the file format is supported by the underlying platform, the
image object is returned and usable.
Icon resources
− An "icon" is thought to be a resource of an application, and can be
retrieved by a short name or id rather than by a full pathname.
− Icons can be retrieved from the underlying system through the use
of the for_resource() method of Image. The preferred method,
however, is to use IconCache:
var image = Image.for_file(File.for_eqela_path("/my/test.png"));
var image = Image.for_resource("arrow_up");
var img2 = IconCache.get(“arrow_up”);
- 16. Copyright © 2014 Job and Esther Technologies
Icon resources
− The exact storage location of an icon is very much platform
dependent. However, all image files placed in the source
code directory will be considered an icon resource.
− Example of a source code directory:
− The .png files above could be retrieve in the application as
follows:
Main.eq
SecondaryWidget.eq
TestWidget.eq
arrow_up.png
arrow_down.png
var up = IconCache.get("arrow_up");
var down = IconCache.get("arrow_down");
- 17. Copyright © 2014 Job and Esther Technologies
Resizing images
− To resize an image, use the resize() method of Image:
* This would make a new copy of the image "img", and resize it to 100x100 pixels.
Note that the original image is not modified.
var newimage = img.resize(100, 100);
- 18. Copyright © 2014 Job and Esther Technologies
Common concepts
Length, sizes and positions
Units and sizes
− The following units are accepted by Eqela as length/size
specifications:
“px” - pixels
"mm" - millimeters
"um" - micrometers
"nm" - nanometers
"in" - inches
Example:
"100px" - one hundred pixels
"10mm" - ten millimeters (which is one centimeter)
"1in" - one inch
- 19. Copyright © 2014 Job and Esther Technologies
Units and sizes
− It is a very strong recommendation to use physical sizes
when implementing the user interfaces of their applications.
− Use either inches, millimeters, nanometers or micrometers,
(instead of pixel values), to retain the look of the user
interface regardless of the density and type of the screen
used.
The Length class
− The support for the different units is practically made
available through the eq.gui.Length class.
This can be used to convert the different units into pixels.
Example:
var tenmm = Length.to_pixels("10mm", get_dpi());
var up = IconCache.get("arrow_up", tenmm, tenmm);
- 20. Copyright © 2014 Job and Esther Technologies
The px method
− The eq.gui.Widget offers a shortcut to convert the different
units into pixels
− Using the px() method:
Size types
− Commonly used size types available in the Eqela GUI API:
− com.eqela.libgui.Size, com.eqela.libgui.Position,
com.eqela.libgui.Rectangle
− These can be constructed as follows:
var tenmm = px("10mm");
var up = IconCache.get("arrow_up", tenmm, tenmm);
var size = Size.instance(100, 200); // width=100, height=200
var position = Position.instance(10, 20); // x=10, y=20
var rect = Rectangle.instance(10,20,100,200); // combination of the two
- 21. Copyright © 2014 Job and Esther Technologies
Developing widgets
Creating a new widget
To create a new widget, simply inherit either the
com.eqela.libwidget.Widget class or another class that
is derived from it.
A very basic widget can be created as follows:
* This is a full-featured widget, can be used as an application main class and added to
other widgets.
class MyWidget : Widget
{
}
- 22. Copyright © 2014 Job and Esther Technologies
A slightly more useful example is here:
− This widget is derived from
com.eqela.libwidget.LabelWidget.
class MyLabelWidget : LabelWidget
{
public MyLabelWidget() {
set_text("This is my text");
}
}
- 23. Copyright © 2014 Job and Esther Technologies
Developing widgets
Widget lifecycle
1. Constructed
An instance of the class is created and the constructor of
the class has been called
1. Initialized
The widget has been added to another widget that itself
has been added to a widget engine backend.
1. Started
The widget becomes visible on the screen.
- 24. Copyright © 2014 Job and Esther Technologies
Developing widgets
Drawing your widget
The render method
− To create a widget that draws itself, simply inherit the
com.eqela.libwidget.Widget class.
− Then override the render() method of the Widget.
* The override specifier is optional but recommended.
class MyRenderableWidget : Widget
{
public override Collection render() {
}
}
- 25. Copyright © 2014 Job and Esther Technologies
Example of rendering
class MyRenderableWidget : Widget
{
public Collection render() {
var v = LinkedList.create();
int sz = px("30mm");
v.add(new FillColorOperation().set_shape(RectangleShape
.create(0, 0, get_width(), get_height()))
.set_color(Color.instance("#FF0000")));
v.add(new FillColorOperation().set_shape(RectangleShape
.create(0, 0, sz, sz))
.set_color(Color.instance("#00FF00"))
.set_x((get_width() - sz) / 2).set_y((get_height() - sz)/2));
return(v);
}
}
- 26. Copyright © 2014 Job and Esther Technologies
Animation
− The AnimationListener interface can be implemented to react to changes in /
progression of animations.
− Animations are executed by various means: Eg. activate() method or
ChangerWidget, or many of the methods of Widget, eg. Resize(), move_resize(),
move(), set_scale(), set_rotation(), set_alpha(), set_align*()
− Consider the following example:
class Main : LayerWidget
{
String color;
MyWidget mw;
public void initialize() {
base.initialize();
mw = new MyWidget();
add(mw);
}
public void start() {
base.start();
move_resize_child(mw, 0, 0, 100, 100);
}
}
- 27. Copyright © 2014 Job and Esther Technologies
public class MyWidget : ChangerWidget, AnimationListener
{
Widget current;
Widget next;
String color;
public void nextcolor() {
if (color.equals(“#FF0000”)) {
color = "#00FF00";
}
else if ("#00FF00".equals(color)) {
color = "#FF0000";
}
next = CanvasWidget.for_color(Color.instance(color));
add_changer(next);
activate(next, true, this);
}
public void on_animation_listener_end() {
remove(current);
current = next;
nextcolor();
}
public void start() {
base.start();
color = "#FF0000";
nextcolor();
}
}
What does this program do?
- 28. Copyright © 2014 Job and Esther Technologies
Making widget layouts
Review on the basics
Widgets can be added as children of other widgets.
− Creates a widget tree
Each widget has a parent and can have multiple
children.
X position, y position, width, and height are inherent
attributes.
− Determines the location of the widget in relation to the parent.
Layout widgets are standard widgets
− Their purpose is not to draw themselves, but to position child
widgets in accordance to layout rules.
- 29. Copyright © 2014 Job and Esther Technologies
Making widget layouts
Sizing mechanism
Key concepts:
− The size of the widget is determined by its width and its
height.
It is the parent of the widget that will assign a size to each widget.
− The size request of a widget is determined by a width request
and a height request.
The actual size and the size request do not always match
It is legal for a widget to change its size request
dynamically based on a size it has been assigned.
− eg. A multiline label does this when its width has been set,
after which its height request gets recomputed based on the
flow of the text given the new width.
- 30. Copyright © 2014 Job and Esther Technologies
A widget can set its size request in the initialize()
method as follows:
* Always draw to the actual size that can be retrieved using get_width() and
get_height().
* Never assume that the size request has been granted.
class MyWidget : Widget
{
public override void initialize() {
set_size_request(px("40mm"), px("10mm"));
}
}
- 31. Copyright © 2014 Job and Esther Technologies
Making widget layouts
Layout widgets
com.eqela.libwidget.ContainerWidget
− Not to be used in actual layouts.
− It is a base class that is inherited by most of the layout
widgets in the Eqela GUI API.
− Handles the basic functionality
Add child widgets
Tracking and forwarding events to child widgets
− Not implemented in ContainerWidget is the virtual method
arrange_children()
To develop a layout widget would be to inherit the ContainerWidget,
then implement the arrange_children() method.
- 32. Copyright © 2014 Job and Esther Technologies
com.eqela.libwidget.LayerWidget
− Lays out all its child widgets on top of each other.
− Each child widgets have the same location and size as the
parent LayerWidget
Example:
class MyLayerWidget : LayerWidget
{
public override void initialize() {
base.initialize();
add(LabelWidget.instance().set_text("First label")
.set_color(Color.instance("#FFFFFF")));
add(LabelWidget.instance().set_text("Second label")
.set_color(Color.instance("#FFFFFF")));
}
}
- 34. Copyright © 2014 Job and Esther Technologies
com.eqela.libwidget.AlignWidget
− Offers a way to flexibly position a widget inside another
widget while also honoring the size requests of the child
widget
− Two extra attributes for alignment:
Horizontal: -1 (far left), 0 (middle), or 1 (far right)
Vertical: -1 (topmost), 0 (middle), or 1 (bottom)
Example:
class MyAlignWidget : AlignWidget
{
public override void initialize() {
base.initialize();
add_align(-1, -1, LabelWidget.instance().set_text("First label")
.set_color(Color.instance("#FFFFFF")));
add_align(1, 1, LabelWidget.instance().set_text("Second label")
.set_color(Color.instance("#FFFFFF")));
}
}
- 36. Copyright © 2014 Job and Esther Technologies
Box widgets
• com.eqela.libwidget.HBoxWidget and
com.eqela.libwidget.VBoxWidget
• These are used to flow widgets dynamically either from top to
bottom (VBoxWidget) or left to right (HBoxWidget).
• The weight parameter:
Used to specify relative weight of widgets that share the same
container.
An integer (default to 0)
- 37. Copyright © 2014 Job and Esther Technologies
Example:
* The “Widget” widget does not draw anything, but because of the weight of 1, it will
be sized to fill all free space in the widget.
class MyVBoxWidget : VBoxWidget
{
public override void initialize() {
base.initialize();
add(LabelWidget.instance().set_text("First label")
.set_color(Color.instance("#FFFFFF")));
add(LabelWidget.instance().set_text("Second label")
.set_color(Color.instance("#FFFFFF")));
add_vbox(1, new Widget());
add(ButtonWidget.instance().set_text("Click me"));
}
}
- 39. Copyright © 2014 Job and Esther Technologies
Box widgets (both horizontal and vertical) can be mixed, which is
often the case, to create complete GUI layouts:
class MyVBoxWidget : VBoxWidget
{
public override void initialize() {
base.initialize();
var hbox = HBoxWidget.instance();
add(hbox);
hbox.add(ButtonWidget.instance().set_text("OK"));
hbox.add(ButtonWidget.instance().set_text("Cancel"));
add(LabelWidget.instance().set_text("First label")
.set_color(Color.instance("#FFFFFF")));
add(LabelWidget.instance().set_text("Second label")
.set_color(Color.instance("#FFFFFF")));
add_vbox(1, new Widget());
add(ButtonWidget.instance().set_text("Click me"));
}
}
- 41. Copyright © 2014 Job and Esther Technologies
Other GUI features
Scrolling
The Eqela GUI API provides scrolling features through
one or all of:
− com.eqela.libscrollerwidget.ScrollerWidget
Provides scrolling in both directions
− com.eqela.libscrollerwidget.VScrollerWidget
Provides scrolling vertically
− com.eqela.libscrollerwidget.HScrollerWidget
Provides scrolling horizontally
Any widget can be added as a child of one of these
scroller widgets.
− Scroller widgets will always grant the requested size of the
child widget.
- 42. Copyright © 2014 Job and Esther Technologies
Scrolling
The methods of scrolling:
− Dragging the widget up,
down, left or right
− Using the mouse scroll
wheel
− Keyboard scrolling with
up/down keys
The ScrollerWidget
- 43. Copyright © 2014 Job and Esther Technologies
Other GUI features
Handling screen orientation changes
The Eqela API also provides a mechanism for any
widget to be aware of changes in its size class (large or
small) and orientation (landscape or portrait).
An application can know about an orientation / size
class change by overriding the
on_orientation_changed() method:
class MyOrientationWidget : Widget
{
public override void on_orientation_changed() {
// code for handling the change
}
}
- 44. Copyright © 2014 Job and Esther Technologies
●
Eqela live implements screen orientation change
Portrait Landscape
- 45. Copyright © 2014 Job and Esther Technologies
Handling screen orientation changes
Some convenience methods for handling and detecting
the change:
Methods Description
is_small()
is_large()
is_portrait()
is_landscape()
Using these methods, the widget can determine what its
new size and orientation are.
set_current_view()
initialize_view()
These methods provide a mechanism for reinitializing the
widget's user interface as a response to size or orientation
changes.
- 46. Copyright © 2014 Job and Esther Technologies
Example:
class MyOrientationWidget : Widget
{
public override void on_orientation_changed() {
base.on_orientation_changed();
if(is_small()) {
set_current_view("small");
}
else {
if(is_landscape()) {
set_current_view("large_landscape");
}
else {
set_current_view("large_portrait");
}
}
}
public override void initialize_view(String name) {
if("small".equals(name)) {
// add child widgets / do other UI initialization
}
- 47. Copyright © 2014 Job and Esther Technologies
else if("large_landscape".equals(name)) {
// add child widgets / do other UI initialization
}
else if("large_portrait".equals(name)) {
// add child widgets / do other UI initialization
}
}
}
- 48. Copyright © 2014 Job and Esther Technologies
Other GUI features
Handling URLs
com.eqela.libcommonwidget.URLButtonWidget
− Creates a GUI button that, when clicked, opens a URL
address.
Example:
class MyVBoxWidget : VBoxWidget
{
public void initialize() {
base.initialize();
add(URLButtonWidget.for_url("http://www.eqela.com"));
}
}
- 49. Copyright © 2014 Job and Esther Technologies
Other GUI features
On-screen keyboards
Eqela also supports virtual, on-screen keyboard
On platforms where a virtual keyboard is needed, one
will automatically appear when a widget is focused that
requires text input.