Skip to content

Commit

Permalink
Change main widget from code to .ui file
Browse files Browse the repository at this point in the history
No more sketchy editing of ui code! Now the main widget is all done
in the designer app, probably fixed some UI bugs along the way (but
not the painting problem with the spinner/checkbox, #9)
  • Loading branch information
julianneswinoga committed Feb 24, 2024
1 parent 0e24f04 commit f940e67
Show file tree
Hide file tree
Showing 7 changed files with 300 additions and 92 deletions.
85 changes: 5 additions & 80 deletions OATFWGUI/gui_logic.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,14 @@
from typing import List, Optional
from pathlib import Path

from PySide6.QtCore import Slot, QThreadPool, QFile, QProcess, Qt
from PySide6.QtGui import QFont
from PySide6.QtWidgets import QLabel, QComboBox, QWidget, QFileDialog, QPushButton, QPlainTextEdit, QGridLayout, \
QHBoxLayout, QCheckBox
from PySide6.QtCore import Slot, QThreadPool, QFile, QProcess
from PySide6.QtWidgets import QWidget, QFileDialog

import requests

from log_utils import LogObject, LoggedExternalFile
from log_utils import LoggedExternalFile
from qt_extensions import Worker
from qbusyindicatorgoodbad import QBusyIndicatorGoodBad, BusyIndicatorState
from qbusyindicatorgoodbad import BusyIndicatorState
from external_processes import external_processes, get_install_dir
from gui_state import LogicState, PioEnv, FWVersion
from anon_usage_data import AnonStatsDialog, create_anon_stats, upload_anon_stats
Expand Down Expand Up @@ -89,7 +87,7 @@ def extract_fw(zipfile_name: Path) -> Path:


class BusinessLogic:
def __init__(self, main_app: 'MainWidget'):
def __init__(self, main_app: QWidget):
self.logic_state = LogicState()

self.main_app = main_app
Expand Down Expand Up @@ -369,76 +367,3 @@ def pio_upload_finished(self):
def modal_show_stats(self):
dlg = AnonStatsDialog(self.logic_state, self.main_app)
dlg.exec_()


class MainWidget(QWidget):
def __init__(self, log_object: LogObject):
QWidget.__init__(self)

# widgets
self.wMsg_fw_version = QLabel('Select firmware version:')
self.wCombo_fw_version = QComboBox()
self.wCombo_fw_version.setPlaceholderText('Grabbing FW Versions...')
self.wBtn_download_fw = QPushButton('Download')
self.wBtn_download_fw.setEnabled(False)
self.wSpn_download = QBusyIndicatorGoodBad(fixed_size=(50, 50))

self.wMsg_pio_env = QLabel('Select board:')
self.wCombo_pio_env = QComboBox()
self.wCombo_pio_env.setPlaceholderText('No FW downloaded yet...')
self.wBtn_select_local_config = QPushButton('Select local config file')
self.wBtn_build_fw = QPushButton('Build FW')
self.wBtn_build_fw.setEnabled(False)
self.wMsg_config_path = QLabel('No config file selected')
self.wSpn_build = QBusyIndicatorGoodBad(fixed_size=(50, 50))

self.wBtn_refresh_ports = QPushButton('Refresh ports')
self.wCombo_serial_port = QComboBox()
self.wCombo_serial_port.setPlaceholderText('No port selected')
self.wBtn_upload_fw = QPushButton('Upload FW')
self.wBtn_upload_fw.setEnabled(False)
self.wSpn_upload = QBusyIndicatorGoodBad(fixed_size=(50, 50))

self.wChk_upload_stats = QCheckBox('Upload anonymous statistics?',
toolTip='After a successful firmware update, upload anonymous firmware details to the OAT devs')
self.wBtn_what_stats = QPushButton('What will be uploaded?')

self.logText = QPlainTextEdit()
self.logText.setLineWrapMode(QPlainTextEdit.NoWrap)
self.logText.setReadOnly(True)
log_font = QFont('this-font-does-not-exist')
log_font.setStyleHint(QFont.Monospace) # Let Qt pick a monospace font
self.logText.setFont(log_font)

# layout
self.g_layout = QGridLayout()

layout_arr = [
[self.wMsg_fw_version, self.wCombo_fw_version, self.wBtn_download_fw, self.wSpn_download],
[self.wMsg_pio_env, self.wCombo_pio_env, self.wBtn_select_local_config, self.wBtn_build_fw],
[self.wMsg_config_path, None, None, self.wSpn_build],
[self.wBtn_refresh_ports, self.wCombo_serial_port, self.wBtn_upload_fw, self.wSpn_upload],
[None, None, self.wChk_upload_stats, None],
[None, None, self.wBtn_what_stats, None],
]
for y, row_arr in enumerate(layout_arr):
for x, widget in enumerate(row_arr):
rowSpan = 1
colSpan = 1
while x + colSpan < len(row_arr) and row_arr[x + colSpan] is None:
# next widget is None, expand column
colSpan += 1
if widget is not None:
self.g_layout.addWidget(widget, y, x, rowSpan, colSpan)
self.g_layout.setAlignment(Qt.AlignTop)

# log window will take up the entire right side
self.h_layout = QHBoxLayout(self)
self.h_layout.addLayout(self.g_layout)
self.h_layout.addWidget(self.logText)

# signals
log_object.log_signal.connect(self.logText.appendHtml)

# business logic will connect signals as well
self.logic = BusinessLogic(self)
25 changes: 20 additions & 5 deletions OATFWGUI/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,14 @@
from typing import Dict, Tuple, Optional

import semver
from PySide6.QtCore import Slot, Qt
from PySide6.QtCore import Slot, Qt, QFile
from PySide6.QtWidgets import QApplication, QMainWindow, QStatusBar, QLabel
from PySide6.QtGui import QAction, QActionGroup
from PySide6.QtUiTools import QUiLoader

from _version import __version__
from log_utils import LogObject, setup_logging
from gui_logic import MainWidget
from gui_logic import BusinessLogic
from platform_check import get_platform, PlatformEnum
from external_processes import external_processes, add_external_process, get_install_dir
from anon_usage_data import create_anon_stats
Expand Down Expand Up @@ -191,10 +192,24 @@ def __init__(self):
self.bug_hyperlink.setOpenExternalLinks(True)
self.status_bar.addPermanentWidget(self.bug_hyperlink) # addPermanentWidget == right side

log.debug('Creating main widget')
self.main_widget = MainWidget(l_o)
# Load the main widget from the .ui file
# Need to tell the UI loader where our custom widgets are
os.environ['PYSIDE_DESIGNER_PLUGINS'] = str(Path(get_install_dir(), 'OATFWGUI'))

main_widget_ui_path = Path(get_install_dir(), 'OATFWGUI', 'main_widget.ui')
log.debug(f'Loading main widget UI from {main_widget_ui_path}')
ui_file = QFile(main_widget_ui_path)
ui_file.open(QFile.ReadOnly)
loader = QUiLoader()
self.main_widget = loader.load(ui_file)
ui_file.close()
self.setCentralWidget(self.main_widget)

# signals
l_o.log_signal.connect(self.main_widget.logText.appendHtml)
# business logic will connect signals as well
self.logic = BusinessLogic(self.main_widget)

def add_log_menu_helper(self, name: str, cb_fn, is_checked=False):
action = QAction(name)
action.setCheckable(True)
Expand Down Expand Up @@ -266,7 +281,7 @@ def main():
else:
log.debug('NOT executing app')
log.debug('Testing anonymous statistics creation')
anon_stats = create_anon_stats(widget.main_widget.logic.logic_state)
anon_stats = create_anon_stats(widget.logic.logic_state)
log.debug(f'Statistics: {json.dumps(anon_stats)}')
# Wait a bit before exiting, prevents Qt complaining about deleted objects
time.sleep(1.0)
Expand Down
183 changes: 183 additions & 0 deletions OATFWGUI/main_widget.ui
Original file line number Diff line number Diff line change
@@ -0,0 +1,183 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>TopLevelWidget</class>
<widget class="QWidget" name="TopLevelWidget">
<property name="enabled">
<bool>true</bool>
</property>
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>766</width>
<height>513</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QGridLayout" name="gridLayout_2">
<item row="0" column="0">
<layout class="QHBoxLayout" name="horizontalLayout">
<property name="sizeConstraint">
<enum>QLayout::SetMaximumSize</enum>
</property>
<item>
<layout class="QGridLayout" name="gridLayout">
<item row="1" column="3">
<widget class="QPushButton" name="wBtn_select_local_config">
<property name="text">
<string>Select local config file</string>
</property>
</widget>
</item>
<item row="5" column="3">
<widget class="QPushButton" name="wBtn_what_stats">
<property name="text">
<string>What will be uploaded?</string>
</property>
</widget>
</item>
<item row="3" column="3">
<widget class="QPushButton" name="wBtn_upload_fw">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>Upload FW</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QComboBox" name="wCombo_serial_port">
<property name="placeholderText">
<string>No port selected</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QComboBox" name="wCombo_pio_env">
<property name="placeholderText">
<string>No FW downloaded yet...</string>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="wMsg_fw_version">
<property name="text">
<string>Select firmware version:</string>
</property>
</widget>
</item>
<item row="0" column="3">
<widget class="QPushButton" name="wBtn_download_fw">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>Download</string>
</property>
</widget>
</item>
<item row="4" column="3">
<widget class="QCheckBox" name="wChk_upload_stats">
<property name="toolTip">
<string>After a successful firmware update, upload anonymous firmware details to the OAT devs</string>
</property>
<property name="text">
<string>Upload anonymous statistics?</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="wMsg_pio_env">
<property name="text">
<string>Select board:</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QComboBox" name="wCombo_fw_version">
<property name="placeholderText">
<string>Grabbing FW Versions...</string>
</property>
</widget>
</item>
<item row="6" column="3">
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item row="2" column="4">
<widget class="QBusyIndicatorGoodBad" name="wSpn_build"/>
</item>
<item row="1" column="4">
<widget class="QPushButton" name="wBtn_build_fw">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>Build FW</string>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QPushButton" name="wBtn_refresh_ports">
<property name="text">
<string>Refresh ports</string>
</property>
</widget>
</item>
<item row="3" column="4">
<widget class="QBusyIndicatorGoodBad" name="wSpn_upload"/>
</item>
<item row="0" column="4">
<widget class="QBusyIndicatorGoodBad" name="wSpn_download"/>
</item>
<item row="2" column="0" colspan="4">
<widget class="QLabel" name="wMsg_config_path">
<property name="text">
<string>No config file selected</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QPlainTextEdit" name="logText">
<property name="font">
<font>
<family>Monospace</family>
</font>
</property>
<property name="lineWrapMode">
<enum>QPlainTextEdit::NoWrap</enum>
</property>
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>QBusyIndicatorGoodBad</class>
<extends>QWidget</extends>
<header>qbusyindicatorgoodbad</header>
<container>1</container>
</customwidget>
</customwidgets>
<resources/>
<connections/>
</ui>
Loading

0 comments on commit f940e67

Please sign in to comment.