'''The main window and main page which links to the others'''
import tkinter.ttk as ttk
import tkinter as tk
from tkinter.font import Font
from config import GUIConfig, SimulatorConfig
from gui.sim import Simulator
from gui.conf import ConfigFrame
conf = GUIConfig()
visConf = SimulatorConfig()
[docs]class MainWindow(tk.Tk):
'''The main Tkinter window of the application
Encapsulates :class:`~gui.sim.Simulator` and :class:`~gui.conf.ConfigFrame`
'''
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.tk_setPalette(background='white')
self.wm_title(conf.Title)
self.style = ttk.Style()
self.style.theme_use(conf.Theme)
self.geometry('%dx%d' %
(conf.VisualiserWidth + conf.PanelWidth, conf.Height))
self.resizable(width=True, height=False)
self.rowconfigure(0, weight=1)
self.columnconfigure(0, weight=1)
self.font = Font(**conf.Font)
self.fontBold = Font(**conf.FontBold)
self.fontHeading = Font(**conf.FontHeading)
self.fontMonospace = Font(**conf.FontMonospace)
self._focusSim = False # is focus on the simulator?
self._cont = tk.Frame(self)
self._cont.grid(row=0, column=0, sticky='nesw')
self._cont.rowconfigure(0, weight=1)
self._cont.columnconfigure(0, weight=1)
self._frames = {}
for frameClass in (MainFrame, Simulator, ConfigFrame):
frame = frameClass(self._cont, self)
frame.grid(row=0, column=0, sticky='nesw')
self._frames[frameClass.__name__] = frame
self.focus('MainFrame')
self.bind_all('<KeyPress>', self._keyPress)
self.after(0, self._tick)
@property
def _simulator(self):
'''The encapsulated :class:`~gui.sim.Simulator`
:getter: Get the simulator
:type: :class:`~tkinter.Widget`
'''
return self._frames['Simulator']
[docs] def _tick(self):
'''Run :py:meth:`~gui.sim.Simulator.tick` on the
:class:`~gui.sim.Simulator`
Repeatedly calls itself in intervals of
:py:attr:`~config.SimulatorConfig.TickRate` milliseconds while the
Simulator window remains focused
'''
if not self._focusSim:
return
self._simulator.tick()
self.after(visConf.TickRate, self._tick)
[docs] def _keyPress(self, event):
'''Tkinter key press callback method, sends events to the
:class:`~gui.sim.Simulator` if it is currently focused
'''
if not self._focusSim:
return
self._simulator.keyPress(event)
[docs] def focus(self, name):
'''Focus on a specified contained frame. Starts the tick cycle by
calling :py:meth:`_tick` if focusing on the :class:`~gui.sim.Simulator`
:param name: (:class:`str`) Class name of the encapsulated frame that
should be focused
One of 'MainFrame', 'ConfigFrame'
'''
for frame in self._frames.values():
frame.grid_remove()
frame = self._frames[name]
frame.grid()
if getattr(frame, 'focus'):
frame.focus()
self._focusSim = name == 'Simulator'
# resize main window if necessary
width = conf.VisualiserWidth \
*(1 if not self._focusSim or frame.mode < 2 else 2) +conf.PanelWidth
if self.winfo_width() != width:
self.geometry('%dx%d' % (width, conf.Height))
self.after(0, self._tick)
[docs] def back(self):
'''Return to the main menu by raising the :class:`~gui.main.MainFrame`
to the top'''
self.focus('MainFrame')
[docs]class MainFrame(tk.Frame):
'''Main 'page' of the application, linking to the
:class:`~gui.sim.Simulator` and :class:`~gui.conf.ConfigFrame` using
:class:`~tkinter.ttk.Button` widgets. These cause the
:class:`~gui.main.MainWindow` to focus on the desired frame
:param root: :class:`~tkinter.Widget` parent
:param main: :class:`MainWindow`
'''
def __init__(self, root, main):
super().__init__(root, background='white')
self._main = main
self.grid(padx=10, pady=30)
self.columnconfigure(0, weight=1, uniform='a')
self.columnconfigure(1, weight=1, uniform='a')
self.rowconfigure(2, weight=1, uniform='a')
self.rowconfigure(3, weight=1, uniform='a')
self._title = tk.Label(self, text=conf.Title, font=main.fontHeading,
anchor='center',background='white')
self._title.grid(row=0, column=0, sticky='ew', columnspan=2,
pady=(0, 4))
self._subtitle = tk.Label(self, text=conf.Subtitle, font=main.font,
anchor='center',background='white')
self._subtitle.grid(row=1, column=0, sticky='ew', columnspan=2,
pady=(0, 30))
self._compare = ttk.Button(self, text=conf.CompareText,
command=lambda: self.startSim(2))
self._compare.grid(row=2, column=0, sticky='nesw',
padx=(0, conf.MainButtonXPad/2))
self._test = ttk.Button(self, text=conf.TestText,
command=lambda: self.startSim(1))
self._test.grid(row=2, column=1, sticky='nesw',
padx=(conf.MainButtonXPad/2, 0))
self._data = ttk.Button(self, text=conf.DataText,
command=lambda: main.focus('Simulator'))
self._data.grid(row=3, column=0, sticky='nesw',
padx=(0, conf.MainButtonXPad/2), pady=(conf.MainButtonYPad, 0))
self._config = ttk.Button(self, text=conf.ConfText,
command=lambda: main.focus('ConfigFrame'))
self._config.grid(row=3, column=1, sticky='nesw',
padx=(conf.MainButtonXPad/2, 0), pady=(conf.MainButtonYPad, 0))
[docs] def startSim(self, mode):
self._main._simulator.mode = mode
self._main.focus('Simulator')