diff options
-rw-r--r-- | TODO | 3 | ||||
-rw-r--r-- | ranger/gui/defaultui.py | 22 | ||||
-rw-r--r-- | ranger/gui/displayable.py | 135 | ||||
-rw-r--r-- | ranger/gui/widgets/filelistcontainer.py | 18 | ||||
-rw-r--r-- | test/tc_displayable.py | 12 | ||||
-rw-r--r-- | test/tc_ui.py | 2 |
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() |