[GUI] Are windows just ordinary widgets?

Wolfgang Thaller wolfgang.thaller@gmx.net
Fri, 2 May 2003 00:08:41 +0200


Axel Simon wrote:
> Yes, I expected that. But perhaps we can create a (rather flat) object
> hierarchy which maps onto all backends.

If you say "object hierarchy", do you mean a set of types with upcast 
and downcast functions? Or are you referring to type classes?

As to "rather flat", I'd say yes, I think that's what we have to do.

> This was my proposal:
> http://haskell.org/pipermail/gui/2003-April/000459.html

OK so you're talking about upcast & downcast functions (as class 
members). At least that's how I would try to describe your approach. 
The question where to put the actual functions remains open.

I think upcast and downcast functions become ugly as soon as the 
hierarchy doesn't match the underlying backend.
What "upcasted" generic types do we need anyway?
As I said, we need a
data Pane = ....
class PaneClass p where
     toPane :: p -> Pane
     fromPane :: Pane -> Maybe p

... at least in order to be able to implement dynamic layout in Haskell 
(for platforms that don't have it).
I'm using the term Pane to mean any widget that can be placed inside a 
window; that is widgets minus windows and menu items.

Do we need any other upcast/downcast functionality?
Does anyone want to have a list of _any kind_ of widget, mixing windows 
and buttons and layout containers etc?
Does anyone want to have a list of any kind of buttons, that may 
contain both push buttons and toggle buttons, but no edit text fields 
and labels?
If the answer is no, then let's not include any more upcast/downcast 
functions, at least not in CGA 1.0, because they will never be 
conveniently implementable on all platforms at the same time.

We could then just have classes that contain some functionality, and 
some plain functions where a certain functionality is only available at 
one widget.
The next question we need to ask is, which widget type supports what 
functionality?
I'd say we should only use single-function HasFoo classes where 
necessary; I prefer having logical groups of functionality, like 
"Container"; but I don't have a strong opinion on this issue. On the 
other hand, one-function-per-class-style is harder to screw up --- it 
will probably take a few tries until we have figured out what 
functionality we can group together in classes. Perhaps we should do a 
rough design first (which would have classes like HasOnActivate along 
with classes like Container), and then, when everything is basically 
there, go over it again and reorganize some classes.

Below I've attached what I'm currently thinking of... could we have 
another quick "yes"/"no, because" vote and/or some counter-proposals?

Cheers,

Wolfgang

================== cut here ==================

import Attributes -- from the CGA example (indirectly from HToolkit)

data Pane = ....
class PaneClass p where
     toPane :: p -> Pane
     fromPane :: Pane -> Maybe p
     -- plus any functions and attributes that are supported by all 
kinds of panes
     -- and not supported by any window or other object

instance PaneClass Pane where
     toPane = id
     fromPane = Just
     -- ...

class Container c where
     -- ...

class HasOnActivate a where
	doOnActivate :: a -> IO () -> IO( IO() )

data Button = ...
instance PaneClass Button where
     -- ...
mkButton :: Container c => c -> [Prop Button] -> IO Button
instance HasOnActivate Button where
	doOnActivate = ...

data TextEntry = ...
instance PaneClass TextEntry where
     -- ...

mkTextEntry :: Container c => c -> [Prop TextEntry] -> IO TextEntry

data GridBox = ...
instance PaneClass GridBox where
     -- ...
instance Container GridBox where
     -- ...
column :: PaneClass c => Attr (GridBox,c) Int
row :: PaneClass c => Attr (GridBox,c) Int
columnspan :: PaneClass c => Attr (GridBox,c) Int
rowspan :: PaneClass c => Attr (GridBox,c) Int
-- plus some more

data Window = ...
-- no PaneClass instance for Window
instance Container Window