Module rangedslider
[hide private]
[frames] | no frames]

Source Code for Module rangedslider

  1  ### BITPIM 
  2  ### 
  3  ### Copyright (C) 2005 Roger Binns <rogerb@rogerbinns.com> 
  4  ### 
  5  ### This program is free software; you can redistribute it and/or modify 
  6  ### it under the terms of the BitPim license as detailed in the LICENSE file. 
  7  ### 
  8  ### $Id: rangedslider.py 2249 2005-03-22 07:13:19Z rogerb $ 
  9   
 10  "A ranged slider that has a current position and a start/end" 
 11   
 12   
 13  import wx 
 14  import wx.lib.newevent 
 15   
 16  import guihelper 
 17   
 18  PosChangedEvent, EVT_POS_CHANGED = wx.lib.newevent.NewCommandEvent() 
 19  ChangingEvent, EVT_CHANGING = wx.lib.newevent.NewCommandEvent() 
 20   
21 -class RangedSlider(wx.PyWindow):
22 23 THICKNESS=7 24
25 - def __init__(self, parent, id=-1, size=wx.DefaultSize, pos=wx.DefaultPosition, style=0):
26 wx.PyWindow.__init__(self, parent, id=id, size=size, pos=pos, style=style|wx.FULL_REPAINT_ON_RESIZE) 27 28 self.bg=wx.Brush(parent.GetBackgroundColour()) 29 30 self.imgcurrent=guihelper.getimage("ranged-slider-current") 31 self.bmpcurrent=self.imgcurrent.ConvertToBitmap() 32 self.imgstart=guihelper.getimage("ranged-slider-start") 33 self.bmpstart=self.imgstart.ConvertToBitmap() 34 self.imgend=guihelper.getimage("ranged-slider-end") 35 self.bmpend=self.imgend.ConvertToBitmap() 36 37 # first coord is added to desired x to get where to draw x 38 # second is added to centre of line to get where to draw y 39 self.hotcurrent=-self.imgcurrent.GetWidth()/2, -self.imgcurrent.GetHeight()+2 40 self.hotstart=-13, -20 41 self.hotend=-7,-20 42 43 self.pickers=(self.imgcurrent, self.bmpcurrent,self.hotcurrent), \ 44 (self.imgstart, self.bmpstart, self.hotstart), \ 45 (self.imgend, self.bmpend, self.hotend) 46 47 self.padleft=2+max([0]+[-h[0] for _,_,h in self.pickers]) 48 self.padright=2+max([0]+[i.GetWidth()+h[0] for i,_,h in self.pickers]) 49 50 assert self.padleft>=2 51 assert self.padright>=2 52 self.padleft=max(self.padleft,self.padright) 53 self.padright=self.padleft 54 55 self.poscurrent=0.5 56 self.posstart=0.0 57 self.posend=1.0 58 59 self._bufbmp=None 60 61 self.pen=wx.Pen(wx.NamedColour("LIGHTSTEELBLUE3"), self.THICKNESS) 62 self.pen.SetCap(wx.CAP_BUTT) 63 64 self.clickinfo=None 65 66 wx.EVT_ERASE_BACKGROUND(self, lambda evt: None) 67 wx.EVT_PAINT(self, self.OnPaint) 68 wx.EVT_LEFT_DOWN(self, self.OnLeftDown) 69 wx.EVT_LEFT_UP(self, self.OnLeftUp) 70 wx.EVT_MOTION(self, self.OnMotion)
71
72 - def DoGetBestSize(self):
73 sz=self.GetClientSize() 74 halfheight=self.THICKNESS 75 for i,_,h in self.pickers: 76 halfheight=max(halfheight, abs(h[1]), abs(h[1]+i.GetHeight())) 77 78 return min(100,sz.width),halfheight*2
79 80 81
82 - def OnPaint(self, _):
83 sz=self.GetClientSize() 84 if self._bufbmp is None or sz.width>self._bufbmp.GetWidth() or sz.height>self._bufbmp.GetHeight(): 85 self._bufbmp=wx.EmptyBitmap((sz.width+64)&~8, (sz.height+64)&~8) 86 dc=wx.BufferedPaintDC(self, self._bufbmp, style=wx.BUFFER_VIRTUAL_AREA) 87 dc.SetBackground(self.bg) 88 dc.Clear() 89 dc.SetPen(self.pen) 90 y=sz.height/2 91 dc.DrawLine(self.padleft,y, sz.width-self.padright, y) 92 dc.SetPen(wx.NullPen) 93 start=self.padleft 94 width=sz.width-self.padleft-self.padright 95 96 dc.DrawBitmap(self.bmpcurrent, start+int(width*self.poscurrent)+self.hotcurrent[0], y+self.hotcurrent[1], True) 97 dc.DrawBitmap(self.bmpstart, start+int(width*self.posstart)+self.hotstart[0], y+self.hotstart[1], True) 98 dc.DrawBitmap(self.bmpend, start+int(width*self.posend)+self.hotend[0], y+self.hotend[1], True)
99
100 - def _isinimage(self, image, relx, rely):
101 "Works out if click is in image, and not transparent area of image" 102 if image.HasAlpha(): 103 return image.GetAlpha(relx, rely)>0 104 if image.HasMask(): 105 return not (image.GetRed(relx, rely)==image.GetMaskRed() and 106 image.GetGreen(relx, rely)==image.GetMaskGreen() and 107 image.GetBlue(relx, rely)==image.GetMaskBlue()) 108 # we have no way of telling, so say yes 109 return True
110
111 - def OnLeftDown(self, evt):
112 x,y=evt.GetX(), evt.GetY() 113 sz=self.GetClientSize() 114 liney=sz.height/2 115 start=self.padleft 116 width=sz.width-self.padleft-self.padright 117 # now try to work out what was clicked on 118 xx,yy=start+int(width*self.poscurrent)+self.hotcurrent[0], liney+self.hotcurrent[1] 119 if xx<=x<xx+self.imgcurrent.GetWidth() and yy<=y<yy+self.imgcurrent.GetHeight(): 120 relx,rely=x-xx,y-yy 121 if self._isinimage(self.imgcurrent, relx, rely): 122 print "oncurrent" 123 self.clickinfo=0,x,self.poscurrent 124 return 125 xx,yy=start+int(width*self.posstart)+self.hotstart[0], liney+self.hotstart[1] 126 if xx<=x<xx+self.imgstart.GetWidth() and yy<=y<yy+self.imgstart.GetHeight(): 127 relx,rely=x-xx,y-yy 128 if self._isinimage(self.imgstart, relx, rely): 129 print "onstart" 130 self.clickinfo=1,x,self.posstart 131 return 132 xx,yy=start+int(width*self.posend)+self.hotend[0], liney+self.hotend[1] 133 if xx<=x<xx+self.imgend.GetWidth() and yy<=y<yy+self.imgend.GetHeight(): 134 relx,rely=x-xx,y-yy 135 if self._isinimage(self.imgend, relx, rely): 136 print "onend" 137 self.clickinfo=2,x,self.posend 138 return 139 if start<=x<start+width and liney-self.THICKNESS/2<=y<=liney+self.THICKNESS/2: 140 self.poscurrent=(x-start)/float(width) 141 self.Refresh(False) 142 self.clickinfo=0,x,y 143 return 144 self.clickinfo=None
145
146 - def OnMotion(self, evt):
147 if self.clickinfo is None or not evt.Dragging(): 148 return 149 x,y=evt.GetX(), evt.GetY() 150 sz=self.GetClientSize() 151 liney=sz.height/2 152 start=self.padleft 153 width=sz.width-self.padleft-self.padright 154 155 origpos=self.clickinfo[2] 156 origx=self.clickinfo[1] 157 delta=origx-x 158 newpos=origpos-delta/float(width) 159 if newpos<0: newpos=0.0 160 elif newpos>1: newpos=1.0 161 if self.clickinfo[0]==0: self.poscurrent=newpos 162 elif self.clickinfo[0]==1: self.posstart=min(newpos,self.posend) 163 elif self.clickinfo[0]==2: self.posend=max(newpos, self.posstart) 164 if newpos!=origpos: 165 wx.PostEvent(self, ChangingEvent(self.GetId())) 166 self.Refresh(False)
167
168 - def OnLeftUp(self, evt):
169 if self.clickinfo is not None and self.clickinfo[0]==0: 170 wx.PostEvent(self, PosChangedEvent(self.GetId(), poscurrent=self.poscurrent))
171 172 # main API
173 - def GetCurrent(self):
174 return self.poscurrent
175 - def SetCurrent(self, pos):
176 assert 0<=pos<=1 177 self.poscurrent=pos 178 self.Refresh(False)
179 - def GetStart(self):
180 return self.posstart
181 - def SetStart(self, pos):
182 assert 0<=pos<=1 183 self.posstart=pos 184 self.Refresh(False)
185 - def GetEnd(self):
186 return self.posend
187 - def SetEnd(self, pos):
188 assert 0<=pos<=1 189 self.posend=pos 190 self.Refresh(False)
191 192 193 if __name__=='__main__': 194 app=wx.PySimpleApp() 195 196 import sys 197 import common 198 sys.excepthook=common.formatexceptioneh 199 200 f=wx.Frame(None, title="Ranged Slider Tester") 201 rs=RangedSlider(f) 202 f.Show() 203 204 app.MainLoop() 205