Skip to content

Commit efd158c

Browse files
author
Mehmet Aksoy
committed
Updates UI and action logic for version 1.7.0
Refactors the UI action logic into a separate module for better organization. Improves the UI by collapsing configuration options in basic view and restoring them in advanced view, preserving layout and widget properties. Updates the about dialog and help dialog to reflect the new version number (1.7.0) and legal information. Enhances UI with a more compact menu bar style and updates button labels. Fixes #13 - update versioning across application
1 parent 1784fe4 commit efd158c

File tree

6 files changed

+375
-181
lines changed

6 files changed

+375
-181
lines changed

main.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,12 @@
77
__copyright__ = "Copyright 2023, The AFCOM Project"
88
__credits__ = ["Mehmet Cagri Aksoy"]
99
__license__ = "JGPLv3"
10-
__version__ = "2024.11"
10+
__version__ = "1.7.0"
1111
__maintainer__ = "Mehmet Cagri Aksoy"
1212
__status__ = "Production"
1313

1414
from src.ui_main import start_ui_design
1515

1616
if __name__ == "__main__":
17-
print("AFCOM - Serial Communication GUI Program")
18-
start_ui_design()
17+
#print("AFCOM - Serial Communication GUI Program")
18+
start_ui_design()

src/action_ui.py

Lines changed: 111 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
except ImportError:
2525
requests = None
2626

27-
CURRENT_VERSION = "v1.6.0"
27+
CURRENT_VERSION = "v1.7.0"
2828

2929
def action_save_as(ui):
3030
"""
@@ -52,32 +52,124 @@ def action_save(ui):
5252
action_save_as(ui)
5353

5454
def basic_view_enabled(ui):
55-
""" Hide specific layouts in the UI for basic view """
56-
# Hide all widgets in the verticalLayout_config
57-
for i in range(ui.verticalLayout_config.count()):
58-
widget = ui.verticalLayout_config.itemAt(i).widget()
55+
""" Hide specific layouts in the UI for basic view and collapse the
56+
reserved space so the window side doesn't leave an empty gap.
57+
58+
This saves the layouts' margins/spacing and widgets' maximum heights the
59+
first time it's called, then sets margins and spacing to zero and forces
60+
widgets to zero height so the layout collapses. The values are restored
61+
by `advanced_view_enabled`.
62+
"""
63+
# Short aliases
64+
v_layout = ui.verticalLayout_config
65+
f_layout = ui.formLayout_config
66+
67+
# Save original layout settings and widget max heights once
68+
if not hasattr(ui, '_basic_view_saved'):
69+
ui._basic_view_saved = {
70+
'v_margins': v_layout.contentsMargins(),
71+
'v_spacing': v_layout.spacing(),
72+
'f_margins': f_layout.contentsMargins(),
73+
'f_spacing': f_layout.spacing(),
74+
'widgets_maxheight': {}
75+
}
76+
77+
# Collapse layout spacing and margins to remove empty space
78+
try:
79+
v_layout.setContentsMargins(0, 0, 0, 0)
80+
v_layout.setSpacing(0)
81+
except Exception:
82+
pass
83+
try:
84+
f_layout.setContentsMargins(0, 0, 0, 0)
85+
f_layout.setSpacing(0)
86+
except Exception:
87+
pass
88+
89+
# Hide and shrink widgets inside the layouts
90+
for i in range(v_layout.count()):
91+
item = v_layout.itemAt(i)
92+
widget = item.widget() if item else None
5993
if widget:
94+
# store previous maximum height to restore later
95+
ui._basic_view_saved['widgets_maxheight'][str(id(widget))] = widget.maximumHeight()
96+
widget.setMaximumHeight(0)
6097
widget.setVisible(False)
6198

62-
# Optionally, hide all widgets in the formLayout_config
63-
for i in range(ui.formLayout_config.count()):
64-
widget = ui.formLayout_config.itemAt(i).widget()
99+
for i in range(f_layout.count()):
100+
item = f_layout.itemAt(i)
101+
widget = item.widget() if item else None
65102
if widget:
103+
ui._basic_view_saved['widgets_maxheight'][str(id(widget))] = widget.maximumHeight()
104+
widget.setMaximumHeight(0)
66105
widget.setVisible(False)
67106

68107
def advanced_view_enabled(ui):
69-
""" Show specific layouts in the UI for advanced view """
70-
# Show all widgets in the verticalLayout_config
71-
for i in range(ui.verticalLayout_config.count()):
72-
widget = ui.verticalLayout_config.itemAt(i).widget()
73-
if widget:
74-
widget.setVisible(True)
108+
""" Show specific layouts in the UI for advanced view and restore the
109+
layout margins/spacing and widgets' sizes saved by `basic_view_enabled`.
110+
"""
111+
v_layout = ui.verticalLayout_config
112+
f_layout = ui.formLayout_config
75113

76-
# Optionally, show all widgets in the formLayout_config
77-
for i in range(ui.formLayout_config.count()):
78-
widget = ui.formLayout_config.itemAt(i).widget()
79-
if widget:
80-
widget.setVisible(True)
114+
# Restore layout margins/spacing if we saved them earlier
115+
if hasattr(ui, '_basic_view_saved'):
116+
saved = ui._basic_view_saved
117+
try:
118+
m = saved.get('v_margins')
119+
if m is not None:
120+
v_layout.setContentsMargins(m.left(), m.top(), m.right(), m.bottom())
121+
v_layout.setSpacing(saved.get('v_spacing', v_layout.spacing()))
122+
except Exception:
123+
pass
124+
try:
125+
m = saved.get('f_margins')
126+
if m is not None:
127+
f_layout.setContentsMargins(m.left(), m.top(), m.right(), m.bottom())
128+
f_layout.setSpacing(saved.get('f_spacing', f_layout.spacing()))
129+
except Exception:
130+
pass
131+
132+
# Restore widgets' maximum heights and visibility
133+
for i in range(v_layout.count()):
134+
item = v_layout.itemAt(i)
135+
widget = item.widget() if item else None
136+
if widget:
137+
key = str(id(widget))
138+
prev_h = saved['widgets_maxheight'].get(key)
139+
if prev_h is not None:
140+
widget.setMaximumHeight(prev_h)
141+
else:
142+
widget.setMaximumHeight(16777215)
143+
widget.setVisible(True)
144+
145+
for i in range(f_layout.count()):
146+
item = f_layout.itemAt(i)
147+
widget = item.widget() if item else None
148+
if widget:
149+
key = str(id(widget))
150+
prev_h = saved['widgets_maxheight'].get(key)
151+
if prev_h is not None:
152+
widget.setMaximumHeight(prev_h)
153+
else:
154+
widget.setMaximumHeight(16777215)
155+
widget.setVisible(True)
156+
# clear saved state
157+
delattr(ui, '_basic_view_saved') if hasattr(ui, '_basic_view_saved') else None
158+
else:
159+
# Fallback: simply show widgets
160+
for i in range(v_layout.count()):
161+
item = v_layout.itemAt(i)
162+
widget = item.widget() if item else None
163+
if widget:
164+
widget.setVisible(True)
165+
widget.setMaximumHeight(16777215)
166+
167+
for i in range(f_layout.count()):
168+
item = f_layout.itemAt(i)
169+
widget = item.widget() if item else None
170+
if widget:
171+
widget.setVisible(True)
172+
widget.setMaximumHeight(16777215)
81173

82174
def clear_buffer(ui):
83175
""" Clear the buffer """

src/ui_main.py

Lines changed: 40 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
__author__ = 'Mehmet Cagri Aksoy - github.com/mcagriaksoy'
88
__annotations__ = 'AFCOM - Serial Communication GUI Program'
9-
__version__ = '2025 - 1.4.0.0'
9+
__version__ = '1.7.0'
1010
__license__ = 'JGPLv3'
1111
__status__ = 'Development'
1212

@@ -161,10 +161,46 @@ def __init__(self):
161161
loader = QUiLoader()
162162
self.ui = loader.load(ui_file)
163163
self.ui.show()
164+
# Try to make the menu bar more compact (smaller height and padding).
165+
# Some platforms/skins make the menubar very tall; force a tighter style.
166+
try:
167+
m = getattr(self.ui, 'menuBar', None)
168+
if callable(m):
169+
mb = m()
170+
else:
171+
mb = m
172+
if mb is not None:
173+
# Avoid forcing a fixed height (which can trigger the overflow '>>').
174+
# Reduce font size and item padding so the menu is visually smaller
175+
# but items remain visible.
176+
mb.setStyleSheet(
177+
"QMenuBar { font-size: 8pt; }")
178+
mb.setStyleSheet(mb.styleSheet() +
179+
"QMenuBar::item { padding: 2px 8px; margin: 0px; }")
180+
mb.updateGeometry()
181+
except Exception:
182+
pass
164183
else: # PROGRAM_TYPE_RELEASE
165184
print("UI File Found!")
166185
self.ui = Ui_main_window()
167186
self.ui.setupUi(self)
187+
# Apply the same compact menubar style in release mode (setupUi created the menubar
188+
# on the QMainWindow instance `self`). Use safe checks so this doesn't fail.
189+
try:
190+
m = getattr(self, 'menuBar', None)
191+
if callable(m):
192+
mb = m()
193+
else:
194+
mb = m
195+
if mb is not None:
196+
# Avoid fixed height to prevent the menu overflow chevron (>>).
197+
mb.setStyleSheet(
198+
"QMenuBar { font-size: 9pt; }")
199+
mb.setStyleSheet(mb.styleSheet() +
200+
"QMenuBar::item { padding: 2px 8px; margin: 0px; }")
201+
mb.updateGeometry()
202+
except Exception:
203+
pass
168204

169205
if (is_windows_dark_mode(self)):
170206
print("Windows Dark Mode is enabled!")
@@ -213,7 +249,7 @@ def __init__(self):
213249
self.ui.actionHelp_2.triggered.connect(action_ui.show_help_dialog)
214250
self.ui.actionPreferences.triggered.connect(action_ui.show_settings_dialog)
215251

216-
# Night mode button event
252+
# Dark mode button event
217253
self.night_mode_enabled = False
218254
if hasattr(self.ui, 'nightMode_Button'):
219255
self.ui.nightMode_Button.clicked.connect(self.enable_night_mode)
@@ -461,7 +497,7 @@ def read_data_from_thread(self, serial_data):
461497
self.on_stop_button_clicked()
462498
else:
463499
html_data = ansi_to_html(serial_data.replace('\r\n', '<br>').replace('\n', '<br>'))
464-
# Adjust text color for day/night mode
500+
# Adjust text color for day/Dark mode
465501
if hasattr(self, 'night_mode_enabled') and self.night_mode_enabled:
466502
# Night mode: convert black text to white
467503
html_data = html_data.replace('color:black;', 'color:white;')
@@ -509,7 +545,7 @@ def enable_night_mode(self):
509545
else:
510546
self.ui.data_textEdit.setStyleSheet("")
511547
if hasattr(self.ui.nightMode_Button, 'setText'):
512-
self.ui.nightMode_Button.setText("Night Mode")
548+
self.ui.nightMode_Button.setText("Dark Mode")
513549
self.night_mode_enabled = False
514550

515551
def closeEvent(self, event):

ui/help.ui

Lines changed: 57 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,34 @@
66
<rect>
77
<x>0</x>
88
<y>0</y>
9-
<width>765</width>
10-
<height>397</height>
9+
<width>768</width>
10+
<height>378</height>
1111
</rect>
1212
</property>
13+
<property name="sizePolicy">
14+
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
15+
<horstretch>0</horstretch>
16+
<verstretch>0</verstretch>
17+
</sizepolicy>
18+
</property>
19+
<property name="minimumSize">
20+
<size>
21+
<width>768</width>
22+
<height>378</height>
23+
</size>
24+
</property>
25+
<property name="maximumSize">
26+
<size>
27+
<width>768</width>
28+
<height>378</height>
29+
</size>
30+
</property>
1331
<property name="windowTitle">
1432
<string>Dialog</string>
1533
</property>
34+
<property name="windowIcon">
35+
<iconset theme="QIcon::ThemeIcon::DialogQuestion"/>
36+
</property>
1637
<widget class="QTextEdit" name="textEdit_3">
1738
<property name="geometry">
1839
<rect>
@@ -22,6 +43,27 @@
2243
<height>341</height>
2344
</rect>
2445
</property>
46+
<property name="sizePolicy">
47+
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
48+
<horstretch>0</horstretch>
49+
<verstretch>0</verstretch>
50+
</sizepolicy>
51+
</property>
52+
<property name="minimumSize">
53+
<size>
54+
<width>751</width>
55+
<height>341</height>
56+
</size>
57+
</property>
58+
<property name="maximumSize">
59+
<size>
60+
<width>751</width>
61+
<height>341</height>
62+
</size>
63+
</property>
64+
<property name="frameShape">
65+
<enum>QFrame::Shape::NoFrame</enum>
66+
</property>
2567
<property name="undoRedoEnabled">
2668
<bool>false</bool>
2769
</property>
@@ -30,16 +72,19 @@
3072
</property>
3173
<property name="html">
3274
<string>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
33-
&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
75+
&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;meta charset=&quot;utf-8&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
3476
p, li { white-space: pre-wrap; }
35-
&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;&quot;&gt;
36-
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Segoe UI'; font-size:12pt; font-weight:696;&quot;&gt;Information&lt;/span&gt;&lt;/p&gt;
37-
&lt;p align=&quot;justify&quot; style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Segoe UI'; font-size:12pt;&quot;&gt;The AFCOM (also known as Serial communication GUI program) tool is a software application that allows users to send and receive data via the serial port (COM port) of their computer. The tool can be used for various purposes, such as testing, debugging, or communicating with other devices that use the serial protocol. &lt;/span&gt;&lt;/p&gt;
38-
&lt;p align=&quot;justify&quot; style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Segoe UI'; font-size:12pt; font-weight:696;&quot;&gt;Features&lt;/span&gt;&lt;span style=&quot; font-family:'Segoe UI'; font-size:12pt;&quot;&gt; &lt;/span&gt;&lt;/p&gt;
39-
&lt;p align=&quot;justify&quot; style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Segoe UI'; font-size:12pt;&quot;&gt;The COM port tool has the following features: It supports multiple COM ports and can detect the available ports automatically. It allows users to configure the parameters of the serial communication, such as baud rate. It provides a user-friendly interface that shows the transmitted and received data in hexadecimal, decimal, ASCII, or binary formats. It allows users to save and load the data to and from files.&lt;/span&gt;&lt;/p&gt;
40-
&lt;p align=&quot;justify&quot; style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Segoe UI'; font-size:12pt; font-weight:696;&quot;&gt;Legal Information&lt;/span&gt;&lt;/p&gt;
41-
&lt;p align=&quot;justify&quot; style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Segoe UI'; font-size:12pt;&quot;&gt;This application incorporates Qt for Python (PySide), which is licensed under the GNU Lesser General Public License version 3 (LGPLv3). By using this software, you agree to comply with the terms of the LGPLv3 license. For more information about Qt for Python, visit https://www.qt.io/qt-for-python. A copy of the LGPLv3 license is included with this application.&lt;/span&gt;&lt;/p&gt;
42-
&lt;p align=&quot;justify&quot; style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Segoe UI'; font-size:9pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
77+
hr { height: 1px; border-width: 0; }
78+
li.unchecked::marker { content: &quot;\2610&quot;; }
79+
li.checked::marker { content: &quot;\2612&quot;; }
80+
&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'Segoe UI'; font-size:9pt; font-weight:400; font-style:normal;&quot;&gt;
81+
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:12pt; font-weight:696;&quot;&gt;Information&lt;/span&gt;&lt;/p&gt;
82+
&lt;p align=&quot;justify&quot; style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:12pt;&quot;&gt;The AFCOM (also known as Serial communication GUI program) tool is a software application that allows users to send and receive data via the serial port (COM port) of their computer. The tool can be used for various purposes, such as testing, debugging, or communicating with other devices that use the serial protocol. &lt;/span&gt;&lt;/p&gt;
83+
&lt;p align=&quot;justify&quot; style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:12pt; font-weight:696;&quot;&gt;Features&lt;/span&gt;&lt;span style=&quot; font-size:12pt;&quot;&gt; &lt;/span&gt;&lt;/p&gt;
84+
&lt;p align=&quot;justify&quot; style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:12pt;&quot;&gt;The COM port tool has the following features: It supports multiple COM ports and can detect the available ports automatically. It allows users to configure the parameters of the serial communication, such as baud rate. It provides a user-friendly interface that shows the transmitted and received data in hexadecimal, decimal, ASCII, or binary formats. It allows users to save and load the data to and from files.&lt;/span&gt;&lt;/p&gt;
85+
&lt;p align=&quot;justify&quot; style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:12pt; font-weight:696;&quot;&gt;Legal Information&lt;/span&gt;&lt;/p&gt;
86+
&lt;p align=&quot;justify&quot; style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:12pt;&quot;&gt;This application incorporates Qt for Python (PySide), which is licensed under the GNU Lesser General Public License version 3 (LGPLv3). By using this software, you agree to comply with the terms of the LGPLv3 license. For more information about Qt for Python, visit https://www.qt.io/qt-for-python. A copy of the LGPLv3 license is included with this application.&lt;/span&gt;&lt;/p&gt;
87+
&lt;p align=&quot;justify&quot; style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
4388
</property>
4489
<property name="acceptRichText">
4590
<bool>false</bool>
@@ -55,7 +100,7 @@ p, li { white-space: pre-wrap; }
55100
</rect>
56101
</property>
57102
<property name="text">
58-
<string>AFCOM Client v1.6.0 (C) 2020 - 2025 Author: Mehmet Cagri Aksoy github.com/mcagriaksoy</string>
103+
<string>AFCOM Client v1.7.0 (C) 2020 - 2025 Author: Mehmet Cagri Aksoy github.com/mcagriaksoy</string>
59104
</property>
60105
</widget>
61106
</widget>

0 commit comments

Comments
 (0)