1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24 """The molecule, residue, and spin tree view GUI elements."""
25
26
27
28 import wx
29
30
31 from generic_fns.selection import is_mol_selected, is_res_selected, is_spin_selected
32 from generic_fns.mol_res_spin import get_molecule_ids, get_residue_ids, get_spin_ids, molecule_loop, residue_loop, spin_loop
33 from generic_fns.pipes import get_pipe
34 from status import Status; status = Status()
35
36
37 from gui import paths
38 from gui.components.menu import build_menu_item
39 from gui.message import Question
40 from gui.misc import gui_to_str
41 from gui.user_functions import User_functions
42
43
45 """The tree view class."""
46
47
48 MENU_ROOT_MOLECULE_CREATE = wx.NewId()
49 MENU_ROOT_LOAD_SPINS = wx.NewId()
50 MENU_SPIN_SPIN_DELETE = wx.NewId()
51 MENU_SPIN_SPIN_SELECT = wx.NewId()
52 MENU_SPIN_SPIN_DESELECT = wx.NewId()
53 MENU_RESIDUE_SPIN_ADD = wx.NewId()
54 MENU_RESIDUE_RESIDUE_DELETE = wx.NewId()
55 MENU_RESIDUE_RESIDUE_SELECT = wx.NewId()
56 MENU_RESIDUE_RESIDUE_DESELECT = wx.NewId()
57 MENU_MOLECULE_RESIDUE_CREATE = wx.NewId()
58 MENU_MOLECULE_MOLECULE_DELETE = wx.NewId()
59 MENU_MOLECULE_MOLECULE_DESELECT = wx.NewId()
60 MENU_MOLECULE_MOLECULE_SELECT = wx.NewId()
61
62 - def __init__(self, gui, parent=None, id=None):
63 """Set up the tree GUI element.
64
65 @param gui: The gui object.
66 @type gui: wx object
67 @keyword parent: The parent GUI element that this is to be attached to.
68 @type parent: wx object
69 @keyword id: The ID number.
70 @type id: int
71 """
72
73
74 self.gui = gui
75 self.parent = parent
76
77
78 wx.Window.__init__(self, parent, id, style=wx.WANTS_CHARS)
79
80
81 self.icon_size = 22
82
83
84 self.tree = wx.TreeCtrl(parent=self, id=-1, pos=wx.DefaultPosition, size=wx.DefaultSize, style=wx.TR_DEFAULT_STYLE)
85
86
87 self.tree_ids = {}
88
89
90 self.Bind(wx.EVT_SIZE, self._resize)
91
92
93 self.root = self.tree.AddRoot("Spin system information")
94 self.tree.SetPyData(self.root, "root")
95
96
97 icon_list = wx.ImageList(self.icon_size, self.icon_size)
98
99
100 self.icon_mol_index = icon_list.Add(wx.Bitmap(paths.icon_22x22.molecule, wx.BITMAP_TYPE_ANY))
101 self.icon_mol_unfold_index = icon_list.Add(wx.Bitmap(paths.icon_22x22.molecule_unfolded, wx.BITMAP_TYPE_ANY))
102 self.icon_res_index = icon_list.Add(wx.Bitmap(paths.icon_22x22.residue, wx.BITMAP_TYPE_ANY))
103 self.icon_spin_index = icon_list.Add(wx.Bitmap(paths.icon_22x22.spin, wx.BITMAP_TYPE_ANY))
104
105
106 self.icon_mol_index_desel = icon_list.Add(wx.Bitmap(paths.icon_22x22.molecule_grey, wx.BITMAP_TYPE_ANY))
107 self.icon_mol_unfold_index_desel = icon_list.Add(wx.Bitmap(paths.icon_22x22.molecule_unfolded_grey, wx.BITMAP_TYPE_ANY))
108 self.icon_res_index_desel = icon_list.Add(wx.Bitmap(paths.icon_22x22.residue_grey, wx.BITMAP_TYPE_ANY))
109 self.icon_spin_index_desel = icon_list.Add(wx.Bitmap(paths.icon_22x22.spin_grey, wx.BITMAP_TYPE_ANY))
110
111
112 self.tree.SetImageList(icon_list)
113
114
115 self.icon_list = icon_list
116
117
118 self.update()
119
120
121 self.tree.Bind(wx.EVT_TREE_SEL_CHANGED, self._selection)
122 self.tree.Bind(wx.EVT_RIGHT_DOWN, self._right_click)
123
124
126 """Resize the tree element.
127
128 @param event: The wx event.
129 @type event: wx event
130 """
131
132
133 width, height = self.GetClientSizeTuple()
134
135
136 self.tree.SetDimensions(0, 0, width, height)
137
138
140 """Handle right clicks in the tree.
141
142 @param event: The wx event.
143 @type event: wx event
144 """
145
146
147 pos = event.GetPosition()
148
149
150 item, flags = self.tree.HitTest(pos)
151
152
153 if not item.IsOk():
154 self.info = None
155 else:
156 self.info = self.tree.GetItemPyData(item)
157
158
159 if self.info == None:
160 self.menu_default()
161
162
163 elif self.info == 'root':
164 self.menu_root()
165
166
167 elif self.info['type'] == 'mol':
168 self.menu_molecule()
169
170
171 elif self.info['type'] == 'res':
172 self.menu_residue()
173
174
175 elif self.info['type'] == 'spin':
176 self.menu_spin()
177
178
180 """Handle changes in selection in the tree.
181
182 @param event: The wx event.
183 @type event: wx event
184 """
185
186
187 item = event.GetItem()
188
189
190 info = self.tree.GetItemPyData(item)
191
192
193 self.gui.spin_viewer.container.display(info)
194
195
208
209
222
223
236
237
239 """Wrapper method.
240
241 @param event: The wx event.
242 @type event: wx event
243 """
244
245
246 msg = "Are you sure you would like to delete this molecule? This only affects the spin data, all structural data will remain. This operation cannot be undone."
247 if status.show_gui and Question(msg, parent=self.gui.spin_viewer, default=False, size=(400, 170)).ShowModal() == wx.ID_NO:
248 return
249
250
251 self.gui.interpreter.queue('molecule.delete', gui_to_str(self.info['id']))
252
253
254 status.observers.gui_uf.notify()
255
256
258 """Wrapper method.
259
260 @param event: The wx event.
261 @type event: wx event
262 """
263
264
265 msg = "Are you sure you would like to delete this residue? This only affects the spin data, all structural data will remain. This operation cannot be undone."
266 if status.show_gui and Question(msg, parent=self.gui.spin_viewer, default=False, size=(400, 170)).ShowModal() == wx.ID_NO:
267 return
268
269
270 self.gui.interpreter.queue('residue.delete', gui_to_str(self.info['id']))
271
272
273 status.observers.gui_uf.notify()
274
275
277 """Wrapper method.
278
279 @param event: The wx event.
280 @type event: wx event
281 """
282
283
284 msg = "Are you sure you would like to delete this spin? This only affects the spin data, all structural data will remain. This operation cannot be undone."
285 if status.show_gui and Question(msg, parent=self.gui.spin_viewer, default=False, size=(400, 170)).ShowModal() == wx.ID_NO:
286 return
287
288
289 self.gui.interpreter.queue('spin.delete', gui_to_str(self.info['id']))
290
291
292 status.observers.gui_uf.notify()
293
294
296 """Wrapper method.
297
298 @param event: The wx event.
299 @type event: wx event
300 """
301
302
303 msg = "Are you sure you would like to deselect all spins of this molecule?"
304 if status.show_gui and Question(msg, parent=self.gui.spin_viewer, default=False).ShowModal() == wx.ID_NO:
305 return
306
307
308 self.gui.interpreter.queue('deselect.spin', spin_id=gui_to_str(self.info['id']), change_all=False)
309
310
311 status.observers.gui_uf.notify()
312
313
315 """Wrapper method.
316
317 @param event: The wx event.
318 @type event: wx event
319 """
320
321
322 msg = "Are you sure you would like to deselect all spins of this residue?"
323 if status.show_gui and Question(msg, parent=self.gui.spin_viewer, default=False).ShowModal() == wx.ID_NO:
324 return
325
326
327 self.gui.interpreter.queue('deselect.spin', spin_id=gui_to_str(self.info['id']), change_all=False)
328
329
330 status.observers.gui_uf.notify()
331
332
334 """Wrapper method.
335
336 @param event: The wx event.
337 @type event: wx event
338 """
339
340
341 self.gui.interpreter.queue('deselect.spin', spin_id=gui_to_str(self.info['id']), change_all=False)
342
343
344 status.observers.gui_uf.notify()
345
346
348 """Get the python data structure associated with the current item.
349
350 @return: The dictionary of data.
351 @rtype: dict
352 """
353
354
355 item = self.tree.GetSelection()
356
357
358 if not item.IsOk():
359 return
360
361
362 return self.tree.GetItemPyData(item)
363
364
384
385
387 """The right click molecule menu."""
388
389
390 menu = wx.Menu()
391 item = build_menu_item(menu, id=self.MENU_MOLECULE_RESIDUE_CREATE, text="Add residue", icon=paths.icon_16x16.add)
392 menu.AppendItem(item)
393 if status.exec_lock.locked():
394 item.Enable(False)
395 item = build_menu_item(menu, id=self.MENU_MOLECULE_MOLECULE_DELETE, text="Delete molecule", icon=paths.icon_16x16.remove)
396 menu.AppendItem(item)
397 if status.exec_lock.locked():
398 item.Enable(False)
399
400
401 if self.info['select']:
402 item = build_menu_item(menu, id=self.MENU_MOLECULE_MOLECULE_DESELECT, text="Deselect")
403 menu.AppendItem(item)
404 if status.exec_lock.locked():
405 item.Enable(False)
406 else:
407 item = build_menu_item(menu, id=self.MENU_MOLECULE_MOLECULE_SELECT, text="Select")
408 menu.AppendItem(item)
409 if status.exec_lock.locked():
410 item.Enable(False)
411
412
413 self.Bind(wx.EVT_MENU, self.create_residue, id=self.MENU_MOLECULE_RESIDUE_CREATE)
414 self.Bind(wx.EVT_MENU, self.delete_molecule, id=self.MENU_MOLECULE_MOLECULE_DELETE)
415 if self.info['select']:
416 self.Bind(wx.EVT_MENU, self.deselect_molecule, id=self.MENU_MOLECULE_MOLECULE_DESELECT)
417 else:
418 self.Bind(wx.EVT_MENU, self.select_molecule, id=self.MENU_MOLECULE_MOLECULE_SELECT)
419
420
421 if status.show_gui:
422 self.PopupMenu(menu)
423 menu.Destroy()
424
425
427 """The right click molecule menu."""
428
429
430 menu = wx.Menu()
431 item = build_menu_item(menu, id=self.MENU_RESIDUE_SPIN_ADD, text="Add spin", icon=paths.icon_16x16.add)
432 menu.AppendItem(item)
433 if status.exec_lock.locked():
434 item.Enable(False)
435 item = build_menu_item(menu, id=self.MENU_RESIDUE_RESIDUE_DELETE, text="Delete residue", icon=paths.icon_16x16.remove)
436 menu.AppendItem(item)
437 if status.exec_lock.locked():
438 item.Enable(False)
439
440
441 if self.info['select']:
442 item = build_menu_item(menu, id=self.MENU_RESIDUE_RESIDUE_DESELECT, text="Deselect")
443 menu.AppendItem(item)
444 if status.exec_lock.locked():
445 item.Enable(False)
446 else:
447 item = build_menu_item(menu, id=self.MENU_RESIDUE_RESIDUE_SELECT, text="Select")
448 menu.AppendItem(item)
449 if status.exec_lock.locked():
450 item.Enable(False)
451
452
453 self.Bind(wx.EVT_MENU, self.create_spin, id=self.MENU_RESIDUE_SPIN_ADD)
454 self.Bind(wx.EVT_MENU, self.delete_residue, id=self.MENU_RESIDUE_RESIDUE_DELETE)
455 if self.info['select']:
456 self.Bind(wx.EVT_MENU, self.deselect_residue, id=self.MENU_RESIDUE_RESIDUE_DESELECT)
457 else:
458 self.Bind(wx.EVT_MENU, self.select_residue, id=self.MENU_RESIDUE_RESIDUE_SELECT)
459
460
461 if status.show_gui:
462 self.PopupMenu(menu)
463 menu.Destroy()
464
465
467 """The right click root menu."""
468
469
470 menu = wx.Menu()
471
472
473 item = build_menu_item(menu, id=self.MENU_ROOT_MOLECULE_CREATE, text="Add molecule", icon=paths.icon_16x16.add)
474 menu.AppendItem(item)
475 if status.exec_lock.locked():
476 item.Enable(False)
477
478
479 item = build_menu_item(menu, id=self.MENU_ROOT_LOAD_SPINS, text="Load spins", icon=paths.icon_16x16.spin)
480 menu.AppendItem(item)
481 if status.exec_lock.locked():
482 item.Enable(False)
483
484
485 self.Bind(wx.EVT_MENU, self.create_molecule, id=self.MENU_ROOT_MOLECULE_CREATE)
486 self.Bind(wx.EVT_MENU, self.gui.spin_viewer.load_spins_wizard, id=self.MENU_ROOT_LOAD_SPINS)
487
488
489 if status.show_gui:
490 self.PopupMenu(menu)
491 menu.Destroy()
492
493
495 """The right click spin menu."""
496
497
498 menu = wx.Menu()
499 item = build_menu_item(menu, id=self.MENU_SPIN_SPIN_DELETE, text="Delete spin", icon=paths.icon_16x16.remove)
500 menu.AppendItem(item)
501 if status.exec_lock.locked():
502 item.Enable(False)
503
504
505 if self.info['select']:
506 item = build_menu_item(menu, id=self.MENU_SPIN_SPIN_DESELECT, text="Deselect")
507 menu.AppendItem(item)
508 if status.exec_lock.locked():
509 item.Enable(False)
510 else:
511 item = build_menu_item(menu, id=self.MENU_SPIN_SPIN_SELECT, text="Select")
512 menu.AppendItem(item)
513 if status.exec_lock.locked():
514 item.Enable(False)
515
516
517 self.Bind(wx.EVT_MENU, self.delete_spin, id=self.MENU_SPIN_SPIN_DELETE)
518 if self.info['select']:
519 self.Bind(wx.EVT_MENU, self.deselect_spin, id=self.MENU_SPIN_SPIN_DESELECT)
520 else:
521 self.Bind(wx.EVT_MENU, self.select_spin, id=self.MENU_SPIN_SPIN_SELECT)
522
523
524 if status.show_gui:
525 self.PopupMenu(menu)
526 menu.Destroy()
527
528
530 """Remove any molecules which have been deleted."""
531
532
533 mol_ids = get_molecule_ids()
534
535
536 prune_list = []
537 for key in self.tree_ids.keys():
538
539 info = self.tree.GetItemPyData(key)
540
541
542 if info['id'] not in mol_ids:
543 self.tree.Delete(key)
544 self.tree_ids.pop(key)
545
546
548 """Remove any molecules which have been deleted.
549
550 @param mol_branch_id: The molecule branch ID of the wx.TreeCtrl object.
551 @type mol_branch_id: TreeItemId
552 @param mol_id: The molecule identification string.
553 @type mol_id: str
554 """
555
556
557 res_ids = get_residue_ids(mol_id)
558
559
560 prune_list = []
561 for key in self.tree_ids[mol_branch_id].keys():
562
563 info = self.tree.GetItemPyData(key)
564
565
566 if info['id'] not in res_ids:
567 self.tree.Delete(key)
568 self.tree_ids[mol_branch_id].pop(key)
569
570
571 - def prune_spin(self, mol_branch_id, res_branch_id, res_id):
572 """Remove any spins which have been deleted.
573
574 @param mol_branch_id: The molecule branch ID of the wx.TreeCtrl object.
575 @type mol_branch_id: TreeItemId
576 @param res_branch_id: The residue branch ID of the wx.TreeCtrl object.
577 @type res_branch_id: TreeItemId
578 @param res_id: The residue identification string.
579 @type res_id: str
580 """
581
582
583 spin_ids = get_spin_ids(res_id)
584
585
586 prune_list = []
587 for key in self.tree_ids[mol_branch_id][res_branch_id].keys():
588
589 info = self.tree.GetItemPyData(key)
590
591
592 if info['id'] not in spin_ids:
593 self.tree.Delete(key)
594 self.tree_ids[mol_branch_id][res_branch_id].pop(key)
595
596
598 """Wrapper method.
599
600 @param event: The wx event.
601 @type event: wx event
602 """
603
604
605 msg = "Are you sure you would like to select all spins of this molecule?"
606 if status.show_gui and Question(msg, parent=self.gui.spin_viewer, default=False).ShowModal() == wx.ID_NO:
607 return
608
609
610 self.gui.interpreter.queue('select.spin', spin_id=gui_to_str(self.info['id']), change_all=False)
611
612
613 status.observers.gui_uf.notify()
614
615
617 """Wrapper method.
618
619 @param event: The wx event.
620 @type event: wx event
621 """
622
623
624 msg = "Are you sure you would like to select all spins of this residue?"
625 if status.show_gui and Question(msg, parent=self.gui.spin_viewer, default=False).ShowModal() == wx.ID_NO:
626 return
627
628
629 self.gui.interpreter.queue('select.spin', spin_id=gui_to_str(self.info['id']), change_all=False)
630
631
632 status.observers.gui_uf.notify()
633
634
636 """Wrapper method.
637
638 @param event: The wx event.
639 @type event: wx event
640 """
641
642
643 self.gui.interpreter.queue('select.spin', spin_id=gui_to_str(self.info['id']), change_all=False)
644
645
646 status.observers.gui_uf.notify()
647
648
650 """Set the molecule bitmaps.
651
652 @param mol_branch_id: The molecule branch ID of the wx.TreeCtrl object.
653 @type mol_branch_id: TreeItemId
654 @keyword select: The selection flag.
655 @type select: bool
656 """
657
658
659 if select:
660 bmp = self.icon_mol_index
661 bmp_unfold = self.icon_mol_unfold_index
662
663
664 else:
665 bmp = self.icon_mol_index_desel
666 bmp_unfold = self.icon_mol_unfold_index_desel
667
668
669 self.tree.SetItemImage(mol_branch_id, bmp, wx.TreeItemIcon_Normal)
670 self.tree.SetItemImage(mol_branch_id, bmp_unfold, wx.TreeItemIcon_Expanded)
671
672
674 """Set the residue bitmaps.
675
676 @param res_branch_id: The residue branch ID of the wx.TreeCtrl object.
677 @type res_branch_id: TreeItemId
678 @keyword select: The selection flag.
679 @type select: bool
680 """
681
682
683 if select:
684 bmp = self.icon_res_index
685
686
687 else:
688 bmp = self.icon_res_index_desel
689
690
691 self.tree.SetItemImage(res_branch_id, bmp, wx.TreeItemIcon_Normal & wx.TreeItemIcon_Expanded)
692
693
695 """Set the spin bitmaps.
696
697 @param spin_branch_id: The spin branch ID of the wx.TreeCtrl object.
698 @type spin_branch_id: TreeItemId
699 @keyword select: The selection flag.
700 @type select: bool
701 """
702
703
704 if select:
705 bmp = self.icon_spin_index
706
707
708 else:
709 bmp = self.icon_spin_index_desel
710
711
712 self.tree.SetItemImage(spin_branch_id, bmp, wx.TreeItemIcon_Normal & wx.TreeItemIcon_Expanded)
713
714
715 - def update(self, pipe_name=None):
716 """Update the tree view using the given data pipe."""
717
718
719 status.pipe_lock.acquire('spin viewer window')
720 status.spin_lock.acquire('spin viewer window')
721 try:
722
723 if not pipe_name:
724 pipe = cdp
725 else:
726 pipe = get_pipe(pipe_name)
727
728
729 if not pipe:
730 self.tree.DeleteChildren(self.root)
731 return
732
733
734 for mol, mol_id in molecule_loop(return_id=True):
735 self.update_mol(mol, mol_id)
736
737
738 self.prune_mol()
739
740
741 finally:
742 status.pipe_lock.release('spin viewer window')
743 status.spin_lock.release('spin viewer window')
744
745
747 """Update the given molecule in the tree.
748
749 @param mol: The molecule container.
750 @type mol: MoleculeContainer instance
751 @param mol_id: The molecule identification string.
752 @type mol_id: str
753 """
754
755
756 new_mol = True
757 for key in self.tree_ids.keys():
758
759 data = self.tree.GetItemPyData(key)
760
761
762 if mol_id == data['id']:
763 new_mol = False
764 mol_branch_id = key
765 break
766
767
768 if new_mol:
769
770 mol_branch_id = self.tree.AppendItem(self.root, "Molecule: %s" % mol.name)
771
772
773 data = {
774 'type': 'mol',
775 'mol_name': mol.name,
776 'id': mol_id,
777 'select': is_mol_selected(mol_id)
778 }
779 self.tree.SetPyData(mol_branch_id, data)
780
781
782 self.tree_ids[mol_branch_id] = {}
783
784
785 self.set_bitmap_mol(mol_branch_id, select=data['select'])
786
787
788 else:
789
790 select = is_mol_selected(data['id'])
791
792
793 if select != data['select']:
794
795 data['select'] = select
796
797
798 self.set_bitmap_mol(mol_branch_id, select=data['select'])
799
800
801 for res, res_id in residue_loop(mol_id, return_id=True):
802 self.update_res(mol_branch_id, mol, res, res_id)
803
804
805 if new_mol and data['select']:
806 self.tree.Expand(mol_branch_id)
807
808
809 self.prune_res(mol_branch_id, mol_id)
810
811
812 self.tree.Expand(self.root)
813
814
815 - def update_res(self, mol_branch_id, mol, res, res_id):
816 """Update the given residue in the tree.
817
818 @param mol_branch_id: The molecule branch ID of the wx.TreeCtrl object.
819 @type mol_branch_id: TreeItemId
820 @param mol: The molecule container.
821 @type mol: MoleculeContainer instance
822 @param res: The residue container.
823 @type res: ResidueContainer instance
824 @param res_id: The residue identification string.
825 @type res_id: str
826 """
827
828
829 new_res = True
830 for key in self.tree_ids[mol_branch_id].keys():
831
832 data = self.tree.GetItemPyData(key)
833
834
835 if res_id == data['id']:
836 new_res = False
837 res_branch_id = key
838 break
839
840
841 if new_res:
842
843 res_branch_id = self.tree.AppendItem(mol_branch_id, "Residue: %s %s" % (res.num, res.name))
844
845
846 data = {
847 'type': 'res',
848 'mol_name': mol.name,
849 'res_name': res.name,
850 'res_num': res.num,
851 'id': res_id,
852 'select': is_res_selected(res_id)
853 }
854 self.tree.SetPyData(res_branch_id, data)
855
856
857 self.tree_ids[mol_branch_id][res_branch_id] = {}
858
859
860 self.set_bitmap_res(res_branch_id, select=data['select'])
861
862
863 else:
864
865 select = is_res_selected(data['id'])
866
867
868 if select != data['select']:
869
870 data['select'] = select
871
872
873 self.set_bitmap_res(res_branch_id, select=data['select'])
874
875
876 for spin, spin_id in spin_loop(res_id, return_id=True):
877 self.update_spin(mol_branch_id, res_branch_id, mol, res, spin, spin_id)
878
879
880 if new_res and data['select']:
881 self.tree.Expand(res_branch_id)
882
883
884 self.prune_spin(mol_branch_id, res_branch_id, res_id)
885
886
887 - def update_spin(self, mol_branch_id, res_branch_id, mol, res, spin, spin_id):
888 """Update the given spin in the tree.
889
890 @param mol_branch_id: The molecule branch ID of the wx.TreeCtrl object.
891 @type mol_branch_id: TreeItemId
892 @param res_branch_id: The residue branch ID of the wx.TreeCtrl object.
893 @type res_branch_id: TreeItemId
894 @param mol: The molecule container.
895 @type mol: MoleculeContainer instance
896 @param res: The residue container.
897 @type res: ResidueContainer instance
898 @param spin: The spin container.
899 @type spin: SpinContainer instance
900 @param spin_id: The spin identification string.
901 @type spin_id: str
902 """
903
904
905 new_spin = True
906 for key in self.tree_ids[mol_branch_id][res_branch_id].keys():
907
908 data = self.tree.GetItemPyData(key)
909
910
911 if spin_id == data['id']:
912 new_spin = False
913 spin_branch_id = key
914 break
915
916
917 if new_spin:
918
919 spin_branch_id = self.tree.AppendItem(res_branch_id, "Spin: %s %s" % (spin.num, spin.name))
920
921
922 data = {
923 'type': 'spin',
924 'mol_name': mol.name,
925 'res_name': res.name,
926 'res_num': res.num,
927 'spin_name': spin.name,
928 'spin_num': spin.num,
929 'id': spin_id,
930 'select': is_spin_selected(spin_id)
931 }
932 self.tree.SetPyData(spin_branch_id, data)
933
934
935 self.tree_ids[mol_branch_id][res_branch_id][spin_branch_id] = True
936
937
938 self.set_bitmap_spin(spin_branch_id, select=data['select'])
939
940
941 else:
942
943 select = is_spin_selected(data['id'])
944
945
946 if select != data['select']:
947
948 data['select'] = select
949
950
951 self.set_bitmap_spin(spin_branch_id, select=data['select'])
952
953
954 if new_spin and data['select']:
955 self.tree.Expand(spin_branch_id)
956