GUIElements.py 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710
  1. from PyQt5 import QtGui, QtCore, QtWidgets, QtWidgets
  2. from copy import copy
  3. import re
  4. import logging
  5. log = logging.getLogger('base')
  6. EDIT_SIZE_HINT = 70
  7. class RadioSet(QtWidgets.QWidget):
  8. activated_custom = QtCore.pyqtSignal()
  9. def __init__(self, choices, orientation='horizontal', parent=None, stretch=None):
  10. """
  11. The choices are specified as a list of dictionaries containing:
  12. * 'label': Shown in the UI
  13. * 'value': The value returned is selected
  14. :param choices: List of choices. See description.
  15. :param orientation: 'horizontal' (default) of 'vertical'.
  16. :param parent: Qt parent widget.
  17. :type choices: list
  18. """
  19. super(RadioSet, self).__init__(parent)
  20. self.choices = copy(choices)
  21. if orientation == 'horizontal':
  22. layout = QtWidgets.QHBoxLayout()
  23. else:
  24. layout = QtWidgets.QVBoxLayout()
  25. group = QtWidgets.QButtonGroup(self)
  26. for choice in self.choices:
  27. choice['radio'] = QtWidgets.QRadioButton(choice['label'])
  28. group.addButton(choice['radio'])
  29. layout.addWidget(choice['radio'], stretch=0)
  30. choice['radio'].toggled.connect(self.on_toggle)
  31. layout.setContentsMargins(0, 0, 0, 0)
  32. if stretch is False:
  33. pass
  34. else:
  35. layout.addStretch()
  36. self.setLayout(layout)
  37. self.group_toggle_fn = lambda: None
  38. def on_toggle(self):
  39. # log.debug("Radio toggled")
  40. radio = self.sender()
  41. if radio.isChecked():
  42. self.group_toggle_fn()
  43. self.activated_custom.emit()
  44. return
  45. def get_value(self):
  46. for choice in self.choices:
  47. if choice['radio'].isChecked():
  48. return choice['value']
  49. log.error("No button was toggled in RadioSet.")
  50. return None
  51. def set_value(self, val):
  52. for choice in self.choices:
  53. if choice['value'] == val:
  54. choice['radio'].setChecked(True)
  55. return
  56. log.error("Value given is not part of this RadioSet: %s" % str(val))
  57. # class RadioGroupChoice(QtWidgets.QWidget):
  58. # def __init__(self, label_1, label_2, to_check, hide_list, show_list, parent=None):
  59. # """
  60. # The choices are specified as a list of dictionaries containing:
  61. #
  62. # * 'label': Shown in the UI
  63. # * 'value': The value returned is selected
  64. #
  65. # :param choices: List of choices. See description.
  66. # :param orientation: 'horizontal' (default) of 'vertical'.
  67. # :param parent: Qt parent widget.
  68. # :type choices: list
  69. # """
  70. # super().__init__(parent)
  71. #
  72. # group = QtGui.QButtonGroup(self)
  73. #
  74. # self.lbl1 = label_1
  75. # self.lbl2 = label_2
  76. # self.hide_list = hide_list
  77. # self.show_list = show_list
  78. #
  79. # self.btn1 = QtGui.QRadioButton(str(label_1))
  80. # self.btn2 = QtGui.QRadioButton(str(label_2))
  81. # group.addButton(self.btn1)
  82. # group.addButton(self.btn2)
  83. #
  84. # if to_check == 1:
  85. # self.btn1.setChecked(True)
  86. # else:
  87. # self.btn2.setChecked(True)
  88. #
  89. # self.btn1.toggled.connect(lambda: self.btn_state(self.btn1))
  90. # self.btn2.toggled.connect(lambda: self.btn_state(self.btn2))
  91. #
  92. # def btn_state(self, btn):
  93. # if btn.text() == self.lbl1:
  94. # if btn.isChecked() is True:
  95. # self.show_widgets(self.show_list)
  96. # self.hide_widgets(self.hide_list)
  97. # else:
  98. # self.show_widgets(self.hide_list)
  99. # self.hide_widgets(self.show_list)
  100. #
  101. # def hide_widgets(self, lst):
  102. # for wgt in lst:
  103. # wgt.hide()
  104. #
  105. # def show_widgets(self, lst):
  106. # for wgt in lst:
  107. # wgt.show()
  108. class LengthEntry(QtWidgets.QLineEdit):
  109. def __init__(self, output_units='IN', parent=None):
  110. super(LengthEntry, self).__init__(parent)
  111. self.output_units = output_units
  112. self.format_re = re.compile(r"^([^\s]+)(?:\s([a-zA-Z]+))?$")
  113. # Unit conversion table OUTPUT-INPUT
  114. self.scales = {
  115. 'IN': {'IN': 1.0,
  116. 'MM': 1/25.4},
  117. 'MM': {'IN': 25.4,
  118. 'MM': 1.0}
  119. }
  120. self.readyToEdit = True
  121. def mousePressEvent(self, e, Parent=None):
  122. super(LengthEntry, self).mousePressEvent(e) # required to deselect on 2e click
  123. if self.readyToEdit:
  124. self.selectAll()
  125. self.readyToEdit = False
  126. def focusOutEvent(self, e):
  127. super(LengthEntry, self).focusOutEvent(e) # required to remove cursor on focusOut
  128. self.deselect()
  129. self.readyToEdit = True
  130. def returnPressed(self, *args, **kwargs):
  131. val = self.get_value()
  132. if val is not None:
  133. self.set_text(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. # match = self.format_re.search(raw)
  139. try:
  140. units = raw[-2:]
  141. units = self.scales[self.output_units][units.upper()]
  142. value = raw[:-2]
  143. return float(eval(value))*units
  144. except IndexError:
  145. value = raw
  146. return float(eval(value))
  147. except KeyError:
  148. value = raw
  149. return float(eval(value))
  150. except:
  151. log.warning("Could not parse value in entry: %s" % str(raw))
  152. return None
  153. def set_value(self, val):
  154. self.setText(str('%.4f' % val))
  155. def sizeHint(self):
  156. default_hint_size = super(LengthEntry, self).sizeHint()
  157. return QtCore.QSize(EDIT_SIZE_HINT, default_hint_size.height())
  158. class FloatEntry(QtWidgets.QLineEdit):
  159. def __init__(self, parent=None):
  160. super(FloatEntry, self).__init__(parent)
  161. self.readyToEdit = True
  162. def mousePressEvent(self, e, Parent=None):
  163. super(FloatEntry, self).mousePressEvent(e) # required to deselect on 2e click
  164. if self.readyToEdit:
  165. self.selectAll()
  166. self.readyToEdit = False
  167. def focusOutEvent(self, e):
  168. super(FloatEntry, self).focusOutEvent(e) # required to remove cursor on focusOut
  169. self.deselect()
  170. self.readyToEdit = True
  171. def returnPressed(self, *args, **kwargs):
  172. val = self.get_value()
  173. if val is not None:
  174. self.set_text(str(val))
  175. else:
  176. log.warning("Could not interpret entry: %s" % self.text())
  177. def get_value(self):
  178. raw = str(self.text()).strip(' ')
  179. evaled = 0.0
  180. try:
  181. evaled = eval(raw)
  182. except:
  183. if evaled is not None:
  184. log.error("Could not evaluate: %s" % str(raw))
  185. return None
  186. return float(evaled)
  187. def set_value(self, val):
  188. if val is not None:
  189. self.setText("%.6f" % val)
  190. else:
  191. self.setText("")
  192. def sizeHint(self):
  193. default_hint_size = super(FloatEntry, self).sizeHint()
  194. return QtCore.QSize(EDIT_SIZE_HINT, default_hint_size.height())
  195. class FloatEntry2(QtWidgets.QLineEdit):
  196. def __init__(self, parent=None):
  197. super(FloatEntry2, self).__init__(parent)
  198. self.readyToEdit = True
  199. def mousePressEvent(self, e, Parent=None):
  200. super(FloatEntry2, self).mousePressEvent(e) # required to deselect on 2e click
  201. if self.readyToEdit:
  202. self.selectAll()
  203. self.readyToEdit = False
  204. def focusOutEvent(self, e):
  205. super(FloatEntry2, self).focusOutEvent(e) # required to remove cursor on focusOut
  206. self.deselect()
  207. self.readyToEdit = True
  208. def get_value(self):
  209. raw = str(self.text()).strip(' ')
  210. evaled = 0.0
  211. try:
  212. evaled = eval(raw)
  213. except:
  214. if evaled is not None:
  215. log.error("Could not evaluate: %s" % str(raw))
  216. return None
  217. return float(evaled)
  218. def set_value(self, val):
  219. self.setText("%.6f" % val)
  220. def sizeHint(self):
  221. default_hint_size = super(FloatEntry2, self).sizeHint()
  222. return QtCore.QSize(EDIT_SIZE_HINT, default_hint_size.height())
  223. class IntEntry(QtWidgets.QLineEdit):
  224. def __init__(self, parent=None, allow_empty=False, empty_val=None):
  225. super(IntEntry, self).__init__(parent)
  226. self.allow_empty = allow_empty
  227. self.empty_val = empty_val
  228. self.readyToEdit = True
  229. def mousePressEvent(self, e, Parent=None):
  230. super(IntEntry, self).mousePressEvent(e) # required to deselect on 2e click
  231. if self.readyToEdit:
  232. self.selectAll()
  233. self.readyToEdit = False
  234. def focusOutEvent(self, e):
  235. super(IntEntry, self).focusOutEvent(e) # required to remove cursor on focusOut
  236. self.deselect()
  237. self.readyToEdit = True
  238. def get_value(self):
  239. if self.allow_empty:
  240. if str(self.text()) == "":
  241. return self.empty_val
  242. # make the text() first a float and then int because if text is a float type,
  243. # the int() can't convert directly a "text float" into a int type.
  244. ret_val = float(self.text())
  245. ret_val = int(ret_val)
  246. return ret_val
  247. def set_value(self, val):
  248. if val == self.empty_val and self.allow_empty:
  249. self.setText("")
  250. return
  251. self.setText(str(val))
  252. def sizeHint(self):
  253. default_hint_size = super(IntEntry, self).sizeHint()
  254. return QtCore.QSize(EDIT_SIZE_HINT, default_hint_size.height())
  255. class FCEntry(QtWidgets.QLineEdit):
  256. def __init__(self, parent=None):
  257. super(FCEntry, self).__init__(parent)
  258. self.readyToEdit = True
  259. def mousePressEvent(self, e, Parent=None):
  260. super(FCEntry, self).mousePressEvent(e) # required to deselect on 2e click
  261. if self.readyToEdit:
  262. self.selectAll()
  263. self.readyToEdit = False
  264. def focusOutEvent(self, e):
  265. super(FCEntry, self).focusOutEvent(e) # required to remove cursor on focusOut
  266. self.deselect()
  267. self.readyToEdit = True
  268. def get_value(self):
  269. return str(self.text())
  270. def set_value(self, val):
  271. self.setText(str(val))
  272. def sizeHint(self):
  273. default_hint_size = super(FCEntry, self).sizeHint()
  274. return QtCore.QSize(EDIT_SIZE_HINT, default_hint_size.height())
  275. class FCEntry2(FCEntry):
  276. def __init__(self, parent=None):
  277. super(FCEntry2, self).__init__(parent)
  278. self.readyToEdit = True
  279. def set_value(self, val):
  280. self.setText('%.5f' % float(val))
  281. class EvalEntry(QtWidgets.QLineEdit):
  282. def __init__(self, parent=None):
  283. super(EvalEntry, self).__init__(parent)
  284. self.readyToEdit = True
  285. def mousePressEvent(self, e, Parent=None):
  286. super(EvalEntry, self).mousePressEvent(e) # required to deselect on 2e click
  287. if self.readyToEdit:
  288. self.selectAll()
  289. self.readyToEdit = False
  290. def focusOutEvent(self, e):
  291. super(EvalEntry, self).focusOutEvent(e) # required to remove cursor on focusOut
  292. self.deselect()
  293. self.readyToEdit = True
  294. def returnPressed(self, *args, **kwargs):
  295. val = self.get_value()
  296. if val is not None:
  297. self.setText(str(val))
  298. else:
  299. log.warning("Could not interpret entry: %s" % self.get_text())
  300. def get_value(self):
  301. raw = str(self.text()).strip(' ')
  302. evaled = 0.0
  303. try:
  304. evaled = eval(raw)
  305. except:
  306. if evaled is not None:
  307. log.error("Could not evaluate: %s" % str(raw))
  308. return None
  309. return evaled
  310. def set_value(self, val):
  311. self.setText(str(val))
  312. def sizeHint(self):
  313. default_hint_size = super(EvalEntry, self).sizeHint()
  314. return QtCore.QSize(EDIT_SIZE_HINT, default_hint_size.height())
  315. class EvalEntry2(QtWidgets.QLineEdit):
  316. def __init__(self, parent=None):
  317. super(EvalEntry2, self).__init__(parent)
  318. self.readyToEdit = True
  319. def mousePressEvent(self, e, Parent=None):
  320. super(EvalEntry2, self).mousePressEvent(e) # required to deselect on 2e click
  321. if self.readyToEdit:
  322. self.selectAll()
  323. self.readyToEdit = False
  324. def focusOutEvent(self, e):
  325. super(EvalEntry2, self).focusOutEvent(e) # required to remove cursor on focusOut
  326. self.deselect()
  327. self.readyToEdit = True
  328. def get_value(self):
  329. raw = str(self.text()).strip(' ')
  330. evaled = 0.0
  331. try:
  332. evaled = eval(raw)
  333. except:
  334. if evaled is not None:
  335. log.error("Could not evaluate: %s" % str(raw))
  336. return None
  337. return evaled
  338. def set_value(self, val):
  339. self.setText(str(val))
  340. def sizeHint(self):
  341. default_hint_size = super(EvalEntry2, self).sizeHint()
  342. return QtCore.QSize(EDIT_SIZE_HINT, default_hint_size.height())
  343. class FCCheckBox(QtWidgets.QCheckBox):
  344. def __init__(self, label='', parent=None):
  345. super(FCCheckBox, self).__init__(str(label), parent)
  346. def get_value(self):
  347. return self.isChecked()
  348. def set_value(self, val):
  349. self.setChecked(val)
  350. def toggle(self):
  351. self.set_value(not self.get_value())
  352. class FCTextArea(QtWidgets.QPlainTextEdit):
  353. def __init__(self, parent=None):
  354. super(FCTextArea, self).__init__(parent)
  355. def set_value(self, val):
  356. self.setPlainText(val)
  357. def get_value(self):
  358. return str(self.toPlainText())
  359. def sizeHint(self):
  360. default_hint_size = super(FCTextArea, self).sizeHint()
  361. return QtCore.QSize(EDIT_SIZE_HINT, default_hint_size.height())
  362. class FCTextAreaRich(QtWidgets.QTextEdit):
  363. def __init__(self, parent=None):
  364. super(FCTextAreaRich, self).__init__(parent)
  365. def set_value(self, val):
  366. self.setText(val)
  367. def get_value(self):
  368. return str(self.toPlainText())
  369. def sizeHint(self):
  370. default_hint_size = super(FCTextAreaRich, self).sizeHint()
  371. return QtCore.QSize(EDIT_SIZE_HINT, default_hint_size.height())
  372. class FCComboBox(QtWidgets.QComboBox):
  373. def __init__(self, parent=None):
  374. super(FCComboBox, self).__init__(parent)
  375. self.setFocusPolicy(QtCore.Qt.StrongFocus)
  376. def wheelEvent(self, *args, **kwargs):
  377. pass
  378. def get_value(self):
  379. return str(self.currentText())
  380. def set_value(self, val):
  381. self.setCurrentIndex(self.findText(str(val)))
  382. class FCInputDialog(QtWidgets.QInputDialog):
  383. def __init__(self, parent=None, ok=False, val=None, title=None, text=None, min=None, max=None, decimals=None):
  384. super(FCInputDialog, self).__init__(parent)
  385. self.allow_empty = ok
  386. self.empty_val = val
  387. if title is None:
  388. self.title = 'title'
  389. else:
  390. self.title = title
  391. if text is None:
  392. self.text = 'text'
  393. else:
  394. self.text = text
  395. if min is None:
  396. self.min = 0
  397. else:
  398. self.min = min
  399. if max is None:
  400. self.max = 0
  401. else:
  402. self.max = max
  403. if decimals is None:
  404. self.decimals = 6
  405. else:
  406. self.decimals = decimals
  407. def get_value(self):
  408. self.val,self.ok = self.getDouble(self, self.title, self.text, min=self.min,
  409. max=self.max, decimals=self.decimals)
  410. return [self.val, self.ok]
  411. # "Transform", "Enter the Angle value:"
  412. def set_value(self, val):
  413. pass
  414. class FCButton(QtWidgets.QPushButton):
  415. def __init__(self, parent=None):
  416. super(FCButton, self).__init__(parent)
  417. def get_value(self):
  418. return self.isChecked()
  419. def set_value(self, val):
  420. self.setText(str(val))
  421. class FCTab(QtWidgets.QTabWidget):
  422. def __init__(self, parent=None):
  423. super(FCTab, self).__init__(parent)
  424. self.setTabsClosable(True)
  425. self.tabCloseRequested.connect(self.closeTab)
  426. def deleteTab(self, currentIndex):
  427. widget = self.widget(currentIndex)
  428. if widget is not None:
  429. widget.deleteLater()
  430. self.removeTab(currentIndex)
  431. def closeTab(self, currentIndex):
  432. self.removeTab(currentIndex)
  433. def protectTab(self, currentIndex):
  434. self.tabBar().setTabButton(currentIndex, QtWidgets.QTabBar.RightSide, None)
  435. class VerticalScrollArea(QtWidgets.QScrollArea):
  436. """
  437. This widget extends QtGui.QScrollArea to make a vertical-only
  438. scroll area that also expands horizontally to accomodate
  439. its contents.
  440. """
  441. def __init__(self, parent=None):
  442. QtWidgets.QScrollArea.__init__(self, parent=parent)
  443. self.setWidgetResizable(True)
  444. self.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
  445. self.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAsNeeded)
  446. def eventFilter(self, source, event):
  447. """
  448. The event filter gets automatically installed when setWidget()
  449. is called.
  450. :param source:
  451. :param event:
  452. :return:
  453. """
  454. if event.type() == QtCore.QEvent.Resize and source == self.widget():
  455. # log.debug("VerticalScrollArea: Widget resized:")
  456. # log.debug(" minimumSizeHint().width() = %d" % self.widget().minimumSizeHint().width())
  457. # log.debug(" verticalScrollBar().width() = %d" % self.verticalScrollBar().width())
  458. self.setMinimumWidth(self.widget().sizeHint().width() +
  459. self.verticalScrollBar().sizeHint().width())
  460. # if self.verticalScrollBar().isVisible():
  461. # log.debug(" Scroll bar visible")
  462. # self.setMinimumWidth(self.widget().minimumSizeHint().width() +
  463. # self.verticalScrollBar().width())
  464. # else:
  465. # log.debug(" Scroll bar hidden")
  466. # self.setMinimumWidth(self.widget().minimumSizeHint().width())
  467. return QtWidgets.QWidget.eventFilter(self, source, event)
  468. class OptionalInputSection:
  469. def __init__(self, cb, optinputs, logic=True):
  470. """
  471. Associates the a checkbox with a set of inputs.
  472. :param cb: Checkbox that enables the optional inputs.
  473. :param optinputs: List of widgets that are optional.
  474. :param logic: When True the logic is normal, when False the logic is in reverse
  475. It means that for logic=True, when the checkbox is checked the widgets are Enabled, and
  476. for logic=False, when the checkbox is checked the widgets are Disabled
  477. :return:
  478. """
  479. assert isinstance(cb, FCCheckBox), \
  480. "Expected an FCCheckBox, got %s" % type(cb)
  481. self.cb = cb
  482. self.optinputs = optinputs
  483. self.logic = logic
  484. self.on_cb_change()
  485. self.cb.stateChanged.connect(self.on_cb_change)
  486. def on_cb_change(self):
  487. if self.cb.checkState():
  488. for widget in self.optinputs:
  489. if self.logic is True:
  490. widget.setEnabled(True)
  491. else:
  492. widget.setEnabled(False)
  493. else:
  494. for widget in self.optinputs:
  495. if self.logic is True:
  496. widget.setEnabled(False)
  497. else:
  498. widget.setEnabled(True)
  499. class FCTable(QtWidgets.QTableWidget):
  500. def __init__(self, parent=None):
  501. super(FCTable, self).__init__(parent)
  502. def sizeHint(self):
  503. default_hint_size = super(FCTable, self).sizeHint()
  504. return QtCore.QSize(EDIT_SIZE_HINT, default_hint_size.height())
  505. def getHeight(self):
  506. height = self.horizontalHeader().height()
  507. for i in range(self.rowCount()):
  508. height += self.rowHeight(i)
  509. return height
  510. def getWidth(self):
  511. width = self.verticalHeader().width()
  512. for i in range(self.columnCount()):
  513. width += self.columnWidth(i)
  514. return width
  515. # color is in format QtGui.Qcolor(r, g, b, alfa) with or without alfa
  516. def setColortoRow(self, rowIndex, color):
  517. for j in range(self.columnCount()):
  518. self.item(rowIndex, j).setBackground(color)
  519. # if user is clicking an blank area inside the QTableWidget it will deselect currently selected rows
  520. def mousePressEvent(self, event):
  521. if self.itemAt(event.pos()) is None:
  522. self.clearSelection()
  523. else:
  524. QtWidgets.QTableWidget.mousePressEvent(self, event)
  525. def setupContextMenu(self):
  526. self.setContextMenuPolicy(QtCore.Qt.ActionsContextMenu)
  527. def addContextMenu(self, entry, call_function, icon=None):
  528. action_name = str(entry)
  529. action = QtWidgets.QAction(self)
  530. action.setText(action_name)
  531. if icon:
  532. assert isinstance(icon, QtGui.QIcon), \
  533. "Expected the argument to be QtGui.QIcon. Instead it is %s" % type(icon)
  534. action.setIcon(icon)
  535. self.addAction(action)
  536. action.triggered.connect(call_function)
  537. class FCSpinner(QtWidgets.QSpinBox):
  538. def __init__(self, parent=None):
  539. super(FCSpinner, self).__init__(parent)
  540. def get_value(self):
  541. return str(self.value())
  542. def set_value(self, val):
  543. try:
  544. k = int(val)
  545. except Exception as e:
  546. raise e
  547. self.setValue(k)
  548. # def sizeHint(self):
  549. # default_hint_size = super(FCSpinner, self).sizeHint()
  550. # return QtCore.QSize(EDIT_SIZE_HINT, default_hint_size.height())
  551. class Dialog_box(QtWidgets.QWidget):
  552. def __init__(self, title=None, label=None):
  553. """
  554. :param title: string with the window title
  555. :param label: string with the message inside the dialog box
  556. """
  557. super(Dialog_box, self).__init__()
  558. self.location = (0, 0)
  559. self.ok = False
  560. dialog_box = QtWidgets.QInputDialog()
  561. dialog_box.setFixedWidth(270)
  562. self.location, self.ok = dialog_box.getText(self, title, label)