CMS 3D CMS Logo

 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Pages
WidgetContainer.py
Go to the documentation of this file.
1 import logging
2 
3 from PyQt4.QtCore import *
4 from PyQt4.QtGui import *
5 
6 from Vispa.Gui.VispaWidget import VispaWidget
7 from Vispa.Gui.ConnectableWidget import ConnectableWidget
8 from Vispa.Gui.ConnectableWidgetOwner import ConnectableWidgetOwner
9 from Vispa.Gui.PortConnection import PortConnection
10 
12 
13  # inherited properties
14  BACKGROUND_SHAPE = 'ROUNDRECT'
15  #PEN_COLOR = QColor('blue')
16  PEN_COLOR = QColor(0, 75, 141)
17  FILL_COLOR1 = QColor('white')
18  FILL_COLOR2 = QColor('white')
19 
20  WIDTH = 10
21  HEIGHT = 10
22 
23  AUTOSIZE = True
24  AUTOSIZE_KEEP_ASPECT_RATIO = False
25 
26  # new properties
27  AUTOLAYOUT_CHILDREN_ENABLED = False
28  AUTOSIZE_ADJUST_CONTAINER_POSITION = True
29 
30  def __init__(self, parent=None):
31  #logging.debug(__name__ + ": __init__()")
32  self._childrenVisible = True
35  self._collapseMenuButton = None
36  self._collapsable=True
37  self._hiddenChildren = []
38 
39  ConnectableWidget.__init__(self, parent)
40 
43 
44  self.setShowCollapseMenu(True)
45 
46  def enableAutolayoutChildren(self, autolayout):
47  """ If autolayout is True children of this container are arranged when this container auto-sizes.
48 
49  If this option is enabled make sure children are not dragable because that would conflict with autolayouting.
50  """
51  self._autolayoutChildrenEnabled = autolayout
52 
55 
58 
60  return self._autolayoutChildrenEnabled
61 
63  """ If container is collapsed use single background color.
64  """
65  if self._childrenVisible:
66  ConnectableWidget.defineBackgroundBrush(self)
67  else:
68  self._backgroundBrush = self.penColor()
69 
70  def sizeHint(self):
71  """ Calculates needed space for content.
72  """
73  #logging.debug(__name__ +": sizeHint()")
74  childrenRect = self.childrenRect()
75  width = childrenRect.bottomRight().x() + self.getDistance('rightMargin')
76  height = childrenRect.bottomRight().y() + self.getDistance('bottomMargin')
77 
78  # make zoom independent
79  width = 1.0 / self.zoomFactor() * width
80  height = 1.0 / self.zoomFactor() * height
81 
82  # from now on in 100% dimensions
83  superClassNeededSpace = VispaWidget.sizeHint(self)
84 
85  width = max(width, superClassNeededSpace.width(), WidgetContainer.WIDTH)
86  height = max(height, superClassNeededSpace.height(), WidgetContainer.HEIGHT)
87 
88  return QSize(width, height)
89 
90  def contentStartX(self):
91  """ Get start x coordinate position of widget content. Especially for autolayoutChildren().
92  """
93  return self.getDistance("contentStartX")
94 
95  def contentStartY(self):
96  """ Get start y coordinate position of widget content. Especially for autolayoutChildren().
97  """
98  return self.getDistance("contentStartY")
99 
100  def autosize(self):
101  """ Overwrite VispaWidget's function.
102 
103  This adds size and position handling for left and top sides of container.
104  VispaWidget only takes care of right and bottom sides as widget position remains constant.
105  This function also adjusts the container's position as needed to include all children.
106  """
108  self.autolayoutChildren()
109  self.updateConnections()
110 
111  childrenRect = WidgetContainer.childrenRect(self)
112  if self._autosizeAdjustContainerPositionFlag and self._childrenVisible and (childrenRect.width() != 0 or childrenRect.height() != 0):
113  # increase / decrease size of container on left and top side
114 
115  # round to prevent drifting wehen zoom != 100%
116  xMargin = round(self.contentStartX())
117  yMargin = round(self.contentStartY())
118  childrenRectX = childrenRect.x()
119  childrenRectY = childrenRect.y()
120 
121  xOffset = 0
122  yOffset = 0
123  if childrenRectX != xMargin:
124  xOffset = - childrenRectX + xMargin
125  if childrenRectY != yMargin:
126  yOffset = - childrenRectY + yMargin
127 
128  if xOffset != 0 or yOffset != 0:
129  self.move(self.x() - xOffset , self.y() - yOffset)
130  for child in self.children():
131  #if isinstance(child,QWidget): # needed for PyQt4.5
132  if hasattr(child, "move"):
133  child.move(child.x() + xOffset, child.y() + yOffset)
134 
135  VispaWidget.autosize(self)
136  self.emit(SIGNAL("sizeChanged"), self)
137 
139  """ This function arranges children one after each other in a column.
140 
141  See setAuotlayoutChildrenEnabled().
142  """
143  #logging.debug(self.__class__.__name__ +": autolayoutChildren()")
144 
145  # round to prevent drifting when zoom != 100%
146  xPos = round(self.contentStartX())
147  yPos = round(self.contentStartY())
148 
149  for child in self.children():
150  if isinstance(child, VispaWidget) and child.isVisible():
151  child.move(xPos, yPos)
152  yPos += child.height() + self.getDistance("topMargin")
153 
154  def widgetDragged(self, widget):
155  """ Call autosize().
156 
157  Overwritten function of ConnectableWidgetOwner.
158  """
159  if self.autosizeEnabled():
160  self.autosize()
161  # not sure this is still needed (2010-07-06), remove if possible
162  #for connection in [child for child in self.children() if isinstance(child, PortConnection)]:
163  # connection.updateConnection()
164 
165  ConnectableWidgetOwner.widgetDragged(self, widget)
166 
167  def mouseDoubleClickEvent(self, event):
168  """ Call toggleCollapse().
169  """
170  if event.pos().y() <= self.getDistance("titleFieldBottom"):
171  self.toggleCollapse()
172  if isinstance(self.parent(), ConnectableWidgetOwner):
173  self.parent().widgetDoubleClicked(self)
174 
175  def mousePressEvent(self, event):
176  """ Makes sure event is forwarded to both base classes.
177  """
178  ConnectableWidgetOwner.mousePressEvent(self, event)
179  VispaWidget.mousePressEvent(self, event)
180 
181  def mouseMoveEvent(self, event):
182  if bool(event.buttons() & Qt.LeftButton):
183  VispaWidget.mouseMoveEvent(self, event)
184  elif self.menu():
185  self.positionizeMenuWidget()
186 
187  if event.pos().y() <= self.getDistance("titleFieldBottom"):
188  self.showMenu()
189  elif self.menu():
190  self.menu().hide()
191 
192  def collapsed(self):
193  """ Returns True if widget is collapsed. In this case the children are not visible.
194 
195  Otherwise False is returned.
196  """
197  return not self._childrenVisible
198 
199  def toggleCollapse(self):
200  """ Toggles visibility of children between True and False.
201  """
202  if self.menu():
203  self.menu().hide()
204 
205 
206  if self._childrenVisible:
207  self._hiddenChildren = []
208  self._childrenVisible = False
209  else:
210  self._childrenVisible = True
211 
212  for child in self.children():
213  if isinstance(child,QWidget): # needed for PyQt4.5
214  if not self._childrenVisible and not child.isVisible():
215  # remember already hidden children while hiding
216  self._hiddenChildren.append(child)
217  elif not child in self._hiddenChildren:
218  # prevent to make previously hidden children visible
219  child.setVisible(self._childrenVisible)
220 
221  if self._childrenVisible:
224  self.setColors(self.PEN_COLOR, self.FILL_COLOR1, self.FILL_COLOR2)
225  else:
226  self.enableBackgroundGradient(False)
227  self.enableColorHeaderBackground(False)
228  self.setColors(self.PEN_COLOR, self.PEN_COLOR, None)
229 
230  self.autosize()
231  self.widgetDragged(self)
232 
233  def showMenu(self):
234  if self._collapseMenuButton:
235  if self._childrenVisible and self._collapsable:
236  self.menu().setEntryText(self._collapseMenuButton, "Collapse")
237  #self._collapseMenuButton.setText("Collapse")
238  else:
239  self.menu().setEntryText(self._collapseMenuButton, "Expand")
240  #self._collapseMenuButton.setText("Expand")
241  ConnectableWidget.showMenu(self)
242 
243  def setShowCollapseMenu(self, show=True):
244  if show and not self._collapseMenuButton:
245  self._collapseMenuButton = self.addMenuEntry("", self.toggleCollapse)
246  elif not show and self._collapseMenuButton:
248  self._collapseMenuButton = None
249 
250  def setNotCollapsable(self):
251  self._collapsable=False
252 
const T & max(const T &a, const T &b)
Definition: DDAxes.h:10