Open UplinkPhobia opened 3 years ago
Dialogs are only meant to be attached to the GUI, because that's how they can ensure that they appear above all of the other widgets.
My first instinct is that if you want a dialog widget with a non-GUI parent, then probably the best approach is to make your own widget class (which is pretty much what you've done). But maybe it'd be helpful if you could explain in more detail what you're trying to accomplish.
If the best way is to subclass, it's probably what I'll do if I need it.
Basically what I wanted to make (I'm just testing things, so it's not a big issue) was a sort of game interface, with menus on the sides and the map view in the middle (e.g. a 3-panes VBox, with the middle one being the one with the map and sprites and such and the others showing statuses, message logs, etc). My idea was that having popup menus that can be moved around and closed easily would be nice, for example an info popup or so, that you could move in a corner of the pane until you don't need it anymore. And I was trying to see if those popups could be "limited" to inside the map pane, so they wouldn't overlap with the other menus.
So as you can see, it's quite a specific use, that was more meant to be an experiment than a real need, and I'll manage if needed, I was just wondering if it was intentional to "limit" their root to the gui itself.
Thanks for the explanation by the way!
Ah, that makes sense. You'll definitely need custom widgets to get something like that, but it actually shouldn't be too hard. One thing to note is that you'll want to make use of ScrollPane
to implement dragging*. Specifically, I think you'd want the middle pane of your VBox
to be a Stack
, with the bottom layer being the game map and the top layer being a ScrollPane
(or possibly a custom ScrollPane
subclass). You'd then add your dialog widgets to the ScrollPane
, so that they'd appear on top of the map and could interact with the ScrollPane
to be dragged around.
If you decide to do this, a lot of the code in glooey/scrolling.py
might be informative. Specifically, Viewport
is a good example of a ScrollPane
subclass, and HVScrollBar.GripMover
is a good example of how dragging might be implemented. Let me know if you have any questions. The scrolling
module has a lot of tricky code and isn't very well documented, so it could be hard to understand. But I'm happy to answer questions, and getting questions would probably encourage me to improve the documentation...
TBH, there probably should be a built-in draggable dialog class that basically implements the scheme I outlined above. Not sure I'll get to that, but I would be interested in a PR if you end up implementing something similar. It might also make sense to generalize the Dialog
class so that it's parent can be any Stack
, but I'll have to think about that some more.
*Manually updating the coordinates of the widget (e.g. using a Board
or something) is very inefficient, because it forces glooey
to recalculate the positions and sizes of all the widgets composing the dialog each frame. ScrollPane
avoids this by using OpenGL to change where the dialog is rendered, without changing its underlying coordinates.
I managed to make a sort of working prototype with a board inside a scrollpane (I just used it to avoid crashes when the dialogs were dragged out of the window), since it felt the board was the only easy way to move widgets like that. It does indeed seem to be performance heavy, as it started lagging heavily when adding too many dialogs.
I'll try the solution you gave, but aren't ScrollPane only used to move the whole "view"? In such a case I'd need one pane per dialog if I want to show multiple dialogs?
In any case, I'll experiment and dig through the code, and if I manage to make something clean I could make a PR. Need to find motivation to work on it though :')
That's a good point, you would need one pane per dialog. That might not be a bad thing though, because it'd force you to be explicit about the layering of the dialogs (since each dialog would be associated with a different pane in a different layer of the stack). Maybe a good API would hide the scroll pane from the user, e.g.:
class DraggableDialog:
def __init__(self):
self.pane = ScrollPane()
self.pane.add(self)
def open(self, stack):
stack.add(self.pane)
def close(self):
self.pane.parent.remove(self.pane)
A quick correction: every time I mentioned ScrollPane
previously, I should've said Mover
. Mover
implements translation via OpenGL, while ScrollPane
implements clipping. It's the former that's relevant to dialogs.
Hey,
I tried creating a dialog that I'd add to a Board (to make a sort of "window" system). However closing them crashes as it tries to detach them from the gui and not the board.
Is there a clean way to do that? I tried replacing the open() and close() methods, but it doesn't really feel so clean.