Hi!

Now the filechooser uses a Pile widget with both flow and box widgets.


Rebecca


#!/usr/bin/env  python

"""
A filechooser for urwid.

Author: Rebecca Breu ([EMAIL PROTECTED])
License: GPL
"""


from urwid import *
from urwid import WidgetWrap

import os
from os.path import normpath, abspath, join

__all__ = ["FileChooser"]


######################################################################
class SelText(Text):
    """
    A selectable text widget. See urwid.Text.
    """

    def selectable(self):
        """
        Make widget selectable.
        """
        return True


    def keypress(self, size, key):
        """
        Don't handle any keys.
        """
        return key


######################################################################
class FileChooser(WidgetWrap):
    """
    Creates a dialog (BoxWidget) for choosing a file.
    
    It displays the subdirectories and files in the selected directory in two 
    different ListBoxes, and the whole filename of the selected file in an
    Edit widget. The user can choose from the ListBoxes, or type an arbitrary
    path in the Edit widget. After pressing enter in the Edit widget, the
    ListBoxes will be updated accordingly. 

    The FileChooser has some text in English, but one can easiliy create a new 
    widget inheriting from FileChooser and alter the string constants
    SELECTION_TEXT and SHOW_HIDDEN_TEXT.
    """

    SELECTION_TEXT = "Selection"
    SHOW_HIDDEN_TEXT = "Show hidden files"
    
    _blank = Text("")
    
    def __init__(self, directory=".", file="", attr=(None, None),
                 show_hidden=False):
        """
        directory, file -- default selection
        attr -- (inner selectable widgets, selected widgets)
        show_hidden -- If True, hidden files are shown by default.
        """

        selection = None
        b_pressed = None
        
        self.directory = abspath(directory)
        self.file = ""
        self.attr = attr
        self.show_hidden=show_hidden
        
        #Create dummy widgets for directory and file display:
        self.dir_widget = AttrWrap(ListBox([self._blank]), self.attr[0])
        self.file_widget = AttrWrap(ListBox([self._blank]), self.attr[0])

        columns = Columns([self.dir_widget, self.file_widget], 1)

        #Selection widget:
        self.select_widget = AttrWrap(Edit("", ""),
                                      self.attr[0], self.attr[1])

        #Buttons and checkbox:
        button_widgets = [AttrWrap(Button(button, self._action),
                                   attr[0], attr[1])
                          for button in ["OK", "Cancel"]]
        button_grid = GridFlow(button_widgets, 12, 2, 1, 'center')

        button_cols = Columns([CheckBox(self.SHOW_HIDDEN_TEXT,
                                        self.show_hidden,
                                        False, self._toggle_hidden),
                               button_grid])
        
        self.outer_widget = Pile([("flow", self._blank),
                                  columns,
                                  ("flow", self._blank),
                                  ("flow", Text(self.SELECTION_TEXT)),
                                  ("flow", self.select_widget),
                                  ("flow", self._blank),
                                  ("flow", button_cols),
                                  ("flow", self._blank),
                                  ])
        
        self.update_widgets()
       
        WidgetWrap.__init__(self, self.outer_widget)


    def _dirfiles(self, directory):
        """
        Get a list of all directories and files in directory.
        List contains hidden files/dirs only if self.show_hidden is True.
        """
        
        dirlist = [".", ".."]
        filelist = []

        for entry in os.listdir(directory):
            path = os.path.join(directory, entry)
            if self.show_hidden or not entry.startswith("."):
                if os.path.isdir(path):
                    dirlist.append(entry)
                elif os.path.isfile(path):
                    filelist.append(entry)
                else:
                    pass

        return (dirlist, filelist)


    def update_widgets(self, update_dir=True, update_file=True,
                       update_select=True):
        """
        Update self.dir_widget, self.file_widget or self.select_widget,
        corresponding to which of the paramters are set to True.
        """

        if update_dir or update_file:
            (dirlist, filelist) = self._dirfiles(self.directory)

        if update_dir:
            #Directory widget:
            widget_list = [AttrWrap(SelText(dir), None, self.attr[1])
                           for dir in dirlist]

            self.dir_widget.w.body = SimpleListWalker(widget_list)

        if update_file:
            #File widget:
            widget_list = [AttrWrap(SelText(dir), None, self.attr[1])
                           for dir in filelist]

            self.file_widget.w.body = SimpleListWalker(widget_list)

        if update_select:
            #Selection widget:
            selected_file = join(self.directory, self.file)
            self.select_widget.set_edit_text(selected_file)
        


    def _focused_widgets(self):
        """
        Return a list of focused widgets.
        """

        focused = [self.outer_widget]
        widget = self.outer_widget

        while hasattr(widget, "get_focus"):
            widget = widget.get_focus()
            try:
                focused.append(widget[0])
            except AttributeError:
                focused.append(widget)

        return focused
    

    def _action(self, button):
        """
        Function called when a button is pressed.
        Should not be called manually.
        """

        if button.get_label() == "OK":
            self.selection = self.select_widget.get_edit_text()
            
        self.b_pressed = button.get_label()
        


    def _toggle_hidden(self, checkbox, new_state):
        """
        Function called when the \"Show hidden files\" checkbox
        ist toggled.
        Should not be called manually.
        """
        
        self.show_hidden = new_state
        self.update_widgets(True, True)


    def keypress(self, size, key):
        """
        <RETURN> key selects a path or file, other keys will be passed to
        the Pile widget.
        """

        if key == "enter":
            focused = self._focused_widgets()
            if focused[-2] == self.dir_widget:
                #User has selected a directory from the list:
                new_dir = focused[-1].w.get_text()[0]
                self.directory = normpath(join(self.directory, new_dir))
                self.file = ""
                self.update_widgets()
                return
            elif focused[-2] == self.file_widget:
                #User has selected a file from the list:
                self.file = focused[-1].w.get_text()[0]
                focus = (self.dir_widget.get_focus()[1],
                         self.file_widget.get_focus()[1])
                self.update_widgets(False, False, True)
                return
            elif focused[-1] == self.select_widget:
                #User has pressed enter in the "Selection Widget":
                path = self.select_widget.get_edit_text()
                (self.directory, self.file) = os.path.split(path)
                self.update_widgets(True, True, False)
                return
        
        return self.outer_widget.keypress(size, key)


    def mouse_event(self, size, event, button, col, row, focus):
        """
        First mouse button selects a path or file, other keys will be passed to
        the Pile widget.
        """
        handled = self.outer_widget.mouse_event(size, event, button, col, row,
                                                focus)
        
        if event == "mouse press" and button == 1:
            focused = self._focused_widgets()
            if focused[-2] == self.dir_widget:
                #User has selected a directory from the list:
                new_dir = focused[-1].w.get_text()[0]
                self.directory = normpath(join(self.directory, new_dir))
                self.file = ""
                self.update_widgets()
                return
            elif focused[-2] == self.file_widget:
                #User has selected a file from the list:
                self.file = focused[-1].w.get_text()[0]
                focus = (self.dir_widget.get_focus()[1],
                         self.file_widget.get_focus()[1])
                self.update_widgets(False, False, True)
                return

            handled = True

        return handled

           

######################################################################
#End of module part
######################################################################
    
def main():

    global selection
    global ui
    
    ui = urwid.curses_display.Screen()

    ui.register_palette(
        [('menu', 'black', 'dark cyan', 'standout'),
         ('menuf', 'black', 'light gray'),
         ('bg', 'light gray', 'dark blue'),
         ])

    ui.run_wrapper(run)
    
    print selection


def run():
    
    global selection
    global ui
    
    ui.set_mouse_tracking()
    dim = ui.get_cols_rows()

    widget = AttrWrap(FileChooser(attr=("menu", "menuf")), "bg");

    keys = True

    while True:
        if keys:
            ui.draw_screen(dim, widget.render(dim, True))
            
        keys = ui.get_input()

        if widget.b_pressed == "OK":
            selection = "You selected: " + widget.selection
            return
        
        if widget.b_pressed == "Cancel":
            selection = "No file selected."
            return
        
        if "window resize" in keys:
            dim = ui.get_cols_rows()
            
        for k in keys:
            if urwid.is_mouse_event(k):
                event, button, col, row = k
                widget.mouse_event(dim, event, button, col, row, focus=True)
            else:
                widget.keypress(dim, k)


 
if __name__ == "__main__":
    import urwid
    import urwid.curses_display
    main()
_______________________________________________
Urwid mailing list
[email protected]
http://lists.excess.org/mailman/listinfo/urwid

Reply via email to