From 22d813df63e960aa608f96d45503e15e02e5a649 Mon Sep 17 00:00:00 2001 From: Blake Harnden <32446120+bharnden@users.noreply.github.com> Date: Mon, 11 May 2020 22:00:52 -0700 Subject: [PATCH] pygui: updated validation to be wrapper classes around ttk.Entry for convenience and less code --- daemon/core/gui/app.py | 3 - daemon/core/gui/dialogs/canvassizeandscale.py | 82 +------ daemon/core/gui/dialogs/colorpicker.py | 33 +-- daemon/core/gui/dialogs/linkconfig.py | 78 ++----- daemon/core/gui/dialogs/nodeconfig.py | 13 +- daemon/core/gui/dialogs/preferences.py | 10 +- daemon/core/gui/validation.py | 219 ++++++------------ daemon/core/gui/widgets.py | 37 +-- 8 files changed, 125 insertions(+), 350 deletions(-) diff --git a/daemon/core/gui/app.py b/daemon/core/gui/app.py index 5ca95ab5..73aabb17 100644 --- a/daemon/core/gui/app.py +++ b/daemon/core/gui/app.py @@ -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): diff --git a/daemon/core/gui/dialogs/canvassizeandscale.py b/daemon/core/gui/dialogs/canvassizeandscale.py index 3418af8b..6a63a1ae 100644 --- a/daemon/core/gui/dialogs/canvassizeandscale.py +++ b/daemon/core/gui/dialogs/canvassizeandscale.py @@ -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("", 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("", 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("", 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("", 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("", 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("", 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("", 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("", 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("", 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("", 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): diff --git a/daemon/core/gui/dialogs/colorpicker.py b/daemon/core/gui/dialogs/colorpicker.py index c4268788..9087d6df 100644 --- a/daemon/core/gui/dialogs/colorpicker.py +++ b/daemon/core/gui/dialogs/colorpicker.py @@ -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) diff --git a/daemon/core/gui/dialogs/linkconfig.py b/daemon/core/gui/dialogs/linkconfig.py index 4f569ef2..92361ed4 100644 --- a/daemon/core/gui/dialogs/linkconfig.py +++ b/daemon/core/gui/dialogs/linkconfig.py @@ -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) diff --git a/daemon/core/gui/dialogs/nodeconfig.py b/daemon/core/gui/dialogs/nodeconfig.py index 85a839e5..73f0ac09 100644 --- a/daemon/core/gui/dialogs/nodeconfig.py +++ b/daemon/core/gui/dialogs/nodeconfig.py @@ -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( - "", 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 diff --git a/daemon/core/gui/dialogs/preferences.py b/daemon/core/gui/dialogs/preferences.py index 9c9ba16f..11d1ba95 100644 --- a/daemon/core/gui/dialogs/preferences.py +++ b/daemon/core/gui/dialogs/preferences.py @@ -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) diff --git a/daemon/core/gui/validation.py b/daemon/core/gui/validation.py index fee075ad..873db189 100644 --- a/daemon/core/gui/validation.py +++ b/daemon/core/gui/validation.py @@ -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("", 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 diff --git a/daemon/core/gui/widgets.py b/daemon/core/gui/widgets.py index 5750e286..6f51bd8c 100644 --- a/daemon/core/gui/widgets.py +++ b/daemon/core/gui/widgets.py @@ -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( - "", - 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( - "", - 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)