Пример #1
0
def main(arg_list):
    """Parse the command line options and arguments specified in arg_list.

    Run either the command line user interface, the graphical user interface,
    or display the usage message.
    """
    usage_message = ("Usage:\n"
                     "Show help: logsim.py -h\n"
                     "Command line user interface: logsim.py -c <file path>\n"
                     "Graphical user interface: logsim.py <file path>")
    try:
        options, arguments = getopt.getopt(arg_list, "hc:")
    except getopt.GetoptError:
        print("Error: invalid command line arguments\n")
        print(usage_message)
        sys.exit()

    # Initialise instances of the four inner simulator classes
    names = Names()
    devices = Devices(names)
    network = Network(names, devices)
    monitors = Monitors(names, devices, network)

    for option, path in options:
        if option == "-h":  # print the usage message
            print(usage_message)
            sys.exit()
        elif option == "-c":  # use the command line user interface
            scanner = Scanner(path, names)
            parser = Parser(names, devices, network, monitors, scanner)
            if parser.parse_network():
                # Initialise an instance of the userint.UserInterface() class
                userint = UserInterface(names, devices, network, monitors)
                userint.command_interface()

    if not options:  # no option given, use the graphical user interface

        if len(arguments) != 1:  # wrong number of arguments
            print("Error: one file path required\n")
            print(usage_message)
            sys.exit()

        [path] = arguments
        scanner = Scanner(path, names)
        parser = Parser(names, devices, network, monitors, scanner)
        if parser.parse_network():
            # Initialise an instance of the gui.Gui() class
            app = wx.App()
            builtins._ = wx.GetTranslation
            locale = wx.Locale()
            locale.Init(wx.LANGUAGE_DEFAULT)
            locale.AddCatalogLookupPathPrefix('./locale')
            locale.AddCatalog('zh_CN')
            gui = Gui("Logic Simulator", path, names, devices, network,
                      monitors)
            gui.Show(True)
            app.MainLoop()
Пример #2
0
def test_error_location(names, devices, network, monitors, capsys):
    """Test if error detection correctly prints out location of error
    """
    sc = Scanner(error_location, names)
    parser = Parser(names, devices, network, monitors, sc)
    parser.parse_network()
    captured = capsys.readouterr()

    line_number = "line 10"
    try:
        assert (line_number in captured.out)
    except AttributeError:
        assert (line_number in captured[0])
Пример #3
0
def test_semantic_errors(bad_file, error_message, names, devices, network,
                         monitors, capsys):
    """Going through all the files which should throw semantic errors
    and seeing if correct error message is displayed by looking as system output
    """
    sc = Scanner(bad_file, names)
    parser = Parser(names, devices, network, monitors, sc)
    parser.parse_network()
    captured = capsys.readouterr()

    try:
        assert (error_message in captured.out)
    except AttributeError:
        assert (error_message in captured[0])
Пример #4
0
def test_parse_network_correct():
    """Test the overall parse.py flow with a complicated
    enough but correct definition file."""
    my_names = Names()
    my_scanner = Scanner("test_def_files/sequential.txt", my_names)
    my_devices = Devices(my_names)
    my_network = Network(my_names, my_devices)
    my_monitors = Monitors(my_names, my_devices, my_network)
    my_parser = Parser(
        my_names,
        my_devices,
        my_network,
        my_monitors,
        my_scanner)
    # Check that no semantic or syntax errors were made
    assert my_parser.parse_network()
Пример #5
0
def test_parse_network_incorrect_semantics12():
    """Test the overall parse.py flow with a definition file with incorrect
    semantics. Basically, this file opens a block comment but does not close
    it. Ensure that parser does not get stuck in infinite loop."""
    my_names = Names()
    my_scanner = Scanner("test_def_files/for_check_infiniteloop.txt", my_names)
    my_devices = Devices(my_names)
    my_network = Network(my_names, my_devices)
    my_monitors = Monitors(my_names, my_devices, my_network)
    my_parser = Parser(
        my_names,
        my_devices,
        my_network,
        my_monitors,
        my_scanner)
    # Check that parse_network() returns False
    assert not my_parser.parse_network()
Пример #6
0
def test_parse_network_incorrect_syntax():
    """Test the overall parse.py flow with a definition file
    with incorrect syntax."""
    my_names = Names()
    my_scanner = Scanner("test_def_files/srbistablewrong.txt", my_names)
    my_devices = Devices(my_names)
    my_network = Network(my_names, my_devices)
    my_monitors = Monitors(my_names, my_devices, my_network)
    my_parser = Parser(
        my_names,
        my_devices,
        my_network,
        my_monitors,
        my_scanner)
    assert not my_parser.parse_network()
    assert len(my_parser.syntax_errors_list) == 2
    assert my_parser.syntax_errors_list[0] == "start"
    assert my_parser.syntax_errors_list[1] == my_scanner.DEVICES_ID
Пример #7
0
def main(arg_list):
    """Parse the command line options and arguments specified in arg_list.

    Run either the command line user interface, the graphical user interface,
    or display the usage message.
    """
    usage_message = ("Usage:\n"
                     "Show help: logsim.py -h\n"
                     "Command line user interface: logsim.py -c <file path>\n"
                     "Graphical user interface: logsim.py <file path>")
    try:
        options, arguments = getopt.getopt(arg_list, "hc:")
    except getopt.GetoptError:
        print("Error: invalid command line arguments\n")
        print(usage_message)
        sys.exit()

    # Initialise instances of the four inner simulator classes
    names = Names()
    devices = Devices(names)
    network = Network(names, devices)
    monitors = Monitors(names, devices, network)

    for option, path in options:
        if option == "-h":  # print the usage message
            print(usage_message)
            sys.exit()
        elif option == "-c":  # use the command line user interface
            scanner = Scanner(path, names)
            parser = Parser(names, devices, network, monitors, scanner)
            if parser.parse_network():
                # Initialise an instance of the userint.UserInterface() class
                userint = UserInterface(names, devices, network, monitors)
                userint.command_interface()

    if not options:  # no option given, use the graphical user interface

        # Initialise an instance of the gui.Gui() class
        app = wx.App()
        gui = Gui("Logic Simulator")
        # gui = Gui("Logic Simulator", None, names, devices, network, monitors)
        gui.Show(True)
        app.MainLoop()
Пример #8
0
def test_parse_network_incorrect_semantics11():
    """Test the overall parse.py flow with a definition file
    with incorrect semantics."""
    my_names = Names()
    my_scanner = Scanner("test_def_files/monitordeviceabsent.txt", my_names)
    my_devices = Devices(my_names)
    my_network = Network(my_names, my_devices)
    my_monitors = Monitors(my_names, my_devices, my_network)
    my_parser = Parser(
        my_names,
        my_devices,
        my_network,
        my_monitors,
        my_scanner)
    # Check that parse_network() returns False
    assert not my_parser.parse_network()
    # Check that there are no syntax errors
    assert len(my_parser.syntax_errors_list) == 0
    # Check that 1 semantic error is logged (from actual error)
    assert len(my_parser.semantic_errors_list) == 1
    assert my_parser.semantic_errors_list[0] == my_network.DEVICE_ABSENT
Пример #9
0
def main(arg_parser):
    """Parse the command line options and arguments specified in arg_list.

    Run either the command line user interface, the graphical user interface,
    or display the usage message.
    """
    # Add check to see if path leads to a .txt file
    if arg_parser.path is not None:
        if arg_parser.path[-3:] != "txt":
            raise TypeError("***ERROR: Please load in a .txt file")
    # Check if user tries to input translation into command line
    # interface
    if arg_parser.c and arg_parser.r:
        print("Cannot launch command line mode with translator")
        sys.exit()
    # Initialise instances of the four inner simulator classes
    names = Names()
    devices = Devices(names)
    network = Network(names, devices)
    monitors = Monitors(names, devices, network)
    scanner = Scanner(arg_parser.path, names)
    parser = Parser(names, devices, network, monitors, scanner)
    if parser.parse_network():
        if arg_parser.c:
            # Initialise instance of the userint.UserInterface() class
            userint = UserInterface(names, devices, network, monitors)
            userint.command_interface()
        else:
            if arg_parser.r:
                lang = u"el"
            else:
                lang = u"en"
            # Initialise an instance of the gui.Gui() class
            file_name = get_file_name(arg_parser.path)
            title = "Logic Simulator - " + file_name
            app = wx.App()
            gui = Gui(title, arg_parser.path, names, devices, network,
                      monitors, lang)
            gui.Show(True)
            app.MainLoop()
Пример #10
0
def test_parse_network_incorrect_semantics6():
    """Test the overall parse.py flow with a definition file
    with incorrect semantics."""
    my_names = Names()
    my_scanner = Scanner("test_def_files/connectionportabsent.txt", my_names)
    my_devices = Devices(my_names)
    my_network = Network(my_names, my_devices)
    my_monitors = Monitors(my_names, my_devices, my_network)
    my_parser = Parser(
        my_names,
        my_devices,
        my_network,
        my_monitors,
        my_scanner)
    # Check that parse_network() returns False
    assert not my_parser.parse_network()
    # Check that there are no syntax errors
    assert len(my_parser.syntax_errors_list) == 0
    # Check that 2 semantic errors are logged (one from actual error, one from
    # network.check_network())
    assert len(my_parser.semantic_errors_list) == 2
    assert my_parser.semantic_errors_list[0] == my_network.PORT_ABSENT
Пример #11
0
def test_parse_network_incorrect_semantics3():
    """Test the overall parse.py flow with a definition file
    with incorrect semantics."""
    my_names = Names()
    my_scanner = Scanner("test_def_files/devicequalifierpresent.txt", my_names)
    my_devices = Devices(my_names)
    my_network = Network(my_names, my_devices)
    my_monitors = Monitors(my_names, my_devices, my_network)
    my_parser = Parser(
        my_names,
        my_devices,
        my_network,
        my_monitors,
        my_scanner)
    # Check that parse_network() returns False
    assert not my_parser.parse_network()
    # Check that there are no syntax errors
    assert len(my_parser.syntax_errors_list) == 0
    # Check that 2 semantic errors are raised (one from
    # network.check_network())
    assert len(my_parser.semantic_errors_list) == 2
    assert my_parser.semantic_errors_list[0] == my_devices.QUALIFIER_PRESENT
Пример #12
0
def main(arg_list):
    """Parse the command line options and arguments specified in arg_list.

    Run either the command line user interface, the graphical user interface,
    or display the usage message.
    """
    usage_message = (
        "Usage:\n"
        "Show help: logsim.py -h\n"
        "Command line user interface: logsim.py -c <file path>\n"
        "Graphical user interface: logsim.py <file path> or logsim.py")
    try:
        options, arguments = getopt.getopt(arg_list, "hc:")
    except getopt.GetoptError:
        print("Error: invalid command line arguments\n")
        print(usage_message)
        sys.exit()

    # Initialise instances of the four inner simulator classes
    names = Names()
    devices = Devices(names)
    network = Network(names, devices)
    monitors = Monitors(names, devices, network)
    #device = Device(self.names.lookup([names]))
    #names = None
    #devices = None
    #network = None
    #monitors = None

    for option, path in options:
        if option == "-h":  # print the usage message
            print(usage_message)
            sys.exit()
        elif option == "-c":  # use the command line user interface
            scanner = Scanner(path, names)
            parser = Parser(names, devices, network, monitors, scanner)
            if parser.parse_network():
                # Initialise an instance of the userint.UserInterface() class
                userint = UserInterface(names, devices, network, monitors)
                userint.command_interface()

    if not options:  # no option given, use the graphical user interface
        app = ab.BaseApp(redirect=False)
        error = ErrorFrame()

        if len(arguments) == 0:  # wrong number of arguments
            # Initialise an instance of the gui.Gui() class
            path = None
            #print('len(arguments) = 0 if statement is accessed')
            scanner = Scanner(path, names)
            parser = Parser(names, devices, network, monitors, scanner)
            gui = Gui("LogicSim", path, names, devices, network, monitors)
            gui.Show(True)

        elif len(arguments) != 0 and len(arguments) != 1:
            print("Error: one or no file path required\n")
            print(usage_message)
            sys.exit()

        else:
            [path] = arguments
            scanner = Scanner(path, names)
            parser = Parser(names, devices, network, monitors, scanner)
            if parser.parse_network():
                # Initialise an instance of the gui.Gui() class
                #import app_base as ab
                #app = ab.BaseApp(redirect=False)
                #app = wx.App()
                gui = Gui("LogicSim", path, names, devices, network, monitors)
                gui.Show(True)

        error.ShowModal()
        app.MainLoop()
Пример #13
0
    def execute(self, command_manager):
        """Execute load command
        Return NO_ERROR, None if successful.
        """
        self.command_manager = command_manager
        self.gui = command_manager.gui
        if self.path.split('.')[-1] == "defb":
            # File is an already built network
            with open(self.path, 'rb') as fp:
                try:
                    monitors, devices, network, names, completed_cycles = \
                        pickle.load(fp)
                except pickle.UnpicklingError:
                    return self.command_manager.INVALID_DEFINITION_FILE, None

        else:  # File is a definition file
            names = Names()
            devices = Devices(names)
            network = Network(names, devices)
            monitors = Monitors(names, devices, network)
            scanner = Scanner(self.path, names)
            parser = Parser(names, devices, network, monitors, scanner)
            completed_cycles = 0
            if not parser.parse_network():
                errors = parser.error_to_gui
                self.gui.log_text('\n'.join(errors))
                error_message = errors[0]
                return self.command_manager.INVALID_DEFINITION_FILE, \
                    error_message

        # Set new instances
        self.command_manager.monitors = monitors
        self.command_manager.devices = devices
        self.command_manager.network = network
        self.command_manager.names = names
        self.command_manager.undo_stack.clear()
        self.command_manager.redo_stack.clear()
        self.gui.monitors = self.command_manager.monitors
        self.gui.devices = self.command_manager.devices
        self.gui.network = self.command_manager.network
        self.gui.names = self.command_manager.names
        self.gui.switches = self.gui.devices.find_devices(devices.SWITCH)
        swithces_names = [
            names.get_name_string(switch_id) for switch_id in self.gui.switches
        ]
        self.gui.switches_select.Clear()
        for switch_name in swithces_names:
            self.gui.switches_select.Append(switch_name)
        self.gui.canvas_2D.monitors = self.command_manager.monitors
        self.gui.canvas_3D.monitors = self.command_manager.monitors
        self.gui.monitors_select.Clear()
        for monitor_name in self.gui.monitors.get_signal_names()[0] + \
                self.gui.monitors.get_signal_names()[1]:
            self.gui.monitors_select.Append(monitor_name)
        self.gui.canvas_2D.devices = self.command_manager.devices
        self.gui.canvas_3D.devices = self.command_manager.devices
        self.gui.update_cycles(completed_cycles)
        self.gui.switches_select.SetValue("")
        self.gui.switches_update_toggle()
        self.gui.monitors_select.SetValue("")
        self.gui.monitors_update_toggle()
        self.gui.log_text(_("Load file ") + self.path)
        self.gui.path = self.path
        self.gui.load_file_text_box.SetValue(self.path.split('/')[-1])
        self.gui.canvas.render()
        return self.command_manager.NO_ERROR, None
Пример #14
0
class ParserTestCase:
    """Receive an input file (as strings), run the parser and check the
       error code."""
    def __init__(self):
        self.testfile_name = 'testfile.txt'
        self.testfile = ''
        self.input_lines = []
        self.expected_output = []
        self.actual_output = []
        self.parser = None
        self.ErrorTuple = namedtuple('ErrorTuple', 'error, linum, pos')

    def add_input_line(self, line):
        """Add a line to the testfile."""
        if not isinstance(line, str):
            raise TypeError("the line to be added should be a str")
        self.input_lines.append(line)

    def add_expected_error(self, error_name, line_number, cursor_pos):
        """Add an expected error tuple to the output list."""
        error_tuple = self.ErrorTuple(error_name, line_number, cursor_pos)
        self.expected_output.append(error_tuple)

    def make_testfile(self):
        """Write the input lines into the testfile."""
        self.testfile = '\n'.join(self.input_lines)
        with open(self.testfile_name, 'w') as fout:
            fout.write(self.testfile)
        self.input_lines = []

    def make_parser(self):
        """Initialise a parser for the testcase."""
        if self.parser is not None:
            return None
        names = Names()
        scanner = Scanner(self.testfile_name, names)
        devices = Devices(names)
        network = Network(names, devices)
        monitors = Monitors(names, devices, network)
        self.parser = Parser(names,
                             devices,
                             network,
                             monitors,
                             scanner,
                             test_mode=True)

    def execute(self):
        """Run parser to produce the output."""
        self.make_testfile()
        self.make_parser()
        self.parser.parse_network()
        self.actual_output = self.parser.error_tuple_list
        os.remove(self.testfile_name)

    def passed(self):
        """Check whether the testcase passes."""
        if self.actual_output == self.expected_output:
            return True
        print("\nInput file:")
        print(self.testfile + '\n')
        print("actual: [", end='')
        print(("\n" + " " * 9).join(map(str, self.actual_output)), end=']\n')
        print("expect: [", end='')
        print(("\n" + " " * 9).join(map(str, self.expected_output)), end=']\n')
        return False
Пример #15
0
def main(arg_list):
    """Parse the command line options and arguments specified in arg_list.

    Run either the command line user interface, the graphical user interface,
    or display the usage message.
    """
    usage_message = ("Usage:\n"
                     "Show help: logsim.py -h\n"
                     "Command line user interface: logsim.py -c <file path>\n"
                     "Graphical user interface: logsim.py <file path>")
    try:
        options, arguments = getopt.getopt(arg_list, "hc:")
    except getopt.GetoptError:
        print("Error: invalid command line arguments\n")
        print(usage_message)
        sys.exit()

    for option, path in options:
        if option == "-h":  # print the usage message
            print(usage_message)
            sys.exit()
        elif option == "-c":  # use the command line user interface
            names = Names()
            devices = Devices(names)
            network = Network(names, devices)
            monitors = Monitors(names, devices, network)
            scanner = Scanner(path, names)
            parser = Parser(names, devices, network, monitors, scanner)
            if parser.parse_network():
                error_list = scanner.error_list
                for error in error_list:
                    print(error)
                # Initialise an instance of the userint.UserInterface() class
                userint = UserInterface(names, devices, network, monitors)
                userint.command_interface()
            else:
                error_list = scanner.error_list
                for error in error_list:
                    print(error)

    if not options:  # no option given, use the graphical user interface

        path = None
        names = None
        devices = None
        network = None
        monitors = None
        filename = None
        app = wx.App()

        # Internationalisation
        builtins._ = wx.GetTranslation
        locale = wx.Locale()
        locale.Init(wx.LANGUAGE_DEFAULT)
        locale.AddCatalogLookupPathPrefix('./locale')
        locale.AddCatalog('messages')

        gui = Gui(_("பனி Logic Simulator"), path, names, devices, network,
                  monitors, filename, True)
        gui.Show(True)
        gui.startup_load()
        app.MainLoop()

        while gui.load_new is True:
            path = gui.current_pathname
            filename = gui.current_filename
            names = Names()
            devices = Devices(names)
            network = Network(names, devices)
            monitors = Monitors(names, devices, network)
            scanner = Scanner(path, names)
            parser = Parser(names, devices, network, monitors, scanner)
            if parser.parse_network():
                # Initialise an instance of the gui.Gui() class
                gui = Gui(
                    _("பனி Logic Simulator - {}").format(filename), path,
                    names, devices, network, monitors, filename)
                gui.Show(True)
                app.MainLoop()
Пример #16
0
def test_fulladder_semantic(request, names, devices, network, monitors):
    """Testing error-less file doesn't throw errors"""
    sc = Scanner(fulladderpath, names)
    parser = Parser(names, devices, network, monitors, sc)
    assert parser.parse_network() == True
Пример #17
0
def main(arg_list):
    """Parse the command line options and arguments specified in arg_list.

    Run either the command line user interface, the graphical user interface,
    or display the usage message.
    """
    usage_message = ("Usage:\n"
                     "Show help: logsim.py -h\n"
                     "Command line user interface: logsim.py -c <file path>\n"
                     "Graphical user interface: logsim.py <file path>")
    try:
        options, arguments = getopt.getopt(arg_list, "hc:")
    except getopt.GetoptError:
        print("Error: invalid command line arguments\n")
        print(usage_message)
        sys.exit()

    # Initialise instances of the four inner simulator classes
    names = Names()
    devices = Devices(names)
    network = Network(names, devices)
    monitors = Monitors(names, devices, network)

    for option, path in options:
        if option == "-h":  # print the usage message
            print(usage_message)
            sys.exit()
        elif option == "-c":  # use the command line user interface
            scanner = Scanner(path, names)
            parser = Parser(names, devices, network, monitors, scanner)
            if parser.parse_network():
                # Initialise an instance of the userint.UserInterface() class
                userint = UserInterface(names, devices, network, monitors)
                userint.command_interface()

    if not options:  # no option given, use the graphical user interface

        if len(arguments) != 1:  # wrong number of arguments
            print("Error: one file path required\n")
            print(usage_message)
            sys.exit()

        [path] = arguments
        scanner = Scanner(path, names)
        parser = Parser(names, devices, network, monitors, scanner)
        if parser.parse_network():
            # Initialise an instance of the gui.Gui() class
            app = wx.App()
            gui = Gui("Logic Simulator", path, names, devices, network,
                      monitors)
            gui.Show(True)
            app.MainLoop()

            while hasattr(gui, 'edit_restart'):
                # GUI terminated and set the edit_restart flag.
                # We open the file in an editor to allow the user
                # to change the file, then restart the GUI.
                del app
                run_editor(path)
                # Re-initialise everything
                names = Names()
                devices = Devices(names)
                network = Network(names, devices)
                monitors = Monitors(names, devices, network)
                scanner = Scanner(path, names)
                parser = Parser(names, devices, network, monitors, scanner)
                if parser.parse_network():
                    app = wx.App()
                    gui = Gui("Logic Simulator", path, names, devices, network,
                              monitors)
                    gui.Show(True)
                    app.MainLoop()
                else:
                    # Parser error messages would be enough, no need to
                    # re-inform users of parser failure.
                    break
Пример #18
0
import scanner
from parse import Parser
from names import Names
from network import Network
from monitors import Monitors
import devices
import sys

my_names=Names()
my_scanner=scanner.Scanner(sys.argv[1], my_names)
# my_scanner=scanner.Scanner("connectioninputconnected.txt", my_names)
my_devices=devices.Devices(my_names)
my_network=Network(my_names, my_devices)
my_monitors=Monitors(my_names, my_devices, my_network)
my_parser=Parser(my_names, my_devices, my_network, my_monitors, my_scanner)
print(my_parser.parse_network())
Пример #19
0
class Gui(wx.Frame):
    """Configure the main window and all the widgets.

    This class provides a graphical user interface for the Logic Simulator and
    enables the user to change the circuit properties and run simulations.

    Parameters
    ----------
    title: title of the window.

    Public methods
    --------------
    on_menu(self, event): Event handler for the file menu. Contains About, Open and Close.

    on_spin_run(self, event): Event handler for when the user changes the spin
                           control value for number of cycles to run.

    on_spin_run(self, event): Event handler for when the user changes the spin
                           control value for number of cycles to continue.

    on_run_button(self, event): Event handler for when the user clicks the run button.

    on_run_button(self, event): Event handler for when the user clicks the continue button.

    on_switch_button(self, event): Event handler for when the user clicks the switch button.

    on_monitor_button(self, event): Event handler for when the user clicks the monitor button.

    on_restore_view_button(self, event): Event handler for when the user clicks the restore view button.  Resets the
                                         canvas to its original zoom level and orientation

    on_three_d_button(self, event): Event handler for when the user clicks the Enable 3D/Disable 3D button.

    on_quit_button(self, event): Event handler for when the user clicks the Quit button

    run_command(self): Runs the simulation from scratch.

    continue_command(self): Continues a previously run simulation.

    run_network(self, cycles): Runs the network for the specified number of
                               simulation cycles.

    monitor_command(self): Sets the specified monitor.

    zap_command(self): Removes the specified monitor.

    draw_signals(self): Obtain the monitored outputs as arrays to be drawn onto the canvas

    load_file(self): Loads the selected definition file and reinitialises the GUI parameters.

    print(self): Print messages onto the status message box
    """
    def __init__(self,
                 title,
                 path,
                 names,
                 devices,
                 network,
                 monitors,
                 app,
                 logging=False):
        """Initialise widgets and layout."""
        super().__init__(parent=None, title=title, size=(1200, 600))

        # Replicate userint.py's functionality
        self.names = names
        self.devices = devices
        self.monitors = monitors
        self.network = network
        self.path = path
        self.cycles_completed = 0  # number of simulation cycles completed

        # Configure the file menu
        fileMenu = wx.Menu()
        menuBar = wx.MenuBar()
        fileMenu.Append(wx.ID_ABOUT, _(u"&About"))
        fileMenu.Append(wx.ID_OPEN, _(u"&Open"))
        fileMenu.Append(wx.ID_EXIT, _(u"&Exit"))
        menuBar.Append(fileMenu, _(u"&File"))
        self.SetMenuBar(menuBar)

        # Canvas for drawing signals
        self.canvas = MyGLCanvas(self, self.devices, self.monitors)

        # Configure the widgets
        self.text_run_cycle = wx.StaticText(self, wx.ID_ANY, _(u"Cycles"))
        self.text_continue_cycle = wx.StaticText(self, wx.ID_ANY, _(u"Cycles"))
        self.spin_run = wx.SpinCtrl(self, wx.ID_ANY, "10")
        self.spin_continue = wx.SpinCtrl(self, wx.ID_ANY, "10")
        self.run_button = wx.Button(self, wx.ID_ANY, _(u"Run"))
        self.continue_button = wx.Button(self, wx.ID_ANY, _(u"Continue"))
        self.continue_button.Enable(False)
        self.restore_view_button = wx.Button(self, wx.ID_ANY,
                                             _(u"Restore view"))
        self.threeD_button = wx.Button(self, wx.ID_ANY, _(u"Enable 3D"))
        self.quit_button = wx.Button(self, wx.ID_ANY, _(u"Quit"))
        self.switch_button = wx.Button(self, wx.ID_ANY,
                                       _(u"Set Switches On/Off"))
        self.monitor_button = wx.Button(self, wx.ID_ANY,
                                        _(u"Set/Zap Monitors"))
        self.status_text = wx.StaticText(self, wx.ID_ANY,
                                         _(u"Status Messages:"))
        self.message = ""
        self.message_box = wx.TextCtrl(self,
                                       wx.ID_ANY,
                                       self.message,
                                       style=wx.TE_MULTILINE | wx.TE_READONLY)
        self.print(self.path)

        # Bind events to widgets
        self.Bind(wx.EVT_MENU, self.on_menu)
        self.spin_run.Bind(wx.EVT_SPINCTRL, self.on_spin_run)
        self.spin_continue.Bind(wx.EVT_SPINCTRL, self.on_spin_continue)
        self.run_button.Bind(wx.EVT_BUTTON, self.on_run_button)
        self.continue_button.Bind(wx.EVT_BUTTON, self.on_continue_button)
        self.switch_button.Bind(wx.EVT_BUTTON, self.on_switch_button)
        self.monitor_button.Bind(wx.EVT_BUTTON, self.on_monitor_button)
        self.restore_view_button.Bind(wx.EVT_BUTTON,
                                      self.on_restore_view_button)
        self.threeD_button.Bind(wx.EVT_BUTTON, self.on_three_d_button)
        self.quit_button.Bind(wx.EVT_BUTTON, self.on_quit_button)

        # Configure sizers for layout
        self.main_sizer = wx.BoxSizer(wx.HORIZONTAL)
        self.side_sizer = wx.BoxSizer(wx.VERTICAL)
        simulate_run_sizer = wx.BoxSizer(wx.HORIZONTAL)
        simulate_continue_sizer = wx.BoxSizer(wx.HORIZONTAL)
        button_sizer = wx.BoxSizer(wx.VERTICAL)
        text_sizer = wx.BoxSizer(wx.VERTICAL)

        self.main_sizer.Add(self.canvas, 5, wx.EXPAND | wx.ALL, 5)
        self.main_sizer.Add(self.side_sizer, 1, wx.ALL, 5)

        self.side_sizer.Add(simulate_run_sizer, 0, wx.TOP, 5)
        self.side_sizer.Add(simulate_continue_sizer, 0, wx.TOP, 5)
        self.side_sizer.Add(button_sizer, 1, wx.TOP, 5)
        self.side_sizer.Add(text_sizer, 5, wx.ALIGN_CENTRE | wx.EXPAND, 5)

        simulate_run_sizer.Add(self.run_button, 2, wx.ALL, 5)
        simulate_run_sizer.Add(self.spin_run, 2, wx.ALL, 5)
        simulate_run_sizer.Add(self.text_run_cycle, 1, wx.ALL, 5)
        simulate_continue_sizer.Add(self.continue_button, 2, wx.ALL, 5)
        simulate_continue_sizer.Add(self.spin_continue, 2, wx.ALL, 5)
        simulate_continue_sizer.Add(self.text_continue_cycle, 1, wx.ALL, 5)

        button_sizer.Add(self.switch_button, 1, wx.ALL, 5)
        button_sizer.Add(self.monitor_button, 1, wx.ALL, 5)
        button_sizer.Add(self.restore_view_button, 1, wx.ALL, 5)
        button_sizer.Add(self.threeD_button, 1, wx.ALL, 5)
        button_sizer.Add(self.quit_button, 1, wx.ALL, 5)

        text_sizer.Add(0, 0, 1)
        text_sizer.Add(self.status_text, 0, wx.ALL, 5)
        text_sizer.Add(self.message_box, 3, wx.EXPAND, 5)

        self.SetSizeHints(800, 400)
        self.SetSizer(self.main_sizer)

        # Configure default/initial values
        self.spin_value_run = "10"  # must be same as initial display on spin widget
        self.spin_value_continue = "10"
        self.switch_selections = []
        self.list_of_monitors = []
        self.monitor_selections = []
        self.monitor = []

        # sets whether the list of monitors in system can be changed
        self.toggle_list_of_monitors = 1
        self.toggle_run = False
        self.threeD_toggle = 0

        # enables printing to console/terminal
        self.logging = False

    def on_menu(self, event):
        """Handle the event when the user selects a menu item."""
        Id = event.GetId()
        if Id == wx.ID_EXIT:
            self.Close(True)
        if Id == wx.ID_ABOUT:
            wx.MessageBox(_(u"Logic Simulator\nCreated by Team 10\n2019"),
                          _(u"About Logsim"), wx.ICON_INFORMATION | wx.OK)
        if Id == wx.ID_OPEN:
            self.load_file()

    def on_spin_run(self, event):
        """Handle the event when the user changes the spin control value."""
        self.spin_value_run = self.spin_run.GetValue()
        text = "".join(
            [_(u"New spin control value: "),
             str(self.spin_value_run)])
        self.print(text)

    def on_spin_continue(self, event):
        """Handle the event when the user changes the spin control value."""
        self.spin_value_continue = self.spin_continue.GetValue()
        text = "".join(
            [_(u"New spin control value: "),
             str(self.spin_value_continue)])
        self.print(text)

    def on_run_button(self, event):
        """Handle the event when the user clicks the run button."""
        self.print(_(u"Run button pressed."))
        if self.toggle_run is False:
            self.toggle_run = True
            self.continue_button.Enable(True)
        self.run_command()

    def on_continue_button(self, event):
        """Handle the event when the user clicks the continue button."""
        self.print(_(u"Continue button pressed."))
        self.continue_command()

    def on_switch_button(self, event):
        """Handle the event when the user clicks the switch button."""
        self.print(_(u"Setting switches"))

        switch_list = []
        switch_id = self.devices.find_devices(self.devices.SWITCH)
        for i in range(len(switch_id)):
            k = self.names.get_name_string(switch_id[i])
            if k is not None:
                switch_list.append(k)

        switch_dialog = wx.MultiChoiceDialog(self,
                                             _(u"Set switches On/Off"),
                                             _(u"Set switches"),
                                             switch_list,
                                             style=wx.OK)
        switch_dialog.SetSelections(self.switch_selections)

        if switch_dialog.ShowModal() == wx.ID_OK:
            self.switch_selections = switch_dialog.GetSelections()

        switch_state = [0] * len(switch_list)

        for i in range(len(self.switch_selections)):
            switch_state[self.switch_selections[i]] = 1

        for i in range(len(switch_list)):
            state = self.devices.set_switch(switch_id[i], switch_state[i])
            if self.logging is True:
                if state:
                    print("Successfully set switch.")
                else:
                    print("Error! Invalid switch.")

    def on_monitor_button(self, event):
        """Handle the event when the user clicks the monitor button."""
        text = _(u"Setting/Zapping which signals to monitor")
        self.canvas.render(text)

        monitor_id_list = list(self.monitors.monitors_dictionary)

        # append devices with outputs that are not defined as monitorable in definition file.
        for device_id in self.devices.find_devices():
            device = self.devices.get_device(device_id)
            for output_id in device.outputs:
                if (device_id,
                        output_id) not in self.monitors.monitors_dictionary:
                    monitor_id_list.append((device_id, output_id))

        for i in range(len(monitor_id_list)):
            if monitor_id_list[i][0] is None:
                return None
            elif monitor_id_list[i][1] is not None:
                port_id = monitor_id_list[i][1]
                if port_id is None:
                    return None
            else:
                port_id = None

            string_name = self.names.get_name_string(monitor_id_list[i][0])

            if port_id is not None:
                port_name = self.names.get_name_string(monitor_id_list[i][1])
            else:
                port_name = ""
            if string_name is not None:

                # only append to this list the first time button is clicked
                if self.toggle_list_of_monitors == 1:
                    self.list_of_monitors.append(
                        str(string_name) + "." + str(port_name))
                    self.monitor.append([monitor_id_list[i][0], port_id])

        # prevent self.list_of_monitors and self.monitors from being overwritten when zapped
        self.toggle_list_of_monitors = 0

        monitor_dialog = wx.MultiChoiceDialog(
            self,
            _(u"Set/Zap which signals to monitor"),
            _(u"Set/Zap signals"),
            self.list_of_monitors,
            style=wx.OK)
        monitor_dialog.SetSelections(self.monitor_selections)

        signal_state = [0] * len(self.list_of_monitors)

        if monitor_dialog.ShowModal() == wx.ID_OK:
            self.monitor_selections = monitor_dialog.GetSelections()

        for i in range(len(self.monitor_selections)):
            signal_state[self.monitor_selections[i]] = 1

        if sum(signal_state) == 0:
            self.print(_(u"All monitors are zapped."))

        for i in range(len(signal_state)):
            if signal_state[i] == 1:
                self.monitor_command(self.monitor[i])
            elif signal_state[i] == 0:
                self.zap_command(self.monitor[i])
            else:
                raise ValueError

    def on_restore_view_button(self, event):
        """" Handles the event when restore view button is clicked. Resets the canvas to its original zoom level and
        orientation"""
        self.canvas.reset_view()

    def on_three_d_button(self, event):
        """ Handles the event for when the user clicks the Enable 3D/Disable 3D button.
            renders the signals in 2D or 3D. """
        if self.threeD_toggle:
            self.threeD_button.SetLabel(_(u"Enable 3D"))
            self.threeD_toggle = False
            self.canvas.toggle_3D = False
            self.canvas.init = False
            self.canvas.Refresh()
            self.canvas.reset_view()
        else:
            self.threeD_button.SetLabel(_(u"Disable 3D"))
            self.threeD_toggle = True
            self.canvas.toggle_3D = True
            self.canvas.init = False
            self.canvas.Refresh()
            self.canvas.reset_view()

    def on_quit_button(self, event):
        """ Handles the event when Quit button is clicked. Ends the program and closes the window."""
        self.Close()

    # ported from userint.py and changed slightly
    def run_command(self):
        """Run the simulation from scratch."""
        self.cycles_completed = 0
        cycles = int(self.spin_value_run)

        if cycles is not None:  # if the number of cycles provided is valid
            self.monitors.reset_monitors()
            self.print("".join(
                [_(u"Running for "),
                 str(cycles), _(u" cycles")]))
            self.devices.cold_startup()
            if self.run_network(cycles):
                self.cycles_completed += cycles

        self.draw_signals()

    def continue_command(self):
        """Continue a previously run simulation."""
        cycles = int(self.spin_value_continue)
        if cycles is not None:  # if the number of cycles provided is valid
            if self.cycles_completed == 0:
                self.print(_(u"Error! Nothing to continue. Run first."))
            elif self.run_network(cycles):
                self.cycles_completed += cycles
                self.print(" ".join([
                    _(u"Continuing for"),
                    str(cycles),
                    _(u"cycles."),
                    _(u"Total:"),
                    str(self.cycles_completed)
                ]),
                           append=True)

        self.draw_signals()

    def run_network(self, cycles):
        """Run the network for the specified number of simulation cycles.

        Return True if successful.
        """
        for _ in range(cycles):
            if self.network.execute_network():
                self.monitors.record_signals()
            else:
                self.print(_(u"Error! Network oscillating."))
                return False
        # self.monitors.display_signals()
        return True

    def monitor_command(self, monitor):
        """Set the specified monitor."""
        if monitor is not None:
            [device, port] = monitor
            monitor_error = self.monitors.make_monitor(device, port,
                                                       self.cycles_completed)
            if self.logging:
                if monitor_error == self.monitors.NO_ERROR or self.monitors.MONITOR_PRESENT:
                    print("Successfully made monitor.")
                else:
                    print("Error! Could not make monitor.")

    def zap_command(self, monitor):
        """Remove the specified monitor."""
        if monitor is not None:
            [device, port] = monitor
            if self.monitors.get_monitor_signal(device, port) is not None:
                if self.monitors.remove_monitor(device, port):
                    if self.logging:
                        print("Successfully zapped monitor")
                else:
                    if self.logging:
                        print("Error! Could not zap monitor.")
            else:
                if self.logging:
                    print("Monitor was already zapped")

    def draw_signals(self):
        """"Obtain the monitored outputs as arrays to be drawn onto the canvas"""
        margin = self.monitors.get_margin()
        text_array = []
        signal_array = []
        for device_id, output_id in self.monitors.monitors_dictionary:
            monitor_name = self.devices.get_signal_name(device_id, output_id)
            name_length = len(monitor_name)
            signal_list = self.monitors.monitors_dictionary[(device_id,
                                                             output_id)]
            text = monitor_name + (margin - name_length) * " "
            signal_array.append(signal_list)
            text_array.append(text)

        self.canvas.draw_signals(text_array, signal_array)

    def load_file(self):
        """Loads the selected definition file and reinitialises the GUI parameters. """
        with wx.FileDialog(self,
                           "Open test definition file",
                           wildcard="TXT files (*.txt)|*.txt",
                           style=wx.FD_OPEN
                           | wx.FD_FILE_MUST_EXIST) as fileDialog:
            if fileDialog.ShowModal() == wx.ID_CANCEL:
                return  # the user changed their mind

            # Proceed loading the file chosen by the user
            self.path = fileDialog.GetPath()
            try:
                self.names = Names()
                self.devices = Devices(self.names)
                self.network = Network(self.names, self.devices)
                self.monitors = Monitors(self.names, self.devices,
                                         self.network)
                self.scanner = Scanner(self.path, self.names)
                self.parser = Parser(self.names, self.devices, self.network,
                                     self.monitors, self.scanner)
                self.parser.parse_network()
                self.cycles_completed = 0  # number of simulation cycles completed
                self.canvas.devices = self.devices

                # Configure default/initial values
                self.switch_selections = []
                self.list_of_monitors = []
                self.monitor_selections = []
                self.monitor = []

                # sets whether the list of monitors in system can be changed
                self.toggle_list_of_monitors = 1
                self.toggle_run = False

            except IOError:
                self.print(_(u"Cannot open file '%s'.") % self.path)

    def print(self, text, append=False):
        """Print messages onto the status message box"""
        if append:
            self.message_box.WriteText(text)
        else:
            self.message_box.Clear()
            self.message_box.WriteText(text)
Пример #20
0
class Gui(wx.Frame):
    """Configure the main window and all the widgets.

    This class provides a graphical user interface for the Logic Simulator and
    enables the user to change the circuit properties and run simulations.

    Parameters
    ----------
    title: title of the window.

    Public methods
    --------------
    on_menu(self, event): Event handler for the file menu.

    on_size(self, event): Event handler for window resizing.

    on_reload(self): Handle the event when the user reloads the file.

    on_lang_change(self): Show dialog for language change.

    on_toggle_3d_vew(self): Toggle 3D view.

    on_help(self): Shows a help window with user instructions.

    on_center(self): Centers the canvas to its default state of zoom and
                     panning.

    on_continue(self): Run the continue_command when continue button pressed.

    continue_command(self): Continue a previously run simulation.

    on_run(self): Run the run_command when run button pressed.

    run_command(self): Run the simulation from scratch.

    run_network(self, cycles): Run the network for the specified number of
                               simulation cycles.

    on_open(self): Open the file browser and parse the file chosen.

    load_file(self, file_path): Load a file for parsing and running.

    run_parser(self, file_path): Reset modules and call parse_network.

    clear_log(self): Clear the activity log.

    log_message(self, text, style, no_new_line): Add message to the activity
                                                 log.

    set_switch(self, switch_name, is_on): Turn a swtich on and off.

    set_monitor(self, monitor_name, is_active): Activate or deactivate a
                                                monitor.

    update_tabs(self): Update the right panel tabs with new values.

    update_texts(self): Updates the text fields of the application after
                        a change of locale.

    make_right_sizer(self): Helper function that creates the right panel sizer.

    def update_language(self, lang): Update the language to the requested one.
    """
    def __init__(self, title):
        """Initialise widgets and layout."""
        super().__init__(parent=None, title=title, size=(800, 600))
        self.names = Names()
        self.devices = Devices(self.names)
        self.network = Network(self.names, self.devices)
        self.monitors = Monitors(self.names, self.devices, self.network)

        # work around for Python stealing "_"
        sys.displayhook = _displayHook

        # Add locale path and update the language
        self.locale = None
        wx.Locale.AddCatalogLookupPathPrefix('locale')
        sys_lang = wx.Locale.GetSystemLanguage()
        lang_name = wx.Locale.GetLanguageCanonicalName(sys_lang)
        self.update_language(lang_name[:2])

        # Add fonts
        self.NORMAL_FONT = wx.TextAttr()
        self.MONOSPACE_FONT = wx.TextAttr(
            'BLACK',
            font=wx.Font(wx.FontInfo(10).Family(wx.FONTFAMILY_TELETYPE)))

        # Add IDs for menu and toolbar items
        self.ID_OPEN = 1001
        self.ID_CENTER = 1002
        self.ID_RUN = 1003
        self.ID_CONTINUE = 1004
        self.ID_CYCLES_CTRL = 1005
        self.ID_HELP = 1006
        self.ID_CLEAR = 1007
        self.ID_TOGGLE_3D = 1008
        self.ID_LANG = 1009
        self.ID_RELOAD = 1010

        # Configure the file menu
        fileMenu = wx.Menu()
        viewMenu = wx.Menu()
        runMenu = wx.Menu()
        optionsMenu = wx.Menu()
        helpMenu = wx.Menu()
        menuBar = wx.MenuBar()

        fileMenu.Append(self.ID_OPEN, _("&Open") + "\tCtrl+O")
        fileMenu.Append(self.ID_RELOAD, _("&Reload") + "\tCtrl+R")
        fileMenu.Append(wx.ID_EXIT, _("&Exit"))

        viewMenu.Append(self.ID_CENTER, _("&Center") + "\tCtrl+E")
        viewMenu.Append(self.ID_TOGGLE_3D,
                        _("&Toggle 2D/3D view") + "\tCtrl+T")
        viewMenu.Append(self.ID_CLEAR, _("&Clear Activity Log") + "\tCtrl+L")

        runMenu.Append(self.ID_RUN, _("R&un") + "\tCtrl+Shift+R")
        runMenu.Append(self.ID_CONTINUE, _("&Continue") + "\tCtrl+Shift+C")

        optionsMenu.Append(self.ID_LANG, _("Change &Language"))

        helpMenu.Append(self.ID_HELP, _("&Help") + "\tCtrl+H")
        helpMenu.Append(wx.ID_ABOUT, _("&About"))

        menuBar.Append(fileMenu, _("&File"))
        menuBar.Append(viewMenu, _("&View"))
        menuBar.Append(runMenu, _("&Simulation"))
        menuBar.Append(optionsMenu, _("O&ptions"))
        menuBar.Append(helpMenu, _("&Help"))
        self.SetMenuBar(menuBar)

        # Load icons
        appIcon = wx.Icon("res/cylinder.png")
        self.SetIcon(appIcon)
        openIcon = wx.Bitmap("res/open_mat.png")
        reloadIcon = wx.Bitmap("res/reload_mat.png")
        centerIcon = wx.Bitmap("res/center_mat.png")
        runIcon = wx.Bitmap("res/run.png")
        continueIcon = wx.Bitmap("res/continue_mat.png")
        infoIcon = wx.Bitmap("res/info_mat_outline.png")
        self.layout2dIcon = wx.Bitmap("res/layout2d.png")
        self.layout3dIcon = wx.Bitmap("res/layout3d.png")
        flagIcon = langlc.GetLanguageFlag(self.locale.GetLanguage())

        # Configure toolbar
        # Keep a reference to the toolBar to update its icons
        self.toolBar = self.CreateToolBar()
        # TODO Change names icons and event handling of tools
        # TODO Add Shorthelp option to tools (i.e. tooltip)
        # TODO Create matching options in the fileMenu and associate them
        # with shortcuts
        self.spin = wx.SpinCtrl(self.toolBar, value='10')
        self.toolBar.AddTool(self.ID_OPEN, "Tool2", openIcon)
        self.toolBar.AddTool(self.ID_RELOAD, "Tool8", reloadIcon)
        self.toolBar.AddSeparator()
        self.toolBar.AddTool(self.ID_CENTER, "Tool3", centerIcon)
        self.toolBar.AddTool(self.ID_TOGGLE_3D, "Tool6", self.layout3dIcon)
        self.toolBar.AddSeparator()
        self.toolBar.AddTool(self.ID_RUN, "Tool4", runIcon)
        self.toolBar.AddTool(self.ID_CONTINUE, "Tool5", continueIcon)
        self.toolBar.AddControl(self.spin, "SpinCtrl")
        self.toolBar.AddSeparator()
        self.toolBar.AddTool(self.ID_LANG, "Tool7", flagIcon)
        self.toolBar.AddSeparator()
        self.toolBar.AddTool(self.ID_HELP,
                             "Tool1",
                             infoIcon,
                             shortHelp=_("Help"))
        self.SetToolBar(self.toolBar)

        # State variables
        self.current_file_path = None  # set current file path
        self.parse_success = False  # prevents run and continue if parse fails
        self.canvas_mode = '2d'  # current display mode of canvas
        self.cycles_completed = 0  # number of simulation cycles completed

        # Canvas for drawing signals
        self.canvas = MyGLCanvasWrapper(self)

        # Configure the widgets
        self.activity_log = wx.TextCtrl(self,
                                        wx.ID_ANY,
                                        _("Ready. Please load a file."),
                                        style=wx.TE_MULTILINE | wx.TE_READONLY)
        self.activity_log_label = wx.StaticText(self, label=_("Activity Log"))

        # Bind events to widgets
        self.Bind(wx.EVT_MENU, self.on_menu)
        self.Bind(wx.EVT_SIZE, self.on_size)

        # Configure sizers for layout
        main_sizer = wx.BoxSizer(wx.HORIZONTAL)
        right_sizer = wx.BoxSizer(wx.VERTICAL)
        left_sizer = wx.BoxSizer(wx.VERTICAL)

        left_sizer.Add(self.canvas, 3, wx.EXPAND | wx.ALL, 5)
        left_sizer.Add(self.activity_log_label, 0.2, wx.EXPAND | wx.ALL, 5)
        left_sizer.Add(self.activity_log, 1, wx.EXPAND | wx.ALL, 5)

        right_sizer = self.make_right_sizer()

        main_sizer.Add(left_sizer, 5, wx.EXPAND | wx.ALL, 5)
        main_sizer.Add(right_sizer, 0, wx.EXPAND | wx.ALL, 5)

        self.SetSizeHints(1200, 800)
        self.SetSizer(main_sizer)

    def make_right_sizer(self):
        """Helper function that creates the right sizer"""
        right_sizer = wx.BoxSizer(wx.VERTICAL)

        # Create the notebook to hold tabs
        self.notebook = wx.Notebook(self, size=(200, -1))

        # Create the tabs
        self.monitor_tab = CustomTab(self.notebook)
        self.switch_tab = CustomTab(self.notebook)
        self.monitor_tab.set_on_item_selected_listener(self.set_monitor)
        self.switch_tab.set_on_item_selected_listener(self.set_switch)

        self.notebook.AddPage(self.monitor_tab, _("Monitors"))
        self.notebook.AddPage(self.switch_tab, _("Switches"))

        right_sizer.Add(self.notebook, 1, wx.EXPAND | wx.ALL, 5)
        return right_sizer

    def update_language(self, lang):
        """
        Update the language to the requested one.

        Make *sure* any existing locale is deleted before the new
        one is created.  The old C++ object needs to be deleted
        before the new one is created, and if we just assign a new
        instance to the old Python variable, the old C++ locale will
        not be destroyed soon enough, likely causing a crash.

        :param string `lang`: one of the supported language codes

        """
        # if an unsupported language is requested default to English
        if lang in appC.supLang:
            selLang = appC.supLang[lang]
        else:
            selLang = wx.LANGUAGE_ENGLISH

        if self.locale:
            assert sys.getrefcount(self.locale) <= 2
            del self.locale

        # create a locale object for this language
        self.locale = wx.Locale(selLang)
        if self.locale.IsOk():
            self.locale.AddCatalog(appC.langDomain)
        else:
            self.locale = None

    def update_texts(self):
        """Updates the text fields around the application after a change
        of locale.
        """

        # Update menu items
        # WARNING: This update assumes a certain order of menus
        # Does NOT scale; Consider refactoring for robustness
        # 0 -> files
        # 1 -> view
        # 2 -> simulation
        # 3 -> options
        # 4 -> help
        menuBar = self.GetMenuBar()
        menuBar.SetMenuLabel(0, _("&File"))
        menuBar.SetMenuLabel(1, _("&View"))
        menuBar.SetMenuLabel(2, _("&Simulation"))
        menuBar.SetMenuLabel(3, _("O&ptions"))
        menuBar.SetMenuLabel(4, _("&Help"))

        # Update menu subitems
        menuBar.SetLabel(self.ID_OPEN, _("&Open") + "\tCtrl+O")
        menuBar.SetLabel(self.ID_RELOAD, _("&Reload") + "\tCtrl+R")
        menuBar.SetLabel(wx.ID_EXIT, _("&Exit"))

        menuBar.SetLabel(self.ID_CENTER, _("&Center") + "\tCtrl+E")
        menuBar.SetLabel(self.ID_TOGGLE_3D,
                         _("&Toggle 2D/3D vew") + "\tCtrl+T")
        menuBar.SetLabel(self.ID_CLEAR, _("&Clear Activity Log") + "\tCtrl+L")
        menuBar.SetLabel(self.ID_LANG, _("Change &Language"))

        menuBar.SetLabel(self.ID_RUN, _("&Run") + "\tCtrl+Shift+R")
        menuBar.SetLabel(self.ID_CONTINUE, _("&Continue") + "\tCtrl+Shift+C")

        menuBar.SetLabel(self.ID_HELP, _("&Help") + "\tCtrl+H")
        menuBar.SetLabel(wx.ID_ABOUT, _("&About"))

        # Update toolbar tooltips
        # TODO

        # Update flag icon
        flagIcon = langlc.GetLanguageFlag(self.locale.GetLanguage())
        self.GetToolBar().SetToolNormalBitmap(self.ID_LANG, flagIcon)

        # Update right panel
        self.notebook.SetPageText(0, _("Monitors"))
        self.notebook.SetPageText(1, _("Switches"))
        self.monitor_tab.update_texts()
        self.switch_tab.update_texts()

        # Update static texts
        self.activity_log_label.SetLabel(_("Activity Log"))

    def update_tabs(self):
        """Update the tabs with new values."""

        # Get monitor names
        [mons, non_mons] = self.monitors.get_signal_names()

        # Get switch names
        switch_ids = self.devices.find_devices(self.devices.SWITCH)
        switch_names = [
            self.names.get_name_string(sw_id) for sw_id in switch_ids
        ]
        switch_signals = [
            self.devices.get_device(sw_id).switch_state for sw_id in switch_ids
        ]
        switch_states = [
            True if sig in [self.devices.HIGH, self.devices.RISING] else False
            for sig in switch_signals
        ]

        # Reset tab elements
        self.monitor_tab.clear()
        self.monitor_tab.append(list(zip(mons, [True for i in mons])))
        self.monitor_tab.append(list(zip(non_mons, [False for i in non_mons])))
        self.switch_tab.clear()
        self.switch_tab.append(list(zip(switch_names, switch_states)))

    def set_monitor(self, monitor_name, is_active):
        """Activate or deactivate a monitor.

        Parameters
        ----------
        monitor_id: The id of the monitor to change state
        is_active: The state of the monitor; True to activate
                   and False to deactivate
        """
        # Split the monitor to device name and port name if it exists
        splt = monitor_name.split('.')
        if len(splt) == 1:
            # No port given
            device_id = self.names.query(splt[0])
            port_id = None
        elif len(splt) == 2:
            # Port given
            device_id = self.names.query(splt[0])
            port_id = self.names.query(splt[1])
        else:
            # TODO: Print error
            pass

        if device_id is None:
            # TODO: Reformat error text for consistency with parser
            self.log_message(
                _("Error: Monitor {} not found.").format(monitor_name))
            return
        # Add/remove monitor
        if is_active:
            action = _("activated")
            monitor_error = self.monitors.make_monitor(device_id, port_id,
                                                       self.cycles_completed)
            if monitor_error == self.monitors.NO_ERROR:
                self.log_message(
                    _("Monitor {} was {}.").format(monitor_name, action))
            else:
                # TODO: Print error
                return
        else:
            action = _("deactivated")
            if self.monitors.remove_monitor(device_id, port_id):
                self.log_message("Monitor {} was {}.".format(
                    monitor_name, action))
            else:
                # TODO: Print error
                return
        self.canvas.restore_state()
        self.canvas.render(_("Monitor changed"))

    def set_switch(self, switch_name, is_on):
        """Turn a swtich on and off.

        Parameters
        ----------
        switch_id: The id of the switch to change output
        is_on: The state of the monitor; True to turn on
               and False to turn off

        """
        # Get the switch id
        switch_id = self.names.query(switch_name)

        if switch_id is None:
            # TODO: Reformat error text for consistency with parser
            self.log_message(
                _("Error: Monitor {} not found.").format(monitor_name))
            return
        # Turn on/off the switch
        if is_on:
            switch_state = 1
            state_text = _("ON")
        else:
            switch_state = 0
            state_text = _("OFF")
        if self.devices.set_switch(switch_id, switch_state):
            self.log_message(
                _("Switch {} was switched {}").format(switch_name, state_text))
        else:
            # TODO: Print error
            return

    def clear_log(self):
        """Clear the activity log."""
        self.activity_log.Clear()

    def log_message(self, text, style=None, no_new_line=False):
        """Add message to the activity log."""
        if style is not None:
            self.activity_log.SetDefaultStyle(style)
        if no_new_line:
            self.activity_log.AppendText(str(text))
        else:
            self.activity_log.AppendText("\n" + str(text))
        self.activity_log.ShowPosition(self.activity_log.GetLastPosition())
        self.activity_log.SetDefaultStyle(self.NORMAL_FONT)

    #################
    # author: Jorge #
    #################

    def run_parser(self, file_path):
        """Call parse_network() from path specified.

        To do so first reinitzialize all modules and cycles_completed.
        """
        # clear all at the begging
        self.cycles_completed = 0
        self.names = Names()
        self.devices = Devices(self.names)
        self.network = Network(self.names, self.devices)
        self.monitors = Monitors(self.names, self.devices, self.network)
        self.scanner = Scanner(file_path, self.names)
        self.parser = Parser(self.names, self.devices, self.network,
                             self.monitors, self.scanner)
        # Capture the stdout from parse_network()
        captured_stdout = io.StringIO()
        with redirect_stdout(captured_stdout):
            if self.parser.parse_network():
                self.parse_success = True
                self.log_message(_("Succesfully parsed network."))
            else:
                self.parse_success = False
                self.log_message(_("Failed to parse network."))
                # Show error messages captured in activity log
                self.log_message(captured_stdout.getvalue(),
                                 self.MONOSPACE_FONT)

    def load_file(self, file_path):
        """Load a file for parsing and running."""
        self.run_parser(file_path)
        self.canvas.restore_state()
        self.update_tabs()

    def on_open(self):
        """Open the file browser and parse the file chosen."""
        text = _("Open file dialog.")
        openFileDialog = wx.FileDialog(
            self,
            _("Open"),
            wildcard="Circuit Definition files (*.txt;*.lcdf)|*.txt;*.lcdf",
            style=wx.FD_OPEN | wx.FD_FILE_MUST_EXIST)
        res = openFileDialog.ShowModal()
        if res == wx.ID_OK:  # user selected a file
            self.current_file_path = openFileDialog.GetPath()
            self.clear_log()
            self.log_message(_("File opened: {}").format(
                self.current_file_path),
                             no_new_line=True)
            self.load_file(self.current_file_path)
            self.canvas.render(_("Opened file"))

    def run_network(self, cycles):
        """Run the network for the specified number of simulation cycles.

        Return True if successful.
        """
        for i in range(cycles):
            if self.network is None:
                self.log_message(_("Error! No file loaded."))
                return False
            if self.network.execute_network():
                self.monitors.record_signals()
            else:
                self.log_message(_("Error! Network oscillating."))
                return False
        return True

    def run_command(self):
        """Run the simulation from scratch."""
        if not self.parse_success:
            self.log_message(_("Error! Nothing to run. Parsing failed."))
            return
        self.cycles_completed = 0
        cycles = self.spin.GetValue()  # this must get input from other box

        if cycles is not None:  # if the number of cycles provided is valid
            self.monitors.reset_monitors()
            self.log_message(_("Running for {} cycles").format(cycles))
            self.devices.cold_startup()
            if self.run_network(cycles):
                self.cycles_completed += cycles

    def on_run(self):
        """Run the run_command when run button pressed."""
        self.run_command()
        self.canvas.recenter()
        self.canvas.render(_("RUN"))

    def continue_command(self):
        """Continue a previously run simulation."""
        if not self.parse_success:
            self.log_message(_("Error! Nothing to continue. Parsing failed."))
            return
        cycles = self.spin.GetValue()
        if cycles is not None:  # if the number of cycles provided is valid
            if self.cycles_completed == 0:
                self.log_message(_("Error! Nothing to continue. Run first."))
            elif self.run_network(cycles):
                self.cycles_completed += cycles
                self.log_message(
                    _("Continuing for {} cycles. Total: {}").format(
                        cycles, self.cycles_completed))

    def on_continue(self):
        """Run the continue_command when run button pressed."""
        self.continue_command()
        self.canvas.render(_("Continue"))
        self.canvas.recenter(pan_to_end=True)

    ####################
    # author: Dimitris #
    ####################

    def on_center(self):
        """Centers the canvas to its default state of zoom and panning."""
        self.log_message(_("Center canvas."))
        self.canvas.recenter()

    def on_help(self):
        """Shows a help window with user instructions."""
        help_title = _("Help - Program controls ")
        # TODO Find a more elegant way to provide localisation for this text
        help_content = ("" + _("Shortcuts: \n") + _("Ctrl + O: Open file\n") +
                        _("Ctrl + H: Help\n") + _("Ctrl + R: Run\n") +
                        _("Ctrl + Shift + C: Continue\n") +
                        _("Ctrl + E: Center canvas\n") +
                        _("Ctrl + T: Toggle 2D/3D view\n") +
                        _("Ctrl + L: Clear activity log\n\n") +
                        _("User Instructions:\n") +
                        _("Use the Open file button to select ") +
                        _("the desired circuit defnition file.") +
                        _("If the file contains no errors the activity") +
                        _(" log at the bottom of the window") +
                        _("will read \"Succesfully parsed network\". ") +
                        _("If there are errors, the activity log") +
                        _("will read \"Failed to parse network\".\n\n") +
                        _("If the network was parsed correctly it can be"
                          "ran. ") + _("Use the plus and minus on the") +
                        _("cycle selector to select the desired number") +
                        _(" of cycles for the simulation or") +
                        _("type in th desired number. Press the Run ") +
                        _("button to run the simulator for the number") +
                        _("of cycles selected and display the waveforms ") +
                        _("at the current monitor points (from a") +
                        _("cold-startup of the circuit). Press the ") +
                        _("Continue button to run the simulator") +
                        _("for an additional number of cycles as selected ") +
                        _("in the cycle selector and") +
                        _("display the waveforms at the current monitor "
                          "points.\n\n") +
                        _("The canvas can be restored to its default state ") +
                        _("of position and zoomby") +
                        _("selecting the center button.\n\n") +
                        _("Different monitor points can be set ") +
                        _("and zapped by first selecting the") +
                        _("Monitors tab on the right panel, and then ") +
                        _("selecting the desired monitor") +
                        _("point from the list.\n\n") +
                        _("Switches can be operated by first selecting ") +
                        _("the Switches tab on the right") +
                        _("panel, and then selecting the desired switches."))

        wx.MessageBox(help_content, help_title, wx.ICON_INFORMATION | wx.OK)

    def on_toggle_3d_vew(self):
        """Toggle 3D view."""
        if self.canvas_mode == '2d':
            self.canvas_mode = '3d'
            self.toolBar.SetToolNormalBitmap(self.ID_TOGGLE_3D,
                                             self.layout2dIcon)
        else:
            self.canvas_mode = '2d'
            self.toolBar.SetToolNormalBitmap(self.ID_TOGGLE_3D,
                                             self.layout3dIcon)
        self.canvas.toggle_drawing_mode()

    ##################
    # author: George #
    ##################

    def on_lang_change(self):
        """Show dialog for language change."""
        dlg = LangDialog(
            self,
            -1,
            _("Pick your language"),
            self.locale.GetLanguage(),
            size=(350, 200),
            style=wx.DEFAULT_DIALOG_STYLE,
        )

        # This does not return until the dialog is closed.
        val = dlg.ShowModal()

        sel_lang = dlg.GetLangSelected()
        if val == wx.ID_OK:
            # User pressed OK
            self.update_language(
                wx.Locale.GetLanguageCanonicalName(sel_lang)[:2])
            self.update_texts()

        dlg.Destroy()

    def on_reload(self):
        """Handle the event when the user reloads the file."""
        if self.current_file_path is None:
            # No file has been loaded
            self.log_message(_("No file loaded. Please load a file."))
            return
        self.clear_log()
        self.log_message(_("File reloaded: {}").format(self.current_file_path),
                         no_new_line=True)
        self.load_file(self.current_file_path)

    def on_menu(self, event):
        """Handle the event when the user selects a menu item."""
        Id = event.GetId()
        if Id == wx.ID_EXIT:
            self.Close(True)
        elif Id == wx.ID_ABOUT:
            wx.MessageBox(_("Logic Simulator\nCreated by Psylinders\n2019"),
                          _("About Logsim"), wx.ICON_INFORMATION | wx.OK)
        elif Id == self.ID_OPEN:  # file dialog
            self.on_open()
        elif Id == self.ID_RUN:  # run button
            self.on_run()
        elif Id == self.ID_CONTINUE:  # continue button
            self.on_continue()
        elif Id == self.ID_CENTER:  # center button
            self.on_center()
        elif Id == self.ID_HELP:  # help button
            self.on_help()
        elif Id == self.ID_CLEAR:  # help button
            self.clear_log()
        elif Id == self.ID_TOGGLE_3D:  # togge 3D view button
            self.on_toggle_3d_vew()
        elif Id == self.ID_LANG:
            self.on_lang_change()
        elif Id == self.ID_RELOAD:
            self.on_reload()

    def on_size(self, event):
        """Handle the event when the window resizes."""
        self.Refresh()
        event.Skip()
Пример #21
0
def main(arg_list):
    """Parse the command line options and arguments specified in arg_list.

    Run either the command line user interface, the graphical user interface,
    or display the usage message.
    """
    print('arg_list', arg_list)
    usage_message = ("Usage:\n"
                     "Show help: logsim.py -h\n"
                     "Command line user interface: logsim.py -c <file path>\n"
                     "Graphical user interface: logsim.py <file path>")
    try:
        options, arguments = getopt.getopt(arg_list, "hc:")
    except getopt.GetoptError:
        print(_(u"Error: invalid command line arguments\n"))
        print(usage_message)
        sys.exit()

    # Initialise instances of the four inner simulator classes
    names = Names()
    devices = Devices(names)
    network = Network(names, devices)
    monitors = Monitors(names, devices, network)

    for option, path in options:
        if option == "-h":  # print the usage message
            print(usage_message)
            sys.exit()
        elif option == "-c":  # use the command line user interface
            scanner = Scanner(path, names)
            parser = Parser(names, devices, network, monitors, scanner)
            if parser.parse_network():
                # Initialise an instance of the userint.UserInterface() class
                userint = UserInterface(names, devices, network, monitors)
                userint.command_interface()

    if not options:  # no option given, use the graphical user interface

        if len(arguments) != 1:
            if len(arguments) == 2:  # wrong number of arguments
                [path] = [arguments[0]]
            else:
                print(_(u"Error: one file path required\./logsim.yn"))
                print(usage_message)
                sys.exit()
        else:
            [path] = arguments

        scanner = Scanner(path, names)
        parser = Parser(names, devices, network, monitors, scanner)
        if parser.parse_network():
            # Initialise an instance of the gui.Gui() class

            app = ab.BaseApp(redirect=False)
            language = LanguageGui()
            language.Show(True)
            app.MainLoop()

            from gui_3D import lang

            app = ab.BaseApp(redirect=False)
            if lang == "Chinese":
                app.updateLanguage(u"zh_CN")
            gui = Gui(_(u"Logic Simulator"), path, names, devices, network,
                      monitors, app)
            gui.Show(True)
            gui.load_file()
            app.MainLoop()
Пример #22
0
class Gui(wx.Frame):
    """
    Configure the main window and all the widgets.

    This class provides a graphical user interface for the Logic Simulator and
    enables the user to change the circuit properties and run simulations.

    Parameters
    ----------
    title: Title of the window.
    path: Path of circuit specification file
    names: instance of the names.Names() class.
    devices: instance of the devices.Devices() class.
    monitors: instance of the monitors.Monitors() class.
    network: instance of the network.Network() class.
    lang: Language specification.

    Public methods
    --------------
    on_menu(self, event): Event handler for the file menu.
    on_run_button(self, event): Event handler for when the user clicks the run
                                button.
    on_continue_button(self, event): Event handler for when the user clicks the
                                     continue button.
    on_config_button(self, event): Event handler for when user clicks apply
                                   button.
    on_show(self, event): Event handler for when user clicks show button.
    on_remove(self, event): Event handler for when user clicks remove button.
    on_conf_select(self, event): Update current conf var shown in gui
                                 when new config device selected.
    on_open(self): Handles event of loading a new circuit file in GUI.
    on_2D(self, event): Handles event when user clicks 2D view button.
    on_3D(self, event):Handles event when user clicks 3D view button.
    on_reset(self, event): Handles event when user clicks reset button.
    updateLanguage(self, lang): Update language shown in GUI.

    Private methods
    ---------------
    _re_render(self): Rerenders traces and labels after any action.
    _gen_lists(self): Set self.outputs, self.configurable, self.monitored.
    _run_network(self, cycles, warm_flag): Run network in response
                                           to some change.
    _verify_number(self, num, lower_bound, upper_bound): Validate config var.
    _regen_monitored(self): Update monitor display in GUI.
    _get_file_name(self, path_name): Extracts file name from path.
    _update_labels(self): Updates widget labels with selected language.
    """
    def __init__(self,
                 title,
                 path,
                 names,
                 devices,
                 network,
                 monitors,
                 lang=u"en"):
        """Initialise widgets and layout."""
        super().__init__(parent=None, title=title, size=(928, 700))

        # Set locale
        self.locale = None
        wx.Locale.AddCatalogLookupPathPrefix('locale')
        self.updateLanguage(lang)
        # Configure the file menu
        self.fileMenu = wx.Menu()
        self.fileMenu.Append(wx.ID_ABOUT, _(u"&About"))
        self.fileMenu.Append(wx.ID_EXIT, _(u"&Exit"))
        self.fileMenu.Append(wx.ID_OPEN, _(u"&Open"))
        # Configure the language menu
        self.langMenu = wx.Menu()
        self.id_ro = wx.NewId()
        self.id_en = wx.NewId()
        self.langMenu.Append(self.id_en, _(u"&English"))
        self.langMenu.Append(self.id_ro, _(u"&Română"))
        # Configure view menu
        self.viewMenu = wx.Menu()
        self.viewMenu.Append(wx.ID_NO, _(u"2D Display"))
        self.viewMenu.Append(wx.ID_YES, _(u"3D Display"))
        self.currentview = wx.ID_NO
        # Create menu bar
        self.menuBar = wx.MenuBar()
        self.menuBar.Append(self.fileMenu, _(u"&File"))
        self.menuBar.Append(self.viewMenu, _(u"View"))
        self.menuBar.Append(self.langMenu, _(u"Language"))
        self.SetMenuBar(self.menuBar)

        # number of simulation cycles completed
        self.cycles_completed = 0
        # current file path
        self.path = path

        self.devices = devices
        self.monitors = monitors
        self.names = names
        self.network = network
        self.title = title

        # Creating 2D arrays with names and IDs of devices/signals
        # for all devices, configurable devices, and monitored signals.
        # self.monitored can change but self.outputs and
        # self.configurable can't change.
        [self.outputs, self.configurable, self.monitored] = self._gen_lists()

        # Configure the widgets/canvas:
        # Canvas for drawing signals
        self.my3D_canvas = My3DGLCanvas(self, devices, monitors, names)
        self.traces_canvas = MyTraces(self, devices, monitors, names)
        self.labels_canvas = MyLabels(self, devices, monitors, names)
        self.axis_canvas = MyAxis(self, self.cycles_completed)
        self.axis_title = wx.StaticText(self, wx.ID_ANY, "")
        # Connecting canva to share attributes.
        self.traces_canvas.labels = self.labels_canvas
        self.traces_canvas.axis = self.axis_canvas
        self.labels_canvas.traces = self.traces_canvas
        self.labels_canvas.SetInitialSize(wx.Size(110, -1))
        # Widget for error reporting/user feedback
        self.act_log = wx.TextCtrl(self,
                                   wx.ID_ANY,
                                   style=(wx.TE_MULTILINE | wx.TE_READONLY
                                          | wx.TE_LEFT | wx.TE_BESTWRAP),
                                   name="Activity Log Panel")
        font1 = wx.Font(10, wx.TELETYPE, wx.NORMAL, wx.NORMAL)
        self.act_log.SetFont(font1)
        # Widgets to control number of cycles.
        self.cycles = wx.SpinCtrl(self, wx.ID_ANY, "10")
        self.run_button = wx.Button(self, wx.ID_ANY, _("Run"))
        self.continue_button = wx.Button(self, wx.ID_ANY, _("Continue"))
        # Widgets to control configuration of clocks and switches.
        self.config_button = wx.Button(self, wx.ID_ANY, _("Apply"))
        self.config_list = wx.ComboBox(self,
                                       wx.ID_ANY,
                                       "",
                                       choices=self.configurable[0],
                                       style=(wx.CB_READONLY))
        # Deal with situation where circuit has no configurable devices.
        if len(self.configurable[0]) > 0:
            # Select first device in list as default
            self.config_list.SetSelection(0)
            self.config_var = wx.SpinCtrl(self, wx.ID_ANY,
                                          str(self.configurable[2][0]))
        else:
            # Initialise widget but disable button.
            self.config_var = wx.SpinCtrl(self, wx.ID_ANY)
            self.config_button.Disable()
        # Widgets to display/select all possible outputs.
        self.outs = wx.ListBox(self,
                               wx.ID_ANY,
                               style=(wx.LB_MULTIPLE | wx.LB_NEEDED_SB),
                               choices=self.outputs[0])
        self.add_outs = wx.Button(self, wx.ID_ANY, _("Show"))
        # Widgets to display/remove all current monitored outputs.
        self.mons = wx.ListBox(self,
                               wx.ID_ANY,
                               style=(wx.LB_MULTIPLE | wx.LB_NEEDED_SB),
                               choices=self.monitored[0])
        self.dele_mons = wx.Button(self, wx.ID_ANY, _("Remove"))
        # Toggle view and reload file buttons.
        self.view2D = wx.Button(self, wx.ID_ANY, _("2D View"))
        self.view3D = wx.Button(self, wx.ID_ANY, _("3D View"))
        self.reset = wx.Button(self, wx.ID_ANY, _("Reset View"))
        self.reload = wx.Button(self, wx.ID_ANY, _("Reload File"))

        # Styling text of titles in widgets
        self.title_font = wx.Font(12, wx.MODERN, wx.NORMAL, wx.BOLD)
        # self.cyc_title.SetFont(self.title_font)
        # self.config_title.SetFont(self.title_font)
        # self.out_title.SetFont(self.title_font)
        # self.mon_title.SetFont(self.title_font)
        # self.uf_title.SetFont(self.title_font)
        self.axis_title.SetFont(self.title_font)

        # Bind events to widgets
        self.Bind(wx.EVT_MENU, self.on_menu)
        self.run_button.Bind(wx.EVT_BUTTON, self.on_run_button)
        self.continue_button.Bind(wx.EVT_BUTTON, self.on_continue_button)
        self.config_button.Bind(wx.EVT_BUTTON, self.on_config_button)
        self.add_outs.Bind(wx.EVT_BUTTON, self.on_show)
        self.dele_mons.Bind(wx.EVT_BUTTON, self.on_remove)
        self.config_list.Bind(wx.EVT_COMBOBOX, self.on_conf_select)
        self.view2D.Bind(wx.EVT_BUTTON, self.on_2D)
        self.view3D.Bind(wx.EVT_BUTTON, self.on_3D)
        self.reset.Bind(wx.EVT_BUTTON, self.on_reset)
        self.reload.Bind(wx.EVT_BUTTON, self.on_reload)

        # Root level app section splitter.
        self.main_sizer = wx.BoxSizer(wx.HORIZONTAL)

        canv = wx.StaticBox(self, wx.ID_ANY)
        self.canv_maj_sizer = wx.StaticBoxSizer(canv, wx.VERTICAL)
        # Sizer to horizontally align labels canvas and trace
        # canvas.
        canv_sizer = wx.BoxSizer(wx.HORIZONTAL)
        # Sizer to horizontally align axis title and axis.
        canv_axis_sizer = wx.BoxSizer(wx.HORIZONTAL)
        # Sizer to vertically arrange 2D/3D canvas and user
        # feedback section.
        self.canv_feed_sizer = wx.BoxSizer(wx.VERTICAL)
        # Sizer to organise sidebar elements vertically.
        side_sizer = wx.BoxSizer(wx.VERTICAL)

        # Sizers and Boxes to organise sidebar elements.
        # StaticBoxes are parents of StaticBoxSizers.
        # Horizontal BoxSizers used to arrange side by side
        # elements in a StaticBox.
        self.uf = wx.StaticBox(self, wx.ID_ANY, _("Activity Log"))
        self.cyc = wx.StaticBox(self, wx.ID_ANY, _("Cycles"))
        self.conf = wx.StaticBox(self, wx.ID_ANY, _("Configure Devices"))
        self.out = wx.StaticBox(self, wx.ID_ANY, _("Outputs"))
        self.mon = wx.StaticBox(self, wx.ID_ANY, _("Monitored Outputs"))
        self.ax = wx.StaticBox(self, wx.ID_ANY)
        self.tog = wx.StaticBox(self, wx.ID_ANY)

        # To align with labels canvas
        self.ax.SetMinSize(wx.Size(110, 20))
        uf_sizer = wx.StaticBoxSizer(self.uf, wx.VERTICAL)
        cyc_sizer = wx.StaticBoxSizer(self.cyc, wx.VERTICAL)
        cyc_but_sizer = wx.BoxSizer(wx.HORIZONTAL)
        config_sizer = wx.StaticBoxSizer(self.conf, wx.VERTICAL)
        config_but_sizer = wx.BoxSizer(wx.HORIZONTAL)
        out_sizer = wx.StaticBoxSizer(self.out, wx.VERTICAL)
        mon_sizer = wx.StaticBoxSizer(self.mon, wx.VERTICAL)
        tog_sizer = wx.StaticBoxSizer(self.tog, wx.VERTICAL)
        dim_but_sizer = wx.BoxSizer(wx.HORIZONTAL)
        reset_but_sizer = wx.BoxSizer(wx.HORIZONTAL)
        ax_title = wx.StaticBoxSizer(self.ax, wx.HORIZONTAL)

        # Add widgets to relevent sizers/boxes. Add sub-sizers
        # to parent sizers. 'Add' method allows behaviour modes
        # of widgets to be specified using wx Stock Constants.
        # Order in which widgets are added to sizers are determined
        # by order in which Add methods called.
        # Box.Add(control, proportion, flag, border)
        # Left and Right sections of GUI
        self.main_sizer.Add(self.canv_feed_sizer, 4, wx.EXPAND | wx.ALL, 5)
        self.main_sizer.Add(side_sizer, 0, wx.ALL | wx.EXPAND, 5)
        # Canva and activity log
        self.canv_feed_sizer.Add(self.canv_maj_sizer, 4, wx.EXPAND | wx.ALL, 5)
        self.canv_feed_sizer.Add(self.my3D_canvas, 4, wx.EXPAND | wx.ALL, 5)
        self.canv_feed_sizer.Add(uf_sizer, 1, wx.EXPAND | wx.ALL, 1)
        self.canv_feed_sizer.Hide(1)
        # Trace/Labels sections and axis section
        self.canv_maj_sizer.Add(canv_sizer, 1, wx.EXPAND)
        self.canv_maj_sizer.Add(canv_axis_sizer, 0, wx.EXPAND)
        # Labels canvas and traces canvas
        canv_sizer.Add(self.labels_canvas, 0, wx.ALL | wx.EXPAND, 5)
        canv_sizer.Add(self.traces_canvas, 6, wx.EXPAND | wx.ALL, 5)
        # Axis title and axis.
        canv_axis_sizer.Add(ax_title, 0, wx.EXPAND | wx.ALL, 5)
        canv_axis_sizer.Add(self.axis_canvas, 6, wx.EXPAND | wx.ALL, 5)
        # To size and align axis title container.
        ax_title.Add(self.axis_title, 1, wx.EXPAND | wx.ALIGN_CENTER)
        # Activity log title and output box.
        # uf_sizer.Add(self.uf_title, 0, wx.LEFT, 5)
        uf_sizer.Add(self.act_log, 1, wx.EXPAND | wx.ALL, 5)
        # Right sidebar.
        side_sizer.Add(cyc_sizer, 0, wx.ALIGN_CENTER | wx.EXPAND)  # Cycles
        side_sizer.Add(config_sizer, 0,
                       wx.ALIGN_CENTER | wx.EXPAND)  # Configure devices
        side_sizer.Add(out_sizer, 1, wx.ALIGN_CENTER | wx.EXPAND)  # Outputs
        side_sizer.Add(mon_sizer, 1,
                       wx.ALIGN_CENTER | wx.EXPAND)  # Monitored Outputs
        side_sizer.Add(tog_sizer, 0,
                       wx.ALIGN_CENTER | wx.EXPAND)  # Toggle Buttons
        # Cycles
        # cyc_sizer.Add(self.cyc_title, 0, wx.BOTTOM, 10)  # Title
        cyc_sizer.Add(self.cycles, 0, wx.EXPAND | wx.ALL, 10)  # Textbox
        cyc_sizer.Add(cyc_but_sizer, 0, wx.ALIGN_CENTER, 1)  # Buttons
        # Organising run and continue button horizontally
        cyc_but_sizer.Add(self.run_button, 1, wx.ALL, 5)  # Run button
        cyc_but_sizer.Add(self.continue_button, 1, wx.ALL,
                          5)  # Continue Button
        # Configure devices dropdown list
        # config_sizer.Add(self.config_title, 0, wx.BOTTOM, 10)  # Title

        # Second Interim Report Feedback Update: Swap widget order.

        config_sizer.Add(self.config_list, 1, wx.EXPAND | wx.ALL,
                         16)  # Dropdown List
        config_sizer.Add(config_but_sizer, 0, wx.ALL | wx.ALIGN_CENTER,
                         5)  # Apply button
        # and textbox

        # Organising apply button and text box horizontally
        config_but_sizer.Add(self.config_button, 0, wx.RIGHT,
                             6)  # Apply Button
        config_but_sizer.Add(self.config_var, 1, wx.BOTTOM | wx.LEFT,
                             5)  # Textbox
        # Output list and add monitor button
        # out_sizer.Add(self.out_title, 0, wx.BOTTOM, 10)  # Title
        out_sizer.Add(self.outs, 1, wx.ALL | wx.EXPAND, 10)  # List
        out_sizer.Add(self.add_outs, 0, wx.ALIGN_CENTER | wx.ALL, 5)  # Button
        # Monitor list and delete button.
        # mon_sizer.Add(self.mon_title, 0, wx.BOTTOM, 10)  # Title
        mon_sizer.Add(self.mons, 1, wx.ALL | wx.EXPAND, 10)  # List
        mon_sizer.Add(self.dele_mons, 0, wx.ALIGN_CENTER | wx.ALL, 5)  # Button
        # 2D, 3D, Reset, Reload Buttons
        tog_sizer.Add(dim_but_sizer, 0, wx.ALIGN_CENTER, 1)
        tog_sizer.Add(reset_but_sizer, 0, wx.ALIGN_CENTER, 1)
        # 2D, 3D, View Buttons
        dim_but_sizer.Add(self.view2D, 1, wx.ALL, 5)
        dim_but_sizer.Add(self.view3D, 1, wx.ALL, 5)
        # reset, reload, View Buttons
        reset_but_sizer.Add(self.reset, 1, wx.ALL, 5)
        reset_but_sizer.Add(self.reload, 1, wx.ALL, 5)

        # Set min size of window.
        self.SetMinSize(wx.Size(1100, 900))
        self.SetInitialSize(wx.Size(1100, 900))
        # Set main_sizer as the main sizer of the wx.Frame
        self.SetSizer(self.main_sizer)

    def _re_render(self):
        """
        Private function that updates monitors and devices
        in classes in canva.py and then calls its render method
        to replot traces taking into account updates.
        """
        print('rendering')
        if self.currentview == wx.ID_NO:
            self.traces_canvas.SetColour("grey")
            self.traces_canvas.monitors = self.monitors
            self.traces_canvas.devices = self.devices
            self.traces_canvas.render()
            self.labels_canvas.monitors = self.monitors
            self.labels_canvas.devices = self.devices
            self.labels_canvas.render()
            self.axis_canvas.cycles = self.cycles_completed
            self.axis_canvas.render()
        if self.currentview == wx.ID_YES:
            self.my3D_canvas.monitors = self.monitors
            self.my3D_canvas.devices = self.devices
            self.my3D_canvas.render()

    def _gen_lists(self):
        """
        Create arrays of two sub-arrays for: all possible
        outputs, configurable outputs and monitored outputs.
        The first sub-array stores name strings of outputs
        and the second sub_array stores the device_id and
        output_id of the corresponding output.
        """
        outputs = [[] for i in range(2)]
        configurable = [[] for i in range(3)]
        monitored = [[] for i in range(2)]

        for device in self.devices.devices_list:
            # Get device name.
            dev_name = self.names.get_name_string(device.device_id)
            # Append output name to device name if output name explicit.
            if device.device_kind == self.devices.D_TYPE:
                for output in device.outputs:
                    out_name = self.names.get_name_string(output)
                    outputs[0].append(dev_name + "." + out_name)
                    outputs[1].append((device.device_id, output))
            else:
                outputs[0].append(dev_name)
                outputs[1].append((device.device_id, None))
            # Recording devices that are clocks or switches.
            if (device.device_kind == self.devices.CLOCK
                    or device.device_kind == self.devices.SWITCH):
                configurable[0].append(dev_name)
                configurable[1].append(device.device_id)
                if device.device_kind == self.devices.CLOCK:
                    configurable[2].append(device.clock_half_period)
                if device.device_kind == self.devices.SWITCH:
                    configurable[2].append(device.switch_state)
        # Recording monitored outputs.
        for monitor in self.monitors.monitors_dictionary:
            dev_name = self.names.get_name_string(monitor[0])
            out_name = self.names.get_name_string(monitor[1])
            if out_name is not None:
                monitored[0].append(dev_name + "." + out_name)
            else:
                monitored[0].append(dev_name)
            monitored[1].append(monitor)

        return [outputs, configurable, monitored]

    def _regen_monitored(self, monitor):
        """
        Private method to regenerate monitored outputs list in GUI.
        """
        dev_name = self.names.get_name_string(monitor[0])
        out_name = self.names.get_name_string(monitor[1])
        if out_name is not None:  # For DTYPE devices
            self.monitored[0].append(dev_name + "." + out_name)
            self.monitored[1].append(monitor)
            # Update Monitored Outputs List in GUI
            self.mons.InsertItems([dev_name + "." + out_name],
                                  self.mons.GetCount())
        else:
            self.monitored[0].append(dev_name)
            self.monitored[1].append(monitor)
            # Update Monitored Outputs List in GUI
            self.mons.InsertItems([dev_name], self.mons.GetCount())

    def _run_network(self, cycles, warm_flag=False):
        """
        Run the network for the specified number of simulation cycles.
        Return True if successful.
        """
        # If running network only to update traces.
        if warm_flag:
            self.monitors.reset_monitors()  # Clear previously stored signals

        for _ in range(cycles):
            # Network executed and signal recorded one cycle
            # at a time.
            if self.network.execute_network():
                self.monitors.record_signals()
            else:
                print("Error! Network oscillating.")
                self.act_log.AppendText(
                    _("***Error: Network oscillating.") + "\n")
                return False
        # Displays results in command line interface.
        self.monitors.display_signals()
        return True

    def _verify_number(self, num, lower_bound, upper_bound):
        """
        Return the current number if it is within provided bounds.
        Return None if no number is provided or if it falls outside the valid
        range.
        """
        if upper_bound is not None:
            if num > upper_bound:
                print("Number out of range.")
                return None

        if lower_bound is not None:
            if num < lower_bound:
                print("Number out of range.")
                return None

        return num

    def on_conf_select(self, event):
        """
        Handle event when user selects a configurable
        device and accordingly update default value in
        config var input box to current device config var
        value
        """
        config_var = self.configurable[2][
            self.config_list.GetCurrentSelection()]
        self.config_var.SetValue(config_var)

    def on_menu(self, event):  # TODO DAVID
        """Handle the event when the user selects a menu item."""
        Id = event.GetId()
        if Id == wx.ID_EXIT:
            self.Close(True)
        if Id == wx.ID_ABOUT:
            wx.MessageBox(
                _("Logic Simulator\nCreated by ") + "David Almasan, " +
                "Vatsal Raina, Karthik Suresh\nGF2 Software\n" +
                _("2019 IIB Summer Term"), _("About Logsim"),
                wx.ICON_INFORMATION | wx.OK)
        if Id == wx.ID_OPEN:
            self.on_open()

        if Id == wx.ID_YES:
            self.on_3D(None)

        if Id == wx.ID_NO:
            self.on_2D(None)

        if Id == self.id_en:
            self.updateLanguage(u"en")
            self._update_Labels()

        if Id == self.id_ro:
            self.updateLanguage(u"el")
            self._update_Labels()

    def on_2D(self, event):
        """Handle event when user clicks 2D view button"""
        if self.currentview == wx.ID_YES:
            # Hide 3D view
            self.canv_feed_sizer.Hide(1)
            # Show 2D view
            self.canv_feed_sizer.Show(0)
            # Reload
            self.main_sizer.Layout()
            self.Fit()
            # Update view record
            self.currentview = wx.ID_NO
            # Force axis update
            self.axis_canvas.cycles = self.cycles_completed
            self.axis_canvas.render()

    def on_3D(self, event):
        """Handle event when user clicks 3D view button"""
        if self.currentview == wx.ID_NO:
            # Hide 2D view
            self.canv_feed_sizer.Hide(0)
            # Show 3D view
            self.canv_feed_sizer.Show(1)
            # Reload
            self.main_sizer.Layout()
            self.Fit()
            # Update view record
            self.currentview = wx.ID_YES

    def on_reset(self, event):
        """Handle event when user clicks rest view"""
        # If 3D, reset rotation and pan variables.
        if self.currentview == wx.ID_YES:
            self.my3D_canvas.reset_pan()
        # If 2D, reset pan vairbles in all canvases.
        if self.currentview == wx.ID_NO:
            MyOpenGLCanvas.pan_x = 0
            MyOpenGLCanvas.pan_y = 0
            self.traces_canvas.init = False
            self.axis_canvas.init = False
            self.labels_canvas.init = False
            self.traces_canvas.Refresh()
            self.axis_canvas.Refresh()
            self.labels_canvas.Refresh()

    def on_run_button(self, event):
        """Run the simulation from scratch when user clicks Run button."""
        self.cycles_completed = 0
        cycles = self.cycles.GetValue()

        if cycles is not None:  # if the number of cycles provided is valid
            self.monitors.reset_monitors()  # Clear previously stored signals
            self.devices.cold_startup()  # Random initialisation
            if self._run_network(cycles):
                self.act_log.AppendText("".join(
                    [_("Running for "),
                     str(cycles), _(" cycles")]) + '\n')
                self.cycles_completed += cycles
                # Update pan variable to ensure new plot
                # not generated off screen.
                MyOpenGLCanvas.pan_x = 0
                self.traces_canvas.init = False
                self.axis_canvas.init = False
                self.labels_canvas.init = False
                self._re_render()  # Update plots

    def on_continue_button(self, event):
        """Continue a previously run simulation."""
        cycles = self.cycles.GetValue()
        if cycles is not None:  # if the number of cycles provided is valid
            if self.cycles_completed == 0:
                self.act_log.AppendText(
                    _("Error! Nothing to continue. Run first.") + '\n')
            elif self._run_network(cycles):
                self.cycles_completed += cycles
                self._re_render()  # Update plots
                self.act_log.AppendText("".join([
                    _("Continuing for "),
                    str(cycles),
                    _(" cycles."),
                    _(" Total:"),
                    str(self.cycles_completed)
                ]) + '\n')

    def on_config_button(self, event):
        """Handle the event when the user clicks the apply button."""
        # Gather device id of device user wants to configure and
        # configure variable.
        config = self.config_var.GetValue()
        dev_id = self.configurable[1][self.config_list.GetSelection()]

        # Validate configure variable based on device type selected
        if self.devices.get_device(dev_id).device_kind == self.devices.SWITCH:
            switch_state = self._verify_number(config, 0, 1)
            if switch_state is not None:
                # Changing switch state.
                if self.devices.set_switch(dev_id, switch_state):
                    print("Successfully set switch " +
                          self.names.get_name_string(dev_id) + "\n")
                    dv_id = dev_id  # pep8
                    self.act_log.AppendText(
                        _("Successfully set switch ") +
                        self.names.get_name_string(dv_id) + "\n")
                    self.configurable[2][
                        self.config_list.GetSelection()] = switch_state

                else:
                    print("Error! Invalid switch." + "\n")
                    self.act_log.AppendText(_("Error! Invalid switch.") + "\n")
            else:
                print("Error! Switch state must be " + "0 (OFF) or 1 (ON)." +
                      "\n")
                self.act_log.AppendText(
                    _("Error! Switch state must be ") +
                    _("0 (OFF) or 1 (ON).") + "\n")
        elif (self.devices.get_device(dev_id).device_kind == self.devices.CLOCK
              ):
            print("Changing clock half-period")
            half_period = self._verify_number(config, 1, None)
            if half_period is not None:
                # Changing clock period.
                if self.devices.set_clock(dev_id, half_period):
                    print("Successfully set CLOCK " +
                          self.names.get_name_string(dev_id) +
                          " half-period to " + str(config) + "\n")
                    self.act_log.AppendText(
                        _("Successfully set CLOCK ") +
                        self.names.get_name_string(dev_id) +
                        _(" half-period to ") + str(config) + "\n")
                    self.configurable[2][
                        self.config_list.GetSelection()] = half_period
                else:
                    print("Error! Invalid CLOCK." + "\n")
                    self.act_log.AppendText(_("Error! Invalid CLOCK.") + "\n")
            else:
                print("Error! CLOCK half-period must be " +
                      "positive integer" + "\n")
                self.act_log.AppendText(
                    _("Error! CLOCK" + "half-period must be ") +
                    _("positive integer") + "\n")
        self._re_render()  # Update plots

    def on_show(self, event):
        """
        Set the selected outputs to be monitored. Called in
        reponse to user clicking 'Show'.
        """
        # Get list indicies of outputs selected by user
        selected = self.outs.GetSelections()
        for i in selected:
            # Find names id from GUI list id
            monitor = self.outputs[1][i]
            if monitor is not None:
                [device, port] = monitor
                monitor_error = self.monitors.make_monitor(
                    device, port, self.cycles_completed)
                if monitor_error == self.monitors.NO_ERROR:
                    # print("Successfully made monitor.")
                    self.act_log.AppendText(
                        _("Successfully made monitor.") + '\n')
                    # Update monitored output gui list.
                    self._regen_monitored(monitor)
                else:
                    # print("Error! Could not make monitor.")
                    self.act_log.AppendText(
                        _("Error! Monitor already ") + _("selected.") + '\n')
        self._re_render()

    def on_remove(self, event):
        """
        Remove selected monitored outputs. Called in
        reponse to user clicking 'Remove'.
        """
        # Get list indicies of outputs selected by user
        to_remove = self.mons.GetSelections()
        # Remove selected monitors in reverse order to
        # ensure indicies are not out of range.
        for i in to_remove[::-1]:
            # Find names id from GUI list id
            monitor = self.monitored[1][i]
            if monitor is not None:
                [device, port] = monitor
                if self.monitors.remove_monitor(device, port):
                    self.act_log.AppendText(
                        _("Successfully zapped monitor") + '\n')
                    # Remove from displayed and internal lists.
                    self.mons.Delete(i)
                    self.monitored[0].pop(i)
                    self.monitored[1].pop(i)
                else:
                    # print("Error! Could not zap monitor.")
                    self.act_log.AppendText(
                        _("Error! Could not zap monitor.") + '\n')
        # Remove relevant traces.
        self._re_render()

    def _get_file_name(self, path_name):
        """ Gets file name from file path """
        file_name = ""
        for c in path_name[::-1]:
            if c != '/':
                file_name += c
            else:
                break
        file_name = file_name[::-1]
        return file_name

    def on_open(self):
        """Handles user event to open a new file"""
        # otherwise ask the user what new file to open
        with wx.FileDialog(self, _("Open Text file"),
                           wildcard=_("Text files") + "(*.txt)|*.txt",
                           style=wx.FD_OPEN | wx.FD_FILE_MUST_EXIST) \
                as fileDialog:

            if fileDialog.ShowModal() == wx.ID_EXIT:
                return  # the user changed their mind

            # Proceed loading the file chosen by the user
            path_name = fileDialog.GetPath()
            # Extract file name from path, show in title.
            # Second Interim Report Feedback Update: Show current file.
            self.SetTitle("Logic Simulator - " +
                          self._get_file_name(path_name))
        self.path = path_name
        self.on_reload(None, True)

    def on_reload(self, event, new=False):
        """
        Handles loading of circuit specification file.
        Called when new file loaded or current file reloaded.
        """
        # Create new render
        self.cycles_completed = 0
        self.start = (0, 0)
        self.names = Names()
        self.devices = Devices(self.names)
        self.network = Network(self.names, self.devices)
        self.monitors = Monitors(self.names, self.devices, self.network)
        self.scanner = Scanner(self.path, self.names)
        self.parser = Parser(self.names, self.devices, self.network,
                             self.monitors, self.scanner)
        if self.parser.parse_network():
            self.run_button.Enable()
            self.continue_button.Enable()
            self.config_button.Enable()
            self.add_outs.Enable()
            self.dele_mons.Enable()
            self.view2D.Enable()
            self.view3D.Enable()
            self.reset.Enable()
            [self.outputs, self.configurable,
             self.monitored] = self._gen_lists()
            self.outs.Set(self.outputs[0])

            # Added after discovering application crashes
            # when SIGGEN circuit loaded. Before this every
            # ciruit had to include a configurable device.
            if len(self.configurable[0]) > 0:
                self.config_list.Set(self.configurable[0])
                self.config_list.SetSelection(0)
                self.config_var.SetValue(self.configurable[2][0])
            else:
                self.config_var.SetValue(0)
                self.config_list.Clear()
                self.config_button.Disable()

            self.mons.Set(self.monitored[0])
            # Ensure pan variables are restored,
            # and new file loaded in both views.
            self.on_reset(None)
            self._re_render()
            if self.currentview == wx.ID_YES:
                self.on_2D(None)
            else:
                self.on_3D(None)
            self.on_reset(None)
            self._re_render()
            if self.currentview == wx.ID_NO:
                self.on_3D(None)
            else:
                self.on_2D(None)
            self.act_log.Clear()
            if new:
                self.act_log.AppendText(
                    _("Successfully loaded new file!") + "\n")
            else:
                self.act_log.AppendText(
                    _("Successfully reloaded file!") + "\n")
        else:
            self.act_log.Clear()
            # if new:
            #     self.act_log.AppendText(_("Unsuccessful Load!")+ "\n\n")
            # else:
            #     self.act_log.AppendText(_("Unsuccessful Reload!")+ "\n\n")
            for err_msg in self.parser.print_gui:
                self.act_log.AppendText(_(err_msg))
            self.act_log.AppendText(_(self.scanner.broken_comment_msg) + '\n')
            self.act_log.AppendText(
                _("***ERROR: Circuit could not ") + _("be parsed. Try again") +
                "\n\n\n")
            self.run_button.Disable()
            self.continue_button.Disable()
            self.config_button.Disable()
            self.add_outs.Disable()
            self.dele_mons.Disable()
            self.view2D.Disable()
            self.view3D.Disable()
            self.reset.Disable()
            # Delete traces
            self.names = None
            self.devices = None
            self.network = None
            # Set devices and monitors on the right canvas to None
            self.config_list.SetValue("")
            self.outputs = [[] for i in range(2)]
            self.configurable = [[] for i in range(2)]
            self.monitored = [[] for i in range(2)]
            self.outs.Clear()
            self.config_list.Clear()
            self.mons.Clear()
            self.on_reset(None)
            self._re_render()
            if self.currentview == wx.ID_YES:
                self.on_2D(None)
            else:
                self.on_3D(None)
            self.on_reset(None)
            self._re_render()
            if self.currentview == wx.ID_NO:
                self.on_3D(None)
            else:
                self.on_2D(None)

    def updateLanguage(self, lang):
        """
        Update the language to the requested one.

        Make *sure* any existing locale is deleted before the new
        one is created.  The old C++ object needs to be deleted
        before the new one is created, and if we just assign a new
        instance to the old Python variable, the old C++ locale will
        not be destroyed soon enough, likely causing a crash.

        :param string `lang`: one of the supported language codes

        """
        # if an unsupported language is requested default to English
        if lang in appC.supLang:
            selLang = appC.supLang[lang]
        else:
            selLang = wx.LANGUAGE_DEFAULT

        if self.locale:
            assert sys.getrefcount(self.locale) <= 2
            del self.locale

        # create a locale object for this language
        self.locale = wx.Locale(selLang)
        if self.locale.IsOk():
            self.locale.AddCatalog(appC.langDomain)
            # self.act_log.AppendText("updated")
        else:
            self.locale = None

    def _update_Labels(self):
        """Updates labels in GUI to selected language."""
        self.run_button.SetLabel(_("Run"))
        self.continue_button.SetLabel(_("Continue"))
        self.config_button.SetLabel(_("Apply"))
        self.add_outs.SetLabel(_("Show"))
        self.dele_mons.SetLabel(_("Remove"))
        self.view2D.SetLabel(_("2D View"))
        self.view3D.SetLabel(_("3D View"))
        self.reset.SetLabel(_("Reset View"))
        self.reload.SetLabel(_("Reload File"))

        self.uf.SetLabel(_("Activity Log"))
        self.cyc.SetLabel(_("Cycles"))
        self.conf.SetLabel(_("Configure Devices"))
        self.out.SetLabel(_("Outputs"))
        self.mon.SetLabel(_("Monitored Outputs"))

        self.fileMenu.SetLabel(wx.ID_ABOUT, _(u"&About"))
        self.fileMenu.SetLabel(wx.ID_EXIT, _(u"&Exit"))
        self.fileMenu.SetLabel(wx.ID_OPEN, _(u"&Open"))
        self.viewMenu.SetLabel(wx.ID_NO, _("2D Display"))
        self.viewMenu.SetLabel(wx.ID_YES, _("3D Display"))
        self.langMenu.SetLabel(self.id_en, _(u"&English"))
        self.langMenu.SetLabel(self.id_ro, _(u"&Română"))
        self.menuBar.SetMenuLabel(0, _(u"&File"))
        self.menuBar.SetMenuLabel(1, _(u"View"))
        self.menuBar.SetMenuLabel(2, _(u"Language"))

        self.main_sizer.Layout()
        self.Fit()
Пример #23
0
def main(arg_list):
    """Parse the command line options and arguments specified in arg_list.

    Run either the command line user interface, the graphical user interface,
    or display the usage message.
    """
    usage_message = (
        "Usage:\n"
        "Show help: logsim.py -h\n"
        "Command line user interface: logsim.py -c <file path>\n"
        "Graphical user interface with a blank circuit: logsim.py\n"
        "Graphical user interface with a predefined test circuit: logsim.py -t <circuit_number>\n"
        "Graphical user interface with loading a file: logsim.py <file path>")
    try:
        options, arguments = getopt.getopt(arg_list, "hct:")
    except getopt.GetoptError:
        print("Error: invalid command line arguments\n")
        print(usage_message)
        sys.exit()

    # Initialise instances of the four inner simulator classes
    names = Names()
    devices = Devices(names)
    network = Network(names, devices)
    monitors = Monitors(names, devices, network)
    import app_base as ab
    for option, path in options:
        if option == "-h":  # print the usage message
            print(usage_message)
            sys.exit()
        elif option == "-c":  # use the command line user interface
            scanner = Scanner(path, names)
            parser = Parser(names, devices, network, monitors, scanner)
            if parser.parse_network():
                # Initialise an instance of the userint.UserInterface() class
                userint = UserInterface(names, devices, network, monitors)
                userint.command_interface()
        elif option == "-t":  # manually create the devices, network, and monitors for testing
            if path == "1":
                names, devices, network, monitors = test_1()
            elif path == "2":
                names, devices, network, monitors = test_2()
            elif path == "3":
                names, devices, network, monitors = test_3()
            elif path == "4":
                names, devices, network, monitors = test_4()
            else:
                print("Error: invalid test number.\n")
                sys.exit()

            # Initialise an instance of the gui.Gui() class
            app = wx.App()
            gui = Gui("Logic Simulator", path, names, devices, network,
                      monitors, "en", 0)
            gui.Show(True)
            app.MainLoop()

    if not options:  # no option given, use the graphical user interface

        if len(arguments) == 0:  # Open the blank gui
            # Initialise an instance of the gui.Gui() class
            app = wx.App()
            gui = Gui("Logic Simulator", None, names, devices, network,
                      monitors, "en", 0)
            gui.Show(True)
            app.MainLoop()

        elif len(arguments) == 1:
            [path] = arguments
            scanner = Scanner(path, names)
            parser = Parser(names, devices, network, monitors, scanner)
            if parser.parse_network():
                # Initialise an instance of the gui.Gui() class
                app = wx.App()
                gui = Gui("Logic Simulator", path, names, devices, network,
                          monitors, "en", 0)
                gui.Show(True)
                app.MainLoop()

        else:  # wrong number of arguments
            print("Error: Too many arguments given\n")
            print(usage_message)
            sys.exit()
Пример #24
0
class Gui(wx.Frame):  # main options screen
    def __init__(self, title):
        """Initialise widgets and layout."""
        super().__init__(parent=None, title=title)

        self.SetIcon(wx.Icon('GUI/CUED Software.png'))
        self.Maximize(True)
        self.SetBackgroundColour((186, 211, 255))
        self.header_font = wx.Font(25, wx.FONTFAMILY_SWISS, wx.NORMAL,
                                   wx.FONTWEIGHT_BOLD, False)
        self.label_font = wx.Font(10, wx.FONTFAMILY_SWISS, wx.NORMAL,
                                  wx.NORMAL, False)

        self.makeLeftSizer()
        self.makeMiddleSizer()
        self.makeRightSizer()

        outer = wx.BoxSizer(wx.VERTICAL)
        self.main_sizer = wx.BoxSizer(wx.HORIZONTAL)
        self.main_sizer.Add(self.left_panel, 3, wx.ALL | wx.EXPAND, 20)
        self.main_sizer.Add(self.middle_panel, 3, wx.ALL | wx.EXPAND, 20)
        self.main_sizer.Add(self.right_panel, 3, wx.ALL | wx.EXPAND, 20)

        helpBtn = wx.Button(self, wx.ID_ANY, "Help")
        helpBtn.Bind(wx.EVT_BUTTON, self.open_help)
        outer.Add(helpBtn, 0, wx.ALL | wx.ALIGN_RIGHT, 0)
        outer.Add(self.main_sizer, 0, wx.EXPAND | wx.ALL, 0)
        self.SetSizer(outer)

    def makeLeftSizer(self):
        self.left_panel = wx.Panel(self)
        self.left_panel.SetBackgroundColour((37, 103, 209))
        self.load_btn = wx.Button(self.left_panel, wx.ID_ANY, "Browse Files")
        self.check_btn = wx.Button(self.left_panel, wx.ID_ANY, 'Verify Code')

        left_heading = wx.StaticText(self.left_panel, -1, label="Editor")
        left_heading = self.style(left_heading, self.header_font)

        editor_font = wx.Font(14, wx.MODERN, wx.NORMAL, wx.NORMAL, False,
                              u'Consolas')
        self.input_text = wx.stc.StyledTextCtrl(self.left_panel,
                                                size=(-1, wx.ALL))
        self.input_text.SetMarginType(1, wx.stc.STC_MARGIN_NUMBER)
        self.input_text.SetMarginWidth(3, 15)
        self.input_text.SetUseHorizontalScrollBar(False)
        self.input_text.StyleSetFont(0, editor_font)
        self.input_text.AppendText("DEVICES {\n\n}\nCONNECTIONS {\n\n}")

        self.error_text = wx.TextCtrl(self.left_panel,
                                      wx.ID_ANY,
                                      size=(-1, wx.ALL),
                                      style=wx.TE_MULTILINE | wx.TE_READONLY,
                                      value="Click run to check for errors")
        self.error_text.SetFont(editor_font)
        self.error_text.SetStyle(0, -1, wx.TextAttr(wx.RED))

        self.left_sizer = wx.BoxSizer(wx.VERTICAL)

        self.left_sizer.Add(left_heading, 0, wx.ALL | wx.ALIGN_CENTER, 10)
        row = wx.BoxSizer(wx.HORIZONTAL)
        row.Add(self.load_btn, 1, wx.ALIGN_LEFT, 5)
        row.Add(self.check_btn, 1, wx.ALIGN_RIGHT, 5)
        self.left_sizer.Add(row, 0, wx.ALL | wx.ALIGN_CENTER, 5)
        self.left_sizer.Add(self.input_text, 6, wx.EXPAND | wx.ALL, 10)
        self.left_sizer.Add(self.error_text, 1, wx.EXPAND | wx.ALL, 10)

        self.left_panel.SetSizer(self.left_sizer)

        self.load_btn.Bind(wx.EVT_BUTTON, self.LoadFile)
        self.check_btn.Bind(wx.EVT_BUTTON, self.CheckText)

    def makeMiddleSizer(self):
        self.middle_panel = wx.lib.scrolledpanel.ScrolledPanel(self)
        self.middle_panel.SetBackgroundColour((37, 103, 209))
        self.middle_panel.SetupScrolling(scroll_x=False)

        self.middle_sizer = wx.BoxSizer(wx.VERTICAL)
        self.middle_panel.SetSizer(self.middle_sizer)

        self.middle_panel.Hide()
        self.Layout()

    def makeRightSizer(self):
        self.right_panel = wx.Panel(self)
        self.right_panel.SetBackgroundColour('white')
        self.right_sizer = wx.BoxSizer(wx.VERTICAL)
        self.right_panel.SetSizer(self.right_sizer)

        self.right_panel.Hide()
        self.Layout()

    def CheckText(self, event):
        self.names = Names()
        self.devices = Devices(self.names)
        self.network = Network(self.names, self.devices)
        self.monitors = Monitors(self.names, self.devices, self.network)
        self.scanner = Scanner(self.input_text.GetValue(), self.names, True)
        self.parser = Parser(self.names, self.devices, self.network,
                             self.monitors, self.scanner)
        status = None
        # try:
        status = self.parser.parse_network()
        # except:
        #     pass

        if self.scanner.total_error_string == "":
            self.error_text.AppendText("No errors found")
        else:
            self.error_text.Clear()
            self.error_text.AppendText(self.scanner.total_error_string)
            self.error_text.SetStyle(0, -1, wx.TextAttr(wx.RED))

            self.middle_panel.Hide()
            self.right_panel.Hide()
            self.Layout()
            return

        if status == True and len(self.devices.devices_list) > 0:

            self.error_text.Clear()
            self.middle_sizer.Clear(True)
            self.middle_panel.Update()
            try:
                self.right_sizer.Remove(1)
            except:
                pass
            self.right_panel.Update()

            middle_heading = wx.StaticText(self.middle_panel, label="Options")
            middle_heading = self.style(middle_heading, self.header_font)
            self.middle_sizer.Add(middle_heading, 0, wx.ALL | wx.ALIGN_CENTER,
                                  10)

            self.toggle_right_panel = wx.ToggleButton(
                self.middle_panel, label="show circuit (experimental)")
            self.toggle_right_panel.Bind(wx.EVT_TOGGLEBUTTON,
                                         self.OnRightPanelToggle)
            self.middle_sizer.Add(self.toggle_right_panel, 0,
                                  wx.ALL | wx.ALIGN_RIGHT, 5)

            device_info = wx.FlexGridSizer(4, 0, 10)
            # ------------- HEADINGS ------------- #
            label = wx.StaticText(self.middle_panel, label="Name")
            label = self.style(label, self.label_font)
            device_info.Add(label, 0, wx.EXPAND | wx.ALL, 0)

            label = wx.StaticText(self.middle_panel, label="Type")
            label = self.style(label, self.label_font)
            device_info.Add(label, 0, wx.EXPAND | wx.ALL, 0)

            label = wx.StaticText(self.middle_panel, label="Inputs")
            label = self.style(label, self.label_font)
            device_info.Add(label, 0, wx.EXPAND | wx.ALL, 0)

            label = wx.StaticText(self.middle_panel, label="Outputs")
            label = self.style(label, self.label_font)
            device_info.Add(label, 0, wx.EXPAND | wx.ALL, 0)

            # ---------------- TABLE --------------- #
            for device in self.devices.devices_list:

                name = self.devices.names.get_name_string(device.device_id)

                # DEVICE NAME
                label = wx.StaticText(self.middle_panel,
                                      label=self.devices.names.get_name_string(
                                          device.device_id))
                label = self.style(label, self.label_font)
                device_info.Add(label, 0, wx.ALL | wx.ALIGN_CENTER_VERTICAL, 5)
                # DEVICE TYPE
                label = wx.StaticText(self.middle_panel,
                                      label=self.devices.names.get_name_string(
                                          device.device_kind))
                label = self.style(label, self.label_font)
                device_info.Add(label, 0, wx.ALL | wx.ALIGN_CENTER_VERTICAL, 5)
                # INPUT NAMES
                s = ""
                for i in device.inputs:
                    s = s + '{}.{}\n'.format(name,
                                             self.names.get_name_string(i))
                s = s[:-1]

                label = wx.StaticText(self.middle_panel, label=s)
                label = self.style(label, self.label_font)
                device_info.Add(label, 0,
                                wx.EXPAND | wx.ALL | wx.ALIGN_CENTER_VERTICAL,
                                5)
                # MONITOR OPTIONS
                # TODO: make them do somwthing
                if device.device_kind == self.devices.D_TYPE:
                    device.monitor_btn = wx.ToggleButton(
                        self.middle_panel, label="monitor {}.Q".format(name))
                    device.monitor_btn_bar = wx.ToggleButton(
                        self.middle_panel,
                        label="monitor {}.QBAR".format(name))
                    device.monitor_btn.Bind(wx.EVT_TOGGLEBUTTON,
                                            self.OnToggleClick)

                    device.monitor_btn.SetForegroundColour('white')
                    device.monitor_btn_bar.Bind(wx.EVT_TOGGLEBUTTON,
                                                self.OnToggleClick)
                    device.monitor_btn_bar.SetForegroundColour('white')

                    row = wx.BoxSizer(wx.VERTICAL)
                    row.Add(
                        device.monitor_btn, 1,
                        wx.ALL | wx.ALIGN_CENTER | wx.ALIGN_CENTER_VERTICAL, 5)
                    row.Add(
                        device.monitor_btn_bar, 1,
                        wx.ALL | wx.ALIGN_CENTER | wx.ALIGN_CENTER_VERTICAL, 5)

                    if name + '.Q' in self.monitors.get_signal_names()[0]:
                        device.monitor_btn.SetValue(True)
                        device.monitor_btn.SetBackgroundColour('#3ac10d')
                    else:
                        device.monitor_btn.SetBackgroundColour('#e0473a')

                    if name + '.QBAR' in self.monitors.get_signal_names()[0]:
                        device.monitor_btn_bar.SetValue(True)
                        device.monitor_btn_bar.SetBackgroundColour('#3ac10d')
                    else:
                        device.monitor_btn_bar.SetBackgroundColour('#e0473a')

                    device_info.Add(
                        row, 1,
                        wx.ALL | wx.ALIGN_CENTER | wx.ALIGN_CENTER_VERTICAL, 5)
                else:
                    device.monitor_btn = wx.ToggleButton(
                        self.middle_panel, label="monitor {}".format(name))
                    device.monitor_btn.Bind(wx.EVT_TOGGLEBUTTON,
                                            self.OnToggleClick)
                    device.monitor_btn.SetForegroundColour('white')

                    if name in self.monitors.get_signal_names()[0]:
                        device.monitor_btn.SetValue(True)
                        device.monitor_btn.SetBackgroundColour('#3ac10d')
                    else:
                        device.monitor_btn.SetBackgroundColour('#e0473a')

                    device_info.Add(
                        device.monitor_btn, 1,
                        wx.ALL | wx.ALIGN_CENTER | wx.ALIGN_CENTER_VERTICAL, 5)

            # ----------- SET INITIAL SWITCH STATES ------------ #
            self.switch_options = wx.FlexGridSizer(2, 0, 30)
            for device in self.devices.devices_list:
                if device.device_kind != self.devices.SWITCH:
                    continue
                name = self.devices.names.get_name_string(device.device_id)

                label = wx.StaticText(self.middle_panel, 1, label=name)
                label = self.style(label, self.label_font)
                self.switch_options.Add(label, 1,
                                        wx.ALL | wx.ALIGN_CENTER_VERTICAL, 5)

                device.switch_btn = wx.ToggleButton(
                    self.middle_panel, label="initial switch state")
                device.switch_btn.Bind(wx.EVT_TOGGLEBUTTON, self.OnToggleClick)
                device.switch_btn.SetForegroundColour('white')
                if device.switch_state:
                    device.switch_btn.SetValue(True)
                    device.switch_btn.SetBackgroundColour('#3ac10d')
                else:
                    device.switch_btn.SetBackgroundColour('#e0473a')

                self.switch_options.Add(device.switch_btn, 1, wx.ALL, 5)

            self.middle_sizer.Insert(1, self.switch_options, 0,
                                     wx.ALL | wx.ALIGN_CENTER, 30)
            self.middle_sizer.Insert(1, wx.StaticLine(self.middle_panel), 0,
                                     wx.EXPAND, 5)

            self.middle_sizer.Insert(1, device_info, 0,
                                     wx.ALL | wx.ALIGN_CENTER, 30)

            simulate_btn = wx.Button(self.middle_panel, label="Simulate!")
            simulate_btn.Bind(wx.EVT_BUTTON, self.newSimulate)

            self.middle_sizer.Add(simulate_btn, 0, wx.ALL | wx.EXPAND, 30)

        self.middle_panel.Show()
        self.SimulateWindow = SimulatePage(self)

        self.canvas = CircuitDiagram(self.right_panel, self.devices,
                                     self.network, self.names)
        self.right_sizer.Clear()
        self.right_sizer.Add(self.canvas, 1, wx.EXPAND | wx.ALL, 0)

        self.Layout()

    def newSimulate(self, event):
        self.SimulateWindow.Show()

        self.monitors.reset_monitors()

        for device in self.devices.devices_list:
            if hasattr(device, 'monitor_btn'):
                if device.monitor_btn.GetValue():
                    if device.device_kind == self.devices.D_TYPE:
                        self.monitors.make_monitor(device.device_id,
                                                   self.names.query("Q"))
                    else:
                        self.monitors.make_monitor(device.device_id, None)

            if hasattr(device, 'monitor_btn_bar'):
                if device.monitor_btn_bar.GetValue():
                    self.monitors.make_monitor(device.device_id,
                                               self.names.query("QBAR"))

            if hasattr(device, 'switch_btn'):
                if device.switch_btn.GetValue():
                    self.devices.set_switch(device.device_id,
                                            self.devices.HIGH)
                else:
                    self.devices.set_switch(device.device_id, self.devices.LOW)

        self.SimulateWindow.run(5)

    def OnRightPanelToggle(self, event):
        obj = event.GetEventObject()
        if obj.GetValue():
            self.right_panel.Show()
        else:
            self.right_panel.Hide()
        self.Layout()

    def OnToggleClick(self, event):
        obj = event.GetEventObject()
        if obj.GetValue():
            obj.SetBackgroundColour('#3ac10d')
        else:
            obj.SetBackgroundColour('#e0473a')

    def style(self, obj, font, fgcolour='white', bgcolour=None):
        obj.SetForegroundColour(fgcolour)
        obj.SetBackgroundColour(bgcolour)
        obj.SetFont(font)
        return obj

    def LoadFile(self, event):

        # otherwise ask the user what new file to open
        with wx.FileDialog(self,
                           "Open file",
                           wildcard="TXT files (*.txt)|*.txt",
                           style=wx.FD_OPEN
                           | wx.FD_FILE_MUST_EXIST) as fileDialog:
            fileDialog.SetSize((120, 80))

            if fileDialog.ShowModal() == wx.ID_CANCEL:
                return  # the user changed their mind

            # Proceed loading the file chosen by the user
            pathname = fileDialog.GetPath()
            try:
                with open(pathname, 'r') as f:
                    self.input_text.ClearAll()
                    self.input_text.AppendText(f.read())
            except IOError:
                wx.LogError("Cannot open file '%s'." % pathname)

    def open_help(self, event):
        filepath = 'GUI/helpfile.pdf'
        import subprocess
        import os
        import platform

        if platform.system() == 'Darwin':  # macOS
            subprocess.call(('open', filepath))
        elif platform.system() == 'Windows':  # Windows
            filepath = filepath.replace('/', '\\')
            os.startfile(filepath)
        else:  # linux variants
            subprocess.call(('xdg-open', filepath))
        event.Skip()
Пример #25
0
class Gui(wx.Frame):
    """
    Configure the main window and all the widgets.

    This class provides a graphical user interface for the Logic Simulator and
    enables the user to change the circuit properties and run simulations.

    Parameters
    ----------
    title: title of the window.

    Public methods
    --------------
    on_menu(self, event): Event handler for the file menu.

    on_spin(self, event): Event handler for when the user changes the spin
                           control value.

    on_run_button(self, event): Event handler for when the user clicks the run
                                button.

    on_text_box(self, event): Event handler for when the user enters text.
    """
    def __init__(self, title, path, names, devices, network, monitors):
        """Initialise widgets and layout."""
        super().__init__(parent=None, title=title, size=(800, 600))
        """Initialise variables."""
        self.names = names
        self.devices = devices
        self.monitors = monitors
        self.network = network
        # Setting up the file menu
        self.fileMenu = wx.Menu()
        self.fileMenu.Append(102, _(u"&About"))
        self.fileMenu.Append(wx.ID_OPEN, _(u"&Open"))
        self.fileMenu.Append(103, _(u"&Quit"))

        # Create the menu bar
        self.menuBar = wx.MenuBar()
        # Adding the "file menu" to the menu bar
        self.menuBar.Append(self.fileMenu, _(u"&File"))
        # Adding the menu bar to the frame content
        self.SetMenuBar(self.menuBar)

        # Canvas for drawing signals
        self.canvas_2d = MyGLCanvas2D(self, devices, monitors)
        self.canvas_3d = MyGLCanvas3D(self, devices, monitors)
        self.canvas_2d.Show()
        self.canvas_3d.Hide()

        # Configure the widgets
        self.lblLogWindow = wx.StaticText(self, -1, label=_(u"Console"))
        self.logWindow = wx.TextCtrl(self,
                                     -1,
                                     style=wx.TE_MULTILINE | wx.TE_READONLY,
                                     size=(100, 500))

        self.lblList = ['2D', '3D']
        self.render = wx.RadioBox(self,
                                  label=_(u"Render"),
                                  choices=self.lblList,
                                  majorDimension=1,
                                  style=wx.RA_SPECIFY_ROWS)
        self.render.SetSelection(0)
        self.state = self.render.GetSelection()
        self.languagelist = ["English", "Chinese"]
        self.language = wx.RadioBox(self,
                                    label=_(u"Language"),
                                    choices=self.languagelist,
                                    majorDimension=1,
                                    style=wx.RA_SPECIFY_ROWS)
        global lang_sel
        self.language.SetSelection(lang_sel)
        self.current_lang = self.language.GetSelection()
        self.text_run = wx.StaticText(self, wx.ID_ANY, _(u"Cycles to run"))
        self.text_cont = wx.StaticText(self, wx.ID_ANY,
                                       _(u"Cycles to continue"))
        self.spin_run = wx.SpinCtrl(self, wx.ID_ANY, "10", max=2147483647)
        self.spin_cont = wx.SpinCtrl(self, wx.ID_ANY, "2", max=2147483647)
        self.run = wx.Button(self, wx.ID_ANY, _(u"Run"))
        self.cont = wx.Button(self, wx.ID_ANY, _(u"Continue"))
        self.ResetButton = wx.Button(self, wx.ID_ANY, _(u"Clear"))
        self.set_switch = wx.Button(self, wx.ID_ANY, _(u"Set Switches"))
        self.select_monitor = wx.Button(self, wx.ID_ANY, _(u"Monitor"))
        self.default_position = wx.Button(self, wx.ID_ANY,
                                          _(u"Default Position"))

        # Bind events to widgets
        self.Bind(wx.EVT_MENU, self.on_menu)
        self.render.Bind(wx.EVT_RADIOBOX, self.on_radiobox)
        self.language.Bind(wx.EVT_RADIOBOX, self.on_sel_language)
        self.spin_run.Bind(wx.EVT_SPINCTRL, self.on_spin)
        self.spin_cont.Bind(wx.EVT_SPINCTRL, self.on_spin_cont)
        self.run.Bind(wx.EVT_BUTTON, self.on_run_button)
        self.cont.Bind(wx.EVT_BUTTON, self.on_continue_button)
        self.ResetButton.Bind(wx.EVT_BUTTON, self.on_reset_button)
        self.set_switch.Bind(wx.EVT_BUTTON, self.check_box)
        self.select_monitor.Bind(wx.EVT_BUTTON, self.check_box_monitor)
        self.default_position.Bind(wx.EVT_BUTTON, self.on_default_pos)

        # Configure sizers for layout
        self.main_sizer = wx.BoxSizer(wx.HORIZONTAL)
        side_sizer = wx.BoxSizer(wx.VERTICAL)

        self.main_sizer.Add(self.canvas_2d, 5, wx.EXPAND | wx.ALL, 5)
        self.main_sizer.Add(side_sizer, 1, wx.ALL, 5)

        side_sizer.Add(self.language, 0, wx.TOP, 5)
        side_sizer.Add(self.render, 0, wx.TOP, 5)
        side_sizer.Add(self.text_run, 1, wx.TOP, 10)
        side_sizer.Add(self.spin_run, 1, wx.ALL, 5)
        side_sizer.Add(self.run, 1, wx.EXPAND, 5)
        side_sizer.Add(self.text_cont, 1, wx.TOP, 10)
        side_sizer.Add(self.spin_cont, 1, wx.ALL, 5)
        side_sizer.Add(self.cont, 1, wx.EXPAND, 5)
        side_sizer.Add(self.set_switch, 1, wx.EXPAND, 5)
        side_sizer.Add(self.select_monitor, 1, wx.EXPAND, 5)
        side_sizer.Add(self.ResetButton, 1, wx.EXPAND, 5)
        side_sizer.Add(self.default_position, 1, wx.EXPAND, 5)
        side_sizer.Add(self.lblLogWindow, 1, wx.TOP, 5)
        side_sizer.Add(self.logWindow, 1, wx.EXPAND, 5)

        self.SetSizeHints(600, 600)
        self.SetSizer(self.main_sizer)

        # A modal show will lock out the other windows until it has been dealth with
        # Very useful in some programming tasks to ensure that things happen in an order
        # that the programmer expects, but can be very frustrating to the user if it is
        # used to excess
        self.exitconfirmation = wx.MessageDialog(
            self, _(u"Are you sure you want to quit the simulation? \n"),
            _(u"Confirmation"), wx.YES_NO)
        self.openFileDialog = wx.FileDialog(
            self, _(u"Select Logic Definition File"), "", "",
            _(u"Logic definition files (*.txt)|*.txt"),
            wx.FD_OPEN | wx.FD_FILE_MUST_EXIST)
        sys.stdout = self.logWindow

    def on_sel_language(self, event):
        self.current_lang = self.language.GetSelection()

        if self.current_lang == 0:
            app = ab.BaseApp(redirect=False)
            app.updateLanguage(u"en")
            print(_(u"English is selected"))
            global lang_sel
            lang_sel = 0
        else:
            app = ab.BaseApp(redirect=False)
            app.updateLanguage(u"zh_CN")
            print(_(u"Chinese is selected"))
            lang_sel = 1

        self.text_run.SetLabel(_(u"Cycles to run"))
        self.text_cont.SetLabel(_(u"Cycles to continue"))
        self.run.SetLabel(_(u"Run"))
        self.cont.SetLabel(_(u"Continue"))
        self.ResetButton.SetLabel(_(u"Clear"))
        self.set_switch.SetLabel(_(u"Set Switches"))
        self.select_monitor.SetLabel(_(u"Monitor"))
        self.default_position.SetLabel(_(u"Default Position"))
        self.language.SetLabel(_(u"Language"))
        self.render.SetLabel(_(u"Render"))
        self.lblLogWindow.SetLabel(_(u"Console"))
        self.fileMenu.SetLabel(102, _(u"About"))
        self.fileMenu.SetLabel(103, _(u"Quit"))
        self.menuBar.SetMenuLabel(0, _(u"File"))
        self.fileMenu.SetLabel(wx.ID_OPEN, _(u"&Open"))

    def on_radiobox(self, event):
        self.state = self.render.GetSelection()
        print(self.lblList[self.state], _(u" was selected"))
        if self.state == 0:
            #Change from 3D to 2D
            self.main_sizer.Replace(self.canvas_3d, self.canvas_2d)
            self.canvas_3d.Hide()
            self.canvas_2d.Show()
        else:
            #Change from 2D to 3D
            self.main_sizer.Replace(self.canvas_2d, self.canvas_3d)
            self.canvas_2d.Hide()
            self.canvas_3d.Show()
        self.main_sizer.Layout()

    def on_default_pos(self, event):
        self.canvas_2d.default_position()
        self.canvas_3d.default_position()

    def check_box_monitor(self, event):
        MyDialog_monitor(self, -1, _(u"Select signals to monitor"), self.names,
                         self.devices, self.monitors).Show()

    def check_box(self, event):
        MyDialog(self, -1, _(u"Set switches to 1"), self.names,
                 self.devices).Show()

    def on_menu(self, event):
        """Handle the event when the user selects a menu item."""
        Id = event.GetId()
        if Id == 103:
            exitconf = self.exitconfirmation.ShowModal()
            if exitconf == wx.ID_YES:
                self.Close(True)
        if Id == 102:
            wx.MessageBox(
                _(u"Display the signal traces at different monitored outputs.  \nRed trace represents '1', blue trace represents '0'.\nOutputs to be monitored can be selected by clicking 'Monitor'.\nSwitches levels can be selected by clicking 'Set Switches'"
                  ), _(u"About Logsim"), wx.ICON_INFORMATION | wx.OK)

        if Id == wx.ID_OPEN:
            with wx.FileDialog(self) as fileDialog:
                if fileDialog.ShowModal() == wx.ID_CANCEL:
                    return
                path = fileDialog.GetPath()
                self.Close(True)

                app = wx.App()
                error = ErrorFrame()

                names = Names()
                devices = Devices(names)
                network = Network(names, devices)
                monitors = Monitors(names, devices, network)
                self.names = names
                self.devices = devices
                self.network = network
                self.monitors = monitors
                self.scanner = Scanner(path, self.names)
                self.parser = Parser(self.names, self.devices, self.network,
                                     self.monitors, self.scanner)
                global global_cycles_completed
                global hold
                global hold_monitor
                global_cycles_completed = 0
                hold = {}
                hold_monitor = {}
                try:
                    self.parser.parse_network()
                    gui = Gui("LogicSim", path, self.names, self.devices,
                              self.network, self.monitors)
                    gui.Show(True)
                except:
                    pass

                error.ShowModal()
                app.MainLoop()

    def on_spin(self, event):
        """Handle the event when the user changes the spin control value."""
        spin_value = self.spin_run.GetValue()
        text = "".join([_(u"New run spin control value: "), str(spin_value)])
        if self.state == 0:
            self.canvas_2d.render(text)
        else:
            self.canvas_3d.render()
        return spin_value

    def on_spin_cont(self, event):
        """Handle the event when the user changes the spin control value."""
        spin_value_cont = self.spin_cont.GetValue()
        text = "".join(
            [_(u"New continue spin control value: "),
             str(spin_value_cont)])
        if self.state == 0:
            self.canvas_2d.render(text)
        else:
            self.canvas_3d.render()
        return spin_value_cont

    def on_run_button(self, event):
        """Handle the event when the user clicks the run button."""
        text = _(u"Run button pressed.")
        if self.state == 0:
            self.canvas_2d.render(text)
        else:
            self.canvas_3d.render()
        self.run_command()

    def on_continue_button(self, event):
        """Handle the event when the user clicks the Continue button."""
        text = _(u"Continue button pressed.")
        if self.state == 0:
            self.canvas_2d.render(text)
        else:
            self.canvas_3d.render()
        self.continue_command()

    def on_reset_button(self, event):
        """Handle the event when the user clicks the reset button."""
        text = _(u"Reset button pressed.")
        if self.state == 0:
            self.canvas_2d.render(text)
        else:
            self.canvas_3d.render()

        dialog_box = MyDialog_monitor(self, -1,
                                      _(u"Select signals to monitor"),
                                      self.names, self.devices, self.monitors)
        dialog_box.Destroy()

        global hold_monitor
        differential = hold_monitor

        hold_monitor = dict.fromkeys(hold_monitor, False)

        dialog_box = MyDialog_monitor(self, -1,
                                      _(u"Select signals to monitor"),
                                      self.names, self.devices, self.monitors)

        hold_monitor = differential
        dialog_box.ok_button(wx.EVT_BUTTON)

        dialog_box.Destroy()
        hold_monitor = dict.fromkeys(hold_monitor, False)
        if self.state == 0:
            self.canvas_2d.Refresh()
        else:
            self.canvas_3d.Refresh()
        global global_cycles_completed
        global_cycles_completed = 0

    def on_text_box(self, event):
        """Handle the event when the user enters text."""
        text_box_value = self.text_box.GetValue()
        text = "".join([_(u"New text box value: "), text_box_value])
        if self.state == 0:
            self.canvas_2d.render(text)
        else:
            self.canvas_3d.render()

    def run_command(self):
        """Run the simulation from scratch."""
        global global_cycles_completed
        global_cycles_completed = 0

        cycles = self.on_spin(wx.SpinCtrl)

        # check that this function has been called on pressing run button
        text = "".join([
            _(u"run_command function has been called, number of cycles is: "),
            str(cycles)
        ])
        if self.state == 0:
            self.canvas_2d.render(text, True)
        else:
            self.canvas_3d.render()

        if cycles is not None:  # if the number of cycles provided is valid
            self.monitors.reset_monitors()
            print("".join([_(u"Running for "), str(cycles), _(u" cycles")]))
            self.devices.cold_startup()
            if self.run_network(cycles):
                global_cycles_completed += cycles

    def continue_command(self):
        """Continue a previously run simulation."""
        cycles_cont = self.on_spin_cont(wx.SpinCtrl)
        global global_cycles_completed
        # check that this function has been called on pressing continue button
        text = "".join([
            _(u"continue_command function has been called, number of cycles is: "
              ),
            str(cycles_cont)
        ])
        if self.state == 0:
            self.canvas_2d.render(text, True)
        else:
            self.canvas_3d.render()
        if cycles_cont is not None:  # if the number of cycles provided is valid
            if global_cycles_completed == 0:
                print(_(u"Error! Nothing to continue. Run first."))
            elif self.run_network(cycles_cont):
                global_cycles_completed += cycles_cont
                print(" ".join([
                    _(u"Continuing for"),
                    str(cycles_cont),
                    _(u"cycles."),
                    _(u"Total:"),
                    str(global_cycles_completed)
                ]))

    def run_network(self, cycles):
        """Run the network for the specified number of simulation cycles.

        Return True if successful.
        """
        for _ in range(cycles):
            if self.network.execute_network():
                self.monitors.record_signals()
            else:
                print(_(u"Error! Network oscillating."))
                return False
        self.monitors.display_signals()
        text = "The signal trace is printed"
        if self.state == 0:
            self.canvas_2d.render(text, True)
        else:
            self.canvas_3d.render()
        return True
Пример #26
0
Файл: gui.py Проект: ip342/GF2
    def on_load_button(self, event):
        """Handle the event when the user clicks load button."""
        with wx.FileDialog(self,
                           _("Open Definition file"),
                           wildcard="Definition files (*.txt)|*.txt",
                           style=wx.FD_OPEN
                           | wx.FD_FILE_MUST_EXIST) as fileDialog:

            if fileDialog.ShowModal() == wx.ID_CANCEL:
                return

            self.pathname = fileDialog.GetPath()

            self.filename = self.path_leaf(self.pathname)

            names = Names()
            devices = Devices(names)
            network = Network(names, devices)
            monitors = Monitors(names, devices, network)
            scanner = Scanner(self.pathname, names)
            parser = Parser(names, devices, network, monitors, scanner)
            parser.parse_network()
            error_list = scanner.error_list
            num_errors = len(error_list)

            pages = math.ceil(num_errors / 4)

            if num_errors != 0:

                text_list = []
                tab_labels = []

                for i in range(pages - 1):
                    tab_labels.append("{}-{}".format(1 + i * 4, 4 + i * 4))
                    label = 4 + i * 4

                if num_errors == 1:
                    tab_labels.append("1")
                elif num_errors <= 4:
                    tab_labels.append("1-{}".format(num_errors))
                else:
                    if (label + 1) == num_errors:
                        tab_labels.append("{}".format(num_errors))
                    else:
                        tab_labels.append("{}-{}".format(
                            label + 1, num_errors))

                if num_errors == 1:
                    overview = _("\nDefinition file '{}' contains {} error.")\
                        .format(self.filename, num_errors)
                else:
                    overview = _("\nDefinition file '{}' contains {} errors.")\
                        .format(self.filename, num_errors)

                for i in range(pages):
                    if i == 0:
                        text = '\n' + '*' * 76 + '\n'
                    else:
                        text = "".format(self.filename, num_errors)
                    for j in range(4):
                        try:
                            text += (error_list[j + i * 4] + "\n")
                        except IndexError:
                            text += ('\n' * 8)
                    text_list.append(text)

                frame = DefinitionErrors(self,
                                         title=_("Error!"),
                                         text=text_list,
                                         tabs=tab_labels,
                                         overview=overview)

                return

        self.current_filename = self.filename
        self.current_pathname = self.pathname
        self.load_new = True
        self.Show(False)
        self.Destroy()