Example #1
0
class SlidingPanel(RelativeLayout):
	"""An empty panel that slides from a side"""

	side = StringProperty("left")
	"""Side from which the menu will slide from
	Valid values are "left" and "right"
	"""

	animation_length = NumericProperty(0.3)
	"""How long will the animation last"""

	def __init__(self, **kwargs):
		self.register_event_type('on_closed')
		self.register_event_type('on_opening')
		self.register_event_type('on_opened')
		self.register_event_type('on_closing')
		self.animation_open = Animation(duration=self.animation_length,
		                                t="out_sine")
		self.animation_dismiss = Animation(duration=self.animation_length,
		                                   t="out_sine")

		self.shadow = Shadow(width=0, opacity=0.8, size_hint_x=None,
		                     on_release=lambda x: self.dismiss())
		super(SlidingPanel, self).__init__(**kwargs)
		self.orientation = "vertical"
		self.size_hint = (None, None)
		self.status = "closed"
		self.timer = None

		self.shadow.fade_out(0)
		self.bind(height=self.shadow.setter('height'))
		helpers.bind_to_rotation(self._device_rotated)


	def on_touch_down(self, touch):
		# Prevents touch events from propagating to anything below the widget.
		super(SlidingPanel, self).on_touch_down(touch)
		if self.collide_point(*touch.pos):
			return True

	def open(self):
		if self.status != "closed":
			return
		self.update_animations()
		self.shadow.fade_in(self.animation_length, add_to=self)
		self.animation_open.start(self)
		self.dispatch('on_opening')
		self.status = "opening"
		self.timer = ThreadedTimer(
			self.animation_length + 0.1, self._fix_status).start()

	def dismiss(self):
		if self.status != "open":
			return
		self.update_animations()
		self.shadow.fade_out(self.animation_length)
		self.animation_dismiss.start(self)
		self.dispatch('on_closing')
		self.status = "closing"
		self.timer = ThreadedTimer(
			self.animation_length + 0.1, self._fix_status).start()

	def update_animations(self):
		if self.side == "left":
			self.shadow.x = self.width
			if self.status == "closed":
				self.animation_open.animated_properties['x'] = self.x +\
			                                                   self.width
			elif self.status == "open":
				self.animation_dismiss.animated_properties['x'] = self.x -\
				                                                  self.width
		elif self.side == "right":
			self.shadow.x = 0 - self.shadow.width
			if self.status == "closed":
				self.animation_open.animated_properties['x'] = \
					self.parent.width - self.width
			elif self.status == "open":
				self.animation_dismiss.animated_properties['x'] = \
					self.parent.x + self.width
		self.animation_dismiss.animated_properties['y'] = float(self.y)

	def _device_rotated(self, orientation):
		self.update_animations()

	def toggle(self):
		if self.status == "open":
			self.dismiss()
		elif self.status == "closed":
			self.open()

	def _fix_status(self):
		if self.status == "opening":
			self.status = "open"
		elif self.status == "closing":
			self.status = "closed"
		else:
			return
		self.timer = None

	def on_side(self, instance, value):
		if value == "left":
			self.shadow.x = self.width
			value.unbind(width=self.setter('x'))
		elif value == "right":
			self.shadow.x = self.shadow.width - self.width
		else:
			raise ValueError(
				"Valid values for side are \"left\" and \"right\"")

	def on_parent(self, instance, value):
		value.bind(height=self.setter('height'))
		value.bind(x=self._set_x)
		value.bind(y=self._set_y)
		value.bind(width=self.shadow.setter('width'))
		if self.side == "left":
			self.x = value.x - self.width
		elif self.side == "right":
			value.bind(width=self.setter('x'))

	def _set_x(self, instance, value):
		if self.side == "left":
			self.x = value - self.width
		elif self.side == "right":
			self.x = instance.width

	def _set_y(self, instance, value):
		self.y = value

	def on_closed(self):
		pass

	def on_opening(self):
		pass

	def on_opened(self):
		pass

	def on_closing(self):
		pass