view frontends/primitivus/custom_widgets.py @ 113:e5ca22113280

Primitivus: profile manager - new custom widgets: Password, List, GenericDialog, InputDialog, ConfirmationDialog
author Goffi <goffi@goffi.org>
date Thu, 01 Jul 2010 15:35:56 +0800
parents
children 77f48939ad6e
line wrap: on
line source

#!/usr/bin/python
# -*- coding: utf-8 -*-

"""
Primitivus: a SAT frontend
Copyright (C) 2009, 2010  Jérôme Poisson (goffi@goffi.org)

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>.
"""

import urwid

class Password(urwid.Edit):

    def __init__(self, *args, **kwargs):
        self.hidden_char=kwargs['hidden_char'] if kwargs.has_key('hidden_char') else '*'
        self.__real_text=''
        super(Password, self).__init__(*args, **kwargs)

    def set_edit_text(self, text):
        self.__real_text = text
        hidden_txt = len(text)*'*'
        super(Password, self).set_edit_text(hidden_txt)

    def get_edit_text(self):
        return self.__real_text

class SelectableText(urwid.FlowWidget):
    signals = ['change']
    
    def __init__(self, text, align='left'):
        self.text=unicode(text)
        self.align = align
        self.__selected=False

    def getValue(self):
        return self.text
    
    def setState(self, selected, invisible=False):
        """Change state
        @param selected: boolean state value
        @param invisible: don't emit change signal if True"""
        assert(type(selected)==bool)
        self.__selected=selected
        if not invisible:
            self._emit("change", self.__selected)
        self._invalidate()
   
    def getState(self):
        return self.__selected

    def selectable(self):
        return True

    def keypress(self, size, key):
        if key==' ' or key=='enter':
            self.setState(not self.__selected)
        else:
            return key

    def rows(self,size,focus=False):
        return self.display_widget(size, focus).rows(size, focus)

    def render(self, size, focus=False):
        return self.display_widget(size, focus).render(size, focus)

    def display_widget(self, size, focus):
        attr = 'selected' if self.__selected else 'default'
        if focus:
            attr+="_focus"
        return urwid.Text((attr,self.text), align=self.align)

class List(urwid.WidgetWrap):
    signals = ['change']

    def __init__(self, options, style=[], align='left', on_state_change=None, user_data=None):
        assert(options)
        self.single = 'single' in style
        self.align = align
        
        if on_state_change:
            urwid.connect_signal(self, 'change', on_state_change, user_data)
        
        widgets = [SelectableText(option,align) for option in options]
        for widget in widgets:
            urwid.connect_signal(widget, 'change', self.__onStateChange)
        self.content = urwid.SimpleListWalker(widgets)
        self.list_box = urwid.ListBox(self.content)
        if self.single:
            self.content[0].setState(True)
        display_widget = urwid.BoxAdapter(self.list_box, min(len(options),5))
        
        urwid.WidgetWrap.__init__(self, display_widget)

    def __onStateChange(self, widget, selected):
        if self.single:
            if not selected:
                #if in single mode, it's forbidden to unselect a value
                widget.setState(True, invisible=True)
                return
            else:
                self.unselectAll(invisible=True)
                widget.setState(True, invisible=True)
        self._emit("change")


    def unselectAll(self, invisible=False):
        for widget in self.content:
            if widget.getState():
                widget.setState(False, invisible)
                widget._invalidate()

    def getValues(self):
        result = []
        for widget in self.content:
            if widget.getState():
                result.append(widget.getValue())
        return result

    def changeValues(self, new_values):
        widgets = [SelectableText(self, option) for option in new_values]
        self.content[:] = widgets
        
    def selectValue(self, value):
        self.unselectAll()
        idx = 0
        for widget in self.content:
            if widget.getValue() == value:
                widget.setState(True)
                self.list_box.set_focus(idx)
                return
            idx+=1

class genericDialog(urwid.WidgetWrap):

    def __init__(self, widgets_lst, title, style=[], **kwargs):
        frame_header = urwid.AttrMap(urwid.Text(title,'center'),'title')
       
        buttons = None

        if "OK/CANCEL" in style:
            buttons = [urwid.Button(_("Cancel"), kwargs['cancel_cb']),
                      urwid.Button(_("Ok"), kwargs['ok_cb'], kwargs['ok_value'])]
        elif "YES/NO" in style:
            buttons = [urwid.Button(_("Yes"), kwargs['yes_cb']),
                      urwid.Button(_("No"), kwargs['no_cb'], kwargs['yes_value'])]
        if buttons:
            buttons_flow = urwid.GridFlow(buttons, max([len(button.get_label()) for button in buttons])+4, 1, 1, 'center')
            widgets_lst.append(buttons_flow)
        body_content = urwid.SimpleListWalker(widgets_lst)
        frame_body = urwid.ListBox(body_content)
        frame = urwid.Frame(frame_body, frame_header)
        decorated_frame = urwid.LineBox(frame)
        urwid.WidgetWrap.__init__(self, decorated_frame)



class InputDialog(genericDialog):

    def __init__(self, title, instrucions, style=['OK/CANCEL'], **kwargs):
        instr_wid = urwid.Text(instrucions+':')
        edit_box = urwid.Edit()
        genericDialog.__init__(self, [instr_wid,edit_box], title, style, ok_value=edit_box, **kwargs)

class ConfirmDialog(genericDialog):

    def __init__(self, title, style=['YES/NO'], **kwargs):
        genericDialog.__init__(self, [], title, style, yes_value=None, **kwargs)