Add rangeslider/rangeslider.py
This commit is contained in:
170
rangeslider/rangeslider.py
Normal file
170
rangeslider/rangeslider.py
Normal file
@@ -0,0 +1,170 @@
|
||||
import wx
|
||||
|
||||
class RangeSlider(wx.Panel):
|
||||
def __init__(self, parent, id=wx.ID_ANY, minValue=0, maxValue=100,
|
||||
minRange=20, maxRange=80, orientation=wx.HORIZONTAL, **kwargs):
|
||||
super().__init__(parent, id, **kwargs)
|
||||
self.minValue = minValue
|
||||
self.maxValue = maxValue
|
||||
self.minRange = minRange
|
||||
self.maxRange = maxRange
|
||||
self.orientation = orientation
|
||||
|
||||
self.dragging = None
|
||||
self.offset = 0
|
||||
|
||||
self.Bind(wx.EVT_PAINT, self.OnPaint)
|
||||
self.Bind(wx.EVT_LEFT_DOWN, self.OnLeftDown)
|
||||
self.Bind(wx.EVT_LEFT_UP, self.OnLeftUp)
|
||||
self.Bind(wx.EVT_MOTION, self.OnMouseMove)
|
||||
self.Bind(wx.EVT_SIZE, self.OnResize)
|
||||
|
||||
def OnPaint(self, event):
|
||||
dc = wx.PaintDC(self)
|
||||
self.Draw(dc)
|
||||
|
||||
def OnResize(self, event):
|
||||
self.Refresh()
|
||||
event.Skip()
|
||||
|
||||
def OnLeftDown(self, event):
|
||||
pos = event.GetPosition()
|
||||
min_rect = self.GetMinRangeRect()
|
||||
max_rect = self.GetMaxRangeRect()
|
||||
|
||||
if min_rect.Contains(pos):
|
||||
self.dragging = 'min'
|
||||
self.offset = pos - min_rect.GetPosition()
|
||||
elif max_rect.Contains(pos):
|
||||
self.dragging = 'max'
|
||||
self.offset = pos - max_rect.GetPosition()
|
||||
elif self.GetRangeRect().Contains(pos):
|
||||
self.dragging = 'range'
|
||||
self.offset = pos - self.GetRangeRect().GetPosition()
|
||||
|
||||
self.CaptureMouse()
|
||||
|
||||
def OnLeftUp(self, event):
|
||||
if self.HasCapture():
|
||||
self.ReleaseMouse()
|
||||
self.dragging = None
|
||||
|
||||
def OnMouseMove(self, event):
|
||||
if self.dragging:
|
||||
pos = event.GetPosition()
|
||||
size = self.GetClientSize()
|
||||
width = size.GetWidth() if self.orientation == wx.HORIZONTAL else size.GetHeight()
|
||||
total_range = self.maxValue - self.minValue
|
||||
step = total_range / width
|
||||
|
||||
if self.dragging == 'min':
|
||||
new_min = self.minValue + int((pos.x - self.offset.x) * step) if self.orientation == wx.HORIZONTAL else self.minValue + int((pos.y - self.offset.y) * step)
|
||||
new_min = max(self.minValue, min(new_min, self.maxRange - 1))
|
||||
self.minRange = new_min
|
||||
elif self.dragging == 'max':
|
||||
new_max = self.minValue + int((pos.x - self.offset.x) * step) if self.orientation == wx.HORIZONTAL else self.minValue + int((pos.y - self.offset.y) * step)
|
||||
new_max = min(self.maxValue, max(new_max, self.minRange + 1))
|
||||
self.maxRange = new_max
|
||||
elif self.dragging == 'range':
|
||||
range_width = self.maxRange - self.minRange
|
||||
new_min = self.minValue + int((pos.x - self.offset.x) * step) if self.orientation == wx.HORIZONTAL else self.minValue + int((pos.y - self.offset.y) * step)
|
||||
new_min = max(self.minValue, min(new_min, self.maxValue - range_width))
|
||||
self.minRange = new_min
|
||||
self.maxRange = new_min + range_width
|
||||
|
||||
self.Refresh()
|
||||
|
||||
def Draw(self, dc):
|
||||
size = self.GetClientSize()
|
||||
width, height = size.GetWidth(), size.GetHeight()
|
||||
|
||||
total_range = self.maxValue - self.minValue
|
||||
if self.orientation == wx.HORIZONTAL:
|
||||
min_pos = int((self.minRange - self.minValue) / total_range * width)
|
||||
max_pos = int((self.maxRange - self.minValue) / total_range * width)
|
||||
else:
|
||||
min_pos = int((self.minRange - self.minValue) / total_range * height)
|
||||
max_pos = int((self.maxRange - self.minValue) / total_range * height)
|
||||
|
||||
# Background
|
||||
dc.SetBrush(wx.Brush(wx.SystemSettings.GetColour(wx.SYS_COLOUR_3DFACE)))
|
||||
dc.DrawRectangle(0, 0, width, height)
|
||||
|
||||
# Draw range bar
|
||||
dc.SetBrush(wx.Brush(wx.SystemSettings.GetColour(wx.SYS_COLOUR_HIGHLIGHT)))
|
||||
if self.orientation == wx.HORIZONTAL:
|
||||
dc.DrawRectangle(min_pos, 0, max_pos - min_pos, height)
|
||||
else:
|
||||
dc.DrawRectangle(0, min_pos, width, max_pos - min_pos)
|
||||
|
||||
# Draw min and max handles
|
||||
dc.SetBrush(wx.Brush(wx.SystemSettings.GetColour(wx.SYS_COLOUR_BTNFACE)))
|
||||
handle_width = 10 if self.orientation == wx.HORIZONTAL else width
|
||||
handle_height = 10 if self.orientation == wx.VERTICAL else height
|
||||
|
||||
if self.orientation == wx.HORIZONTAL:
|
||||
dc.DrawRectangle(min_pos - 5, 0, handle_width, handle_height)
|
||||
dc.DrawRectangle(max_pos - 5, 0, handle_width, handle_height)
|
||||
else:
|
||||
dc.DrawRectangle(0, min_pos - 5, handle_width, handle_height)
|
||||
dc.DrawRectangle(0, max_pos - 5, handle_width, handle_height)
|
||||
|
||||
def GetMinRangeRect(self):
|
||||
size = self.GetClientSize()
|
||||
width, height = size.GetWidth(), size.GetHeight()
|
||||
total_range = self.maxValue - self.minValue
|
||||
|
||||
if self.orientation == wx.HORIZONTAL:
|
||||
min_pos = int((self.minRange - self.minValue) / total_range * width)
|
||||
return wx.Rect(min_pos - 5, 0, 10, height)
|
||||
else:
|
||||
min_pos = int((self.minRange - self.minValue) / total_range * height)
|
||||
return wx.Rect(0, min_pos - 5, width, 10)
|
||||
|
||||
def GetMaxRangeRect(self):
|
||||
size = self.GetClientSize()
|
||||
width, height = size.GetWidth(), size.GetHeight()
|
||||
total_range = self.maxValue - self.minValue
|
||||
|
||||
if self.orientation == wx.HORIZONTAL:
|
||||
max_pos = int((self.maxRange - self.minValue) / total_range * width)
|
||||
return wx.Rect(max_pos - 5, 0, 10, height)
|
||||
else:
|
||||
max_pos = int((self.maxRange - self.minValue) / total_range * height)
|
||||
return wx.Rect(0, max_pos - 5, width, 10)
|
||||
|
||||
def GetRangeRect(self):
|
||||
size = self.GetClientSize()
|
||||
width, height = size.GetWidth(), size.GetHeight()
|
||||
total_range = self.maxValue - self.minValue
|
||||
|
||||
if self.orientation == wx.HORIZONTAL:
|
||||
min_pos = int((self.minRange - self.minValue) / total_range * width)
|
||||
max_pos = int((self.maxRange - self.minValue) / total_range * width)
|
||||
return wx.Rect(min_pos, 0, max_pos - min_pos, height)
|
||||
else:
|
||||
min_pos = int((self.minRange - self.minValue) / total_range * height)
|
||||
max_pos = int((self.maxRange - self.minValue) / total_range * height)
|
||||
return wx.Rect(0, min_pos, width, max_pos - min_pos)
|
||||
|
||||
class MainFrame(wx.Frame):
|
||||
def __init__(self):
|
||||
super().__init__(None, title='Range Slider Example', size=(400, 200))
|
||||
panel = wx.Panel(self)
|
||||
|
||||
self.horizontal_slider = RangeSlider(panel, minValue=0, maxValue=100, minRange=20, maxRange=80,
|
||||
orientation=wx.HORIZONTAL, pos=(10, 10), size=(380, 50))
|
||||
self.vertical_slider = RangeSlider(panel, minValue=0, maxValue=100, minRange=20, maxRange=80,
|
||||
orientation=wx.VERTICAL, pos=(10, 70), size=(50, 120))
|
||||
|
||||
sizer = wx.BoxSizer(wx.HORIZONTAL)
|
||||
sizer.Add(self.horizontal_slider, 1, wx.EXPAND | wx.ALL, 10)
|
||||
sizer.Add(self.vertical_slider, 0, wx.EXPAND | wx.ALL, 10)
|
||||
panel.SetSizer(sizer)
|
||||
|
||||
self.Show()
|
||||
|
||||
if __name__ == '__main__':
|
||||
app = wx.App(False)
|
||||
frame = MainFrame()
|
||||
app.MainLoop()
|
Reference in New Issue
Block a user