summary refs log tree commit diff stats
path: root/ranger/gui/displayable.py
diff options
context:
space:
mode:
Diffstat (limited to 'ranger/gui/displayable.py')
-rw-r--r--ranger/gui/displayable.py135
1 files changed, 95 insertions, 40 deletions
diff --git a/ranger/gui/displayable.py b/ranger/gui/displayable.py
index 41ed9ae4..315d2f7b 100644
--- a/ranger/gui/displayable.py
+++ b/ranger/gui/displayable.py
@@ -3,10 +3,42 @@ from ranger import log
 import _curses
 
 class Displayable(EnvironmentAware, FileManagerAware, SettingsAware):
-	focused = False
-	visible = True
-	win = None
-	colorscheme = None
+	"""
+	Displayables are objects which are displayed on the screen.
+
+	This is just the abstract class, defining basic operations
+	such as resizing, printing, changing colors.
+	Subclasses of displayable should implement this interface:
+
+	draw() -- draw the object here. Is only called if visible.
+	poke() -- is called just before draw(), even if not visible.
+	finalize() -- called after all objects finished drawing.
+	click(event) -- called with a MouseEvent. This is called on all
+		visible objects under the mouse, until one returns True.
+	press(key) -- called after a key press on focused objects.
+	destroy() -- called before destroying the displayable object
+
+	This abstract class defines the following (helper) methods:
+
+	color(*keys) -- sets the color associated with the keys from
+		the current colorscheme.
+	color_at(y, x, wid, *keys) -- sets the color at the given position
+	color_reset() -- resets the color to the default
+	addstr(*args) -- failsafe version of self.win.addstr(*args)
+	__contains__(item) -- is the item (y, x) inside the widget?
+	
+	These attributes are set:
+
+	Modifiable:
+		focused -- Focused objects receive press() calls.
+		visible -- Visible objects receive draw() and finalize() calls
+	
+	Read-Only: (i.e. reccomended not to change manually)
+		win -- the own curses window object
+		parent -- the parent (DisplayableContainer) object or None
+		x, y, wid, hei -- absolute coordinates and boundaries
+		settings, fm, env -- inherited shared variables
+	"""
 
 	def __init__(self, win, env=None, fm=None, settings=None):
 		from ranger.gui.ui import UI
@@ -17,11 +49,12 @@ class Displayable(EnvironmentAware, FileManagerAware, SettingsAware):
 		if settings is not None:
 			self.settings = settings
 
+		self.focused = False
+		self.visible = True
 		self.x = 0
 		self.y = 0
 		self.wid = 0
 		self.hei = 0
-		self.colorscheme = self.settings.colorscheme
 		self.parent = None
 
 		if win is not None:
@@ -57,7 +90,7 @@ class Displayable(EnvironmentAware, FileManagerAware, SettingsAware):
 	def color(self, keylist = None, *keys):
 		"""Change the colors from now on."""
 		keys = combine(keylist, keys)
-		attr = self.colorscheme.get_attr(*keys)
+		attr = self.settings.colorscheme.get_attr(*keys)
 		try:
 			self.win.attrset(attr)
 		except _curses.error:
@@ -66,7 +99,7 @@ class Displayable(EnvironmentAware, FileManagerAware, SettingsAware):
 	def color_at(self, y, x, wid, keylist = None, *keys):
 		"""Change the colors at the specified position"""
 		keys = combine(keylist, keys)
-		attr = self.colorscheme.get_attr(*keys)
+		attr = self.settings.colorscheme.get_attr(*keys)
 		try:
 			self.win.chgat(y, x, wid, attr)
 		except _curses.error:
@@ -107,15 +140,6 @@ class Displayable(EnvironmentAware, FileManagerAware, SettingsAware):
 		"""
 		pass
 
-	def activate(self, boolean):
-		boolean = bool(boolean)
-		self.visible = boolean
-		self.focused = boolean
-	
-	def show(self, boolean):
-		boolean = bool(boolean)
-		self.visible = boolean
-
 	def poke(self):
 		"""Called before drawing, even if invisible"""
 	
@@ -162,7 +186,6 @@ class Displayable(EnvironmentAware, FileManagerAware, SettingsAware):
 
 		if hei != self.hei or wid != self.wid:
 			try:
-#				log("resizing " + self.__class__.__name__)
 				self.win.resize(hei, wid)
 			except:
 				# Not enough space for resizing...
@@ -189,7 +212,23 @@ class Displayable(EnvironmentAware, FileManagerAware, SettingsAware):
 				self.x += self.parent.x
 
 class DisplayableContainer(Displayable):
-	container = None
+	"""
+	DisplayableContainers are Displayables which contain other Displayables.
+
+	This is also an abstract class. The methods draw, poke, finalize,
+	click, press and destroy are overridden here and will recursively
+	call the function on all contained objects.
+
+	New methods:
+
+	add_child(object) -- add the object to the container.
+	remove_child(object) -- remove the object from the container.
+
+	New attributes:
+
+	container -- a list with all contained objects (rw)
+	"""
+
 	def __init__(self, win, env=None, fm=None, settings=None):
 		if env is not None:
 			self.env = env
@@ -198,9 +237,12 @@ class DisplayableContainer(Displayable):
 		if settings is not None:
 			self.settings = settings
 
-		Displayable.__init__(self, win)
 		self.container = []
 
+		Displayable.__init__(self, win)
+	
+	# ----------------------------------------------- overrides
+
 	def poke(self):
 		"""Recursively called on objects in container"""
 		for displayable in self.container:
@@ -217,24 +259,10 @@ class DisplayableContainer(Displayable):
 		for displayable in self.container:
 			if displayable.visible:
 				displayable.finalize()
-	
-	def get_focused_obj(self):
-		"""Finds a focused displayable object in the container."""
-		for displayable in self.container:
-			if displayable.focused:
-				return displayable
-			try:
-				obj = displayable.get_focused_obj()
-			except AttributeError:
-				pass
-			else:
-				if obj is not None:
-					return obj
-		return None
 
 	def press(self, key):
 		"""Recursively called on objects in container"""
-		focused_obj = self.get_focused_obj()
+		focused_obj = self._get_focused_obj()
 
 		if focused_obj:
 			focused_obj.press(key)
@@ -243,7 +271,7 @@ class DisplayableContainer(Displayable):
 
 	def click(self, event):
 		"""Recursively called on objects in container"""
-		focused_obj = self.get_focused_obj()
+		focused_obj = self._get_focused_obj()
 		if focused_obj and focused_obj.click(event):
 			return True
 
@@ -254,16 +282,43 @@ class DisplayableContainer(Displayable):
 
 		return False
 
-	def add_obj(self, *objs):
-		self.container.extend(objs)
-		for obj in objs:
-			obj.parent = self
-
 	def destroy(self):
 		"""Recursively called on objects in container"""
 		for displayable in self.container:
 			displayable.destroy()
 
+	# ----------------------------------------------- new methods
+
+	def add_child(self, obj):
+		"""Add the objects to the container."""
+		if obj.parent:
+			obj.parent.remove_child(obj)
+		self.container.append(obj)
+		obj.parent = self
+	
+	def remove_child(self, obj):
+		"""Remove the object from the container."""
+		try:
+			container.remove(obj)
+		except ValueError:
+			pass
+		else:
+			obj.parent = None
+	
+	def _get_focused_obj(self):
+		# Finds a focused displayable object in the container.
+		for displayable in self.container:
+			if displayable.focused:
+				return displayable
+			try:
+				obj = displayable._get_focused_obj()
+			except AttributeError:
+				pass
+			else:
+				if obj is not None:
+					return obj
+		return None
+
 class OutOfBoundsException(Exception):
 	pass