Add missing properties to keymap export operator.
[blender.git] / release / scripts / ui / space_userpref.py
1 # ##### BEGIN GPL LICENSE BLOCK #####
2 #
3 #  This program is free software; you can redistribute it and/or
4 #  modify it under the terms of the GNU General Public License
5 #  as published by the Free Software Foundation; either version 2
6 #  of the License, or (at your option) any later version.
7 #
8 #  This program is distributed in the hope that it will be useful,
9 #  but WITHOUT ANY WARRANTY; without even the implied warranty of
10 #  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11 #  GNU General Public License for more details.
12 #
13 #  You should have received a copy of the GNU General Public License
14 #  along with this program; if not, write to the Free Software Foundation,
15 #  Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
16 #
17 # ##### END GPL LICENSE BLOCK #####
18
19 # <pep8 compliant>
20 import bpy
21 import os.path
22
23 # General UI Theme Settings (User Interface)
24 def ui_items_general(col, context):
25     row = col.row()
26     sub = row.column()
27     sub.prop(context, "outline")
28     sub.prop(context, "item", slider=True)
29     sub = row.column()
30     sub.prop(context, "inner", slider=True)
31     sub.prop(context, "inner_sel", slider=True)
32     sub = row.column()
33     sub.prop(context, "text")
34     sub.prop(context, "text_sel")
35     sub = row.column()
36     sub.prop(context, "shaded")
37     subsub = sub.column(align=True)
38     subsub.active = context.shaded
39     subsub.prop(context, "shadetop")
40     subsub.prop(context, "shadedown")
41     
42     col.separator()
43     
44 def opengl_lamp_buttons(column, lamp):
45     split = column.split(percentage=0.1)
46
47     if lamp.enabled == True:
48         split.prop(lamp, "enabled", text="", icon='OUTLINER_OB_LAMP')
49     else:
50         split.prop(lamp, "enabled", text="", icon='LAMP_DATA')
51
52     col = split.column()
53     col.active = lamp.enabled
54     row = col.row()
55     row.label(text="Diffuse:")
56     row.prop(lamp, "diffuse_color", text="")
57     row = col.row()
58     row.label(text="Specular:")
59     row.prop(lamp, "specular_color", text="")
60
61     col = split.column()
62     col.active = lamp.enabled
63     col.prop(lamp, "direction", text="")
64
65 KM_HIERARCHY = [
66                     ('Window', 'EMPTY', 'WINDOW', []), # file save, window change, exit
67                     ('Screen', 'EMPTY', 'WINDOW', [    # full screen, undo, screenshot
68                         ('Screen Editing', 'EMPTY', 'WINDOW', []),    # resizing, action corners
69                         ]),
70
71                     ('View2D', 'EMPTY', 'WINDOW', []),    # view 2d navigation (per region)
72                     ('View2D Buttons List', 'EMPTY', 'WINDOW', []), # view 2d with buttons navigation
73                     ('Header', 'EMPTY', 'WINDOW', []),    # header stuff (per region)
74                     ('Grease Pencil', 'EMPTY', 'WINDOW', []), # grease pencil stuff (per region)
75
76                     ('3D View', 'VIEW_3D', 'WINDOW', [ # view 3d navigation and generic stuff (select, transform)
77                         ('Object Mode', 'EMPTY', 'WINDOW', []),
78                         ('Mesh', 'EMPTY', 'WINDOW', []),
79                         ('Curve', 'EMPTY', 'WINDOW', []),
80                         ('Armature', 'EMPTY', 'WINDOW', []),
81                         ('Metaball', 'EMPTY', 'WINDOW', []),
82                         ('Lattice', 'EMPTY', 'WINDOW', []),
83                         ('Font', 'EMPTY', 'WINDOW', []),
84
85                         ('Pose', 'EMPTY', 'WINDOW', []),
86
87                         ('Vertex Paint', 'EMPTY', 'WINDOW', []),
88                         ('Weight Paint', 'EMPTY', 'WINDOW', []),
89                         ('Face Mask', 'EMPTY', 'WINDOW', []),
90                         ('Image Paint', 'EMPTY', 'WINDOW', []), # image and view3d
91                         ('Sculpt', 'EMPTY', 'WINDOW', []),
92
93                         ('Armature Sketch', 'EMPTY', 'WINDOW', []),
94                         ('Particle', 'EMPTY', 'WINDOW', []),
95
96                         ('Object Non-modal', 'EMPTY', 'WINDOW', []), # mode change
97
98                         ('3D View Generic', 'VIEW_3D', 'WINDOW', [])    # toolbar and properties
99                         ]),
100
101                     ('Frames', 'EMPTY', 'WINDOW', []),    # frame navigation (per region)
102                     ('Markers', 'EMPTY', 'WINDOW', []),    # markers (per region)
103                     ('Animation', 'EMPTY', 'WINDOW', []),    # frame change on click, preview range (per region)
104                     ('Animation Channels', 'EMPTY', 'WINDOW', []),
105                     ('Graph Editor', 'GRAPH_EDITOR', 'WINDOW', [
106                         ('Graph Editor Generic', 'GRAPH_EDITOR', 'WINDOW', [])
107                         ]),
108                     ('Dopesheet', 'DOPESHEET_EDITOR', 'WINDOW', []),
109                     ('NLA Editor', 'NLA_EDITOR', 'WINDOW', [
110                         ('NLA Channels', 'NLA_EDITOR', 'WINDOW', []),
111                         ('NLA Generic', 'NLA_EDITOR', 'WINDOW', [])
112                         ]),
113
114                     ('Image', 'IMAGE_EDITOR', 'WINDOW', [
115                         ('UV Editor', 'EMPTY', 'WINDOW', []), # image (reverse order, UVEdit before Image
116                         ('Image Paint', 'EMPTY', 'WINDOW', []), # image and view3d
117                         ('Image Generic', 'IMAGE_EDITOR', 'WINDOW', [])
118                         ]),
119
120                     ('Timeline', 'TIMELINE', 'WINDOW', []),
121                     ('Outliner', 'OUTLINER', 'WINDOW', []),
122
123                     ('Node Editor', 'NODE_EDITOR', 'WINDOW', [
124                         ('Node Generic', 'NODE_EDITOR', 'WINDOW', [])
125                         ]),
126                     ('Sequencer', 'SEQUENCE_EDITOR', 'WINDOW', []),
127                     ('Logic Editor', 'LOGIC_EDITOR', 'WINDOW', []),
128
129                     ('File Browser', 'FILE_BROWSER', 'WINDOW', [
130                         ('File Browser Main', 'FILE_BROWSER', 'WINDOW', []),
131                         ('File Browser Buttons', 'FILE_BROWSER', 'WINDOW', [])
132                         ]),
133
134                     ('Property Editor', 'PROPERTIES', 'WINDOW', []), # align context menu
135
136                     ('Script', 'SCRIPTS_WINDOW', 'WINDOW', []),
137                     ('Text', 'TEXT_EDITOR', 'WINDOW', []),
138                     ('Console', 'CONSOLE', 'WINDOW', []),
139
140                     ('View3D Gesture Circle', 'EMPTY', 'WINDOW', []),
141                     ('Gesture Border', 'EMPTY', 'WINDOW', []),
142                     ('Standard Modal Map', 'EMPTY', 'WINDOW', []),
143                     ('Transform Modal Map', 'EMPTY', 'WINDOW', []),
144                     ('View3D Fly Modal', 'EMPTY', 'WINDOW', []),
145                     ('View3D Rotate Modal', 'EMPTY', 'WINDOW', []),
146                     ('View3D Move Modal', 'EMPTY', 'WINDOW', []),
147                     ('View3D Zoom Modal', 'EMPTY', 'WINDOW', []),
148                 ]
149
150
151 class USERPREF_HT_header(bpy.types.Header):
152     bl_space_type = 'USER_PREFERENCES'
153
154     def draw(self, context):
155         layout = self.layout
156         layout.template_header(menus=False)
157
158         userpref = context.user_preferences
159
160         layout.operator_context = 'EXEC_AREA'
161         layout.operator("wm.save_homefile", text="Save As Default")
162
163         if userpref.active_section == 'INPUT':
164             layout.operator_context = 'INVOKE_DEFAULT'
165             op = layout.operator("wm.keyconfig_export", "Export Key Configuration...")
166             op.path = "keymap.py"
167
168
169 class USERPREF_PT_tabs(bpy.types.Panel):
170     bl_label = ""
171     bl_space_type = 'USER_PREFERENCES'
172     bl_region_type = 'WINDOW'
173     bl_show_header = False
174
175     def draw(self, context):
176         layout = self.layout
177
178         userpref = context.user_preferences
179
180         layout.prop(userpref, "active_section", expand=True)
181
182
183 class USERPREF_PT_interface(bpy.types.Panel):
184     bl_space_type = 'USER_PREFERENCES'
185     bl_label = "Interface"
186     bl_region_type = 'WINDOW'
187     bl_show_header = False
188
189     def poll(self, context):
190         userpref = context.user_preferences
191         return (userpref.active_section == 'INTERFACE')
192
193     def draw(self, context):
194         layout = self.layout
195
196         userpref = context.user_preferences
197         view = userpref.view
198
199         row = layout.row()
200
201         col = row.column()
202         col.label(text="Display:")
203         col.prop(view, "tooltips")
204         col.prop(view, "display_object_info", text="Object Info")
205         col.prop(view, "use_large_cursors")
206         col.prop(view, "show_view_name", text="View Name")
207         col.prop(view, "show_playback_fps", text="Playback FPS")
208         col.prop(view, "global_scene")
209         col.prop(view, "pin_floating_panels")
210         col.prop(view, "object_origin_size")
211
212         col.separator()
213         col.separator()
214         col.separator()
215
216         col.prop(view, "show_mini_axis", text="Display Mini Axis")
217         sub = col.column()
218         sub.enabled = view.show_mini_axis
219         sub.prop(view, "mini_axis_size", text="Size")
220         sub.prop(view, "mini_axis_brightness", text="Brightness")
221
222         row.separator()
223         row.separator()
224
225         col = row.column()
226         col.label(text="View Manipulation:")
227         col.prop(view, "auto_depth")
228         col.prop(view, "zoom_to_mouse")
229         col.prop(view, "rotate_around_selection")
230         col.prop(view, "global_pivot")
231
232         col.separator()
233
234         col.prop(view, "auto_perspective")
235         col.prop(view, "smooth_view")
236         col.prop(view, "rotation_angle")
237
238         row.separator()
239         row.separator()
240
241         col = row.column()
242         #Toolbox doesn't exist yet
243         #col.label(text="Toolbox:")
244         #col.prop(view, "use_column_layout")
245         #col.label(text="Open Toolbox Delay:")
246         #col.prop(view, "open_left_mouse_delay", text="Hold LMB")
247         #col.prop(view, "open_right_mouse_delay", text="Hold RMB")
248         col.prop(view, "use_manipulator")
249         sub = col.column()
250         sub.enabled = view.use_manipulator
251         sub.prop(view, "manipulator_size", text="Size")
252         sub.prop(view, "manipulator_handle_size", text="Handle Size")
253         sub.prop(view, "manipulator_hotspot", text="Hotspot")
254
255         col.separator()
256         col.separator()
257         col.separator()
258
259         col.label(text="Menus:")
260         col.prop(view, "open_mouse_over")
261         col.label(text="Menu Open Delay:")
262         col.prop(view, "open_toplevel_delay", text="Top Level")
263         col.prop(view, "open_sublevel_delay", text="Sub Level")
264
265
266 class USERPREF_PT_edit(bpy.types.Panel):
267     bl_space_type = 'USER_PREFERENCES'
268     bl_label = "Edit"
269     bl_region_type = 'WINDOW'
270     bl_show_header = False
271
272     def poll(self, context):
273         userpref = context.user_preferences
274         return (userpref.active_section == 'EDITING')
275
276     def draw(self, context):
277         layout = self.layout
278
279         userpref = context.user_preferences
280         edit = userpref.edit
281
282         row = layout.row()
283
284         col = row.column()
285         col.label(text="Link Materials To:")
286         col.prop(edit, "material_link", text="")
287
288         col.separator()
289         col.separator()
290         col.separator()
291
292         col.label(text="New Objects:")
293         col.prop(edit, "enter_edit_mode")
294         col.label(text="Align To:")
295         col.prop(edit, "object_align", text="")
296
297         col.separator()
298         col.separator()
299         col.separator()
300
301         col.label(text="Undo:")
302         col.prop(edit, "global_undo")
303         col.prop(edit, "undo_steps", text="Steps")
304         col.prop(edit, "undo_memory_limit", text="Memory Limit")
305
306         row.separator()
307         row.separator()
308
309         col = row.column()
310         col.label(text="Snap:")
311         col.prop(edit, "snap_translate", text="Translate")
312         col.prop(edit, "snap_rotate", text="Rotate")
313         col.prop(edit, "snap_scale", text="Scale")
314         col.separator()
315         col.separator()
316         col.separator()
317         col.label(text="Grease Pencil:")
318         col.prop(edit, "grease_pencil_manhattan_distance", text="Manhattan Distance")
319         col.prop(edit, "grease_pencil_euclidean_distance", text="Euclidean Distance")
320         #col.prop(edit, "grease_pencil_simplify_stroke", text="Simplify Stroke")
321         col.prop(edit, "grease_pencil_eraser_radius", text="Eraser Radius")
322         col.prop(edit, "grease_pencil_smooth_stroke", text="Smooth Stroke")
323
324         row.separator()
325         row.separator()
326
327         col = row.column()
328         col.label(text="Keyframing:")
329         col.prop(edit, "use_visual_keying")
330         col.prop(edit, "keyframe_insert_needed", text="Only Insert Needed")
331
332         col.separator()
333
334         col.label(text="New F-Curve Defaults:")
335         col.prop(edit, "new_interpolation_type", text="Interpolation")
336         col.prop(edit, "insertkey_xyz_to_rgb", text="XYZ to RGB")
337
338         col.separator()
339
340         col.prop(edit, "auto_keying_enable", text="Auto Keyframing:")
341
342         sub = col.column()
343
344         sub.active = edit.auto_keying_enable
345         sub.prop(edit, "auto_keyframe_insert_keyingset", text="Only Insert for Keying Set")
346         sub.prop(edit, "auto_keyframe_insert_available", text="Only Insert Available")
347
348         col.separator()
349         col.separator()
350         col.separator()
351
352         col.label(text="Transform:")
353         col.prop(edit, "drag_immediately")
354
355         row.separator()
356         row.separator()
357
358         col = row.column()
359         col.label(text="Duplicate Data:")
360         col.prop(edit, "duplicate_mesh", text="Mesh")
361         col.prop(edit, "duplicate_surface", text="Surface")
362         col.prop(edit, "duplicate_curve", text="Curve")
363         col.prop(edit, "duplicate_text", text="Text")
364         col.prop(edit, "duplicate_metaball", text="Metaball")
365         col.prop(edit, "duplicate_armature", text="Armature")
366         col.prop(edit, "duplicate_lamp", text="Lamp")
367         col.prop(edit, "duplicate_material", text="Material")
368         col.prop(edit, "duplicate_texture", text="Texture")
369         col.prop(edit, "duplicate_fcurve", text="F-Curve")
370         col.prop(edit, "duplicate_action", text="Action")
371         col.prop(edit, "duplicate_particle", text="Particle")
372
373
374 class USERPREF_PT_system(bpy.types.Panel):
375     bl_space_type = 'USER_PREFERENCES'
376     bl_label = "System"
377     bl_region_type = 'WINDOW'
378     bl_show_header = False
379
380     def poll(self, context):
381         userpref = context.user_preferences
382         return (userpref.active_section == 'SYSTEM')
383
384     def draw(self, context):
385         layout = self.layout
386
387         userpref = context.user_preferences
388         system = userpref.system
389
390         split = layout.split()
391
392
393         # 1. Column
394         column = split.column()
395         colsplit = column.split(percentage=0.85)
396
397         col = colsplit.column()
398         col.label(text="General:")
399         col.prop(system, "dpi")
400         col.prop(system, "frame_server_port")
401         col.prop(system, "scrollback", text="Console Scrollback")
402         col.prop(system, "auto_run_python_scripts")
403
404         col.separator()
405         col.separator()
406         col.separator()
407
408         col.label(text="Sound:")
409         col.row().prop(system, "audio_device", expand=True)
410         sub = col.column()
411         sub.active = system.audio_device != 'NONE'
412         #sub.prop(system, "enable_all_codecs")
413         sub.prop(system, "audio_channels", text="Channels")
414         sub.prop(system, "audio_mixing_buffer", text="Mixing Buffer")
415         sub.prop(system, "audio_sample_rate", text="Sample Rate")
416         sub.prop(system, "audio_sample_format", text="Sample Format")
417
418         col.separator()
419         col.separator()
420         col.separator()
421         
422         col.label(text="Screencast:")
423         col.prop(system, "screencast_fps")
424         col.prop(system, "screencast_wait_time")     
425         col.separator()
426         col.separator()
427         col.separator()
428
429         #column = split.column()
430         #colsplit = column.split(percentage=0.85)
431
432         # No translation in 2.5 yet
433         #col.prop(system, "language")
434         #col.label(text="Translate:")
435         #col.prop(system, "translate_tooltips", text="Tooltips")
436         #col.prop(system, "translate_buttons", text="Labels")
437         #col.prop(system, "translate_toolbox", text="Toolbox")
438
439         #col.separator()
440
441         #col.prop(system, "use_textured_fonts")
442         
443
444         # 2. Column
445         column = split.column()
446         colsplit = column.split(percentage=0.85)
447
448         col = colsplit.column()
449         col.label(text="OpenGL:")
450         col.prop(system, "clip_alpha", slider=True)
451         col.prop(system, "use_mipmaps")
452         col.prop(system, "use_vbos")
453         #Anti-aliasing is disabled as it breaks broder/lasso select
454         #col.prop(system, "use_antialiasing")
455         col.label(text="Window Draw Method:")
456         col.row().prop(system, "window_draw_method", expand=True)
457         col.label(text="Textures:")
458         col.prop(system, "gl_texture_limit", text="Limit Size")
459         col.prop(system, "texture_time_out", text="Time Out")
460         col.prop(system, "texture_collection_rate", text="Collection Rate")
461
462         col.separator()
463         col.separator()
464         col.separator()
465
466         col.label(text="Sequencer:")
467         col.prop(system, "prefetch_frames")
468         col.prop(system, "memory_cache_limit")
469         
470
471         # 3. Column
472         column = split.column()
473
474         column.label(text="Solid OpenGL lights:")
475
476         split = column.split(percentage=0.1)
477         split.label()
478         split.label(text="Colors:")
479         split.label(text="Direction:")
480         
481         lamp = system.solid_lights[0]
482         opengl_lamp_buttons(column, lamp)
483         
484         lamp = system.solid_lights[1]
485         opengl_lamp_buttons(column, lamp)
486         
487         lamp = system.solid_lights[2]
488         opengl_lamp_buttons(column, lamp)
489
490         column.separator()
491         column.separator()
492         column.separator()
493         
494         column.label(text="Color Picker Type:")
495         column.row().prop(system, "color_picker_type", text="")
496         
497         column.separator()
498         column.separator()
499         column.separator()
500         
501         column.prop(system, "use_weight_color_range", text="Custom Weight Paint Range")
502         sub = column.column()
503         sub.active = system.use_weight_color_range
504         sub.template_color_ramp(system, "weight_color_range", expand=True)
505
506
507 class USERPREF_PT_theme(bpy.types.Panel):
508     bl_space_type = 'USER_PREFERENCES'
509     bl_label = "Themes"
510     bl_region_type = 'WINDOW'
511     bl_show_header = False
512
513     def poll(self, context):
514         userpref = context.user_preferences
515         return (userpref.active_section == 'THEMES')
516
517     def draw(self, context):
518         layout = self.layout
519
520         theme = context.user_preferences.themes[0]
521
522         split_themes = layout.split(percentage=0.2)
523         split_themes.prop(theme, "theme_area", expand=True)
524
525         split = split_themes.split()
526         
527         if theme.theme_area == 'USER_INTERFACE':
528             col = split.column()
529
530             ui = theme.user_interface.wcol_regular
531             col.label(text="Regular:")
532             ui_items_general(col, ui)
533
534             ui = theme.user_interface.wcol_tool
535             col.label(text="Tool:")
536             ui_items_general(col, ui)
537
538             ui = theme.user_interface.wcol_radio
539             col.label(text="Radio Buttons:")
540             ui_items_general(col, ui)
541
542             ui = theme.user_interface.wcol_text
543             col.label(text="Text:")
544             ui_items_general(col, ui)
545
546             ui = theme.user_interface.wcol_option
547             col.label(text="Option:")
548             ui_items_general(col, ui)
549
550             ui = theme.user_interface.wcol_toggle
551             col.label(text="Toggle:")
552             ui_items_general(col, ui)
553
554             ui = theme.user_interface.wcol_num
555             col.label(text="Number Field:")
556             ui_items_general(col, ui)
557
558             ui = theme.user_interface.wcol_numslider
559             col.label(text="Value Slider:")
560             ui_items_general(col, ui)
561
562             ui = theme.user_interface.wcol_box
563             col.label(text="Box:")
564             ui_items_general(col, ui)
565
566             ui = theme.user_interface.wcol_menu
567             col.label(text="Menu:")
568             ui_items_general(col, ui)
569
570             ui = theme.user_interface.wcol_pulldown
571             col.label(text="Pulldown:")
572             ui_items_general(col, ui)
573
574             ui = theme.user_interface.wcol_menu_back
575             col.label(text="Menu Back:")
576             ui_items_general(col, ui)
577
578             ui = theme.user_interface.wcol_menu_item
579             col.label(text="Menu Item:")
580             ui_items_general(col, ui)
581
582             ui = theme.user_interface.wcol_scroll
583             col.label(text="Scroll Bar:")
584             ui_items_general(col, ui)
585
586             ui = theme.user_interface.wcol_list_item
587             col.label(text="List Item:")
588             ui_items_general(col, ui)
589
590             ui = theme.user_interface.wcol_state
591             col.label(text="State:")
592
593             row = col.row()
594             sub = row.column()
595             sub.prop(ui, "inner_anim")
596             sub.prop(ui, "inner_anim_sel")
597             sub = row.column()
598             sub.prop(ui, "inner_driven")
599             sub.prop(ui, "inner_driven_sel")
600             sub = row.column()
601             sub.prop(ui, "inner_key")
602             sub.prop(ui, "inner_key_sel")
603             sub = row.column()
604             sub.prop(ui, "blend")
605
606             ui = theme.user_interface
607             col.separator()
608             col.separator()
609             col.prop(ui, "icon_file")
610
611             layout.separator()
612             layout.separator()
613
614
615         elif theme.theme_area == 'VIEW_3D':
616             v3d = theme.view_3d
617
618             col = split.column()
619             col.prop(v3d, "back")
620             col.prop(v3d, "button")
621             col.prop(v3d, "button_title")
622             col.prop(v3d, "button_text")
623             col.prop(v3d, "header")
624
625             col = split.column()
626             col.prop(v3d, "grid")
627             col.prop(v3d, "wire")
628             col.prop(v3d, "lamp", slider=True)
629             col.prop(v3d, "editmesh_active", slider=True)
630
631             col = split.column()
632             col.prop(v3d, "object_selected")
633             col.prop(v3d, "object_active")
634             col.prop(v3d, "object_grouped")
635             col.prop(v3d, "object_grouped_active")
636             col.prop(v3d, "transform")
637
638             col = split.column()
639             col.prop(v3d, "vertex")
640             col.prop(v3d, "face", slider=True)
641             col.prop(v3d, "normal")
642             col.prop(v3d, "bone_solid")
643             col.prop(v3d, "bone_pose")
644             #col.prop(v3d, "edge") Doesn't seem to work
645
646         elif theme.theme_area == 'GRAPH_EDITOR':
647             graph = theme.graph_editor
648
649             col = split.column()
650             col.prop(graph, "back")
651             col.prop(graph, "button")
652             col.prop(graph, "button_title")
653             col.prop(graph, "button_text")
654
655             col = split.column()
656             col.prop(graph, "header")
657             col.prop(graph, "grid")
658             col.prop(graph, "list")
659             col.prop(graph, "channel_group")
660
661             col = split.column()
662             col.prop(graph, "active_channels_group")
663             col.prop(graph, "dopesheet_channel")
664             col.prop(graph, "dopesheet_subchannel")
665             col.prop(graph, "vertex")
666
667             col = split.column()
668             col.prop(graph, "current_frame")
669             col.prop(graph, "handle_vertex")
670             col.prop(graph, "handle_vertex_select")
671             col.separator()
672             col.prop(graph, "handle_vertex_size")
673
674         elif theme.theme_area == 'FILE_BROWSER':
675             file_browse = theme.file_browser
676
677             col = split.column()
678             col.prop(file_browse, "back")
679             col.prop(file_browse, "text")
680             col.prop(file_browse, "text_hi")
681
682             col = split.column()
683             col.prop(file_browse, "header")
684             col.prop(file_browse, "list")
685
686             col = split.column()
687             col.prop(file_browse, "selected_file")
688             col.prop(file_browse, "tiles")
689
690             col = split.column()
691             col.prop(file_browse, "active_file")
692             col.prop(file_browse, "active_file_text")
693
694         elif theme.theme_area == 'NLA_EDITOR':
695             nla = theme.nla_editor
696
697             col = split.column()
698             col.prop(nla, "back")
699             col.prop(nla, "button")
700             col.prop(nla, "button_title")
701
702             col = split.column()
703             col.prop(nla, "button_text")
704             col.prop(nla, "text")
705             col.prop(nla, "header")
706
707             col = split.column()
708             col.prop(nla, "grid")
709             col.prop(nla, "bars")
710             col.prop(nla, "bars_selected")
711
712             col = split.column()
713             col.prop(nla, "strips")
714             col.prop(nla, "strips_selected")
715             col.prop(nla, "current_frame")
716
717         elif theme.theme_area == 'DOPESHEET_EDITOR':
718             dope = theme.dopesheet_editor
719
720             col = split.column()
721             col.prop(dope, "back")
722             col.prop(dope, "list")
723             col.prop(dope, "text")
724             col.prop(dope, "header")
725
726             col = split.column()
727             col.prop(dope, "grid")
728             col.prop(dope, "channels")
729             col.prop(dope, "channels_selected")
730             col.prop(dope, "channel_group")
731
732             col = split.column()
733             col.prop(dope, "active_channels_group")
734             col.prop(dope, "long_key")
735             col.prop(dope, "long_key_selected")
736
737             col = split.column()
738             col.prop(dope, "current_frame")
739             col.prop(dope, "dopesheet_channel")
740             col.prop(dope, "dopesheet_subchannel")
741
742         elif theme.theme_area == 'IMAGE_EDITOR':
743             image = theme.image_editor
744
745             col = split.column()
746             col.prop(image, "back")
747             col.prop(image, "scope_back")
748             col.prop(image, "button")
749
750             col = split.column()
751             col.prop(image, "button_title")
752             col.prop(image, "button_text")
753
754             col = split.column()
755             col.prop(image, "header")
756
757             col = split.column()
758             col.prop(image, "editmesh_active", slider=True)
759
760         elif theme.theme_area == 'SEQUENCE_EDITOR':
761             seq = theme.sequence_editor
762
763             col = split.column()
764             col.prop(seq, "back")
765             col.prop(seq, "button")
766             col.prop(seq, "button_title")
767             col.prop(seq, "button_text")
768             col.prop(seq, "text")
769
770             col = split.column()
771             col.prop(seq, "header")
772             col.prop(seq, "grid")
773             col.prop(seq, "movie_strip")
774             col.prop(seq, "image_strip")
775             col.prop(seq, "scene_strip")
776
777             col = split.column()
778             col.prop(seq, "audio_strip")
779             col.prop(seq, "effect_strip")
780             col.prop(seq, "plugin_strip")
781             col.prop(seq, "transition_strip")
782
783             col = split.column()
784             col.prop(seq, "meta_strip")
785             col.prop(seq, "current_frame")
786             col.prop(seq, "keyframe")
787             col.prop(seq, "draw_action")
788
789         elif theme.theme_area == 'PROPERTIES':
790             prop = theme.properties
791
792             col = split.column()
793             col.prop(prop, "back")
794
795             col = split.column()
796             col.prop(prop, "title")
797
798             col = split.column()
799             col.prop(prop, "text")
800
801             col = split.column()
802             col.prop(prop, "header")
803
804         elif theme.theme_area == 'TEXT_EDITOR':
805             text = theme.text_editor
806
807             col = split.column()
808             col.prop(text, "back")
809             col.prop(text, "button")
810             col.prop(text, "button_title")
811             col.prop(text, "button_text")
812
813             col = split.column()
814             col.prop(text, "text")
815             col.prop(text, "text_hi")
816             col.prop(text, "header")
817             col.prop(text, "line_numbers_background")
818
819             col = split.column()
820             col.prop(text, "selected_text")
821             col.prop(text, "cursor")
822             col.prop(text, "syntax_builtin")
823             col.prop(text, "syntax_special")
824
825             col = split.column()
826             col.prop(text, "syntax_comment")
827             col.prop(text, "syntax_string")
828             col.prop(text, "syntax_numbers")
829
830         elif theme.theme_area == 'TIMELINE':
831             time = theme.timeline
832
833             col = split.column()
834             col.prop(time, "back")
835             col.prop(time, "text")
836
837             col = split.column()
838             col.prop(time, "header")
839
840             col = split.column()
841             col.prop(time, "grid")
842
843             col = split.column()
844             col.prop(time, "current_frame")
845
846         elif theme.theme_area == 'NODE_EDITOR':
847             node = theme.node_editor
848
849             col = split.column()
850             col.prop(node, "back")
851             col.prop(node, "button")
852             col.prop(node, "button_title")
853             col.prop(node, "button_text")
854
855             col = split.column()
856             col.prop(node, "text")
857             col.prop(node, "text_hi")
858             col.prop(node, "header")
859             col.prop(node, "wires")
860
861             col = split.column()
862             col.prop(node, "wire_select")
863             col.prop(node, "selected_text")
864             col.prop(node, "node_backdrop", slider=True)
865             col.prop(node, "in_out_node")
866
867             col = split.column()
868             col.prop(node, "converter_node")
869             col.prop(node, "operator_node")
870             col.prop(node, "group_node")
871
872         elif theme.theme_area == 'LOGIC_EDITOR':
873             logic = theme.logic_editor
874
875             col = split.column()
876             col.prop(logic, "back")
877             col.prop(logic, "button")
878
879             col = split.column()
880             col.prop(logic, "button_title")
881             col.prop(logic, "button_text")
882
883             col = split.column()
884             col.prop(logic, "text")
885             col.prop(logic, "header")
886
887             col = split.column()
888             col.prop(logic, "panel")
889
890         elif theme.theme_area == 'OUTLINER':
891             out = theme.outliner
892
893             col = split.column()
894             col.prop(out, "back")
895
896             col = split.column()
897             col.prop(out, "text")
898
899             col = split.column()
900             col.prop(out, "text_hi")
901
902             col = split.column()
903             col.prop(out, "header")
904
905         elif theme.theme_area == 'INFO':
906             info = theme.info
907
908             col = split.column()
909             col.prop(info, "back")
910
911             col = split.column()
912             col.prop(info, "header")
913
914             col = split.column()
915             col.prop(info, "header_text")
916
917             col = split.column()
918
919         elif theme.theme_area == 'USER_PREFERENCES':
920             prefs = theme.user_preferences
921
922             col = split.column()
923             col.prop(prefs, "back")
924
925             col = split.column()
926             col.prop(prefs, "text")
927
928             col = split.column()
929             col.prop(prefs, "header")
930
931             col = split.column()
932             col.prop(prefs, "header_text")
933             
934         elif theme.theme_area == 'CONSOLE':
935             prefs = theme.console
936              
937             col = split.column()
938             col.prop(prefs, "header")
939             
940             col = split.column()
941             col.prop(prefs, "line_output")
942             col.prop(prefs, "line_input")
943             col.prop(prefs, "line_info")
944             col.prop(prefs, "line_error")
945             
946
947
948 class USERPREF_PT_file(bpy.types.Panel):
949     bl_space_type = 'USER_PREFERENCES'
950     bl_label = "Files"
951     bl_region_type = 'WINDOW'
952     bl_show_header = False
953
954     def poll(self, context):
955         userpref = context.user_preferences
956         return (userpref.active_section == 'FILES')
957
958     def draw(self, context):
959         layout = self.layout
960
961         userpref = context.user_preferences
962         paths = userpref.filepaths
963
964         split = layout.split(percentage=0.7)
965
966         col = split.column()
967         col.label(text="File Paths:")
968
969         colsplit = col.split(percentage=0.95)
970         col1 = colsplit.split(percentage=0.3)
971
972         sub = col1.column()
973         sub.label(text="Fonts:")
974         sub.label(text="Textures:")
975         sub.label(text="Texture Plugins:")
976         sub.label(text="Sequence Plugins:")
977         sub.label(text="Render Output:")
978         sub.label(text="Scripts:")
979         sub.label(text="Sounds:")
980         sub.label(text="Temp:")
981         sub.label(text="Animation Player:")
982
983         sub = col1.column()
984         sub.prop(paths, "fonts_directory", text="")
985         sub.prop(paths, "textures_directory", text="")
986         sub.prop(paths, "texture_plugin_directory", text="")
987         sub.prop(paths, "sequence_plugin_directory", text="")
988         sub.prop(paths, "render_output_directory", text="")
989         sub.prop(paths, "python_scripts_directory", text="")
990         sub.prop(paths, "sounds_directory", text="")
991         sub.prop(paths, "temporary_directory", text="")
992         subsplit = sub.split(percentage=0.3)
993         subsplit.prop(paths, "animation_player_preset", text="")
994         subsplit.prop(paths, "animation_player", text="")
995
996         col = split.column()
997         col.label(text="Save & Load:")
998         col.prop(paths, "use_relative_paths")
999         col.prop(paths, "compress_file")
1000         col.prop(paths, "load_ui")
1001         col.prop(paths, "filter_file_extensions")
1002         col.prop(paths, "hide_dot_files_datablocks")
1003
1004         col.separator()
1005         col.separator()
1006
1007         col.label(text="Auto Save:")
1008         col.prop(paths, "save_version")
1009         col.prop(paths, "recent_files")
1010         col.prop(paths, "save_preview_images")
1011         col.prop(paths, "auto_save_temporary_files")
1012         sub = col.column()
1013         sub.enabled = paths.auto_save_temporary_files
1014         sub.prop(paths, "auto_save_time", text="Timer (mins)")
1015
1016
1017 class USERPREF_PT_input(bpy.types.Panel):
1018     bl_space_type = 'USER_PREFERENCES'
1019     bl_label = "Input"
1020     bl_region_type = 'WINDOW'
1021     bl_show_header = False
1022
1023     def poll(self, context):
1024         userpref = context.user_preferences
1025         return (userpref.active_section == 'INPUT')
1026
1027     def draw_entry(self, kc, entry, col, level=0):
1028         idname, spaceid, regionid, children = entry
1029
1030         km = kc.find_keymap(idname, space_type=spaceid, region_type=regionid)
1031
1032         if km:
1033             self.draw_km(kc, km, children, col, level)
1034
1035     def indented_layout(self, layout, level):
1036         indentpx = 16
1037         if level == 0:
1038             level = 0.0001   # Tweak so that a percentage of 0 won't split by half
1039         indent = level * indentpx / bpy.context.region.width
1040
1041         split = layout.split(percentage=indent)
1042         col = split.column()
1043         col = split.column()
1044         return col
1045
1046     def draw_km(self, kc, km, children, layout, level):
1047         km = km.active()
1048
1049         layout.set_context_pointer("keymap", km)
1050
1051         col = self.indented_layout(layout, level)
1052
1053         row = col.row()
1054         row.prop(km, "children_expanded", text="", no_bg=True)
1055         row.label(text=km.name)
1056         
1057         row.label()
1058         row.label()
1059
1060         if km.modal:
1061             row.label(text="", icon='LINKED')
1062         if km.user_defined:
1063             row.operator("wm.keymap_restore", text="Restore")
1064         else:
1065             row.operator("wm.keymap_edit", text="Edit")
1066
1067         if km.children_expanded:
1068             if children:
1069                 # Put the Parent key map's entries in a 'global' sub-category
1070                 # equal in hierarchy to the other children categories
1071                 subcol = self.indented_layout(col, level + 1)
1072                 subrow = subcol.row()
1073                 subrow.prop(km, "items_expanded", text="", no_bg=True)
1074                 subrow.label(text="%s (Global)" % km.name)
1075             else:
1076                 km.items_expanded = True
1077
1078             # Key Map items
1079             if km.items_expanded:
1080                 for kmi in km.items:
1081                     self.draw_kmi(kc, km, kmi, col, level + 1)
1082
1083                 # "Add New" at end of keymap item list
1084                 col = self.indented_layout(col, level + 1)
1085                 subcol = col.split(percentage=0.2).column()
1086                 subcol.active = km.user_defined
1087                 subcol.operator("wm.keyitem_add", text="Add New", icon='ZOOMIN')
1088
1089             col.separator()
1090
1091             # Child key maps
1092             if children:
1093                 subcol = col.column()
1094                 row = subcol.row()
1095
1096                 for entry in children:
1097                     self.draw_entry(kc, entry, col, level + 1)
1098
1099     def draw_kmi(self, kc, km, kmi, layout, level):
1100         # reset keymap pointer, it might get changed by modal keymaps added after keymap items
1101         layout.set_context_pointer("keymap", km)
1102         layout.set_context_pointer("keyitem", kmi)
1103
1104         col = self.indented_layout(layout, level)
1105
1106         col.enabled = km.user_defined
1107
1108         if km.user_defined:
1109             col = col.column(align=True)
1110             box = col.box()
1111         else:
1112             box = col.column()
1113
1114         split = box.split(percentage=0.4)
1115
1116         # header bar
1117         row = split.row()
1118         row.prop(kmi, "expanded", text="", no_bg=True)
1119         row.prop(kmi, "active", text="", no_bg=True)
1120
1121         if km.modal:
1122             row.prop(kmi, "propvalue", text="")
1123         else:
1124             row.label(text=kmi.name)
1125
1126         row = split.row()
1127         row.prop(kmi, "map_type", text="")
1128         if kmi.map_type == 'KEYBOARD':
1129             row.prop(kmi, "type", text="", full_event=True)
1130         elif kmi.map_type == 'MOUSE':
1131             row.prop(kmi, "type", text="", full_event=True)
1132         elif kmi.map_type == 'TWEAK':
1133             subrow = row.row()
1134             subrow.prop(kmi, "type", text="")
1135             subrow.prop(kmi, "value", text="")
1136         elif kmi.map_type == 'TIMER':
1137             row.prop(kmi, "type", text="")
1138         else:
1139             row.label()
1140
1141         row.operator("wm.keyitem_restore", text="", icon='BACK')
1142         row.operator("wm.keyitem_remove", text="", icon='X')
1143
1144         # Expanded, additional event settings
1145         if kmi.expanded:
1146             box = col.box()
1147
1148             if kmi.map_type not in ('TEXTINPUT', 'TIMER'):
1149                 split = box.split(percentage=0.4)
1150                 sub = split.row()
1151
1152                 if km.modal:
1153                     sub.prop(kmi, "propvalue", text="")
1154                 else:
1155                     sub.prop(kmi, "idname", text="")
1156
1157                 sub = split.column()
1158                 subrow = sub.row(align=True)
1159
1160                 if kmi.map_type == 'KEYBOARD':
1161                     subrow.prop(kmi, "type", text="", event=True)
1162                     subrow.prop(kmi, "value", text="")
1163                 elif kmi.map_type == 'MOUSE':
1164                     subrow.prop(kmi, "type", text="")
1165                     subrow.prop(kmi, "value", text="")
1166
1167                 subrow = sub.row()
1168                 subrow.scale_x = 0.75
1169                 subrow.prop(kmi, "any")
1170                 subrow.prop(kmi, "shift")
1171                 subrow.prop(kmi, "ctrl")
1172                 subrow.prop(kmi, "alt")
1173                 subrow.prop(kmi, "oskey", text="Cmd")
1174                 subrow.prop(kmi, "key_modifier", text="", event=True)
1175                 
1176             def display_properties(properties, title = None):
1177                 box.separator()
1178                 if title:
1179                     box.label(text=title)
1180                 flow = box.column_flow(columns=2)
1181                 for pname in dir(properties):
1182                     if not properties.is_property_hidden(pname):
1183                         value = eval("properties." + pname)
1184                         if isinstance(value, bpy.types.OperatorProperties):
1185                             display_properties(value, title = pname)
1186                         else:
1187                             flow.prop(properties, pname)
1188
1189             # Operator properties
1190             props = kmi.properties
1191             if props is not None:
1192                 display_properties(props)
1193
1194             # Modal key maps attached to this operator
1195             if not km.modal:
1196                 kmm = kc.find_keymap_modal(kmi.idname)
1197                 if kmm:
1198                     self.draw_km(kc, kmm, None, layout, level + 1)
1199
1200     def draw_input_prefs(self, inputs, layout):
1201         # General settings
1202         row = layout.row()
1203         col = row.column()
1204
1205         sub = col.column()
1206         sub.label(text="Mouse:")
1207         sub1 = sub.column()
1208         sub1.enabled = (inputs.select_mouse == 'RIGHT')
1209         sub1.prop(inputs, "emulate_3_button_mouse")
1210         sub.prop(inputs, "continuous_mouse")
1211
1212         sub.label(text="Select With:")
1213         sub.row().prop(inputs, "select_mouse", expand=True)
1214
1215         sub = col.column()
1216         sub.label(text="Double Click:")
1217         sub.prop(inputs, "double_click_time", text="Speed")
1218
1219         sub.separator()
1220
1221         sub.prop(inputs, "emulate_numpad")
1222
1223         sub.separator()
1224
1225         sub.label(text="Orbit Style:")
1226         sub.row().prop(inputs, "view_rotation", expand=True)
1227
1228         sub.label(text="Zoom Style:")
1229         sub.row().prop(inputs, "viewport_zoom_style", expand=True)
1230         if inputs.viewport_zoom_style == 'DOLLY':
1231             sub.row().prop(inputs, "zoom_axis", expand=True)
1232             sub.prop(inputs, "invert_zoom_direction")
1233
1234         #sub.prop(inputs, "use_middle_mouse_paste")
1235
1236         #col.separator()
1237
1238         #sub = col.column()
1239         #sub.label(text="Mouse Wheel:")
1240         #sub.prop(view, "wheel_scroll_lines", text="Scroll Lines")
1241
1242         col.separator()
1243
1244         sub = col.column()
1245         sub.label(text="NDOF Device:")
1246         sub.prop(inputs, "ndof_pan_speed", text="Pan Speed")
1247         sub.prop(inputs, "ndof_rotate_speed", text="Orbit Speed")
1248
1249         row.separator()
1250
1251     def draw_filtered(self, kc, layout):
1252         filter = kc.filter.lower()
1253
1254         for km in kc.keymaps:
1255             km = km.active()
1256
1257             filtered_items = [kmi for kmi in km.items if filter in kmi.name.lower()]
1258
1259             if len(filtered_items) != 0:
1260                 layout.set_context_pointer("keymap", km)
1261                 col = layout.column()
1262
1263                 row = col.row()
1264                 row.label(text=km.name, icon="DOT")
1265
1266                 row.label()
1267                 row.label()
1268
1269                 if km.user_defined:
1270                     row.operator("wm.keymap_restore", text="Restore")
1271                 else:
1272                     row.operator("wm.keymap_edit", text="Edit")
1273
1274                 for kmi in filtered_items:
1275                     self.draw_kmi(kc, km, kmi, col, 1)
1276
1277                 # "Add New" at end of keymap item list
1278                 col = self.indented_layout(layout, 1)
1279                 subcol = col.split(percentage=0.2).column()
1280                 subcol.active = km.user_defined
1281                 subcol.operator("wm.keyitem_add", text="Add New", icon='ZOOMIN')
1282
1283     def draw_hierarchy(self, defkc, layout):
1284         for entry in KM_HIERARCHY:
1285             self.draw_entry(defkc, entry, layout)
1286
1287     def draw(self, context):
1288         layout = self.layout
1289
1290         userpref = context.user_preferences
1291         wm = context.manager
1292
1293         inputs = userpref.inputs
1294
1295         split = layout.split(percentage=0.25)
1296
1297         # Input settings
1298         self.draw_input_prefs(inputs, split)
1299
1300         # Keymap Settings
1301         col = split.column()
1302         # kc = wm.active_keyconfig
1303         kc = wm.default_keyconfig
1304
1305         sub = col.column()
1306
1307         subsplit = sub.split()
1308         subcol = subsplit.column()
1309         subcol.prop_object(wm, "active_keyconfig", wm, "keyconfigs", text="Configuration:")
1310
1311         subcol = subsplit.column()
1312         subcol.prop(kc, "filter", icon="VIEWZOOM")
1313
1314         col.separator()
1315
1316         if kc.filter != "":
1317             self.draw_filtered(kc, col)
1318         else:
1319             self.draw_hierarchy(kc, col)
1320
1321 bpy.types.register(USERPREF_HT_header)
1322 bpy.types.register(USERPREF_PT_tabs)
1323 bpy.types.register(USERPREF_PT_interface)
1324 bpy.types.register(USERPREF_PT_theme)
1325 bpy.types.register(USERPREF_PT_edit)
1326 bpy.types.register(USERPREF_PT_system)
1327 bpy.types.register(USERPREF_PT_file)
1328 bpy.types.register(USERPREF_PT_input)
1329
1330 from bpy.props import *
1331
1332
1333 class WM_OT_keyconfig_test(bpy.types.Operator):
1334     "Test keyconfig for conflicts."
1335     bl_idname = "wm.keyconfig_test"
1336     bl_label = "Test Key Configuration for Conflicts"
1337
1338     def testEntry(self, kc, entry, src=None, parent=None):
1339         result = False
1340
1341         def kmistr(kmi):
1342             if km.modal:
1343                 s = ["kmi = km.add_modal_item(\'%s\', \'%s\', \'%s\'" % (kmi.propvalue, kmi.type, kmi.value)]
1344             else:
1345                 s = ["kmi = km.add_item(\'%s\', \'%s\', \'%s\'" % (kmi.idname, kmi.type, kmi.value)]
1346
1347             if kmi.any:
1348                 s.append(", any=True")
1349             else:
1350                 if kmi.shift:
1351                     s.append(", shift=True")
1352                 if kmi.ctrl:
1353                     s.append(", ctrl=True")
1354                 if kmi.alt:
1355                     s.append(", alt=True")
1356                 if kmi.oskey:
1357                     s.append(", oskey=True")
1358             if kmi.key_modifier and kmi.key_modifier != 'NONE':
1359                 s.append(", key_modifier=\'%s\'" % kmi.key_modifier)
1360
1361             s.append(")\n")
1362             
1363             def export_properties(prefix, properties):
1364                 for pname in dir(properties):
1365                     if not properties.is_property_hidden(pname):
1366                         value = eval("properties.%s" % pname)
1367                         if isinstance(value, bpy.types.OperatorProperties):
1368                             export_properties(prefix + "." + pname, value)
1369                         elif properties.is_property_set(pname):
1370                             value = _string_value(value)
1371                             if value != "":
1372                                 s.append(prefix + ".%s = %s\n" % (pname, value))
1373
1374             props = kmi.properties
1375
1376             if props is not None:
1377                 export_properties("kmi.properties", props)
1378
1379             return "".join(s).strip()
1380
1381         idname, spaceid, regionid, children = entry
1382
1383         km = kc.find_keymap(idname, space_type=spaceid, region_type=regionid)
1384
1385         if km:
1386             km = km.active()
1387
1388             if src:
1389                 for item in km.items:
1390                     if src.compare(item):
1391                         print("===========")
1392                         print(parent.name)
1393                         print(kmistr(src))
1394                         print(km.name)
1395                         print(kmistr(item))
1396                         result = True
1397
1398                 for child in children:
1399                     if self.testEntry(kc, child, src, parent):
1400                         result = True
1401             else:
1402                 for i in range(len(km.items)):
1403                     src = km.items[i]
1404
1405                     for child in children:
1406                         if self.testEntry(kc, child, src, km):
1407                             result = True
1408
1409                     for j in range(len(km.items) - i - 1):
1410                         item = km.items[j + i + 1]
1411                         if src.compare(item):
1412                             print("===========")
1413                             print(km.name)
1414                             print(kmistr(src))
1415                             print(kmistr(item))
1416                             result = True
1417
1418                 for child in children:
1419                     if self.testEntry(kc, child):
1420                         result = True
1421
1422         return result
1423
1424     def testConfig(self, kc):
1425         result = False
1426         for entry in KM_HIERARCHY:
1427             if self.testEntry(kc, entry):
1428                 result = True
1429         return result
1430
1431     def execute(self, context):
1432         wm = context.manager
1433         kc = wm.default_keyconfig
1434
1435         if self.testConfig(kc):
1436             print("CONFLICT")
1437
1438         return {'FINISHED'}
1439
1440
1441 def _string_value(value):
1442     result = ""
1443     if isinstance(value, str):
1444         if value != "":
1445             result = "\'%s\'" % value
1446     elif isinstance(value, bool):
1447         if value:
1448             result = "True"
1449         else:
1450             result = "False"
1451     elif isinstance(value, float):
1452         result = "%.10f" % value
1453     elif isinstance(value, int):
1454         result = "%d" % value
1455     elif getattr(value, '__len__', False):
1456         if len(value):
1457             result = "["
1458             for i in range(0, len(value)):
1459                 result += _string_value(value[i])
1460                 if i != len(value)-1:
1461                     result += ", "
1462             result += "]"
1463     else:
1464         print("Export key configuration: can't write ", value)
1465
1466     return result
1467
1468
1469 class WM_OT_keyconfig_export(bpy.types.Operator):
1470     "Export key configuration to a python script."
1471     bl_idname = "wm.keyconfig_export"
1472     bl_label = "Export Key Configuration..."
1473
1474     path = bpy.props.StringProperty(name="File Path", description="File path to write file to.")
1475     filename = bpy.props.StringProperty(name="File Name", description="Name of the file.")
1476     directory = bpy.props.StringProperty(name="Directory", description="Directory of the file.")
1477     filter_folder = bpy.props.BoolProperty(name="Filter folders", description="", default=True)
1478     filter_text = bpy.props.BoolProperty(name="Filter text", description="", default=True)
1479     filter_python = bpy.props.BoolProperty(name="Filter python", description="", default=True)
1480
1481     def execute(self, context):
1482         if not self.properties.path:
1483             raise Exception("File path not set.")
1484
1485         f = open(self.properties.path, "w")
1486         if not f:
1487             raise Exception("Could not open file.")
1488
1489         wm = context.manager
1490         kc = wm.active_keyconfig
1491
1492         if kc.name == 'Blender':
1493             name = os.path.splitext(os.path.basename(self.properties.path))[0]
1494         else:
1495             name = kc.name
1496
1497         f.write('# Configuration %s\n' % name)
1498
1499         f.write("wm = bpy.data.window_managers[0]\n")
1500         f.write("kc = wm.add_keyconfig(\'%s\')\n\n" % name)
1501
1502         for km in kc.keymaps:
1503             km = km.active()
1504             f.write("# Map %s\n" % km.name)
1505             f.write("km = kc.add_keymap(\'%s\', space_type=\'%s\', region_type=\'%s\', modal=%s)\n\n" % (km.name, km.space_type, km.region_type, km.modal))
1506             for kmi in km.items:
1507                 if km.modal:
1508                     f.write("kmi = km.add_modal_item(\'%s\', \'%s\', \'%s\'" % (kmi.propvalue, kmi.type, kmi.value))
1509                 else:
1510                     f.write("kmi = km.add_item(\'%s\', \'%s\', \'%s\'" % (kmi.idname, kmi.type, kmi.value))
1511                 if kmi.any:
1512                     f.write(", any=True")
1513                 else:
1514                     if kmi.shift:
1515                         f.write(", shift=True")
1516                     if kmi.ctrl:
1517                         f.write(", ctrl=True")
1518                     if kmi.alt:
1519                         f.write(", alt=True")
1520                     if kmi.oskey:
1521                         f.write(", oskey=True")
1522                 if kmi.key_modifier and kmi.key_modifier != 'NONE':
1523                     f.write(", key_modifier=\'%s\'" % kmi.key_modifier)
1524                 f.write(")\n")
1525
1526                 def export_properties(prefix, properties):
1527                     for pname in dir(properties):
1528                         if not properties.is_property_hidden(pname):
1529                             value = eval("properties.%s" % pname)
1530                             if isinstance(value, bpy.types.OperatorProperties):
1531                                 export_properties(prefix + "." + pname, value)
1532                             elif properties.is_property_set(pname):
1533                                 value = _string_value(value)
1534                                 if value != "":
1535                                     f.write(prefix + ".%s = %s\n" % (pname, value))
1536     
1537                 props = kmi.properties
1538     
1539                 if props is not None:
1540                     export_properties("kmi.properties", props)
1541
1542             f.write("\n")
1543
1544         f.write("wm.active_keyconfig = wm.keyconfigs[\'%s\']\n" % name)
1545         f.close()
1546
1547         return {'FINISHED'}
1548
1549     def invoke(self, context, event):
1550         wm = context.manager
1551         wm.add_fileselect(self)
1552         return {'RUNNING_MODAL'}
1553
1554
1555 class WM_OT_keymap_edit(bpy.types.Operator):
1556     "Edit key map."
1557     bl_idname = "wm.keymap_edit"
1558     bl_label = "Edit Key Map"
1559
1560     def execute(self, context):
1561         wm = context.manager
1562         km = context.keymap
1563         km.copy_to_user()
1564         return {'FINISHED'}
1565
1566
1567 class WM_OT_keymap_restore(bpy.types.Operator):
1568     "Restore key map(s)."
1569     bl_idname = "wm.keymap_restore"
1570     bl_label = "Restore Key Map(s)"
1571
1572     all = BoolProperty(attr="all", name="All Keymaps", description="Restore all keymaps to default.")
1573
1574     def execute(self, context):
1575         wm = context.manager
1576
1577         if self.properties.all:
1578             for km in wm.default_keyconfig.keymaps:
1579                 km.restore_to_default()
1580         else:
1581             km = context.keymap
1582             km.restore_to_default()
1583
1584         return {'FINISHED'}
1585
1586
1587 class WM_OT_keyitem_restore(bpy.types.Operator):
1588     "Restore key map item."
1589     bl_idname = "wm.keyitem_restore"
1590     bl_label = "Restore Key Map Item"
1591
1592     def poll(self, context):
1593         kmi = context.keyitem
1594         km = context.keymap
1595         return km and kmi and kmi.id != 0
1596
1597     def execute(self, context):
1598         wm = context.manager
1599         kmi = context.keyitem
1600         km = context.keymap
1601
1602         km.restore_item_to_default(kmi)
1603
1604         return {'FINISHED'}
1605
1606
1607 class WM_OT_keyitem_add(bpy.types.Operator):
1608     "Add key map item."
1609     bl_idname = "wm.keyitem_add"
1610     bl_label = "Add Key Map Item"
1611
1612     def execute(self, context):
1613         wm = context.manager
1614         km = context.keymap
1615         kc = wm.default_keyconfig
1616
1617         if km.modal:
1618             km.add_modal_item("", 'A', 'PRESS') # kmi
1619         else:
1620             km.add_item("none", 'A', 'PRESS') # kmi
1621
1622         # clear filter and expand keymap so we can see the newly added item
1623         if kc.filter != '':
1624             kc.filter = ''
1625             km.items_expanded = True
1626             km.children_expanded = True
1627
1628         return {'FINISHED'}
1629
1630
1631 class WM_OT_keyitem_remove(bpy.types.Operator):
1632     "Remove key map item."
1633     bl_idname = "wm.keyitem_remove"
1634     bl_label = "Remove Key Map Item"
1635
1636     def execute(self, context):
1637         wm = context.manager
1638         kmi = context.keyitem
1639         km = context.keymap
1640         km.remove_item(kmi)
1641         return {'FINISHED'}
1642
1643 bpy.types.register(WM_OT_keyconfig_export)
1644 bpy.types.register(WM_OT_keyconfig_test)
1645 bpy.types.register(WM_OT_keymap_edit)
1646 bpy.types.register(WM_OT_keymap_restore)
1647 bpy.types.register(WM_OT_keyitem_add)
1648 bpy.types.register(WM_OT_keyitem_remove)
1649 bpy.types.register(WM_OT_keyitem_restore)