добавь возможность использования системы управления версиями, такой как Git, для отслеживания изменений и совместной работы .                                                                                                                                                                                                                       import os
from tkinter import 
from tkinter import filedialog
from PIL import Image, ImageTk
from collections import deque

class ToolTip:
“”“
A class for creating tooltip windows for widgets.
“””
def init(self, widget, text):
“”“
Initializes a new ToolTip instance.
:param widget: The widget to attach the tooltip to.
:param text: The text to display in the tooltip.
“””
self.widget = widget
self.text = text
self.tip_window = None

def show(self, event=None):
“”“
Displays the tooltip window.
:param event: The event that triggered the tooltip.
“””
x, y, _, _ = self.widget.bbox(“insert”)
x += self.widget.winfo_rootx() + 25
y += self.widget.winfo_rooty() + 25
self.tip_window = Toplevel(self.widget)
self.tip_window.wm_overrideredirect(True)
self.tip_window.wm_geometry(f"+{x}+{y}“)
label = Label(self.tip_window, text=self.text, background=”#FFFFE0", relief=SOLID, borderwidth=1)
label.pack()

def hide(self, event=None):
“”“
Hides the tooltip window.
:param event: The event that triggered hiding the tooltip.
“””
if self.tip_window:
self.tip_window.destroy()
self.tip_window = None

class ImageEditor:
“”“
A class for the main image editor application.
“””
def init(self):
“”“
Initializes a new ImageEditor instance.
“””
self.master = Tk()
self.master.title(“Image Editor”)
self.undo_icon = PhotoImage(file=‘undo.gif’)
self.redo_icon = PhotoImage(file=‘redo.gif’)
self.open_file_icon = PhotoImage(file=‘open-file.gif’)
self.save_file_icon = PhotoImage(file=‘save-file.gif’)
self.init_menu()
self.init_toolbar()
self.init_canvas()
self.init_statusbar()
self.master.bind(“<Key>”, self.handle_key_press)
self.history = ActionHistory(self)
self.key_images = {}
self.tk_images = []

def init_menu(self):
“”“
Initializes the menu for the main window.
“””
self.menu = Menu(self.master)
self.master.config(menu=self.menu)

self.file_menu = Menu(self.menu)
self.menu.add_cascade(label=“File”, menu=self.file_menu)

self.file_menu.add_command(label=“Open”, image=self.open_file_icon, compound=LEFT, command=self.open_file)
self.file_menu.add_command(label=“Save”, image=self.save_file_icon, compound=LEFT, command=self.save_file)
self.file_menu.add_separator()
self.file_menu.add_command(label=“Exit”, command=self.master.quit)

self.init_help_menu()

def init_toolbar(self):
“”“
Initializes the toolbar for the main window.
“””
self.toolbar = Frame(self.master, bd=1, relief=SUNKEN)
self.undo_button = self.create_toolbar_button(self.undo_icon, self.history.undo_key_image, “Undo last action (Ctrl+Z)”)
self.redo_button = self.create_toolbar_button(self.redo_icon, self.history.redo_key_image, “Redo last action (Ctrl+Y)”)

def create_toolbar_button(self, icon, command, tooltip_text):
“”“
Creates a button for the toolbar.
:param icon: The icon image for the button.
:param command: The command to execute when the button is clicked.
:param tooltip_text: The text to display in the tooltip.
:return: The created button.
“””
button = Button(self.toolbar, image=icon, command=command)
button.pack(side=LEFT, padx=2, pady=2)
self.create_tooltip(button, tooltip_text)
return button

def init_canvas(self):
“”“
Initializes the canvas for displaying images.
“””
self.canvas = Canvas(self.master, bg=“white”)
self.context_menu = Menu(self.canvas, tearoff=0)
self.canvas.bind(“<Button-3>”, self.show_context_menu)

def init_statusbar(self):
“”“
Initializes the status bar at the bottom of the main window.
“””
self.status_var = StringVar()
self.status_var.set(“Ready”)
self.statusbar = Label(self.master, textvariable=self.status_var, bd=1, relief=SUNKEN, anchor=W)
self.statusbar.pack(side=BOTTOM, fill=X)

def handle_key_press(self, event):
“”“
Handles key press events.
:param event: The key press event.
“””
key = event.keysym.lower()
if key.isalpha() and len(key) == 1:
if key in self.key_images:
self.history.add_key_image_state(self.key_images, key=key)
self.display_bound_images(self.key_images[key])
elif key == ‘z’ and (event.state & 0x0001): # Pressed CTRL+Z
self.history.undo_key_image()
elif key == ‘y’ and (event.state & 0x0001): # Pressed CTRL+Y
self.history.redo_key_image()

def open_file(self):
“”“
Opens a file dialog to select and open an image file.
“””
filetypes = ((“JPEG files”, “.jpg”), (“PNG files”, “.png”), (“All files”, ".“))
filename = filedialog.askopenfilename(title=“Open file”, filetypes=filetypes)
if filename:
try:
key = os.path.basename(filename)[0].lower()
image = Image.open(filename)
self.add_image_to_key(key, image)
self.display_bound_images(self.key_images[key])
self.status_var.set(f"Opened {filename}”)
except Exception as e:
self.status_var.set(f"Failed to open {filename}“)
print(e)

def add_image_to_key(self, key, image):
“””
Adds an image to a key.
:param key: The key to bind the image to.
:param image: The image to add.
“”“
if key in self.key_images:
self.key_images[key].append(image)
else:
self.key_images[key] = deque([image])
self.history.add_key_image_state(self.key_images, key=key)

def save_file(self):
“””
Opens a file dialog to save the canvas as an image file.
“”“
filetypes = ((“JPEG files”, “.jpg”), (“PNG files”, “.png”), (“All files”, “.*”))
filename = filedialog.asksaveasfilename(title=“Save file”, filetypes=filetypes)
if filename:
try:
self.canvas.postscript(file=“tmp_canvas.eps”, colormode=“color”)
img = Image.open(“tmp_canvas.eps”)
img.save(filename)
os.remove(“tmp_canvas.eps”)
self.status_var.set(f"Saved {filename}”)
except Exception as e:
self.status_var.set(f"Failed to save {filename}“)
print(e)

def show_context_menu(self, event):
“””
Shows the context menu at the mouse position.
:param event: The mouse event that triggered showing the context menu.
“”“
self.context_menu.post(event.x_root, event.y_root)

def init_help_menu(self):
“””
Initializes the help menu.
“”“
self.help_menu = Menu(self.menu)
self.menu.add_cascade(label=“Help”, menu=self.help_menu)

self.help_menu.add_command(label=“Hotkeys and actions”, command=self.show_help)
self.help_menu.add_command(label=“Show History”, command=self.show_history)

def show_help(self):
“””
Displays a help window with hotkeys and actions information.
“”“
help_text = “””
Hotkeys and actions:
A-Z: Show images bound to the key.
Ctrl+Z: Undo last action.
Ctrl+Y: Redo last action.

Undo: Undo last action. (Button)
Redo: Redo last action. (Button)
“”“
self.show_help_window(“Help”, help_text)

def show_history(self):
“””
Displays a help window with the action history.
“”“
history_text = “\n”.join([f"Action {i + 1}: {action[‘key’]}” for i, action in enumerate(self.history.actions)])
self.show_help_window(“Action History”, history_text)

def show_help_window(self, title, text):
“”“
Displays a help window with the given title and text.
:param title: The title of the help window.
:param text: The text to display in the help window.
“””
help_window = Toplevel(self.master)
help_window.title(title)
help_label = Label(help_window, text=text, justify=LEFT)
help_label.pack(padx=10, pady=10)
help_close_button = Button(help_window, text=“Close”, command=help_window.destroy)
help_close_button.pack(pady=5)

def run(self):
“”“
Runs the main event loop for the application.
“””
self.master.mainloop()

class ActionHistory:
“”“
A class for managing the action history of the image editor.
“””
def init(self, editor):
“”“
Initializes a new ActionHistory instance.
:param editor: The ImageEditor instance.
“””
self.editor = editor
self.actions = deque()
self.current = -1

def add_key_image_state(self, key_images, key):
“”“
Adds a new key image state to the action history.
:param key_images: The dictionary of key images.
:param key: The key of the current state.
“””
if self.current < len(self.actions) - 1:
self.actions = self.actions[:self.current + 1]
self.actions.append({“key”: key, “key_images”: key_images.copy()})
self.current += 1

def undo_key_image_state(self):
“”“
Undoes the key image state of the last action in the action history.
“””
if self.current > -1:
action = self.actions[self.current]
key = action[“key”]
key_images = action[“key_images”]
self.display_bound_images(key_images)
self.current -= 1

def redo_key_image_state(self):
“”“
Redoes the key image state of the next action in the action history.
“””
if self.current < len(self.actions) - 1:
self.current += 1
action = self.actions[self.current]
key = action[“key”]
key_images = action[“key_images”]
self.display_bound_images(key_images)

def display_bound_images(self, images):
“”“
Displays the bound images on the canvas.
:param images: The images to display.
“””
self.editor.canvas.delete(“all”)