Subversion Repositories HelenOS

Rev

Rev 3805 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

  1. #
  2. # Copyright (c) 2009 Martin Decky
  3. # All rights reserved.
  4. #
  5. # Redistribution and use in source and binary forms, with or without
  6. # modification, are permitted provided that the following conditions
  7. # are met:
  8. #
  9. # - Redistributions of source code must retain the above copyright
  10. #   notice, this list of conditions and the following disclaimer.
  11. # - Redistributions in binary form must reproduce the above copyright
  12. #   notice, this list of conditions and the following disclaimer in the
  13. #   documentation and/or other materials provided with the distribution.
  14. # - The name of the author may not be used to endorse or promote products
  15. #   derived from this software without specific prior written permission.
  16. #
  17. # THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
  18. # IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  19. # OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
  20. # IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
  21. # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  22. # NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  23. # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  24. # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  25. # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  26. # THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  27. #
  28. """
  29. Text User Interface wrapper
  30. """
  31.  
  32. import sys
  33. import os
  34.  
  35. def call_dlg(dlgcmd, *args, **kw):
  36.     "Wrapper for calling 'dialog' program"
  37.    
  38.     indesc, outdesc = os.pipe()
  39.     pid = os.fork()
  40.     if (not pid):
  41.         os.close(2)
  42.         os.dup(outdesc)
  43.         os.close(indesc)
  44.        
  45.         dlgargs = [dlgcmd]
  46.         for key, val in kw.items():
  47.             dlgargs.append('--' + key)
  48.             dlgargs.append(val)
  49.        
  50.         dlgargs += args
  51.         os.execlp(dlgcmd, *dlgargs)
  52.    
  53.     os.close(outdesc)
  54.    
  55.     try:
  56.         errout = os.fdopen(indesc, 'r')
  57.         data = errout.read()
  58.         errout.close()
  59.         pid, status = os.wait()
  60.     except:
  61.         # Reset terminal
  62.         os.system('reset')
  63.         raise
  64.    
  65.     if (not os.WIFEXITED(status)):
  66.         # Reset terminal
  67.         os.system('reset')
  68.         raise EOFError
  69.    
  70.     status = os.WEXITSTATUS(status)
  71.     if (status == 255):
  72.         raise EOFError
  73.    
  74.     return (status, data)
  75.  
  76. try:
  77.     import snack
  78.     newt = True
  79.     dialog = False
  80. except ImportError:
  81.     newt = False
  82.    
  83.     dlgcmd = os.environ.get('DIALOG', 'dialog')
  84.     if (call_dlg(dlgcmd, '--print-maxsize')[0] != 0):
  85.         dialog = False
  86.     else:
  87.         dialog = True
  88.  
  89. width_extra = 13
  90. height_extra = 11
  91.  
  92. def width_fix(screen, width):
  93.     "Correct width to screen size"
  94.    
  95.     if (width + width_extra > screen.width):
  96.         width = screen.width - width_extra
  97.    
  98.     if (width <= 0):
  99.         width = screen.width
  100.    
  101.     return width
  102.  
  103. def height_fix(screen, height):
  104.     "Correct height to screen size"
  105.    
  106.     if (height + height_extra > screen.height):
  107.         height = screen.height - height_extra
  108.    
  109.     if (height <= 0):
  110.         height = screen.height
  111.    
  112.     return height
  113.  
  114. def screen_init():
  115.     "Initialize the screen"
  116.    
  117.     if (newt):
  118.         return snack.SnackScreen()
  119.    
  120.     return None
  121.  
  122. def screen_done(screen):
  123.     "Cleanup the screen"
  124.    
  125.     if (newt):
  126.         screen.finish()
  127.  
  128. def choice_window(screen, title, text, options, position):
  129.     "Create options menu"
  130.    
  131.     maxopt = 0
  132.     for option in options:
  133.         length = len(option)
  134.         if (length > maxopt):
  135.             maxopt = length
  136.    
  137.     width = maxopt
  138.     height = len(options)
  139.    
  140.     if (newt):
  141.         width = width_fix(screen, width + width_extra)
  142.         height = height_fix(screen, height)
  143.        
  144.         buttonbar = snack.ButtonBar(screen, ('Done', 'Cancel'))
  145.         textbox = snack.TextboxReflowed(width, text)
  146.         listbox = snack.Listbox(height, scroll = True, returnExit = 1)
  147.        
  148.         cnt = 0
  149.         for option in options:
  150.             listbox.append(option, cnt)
  151.             cnt += 1
  152.        
  153.         if (position != None):
  154.             listbox.setCurrent(position)
  155.        
  156.         grid = snack.GridForm(screen, title, 1, 3)
  157.         grid.add(textbox, 0, 0)
  158.         grid.add(listbox, 0, 1, padding = (0, 1, 0, 1))
  159.         grid.add(buttonbar, 0, 2, growx = 1)
  160.        
  161.         retval = grid.runOnce()
  162.        
  163.         return (buttonbar.buttonPressed(retval), listbox.current())
  164.     elif (dialog):
  165.         args = []
  166.         cnt = 0
  167.         for option in options:
  168.             args.append(str(cnt + 1))
  169.             args.append(option)
  170.            
  171.             cnt += 1
  172.        
  173.         kw = {}
  174.         if (position != None):
  175.             kw['default-item'] = str(position + 1)
  176.        
  177.         status, data = call_dlg(dlgcmd, '--title', title, '--extra-button', '--extra-label', 'Done', '--menu', text, str(height + height_extra), str(width + width_extra), str(cnt), *args, **kw)
  178.        
  179.         if (status == 1):
  180.             return ('cancel', None)
  181.        
  182.         try:
  183.             choice = int(data) - 1
  184.         except ValueError:
  185.             return ('cancel', None)
  186.        
  187.         if (status == 0):
  188.             return (None, choice)
  189.        
  190.         return ('done', choice)
  191.    
  192.     sys.stdout.write("\n *** %s *** \n%s\n\n" % (title, text))
  193.    
  194.     maxcnt = len(str(len(options)))
  195.     cnt = 0
  196.     for option in options:
  197.         sys.stdout.write("%*s. %s\n" % (maxcnt, cnt + 1, option))
  198.         cnt += 1
  199.    
  200.     sys.stdout.write("\n%*s. Done\n" % (maxcnt, '0'))
  201.     sys.stdout.write("%*s. Quit\n\n" % (maxcnt, 'q'))
  202.    
  203.     while True:
  204.         if (position != None):
  205.             sys.stdout.write("Selection[%s]: " % str(position + 1))
  206.         else:
  207.             sys.stdout.write("Selection: ")
  208.         inp = sys.stdin.readline()
  209.        
  210.         if (not inp):
  211.             raise EOFError
  212.        
  213.         if (not inp.strip()):
  214.             if (position != None):
  215.                 return (None, position)
  216.             continue
  217.        
  218.         if (inp.strip() == 'q'):
  219.             return ('cancel', None)
  220.        
  221.         try:
  222.             choice = int(inp.strip())
  223.         except ValueError:
  224.             continue
  225.        
  226.         if (choice == 0):
  227.             return ('done', 0)
  228.        
  229.         if (choice < 1) or (choice > len(options)):
  230.             continue
  231.        
  232.         return (None, choice - 1)
  233.  
  234. def error_dialog(screen, title, msg):
  235.     "Print error dialog"
  236.    
  237.     width = len(msg)
  238.    
  239.     if (newt):
  240.         width = width_fix(screen, width)
  241.        
  242.         buttonbar = snack.ButtonBar(screen, ['Ok'])
  243.         textbox = snack.TextboxReflowed(width, msg)
  244.        
  245.         grid = snack.GridForm(screen, title, 1, 2)
  246.         grid.add(textbox, 0, 0, padding = (0, 0, 0, 1))
  247.         grid.add(buttonbar, 0, 1, growx = 1)
  248.         grid.runOnce()
  249.     elif (dialog):
  250.         call_dlg(dlgcmd, '--title', title, '--msgbox', msg, '6', str(width + width_extra))
  251.    
  252.     sys.stdout.write("\n%s: %s\n" % (title, msg))
  253.