-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathCustomUltimateListCtrl.py
More file actions
13671 lines (9501 loc) · 447 KB
/
CustomUltimateListCtrl.py
File metadata and controls
13671 lines (9501 loc) · 447 KB
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
# --------------------------------------------------------------------------------- #
# ULTIMATELISTCTRL wxPython IMPLEMENTATION
# Inspired by and heavily based on the wxWidgets C++ generic version of wxListCtrl.
#
# Andrea Gavana, @ 08 May 2009
# Latest Revision: 27 Dec 2012, 21.00 GMT
#
#
# TODO List
#
# 1) Subitem selection;
# 2) Watermark? (almost, does not work very well :-( );
# 3) Groups? (Maybe, check ObjectListView);
# 4) Scrolling items as headers and footers;
# 5) Alpha channel for text/background of items;
# 6) Custom renderers for headers/footers (done);
# 7) Fading in and out on mouse motion (a la Windows Vista Aero);
# 8) Sub-text for headers/footers (grey text below the header/footer text);
# 9) Fixing the columns to the left or right side of the control layout;
# 10) Skins for header and scrollbars (implemented for headers/footers).
#
#
# For all kind of problems, requests of enhancements and bug reports, please
# write to me at:
#
# andrea.gavana@gmail.com
# andrea.gavana@maerskoil.com
#
# Or, obviously, to the wxPython mailing list!!!
#
# Tags: phoenix-port, documented, unittest, py3-port
#
# End Of Comments
# --------------------------------------------------------------------------------- #
"""
Description
===========
UltimateListCtrl is a class that mimics the behaviour of :class:`ListCtrl`, 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 list control.
In addition to the standard :class:`ListCtrl` behaviour this class supports:
Appearance
==========
* Multiple images for items/subitems;
* Images can be of any size and not limited to a single specific pair of `width`, `height`
as it is the case of :class:`wx.ImageList`. Simply use :class:`PyImageList` instead of :class:`wx.ImageList`
to add your images.
* Font, colour, background, custom renderers and formatting for items and subitems;
* Ability to add persistent data to an item using :meth:`~UltimateListCtrl.SetItemPyData` and :meth:`~UltimateListCtrl.GetItemPyData`:
the data can be any Python object and not necessarily an integer as in :class:`ListCtrl`;
* CheckBox-type items and subitems;
* RadioButton-type items and subitems;
* Overflowing items/subitems, a la :class:`grid.Grid`, i.e. an item/subitem may overwrite neighboring
items/subitems if its text would not normally fit in the space allotted to it;
* Hyperlink-type items and subitems: they look like an hyperlink, with the proper mouse
cursor on hovering;
* Multiline text items and subitems;
* Variable row heights depending on the item/subitem kind/text/window;
* User defined item/subitem renderers: these renderer classes **must** implement the methods
`DrawSubItem`, `GetLineHeight` and `GetSubItemWidth` (see the demo);
* Enabling/disabling items (together with their plain or grayed out icons);
* Whatever non-toplevel widget can be attached next to an item/subitem;
* Column headers are fully customizable in terms of icons, colour, font, alignment etc...;
* Column headers can have their own checkbox/radiobutton;
* Column footers are fully customizable in terms of icons, colour, font, alignment etc...;
* Column footers can have their own checkbox/radiobutton;
* Ability to hide/show columns;
* Default selection style, gradient (horizontal/vertical) selection style and Windows
Vista selection style.
And a lot more. Check the demo for an almost complete review of the functionalities.
Usage
=====
Usage example::
import sys
import wx
import wx.lib.agw.ultimatelistctrl as ULC
class MyFrame(wx.Frame):
def __init__(self, parent):
wx.Frame.__init__(self, parent, -1, "UltimateListCtrl Demo")
list = ULC.UltimateListCtrl(self, wx.ID_ANY, agwStyle=ULC.ULC_REPORT | ULC.ULC_VRULES | ULC.ULC_HRULES | ULC.ULC_SINGLE_SEL | ULC.ULC_HAS_VARIABLE_ROW_HEIGHT)
list.InsertColumn(0, "Column 1")
list.InsertColumn(1, "Column 2")
index = list.InsertStringItem(sys.maxsize, "Item 1")
list.SetStringItem(index, 1, "Sub-item 1")
index = list.InsertStringItem(sys.maxsize, "Item 2")
list.SetStringItem(index, 1, "Sub-item 2")
choice = wx.Choice(list, -1, choices=["one", "two"])
index = list.InsertStringItem(sys.maxsize, "A widget")
list.SetItemWindow(index, 1, choice, expand=True)
sizer = wx.BoxSizer(wx.VERTICAL)
sizer.Add(list, 1, wx.EXPAND)
self.SetSizer(sizer)
# our normal wxApp-derived class, as usual
if __name__ == "__main__":
app = wx.App(0)
frame = MyFrame(None)
app.SetTopWindow(frame)
frame.Show()
app.MainLoop()
Window Styles
=============
This class supports the following window styles:
=============================== =========== ====================================================================================================
Window Styles Hex Value Description
=============================== =========== ====================================================================================================
``ULC_VRULES`` 0x1 Draws light vertical rules between rows in report mode.
``ULC_HRULES`` 0x2 Draws light horizontal rules between rows in report mode.
``ULC_ICON`` 0x4 Large icon view, with optional labels.
``ULC_SMALL_ICON`` 0x8 Small icon view, with optional labels.
``ULC_LIST`` 0x10 Multicolumn list view, with optional small icons. Columns are computed automatically, i.e. you don't set columns as in ``ULC_REPORT``. In other words, the list wraps, unlike a :class:`ListBox`.
``ULC_REPORT`` 0x20 Single or multicolumn report view, with optional header.
``ULC_ALIGN_TOP`` 0x40 Icons align to the top. Win32 default, Win32 only.
``ULC_ALIGN_LEFT`` 0x80 Icons align to the left.
``ULC_AUTOARRANGE`` 0x100 Icons arrange themselves. Win32 only.
``ULC_VIRTUAL`` 0x200 The application provides items text on demand. May only be used with ``ULC_REPORT``.
``ULC_EDIT_LABELS`` 0x400 Labels are editable: the application will be notified when editing starts.
``ULC_NO_HEADER`` 0x800 No header in report mode.
``ULC_NO_SORT_HEADER`` 0x1000 No Docs.
``ULC_SINGLE_SEL`` 0x2000 Single selection (default is multiple).
``ULC_SORT_ASCENDING`` 0x4000 Sort in ascending order. (You must still supply a comparison callback in :meth:`ListCtrl.SortItems`.)
``ULC_SORT_DESCENDING`` 0x8000 Sort in descending order. (You must still supply a comparison callback in :meth:`ListCtrl.SortItems`.)
``ULC_TILE`` 0x10000 Each item appears as a full-sized icon with a label of one or more lines beside it (partially implemented).
``ULC_NO_HIGHLIGHT`` 0x20000 No highlight when an item is selected.
``ULC_STICKY_HIGHLIGHT`` 0x40000 Items are selected by simply hovering on them, with no need to click on them.
``ULC_STICKY_NOSELEVENT`` 0x80000 Don't send a selection event when using ``ULC_STICKY_HIGHLIGHT`` style.
``ULC_SEND_LEFTCLICK`` 0x100000 Send a left click event when an item is selected.
``ULC_HAS_VARIABLE_ROW_HEIGHT`` 0x200000 The list has variable row heights.
``ULC_AUTO_CHECK_CHILD`` 0x400000 When a column header has a checkbox associated, auto-check all the subitems in that column.
``ULC_AUTO_TOGGLE_CHILD`` 0x800000 When a column header has a checkbox associated, toggle all the subitems in that column.
``ULC_AUTO_CHECK_PARENT`` 0x1000000 Only meaningful foe checkbox-type items: when an item is checked/unchecked its column header item is checked/unchecked as well.
``ULC_SHOW_TOOLTIPS`` 0x2000000 Show tooltips for ellipsized items/subitems (text too long to be shown in the available space) containing the full item/subitem text.
``ULC_HOT_TRACKING`` 0x4000000 Enable hot tracking of items on mouse motion.
``ULC_BORDER_SELECT`` 0x8000000 Changes border colour when an item is selected, instead of highlighting the item.
``ULC_TRACK_SELECT`` 0x10000000 Enables hot-track selection in a list control. Hot track selection means that an item is automatically selected when the cursor remains over the item for a certain period of time. The delay is retrieved on Windows using the `win32api` call `win32gui.SystemParametersInfo(win32con.SPI_GETMOUSEHOVERTIME)`, and is defaulted to 400ms on other platforms. This style applies to all views of `UltimateListCtrl`.
``ULC_HEADER_IN_ALL_VIEWS`` 0x20000000 Show column headers in all view modes.
``ULC_NO_FULL_ROW_SELECT`` 0x40000000 When an item is selected, the only the item in the first column is highlighted.
``ULC_FOOTER`` 0x80000000 Show a footer too (only when header is present).
``ULC_USER_ROW_HEIGHT`` 0x100000000 Allows to set a custom row height (one value for all the items, only in report mode).
``ULC_NO_ITEM_DRAG`` 0x200000000 Disable item dragging
=============================== =========== ====================================================================================================
Events Processing
=================
This class processes the following events:
======================================== ====================================================================================================
Event Name Description
======================================== ====================================================================================================
``EVT_LIST_BEGIN_DRAG`` Begin dragging with the left mouse button.
``EVT_LIST_BEGIN_RDRAG`` Begin dragging with the right mouse button.
``EVT_LIST_BEGIN_LABEL_EDIT`` Begin editing a label. This can be prevented by calling `Veto()`.
``EVT_LIST_END_LABEL_EDIT`` Finish editing a label. This can be prevented by calling `Veto()`.
``EVT_LIST_DELETE_ITEM`` An item was deleted.
``EVT_LIST_DELETE_ALL_ITEMS`` All items were deleted.
``EVT_LIST_KEY_DOWN`` A key has been pressed.
``EVT_LIST_INSERT_ITEM`` An item has been inserted.
``EVT_LIST_COL_CLICK`` A column (`m_col`) has been left-clicked.
``EVT_LIST_COL_RIGHT_CLICK`` A column (`m_col`) has been right-clicked.
``EVT_LIST_COL_BEGIN_DRAG`` The user started resizing a column - can be vetoed.
``EVT_LIST_COL_END_DRAG`` The user finished resizing a column.
``EVT_LIST_COL_DRAGGING`` The divider between columns is being dragged.
``EVT_LIST_ITEM_SELECTED`` The item has been selected.
``EVT_LIST_ITEM_DESELECTED`` The item has been deselected.
``EVT_LIST_ITEM_RIGHT_CLICK`` The right mouse button has been clicked on an item.
``EVT_LIST_ITEM_MIDDLE_CLICK`` The middle mouse button has been clicked on an item.
``EVT_LIST_ITEM_ACTIVATED`` The item has been activated (``ENTER`` or double click).
``EVT_LIST_ITEM_FOCUSED`` The currently focused item has changed.
``EVT_LIST_CACHE_HINT`` Prepare cache for a virtual list control.
``EVT_LIST_ITEM_CHECKING`` An item/subitem is being checked.
``EVT_LIST_ITEM_CHECKED`` An item/subitem has been checked.
``EVT_LIST_COL_CHECKING`` A column header is being checked.
``EVT_LIST_COL_CHECKED`` A column header has being checked.
``EVT_LIST_FOOTER_CHECKING`` A column footer is being checked.
``EVT_LIST_FOOTER_CHECKED`` A column footer has being checked.
``EVT_LIST_ITEM_HYPERLINK`` An hyperlink item has been clicked.
``EVT_LIST_FOOTER_CLICK`` The user left-clicked on a column footer.
``EVT_LIST_FOOTER_RIGHT_CLICK`` The user right-clicked on a column footer.
``EVT_LIST_ITEM_LEFT_CLICK`` Send a left-click event after an item is selected.
``EVT_LIST_END_DRAG`` Notify an end-drag operation.
======================================== ====================================================================================================
Supported Platforms
===================
UltimateListCtrl has been tested on the following platforms:
* Windows (Windows XP);
License And Version
===================
UltimateListCtrl is distributed under the wxPython license.
Latest Revision: Andrea Gavana @ 27 Dec 2012, 21.00 GMT
Version 0.8
"""
import wx
import math
import bisect
import zlib
from functools import cmp_to_key
import six
from wx.lib.expando import ExpandoTextCtrl
# Version Info
__version__ = "0.8"
# wxPython version string
_VERSION_STRING = wx.VERSION_STRING
# ----------------------------------------------------------------------------
# UltimateListCtrl constants
# ----------------------------------------------------------------------------
# style flags
ULC_VRULES = wx.LC_VRULES
""" Draws light vertical rules between rows in report mode. """
ULC_HRULES = wx.LC_HRULES
""" Draws light horizontal rules between rows in report mode. """
ULC_ICON = wx.LC_ICON
ULC_SMALL_ICON = wx.LC_SMALL_ICON
ULC_LIST = wx.LC_LIST
ULC_REPORT = wx.LC_REPORT
ULC_TILE = 0x10000
ULC_ALIGN_TOP = wx.LC_ALIGN_TOP
ULC_ALIGN_LEFT = wx.LC_ALIGN_LEFT
ULC_AUTOARRANGE = wx.LC_AUTOARRANGE
ULC_VIRTUAL = wx.LC_VIRTUAL
ULC_EDIT_LABELS = wx.LC_EDIT_LABELS
ULC_NO_HEADER = wx.LC_NO_HEADER
ULC_NO_SORT_HEADER = wx.LC_NO_SORT_HEADER
ULC_SINGLE_SEL = wx.LC_SINGLE_SEL
ULC_SORT_ASCENDING = wx.LC_SORT_ASCENDING
ULC_SORT_DESCENDING = wx.LC_SORT_DESCENDING
ULC_NO_HIGHLIGHT = 0x20000
ULC_STICKY_HIGHLIGHT = 0x40000
ULC_STICKY_NOSELEVENT = 0x80000
ULC_SEND_LEFTCLICK = 0x100000
ULC_HAS_VARIABLE_ROW_HEIGHT = 0x200000
ULC_AUTO_CHECK_CHILD = 0x400000 # only meaningful for checkboxes
ULC_AUTO_TOGGLE_CHILD = 0x800000 # only meaningful for checkboxes
ULC_AUTO_CHECK_PARENT = 0x1000000 # only meaningful for checkboxes
ULC_SHOW_TOOLTIPS = 0x2000000 # shows tooltips on items with ellipsis (...)
ULC_HOT_TRACKING = 0x4000000 # enable hot tracking on mouse motion
ULC_BORDER_SELECT = 0x8000000 # changes border colour when an item is selected, instead of highlighting the item
ULC_TRACK_SELECT = 0x10000000 # Enables hot-track selection in a list control. Hot track selection means that an item
# is automatically selected when the cursor remains over the item for a certain period
# of time. The delay is retrieved on Windows using the win32api call
# win32gui.SystemParametersInfo(win32con.SPI_GETMOUSEHOVERTIME), and is defaulted to 400ms
# on other platforms. This style applies to all styles of UltimateListCtrl.
ULC_HEADER_IN_ALL_VIEWS = 0x20000000 # Show column headers in all view modes
ULC_NO_FULL_ROW_SELECT = 0x40000000 # When an item is selected, the only the item in the first column is highlighted
ULC_FOOTER = 0x80000000 # Show a footer too (only when header is present)
ULC_USER_ROW_HEIGHT = 0x100000000 # Allows to set a custom row height (one value for all the items, only in report mode).
ULC_NO_ITEM_DRAG = 0x200000000 # Disable item dragging
ULC_MASK_TYPE = ULC_ICON | ULC_SMALL_ICON | ULC_LIST | ULC_REPORT | ULC_TILE
ULC_MASK_ALIGN = ULC_ALIGN_TOP | ULC_ALIGN_LEFT
ULC_MASK_SORT = ULC_SORT_ASCENDING | ULC_SORT_DESCENDING
# for compatibility only
ULC_USER_TEXT = ULC_VIRTUAL
# Omitted because
# (a) too much detail
# (b) not enough style flags
# (c) not implemented anyhow in the generic version
#
# ULC_NO_SCROLL
# ULC_NO_LABEL_WRAP
# ULC_OWNERDRAW_FIXED
# ULC_SHOW_SEL_ALWAYS
# Mask flags to tell app/GUI what fields of UltimateListItem are valid
ULC_MASK_STATE = wx.LIST_MASK_STATE
ULC_MASK_TEXT = wx.LIST_MASK_TEXT
ULC_MASK_IMAGE = wx.LIST_MASK_IMAGE
ULC_MASK_DATA = wx.LIST_MASK_DATA
ULC_SET_ITEM = wx.LIST_SET_ITEM
ULC_MASK_WIDTH = wx.LIST_MASK_WIDTH
ULC_MASK_FORMAT = wx.LIST_MASK_FORMAT
ULC_MASK_FONTCOLOUR = 0x0080
ULC_MASK_FONT = 0x0100
ULC_MASK_BACKCOLOUR = 0x0200
ULC_MASK_KIND = 0x0400
ULC_MASK_ENABLE = 0x0800
ULC_MASK_CHECK = 0x1000
ULC_MASK_HYPERTEXT = 0x2000
ULC_MASK_WINDOW = 0x4000
ULC_MASK_PYDATA = 0x8000
ULC_MASK_SHOWN = 0x10000
ULC_MASK_RENDERER = 0x20000
ULC_MASK_OVERFLOW = 0x40000
ULC_MASK_FOOTER_TEXT = 0x80000
ULC_MASK_FOOTER_IMAGE = 0x100000
ULC_MASK_FOOTER_FORMAT = 0x200000
ULC_MASK_FOOTER_FONT = 0x400000
ULC_MASK_FOOTER_CHECK = 0x800000
ULC_MASK_FOOTER_KIND = 0x1000000
ULC_MASK_TOOLTIP = 0x2000000
# State flags for indicating the state of an item
ULC_STATE_DONTCARE = wx.LIST_STATE_DONTCARE
ULC_STATE_DROPHILITED = wx.LIST_STATE_DROPHILITED # MSW only
ULC_STATE_FOCUSED = wx.LIST_STATE_FOCUSED
ULC_STATE_SELECTED = wx.LIST_STATE_SELECTED
ULC_STATE_CUT = wx.LIST_STATE_CUT # MSW only
# Hit test flags, used in HitTest
ULC_HITTEST_ABOVE = wx.LIST_HITTEST_ABOVE # Above the client area.
ULC_HITTEST_BELOW = wx.LIST_HITTEST_BELOW # Below the client area.
ULC_HITTEST_NOWHERE = wx.LIST_HITTEST_NOWHERE # In the client area but below the last item.
ULC_HITTEST_ONITEMICON = wx.LIST_HITTEST_ONITEMICON # On the bitmap associated with an item.
ULC_HITTEST_ONITEMLABEL = wx.LIST_HITTEST_ONITEMLABEL # On the label (string) associated with an item.
ULC_HITTEST_ONITEMSTATEICON = wx.LIST_HITTEST_ONITEMSTATEICON # On the state icon for a tree view item that is in a user-defined state.
ULC_HITTEST_TOLEFT = wx.LIST_HITTEST_TOLEFT # To the left of the client area.
ULC_HITTEST_TORIGHT = wx.LIST_HITTEST_TORIGHT # To the right of the client area.
ULC_HITTEST_ONITEMCHECK = 0x1000 # On the checkbox (if any)
ULC_HITTEST_ONITEM = ULC_HITTEST_ONITEMICON | ULC_HITTEST_ONITEMLABEL | ULC_HITTEST_ONITEMSTATEICON | ULC_HITTEST_ONITEMCHECK
# Flags for GetNextItem (MSW only except ULC_NEXT_ALL)
ULC_NEXT_ABOVE = wx.LIST_NEXT_ABOVE # Searches for an item above the specified item
ULC_NEXT_ALL = wx.LIST_NEXT_ALL # Searches for subsequent item by index
ULC_NEXT_BELOW = wx.LIST_NEXT_BELOW # Searches for an item below the specified item
ULC_NEXT_LEFT = wx.LIST_NEXT_LEFT # Searches for an item to the left of the specified item
ULC_NEXT_RIGHT = wx.LIST_NEXT_RIGHT # Searches for an item to the right of the specified item
# Alignment flags for Arrange (MSW only except ULC_ALIGN_LEFT)
ULC_ALIGN_DEFAULT = wx.LIST_ALIGN_DEFAULT
ULC_ALIGN_SNAP_TO_GRID = wx.LIST_ALIGN_SNAP_TO_GRID
# Column format (MSW only except ULC_FORMAT_LEFT)
ULC_FORMAT_LEFT = wx.LIST_FORMAT_LEFT
ULC_FORMAT_RIGHT = wx.LIST_FORMAT_RIGHT
ULC_FORMAT_CENTRE = wx.LIST_FORMAT_CENTRE
ULC_FORMAT_CENTER = ULC_FORMAT_CENTRE
# Autosize values for SetColumnWidth
ULC_AUTOSIZE = wx.LIST_AUTOSIZE
ULC_AUTOSIZE_USEHEADER = wx.LIST_AUTOSIZE_USEHEADER # partly supported by generic version
ULC_AUTOSIZE_FILL = -3
# Flag values for GetItemRect
ULC_RECT_BOUNDS = wx.LIST_RECT_BOUNDS
ULC_RECT_ICON = wx.LIST_RECT_ICON
ULC_RECT_LABEL = wx.LIST_RECT_LABEL
# Flag values for FindItem (MSW only)
ULC_FIND_UP = wx.LIST_FIND_UP
ULC_FIND_DOWN = wx.LIST_FIND_DOWN
ULC_FIND_LEFT = wx.LIST_FIND_LEFT
ULC_FIND_RIGHT = wx.LIST_FIND_RIGHT
# Items/subitems rect
ULC_GETSUBITEMRECT_WHOLEITEM = wx.LIST_GETSUBITEMRECT_WHOLEITEM
# ----------------------------------------------------------------------------
# UltimateListCtrl event macros
# ----------------------------------------------------------------------------
wxEVT_COMMAND_LIST_BEGIN_DRAG = wx.wxEVT_COMMAND_LIST_BEGIN_DRAG
wxEVT_COMMAND_LIST_BEGIN_RDRAG = wx.wxEVT_COMMAND_LIST_BEGIN_RDRAG
wxEVT_COMMAND_LIST_BEGIN_LABEL_EDIT = wx.wxEVT_COMMAND_LIST_BEGIN_LABEL_EDIT
wxEVT_COMMAND_LIST_END_LABEL_EDIT = wx.wxEVT_COMMAND_LIST_END_LABEL_EDIT
wxEVT_COMMAND_LIST_DELETE_ITEM = wx.wxEVT_COMMAND_LIST_DELETE_ITEM
wxEVT_COMMAND_LIST_DELETE_ALL_ITEMS = wx.wxEVT_COMMAND_LIST_DELETE_ALL_ITEMS
wxEVT_COMMAND_LIST_ITEM_SELECTED = wx.wxEVT_COMMAND_LIST_ITEM_SELECTED
wxEVT_COMMAND_LIST_ITEM_DESELECTED = wx.wxEVT_COMMAND_LIST_ITEM_DESELECTED
wxEVT_COMMAND_LIST_KEY_DOWN = wx.wxEVT_COMMAND_LIST_KEY_DOWN
wxEVT_COMMAND_LIST_INSERT_ITEM = wx.wxEVT_COMMAND_LIST_INSERT_ITEM
wxEVT_COMMAND_LIST_COL_CLICK = wx.wxEVT_COMMAND_LIST_COL_CLICK
wxEVT_COMMAND_LIST_ITEM_RIGHT_CLICK = wx.wxEVT_COMMAND_LIST_ITEM_RIGHT_CLICK
wxEVT_COMMAND_LIST_ITEM_MIDDLE_CLICK = wx.wxEVT_COMMAND_LIST_ITEM_MIDDLE_CLICK
wxEVT_COMMAND_LIST_ITEM_ACTIVATED = wx.wxEVT_COMMAND_LIST_ITEM_ACTIVATED
wxEVT_COMMAND_LIST_CACHE_HINT = wx.wxEVT_COMMAND_LIST_CACHE_HINT
wxEVT_COMMAND_LIST_COL_RIGHT_CLICK = wx.wxEVT_COMMAND_LIST_COL_RIGHT_CLICK
wxEVT_COMMAND_LIST_COL_BEGIN_DRAG = wx.wxEVT_COMMAND_LIST_COL_BEGIN_DRAG
wxEVT_COMMAND_LIST_COL_DRAGGING = wx.wxEVT_COMMAND_LIST_COL_DRAGGING
wxEVT_COMMAND_LIST_COL_END_DRAG = wx.wxEVT_COMMAND_LIST_COL_END_DRAG
wxEVT_COMMAND_LIST_ITEM_FOCUSED = wx.wxEVT_COMMAND_LIST_ITEM_FOCUSED
wxEVT_COMMAND_LIST_FOOTER_CLICK = wx.NewEventType()
wxEVT_COMMAND_LIST_FOOTER_RIGHT_CLICK = wx.NewEventType()
wxEVT_COMMAND_LIST_FOOTER_CHECKING = wx.NewEventType()
wxEVT_COMMAND_LIST_FOOTER_CHECKED = wx.NewEventType()
wxEVT_COMMAND_LIST_ITEM_LEFT_CLICK = wx.NewEventType()
wxEVT_COMMAND_LIST_ITEM_CHECKING = wx.NewEventType()
wxEVT_COMMAND_LIST_ITEM_CHECKED = wx.NewEventType()
wxEVT_COMMAND_LIST_ITEM_HYPERLINK = wx.NewEventType()
wxEVT_COMMAND_LIST_END_DRAG = wx.NewEventType()
wxEVT_COMMAND_LIST_COL_CHECKING = wx.NewEventType()
wxEVT_COMMAND_LIST_COL_CHECKED = wx.NewEventType()
EVT_LIST_BEGIN_DRAG = wx.EVT_LIST_BEGIN_DRAG
EVT_LIST_BEGIN_RDRAG = wx.EVT_LIST_BEGIN_RDRAG
EVT_LIST_BEGIN_LABEL_EDIT = wx.EVT_LIST_BEGIN_LABEL_EDIT
EVT_LIST_END_LABEL_EDIT = wx.EVT_LIST_END_LABEL_EDIT
EVT_LIST_DELETE_ITEM = wx.EVT_LIST_DELETE_ITEM
EVT_LIST_DELETE_ALL_ITEMS = wx.EVT_LIST_DELETE_ALL_ITEMS
EVT_LIST_KEY_DOWN = wx.EVT_LIST_KEY_DOWN
EVT_LIST_INSERT_ITEM = wx.EVT_LIST_INSERT_ITEM
EVT_LIST_COL_CLICK = wx.EVT_LIST_COL_CLICK
EVT_LIST_COL_RIGHT_CLICK = wx.EVT_LIST_COL_RIGHT_CLICK
EVT_LIST_COL_BEGIN_DRAG = wx.EVT_LIST_COL_BEGIN_DRAG
EVT_LIST_COL_END_DRAG = wx.EVT_LIST_COL_END_DRAG
EVT_LIST_COL_DRAGGING = wx.EVT_LIST_COL_DRAGGING
EVT_LIST_ITEM_SELECTED = wx.EVT_LIST_ITEM_SELECTED
EVT_LIST_ITEM_DESELECTED = wx.EVT_LIST_ITEM_DESELECTED
EVT_LIST_ITEM_RIGHT_CLICK = wx.EVT_LIST_ITEM_RIGHT_CLICK
EVT_LIST_ITEM_MIDDLE_CLICK = wx.EVT_LIST_ITEM_MIDDLE_CLICK
EVT_LIST_ITEM_ACTIVATED = wx.EVT_LIST_ITEM_ACTIVATED
EVT_LIST_ITEM_FOCUSED = wx.EVT_LIST_ITEM_FOCUSED
EVT_LIST_CACHE_HINT = wx.EVT_LIST_CACHE_HINT
EVT_LIST_ITEM_LEFT_CLICK = wx.PyEventBinder(wxEVT_COMMAND_LIST_ITEM_LEFT_CLICK, 1)
EVT_LIST_ITEM_CHECKING = wx.PyEventBinder(wxEVT_COMMAND_LIST_ITEM_CHECKING, 1)
EVT_LIST_ITEM_CHECKED = wx.PyEventBinder(wxEVT_COMMAND_LIST_ITEM_CHECKED, 1)
EVT_LIST_ITEM_HYPERLINK = wx.PyEventBinder(wxEVT_COMMAND_LIST_ITEM_HYPERLINK, 1)
EVT_LIST_END_DRAG = wx.PyEventBinder(wxEVT_COMMAND_LIST_END_DRAG, 1)
EVT_LIST_COL_CHECKING = wx.PyEventBinder(wxEVT_COMMAND_LIST_COL_CHECKING, 1)
EVT_LIST_COL_CHECKED = wx.PyEventBinder(wxEVT_COMMAND_LIST_COL_CHECKED, 1)
EVT_LIST_FOOTER_CLICK = wx.PyEventBinder(wxEVT_COMMAND_LIST_FOOTER_CLICK, 1)
EVT_LIST_FOOTER_RIGHT_CLICK = wx.PyEventBinder(wxEVT_COMMAND_LIST_FOOTER_RIGHT_CLICK, 1)
EVT_LIST_FOOTER_CHECKING = wx.PyEventBinder(wxEVT_COMMAND_LIST_FOOTER_CHECKING, 1)
EVT_LIST_FOOTER_CHECKED = wx.PyEventBinder(wxEVT_COMMAND_LIST_FOOTER_CHECKED, 1)
# NOTE: If using the wxExtListBox visual attributes works everywhere then this can
# be removed, as well as the #else case below.
_USE_VISATTR = 0
# ----------------------------------------------------------------------------
# Constants
# ----------------------------------------------------------------------------
SCROLL_UNIT_X = 15
SCROLL_UNIT_Y = 15
# the spacing between the lines (in report mode)
LINE_SPACING = 0
# extra margins around the text label
EXTRA_WIDTH = 4
EXTRA_HEIGHT = 4
if wx.Platform == "__WXGTK__":
EXTRA_HEIGHT = 6
# margin between the window and the items
EXTRA_BORDER_X = 2
EXTRA_BORDER_Y = 2
# offset for the header window
HEADER_OFFSET_X = 1
HEADER_OFFSET_Y = 1
# margin between rows of icons in [small] icon view
MARGIN_BETWEEN_ROWS = 6
# when autosizing the columns, add some slack
AUTOSIZE_COL_MARGIN = 10
# default and minimal widths for the header columns
WIDTH_COL_DEFAULT = 80
WIDTH_COL_MIN = 10
# the space between the image and the text in the report mode
IMAGE_MARGIN_IN_REPORT_MODE = 5
# the space between the image and the text in the report mode in header
HEADER_IMAGE_MARGIN_IN_REPORT_MODE = 2
# and the width of the icon, if any
MARGIN_BETWEEN_TEXT_AND_ICON = 2
# 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)
# Mouse hover time for track selection
HOVER_TIME = 400
if wx.Platform == "__WXMSW__":
try:
import win32gui, win32con
HOVER_TIME = win32gui.SystemParametersInfo(win32con.SPI_GETMOUSEHOVERTIME)
except ImportError:
pass
# For PyImageList
IL_FIXED_SIZE = 0
IL_VARIABLE_SIZE = 1
# Python integers, to make long types to work with CreateListItem
INTEGER_TYPES = six.integer_types
# ----------------------------------------------------------------------------
# Functions
# ----------------------------------------------------------------------------
# Utility method
def to_list(input):
"""
Converts the input data into a Python list.
:param `input`: can be an integer or a Python list (in which case nothing will
be done to `input`.
"""
if isinstance(input, list):
return input
elif isinstance(input, INTEGER_TYPES):
return [input]
else:
raise Exception("Invalid parameter passed to `to_list`: only integers and list are accepted.")
def CheckVariableRowHeight(listCtrl, text):
"""
Checks whether a `text` contains multiline strings and if the `listCtrl` window
style is compatible with multiline strings.
:param `listCtrl`: an instance of :class:`UltimateListCtrl`;
:param `text`: the text to analyze.
"""
if not listCtrl.HasAGWFlag(ULC_HAS_VARIABLE_ROW_HEIGHT):
if "\n" in text:
raise Exception("Multiline text items are not allowed without the ULC_HAS_VARIABLE_ROW_HEIGHT style.")
def CreateListItem(itemOrId, col):
"""
Creates a new instance of :class:`UltimateListItem`.
:param `itemOrId`: can be an instance of :class:`UltimateListItem` or an integer;
:param `col`: the item column.
"""
if type(itemOrId) in INTEGER_TYPES:
item = UltimateListItem()
item._itemId = itemOrId
item._col = col
else:
item = itemOrId
return item
# ----------------------------------------------------------------------------
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.
"""
img = original.ConvertToImage()
return wx.Bitmap(img.ConvertToGreyscale())
# ----------------------------------------------------------------------------
#----------------------------------------------------------------------
def GetdragcursorData():
""" Returns the drag and drop cursor image as a decompressed stream of characters. """
return zlib.decompress(
b"x\xda\xeb\x0c\xf0s\xe7\xe5\x92\xe2b``\xe0\xf5\xf4p\t\x02\xd2\xa2@,\xcf\xc1\
\x06$9z\xda>\x00)\xce\x02\x8f\xc8b\x06\x06na\x10fd\x985G\x02(\xd8W\xe2\x1aQ\
\xe2\x9c\x9f\x9b\x9b\x9aW\xc2\x90\xec\x11\xe4\xab\x90\x9cQ\x9a\x97\x9d\x93\
\x9a\xa7`l\xa4\x90\x99\x9e\x97_\x94\x9a\xc2\xeb\x18\xec\xec\xe9i\xa5\xa0\xa7\
W\xa5\xaa\x07\x01P:7\x1eH\xe4\xe8\xe9\xd9\x808\x11\xbc\x1e\xae\x11V\n\x06@`\
\xeehd\n\xa2-\x0c,\x8cA\xb4\x9b\t\x94o\xe2b\x08\xa2\xcd\\L\xdd@\xb4\xab\x85\
\x993\x886v\xb6p\x02\xd1\x86N\xa6\x16\x12\xf7~\xdf\x05\xbal\xa9\xa7\x8bcH\
\xc5\x9c3W9\xb9\x1a\x14\x04X/\xec\xfc\xbft\xed\x02\xa5\xf4\xc2m\xfa*<N\x17??\
\x0frqy\x9c\xd3\xb2f5\xaf\x89\x8f9Gk\xbc\x08\xa7\xbf\x06\x97\x98\x06S\xd8E\
\xbd\x9cE\xb2\x15\x9da\x89\xe2k\x0f\x9c\xb6|\x1a\xea\x14X\x1d6G\x83E\xe7\x9c\
\x1dO\xa8\xde\xb6\x84l\x15\x9eS\xcf\xc2tf\x15\xde\xf7\xb5\xb2]\xf0\x96+\xf5@\
D\x90\x1d\xef19_\xf5\xde5y\xb6+\xa7\xdeZ\xfbA\x9bu\x9f`\xffD\xafYn\xf6\x9eW\
\xeb>\xb6\x7f\x98\\U\xcb\xf5\xd5\xcb\x9a'\xe7\xf4\xd7\x0b\xba\x9e\xdb\x17E\
\xfdf\x97Z\xcb\xcc\xc0\xf0\xff?3\xc3\x92\xabN\x8arB\xc7\x8f\x03\x1d\xcc\xe0\
\xe9\xea\xe7\xb2\xce)\xa1\t\x00B7|\x00" )
def GetdragcursorBitmap():
""" Returns the drag and drop cursor image as a :class:`wx.Bitmap`. """
return wx.Bitmap(GetdragcursorImage())
def GetdragcursorImage():
""" Returns the drag and drop cursor image as a :class:`wx.Image`. """
stream = six.BytesIO(GetdragcursorData())
return wx.Image(stream)
#-----------------------------------------------------------------------------
# PyImageList
#-----------------------------------------------------------------------------
class PyImageList(object):
"""
A :class:`PyImageList` contains a list of images. Images can have masks for
transparent drawing, and can be made from a variety of sources including
bitmaps and icons.
:class:`PyImageList` is used in conjunction with :class:`UltimateListCtrl`.
:note: The main improvements that :class:`PyImageList` introduces is the removal
of the limitation of same-size images inside the image list. If you use
the style ``IL_VARIABLE_SIZE`` then each image can have any size (in terms
of width and height).
"""
def __init__(self, width, height, mask=True, initialCount=1, style=IL_VARIABLE_SIZE):
"""
Default class constructor.
:param `width`: the width of the images in the image list, in pixels (unused
if you specify the ``IL_VARIABLE_SIZE`` style;
:param `height`: the height of the images in the image list, in pixels (unused
if you specify the ``IL_VARIABLE_SIZE`` style;
:param `mask`: ``True`` if masks should be created for all images (unused in
:class:`PyImageList`);
:param `initialCount`: the initial size of the list (unused in :class:`PyImageList`);
:param `style`: can be one of the following bits:
==================== ===== =================================
Style Flag Value Description
==================== ===== =================================
``IL_FIXED_SIZE`` 0 All the images in :class:`PyImageList` have the same size (width, height)
``IL_VARIABLE_SIZE`` 1 Each image can have any size (in terms of width and height)
==================== ===== =================================
"""
self._width = width
self._height = height
self._mask = mask
self._initialCount = 1
self._style = style
self._images = []
def GetImageCount(self):
""" Returns the number of images in the list. """
return len(self._images)
def Add(self, bitmap):
"""
Adds a new image or images using a bitmap.
:param `bitmap`: a valid :class:`wx.Bitmap` object.
:return: The new zero-based image index.
:note: If the bitmap is wider than the images in the list and you are not using
the ``IL_VARIABLE_SIZE`` style, then the bitmap will automatically be split
into smaller images, each matching the dimensions of the image list.
"""
index = len(self._images)
# Mimic behavior of Windows ImageList_Add that automatically breaks up the added
# bitmap into sub-images of the correct size
if self._style & IL_FIXED_SIZE:
if self._width > 0 and bitmap.GetWidth() > self._width and \
bitmap.GetHeight() >= self._height:
numImages = bitmap.GetWidth()/self._width
for subIndex in range(numImages):
rect = wx.Rect(self._width * subIndex, 0, self._width, self._height)
tmpBmp = bitmap.GetSubBitmap(rect)
self._images.append(tmpBmp)
else:
self._images.append(bitmap)
else:
self._images.append(bitmap)
if self._width == 0 and self._height == 0:
self._width = bitmap.GetWidth()
self._height = bitmap.GetHeight()
return index
def AddIcon(self, icon):
"""
Adds a new image using an icon.
:param `icon`: a valid :class:`Icon` object.
:return: The new zero-based image index.
:note: If the icon is wider than the images in the list and you are not using
the ``IL_VARIABLE_SIZE`` style, then the icon will automatically be split
into smaller images, each matching the dimensions of the image list.
"""
return self.Add(wx.Bitmap(icon))
def AddWithColourMask(self, bitmap, maskColour):
"""
Adds a new image or images using a bitmap and a colour mask.
:param `bitmap`: a valid :class:`wx.Bitmap` object;
:param `colour`: an instance of :class:`wx.Colour`, a colour indicating which parts
of the image are transparent.
:return: The new zero-based image index.
:note: If the bitmap is wider than the images in the list and you are not using
the ``IL_VARIABLE_SIZE`` style, then the bitmap will automatically be split
into smaller images, each matching the dimensions of the image list.
"""
img = bitmap.ConvertToImage()
img.SetMaskColour(maskColour.Red(), maskColour.Green(), maskColour.Blue())
return self.Add(wx.Bitmap(img))
def GetBitmap(self, index):
"""
Returns the bitmap corresponding to the given `index`, or :class:`NullBitmap`
if the index is invalid.
:param `index`: the bitmap index.
"""
if index >= len(self._images):
return wx.NullBitmap
return self._images[index]
def GetIcon(self, index):
"""
Returns the icon corresponding to the given `index`, or :class:`NullIcon`
if the index is invalid.
:param `index`: the icon index.
"""
if index >= len(self._images):
return wx.NullIcon
icon = wx.Icon()
icon.CopyFromBitmap(self.GetBitmap(index))
return icon
def Replace(self, index, bitmap):
"""
Replaces the existing image with the new bitmap.
:param `index`: the index at which the image should be replaced;
:param `bitmap`: the new bitmap to add to the image list, an instance of
:class:`wx.Bitmap`.
"""
if index >= len(self._images):
raise Exception("Wrong index in image list")
self._images[index] = bitmap
return True
def ReplaceIcon(self, index, icon):
"""
Replaces the existing image with the new icon.
:param `index`: the index at which the image should be replaced;
:param `icon`: the new icon to add to the image list, an instance of
:class:`Icon`.
"""
return self.Replace(index, wx.Bitmap(icon))
def Remove(self, index):
"""
Removes the image at the given position.
:param `index`: the zero-based index of the image to be removed.
"""
if index >= len(self._images):
raise Exception("Wrong index in image list")
self._images.pop(index)
return True
def RemoveAll(self):
""" Removes all the images in the list. """
self._images = []
return True
def GetSize(self, index):
"""
Retrieves the size of an image in the list.
:param `index`: the zero-based index of the image.
:return: a tuple of `(width, height)` properties of the chosen bitmap.
"""
if index >= len(self._images):
raise Exception("Wrong index in image list")
bmp = self._images[index]
return bmp.GetWidth(), bmp.GetHeight()
def Draw(self, index, dc, x, y, flags, solidBackground=True):
"""
Draws a specified image onto a device context.
:param `index`: the image index, starting from zero;
:param `dc`: an instance of :class:`wx.DC`;
:param `x`: x position on the device context;
:param `y`: y position on the device context;
:param `flags`: how to draw the image. A bitlist of a selection of the following:
================================= =======================================
Flag Paarameter Description
================================= =======================================
``wx.IMAGELIST_DRAW_NORMAL`` Draw the image normally
``wx.IMAGELIST_DRAW_TRANSPARENT`` Draw the image with transparency
``wx.IMAGELIST_DRAW_SELECTED`` Draw the image in selected state
``wx.IMAGELIST_DRAW_FOCUSED`` Draw the image in a focused state
================================= =======================================
:param `solidBackground`: currently unused.
"""
if index >= len(self._images):
raise Exception("Wrong index in image list")
bmp = self._images[index]
dc.DrawBitmap(bmp, x, int(y), (flags & wx.IMAGELIST_DRAW_TRANSPARENT) > 0)
return True
class SelectionStore(object):
"""
SelectionStore is used to store the selected items in the virtual
controls, i.e. it is well suited for storing even when the control contains
a huge (practically infinite) number of items.
Of course, internally it still has to store the selected items somehow (as
an array currently) but the advantage is that it can handle the selection
of all items (common operation) efficiently and that it could be made even
smarter in the future (e.g. store the selections as an array of ranges +
individual items) without changing its API.
"""
def __init__(self):
""" Default class constructor. """
# the array of items whose selection state is different from default
self._itemsSel = []
# the default state: normally, False (i.e. off) but maybe set to true if
# there are more selected items than non selected ones - this allows to
# handle selection of all items efficiently
self._defaultState = False
# the total number of items we handle
self._count = 0
# special case of SetItemCount(0)
def Clear(self):
""" Clears the number of selected items. """
self._itemsSel = []
self._count = 0
self._defaultState = False
# return the total number of selected items
def GetSelectedCount(self):
""" Return the total number of selected items. """
return (self._defaultState and [self._count - len(self._itemsSel)] or [len(self._itemsSel)])[0]
def IsSelected(self, item):
"""
Returns ``True`` if the given item is selected.
:param `item`: the item to check for selection state.
"""
isSel = item in self._itemsSel
# if the default state is to be selected, being in m_itemsSel means that
# the item is not selected, so we have to inverse the logic
return (self._defaultState and [not isSel] or [isSel])[0]
def SelectItem(self, item, select=True):
"""
Selects the given item.
:param `item`: the item to select;
:param `select`: ``True`` to select the item, ``False`` otherwise.
:return: ``True`` if the items selection really changed.
"""
# search for the item ourselves as like this we get the index where to
# insert it later if needed, so we do only one search in the array instead
# of two (adding item to a sorted array requires a search)
index = bisect.bisect_right(self._itemsSel, item)
isSel = index < len(self._itemsSel) and self._itemsSel[index] == item
if select != self._defaultState:
if item not in self._itemsSel:
bisect.insort_right(self._itemsSel, item)
return True
else: # reset to default state
if item in self._itemsSel: