[GUI] RFC: CGA-Example 1.2 stuff

Axel Simon A.Simon@ukc.ac.uk
Fri, 2 May 2003 19:11:18 +0100


On Thu, May 01, 2003 at 11:59:48PM -0400, David J. Sankel wrote:
> Before I finish CGA-Example 1.2 we ought to reach a sort of concensus on 
> certain issues.  Here is what I think will be in 1.2.  This is a RFC: 
> 
> ####
> ## 1.  A matching LaTeX specification. 
> 
> This will include a section for platform specific extensions via the module 
> system.

I don't think we really need a specification in Latex. I'd rather see a 
set of Haskell modules with empty function bodies. The explanaition can be 
in the Haddocked comments.

> There could be implementation (toolkit,back-end) specific 
> extensions where the implementation is called IMPL.  Those would go under: 
> 
> CGA.extentions.IMPL 

Backend provide a superset of the entities defined in the CGA 
specification. But the difference to the CGA is not an extension.

> Their might be general extensions that might intersect implementations.  
> Lets say the extension is called OpenGL: 
> 
> CGA.extentions.OpenGL 
> 
> And for extensions that use a different constructor (with the extension 
> named EXT, we would use: 
> 
> data T_EXT = A_EXT Int | B_EXT float . . . 

No, please. I think using the module system is nicer. We don't need to 
create aritifical name spaces because we are not in C. Let me clearify:

Let's suppose the file CGA.hs in the fptools repository contains the
following definitons:

module CGA(Foo(..), foo) where

data Foo = Bar

foo :: Int -> Int
foo = undefined

Anyone providing a backend to the CGA copies the first line into her/his 
library under the same name. If that person is me, I would write:

module CGA(Foo(..), foo) where

import Gtk (Foo(Bar), foo)

thus I only make things from Gtk visible which are defined in the CGA. If 
the user wants to use the Gtk specific constructors Bar2 and the function 
bar (s)he needs to write:

import CGA
import Gtk

-- Gtk specific function: uses Bar2 constructor.
myFunc :: Foo -> Foo
myFunc Bar2 = Bar
myFunc Bar = Bar

And by explicitly importing Gtk the user is aware that (s)he uses backend 
specific extensions. Additional benefits:

- the user can try to compile her/his GUI application with -package CGA. 
It won't run, but if it compiles (s)he can be sure the program would run 
with another backend as well.

- we could provide a program that uses all functions from the CGA in 
fptools repository. By compiling this program against different backends, 
we could check that we export everything that the CGA requires.

- the modules in the fptools repository can serve as the documentation for 
people writing cross-platform applications.

> ####
> ## 2.  toWidget out of IO Monad. 
> 
> That is if we want to continue with this route.  The other route being the 
> class hierarchy. 
> 
> Benefits of toWidget style:
> Allows for lists of widgets.
> Allows for compositional construction of new widgets. 
> 
> Negatives of toWidget style/Benefits of class Hierarchy:
> OO style of custom widget construction
> No lists of Widgets.
> How would children work?
> Class hierarchy probably will not match all backends. 
I am confused about the different routes. I would need to have a closer 
look to see these points.

> 
> ####
> ## 3.  Multiple Callback Support with unregister support. 
> 
> This is fine and dandy minus the implementation details.  If this is 
> implemented in Haskell, we have two possible ways to do this.  These refer 
> to each callback list instance. 
> 
> a) We maintain a list of IO callback methods.  Each callback is identified 
> by it's index in this list.  When a callback is unregistered, it's index is 
> changed to the (return ()) callback. 
> 
> b) Each callback is given a unique identifier by some generator.  When a 
> callback is unregistered, it will filter the list and remove the invalid 
> callback. 

Why do you need to keep the unregister functions in a list? Is this 
specific to your example?

> ####
> ## 4.  Is a Window a Widget? 
> 
> a)  No Windows. 
> 
> A window is certainly different than an ordinary widget.  It doesn't make 
> any sense to have a window as a child of another window.  However, we may, 
> perhaps, be able to remove the window completely from CGA.  (this may be a 
> bit too different). 
> 
> Lets say that an object without a parent can be displayed on the screen.  
> So, if I say 
> 
> >a <- mkButton [ label := "okay", visible := True ]
> >doOnActivate a (exitWith ExitSuccess)
> 
> I will get a button on the screen with the title bar stating "okay" with 
> the label being "okay".  Or perhaps the title bar says nothing.  Simple 
> applications don't require messing around with windows.  A window is simply 
> the highest parent in the family.  This way everything can logically be a 
> widget. 
> 
> What about specialized windows with titlebars, etc.  For some widgets, say 
> VBox, we may want added attributes like title.  Eventually when we get to 
> cross-platform application widgets (with menu's, etc . . .) we just make 
> one of these the highest in the hierarchy.  If it is not the highest, it 
> could still be useful . . . say in a gui builder. 
> 
> b)  Windows are not widgets.  This can be done easily enough.  It is less 
> elegant as a) IMHO opinion. 

I don't really see an advantage in a), though. Just avoiding two lines to 
create a containing dialog around a button is not a good justification of 
all the implementation work involved in your proposal IMHO.

I think b) is most elegant and fits in when we define different classes of 
applications/dialogs.

> c)  Windows are widgets.  We must think about and handle the cases when a 
> window is not a parent. 
> 
> ####
> ## 5.  Adding children to a parent. 
> 
> Certain widgets and windows can have children widgets.  How do we add them? 
> 
> If 4a) was implemented, we could talk about widgets independent of parents 
> and it wouldn't be a problem on Mac. 
> 
> Otherwise, we need to assess the usefulness of creating a widget without a 
> parent. 
> 
> ##
> Benefits of no-parent construction: 
> 
> Code for certain container class would reflect the thinking of the 
> programmer more and makes for easy change.  For example: 
> 
> >set container [ children := [name, address, phoneNumber] ]
> 
> could be quickly rearranged to 
> 
> >set container [ children := [name, phoneNumber, address] ]
> 
> For certain containers, such as GridBox, the name of the child as well as 
> other parameters must be set to make it a child.  This creates problems. 
> 
> ##
> Benefits of parent construction: 
> 
> Writing backends for Mac platforms would be easier.
> It doesn't make any sense to create a widget without parent (unless 4a was 
> implemented) 

Can we come up with an example where the latter falls over (providing the 
parent when you create a widget)? This approach always avoid the problem 
of the user adding one widget to two different widget hierarchies.


> ####
> ## 6. certain Has* functions need to be made for every widget 
> 
> The fltk implementation is more verbose than it needs to be.  I could have 
> made these redundant functions transform the item into a Fl.Widget for a 
> default. 

I don't like Has* classes. But I guess I made myself clear already.

> ####
> ## 7. Heiarchy 
> 
> Should there be an object hierarchy?  Since this is a simple thing to add 
> after it has been implemented with the Has* functions, I suggest we push 
> this back.  Since toWidget is simple enough for now, I think we should 
> stick too it. (I'm interested in counter-opinions though) 

I'll have a look.

Axel.