~ubuntu-branches/ubuntu/quantal/wicd/quantal

« back to all changes in this revision

Viewing changes to curses/curses_misc.py

  • Committer: Bazaar Package Importer
  • Author(s): David Paleino
  • Date: 2009-06-22 17:59:27 UTC
  • mfrom: (1.1.4 upstream)
  • Revision ID: james.westby@ubuntu.com-20090622175927-iax3alden0bmj6zg
Tags: 1.6.1-3
* debian/config, debian/templates updated:
  - only show users to add to netdev, skip those who are already
    members (Closes: #534138)
  - gracefully handle upgrades from previous broken versions, where
    debconf set a value of ${default} for wicd/users
    (Closes: #532112)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#!/usr/bin/env python
 
2
# -* coding: utf-8 -*-
 
3
 
 
4
""" curses_misc.py: Module for various widgets that are used throughout 
 
5
wicd-curses.
 
6
"""
 
7
 
 
8
#       Copyright (C) 2008-2009 Andrew Psaltis
 
9
 
 
10
#       This program is free software; you can redistribute it and/or modify
 
11
#       it under the terms of the GNU General Public License as published by
 
12
#       the Free Software Foundation; either version 2 of the License, or
 
13
#       (at your option) any later version.
 
14
#       
 
15
#       This program is distributed in the hope that it will be useful,
 
16
#       but WITHOUT ANY WARRANTY; without even the implied warranty of
 
17
#       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
18
#       GNU General Public License for more details.
 
19
#       
 
20
#       You should have received a copy of the GNU General Public License
 
21
#       along with this program; if not, write to the Free Software
 
22
#       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 
23
#       MA 02110-1301, USA.
 
24
 
 
25
import urwid
 
26
 
 
27
# Uses code that is towards the bottom
 
28
def error(ui,parent,message):
 
29
    """Shows an error dialog (or something that resembles one)"""
 
30
    #     /\
 
31
    #    /!!\
 
32
    #   /____\
 
33
    dialog = TextDialog(message,6,40,('important',"ERROR"))
 
34
    return dialog.run(ui,parent)
 
35
 
 
36
# My savior.  :-)
 
37
# Although I could have made this myself pretty easily, just want to give credit
 
38
# where it's due.
 
39
# http://excess.org/urwid/browser/contrib/trunk/rbreu_filechooser.py
 
40
class SelText(urwid.Text):
 
41
    """A selectable text widget. See urwid.Text."""
 
42
 
 
43
    def selectable(self):
 
44
        """Make widget selectable."""
 
45
        return True
 
46
 
 
47
 
 
48
    def keypress(self, size, key):
 
49
        """Don't handle any keys."""
 
50
        return key
 
51
 
 
52
# ListBox that can't be selected.
 
53
class NSelListBox(urwid.ListBox):
 
54
    def selectable(self):
 
55
        return False
 
56
 
 
57
# This class is annoying.  :/
 
58
class DynWrap(urwid.AttrWrap):
 
59
    """
 
60
    Makes an object have mutable selectivity.  Attributes will change like
 
61
    those in an AttrWrap
 
62
 
 
63
    w = widget to wrap
 
64
    sensitive = current selectable state
 
65
    attrs = tuple of (attr_sens,attr_not_sens)
 
66
    attrfoc = attributes when in focus, defaults to nothing
 
67
    """
 
68
 
 
69
    def __init__(self,w,sensitive=True,attrs=('editbx','editnfc'),focus_attr='editfc'):
 
70
        self._attrs=attrs
 
71
        self._sensitive = sensitive
 
72
        
 
73
        cur_attr = attrs[0] if sensitive else attrs[1]
 
74
 
 
75
        self.__super.__init__(w,cur_attr,focus_attr)
 
76
 
 
77
    def get_sensitive(self):
 
78
        return self._sensitive
 
79
    def set_sensitive(self,state):
 
80
        if state:
 
81
            self.set_attr(self._attrs[0])
 
82
        else:
 
83
            self.set_attr(self._attrs[1])
 
84
        self._sensitive = state
 
85
    property(get_sensitive,set_sensitive)
 
86
 
 
87
    def get_attrs(self):
 
88
        return self._attrs
 
89
    def set_attrs(self,attrs):
 
90
        self._attrs = attrs
 
91
    property(get_attrs,set_attrs)
 
92
 
 
93
    def selectable(self):
 
94
        return self._sensitive
 
95
 
 
96
# Just an Edit Dynwrapped to the most common specifications
 
97
class DynEdit(DynWrap):
 
98
    def __init__(self,caption='',edit_text='',sensitive=True,attrs=('editbx','editnfc'),focus_attr='editfc'):
 
99
        caption = ('editcp',caption + ': ')
 
100
        edit = urwid.Edit(caption,edit_text)
 
101
        self.__super.__init__(edit,sensitive,attrs,focus_attr)
 
102
 
 
103
# Just an IntEdit Dynwrapped to the most common specifications
 
104
class DynIntEdit(DynWrap):
 
105
    def __init__(self,caption='',edit_text='',sensitive=True,attrs=('editbx','editnfc'),focus_attr='editfc'):
 
106
        caption = ('editcp',caption + ':')
 
107
        edit = urwid.IntEdit(caption,edit_text)
 
108
        self.__super.__init__(edit,sensitive,attrs,focus_attr)
 
109
 
 
110
class DynRadioButton(DynWrap):
 
111
    def __init__(self,group,label,state='first True',on_state_change=None, user_data=None, sensitive=True, attrs=('body','editnfc'),focus_attr='body'):
 
112
        #caption = ('editcp',caption + ':')
 
113
        button = urwid.RadioButton(group,label,state,on_state_change,user_data)
 
114
        self.__super.__init__(button,sensitive,attrs,focus_attr)
 
115
 
 
116
class MaskingEditException(Exception):
 
117
    pass
 
118
 
 
119
# Password-style edit
 
120
class MaskingEdit(urwid.Edit):
 
121
    """
 
122
    mask_mode = one of:
 
123
        "always" : everything is a '*' all of the time
 
124
        "no_focus" : everything is a '*' only when not in focus
 
125
        "off" : everything is always unmasked
 
126
    mask_char = the single character that masks all other characters in the field
 
127
    """
 
128
    def __init__(self, caption = "", edit_text = "", multiline = False,
 
129
            align = 'left', wrap = 'space', allow_tab = False,
 
130
            edit_pos = None, layout=None, mask_mode="always",mask_char='*'):
 
131
        self.mask_mode = mask_mode
 
132
        if len(mask_char) > 1:
 
133
            raise MaskingEditException('Masks of more than one character are not supported!')
 
134
        self.mask_char = mask_char
 
135
        self.__super.__init__(caption,edit_text,multiline,align,wrap,allow_tab,edit_pos,layout)
 
136
 
 
137
    def get_caption(self):
 
138
        return self.caption
 
139
    def get_mask_mode(self):
 
140
        return self.mask_mode
 
141
    def set_mask_mode(self,mode):
 
142
        self.mask_mode = mode
 
143
 
 
144
    def get_masked_text(self):
 
145
        return self.mask_char*len(self.get_edit_text())
 
146
 
 
147
    def render(self,(maxcol,), focus=False):
 
148
        """ 
 
149
        Render edit widget and return canvas.  Include cursor when in
 
150
        focus.
 
151
        """
 
152
        # If we aren't masking anything ATM, then act like an Edit.
 
153
        # No problems.
 
154
        if self.mask_mode == "off" or (self.mask_mode == 'no_focus' and focus == True):
 
155
            canv = self.__super.render((maxcol,),focus)
 
156
            # The cache messes this thing up, because I am totally changing what
 
157
            # is displayed.
 
158
            self._invalidate()
 
159
            return canv
 
160
 
 
161
        # Else, we have a slight mess to deal with...
 
162
        self._shift_view_to_cursor = not not focus # force bool
 
163
 
 
164
        text, attr = self.get_text()
 
165
        text = text[:len(self.caption)]+self.get_masked_text()
 
166
        trans = self.get_line_translation( maxcol, (text,attr) )
 
167
        canv = urwid.canvas.apply_text_layout(text, attr, trans, maxcol)
 
168
 
 
169
        if focus:
 
170
            canv = urwid.CompositeCanvas(canv)
 
171
            canv.cursor = self.get_cursor_coords((maxcol,))
 
172
 
 
173
        return canv
 
174
 
 
175
# Tabbed interface, mostly for use in the Preferences Dialog
 
176
class TabColumns(urwid.WidgetWrap):
 
177
    """
 
178
    titles_dict = dictionary of tab_contents (a SelText) : tab_widget (box)
 
179
    attr = normal attributes
 
180
    attrsel = attribute when active
 
181
    """
 
182
    # FIXME Make the bottom_part optional
 
183
    def __init__(self,tab_str,tab_wid,title,bottom_part=None,attr=('body','focus'),
 
184
            attrsel='tab active', attrtitle='header'):
 
185
        #self.bottom_part = bottom_part
 
186
        #title_wid = urwid.Text((attrtitle,title),align='right')
 
187
        column_list = []
 
188
        for w in tab_str:
 
189
            text,trash = w.get_text()
 
190
            column_list.append(('fixed',len(text),w))
 
191
        column_list.append(urwid.Text((attrtitle,title),align='right'))
 
192
 
 
193
        self.tab_map = dict(zip(tab_str,tab_wid))
 
194
        self.active_tab = tab_str[0]
 
195
        self.columns = urwid.Columns(column_list,dividechars=1)
 
196
        #walker   = urwid.SimpleListWalker([self.columns,tab_wid[0]])
 
197
        #self.listbox = urwid.ListBox(walker)
 
198
        self.gen_pile(tab_wid[0],True)
 
199
        self.frame = urwid.Frame(self.pile)
 
200
        self.__super.__init__(self.frame)
 
201
        
 
202
    # Make the pile in the middle
 
203
    def gen_pile(self,lbox,firstrun=False):
 
204
        self.pile = urwid.Pile([
 
205
            ('fixed',1,urwid.Filler(self.columns,'top')),
 
206
            urwid.Filler(lbox,'top',height=('relative',99)),
 
207
            #('fixed',1,urwid.Filler(self.bottom_part,'bottom'))
 
208
            ])
 
209
        if not firstrun:
 
210
            self.frame.set_body(self.pile)
 
211
            self.set_w(self.frame)
 
212
 
 
213
    def selectable(self):
 
214
        return True
 
215
 
 
216
    def keypress(self,size,key):
 
217
        if key == "meta [" or key == "meta ]":
 
218
            self._w.get_body().set_focus(0)
 
219
            newK = 'left' if key[-1] == '[' else 'right'
 
220
            self.keypress(size,newK)
 
221
            self._w.get_body().set_focus(1)
 
222
        else:
 
223
            key = self._w.keypress(size,key)
 
224
            wid = self.pile.get_focus().get_body()
 
225
            if wid == self.columns:
 
226
            #    lw = self.listbox.body
 
227
            #    lw.pop(1)
 
228
                self.active_tab.set_attr('body')
 
229
                self.columns.get_focus().set_attr('tab active')
 
230
                self.active_tab = self.columns.get_focus()
 
231
                self.gen_pile(self.tab_map[self.active_tab])
 
232
        
 
233
        return key
 
234
        #    self.listbox.body = lw
 
235
    def mouse_event(self,size,event,button,x,y,focus):
 
236
        wid = self.pile.get_focus().get_body()
 
237
        if wid == self.columns:
 
238
            self.active_tab.set_attr('body')
 
239
 
 
240
        self._w.mouse_event(size,event,button,x,y,focus)
 
241
        if wid == self.columns:
 
242
            self.active_tab.set_attr('body')
 
243
            self.columns.get_focus().set_attr('tab active')
 
244
            self.active_tab = self.columns.get_focus()
 
245
            self.gen_pile(self.tab_map[self.active_tab])
 
246
 
 
247
 
 
248
### Combo box code begins here
 
249
class ComboBoxException(Exception):
 
250
    pass
 
251
 
 
252
# A "combo box" of SelTexts
 
253
# I based this off of the code found here:
 
254
# http://excess.org/urwid/browser/contrib/trunk/rbreu_menus.py
 
255
# This is a hack/kludge.  It isn't without quirks, but it more or less works.
 
256
# We need to wait for changes in urwid's Canvas controls before we can actually
 
257
# make a real ComboBox.
 
258
class ComboBox(urwid.WidgetWrap):
 
259
    """A ComboBox of text objects"""
 
260
    class ComboSpace(urwid.WidgetWrap):
 
261
        """The actual menu-like space that comes down from the ComboBox"""
 
262
        def __init__(self,list,body,ui,show_first,pos=(0,0),attr=('body','focus')):
 
263
            """
 
264
            body      : parent widget
 
265
            list      : stuff to include in the combobox
 
266
            ui        : the screen
 
267
            show_first: index of the element in the list to pick first
 
268
            pos       : a tuple of (row,col) where to put the list
 
269
            attr      : a tuple of (attr_no_focus,attr_focus)
 
270
            """
 
271
            
 
272
            #Calculate width and height of the menu widget:
 
273
            height = len(list)
 
274
            width = 0
 
275
            for entry in list:
 
276
                if len(entry) > width:
 
277
                    width = len(entry)
 
278
            content = [urwid.AttrWrap(SelText(w), attr[0], attr[1])
 
279
                       for w in list]
 
280
            self._listbox = urwid.ListBox(content)
 
281
            self._listbox.set_focus(show_first)
 
282
 
 
283
            overlay = urwid.Overlay(self._listbox, body, ('fixed left', pos[0]),
 
284
                                    width + 2, ('fixed top', pos[1]), height)
 
285
            self.__super.__init__(overlay)
 
286
 
 
287
        def show(self,ui,display):
 
288
 
 
289
            dim = ui.get_cols_rows()
 
290
            keys = True
 
291
            
 
292
            #Event loop:
 
293
            while True:
 
294
                if keys:
 
295
                    ui.draw_screen(dim, self.render(dim, True))
 
296
                    
 
297
                keys = ui.get_input()
 
298
 
 
299
                if "window resize" in keys:
 
300
                    dim = ui.get_cols_rows()
 
301
                if "esc" in keys:
 
302
                    return None
 
303
                if "enter" in keys:
 
304
                    (wid,pos) = self._listbox.get_focus()
 
305
                    (text,attr) = wid.get_text()
 
306
                    return text
 
307
 
 
308
                for k in keys:
 
309
                    #Send key to underlying widget:
 
310
                    self._w.keypress(dim, k)
 
311
 
 
312
        #def get_size(self):
 
313
 
 
314
    def __init__(self,label='',list=[],attrs=('body','editnfc'),focus_attr='focus',use_enter=True,focus=0,callback=None,user_args=None):
 
315
        """
 
316
        label     : bit of text that preceeds the combobox.  If it is "", then 
 
317
                    ignore it
 
318
        list      : stuff to include in the combobox
 
319
        body      : parent widget
 
320
        ui        : the screen
 
321
        row       : where this object is to be found onscreen
 
322
        focus     : index of the element in the list to pick first
 
323
        callback  : function that takes (combobox,sel_index,user_args=None)
 
324
        user_args : user_args in the callback
 
325
        """
 
326
        
 
327
        self.DOWN_ARROW = '    vvv'
 
328
        self.label = urwid.Text(label)
 
329
        self.attrs = attrs
 
330
        self.focus_attr = focus_attr
 
331
        self.list = list
 
332
 
 
333
        str,trash =  self.label.get_text()
 
334
 
 
335
        self.overlay = None
 
336
        #w,sensitive=True,attrs=('editbx','editnfc'),focus_attr='editfc')
 
337
        self.cbox  = DynWrap(SelText(self.DOWN_ARROW),attrs=attrs,focus_attr=focus_attr)
 
338
        # Unicode will kill me sooner or later.  ^_^
 
339
        if label != '':
 
340
            w = urwid.Columns([('fixed',len(str),self.label),self.cbox],dividechars=1)
 
341
        else:
 
342
            w = urwid.Columns([self.cbox])
 
343
        self.__super.__init__(w)
 
344
 
 
345
        # We need this to pick our keypresses
 
346
        self.use_enter = use_enter
 
347
        # The Focus
 
348
        self.focus = focus
 
349
 
 
350
        # The callback and friends
 
351
        self.callback = callback
 
352
        self.user_args = user_args
 
353
 
 
354
        # Widget references to simplify some things
 
355
        self.parent = None
 
356
        self.ui = None
 
357
        self.row = None
 
358
    def set_list(self,list):
 
359
        self.list = list
 
360
 
 
361
    def set_focus(self,index):
 
362
        self.focus = index
 
363
        self.cbox.set_w(SelText(self.list[index]+self.DOWN_ARROW))
 
364
        if self.overlay:
 
365
            self.overlay._listbox.set_focus(index)
 
366
 
 
367
    def rebuild_combobox(self):
 
368
        self.build_combobox(self.parent,self.ui,self.row)
 
369
    def build_combobox(self,parent,ui,row):
 
370
        str,trash =  self.label.get_text()
 
371
 
 
372
        self.cbox = DynWrap(SelText([self.list[self.focus]+self.DOWN_ARROW]),
 
373
                attrs=self.attrs,focus_attr=self.focus_attr)
 
374
        if str != '':
 
375
            w = urwid.Columns([('fixed',len(str),self.label),self.cbox],
 
376
                    dividechars=1)
 
377
            self.overlay = self.ComboSpace(self.list,parent,ui,self.focus,
 
378
                    pos=(len(str)+1,row))
 
379
        else:
 
380
            w = urwid.Columns([self.cbox])
 
381
            self.overlay = self.ComboSpace(self.list,parent,ui,self.focus,
 
382
                    pos=(0,row))
 
383
 
 
384
        self.set_w(w)
 
385
        self.parent = parent
 
386
        self.ui = ui
 
387
        self.row = row
 
388
 
 
389
    # If we press space or enter, be a combo box!
 
390
    def keypress(self,size,key):
 
391
        activate = key == ' '
 
392
        if self.use_enter:
 
393
            activate = activate or key == 'enter'
 
394
        if activate:
 
395
            # Die if the user didn't prepare the combobox overlay
 
396
            if self.overlay == None:
 
397
                raise ComboBoxException('ComboBox must be built before use!')
 
398
            retval = self.overlay.show(self.ui,self.parent)
 
399
            if retval != None:
 
400
                self.set_focus(self.list.index(retval))
 
401
                #self.cbox.set_w(SelText(retval+'    vvv'))
 
402
                if self.callback != None:
 
403
                    self.callback(self,self.overlay._listbox.get_focus()[1],
 
404
                            self.user_args)
 
405
        return self._w.keypress(size,key)
 
406
 
 
407
    def selectable(self):
 
408
        return self.cbox.selectable()
 
409
 
 
410
    def get_focus(self):
 
411
        if self.overlay:
 
412
            return self.overlay._listbox.get_focus()
 
413
        else:
 
414
            return None,self.focus
 
415
 
 
416
    def get_sensitive(self):
 
417
        return self.cbox.get_sensitive()
 
418
    def set_sensitive(self,state):
 
419
        self.cbox.set_sensitive(state)
 
420
 
 
421
# This is a h4x3d copy of some of the code in Ian Ward's dialog.py example.
 
422
class DialogExit(Exception):
 
423
    pass
 
424
 
 
425
class Dialog2(urwid.WidgetWrap):
 
426
    def __init__(self, text, height,width, body=None ):
 
427
       self.width = int(width)
 
428
       if width <= 0:
 
429
           self.width = ('relative', 80)
 
430
       self.height = int(height)
 
431
       if height <= 0:
 
432
           self.height = ('relative', 80)
 
433
           
 
434
       self.body = body
 
435
       if body is None:
 
436
           # fill space with nothing
 
437
           body = urwid.Filler(urwid.Divider(),'top')
 
438
    
 
439
       self.frame = urwid.Frame( body, focus_part='footer')
 
440
       if text is not None:
 
441
               self.frame.header = urwid.Pile( [urwid.Text(text,align='right'),
 
442
                       urwid.Divider()] )
 
443
       w = self.frame
 
444
       self.view = w
 
445
       
 
446
       # pad area around listbox
 
447
       #w = urwid.Padding(w, ('fixed left',2), ('fixed right',2))
 
448
       #w = urwid.Filler(w, ('fixed top',1), ('fixed bottom',1))
 
449
       #w = urwid.AttrWrap(w, 'body')
 
450
 
 
451
    # buttons: tuple of name,exitcode
 
452
    def add_buttons(self, buttons):
 
453
        l = []
 
454
        for name, exitcode in buttons:
 
455
            b = urwid.Button( name, self.button_press )
 
456
            b.exitcode = exitcode
 
457
            b = urwid.AttrWrap( b, 'body','focus' )
 
458
            l.append( b )
 
459
        self.buttons = urwid.GridFlow(l, 10, 3, 1, 'center')
 
460
        self.frame.footer = urwid.Pile( [ urwid.Divider(),
 
461
            self.buttons ], focus_item = 1)
 
462
 
 
463
    def button_press(self, button):
 
464
        raise DialogExit(button.exitcode)
 
465
 
 
466
    def run(self,ui,parent):
 
467
        ui.set_mouse_tracking()
 
468
        size = ui.get_cols_rows()
 
469
        overlay = urwid.Overlay(urwid.LineBox(self.view),
 
470
                                parent, 'center', self.width,
 
471
                                'middle', self.height)
 
472
        try:
 
473
            while True:
 
474
                canvas = overlay.render( size, focus=True )
 
475
                ui.draw_screen( size, canvas )
 
476
                keys = None
 
477
                while not keys:
 
478
                    keys = ui.get_input()
 
479
                for k in keys:
 
480
                    if urwid.is_mouse_event(k):
 
481
                        event, button, col, row = k
 
482
                        overlay.mouse_event( size,
 
483
                                event, button, col, row,
 
484
                                focus=True)
 
485
                    else:
 
486
                        if k == 'window resize':
 
487
                            size = ui.get_cols_rows()
 
488
                        k = self.view.keypress( size, k )
 
489
                        if k == 'esc':
 
490
                            raise DialogExit(-1)
 
491
                        if k:
 
492
                            self.unhandled_key( size, k)
 
493
        except DialogExit, e:
 
494
            return self.on_exit( e.args[0] )
 
495
               
 
496
    def on_exit(self, exitcode):
 
497
        return exitcode, ""
 
498
 
 
499
    def unhandled_key(self, size, key):
 
500
        pass
 
501
 
 
502
# Simple dialog with text in it and "OK"
 
503
class TextDialog(Dialog2):
 
504
    def __init__(self, text, height, width, header=None,align='left'):
 
505
        l = [urwid.Text(text)]
 
506
        #for line in text:
 
507
        #    l.append( urwid.Text( line,align=align))
 
508
        body = urwid.ListBox(l)
 
509
        body = urwid.AttrWrap(body, 'body')
 
510
 
 
511
        Dialog2.__init__(self, header, height+2, width+2, body)
 
512
        self.add_buttons([('OK',1)])
 
513
 
 
514
 
 
515
    def unhandled_key(self, size, k):
 
516
        if k in ('up','page up','down','page down'):
 
517
            self.frame.set_focus('body')
 
518
            self.view.keypress( size, k )
 
519
            self.frame.set_focus('footer')
 
520
 
 
521
class InputDialog(Dialog2):
 
522
    def __init__(self, text, height, width,ok_name='OK',edit_text=''):
 
523
        self.edit = urwid.Edit(wrap='clip',edit_text=edit_text)
 
524
        body = urwid.ListBox([self.edit])
 
525
        body = urwid.AttrWrap(body, 'editbx','editfc')
 
526
       
 
527
        Dialog2.__init__(self, text, height, width, body)
 
528
       
 
529
        self.frame.set_focus('body')
 
530
        self.add_buttons([(ok_name,0),('Cancel',-1)])
 
531
       
 
532
    def unhandled_key(self, size, k):
 
533
        if k in ('up','page up'):
 
534
            self.frame.set_focus('body')
 
535
        if k in ('down','page down'):
 
536
            self.frame.set_focus('footer')
 
537
        if k == 'enter':
 
538
            # pass enter to the "ok" button
 
539
            self.frame.set_focus('footer')
 
540
            self.view.keypress( size, k )
 
541
       
 
542
    def on_exit(self, exitcode):
 
543
        return exitcode, self.edit.get_edit_text()
 
544
 
 
545
 
 
546
class ClickCols(urwid.WidgetWrap):
 
547
    def __init__(self,items,callback=None,args=None):
 
548
        cols = urwid.Columns(items)
 
549
        self.__super.__init__(cols)
 
550
        self.callback = callback
 
551
        self.args = args
 
552
    def mouse_event(self,size,event,button,x,y,focus):
 
553
        if event == "mouse press":
 
554
            # The keypress dealie in wicd-curses.py expects a list of keystrokes
 
555
            self.callback([self.args])
 
556
 
 
557
# htop-style menu menu-bar on the bottom of the screen
 
558
class OptCols(urwid.WidgetWrap):
 
559
    # tuples = [(key,desc)], on_event gets passed a key
 
560
    # attrs = (attr_key,attr_desc)
 
561
    # handler = function passed the key of the "button" pressed
 
562
    # mentions of 'left' and right will be converted to <- and -> respectively
 
563
    def __init__(self,tuples,handler,attrs=('body','infobar'),debug=False):
 
564
        # Find the longest string.  Keys for this bar should be no greater than
 
565
        # 2 characters long (e.g., -> for left)
 
566
        #maxlen = 6
 
567
        #for i in tuples:
 
568
        #    newmax = len(i[0])+len(i[1])
 
569
        #    if newmax > maxlen:
 
570
        #        maxlen = newmax
 
571
        
 
572
        # Construct the texts
 
573
        textList = []
 
574
        i = 0
 
575
        # callbacks map the text contents to its assigned callback.
 
576
        self.callbacks = []
 
577
        for cmd in tuples:
 
578
            splitcmd = cmd[0].split()
 
579
            key = ''
 
580
            for part in splitcmd:
 
581
                if part == 'ctrl':
 
582
                    key+='Ctrl+'
 
583
                elif part == 'meta':
 
584
                    # If anyone has a problem with this, they can bother me
 
585
                    # about it.
 
586
                    key+='Alt+'
 
587
                else:
 
588
                   if part == 'left':
 
589
                       key += '<-'
 
590
                   elif part == 'right':
 
591
                       key += '->'
 
592
                   elif part == 'esc':
 
593
                       key += 'ESC'
 
594
                   elif part == 'enter':
 
595
                       key += 'Enter'
 
596
                   else:
 
597
                       key += part
 
598
            
 
599
            #theText = urwid.Text([(attrs[0],cmd[0]),(attrs[1],cmd[1])])
 
600
            if debug:
 
601
                callback = self.debugClick
 
602
                args = cmd[1]
 
603
            else:
 
604
                callback = handler
 
605
                args = cmd[0]
 
606
            #self.callbacks.append(cmd[2])
 
607
            col = ClickCols([
 
608
                ('fixed',len(key)+1,urwid.Text((attrs[0],key+':')) ),
 
609
                              urwid.AttrWrap(urwid.Text(cmd[1]),attrs[1])],
 
610
                              callback,args)
 
611
            #if i != len(tuples)-1:
 
612
            #    textList.append(('fixed',maxlen,col))
 
613
            #else: # The last one
 
614
            textList.append(col)
 
615
            i+=1
 
616
        if debug:
 
617
            self.debug = urwid.Text("DEBUG_MODE")
 
618
            textList.append(('fixed',10,self.debug))
 
619
            
 
620
        cols = urwid.Columns(textList)
 
621
        self.__super.__init__(cols)
 
622
    def debugClick(self,args):
 
623
        self.debug.set_text(args)
 
624
 
 
625
    def mouse_event(self,size,event,button,x,y,focus):
 
626
        # Widgets are evenly long (as of current), so...
 
627
        return self._w.mouse_event(size,event,button,x,y,focus)
 
628
        """
 
629
        if self.debug:
 
630
            if x > size[0]-10:
 
631
                return
 
632
            widsize = (size[0]-10)/len(self.callbacks)
 
633
        else:
 
634
            widsize = size[0]/len(self.callbacks)
 
635
        widnum = x/widsize
 
636
        if self.debug:
 
637
            text = str(widnum)
 
638
            if self.callbacks[widnum] == None:
 
639
                text += " None"
 
640
            self.debug.set_text(text)
 
641
        elif self.callbacks[widnum] != None:
 
642
            self.callbacks[widnum]()
 
643
        """