1
2
3
4
5
6
7
8
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
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
38
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
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
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
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
109 return True
110
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
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
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
169 if self.clickinfo is not None and self.clickinfo[0]==0:
170 wx.PostEvent(self, PosChangedEvent(self.GetId(), poscurrent=self.poscurrent))
171
172
174 return self.poscurrent
176 assert 0<=pos<=1
177 self.poscurrent=pos
178 self.Refresh(False)
182 assert 0<=pos<=1
183 self.posstart=pos
184 self.Refresh(False)
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