1
+ """
2
+ GUI components for macOS_application_speedtest_for_python.
3
+ """
4
+ import tkinter as tk
5
+ from tkinter import ttk , messagebox , Menu
6
+ import logging
7
+
8
+ logger = logging .getLogger ("SpeedTest" )
9
+
10
+
11
+ class ResultsFrame (tk .Frame ):
12
+ """Frame for displaying speed test results."""
13
+
14
+ def __init__ (self , master , ** kwargs ):
15
+ super ().__init__ (master , ** kwargs )
16
+
17
+ # Create labels for results
18
+ self .result_title = tk .Label (self , text = "Test Results" , font = ("Helvetica" , 14 , "bold" ))
19
+ self .result_title .pack (pady = (10 , 5 ))
20
+
21
+ # Download speed result
22
+ self .download_frame = tk .Frame (self )
23
+ self .download_frame .pack (fill = "x" , pady = 2 )
24
+
25
+ self .download_label = tk .Label (self .download_frame , text = "Download Speed:" , width = 15 ,
26
+ anchor = "w" )
27
+ self .download_label .pack (side = "left" , padx = 5 )
28
+
29
+ self .download_value = tk .Label (self .download_frame , text = "-- Mbps" , width = 15 , anchor = "e" )
30
+ self .download_value .pack (side = "left" , padx = 5 )
31
+
32
+ # Upload speed result
33
+ self .upload_frame = tk .Frame (self )
34
+ self .upload_frame .pack (fill = "x" , pady = 2 )
35
+
36
+ self .upload_label = tk .Label (self .upload_frame , text = "Upload Speed:" , width = 15 , anchor = "w" )
37
+ self .upload_label .pack (side = "left" , padx = 5 )
38
+
39
+ self .upload_value = tk .Label (self .upload_frame , text = "-- Mbps" , width = 15 , anchor = "e" )
40
+ self .upload_value .pack (side = "left" , padx = 5 )
41
+
42
+ # Ping result
43
+ self .ping_frame = tk .Frame (self )
44
+ self .ping_frame .pack (fill = "x" , pady = 2 )
45
+
46
+ self .ping_label = tk .Label (self .ping_frame , text = "Ping:" , width = 15 , anchor = "w" )
47
+ self .ping_label .pack (side = "left" , padx = 5 )
48
+
49
+ self .ping_value = tk .Label (self .ping_frame , text = "-- ms" , width = 15 , anchor = "e" )
50
+ self .ping_value .pack (side = "left" , padx = 5 )
51
+
52
+ # Timestamp
53
+ self .timestamp_frame = tk .Frame (self )
54
+ self .timestamp_frame .pack (fill = "x" , pady = 2 )
55
+
56
+ self .timestamp_label = tk .Label (self .timestamp_frame , text = "Test Time:" , width = 15 ,
57
+ anchor = "w" )
58
+ self .timestamp_label .pack (side = "left" , padx = 5 )
59
+
60
+ self .timestamp_value = tk .Label (self .timestamp_frame , text = "--" , width = 25 , anchor = "e" )
61
+ self .timestamp_value .pack (side = "left" , padx = 5 )
62
+
63
+ # Initially hide
64
+ self .pack_forget ()
65
+
66
+ def update_results (self , download , upload , ping , timestamp ):
67
+ """Updates the result values."""
68
+ self .download_value .config (text = f"{ download } Mbps" )
69
+ self .upload_value .config (text = f"{ upload } Mbps" )
70
+ self .ping_value .config (text = f"{ ping } ms" )
71
+ self .timestamp_value .config (text = timestamp )
72
+ self .pack (fill = "both" , expand = True , pady = 10 )
73
+
74
+ def clear (self ):
75
+ """Clears the result values."""
76
+ self .download_value .config (text = "-- Mbps" )
77
+ self .upload_value .config (text = "-- Mbps" )
78
+ self .ping_value .config (text = "-- ms" )
79
+ self .timestamp_value .config (text = "--" )
80
+
81
+
82
+ class SettingsWindow :
83
+ """Window for application settings."""
84
+
85
+ def __init__ (self , parent , settings , save_callback ):
86
+ self .parent = parent
87
+ self .settings = settings
88
+ self .save_callback = save_callback
89
+
90
+ # Create a new window
91
+ self .window = tk .Toplevel (parent )
92
+ self .window .title ("Settings" )
93
+ self .window .geometry ("400x300" )
94
+ self .window .resizable (False , False )
95
+ self .window .transient (parent )
96
+ self .window .grab_set ()
97
+
98
+ # Center on parent
99
+ x = parent .winfo_x () + (parent .winfo_width () // 2 ) - (400 // 2 )
100
+ y = parent .winfo_y () + (parent .winfo_height () // 2 ) - (300 // 2 )
101
+ self .window .geometry (f"+{ x } +{ y } " )
102
+
103
+ # Create a frame for settings
104
+ self .frame = tk .Frame (self .window , padx = 20 , pady = 20 )
105
+ self .frame .pack (fill = "both" , expand = True )
106
+
107
+ # Auto save results
108
+ self .auto_save_var = tk .BooleanVar (value = settings .get ("auto_save_results" , True ))
109
+ self .auto_save_check = ttk .Checkbutton (
110
+ self .frame ,
111
+ text = "Automatically save test results" ,
112
+ variable = self .auto_save_var
113
+ )
114
+ self .auto_save_check .pack (anchor = "w" , pady = 5 )
115
+
116
+ # Show network info
117
+ self .show_network_var = tk .BooleanVar (value = settings .get ("show_network_info" , True ))
118
+ self .show_network_check = ttk .Checkbutton (
119
+ self .frame ,
120
+ text = "Show network adapter information" ,
121
+ variable = self .show_network_var
122
+ )
123
+ self .show_network_check .pack (anchor = "w" , pady = 5 )
124
+
125
+ # Dark mode option
126
+ self .dark_mode_var = tk .BooleanVar (value = settings .get ("dark_mode" , False ))
127
+ self .dark_mode_check = ttk .Checkbutton (
128
+ self .frame ,
129
+ text = "Dark mode (requires restart)" ,
130
+ variable = self .dark_mode_var
131
+ )
132
+ self .dark_mode_check .pack (anchor = "w" , pady = 5 )
133
+
134
+ # Create buttons
135
+ self .button_frame = tk .Frame (self .window )
136
+ self .button_frame .pack (fill = "x" , padx = 20 , pady = 20 )
137
+
138
+ self .save_button = ttk .Button (
139
+ self .button_frame ,
140
+ text = "Save" ,
141
+ command = self .save_settings
142
+ )
143
+ self .save_button .pack (side = "right" , padx = 5 )
144
+
145
+ self .cancel_button = ttk .Button (
146
+ self .button_frame ,
147
+ text = "Cancel" ,
148
+ command = self .window .destroy
149
+ )
150
+ self .cancel_button .pack (side = "right" , padx = 5 )
151
+
152
+ def save_settings (self ):
153
+ """Saves the settings and closes the window."""
154
+ self .settings ["auto_save_results" ] = self .auto_save_var .get ()
155
+ self .settings ["show_network_info" ] = self .show_network_var .get ()
156
+ self .settings ["dark_mode" ] = self .dark_mode_var .get ()
157
+
158
+ if self .save_callback :
159
+ self .save_callback (self .settings )
160
+
161
+ self .window .destroy ()
162
+
163
+
164
+ def create_menu (root , settings_callback , about_callback ):
165
+ """Creates the application menu bar."""
166
+ menubar = Menu (root )
167
+
168
+ # File menu
169
+ file_menu = Menu (menubar , tearoff = 0 )
170
+ file_menu .add_command (label = "Settings" , command = settings_callback )
171
+ file_menu .add_separator ()
172
+ file_menu .add_command (label = "Exit" , command = root .quit )
173
+ menubar .add_cascade (label = "File" , menu = file_menu )
174
+
175
+ # Tools menu
176
+ tools_menu = Menu (menubar , tearoff = 0 )
177
+ tools_menu .add_command (label = "Export All History" , command = lambda : messagebox .showinfo (
178
+ "Feature Coming Soon" , "This feature will be available in the next update."
179
+ ))
180
+ tools_menu .add_command (label = "Clear History" , command = lambda : messagebox .showinfo (
181
+ "Feature Coming Soon" , "This feature will be available in the next update."
182
+ ))
183
+ menubar .add_cascade (label = "Tools" , menu = tools_menu )
184
+
185
+ # Help menu
186
+ help_menu = Menu (menubar , tearoff = 0 )
187
+ help_menu .add_command (label = "View Help" , command = lambda : messagebox .showinfo (
188
+ "Help" ,
189
+ "For help and documentation, please visit: https://github.com/AlexTkDev/"
190
+ "macOS_application_speedtest_for_python"
191
+ ))
192
+ help_menu .add_separator ()
193
+ help_menu .add_command (label = "About" , command = about_callback )
194
+ menubar .add_cascade (label = "Help" , menu = help_menu )
195
+
196
+ root .config (menu = menubar )
197
+
198
+ return menubar
199
+
200
+
201
+ def show_about_dialog (parent ):
202
+ """Shows the About dialog."""
203
+ from speedtest_app import __version__
204
+
205
+ about_window = tk .Toplevel (parent )
206
+ about_window .title ("About Internet Speed Test" )
207
+ about_window .geometry ("300x200" )
208
+ about_window .resizable (False , False )
209
+ about_window .transient (parent )
210
+ about_window .grab_set ()
211
+
212
+ # Center on parent
213
+ x = parent .winfo_x () + (parent .winfo_width () // 2 ) - (300 // 2 )
214
+ y = parent .winfo_y () + (parent .winfo_height () // 2 ) - (200 // 2 )
215
+ about_window .geometry (f"+{ x } +{ y } " )
216
+
217
+ # App name and version
218
+ app_name = tk .Label (about_window , text = "Internet Speed Test" , font = ("Helvetica" , 16 , "bold" ))
219
+ app_name .pack (pady = (20 , 5 ))
220
+
221
+ version = tk .Label (about_window , text = f"Version { __version__ } " )
222
+ version .pack ()
223
+
224
+ # Separator
225
+ separator = ttk .Separator (about_window , orient = "horizontal" )
226
+ separator .pack (fill = "x" , padx = 20 , pady = 10 )
227
+
228
+ # Developer info
229
+ dev_info = tk .Label (about_window , text = "Developed by Aleksandr" )
230
+ dev_info .pack ()
231
+
232
+ # Copyright info
233
+ copyright_info = tk .Label (about_window , text = "© 2024 Aleksandr. MIT License" )
234
+ copyright_info .pack ()
235
+
236
+ # Close button
237
+ close_button = ttk .Button (about_window , text = "Close" , command = about_window .destroy )
238
+ close_button .pack (pady = 20 )
0 commit comments