nltk 3.2__zip → 3.3__zip
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {nltk-3.2 → nltk-3.3}/INSTALL.txt +6 -6
- {nltk-3.2 → nltk-3.3}/LICENSE.txt +13 -13
- {nltk-3.2 → nltk-3.3}/MANIFEST.in +6 -6
- {nltk-3.2/nltk.egg-info → nltk-3.3}/PKG-INFO +13 -5
- nltk-3.2/README.txt → nltk-3.3/README.md +49 -48
- nltk-3.3/nltk/VERSION +1 -0
- {nltk-3.2 → nltk-3.3}/nltk/__init__.py +185 -185
- {nltk-3.2 → nltk-3.3}/nltk/app/__init__.py +52 -53
- {nltk-3.2 → nltk-3.3}/nltk/app/chartparser_app.py +2276 -2276
- {nltk-3.2 → nltk-3.3}/nltk/app/chunkparser_app.py +1262 -1264
- {nltk-3.2 → nltk-3.3}/nltk/app/collocations_app.py +347 -350
- {nltk-3.2 → nltk-3.3}/nltk/app/concordance_app.py +568 -570
- {nltk-3.2 → nltk-3.3}/nltk/app/nemo_app.py +156 -155
- {nltk-3.2 → nltk-3.3}/nltk/app/rdparser_app.py +892 -894
- {nltk-3.2 → nltk-3.3}/nltk/app/srparser_app.py +809 -809
- {nltk-3.2 → nltk-3.3}/nltk/app/wordfreq_app.py +32 -32
- {nltk-3.2 → nltk-3.3}/nltk/app/wordnet_app.py +968 -968
- {nltk-3.2 → nltk-3.3}/nltk/book.py +91 -90
- {nltk-3.2 → nltk-3.3}/nltk/ccg/__init__.py +22 -22
- {nltk-3.2 → nltk-3.3}/nltk/ccg/api.py +359 -335
- {nltk-3.2 → nltk-3.3}/nltk/ccg/chart.py +394 -361
- {nltk-3.2 → nltk-3.3}/nltk/ccg/combinator.py +343 -312
- {nltk-3.2 → nltk-3.3}/nltk/ccg/lexicon.py +328 -290
- nltk-3.3/nltk/ccg/logic.py +46 -0
- {nltk-3.2 → nltk-3.3}/nltk/chat/__init__.py +49 -49
- {nltk-3.2 → nltk-3.3}/nltk/chat/eliza.py +244 -244
- {nltk-3.2 → nltk-3.3}/nltk/chat/iesha.py +140 -140
- {nltk-3.2 → nltk-3.3}/nltk/chat/rude.py +92 -92
- {nltk-3.2 → nltk-3.3}/nltk/chat/suntsu.py +117 -117
- {nltk-3.2 → nltk-3.3}/nltk/chat/util.py +122 -120
- {nltk-3.2 → nltk-3.3}/nltk/chat/zen.py +282 -282
- {nltk-3.2 → nltk-3.3}/nltk/chunk/__init__.py +190 -190
- {nltk-3.2 → nltk-3.3}/nltk/chunk/api.py +51 -51
- {nltk-3.2 → nltk-3.3}/nltk/chunk/named_entity.py +331 -331
- {nltk-3.2 → nltk-3.3}/nltk/chunk/regexp.py +1390 -1384
- {nltk-3.2 → nltk-3.3}/nltk/chunk/util.py +600 -600
- {nltk-3.2 → nltk-3.3}/nltk/classify/__init__.py +98 -98
- {nltk-3.2 → nltk-3.3}/nltk/classify/api.py +193 -193
- {nltk-3.2 → nltk-3.3}/nltk/classify/decisiontree.py +295 -295
- {nltk-3.2 → nltk-3.3}/nltk/classify/maxent.py +1510 -1492
- {nltk-3.2 → nltk-3.3}/nltk/classify/megam.py +179 -178
- {nltk-3.2 → nltk-3.3}/nltk/classify/naivebayes.py +245 -242
- {nltk-3.2 → nltk-3.3}/nltk/classify/positivenaivebayes.py +170 -170
- {nltk-3.2 → nltk-3.3}/nltk/classify/rte_classify.py +160 -191
- {nltk-3.2 → nltk-3.3}/nltk/classify/scikitlearn.py +153 -151
- {nltk-3.2 → nltk-3.3}/nltk/classify/senna.py +183 -181
- {nltk-3.2 → nltk-3.3}/nltk/classify/svm.py +15 -15
- {nltk-3.2 → nltk-3.3}/nltk/classify/tadm.py +113 -112
- {nltk-3.2 → nltk-3.3}/nltk/classify/textcat.py +193 -193
- {nltk-3.2 → nltk-3.3}/nltk/classify/util.py +324 -312
- {nltk-3.2 → nltk-3.3}/nltk/classify/weka.py +346 -345
- {nltk-3.2 → nltk-3.3}/nltk/cluster/__init__.py +86 -86
- {nltk-3.2 → nltk-3.3}/nltk/cluster/api.py +74 -70
- {nltk-3.2 → nltk-3.3}/nltk/cluster/em.py +247 -247
- {nltk-3.2 → nltk-3.3}/nltk/cluster/gaac.py +168 -168
- {nltk-3.2 → nltk-3.3}/nltk/cluster/kmeans.py +221 -221
- {nltk-3.2 → nltk-3.3}/nltk/cluster/util.py +304 -289
- nltk-3.3/nltk/collections.py +640 -0
- {nltk-3.2 → nltk-3.3}/nltk/collocations.py +388 -388
- nltk-3.3/nltk/compat.py +365 -0
- {nltk-3.2 → nltk-3.3}/nltk/corpus/__init__.py +341 -320
- {nltk-3.2 → nltk-3.3}/nltk/corpus/europarl_raw.py +44 -44
- {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/__init__.py +147 -145
- {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/aligned.py +115 -114
- {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/api.py +448 -446
- {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/bnc.py +252 -252
- {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/bracket_parse.py +227 -227
- {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/categorized_sents.py +179 -178
- {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/chasen.py +140 -139
- {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/childes.py +522 -494
- {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/chunked.py +212 -212
- {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/cmudict.py +97 -95
- {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/comparative_sents.py +280 -278
- {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/conll.py +528 -521
- {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/crubadan.py +116 -116
- {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/dependency.py +101 -101
- {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/framenet.py +3059 -2093
- {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/ieer.py +112 -111
- {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/indian.py +85 -86
- {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/ipipan.py +332 -331
- {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/knbc.py +187 -187
- {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/lin.py +156 -156
- {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/mte.py +311 -310
- {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/nkjp.py +429 -428
- {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/nombank.py +421 -421
- {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/nps_chat.py +73 -73
- {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/opinion_lexicon.py +115 -115
- {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/panlex_lite.py +165 -165
- nltk-3.3/nltk/corpus/reader/pl196x.py +292 -0
- {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/plaintext.py +232 -233
- {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/ppattach.py +96 -95
- {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/propbank.py +479 -481
- {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/pros_cons.py +128 -126
- {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/reviews.py +330 -328
- {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/rte.py +144 -146
- {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/semcor.py +256 -256
- {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/senseval.py +203 -201
- {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/sentiwordnet.py +137 -137
- {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/sinica_treebank.py +75 -75
- {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/string_category.py +60 -59
- {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/switchboard.py +119 -119
- {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/tagged.py +295 -294
- {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/timit.py +452 -450
- {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/toolbox.py +68 -68
- {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/twitter.py +155 -157
- {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/udhr.py +80 -80
- {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/util.py +804 -800
- nltk-3.3/nltk/corpus/reader/verbnet.py +595 -0
- nltk-3.3/nltk/corpus/reader/wordlist.py +134 -0
- {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/wordnet.py +2108 -2036
- {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/xmldocs.py +392 -387
- {nltk-3.2 → nltk-3.3}/nltk/corpus/reader/ycoe.py +243 -242
- {nltk-3.2 → nltk-3.3}/nltk/corpus/util.py +144 -127
- {nltk-3.2 → nltk-3.3}/nltk/data.py +1487 -1451
- {nltk-3.2 → nltk-3.3}/nltk/decorators.py +219 -215
- {nltk-3.2 → nltk-3.3}/nltk/downloader.py +2278 -2274
- {nltk-3.2 → nltk-3.3}/nltk/draw/__init__.py +27 -27
- {nltk-3.2 → nltk-3.3}/nltk/draw/cfg.py +774 -777
- {nltk-3.2 → nltk-3.3}/nltk/draw/dispersion.py +58 -58
- {nltk-3.2 → nltk-3.3}/nltk/draw/table.py +1098 -1098
- {nltk-3.2 → nltk-3.3}/nltk/draw/tree.py +963 -966
- {nltk-3.2 → nltk-3.3}/nltk/draw/util.py +2356 -2356
- {nltk-3.2 → nltk-3.3}/nltk/featstruct.py +2617 -2500
- {nltk-3.2 → nltk-3.3}/nltk/grammar.py +1559 -1516
- {nltk-3.2 → nltk-3.3}/nltk/help.py +56 -56
- {nltk-3.2 → nltk-3.3}/nltk/inference/__init__.py +20 -20
- {nltk-3.2 → nltk-3.3}/nltk/inference/api.py +597 -589
- {nltk-3.2 → nltk-3.3}/nltk/inference/discourse.py +612 -608
- {nltk-3.2 → nltk-3.3}/nltk/inference/mace.py +311 -311
- {nltk-3.2 → nltk-3.3}/nltk/inference/nonmonotonic.py +509 -509
- {nltk-3.2 → nltk-3.3}/nltk/inference/prover9.py +431 -431
- {nltk-3.2 → nltk-3.3}/nltk/inference/resolution.py +687 -687
- {nltk-3.2 → nltk-3.3}/nltk/inference/tableau.py +607 -607
- {nltk-3.2 → nltk-3.3}/nltk/internals.py +982 -982
- {nltk-3.2 → nltk-3.3}/nltk/jsontags.py +63 -63
- {nltk-3.2 → nltk-3.3}/nltk/lazyimport.py +142 -142
- {nltk-3.2 → nltk-3.3}/nltk/metrics/__init__.py +30 -29
- {nltk-3.2 → nltk-3.3}/nltk/metrics/agreement.py +421 -401
- nltk-3.3/nltk/metrics/aline.py +607 -0
- {nltk-3.2 → nltk-3.3}/nltk/metrics/association.py +414 -410
- {nltk-3.2 → nltk-3.3}/nltk/metrics/confusionmatrix.py +206 -206
- {nltk-3.2 → nltk-3.3}/nltk/metrics/distance.py +207 -202
- {nltk-3.2 → nltk-3.3}/nltk/metrics/paice.py +381 -381
- {nltk-3.2 → nltk-3.3}/nltk/metrics/scores.py +228 -228
- {nltk-3.2 → nltk-3.3}/nltk/metrics/segmentation.py +231 -232
- {nltk-3.2 → nltk-3.3}/nltk/metrics/spearman.py +69 -69
- {nltk-3.2 → nltk-3.3}/nltk/misc/__init__.py +11 -11
- {nltk-3.2 → nltk-3.3}/nltk/misc/babelfish.py +10 -10
- {nltk-3.2 → nltk-3.3}/nltk/misc/chomsky.py +135 -133
- {nltk-3.2 → nltk-3.3}/nltk/misc/minimalset.py +83 -83
- {nltk-3.2 → nltk-3.3}/nltk/misc/sort.py +157 -157
- {nltk-3.2 → nltk-3.3}/nltk/misc/wordfinder.py +129 -129
- {nltk-3.2 → nltk-3.3}/nltk/parse/__init__.py +81 -80
- {nltk-3.2 → nltk-3.3}/nltk/parse/api.py +66 -66
- {nltk-3.2 → nltk-3.3}/nltk/parse/bllip.py +282 -282
- {nltk-3.2 → nltk-3.3}/nltk/parse/chart.py +1682 -1681
- nltk-3.3/nltk/parse/corenlp.py +780 -0
- {nltk-3.2 → nltk-3.3}/nltk/parse/dependencygraph.py +760 -758
- {nltk-3.2 → nltk-3.3}/nltk/parse/earleychart.py +452 -451
- {nltk-3.2 → nltk-3.3}/nltk/parse/evaluate.py +129 -129
- {nltk-3.2 → nltk-3.3}/nltk/parse/featurechart.py +580 -578
- {nltk-3.2 → nltk-3.3}/nltk/parse/generate.py +87 -76
- {nltk-3.2 → nltk-3.3}/nltk/parse/malt.py +356 -356
- {nltk-3.2 → nltk-3.3}/nltk/parse/nonprojectivedependencyparser.py +783 -783
- {nltk-3.2 → nltk-3.3}/nltk/parse/pchart.py +522 -522
- {nltk-3.2 → nltk-3.3}/nltk/parse/projectivedependencyparser.py +579 -578
- {nltk-3.2 → nltk-3.3}/nltk/parse/recursivedescent.py +655 -656
- {nltk-3.2 → nltk-3.3}/nltk/parse/shiftreduce.py +458 -459
- {nltk-3.2 → nltk-3.3}/nltk/parse/stanford.py +431 -406
- {nltk-3.2 → nltk-3.3}/nltk/parse/transitionparser.py +774 -772
- {nltk-3.2 → nltk-3.3}/nltk/parse/util.py +231 -231
- {nltk-3.2 → nltk-3.3}/nltk/parse/viterbi.py +401 -401
- {nltk-3.2 → nltk-3.3}/nltk/probability.py +2410 -2355
- {nltk-3.2 → nltk-3.3}/nltk/sem/__init__.py +61 -61
- {nltk-3.2 → nltk-3.3}/nltk/sem/boxer.py +1261 -1261
- {nltk-3.2 → nltk-3.3}/nltk/sem/chat80.py +782 -782
- {nltk-3.2 → nltk-3.3}/nltk/sem/cooper_storage.py +118 -118
- {nltk-3.2 → nltk-3.3}/nltk/sem/drt.py +1258 -1257
- {nltk-3.2 → nltk-3.3}/nltk/sem/drt_glue_demo.py +485 -489
- {nltk-3.2 → nltk-3.3}/nltk/sem/evaluate.py +790 -784
- {nltk-3.2 → nltk-3.3}/nltk/sem/glue.py +696 -694
- {nltk-3.2 → nltk-3.3}/nltk/sem/hole.py +386 -384
- {nltk-3.2 → nltk-3.3}/nltk/sem/lfg.py +210 -208
- {nltk-3.2 → nltk-3.3}/nltk/sem/linearlogic.py +451 -449
- {nltk-3.2 → nltk-3.3}/nltk/sem/logic.py +1910 -1910
- {nltk-3.2 → nltk-3.3}/nltk/sem/relextract.py +476 -483
- {nltk-3.2 → nltk-3.3}/nltk/sem/skolemize.py +101 -101
- {nltk-3.2 → nltk-3.3}/nltk/sem/util.py +249 -249
- {nltk-3.2 → nltk-3.3}/nltk/sentiment/__init__.py +14 -14
- {nltk-3.2 → nltk-3.3}/nltk/sentiment/sentiment_analyzer.py +229 -229
- {nltk-3.2 → nltk-3.3}/nltk/sentiment/util.py +762 -752
- {nltk-3.2 → nltk-3.3}/nltk/sentiment/vader.py +443 -445
- {nltk-3.2 → nltk-3.3}/nltk/stem/__init__.py +31 -33
- {nltk-3.2 → nltk-3.3}/nltk/stem/api.py +28 -25
- nltk-3.3/nltk/stem/arlstem.py +369 -0
- {nltk-3.2 → nltk-3.3}/nltk/stem/isri.py +345 -345
- {nltk-3.2 → nltk-3.3}/nltk/stem/lancaster.py +337 -310
- nltk-3.3/nltk/stem/porter.py +710 -0
- {nltk-3.2 → nltk-3.3}/nltk/stem/regexp.py +61 -61
- {nltk-3.2 → nltk-3.3}/nltk/stem/rslp.py +142 -142
- {nltk-3.2 → nltk-3.3}/nltk/stem/snowball.py +4236 -3712
- {nltk-3.2 → nltk-3.3}/nltk/stem/util.py +22 -12
- {nltk-3.2 → nltk-3.3}/nltk/stem/wordnet.py +51 -51
- {nltk-3.2 → nltk-3.3}/nltk/tag/__init__.py +152 -127
- {nltk-3.2 → nltk-3.3}/nltk/tag/api.py +86 -81
- {nltk-3.2 → nltk-3.3}/nltk/tag/brill.py +424 -426
- {nltk-3.2 → nltk-3.3}/nltk/tag/brill_trainer.py +608 -608
- {nltk-3.2 → nltk-3.3}/nltk/tag/crf.py +204 -200
- {nltk-3.2 → nltk-3.3}/nltk/tag/hmm.py +1277 -1277
- {nltk-3.2 → nltk-3.3}/nltk/tag/hunpos.py +132 -132
- {nltk-3.2 → nltk-3.3}/nltk/tag/mapping.py +101 -101
- {nltk-3.2 → nltk-3.3}/nltk/tag/perceptron.py +329 -314
- {nltk-3.2 → nltk-3.3}/nltk/tag/senna.py +147 -145
- {nltk-3.2 → nltk-3.3}/nltk/tag/sequential.py +740 -736
- {nltk-3.2 → nltk-3.3}/nltk/tag/stanford.py +219 -196
- {nltk-3.2 → nltk-3.3}/nltk/tag/tnt.py +595 -604
- {nltk-3.2 → nltk-3.3}/nltk/tag/util.py +72 -72
- {nltk-3.2 → nltk-3.3}/nltk/tbl/__init__.py +28 -28
- {nltk-3.2 → nltk-3.3}/nltk/tbl/api.py +1 -1
- {nltk-3.2 → nltk-3.3}/nltk/tbl/demo.py +366 -366
- {nltk-3.2 → nltk-3.3}/nltk/tbl/erroranalysis.py +39 -39
- {nltk-3.2 → nltk-3.3}/nltk/tbl/feature.py +259 -261
- {nltk-3.2 → nltk-3.3}/nltk/tbl/rule.py +321 -321
- {nltk-3.2 → nltk-3.3}/nltk/tbl/template.py +303 -308
- {nltk-3.2 → nltk-3.3}/nltk/test/__init__.py +18 -18
- {nltk-3.2 → nltk-3.3}/nltk/test/all.py +24 -23
- {nltk-3.2 → nltk-3.3}/nltk/test/bleu.doctest +14 -14
- {nltk-3.2 → nltk-3.3}/nltk/test/bnc.doctest +60 -60
- {nltk-3.2 → nltk-3.3}/nltk/test/ccg.doctest +376 -395
- nltk-3.3/nltk/test/ccg_semantics.doctest +553 -0
- {nltk-3.2 → nltk-3.3}/nltk/test/chat80.doctest +234 -234
- {nltk-3.2 → nltk-3.3}/nltk/test/childes.doctest +184 -184
- {nltk-3.2 → nltk-3.3}/nltk/test/childes_fixt.py +14 -13
- {nltk-3.2 → nltk-3.3}/nltk/test/chunk.doctest +373 -373
- {nltk-3.2 → nltk-3.3}/nltk/test/classify.doctest +185 -185
- {nltk-3.2 → nltk-3.3}/nltk/test/classify_fixt.py +11 -10
- nltk-3.3/nltk/test/collections.doctest +20 -0
- {nltk-3.2 → nltk-3.3}/nltk/test/collocations.doctest +276 -276
- {nltk-3.2 → nltk-3.3}/nltk/test/compat.doctest +134 -138
- {nltk-3.2 → nltk-3.3}/nltk/test/compat_fixt.py +9 -8
- nltk-3.3/nltk/test/concordance.doctest +55 -0
- {nltk-3.2 → nltk-3.3}/nltk/test/corpus.doctest +2200 -2212
- {nltk-3.2 → nltk-3.3}/nltk/test/corpus_fixt.py +3 -3
- {nltk-3.2 → nltk-3.3}/nltk/test/crubadan.doctest +65 -65
- {nltk-3.2 → nltk-3.3}/nltk/test/data.doctest +379 -379
- {nltk-3.2 → nltk-3.3}/nltk/test/dependency.doctest +241 -241
- {nltk-3.2 → nltk-3.3}/nltk/test/discourse.doctest +546 -546
- {nltk-3.2 → nltk-3.3}/nltk/test/discourse_fixt.py +14 -13
- {nltk-3.2 → nltk-3.3}/nltk/test/doctest_nose_plugin.py +159 -156
- {nltk-3.2 → nltk-3.3}/nltk/test/drt.doctest +517 -517
- {nltk-3.2 → nltk-3.3}/nltk/test/featgram.doctest +607 -607
- {nltk-3.2 → nltk-3.3}/nltk/test/featstruct.doctest +1229 -1230
- {nltk-3.2 → nltk-3.3}/nltk/test/framenet.doctest +288 -239
- {nltk-3.2 → nltk-3.3}/nltk/test/generate.doctest +67 -67
- {nltk-3.2 → nltk-3.3}/nltk/test/gensim.doctest +140 -141
- {nltk-3.2 → nltk-3.3}/nltk/test/gensim_fixt.py +10 -9
- {nltk-3.2 → nltk-3.3}/nltk/test/gluesemantics.doctest +384 -386
- {nltk-3.2 → nltk-3.3}/nltk/test/gluesemantics_malt.doctest +68 -68
- {nltk-3.2 → nltk-3.3}/nltk/test/gluesemantics_malt_fixt.py +12 -11
- {nltk-3.2 → nltk-3.3}/nltk/test/grammar.doctest +48 -48
- {nltk-3.2 → nltk-3.3}/nltk/test/grammartestsuites.doctest +109 -109
- {nltk-3.2 → nltk-3.3}/nltk/test/index.doctest +100 -100
- {nltk-3.2 → nltk-3.3}/nltk/test/inference.doctest +534 -534
- {nltk-3.2 → nltk-3.3}/nltk/test/inference_fixt.py +12 -11
- {nltk-3.2 → nltk-3.3}/nltk/test/internals.doctest +140 -140
- {nltk-3.2 → nltk-3.3}/nltk/test/japanese.doctest +48 -48
- {nltk-3.2 → nltk-3.3}/nltk/test/logic.doctest +1098 -1098
- {nltk-3.2 → nltk-3.3}/nltk/test/metrics.doctest +270 -270
- {nltk-3.2 → nltk-3.3}/nltk/test/misc.doctest +118 -118
- {nltk-3.2 → nltk-3.3}/nltk/test/nonmonotonic.doctest +286 -286
- {nltk-3.2 → nltk-3.3}/nltk/test/nonmonotonic_fixt.py +12 -11
- {nltk-3.2 → nltk-3.3}/nltk/test/paice.doctest +35 -35
- {nltk-3.2 → nltk-3.3}/nltk/test/parse.doctest +884 -884
- {nltk-3.2 → nltk-3.3}/nltk/test/portuguese_en.doctest +565 -565
- {nltk-3.2 → nltk-3.3}/nltk/test/portuguese_en_fixt.py +16 -16
- {nltk-3.2 → nltk-3.3}/nltk/test/probability.doctest +304 -304
- {nltk-3.2 → nltk-3.3}/nltk/test/probability_fixt.py +13 -12
- {nltk-3.2 → nltk-3.3}/nltk/test/propbank.doctest +176 -176
- {nltk-3.2 → nltk-3.3}/nltk/test/relextract.doctest +263 -263
- {nltk-3.2 → nltk-3.3}/nltk/test/resolution.doctest +221 -221
- {nltk-3.2 → nltk-3.3}/nltk/test/runtests.py +86 -64
- {nltk-3.2 → nltk-3.3}/nltk/test/segmentation_fixt.py +10 -10
- {nltk-3.2 → nltk-3.3}/nltk/test/semantics.doctest +665 -665
- {nltk-3.2 → nltk-3.3}/nltk/test/semantics_fixt.py +7 -7
- {nltk-3.2 → nltk-3.3}/nltk/test/sentiment.doctest +233 -233
- {nltk-3.2 → nltk-3.3}/nltk/test/sentiwordnet.doctest +41 -41
- {nltk-3.2 → nltk-3.3}/nltk/test/simple.doctest +85 -85
- {nltk-3.2 → nltk-3.3}/nltk/test/stem.doctest +78 -78
- {nltk-3.2 → nltk-3.3}/nltk/test/tag.doctest +33 -33
- {nltk-3.2 → nltk-3.3}/nltk/test/tokenize.doctest +273 -166
- {nltk-3.2 → nltk-3.3}/nltk/test/toolbox.doctest +307 -307
- {nltk-3.2 → nltk-3.3}/nltk/test/translate.doctest +242 -242
- {nltk-3.2 → nltk-3.3}/nltk/test/translate_fixt.py +3 -3
- {nltk-3.2 → nltk-3.3}/nltk/test/tree.doctest +1101 -1101
- {nltk-3.2 → nltk-3.3}/nltk/test/treeprettyprinter.doctest +127 -127
- {nltk-3.2 → nltk-3.3}/nltk/test/treetransforms.doctest +156 -156
- nltk-3.3/nltk/test/unit/test_2x_compat.py +63 -0
- nltk-3.3/nltk/test/unit/test_aline.py +52 -0
- nltk-3.3/nltk/test/unit/test_chunk.py +56 -0
- {nltk-3.2 → nltk-3.3}/nltk/test/unit/test_classify.py +55 -53
- {nltk-3.2 → nltk-3.3}/nltk/test/unit/test_collocations.py +88 -79
- nltk-3.3/nltk/test/unit/test_concordance.py +98 -0
- nltk-3.3/nltk/test/unit/test_corenlp.py +1000 -0
- {nltk-3.2 → nltk-3.3}/nltk/test/unit/test_corpora.py +200 -183
- {nltk-3.2 → nltk-3.3}/nltk/test/unit/test_corpus_views.py +45 -45
- {nltk-3.2 → nltk-3.3}/nltk/test/unit/test_hmm.py +88 -88
- {nltk-3.2 → nltk-3.3}/nltk/test/unit/test_json2csv_corpus.py +188 -187
- {nltk-3.2 → nltk-3.3}/nltk/test/unit/test_naivebayes.py +26 -26
- nltk-3.3/nltk/test/unit/test_rte_classify.py +86 -0
- {nltk-3.2 → nltk-3.3}/nltk/test/unit/test_seekable_unicode_stream_reader.py +124 -124
- nltk-3.3/nltk/test/unit/test_senna.py +74 -0
- nltk-3.3/nltk/test/unit/test_stem.py +121 -0
- {nltk-3.2 → nltk-3.3}/nltk/test/unit/test_tag.py +20 -20
- {nltk-3.2 → nltk-3.3}/nltk/test/unit/test_tgrep.py +628 -626
- nltk-3.3/nltk/test/unit/test_tokenize.py +168 -0
- {nltk-3.2 → nltk-3.3}/nltk/test/unit/test_twitter_auth.py +185 -185
- nltk-3.3/nltk/test/unit/test_wordnet.py +134 -0
- nltk-3.3/nltk/test/unit/translate/test_bleu.py +244 -0
- nltk-3.3/nltk/test/unit/translate/test_gdfa.py +57 -0
- {nltk-3.2 → nltk-3.3}/nltk/test/unit/translate/test_ibm1.py +75 -75
- {nltk-3.2 → nltk-3.3}/nltk/test/unit/translate/test_ibm2.py +87 -87
- {nltk-3.2 → nltk-3.3}/nltk/test/unit/translate/test_ibm3.py +105 -105
- {nltk-3.2 → nltk-3.3}/nltk/test/unit/translate/test_ibm4.py +126 -126
- {nltk-3.2 → nltk-3.3}/nltk/test/unit/translate/test_ibm5.py +166 -166
- {nltk-3.2 → nltk-3.3}/nltk/test/unit/translate/test_ibm_model.py +270 -270
- nltk-3.3/nltk/test/unit/translate/test_nist.py +37 -0
- {nltk-3.2 → nltk-3.3}/nltk/test/unit/translate/test_stack_decoder.py +300 -300
- {nltk-3.2 → nltk-3.3}/nltk/test/unit/utils.py +41 -41
- {nltk-3.2 → nltk-3.3}/nltk/test/util.doctest +48 -48
- {nltk-3.2 → nltk-3.3}/nltk/test/wordnet.doctest +595 -581
- {nltk-3.2 → nltk-3.3}/nltk/test/wordnet_fixt.py +7 -6
- {nltk-3.2 → nltk-3.3}/nltk/test/wordnet_lch.doctest +53 -53
- {nltk-3.2 → nltk-3.3}/nltk/test/wsd.doctest +68 -68
- {nltk-3.2 → nltk-3.3}/nltk/text.py +663 -610
- {nltk-3.2 → nltk-3.3}/nltk/tgrep.py +938 -937
- {nltk-3.2 → nltk-3.3}/nltk/tokenize/__init__.py +130 -107
- {nltk-3.2 → nltk-3.3}/nltk/tokenize/api.py +77 -78
- {nltk-3.2 → nltk-3.3}/nltk/tokenize/casual.py +343 -342
- {nltk-3.2 → nltk-3.3}/nltk/tokenize/mwe.py +120 -120
- nltk-3.3/nltk/tokenize/nist.py +173 -0
- {nltk-3.2 → nltk-3.3}/nltk/tokenize/punkt.py +1620 -1601
- {nltk-3.2 → nltk-3.3}/nltk/tokenize/regexp.py +208 -202
- nltk-3.3/nltk/tokenize/repp.py +151 -0
- {nltk-3.2 → nltk-3.3}/nltk/tokenize/sexpr.py +140 -142
- {nltk-3.2 → nltk-3.3}/nltk/tokenize/simple.py +138 -136
- {nltk-3.2 → nltk-3.3}/nltk/tokenize/stanford.py +117 -113
- nltk-3.3/nltk/tokenize/stanford_segmenter.py +246 -0
- {nltk-3.2 → nltk-3.3}/nltk/tokenize/texttiling.py +458 -460
- nltk-3.3/nltk/tokenize/toktok.py +155 -0
- nltk-3.3/nltk/tokenize/treebank.py +363 -0
- nltk-3.3/nltk/tokenize/util.py +261 -0
- {nltk-3.2 → nltk-3.3}/nltk/toolbox.py +499 -497
- {nltk-3.2 → nltk-3.3}/nltk/translate/__init__.py +24 -24
- {nltk-3.2 → nltk-3.3}/nltk/translate/api.py +331 -321
- {nltk-3.2 → nltk-3.3}/nltk/translate/bleu_score.py +615 -556
- nltk-3.3/nltk/translate/chrf_score.py +137 -0
- {nltk-3.2 → nltk-3.3}/nltk/translate/gale_church.py +248 -235
- {nltk-3.2 → nltk-3.3}/nltk/translate/gdfa.py +135 -131
- nltk-3.3/nltk/translate/gleu_score.py +193 -0
- {nltk-3.2 → nltk-3.3}/nltk/translate/ibm1.py +250 -241
- {nltk-3.2 → nltk-3.3}/nltk/translate/ibm2.py +308 -308
- {nltk-3.2 → nltk-3.3}/nltk/translate/ibm3.py +337 -337
- {nltk-3.2 → nltk-3.3}/nltk/translate/ibm4.py +467 -467
- {nltk-3.2 → nltk-3.3}/nltk/translate/ibm5.py +639 -639
- {nltk-3.2 → nltk-3.3}/nltk/translate/ibm_model.py +536 -533
- {nltk-3.2 → nltk-3.3}/nltk/translate/metrics.py +40 -40
- nltk-3.3/nltk/translate/nist_score.py +178 -0
- {nltk-3.2 → nltk-3.3}/nltk/translate/phrase_based.py +175 -175
- {nltk-3.2 → nltk-3.3}/nltk/translate/ribes_score.py +325 -325
- {nltk-3.2 → nltk-3.3}/nltk/translate/stack_decoder.py +499 -495
- {nltk-3.2 → nltk-3.3}/nltk/tree.py +1605 -1603
- {nltk-3.2 → nltk-3.3}/nltk/treeprettyprinter.py +564 -564
- {nltk-3.2 → nltk-3.3}/nltk/treetransforms.py +309 -309
- {nltk-3.2 → nltk-3.3}/nltk/twitter/__init__.py +28 -28
- {nltk-3.2 → nltk-3.3}/nltk/twitter/api.py +141 -136
- {nltk-3.2 → nltk-3.3}/nltk/twitter/common.py +264 -258
- {nltk-3.2 → nltk-3.3}/nltk/twitter/twitter_demo.py +288 -288
- {nltk-3.2 → nltk-3.3}/nltk/twitter/twitterclient.py +530 -530
- {nltk-3.2 → nltk-3.3}/nltk/twitter/util.py +147 -146
- nltk-3.3/nltk/util.py +751 -0
- {nltk-3.2 → nltk-3.3}/nltk/wsd.py +53 -53
- {nltk-3.2 → nltk-3.3/nltk.egg-info}/PKG-INFO +13 -5
- {nltk-3.2 → nltk-3.3}/nltk.egg-info/SOURCES.txt +26 -3
- nltk-3.3/nltk.egg-info/requires.txt +31 -0
- {nltk-3.2 → nltk-3.3}/setup.cfg +0 -1
- {nltk-3.2 → nltk-3.3}/setup.py +102 -75
- nltk-3.2/nltk/VERSION +0 -1
- nltk-3.2/nltk/compat.py +0 -680
- nltk-3.2/nltk/corpus/reader/pl196x.py +0 -278
- nltk-3.2/nltk/corpus/reader/verbnet.py +0 -408
- nltk-3.2/nltk/corpus/reader/wordlist.py +0 -37
- nltk-3.2/nltk/sentiment/vader_lexicon.txt +0 -7517
- nltk-3.2/nltk/six.py +0 -868
- nltk-3.2/nltk/stem/porter.py +0 -692
- nltk-3.2/nltk/test/unit/test_2x_compat.py +0 -26
- nltk-3.2/nltk/test/unit/test_stem.py +0 -36
- nltk-3.2/nltk/test/unit/test_tokenize.py +0 -23
- nltk-3.2/nltk/test/unit/translate/test_bleu.py +0 -84
- nltk-3.2/nltk/tokenize/treebank.py +0 -124
- nltk-3.2/nltk/tokenize/util.py +0 -90
- nltk-3.2/nltk/util.py +0 -1364
- {nltk-3.2 → nltk-3.3}/nltk/test/unit/__init__.py +0 -0
- {nltk-3.2 → nltk-3.3}/nltk/test/unit/translate/__init__.py +0 -0
- {nltk-3.2 → nltk-3.3}/nltk.egg-info/dependency_links.txt +0 -0
- {nltk-3.2 → nltk-3.3}/nltk.egg-info/not-zip-safe +0 -0
- {nltk-3.2 → nltk-3.3}/nltk.egg-info/top_level.txt +0 -0
|
@@ -1,2356 +1,2356 @@
|
|
|
1
|
-
# Natural Language Toolkit: Drawing utilities
|
|
2
|
-
#
|
|
3
|
-
# Copyright (C) 2001-
|
|
4
|
-
# Author: Edward Loper <edloper@gmail.com>
|
|
5
|
-
# URL: <http://nltk.org/>
|
|
6
|
-
# For license information, see LICENSE.TXT
|
|
7
|
-
|
|
8
|
-
"""
|
|
9
|
-
Tools for graphically displaying and interacting with the objects and
|
|
10
|
-
processing classes defined by the Toolkit. These tools are primarily
|
|
11
|
-
intended to help students visualize the objects that they create.
|
|
12
|
-
|
|
13
|
-
The graphical tools are typically built using "canvas widgets", each
|
|
14
|
-
of which encapsulates the graphical elements and bindings used to
|
|
15
|
-
display a complex object on a Tkinter ``Canvas``. For example, NLTK
|
|
16
|
-
defines canvas widgets for displaying trees and directed graphs, as
|
|
17
|
-
well as a number of simpler widgets. These canvas widgets make it
|
|
18
|
-
easier to build new graphical tools and demos. See the class
|
|
19
|
-
documentation for ``CanvasWidget`` for more information.
|
|
20
|
-
|
|
21
|
-
The ``nltk.draw`` module defines the abstract ``CanvasWidget`` base
|
|
22
|
-
class, and a number of simple canvas widgets. The remaining canvas
|
|
23
|
-
widgets are defined by submodules, such as ``nltk.draw.tree``.
|
|
24
|
-
|
|
25
|
-
The ``nltk.draw`` module also defines ``CanvasFrame``, which
|
|
26
|
-
encapsulates a ``Canvas`` and its scrollbars. It uses a
|
|
27
|
-
``ScrollWatcherWidget`` to ensure that all canvas widgets contained on
|
|
28
|
-
its canvas are within the scroll region.
|
|
29
|
-
|
|
30
|
-
Acknowledgements: Many of the ideas behind the canvas widget system
|
|
31
|
-
are derived from ``CLIG``, a Tk-based grapher for linguistic data
|
|
32
|
-
structures. For more information, see the CLIG
|
|
33
|
-
homepage (http://www.ags.uni-sb.de/~konrad/clig.html).
|
|
34
|
-
|
|
35
|
-
"""
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
import
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
>>>
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
canvas
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
-
|
|
110
|
-
- Call
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
``
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
:
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
:
|
|
141
|
-
:
|
|
142
|
-
:
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
:
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
:
|
|
151
|
-
:
|
|
152
|
-
:
|
|
153
|
-
:
|
|
154
|
-
:
|
|
155
|
-
:
|
|
156
|
-
:
|
|
157
|
-
:
|
|
158
|
-
:
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
:
|
|
173
|
-
:
|
|
174
|
-
:
|
|
175
|
-
:
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
self.
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
#
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
self.
|
|
199
|
-
self.
|
|
200
|
-
self.
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
if
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
:
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
:
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
:
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
``
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
if anchor == '
|
|
316
|
-
if anchor == '
|
|
317
|
-
if anchor == '
|
|
318
|
-
if anchor == '
|
|
319
|
-
if anchor == '
|
|
320
|
-
if anchor == '
|
|
321
|
-
if anchor == '
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
``CanvasWidget``
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
:
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
self.__canvas.tag_unbind(tag, '<ButtonPress-
|
|
344
|
-
self.__canvas.tag_unbind(tag, '<ButtonPress-
|
|
345
|
-
|
|
346
|
-
self.__canvas
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
:
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
#
|
|
360
|
-
|
|
361
|
-
self.__updating
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
self.
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
tags
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
:
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
:
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
:
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
:
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
``CanvasWidget``
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
:
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
self.
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
:
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
-
|
|
518
|
-
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
#
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
self.__canvas.bind('<ButtonRelease-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
#
|
|
536
|
-
if
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
self.
|
|
556
|
-
self.
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
self.__drag_x
|
|
566
|
-
self.
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
-
|
|
573
|
-
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
self.__canvas.unbind('<
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
if
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
#
|
|
620
|
-
#
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
- It
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
if
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
self
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
- It
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
child
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
def _update(self, child):
|
|
688
|
-
"""
|
|
689
|
-
Update this canvas widget in response to a change in one of
|
|
690
|
-
its children.
|
|
691
|
-
|
|
692
|
-
:param child: The child that changed.
|
|
693
|
-
:type child: CanvasWidget
|
|
694
|
-
:rtype: None
|
|
695
|
-
"""
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
- ``
|
|
708
|
-
- ``
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
:
|
|
720
|
-
:
|
|
721
|
-
:
|
|
722
|
-
:param
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
self.
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
:
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
:
|
|
759
|
-
:
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
self.
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
``
|
|
775
|
-
``
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
- ``
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
'
|
|
788
|
-
'
|
|
789
|
-
'
|
|
790
|
-
'
|
|
791
|
-
'
|
|
792
|
-
'
|
|
793
|
-
'
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
:
|
|
802
|
-
:
|
|
803
|
-
:
|
|
804
|
-
:param
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
:
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
self.
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
top
|
|
842
|
-
|
|
843
|
-
top
|
|
844
|
-
|
|
845
|
-
text
|
|
846
|
-
text.
|
|
847
|
-
sb
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
and
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
:
|
|
879
|
-
:param
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
:
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
self.
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
:
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
:
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
self.
|
|
909
|
-
self.
|
|
910
|
-
self.
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
name =
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
- ``
|
|
924
|
-
- ``
|
|
925
|
-
- ``
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
:
|
|
935
|
-
:param
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
:
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
self.
|
|
942
|
-
self.
|
|
943
|
-
self._box
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
- ``
|
|
977
|
-
- ``
|
|
978
|
-
- ``
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
- ``
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
:
|
|
989
|
-
:param
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
:
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
self.
|
|
996
|
-
self.
|
|
997
|
-
self.
|
|
998
|
-
self.
|
|
999
|
-
self._double
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
elif attr == '
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
dx
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
- ``
|
|
1083
|
-
- ``
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
:
|
|
1091
|
-
:param
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
:
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
self.
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
self.canvas().itemconfig(self.
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
self.canvas().itemconfig(self.
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
self.canvas().coords(self.
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
- ``
|
|
1137
|
-
- ``
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
:
|
|
1145
|
-
:param
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
:
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
self.
|
|
1152
|
-
self.
|
|
1153
|
-
self
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
self.canvas().itemconfig(self.
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
self.canvas().itemconfig(self.
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
:
|
|
1203
|
-
:param
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
:
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
self.
|
|
1210
|
-
self.
|
|
1211
|
-
self.
|
|
1212
|
-
self.
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
elif attr == '
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
elif attr == '
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
if self._align == '
|
|
1235
|
-
if self._align == '
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
(
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
(
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
(
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
:
|
|
1300
|
-
:
|
|
1301
|
-
:
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
index =
|
|
1306
|
-
self.
|
|
1307
|
-
self.
|
|
1308
|
-
self.
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
:
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
self.
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
:
|
|
1330
|
-
:
|
|
1331
|
-
:
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
self.
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
:
|
|
1360
|
-
:param
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
:
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
self.
|
|
1367
|
-
self.
|
|
1368
|
-
self.
|
|
1369
|
-
self.
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
elif attr == '
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
elif attr == '
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
if self._align == '
|
|
1392
|
-
if self._align == '
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
(left,
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
(x1,
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
self.
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
(left,
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
:
|
|
1457
|
-
:
|
|
1458
|
-
:
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
index =
|
|
1463
|
-
self.
|
|
1464
|
-
self.
|
|
1465
|
-
self.
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
:
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
self.
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
:
|
|
1487
|
-
:
|
|
1488
|
-
:
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
self.
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
A
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
height
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
:
|
|
1512
|
-
:
|
|
1513
|
-
:
|
|
1514
|
-
:
|
|
1515
|
-
:
|
|
1516
|
-
:param
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
if
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
:
|
|
1531
|
-
:
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
:
|
|
1542
|
-
:
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
:
|
|
1564
|
-
:
|
|
1565
|
-
:
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
:
|
|
1582
|
-
:
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
self.
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
|
|
1589
|
-
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
:
|
|
1595
|
-
:
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
if
|
|
1614
|
-
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
|
|
1620
|
-
|
|
1621
|
-
|
|
1622
|
-
|
|
1623
|
-
|
|
1624
|
-
|
|
1625
|
-
|
|
1626
|
-
|
|
1627
|
-
|
|
1628
|
-
|
|
1629
|
-
|
|
1630
|
-
|
|
1631
|
-
|
|
1632
|
-
|
|
1633
|
-
|
|
1634
|
-
are
|
|
1635
|
-
|
|
1636
|
-
|
|
1637
|
-
|
|
1638
|
-
|
|
1639
|
-
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
|
|
1643
|
-
|
|
1644
|
-
|
|
1645
|
-
:
|
|
1646
|
-
|
|
1647
|
-
|
|
1648
|
-
|
|
1649
|
-
|
|
1650
|
-
|
|
1651
|
-
|
|
1652
|
-
|
|
1653
|
-
|
|
1654
|
-
self._parent
|
|
1655
|
-
self._parent.
|
|
1656
|
-
self._parent.bind('<Control-
|
|
1657
|
-
self._parent.bind('<Control-
|
|
1658
|
-
|
|
1659
|
-
|
|
1660
|
-
|
|
1661
|
-
|
|
1662
|
-
|
|
1663
|
-
self.
|
|
1664
|
-
|
|
1665
|
-
|
|
1666
|
-
|
|
1667
|
-
|
|
1668
|
-
|
|
1669
|
-
canvas['
|
|
1670
|
-
|
|
1671
|
-
|
|
1672
|
-
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
|
|
1677
|
-
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
|
|
1681
|
-
|
|
1682
|
-
|
|
1683
|
-
self.
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
filemenu
|
|
1690
|
-
|
|
1691
|
-
|
|
1692
|
-
|
|
1693
|
-
|
|
1694
|
-
|
|
1695
|
-
|
|
1696
|
-
|
|
1697
|
-
|
|
1698
|
-
|
|
1699
|
-
|
|
1700
|
-
|
|
1701
|
-
|
|
1702
|
-
|
|
1703
|
-
:
|
|
1704
|
-
:
|
|
1705
|
-
|
|
1706
|
-
|
|
1707
|
-
|
|
1708
|
-
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
|
-
filename
|
|
1712
|
-
|
|
1713
|
-
|
|
1714
|
-
|
|
1715
|
-
|
|
1716
|
-
|
|
1717
|
-
|
|
1718
|
-
|
|
1719
|
-
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
:
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
|
|
1734
|
-
|
|
1735
|
-
|
|
1736
|
-
|
|
1737
|
-
|
|
1738
|
-
|
|
1739
|
-
|
|
1740
|
-
|
|
1741
|
-
|
|
1742
|
-
|
|
1743
|
-
|
|
1744
|
-
|
|
1745
|
-
|
|
1746
|
-
|
|
1747
|
-
|
|
1748
|
-
:
|
|
1749
|
-
|
|
1750
|
-
|
|
1751
|
-
|
|
1752
|
-
|
|
1753
|
-
|
|
1754
|
-
|
|
1755
|
-
|
|
1756
|
-
|
|
1757
|
-
|
|
1758
|
-
|
|
1759
|
-
|
|
1760
|
-
|
|
1761
|
-
|
|
1762
|
-
|
|
1763
|
-
|
|
1764
|
-
|
|
1765
|
-
|
|
1766
|
-
|
|
1767
|
-
|
|
1768
|
-
|
|
1769
|
-
|
|
1770
|
-
"""
|
|
1771
|
-
|
|
1772
|
-
|
|
1773
|
-
|
|
1774
|
-
|
|
1775
|
-
|
|
1776
|
-
|
|
1777
|
-
|
|
1778
|
-
|
|
1779
|
-
|
|
1780
|
-
widget
|
|
1781
|
-
|
|
1782
|
-
|
|
1783
|
-
|
|
1784
|
-
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
|
|
1788
|
-
|
|
1789
|
-
|
|
1790
|
-
|
|
1791
|
-
|
|
1792
|
-
|
|
1793
|
-
|
|
1794
|
-
|
|
1795
|
-
|
|
1796
|
-
|
|
1797
|
-
|
|
1798
|
-
|
|
1799
|
-
|
|
1800
|
-
|
|
1801
|
-
|
|
1802
|
-
|
|
1803
|
-
|
|
1804
|
-
|
|
1805
|
-
|
|
1806
|
-
|
|
1807
|
-
|
|
1808
|
-
|
|
1809
|
-
|
|
1810
|
-
|
|
1811
|
-
|
|
1812
|
-
|
|
1813
|
-
|
|
1814
|
-
|
|
1815
|
-
|
|
1816
|
-
|
|
1817
|
-
|
|
1818
|
-
|
|
1819
|
-
|
|
1820
|
-
|
|
1821
|
-
|
|
1822
|
-
|
|
1823
|
-
|
|
1824
|
-
|
|
1825
|
-
|
|
1826
|
-
|
|
1827
|
-
self._parent
|
|
1828
|
-
|
|
1829
|
-
|
|
1830
|
-
|
|
1831
|
-
|
|
1832
|
-
|
|
1833
|
-
|
|
1834
|
-
|
|
1835
|
-
|
|
1836
|
-
|
|
1837
|
-
|
|
1838
|
-
|
|
1839
|
-
|
|
1840
|
-
|
|
1841
|
-
##//////////////////////////////////////////////////////
|
|
1842
|
-
|
|
1843
|
-
|
|
1844
|
-
|
|
1845
|
-
|
|
1846
|
-
|
|
1847
|
-
|
|
1848
|
-
|
|
1849
|
-
|
|
1850
|
-
|
|
1851
|
-
|
|
1852
|
-
|
|
1853
|
-
|
|
1854
|
-
|
|
1855
|
-
|
|
1856
|
-
|
|
1857
|
-
|
|
1858
|
-
self._top = top =
|
|
1859
|
-
|
|
1860
|
-
|
|
1861
|
-
|
|
1862
|
-
|
|
1863
|
-
|
|
1864
|
-
|
|
1865
|
-
|
|
1866
|
-
|
|
1867
|
-
|
|
1868
|
-
|
|
1869
|
-
|
|
1870
|
-
textbox
|
|
1871
|
-
|
|
1872
|
-
textbox.
|
|
1873
|
-
|
|
1874
|
-
textbox
|
|
1875
|
-
|
|
1876
|
-
|
|
1877
|
-
|
|
1878
|
-
|
|
1879
|
-
top.bind('
|
|
1880
|
-
top.bind('
|
|
1881
|
-
top.bind('
|
|
1882
|
-
|
|
1883
|
-
|
|
1884
|
-
|
|
1885
|
-
|
|
1886
|
-
|
|
1887
|
-
|
|
1888
|
-
|
|
1889
|
-
|
|
1890
|
-
|
|
1891
|
-
|
|
1892
|
-
|
|
1893
|
-
|
|
1894
|
-
|
|
1895
|
-
|
|
1896
|
-
|
|
1897
|
-
|
|
1898
|
-
|
|
1899
|
-
|
|
1900
|
-
|
|
1901
|
-
|
|
1902
|
-
|
|
1903
|
-
|
|
1904
|
-
|
|
1905
|
-
|
|
1906
|
-
|
|
1907
|
-
self._top
|
|
1908
|
-
|
|
1909
|
-
|
|
1910
|
-
|
|
1911
|
-
|
|
1912
|
-
|
|
1913
|
-
|
|
1914
|
-
|
|
1915
|
-
|
|
1916
|
-
|
|
1917
|
-
|
|
1918
|
-
|
|
1919
|
-
|
|
1920
|
-
|
|
1921
|
-
##//////////////////////////////////////////////////////
|
|
1922
|
-
|
|
1923
|
-
|
|
1924
|
-
|
|
1925
|
-
|
|
1926
|
-
"""
|
|
1927
|
-
|
|
1928
|
-
|
|
1929
|
-
|
|
1930
|
-
|
|
1931
|
-
self.
|
|
1932
|
-
|
|
1933
|
-
|
|
1934
|
-
|
|
1935
|
-
|
|
1936
|
-
|
|
1937
|
-
|
|
1938
|
-
|
|
1939
|
-
|
|
1940
|
-
|
|
1941
|
-
|
|
1942
|
-
|
|
1943
|
-
|
|
1944
|
-
|
|
1945
|
-
|
|
1946
|
-
self._entry
|
|
1947
|
-
|
|
1948
|
-
|
|
1949
|
-
|
|
1950
|
-
|
|
1951
|
-
|
|
1952
|
-
|
|
1953
|
-
|
|
1954
|
-
buttons.
|
|
1955
|
-
|
|
1956
|
-
|
|
1957
|
-
b = Button(buttons, text='
|
|
1958
|
-
|
|
1959
|
-
b
|
|
1960
|
-
|
|
1961
|
-
b.pack(side='left')
|
|
1962
|
-
|
|
1963
|
-
|
|
1964
|
-
|
|
1965
|
-
self._top.bind('<
|
|
1966
|
-
|
|
1967
|
-
self.
|
|
1968
|
-
|
|
1969
|
-
|
|
1970
|
-
|
|
1971
|
-
|
|
1972
|
-
|
|
1973
|
-
|
|
1974
|
-
|
|
1975
|
-
|
|
1976
|
-
|
|
1977
|
-
|
|
1978
|
-
self.
|
|
1979
|
-
|
|
1980
|
-
|
|
1981
|
-
|
|
1982
|
-
|
|
1983
|
-
|
|
1984
|
-
|
|
1985
|
-
|
|
1986
|
-
|
|
1987
|
-
|
|
1988
|
-
|
|
1989
|
-
|
|
1990
|
-
|
|
1991
|
-
self._top
|
|
1992
|
-
|
|
1993
|
-
|
|
1994
|
-
|
|
1995
|
-
##//////////////////////////////////////////////////////
|
|
1996
|
-
|
|
1997
|
-
|
|
1998
|
-
|
|
1999
|
-
|
|
2000
|
-
|
|
2001
|
-
|
|
2002
|
-
|
|
2003
|
-
- ``
|
|
2004
|
-
|
|
2005
|
-
|
|
2006
|
-
|
|
2007
|
-
|
|
2008
|
-
|
|
2009
|
-
|
|
2010
|
-
|
|
2011
|
-
|
|
2012
|
-
|
|
2013
|
-
|
|
2014
|
-
|
|
2015
|
-
:param
|
|
2016
|
-
|
|
2017
|
-
|
|
2018
|
-
|
|
2019
|
-
|
|
2020
|
-
|
|
2021
|
-
|
|
2022
|
-
|
|
2023
|
-
|
|
2024
|
-
|
|
2025
|
-
|
|
2026
|
-
|
|
2027
|
-
|
|
2028
|
-
|
|
2029
|
-
|
|
2030
|
-
|
|
2031
|
-
|
|
2032
|
-
|
|
2033
|
-
|
|
2034
|
-
|
|
2035
|
-
|
|
2036
|
-
#////////////////////////////////////////////////////////////
|
|
2037
|
-
|
|
2038
|
-
|
|
2039
|
-
|
|
2040
|
-
|
|
2041
|
-
|
|
2042
|
-
|
|
2043
|
-
|
|
2044
|
-
|
|
2045
|
-
|
|
2046
|
-
|
|
2047
|
-
|
|
2048
|
-
|
|
2049
|
-
|
|
2050
|
-
|
|
2051
|
-
|
|
2052
|
-
|
|
2053
|
-
|
|
2054
|
-
|
|
2055
|
-
|
|
2056
|
-
|
|
2057
|
-
|
|
2058
|
-
|
|
2059
|
-
|
|
2060
|
-
|
|
2061
|
-
|
|
2062
|
-
|
|
2063
|
-
|
|
2064
|
-
|
|
2065
|
-
|
|
2066
|
-
|
|
2067
|
-
|
|
2068
|
-
|
|
2069
|
-
|
|
2070
|
-
|
|
2071
|
-
|
|
2072
|
-
|
|
2073
|
-
|
|
2074
|
-
self._items
|
|
2075
|
-
|
|
2076
|
-
|
|
2077
|
-
self._textwidget
|
|
2078
|
-
|
|
2079
|
-
|
|
2080
|
-
|
|
2081
|
-
|
|
2082
|
-
|
|
2083
|
-
|
|
2084
|
-
|
|
2085
|
-
self._textwidget.
|
|
2086
|
-
self._textwidget
|
|
2087
|
-
|
|
2088
|
-
|
|
2089
|
-
|
|
2090
|
-
|
|
2091
|
-
|
|
2092
|
-
|
|
2093
|
-
|
|
2094
|
-
|
|
2095
|
-
:raise
|
|
2096
|
-
|
|
2097
|
-
|
|
2098
|
-
|
|
2099
|
-
self.
|
|
2100
|
-
|
|
2101
|
-
|
|
2102
|
-
|
|
2103
|
-
|
|
2104
|
-
|
|
2105
|
-
|
|
2106
|
-
|
|
2107
|
-
|
|
2108
|
-
|
|
2109
|
-
|
|
2110
|
-
|
|
2111
|
-
|
|
2112
|
-
|
|
2113
|
-
|
|
2114
|
-
|
|
2115
|
-
|
|
2116
|
-
|
|
2117
|
-
|
|
2118
|
-
|
|
2119
|
-
|
|
2120
|
-
|
|
2121
|
-
|
|
2122
|
-
self.
|
|
2123
|
-
|
|
2124
|
-
|
|
2125
|
-
|
|
2126
|
-
|
|
2127
|
-
the
|
|
2128
|
-
|
|
2129
|
-
|
|
2130
|
-
self.
|
|
2131
|
-
|
|
2132
|
-
|
|
2133
|
-
|
|
2134
|
-
|
|
2135
|
-
|
|
2136
|
-
|
|
2137
|
-
|
|
2138
|
-
|
|
2139
|
-
|
|
2140
|
-
|
|
2141
|
-
|
|
2142
|
-
|
|
2143
|
-
|
|
2144
|
-
|
|
2145
|
-
|
|
2146
|
-
|
|
2147
|
-
|
|
2148
|
-
|
|
2149
|
-
|
|
2150
|
-
|
|
2151
|
-
|
|
2152
|
-
|
|
2153
|
-
|
|
2154
|
-
|
|
2155
|
-
|
|
2156
|
-
|
|
2157
|
-
|
|
2158
|
-
|
|
2159
|
-
|
|
2160
|
-
|
|
2161
|
-
|
|
2162
|
-
|
|
2163
|
-
elif event == '
|
|
2164
|
-
|
|
2165
|
-
|
|
2166
|
-
|
|
2167
|
-
|
|
2168
|
-
|
|
2169
|
-
|
|
2170
|
-
|
|
2171
|
-
|
|
2172
|
-
|
|
2173
|
-
|
|
2174
|
-
|
|
2175
|
-
|
|
2176
|
-
|
|
2177
|
-
|
|
2178
|
-
|
|
2179
|
-
|
|
2180
|
-
|
|
2181
|
-
|
|
2182
|
-
|
|
2183
|
-
|
|
2184
|
-
|
|
2185
|
-
|
|
2186
|
-
|
|
2187
|
-
|
|
2188
|
-
|
|
2189
|
-
|
|
2190
|
-
|
|
2191
|
-
|
|
2192
|
-
|
|
2193
|
-
|
|
2194
|
-
|
|
2195
|
-
|
|
2196
|
-
|
|
2197
|
-
|
|
2198
|
-
self.
|
|
2199
|
-
|
|
2200
|
-
|
|
2201
|
-
self.
|
|
2202
|
-
self._textscroll.
|
|
2203
|
-
self.
|
|
2204
|
-
|
|
2205
|
-
|
|
2206
|
-
|
|
2207
|
-
|
|
2208
|
-
|
|
2209
|
-
|
|
2210
|
-
|
|
2211
|
-
|
|
2212
|
-
self._textwidget.tag_config('sel', foreground=''
|
|
2213
|
-
|
|
2214
|
-
|
|
2215
|
-
|
|
2216
|
-
|
|
2217
|
-
|
|
2218
|
-
if
|
|
2219
|
-
|
|
2220
|
-
|
|
2221
|
-
|
|
2222
|
-
|
|
2223
|
-
|
|
2224
|
-
|
|
2225
|
-
|
|
2226
|
-
|
|
2227
|
-
|
|
2228
|
-
|
|
2229
|
-
|
|
2230
|
-
|
|
2231
|
-
|
|
2232
|
-
|
|
2233
|
-
|
|
2234
|
-
|
|
2235
|
-
|
|
2236
|
-
|
|
2237
|
-
|
|
2238
|
-
elif event.keysym == '
|
|
2239
|
-
elif event.keysym == '
|
|
2240
|
-
elif event.keysym == '
|
|
2241
|
-
|
|
2242
|
-
|
|
2243
|
-
|
|
2244
|
-
self._textwidget.
|
|
2245
|
-
self._textwidget.
|
|
2246
|
-
self._textwidget.
|
|
2247
|
-
|
|
2248
|
-
|
|
2249
|
-
|
|
2250
|
-
|
|
2251
|
-
|
|
2252
|
-
|
|
2253
|
-
|
|
2254
|
-
|
|
2255
|
-
|
|
2256
|
-
|
|
2257
|
-
|
|
2258
|
-
|
|
2259
|
-
|
|
2260
|
-
|
|
2261
|
-
|
|
2262
|
-
|
|
2263
|
-
|
|
2264
|
-
|
|
2265
|
-
|
|
2266
|
-
|
|
2267
|
-
|
|
2268
|
-
|
|
2269
|
-
|
|
2270
|
-
"
|
|
2271
|
-
|
|
2272
|
-
|
|
2273
|
-
self
|
|
2274
|
-
self.
|
|
2275
|
-
self.
|
|
2276
|
-
|
|
2277
|
-
|
|
2278
|
-
|
|
2279
|
-
|
|
2280
|
-
|
|
2281
|
-
|
|
2282
|
-
|
|
2283
|
-
|
|
2284
|
-
|
|
2285
|
-
|
|
2286
|
-
self.
|
|
2287
|
-
|
|
2288
|
-
|
|
2289
|
-
|
|
2290
|
-
|
|
2291
|
-
|
|
2292
|
-
|
|
2293
|
-
|
|
2294
|
-
|
|
2295
|
-
|
|
2296
|
-
|
|
2297
|
-
self.
|
|
2298
|
-
|
|
2299
|
-
|
|
2300
|
-
|
|
2301
|
-
|
|
2302
|
-
|
|
2303
|
-
|
|
2304
|
-
|
|
2305
|
-
|
|
2306
|
-
|
|
2307
|
-
self
|
|
2308
|
-
|
|
2309
|
-
|
|
2310
|
-
|
|
2311
|
-
|
|
2312
|
-
|
|
2313
|
-
|
|
2314
|
-
|
|
2315
|
-
|
|
2316
|
-
|
|
2317
|
-
|
|
2318
|
-
|
|
2319
|
-
|
|
2320
|
-
|
|
2321
|
-
|
|
2322
|
-
|
|
2323
|
-
|
|
2324
|
-
|
|
2325
|
-
|
|
2326
|
-
|
|
2327
|
-
|
|
2328
|
-
|
|
2329
|
-
|
|
2330
|
-
|
|
2331
|
-
|
|
2332
|
-
|
|
2333
|
-
|
|
2334
|
-
SymbolWidget(c, '
|
|
2335
|
-
|
|
2336
|
-
TextWidget(c, '
|
|
2337
|
-
|
|
2338
|
-
|
|
2339
|
-
|
|
2340
|
-
|
|
2341
|
-
|
|
2342
|
-
|
|
2343
|
-
|
|
2344
|
-
|
|
2345
|
-
|
|
2346
|
-
|
|
2347
|
-
|
|
2348
|
-
|
|
2349
|
-
|
|
2350
|
-
|
|
2351
|
-
|
|
2352
|
-
|
|
2353
|
-
|
|
2354
|
-
|
|
2355
|
-
|
|
2356
|
-
|
|
1
|
+
# Natural Language Toolkit: Drawing utilities
|
|
2
|
+
#
|
|
3
|
+
# Copyright (C) 2001-2018 NLTK Project
|
|
4
|
+
# Author: Edward Loper <edloper@gmail.com>
|
|
5
|
+
# URL: <http://nltk.org/>
|
|
6
|
+
# For license information, see LICENSE.TXT
|
|
7
|
+
|
|
8
|
+
"""
|
|
9
|
+
Tools for graphically displaying and interacting with the objects and
|
|
10
|
+
processing classes defined by the Toolkit. These tools are primarily
|
|
11
|
+
intended to help students visualize the objects that they create.
|
|
12
|
+
|
|
13
|
+
The graphical tools are typically built using "canvas widgets", each
|
|
14
|
+
of which encapsulates the graphical elements and bindings used to
|
|
15
|
+
display a complex object on a Tkinter ``Canvas``. For example, NLTK
|
|
16
|
+
defines canvas widgets for displaying trees and directed graphs, as
|
|
17
|
+
well as a number of simpler widgets. These canvas widgets make it
|
|
18
|
+
easier to build new graphical tools and demos. See the class
|
|
19
|
+
documentation for ``CanvasWidget`` for more information.
|
|
20
|
+
|
|
21
|
+
The ``nltk.draw`` module defines the abstract ``CanvasWidget`` base
|
|
22
|
+
class, and a number of simple canvas widgets. The remaining canvas
|
|
23
|
+
widgets are defined by submodules, such as ``nltk.draw.tree``.
|
|
24
|
+
|
|
25
|
+
The ``nltk.draw`` module also defines ``CanvasFrame``, which
|
|
26
|
+
encapsulates a ``Canvas`` and its scrollbars. It uses a
|
|
27
|
+
``ScrollWatcherWidget`` to ensure that all canvas widgets contained on
|
|
28
|
+
its canvas are within the scroll region.
|
|
29
|
+
|
|
30
|
+
Acknowledgements: Many of the ideas behind the canvas widget system
|
|
31
|
+
are derived from ``CLIG``, a Tk-based grapher for linguistic data
|
|
32
|
+
structures. For more information, see the CLIG
|
|
33
|
+
homepage (http://www.ags.uni-sb.de/~konrad/clig.html).
|
|
34
|
+
|
|
35
|
+
"""
|
|
36
|
+
from abc import ABCMeta, abstractmethod
|
|
37
|
+
from six import add_metaclass
|
|
38
|
+
from six.moves.tkinter import (Button, Canvas, Entry, Frame, Label, Menu,
|
|
39
|
+
Menubutton, Scrollbar, StringVar, Text, Tk,
|
|
40
|
+
Toplevel, Widget, RAISED)
|
|
41
|
+
from six.moves.tkinter_tkfiledialog import asksaveasfilename
|
|
42
|
+
|
|
43
|
+
from nltk.util import in_idle
|
|
44
|
+
|
|
45
|
+
##//////////////////////////////////////////////////////
|
|
46
|
+
## CanvasWidget
|
|
47
|
+
##//////////////////////////////////////////////////////
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
@add_metaclass(ABCMeta)
|
|
51
|
+
class CanvasWidget(object):
|
|
52
|
+
"""
|
|
53
|
+
A collection of graphical elements and bindings used to display a
|
|
54
|
+
complex object on a Tkinter ``Canvas``. A canvas widget is
|
|
55
|
+
responsible for managing the ``Canvas`` tags and callback bindings
|
|
56
|
+
necessary to display and interact with the object. Canvas widgets
|
|
57
|
+
are often organized into hierarchies, where parent canvas widgets
|
|
58
|
+
control aspects of their child widgets.
|
|
59
|
+
|
|
60
|
+
Each canvas widget is bound to a single ``Canvas``. This ``Canvas``
|
|
61
|
+
is specified as the first argument to the ``CanvasWidget``'s
|
|
62
|
+
constructor.
|
|
63
|
+
|
|
64
|
+
Attributes. Each canvas widget can support a variety of
|
|
65
|
+
"attributes", which control how the canvas widget is displayed.
|
|
66
|
+
Some typical examples attributes are ``color``, ``font``, and
|
|
67
|
+
``radius``. Each attribute has a default value. This default
|
|
68
|
+
value can be overridden in the constructor, using keyword
|
|
69
|
+
arguments of the form ``attribute=value``:
|
|
70
|
+
|
|
71
|
+
>>> from nltk.draw.util import TextWidget
|
|
72
|
+
>>> cn = TextWidget(c, 'test', color='red')
|
|
73
|
+
|
|
74
|
+
Attribute values can also be changed after a canvas widget has
|
|
75
|
+
been constructed, using the ``__setitem__`` operator:
|
|
76
|
+
|
|
77
|
+
>>> cn['font'] = 'times'
|
|
78
|
+
|
|
79
|
+
The current value of an attribute value can be queried using the
|
|
80
|
+
``__getitem__`` operator:
|
|
81
|
+
|
|
82
|
+
>>> cn['color']
|
|
83
|
+
red
|
|
84
|
+
|
|
85
|
+
For a list of the attributes supported by a type of canvas widget,
|
|
86
|
+
see its class documentation.
|
|
87
|
+
|
|
88
|
+
Interaction. The attribute ``'draggable'`` controls whether the
|
|
89
|
+
user can drag a canvas widget around the canvas. By default,
|
|
90
|
+
canvas widgets are not draggable.
|
|
91
|
+
|
|
92
|
+
``CanvasWidget`` provides callback support for two types of user
|
|
93
|
+
interaction: clicking and dragging. The method ``bind_click``
|
|
94
|
+
registers a callback function that is called whenever the canvas
|
|
95
|
+
widget is clicked. The method ``bind_drag`` registers a callback
|
|
96
|
+
function that is called after the canvas widget is dragged. If
|
|
97
|
+
the user clicks or drags a canvas widget with no registered
|
|
98
|
+
callback function, then the interaction event will propagate to
|
|
99
|
+
its parent. For each canvas widget, only one callback function
|
|
100
|
+
may be registered for an interaction event. Callback functions
|
|
101
|
+
can be deregistered with the ``unbind_click`` and ``unbind_drag``
|
|
102
|
+
methods.
|
|
103
|
+
|
|
104
|
+
Subclassing. ``CanvasWidget`` is an abstract class. Subclasses
|
|
105
|
+
are required to implement the following methods:
|
|
106
|
+
|
|
107
|
+
- ``__init__``: Builds a new canvas widget. It must perform the
|
|
108
|
+
following three tasks (in order):
|
|
109
|
+
- Create any new graphical elements.
|
|
110
|
+
- Call ``_add_child_widget`` on each child widget.
|
|
111
|
+
- Call the ``CanvasWidget`` constructor.
|
|
112
|
+
- ``_tags``: Returns a list of the canvas tags for all graphical
|
|
113
|
+
elements managed by this canvas widget, not including
|
|
114
|
+
graphical elements managed by its child widgets.
|
|
115
|
+
- ``_manage``: Arranges the child widgets of this canvas widget.
|
|
116
|
+
This is typically only called when the canvas widget is
|
|
117
|
+
created.
|
|
118
|
+
- ``_update``: Update this canvas widget in response to a
|
|
119
|
+
change in a single child.
|
|
120
|
+
|
|
121
|
+
For a ``CanvasWidget`` with no child widgets, the default
|
|
122
|
+
definitions for ``_manage`` and ``_update`` may be used.
|
|
123
|
+
|
|
124
|
+
If a subclass defines any attributes, then it should implement
|
|
125
|
+
``__getitem__`` and ``__setitem__``. If either of these methods is
|
|
126
|
+
called with an unknown attribute, then they should propagate the
|
|
127
|
+
request to ``CanvasWidget``.
|
|
128
|
+
|
|
129
|
+
Most subclasses implement a number of additional methods that
|
|
130
|
+
modify the ``CanvasWidget`` in some way. These methods must call
|
|
131
|
+
``parent.update(self)`` after making any changes to the canvas
|
|
132
|
+
widget's graphical elements. The canvas widget must also call
|
|
133
|
+
``parent.update(self)`` after changing any attribute value that
|
|
134
|
+
affects the shape or position of the canvas widget's graphical
|
|
135
|
+
elements.
|
|
136
|
+
|
|
137
|
+
:type __canvas: Tkinter.Canvas
|
|
138
|
+
:ivar __canvas: This ``CanvasWidget``'s canvas.
|
|
139
|
+
|
|
140
|
+
:type __parent: CanvasWidget or None
|
|
141
|
+
:ivar __parent: This ``CanvasWidget``'s hierarchical parent widget.
|
|
142
|
+
:type __children: list(CanvasWidget)
|
|
143
|
+
:ivar __children: This ``CanvasWidget``'s hierarchical child widgets.
|
|
144
|
+
|
|
145
|
+
:type __updating: bool
|
|
146
|
+
:ivar __updating: Is this canvas widget currently performing an
|
|
147
|
+
update? If it is, then it will ignore any new update requests
|
|
148
|
+
from child widgets.
|
|
149
|
+
|
|
150
|
+
:type __draggable: bool
|
|
151
|
+
:ivar __draggable: Is this canvas widget draggable?
|
|
152
|
+
:type __press: event
|
|
153
|
+
:ivar __press: The ButtonPress event that we're currently handling.
|
|
154
|
+
:type __drag_x: int
|
|
155
|
+
:ivar __drag_x: Where it's been moved to (to find dx)
|
|
156
|
+
:type __drag_y: int
|
|
157
|
+
:ivar __drag_y: Where it's been moved to (to find dy)
|
|
158
|
+
:type __callbacks: dictionary
|
|
159
|
+
:ivar __callbacks: Registered callbacks. Currently, four keys are
|
|
160
|
+
used: ``1``, ``2``, ``3``, and ``'drag'``. The values are
|
|
161
|
+
callback functions. Each callback function takes a single
|
|
162
|
+
argument, which is the ``CanvasWidget`` that triggered the
|
|
163
|
+
callback.
|
|
164
|
+
"""
|
|
165
|
+
def __init__(self, canvas, parent=None, **attribs):
|
|
166
|
+
"""
|
|
167
|
+
Create a new canvas widget. This constructor should only be
|
|
168
|
+
called by subclass constructors; and it should be called only
|
|
169
|
+
"after" the subclass has constructed all graphical canvas
|
|
170
|
+
objects and registered all child widgets.
|
|
171
|
+
|
|
172
|
+
:param canvas: This canvas widget's canvas.
|
|
173
|
+
:type canvas: Tkinter.Canvas
|
|
174
|
+
:param parent: This canvas widget's hierarchical parent.
|
|
175
|
+
:type parent: CanvasWidget
|
|
176
|
+
:param attribs: The new canvas widget's attributes.
|
|
177
|
+
"""
|
|
178
|
+
if self.__class__ == CanvasWidget:
|
|
179
|
+
raise TypeError('CanvasWidget is an abstract base class')
|
|
180
|
+
|
|
181
|
+
if not isinstance(canvas, Canvas):
|
|
182
|
+
raise TypeError('Expected a canvas!')
|
|
183
|
+
|
|
184
|
+
self.__canvas = canvas
|
|
185
|
+
self.__parent = parent
|
|
186
|
+
|
|
187
|
+
# If the subclass constructor called _add_child_widget, then
|
|
188
|
+
# self.__children will already exist.
|
|
189
|
+
if not hasattr(self, '_CanvasWidget__children'): self.__children = []
|
|
190
|
+
|
|
191
|
+
# Is this widget hidden?
|
|
192
|
+
self.__hidden = 0
|
|
193
|
+
|
|
194
|
+
# Update control (prevents infinite loops)
|
|
195
|
+
self.__updating = 0
|
|
196
|
+
|
|
197
|
+
# Button-press and drag callback handling.
|
|
198
|
+
self.__press = None
|
|
199
|
+
self.__drag_x = self.__drag_y = 0
|
|
200
|
+
self.__callbacks = {}
|
|
201
|
+
self.__draggable = 0
|
|
202
|
+
|
|
203
|
+
# Set up attributes.
|
|
204
|
+
for (attr, value) in list(attribs.items()): self[attr] = value
|
|
205
|
+
|
|
206
|
+
# Manage this canvas widget
|
|
207
|
+
self._manage()
|
|
208
|
+
|
|
209
|
+
# Register any new bindings
|
|
210
|
+
for tag in self._tags():
|
|
211
|
+
self.__canvas.tag_bind(tag, '<ButtonPress-1>',
|
|
212
|
+
self.__press_cb)
|
|
213
|
+
self.__canvas.tag_bind(tag, '<ButtonPress-2>',
|
|
214
|
+
self.__press_cb)
|
|
215
|
+
self.__canvas.tag_bind(tag, '<ButtonPress-3>',
|
|
216
|
+
self.__press_cb)
|
|
217
|
+
|
|
218
|
+
##//////////////////////////////////////////////////////
|
|
219
|
+
## Inherited methods.
|
|
220
|
+
##//////////////////////////////////////////////////////
|
|
221
|
+
|
|
222
|
+
def bbox(self):
|
|
223
|
+
"""
|
|
224
|
+
:return: A bounding box for this ``CanvasWidget``. The bounding
|
|
225
|
+
box is a tuple of four coordinates, *(xmin, ymin, xmax, ymax)*,
|
|
226
|
+
for a rectangle which encloses all of the canvas
|
|
227
|
+
widget's graphical elements. Bounding box coordinates are
|
|
228
|
+
specified with respect to the coordinate space of the ``Canvas``.
|
|
229
|
+
:rtype: tuple(int, int, int, int)
|
|
230
|
+
"""
|
|
231
|
+
if self.__hidden: return (0,0,0,0)
|
|
232
|
+
if len(self.tags()) == 0: raise ValueError('No tags')
|
|
233
|
+
return self.__canvas.bbox(*self.tags())
|
|
234
|
+
|
|
235
|
+
def width(self):
|
|
236
|
+
"""
|
|
237
|
+
:return: The width of this canvas widget's bounding box, in
|
|
238
|
+
its ``Canvas``'s coordinate space.
|
|
239
|
+
:rtype: int
|
|
240
|
+
"""
|
|
241
|
+
if len(self.tags()) == 0: raise ValueError('No tags')
|
|
242
|
+
bbox = self.__canvas.bbox(*self.tags())
|
|
243
|
+
return bbox[2]-bbox[0]
|
|
244
|
+
|
|
245
|
+
def height(self):
|
|
246
|
+
"""
|
|
247
|
+
:return: The height of this canvas widget's bounding box, in
|
|
248
|
+
its ``Canvas``'s coordinate space.
|
|
249
|
+
:rtype: int
|
|
250
|
+
"""
|
|
251
|
+
if len(self.tags()) == 0: raise ValueError('No tags')
|
|
252
|
+
bbox = self.__canvas.bbox(*self.tags())
|
|
253
|
+
return bbox[3]-bbox[1]
|
|
254
|
+
|
|
255
|
+
def parent(self):
|
|
256
|
+
"""
|
|
257
|
+
:return: The hierarchical parent of this canvas widget.
|
|
258
|
+
``self`` is considered a subpart of its parent for
|
|
259
|
+
purposes of user interaction.
|
|
260
|
+
:rtype: CanvasWidget or None
|
|
261
|
+
"""
|
|
262
|
+
return self.__parent
|
|
263
|
+
|
|
264
|
+
def child_widgets(self):
|
|
265
|
+
"""
|
|
266
|
+
:return: A list of the hierarchical children of this canvas
|
|
267
|
+
widget. These children are considered part of ``self``
|
|
268
|
+
for purposes of user interaction.
|
|
269
|
+
:rtype: list of CanvasWidget
|
|
270
|
+
"""
|
|
271
|
+
return self.__children
|
|
272
|
+
|
|
273
|
+
def canvas(self):
|
|
274
|
+
"""
|
|
275
|
+
:return: The canvas that this canvas widget is bound to.
|
|
276
|
+
:rtype: Tkinter.Canvas
|
|
277
|
+
"""
|
|
278
|
+
return self.__canvas
|
|
279
|
+
|
|
280
|
+
def move(self, dx, dy):
|
|
281
|
+
"""
|
|
282
|
+
Move this canvas widget by a given distance. In particular,
|
|
283
|
+
shift the canvas widget right by ``dx`` pixels, and down by
|
|
284
|
+
``dy`` pixels. Both ``dx`` and ``dy`` may be negative, resulting
|
|
285
|
+
in leftward or upward movement.
|
|
286
|
+
|
|
287
|
+
:type dx: int
|
|
288
|
+
:param dx: The number of pixels to move this canvas widget
|
|
289
|
+
rightwards.
|
|
290
|
+
:type dy: int
|
|
291
|
+
:param dy: The number of pixels to move this canvas widget
|
|
292
|
+
downwards.
|
|
293
|
+
:rtype: None
|
|
294
|
+
"""
|
|
295
|
+
if dx == dy == 0: return
|
|
296
|
+
for tag in self.tags():
|
|
297
|
+
self.__canvas.move(tag, dx, dy)
|
|
298
|
+
if self.__parent: self.__parent.update(self)
|
|
299
|
+
|
|
300
|
+
def moveto(self, x, y, anchor='NW'):
|
|
301
|
+
"""
|
|
302
|
+
Move this canvas widget to the given location. In particular,
|
|
303
|
+
shift the canvas widget such that the corner or side of the
|
|
304
|
+
bounding box specified by ``anchor`` is at location (``x``,
|
|
305
|
+
``y``).
|
|
306
|
+
|
|
307
|
+
:param x,y: The location that the canvas widget should be moved
|
|
308
|
+
to.
|
|
309
|
+
:param anchor: The corner or side of the canvas widget that
|
|
310
|
+
should be moved to the specified location. ``'N'``
|
|
311
|
+
specifies the top center; ``'NE'`` specifies the top right
|
|
312
|
+
corner; etc.
|
|
313
|
+
"""
|
|
314
|
+
x1,y1,x2,y2 = self.bbox()
|
|
315
|
+
if anchor == 'NW': self.move(x-x1, y-y1)
|
|
316
|
+
if anchor == 'N': self.move(x-x1/2-x2/2, y-y1)
|
|
317
|
+
if anchor == 'NE': self.move(x-x2, y-y1)
|
|
318
|
+
if anchor == 'E': self.move(x-x2, y-y1/2-y2/2)
|
|
319
|
+
if anchor == 'SE': self.move(x-x2, y-y2)
|
|
320
|
+
if anchor == 'S': self.move(x-x1/2-x2/2, y-y2)
|
|
321
|
+
if anchor == 'SW': self.move(x-x1, y-y2)
|
|
322
|
+
if anchor == 'W': self.move(x-x1, y-y1/2-y2/2)
|
|
323
|
+
|
|
324
|
+
def destroy(self):
|
|
325
|
+
"""
|
|
326
|
+
Remove this ``CanvasWidget`` from its ``Canvas``. After a
|
|
327
|
+
``CanvasWidget`` has been destroyed, it should not be accessed.
|
|
328
|
+
|
|
329
|
+
Note that you only need to destroy a top-level
|
|
330
|
+
``CanvasWidget``; its child widgets will be destroyed
|
|
331
|
+
automatically. If you destroy a non-top-level
|
|
332
|
+
``CanvasWidget``, then the entire top-level widget will be
|
|
333
|
+
destroyed.
|
|
334
|
+
|
|
335
|
+
:raise ValueError: if this ``CanvasWidget`` has a parent.
|
|
336
|
+
:rtype: None
|
|
337
|
+
"""
|
|
338
|
+
if self.__parent is not None:
|
|
339
|
+
self.__parent.destroy()
|
|
340
|
+
return
|
|
341
|
+
|
|
342
|
+
for tag in self.tags():
|
|
343
|
+
self.__canvas.tag_unbind(tag, '<ButtonPress-1>')
|
|
344
|
+
self.__canvas.tag_unbind(tag, '<ButtonPress-2>')
|
|
345
|
+
self.__canvas.tag_unbind(tag, '<ButtonPress-3>')
|
|
346
|
+
self.__canvas.delete(*self.tags())
|
|
347
|
+
self.__canvas = None
|
|
348
|
+
|
|
349
|
+
def update(self, child):
|
|
350
|
+
"""
|
|
351
|
+
Update the graphical display of this canvas widget, and all of
|
|
352
|
+
its ancestors, in response to a change in one of this canvas
|
|
353
|
+
widget's children.
|
|
354
|
+
|
|
355
|
+
:param child: The child widget that changed.
|
|
356
|
+
:type child: CanvasWidget
|
|
357
|
+
"""
|
|
358
|
+
if self.__hidden or child.__hidden: return
|
|
359
|
+
# If we're already updating, then do nothing. This prevents
|
|
360
|
+
# infinite loops when _update modifies its children.
|
|
361
|
+
if self.__updating: return
|
|
362
|
+
self.__updating = 1
|
|
363
|
+
|
|
364
|
+
# Update this CanvasWidget.
|
|
365
|
+
self._update(child)
|
|
366
|
+
|
|
367
|
+
# Propagate update request to the parent.
|
|
368
|
+
if self.__parent: self.__parent.update(self)
|
|
369
|
+
|
|
370
|
+
# We're done updating.
|
|
371
|
+
self.__updating = 0
|
|
372
|
+
|
|
373
|
+
def manage(self):
|
|
374
|
+
"""
|
|
375
|
+
Arrange this canvas widget and all of its descendants.
|
|
376
|
+
|
|
377
|
+
:rtype: None
|
|
378
|
+
"""
|
|
379
|
+
if self.__hidden: return
|
|
380
|
+
for child in self.__children: child.manage()
|
|
381
|
+
self._manage()
|
|
382
|
+
|
|
383
|
+
def tags(self):
|
|
384
|
+
"""
|
|
385
|
+
:return: a list of the canvas tags for all graphical
|
|
386
|
+
elements managed by this canvas widget, including
|
|
387
|
+
graphical elements managed by its child widgets.
|
|
388
|
+
:rtype: list of int
|
|
389
|
+
"""
|
|
390
|
+
if self.__canvas is None:
|
|
391
|
+
raise ValueError('Attempt to access a destroyed canvas widget')
|
|
392
|
+
tags = []
|
|
393
|
+
tags += self._tags()
|
|
394
|
+
for child in self.__children:
|
|
395
|
+
tags += child.tags()
|
|
396
|
+
return tags
|
|
397
|
+
|
|
398
|
+
def __setitem__(self, attr, value):
|
|
399
|
+
"""
|
|
400
|
+
Set the value of the attribute ``attr`` to ``value``. See the
|
|
401
|
+
class documentation for a list of attributes supported by this
|
|
402
|
+
canvas widget.
|
|
403
|
+
|
|
404
|
+
:rtype: None
|
|
405
|
+
"""
|
|
406
|
+
if attr == 'draggable':
|
|
407
|
+
self.__draggable = value
|
|
408
|
+
else:
|
|
409
|
+
raise ValueError('Unknown attribute %r' % attr)
|
|
410
|
+
|
|
411
|
+
def __getitem__(self, attr):
|
|
412
|
+
"""
|
|
413
|
+
:return: the value of the attribute ``attr``. See the class
|
|
414
|
+
documentation for a list of attributes supported by this
|
|
415
|
+
canvas widget.
|
|
416
|
+
:rtype: (any)
|
|
417
|
+
"""
|
|
418
|
+
if attr == 'draggable':
|
|
419
|
+
return self.__draggable
|
|
420
|
+
else:
|
|
421
|
+
raise ValueError('Unknown attribute %r' % attr)
|
|
422
|
+
|
|
423
|
+
def __repr__(self):
|
|
424
|
+
"""
|
|
425
|
+
:return: a string representation of this canvas widget.
|
|
426
|
+
:rtype: str
|
|
427
|
+
"""
|
|
428
|
+
return '<%s>' % self.__class__.__name__
|
|
429
|
+
|
|
430
|
+
def hide(self):
|
|
431
|
+
"""
|
|
432
|
+
Temporarily hide this canvas widget.
|
|
433
|
+
|
|
434
|
+
:rtype: None
|
|
435
|
+
"""
|
|
436
|
+
self.__hidden = 1
|
|
437
|
+
for tag in self.tags():
|
|
438
|
+
self.__canvas.itemconfig(tag, state='hidden')
|
|
439
|
+
|
|
440
|
+
def show(self):
|
|
441
|
+
"""
|
|
442
|
+
Show a hidden canvas widget.
|
|
443
|
+
|
|
444
|
+
:rtype: None
|
|
445
|
+
"""
|
|
446
|
+
self.__hidden = 0
|
|
447
|
+
for tag in self.tags():
|
|
448
|
+
self.__canvas.itemconfig(tag, state='normal')
|
|
449
|
+
|
|
450
|
+
def hidden(self):
|
|
451
|
+
"""
|
|
452
|
+
:return: True if this canvas widget is hidden.
|
|
453
|
+
:rtype: bool
|
|
454
|
+
"""
|
|
455
|
+
return self.__hidden
|
|
456
|
+
|
|
457
|
+
##//////////////////////////////////////////////////////
|
|
458
|
+
## Callback interface
|
|
459
|
+
##//////////////////////////////////////////////////////
|
|
460
|
+
|
|
461
|
+
def bind_click(self, callback, button=1):
|
|
462
|
+
"""
|
|
463
|
+
Register a new callback that will be called whenever this
|
|
464
|
+
``CanvasWidget`` is clicked on.
|
|
465
|
+
|
|
466
|
+
:type callback: function
|
|
467
|
+
:param callback: The callback function that will be called
|
|
468
|
+
whenever this ``CanvasWidget`` is clicked. This function
|
|
469
|
+
will be called with this ``CanvasWidget`` as its argument.
|
|
470
|
+
:type button: int
|
|
471
|
+
:param button: Which button the user should use to click on
|
|
472
|
+
this ``CanvasWidget``. Typically, this should be 1 (left
|
|
473
|
+
button), 3 (right button), or 2 (middle button).
|
|
474
|
+
"""
|
|
475
|
+
self.__callbacks[button] = callback
|
|
476
|
+
|
|
477
|
+
def bind_drag(self, callback):
|
|
478
|
+
"""
|
|
479
|
+
Register a new callback that will be called after this
|
|
480
|
+
``CanvasWidget`` is dragged. This implicitly makes this
|
|
481
|
+
``CanvasWidget`` draggable.
|
|
482
|
+
|
|
483
|
+
:type callback: function
|
|
484
|
+
:param callback: The callback function that will be called
|
|
485
|
+
whenever this ``CanvasWidget`` is clicked. This function
|
|
486
|
+
will be called with this ``CanvasWidget`` as its argument.
|
|
487
|
+
"""
|
|
488
|
+
self.__draggable = 1
|
|
489
|
+
self.__callbacks['drag'] = callback
|
|
490
|
+
|
|
491
|
+
def unbind_click(self, button=1):
|
|
492
|
+
"""
|
|
493
|
+
Remove a callback that was registered with ``bind_click``.
|
|
494
|
+
|
|
495
|
+
:type button: int
|
|
496
|
+
:param button: Which button the user should use to click on
|
|
497
|
+
this ``CanvasWidget``. Typically, this should be 1 (left
|
|
498
|
+
button), 3 (right button), or 2 (middle button).
|
|
499
|
+
"""
|
|
500
|
+
try: del self.__callbacks[button]
|
|
501
|
+
except: pass
|
|
502
|
+
|
|
503
|
+
def unbind_drag(self):
|
|
504
|
+
"""
|
|
505
|
+
Remove a callback that was registered with ``bind_drag``.
|
|
506
|
+
"""
|
|
507
|
+
try: del self.__callbacks['drag']
|
|
508
|
+
except: pass
|
|
509
|
+
|
|
510
|
+
##//////////////////////////////////////////////////////
|
|
511
|
+
## Callback internals
|
|
512
|
+
##//////////////////////////////////////////////////////
|
|
513
|
+
|
|
514
|
+
def __press_cb(self, event):
|
|
515
|
+
"""
|
|
516
|
+
Handle a button-press event:
|
|
517
|
+
- record the button press event in ``self.__press``
|
|
518
|
+
- register a button-release callback.
|
|
519
|
+
- if this CanvasWidget or any of its ancestors are
|
|
520
|
+
draggable, then register the appropriate motion callback.
|
|
521
|
+
"""
|
|
522
|
+
# If we're already waiting for a button release, then ignore
|
|
523
|
+
# this new button press.
|
|
524
|
+
if (self.__canvas.bind('<ButtonRelease-1>') or
|
|
525
|
+
self.__canvas.bind('<ButtonRelease-2>') or
|
|
526
|
+
self.__canvas.bind('<ButtonRelease-3>')):
|
|
527
|
+
return
|
|
528
|
+
|
|
529
|
+
# Unbind motion (just in case; this shouldn't be necessary)
|
|
530
|
+
self.__canvas.unbind('<Motion>')
|
|
531
|
+
|
|
532
|
+
# Record the button press event.
|
|
533
|
+
self.__press = event
|
|
534
|
+
|
|
535
|
+
# If any ancestor is draggable, set up a motion callback.
|
|
536
|
+
# (Only if they pressed button number 1)
|
|
537
|
+
if event.num == 1:
|
|
538
|
+
widget = self
|
|
539
|
+
while widget is not None:
|
|
540
|
+
if widget['draggable']:
|
|
541
|
+
widget.__start_drag(event)
|
|
542
|
+
break
|
|
543
|
+
widget = widget.parent()
|
|
544
|
+
|
|
545
|
+
# Set up the button release callback.
|
|
546
|
+
self.__canvas.bind('<ButtonRelease-%d>' % event.num,
|
|
547
|
+
self.__release_cb)
|
|
548
|
+
|
|
549
|
+
def __start_drag(self, event):
|
|
550
|
+
"""
|
|
551
|
+
Begin dragging this object:
|
|
552
|
+
- register a motion callback
|
|
553
|
+
- record the drag coordinates
|
|
554
|
+
"""
|
|
555
|
+
self.__canvas.bind('<Motion>', self.__motion_cb)
|
|
556
|
+
self.__drag_x = event.x
|
|
557
|
+
self.__drag_y = event.y
|
|
558
|
+
|
|
559
|
+
def __motion_cb(self, event):
|
|
560
|
+
"""
|
|
561
|
+
Handle a motion event:
|
|
562
|
+
- move this object to the new location
|
|
563
|
+
- record the new drag coordinates
|
|
564
|
+
"""
|
|
565
|
+
self.move(event.x-self.__drag_x, event.y-self.__drag_y)
|
|
566
|
+
self.__drag_x = event.x
|
|
567
|
+
self.__drag_y = event.y
|
|
568
|
+
|
|
569
|
+
def __release_cb(self, event):
|
|
570
|
+
"""
|
|
571
|
+
Handle a release callback:
|
|
572
|
+
- unregister motion & button release callbacks.
|
|
573
|
+
- decide whether they clicked, dragged, or cancelled
|
|
574
|
+
- call the appropriate handler.
|
|
575
|
+
"""
|
|
576
|
+
# Unbind the button release & motion callbacks.
|
|
577
|
+
self.__canvas.unbind('<ButtonRelease-%d>' % event.num)
|
|
578
|
+
self.__canvas.unbind('<Motion>')
|
|
579
|
+
|
|
580
|
+
# Is it a click or a drag?
|
|
581
|
+
if (event.time - self.__press.time < 100 and
|
|
582
|
+
abs(event.x-self.__press.x) + abs(event.y-self.__press.y) < 5):
|
|
583
|
+
# Move it back, if we were dragging.
|
|
584
|
+
if self.__draggable and event.num == 1:
|
|
585
|
+
self.move(self.__press.x - self.__drag_x,
|
|
586
|
+
self.__press.y - self.__drag_y)
|
|
587
|
+
self.__click(event.num)
|
|
588
|
+
elif event.num == 1:
|
|
589
|
+
self.__drag()
|
|
590
|
+
|
|
591
|
+
self.__press = None
|
|
592
|
+
|
|
593
|
+
def __drag(self):
|
|
594
|
+
"""
|
|
595
|
+
If this ``CanvasWidget`` has a drag callback, then call it;
|
|
596
|
+
otherwise, find the closest ancestor with a drag callback, and
|
|
597
|
+
call it. If no ancestors have a drag callback, do nothing.
|
|
598
|
+
"""
|
|
599
|
+
if self.__draggable:
|
|
600
|
+
if 'drag' in self.__callbacks:
|
|
601
|
+
cb = self.__callbacks['drag']
|
|
602
|
+
try:
|
|
603
|
+
cb(self)
|
|
604
|
+
except:
|
|
605
|
+
print('Error in drag callback for %r' % self)
|
|
606
|
+
elif self.__parent is not None:
|
|
607
|
+
self.__parent.__drag()
|
|
608
|
+
|
|
609
|
+
def __click(self, button):
|
|
610
|
+
"""
|
|
611
|
+
If this ``CanvasWidget`` has a drag callback, then call it;
|
|
612
|
+
otherwise, find the closest ancestor with a click callback, and
|
|
613
|
+
call it. If no ancestors have a click callback, do nothing.
|
|
614
|
+
"""
|
|
615
|
+
if button in self.__callbacks:
|
|
616
|
+
cb = self.__callbacks[button]
|
|
617
|
+
#try:
|
|
618
|
+
cb(self)
|
|
619
|
+
#except:
|
|
620
|
+
# print 'Error in click callback for %r' % self
|
|
621
|
+
# raise
|
|
622
|
+
elif self.__parent is not None:
|
|
623
|
+
self.__parent.__click(button)
|
|
624
|
+
|
|
625
|
+
##//////////////////////////////////////////////////////
|
|
626
|
+
## Child/parent Handling
|
|
627
|
+
##//////////////////////////////////////////////////////
|
|
628
|
+
|
|
629
|
+
def _add_child_widget(self, child):
|
|
630
|
+
"""
|
|
631
|
+
Register a hierarchical child widget. The child will be
|
|
632
|
+
considered part of this canvas widget for purposes of user
|
|
633
|
+
interaction. ``_add_child_widget`` has two direct effects:
|
|
634
|
+
- It sets ``child``'s parent to this canvas widget.
|
|
635
|
+
- It adds ``child`` to the list of canvas widgets returned by
|
|
636
|
+
the ``child_widgets`` member function.
|
|
637
|
+
|
|
638
|
+
:param child: The new child widget. ``child`` must not already
|
|
639
|
+
have a parent.
|
|
640
|
+
:type child: CanvasWidget
|
|
641
|
+
"""
|
|
642
|
+
if not hasattr(self, '_CanvasWidget__children'): self.__children = []
|
|
643
|
+
if child.__parent is not None:
|
|
644
|
+
raise ValueError('%s already has a parent', child)
|
|
645
|
+
child.__parent = self
|
|
646
|
+
self.__children.append(child)
|
|
647
|
+
|
|
648
|
+
def _remove_child_widget(self, child):
|
|
649
|
+
"""
|
|
650
|
+
Remove a hierarchical child widget. This child will no longer
|
|
651
|
+
be considered part of this canvas widget for purposes of user
|
|
652
|
+
interaction. ``_add_child_widget`` has two direct effects:
|
|
653
|
+
- It sets ``child``'s parent to None.
|
|
654
|
+
- It removes ``child`` from the list of canvas widgets
|
|
655
|
+
returned by the ``child_widgets`` member function.
|
|
656
|
+
|
|
657
|
+
:param child: The child widget to remove. ``child`` must be a
|
|
658
|
+
child of this canvas widget.
|
|
659
|
+
:type child: CanvasWidget
|
|
660
|
+
"""
|
|
661
|
+
self.__children.remove(child)
|
|
662
|
+
child.__parent = None
|
|
663
|
+
|
|
664
|
+
##//////////////////////////////////////////////////////
|
|
665
|
+
## Defined by subclass
|
|
666
|
+
##//////////////////////////////////////////////////////
|
|
667
|
+
|
|
668
|
+
@abstractmethod
|
|
669
|
+
def _tags(self):
|
|
670
|
+
"""
|
|
671
|
+
:return: a list of canvas tags for all graphical elements
|
|
672
|
+
managed by this canvas widget, not including graphical
|
|
673
|
+
elements managed by its child widgets.
|
|
674
|
+
:rtype: list of int
|
|
675
|
+
"""
|
|
676
|
+
|
|
677
|
+
def _manage(self):
|
|
678
|
+
"""
|
|
679
|
+
Arrange the child widgets of this canvas widget. This method
|
|
680
|
+
is called when the canvas widget is initially created. It is
|
|
681
|
+
also called if the user calls the ``manage`` method on this
|
|
682
|
+
canvas widget or any of its ancestors.
|
|
683
|
+
|
|
684
|
+
:rtype: None
|
|
685
|
+
"""
|
|
686
|
+
|
|
687
|
+
def _update(self, child):
|
|
688
|
+
"""
|
|
689
|
+
Update this canvas widget in response to a change in one of
|
|
690
|
+
its children.
|
|
691
|
+
|
|
692
|
+
:param child: The child that changed.
|
|
693
|
+
:type child: CanvasWidget
|
|
694
|
+
:rtype: None
|
|
695
|
+
"""
|
|
696
|
+
|
|
697
|
+
##//////////////////////////////////////////////////////
|
|
698
|
+
## Basic widgets.
|
|
699
|
+
##//////////////////////////////////////////////////////
|
|
700
|
+
|
|
701
|
+
class TextWidget(CanvasWidget):
|
|
702
|
+
"""
|
|
703
|
+
A canvas widget that displays a single string of text.
|
|
704
|
+
|
|
705
|
+
Attributes:
|
|
706
|
+
- ``color``: the color of the text.
|
|
707
|
+
- ``font``: the font used to display the text.
|
|
708
|
+
- ``justify``: justification for multi-line texts. Valid values
|
|
709
|
+
are ``left``, ``center``, and ``right``.
|
|
710
|
+
- ``width``: the width of the text. If the text is wider than
|
|
711
|
+
this width, it will be line-wrapped at whitespace.
|
|
712
|
+
- ``draggable``: whether the text can be dragged by the user.
|
|
713
|
+
"""
|
|
714
|
+
def __init__(self, canvas, text, **attribs):
|
|
715
|
+
"""
|
|
716
|
+
Create a new text widget.
|
|
717
|
+
|
|
718
|
+
:type canvas: Tkinter.Canvas
|
|
719
|
+
:param canvas: This canvas widget's canvas.
|
|
720
|
+
:type text: str
|
|
721
|
+
:param text: The string of text to display.
|
|
722
|
+
:param attribs: The new canvas widget's attributes.
|
|
723
|
+
"""
|
|
724
|
+
self._text = text
|
|
725
|
+
self._tag = canvas.create_text(1, 1, text=text)
|
|
726
|
+
CanvasWidget.__init__(self, canvas, **attribs)
|
|
727
|
+
|
|
728
|
+
def __setitem__(self, attr, value):
|
|
729
|
+
if attr in ('color', 'font', 'justify', 'width'):
|
|
730
|
+
if attr == 'color': attr = 'fill'
|
|
731
|
+
self.canvas().itemconfig(self._tag, {attr:value})
|
|
732
|
+
else:
|
|
733
|
+
CanvasWidget.__setitem__(self, attr, value)
|
|
734
|
+
|
|
735
|
+
def __getitem__(self, attr):
|
|
736
|
+
if attr == 'width':
|
|
737
|
+
return int(self.canvas().itemcget(self._tag, attr))
|
|
738
|
+
elif attr in ('color', 'font', 'justify'):
|
|
739
|
+
if attr == 'color': attr = 'fill'
|
|
740
|
+
return self.canvas().itemcget(self._tag, attr)
|
|
741
|
+
else:
|
|
742
|
+
return CanvasWidget.__getitem__(self, attr)
|
|
743
|
+
|
|
744
|
+
def _tags(self): return [self._tag]
|
|
745
|
+
|
|
746
|
+
def text(self):
|
|
747
|
+
"""
|
|
748
|
+
:return: The text displayed by this text widget.
|
|
749
|
+
:rtype: str
|
|
750
|
+
"""
|
|
751
|
+
return self.canvas().itemcget(self._tag, 'TEXT')
|
|
752
|
+
|
|
753
|
+
def set_text(self, text):
|
|
754
|
+
"""
|
|
755
|
+
Change the text that is displayed by this text widget.
|
|
756
|
+
|
|
757
|
+
:type text: str
|
|
758
|
+
:param text: The string of text to display.
|
|
759
|
+
:rtype: None
|
|
760
|
+
"""
|
|
761
|
+
self.canvas().itemconfig(self._tag, text=text)
|
|
762
|
+
if self.parent() is not None:
|
|
763
|
+
self.parent().update(self)
|
|
764
|
+
|
|
765
|
+
def __repr__(self):
|
|
766
|
+
return '[Text: %r]' % self._text
|
|
767
|
+
|
|
768
|
+
class SymbolWidget(TextWidget):
|
|
769
|
+
"""
|
|
770
|
+
A canvas widget that displays special symbols, such as the
|
|
771
|
+
negation sign and the exists operator. Symbols are specified by
|
|
772
|
+
name. Currently, the following symbol names are defined: ``neg``,
|
|
773
|
+
``disj``, ``conj``, ``lambda``, ``merge``, ``forall``, ``exists``,
|
|
774
|
+
``subseteq``, ``subset``, ``notsubset``, ``emptyset``, ``imp``,
|
|
775
|
+
``rightarrow``, ``equal``, ``notequal``, ``epsilon``.
|
|
776
|
+
|
|
777
|
+
Attributes:
|
|
778
|
+
|
|
779
|
+
- ``color``: the color of the text.
|
|
780
|
+
- ``draggable``: whether the text can be dragged by the user.
|
|
781
|
+
|
|
782
|
+
:cvar SYMBOLS: A dictionary mapping from symbols to the character
|
|
783
|
+
in the ``symbol`` font used to render them.
|
|
784
|
+
"""
|
|
785
|
+
SYMBOLS = {'neg':'\330', 'disj':'\332', 'conj': '\331',
|
|
786
|
+
'lambda': '\154', 'merge': '\304',
|
|
787
|
+
'forall': '\042', 'exists': '\044',
|
|
788
|
+
'subseteq': '\315', 'subset': '\314',
|
|
789
|
+
'notsubset': '\313', 'emptyset': '\306',
|
|
790
|
+
'imp': '\336', 'rightarrow': chr(222), #'\256',
|
|
791
|
+
'equal': '\75', 'notequal': '\271',
|
|
792
|
+
'intersection': '\307', 'union': '\310',
|
|
793
|
+
'epsilon': 'e',
|
|
794
|
+
}
|
|
795
|
+
|
|
796
|
+
def __init__(self, canvas, symbol, **attribs):
|
|
797
|
+
"""
|
|
798
|
+
Create a new symbol widget.
|
|
799
|
+
|
|
800
|
+
:type canvas: Tkinter.Canvas
|
|
801
|
+
:param canvas: This canvas widget's canvas.
|
|
802
|
+
:type symbol: str
|
|
803
|
+
:param symbol: The name of the symbol to display.
|
|
804
|
+
:param attribs: The new canvas widget's attributes.
|
|
805
|
+
"""
|
|
806
|
+
attribs['font'] = 'symbol'
|
|
807
|
+
TextWidget.__init__(self, canvas, '', **attribs)
|
|
808
|
+
self.set_symbol(symbol)
|
|
809
|
+
|
|
810
|
+
def symbol(self):
|
|
811
|
+
"""
|
|
812
|
+
:return: the name of the symbol that is displayed by this
|
|
813
|
+
symbol widget.
|
|
814
|
+
:rtype: str
|
|
815
|
+
"""
|
|
816
|
+
return self._symbol
|
|
817
|
+
|
|
818
|
+
def set_symbol(self, symbol):
|
|
819
|
+
"""
|
|
820
|
+
Change the symbol that is displayed by this symbol widget.
|
|
821
|
+
|
|
822
|
+
:type symbol: str
|
|
823
|
+
:param symbol: The name of the symbol to display.
|
|
824
|
+
"""
|
|
825
|
+
if symbol not in SymbolWidget.SYMBOLS:
|
|
826
|
+
raise ValueError('Unknown symbol: %s' % symbol)
|
|
827
|
+
self._symbol = symbol
|
|
828
|
+
self.set_text(SymbolWidget.SYMBOLS[symbol])
|
|
829
|
+
|
|
830
|
+
def __repr__(self):
|
|
831
|
+
return '[Symbol: %r]' % self._symbol
|
|
832
|
+
|
|
833
|
+
@staticmethod
|
|
834
|
+
def symbolsheet(size=20):
|
|
835
|
+
"""
|
|
836
|
+
Open a new Tkinter window that displays the entire alphabet
|
|
837
|
+
for the symbol font. This is useful for constructing the
|
|
838
|
+
``SymbolWidget.SYMBOLS`` dictionary.
|
|
839
|
+
"""
|
|
840
|
+
top = Tk()
|
|
841
|
+
def destroy(e, top=top): top.destroy()
|
|
842
|
+
top.bind('q', destroy)
|
|
843
|
+
Button(top, text='Quit', command=top.destroy).pack(side='bottom')
|
|
844
|
+
text = Text(top, font=('helvetica', -size), width=20, height=30)
|
|
845
|
+
text.pack(side='left')
|
|
846
|
+
sb=Scrollbar(top, command=text.yview)
|
|
847
|
+
text['yscrollcommand']=sb.set
|
|
848
|
+
sb.pack(side='right', fill='y')
|
|
849
|
+
text.tag_config('symbol', font=('symbol', -size))
|
|
850
|
+
for i in range(256):
|
|
851
|
+
if i in (0,10): continue # null and newline
|
|
852
|
+
for k,v in list(SymbolWidget.SYMBOLS.items()):
|
|
853
|
+
if v == chr(i):
|
|
854
|
+
text.insert('end', '%-10s\t' % k)
|
|
855
|
+
break
|
|
856
|
+
else:
|
|
857
|
+
text.insert('end', '%-10d \t' % i)
|
|
858
|
+
text.insert('end', '[%s]\n' % chr(i), 'symbol')
|
|
859
|
+
top.mainloop()
|
|
860
|
+
|
|
861
|
+
|
|
862
|
+
class AbstractContainerWidget(CanvasWidget):
|
|
863
|
+
"""
|
|
864
|
+
An abstract class for canvas widgets that contain a single child,
|
|
865
|
+
such as ``BoxWidget`` and ``OvalWidget``. Subclasses must define
|
|
866
|
+
a constructor, which should create any new graphical elements and
|
|
867
|
+
then call the ``AbstractCanvasContainer`` constructor. Subclasses
|
|
868
|
+
must also define the ``_update`` method and the ``_tags`` method;
|
|
869
|
+
and any subclasses that define attributes should define
|
|
870
|
+
``__setitem__`` and ``__getitem__``.
|
|
871
|
+
"""
|
|
872
|
+
def __init__(self, canvas, child, **attribs):
|
|
873
|
+
"""
|
|
874
|
+
Create a new container widget. This constructor should only
|
|
875
|
+
be called by subclass constructors.
|
|
876
|
+
|
|
877
|
+
:type canvas: Tkinter.Canvas
|
|
878
|
+
:param canvas: This canvas widget's canvas.
|
|
879
|
+
:param child: The container's child widget. ``child`` must not
|
|
880
|
+
have a parent.
|
|
881
|
+
:type child: CanvasWidget
|
|
882
|
+
:param attribs: The new canvas widget's attributes.
|
|
883
|
+
"""
|
|
884
|
+
self._child = child
|
|
885
|
+
self._add_child_widget(child)
|
|
886
|
+
CanvasWidget.__init__(self, canvas, **attribs)
|
|
887
|
+
|
|
888
|
+
def _manage(self):
|
|
889
|
+
self._update(self._child)
|
|
890
|
+
|
|
891
|
+
def child(self):
|
|
892
|
+
"""
|
|
893
|
+
:return: The child widget contained by this container widget.
|
|
894
|
+
:rtype: CanvasWidget
|
|
895
|
+
"""
|
|
896
|
+
return self._child
|
|
897
|
+
|
|
898
|
+
def set_child(self, child):
|
|
899
|
+
"""
|
|
900
|
+
Change the child widget contained by this container widget.
|
|
901
|
+
|
|
902
|
+
:param child: The new child widget. ``child`` must not have a
|
|
903
|
+
parent.
|
|
904
|
+
:type child: CanvasWidget
|
|
905
|
+
:rtype: None
|
|
906
|
+
"""
|
|
907
|
+
self._remove_child_widget(self._child)
|
|
908
|
+
self._add_child_widget(child)
|
|
909
|
+
self._child = child
|
|
910
|
+
self.update(child)
|
|
911
|
+
|
|
912
|
+
def __repr__(self):
|
|
913
|
+
name = self.__class__.__name__
|
|
914
|
+
if name[-6:] == 'Widget': name = name[:-6]
|
|
915
|
+
return '[%s: %r]' % (name, self._child)
|
|
916
|
+
|
|
917
|
+
class BoxWidget(AbstractContainerWidget):
|
|
918
|
+
"""
|
|
919
|
+
A canvas widget that places a box around a child widget.
|
|
920
|
+
|
|
921
|
+
Attributes:
|
|
922
|
+
- ``fill``: The color used to fill the interior of the box.
|
|
923
|
+
- ``outline``: The color used to draw the outline of the box.
|
|
924
|
+
- ``width``: The width of the outline of the box.
|
|
925
|
+
- ``margin``: The number of pixels space left between the child
|
|
926
|
+
and the box.
|
|
927
|
+
- ``draggable``: whether the text can be dragged by the user.
|
|
928
|
+
"""
|
|
929
|
+
def __init__(self, canvas, child, **attribs):
|
|
930
|
+
"""
|
|
931
|
+
Create a new box widget.
|
|
932
|
+
|
|
933
|
+
:type canvas: Tkinter.Canvas
|
|
934
|
+
:param canvas: This canvas widget's canvas.
|
|
935
|
+
:param child: The child widget. ``child`` must not have a
|
|
936
|
+
parent.
|
|
937
|
+
:type child: CanvasWidget
|
|
938
|
+
:param attribs: The new canvas widget's attributes.
|
|
939
|
+
"""
|
|
940
|
+
self._child = child
|
|
941
|
+
self._margin = 1
|
|
942
|
+
self._box = canvas.create_rectangle(1,1,1,1)
|
|
943
|
+
canvas.tag_lower(self._box)
|
|
944
|
+
AbstractContainerWidget.__init__(self, canvas, child, **attribs)
|
|
945
|
+
|
|
946
|
+
def __setitem__(self, attr, value):
|
|
947
|
+
if attr == 'margin': self._margin = value
|
|
948
|
+
elif attr in ('outline', 'fill', 'width'):
|
|
949
|
+
self.canvas().itemconfig(self._box, {attr:value})
|
|
950
|
+
else:
|
|
951
|
+
CanvasWidget.__setitem__(self, attr, value)
|
|
952
|
+
|
|
953
|
+
def __getitem__(self, attr):
|
|
954
|
+
if attr == 'margin': return self._margin
|
|
955
|
+
elif attr == 'width':
|
|
956
|
+
return float(self.canvas().itemcget(self._box, attr))
|
|
957
|
+
elif attr in ('outline', 'fill', 'width'):
|
|
958
|
+
return self.canvas().itemcget(self._box, attr)
|
|
959
|
+
else:
|
|
960
|
+
return CanvasWidget.__getitem__(self, attr)
|
|
961
|
+
|
|
962
|
+
def _update(self, child):
|
|
963
|
+
(x1, y1, x2, y2) = child.bbox()
|
|
964
|
+
margin = self._margin + self['width']/2
|
|
965
|
+
self.canvas().coords(self._box, x1-margin, y1-margin,
|
|
966
|
+
x2+margin, y2+margin)
|
|
967
|
+
|
|
968
|
+
def _tags(self): return [self._box]
|
|
969
|
+
|
|
970
|
+
class OvalWidget(AbstractContainerWidget):
|
|
971
|
+
"""
|
|
972
|
+
A canvas widget that places a oval around a child widget.
|
|
973
|
+
|
|
974
|
+
Attributes:
|
|
975
|
+
- ``fill``: The color used to fill the interior of the oval.
|
|
976
|
+
- ``outline``: The color used to draw the outline of the oval.
|
|
977
|
+
- ``width``: The width of the outline of the oval.
|
|
978
|
+
- ``margin``: The number of pixels space left between the child
|
|
979
|
+
and the oval.
|
|
980
|
+
- ``draggable``: whether the text can be dragged by the user.
|
|
981
|
+
- ``double``: If true, then a double-oval is drawn.
|
|
982
|
+
"""
|
|
983
|
+
def __init__(self, canvas, child, **attribs):
|
|
984
|
+
"""
|
|
985
|
+
Create a new oval widget.
|
|
986
|
+
|
|
987
|
+
:type canvas: Tkinter.Canvas
|
|
988
|
+
:param canvas: This canvas widget's canvas.
|
|
989
|
+
:param child: The child widget. ``child`` must not have a
|
|
990
|
+
parent.
|
|
991
|
+
:type child: CanvasWidget
|
|
992
|
+
:param attribs: The new canvas widget's attributes.
|
|
993
|
+
"""
|
|
994
|
+
self._child = child
|
|
995
|
+
self._margin = 1
|
|
996
|
+
self._oval = canvas.create_oval(1,1,1,1)
|
|
997
|
+
self._circle = attribs.pop('circle', False)
|
|
998
|
+
self._double = attribs.pop('double', False)
|
|
999
|
+
if self._double:
|
|
1000
|
+
self._oval2 = canvas.create_oval(1,1,1,1)
|
|
1001
|
+
else:
|
|
1002
|
+
self._oval2 = None
|
|
1003
|
+
canvas.tag_lower(self._oval)
|
|
1004
|
+
AbstractContainerWidget.__init__(self, canvas, child, **attribs)
|
|
1005
|
+
|
|
1006
|
+
def __setitem__(self, attr, value):
|
|
1007
|
+
c = self.canvas()
|
|
1008
|
+
if attr == 'margin': self._margin = value
|
|
1009
|
+
elif attr == 'double':
|
|
1010
|
+
if value==True and self._oval2 is None:
|
|
1011
|
+
# Copy attributes & position from self._oval.
|
|
1012
|
+
x1, y1, x2, y2 = c.bbox(self._oval)
|
|
1013
|
+
w = self['width']*2
|
|
1014
|
+
self._oval2 = c.create_oval(x1-w, y1-w, x2+w, y2+w,
|
|
1015
|
+
outline=c.itemcget(self._oval, 'outline'),
|
|
1016
|
+
width=c.itemcget(self._oval, 'width'))
|
|
1017
|
+
c.tag_lower(self._oval2)
|
|
1018
|
+
if value==False and self._oval2 is not None:
|
|
1019
|
+
c.delete(self._oval2)
|
|
1020
|
+
self._oval2 = None
|
|
1021
|
+
elif attr in ('outline', 'fill', 'width'):
|
|
1022
|
+
c.itemconfig(self._oval, {attr:value})
|
|
1023
|
+
if self._oval2 is not None and attr!='fill':
|
|
1024
|
+
c.itemconfig(self._oval2, {attr:value})
|
|
1025
|
+
if self._oval2 is not None and attr!='fill':
|
|
1026
|
+
self.canvas().itemconfig(self._oval2, {attr:value})
|
|
1027
|
+
else:
|
|
1028
|
+
CanvasWidget.__setitem__(self, attr, value)
|
|
1029
|
+
|
|
1030
|
+
def __getitem__(self, attr):
|
|
1031
|
+
if attr == 'margin': return self._margin
|
|
1032
|
+
elif attr == 'double': return self._double is not None
|
|
1033
|
+
elif attr == 'width':
|
|
1034
|
+
return float(self.canvas().itemcget(self._oval, attr))
|
|
1035
|
+
elif attr in ('outline', 'fill', 'width'):
|
|
1036
|
+
return self.canvas().itemcget(self._oval, attr)
|
|
1037
|
+
else:
|
|
1038
|
+
return CanvasWidget.__getitem__(self, attr)
|
|
1039
|
+
|
|
1040
|
+
# The ratio between inscribed & circumscribed ovals
|
|
1041
|
+
RATIO = 1.4142135623730949
|
|
1042
|
+
|
|
1043
|
+
def _update(self, child):
|
|
1044
|
+
R = OvalWidget.RATIO
|
|
1045
|
+
(x1, y1, x2, y2) = child.bbox()
|
|
1046
|
+
margin = self._margin
|
|
1047
|
+
|
|
1048
|
+
# If we're a circle, pretend our contents are square.
|
|
1049
|
+
if self._circle:
|
|
1050
|
+
dx, dy = abs(x1-x2), abs(y1-y2)
|
|
1051
|
+
if dx > dy:
|
|
1052
|
+
y = (y1+y2)/2
|
|
1053
|
+
y1, y2 = y-dx/2, y+dx/2
|
|
1054
|
+
elif dy > dx:
|
|
1055
|
+
x = (x1+x2)/2
|
|
1056
|
+
x1, x2 = x-dy/2, x+dy/2
|
|
1057
|
+
|
|
1058
|
+
# Find the four corners.
|
|
1059
|
+
left = int(( x1*(1+R) + x2*(1-R) ) / 2)
|
|
1060
|
+
right = left + int((x2-x1)*R)
|
|
1061
|
+
top = int(( y1*(1+R) + y2*(1-R) ) / 2)
|
|
1062
|
+
bot = top + int((y2-y1)*R)
|
|
1063
|
+
self.canvas().coords(self._oval, left-margin, top-margin,
|
|
1064
|
+
right+margin, bot+margin)
|
|
1065
|
+
if self._oval2 is not None:
|
|
1066
|
+
self.canvas().coords(self._oval2, left-margin+2, top-margin+2,
|
|
1067
|
+
right+margin-2, bot+margin-2)
|
|
1068
|
+
|
|
1069
|
+
def _tags(self):
|
|
1070
|
+
if self._oval2 is None:
|
|
1071
|
+
return [self._oval]
|
|
1072
|
+
else:
|
|
1073
|
+
return [self._oval, self._oval2]
|
|
1074
|
+
|
|
1075
|
+
class ParenWidget(AbstractContainerWidget):
|
|
1076
|
+
"""
|
|
1077
|
+
A canvas widget that places a pair of parenthases around a child
|
|
1078
|
+
widget.
|
|
1079
|
+
|
|
1080
|
+
Attributes:
|
|
1081
|
+
- ``color``: The color used to draw the parenthases.
|
|
1082
|
+
- ``width``: The width of the parenthases.
|
|
1083
|
+
- ``draggable``: whether the text can be dragged by the user.
|
|
1084
|
+
"""
|
|
1085
|
+
def __init__(self, canvas, child, **attribs):
|
|
1086
|
+
"""
|
|
1087
|
+
Create a new parenthasis widget.
|
|
1088
|
+
|
|
1089
|
+
:type canvas: Tkinter.Canvas
|
|
1090
|
+
:param canvas: This canvas widget's canvas.
|
|
1091
|
+
:param child: The child widget. ``child`` must not have a
|
|
1092
|
+
parent.
|
|
1093
|
+
:type child: CanvasWidget
|
|
1094
|
+
:param attribs: The new canvas widget's attributes.
|
|
1095
|
+
"""
|
|
1096
|
+
self._child = child
|
|
1097
|
+
self._oparen = canvas.create_arc(1,1,1,1, style='arc',
|
|
1098
|
+
start=90, extent=180)
|
|
1099
|
+
self._cparen = canvas.create_arc(1,1,1,1, style='arc',
|
|
1100
|
+
start=-90, extent=180)
|
|
1101
|
+
AbstractContainerWidget.__init__(self, canvas, child, **attribs)
|
|
1102
|
+
|
|
1103
|
+
def __setitem__(self, attr, value):
|
|
1104
|
+
if attr == 'color':
|
|
1105
|
+
self.canvas().itemconfig(self._oparen, outline=value)
|
|
1106
|
+
self.canvas().itemconfig(self._cparen, outline=value)
|
|
1107
|
+
elif attr == 'width':
|
|
1108
|
+
self.canvas().itemconfig(self._oparen, width=value)
|
|
1109
|
+
self.canvas().itemconfig(self._cparen, width=value)
|
|
1110
|
+
else:
|
|
1111
|
+
CanvasWidget.__setitem__(self, attr, value)
|
|
1112
|
+
|
|
1113
|
+
def __getitem__(self, attr):
|
|
1114
|
+
if attr == 'color':
|
|
1115
|
+
return self.canvas().itemcget(self._oparen, 'outline')
|
|
1116
|
+
elif attr == 'width':
|
|
1117
|
+
return self.canvas().itemcget(self._oparen, 'width')
|
|
1118
|
+
else:
|
|
1119
|
+
return CanvasWidget.__getitem__(self, attr)
|
|
1120
|
+
|
|
1121
|
+
def _update(self, child):
|
|
1122
|
+
(x1, y1, x2, y2) = child.bbox()
|
|
1123
|
+
width = max((y2-y1)/6, 4)
|
|
1124
|
+
self.canvas().coords(self._oparen, x1-width, y1, x1+width, y2)
|
|
1125
|
+
self.canvas().coords(self._cparen, x2-width, y1, x2+width, y2)
|
|
1126
|
+
|
|
1127
|
+
def _tags(self): return [self._oparen, self._cparen]
|
|
1128
|
+
|
|
1129
|
+
class BracketWidget(AbstractContainerWidget):
|
|
1130
|
+
"""
|
|
1131
|
+
A canvas widget that places a pair of brackets around a child
|
|
1132
|
+
widget.
|
|
1133
|
+
|
|
1134
|
+
Attributes:
|
|
1135
|
+
- ``color``: The color used to draw the brackets.
|
|
1136
|
+
- ``width``: The width of the brackets.
|
|
1137
|
+
- ``draggable``: whether the text can be dragged by the user.
|
|
1138
|
+
"""
|
|
1139
|
+
def __init__(self, canvas, child, **attribs):
|
|
1140
|
+
"""
|
|
1141
|
+
Create a new bracket widget.
|
|
1142
|
+
|
|
1143
|
+
:type canvas: Tkinter.Canvas
|
|
1144
|
+
:param canvas: This canvas widget's canvas.
|
|
1145
|
+
:param child: The child widget. ``child`` must not have a
|
|
1146
|
+
parent.
|
|
1147
|
+
:type child: CanvasWidget
|
|
1148
|
+
:param attribs: The new canvas widget's attributes.
|
|
1149
|
+
"""
|
|
1150
|
+
self._child = child
|
|
1151
|
+
self._obrack = canvas.create_line(1,1,1,1,1,1,1,1)
|
|
1152
|
+
self._cbrack = canvas.create_line(1,1,1,1,1,1,1,1)
|
|
1153
|
+
AbstractContainerWidget.__init__(self, canvas, child, **attribs)
|
|
1154
|
+
|
|
1155
|
+
def __setitem__(self, attr, value):
|
|
1156
|
+
if attr == 'color':
|
|
1157
|
+
self.canvas().itemconfig(self._obrack, fill=value)
|
|
1158
|
+
self.canvas().itemconfig(self._cbrack, fill=value)
|
|
1159
|
+
elif attr == 'width':
|
|
1160
|
+
self.canvas().itemconfig(self._obrack, width=value)
|
|
1161
|
+
self.canvas().itemconfig(self._cbrack, width=value)
|
|
1162
|
+
else:
|
|
1163
|
+
CanvasWidget.__setitem__(self, attr, value)
|
|
1164
|
+
|
|
1165
|
+
def __getitem__(self, attr):
|
|
1166
|
+
if attr == 'color':
|
|
1167
|
+
return self.canvas().itemcget(self._obrack, 'outline')
|
|
1168
|
+
elif attr == 'width':
|
|
1169
|
+
return self.canvas().itemcget(self._obrack, 'width')
|
|
1170
|
+
else:
|
|
1171
|
+
return CanvasWidget.__getitem__(self, attr)
|
|
1172
|
+
|
|
1173
|
+
def _update(self, child):
|
|
1174
|
+
(x1, y1, x2, y2) = child.bbox()
|
|
1175
|
+
width = max((y2-y1)/8, 2)
|
|
1176
|
+
self.canvas().coords(self._obrack, x1, y1, x1-width, y1,
|
|
1177
|
+
x1-width, y2, x1, y2)
|
|
1178
|
+
self.canvas().coords(self._cbrack, x2, y1, x2+width, y1,
|
|
1179
|
+
x2+width, y2, x2, y2)
|
|
1180
|
+
|
|
1181
|
+
def _tags(self): return [self._obrack, self._cbrack]
|
|
1182
|
+
|
|
1183
|
+
class SequenceWidget(CanvasWidget):
|
|
1184
|
+
"""
|
|
1185
|
+
A canvas widget that keeps a list of canvas widgets in a
|
|
1186
|
+
horizontal line.
|
|
1187
|
+
|
|
1188
|
+
Attributes:
|
|
1189
|
+
- ``align``: The vertical alignment of the children. Possible
|
|
1190
|
+
values are ``'top'``, ``'center'``, and ``'bottom'``. By
|
|
1191
|
+
default, children are center-aligned.
|
|
1192
|
+
- ``space``: The amount of horizontal space to place between
|
|
1193
|
+
children. By default, one pixel of space is used.
|
|
1194
|
+
- ``ordered``: If true, then keep the children in their
|
|
1195
|
+
original order.
|
|
1196
|
+
"""
|
|
1197
|
+
def __init__(self, canvas, *children, **attribs):
|
|
1198
|
+
"""
|
|
1199
|
+
Create a new sequence widget.
|
|
1200
|
+
|
|
1201
|
+
:type canvas: Tkinter.Canvas
|
|
1202
|
+
:param canvas: This canvas widget's canvas.
|
|
1203
|
+
:param children: The widgets that should be aligned
|
|
1204
|
+
horizontally. Each child must not have a parent.
|
|
1205
|
+
:type children: list(CanvasWidget)
|
|
1206
|
+
:param attribs: The new canvas widget's attributes.
|
|
1207
|
+
"""
|
|
1208
|
+
self._align = 'center'
|
|
1209
|
+
self._space = 1
|
|
1210
|
+
self._ordered = False
|
|
1211
|
+
self._children = list(children)
|
|
1212
|
+
for child in children: self._add_child_widget(child)
|
|
1213
|
+
CanvasWidget.__init__(self, canvas, **attribs)
|
|
1214
|
+
|
|
1215
|
+
def __setitem__(self, attr, value):
|
|
1216
|
+
if attr == 'align':
|
|
1217
|
+
if value not in ('top', 'bottom', 'center'):
|
|
1218
|
+
raise ValueError('Bad alignment: %r' % value)
|
|
1219
|
+
self._align = value
|
|
1220
|
+
elif attr == 'space': self._space = value
|
|
1221
|
+
elif attr == 'ordered': self._ordered = value
|
|
1222
|
+
else: CanvasWidget.__setitem__(self, attr, value)
|
|
1223
|
+
|
|
1224
|
+
def __getitem__(self, attr):
|
|
1225
|
+
if attr == 'align': return self._align
|
|
1226
|
+
elif attr == 'space': return self._space
|
|
1227
|
+
elif attr == 'ordered': return self._ordered
|
|
1228
|
+
else: return CanvasWidget.__getitem__(self, attr)
|
|
1229
|
+
|
|
1230
|
+
def _tags(self): return []
|
|
1231
|
+
|
|
1232
|
+
def _yalign(self, top, bot):
|
|
1233
|
+
if self._align == 'top': return top
|
|
1234
|
+
if self._align == 'bottom': return bot
|
|
1235
|
+
if self._align == 'center': return (top+bot)/2
|
|
1236
|
+
|
|
1237
|
+
def _update(self, child):
|
|
1238
|
+
# Align all children with child.
|
|
1239
|
+
(left, top, right, bot) = child.bbox()
|
|
1240
|
+
y = self._yalign(top, bot)
|
|
1241
|
+
for c in self._children:
|
|
1242
|
+
(x1, y1, x2, y2) = c.bbox()
|
|
1243
|
+
c.move(0, y-self._yalign(y1,y2))
|
|
1244
|
+
|
|
1245
|
+
if self._ordered and len(self._children) > 1:
|
|
1246
|
+
index = self._children.index(child)
|
|
1247
|
+
|
|
1248
|
+
x = right + self._space
|
|
1249
|
+
for i in range(index+1, len(self._children)):
|
|
1250
|
+
(x1, y1, x2, y2) = self._children[i].bbox()
|
|
1251
|
+
if x > x1:
|
|
1252
|
+
self._children[i].move(x-x1, 0)
|
|
1253
|
+
x += x2-x1 + self._space
|
|
1254
|
+
|
|
1255
|
+
x = left - self._space
|
|
1256
|
+
for i in range(index-1, -1, -1):
|
|
1257
|
+
(x1, y1, x2, y2) = self._children[i].bbox()
|
|
1258
|
+
if x < x2:
|
|
1259
|
+
self._children[i].move(x-x2, 0)
|
|
1260
|
+
x -= x2-x1 + self._space
|
|
1261
|
+
|
|
1262
|
+
def _manage(self):
|
|
1263
|
+
if len(self._children) == 0: return
|
|
1264
|
+
child = self._children[0]
|
|
1265
|
+
|
|
1266
|
+
# Align all children with child.
|
|
1267
|
+
(left, top, right, bot) = child.bbox()
|
|
1268
|
+
y = self._yalign(top, bot)
|
|
1269
|
+
|
|
1270
|
+
index = self._children.index(child)
|
|
1271
|
+
|
|
1272
|
+
# Line up children to the right of child.
|
|
1273
|
+
x = right + self._space
|
|
1274
|
+
for i in range(index+1, len(self._children)):
|
|
1275
|
+
(x1, y1, x2, y2) = self._children[i].bbox()
|
|
1276
|
+
self._children[i].move(x-x1, y-self._yalign(y1,y2))
|
|
1277
|
+
x += x2-x1 + self._space
|
|
1278
|
+
|
|
1279
|
+
# Line up children to the left of child.
|
|
1280
|
+
x = left - self._space
|
|
1281
|
+
for i in range(index-1, -1, -1):
|
|
1282
|
+
(x1, y1, x2, y2) = self._children[i].bbox()
|
|
1283
|
+
self._children[i].move(x-x2, y-self._yalign(y1,y2))
|
|
1284
|
+
x -= x2-x1 + self._space
|
|
1285
|
+
|
|
1286
|
+
def __repr__(self):
|
|
1287
|
+
return '[Sequence: ' + repr(self._children)[1:-1]+']'
|
|
1288
|
+
|
|
1289
|
+
# Provide an alias for the child_widgets() member.
|
|
1290
|
+
children = CanvasWidget.child_widgets
|
|
1291
|
+
|
|
1292
|
+
def replace_child(self, oldchild, newchild):
|
|
1293
|
+
"""
|
|
1294
|
+
Replace the child canvas widget ``oldchild`` with ``newchild``.
|
|
1295
|
+
``newchild`` must not have a parent. ``oldchild``'s parent will
|
|
1296
|
+
be set to None.
|
|
1297
|
+
|
|
1298
|
+
:type oldchild: CanvasWidget
|
|
1299
|
+
:param oldchild: The child canvas widget to remove.
|
|
1300
|
+
:type newchild: CanvasWidget
|
|
1301
|
+
:param newchild: The canvas widget that should replace
|
|
1302
|
+
``oldchild``.
|
|
1303
|
+
"""
|
|
1304
|
+
index = self._children.index(oldchild)
|
|
1305
|
+
self._children[index] = newchild
|
|
1306
|
+
self._remove_child_widget(oldchild)
|
|
1307
|
+
self._add_child_widget(newchild)
|
|
1308
|
+
self.update(newchild)
|
|
1309
|
+
|
|
1310
|
+
def remove_child(self, child):
|
|
1311
|
+
"""
|
|
1312
|
+
Remove the given child canvas widget. ``child``'s parent will
|
|
1313
|
+
be set ot None.
|
|
1314
|
+
|
|
1315
|
+
:type child: CanvasWidget
|
|
1316
|
+
:param child: The child canvas widget to remove.
|
|
1317
|
+
"""
|
|
1318
|
+
index = self._children.index(child)
|
|
1319
|
+
del self._children[index]
|
|
1320
|
+
self._remove_child_widget(child)
|
|
1321
|
+
if len(self._children) > 0:
|
|
1322
|
+
self.update(self._children[0])
|
|
1323
|
+
|
|
1324
|
+
def insert_child(self, index, child):
|
|
1325
|
+
"""
|
|
1326
|
+
Insert a child canvas widget before a given index.
|
|
1327
|
+
|
|
1328
|
+
:type child: CanvasWidget
|
|
1329
|
+
:param child: The canvas widget that should be inserted.
|
|
1330
|
+
:type index: int
|
|
1331
|
+
:param index: The index where the child widget should be
|
|
1332
|
+
inserted. In particular, the index of ``child`` will be
|
|
1333
|
+
``index``; and the index of any children whose indices were
|
|
1334
|
+
greater than equal to ``index`` before ``child`` was
|
|
1335
|
+
inserted will be incremented by one.
|
|
1336
|
+
"""
|
|
1337
|
+
self._children.insert(index, child)
|
|
1338
|
+
self._add_child_widget(child)
|
|
1339
|
+
|
|
1340
|
+
class StackWidget(CanvasWidget):
|
|
1341
|
+
"""
|
|
1342
|
+
A canvas widget that keeps a list of canvas widgets in a vertical
|
|
1343
|
+
line.
|
|
1344
|
+
|
|
1345
|
+
Attributes:
|
|
1346
|
+
- ``align``: The horizontal alignment of the children. Possible
|
|
1347
|
+
values are ``'left'``, ``'center'``, and ``'right'``. By
|
|
1348
|
+
default, children are center-aligned.
|
|
1349
|
+
- ``space``: The amount of vertical space to place between
|
|
1350
|
+
children. By default, one pixel of space is used.
|
|
1351
|
+
- ``ordered``: If true, then keep the children in their
|
|
1352
|
+
original order.
|
|
1353
|
+
"""
|
|
1354
|
+
def __init__(self, canvas, *children, **attribs):
|
|
1355
|
+
"""
|
|
1356
|
+
Create a new stack widget.
|
|
1357
|
+
|
|
1358
|
+
:type canvas: Tkinter.Canvas
|
|
1359
|
+
:param canvas: This canvas widget's canvas.
|
|
1360
|
+
:param children: The widgets that should be aligned
|
|
1361
|
+
vertically. Each child must not have a parent.
|
|
1362
|
+
:type children: list(CanvasWidget)
|
|
1363
|
+
:param attribs: The new canvas widget's attributes.
|
|
1364
|
+
"""
|
|
1365
|
+
self._align = 'center'
|
|
1366
|
+
self._space = 1
|
|
1367
|
+
self._ordered = False
|
|
1368
|
+
self._children = list(children)
|
|
1369
|
+
for child in children: self._add_child_widget(child)
|
|
1370
|
+
CanvasWidget.__init__(self, canvas, **attribs)
|
|
1371
|
+
|
|
1372
|
+
def __setitem__(self, attr, value):
|
|
1373
|
+
if attr == 'align':
|
|
1374
|
+
if value not in ('left', 'right', 'center'):
|
|
1375
|
+
raise ValueError('Bad alignment: %r' % value)
|
|
1376
|
+
self._align = value
|
|
1377
|
+
elif attr == 'space': self._space = value
|
|
1378
|
+
elif attr == 'ordered': self._ordered = value
|
|
1379
|
+
else: CanvasWidget.__setitem__(self, attr, value)
|
|
1380
|
+
|
|
1381
|
+
def __getitem__(self, attr):
|
|
1382
|
+
if attr == 'align': return self._align
|
|
1383
|
+
elif attr == 'space': return self._space
|
|
1384
|
+
elif attr == 'ordered': return self._ordered
|
|
1385
|
+
else: return CanvasWidget.__getitem__(self, attr)
|
|
1386
|
+
|
|
1387
|
+
def _tags(self): return []
|
|
1388
|
+
|
|
1389
|
+
def _xalign(self, left, right):
|
|
1390
|
+
if self._align == 'left': return left
|
|
1391
|
+
if self._align == 'right': return right
|
|
1392
|
+
if self._align == 'center': return (left+right)/2
|
|
1393
|
+
|
|
1394
|
+
def _update(self, child):
|
|
1395
|
+
# Align all children with child.
|
|
1396
|
+
(left, top, right, bot) = child.bbox()
|
|
1397
|
+
x = self._xalign(left, right)
|
|
1398
|
+
for c in self._children:
|
|
1399
|
+
(x1, y1, x2, y2) = c.bbox()
|
|
1400
|
+
c.move(x-self._xalign(x1,x2), 0)
|
|
1401
|
+
|
|
1402
|
+
if self._ordered and len(self._children) > 1:
|
|
1403
|
+
index = self._children.index(child)
|
|
1404
|
+
|
|
1405
|
+
y = bot + self._space
|
|
1406
|
+
for i in range(index+1, len(self._children)):
|
|
1407
|
+
(x1, y1, x2, y2) = self._children[i].bbox()
|
|
1408
|
+
if y > y1:
|
|
1409
|
+
self._children[i].move(0, y-y1)
|
|
1410
|
+
y += y2-y1 + self._space
|
|
1411
|
+
|
|
1412
|
+
y = top - self._space
|
|
1413
|
+
for i in range(index-1, -1, -1):
|
|
1414
|
+
(x1, y1, x2, y2) = self._children[i].bbox()
|
|
1415
|
+
if y < y2:
|
|
1416
|
+
self._children[i].move(0, y-y2)
|
|
1417
|
+
y -= y2-y1 + self._space
|
|
1418
|
+
|
|
1419
|
+
def _manage(self):
|
|
1420
|
+
if len(self._children) == 0: return
|
|
1421
|
+
child = self._children[0]
|
|
1422
|
+
|
|
1423
|
+
# Align all children with child.
|
|
1424
|
+
(left, top, right, bot) = child.bbox()
|
|
1425
|
+
x = self._xalign(left, right)
|
|
1426
|
+
|
|
1427
|
+
index = self._children.index(child)
|
|
1428
|
+
|
|
1429
|
+
# Line up children below the child.
|
|
1430
|
+
y = bot + self._space
|
|
1431
|
+
for i in range(index+1, len(self._children)):
|
|
1432
|
+
(x1, y1, x2, y2) = self._children[i].bbox()
|
|
1433
|
+
self._children[i].move(x-self._xalign(x1,x2), y-y1)
|
|
1434
|
+
y += y2-y1 + self._space
|
|
1435
|
+
|
|
1436
|
+
# Line up children above the child.
|
|
1437
|
+
y = top - self._space
|
|
1438
|
+
for i in range(index-1, -1, -1):
|
|
1439
|
+
(x1, y1, x2, y2) = self._children[i].bbox()
|
|
1440
|
+
self._children[i].move(x-self._xalign(x1,x2), y-y2)
|
|
1441
|
+
y -= y2-y1 + self._space
|
|
1442
|
+
|
|
1443
|
+
def __repr__(self):
|
|
1444
|
+
return '[Stack: ' + repr(self._children)[1:-1]+']'
|
|
1445
|
+
|
|
1446
|
+
# Provide an alias for the child_widgets() member.
|
|
1447
|
+
children = CanvasWidget.child_widgets
|
|
1448
|
+
|
|
1449
|
+
def replace_child(self, oldchild, newchild):
|
|
1450
|
+
"""
|
|
1451
|
+
Replace the child canvas widget ``oldchild`` with ``newchild``.
|
|
1452
|
+
``newchild`` must not have a parent. ``oldchild``'s parent will
|
|
1453
|
+
be set to None.
|
|
1454
|
+
|
|
1455
|
+
:type oldchild: CanvasWidget
|
|
1456
|
+
:param oldchild: The child canvas widget to remove.
|
|
1457
|
+
:type newchild: CanvasWidget
|
|
1458
|
+
:param newchild: The canvas widget that should replace
|
|
1459
|
+
``oldchild``.
|
|
1460
|
+
"""
|
|
1461
|
+
index = self._children.index(oldchild)
|
|
1462
|
+
self._children[index] = newchild
|
|
1463
|
+
self._remove_child_widget(oldchild)
|
|
1464
|
+
self._add_child_widget(newchild)
|
|
1465
|
+
self.update(newchild)
|
|
1466
|
+
|
|
1467
|
+
def remove_child(self, child):
|
|
1468
|
+
"""
|
|
1469
|
+
Remove the given child canvas widget. ``child``'s parent will
|
|
1470
|
+
be set ot None.
|
|
1471
|
+
|
|
1472
|
+
:type child: CanvasWidget
|
|
1473
|
+
:param child: The child canvas widget to remove.
|
|
1474
|
+
"""
|
|
1475
|
+
index = self._children.index(child)
|
|
1476
|
+
del self._children[index]
|
|
1477
|
+
self._remove_child_widget(child)
|
|
1478
|
+
if len(self._children) > 0:
|
|
1479
|
+
self.update(self._children[0])
|
|
1480
|
+
|
|
1481
|
+
def insert_child(self, index, child):
|
|
1482
|
+
"""
|
|
1483
|
+
Insert a child canvas widget before a given index.
|
|
1484
|
+
|
|
1485
|
+
:type child: CanvasWidget
|
|
1486
|
+
:param child: The canvas widget that should be inserted.
|
|
1487
|
+
:type index: int
|
|
1488
|
+
:param index: The index where the child widget should be
|
|
1489
|
+
inserted. In particular, the index of ``child`` will be
|
|
1490
|
+
``index``; and the index of any children whose indices were
|
|
1491
|
+
greater than equal to ``index`` before ``child`` was
|
|
1492
|
+
inserted will be incremented by one.
|
|
1493
|
+
"""
|
|
1494
|
+
self._children.insert(index, child)
|
|
1495
|
+
self._add_child_widget(child)
|
|
1496
|
+
|
|
1497
|
+
class SpaceWidget(CanvasWidget):
|
|
1498
|
+
"""
|
|
1499
|
+
A canvas widget that takes up space but does not display
|
|
1500
|
+
anything. A ``SpaceWidget`` can be used to add space between
|
|
1501
|
+
elements. Each space widget is characterized by a width and a
|
|
1502
|
+
height. If you wish to only create horizontal space, then use a
|
|
1503
|
+
height of zero; and if you wish to only create vertical space, use
|
|
1504
|
+
a width of zero.
|
|
1505
|
+
"""
|
|
1506
|
+
def __init__(self, canvas, width, height, **attribs):
|
|
1507
|
+
"""
|
|
1508
|
+
Create a new space widget.
|
|
1509
|
+
|
|
1510
|
+
:type canvas: Tkinter.Canvas
|
|
1511
|
+
:param canvas: This canvas widget's canvas.
|
|
1512
|
+
:type width: int
|
|
1513
|
+
:param width: The width of the new space widget.
|
|
1514
|
+
:type height: int
|
|
1515
|
+
:param height: The height of the new space widget.
|
|
1516
|
+
:param attribs: The new canvas widget's attributes.
|
|
1517
|
+
"""
|
|
1518
|
+
# For some reason,
|
|
1519
|
+
if width > 4: width -= 4
|
|
1520
|
+
if height > 4: height -= 4
|
|
1521
|
+
self._tag = canvas.create_line(1, 1, width, height, fill='')
|
|
1522
|
+
CanvasWidget.__init__(self, canvas, **attribs)
|
|
1523
|
+
|
|
1524
|
+
# note: width() and height() are already defined by CanvasWidget.
|
|
1525
|
+
def set_width(self, width):
|
|
1526
|
+
"""
|
|
1527
|
+
Change the width of this space widget.
|
|
1528
|
+
|
|
1529
|
+
:param width: The new width.
|
|
1530
|
+
:type width: int
|
|
1531
|
+
:rtype: None
|
|
1532
|
+
"""
|
|
1533
|
+
[x1, y1, x2, y2] = self.bbox()
|
|
1534
|
+
self.canvas().coords(self._tag, x1, y1, x1+width, y2)
|
|
1535
|
+
|
|
1536
|
+
def set_height(self, height):
|
|
1537
|
+
"""
|
|
1538
|
+
Change the height of this space widget.
|
|
1539
|
+
|
|
1540
|
+
:param height: The new height.
|
|
1541
|
+
:type height: int
|
|
1542
|
+
:rtype: None
|
|
1543
|
+
"""
|
|
1544
|
+
[x1, y1, x2, y2] = self.bbox()
|
|
1545
|
+
self.canvas().coords(self._tag, x1, y1, x2, y1+height)
|
|
1546
|
+
|
|
1547
|
+
def _tags(self): return [self._tag]
|
|
1548
|
+
|
|
1549
|
+
def __repr__(self): return '[Space]'
|
|
1550
|
+
|
|
1551
|
+
class ScrollWatcherWidget(CanvasWidget):
|
|
1552
|
+
"""
|
|
1553
|
+
A special canvas widget that adjusts its ``Canvas``'s scrollregion
|
|
1554
|
+
to always include the bounding boxes of all of its children. The
|
|
1555
|
+
scroll-watcher widget will only increase the size of the
|
|
1556
|
+
``Canvas``'s scrollregion; it will never decrease it.
|
|
1557
|
+
"""
|
|
1558
|
+
def __init__(self, canvas, *children, **attribs):
|
|
1559
|
+
"""
|
|
1560
|
+
Create a new scroll-watcher widget.
|
|
1561
|
+
|
|
1562
|
+
:type canvas: Tkinter.Canvas
|
|
1563
|
+
:param canvas: This canvas widget's canvas.
|
|
1564
|
+
:type children: list(CanvasWidget)
|
|
1565
|
+
:param children: The canvas widgets watched by the
|
|
1566
|
+
scroll-watcher. The scroll-watcher will ensure that these
|
|
1567
|
+
canvas widgets are always contained in their canvas's
|
|
1568
|
+
scrollregion.
|
|
1569
|
+
:param attribs: The new canvas widget's attributes.
|
|
1570
|
+
"""
|
|
1571
|
+
for child in children: self._add_child_widget(child)
|
|
1572
|
+
CanvasWidget.__init__(self, canvas, **attribs)
|
|
1573
|
+
|
|
1574
|
+
def add_child(self, canvaswidget):
|
|
1575
|
+
"""
|
|
1576
|
+
Add a new canvas widget to the scroll-watcher. The
|
|
1577
|
+
scroll-watcher will ensure that the new canvas widget is
|
|
1578
|
+
always contained in its canvas's scrollregion.
|
|
1579
|
+
|
|
1580
|
+
:param canvaswidget: The new canvas widget.
|
|
1581
|
+
:type canvaswidget: CanvasWidget
|
|
1582
|
+
:rtype: None
|
|
1583
|
+
"""
|
|
1584
|
+
self._add_child_widget(canvaswidget)
|
|
1585
|
+
self.update(canvaswidget)
|
|
1586
|
+
|
|
1587
|
+
def remove_child(self, canvaswidget):
|
|
1588
|
+
"""
|
|
1589
|
+
Remove a canvas widget from the scroll-watcher. The
|
|
1590
|
+
scroll-watcher will no longer ensure that the new canvas
|
|
1591
|
+
widget is always contained in its canvas's scrollregion.
|
|
1592
|
+
|
|
1593
|
+
:param canvaswidget: The canvas widget to remove.
|
|
1594
|
+
:type canvaswidget: CanvasWidget
|
|
1595
|
+
:rtype: None
|
|
1596
|
+
"""
|
|
1597
|
+
self._remove_child_widget(canvaswidget)
|
|
1598
|
+
|
|
1599
|
+
def _tags(self): return []
|
|
1600
|
+
|
|
1601
|
+
def _update(self, child):
|
|
1602
|
+
self._adjust_scrollregion()
|
|
1603
|
+
|
|
1604
|
+
def _adjust_scrollregion(self):
|
|
1605
|
+
"""
|
|
1606
|
+
Adjust the scrollregion of this scroll-watcher's ``Canvas`` to
|
|
1607
|
+
include the bounding boxes of all of its children.
|
|
1608
|
+
"""
|
|
1609
|
+
bbox = self.bbox()
|
|
1610
|
+
canvas = self.canvas()
|
|
1611
|
+
scrollregion = [int(n) for n in canvas['scrollregion'].split()]
|
|
1612
|
+
if len(scrollregion) != 4: return
|
|
1613
|
+
if (bbox[0] < scrollregion[0] or bbox[1] < scrollregion[1] or
|
|
1614
|
+
bbox[2] > scrollregion[2] or bbox[3] > scrollregion[3]):
|
|
1615
|
+
scrollregion = ('%d %d %d %d' %
|
|
1616
|
+
(min(bbox[0], scrollregion[0]),
|
|
1617
|
+
min(bbox[1], scrollregion[1]),
|
|
1618
|
+
max(bbox[2], scrollregion[2]),
|
|
1619
|
+
max(bbox[3], scrollregion[3])))
|
|
1620
|
+
canvas['scrollregion'] = scrollregion
|
|
1621
|
+
|
|
1622
|
+
##//////////////////////////////////////////////////////
|
|
1623
|
+
## Canvas Frame
|
|
1624
|
+
##//////////////////////////////////////////////////////
|
|
1625
|
+
|
|
1626
|
+
class CanvasFrame(object):
|
|
1627
|
+
"""
|
|
1628
|
+
A ``Tkinter`` frame containing a canvas and scrollbars.
|
|
1629
|
+
``CanvasFrame`` uses a ``ScrollWatcherWidget`` to ensure that all of
|
|
1630
|
+
the canvas widgets contained on its canvas are within its
|
|
1631
|
+
scrollregion. In order for ``CanvasFrame`` to make these checks,
|
|
1632
|
+
all canvas widgets must be registered with ``add_widget`` when they
|
|
1633
|
+
are added to the canvas; and destroyed with ``destroy_widget`` when
|
|
1634
|
+
they are no longer needed.
|
|
1635
|
+
|
|
1636
|
+
If a ``CanvasFrame`` is created with no parent, then it will create
|
|
1637
|
+
its own main window, including a "Done" button and a "Print"
|
|
1638
|
+
button.
|
|
1639
|
+
"""
|
|
1640
|
+
def __init__(self, parent=None, **kw):
|
|
1641
|
+
"""
|
|
1642
|
+
Create a new ``CanvasFrame``.
|
|
1643
|
+
|
|
1644
|
+
:type parent: Tkinter.BaseWidget or Tkinter.Tk
|
|
1645
|
+
:param parent: The parent ``Tkinter`` widget. If no parent is
|
|
1646
|
+
specified, then ``CanvasFrame`` will create a new main
|
|
1647
|
+
window.
|
|
1648
|
+
:param kw: Keyword arguments for the new ``Canvas``. See the
|
|
1649
|
+
documentation for ``Tkinter.Canvas`` for more information.
|
|
1650
|
+
"""
|
|
1651
|
+
# If no parent was given, set up a top-level window.
|
|
1652
|
+
if parent is None:
|
|
1653
|
+
self._parent = Tk()
|
|
1654
|
+
self._parent.title('NLTK')
|
|
1655
|
+
self._parent.bind('<Control-p>', lambda e: self.print_to_file())
|
|
1656
|
+
self._parent.bind('<Control-x>', self.destroy)
|
|
1657
|
+
self._parent.bind('<Control-q>', self.destroy)
|
|
1658
|
+
else:
|
|
1659
|
+
self._parent = parent
|
|
1660
|
+
|
|
1661
|
+
# Create a frame for the canvas & scrollbars
|
|
1662
|
+
self._frame = frame = Frame(self._parent)
|
|
1663
|
+
self._canvas = canvas = Canvas(frame, **kw)
|
|
1664
|
+
xscrollbar = Scrollbar(self._frame, orient='horizontal')
|
|
1665
|
+
yscrollbar = Scrollbar(self._frame, orient='vertical')
|
|
1666
|
+
xscrollbar['command'] = canvas.xview
|
|
1667
|
+
yscrollbar['command'] = canvas.yview
|
|
1668
|
+
canvas['xscrollcommand'] = xscrollbar.set
|
|
1669
|
+
canvas['yscrollcommand'] = yscrollbar.set
|
|
1670
|
+
yscrollbar.pack(fill='y', side='right')
|
|
1671
|
+
xscrollbar.pack(fill='x', side='bottom')
|
|
1672
|
+
canvas.pack(expand=1, fill='both', side='left')
|
|
1673
|
+
|
|
1674
|
+
# Set initial scroll region.
|
|
1675
|
+
scrollregion = '0 0 %s %s' % (canvas['width'], canvas['height'])
|
|
1676
|
+
canvas['scrollregion'] = scrollregion
|
|
1677
|
+
|
|
1678
|
+
self._scrollwatcher = ScrollWatcherWidget(canvas)
|
|
1679
|
+
|
|
1680
|
+
# If no parent was given, pack the frame, and add a menu.
|
|
1681
|
+
if parent is None:
|
|
1682
|
+
self.pack(expand=1, fill='both')
|
|
1683
|
+
self._init_menubar()
|
|
1684
|
+
|
|
1685
|
+
def _init_menubar(self):
|
|
1686
|
+
menubar = Menu(self._parent)
|
|
1687
|
+
|
|
1688
|
+
filemenu = Menu(menubar, tearoff=0)
|
|
1689
|
+
filemenu.add_command(label='Print to Postscript', underline=0,
|
|
1690
|
+
command=self.print_to_file, accelerator='Ctrl-p')
|
|
1691
|
+
filemenu.add_command(label='Exit', underline=1,
|
|
1692
|
+
command=self.destroy, accelerator='Ctrl-x')
|
|
1693
|
+
menubar.add_cascade(label='File', underline=0, menu=filemenu)
|
|
1694
|
+
|
|
1695
|
+
self._parent.config(menu=menubar)
|
|
1696
|
+
|
|
1697
|
+
def print_to_file(self, filename=None):
|
|
1698
|
+
"""
|
|
1699
|
+
Print the contents of this ``CanvasFrame`` to a postscript
|
|
1700
|
+
file. If no filename is given, then prompt the user for one.
|
|
1701
|
+
|
|
1702
|
+
:param filename: The name of the file to print the tree to.
|
|
1703
|
+
:type filename: str
|
|
1704
|
+
:rtype: None
|
|
1705
|
+
"""
|
|
1706
|
+
if filename is None:
|
|
1707
|
+
ftypes = [('Postscript files', '.ps'),
|
|
1708
|
+
('All files', '*')]
|
|
1709
|
+
filename = asksaveasfilename(filetypes=ftypes,
|
|
1710
|
+
defaultextension='.ps')
|
|
1711
|
+
if not filename: return
|
|
1712
|
+
(x0, y0, w, h) = self.scrollregion()
|
|
1713
|
+
postscript = self._canvas.postscript(x=x0, y=y0,
|
|
1714
|
+
width=w+2, height=h+2,
|
|
1715
|
+
pagewidth=w+2, # points = 1/72 inch
|
|
1716
|
+
pageheight=h+2, # points = 1/72 inch
|
|
1717
|
+
pagex=0, pagey=0)
|
|
1718
|
+
# workaround for bug in Tk font handling
|
|
1719
|
+
postscript = postscript.replace(' 0 scalefont ', ' 9 scalefont ')
|
|
1720
|
+
with open(filename, 'wb') as f:
|
|
1721
|
+
f.write(postscript.encode('utf8'))
|
|
1722
|
+
|
|
1723
|
+
def scrollregion(self):
|
|
1724
|
+
"""
|
|
1725
|
+
:return: The current scroll region for the canvas managed by
|
|
1726
|
+
this ``CanvasFrame``.
|
|
1727
|
+
:rtype: 4-tuple of int
|
|
1728
|
+
"""
|
|
1729
|
+
(x1, y1, x2, y2) = self._canvas['scrollregion'].split()
|
|
1730
|
+
return (int(x1), int(y1), int(x2), int(y2))
|
|
1731
|
+
|
|
1732
|
+
def canvas(self):
|
|
1733
|
+
"""
|
|
1734
|
+
:return: The canvas managed by this ``CanvasFrame``.
|
|
1735
|
+
:rtype: Tkinter.Canvas
|
|
1736
|
+
"""
|
|
1737
|
+
return self._canvas
|
|
1738
|
+
|
|
1739
|
+
def add_widget(self, canvaswidget, x=None, y=None):
|
|
1740
|
+
"""
|
|
1741
|
+
Register a canvas widget with this ``CanvasFrame``. The
|
|
1742
|
+
``CanvasFrame`` will ensure that this canvas widget is always
|
|
1743
|
+
within the ``Canvas``'s scrollregion. If no coordinates are
|
|
1744
|
+
given for the canvas widget, then the ``CanvasFrame`` will
|
|
1745
|
+
attempt to find a clear area of the canvas for it.
|
|
1746
|
+
|
|
1747
|
+
:type canvaswidget: CanvasWidget
|
|
1748
|
+
:param canvaswidget: The new canvas widget. ``canvaswidget``
|
|
1749
|
+
must have been created on this ``CanvasFrame``'s canvas.
|
|
1750
|
+
:type x: int
|
|
1751
|
+
:param x: The initial x coordinate for the upper left hand
|
|
1752
|
+
corner of ``canvaswidget``, in the canvas's coordinate
|
|
1753
|
+
space.
|
|
1754
|
+
:type y: int
|
|
1755
|
+
:param y: The initial y coordinate for the upper left hand
|
|
1756
|
+
corner of ``canvaswidget``, in the canvas's coordinate
|
|
1757
|
+
space.
|
|
1758
|
+
"""
|
|
1759
|
+
if x is None or y is None:
|
|
1760
|
+
(x, y) = self._find_room(canvaswidget, x, y)
|
|
1761
|
+
|
|
1762
|
+
# Move to (x,y)
|
|
1763
|
+
(x1,y1,x2,y2) = canvaswidget.bbox()
|
|
1764
|
+
canvaswidget.move(x-x1,y-y1)
|
|
1765
|
+
|
|
1766
|
+
# Register with scrollwatcher.
|
|
1767
|
+
self._scrollwatcher.add_child(canvaswidget)
|
|
1768
|
+
|
|
1769
|
+
def _find_room(self, widget, desired_x, desired_y):
|
|
1770
|
+
"""
|
|
1771
|
+
Try to find a space for a given widget.
|
|
1772
|
+
"""
|
|
1773
|
+
(left, top, right, bot) = self.scrollregion()
|
|
1774
|
+
w = widget.width()
|
|
1775
|
+
h = widget.height()
|
|
1776
|
+
|
|
1777
|
+
if w >= (right-left): return (0,0)
|
|
1778
|
+
if h >= (bot-top): return (0,0)
|
|
1779
|
+
|
|
1780
|
+
# Move the widget out of the way, for now.
|
|
1781
|
+
(x1,y1,x2,y2) = widget.bbox()
|
|
1782
|
+
widget.move(left-x2-50, top-y2-50)
|
|
1783
|
+
|
|
1784
|
+
if desired_x is not None:
|
|
1785
|
+
x = desired_x
|
|
1786
|
+
for y in range(top, bot-h, int((bot-top-h)/10)):
|
|
1787
|
+
if not self._canvas.find_overlapping(x-5, y-5, x+w+5, y+h+5):
|
|
1788
|
+
return (x,y)
|
|
1789
|
+
|
|
1790
|
+
if desired_y is not None:
|
|
1791
|
+
y = desired_y
|
|
1792
|
+
for x in range(left, right-w, int((right-left-w)/10)):
|
|
1793
|
+
if not self._canvas.find_overlapping(x-5, y-5, x+w+5, y+h+5):
|
|
1794
|
+
return (x,y)
|
|
1795
|
+
|
|
1796
|
+
for y in range(top, bot-h, int((bot-top-h)/10)):
|
|
1797
|
+
for x in range(left, right-w, int((right-left-w)/10)):
|
|
1798
|
+
if not self._canvas.find_overlapping(x-5, y-5, x+w+5, y+h+5):
|
|
1799
|
+
return (x,y)
|
|
1800
|
+
return (0,0)
|
|
1801
|
+
|
|
1802
|
+
def destroy_widget(self, canvaswidget):
|
|
1803
|
+
"""
|
|
1804
|
+
Remove a canvas widget from this ``CanvasFrame``. This
|
|
1805
|
+
deregisters the canvas widget, and destroys it.
|
|
1806
|
+
"""
|
|
1807
|
+
self.remove_widget(canvaswidget)
|
|
1808
|
+
canvaswidget.destroy()
|
|
1809
|
+
|
|
1810
|
+
def remove_widget(self, canvaswidget):
|
|
1811
|
+
# Deregister with scrollwatcher.
|
|
1812
|
+
self._scrollwatcher.remove_child(canvaswidget)
|
|
1813
|
+
|
|
1814
|
+
def pack(self, cnf={}, **kw):
|
|
1815
|
+
"""
|
|
1816
|
+
Pack this ``CanvasFrame``. See the documentation for
|
|
1817
|
+
``Tkinter.Pack`` for more information.
|
|
1818
|
+
"""
|
|
1819
|
+
self._frame.pack(cnf, **kw)
|
|
1820
|
+
# Adjust to be big enough for kids?
|
|
1821
|
+
|
|
1822
|
+
def destroy(self, *e):
|
|
1823
|
+
"""
|
|
1824
|
+
Destroy this ``CanvasFrame``. If this ``CanvasFrame`` created a
|
|
1825
|
+
top-level window, then this will close that window.
|
|
1826
|
+
"""
|
|
1827
|
+
if self._parent is None: return
|
|
1828
|
+
self._parent.destroy()
|
|
1829
|
+
self._parent = None
|
|
1830
|
+
|
|
1831
|
+
def mainloop(self, *args, **kwargs):
|
|
1832
|
+
"""
|
|
1833
|
+
Enter the Tkinter mainloop. This function must be called if
|
|
1834
|
+
this frame is created from a non-interactive program (e.g.
|
|
1835
|
+
from a secript); otherwise, the frame will close as soon as
|
|
1836
|
+
the script completes.
|
|
1837
|
+
"""
|
|
1838
|
+
if in_idle(): return
|
|
1839
|
+
self._parent.mainloop(*args, **kwargs)
|
|
1840
|
+
|
|
1841
|
+
##//////////////////////////////////////////////////////
|
|
1842
|
+
## Text display
|
|
1843
|
+
##//////////////////////////////////////////////////////
|
|
1844
|
+
|
|
1845
|
+
class ShowText(object):
|
|
1846
|
+
"""
|
|
1847
|
+
A ``Tkinter`` window used to display a text. ``ShowText`` is
|
|
1848
|
+
typically used by graphical tools to display help text, or similar
|
|
1849
|
+
information.
|
|
1850
|
+
"""
|
|
1851
|
+
def __init__(self, root, title, text, width=None, height=None,
|
|
1852
|
+
**textbox_options):
|
|
1853
|
+
if width is None or height is None:
|
|
1854
|
+
(width, height) = self.find_dimentions(text, width, height)
|
|
1855
|
+
|
|
1856
|
+
# Create the main window.
|
|
1857
|
+
if root is None:
|
|
1858
|
+
self._top = top = Tk()
|
|
1859
|
+
else:
|
|
1860
|
+
self._top = top = Toplevel(root)
|
|
1861
|
+
top.title(title)
|
|
1862
|
+
|
|
1863
|
+
b = Button(top, text='Ok', command=self.destroy)
|
|
1864
|
+
b.pack(side='bottom')
|
|
1865
|
+
|
|
1866
|
+
tbf = Frame(top)
|
|
1867
|
+
tbf.pack(expand=1, fill='both')
|
|
1868
|
+
scrollbar = Scrollbar(tbf, orient='vertical')
|
|
1869
|
+
scrollbar.pack(side='right', fill='y')
|
|
1870
|
+
textbox = Text(tbf, wrap='word', width=width,
|
|
1871
|
+
height=height, **textbox_options)
|
|
1872
|
+
textbox.insert('end', text)
|
|
1873
|
+
textbox['state'] = 'disabled'
|
|
1874
|
+
textbox.pack(side='left', expand=1, fill='both')
|
|
1875
|
+
scrollbar['command'] = textbox.yview
|
|
1876
|
+
textbox['yscrollcommand'] = scrollbar.set
|
|
1877
|
+
|
|
1878
|
+
# Make it easy to close the window.
|
|
1879
|
+
top.bind('q', self.destroy)
|
|
1880
|
+
top.bind('x', self.destroy)
|
|
1881
|
+
top.bind('c', self.destroy)
|
|
1882
|
+
top.bind('<Return>', self.destroy)
|
|
1883
|
+
top.bind('<Escape>', self.destroy)
|
|
1884
|
+
|
|
1885
|
+
# Focus the scrollbar, so they can use up/down, etc.
|
|
1886
|
+
scrollbar.focus()
|
|
1887
|
+
|
|
1888
|
+
def find_dimentions(self, text, width, height):
|
|
1889
|
+
lines = text.split('\n')
|
|
1890
|
+
if width is None:
|
|
1891
|
+
maxwidth = max(len(line) for line in lines)
|
|
1892
|
+
width = min(maxwidth, 80)
|
|
1893
|
+
|
|
1894
|
+
# Now, find height.
|
|
1895
|
+
height = 0
|
|
1896
|
+
for line in lines:
|
|
1897
|
+
while len(line) > width:
|
|
1898
|
+
brk = line[:width].rfind(' ')
|
|
1899
|
+
line = line[brk:]
|
|
1900
|
+
height += 1
|
|
1901
|
+
height += 1
|
|
1902
|
+
height = min(height, 25)
|
|
1903
|
+
|
|
1904
|
+
return (width, height)
|
|
1905
|
+
|
|
1906
|
+
def destroy(self, *e):
|
|
1907
|
+
if self._top is None: return
|
|
1908
|
+
self._top.destroy()
|
|
1909
|
+
self._top = None
|
|
1910
|
+
|
|
1911
|
+
def mainloop(self, *args, **kwargs):
|
|
1912
|
+
"""
|
|
1913
|
+
Enter the Tkinter mainloop. This function must be called if
|
|
1914
|
+
this window is created from a non-interactive program (e.g.
|
|
1915
|
+
from a secript); otherwise, the window will close as soon as
|
|
1916
|
+
the script completes.
|
|
1917
|
+
"""
|
|
1918
|
+
if in_idle(): return
|
|
1919
|
+
self._top.mainloop(*args, **kwargs)
|
|
1920
|
+
|
|
1921
|
+
##//////////////////////////////////////////////////////
|
|
1922
|
+
## Entry dialog
|
|
1923
|
+
##//////////////////////////////////////////////////////
|
|
1924
|
+
|
|
1925
|
+
class EntryDialog(object):
|
|
1926
|
+
"""
|
|
1927
|
+
A dialog box for entering
|
|
1928
|
+
"""
|
|
1929
|
+
def __init__(self, parent, original_text='', instructions='',
|
|
1930
|
+
set_callback=None, title=None):
|
|
1931
|
+
self._parent = parent
|
|
1932
|
+
self._original_text = original_text
|
|
1933
|
+
self._set_callback = set_callback
|
|
1934
|
+
|
|
1935
|
+
width = int(max(30, len(original_text)*3/2))
|
|
1936
|
+
self._top = Toplevel(parent)
|
|
1937
|
+
|
|
1938
|
+
if title: self._top.title(title)
|
|
1939
|
+
|
|
1940
|
+
# The text entry box.
|
|
1941
|
+
entryframe = Frame(self._top)
|
|
1942
|
+
entryframe.pack(expand=1, fill='both', padx=5, pady=5,ipady=10)
|
|
1943
|
+
if instructions:
|
|
1944
|
+
l=Label(entryframe, text=instructions)
|
|
1945
|
+
l.pack(side='top', anchor='w', padx=30)
|
|
1946
|
+
self._entry = Entry(entryframe, width=width)
|
|
1947
|
+
self._entry.pack(expand=1, fill='x', padx=30)
|
|
1948
|
+
self._entry.insert(0, original_text)
|
|
1949
|
+
|
|
1950
|
+
# A divider
|
|
1951
|
+
divider = Frame(self._top, borderwidth=1, relief='sunken')
|
|
1952
|
+
divider.pack(fill='x', ipady=1, padx=10)
|
|
1953
|
+
|
|
1954
|
+
# The buttons.
|
|
1955
|
+
buttons = Frame(self._top)
|
|
1956
|
+
buttons.pack(expand=0, fill='x', padx=5, pady=5)
|
|
1957
|
+
b = Button(buttons, text='Cancel', command=self._cancel, width=8)
|
|
1958
|
+
b.pack(side='right', padx=5)
|
|
1959
|
+
b = Button(buttons, text='Ok', command=self._ok,
|
|
1960
|
+
width=8, default='active')
|
|
1961
|
+
b.pack(side='left', padx=5)
|
|
1962
|
+
b = Button(buttons, text='Apply', command=self._apply, width=8)
|
|
1963
|
+
b.pack(side='left')
|
|
1964
|
+
|
|
1965
|
+
self._top.bind('<Return>', self._ok)
|
|
1966
|
+
self._top.bind('<Control-q>', self._cancel)
|
|
1967
|
+
self._top.bind('<Escape>', self._cancel)
|
|
1968
|
+
|
|
1969
|
+
self._entry.focus()
|
|
1970
|
+
|
|
1971
|
+
def _reset(self, *e):
|
|
1972
|
+
self._entry.delete(0,'end')
|
|
1973
|
+
self._entry.insert(0, self._original_text)
|
|
1974
|
+
if self._set_callback:
|
|
1975
|
+
self._set_callback(self._original_text)
|
|
1976
|
+
|
|
1977
|
+
def _cancel(self, *e):
|
|
1978
|
+
try: self._reset()
|
|
1979
|
+
except: pass
|
|
1980
|
+
self._destroy()
|
|
1981
|
+
|
|
1982
|
+
def _ok(self, *e):
|
|
1983
|
+
self._apply()
|
|
1984
|
+
self._destroy()
|
|
1985
|
+
|
|
1986
|
+
def _apply(self, *e):
|
|
1987
|
+
if self._set_callback:
|
|
1988
|
+
self._set_callback(self._entry.get())
|
|
1989
|
+
|
|
1990
|
+
def _destroy(self, *e):
|
|
1991
|
+
if self._top is None: return
|
|
1992
|
+
self._top.destroy()
|
|
1993
|
+
self._top = None
|
|
1994
|
+
|
|
1995
|
+
##//////////////////////////////////////////////////////
|
|
1996
|
+
## Colorized List
|
|
1997
|
+
##//////////////////////////////////////////////////////
|
|
1998
|
+
|
|
1999
|
+
class ColorizedList(object):
|
|
2000
|
+
"""
|
|
2001
|
+
An abstract base class for displaying a colorized list of items.
|
|
2002
|
+
Subclasses should define:
|
|
2003
|
+
- ``_init_colortags``, which sets up Text color tags that
|
|
2004
|
+
will be used by the list.
|
|
2005
|
+
- ``_item_repr``, which returns a list of (text,colortag)
|
|
2006
|
+
tuples that make up the colorized representation of the
|
|
2007
|
+
item.
|
|
2008
|
+
:note: Typically, you will want to register a callback for
|
|
2009
|
+
``'select'`` that calls ``mark`` on the given item.
|
|
2010
|
+
"""
|
|
2011
|
+
def __init__(self, parent, items=[], **options):
|
|
2012
|
+
"""
|
|
2013
|
+
Construct a new list.
|
|
2014
|
+
|
|
2015
|
+
:param parent: The Tk widget that contains the colorized list
|
|
2016
|
+
:param items: The initial contents of the colorized list.
|
|
2017
|
+
:param options:
|
|
2018
|
+
"""
|
|
2019
|
+
self._parent = parent
|
|
2020
|
+
self._callbacks = {}
|
|
2021
|
+
|
|
2022
|
+
# Which items are marked?
|
|
2023
|
+
self._marks = {}
|
|
2024
|
+
|
|
2025
|
+
# Initialize the Tkinter frames.
|
|
2026
|
+
self._init_itemframe(options.copy())
|
|
2027
|
+
|
|
2028
|
+
# Set up key & mouse bindings.
|
|
2029
|
+
self._textwidget.bind('<KeyPress>', self._keypress)
|
|
2030
|
+
self._textwidget.bind('<ButtonPress>', self._buttonpress)
|
|
2031
|
+
|
|
2032
|
+
# Fill in the given CFG's items.
|
|
2033
|
+
self._items = None
|
|
2034
|
+
self.set(items)
|
|
2035
|
+
|
|
2036
|
+
#////////////////////////////////////////////////////////////
|
|
2037
|
+
# Abstract methods
|
|
2038
|
+
#////////////////////////////////////////////////////////////
|
|
2039
|
+
@abstractmethod
|
|
2040
|
+
def _init_colortags(self, textwidget, options):
|
|
2041
|
+
"""
|
|
2042
|
+
Set up any colortags that will be used by this colorized list.
|
|
2043
|
+
E.g.:
|
|
2044
|
+
>>> textwidget.tag_config('terminal', foreground='black')
|
|
2045
|
+
"""
|
|
2046
|
+
|
|
2047
|
+
@abstractmethod
|
|
2048
|
+
def _item_repr(self, item):
|
|
2049
|
+
"""
|
|
2050
|
+
Return a list of (text, colortag) tuples that make up the
|
|
2051
|
+
colorized representation of the item. Colorized
|
|
2052
|
+
representations may not span multiple lines. I.e., the text
|
|
2053
|
+
strings returned may not contain newline characters.
|
|
2054
|
+
"""
|
|
2055
|
+
|
|
2056
|
+
#////////////////////////////////////////////////////////////
|
|
2057
|
+
# Item Access
|
|
2058
|
+
#////////////////////////////////////////////////////////////
|
|
2059
|
+
|
|
2060
|
+
def get(self, index=None):
|
|
2061
|
+
"""
|
|
2062
|
+
:return: A list of the items contained by this list.
|
|
2063
|
+
"""
|
|
2064
|
+
if index is None:
|
|
2065
|
+
return self._items[:]
|
|
2066
|
+
else:
|
|
2067
|
+
return self._items[index]
|
|
2068
|
+
|
|
2069
|
+
def set(self, items):
|
|
2070
|
+
"""
|
|
2071
|
+
Modify the list of items contained by this list.
|
|
2072
|
+
"""
|
|
2073
|
+
items = list(items)
|
|
2074
|
+
if self._items == items: return
|
|
2075
|
+
self._items = list(items)
|
|
2076
|
+
|
|
2077
|
+
self._textwidget['state'] = 'normal'
|
|
2078
|
+
self._textwidget.delete('1.0', 'end')
|
|
2079
|
+
for item in items:
|
|
2080
|
+
for (text, colortag) in self._item_repr(item):
|
|
2081
|
+
assert '\n' not in text, 'item repr may not contain newline'
|
|
2082
|
+
self._textwidget.insert('end', text, colortag)
|
|
2083
|
+
self._textwidget.insert('end', '\n')
|
|
2084
|
+
# Remove the final newline
|
|
2085
|
+
self._textwidget.delete('end-1char', 'end')
|
|
2086
|
+
self._textwidget.mark_set('insert', '1.0')
|
|
2087
|
+
self._textwidget['state'] = 'disabled'
|
|
2088
|
+
# Clear all marks
|
|
2089
|
+
self._marks.clear()
|
|
2090
|
+
|
|
2091
|
+
def unmark(self, item=None):
|
|
2092
|
+
"""
|
|
2093
|
+
Remove highlighting from the given item; or from every item,
|
|
2094
|
+
if no item is given.
|
|
2095
|
+
:raise ValueError: If ``item`` is not contained in the list.
|
|
2096
|
+
:raise KeyError: If ``item`` is not marked.
|
|
2097
|
+
"""
|
|
2098
|
+
if item is None:
|
|
2099
|
+
self._marks.clear()
|
|
2100
|
+
self._textwidget.tag_remove('highlight', '1.0', 'end+1char')
|
|
2101
|
+
else:
|
|
2102
|
+
index = self._items.index(item)
|
|
2103
|
+
del self._marks[item]
|
|
2104
|
+
(start, end) = ('%d.0' % (index+1), '%d.0' % (index+2))
|
|
2105
|
+
self._textwidget.tag_remove('highlight', start, end)
|
|
2106
|
+
|
|
2107
|
+
def mark(self, item):
|
|
2108
|
+
"""
|
|
2109
|
+
Highlight the given item.
|
|
2110
|
+
:raise ValueError: If ``item`` is not contained in the list.
|
|
2111
|
+
"""
|
|
2112
|
+
self._marks[item] = 1
|
|
2113
|
+
index = self._items.index(item)
|
|
2114
|
+
(start, end) = ('%d.0' % (index+1), '%d.0' % (index+2))
|
|
2115
|
+
self._textwidget.tag_add('highlight', start, end)
|
|
2116
|
+
|
|
2117
|
+
def markonly(self, item):
|
|
2118
|
+
"""
|
|
2119
|
+
Remove any current highlighting, and mark the given item.
|
|
2120
|
+
:raise ValueError: If ``item`` is not contained in the list.
|
|
2121
|
+
"""
|
|
2122
|
+
self.unmark()
|
|
2123
|
+
self.mark(item)
|
|
2124
|
+
|
|
2125
|
+
def view(self, item):
|
|
2126
|
+
"""
|
|
2127
|
+
Adjust the view such that the given item is visible. If
|
|
2128
|
+
the item is already visible, then do nothing.
|
|
2129
|
+
"""
|
|
2130
|
+
index = self._items.index(item)
|
|
2131
|
+
self._textwidget.see('%d.0' % (index+1))
|
|
2132
|
+
|
|
2133
|
+
#////////////////////////////////////////////////////////////
|
|
2134
|
+
# Callbacks
|
|
2135
|
+
#////////////////////////////////////////////////////////////
|
|
2136
|
+
|
|
2137
|
+
def add_callback(self, event, func):
|
|
2138
|
+
"""
|
|
2139
|
+
Register a callback function with the list. This function
|
|
2140
|
+
will be called whenever the given event occurs.
|
|
2141
|
+
|
|
2142
|
+
:param event: The event that will trigger the callback
|
|
2143
|
+
function. Valid events are: click1, click2, click3,
|
|
2144
|
+
space, return, select, up, down, next, prior, move
|
|
2145
|
+
:param func: The function that should be called when
|
|
2146
|
+
the event occurs. ``func`` will be called with a
|
|
2147
|
+
single item as its argument. (The item selected
|
|
2148
|
+
or the item moved to).
|
|
2149
|
+
"""
|
|
2150
|
+
if event == 'select': events = ['click1', 'space', 'return']
|
|
2151
|
+
elif event == 'move': events = ['up', 'down', 'next', 'prior']
|
|
2152
|
+
else: events = [event]
|
|
2153
|
+
|
|
2154
|
+
for e in events:
|
|
2155
|
+
self._callbacks.setdefault(e,{})[func] = 1
|
|
2156
|
+
|
|
2157
|
+
def remove_callback(self, event, func=None):
|
|
2158
|
+
"""
|
|
2159
|
+
Deregister a callback function. If ``func`` is none, then
|
|
2160
|
+
all callbacks are removed for the given event.
|
|
2161
|
+
"""
|
|
2162
|
+
if event is None: events = list(self._callbacks.keys())
|
|
2163
|
+
elif event == 'select': events = ['click1', 'space', 'return']
|
|
2164
|
+
elif event == 'move': events = ['up', 'down', 'next', 'prior']
|
|
2165
|
+
else: events = [event]
|
|
2166
|
+
|
|
2167
|
+
for e in events:
|
|
2168
|
+
if func is None: del self._callbacks[e]
|
|
2169
|
+
else:
|
|
2170
|
+
try: del self._callbacks[e][func]
|
|
2171
|
+
except: pass
|
|
2172
|
+
|
|
2173
|
+
#////////////////////////////////////////////////////////////
|
|
2174
|
+
# Tkinter Methods
|
|
2175
|
+
#////////////////////////////////////////////////////////////
|
|
2176
|
+
|
|
2177
|
+
def pack(self, cnf={}, **kw):
|
|
2178
|
+
# "@include: Tkinter.Pack.pack"
|
|
2179
|
+
self._itemframe.pack(cnf, **kw)
|
|
2180
|
+
|
|
2181
|
+
def grid(self, cnf={}, **kw):
|
|
2182
|
+
# "@include: Tkinter.Grid.grid"
|
|
2183
|
+
self._itemframe.grid(cnf, *kw)
|
|
2184
|
+
|
|
2185
|
+
def focus(self):
|
|
2186
|
+
# "@include: Tkinter.Widget.focus"
|
|
2187
|
+
self._textwidget.focus()
|
|
2188
|
+
|
|
2189
|
+
#////////////////////////////////////////////////////////////
|
|
2190
|
+
# Internal Methods
|
|
2191
|
+
#////////////////////////////////////////////////////////////
|
|
2192
|
+
|
|
2193
|
+
def _init_itemframe(self, options):
|
|
2194
|
+
self._itemframe = Frame(self._parent)
|
|
2195
|
+
|
|
2196
|
+
# Create the basic Text widget & scrollbar.
|
|
2197
|
+
options.setdefault('background', '#e0e0e0')
|
|
2198
|
+
self._textwidget = Text(self._itemframe, **options)
|
|
2199
|
+
self._textscroll = Scrollbar(self._itemframe, takefocus=0,
|
|
2200
|
+
orient='vertical')
|
|
2201
|
+
self._textwidget.config(yscrollcommand = self._textscroll.set)
|
|
2202
|
+
self._textscroll.config(command=self._textwidget.yview)
|
|
2203
|
+
self._textscroll.pack(side='right', fill='y')
|
|
2204
|
+
self._textwidget.pack(expand=1, fill='both', side='left')
|
|
2205
|
+
|
|
2206
|
+
# Initialize the colorization tags
|
|
2207
|
+
self._textwidget.tag_config('highlight', background='#e0ffff',
|
|
2208
|
+
border='1', relief='raised')
|
|
2209
|
+
self._init_colortags(self._textwidget, options)
|
|
2210
|
+
|
|
2211
|
+
# How do I want to mark keyboard selection?
|
|
2212
|
+
self._textwidget.tag_config('sel', foreground='')
|
|
2213
|
+
self._textwidget.tag_config('sel', foreground='', background='',
|
|
2214
|
+
border='', underline=1)
|
|
2215
|
+
self._textwidget.tag_lower('highlight', 'sel')
|
|
2216
|
+
|
|
2217
|
+
def _fire_callback(self, event, itemnum):
|
|
2218
|
+
if event not in self._callbacks: return
|
|
2219
|
+
if 0 <= itemnum < len(self._items):
|
|
2220
|
+
item = self._items[itemnum]
|
|
2221
|
+
else:
|
|
2222
|
+
item = None
|
|
2223
|
+
for cb_func in list(self._callbacks[event].keys()):
|
|
2224
|
+
cb_func(item)
|
|
2225
|
+
|
|
2226
|
+
def _buttonpress(self, event):
|
|
2227
|
+
clickloc = '@%d,%d' % (event.x,event.y)
|
|
2228
|
+
insert_point = self._textwidget.index(clickloc)
|
|
2229
|
+
itemnum = int(insert_point.split('.')[0])-1
|
|
2230
|
+
self._fire_callback('click%d' % event.num, itemnum)
|
|
2231
|
+
|
|
2232
|
+
def _keypress(self, event):
|
|
2233
|
+
if event.keysym == 'Return' or event.keysym == 'space':
|
|
2234
|
+
insert_point = self._textwidget.index('insert')
|
|
2235
|
+
itemnum = int(insert_point.split('.')[0])-1
|
|
2236
|
+
self._fire_callback(event.keysym.lower(), itemnum)
|
|
2237
|
+
return
|
|
2238
|
+
elif event.keysym == 'Down': delta='+1line'
|
|
2239
|
+
elif event.keysym == 'Up': delta='-1line'
|
|
2240
|
+
elif event.keysym == 'Next': delta='+10lines'
|
|
2241
|
+
elif event.keysym == 'Prior': delta='-10lines'
|
|
2242
|
+
else: return 'continue'
|
|
2243
|
+
|
|
2244
|
+
self._textwidget.mark_set('insert', 'insert'+delta)
|
|
2245
|
+
self._textwidget.see('insert')
|
|
2246
|
+
self._textwidget.tag_remove('sel', '1.0', 'end+1char')
|
|
2247
|
+
self._textwidget.tag_add('sel', 'insert linestart', 'insert lineend')
|
|
2248
|
+
|
|
2249
|
+
insert_point = self._textwidget.index('insert')
|
|
2250
|
+
itemnum = int(insert_point.split('.')[0])-1
|
|
2251
|
+
self._fire_callback(event.keysym.lower(), itemnum)
|
|
2252
|
+
|
|
2253
|
+
return 'break'
|
|
2254
|
+
|
|
2255
|
+
##//////////////////////////////////////////////////////
|
|
2256
|
+
## Improved OptionMenu
|
|
2257
|
+
##//////////////////////////////////////////////////////
|
|
2258
|
+
|
|
2259
|
+
class MutableOptionMenu(Menubutton):
|
|
2260
|
+
def __init__(self, master, values, **options):
|
|
2261
|
+
self._callback = options.get('command')
|
|
2262
|
+
if 'command' in options: del options['command']
|
|
2263
|
+
|
|
2264
|
+
# Create a variable
|
|
2265
|
+
self._variable = variable = StringVar()
|
|
2266
|
+
if len(values) > 0:
|
|
2267
|
+
variable.set(values[0])
|
|
2268
|
+
|
|
2269
|
+
kw = {"borderwidth": 2, "textvariable": variable,
|
|
2270
|
+
"indicatoron": 1, "relief": RAISED, "anchor": "c",
|
|
2271
|
+
"highlightthickness": 2}
|
|
2272
|
+
kw.update(options)
|
|
2273
|
+
Widget.__init__(self, master, "menubutton", kw)
|
|
2274
|
+
self.widgetName = 'tk_optionMenu'
|
|
2275
|
+
self._menu = Menu(self, name="menu", tearoff=0,)
|
|
2276
|
+
self.menuname = self._menu._w
|
|
2277
|
+
|
|
2278
|
+
self._values = []
|
|
2279
|
+
for value in values: self.add(value)
|
|
2280
|
+
|
|
2281
|
+
self["menu"] = self._menu
|
|
2282
|
+
|
|
2283
|
+
def add(self, value):
|
|
2284
|
+
if value in self._values: return
|
|
2285
|
+
def set(value=value): self.set(value)
|
|
2286
|
+
self._menu.add_command(label=value, command=set)
|
|
2287
|
+
self._values.append(value)
|
|
2288
|
+
|
|
2289
|
+
def set(self, value):
|
|
2290
|
+
self._variable.set(value)
|
|
2291
|
+
if self._callback:
|
|
2292
|
+
self._callback(value)
|
|
2293
|
+
|
|
2294
|
+
def remove(self, value):
|
|
2295
|
+
# Might raise indexerror: pass to parent.
|
|
2296
|
+
i = self._values.index(value)
|
|
2297
|
+
del self._values[i]
|
|
2298
|
+
self._menu.delete(i, i)
|
|
2299
|
+
|
|
2300
|
+
def __getitem__(self, name):
|
|
2301
|
+
if name == 'menu':
|
|
2302
|
+
return self.__menu
|
|
2303
|
+
return Widget.__getitem__(self, name)
|
|
2304
|
+
|
|
2305
|
+
def destroy(self):
|
|
2306
|
+
"""Destroy this widget and the associated menu."""
|
|
2307
|
+
Menubutton.destroy(self)
|
|
2308
|
+
self._menu = None
|
|
2309
|
+
|
|
2310
|
+
##//////////////////////////////////////////////////////
|
|
2311
|
+
## Test code.
|
|
2312
|
+
##//////////////////////////////////////////////////////
|
|
2313
|
+
|
|
2314
|
+
def demo():
|
|
2315
|
+
"""
|
|
2316
|
+
A simple demonstration showing how to use canvas widgets.
|
|
2317
|
+
"""
|
|
2318
|
+
def fill(cw):
|
|
2319
|
+
from random import randint
|
|
2320
|
+
cw['fill'] = '#00%04d' % randint(0,9999)
|
|
2321
|
+
def color(cw):
|
|
2322
|
+
from random import randint
|
|
2323
|
+
cw['color'] = '#ff%04d' % randint(0,9999)
|
|
2324
|
+
|
|
2325
|
+
cf = CanvasFrame(closeenough=10, width=300, height=300)
|
|
2326
|
+
c = cf.canvas()
|
|
2327
|
+
ct3 = TextWidget(c, 'hiya there', draggable=1)
|
|
2328
|
+
ct2 = TextWidget(c, 'o o\n||\n___\n U', draggable=1, justify='center')
|
|
2329
|
+
co = OvalWidget(c, ct2, outline='red')
|
|
2330
|
+
ct = TextWidget(c, 'o o\n||\n\\___/', draggable=1, justify='center')
|
|
2331
|
+
cp = ParenWidget(c, ct, color='red')
|
|
2332
|
+
cb = BoxWidget(c, cp, fill='cyan', draggable=1, width=3, margin=10)
|
|
2333
|
+
equation = SequenceWidget(c,
|
|
2334
|
+
SymbolWidget(c, 'forall'), TextWidget(c, 'x'),
|
|
2335
|
+
SymbolWidget(c, 'exists'), TextWidget(c, 'y: '),
|
|
2336
|
+
TextWidget(c, 'x'), SymbolWidget(c, 'notequal'),
|
|
2337
|
+
TextWidget(c, 'y'))
|
|
2338
|
+
space = SpaceWidget(c, 0, 30)
|
|
2339
|
+
cstack = StackWidget(c, cb, ct3, space, co, equation, align='center')
|
|
2340
|
+
foo = TextWidget(c, 'try clicking\nand dragging',
|
|
2341
|
+
draggable=1, justify='center')
|
|
2342
|
+
cs = SequenceWidget(c, cstack, foo)
|
|
2343
|
+
zz = BracketWidget(c, cs, color='green4', width=3)
|
|
2344
|
+
cf.add_widget(zz, 60, 30)
|
|
2345
|
+
|
|
2346
|
+
cb.bind_click(fill)
|
|
2347
|
+
ct.bind_click(color)
|
|
2348
|
+
co.bind_click(fill)
|
|
2349
|
+
ct2.bind_click(color)
|
|
2350
|
+
ct3.bind_click(color)
|
|
2351
|
+
|
|
2352
|
+
cf.mainloop()
|
|
2353
|
+
#ShowText(None, 'title', ((('this is text'*150)+'\n')*5))
|
|
2354
|
+
|
|
2355
|
+
if __name__ == '__main__':
|
|
2356
|
+
demo()
|