commit
This commit is contained in:
commit
8a24549cdb
21 changed files with 3478 additions and 0 deletions
217
StartingPoint/gui.py
Normal file
217
StartingPoint/gui.py
Normal file
|
|
@ -0,0 +1,217 @@
|
|||
import tkinter
|
||||
from lib.controller import pretty_time
|
||||
import random
|
||||
|
||||
WATER_COLOR = '#1c8ce8'
|
||||
SKY_COLOR = '#ffc4d4'
|
||||
DOOR_COLOR = '#633f09'
|
||||
|
||||
TRAFFIC_LIGHT_OFF_COLOR = '#362d2d'
|
||||
TRAFFIC_LIGHT_RED_COLOR = '#ff0000'
|
||||
TRAFFIC_LIGHT_GREEN_COLOR = '#4be81c'
|
||||
|
||||
DEFAULT_WIDGET_COLOR = '#d9d9d9'
|
||||
|
||||
# Paints a single lock door onto canvas
|
||||
class LockDoorView:
|
||||
def __init__(self, canvas, x, scale=1):
|
||||
self.canvas = canvas
|
||||
self.door_id = canvas.create_rectangle((x-10)*scale, 70*scale, (x+10)*scale, 250*scale)
|
||||
self.flow_id = canvas.create_rectangle((x-12)*scale, 220*scale, (x+12)*scale, 240*scale, outline='')
|
||||
|
||||
canvas.create_oval((x-15)*scale, 10, (x+15)*scale, 54, fill='black')
|
||||
self.red_light_id = canvas.create_oval((x-10)*scale, 12, (x+10)*scale, 32, outline='')
|
||||
self.green_light_id = canvas.create_oval((x-10)*scale, 32, (x+10)*scale, 52, outline='')
|
||||
|
||||
self.set_doors(open=False)
|
||||
self.set_flow(open=False)
|
||||
self.set_red_light()
|
||||
|
||||
def set_doors(self, open):
|
||||
if open:
|
||||
self.canvas.itemconfig(self.door_id, fill='', outline='black', dash=(4,6))
|
||||
else:
|
||||
self.canvas.itemconfig(self.door_id, fill=DOOR_COLOR, outline='', dash=None)
|
||||
|
||||
def set_flow(self, open):
|
||||
if open:
|
||||
self.canvas.itemconfig(self.flow_id, fill=WATER_COLOR)
|
||||
else:
|
||||
self.canvas.itemconfig(self.flow_id, fill='')
|
||||
|
||||
def set_green_light(self):
|
||||
self.canvas.itemconfig(self.red_light_id, fill=TRAFFIC_LIGHT_OFF_COLOR)
|
||||
self.canvas.itemconfig(self.green_light_id, fill=TRAFFIC_LIGHT_GREEN_COLOR)
|
||||
|
||||
def set_red_light(self):
|
||||
self.canvas.itemconfig(self.red_light_id, fill=TRAFFIC_LIGHT_RED_COLOR)
|
||||
self.canvas.itemconfig(self.green_light_id, fill=TRAFFIC_LIGHT_OFF_COLOR)
|
||||
|
||||
# TkInter canvas with water levels, doors
|
||||
class LockView:
|
||||
def __init__(self, parent, scale=1):
|
||||
self.scale = scale
|
||||
self.canvas = tkinter.Canvas(parent, bg=SKY_COLOR, width=600*scale, height=250*scale)
|
||||
# LOW side:
|
||||
self.canvas.create_rectangle(0, 200*scale, 200*scale, 250*scale, fill=WATER_COLOR, outline='')
|
||||
# MIDDLE side:
|
||||
self.middle_rectangle_id = self.canvas.create_rectangle(200*scale, 200*scale, 400*scale, 250*scale, fill=WATER_COLOR, outline='')
|
||||
# HIGH side:
|
||||
self.canvas.create_rectangle(400*scale, 100*scale, 600*scale, 250*scale, fill=WATER_COLOR, outline='')
|
||||
|
||||
self.ldoor = LockDoorView(self.canvas, 200, scale)
|
||||
self.hdoor = LockDoorView(self.canvas, 400, scale)
|
||||
|
||||
def set_water_lvl(self, water_lvl):
|
||||
self.canvas.coords(self.middle_rectangle_id, 200*self.scale, (250-water_lvl/10)*self.scale, 400*self.scale, 250*self.scale)
|
||||
|
||||
class GUI:
|
||||
def __init__(self, sim, sc, wlvlsc, toplevel, randomseed=0):
|
||||
# to raise input events
|
||||
self.sim = sim
|
||||
self.sc = sc
|
||||
self.wlvlsc = wlvlsc
|
||||
|
||||
self.rand = random.Random(randomseed) # seed
|
||||
|
||||
toplevel.resizable(0,0)
|
||||
toplevel.title("Lock Simulator")
|
||||
|
||||
self.lock_view = LockView(toplevel)
|
||||
self.lock_view.canvas.pack(side=tkinter.TOP)
|
||||
|
||||
self.var_simtime = tkinter.StringVar()
|
||||
self.var_ldoors = tkinter.StringVar(value="CLOSED")
|
||||
self.var_hdoors = tkinter.StringVar(value="CLOSED")
|
||||
self.var_lflow = tkinter.StringVar(value="CLOSED")
|
||||
self.var_hflow = tkinter.StringVar(value="CLOSED")
|
||||
self.var_lsignal = tkinter.StringVar(value="RED")
|
||||
self.var_hsignal = tkinter.StringVar(value="RED")
|
||||
self.var_sensor = tkinter.StringVar(value="")
|
||||
self.var_real_lvl = tkinter.StringVar(value="")
|
||||
self.var_sensor_status = tkinter.StringVar(value="NO FAILURE DETECTED")
|
||||
|
||||
sim_frame = tkinter.LabelFrame(toplevel, text="Environment")
|
||||
tkinter.Label(sim_frame, text="Real Water Level").grid(column=0, row=0)
|
||||
tkinter.Entry(sim_frame, state='readonly', width=8, textvariable=self.var_real_lvl, justify=tkinter.RIGHT).grid(column=1, row=0)
|
||||
tkinter.Label(sim_frame, text="cm").grid(column=2, row=0)
|
||||
|
||||
tkinter.Label(sim_frame, text="Water Level Sensor").grid(column=0, row=1)
|
||||
self.entry_sensor = tkinter.Entry(sim_frame, state='readonly', width=8, textvariable=self.var_sensor, justify=tkinter.RIGHT)
|
||||
self.entry_sensor.grid(row=1, column=1)
|
||||
tkinter.Label(sim_frame, text="cm").grid(row=1, column=2)
|
||||
|
||||
self.button_broken_sensor = tkinter.Button(sim_frame, text="Break Sensor",
|
||||
command=self.break_sensor, width=14)
|
||||
self.button_unbroken_sensor = tkinter.Button(sim_frame, text="Un-break Sensor",
|
||||
command=self.unbreak_sensor, width=14, state=tkinter.DISABLED)
|
||||
self.button_broken_sensor.grid(column=0, row=3, columnspan=3)
|
||||
self.button_unbroken_sensor.grid(column=0, row=4, columnspan=3)
|
||||
|
||||
tkinter.Label(sim_frame, text="Simulated Time").grid(column=0, row=5)
|
||||
tkinter.Entry(sim_frame, state='readonly', width=8, textvariable=self.var_simtime, justify=tkinter.RIGHT).grid(row=5, column=1)
|
||||
tkinter.Label(sim_frame, text="s").grid(row=5, column=2)
|
||||
sim_frame.pack(side=tkinter.LEFT)
|
||||
|
||||
request_frame = tkinter.LabelFrame(toplevel, text="Actions")
|
||||
self.button_change_lvl = tkinter.Button(request_frame, command=lambda: self.sim.add_input_now(self.sc, "request_lvl_change"), width=18)
|
||||
self.button_change_lvl.pack()
|
||||
self.button_resume = tkinter.Button(request_frame, text="Resume (make sure sensor is repaired first!)",
|
||||
command=self.resume, wraplength=160, width=18, state=tkinter.DISABLED)
|
||||
self.button_resume.pack()
|
||||
request_frame.pack(side=tkinter.LEFT)
|
||||
|
||||
self.set_request_pending(value=False)
|
||||
|
||||
status_frame = tkinter.LabelFrame(toplevel, text="Status")
|
||||
tkinter.Label(status_frame, text="Low").grid(row=0, column=1)
|
||||
tkinter.Label(status_frame, text="High").grid(row=0, column=2)
|
||||
tkinter.Label(status_frame, text="Doors").grid(row=1, column=0)
|
||||
tkinter.Label(status_frame, text="Flow").grid(row=2, column=0)
|
||||
tkinter.Label(status_frame, text="Signal").grid(row=3, column=0)
|
||||
tkinter.Entry(status_frame, state='readonly', width=8, textvariable=self.var_ldoors).grid(row=1, column=1)
|
||||
tkinter.Entry(status_frame, state='readonly', width=8, textvariable=self.var_hdoors).grid(row=1, column=2)
|
||||
tkinter.Entry(status_frame, state='readonly', width=8, textvariable=self.var_lflow).grid(row=2, column=1)
|
||||
tkinter.Entry(status_frame, state='readonly', width=8, textvariable=self.var_hflow).grid(row=2, column=2)
|
||||
tkinter.Entry(status_frame, state='readonly', width=8, textvariable=self.var_lsignal).grid(row=3, column=1)
|
||||
tkinter.Entry(status_frame, state='readonly', width=8, textvariable=self.var_hsignal).grid(row=3, column=2)
|
||||
tkinter.Label(status_frame, text="Sensor").grid(row=4, column=0)
|
||||
tkinter.Entry(status_frame, state='readonly', width=18, textvariable=self.var_sensor_status).grid(row=4, column=1, columnspan=2)
|
||||
status_frame.pack(side=tkinter.LEFT)
|
||||
|
||||
def set_doors(self, side, open):
|
||||
strval = "OPEN" if open else "CLOSED"
|
||||
if side == self.sc.LOW:
|
||||
self.var_ldoors.set(strval)
|
||||
self.lock_view.ldoor.set_doors(open)
|
||||
elif side == self.sc.HIGH:
|
||||
self.var_hdoors.set(strval)
|
||||
self.lock_view.hdoor.set_doors(open)
|
||||
|
||||
def set_flow(self, side, open):
|
||||
strval = "OPEN" if open else "CLOSED"
|
||||
eventname = "open_flow" if open else "close_flow"
|
||||
self.sim.add_input_sync(self.wlvlsc, eventname, value=side)
|
||||
if side == self.sc.LOW:
|
||||
self.var_lflow.set(strval)
|
||||
self.lock_view.ldoor.set_flow(open)
|
||||
elif side == self.sc.HIGH:
|
||||
self.var_hflow.set(strval)
|
||||
self.lock_view.hdoor.set_flow(open)
|
||||
|
||||
def set_green_light(self, side):
|
||||
if side == self.sc.LOW:
|
||||
self.var_lsignal.set("GREEN")
|
||||
self.lock_view.ldoor.set_green_light()
|
||||
else:
|
||||
self.var_hsignal.set("GREEN")
|
||||
self.lock_view.hdoor.set_green_light()
|
||||
|
||||
def set_red_light(self, side):
|
||||
if side == self.sc.LOW:
|
||||
self.var_lsignal.set("RED")
|
||||
self.lock_view.ldoor.set_red_light()
|
||||
else:
|
||||
self.var_hsignal.set("RED")
|
||||
self.lock_view.hdoor.set_red_light()
|
||||
|
||||
def break_sensor(self):
|
||||
self.sim.add_input_now(self.wlvlsc, "toggle_sensor_broken")
|
||||
self.entry_sensor.config(readonlybackground='red')
|
||||
self.button_broken_sensor.config(state=tkinter.DISABLED)
|
||||
self.button_unbroken_sensor.config(state=tkinter.NORMAL)
|
||||
|
||||
def unbreak_sensor(self):
|
||||
self.sim.add_input_now(self.wlvlsc, "toggle_sensor_broken")
|
||||
self.entry_sensor.config(readonlybackground=DEFAULT_WIDGET_COLOR) # default color
|
||||
self.button_broken_sensor.config(state=tkinter.NORMAL)
|
||||
self.button_unbroken_sensor.config(state=tkinter.DISABLED)
|
||||
|
||||
def resume(self):
|
||||
self.sim.add_input_now(self.sc, "resume")
|
||||
self.button_resume.config(state=tkinter.DISABLED, bg=DEFAULT_WIDGET_COLOR)
|
||||
self.var_sensor_status.set("NO FAILURE DETECTED")
|
||||
|
||||
def set_request_pending(self, value):
|
||||
if value:
|
||||
self.button_change_lvl.config(state=tkinter.DISABLED, text="Change requested")
|
||||
else:
|
||||
self.button_change_lvl.config(state=tkinter.NORMAL, text="Change water level")
|
||||
|
||||
def on_water_level_reading(self, water_level):
|
||||
# the measured water level - can be nonsense if sensor is broken
|
||||
noisy_water_level = int(water_level + self.rand.random()*10)
|
||||
self.sim.add_input_sync(self.sc, "water_lvl", value=noisy_water_level)
|
||||
self.var_sensor.set(noisy_water_level)
|
||||
|
||||
def on_real_water_level(self, water_level):
|
||||
# the actual water level
|
||||
self.var_real_lvl.set(int(water_level))
|
||||
self.lock_view.set_water_lvl(water_level)
|
||||
|
||||
def set_sensor_broken(self):
|
||||
self.button_resume.config(state=tkinter.NORMAL, bg='yellow')
|
||||
self.var_sensor_status.set("FAILURE DETECTED")
|
||||
|
||||
def time_changed(self, simtime):
|
||||
self.var_simtime.set(pretty_time(simtime))
|
||||
Loading…
Add table
Add a link
Reference in a new issue