pygui: updated validation to be wrapper classes around ttk.Entry for convenience and less code
This commit is contained in:
parent
150db07497
commit
22d813df63
8 changed files with 125 additions and 350 deletions
|
@ -15,7 +15,6 @@ from core.gui.menubar import Menubar
|
|||
from core.gui.nodeutils import NodeUtils
|
||||
from core.gui.statusbar import StatusBar
|
||||
from core.gui.toolbar import Toolbar
|
||||
from core.gui.validation import InputValidation
|
||||
|
||||
WIDTH = 1000
|
||||
HEIGHT = 800
|
||||
|
@ -33,7 +32,6 @@ class Application(ttk.Frame):
|
|||
self.right_frame = None
|
||||
self.canvas = None
|
||||
self.statusbar = None
|
||||
self.validation = None
|
||||
self.progress = None
|
||||
|
||||
# fonts
|
||||
|
@ -73,7 +71,6 @@ class Application(ttk.Frame):
|
|||
self.master.protocol("WM_DELETE_WINDOW", self.on_closing)
|
||||
image = Images.get(ImageEnum.CORE, 16)
|
||||
self.master.tk.call("wm", "iconphoto", self.master._w, image)
|
||||
self.validation = InputValidation(self)
|
||||
self.master.option_add("*tearOff", tk.FALSE)
|
||||
|
||||
def center(self):
|
||||
|
|
|
@ -5,6 +5,7 @@ import tkinter as tk
|
|||
from tkinter import font, ttk
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from core.gui import validation
|
||||
from core.gui.dialogs.dialog import Dialog
|
||||
from core.gui.themes import FRAME_PAD, PADX, PADY
|
||||
|
||||
|
@ -21,7 +22,6 @@ class SizeAndScaleDialog(Dialog):
|
|||
"""
|
||||
super().__init__(app, "Canvas Size and Scale")
|
||||
self.canvas = self.app.canvas
|
||||
self.validation = app.validation
|
||||
self.section_font = font.Font(weight="bold")
|
||||
width, height = self.canvas.current_dimensions
|
||||
self.pixel_width = tk.IntVar(value=width)
|
||||
|
@ -59,23 +59,11 @@ class SizeAndScaleDialog(Dialog):
|
|||
frame.columnconfigure(3, weight=1)
|
||||
label = ttk.Label(frame, text="Width")
|
||||
label.grid(row=0, column=0, sticky="w", padx=PADX)
|
||||
entry = ttk.Entry(
|
||||
frame,
|
||||
textvariable=self.pixel_width,
|
||||
validate="key",
|
||||
validatecommand=(self.validation.positive_int, "%P"),
|
||||
)
|
||||
entry.bind("<FocusOut>", lambda event: self.validation.focus_out(event, "0"))
|
||||
entry = validation.PositiveIntEntry(frame, textvariable=self.pixel_width)
|
||||
entry.grid(row=0, column=1, sticky="ew", padx=PADX)
|
||||
label = ttk.Label(frame, text="x Height")
|
||||
label.grid(row=0, column=2, sticky="w", padx=PADX)
|
||||
entry = ttk.Entry(
|
||||
frame,
|
||||
textvariable=self.pixel_height,
|
||||
validate="key",
|
||||
validatecommand=(self.validation.positive_int, "%P"),
|
||||
)
|
||||
entry.bind("<FocusOut>", lambda event: self.validation.focus_out(event, "0"))
|
||||
entry = validation.PositiveIntEntry(frame, textvariable=self.pixel_height)
|
||||
entry.grid(row=0, column=3, sticky="ew", padx=PADX)
|
||||
label = ttk.Label(frame, text="Pixels")
|
||||
label.grid(row=0, column=4, sticky="w")
|
||||
|
@ -87,23 +75,11 @@ class SizeAndScaleDialog(Dialog):
|
|||
frame.columnconfigure(3, weight=1)
|
||||
label = ttk.Label(frame, text="Width")
|
||||
label.grid(row=0, column=0, sticky="w", padx=PADX)
|
||||
entry = ttk.Entry(
|
||||
frame,
|
||||
textvariable=self.meters_width,
|
||||
validate="key",
|
||||
validatecommand=(self.validation.positive_float, "%P"),
|
||||
)
|
||||
entry.bind("<FocusOut>", lambda event: self.validation.focus_out(event, "0"))
|
||||
entry = validation.PositiveFloatEntry(frame, textvariable=self.meters_width)
|
||||
entry.grid(row=0, column=1, sticky="ew", padx=PADX)
|
||||
label = ttk.Label(frame, text="x Height")
|
||||
label.grid(row=0, column=2, sticky="w", padx=PADX)
|
||||
entry = ttk.Entry(
|
||||
frame,
|
||||
textvariable=self.meters_height,
|
||||
validate="key",
|
||||
validatecommand=(self.validation.positive_float, "%P"),
|
||||
)
|
||||
entry.bind("<FocusOut>", lambda event: self.validation.focus_out(event, "0"))
|
||||
entry = validation.PositiveFloatEntry(frame, textvariable=self.meters_height)
|
||||
entry.grid(row=0, column=3, sticky="ew", padx=PADX)
|
||||
label = ttk.Label(frame, text="Meters")
|
||||
label.grid(row=0, column=4, sticky="w")
|
||||
|
@ -118,13 +94,7 @@ class SizeAndScaleDialog(Dialog):
|
|||
frame.columnconfigure(1, weight=1)
|
||||
label = ttk.Label(frame, text=f"{PIXEL_SCALE} Pixels =")
|
||||
label.grid(row=0, column=0, sticky="w", padx=PADX)
|
||||
entry = ttk.Entry(
|
||||
frame,
|
||||
textvariable=self.scale,
|
||||
validate="key",
|
||||
validatecommand=(self.validation.positive_float, "%P"),
|
||||
)
|
||||
entry.bind("<FocusOut>", lambda event: self.validation.focus_out(event, "0"))
|
||||
entry = validation.PositiveFloatEntry(frame, textvariable=self.scale)
|
||||
entry.grid(row=0, column=1, sticky="ew", padx=PADX)
|
||||
label = ttk.Label(frame, text="Meters")
|
||||
label.grid(row=0, column=2, sticky="w")
|
||||
|
@ -148,24 +118,12 @@ class SizeAndScaleDialog(Dialog):
|
|||
|
||||
label = ttk.Label(frame, text="X")
|
||||
label.grid(row=0, column=0, sticky="w", padx=PADX)
|
||||
entry = ttk.Entry(
|
||||
frame,
|
||||
textvariable=self.x,
|
||||
validate="key",
|
||||
validatecommand=(self.validation.positive_float, "%P"),
|
||||
)
|
||||
entry.bind("<FocusOut>", lambda event: self.validation.focus_out(event, "0"))
|
||||
entry = validation.PositiveFloatEntry(frame, textvariable=self.x)
|
||||
entry.grid(row=0, column=1, sticky="ew", padx=PADX)
|
||||
|
||||
label = ttk.Label(frame, text="Y")
|
||||
label.grid(row=0, column=2, sticky="w", padx=PADX)
|
||||
entry = ttk.Entry(
|
||||
frame,
|
||||
textvariable=self.y,
|
||||
validate="key",
|
||||
validatecommand=(self.validation.positive_float, "%P"),
|
||||
)
|
||||
entry.bind("<FocusOut>", lambda event: self.validation.focus_out(event, "0"))
|
||||
entry = validation.PositiveFloatEntry(frame, textvariable=self.y)
|
||||
entry.grid(row=0, column=3, sticky="ew", padx=PADX)
|
||||
|
||||
label = ttk.Label(label_frame, text="Translates To")
|
||||
|
@ -179,35 +137,17 @@ class SizeAndScaleDialog(Dialog):
|
|||
|
||||
label = ttk.Label(frame, text="Lat")
|
||||
label.grid(row=0, column=0, sticky="w", padx=PADX)
|
||||
entry = ttk.Entry(
|
||||
frame,
|
||||
textvariable=self.lat,
|
||||
validate="key",
|
||||
validatecommand=(self.validation.float, "%P"),
|
||||
)
|
||||
entry.bind("<FocusOut>", lambda event: self.validation.focus_out(event, "0"))
|
||||
entry = validation.FloatEntry(frame, textvariable=self.lat)
|
||||
entry.grid(row=0, column=1, sticky="ew", padx=PADX)
|
||||
|
||||
label = ttk.Label(frame, text="Lon")
|
||||
label.grid(row=0, column=2, sticky="w", padx=PADX)
|
||||
entry = ttk.Entry(
|
||||
frame,
|
||||
textvariable=self.lon,
|
||||
validate="key",
|
||||
validatecommand=(self.validation.float, "%P"),
|
||||
)
|
||||
entry.bind("<FocusOut>", lambda event: self.validation.focus_out(event, "0"))
|
||||
entry = validation.FloatEntry(frame, textvariable=self.lon)
|
||||
entry.grid(row=0, column=3, sticky="ew", padx=PADX)
|
||||
|
||||
label = ttk.Label(frame, text="Alt")
|
||||
label.grid(row=0, column=4, sticky="w", padx=PADX)
|
||||
entry = ttk.Entry(
|
||||
frame,
|
||||
textvariable=self.alt,
|
||||
validate="key",
|
||||
validatecommand=(self.validation.float, "%P"),
|
||||
)
|
||||
entry.bind("<FocusOut>", lambda event: self.validation.focus_out(event, "0"))
|
||||
entry = validation.FloatEntry(frame, textvariable=self.alt)
|
||||
entry.grid(row=0, column=5, sticky="ew")
|
||||
|
||||
def draw_save_as_default(self):
|
||||
|
|
|
@ -5,6 +5,7 @@ import tkinter as tk
|
|||
from tkinter import ttk
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from core.gui import validation
|
||||
from core.gui.dialogs.dialog import Dialog
|
||||
|
||||
if TYPE_CHECKING:
|
||||
|
@ -50,13 +51,7 @@ class ColorPickerDialog(Dialog):
|
|||
frame.columnconfigure(3, weight=2)
|
||||
label = ttk.Label(frame, text="R: ")
|
||||
label.grid(row=0, column=0)
|
||||
self.red_entry = ttk.Entry(
|
||||
frame,
|
||||
width=4,
|
||||
textvariable=self.red,
|
||||
validate="key",
|
||||
validatecommand=(self.app.validation.rgb, "%P"),
|
||||
)
|
||||
self.red_entry = validation.RgbEntry(frame, width=4, textvariable=self.red)
|
||||
self.red_entry.grid(row=0, column=1, sticky="nsew")
|
||||
scale = ttk.Scale(
|
||||
frame,
|
||||
|
@ -82,20 +77,13 @@ class ColorPickerDialog(Dialog):
|
|||
frame.columnconfigure(3, weight=2)
|
||||
label = ttk.Label(frame, text="G: ")
|
||||
label.grid(row=0, column=0)
|
||||
self.green_entry = ttk.Entry(
|
||||
frame,
|
||||
width=4,
|
||||
textvariable=self.green,
|
||||
validate="key",
|
||||
validatecommand=(self.app.validation.rgb, "%P"),
|
||||
)
|
||||
self.green_entry = validation.RgbEntry(frame, width=4, textvariable=self.green)
|
||||
self.green_entry.grid(row=0, column=1, sticky="nsew")
|
||||
scale = ttk.Scale(
|
||||
frame,
|
||||
from_=0,
|
||||
to=255,
|
||||
value=0,
|
||||
# length=200,
|
||||
orient=tk.HORIZONTAL,
|
||||
variable=self.green_scale,
|
||||
command=lambda x: self.scale_callback(self.green_scale, self.green),
|
||||
|
@ -114,13 +102,7 @@ class ColorPickerDialog(Dialog):
|
|||
frame.columnconfigure(3, weight=2)
|
||||
label = ttk.Label(frame, text="B: ")
|
||||
label.grid(row=0, column=0)
|
||||
self.blue_entry = ttk.Entry(
|
||||
frame,
|
||||
width=4,
|
||||
textvariable=self.blue,
|
||||
validate="key",
|
||||
validatecommand=(self.app.validation.rgb, "%P"),
|
||||
)
|
||||
self.blue_entry = validation.RgbEntry(frame, width=4, textvariable=self.blue)
|
||||
self.blue_entry.grid(row=0, column=1, sticky="nsew")
|
||||
scale = ttk.Scale(
|
||||
frame,
|
||||
|
@ -144,12 +126,7 @@ class ColorPickerDialog(Dialog):
|
|||
frame.columnconfigure(0, weight=1)
|
||||
label = ttk.Label(frame, text="Selection: ")
|
||||
label.grid(row=0, column=0, sticky="nsew")
|
||||
self.hex_entry = ttk.Entry(
|
||||
frame,
|
||||
textvariable=self.hex,
|
||||
validate="key",
|
||||
validatecommand=(self.app.validation.hex, "%P"),
|
||||
)
|
||||
self.hex_entry = validation.HexEntry(frame, textvariable=self.hex)
|
||||
self.hex_entry.grid(row=1, column=0, sticky="nsew")
|
||||
self.display = tk.Frame(frame, background=self.color, width=100, height=100)
|
||||
self.display.grid(row=2, column=0)
|
||||
|
|
|
@ -6,6 +6,7 @@ from tkinter import ttk
|
|||
from typing import TYPE_CHECKING, Union
|
||||
|
||||
from core.api.grpc import core_pb2
|
||||
from core.gui import validation
|
||||
from core.gui.dialogs.colorpicker import ColorPickerDialog
|
||||
from core.gui.dialogs.dialog import Dialog
|
||||
from core.gui.themes import PADX, PADY
|
||||
|
@ -120,95 +121,65 @@ class LinkConfigurationDialog(Dialog):
|
|||
|
||||
label = ttk.Label(frame, text="Bandwidth (bps)")
|
||||
label.grid(row=row, column=0, sticky="ew")
|
||||
entry = ttk.Entry(
|
||||
frame,
|
||||
textvariable=self.bandwidth,
|
||||
validate="key",
|
||||
validatecommand=(self.app.validation.positive_int, "%P"),
|
||||
entry = validation.PositiveIntEntry(
|
||||
frame, empty_enabled=False, textvariable=self.bandwidth
|
||||
)
|
||||
entry.grid(row=row, column=1, sticky="ew", pady=PADY)
|
||||
if not self.is_symmetric:
|
||||
entry = ttk.Entry(
|
||||
frame,
|
||||
textvariable=self.down_bandwidth,
|
||||
validate="key",
|
||||
validatecommand=(self.app.validation.positive_int, "%P"),
|
||||
entry = validation.PositiveIntEntry(
|
||||
frame, empty_enabled=False, textvariable=self.down_bandwidth
|
||||
)
|
||||
entry.grid(row=row, column=2, sticky="ew", pady=PADY)
|
||||
row = row + 1
|
||||
|
||||
label = ttk.Label(frame, text="Delay (us)")
|
||||
label.grid(row=row, column=0, sticky="ew")
|
||||
entry = ttk.Entry(
|
||||
frame,
|
||||
textvariable=self.delay,
|
||||
validate="key",
|
||||
validatecommand=(self.app.validation.positive_int, "%P"),
|
||||
entry = validation.PositiveIntEntry(
|
||||
frame, empty_enabled=False, textvariable=self.delay
|
||||
)
|
||||
entry.grid(row=row, column=1, sticky="ew", pady=PADY)
|
||||
if not self.is_symmetric:
|
||||
entry = ttk.Entry(
|
||||
frame,
|
||||
textvariable=self.down_delay,
|
||||
validate="key",
|
||||
validatecommand=(self.app.validation.positive_int, "%P"),
|
||||
entry = validation.PositiveIntEntry(
|
||||
frame, empty_enabled=False, textvariable=self.down_delay
|
||||
)
|
||||
entry.grid(row=row, column=2, sticky="ew", pady=PADY)
|
||||
row = row + 1
|
||||
|
||||
label = ttk.Label(frame, text="Jitter (us)")
|
||||
label.grid(row=row, column=0, sticky="ew")
|
||||
entry = ttk.Entry(
|
||||
frame,
|
||||
textvariable=self.jitter,
|
||||
validate="key",
|
||||
validatecommand=(self.app.validation.positive_int, "%P"),
|
||||
entry = validation.PositiveIntEntry(
|
||||
frame, empty_enabled=False, textvariable=self.jitter
|
||||
)
|
||||
entry.grid(row=row, column=1, sticky="ew", pady=PADY)
|
||||
if not self.is_symmetric:
|
||||
entry = ttk.Entry(
|
||||
frame,
|
||||
textvariable=self.down_jitter,
|
||||
validate="key",
|
||||
validatecommand=(self.app.validation.positive_int, "%P"),
|
||||
entry = validation.PositiveIntEntry(
|
||||
frame, empty_enabled=False, textvariable=self.down_jitter
|
||||
)
|
||||
entry.grid(row=row, column=2, sticky="ew", pady=PADY)
|
||||
row = row + 1
|
||||
|
||||
label = ttk.Label(frame, text="Loss (%)")
|
||||
label.grid(row=row, column=0, sticky="ew")
|
||||
entry = ttk.Entry(
|
||||
frame,
|
||||
textvariable=self.loss,
|
||||
validate="key",
|
||||
validatecommand=(self.app.validation.positive_float, "%P"),
|
||||
entry = validation.PositiveFloatEntry(
|
||||
frame, empty_enabled=False, textvariable=self.loss
|
||||
)
|
||||
entry.grid(row=row, column=1, sticky="ew", pady=PADY)
|
||||
if not self.is_symmetric:
|
||||
entry = ttk.Entry(
|
||||
frame,
|
||||
textvariable=self.down_loss,
|
||||
validate="key",
|
||||
validatecommand=(self.app.validation.positive_float, "%P"),
|
||||
entry = validation.PositiveFloatEntry(
|
||||
frame, empty_enabled=False, textvariable=self.down_loss
|
||||
)
|
||||
entry.grid(row=row, column=2, sticky="ew", pady=PADY)
|
||||
row = row + 1
|
||||
|
||||
label = ttk.Label(frame, text="Duplicate (%)")
|
||||
label.grid(row=row, column=0, sticky="ew")
|
||||
entry = ttk.Entry(
|
||||
frame,
|
||||
textvariable=self.duplicate,
|
||||
validate="key",
|
||||
validatecommand=(self.app.validation.positive_int, "%P"),
|
||||
entry = validation.PositiveIntEntry(
|
||||
frame, empty_enabled=False, textvariable=self.duplicate
|
||||
)
|
||||
entry.grid(row=row, column=1, sticky="ew", pady=PADY)
|
||||
if not self.is_symmetric:
|
||||
entry = ttk.Entry(
|
||||
frame,
|
||||
textvariable=self.down_duplicate,
|
||||
validate="key",
|
||||
validatecommand=(self.app.validation.positive_int, "%P"),
|
||||
entry = validation.PositiveIntEntry(
|
||||
frame, empty_enabled=False, textvariable=self.down_duplicate
|
||||
)
|
||||
entry.grid(row=row, column=2, sticky="ew", pady=PADY)
|
||||
row = row + 1
|
||||
|
@ -229,11 +200,8 @@ class LinkConfigurationDialog(Dialog):
|
|||
|
||||
label = ttk.Label(frame, text="Width")
|
||||
label.grid(row=row, column=0, sticky="ew")
|
||||
entry = ttk.Entry(
|
||||
frame,
|
||||
textvariable=self.width,
|
||||
validate="key",
|
||||
validatecommand=(self.app.validation.positive_float, "%P"),
|
||||
entry = validation.PositiveFloatEntry(
|
||||
frame, empty_enabled=False, textvariable=self.width
|
||||
)
|
||||
entry.grid(row=row, column=1, sticky="ew", pady=PADY)
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@ from typing import TYPE_CHECKING
|
|||
|
||||
import netaddr
|
||||
|
||||
from core.gui import nodeutils
|
||||
from core.gui import nodeutils, validation
|
||||
from core.gui.appconfig import ICONS_PATH
|
||||
from core.gui.dialogs.dialog import Dialog
|
||||
from core.gui.dialogs.emaneconfig import EmaneModelDialog
|
||||
|
@ -143,16 +143,7 @@ class NodeConfigDialog(Dialog):
|
|||
# name field
|
||||
label = ttk.Label(frame, text="Name")
|
||||
label.grid(row=row, column=0, sticky="ew", padx=PADX, pady=PADY)
|
||||
entry = ttk.Entry(
|
||||
frame,
|
||||
textvariable=self.name,
|
||||
validate="key",
|
||||
validatecommand=(self.app.validation.name, "%P"),
|
||||
state=state,
|
||||
)
|
||||
entry.bind(
|
||||
"<FocusOut>", lambda event: self.app.validation.focus_out(event, "noname")
|
||||
)
|
||||
entry = validation.NodeNameEntry(frame, textvariable=self.name, state=state)
|
||||
entry.grid(row=row, column=1, sticky="ew")
|
||||
row += 1
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@ import tkinter as tk
|
|||
from tkinter import ttk
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from core.gui import appconfig
|
||||
from core.gui import appconfig, validation
|
||||
from core.gui.dialogs.dialog import Dialog
|
||||
from core.gui.themes import FRAME_PAD, PADX, PADY, scale_fonts
|
||||
from core.gui.validation import LARGEST_SCALE, SMALLEST_SCALE
|
||||
|
@ -80,12 +80,8 @@ class PreferencesDialog(Dialog):
|
|||
variable=self.gui_scale,
|
||||
)
|
||||
scale.grid(row=0, column=0, sticky="ew")
|
||||
entry = ttk.Entry(
|
||||
scale_frame,
|
||||
textvariable=self.gui_scale,
|
||||
width=4,
|
||||
validate="key",
|
||||
validatecommand=(self.app.validation.app_scale, "%P"),
|
||||
entry = validation.AppScaleEntry(
|
||||
scale_frame, textvariable=self.gui_scale, width=4
|
||||
)
|
||||
entry.grid(row=0, column=1)
|
||||
|
||||
|
|
|
@ -3,71 +3,63 @@ input validation
|
|||
"""
|
||||
import re
|
||||
import tkinter as tk
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
import netaddr
|
||||
from netaddr import IPNetwork
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from core.gui.app import Application
|
||||
from tkinter import ttk
|
||||
|
||||
SMALLEST_SCALE = 0.5
|
||||
LARGEST_SCALE = 5.0
|
||||
HEX_REGEX = re.compile("^([#]([0-9]|[a-f])+)$|^[#]$")
|
||||
|
||||
|
||||
class InputValidation:
|
||||
def __init__(self, app: "Application"):
|
||||
self.master = app.master
|
||||
self.positive_int = None
|
||||
self.positive_float = None
|
||||
self.float = None
|
||||
self.app_scale = None
|
||||
self.name = None
|
||||
self.ip4 = None
|
||||
self.rgb = None
|
||||
self.hex = None
|
||||
self.register()
|
||||
class ValidationEntry(ttk.Entry):
|
||||
empty = None
|
||||
|
||||
def register(self):
|
||||
self.positive_int = self.master.register(self.check_positive_int)
|
||||
self.positive_float = self.master.register(self.check_positive_float)
|
||||
self.float = self.master.register(self.check_float)
|
||||
self.app_scale = self.master.register(self.check_scale_value)
|
||||
self.name = self.master.register(self.check_node_name)
|
||||
self.ip4 = self.master.register(self.check_ip4)
|
||||
self.rgb = self.master.register(self.check_rbg)
|
||||
self.hex = self.master.register(self.check_hex)
|
||||
def __init__(self, master=None, widget=None, empty_enabled=True, **kwargs) -> None:
|
||||
super().__init__(master, widget, **kwargs)
|
||||
cmd = self.register(self.is_valid)
|
||||
self.configure(validate="key", validatecommand=(cmd, "%P"))
|
||||
if self.empty is not None and empty_enabled:
|
||||
self.bind("<FocusOut>", self.focus_out)
|
||||
|
||||
@classmethod
|
||||
def ip_focus_out(cls, event: tk.Event):
|
||||
value = event.widget.get()
|
||||
try:
|
||||
IPNetwork(value)
|
||||
except netaddr.core.AddrFormatError:
|
||||
event.widget.delete(0, tk.END)
|
||||
event.widget.insert(tk.END, "invalid")
|
||||
def is_valid(self, s: str) -> bool:
|
||||
raise NotImplementedError
|
||||
|
||||
@classmethod
|
||||
def focus_out(cls, event: tk.Event, default: str):
|
||||
value = event.widget.get()
|
||||
if value == "":
|
||||
event.widget.insert(tk.END, default)
|
||||
def focus_out(self, _event: tk.Event) -> None:
|
||||
value = self.get()
|
||||
if not value:
|
||||
self.insert(tk.END, self.empty)
|
||||
|
||||
@classmethod
|
||||
def check_positive_int(cls, s: str) -> bool:
|
||||
if len(s) == 0:
|
||||
|
||||
class PositiveIntEntry(ValidationEntry):
|
||||
empty = "0"
|
||||
|
||||
def is_valid(self, s: str) -> bool:
|
||||
if not s:
|
||||
return True
|
||||
try:
|
||||
int_value = int(s)
|
||||
if int_value >= 0:
|
||||
return True
|
||||
return False
|
||||
value = int(s)
|
||||
return value >= 0
|
||||
except ValueError:
|
||||
return False
|
||||
|
||||
@classmethod
|
||||
def check_float(cls, s: str) -> bool:
|
||||
if len(s) == 0:
|
||||
|
||||
class PositiveFloatEntry(ValidationEntry):
|
||||
empty = "0.0"
|
||||
|
||||
def is_valid(self, s: str) -> bool:
|
||||
if not s:
|
||||
return True
|
||||
try:
|
||||
value = float(s)
|
||||
return value >= 0.0
|
||||
except ValueError:
|
||||
return False
|
||||
|
||||
|
||||
class FloatEntry(ValidationEntry):
|
||||
empty = "0.0"
|
||||
|
||||
def is_valid(self, s: str) -> bool:
|
||||
if not s:
|
||||
return True
|
||||
try:
|
||||
float(s)
|
||||
|
@ -75,109 +67,50 @@ class InputValidation:
|
|||
except ValueError:
|
||||
return False
|
||||
|
||||
@classmethod
|
||||
def check_positive_float(cls, s: str) -> bool:
|
||||
if len(s) == 0:
|
||||
return True
|
||||
try:
|
||||
float_value = float(s)
|
||||
if float_value >= 0.0:
|
||||
return True
|
||||
return False
|
||||
except ValueError:
|
||||
return False
|
||||
|
||||
@classmethod
|
||||
def check_node_name(cls, s: str) -> bool:
|
||||
if len(s) < 0:
|
||||
return False
|
||||
if len(s) == 0:
|
||||
return True
|
||||
for char in s:
|
||||
if not char.isalnum() and char != "_":
|
||||
return False
|
||||
return True
|
||||
|
||||
@classmethod
|
||||
def check_canvas_int(cls, s: str) -> bool:
|
||||
if len(s) == 0:
|
||||
return True
|
||||
try:
|
||||
int_value = int(s)
|
||||
if int_value >= 0:
|
||||
return True
|
||||
return False
|
||||
except ValueError:
|
||||
return False
|
||||
|
||||
@classmethod
|
||||
def check_canvas_float(cls, s: str) -> bool:
|
||||
if not s:
|
||||
return True
|
||||
try:
|
||||
float_value = float(s)
|
||||
if float_value >= 0.0:
|
||||
return True
|
||||
return False
|
||||
except ValueError:
|
||||
return False
|
||||
|
||||
@classmethod
|
||||
def check_scale_value(cls, s: str) -> bool:
|
||||
if not s:
|
||||
return True
|
||||
try:
|
||||
float_value = float(s)
|
||||
if SMALLEST_SCALE <= float_value <= LARGEST_SCALE or float_value == 0:
|
||||
return True
|
||||
return False
|
||||
except ValueError:
|
||||
return False
|
||||
|
||||
@classmethod
|
||||
def check_ip4(cls, s: str) -> bool:
|
||||
if not s:
|
||||
return True
|
||||
pat = re.compile("^([0-9]+[.])*[0-9]*$")
|
||||
if pat.match(s) is not None:
|
||||
_32bits = s.split(".")
|
||||
if len(_32bits) > 4:
|
||||
return False
|
||||
for _8bits in _32bits:
|
||||
if (
|
||||
(_8bits and int(_8bits) > 255)
|
||||
or len(_8bits) > 3
|
||||
or (_8bits.startswith("0") and len(_8bits) > 1)
|
||||
):
|
||||
return False
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
@classmethod
|
||||
def check_rbg(cls, s: str) -> bool:
|
||||
class RgbEntry(ValidationEntry):
|
||||
def is_valid(self, s: str) -> bool:
|
||||
if not s:
|
||||
return True
|
||||
if s.startswith("0") and len(s) >= 2:
|
||||
return False
|
||||
try:
|
||||
value = int(s)
|
||||
if 0 <= value <= 255:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
return 0 <= value <= 255
|
||||
except ValueError:
|
||||
return False
|
||||
|
||||
@classmethod
|
||||
def check_hex(cls, s: str) -> bool:
|
||||
|
||||
class HexEntry(ValidationEntry):
|
||||
def is_valid(self, s: str) -> bool:
|
||||
if not s:
|
||||
return True
|
||||
pat = re.compile("^([#]([0-9]|[a-f])+)$|^[#]$")
|
||||
if pat.match(s):
|
||||
if 0 <= len(s) <= 7:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
if HEX_REGEX.match(s):
|
||||
return 0 <= len(s) <= 7
|
||||
else:
|
||||
return False
|
||||
|
||||
|
||||
class NodeNameEntry(ValidationEntry):
|
||||
empty = "noname"
|
||||
|
||||
def is_valid(self, s: str) -> bool:
|
||||
if len(s) < 0:
|
||||
return False
|
||||
if len(s) == 0:
|
||||
return True
|
||||
for x in s:
|
||||
if not x.isalnum() and x != "_":
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
class AppScaleEntry(ValidationEntry):
|
||||
def is_valid(self, s: str) -> bool:
|
||||
if not s:
|
||||
return True
|
||||
try:
|
||||
float_value = float(s)
|
||||
return SMALLEST_SCALE <= float_value <= LARGEST_SCALE or float_value == 0
|
||||
except ValueError:
|
||||
return False
|
||||
|
|
|
@ -6,7 +6,7 @@ from tkinter import filedialog, font, ttk
|
|||
from typing import TYPE_CHECKING, Dict
|
||||
|
||||
from core.api.grpc import common_pb2, core_pb2
|
||||
from core.gui import themes
|
||||
from core.gui import themes, validation
|
||||
from core.gui.themes import FRAME_PAD, PADX, PADY
|
||||
|
||||
if TYPE_CHECKING:
|
||||
|
@ -127,43 +127,16 @@ class ConfigFrame(ttk.Notebook):
|
|||
button = ttk.Button(file_frame, text="...", command=func)
|
||||
button.grid(row=0, column=1)
|
||||
else:
|
||||
if "controlnet" in option.name and "script" not in option.name:
|
||||
entry = ttk.Entry(
|
||||
tab.frame,
|
||||
textvariable=value,
|
||||
validate="key",
|
||||
validatecommand=(self.app.validation.ip4, "%P"),
|
||||
)
|
||||
entry.grid(row=index, column=1, sticky="ew")
|
||||
else:
|
||||
entry = ttk.Entry(tab.frame, textvariable=value)
|
||||
entry.grid(row=index, column=1, sticky="ew")
|
||||
entry = ttk.Entry(tab.frame, textvariable=value)
|
||||
entry.grid(row=index, column=1, sticky="ew")
|
||||
|
||||
elif option.type in INT_TYPES:
|
||||
value.set(option.value)
|
||||
entry = ttk.Entry(
|
||||
tab.frame,
|
||||
textvariable=value,
|
||||
validate="key",
|
||||
validatecommand=(self.app.validation.positive_int, "%P"),
|
||||
)
|
||||
entry.bind(
|
||||
"<FocusOut>",
|
||||
lambda event: self.app.validation.focus_out(event, "0"),
|
||||
)
|
||||
entry = validation.PositiveIntEntry(tab.frame, textvariable=value)
|
||||
entry.grid(row=index, column=1, sticky="ew")
|
||||
elif option.type == core_pb2.ConfigOptionType.FLOAT:
|
||||
value.set(option.value)
|
||||
entry = ttk.Entry(
|
||||
tab.frame,
|
||||
textvariable=value,
|
||||
validate="key",
|
||||
validatecommand=(self.app.validation.positive_float, "%P"),
|
||||
)
|
||||
entry.bind(
|
||||
"<FocusOut>",
|
||||
lambda event: self.app.validation.focus_out(event, "0"),
|
||||
)
|
||||
entry = validation.PositiveFloatEntry(tab.frame, textvariable=value)
|
||||
entry.grid(row=index, column=1, sticky="ew")
|
||||
else:
|
||||
logging.error("unhandled config option type: %s", option.type)
|
||||
|
|
Loading…
Reference in a new issue