import contextlib
import tkinter.ttk as ttk
from tkinter import BooleanVar, DoubleVar, TclError
from .base import Base
from .canvasview import CanvasView
[docs]
class NumericIndicator(Base):
"""A label that displays a formatted numeric value from a tkinter variable."""
def __init__(self, value_variable=None, value=0, format_string="{0}"):
Base.__init__(self)
self.format_string = format_string
if value_variable is not None:
self.value_variable = value_variable
else:
self.value_variable = DoubleVar()
self.value_variable.trace_add("write", self.value_updated)
[docs]
def value_updated(self, var, index, mode):
"""Callback triggered when the value variable changes."""
self.update_text()
[docs]
def update_text(self):
"""Format the current value and update the label text."""
try:
formatted_text = self.format_string.format(self.value_variable.get())
if self.widget is not None:
self.widget.configure(text=formatted_text)
except Exception as err:
print(err)
[docs]
class BooleanIndicator(CanvasView):
"""A colored circle indicator that is green when True and red when False."""
def __init__(self, diameter=15):
super().__init__(width=diameter + 4, height=diameter + 4)
self.diameter = diameter
[docs]
def value_updated(self, var, index, mode):
"""Callback triggered when the boolean variable changes."""
self.draw_canvas()
[docs]
def draw_canvas(self):
"""Draw the indicator circle with the appropriate color."""
border = 1
value = self.value_variable.get()
color = "green2" if value is True else "red"
self.widget.create_oval(
(4, 4, 4 + self.diameter, 4 + self.diameter),
outline="black",
fill=color,
width=border,
)
[docs]
class Level(CanvasView):
"""A horizontal bar indicator that fills proportionally to a value."""
def __init__(self, maximum=100, width=200, height=20):
super().__init__()
self.maximum = maximum
self.width = width
self.height = height
[docs]
def value_updated(self, var, index, mode):
"""Clamp the value to the valid range and redraw the bar."""
value = 0
with contextlib.suppress(TclError):
value = self.value_variable.get()
if value < 0:
value = 0
elif value > self.maximum:
value = self.maximum
self.value_variable.set(value)
self.draw_canvas()
[docs]
def draw_canvas(self):
"""Draw the level bar reflecting the current value."""
border = 2
width = float(self.widget["width"])
height = float(self.widget["height"])
value = self.value_variable.get()
level_width = value / self.maximum * (width - border)
self.widget.create_rectangle(
4, 4, width, height, outline="black", fill="white", width=border
)
if level_width > 0:
self.widget.create_rectangle(4, 4, level_width, height - border, fill="red")