-
Notifications
You must be signed in to change notification settings - Fork 15
/
Copy pathsvptreectrl.py
8740 lines (6181 loc) · 304 KB
/
svptreectrl.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
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
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
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
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
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
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
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
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
481
482
483
484
485
486
487
488
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
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
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
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
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
688
689
690
691
692
693
694
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
723
724
725
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
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
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
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
990
991
992
993
994
995
996
997
998
999
1000
# --------------------------------------------------------------------------------- #
# CUSTOMTREECTRL wxPython IMPLEMENTATION
# Inspired By And Heavily Based On wxGenericTreeCtrl.
#
# Andrea Gavana, @ 17 May 2006
# Latest Revision: 03 Jan 2014, 23.00 GMT
#
#
# TODO List
#
# Almost All The Features Of wx.TreeCtrl Are Available, And There Is Practically
# No Limit In What Could Be Added To This Class. The First Things That Comes
# To My Mind Are:
#
# 1. Try To Implement A More Flicker-Free Background Image In Cases Like
# Centered Or Stretched Image (Now CustomTreeCtrl Supports Only Tiled
# Background Images).
#
# 2. Try To Mimic Windows wx.TreeCtrl Expanding/Collapsing behaviour: CustomTreeCtrl
# Suddenly Expands/Collapses The Nodes On Mouse Click While The Native Control
# Has Some Kind Of "Smooth" Expanding/Collapsing, Like A Wave. I Don't Even
# Know Where To Start To Do That.
#
# 3. Speed Up General OnPaint Things? I Have No Idea, Here CustomTreeCtrl Is Quite
# Fast, But We Should See On Slower Machines.
#
#
# For All Kind Of Problems, Requests Of Enhancements And Bug Reports, Please
# Write To Me At:
#
#
# Or, Obviously, To The wxPython Mailing List!!!
#
#
# End Of Comments
# --------------------------------------------------------------------------------- #
"""
:class:`CustomTreeCtrl` is a class that mimics the behaviour of :class:`TreeCtrl`, with some more
enhancements.
Description
===========
:class:`CustomTreeCtrl` is a class that mimics the behaviour of :class:`TreeCtrl`, with almost the
same base functionalities plus some more enhancements. This class does not rely on
the native control, as it is a full owner-drawn tree control.
Apart of the base functionalities of :class:`CustomTreeCtrl` (described below), in addition
to the standard :class:`TreeCtrl` behaviour this class supports:
* CheckBox-type items: checkboxes are easy to handle, just selected or unselected
state with no particular issues in handling the item's children;
* Added support for 3-state value checkbox items;
* RadioButton-type items: since I elected to put radiobuttons in :class:`CustomTreeCtrl`, I
needed some way to handle them, that made sense. So, I used the following approach:
- All peer-nodes that are radiobuttons will be mutually exclusive. In other words,
only one of a set of radiobuttons that share a common parent can be checked at
once. If a radiobutton node becomes checked, then all of its peer radiobuttons
must be unchecked.
- If a radiobutton node becomes unchecked, then all of its child nodes will become
inactive.
* Hyperlink-type items: they look like an hyperlink, with the proper mouse cursor on
hovering;
* Multiline text items (**note**: to add a newline character in a multiline item, press
``Shift`` + ``Enter`` as the ``Enter`` key alone is consumed by :class:`CustomTreeCtrl` to finish
the editing and ``Ctrl`` + ``Enter`` is consumed by the platform for tab navigation);
* Enabling/disabling items (together with their plain or grayed out icons);
* Whatever non-toplevel widget can be attached next to an item;
* Possibility to horizontally align the widgets attached to tree items on the
same tree level.
* Possibility to align the widgets attached to tree items to the rightmost edge of :class:`CustomTreeCtrl`;
* Default selection style, gradient (horizontal/vertical) selection style and Windows
Vista selection style;
* Customized drag and drop images built on the fly;
* Setting the :class:`CustomTreeCtrl` item buttons to a personalized imagelist;
* Setting the :class:`CustomTreeCtrl` check/radio item icons to a personalized imagelist;
* Changing the style of the lines that connect the items (in terms of :class:`wx.Pen` styles);
* Using an image as a :class:`CustomTreeCtrl` background (currently only in "tile" mode);
* Adding images to any item in the leftmost area of the :class:`CustomTreeCtrl` client window.
* Separator-type items which are simply visual indicators that are meant to set apart
or divide tree items, with the following caveats:
- Separator items should not have children, labels, data or an associated window;
- You can change the color of individual separators by using meth:~CustomTreeCtrl.SetItemTextColour`, or you can use
meth:~CustomTreeCtrl.SetSeparatorColour` to change the color of all separators. The default separator colour
is that returned by `SystemSettings.GetColour(wx.SYS_COLOUR_GRAYTEXT)`;
- Separators can be selected just like any other tree item;
- Separators cannot have text;
- Separators cannot have children;
- Separators cannot be edited via the ``EVT_TREE_BEGIN_LABEL_EDIT`` event.
* Ellipsization of long items when the horizontal space is low, via the ``TR_ELLIPSIZE_LONG_ITEMS``
style (`New in version 0.9.3`);
* Tooltips on long items when the horizontal space is low, via the ``TR_TOOLTIP_ON_LONG_ITEMS``
style (`New in version 0.9.3`).
And a lot more. Check the demo for an almost complete review of the functionalities.
Base Functionalities
====================
:class:`CustomTreeCtrl` supports all the :class:`TreeCtrl` styles, except:
- ``TR_EXTENDED``: supports for this style is on the todo list (am I sure of this?).
Plus it has 3 more styles to handle checkbox-type items:
- ``TR_AUTO_CHECK_CHILD``: automatically checks/unchecks the item children;
- ``TR_AUTO_CHECK_PARENT``: automatically checks/unchecks the item parent;
- ``TR_AUTO_TOGGLE_CHILD``: automatically toggles the item children.
And two styles you can use to force the horizontal alignment of all the widgets
attached to the tree items:
- ``TR_ALIGN_WINDOWS``: aligns horizontally the windows belonging to the item on the
same tree level.
- ``TR_ALIGN_WINDOWS_RIGHT``: aligns to the rightmost position the windows belonging
to the item on the same tree level.
And two styles related to long items (with a lot of text in them), which can be
ellipsized and/or highlighted with a tooltip:
- ``TR_ELLIPSIZE_LONG_ITEMS``: ellipsizes long items when the horizontal space for
:class:`CustomTreeCtrl` is low (`New in version 0.9.3`);
- ``TR_TOOLTIP_ON_LONG_ITEMS``: shows tooltips on long items when the horizontal space
for :class:`CustomTreeCtrl` is low (`New in version 0.9.3`);.
All the methods available in :class:`TreeCtrl` are also available in :class:`CustomTreeCtrl`.
Usage
=====
Usage example::
import wx
import wx.lib.agw.customtreectrl as CT
class MyFrame(wx.Frame):
def __init__(self, parent):
wx.Frame.__init__(self, parent, -1, "CustomTreeCtrl Demo")
# Create a CustomTreeCtrl instance
custom_tree = CT.CustomTreeCtrl(self, agwStyle=wx.TR_DEFAULT_STYLE)
# Add a root node to it
root = custom_tree.AddRoot("The Root Item")
# Create an image list to add icons next to an item
il = wx.ImageList(16, 16)
fldridx = il.Add(wx.ArtProvider.GetBitmap(wx.ART_FOLDER, wx.ART_OTHER, (16, 16)))
fldropenidx = il.Add(wx.ArtProvider.GetBitmap(wx.ART_FILE_OPEN, wx.ART_OTHER, (16, 16)))
fileidx = il.Add(wx.ArtProvider.GetBitmap(wx.ART_NORMAL_FILE, wx.ART_OTHER, (16, 16)))
custom_tree.SetImageList(il)
custom_tree.SetItemImage(root, fldridx, wx.TreeItemIcon_Normal)
custom_tree.SetItemImage(root, fldropenidx, wx.TreeItemIcon_Expanded)
for x in range(15):
child = custom_tree.AppendItem(root, "Item %d" % x)
custom_tree.SetItemImage(child, fldridx, wx.TreeItemIcon_Normal)
custom_tree.SetItemImage(child, fldropenidx, wx.TreeItemIcon_Expanded)
for y in range(5):
last = custom_tree.AppendItem(child, "item %d-%s" % (x, chr(ord("a")+y)))
custom_tree.SetItemImage(last, fldridx, wx.TreeItemIcon_Normal)
custom_tree.SetItemImage(last, fldropenidx, wx.TreeItemIcon_Expanded)
for z in range(5):
item = custom_tree.AppendItem(last, "item %d-%s-%d" % (x, chr(ord("a")+y), z))
custom_tree.SetItemImage(item, fileidx, wx.TreeItemIcon_Normal)
custom_tree.SetItemImage(item, smileidx, wx.TreeItemIcon_Selected)
custom_tree.Expand(root)
# our normal wxApp-derived class, as usual
app = wx.App(0)
frame = MyFrame(None)
app.SetTopWindow(frame)
frame.Show()
app.MainLoop()
Events
======
All the events supported by :class:`TreeCtrl` are also available in :class:`CustomTreeCtrl`, with
a few exceptions:
- ``EVT_TREE_GET_INFO`` (don't know what this means);
- ``EVT_TREE_SET_INFO`` (don't know what this means);
- ``EVT_TREE_ITEM_MIDDLE_CLICK`` (not implemented, but easy to add);
- ``EVT_TREE_STATE_IMAGE_CLICK`` (no need for that, look at the checking events below).
Plus, :class:`CustomTreeCtrl` supports the events related to the checkbutton-type items:
- ``EVT_TREE_ITEM_CHECKING``: an item is being checked;
- ``EVT_TREE_ITEM_CHECKED``: an item has been checked.
And to hyperlink-type items:
- ``EVT_TREE_ITEM_HYPERLINK``: an hyperlink item has been clicked (this event is sent
after the ``EVT_TREE_SEL_CHANGED`` event).
Supported Platforms
===================
:class:`CustomTreeCtrl` has been tested on the following platforms:
* Windows (Windows XP);
* GTK (Thanks to Michele Petrazzo);
* Mac OS (Thanks to John Jackson).
Window Styles
=============
This class supports the following window styles:
============================== =========== ==================================================
Window Styles Hex Value Description
============================== =========== ==================================================
``TR_NO_BUTTONS`` 0x0 For convenience to document that no buttons are to be drawn.
``TR_SINGLE`` 0x0 For convenience to document that only one item may be selected at a time. Selecting another item causes the current selection, if any, to be deselected. This is the default.
``TR_HAS_BUTTONS`` 0x1 Use this style to show + and - buttons to the left of parent items.
``TR_NO_LINES`` 0x4 Use this style to hide vertical level connectors.
``TR_LINES_AT_ROOT`` 0x8 Use this style to show lines between root nodes. Only applicable if ``TR_HIDE_ROOT`` is set and ``TR_NO_LINES`` is not set.
``TR_DEFAULT_STYLE`` 0x9 The set of flags that are closest to the defaults for the native control for a particular toolkit.
``TR_TWIST_BUTTONS`` 0x10 Use old Mac-twist style buttons.
``TR_MULTIPLE`` 0x20 Use this style to allow a range of items to be selected. If a second range is selected, the current range, if any, is deselected.
``TR_EXTENDED`` 0x40 Use this style to allow disjoint items to be selected. (Only partially implemented; may not work in all cases).
``TR_HAS_VARIABLE_ROW_HEIGHT`` 0x80 Use this style to cause row heights to be just big enough to fit the content. If not set, all rows use the largest row height. The default is that this flag is unset.
``TR_EDIT_LABELS`` 0x200 Use this style if you wish the user to be able to edit labels in the tree control.
``TR_ROW_LINES`` 0x400 Use this style to draw a contrasting border between displayed rows.
``TR_HIDE_ROOT`` 0x800 Use this style to suppress the display of the root node, effectively causing the first-level nodes to appear as a series of root nodes.
``TR_FULL_ROW_HIGHLIGHT`` 0x2000 Use this style to have the background colour and the selection highlight extend over the entire horizontal row of the tree control window.
``TR_AUTO_CHECK_CHILD`` 0x4000 Only meaningful foe checkbox-type items: when a parent item is checked/unchecked its children are checked/unchecked as well.
``TR_AUTO_TOGGLE_CHILD`` 0x8000 Only meaningful foe checkbox-type items: when a parent item is checked/unchecked its children are toggled accordingly.
``TR_AUTO_CHECK_PARENT`` 0x10000 Only meaningful foe checkbox-type items: when a child item is checked/unchecked its parent item is checked/unchecked as well.
``TR_ALIGN_WINDOWS`` 0x20000 Flag used to align windows (in items with windows) at the same horizontal position.
``TR_ALIGN_WINDOWS_RIGHT`` 0x40000 Flag used to align windows (in items with windows) to the rightmost edge of :class:`CustomTreeCtrl`.
``TR_ELLIPSIZE_LONG_ITEMS`` 0x80000 Flag used to ellipsize long items when the horizontal space for :class:`CustomTreeCtrl` is low.
``TR_TOOLTIP_ON_LONG_ITEMS`` 0x100000 Flag used to show tooltips on long items when the horizontal space for :class:`CustomTreeCtrl` is low.
============================== =========== ==================================================
Events Processing
=================
This class processes the following events:
============================== ==================================================
Event Name Description
============================== ==================================================
``EVT_TREE_BEGIN_DRAG`` Begin dragging with the left mouse button.
``EVT_TREE_BEGIN_LABEL_EDIT`` Begin editing a label. This can be prevented by calling meth:~TreeEvent.Veto`.
``EVT_TREE_BEGIN_RDRAG`` Begin dragging with the right mouse button.
``EVT_TREE_DELETE_ITEM`` Delete an item.
``EVT_TREE_END_DRAG`` End dragging with the left or right mouse button.
``EVT_TREE_END_LABEL_EDIT`` End editing a label. This can be prevented by calling meth:~TreeEvent.Veto`.
``EVT_TREE_GET_INFO`` Request information from the application (not implemented in :class:`CustomTreeCtrl`).
``EVT_TREE_ITEM_ACTIVATED`` The item has been activated, i.e. chosen by double clicking it with mouse or from keyboard.
``EVT_TREE_ITEM_CHECKED`` A checkbox or radiobox type item has been checked.
``EVT_TREE_ITEM_CHECKING`` A checkbox or radiobox type item is being checked.
``EVT_TREE_ITEM_COLLAPSED`` The item has been collapsed.
``EVT_TREE_ITEM_COLLAPSING`` The item is being collapsed. This can be prevented by calling meth:~TreeEvent.Veto`.
``EVT_TREE_ITEM_EXPANDED`` The item has been expanded.
``EVT_TREE_ITEM_EXPANDING`` The item is being expanded. This can be prevented by calling meth:~TreeEvent.Veto`.
``EVT_TREE_ITEM_GETTOOLTIP`` The opportunity to set the item tooltip is being given to the application (call `TreeEvent.SetToolTip`).
``EVT_TREE_ITEM_HYPERLINK`` An hyperlink type item has been clicked.
``EVT_TREE_ITEM_MENU`` The context menu for the selected item has been requested, either by a right click or by using the menu key.
``EVT_TREE_ITEM_MIDDLE_CLICK`` The user has clicked the item with the middle mouse button (not implemented in :class:`CustomTreeCtrl`).
``EVT_TREE_ITEM_RIGHT_CLICK`` The user has clicked the item with the right mouse button.
``EVT_TREE_KEY_DOWN`` A key has been pressed.
``EVT_TREE_SEL_CHANGED`` Selection has changed.
``EVT_TREE_SEL_CHANGING`` Selection is changing. This can be prevented by calling meth:~TreeEvent.Veto`.
``EVT_TREE_SET_INFO`` Information is being supplied to the application (not implemented in :class:`CustomTreeCtrl`).
``EVT_TREE_STATE_IMAGE_CLICK`` The state image has been clicked (not implemented in :class:`CustomTreeCtrl`).
============================== ==================================================
License And Version
===================
:class:`CustomTreeCtrl` is distributed under the wxPython license.
Latest Revision: Andrea Gavana @ 03 Jan 2014, 23.00 GMT
Version 2.6
"""
# Version Info
__version__ = "2.6"
from builtins import input
from builtins import range
import wx
from wx.lib.expando import ExpandoTextCtrl
# ----------------------------------------------------------------------------
# Constants
# ----------------------------------------------------------------------------
_NO_IMAGE = -1
_PIXELS_PER_UNIT = 10
# Start editing the current item after half a second (if the mouse hasn't
# been clicked/moved)
_DELAY = 500
# wxPython version string
_VERSION_STRING = wx.VERSION_STRING
# ----------------------------------------------------------------------------
# Constants
# ----------------------------------------------------------------------------
# Enum for different images associated with a treectrl item
TreeItemIcon_Normal = 0 # not selected, not expanded
""" The tree item is not selected and not expanded. """
TreeItemIcon_Selected = 1 # selected, not expanded
""" The tree item is selected and not expanded. """
TreeItemIcon_Expanded = 2 # not selected, expanded
""" The tree item is not selected but expanded. """
TreeItemIcon_SelectedExpanded = 3 # selected, expanded
""" The tree item is selected and expanded. """
TreeItemIcon_Checked = 0 # check button, checked
""" The item's check button is checked. """
TreeItemIcon_NotChecked = 1 # check button, not checked
""" The item's check button is not checked. """
TreeItemIcon_Undetermined = 2 # check button, undetermined
""" The item's check button is in undetermined state (used only for a 3-state check button). """
TreeItemIcon_Flagged = 3 # radio button, selected
""" The item's radio button is checked. """
TreeItemIcon_NotFlagged = 4 # radio button, not selected
""" The item's radio button is not checked. """
# ----------------------------------------------------------------------------
# CustomTreeCtrl flags
# ----------------------------------------------------------------------------
TR_NO_BUTTONS = wx.TR_NO_BUTTONS # for convenience
""" For convenience to document that no buttons are to be drawn. """
TR_HAS_BUTTONS = wx.TR_HAS_BUTTONS # draw collapsed/expanded btns
""" Use this style to show + and - buttons to the left of parent items. """
TR_NO_LINES = wx.TR_NO_LINES # don't draw lines at all
""" Use this style to hide vertical level connectors. """
TR_LINES_AT_ROOT = wx.TR_LINES_AT_ROOT # connect top-level nodes
""" Use this style to show lines between root nodes. Only applicable if ``TR_HIDE_ROOT`` is set and ``TR_NO_LINES`` is not set. """
TR_TWIST_BUTTONS = wx.TR_TWIST_BUTTONS # still used by wxTreeListCtrl
""" Use old Mac-twist style buttons. """
TR_SINGLE = wx.TR_SINGLE # for convenience
""" For convenience to document that only one item may be selected at a time. Selecting another item causes the current selection, if any, to be deselected. This is the default. """
TR_MULTIPLE = wx.TR_MULTIPLE # can select multiple items
""" Use this style to allow a range of items to be selected. If a second range is selected, the current range, if any, is deselected. """
TR_EXTENDED = 0x40 # TODO: allow extended selection
""" Use this style to allow disjoint items to be selected. (Only partially implemented; may not work in all cases). """
TR_HAS_VARIABLE_ROW_HEIGHT = wx.TR_HAS_VARIABLE_ROW_HEIGHT # what it says
""" Use this style to cause row heights to be just big enough to fit the content. If not set, all rows use the largest row height. The default is that this flag is unset. """
TR_EDIT_LABELS = wx.TR_EDIT_LABELS # can edit item labels
""" Use this style if you wish the user to be able to edit labels in the tree control. """
TR_ROW_LINES = wx.TR_ROW_LINES # put border around items
""" Use this style to draw a contrasting border between displayed rows. """
TR_HIDE_ROOT = wx.TR_HIDE_ROOT # don't display root node
""" Use this style to suppress the display of the root node, effectively causing the first-level nodes to appear as a series of root nodes. """
TR_FULL_ROW_HIGHLIGHT = wx.TR_FULL_ROW_HIGHLIGHT # highlight full horz space
""" Use this style to have the background colour and the selection highlight extend over the entire horizontal row of the tree control window. """
TR_AUTO_CHECK_CHILD = 0x04000 # only meaningful for checkboxes
""" Only meaningful for checkbox-type items: when a parent item is checked/unchecked its children are checked/unchecked as well. """
TR_AUTO_TOGGLE_CHILD = 0x08000 # only meaningful for checkboxes
""" Only meaningful foe checkbox-type items: when a parent item is checked/unchecked its children are toggled accordingly. """
TR_AUTO_CHECK_PARENT = 0x10000 # only meaningful for checkboxes
""" Only meaningful foe checkbox-type items: when a child item is checked/unchecked its parent item is checked/unchecked as well. """
TR_ALIGN_WINDOWS = 0x20000 # to align windows horizontally for items at the same level
""" Flag used to align windows (in items with windows) at the same horizontal position. """
TR_ALIGN_WINDOWS_RIGHT = 0x40000 # to align windows to the rightmost edge of CustomTreeCtrl
""" Flag used to align windows (in items with windows) to the rightmost edge of :class:`CustomTreeCtrl`."""
TR_ELLIPSIZE_LONG_ITEMS = 0x80000 # to ellipsize long items when horizontal space is low
""" Flag used to ellipsize long items when the horizontal space for :class:`CustomTreeCtrl` is low."""
TR_TOOLTIP_ON_LONG_ITEMS = 0x100000 # to display tooltips on long items when horizontal space is low
""" Flag used to show tooltips on long items when the horizontal space for :class:`CustomTreeCtrl` is low."""
TR_DEFAULT_STYLE = wx.TR_DEFAULT_STYLE # default style for the tree control
""" The set of flags that are closest to the defaults for the native control for a particular toolkit. """
# Values for the `flags` parameter of CustomTreeCtrl.HitTest() which determine
# where exactly the specified point is situated:
TREE_HITTEST_ABOVE = wx.TREE_HITTEST_ABOVE
""" Above the client area. """
TREE_HITTEST_BELOW = wx.TREE_HITTEST_BELOW
""" Below the client area. """
TREE_HITTEST_NOWHERE = wx.TREE_HITTEST_NOWHERE
""" No item has been hit. """
TREE_HITTEST_ONITEMBUTTON = wx.TREE_HITTEST_ONITEMBUTTON
""" On the button associated with an item. """
TREE_HITTEST_ONITEMICON = wx.TREE_HITTEST_ONITEMICON
""" On the bitmap associated with an item. """
TREE_HITTEST_ONITEMINDENT = wx.TREE_HITTEST_ONITEMINDENT
""" On the indent associated with an item. """
TREE_HITTEST_ONITEMLABEL = wx.TREE_HITTEST_ONITEMLABEL
""" On the label (string) associated with an item. """
TREE_HITTEST_ONITEMRIGHT = wx.TREE_HITTEST_ONITEMRIGHT
""" On the right of the label associated with an item. """
TREE_HITTEST_ONITEMSTATEICON = wx.TREE_HITTEST_ONITEMSTATEICON
""" On the right of the label associated with an item. """
TREE_HITTEST_TOLEFT = wx.TREE_HITTEST_TOLEFT
""" On the left of an item. """
TREE_HITTEST_TORIGHT = wx.TREE_HITTEST_TORIGHT
""" On the right of an item. """
TREE_HITTEST_ONITEMUPPERPART = wx.TREE_HITTEST_ONITEMUPPERPART
""" On the upper part (first half) of the item. """
TREE_HITTEST_ONITEMLOWERPART = wx.TREE_HITTEST_ONITEMLOWERPART
""" On the lower part (second half) of the item. """
TREE_HITTEST_ONITEMCHECKICON = 0x4000
""" On the check icon, if present. """
TREE_HITTEST_ONITEM = TREE_HITTEST_ONITEMICON | TREE_HITTEST_ONITEMLABEL | TREE_HITTEST_ONITEMCHECKICON
""" Anywhere on the item. """
TREE_ITEMTYPE_NORMAL = 0
""" A normal item. """
TREE_ITEMTYPE_CHECK = 1
""" A checkbox-like item. """
TREE_ITEMTYPE_RADIO = 2
""" A radiobutton-like item. """
# Background Image Style
_StyleTile = 0
_StyleStretch = 1
# Windows Vista Colours
_rgbSelectOuter = wx.Colour(170, 200, 245)
_rgbSelectInner = wx.Colour(230, 250, 250)
_rgbSelectTop = wx.Colour(210, 240, 250)
_rgbSelectBottom = wx.Colour(185, 215, 250)
_rgbNoFocusTop = wx.Colour(250, 250, 250)
_rgbNoFocusBottom = wx.Colour(235, 235, 235)
_rgbNoFocusOuter = wx.Colour(220, 220, 220)
_rgbNoFocusInner = wx.Colour(245, 245, 245)
# Flags for wx.RendererNative
_CONTROL_EXPANDED = 8
_CONTROL_CURRENT = 16
# ----------------------------------------------------------------------------
# CustomTreeCtrl events and binding for handling them
# ----------------------------------------------------------------------------
wxEVT_TREE_BEGIN_DRAG = wx.wxEVT_COMMAND_TREE_BEGIN_DRAG
wxEVT_TREE_BEGIN_RDRAG = wx.wxEVT_COMMAND_TREE_BEGIN_RDRAG
wxEVT_TREE_BEGIN_LABEL_EDIT = wx.wxEVT_COMMAND_TREE_BEGIN_LABEL_EDIT
wxEVT_TREE_END_LABEL_EDIT = wx.wxEVT_COMMAND_TREE_END_LABEL_EDIT
wxEVT_TREE_DELETE_ITEM = wx.wxEVT_COMMAND_TREE_DELETE_ITEM
wxEVT_TREE_GET_INFO = wx.wxEVT_COMMAND_TREE_GET_INFO
wxEVT_TREE_SET_INFO = wx.wxEVT_COMMAND_TREE_SET_INFO
wxEVT_TREE_ITEM_EXPANDED = wx.wxEVT_COMMAND_TREE_ITEM_EXPANDED
wxEVT_TREE_ITEM_EXPANDING = wx.wxEVT_COMMAND_TREE_ITEM_EXPANDING
wxEVT_TREE_ITEM_COLLAPSED = wx.wxEVT_COMMAND_TREE_ITEM_COLLAPSED
wxEVT_TREE_ITEM_COLLAPSING = wx.wxEVT_COMMAND_TREE_ITEM_COLLAPSING
wxEVT_TREE_SEL_CHANGED = wx.wxEVT_COMMAND_TREE_SEL_CHANGED
wxEVT_TREE_SEL_CHANGING = wx.wxEVT_COMMAND_TREE_SEL_CHANGING
wxEVT_TREE_KEY_DOWN = wx.wxEVT_COMMAND_TREE_KEY_DOWN
wxEVT_TREE_ITEM_ACTIVATED = wx.wxEVT_COMMAND_TREE_ITEM_ACTIVATED
wxEVT_TREE_ITEM_RIGHT_CLICK = wx.wxEVT_COMMAND_TREE_ITEM_RIGHT_CLICK
wxEVT_TREE_ITEM_MIDDLE_CLICK = wx.wxEVT_COMMAND_TREE_ITEM_MIDDLE_CLICK
wxEVT_TREE_END_DRAG = wx.wxEVT_COMMAND_TREE_END_DRAG
wxEVT_TREE_STATE_IMAGE_CLICK = wx.wxEVT_COMMAND_TREE_STATE_IMAGE_CLICK
wxEVT_TREE_ITEM_GETTOOLTIP = wx.wxEVT_COMMAND_TREE_ITEM_GETTOOLTIP
wxEVT_TREE_ITEM_MENU = wx.wxEVT_COMMAND_TREE_ITEM_MENU
wxEVT_TREE_ITEM_CHECKING = wx.NewEventType()
wxEVT_TREE_ITEM_CHECKED = wx.NewEventType()
wxEVT_TREE_ITEM_HYPERLINK = wx.NewEventType()
EVT_TREE_BEGIN_DRAG = wx.EVT_TREE_BEGIN_DRAG
""" Begin dragging with the left mouse button. """
EVT_TREE_BEGIN_RDRAG = wx.EVT_TREE_BEGIN_RDRAG
""" Begin dragging with the right mouse button. """
EVT_TREE_BEGIN_LABEL_EDIT = wx.EVT_TREE_BEGIN_LABEL_EDIT
""" Begin editing a label. This can be prevented by calling meth:~TreeEvent.Veto`. """
EVT_TREE_END_LABEL_EDIT = wx.EVT_TREE_END_LABEL_EDIT
""" End editing a label. This can be prevented by calling meth:~TreeEvent.Veto`. """
EVT_TREE_DELETE_ITEM = wx.EVT_TREE_DELETE_ITEM
""" Delete an item. """
EVT_TREE_GET_INFO = wx.EVT_TREE_GET_INFO
""" Request information from the application (not implemented in :class:`CustomTreeCtrl`). """
EVT_TREE_SET_INFO = wx.EVT_TREE_SET_INFO
""" Information is being supplied to the application (not implemented in :class:`CustomTreeCtrl`). """
EVT_TREE_ITEM_EXPANDED = wx.EVT_TREE_ITEM_EXPANDED
""" The item has been expanded. """
EVT_TREE_ITEM_EXPANDING = wx.EVT_TREE_ITEM_EXPANDING
""" The item is being expanded. This can be prevented by calling meth:~TreeEvent.Veto`. """
EVT_TREE_ITEM_COLLAPSED = wx.EVT_TREE_ITEM_COLLAPSED
""" The item has been collapsed. """
EVT_TREE_ITEM_COLLAPSING = wx.EVT_TREE_ITEM_COLLAPSING
""" The item is being collapsed. This can be prevented by calling meth:~TreeEvent.Veto`. """
EVT_TREE_SEL_CHANGED = wx.EVT_TREE_SEL_CHANGED
""" Selection has changed. """
EVT_TREE_SEL_CHANGING = wx.EVT_TREE_SEL_CHANGING
""" Selection is changing. This can be prevented by calling meth:~TreeEvent.Veto`. """
EVT_TREE_KEY_DOWN = wx.EVT_TREE_KEY_DOWN
""" A key has been pressed. """
EVT_TREE_ITEM_ACTIVATED = wx.EVT_TREE_ITEM_ACTIVATED
""" The item has been activated, i.e. chosen by double clicking it with mouse or from keyboard. """
EVT_TREE_ITEM_RIGHT_CLICK = wx.EVT_TREE_ITEM_RIGHT_CLICK
""" The user has clicked the item with the right mouse button. """
EVT_TREE_ITEM_MIDDLE_CLICK = wx.EVT_TREE_ITEM_MIDDLE_CLICK
""" The user has clicked the item with the middle mouse button (not implemented in :class:`CustomTreeCtrl`). """
EVT_TREE_END_DRAG = wx.EVT_TREE_END_DRAG
""" End dragging with the left or right mouse button. """
EVT_TREE_STATE_IMAGE_CLICK = wx.EVT_TREE_STATE_IMAGE_CLICK
""" The state image has been clicked (not implemented in :class:`CustomTreeCtrl`). """
EVT_TREE_ITEM_GETTOOLTIP = wx.EVT_TREE_ITEM_GETTOOLTIP
""" The opportunity to set the item tooltip is being given to the application (call `TreeEvent.SetToolTip`). """
EVT_TREE_ITEM_MENU = wx.EVT_TREE_ITEM_MENU
""" The context menu for the selected item has been requested, either by a right click or by using the menu key. """
EVT_TREE_ITEM_CHECKING = wx.PyEventBinder(wxEVT_TREE_ITEM_CHECKING, 1)
""" A checkbox or radiobox type item is being checked. """
EVT_TREE_ITEM_CHECKED = wx.PyEventBinder(wxEVT_TREE_ITEM_CHECKED, 1)
""" A checkbox or radiobox type item has been checked. """
EVT_TREE_ITEM_HYPERLINK = wx.PyEventBinder(wxEVT_TREE_ITEM_HYPERLINK, 1)
""" An hyperlink type item has been clicked. """
# ----------------------------------------------------------------------------
def MakeDisabledBitmap(original):
"""
Creates a disabled-looking bitmap starting from the input one.
:param `original`: an instance of :class:`wx.Bitmap` to be greyed-out.
:return: An instance of :class:`wx.Bitmap`, containing a disabled-looking
representation of the original item image.
"""
img = original.ConvertToImage()
return wx.Bitmap(img.ConvertToGreyscale())
# ----------------------------------------------------------------------------
def DrawTreeItemButton(win, dc, rect, flags):
"""
Draw the expanded/collapsed icon for a tree control item.
:param `win`: an instance of :class:`wx.Window`;
:param `dc`: an instance of :class:`wx.DC`;
:param wx.Rect `rect`: the client rectangle where to draw the tree item button;
:param integer `flags`: contains ``wx.CONTROL_EXPANDED`` bit for expanded tree items.
:note: This is a simple replacement of :meth:`RendererNative.DrawTreeItemButton`.
:note: This method is never used in wxPython versions newer than 2.6.2.1.
"""
# white background
dc.SetPen(wx.GREY_PEN)
dc.SetBrush(wx.WHITE_BRUSH)
dc.DrawRectangle(rect)
# black lines
xMiddle = rect.x + rect.width//2
yMiddle = rect.y + rect.height//2
# half of the length of the horz lines in "-" and "+"
halfWidth = rect.width//2 - 2
dc.SetPen(wx.BLACK_PEN)
dc.DrawLine(xMiddle - halfWidth, yMiddle,
xMiddle + halfWidth + 1, yMiddle)
if not flags & _CONTROL_EXPANDED:
# turn "-" into "+"
halfHeight = rect.height//2 - 2
dc.DrawLine(xMiddle, yMiddle - halfHeight,
xMiddle, yMiddle + halfHeight + 1)
# ----------------------------------------------------------------------------
def EventFlagsToSelType(style, shiftDown=False, ctrlDown=False):
"""
Translate the key or mouse event flag to the type of selection we
are dealing with.
:param integer `style`: the main :class:`CustomTreeCtrl` window style flag;
:param bool `shiftDown`: ``True`` if the ``Shift`` key is pressed, ``False`` otherwise;
:param bool `ctrlDown`: ``True`` if the ``Ctrl`` key is pressed, ``False`` otherwise;
:return: A 3-elements tuple, with the following elements:
- `is_multiple`: ``True`` if :class:`CustomTreeCtrl` has the ``TR_MULTIPLE`` flag set, ``False`` otherwise;
- `extended_select`: ``True`` if the ``Shift`` key is pressend and if :class:`CustomTreeCtrl` has the
``TR_MULTIPLE`` flag set, ``False`` otherwise;
- `unselect_others`: ``True`` if the ``Ctrl`` key is pressend and if :class:`CustomTreeCtrl` has the
``TR_MULTIPLE`` flag set, ``False`` otherwise.
"""
is_multiple = (style & TR_MULTIPLE) != 0
extended_select = shiftDown and is_multiple
unselect_others = not (extended_select or (ctrlDown and is_multiple))
return is_multiple, extended_select, unselect_others
# ----------------------------------------------------------------------------
def ChopText(dc, text, max_size):
"""
Chops the input `text` if its size does not fit in `max_size`, by cutting the
text and adding ellipsis at the end.
:param `dc`: a :class:`wx.DC` device context;
:param `text`: the text to chop;
:param `max_size`: the maximum size in which the text should fit.
:note: This method is used exclusively when :class:`CustomTreeCtrl` has the ``TR_ELLIPSIZE_LONG_ITEMS``
style set.
.. versionadded:: 0.9.3
"""
# first check if the text fits with no problems
x, y, dummy = dc.GetFullMultiLineTextExtent(text)
if x <= max_size:
return text
textLen = len(text)
last_good_length = 0
for i in range(textLen, -1, -1):
s = text[0:i]
s += "..."
x, y = dc.GetTextExtent(s)
last_good_length = i
if x < max_size:
break
# ret = text[0:last_good_length] + "..."
ret = '...' + text[-last_good_length:]
return ret
#---------------------------------------------------------------------------
# DragImage Implementation
# This Class Handles The Creation Of A Custom Image In Case Of Item Drag
# And Drop.
#---------------------------------------------------------------------------
class DragImage(wx.DragImage):
"""
This class handles the creation of a custom image in case of item drag
and drop.
"""
def __init__(self, treeCtrl, item):
"""
Default class constructor.
For internal use: do not call it in your code!
:param `treeCtrl`: the parent :class:`CustomTreeCtrl`;
:param `item`: one of the tree control item (an instance of :class:`GenericTreeItem`).
"""
text = item.GetText()
font = item.Attr().GetFont()
colour = item.Attr().GetTextColour()
if not colour:
colour = wx.BLACK
if not font:
font = treeCtrl._normalFont
backcolour = treeCtrl.GetBackgroundColour()
r, g, b = int(backcolour.Red()), int(backcolour.Green()), int(backcolour.Blue())
backcolour = ((r >> 1) + 20, (g >> 1) + 20, (b >> 1) + 20)
backcolour = wx.Colour(backcolour[0], backcolour[1], backcolour[2])
self._backgroundColour = backcolour
tempdc = wx.ClientDC(treeCtrl)
tempdc.SetFont(font)
width, height, dummy = tempdc.GetFullMultiLineTextExtent(text + "M")
image = item.GetCurrentImage()
image_w, image_h = 0, 0
wcheck, hcheck = 0, 0
itemcheck = None
itemimage = None
ximagepos = 0
yimagepos = 0
xcheckpos = 0
ycheckpos = 0
if image != _NO_IMAGE:
if treeCtrl._imageListNormal:
image_w, image_h = treeCtrl._imageListNormal.GetSize(image)
image_w += 4
itemimage = treeCtrl._imageListNormal.GetBitmap(image)
checkimage = item.GetCurrentCheckedImage()
if checkimage is not None:
if treeCtrl._imageListCheck:
wcheck, hcheck = treeCtrl._imageListCheck.GetSize(checkimage)
wcheck += 4
itemcheck = treeCtrl._imageListCheck.GetBitmap(checkimage)
total_h = max(hcheck, height)
total_h = max(image_h, total_h)
if image_w:
ximagepos = wcheck
yimagepos = ((total_h > image_h) and [(total_h-image_h)//2] or [0])[0]
if checkimage is not None:
xcheckpos = 2
ycheckpos = ((total_h > image_h) and [(total_h-image_h)//2] or [0])[0] + 2
extraH = ((total_h > height) and [(total_h - height)//2] or [0])[0]
extraH = ((total_h > height) and [(total_h - height)/2] or [0])[0]
xtextpos = wcheck + image_w
ytextpos = extraH
total_h = max(image_h, hcheck)
total_h = max(total_h, height)
if total_h < 30:
total_h += 2 # at least 2 pixels
else:
total_h += total_h//10 # otherwise 10% extra spacing
total_w = image_w + wcheck + width
self._total_w = total_w
self._total_h = total_h
self._itemimage = itemimage
self._itemcheck = itemcheck
self._text = text
self._colour = colour
self._font = font
self._xtextpos = xtextpos
self._ytextpos = ytextpos
self._ximagepos = ximagepos
self._yimagepos = yimagepos
self._xcheckpos = xcheckpos
self._ycheckpos = ycheckpos
self._textwidth = width
self._textheight = height
self._extraH = extraH
self._bitmap = self.CreateBitmap()
wx.DragImage.__init__(self, self._bitmap)
def CreateBitmap(self):
"""
Actually creates the drag and drop bitmap for :class:`DragImage`.
:return: An instance of :class:`DragImage`, a close representation of the item's
appearance (i.e., a screenshot of the item).
"""
memory = wx.MemoryDC()
bitmap = wx.Bitmap(self._total_w, self._total_h)
memory.SelectObject(bitmap)
if wx.Platform == '__WXMAC__':
memory.SetBackground(wx.TRANSPARENT_BRUSH)
else:
memory.SetBackground(wx.Brush(self._backgroundColour))
memory.SetBackgroundMode(wx.TRANSPARENT)
memory.SetFont(self._font)
memory.SetTextForeground(self._colour)
memory.Clear()
if self._itemimage:
memory.DrawBitmap(self._itemimage, self._ximagepos, self._yimagepos, True)
if self._itemcheck:
memory.DrawBitmap(self._itemcheck, self._xcheckpos, self._ycheckpos, True)
textrect = wx.Rect(self._xtextpos, self._ytextpos+self._extraH, self._textwidth, self._textheight)
memory.DrawLabel(self._text, textrect)
memory.SelectObject(wx.NullBitmap)
# Gtk and Windows unfortunatly don't do so well with transparent
# drawing so this hack corrects the image to have a transparent
# background.
if wx.Platform != '__WXMAC__':
timg = bitmap.ConvertToImage()
if not timg.HasAlpha():
timg.InitAlpha()
for y in range(timg.GetHeight()):
for x in range(timg.GetWidth()):
pix = wx.Colour(timg.GetRed(x, y),
timg.GetGreen(x, y),
timg.GetBlue(x, y))
if pix == self._backgroundColour:
timg.SetAlpha(x, y, 0)
bitmap = timg.ConvertToBitmap()
return bitmap
# ----------------------------------------------------------------------------
# TreeItemAttr: a structure containing the visual attributes of an item
# ----------------------------------------------------------------------------
class TreeItemAttr(object):
"""
Creates the item attributes (text colour, background colour and font).
:note: This class is inspired by the wxWidgets generic implementation of :class:`TreeItemAttr`.
"""
def __init__(self, colText=wx.NullColour, colBack=wx.NullColour, colBorder=wx.NullColour,font=wx.NullFont):
"""
Default class constructor.
For internal use: do not call it in your code!
:param `colText`: the text colour, an instance of :class:`Colour`;
:param `colBack`: the tree item background colour, an instance of :class:`Colour`;
:param `colBorder`: the tree item border colour, an instance of :class:`Colour`;
:param `font`: the tree item font, an instance of :class:`Font`.
"""
self._colText = colText
self._colBack = colBack
self._colBorder = colBorder
self._font = font
# setters
def SetTextColour(self, colText):
"""
Sets the text colour attribute.
:param `colText`: an instance of :class:`wx.Colour`.
"""
self._colText = colText
def SetBackgroundColour(self, colBack):
"""
Sets the item background colour attribute.
:param `colBack`: an instance of :class:`wx.Colour`.
"""
self._colBack = colBack
def SetBorderColour(self, colBorder):
"""
Sets the item border colour attribute.
:param `colBack`: an instance of :class:`wx.Colour`.
.. versionadded:: 0.9.6
"""
self._colBorder = colBorder
def SetFont(self, font):
"""
Sets the item font attribute.
:param `font`: an instance of :class:`wx.Font`.
"""
self._font = font
# accessors
def HasTextColour(self):
"""
Returns whether the attribute has text colour.
:return: ``True`` if the text colour attribute has been set, ``False`` otherwise.
"""
return self._colText != wx.NullColour and self._colText.IsOk()
def HasBackgroundColour(self):
"""
Returns whether the attribute has background colour.
:return: ``True`` if the background colour attribute has been set, ``False`` otherwise.
"""
return self._colBack != wx.NullColour and self._colBack.IsOk()
def HasBorderColour(self):
"""
Returns whether the attribute has border colour.
:return: ``True`` if the border colour attribute has been set, ``False`` otherwise.
.. versionadded:: 0.9.6
"""
return self._colBorder != wx.NullColour and self._colBorder.IsOk()
def HasFont(self):
"""
Returns whether the attribute has font.
:return: ``True`` if the font attribute has been set, ``False`` otherwise.
"""
return self._font != wx.NullFont and self._font.IsOk()
# getters
def GetTextColour(self):
"""
Returns the attribute text colour.
:return: An instance of :class:`wx.Colour`.
"""
return self._colText
def GetBackgroundColour(self):
"""
Returns the attribute background colour.
:return: An instance of :class:`wx.Colour`.
"""
return self._colBack
def GetBorderColour(self):
"""
Returns the attribute border colour.
:return: An instance of :class:`wx.Colour`.
.. versionadded:: 0.9.6
"""
return self._colBorder
def GetFont(self):
"""
Returns the attribute font.
:return: An instance of :class:`wx.Font`.
"""
return self._font
# ----------------------------------------------------------------------------
# CommandTreeEvent Is A Special Subclassing Of wx.CommandEvent
#
# NB: Note That Not All The Accessors Make Sense For All The Events, See The
# Event Description Below.
# ----------------------------------------------------------------------------
class CommandTreeEvent(wx.CommandEvent):
"""
:class:`CommandTreeEvent` is a special subclassing of :class:`CommandEvent`.
:note: Not all the accessors make sense for all the events, see the event description for every method in this class.
"""