addons-contrib: more view_layer syntax updates
[blender-addons-contrib.git] / system_keyboard_svg.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
21 # this script creates Keyboard layout images of the current keyboard configuration.
22 # first implementation done by jbakker
23 # version 0.2 - file manager directory on export, modified the SVG layout (lijenstina)
24
25 bl_info = {
26     "name": "Keyboard Layout (SVG)",
27     "author": "Jbakker",
28     "version": (0, 2),
29     "blender": (2, 60, 0),
30     "location": "Help Menu > Save Shortcuts as SVG files",
31     "description": "Save the hotkeys as .svg files (search: Keyboard)",
32     "warning": "",
33     "wiki_url": "https://wiki.blender.org/index.php/Extensions:2.6/Py/"
34                 "Scripts/System/keymaps_to_svg",
35     "tracker_url": "https://developer.blender.org/maniphest/task/edit/form/2/",
36     "category": "System"
37     }
38
39 import bpy
40 import os
41 from math import ceil
42 from bpy.props import StringProperty
43
44 keyboard = (
45     ('`', 'ONE', 'TWO', 'THREE', 'FOUR', 'FIVE', 'SIX', 'SEVEN', 'EIGHT', 'NINE',
46     'ZERO', 'MINUS', 'EQUAL', 'BACKSPACE'),
47     ('TAB', 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P', '(', ')', '\\'),
48     ('CAPSLOCK', 'A', 'S', 'D', 'F', 'G', 'H', 'J', 'K', 'L', ';', "'", 'ENTER'),
49     ('SHIFT', 'Z', 'X', 'C', 'V', 'B', 'N', 'M', ',', '.', '/', 'SHIFT'),
50     ('CONTROL', 'OSKEY', 'ALT', 'SPACE', 'ALT', 'OSKEY', 'MENUKEY', 'CONTROL')
51     )
52
53 # default dimension of a single key [width, height]
54 HEIGHT_KEY = 160
55 DEFAULT_KEY_DIMENSION = 170, HEIGHT_KEY
56 # alternative dimensions of specific keys [keyname,[width, height]]
57 ALTERNATIVE_KEY_DIMENSIONS = {
58     'BACKSPACE': (270, HEIGHT_KEY),
59     'TAB': (220, HEIGHT_KEY),
60     '\\': (220, HEIGHT_KEY),
61     'CAPSLOCK': (285, HEIGHT_KEY),
62     'ENTER': (345, HEIGHT_KEY),
63     'SHIFT': (410, HEIGHT_KEY),
64     'CONTROL': (230, HEIGHT_KEY),
65     'ALT': DEFAULT_KEY_DIMENSION,
66     'OSKEY': DEFAULT_KEY_DIMENSION,
67     'MENUKEY': DEFAULT_KEY_DIMENSION,
68     'SPACE': (1290, HEIGHT_KEY),
69 }
70 INFO_STRING = "Modifier keys Info: [C] = Ctrl, [A] = Alt, [S] = Shift"
71
72
73 def createKeyboard(viewtype, filepaths):
74     """
75     Creates a keyboard layout (.svg) file of the current configuration for a specific viewtype.
76     example of a viewtype is "VIEW_3D".
77     """
78
79     for keyconfig in bpy.data.window_managers[0].keyconfigs:
80         kc_map = {}
81         for keymap in keyconfig.keymaps:
82             if keymap.space_type == viewtype:
83                 for key in keymap.keymap_items:
84                     if key.map_type == 'KEYBOARD':
85                         test = 0
86                         cont = ""
87                         if key.ctrl:
88                             test = test + 1
89                             cont = "C"
90                         if key.alt:
91                             test = test + 2
92                             cont = cont + "A"
93                         if key.shift:
94                             test = test + 4
95                             cont = cont + "S"
96                         if key.oskey:
97                             test = test + 8
98                             cont = cont + "O"
99                         if len(cont) > 0:
100                             cont = "[" + cont + "] "
101                         ktype = key.type
102                         if ktype not in kc_map:
103                             kc_map[ktype] = []
104                         kc_map[ktype].append((test, cont + key.name))
105
106         filename = "keyboard_%s.svg" % viewtype
107         export_path = os.path.join(os.path.normpath(filepaths), filename)
108         with open(export_path, mode="w") as svgfile:
109             svgfile.write("""<?xml version="1.0" standalone="no"?>
110     <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
111         """)
112             svgfile.write("""<svg width="2800" height="1000" version="1.1" xmlns="http://www.w3.org/2000/svg">
113         """)
114             svgfile.write("""<style>
115     rect {
116         fill:rgb(223,235,238);
117         stroke-width:1;
118         stroke:rgb(0,0,0);
119     }
120     text.header {
121         font-size:xx-large;
122     }
123     text.key {
124         fill:rgb(0,65,100);
125         font-size:x-large;
126         stroke-width:2;
127         stroke:rgb(0,65,100);
128     }
129     text.action {
130         font-size:smaller;
131     }
132     text.add0 {
133         font-size:smaller;
134         fill:rgb(0,0,0)
135     }
136     text.add1 {
137         font-size:smaller;
138         fill:rgb(255,0,0)
139     }
140     text.add2 {
141         font-size:smaller;
142         fill:rgb(0,128,115)
143     }
144     text.add3 {
145        font-size:smaller;
146        fill:rgb(128,128,0)
147     }
148     text.add4 {
149         font-size:smaller;
150         fill:rgb(0,0,255)
151     }
152     text.add5 {
153         font-size:smaller;
154         fill:rgb(128,0,128)
155     }
156     text.add6 {
157         font-size:smaller;
158         fill:rgb(0, 128, 128)
159     }
160     text.add7 {
161         font-size:smaller;
162         fill:rgb(128,128,128)
163     }
164     text.add8 {
165         font-size:smaller;
166         fill:rgb(128,128,128)
167     }
168     text.add9 {
169         font-size:smaller;
170         fill:rgb(255,128,128)
171     }
172     text.add10 {
173         font-size:smaller;
174         fill:rgb(128,255,128)
175     }
176     text.add11 {
177         font-size:smaller;
178         fill:rgb(255,255,128)
179     }
180     text.add12 {
181         font-size:smaller;
182         fill:rgb(128,128,255)
183     }
184     text.add13 {
185         font-size:smaller;
186         fill:rgb(255,128,255)
187     }
188     text.add14 {
189         font-size:smaller;
190         fill:rgb(128,255,255)
191     }
192     text.add15 {
193         font-size:smaller;
194         fill:rgb(255,255,128)
195     }
196     </style>
197     """)
198             svgfile.write("""<text class="header" x="30" y="32">Keyboard Layout for """ + viewtype + """</text>
199     """)
200
201             x = 20
202             xgap = 20
203             ygap = 20
204             y = 48
205             for row in keyboard:
206                 x = 30
207                 for key in row:
208                     width, height = ALTERNATIVE_KEY_DIMENSIONS.get(key, DEFAULT_KEY_DIMENSION)
209                     tx = ceil(width * 0.2)
210                     ty = 32
211                     svgfile.write("""<rect x=\"""" + str(x) +
212                                   """\" y=\"""" + str(y) +
213                                   """\" width=\"""" + str(width) +
214                                   """\" height=\"""" + str(height) +
215                                   """\" rx="20" ry="20" />
216         """)
217                     svgfile.write("""<text class="key" x=\"""" + str(x + tx) +
218                                   """\" y=\"""" + str(y + ty) +
219                                   """\" width=\"""" + str(width) +
220                                   """\" height=\"""" + str(height) + """\">
221         """)
222                     svgfile.write(key)
223                     svgfile.write("</text>")
224                     ty = ty + 16
225                     tx = 4
226                     if key in kc_map:
227                         for a in kc_map[key]:
228                             svgfile.write("""<text class="add""" + str(a[0]) +
229                                           """" x=\"""" + str(x + tx) +
230                                           """\" y=\"""" + str(y + ty) +
231                                           """\" width=\"""" + str(width) +
232                                           """\" height=\"""" + str(height) + """\">
233         """)
234                             svgfile.write(a[1])
235                             svgfile.write("</text>")
236                             ty = ty + 16
237                     x = x + width + xgap
238                 y = y + HEIGHT_KEY + ygap
239
240             svgfile.write("""<text class="header" x="30" y="975" >""")
241             svgfile.write(INFO_STRING)
242             svgfile.write("</text>")
243
244             svgfile.write("""</svg>""")
245
246
247 class WM_OT_keyboardlayout(bpy.types.Operator):
248     bl_idname = "wm.keyboardlayout"
249     bl_label = "Save Shortcuts as SVG files"
250     bl_description = ("Export the keyboard layouts in SVG format\n"
251                       "for each Editor in a separate file")
252
253     directory: StringProperty(
254         subtype='FILE_PATH',
255         options={'SKIP_SAVE'},
256         )
257
258     def invoke(self, context, event):
259         if not self.directory:
260             self.directory = ""
261
262         wm = context.window_manager
263         wm.fileselect_add(self)
264         return {'RUNNING_MODAL'}
265
266     def execute(self, context):
267         if not (os.path.isdir(self.directory) and os.path.exists(self.directory)):
268             self.report({'WARNING'},
269                         "Chosen path is not a directory or it doesn't exist. Operation Cancelled")
270             return {'CANCELLED'}
271
272         # Iterate over all viewtypes to export the keyboard layout
273         for vt in ('VIEW_3D',
274                    'LOGIC_EDITOR',
275                    'NODE_EDITOR',
276                    'CONSOLE',
277                    'GRAPH_EDITOR',
278                    'PROPERTIES',
279                    'SEQUENCE_EDITOR',
280                    'OUTLINER',
281                    'IMAGE_EDITOR',
282                    'TEXT_EDITOR',
283                    'DOPESHEET_EDITOR',
284                    'Window'):
285
286             createKeyboard(vt, self.directory)
287
288         return {'FINISHED'}
289
290
291 def menu_func_help(self, context):
292     self.layout.separator()
293     self.layout.operator(WM_OT_keyboardlayout.bl_idname, icon="IMGDISPLAY")
294
295
296 def register():
297     bpy.utils.register_class(WM_OT_keyboardlayout)
298
299     bpy.types.TOPBAR_MT_help.append(menu_func_help)
300
301
302 def unregister():
303     bpy.types.TOPBAR_MT_help.remove(menu_func_help)
304
305     bpy.utils.unregister_class(WM_OT_keyboardlayout)
306
307
308 if __name__ == "__main__":
309     register()