Add rangeslider/rangeslider.py

This commit is contained in:
2024-07-27 15:00:00 +02:00
parent fc0c582369
commit 4ec1c28afd

170
rangeslider/rangeslider.py Normal file
View 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()