Skip to content

Commit 43595c9

Browse files
committed
bpo-35598: IDLE: Refactor window and frame class
1 parent 29c1172 commit 43595c9

File tree

4 files changed

+173
-81
lines changed

4 files changed

+173
-81
lines changed

Lib/idlelib/config_key.py

+81-54
Original file line numberDiff line numberDiff line change
@@ -40,31 +40,22 @@ def translate_key(key, modifiers):
4040
return f'Key-{key}'
4141

4242

43-
class GetKeysDialog(Toplevel):
43+
class GetKeysFrame(Frame):
4444

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

48-
def __init__(self, parent, title, action, current_key_sequences,
49-
*, _htest=False, _utest=False):
48+
def __init__(self, parent, action, current_key_sequences):
5049
"""
5150
parent - parent of this dialog
52-
title - string which is the title of the popup dialog
53-
action - string, the name of the virtual event these keys will be
51+
action - the name of the virtual event these keys will be
5452
mapped to
55-
current_key_sequences - list, a list of all key sequence lists
53+
current_key_sequences - a list of all key sequence lists
5654
currently mapped to virtual events, for overlap checking
57-
_htest - bool, change box location when running htest
58-
_utest - bool, do not wait when running unittest
5955
"""
60-
Toplevel.__init__(self, parent)
61-
self.withdraw() # Hide while setting geometry.
62-
self.configure(borderwidth=5)
63-
self.resizable(height=False, width=False)
64-
self.title(title)
65-
self.transient(parent)
66-
self.grab_set()
67-
self.protocol("WM_DELETE_WINDOW", self.cancel)
56+
super().__init__(parent)
57+
self['borderwidth'] = 2
58+
self['relief'] = 'sunken'
6859
self.parent = parent
6960
self.action = action
7061
self.current_key_sequences = current_key_sequences
@@ -80,39 +71,14 @@ def __init__(self, parent, title, action, current_key_sequences,
8071
self.modifier_vars.append(variable)
8172
self.advanced = False
8273
self.create_widgets()
83-
self.update_idletasks()
84-
self.geometry(
85-
"+%d+%d" % (
86-
parent.winfo_rootx() +
87-
(parent.winfo_width()/2 - self.winfo_reqwidth()/2),
88-
parent.winfo_rooty() +
89-
((parent.winfo_height()/2 - self.winfo_reqheight()/2)
90-
if not _htest else 150)
91-
) ) # Center dialog over parent (or below htest box).
92-
if not _utest:
93-
self.deiconify() # Geometry set, unhide.
94-
self.wait_window()
9574

9675
def showerror(self, *args, **kwargs):
9776
# Make testing easier. Replace in #30751.
9877
messagebox.showerror(*args, **kwargs)
9978

10079
def create_widgets(self):
101-
self.frame = frame = Frame(self, borderwidth=2, relief='sunken')
102-
frame.pack(side='top', expand=True, fill='both')
103-
104-
frame_buttons = Frame(self)
105-
frame_buttons.pack(side='bottom', fill='x')
106-
107-
self.button_ok = Button(frame_buttons, text='OK',
108-
width=8, command=self.ok)
109-
self.button_ok.grid(row=0, column=0, padx=5, pady=5)
110-
self.button_cancel = Button(frame_buttons, text='Cancel',
111-
width=8, command=self.cancel)
112-
self.button_cancel.grid(row=0, column=1, padx=5, pady=5)
113-
11480
# Basic entry key sequence.
115-
self.frame_keyseq_basic = Frame(frame, name='keyseq_basic')
81+
self.frame_keyseq_basic = Frame(self, name='keyseq_basic')
11682
self.frame_keyseq_basic.grid(row=0, column=0, sticky='nsew',
11783
padx=5, pady=5)
11884
basic_title = Label(self.frame_keyseq_basic,
@@ -125,7 +91,7 @@ def create_widgets(self):
12591
basic_keys.pack(ipadx=5, ipady=5, fill='x')
12692

12793
# Basic entry controls.
128-
self.frame_controls_basic = Frame(frame)
94+
self.frame_controls_basic = Frame(self)
12995
self.frame_controls_basic.grid(row=1, column=0, sticky='nsew', padx=5)
13096

13197
# Basic entry modifiers.
@@ -167,7 +133,7 @@ def create_widgets(self):
167133
self.button_clear.grid(row=2, column=0, columnspan=4)
168134

169135
# Advanced entry key sequence.
170-
self.frame_keyseq_advanced = Frame(frame, name='keyseq_advanced')
136+
self.frame_keyseq_advanced = Frame(self, name='keyseq_advanced')
171137
self.frame_keyseq_advanced.grid(row=0, column=0, sticky='nsew',
172138
padx=5, pady=5)
173139
advanced_title = Label(self.frame_keyseq_advanced, justify='left',
@@ -179,7 +145,7 @@ def create_widgets(self):
179145
self.advanced_keys.pack(fill='x')
180146

181147
# Advanced entry help text.
182-
self.frame_help_advanced = Frame(frame)
148+
self.frame_help_advanced = Frame(self)
183149
self.frame_help_advanced.grid(row=1, column=0, sticky='nsew', padx=5)
184150
help_advanced = Label(self.frame_help_advanced, justify='left',
185151
text="Key bindings are specified using Tkinter keysyms as\n"+
@@ -194,7 +160,7 @@ def create_widgets(self):
194160
help_advanced.grid(row=0, column=0, sticky='nsew')
195161

196162
# Switch between basic and advanced.
197-
self.button_level = Button(frame, command=self.toggle_level,
163+
self.button_level = Button(self, command=self.toggle_level,
198164
text='<< Basic Key Binding Entry')
199165
self.button_level.grid(row=2, column=0, stick='ew', padx=5, pady=5)
200166
self.toggle_level()
@@ -255,21 +221,16 @@ def clear_key_seq(self):
255221
variable.set('')
256222
self.key_string.set('')
257223

258-
def ok(self, event=None):
224+
def ok(self):
225+
self.result = ''
259226
keys = self.key_string.get().strip()
260227
if not keys:
261228
self.showerror(title=self.keyerror_title, parent=self,
262229
message="No key specified.")
263230
return
264231
if (self.advanced or self.keys_ok(keys)) and self.bind_ok(keys):
265232
self.result = keys
266-
self.grab_release()
267-
self.destroy()
268-
269-
def cancel(self, event=None):
270-
self.result = ''
271-
self.grab_release()
272-
self.destroy()
233+
return
273234

274235
def keys_ok(self, keys):
275236
"""Validity check on user's 'basic' keybinding selection.
@@ -317,6 +278,72 @@ def bind_ok(self, keys):
317278
return True
318279

319280

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

2525
from idlelib.config import idleConf, ConfigChanges
26-
from idlelib.config_key import GetKeysDialog
26+
from idlelib.config_key import GetKeysWindow
2727
from idlelib.dynoption import DynOptionMenu
2828
from idlelib import macosx
2929
from idlelib.query import SectionName, HelpSource
@@ -1623,7 +1623,7 @@ def get_new_keys(self):
16231623
for event in key_set_changes:
16241624
current_bindings[event] = key_set_changes[event].split()
16251625
current_key_sequences = list(current_bindings.values())
1626-
new_keys = GetKeysDialog(self, 'Get New Keys', bind_name,
1626+
new_keys = GetKeysWindow(self, 'Get New Keys', bind_name,
16271627
current_key_sequences).result
16281628
if new_keys:
16291629
if self.keyset_source.get(): # Current key set is a built-in.

0 commit comments

Comments
 (0)