コード例 #1
0
ファイル: gui.py プロジェクト: zyh121382/LaTeX-OCR
class App(QMainWindow):
    def __init__(self, args=None):
        super().__init__()
        self.args = args
        self.initModel()
        self.initUI()
        self.snipWidget = SnipWidget(self)

        self.show()

    def initModel(self):
        args, *objs = pix2tex.initialize(self.args)
        self.args = args
        self.objs = objs

    def initUI(self):
        self.setWindowTitle("LaTeX OCR")
        QApplication.setWindowIcon(QtGui.QIcon(':/icons/icon.svg'))
        self.left = 300
        self.top = 300
        self.width = 500
        self.height = 300
        self.setGeometry(self.left, self.top, self.width, self.height)

        # Create LaTeX display
        self.webView = QWebEngineView()
        self.webView.setHtml("")
        self.webView.setMinimumHeight(80)

        # Create textbox
        self.textbox = QTextEdit(self)
        self.textbox.textChanged.connect(self.displayPrediction)
        self.textbox.setMinimumHeight(40)

        # Create temperature text input
        self.tempField = QDoubleSpinBox(self)
        self.tempField.setValue(self.args.get('temperature', 0.25))
        self.tempField.setRange(0, 1)
        self.tempField.setSingleStep(0.1)

        # Create snip button
        self.snipButton = QPushButton('Snip', self)
        self.snipButton.clicked.connect(self.onClick)

        # Create retry button
        self.retryButton = QPushButton('Retry', self)
        self.retryButton.setEnabled(False)
        self.retryButton.clicked.connect(self.returnSnip)

        # Create layout
        centralWidget = QWidget()
        centralWidget.setMinimumWidth(200)
        self.setCentralWidget(centralWidget)

        lay = QVBoxLayout(centralWidget)
        lay.addWidget(self.webView, stretch=4)
        lay.addWidget(self.textbox, stretch=2)
        buttons = QHBoxLayout()
        buttons.addWidget(self.snipButton)
        buttons.addWidget(self.retryButton)
        lay.addLayout(buttons)
        settings = QFormLayout()
        settings.addRow('Temperature:', self.tempField)
        lay.addLayout(settings)

    @pyqtSlot()
    def onClick(self):
        self.close()
        self.snipWidget.snip()

    def returnSnip(self, img=None):
        # Show processing icon
        pageSource = """<center>
        <img src="qrc:/icons/processing-icon-anim.svg" width="50", height="50">
        </center>"""
        self.webView.setHtml(pageSource)

        self.snipButton.setEnabled(False)
        self.retryButton.setEnabled(False)

        self.show()
        try:
            self.args.temperature = self.tempField.value()
            if self.args.temperature == 0:
                self.args.temperature = 1e-8
        except:
            pass
        # Run the model in a separate thread
        self.thread = ModelThread(img=img, args=self.args, objs=self.objs)
        self.thread.finished.connect(self.returnPrediction)
        self.thread.finished.connect(self.thread.deleteLater)

        self.thread.start()

    def returnPrediction(self, result):
        self.snipButton.setEnabled(True)

        success, prediction = result["success"], result["prediction"]

        if success:
            self.displayPrediction(prediction)
            self.retryButton.setEnabled(True)
        else:
            self.webView.setHtml("")
            msg = QMessageBox()
            msg.setWindowTitle(" ")
            msg.setText("Prediction failed.")
            msg.exec_()

    def displayPrediction(self, prediction=None):
        if prediction is not None:
            self.textbox.setText("${equation}$".format(equation=prediction))
        else:
            prediction = self.textbox.toPlainText().strip('$')
        pageSource = """
        <html>
        <head><script id="MathJax-script" src="qrc:MathJax.js"></script>
        <script>
        MathJax.Hub.Config({messageStyle: 'none',tex2jax: {preview: 'none'}});
        MathJax.Hub.Queue(
            function () {
                document.getElementById("equation").style.visibility = "";
            }
            );
        </script>
        </head> """ + """
        <body>
        <div id="equation" style="font-size:1em; visibility:hidden">$${equation}$$</div>
        </body>
        </html>
            """.format(equation=prediction)
        self.webView.setHtml(pageSource)
コード例 #2
0
ファイル: MainView.py プロジェクト: kaileby/EduWatching
class View_Main(QMainWindow, Ui_MainWindow):
    classroom_briefs = []
    class_brief_threads = []
    view_real_time = None

    def __init__(self):
        super().__init__()
        self.setupUi(self)

        # 四个页面的切换
        self.widget_building.clicked.connect(self.change_page_class)
        self.widget_status.clicked.connect(self.change_page_status)
        self.widget_abnormal.clicked.connect(self.change_page_abnormal)
        self.widget_record.clicked.connect(self.change_page_record)

        # 从数据库读取教室信息
        get_class_briefs(self.classroom_briefs)
        # 多线程完成教室初始化显示
        threads = []
        for brief in self.classroom_briefs:
            threads.append(
                threading.Thread(target=init_thumbnail, args=(brief, )))
        for thread in threads:
            thread.start()
            thread.join()

        # 注册教室列表
        self.class_web = QWebEngineView(self.page_class)
        self.class_channel = QWebChannel(self.class_web.page())
        self.class_obj = ClassObj()

        # 注册按教学楼分类的标题组件
        self.building_title_web = QWebEngineView(self.page_class)
        self.building_title_web.setMaximumHeight(90)
        self.building_title_web.setMinimumHeight(90)
        self.building_title_channel = QWebChannel(
            self.building_title_web.page())
        self.building_title_obj = BuildingTitleObj()

        # 注册按状态分类的标题栏组件
        self.state_title_web = QWebEngineView(self.page_class)
        self.state_title_web.setMinimumHeight(65)
        self.state_title_web.setMaximumHeight(65)
        self.state_title_channel = QWebChannel(self.state_title_web.page())
        self.state_title_obj = StateTitleObj()

        self.setup_class_page()

        # 注册上课回看列表需要的组件
        self.record_list_page = QWebEngineView(self.page_reocrd)
        self.record_list_channel = QWebChannel(self.record_list_page.page())
        self.record_list_obj = RecordListObj()
        self.setup_record_table()

    def setup_class_page(self):
        # 初始化按教学楼搜索标题栏
        self.building_title_obj.sig_confirm_clicked.connect(
            self.sift_by_building)
        self.building_title_channel.registerObject('building_title_obj',
                                                   self.building_title_obj)
        self.building_title_web.page().setWebChannel(
            self.building_title_channel)
        self.building_title_web.load(
            QUrl.fromLocalFile(
                os.path.abspath('view/html/TitleBuilding.html')))

        # 初始化按状态搜索标题栏
        self.state_title_channel.registerObject('state_title_obj',
                                                self.state_title_obj)
        self.state_title_web.page().setWebChannel(self.state_title_channel)
        self.state_title_web.load(
            QUrl.fromLocalFile(os.path.abspath('view/html/TitleState.html')))
        self.state_title_web.hide()

        # 初始化教室页面
        self.class_obj.sig_class_item_clicked.connect(self.open_real_time)
        self.class_channel.registerObject('class_obj', self.class_obj)
        self.class_web.page().setWebChannel(self.class_channel)
        self.class_web.load(
            QUrl.fromLocalFile(os.path.abspath('view/html/ClassTable.html')))
        self.class_web.loadFinished.connect(self.refresh_page)

        self.verticalLayout_7.addWidget(self.building_title_web)
        self.verticalLayout_7.addWidget(self.state_title_web)
        self.verticalLayout_7.addWidget(self.class_web)
        # 统计学生人数线程对象生成
        for brief in self.classroom_briefs:
            self.class_brief_threads.append(
                ClassBriefThread(brief, self.class_web.page()))
        for thread in self.class_brief_threads:
            thread.start()

    def refresh_page(self):
        # 刷新教室列表的显示
        init_table = ''
        for brief in self.classroom_briefs:
            if brief.isShow:
                init_table += HTMLFactory.get_instance().class_brief_box_first(
                    brief)
        self.class_web.page().runJavaScript(
            "setupTable('{0}')".format(init_table))

    def open_real_time(self, class_brief_id):
        for brief in self.classroom_briefs:
            if brief.classroom.classroom_id == class_brief_id:
                print(
                    ">>>>>>>>>>>>>>>>>>>>>> classroom {0} begin to be monitored"
                    .format(class_brief_id))
                for thread in self.class_brief_threads:
                    thread.pause()
                time.sleep(2)
                self.view_real_time = View_RealTime(brief)
                self.view_real_time.sig_on_closed.connect(self.resume)
                self.view_real_time.showMaximized()
                break

    def sift_by_building(self, campus, building, floor):
        # 按照教学楼显示
        # 根据校区、教学楼、教室号来进行筛选
        for brief in self.classroom_briefs:
            if (campus in brief.classroom.campus) and (
                    building in brief.classroom.building) and (
                        floor in brief.classroom.floor):
                if not brief.isShow:
                    self.add_box(brief)
                    brief.isShow = True
            elif brief.isShow:
                self.remove_box(brief)
                brief.isShow = False

    # 初始化上课回看列表
    def setup_record_table(self):
        self.record_list_obj.sig_record_list_item_clicked.connect(
            self.open_replay)
        self.record_list_channel.registerObject('record_list_obj',
                                                self.record_list_obj)
        self.record_list_page.page().setWebChannel(self.record_list_channel)
        self.verticalLayout_10.addWidget(self.record_list_page)
        self.record_list_page.load(
            QUrl.fromLocalFile(os.path.abspath('view/html/Record.html')))

    def open_replay(self, item_id):
        self.view_replay = View_Replay()
        self.view_replay.showMaximized()

    def change_page_class(self):
        for thread in self.class_brief_threads:
            thread.resume()
        self.stackedWidget.setCurrentIndex(0)
        self.building_title_web.show()
        self.state_title_web.hide()

        for brief in self.classroom_briefs:
            if not brief.isShow:
                self.add_box(brief)
                brief.isShow = True

    def change_page_status(self):
        for thread in self.class_brief_threads:
            thread.resume()
        self.stackedWidget.setCurrentIndex(0)
        self.building_title_web.hide()
        self.state_title_web.show()

        for brief in self.classroom_briefs:
            if not brief.isShow:
                self.add_box(brief)
                brief.isShow = True

    def change_page_abnormal(self):
        for thread in self.class_brief_threads:
            thread.resume()
        self.stackedWidget.setCurrentIndex(0)
        self.building_title_web.hide()
        self.state_title_web.hide()

        for brief in self.classroom_briefs:
            if brief.isAbnormal:
                if not brief.isShow:
                    self.add_box(brief)
                brief.isShow = True
            else:
                if brief.isShow:
                    self.remove_box(brief)
                brief.isShow = False

    def add_box(self, brief):
        box = HTMLFactory.get_instance().class_brief_box_first(brief)
        update_class_table_lock.acquire()
        self.class_web.page().runJavaScript("addBox('{0}')".format(box))
        update_class_table_lock.release()

    def remove_box(self, brief):
        update_class_table_lock.acquire()
        self.class_web.page().runJavaScript("removeBox('class_{}')".format(
            brief.classroom.classroom_id))
        update_class_table_lock.release()

    def change_page_record(self):
        self.stackedWidget.setCurrentIndex(1)
        for thread in self.class_brief_threads:
            thread.pause()

    # 关闭实时监控页之后调用
    def resume(self):
        for thread in self.class_brief_threads:
            thread.resume()
コード例 #3
0
ファイル: Window.py プロジェクト: JX25/LwH-1
class App(QWidget):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.actions = []
        self.project = Project()
        self.create_window()

    def create_window(self):
        # labels
        nameLabel = QLabel("Nazwa akcji", self)
        nameLabel.setFixedWidth(100)
        durationLabel = QLabel("Czas trwania akcji", self)
        durationLabel.setFixedWidth(100)
        predLabel = QLabel("Poprzednicy [;]", self)
        predLabel.setFixedWidth(100)
        self.criticalPathLabel = QLabel("Ścieżka krytyczna: ", self)
        self.timeLabel = QLabel("Czas trwania: ", self)
        self.messageLabel = QLabel("", self)
        self.graphLabel = QLabel(self)

        pixmap2 = QPixmap('images/graph.png')

        self.graphLabel.setPixmap(pixmap2)
        # entries
        self.nameEntry = QLineEdit()
        self.nameEntry.setFixedWidth(150)
        self.durationEntry = QLineEdit()
        self.durationEntry.setFixedWidth(150)
        self.predEntry = QLineEdit()
        self.predEntry.setFixedWidth(150)

        # buttons
        addButton = QPushButton("Dodaj czynność", self)
        addButton.setFixedWidth(100)
        computeButton = QPushButton("Oblicz", self)
        computeButton.setFixedWidth(100)

        # buttons action
        addButton.clicked.connect(self.add_action)
        computeButton.clicked.connect(self.compute_task)

        # web view
        self.view = QWebEngineView(self)
        self.view.setMinimumWidth(800)
        self.view.setMinimumHeight(600)
        url = QtCore.QUrl.fromLocalFile(r"/temp-plot.html")
        self.view.load(url)
        # grid

        hboxRow1 = QHBoxLayout()
        hboxRow1.addWidget(nameLabel)
        hboxRow1.addWidget(self.nameEntry)
        hboxRow1.addWidget(addButton)
        hboxRow1.addStretch(1)

        hboxRow2 = QHBoxLayout()
        hboxRow2.addWidget(durationLabel)
        hboxRow2.addWidget(self.durationEntry)
        hboxRow2.addWidget(computeButton)
        hboxRow2.addStretch(1)

        hboxRow3 = QHBoxLayout()
        hboxRow3.addWidget(predLabel)
        hboxRow3.addWidget(self.predEntry)
        hboxRow3.addStretch(1)

        vboxRowLast = QVBoxLayout()
        vboxRowLast.addWidget(self.criticalPathLabel)
        vboxRowLast.addWidget(self.timeLabel)

        vboxEntryData = QVBoxLayout()
        vboxEntryData.addLayout(hboxRow1)
        vboxEntryData.addLayout(hboxRow2)
        vboxEntryData.addLayout(hboxRow3)
        vboxEntryData.addLayout(vboxRowLast)

        vboxGraphInfo = QVBoxLayout()
        vboxGraphInfo.addWidget(self.graphLabel)
        vboxGraphInfo.addStretch(1)
        vboxGraphInfo.addWidget(self.messageLabel)

        vboxLeftSide = QVBoxLayout()
        vboxLeftSide.addLayout(vboxEntryData)
        vboxLeftSide.addStretch(1)
        vboxLeftSide.addLayout(vboxGraphInfo)

        hboxFinal = QHBoxLayout()
        hboxFinal.addLayout(vboxLeftSide)
        hboxFinal.addStretch(1)
        hboxFinal.addWidget(self.view)

        self.setLayout(hboxFinal)
        self.resize(500, 500)
        self.setWindowTitle("App")
        self.show()

    def add_action(self):
        name = self.nameEntry.text()
        duration = self.durationEntry.text()
        if self.predEntry.text() == '':
            pred = []
        else:
            pred = self.predEntry.text().split(";")
        try:  #s
            self.actions.append(Action(name, duration, pred))
            self.messageLabel.setText("Dodano czynność: " + name)
        except Exception as error:
            self.messageLabel.setText(error.args[0])
            self.actions = []
        for task in self.actions:
            print(task.name + " " + str(task.duration) + " " +
                  str(task.predecessors))

    def compute_task(self):
        if self.actions != []:
            self.project.create_network(self.actions)
            cp = self.project.get_critical_path()
            dr = self.project.get_duration()
            create_graph_image(self.actions, cp)
            self.graphLabel.setPixmap(QPixmap('images/graph.png'))
            create_gantt_chart(self.actions, cp)
            url = QtCore.QUrl.fromLocalFile(r"/temp-plot.html")
            self.view.load(url)
            # self.ganttLabel.setPixmap(QPixmap('images/gantt.png'))
            self.timeLabel.setText("Czas trwania " + str(dr) + "h")
            string_cp = str(cp[0])
            for node in cp[1:]:
                string_cp += " -> " + str(node)
            self.criticalPathLabel.setText(string_cp)
            self.actions = []
            self.project = Project()
        else:
            self.messageLabel.setText("Brak danych!")
            self.actions = []
            self.project = Project()
コード例 #4
0
class OWPlotlyViewer(SparkEnvironment, widget.OWWidget):
    # --------------- Widget metadata protocol ---------------
    priority = 2

    name = "Plotly"
    description = "A plotly canvas"
    icon = "../assets/DataFrameViewer.svg"

    input_figure: go.Figure = None

    class Inputs:
        figure = widget.Input("Figure", go.Figure)

    class Outputs:
        pass
        #data_frame = widget.Output("DataFrame", pyspark.sql.DataFrame)

    want_control_area = True

    def __init__(self):
        super().__init__()
        self.controlArea.setMinimumWidth(250)
        self.v_info_box = gui.vBox(self.controlArea, 'Info')
        self.v_info = gui.label(self.v_info_box, self, '')
        self.v_info.setAlignment(QtCore.Qt.AlignTop)

        self.mainArea.setMinimumWidth(800)
        self.mainArea.setMinimumHeight(600)

        self.v_webview = QWebEngineView(self.mainArea)
        self.v_webview.setMinimumWidth(800)
        self.v_webview.setMinimumHeight(600)

    @Inputs.figure
    def set_input_figure(self, figure):
        self.input_figure = figure

    # called after received all inputs
    def handleNewSignals(self):
        self.apply()

    def _check_input(self):
        if self.input_figure is None:
            self.warning('Input figure does not exist')
            return False
        else:
            return True

    # this is the logic: computation, update UI, send outputs. ..
    def apply(self):
        if not self._check_input():
            return

        self.clear_messages()

        filename = tempfile.NamedTemporaryFile(suffix='.html').name
        print('Plot file path: %s' % filename)
        plotly.offline.plot(self.input_figure,
                            output_type='file',
                            filename=filename,
                            auto_open=False,
                            show_link=False)  # , include_plotlyjs=True)

        self.v_webview.load(QUrl.fromLocalFile(filename))
コード例 #5
0
# loop.exec_()
# html = webview.page().mainFrame().toHtml()
# tree = lxml.html.fromstring(html)
# content = tree.cssselect('#result')[0].text
# print(content)

## 新版本使用
# pip install PySide2==5.12.0
# pip install PyQt5==5.11.3
# try:
#     from PySide2.QtCore import QUrl
#     from PySide2.QtWidgets import QApplication
#     from PySide2.QtWebEngineWidgets import QWebEnginePage, QWebEngineView
# except:
from PyQt5.QtCore import QUrl
from PyQt5.QtWidgets import QApplication
from PyQt5.QtWebEngineWidgets import QWebEnginePage, QWebEngineView
# 弹窗显示
url = 'http://example.webscraping.com/places/default/search'
app = QApplication([])
view = QWebEngineView()
view.setWindowTitle("阿尔法科技有限公司")
view.setMinimumWidth(1000)
view.setMinimumHeight(800)
view.load(QUrl(url))
view.show()
app.exec()

# 基于webkit的解决方案
# Ghost是Selenium 与PhantomJS 的结合体,安装时会携带PySide,PyQt4
# pip install Ghost==0.5.0
コード例 #6
0
class MainWindow(QWidget):
    def __init__(self):
        super().__init__()

        # Init a state dict
        self.state = {
            "internet": {
                "connected": False,
            },
            "serial": {
                "client": serial.Serial(),
                "connected": False,
                "device": "",
                "baud": 0,
            },
            "mqtt": {
                "client": mqtt.Client(),
                "connected": False,
                "hostname": "",
                "port": "",
                "username": "",
            }
        }

        # Grab config
        self.config = configparser.ConfigParser()
        self.config.read('config.ini')

        # Setup MQTT Callbacks
        self.state["mqtt"]["client"].on_connect = self.mqtt_on_connect
        self.state["mqtt"]["client"].on_disconnect = self.mqtt_on_disconnect
        self.state["mqtt"]["client"].on_subscribe = self.mqtt_on_subscribe
        self.state["mqtt"]["client"].on_unsubscribe = self.mqtt_on_unsubscribe
        self.state["mqtt"]["client"].on_publish = self.mqtt_on_publish
        self.state["mqtt"]["client"].on_message = self.mqtt_on_message
        self.state["mqtt"]["client"].on_log = self.mqtt_on_log

        # Setup support things
        self.create_icons()

        # Setup main window
        self.layout_main_window = QGridLayout()

        self.setWindowTitle("Icarus GCS")
        self.setWindowIcon(QIcon('assets/balloon_map_icon.png'))

        self.create_toolbar_interface()
        self.create_map_interface()
        self.create_serial_interface()
        self.create_mqtt_interface()

        self.layout_main_window.addWidget(self.toolbar_status, 0, 1, 1, -1)
        self.layout_main_window.addWidget(self.webengine_map, 1, 1, -1, -1)
        self.layout_main_window.addWidget(self.groupbox_serial_interface, 0, 0,
                                          2, 1)
        self.layout_main_window.addWidget(self.groupbox_mqtt_interface, 2, 0)

        self.setLayout(self.layout_main_window)

        # Setup timers for events
        self.timer_internet_status = QTimer(self)
        self.timer_internet_status.timeout.connect(
            self.on_timer_internet_status)
        self.timer_internet_status.start(5 * 1000)

        # Check timed events once at the start
        # self.on_timer_internet_status()

        # Let's do this!
        self.show()

    def create_toolbar_interface(self):
        self.toolbar_status = QToolBar()
        self.toolbar_status.setFloatable(False)
        self.toolbar_status.setMovable(False)
        self.toolbar_status.setIconSize(QSize(24, 24))

        self.toolbutton_internet_status = QToolButton()
        self.toolbutton_internet_status.setIcon(self.icons["cloud-line"])
        self.toolbutton_internet_status.setEnabled(False)

        self.toolbutton_mqtt_status = QToolButton()
        self.toolbutton_mqtt_status.setIcon(self.icons["server-line"])
        self.toolbutton_mqtt_status.setEnabled(False)

        self.toolbutton_radio_status = QToolButton()
        self.toolbutton_radio_status.setIcon(self.icons["wifi-line"])
        self.toolbutton_radio_status.setEnabled(False)

        self.toolbutton_cellular_status = QToolButton()
        self.toolbutton_cellular_status.setIcon(self.icons["sim-card-line"])
        self.toolbutton_cellular_status.setEnabled(False)

        self.toolbutton_heartbeat_status = QToolButton()
        self.toolbutton_heartbeat_status.setIcon(self.icons["heart-line"])
        self.toolbutton_heartbeat_status.setEnabled(False)

        self.toolbar_status.addWidget(self.toolbutton_internet_status)
        self.toolbar_status.addWidget(self.toolbutton_mqtt_status)
        self.toolbar_status.addWidget(self.toolbutton_radio_status)
        self.toolbar_status.addWidget(self.toolbutton_cellular_status)
        self.toolbar_status.addWidget(self.toolbutton_heartbeat_status)

    def create_map_interface(self):
        self.webengine_map = QWebEngineView()

        self.map_wrapper = MapWrapper(
            self.webengine_map, {
                "home_latitude": self.config["Map"]["Home Latitude"],
                "home_longitude": self.config["Map"]["Home Longitude"],
                "home_zoom": self.config["Map"]["Zoom Level"],
                "max_zoom": self.config["Map"]["Max Zoom Level"],
                "min_zoom": self.config["Map"]["Min Zoom Level"],
            })

        self.map_view_webchannel = QWebChannel()
        self.map_view_webchannel.registerObject("python_link",
                                                self.map_wrapper)
        self.webengine_map.page().setWebChannel(self.map_view_webchannel)
        self.webengine_map.load(
            QtCore.QUrl.fromLocalFile(
                QtCore.QDir.current().filePath("static/map.html")))
        self.webengine_map.setMinimumWidth(1024)
        self.webengine_map.setMinimumHeight(768)

    def create_serial_interface(self):
        self.groupbox_serial_interface = QGroupBox("Serial")
        self.groupbox_serial_interface.setMinimumWidth(320)
        self.groupbox_serial_interface.setMaximumWidth(320)
        self.layout_serial_interface = QGridLayout()
        self.groupbox_serial_interface.setLayout(self.layout_serial_interface)

        self.label_serial_port = QLabel(self)
        self.label_serial_port.setText("Device:")
        self.label_serial_port.setMinimumWidth(100)
        self.label_serial_port.setMaximumWidth(100)

        self.combo_serial_port = QComboBox(self)
        devices = self.serial_list_ports()
        for device in devices:
            self.combo_serial_port.addItem(device)

        self.label_serial_baud_rate = QLabel(self)
        self.label_serial_baud_rate.setText("Baud Rate:")

        self.line_edit_serial_baud_rate = QLineEdit(self)
        self.line_edit_serial_baud_rate.setText("115200")

        self.button_serial_connect = QPushButton(self)
        self.button_serial_connect.setText("Connect")
        self.button_serial_connect.clicked.connect(
            self.button_serial_connect_clicked)

        self.layout_serial_interface.addWidget(self.label_serial_port, 0, 0)
        self.layout_serial_interface.addWidget(self.combo_serial_port, 0, 1)
        self.layout_serial_interface.addWidget(self.label_serial_baud_rate, 1,
                                               0)
        self.layout_serial_interface.addWidget(self.line_edit_serial_baud_rate,
                                               1, 1)
        self.layout_serial_interface.addWidget(self.button_serial_connect, 2,
                                               0, 1, 2)

    def lock_serial_interface(self):
        self.combo_serial_port.setReadOnly(True)
        self.line_edit_serial_baud_rate.setReadOnly(True)

        self.button_serial_connect.setText("Disconnect")

    def unlock_serial_interface(self):
        self.combo_serial_port.setReadOnly(False)
        self.line_edit_serial_baud_rate.setReadOnly(False)

        self.button_serial_connect.setText("Connect")

    def serial_list_ports(self):
        ports = list(serial.tools.list_ports.comports(False))
        devices = []

        for port in ports:
            devices.append(str(port.description) + " (" + port.device + ")")

        return devices

    def button_serial_connect_clicked(self):
        if not self.state["serial"]["connected"]:
            selected_serial_port = self.combo_serial_port.currentText().split(
                "(")[1].replace(")", "")

            try:
                self.state["serial"]["client"].port = selected_serial_port
                self.state["serial"]["client"].baudrate = int(
                    self.line_edit_serial_baud_rate.text())
                self.state["serial"]["client"].open()

                self.state["serial"]["connected"] = True
                self.state["serial"]["device"] = selected_serial_port
                self.state["serial"][
                    "baud"] = self.line_edit_serial_baud_rate.text()

                self.lock_serial_interface()

                print("Connected to: " + self.combo_serial_port.currentText())
            except serial.SerialException as e:
                print("Failed to connect to Serial Port: " +
                      self.combo_serial_port.currentText())
                print(e)
        else:
            try:
                self.serial_port.close()

                self.state["serial"]["connected"] = False
                self.state["serial"]["device"] = ""
                self.state["serial"]["baud"] = 0

                self.unlock_serial_interface()

                print("Disconnected from: " + self.state["serial"]["device"])
            except serial.SerialException as e:
                print("Failed to disconnect from: " +
                      self.state["serial"]["device"])
                print(e)

    def create_mqtt_interface(self):
        self.groupbox_mqtt_interface = QGroupBox("MQTT")
        self.groupbox_mqtt_interface.setMinimumWidth(320)
        self.groupbox_mqtt_interface.setMaximumWidth(320)
        self.layout_mqtt_interface = QGridLayout()
        self.groupbox_mqtt_interface.setLayout(self.layout_mqtt_interface)

        self.label_internet_status = QLabel(self)
        self.label_internet_status.setText("Internet:")
        self.label_internet_status.setMinimumWidth(100)
        self.label_internet_status.setMaximumWidth(100)

        self.line_edit_internet_status = QLineEdit(self)
        self.line_edit_internet_status.setText("Disconnected")
        self.line_edit_internet_status.setReadOnly(True)

        self.label_mqtt_hostname = QLabel(self)
        self.label_mqtt_hostname.setText("Hostname:")

        self.line_edit_mqtt_hostname = QLineEdit(self)
        self.line_edit_mqtt_hostname.setText(self.config["MQTT"]["Hostname"])

        self.label_mqtt_port = QLabel(self)
        self.label_mqtt_port.setText("Port: ")

        self.line_edit_mqtt_port = QLineEdit(self)
        self.line_edit_mqtt_port.setText(self.config["MQTT"]["Port"])

        self.label_mqtt_username = QLabel(self)
        self.label_mqtt_username.setText("Username: "******"MQTT"]["Username"])

        self.label_mqtt_password = QLabel(self)
        self.label_mqtt_password.setText("Password: "******"MQTT"]["Password"])
        self.line_edit_mqtt_password.setEchoMode(QLineEdit.Password)

        self.button_mqtt_connect = QPushButton(self)
        self.button_mqtt_connect.setText("Connect")
        self.button_mqtt_connect.clicked.connect(
            self.button_mqtt_connect_clicked)

        self.label_mqtt_topic = QLabel(self)
        self.label_mqtt_topic.setText("Topic:")

        self.line_edit_mqtt_topic = QLineEdit(self)

        self.button_mqtt_subscribe = QPushButton(self)
        self.button_mqtt_subscribe.setText("Subscribe")
        #self.button_mqtt_subscribe.clicked.connect(self.button_mqtt_subscribe_clicked)

        self.list_box_mqtt_subscriptions = QListWidget(self)
        self.list_box_mqtt_subscriptions.setMaximumHeight(100)

        self.button_mqtt_unsubscribe = QPushButton(self)
        self.button_mqtt_unsubscribe.setText("Unsubscribe")
        #self.button_mqtt_unsubscribe.clicked.connect(self.button_mqtt_unsubscribe_clicked)

        self.layout_mqtt_interface.addWidget(self.label_internet_status, 0, 0)
        self.layout_mqtt_interface.addWidget(self.line_edit_internet_status, 0,
                                             1)
        self.layout_mqtt_interface.addWidget(self.label_mqtt_hostname, 1, 0)
        self.layout_mqtt_interface.addWidget(self.line_edit_mqtt_hostname, 1,
                                             1)
        self.layout_mqtt_interface.addWidget(self.label_mqtt_port, 2, 0)
        self.layout_mqtt_interface.addWidget(self.line_edit_mqtt_port, 2, 1)
        self.layout_mqtt_interface.addWidget(self.label_mqtt_username, 3, 0)
        self.layout_mqtt_interface.addWidget(self.line_edit_mqtt_username, 3,
                                             1)
        self.layout_mqtt_interface.addWidget(self.label_mqtt_password, 4, 0)
        self.layout_mqtt_interface.addWidget(self.line_edit_mqtt_password, 4,
                                             1)
        self.layout_mqtt_interface.addWidget(self.button_mqtt_connect, 5, 0, 1,
                                             2)
        self.layout_mqtt_interface.addWidget(self.label_mqtt_topic, 6, 0)
        self.layout_mqtt_interface.addWidget(self.line_edit_mqtt_topic, 6, 1)
        self.layout_mqtt_interface.addWidget(self.button_mqtt_subscribe, 7, 0,
                                             1, 2)
        self.layout_mqtt_interface.addWidget(self.list_box_mqtt_subscriptions,
                                             8, 0, 1, 2)
        self.layout_mqtt_interface.addWidget(self.button_mqtt_unsubscribe, 9,
                                             0, 1, 2)

    def lock_mqtt_interface(self):
        self.line_edit_mqtt_hostname.setReadOnly(True)
        self.line_edit_mqtt_port.setReadOnly(True)
        self.line_edit_mqtt_username.setReadOnly(True)
        self.line_edit_mqtt_password.setReadOnly(True)

        self.button_mqtt_connect.setText("Disconnect")

    def unlock_mqtt_interface(self):
        self.line_edit_mqtt_hostname.setReadOnly(False)
        self.line_edit_mqtt_port.setReadOnly(False)
        self.line_edit_mqtt_username.setReadOnly(False)
        self.line_edit_mqtt_password.setReadOnly(False)

        self.button_mqtt_connect.setText("Connect")

    def button_mqtt_connect_clicked(self):
        if not self.state["mqtt"]["connected"]:
            self.state["mqtt"]["client"].username_pw_set(
                self.line_edit_mqtt_username.text(),
                self.line_edit_mqtt_password.text())
            self.state["mqtt"]["client"].connect(
                self.line_edit_mqtt_hostname.text(),
                int(self.line_edit_mqtt_port.text()), 30)
            self.state["mqtt"]["client"].loop_start()
        else:
            self.state["mqtt"]["client"].loop_stop()
            self.state["mqtt"]["client"].disconnect()

    def create_chart_interface(self):
        fig = Figure(figsize=(100, 100), dpi=100)
        self.axes = fig.add_subplot(111)
        fig.axes.plot([0, 1, 2, 3, 4], [10, 1, 20, 3, 40])

        self.wid
        self.layout_chart_interface = QGridLayout()

    def on_timer_internet_status(self):
        try:
            socket.create_connection(("1.1.1.1", 53))
            self.state["internet"]["connected"] = True
            self.line_edit_internet_status.setText("Connected")
            self.toolbutton_internet_status.setIcon(self.icons["cloud"])
            return True
        except OSError:
            pass

        self.state["internet"]["connected"] = False
        self.line_edit_internet_status.setText("Disconnected")
        self.toolbutton_internet_status.setIcon(self.icons["cloud-line"])
        return False

    def mqtt_on_connect(self, client, userdata, flags, return_code):
        if return_code == 0:
            print("Connected to MQTT broker at: " +
                  self.line_edit_mqtt_hostname.text())
            self.state["mqtt"]["connected"] = True
            self.state["mqtt"]["hostname"] = self.line_edit_mqtt_hostname.text(
            )
            self.state["mqtt"]["port"] = self.line_edit_mqtt_port.text()
            self.state["mqtt"]["username"] = self.line_edit_mqtt_username.text(
            )
            self.toolbutton_mqtt_status.setIcon(self.icons["server"])
            self.lock_mqtt_interface()
        else:
            print("Failed to connect to MQTT broker at: " +
                  self.line_edit_mqtt_hostname.text())

    def mqtt_on_disconnect(self, client, userdata, return_code):
        if return_code == 0:
            print("Disconnected from MQTT broker")
        else:
            print(
                "Failed to cleanly disconnect from MQTT broker, already disconnected"
            )

        self.state["mqtt"]["connected"] = False
        self.state["mqtt"]["hostname"] = ""
        self.state["mqtt"]["port"] = ""
        self.state["mqtt"]["username"] = ""
        self.toolbutton_mqtt_status.setIcon(self.icons["server-line"])
        self.unlock_mqtt_interface()

    def mqtt_on_subscribe(self, client, userdata, message_id, granted_qos):
        print("test")

    def mqtt_on_unsubscribe(self, client, userdata, message_id):
        print("test")

    def mqtt_on_publish(self, client, userdata, message_id):
        print("test")

    def mqtt_on_message(self, client, userdata, message):
        print("test")

    def mqtt_on_log(self, client, userdata, level, string):
        print(level + ", " + string)

    def create_icons(self):
        self.icons = {}

        icon_path = "assets/remix/icons"

        self.icons["cloud"] = QIcon(icon_path + "/Business/cloud-fill.svg")
        self.icons["cloud-line"] = QIcon(icon_path +
                                         "/Business/cloud-line.svg")
        self.icons["cloud-off"] = QIcon(icon_path +
                                        "/Business/cloud-off-fill.svg")
        self.icons["wifi"] = QIcon(icon_path + "/Device/signal-wifi-fill.svg")
        self.icons["wifi-line"] = QIcon(icon_path +
                                        "/Device/signal-wifi-line.svg")
        self.icons["server"] = QIcon(icon_path + "/Device/server-fill.svg")
        self.icons["server-line"] = QIcon(icon_path +
                                          "/Device/server-line.svg")
        self.icons["wifi-off"] = QIcon(icon_path +
                                       "/Device/signal-wifi-off-fill.svg")
        self.icons["radio"] = QIcon(icon_path + "/Device/wifi-fill.svg")
        self.icons["radio-off"] = QIcon(icon_path +
                                        "/Device/wifi-off-fill.svg")
        self.icons["sim-card"] = QIcon(icon_path +
                                       "/Device/sim-card-2-fill.svg")
        self.icons["sim-card-line"] = QIcon(icon_path +
                                            "/Device/sim-card-2-line.svg")
        self.icons["takeoff"] = QIcon(icon_path +
                                      "/Map/flight-takeoff-fill.svg")
        self.icons["land"] = QIcon(icon_path + "/Map/flight-land-fill.svg")
        self.icons["heart"] = QIcon(icon_path + "/Health/heart-3-fill.svg")
        self.icons["heart-line"] = QIcon(icon_path +
                                         "/Health/heart-3-line.svg")
        self.icons["heart-off"] = QIcon(icon_path + "/Health/dislike-fill.svg")
        self.icons["heart-pulse"] = QIcon(icon_path +
                                          "/Health/heart-pulse-fill.svg")