예제 #1
0
class ExplorerProGui(BanyanBase):
    """
    The Pimoroni Explorer-Pro For Raspberry Pi Demo Station GUI
    """

    def __init__(self, **kwargs):
        """
        Build the main screen as a notebook.
        """

        # initialize the parent class
        super(ExplorerProGui, self).__init__(
            back_plane_ip_address=kwargs['back_plane_ip_address'],
            subscriber_port=kwargs['subscriber_port'],
            publisher_port=kwargs['publisher_port'],
            process_name=kwargs['process_name'])

        self.set_subscriber_topic('report_from_hardware')

        self.main = Tk()
        self.main.title('Demo Station For Explorer-Pro HAT')

        # gives weight to the cells in the grid
        rows = 0
        while rows < 50:
            self.main.rowconfigure(rows, weight=1)
            self.main.columnconfigure(rows, weight=1)
            rows += 1

        # Defines and places the notebook widget
        self.nb = Notebook(self.main, padding=20, height=300, width=800)
        self.nb.grid(row=1, column=0, columnspan=50, rowspan=49, sticky='NESW')

        # create the analog inputs tab
        self.analog_inputs_tab = Frame(self.nb, padding=[130, 20])
        self.nb.add(self.analog_inputs_tab, text='Analog Inputs')
        # create an instance of the AnalogInputs class
        self.analog_inputs = AnalogInputs(self.analog_inputs_tab, self)

        # create the digital inputs tab
        self.digital_inputs_tab = Frame(self.nb, padding=[130, 20])
        self.nb.add(self.digital_inputs_tab, text='Digital Inputs')
        # create an instance of the DigitalInputs class
        # to populate and control Signal inputs
        self.digital_inputs = DigitalInputs(self.digital_inputs_tab, self)

        # create the touch tab
        self.touch_tab = Frame(self.nb, padding=10)
        self.nb.add(self.touch_tab, text='Touch Inputs')
        self.touch_inputs = TouchInputs(self.touch_tab, self)

        # create the digital outputs tab
        self.digital_outputs_tab = Frame(self.nb, padding=10)
        self.nb.add(self.digital_outputs_tab, text='Digital Outputs')
        # create an instance of the DigitalOutputs class
        # to populate and control digital outputs
        self.digital_outputs = DigitalOutputs(self.digital_outputs_tab, self)

        # create the LED digital outputs tab
        self.led_digital_outputs_tab = Frame(self.nb, padding=10)
        self.nb.add(self.led_digital_outputs_tab, text='LED Digital Outputs')
        # create an instance of the DigitalOutputs class
        # to populate and control digital outputs
        self.led_digital_outputs = LedDigitalOutputs(self.led_digital_outputs_tab, self)

        # create the pwm output tab
        self.pwm_output_tab = Frame(self.nb, padding=10)
        self.nb.add(self.pwm_output_tab, text='PWM Outputs')
        self.pwm_output = PwmOutputs(self.pwm_output_tab, self)

        # create the LED PWM output tab
        self.led_pwm_output_tab = Frame(self.nb, padding=10)
        self.nb.add(self.led_pwm_output_tab, text='LED PWM Outputs')
        self.led_pwm_output = LedPwmOutputs(self.led_pwm_output_tab, self)

        # create the dc motors tab
        self.motors_tab = Frame(self.nb, padding=10)
        self.nb.add(self.motors_tab, text='DC Motors')
        self.dc_motors = DcMotors(self.motors_tab, self)

        l = Label(self.main,
                  text='Copyright (c) 2019 Alan Yorinks All Rights Reserved.')
        l.config(font="Helvetica 8 ")
        l.grid(row=48, column=0, padx=[505, 0])

        self.main.after(5, self.get_message)

        try:
            self.main.mainloop()
        except KeyboardInterrupt:
            self.on_closing()

    def notebook_tab_selection(self):
        print(self.nb.tab(self.nb.select(), "text"))
        print(self.nb.index(self.nb.select()))

    # noinspection DuplicatedCode
    def get_message(self):
        """
        This method is called from the tkevent loop "after" method.
        It will poll for new zeromq messages within the tkinter event loop.
        """
        try:
            data = self.subscriber.recv_multipart(zmq.NOBLOCK)
            self.incoming_message_processing(data[0].decode(),
                                             msgpack.unpackb(data[1],
                                                             raw=False))
            self.main.after(1, self.get_message)

        except zmq.error.Again:
            try:
                self.main.after(1, self.get_message)
            except KeyboardInterrupt:
                self.main.destroy()
                self.publisher.close()
                self.subscriber.close()
                self.context.term()
                sys.exit(0)
        except KeyboardInterrupt:
            self.main.destroy()
            self.publisher.close()
            self.subscriber.close()
            self.context.term()
            sys.exit(0)

    def incoming_message_processing(self, topic, payload):
        """
        This method processes the incoming pin state change
        messages for GPIO pins set as inputs.

        :param topic:
        :param payload:

        Typical report: {'report': 'digital_input', 'pin': pin,
                       'value': level, 'timestamp': time.time()}
        """
        # if the pin currently input active, process the state change
        pin = payload['pin'] - 1
        value = payload['value']
        timestamp = payload['timestamp']
        report_type = payload['report']
        if report_type == 'analog_input':
            if 0 <= pin <= 3:
                self.analog_inputs.set_input_value(pin, value)
                self.analog_inputs.set_time_stamp_value(pin, timestamp)
            else:
                raise RuntimeError('analog pin out of range: ', pin)
        elif report_type == 'digital_input':
            if 0 <= pin <= 3:
                self.digital_inputs.set_input_value(pin, value)
                self.digital_inputs.set_time_stamp_value(pin, timestamp)
            else:
                raise RuntimeError('digital pin out of range')
        elif report_type == 'touch':
            if 0 <= pin <= 8:
                self.touch_inputs.set_input_value(pin, value)
                self.touch_inputs.set_time_stamp_value(pin, timestamp)
            else:
                raise RuntimeError('touch pin out of range')
        else:
            raise RuntimeError('Unknown report type: ', payload['report'])

    def on_closing(self):
        """
        Destroy the window
        """
        self.clean_up()
        self.main.destroy()
예제 #2
0
class App:
    # need it for generate reports
    __ast = None
    __sym_table = None
    __sym_table_3d = None

    def __init__(self, ide):

        # setting title
        ide.title("TenorC @danii_mor")

        # setting window size
        width=700
        height=400
        screenwidth = ide.winfo_screenwidth()
        screenheight = ide.winfo_screenheight()
        alignstr = '%dx%d+%d+%d' % (width, height, (screenwidth - width) / 2, (screenheight - height) / 2)
        ide.geometry(alignstr)
        ide.resizable(width=True, height=True)

        # create menubar
        menubar = Menu(ide)

        # file menu
        filemenu = Menu(menubar, tearoff=0)
        filemenu.add_command(label="New", command=self.newFile)
        filemenu.add_command(label="Open", command=self.file_open)
        filemenu.add_command(label="Save", command=self.file_save)
        filemenu.add_command(label="Save as...", command=self.file_save_as)
        filemenu.add_command(label="Close", command=self.exitTab)

        filemenu.add_separator()

        filemenu.add_command(label="Exit", command=ide.quit)
        

        # edit menu
        editmenu = Menu(menubar, tearoff=0)
        editmenu.add_command(label="Cut", command=self.donothing)
        editmenu.add_command(label="Copy", command=self.copy_to_clipboard)
        editmenu.add_command(label="Paste", command=self.donothing)

        editmenu.add_separator()

        editmenu.add_command(label="Find", command=self.donothing)
        editmenu.add_command(label="Replace", command=self.donothing)


        # run menu
        runmenu = Menu(menubar, tearoff=0)
        runmenu.add_command(label="Execute Analysis", command=self.execute_current_tab_lef)
        runmenu.add_command(label="Show Intermediate Code", command=self.show3D)

        runmenu.add_separator()

        runmenu.add_command(label="Symbol Table", command=self.show_sym_table)
        runmenu.add_command(label="Error Report", command=self.show_error)
        runmenu.add_command(label="Abstract Syntax Tree", command=self.show_ast)
        runmenu.add_command(label="Grammar", command=self.show_grammar)

        runmenu.add_separator()
        
        runmenu.add_command(label="Debugging", command=self.execute_debug)


        # option menu
        #optionmenu = Menu(menubar, tearoff=0)
        #optionmenu.add_command(label="Theme...", command=self.donothing)
        #optionmenu.add_command(label="Line Numbers...", command=self.donothing)


        # help menu
        helpmenu = Menu(menubar, tearoff=0)
        helpmenu.add_command(label="Help", command=self.donothing)
        helpmenu.add_command(label="About...", command=self.show_info)
        

        # setting menu
        menubar.add_cascade(label="File", menu=filemenu)
        menubar.add_cascade(label="Edit", menu=editmenu)
        menubar.add_cascade(label="Run", menu=runmenu)
        menubar.add_cascade(label="Help", menu=helpmenu)
        ide.config(menu=menubar)

        # setting editor area
        self.tabs = Notebook(ide)
        f1 = Frame(self.tabs)
        self.tabs.add(f1, text="+")
        self.tabs.pack(side="top", fill="both", expand=True, padx=10, pady=0)

        self.tabs.bind("<<NotebookTabChanged>>", self.addTab)


        # setting terminal area
        self.terminal= Text(ide)
        ft = tkFont.Font(family="Lucinda Console", size=10)
        self.terminal["font"] = ft
        self.terminal["wrap"] = "word"
        self.terminal["fg"] = "white"
        self.terminal["bg"] = "black"
        self.terminal["insertbackground"] ="white"
        self.terminal["height"] = 5
        self.terminal["width"] = 5
        self.terminal.pack( side = "left", fill = "both", expand=True,  padx=10, pady=10)

        terminal_scroll = Scrollbar(ide)
        terminal_scroll["orient"] = "vertical"
        terminal_scroll["command"] = self.terminal.yview
        terminal_scroll.pack(side="right", fill="y")

        self.terminal.configure(yscrollcommand=terminal_scroll.set)
        self.terminal.bind("<Return>", self.execute_command)

    def copy_to_clipboard(self):
        selectedTab = self.tabs.index("current")
        currentTextArea = self.tabs.winfo_children()[selectedTab+1].textarea
        try:
            selected_text= currentTextArea.get("sel.first", "sel.last")
            currentTextArea.clipboard_append(selected_text)
        except:
            pass

    def show_grammar(self):
        if self.__sym_table:
            window = Toplevel()
            window['bg'] = 'black'
            productions = self.__sym_table.getGrammar()
            keys = list(productions.keys())
            keys.sort()
            grammar = Message(window)
            txt = ''
            for production in keys:
                txt += productions[production] + '\n' 
            grammar['fg'] = 'white'
            grammar['bg'] = 'black'
            grammar['text'] = txt
            grammar.pack(side='left')
    
    def show_error(self):
        if self.__sym_table:
            if self.__sym_table.error != '':
                window = Toplevel()
                window['bg'] = 'black'

                grammar = Message(window)
                grammar['fg'] = 'white'
                grammar['bg'] = 'black'
                grammar['text'] = self.__sym_table.error
                grammar.pack(side='left')
            else:
                window = Toplevel()
                window['bg'] = 'black'

                grammar = Message(window)
                grammar['fg'] = 'white'
                grammar['bg'] = 'black'
                grammar['text'] = 'Not Errors Found'
                grammar.pack(side='left')

    # TODO fix it
    def show_sym_table(self):
        if self.__sym_table:
            showTable(self.__sym_table)

    def show_ast(self):
        self.__ast.graph()
        showAST()

    codeGenerated = None
    def show3D(self):
        if self.codeGenerated != None:
            window = Toplevel()
            window['bg'] = 'black'

            grammar = Text(window)
            grammar['fg'] = 'white'
            grammar['bg'] = 'black'
            grammar.insert(1.0, self.codeGenerated)
            grammar.pack(side='left')

    def show_info(self):
        window = Toplevel()
        window['bg'] = 'black'

        grammar = Message(window)
        grammar['fg'] = 'white'
        grammar['bg'] = 'black'
        grammar['text'] = 'Augus intermediate code by Engr. Espino\nTenorC 1.23.2a Developed by @danii_mor\n 201314810'
        grammar.pack(side='left')

    def update_line_debugg(self, event= None):
        self.count["text"] = "Line: %s" % str(self.c+1)

        lines = self.codeGenerated.split('\n')

        # start execute line by self.c counter
        ply_left_3d = titus.parse()
        if self.c < len(lines):
            if "main:" not in lines[self.c]:
                line = "main:" + lines[self.c]
                result  = ply_left_3d(titus, line)
                if result:
                    ast = result[0]
                    ast.setType("LABEL")
                    ast.setValue("S")
                    ast.root = result[0]

                    if self.__sym_table_3d != None:
                        new_table =  {**self.__sym_table_3d.printTable(), **result[1].printTable()}
                        for sym_id in new_table:
                            sym = new_table[sym_id]
                            if sym != None:
                                if type(sym) == dict:
                                    continue
                                if sym.getValue() == None:
                                    try:
                                        new_table[sym_id] = self.__sym_table_3d.printTable()[sym_id]
                                    except:
                                        pass
                        self.__sym_table_3d.setTable({**self.__sym_table_3d.printTable(), **new_table})
                    else:
                        self.__sym_table_3d = result[1]
                        # define mode for syntax-tree know how to autoexecute
                        self.__sym_table_3d.setMode(1)

                    compute = [None, None]

                    # start execute
                    self.__sym_table_3d.terminal = self.terminal
                    compute = ast.start_execute(self.__sym_table_3d, "MAIN")
                    # lookup the last line
                    index = self.terminal.search(r'\n', "insert", backwards=True, regexp=True)
                    txt = self.terminal.get(str(index),'end-1c')
                    if txt == "":
                        index ="1.0"
                    else:
                        index = self.terminal.index("%s+1c" % index)
                    if compute[0]:
                        self.terminal.insert(str(float(index)+1), compute[0])
                        self.__sym_table_3d.cleanLog()
                    if compute[1]:
                        goto_line = 0
                        for l in lines:
                            if (compute[1]+":") in l:
                                break
                            goto_line = goto_line + 1
                        
                        self.c = goto_line - 1

            if self.__sym_table != None:
                if self.__sym_table.error != '':
                    # lookup the last line
                    index = self.terminal.search(r'\n', "insert", backwards=True, regexp=True)
                    txt = self.terminal.get(str(index),'end-1c')
                    if txt == "":
                        index ="1.0"
                    else:
                        index = self.terminal.index("%s+1c" % index)
                    self.terminal.insert(str(float(index)+1), "\nTenorC>> Error Report Generated\n")

            self.c = self.c + 1
            self.label_last_line["text"] = "Line: %s" % str(self.c+1)

    c = 0
    def execute_debug(self, event = None):
        self.__sym_table_3d = None

        self.c = 0
        # create debug player
        window = Toplevel()
        window['bg'] = 'black'

        label_count = Label(window, text="Execute Now:", 
                            borderwidth=0, width=10, bg = "black", fg = "white")
        label_count.grid(row=0, column=0, sticky="nsew", padx=1, pady=1)

        label_last = Label(window, text="Executed Before:", 
                            borderwidth=0, width=10, bg = "black", fg = "white")
        label_last.grid(row=0, column=2, sticky="nsew", padx=1, pady=1)

        self.label_last_line = Label(window, text="Line: 1", 
                            borderwidth=0, width=10, bg = "black", fg = "white")
        self.label_last_line.grid(row=1, column=0, sticky="nsew", padx=1, pady=1)

        execute = Button(window, text='>',
                                   command=self.update_line_debugg)
        execute.grid(row=1, column=1, sticky="nsew", padx=1, pady=1)

        self.count = Label(window, text="Line: 0", 
                            borderwidth=0, width=10, bg = "black", fg = "white")
        self.count.grid(row=1, column=2, sticky="nsew", padx=1, pady=1)

        window.grid_columnconfigure(0, weight=1)
        window.grid_columnconfigure(1, weight=1)
        window.grid_columnconfigure(2, weight=1)
        window.resizable(width=True, height=False)


        # get all txt from current tab
        selectedTab = self.tabs.index("current")
        currentTextArea = self.tabs.winfo_children()[selectedTab+1].textarea
        input = currentTextArea.get('1.0','end-1c')

        # new singleton symbol table
        self.__sym_table = table()

        # define mode for syntax-tree know how to autoexecute
        self.__sym_table.setMode(0)

        # start lex and sintactic analysis
        ply_left = tenorC.parse()

        self.__ast  = ply_left(tenorC, input, self.__sym_table)

        # TODO sintax error recover
        if self.__ast != None:
            self.__ast.execute(self.__sym_table)
            self.codeGenerated = self.__ast.get3D()

    def execute_current_tab_lef(self):
        # get all txt from current tab
        selectedTab = self.tabs.index("current")
        currentTextArea = self.tabs.winfo_children()[selectedTab+1].textarea
        input = currentTextArea.get('1.0','end-1c')

        # new singleton symbol table
        self.__sym_table = table()

        # define mode for syntax-tree know how to autoexecute
        self.__sym_table.setMode(0)

        # start lex and sintactic analysis
        ply_left = tenorC.parse()

        self.__ast  = ply_left(tenorC, input, self.__sym_table)

        # TODO sintax error recover
        if self.__ast != None:
            self.__ast.execute(self.__sym_table)
            self.codeGenerated = self.__ast.get3D()

            ## start executing

            ply_left_3d = titus.parse()
            result  = ply_left_3d(titus, self.codeGenerated)

            if result:
                ast_3D = result[0]
                ast_3D.setType("LABEL")
                ast_3D.setValue("S")
                ast_3D.root = True

                self.__sym_table_3d = result[1]

                # define mode for syntax-tree know how to autoexecute
                self.__sym_table_3d.setMode(1)

                goto_called = True
                start_from = "MAIN"
                compute = [None, None]
                while goto_called:
                    goto_called = False
                    self.__sym_table_3d.terminal = self.terminal
                    compute = ast_3D.start_execute(self.__sym_table_3d, start_from)
                    # lookup the last line
                    index = self.terminal.search(r'\n', "insert", backwards=True, regexp=True)
                    txt = self.terminal.get(str(index),'end-1c')
                    if txt == "":
                        index ="1.0"
                    else:
                        index = self.terminal.index("%s+1c" % index)
                    if compute[0]:
                        self.terminal.insert(str(float(index)+1), compute[0])
                        self.__sym_table_3d.cleanLog()
                    if compute[1]:
                        goto_called = True
                        start_from = compute[1]

        elif self.__sym_table.error != '':
            # lookup the last line
            index = self.terminal.search(r'\n', "insert", backwards=True, regexp=True)
            txt = self.terminal.get(str(index),'end-1c')
            if txt == "":
                index ="1.0"
            else:
                index = self.terminal.index("%s+1c" % index)
            self.terminal.insert(str(float(index)+1), "\nTenorC>> Error Report Generated\n")
    
    def execute_command(self, event):
        # lookup the last line
        index = self.terminal.search(r'\n', "insert", backwards=True, regexp=True)
        input = self.terminal.get(str(index),'end-1c')
        if input == "":
            index ="1.0"
        else:
            index = self.terminal.index("%s+1c" % index)
        input = self.terminal.get(index,'end-1c')
        # send the input to the calculate 
        self.__sym_table_3d.read_input.set(input)

    def newFile(self):
        lastindex = self.tabs.index("end")-1

        textarea = Editor(self.tabs)
        self.tabs.insert(lastindex, textarea, text="Tab" + str(lastindex+1))
        self.tabs.select(lastindex)

    def exitTab(self):
        result = self.save_if_modified()
        if result != None: #None => Aborted or Save cancelled, False => Discarded, True = Saved or Not modified
            selectedTab = self.tabs.index("current")
            currentTab = self.tabs.winfo_children()[selectedTab+1]
            
            self.tabs.select(self.tabs.winfo_children()[selectedTab])
            currentTab.destroy()

    def save_if_modified(self, event=None):
        selectedTab = self.tabs.index("current")
        currentTextArea = self.tabs.winfo_children()[selectedTab+1].textarea
        if currentTextArea.edit_modified(): #modified
            response = messagebox.askyesnocancel("Save?", "This document has been modified. Do you want to save changes?") #yes = True, no = False, cancel = None
            if response: #yes/save
                result = self.file_save()
                if result == "saved": #saved
                    return True
                else: #save cancelled
                    return None
            else:
                return response #None = cancel/abort, False = no/discard
        else: #not modified
            return True

    def file_open(self, event=None, filepath=None):
        if filepath == None:
            filepath = filedialog.askopenfilename()
        if filepath != None  and filepath != '':
            with open(filepath, encoding="utf-8") as f:
                fileContents = f.read()# Get all the text from file.           
            # Set current text to a new Tab file contents
            lastindex = self.tabs.index("end")-1

            textarea = Editor(self.tabs)
            self.tabs.insert(lastindex, textarea, text="Tab" + str(lastindex+1))
            self.tabs.select(lastindex)

            textarea.textarea.insert(1.0, fileContents)
            textarea.textarea.edit_modified(False)
            tab_tittle = os.path.basename(filepath)
            self.tabs.tab(lastindex, text = tab_tittle)

    def file_save(self, event=None):
        selectedTab = self.tabs.index("current")
        currentName = self.tabs.tab(selectedTab, "text")
        if 'Tab' in currentName:
            result = self.file_save_as()
        else:
            result = self.file_save_as(filepath='./' + currentName)
        return result

    def file_save_as(self, event=None, filepath=None):
        if filepath == None:
            filepath = filedialog.asksaveasfilename(filetypes=(('Text files', '*.txt'), ('C files', '*.mc'), ('All files', '*.*'))) #defaultextension='.txt'
        try:
            with open(filepath, 'wb') as f:
                selectedTab = self.tabs.index("current")
                currentTextArea = self.tabs.winfo_children()[selectedTab+1].textarea
                text = currentTextArea.get(1.0, "end-1c")
                f.write(bytes(text, 'UTF-8'))
                currentTextArea.edit_modified(False)
                tab_tittle = os.path.basename(filepath)
                self.tabs.tab(selectedTab, text = tab_tittle)
                return "saved"
        except FileNotFoundError:
            print('TenorC>> File Not Found Error')
            return "cancelled"

    def addTab(self, event):
        selectedTab = self.tabs.index("current")
        lastindex = self.tabs.index("end")-1

        if selectedTab == lastindex :
            textarea = Editor(self.tabs)
            self.tabs.insert(lastindex, textarea, text="Tab" + str(lastindex+1))
            self.tabs.select(lastindex)

    def donothing(self):
        print("clicked")
예제 #3
0
파일: mainview.py 프로젝트: gokai/tim
class Main(object):
    def __init__(self, title):
        root = Tk()
        root.title(title)
        root.focus_set()
        root.rowconfigure(0, weight=0)
        root.columnconfigure(0, weight=1)
        root.rowconfigure(1, weight=1)
        self._root = root

        self.menubar = Frame(root)
        self.menubar.grid(row=0, column=0, sticky=(W, E))
        self.menubar['takefocus'] = False

        quit_button = Button(self.menubar, text='Quit', command=self.quit)
        quit_button.grid(row=0, column=0)

        self._menucolumn = 1
        self.views = list()

        self.paned_win = PanedWindow(root, orient=HORIZONTAL)
        self.paned_win.grid(row=1, column=0, sticky=(N, S, W, E))

        self._query = None
        self._accept_func = None

        self.sidebar_views = dict()
        self.sidebar_count = 0
        self.sidebar = PanedWindow(self.paned_win)
        self.paned_win.add(self.sidebar, weight=1)

        self.tabs = Notebook(self.paned_win)
        self.tabs.enable_traversal()
        self.paned_win.add(self.tabs, weight=5)
        self.root = self.tabs

    def add_menubutton(self, label, action):
        button = Button(self.menubar, text=label, command=action)
        button.grid(row=0, column=self._menucolumn)
        self._menucolumn += 1

    def add_sidebar(self, view, name):
        self.sidebar_views[name] = view
        self.sidebar.add(view.widget, weight=1)
        view.widget.focus_set()
        self.sidebar_count += 1
        if self.sidebar_count == 1:
            self.sidebar_views['main'] = view

    def remove_sidebar_view(self, name):
        self.sidebar.forget(self.sidebar_views[name].widget)
        self.sidebar_count -= 1
        del self.sidebar_views[name]
        if self.sidebar_count == 0:
            del self.sidebar_views['main']

    def get_sidebar_view(self, name):
        return self.sidebar_views.get(name)

    def focus_sidebar(self):
        if 'main' in self.sidebar_views.keys():
            self.sidebar_views['main'].widget.focus_set()

    def focus_main_view(self):
        self.get_current_view().widget.focus_set()

    def new_view(self, view):
        self.views.append(view)
        self.tabs.add(view.widget, text=" {}.".format(self.tabs.index('end')))
        self.tabs.select(view.widget)

        view.widget.focus_set()
        self.view_changed()

    def remove_view(self, view):
        self.views.remove(view)
        self.tabs.forget(view.widget)
        if len(self.views) >= 1:
            widget = self.views[-1].widget
            self.tabs.select(widget)
            widget.focus_set()
        else:
            self.sidebar_views['main'].widget.focus_set()
        self.view_changed()

    def delete_current_view(self, event):
        if self.tabs.index('end') > 0:
            self.remove_view(self.get_current_view())

    def close_query(self):
        if self._query is not None:
            self._query.event_generate('<<MainQueryClose>>')
            self._query.destroy()
            self._query = None
            self._accept_func = None
            self._menucolumn -= 1

    def accept_query(self, event):
        if self._query is not None:
            if self._accept_func is not None:
                self._accept_func(event.widget.get(),
                                  event.widget.original_value)
                self.close_query()
            else:
                event.widget.event_generate('<<MainQueryAccept>>')

    def text_query(self, query_lable, original_text=None, accept_func=None):
        if self._query is not None:
            return
        frame = Frame(self.menubar)
        label = Label(frame, text=query_lable)
        label.grid(column=0, row=0, sticky=(N, S))
        self._accept_func = accept_func

        entry = Entry(frame)
        if original_text is not None:
            entry.insert(0, original_text)
        entry.original_value = original_text
        entry.grid(column=1, row=0, sticky=(N, S, W, E))
        kb.make_bindings(kb.text_query, {
            'accept': self.accept_query,
            'cancel': lambda e: self.close_query()
        }, entry.bind)

        frame.grid(column=self._menucolumn, row=0)
        self._menucolumn += 1
        entry.focus_set()
        self._query = frame

    def get_current_view(self):
        if self.tabs.index('end') > 0:
            return self.views[self.tabs.index('current')]
        else:
            return self.sidebar_views['main']

    def view_changed(self):
        self._root.event_generate('<<MainViewChanged>>')

    def display(self):
        self._root.mainloop()

    def quit(self):
        self._root.destroy()
예제 #4
0
class GuiMain:
    def __init__(self):
        """
        Main Gui Entrance
        """
        tkinter.Tk.report_callback_exception = self.throw
        # Main window
        self.destroyed = False
        LoggerGui.info("Initializing GUI")
        self.main_window = tkinter.Tk()
        self.main_window.wm_title("DRC Sim Server")
        icon = tkinter.PhotoImage(data=Resource("image/icon.gif").resource)
        self.main_window.tk.call("wm", "iconphoto", self.main_window, icon)
        self.main_window.protocol("WM_DELETE_WINDOW", self.on_closing)
        self.main_window.resizable(False, False)
        # Notebook
        self.tab_id = None
        self.notebook = Notebook(self.main_window, width=600, height=300)
        self.notebook.grid(column=0, row=0)
        self.notebook.bind("<<NotebookTabChanged>>", self.on_tab_changed)
        # Run Server Frame
        self.frame_run_server = FrameRunServer(self.notebook)
        self.notebook.add(self.frame_run_server, text="Run Server")
        # Get Key Frame
        self.frame_get_key = FrameGetKey(self.notebook)
        self.notebook.add(self.frame_get_key, text="Get Key")
        # Log Frame
        self.frame_log = FrameLog(self.notebook)
        self.notebook.add(self.frame_log, text="Log")
        # About Frame
        self.frame_about = FrameAbout(self.notebook)
        self.notebook.add(self.frame_about, text="About")

    @staticmethod
    def throw(*args):
        """
        Throw exceptions from Tkinter
        :param args: arguments
        :return: None
        """
        for arg in args:
            if isinstance(arg, Exception):
                LoggerGui.throw(arg)

    def after(self):
        """
        Empty loop to catch KeyboardInterrupt
        :return: None
        """
        self.main_window.after(1000, self.after)

    def start(self):
        """
        Start the main window loop
        :return:
        """
        LoggerGui.info("Opening GUI")
        self.after()
        self.main_window.mainloop()
        LoggerGui.info("GUI Closed")

    def stop(self):
        """
        Convenience function to call on_closing()
        :return: None
        """
        self.on_closing()

    def on_closing(self):
        """
        Close the main window and current tab
        :return: None
        """
        if self.destroyed:
            return
        self.destroyed = True
        LoggerGui.info("Closing GUI")
        if self.tab_id in self.notebook.children:
            self.notebook.children[self.tab_id].deactivate()
        try:
            self.main_window.destroy()
        except Exception as e:
            LoggerGui.exception(e)

    # noinspection PyUnusedLocal
    def on_tab_changed(self, event):
        """
        Close the previous tab and initialize a new one
        :param event: tab event
        :return: None
        """
        tab_id = self.notebook.select()
        tab_index = self.notebook.index(tab_id)
        tab_name = self.notebook.tab(tab_index, "text")
        LoggerGui.debug("Notebook tab changed to \"%s\" with id %d", tab_name,
                        tab_index)
        self.tab_id = tab_id.split(".")[len(
            tab_id.split(".")) - 1]  # Parse notebook/tab id to only tab id
        if self.notebook.children[self.tab_id].kill_other_tabs():
            for tab in self.notebook.children:
                if tab != self.tab_id:
                    self.notebook.children[tab].deactivate()
        self.notebook.children[self.tab_id].activate()
class App:
    def __init__(self):
        # создание основного окна Tkinter
        self.window = Tk()
        self.window.title("Треугольники")
        self.window.geometry('520x520')
        self.window.minsize(520, 520)
        self.window.maxsize(520, 520)

        self.press_x, self.press_y = 0, 0
        self.release_x, self.release_y = 0, 0

        # флаги нажатия/отжатия кнопки
        self.pressed = False

        # размещение элементов интерфейса

        # основной элемент - Canvas
        self.canvas_x = 470
        self.canvas_y = 270
        self.c = Canvas(self.window,
                        width=self.canvas_x,
                        height=self.canvas_y,
                        bg='black')
        self.c.pack(side=TOP, padx=10, pady=(10, 10))

        # элементы управления: настройки, отображение параметров, очистка/выход
        setup = Frame(self.window, width=470)
        setup_left = Frame(setup, width=270)
        setup_right = Frame(setup, width=200)

        self.setup_notebook = Notebook(setup_left)

        setup1 = Frame(setup_left, width=250, height=140)
        setup2 = Frame(setup_left, width=250, height=140)
        setup3 = Frame(setup_left, width=250, height=140)

        # элементы управления на вкладках
        # вкладка 1
        Label(setup1, text='Длина стороны').pack(side=TOP,
                                                 pady=(10, 0),
                                                 padx=(10, 0),
                                                 anchor=W)
        self.scal_b = Scale(setup1,
                            orient=HORIZONTAL,
                            length=200,
                            from_=0,
                            to=300,
                            tickinterval=100,
                            resolution=10)
        self.scal_b.pack(side=TOP)
        self.scal_b.set(100)
        self.scal_b.bind("<ButtonRelease-1>", self.draw_triangle)
        Label(setup1, text='Угол \u03b1').pack(side=TOP,
                                               pady=(10, 0),
                                               padx=(10, 0),
                                               anchor=W)
        self.scal_alpha = Scale(setup1,
                                orient=HORIZONTAL,
                                length=200,
                                from_=0,
                                to=180,
                                tickinterval=30,
                                resolution=15)
        self.scal_alpha.pack(side=TOP)
        self.scal_alpha.set(30)
        self.scal_alpha.bind("<ButtonRelease-1>", self.draw_triangle)

        # вкладка 2
        Label(setup2, text='Угол \u03b1').pack(side=TOP,
                                               pady=(10, 0),
                                               padx=(10, 0),
                                               anchor=W)
        self.scal_alpha2 = Scale(setup2,
                                 orient=HORIZONTAL,
                                 length=200,
                                 from_=0,
                                 to=90,
                                 tickinterval=15,
                                 resolution=5)
        self.scal_alpha2.pack(side=TOP)
        self.scal_alpha2.set(60)
        self.scal_alpha2.bind("<ButtonRelease-1>", self.draw_triangle)
        Label(setup2, text='Угол \u03b2').pack(side=TOP,
                                               pady=(10, 0),
                                               padx=(10, 0),
                                               anchor=W)
        self.scal_beta = Scale(setup2,
                               orient=HORIZONTAL,
                               length=200,
                               from_=0,
                               to=90,
                               tickinterval=15,
                               resolution=5)
        self.scal_beta.pack(side=TOP)
        self.scal_beta.set(60)
        self.scal_beta.bind("<ButtonRelease-1>", self.draw_triangle)

        # вкладка 3
        Label(setup3, text='Длина стороны 2').pack(side=TOP,
                                                   pady=(10, 0),
                                                   padx=(10, 0),
                                                   anchor=W)
        self.scal_a = Scale(setup3,
                            orient=HORIZONTAL,
                            length=200,
                            from_=0,
                            to=300,
                            tickinterval=100,
                            resolution=10)
        self.scal_a.pack(side=TOP)
        self.scal_a.set(100)
        self.scal_a.bind("<ButtonRelease-1>", self.draw_triangle)
        Label(setup3, text='Длина стороны 3').pack(side=TOP,
                                                   pady=(10, 0),
                                                   padx=(10, 0),
                                                   anchor=W)
        self.scal_b2 = Scale(setup3,
                             orient=HORIZONTAL,
                             length=200,
                             from_=0,
                             to=300,
                             tickinterval=100,
                             resolution=10)
        self.scal_b2.pack(side=TOP)
        self.scal_b2.set(100)
        self.scal_b2.bind("<ButtonRelease-1>", self.draw_triangle)

        setup1.pack()
        setup2.pack()
        setup3.pack()

        self.setup_notebook.add(setup1, text='Задача 1')
        self.setup_notebook.add(setup2, text='Задача 2')
        self.setup_notebook.add(setup3, text='Задача 3')
        self.setup_notebook.bind('<<NotebookTabChanged>>', self.draw_triangle)

        self.setup_notebook.pack(side=LEFT)

        columns = ('#1', '#2')
        self.params = Treeview(setup_right,
                               show='headings',
                               columns=columns,
                               height=5)
        self.params.heading('#1', text='Параметр')
        self.params.heading('#2', text='Значение')
        self.params.column('#1', width=110, minwidth=50, stretch=NO, anchor=N)
        self.params.column('#2', width=110, minwidth=50, stretch=NO, anchor=N)
        self.params.pack(side=TOP, padx=(15, 0), pady=(15, 5))

        butframe = Frame(setup_right)
        Button(butframe, text='Очистить', width=10,
               command=self.draw_base()).pack(side=LEFT, padx=(25, 5))
        Button(butframe,
               text='Выход',
               width=10,
               command=lambda x=0: sys.exit(x)).pack(side=LEFT, padx=(0, 10))
        butframe.pack(side=TOP, pady=(17, 5))

        setup_left.pack(side=LEFT, padx=(0, 20))
        setup_right.pack(side=LEFT)
        setup.pack(side=TOP, pady=(5, 10), padx=(5, 5))

        self.window.bind('<Button-1>', self.press)
        self.window.bind('<ButtonRelease-1>', self.release)
        self.window.bind('<Motion>', self.motion)

        self.draw_base()
        self.window.mainloop()

    def motion(self, event):
        if self.pressed:
            if event.widget.master is not None:
                if event.widget.widgetName == 'canvas':
                    self.draw_base()
                    self.c.create_line(
                        [self.press_x, self.press_y, event.x, event.y],
                        dash=True,
                        fill='yellow')

    def draw_base(self):
        self.c.delete("all")
        # базовые оси
        self.c.create_line([10, 250, 460, 250], arrow=LAST, fill='white')
        self.c.create_line([20, 260, 20, 10], arrow=LAST, fill='white')

        # метки
        for i in range(1, 5):
            self.c.create_line([100 * i + 20, 247, 100 * i + 20, 253],
                               fill='white')
        for i in range(1, 3):
            self.c.create_line([17, 250 - 100 * i, 23, 250 - 100 * i],
                               fill='white')

        # надписи
        # наименование осей
        self.c.create_text(457, 258, text='x', fill='white')
        self.c.create_text(30, 15, text='y', fill='white')
        # наименование меток
        for i in range(0, 5):
            self.c.create_text(100 * i + 25,
                               260,
                               text=str(100 * i),
                               fill='white')
        for i in range(1, 3):
            self.c.create_text(34,
                               250 - 100 * i,
                               text=str(100 * i),
                               fill='white')

    def press(self, event):
        """
        Обработчик события "нажатие кнопки мыши"
        :param event:
        :return:
        """
        if event.widget.master is not None:
            if event.widget.widgetName == 'canvas':
                self.draw_base()
                self.press_x, self.press_y = event.x, event.y
                self.pressed = True

    def release(self, event):
        if event.widget.master is not None:
            if event.widget.widgetName == 'canvas':
                self.release_x, self.release_y = event.x, event.y
                if (self.release_x in range(450)) & (self.release_y
                                                     in range(250)):
                    self.draw_triangle(None)
        self.pressed = False

    def check_coordinates(self, C):
        if (C[0] < 0) | (C[1] < 0):
            return False
        if (C[0] > self.canvas_x) | (C[1] > self.canvas_y):
            return False
        return True

    def draw_triangle(self, event):
        if (self.press_x > 0) & (self.press_y > 0) & (self.release_x > 0) & (
                self.release_y > 0):
            self.draw_base()
            triangle = Math((self.press_x, self.press_y),
                            (self.release_x, self.release_y), (20, 250))
            task = self.setup_notebook.index(self.setup_notebook.select()) + 1
            if task == 1:
                data_dict = {
                    'b': self.scal_b.get(),
                    'alpha': self.scal_alpha.get()
                }
            elif task == 2:
                data_dict = {
                    'alpha': self.scal_alpha2.get(),
                    'beta': self.scal_beta.get()
                }
            elif task == 3:
                data_dict = {'a': self.scal_a.get(), 'b': self.scal_b2.get()}
            else:
                return
            C1, C2, data_dict = triangle.get_c(task, data_dict)
            if self.check_coordinates(C1) & self.check_coordinates(C2):
                self.c.create_polygon([
                    self.press_x, self.press_y, self.release_x, self.release_y,
                    C1[0], C1[1]
                ],
                                      fill='red')
                self.c.create_polygon([
                    self.press_x, self.press_y, self.release_x, self.release_y,
                    C2[0], C2[1]
                ],
                                      fill='blue')
                self.update_treeview(data_dict)
            else:
                self.c.create_text(300,
                                   100,
                                   text='Одна из точек вне области построения',
                                   fill='white')

    def update_treeview(self, data):
        """
        запись параметров в элемент Treeview
        :return: None
        """
        for x in self.params.get_children():
            self.params.delete(x)
        for key in data.keys():
            self.params.insert("", END, values=[key, data[key]])
예제 #6
0
class Root(ThemedTk):
    def __init__(self):
        ThemedTk.__init__(self)
        if platform.system() is 'Windows':
            self.set_theme("vista")
        else:
            self.set_theme("clearlooks")

        self.set_title()
        img = ImageTk.PhotoImage(file=Path(__file__).resolve().parent / 'images' / 'icon.png')
        self.iconphoto(True, img)

        self.menu_bar = MenuBar(self)
        self.config(menu=self.menu_bar)

        self.rowconfigure(0, weight=1)
        self.columnconfigure(1, weight=1)

        self.minutiae = []

        self.file_path = Path()

        self.image_raw = Image.new('RGBA', (512, 512), (255, 255, 255, 255))
        self.image_fingerprint = self.image_raw
        self.image_minutiae = None
        self.image = ImageTk.PhotoImage(self.image_raw)

        self.image_canvas = Canvas(self, bd=0, highlightthickness=0)
        self.image_canvas.create_image(0, 0, image=self.image, anchor=N + W, tags="IMG")
        self.image_canvas.grid(row=0, column=1, sticky=NSEW)

        self.notebook = Notebook(self)
        self.notebook.grid(row=0, column=0, sticky=NSEW)
        self.tabs = [
            MindtctFrame(self, self.load_fingerprint_image),
            MinutiaeEditorFrame(self, self.load_fingerprint_image, self.load_minutiae_file, self.save_minutiae_file)
        ]
        self.notebook.add(self.tabs[0], text="MINDTCT")
        self.notebook.add(self.tabs[1], text="Minutiae Editor")

        self.image_canvas.bind("<Button-1>", self.on_canvas_mouse_left_click)
        self.image_canvas.bind("<Control-Button-1>", self.on_canvas_ctrl_mouse_left_click)
        self.image_canvas.bind("<B1-Motion>", self.on_canvas_mouse_left_drag)
        self.image_canvas.bind("<ButtonRelease-1>", self.on_canvas_mouse_left_release)
        self.image_canvas.bind("<Button-3>", self.on_canvas_mouse_right_click)
        self.bind("<Configure>", self.redraw)

    def set_title(self, title: str = None):
        """
        Sets the main window's title. If a string is provided then the title will be set to 
        "[string] - [programme name]". If None is supplied just the programme name is displayed.
        :param title: The text to set as the title. 
        """
        text = "" if title is None else "{0} - ".format(title)
        self.title(text + "Py Minutiae Viewer")

    def redraw(self, _=None):
        im = self.image_raw.copy()

        # Apply drawing from each active tab
        for tab in self.tabs:
            im = tab.fingerprint_drawing(im)

        # Scale image to fit canvas
        im, _ = scale_image_to_fit_minutiae_canvas(self.image_canvas, im)
        self.image_fingerprint = im
        self.image = ImageTk.PhotoImage(self.image_fingerprint)
        self.image_canvas.delete("IMG")
        self.image_canvas.create_image(0, 0, image=self.image, anchor=N + W, tags="IMG")

        # Draw minutiae
        self.draw_minutiae()

    def load_fingerprint_image(self):
        file_path = askopenfilename(filetypes=(("Image files", ('*.bmp', '*.jpeg', '*.jpg', '*.png')),
                                               ("All files", "*.*")))
        if file_path:
            self.image_raw = Image.open(file_path).convert("RGBA")
            self.redraw()
            self.file_path = Path(file_path).resolve()
            self.set_title(self.file_path.name)
            self.minutiae = []
            self.update_idletasks()

            self.tabs[self.notebook.index("current")].load_fingerprint_image(self.image_raw)

    def load_minutiae_file(self):
        file_path = askopenfilename(initialfile=self.file_path.stem,
                                    filetypes=(("All minutiae files", ('*.min', '*.sim', '*.xyt')),
                                               ("Simple minutiae file", '*.sim'),
                                               ("NBIST minutiae file", '*.min'),
                                               ("x y theta file", '*.xyt'),
                                               ("All files", "*.*")))
        if file_path:
            # Select the correct file format
            if Path(file_path).suffix == '.sim':
                reader = MinutiaeReader(MinutiaeFileFormat.SIMPLE)
            elif Path(file_path).suffix == '.min':
                reader = MinutiaeReader(MinutiaeFileFormat.NBIST)
            elif Path(file_path).suffix == '.xyt':
                reader = MinutiaeReader(MinutiaeFileFormat.XYT)
            else:
                showerror("Read Minutiae File", "The chosen file had an extension of '{}', which can't be interpreted."
                          .format(Path(file_path).suffix))
                return

            try:
                self.minutiae = reader.read(file_path)
                self.draw_minutiae()

                self.tabs[self.notebook.index("current")].load_minutiae_file()
            except Exception as e:
                traceback.print_exc()
                showerror("Read Minutiae File", "There was an error in reading the minutiae file.\n\n"
                                                "The error message was:\n{}".format(e))

    def save_minutiae_file(self):
        file_path = asksaveasfilename(initialfile=self.file_path.stem,
                                      filetypes=(("Simple minutiae file", '*.sim'),
                                                 ("NBIST minutiae file", '*.min'),
                                                 ("x y theta file", '*.xyt')))
        if file_path:
            # Select the correct file format
            if Path(file_path).suffix == '.sim':
                writer = MinutiaeEncoder(MinutiaeFileFormat.SIMPLE)
            elif Path(file_path).suffix == '.min':
                writer = MinutiaeEncoder(MinutiaeFileFormat.NBIST)
            elif Path(file_path).suffix == '.xyt':
                writer = MinutiaeEncoder(MinutiaeFileFormat.XYT)
            else:
                showerror("Save Minutiae File", "The chosen file had an extension of '{}', which can't be interpreted."
                          .format(Path(file_path).suffix))
                return

            try:
                writer.write(file_path, self.minutiae, self.image_raw)
            except Exception as e:
                traceback.print_exc()
                showerror("Save Minutiae File", "There was an error in saving the minutiae file.\n\n"
                                                "The error message was:\n{}".format(e))

    def exit_application(self):
        """
        Attempts to exit the application. 
        """
        self.destroy()

    def draw_minutiae(self):

        # Apply filtering from each active module
        minutiae = [m.copy() for m in self.minutiae]
        for tab in self.tabs:
            minutiae = tab.minutiae_filtering(minutiae)

        # Scale minutiae
        ratio = self.image_fingerprint.width / self.image_raw.width
        minutiae = [Minutia(int(m.x * ratio), int(m.y * ratio), m.angle, m.minutia_type, m.quality) for m in minutiae]

        im = Image.new('RGBA', self.image_fingerprint.size, (0, 0, 0, 0))
        self.image_minutiae = draw_minutiae(im, minutiae)

        im = self.image_fingerprint.copy()
        im.paste(self.image_minutiae, (0, 0), self.image_minutiae)
        self.image = ImageTk.PhotoImage(im)
        self.image_canvas.delete("IMG")
        self.image_canvas.create_image(0, 0, image=self.image, anchor=N + W, tags="IMG")
        self.update_idletasks()

    def draw_single_minutia(self, minutia: Minutia):
        temp_image = draw_minutiae(self.image_minutiae, [minutia])
        im = self.image_fingerprint.copy()
        im.paste(temp_image, (0, 0), temp_image)

        self.image = ImageTk.PhotoImage(im)
        self.image_canvas.delete("IMG")
        self.image_canvas.create_image(0, 0, image=self.image, anchor=N + W, tags="IMG")
        self.update_idletasks()

    def number_of_minutiae(self):
        """
        Returns the number of minutiae features.
        :return: Number of minutiae.
        """
        return len(self.minutiae)

    def is_point_in_canvas_image(self, x: int, y: int) -> bool:
        """
        Tests if a point is within the fingerprint image.
        :param x: x co-ordinate of the point to test.
        :param y: y co-ordinate of the point to test.
        :return: True if point is in the image, false otherwise.
        """
        if x > self.image.width() or y > self.image.height():
            return False
        else:
            return True

    def canvas_image_scale_factor(self) -> float:
        """
        Calculates the ratio between the canvas image's actual size and its displayed size.
        :return: The ratio.
        """
        return self.image_raw.width / self.image.width()

    def on_canvas_mouse_left_click(self, event):
        self.tabs[self.notebook.index('current')].on_canvas_mouse_left_click(event)

    def on_canvas_ctrl_mouse_left_click(self, event):
        self.tabs[self.notebook.index('current')].on_canvas_ctrl_mouse_left_click(event)

    def on_canvas_mouse_left_drag(self, event):
        self.tabs[self.notebook.index('current')].on_canvas_mouse_left_drag(event)

    def on_canvas_mouse_left_release(self, event):
        self.tabs[self.notebook.index('current')].on_canvas_mouse_left_release(event)

    def on_canvas_mouse_right_click(self, event):
        self.tabs[self.notebook.index('current')].on_canvas_mouse_right_click(event)
예제 #7
0
class OptionsView:
    def __init__(self, settings, root, textFrameManager):
        self._settings = settings
        self._root = root
        self._textFrameManager = textFrameManager

        self._highlightWorker = None
        self._guiWorker = None

        self._showing = False
        self._saving = False

        self._textFrame: TF.TextFrame = None

    def linkWorkers(self, workers):
        self._highlightWorker = workers.highlightWorker
        self._guiWorker = workers.guiWorker

    def linkTextFrame(self, textFrame):
        self._textFrame = textFrame

    def _onClosing(self, savingSettings=False):

        # Delete all variable observers
        for settingsLine in list(self._setsDict.values()):
            for entry in list(settingsLine.entries.values()):
                try:
                    entry.var.trace_vdelete("w", entry.observer)
                except:
                    pass

        # Delete all view elements
        del self._setsDict

        # Close window
        self._view.destroy()

        if not savingSettings:
            self._showing = False

    class SettingsLineTemplate:
        def __init__(self, setGroup, setId, setDisplayName, setType):
            self.setGroup = setGroup
            self.setId = setId
            self.setDisplayName = setDisplayName
            self.setType = setType

    class SettingsLine:
        def __init__(self, group):
            self.group = group
            self.entries = dict()

    class LineColorSettingsLine(SettingsLine):
        def __init__(self, group):
            super().__init__(group)
            self.lineFrame = None

    class Entry:
        def __init__(self, entryType, entryVar):
            self.label: tk.Label = None
            self.var = None
            self.observer = None
            self.input: tk.Entry = None
            self.button: tk.Button = None
            self.data = OptionsView.EntryData(entryType, entryVar)

        def isVarUpdated(self):
            updated = False
            try:
                updated = self.var.get() != self.data.entryVar
            except AttributeError:
                traceLog(LogLevel.ERROR,
                         "Tkinter var in OptionsView not initiated")
                updated = True
            return updated

    class EntryData:
        def __init__(self, entryType, entryVar):
            self.entryType = entryType
            self.entryVar = entryVar
            self.validation = OptionsView.EntryDataValidation(
                OptionsView.ENTRY_VALIDATION_OK, "white", "")

    class EntryDataValidation:
        def __init__(self, status, backgroundColor, infoText):
            self.status = status
            self.backgroundColor = backgroundColor
            self.infoText = infoText

    ENTRY_TYPE_COLOR = "typeColor"
    ENTRY_TYPE_STRING = "typeString"
    ENTRY_TYPE_INT = "typeInt"
    ENTRY_TYPE_REGEX = "typeRegex"
    ENTRY_TYPE_TOGGLE = "typeToggle"
    ENTRY_TYPE_OTHER = "typeOther"

    ENTRY_VALIDATION_OK = "entryValidationOk"
    ENTRY_VALIDATION_FAILED = "entryValidationFailed"
    ENTRY_VALIDATION_DUPLICATE = "entryValidationDuplicate"

    GROUP_TEXT_AREA = "groupTextArea"
    GROUP_SEARCH = "groupSearch"
    GROUP_LOGGING = "groupLogging"
    GROUP_LINE_COLORING = "groupLineColoring"

    EDIT_UP = "editUp"
    EDIT_DOWN = "editDown"
    EDIT_DELETE = "editDelete"

    ROW_HIGHLIGHT_COLOR = "gray"

    LOG_EXAMPLE_FILE = r"appdata\log_example.txt"

    def _loadLogExample(self):
        log = "[12:34:56.789] Main::test\n[12:34:56.789] Main::TestTwo"
        try:
            with open(
                    os.path.join(self._settings.get(Sets.CT_HOMEPATH_FULL),
                                 self.LOG_EXAMPLE_FILE), "r") as file:
                log = file.read()
        except FileNotFoundError:
            traceLog(LogLevel.WARNING,
                     "Log example file not found. Using default example")
        return log

    def show(self):

        # Only allow one options view at a time # TODO Can be done with a global var, then a global instance of OptionsView is not needed
        if not self._showing:

            self._showing = True

            self._lineColorMap = self._textFrame.getLineColorMap()

            self._view = tk.Toplevel(self._root)
            self._view.title("Options")
            self._view.protocol("WM_DELETE_WINDOW", self._onClosing)

            self._view.iconbitmap(self._settings.get(Sets.ICON_PATH_FULL))

            self._setsDict = dict()

            ##############################
            # TAB CONTROL

            self._tabsFrame = tk.Frame(self._view)
            self._tabsFrame.grid(row=0, column=0, sticky="nsew")
            self._view.columnconfigure(0, weight=1)
            self._view.rowconfigure(0, weight=1)

            self._tabControl = Notebook(self._tabsFrame, padding=10)

            self._tabControl.grid(row=0, column=0, sticky=tk.N)
            self._tabList = list()

            ##############################
            # TEXT EXAMPLE

            logExample = self._loadLogExample()
            exampleTextFrameHeightMin = 400
            exampleTextFrameWidth = 650

            self._exampleTextFrame = tk.Frame(self._tabsFrame,
                                              height=exampleTextFrameHeightMin,
                                              width=exampleTextFrameWidth)
            self._exampleTextFrame.grid(row=0,
                                        column=1,
                                        padx=(0, 10),
                                        pady=(10, 10),
                                        sticky="nsew")
            self._exampleTextFrame.grid_propagate(False)
            self._tabsFrame.columnconfigure(1, weight=1)
            self._tabsFrame.rowconfigure(0, weight=1)

            tFont = Font(family=self._settings.get(Sets.TEXTAREA_FONT_FAMILY),
                         size=self._settings.get(Sets.TEXTAREA_FONT_SIZE))
            self._exampleText = tk.Text(self._exampleTextFrame,height=1, width=2,\
                                            background=self._settings.get(Sets.TEXTAREA_BACKGROUND_COLOR),\
                                            selectbackground=self._settings.get(Sets.TEXTAREA_SELECT_BACKGROUND_COLOR),\
                                            foreground=self._settings.get(Sets.TEXTAREA_COLOR),\
                                            font=tFont)
            self._exampleText.grid(row=0,
                                   column=0,
                                   padx=(0, 0),
                                   pady=(10, 0),
                                   sticky="nsew")
            self._exampleTextFrame.columnconfigure(0, weight=1)
            self._exampleTextFrame.rowconfigure(0, weight=1)

            self._updateExampleTextLineWrap(
                self._settings.get(Sets.TEXTAREA_LINE_WRAP))

            self._exampleText.insert(1.0, logExample)

            xscrollbar = tk.Scrollbar(self._exampleTextFrame,
                                      orient=tk.HORIZONTAL,
                                      command=self._exampleText.xview)
            xscrollbar.grid(row=1, column=0, sticky=tk.W + tk.E)
            self._exampleText["xscrollcommand"] = xscrollbar.set

            yscrollbar = tk.Scrollbar(self._exampleTextFrame,
                                      orient=tk.VERTICAL,
                                      command=self._exampleText.yview)
            yscrollbar.grid(row=0, column=1, sticky=tk.N + tk.S)
            self._exampleText["yscrollcommand"] = yscrollbar.set

            ###############
            # Tab: Line Coloring

            self._lineColoringFrame = tk.Frame(self._tabControl,
                                               padx=5,
                                               pady=5)
            self._lineColoringFrame.grid(row=0, column=0, sticky=tk.N)
            self._tabControl.add(self._lineColoringFrame, text="Line Coloring")
            self._tabList.append(self.GROUP_LINE_COLORING)

            self._setsDict.update(
                self._createLineColorRows(self._lineColoringFrame,
                                          self._lineColorMap))

            upButton = tk.Button(self._lineColoringFrame,
                                 text="UP",
                                 command=partial(self._editLineColorRow,
                                                 self.EDIT_UP))
            upButton.grid(row=0, column=2, padx=2)

            downButton = tk.Button(self._lineColoringFrame,
                                   text="DOWN",
                                   command=partial(self._editLineColorRow,
                                                   self.EDIT_DOWN))
            downButton.grid(row=1, column=2, padx=2)

            deleteButton = tk.Button(self._lineColoringFrame,
                                     text="Delete",
                                     command=partial(self._editLineColorRow,
                                                     self.EDIT_DELETE))
            deleteButton.grid(row=2, column=2, padx=2)
            self._lastFocusInRowId = ""
            self._lastFocusOutRowId = ""

            self._newButtonRow = len(self._lineColorMap)
            self._newButton = tk.Button(self._lineColoringFrame,
                                        text="New Line",
                                        command=partial(
                                            self._addNewEmptyLineColor))
            self._newButton.grid(row=self._newButtonRow,
                                 column=0,
                                 sticky=tk.W,
                                 padx=(2, 100),
                                 pady=2)

            self._deletedLineColorRows = list()

            ###############
            # Tab: Text Area

            self._textAreaFrame = tk.Frame(self._tabControl, padx=5, pady=5)
            self._textAreaFrame.grid(row=0, column=0, sticky=tk.N)
            self._tabControl.add(self._textAreaFrame, text="Text Area")
            self._tabList.append(self.GROUP_TEXT_AREA)

            setLines = list()
            setLines.append(
                self.SettingsLineTemplate(self.GROUP_TEXT_AREA,
                                          Sets.TEXTAREA_BACKGROUND_COLOR,
                                          "Background Color",
                                          self.ENTRY_TYPE_COLOR))
            setLines.append(
                self.SettingsLineTemplate(
                    self.GROUP_TEXT_AREA,
                    Sets.TEXTAREA_SELECT_BACKGROUND_COLOR,
                    "Background Color Select", self.ENTRY_TYPE_COLOR))
            setLines.append(
                self.SettingsLineTemplate(self.GROUP_TEXT_AREA,
                                          Sets.TEXTAREA_COLOR, "Text Color",
                                          self.ENTRY_TYPE_COLOR))
            setLines.append(
                self.SettingsLineTemplate(self.GROUP_TEXT_AREA,
                                          Sets.TEXTAREA_FONT_FAMILY,
                                          "Font Family",
                                          self.ENTRY_TYPE_STRING))
            setLines.append(
                self.SettingsLineTemplate(self.GROUP_TEXT_AREA,
                                          Sets.TEXTAREA_FONT_SIZE, "Font Size",
                                          self.ENTRY_TYPE_INT))
            setLines.append(
                self.SettingsLineTemplate(self.GROUP_TEXT_AREA,
                                          Sets.TEXTAREA_LINE_WRAP, "Line Wrap",
                                          self.ENTRY_TYPE_TOGGLE))

            self._setsDict.update(
                self._createStandardRows(self._textAreaFrame, setLines, 0))

            ###############
            # Tab: Search

            self._searchFrame = tk.Frame(self._tabControl, padx=5, pady=5)
            self._searchFrame.grid(row=0, column=0, sticky=tk.N)
            self._tabControl.add(self._searchFrame, text="Search")
            self._tabList.append(self.GROUP_SEARCH)

            setLines = list()
            setLines.append(
                self.SettingsLineTemplate(self.GROUP_SEARCH,
                                          Sets.SEARCH_MATCH_COLOR,
                                          "Search match background color",
                                          self.ENTRY_TYPE_COLOR))
            setLines.append(
                self.SettingsLineTemplate(self.GROUP_SEARCH,
                                          Sets.SEARCH_SELECTED_COLOR,
                                          "Search selected background color",
                                          self.ENTRY_TYPE_COLOR))
            setLines.append(
                self.SettingsLineTemplate(
                    self.GROUP_SEARCH, Sets.SEARCH_SELECTED_LINE_COLOR,
                    "Search selected line background color",
                    self.ENTRY_TYPE_COLOR))

            self._setsDict.update(
                self._createStandardRows(self._searchFrame, setLines, 0))

            ###############
            # Tab: Logging

            self._loggingFrame = tk.Frame(self._tabControl, padx=5, pady=5)
            self._loggingFrame.grid(row=0, column=0, sticky=tk.N)
            self._tabControl.add(self._loggingFrame, text="Logging")
            self._tabList.append(self.GROUP_LOGGING)

            setLines = list()
            setLines.append(
                self.SettingsLineTemplate(self.GROUP_LOGGING,
                                          Sets.LOG_FILE_PATH, "Log file path",
                                          self.ENTRY_TYPE_OTHER))
            setLines.append(
                self.SettingsLineTemplate(self.GROUP_LOGGING,
                                          Sets.LOG_FILE_BASE_NAME,
                                          "Log file base name",
                                          self.ENTRY_TYPE_OTHER))
            setLines.append(
                self.SettingsLineTemplate(self.GROUP_LOGGING,
                                          Sets.LOG_FILE_TIMESTAMP,
                                          "Time stamp", self.ENTRY_TYPE_OTHER))

            self._setsDict.update(
                self._createStandardRows(self._loggingFrame, setLines, 0))

            ##############################
            # CONTROL ROW

            self._optionsControlFrame = tk.Frame(self._view)
            self._optionsControlFrame.grid(row=1,
                                           column=0,
                                           padx=(10, 10),
                                           pady=(0, 10),
                                           sticky=tk.W + tk.E)

            self._optionsInfoLabel = tk.Label(self._optionsControlFrame,
                                              text="",
                                              justify=tk.LEFT)
            self._optionsInfoLabel.grid(row=0, column=0, sticky=tk.W)
            self._optionsControlFrame.columnconfigure(0, weight=1)

            self._optionsCancelButton = tk.Button(self._optionsControlFrame,
                                                  text="Cancel",
                                                  command=self._onClosing)
            self._optionsCancelButton.grid(row=0,
                                           column=1,
                                           padx=5,
                                           sticky=tk.E)

            self._optionsSaveButton = tk.Button(self._optionsControlFrame,
                                                text="Save",
                                                command=self._saveSettings)
            self._optionsSaveButton.grid(row=0, column=2, sticky=tk.E)
            if self._saving:
                self._optionsSaveButton.config(state=tk.DISABLED)
            else:
                self._optionsSaveButton.config(state=tk.NORMAL)

            self._tabControl.bind("<<NotebookTabChanged>>", self._tabChanged)

            # print("Number of settings " + str(len(self._setsDict)))

    def _saveSettings(self):

        saveSettingsThread = threading.Thread(target=self._saveSettingsProcess,
                                              name="SaveSettings")
        saveSettingsThread.start()

        self._saving = True

    def _setSaveButtonState(self, state):
        if self._showing:
            try:
                self._optionsSaveButton.config(state=state)
            except:
                # Catch if function is called while save button does not exist
                traceLog(LogLevel.ERROR, "Error updating save button state")

    def _saveSettingsProcess(self):
        # Saving will block, so must be done in different thread

        # setsDict will be deleted in the onClosing function
        tempSetsDict = self._setsDict

        # Close options view
        self._root.after(10, self._onClosing, True)

        # Get registered textFrames
        textFrames = self._textFrameManager.getTextFrames()

        # Show saving message
        for textFrame in textFrames:
            textFrame.showSpinner("Reloading View")

        # Stop workers using the settings
        self._highlightWorker.stopWorker(emptyQueue=False)
        self._guiWorker.stopWorker()

        # Save all settings
        tempLineColorMap = dict()
        tempLineColorRows = dict()
        # Sort settings to guarantee right order of line coloring
        for rowId in sorted(tempSetsDict.keys()):

            if Sets.LINE_COLOR_MAP in rowId:
                tempLineColorMap[rowId] = dict()
                tempLineColorRows[rowId] = tempSetsDict[rowId]

            for entryName in tempSetsDict[rowId].entries.keys():
                setting = tempSetsDict[rowId].entries[entryName].var.get()
                if Sets.LINE_COLOR_MAP in rowId:
                    tempLineColorMap[rowId][entryName] = setting
                else:
                    self._settings.setOption(rowId, setting)

        self._settings.setOption(Sets.LINE_COLOR_MAP, tempLineColorMap)

        # Once settings have been saved, allow for reopen of options view
        self._showing = False

        # Delete line color tags
        for deletedRowData in self._deletedLineColorRows:
            for textFrame in textFrames:
                textFrame.deleteTextTag(deletedRowData["tagName"])

        # Process added or updated line color rows
        for rowId in tempLineColorRows.keys():
            if tempLineColorRows[rowId].entries["regex"].isVarUpdated():
                if tempLineColorRows[rowId].entries["regex"].data.entryVar:
                    oldTagName = TF.createLineColorTagName(
                        tempLineColorRows[rowId].entries["regex"].data.entryVar
                    )
                    for textFrame in textFrames:
                        textFrame.deleteTextTag(oldTagName)
                    # print("Delete edited row id: " + rowId)
                for textFrame in textFrames:
                    textFrame.createAndAddLineColorTag(
                        tempLineColorRows[rowId].entries["regex"].var.get(),
                        tempLineColorRows[rowId].entries["color"].var.get())
                # print("Added line color row: " + rowId)

            elif tempLineColorRows[rowId].entries["color"].isVarUpdated():
                tagName = TF.createLineColorTagName(
                    tempLineColorRows[rowId].entries["regex"].var.get())
                for textFrame in textFrames:
                    textFrame.updateTagColor(
                        tagName,
                        tempLineColorRows[rowId].entries["color"].var.get())

        # Reorder line color tags
        rowIds = sorted(tempLineColorRows.keys())
        if rowIds:
            preTagName = TF.createLineColorTagName(
                tempLineColorRows[rowIds[0]].entries["regex"].var.get())
            for rowId in rowIds[1:-1]:
                tagName = TF.createLineColorTagName(
                    tempLineColorRows[rowId].entries["regex"].var.get())
                for textFrame in textFrames:
                    textFrame.textArea.tag_raise(tagName, aboveThis=preTagName)
                preTagName = tagName

        # print(*self._textFrame.textArea.tag_names(),sep=", ")

        # Reload main interface
        for textFrame in textFrames:
            textFrame.reloadLineColorMap()
            textFrame.reloadTextFrame()

        # Start workers
        self._highlightWorker.startWorker()
        self._guiWorker.startWorker()

        # Remove spinners
        for textFrame in textFrames:
            textFrame.closeSpinner()

        # Update save button, if window has been opened again
        self._root.after(10, self._setSaveButtonState, tk.NORMAL)
        self._saving = False

    ####################################
    # View Creation

    def _addNewEmptyLineColor(self):
        # print("New Button " + str(self.newButtonRow))

        self._newButton.grid(row=self._newButtonRow + 1)

        rowId = self._getRowId(self._newButtonRow)
        self._setsDict[rowId] = self._createSingleLineColorRow(
            self._lineColoringFrame, self._newButtonRow, rowId, "", "white")

        self._newButtonRow += 1

    def _editLineColorRow(self, edit):
        # print("Last focus in " + self.lastFocusInRowId)
        # print("Last focus out " + self.lastFocusOutRowId)

        # If lastFocusIn is not the same as lastFocusOut,
        # we know that lastFocusIn is currently selected.
        if self._lastFocusInRowId != self._lastFocusOutRowId:
            if Sets.LINE_COLOR_MAP in self._lastFocusInRowId:
                # print("EDIT: " + self.lastFocusInRowId)

                # Get row number
                # TODO Use getRowNum??
                rowNum = int(
                    self._lastFocusInRowId.replace(Sets.LINE_COLOR_MAP, ""))

                # Find index of rows to edit
                indexToChange = list()
                if edit == self.EDIT_UP:
                    if rowNum > 0:
                        indexToChange = [rowNum - 1, rowNum]
                elif edit == self.EDIT_DOWN:
                    if rowNum < (self._newButtonRow - 1):
                        indexToChange = [rowNum, rowNum + 1]
                elif edit == self.EDIT_DELETE:
                    indexToChange = range(rowNum, self._newButtonRow)

                if indexToChange:

                    tempTextColorMap = list()
                    for i in indexToChange:
                        # Save regex and color
                        rowId = self._getRowId(i)
                        tempTextColorMap.append((self._setsDict[rowId].entries["regex"].var.get(), \
                                                 self._setsDict[rowId].entries["regex"].data, \
                                                 self._setsDict[rowId].entries["color"].var.get(), \
                                                 self._setsDict[rowId].entries["color"].data))

                        # Remove rows to edit from view
                        self._setsDict[rowId].lineFrame.destroy()
                        del self._setsDict[rowId]

                    # Reorder or delete saved rows
                    newRowNum = -1
                    if edit == self.EDIT_UP:
                        tempTextColorMap[1], tempTextColorMap[
                            0] = tempTextColorMap[0], tempTextColorMap[1]
                        newRowNum = rowNum - 1
                    elif edit == self.EDIT_DOWN:
                        tempTextColorMap[1], tempTextColorMap[
                            0] = tempTextColorMap[0], tempTextColorMap[1]
                        newRowNum = rowNum + 1
                    elif edit == self.EDIT_DELETE:
                        deletedRowData = dict()
                        deletedRowData["tagName"] = TF.createLineColorTagName(
                            tempTextColorMap[0][0])
                        self._deletedLineColorRows.append(deletedRowData)
                        del tempTextColorMap[0]

                    # Recreate saved rows
                    for i, (regexVar, regexData, colorVar,
                            colorData) in enumerate(tempTextColorMap):
                        rowId = self._getRowId(indexToChange[i])
                        self._setsDict[rowId] = self._createSingleLineColorRow(
                            self._lineColoringFrame, indexToChange[i], rowId,
                            regexVar, colorVar)
                        self._setsDict[rowId].entries["regex"].data = regexData
                        self._setsDict[rowId].entries["color"].data = colorData

                    # If move up or down, refocus
                    if newRowNum > -1:
                        rowId = self._getRowId(newRowNum)
                        self._focusInSet(rowId)
                    # If delete, update row count and move newButton
                    else:
                        self._newButtonRow = self._newButtonRow - 1
                        self._newButton.grid(row=self._newButtonRow)
                        self._lastFocusInRowId = ""

                    self._updateExampleText(self.GROUP_LINE_COLORING)

    def _createLineColorRows(self, parent, lineColorMap):
        setDict = dict()
        for rowId in sorted(lineColorMap.keys()):
            rowNum = int(rowId.replace(Sets.LINE_COLOR_MAP, ""))
            setDict[rowId] = self._createSingleLineColorRow(
                parent, rowNum, rowId, lineColorMap[rowId]["regex"],
                lineColorMap[rowId]["color"])

        return setDict

    def _createSingleLineColorRow(self, parent, row, rowId, regex, color):
        colorLine = self.LineColorSettingsLine(self.GROUP_LINE_COLORING)

        colorLine.lineFrame = tk.Frame(parent,
                                       highlightcolor=self.ROW_HIGHLIGHT_COLOR,
                                       highlightthickness=2)
        colorLine.lineFrame.grid(row=row, column=0)
        colorLine.lineFrame.bind("<Button-1>", partial(self._focusInSet,
                                                       rowId))
        colorLine.lineFrame.bind("<FocusOut>", partial(self._focusOut, rowId))

        regexEntry = self.Entry(self.ENTRY_TYPE_REGEX, regex)
        entryName = "regex"

        regexEntry.label = tk.Label(colorLine.lineFrame, text="Regex")
        regexEntry.label.grid(row=0, column=0)
        regexEntry.label.bind("<Button-1>", partial(self._focusInSet, rowId))
        regexEntry.var = tk.StringVar(colorLine.lineFrame)
        regexEntry.var.set(regex)
        regexEntry.observer = regexEntry.var.trace(
            "w", partial(self._validateInput, rowId, entryName))

        regexEntry.input = tk.Entry(colorLine.lineFrame,
                                    textvariable=regexEntry.var,
                                    width=30,
                                    takefocus=False)
        regexEntry.input.grid(row=0, column=1)
        regexEntry.input.bind("<Button-1>", partial(self._focusInLog, rowId))

        colorLine.entries[entryName] = regexEntry

        colorEntry = self.Entry(self.ENTRY_TYPE_COLOR, color)
        entryName = "color"

        colorEntry.label = tk.Label(colorLine.lineFrame, text="Color")
        colorEntry.label.grid(row=0, column=2)
        colorEntry.label.bind("<Button-1>", partial(self._focusInSet, rowId))

        colorEntry.var = tk.StringVar(colorLine.lineFrame)
        colorEntry.var.set(color)
        colorEntry.observer = colorEntry.var.trace(
            "w", partial(self._validateInput, rowId, entryName))
        colorEntry.input = tk.Entry(colorLine.lineFrame,
                                    textvariable=colorEntry.var,
                                    width=10,
                                    takefocus=False)
        colorEntry.input.grid(row=0, column=3)
        colorEntry.input.bind("<Button-1>", partial(self._focusInLog, rowId))

        colorEntry.button = tk.Button(colorLine.lineFrame,
                                      bg=color,
                                      width=3,
                                      command=partial(self._getColor, rowId,
                                                      entryName, True))
        colorEntry.button.grid(row=0, column=4, padx=4)
        colorEntry.button.bind("<Button-1>", partial(self._focusInSet, rowId))

        colorLine.entries[entryName] = colorEntry

        return colorLine

    def _createStandardRows(self, parent, setLines, startRow):
        setDict = dict()

        # Find longest entry in settings
        maxLen = 0
        for setLine in setLines:
            setLen = len(str(self._settings.get(setLine.setId)))
            if setLen > maxLen:
                maxLen = setLen

        row = startRow
        for setLine in setLines:
            setRow = self.SettingsLine(setLine.setGroup)
            entry = self.Entry(setLine.setType,
                               self._settings.get(setLine.setId))

            entryName = "entry"

            # TODO Add frame and highlight to colors (remember column widths and alignment)

            entry.label = tk.Label(parent, text=setLine.setDisplayName)
            entry.label.grid(row=row, column=0, sticky=tk.W)

            ########
            # Entry variable
            if setLine.setType == self.ENTRY_TYPE_INT:
                entry.var = tk.IntVar(parent)
            else:
                entry.var = tk.StringVar(parent)

            # Init entry var
            entry.var.set(self._settings.get(setLine.setId))
            # TODO use tkinter validateCommand
            entry.observer = entry.var.trace(
                "w", partial(self._validateInput, setLine.setId, entryName))

            ########
            # Input field
            if setLine.setType == self.ENTRY_TYPE_TOGGLE:
                # TODO create better toggle values (link to specific settings)
                toggleButtonFrame = tk.Frame(parent)
                toggleButtonFrame.grid(row=row, column=1, sticky=tk.E + tk.W)
                toggleButtonFrame.grid_columnconfigure(0, weight=1)
                toggleButtonFrame.grid_columnconfigure(1, weight=1)
                onButton = tk.Radiobutton(toggleButtonFrame,
                                          text="On",
                                          variable=entry.var,
                                          indicatoron=False,
                                          value="on")
                onButton.grid(row=0, column=0, sticky=tk.E + tk.W)
                offButton = tk.Radiobutton(toggleButtonFrame,
                                           text="Off",
                                           variable=entry.var,
                                           indicatoron=False,
                                           value="off")
                offButton.grid(row=0, column=1, sticky=tk.E + tk.W)
            else:
                # TODO Find better solution for entry width
                entry.input = tk.Entry(parent,
                                       textvariable=entry.var,
                                       width=int(maxLen * 1.5),
                                       takefocus=False)
                entry.input.grid(row=row, column=1)

            ########
            # Color button
            if setLine.setType == self.ENTRY_TYPE_COLOR:
                entry.button = tk.Button(parent,
                                         bg=self._settings.get(setLine.setId),
                                         width=3,
                                         command=partial(
                                             self._getColor, setLine.setId,
                                             entryName))
                entry.button.grid(row=row, column=2, padx=4)

            setRow.entries[entryName] = entry
            setDict[setLine.setId] = setRow

            row += 1

        return setDict

    ####################################
    # View Interaction

    def _focusOut(self, rowId, event):
        self._lastFocusOutRowId = rowId

    def _focusInSet(self, rowId, event=0):
        self._setsDict[rowId].lineFrame.focus_set()
        self._focusInLog(rowId, event)

    def _focusInLog(self, rowId, event=0):
        self._lastFocusInRowId = rowId
        if self._lastFocusOutRowId == rowId:
            self._lastFocusOutRowId = ""

    def _getColor(self, rowId, entry, highlight=False):

        if highlight:
            hg = self._setsDict[rowId].lineFrame.cget("highlightbackground")
            self._setsDict[rowId].lineFrame.config(
                highlightbackground=self.ROW_HIGHLIGHT_COLOR)

        currentColor = self._setsDict[rowId].entries[entry].button.cget("bg")

        if not self._isValidColor(currentColor):
            currentColor = None

        color = askcolor(initialcolor=currentColor, parent=self._view)

        if color[1] != None:
            self._setsDict[rowId].entries[entry].var.set(color[1])
            self._setsDict[rowId].entries[entry].button.config(bg=color[1])

        if highlight:
            self._setsDict[rowId].lineFrame.config(highlightbackground=hg)
            self._focusInLog(rowId)

    # class WidgetSize:
    #     def __init__(self,width,height,posx,posy):
    #         self.width = width
    #         self.height = height
    #         self.posx = posx
    #         self.posy = posy

    # def _getWidgetSize_(self,widget):

    #     width = widget.winfo_width()
    #     height = widget.winfo_height()
    #     posx = widget.winfo_x()
    #     posy = widget.winfo_y()

    #     return self.WidgetSize(width,height,posx,posy)

    def _tabChanged(self, event):
        self._view.focus_set()
        self._exampleText.tag_remove("sel", 1.0, tk.END)
        self._updateExampleText(
            self._tabList[self._tabControl.index("current")])

    def _updateExampleText(self, group):

        #####################
        # Setup

        # Delete all search tags
        self._exampleText.tag_delete(Sets.SEARCH_SELECTED_LINE_COLOR)
        self._exampleText.tag_delete(Sets.SEARCH_MATCH_COLOR)
        self._exampleText.tag_delete(Sets.SEARCH_SELECTED_COLOR)

        # Delete all current line color tags
        tagNames = self._exampleText.tag_names()
        for tagName in tagNames:
            if Sets.LINE_COLOR_MAP in tagName:
                self._exampleText.tag_delete(tagName)

        entryName = "entry"
        if group == self.GROUP_TEXT_AREA:
            # General text area
            try:
                tFont = Font(family=self._setsDict[Sets.TEXTAREA_FONT_FAMILY].entries[entryName].var.get(),\
                            size=self._setsDict[Sets.TEXTAREA_FONT_SIZE].entries[entryName].var.get())
                self._exampleText.config(background=self._setsDict[Sets.TEXTAREA_BACKGROUND_COLOR].entries[entryName].var.get(),\
                                                selectbackground=self._setsDict[Sets.TEXTAREA_SELECT_BACKGROUND_COLOR].entries[entryName].var.get(),\
                                                foreground=self._setsDict[Sets.TEXTAREA_COLOR].entries[entryName].var.get(),\
                                                font=tFont)

                lineWrapString = self._setsDict[
                    Sets.TEXTAREA_LINE_WRAP].entries[entryName].var.get()
                if lineWrapString == "on":
                    self._updateExampleTextLineWrap(Sets.LINE_WRAP_ON)
                elif lineWrapString == "off":
                    self._updateExampleTextLineWrap(Sets.LINE_WRAP_OFF)

            except tk.TclError:
                pass

        elif group == self.GROUP_SEARCH:

            searchString = "Main"

            # Create search tags
            self._exampleText.tag_configure(Sets.SEARCH_SELECTED_LINE_COLOR, \
                                            background=self._setsDict[Sets.SEARCH_SELECTED_LINE_COLOR].entries[entryName].var.get(),\
                                            selectbackground=util.lightOrDarkenColor(self._setsDict[Sets.SEARCH_SELECTED_LINE_COLOR].entries[entryName].var.get(),Sets.SELECTED_LINE_DARKEN_COLOR))
            self._exampleText.tag_configure(Sets.SEARCH_MATCH_COLOR, \
                                            background=self._setsDict[Sets.SEARCH_MATCH_COLOR].entries[entryName].var.get(),\
                                            selectbackground=util.lightOrDarkenColor(self._setsDict[Sets.SEARCH_MATCH_COLOR].entries[entryName].var.get(),Sets.SELECTED_LINE_DARKEN_COLOR))
            self._exampleText.tag_configure(Sets.SEARCH_SELECTED_COLOR, \
                                            background=self._setsDict[Sets.SEARCH_SELECTED_COLOR].entries[entryName].var.get(), \
                                            selectbackground=util.lightOrDarkenColor(self._setsDict[Sets.SEARCH_SELECTED_COLOR].entries[entryName].var.get(),Sets.SELECTED_LINE_DARKEN_COLOR))

            # Do search
            countVar = tk.StringVar()
            results = list()
            start = 1.0
            while True:
                pos = self._exampleText.search(searchString,
                                               start,
                                               stopindex=tk.END,
                                               count=countVar,
                                               nocase=False,
                                               regexp=False)
                if not pos:
                    break
                else:
                    results.append((pos, pos + "+" + countVar.get() + "c"))
                    start = pos + "+1c"

            # Add search tags
            first = True
            for result in results:
                self._exampleText.tag_add(Sets.SEARCH_MATCH_COLOR, result[0],
                                          result[1])
                if first:
                    first = False
                    self._exampleText.tag_add(Sets.SEARCH_SELECTED_COLOR,
                                              result[0], result[1])
                    selectLine = result[0].split(".")[0]
                    self._exampleText.tag_add(Sets.SEARCH_SELECTED_LINE_COLOR,
                                              selectLine + ".0",
                                              selectLine + ".0+1l")

        if group == self.GROUP_LINE_COLORING or group == self.GROUP_SEARCH:

            # Get line color map from view
            tempLineColorMap = list()
            for rowId in sorted(self._setsDict.keys()):
                if Sets.LINE_COLOR_MAP in rowId:
                    lineInfo = dict()
                    lineInfo["regex"] = self._setsDict[rowId].entries[
                        "regex"].var.get()
                    lineInfo["color"] = self._setsDict[rowId].entries[
                        "color"].var.get()
                    lineInfo["tagName"] = TF.createLineColorTagName(
                        lineInfo["regex"])
                    tempLineColorMap.append(lineInfo)

            # Apply new line colors
            for lineInfo in tempLineColorMap:
                self._exampleText.tag_configure(lineInfo["tagName"],
                                                foreground=lineInfo["color"])

                countVar = tk.StringVar()
                start = 1.0
                while True:
                    pos = self._exampleText.search(lineInfo["regex"],
                                                   start,
                                                   stopindex=tk.END,
                                                   count=countVar,
                                                   nocase=False,
                                                   regexp=True)
                    if not pos:
                        break
                    else:
                        self._exampleText.tag_add(
                            lineInfo["tagName"], pos,
                            pos + "+" + countVar.get() + "c")
                        start = pos + "+1c"

    def _updateExampleTextLineWrap(self, lineWrapState):

        if lineWrapState == Sets.LINE_WRAP_ON:
            self._exampleText.config(wrap=tk.CHAR)
        else:
            self._exampleText.config(wrap=tk.NONE)

    ####################################
    # Entry Validation

    def _validateInput(self, rowId, entryName, *args):

        # Get variable
        try:
            settingsLine: self.SettingsLine = self._setsDict[rowId]
            entry: self.Entry = settingsLine.entries[entryName]
            varIn = entry.var.get()
            validationStatus = self.ENTRY_VALIDATION_OK
        except tk.TclError:
            # print("Tcl Error")
            validationStatus = self.ENTRY_VALIDATION_FAILED

        if validationStatus == self.ENTRY_VALIDATION_OK:

            # Check Colors
            if entry.data.entryType == self.ENTRY_TYPE_COLOR:
                if self._isValidColor(varIn):
                    # print("Color " + str(color))
                    entry.button.config(background=varIn)
                    validationStatus = self.ENTRY_VALIDATION_OK
                else:
                    validationStatus = self.ENTRY_VALIDATION_FAILED

            # Check regex
            if entry.data.entryType == self.ENTRY_TYPE_REGEX:

                # Validate regex
                if self._isValidRegex(varIn):
                    entry.data.validation.status = self.ENTRY_VALIDATION_OK
                else:
                    entry.data.validation.status = self.ENTRY_VALIDATION_FAILED

                self._updateAllRegexEntries()

                validationStatus = entry.data.validation.status

            # Check font family
            if rowId == Sets.TEXTAREA_FONT_FAMILY:
                if self._isValidFontFamily(varIn):
                    validationStatus = self.ENTRY_VALIDATION_OK
                else:
                    validationStatus = self.ENTRY_VALIDATION_FAILED

            # Check font size
            if rowId == Sets.TEXTAREA_FONT_SIZE:
                if self._isValidFontSize(varIn):
                    validationStatus = self.ENTRY_VALIDATION_OK
                else:
                    validationStatus = self.ENTRY_VALIDATION_FAILED

        #######
        # Update validation info

        if validationStatus == self.ENTRY_VALIDATION_OK:
            entry.data.validation.status = self.ENTRY_VALIDATION_OK
            entry.data.validation.backgroundColor = "white"
            entry.data.validation.infoText = ""
        elif validationStatus == self.ENTRY_VALIDATION_FAILED:
            entry.data.validation.status = self.ENTRY_VALIDATION_FAILED
            entry.data.validation.backgroundColor = "red"
            entry.data.validation.infoText = "Non-valid input."

        if not entry.data.entryType == self.ENTRY_TYPE_TOGGLE:
            entry.input.config(
                background=entry.data.validation.backgroundColor)

        infoText = ""
        for key in self._setsDict.keys():
            for (entryKey, entryItem) in self._setsDict[key].entries.items():
                if entryItem.data.validation.status != self.ENTRY_VALIDATION_OK:
                    entryId = key + "_" + entryKey
                    if infoText:
                        infoText += "\n"
                    infoText += entryId + ": " + entryItem.data.validation.infoText

        if infoText:
            self._optionsInfoLabel.config(text=infoText)
            self._setSaveButtonState(tk.DISABLED)
        else:
            self._optionsInfoLabel.config(text="")
            self._setSaveButtonState(tk.NORMAL)
            self._updateExampleText(settingsLine.group)

    def _isValidColor(self, colorString):
        isValid = True
        try:
            tk.Label(None, background=colorString)
        except tk.TclError:
            # print("Color Error")
            isValid = False
        return isValid

    def _isValidFontFamily(self, family):
        fontList = tk.font.families()
        return family in fontList

    def _isValidFontSize(self, size):
        isValid = True
        try:
            Font(size=size)
        except tk.TclError:
            # print("Font Size Error")
            isValid = False

        if isValid:
            if int(size) < 1:
                isValid = False

        return isValid

    def _isValidRegex(self, regex):
        isValid = True
        try:
            # re.compile(regex) # Tkinter does not allow all regex, so this cannot be used
            self._exampleText.search(regex, 1.0, stopindex=tk.END, regexp=True)
        except:
            isValid = False
        return isValid

    def _updateAllRegexEntries(self):
        # Get all regex
        regexList = list()
        for key in self._setsDict.keys():
            try:
                value = self._setsDict[key].entries["regex"].var.get()
                regexList.append(value)
            except KeyError:
                pass

        # Find any duplicate entries
        regexListCount = Counter(regexList)
        regexDuplicateList = [
            regex for regex, count in regexListCount.items() if count > 1
        ]

        # Update all duplicate regex entries
        for key in self._setsDict.keys():
            try:
                regexEntry = self._setsDict[key].entries["regex"]
                # Only update status if entry validation status is not currently failed
                if regexEntry.data.validation.status != self.ENTRY_VALIDATION_FAILED:
                    # Mark duplicates
                    if regexEntry.var.get() in regexDuplicateList:
                        # print("New duplicate: " + regexEntry.var.get())
                        regexEntry.data.validation.status = self.ENTRY_VALIDATION_DUPLICATE
                        regexEntry.data.validation.backgroundColor = "yellow"
                        regexEntry.data.validation.infoText = "Duplicate regex entry not allowed."
                    else:
                        # Clear previous duplicates that are now valid
                        if regexEntry.data.validation.status == self.ENTRY_VALIDATION_DUPLICATE:
                            # print("Clear duplicate: " + regexEntry.var.get())
                            regexEntry.data.validation.status = self.ENTRY_VALIDATION_OK
                            regexEntry.data.validation.backgroundColor = "white"
                            regexEntry.data.validation.infoText = ""

                    regexEntry.input.config(
                        background=regexEntry.data.validation.backgroundColor)
            except KeyError:
                pass

    ####################################
    # Misc

    def _getRowId(self, rowNum):
        return Sets.LINE_COLOR_MAP + "{:02d}".format(rowNum)
예제 #8
0
파일: mainview.py 프로젝트: gokai/tim
class Main(object):

    def __init__(self, title):
        root = Tk()
        root.title(title)
        root.focus_set()
        root.rowconfigure(0, weight=0)
        root.columnconfigure(0, weight=1)
        root.rowconfigure(1, weight=1)
        self._root = root

        self.menubar = Frame(root)
        self.menubar.grid(row=0, column=0, sticky=(W, E))
        self.menubar['takefocus'] = False

        quit_button = Button(self.menubar, text='Quit', command=self.quit)
        quit_button.grid(row=0, column=0)

        self._menucolumn = 1
        self.views = list()

        self.paned_win = PanedWindow(root, orient=HORIZONTAL)
        self.paned_win.grid(row=1, column=0, sticky=(N, S, W, E))

        self._query = None
        self._accept_func = None

        self.sidebar_views = dict()
        self.sidebar_count = 0
        self.sidebar = PanedWindow(self.paned_win)
        self.paned_win.add(self.sidebar, weight=1)
        
        self.tabs = Notebook(self.paned_win)
        self.tabs.enable_traversal()
        self.paned_win.add(self.tabs, weight=5)
        self.root = self.tabs

    def add_menubutton(self, label, action):
        button = Button(self.menubar, text=label, command=action)
        button.grid(row=0, column=self._menucolumn)
        self._menucolumn += 1

    def add_sidebar(self, view, name):
        self.sidebar_views[name] = view
        self.sidebar.add(view.widget, weight=1)
        view.widget.focus_set()
        self.sidebar_count += 1
        if self.sidebar_count == 1:
            self.sidebar_views['main'] = view

    def remove_sidebar_view(self, name):
        self.sidebar.forget(self.sidebar_views[name].widget)
        self.sidebar_count -= 1
        del self.sidebar_views[name]
        if self.sidebar_count == 0:
            del self.sidebar_views['main']

    def get_sidebar_view(self, name):
        return self.sidebar_views.get(name)

    def focus_sidebar(self):
        if 'main' in self.sidebar_views.keys():
            self.sidebar_views['main'].widget.focus_set()

    def focus_main_view(self):
        self.get_current_view().widget.focus_set()

    def new_view(self, view):
        self.views.append(view)
        self.tabs.add(view.widget, text=" {}.".format(self.tabs.index('end')))
        self.tabs.select(view.widget)

        view.widget.focus_set()
        self.view_changed()

    def remove_view(self, view):
        self.views.remove(view)
        self.tabs.forget(view.widget)
        if len(self.views) >= 1:
            widget = self.views[-1].widget
            self.tabs.select(widget)
            widget.focus_set()
        else:
            self.sidebar_views['main'].widget.focus_set()
        self.view_changed()

    def delete_current_view(self, event):
        if self.tabs.index('end') > 0:
            self.remove_view(self.get_current_view())

    def close_query(self):
        if self._query is not None:
            self._query.event_generate('<<MainQueryClose>>')
            self._query.destroy()
            self._query = None
            self._accept_func = None
            self._menucolumn -= 1

    def accept_query(self, event):
        if self._query is not None:
            if self._accept_func is not None:
                self._accept_func(event.widget.get(), event.widget.original_value)
                self.close_query()
            else:
                event.widget.event_generate('<<MainQueryAccept>>')

    def text_query(self, query_lable, original_text=None, accept_func=None):
        if self._query is not None:
            return
        frame = Frame(self.menubar)
        label = Label(frame, text=query_lable)
        label.grid(column=0, row=0, sticky=(N, S))
        self._accept_func = accept_func

        entry = Entry(frame)
        if original_text is not None:
            entry.insert(0, original_text)
        entry.original_value = original_text
        entry.grid(column=1, row=0, sticky=(N,S,W,E))
        kb.make_bindings(kb.text_query, 
                {'accept': self.accept_query,
                 'cancel': lambda e: self.close_query()}, entry.bind)

        frame.grid(column=self._menucolumn, row=0)
        self._menucolumn += 1
        entry.focus_set()
        self._query = frame

    def get_current_view(self):
        if self.tabs.index('end') > 0:
            return self.views[self.tabs.index('current')]
        else:
            return self.sidebar_views['main']

    def view_changed(self):
        self._root.event_generate('<<MainViewChanged>>')

    def display(self):
        self._root.mainloop()

    def quit(self):
        self._root.destroy()
예제 #9
0
파일: cim.py 프로젝트: ZanderBrown/Tiborcim
class CimApp(Frame):
    def __init__(self):
        Frame.__init__(self)
        self.file = None;
        self.master.title("Tiborcim")
        self.master.iconphoto(True, PhotoImage(file=ICON_PNG))
        self.files = []
        self.current_tab = StringVar()
        self.pack(expand=1, fill="both")
        self.master.minsize(300,300)
        self.master.geometry("500x500")

        self.menubar = Menu(self.master)
        self.fileMenu = Menu(self.master, tearoff=0)
        self.fileMenu.add_command(label="New", command=self.new_file,
                                  underline=0, accelerator="Ctrl+N")
        self.fileMenu.add_command(label="Open...", command=self.load_file,
                                  underline=0, accelerator="Ctrl+O")
        self.fileMenu.add_command(label="Save", command=self.file_save,
                                  underline=0, accelerator="Ctrl+S")
        self.fileMenu.add_command(label="Save As...", command=self.file_save_as,
                                  underline=5, accelerator="Ctrl+Alt+S")
        self.fileMenu.add_command(label="Close", command=self.close_file,
                                  underline=0, accelerator="Ctrl+W")
        self.fileMenu.add_separator()
        self.fileMenu.add_command(label="Exit", command=self.file_quit, underline=1)
        self.menubar.add_cascade(label="File", menu=self.fileMenu, underline=0)

        self.edit_program = Menu(self.master, tearoff=0)
        self.edit_program.add_command(label="Undo", command=self.edit_undo,
                                  underline=0, accelerator="Ctrl+Z")
        self.edit_program.add_command(label="Redo", command=self.edit_redo,
                                      underline=0, accelerator="Ctrl+Y")
        self.edit_program.add_separator()
        self.edit_program.add_command(label="Cut",
                                      command=self.edit_cut,
                                      underline=2,
                                      accelerator="Ctrl+X")
        self.edit_program.add_command(label="Copy",
                                      command=self.edit_copy,
                                      underline=0,
                                      accelerator="Ctrl+C")
        self.edit_program.add_command(label="Paste",
                                      command=self.edit_paste,
                                      underline=0,
                                      accelerator="Ctrl+V")
        self.menubar.add_cascade(label="Edit", menu=self.edit_program, underline=0)

        self.menu_program = Menu(self.master, tearoff=0)
        self.menu_program.add_command(label="Convert",
                                      command=self.convert_file,
                                      underline=0,
                                      accelerator="Ctrl+T")
        self.menu_program.add_command(label="Flash",
                                      command=self.flash_file,
                                      underline=0,
                                      accelerator="Ctrl+B")
        self.menu_program.add_separator()
        self.menubar.add_cascade(label="Program", menu=self.menu_program, underline=0)

        self.menu_view = Menu(self.master,
                              tearoff=0)
        self.viewmode = StringVar()
        self.viewmode.set("tiborcim")
        self.menu_view.add_radiobutton(label="Tiborcim",
                                       command=self.view_tiborcim,
                                       variable=self.viewmode,
                                       value="tiborcim",
                                       underline=0)
        self.menu_view.add_radiobutton(label="Python",
                                       command=self.view_python,
                                       variable=self.viewmode,
                                       value="python",
                                       underline=0)
        self.menubar.add_cascade(label="View",
                                 menu=self.menu_view,
                                 underline=0)

        self.menu_help = Menu(self.master,
                              tearoff=0)
        
        self.menu_samples = Menu(self.master, tearoff=0)
        samples = tiborcim.resources.samples_list()
        def add_sample (sample):
            self.menu_samples.add_command(label=sample,
                                          command=lambda: self.help_sample(sample))
        for sample in samples:
            add_sample(sample)
    
        self.menu_help.add_cascade(label="Samples",
                                   menu=self.menu_samples,
                                   underline=0)
        self.menu_help.add_separator()
        self.menu_help.add_command(label="README",
                                   command=self.help_readme,
                                   underline=0)
        self.menu_help.add_separator()
        self.menu_help.add_command(label="About",
                                   command=self.help_about,
                                   underline=0)
        self.menubar.add_cascade(label="Help",
                                 menu=self.menu_help,
                                 underline=0)

        self.master.config(width=450,
                           height=400,
                           menu=self.menubar)

        self.bind_all("<Control-o>", self.load_file)
        self.bind_all("<Control-s>", self.file_save)
        self.bind_all("<Control-Alt-s>", self.file_save_as)
        self.bind_all("<Control-t>", self.convert_file)
        self.bind_all("<Control-b>", self.flash_file)
        self.bind_all("<Control-w>", self.close_file)
        self.master.protocol("WM_DELETE_WINDOW", self.file_quit)

        self.file_tabs = Notebook(self)
        self.file_tabs.bind_all("<<NotebookTabChanged>>", self.file_changed)
        self.file_tabs.pack(expand=1, fill="both")

    def file_changed(self, event):
        if len(self.file_tabs.tabs()) <= 0:
            self.add_file()
            return
        title = str(event.widget.tab(event.widget.index("current"),"text")).upper().strip()
        self.menu_program.delete(3, END)
        for tab in self.file_tabs.tabs():
            tabtext = self.file_tabs.tab(self.file_tabs.index(tab),"text")
            if tabtext.upper().strip() == title:
                self.current_tab.set(tab)        
            self.menu_program.add_radiobutton(label=tabtext, command=self.program_switch,
                                  underline=1, value=tab, variable=self.current_tab)
        if title != "PYTHON" or title != "TIBORCIM":
            if self.current_file().filename is not None:
                self.master.title(self.current_file().get_file() + " - Tiborcim")
            else:
                self.master.title("Tiborcim")
            if str(self.current_file().tab(self.current_file().index("current"),"text")).upper().strip() == "TIBORCIM":
                self.menubar.entryconfig("Edit", state=NORMAL)
            else:
                self.menubar.entryconfig("Edit", state=DISABLED)
            self.viewmode.set(self.current_file().viewmode)
        if title == "PYTHON":
            self.menubar.entryconfig("Edit", state=DISABLED)
            self.current_file().viewmode = "python";
            self.viewmode.set("python");
        if title == "TIBORCIM":
            self.menubar.entryconfig("Edit", state=NORMAL)
            self.current_file().viewmode = "tiborcim";
            self.viewmode.set("tiborcim");

    def add_file(self, file=None):
        filepage = CimFilePage(self.file_tabs)
        if file is None:
            self.file_tabs.add(filepage, text="Unsaved Program")
        else:
            filepage.load_file(file)
            self.file_tabs.add(filepage, text=filepage.get_file())
        self.files.append(filepage)
        self.file_tabs.select(filepage)

    def view_tiborcim(self, event=None):
        self.current_file().view_tiborcim()

    def view_python(self, event=None):
        self.current_file().view_python()

    def program_switch(self):
        self.file_tabs.select(self.current_tab.get())

    def new_file(self, event=None):
        self.add_file()

    def load_file(self, event=None):
        fname = askopenfilename(filetypes=(("Tiborcim", "*.tibas"),("All files", "*.*") ), parent=self.master)
        if fname:
            self.add_file(fname)

    def file_save(self, event=None):
        self.current_file().save_file()
        self.file_tabs.tab(self.current_file(), text=self.current_file().get_file())

    def file_save_as(self, event=None):
        self.current_file().save_file_as()
        self.file_tabs.tab(self.current_file(), text=self.current_file().get_file())

    def convert_file(self, event=None):
        self.current_file().convert_file()

    def current_file(self, event=None):
        return self.files[int(self.file_tabs.index(self.file_tabs.select()))]

    def flash_file(self, event=None):
        from tiborcim.tibc import compiler as tibc
        from tiborcim.tibc import flash
        from tiborcim.tibc import TibcStatus as status
        com = tibc(self.current_file().text_tiborcim.get("1.0", "end"))
        res = flash(''.join(com.output))
        if res is status.SUCCESS:
            showinfo(title='Success', message='File Flashed', parent=self.master)
        else:
            showerror(title='Failure', message='An Error Occured. Code: %s' % res, parent=self.master)

    def close_file(self, event=None):
        logging.debug("Close File")
        file = self.current_file()
        if file.close():
            self.file_tabs.forget(file)
            self.files.remove(file)

    def edit_cut(self, event=None):
        self.current_file().text_tiborcim.event_generate('<Control-x>')

    def edit_copy(self, event=None):
        self.current_file().text_tiborcim.event_generate('<Control-c>')

    def edit_paste(self, event=None):
        self.current_file().text_tiborcim.event_generate('<Control-v>')

    def edit_redo(self, event=None):
        self.current_file().text_tiborcim.edit_redo()
        
    def edit_undo(self, event=None):
        self.current_file().text_tiborcim.edit_undo()

    def help_about(self, event=None):
        CimAbout.show(self)

    def help_readme(self, event=None):
        CimReadme.show(self)

    def help_sample(self, sam):
        print(sam)
        filepage = CimFilePage(self.file_tabs)
        filepage.load_file(tiborcim.resources.sample_path(sam))
        filepage.filename = None
        self.file_tabs.add(filepage, text="Unsaved Program")
        self.files.append(filepage)
        self.file_tabs.select(filepage)

    def file_quit(self, event=None):
        for ndx, member in enumerate(self.files):
            logging.debug(self.files[ndx].saved)
            if not self.files[ndx].close():
                return

        self.quit()
예제 #10
0
class CrickitGui(BanyanBase):
    """
    The Crickit For Raspberry Pi Demo Station GUI
    """
    def __init__(self, **kwargs):
        """
        Build the main screen as a notebook.
        """

        # initialize the parent class
        super(CrickitGui, self).__init__(
            back_plane_ip_address=kwargs['back_plane_ip_address'],
            subscriber_port=kwargs['subscriber_port'],
            publisher_port=kwargs['publisher_port'],
            process_name=kwargs['process_name'])

        self.set_subscriber_topic('report_from_hardware')

        self.main = Tk()
        self.main.title('Demo Station For Raspberry Pi Crickit')

        # gives weight to the cells in the grid
        rows = 0
        while rows < 50:
            self.main.rowconfigure(rows, weight=1)
            self.main.columnconfigure(rows, weight=1)
            rows += 1

        # Defines and places the notebook widget
        self.nb = Notebook(self.main, padding=20, height=300, width=800)
        self.nb.grid(row=1, column=0, columnspan=50, rowspan=49, sticky='NESW')

        # create the signal inputs tab
        self.signal_inputs_tab = Frame(self.nb, padding=10)
        self.nb.add(self.signal_inputs_tab, text='Signal Inputs')
        # create an instance of the SignalInputs class
        # to populate and control Signal inputs
        self.signal_inputs = SignalInputs(self.signal_inputs_tab, self)

        # create the signal outputs tab
        self.signal_outputs_tab = Frame(self.nb, padding=10)
        self.nb.add(self.signal_outputs_tab, text='Signal Outputs')
        # create an instance of the SignalOutputs class
        # to populate and control Signal outputs
        self.signal_outputs = SignalOutputs(self.signal_outputs_tab, self)

        # create the signals tab
        self.touch_tab = Frame(self.nb, padding=10)
        self.nb.add(self.touch_tab, text='Touch Inputs')
        self.touch_inputs = TouchInputs(self.touch_tab, self)

        # create the drives tab
        self.drives_tab = Frame(self.nb, padding=10)
        self.nb.add(self.drives_tab, text='Drive Outputs')
        self.drive_outputs = DriveOutputs(self.drives_tab, self)

        # create the dc motors tab
        self.motors_tab = Frame(self.nb, padding=10)
        self.nb.add(self.motors_tab, text='DC Motors')
        self.dc_motors = DcMotors(self.motors_tab, self)

        # create the servo motors tab
        self.servos_tab = Frame(self.nb, padding=10)
        self.nb.add(self.servos_tab, text='Servo Motors')
        self.servos = Servos(self.servos_tab, self)

        # create the stepper motors tab
        self.steppers_tab = Frame(self.nb, padding=10)
        self.nb.add(self.steppers_tab, text='Stepper Motors')
        self.stepper_motors = Steppers(self.steppers_tab, self)

        # create the stepper motors tab
        self.neopixels_tab = Frame(self.nb, padding=10)
        self.nb.add(self.neopixels_tab, text='NeoPixels')
        self.stepper_motors = NeoPixels(self.neopixels_tab, self)

        l = Label(self.main,
                  text='Copyright (c) 2019 Alan Yorinks All Rights Reserved.')
        l.config(font="Helvetica 8 ")
        l.grid(row=48, column=0, padx=[505, 0])

        self.main.after(5, self.get_message)

        try:
            self.main.mainloop()
        except KeyboardInterrupt:
            self.on_closing()

    def notebook_tab_selection(self):
        print(self.nb.tab(self.nb.select(), "text"))
        print(self.nb.index(self.nb.select()))

    def get_message(self):
        """
        This method is called from the tkevent loop "after" method.
        It will poll for new zeromq messages within the tkinter event loop.
        """
        try:
            data = self.subscriber.recv_multipart(zmq.NOBLOCK)
            self.incoming_message_processing(
                data[0].decode(), msgpack.unpackb(data[1], raw=False))
            self.main.after(1, self.get_message)

        except zmq.error.Again:
            try:
                self.main.after(1, self.get_message)
            except KeyboardInterrupt:
                self.main.destroy()
                self.publisher.close()
                self.subscriber.close()
                self.context.term()
                sys.exit(0)
        except KeyboardInterrupt:
            self.main.destroy()
            self.publisher.close()
            self.subscriber.close()
            self.context.term()
            sys.exit(0)

    def incoming_message_processing(self, topic, payload):
        """
        This method processes the incoming pin state change
        messages for GPIO pins set as inputs.

        :param topic:
        :param payload:

        Typical report: {'report': 'digital_input', 'pin': pin,
                       'value': level, 'timestamp': time.time()}
        """
        # if the pin currently input active, process the state change
        pin = payload['pin']
        value = payload['value']
        timestamp = payload['timestamp']
        if 0 <= pin < 8:
            self.signal_inputs.set_input_value(pin, value)
            self.signal_inputs.set_time_stamp_value(pin, timestamp)
        if 8 <= pin < 12:
            # we subtract eight to normalize the pin number
            self.touch_inputs.set_input_value(pin - 8, value)
            self.touch_inputs.set_time_stamp_value(pin - 8, timestamp)

    def on_closing(self):
        """
        Destroy the window
        """
        self.clean_up()
        self.main.destroy()
예제 #11
0
파일: txteditor.py 프로젝트: eukap/pyted
class Application(Frame):
    class TextFrameTab:
        def __init__(self, obj):
            self.text_frm = Frame(obj.notebook)
            self.text_frm.pack(side=TOP, expand=YES, fill=BOTH)

            self.text = Text(self.text_frm)
            self.text.config(fg='#111111',
                             bg='#f2f2f2',
                             bd=0,
                             wrap=WORD,
                             undo=True,
                             maxundo=100,
                             autoseparators=True,
                             selectbackground='#bbbbcf')
            self.text.focus()
            self.yscroll = Scrollbar(self.text_frm, orient=VERTICAL)
            self.yscroll.config(cursor='arrow',
                                command=self.text.yview,
                                bg='#777777',
                                activebackground='#6d6d6d',
                                troughcolor='#c2c2c2')
            self.text['yscrollcommand'] = self.yscroll.set
            self.yscroll.pack(side=RIGHT, fill=Y)
            self.text.pack(side=LEFT, expand=YES, fill=BOTH)
            self.text.edit_modified(arg=False)
            obj.textwidgets.append(self.text)

            obj.notebook.add(self.text_frm, padding=1, text=obj.filenames[-1])
            obj.notebook.select(self.text_frm)

            self.file_menu = obj.file_menu
            self.notebook = obj.notebook
            self.filenames = obj.filenames
            self.save_btn = obj.save_btn

            self.statusbar_line_lbl = obj.statusbar_line_lbl
            self.statusbar_col_lbl = obj.statusbar_col_lbl

            # Disable 'Save' menu item
            self.file_menu.entryconfigure(4, state=DISABLED)

            self.text.bind('<<StateChecking>>', self.check_state)
            self.text.bind('<<StateChecking>>', self.mark_line, add='+')

        def mark_line(self, event):
            if 'currline' in self.text.tag_names():
                self.text.tag_delete('currline')
            self.text.tag_add('currline', 'insert linestart',
                              'insert linestart + 1 lines')
            # Highlight the current line
            self.text.tag_config('currline', background='#dadada')
            self.text.tag_lower('currline')

        def check_state(self, event):
            line_number = self.text.index(INSERT).split('.')[0]
            # Display the line number of the current cursor position
            # on the status bar
            self.statusbar_line_lbl.config(text='ln: ' + line_number)

            col_number = str(int(self.text.index(INSERT).split('.')[1]) + 1)
            # Display the column number of the current cursor position
            # on the status bar
            self.statusbar_col_lbl.config(text='col: ' + col_number)

            try:
                current_index = self.notebook.index('current')
                modified = self.text.edit_modified()
                if modified:
                    # Enable 'Save' menu item
                    self.file_menu.entryconfigure(4, state=NORMAL)
                    # Add asterisk to the header of the tab
                    self.notebook.tab(current_index,
                                      text='*' + self.filenames[current_index])
                    self.save_btn.config(state=NORMAL)
                else:
                    # Disable 'Save' menu item
                    self.file_menu.entryconfigure(4, state=DISABLED)
                    # If there is asterisk at the header of the tab,
                    # remove it
                    self.notebook.tab(current_index,
                                      text=self.filenames[current_index])
                    self.save_btn.config(state=DISABLED)
            except TclError:
                pass

    def __init__(self, parent=None):
        Frame.__init__(self, parent)
        # A dictionary with paths to opened and/or saved files
        self.filepaths = {}
        # A list with names of files opened in separate tabs
        self.filenames = ['Untitled']
        # A list with existing text widgets
        self.textwidgets = []

        self.menubar = Frame(self)
        self.menubar.config(bg='#444444', bd=0, relief=FLAT, padx=2)
        self.menubar.pack(side=TOP, fill=X)

        self.toolbar = Frame(self)
        self.toolbar.config(bg='#444444', bd=1, relief=GROOVE, pady=6, padx=2)
        self.toolbar.pack(side=TOP, fill=X)

        self.statusbar = Frame(self)
        self.statusbar.config(bg='#222222', bd=0, relief=FLAT, padx=10)
        self.statusbar.pack(side=BOTTOM, fill=X)

        self.style = Style()
        self.style.configure('TNotebook', background='#606060')

        self.notebook = Notebook(self)
        self.notebook.enable_traversal()
        self.notebook.pack(side=TOP, expand=YES, fill=BOTH)

        self.file_menu_btn = Menubutton(self.menubar)
        self.file_menu_btn.config(text='File',
                                  bg='#444444',
                                  fg='#eeeeee',
                                  activeforeground='#eeeeee',
                                  activebackground='#647899',
                                  underline=0)
        self.file_menu_btn.pack(side=LEFT)
        self.file_menu = Menu(self.file_menu_btn, tearoff=0)
        self.file_menu_btn['menu'] = self.file_menu
        self.file_menu.config(fg='#eeeeee',
                              activeforeground='#eeeeee',
                              bg='#444444',
                              activebackground='#647899')
        self.file_menu.add_command(label='New',
                                   command=self.create_new_doc,
                                   accelerator=' ' * 14 + 'Ctrl+N')
        self.file_menu.add_command(label='Open',
                                   command=self.open_file,
                                   accelerator=' ' * 14 + 'Ctrl+O')
        self.file_menu.add_command(label='Close',
                                   command=self.close_tab,
                                   accelerator=' ' * 14 + 'Ctrl+W')
        self.file_menu.add_separator()
        self.file_menu.add_command(label='Save',
                                   command=self.save_file,
                                   accelerator=' ' * 14 + 'Ctrl+S')
        self.file_menu.add_command(label='Save As',
                                   command=self.save_as_file,
                                   accelerator='    Ctrl+Shift+S')
        self.file_menu.add_separator()
        self.file_menu.add_command(label='Exit',
                                   command=self.quit_from_app,
                                   accelerator=' ' * 14 + 'Ctrl+Q')

        self.edit_menu_btn = Menubutton(self.menubar)
        self.edit_menu_btn.config(text='Edit',
                                  fg='#eeeeee',
                                  bg='#444444',
                                  activebackground='#647899',
                                  activeforeground='#eeeeee',
                                  underline=0)
        self.edit_menu_btn.pack(side=LEFT)
        self.edit_menu = Menu(self.edit_menu_btn, tearoff=0)
        self.edit_menu_btn['menu'] = self.edit_menu
        self.edit_menu.config(fg='#eeeeee',
                              activeforeground='#eeeeee',
                              bg='#444444',
                              activebackground='#647899')
        self.edit_menu.add_command(label='Undo',
                                   command=self.undo,
                                   accelerator=' ' * 10 + 'Ctrl+Z')
        self.edit_menu.add_command(label='Redo',
                                   command=self.redo,
                                   accelerator='Ctrl+Shift+Z')
        self.edit_menu.add_separator()
        self.edit_menu.add_command(label='Cut',
                                   command=self.cut_text,
                                   accelerator=' ' * 10 + 'Ctrl+X')
        self.edit_menu.add_command(label='Copy',
                                   command=self.copy_text,
                                   accelerator=' ' * 10 + 'Ctrl+C')
        self.edit_menu.add_command(label='Paste',
                                   command=self.paste_text,
                                   accelerator=' ' * 10 + 'Ctrl+V')
        self.edit_menu.add_command(label='Delete', command=self.del_text)
        self.edit_menu.add_separator()
        self.edit_menu.add_command(label='Select All',
                                   command=self.select_all,
                                   accelerator=' ' * 10 + 'Ctrl+A')

        self.help_menu_btn = Menubutton(self.menubar)
        self.help_menu_btn.config(text='Help',
                                  fg='#eeeeee',
                                  bg='#444444',
                                  activeforeground='#eeeeee',
                                  activebackground='#647899',
                                  underline=0)
        self.help_menu_btn.pack(side=LEFT)
        self.help_menu = Menu(self.help_menu_btn, tearoff=0)
        self.help_menu_btn['menu'] = self.help_menu
        self.help_menu.config(fg='#eeeeee',
                              activeforeground='#eeeeee',
                              bg='#444444',
                              activebackground='#647899')
        self.help_menu.add_command(label='About', command=self.show_about)

        self.file_tool_frm = Frame(self.toolbar)
        self.file_tool_frm.config(bg='#444444', bd=0, relief=FLAT, padx=4)
        self.file_tool_frm.pack(side=LEFT)

        self.edit_tool_frm = Frame(self.toolbar)
        self.edit_tool_frm.config(bg='#444444', bd=0, relief=FLAT, padx=12)
        self.edit_tool_frm.pack(side=LEFT)

        self.hint_lbl = Label(self.toolbar)
        self.hint_lbl.config(bg='#444444',
                             fg='#eeeeee',
                             font=('Sans', '10', 'italic'),
                             bd=0,
                             relief=FLAT,
                             padx=12)
        self.hint_lbl.pack(side=LEFT)

        self.new_btn = Button(self.file_tool_frm)
        self.new_btn.config(text='\u2795',
                            font=('Sans', '12'),
                            fg='#eeeeee',
                            bg='#333333',
                            bd=0,
                            activebackground='#555555',
                            activeforeground='#ffffff',
                            padx=4,
                            pady=0,
                            command=self.create_new_doc)
        self.new_btn.grid(row=0, column=0)
        self.new_btn.bind('<Enter>',
                          lambda x: self.hint_lbl.config(text='New'))
        self.new_btn.bind('<Leave>', lambda x: self.hint_lbl.config(text=''))

        self.open_btn = Button(self.file_tool_frm)
        self.open_btn.config(text='\u21e9',
                             font=('Sans', '12', 'bold'),
                             fg='#eeeeee',
                             bg='#333333',
                             bd=0,
                             activebackground='#555555',
                             activeforeground='#ffffff',
                             padx=4,
                             pady=0,
                             command=self.open_file)
        self.open_btn.grid(row=0, column=1, padx=20)
        self.open_btn.bind('<Enter>',
                           lambda x: self.hint_lbl.config(text='Open'))
        self.open_btn.bind('<Leave>', lambda x: self.hint_lbl.config(text=''))

        self.save_btn = Button(self.file_tool_frm)
        self.save_btn.config(text='\u21e7',
                             font=('Sans', '12', 'bold'),
                             fg='#eeeeee',
                             bg='#333333',
                             bd=0,
                             activebackground='#555555',
                             activeforeground='#ffffff',
                             padx=4,
                             pady=0,
                             state=DISABLED,
                             command=self.save_file)
        self.save_btn.grid(row=0, column=2, padx=0)
        self.save_btn.bind('<Enter>',
                           lambda x: self.hint_lbl.config(text='Save'))
        self.save_btn.bind('<Leave>', lambda x: self.hint_lbl.config(text=''))
        self.save_btn.bind('<Motion>', self.save_btn_handler)

        self.close_btn = Button(self.file_tool_frm)
        self.close_btn.config(text='\u2717',
                              font=('Sans', '12', 'bold'),
                              fg='#eeeeee',
                              bg='#333333',
                              bd=0,
                              activebackground='#555555',
                              activeforeground='#ffffff',
                              padx=4,
                              pady=0,
                              command=self.close_tab)
        self.close_btn.grid(row=0, column=3, padx=20)
        self.close_btn.bind('<Enter>',
                            lambda x: self.hint_lbl.config(text='Close'))
        self.close_btn.bind('<Leave>', lambda x: self.hint_lbl.config(text=''))

        self.undo_btn = Button(self.edit_tool_frm)
        self.undo_btn.config(text='\u21b6',
                             font=('Sans', '12'),
                             fg='#eeeeee',
                             bg='#333333',
                             bd=0,
                             activebackground='#555555',
                             activeforeground='#ffffff',
                             padx=4,
                             pady=0,
                             command=self.undo)
        self.undo_btn.grid(row=0, column=0)
        self.undo_btn.bind('<Enter>',
                           lambda x: self.hint_lbl.config(text='Undo'))
        self.undo_btn.bind('<Leave>', lambda x: self.hint_lbl.config(text=''))

        self.redo_btn = Button(self.edit_tool_frm)
        self.redo_btn.config(text='\u21b7',
                             font=('Sans', '12'),
                             fg='#eeeeee',
                             bg='#333333',
                             bd=0,
                             activebackground='#555555',
                             activeforeground='#ffffff',
                             padx=4,
                             pady=0,
                             command=self.redo)
        self.redo_btn.grid(row=0, column=1, padx=20)
        self.redo_btn.bind('<Enter>',
                           lambda x: self.hint_lbl.config(text='Redo'))
        self.redo_btn.bind('<Leave>', lambda x: self.hint_lbl.config(text=''))

        self.quit_btn = Button(self.toolbar)
        self.quit_btn.config(text='Quit',
                             font=('Sans', '10'),
                             fg='#eeeeee',
                             bg='#333333',
                             activebackground='#647899',
                             activeforeground='#ffffff',
                             bd=0,
                             padx=4,
                             pady=2,
                             command=self.quit_from_app)
        self.quit_btn.pack(side=RIGHT)

        self.statusbar_col_lbl = Label(self.statusbar)
        self.statusbar_col_lbl.config(text='col: 1',
                                      fg='#ffffff',
                                      bg='#222222',
                                      activeforeground='#ffffff',
                                      activebackground='#222222',
                                      bd=0,
                                      font=('Sans', '11', 'italic'),
                                      padx=10)
        self.statusbar_col_lbl.pack(side=RIGHT)

        self.statusbar_line_lbl = Label(self.statusbar)
        self.statusbar_line_lbl.config(text='ln: 1',
                                       fg='#ffffff',
                                       bg='#222222',
                                       bd=0,
                                       padx=10,
                                       activeforeground='#ffffff',
                                       activebackground='#222222',
                                       font=('Sans', '11', 'italic'))
        self.statusbar_line_lbl.pack(side=RIGHT)

        self.tab = self.TextFrameTab(self)

        # Create the '<<StateChecking>>' virtual event
        self.event_add('<<StateChecking>>', '<Any-KeyPress>',
                       '<Any-KeyRelease>', '<Any-ButtonRelease>', '<FocusIn>',
                       '<FocusOut>')

        # Create event bindings for keyboard shortcuts
        self.bind_all('<Control-n>', self.create_new_doc)
        self.bind_all('<Control-o>', self.open_file)
        self.bind_all('<Control-w>', self.close_tab)
        self.bind_all('<Control-s>', self.save_file)
        self.bind_all('<Control-Shift-S>', self.save_as_file)
        self.bind_all('<Control-q>', self.quit_from_app)
        self.bind_all('<Control-a>', self.select_all)
        if sys.platform.startswith('win32'):
            self.bind_all('<Control-Shift-Z>', self.redo)

    def save_btn_handler(self, event):
        try:
            textwidget = self.focus_lastfor()
            current_index = self.notebook.index('current')
            if textwidget.edit_modified():
                self.save_btn.config(state=NORMAL)
                # Add an asterisk to the header of the tab
                self.notebook.tab(current_index,
                                  text='*' + self.filenames[current_index])
            else:
                self.save_btn.config(state=DISABLED)
                # If there is an asterisk at the header of the tab,
                # remove it
                self.notebook.tab(current_index,
                                  text=self.filenames[current_index])
        except TclError:
            pass

    def show_progress(self, proc, fpath):
        """
        Shows a message on the status bar about saving or downloading
        process
        """
        label = Label(self.statusbar)
        msg = "{} {}... ".format(proc, fpath)
        label.config(text=msg,
                     fg='#ffffff',
                     bg='#222222',
                     bd=0,
                     font=('Sans', '9', 'italic'))
        label.pack(side=LEFT)

        timer = threading.Timer(3.0, label.destroy)
        timer.start()

    def create_new_doc(self, event=None):
        # 'event' is the '<Control-n>' probable event
        self.filenames.append('Untitled')
        self.TextFrameTab(self)

    def open_file(self, event=None):
        # If there is the '<Control-o>' event
        if event:
            textwidget = self.focus_lastfor()
            textwidget.edit_modified(arg=False)
        filepath = askopenfilename(filetypes=(('All files', '*'), ))
        if filepath:
            p = Path(filepath)
            filename = p.parts[-1]
            try:
                with open(filepath) as file:
                    if self.notebook.index('end') > 0:
                        textwidget = self.focus_lastfor()
                        modified = textwidget.edit_modified()
                        current_index = self.notebook.index('current')
                        if (self.filenames[current_index] == 'Untitled'
                                and not modified):
                            self.filepaths[current_index] = filepath
                            self.filenames[current_index] = filename
                            textwidget.insert(1.0, file.read())
                            textwidget.edit_modified(arg=False)
                            self.notebook.tab('current', text=filename)
                        else:
                            self.filepaths[current_index + 1] = filepath
                            self.filenames.append(filename)
                            tab = self.TextFrameTab(self)
                            tab.text.insert(1.0, file.read())
                            tab.text.edit_modified(arg=False)
                            self.notebook.tab('current', text=filename)
                    else:
                        self.filenames.append(filename)
                        tab = self.TextFrameTab(self)
                        tab.text.insert(1.0, file.read())
                        tab.text.edit_modified(arg=False)
                        self.notebook.tab(0, text=filename)
                        self.filepaths[0] = filepath
            except UnicodeDecodeError:
                msg = "Unknown encoding!".format(filename)
                showerror(message=msg)
                self.close_tab()
                self.create_new_doc()
            thread = threading.Thread(target=self.show_progress,
                                      args=('Downloading', filepath))
            thread.start()

    def close_tab(self, event=None):
        # 'event' is the '<Control-w>' probable event
        def close(obj):
            try:
                current_index = self.notebook.index('current')
                del obj.filenames[current_index]
                del obj.textwidgets[current_index]
                if current_index in obj.filepaths:
                    del obj.filepaths[current_index]
                obj.notebook.forget(current_index)
            except TclError:
                pass

        if self.notebook.index('end') > 0:
            textwidget = self.focus_lastfor()
            modified = textwidget.edit_modified()
            if modified:
                curr_index = self.notebook.index('current')
                msg = "'{}' has been modified. Do you want " \
                      "to save changes?".format(self.filenames[curr_index])
                msgbox = Message(type=YESNOCANCEL, message=msg, icon=QUESTION)
                answer = msgbox.show()
                if answer == YES:
                    self.save_file()
                    close(self)
                elif answer == NO:
                    close(self)
            else:
                close(self)

    def save_file(self, event=None):
        # 'event' is the '<Control-s>' probable event
        if self.notebook.index('end') > 0:
            current_index = self.notebook.index('current')
            if current_index in self.filepaths:
                filepath = self.filepaths[current_index]
                textwidget = self.focus_lastfor()
                text = textwidget.get(1.0, END)
                with open(filepath, 'w') as file:
                    file.write(text)
                self.file_menu.entryconfigure(4, state=DISABLED)
                textwidget.edit_modified(arg=False)
                thread = threading.Thread(target=self.show_progress,
                                          args=('Saving', filepath))
                thread.start()
            else:
                self.save_as_file()

    def save_as_file(self, event=None):
        # 'event' is the '<Control-Shift-S>' probable event
        if self.notebook.index('end') > 0:
            filepath = asksaveasfilename()
            if filepath:
                p = Path(filepath)
                filename = p.parts[-1]
                current_index = self.notebook.index('current')
                self.filepaths[current_index] = filepath
                self.notebook.tab('current', text=filename)
                self.filenames[current_index] = filename
                textwidget = self.focus_lastfor()
                text = textwidget.get(1.0, END)
                with open(filepath, 'w') as file:
                    file.write(text)
                self.file_menu.entryconfigure(4, state=DISABLED)
                textwidget.edit_modified(arg=False)
                thread = threading.Thread(target=self.show_progress,
                                          args=('Saving', filepath))
                thread.start()

    def undo(self):
        try:
            textwidget = self.focus_lastfor()
            textwidget.edit_undo()
        except TclError:
            pass

    def redo(self, event=None):
        # 'event' is the '<Control-Shift-Z>' probable event for Windows
        try:
            textwidget = self.focus_lastfor()
            textwidget.edit_redo()
        except TclError:
            pass

    def cut_text(self):
        try:
            textwidget = self.focus_lastfor()
            text = textwidget.get(SEL_FIRST, SEL_LAST)
            textwidget.delete(SEL_FIRST, SEL_LAST)
            textwidget.clipboard_clear()
            textwidget.clipboard_append(text)
        except TclError:
            pass

    def copy_text(self):
        try:
            textwidget = self.focus_lastfor()
            text = textwidget.get(SEL_FIRST, SEL_LAST)
            textwidget.clipboard_clear()
            textwidget.clipboard_append(text)
        except TclError:
            pass

    def paste_text(self):
        try:
            textwidget = self.focus_lastfor()
            text = textwidget.selection_get(selection='CLIPBOARD')
            textwidget.insert(INSERT, text)
        except TclError:
            pass

    def del_text(self):
        try:
            textwidget = self.focus_lastfor()
            textwidget.delete(SEL_FIRST, SEL_LAST)
        except TclError:
            pass

    def select_all(self, event=None):
        # 'event' is the '<Control-a>' probable event
        textwidget = self.focus_lastfor()
        textwidget.tag_add(SEL, 1.0, END)

    def show_about(self):
        txt_0 = "PyTEd 0.1.0"
        txt_1 = "PyTEd is a simple text editor based\n" \
                "on the tkinter interface"
        txt_2 = "Copyright " + '\u00a9' + " 2019 Eugene Kapshuk"
        txt_3 = "Source code: "
        txt_4 = "https://github.com/eukap/pyted"
        txt_5 = "License: MIT"
        window = Toplevel()
        window.title('About PyTEd')
        window.geometry('350x280')
        window.transient(self)
        window.resizable(width=False, height=False)

        label_0 = Label(window)
        label_0.config(fg='#000000',
                       bg='#ddddd8',
                       text=txt_0,
                       font=('Sans', '12', 'bold'),
                       justify=CENTER,
                       pady=10)
        label_0.pack(side=TOP, fill=X)

        label_1 = Label(window)
        label_1.config(fg='#000000',
                       bg='#ddddd8',
                       text=txt_1,
                       font=('Sans', '11', 'normal'),
                       justify=CENTER,
                       pady=10)
        label_1.pack(side=TOP, fill=X)

        label_2 = Label(window)
        label_2.config(fg='#000000',
                       bg='#ddddd8',
                       text=txt_2,
                       font=('Sans', '11', 'normal'),
                       justify=CENTER,
                       pady=10)
        label_2.pack(side=TOP, fill=X)

        frame_0 = Frame(window)
        frame_0.config(bg='#ddddd8', bd=0, relief=FLAT, padx=2, pady=2)
        frame_0.pack(side=TOP, fill=X)

        label_3 = Label(frame_0)
        label_3.config(fg='#000000',
                       bg='#ddddd8',
                       text=txt_3,
                       font=('Sans', '11', 'normal'),
                       justify=CENTER,
                       padx=2,
                       pady=10)
        label_3.pack(side=LEFT, fill=X)

        label_4 = Label(frame_0)
        label_4.config(fg='#1111cc',
                       bg='#ddddd8',
                       text=txt_4,
                       font=('Sans', '11', 'normal'),
                       cursor='hand1',
                       justify=CENTER,
                       padx=4,
                       pady=0)
        label_4.pack(side=LEFT, fill=X)
        label_4.bind(
            '<Button-1>', lambda x: webbrowser.open_new_tab(
                'https://github.com/eukap/pyted'))

        label_5 = Label(window)
        label_5.config(fg='#000000',
                       bg='#ddddd8',
                       text=txt_5,
                       font=('Sans', '11', 'normal'),
                       justify=CENTER,
                       pady=8)
        label_5.pack(side=TOP, fill=X)

        frame_1 = Frame(window)
        frame_1.config(bg='#ddddd8', bd=0, relief=FLAT, padx=0, pady=12)
        frame_1.pack(side=BOTTOM, fill=BOTH, expand=YES)

        btn = Button(frame_1)
        btn.config(text='Close',
                   fg='#000000',
                   bg='#efefef',
                   activeforeground='#000000',
                   activebackground='#e9e9e9',
                   font=('Sans', '10', 'normal'),
                   command=window.destroy)
        btn.pack(side=TOP)

    def quit_from_app(self, event=None):
        # 'event' is the '<Control-q>' probable event
        modified = False
        for widget in self.textwidgets:
            if widget.edit_modified():
                modified = True
                break
        if modified:
            msg = "Some changes haven't been saved. " \
                  "Do you really want to exit?"
            msgbox = Message(type=YESNO, message=msg, icon=QUESTION)
            answer = msgbox.show()
            if answer == YES:
                self.quit()
        else:
            self.quit()
예제 #12
0
class App(Tk):

    def __init__(self, args):
        Tk.__init__(self)
        self.height = '720'
        self.width = '1280'
        self.Editors = []
        self.Filenames = {}
        self.lexer_selector = self.createLexers()
        self.Lexers = dict()
        self._icon = Image("photo", file='img/notebook/icon.png')

        self.code_font = Font(family="Latin Modern Mono", size=15)
        self.title_font = Font(family="Ubuntu Mono", size=15)
        self.underline_font = Font(underline=True)

        self.MainWindow = Frame(self, background='#282c34')
        self.notebook = Notebook(self)
        self.configureUI()
        self.args = args

        self.awk_img = PhotoImage(file='img/fext/awk.png')
        self.bash_img = PhotoImage(file='img/fext/bash.png')
        self.c_img = PhotoImage(file='img/fext/c.png')
        self.cs_img = PhotoImage(file='img/fext/c#.png')
        self.cmake_img = PhotoImage(file='img/fext/cmake.png')
        self.coffee_img = PhotoImage(file='img/fext/coffee.png')
        self.cpp_img = PhotoImage(file='img/fext/cpp.png')
        self.css_img = PhotoImage(file='img/fext/css.png')
        self.delphi_img = PhotoImage(file='img/fext/delphi.png')
        self.eiffel_img = PhotoImage(file='img/fext/eiffel.png')
        self.erlang_img = PhotoImage(file='img/fext/erlang.png')
        self.fs_img = PhotoImage(file='img/fext/f#.png')
        self.fortran_img = PhotoImage(file='img/fext/fortran.png')
        self.go_img = PhotoImage(file='img/fext/golang.png')
        self.haskell_img = PhotoImage(file='img/fext/haskell.png')
        self.html_img = PhotoImage(file='img/fext/html.png')
        self.java_img = PhotoImage(file='img/fext/java.png')
        self.js_img = PhotoImage(file='img/fext/js.png')
        self.json_img = PhotoImage(file='img/fext/json.png')
        self.kotlin_img = PhotoImage(file='img/fext/kotlin.png')
        self.lisp_img = PhotoImage(file='img/fext/lisp.png')
        self.makefile_img = PhotoImage(file='img/fext/makefile.png')
        self.matlab_img = PhotoImage(file='img/fext/matlab.png')
        self.mysql_img = PhotoImage(file='img/fext/mysql.png')
        self.perl_img = PhotoImage(file='img/fext/perl.png')
        self.php_img = PhotoImage(file='img/fext/php.png')
        self.prolog_img = PhotoImage(file='img/fext/prolog.png')
        self.python_img = PhotoImage(file='img/fext/python.png')
        self.ruby_img = PhotoImage(file='img/fext/ruby.png')
        self.sass_img = PhotoImage(file='img/fext/sass.png')
        self.scala_img = PhotoImage(file='img/fext/scala.png')
        self.swift_img = PhotoImage(file='img/fext/swift.png')
        self.tcl_img = PhotoImage(file='img/fext/tcl.png')
        self.ts_img = PhotoImage(file='img/fext/ts.png')
        self.txt_img = PhotoImage(file='img/fext/txt.png')
        self.verilog_img = PhotoImage(file='img/fext/verilog.png')
        self.vhdl_img = PhotoImage(file='img/fext/vhdl.png')
        self.xml_img = PhotoImage(file='img/fext/xml.png')
        self.yaml_img = PhotoImage(file='img/fext/yaml.png')

        for file_name in self.args:
            self.openFileByName(file_name)

        self.mainloop()

    def configureUI(self):

        self.configureWindow()
        self.configureMenu()
        self.configureNotebook()
        self.contextualMenu()
        self.bindWindowEvents()
        self.configureStatusBar()

    def configureWindow(self):

        self.geometry(self.width+'x'+self.height+'+0+0')
        self.title("Quode-IDE")
        self.wm_iconphoto(False, self._icon)
        self.MainWindow.pack()

    def configureMenu(self):

        self.menu_bar = Menu(self, background='#21252b', foreground='#ffffff')
        self.file_menu = Menu(self.menu_bar, tearoff=0)
        self.file_menu.add_command(label='New Tab',
                                font=self.title_font,
                                command=self.createNewEditor,
                                activebackground='#123456',
                                activeforeground='#ffffff',
                                accelerator='Ctrl + N')
        self.file_menu.add_command(label="Open",
                                font=self.title_font,
                                command=self.openFile,
                                activebackground='#123456',
                                activeforeground='#ffffff',
                                accelerator='Ctrl + O')
        self.file_menu.add_command(label="Save",
                                font=self.title_font,
                                command=self.saveFile,
                                activebackground='#123456',
                                activeforeground='#ffffff',
                                accelerator='Ctrl + S')
        self.file_menu.add_command(label='Remove Tab',
                                font=self.title_font,
                                command=self.removeCurrentEditor,
                                activebackground='#123456',
                                activeforeground='#ffffff',
                                accelerator='Ctrl + R')
        self.file_menu.add_separator()
        self.file_menu.add_command(label="Exit",
                                font=self.title_font,
                                command=self.askQuit,
                                activebackground='#123456',
                                activeforeground='#ffffff',
                                accelerator='Ctrl + Q')
        self.menu_bar.add_cascade(label="File",
                                font=self.title_font,
                                activebackground='#123456',
                                activeforeground='#ffffff',
                                menu=self.file_menu)

        self.edit_menu = Menu(self.menu_bar,
                                tearoff=0,
                                activebackground='#123456')
        self.edit_menu.add_command(label="Cut",
                                font=self.title_font,
                                command=self.cutSelection,
                                activebackground='#123456',
                                activeforeground='#ffffff',
                                accelerator="Ctrl + X")
        self.edit_menu.add_command(label="Copy",
                                font=self.title_font,
                                command=self.copySelection,
                                activebackground='#123456',
                                activeforeground='#ffffff',
                                accelerator="Ctrl + C")
        self.edit_menu.add_command(label="Paste",
                                font=self.title_font,
                                command=self.pasteSelection,
                                activebackground='#123456',
                                activeforeground='#ffffff',
                                accelerator="Ctrl + V")
        self.edit_menu.add_command(label="Replace (All)",
                                font=self.title_font,
                                activebackground='#123456',
                                activeforeground='#ffffff',
                                command=self.replaceAllWindow)
        self.menu_bar.add_cascade(label="Edit",
                                font=self.title_font,
                                activebackground='#123456',
                                activeforeground='#ffffff',
                                menu=self.edit_menu)

        self.view_menu = Menu(self.menu_bar, tearoff=0)
        self.view_menu.add_command(label="Increase Font Size",
                                font=self.title_font,
                                command=self.increaseFontSize,
                                activebackground='#123456',
                                activeforeground='#ffffff',
                                accelerator="Ctrl + +/=")
        self.view_menu.add_command(label="Decrease Font Size",
                                font=self.title_font,
                                command=self.decreaseFontSize,
                                activebackground='#123456',
                                activeforeground='#ffffff',
                                accelerator="Ctrl + -/_")
        self.view_menu.add_command(label="Find",
                                font=self.title_font,
                                command=self.searchWindow,
                                activebackground='#123456',
                                activeforeground='#ffffff',
                                accelerator="Ctrl + f")
        self.view_menu.add_command(label="File tree",
                                font=self.title_font,
                                command=self.showFileTree,
                                activebackground='#123456',
                                activeforeground='#ffffff',
                                accelerator="Ctrl + t")
        self.menu_bar.add_cascade(label="View",
                                font=self.title_font,
                                activebackground='#123456',
                                activeforeground='#ffffff',
                                menu=self.view_menu)

        self.run_menu = Menu(self.menu_bar, tearoff=0)
        self.run_menu.add_command(label='Run',
                                activebackground='#123456',
                                activeforeground='#ffffff',
                                command=self.runCurrentEditor,
                                font=self.title_font)
        self.menu_bar.add_cascade(label='Run',
                                activebackground='#123456',
                                activeforeground='#ffffff',
                                font=self.title_font,
                                menu=self.run_menu)

        self.help_menu = Menu(self.menu_bar, tearoff=0)
        self.help_menu.add_command(label="About",
                                activebackground='#123456',
                                activeforeground='#ffffff',
                                font=self.title_font,
                                command=self.printAbout)
        self.menu_bar.add_cascade(label="Help",
                                font=self.title_font,
                                activebackground='#123456',
                                activeforeground='#ffffff',
                                menu=self.help_menu)
        self.config(menu=self.menu_bar)

    def configureNotebook(self):

        self.notebook.place_configure(relx=0, rely=0, relheight=0.97, relwidth=1)
        self.notebook.enable_traversal()

    def configureStatusBar(self):

        self.status_bar_label = Label(self)
        self.status_bar_label.place_configure(relx=0,
                                            rely=0.97,
                                            relheight=0.03,
                                            relwidth=1)
        self.status_bar_label.config(text=self.getStatusText())


    def langImg(self, ext):

        img = None
        if (ext == '.c'): img = self.c_img
        elif(ext == '.h'): img = self.c_img
        elif(ext == '.cpp'): img = self.cpp_img
        elif(ext == '.hpp'): img = self.cpp_img
        elif(ext == '.css'): img = self.css_img
        elif(ext == '.sass'): img = self.sass_img
        elif(ext == '.yaml'): img = self.yaml_img
        elif(ext == '.yml'): img = self.yaml_img
        elif(ext == '.json'): img = self.json_img
        elif(ext == '.cs'): img = self.cs_img
        elif(ext == '.fs'): img = self.fs_img
        elif(ext == '.e'): img = self.eiffel_img
        elif(ext == '.erl'): img = self.erlang_img
        elif(ext == '.hrl'): img = self.erlang_img
        elif(ext == '.es'): img = self.erlang_img
        elif(ext == '.f03'): img = self.fortran_img
        elif(ext == '.f90'): img = self.fortran_img
        elif(ext == '.F03'): img = self.fortran_img
        elif(ext == '.F90'): img = self.fortran_img
        elif(ext == '.go'): img = self.go_img
        elif(ext == '.hs'): img = self.haskell_img
        elif(ext == '.v'): img = self.verilog_img
        elif(ext == '.vhdl'): img = self.vhdl_img
        elif(ext == '.vhd'): img = self.vhdl_img
        elif(ext == '.html'): img = self.html_img
        elif(ext == '.htm'): img = self.html_img
        elif(ext == '.xhtml'): img = self.html_img
        elif(ext == '.xml'): img = self.xml_img
        elif(ext == '.js'): img = self.js_img
        elif(ext == '.tex'): img = self.ts_img
        elif(ext == '.coffee'): img = self.coffee_img
        elif(ext == '.java'): img = self.java_img
        elif(ext == '.scala'): img = self.scala_img
        elif(ext == '.kt'): img = self.kotlin_img
        elif(ext == '.ktm'): img = self.kotlin_img
        elif(ext == '.kts'): img = self.kotlin_img
        elif(ext == '.lisp'): img = self.lisp_img
        elif(ext == 'make'): img = self.makefile_img
        elif(ext == 'Make'): img = self.makefile_img
        elif(ext == 'cmake'): img = self.cmake_img
        elif(ext == 'CMake'): img = self.cmake_img
        elif(ext == '.m'): img = self.matlab_img
        elif(ext == '.mat'): img = self.matlab_img
        elif(ext == '.dpr'): img = self.delphi_img
        elif(ext == '.perl'): img = self.perl_img
        elif(ext == '.php'): img = self.php_img
        elif(ext == '.pr'): img = self.prolog_img
        elif(ext == '.py'): img = self.python_img
        elif(ext == '.rb'): img = self.ruby_img
        elif(ext == '.sh'): img = self.bash_img
        elif(ext == '.sql'): img = self.mysql_img
        elif(ext == '.mysql'): img = self.mysql_img
        elif(ext == '.tcl'): img = self.tcl_img
        elif(ext == '.awk'): img = self.awk_img
        else: img = self.txt_img

        return img

    def _get_current_editor(self):
        try:
            index = self.notebook.index('current')
            curr_editor = self.Editors[index]

            return curr_editor

        except _tkinter.TclError:
            messagebox.showerror('Error', 'No Editors Opened!!')
            return None

    def createNewEditor(self):

        new_tab_name = askstring('New Tab', 'Enter name of new tab')
        if new_tab_name:
            f_name, ext = os.path.splitext(new_tab_name)
            scrolled_text = ScrolledText(font=self.code_font,
                                        undo=True, tabs=('2c'),
                                        background='#282c34',
                                        insertbackground='#ffffff',
                                        foreground='#abb2a4')

            self.Editors.append(scrolled_text)
            self.Filenames[scrolled_text] = None
            try :
                lexer = self.lexer_selector[ext]
            except KeyError:
                lexer = None
            self.Lexers[scrolled_text] = lexer
            self.notebook.add(scrolled_text,
                            image=self.langImg(ext),
                            text=os.path.split(new_tab_name)[1],
                            compound='left')
            self.notebook.select(scrolled_text)
            self.createTags()
            self.recolorize(None)
            self.setStatusText(self.getStatusText())

            self.miscBindings(scrolled_text)
            scrolled_text.focus_set()
            scrolled_text.edit_reset()

    def openFile(self):

        opened_file_name = fd.askopenfilename(initialdir=".",
                                              title="Select file",
                                              filetypes=(('all files', '*.*'),))
        if not isinstance(opened_file_name, tuple):
            ext = os.path.splitext(opened_file_name)[1]
            scrolled_text = ScrolledText(font=self.code_font,
                                        undo=True, tabs=('2c'),
                                        background='#282c34',
                                        insertbackground='#ffffff',
                                        foreground='#abb2a4')
            self.Editors.append(scrolled_text)
            self.Filenames[scrolled_text] = opened_file_name
            self.notebook.add(scrolled_text,
                                image=self.langImg(ext),
                                text=os.path.split(opened_file_name)[1],
                                compound='left')
            with open(opened_file_name) as f:
                file_text = f.read()
                f.close()
                scrolled_text.insert('end', file_text)

            self.notebook.select(scrolled_text)
            try :
                lexer = self.lexer_selector[ext]
            except KeyError:
                lexer = None
            self.Lexers[scrolled_text] = lexer
            self.createTags()
            self.recolorize(None)
            scrolled_text.focus_set()
            scrolled_text.edit_reset()
            self.miscBindings(scrolled_text)
            self.setStatusText(self.getStatusText())

    def openFileByName(self, path):

        opened_file_name = path
        if opened_file_name[0] != '/':
            opened_file_name  = os.path.dirname(os.path.abspath(__file__)) + '/' + path
        if not os.path.isdir(opened_file_name):
            ext = os.path.splitext(opened_file_name)[1]
            scrolled_text = ScrolledText(font=self.code_font,
                                        undo=True, tabs=('1.28c'),
                                        background='#282c34',
                                        insertbackground='#ffffff',
                                        foreground='#abb2a4')
            self.Editors.append(scrolled_text)
            self.Filenames[scrolled_text] = opened_file_name
            print(opened_file_name)
            self.notebook.add(scrolled_text,
                                image=self.langImg(ext),
                                text=os.path.split(opened_file_name)[1],
                                compound='left')
            with open(opened_file_name) as f:
                file_text = f.read()
                f.close()
                scrolled_text.insert('end', file_text)

            self.notebook.select(scrolled_text)
            try:
                lexer = self.lexer_selector[ext]
            except KeyError:
                lexer = None
            self.Lexers[scrolled_text] = lexer
            self.createTags()
            self.recolorize(None)
            scrolled_text.focus_set()
            scrolled_text.edit_reset()
            self.miscBindings(scrolled_text)
            self.setStatusText(self.getStatusText())

    def saveFile(self):
        try:
            editor_index = self.notebook.index('current')
            curr_editor = self.Editors[editor_index]
            curr_text = curr_editor.get("1.0", "end")
            if self.Filenames[curr_editor] is not None:
                with open(self.Filenames[curr_editor], 'r+') as f:
                    f.write(curr_text)
                    messagebox.showinfo('Save', 'File Saved!!!')
                    curr_editor.edit_reset()

            else:
                new_file_path = fd.asksaveasfilename(initialdir='.',
                                                filetypes=[("All files", "*")])
                if not isinstance(new_file_path, tuple):

                    self.Filenames[curr_editor] = new_file_path
                    new_file = open(new_file_path, 'w+')
                    new_file.close()

                    new_file = open(new_file_path, 'r+')
                    new_file.write(curr_text)
                    messagebox.showinfo('Save', 'File Saved!!!')
                    self.Filenames[curr_editor] = new_file_path
                    curr_editor.edit_reset()

        except _tkinter.TclError:
            messagebox.showerror("Save File", "No file to save")

    def removeCurrentEditor(self):

        try:
            curr_editor = self._get_current_editor()
            if messagebox.askyesno('Remove Current Tab',
                                'Are you sure you want to remove this Editor?',
                                icon='warning'):
                index = self.notebook.select('current')
                self.notebook.forget(index)
                self.Editors.remove(curr_editor)
                self.Filenames.pop(curr_editor, None)
                self.Lexers.pop(curr_editor, None)

        except _tkinter.TclError:
            messagebox.showerror('Remove Tab', 'Oops!! No tabs to remove!!')


    def askQuit(self):

        if messagebox.askyesno('Remove Current Tab',
                            'Do you really wanna Exit?',
                            icon='warning'):
            self.destroy()

    def bindWindowEvents(self):

        self.bind('<Control-n>', func=lambda e:self.createNewEditor())
        self.bind('<Control-o>', func=lambda e:self.openFile())
        self.bind('<Control-s>', func=lambda e:self.saveFile())
        self.bind('<Control-r>', func=lambda e:self.removeCurrentEditor())
        self.bind('<Control-q>', func=lambda e:self.askQuit())
        self.bind('<Control-x>', func=lambda e:self.cutSelection())
        self.bind('<Control-c>', func=lambda e:self.copySelection())
        self.bind('<Control-v>', func=lambda e:self.pasteSelection())
        self.bind('<Control-a>', func=lambda e:self.selectAll())
        self.bind('<Control-f>', func=lambda e:self.searchWindow())
        self.bind('<Control-z>', func=lambda e:self.undoChange())
        self.bind('<Control-y>', func=lambda e:self.redoChange())
        self.bind('<Control-t>', func=lambda e:self.showFileTree())

        self.bind('<Control-N>', func=lambda e:self.createNewEditor())
        self.bind('<Control-O>', func=lambda e:self.openFile())
        self.bind('<Control-S>', func=lambda e:self.saveFile())
        self.bind('<Control-R>', func=lambda e:self.removeCurrentEditor())
        self.bind('<Control-Q>', func=lambda e:self.askQuit())
        self.bind('<Control-X>', func=lambda e:self.cutSelection())
        self.bind('<Control-C>', func=lambda e:self.copySelection())
        self.bind('<Control-V>', func=lambda e:self.pasteSelection())
        self.bind('<Control-A>', func=lambda e:self.selectAll())
        self.bind('<Control-F>', func=lambda e:self.searchWindow())
        self.bind('<Control-Z>', func=lambda e:self.undoChange())
        self.bind('<Control-Y>', func=lambda e:self.redoChange())
        self.bind('<Control-T>', func=lambda e:self.showFileTree())

        self.bind('<Control-plus>', func=lambda e:self.increaseFontSize())
        self.bind('<Control-minus>', func=lambda e:self.decreaseFontSize())
        self.bind('<Control-KP_Add>', func=lambda e:self.increaseFontSize())
        self.bind('<Control-KP_Subtract>', func=lambda e:self.decreaseFontSize())

        self.bind("<Key>", func=lambda e:self.anyKeyBindings(e))
        # self.bind("<Key>", func=lambda e:self.setStatusText(self.getStatusText()))

        self.bind('<Button>', func=lambda e: self.anyButtonBindings(e))
        self.bind('<Button-3>',
                func=lambda e: self.contextual_menu.post(e.x_root, e.y_root))

    def anyKeyBindings(self, event):

        self.recolorize(None)
        self.setStatusText(self.getStatusText())

    def anyButtonBindings(self, event):

        self.contextual_menu.unpost()
        self.setStatusText(self.getStatusText())

    def cutSelection(self):

        curr_editor = self._get_current_editor()
        curr_editor.event_generate('<<Cut>>')

    def copySelection(self):

        curr_editor = self._get_current_editor()
        curr_editor.event_generate('<<Copy>>')

    def pasteSelection(self):

        curr_editor = self._get_current_editor()
        curr_editor.event_generate('<<Paste>>')

    def contextualMenu(self):

        self.contextual_menu = Menu(self, tearoff=False)

        self.contextual_menu.add_command(label='New Editor',
                                        command=self.createNewEditor)
        self.contextual_menu.add_command(label='Open File',
                                        command=self.openFile)
        self.contextual_menu.add_command(label='Save Editor',
                                        command=self.saveFile)
        self.contextual_menu.add_separator()
        self.contextual_menu.add_command(label='Remove Editor',
                                        command=self.removeCurrentEditor)
        self.contextual_menu.add_command(label='Change title',
                                        command=self.changeEditorTitle)

    def unpostContextMenu(self):

        self.contextual_menu.unpost()

    def changeEditorTitle(self):

        curr_editor = self._get_current_editor()
        new_title = askstring('New Editor', "Enter new title")
        new_ext = os.path.splitext(new_title)[1]
        self.notebook.tab(curr_editor,
                        text=new_title,
                        image=self.langImg(new_ext))
        try :
            new_lexer = self.lexer_selector[new_ext]
        except KeyError:
            new_lexer = None
        self.Lexers[curr_editor] = new_lexer
        self.recolorize(None)

    def increaseFontSize(self):

        curr_editor = self._get_current_editor() # FIXME
        curr_font = Font(curr_editor, curr_editor.cget("font"))
        curr_size = curr_font.cget('size')
        new_size = curr_size+1
        curr_font.configure(size=new_size)
        new_font = curr_font
        curr_editor.configure(font=new_font)

        # print(Font(curr_editor, curr_editor.cget("font")).cget("size"))

    def decreaseFontSize(self):

        curr_editor = self._get_current_editor() # FIXME
        curr_font = Font(curr_editor, curr_editor.cget("font"))
        curr_size = curr_font.cget('size')
        if curr_size > 1:
            new_size = curr_size-1
            curr_font.configure(size=new_size)

    def undoChange(self):
        try:

            curr_editor = self._get_current_editor()
            curr_editor.edit_undo()
            self.createTags()
            self.recolorize(None)
        except _tkinter.TclError:
            pass

    def redoChange(self):
        try:
            curr_editor = self._get_current_editor()
            curr_editor.edit_redo()
        except _tkinter.TclError:
            pass

    def selectAll(self):
        curr_editor = self._get_current_editor()
        curr_editor.tag_add('sel', '1.0', 'end')
        return "break"

    def searchWindow(self):

        self.search_window = SearchWindow(self, 0)

    def removeAllTags(self):

        curr_editor = self._get_current_editor()
        for tag in curr_editor.tag_names():
            curr_editor.tag_delete(tag)

    def replaceAllWindow(self):

        self.replace_window = ReplaceTextWindow(self)

    def replaceAll(self, a, b):

        curr_editor = self._get_current_editor()
        start = "1.0"
        text = curr_editor.get(start, "end")
        if curr_editor:
            pos = curr_editor.search(a, start, stopindex="end")

            while pos:
                length = len(text)
                row, col = pos.split('.')
                end = int(col) + length
                end = row + '.' + str(end)
                curr_editor.tag_add('found', pos, end)
                start = end
                pos = curr_editor.search(a, start, stopindex="end")
            replaced = 0
            if a:
                coordinates = []
                index_list = list(curr_editor.tag_ranges("found"))
                index_list.reverse()
                while index_list:
                    coordinates.append([index_list.pop(), index_list.pop()])
                for start, end in coordinates:
                    curr_editor.delete(start, end)
                    curr_editor.insert(start, b)
                    replaced += 1
                curr_editor.tag_delete("found")
                return replaced

    def createTags(self):
        curr_editor = self._get_current_editor()
        bold_font = Font(curr_editor, curr_editor.cget("font"))
        bold_font.configure(weight='bold')

        italic_font = Font(curr_editor, curr_editor.cget("font"))
        italic_font.configure(slant='italic')

        bold_italic_font = Font(curr_editor, curr_editor.cget("font"))
        bold_italic_font.configure(weight='bold', slant='italic')

        style = get_style_by_name('default')
        for ttype, ndef in style:
            tag_font = None
            if ndef['bold'] and ndef['italic']:
                tag_font = bold_italic_font
            elif ndef['bold']:
                tag_font = bold_font
            elif ndef['italic']:
                tag_font = italic_font

            if ndef['color']:
                foreground = "#%s" % ndef['color']
            else:
                foreground = None

            curr_editor.tag_configure(str(ttype),
                                    foreground=foreground,
                                    font=tag_font)

    def recolorize(self, event):

        if len(self.Editors) != 0:
            curr_editor = self._get_current_editor()
            code = curr_editor.get("1.0", "end-1c")
            lexer = self.Lexers[curr_editor]
            if lexer is not None:
                tokensource = lexer.get_tokens(text=code)
                start_line = 1
                start_index = 0
                end_line = 1
                end_index = 0
                for ttype, value in tokensource:
                    if "\n" in value:
                        end_line += value.count("\n")
                        end_index = len(value.rsplit("\n", 1)[1])
                    else:
                        end_index += len(value)

                    if value not in (" ", "\n"):
                        index1 = "%s.%s" % (start_line, start_index)
                        index2 = "%s.%s" % (end_line, end_index)

                        for tagname in curr_editor.tag_names(index1):
                            curr_editor.tag_remove(tagname, index1, index2)

                        curr_editor.tag_add(str(ttype), index1, index2)

                    start_line = end_line
                    start_index = end_index

            # self.underlineComplement()

    def createLexers(self):

        lex = {}
        lex['.c'] = CFamilyLexer()
        lex['.h'] = CFamilyLexer()
        lex['.cpp'] = CppLexer()
        lex['.hpp'] = CppLexer()
        lex['.css'] = CssLexer()
        lex['.sass'] = SassLexer()
        lex['.yaml'] = YamlLexer()
        lex['.yml'] = YamlLexer()
        lex['.json'] = JsonLexer()
        lex['.cs'] = CSharpLexer()
        lex['.fs'] = FSharpLexer()
        lex['.e'] = EiffelLexer()
        lex['.erl'] = ErlangLexer()
        lex['.hrl'] = ErlangLexer()
        lex['.es'] = ErlangLexer()
        lex['.f03'] = FortranLexer()
        lex['.f90'] = FortranLexer()
        lex['.F03'] = FortranLexer()
        lex['.F90'] = FortranLexer()
        lex['.go'] = GoLexer()
        lex['.hs'] = HaskellLexer()
        lex['.v'] = VerilogLexer()
        lex['.vhdl'] = VhdlLexer()
        lex['.vhd'] = VhdlLexer()
        lex['.html'] = HtmlLexer()
        lex['.htm'] = HtmlLexer()
        lex['.xhtml'] = HtmlLexer()
        lex['.xml'] = XmlLexer()
        lex['.js'] = JavascriptLexer()
        lex['.tex'] = TypeScriptLexer()
        lex['.coffee'] = CoffeeScriptLexer()
        lex['.java'] = JavaLexer()
        lex['.scala'] = ScalaLexer()
        lex['.kt'] = KotlinLexer()
        lex['.ktm'] = KotlinLexer()
        lex['.kts'] = KotlinLexer()
        lex['.lisp'] = CommonLispLexer()
        lex['make'] = MakefileLexer()
        lex['Make'] = MakefileLexer()
        lex['CMake'] = CMakeLexer()
        lex['cmake'] = CMakeLexer()
        lex['.m'] = MatlabLexer()
        lex['.mat'] = MatlabLexer()
        lex['.dpr'] = DelphiLexer()
        lex['.perl'] = PerlLexer()
        lex['.php'] = PhpLexer()
        lex['.pr'] = PrologLexer()
        lex['.py'] = Python3Lexer()
        lex['.rb'] = RubyLexer()
        lex['.sh'] = BashLexer()
        lex['.sql'] = MySqlLexer()
        lex['.mysql'] = MySqlLexer()
        lex['.tcl'] = TclLexer()
        lex['.awk'] = AwkLexer()

        return lex

    def getStatusText(self):

        if len(self.Editors):
            curr_editor = self._get_current_editor()
            cursor_position = curr_editor.index('insert')
            if cursor_position is not None:
                row, col = cursor_position.split('.')
                return "Row: %s Col: %s"%(row, col)
            else:
                return "Quode-IDE"
        else:
            return "Quode-IDE"

    def setStatusText(self, text):

        if len(self.Editors):
            self.status_bar_label.config(text=text)
        else:
            self.status_bar_label.config(text="Quode-IDE")

    def miscBindings(self, scrolled_text):

        scrolled_text.bind('<Control-z>', func=self.undoChange)
        scrolled_text.bind('<Control-y>', func=self.redoChange)
        scrolled_text.bind('<KeyRelease-quoteright>',
                           func=lambda e: self.completeQuoteright(scrolled_text))
        scrolled_text.bind('<KeyRelease-quotedbl>',
                           func=lambda e: self.completeQuotedbl(scrolled_text))
        scrolled_text.bind('<KeyRelease-parenleft>',
                           func=lambda e: self.completeParen(scrolled_text))
        scrolled_text.bind('<KeyRelease-bracketleft>',
                           func=lambda e: self.completeBracket(scrolled_text))
        scrolled_text.bind('<KeyRelease-braceleft>',
                           func=lambda e: self.completeBrace(scrolled_text))
        scrolled_text.bind('<KeyRelease-less>',
                           func=lambda e: self.completeAngles(scrolled_text))
        scrolled_text.bind('<KeyRelease-Return>',
                           func=lambda e: self.returnNewLine(scrolled_text))

        scrolled_text.bind('<parenright>',
                           func=lambda e: self.skipRParen(scrolled_text))
        scrolled_text.bind('<bracketright>',
                           func=lambda e: self.skipRBracket(scrolled_text))
        scrolled_text.bind('<braceright>',
                           func=lambda e: self.skipRBrace(scrolled_text))
        scrolled_text.bind('<greater>',
                           func=lambda e: self.skipRAngle(scrolled_text))
        scrolled_text.bind('<BackSpace>',
                           func=lambda e: self.erasePair(scrolled_text))

    def completeParen(self, scrolled_text):
        scrolled_text.mark_gravity('insert', 'left')
        scrolled_text.insert('insert', ')')
        scrolled_text.mark_gravity('insert', 'right')
        self.recolorize(None)

    def completeBracket(self, scrolled_text):

        scrolled_text.mark_gravity('insert', 'left')
        scrolled_text.insert('insert', ']')
        scrolled_text.mark_gravity('insert', 'right')
        self.recolorize(None)

    def completeBrace(self, scrolled_text):

        scrolled_text.mark_gravity('insert', 'left')
        scrolled_text.insert('insert', '}')
        scrolled_text.mark_gravity('insert', 'right')
        self.recolorize(None)

    def completeQuoteright(self, scrolled_text):

        scrolled_text.mark_gravity('insert', 'left')
        scrolled_text.insert('insert', '\'')
        scrolled_text.mark_gravity('insert', 'right')
        self.recolorize(None)

    def completeQuotedbl(self, scrolled_text):

        scrolled_text.mark_gravity('insert', 'left')
        scrolled_text.insert('insert', '"')
        scrolled_text.mark_gravity('insert', 'right')
        self.recolorize(None)

    def completeAngles(self, scrolled_text):

        scrolled_text.mark_gravity('insert', 'left')
        scrolled_text.insert('insert', '>')
        scrolled_text.mark_gravity('insert', 'right')
        self.recolorize(None)

    def returnNewLine(self, scrolled_text):

        curr_editor = self._get_current_editor()
        cursor_position = curr_editor.index('insert')

        row_index = int(cursor_position.split('.')[0])
        prev_row_index = str(row_index - 1) + '.0'
        prev_line = curr_editor.get(prev_row_index, prev_row_index + ' lineend')
        this_line = curr_editor.get(cursor_position + ' linestart', cursor_position + ' lineend')
        if(len(prev_line) > 1):
            left_char = prev_line[-1]

            new_line = ''.join(self.notAlphaLine(prev_line))

            if len(this_line) > 0:
                right_char = this_line[0]
                if self._are_braces_paired(left_char, right_char):
                    curr_editor.insert('insert', new_line + '\t')
                    curr_editor.mark_gravity('insert', 'left')
                    curr_editor.insert('insert', '\n\t')
                    curr_editor.mark_gravity('insert', 'right')
            else:
                curr_editor.insert('insert', new_line)
        elif(len(prev_line) == 1):
            if(len(this_line) == 0):
                if (prev_line == '\t'):
                    curr_editor.insert('insert', '\t')
            if(len(this_line) > 0):
                left_char = prev_line[0]
                right_char = this_line[0]
                if self._are_braces_paired(left_char, right_char):
                    curr_editor.insert('insert', '\t')
                    curr_editor.mark_gravity('insert', 'left')
                    curr_editor.insert('insert', '\n')
                    curr_editor.mark_gravity('insert', 'right')

    def _are_braces_paired(self, lchar, rchar):

        if(lchar == '(' and rchar == ')'):
            return True
        if(lchar == '[' and rchar == ']'):
            return True
        if(lchar == '{' and rchar == '}'):
            return True
        return False

    def notAlphaLine(self, line):

        new_line = []
        line = ''.join(line)
        for char in line:
            if (char == ' ' or char == '\t'):
                new_line.append(char)
            else:
                return new_line
        return new_line

    def skipRParen(self, scrolled_text):
        try:
            cursor_position = scrolled_text.index('insert')
            row, col = map(int, cursor_position.split('.'))
            next_position = str(row) + '.' + str(col+1)
            if scrolled_text.get(cursor_position, next_position) == ')':
                scrolled_text.delete(cursor_position, next_position)
        except:
            pass

    def skipRBracket(self, scrolled_text):
        try:
            cursor_position = scrolled_text.index('insert')
            row, col = map(int, cursor_position.split('.'))
            next_position = str(row) + '.' + str(col+1)
            if scrolled_text.get(cursor_position, next_position) == ']':
                scrolled_text.delete(cursor_position, next_position)
        except:
            pass

    def skipRBrace(self, scrolled_text):
        try:
            cursor_position = scrolled_text.index('insert')
            row, col = map(int, cursor_position.split('.'))
            next_position = str(row) + '.' + str(col+1)
            if scrolled_text.get(cursor_position, next_position) == '}':
                scrolled_text.delete(cursor_position, next_position)
        except:
            pass

    def skipRAngle(self, scrolled_text):
        try:
            cursor_position = scrolled_text.index('insert')
            row, col = map(int, cursor_position.split('.'))
            next_position = str(row) + '.' + str(col+1)
            if scrolled_text.get(cursor_position, next_position) == '>':
                scrolled_text.delete(cursor_position, next_position)
        except:
            pass

    def erasePair(self, scrolled_text):

        try:
            cursor_position = scrolled_text.index('insert')
            row, col = map(int, cursor_position.split('.'))
            prev_position = str(row) + '.' + str(col-1)
            next_position = str(row) + '.' + str(col+1)
            curr_char = scrolled_text.get(cursor_position, next_position)
            prev_char = scrolled_text.get(prev_position, cursor_position)
            if curr_char == ')' and prev_char == '(':
                scrolled_text.delete(cursor_position, next_position)
            if curr_char == ']' and prev_char == '[':
                scrolled_text.delete(cursor_position, next_position)
            if curr_char == '}' and prev_char == '{':
                scrolled_text.delete(cursor_position, next_position)
            if curr_char == '>' and prev_char == '<':
                scrolled_text.delete(cursor_position, next_position)
        except:
            pass

    def runCurrentEditor(self):
        if len(self.Editors):
            curr_editor = self._get_current_editor()
            if self.Filenames[curr_editor] is not None:
                os.system('gnome-terminal --working-directory=%s' % os.path.dirname(self.Filenames[curr_editor]))
            else:
                messagebox.showerror(title="Could Not Open Terminal",
                                    message="Please save the File to run it")

    def showFileTree(self):

        if len(self.Editors):
            curr_editor = self._get_current_editor()
            directory = os.path.dirname(self.Filenames[curr_editor])
            FileTree(curr_editor, directory)

    def printAbout(self):

        about = """


   qqqqq                           dd                    ii  ddddddd     eeeeeee
  qqq qqq                          dd                    ii  dd     dd   ee
 qqq   qqq                         dd                    ii  dd      dd  ee
qqq     qqq                        dd                    ii  dd      dd  ee
qqq     qqq uu    uu    oo      ddddd   eeeee            ii  dd      dd  eeeeeee
qqq     qqq uu    uu  oo  oo   dd  dd  ee   ee           ii  dd      dd  ee
qqq     qqq uu    uu oo    oo dd   dd ee     ee  zzzzz   ii  dd      dd  ee
 qqq   qqq  uu    uu oo    oo dd   dd eeeeeeeee          ii  dd      dd  ee
  qqq qqq   uu    uu  oo  oo  dd   dd  ee                ii  dd    dd    ee
   qqqqq      uuuu      oo      ddddd   eeeeee           ii  dddddd      eeeeeee
       qqqqqq


       Quode-IDE(Integrated Development Environment)

       Author : Yash Khasbage


DISCLAIMER:

    Identifiers used in this software are purely fictious and bear no
    resembalance to any person living or dead. Any resembalace is purely
    co-incidental.

    No animals were harmed in coding of this software.

        """
        print(about)
        messagebox.showinfo(title="About", message="Check terminal")

    def _get_int_row_col(self):

        curr_editor = self._get_current_editor()
        return list(map(int, curr_editor.index('insert').split('.')))

    def _get_str_row_col(self):

        curr_editor = self._get_current_editor()
        return curr_editor.index('insert')

    def _str_to_int(self, pos):

        return list(map(int, pos.split('.')))

    def _get_current_char(self):

        row, col = self._get_int_row_col()
        curr_pos = str(row)+'.'+str(col)
        next_pos = str(row)+'.'+str(col+1)
        curr_editor = self._get_current_editor()
        return curr_editor.get(curr_pos, next_pos)

    def _next_position(self, pos):
        row, col = list(map(int, pos.split('.')))
        return '%d.%d'%(row, col+1)

    def underlineComplement(self):

        if len(self.Editors):

            pos = self._get_str_row_col()
            curr_char = self._get_current_char()
            if(curr_char == '('):
                self.underlineRParen(pos)
            elif(curr_char == ')'):
                self.underlineLParen(pos)
            elif(curr_char == '['):
                self.underlineRBracket(pos)
            elif(curr_char == ']'):
                self.underlineLBracket(pos)
            elif(curr_char == '{'):
                self.underlineRBrace(pos)
            elif(curr_char == '}'):
                self.underlineLBrace(pos)
            elif(curr_char == '<'):
                self.underlineRAngle(pos)
            elif(curr_char == '>'):
                self.underlineLAngle(pos)

    def underlineRParen(self, l_pos):
        return
        curr_editor = self._get_current_editor()
        text = curr_editor.get(l_pos, 'end')
        count = 0
        index = 0
        for i in range(len(text)):
            if(text[i] == ')' and count == 0):
                index = i
            elif(text[i] == '('):
                count += 1
            elif(text[i] == ')'):
                count -= 1
        j = 0
        line = self._str_to_int(l_pos)[0]
        line_number = 0
        start = l_pos
        end = '%d.end' % line
        j_prev = 0
        while(index > j):
            j_prev = j
            j += len(curr_editor.get(start, end)) - 1
            line_number += 1
            start = "%d.0" % (line+line_number)
        r_paren_index = '%d.%d' % (line+line_number, index-j_prev)
        print("index", index)
        print("j", j)
        print("linenumber", line_number)
        print("r_paren_index", r_paren_index)
        curr_editor.tag_add('underline',
                            l_pos,
                            self._next_position(l_pos))
        curr_editor.tag_add('underline',
                            r_paren_index,
                            self._next_position(r_paren_index))
        curr_editor.tag_configure('underline', underline=True)


    def underlineLParen(self, r_pos):

        pass

    def underlineRBracket(self, l_pos):

        pass

    def underlineLBracket(self, r_pos):

        pass

    def underlineRbrace(self, l_pos):

        pass

    def underlineLBrace(self, r_pos):

        pass

    def underlineRAngle(self, l_pos):

        pass

    def underlineLAngle(self, r_pos):

        pass
class ViewResults(Observer, View):
    """Takes care of the presentation of the Flow diagram."""
    def __init__(self, parent, col=0, row=0, root=None):
        super().__init__(parent,
                         col=col,
                         row=row,
                         sticky=NSEW,
                         scrollbars=False,
                         root=root)
        self._notebook = Notebook(self._frame, name="nb")
        self._notebook.columnconfigure(0, weight=1)
        self._notebook.rowconfigure(0, weight=1)
        self._notebook.config()
        self._notebook.grid(sticky=NSEW)
        self._notebook.grid(sticky=NSEW)
        self._tabs = []  # type: List[ImageTab]
        self._results = None
        self._parent = parent
        self.image_overlay = np.empty(shape=(0, 0, 0), dtype=np.uint8)

        # TODO: Work around below should be fixed; need to create a tab first and delete it, or background is old image in constant scale.
        name_init = "initialization_image"
        self.add_to_tab(np.zeros((1, 1, 3), dtype=np.uint8), name_init)
        self.RemoveTab(name_init)

        self.__temp_data_queue = Queue(
        )  # used for update function to store data in

        # add custom event handler to let updates be taken care of in tk main loop
        parent.root.bind("<<ViewResults.Update>>", self.__update)
        self._notebook.bind("<<NotebookTabChanged>>", self.__on_tabchange)

        self.__last_selected_tab = None

    def __on_tabchange(self, event):
        try:
            tab_index = self._notebook.index(self._notebook.select())
        except TclError as ex:
            return  # there are no tabs yet
        if self.__last_selected_tab is not None:
            self.__last_selected_tab.on_tab_deselect()
        self.__last_selected_tab = self._tabs[tab_index]
        self.__last_selected_tab.on_tab_selected()

    def RemoveTab(self, name):
        for tab in self._tabs:
            if name is tab.GetName():
                tab.destroy()
                self._tabs.remove(tab)

    def add_to_tab(self, npimage, name):
        if npimage is None:
            return

        # check if one exists; if so use that
        for tab in self._tabs:
            if tab.GetName() == name:
                tab.SetImage(npimage=npimage)
                return
        #create new tab one
        tab = ImageTab(name=name, notebook=self._notebook, parent=self)
        self._tabs.append(tab)
        self.add_to_tab(npimage=npimage, name=name)

    def __findAllImagesAndShow(self, flowblock_name):
        if self._results is None:
            return
        imageVars = self._results.FindAllOfType(ImageVar().name)
        for key, var in imageVars.items():
            name = key.split(".")[0]
            if name == flowblock_name:
                self.add_to_tab(var.value, name)

    def __draw_all_drawables_until(self, flowblock_name=None):
        '''
        Draws al drawable results to image_overlay. Images is as large as to fit all drawables.
        :param flowblock_name: draw until this block.
        :return:
        '''
        results = self.get_controller().results.get_result_dict(
        )  # type: Dict[str,Dict[str,Var]]
        self.image_overlay = np.empty(shape=(0, 0, 0), dtype=np.uint8)
        logging.debug("Starting drawing of drawables...")
        for key, value in results.items():
            for key2, value2 in value.items():
                if type(value2) == list:
                    for value3 in value2:
                        self.image_overlay = value3.draw(self.image_overlay)
                else:
                    self.image_overlay = value2.draw(self.image_overlay)
        logging.debug("Finished drawing of drawables.")

    def __update(self, event):
        self._results = self.get_controller().results.get_results_for_block()
        try:
            flowblock_name = self.__temp_data_queue.get_nowait(
            )["flowblock_name"]
        except Empty:
            flowblock_name = None
        if not flowblock_name is None:
            # redraw al drawables
            self.__draw_all_drawables_until(flowblock_name)
            # a flowblock has just updated, go and show all containing images
            self.__findAllImagesAndShow(flowblock_name)

    def Update(self, *args, **kwargs):
        self.__temp_data_queue.put_nowait(
            {"flowblock_name": kwargs.get("flowblock_name", None)})
        self._parent.root.event_generate("<<ViewResults.Update>>")