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