From ee1fddd4dffe32793680fc3e1cabdb714b15968e Mon Sep 17 00:00:00 2001
From: niklaus johner <njohner@kb-satre.pz.unibas.ch>
Date: Tue, 5 Aug 2014 18:34:49 +0200
Subject: [PATCH] Replaced the trajectory widget by a more fancy version

---
 modules/gui/pymod/CMakeLists.txt       |   2 +-
 modules/gui/pymod/__init__.py          |   1 +
 modules/gui/pymod/traj.py              | 143 ----------
 modules/gui/pymod/trajectory_viewer.py | 357 +++++++++++++++++++++++++
 4 files changed, 359 insertions(+), 144 deletions(-)
 delete mode 100644 modules/gui/pymod/traj.py
 create mode 100644 modules/gui/pymod/trajectory_viewer.py

diff --git a/modules/gui/pymod/CMakeLists.txt b/modules/gui/pymod/CMakeLists.txt
index 87a9c6337..3c9e13e8a 100644
--- a/modules/gui/pymod/CMakeLists.txt
+++ b/modules/gui/pymod/CMakeLists.txt
@@ -79,7 +79,7 @@ set(OST_GUI_PYMOD_MODULES
   init_menubar.py
   init_spacenav.py
   init_splash.py
-  traj.py
+  trajectory_viewer.py
   helpwidget.py
   table.py
   gosty_startup.py
diff --git a/modules/gui/pymod/__init__.py b/modules/gui/pymod/__init__.py
index 784891690..ce813e7ef 100644
--- a/modules/gui/pymod/__init__.py
+++ b/modules/gui/pymod/__init__.py
@@ -16,6 +16,7 @@
 # along with this library; if not, write to the Free Software Foundation, Inc.,
 # 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 #------------------------------------------------------------------------------
+import ost.gui.trajectory_viewer
 from _ost_gui import *
 import sip
 
diff --git a/modules/gui/pymod/traj.py b/modules/gui/pymod/traj.py
deleted file mode 100644
index 1fcb1c779..000000000
--- a/modules/gui/pymod/traj.py
+++ /dev/null
@@ -1,143 +0,0 @@
-#-------------------------------------------------------------------------------
-# This file is part of the OpenStructure project <www.openstructure.org>
-#
-# Copyright (C) 2008-2011 by the OpenStructure authors
-#
-# This library is free software; you can redistribute it and/or modify it under
-# the terms of the GNU Lesser General Public License as published by the Free
-# Software Foundation; either version 3.0 of the License, or (at your option)
-# any later version.
-# This library is distributed in the hope that it will be useful, but WITHOUT
-# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
-# FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
-# details.
-#
-# You should have received a copy of the GNU Lesser General Public License
-# along with this library; if not, write to the Free Software Foundation, Inc.,
-# 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
-#-------------------------------------------------------------------------------
-from PyQt4.QtCore import *
-from PyQt4.QtGui import *
-from ost import *
-
-class TrajWidget(QWidget):
-  def __init__(self, traj=None, render_mode=gfx.SIMPLE, sel='', parent=None):
-    QWidget.__init__(self, parent, Qt.Tool)
-    self.render_mode=render_mode
-    vb=QVBoxLayout()
-    hb=QHBoxLayout()
-    hb2=QHBoxLayout() 
-    self.selection=sel
-    self.callback=None   
-    self._slider=QSlider(self)
-    self._slider.setOrientation(Qt.Horizontal)
-    self._speed_slider=QSlider(self)
-    self._speed_slider.setOrientation(Qt.Horizontal)
-    self._play=QToolButton(self)
-    self._repeat=QCheckBox(self)
-    self._frame=QLabel(self)
-    self._frameNo=QLabel(self)
-    self._frameEnd=QLabel(self)
-    self._repeat.setText('Repeat')
-    self._slider.setTracking(True)
-    self._play.setText('Play')
-    self._play.setCheckable(True)
-    self._frame.setText('Frame: ')
-    self._frameNo.setNum(0)
-    self._frameNo.setAlignment(Qt.AlignRight)
-    self._frameEnd.setText('/ '+ str(traj.GetFrameCount()-1))
-    self._frameEnd.setAlignment(Qt.AlignLeft)
-    self._speed_slider.setTracking(True)
-    self._speed_slider.setRange(-1000,-1)
-    self._speed_slider.value=-100
-    hb.addWidget(self._play)
-    hb.addWidget(self._repeat)
-    hb2.addWidget(self._frame)
-    hb2.addWidget(self._frameNo)
-    hb2.addWidget(self._frameEnd)
-    hb2.addWidget(self._speed_slider)
-    self.setLayout(vb)
-    vb.addLayout(hb)
-    vb.addWidget(self._slider)
-    vb.addLayout(hb2)
-    self.traj=traj
-    self.time=1
-    QObject.connect(self._play, SIGNAL('toggled(bool)'), 
-                    self._TogglePlay)
-    QObject.connect(self._slider, SIGNAL('valueChanged(int)'), 
-                    self._SliderValueChanged)
-    QObject.connect(self._speed_slider,SIGNAL('valueChanged(int)'),self._SpeedSliderValChanged)
-
-  def _SpeedSliderValChanged(self,speed_pos):
-    self.time=-speed_pos
-    if self._play.isChecked():
-      self._TogglePlay(False)
-      self._TogglePlay(True)
-  
-  def _SetTime(self,t):
-    self.time=t
-    self._speed_slider.setSliderPosition(-t)
-    if self._play.isChecked():
-      self._TogglePlay(False)
-      self._TogglePlay(True)
-  
-  def _SliderValueChanged(self, pos):
-    self.current_frame=pos
-    self._traj.CopyFrame(self.current_frame)
-    self.gfx_entity.UpdatePositions()
-
-  def _GetCurrentFrame(self):
-    return self._slider.sliderPosition()
-    
-  def _SetCurrentFrame(self, pos):
-    if self._slider.maximum()<pos:
-      if self._repeat.isChecked():
-        pos=0
-      else:
-        pos=self._slider.maximum()
-    self._slider.setSliderPosition(pos)
-    self._frameNo.setNum(pos)
-    
-  current_frame=property(_GetCurrentFrame, _SetCurrentFrame)
-  
-  def timerEvent(self, event):
-    self.gfx_entity.BlurSnapshot()
-    self.current_frame+=1
-    if self.callback:
-      self.callback(self.gfx_entity)
-    self.gfx_entity.UpdatePositions()
-  
-  def _TogglePlay(self, playing):
-    if playing:
-      self.timer_id_=self.startTimer(self.time)
-    else:
-      self.killTimer(self.timer_id_)
-
-  def _SetTraj(self, traj):
-    self._traj=traj
-    if self._traj:
-      ev=traj.GetEntity()
-      self.gfx_entity=gfx.Entity("mol",self.render_mode,
-                                 ev.Select(self.selection))
-      gfx.Scene().Add(self.gfx_entity)
-      gfx.Scene().CenterOn(self.gfx_entity)
-      # enable the blur effect
-      #self.gfx_entity.SetBlur(True)
-      self._slider.setMinimum(0)
-      self._slider.setMaximum(self._traj.GetFrameCount()-1)
-      self._slider.setSliderPosition(0)
-    else:
-      if self._traj:
-        del self._anim
-      self._traj=None
-  def _SetBlur(self, blur):
-    self.gfx_entity.SetBlur(blur)
-
-  def _GetBlur(self):
-    return self.gfx_entity.GetBlur()
-
-  def _GetTraj(self):
-    return self._traj
-
-  blur=property(_GetBlur, _SetBlur)
-  traj=property(_GetTraj, _SetTraj)
diff --git a/modules/gui/pymod/trajectory_viewer.py b/modules/gui/pymod/trajectory_viewer.py
new file mode 100644
index 000000000..0741f98fb
--- /dev/null
+++ b/modules/gui/pymod/trajectory_viewer.py
@@ -0,0 +1,357 @@
+"""
+This module defines a widget used for visualization of trajectories.
+
+"""
+
+__all__=('TrajWidget','SetTimeUnit','AddTrajectory','RemoveTrajectory','SetSpeed','ReleaseGfxEntity','FixGfxEntity')
+
+#-------------------------------------------------------------------------------
+# This file is part of the OpenStructure project <www.openstructure.org>
+#
+# Copyright (C) 2008-2011 by the OpenStructure authors
+#
+# This library is free software; you can redistribute it and/or modify it under
+# the terms of the GNU Lesser General Public License as published by the Free
+# Software Foundation; either version 3.0 of the License, or (at your option)
+# any later version.
+# This library is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+# FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
+# details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this library; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+#-------------------------------------------------------------------------------
+#from PyQt4.QtCore import *
+#from PyQt4.QtGui import *
+import PyQt4 as _PyQt4
+from PyQt4.QtCore import Qt as _Qt
+from PyQt4.QtCore import QObject as _QObject
+from PyQt4.QtGui import QWidget as _QWidget
+from PyQt4.QtGui import QLabel as _QLabel
+from PyQt4.QtGui import QPushButton as _QPushButton
+from PyQt4.QtCore import SIGNAL as _SIGNAL
+from PyQt4.QtCore import QString as _QString
+import ost as _ost
+import math as _math
+
+
+class TrajWidget(_QWidget):
+  def __init__(self, trajlist=None, golist=None, parent=None,ref_index=0):
+    _QWidget.__init__(self, parent, _Qt.Tool)
+    self.setFocusPolicy(_Qt.ClickFocus)
+    self.ref_index_=ref_index
+    self.trajlist_=trajlist
+    self.golist_=golist
+    self.ehlist_=[go.GetView().handle for go in self.golist_]
+    self.index_dict={}
+    self.fix_dict={}
+    self.modifiers=None
+    for i,go in enumerate(self.golist_):
+      self.index_dict[go.name]=i
+    vb=_PyQt4.QtGui.QVBoxLayout()
+    hb=_PyQt4.QtGui.QHBoxLayout()
+    hb1=_PyQt4.QtGui.QHBoxLayout()
+    hb2=_PyQt4.QtGui.QHBoxLayout()
+    hb3=_PyQt4.QtGui.QHBoxLayout()
+    hb4=_PyQt4.QtGui.QHBoxLayout()
+    self.callback=None   
+    self._slider=_PyQt4.QtGui.QSlider(self)
+    self._slider.setOrientation(_Qt.Horizontal)
+    self._speed_slider=_PyQt4.QtGui.QSlider(self)
+    self._speed_slider.setOrientation(_Qt.Horizontal)
+    self._speedLabel=_QLabel(self)
+    self._speedLabel.setText('Speed:')
+    self._speedLabel.setAlignment(_Qt.AlignLeft)
+    self._play=_PyQt4.QtGui.QToolButton(self)
+    self._repeat=_PyQt4.QtGui.QCheckBox(self)
+    self._frame=_QLabel(self)
+    self._frameNo=_QLabel(self)
+    self._frameEnd=_QLabel(self)
+    self._repeat.setText('Repeat')
+    self._slider.setTracking(True)
+    self._play.setText('Play')
+    self._play.setCheckable(True)
+    self._frame.setText('Frame: ')
+    self._frameNo.setNum(0)
+    self._frameNo.setAlignment(_Qt.AlignRight)
+    self._frameEnd.setAlignment(_Qt.AlignLeft)
+    self._timeLabel=_QLabel(self)
+    self._timeNo=_QLabel(self)
+    self._timeEnd=_QLabel(self)
+    self._timeUnit=_QLabel(self)
+    self._timeLabel.setText('Time: ')
+    self._timeNo.setNum(0)
+    self._timeNo.setAlignment(_Qt.AlignRight)
+    self._timeEnd.setAlignment(_Qt.AlignLeft)
+    self._timeUnit.setAlignment(_Qt.AlignLeft)
+    self._speed_slider.setTracking(True)
+    self._speed_slider_min=-50
+    self._speed_slider_max=-10
+    self._speed_slider.setRange(self._speed_slider_min,self._speed_slider_max)
+    self._right_arrow=_QPushButton(">")
+    self._right_arrow2=_QPushButton(">>")
+    self._right_end=_QPushButton(">|")
+    self._left_arrow=_QPushButton("<")
+    self._left_arrow2=_QPushButton("<<")
+    self._left_end=_QPushButton("|<")
+    self._align_selection=_PyQt4.QtGui.QLineEdit()
+    self._align=_QPushButton("Align")
+    self._align_label=_QLabel(self)
+    self._align_label.setText('Selection:')
+    self._ref_entity_selection=_PyQt4.QtGui.QComboBox()
+    for go in self.golist_:self._ref_entity_selection.addItem(go.name)
+    self._ref_entity_selection_label=_QLabel(self)
+    self._ref_entity_selection_label.setText('Ref. Entity:')
+    hb.addWidget(self._play)
+    hb.addWidget(self._repeat)
+    hb.addWidget(self._ref_entity_selection_label)
+    hb.addWidget(self._ref_entity_selection)
+    hb1.addWidget(self._left_end)
+    hb1.addWidget(self._left_arrow2)
+    hb1.addWidget(self._left_arrow)
+    hb1.addWidget(self._right_arrow)
+    hb1.addWidget(self._right_arrow2)
+    hb1.addWidget(self._right_end)
+    hb2.addWidget(self._frame)
+    hb2.addWidget(self._frameNo)
+    hb2.addWidget(self._frameEnd)
+    hb2.addWidget(self._timeLabel)
+    hb2.addWidget(self._timeNo)
+    hb2.addWidget(self._timeEnd)
+    hb2.addWidget(self._timeUnit)
+    hb3.addWidget(self._speedLabel)
+    hb3.addWidget(self._speed_slider)
+    hb4.addWidget(self._align_label)
+    hb4.addWidget(self._align_selection)
+    hb4.addWidget(self._align)
+    self.setLayout(vb)
+    vb.addLayout(hb)
+    vb.addLayout(hb1)
+    vb.addWidget(self._slider)
+    vb.addLayout(hb2)
+    vb.addLayout(hb3)
+    vb.addLayout(hb4)
+    self._SetSpeedSliderPos(self._speed_slider_min+0.5*(self._speed_slider_max-self._speed_slider_min))
+    _QObject.connect(self._play, _SIGNAL('toggled(bool)'), 
+                    self._TogglePlay)
+    _QObject.connect(self._slider, _SIGNAL('valueChanged(int)'), 
+                    self._SliderValueChanged)
+    _QObject.connect(self._speed_slider,_SIGNAL('valueChanged(int)'),self._SpeedSliderValChanged)
+    _QObject.connect(self._right_end,_SIGNAL('clicked()'),self._RightEndClicked)
+    _QObject.connect(self._right_arrow2,_SIGNAL('clicked()'),self._Right2Clicked)
+    _QObject.connect(self._right_arrow,_SIGNAL('clicked()'),self._RightClicked)
+    _QObject.connect(self._left_arrow2,_SIGNAL('clicked()'),self._Left2Clicked)
+    _QObject.connect(self._left_arrow,_SIGNAL('clicked()'),self._LeftClicked)
+    _QObject.connect(self._left_end,_SIGNAL('clicked()'),self._LeftEndClicked)
+    _QObject.connect(self._align, _SIGNAL('clicked()'), self._AlignClicked)
+    _QObject.connect(self._ref_entity_selection, _SIGNAL('currentIndexChanged(int)'), self._EntitySelected)
+    self._slider.setMinimum(0)
+    self.frame_number_=self.traj_.GetFrameCount()-1
+    self.timestep_=self.traj_.GetDelta()
+    self.SetTimeUnit('ns')
+    self.SetReferenceIndex(0)
+    
+  def _p2u(self,u):
+    if u=="s":
+      return 1.0e-12
+    elif u=="ms":
+      return 1.0e-9
+    elif u=="us":
+      return 1.0e-6
+    elif u=="ns":
+      return 1.0e-3
+    elif u=="ps":
+      return 1.0
+    elif u=="fs":
+      return 1.0e3
+    raise RuntimeError("expected one of s,ms,us,ns,ps or fs for unit")
+
+  def SetTimeUnit(self,u):
+    self._time_prefactor=self._p2u(u)
+    self._timeEnd.setText('/ '+ str((self.frame_number_-1)*self.timestep_*self._time_prefactor))
+    self._timeNo.setNum(self.current_frame*self.timestep_*self._time_prefactor)
+    self._timeUnit.setText('['+u+']')
+  
+  def _SetSpeedSliderPos(self,pos):
+    self._speed_slider.setSliderPosition(pos)
+    self._SpeedSliderValChanged(pos)
+    
+  def _SpeedSliderValChanged(self,speed_pos):
+    self.time=_math.exp(-0.15*speed_pos)
+    if self._play.isChecked():
+      self._TogglePlay(False)
+      self._TogglePlay(True)
+  
+  def _SetTime(self,t):
+    self.time=t
+    self._speed_slider.setSliderPosition(-1./0.15*_math.log(t))
+    if self._play.isChecked():
+      self._TogglePlay(False)
+      self._TogglePlay(True)
+  
+  
+  def _SliderValueChanged(self, pos):
+    self.current_frame=pos
+    for traj,go in zip(self.trajlist_,self.golist_):
+      if go.name in self.fix_dict:continue
+      traj.CopyFrame(self.current_frame)
+      go.UpdatePositions()
+
+  def _GetCurrentFrame(self):
+    return self._slider.sliderPosition()
+    
+  def _SetCurrentFrame(self, pos):
+    if self._slider.maximum()<pos:
+      if self._repeat.isChecked():
+        pos=0
+      else:
+        pos=self._slider.maximum()
+    self._slider.setSliderPosition(pos)
+    self._frameNo.setNum(pos)
+    self._timeNo.setNum(pos*self.timestep_*self._time_prefactor)
+    
+  current_frame=property(_GetCurrentFrame, _SetCurrentFrame)
+  
+  def _GetReferenceTraj(self):
+    return self.trajlist_[self.ref_index_]
+  traj_=property(_GetReferenceTraj)
+  
+  def timerEvent(self, event):
+    #if self.callback:
+    #  self.callback(self.golist_)
+    self.current_frame+=1
+    for go in self.golist_:
+      if go.name in self.fix_dict:continue
+      go.BlurSnapshot()
+      go.UpdatePositions()
+  
+  def _TogglePlay(self, playing):
+    if playing:
+      self.timer_id_=self.startTimer(self.time)
+    else:
+      self.killTimer(self.timer_id_)
+  
+  def _LeftClicked(self):
+    if self.current_frame>0:
+      self.current_frame-=1
+  
+  def _RightClicked(self):
+    if self.current_frame<self.frame_number_-1:
+      self.current_frame+=1
+  
+  def _Left2Clicked(self):
+    if self.current_frame>=10:
+      self.current_frame-=10
+  
+  def _Right2Clicked(self):
+    if self.current_frame<self.frame_number_-10:
+      self.current_frame+=10
+  
+  def _LeftEndClicked(self):
+    if self.current_frame>0:
+      self.current_frame=0
+  
+  def _RightEndClicked(self):
+    if self.current_frame<self.frame_number_-1:
+      self.current_frame=self.frame_number_-1
+    
+  def _AlignClicked(self):
+    ref_eh=self.ehlist_[self.ref_index_]
+    ref_v=ref_eh.Select(str(self._align_selection.text()))
+    if ref_v.GetAtomCount()<=3:
+      print 'not enough atoms for alignment'
+      return
+    for i,t,eh in zip(range(len(self.trajlist_)),self.trajlist_,self.ehlist_):
+      t=_ost.mol.alg.SuperposeFrames(t,eh.Select(str(self._align_selection.text())),ref_v)
+      self.trajlist_[i]=t
+      
+  def _SetBlur(self, blur):
+    for go in self.golist_:
+      go.SetBlur(blur)
+
+  def _GetBlur(self):
+    return self.gfx_entity.GetBlur()
+
+  blur=property(_GetBlur, _SetBlur)
+
+  def SetReferenceIndex(self,ref_index):
+    if type(ref_index)==type(''):
+      self.ref_index_=self.index_dict[ref_index]
+    else:
+      self.ref_index_=ref_index
+    self.frame_number_=self.traj_.GetFrameCount()
+    self.timestep_=self.traj_.GetDelta()
+    self._slider.setMaximum(self.frame_number_-1)
+    self._frameEnd.setText('/ '+ str(self.frame_number_-1))
+    self._timeEnd.setText('/ '+ str((self.frame_number_-1)*self.timestep_*self._time_prefactor))
+    self._ref_entity_selection.setCurrentIndex(self.ref_index_)
+  
+  def _EntitySelected(self,index):
+    ref_index=self.index_dict[str(self._ref_entity_selection.currentText())]
+    self.SetReferenceIndex(ref_index)
+  
+  def keyPressEvent(self, event):
+    key=event.key()
+    if event.modifiers()==_Qt.ControlModifier:
+      self.modifiers=event.modifiers()
+    if self.modifiers==_Qt.ControlModifier:
+      if key==_Qt.Key_Left:
+        self._Left2Clicked()
+      elif key==_Qt.Key_Right:
+        self._Right2Clicked()
+    else:
+      if key==_Qt.Key_Left:
+        self._LeftClicked()
+      elif key==_Qt.Key_Right:
+        self._RightClicked()
+      elif key==_Qt.Key_Space:
+        self._play.setChecked(not self._play.isChecked())
+      else:
+        _QWidget.keyPressEvent(self, event)
+  
+  def keyReleaseEvent(self, event):
+    if event.key()==_Qt.Key_Control:
+      self.modifiers=None
+    else:
+      _QWidget.keyPressEvent(self, event)
+  
+  def FixGfxEntity(self,index,frame_number=None):
+    if not frame_number:frame_number=self.current_frame
+    if type(index)==type(''):
+      self.fix_dict[index]=frame_number
+      i=self.index_dict[index]
+    else:
+      i=index
+      self.fix_dict[self.golist_[i].name]=frame_number
+    self.trajlist_[i].CopyFrame(frame_number)
+    self.golist_[i].UpdatePositions()
+  
+  def ReleaseGfxEntity(self,index):
+    if type(index)==type(''):self.fix_dict.pop(index)
+    else:self.fix_dict.pop(self.golist_[index].name)
+  
+  def AddTrajectory(self,traj,go):
+    self.trajlist_.append(traj)
+    self.golist_.append(go)
+    self.ehlist_.append(go.GetView().handle)
+    self.index_dict[go.name]=len(self.golist_)-1
+  
+  def RemoveTrajectory(self,index):
+    if type(index)==type(''):
+      index=self.index_dict[index]
+    self.trajlist_.pop(index)
+    self.golist_.pop(index)
+    self.ehlist_.pop(index)
+  
+  def SetSpeed(self,val):
+  #Value should be between 0 and 1
+    if not (val<=1. and val >=0.):
+      print 'Speed should be set between 0 and 1'
+      return
+    else:
+      val=self._speed_slider_min-val*(self._speed_slider_min-self._speed_slider_max)
+      self._SetSpeedSliderPos(val)
+      print val
+      
-- 
GitLab