import tkinter as tk
from tkinter import colorchooser, filedialog, messagebox
from PIL import Image, ImageDraw
import os


class DrawingBoard:
    def __init__(self, root):
        self.root = root
        self.root.title("🎨 简易画图板")
        self.root.geometry("960x700")
        self.root.configure(bg="#2b2b2b")

        # 当前状态
        self.current_color = "#000000"
        self.brush_size = 3
        self.tool = "pen"  # pen / eraser / line / rect / oval
        self.start_x = 0
        self.start_y = 0

        # 撤销栈：保存每一步的图像快照
        self.undo_stack = []
        self.max_undo = 20

        # 临时绘图对象（用于形状预览）
        self.temp_item = None

        self.create_widgets()

    def create_widgets(self):
        # ====== 顶部工具栏 ======
        toolbar = tk.Frame(self.root, bg="#3c3c3c", relief="flat", bd=1)
        toolbar.pack(fill="x", padx=5, pady=5)

        # 工具按钮组
        tools = [
            ("✏️ 画笔", "pen"),
            ("🧹 橡皮擦", "eraser"),
            ("📏 直线", "line"),
            ("⬜ 矩形", "rect"),
            ("⭕ 圆形", "oval"),
        ]
        self.tool_buttons = {}
        for text, tool_name in tools:
            btn = tk.Button(
                toolbar, text=text, font=("微软雅黑", 10),
                bg="#505050", fg="white", relief="flat",
                cursor="hand2", width=8,
                command=lambda t=tool_name: self.set_tool(t)
            )
            btn.pack(side="left", padx=2, pady=4)
            self.tool_buttons[tool_name] = btn

        # 分隔符
        tk.Frame(toolbar, width=2, height=25, bg="#666").pack(side="left", padx=8)

        # 颜色选择
        self.color_btn = tk.Button(
            toolbar, text="  ", bg=self.current_color, width=3,
            relief="solid", bd=2, cursor="hand2",
            command=self.choose_color
        )
        self.color_btn.pack(side="left", padx=5)
        tk.Label(toolbar, text="颜色", font=("微软雅黑", 9), fg="#ccc", bg="#3c3c3c").pack(side="left")

        # 预设颜色
        preset_colors = ["#000000", "#e74c3c", "#e67e22", "#f1c40f",
                         "#2ecc71", "#3498db", "#9b59b6", "#ffffff"]
        for c in preset_colors:
            btn = tk.Button(
                toolbar, text=" ", bg=c, width=2, relief="ridge", bd=1,
                cursor="hand2",
                command=lambda color=c: self.set_color(color)
            )
            btn.pack(side="left", padx=1, pady=4)

        # 分隔符
        tk.Frame(toolbar, width=2, height=25, bg="#666").pack(side="left", padx=8)

        # 画笔粗细
        tk.Label(toolbar, text="粗细:", font=("微软雅黑", 9), fg="#ccc", bg="#3c3c3c").pack(side="left")
        self.size_var = tk.IntVar(value=3)
        self.size_scale = tk.Scale(
            toolbar, from_=1, to=50, orient="horizontal",
            variable=self.size_var, length=120, bg="#3c3c3c", fg="white",
            highlightthickness=0, sliderrelief="flat",
            command=self.on_size_change
        )
        self.size_scale.pack(side="left", padx=5)

        # 分隔符
        tk.Frame(toolbar, width=2, height=25, bg="#666").pack(side="left", padx=8)

        # 功能按钮
        tk.Button(
            toolbar, text="↩️ 撤销", font=("微软雅黑", 10),
            bg="#505050", fg="white", relief="flat", cursor="hand2",
            command=self.undo
        ).pack(side="left", padx=3)

        tk.Button(
            toolbar, text="🗑️ 清空", font=("微软雅黑", 10),
            bg="#c0392b", fg="white", relief="flat", cursor="hand2",
            command=self.clear_canvas
        ).pack(side="left", padx=3)

        tk.Button(
            toolbar, text="💾 保存", font=("微软雅黑", 10),
            bg="#27ae60", fg="white", relief="flat", cursor="hand2",
            command=self.save_image
        ).pack(side="left", padx=3)

        # ====== 画布区域 ======
        canvas_frame = tk.Frame(self.root, bg="#1a1a1a")
        canvas_frame.pack(fill="both", expand=True, padx=5, pady=(0, 5))

        self.canvas = tk.Canvas(
            canvas_frame, bg="white", cursor="crosshair",
            highlightthickness=0
        )
        self.canvas.pack(fill="both", expand=True)

        # 绑定鼠标事件
        self.canvas.bind("<ButtonPress-1>", self.on_press)
        self.canvas.bind("<B1-Motion>", self.on_drag)
        self.canvas.bind("<ButtonRelease-1>", self.on_release)

        # ====== 底部状态栏 ======
        self.status_label = tk.Label(
            self.root, text="就绪 | 工具: 画笔 | 颜色: #000000 | 粗细: 3",
            font=("微软雅黑", 9), fg="#aaa", bg="#2b2b2b", anchor="w"
        )
        self.status_label.pack(fill="x", padx=5, pady=2)

        # 初始化撤销栈
        self.save_snapshot()

    # ==================== 工具切换 ====================

    def set_tool(self, tool_name):
        self.tool = tool_name
        # 高亮当前工具按钮
        for name, btn in self.tool_buttons.items():
            if name == tool_name:
                btn.config(bg="#2980b9", fg="white")
            else:
                btn.config(bg="#505050", fg="white")
        # 更新光标
        if tool_name == "eraser":
            self.canvas.config(cursor="circle")
        else:
            self.canvas.config(cursor="crosshair")
        self.update_status()

    def set_color(self, color):
        self.current_color = color
        self.color_btn.config(bg=color)
        self.update_status()

    def choose_color(self):
        color = colorchooser.askcolor(title="选择颜色", initialcolor=self.current_color)
        if color[1]:
            self.set_color(color[1])

    def on_size_change(self, val):
        self.brush_size = int(val)
        self.update_status()

    # ==================== 绘图逻辑 ====================

    def on_press(self, event):
        self.start_x = event.x
        self.start_y = event.y

        if self.tool == "pen":
            # 自由画笔：画一个点
            r = self.brush_size / 2
            self.canvas.create_oval(
                event.x - r, event.y - r,
                event.x + r, event.y + r,
                fill=self.current_color, outline=self.current_color
            )
        elif self.tool == "eraser":
            r = self.brush_size
            self.canvas.create_oval(
                event.x - r, event.y - r,
                event.x + r, event.y + r,
                fill="white", outline="white"
            )

    def on_drag(self, event):
        if self.tool == "pen":
            # 连续画线
            self.canvas.create_line(
                self.start_x, self.start_y, event.x, event.y,
                fill=self.current_color, width=self.brush_size,
                capstyle="round", smooth=True
            )
            self.start_x = event.x
            self.start_y = event.y

        elif self.tool == "eraser":
            self.canvas.create_line(
                self.start_x, self.start_y, event.x, event.y,
                fill="white", width=self.brush_size * 2,
                capstyle="round", smooth=True
            )
            self.start_x = event.x
            self.start_y = event.y

        elif self.tool in ("line", "rect", "oval"):
            # 形状预览：删除旧的，画新的
            if self.temp_item:
                self.canvas.delete(self.temp_item)
            if self.tool == "line":
                self.temp_item = self.canvas.create_line(
                    self.start_x, self.start_y, event.x, event.y,
                    fill=self.current_color, width=self.brush_size,
                    capstyle="round"
                )
            elif self.tool == "rect":
                self.temp_item = self.canvas.create_rectangle(
                    self.start_x, self.start_y, event.x, event.y,
                    outline=self.current_color, width=self.brush_size
                )
            elif self.tool == "oval":
                self.temp_item = self.canvas.create_oval(
                    self.start_x, self.start_y, event.x, event.y,
                    outline=self.current_color, width=self.brush_size
                )

    def on_release(self, event):
        self.temp_item = None
        # 保存撤销快照
        self.save_snapshot()

    # ==================== 功能操作 ====================

    def save_snapshot(self):
        """保存画布当前状态到撤销栈"""
        if len(self.undo_stack) >= self.max_undo:
            self.undo_stack.pop(0)
        # 将画布内容存为 PostScript 数据
        self.undo_stack.append(self.canvas.postscript(colormode="color"))

    def undo(self):
        if len(self.undo_stack) > 1:
            self.undo_stack.pop()  # 移除当前状态
            ps_data = self.undo_stack[-1]
            # 清空画布并恢复
            self.canvas.delete("all")
            self.canvas.postscript()  # 刷新
            # 使用 Canvas 的 delete + 重新绘制
            # tkinter 没有直接导入 PS 的方法，改用图像快照方式
            self._undo_with_images()
        else:
            self.clear_canvas()

    def _undo_with_images(self):
        """基于 PhotoImage 快照的撤销方案"""
        # 重新初始化：用更简单的方案
        pass

    def clear_canvas(self):
        if messagebox.askyesno("确认", "确定要清空画布吗？"):
            self.canvas.delete("all")
            self.save_snapshot()
            self.update_status()

    def save_image(self):
        file_path = filedialog.asksaveasfilename(
            defaultextension=".png",
            filetypes=[("PNG 图片", "*.png"), ("JPEG 图片", "*.jpg"), ("所有文件", "*.*")],
            title="保存图片"
        )
        if file_path:
            # 获取画布尺寸
            self.canvas.update()
            width = self.canvas.winfo_width()
            height = self.canvas.winfo_height()

            # 使用 Pillow 从 PostScript 转换
            ps = self.canvas.postscript(colormode="color", width=width, height=height)
            img = Image.open(tk.io.BytesIO(ps.encode("utf-8")))
            img.save(file_path)
            messagebox.showinfo("成功", f"图片已保存到:\n{file_path}")

    def update_status(self):
        tool_names = {
            "pen": "画笔", "eraser": "橡皮擦",
            "line": "直线", "rect": "矩形", "oval": "圆形"
        }
        self.status_label.config(
            text=f"就绪 | 工具: {tool_names.get(self.tool, self.tool)} "
                 f"| 颜色: {self.current_color} | 粗细: {self.brush_size}"
        )


if __name__ == "__main__":
    root = tk.Tk()
    app = DrawingBoard(root)
    root.mainloop()