
Glynn Clements wrote:
Wolfgang Thaller wrote:
b) Windows are not widgets. This can be done easily enough. It is less elegant as a) IMHO opinion. c) Windows are widgets. We must think about and handle the cases when a window is not a parent.
I'm for b), in the sense that Window should not be an instance of IsWidget. Implementing a common generic type for Windows and Controls/Panes is tedious/artificial on MacOS. I see no problem with Window being an instance of classes like HasSize, HasTitle etc. and providing many features that other widgets have.
So, if you take an arbitrary widget, and find all of its ancestors by repeated application of getParent (or whatever it's called), where do you end up?
On MacOS, you'd repeatedly call GetSuperControl() until you reach the root control of a window, for which there is no super control. For any "Control" (widget inside window, but not window), you can call GetControlOwner(), which returns the window that the control is in. Windows on MacOS do not have parents. Only while a window-modal dialog is _active_ it has a parent window. On Win32, IIRC, you get all the way to the top-level windows created by the application. This will be just one MDI frame window for MDI apps, but several windows for apps that use separate toplevels. We can map the hierarchy within windows one-to-one on all (?) platforms. The relationships between windows are less "standardized" and will require an additional abstraction layer. That's another reason why a distinction between Windows and Panes makes sense for CGA. BTW: why do you need to walk the widget hierarchy all the way to the top? The only reason why I ever needed to do that in any toolkit was to find the toplevel window that contained a widget (which could have been much easier if there had been a dedicated function for finding the Window, as there is on MacOS).
I'm dubious as to the implications of trying to declare that windows aren't widgets on backends where windows really are widgets.
Implementing the fiction is easy enough; you just end up with lots of pairs of functions with different names (e.g. getWidgetSize, getWindowSize) which happen to have identical implementations.
I thought that's what we have type classes for in Haskell. We'd have getSize implementations for Windows and for Panes (non-window widgets).
The problems lie in keeping up the illusion; unless you trap every single place where widgets escape to Haskell-land, code will end up being passed widgets which turn out to be windows.
Keeping up an illusion is always difficult. But we have to keep up at least one illusion, because otherwise we'd have not one cross-platform API but several platform-specific APIs. Now I realize that having different functions (like getWindowSize and getWidgetSize) is undesirable. Axel will probably oppose having another type class here. Also, using a type class will probably require explicit instance declarations for every widget type. It _is_ possible to unify Panes and Windows under MacOS; the MacOS implementation would have to look about like this: import Carbon(WindowRef, ControlRef) class IsWidget w where toWidget :: w -> Widget data Widget = WindowWidget WindowRef | ControlWidget ControlRef getSize :: IsWidget w => w -> IO (Int, Int) getSize w = case (toWidget w) of WindowWidget win -> getWindowSize win ControlWidget ctl -> getControlSize win getWindowSize win = ... getControlSize ctl = ... -- and so on for every function that all widgets have in common. I don't like that, but perhaps it's necessary. In any case, I still want class IsPane p where toPane :: p -> Pane Also, we should be very careful about where to put the container functionality. Not all widgets are containers, and I don't think the relation between windows can be referred to as a containment relationship (it should be treated separately). I'm in favour of a class Container, that is implemented by Window and by some specific types like GridBox. Widget constructors would then look like newFoo :: Container c => c -> [Prop Foo] -> IO Foo. The disadvantage of this is that it becomes hard to have a general getParent function... what are the alternatives? Cheers, Wolfgang