home *** CD-ROM | disk | FTP | other *** search
/ Windows News 2005 November / WNnov2005.iso / Windows / Equipement / Blender / blender-2.37a-windows.exe / $_5_ / .blender / scripts / config.py < prev    next >
Text File  |  2005-04-16  |  22KB  |  793 lines

  1. #!BPY
  2.  
  3. """
  4. Name: 'Scripts Config Editor'
  5. Blender: 236
  6. Group: 'System'
  7. Tooltip: 'View and edit available scripts configuration data'
  8. """
  9.  
  10. __author__ = "Willian P. Germano"
  11. __version__ = "0.1 2005/04/14"
  12. __email__ = ('scripts', 'Author, wgermano:ig*com*br')
  13. __url__ = ('blender', 'elysiun')
  14.  
  15. __bpydoc__ ="""\
  16. This script can be used to view and edit configuration data stored
  17. by other scripts.
  18.  
  19. Technical: this data is saved as dictionary keys with the
  20. Blender.Registry module functions.  It is persistent while Blender is
  21. running and, if the script's author chose to, is also saved to a file
  22. in the scripts config data dir.
  23.  
  24. Usage:
  25.  
  26. - Start Screen:
  27.  
  28. To access any available key, select it from (one of) the menu(s).
  29.  
  30. Hotkeys:<br>
  31.    ESC or Q: [Q]uit<br>
  32.    H: [H]elp
  33.  
  34. - Keys Config Screen:
  35.  
  36. This screen exposes the configuration data for the chosen script key.  If the
  37. buttons don't fit completely on the screen, you can scroll up or down with
  38. arrow keys or a mouse wheel.  Leave the mouse pointer over any button to get
  39. a tooltip about that option.
  40.  
  41. Any change can be reverted -- unless you have already applied it.
  42.  
  43. If the key is already stored in a config file, there will be a toggle button
  44. (called 'file') that controls whether the changes will be written back to
  45. the file or not.  If you just want to change the configuration for the current
  46. session, simply unset that button.  Note, though, that data from files has
  47. precedence over those keys already loaded in Blender, so if you re-run this
  48. config editor, unsaved changes will not be seen.
  49.  
  50. Hotkeys:<br>
  51.    ESC: back to Start Screen<br>
  52.    Q: [Q]uit<br>
  53.    U: [U]ndo changes<br>
  54.    ENTER: apply changes (can't be reverted, then)<br>
  55.    UP, DOWN Arrows and mouse wheel: scroll text up / down
  56.  
  57. Notes:
  58.  
  59. a) Available keys are determined by which scripts you use.  If the key you
  60. expect isn't available (or maybe there are none or too few keys), either the
  61. related script doesn't need or still doesn't support this feature or the key
  62. has not been stored yet, in which case you just need to run that script once
  63. to make its config data available.
  64.  
  65. b) There are two places where config data files can be saved: the
  66. bpydata/config/ dir (1) inside the default scripts dir or (2) inside the user
  67. defined Python scripts dir
  68. (User Preferences window -> File Paths tab -> Python path).  If available,
  69. (2) is the default and also the recommended option, because then fresh Blender
  70. installations won't delete your config data.  To use this option, simply set a
  71. dir for Python scripts at the User Preferences window and make sure this dir
  72. has the subdirs bpydata/ and bpydata/config/ inside it.
  73.  
  74. c) The key called "General" in the "Other" menu has general config options.
  75. All scripts where that data is relevant are recommended to access it and set
  76. behaviors accordingly.
  77. """
  78.  
  79. # $Id: config.py,v 1.1 2005/04/16 05:25:41 ianwill Exp $
  80. #
  81. # --------------------------------------------------------------------------
  82. # config.py version 0.1 2005/04/08
  83. # --------------------------------------------------------------------------
  84. # ***** BEGIN GPL LICENSE BLOCK *****
  85. #
  86. # Copyright (C) 2004: Willian P. Germano, wgermano _at_ ig.com.br
  87. #
  88. # This program is free software; you can redistribute it and/or
  89. # modify it under the terms of the GNU General Public License
  90. # as published by the Free Software Foundation; either version 2
  91. # of the License, or (at your option) any later version.
  92. #
  93. # This program is distributed in the hope that it will be useful,
  94. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  95. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  96. # GNU General Public License for more details.
  97. #
  98. # You should have received a copy of the GNU General Public License
  99. # along with this program; if not, write to the Free Software Foundation,
  100. # Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  101. #
  102. # ***** END GPL LICENCE BLOCK *****
  103. # --------------------------------------------------------------------------
  104.  
  105. import Blender
  106. from Blender import Draw, BGL, Registry, Window, sys as bsys
  107. from Blender.Window import Theme
  108. from BPyRegistry import LoadConfigData, SaveConfigData, HasConfigData,\
  109.     BPY_KEY_IN_FILE, MAX_STR_LEN, MAX_ITEMS_NUM
  110.  
  111. # ---
  112. # The "General" configure options key is managed from this script.
  113. verbose = True
  114. confirm_overwrite = True
  115.  
  116. tooltips = {
  117.     'verbose': 'print script messages (info, warnings, errors) to the console',
  118.     'confirm_overwrite': 'scripts should always confirm before overwriting files'
  119. }
  120.  
  121. CFG_LIST = ['verbose', 'confirm_overwrite', 'tooltips']
  122. KEY_NAME = 'General'
  123.  
  124. def update_registry():
  125.     rd = {}
  126.     for var in CFG_LIST:
  127.         exec("rd['%s']=%s" % (var, var))
  128.     Registry.SetKey(KEY_NAME, rd, True)
  129.  
  130. rd = Registry.GetKey('General', True)
  131. if rd:
  132.     try:
  133.         for var in CFG_LIST[:-1]: # no need to update tooltips
  134.             exec("%s=rd['%s']" % (var, var))
  135.     except: update_registry()
  136.  
  137. else:
  138.     update_registry()
  139. # ---
  140.  
  141. # script globals:
  142. CFGKEY = ''
  143. LABELS = []
  144. GD = {} # groups dict (includes "Other" for unmapped keys)
  145. INDEX = 0 # to pass button indices to fs callbacks
  146. FREEKEY_IDX = 0 # index of set of keys not mapped to a script name
  147. KEYMENUS = []
  148. ALL_SCRIPTS = {}
  149. ALL_GROUPS = []
  150. START_SCREEN  = 0
  151. CONFIG_SCREEN = 1
  152. DISK_UPDATE = True # write changed data to its config file
  153.  
  154. ACCEPTED_TYPES = [bool, int, float, str, unicode]
  155.  
  156. SCREEN = START_SCREEN
  157.  
  158. SCROLL_DOWN = 0
  159.  
  160. # events:
  161. BEVT_START = 50
  162. BEVT_EXIT = 0 + BEVT_START
  163. BEVT_BACK = 1 + BEVT_START
  164. BEVT_DISK = 2 + BEVT_START
  165. BEVT_CANCEL = 3 + BEVT_START
  166. BEVT_APPLY = 4 + BEVT_START
  167. BEVT_HELP = 5 + BEVT_START
  168. BEVT_DEL = 6 + BEVT_START
  169. BEVT_KEYMENU = []
  170. BUT_KEYMENU = []
  171. BEVT_BOOL = 100
  172. BEVT_INT = BEVT_BOOL + MAX_ITEMS_NUM
  173. BEVT_FLOAT = BEVT_BOOL + 2*MAX_ITEMS_NUM
  174. BEVT_STR = BEVT_BOOL + 3*MAX_ITEMS_NUM
  175. BEVT_BROWSEDIR = BEVT_BOOL + 4*MAX_ITEMS_NUM
  176. BEVT_BROWSEFILE = BEVT_BOOL + 5*MAX_ITEMS_NUM
  177. BUT_TYPES = {
  178.     bool: 0,
  179.     int: 0,
  180.     float: 0,
  181.     str: 0
  182. }
  183.  
  184. # Function definitions:
  185.  
  186. def get_keys():
  187.     LoadConfigData() # loads all data from files in (u)scripts/bpydata/config/
  188.     return [k for k in Registry.Keys() if k[0] != "_"]
  189.  
  190.  
  191. def show_help(script = 'config.py'):
  192.     Blender.ShowHelp(script)
  193.  
  194.  
  195. def fs_dir_callback(pathname):
  196.     global CFGKEY, INDEX
  197.  
  198.     pathname = bsys.dirname(pathname)
  199.     datatypes = CFGKEY.sorteddata
  200.     datatypes[str][INDEX][1] = pathname
  201.  
  202.  
  203. def fs_file_callback(pathname):
  204.     global CFGKEY, INDEX
  205.  
  206.     datatypes = CFGKEY.sorteddata
  207.     datatypes[str][INDEX][1] = pathname
  208.  
  209.  
  210. # parse Bpymenus file to get all script filenames
  211. # (used to show help for a given key)
  212. def fill_scripts_dict():
  213.     global ALL_SCRIPTS, ALL_GROUPS
  214.  
  215.     group = ''
  216.     group_len = 0
  217.     sep = bsys.sep
  218.     home = Blender.Get('homedir')
  219.     if not home:
  220.         errmsg = """
  221. Can't find Blender's home dir and so can't find the
  222. Bpymenus file automatically stored inside it, which
  223. is needed by this script.  Please run the
  224. Help -> System -> System Information script to get
  225. information about how to fix this.
  226. """
  227.         raise SystemError, errmsg
  228.     fname = bsys.join(home, 'Bpymenus')
  229.     if not bsys.exists(fname): return False
  230.     f = file(fname, 'r')
  231.     lines = f.readlines()
  232.     f.close()
  233.     for l in lines:
  234.         if l.rfind('{') > 0:
  235.             group = l.split()[0]
  236.             ALL_GROUPS.append(group)
  237.             group_len += 1
  238.             continue
  239.         elif l[0] != "'": continue
  240.         fields = l.split("'")
  241.         if len(fields) > 2:
  242.             menuname = fields[1].replace('...','')
  243.             fields = fields[2].split()
  244.             if len(fields) > 1:
  245.                 fname = fields[1].split(sep)[-1]
  246.                 ALL_SCRIPTS[fname] = (menuname, group_len - 1)
  247.     return True
  248.  
  249.  
  250. def map_to_registered_script(name):
  251.     global ALL_SCRIPTS
  252.  
  253.     if not name.endswith('.py'):
  254.         name = "%s.py" % name
  255.     if ALL_SCRIPTS.has_key(name):
  256.         return ALL_SCRIPTS[name] # == (menuname, group index)
  257.     return None
  258.  
  259.  
  260. def reset():
  261.     global LABELS, GD, KEYMENUS, KEYS
  262.  
  263.     # init_data is recalled when a key is deleted, so:
  264.     LABELS = []
  265.     GD = {}
  266.     KEYMENUS = []
  267.     KEYS = get_keys()
  268.  
  269.  
  270. # gather all script info, fill gui menus
  271. def init_data():
  272.     global KEYS, GD, ALL_GROUPS, ALL_SCRIPTS, KEYMENUS, LABELS
  273.     global BUT_KEYMENU, BEVT_KEYMENU, FREEKEY_IDX
  274.  
  275.     for k in ALL_GROUPS:
  276.         GD[k] = []
  277.     GD[None] = []
  278.  
  279.     for k in KEYS:
  280.         res = map_to_registered_script(k)
  281.         if res:
  282.             GD[ALL_GROUPS[res[1]]].append((k, res[0]))
  283.         else: GD[None].append((k, k))
  284.  
  285.     for k in GD.keys():
  286.         if not GD[k]: GD.pop(k)
  287.  
  288.     if GD.has_key(None):
  289.         GD['Other'] = GD[None]
  290.         GD.pop(None)
  291.         FREEKEY_IDX = -1
  292.  
  293.     BUT_KEYMENU = range(len(GD))
  294.  
  295.     for k in GD.keys():
  296.         kmenu = ['Configuration Keys: %s%%t' % k]
  297.         for j in GD[k]:
  298.             kmenu.append(j[1])
  299.         kmenu = "|".join(kmenu)
  300.         KEYMENUS.append(kmenu)
  301.         LABELS.append(k)
  302.  
  303.     if FREEKEY_IDX < 0:
  304.         FREEKEY_IDX = LABELS.index('Other')
  305.  
  306.     length = len(KEYMENUS)
  307.     BEVT_KEYMENU = range(1, length + 1)
  308.     BUT_KEYMENU = range(length)
  309.  
  310.  
  311. # for theme colors:
  312. def float_colors(cols):
  313.     return map(lambda x: x / 255.0, cols)
  314.  
  315.  
  316.  
  317. class Config:
  318.  
  319.     def __init__(self, key, has_group = True):
  320.         global DISK_UPDATE
  321.  
  322.         self.key = key
  323.         self.has_group = has_group
  324.         self.name = key
  325.         self.fromdisk = HasConfigData(key) & BPY_KEY_IN_FILE
  326.         if not self.fromdisk: DISK_UPDATE = False
  327.         else: DISK_UPDATE = True
  328.  
  329.         self.origdata = Registry.GetKey(key, True)
  330.         data = self.data = self.origdata.copy()
  331.  
  332.         if not data:
  333.             Draw.PupMenu('ERROR: couldn\'t find requested data')
  334.             self.data = None
  335.             return
  336.  
  337.         keys = data.keys()
  338.         nd = {}
  339.         for k in keys:
  340.             nd[k.lower()] = k
  341.  
  342.         if nd.has_key('tooltips'):
  343.             ndval = nd['tooltips']
  344.             self.tips = data[ndval]
  345.             data.pop(ndval)
  346.         else: self.tips = 0
  347.  
  348.         if nd.has_key('limits'):
  349.             ndval = nd['limits']
  350.             self.limits = data[ndval]
  351.             data.pop(ndval)
  352.         else: self.limits = 0
  353.  
  354.         if self.has_group:
  355.             scriptname = key
  356.             if not scriptname.endswith('.py'):
  357.                 scriptname = "%s.py" % scriptname
  358.         elif nd.has_key('script'):
  359.                 ndval = nd['script']
  360.                 scriptname = data[ndval]
  361.                 data.pop(ndval)
  362.                 if not scriptname.endswith('.py'):
  363.                     scriptname = "%s.py" % scriptname
  364.         else: scriptname = None
  365.  
  366.         self.scriptname = scriptname
  367.  
  368.         self.sort()
  369.  
  370.  
  371.     def needs_update(self): # check if user changed data
  372.         data = self.data
  373.         new = self.sorteddata
  374.  
  375.         for vartype in new.keys():
  376.             for i in new[vartype]:
  377.                 if data[i[0]] != i[1]: return 1
  378.  
  379.         return 0 # no changes
  380.  
  381.  
  382.     def update(self): # update original key
  383.         global DISK_UPDATE
  384.  
  385.         data = self.data
  386.         odata = self.origdata
  387.         new = self.sorteddata
  388.         for vartype in new.keys():
  389.             for i in new[vartype]:
  390.                 if data[i[0]] != i[1]: data[i[0]] = i[1]
  391.                 if odata[i[0]] != i[1]: odata[i[0]] = i[1]
  392.  
  393.         if DISK_UPDATE: Registry.SetKey(self.key, odata, True)
  394.  
  395.     def delete(self):
  396.         global DISK_UPDATE
  397.  
  398.         delmsg = 'OK?%t|Delete key from memory'
  399.         if DISK_UPDATE:
  400.             delmsg = "%s and from disk" % delmsg
  401.         if Draw.PupMenu(delmsg) == 1:
  402.             Registry.RemoveKey(self.key, DISK_UPDATE)
  403.             return True
  404.  
  405.         return False
  406.  
  407.  
  408.     def revert(self): # revert to original key
  409.         data = self.data
  410.         new = self.sorteddata
  411.         for vartype in new.keys():
  412.             for i in new[vartype]:
  413.                 if data[i[0]] != i[1]: i[1] = data[i[0]]
  414.  
  415.  
  416.     def sort(self): # create a new dict with types as keys
  417.         global ACCEPTED_TYPES, BUT_TYPES
  418.  
  419.         data = self.data
  420.         datatypes = {}
  421.         keys = [k for k in data.keys() if k[0] != '_']
  422.         for k in keys:
  423.             val = data[k]
  424.             tval = type(val)
  425.             if tval not in ACCEPTED_TYPES: continue
  426.             if not datatypes.has_key(tval):
  427.                 datatypes[tval] = []
  428.             datatypes[type(val)].append([k, val])
  429.         if datatypes.has_key(unicode):
  430.             if not datatypes.has_key(str): datatypes[str] = datatypes[unicode]
  431.             else:
  432.                 for i in datatypes[unicode]: datatypes[str].append(i)
  433.             datatypes.pop(unicode)
  434.         for k in datatypes.keys():
  435.             dk = datatypes[k]
  436.             dk.sort()
  437.             dk.reverse()
  438.             BUT_TYPES[k] = range(len(dk))
  439.         self.sorteddata = datatypes
  440.  
  441.  
  442. # GUI:
  443.  
  444. # gui callbacks:
  445.  
  446. def gui(): # drawing the screen
  447.  
  448.     global SCREEN, START_SCREEN, CONFIG_SCREEN, KEYMENUS, LABELS
  449.     global BEVT_KEYMENU, BUT_KEYMENU, CFGKEY
  450.     global BUT_TYPES, SCROLL_DOWN, VARS_NUM
  451.  
  452.     WIDTH, HEIGHT = Window.GetAreaSize()
  453.  
  454.     theme = Theme.Get()[0]
  455.     tui = theme.get('ui')
  456.     ttxt = theme.get('text')
  457.  
  458.     COL_BG = float_colors(ttxt.back)
  459.     COL_TXT = ttxt.text
  460.     COL_TXTHI = ttxt.text_hi
  461.  
  462.     BGL.glClearColor(COL_BG[0],COL_BG[1],COL_BG[2],COL_BG[3])
  463.     BGL.glClear(BGL.GL_COLOR_BUFFER_BIT)
  464.     BGL.glColor3ub(COL_TXT[0],COL_TXT[1], COL_TXT[2])
  465.  
  466.     if SCREEN == START_SCREEN:
  467.         x = 10
  468.         y = 10
  469.         h = 20
  470.         w = 90
  471.         BGL.glRasterPos2i(x, y)
  472.         Draw.Text('Select a configuration key to access it.  Press Q or ESC to leave.')
  473.         km_len = len(KEYMENUS)
  474.         km_columns = (WIDTH - x) / w
  475.         if km_columns == 0: km_rows = km_len
  476.         else:
  477.             km_rows = km_len / km_columns
  478.             if (km_len % km_columns): km_rows += 1
  479.         if km_rows == 0: km_rows = 1
  480.         ystart = y + 2*h*km_rows
  481.         if ystart > (HEIGHT - 70): ystart = HEIGHT - 70
  482.         y = ystart
  483.         column = 1
  484.         for i, km in enumerate(KEYMENUS):
  485.             column += 1
  486.             BGL.glRasterPos2i(x + 2, y + h + 5)
  487.             Draw.Text(LABELS[i])
  488.             BUT_KEYMENU[i] = Draw.Menu(km, BEVT_KEYMENU[i],
  489.                 x, y, w - 10, h, 0, 'Choose a key to access its configuration data')
  490.             if column > km_columns:
  491.                 column = 1
  492.                 y -= 2*h
  493.                 if y < 35: break
  494.                 x = 10
  495.             else: x += w
  496.         x = 10
  497.         y = 50 + ystart
  498.         BGL.glColor3ub(COL_TXTHI[0], COL_TXTHI[1], COL_TXTHI[2])
  499.         BGL.glRasterPos2i(x, y)
  500.         Draw.Text('Scripts Configuration Editor')
  501.         Draw.PushButton('help', BEVT_HELP, x, 22, 45, 16,
  502.             'View help information about this script (hotkey: H)')
  503.  
  504.     elif SCREEN == CONFIG_SCREEN:
  505.         x = y = 10
  506.         h = 18
  507.         data = CFGKEY.sorteddata
  508.         tips = CFGKEY.tips
  509.         fromdisk = CFGKEY.fromdisk
  510.         limits = CFGKEY.limits
  511.         VARS_NUM = 0
  512.         for k in data.keys():
  513.             VARS_NUM += len(data[k])
  514.         lines = VARS_NUM + 5 # to account for header and footer
  515.         y = lines*h
  516.         if y > HEIGHT - 20: y = HEIGHT - 20
  517.         BGL.glColor3ub(COL_TXTHI[0],COL_TXTHI[1], COL_TXTHI[2])
  518.         BGL.glRasterPos2i(x, y)
  519.         Draw.Text('Scripts Configuration Editor')
  520.         y -= 20
  521.         BGL.glColor3ub(COL_TXT[0],COL_TXT[1], COL_TXT[2])
  522.         txtsize = 10
  523.         if HEIGHT < lines*h:
  524.             BGL.glRasterPos2i(10, 5)
  525.             txtsize += Draw.Text('Arrow keys or mouse wheel to scroll, ')
  526.         BGL.glRasterPos2i(txtsize, 5)
  527.         Draw.Text('Q or ESC to return.')
  528.         BGL.glRasterPos2i(x, y)
  529.         Draw.Text('Key: "%s"' % CFGKEY.name)
  530.         bh = 16
  531.         bw = 45
  532.         by = 16
  533.         i = -1
  534.         if CFGKEY.scriptname:
  535.             i = 0
  536.             Draw.PushButton('help', BEVT_HELP, x, by, bw, bh,
  537.                 'Show documentation for the script that owns this key (hotkey: H)')
  538.         Draw.PushButton('back', BEVT_BACK, x + (1+i)*bw, by, bw, bh,
  539.             'Back to config keys selection screen (hotkey: ESC)')
  540.         Draw.PushButton('exit', BEVT_EXIT, x + (2+i)*bw, by, bw, bh,
  541.             'Exit from Scripts Config Editor (hotkey: Q)')
  542.         Draw.PushButton('revert', BEVT_CANCEL, x + (3+i)*bw, by, bw, bh,
  543.             'Revert data to original values (hotkey: U)')
  544.         Draw.PushButton('apply', BEVT_APPLY, x + (4+i)*bw, by, bw, bh,
  545.             'Apply changes, if any (hotkey: ENTER)')
  546.         delmsg = 'Delete this data key from memory'
  547.         if fromdisk: delmsg = "%s and from disk" % delmsg
  548.         Draw.PushButton('delete', BEVT_DEL, x + (5+i)*bw, by, bw, bh,
  549.             '%s (hotkey: DELETE)' % delmsg)
  550.         if fromdisk:
  551.             Draw.Toggle("file", BEVT_DISK, x + 3 + (6+i)*bw, by, bw, bh, DISK_UPDATE,
  552.                 'Update also the file where this config key is stored')
  553.         i = -1
  554.         top = -1
  555.         y -= 20
  556.         yend = 30
  557.         if data.has_key(bool) and y > 0:
  558.             lst = data[bool]
  559.             for l in lst:
  560.                 top += 1
  561.                 i += 1
  562.                 if top < SCROLL_DOWN: continue
  563.                 y -= h
  564.                 if y < yend: break
  565.                 w = 20
  566.                 tog = data[bool][i][1]
  567.                 if tips and tips.has_key(l[0]): tooltip = tips[l[0]]
  568.                 else: tooltip = "click to toggle"
  569.                 BUT_TYPES[bool][i] = Draw.Toggle("", BEVT_BOOL + i,
  570.                     x, y, w, h, tog, tooltip)
  571.                 BGL.glRasterPos2i(x + w + 3, y + 5)
  572.                 Draw.Text(l[0].lower().replace('_', ' '))
  573.             i = -1
  574.             y -= 5
  575.         if data.has_key(int) and y > 0:
  576.             lst = data[int]
  577.             for l in lst:
  578.                 w = 70
  579.                 top += 1
  580.                 i += 1
  581.                 if top < SCROLL_DOWN: continue
  582.                 y -= h
  583.                 if y < yend: break
  584.                 val = data[int][i][1]
  585.                 if limits: min, max = limits[l[0]]
  586.                 else: min, max = 0, 10
  587.                 if tips and tips.has_key(l[0]): tooltip = tips[l[0]]
  588.                 else: tooltip = "click / drag to change"
  589.                 BUT_TYPES[int][i] = Draw.Number("", BEVT_INT + i,
  590.                     x, y, w, h, val, min, max, tooltip)
  591.                 BGL.glRasterPos2i(x + w + 3, y + 3)
  592.                 Draw.Text(l[0].lower().replace('_', ' '))
  593.             i = -1
  594.             y -= 5
  595.         if data.has_key(float) and y > 0:
  596.             lst = data[float]
  597.             for l in lst:
  598.                 w = 70
  599.                 top += 1
  600.                 i += 1
  601.                 if top < SCROLL_DOWN: continue
  602.                 y -= h
  603.                 if y < yend: break
  604.                 val = data[float][i][1]
  605.                 if limits: min, max = limits[l[0]]
  606.                 else: min, max = 0.0, 1.0
  607.                 if tips and tips.has_key(l[0]): tooltip = tips[l[0]]
  608.                 else: tooltip = "click and drag to change"
  609.                 BUT_TYPES[float][i] = Draw.Number("", BEVT_FLOAT + i,
  610.                     x, y, w, h, val, min, max, tooltip)
  611.                 BGL.glRasterPos2i(x + w + 3, y + 3)
  612.                 Draw.Text(l[0].lower().replace('_', ' '))
  613.             i = -1
  614.             y -= 5
  615.         if data.has_key(str) and y > 0:
  616.             lst = data[str]
  617.             for l in lst:
  618.                 top += 1
  619.                 i += 1
  620.                 if top < SCROLL_DOWN: continue
  621.                 y -= h
  622.                 if y < yend: break
  623.                 name = l[0].lower()
  624.                 is_dir = is_file = False
  625.                 if name.find('_dir', -4) > 0:    is_dir = True
  626.                 elif name.find('_file', -5) > 0: is_file = True
  627.                 w = WIDTH - 20
  628.                 wbrowse = 50
  629.                 if is_dir and w > wbrowse: w -= wbrowse
  630.                 if tips and tips.has_key(l[0]): tooltip = tips[l[0]]
  631.                 else: tooltip = "click to write a new string"
  632.                 name = name.replace('_',' ') + ': '
  633.                 BUT_TYPES[str][i] = Draw.String(name, BEVT_STR + i,
  634.                     x, y, w, h, l[1], MAX_STR_LEN, tooltip)
  635.                 if is_dir:
  636.                     Draw.PushButton('browse', BEVT_BROWSEDIR + i, x+w+1, y, wbrowse, h,
  637.                         'click to open a file selector (pick any file in the desired dir)')
  638.                 elif is_file:
  639.                     Draw.PushButton('browse', BEVT_BROWSEFILE + i, x + w + 1, y, 50, h,
  640.                         'click to open a file selector')
  641.  
  642.  
  643. def fit_scroll():
  644.     global SCROLL_DOWN, VARS_NUM
  645.     max = VARS_NUM - 1 # so last item is always visible
  646.     if SCROLL_DOWN > max:
  647.         SCROLL_DOWN = max
  648.     elif SCROLL_DOWN < 0:
  649.         SCROLL_DOWN = 0
  650.  
  651.  
  652. def event(evt, val): # input events
  653.  
  654.     global SCREEN, START_SCREEN, CONFIG_SCREEN
  655.     global SCROLL_DOWN, CFGKEY
  656.  
  657.     if not val: return
  658.  
  659.     if evt == Draw.ESCKEY:
  660.         if SCREEN == START_SCREEN: Draw.Exit()
  661.         else:
  662.             if CFGKEY.needs_update():
  663.                 if Draw.PupMenu('UPDATE?%t|Data was changed') == 1:
  664.                     CFGKEY.update()
  665.             SCREEN = START_SCREEN
  666.             SCROLL_DOWN = 0
  667.             Draw.Redraw()
  668.         return
  669.     elif evt == Draw.QKEY:
  670.         if SCREEN == CONFIG_SCREEN and CFGKEY.needs_update():
  671.             if Draw.PupMenu('UPDATE?%t|Data was changed') == 1:
  672.                 CFGKEY.update()
  673.         Draw.Exit()
  674.         return
  675.     elif evt == Draw.HKEY:
  676.         if SCREEN == START_SCREEN: show_help()
  677.         elif CFGKEY.scriptname: show_help(CFGKEY.scriptname)
  678.         return
  679.  
  680.     elif SCREEN == CONFIG_SCREEN:
  681.         if evt in [Draw.DOWNARROWKEY, Draw.WHEELDOWNMOUSE]:
  682.             SCROLL_DOWN += 1
  683.             fit_scroll()
  684.         elif evt in [Draw.UPARROWKEY, Draw.WHEELUPMOUSE]:
  685.             SCROLL_DOWN -= 1
  686.             fit_scroll()
  687.         elif evt == Draw.UKEY:
  688.             if CFGKEY.needs_update():
  689.                 CFGKEY.revert()
  690.         elif evt == Draw.RETKEY or evt == Draw.PADENTER:
  691.             if CFGKEY.needs_update():
  692.                 CFGKEY.update()
  693.         elif evt == Draw.DELKEY:
  694.             if CFGKEY.delete():
  695.                 reset()
  696.                 init_data()
  697.                 SCREEN = START_SCREEN
  698.                 SCROLL_DOWN = 0
  699.         else: return
  700.         Draw.Redraw()
  701.  
  702.  
  703. def button_event(evt): # gui button events
  704.  
  705.     global SCREEN, START_SCREEN, CONFIG_SCREEN, CFGKEY, DISK_UPDATE
  706.     global BEVT_KEYMENU, BUT_KEYMENU, BUT_TYPES, SCROLL_DOWN, GD, INDEX
  707.     global BEVT_EXIT, BEVT_BACK, BEVT_APPLY, BEVT_CANCEL, BEVT_HELP, FREEKEY_IDX
  708.  
  709.     if SCREEN == START_SCREEN:
  710.         for e in BEVT_KEYMENU:
  711.             if evt == e:
  712.                 index = e - 1
  713.                 k = BUT_KEYMENU[index].val - 1
  714.                 CFGKEY = Config(GD[LABELS[index]][k][0], index != FREEKEY_IDX)
  715.                 if CFGKEY.data:
  716.                     SCREEN = CONFIG_SCREEN
  717.                     Draw.Redraw()
  718.                     return
  719.         if evt == BEVT_EXIT:
  720.             Draw.Exit()
  721.         elif evt == BEVT_HELP:
  722.             show_help()
  723.         return
  724.  
  725.     elif SCREEN == CONFIG_SCREEN:
  726.         datatypes = CFGKEY.sorteddata
  727.         if evt >= BEVT_BROWSEFILE:
  728.             INDEX = evt - BEVT_BROWSEFILE
  729.             Window.FileSelector(fs_file_callback, 'Choose file')
  730.         elif evt >= BEVT_BROWSEDIR:
  731.             INDEX = evt - BEVT_BROWSEDIR
  732.             Window.FileSelector(fs_dir_callback, 'Choose any file')
  733.         elif evt >= BEVT_STR:
  734.             var = BUT_TYPES[str][evt - BEVT_STR].val
  735.             datatypes[str][evt - BEVT_STR][1] = var
  736.         elif evt >= BEVT_FLOAT:
  737.             var = BUT_TYPES[float][evt - BEVT_FLOAT].val
  738.             datatypes[float][evt - BEVT_FLOAT][1] = var
  739.         elif evt >= BEVT_INT:
  740.             var = BUT_TYPES[int][evt - BEVT_INT].val
  741.             datatypes[int][evt - BEVT_INT][1] = var
  742.         elif evt >= BEVT_BOOL:
  743.             var = datatypes[bool][evt - BEVT_BOOL][1]
  744.             if var == True: var = False
  745.             else: var = True
  746.             datatypes[bool][evt - BEVT_BOOL][1] = var
  747.  
  748.         elif evt == BEVT_BACK:
  749.             if SCREEN == CONFIG_SCREEN:
  750.                 SCREEN = START_SCREEN
  751.                 SCROLL_DOWN = 0
  752.                 Draw.Redraw()
  753.         elif evt == BEVT_EXIT:
  754.             if CFGKEY.needs_update():
  755.                 if Draw.PupMenu('UPDATE?%t|Data was changed') == 1:
  756.                     CFGKEY.update()
  757.             Draw.Exit()
  758.             return
  759.         elif evt == BEVT_APPLY:
  760.             if CFGKEY.needs_update():
  761.                 CFGKEY.update()
  762.         elif evt == BEVT_CANCEL:
  763.             if CFGKEY.needs_update():
  764.                 CFGKEY.revert()
  765.         elif evt == BEVT_DEL:
  766.             if CFGKEY.delete():
  767.                 reset()
  768.                 init_data()
  769.                 SCREEN = START_SCREEN
  770.                 SCROLL_DOWN = 0
  771.         elif evt == BEVT_DISK:
  772.             if DISK_UPDATE: DISK_UPDATE = False
  773.             else: DISK_UPDATE = True
  774.         elif evt == BEVT_HELP:
  775.             show_help(CFGKEY.scriptname)
  776.             return
  777.         else:
  778.             return
  779.     Draw.Redraw()
  780.  
  781. # End of definitions
  782.  
  783.  
  784. KEYS = get_keys()
  785.  
  786. if not KEYS:
  787.     Draw.PupMenu("NO DATA: please read this help screen")
  788.     Blender.ShowHelp('config.py')
  789. else:
  790.     fill_scripts_dict()
  791.     init_data()
  792.     Draw.Register(gui, event, button_event)
  793.