
On Sun, Apr 06, 2003 at 09:37:41PM -0700, David Sankel wrote:
--- Glynn Clements
wrote: Axel Simon wrote:
- Callbacks get separate functions which called on<WidgetName><ActionName>
Just on<ActionName> would be better. The "activate" callback is the same callback whether it's a push-button, toggle-button, etc.
I agree with this.
Ok, no problem. Related, but originally later in this email:
I agree that things like this should use classes:
class HasLabelAttribute a where -- ...
"Clicked" is likely to be an inappropriate name. E.g. several Motif widget classes have an "activate" callback. For a
Daan implemented a rather ad-hoc approach of partitioning attributes and callbacks into type classes (message from Mon, 10 Feb 2003 23:59:16 +0100). He agreed that a more orthogonal approach seems to be to either: a) give each attribute/callback its own class b) let each widget class containt all attributes and callbacks I don't like a) because we would define a lot of classes with rather special functionality (imagine "class ColumnChangeCallback"?!) which will only have a single instance in practice. This is particularly bad since the module system does not allow us to control what classes are exported, leading to a polution of the global class namespace and longer compile times. On the other hand b) doesn't seem to work out logically. Suppose we have push buttons, menu entries, table entries, etc. They can all be activated, thus the classes "Button", "MenuEntry", "TableEntry" need to have a member "onActivate". So we need to put this member in the parent of all these classes which is probably "Widget". But descendants of "Widget" include also "DialogBox" or something similar which cannot be activated. BTW Gtk takes the latter approach. Widget contains a callback called onActivate which is dead if the derived widget has no such capability.
Read-only or write-only attributes could be implemented by throwing an error for prohibited operations. Read-only attributes could be implemented by simply ignoring write operations. I agree with Alastair here that catching errors at compile is preferable.
Although I haven't discovered a use for write-only attributes for a gui toolkit, it seems that it would fit clearly in the constructor. Ok, some inspiration: Gtk allows labels to contain either a simple string or markup like "<red>warning</red>: about to erase file". If the markup is passed as an algebraic data type we would need to parse the label's text in order to get the algebraic data type back. So it's easier to consider the text of a Gtk lable as write only. But the label can be changed after the creation. Note that I do not claim that this is useful. We might get away with passing all write-only attributes at construction time.
newSomething requiredArgument [attribute := list]
For read-only attributes, you would most always want to read the value and nothing else.
h <- getHeight myButton I think it would be more systematic (and thus easier to learn) if we could use "get" here as well.
data WidgetClass w => Attr a w = <abstract>
Using "WidgetClass" will confuse anyone who is used to Xt. With Xt, a "WidgetClass" is a (pointer to a) record which describes the class itself; the individual widgets have type "Widget". That is the same in Gtk. But it is not possible to change the common class description without going through an instance. In gtk2hs I borrowed form gtk+hs which has class WidgetClass w where... and instance WidgetClass Widget where... which basically contains nothing but casting functions. The class names talk about types so I think it is consistent to use WidgetClass here. But I'll be flexible if this is fundamentally wrong.
-- An example for a Button widget: The constructor has one -- mandatory argument. newButton :: Container -> [Setter Button] -> IO Button
1. This omits widget name, which should be mandatory.
This has been discussed thoroughly earlier. There didn't seem to be a consensus to do this. I suggest that this be an CGA implementation specific extension. Maybe we can discuss that together with the layout issue. Specifying layout across GUI toolkits is probably one of the biggest challenges.
More importantly, most callbacks will need to take one or more parameters which provide further information about the event. [..] 1. Records (with named fields) would be preferable to tuples; Some callbacks get passed a significant amount of data.
Can you give an example where a standard widget would pass a significant amount of data? In Gtk you can connect to "onActivate" which takes "IO ()" as callback handler. If you go for the bare button click, it looks like this: | Button { sent :: Bool, click :: Click, time :: Integer, x,y :: Double, modif :: Modifier, button :: Button, xRoot, yRoot :: Double } which is one constructor for an "Event". I don't see an advantage in requireing to pass exactly one parameter to each callback. A lot of other events have two or three parameters, I think you can write that many underscores. Usually you are interested in at least one bit of information and then I'd rather write handler _ xPos _ = than handler (_,xPos,_) =
2. This approach requires a different function for each type of callback. I would prefer a single polymorphic addCallback function.
This is again making runtime errors into what could have been compile time errors. I think this is reason enough not to do it this way. Although I don't see the latter point, I object the single addCallback approach. It makes the implementation more difficult and programs harder to understand. I don't see any advantage.
Axel.