-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathanimated_toggle.py
More file actions
215 lines (167 loc) · 6.79 KB
/
Copy pathanimated_toggle.py
File metadata and controls
215 lines (167 loc) · 6.79 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
"""
Animated Toggle Switch Widget for NoSQL2SQL
Apple-style toggle switches with smooth animations
"""
import tkinter as tk
from tkinter import ttk
class AnimatedToggle(tk.Canvas):
"""Apple-style animated toggle switch"""
def __init__(self, parent, width=60, height=30, on_color="#34C759",
off_color="#C7C7CC", callback=None):
super().__init__(parent, width=width, height=height,
highlightthickness=0, cursor="hand2")
self.width = width
self.height = height
self.on_color = on_color
self.off_color = off_color
self.callback = callback
self.state = False
self.animating = False
self.animation_steps = 10
self.animation_delay = 20 # ms
self._create_widgets()
self.bind("<Button-1>", self._on_click)
def _create_widgets(self):
"""Create the toggle switch elements"""
# Background track
self.track = self.create_oval(
2, 2, self.width-2, self.height-2,
fill=self.off_color,
outline="",
tags="track"
)
# Slider knob
knob_size = self.height - 6
self.knob = self.create_oval(
3, 3, 3 + knob_size, 3 + knob_size,
fill="white",
outline="#D0D0D0",
width=1,
tags="knob"
)
def _on_click(self, event):
"""Handle click event"""
if not self.animating:
self.toggle()
def toggle(self):
"""Toggle the switch state with animation"""
self.state = not self.state
self._animate()
if self.callback:
self.callback(self.state)
def set_state(self, state, animate=True):
"""Set the switch state programmatically"""
if self.state != state:
self.state = state
if animate:
self._animate()
else:
self._set_position(1.0 if state else 0.0)
def get_state(self):
"""Get current state"""
return self.state
def _animate(self):
"""Animate the toggle transition"""
self.animating = True
start_pos = 1.0 if not self.state else 0.0
end_pos = 1.0 if self.state else 0.0
self._animate_step(0, start_pos, end_pos)
def _animate_step(self, step, start_pos, end_pos):
"""Perform one step of the animation"""
if step <= self.animation_steps:
# Calculate easing (ease-in-out)
t = step / self.animation_steps
eased_t = t * t * (3.0 - 2.0 * t) # Smoothstep function
current_pos = start_pos + (end_pos - start_pos) * eased_t
self._set_position(current_pos)
self.after(self.animation_delay,
lambda: self._animate_step(step + 1, start_pos, end_pos))
else:
self.animating = False
def _set_position(self, position):
"""Set the knob position (0.0 = off, 1.0 = on)"""
# Update track color
if position > 0.5:
# Interpolate color
ratio = (position - 0.5) * 2
color = self._interpolate_color(self.off_color, self.on_color, ratio)
else:
color = self.off_color
self.itemconfig(self.track, fill=color)
# Calculate knob position
knob_size = self.height - 6
max_x = self.width - knob_size - 3
min_x = 3
x = min_x + (max_x - min_x) * position
# Move knob
self.coords(self.knob, x, 3, x + knob_size, 3 + knob_size)
def _interpolate_color(self, color1, color2, ratio):
"""Interpolate between two hex colors"""
# Convert hex to RGB
r1, g1, b1 = int(color1[1:3], 16), int(color1[3:5], 16), int(color1[5:7], 16)
r2, g2, b2 = int(color2[1:3], 16), int(color2[3:5], 16), int(color2[5:7], 16)
# Interpolate
r = int(r1 + (r2 - r1) * ratio)
g = int(g1 + (g2 - g1) * ratio)
b = int(b1 + (b2 - b1) * ratio)
return f"#{r:02x}{g:02x}{b:02x}"
def set_colors(self, on_color=None, off_color=None):
"""Update toggle colors"""
if on_color:
self.on_color = on_color
if off_color:
self.off_color = off_color
# Refresh display
self._set_position(1.0 if self.state else 0.0)
class LabeledToggle(ttk.Frame):
"""Toggle switch with label"""
def __init__(self, parent, text="", on_color="#34C759", off_color="#C7C7CC",
callback=None, **kwargs):
super().__init__(parent, **kwargs)
self.label = ttk.Label(self, text=text)
self.label.pack(side=tk.LEFT, padx=(0, 10))
self.toggle = AnimatedToggle(self, on_color=on_color,
off_color=off_color, callback=callback)
self.toggle.pack(side=tk.LEFT)
def set_state(self, state, animate=True):
"""Set toggle state"""
self.toggle.set_state(state, animate)
def get_state(self):
"""Get toggle state"""
return self.toggle.get_state()
def set_text(self, text):
"""Update label text"""
self.label.config(text=text)
if __name__ == "__main__":
# Test the animated toggle
root = tk.Tk()
root.title("Animated Toggle Test")
root.geometry("400x400")
root.configure(bg="#FFFFFF")
frame = ttk.Frame(root, padding="20")
frame.pack(fill=tk.BOTH, expand=True)
ttk.Label(frame, text="Toggle Switch Demo",
font=("Arial", 16, "bold")).pack(pady=10)
# Status label
status_label = ttk.Label(frame, text="Status: OFF", font=("Arial", 12))
status_label.pack(pady=10)
def on_toggle(state):
status_label.config(text=f"Status: {'ON' if state else 'OFF'}")
print(f"Toggle changed to: {state}")
# Simple toggle
ttk.Label(frame, text="Simple Toggle:").pack(pady=(20, 5))
toggle1 = AnimatedToggle(frame, callback=on_toggle)
toggle1.pack(pady=5)
# Labeled toggles
ttk.Label(frame, text="Labeled Toggles:").pack(pady=(20, 5))
LabeledToggle(frame, text="Dark Mode", callback=lambda s: print(f"Dark Mode: {s}")).pack(pady=5, fill=tk.X)
LabeledToggle(frame, text="MCP Enabled", callback=lambda s: print(f"MCP: {s}")).pack(pady=5, fill=tk.X)
LabeledToggle(frame, text="AI Recommendations",
on_color="#0A84FF",
callback=lambda s: print(f"AI: {s}")).pack(pady=5, fill=tk.X)
# Test button
def test_animation():
toggle1.toggle()
ttk.Button(frame, text="Toggle Programmatically",
command=test_animation).pack(pady=20)
root.mainloop()