
Overview :: This is an example of a low-level binding to a c++ GUI library and a mid-level abstraction over it. This was created primarily to spark discussion in the gui@haskell.org mailing list and secondarily to provide a simple example that can be compiled using ghc without any language extensions. I encourage those who code, to implement their ideas for the Common GUI API using this simple framework. This would allow all reviewers to understand exactly what you are talking about by running your examples. Fltk was chosen for its simplicity and portability. I didn't use an existing library because I wanted a short example where the source code is easy to comprehend at all levels. Questions :: 1) How does the interface look in Test_midlevel.hs? Is there any critiques in regard to using this style in CGA (Common GUI API)? 2) What drastic or minor changes would have to be made to the Test_midlevel.hs file to make it CGA compatible? Yes, this is a completely subjective question. In your opinion, what should Test_midlevel.hs look like? 3) There has been some discussion about using non-standard Haskell extensions in CGA. No extensions have been used in this example. Exactly what extensions would be useful in this example or in CGA as a imaginary whole? Is it worth it to use said extensions and allow CGA to be incompatible with Haskell98? 4) Haskell has one namespace, the global one. Since there would be a lot of function names and attributes in CGA, their names should be well thought out. Is there any initial ideas on how to handle this? 5) I am willing to implement more stuff like this. What other stuff would you like to see with this? Running :: To run the examples, one needs a standard Haskell compiler with ffi (ghc) and fltk installed (http://www.fltk.org). run make. If necessary, change the makefile to modify for your configuration. f_*_stub.cpp -- These are the stubs that are used to bind the c++ library to c functions. This is required because the Haskell ffi standard does not specify any conventions for C++. Fl.hs Box.hs Button.hs Window.hs -- These contain the bindings to the stub files. They also provide a low-level interface for the GUI toolkit. Test_lowlevel.hs -- This is a simple program demonstrating use of the low-level binding. Attributes.hs -- This code was taken from the htoolkit cvs server. Simple modifications were made to suit our purposes. A_Button.hs -- This is an abstraction over the low-level Button interface. It uses the Attributes module for the mid-level interface. Test_midlevel.hs -- This is the same simple program as Test_lowlevel.hs except it uses A_Button instead of Button to demonstrate use of the Attributes abstraction. Cheers, David J. Sankel

David Sankel wrote:
Questions :: 1) How does the interface look in Test_midlevel.hs? Is there any critiques in regard to using this style in CGA (Common GUI API)?
1. Widgets aren't being given names. This makes it impossible to refer
to them from outside of the code. It also eliminates the possibility
of implementing a useable Xt (e.g. Motif) backend. Toolkits which
don't name widgets can just ignore the name.
2. Widget properties (label, position, dimension) are being embedded
in the code, which is a bad idea. This point is closely tied in with
point 1.
3. Personally, I would prefer a generic widget creation function,
rather than a different function for each type of widget. E.g. Xt has
XtCreateWidget(), with the widget class being passed as an argument.
A more Haskell-ish approach would be to use typeclasses, e.g.:
class Widget a where
create :: String -> a -> [Property] -> IO a
-- create name parent properties = ...
Of course, you can always provide type-specific constructors in
addition; doing the reverse is more involved.
--
Glynn Clements

--- Glynn Clements
David Sankel wrote:
Questions :: 1) How does the interface look in Test_midlevel.hs? Is there any critiques in regard to using this style in CGA (Common GUI API)?
1. Widgets aren't being given names. This makes it impossible to refer to them from outside of the code. It also eliminates the possibility of implementing a useable Xt (e.g. Motif) backend. Toolkits which don't name widgets can just ignore the name.
I'm sorry, I don't understand what you mean by "impossible to refer to them from outside of the code". Can you give me an example of what you are talking about.
2. Widget properties (label, position, dimension) are being embedded in the code, which is a bad idea. This point is closely tied in with point 1.
Where should this be in your opinion?
3. Personally, I would prefer a generic widget creation function, rather than a different function for each type of widget. E.g. Xt has XtCreateWidget(), with the widget class being passed as an argument. A more Haskell-ish approach would be to use typeclasses, e.g.:
class Widget a where create :: String -> a -> [Property] -> IO a -- create name parent properties = ...
Why would you prefer this over the other method? One problem with this method seems to be runtime errors for nonexistant classes. David J. Sankel

David Sankel wrote:
Questions :: 1) How does the interface look in Test_midlevel.hs? Is there any critiques in regard to using this style in CGA (Common GUI API)?
1. Widgets aren't being given names. This makes it impossible to refer to them from outside of the code. It also eliminates the possibility of implementing a useable Xt (e.g. Motif) backend. Toolkits which don't name widgets can just ignore the name.
I'm sorry, I don't understand what you mean by "impossible to refer to them from outside of the code". Can you give me an example of what you are talking about.
X resources. In an Xt-based program, every widget has a "pathname", so widget properties can be specified in external files, command-line arguments etc. Also, the Editres protocol allows one program to query/set properties of a named widget in another program.
2. Widget properties (label, position, dimension) are being embedded in the code, which is a bad idea. This point is closely tied in with point 1.
Where should this be in your opinion?
For Xt-based programs, these settings are obtained via X resources. The X resource mechanism operates by merging several files to create a resource database. Properties which are specific to the application (e.g. widget labels) normally go into a file which is provided with the application (look in /usr/lib/X11/app-defaults/ or /etc/X11/app-defaults/ for examples). Other properties (typically stylistic properties such as colours and fonts) are normally defined by the user (e.g. in ~/.Xdefaults or via the RESOURCE_MANAGER property on the root window). The mechanism by which resource files are located allows for per-language resource files, as well as for different resource files for mono/colour displays, different resource files for different hosts (a single installation may be used on multiple systems via NFS), etc. On Windows, natural language strings normally live in a string table resource. This means that the translators only need to translate a simple text file, not source code. Also, specifying literal dimensions is normally wrong. A widget's dimensions vary depending upon the label (which is language-specific) and the font (which is a user preference). Xt-based toolkits don't normally use absolute positions, but specify positions relative to an edge of another widget or the parent. This deals with the fact that you don't know the sizes of the widgets at compile time, and allows the layout to remain sensible if the parent is resized (or if the parent's initial size wasn't what you were expecting; under X, you can't *force* a top-level window to have a specific size).
3. Personally, I would prefer a generic widget creation function, rather than a different function for each type of widget. E.g. Xt has XtCreateWidget(), with the widget class being passed as an argument. A more Haskell-ish approach would be to use typeclasses, e.g.:
class Widget a where create :: String -> a -> [Property] -> IO a -- create name parent properties = ...
That should be: create :: (Widget b) => String -> b -> [Property] -> IO a A widget's parent must be a widget, but not necessarily the same type of widget.
Why would you prefer this over the other method?
Partly for simplicity and uniformity in general, and partly for simplifying code which constructs UIs dynamically. If you have the generic interface, you can easily implement type-specific versions, e.g.: createLabel :: (Widget a) => String -> a -> [Property] -> IO LabelWidget createLabel = create createButton :: (Widget a) => String -> a -> [Property] -> IO ButtonWidget createButton = create OTOH, if you only have the type-specific versions, implementing a generic function comes down to a case statement which has to be extended as new types are added.
One problem with this method seems to be runtime errors for nonexistant classes.
No; with either approach, the class has to exist at compile time. If
you have widget-class values which are passed as an argument (as for
XtCreateWidget), you have to get the value from somewhere. With type
classes, the compiler will infer a specific type, which has to exist.
--
Glynn Clements

--- Glynn Clements
3. Personally, I would prefer a generic widget creation function, rather than a different function for each type of widget. E.g. Xt has XtCreateWidget(), with the widget class being passed as an argument. A more Haskell-ish approach would be to use typeclasses, e.g.:
class Widget a where create :: String -> a -> [Property] -> IO a -- create name parent properties = ...
That should be:
create :: (Widget b) => String -> b -> [Property] -> IO a
A widget's parent must be a widget, but not necessarily the same type of widget.
Ahh, I thought you wanted to create widgets based on the String parameter. So in the following code, you would get an ambiguity error, right? do -- mainWindow defined above a <- create "Some_Button" mainWindow [ label := "Okay" ] runGUI mainWindow -- or whatever it is. The system does not know if a is a button, a label, or whatever. It would have to look like this to remove the ambiguity do -- mainWindow defined above a <- create "Some_Button" mainWindow [ label := "Okay" ] :: Button runGUI mainWindow -- or whatever it is. It seems like this would defeat the purpose of having a generic create function since Button needs to be in there somewhere. Although, I do find your argument very credible. David J. Sankel

David Sankel wrote:
Ahh, I thought you wanted to create widgets based on the String parameter.
No; that wasn't the intention. Although Windows *does* refer to window classes by name; I'm not sure if that's relevant here, though.
So in the following code, you would get an ambiguity error, right?
do -- mainWindow defined above a <- create "Some_Button" mainWindow [ label := "Okay" ] runGUI mainWindow -- or whatever it is.
Yes.
The system does not know if a is a button, a label, or whatever. It would have to look like this to remove the ambiguity
With a type-class approach, the type would need to be explicitly specified somewhere most of the time; it may be that you specify the variable's type, or you store the handle in a record field which has a defined type. Occasionally you might pass the handle to a function which only operates upon a certain type of widget, in which case the compiler could infer the type.
do -- mainWindow defined above a <- create "Some_Button" mainWindow [ label := "Okay" ] :: Button runGUI mainWindow -- or whatever it is.
It seems like this would defeat the purpose of having a generic create function since Button needs to be in there somewhere. Although, I do find your argument very credible.
Different types of widget seem to have enough in common that type
classes might be an appropriate solution. Other factors might
contradict this, though.
--
Glynn Clements

On Wed, 5 Mar 2003 10:35:39 +0000
Glynn Clements
1. Widgets aren't being given names. This makes it impossible to refer to them from outside of the code. It also eliminates the possibility of implementing a useable Xt (e.g. Motif) backend. Toolkits which don't name widgets can just ignore the name.
Apart from the fact that I would like names for widget as an added comfort, why do you have to name widget to implement them in Xt? Couldn't you just use a unique string generator and wrap the names into an ADT? I apologize if the question is stupid. Vincenzo

Nick Name wrote:
1. Widgets aren't being given names. This makes it impossible to refer to them from outside of the code. It also eliminates the possibility of implementing a useable Xt (e.g. Motif) backend. Toolkits which don't name widgets can just ignore the name.
Apart from the fact that I would like names for widget as an added comfort, why do you have to name widget to implement them in Xt? Couldn't you just use a unique string generator and wrap the names into an ADT? I apologize if the question is stupid.
Well by "useable" [sic], I meant the ability to use resource files,
-xrm, Editres etc. Yes, you could implement an Xt backend, but using
automatically-generated widget names would significantly reduce its
functionality.
--
Glynn Clements

the widget name could just be another property, settable by whatever our standard get/set routines turn out to be. if 90% of toolkits ignore the name anyway, forcing a user to specify them always would probably result in people giving them meaningless names anyway if they don't know what they are for. we can probably generate somewhat useful names automatically. like button1..button3 for the first three children buttons of a given widget or whatnot... John On Thu, Mar 06, 2003 at 05:19:54AM +0000, Glynn Clements wrote:
Nick Name wrote:
1. Widgets aren't being given names. This makes it impossible to refer to them from outside of the code. It also eliminates the possibility of implementing a useable Xt (e.g. Motif) backend. Toolkits which don't name widgets can just ignore the name.
Apart from the fact that I would like names for widget as an added comfort, why do you have to name widget to implement them in Xt? Couldn't you just use a unique string generator and wrap the names into an ADT? I apologize if the question is stupid.
Well by "useable" [sic], I meant the ability to use resource files, -xrm, Editres etc. Yes, you could implement an Xt backend, but using automatically-generated widget names would significantly reduce its functionality.
-- Glynn Clements
_______________________________________________ GUI mailing list GUI@haskell.org http://www.haskell.org/mailman/listinfo/gui
-- --------------------------------------------------------------------------- John Meacham - California Institute of Technology, Alum. - john@foo.net ---------------------------------------------------------------------------

John Meacham wrote:
the widget name could just be another property, settable by whatever our standard get/set routines turn out to be.
On Xt, the widget name: a) isn't a property, b) has to be specified at creation time, and c) cannot subsequently changed. You could fudge a), by making the property-handling code have a special-case trap for the name; but that's ugly. BTW, some properties have to be specified at creation time, and can't subsequently be changed.
if 90% of toolkits ignore the name anyway, forcing a user to specify them always would probably result in people giving them meaningless names anyway if they don't know what they are for.
The proportion of toolkits doesn't matter; if you want to write code which works on all toolkits, you have to have a name. Also, there are benefits to having named widgets; e.g. it would be possible to implement some of Xt's features on other toolkits.
we can probably generate somewhat useful names automatically. like button1..button3 for the first three children buttons of a given widget or whatnot...
That results in a maintenance headache. If you add another widget,
subsequent widgets would get renamed, and you would then have to
change the resource files to match. Similarly, if a widget is
optional, the names of subsequent widgets would vary.
--
Glynn Clements

--- Glynn Clements
if 90% of toolkits ignore the name anyway, forcing a user to specify them always would probably result in people giving them meaningless names anyway if
John Meacham wrote: they don't know what
they are for.
I am in agreement with John here.
The proportion of toolkits doesn't matter; if you want to write code which works on all toolkits, you have to have a name.
I think writing code which works on all tookits is out of the scope of CGA. However, as Glynn agreed to before, names are not a requirement for a Motif backend. They simply would not play ball extremely well with the Motif style (but good enough IMHO), which should be noted is absent in most modern GUI API's. David J. Sankel
participants (4)
-
David Sankel
-
Glynn Clements
-
John Meacham
-
Nick Name