Skip to content

Commit 25e8e0e

Browse files
committed
update config panels grid
1 parent 2a97635 commit 25e8e0e

12 files changed

Lines changed: 237 additions & 174 deletions

src/pygpsclient/dynamic_config_frame.py

Lines changed: 35 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -227,7 +227,7 @@ def _body(self):
227227
command=self._on_refresh,
228228
font=self.__app.font_md,
229229
)
230-
self._lbl_command = Label(self, text="", width=30, anchor=W)
230+
self._lbl_command = Label(self, text="", anchor=W)
231231
self._frm_container = Frame(self)
232232
self._can_container = Canvas(self._frm_container)
233233
self._frm_attrs = Frame(self._can_container)
@@ -248,31 +248,45 @@ def _do_layout(self):
248248
Layout widgets.
249249
"""
250250

251-
self._lbl_cfg_dyn.grid(column=0, row=0, columnspan=4, padx=3, sticky=EW)
251+
self._lbl_cfg_dyn.grid(column=0, row=0, columnspan=3, padx=3, pady=3, sticky=EW)
252252
self._lbx_cfg_cmd.grid(
253-
column=0, row=1, columnspan=2, rowspan=6, padx=3, pady=3, sticky=EW
253+
column=0, row=1, columnspan=1, rowspan=10, padx=3, pady=3, sticky=EW
254+
)
255+
self._scr_cfg_cmd.grid(column=1, row=1, rowspan=10, sticky=(N, S, W))
256+
self._btn_send_command.grid(
257+
column=2, row=1, ipadx=3, ipady=3, padx=3, pady=3, sticky=W
258+
)
259+
self._lbl_send_command.grid(
260+
column=2, row=2, ipadx=3, ipady=3, padx=3, pady=3, sticky=W
261+
)
262+
self._btn_refresh.grid(
263+
column=2, row=3, ipadx=3, ipady=3, padx=3, pady=3, sticky=W
264+
)
265+
self._lbl_command.grid(
266+
column=0, row=11, columnspan=3, padx=3, pady=3, sticky=EW
254267
)
255-
self._scr_cfg_cmd.grid(column=1, row=1, rowspan=6, sticky=(N, S, E))
256-
self._btn_send_command.grid(column=3, row=1, ipadx=3, ipady=3, sticky=W)
257-
self._lbl_send_command.grid(column=3, row=2, ipadx=3, ipady=3, sticky=W)
258-
self._btn_refresh.grid(column=3, row=3, ipadx=3, ipady=3, sticky=W)
259-
self._lbl_command.grid(column=0, row=7, columnspan=4, padx=3, sticky=EW)
260268
self._frm_container.grid(
261-
column=0, row=8, columnspan=4, rowspan=15, padx=3, sticky=NSEW
269+
column=0,
270+
row=12,
271+
columnspan=3,
272+
rowspan=15,
273+
padx=3,
274+
pady=3,
275+
sticky=NSEW,
262276
)
263277
self._can_container.grid(
264-
column=0, row=0, columnspan=3, rowspan=15, padx=3, sticky=NSEW
278+
column=0,
279+
row=0,
280+
columnspan=3,
281+
rowspan=15,
282+
padx=3,
283+
pady=3,
284+
sticky=NSEW,
265285
)
266-
self._scr_container_ver.grid(column=3, row=0, rowspan=15, sticky=(N, S, E))
286+
self._scr_container_ver.grid(column=3, row=0, rowspan=15, sticky=(N, S, W))
267287
self._scr_container_hor.grid(
268-
column=0, row=15, columnspan=4, rowspan=15, sticky=EW
288+
column=0, row=15, columnspan=3, rowspan=15, sticky=EW
269289
)
270-
271-
cols, rows = self.grid_size()
272-
for i in range(cols):
273-
self.grid_columnconfigure(i, weight=1)
274-
for i in range(rows):
275-
self.grid_rowconfigure(i, weight=1)
276290
self.option_add("*Font", self.__app.font_sm)
277291

278292
def _attach_events(self):
@@ -535,13 +549,13 @@ def _clear_widgets(self):
535549
wdg.destroy()
536550
wdg = None
537551
Label(self._frm_attrs, text="Attribute", width=12, anchor=W).grid(
538-
column=0, row=0, padx=3, sticky=(W)
552+
column=0, row=0, padx=3, sticky=W
539553
)
540554
Label(self._frm_attrs, text="Value", width=20, anchor=W).grid(
541-
column=1, row=0, padx=3, sticky=(W)
555+
column=1, row=0, padx=3, sticky=W
542556
)
543557
Label(self._frm_attrs, text="Type", width=5, anchor=W).grid(
544-
column=2, row=0, padx=3, sticky=(W)
558+
column=2, row=0, padx=3, sticky=W
545559
)
546560

547561
def _add_widgets(self, pdict: dict, row: int, index: int) -> int:

src/pygpsclient/globals.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -271,6 +271,8 @@
271271
VALDMY = 8
272272
VALLEN = 9
273273
VALBOOL = 10
274+
VALREGEX = 11
275+
VALCUSTOM = 12
274276
WAYPOINT = "waypoint"
275277
WIDGETU1 = (200, 200) # small widget size
276278
WIDGETU2 = (300, 200) # medium widget size

src/pygpsclient/hardware_info_frame.py

Lines changed: 16 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
:license: BSD 3-Clause
1111
"""
1212

13-
from tkinter import Frame, Label, W
13+
from tkinter import EW, Frame, Label, W
1414

1515
from PIL import Image, ImageTk
1616

@@ -62,38 +62,31 @@ def _body(self):
6262
"""
6363

6464
self._lbl_hwverl = Label(self, text="Hardware")
65-
self._lbl_hwver = Label(self)
65+
self._lbl_hwver = Label(self, anchor=W)
6666
self._lbl_swverl = Label(self, text="Software")
67-
self._lbl_swver = Label(self)
67+
self._lbl_swver = Label(self, anchor=W)
6868
self._lbl_fwverl = Label(self, text="Firmware")
69-
self._lbl_fwver = Label(self)
69+
self._lbl_fwver = Label(self, anchor=W)
7070
self._lbl_romverl = Label(self, text="Protocol")
71-
self._lbl_romver = Label(self)
71+
self._lbl_romver = Label(self, anchor=W)
7272
self._lbl_gnssl = Label(self, text="GNSS/AS")
73-
self._lbl_gnss = Label(self)
73+
self._lbl_gnss = Label(self, anchor=W)
7474

7575
def _do_layout(self):
7676
"""
7777
Layout widgets.
7878
"""
7979

80-
self._lbl_hwverl.grid(column=0, row=0, padx=2, sticky=W)
81-
self._lbl_hwver.grid(column=1, row=0, columnspan=2, padx=2, sticky=W)
82-
self._lbl_swverl.grid(column=3, row=0, padx=2, sticky=W)
83-
self._lbl_swver.grid(column=4, row=0, columnspan=2, padx=2, sticky=W)
84-
self._lbl_fwverl.grid(column=0, row=1, padx=2, sticky=W)
85-
self._lbl_fwver.grid(column=1, row=1, columnspan=2, padx=2, sticky=W)
86-
self._lbl_romverl.grid(column=3, row=1, padx=2, sticky=W)
87-
self._lbl_romver.grid(column=4, row=1, columnspan=2, padx=2, sticky=W)
88-
self._lbl_gnssl.grid(column=0, row=2, columnspan=1, padx=2, sticky=W)
89-
self._lbl_gnss.grid(column=1, row=2, columnspan=4, padx=2, sticky=W)
90-
91-
cols, rows = self.grid_size()
92-
for i in range(cols):
93-
self.grid_columnconfigure(i, weight=1)
94-
for i in range(rows):
95-
self.grid_rowconfigure(i, weight=1)
96-
# self.option_add("*Font", self.__app.font_sm)
80+
self._lbl_hwverl.grid(column=0, row=0, padx=3, pady=3, sticky=W)
81+
self._lbl_hwver.grid(column=1, row=0, columnspan=2, padx=3, pady=3, sticky=EW)
82+
self._lbl_swverl.grid(column=3, row=0, padx=3, pady=3, sticky=W)
83+
self._lbl_swver.grid(column=4, row=0, columnspan=2, padx=3, pady=3, sticky=EW)
84+
self._lbl_fwverl.grid(column=0, row=1, padx=3, pady=3, sticky=W)
85+
self._lbl_fwver.grid(column=1, row=1, columnspan=2, padx=3, pady=3, sticky=EW)
86+
self._lbl_romverl.grid(column=3, row=1, padx=3, pady=3, sticky=W)
87+
self._lbl_romver.grid(column=4, row=1, columnspan=2, padx=3, pady=3, sticky=EW)
88+
self._lbl_gnssl.grid(column=0, row=2, columnspan=1, padx=3, pady=3, sticky=W)
89+
self._lbl_gnss.grid(column=1, row=2, columnspan=4, padx=3, pady=3, sticky=EW)
9790

9891
def _attach_events(self):
9992
"""

src/pygpsclient/helpers.py

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@
3838
Tk,
3939
font,
4040
)
41-
from types import NoneType
41+
from types import FunctionType, NoneType
4242
from typing import Any, Literal
4343

4444
from pygnssutils import version as PGVERSION
@@ -88,13 +88,15 @@
8888
UMK,
8989
VALBLANK,
9090
VALBOOL,
91+
VALCUSTOM,
9192
VALDMY,
9293
VALFLOAT,
9394
VALHEX,
9495
VALINT,
9596
VALLEN,
9697
VALNONBLANK,
9798
VALNONSPACE,
99+
VALREGEX,
98100
VALURL,
99101
Area,
100102
Point,
@@ -117,20 +119,32 @@
117119
}
118120

119121

120-
def validate(self: Entry, valmode: int, low=MINFLOAT, high=MAXFLOAT) -> bool:
122+
def validate(
123+
self: Entry,
124+
valmode: int,
125+
low: int | float = MINFLOAT,
126+
high: int | float = MAXFLOAT,
127+
regex: str | NoneType = None,
128+
func: FunctionType | NoneType = None,
129+
args: tuple = (),
130+
) -> bool:
121131
"""
122132
Extends tkinter.Entry class to add parameterised validation
123133
and error highlighting.
124134
125135
:param Entry self: tkinter entry widget instance
126136
:param int valmode: int representing validation type - can be OR'd
127-
:param object low: optional min value
128-
:param object high: optional max value
137+
:param int | float low: optional min value
138+
:param int | float high: optional max value
139+
:param str | NoneType regex: regex expression
140+
:param FunctionType | NoneType func: custom validation function
141+
:param Any args: optional function arguments
142+
129143
:return: True/False
130144
:rtype: bool
131145
"""
132146

133-
valid = True
147+
valid = False
134148
try:
135149
val = self.get()
136150
if valmode == VALBLANK and val == "":
@@ -151,10 +165,16 @@ def validate(self: Entry, valmode: int, low=MINFLOAT, high=MAXFLOAT) -> bool:
151165
valid = val != "" and not val.isspace()
152166
elif valmode == VALHEX: # valid hexadecimal
153167
bytes.fromhex(val)
168+
valid = True
154169
elif valmode == VALDMY: # valid date YYYYMMDD
155170
datetime(int(val[0:4]), int(val[4:6]), int(val[6:8]))
171+
valid = True
156172
elif valmode == VALLEN: # valid length
157173
valid = low <= len(val) <= high
174+
elif valmode == VALREGEX and regex is not None: # matches given regex
175+
valid = re.compile(regex).search(val) is not None
176+
elif valmode == VALCUSTOM and func is not None: # custom validation function
177+
valid = func(val, *args)
158178
except ValueError:
159179
valid = False
160180

src/pygpsclient/nmea_preset_frame.py

Lines changed: 11 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -41,9 +41,9 @@
4141
ICON_WARNING,
4242
NMEA_PRESET,
4343
OKCOL,
44-
VALNONBLANK,
44+
VALREGEX,
4545
)
46-
from pygpsclient.helpers import validate
46+
from pygpsclient.helpers import validate # pylint: disable=unused-import
4747
from pygpsclient.strings import (
4848
CONFIRM,
4949
DLGACTION,
@@ -54,6 +54,7 @@
5454
CANCELLED = 0
5555
CONFIRMED = 1
5656
NOMINAL = 2
57+
NMEAPRESETREGEX = r"^(?:(?:[^;]+;){3}\s?[0-2];?)+$"
5758

5859

5960
class NMEA_PRESET_Frame(Frame):
@@ -136,23 +137,15 @@ def _do_layout(self):
136137
"""
137138

138139
self._lbl_command.grid(column=0, row=0, padx=3, sticky=W)
139-
self._ent_command.grid(column=1, row=0, columnspan=5, padx=3, sticky=EW)
140-
self._lbl_presets.grid(column=0, row=1, columnspan=6, padx=3, sticky=EW)
140+
self._ent_command.grid(column=1, row=0, columnspan=3, padx=3, sticky=EW)
141+
self._lbl_presets.grid(column=0, row=1, columnspan=4, padx=3, sticky=EW)
141142
self._lbx_preset.grid(
142-
column=0, row=2, columnspan=3, rowspan=20, padx=3, pady=3, sticky=EW
143+
column=0, row=2, columnspan=2, rowspan=20, padx=3, pady=3, sticky=EW
143144
)
144145
self._scr_presetv.grid(column=2, row=2, rowspan=20, sticky=(N, S, E))
145-
self._scr_preseth.grid(column=0, row=22, columnspan=3, sticky=EW)
146-
self._btn_send_command.grid(column=3, row=2, padx=3, ipadx=3, ipady=3, sticky=E)
147-
self._lbl_send_command.grid(
148-
column=3, row=3, padx=3, ipadx=3, ipady=3, sticky=EW
149-
)
150-
151-
cols, rows = self.grid_size()
152-
for i in range(cols):
153-
self.grid_columnconfigure(i, weight=1)
154-
for i in range(rows):
155-
self.grid_rowconfigure(i, weight=1)
146+
self._scr_preseth.grid(column=0, row=22, columnspan=2, sticky=EW)
147+
self._btn_send_command.grid(column=3, row=2, padx=3, ipadx=3, ipady=3, sticky=W)
148+
self._lbl_send_command.grid(column=3, row=3, padx=3, ipadx=3, ipady=3, sticky=W)
156149
self.option_add("*Font", self.__app.font_sm)
157150

158151
def _attach_events(self):
@@ -187,8 +180,8 @@ def _on_send_preset(self, *args, **kwargs): # pylint: disable=unused-argument
187180
Preset command send button has been clicked.
188181
"""
189182

190-
if not self._ent_command.validate(VALNONBLANK):
191-
self.__container.status_label = ("Select preset or enter command", ERRCOL)
183+
if not self._ent_command.validate(VALREGEX, regex=NMEAPRESETREGEX):
184+
self.__container.status_label = ("Invalid command format", ERRCOL)
192185
return
193186
self._preset_command = self._command.get()
194187

src/pygpsclient/tty_preset_dialog.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,10 @@
4646
TTYERR,
4747
TTYMARKER,
4848
TTYOK,
49+
VALNONBLANK,
4950
)
5051
from pygpsclient.hardware_info_frame import Hardware_Info_Frame
52+
from pygpsclient.helpers import validate # pylint: disable=unused-import
5153
from pygpsclient.strings import (
5254
CONFIRM,
5355
DLGACTION,
@@ -249,8 +251,8 @@ def _on_send_command(self, *args, **kwargs): # pylint: disable=unused-argument
249251
Preset command send button has been clicked.
250252
"""
251253

252-
if self._command.get() in ("", None):
253-
self.status_label = ("Enter or select command", ERRCOL)
254+
if not self._ent_command.validate(VALNONBLANK):
255+
self.status_label = ("Invalid command format", ERRCOL)
254256
return
255257

256258
try:

0 commit comments

Comments
 (0)