Skip to content

Commit ab2f1a6

Browse files
bpo-35675: IDLE - separate config_key window and frame (GH-11427)
bpo-35598: IDLE: Refactor window and frame class Co-authored-by: Terry Jan Reedy <[email protected]> (cherry picked from commit 1cc308d) Co-authored-by: Cheryl Sabella <[email protected]>
1 parent 6537bc9 commit ab2f1a6

File tree

4 files changed

+174
-82
lines changed

4 files changed

+174
-82
lines changed

Lib/idlelib/config_key.py

+82-55
Original file line numberDiff line numberDiff line change
@@ -41,32 +41,22 @@ def translate_key(key, modifiers):
4141
return f'Key-{key}'
4242

4343

44-
class GetKeysDialog(Toplevel):
44+
class GetKeysFrame(Frame):
4545

4646
# Dialog title for invalid key sequence
4747
keyerror_title = 'Key Sequence Error'
4848

49-
def __init__(self, parent, title, action, current_key_sequences,
50-
*, _htest=False, _utest=False):
49+
def __init__(self, parent, action, current_key_sequences):
5150
"""
5251
parent - parent of this dialog
53-
title - string which is the title of the popup dialog
54-
action - string, the name of the virtual event these keys will be
52+
action - the name of the virtual event these keys will be
5553
mapped to
56-
current_key_sequences - list, a list of all key sequence lists
54+
current_key_sequences - a list of all key sequence lists
5755
currently mapped to virtual events, for overlap checking
58-
_htest - bool, change box location when running htest
59-
_utest - bool, do not wait when running unittest
6056
"""
61-
Toplevel.__init__(self, parent)
62-
self.withdraw() # Hide while setting geometry.
63-
self.configure(borderwidth=5)
64-
self.resizable(height=False, width=False)
65-
self.title(title)
66-
self.transient(parent)
67-
_setup_dialog(self)
68-
self.grab_set()
69-
self.protocol("WM_DELETE_WINDOW", self.cancel)
57+
super().__init__(parent)
58+
self['borderwidth'] = 2
59+
self['relief'] = 'sunken'
7060
self.parent = parent
7161
self.action = action
7262
self.current_key_sequences = current_key_sequences
@@ -82,39 +72,14 @@ def __init__(self, parent, title, action, current_key_sequences,
8272
self.modifier_vars.append(variable)
8373
self.advanced = False
8474
self.create_widgets()
85-
self.update_idletasks()
86-
self.geometry(
87-
"+%d+%d" % (
88-
parent.winfo_rootx() +
89-
(parent.winfo_width()/2 - self.winfo_reqwidth()/2),
90-
parent.winfo_rooty() +
91-
((parent.winfo_height()/2 - self.winfo_reqheight()/2)
92-
if not _htest else 150)
93-
) ) # Center dialog over parent (or below htest box).
94-
if not _utest:
95-
self.deiconify() # Geometry set, unhide.
96-
self.wait_window()
9775

9876
def showerror(self, *args, **kwargs):
9977
# Make testing easier. Replace in #30751.
10078
messagebox.showerror(*args, **kwargs)
10179

10280
def create_widgets(self):
103-
self.frame = frame = Frame(self, borderwidth=2, relief='sunken')
104-
frame.pack(side='top', expand=True, fill='both')
105-
106-
frame_buttons = Frame(self)
107-
frame_buttons.pack(side='bottom', fill='x')
108-
109-
self.button_ok = Button(frame_buttons, text='OK',
110-
width=8, command=self.ok)
111-
self.button_ok.grid(row=0, column=0, padx=5, pady=5)
112-
self.button_cancel = Button(frame_buttons, text='Cancel',
113-
width=8, command=self.cancel)
114-
self.button_cancel.grid(row=0, column=1, padx=5, pady=5)
115-
11681
# Basic entry key sequence.
117-
self.frame_keyseq_basic = Frame(frame, name='keyseq_basic')
82+
self.frame_keyseq_basic = Frame(self, name='keyseq_basic')
11883
self.frame_keyseq_basic.grid(row=0, column=0, sticky='nsew',
11984
padx=5, pady=5)
12085
basic_title = Label(self.frame_keyseq_basic,
@@ -127,7 +92,7 @@ def create_widgets(self):
12792
basic_keys.pack(ipadx=5, ipady=5, fill='x')
12893

12994
# Basic entry controls.
130-
self.frame_controls_basic = Frame(frame)
95+
self.frame_controls_basic = Frame(self)
13196
self.frame_controls_basic.grid(row=1, column=0, sticky='nsew', padx=5)
13297

13398
# Basic entry modifiers.
@@ -169,7 +134,7 @@ def create_widgets(self):
169134
self.button_clear.grid(row=2, column=0, columnspan=4)
170135

171136
# Advanced entry key sequence.
172-
self.frame_keyseq_advanced = Frame(frame, name='keyseq_advanced')
137+
self.frame_keyseq_advanced = Frame(self, name='keyseq_advanced')
173138
self.frame_keyseq_advanced.grid(row=0, column=0, sticky='nsew',
174139
padx=5, pady=5)
175140
advanced_title = Label(self.frame_keyseq_advanced, justify='left',
@@ -181,7 +146,7 @@ def create_widgets(self):
181146
self.advanced_keys.pack(fill='x')
182147

183148
# Advanced entry help text.
184-
self.frame_help_advanced = Frame(frame)
149+
self.frame_help_advanced = Frame(self)
185150
self.frame_help_advanced.grid(row=1, column=0, sticky='nsew', padx=5)
186151
help_advanced = Label(self.frame_help_advanced, justify='left',
187152
text="Key bindings are specified using Tkinter keysyms as\n"+
@@ -196,7 +161,7 @@ def create_widgets(self):
196161
help_advanced.grid(row=0, column=0, sticky='nsew')
197162

198163
# Switch between basic and advanced.
199-
self.button_level = Button(frame, command=self.toggle_level,
164+
self.button_level = Button(self, command=self.toggle_level,
200165
text='<< Basic Key Binding Entry')
201166
self.button_level.grid(row=2, column=0, stick='ew', padx=5, pady=5)
202167
self.toggle_level()
@@ -257,21 +222,16 @@ def clear_key_seq(self):
257222
variable.set('')
258223
self.key_string.set('')
259224

260-
def ok(self, event=None):
225+
def ok(self):
226+
self.result = ''
261227
keys = self.key_string.get().strip()
262228
if not keys:
263229
self.showerror(title=self.keyerror_title, parent=self,
264230
message="No key specified.")
265231
return
266232
if (self.advanced or self.keys_ok(keys)) and self.bind_ok(keys):
267233
self.result = keys
268-
self.grab_release()
269-
self.destroy()
270-
271-
def cancel(self, event=None):
272-
self.result = ''
273-
self.grab_release()
274-
self.destroy()
234+
return
275235

276236
def keys_ok(self, keys):
277237
"""Validity check on user's 'basic' keybinding selection.
@@ -319,6 +279,73 @@ def bind_ok(self, keys):
319279
return True
320280

321281

282+
class GetKeysWindow(Toplevel):
283+
284+
def __init__(self, parent, title, action, current_key_sequences,
285+
*, _htest=False, _utest=False):
286+
"""
287+
parent - parent of this dialog
288+
title - string which is the title of the popup dialog
289+
action - string, the name of the virtual event these keys will be
290+
mapped to
291+
current_key_sequences - list, a list of all key sequence lists
292+
currently mapped to virtual events, for overlap checking
293+
_htest - bool, change box location when running htest
294+
_utest - bool, do not wait when running unittest
295+
"""
296+
super().__init__(parent)
297+
self.withdraw() # Hide while setting geometry.
298+
self['borderwidth'] = 5
299+
self.resizable(height=False, width=False)
300+
# Needed for winfo_reqwidth().
301+
self.update_idletasks()
302+
# Center dialog over parent (or below htest box).
303+
x = (parent.winfo_rootx() +
304+
(parent.winfo_width()//2 - self.winfo_reqwidth()//2))
305+
y = (parent.winfo_rooty() +
306+
((parent.winfo_height()//2 - self.winfo_reqheight()//2)
307+
if not _htest else 150))
308+
self.geometry(f"+{x}+{y}")
309+
310+
self.title(title)
311+
self.frame = frame = GetKeysFrame(self, action, current_key_sequences)
312+
self.protocol("WM_DELETE_WINDOW", self.cancel)
313+
frame_buttons = Frame(self)
314+
self.button_ok = Button(frame_buttons, text='OK',
315+
width=8, command=self.ok)
316+
self.button_cancel = Button(frame_buttons, text='Cancel',
317+
width=8, command=self.cancel)
318+
self.button_ok.grid(row=0, column=0, padx=5, pady=5)
319+
self.button_cancel.grid(row=0, column=1, padx=5, pady=5)
320+
frame.pack(side='top', expand=True, fill='both')
321+
frame_buttons.pack(side='bottom', fill='x')
322+
323+
self.transient(parent)
324+
_setup_dialog(self)
325+
self.grab_set()
326+
if not _utest:
327+
self.deiconify() # Geometry set, unhide.
328+
self.wait_window()
329+
330+
@property
331+
def result(self):
332+
return self.frame.result
333+
334+
@result.setter
335+
def result(self, value):
336+
self.frame.result = value
337+
338+
def ok(self, event=None):
339+
self.frame.ok()
340+
self.grab_release()
341+
self.destroy()
342+
343+
def cancel(self, event=None):
344+
self.result = ''
345+
self.grab_release()
346+
self.destroy()
347+
348+
322349
if __name__ == '__main__':
323350
from unittest import main
324351
main('idlelib.idle_test.test_config_key', verbosity=2, exit=False)

Lib/idlelib/configdialog.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
from tkinter import messagebox
2525

2626
from idlelib.config import idleConf, ConfigChanges
27-
from idlelib.config_key import GetKeysDialog
27+
from idlelib.config_key import GetKeysWindow
2828
from idlelib.dynoption import DynOptionMenu
2929
from idlelib import macosx
3030
from idlelib.query import SectionName, HelpSource
@@ -1397,7 +1397,7 @@ def get_new_keys(self):
13971397
for event in key_set_changes:
13981398
current_bindings[event] = key_set_changes[event].split()
13991399
current_key_sequences = list(current_bindings.values())
1400-
new_keys = GetKeysDialog(self, 'Get New Keys', bind_name,
1400+
new_keys = GetKeysWindow(self, 'Get New Keys', bind_name,
14011401
current_key_sequences).result
14021402
if new_keys:
14031403
if self.keyset_source.get(): # Current key set is a built-in.

0 commit comments

Comments
 (0)