[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