GUIElements.py 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283
  1. from PyQt4 import QtGui, QtCore
  2. from copy import copy
  3. #import FlatCAMApp
  4. import re
  5. import logging
  6. log = logging.getLogger('base')
  7. class RadioSet(QtGui.QWidget):
  8. def __init__(self, choices, orientation='horizontal', parent=None):
  9. """
  10. The choices are specified as a list of dictionaries containing:
  11. * 'label': Shown in the UI
  12. * 'value': The value returned is selected
  13. :param choices: List of choices. See description.
  14. :type choices: list
  15. """
  16. super(RadioSet, self).__init__(parent)
  17. self.choices = copy(choices)
  18. if orientation == 'horizontal':
  19. layout = QtGui.QHBoxLayout()
  20. else:
  21. layout = QtGui.QVBoxLayout()
  22. group = QtGui.QButtonGroup(self)
  23. for choice in self.choices:
  24. choice['radio'] = QtGui.QRadioButton(choice['label'])
  25. group.addButton(choice['radio'])
  26. layout.addWidget(choice['radio'], stretch=0)
  27. choice['radio'].toggled.connect(self.on_toggle)
  28. layout.addStretch()
  29. self.setLayout(layout)
  30. self.group_toggle_fn = lambda: None
  31. def on_toggle(self):
  32. log.debug("Radio toggled")
  33. radio = self.sender()
  34. if radio.isChecked():
  35. self.group_toggle_fn()
  36. return
  37. def get_value(self):
  38. for choice in self.choices:
  39. if choice['radio'].isChecked():
  40. return choice['value']
  41. log.error("No button was toggled in RadioSet.")
  42. return None
  43. def set_value(self, val):
  44. for choice in self.choices:
  45. if choice['value'] == val:
  46. choice['radio'].setChecked(True)
  47. return
  48. log.error("Value given is not part of this RadioSet: %s" % str(val))
  49. class LengthEntry(QtGui.QLineEdit):
  50. def __init__(self, output_units='IN', parent=None):
  51. super(LengthEntry, self).__init__(parent)
  52. self.output_units = output_units
  53. self.format_re = re.compile(r"^([^\s]+)(?:\s([a-zA-Z]+))?$")
  54. # Unit conversion table OUTPUT-INPUT
  55. self.scales = {
  56. 'IN': {'IN': 1.0,
  57. 'MM': 1/25.4},
  58. 'MM': {'IN': 25.4,
  59. 'MM': 1.0}
  60. }
  61. def returnPressed(self, *args, **kwargs):
  62. val = self.get_value()
  63. if val is not None:
  64. self.set_text(QtCore.QString(str(val)))
  65. else:
  66. log.warning("Could not interpret entry: %s" % self.get_text())
  67. def get_value(self):
  68. raw = str(self.text()).strip(' ')
  69. # match = self.format_re.search(raw)
  70. try:
  71. units = raw[-2:]
  72. units = self.scales[self.output_units][units.upper()]
  73. value = raw[:-2]
  74. return float(eval(value))*units
  75. except IndexError:
  76. value = raw
  77. return float(eval(value))
  78. except KeyError:
  79. value = raw
  80. return float(eval(value))
  81. except:
  82. log.warning("Could not parse value in entry: %s" % str(raw))
  83. return None
  84. def set_value(self, val):
  85. self.setText(QtCore.QString(str(val)))
  86. class FloatEntry(QtGui.QLineEdit):
  87. def __init__(self, parent=None):
  88. super(FloatEntry, self).__init__(parent)
  89. def returnPressed(self, *args, **kwargs):
  90. val = self.get_value()
  91. if val is not None:
  92. self.set_text(QtCore.QString(str(val)))
  93. else:
  94. log.warning("Could not interpret entry: %s" % self.text())
  95. def get_value(self):
  96. raw = str(self.text()).strip(' ')
  97. try:
  98. evaled = eval(raw)
  99. except:
  100. log.error("Could not evaluate: %s" % str(raw))
  101. return None
  102. return float(evaled)
  103. def set_value(self, val):
  104. self.setText("%.6f" % val)
  105. class IntEntry(QtGui.QLineEdit):
  106. def __init__(self, parent=None, allow_empty=False, empty_val=None):
  107. super(IntEntry, self).__init__(parent)
  108. self.allow_empty = allow_empty
  109. self.empty_val = empty_val
  110. def get_value(self):
  111. if self.allow_empty:
  112. if str(self.text()) == "":
  113. return self.empty_val
  114. return int(self.text())
  115. def set_value(self, val):
  116. if val == self.empty_val and self.allow_empty:
  117. self.setText(QtCore.QString(""))
  118. return
  119. self.setText(QtCore.QString(str(val)))
  120. class FCEntry(QtGui.QLineEdit):
  121. def __init__(self, parent=None):
  122. super(FCEntry, self).__init__(parent)
  123. def get_value(self):
  124. return str(self.text())
  125. def set_value(self, val):
  126. self.setText(QtCore.QString(str(val)))
  127. class EvalEntry(QtGui.QLineEdit):
  128. def __init__(self, parent=None):
  129. super(EvalEntry, self).__init__(parent)
  130. def returnPressed(self, *args, **kwargs):
  131. val = self.get_value()
  132. if val is not None:
  133. self.setText(QtCore.QString(str(val)))
  134. else:
  135. log.warning("Could not interpret entry: %s" % self.get_text())
  136. def get_value(self):
  137. raw = str(self.text()).strip(' ')
  138. try:
  139. return eval(raw)
  140. except:
  141. log.error("Could not evaluate: %s" % str(raw))
  142. return None
  143. def set_value(self, val):
  144. self.setText(QtCore.QString(str(val)))
  145. class FCCheckBox(QtGui.QCheckBox):
  146. def __init__(self, label='', parent=None):
  147. super(FCCheckBox, self).__init__(QtCore.QString(label), parent)
  148. def get_value(self):
  149. return self.isChecked()
  150. def set_value(self, val):
  151. self.setChecked(val)
  152. class FCTextArea(QtGui.QPlainTextEdit):
  153. def __init__(self, parent=None):
  154. super(FCTextArea, self).__init__(parent)
  155. def set_value(self, val):
  156. self.setPlainText(val)
  157. def get_value(self):
  158. return str(self.toPlainText())
  159. class VerticalScrollArea(QtGui.QScrollArea):
  160. """
  161. This widget extends QtGui.QScrollArea to make a vertical-only
  162. scroll area that also expands horizontally to accomodate
  163. its contents.
  164. """
  165. def __init__(self, parent=None):
  166. QtGui.QScrollArea.__init__(self, parent=parent)
  167. self.setWidgetResizable(True)
  168. self.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
  169. self.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAsNeeded)
  170. def eventFilter(self, source, event):
  171. """
  172. The event filter gets automatically installed when setWidget()
  173. is called.
  174. :param source:
  175. :param event:
  176. :return:
  177. """
  178. if event.type() == QtCore.QEvent.Resize and source == self.widget():
  179. # log.debug("VerticalScrollArea: Widget resized:")
  180. # log.debug(" minimumSizeHint().width() = %d" % self.widget().minimumSizeHint().width())
  181. # log.debug(" verticalScrollBar().width() = %d" % self.verticalScrollBar().width())
  182. self.setMinimumWidth(self.widget().sizeHint().width() +
  183. self.verticalScrollBar().sizeHint().width())
  184. # if self.verticalScrollBar().isVisible():
  185. # log.debug(" Scroll bar visible")
  186. # self.setMinimumWidth(self.widget().minimumSizeHint().width() +
  187. # self.verticalScrollBar().width())
  188. # else:
  189. # log.debug(" Scroll bar hidden")
  190. # self.setMinimumWidth(self.widget().minimumSizeHint().width())
  191. return QtGui.QWidget.eventFilter(self, source, event)
  192. class OptionalInputSection:
  193. def __init__(self, cb, optinputs):
  194. """
  195. Associates the a checkbox with a set of inputs.
  196. :param cb: Checkbox that enables the optional inputs.
  197. :param optinputs: List of widgets that are optional.
  198. :return:
  199. """
  200. assert isinstance(cb, FCCheckBox), \
  201. "Expected an FCCheckBox, got %s" % type(cb)
  202. self.cb = cb
  203. self.optinputs = optinputs
  204. self.on_cb_change()
  205. self.cb.stateChanged.connect(self.on_cb_change)
  206. def on_cb_change(self):
  207. if self.cb.checkState():
  208. for widget in self.optinputs:
  209. widget.setEnabled(True)
  210. else:
  211. for widget in self.optinputs:
  212. widget.setEnabled(False)