SICS T92:10
Using SICStus Objects in the
Design of Graphical User
Interfaces
Thomas Sjöland
SICS
August 1992
SICS Technical Report ISSN 1100-3154
Swedish Institute of Computer Science
Box 1263, S-164 28 Kista, SWEDEN
Using SICStus Objects in the Design of
Graphical User Interfaces
Thomas Sjöland
SICS, Box 1263, S-164 28 Kista, Sweden
tel: +46 8 752 1542
Electronic mail: [email protected]
Abstract
The functionalities of SICStus Objects, a system allowing object oriented
programming in SICStus Prolog are shown and an example is presented:
support software for building graphical user interfaces.
This text assumes a basic knowledge about Prolog programming in SICStus
Prolog and some intuition about object oriented programming.
SICStus Objects was implemented as an embedded language in SICStus
Prolog by Seif Haridi and Kent Boortz. SICStus Prolog is developed and
maintained by Mats Carlsson, Stefan Andersson and Kent Boortz at SICS with
support from Ellemtel Utvecklings AB.
Background
Some Prolog vendors supply their systems with possibilities for using object
orientation together with Prolog. Commercial systems known to us are Prolog++ from
Logic Programming Associates, Logical Object Systems (LOS) from Imperial College
[McCabe89] and ELSA from ELSA Software.
SICStus Objects, the system described here has a lot in common with LPA's
Prolog++ [Vasey, Spencer et.al.90], and with the systems described by Fromherz
[Fromherz91] and Moss [Moss90].
SICStus Objects
SICStus Objects provides the Prolog programmer with mechanisms for defining and
using objects as a programming paradigm together with SICStus Prolog.
• Prolog goals can be called from components in objects and messages can be sent to
objects from ordinary Prolog clauses.
• The language SICStus Objects is translated into Prolog. This gives the possibility of
using the Prolog compiler.
NB: The current implementation is fairly straightforward. E.g. it does not optimize
inheritance or updates of objects. This might limit the applicability of the system.
Terminology
Object oriented programs consist of definitions of data together with methods to
manipulate the data. Often the notion "class" is used when talking about a definition
and "object" is used when talking about an instance of the class which is created
during run-time. SICStus Objects follows the convention of LPA's Prolog++ using
"object" for the description and "instance" for objects created during the execution of
the program. This is motivated by the fact that an object in SICStus Objects can be
modified. Objects and instances behave similarly with the major difference that objects
can be compiled whereas instances cannot. Methods and data (attributes), are here
referred to as components. Components in compiled objects cannot be modified unless
declared dynamic. Regardless of these differences it is appropriate to use the term
"object" unless we are specifically talking about instances.
Compiling and running SICStus Objects
In SICStus Objects the user can freely mix SICStus Prolog code with the object
oriented code. This allows a great deal of flexibility. When a SICStus Objects program
is to be preprocessed or run you load the translator, the runtime system and the
definitions of the object object.
:- use_module(library(objects)).
The object oriented programs should be translated into Prolog. This is accomplished
by using a call of this form:
:- translate(myfile).
This call translates myfile into the Prolog source file myfile.pl, which can
subsequently be compiled (or loaded) by SICStus Prolog in the usual way.
A program in SICStus Objects consist of a set of object definitions. Outside the
definitions of objects you can write any ordinary clauses and directives in SICStus
Prolog. The syntax of Prolog is extended with operators for invoking the object
oriented system from Prolog.
The following operators are defined for SICStus Objects:
:- op(1200,fy,[open_object,close_object]).
:- op(800,xfx,['<-']).
:- op(600,xfx, [':=','+=','-=']).
Syntax
In SICStus Objects the Prolog syntax is used for definitions.
An object definition is bracketed thus:
open_object <ObjectName>.
…<definitions for hierarchy and components>
close_object <ObjectName>.
The syntax of components is that of Prolog clauses. The inheritance hierarchy is
specified by defining the component super/1. A link is specified by defining the
component link/2. The keyword dynamic is used to specify that a component
may be modified. Undefined components are considered as dynamic when added to an
object. Prolog goals are simply written in the body, while component access of
An example of an object definition
open_object my_object.
super(another_object).
dynamic(attribute/1).
attribute(value).
attribute(anothervalue).
method(X) :- prologgoal(X),
johnnys_object <- method(X).
method(X) :- myself <- attribute(X),
self <- inherited_method(X,X).
link(method_of_other_object/3,other_object).
close_object my_object.
SICStus Objects is a dynamic object system
A static object system cannot create objects during the execution. Therefore in a static
object system there is no need to distinguish between objects and instances. Each
object which is being used has its own definition and a unique set of components,
playing the role of state variables.
A dynamic object system allows the program to create objects in the system. SICStus
Objects is a dynamic object system.
Modifying the state
The idea of a state variable is alien to logic programming but it is practical in many
situations. State variables are implemented in SICStus Objects as components by using
the database features of SICStus Prolog. Therefore components can be added and
removed to/from objects as well as modified in addition to just being used.
Object definitions and object instances
An object definition which is written in the source code describes an object but also a
class of object instances. When object instances are created, the object is used as a
template. The object instance receives a name which can be used as a reference when
sending messages. In SICStus Objects messages can be sent to objects and to
instances. The distinction between objects and instances is that instances are not named
in the source code, but the instances are given unique names upon being created.
Components
An object is a collection of components. Components are known to the object and its
ancestors in the object hierarchy. The object hierarchy is specified with the component
super/1, defining the object(s) from which the current object automatically inherits
components which are not defined in the object itself. In SICStus Objects,
mechanisms for creating objects and instances as well as for sending messages to the
objects (instances) are provided.
A component of an object can be defined, accessed, modified and deleted. SICStus
Objects allows a component to be seen as a relation, i.e. several alternatives are
allowed. The access mechanism can backtrack upon failure just like in Prolog but
backtracking is limited to be only within the first found object which contains the
component.
Object hierarchies and inheritance mechanisms
When an object lacks a component the system can search for it in another object. By
making precise exactly which objects are higher than a given object and introducing an
object which is higher than any other object a semilattice of objects, an object
hierarchy, is formed. The highest object in the hierarchy is the object
object,which
has no defined component super/1. Specialisation of objects is achieved through
inheritance. When a component is not defined in an object it is looked for in the
objects that are higher. The immediately higher objects are defined in the component
super. Multiple inheritance is provided since an object may refer to several other
objects with the component super/1 by simply adding more declarations of the
component super/1.
Since the hierarchy links are components, explicit searches in the hierarchy can be
programmed with a large degree of freedom.
Shadowing
Shadowing (overriding inheritance) means that components which are found in objects
which are lower in the hierarchy hide components from higher objects.
In SICStus Objects a component is found in a unique object. Since SICStus Objects is
based on Prolog, alternatives are allowed which can be used for backtracking. The
alternatives are only searched in the chosen object, even if there are definitions in other
places in the object hierarchy. In LOS [McCabe89] there are two different
mechanisms for inheritance. Except for shadowing LOS uses the union of all
be avoided by using the component super/1 and including a clause to distribute
messages upwards in the hierarchy:
…
method(InData)
:-myself <- super(S), S <- method(InData).
…
Since multiple inheritance is provided, shadowing can be implemented in various
ways. In SICStus Objects the principle that is followed is this:
Inheritance as specialisation:
The object that is identified as the carrier of an inherited component is the leftmost one
which does not have a subobject in which the component occurs.
In figure 1, the principle used to resolve multiple inheritance is shown with a perhaps
somewhat contrived example. Consider four objects a,b,c and d where d has a, b and
c as
super and b and c have a as super. A component m is defined in a and c, a
component n is defined in a and b, and a component o is defined in b and c. In some
object oriented systems multiple inheritance is resolved by a left-to-right depth first
search upwards in the lattice. Such a search traverses first one branch and then
possibly the others, one at a time. An access to m from d would identify the m in a
via b rather than the more specialised version in c. Considering the component n on
the other hand it is clear that the problem cannot be resolved with a reordering of the
branches. In one of the cases a component will be found which should have been
shadowed by a specialized instance of it. Furthermore, since inheritance should be
regarded as specialisation, a breadth first search is not sufficient to implement the
principle (consider that d has a as a direct super which would give the m of a rather
than that of c).
By using the rule above implemented as a topological sort, d gets the n and the o of b
and the m of c.
a : m , n
b : n , o
c : m , o
d
Fig 1: Inheritance as specialisation, the principle used to
resolve multiple inheritance in SICStus Objects, gives
d the n and the o of b and the m of c.
Components can also be inherited from named objects without considering the
hierarchy. This explicit inheritance is provided by defining links.
It is essential to ensure that the design of the inheritance relation does not create loops,
i.e. the super relation should be a semi-lattice with object as the top element.
Polymorphism is achieved by using the same component name to define different
behaviours for different objects.
Encapsulation and abstraction
Since all objects are defined in parentheses (open_object, close_object) and
the components are unique to the object the components are encapsulated. In SICStus
Objects components can also be defined as private. Such components are not inherited.
Otherwise they are understood as public. Public is the default case.
The name of an object and the names of its public components are its abstraction.
Communication and control of the execution
The central operation for an object oriented system is transfer of messages. Message
transfer is essentially the same as goal resolution in Prolog using the inheritance
hierarchy to find the addressed component.
Messages are sent to objects and are of two types:
1) request for execution of a method or finding the value of a component, e.g.:
obj <- message(Hello)
2) request for modification of a component, e.g.:
obj <- update(attribute3(<new_value>))
obj <- retract(attribute3(_))
obj <- assert(attribute3(<new_value>))
self
and
myself
In order to use components from the current object even when inheritance is at play,
the keyword self can be used. self is used to refer to the object that used the
component. Another keyword, myself refers to the name of the object definition in
which the method definition is localized. In fact this usage means that myself is
redundant since you can always use the name of an object explicitely, but it is
introduced for convenience and to produce more readable code.
sender
provides selective component invocation
The keyword sender is used to refer to the object that requested the component. By
testing sender the access to components can be arbitrarily limited.
Operations on objects and object instances
Objects can be created based on other object definitions and also be removed. An
instance is normally considered to have as its super the object in respect to which it
was created. The method new/1, defined in the object object is used to create
instances of an object, e.g.:
my_object <- new(Reference)
Executing new/1 means that a new object is created which is considered as a
subobject (instance) of the object my_object. It has a unique set of components
which can be used for storing values.The components are inherited from
my_object.
If components have been defined as dynamic they can be added and deleted from an
object. Components which are not in the source code are considered to be dynamic.
The object
object
and its components
The top element of the object hierarchy is an object to which all other objects are
subobjects (instances), the object object. The components of object are available to
all objects in the system.
Systems for object oriented programming are often implemented together with an
interactive graphical programming environment. In this there are tools to inspect the
control structures (e.g. "object browsers") and to construct program code. Such tools
are yet to be implemented for SICStus Objects.
Standard
The combination of object oriented programming and logic programming in Prolog is
still a matter of research and early development. There is currently no standard
available.
An example:
gm objects
, interfacing to the graphics
manager
As an example of the use of SICStus Objects we choose an object oriented interface to
the graphics manager of SICStus Prolog, GM [AlAnFlFrNiSu91]. GM is written in
C++ using Interviews, a set of classes used to specify graphical interactors, visible
graphical "things" which have certain predefined behaviours. In order to make it
possible to extend the interface in such a way as to allow the programmer to define
new interactors with their own behaviour an object oriented approach is a significant
help. We will show how the basic interface is constructed in SICStus Objects, and
then we give some examples of how it can be extended to support a few new
interactors of the programmer's choice. The name gm objects will be used in
reference to the graphical subsystem.
In gm objects the object hierarchy of SICStus Objects is used to define methods
for constructing and manipulating graphical objects. The available graphical objects are
given by GM.
The components of
gm objects
Objects in gm objects have a set of components to manage the state of the
interface. The central idea of gm objects is to consider the "visible things" as
objects in SICStus Objects. The contents of a visible object are specified in the
component content/1. Some default operations for managing the visualisation of
the object are provided.
In order to create an object which is subordinated to gm_object you use the method
gmnew/1. When sent to an object which is subordinate to gm_object it will
create an object of this type, performing the appropriate procedures for setting up the
object and making it visible under Xwindows. The inheritance hierarchy is used to
enable the system to automatically choose the desired initiation method
intervention by the programmer. This makes it possible for the programmer to use gm
objects without considering the underlying GM package with its handling of
references to graphical objects. The references and properties needed to construct the
object are to be found as components in the object. By doing so the costly
communication in order to inspect the visual objects is avoided. In some cases this
enhances the functionality of the graphic system since GM does not provide access to
its internal state from the Prolog program. Composite objects may be constructed as
objects in gm objects without modifying the low level GM system.
The object hierarchy of gm objects
The inheritance relation (super) of gm objects is shown in figure 2 (except for
explicit links of particular components). The relation is interpreted thus: "when X is a
super of Y a component of Y which is not defined in Y itself can be found in X".
<fig 2 > The object hierarchy of gm objects
o b j e c t gm gm_object gm_window gm_windowcontent gm_active gm_view g m _ t e x t gm_input gm_slider gm_inactive gm_output gm_hbox gm_vbox gm_menu gm_button gm_graphic gm_line gm_ellipse g m _ f i l l e l l i p s e g m _ c i r c l e g m _ f i l l c i r c l e g m _ r e c t g m _ f i l l r e c t g m _ s t r i n g gm_bitmap gm_picture gm_fillpolygon gm_polygon
Visible objects in
gm objects
Some visible objects can be contained in other visible objects. A relation describing the
visible objects that may be contained within other visible objects is a natural way to
display this constraint.
gm_window : gm_hbox | gm_vbox | gm_view | gm_text
| gm_input | gm_output | gm_slider
| gm_button
gm_hbox : gm_vbox | gm_view | gm_text
| gm_input | gm_output | gm_slider
| gm_button
gm_vbox : gm_hbox | gm_view | gm_text
| gm_input | gm_output | gm_slider
| gm_button
gm_view : gm_menu | gm_line
| gm_ellipse | gm_fillellipse
| gm_circle | gm_fillcircle
| gm_rect | gm_fillrect
| gm_polygon | gm_fillpolygon
| gm_string | gm_bitmap |
gm_picture
gm_text : gm_menu
How to use
gm objects
gm objects hides the fact that GM requires that visible objects are constructed in a
particular order. The user specifies the content/1 components of the visible
objects. Thereafter (s)he should send the message gmnew/1 to the object specifying
the window. The methods for creating the content of a window will then look up the
content/1 components describing the layout of the window and creates an object
for each of the visible parts in the appropriate order. It is essential that recursive
objects are not specified since that will lead the construction method gmnew into an
infinite regress. (A tool to check whether a specification is circular, recursive, is a
good exercise in order to familiarize oneself with SICStus Objects and gm
Event handlers
An important aspect of GUI construction is the handling of events. It is important to be
able to construct a modeless interface, i.e. the interface should be so designed that it is
possible to get a response for any keyklick, selection or similar interaction which is
possible on the screen, rather than having the program wait for a particular input at any
given time. Sometimes, but more rarely, it is essential that the program awaits
particular inputs such as responses to queries etc. before accepting other input. This
later kind of interface is called moded interface and should also be provided, although
that issue is not tackled here. gm objects provides a method, run/0, which is
located in the object gm. The call:
gm <- run.
will start the event handling loop. This loop awaits action from the user. Upon
receiving a message it dispatches the messages to the object in which the event took
place. By specifying an eventhandler as a method of that object the system allows the
user to tailor the responses of the program based of the object hierarchy. The method
should be specified as eventhandle/1. Any programming technique of SICStus
Objects in combination with SICStus Prolog is available, but it is adviced that
responses programmed in the eventhandler are of a reasonably short duration. The
only method that should be allowed to go in an infinite loop is run/0 of the object
gm.
If the generic event handling loop, run/0, is inappropriate the event handling can be
programmed by using either
gm_object <- wait_event(E)
or
gm_object <- next_event(E)
which waits or polls the event queue for incoming events. Whenever the application
wants to treat a received event,
gm_object <- event_handle(E)
can be used. This call can also be used to mimick the reception of an event. If a
sequence of events is recorded, this could for instance be used in a later playback of a
sequence of events.
Object definitions in gm objects
compile_objects(File) :- gm <- end, object <- clean, translate(File), compile(File).
object_listing :- object_listing(object,0).
object_listing(O,Tab)
:-tab(Tab), write(O), nl, Tab1 is Tab+3,
findall(_,(O <- sub(Obj), object_listing(Obj,Tab1)),_).
full_object_listing :- full_object_listing(object,0).
full_object_listing(O,Tab)
:-tab(Tab), write(O), write('#'), nl, Tab0 is Tab+1,
findall(_,(O <- attribute(A),tab(Tab0),write(A),nl),_), Tab1 is Tab+3,
findall(_,(O <- sub(Obj), full_object_listing(Obj,Tab1)),_).
on(X, [X|_]).
on(X, [_|L]) :- on(X, L).
write_seq([]).
%---% gm. %---open_object gm. dynamic(host/1). host(hathor). dynamic(username/1). username(thomas).
start :- myself <- host(Host),
myself <- username(Username), (myself <- started -> myself <- end ; true), start.
start(Host) :- self <- update(host(Host)), start. start(Host,Username)
myself <- update(username(Username)), myself <- start(Host). started :- started.
end
bagof1(I,(gm_object <- instance(I), I <- delete),_), end, freeall. % event loop
run :- write_seq([self,'waiting for event']), nl, waitevent(E), write_seq([self,'received event',E]), nl, eventaddress(E,WindowObject), write_seq([self,'dispatching to',WindowObject]), nl, ((WindowObject <- eventhandle(E)) -> true ; write_seq([self,'failed eventhandle'(WindowObject,E)]), nl), ((\+ E=menu(_,quit)) -> self <- run).
close_object gm.
objref_to_name(Ref, Name) :- clause(gmlib:named_object(Name,Ref,_), _).
eventaddress(down(_Window,View,_,_),Ref) :- objref_to_name(View,Ref). eventaddress(button(Window,_),Ref) :- objref_to_name(Window,Ref). eventaddress(menu(Window,_),Ref) :- objref_to_name(Window,Ref).
eventaddress(return(_Window,Input),Ref) :- objref_to_name(Input,Ref). eventaddress(slider(_Window,Slider,_),Ref) :- objref_to_name(Slider,Ref). eventaddress(noevent,gm_object). %---% gm_object. %---open_object gm_object. % Attributes. % constructor(Constructor)
% contains current Constructor as defined in subclasses % gm_ref(GM-reference)
% contains current reference to GM-object gmnew(Ref) :- self <- new(Ref),
Ref <- gmcreate.
gmcreate :- write_seq([self,'gmcreate/0']), nl, self <- gmcreate(self).
gmcreate(T) :- T==[], !.
gmcreate(A) :- nonvar(A), A=[H|T], !, self <- gmcreate(H), self <- gmcreate(T).
gmcreate(Ref) :- self <- constructor(Constructor), GmRef=Ref,
(gmcreate(GmRef,Constructor) ->
self <- update(gm_ref(GmRef)) ;
write_seq(['prolog:gmcreate/2 failed for', GmRef,Constructor]),nl). gmsend(Message)
:-self <- gm_ref(GmRef), gmexist(GmRef),
gmsend(GmRef,Message). gmexist:- self <- gm_ref(GmRef),
gmexist(GmRef). % events (polling) nextevent :- nextevent(Event), self <- eventhandle(Event). % events (waiting) waitevent :- waitevent(Event),
self <- eventhandle(Event).
% local events to this object (polling)
nextevent(Event) :- self <- gmsend(nextevent(Event)).
% local events to this object (waiting)
waitevent(Event) :- self <- gmsend(waitevent(Event)).
eventhandle(button(Window,Eventname))
write_seq(['An unknown button was pressed', button(Window,Eventname)]), nl. eventhandle(menu(Window,Eventname))
write_seq(['An unknown menu was selected',
menu(Window,Eventname)]), nl. eventhandle(return(Window,Browser,LineNo)) write_seq(['An unexpected return event occurred',
return(Window,Browser,LineNo)]), nl. eventhandle(return(Window,Input))
write_seq(['An unexpected return event occurred', return(Window,Input)]), nl. eventhandle(down(Window,View,X,Y))
write_seq(['An unexpected down event occurred', down(Window,View,X,Y)]), nl. eventhandle(slider(Window,Slider,Value))
write_seq(['An unexpected slider release event occurred', slider(Window,Slider,Value)]), nl. eventhandle(noevent)
write_seq(['An unexpected noevent event occurred']), nl. close_object gm_object.
%---% gm_window.
%---% create subobjects to this class to describe different window types
% the field content(_) contains the object class name for the component(s) % which is (are) automatically created and put into the window created by % sending gmcreate to the window class.
% open_object gm_window. super(gm_object). % attributes: % content(Class) % contentref(Ref)
gmcreate :- self <- gmcreate_window(self). gmcreate_window(WindowTitle) self <- update(name(WindowTitle)), self <- content(Class), Class <- gmnew(ObjRef), ObjRef <- update(partof(self)), self <- update(contentref(ObjRef)), ObjRef <- gm_ref(GmRef), self <- update(constructor(window(WindowTitle,GmRef))), self <- gmcreate(self).
update :- self <- gmsend(close), self <- gmcreate(self). open :- self <- gmsend(open).
open(X,Y) :- self <- gmsend(open(X,Y)). close :- self <- gmsend(close),
self<- contentref(R), (R <- menuref(M) -> (M <- delete) ; true), R <- delete, self <- delete.
raise :- self <- gmsend(raise). lower :- self <- gmsend(lower). iconify :- self <- gmsend(iconify).
setcursor(Cursor) :- self <- gmsend(setcursor(Cursor)). getcursor(Cursor) :- self <- gmsend(getcursor(Cursor)).
%---eventhandle(menu(Window,quit)) :-write_seq(['Deleting window',Window]), nl, self <- close. %---close_object gm_window.
%---% gm_window_content. %---open_object gm_window_content. super(gm_object). % Attributes:
% partof(_) reference to a window. gmnewcontent(Ref) :-self <- content(C), (C=space -> Ref=space ; C=space(frame(O)) -> (O <- gmnew(Ref0),Ref=space(frame(Ref0))) ; C=frame(space(O)) -> (O <- gmnew(Ref0),Ref=frame(space(Ref0))) ; C=space(O) -> (O <- gmnew(Ref0), Ref=space(Ref0)) ; C=border -> Ref=border ; C=frame(O) -> (O <- gmnew(Ref0), Ref=frame(Ref0)) ; C=scroller(O) -> (O <- gmnew(Ref0), Ref=scroller(Ref0)) ; C <- gmnew(Ref) ) . close_object gm_window_content.
%---% gm_active.
%---open_object gm_active.
% for view, text, input and slider (and button) super(gm_window_content).
enable :- self <- gmsend(enable). disable :- self <- gmsend(disable). close_object gm_active. %---% gm_view. %---open_object gm_view. super(gm_active). % graphic(_)
% a set of names of subclasses of gm_graphic which are contained here %
% graphicref(_)
% a set of references to instances of gm_graphic which are in this view %---not called by user directly
---eventhandle(_,quit) :- self <- partof(Window), Window <- close.
%---gmcreate :- self <- gmcreate(200,100),
self <- enable. gmcreate(Xsize,Ysize) self <- update(constructor(view(Xsize,Ysize))), self <- gmcreate(self), bagof1((C,GraphicRef), (self <- graphic(C), C <- gmnewgraphic(self,GraphicRef), self <- assert(graphicref(GraphicRef))), _ ) , self <- setmenu.
line(X1,Y1,X2,Y2) :- self <- gmsend(line(X1,Y1,X2,Y2)). ellipse(X,Y,R1,R2) :- self <- gmsend(ellipse(X,Y,R1,R2)). fillellipse(X,Y,R1,R2) :- self <- gmsend(fillellipse(X,Y,R1,R2)). circle(X,Y,R) :- self <- gmsend(circle(X,Y,R)).
fillcircle(X,Y,R) :- self <- gmsend(fillcircle(X,Y,R)). rect(X1,Y1,X2,Y2) :- self <- gmsend(rect(X1,Y1,X2,Y2)). fillrect(X1,Y1,X2,Y2) :- self <- gmsend(fillrect(X1,Y1,X2,Y2)). polygon(Xedges,Yedges) :- self <- gmsend(polygon(Xedges,Yedges)). fillpolygon(Xedges,Yedges) :- self <- gmsend(fillpolygon(Xedges,Yedges)). string(X,Y,Text) :- self <- gmsend(string(X,Y,Text)).
bitmap(X,Y,Filename) :- self <- gmsend(bitmap(X,Y,Filename)). setcolors(Fgcolor,Bgcolor) :- self <- gmsend(setcolors(Fgcolor,Bgcolor)). setpattern(Pattern) :- self <- gmsend(setpattern(Pattern)).
setbrush(Pattern,Width) :- self <- gmsend(setbrush(Pattern,Width)). setfont(Font) :- self <- gmsend(setfont(Font)).
stringlength(Text,Length) :- self <- gmsend(stringlength(Text,Length)). batchmode :- self <- gmsend(batchmode).
batchmodeoff :- self <- gmsend(batchmodeoff). update :- self <- update.
setmenu :- self <- setmenu(gm_menu). setmenu(Menu)
:-Menu <- gmnew(:-MenuRef),
self <- update(menuref(MenuRef)), MenuRef <- gm_ref(MenuGmRef), self <- gmsend(setmenu(MenuGmRef)). clear :- self <- gmsend(clear).
zoom(Amount) :- self <- gmsend(zoom(Amount)). scrollto(X,Y) :- self <- gmsend(scrollto(X,Y)). scrollby(X,Y) :- self <- gmsend(scrollby(X,Y)). getcur(X,Y) :- self <- gmsend(getcur(X,Y)). link(setcursor/1,gm_window).
link(getcursor/1,gm_window). close_object gm_view.
%---% gm_text.
%---open_object gm_text.
super(gm_active).
gmcreate :- self <- gmcreate(12,40,5), self <- enable. gmcreate(Rows,Cols,Tab) self <- update(constructor(text(Rows,Cols,Tab))), self <- constructor(C), self <- gmcreate(self), self <- setmenu. gmcreate(Rows,Cols,Tab,Font) self <- update(constructor(text(Rows,Cols,Tab,Font))), self <- gmcreate(self), self <- setmenu.
readfile(File) :- self <- gmsend(readfile(File)). writefile(File) :- self <- gmsend(writefile(File)). link(setmenu/0,gm_view).
link(setmenu/1,gm_view).
insert(Text) :- self <- gmsend(insert(Text)). delete_text :- self <- gmsend(delete). delete_text(N) :- self <- gmsend(delete(N)). clear :- self <- gmsend(clear).
readonly :- self <- gmsend(readonly). readwrite :- self <- gmsend(readwrite). moveto(X,Y) :- self <- gmsend(moveto(X,Y)). moveby(X,Y) :- self <- gmsend(moveby(X,Y)). in(all,Text) :- self <- gmsend(in(all,Text)).
in(selection,Text) :- self <- gmsend(in(selection,Text)). in(line(LineFrom,LineTo),Text)
:-self <- gmsend(in(line(LineFrom,LineTo),Text)). in(word,Text) :- self <- gmsend(in(word,Text)).
forwardsearch(Text) :- self <- gmsend(forwardsearch(Text)). backwardsearch(Text) :- self <- gmsend(backwardsearch(Text)). close_object gm_text.
%---% gm_input.
%---open_object gm_input.
super(gm_active).
gmcreate :- self <- gmcreate_input(self), self <- enable.
gmcreate_input(Text) :- self <- update(constructor(input(Text))), self <- gmcreate(self).
gmcreate(Text,Font) :- self <- update(constructor(input(Text,Font))), self <- gmcreate(self).
in(Text) :- self <- gmsend(in(Text)). out(Text) :- self <- gmsend(out(Text)). close_object gm_input. %---% gm_button. %---open_object gm_button. super(gm_active).
gmcreate :- self <- gmcreate(self,self), self <- enable. gmcreate(Name,Message) :- self <-update(constructor(button(Name,Message))), self <- gmcreate(self). gmcreate(Name,Message,Attribute) :-self <-update(constructor(button(Name,Message,Attribute))), self <- gmcreate(self). close_object gm_button. %---% gm_slider. %---open_object gm_slider. super(gm_active).
gmcreate :- self <- gmcreate_slider(self), self <- enable,
self <- value(V),
self <- update(value(V)). gmcreate_slider(Name)
self <- gmcreate(self), self <- enable.
value(Val) :- self <- gmsend(value(Val)), self <- update(value(Val)). close_object gm_slider. %---% gm_inactive. %---open_object gm_inactive. super(gm_window_content). close_object gm_inactive. %---% gm_output. %---open_object gm_output. super(gm_inactive).
gmcreate :- self <- gmcreate_output(self).
gmcreate_output(Text) :- self <- update(constructor(output(Text))), self <- gmcreate(self).
gmcreate(Text,Font) :- self <- update(constructor(output(Text,Font))), self <- gmcreate(self).
out(Text) :- self <- gmsend(out(Text)). close_object gm_output.
%---% gm_hbox.
%---% create subobjects to this class to describe your different hboxes
open_object gm_hbox.
super(gm_window_content). gmcreate :- bagof1(ContentRef,
(self <- gmnewcontent(ContentRef)), ContentRefs), self <- update(contentref(ContentRefs)),
self <- gmcreate_hbox(ContentRefs).
gmcreate_hbox(Items) :- self <- update(constructor(hbox(Items))), self <- gmcreate(self).
close_object gm_hbox.
%---% gm_vbox.
%---% create subobjects to this class to describe your different hboxes
open_object gm_vbox. super(gm_window_content). gmcreate :- bagof1(ContentRef,(self <-gmnewcontent(ContentRef)),ContentRefs), self <- update(contentref(ContentRefs)), self <- gmcreate_vbox(ContentRefs). gmcreate_vbox(Items) :-self <- update(constructor(vbox(Items))), self <- gmcreate(self). close_object gm_vbox. %---% gm_menu. %---open_object gm_menu. super(gm_object).
gmcreate :- self <- gmcreate([quit],[quit]). gmcreate(Messages,Items) self <- update(constructor(menu(Messages,Items))), self <- gmcreate(self). close_object gm_menu. %---% gm_graphic. %---open_object gm_graphic. super(gm_object). % dynamic(in_view/1).
% tells in what gm_view object this graphic resides %
% graphicspec(Spec)
% specifies which graphic we are talking about gmnewgraphic(View,GraphicRef) :-self <- new(W), W <- graphicspec(S0), S0=..[Name|Args], S1=..[Name,GraphicRef|Args], View <- gmsend(S1), W <- update(in_view(View)),
W <- update(gm_ref(GraphicRef)). move(Dx,Dy) :- self <- in_view(W),
self <- gm_ref(R),
W <- gmsend(move(R,Dx,Dy)). moveto(Dx,Dy) :- self <- in_view(W),
self <- gm_ref(R),
W <- gmsend(moveto(R,Dx,Dy)). rotate(Ref,Angle) :- self <- in_view(W),
self <- gm_ref(R),
W <- gmsend(rotate(R,Ref,Angle)). scale(Xs,Ys) :- self <- in_view(W),
self <- gm_ref(R),
W <- gmsend(scale(R,Xs,Ys)). remove :- self <- in_view(W),
self <- gm_ref(R), W <- gmsend(remove(R)), self <- delete. close_object gm_graphic. %---% gm_line. %---open_object gm_line. super(gm_graphic). % graphicspec(line(X1,Y1,X2,Y2)). close_object gm_line. %---% gm_ellipse. %---open_object gm_ellipse. super(gm_graphic). % graphicspec(ellipse(X,Y,R1,R2)). close_object gm_ellipse. %---% gm_fillellipse. %---open_object gm_fillellipse.
super(gm_graphic). % graphicspec(fillellipse(X,Y,R1,R2)) close_object gm_fillellipse. %---% gm_circle. %---open_object gm_circle. super(gm_graphic). % graphicspec(circle(X,Y,R)) close_object gm_circle. %---% gm_fillcircle. %---open_object gm_fillcircle. super(gm_graphic). % graphicspec(fill_circle(X,Y,R)). close_object gm_fillcircle. %---% gm_rect. %---open_object gm_rect. super(gm_graphic). % graphicspec(rect(X1,Y1,X2,Y2)). close_object gm_rect. %---% gm_fillrect. %---open_object gm_fillrect. super(gm_graphic). % graphicspec(fillrect(X1,Y1,X2,Y2)). close_object gm_fillrect. %---% gm_polygon. %---open_object gm_polygon. super(gm_graphic).
% graphicspec(polygon(Xedges,Yedges)). close_object gm_polygon. %---% gm_fillpolygon. %---open_object gm_fillpolygon. super(gm_graphic). % graphicspec(fillpolygon(Xedges,Yedges)) close_object gm_fillpolygon. %---% gm_string. %---open_object gm_string. super(gm_graphic). % graphicspec(string(X,Y,Text)). newtext(Text) :- self <- gm_ref(R),
self <- in_view(W), W <- gmsend(newtext(R,Text)). close_object gm_string. %---% gm_bitmap. %---open_object gm_bitmap. super(gm_graphic). % graphicspec(bitmap(X,Y,Filename)). close_object gm_bitmap.
%---User defined objects based on gm objects
% Examples of user defined objects for gm objects, i.e. use of gm objects
call_me :- gm <- start, my_window <- gmnew(W), W <- open, gm <- run. %---% example of a window containing a possible object (only one NB)
%---open_object my_window. super(gm_window). content(my_vbox). close_object my_window. %---% example of a vertical box
%---open_object my_vbox. super(gm_vbox). content(my_hbox). content(frame(space(gm_button))). content(my_hbox). content(border). content(frame(my_view)). content(my_hbox). content(space(frame(gm_button))). close_object my_vbox. %---% example of a horizontal box
%---open_object my_hbox. super(gm_hbox). content(gm_slider). content(space). content(scroller(my_view)). content(scroller(my_text)). content(gm_output). content(gm_input). content(border). content(gm_button). close_object my_hbox.
%---% example of a text %---open_object my_text. super(gm_text). % to implement: ... content('my_textfile'). close_object my_text. %---% example of an input %---open_object my_input. super(gm_input). close_object my_input. %---% example of a view %---open_object my_view. super(gm_view). graphic(my_line0). graphic(my_line1). graphic(my_line2). graphic(my_line3). close_object my_view. %---% example of movable lines
%---open_object my_line0. super(gm_line). % in_view/1. % graphicspec(line(X1,Y1,X2,Y2)). graphicspec(line(0,0,100,100)). close_object my_line0. open_object my_line1. super(gm_line). % in_view/1. % graphicspec(line(X1,Y1,X2,Y2)). graphicspec(line(100,100,50,100)). close_object my_line1. open_object my_line2. super(gm_line).
% in_view/1. % graphicspec(line(X1,Y1,X2,Y2)). graphicspec(line(50,100,0,0)). close_object my_line2. open_object my_line3. super(gm_line). % in_view/1. % graphicspec(line(X1,Y1,X2,Y2)). graphicspec(line(25,50,75,50)). close_object my_line3.