import tkinter as tk
from tkinter import colorchooser, messagebox
import math
import random

# ========================
# 全局配置
# ========================
WIDTH, HEIGHT = 820, 640

# ========================
# 主题
# ========================
THEMES = {
    "🌸 樱花粉": {"bg": "#FFF0F5", "fg": "#C2185B", "panel": "#FCE4EC", "btn": "#F48FB1", "accent": "#E91E63"},
    "💙 天空蓝": {"bg": "#E3F2FD", "fg": "#0D47A1", "panel": "#BBDEFB", "btn": "#42A5F5", "accent": "#1565C0"},
    "💚 抹茶绿": {"bg": "#E8F5E9", "fg": "#1B5E20", "panel": "#C8E6C9", "btn": "#66BB6A", "accent": "#2E7D32"},
    "🧡 蜜桔橙": {"bg": "#FFF3E0", "fg": "#E65100", "panel": "#FFE0B2", "btn": "#FF9800", "accent": "#EF6C00"},
    "💜 梦幻紫": {"bg": "#F3E5F5", "fg": "#4A148C", "panel": "#E1BEE7", "btn": "#AB47BC", "accent": "#7B1FA2"},
    "🌈 糖果色": {"bg": "#FFF9C4", "fg": "#F57F17", "panel": "#FFF59D", "btn": "#FFD54F", "accent": "#FF8F00"},
}
cur_theme = "🌸 樱花粉"

# ========================
# 颜色数据库（中文名 + 色值）
# ========================
COLOR_DB = [
    # 红色系
    ("中国红", "#FF0000"), ("深红", "#8B0000"), ("砖红", "#B22222"),
    ("珊瑚红", "#FF7F50"), ("玫红", "#FF1493"), ("桃红", "#FFDAB9"),
    ("樱花粉", "#FFB7C5"), ("西瓜红", "#FC6C85"), ("铁锈红", "#A52A2A"),
    # 橙色系
    ("橙色", "#FFA500"), ("深橙", "#D2691E"), ("杏色", "#FFCBA4"),
    ("琥珀橙", "#FFBF00"), ("南瓜橙", "#E8860C"), ("蜜桔", "#FF8C00"),
    # 黄色系
    ("金黄", "#FFD700"), ("柠檬黄", "#FFF44F"), ("玉米黄", "#FBEC5D"),
    ("土黄", "#BDB76B"), ("芥末黄", "#FFDB58"), ("奶油黄", "#FFFDD0"),
    # 绿色系
    ("森林绿", "#228B22"), ("草绿", "#7CFC90"), ("薄荷绿", "#00FF7F"),
    ("橄榄绿", "#808000"), ("翡翠绿", "#50C878"), ("军绿", "#4B5320"),
    ("苹果绿", "#8DB600"), ("孔雀绿", "#009B77"), ("苔绿", "#8A9A5B"),
    # 蓝色系
    ("天蓝", "#87CEEB"), ("深蓝", "#00008B"), ("宝蓝", "#4169E1"),
    ("湖蓝", "#0077BE"), ("藏青", "#191970"), ("钢蓝", "#4682B4"),
    ("青蓝", "#00FFFF"), ("牛仔蓝", "#5B92E5"), ("冰蓝", "#A5F2F3"),
    # 紫色系
    ("紫色", "#800080"), ("薰衣草紫", "#E6E6FA"), ("葡萄紫", "#6F2DA8"),
    ("丁香紫", "#C8A2C8"), ("茄子紫", "#4B0082"), ("梅子紫", "#9370DB"),
    # 粉色系
    ("粉色", "#FFC0CB"), ("深粉", "#FF69B4"), ("浅粉", "#FFB6C1"),
    ("玫瑰粉", "#FF007F"), ("贝壳粉", "#FFEFD5"), ("芭蕾粉", "#FAAFBE"),
    # 棕色系
    ("棕色", "#A52A2A"), ("深棕", "#5D4037"), ("咖啡棕", "#6F4E37"),
    ("焦糖棕", "#A0522D"), ("胡桃棕", "#8B5A2B"), ("驼色", "#C19A6B"),
    # 灰色/黑白
    ("黑色", "#000000"), ("深灰", "#404040"), ("中灰", "#808080"),
    ("浅灰", "#D3D3D3"), ("白色", "#FFFFFF"), ("银色", "#C0C0C0"),
    # 其他
    ("青色", "#00CED1"), ("靛蓝", "#4B0082"), ("珊瑚色", "#FF7F50"),
    ("番茄红", "#FF6347"), ("鲑鱼色", "#FA8072"), ("青绿", "#008080"),
    ("橄榄色", "#556B2F"), ("亚麻色", "#FAF0E6"), ("象牙白", "#FFFFF0"),
    ("香槟金", "#F7E7CE"), ("宝石蓝", "#1F3A5F"), ("祖母绿", "#2E8B57"),
]

# ========================
# UI 引用
# ========================
root = None
canvas = None
lbl_name = None
lbl_hex = None
lbl_rgb = None
lbl_hsl = None
lbl_cmyk = None
lbl_match = None
lbl_detail = None
theme_btns = []
all_widgets = []

cur_color = "#FF0000"
cur_color_name = "中国红"

# ========================
# 颜色工具
# ========================
def hex_to_rgb(hex_str):
    """#RRGGBB → (R,G,B)"""
    hex_str = hex_str.lstrip("#")
    return tuple(int(hex_str[i:i+2], 16) for i in (0, 2, 4))

def rgb_to_hex(rgb):
    """(R,G,B) → #RRGGBB"""
    r, g, b = rgb
    return f"#{r:02x}{g:02x}{b:02x}"

def rgb_to_hsl(rgb):
    """RGB → HSL"""
    r, g, b = [x / 255 for x in rgb]
    mx = max(r, g, b)
    mn = min(r, g, b)
    diff = mx - mn

    # Lightness
    l = (mx + mn) / 2

    if diff == 0:
        h = s = 0
    else:
        # Saturation
        s = diff / (1 - abs(2 * l - 1)) if l > 0 and l < 1 else 0
        # Hue
        if mx == r:
            h = (60 * ((g - b) / diff) + 360) % 360
        elif mx == g:
            h = (60 * ((b - r) / diff) + 120) % 360
        else:
            h = (60 * ((r - g) / diff) + 240) % 360

    return (round(h, 1), round(s * 100, 1), round(l * 100, 1))

def rgb_to_cmyk(rgb):
    """RGB → CMYK"""
    r, g, b = [x / 255 for x in rgb]
    k = 1 - max(r, g, b)
    if k == 1:
        return (0, 0, 0, 100)
    c = (1 - r - k) / (1 - k)
    m = (1 - g - k) / (1 - k)
    y = (1 - b - k) / (1 - k)
    return (round(c * 100, 1), round(m * 100, 1), round(y * 100, 1), round(k * 100, 1))

def color_distance(rgb1, rgb2):
    """两个颜色的欧氏距离"""
    return math.sqrt(sum((a - b) ** 2 for a, b in zip(rgb1, rgb2)))

def find_closest_color(hex_str):
    """找到最接近的命名颜色"""
    rgb = hex_to_rgb(hex_str)
    closest = min(COLOR_DB, key=lambda x: color_distance(rgb, hex_to_rgb(x[1])))
    return closest

def get_brightness(rgb):
    """亮度 (0-255)"""
    r, g, b = rgb
    return int(0.299 * r + 0.587 * g + 0.114 * b)

def get_text_color_on_bg(hex_str):
    """在背景上用什么文字色"""
    rgb = hex_to_rgb(hex_str)
    return "#FFFFFF" if get_brightness(rgb) < 128 else "#212121"

def get_color_temperature(hex_str):
    """色温判断"""
    r, g, b = hex_to_rgb(hex_str)
    if r > b + 20:
        return "暖色 🔥"
    elif b > r + 20:
        return "冷色 ❄️"
    else:
        return "中性 ⚖️"

# ========================
# 调色板生成
# ========================
def generate_palette(hex_str, mode="complementary"):
    """生成配色方案"""
    r, g, b = hex_to_rgb(hex_str)
    h, s, l = rgb_to_hsl((r, g, b))

    palettes = {}

    if mode == "complementary":
        # 互补色
        h2 = (h + 180) % 360
        rgb2 = hsl_to_rgb((h2, s, l))
        palettes["互补色"] = rgb_to_hex(rgb2)
        # 三角色
        h3 = (h + 120) % 360
        h4 = (h + 240) % 360
        palettes["三角色 1"] = rgb_to_hex(hsl_to_rgb((h3, s, l)))
        palettes["三角色 2"] = rgb_to_hex(hsl_to_rgb((h4, s, l)))

    elif mode == "analogous":
        # 邻近色
        for i, offset in enumerate([-30, -15, 15, 30]):
            h2 = (h + offset) % 360
            palettes[f"邻近 {offset}°"] = rgb_to_hex(hsl_to_rgb((h2, s, l)))

    elif mode == "monochromatic":
        # 同色系
        for i, dl in enumerate([-20, -10, 10, 20]):
            ll = clamp(l + dl, 5, 95)
            palettes[f"明度 {dl:+d}%"] = rgb_to_hex(hsl_to_rgb((h, s, ll)))

    elif mode == "split":
        # 分裂互补
        for offset in [150, 210]:
            h2 = (h + offset) % 360
            palettes[f"分裂 {offset}°"] = rgb_to_hex(hsl_to_rgb((h2, s, l)))

    return palettes

def hsl_to_rgb(hsl):
    """HSL → RGB"""
    h, s, l = hsl
    h /= 360
    s /= 100
    l /= 100

    if s == 0:
        r = g = b = int(l * 255)
        return (r, g, b)

    if l < 0.5:
        q = l * (1 + s)
    else:
        q = l + s - l * s
    p = 2 * l - q

    def hue_to_rgb(p, q, t):
        if t < 0: t += 1
        if t > 1: t -= 1
        if t < 1/6: return p + (q - p) * 6 * t
        if t < 1/2: return q
        if t < 2/3: return p + (q - p) * (2/3 - t) * 6
        return p

    r = int(hue_to_rgb(p, q, h + 1/3) * 255)
    g = int(hue_to_rgb(p, q, h) * 255)
    b = int(hue_to_rgb(p, q, h - 1/3) * 255)
    return (r, g, b)

def clamp(v, lo, hi):
    return max(lo, min(hi, v))

# ========================
# 绘制
# ========================
def draw_color_display():
    """绘制颜色展示区"""
    canvas.delete("all")
    t = THEMES[cur_theme]

    # 主色块
    cx = WIDTH // 2
    cy = 80
    size = 120

    canvas.create_rectangle(cx - size, cy - size//2, cx + size, cy + size//2,
                            fill=cur_color, outline="#333", width=3)

    # 颜色名
    txt_color = get_text_color_on_bg(cur_color)
    canvas.create_text(cx, cy - 10, text=cur_color_name,
                       font=("Comic Sans MS", 18, "bold"), fill=txt_color)
    canvas.create_text(cx, cy + 18, text=cur_color.upper(),
                       font=("Comic Sans MS", 14), fill=txt_color)

    # RGB条
    r, g, b = hex_to_rgb(cur_color)
    bar_y = cy + size//2 + 20
    bar_w = 60
    bar_x = cx - 105

    # R
    canvas.create_rectangle(bar_x, bar_y, bar_x + bar_w, bar_y + 16, fill="#F44336", outline="")
    canvas.create_rectangle(bar_x, bar_y, bar_x + int(bar_w * r / 255), bar_y + 16, fill="#FFCDD2", outline="")
    canvas.create_text(bar_x + bar_w + 25, bar_y + 8, text=f"R:{r}", font=("Consolas", 10), fill=t["fg"])

    # G
    bar_y2 = bar_y + 20
    canvas.create_rectangle(bar_x, bar_y2, bar_x + bar_w, bar_y2 + 16, fill="#4CAF50", outline="")
    canvas.create_rectangle(bar_x, bar_y2, bar_x + int(bar_w * g / 255), bar_y2 + 16, fill="#C8E6C9", outline="")
    canvas.create_text(bar_x + bar_w + 25, bar_y2 + 8, text=f"G:{g}", font=("Consolas", 10), fill=t["fg"])

    # B
    bar_y3 = bar_y2 + 20
    canvas.create_rectangle(bar_x, bar_y3, bar_x + bar_w, bar_y3 + 16, fill="#2196F3", outline="")
    canvas.create_rectangle(bar_x, bar_y3, bar_x + int(bar_w * b / 255), bar_y3 + 16, fill="#BBDEFB", outline="")
    canvas.create_text(bar_x + bar_w + 25, bar_y3 + 8, text=f"B:{b}", font=("Consolas", 10), fill=t["fg"])

    # 色温
    temp = get_color_temperature(cur_color)
    canvas.create_text(cx, bar_y3 + 30, text=f"🌡️ 色温：{temp}",
                       font=("Comic Sans MS", 11), fill=t["accent"])

    # 配色方案
    py = bar_y3 + 55
    canvas.create_text(cx, py, text="🎨 配色方案", font=("Comic Sans MS", 11, "bold"), fill=t["fg"])

    modes = [("互补+三角", "complementary"), ("邻近色", "analogous"),
             ("同色系", "monochromatic"), ("分裂互补", "split")]
    mode_names = ["互补+三角", "邻近色", "同色系", "分裂互补"]
    palettes = generate_palette(cur_color, "complementary")
    palettes2 = generate_palette(cur_color, "analogous")
    palettes3 = generate_palette(cur_color, "monochromatic")
    palettes4 = generate_palette(cur_color, "split")

    all_palettes = [palettes, palettes2, palettes3, palettes4]

    py += 20
    sw = 50
    for idx, (pals, mname) in enumerate(zip(all_palettes, mode_names)):
        sx = cx - 130
        canvas.create_text(sx - 10, py, text=f"{mname}:", font=("Comic Sans MS", 9), fill=t["fg"], anchor="e")
        for j, (pname, phex) in enumerate(list(pals.items())[:4]):
            px = sx + j * (sw + 5)
            canvas.create_rectangle(px, py - 12, px + sw, py + 12, fill=phex, outline="#666")
            ptxt = get_text_color_on_bg(phex)
            canvas.create_text(px + sw//2, py, text=phex, font=("Consolas", 7), fill=ptxt)
        py += 30

def draw_color_wheel():
    """绘制色轮"""
    canvas.delete("wheel")
    t = THEMES[cur_theme]

    # 小色轮
    wx = 90
    wy = 60
    r = 50
    for angle in range(360):
        rad = math.radians(angle)
        x1 = wx + r * math.cos(rad)
        y1 = wy + r * math.sin(rad)
        x2 = wx + (r+1) * math.cos(rad)
        y2 = wy + (r+1) * math.sin(rad)
        color = rgb_to_hex(hsl_to_rgb((angle, 80, 50)))
        canvas.create_line(x1, y1, x2, y2, fill=color, width=2, tags="wheel")

    canvas.create_oval(wx-r-2, wy-r-2, wx+r+2, wy+r+2, outline="#666", tags="wheel")
    canvas.create_text(wx, wy + r + 15, text="色轮", font=("Comic Sans MS", 9), fill=t["fg"], tags="wheel")

    # 当前颜色在色轮上的位置
    h, _, _ = rgb_to_hsl(hex_to_rgb(cur_color))
    rad = math.radians(h)
    mx = wx + (r+8) * math.cos(rad)
    my = wy + (r+8) * math.sin(rad)
    canvas.create_oval(mx-5, my-5, mx+5, my+5, fill=cur_color, outline="#333", width=2, tags="wheel")

# ========================
# 更新信息
# ========================
def update_info():
    """更新信息面板"""
    rgb = hex_to_rgb(cur_color)
    h, s, l = rgb_to_hsl(rgb)
    c, m, y_c, k = rgb_to_cmyk(rgb)

    lbl_hex.config(text=f"HEX: {cur_color.upper()}")
    lbl_rgb.config(text=f"RGB: ({rgb[0]}, {rgb[1]}, {rgb[2]})")
    lbl_hsl.config(text=f"HSL: ({h}°, {s}%, {l}%)")
    lbl_cmyk.config(text=f"CMYK: ({c}%, {m}%, {y_c}%, {k}%)")

    # 最匹配颜色
    closest_name, closest_hex = find_closest_color(cur_color)
    lbl_match.config(text=f"🎯 最接近：{closest_name} ({closest_hex.upper()})")

    # 亮度
    bright = get_brightness(rgb)
    lbl_detail.config(text=f"💡 亮度: {bright}/255 | 🌡️ 色温: {get_color_temperature(cur_color)}")

    draw_color_display()
    draw_color_wheel()

# ========================
# 颜色选择
# ========================
def pick_color():
    """弹出颜色选择器"""
    global cur_color, cur_color_name
    result = colorchooser.askcolor(title="选择颜色", initialcolor=cur_color)
    if result and result[1]:
        cur_color = result[1]
        name, _ = find_closest_color(cur_color)
        cur_color_name = name
        update_info()

def set_color(hex_str, name=None):
    """设置颜色"""
    global cur_color, cur_color_name
    cur_color = hex_str
    if name:
        cur_color_name = name
    else:
        n, _ = find_closest_color(cur_color)
        cur_color_name = n
    update_info()

def random_color():
    """随机颜色"""
    r = random.randint(0, 255)
    g = random.randint(0, 255)
    b = random.randint(0, 255)
    set_color(rgb_to_hex((r, g, b)))

# ========================
# 颜色混合
# ========================
def mix_colors():
    """混合两种颜色"""
    try:
        c1 = entry_mix1.get().strip()
        c2 = entry_mix2.get().strip()
        ratio = float(entry_ratio.get().strip()) / 100

        if not c1.startswith("#"):
            c1 = "#" + c1
        if not c2.startswith("#"):
            c2 = "#" + c2

        r1, g1, b1 = hex_to_rgb(c1)
        r2, g2, b2 = hex_to_rgb(c2)

        rm = int(r1 * (1 - ratio) + r2 * ratio)
        gm = int(g1 * (1 - ratio) + g2 * ratio)
        bm = int(b1 * (1 - ratio) + b2 * ratio)

        result_hex = rgb_to_hex((rm, gm, bm))
        set_color(result_hex)
        lbl_mix_result.config(text=f"✅ 混合结果: {result_hex.upper()}",
                              fg="#4CAF50")
    except Exception as e:
        lbl_mix_result.config(text=f"❌ 格式错误，请用 #RRGGBB 格式", fg="#F44336")

# ========================
# 换肤
# ========================
def apply_theme(name):
    global cur_theme
    cur_theme = name
    t = THEMES[name]

    root.config(bg=t["bg"])
    for w in all_widgets:
        try:
            w.config(bg=t["bg"], fg=t["fg"])
        except:
            pass

    for btn in theme_btns:
        btn.config(bg=t["btn"], fg="white")

    update_info()

# ========================
# 构建界面
# ========================
def build_ui():
    global root, canvas, lbl_name, lbl_hex, lbl_rgb, lbl_hsl, lbl_cmyk
    global lbl_match, lbl_detail, entry_mix1, entry_mix2, entry_ratio
    global lbl_mix_result, theme_btns, all_widgets

    root = tk.Tk()
    root.title("🎨 颜色识别器")
    root.geometry(f"{WIDTH}x{HEIGHT}")
    root.resizable(False, False)

    # ====== 顶部 ======
    top = tk.Frame(root)
    top.pack(fill="x", pady=5)

    tk.Label(top, text="🎨 颜色识别器 ✨", font=("Comic Sans MS", 18, "bold")).pack()

    # 主题栏
    tf = tk.Frame(top)
    tf.pack(pady=2)
    tk.Label(tf, text="🎨 ", font=("Comic Sans MS", 9)).pack(side="left")
    for name in THEMES:
        btn = tk.Button(tf, text=name, font=("Comic Sans MS", 8, "bold"),
                         relief="raised", bd=1, padx=4,
                         command=lambda n=name: apply_theme(n))
        btn.pack(side="left", padx=2)
        theme_btns.append(btn)

    # ====== 操作栏 ======
    toolbar = tk.Frame(root)
    toolbar.pack(fill="x", pady=5)

    btn_pick = tk.Button(toolbar, text="🖌️ 选择颜色", font=("Comic Sans MS", 11, "bold"),
                          bg="#E91E63", fg="white", padx=8, command=pick_color)
    btn_pick.pack(side="left", padx=8)

    btn_rand = tk.Button(toolbar, text="🎲 随机颜色", font=("Comic Sans MS", 10),
                          bg="#FF9800", fg="white", command=random_color)
    btn_rand.pack(side="left", padx=5)

    # 手动输入
    tk.Label(toolbar, text="HEX:", font=("Comic Sans MS", 10)).pack(side="left", padx=(15, 3))
    entry_hex = tk.Entry(toolbar, font=("Consolas", 11), width=10, justify="center")
    entry_hex.insert(0, "#FF0000")
    entry_hex.pack(side="left", padx=2)

    def apply_hex():
        v = entry_hex.get().strip()
        if not v.startswith("#"):
            v = "#" + v
        if len(v) == 7:
            set_color(v.upper())

    btn_apply = tk.Button(toolbar, text="✅", font=("Comic Sans MS", 10, "bold"),
                           bg="#4CAF50", fg="white", command=apply_hex)
    btn_apply.pack(side="left", padx=3)

    # ====== 信息面板 ======
    info_bar = tk.Frame(root)
    info_bar.pack(fill="x", pady=2)

    lbl_hex = tk.Label(info_bar, text="HEX: #FF0000", font=("Consolas", 11, "bold"))
    lbl_hex.pack(side="left", padx=12)

    lbl_rgb = tk.Label(info_bar, text="RGB: (255, 0, 0)", font=("Consolas", 10))
    lbl_rgb.pack(side="left", padx=12)

    lbl_hsl = tk.Label(info_bar, text="HSL: (0°, 100%, 50%)", font=("Consolas", 10))
    lbl_hsl.pack(side="left", padx=12)

    lbl_cmyk = tk.Label(info_bar, text="CMYK: (0%, 100%, 100%, 0%)", font=("Consolas", 10))
    lbl_cmyk.pack(side="left", padx=12)

    # ====== 画布 ======
    canvas_frame = tk.Frame(root)
    canvas_frame.pack(fill="both", expand=True, padx=5, pady=3)

    canvas = tk.Canvas(canvas_frame, width=WIDTH-20, height=280, highlightthickness=0)
    canvas.pack(fill="both", expand=True)

    # ====== 匹配 + 混合 ======
    bottom = tk.Frame(root)
    bottom.pack(fill="x", pady=3)

    lbl_match = tk.Label(bottom, text="🎯 最接近：", font=("Comic Sans MS", 11, "bold"))
    lbl_match.pack(side="left", padx=10)

    lbl_detail = tk.Label(bottom, text="", font=("Comic Sans MS", 10))
    lbl_detail.pack(side="left", padx=10)

    # 混合器
    mix_frame = tk.Frame(root)
    mix_frame.pack(fill="x", pady=3)

    tk.Label(mix_frame, text="🧪 颜色混合：", font=("Comic Sans MS", 10, "bold")).pack(side="left", padx=8)

    entry_mix1 = tk.Entry(mix_frame, font=("Consolas", 10), width=8, justify="center")
    entry_mix1.pack(side="left", padx=2)
    entry_mix1.insert(0, "#FF0000")

    tk.Label(mix_frame, text="+").pack(side="left", padx=2)

    entry_mix2 = tk.Entry(mix_frame, font=("Consolas", 10), width=8, justify="center")
    entry_mix2.pack(side="left", padx=2)
    entry_mix2.insert(0, "#0000FF")

    tk.Label(mix_frame, text="比例").pack(side="left", padx=3)
    entry_ratio = tk.Entry(mix_frame, font=("Consolas", 10), width=4, justify="center")
    entry_ratio.pack(side="left", padx=2)
    entry_ratio.insert(0, "50")
    tk.Label(mix_frame, text="%").pack(side="left")

    btn_mix = tk.Button(mix_frame, text="🔀 混合", font=("Comic Sans MS", 10, "bold"),
                         bg="#7B1FA2", fg="white", command=mix_colors)
    btn_mix.pack(side="left", padx=5)

    lbl_mix_result = tk.Label(mix_frame, text="", font=("Comic Sans MS", 10))
    lbl_mix_result.pack(side="left", padx=8)

    # ====== 颜色库 ======
    lib_frame = tk.Frame(root)
    lib_frame.pack(fill="both", expand=True, padx=5, pady=3)

    tk.Label(lib_frame, text="📚 颜色库（点击使用）：", font=("Comic Sans MS", 10, "bold")).pack(anchor="w", padx=5)

    # 颜色按钮区域（用Canvas做滚动）
    color_canvas = tk.Canvas(lib_frame, height=80, highlightthickness=0)
    color_canvas.pack(fill="both", expand=True, padx=3, pady=2)

    color_inner = tk.Frame(color_canvas)
    color_canvas.create_window((0, 0), window=color_inner, anchor="nw")

    # 分组显示
    categories = {
        "🔴 红色系": COLOR_DB[:9],
        "🟠 橙色系": COLOR_DB[9:15],
        "🟡 黄色系": COLOR_DB[15:21],
        "🟢 绿色系": COLOR_DB[21:30],
        "🔵 蓝色系": COLOR_DB[30:39],
        "🟣 紫色系": COLOR_DB[39:45],
        "🩷 粉色系": COLOR_DB[45:51],
        "🟤 棕色系": COLOR_DB[51:57],
    }

    for cat_name, colors in categories.items():
        cat_frame = tk.Frame(color_inner)
        cat_frame.pack(anchor="w", pady=1)
        tk.Label(cat_frame, text=cat_name, font=("Comic Sans MS", 8, "bold"), width=10, anchor="w").pack(side="left")
        for cname, chex in colors:
            btn = tk.Button(cat_frame, text=cname, font=("Comic Sans MS", 7),
                             bg=chex, fg=get_text_color_on_bg(chex),
                             width=7, relief="raised", bd=1,
                             command=lambda h=chex, n=cname: set_color(h, n))
            btn.pack(side="left", padx=1)

    # 底部
    bot = tk.Frame(root)
    bot.pack(fill="x", side="bottom", pady=2)
    tk.Label(bot, text="💡 点击色块使用 | 输入HEX回车确认 | 混合两种颜色看效果",
             font=("Comic Sans MS", 9)).pack()

    # 收集
    all_widgets.extend([top, tf, toolbar, info_bar, bottom, mix_frame,
                        lib_frame, btn_pick, btn_rand, btn_apply,
                        lbl_hex, lbl_rgb, lbl_hsl, lbl_cmyk, lbl_match, lbl_detail])

    # 绑定回车
    entry_hex.bind("<Return>", lambda e: apply_hex())
    entry_ratio.bind("<Return>", lambda e: mix_colors())

# ========================
# 启动
# ========================
def init():
    build_ui()
    apply_theme("🌸 樱花粉")
    set_color("#FF0000", "中国红")
    update_info()

if __name__ == "__main__":
    init()
    root.mainloop()
