more_bugs (#51)

closes #46, #47, #7

Co-authored-by: Dominik Demuth <dominik.demuth@physik.tu-darmstadt.de>
Reviewed-on: #51
This commit is contained in:
Dominik Demuth 2023-04-16 15:40:58 +00:00
parent bb3d5ac58b
commit 59625c1581
6 changed files with 142 additions and 57 deletions

View File

@ -70,12 +70,12 @@ class Ui_BaseWindow(object):
self.integralwidget = IntegralWidget() self.integralwidget = IntegralWidget()
self.integralwidget.setObjectName("integralwidget") self.integralwidget.setObjectName("integralwidget")
self.tabWidget.addTab(self.integralwidget, "") self.tabWidget.addTab(self.integralwidget, "")
self.area = QtWidgets.QMdiArea(self.splitter) self.area = MdiAreaTile(self.splitter)
self.area.setObjectName("area") self.area.setObjectName("area")
self.horizontalLayout.addWidget(self.splitter) self.horizontalLayout.addWidget(self.splitter)
BaseWindow.setCentralWidget(self.centralwidget) BaseWindow.setCentralWidget(self.centralwidget)
self.menubar = QtWidgets.QMenuBar(BaseWindow) self.menubar = QtWidgets.QMenuBar(BaseWindow)
self.menubar.setGeometry(QtCore.QRect(0, 0, 1386, 20)) self.menubar.setGeometry(QtCore.QRect(0, 0, 1386, 22))
self.menubar.setObjectName("menubar") self.menubar.setObjectName("menubar")
self.menuFile = QtWidgets.QMenu(self.menubar) self.menuFile = QtWidgets.QMenu(self.menubar)
self.menuFile.setObjectName("menuFile") self.menuFile.setObjectName("menuFile")
@ -261,6 +261,10 @@ class Ui_BaseWindow(object):
self.actionMaximize.setObjectName("actionMaximize") self.actionMaximize.setObjectName("actionMaximize")
self.actionTile = QtWidgets.QAction(BaseWindow) self.actionTile = QtWidgets.QAction(BaseWindow)
self.actionTile.setObjectName("actionTile") self.actionTile.setObjectName("actionTile")
self.actionTileVertical = QtWidgets.QAction(BaseWindow)
self.actionTileVertical.setObjectName("actionTileVertical")
self.actionTileHorizontal = QtWidgets.QAction(BaseWindow)
self.actionTileHorizontal.setObjectName("actionTileHorizontal")
self.actionMinimize = QtWidgets.QAction(BaseWindow) self.actionMinimize = QtWidgets.QAction(BaseWindow)
self.actionMinimize.setCheckable(True) self.actionMinimize.setCheckable(True)
self.actionMinimize.setVisible(False) self.actionMinimize.setVisible(False)
@ -428,6 +432,8 @@ class Ui_BaseWindow(object):
self.menuOptions.addAction(self.actionConfiguration) self.menuOptions.addAction(self.actionConfiguration)
self.menuOptions.addAction(self.actionCreate_starter) self.menuOptions.addAction(self.actionCreate_starter)
self.menuView.addAction(self.actionTile) self.menuView.addAction(self.actionTile)
self.menuView.addAction(self.actionTileVertical)
self.menuView.addAction(self.actionTileHorizontal)
self.menuView.addAction(self.actionCascade_windows) self.menuView.addAction(self.actionCascade_windows)
self.menuWindow.addAction(self.actionNew_window) self.menuWindow.addAction(self.actionNew_window)
self.menuWindow.addAction(self.actionDelete_window) self.menuWindow.addAction(self.actionDelete_window)
@ -571,6 +577,8 @@ class Ui_BaseWindow(object):
self.actionGuide_lines.setText(_translate("BaseWindow", "Draw lines...")) self.actionGuide_lines.setText(_translate("BaseWindow", "Draw lines..."))
self.actionMaximize.setText(_translate("BaseWindow", "Maximize")) self.actionMaximize.setText(_translate("BaseWindow", "Maximize"))
self.actionTile.setText(_translate("BaseWindow", "Tile windows")) self.actionTile.setText(_translate("BaseWindow", "Tile windows"))
self.actionTileVertical.setText(_translate("BaseWindow", "Tile windows vertically"))
self.actionTileHorizontal.setText(_translate("BaseWindow", "Tile windows horizontally"))
self.actionMinimize.setText(_translate("BaseWindow", "Minimize")) self.actionMinimize.setText(_translate("BaseWindow", "Minimize"))
self.actionNew_window.setText(_translate("BaseWindow", "New graph")) self.actionNew_window.setText(_translate("BaseWindow", "New graph"))
self.actionDelete_window.setText(_translate("BaseWindow", "Delete graph")) self.actionDelete_window.setText(_translate("BaseWindow", "Delete graph"))
@ -626,4 +634,5 @@ from ..data.signaledit.editsignalwidget import EditSignalWidget
from ..data.valueeditwidget import ValueEditWidget from ..data.valueeditwidget import ValueEditWidget
from ..fit.fitwindow import QFitDialog from ..fit.fitwindow import QFitDialog
from ..graphs.drawings import DrawingsWidget from ..graphs.drawings import DrawingsWidget
from ..lib.mdiarea import MdiAreaTile
from ..nmr.t1widget import QT1Widget from ..nmr.t1widget import QT1Widget

50
src/gui_qt/lib/mdiarea.py Normal file
View File

@ -0,0 +1,50 @@
from __future__ import annotations
from ..Qt import QtWidgets, QtCore
from nmreval.lib.logger import logger
from ..graphs.graphwindow import QGraphWindow
class MdiAreaTile(QtWidgets.QMdiArea):
def __init__(self, parent=None):
super().__init__(parent=parent)
def tileSubWindowsVertically(self):
window_list = self.subWindowList()
rect = QtCore.QRect(0, 0, self.width(), int(self.height() / len(window_list)))
pos = QtCore.QPoint(0, 0)
for win in window_list:
win.setGeometry(rect)
win.move(pos)
pos.setY(pos.y() + win.height())
def tileSubWindowsHorizontally(self):
window_list = self.subWindowList()
rect = QtCore.QRect(0, 0, int(self.width() / len(window_list)), self.height())
pos = QtCore.QPoint(0, 0)
for win in window_list:
print(win.minimumSize())
win.setGeometry(rect)
win.move(pos)
pos.setX(pos.x() + win.width())
def addSubWindow(self, widget: QtWidgets.QWidget, flags: QtCore.Qt.WindowFlags = QtCore.Qt.WindowFlags()) -> QtWidgets.QMdiSubWindow | None:
subwindow = super().addSubWindow(widget)
subwindow.setOption(QtWidgets.QMdiSubWindow.RubberBandMove, True)
subwindow.setOption(QtWidgets.QMdiSubWindow.RubberBandResize, True)
subwindow.setMinimumHeight(240)
subwindow.setMinimumWidth(360)
return subwindow
def setActiveSubWidget(self, key: str):
for win in self.subWindowList():
wdgt = win.widget()
if isinstance(wdgt, QGraphWindow) and wdgt.id == key:
self.setActiveSubWindow(win)
break

View File

@ -6,7 +6,7 @@ import numpy as np
from ..Qt import QtWidgets, QtCore, QtGui from ..Qt import QtWidgets, QtCore, QtGui
__all__ = ['Game'] __all__ = ['Game', 'QMines']
class Game(QtWidgets.QDialog): class Game(QtWidgets.QDialog):

View File

@ -2,7 +2,6 @@ from __future__ import annotations
import datetime import datetime
import os import os
import pathlib
import re import re
from pathlib import Path from pathlib import Path
@ -115,7 +114,10 @@ class NMRMainWindow(QtWidgets.QMainWindow, Ui_BaseWindow):
self.mousepos = QtWidgets.QLabel('') self.mousepos = QtWidgets.QLabel('')
self.status = QtWidgets.QLabel('') self.status = QtWidgets.QLabel('')
# noinspection PyUnresolvedReferences
self.statusBar.addWidget(self.status) self.statusBar.addWidget(self.status)
# noinspection PyUnresolvedReferences
self.statusBar.addWidget(self.mousepos) self.statusBar.addWidget(self.mousepos)
self.fitregion = RegionItem() self.fitregion = RegionItem()
@ -151,8 +153,6 @@ class NMRMainWindow(QtWidgets.QMainWindow, Ui_BaseWindow):
self.actionUndo.setIcon(icon) self.actionUndo.setIcon(icon)
self.menuData.insertAction(self.actionRedo, self.actionUndo) self.menuData.insertAction(self.actionRedo, self.actionUndo)
# self.actionSave.triggered.connect(lambda: self.management.save('/autohome/dominik/nmreval/testdata/test.nmr', ''))
# self.actionSave.triggered.connect(self.save)
self.action_save_fit_parameter.triggered.connect(self.save_fit_parameter) self.action_save_fit_parameter.triggered.connect(self.save_fit_parameter)
self.ac_group2.triggered.connect(self.change_fit_limits) self.ac_group2.triggered.connect(self.change_fit_limits)
@ -165,6 +165,12 @@ class NMRMainWindow(QtWidgets.QMainWindow, Ui_BaseWindow):
self.action_new_set.triggered.connect(self.management.create_empty) self.action_new_set.triggered.connect(self.management.create_empty)
self.actionDelete_window.triggered.connect(self.management.delete_sets)
self.actionCascade_windows.triggered.connect(self.area.cascadeSubWindows)
self.actionTile.triggered.connect(self.area.tileSubWindows)
self.actionTileHorizontal.triggered.connect(self.area.tileSubWindowsHorizontally)
self.actionTileVertical.triggered.connect(self.area.tileSubWindowsVertically)
self.datawidget.keyChanged.connect(self.management.change_keys) self.datawidget.keyChanged.connect(self.management.change_keys)
self.datawidget.tree.deleteItem.connect(self.management.delete_sets) self.datawidget.tree.deleteItem.connect(self.management.delete_sets)
self.datawidget.tree.moveItem.connect(self.management.move_sets) self.datawidget.tree.moveItem.connect(self.management.move_sets)
@ -178,7 +184,8 @@ class NMRMainWindow(QtWidgets.QMainWindow, Ui_BaseWindow):
self.datawidget.tree.saveFits.connect(self.save_fit_parameter) self.datawidget.tree.saveFits.connect(self.save_fit_parameter)
self.datawidget.tree.extendFits.connect(self.extend_fit) self.datawidget.tree.extendFits.connect(self.extend_fit)
self.management.newData.connect(self.show_new_data) self.management.newData[list, str].connect(self.show_new_data)
self.management.newData[list, str, bool].connect(self.show_new_data)
self.management.newGraph.connect(self.new_graph) self.management.newGraph.connect(self.new_graph)
self.management.dataChanged.connect(self.update_data) self.management.dataChanged.connect(self.update_data)
self.management.deleteData.connect(self.delete_data) self.management.deleteData.connect(self.delete_data)
@ -191,13 +198,14 @@ class NMRMainWindow(QtWidgets.QMainWindow, Ui_BaseWindow):
self.fit_dialog._management = self.management self.fit_dialog._management = self.management
self.fit_dialog.preview_emit.connect(self.show_fit_preview) self.fit_dialog.preview_emit.connect(self.show_fit_preview)
self.fit_dialog.fitStartSig.connect(self.start_fit) self.fit_dialog.fitStartSig.connect(self.start_fit)
self.fit_dialog.abortFit.connect(lambda : self.management.stopFit.emit()) self.fit_dialog.abortFit.connect(lambda: self.management.stopFit.emit())
self.movedialog.moveData.connect(self.move_sets) self.movedialog.moveData.connect(self.move_sets)
self.movedialog.copyData.connect(self.management.copy_sets) self.movedialog.copyData.connect(self.management.copy_sets)
self.ptsselectwidget.points_selected.connect(self.management.extract_points) self.ptsselectwidget.points_selected.connect(self.management.extract_points)
self.t1tauwidget.newData.connect(self.management.add_new_data)
self.t1tauwidget.newData.connect(self.management.add_new_data) self.t1tauwidget.newData.connect(self.management.add_new_data)
self.editsignalwidget.do_something.connect(self.management.apply) self.editsignalwidget.do_something.connect(self.management.apply)
@ -279,7 +287,7 @@ class NMRMainWindow(QtWidgets.QMainWindow, Ui_BaseWindow):
use_underscore = save_dialog.checkBox.isChecked() use_underscore = save_dialog.checkBox.isChecked()
self.management.save(savefile, selected_filter, strip_spaces=use_underscore) self.management.save(savefile, selected_filter, strip_spaces=use_underscore)
param_outfile = re.sub('[_\s-]?<label>[_\s-]?', '', savefile.stem) param_outfile = re.sub(r'[_\s-]?<label>[_\s-]?', '', savefile.stem)
bad_character = r'/*<>\|:"' bad_character = r'/*<>\|:"'
for c in bad_character: for c in bad_character:
@ -321,10 +329,15 @@ class NMRMainWindow(QtWidgets.QMainWindow, Ui_BaseWindow):
return w.id return w.id
@QtCore.pyqtSlot(list, str) @QtCore.pyqtSlot(list, str)
def show_new_data(self, sets: list, graph: str): @QtCore.pyqtSlot(list, str, bool)
def show_new_data(self, sets: list, graph: str, skip_change: bool = False):
if len(sets) == 0: if len(sets) == 0:
return return
prev_graph = ''
if skip_change:
prev_graph = self.management.current_graph
if graph == '': if graph == '':
graph = self.new_graph() graph = self.new_graph()
@ -336,16 +349,14 @@ class NMRMainWindow(QtWidgets.QMainWindow, Ui_BaseWindow):
self.datawidget.add_item(new_item.id, new_item.name, graph) self.datawidget.add_item(new_item.id, new_item.name, graph)
self.datawidget.blockSignals(False) self.datawidget.blockSignals(False)
if graph == self.fit_dialog.connected_figure: # if graph == self.fit_dialog.connected_figure:
self.fit_dialog.load(self.management.graphs.active(graph)) # self.fit_dialog.load(self.management.graphs.active(graph))
if skip_change:
self.area.setActiveSubWidget(prev_graph)
if self.valuewidget.isVisible(): if self.valuewidget.isVisible():
self.valuewidget(self.management.graphs.tree()) self.valuewidget(self.management.graphs.tree())
@QtCore.pyqtSlot(name='on_actionDelete_window_triggered')
def delete_windows(self):
self.management.delete_sets()
@QtCore.pyqtSlot(str) @QtCore.pyqtSlot(str)
def remove_graph(self, gid: str): def remove_graph(self, gid: str):
self.datawidget.remove_item([gid]) self.datawidget.remove_item([gid])
@ -389,7 +400,6 @@ class NMRMainWindow(QtWidgets.QMainWindow, Ui_BaseWindow):
break break
if w is not None: if w is not None:
self.area.removeSubWindow(w) self.area.removeSubWindow(w)
w.close() w.close()
@ -419,7 +429,7 @@ class NMRMainWindow(QtWidgets.QMainWindow, Ui_BaseWindow):
self.datawidget.blockSignals(False) self.datawidget.blockSignals(False)
w.mousePositionChanged.connect(self.mousemoved) w.mousePositionChanged.connect(self.mousemoved)
w.aboutToClose.connect(self.delete_windows) w.aboutToClose.connect(self.management.delete_sets)
w.positionClicked.connect(self.point_selected) w.positionClicked.connect(self.point_selected)
w.show() w.show()
@ -430,42 +440,36 @@ class NMRMainWindow(QtWidgets.QMainWindow, Ui_BaseWindow):
@QtCore.pyqtSlot(QtWidgets.QMdiSubWindow, name='on_area_subWindowActivated') @QtCore.pyqtSlot(QtWidgets.QMdiSubWindow, name='on_area_subWindowActivated')
def change_window(self, wd): def change_window(self, wd):
""" Called every time focus moves from or to a subwindow. Returns None if current focus is not on a subwindow""" """ Called every time focus moves from or to a subwindow. Returns None if current focus is not on a subwindow"""
if wd is not None: if wd is None:
if self.current_graph_widget is not None: return
self.current_graph_widget.closable = True
if self.ptsselectwidget.isVisible(): if self.current_graph_widget is not None:
self._select_ptswidget(False, False, False) self.current_graph_widget.closable = True
if self.fit_dialog.isVisible():
self._select_fitwidget(False, False)
self.current_graph_widget = wd.widget()
self.management.current_graph = wd.widget().id
self.current_plotitem = self.current_graph_widget.graphic
self.change_mouse_mode(self.actionMouse_behaviour.isChecked())
pick = False
block = False
if self.ptsselectwidget.isVisible(): if self.ptsselectwidget.isVisible():
pick, block = self._select_ptswidget(True, pick, block) self._select_ptswidget(False, False, False)
if self.fit_dialog.isVisible(): if self.fit_dialog.isVisible():
block = self._select_fitwidget(True, block) self._select_fitwidget(False, False)
self._set_pick_block(pick, block) self.current_graph_widget = wd.widget()
self.management.current_graph = wd.widget().id
self.current_plotitem = self.current_graph_widget.graphic
self.datawidget.tree.blockSignals(True) self.change_mouse_mode(self.actionMouse_behaviour.isChecked())
self.datawidget.tree.highlight(self.management.current_graph)
self.datawidget.tree.blockSignals(False)
@QtCore.pyqtSlot(name='on_actionCascade_windows_triggered') pick = False
@QtCore.pyqtSlot(name='on_actionTile_triggered') block = False
def change_window_size(self): if self.ptsselectwidget.isVisible():
if self.sender() == self.actionCascade_windows: pick, block = self._select_ptswidget(True, pick, block)
self.area.cascadeSubWindows() if self.fit_dialog.isVisible():
elif self.sender() == self.actionTile: block = self._select_fitwidget(True, block)
self.area.tileSubWindows()
self._set_pick_block(pick, block)
self.datawidget.tree.blockSignals(True)
self.datawidget.tree.highlight(self.management.current_graph)
self.datawidget.tree.blockSignals(False)
@QtCore.pyqtSlot(name='on_actionChange_datatypes_triggered') @QtCore.pyqtSlot(name='on_actionChange_datatypes_triggered')
def type_change_dialog(self): def type_change_dialog(self):
@ -558,8 +562,9 @@ class NMRMainWindow(QtWidgets.QMainWindow, Ui_BaseWindow):
self.management.graphs[current_graph].add_external(self.valuewidget.selection_imag) self.management.graphs[current_graph].add_external(self.valuewidget.selection_imag)
else: else:
if self.valuewidget.connected_figure is not None: if self.valuewidget.connected_figure is not None:
self.management.graphs[self.valuewidget.connected_figure].remove_external(self.valuewidget.selection_real) conn_fig = self.valuewidget.connected_figure
self.management.graphs[self.valuewidget.connected_figure].remove_external(self.valuewidget.selection_imag) self.management.graphs[conn_fig].remove_external(self.valuewidget.selection_real)
self.management.graphs[conn_fig].remove_external(self.valuewidget.selection_imag)
def _select_integralwidget(self, onoff: bool, pick_required: bool, block_window: bool) -> tuple[bool, bool]: def _select_integralwidget(self, onoff: bool, pick_required: bool, block_window: bool) -> tuple[bool, bool]:
if self.current_graph_widget is None: if self.current_graph_widget is None:
@ -623,7 +628,8 @@ class NMRMainWindow(QtWidgets.QMainWindow, Ui_BaseWindow):
@QtCore.pyqtSlot(str) @QtCore.pyqtSlot(str)
def get_data(self, key: str): def get_data(self, key: str):
self.sender().set_data(self.management[key]) if hasattr(self.sender(), 'set_data'):
self.sender().set_data(self.management[key])
@QtCore.pyqtSlot(name='on_actionCalculateT1_triggered') @QtCore.pyqtSlot(name='on_actionCalculateT1_triggered')
def show_t1calc_dialog(self): def show_t1calc_dialog(self):
@ -832,6 +838,7 @@ class NMRMainWindow(QtWidgets.QMainWindow, Ui_BaseWindow):
except KeyError: except KeyError:
ret_val = None ret_val = None
# noinspection PyUnresolvedReferences
self.sender().receive_data(ret_val) self.sender().receive_data(ret_val)
return ret_val return ret_val
@ -847,7 +854,7 @@ class NMRMainWindow(QtWidgets.QMainWindow, Ui_BaseWindow):
self.t1tauwidget.t1min_picked(pos) self.t1tauwidget.t1min_picked(pos)
elif w == self.integralwidget: elif w == self.integralwidget:
region, integral_plot = self.integralwidget.add(pos) region, integral_plot = self.integralwidget.add(pos)
self.current_graph_widget.add_external(region) self.current_graph_widget.add_external(region)
self.current_graph_widget.add_external(integral_plot) self.current_graph_widget.add_external(integral_plot)
@ -928,7 +935,8 @@ class NMRMainWindow(QtWidgets.QMainWindow, Ui_BaseWindow):
res_dialog.show() res_dialog.show()
@QtCore.pyqtSlot(dict, list, str, bool, bool, list) @QtCore.pyqtSlot(dict, list, str, bool, bool, list)
def accepts_fit(self, res: dict, opts: list, param_graph: str, show_fit: bool, parts: bool, extrapolate: list) -> None: def accepts_fit(self, res: dict, opts: list, param_graph: str,
show_fit: bool, parts: bool, extrapolate: list) -> None:
self.fit_dialog.set_parameter(res) self.fit_dialog.set_parameter(res)
self.management.make_fits(res, opts, param_graph, show_fit, parts, extrapolate) self.management.make_fits(res, opts, param_graph, show_fit, parts, extrapolate)

View File

@ -74,7 +74,7 @@ class UpperManagement(QtCore.QObject):
newGraph = QtCore.pyqtSignal() newGraph = QtCore.pyqtSignal()
restoreGraph = QtCore.pyqtSignal(str) restoreGraph = QtCore.pyqtSignal(str)
deleteGraph = QtCore.pyqtSignal(str) deleteGraph = QtCore.pyqtSignal(str)
newData = QtCore.pyqtSignal(list, str) newData = QtCore.pyqtSignal([list, str], [list, str, bool])
deleteData = QtCore.pyqtSignal(list) deleteData = QtCore.pyqtSignal(list)
dataChanged = QtCore.pyqtSignal(str) dataChanged = QtCore.pyqtSignal(str)
fitFinished = QtCore.pyqtSignal(list) fitFinished = QtCore.pyqtSignal(list)
@ -287,6 +287,7 @@ class UpperManagement(QtCore.QObject):
@QtCore.pyqtSlot(list) @QtCore.pyqtSlot(list)
@QtCore.pyqtSlot(str) @QtCore.pyqtSlot(str)
@QtCore.pyqtSlot()
def delete_sets(self, rm_sets: list = None): def delete_sets(self, rm_sets: list = None):
rm_graphs = [] rm_graphs = []
@ -624,8 +625,7 @@ class UpperManagement(QtCore.QObject):
if not graph_id: if not graph_id:
graph_id = '' graph_id = ''
# TODO add flag that new window will not get focus, because it messes up the data_table in fitwindow self.newData[list, str, bool].emit(p_id_list, graph_id, True)
self.newData.emit(p_id_list, graph_id)
def save_fit_parameter(self, fname: str | pathlib.Path, fit_sets: list[str] = None): def save_fit_parameter(self, fname: str | pathlib.Path, fit_sets: list[str] = None):
if fit_sets is None: if fit_sets is None:

View File

@ -125,7 +125,7 @@
</attribute> </attribute>
</widget> </widget>
</widget> </widget>
<widget class="QMdiArea" name="area"/> <widget class="MdiAreaTile" name="area"/>
</widget> </widget>
</item> </item>
</layout> </layout>
@ -136,7 +136,7 @@
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>1386</width> <width>1386</width>
<height>20</height> <height>22</height>
</rect> </rect>
</property> </property>
<widget class="QMenu" name="menuFile"> <widget class="QMenu" name="menuFile">
@ -274,6 +274,8 @@
<string>View</string> <string>View</string>
</property> </property>
<addaction name="actionTile"/> <addaction name="actionTile"/>
<addaction name="actionTileVertical"/>
<addaction name="actionTileHorizontal"/>
<addaction name="actionCascade_windows"/> <addaction name="actionCascade_windows"/>
</widget> </widget>
<addaction name="actionNew_window"/> <addaction name="actionNew_window"/>
@ -743,6 +745,16 @@
<string>Tile windows</string> <string>Tile windows</string>
</property> </property>
</action> </action>
<action name="actionTileVertical">
<property name="text">
<string>Tile windows vertically</string>
</property>
</action>
<action name="actionTileHorizontal">
<property name="text">
<string>Tile windows horizontally</string>
</property>
</action>
<action name="actionMinimize"> <action name="actionMinimize">
<property name="checkable"> <property name="checkable">
<bool>true</bool> <bool>true</bool>
@ -1060,6 +1072,12 @@
<header>..data.integral_widget</header> <header>..data.integral_widget</header>
<container>1</container> <container>1</container>
</customwidget> </customwidget>
<customwidget>
<class>MdiAreaTile</class>
<extends>QFrame</extends>
<header>..lib.mdiarea</header>
<container>1</container>
</customwidget>
</customwidgets> </customwidgets>
<resources/> <resources/>
<connections> <connections>