Merged changes in the trunk up to revision 28536.
[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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 #
17 # ##### END GPL LICENSE BLOCK #####
18
19 # <pep8 compliant>
20 import bpy
21 import os
22 import shutil
23
24
25 def ui_items_general(col, context):
26     """ General UI Theme Settings (User Interface)
27     """
28     row = col.row()
29     sub = row.column()
30     sub.prop(context, "outline")
31     sub.prop(context, "item", slider=True)
32     sub = row.column()
33     sub.prop(context, "inner", slider=True)
34     sub.prop(context, "inner_sel", slider=True)
35     sub = row.column()
36     sub.prop(context, "text")
37     sub.prop(context, "text_sel")
38     sub = row.column()
39     sub.prop(context, "shaded")
40     subsub = sub.column(align=True)
41     subsub.active = context.shaded
42     subsub.prop(context, "shadetop")
43     subsub.prop(context, "shadedown")
44
45     col.separator()
46
47
48 def opengl_lamp_buttons(column, lamp):
49     split = column.split(percentage=0.1)
50
51     if lamp.enabled == True:
52         split.prop(lamp, "enabled", text="", icon='OUTLINER_OB_LAMP')
53     else:
54         split.prop(lamp, "enabled", text="", icon='LAMP_DATA')
55
56     col = split.column()
57     col.active = lamp.enabled
58     row = col.row()
59     row.label(text="Diffuse:")
60     row.prop(lamp, "diffuse_color", text="")
61     row = col.row()
62     row.label(text="Specular:")
63     row.prop(lamp, "specular_color", text="")
64
65     col = split.column()
66     col.active = lamp.enabled
67     col.prop(lamp, "direction", text="")
68
69
70 class USERPREF_HT_header(bpy.types.Header):
71     bl_space_type = 'USER_PREFERENCES'
72
73     def draw(self, context):
74         layout = self.layout
75         layout.template_header(menus=False)
76
77         userpref = context.user_preferences
78
79         layout.operator_context = 'EXEC_AREA'
80         layout.operator("wm.save_homefile", text="Save As Default")
81
82         layout.operator_context = 'INVOKE_DEFAULT'
83
84         if userpref.active_section == 'INPUT':
85             op = layout.operator("wm.keyconfig_export")
86             op.path = "keymap.py"
87             op = layout.operator("wm.keyconfig_import")
88             op.path = "keymap.py"
89         elif userpref.active_section == 'ADDONS':
90             op = layout.operator("wm.addon_install")
91             op.path = "*.py"
92         elif userpref.active_section == 'THEMES':
93             op = layout.operator("ui.reset_default_theme")
94
95
96 class USERPREF_PT_tabs(bpy.types.Panel):
97     bl_label = ""
98     bl_space_type = 'USER_PREFERENCES'
99     bl_region_type = 'WINDOW'
100     bl_show_header = False
101
102     def draw(self, context):
103         layout = self.layout
104
105         userpref = context.user_preferences
106
107         layout.prop(userpref, "active_section", expand=True)
108
109
110 class USERPREF_MT_interaction_presets(bpy.types.Menu):
111     bl_label = "Presets"
112     preset_subdir = "interaction"
113     preset_operator = "script.execute_preset"
114     draw = bpy.types.Menu.draw_preset
115
116
117 class USERPREF_MT_splash(bpy.types.Menu):
118     bl_label = "Splash"
119
120     def draw(self, context):
121         layout = self.layout
122         split = layout.split()
123         row = split.row()
124         row.label("")
125         row = split.row()
126         row.label("Interaction:")
127         row.menu("USERPREF_MT_interaction_presets", text=bpy.types.USERPREF_MT_interaction_presets.bl_label)
128
129
130 class USERPREF_PT_interface(bpy.types.Panel):
131     bl_space_type = 'USER_PREFERENCES'
132     bl_label = "Interface"
133     bl_region_type = 'WINDOW'
134     bl_show_header = False
135
136     def poll(self, context):
137         userpref = context.user_preferences
138         return (userpref.active_section == 'INTERFACE')
139
140     def draw(self, context):
141         layout = self.layout
142
143         userpref = context.user_preferences
144         view = userpref.view
145
146         row = layout.row()
147
148         col = row.column()
149         col.label(text="Display:")
150         col.prop(view, "tooltips")
151         col.prop(view, "display_object_info", text="Object Info")
152         col.prop(view, "use_large_cursors")
153         col.prop(view, "show_view_name", text="View Name")
154         col.prop(view, "show_playback_fps", text="Playback FPS")
155         col.prop(view, "global_scene")
156         col.prop(view, "pin_floating_panels")
157         col.prop(view, "object_origin_size")
158
159         col.separator()
160         col.separator()
161         col.separator()
162
163         col.prop(view, "show_mini_axis", text="Display Mini Axis")
164         sub = col.column()
165         sub.enabled = view.show_mini_axis
166         sub.prop(view, "mini_axis_size", text="Size")
167         sub.prop(view, "mini_axis_brightness", text="Brightness")
168
169         row.separator()
170         row.separator()
171
172         col = row.column()
173         col.label(text="View Manipulation:")
174         col.prop(view, "auto_depth")
175         col.prop(view, "zoom_to_mouse")
176         col.prop(view, "rotate_around_selection")
177         col.prop(view, "global_pivot")
178
179         col.separator()
180
181         col.prop(view, "auto_perspective")
182         col.prop(view, "smooth_view")
183         col.prop(view, "rotation_angle")
184         
185         col.separator()
186         col.separator()
187         
188         col.label(text="2D Viewports:")
189         col.prop(view, "view2d_grid_minimum_spacing", text="Minimum Grid Spacing")
190         col.prop(view, "timecode_style")
191         
192         col.separator()
193         col.separator()
194
195         col.label(text="2D Viewports:")
196         col.prop(view, "view2d_grid_minimum_spacing", text="Minimum Grid Spacing")
197         col.prop(view, "timecode_style")
198
199         row.separator()
200         row.separator()
201
202         col = row.column()
203         #Toolbox doesn't exist yet
204         #col.label(text="Toolbox:")
205         #col.prop(view, "use_column_layout")
206         #col.label(text="Open Toolbox Delay:")
207         #col.prop(view, "open_left_mouse_delay", text="Hold LMB")
208         #col.prop(view, "open_right_mouse_delay", text="Hold RMB")
209         col.prop(view, "use_manipulator")
210         sub = col.column()
211         sub.enabled = view.use_manipulator
212         sub.prop(view, "manipulator_size", text="Size")
213         sub.prop(view, "manipulator_handle_size", text="Handle Size")
214         sub.prop(view, "manipulator_hotspot", text="Hotspot")
215
216         col.separator()
217         col.separator()
218         col.separator()
219
220         col.label(text="Menus:")
221         col.prop(view, "open_mouse_over")
222         col.label(text="Menu Open Delay:")
223         col.prop(view, "open_toplevel_delay", text="Top Level")
224         col.prop(view, "open_sublevel_delay", text="Sub Level")
225
226         col.separator()
227
228         col.prop(view, "show_splash")
229
230
231 class USERPREF_PT_edit(bpy.types.Panel):
232     bl_space_type = 'USER_PREFERENCES'
233     bl_label = "Edit"
234     bl_region_type = 'WINDOW'
235     bl_show_header = False
236
237     def poll(self, context):
238         userpref = context.user_preferences
239         return (userpref.active_section == 'EDITING')
240
241     def draw(self, context):
242         layout = self.layout
243
244         userpref = context.user_preferences
245         edit = userpref.edit
246
247         row = layout.row()
248
249         col = row.column()
250         col.label(text="Link Materials To:")
251         col.prop(edit, "material_link", text="")
252
253         col.separator()
254         col.separator()
255         col.separator()
256
257         col.label(text="New Objects:")
258         col.prop(edit, "enter_edit_mode")
259         col.label(text="Align To:")
260         col.prop(edit, "object_align", text="")
261
262         col.separator()
263         col.separator()
264         col.separator()
265
266         col.label(text="Undo:")
267         col.prop(edit, "global_undo")
268         col.prop(edit, "undo_steps", text="Steps")
269         col.prop(edit, "undo_memory_limit", text="Memory Limit")
270
271         row.separator()
272         row.separator()
273
274         col = row.column()
275         col.label(text="Snap:")
276         col.prop(edit, "snap_translate", text="Translate")
277         col.prop(edit, "snap_rotate", text="Rotate")
278         col.prop(edit, "snap_scale", text="Scale")
279         col.separator()
280         col.separator()
281         col.separator()
282         col.label(text="Grease Pencil:")
283         col.prop(edit, "grease_pencil_manhattan_distance", text="Manhattan Distance")
284         col.prop(edit, "grease_pencil_euclidean_distance", text="Euclidean Distance")
285         #col.prop(edit, "grease_pencil_simplify_stroke", text="Simplify Stroke")
286         col.prop(edit, "grease_pencil_eraser_radius", text="Eraser Radius")
287         col.prop(edit, "grease_pencil_smooth_stroke", text="Smooth Stroke")
288         col.separator()
289         col.separator()
290         col.separator()
291         col.label(text="Playback:")
292         col.prop(edit, "use_negative_frames")
293
294         row.separator()
295         row.separator()
296
297         col = row.column()
298         col.label(text="Keyframing:")
299         col.prop(edit, "use_visual_keying")
300         col.prop(edit, "keyframe_insert_needed", text="Only Insert Needed")
301
302         col.separator()
303
304         col.prop(edit, "use_auto_keying", text="Auto Keyframing:")
305
306         sub = col.column()
307
308         # sub.active = edit.use_auto_keying # incorrect, timeline can enable
309         sub.prop(edit, "auto_keyframe_insert_keyingset", text="Only Insert for Keying Set")
310         sub.prop(edit, "auto_keyframe_insert_available", text="Only Insert Available")
311
312         col.separator()
313
314         col.label(text="New F-Curve Defaults:")
315         col.prop(edit, "keyframe_new_interpolation_type", text="Interpolation")
316         col.prop(edit, "keyframe_new_handle_type", text="Handles")
317         col.prop(edit, "insertkey_xyz_to_rgb", text="XYZ to RGB")
318
319         col.separator()
320         col.separator()
321         col.separator()
322
323         col.label(text="Transform:")
324         col.prop(edit, "drag_immediately")
325
326         row.separator()
327         row.separator()
328
329         col = row.column()
330         col.label(text="Duplicate Data:")
331         col.prop(edit, "duplicate_mesh", text="Mesh")
332         col.prop(edit, "duplicate_surface", text="Surface")
333         col.prop(edit, "duplicate_curve", text="Curve")
334         col.prop(edit, "duplicate_text", text="Text")
335         col.prop(edit, "duplicate_metaball", text="Metaball")
336         col.prop(edit, "duplicate_armature", text="Armature")
337         col.prop(edit, "duplicate_lamp", text="Lamp")
338         col.prop(edit, "duplicate_material", text="Material")
339         col.prop(edit, "duplicate_texture", text="Texture")
340         col.prop(edit, "duplicate_fcurve", text="F-Curve")
341         col.prop(edit, "duplicate_action", text="Action")
342         col.prop(edit, "duplicate_particle", text="Particle")
343
344
345 class USERPREF_PT_system(bpy.types.Panel):
346     bl_space_type = 'USER_PREFERENCES'
347     bl_label = "System"
348     bl_region_type = 'WINDOW'
349     bl_show_header = False
350
351     def poll(self, context):
352         userpref = context.user_preferences
353         return (userpref.active_section == 'SYSTEM')
354
355     def draw(self, context):
356         layout = self.layout
357
358         userpref = context.user_preferences
359         system = userpref.system
360
361         split = layout.split()
362
363
364         # 1. Column
365         column = split.column()
366         colsplit = column.split(percentage=0.85)
367
368         col = colsplit.column()
369         col.label(text="General:")
370         col.prop(system, "dpi")
371         col.prop(system, "frame_server_port")
372         col.prop(system, "scrollback", text="Console Scrollback")
373         col.prop(system, "auto_execute_scripts")
374         col.prop(system, "tabs_as_spaces")
375
376         col.separator()
377         col.separator()
378         col.separator()
379
380         col.label(text="Sound:")
381         col.row().prop(system, "audio_device", expand=True)
382         sub = col.column()
383         sub.active = system.audio_device != 'NONE'
384         #sub.prop(system, "enable_all_codecs")
385         sub.prop(system, "audio_channels", text="Channels")
386         sub.prop(system, "audio_mixing_buffer", text="Mixing Buffer")
387         sub.prop(system, "audio_sample_rate", text="Sample Rate")
388         sub.prop(system, "audio_sample_format", text="Sample Format")
389
390         col.separator()
391         col.separator()
392         col.separator()
393
394         col.label(text="Screencast:")
395         col.prop(system, "screencast_fps")
396         col.prop(system, "screencast_wait_time")
397         col.separator()
398         col.separator()
399         col.separator()
400
401         #column = split.column()
402         #colsplit = column.split(percentage=0.85)
403
404         # No translation in 2.5 yet
405         #col.prop(system, "language")
406         #col.label(text="Translate:")
407         #col.prop(system, "translate_tooltips", text="Tooltips")
408         #col.prop(system, "translate_buttons", text="Labels")
409         #col.prop(system, "translate_toolbox", text="Toolbox")
410
411         #col.separator()
412
413         #col.prop(system, "use_textured_fonts")
414
415
416         # 2. Column
417         column = split.column()
418         colsplit = column.split(percentage=0.85)
419
420         col = colsplit.column()
421         col.label(text="OpenGL:")
422         col.prop(system, "clip_alpha", slider=True)
423         col.prop(system, "use_mipmaps")
424         col.prop(system, "use_vbos")
425         #Anti-aliasing is disabled as it breaks broder/lasso select
426         #col.prop(system, "use_antialiasing")
427         col.label(text="Window Draw Method:")
428         col.prop(system, "window_draw_method", text="")
429         col.label(text="Textures:")
430         col.prop(system, "gl_texture_limit", text="Limit Size")
431         col.prop(system, "texture_time_out", text="Time Out")
432         col.prop(system, "texture_collection_rate", text="Collection Rate")
433
434         col.separator()
435         col.separator()
436         col.separator()
437
438         col.label(text="Sequencer:")
439         col.prop(system, "prefetch_frames")
440         col.prop(system, "memory_cache_limit")
441
442
443         # 3. Column
444         column = split.column()
445
446         column.label(text="Solid OpenGL lights:")
447
448         split = column.split(percentage=0.1)
449         split.label()
450         split.label(text="Colors:")
451         split.label(text="Direction:")
452
453         lamp = system.solid_lights[0]
454         opengl_lamp_buttons(column, lamp)
455
456         lamp = system.solid_lights[1]
457         opengl_lamp_buttons(column, lamp)
458
459         lamp = system.solid_lights[2]
460         opengl_lamp_buttons(column, lamp)
461
462         column.separator()
463         column.separator()
464         column.separator()
465
466         column.label(text="Color Picker Type:")
467         column.row().prop(system, "color_picker_type", text="")
468
469         column.separator()
470         column.separator()
471         column.separator()
472
473         column.prop(system, "use_weight_color_range", text="Custom Weight Paint Range")
474         sub = column.column()
475         sub.active = system.use_weight_color_range
476         sub.template_color_ramp(system, "weight_color_range", expand=True)
477
478
479 class USERPREF_PT_theme(bpy.types.Panel):
480     bl_space_type = 'USER_PREFERENCES'
481     bl_label = "Themes"
482     bl_region_type = 'WINDOW'
483     bl_show_header = False
484
485     def poll(self, context):
486         userpref = context.user_preferences
487         return (userpref.active_section == 'THEMES')
488
489     def draw(self, context):
490         layout = self.layout
491
492         theme = context.user_preferences.themes[0]
493
494         split_themes = layout.split(percentage=0.2)
495         split_themes.prop(theme, "theme_area", expand=True)
496
497         split = split_themes.split()
498
499         if theme.theme_area == 'USER_INTERFACE':
500             col = split.column()
501
502             ui = theme.user_interface.wcol_regular
503             col.label(text="Regular:")
504             ui_items_general(col, ui)
505
506             ui = theme.user_interface.wcol_tool
507             col.label(text="Tool:")
508             ui_items_general(col, ui)
509
510             ui = theme.user_interface.wcol_radio
511             col.label(text="Radio Buttons:")
512             ui_items_general(col, ui)
513
514             ui = theme.user_interface.wcol_text
515             col.label(text="Text:")
516             ui_items_general(col, ui)
517
518             ui = theme.user_interface.wcol_option
519             col.label(text="Option:")
520             ui_items_general(col, ui)
521
522             ui = theme.user_interface.wcol_toggle
523             col.label(text="Toggle:")
524             ui_items_general(col, ui)
525
526             ui = theme.user_interface.wcol_num
527             col.label(text="Number Field:")
528             ui_items_general(col, ui)
529
530             ui = theme.user_interface.wcol_numslider
531             col.label(text="Value Slider:")
532             ui_items_general(col, ui)
533
534             ui = theme.user_interface.wcol_box
535             col.label(text="Box:")
536             ui_items_general(col, ui)
537
538             ui = theme.user_interface.wcol_menu
539             col.label(text="Menu:")
540             ui_items_general(col, ui)
541
542             ui = theme.user_interface.wcol_pulldown
543             col.label(text="Pulldown:")
544             ui_items_general(col, ui)
545
546             ui = theme.user_interface.wcol_menu_back
547             col.label(text="Menu Back:")
548             ui_items_general(col, ui)
549
550             ui = theme.user_interface.wcol_menu_item
551             col.label(text="Menu Item:")
552             ui_items_general(col, ui)
553
554             ui = theme.user_interface.wcol_scroll
555             col.label(text="Scroll Bar:")
556             ui_items_general(col, ui)
557
558             ui = theme.user_interface.wcol_list_item
559             col.label(text="List Item:")
560             ui_items_general(col, ui)
561
562             ui = theme.user_interface.wcol_state
563             col.label(text="State:")
564
565             row = col.row()
566             sub = row.column()
567             sub.prop(ui, "inner_anim")
568             sub.prop(ui, "inner_anim_sel")
569             sub = row.column()
570             sub.prop(ui, "inner_driven")
571             sub.prop(ui, "inner_driven_sel")
572             sub = row.column()
573             sub.prop(ui, "inner_key")
574             sub.prop(ui, "inner_key_sel")
575             sub = row.column()
576             sub.prop(ui, "blend")
577
578             ui = theme.user_interface
579             col.separator()
580             col.separator()
581             col.prop(ui, "icon_file")
582
583             layout.separator()
584             layout.separator()
585
586
587         elif theme.theme_area == 'VIEW_3D':
588             v3d = theme.view_3d
589
590             col = split.column()
591             col.prop(v3d, "back")
592             col.prop(v3d, "button")
593             col.prop(v3d, "button_title")
594             col.prop(v3d, "button_text")
595             col.prop(v3d, "header")
596
597             col = split.column()
598             col.prop(v3d, "grid")
599             col.prop(v3d, "wire")
600             col.prop(v3d, "lamp", slider=True)
601             col.prop(v3d, "editmesh_active", slider=True)
602
603             col = split.column()
604             col.prop(v3d, "object_selected")
605             col.prop(v3d, "object_active")
606             col.prop(v3d, "object_grouped")
607             col.prop(v3d, "object_grouped_active")
608             col.prop(v3d, "transform")
609             col.prop(v3d, "nurb_uline")
610             col.prop(v3d, "nurb_vline")
611             col.prop(v3d, "nurb_sel_uline")
612             col.prop(v3d, "nurb_sel_vline")
613             col.prop(v3d, "handle_free")
614             col.prop(v3d, "handle_auto")
615             col.prop(v3d, "handle_vect")
616             col.prop(v3d, "handle_align")
617             col.prop(v3d, "handle_sel_free")
618             col.prop(v3d, "handle_sel_auto")
619             col.prop(v3d, "handle_sel_vect")
620             col.prop(v3d, "handle_sel_align")
621             col.prop(v3d, "act_spline")
622             col.prop(v3d, "lastsel_point")
623
624             col = split.column()
625             col.prop(v3d, "vertex")
626             col.prop(v3d, "face", slider=True)
627             col.prop(v3d, "normal")
628             col.prop(v3d, "vertex_normal")
629             col.prop(v3d, "bone_solid")
630             col.prop(v3d, "bone_pose")
631             col.prop(v3d, "edge_seam")
632             col.prop(v3d, "edge_sharp")
633             col.prop(v3d, "edge_crease")
634             #col.prop(v3d, "edge") Doesn't seem to work
635
636         elif theme.theme_area == 'GRAPH_EDITOR':
637             graph = theme.graph_editor
638
639             col = split.column()
640             col.prop(graph, "back")
641             col.prop(graph, "button")
642             col.prop(graph, "button_title")
643             col.prop(graph, "button_text")
644
645             col = split.column()
646             col.prop(graph, "header")
647             col.prop(graph, "grid")
648             col.prop(graph, "list")
649             col.prop(graph, "channel_group")
650
651             col = split.column()
652             col.prop(graph, "active_channels_group")
653             col.prop(graph, "dopesheet_channel")
654             col.prop(graph, "dopesheet_subchannel")
655             col.prop(graph, "frame_current")
656
657             col = split.column()
658             col.prop(graph, "vertex")
659             col.prop(graph, "handle_vertex")
660             col.prop(graph, "handle_vertex_select")
661             col.separator()
662             col.prop(graph, "handle_vertex_size")
663             col.separator()
664             col.separator()
665             col.prop(graph, "handle_free")
666             col.prop(graph, "handle_auto")
667             col.prop(graph, "handle_vect")
668             col.prop(graph, "handle_align")
669             col.prop(graph, "handle_sel_free")
670             col.prop(graph, "handle_sel_auto")
671             col.prop(graph, "handle_sel_vect")
672             col.prop(graph, "handle_sel_align")
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, "frame_current")
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, "frame_current")
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, "frame_current")
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, "frame_current")
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, "back")
939             col.prop(prefs, "header")
940
941             col = split.column()
942             col.prop(prefs, "line_output")
943             col.prop(prefs, "line_input")
944             col.prop(prefs, "line_info")
945             col.prop(prefs, "line_error")
946             col.prop(prefs, "cursor")
947
948
949 class USERPREF_PT_file(bpy.types.Panel):
950     bl_space_type = 'USER_PREFERENCES'
951     bl_label = "Files"
952     bl_region_type = 'WINDOW'
953     bl_show_header = False
954
955     def poll(self, context):
956         userpref = context.user_preferences
957         return (userpref.active_section == 'FILES')
958
959     def draw(self, context):
960         layout = self.layout
961
962         userpref = context.user_preferences
963         paths = userpref.filepaths
964
965         split = layout.split(percentage=0.7)
966
967         col = split.column()
968         col.label(text="File Paths:")
969
970         colsplit = col.split(percentage=0.95)
971         col1 = colsplit.split(percentage=0.3)
972
973         sub = col1.column()
974         sub.label(text="Fonts:")
975         sub.label(text="Textures:")
976         sub.label(text="Texture Plugins:")
977         sub.label(text="Sequence Plugins:")
978         sub.label(text="Render Output:")
979         sub.label(text="Scripts:")
980         sub.label(text="Sounds:")
981         sub.label(text="Temp:")
982         sub.label(text="Image Editor:")
983         sub.label(text="Animation Player:")
984
985         sub = col1.column()
986         sub.prop(paths, "fonts_directory", text="")
987         sub.prop(paths, "textures_directory", text="")
988         sub.prop(paths, "texture_plugin_directory", text="")
989         sub.prop(paths, "sequence_plugin_directory", text="")
990         sub.prop(paths, "render_output_directory", text="")
991         sub.prop(paths, "python_scripts_directory", text="")
992         sub.prop(paths, "sounds_directory", text="")
993         sub.prop(paths, "temporary_directory", text="")
994         sub.prop(paths, "image_editor", text="")
995         subsplit = sub.split(percentage=0.3)
996         subsplit.prop(paths, "animation_player_preset", text="")
997         subsplit.prop(paths, "animation_player", text="")
998
999         col = split.column()
1000         col.label(text="Save & Load:")
1001         col.prop(paths, "use_relative_paths")
1002         col.prop(paths, "compress_file")
1003         col.prop(paths, "load_ui")
1004         col.prop(paths, "filter_file_extensions")
1005         col.prop(paths, "hide_dot_files_datablocks")
1006
1007         col.separator()
1008         col.separator()
1009
1010         col.label(text="Auto Save:")
1011         col.prop(paths, "save_version")
1012         col.prop(paths, "recent_files")
1013         col.prop(paths, "save_preview_images")
1014         col.prop(paths, "auto_save_temporary_files")
1015         sub = col.column()
1016         sub.enabled = paths.auto_save_temporary_files
1017         sub.prop(paths, "auto_save_time", text="Timer (mins)")
1018
1019 from space_userpref_keymap import InputKeyMapPanel
1020
1021
1022 class USERPREF_PT_input(InputKeyMapPanel):
1023     bl_space_type = 'USER_PREFERENCES'
1024     bl_label = "Input"
1025
1026     def poll(self, context):
1027         userpref = context.user_preferences
1028         return (userpref.active_section == 'INPUT')
1029
1030     def draw_input_prefs(self, inputs, layout):
1031         # General settings
1032         row = layout.row()
1033         col = row.column()
1034
1035         sub = col.column()
1036         sub.label(text="Presets:")
1037         subrow = sub.row(align=True)
1038         subrow.menu("USERPREF_MT_interaction_presets", text=bpy.types.USERPREF_MT_interaction_presets.bl_label)
1039         subrow.operator("wm.interaction_preset_add", text="", icon="ZOOMIN")
1040         sub.separator()
1041
1042         sub.label(text="Mouse:")
1043         sub1 = sub.column()
1044         sub1.enabled = (inputs.select_mouse == 'RIGHT')
1045         sub1.prop(inputs, "emulate_3_button_mouse")
1046         sub.prop(inputs, "continuous_mouse")
1047
1048         sub.label(text="Select With:")
1049         sub.row().prop(inputs, "select_mouse", expand=True)
1050
1051         sub = col.column()
1052         sub.label(text="Double Click:")
1053         sub.prop(inputs, "double_click_time", text="Speed")
1054
1055         sub.separator()
1056
1057         sub.prop(inputs, "emulate_numpad")
1058
1059         sub.separator()
1060
1061         sub.label(text="Orbit Style:")
1062         sub.row().prop(inputs, "view_rotation", expand=True)
1063
1064         sub.label(text="Zoom Style:")
1065         sub.row().prop(inputs, "zoom_style", text="")
1066         if inputs.zoom_style == 'DOLLY':
1067             sub.row().prop(inputs, "zoom_axis", expand=True)
1068             sub.prop(inputs, "invert_zoom_direction")
1069
1070         #sub.prop(inputs, "use_middle_mouse_paste")
1071
1072         #col.separator()
1073
1074         #sub = col.column()
1075         #sub.label(text="Mouse Wheel:")
1076         #sub.prop(view, "wheel_scroll_lines", text="Scroll Lines")
1077
1078         col.separator()
1079         ''' not implemented yet
1080         sub = col.column()
1081         sub.label(text="NDOF Device:")
1082         sub.prop(inputs, "ndof_pan_speed", text="Pan Speed")
1083         sub.prop(inputs, "ndof_rotate_speed", text="Orbit Speed")
1084         '''
1085
1086         row.separator()
1087
1088     def draw(self, context):
1089         layout = self.layout
1090
1091         #import time
1092
1093         #start = time.time()
1094
1095         userpref = context.user_preferences
1096         wm = context.manager
1097
1098         inputs = userpref.inputs
1099
1100         split = layout.split(percentage=0.25)
1101
1102         # Input settings
1103         self.draw_input_prefs(inputs, split)
1104
1105         # Keymap Settings
1106         self.draw_keymaps(context, split)
1107
1108         #print("runtime", time.time() - start)
1109
1110
1111 class USERPREF_PT_addons(bpy.types.Panel):
1112     bl_space_type = 'USER_PREFERENCES'
1113     bl_label = "Addons"
1114     bl_region_type = 'WINDOW'
1115     bl_show_header = False
1116
1117     def poll(self, context):
1118         userpref = context.user_preferences
1119         return (userpref.active_section == 'ADDONS')
1120
1121     def _addon_list(self):
1122         import sys
1123         modules = []
1124         loaded_modules = set()
1125         paths = bpy.utils.script_paths("addons")
1126         # sys.path.insert(0, None)
1127         for path in paths:
1128             # sys.path[0] = path
1129             modules.extend(bpy.utils.modules_from_path(path, loaded_modules))
1130
1131         # del sys.path[0]
1132         return modules
1133
1134     def draw(self, context):
1135         layout = self.layout
1136
1137         userpref = context.user_preferences
1138         used_ext = {ext.module for ext in userpref.addons}
1139
1140         # collect the categories that can be filtered on
1141         addons = [(mod, addon_info_get(mod)) for mod in self._addon_list()]
1142
1143         cats = {info["category"] for mod, info in addons}
1144         cats.discard("")
1145
1146         cats = ['All', 'Disabled', 'Enabled'] + sorted(cats)
1147
1148         bpy.types.Scene.EnumProperty(items=[(cat, cat, str(i)) for i, cat in enumerate(cats)],
1149             name="Category", attr="addon_filter", description="Filter add-ons by category")
1150         bpy.types.Scene.StringProperty(name="Search", attr="addon_search",
1151             description="Search within the selected filter")
1152
1153         row = layout.row()
1154         row.prop(context.scene, "addon_filter", text="Filter")
1155         row.prop(context.scene, "addon_search", text="Search", icon='VIEWZOOM')
1156         layout.separator()
1157
1158         filter = context.scene.addon_filter
1159         search = context.scene.addon_search.lower()
1160
1161         for mod, info in addons:
1162             module_name = mod.__name__
1163
1164             is_enabled = module_name in used_ext
1165
1166             # check if add-on should be visible with current filters
1167             if (filter == "All") or \
1168                     (filter == info["category"]) or \
1169                     (filter == "Enabled" and is_enabled) or \
1170                     (filter == "Disabled" and not is_enabled):
1171
1172
1173                 if search and search not in info["name"].lower():
1174                     if info["author"]:
1175                         if search not in info["author"].lower():
1176                             continue
1177                     else:
1178                         continue
1179
1180                 # Addon UI Code
1181                 box = layout.column().box()
1182                 column = box.column()
1183                 row = column.row()
1184
1185                 # Arrow #
1186                 # If there are Infos or UI is expanded
1187                 if info["expanded"]:
1188                     row.operator("wm.addon_expand", icon="TRIA_DOWN").module = module_name
1189                 elif info["author"] or info["version"] or info["url"] or info["location"]:
1190                     row.operator("wm.addon_expand", icon="TRIA_RIGHT").module = module_name
1191                 else:
1192                     # Else, block UI
1193                     arrow = row.column()
1194                     arrow.enabled = False
1195                     arrow.operator("wm.addon_expand", icon="TRIA_RIGHT").module = module_name
1196
1197                 row.label(text=info["name"])
1198                 row.operator("wm.addon_disable" if is_enabled else "wm.addon_enable").module = module_name
1199
1200                 # Expanded UI (only if additional infos are available)
1201                 if info["expanded"]:
1202                     if info["author"]:
1203                         split = column.row().split(percentage=0.15)
1204                         split.label(text='Author:')
1205                         split.label(text=info["author"])
1206                     if info["version"]:
1207                         split = column.row().split(percentage=0.15)
1208                         split.label(text='Version:')
1209                         split.label(text=info["version"])
1210                     if info["location"]:
1211                         split = column.row().split(percentage=0.15)
1212                         split.label(text='Location:')
1213                         split.label(text=info["location"])
1214                     if info["description"]:
1215                         split = column.row().split(percentage=0.15)
1216                         split.label(text='Description:')
1217                         split.label(text=info["description"])
1218                     if info["url"]:
1219                         split = column.row().split(percentage=0.15)
1220                         split.label(text="Internet:")
1221                         split.operator("wm.addon_links", text="Link to the Wiki").link = info["url"]
1222                         split.separator()
1223                         split.separator()
1224
1225         # Append missing scripts
1226         # First collect scripts that are used but have no script file.
1227         module_names = {mod.__name__ for mod, info in addons}
1228         missing_modules = {ext for ext in used_ext if ext not in module_names}
1229
1230         if missing_modules and filter in ("All", "Enabled"):
1231             layout.column().separator()
1232             layout.column().label(text="Missing script files")
1233
1234             module_names = {mod.__name__ for mod, info in addons}
1235             for ext in sorted(missing_modules):
1236                 # Addon UI Code
1237                 box = layout.column().box()
1238                 column = box.column()
1239                 row = column.row()
1240
1241                 row.label(text=ext, icon="ERROR")
1242                 row.operator("wm.addon_disable").module = ext
1243
1244 from bpy.props import *
1245
1246
1247 def addon_info_get(mod, info_basis={"name": "", "author": "", "version": "", "blender": "", "location": "", "description": "", "url": "", "category": "", "expanded": False}):
1248     addon_info = getattr(mod, "bl_addon_info", {})
1249
1250     # avoid re-initializing
1251     if "_init" in addon_info:
1252         return addon_info
1253
1254     if not addon_info:
1255         mod.bl_addon_info = addon_info
1256
1257     for key, value in info_basis.items():
1258         addon_info.setdefault(key, value)
1259
1260     if not addon_info["name"]:
1261         addon_info["name"] = mod.__name__
1262
1263     addon_info["_init"] = None
1264     return addon_info
1265
1266
1267 class WM_OT_addon_enable(bpy.types.Operator):
1268     "Enable an addon"
1269     bl_idname = "wm.addon_enable"
1270     bl_label = "Enable Add-On"
1271
1272     module = StringProperty(name="Module", description="Module name of the addon to enable")
1273
1274     def execute(self, context):
1275         module_name = self.properties.module
1276
1277         try:
1278             mod = __import__(module_name)
1279             mod.register()
1280         except:
1281             import traceback
1282             traceback.print_exc()
1283             return {'CANCELLED'}
1284
1285         ext = context.user_preferences.addons.new()
1286         ext.module = module_name
1287
1288         # check if add-on is written for current blender version, or raise a warning
1289         info = addon_info_get(mod)
1290
1291         if info.get("blender", (0, 0, 0)) > bpy.app.version:
1292             self.report("WARNING','This script was written for a newer version of Blender and might not function (correctly).\nThe script is enabled though.")
1293
1294         return {'FINISHED'}
1295
1296
1297 class WM_OT_addon_disable(bpy.types.Operator):
1298     "Disable an addon"
1299     bl_idname = "wm.addon_disable"
1300     bl_label = "Disable Add-On"
1301
1302     module = StringProperty(name="Module", description="Module name of the addon to disable")
1303
1304     def execute(self, context):
1305         import traceback
1306         module_name = self.properties.module
1307
1308         try:
1309             mod = __import__(module_name)
1310             mod.unregister()
1311         except:
1312             traceback.print_exc()
1313
1314         addons = context.user_preferences.addons
1315         ok = True
1316         while ok: # incase its in more then once.
1317             ok = False
1318             for ext in addons:
1319                 if ext.module == module_name:
1320                     addons.remove(ext)
1321                     ok = True
1322                     break
1323
1324         return {'FINISHED'}
1325
1326
1327 class WM_OT_addon_install(bpy.types.Operator):
1328     "Install an addon"
1329     bl_idname = "wm.addon_install"
1330     bl_label = "Install Add-On..."
1331
1332     module = StringProperty(name="Module", description="Module name of the addon to disable")
1333
1334     path = StringProperty(name="File Path", description="File path to write file to")
1335     filename = StringProperty(name="File Name", description="Name of the file")
1336     directory = StringProperty(name="Directory", description="Directory of the file")
1337     filter_folder = BoolProperty(name="Filter folders", description="", default=True, options={'HIDDEN'})
1338     filter_python = BoolProperty(name="Filter python", description="", default=True, options={'HIDDEN'})
1339
1340     def execute(self, context):
1341         import traceback
1342         import zipfile
1343         pyfile = self.properties.path
1344
1345         path_addons = bpy.utils.script_paths("addons")[-1]
1346
1347         #check to see if the file is in compressed format (.zip)
1348         if zipfile.is_zipfile(pyfile):
1349             try:
1350                 file_to_extract = zipfile.ZipFile(pyfile, 'r')
1351
1352                 #extract the file to "addons"
1353                 file_to_extract.extractall(path_addons)
1354
1355             except:
1356                 traceback.print_exc()
1357                 return {'CANCELLED'}
1358
1359         else:
1360             path_dest = os.path.join(path_addons, os.path.basename(pyfile))
1361
1362             if os.path.exists(path_dest):
1363                 self.report({'WARNING'}, "File already installed to '%s'\n" % path_dest)
1364                 return {'CANCELLED'}
1365
1366             #if not compressed file just copy into the addon path
1367             try:
1368                 shutil.copyfile(pyfile, path_dest)
1369
1370             except:
1371                 traceback.print_exc()
1372                 return {'CANCELLED'}
1373
1374         # TODO, should not be a warning.
1375         # self.report({'WARNING'}, "File installed to '%s'\n" % path_dest)
1376         return {'FINISHED'}
1377
1378     def invoke(self, context, event):
1379         paths = bpy.utils.script_paths("addons")
1380         if not paths:
1381             self.report({'ERROR'}, "No 'addons' path could be found in " + str(bpy.utils.script_paths()))
1382             return {'CANCELLED'}
1383
1384         wm = context.manager
1385         wm.add_fileselect(self)
1386         return {'RUNNING_MODAL'}
1387
1388
1389 class WM_OT_addon_expand(bpy.types.Operator):
1390     "Display more information on this add-on"
1391     bl_idname = "wm.addon_expand"
1392     bl_label = ""
1393
1394     module = StringProperty(name="Module", description="Module name of the addon to expand")
1395
1396     def execute(self, context):
1397         module_name = self.properties.module
1398
1399         # unlikely to fail, module should have alredy been imported
1400         try:
1401             mod = __import__(module_name)
1402         except:
1403             import traceback
1404             traceback.print_exc()
1405             return {'CANCELLED'}
1406
1407         info = addon_info_get(mod)
1408         info["expanded"] = not info["expanded"]
1409         return {'FINISHED'}
1410
1411
1412 class WM_OT_addon_links(bpy.types.Operator):
1413     "Open the Blender Wiki in the Webbrowser"
1414     bl_idname = "wm.addon_links"
1415     bl_label = ""
1416
1417     link = StringProperty(name="Link", description="Link to open")
1418
1419     def execute(self, context):
1420         import webbrowser
1421         webbrowser.open(self.properties.link)
1422         return {'FINISHED'}
1423
1424
1425 classes = [
1426     USERPREF_HT_header,
1427     USERPREF_PT_tabs,
1428     USERPREF_PT_interface,
1429     USERPREF_PT_theme,
1430     USERPREF_PT_edit,
1431     USERPREF_PT_system,
1432     USERPREF_PT_file,
1433     USERPREF_PT_input,
1434     USERPREF_PT_addons,
1435
1436     USERPREF_MT_interaction_presets,
1437     USERPREF_MT_splash,
1438
1439     WM_OT_addon_enable,
1440     WM_OT_addon_disable,
1441     WM_OT_addon_install,
1442     WM_OT_addon_expand,
1443     WM_OT_addon_links]
1444
1445
1446 def register():
1447     register = bpy.types.register
1448     for cls in classes:
1449         register(cls)
1450
1451
1452 def unregister():
1453     unregister = bpy.types.unregister
1454     for cls in classes:
1455         unregister(cls)
1456
1457 if __name__ == "__main__":
1458     register()