@@ -7,11 +7,12 @@ class Piece(QtWidgets.QGroupBox):
7
7
A single `Piece` object is an unit of automation - an object that is meant to represent a single
8
8
physical instrument (like a laser) or a particular functionality (like a plotter or a parameter scan).
9
9
10
- Pieces can be assembled into a :class:`~puzzlepiece.puzzle.Puzzle`.
10
+ Pieces can be assembled into a :class:`~puzzlepiece.puzzle.Puzzle` using the Puzzle's
11
+ :func:`~puzzlepiece.puzzle.Puzzle.add_piece` method.
11
12
12
13
:param puzzle: The parent :class:`~puzzlepiece.puzzle.Puzzle`.
13
- :param custom_horizontal: A bool flat , the custom layout is displayed to the right of the main controls
14
- if True.
14
+ :param custom_horizontal: A bool, the custom layout is displayed to the right of the main controls
15
+ if True.
15
16
"""
16
17
def __init__ (self , puzzle , custom_horizontal = False , * args , ** kwargs ):
17
18
super ().__init__ ()
@@ -72,7 +73,7 @@ def action_layout(self, wrap=2):
72
73
"""
73
74
Genereates a `QGridLayout` for the actions. Override to set a different wrapping.
74
75
75
- :param wrap: the number of columns the actions are displayed in .
76
+ :param wrap: the number of columns the actions are displayed in.
76
77
:rtype: QtWidgets.QGridLayout
77
78
"""
78
79
layout = QtWidgets .QGridLayout ()
@@ -118,6 +119,35 @@ def setup(self):
118
119
"""
119
120
pass
120
121
122
+ def open_popup (self , popup ):
123
+ """
124
+ Open a popup window for this Piece. A popup is a :class:`puzzlepiece.piece.Popup`
125
+ object, which is like a Piece but floats in a separate window attached to the main
126
+ :class:`~puzzlepiece.puzzle.Puzzle`. This can be used for handling additional tasks
127
+ that you don't want to clutter the main Piece. See :class:`puzzlepiece.piece.Popup`
128
+ for details on implementing a Popup.
129
+
130
+ :param popup: a :class:`puzzlepiece.piece.Popup` _class_ to instantiate
131
+ :rtype: puzzlepiece.piece.Popup
132
+ """
133
+ # Instantiate the popup
134
+ if isinstance (popup , type ):
135
+ popup = popup (self , self .puzzle )
136
+ popup .setStyleSheet ("QGroupBox {border:0;}" )
137
+
138
+ # Make a dialog window for the popup to live in
139
+ dialog = _QDialog (self , popup )
140
+ layout = QtWidgets .QVBoxLayout ()
141
+ dialog .setLayout (layout )
142
+ layout .addWidget (popup )
143
+
144
+ # Display the dialog
145
+ dialog .show ()
146
+ dialog .raise_ ()
147
+ dialog .activateWindow ()
148
+
149
+ return popup
150
+
121
151
def call_stop (self ):
122
152
"""
123
153
This method is called by the parent Puzzle when a global stop is called.
@@ -130,8 +160,8 @@ def call_stop(self):
130
160
131
161
def handle_close (self , event ):
132
162
"""
133
- Only called if the :class:`~puzzlepiece.puzzle.Puzzle` debug flag is False.
134
- Override to disconnect hardware etc when the main window closes.
163
+ Only called if the :class:`~puzzlepiece.puzzle.Puzzle` :attr:`~puzzlepiece.puzzle.Puzzle.debug`
164
+ flag is False. Override to disconnect hardware etc when the main window closes.
135
165
"""
136
166
pass
137
167
@@ -218,4 +248,65 @@ def wrapped_main(self, *args, **kwargs):
218
248
return True
219
249
else :
220
250
ensure_function (self )
221
- return ensure_decorator
251
+ return ensure_decorator
252
+
253
+ class _QDialog (QtWidgets .QDialog ):
254
+ """
255
+ A variant of the QDialog specifically for popups, handles closing them
256
+ with a custom function.
257
+ """
258
+ def __init__ (self , parent , popup , * args , ** kwargs ):
259
+ self .popup = popup
260
+ super ().__init__ (parent , * args , ** kwargs )
261
+
262
+ def closeEvent (self , event ):
263
+ self .popup .handle_close ()
264
+ super ().closeEvent (event )
265
+
266
+ class Popup (Piece ):
267
+ """
268
+ A Popup is similar to a Piece, but floats in a separate window attached to the main
269
+ :class:`~puzzlepiece.puzzle.Puzzle`. This can be used for handling additional tasks
270
+ that you don't want to clutter the main Piece. For example you can have a camera
271
+ Piece which can open a Popup to set the camera's region of interest with an interactive
272
+ plot window.
273
+
274
+ A Popup can be created and displayed by calling :func:`puzzlepiece.piece.Piece.open_popup`.
275
+
276
+ A Popup is attached to a specific Piece and knows it through its
277
+ :attr:`~puzzlepiece.piece.Popup.parent_piece` attribute, but it can also access other
278
+ Pieces through the Puzzle, which it knows through its :attr:`~puzzlepiece.piece.Piece.puzzle`
279
+ attribute.
280
+
281
+ A Popup can have params, actions, and custom layouts just like a normal Piece, and are created by
282
+ overriding :func:`~puzzlepiece.piece.Piece.define_params`, :func:`~puzzlepiece.piece.Piece.define_actions`,
283
+ and :func:`~puzzlepiece.piece.Piece.custom_layout` like for a Piece.
284
+
285
+ :param puzzle: The parent :class:`~puzzlepiece.puzzle.Puzzle`.
286
+ :param parent_piece: The parent :class:`~puzzlepiece.piece.Piece`.
287
+ :param custom_horizontal: A bool, the custom layout is displayed to the right of the main controls
288
+ if True.
289
+ """
290
+ def __init__ (self , parent_piece , puzzle , custom_horizontal = False , * args , ** kwargs ):
291
+ self ._parent_piece = parent_piece
292
+ super ().__init__ (puzzle , custom_horizontal , * args , ** kwargs )
293
+ self .layout .setContentsMargins (0 ,0 ,0 ,0 )
294
+
295
+ @property
296
+ def parent_piece (self ):
297
+ """
298
+ A reference to this Popup's parent :class:`~puzzlepiece.piece.Piece`,
299
+ the one that created it through :func:`puzzlepiece.piece.Piece.open_popup`.
300
+ """
301
+ return self ._parent_piece
302
+
303
+ def handle_close (self ):
304
+ """
305
+ Called when the Popup is closed. Override to perform actions when the user
306
+ closes this Popup - for example delete related plot elements.
307
+
308
+ In contrast to :func:`puzzlepiece.piece.Piece.handle_close`, this is called even
309
+ if the :class:`~puzzlepiece.puzzle.Puzzle` :attr:`~puzzlepiece.puzzle.Puzzle.debug`
310
+ flag is True.
311
+ """
312
+ pass
0 commit comments