Integrated Freestyle to rendering pipeline
[blender.git] / release / scripts / config.py
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', 'blenderartists.org')
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$
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
110
111 MAX_STR_LEN = 300 # max length for a string
112 MAX_ITEMS_NUM = 100 # max number for each type of button
113
114 # ---
115 # The "General" configure options key is managed from this script.
116 verbose = True
117 confirm_overwrite = True
118
119 tooltips = {
120         'verbose': 'print script messages (info, warnings, errors) to the console',
121         'confirm_overwrite': 'scripts should always confirm before overwriting files'
122 }
123
124 CFG_LIST = ['verbose', 'confirm_overwrite', 'tooltips']
125 KEY_NAME = 'General'
126
127 def update_registry():
128         rd = {}
129         for var in CFG_LIST:
130                 exec("rd['%s']=%s" % (var, var))
131         Registry.SetKey(KEY_NAME, rd, True)
132
133 rd = Registry.GetKey('General', True)
134 if rd:
135         try:
136                 for var in CFG_LIST[:-1]: # no need to update tooltips
137                         exec("%s=rd['%s']" % (var, var))
138         except: update_registry()
139
140 else:
141         update_registry()
142 # ---
143
144 # script globals:
145 CFGKEY = ''
146 LABELS = []
147 GD = {} # groups dict (includes "Other" for unmapped keys)
148 INDEX = 0 # to pass button indices to fs callbacks
149 FREEKEY_IDX = 0 # index of set of keys not mapped to a script name
150 KEYMENUS = []
151 ALL_SCRIPTS = {}
152 ALL_GROUPS = []
153 START_SCREEN  = 0
154 CONFIG_SCREEN = 1
155 DISK_UPDATE = True # write changed data to its config file
156
157 ACCEPTED_TYPES = [bool, int, float, str, unicode]
158
159 SCREEN = START_SCREEN
160
161 SCROLL_DOWN = 0
162
163 # events:
164 BEVT_START = 50
165 BEVT_EXIT = 0 + BEVT_START
166 BEVT_BACK = 1 + BEVT_START
167 BEVT_DISK = 2 + BEVT_START
168 BEVT_CANCEL = 3 + BEVT_START
169 BEVT_APPLY = 4 + BEVT_START
170 BEVT_HELP = 5 + BEVT_START
171 BEVT_DEL = 6 + BEVT_START
172 BEVT_KEYMENU = []
173 BUT_KEYMENU = []
174 BEVT_BOOL = 100
175 BEVT_INT = BEVT_BOOL + MAX_ITEMS_NUM
176 BEVT_FLOAT = BEVT_BOOL + 2*MAX_ITEMS_NUM
177 BEVT_STR = BEVT_BOOL + 3*MAX_ITEMS_NUM
178 BEVT_BROWSEDIR = BEVT_BOOL + 4*MAX_ITEMS_NUM
179 BEVT_BROWSEFILE = BEVT_BOOL + 5*MAX_ITEMS_NUM
180 BUT_TYPES = {
181         bool: 0,
182         int: 0,
183         float: 0,
184         str: 0
185 }
186
187 # Function definitions:
188
189 def get_keys():
190         LoadConfigData() # loads all data from files in (u)scripts/bpydata/config/
191         return [k for k in Registry.Keys() if k[0] != "_"]
192
193
194 def show_help(script = 'config.py'):
195         Blender.ShowHelp(script)
196
197
198 def fs_dir_callback(pathname):
199         global CFGKEY, INDEX
200
201         pathname = bsys.dirname(pathname)
202         datatypes = CFGKEY.sorteddata
203         datatypes[str][INDEX][1] = pathname
204
205
206 def fs_file_callback(pathname):
207         global CFGKEY, INDEX
208
209         datatypes = CFGKEY.sorteddata
210         datatypes[str][INDEX][1] = pathname
211
212
213 # parse Bpymenus file to get all script filenames
214 # (used to show help for a given key)
215 def fill_scripts_dict():
216         global ALL_SCRIPTS, ALL_GROUPS
217
218         group = ''
219         group_len = 0
220         sep = bsys.sep
221         home = Blender.Get('homedir')
222         if not home:
223                 errmsg = """
224 Can't find Blender's home dir and so can't find the
225 Bpymenus file automatically stored inside it, which
226 is needed by this script.  Please run the
227 Help -> System -> System Information script to get
228 information about how to fix this.
229 """
230                 raise SystemError, errmsg
231         fname = bsys.join(home, 'Bpymenus')
232         if not bsys.exists(fname): return False
233         f = file(fname, 'r')
234         lines = f.readlines()
235         f.close()
236         for l in lines:
237                 if l.rfind('{') > 0:
238                         group = l.split()[0]
239                         ALL_GROUPS.append(group)
240                         group_len += 1
241                         continue
242                 elif l[0] != "'": continue
243                 fields = l.split("'")
244                 if len(fields) > 2:
245                         menuname = fields[1].replace('...','')
246                         fields = fields[2].split()
247                         if len(fields) > 1:
248                                 fname = fields[1].split(sep)[-1]
249                                 i = 1
250                                 while not fname.endswith('.py'):
251                                         i += 1
252                                         fname = "%s %s" % (fname, fields[i])
253                                 ALL_SCRIPTS[fname] = (menuname, group_len - 1)
254         return True
255
256
257 def map_to_registered_script(name):
258         global ALL_SCRIPTS
259
260         if not name.endswith('.py'):
261                 name = "%s.py" % name
262         if ALL_SCRIPTS.has_key(name):
263                 return ALL_SCRIPTS[name] # == (menuname, group index)
264         return None
265
266
267 def reset():
268         global LABELS, GD, KEYMENUS, KEYS
269
270         # init_data is recalled when a key is deleted, so:
271         LABELS = []
272         GD = {}
273         KEYMENUS = []
274         KEYS = get_keys()
275
276
277 # gather all script info, fill gui menus
278 def init_data():
279         global KEYS, GD, ALL_GROUPS, ALL_SCRIPTS, KEYMENUS, LABELS
280         global BUT_KEYMENU, BEVT_KEYMENU, FREEKEY_IDX
281
282         for k in ALL_GROUPS:
283                 GD[k] = []
284         GD[None] = []
285
286         for k in KEYS:
287                 res = map_to_registered_script(k)
288                 if res:
289                         GD[ALL_GROUPS[res[1]]].append((k, res[0]))
290                 else: GD[None].append((k, k))
291
292         for k in GD.keys():
293                 if not GD[k]: GD.pop(k)
294
295         if GD.has_key(None):
296                 GD['Other'] = GD[None]
297                 GD.pop(None)
298                 FREEKEY_IDX = -1
299
300         BUT_KEYMENU = range(len(GD))
301
302         for k in GD.keys():
303                 kmenu = ['Configuration Keys: %s%%t' % k]
304                 for j in GD[k]:
305                         kmenu.append(j[1])
306                 kmenu = "|".join(kmenu)
307                 KEYMENUS.append(kmenu)
308                 LABELS.append(k)
309
310         if FREEKEY_IDX < 0:
311                 FREEKEY_IDX = LABELS.index('Other')
312
313         length = len(KEYMENUS)
314         BEVT_KEYMENU = range(1, length + 1)
315         BUT_KEYMENU = range(length)
316
317
318 # for theme colors:
319 def float_colors(cols):
320         return map(lambda x: x / 255.0, cols)
321
322
323
324 class Config:
325
326         def __init__(self, key, has_group = True):
327                 global DISK_UPDATE
328
329                 self.key = key
330                 self.has_group = has_group
331                 self.name = key
332                 self.fromdisk = HasConfigData(key) & BPY_KEY_IN_FILE
333                 if not self.fromdisk: DISK_UPDATE = False
334                 else: DISK_UPDATE = True
335
336                 self.origdata = Registry.GetKey(key, True)
337                 data = self.data = self.origdata.copy()
338
339                 if not data:
340                         Draw.PupMenu('ERROR: couldn\'t find requested data')
341                         self.data = None
342                         return
343
344                 keys = data.keys()
345                 nd = {}
346                 for k in keys:
347                         nd[k.lower()] = k
348
349                 if nd.has_key('tooltips'):
350                         ndval = nd['tooltips']
351                         self.tips = data[ndval]
352                         data.pop(ndval)
353                 else: self.tips = 0
354
355                 if nd.has_key('limits'):
356                         ndval = nd['limits']
357                         self.limits = data[ndval]
358                         data.pop(ndval)
359                 else: self.limits = 0
360
361                 if self.has_group:
362                         scriptname = key
363                         if not scriptname.endswith('.py'):
364                                 scriptname = "%s.py" % scriptname
365                 elif nd.has_key('script'):
366                                 ndval = nd['script']
367                                 scriptname = data[ndval]
368                                 data.pop(ndval)
369                                 if not scriptname.endswith('.py'):
370                                         scriptname = "%s.py" % scriptname
371                 else: scriptname = None
372
373                 self.scriptname = scriptname
374
375                 self.sort()
376
377
378         def needs_update(self): # check if user changed data
379                 data = self.data
380                 new = self.sorteddata
381
382                 for vartype in new.keys():
383                         for i in new[vartype]:
384                                 if data[i[0]] != i[1]: return 1
385
386                 return 0 # no changes
387
388
389         def update(self): # update original key
390                 global DISK_UPDATE
391
392                 data = self.data
393                 odata = self.origdata
394                 new = self.sorteddata
395                 for vartype in new.keys():
396                         for i in new[vartype]:
397                                 if data[i[0]] != i[1]: data[i[0]] = i[1]
398                                 if odata[i[0]] != i[1]: odata[i[0]] = i[1]
399
400                 if DISK_UPDATE: Registry.SetKey(self.key, odata, True)
401
402         def delete(self):
403                 global DISK_UPDATE
404
405                 delmsg = 'OK?%t|Delete key from memory'
406                 if DISK_UPDATE:
407                         delmsg = "%s and from disk" % delmsg
408                 if Draw.PupMenu(delmsg) == 1:
409                         Registry.RemoveKey(self.key, DISK_UPDATE)
410                         return True
411
412                 return False
413
414
415         def revert(self): # revert to original key
416                 data = self.data
417                 new = self.sorteddata
418                 for vartype in new.keys():
419                         for i in new[vartype]:
420                                 if data[i[0]] != i[1]: i[1] = data[i[0]]
421
422
423         def sort(self): # create a new dict with types as keys
424                 global ACCEPTED_TYPES, BUT_TYPES
425
426                 data = self.data
427                 datatypes = {}
428                 keys = [k for k in data.keys() if k[0] != '_']
429                 for k in keys:
430                         val = data[k]
431                         tval = type(val)
432                         if tval not in ACCEPTED_TYPES: continue
433                         if not datatypes.has_key(tval):
434                                 datatypes[tval] = []
435                         datatypes[type(val)].append([k, val])
436                 if datatypes.has_key(unicode):
437                         if not datatypes.has_key(str): datatypes[str] = datatypes[unicode]
438                         else:
439                                 for i in datatypes[unicode]: datatypes[str].append(i)
440                         datatypes.pop(unicode)
441                 for k in datatypes.keys():
442                         dk = datatypes[k]
443                         dk.sort()
444                         dk.reverse()
445                         BUT_TYPES[k] = range(len(dk))
446                 self.sorteddata = datatypes
447
448
449 # GUI:
450
451 # gui callbacks:
452
453 def gui(): # drawing the screen
454
455         global SCREEN, START_SCREEN, CONFIG_SCREEN, KEYMENUS, LABELS
456         global BEVT_KEYMENU, BUT_KEYMENU, CFGKEY
457         global BUT_TYPES, SCROLL_DOWN, VARS_NUM
458
459         WIDTH, HEIGHT = Window.GetAreaSize()
460
461         theme = Theme.Get()[0]
462         tui = theme.get('ui')
463         ttxt = theme.get('text')
464
465         COL_BG = float_colors(ttxt.back)
466         COL_TXT = ttxt.text
467         COL_TXTHI = ttxt.text_hi
468
469         BGL.glClearColor(COL_BG[0],COL_BG[1],COL_BG[2],COL_BG[3])
470         BGL.glClear(BGL.GL_COLOR_BUFFER_BIT)
471         BGL.glColor3ub(COL_TXT[0],COL_TXT[1], COL_TXT[2])
472
473         if SCREEN == START_SCREEN:
474                 x = 10
475                 y = 10
476                 h = 20
477                 w = 90
478                 BGL.glRasterPos2i(x, y)
479                 Draw.Text('Select a configuration key to access it.  Press Q or ESC to leave.')
480                 km_len = len(KEYMENUS)
481                 km_columns = (WIDTH - x) / w
482                 if km_columns == 0: km_rows = km_len
483                 else:
484                         km_rows = km_len / km_columns
485                         if (km_len % km_columns): km_rows += 1
486                 if km_rows == 0: km_rows = 1
487                 ystart = y + 2*h*km_rows
488                 if ystart > (HEIGHT - 70): ystart = HEIGHT - 70
489                 y = ystart
490                 column = 1
491                 for i, km in enumerate(KEYMENUS):
492                         column += 1
493                         BGL.glRasterPos2i(x + 2, y + h + 5)
494                         Draw.Text(LABELS[i])
495                         BUT_KEYMENU[i] = Draw.Menu(km, BEVT_KEYMENU[i],
496                                 x, y, w - 10, h, 0, 'Choose a key to access its configuration data')
497                         if column > km_columns:
498                                 column = 1
499                                 y -= 2*h
500                                 if y < 35: break
501                                 x = 10
502                         else: x += w
503                 x = 10
504                 y = 50 + ystart
505                 BGL.glColor3ub(COL_TXTHI[0], COL_TXTHI[1], COL_TXTHI[2])
506                 BGL.glRasterPos2i(x, y)
507                 Draw.Text('Scripts Configuration Editor')
508                 Draw.PushButton('help', BEVT_HELP, x, 22, 45, 16,
509                         'View help information about this script (hotkey: H)')
510
511         elif SCREEN == CONFIG_SCREEN:
512                 x = y = 10
513                 h = 18
514                 data = CFGKEY.sorteddata
515                 tips = CFGKEY.tips
516                 fromdisk = CFGKEY.fromdisk
517                 limits = CFGKEY.limits
518                 VARS_NUM = 0
519                 for k in data.keys():
520                         VARS_NUM += len(data[k])
521                 lines = VARS_NUM + 5 # to account for header and footer
522                 y = lines*h
523                 if y > HEIGHT - 20: y = HEIGHT - 20
524                 BGL.glColor3ub(COL_TXTHI[0],COL_TXTHI[1], COL_TXTHI[2])
525                 BGL.glRasterPos2i(x, y)
526                 Draw.Text('Scripts Configuration Editor')
527                 y -= 20
528                 BGL.glColor3ub(COL_TXT[0],COL_TXT[1], COL_TXT[2])
529                 txtsize = 10
530                 if HEIGHT < lines*h:
531                         BGL.glRasterPos2i(10, 5)
532                         txtsize += Draw.Text('Arrow keys or mouse wheel to scroll, ')
533                 BGL.glRasterPos2i(txtsize, 5)
534                 Draw.Text('Q or ESC to return.')
535                 BGL.glRasterPos2i(x, y)
536                 Draw.Text('Key: "%s"' % CFGKEY.name)
537                 bh = 16
538                 bw = 45
539                 by = 16
540                 i = -1
541                 if CFGKEY.scriptname:
542                         i = 0
543                         Draw.PushButton('help', BEVT_HELP, x, by, bw, bh,
544                                 'Show documentation for the script that owns this key (hotkey: H)')
545                 Draw.PushButton('back', BEVT_BACK, x + (1+i)*bw, by, bw, bh,
546                         'Back to config keys selection screen (hotkey: ESC)')
547                 Draw.PushButton('exit', BEVT_EXIT, x + (2+i)*bw, by, bw, bh,
548                         'Exit from Scripts Config Editor (hotkey: Q)')
549                 Draw.PushButton('revert', BEVT_CANCEL, x + (3+i)*bw, by, bw, bh,
550                         'Revert data to original values (hotkey: U)')
551                 Draw.PushButton('apply', BEVT_APPLY, x + (4+i)*bw, by, bw, bh,
552                         'Apply changes, if any (hotkey: ENTER)')
553                 delmsg = 'Delete this data key from memory'
554                 if fromdisk: delmsg = "%s and from disk" % delmsg
555                 Draw.PushButton('delete', BEVT_DEL, x + (5+i)*bw, by, bw, bh,
556                         '%s (hotkey: DELETE)' % delmsg)
557                 if fromdisk:
558                         Draw.Toggle("file", BEVT_DISK, x + 3 + (6+i)*bw, by, bw, bh, DISK_UPDATE,
559                                 'Update also the file where this config key is stored')
560                 i = -1
561                 top = -1
562                 y -= 20
563                 yend = 30
564                 if data.has_key(bool) and y > 0:
565                         lst = data[bool]
566                         for l in lst:
567                                 top += 1
568                                 i += 1
569                                 if top < SCROLL_DOWN: continue
570                                 y -= h
571                                 if y < yend: break
572                                 w = 20
573                                 tog = data[bool][i][1]
574                                 if tips and tips.has_key(l[0]): tooltip = tips[l[0]]
575                                 else: tooltip = "click to toggle"
576                                 BUT_TYPES[bool][i] = Draw.Toggle("", BEVT_BOOL + i,
577                                         x, y, w, h, tog, tooltip)
578                                 BGL.glRasterPos2i(x + w + 3, y + 5)
579                                 Draw.Text(l[0].lower().replace('_', ' '))
580                         i = -1
581                         y -= 5
582                 if data.has_key(int) and y > 0:
583                         lst = data[int]
584                         for l in lst:
585                                 w = 70
586                                 top += 1
587                                 i += 1
588                                 if top < SCROLL_DOWN: continue
589                                 y -= h
590                                 if y < yend: break
591                                 val = data[int][i][1]
592                                 if limits: min, max = limits[l[0]]
593                                 else: min, max = 0, 10
594                                 if tips and tips.has_key(l[0]): tooltip = tips[l[0]]
595                                 else: tooltip = "click / drag to change"
596                                 BUT_TYPES[int][i] = Draw.Number("", BEVT_INT + i,
597                                         x, y, w, h, val, min, max, tooltip)
598                                 BGL.glRasterPos2i(x + w + 3, y + 3)
599                                 Draw.Text(l[0].lower().replace('_', ' '))
600                         i = -1
601                         y -= 5
602                 if data.has_key(float) and y > 0:
603                         lst = data[float]
604                         for l in lst:
605                                 w = 70
606                                 top += 1
607                                 i += 1
608                                 if top < SCROLL_DOWN: continue
609                                 y -= h
610                                 if y < yend: break
611                                 val = data[float][i][1]
612                                 if limits: min, max = limits[l[0]]
613                                 else: min, max = 0.0, 1.0
614                                 if tips and tips.has_key(l[0]): tooltip = tips[l[0]]
615                                 else: tooltip = "click and drag to change"
616                                 BUT_TYPES[float][i] = Draw.Number("", BEVT_FLOAT + i,
617                                         x, y, w, h, val, min, max, tooltip)
618                                 BGL.glRasterPos2i(x + w + 3, y + 3)
619                                 Draw.Text(l[0].lower().replace('_', ' '))
620                         i = -1
621                         y -= 5
622                 if data.has_key(str) and y > 0:
623                         lst = data[str]
624                         for l in lst:
625                                 top += 1
626                                 i += 1
627                                 if top < SCROLL_DOWN: continue
628                                 y -= h
629                                 if y < yend: break
630                                 name = l[0].lower()
631                                 is_dir = is_file = False
632                                 if name.find('_dir', -4) > 0:   is_dir = True
633                                 elif name.find('_file', -5) > 0: is_file = True
634                                 w = WIDTH - 20
635                                 wbrowse = 50
636                                 if is_dir and w > wbrowse: w -= wbrowse
637                                 if tips and tips.has_key(l[0]): tooltip = tips[l[0]]
638                                 else: tooltip = "click to write a new string"
639                                 name = name.replace('_',' ') + ': '
640                                 if len(l[1]) > MAX_STR_LEN:
641                                         l[1] = l[1][:MAX_STR_LEN]
642                                 BUT_TYPES[str][i] = Draw.String(name, BEVT_STR + i,
643                                         x, y, w, h, l[1], MAX_STR_LEN, tooltip)
644                                 if is_dir:
645                                         Draw.PushButton('browse', BEVT_BROWSEDIR + i, x+w+1, y, wbrowse, h,
646                                                 'click to open a file selector (pick any file in the desired dir)')
647                                 elif is_file:
648                                         Draw.PushButton('browse', BEVT_BROWSEFILE + i, x + w + 1, y, 50, h,
649                                                 'click to open a file selector')
650
651
652 def fit_scroll():
653         global SCROLL_DOWN, VARS_NUM
654         max = VARS_NUM - 1 # so last item is always visible
655         if SCROLL_DOWN > max:
656                 SCROLL_DOWN = max
657         elif SCROLL_DOWN < 0:
658                 SCROLL_DOWN = 0
659
660
661 def event(evt, val): # input events
662
663         global SCREEN, START_SCREEN, CONFIG_SCREEN
664         global SCROLL_DOWN, CFGKEY
665
666         if not val: return
667
668         if evt == Draw.ESCKEY:
669                 if SCREEN == START_SCREEN: Draw.Exit()
670                 else:
671                         if CFGKEY.needs_update():
672                                 if Draw.PupMenu('UPDATE?%t|Data was changed') == 1:
673                                         CFGKEY.update()
674                         SCREEN = START_SCREEN
675                         SCROLL_DOWN = 0
676                         Draw.Redraw()
677                 return
678         elif evt == Draw.QKEY:
679                 if SCREEN == CONFIG_SCREEN and CFGKEY.needs_update():
680                         if Draw.PupMenu('UPDATE?%t|Data was changed') == 1:
681                                 CFGKEY.update()
682                 Draw.Exit()
683                 return
684         elif evt == Draw.HKEY:
685                 if SCREEN == START_SCREEN: show_help()
686                 elif CFGKEY.scriptname: show_help(CFGKEY.scriptname)
687                 return
688
689         elif SCREEN == CONFIG_SCREEN:
690                 if evt in [Draw.DOWNARROWKEY, Draw.WHEELDOWNMOUSE]:
691                         SCROLL_DOWN += 1
692                         fit_scroll()
693                 elif evt in [Draw.UPARROWKEY, Draw.WHEELUPMOUSE]:
694                         SCROLL_DOWN -= 1
695                         fit_scroll()
696                 elif evt == Draw.UKEY:
697                         if CFGKEY.needs_update():
698                                 CFGKEY.revert()
699                 elif evt == Draw.RETKEY or evt == Draw.PADENTER:
700                         if CFGKEY.needs_update():
701                                 CFGKEY.update()
702                 elif evt == Draw.DELKEY:
703                         if CFGKEY.delete():
704                                 reset()
705                                 init_data()
706                                 SCREEN = START_SCREEN
707                                 SCROLL_DOWN = 0
708                 else: return
709                 Draw.Redraw()
710
711
712 def button_event(evt): # gui button events
713
714         global SCREEN, START_SCREEN, CONFIG_SCREEN, CFGKEY, DISK_UPDATE
715         global BEVT_KEYMENU, BUT_KEYMENU, BUT_TYPES, SCROLL_DOWN, GD, INDEX
716         global BEVT_EXIT, BEVT_BACK, BEVT_APPLY, BEVT_CANCEL, BEVT_HELP, FREEKEY_IDX
717
718         if SCREEN == START_SCREEN:
719                 for e in BEVT_KEYMENU:
720                         if evt == e:
721                                 index = e - 1
722                                 k = BUT_KEYMENU[index].val - 1
723                                 CFGKEY = Config(GD[LABELS[index]][k][0], index != FREEKEY_IDX)
724                                 if CFGKEY.data:
725                                         SCREEN = CONFIG_SCREEN
726                                         Draw.Redraw()
727                                         return
728                 if evt == BEVT_EXIT:
729                         Draw.Exit()
730                 elif evt == BEVT_HELP:
731                         show_help()
732                 return
733
734         elif SCREEN == CONFIG_SCREEN:
735                 datatypes = CFGKEY.sorteddata
736                 if evt >= BEVT_BROWSEFILE:
737                         INDEX = evt - BEVT_BROWSEFILE
738                         Window.FileSelector(fs_file_callback, 'Choose file')
739                 elif evt >= BEVT_BROWSEDIR:
740                         INDEX = evt - BEVT_BROWSEDIR
741                         Window.FileSelector(fs_dir_callback, 'Choose any file')
742                 elif evt >= BEVT_STR:
743                         var = BUT_TYPES[str][evt - BEVT_STR].val
744                         datatypes[str][evt - BEVT_STR][1] = var
745                 elif evt >= BEVT_FLOAT:
746                         var = BUT_TYPES[float][evt - BEVT_FLOAT].val
747                         datatypes[float][evt - BEVT_FLOAT][1] = var
748                 elif evt >= BEVT_INT:
749                         var = BUT_TYPES[int][evt - BEVT_INT].val
750                         datatypes[int][evt - BEVT_INT][1] = var
751                 elif evt >= BEVT_BOOL:
752                         var = datatypes[bool][evt - BEVT_BOOL][1]
753                         if var == True: var = False
754                         else: var = True
755                         datatypes[bool][evt - BEVT_BOOL][1] = var
756
757                 elif evt == BEVT_BACK:
758                         if SCREEN == CONFIG_SCREEN:
759                                 SCREEN = START_SCREEN
760                                 SCROLL_DOWN = 0
761                                 Draw.Redraw()
762                 elif evt == BEVT_EXIT:
763                         if CFGKEY.needs_update():
764                                 if Draw.PupMenu('UPDATE?%t|Data was changed') == 1:
765                                         CFGKEY.update()
766                         Draw.Exit()
767                         return
768                 elif evt == BEVT_APPLY:
769                         if CFGKEY.needs_update():
770                                 CFGKEY.update()
771                 elif evt == BEVT_CANCEL:
772                         if CFGKEY.needs_update():
773                                 CFGKEY.revert()
774                 elif evt == BEVT_DEL:
775                         if CFGKEY.delete():
776                                 reset()
777                                 init_data()
778                                 SCREEN = START_SCREEN
779                                 SCROLL_DOWN = 0
780                 elif evt == BEVT_DISK:
781                         if DISK_UPDATE: DISK_UPDATE = False
782                         else: DISK_UPDATE = True
783                 elif evt == BEVT_HELP:
784                         show_help(CFGKEY.scriptname)
785                         return
786                 else:
787                         return
788         Draw.Redraw()
789
790 # End of definitions
791
792
793 KEYS = get_keys()
794
795 if not KEYS:
796         Draw.PupMenu("NO DATA: please read this help screen")
797         Blender.ShowHelp('config.py')
798 else:
799         fill_scripts_dict()
800         init_data()
801         Draw.Register(gui, event, button_event)