home *** CD-ROM | disk | FTP | other *** search
/ Windows News 2005 November / WNnov2005.iso / Windows / Equipement / Blender / blender-2.37a-windows.exe / $_5_ / .blender / scripts / help_browser.py < prev    next >
Text File  |  2005-06-13  |  19KB  |  790 lines

  1. #!BPY
  2.  
  3. """
  4. Name: 'Scripts Help Browser'
  5. Blender: 234
  6. Group: 'Help'
  7. Tooltip: 'Show help information about a chosen installed script.'
  8. """
  9.  
  10. __author__ = "Willian P. Germano"
  11. __version__ = "0.1 11/02/04"
  12. __email__ = ('scripts', 'Author, wgermano:ig*com*br')
  13. __url__ = ('blender', 'elysiun')
  14.  
  15. __bpydoc__ ="""\
  16. This script shows help information for scripts registered in the menus.
  17.  
  18. Usage:
  19.  
  20. - Start Screen:
  21.  
  22. To read any script's "user manual" select a script from one of the
  23. available category menus.  If the script has help information in the format
  24. expected by this Help Browser, it will be displayed in the Script Help
  25. Screen.  Otherwise you'll be offered the possibility of loading the chosen
  26. script's source file in Blender's Text Editor.  The programmer(s) may have
  27. written useful comments there for users.
  28.  
  29. Hotkeys:<br>
  30.    ESC or Q: [Q]uit
  31.  
  32. - Script Help Screen:
  33.  
  34. This screen shows the user manual page for the chosen script. If the text
  35. doesn't fit completely on the screen, you can scroll it up or down with
  36. arrow keys or a mouse wheel.  There may be link and email buttons that if
  37. clicked should open your default web browser and email client programs for
  38. further information or support.
  39.  
  40. Hotkeys:<br>
  41.    ESC: back to Start Screen<br>
  42.    Q:   [Q]uit<br>
  43.    S:   view script's [S]ource code in Text Editor<br>
  44.    UP, DOWN Arrows and mouse wheel: scroll text up / down
  45. """
  46.  
  47. # $Id: help_browser.py,v 1.4 2005/06/11 05:30:13 ianwill Exp $
  48. #
  49. # --------------------------------------------------------------------------
  50. # sysinfo.py version 0.1 Jun 09, 2004
  51. # --------------------------------------------------------------------------
  52. # ***** BEGIN GPL LICENSE BLOCK *****
  53. #
  54. # Copyright (C) 2004: Willian P. Germano, wgermano _at_ ig.com.br
  55. #
  56. # This program is free software; you can redistribute it and/or
  57. # modify it under the terms of the GNU General Public License
  58. # as published by the Free Software Foundation; either version 2
  59. # of the License, or (at your option) any later version.
  60. #
  61. # This program is distributed in the hope that it will be useful,
  62. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  63. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  64. # GNU General Public License for more details.
  65. #
  66. # You should have received a copy of the GNU General Public License
  67. # along with this program; if not, write to the Free Software Foundation,
  68. # Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  69. #
  70. # ***** END GPL LICENCE BLOCK *****
  71. # --------------------------------------------------------------------------
  72.  
  73. import Blender
  74. from Blender import sys as bsys, Draw, Window, Registry
  75.  
  76. WEBBROWSER = True
  77. try:
  78.     import webbrowser
  79. except:
  80.     WEBBROWSER = False
  81.  
  82. DEFAULT_EMAILS = {
  83.     'scripts': ['Bf-scripts-dev', 'bf-scripts-dev@blender.org']
  84. }
  85.  
  86. DEFAULT_LINKS = {
  87.     'blender': ["blender.org\'s Python forum", "http://www.blender.org/modules.php?op=modload&name=phpBB2&file=viewforum&f=9"],
  88.     'elysiun': ["elYsiun\'s Python and Plugins forum", "http://www.elysiun.com/forum/viewforum.php?f=5"]
  89. }
  90.  
  91. PADDING = 15
  92. COLUMNS = 1
  93. TEXT_WRAP = 100
  94. WIN_W = WIN_H = 200
  95. SCROLL_DOWN = 0
  96.  
  97. def screen_was_resized():
  98.     global WIN_W, WIN_H
  99.  
  100.     w, h = Window.GetAreaSize()
  101.     if WIN_W != w or WIN_H != h:
  102.         WIN_W = w
  103.         WIN_H = h
  104.         return True
  105.     return False
  106.  
  107. def fit_on_screen():
  108.     global TEXT_WRAP, PADDING, WIN_W, WIN_H, COLUMNS
  109.  
  110.     COLUMNS = 1
  111.     WIN_W, WIN_H = Window.GetAreaSize()
  112.     TEXT_WRAP = int((WIN_W - PADDING) / 6)
  113.     if TEXT_WRAP < 40:
  114.         TEXT_WRAP = 40
  115.     elif TEXT_WRAP > 100:
  116.         if TEXT_WRAP > 110:
  117.             COLUMNS = 2
  118.             TEXT_WRAP /= 2
  119.         else: TEXT_WRAP = 100
  120.  
  121. def cut_point(text, length):
  122.     "Returns position of the last space found before 'length' chars"
  123.     l = length
  124.     c = text[l]
  125.     while c != ' ':
  126.         l -= 1
  127.         if l == 0: return length # no space found
  128.         c = text[l]
  129.     return l
  130.  
  131. def text_wrap(text, length = None):
  132.     global TEXT_WRAP
  133.  
  134.     wrapped = []
  135.     lines = text.split('<br>')
  136.     llen = len(lines)
  137.     if llen > 1:
  138.         if lines[-1] == '': llen -= 1
  139.         for i in range(llen - 1):
  140.             lines[i] = lines[i].rstrip() + '<br>'
  141.         lines[llen-1] = lines[llen-1].rstrip()
  142.  
  143.     if not length: length = TEXT_WRAP
  144.  
  145.     for l in lines:
  146.         while len(l) > length:
  147.             cpt = cut_point(l, length)
  148.             line, l = l[:cpt], l[cpt + 1:]
  149.             wrapped.append(line)
  150.         wrapped.append(l)
  151.     return wrapped
  152.  
  153. def load_script_text(script):
  154.     global PATHS, SCRIPT_INFO
  155.  
  156.     if script.userdir:
  157.         path = PATHS['uscripts']
  158.     else:
  159.         path = PATHS['scripts']
  160.  
  161.     fname = bsys.join(path, script.fname)
  162.  
  163.     source = Blender.Text.Load(fname)
  164.     if source:
  165.         Draw.PupMenu("File loaded%%t|Please check the file \"%s\" in the Text Editor window" % source.name)
  166.  
  167.  
  168. # for theme colors:
  169. def float_colors(cols):
  170.     return map(lambda x: x / 255.0, cols)
  171.  
  172. # globals
  173.  
  174. SCRIPT_INFO = None
  175.  
  176. PATHS = {
  177.     'home': Blender.Get('homedir'),
  178.     'scripts': Blender.Get('scriptsdir'),
  179.     'uscripts': Blender.Get('uscriptsdir')
  180. }
  181.  
  182. if not PATHS['home']:
  183.     errmsg = """
  184. Can't find Blender's home dir and so can't find the
  185. Bpymenus file automatically stored inside it, which
  186. is needed by this script.  Please run the
  187. Help -> System -> System Information script to get
  188. information about how to fix this.
  189. """
  190.     raise SystemError, errmsg
  191.  
  192. BPYMENUS_FILE = bsys.join(PATHS['home'], 'Bpymenus')
  193.  
  194. f = file(BPYMENUS_FILE, 'r')
  195. lines = f.readlines()
  196. f.close()
  197.  
  198. AllGroups = []
  199.  
  200. class Script:
  201.  
  202.     def __init__(self, data):
  203.         self.name = data[0]
  204.         self.version = data[1]
  205.         self.fname = data[2]
  206.         self.userdir = data[3]
  207.         self.tip = data[4]
  208.  
  209. # End of class Script
  210.  
  211.  
  212. class Group:
  213.  
  214.     def __init__(self, name):
  215.         self.name = name
  216.         self.scripts = []
  217.  
  218.     def add_script(self, script):
  219.         self.scripts.append(script)
  220.  
  221.     def get_name(self):
  222.         return self.name
  223.  
  224.     def get_scripts(self):
  225.         return self.scripts
  226.  
  227. # End of class Group
  228.  
  229.  
  230. class BPy_Info:
  231.  
  232.     def __init__(self, script, dict):
  233.  
  234.         self.script = script
  235.  
  236.         self.d = dict
  237.  
  238.         self.header = []
  239.         self.len_header = 0
  240.         self.content = []
  241.         self.len_content = 0
  242.         self.spaces = 0
  243.         self.fix_urls()
  244.         self.make_header()
  245.         self.wrap_lines()
  246.  
  247.     def make_header(self):
  248.  
  249.         sc = self.script
  250.         d = self.d
  251.  
  252.         header = self.header
  253.  
  254.         title = "Script: %s" % sc.name
  255.         version = "Version: %s for Blender %1.2f or newer" % (d['__version__'],
  256.             sc.version / 100.0)
  257.  
  258.         if len(d['__author__']) == 1:
  259.             asuffix = ':'
  260.         else: asuffix = 's:'
  261.  
  262.         authors = "%s%s %s" % ("Author", asuffix, ", ".join(d['__author__']))
  263.  
  264.         header.append(title)
  265.         header.append(version)
  266.         header.append(authors)
  267.         self.len_header = len(header)
  268.  
  269.  
  270.     def fix_urls(self):
  271.  
  272.         emails = self.d['__email__']
  273.         fixed = []
  274.         for a in emails:
  275.             if a in DEFAULT_EMAILS.keys():
  276.                 fixed.append(DEFAULT_EMAILS[a])
  277.             else:
  278.                 a = a.replace('*','.').replace(':','@')
  279.                 ltmp = a.split(',')
  280.                 if len(ltmp) != 2:
  281.                     ltmp = [ltmp[0], ltmp[0]]
  282.                 fixed.append(ltmp)
  283.  
  284.         self.d['__email__'] = fixed
  285.  
  286.         links = self.d['__url__']
  287.         fixed = []
  288.         for a in links:
  289.             if a in DEFAULT_LINKS.keys():
  290.                 fixed.append(DEFAULT_LINKS[a])
  291.             else:
  292.                 ltmp = a.split(',')
  293.                 if len(ltmp) != 2:
  294.                     ltmp = [ltmp[0], ltmp[0]]
  295.                 fixed.append([ltmp[0].strip(), ltmp[1].strip()])
  296.  
  297.         self.d['__url__'] = fixed
  298.  
  299.  
  300.     def wrap_lines(self, reset = 0):
  301.  
  302.         lines = self.d['__bpydoc__'].split('\n')
  303.         self.content = []
  304.         newlines = []
  305.         newline = []
  306.  
  307.         if reset:
  308.             self.len_content = 0
  309.             self.spaces = 0
  310.  
  311.         for l in lines:
  312.             if l == '' and newline:
  313.                 newlines.append(newline)
  314.                 newline = []
  315.                 newlines.append('')
  316.             else: newline.append(l)
  317.         if newline: newlines.append(newline)
  318.  
  319.         for lst in newlines:
  320.             wrapped = text_wrap(" ".join(lst))
  321.             for l in wrapped:
  322.                 self.content.append(l)
  323.                 if l: self.len_content += 1
  324.                 else: self.spaces += 1
  325.  
  326.         if not self.content[-1]:
  327.             self.len_content -= 1
  328.  
  329.  
  330. # End of class BPy_Info
  331.  
  332. def parse_pyobj_close(closetag, lines, i):
  333.     i += 1
  334.     l = lines[i]
  335.     while l.find(closetag) < 0:
  336.         i += 1
  337.         l = "%s%s" % (l, lines[i])
  338.     return [l, i]
  339.  
  340. def parse_pyobj(var, lines, i):
  341.     "Bad code, was in a hurry for release"
  342.  
  343.     l = lines[i].replace(var, '').replace('=','',1).strip()
  344.  
  345.     i0 = i - 1
  346.  
  347.     if l[0] == '"':
  348.         if l[1:3] == '""': # """
  349.             if l.find('"""', 3) < 0: # multiline
  350.                 l2, i = parse_pyobj_close('"""', lines, i)
  351.                 if l[-1] == '\\': l = l[:-1]
  352.                 l = "%s%s" % (l, l2)
  353.         elif l[-1] == '"' and l[-2] != '\\': # single line: "..."
  354.             pass
  355.         else:
  356.             l = "ERROR"
  357.  
  358.     elif l[0] == "'":
  359.         if l[-1] == '\\':
  360.             l2, i = parse_pyobj_close("'", lines, i)
  361.             l = "%s%s" % (l, l2)
  362.         elif l[-1] == "'" and l[-2] !=  '\\': # single line: '...'
  363.             pass
  364.         else:
  365.             l = "ERROR"
  366.  
  367.     elif l[0] == '(':
  368.         if l[-1] != ')':
  369.             l2, i = parse_pyobj_close(')', lines, i)
  370.             l = "%s%s" % (l, l2)
  371.  
  372.     elif l[0] == '[':
  373.         if l[-1] != ']':
  374.             l2, i = parse_pyobj_close(']', lines, i)
  375.             l = "%s%s" % (l, l2)
  376.  
  377.     return [l, i - i0]
  378.  
  379. # helper functions:
  380.  
  381. def parse_help_info(script):
  382.  
  383.     global PATHS, SCRIPT_INFO
  384.  
  385.     if script.userdir:
  386.         path = PATHS['uscripts']
  387.     else:
  388.         path = PATHS['scripts']
  389.  
  390.     fname = bsys.join(path, script.fname)
  391.  
  392.     if not bsys.exists(fname):
  393.         Draw.PupMenu('IO Error: couldn\'t find script %s' % fname)
  394.         return None
  395.  
  396.     f = file(fname, 'r')
  397.     lines = f.readlines()
  398.     f.close()
  399.  
  400.     # fix line endings:
  401.     if lines[0].find('\r'):
  402.         unixlines = []
  403.         for l in lines:
  404.             unixlines.append(l.replace('\r',''))
  405.         lines = unixlines
  406.  
  407.     llen = len(lines)
  408.     has_doc = 0
  409.  
  410.     doc_data = {
  411.         '__author__': '',
  412.         '__version__': '',
  413.         '__url__': '',
  414.         '__email__': '',
  415.         '__bpydoc__': '',
  416.         '__doc__': ''
  417.     }
  418.  
  419.     i = 0
  420.     while i < llen:
  421.         l = lines[i]
  422.         incr = 1
  423.         for k in doc_data.keys():
  424.             if l.find(k, 0, 20) == 0:
  425.                 value, incr = parse_pyobj(k, lines, i)
  426.                 exec("doc_data['%s'] = %s" % (k, value))
  427.                 has_doc = 1
  428.                 break
  429.         i += incr
  430.  
  431.     # fix these to seqs, simplifies coding elsewhere
  432.     for w in ['__author__', '__url__', '__email__']:
  433.         val = doc_data[w]
  434.         if val and type(val) == str:
  435.             doc_data[w] = [doc_data[w]]
  436.  
  437.     if not doc_data['__bpydoc__']:
  438.         if doc_data['__doc__']:
  439.             doc_data['__bpydoc__'] = doc_data['__doc__']
  440.  
  441.     if has_doc: # any data, maybe should confirm at least doc/bpydoc
  442.         info = BPy_Info(script, doc_data)
  443.         SCRIPT_INFO = info
  444.         return True
  445.  
  446.     else:
  447.         return False
  448.  
  449.  
  450. def parse_script_line(l):
  451.  
  452.     try:
  453.         pieces = l.split("'")
  454.         name = pieces[1].replace('...','')
  455.         version, fname, userdir = pieces[2].strip().split()
  456.         tip = pieces[3]
  457.     except:
  458.         return None
  459.  
  460.     return [name, int(version), fname, int(userdir), tip]
  461.  
  462.  
  463. def parse_bpymenus(lines):
  464.  
  465.     global AllGroups
  466.  
  467.     llen = len(lines)
  468.  
  469.     for i in range(llen):
  470.         l = lines[i].strip()
  471.         if not l: continue
  472.         if l[-1] == '{':
  473.             group = Group(l[:-2])
  474.             AllGroups.append(group)
  475.             i += 1
  476.             l = lines[i].strip()
  477.             while l != '}':
  478.                 if l[0] != '|':
  479.                     data = parse_script_line(l)
  480.                     if data:
  481.                         script = Script(data)
  482.                         group.add_script(script)
  483.                 i += 1
  484.                 l = lines[i].strip()
  485.  
  486. #    AllGroups.reverse()
  487.  
  488.  
  489. def create_group_menus():
  490.  
  491.     global AllGroups
  492.     menus = []
  493.  
  494.     for group in AllGroups:
  495.  
  496.         name = group.get_name()
  497.         menu = []
  498.         scripts = group.get_scripts()
  499.         for s in scripts: menu.append(s.name)
  500.         menu = "|".join(menu)
  501.         menu = "%s%%t|%s" % (name, menu)
  502.         menus.append([name, menu])
  503.  
  504.     return menus
  505.  
  506.  
  507. # Collecting data:
  508. fit_on_screen()
  509. parse_bpymenus(lines)
  510. GROUP_MENUS = create_group_menus()
  511.  
  512.  
  513. # GUI:
  514.  
  515. from Blender import BGL
  516. from Blender.Window import Theme
  517.  
  518. # globals:
  519.  
  520. START_SCREEN  = 0
  521. SCRIPT_SCREEN = 1
  522.  
  523. SCREEN = START_SCREEN
  524.  
  525. # gui buttons:
  526. len_gmenus = len(GROUP_MENUS)
  527.  
  528. BUT_GMENU = range(len_gmenus)
  529. for i in range(len_gmenus):
  530.     BUT_GMENU[i] = Draw.Create(0)
  531.  
  532. # events:
  533. BEVT_LINK  = None # range(len(SCRIPT_INFO.links))
  534. BEVT_EMAIL = None # range(len(SCRIPT_INFO.emails))
  535. BEVT_GMENU = range(100, len_gmenus + 100)
  536. BEVT_VIEWSOURCE = 1
  537. BEVT_EXIT = 2
  538. BEVT_BACK = 3
  539.  
  540. # gui callbacks:
  541.  
  542. def gui(): # drawing the screen
  543.  
  544.     global SCREEN, START_SCREEN, SCRIPT_SCREEN
  545.     global SCRIPT_INFO, AllGroups, GROUP_MENUS
  546.     global BEVT_EMAIL, BEVT_LINK
  547.     global BEVT_VIEWSOURCE, BEVT_EXIT, BEVT_BACK, BEVT_GMENU, BUT_GMENU
  548.     global PADDING, WIN_W, WIN_H, SCROLL_DOWN, COLUMNS, FMODE
  549.  
  550.     theme = Theme.Get()[0]
  551.     tui = theme.get('ui')
  552.     ttxt = theme.get('text')
  553.  
  554.     COL_BG = float_colors(ttxt.back)
  555.     COL_TXT = ttxt.text
  556.     COL_TXTHI = ttxt.text_hi
  557.  
  558.     BGL.glClearColor(COL_BG[0],COL_BG[1],COL_BG[2],COL_BG[3])
  559.     BGL.glClear(BGL.GL_COLOR_BUFFER_BIT)
  560.     BGL.glColor3ub(COL_TXT[0],COL_TXT[1], COL_TXT[2])
  561.  
  562.     resize = screen_was_resized()
  563.     if resize: fit_on_screen()
  564.  
  565.     if SCREEN == START_SCREEN:
  566.         x = PADDING
  567.         bw = 85
  568.         bh = 25
  569.         hincr = 50
  570.  
  571.         butcolumns = (WIN_W - 2*x)/ bw
  572.         if butcolumns < 2: butcolumns = 2
  573.         elif butcolumns > 7: butcolumns = 7
  574.  
  575.         len_gm = len(GROUP_MENUS)
  576.         butlines = len_gm / butcolumns
  577.         if len_gm % butcolumns: butlines += 1
  578.  
  579.         h = hincr * butlines + 20
  580.         y = h + bh
  581.  
  582.         BGL.glColor3ub(COL_TXTHI[0],COL_TXTHI[1], COL_TXTHI[2])
  583.         BGL.glRasterPos2i(x, y)
  584.         Draw.Text('Scripts Help Browser')
  585.  
  586.         y -= bh
  587.  
  588.         BGL.glColor3ub(COL_TXT[0],COL_TXT[1], COL_TXT[2])
  589.  
  590.         i = 0
  591.         j = 0
  592.         for group_menu in GROUP_MENUS:
  593.             BGL.glRasterPos2i(x, y)
  594.             Draw.Text(group_menu[0]+':')
  595.             BUT_GMENU[j] = Draw.Menu(group_menu[1], BEVT_GMENU[j],
  596.                 x, y-bh-5, bw, bh, 0,
  597.                 'Choose a script to read its help information')
  598.             if i == butcolumns - 1:
  599.                 x = PADDING
  600.                 i = 0
  601.                 y -= hincr
  602.             else:
  603.                 i += 1
  604.                 x += bw + 3
  605.             j += 1
  606.  
  607.         x = PADDING
  608.         y = 10
  609.         BGL.glRasterPos2i(x, y)
  610.         Draw.Text('Select script for its help.  Press Q or ESC to leave.')
  611.  
  612.     elif SCREEN == SCRIPT_SCREEN:
  613.         if SCRIPT_INFO:
  614.  
  615.             if resize:
  616.                 SCRIPT_INFO.wrap_lines(1)
  617.                 SCROLL_DOWN = 0
  618.  
  619.             h = 18 * SCRIPT_INFO.len_content + 12 * SCRIPT_INFO.spaces
  620.             x = PADDING
  621.             y = WIN_H
  622.             bw = 38
  623.             bh = 16
  624.  
  625.             BGL.glColor3ub(COL_TXTHI[0],COL_TXTHI[1], COL_TXTHI[2])
  626.             for line in SCRIPT_INFO.header:
  627.                 y -= 18
  628.                 BGL.glRasterPos2i(x, y)
  629.                 size = Draw.Text(line)
  630.  
  631.             for line in text_wrap('Tooltip: %s' % SCRIPT_INFO.script.tip):
  632.                 y -= 18
  633.                 BGL.glRasterPos2i(x, y)
  634.                 size = Draw.Text(line)
  635.  
  636.             i = 0
  637.             y -= 28
  638.             for data in SCRIPT_INFO.d['__url__']:
  639.                 Draw.PushButton('link %d' % (i + 1), BEVT_LINK[i],
  640.                     x + i*bw, y, bw, bh, data[0])
  641.                 i += 1
  642.             y -= bh + 1
  643.  
  644.             i = 0
  645.             for data in SCRIPT_INFO.d['__email__']:
  646.                 Draw.PushButton('email', BEVT_EMAIL[i], x + i*bw, y, bw, bh, data[0])
  647.                 i += 1
  648.             y -= 18
  649.  
  650.             y0 = y
  651.             BGL.glColor3ub(COL_TXT[0],COL_TXT[1], COL_TXT[2])
  652.             for line in SCRIPT_INFO.content[SCROLL_DOWN:]:
  653.                 if line:
  654.                     line = line.replace('<br>', '')
  655.                     BGL.glRasterPos2i(x, y)
  656.                     Draw.Text(line)
  657.                     y -= 18
  658.                 else: y -= 12
  659.                 if y < PADDING + 20: # reached end, either stop or go to 2nd column
  660.                     if COLUMNS == 1: break
  661.                     elif x == PADDING: # make sure we're still in column 1
  662.                         x = 6*TEXT_WRAP + PADDING / 2
  663.                         y = y0
  664.  
  665.             x = PADDING
  666.             Draw.PushButton('source', BEVT_VIEWSOURCE, x, 17, 45, bh,
  667.                 'View this script\'s source code in the Text Editor (hotkey: S)')
  668.             Draw.PushButton('exit', BEVT_EXIT, x + 45, 17, 45, bh,
  669.                 'Exit from Scripts Help Browser (hotkey: Q)')
  670.             if not FMODE: Draw.PushButton('back', BEVT_BACK, x + 2*45, 17, 45, bh,
  671.                 'Back to scripts selection screen (hotkey: ESC)')
  672.             BGL.glColor3ub(COL_TXTHI[0],COL_TXTHI[1], COL_TXTHI[2])
  673.             BGL.glRasterPos2i(x, 5)
  674.             Draw.Text('use the arrow keys or the mouse wheel to scroll text', 'small')
  675.  
  676. def fit_scroll():
  677.     global SCROLL_DOWN
  678.     if not SCRIPT_INFO:
  679.         SCROLL_DOWN = 0
  680.         return
  681.     max = SCRIPT_INFO.len_content + SCRIPT_INFO.spaces - 1
  682.     if SCROLL_DOWN > max: SCROLL_DOWN = max
  683.     if SCROLL_DOWN < 0: SCROLL_DOWN = 0
  684.  
  685.  
  686. def event(evt, val): # input events
  687.  
  688.     global SCREEN, START_SCREEN, SCRIPT_SCREEN
  689.     global SCROLL_DOWN, FMODE
  690.  
  691.     if not val: return
  692.  
  693.     if evt == Draw.ESCKEY:
  694.         if SCREEN == START_SCREEN or FMODE: Draw.Exit()
  695.         else:
  696.             SCREEN = START_SCREEN
  697.             SCROLL_DOWN = 0
  698.             Draw.Redraw()
  699.         return
  700.     elif evt == Draw.QKEY:
  701.         Draw.Exit()
  702.         return
  703.     elif evt in [Draw.DOWNARROWKEY, Draw.WHEELDOWNMOUSE] and SCREEN == SCRIPT_SCREEN:
  704.         SCROLL_DOWN += 1
  705.         fit_scroll()
  706.         Draw.Redraw()
  707.         return
  708.     elif evt in [Draw.UPARROWKEY, Draw.WHEELUPMOUSE] and SCREEN == SCRIPT_SCREEN:
  709.         SCROLL_DOWN -= 1
  710.         fit_scroll()
  711.         Draw.Redraw()
  712.         return
  713.     elif evt == Draw.SKEY:
  714.         if SCREEN == SCRIPT_SCREEN and SCRIPT_INFO:
  715.             load_script_text(SCRIPT_INFO.script)
  716.             return
  717.  
  718. def button_event(evt): # gui button events
  719.  
  720.     global SCREEN, START_SCREEN, SCRIPT_SCREEN
  721.     global BEVT_LINK, BEVT_EMAIL, BEVT_GMENU, BUT_GMENU, SCRIPT_INFO
  722.     global SCROLL_DOWN, FMODE
  723.  
  724.     if evt >= 100: # group menus
  725.         for i in range(len(BUT_GMENU)):
  726.             if evt == BEVT_GMENU[i]:
  727.                 group = AllGroups[i]
  728.                 index = BUT_GMENU[i].val - 1
  729.                 if index < 0: return # user didn't pick a menu entry
  730.                 script = group.get_scripts()[BUT_GMENU[i].val - 1]
  731.                 if parse_help_info(script):
  732.                     SCREEN = SCRIPT_SCREEN
  733.                     BEVT_LINK = range(20, len(SCRIPT_INFO.d['__url__']) + 20)
  734.                     BEVT_EMAIL = range(50, len(SCRIPT_INFO.d['__email__']) + 50)
  735.                     Draw.Redraw()
  736.                 else:
  737.                     res = Draw.PupMenu("No help available%t|View Source|Cancel")
  738.                     if res == 1:
  739.                         load_script_text(script)
  740.     elif evt >= 20:
  741.         if not WEBBROWSER:
  742.             Draw.PupMenu('Missing standard Python module%t|You need module "webbrowser" to access the web')
  743.             return
  744.  
  745.         if evt >= 50: # script screen email buttons
  746.             email = SCRIPT_INFO.d['__email__'][evt - 50][1]
  747.             webbrowser.open("mailto:%s" % email)
  748.         else: # >= 20: script screen link buttons
  749.             link = SCRIPT_INFO.d['__url__'][evt - 20][1]
  750.             webbrowser.open(link)
  751.     elif evt == BEVT_VIEWSOURCE:
  752.         if SCREEN == SCRIPT_SCREEN: load_script_text(SCRIPT_INFO.script)
  753.     elif evt == BEVT_EXIT:
  754.         Draw.Exit()
  755.         return
  756.     elif evt == BEVT_BACK:
  757.         if SCREEN == SCRIPT_SCREEN and not FMODE:
  758.             SCREEN = START_SCREEN
  759.             SCRIPT_INFO = None
  760.             SCROLL_DOWN = 0
  761.             Draw.Redraw()
  762.  
  763. keepon = True
  764. FMODE = False # called by Blender.ShowHelp(name) API function ?
  765.  
  766. KEYNAME = '__help_browser'
  767. rd = Registry.GetKey(KEYNAME)
  768. if rd:
  769.     rdscript = rd['script']
  770.     keepon = False
  771.     Registry.RemoveKey(KEYNAME)
  772.     for group in AllGroups:
  773.         for script in group.get_scripts():
  774.             if rdscript == script.fname:
  775.                 parseit = parse_help_info(script)
  776.                 if parseit == True:
  777.                     keepon = True
  778.                     SCREEN = SCRIPT_SCREEN
  779.                     BEVT_LINK = range(20, len(SCRIPT_INFO.d['__url__']) + 20)
  780.                     BEVT_EMAIL = range(50, len(SCRIPT_INFO.d['__email__']) + 50)
  781.                     FMODE = True
  782.                 elif parseit == False:
  783.                     Draw.PupMenu("ERROR: script doesn't have proper help data")
  784.                 break
  785.  
  786. if not keepon:
  787.     Draw.PupMenu("ERROR: couldn't find script")
  788. else:
  789.     Draw.Register(gui, event, button_event)
  790.