-
-
Notifications
You must be signed in to change notification settings - Fork 5.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
WIP: initial stab at an abstract graphics/GUI interface #3981
Conversation
In addition to the usual suspects when it comes to graphics, @stevengj it may be worth looking into how this might interact with your |
I have very limited qualifications to comment here, but this seems like a great direction to me. Being able to abstract out this common language for doing GUI stuff is a big deal. |
I should also add that despite the pull request against master, I'm well aware that this may be 0.3 material. |
I also generally like this direction. The biggest problem is that it seems not much can really be done abstractly. For example there is no need for a A slightly different possible direction is to define a full object model, where you might write (in a mathematica-ish way): Window("test", w, h, Frame(Button("OK", x->x), Button("Cancel", x->x), fill=true)) This would then be passed to |
There are zillion abstract GUI toolkits out there. Can you make a convincing case that your proposal adopts best practices? How does what you are doing relate to:
Let's not re-invent the wheel here. |
The only thing |
Why should we have a toolkit-agnostic approach rather than just picking one good one, like Qt or wx? It's a huge PITA to deal with things like matplotlib that support 15 different toolkit backends, each with slightly different semantics. |
This is not an attempt to replace This is an attempt to bring some small measure of consistency and rationality to our current mess of return types from functions that create new graphics objects. Pretty limited scope, really, but it's currently a blocking issue for making progress in graphics. |
Once you start adding buttons and other widgets, it seems like it will quickly get out of control and become another AWT. Even if that ends up being what we want, we should do it intentionally from the beginning and look carefully at other implementations in high-level languages. |
Basically we have the same "immediate mode" vs. "deferred mode" decision here as in For plain drawing, immediate mode is preferred since a vector graphic is not really stateful, and one tends not to need a hierarchy of lines and such (though you might have a hierarchy of canvases). We could write code to render from a vector object model to an immediate mode API very straightforwardly, (e.g. But GUIs might be different; all the APIs work by creating stateful objects, so maybe we should pick the object-model approach for GUIs by default. |
Lots of prior debate here. I should have referenced JuliaGraphics/Tk.jl#35 in this PR. That issue also refers to an old malinglist discussion. Bottom line, I'd also appreciate it if we pick just one and make it awesome. Even if we do that, however, I think something like this PR is necessary. It's basically part of a good wrapper even if we just have one toolkit. And currently, we have a fairly-mature-but-needs-cleaning-up wrapper around Tk, and a nice-start-but-not-fleshed-out wrapper around Gtk. |
Yes, I think with GUIs (and even just figure window management) it's all about managing state. Some of that can be generic, and I think this PR (because it's quite minimalistic) largely fits within the subset of functions that we can reasonably hope is amenable to a generic/portable solution. Whether we can go a great deal further than this in a generic wrapper is less clear. Whatever we write, it should be a facilitator, not a prison. |
The goal of this is to provide an easy way to make one-off exploratory GUIs. Something like EasyGUI is a good model. Most existing toolkits like Tk and Gtk are either too hard to use and/or don't match Julia well. I don't really want to support multiple backends either; I'd be fine with one that works reasonably well everywhere. I'm not totally convinced we need anything in Base for this. My current plan was to move the simple abstractions like Window and Button from the Tk package into their own package, and then you can pick whether to use full Tk, or the "EasyGUI" equivalent. Personally I only want the latter. |
You wouldn't design a programming language without looking closely at other languages first and making explicit choices. GUI toolkits, simple or complex, have a history of so many failures and so much complexity creeping into even "simple" stuff (think of AWT on both counts) that I think you'd be crazy not to do a survey first and explicitly fashion your design after successful models, or at least explain what techniques you are adopting and which you are rejecting. Let's please avoid half-assed toolkit design in a vacuum, with the excuse that we're only handling simple cases so we don't need to think much about where this is going. |
Another view of this PR is to say simply: to support graphics, Base needs an implementation of a tree data structure. Providing that---and nothing more---is more than half of the code in this PR, and pretty close to the only real "work" being done. A detail is that it has to be one that allows the different nodes to have different types so we can do dispatch on different types of graphics objects. (EDIT: and for dispatch you need to expose that type as a parameter of the node.) I think the issue being addressed here is less "what is a Button and how can we make it simple to use?" and more "how do you keep track of the zillions of items that get created as you build a GUI"? That is, without having to write functions like
In other words, basically we have a big hole in our data structures support. It's just happens that graphics is the place that most pressingly needs this support. (Note that I also wrote a left-child-right-sibling tree for parsing the callgraph in |
What data structures and access models for widgets do successful toolkits use? Moreover, once you have a tree of widgets where you can access callbacks and other properties of the widgets, you are basically designing an AWT. And if you can't access those properties, then the tree is useless. So, you haven't really answered my objection. |
Don't know whether Matlab counts, but there every graphics handle lets you query parents and children. Qt: C++'s inheritance mechanism contributes strongly to a tree structure. More directly, all graphics objects inherit from So for both of these, trees are basically the "root" (pun intended) of the graphics system. We don't have a tree in base, and we need one :-). |
We are making explicit choices. Some of the choices are being discussed here, and some are being or have been discussed elsewhere. Tim and I (and other Julians) have used many gui toolkits. I don't think anybody is advocating that we be half-assed and not think. I do advocate a pretty extreme level of API simplicity though. I'm not worried about being trapped by this, since more widgets can be added, and more options can be added without breaking code (e.g. with keyword args). Most GUI toolkits are very tied to their implementation language. In C++ you often see |
It would be more satisfying (and convincing) to see a rationale along the line of "Qt has a tree consisting of these kinds of objects with this kind of interface" (not to mention their whole signals and slots approach, whose analogue in Julia would probably be more like publish/subscribe coroutines than passing function pointers), SWT does X (e.g. in SWT the windows ["shells"] are not root nodes, and there is instead a top-level "display" which manages event loops, global menus?, etc.), and wx does Y. We are doing Z, because.... A lot of toolkits also have concepts like "Layouts" (e.g. in Qt) to automatically manage widget arrangements. And then there is the whole question of graphical GUI builders, which are important if you are going for maximum ease-of-use. |
It's called "multiple dispatch." In this PR, a node is this:
That's it. All the magic is in
Not true. Do you realize that currently, while |
@timholy, it's precisely the question of T that is at issue here, not the design of a trivial tree data structure. Some key questions are what the widget hierarchy looks like, how the widgets are addressed, what kind of functionality the widgets expose, how the widget layout is specified, whether you use callback functions or publish/subscribe model or ..., how/what events are described, and so on. If you just want to standardize |
You're dismissing the trivial things, but the trivial things are the only things I'm interested in. There are many places in our current graphics API where a few well-placed tweaks will make a considerable difference in the programmer experience, and also let us do things that currently we can't do. That's true no matter whether this is the only API we ever get, or whether we in due course migrate to something else. Often good design has some element of abstraction to it (your I have little taste at the moment for biting off enormous projects on the scale of what AWT sounds like it must be. I think you're projecting your unhappy python experience into a place where it's not necessary. When we get an awesome wrapper around Qt, I'll be a happy guy and probably use little else. But Jeff's EasyGUI idea will still be valuable for those folks who just want to have a single graph with an entry box they can use to tweak a parameter. |
I'm just worried that we will solve the trivial problems in a way that makes it more difficult later to solve the hard problems. And the bitter experience of Java AWT (not to mention the many, many other GUI toolkits in the dustbin of history) shows that it is really easy to get widget abstractions wrong (to the extent that they had to pitch the whole thing in the trash and start over). If you just want to keep track of what windows are open and be able to close them, that may be reasonable. It's when we start building simplistic abstractions for the things inside the window, for buttons and mouse events, that I get worried. |
I'm not sure this needs to be in base. There could be a GUI metapkg which Tk, Gtk, etc. depend upon. which provides a basic "gui" layer. Interfaces in Julia typically should be about functions (and abstract types), not the types that implement them. For example, implementing a
I was going to point this out as well. What you and Tk call a Frame is very similar to what Gtk calls a Layout. However, it's not clear to that this tree adequately reflects the infrastructure necessary for Gtk. Toolkits like GTK don't necessarily have generic "children", since the concept of child and layout is tightly coupled. What they have is probably best described as a hierarchy of layouts ending in an object (which may itself have a hierarchy of layouts). |
I don't believe widget abstractions are all that hard. As far as I can tell, the problems with AWT/Swing are that they look ugly and not native, people aren't quite happy with the layout managers, and code is verbose (common in java). In a generally terser language with closures things are easier. We also have the ability to add arguments and keyword arguments to methods without breaking code. @vtjnash makes a good point; I'm not sure we want a "shadow hierarchy" of objects. I also doubt we can do much generically with a widget tree or an It matters a lot to decide what use cases we care about. For example, do we want to be able to |
Definitely an interesting question, but not one I plan to tackle personally any time soon (I simply don't have the expertise). Don't let me stand in anyone else's way though :-). Given Gadfly's terrific recent progress in displaying to a web browser, that seems like a natural context for exploring such questions. @vtjnash, very useful feedback. I think we're zeroing in on the notion that this should largely be a Tk-specific cleanup. While I have everyone's attention, there are a few specific points worth bringing up for discussion. Important questions:
Less-important questions (either I think I already know the right answer, or it's a small detail we can easily change later):
|
@JeffBezanson, I think the difficulty is precisely the fact that people want their widgets to look native, i.e. to use the native toolkit in the back end, contrasted with the fact that it is hard to write an abstract GUI and have an "existing toolkit comply with whatever is specified". |
I'm working on this in Tk.jl, so closing here. |
Despite some earlier comments by myself in this thread about the how this is a bad idea, I have written a package that abstracts out some of the easier parts of writing a GUI. The backend is implemented for both |
Looks great, I hope to have time to dig into it. I need to think about how to do a more efficient and more julian |
Note that the IPython community is working hard on GUI manipulation capabilities (focusing on JavaScript widgets in the browser, I think). See ipython/ipython#4195 |
It will be great to have that stuff in IJulia. If we had it now we probably wouldn't be working on things like this, assuming the performance is ok. |
Once it lands in IPython, it sounds like it should be straightforward to implement the spec in Julia and leverage the same Javascript widgets. |
@jverzani, I haven't looked at the details, but the principle is great! Can I finally stop robotically adding |
@stevengj, @JeffBezanson, I think expanded browser-based GUI capabilities would be awesome, but I really doubt it will replace the need for a full GUI system. Among other problems, the browser itself intercepts too many things. For example:
Sometimes you basically need to take full control of the GUI environment, and the browser will never let you do that. Of course it would be possible with something built from the ground up based on WebKit, but that's a different issue. |
Well, you might not like
|
How about |
Julia programs certainly need the option of full GUI access, but the question is whether we should have an AWT in Base that sits on top of existing platform-independent toolkits like Qt or Tk, as opposed to just having people pick a toolkit and use it directly. (The zooming question is a red herring, since zooming of plots should be handled by the backend/widget interaction, not by the browser.) |
Oh, I agree we should just pick Qt and be done with it :). |
@timholy All of those things have been possible in a browser for many years. You can directly manipulate images and sound in HTML5*. The only area the browser falls short of desktop GUI toolkits is with respect to access to the local file system. Qt sounds good to me. But until Julia can bind to C++, I've been advancing the state of Gtk: https://github.com/JuliaLang/Gtk.jl/tree/jn/layouts. I've done layouts and buttons. Still working on an easier events manager, images, rich-text widget, and menus. It natively supports getindex/setindex! style operation for configuring many of its features. For example, *you'll have to wait for the next version of IE for some of the features |
Hmm, last time I tried google docs none of that worked. Maybe that was a while ago :). If IPython would permit one to bind the space bar to a "pause/restart the video playback" (and the rest of those features) then I'd say that perhaps this is the way we should go. @vtjnash, I hadn't realized you'd picked up Gtk again; I'll have to take a look sometime. |
I'm worried that Qt is both very large in itself, and will require huge amounts of wrapper code due to being C++. I think many people have the requirements of (1) very easy to program, (2) performs well, (3) portable. @timholy is almost a perfect example of this, except he doesn't really need (1) but I assume would prefer it :) I don't want to reinvent the wheel, but this particular wheel sucks. For example, many people would benefit from being able to create simple |
My fear too. I had wondered about starting a Portable & performant: definitely key requirements. These days I'm kinda bummed about Tk in both of those departments. If you're just showing one image in one window, Tk's performance seems fine (that is, with the rather serious exception of JuliaGraphics/Tk.jl#57), but even simple stuff like dragging a second window across the first one introduces weird latencies, etc. Theoretically I should just figure out what I need to do to fix those issues, but between limited time and a sense that maybe the better plan is to switch toolkits, I just haven't done that.
I'm all in favor of easy!
I've had the same sense, although perhaps that's because at this point I know the low-level stuff better than I understand Winston's internals. |
One can already get at Qt via PyCall. I don't see why someone would undertake the work involved to do so directly from Julia, as in theory this access is as easy as installing Anaconda, then Pkg.add("PyCall"). The huge upside of @vtjnash 's work on Gtk is the integration with Cairo. The basic graphics of WInston will just work along with the GUI controls. |
If we wanted to use QPainter as an alternative to Cairo, I wonder if the overhead of going through Python would be too large. Perhaps we could just wrap QPainter, and use PyCall for everything else? But I'm excited about @vtjnash's Gtk work, so I plan to sit tight and see how that works out. As long as Gtk doesn't end up having its own share of major downsides, I'm all in favor of something that's ready rather than something that will take a lot of effort to get going. |
In the |
Hard as it is to believe, I'm starting to feel like all the GUI toolkits fall short. |
I did some profiling, and basically all the time is spent either in |
Here's a beginning at a generic specification of a window-management/GUI interface. It is toolkit-agnostic (and consequently can't do very much), but it already attempts to provide some facilities that we currently lack. I'm posting it at this early phase because there's enough in place to be able to ask whether this is moving in the right direction, and it's a lot of work to go much further than this.
Most importantly, this organizes graphics objects into a tree, making it possible to query the list of windows, delete objects, etc. For example, currently we have no way (that I know of) of closing all opened windows in a session, short of quitting the session; this will fix that, among other things. In theory you should be able to use multiple toolkits simultaneously (e.g., Tk and Gtk) and everything will work automagically (whether that's wise is another matter...).
For Tk, something like this pull request this will allow us to resolve a currently-messy issue: the split between
TkWidget
andTk_Widget
etc (the various container types). We have two ways of creating windows, one of which can store elementary parent/child relationships and the other which cannot. Moreover, even if you create objects with theTk_Widget
type, traversing towards the root returns aTkWidget
, which means that you've lost the type information (including information about the children in container-objects). Consequently, if you go up a level, you can't go back down again. Fixing such issues should, among other things, make it much easier to address JuliaGraphics/Tk.jl#53.I've gone to some effort to insulate the "toolkit implementer" from the details of tree traversal (and particularly, from having to maintain the organization of the tree). The basic design principle is that
GraphicsHandle
s are to be returned by all operations that create graphics objects, and these handles are simply nodes in a tree. However, they are typed nodes, and consequently when used as arguments they will dispatch to the right functions.None of this is "wired in" yet; you have to
include()
/using
(which facilitates testing at this early stage). Here's a demo session:And here was my
guitest.jl
, which is basically what the "toolkit implementer" needs to write:You can see the generic wrapper releases the implementer from having to worry about any of the tree-hierarchy details.