Bump version number to 2.4.2 to pick up the latest minor bug fixes.
[python/dscho.git] / Mac / Lib / EasyDialogs.py
blob52aad9791d9efdb1c85df5bd00bbe3e0dd78a284
1 """Easy to use dialogs.
3 Message(msg) -- display a message and an OK button.
4 AskString(prompt, default) -- ask for a string, display OK and Cancel buttons.
5 AskPassword(prompt, default) -- like AskString(), but shows text as bullets.
6 AskYesNoCancel(question, default) -- display a question and Yes, No and Cancel buttons.
7 bar = Progress(label, maxvalue) -- Display a progress bar
8 bar.set(value) -- Set value
9 bar.inc( *amount ) -- increment value by amount (default=1)
10 bar.label( *newlabel ) -- get or set text label.
12 More documentation in each function.
13 This module uses DLOG resources 260 and on.
14 Based upon STDWIN dialogs with the same names and functions.
15 """
17 from Carbon.Dlg import GetNewDialog, SetDialogItemText, GetDialogItemText, ModalDialog
18 from Carbon import Qd
19 from Carbon import QuickDraw
20 from Carbon import Dialogs
21 from Carbon import Windows
22 from Carbon import Dlg,Win,Evt,Events # sdm7g
23 from Carbon import Ctl
24 from Carbon import Controls
25 from Carbon import Menu
26 import MacOS
27 import string
28 from Carbon.ControlAccessor import * # Also import Controls constants
29 import macfs
31 def cr2lf(text):
32 if '\r' in text:
33 text = string.join(string.split(text, '\r'), '\n')
34 return text
36 def lf2cr(text):
37 if '\n' in text:
38 text = string.join(string.split(text, '\n'), '\r')
39 if len(text) > 253:
40 text = text[:253] + '\311'
41 return text
43 def Message(msg, id=260, ok=None):
44 """Display a MESSAGE string.
46 Return when the user clicks the OK button or presses Return.
48 The MESSAGE string can be at most 255 characters long.
49 """
51 d = GetNewDialog(id, -1)
52 if not d:
53 print "EasyDialogs: Can't get DLOG resource with id =", id, " (missing resource file?)"
54 return
55 h = d.GetDialogItemAsControl(2)
56 SetDialogItemText(h, lf2cr(msg))
57 if ok != None:
58 h = d.GetDialogItemAsControl(1)
59 h.SetControlTitle(ok)
60 d.SetDialogDefaultItem(1)
61 d.AutoSizeDialog()
62 d.GetDialogWindow().ShowWindow()
63 while 1:
64 n = ModalDialog(None)
65 if n == 1:
66 return
69 def AskString(prompt, default = "", id=261, ok=None, cancel=None):
70 """Display a PROMPT string and a text entry field with a DEFAULT string.
72 Return the contents of the text entry field when the user clicks the
73 OK button or presses Return.
74 Return None when the user clicks the Cancel button.
76 If omitted, DEFAULT is empty.
78 The PROMPT and DEFAULT strings, as well as the return value,
79 can be at most 255 characters long.
80 """
82 d = GetNewDialog(id, -1)
83 if not d:
84 print "EasyDialogs: Can't get DLOG resource with id =", id, " (missing resource file?)"
85 return
86 h = d.GetDialogItemAsControl(3)
87 SetDialogItemText(h, lf2cr(prompt))
88 h = d.GetDialogItemAsControl(4)
89 SetDialogItemText(h, lf2cr(default))
90 d.SelectDialogItemText(4, 0, 999)
91 # d.SetDialogItem(4, 0, 255)
92 if ok != None:
93 h = d.GetDialogItemAsControl(1)
94 h.SetControlTitle(ok)
95 if cancel != None:
96 h = d.GetDialogItemAsControl(2)
97 h.SetControlTitle(cancel)
98 d.SetDialogDefaultItem(1)
99 d.SetDialogCancelItem(2)
100 d.AutoSizeDialog()
101 d.GetDialogWindow().ShowWindow()
102 while 1:
103 n = ModalDialog(None)
104 if n == 1:
105 h = d.GetDialogItemAsControl(4)
106 return cr2lf(GetDialogItemText(h))
107 if n == 2: return None
109 def AskPassword(prompt, default='', id=264, ok=None, cancel=None):
110 """Display a PROMPT string and a text entry field with a DEFAULT string.
111 The string is displayed as bullets only.
113 Return the contents of the text entry field when the user clicks the
114 OK button or presses Return.
115 Return None when the user clicks the Cancel button.
117 If omitted, DEFAULT is empty.
119 The PROMPT and DEFAULT strings, as well as the return value,
120 can be at most 255 characters long.
122 d = GetNewDialog(id, -1)
123 if not d:
124 print "EasyDialogs: Can't get DLOG resource with id =", id, " (missing resource file?)"
125 return
126 h = d.GetDialogItemAsControl(3)
127 SetDialogItemText(h, lf2cr(prompt))
128 pwd = d.GetDialogItemAsControl(4)
129 bullets = '\245'*len(default)
130 ## SetControlData(pwd, kControlEditTextPart, kControlEditTextTextTag, bullets)
131 SetControlData(pwd, kControlEditTextPart, kControlEditTextPasswordTag, default)
132 d.SelectDialogItemText(4, 0, 999)
133 Ctl.SetKeyboardFocus(d.GetDialogWindow(), pwd, kControlEditTextPart)
134 if ok != None:
135 h = d.GetDialogItemAsControl(1)
136 h.SetControlTitle(ok)
137 if cancel != None:
138 h = d.GetDialogItemAsControl(2)
139 h.SetControlTitle(cancel)
140 d.SetDialogDefaultItem(Dialogs.ok)
141 d.SetDialogCancelItem(Dialogs.cancel)
142 d.AutoSizeDialog()
143 d.GetDialogWindow().ShowWindow()
144 while 1:
145 n = ModalDialog(None)
146 if n == 1:
147 h = d.GetDialogItemAsControl(4)
148 return cr2lf(GetControlData(pwd, kControlEditTextPart, kControlEditTextPasswordTag))
149 if n == 2: return None
151 def AskYesNoCancel(question, default = 0, yes=None, no=None, cancel=None, id=262):
152 """Display a QUESTION string which can be answered with Yes or No.
154 Return 1 when the user clicks the Yes button.
155 Return 0 when the user clicks the No button.
156 Return -1 when the user clicks the Cancel button.
158 When the user presses Return, the DEFAULT value is returned.
159 If omitted, this is 0 (No).
161 The QUESTION string can be at most 255 characters.
164 d = GetNewDialog(id, -1)
165 if not d:
166 print "EasyDialogs: Can't get DLOG resource with id =", id, " (missing resource file?)"
167 return
168 # Button assignments:
169 # 1 = default (invisible)
170 # 2 = Yes
171 # 3 = No
172 # 4 = Cancel
173 # The question string is item 5
174 h = d.GetDialogItemAsControl(5)
175 SetDialogItemText(h, lf2cr(question))
176 if yes != None:
177 if yes == '':
178 d.HideDialogItem(2)
179 else:
180 h = d.GetDialogItemAsControl(2)
181 h.SetControlTitle(yes)
182 if no != None:
183 if no == '':
184 d.HideDialogItem(3)
185 else:
186 h = d.GetDialogItemAsControl(3)
187 h.SetControlTitle(no)
188 if cancel != None:
189 if cancel == '':
190 d.HideDialogItem(4)
191 else:
192 h = d.GetDialogItemAsControl(4)
193 h.SetControlTitle(cancel)
194 d.SetDialogCancelItem(4)
195 if default == 1:
196 d.SetDialogDefaultItem(2)
197 elif default == 0:
198 d.SetDialogDefaultItem(3)
199 elif default == -1:
200 d.SetDialogDefaultItem(4)
201 d.AutoSizeDialog()
202 d.GetDialogWindow().ShowWindow()
203 while 1:
204 n = ModalDialog(None)
205 if n == 1: return default
206 if n == 2: return 1
207 if n == 3: return 0
208 if n == 4: return -1
213 screenbounds = Qd.qd.screenBits.bounds
214 screenbounds = screenbounds[0]+4, screenbounds[1]+4, \
215 screenbounds[2]-4, screenbounds[3]-4
217 kControlProgressBarIndeterminateTag = 'inde' # from Controls.py
220 class ProgressBar:
221 def __init__(self, title="Working...", maxval=0, label="", id=263):
222 self.w = None
223 self.d = None
224 self.d = GetNewDialog(id, -1)
225 self.w = self.d.GetDialogWindow()
226 self.label(label)
227 self.title(title)
228 self.set(0, maxval)
229 self.d.AutoSizeDialog()
230 self.w.ShowWindow()
231 self.d.DrawDialog()
233 def __del__( self ):
234 if self.w:
235 self.w.BringToFront()
236 self.w.HideWindow()
237 del self.w
238 del self.d
240 def title(self, newstr=""):
241 """title(text) - Set title of progress window"""
242 self.w.BringToFront()
243 self.w.SetWTitle(newstr)
245 def label( self, *newstr ):
246 """label(text) - Set text in progress box"""
247 self.w.BringToFront()
248 if newstr:
249 self._label = lf2cr(newstr[0])
250 text_h = self.d.GetDialogItemAsControl(2)
251 SetDialogItemText(text_h, self._label)
253 def _update(self, value):
254 maxval = self.maxval
255 if maxval == 0: # an indeterminate bar
256 Ctl.IdleControls(self.w) # spin the barber pole
257 else: # a determinate bar
258 if maxval > 32767:
259 value = int(value/(maxval/32767.0))
260 maxval = 32767
261 progbar = self.d.GetDialogItemAsControl(3)
262 progbar.SetControlMaximum(maxval)
263 progbar.SetControlValue(value) # set the bar length
265 # Test for cancel button
266 ready, ev = Evt.WaitNextEvent( Events.mDownMask, 1 )
267 if ready :
268 what,msg,when,where,mod = ev
269 part = Win.FindWindow(where)[0]
270 if Dlg.IsDialogEvent(ev):
271 ds = Dlg.DialogSelect(ev)
272 if ds[0] and ds[1] == self.d and ds[-1] == 1:
273 self.w.HideWindow()
274 self.w = None
275 self.d = None
276 raise KeyboardInterrupt, ev
277 else:
278 if part == 4: # inDrag
279 self.w.DragWindow(where, screenbounds)
280 else:
281 MacOS.HandleEvent(ev)
284 def set(self, value, max=None):
285 """set(value) - Set progress bar position"""
286 if max != None:
287 self.maxval = max
288 bar = self.d.GetDialogItemAsControl(3)
289 if max <= 0: # indeterminate bar
290 bar.SetControlData(0,kControlProgressBarIndeterminateTag,'\x01')
291 else: # determinate bar
292 bar.SetControlData(0,kControlProgressBarIndeterminateTag,'\x00')
293 if value < 0:
294 value = 0
295 elif value > self.maxval:
296 value = self.maxval
297 self.curval = value
298 self._update(value)
300 def inc(self, n=1):
301 """inc(amt) - Increment progress bar position"""
302 self.set(self.curval + n)
304 ARGV_ID=265
305 ARGV_ITEM_OK=1
306 ARGV_ITEM_CANCEL=2
307 ARGV_OPTION_GROUP=3
308 ARGV_OPTION_EXPLAIN=4
309 ARGV_OPTION_VALUE=5
310 ARGV_OPTION_ADD=6
311 ARGV_COMMAND_GROUP=7
312 ARGV_COMMAND_EXPLAIN=8
313 ARGV_COMMAND_ADD=9
314 ARGV_ADD_OLDFILE=10
315 ARGV_ADD_NEWFILE=11
316 ARGV_ADD_FOLDER=12
317 ARGV_CMDLINE_GROUP=13
318 ARGV_CMDLINE_DATA=14
320 ##def _myModalDialog(d):
321 ## while 1:
322 ## ready, ev = Evt.WaitNextEvent(0xffff, -1)
323 ## print 'DBG: WNE', ready, ev
324 ## if ready :
325 ## what,msg,when,where,mod = ev
326 ## part, window = Win.FindWindow(where)
327 ## if Dlg.IsDialogEvent(ev):
328 ## didit, dlgdone, itemdone = Dlg.DialogSelect(ev)
329 ## print 'DBG: DialogSelect', didit, dlgdone, itemdone, d
330 ## if didit and dlgdone == d:
331 ## return itemdone
332 ## elif window == d.GetDialogWindow():
333 ## d.GetDialogWindow().SelectWindow()
334 ## if part == 4: # inDrag
335 ## d.DragWindow(where, screenbounds)
336 ## else:
337 ## MacOS.HandleEvent(ev)
338 ## else:
339 ## MacOS.HandleEvent(ev)
341 def _setmenu(control, items):
342 mhandle = control.GetControlData_Handle(Controls.kControlMenuPart,
343 Controls.kControlPopupButtonMenuHandleTag)
344 menu = Menu.as_Menu(mhandle)
345 for item in items:
346 if type(item) == type(()):
347 label = item[0]
348 else:
349 label = item
350 if label[-1] == '=' or label[-1] == ':':
351 label = label[:-1]
352 menu.AppendMenu(label)
353 ## mhandle, mid = menu.getpopupinfo()
354 ## control.SetControlData_Handle(Controls.kControlMenuPart,
355 ## Controls.kControlPopupButtonMenuHandleTag, mhandle)
356 control.SetControlMinimum(1)
357 control.SetControlMaximum(len(items)+1)
359 def _selectoption(d, optionlist, idx):
360 if idx < 0 or idx >= len(optionlist):
361 MacOS.SysBeep()
362 return
363 option = optionlist[idx]
364 if type(option) == type(()):
365 if len(option) == 4:
366 help = option[2]
367 elif len(option) > 1:
368 help = option[-1]
369 else:
370 help = ''
371 else:
372 help = ''
373 h = d.GetDialogItemAsControl(ARGV_OPTION_EXPLAIN)
374 if help and len(help) > 250:
375 help = help[:250] + '...'
376 Dlg.SetDialogItemText(h, help)
377 hasvalue = 0
378 if type(option) == type(()):
379 label = option[0]
380 else:
381 label = option
382 if label[-1] == '=' or label[-1] == ':':
383 hasvalue = 1
384 h = d.GetDialogItemAsControl(ARGV_OPTION_VALUE)
385 Dlg.SetDialogItemText(h, '')
386 if hasvalue:
387 d.ShowDialogItem(ARGV_OPTION_VALUE)
388 d.SelectDialogItemText(ARGV_OPTION_VALUE, 0, 0)
389 else:
390 d.HideDialogItem(ARGV_OPTION_VALUE)
393 def GetArgv(optionlist=None, commandlist=None, addoldfile=1, addnewfile=1, addfolder=1, id=ARGV_ID):
394 d = GetNewDialog(id, -1)
395 if not d:
396 print "EasyDialogs: Can't get DLOG resource with id =", id, " (missing resource file?)"
397 return
398 # h = d.GetDialogItemAsControl(3)
399 # SetDialogItemText(h, lf2cr(prompt))
400 # h = d.GetDialogItemAsControl(4)
401 # SetDialogItemText(h, lf2cr(default))
402 # d.SelectDialogItemText(4, 0, 999)
403 # d.SetDialogItem(4, 0, 255)
404 if optionlist:
405 _setmenu(d.GetDialogItemAsControl(ARGV_OPTION_GROUP), optionlist)
406 _selectoption(d, optionlist, 0)
407 else:
408 d.GetDialogItemAsControl(ARGV_OPTION_GROUP).DeactivateControl()
409 if commandlist:
410 _setmenu(d.GetDialogItemAsControl(ARGV_COMMAND_GROUP), commandlist)
411 if type(commandlist[0]) == type(()) and len(commandlist[0]) > 1:
412 help = commandlist[0][-1]
413 h = d.GetDialogItemAsControl(ARGV_COMMAND_EXPLAIN)
414 Dlg.SetDialogItemText(h, help)
415 else:
416 d.GetDialogItemAsControl(ARGV_COMMAND_GROUP).DeactivateControl()
417 if not addoldfile:
418 d.GetDialogItemAsControl(ARGV_ADD_OLDFILE).DeactivateControl()
419 if not addnewfile:
420 d.GetDialogItemAsControl(ARGV_ADD_NEWFILE).DeactivateControl()
421 if not addfolder:
422 d.GetDialogItemAsControl(ARGV_ADD_FOLDER).DeactivateControl()
423 d.SetDialogDefaultItem(ARGV_ITEM_OK)
424 d.SetDialogCancelItem(ARGV_ITEM_CANCEL)
425 d.GetDialogWindow().ShowWindow()
426 d.DrawDialog()
427 if hasattr(MacOS, 'SchedParams'):
428 appsw = MacOS.SchedParams(1, 0)
429 try:
430 while 1:
431 stringstoadd = []
432 n = ModalDialog(None)
433 if n == ARGV_ITEM_OK:
434 break
435 elif n == ARGV_ITEM_CANCEL:
436 raise SystemExit
437 elif n == ARGV_OPTION_GROUP:
438 idx = d.GetDialogItemAsControl(ARGV_OPTION_GROUP).GetControlValue()-1
439 _selectoption(d, optionlist, idx)
440 elif n == ARGV_OPTION_VALUE:
441 pass
442 elif n == ARGV_OPTION_ADD:
443 idx = d.GetDialogItemAsControl(ARGV_OPTION_GROUP).GetControlValue()-1
444 if 0 <= idx < len(optionlist):
445 option = optionlist[idx]
446 if type(option) == type(()):
447 option = option[0]
448 if option[-1] == '=' or option[-1] == ':':
449 option = option[:-1]
450 h = d.GetDialogItemAsControl(ARGV_OPTION_VALUE)
451 value = Dlg.GetDialogItemText(h)
452 else:
453 value = ''
454 if len(option) == 1:
455 stringtoadd = '-' + option
456 else:
457 stringtoadd = '--' + option
458 stringstoadd = [stringtoadd]
459 if value:
460 stringstoadd.append(value)
461 else:
462 MacOS.SysBeep()
463 elif n == ARGV_COMMAND_GROUP:
464 idx = d.GetDialogItemAsControl(ARGV_COMMAND_GROUP).GetControlValue()-1
465 if 0 <= idx < len(commandlist) and type(commandlist[idx]) == type(()) and \
466 len(commandlist[idx]) > 1:
467 help = commandlist[idx][-1]
468 h = d.GetDialogItemAsControl(ARGV_COMMAND_EXPLAIN)
469 Dlg.SetDialogItemText(h, help)
470 elif n == ARGV_COMMAND_ADD:
471 idx = d.GetDialogItemAsControl(ARGV_COMMAND_GROUP).GetControlValue()-1
472 if 0 <= idx < len(commandlist):
473 command = commandlist[idx]
474 if type(command) == type(()):
475 command = command[0]
476 stringstoadd = [command]
477 else:
478 MacOS.SysBeep()
479 elif n == ARGV_ADD_OLDFILE:
480 fss, ok = macfs.StandardGetFile()
481 if ok:
482 stringstoadd = [fss.as_pathname()]
483 elif n == ARGV_ADD_NEWFILE:
484 fss, ok = macfs.StandardPutFile('')
485 if ok:
486 stringstoadd = [fss.as_pathname()]
487 elif n == ARGV_ADD_FOLDER:
488 fss, ok = macfs.GetDirectory()
489 if ok:
490 stringstoadd = [fss.as_pathname()]
491 elif n == ARGV_CMDLINE_DATA:
492 pass # Nothing to do
493 else:
494 raise RuntimeError, "Unknown dialog item %d"%n
496 for stringtoadd in stringstoadd:
497 if '"' in stringtoadd or "'" in stringtoadd or " " in stringtoadd:
498 stringtoadd = `stringtoadd`
499 h = d.GetDialogItemAsControl(ARGV_CMDLINE_DATA)
500 oldstr = GetDialogItemText(h)
501 if oldstr and oldstr[-1] != ' ':
502 oldstr = oldstr + ' '
503 oldstr = oldstr + stringtoadd
504 if oldstr[-1] != ' ':
505 oldstr = oldstr + ' '
506 SetDialogItemText(h, oldstr)
507 d.SelectDialogItemText(ARGV_CMDLINE_DATA, 0x7fff, 0x7fff)
508 h = d.GetDialogItemAsControl(ARGV_CMDLINE_DATA)
509 oldstr = GetDialogItemText(h)
510 tmplist = string.split(oldstr)
511 newlist = []
512 while tmplist:
513 item = tmplist[0]
514 del tmplist[0]
515 if item[0] == '"':
516 while item[-1] != '"':
517 if not tmplist:
518 raise RuntimeError, "Unterminated quoted argument"
519 item = item + ' ' + tmplist[0]
520 del tmplist[0]
521 item = item[1:-1]
522 if item[0] == "'":
523 while item[-1] != "'":
524 if not tmplist:
525 raise RuntimeError, "Unterminated quoted argument"
526 item = item + ' ' + tmplist[0]
527 del tmplist[0]
528 item = item[1:-1]
529 newlist.append(item)
530 return newlist
531 finally:
532 if hasattr(MacOS, 'SchedParams'):
533 apply(MacOS.SchedParams, appsw)
534 del d
536 def test():
537 import time, sys
539 Message("Testing EasyDialogs.")
540 optionlist = (('v', 'Verbose'), ('verbose', 'Verbose as long option'),
541 ('flags=', 'Valued option'), ('f:', 'Short valued option'))
542 commandlist = (('start', 'Start something'), ('stop', 'Stop something'))
543 argv = GetArgv(optionlist=optionlist, commandlist=commandlist, addoldfile=0)
544 for i in range(len(argv)):
545 print 'arg[%d] = %s'%(i, `argv[i]`)
546 print 'Type return to continue - ',
547 sys.stdin.readline()
548 ok = AskYesNoCancel("Do you want to proceed?")
549 ok = AskYesNoCancel("Do you want to identify?", yes="Identify", no="No")
550 if ok > 0:
551 s = AskString("Enter your first name", "Joe")
552 s2 = AskPassword("Okay %s, tell us your nickname"%s, s, cancel="None")
553 if not s2:
554 Message("%s has no secret nickname"%s)
555 else:
556 Message("Hello everybody!!\nThe secret nickname of %s is %s!!!"%(s, s2))
557 text = ( "Working Hard...", "Hardly Working..." ,
558 "So far, so good!", "Keep on truckin'" )
559 bar = ProgressBar("Progress, progress...", 0, label="Ramping up...")
560 try:
561 if hasattr(MacOS, 'SchedParams'):
562 appsw = MacOS.SchedParams(1, 0)
563 for i in xrange(20):
564 bar.inc()
565 time.sleep(0.05)
566 bar.set(0,100)
567 for i in xrange(100):
568 bar.set(i)
569 time.sleep(0.05)
570 if i % 10 == 0:
571 bar.label(text[(i/10) % 4])
572 bar.label("Done.")
573 time.sleep(1.0) # give'em a chance to see "Done."
574 finally:
575 del bar
576 if hasattr(MacOS, 'SchedParams'):
577 apply(MacOS.SchedParams, appsw)
579 if __name__ == '__main__':
580 try:
581 test()
582 except KeyboardInterrupt:
583 Message("Operation Canceled.")