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