"""
Frontend Systems Execute Page File for AGE-ABM Visual Interface
@Author Meghan Ireland
@Co-Authors Max Hall and Matthew Fleischman
@Reference thepythoncode.com. (n.d.). Code for How to Make a Python Code Editor using Tkinter in Python - Python Code. [online]
Available at: https://thepythoncode.com/code/python-code-editor-using-tkinter-python [Accessed 14 Sep. 2023].
| Used as a basis for the designed code editor used as opposed library options
"""
import tkinter as tk
import re
import customtkinter
[docs]
class Execute:
"""This class defines how the execute page looks and works.
"""
def __init__(self, ec_app_ui):
"""Defines all the variables and widgets for the execute page.
"""
self.ec_app_ui = ec_app_ui
### Comboboxes ###
self.combobox_execute_systems = customtkinter.CTkOptionMenu(self.ec_app_ui.page_frame
, values = [], fg_color = self.ec_app_ui.dropdown_menu_color
, button_hover_color= self.ec_app_ui.highlight_colour
, button_color=self.ec_app_ui.comp_btn_colour
, height=self.ec_app_ui.entry_height, command=self.btn_execute_code
, width=self.ec_app_ui.entry_height*6
, font = self.ec_app_ui.font2)
self.combobox_execute_systems.set("Select System")
### Buttons ###
self.button_execute_code = customtkinter.CTkButton(self.ec_app_ui.page_frame
, hover_color=self.ec_app_ui.highlight_colour, text="💻 Code"
, fg_color=self.ec_app_ui.comp_btn_colour
, font = self.ec_app_ui.font2, height=self.ec_app_ui.entry_height
, width=self.ec_app_ui.entry_height*4 - self.ec_app_ui.space_btw_btns)
self.button_execute_save = customtkinter.CTkButton(self.ec_app_ui.page_frame
, hover_color=self.ec_app_ui.highlight_colour, text="✔️ Save Execute"
, command=self.btn_execute_save, fg_color=self.ec_app_ui.comp_btn_colour
, font = self.ec_app_ui.font2, width = self.ec_app_ui.entry_height*9)
### Labels ###
self.label_execute_choose_system = tk.Label(self.ec_app_ui.page_frame
, text="System's Execute to code:", font=self.ec_app_ui.font2
, bg=self.ec_app_ui.frame_colour, fg=self.ec_app_ui.label_text_colour)
### Titles ###
self.label_execute_title = tk.Label(self.ec_app_ui.title_frame, text="Execute Function"
, font=self.ec_app_ui.font1, bg=self.ec_app_ui.title_colour
, fg=self.ec_app_ui.label_text_colour)
self.previous_text = ''
# Define colors for the variouse types of tokens
self.normal = "white"
self.keywords = "#C766FE"
self.comments = "#5b8746"
self.string = "#bf6839"
self.function = "#63b5e3"
self.brackets = "#f3bb11"
self.background = "#2A2A2A"
self.square = "#bf68d1"
self.font = 'Consolas 11'
self.repl = [['(^| )(False|None|True|and|as|assert|async|await|break|class|continue|del|elif|else|except|finally|for|from|global|if|import|in|is|lambda|nonlocal|not|or|pass|raise|return|try|while|with|yield)($| )', self.keywords],
['(^|\t)(False|None|True|and|as|assert|async|await|break|class|continue|del|elif|else|except|finally|for|from|global|if|import|in|is|lambda|nonlocal|not|or|pass|raise|return|try|while|with|yield)($| )', self.keywords],
['".*?"', self.string],
['\'.*?\'', self.string],
['#.*?$', self.comments],
['def', self.function],
['self', self.function],
['\(', self.brackets],
['\)', self.brackets],
['\[',self.square],
['\]',self.square]]
# Make the Text Widget
self.horizontal_scroll=tk.Scrollbar(self.ec_app_ui.root, orient='horizontal')
self.edit_area = tk.Text(
self.ec_app_ui.page_frame,
background=self.background,
foreground=self.normal,
insertbackground=self.normal,
relief="flat",
borderwidth=0,
font=self.font,
wrap='none', xscrollcommand=self.horizontal_scroll.set
)
self.edit_area.configure(wrap=None)
self.edit_area.bind('<KeyRelease>', self.changes)
[docs]
def clear_execute(self):
"""This method clears the execute page.
"""
self.label_execute_title.grid_forget()
self.label_execute_choose_system.grid_forget()
self.edit_area.grid_forget()
self.combobox_execute_systems.grid_forget()
self.button_execute_code.grid_forget()
self.button_execute_save.grid_forget()
[docs]
def execute_tab_btn(self):
"""This method creats the execute page.
"""
if not self.ec_app_ui.collapsed:
self.ec_app_ui.collapsed = False
self.ec_app_ui.collapse_tab_btn()
self.ec_app_ui.clear_all()
self.label_execute_title.grid(row = 0, column = 0)
self.label_execute_choose_system.grid(row = 0, column = 0,padx = 150,pady = 5,sticky="W")
self.combobox_execute_systems.configure(self
, values=self.ec_app_ui.new_model.get_list_systems())
self.combobox_execute_systems.grid(row = 0, column = 2,pady = 5)
[docs]
def btn_execute_save(self):
"""This saves the execute function for the selected system.
"""
system_selected = self.combobox_execute_systems.get()
self.combobox_execute_systems.set("Select System")
function = self.edit_area.get('1.0','end')
self.ec_app_ui.new_model.add_execute(system_selected, function)
self.edit_area.delete('1.0','end')
self.edit_area.grid_forget()
self.button_execute_save.grid_forget()
self.combobox_execute_systems.grid(row = 0, column = 2,pady = 5)
[docs]
def btn_execute_code(self, *args):
"""This method allows the user to edit the execute function for the selected system
"""
system_selected = self.combobox_execute_systems.get()
if not system_selected == "":
self.edit_area.insert('1.0',self.ec_app_ui.new_model.get_execute(system_selected))
self.edit_area.configure(width = 2*self.ec_app_ui.window_width//18, height = 27)
self.edit_area.grid(row = 1, column = 0,pady = 5,columnspan = 5, padx=20)
self.button_execute_save.grid(row = 2, column = 2,pady = 5)
self.combobox_execute_systems.grid_forget()
self.button_execute_code.grid_forget()
[docs]
def selected_system(self,*args):
"""This method is required by a combobox
"""
if self.combobox_execute_systems.get() != "Select System":
self.button_execute_code.grid(row = 0, column = 3,pady = 5,padx=5)
[docs]
def changes(self, *args):
"""Adds the edits
"""
# If actually no changes have been made stop / return the function
if self.edit_area.get('1.0', 'end') == self.previous_text:
return
# Remove all tags so they can be redrawn
for tag in self.edit_area.tag_names():
self.edit_area.tag_remove(tag, "1.0", "end")
# Add tags where the search_re function found the pattern
i = 0
for pattern, color in self.repl:
for start, end in self.search_re(pattern, self.edit_area.get('1.0', 'end')):
self.edit_area.tag_add(f'{i}', start, end)
self.edit_area.tag_config(f'{i}', foreground=color)
i+=1
self.previous_text = self.edit_area.get('1.0', 'end')
[docs]
def search_re(self, pattern, text):
"""Searches for patterns
"""
matches = []
text = text.splitlines()
for i, line in enumerate(text):
for match in re.finditer(pattern, line):
matches.append(
(f"{i + 1}.{match.start()}", f"{i + 1}.{match.end()}")
)
return matches
[docs]
def rgb(self, rgb):
"""RGB value
"""
return "#%02x%02x%02x" % rgb
[docs]
def opened_from_systems(self, system):
"""If user opened tab from the systems page
"""
if not system == "":
self.ec_app_ui.clear_all()
self.label_execute_title.grid(row = 0, column = 0)
self.label_execute_choose_system.grid(row = 0, column = 0,padx = 150,pady = 5,sticky="W")
self.edit_area.insert('1.0',self.ec_app_ui.new_model.get_execute(system))
self.edit_area.configure(width = 2*self.ec_app_ui.window_width//18, height = 27)
self.edit_area.grid(row = 1, column = 0,pady = 5,columnspan = 5, padx=20)
self.button_execute_save.grid(row = 2, column = 2,pady = 5)
self.combobox_execute_systems.grid_forget()
self.button_execute_code.grid_forget()
self.combobox_execute_systems.configure(self
, values=self.ec_app_ui.new_model.get_list_systems())
if not self.ec_app_ui.collapsed:
self.ec_app_ui.collapsed = False
self.ec_app_ui.collapse_tab_btn()