Initial revision
diff --git a/Lib/stdwin/Sliders.py b/Lib/stdwin/Sliders.py
new file mode 100755
index 0000000..8953efd
--- /dev/null
+++ b/Lib/stdwin/Sliders.py
@@ -0,0 +1,74 @@
+# Module 'Sliders'
+#
+# Sliders are somewhat like buttons but have an extra hook that is
+# called whenever their value is changed.
+
+import stdwin
+from stdwinevents import *
+import rect
+from minmax import min, max
+from Buttons import ClassicButton
+
+
+# Field indices in event detail
+#
+_HV = 0
+_CLICKS = 1
+_BUTTON = 2
+_MASK = 3
+
+
+# A dragslider is the simplest possible slider.
+# It looks like a button but dragging the mouse left or right
+# changes the controlled value.
+#
+class DragSlider() = ClassicButton():
+	#
+	# INVARIANTS maintained by the define and setval methods:
+	#
+	#	self.min <= self.val <= self.max
+	#	self.text = `self.val`
+	#
+	# (Notice that unlike in Python ranges, the end point belongs
+	# to the range.)
+	#
+	def define(self, (win, bounds)):
+		self.min = 0
+		self.val = 50
+		self.max = 100
+		self.setval_hook = 0
+		self.pretext = self.postext = ''
+		self.text = self.pretext + `self.val` + self.postext
+		self = ClassicButton.define(self, (win, bounds, self.text))
+		return self
+	#
+	def setval(self, val):
+		val = min(self.max, max(self.min, val))
+		if val <> self.val:
+			self.val = val
+			self.text = self.pretext + `self.val` + self.postext
+			if self.setval_hook:
+				self.setval_hook(self)
+			self.redraw()
+	#
+	def settext(self, text):
+		pass # shouldn't be called at all
+	#
+	def mouse_down(self, detail):
+		h, v = hv = detail[_HV]
+		if self.enabled and self.mousetest(hv):
+			self.anchor = h
+			self.oldval = self.val
+			self.active = 1
+	#
+	def mouse_move(self, detail):
+		if self.active:
+			h, v = detail[_HV]
+			self.setval(self.oldval + (h - self.anchor))
+	#
+	def mouse_up(self, detail):
+		if self.active:
+			h, v = detail[_HV]
+			self.setval(self.oldval + (h - self.anchor))
+			self.active = 0
+	#