Closed Daniel-Diaz closed 2 years ago
Hello Daniel, (wow, there are at least three different Daniels on this project)
sounds like a good idea! I think what we want is a collection of widget types and associated type classes similar to what wxHaskell offers. For instance, there is a Checkable class for widgets that can be checked or unchecked.
I very much appreciate widget suggestions and pull requests. However, before we proceed, I would like to establish a design guide for making widgets, as there are a few gotchas with point 3 when it comes to avoiding spaghetti code in the long run. I have put down some thoughts in a blog post of mine, but the post is already outdated and not entirely accurate.
I intend to write said design guide and put it in the repo soon, but that will take some time. Can you bear with me until then?
Hello Daniel, (wow, there are at least three different Daniels on this project)
Yes, next proposal is to rename the project to "The Apfelmus-Daniel GUI"!
sounds like a good idea! I think what we want is a collection of widget types and associated type classes similar to what wxHaskell offers. For instance, there is a Checkable class for widgets that can be checked or unchecked.
I am glad we are reaching an agreement here.
I very much appreciate widget suggestions and pull requests. However, before we proceed, I would like to establish a design guide for making widgets, as there are a few gotchas with point 3 when it comes to avoiding spaghetti code in the long run. I have put down some thoughts in a blog post of mine, but the post is already outdated and not entirely accurate.
Could you elaborate these "gotchas" of point 3? I have read the post you mentioned, but I think that, even when the issues may be related, they are not about the same thing.
I intend to write said design guide and put it in the repo soon, but that will take some time. Can you bear with me until then?
Sure. As soon as you get down with the design guide, we will be able to start coding right away, following the design principles. In the meanwhile, I will be using my provisional implementation of some widgets for my personal projects.
One of the other Daniels here :smiley:
Could you elaborate these "gotchas" of point 3? I have read the post you mentioned, but I think that, even when the issues may be related, they are not about the same thing.
As we wait for Heinrich, my three cents: at face value, your proposal puts two things on the table: (a) the suggestion to have standard types and classes for common widgets, which is clearly a good idea; and (b) the question about what the actual interfaces and implementations of these widgets will look like, which is where the gotchas, the blog post and the planned design guide meet. For instance, I am currently trying to use Reactive.Threepenny
to implement widgets that follow the three principles stated in the post. While later today I intend to open another discussion issue motivated by these experiments, it will strictly concern point (b); the desirability of (a) is indeed quite independent from it.
Concerning the widget class, I think it's a good idea to change the current element
function and introduce the following class instead
class Widget w where
getElement :: w -> Element
element :: Widget w => w -> IO Element
element = return . getElement
widget :: Widget w => w -> IO w
widget = return
instance Widget Element where
getElement = id
When employing the #
-style, we use the function element
when we want to modify the element and the function widget
when we want to modify the widget. Example:
element w #. "fancy"
widget w # set awesome True
Concerning the attribute setters and getters, i.e. point 3, we could certainly follow traditional GUI libraries and just list a few getters and setters, like WriteAttr
, ReadAttr
and Event
.
However, I think we can do better than that by connecting it to functional reactive programming (FRP). To give an example, I would like the value
property of an input widget to have "change notification" built-in. At the moment, we have
value :: Attr Input String
valueChanged :: Input -> Event String
but I would to see these combined into one thing, for instance a Behavior.
In fact, trying something new along these lines was my primary motivation for departing from wxHaskell and starting my own GUI framework. I have no idea how the new thing will look like, though. But I would like to get a better understanding of it before churning out lots of widgets.
To give you a more detailed overview of what I have in mind, I have now committed the first part of the widget design guide. The "Concepts" section is done, but of course, the "Implementation" sections is conspiciously unfinished.
To proceed, I think it's best that I commit the Widget
class to the development branch right away, so that you get at least a small convenience class for your own widgets, @Daniel-Diaz .
I submit this as a pull request, but please note that this is actually an API proposal.
The attached code shows an example of how it can be implemented in a particular simple case, and explains the general idea. Below I copy of the text that can be found at the source code. Module and function names and other details are provisional and I do not expect to keep them like they are right now. My only intention is to propose an idea.
If the proposal looks reasonable, I will continue working on it.
The idea is to organize elements as widgets. Instead of having every element with the same type, each kind of widget would have a type of its own. In the example above, a simple checkbox widget is implemented. It consists in the following parts:
About attributes, I think plenty of widgets are going to share some of them. In the example above, properties like 'checked' and 'text' may apply to other widgets as well. Type classes can solve this problem in an elegant way. A great consequence of implementing it this way is that users will be only allowed to apply attributes only to those type that makes sense to apply them to. Currently, attributes can be applied freely to any element, which might make the user wonder in each execution if the attribute will work or not, and then go back to code and try another one.
Note that elements will still be used, but certain tasks (like using lists, checkboxes, buttons, etc) can be achieved in a better way.