]> git.ipfire.org Git - thirdparty/newt.git/blob - snack.py
added piles of convienence functions
[thirdparty/newt.git] / snack.py
1 # snack.py: maps C extension module _snack to proper python types in module
2 # snack.
3 # The first section is a very literal mapping.
4 # The second section contains convenience classes that amalgamate
5 # the literal classes and make them more object-oriented.
6
7 import _snack
8 import types
9 import string
10
11 class Widget:
12
13 def setCallback(self, obj):
14 self.w.setCallback(obj)
15
16 class Button(Widget):
17
18 def __init__(self, text):
19 self.w = _snack.button(text)
20
21 class Checkbox(Widget):
22
23 def value(self):
24 return self.w.checkboxValue
25
26 def selected(self):
27 return self.w.checkboxValue != 0
28
29 def __init__(self, text, isOn = 0):
30 self.w = _snack.checkbox(text, isOn)
31
32 class SingleRadioButton(Widget):
33
34 def selected(self):
35 return self.w.key == self.w.radioValue;
36
37 def __init__(self, text, group, isOn = 0):
38 if group:
39 self.w = _snack.radiobutton(text, group.w, isOn)
40 else:
41 self.w = _snack.radiobutton(text, None, isOn)
42
43 class Listbox(Widget):
44
45 def append(self, text, item):
46 key = self.w.listboxAddItem(text)
47 self.key2item[key] = item
48 self.item2key[item] = key
49
50 def insert(self, text, item, before):
51 if (not before):
52 key = self.w.listboxInsertItem(text, 0)
53 else:
54 key = self.w.listboxInsertItem(text, self.item2key[before])
55 self.key2item[key] = item
56 self.item2key[item] = key
57
58 def delete(self, item):
59 self.w.listboxDeleteItem(self.item2key[item])
60 del self.key2item[self.item2key[item]]
61 del self.item2key[item]
62
63 def replace(self, text, item):
64 key = self.w.listboxInsertItem(text, self.item2key[item])
65 self.w.listboxDeleteItem(self.item2key[item])
66 del self.key2item[self.item2key[item]]
67 self.item2key[item] = key
68 self.key2item[key] = item
69
70 def current(self):
71 return self.key2item[self.w.listboxGetCurrent()]
72
73 def setCurrent(self, item):
74 pass
75 #self.w.listboxSetCurrent(self.item2key[item])
76
77 def __init__(self, height, scroll = 0, returnExit = 0, width = 0):
78 self.w = _snack.listbox(height, scroll, returnExit)
79 self.key2item = {}
80 self.item2key = {}
81 if (width):
82 self.w.listboxSetWidth(width)
83
84 class Textbox(Widget):
85
86 def __init__(self, width, height, text, scroll = 0):
87 self.w = _snack.textbox(width, height, text, scroll)
88
89 class TextboxReflowed(Textbox):
90
91 def __init__(self, width, text, flexDown = 5, flexUp = 10):
92 (newtext, width, height) = reflow(text, width, flexDown, flexUp)
93 Textbox.__init__(self, width, height, newtext, 0)
94
95 class Label(Widget):
96
97 def __init__(self, text):
98 self.w = _snack.label(text)
99
100 class Entry(Widget):
101
102 def value(self):
103 return self.w.entryValue
104
105 def set(self, text):
106 return self.w.entrySetValue(text)
107
108 def __init__(self, width, text = "", hidden = 0, scroll = 1,
109 returnExit = 0):
110 self.w = _snack.entry(width, text, hidden, scroll, returnExit)
111
112
113 # Form uses hotkeys
114 hotkeys = { "F1" : _snack.KEY_F1, "F2" : _snack.KEY_F2, "F3" : _snack.KEY_F3,
115 "F4" : _snack.KEY_F4, "F5" : _snack.KEY_F5, "F6" : _snack.KEY_F6,
116 "F7" : _snack.KEY_F7, "F8" : _snack.KEY_F8, "F9" : _snack.KEY_F9,
117 "F10" : _snack.KEY_F10, "F11" : _snack.KEY_F11,
118 "F12" : _snack.KEY_F12 }
119
120 for n in hotkeys.keys():
121 hotkeys[hotkeys[n]] = n
122
123 class Form:
124
125 def addHotKey(self, keyname):
126 self.w.addhotkey(hotkeys[keyname])
127
128 def add(self, widget):
129 if widget.__dict__.has_key('hotkeys'):
130 for key in widget.hotkeys.keys():
131 self.addHotKey(key)
132
133 if widget.__dict__.has_key('gridmembers'):
134 for w in widget.gridmembers:
135 self.add(w)
136 elif widget.__dict__.has_key('w'):
137 self.trans[widget.w.key] = widget
138 return self.w.add(widget.w)
139 return None
140
141 def run(self):
142 (what, which) = self.w.run()
143 if (what == _snack.FORM_EXIT_WIDGET):
144 return self.trans[which]
145
146 return hotkeys[which]
147
148 def __init__(self):
149 self.trans = {}
150 self.w = _snack.form()
151
152 class Grid:
153
154 def place(self, x, y):
155 return self.g.place(x, y)
156
157 def setField(self, what, col, row, padding = (0, 0, 0, 0),
158 anchorLeft = 0, anchorTop = 0, anchorRight = 0,
159 anchorBottom = 0, growx = 0, growy = 0):
160 self.gridmembers.append(what)
161 anchorFlags = 0
162 if (anchorLeft):
163 anchorFlags = _snack.ANCHOR_LEFT
164 elif (anchorRight):
165 anchorFlags = _snack.ANCHOR_RIGHT
166
167 if (anchorTop):
168 anchorFlags = anchorFlags | _snack.ANCHOR_TOP
169 elif (anchorBottom):
170 anchorFlags = anchorFlags | _snack.ANCHOR_BOTTOM
171
172 gridFlags = 0
173 if (growx):
174 gridFlags = _snack.GRID_GROWX
175 if (growy):
176 gridFlags = gridFlags | _snack.GRID_GROWY
177
178 if (what.__dict__.has_key('g')):
179 return self.g.setfield(col, row, what.g, padding, anchorFlags,
180 gridFlags)
181 else:
182 return self.g.setfield(col, row, what.w, padding, anchorFlags)
183
184 def __init__(self, *args):
185 self.g = apply(_snack.grid, args)
186 self.gridmembers = []
187
188 class SnackScreen:
189
190 def __init__(self):
191 _snack.init()
192 (self.width, self.height) = _snack.size()
193 self.pushHelpLine(None)
194
195 def finish(self):
196 return _snack.finish()
197
198 def openWindow(self, left, top, width, height, title):
199 return _snack.openwindow(left, top, width, height, title)
200
201 def pushHelpLine(self, text):
202 if (not text):
203 return _snack.pushhelpline("*default*")
204 else:
205 return _snack.pushhelpline(text)
206
207 def popHelpLine(self):
208 return _snack.pophelpline()
209
210 def drawRootText(self, left, top, text):
211 return _snack.drawroottext(left, top, text)
212
213 def centeredWindow(self, width, height, title):
214 return _snack.centeredwindow(width, height, title)
215
216 def gridWrappedWindow(self, grid, title):
217 return _snack.gridwrappedwindow(grid.g, title)
218
219 def popWindow(self):
220 return _snack.popwindow()
221
222 def refresh(self):
223 return _snack.refresh()
224
225 # returns a tuple of the wrapped text, the actual width, and the actual height
226 def reflow(text, width, flexDown = 5, flexUp = 5):
227 return _snack.reflow(text, width, flexDown, flexUp)
228
229 # combo widgets
230
231 class RadioGroup(Widget):
232
233 def __init__(self):
234 self.prev = None
235 self.buttonlist = []
236
237 def add(self, title, value, default = None):
238 if not self.prev and default == None:
239 # If the first element is not explicitly set to
240 # not be the default, make it be the default
241 default = 1
242 b = SingleRadioButton(title, self.prev, default)
243 self.prev = b
244 self.buttonlist.append((b, value))
245 return b
246
247 def getSelection(self):
248 for (b, value) in self.buttonlist:
249 if b.selected(): return value
250 return None
251
252
253 class RadioBar(Grid):
254
255 def __init__(self, screen, buttonlist):
256 self.list = []
257 self.item = 0
258 self.group = RadioGroup()
259 Grid.__init__(self, 1, len(buttonlist))
260 for (title, value, default) in buttonlist:
261 b = self.group.add(title, value, default)
262 self.list.append(b, value)
263 self.setField(b, 0, self.item, anchorLeft = 1)
264 self.item = self.item + 1
265
266 def getSelection(self):
267 return self.group.getSelection()
268
269
270 # you normally want to pack a ButtonBar with growx = 1
271
272 class ButtonBar(Grid):
273
274 def __init__(self, screen, buttonlist):
275 self.list = []
276 self.hotkeys = {}
277 self.item = 0
278 Grid.__init__(self, len(buttonlist), 1)
279 for blist in buttonlist:
280 if (type(blist) == types.StringType):
281 title = blist
282 value = string.lower(blist)
283 elif len(blist) == 2:
284 (title, value) = blist
285 else:
286 (title, value, hotkey) = blist
287 self.hotkeys[hotkey] = value
288
289 b = Button(title)
290 self.list.append(b, value)
291 self.setField(b, self.item, 0, (1, 0, 1, 0))
292 self.item = self.item + 1
293
294 def buttonPressed(self, result):
295 """Takes the widget returned by Form.run and looks to see
296 if it was one of the widgets in the ButtonBar."""
297
298 if self.hotkeys.has_key(result):
299 return self.hotkeys[result]
300
301 for (button, value) in self.list:
302 if result == button:
303 return value
304 return None
305
306
307 class GridForm(Grid):
308
309 def __init__(self, screen, title, *args):
310 self.screen = screen
311 self.title = title
312 self.form = Form()
313 self.childList = []
314 self.form_created = 0
315 args = list(args)
316 args[:0] = [self]
317 apply(Grid.__init__, tuple(args))
318
319 def add(self, widget, col, row, padding = (0, 0, 0, 0),
320 anchorLeft = 0, anchorTop = 0, anchorRight = 0,
321 anchorBottom = 0, growx = 0, growy = 0):
322 self.setField(widget, col, row, padding, anchorLeft,
323 anchorTop, anchorRight, anchorBottom,
324 growx, growy);
325 self.childList.append(widget)
326
327 def runOnce(self):
328 result = self.run()
329 self.screen.popWindow()
330 return result
331
332 def run(self):
333 if not self.form_created:
334 self.place(1,1)
335 for child in self.childList:
336 self.form.add(child)
337 self.screen.gridWrappedWindow(self, self.title)
338 self.form_created = 1
339 return self.form.run()
340
341 def runPopup(self):
342 if not self.form_created:
343 self.place(1,1)
344 for child in self.childList:
345 self.form.add(child)
346 self.form_created = 1
347 self.screen.gridWrappedWindow(self, self.title)
348 result = self.form.run()
349 self.screen.popWindow()
350 return result
351
352 def ListboxChoiceWindow(screen, title, text, items,
353 buttons = ('Ok', 'Cancel'),
354 width = 40, scroll = 0, height = -1):
355 if (height == -1): height = len(items)
356
357 bb = ButtonBar(screen, buttons)
358 t = TextboxReflowed(width, text)
359 l = Listbox(height, scroll = scroll, returnExit = 1)
360 count = 0
361 for item in items:
362 if (type(item) == types.TupleType):
363 (text, key) = item
364 else:
365 text = item
366 key = count
367
368 l.append(text, key)
369 count = count + 1
370
371 g = GridForm(screen, title, 1, 3)
372 g.add(t, 0, 0)
373 g.add(l, 0, 1, padding = (0, 1, 0, 1))
374 g.add(bb, 0, 2, growx = 1)
375
376 rc = g.runOnce()
377
378 return (bb.buttonPressed(rc), l.current())
379
380 def ButtonChoiceWindow(screen, title, text,
381 buttons = [ 'Ok', 'Cancel' ],
382 width = 40):
383 bb = ButtonBar(screen, buttons)
384 t = TextboxReflowed(width, text)
385
386 g = GridForm(screen, title, 1, 2)
387 g.add(t, 0, 0, padding = (0, 0, 0, 1))
388 g.add(bb, 0, 1, growx = 1)
389 return bb.buttonPressed(g.runOnce())
390
391 def EntryWindow(screen, title, text, prompts, allowCancel = 1, width = 40,
392 entryWidth = 20):
393 bb = ButtonBar(screen, [ 'Ok', 'Cancel' ]);
394 t = TextboxReflowed(width, text)
395
396 count = 0
397 for n in prompts:
398 count = count + 1
399
400 sg = Grid(2, count)
401
402 count = 0
403 entryList = []
404 for n in prompts:
405 if (type(n) == types.TupleType):
406 (n, e) = n
407 else:
408 e = Entry(entryWidth)
409
410 sg.setField(Label(n), 0, count, padding = (0, 0, 1, 0), anchorLeft = 1)
411 sg.setField(e, 1, count, anchorLeft = 1)
412 count = count + 1
413 entryList.append(e)
414
415 g = GridForm(screen, title, 1, 3)
416
417 g.add(t, 0, 0, padding = (0, 0, 0, 1))
418 g.add(sg, 0, 1, padding = (0, 0, 0, 1))
419 g.add(bb, 0, 2, growx = 1)
420
421 result = g.runOnce()
422
423 entryValues = []
424 count = 0
425 for n in prompts:
426 entryValues.append(entryList[count].value())
427 count = count + 1
428
429 return (bb.buttonPressed(result), tuple(entryValues))
430