comparison frontends/primitivus/custom_widgets.py @ 119:ded2431cea5a

Primitivus: chat window / text sending. Primitivus has now the most basics features \o/ - core: new getVersion method - primitivus: new debug key (C-d), only work if SàT is in dev version (D in version) - quick_app: new post_init method, used for automatique task like auto-plug - primitivus: lists now use genericList (Box) or List (Flow) - primitivus: List now manage correctly its size - primitivus: new FocusFrame widget which manage focus changing with 'tab' - primitivus: advancedEdit now manage 'click' signal - primitivus: contactList now manager 'change' and 'click' signals - primitivus: Chat window now working
author Goffi <goffi@goffi.org>
date Mon, 05 Jul 2010 19:13:36 +0800
parents 76055a209ed9
children 1ca5f254ce41
comparison
equal deleted inserted replaced
118:76055a209ed9 119:ded2431cea5a
36 def get_edit_text(self): 36 def get_edit_text(self):
37 return self.__real_text 37 return self.__real_text
38 38
39 class AdvancedEdit(urwid.Edit): 39 class AdvancedEdit(urwid.Edit):
40 """Edit box with some custom improvments""" 40 """Edit box with some custom improvments"""
41 signals = urwid.Edit.signals + ['click']
41 42
42 def keypress(self, size, key): 43 def keypress(self, size, key):
43 #TODO: insert mode is not managed yet 44 #TODO: insert mode is not managed yet
44 if key == 'ctrl a': 45 if key == 'ctrl a':
45 key = 'home' 46 key = 'home'
51 elif key == 'ctrl w': 52 elif key == 'ctrl w':
52 before = self.edit_text[:self.edit_pos] 53 before = self.edit_text[:self.edit_pos]
53 pos = before.rstrip().rfind(" ")+1 54 pos = before.rstrip().rfind(" ")+1
54 self.set_edit_text(before[:pos] + self.edit_text[self.edit_pos:]) 55 self.set_edit_text(before[:pos] + self.edit_text[self.edit_pos:])
55 self.set_edit_pos(pos) 56 self.set_edit_pos(pos)
57 elif key == 'enter':
58 self._emit('click')
56 return super(AdvancedEdit, self).keypress(size, key) 59 return super(AdvancedEdit, self).keypress(size, key)
57 60
58 61
59 class SelectableText(urwid.FlowWidget): 62 class SelectableText(urwid.FlowWidget):
60 signals = ['change'] 63 signals = ['change']
71 """Change state 74 """Change state
72 @param selected: boolean state value 75 @param selected: boolean state value
73 @param invisible: don't emit change signal if True""" 76 @param invisible: don't emit change signal if True"""
74 assert(type(selected)==bool) 77 assert(type(selected)==bool)
75 self.__selected=selected 78 self.__selected=selected
79 self._invalidate()
76 if not invisible: 80 if not invisible:
77 self._emit("change", self.__selected) 81 self._emit("change", self.__selected)
78 self._invalidate()
79 82
80 def getState(self): 83 def getState(self):
81 return self.__selected 84 return self.__selected
82 85
83 def selectable(self): 86 def selectable(self):
99 attr = 'selected' if self.__selected else 'default' 102 attr = 'selected' if self.__selected else 'default'
100 if focus: 103 if focus:
101 attr+="_focus" 104 attr+="_focus"
102 return urwid.Text((attr,self.text), align=self.align) 105 return urwid.Text((attr,self.text), align=self.align)
103 106
104 class List(urwid.WidgetWrap): 107 class GenericList(urwid.WidgetWrap):
105 signals = ['change'] 108 signals = ['click','change']
106 109
107 def __init__(self, options, style=[], align='left', on_state_change=None, user_data=None): 110 def __init__(self, options, style=[], align='left', on_click=None, on_change=None, user_data=None):
111 """
112 Widget managing list of string and their selection
113 @param options: list of strings used for options
114 @param style: list of string:
115 - 'single' if only one must be selected
116 - 'no_first_select' nothing selected when list is first displayed
117 - 'can_select_none' if we can select nothing
118 @param align: alignement of text inside the list
119 @param on_click: method called when click signal is emited
120 @param user_data: data sent to the callback for click signal
121 """
108 self.single = 'single' in style 122 self.single = 'single' in style
123 self.no_first_select = 'no_first_select' in style
124 self.can_select_none = 'can_select_none' in style
109 self.align = align 125 self.align = align
126 self.first_display = True
110 127
111 if on_state_change: 128 if on_click:
112 urwid.connect_signal(self, 'change', on_state_change, user_data) 129 urwid.connect_signal(self, 'click', on_click, user_data)
130
131 if on_change:
132 urwid.connect_signal(self, 'change', on_change, user_data)
113 133
114 self.content = urwid.SimpleListWalker([]) 134 self.content = urwid.SimpleListWalker([])
115 self.list_box = urwid.ListBox(self.content) 135 self.list_box = urwid.ListBox(self.content)
116 urwid.WidgetWrap.__init__(self, self.list_box) 136 urwid.WidgetWrap.__init__(self, self.list_box)
117 self.changeValues(options) 137 self.changeValues(options)
118 138
119 def __onStateChange(self, widget, selected): 139 def __onStateChange(self, widget, selected):
120 if self.single: 140 if self.single:
121 if not selected: 141 if not selected and not self.can_select_none:
122 #if in single mode, it's forbidden to unselect a value 142 #if in single mode, it's forbidden to unselect a value
123 widget.setState(True, invisible=True) 143 widget.setState(True, invisible=True)
124 return 144 return
125 else: 145 if selected:
126 self.unselectAll(invisible=True) 146 self.unselectAll(invisible=True)
127 widget.setState(True, invisible=True) 147 widget.setState(True, invisible=True)
128 self._emit("change") 148 self._emit("click")
129 149
130 150
131 def unselectAll(self, invisible=False): 151 def unselectAll(self, invisible=False):
132 for widget in self.content: 152 for widget in self.content:
133 if widget.getState(): 153 if widget.getState():
134 widget.setState(False, invisible) 154 widget.setState(False, invisible)
135 widget._invalidate() 155 widget._invalidate()
136 156
137 def deleteValue(self, value): 157 def deleteValue(self, value):
138 """Delete the first value equal to the param given""" 158 """Delete the first value equal to the param given"""
139 try: 159 for widget in self.content:
140 self.content.remove(value) 160 if widget.getValue() == value:
141 except ValueError: 161 self.content.remove(widget)
142 raise ValuError("%s ==> %s" % (str(value),str(self.content))) 162 self._emit('change')
143 163 return
144 def getValue(self): 164 raise ValueError("%s ==> %s" % (str(value),str(self.content)))
165
166 def getSelectedValue(self):
145 """Convenience method to get the value selected as a string in single mode, or None""" 167 """Convenience method to get the value selected as a string in single mode, or None"""
146 values = self.getValues() 168 values = self.getSelectedValues()
147 return values[0] if values else None 169 return values[0] if values else None
148 170
149 def getValues(self): 171 def getAllValues(self):
172 """Return values of all items"""
173 return [widget.getValue() for widget in self.content]
174
175 def getSelectedValues(self):
176 """Return values of selected items"""
150 result = [] 177 result = []
151 for widget in self.content: 178 for widget in self.content:
152 if widget.getState(): 179 if widget.getState():
153 result.append(widget.getValue()) 180 result.append(widget.getValue())
154 return result 181 return result
155 182
183 def getDisplayWidget(self):
184 return self.list_box
185
156 def changeValues(self, new_values): 186 def changeValues(self, new_values):
157 """Change all value in one shot""" 187 """Change all value in one shot"""
158 widgets = [SelectableText(option, self.align) for option in new_values] 188 if not self.first_display:
159 for widget in widgets: 189 old_selected = self.getSelectedValues()
190 widgets = []
191 for option in new_values:
192 widget = SelectableText(option, self.align)
193 if not self.first_display and option in old_selected:
194 widget.setState(True)
195 widgets.append(widget)
160 urwid.connect_signal(widget, 'change', self.__onStateChange) 196 urwid.connect_signal(widget, 'change', self.__onStateChange)
161 self.content[:] = widgets 197 self.content[:] = widgets
162 if self.single and new_values: 198 if self.first_display and self.single and new_values and not self.no_first_select:
163 self.content[0].setState(True) 199 self.content[0].setState(True)
164 display_widget = urwid.BoxAdapter(self.list_box, min(len(new_values),5) or 1) 200 display_widget = self.getDisplayWidget()
165 self._set_w(display_widget) 201 self._set_w(display_widget)
166 202 self._emit('change')
203 self.first_display = False
204
167 def selectValue(self, value): 205 def selectValue(self, value):
168 self.unselectAll() 206 self.unselectAll()
169 idx = 0 207 idx = 0
170 for widget in self.content: 208 for widget in self.content:
171 if widget.getValue() == value: 209 if widget.getSelectedValue() == value:
172 widget.setState(True) 210 widget.setState(True)
173 self.list_box.set_focus(idx) 211 self.list_box.set_focus(idx)
174 return 212 return
175 idx+=1 213 idx+=1
176 214
177 class genericDialog(urwid.WidgetWrap): 215 class List(urwid.FlowWidget):
216 """FlowWidget list, same arguments as GenericList, with an additional one 'max_height'"""
217 signals = ['click','change']
218
219 def __init__(self, options, style=[], max_height=5, align='left', on_click=None, on_change=None, user_data=None):
220 self.genericList = GenericList(options, style, align, on_click, on_change, user_data)
221 self.max_height = max_height
222
223 def selectable(self):
224 return True
225
226 def keypress(self, size, key):
227 return self.displayWidget(size,True).keypress(size, key)
228
229 def unselectAll(self, invisible=False):
230 return self.genericList.unselectAll(invisible)
231
232 def deleteValue(self, value):
233 return self.genericList.deleteValue(value)
234
235 def getSelectedValue(self):
236 return self.genericList.getSelectedValue()
237
238 def getAllValues(self):
239 return self.genericList.getAllValues()
240
241 def getSelectedValues(self):
242 return self.genericList.getSelectedValues()
243
244 def changeValues(self, new_values):
245 return self.genericList.changeValues(new_values)
246
247 def selectValue(self, value):
248 return self.genericList.selectValue(value)
249
250 def render(self, size, focus=False):
251 return self.displayWidget(size, focus).render(size, focus)
252
253 def rows(self, size, focus=False):
254 return self.displayWidget(size, focus).rows(size, focus)
255
256 def displayWidget(self, size, focus):
257 list_size = sum([wid.rows(size, focus) for wid in self.genericList.content])
258 height = min(list_size,self.max_height)
259 return urwid.BoxAdapter(self.genericList, height)
260
261 class GenericDialog(urwid.WidgetWrap):
178 262
179 def __init__(self, widgets_lst, title, style=[], **kwargs): 263 def __init__(self, widgets_lst, title, style=[], **kwargs):
180 frame_header = urwid.AttrMap(urwid.Text(title,'center'),'title') 264 frame_header = urwid.AttrMap(urwid.Text(title,'center'),'title')
181 265
182 buttons = None 266 buttons = None
198 decorated_frame = urwid.LineBox(frame) 282 decorated_frame = urwid.LineBox(frame)
199 urwid.WidgetWrap.__init__(self, decorated_frame) 283 urwid.WidgetWrap.__init__(self, decorated_frame)
200 284
201 285
202 286
203 class InputDialog(genericDialog): 287 class InputDialog(GenericDialog):
204 288
205 def __init__(self, title, instrucions, style=['OK/CANCEL'], **kwargs): 289 def __init__(self, title, instrucions, style=['OK/CANCEL'], **kwargs):
206 instr_wid = urwid.Text(instrucions+':') 290 instr_wid = urwid.Text(instrucions+':')
207 edit_box = urwid.Edit() 291 edit_box = urwid.Edit()
208 genericDialog.__init__(self, [instr_wid,edit_box], title, style, ok_value=edit_box, **kwargs) 292 GenericDialog.__init__(self, [instr_wid,edit_box], title, style, ok_value=edit_box, **kwargs)
209 293
210 class ConfirmDialog(genericDialog): 294 class ConfirmDialog(GenericDialog):
211 295
212 def __init__(self, title, style=['YES/NO'], **kwargs): 296 def __init__(self, title, style=['YES/NO'], **kwargs):
213 genericDialog.__init__(self, [], title, style, yes_value=None, **kwargs) 297 GenericDialog.__init__(self, [], title, style, yes_value=None, **kwargs)
214 298
215 class Alert(genericDialog): 299 class Alert(GenericDialog):
216 300
217 def __init__(self, title, message, style=['OK'], **kwargs): 301 def __init__(self, title, message, style=['OK'], **kwargs):
218 genericDialog.__init__(self, [urwid.Text(message, 'center')], title, style, ok_value=None, **kwargs) 302 GenericDialog.__init__(self, [urwid.Text(message, 'center')], title, style, ok_value=None, **kwargs)
303
304 class FocusFrame(urwid.Frame):
305 """Frame which manage "tab" key"""
306
307 def keypress(self, size, key):
308 if key == 'tab':
309 focus_list = ('header','body','footer')
310 focus_idx = focus_list.index(self.focus_part)
311 for i in range(2):
312 focus_idx = (focus_idx + 1) % len(focus_list)
313 focus_name = focus_list[focus_idx]
314 widget = getattr(self,'_'+focus_name)
315 if widget!=None and widget.selectable():
316 self.set_focus(focus_name)
317
318 return urwid.Frame.keypress(self, size, key)