310 lines
9.9 KiB
Python
310 lines
9.9 KiB
Python
# ##### BEGIN GPL LICENSE BLOCK #####
|
|
#
|
|
# This program is free software; you can redistribute it and/or
|
|
# modify it under the terms of the GNU General Public License
|
|
# as published by the Free Software Foundation; either version 2
|
|
# of the License, or (at your option) any later version.
|
|
#
|
|
# This program is distributed in the hope that it will be useful,
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
# GNU General Public License for more details.
|
|
#
|
|
# You should have received a copy of the GNU General Public License
|
|
# along with this program; if not, write to the Free Software Foundation,
|
|
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
#
|
|
# ##### END GPL LICENSE BLOCK #####
|
|
|
|
# <pep8 compliant>
|
|
|
|
# this script creates Keyboard layout images of the current keyboard configuration.
|
|
# first implementation done by jbakker
|
|
# version 0.2 - file manager directory on export, modified the SVG layout (lijenstina)
|
|
|
|
bl_info = {
|
|
"name": "Keyboard Layout (SVG)",
|
|
"author": "Jbakker",
|
|
"version": (0, 2),
|
|
"blender": (2, 80, 0),
|
|
"location": "Help Menu > Save Shortcuts as SVG files",
|
|
"description": "Save the hotkeys as .svg files (search: Keyboard)",
|
|
"warning": "Needs Updating. Basic functions work",
|
|
"doc_url": "https://wiki.blender.org/index.php/Extensions:2.6/Py/"
|
|
"Scripts/System/keymaps_to_svg",
|
|
"tracker_url": "https://developer.blender.org/maniphest/task/edit/form/2/",
|
|
"category": "System",
|
|
}
|
|
|
|
import bpy
|
|
import os
|
|
from math import ceil
|
|
from bpy.props import StringProperty
|
|
|
|
keyboard = (
|
|
('`', 'ONE', 'TWO', 'THREE', 'FOUR', 'FIVE', 'SIX', 'SEVEN', 'EIGHT', 'NINE',
|
|
'ZERO', 'MINUS', 'EQUAL', 'BACKSPACE'),
|
|
('TAB', 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P', '(', ')', '\\'),
|
|
('CAPSLOCK', 'A', 'S', 'D', 'F', 'G', 'H', 'J', 'K', 'L', ';', "'", 'ENTER'),
|
|
('SHIFT', 'Z', 'X', 'C', 'V', 'B', 'N', 'M', ',', '.', '/', 'SHIFT'),
|
|
('CONTROL', 'OSKEY', 'ALT', 'SPACE', 'ALT', 'OSKEY', 'MENUKEY', 'CONTROL')
|
|
)
|
|
|
|
# default dimension of a single key [width, height]
|
|
HEIGHT_KEY = 160
|
|
DEFAULT_KEY_DIMENSION = 170, HEIGHT_KEY
|
|
# alternative dimensions of specific keys [keyname,[width, height]]
|
|
ALTERNATIVE_KEY_DIMENSIONS = {
|
|
'BACKSPACE': (270, HEIGHT_KEY),
|
|
'TAB': (220, HEIGHT_KEY),
|
|
'\\': (220, HEIGHT_KEY),
|
|
'CAPSLOCK': (285, HEIGHT_KEY),
|
|
'ENTER': (345, HEIGHT_KEY),
|
|
'SHIFT': (410, HEIGHT_KEY),
|
|
'CONTROL': (230, HEIGHT_KEY),
|
|
'ALT': DEFAULT_KEY_DIMENSION,
|
|
'OSKEY': DEFAULT_KEY_DIMENSION,
|
|
'MENUKEY': DEFAULT_KEY_DIMENSION,
|
|
'SPACE': (1290, HEIGHT_KEY),
|
|
}
|
|
INFO_STRING = "Modifier keys Info: [C] = Ctrl, [A] = Alt, [S] = Shift"
|
|
|
|
|
|
def createKeyboard(viewtype, filepaths):
|
|
"""
|
|
Creates a keyboard layout (.svg) file of the current configuration for a specific viewtype.
|
|
example of a viewtype is "VIEW_3D".
|
|
"""
|
|
|
|
for keyconfig in bpy.data.window_managers[0].keyconfigs:
|
|
kc_map = {}
|
|
for keymap in keyconfig.keymaps:
|
|
if keymap.space_type == viewtype:
|
|
for key in keymap.keymap_items:
|
|
if key.map_type == 'KEYBOARD':
|
|
test = 0
|
|
cont = ""
|
|
if key.ctrl:
|
|
test = test + 1
|
|
cont = "C"
|
|
if key.alt:
|
|
test = test + 2
|
|
cont = cont + "A"
|
|
if key.shift:
|
|
test = test + 4
|
|
cont = cont + "S"
|
|
if key.oskey:
|
|
test = test + 8
|
|
cont = cont + "O"
|
|
if len(cont) > 0:
|
|
cont = "[" + cont + "] "
|
|
ktype = key.type
|
|
if ktype not in kc_map:
|
|
kc_map[ktype] = []
|
|
kc_map[ktype].append((test, cont + key.name))
|
|
|
|
filename = "keyboard_%s.svg" % viewtype
|
|
export_path = os.path.join(os.path.normpath(filepaths), filename)
|
|
with open(export_path, mode="w") as svgfile:
|
|
svgfile.write("""<?xml version="1.0" standalone="no"?>
|
|
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
|
""")
|
|
svgfile.write("""<svg width="2800" height="1000" version="1.1" xmlns="http://www.w3.org/2000/svg">
|
|
""")
|
|
svgfile.write("""<style>
|
|
rect {
|
|
fill:rgb(223,235,238);
|
|
stroke-width:1;
|
|
stroke:rgb(0,0,0);
|
|
}
|
|
text.header {
|
|
font-size:xx-large;
|
|
}
|
|
text.key {
|
|
fill:rgb(0,65,100);
|
|
font-size:x-large;
|
|
stroke-width:2;
|
|
stroke:rgb(0,65,100);
|
|
}
|
|
text.action {
|
|
font-size:smaller;
|
|
}
|
|
text.add0 {
|
|
font-size:smaller;
|
|
fill:rgb(0,0,0)
|
|
}
|
|
text.add1 {
|
|
font-size:smaller;
|
|
fill:rgb(255,0,0)
|
|
}
|
|
text.add2 {
|
|
font-size:smaller;
|
|
fill:rgb(0,128,115)
|
|
}
|
|
text.add3 {
|
|
font-size:smaller;
|
|
fill:rgb(128,128,0)
|
|
}
|
|
text.add4 {
|
|
font-size:smaller;
|
|
fill:rgb(0,0,255)
|
|
}
|
|
text.add5 {
|
|
font-size:smaller;
|
|
fill:rgb(128,0,128)
|
|
}
|
|
text.add6 {
|
|
font-size:smaller;
|
|
fill:rgb(0, 128, 128)
|
|
}
|
|
text.add7 {
|
|
font-size:smaller;
|
|
fill:rgb(128,128,128)
|
|
}
|
|
text.add8 {
|
|
font-size:smaller;
|
|
fill:rgb(128,128,128)
|
|
}
|
|
text.add9 {
|
|
font-size:smaller;
|
|
fill:rgb(255,128,128)
|
|
}
|
|
text.add10 {
|
|
font-size:smaller;
|
|
fill:rgb(128,255,128)
|
|
}
|
|
text.add11 {
|
|
font-size:smaller;
|
|
fill:rgb(255,255,128)
|
|
}
|
|
text.add12 {
|
|
font-size:smaller;
|
|
fill:rgb(128,128,255)
|
|
}
|
|
text.add13 {
|
|
font-size:smaller;
|
|
fill:rgb(255,128,255)
|
|
}
|
|
text.add14 {
|
|
font-size:smaller;
|
|
fill:rgb(128,255,255)
|
|
}
|
|
text.add15 {
|
|
font-size:smaller;
|
|
fill:rgb(255,255,128)
|
|
}
|
|
</style>
|
|
""")
|
|
svgfile.write("""<text class="header" x="30" y="32">Keyboard Layout for """ + viewtype + """</text>
|
|
""")
|
|
|
|
x = 20
|
|
xgap = 20
|
|
ygap = 20
|
|
y = 48
|
|
for row in keyboard:
|
|
x = 30
|
|
for key in row:
|
|
width, height = ALTERNATIVE_KEY_DIMENSIONS.get(key, DEFAULT_KEY_DIMENSION)
|
|
tx = ceil(width * 0.2)
|
|
ty = 32
|
|
svgfile.write("""<rect x=\"""" + str(x) +
|
|
"""\" y=\"""" + str(y) +
|
|
"""\" width=\"""" + str(width) +
|
|
"""\" height=\"""" + str(height) +
|
|
"""\" rx="20" ry="20" />
|
|
""")
|
|
svgfile.write("""<text class="key" x=\"""" + str(x + tx) +
|
|
"""\" y=\"""" + str(y + ty) +
|
|
"""\" width=\"""" + str(width) +
|
|
"""\" height=\"""" + str(height) + """\">
|
|
""")
|
|
svgfile.write(key)
|
|
svgfile.write("</text>")
|
|
ty = ty + 16
|
|
tx = 4
|
|
if key in kc_map:
|
|
for a in kc_map[key]:
|
|
svgfile.write("""<text class="add""" + str(a[0]) +
|
|
"""" x=\"""" + str(x + tx) +
|
|
"""\" y=\"""" + str(y + ty) +
|
|
"""\" width=\"""" + str(width) +
|
|
"""\" height=\"""" + str(height) + """\">
|
|
""")
|
|
svgfile.write(a[1])
|
|
svgfile.write("</text>")
|
|
ty = ty + 16
|
|
x = x + width + xgap
|
|
y = y + HEIGHT_KEY + ygap
|
|
|
|
svgfile.write("""<text class="header" x="30" y="975" >""")
|
|
svgfile.write(INFO_STRING)
|
|
svgfile.write("</text>")
|
|
|
|
svgfile.write("""</svg>""")
|
|
|
|
|
|
class WM_OT_keyboardlayout(bpy.types.Operator):
|
|
bl_idname = "wm.keyboardlayout"
|
|
bl_label = "Save Shortcuts as SVG files"
|
|
bl_description = ("Export the keyboard layouts in SVG format\n"
|
|
"for each Editor in a separate file")
|
|
|
|
directory: StringProperty(
|
|
subtype='FILE_PATH',
|
|
options={'SKIP_SAVE'},
|
|
)
|
|
|
|
def invoke(self, context, event):
|
|
if not self.directory:
|
|
self.directory = ""
|
|
|
|
wm = context.window_manager
|
|
wm.fileselect_add(self)
|
|
return {'RUNNING_MODAL'}
|
|
|
|
def execute(self, context):
|
|
if not (os.path.isdir(self.directory) and os.path.exists(self.directory)):
|
|
self.report({'WARNING'},
|
|
"Chosen path is not a directory or it doesn't exist. Operation Cancelled")
|
|
return {'CANCELLED'}
|
|
|
|
# Iterate over all viewtypes to export the keyboard layout
|
|
for vt in ('VIEW_3D',
|
|
'LOGIC_EDITOR',
|
|
'NODE_EDITOR',
|
|
'CONSOLE',
|
|
'GRAPH_EDITOR',
|
|
'PROPERTIES',
|
|
'SEQUENCE_EDITOR',
|
|
'OUTLINER',
|
|
'IMAGE_EDITOR',
|
|
'TEXT_EDITOR',
|
|
'DOPESHEET_EDITOR',
|
|
'Window'):
|
|
|
|
createKeyboard(vt, self.directory)
|
|
|
|
return {'FINISHED'}
|
|
|
|
|
|
def menu_func_help(self, context):
|
|
self.layout.separator()
|
|
self.layout.operator(WM_OT_keyboardlayout.bl_idname, icon="IMGDISPLAY")
|
|
|
|
|
|
def register():
|
|
bpy.utils.register_class(WM_OT_keyboardlayout)
|
|
|
|
bpy.types.TOPBAR_MT_help.append(menu_func_help)
|
|
|
|
|
|
def unregister():
|
|
bpy.types.TOPBAR_MT_help.remove(menu_func_help)
|
|
|
|
bpy.utils.unregister_class(WM_OT_keyboardlayout)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
register()
|