[GUI] Are windows just ordinary widgets?

Wolfgang Thaller wolfgang.thaller@gmx.net
Fri, 2 May 2003 21:15:48 +0200


Axel Simon wrote:

> I don't understand what you mean with more upcast/downcast functions.
> Could you explain or give an example?

Things like toButtonClass below...

> I guess we do that widget-by-widget. And don't make these functions 
> part
> of the widget type class.
>
> I'd like to have
>
> setButtonLabel :: ButtonClass b => b -> String -> IO ()
> setButtonLabel b name = ... (toButtonClass b) ...

I'm a afraid of that toButtonClass function... toButtonClass is what I 
call an upcast function,
and upcast functions can only be implemented conveniently if they 
mirror what the backend does.
See also the discussion of HasOnActivate below.

>> import Attributes -- from the CGA example (indirectly from HToolkit)
>>
>> data Pane = ....
>> class PaneClass p where
>>     toPane :: p -> Pane
>>     fromPane :: Pane -> Maybe p
> Yes.
>
>>     -- plus any functions and attributes that are supported by all
>> kinds of panes
>>     -- and not supported by any window or other object
> No. Every function that is supported by all panes can be implemented 
> like
> the setButtonLabel example. I don't see any advantage of making these
> functions memebers of the class.

Ah yes. You're probably right.
But I'd like to add the remark that this _would_ have been a problem if 
we wanted to
do it for the "Widget" class which includes Windows and Panes, because 
not all backends have a common base type for windows and panes.
To avoid similar problems, I'd like to avoid having more "upcasted" 
types like Pane, and use type classes for everything else.

>> class Container c where
>>     -- ...
>>
>> class HasOnActivate a where
>> 	doOnActivate :: a -> IO () -> IO( IO() )
>
> No. As above.

Does that No refer to both Container and HasOnActivate?

For Container, I think we do need them, because there are at least two 
independent types which would implement the Container class, Window and 
GridBox.
A Window should contain only one child widget, because a Window doesn't 
have any layout algorithm (IIRC that's the same thing in GTK?).
Windows and GridBoxes are two completely independent types which cannot 
share any implementation on MacOS, so implementing the functionality 
via some toContainer function wouldn't work well.
That's why we should have a class for Container which contains all the 
functionality necessary for achieving dynamic layout. So I don't

As far as HasOnActivate is concerned...
We could have separate doOnButtonActivate and doOnToggleButtonToggle 
functions without any classes, but I don't think that has any 
advantages.
Are you perhaps thinking of

class ButtonClass b where
	toButton :: b -> Button
instance ButtonClass Button
instance ButtonClass ToggleButton
doOnActivate :: ButtonClass b => b -> IO () -> IO ( IO () )
doOnActivate b io = ... (toButton b) ...

I'm sceptical of that - is ToggleButton derived from Button in all 
backends?
Button and ToggleButton are actually siblings in Carbon (but there are 
still some common functions to work with them, so it's not a real 
problem; it might be in other cases, or for other backends).

That's why I'm in favour of relying on type classes that contain the 
actual functions rather than "toButton"-like functions for widgets;
... but as long as we're inside the "Pane" subtree, i.e. no Windows, I 
think that most problems can be worked around relatively easily. So my 
opinion isn't a very strong one in this case.

> I admit that I find it weird that the Button doesn't have a class. But 
> if
> it is a leave then it's probably not necessary.

My idea was to make all types inside the "Pane" hierarchy "leaves"; I 
wanted to represent all other relationships using different type 
classes.
That way, we can't accidentally make assumptions about relationships 
between widget types that just don't hold true on all backends.
On the other hand, a hierarchy with toFoo (upcast) functions could be 
perfectly viable _as long as_ we avoid the mistake of defining a 
hierarchy that "doesn't fit" with all backends.

>> mkButton :: Container c => c -> [Prop Button] -> IO Button
> newButton. Please!?

Now that you say it, yes!!
(I was copying from the CGA example without thinking about the 
naming...)

Cheers,

Wolfgang