# -*- coding: UTF-8 -*-
# Robot Arm Manual Controller (4-Group Sync)
# 对应 Arduino: 接收 ID 1-4
# 功能: 4组滑块控制，内部处理双舵机合并
import tkinter as tk
from tkinter import ttk
import serial
import serial.tools.list_ports
import time

class RobotGUI:
    def __init__(self, root):
        self.root = root
        self.root.title("Robot Arm Manual Control (Sync)")
        self.root.geometry("450x500")
        
        # --- 变量初始化 ---
        self.ser = None
        self.step_size = tk.IntVar(value=1) # 默认步进
        
        # 4组逻辑角度，初始全部 90
        self.angles = {
            1: 90, # Base
            2: 90, # Big Arm (双)
            3: 90, # Mid Arm (双)
            4: 90  # Gripper
        }
        self.labels = {} 

        # --- 构建界面 ---
        self.create_connection_area()
        self.create_step_selector()
        self.create_servo_controls()
        self.create_footer()

    def create_connection_area(self):
        frame = tk.LabelFrame(self.root, text="Connection", padx=10, pady=10)
        frame.pack(fill="x", padx=10, pady=5)

        tk.Label(frame, text="Port:").pack(side="left")
        self.port_combo = ttk.Combobox(frame, width=15)
        self.port_combo.pack(side="left", padx=5)
        
        tk.Button(frame, text="Refresh", command=self.refresh_ports).pack(side="left")
        self.btn_connect = tk.Button(frame, text="Connect", command=self.toggle_connection, bg="#DDDDDD")
        self.btn_connect.pack(side="left", padx=5)
        self.refresh_ports()

    def create_step_selector(self):
        frame = tk.LabelFrame(self.root, text="Step Size", padx=10, pady=10)
        frame.pack(fill="x", padx=10, pady=5)
        
        tk.Radiobutton(frame, text="1°", variable=self.step_size, value=1).pack(side="left", padx=20)
        tk.Radiobutton(frame, text="5°", variable=self.step_size, value=5).pack(side="left", padx=20)
        tk.Radiobutton(frame, text="10°", variable=self.step_size, value=10).pack(side="left", padx=20)

    def create_servo_controls(self):
        frame = tk.LabelFrame(self.root, text="Joint Control (Dual Servos Synced)", padx=10, pady=10)
        frame.pack(fill="both", expand=True, padx=10, pady=5)

        # 4 行控制条
        self.create_servo_row(frame, 1, "Base (Pin 41)")
        self.create_servo_row(frame, 2, "Big Arm (43 & 45)")
        self.create_servo_row(frame, 3, "Mid Arm (47 & 49)")
        self.create_servo_row(frame, 4, "Gripper (Pin 51)")

    def create_servo_row(self, parent, servo_id, name):
        row = tk.Frame(parent)
        row.pack(fill="x", pady=10)

        tk.Label(row, text=name, width=18, anchor="w", font=("Arial", 10)).pack(side="left")
        
        tk.Button(row, text="  <  ", command=lambda: self.move_servo(servo_id, -1)).pack(side="left")
        
        lbl = tk.Label(row, text=str(self.angles[servo_id]), width=6, font=("Arial", 14, "bold"), fg="blue")
        lbl.pack(side="left", padx=15)
        self.labels[servo_id] = lbl
        
        tk.Button(row, text="  >  ", command=lambda: self.move_servo(servo_id, 1)).pack(side="left")

    def create_footer(self):
        tk.Button(self.root, text="RESET ALL TO 90°", command=self.go_home, bg="#FFCCCC", height=2).pack(fill="x", padx=10, pady=15)

    # --- 逻辑功能 ---

    def refresh_ports(self):
        ports = [p.device for p in serial.tools.list_ports.comports()]
        self.port_combo['values'] = ports
        if ports: self.port_combo.current(0)

    def toggle_connection(self):
        if self.ser and self.ser.is_open:
            self.ser.close()
            self.btn_connect.config(text="Connect", bg="#DDDDDD")
        else:
            try:
                port = self.port_combo.get()
                self.ser = serial.Serial(port, 9600, timeout=1)
                self.btn_connect.config(text="Connected", bg="#99FF99")
                time.sleep(1.5)
            except Exception as e:
                print(f"Error: {e}")

    def move_servo(self, servo_id, direction):
        step = self.step_size.get()
        current = self.angles[servo_id]
        new_angle = current + (step * direction)

        if new_angle < 0: new_angle = 0
        if new_angle > 180: new_angle = 180

        self.angles[servo_id] = new_angle
        self.labels[servo_id].config(text=str(new_angle))
        self.send_command(servo_id, new_angle)

    def go_home(self):
        for i in range(1, 5):
            self.angles[i] = 90
            self.labels[i].config(text="90")
            self.send_command(i, 90)
            time.sleep(0.05)

    def send_command(self, sid, angle):
        if self.ser and self.ser.is_open:
            cmd = f"{sid}:{angle}\n"
            self.ser.write(cmd.encode())
            print(f"Sent: {cmd.strip()}")
        else:
            print(f"Sim: {sid} -> {angle}")

if __name__ == "__main__":
    root = tk.Tk()
    app = RobotGUI(root)
    root.mainloop()