1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 from __future__ import division
18
19 import sys
20 import os.path
21 import re
22
23 import Tkinter as tk
24 import tkMessageBox as mb
25 import tkSimpleDialog as sd
26 import tkColorChooser as cc
27 import Pmw
28 import tkFont
29
30 from traits import Trait, HasTraits, TraitError, HasDynamicTraits, \
31 trait_editors
32 from trait_sheet import TraitEditor, TraitSheetHandler, TraitMonitor, \
33 TraitGroup, TraitGroupList, default_trait_sheet_handler
34 from types import DictType, ListType, TupleType, ModuleType, \
35 StringType, FloatType
36
37
38
39
40
41 trait_editors( __name__ )
42
43
44
45
46
47
48 TRUE = 1
49 FALSE = 0
50
51
52 basic_sequence_types = [ ListType, TupleType ]
53
54
55 standard_bitmap_width = 120
56
57
58 WHITE = '#FFFFFF'
59
60
61 color_choices = ( 0, 128, 192, 255 )
62 color_samples = [ None ] * 48
63 i = 0
64 for r in color_choices:
65 for g in color_choices:
66 for b in ( 0, 128, 255 ):
67 color_samples[i] = '#%02X%02X%02X' % ( r, g, b )
68 i += 1
69
70
71 facenames = None
72
73
74 point_sizes = [
75 '8', '9', '10', '11', '12', '14', '16', '18',
76 '20', '22', '24', '26', '28', '36', '48', '72'
77 ]
78
79
80
81 tooltips_enabled = TRUE
82
83
84 all_digits = re.compile( r'\d+' )
85
86
87
88
89
91
92
93
94
95
101 if title is None:
102 title = '%s Traits' % object.__class__.__name__
103 tk.Toplevel.__init__( self, parent )
104 self.title( title )
105 self.bind( '<Destroy>', self.on_close_page )
106 self.bind( '<Escape>', self.on_close_key )
107
108 self.object = object
109 self.handler = handler
110
111
112 TraitSheet( self, object, traits, handler ).grid( row = 0 )
113
114
115
116 if not handler.position( self, object ):
117
118 pass
119
120 self.resizable( FALSE, FALSE )
121
122
123
124
125
126 - def on_close_page ( self, event ):
127 self.handler.close( self, self.object )
128
129
130
131
132
136
137
138
139
140
142
143
144
145
146
148 tk.Frame.__init__( self, parent )
149 pass
150
151
152
153
154
155 - def add ( self, sheet ):
157
158
159
160
161
164
165
166
167
168
171
172
173
174
175
178
179
180
181
182
185
186
187
188
189
191
192
193
194
195
234
235
236
237
238
240
241 nb = Pmw.NoteBook( self )
242 nb.grid( row = 0, column = 0, sticky = 'new' )
243
244 count = 0
245 for pg in traits:
246
247 page_name = pg.label
248 if page_name is None:
249 count += 1
250 page_name = 'Page %d' % count
251 self.add_page( pg, nb.add( page_name ) )
252
253
254 nb.setnaturalsize()
255
256
257
258
259
260 - def add_page ( self, pg, parent, default_style = 'simple' ):
261 default_style = pg.style or default_style
262 object = pg.object or self.object
263 row_incr = col_incr = 0
264 if pg.orientation == 'horizontal':
265 col_incr = 1
266 else:
267 row_incr = 1
268 show_labels = pg.show_labels_
269 row = col = 0
270 cols = 1 + show_labels
271
272 for pge in pg.values:
273 if isinstance( pge, TraitGroup ):
274 if pge.show_border_:
275 box = Pmw.Group( parent, tag_text = pge.label or '' )
276 box.grid( row = row, column = col, sticky = 'new',
277 padx = 4 )
278 frame = tk.Frame( box.interior() )
279 frame.grid( row = 0, column = 0, sticky = 'news',
280 padx = 4, pady = 3 )
281 box.interior().columnconfigure( 0, weight = 1 )
282 self.add_page( pge, frame, default_style )
283 else:
284 self.add_page( pge, parent )
285 if row_incr:
286 parent.columnconfigure( 0, weight = 1 )
287 row += row_incr
288 col += col_incr
289 else:
290 name = pge.name or ' '
291
292 if name == '-':
293 tk.Frame( parent, bg = '#A0A0A0' ).grid(
294 row = row, column = 0, columnspan = cols, sticky = 'ew' )
295 parent.rowconfigure( row, minsize = 9 )
296 row += 1
297 continue
298
299 if name == ' ':
300 name = '5'
301 if all_digits.match( name ):
302 parent.rowconfigure( row, minsize = int( name ) )
303 row += 1
304 continue
305
306 editor = pge.editor
307 style = pge.style or default_style
308 pge_object = pge.object or object
309 if editor is None:
310 try:
311 editor = pge_object._base_trait( name ).get_editor()
312 except:
313 pass
314
315 if editor is None:
316 continue
317 label = None
318 if show_labels:
319 label = pge.label_for( object )
320 self.add_trait( parent, row, object, name, label, editor,
321 style == 'simple' )
322 parent.columnconfigure( 1, weight = 1 )
323
324
325 row += 1
326
327
328 parent.rowconfigure( row, weight = 1 )
329
330
331
332
333
334 - def add_trait ( self, parent, row, object, trait_name, description, editor,
335 is_simple ):
336 global tooltips_enabled
337
338 col = 0
339 if description is not None:
340 suffix = ':'[ description[-1:] == '?': ]
341 label = tk.Label( parent,
342 text = (description + suffix).capitalize(),
343 anchor = 'e' )
344 label.grid( row = row, sticky = 'new', padx = 0, pady = 2 )
345 col = 1
346 desc = object._base_trait( trait_name ).desc
347 if (desc is not None) and tooltips_enabled:
348 if self.tooltip is None:
349 self.tooltip = Pmw.Balloon( self, state = 'balloon' )
350 self.tooltip.bind( label, 'Specifies ' + desc )
351 label.bind( '<B2-ButtonRelease>', self.on_toggle_help )
352 if is_simple:
353 control = editor.simple_editor( object, trait_name, description,
354 self.handler, parent )
355 control.bind( '<B2-ButtonRelease>', editor.on_restore )
356 else:
357 control = editor.custom_editor( object, trait_name, description,
358 self.handler, parent )
359 control.grid( row = row, column = col, sticky = 'ew', padx = 4, pady = 2 )
360 control.object = object
361 control.trait_name = trait_name
362 control.description = description
363 control.original_value = getattr( object, trait_name )
364 control.handler = self.handler
365 return control
366
367
368
369
370
377
378
379
380
381
383
384
385
386
387
388
389 - def simple_editor ( self, object, trait_name, description, handler,
390 parent ):
391 control = tk.Label( parent, text = self.str( object, trait_name ),
392 relief = tk.SUNKEN )
393 control.object = object
394 control.trait_name = trait_name
395 control.description = description
396 control.handler = handler
397 control.original_value = getattr( object, trait_name )
398 control.bind( '<B1-ButtonRelease>', self.on_popup )
399 control.bind( '<3>', self.on_restore )
400 return control
401
402
403
404
405
407 control = event.widget
408 if hasattr( self, 'popup_editor' ):
409 self.popup_editor( control.object, control.trait_name,
410 control.description, control.handler, control )
411
412
413
414
415
417 control = event.widget
418 object = control.object
419 trait_name = control.trait_name
420 old_value = getattr( object, trait_name )
421 new_value = control.original_value
422 setattr( object, trait_name, new_value )
423 control.handler.changed( object, trait_name, new_value, old_value,
424 FALSE )
425 self.update( object, trait_name, control )
426
427
428
429
430
431
432 - def update ( self, object, trait_name, control ):
433 control.configure( text = self.str( object, trait_name ) )
434
435
436
437
438
439 - def error ( self, description, excp, parent ):
440 mb.showerror( description + ' value error', str( excp ) )
441
442
443
444
445
446 -class TraitEditorText ( tkTraitEditor ):
447
448
449
450
451
452 - def __init__ ( self, dic = {}, auto_set = TRUE ):
453 self.dic = dic
454 self.auto_set = auto_set
455
456
457
458
459
462 while TRUE:
463 value = sd.askstring( 'Prompt',
464 'Enter the new %s value:' % trait_name,
465 initialvalue = getattr( object, trait_name ) )
466 if value is None:
467 return
468 if self.dic.has_key( value ):
469 value = self.dic[ value ]
470 try:
471 self.set( object, trait_name, value, handler )
472 self.update( object, trait_name, control )
473 except TraitError, excp:
474 self.error( description, excp, object.window )
475
476
477
478
479
480
481 - def simple_editor ( self, object, trait_name, description, handler,
482 parent ):
483 var = tk.StringVar()
484 var.set( self.str( object, trait_name ) )
485 control = tk.Entry( parent, textvariable = var )
486 control.var = var
487 control.value = self.get_value( control )
488 control.bind( '<Return>', self.on_enter )
489 control.bind( '<3>', self.on_restore )
490 if self.auto_set:
491 control.bind( '<KeyRelease>', self.on_key )
492 return control
493
494
495
496
497
498
499 - def update ( self, object, trait_name, control ):
500 control.var.set( self.str( object, trait_name ) )
501 control.configure( bg = WHITE )
502
503
504
505
506
507 - def on_enter ( self, event ):
508 control = event.widget
509 try:
510 self.set( control.object, control.trait_name,
511 self.get_value( control ), control.handler )
512 except TraitError, excp:
513 self.error( control.description, excp, control )
514
515
516
517
518
519 - def on_key ( self, event ):
520 control = event.widget
521 value = self.get_value( control )
522 if value != control.value:
523 control.value = value
524 try:
525 setattr( control.object, control.trait_name, value )
526 color = WHITE
527 except:
528 color = '#FFC0C0'
529 control.configure( bg = color )
530
531
532
533
534
535 - def get_value ( self, control ):
536 value = control.var.get().strip()
537 if not self.dic.has_key( value ):
538 return value
539 return self.dic[ value ]
540
541
542
543
544
546
547
548
549
550
551 - def __init__ ( self, values, cols = 1 ):
552 self.cols = cols
553 self.mapped = (type( values ) is DictType)
554 if self.mapped:
555 sorted = values.values()
556 sorted.sort()
557 col = sorted[0].find( ':' ) + 1
558 if col > 0:
559 self.sorted = [ x[ col: ] for x in sorted ]
560 for n, v in values.items():
561 values[n] = v[ col: ]
562 else:
563 self.sorted = sorted
564 self.values = values
565 else:
566 if not type( values ) in basic_sequence_types:
567 handler = values
568 if isinstance( handler, Trait ):
569 handler = handler.setter
570 if hasattr( handler, 'map' ):
571 values = handler.map.keys()
572 values.sort()
573 else:
574 values = handler.values
575 self.values = [ str( x ) for x in values ]
576
577
578
579
580
581
582 - def simple_editor ( self, object, trait_name, description, handler,
583 parent ):
584 delegate = tkDelegate( self.on_value_changed )
585 values = self.all_values()
586 control = Pmw.ComboBox( parent,
587 dropdown = TRUE,
588 selectioncommand = delegate(),
589 scrolledlist_items = values,
590 listheight = min( 150, len( values ) * 24 ) )
591 delegate.control = control
592 control.selectitem( self.current_value( object, trait_name ) )
593 return control
594
595
596
597
598
599
600 - def custom_editor ( self, object, trait_name, description, handler,
601 parent ):
602
603 panel = tk.Frame( parent )
604
605
606 cur_value = self.current_value( object, trait_name )
607
608
609 values = self.all_values()
610 n = len( values )
611 cols = self.cols
612 rows = (n + cols - 1) // cols
613 var = tk.StringVar()
614 delegate = tkDelegate( self.on_click, var = var, panel = panel )
615 incr = [ n // cols ] * cols
616 rem = n % cols
617 for i in range( cols ):
618 incr[i] += (rem > i)
619 incr[-1] = -(reduce( lambda x, y: x + y, incr[:-1], 0 ) - 1)
620
621
622 index = 0
623 for i in range( rows ):
624 for j in range( cols ):
625 value = values[ index ]
626 control = tk.Radiobutton( panel,
627 text = value.capitalize(),
628 value = value,
629 variable = var,
630 command = delegate() )
631 control.grid( row = i, column = j, sticky = 'w' )
632 if value == cur_value:
633 var.set( value )
634 index += incr[j]
635 n -= 1
636 if n <= 0:
637 break
638
639 for j in range( cols ):
640 panel.columnconfigure( j, weight = 1 )
641
642
643 return panel
644
645
646
647
648
650 if self.mapped:
651 return self.sorted
652 return self.values
653
654
655
656
657
659 if self.mapped:
660 return self.values[ getattr( object, trait_name + '_' ) ]
661 return str( getattr( object, trait_name ) )
662
663
664
665
666
668 control = delegate.control
669 try:
670 value = int( value )
671 except:
672 pass
673 self.set( control.object, control.trait_name, value, control.handler )
674
675
676
677
678
680 panel = delegate.panel
681 value = delegate.var.get()
682 try:
683 value = int( value )
684 except:
685 pass
686 self.set( panel.object, panel.trait_name, value, panel.handler )
687
688
689
690
691
693
694
695
696
697
698 - def __init__ ( self, values, suffix = '', cols = 1, path = None ):
699 TraitEditorEnum.__init__( self, values )
700 self.suffix = suffix
701 self.cols = cols
702 if type( path ) is ModuleType:
703 path = os.path.join( os.path.dirname( path.__file__ ), 'images' )
704 self.path = path
705
706
707
708
709
714
715
716
717
718
719
720 - def simple_editor ( self, object, trait_name, description, handler,
721 parent ):
722 control = tk.Button( parent,
723 image = bitmap_cache(
724 self.current_value( object, trait_name ) +
725 self.suffix, self.path ),
726 bg = WHITE )
727 control.configure( command = tkDelegate( self.on_popup,
728 widget = control )() )
729 return control
730
731
732
733
734
735
736 - def custom_editor ( self, object, trait_name, description, handler,
737 parent ):
738
739 panel = tk.Frame( parent )
740
741
742 panel.object = object
743 panel.trait_name = trait_name
744 panel.handler = handler
745
746
747 self.create_image_grid( panel, self.on_click )
748
749
750 return panel
751
752
753
754
755
757
758 i = 0
759 cols = self.cols
760 for value in self.all_values():
761 control = tk.Button( parent,
762 image = bitmap_cache( value + self.suffix,
763 self.path ),
764 command = tkDelegate( handler,
765 parent = parent,
766 value = value )() )
767 control.grid( row = i // cols, column = i % cols, sticky = 'w',
768 padx = 2, pady = 2 )
769 i += 1
770
771 parent.columnconfigure( cols, weight = 1 )
772
773
774
775
776
777
778 - def update ( self, object, trait_name, control ):
782
783
784
785
786
788 parent = delegate.parent
789 self.set( parent.object, parent.trait_name, delegate.value,
790 parent.handler )
791
792
793
794
795
797
798
799
800
801
802 - def __init__ ( self, values, cols = 1 ):
803 self.cols = cols
804 self.values = values
805 if type( values[0] ) is StringType:
806 self.values = [ ( x, x.capitalize() ) for x in values ]
807 self.mapping = mapping = {}
808 for value, key in self.values:
809 mapping[ key ] = value
810
811
812
813
814
815
816 - def simple_editor ( self, object, trait_name, description, handler,
817 parent ):
818 delegate = tkDelegate( self.on_value_changed )
819 labels = self.all_labels()
820 control = Pmw.ComboBox( parent,
821 dropdown = TRUE,
822 selectioncommand = delegate(),
823 scrolledlist_items = labels,
824 listheight = min( 150, len( labels ) * 24 ) )
825 delegate.control = control
826 try:
827 control.selectitem( self.all_values().index(
828 self.current_value( object, trait_name )[0] ) )
829 except:
830 pass
831 return control
832
833
834
835
836
837
838 - def custom_editor ( self, object, trait_name, description, handler,
839 parent ):
840
841 panel = tk.Frame( parent )
842
843
844 cur_value = self.current_value( object, trait_name )
845
846
847 labels = self.all_labels()
848 values = self.all_values()
849 n = len( values )
850 cols = self.cols
851 rows = (n + cols - 1) // cols
852 incr = [ n // cols ] * cols
853 rem = n % cols
854 for i in range( cols ):
855 incr[i] += (rem > i)
856 incr[-1] = -(reduce( lambda x, y: x + y, incr[:-1], 0 ) - 1)
857
858
859 index = 0
860 for i in range( rows ):
861 for j in range( cols ):
862 if n > 0:
863 value = values[ index ]
864 var = tk.IntVar()
865 delegate = tkDelegate( self.on_click,
866 var = var,
867 panel = panel,
868 value = value )
869 control = tk.Checkbutton( panel,
870 text = labels[ index ],
871 variable = var,
872 command = delegate() )
873 control.grid( row = i, column = j, sticky = 'w' )
874 var.set( value in cur_value )
875 index += incr[j]
876 n -= 1
877 if n <= 0:
878 break
879
880 for j in range( cols ):
881 panel.columnconfigure( j, weight = 1 )
882
883
884 return panel
885
886
887
888
889
891 return [ x[1] for x in self.values ]
892
893
894
895
896
898 return [ x[0] for x in self.values ]
899
900
901
902
903
905 return (type( getattr( object, trait_name ) ) is StringType)
906
907
908
909
910
912 value = getattr( object, trait_name )
913 if value is None:
914 return []
915 if type( value ) is not StringType:
916 return value
917 return [ x.strip() for x in value.split( ',' ) ]
918
919
920
921
922
924 control = delegate.control
925 value = self.mapping[ value ]
926 if not self.is_string( control.object, control.trait_name ):
927 value = [ value ]
928 self.set( control.object, control.trait_name, value, control.handler )
929
930
931
932
933
935 panel = delegate.panel
936 value = delegate.value
937 cur_value = self.current_value( panel.object, panel.trait_name )
938 if delegate.var.get():
939 cur_value.append( value )
940 else:
941 cur_value.remove( value )
942 if self.is_string( panel.object, panel.trait_name ):
943 cur_value = ','.join( cur_value )
944 self.set( panel.object, panel.trait_name, cur_value, panel.handler )
945
946
947
948
949
951
952
953
954
955
956
957 - def simple_editor ( self, object, trait_name, description, handler,
958 parent ):
959 var = tk.IntVar()
960 control = tk.Checkbutton( parent,
961 text = '',
962 variable = var,
963 anchor = 'w' )
964 control.configure( command = tkDelegate( self.on_value_changed,
965 control = control,
966 var = var )() )
967 try:
968 value = getattr( object, trait_name + '_' )
969 except:
970 value = getattr( object, trait_name )
971 var.set( value )
972 return control
973
974
975
976
977
979 control = delegate.control
980 self.set( control.object, control.trait_name, delegate.var.get(),
981 control.handler )
982
983
984
985
986
988
989
990
991
992
993 - def __init__ ( self, handler, cols = 1 , auto_set = True):
994 if isinstance( handler, Trait ):
995 handler = handler.setter
996 self.low = handler.low
997 self.high = handler.high
998 self.cols = cols
999 self.auto_set = auto_set
1000 self.is_float = (type( self.low ) is FloatType)
1001
1002
1003
1004
1005
1006
1007 - def simple_editor ( self, object, trait_name, description, handler,
1008 parent ):
1009 value = self.str( object, trait_name )
1010 var = tk.StringVar()
1011 var.set(value)
1012
1013 if self.is_float or abs( self.high - self.low ) > 1000:
1014 control = tk.Entry( parent, textvariable = var )
1015 control.var = var
1016 control.value = value
1017 control.bind( '<Return>', self.on_enter )
1018 control.bind( '<KeyRelease>', self.on_key )
1019 control.bind( '<3>', self.on_restore )
1020 else:
1021 control = Pmw.Counter( parent )
1022 control.configure( datatype = {
1023 'counter': self.on_value_changed,
1024 'control': control,
1025 'min_value': self.low,
1026 'max_value': self.high }
1027 )
1028 control._counterEntry.setentry( str( value ) )
1029
1030 return control
1031
1032
1033
1034
1035
1036
1037 - def custom_editor ( self, object, trait_name, description, handler,
1038 parent ):
1039 if abs( self.high - self.low ) > 15:
1040 return self.simple_editor( object, trait_name, description,
1041 handler, parent )
1042 return TraitEditorEnum.custom_editor( self, object, trait_name,
1043 description, handler, parent )
1044
1045
1046
1047
1048
1050 return [ str( x ) for x in xrange( self.low, self.high + 1 ) ]
1051
1052
1053
1054
1055
1058
1059
1060
1061
1062
1063
1064 - def update ( self, object, trait_name, control ):
1065 if isinstance( control, tk.Entry ):
1066 control.var.set( self.str( object, trait_name ) )
1067 control.configure( bg = WHITE )
1068 else:
1069 control.entryfield.configure(
1070 text = str( getattr( object, trait_name ) ) )
1071
1072
1073
1074
1075
1076 - def on_value_changed ( self, value, factor, incr,
1077 control = None,
1078 min_value = None,
1079 max_value = None ):
1080 value = min( max_value,
1081 max( min_value, int( value ) + factor * incr ) )
1082 try:
1083 self.set( control.object, control.trait_name, value,
1084 control.handler )
1085 return str( value )
1086 except:
1087 raise ValueError
1088
1089
1090
1091
1092
1094 control = event.widget
1095 try:
1096 self.set( control.object, control.trait_name,
1097 control.var.get().strip(), control.handler )
1098 except TraitError, excp:
1099 self.error( control.description, excp, control )
1100
1101
1102
1103
1104
1106 control = event.widget
1107 value = control.var.get()
1108 if value != control.value:
1109 control.value = value
1110 try:
1111 setattr( control.object, control.trait_name, value )
1112 color = WHITE
1113 except:
1114 color = '#FFC0C0'
1115 control.configure( bg = color )
1116
1117
1118
1119
1120
1122
1123
1124
1125
1126
1127 - def __init__ ( self, object, trait_name, description, control, handler,
1128 editor ):
1129 tk.Toplevel.__init__( self, control )
1130 self.title( 'Choose ' + description )
1131 self.bind( '<Escape>', self.on_close_key )
1132
1133
1134 self.object = object
1135 self.trait_name = trait_name
1136 self.control = control
1137 self.handler = handler
1138 self.editor = editor
1139
1140
1141 editor.create_image_grid( self, self.on_click )
1142
1143
1144
1145
1146
1149
1150
1151
1152
1153
1155 self.editor.set( self.object, self.trait_name,
1156 delegate.value, self.handler )
1157 self.editor.update( self.object, self.trait_name, self.control )
1158 self.destroy()
1159
1160
1161
1162
1163
1164
1165 _bitmap_cache = {}
1166
1167
1168 app_path = None
1169 traits_path = None
1170
1172 global app_path, traits_path
1173 if path is None:
1174 if traits_path is None:
1175 import traits
1176 traits_path = os.path.join(
1177 os.path.dirname( traits.__file__ ), 'images' )
1178 path = traits_path
1179 elif path == '':
1180 if app_path is None:
1181 app_path = os.path.join( os.path.dirname( sys.argv[0] ),
1182 '..', 'images' )
1183 path = app_path
1184 filename = os.path.abspath( os.path.join( path,
1185 name.replace( ' ', '_' ).lower() + '.gif' ) )
1186 bitmap = _bitmap_cache.get( filename )
1187 if bitmap is None:
1188 bitmap = _bitmap_cache[ filename ] = tk.PhotoImage( file = filename )
1189 return bitmap
1190
1191
1192
1193
1194
1195 standard_colors = {
1196 'aquamarine': '#70DB93',
1197 'black': '#000000',
1198 'blue': '#0000FF',
1199 'blue violet': '#9F5F9F',
1200 'brown': '#A52A2A',
1201 'cadet blue': '#5F9F9F',
1202 'coral': '#FF7F00',
1203 'cornflower blue': '#42426F',
1204 'cyan': '#00FFFF',
1205 'dark green': '#2F4F2F',
1206 'dark grey': '#2F2F2F',
1207 'dark olive green': '#4F4F2F',
1208 'dark orchid': '#9932CC',
1209 'dark slate blue': '#6B238E',
1210 'dark slate grey': '#2F4F4F',
1211 'dark turquoise': '#7093DB',
1212 'dim grey': '#545454',
1213 'firebrick': '#8E2323',
1214 'forest green': '#238E23',
1215 'gold': '#CC7F32',
1216 'goldenrod': '#DBDB70',
1217 'green': '#00FF00',
1218 'green yellow': '#93DB70',
1219 'grey': '#808080',
1220 'indian red': '#4F2F2F',
1221 'khaki': '#9F9F5F',
1222 'light blue': '#BFD8D8',
1223 'light grey': '#C0C0C0',
1224 'light steel': '#000000',
1225 'lime green': '#32CC32',
1226 'magenta': '#FF00FF',
1227 'maroon': '#8E236B',
1228 'medium aquamarine': '#32CC99',
1229 'medium blue': '#3232CC',
1230 'medium forest green': '#6B8E23',
1231 'medium goldenrod': '#EAEAAD',
1232 'medium orchid': '#9370DB',
1233 'medium sea green': '#426F42',
1234 'medium slate blue': '#7F00FF',
1235 'medium spring green': '#7FFF00',
1236 'medium turquoise': '#70DBDB',
1237 'medium violet red': '#DB7093',
1238 'midnight blue': '#2F2F4F',
1239 'navy': '#23238E',
1240 'orange': '#CC3232',
1241 'orange red': '#FF007F',
1242 'orchid': '#DB70DB',
1243 'pale green': '#8FBC8F',
1244 'pink': '#BC8FEA',
1245 'plum': '#EAADEA',
1246 'purple': '#B000FF',
1247 'red': '#FF0000',
1248 'salmon': '#6F4242',
1249 'sea green': '#238E6B',
1250 'sienna': '#8E6B23',
1251 'sky blue': '#3299CC',
1252 'slate blue': '#007FFF',
1253 'spring green': '#00FF7F',
1254 'steel blue': '#236B8E',
1255 'tan': '#DB9370',
1256 'thistle': '#D8BFD8',
1257 'turquoise': '#ADEAEA',
1258 'violet': '#4F2F4F',
1259 'violet red': '#CC3299',
1260 'wheat': '#D8D8BF',
1261 'white': '#FFFFFF',
1262 'yellow': '#FFFF00',
1263 'yellow green': '#99CC32'
1264 }
1265
1266
1267
1268
1269
1271 if type( value ) is StringType:
1272 if ((len( value ) == 7) and (value[0] == '#') and
1273 (eval( '0x' + value[1:] ) >= 0)):
1274 return value
1275 raise TraitError
1276 return '#%06X' % int( value )
1277
1278 num_to_color.info = ("a string of the form '#RRGGBB' or a number, which in "
1279 "hex is of the form 0xRRGGBB, where RR is red, GG is "
1280 "green, and BB is blue")
1281
1282
1283
1284
1285
1287
1288
1289
1290
1291
1294 color = cc.askcolor( self.to_tk_color( object,
1295 trait_name ) )[1].upper()
1296 if color is not None:
1297 self.set( object, trait_name, self.from_tk_color( color ),
1298 handler )
1299 self.update( object, trait_name, control )
1300
1301
1302
1303
1304
1305
1306 - def simple_editor ( self, object, trait_name, description, handler,
1307 parent ):
1312
1313
1314
1315
1316
1317
1318 - def custom_editor ( self, object, trait_name, description, handler,
1319 parent ):
1320
1321 panel = tk.Frame( parent )
1322 panel.color = self.simple_editor( object, trait_name, description,
1323 handler, panel )
1324 panel.color.grid( row = 0, column = 0, sticky = 'nesw' )
1325
1326
1327 panel2 = tk.Frame( panel )
1328 for i in range( len( color_samples ) ):
1329 tk.Button( panel2,
1330 bg = color_samples[i],
1331 font = 'Helvetica 1',
1332 command = tkDelegate( self.on_click,
1333 panel = panel,
1334 color = color_samples[i] )() ).grid(
1335 row = i // 12, column = i % 12, sticky = 'ew' )
1336 for i in range( 12 ):
1337 panel2.columnconfigure( i, weight = 1 )
1338
1339 panel2.grid( row = 0, column = 1, sticky = 'nesw', padx = 4 )
1340 panel.columnconfigure( 0, minsize = 70 )
1341 panel.columnconfigure( 1, weight = 1 )
1342
1343
1344 return panel
1345
1346
1347
1348
1349
1351 panel = delegate.panel
1352 self.set( panel.object, panel.trait_name,
1353 self.from_tk_color( delegate.color ),
1354 panel.handler )
1355 self.update( panel.object, panel.trait_name, panel.color )
1356
1357
1358
1359
1360
1361
1362 - def update ( self, object, trait_name, control ):
1365
1366
1367
1368
1369
1371 bg_color = self.to_tk_color( object, trait_name )
1372 red = eval( '0x%s' % bg_color[1:3] )
1373 green = eval( '0x%s' % bg_color[3:5] )
1374 blue = eval( '0x%s' % bg_color[5:7] )
1375 fg_color = ( '#FFFFFF', '#000000' )[
1376 (red > 192) or(green > 192) or(blue > 192) ]
1377 control.configure( bg = bg_color, fg = fg_color )
1378
1379
1380
1381
1382
1384 try:
1385 cur_color = getattr( object, trait_name + '_' )
1386 except:
1387 cur_color = getattr( object, trait_name )
1388 if cur_color is None:
1389 return WHITE
1390 return cur_color
1391
1392
1393
1394
1395
1398
1399
1400
1401
1402
1403
1404 color_editor = TraitEditorColor()
1405
1406
1407 color_trait = Trait( 'white', standard_colors, num_to_color,
1408 editor = color_editor )
1409 clear_color_trait = Trait( 'clear', None, standard_colors,
1410 { 'clear': None }, num_to_color,
1411 editor = color_editor )
1412
1413
1414
1415
1416
1417 slant_types = [ 'roman', 'italic' ]
1418 weight_types = [ 'bold' ]
1419 font_noise = [ 'pt', 'point', 'family' ]
1420
1422 try:
1423 size = 10
1424 family = []
1425 slant = 'roman'
1426 weight = 'normal'
1427 underline = overstrike = 0
1428 for word in value.split():
1429 lword = word.lower()
1430 if lword in slant_types:
1431 slant = lword
1432 elif lword in weight_types:
1433 weight = lword
1434 elif lword == 'underline':
1435 underline = 1
1436 elif lword == 'overstrike':
1437 overstrike = 1
1438 elif lword not in font_noise:
1439 try:
1440 size = int( lword )
1441 except:
1442 family.append( word )
1443 if len( family ) == 0:
1444 family = [ 'Helvetica' ]
1445 return tkFont.Font( family = ' '.join( family ),
1446 size = size,
1447 weight = weight,
1448 slant = slant,
1449 underline = underline,
1450 overstrike = overstrike )
1451 except:
1452 pass
1453 raise TraitError
1454
1455 str_to_font.info = ( "a string describing a font (e.g. '12 pt bold italic' "
1456 "or 'Arial bold 14 point')" )
1457
1458
1459
1460
1461
1463
1464
1465
1466
1467
1468
1469 - def simple_editor ( self, object, trait_name, description, handler,
1470 parent ):
1476
1477
1478
1479
1480
1481
1482 - def custom_editor ( self, object, trait_name, description, handler,
1483 parent ):
1484
1485 panel = tk.Frame( parent )
1486
1487
1488 font = panel.font = self.simple_editor( object, trait_name,
1489 description, handler, panel )
1490 font.configure( anchor = 'w' )
1491 font.is_custom = TRUE
1492 font.grid( row = 0, column = 0, columnspan = 2, sticky = 'ew', pady = 3 )
1493
1494
1495 delegate = tkDelegate( self.on_value_changed, panel = panel )
1496 values = self.all_facenames()
1497 panel.facename = control = Pmw.ComboBox( panel,
1498 dropdown = TRUE,
1499 selectioncommand = delegate(),
1500 scrolledlist_items = values,
1501 listheight = min( 150, len( values ) * 24 ) )
1502 control.grid( row = 1, column = 0 )
1503
1504 panel.pointsize = control = Pmw.ComboBox( panel,
1505 dropdown = TRUE,
1506 selectioncommand = delegate(),
1507 scrolledlist_items = point_sizes )
1508 control.grid( row = 1, column = 1, padx = 4 )
1509
1510
1511 self.update_font( object, trait_name, font )
1512
1513
1514 return panel
1515
1516
1517
1518
1519
1520
1521 - def update ( self, object, trait_name, control ):
1524
1525
1526
1527
1528
1529 - def update_font ( self, object, trait_name, control ):
1530 cur_font = self.to_tk_font( object, trait_name )
1531 size = cur_font.cget( 'size' )
1532 if control.is_custom:
1533 panel = control.master
1534 try:
1535 panel.facename.selectitem( cur_font.cget( 'family' ) )
1536 except:
1537 panel.facename.selectitem( 0 )
1538 try:
1539 panel.pointsize.selectitem( size )
1540 except:
1541 panel.pointsize.selectitem( '10' )
1542 cur_font.configure( size = min( 10, size ) )
1543 control.configure( font = cur_font )
1544
1545
1546
1547
1548
1549 - def str ( self, object, trait_name ):
1550 font = getattr( object, trait_name )
1551 size = font.cget( 'size' )
1552 family = font.cget( 'family' )
1553 slant = font.cget( 'slant' )
1554 weight = font.cget( 'weight' )
1555 return '%s point %s %s %s' % ( size, family, slant.capitalize(),
1556 weight.capitalize() )
1557
1558
1559
1560
1561
1563 return ( 'Courier',
1564 'Times',
1565 'Helvetica',
1566 'Arial',
1567 'Verdana' )
1568
1569
1570
1571
1572
1574 panel = delegate.panel
1575 size = panel.pointsize.get()
1576 family = panel.facename.get()
1577 font = tkFont.Font( family = family, size = size )
1578 self.set( panel.object, panel.trait_name,
1579 self.from_tk_font( font ), panel.handler )
1580 self.update( panel.object, panel.trait_name, panel.font )
1581
1582
1583
1584
1585
1586
1588 return getattr( object, trait_name )
1589
1590
1591
1592
1593
1596
1597
1598
1599
1600
1601 font_trait = Trait( 'Arial 10', tkFont.Font, str_to_font,
1602 editor = TraitEditorFont() )
1603
1604
1605
1606
1607
1609
1610
1611
1612
1613
1614 - def __init__ ( self, delegate = None, **kw ):
1615 self.delegate = delegate
1616 for name, value in kw.items():
1617 setattr( self, name, value )
1618
1619
1620
1621
1622
1625
1626
1627
1628
1629
1631 self.delegate( self, *args )
1632