Subversion Repositories HelenOS

Rev

Go to most recent revision | Blame | 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.         if (height > 3):
  145.             large = True
  146.         else:
  147.             large = False
  148.        
  149.         buttonbar = snack.ButtonBar(screen, ('Done', 'Cancel'))
  150.         textbox = snack.TextboxReflowed(width, text)
  151.         listbox = snack.Listbox(height, scroll = large, returnExit = 1)
  152.        
  153.         cnt = 0
  154.         for option in options:
  155.             listbox.append(option, cnt)
  156.             cnt += 1
  157.        
  158.         if (position != None):
  159.             listbox.setCurrent(position)
  160.        
  161.         grid = snack.GridForm(screen, title, 1, 3)
  162.         grid.add(textbox, 0, 0)
  163.         grid.add(listbox, 0, 1, padding = (0, 1, 0, 1))
  164.         grid.add(buttonbar, 0, 2, growx = 1)
  165.        
  166.         retval = grid.runOnce()
  167.        
  168.         return (buttonbar.buttonPressed(retval), listbox.current())
  169.     elif (dialog):
  170.         if (width < 35):
  171.             width = 35
  172.        
  173.         args = []
  174.         cnt = 0
  175.         for option in options:
  176.             args.append(str(cnt + 1))
  177.             args.append(option)
  178.            
  179.             cnt += 1
  180.        
  181.         kw = {}
  182.         if (position != None):
  183.             kw['default-item'] = str(position + 1)
  184.        
  185.         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)
  186.        
  187.         if (status == 1):
  188.             return ('cancel', None)
  189.        
  190.         try:
  191.             choice = int(data) - 1
  192.         except ValueError:
  193.             return ('cancel', None)
  194.        
  195.         if (status == 0):
  196.             return (None, choice)
  197.        
  198.         return ('done', choice)
  199.    
  200.     sys.stdout.write("\n *** %s *** \n%s\n\n" % (title, text))
  201.    
  202.     maxcnt = len(str(len(options)))
  203.     cnt = 0
  204.     for option in options:
  205.         sys.stdout.write("%*s. %s\n" % (maxcnt, cnt + 1, option))
  206.         cnt += 1
  207.    
  208.     sys.stdout.write("\n%*s. Done\n" % (maxcnt, '0'))
  209.     sys.stdout.write("%*s. Quit\n\n" % (maxcnt, 'q'))
  210.    
  211.     while True:
  212.         if (position != None):
  213.             sys.stdout.write("Selection[%s]: " % str(position + 1))
  214.         else:
  215.             sys.stdout.write("Selection: ")
  216.         inp = sys.stdin.readline()
  217.        
  218.         if (not inp):
  219.             raise EOFError
  220.        
  221.         if (not inp.strip()):
  222.             if (position != None):
  223.                 return (None, position)
  224.             continue
  225.        
  226.         if (inp.strip() == 'q'):
  227.             return ('cancel', None)
  228.        
  229.         try:
  230.             choice = int(inp.strip())
  231.         except ValueError:
  232.             continue
  233.        
  234.         if (choice == 0):
  235.             return ('done', 0)
  236.        
  237.         if (choice < 1) or (choice > len(options)):
  238.             continue
  239.        
  240.         return (None, choice - 1)
  241.  
  242. def error_dialog(screen, title, msg):
  243.     "Print error dialog"
  244.    
  245.     width = len(msg)
  246.    
  247.     if (newt):
  248.         width = width_fix(screen, width)
  249.        
  250.         buttonbar = snack.ButtonBar(screen, ['Ok'])
  251.         textbox = snack.TextboxReflowed(width, msg)
  252.        
  253.         grid = snack.GridForm(screen, title, 1, 2)
  254.         grid.add(textbox, 0, 0, padding = (0, 0, 0, 1))
  255.         grid.add(buttonbar, 0, 1, growx = 1)
  256.         grid.runOnce()
  257.     elif (dialog):
  258.         call_dlg(dlgcmd, '--title', title, '--msgbox', msg, '6', str(width + width_extra))
  259.     else:
  260.         sys.stdout.write("\n%s: %s\n" % (title, msg))
  261.