comparison urwid_satext/sat_widgets.py @ 66:287ff3e1edd1

removed trailing spaces
author Goffi <goffi@goffi.org>
date Sat, 21 Dec 2013 16:51:14 +0100
parents 090f3e0754d3
children c270867a80f9
comparison
equal deleted inserted replaced
65:090f3e0754d3 66:287ff3e1edd1
39 """Define method called when completion is asked 39 """Define method called when completion is asked
40 @callback: method with 2 arguments: 40 @callback: method with 2 arguments:
41 - the text to complete 41 - the text to complete
42 - if there was already a completion, a dict with 42 - if there was already a completion, a dict with
43 - 'completed':last completion 43 - 'completed':last completion
44 - 'completion_pos': cursor position where the completion starts 44 - 'completion_pos': cursor position where the completion starts
45 - 'position': last completion cursor position 45 - 'position': last completion cursor position
46 this dict must be used (and can be filled) to find next completion) 46 this dict must be used (and can be filled) to find next completion)
47 and which return the full text completed""" 47 and which return the full text completed"""
48 self.completion_cb = callback 48 self.completion_cb = callback
49 self.completion_data = {} 49 self.completion_data = {}
55 elif key == 'ctrl e': 55 elif key == 'ctrl e':
56 key = 'end' 56 key = 'end'
57 elif key == 'ctrl k': 57 elif key == 'ctrl k':
58 self._delete_highlighted() 58 self._delete_highlighted()
59 self.set_edit_text(self.edit_text[:self.edit_pos]) 59 self.set_edit_text(self.edit_text[:self.edit_pos])
60 elif key == 'ctrl w': 60 elif key == 'ctrl w':
61 before = self.edit_text[:self.edit_pos] 61 before = self.edit_text[:self.edit_pos]
62 pos = before.rstrip().rfind(" ")+1 62 pos = before.rstrip().rfind(" ")+1
63 self.set_edit_text(before[:pos] + self.edit_text[self.edit_pos:]) 63 self.set_edit_text(before[:pos] + self.edit_text[self.edit_pos:])
64 self.set_edit_pos(pos) 64 self.set_edit_pos(pos)
65 elif key == 'enter': 65 elif key == 'enter':
81 self.completion_data['position'] = self.edit_pos 81 self.completion_data['position'] = self.edit_pos
82 return 82 return
83 except AttributeError: 83 except AttributeError:
84 #No completion method defined 84 #No completion method defined
85 pass 85 pass
86 return super(AdvancedEdit, self).keypress(size, key) 86 return super(AdvancedEdit, self).keypress(size, key)
87 87
88 class Password(AdvancedEdit): 88 class Password(AdvancedEdit):
89 """Edit box which doesn't show what is entered (show '*' or other char instead)""" 89 """Edit box which doesn't show what is entered (show '*' or other char instead)"""
90 90
91 def __init__(self, *args, **kwargs): 91 def __init__(self, *args, **kwargs):
108 self._edit_text = self.__real_text 108 self._edit_text = self.__real_text
109 super(Password,self).insert_text(text) 109 super(Password,self).insert_text(text)
110 110
111 def render(self, size, focus=False): 111 def render(self, size, focus=False):
112 return super(Password, self).render(size, focus) 112 return super(Password, self).render(size, focus)
113 113
114 class ModalEdit(AdvancedEdit): 114 class ModalEdit(AdvancedEdit):
115 """AdvancedEdit with vi-like mode management 115 """AdvancedEdit with vi-like mode management
116 - there is a new 'mode' property wich can be changed with properties 116 - there is a new 'mode' property wich can be changed with properties
117 specified during init 117 specified during init
118 - completion callback received a new 'mode' argument 118 - completion callback received a new 'mode' argument
138 mode_key = None 138 mode_key = None
139 for key in self._modes: 139 for key in self._modes:
140 if self._modes[key][0] == value: 140 if self._modes[key][0] == value:
141 mode_key = key 141 mode_key = key
142 break 142 break
143 143
144 mode, caption = self._modes[mode_key] 144 mode, caption = self._modes[mode_key]
145 self._mode = mode 145 self._mode = mode
146 self.set_caption(caption) 146 self.set_caption(caption)
147 if not mode_key: #we are in NORMAL mode 147 if not mode_key: #we are in NORMAL mode
148 self.set_edit_text('') 148 self.set_edit_text('')
156 self.mode = "NORMAL" 156 self.mode = "NORMAL"
157 return 157 return
158 if self._mode == 'NORMAL' and key in self._modes: 158 if self._mode == 'NORMAL' and key in self._modes:
159 self.mode = self._modes[key][0] 159 self.mode = self._modes[key][0]
160 return 160 return
161 return super(ModalEdit, self).keypress(size, key) 161 return super(ModalEdit, self).keypress(size, key)
162 162
163 class SurroundedText(urwid.FlowWidget): 163 class SurroundedText(urwid.FlowWidget):
164 """Text centered on a repeated character (like a Divider, but with a text in the center)""" 164 """Text centered on a repeated character (like a Divider, but with a text in the center)"""
165 165
166 def __init__(self,text,car=utf8decode('─')): 166 def __init__(self,text,car=utf8decode('─')):
180 return urwid.Text(render_text) 180 return urwid.Text(render_text)
181 181
182 class SelectableText(urwid.WidgetWrap): 182 class SelectableText(urwid.WidgetWrap):
183 """Text which can be selected with space""" 183 """Text which can be selected with space"""
184 signals = ['change'] 184 signals = ['change']
185 185
186 def __init__(self, text, align='left', header='', focus_attr='default_focus', selected_text=None, selected=False, data=None): 186 def __init__(self, text, align='left', header='', focus_attr='default_focus', selected_text=None, selected=False, data=None):
187 """@param text: same as urwid.Text's text parameter 187 """@param text: same as urwid.Text's text parameter
188 @param align: same as urwid.Text's align parameter 188 @param align: same as urwid.Text's align parameter
189 @select_attr: attrbute to use when selected 189 @select_attr: attrbute to use when selected
190 @param selected: is the text selected ?""" 190 @param selected: is the text selected ?"""
252 txt_list.extend(txt) 252 txt_list.extend(txt)
253 else: 253 else:
254 txt_list.append(txt) 254 txt_list.append(txt)
255 self._w.base_widget.set_text(txt_list) 255 self._w.base_widget.set_text(txt_list)
256 256
257 257
258 def setState(self, selected, invisible=False): 258 def setState(self, selected, invisible=False):
259 """Change state 259 """Change state
260 @param selected: boolean state value 260 @param selected: boolean state value
261 @param invisible: don't emit change signal if True""" 261 @param invisible: don't emit change signal if True"""
262 assert(type(selected)==bool) 262 assert(type(selected)==bool)
264 self.__set_txt() 264 self.__set_txt()
265 self.__was_focused = False 265 self.__was_focused = False
266 self._invalidate() 266 self._invalidate()
267 if not invisible: 267 if not invisible:
268 self._emit("change", self.__selected) 268 self._emit("change", self.__selected)
269 269
270 def getState(self): 270 def getState(self):
271 return self.__selected 271 return self.__selected
272 272
273 def selectable(self): 273 def selectable(self):
274 return True 274 return True
281 281
282 def mouse_event(self, size, event, button, x, y, focus): 282 def mouse_event(self, size, event, button, x, y, focus):
283 if is_mouse_press(event) and button == 1: 283 if is_mouse_press(event) and button == 1:
284 self.setState(not self.__selected) 284 self.setState(not self.__selected)
285 return True 285 return True
286 286
287 return False 287 return False
288 288
289 def render(self, size, focus=False): 289 def render(self, size, focus=False):
290 attr_list = self._w.base_widget._attrib 290 attr_list = self._w.base_widget._attrib
291 if not focus: 291 if not focus:
292 if self.__was_focused: 292 if self.__was_focused:
293 self.__set_txt() 293 self.__set_txt()
310 self.__was_focused = True #bloody ugly hack :) 310 self.__was_focused = True #bloody ugly hack :)
311 return self._w.render(size, focus) 311 return self._w.render(size, focus)
312 312
313 class ClickableText(SelectableText): 313 class ClickableText(SelectableText):
314 signals = SelectableText.signals + ['click'] 314 signals = SelectableText.signals + ['click']
315 315
316 def setState(self, selected, invisible=False): 316 def setState(self, selected, invisible=False):
317 super(ClickableText,self).setState(False,True) 317 super(ClickableText,self).setState(False,True)
318 if not invisible: 318 if not invisible:
319 self._emit('click') 319 self._emit('click')
320 320
322 322
323 def __init__(self, label, on_press=None, user_data=None, left_border = "[ ", right_border = " ]"): 323 def __init__(self, label, on_press=None, user_data=None, left_border = "[ ", right_border = " ]"):
324 self.label = label 324 self.label = label
325 self.left_border = left_border 325 self.left_border = left_border
326 self.right_border = right_border 326 self.right_border = right_border
327 super(CustomButton, self).__init__([left_border, label, right_border]) 327 super(CustomButton, self).__init__([left_border, label, right_border])
328 self.size = len(self.get_text()) 328 self.size = len(self.get_text())
329 if on_press: 329 if on_press:
330 urwid.connect_signal(self, 'click', on_press, user_data) 330 urwid.connect_signal(self, 'click', on_press, user_data)
331 331
332 def getSize(self): 332 def getSize(self):
347 """ 347 """
348 Widget managing list of string and their selection 348 Widget managing list of string and their selection
349 @param options: list of strings used for options 349 @param options: list of strings used for options
350 @param style: list of string: 350 @param style: list of string:
351 - 'single' if only one must be selected 351 - 'single' if only one must be selected
352 - 'no_first_select' nothing selected when list is first displayed 352 - 'no_first_select' nothing selected when list is first displayed
353 - 'can_select_none' if we can select nothing 353 - 'can_select_none' if we can select nothing
354 @param align: alignement of text inside the list 354 @param align: alignement of text inside the list
355 @param on_click: method called when click signal is emited 355 @param on_click: method called when click signal is emited
356 @param user_data: data sent to the callback for click signal 356 @param user_data: data sent to the callback for click signal
357 """ 357 """
359 self.no_first_select = 'no_first_select' in style 359 self.no_first_select = 'no_first_select' in style
360 self.can_select_none = 'can_select_none' in style 360 self.can_select_none = 'can_select_none' in style
361 self.align = align 361 self.align = align
362 self.option_type = option_type 362 self.option_type = option_type
363 self.first_display = True 363 self.first_display = True
364 364
365 if on_click: 365 if on_click:
366 urwid.connect_signal(self, 'click', on_click, user_data) 366 urwid.connect_signal(self, 'click', on_click, user_data)
367 367
368 if on_change: 368 if on_change:
369 urwid.connect_signal(self, 'change', on_change, user_data) 369 urwid.connect_signal(self, 'change', on_change, user_data)
370 370
371 self.content = urwid.SimpleListWalker([]) 371 self.content = urwid.SimpleListWalker([])
372 self.list_box = urwid.ListBox(self.content) 372 self.list_box = urwid.ListBox(self.content)
373 urwid.WidgetWrap.__init__(self, self.list_box) 373 urwid.WidgetWrap.__init__(self, self.list_box)
374 self.changeValues(options) 374 self.changeValues(options)
375 375
441 if self.first_display and self.single and new_values and not self.no_first_select: 441 if self.first_display and self.single and new_values and not self.no_first_select:
442 self.content[0].setState(True) 442 self.content[0].setState(True)
443 display_widget = self.getDisplayWidget() 443 display_widget = self.getDisplayWidget()
444 self._set_w(display_widget) 444 self._set_w(display_widget)
445 self._emit('change') 445 self._emit('change')
446 self.first_display = False 446 self.first_display = False
447 447
448 def selectValue(self, value): 448 def selectValue(self, value):
449 """Select the first item which has the given value""" 449 """Select the first item which has the given value"""
450 self.unselectAll() 450 self.unselectAll()
451 idx = 0 451 idx = 0
460 """FlowWidget list, same arguments as GenericList, with an additional one 'max_height'""" 460 """FlowWidget list, same arguments as GenericList, with an additional one 'max_height'"""
461 signals = ['click','change'] 461 signals = ['click','change']
462 462
463 def __init__(self, options, style=[], max_height=5, align='left', option_type = SelectableText, on_click=None, on_change=None, user_data=None): 463 def __init__(self, options, style=[], max_height=5, align='left', option_type = SelectableText, on_click=None, on_change=None, user_data=None):
464 self.genericList = GenericList(options, style, align, option_type, on_click, on_change, user_data) 464 self.genericList = GenericList(options, style, align, option_type, on_click, on_change, user_data)
465 self.max_height = max_height 465 self.max_height = max_height
466 466
467 def selectable(self): 467 def selectable(self):
468 return True 468 return True
469 469
470 def keypress(self, size, key): 470 def keypress(self, size, key):
471 return self.displayWidget(size,True).keypress(size, key) 471 return self.displayWidget(size,True).keypress(size, key)
472 472
473 def unselectAll(self, invisible=False): 473 def unselectAll(self, invisible=False):
474 return self.genericList.unselectAll(invisible) 474 return self.genericList.unselectAll(invisible)
475 475
476 def deleteValue(self, value): 476 def deleteValue(self, value):
477 return self.genericList.deleteValue(value) 477 return self.genericList.deleteValue(value)
478 478
479 def getSelectedValue(self): 479 def getSelectedValue(self):
480 return self.genericList.getSelectedValue() 480 return self.genericList.getSelectedValue()
491 def selectValue(self, value): 491 def selectValue(self, value):
492 return self.genericList.selectValue(value) 492 return self.genericList.selectValue(value)
493 493
494 def render(self, size, focus=False): 494 def render(self, size, focus=False):
495 return self.displayWidget(size, focus).render(size, focus) 495 return self.displayWidget(size, focus).render(size, focus)
496 496
497 def rows(self, size, focus=False): 497 def rows(self, size, focus=False):
498 return self.displayWidget(size, focus).rows(size, focus) 498 return self.displayWidget(size, focus).rows(size, focus)
499 499
500 def displayWidget(self, size, focus): 500 def displayWidget(self, size, focus):
501 list_size = sum([wid.rows(size, focus) for wid in self.genericList.content]) 501 list_size = sum([wid.rows(size, focus) for wid in self.genericList.content])
502 height = min(list_size,self.max_height) or 1 502 height = min(list_size,self.max_height) or 1
503 return urwid.BoxAdapter(self.genericList, height) 503 return urwid.BoxAdapter(self.genericList, height)
504 504
505 ## MISC ## 505 ## MISC ##
506 506
507 class NotificationBar(urwid.WidgetWrap): 507 class NotificationBar(urwid.WidgetWrap):
514 urwid.connect_signal(self.message, 'click', lambda wid: self.showNext()) 514 urwid.connect_signal(self.message, 'click', lambda wid: self.showNext())
515 self.progress = ClickableText('') 515 self.progress = ClickableText('')
516 self.columns = urwid.Columns([('fixed',6,self.waitNotifs),self.message,('fixed',4,self.progress)]) 516 self.columns = urwid.Columns([('fixed',6,self.waitNotifs),self.message,('fixed',4,self.progress)])
517 urwid.WidgetWrap.__init__(self, urwid.AttrMap(self.columns,'notifs')) 517 urwid.WidgetWrap.__init__(self, urwid.AttrMap(self.columns,'notifs'))
518 self.notifs = [] 518 self.notifs = []
519 519
520 def __modQueue(self): 520 def __modQueue(self):
521 """must be called each time the notifications queue is changed""" 521 """must be called each time the notifications queue is changed"""
522 self.waitNotifs.set_text(('notifs',"(%i)" % len(self.notifs) if self.notifs else '')) 522 self.waitNotifs.set_text(('notifs',"(%i)" % len(self.notifs) if self.notifs else ''))
523 self._emit('change') 523 self._emit('change')
524 524
582 582
583 583
584 class MenuBox(urwid.WidgetWrap): 584 class MenuBox(urwid.WidgetWrap):
585 """Show menu items of a category in a box""" 585 """Show menu items of a category in a box"""
586 signals = ['click'] 586 signals = ['click']
587 587
588 def __init__(self,parent,items): 588 def __init__(self,parent,items):
589 self.parent = parent 589 self.parent = parent
590 self.selected = None 590 self.selected = None
591 content = urwid.SimpleListWalker([ClickableText(('menuitem',text)) for text in items]) 591 content = urwid.SimpleListWalker([ClickableText(('menuitem',text)) for text in items])
592 for wid in content: 592 for wid in content:
596 menubox = urwid.LineBox(urwid.BoxAdapter(self.listBox,len(items))) 596 menubox = urwid.LineBox(urwid.BoxAdapter(self.listBox,len(items)))
597 urwid.WidgetWrap.__init__(self,menubox) 597 urwid.WidgetWrap.__init__(self,menubox)
598 598
599 def getValue(self): 599 def getValue(self):
600 return self.selected 600 return self.selected
601 601
602 def keypress(self, size, key): 602 def keypress(self, size, key):
603 if key=='up': 603 if key=='up':
604 if self.listBox.get_focus()[1] == 0: 604 if self.listBox.get_focus()[1] == 0:
605 self.parent.keypress(size, key) 605 self.parent.keypress(size, key)
606 elif key=='left' or key=='right': 606 elif key=='left' or key=='right':
607 self.parent.keypress(size,'up') 607 self.parent.keypress(size,'up')
608 self.parent.keypress(size,key) 608 self.parent.keypress(size,key)
609 return super(MenuBox,self).keypress(size,key) 609 return super(MenuBox,self).keypress(size,key)
610 610
611 def mouse_event(self, size, event, button, x, y, focus): 611 def mouse_event(self, size, event, button, x, y, focus):
612 if button == 3: 612 if button == 3:
613 self.parent.keypress(size,'up') 613 self.parent.keypress(size,'up')
614 return True 614 return True
615 return super(MenuBox,self).mouse_event(size, event, button, x, y, focus) 615 return super(MenuBox,self).mouse_event(size, event, button, x, y, focus)
631 self.x_orig = x_orig 631 self.x_orig = x_orig
632 self.shortcuts = {} #keyboard shortcuts 632 self.shortcuts = {} #keyboard shortcuts
633 self.save_bottom = None 633 self.save_bottom = None
634 col_rol = ColumnsRoller() 634 col_rol = ColumnsRoller()
635 urwid.WidgetWrap.__init__(self, urwid.AttrMap(col_rol,'menubar')) 635 urwid.WidgetWrap.__init__(self, urwid.AttrMap(col_rol,'menubar'))
636 636
637 def selectable(self): 637 def selectable(self):
638 return True 638 return True
639 639
640 def getMenuSize(self): 640 def getMenuSize(self):
641 """return the current number of categories in this menu""" 641 """return the current number of categories in this menu"""
642 return len(self.menu_keys) 642 return len(self.menu_keys)
643 643
644 def setOrigX(self, orig_x): 644 def setOrigX(self, orig_x):
645 self.x_orig = orig_x 645 self.x_orig = orig_x
646 646
647 def __buildOverlay(self,menu_key,columns): 647 def __buildOverlay(self,menu_key,columns):
648 """Build the overlay menu which show menuitems 648 """Build the overlay menu which show menuitems
654 max_len = len(item[0]) 654 max_len = len(item[0])
655 655
656 self.save_bottom = self.loop.widget 656 self.save_bottom = self.loop.widget
657 menu_box = MenuBox(self,[item[0] for item in self.menu[menu_key]]) 657 menu_box = MenuBox(self,[item[0] for item in self.menu[menu_key]])
658 urwid.connect_signal(menu_box, 'click', self.onItemClick) 658 urwid.connect_signal(menu_box, 'click', self.onItemClick)
659 659
660 self.loop.widget = urwid.Overlay(urwid.AttrMap(menu_box,'menubar'),self.save_bottom,('fixed left', columns),max_len+2,('fixed top',1),None) 660 self.loop.widget = urwid.Overlay(urwid.AttrMap(menu_box,'menubar'),self.save_bottom,('fixed left', columns),max_len+2,('fixed top',1),None)
661 661
662 def keypress(self, size, key): 662 def keypress(self, size, key):
663 if key == 'down': 663 if key == 'down':
664 key = 'enter' 664 key = 'enter'
665 elif key == 'up': 665 elif key == 'up':
666 if self.save_bottom: 666 if self.save_bottom:
667 self.loop.widget = self.save_bottom 667 self.loop.widget = self.save_bottom
668 self.save_bottom = None 668 self.save_bottom = None
669 669
670 return self._w.base_widget.keypress(size, key) 670 return self._w.base_widget.keypress(size, key)
671 671
672 def checkShortcuts(self, key): 672 def checkShortcuts(self, key):
673 for shortcut in self.shortcuts.keys(): 673 for shortcut in self.shortcuts.keys():
674 if key == shortcut: 674 if key == shortcut:
675 category, item, callback = self.shortcuts[shortcut] 675 category, item, callback = self.shortcuts[shortcut]
676 callback((category, item)) 676 callback((category, item))
702 callback = menu_item[1] 702 callback = menu_item[1]
703 break 703 break
704 if callback: 704 if callback:
705 self.keypress(None,'up') 705 self.keypress(None,'up')
706 callback((category, item)) 706 callback((category, item))
707 707
708 def onCategoryClick(self, button): 708 def onCategoryClick(self, button):
709 self.__buildOverlay(button.get_label(), 709 self.__buildOverlay(button.get_label(),
710 self.x_orig + self._w.base_widget.getStartCol(button)) 710 self.x_orig + self._w.base_widget.getStartCol(button))
711 711
712 712
713 class MenuRoller(urwid.WidgetWrap): 713 class MenuRoller(urwid.WidgetWrap):
714 714
715 def __init__(self,menus_list): 715 def __init__(self,menus_list):
716 """Create a MenuRoller 716 """Create a MenuRoller
718 """ 718 """
719 assert (menus_list) 719 assert (menus_list)
720 self.selected = 0 720 self.selected = 0
721 self.name_list = [] 721 self.name_list = []
722 self.menus = {} 722 self.menus = {}
723 723
724 self.columns = urwid.Columns([urwid.Text(''),urwid.Text('')]) 724 self.columns = urwid.Columns([urwid.Text(''),urwid.Text('')])
725 urwid.WidgetWrap.__init__(self, self.columns) 725 urwid.WidgetWrap.__init__(self, self.columns)
726 726
727 for menu_tuple in menus_list: 727 for menu_tuple in menus_list:
728 name,menu = menu_tuple 728 name,menu = menu_tuple
729 self.addMenu(name, menu) 729 self.addMenu(name, menu)
730 730
731 def __showSelected(self): 731 def __showSelected(self):
732 """show menu selected""" 732 """show menu selected"""
733 name_txt = u'\u21c9 '+self.name_list[self.selected]+u' \u21c7 ' 733 name_txt = u'\u21c9 '+self.name_list[self.selected]+u' \u21c7 '
734 current_name = ClickableText(name_txt) 734 current_name = ClickableText(name_txt)
735 name_len = len(name_txt) 735 name_len = len(name_txt)
736 current_menu = self.menus[self.name_list[self.selected]] 736 current_menu = self.menus[self.name_list[self.selected]]
737 current_menu.setOrigX(name_len) 737 current_menu.setOrigX(name_len)
738 self.columns.contents[0] = (current_name, ('given', name_len, False)) 738 self.columns.contents[0] = (current_name, ('given', name_len, False))
739 self.columns.contents[1] = (current_menu, ('weight', 1, False)) 739 self.columns.contents[1] = (current_menu, ('weight', 1, False))
773 773
774 def checkShortcuts(self, key): 774 def checkShortcuts(self, key):
775 for menu in self.name_list: 775 for menu in self.name_list:
776 key = self.menus[menu].checkShortcuts(key) 776 key = self.menus[menu].checkShortcuts(key)
777 return key 777 return key
778 778
779 779
780 ## DIALOGS ## 780 ## DIALOGS ##
781 781
782 class GenericDialog(urwid.WidgetWrap): 782 class GenericDialog(urwid.WidgetWrap):
783 783
784 def __init__(self, widgets_lst, title, style=[], **kwargs): 784 def __init__(self, widgets_lst, title, style=[], **kwargs):
785 frame_header = urwid.AttrMap(urwid.Text(title,'center'),'title') 785 frame_header = urwid.AttrMap(urwid.Text(title,'center'),'title')
786 786
787 buttons = None 787 buttons = None
788 788
789 if "OK/CANCEL" in style: 789 if "OK/CANCEL" in style:
790 cancel_arg = [kwargs['cancel_value']] if kwargs.has_key('cancel_value') else [] 790 cancel_arg = [kwargs['cancel_value']] if kwargs.has_key('cancel_value') else []
791 ok_arg = [kwargs['ok_value']] if kwargs.has_key('ok_value') else [] 791 ok_arg = [kwargs['ok_value']] if kwargs.has_key('ok_value') else []
831 GenericDialog.__init__(self, [urwid.Text(message, 'center')], title, style, ok_value=None, **kwargs) 831 GenericDialog.__init__(self, [urwid.Text(message, 'center')], title, style, ok_value=None, **kwargs)
832 832
833 ## CONTAINERS ## 833 ## CONTAINERS ##
834 834
835 class ColumnsRoller(urwid.FlowWidget): 835 class ColumnsRoller(urwid.FlowWidget):
836 836
837 def __init__(self, widget_list = None, focus_column=0): 837 def __init__(self, widget_list = None, focus_column=0):
838 self.widget_list = widget_list or [] 838 self.widget_list = widget_list or []
839 self.focus_column = focus_column 839 self.focus_column = focus_column
840 self.__start = 0 840 self.__start = 0
841 self.__next = False 841 self.__next = False
857 def selectable(self): 857 def selectable(self):
858 try: 858 try:
859 return self.widget_list[self.focus_column][1].selectable() 859 return self.widget_list[self.focus_column][1].selectable()
860 except IndexError: 860 except IndexError:
861 return False 861 return False
862 862
863 def keypress(self, size, key): 863 def keypress(self, size, key):
864 if key=='left': 864 if key=='left':
865 if self.focus_column>0: 865 if self.focus_column>0:
866 self.focus_column-=1 866 self.focus_column-=1
867 self._invalidate() 867 self._invalidate()
890 def __calculate_limits(self, size): 890 def __calculate_limits(self, size):
891 (maxcol,) = size 891 (maxcol,) = size
892 _prev = _next = False 892 _prev = _next = False
893 start_wid = 0 893 start_wid = 0
894 end_wid = len(self.widget_list)-1 894 end_wid = len(self.widget_list)-1
895 895
896 total_wid = sum([w[0] for w in self.widget_list]) 896 total_wid = sum([w[0] for w in self.widget_list])
897 while total_wid > maxcol: 897 while total_wid > maxcol:
898 if self.focus_column == end_wid: 898 if self.focus_column == end_wid:
899 if not _prev: 899 if not _prev:
900 total_wid+=1 900 total_wid+=1
905 if not _next: 905 if not _next:
906 total_wid+=1 906 total_wid+=1
907 _next = True 907 _next = True
908 total_wid-=self.widget_list[end_wid][0] 908 total_wid-=self.widget_list[end_wid][0]
909 end_wid-=1 909 end_wid-=1
910 910
911 cols_left = maxcol - total_wid 911 cols_left = maxcol - total_wid
912 self.__start = start_wid #we need to keep it for getStartCol 912 self.__start = start_wid #we need to keep it for getStartCol
913 return _prev,_next,start_wid,end_wid,cols_left 913 return _prev,_next,start_wid,end_wid,cols_left
914 914
915 915
916 def mouse_event(self, size, event, button, x, y, focus): 916 def mouse_event(self, size, event, button, x, y, focus):
917 (maxcol,)=size 917 (maxcol,)=size
918 918
919 if is_mouse_press(event) and button == 1: 919 if is_mouse_press(event) and button == 1:
922 self.keypress(size,'left') 922 self.keypress(size,'left')
923 return True 923 return True
924 if x==maxcol-1 and _next: 924 if x==maxcol-1 and _next:
925 self.keypress(size,'right') 925 self.keypress(size,'right')
926 return True 926 return True
927 927
928 current_pos = 1 if _prev else 0 928 current_pos = 1 if _prev else 0
929 idx = 0 929 idx = 0
930 while current_pos<x and idx<len(self.widget_list): 930 while current_pos<x and idx<len(self.widget_list):
931 width,widget = self.widget_list[idx] 931 width,widget = self.widget_list[idx]
932 if x<=current_pos+width: 932 if x<=current_pos+width:
933 self.focus_column = idx 933 self.focus_column = idx
934 self._invalidate() 934 self._invalidate()
935 if not hasattr(widget,'mouse_event'): 935 if not hasattr(widget,'mouse_event'):
936 return False 936 return False
937 return widget.mouse_event((width,0), event, button, 937 return widget.mouse_event((width,0), event, button,
938 x-current_pos, 0, focus) 938 x-current_pos, 0, focus)
939 939
940 current_pos+=self.widget_list[idx][0] 940 current_pos+=self.widget_list[idx][0]
941 idx+=1 941 idx+=1
942 942
943 return False 943 return False
944 944
945 def render(self, size, focus=False): 945 def render(self, size, focus=False):
946 if not self.widget_list: 946 if not self.widget_list:
947 return SolidCanvas(" ", size[0], 1) 947 return SolidCanvas(" ", size[0], 1)
948 948
949 _prev,_next,start_wid,end_wid,cols_left = self.__calculate_limits(size) 949 _prev,_next,start_wid,end_wid,cols_left = self.__calculate_limits(size)
950 950
951 idx=start_wid 951 idx=start_wid
952 render = [] 952 render = []
953 953
954 for width,widget in self.widget_list[start_wid:end_wid+1]: 954 for width,widget in self.widget_list[start_wid:end_wid+1]:
955 _focus = idx == self.focus_column and focus 955 _focus = idx == self.focus_column and focus
970 970
971 def keypress(self, size, key): 971 def keypress(self, size, key):
972 ret = urwid.Frame.keypress(self, size, key) 972 ret = urwid.Frame.keypress(self, size, key)
973 if not ret: 973 if not ret:
974 return 974 return
975 975
976 if key == 'tab': 976 if key == 'tab':
977 focus_list = ('header','body','footer') 977 focus_list = ('header','body','footer')
978 focus_idx = focus_list.index(self.focus_part) 978 focus_idx = focus_list.index(self.focus_part)
979 for i in range(2): 979 for i in range(2):
980 focus_idx = (focus_idx + 1) % len(focus_list) 980 focus_idx = (focus_idx + 1) % len(focus_list)
981 focus_name = focus_list[focus_idx] 981 focus_name = focus_list[focus_idx]
982 widget = getattr(self,'_'+focus_name) 982 widget = getattr(self,'_'+focus_name)
983 if widget!=None and widget.selectable(): 983 if widget!=None and widget.selectable():
984 self.set_focus(focus_name) 984 self.set_focus(focus_name)
985 985
986 return ret 986 return ret
987 987
988 class TabsContainer(urwid.WidgetWrap): 988 class TabsContainer(urwid.WidgetWrap):
989 signals = ['click'] 989 signals = ['click']
990 990
991 def __init__(self): 991 def __init__(self):
1043 1043
1044 def addFooter(self, widget): 1044 def addFooter(self, widget):
1045 """Add a widget on the bottom of the tab (will be displayed on all pages) 1045 """Add a widget on the bottom of the tab (will be displayed on all pages)
1046 @param widget: FlowWidget""" 1046 @param widget: FlowWidget"""
1047 self._w.footer = widget 1047 self._w.footer = widget
1048 1048
1049 1049
1050 ## DECORATORS ## 1050 ## DECORATORS ##
1051 class LabelLine(urwid.LineBox): 1051 class LabelLine(urwid.LineBox):
1052 """Like LineBox, but with a Label centered in the top line""" 1052 """Like LineBox, but with a Label centered in the top line"""
1053 1053
1057 top_columns.widget_list[1] = label_widget 1057 top_columns.widget_list[1] = label_widget
1058 1058
1059 class VerticalSeparator(urwid.WidgetDecoration, urwid.WidgetWrap): 1059 class VerticalSeparator(urwid.WidgetDecoration, urwid.WidgetWrap):
1060 def __init__(self, original_widget, left_char = u"│", right_char = ''): 1060 def __init__(self, original_widget, left_char = u"│", right_char = ''):
1061 """Draw a separator on left and/or right of original_widget.""" 1061 """Draw a separator on left and/or right of original_widget."""
1062 1062
1063 widgets = [original_widget] 1063 widgets = [original_widget]
1064 if left_char: 1064 if left_char:
1065 widgets.insert(0, ('fixed', 1, urwid.SolidFill(left_char))) 1065 widgets.insert(0, ('fixed', 1, urwid.SolidFill(left_char)))
1066 if right_char: 1066 if right_char:
1067 widgets.append(('fixed', 1, urwid.SolidFill(right_char))) 1067 widgets.append(('fixed', 1, urwid.SolidFill(right_char)))
1068 columns = urwid.Columns(widgets, box_columns = [0,2], focus_column = 1) 1068 columns = urwid.Columns(widgets, box_columns = [0,2], focus_column = 1)
1069 urwid.WidgetDecoration.__init__(self, original_widget) 1069 urwid.WidgetDecoration.__init__(self, original_widget)
1070 urwid.WidgetWrap.__init__(self, columns) 1070 urwid.WidgetWrap.__init__(self, columns)
1071 1071
1072 1072