2626 "tclobjs_to_py" , "setup_master" ]
2727
2828import tkinter
29-
30- _flatten = tkinter ._flatten
29+ from tkinter import _flatten , _join , _stringify
3130
3231# Verify if Tk is new enough to not need the Tile package
3332_REQUIRE_TILE = True if tkinter .TkVersion < 8.5 else False
@@ -47,40 +46,55 @@ def _load_tile(master):
4746 master .tk .eval ('package require tile' ) # TclError may be raised here
4847 master ._tile_loaded = True
4948
49+ def _format_optvalue (value , script = False ):
50+ """Internal function."""
51+ if script :
52+ # if caller passes a Tcl script to tk.call, all the values need to
53+ # be grouped into words (arguments to a command in Tcl dialect)
54+ value = _stringify (value )
55+ elif isinstance (value , (list , tuple )):
56+ value = _join (value )
57+ return value
58+
5059def _format_optdict (optdict , script = False , ignore = None ):
5160 """Formats optdict to a tuple to pass it to tk.call.
5261
5362 E.g. (script=False):
5463 {'foreground': 'blue', 'padding': [1, 2, 3, 4]} returns:
5564 ('-foreground', 'blue', '-padding', '1 2 3 4')"""
56- format = "%s" if not script else "{%s}"
5765
5866 opts = []
5967 for opt , value in optdict .items ():
60- if ignore and opt in ignore :
61- continue
62-
63- if isinstance (value , (list , tuple )):
64- v = []
65- for val in value :
66- if isinstance (val , str ):
67- v .append (str (val ) if val else '{}' )
68- else :
69- v .append (str (val ))
70-
71- # format v according to the script option, but also check for
72- # space in any value in v in order to group them correctly
73- value = format % ' ' .join (
74- ('{%s}' if ' ' in val else '%s' ) % val for val in v )
68+ if not ignore or opt not in ignore :
69+ opts .append ("-%s" % opt )
70+ if value is not None :
71+ opts .append (_format_optvalue (value , script ))
7572
76- if script and value == '' :
77- value = '{}' # empty string in Python is equivalent to {} in Tcl
78-
79- opts .append (("-%s" % opt , value ))
80-
81- # Remember: _flatten skips over None
8273 return _flatten (opts )
8374
75+ def _mapdict_values (items ):
76+ # each value in mapdict is expected to be a sequence, where each item
77+ # is another sequence containing a state (or several) and a value
78+ # E.g. (script=False):
79+ # [('active', 'selected', 'grey'), ('focus', [1, 2, 3, 4])]
80+ # returns:
81+ # ['active selected', 'grey', 'focus', [1, 2, 3, 4]]
82+ opt_val = []
83+ for * state , val in items :
84+ # hacks for bakward compatibility
85+ state [0 ] # raise IndexError if empty
86+ if len (state ) == 1 :
87+ # if it is empty (something that evaluates to False), then
88+ # format it to Tcl code to denote the "normal" state
89+ state = state [0 ] or ''
90+ else :
91+ # group multiple states
92+ state = ' ' .join (state ) # raise TypeError if not str
93+ opt_val .append (state )
94+ if val is not None :
95+ opt_val .append (val )
96+ return opt_val
97+
8498def _format_mapdict (mapdict , script = False ):
8599 """Formats mapdict to pass it to tk.call.
86100
@@ -90,32 +104,11 @@ def _format_mapdict(mapdict, script=False):
90104 returns:
91105
92106 ('-expand', '{active selected} grey focus {1, 2, 3, 4}')"""
93- # if caller passes a Tcl script to tk.call, all the values need to
94- # be grouped into words (arguments to a command in Tcl dialect)
95- format = "%s" if not script else "{%s}"
96107
97108 opts = []
98109 for opt , value in mapdict .items ():
99-
100- opt_val = []
101- # each value in mapdict is expected to be a sequence, where each item
102- # is another sequence containing a state (or several) and a value
103- for statespec in value :
104- state , val = statespec [:- 1 ], statespec [- 1 ]
105-
106- if len (state ) > 1 : # group multiple states
107- state = "{%s}" % ' ' .join (state )
108- else : # single state
109- # if it is empty (something that evaluates to False), then
110- # format it to Tcl code to denote the "normal" state
111- state = state [0 ] or '{}'
112-
113- if isinstance (val , (list , tuple )): # val needs to be grouped
114- val = "{%s}" % ' ' .join (map (str , val ))
115-
116- opt_val .append ("%s %s" % (state , val ))
117-
118- opts .append (("-%s" % opt , format % ' ' .join (opt_val )))
110+ opts .extend (("-%s" % opt ,
111+ _format_optvalue (_mapdict_values (value ), script )))
119112
120113 return _flatten (opts )
121114
@@ -129,7 +122,7 @@ def _format_elemcreate(etype, script=False, *args, **kw):
129122 iname = args [0 ]
130123 # next args, if any, are statespec/value pairs which is almost
131124 # a mapdict, but we just need the value
132- imagespec = _format_mapdict ({ None : args [1 :]})[ 1 ]
125+ imagespec = _join ( _mapdict_values ( args [1 :]))
133126 spec = "%s %s" % (iname , imagespec )
134127
135128 else :
@@ -138,7 +131,7 @@ def _format_elemcreate(etype, script=False, *args, **kw):
138131 # themed styles on Windows XP and Vista.
139132 # Availability: Tk 8.6, Windows XP and Vista.
140133 class_name , part_id = args [:2 ]
141- statemap = _format_mapdict ({ None : args [2 :]})[ 1 ]
134+ statemap = _join ( _mapdict_values ( args [2 :]))
142135 spec = "%s %s %s" % (class_name , part_id , statemap )
143136
144137 opts = _format_optdict (kw , script )
@@ -148,11 +141,11 @@ def _format_elemcreate(etype, script=False, *args, **kw):
148141 # otherwise it will clone {} (empty element)
149142 spec = args [0 ] # theme name
150143 if len (args ) > 1 : # elementfrom specified
151- opts = (args [1 ], )
144+ opts = (_format_optvalue ( args [1 ], script ), )
152145
153146 if script :
154147 spec = '{%s}' % spec
155- opts = ' ' .join (map ( str , opts ) )
148+ opts = ' ' .join (opts )
156149
157150 return spec , opts
158151
@@ -189,7 +182,7 @@ def _format_layoutlist(layout, indent=0, indent_size=2):
189182 for layout_elem in layout :
190183 elem , opts = layout_elem
191184 opts = opts or {}
192- fopts = ' ' .join (map ( str , _format_optdict (opts , True , "children" )))
185+ fopts = ' ' .join (_format_optdict (opts , True , ( "children" , )))
193186 head = "%s%s%s" % (' ' * indent , elem , (" %s" % fopts ) if fopts else '' )
194187
195188 if "children" in opts :
@@ -215,11 +208,11 @@ def _script_from_settings(settings):
215208 for name , opts in settings .items ():
216209 # will format specific keys according to Tcl code
217210 if opts .get ('configure' ): # format 'configure'
218- s = ' ' .join (map ( str , _format_optdict (opts ['configure' ], True ) ))
211+ s = ' ' .join (_format_optdict (opts ['configure' ], True ))
219212 script .append ("ttk::style configure %s %s;" % (name , s ))
220213
221214 if opts .get ('map' ): # format 'map'
222- s = ' ' .join (map ( str , _format_mapdict (opts ['map' ], True ) ))
215+ s = ' ' .join (_format_mapdict (opts ['map' ], True ))
223216 script .append ("ttk::style map %s %s;" % (name , s ))
224217
225218 if 'layout' in opts : # format 'layout' which may be empty
@@ -706,30 +699,9 @@ def __init__(self, master=None, **kw):
706699 exportselection, justify, height, postcommand, state,
707700 textvariable, values, width
708701 """
709- # The "values" option may need special formatting, so leave to
710- # _format_optdict the responsibility to format it
711- if "values" in kw :
712- kw ["values" ] = _format_optdict ({'v' : kw ["values" ]})[1 ]
713-
714702 Entry .__init__ (self , master , "ttk::combobox" , ** kw )
715703
716704
717- def __setitem__ (self , item , value ):
718- if item == "values" :
719- value = _format_optdict ({item : value })[1 ]
720-
721- Entry .__setitem__ (self , item , value )
722-
723-
724- def configure (self , cnf = None , ** kw ):
725- """Custom Combobox configure, created to properly format the values
726- option."""
727- if "values" in kw :
728- kw ["values" ] = _format_optdict ({'v' : kw ["values" ]})[1 ]
729-
730- return Entry .configure (self , cnf , ** kw )
731-
732-
733705 def current (self , newindex = None ):
734706 """If newindex is supplied, sets the combobox value to the
735707 element at position newindex in the list of values. Otherwise,
0 commit comments