APlayer

qslider_custom.py

Feb 9th, 2015
455
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 5.40 KB | None | 0 0
  1. from PySide import QtCore, QtGui
  2. """
  3. Author: Martin Ponweiser
  4. Date: February 2015
  5. License: Public domain
  6.  
  7. Extends the PySide Qt4 QSlider class:
  8.  
  9. QSliderAbsolutePositioning: allows for directly setting the slider value
  10.        by clicking somewhere on the slider (instead of moving in steps).
  11.        
  12. QSliderNonlinear: takes a list of integers and builds a slider that stops
  13.        only at the list values. Tick marks are NOT implemented.
  14.  
  15. Please keep in mind that this is a rather hacky implementation best
  16. suited for prototypes :)
  17. """
  18.  
  19. RANGE_INT = 2147483647
  20.  
  21. def value_magnet(val, stops):
  22.     """ This locks only at the list items """
  23.     for ii in range(len(stops)-1):
  24.         sstart = stops[ii]
  25.         sstop = stops[ii+1]
  26.         if sstart <= val <= sstop:
  27.             average = (sstart + sstop) / 2
  28.             if val <= average:
  29.                 return ii, sstart
  30.             else:
  31.                 return ii+1, sstop
  32.     return 0, val
  33.  
  34.    
  35. class QSliderAbsolutePositioning(QtGui.QSlider):
  36.     def __init__(self, *args):
  37.         super(QSliderAbsolutePositioning, self).__init__(*args)
  38.         self.installEventFilter(self)
  39.        
  40.     def eventFilter(self, widget, event):
  41.         # HACK to avoid erratic slider movements caused by auto-repeat
  42.         # if mouse button is pressed longer.
  43.         if type(event) == QtCore.QTimerEvent:
  44.             # Skip event altogether
  45.             return True
  46.         return QtGui.QSlider.eventFilter(self, widget, event)
  47.    
  48.     def position_force(self, event):
  49.         # HACK!
  50.         # event.x works always because only mouse events are overridden.
  51.         value_current = QtGui.QStyle.sliderValueFromPosition(self.minimum(),
  52.                 self.maximum(), event.x(), self.width())
  53.         self.setValue(value_current)
  54.  
  55.     def mousePressEvent(self, event):
  56.         QtGui.QSlider.mousePressEvent(self, event)
  57.         self.position_force(event)        
  58.    
  59.     def mouseMoveEvent(self, event):
  60.         QtGui.QSlider.mouseMoveEvent(self, event)
  61.         self.position_force(event)
  62.        
  63.    
  64. class QSliderNonlinear(QSliderAbsolutePositioning):
  65.    
  66.     index_changed_signal = QtCore.Signal(int)
  67.    
  68.     def __init__(self, *args):
  69.         super(QSliderNonlinear, self).__init__(*args)
  70.         self.steps_set([0, 1])
  71.  
  72.     def steps_set(self, steps_orig_sorted):
  73.         # Here we scale to a range which QSlider likes, namely integers!
  74.         self.steps_orig_sorted = steps_orig_sorted
  75.        
  76.         range_orig = steps_orig_sorted[-1] - steps_orig_sorted[0]
  77.        
  78.         self.steps_scaled = [int(((step - steps_orig_sorted[0])*RANGE_INT)
  79.                     / range_orig) for step in steps_orig_sorted]
  80.                      
  81.         # Get rid of identical steps.
  82.         self.steps_unique = sorted(list(set(self.steps_scaled)))
  83.    
  84.         self.setMinimum(self.steps_unique[0])
  85.         self.setMaximum(self.steps_unique[-1])
  86.        
  87.         self.step_index_current = 0
  88.        
  89.         self.setValue(self.steps_unique[self.step_index_current])
  90.         self.index_changed_signal.emit(self.orig_index_get())
  91.        
  92.     def orig_index_get(self):
  93.         """
  94.        0 2 2 2 8 <- start from end, we want highest index for identical values.
  95.        1 2 3 4 5
  96.        """
  97.         for ii, vv in enumerate(reversed(self.steps_scaled)):
  98.             if vv == self.value():
  99.                 orig_index = (len(self.steps_scaled)-1) - ii
  100.                 return orig_index
  101.         # self.value is not in steps_scaled
  102.         return None
  103.  
  104.     @QtCore.Slot(int)
  105.     def value_set_from_orig_index(self, index):
  106.         """ External slot """
  107.         value = self.steps_scaled[index]
  108.         self.setValue(value)
  109.  
  110.     def position_force(self, event):
  111.         # HACK!
  112.         value_current = QtGui.QStyle.sliderValueFromPosition(self.minimum(),
  113.                 self.maximum(), event.x(), self.width())
  114.         index_new, value_new = value_magnet(value_current, self.steps_unique)
  115.        
  116.         self.setValue(value_new)
  117.        
  118.         if index_new != self.step_index_current:
  119.             self.step_index_current = index_new
  120.             self.index_changed_signal.emit(self.orig_index_get())
  121.  
  122.     def mouseReleaseEvent(self, event):
  123.         QtGui.QSlider.mouseReleaseEvent(self, event)
  124.         self.position_force(event)    
  125.        
  126.     def wheel_step(self, delta):
  127.         if delta >= 0:
  128.             if self.step_index_current >= len(self.steps_unique)-1:
  129.                 return
  130.             else:
  131.                 self.step_index_current += 1
  132.                 self.setValue(self.steps_unique[self.step_index_current])
  133.         else:
  134.             if self.step_index_current == 0:
  135.                 return
  136.             else:
  137.                 self.step_index_current -= 1
  138.                 self.setValue(self.steps_unique[self.step_index_current])
  139.         self.index_changed_signal.emit(self.orig_index_get())
  140.        
  141.     def wheelEvent(self, event):
  142.         QtGui.QSlider.wheelEvent(self, event)
  143.         self.wheel_step(event.delta())
  144.  
  145.  
  146. @QtCore.Slot(int)
  147. def test_index_print(x):
  148.     print(x)
  149.  
  150.  
  151. if __name__ == "__main__":
  152.  
  153.     import math
  154.  
  155.     app = QtGui.QApplication(sys.argv)
  156.     slider = QSliderNonlinear(QtCore.Qt.Horizontal)
  157.    
  158.     slider.index_changed_signal.connect(test_index_print)
  159.    
  160.     steps = [math.log1p(xx) for xx in xrange(30)]
  161.     print(steps)
  162.     slider.steps_set(steps)
  163.  
  164.     slider.show()
  165.     app.exec_()
Advertisement
Add Comment
Please, Sign In to add comment