summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorhut <hut@lavabit.com>2009-12-31 03:40:08 +0100
committerhut <hut@lavabit.com>2009-12-31 03:40:08 +0100
commita6791aeef4c62960563882796d993873febe7b9c (patch)
tree33f5d9f01607b0795641960436c03160cc232201
parentcd603ff4d0573c407c82f40cba9a164f7373585d (diff)
downloadranger-a6791aeef4c62960563882796d993873febe7b9c.tar.gz
added documentation, clean up
-rw-r--r--TODO3
-rw-r--r--ranger/gui/defaultui.py22
-rw-r--r--ranger/gui/displayable.py135
-rw-r--r--ranger/gui/widgets/filelistcontainer.py18
-rw-r--r--test/tc_displayable.py12
-rw-r--r--test/tc_ui.py2
6 files changed, 128 insertions, 64 deletions
diff --git a/TODO b/TODO
index f0024ac5..7b92c24b 100644
--- a/TODO
+++ b/TODO
@@ -9,7 +9,6 @@ Console
 
 General
 
-   ( ) #3   09/12/06  MVC for widgets
    (X) #5   09/12/06  move code from fm into objects
    (X) #6   09/12/06  move main to __init__
    (X) #7   09/12/06  cooler titlebar
@@ -18,5 +17,5 @@ General
    (X) #10  09/12/24  sorting
    (X) #11  09/12/27  filter
    (X) #12  09/12/27  jump through the list in a specific order
-   ( ) #14  09/12/29  make filelists inherit from pagers
+   (X) #14  09/12/29  make filelists inherit from pagers
    ( ) #15  09/12/29  better way of running processes!!~
diff --git a/ranger/gui/defaultui.py b/ranger/gui/defaultui.py
index 717bb925..08ec0b4b 100644
--- a/ranger/gui/defaultui.py
+++ b/ranger/gui/defaultui.py
@@ -13,28 +13,36 @@ class DefaultUI(UI):
 		from ranger.gui.widgets.notify import Notify
 		from ranger.gui.widgets.pager import Pager
 
+		# Create a title bar
 		self.titlebar = TitleBar(self.win)
-		self.add_obj(self.titlebar)
+		self.add_child(self.titlebar)
 
+		# Create the container for the filelists
 		self.filelist_container = FileListContainer(self.win, RATIO)
-		self.add_obj(self.filelist_container)
+		self.add_child(self.filelist_container)
 		self.main_filelist = self.filelist_container.main_filelist
 
+		# Create the process manager
 		self.pman = ProcessManager(self.win)
 		self.pman.visible = False
-		self.add_obj(self.pman)
+		self.add_child(self.pman)
 
+		# Create the (initially hidden) notify bar
 		self.notify = Notify(self.win)
-		self.add_obj(self.notify)
+		self.add_child(self.notify)
 
+		# Create the status bar
 		self.status = StatusBar(self.win, self.main_filelist)
-		self.add_obj(self.status)
+		self.add_child(self.status)
+
+		# Create the console
 		self.console = Console(self.win)
-		self.add_obj(self.console)
+		self.add_child(self.console)
 		self.console.visible = False
 
+		# Create the pager
 		self.pager = Pager(self.win)
-		self.add_obj(self.pager)
+		self.add_child(self.pager)
 
 	def update_size(self):
 		"""resize all widgets"""
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
 
diff --git a/ranger/gui/widgets/filelistcontainer.py b/ranger/gui/widgets/filelistcontainer.py
index b5ef4190..ed1922b8 100644
--- a/ranger/gui/widgets/filelistcontainer.py
+++ b/ranger/gui/widgets/filelistcontainer.py
@@ -30,7 +30,7 @@ class FileListContainer(Widget, DisplayableContainer):
 
 		for level in range(len(ratios)):
 			fl = FileList(self.win, level + offset)
-			self.add_obj(fl)
+			self.add_child(fl)
 
 		try:
 			self.main_filelist = self.container[preview and -2 or -1]
@@ -41,7 +41,7 @@ class FileListContainer(Widget, DisplayableContainer):
 			self.main_filelist.main_display = True
 
 		self.pager = Pager(self.win, embedded=True)
-		self.add_obj(self.pager)
+		self.add_child(self.pager)
 	
 	def resize(self, y, x, hei, wid):
 		"""Resize all the filelists according to the given ratio"""
@@ -84,20 +84,22 @@ class FileListContainer(Widget, DisplayableContainer):
 			DisplayableContainer.click(self, event)
 	
 	def open_pager(self):
-		self.pager.activate(True)
+		self.pager.visible = True
+		self.pager.focused = True
 		self.pager.open()
 		try:
-			self.container[-2].show(False)
-			self.container[-3].show(False)
+			self.container[-2].visible = False
+			self.container[-3].visible = False
 		except IndexError:
 			pass
 	
 	def close_pager(self):
-		self.pager.activate(False)
+		self.pager.visible = False
+		self.pager.focused = False
 		self.pager.close()
 		try:
-			self.container[-2].show(True)
-			self.container[-3].show(True)
+			self.container[-2].visible = True
+			self.container[-3].visible = True
 		except IndexError:
 			pass
 	
diff --git a/test/tc_displayable.py b/test/tc_displayable.py
index 3acf338b..d7466809 100644
--- a/test/tc_displayable.py
+++ b/test/tc_displayable.py
@@ -74,7 +74,7 @@ class TestDisplayableContainer(unittest.TestCase):
 
 		self.disp = Displayable(**self.initdict)
 		self.disc = DisplayableContainer(**self.initdict)
-		self.disc.add_obj(self.disp)
+		self.disc.add_child(self.disp)
 
 		hei, wid = (100, 100)
 		self.env.termsize = (hei, wid)
@@ -103,20 +103,20 @@ class TestDisplayableContainer(unittest.TestCase):
 	def test_focused_object(self):
 		d1 = Displayable(**self.initdict)
 		d2 = DisplayableContainer(**self.initdict)
-		d2.add_obj(*[Displayable(**self.initdict) for x in range(5)])
+		d2.add_child(*[Displayable(**self.initdict) for x in range(5)])
 		d3 = DisplayableContainer(**self.initdict)
-		d3.add_obj(*[Displayable(**self.initdict) for x in range(5)])
+		d3.add_child(*[Displayable(**self.initdict) for x in range(5)])
 
-		self.disc.add_obj(d1, d2, d3)
+		self.disc.add_child(d1, d2, d3)
 
 		d3.container[3].focused = True
 
-		self.assertEqual(self.disc.get_focused_obj(), d3.container[3])
+		self.assertEqual(self.disc._get_focused_obj(), d3.container[3])
 
 		d3.container[3].focused = False
 		d2.container[0].focused = True
 
-		self.assertEqual(self.disc.get_focused_obj(), d2.container[0])
+		self.assertEqual(self.disc._get_focused_obj(), d2.container[0])
 
 if __name__ == '__main__':
 	unittest.main()
diff --git a/test/tc_ui.py b/test/tc_ui.py
index f509ff36..eb503c5d 100644
--- a/test/tc_ui.py
+++ b/test/tc_ui.py
@@ -17,7 +17,7 @@ class Test(unittest.TestCase):
 
 		def fakesetup():
 			self.ui.widget = Fake()
-			self.ui.add_obj(self.ui.widget)
+			self.ui.add_child(self.ui.widget)
 		self.ui.setup = fakesetup
 
 		self.ui.initialize()
'n841' href='#n841'>841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994