Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #!/usr/bin/python
- # -*- coding: utf-8 -*-
- #-------------------------------------------------------------------------------
- # renderkeys.py
- # http://pastebin.com/jBLu3EFT
- #-------------------------------------------------------------------------------
- u'''RenderKeys outputs an SVG of a keyboard template for Thurly Wop.
- Description:
- It does what it says on the tin.
- Author:
- Daniel Neville (Blancmange), creamygoat@gmail.com
- Copyright:
- None
- Licence:
- Public domain
- INDEX
- Imports
- Exceptions:
- Error
- Helpter functions:
- Save(Data, FileName)
- HTMLEscaped(Text): string
- AttrMarkup(Attributes, PrependSpace): string
- Implementation:
- KeyboardSVG(): string
- Main:
- Main()
- '''
- #-------------------------------------------------------------------------------
- # Imports
- #-------------------------------------------------------------------------------
- from __future__ import division
- import sys
- import traceback
- import math
- from math import (
- pi, sqrt, hypot, sin, cos, tan, asin, acos, atan, atan2, radians, degrees,
- floor, ceil
- )
- #-------------------------------------------------------------------------------
- def Save(Data, FileName):
- u'''Save data to a new file.
- Data is usually a string. If a file with the given name already exists,
- it is overwritten.
- If the string is a Unicode string, it should be encoded:
- Save(Data.encode('utf_8'), FileName)
- Encoding will fail if Data is a non-Unicode string which contains a
- character outside of the 7-bit ASCII range. This can easily occur
- when an ordinary byte string contains a Latin-1 character such as
- the times symbol (“×”, code 215). Take care to prefix non-ASCII
- string constants with “u”.
- '''
- f = open(FileName, 'wb')
- try:
- f.write(Data)
- finally:
- f.close()
- #-------------------------------------------------------------------------------
- def HTMLEscaped(Text):
- u'''Return text safe to use in HTML text and in quoted attributes values.
- Using unquoted values in attribute assignments where the values can be
- chosen by an untrusted agent can lead to a script injection attack unless
- the values are very heavily sanitised. It is good practice to always wrap
- attribute values in single or double quotes.
- '''
- EntityMap = {
- '&': '&',
- '<': '<',
- '>': '>',
- '"': '"',
- "'": ''',
- '`': '`'
- }
- Result = ""
- for RawC in Text:
- SafeC = EntityMap[RawC] if RawC in EntityMap else RawC
- Result += SafeC
- return Result
- #-------------------------------------------------------------------------------
- def AttrMarkup(Attributes, PrependSpace):
- u'''Return HTML-style attribute markup from a dictionary.
- if PrependSpace is True and there is at least one attribute assignment
- generated, a space is added to the beginning of the result.
- Both an empty dictionary and None are valid values for Attributes.
- '''
- Result = ''
- if Attributes is not None:
- for Attr, Value in Attributes.items():
- if PrependSpace or (Result != ''):
- Result += ' '
- Result += HTMLEscaped(Attr) + '="' + HTMLEscaped(Value) + '"'
- return Result
- #-------------------------------------------------------------------------------
- def KeyboardSVG():
- u'''Render the key template as a string of SVG markup.'''
- LegendLayouts = [
- (
- # 0: Letter keys
- [
- [
- 'font-family="Ariel, sans-serif"',
- 'font-size="36" font-weight="normal" text-anchor="middle"'
- ]
- ],
- [[(28, 47)]]
- ),
- (
- # 1: Number and symbol keys
- [
- [
- 'font-family="Ariel, sans-serif"',
- 'font-size="28" font-weight="normal" text-anchor="start"'
- ]
- ],
- [[(22, 60)], [(22, 41), (22, 79)]]
- ),
- (
- # 2: Left-aligned special keys
- [
- [
- 'font-family="Ariel, sans-serif"',
- 'font-size="20" font-weight="normal" text-anchor="start"'
- ]
- ],
- [[(18, 56)], [(18, 44), (18, 68)], [(18, 56), (75, 44), (75, 65)]]
- ),
- (
- # 1: Numerc cluster
- [
- [
- 'font-family="Ariel, sans-serif"',
- 'font-size="28" font-weight="normal" text-anchor="start"'
- ],
- [
- 'font-family="Ariel, sans-serif"',
- 'font-size="20" font-weight="normal" text-anchor="start"'
- ]
- ],
- [[(22, 56)], [(22, 41), (22, 77)]]
- )
- ]
- Minus = u'\u2212'
- AsteriskOp = u'\u2217'
- UpArrow = u'\u2191'
- DownArrow = u'\u2193'
- LeftArrow = u'\u2190'
- RightArrow = u'\u2192'
- KeyGroups = [
- (
- 'Escape and function keys',
- (
- 'Esc',
- 'F1', 'F2', 'F3', 'F4',
- 'F5', 'F6', 'F7', 'F8',
- 'F9', 'F10','F11','F12'
- )
- ),
- (
- 'Numbers and symbols row',
- (
- 'Grave',
- '1', '2', '3', '4', '5', '6', '7', '8', '9', '0',
- 'Hyphen', 'Equals', 'Backspace'
- )
- ),
- (
- 'Top row of letters',
- (
- 'Tab',
- 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P',
- 'LBracket', 'RBracket', 'Backslash'
- )
- ),
- (
- 'Middle row of letters',
- (
- 'CapsLock',
- 'A', 'S', 'D', 'F', 'G', 'H', 'J', 'K', 'L',
- 'Semicolon', 'SingleQuote', 'Return'
- )
- ),
- (
- 'Bottom row of letters',
- (
- 'LShift',
- 'Z', 'X', 'C', 'V', 'B', 'N', 'M',
- 'Comma', 'Period', 'Slash', 'RShift'
- )
- ),
- (
- 'Space bar and qualifier keys',
- (
- 'LCtrl', 'LSys', 'LAlt',
- 'Space',
- 'RAlt', 'RSys', 'RCmd', 'RCtrl'
- )
- ),
- (
- 'Terminal keys',
- (
- 'PrintScreen', 'ScrollLock', 'Pause'
- )
- ),
- (
- 'Editing and navigation keys',
- (
- 'Insert', 'Home', 'PageUp',
- 'Delete', 'End', 'PageDown',
- 'Up',
- 'Left', 'Down', 'Right'
- )
- ),
- (
- 'Numeric cluster',
- (
- 'NumLock', 'Divide', 'Multiply', 'Subtract',
- 'N7', 'N8', 'N9', 'Add',
- 'N4', 'N5', 'N6',
- 'N1', 'N2', 'N3', 'Enter',
- 'N0', 'DecimalPoint'
- )
- )
- ]
- KeyCapData = {
- 'Esc': ((0, 0), (100, 100), (2, [u'Esc'])),
- 'F1': ((200, 0), (100, 100), (2, [u'F1'])),
- 'F2': ((300, 0), (100, 100), (2, [u'F2'])),
- 'F3': ((400, 0), (100, 100), (2, [u'F3'])),
- 'F4': ((500, 0), (100, 100), (2, [u'F4'])),
- 'F5': ((650, 0), (100, 100), (2, [u'F5'])),
- 'F6': ((750, 0), (100, 100), (2, [u'F6'])),
- 'F7': ((850, 0), (100, 100), (2, [u'F7'])),
- 'F8': ((950, 0), (100, 100), (2, [u'F8'])),
- 'F9': ((1100, 0), (100, 100), (2, [u'F9'])),
- 'F10': ((1200, 0), (100, 100), (2, [u'F10'])),
- 'F11': ((1300, 0), (100, 100), (2, [u'F11'])),
- 'F12': ((1400, 0), (100, 100), (2, [u'F12'])),
- 'Grave': ((0, 150), (100, 100), (1, [u'~', u'`'])),
- '1': ((100, 150), (100, 100), (1, [u'!', u'1'])),
- '2': ((200, 150), (100, 100), (1, [u'@', u'2'])),
- '3': ((300, 150), (100, 100), (1, [u'#', u'3'])),
- '4': ((400, 150), (100, 100), (1, [u'$', u'4'])),
- '5': ((500, 150), (100, 100), (1, [u'%', u'5'])),
- '6': ((600, 150), (100, 100), (1, [u'^', u'6'])),
- '7': ((700, 150), (100, 100), (1, [u'&', u'7'])),
- '8': ((800, 150), (100, 100), (1, [AsteriskOp, u'8'])),
- '9': ((900, 150), (100, 100), (1, [u'(', u'9'])),
- '0': ((1000, 150), (100, 100), (1, [u')', u'0'])),
- 'Hyphen': ((1100, 150), (100, 100), (1, [u'—', Minus])),
- 'Equals': ((1200, 150), (100, 100), (1, [u'+', u'='])),
- 'Backspace': ((1300, 150), (200, 100), (2, [u'\u2190 Backspace'])),
- 'Tab': ((0, 250), (150, 100), (2, [u'Tab', u'\u21e4', u'\u21e5'])),
- 'Q': ((150, 250), (100, 100), (0, [u'Q'])),
- 'W': ((250, 250), (100, 100), (0, [u'W'])),
- 'E': ((350, 250), (100, 100), (0, [u'E'])),
- 'R': ((450, 250), (100, 100), (0, [u'R'])),
- 'T': ((550, 250), (100, 100), (0, [u'T'])),
- 'Y': ((650, 250), (100, 100), (0, [u'Y'])),
- 'U': ((750, 250), (100, 100), (0, [u'U'])),
- 'I': ((850, 250), (100, 100), (0, [u'I'])),
- 'O': ((950, 250), (100, 100), (0, [u'O'])),
- 'P': ((1050, 250), (100, 100), (0, [u'P'])),
- 'LBracket': ((1150, 250), (100, 100), (1, [u'{', u'['])),
- 'RBracket': ((1250, 250), (100, 100), (1, [u'}', u']'])),
- 'Backslash': ((1350, 250), (150, 100), (1, [u'|', u'\\'])),
- 'CapsLock': ((0, 350), (175, 100), (2, [u'Caps Lock'])),
- 'A': ((175, 350), (100, 100), (0, [u'A'])),
- 'S': ((275, 350), (100, 100), (0, [u'S'])),
- 'D': ((375, 350), (100, 100), (0, [u'D'])),
- 'F': ((475, 350), (100, 100), (0, [u'F'])),
- 'G': ((575, 350), (100, 100), (0, [u'G'])),
- 'H': ((675, 350), (100, 100), (0, [u'H'])),
- 'J': ((775, 350), (100, 100), (0, [u'J'])),
- 'K': ((875, 350), (100, 100), (0, [u'K'])),
- 'L': ((975, 350), (100, 100), (0, [u'L'])),
- 'Semicolon': ((1075, 350), (100, 100), (1, [u':', u';'])),
- 'SingleQuote': ((1175, 350), (100, 100), (1, [u'"', u'\''])),
- 'Return': ((1275, 350), (225, 100), (2, [u'Enter \u21b5'])),
- 'LShift': ((0, 450), (225, 100), (2,[ u'\u21e7 Shift'])),
- 'Z': ((225, 450), (100, 100), (0, [u'Z'])),
- 'X': ((325, 450), (100, 100), (0, [u'X'])),
- 'C': ((425, 450), (100, 100), (0, [u'C'])),
- 'V': ((525, 450), (100, 100), (0, [u'V'])),
- 'B': ((625, 450), (100, 100), (0, [u'B'])),
- 'N': ((725, 450), (100, 100), (0, [u'N'])),
- 'M': ((825, 450), (100, 100), (0, [u'M'])),
- 'Comma': ((925, 450), (100, 100), (1, [u'<', u','])),
- 'Period': ((1025, 450), (100, 100), (1, [u'>', u'.'])),
- 'Slash': ((1125, 450), (100, 100), (1, [u'?', u'/'])),
- 'RShift': ((1225, 450), (275, 100), (2, [u'\u21e7 Shift'])),
- 'LCtrl': ((0, 550), (150, 100), (2, [u'Ctrl'])),
- 'LSys': ((150, 550), (100, 100), (2, [u'Sys'])),
- 'LAlt': ((250, 550), (150, 100), (2, [u'Alt'])),
- 'Space': ((400, 550), (600, 100), (0, [])),
- 'RAlt': ((1000, 550), (125, 100), (2, [u'Alt'])),
- 'RSys': ((1125, 550), (125, 100), (2, [u'Sys'])),
- 'RCmd': ((1250, 550), (125, 100), (2, [u'Cmd'])),
- 'RCtrl': ((1375, 550), (125, 100), (2, [u'Ctrl'])),
- 'PrintScreen': ((1550, 0), (100, 100), (2, [u'PrtSc', u'SysRq'])),
- 'ScrollLock': ((1650, 0), (100, 100), (2, [u'Scroll', u'Lock'])),
- 'Pause': ((1750, 0), (100, 100), (2, [u'Pause', u'Break'])),
- 'Insert': ((1550, 150), (100, 100), (2, [u'Insert'])),
- 'Delete': ((1550, 250), (100, 100), (2, [u'Delete'])),
- 'Home': ((1650, 150), (100, 100), (2, [u'Home'])),
- 'End': ((1650, 250), (100, 100), (2, [u'End'])),
- 'PageUp': ((1750, 150), (100, 100), (2, [u'Page', u'Up'])),
- 'PageDown': ((1750, 250), (100, 100), (2, [u'Page', u'Down'])),
- 'Up': ((1650, 450), (100, 100), (0, [UpArrow])),
- 'Left': ((1550, 550), (100, 100), (0, [LeftArrow])),
- 'Down': ((1650, 550), (100, 100), (0, [DownArrow])),
- 'Right': ((1750, 550), (100, 100), (0, [RightArrow])),
- 'NumLock': ((1900, 150), (100, 100), (2, [u'Num', u'Lock'])),
- 'Divide': ((2000, 150), (100, 100), (3, [u'/'])),
- 'Multiply': ((2100, 150), (100, 100), (3, [AsteriskOp])),
- 'Subtract': ((2200, 150), (100, 100), (3, [Minus])),
- 'Add': ((2200, 250), (100, 200), (3, [u'+'])),
- 'Enter': ((2200, 450), (100, 200), (2, [u'Enter'])),
- 'DecimalPoint': ((2100, 550), (100, 100), (3, [u'.', u'Del'])),
- 'N0': ((1900, 550), (200, 100), (3, [u'0', u'Ins'])),
- 'N1': ((1900, 450), (100, 100), (3, [u'1', u'End'])),
- 'N2': ((2000, 450), (100, 100), (3, [u'2', DownArrow])),
- 'N3': ((2100, 450), (100, 100), (3, [u'3', u'PgDn'])),
- 'N4': ((1900, 350), (100, 100), (3, [u'4', LeftArrow])),
- 'N5': ((2000, 350), (100, 100), (3, [u'5', u''])),
- 'N6': ((2100, 350), (100, 100), (3, [u'6', RightArrow])),
- 'N7': ((1900, 250), (100, 100), (3, [u'7', u'Home'])),
- 'N8': ((2000, 250), (100, 100), (3, [u'8', UpArrow])),
- 'N9': ((2100, 250), (100, 100), (3, [u'9', u'PgUp']))
- }
- KeySpriteNamesByDimensions = {
- (100, 100): 'key',
- (125, 100): 'keyW125',
- (150, 100): 'keyW150',
- (175, 100): 'keyW175',
- (200, 100): 'keyW200',
- (225, 100): 'keyW225',
- (275, 100): 'keyW275',
- (600, 100): 'keyW600',
- (100, 200): 'keyH200'
- }
- #-----------------------------------------------------------------------------
- def PrologueLines():
- Lines = [
- u'<?xml version="1.0" standalone="no"?>',
- u'<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"',
- u' "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">',
- u'<svg width="28cm" height="7.913043478cm" viewBox="0 0 2300 650"',
- u' preserveAspectRatio="xMidYMid meet"',
- u' xmlns="http://www.w3.org/2000/svg" version="1.1"',
- u' xmlns:xlink="http://www.w3.org/1999/xlink">',
- u'<title>Keyboard Layout</title>',
- u'<defs>',
- u' <symbol id="key" viewBox="0 0 100 100">',
- u' <rect x="5" y="5" width="90" height="90" rx="10" ry="10"/>',
- u' </symbol>',
- u' <symbol id="keyW125" viewBox="0 0 125 100">',
- u' <rect x="5" y="5" width="115" height="90" rx="10" ry="10"/>',
- u' </symbol>',
- u' <symbol id="keyW150" viewBox="0 0 150 100">',
- u' <rect x="5" y="5" width="140" height="90" rx="10" ry="10"/>',
- u' </symbol>',
- u' <symbol id="keyW175" viewBox="0 0 175 100">',
- u' <rect x="5" y="5" width="165" height="90" rx="10" ry="10"/>',
- u' </symbol>',
- u' <symbol id="keyW200" viewBox="0 0 200 100">',
- u' <rect x="5" y="5" width="190" height="90" rx="10" ry="10"/>',
- u' </symbol>',
- u' <symbol id="keyW225" viewBox="0 0 225 100">',
- u' <rect x="5" y="5" width="215" height="90" rx="10" ry="10"/>',
- u' </symbol>',
- u' <symbol id="keyW275" viewBox="0 0 275 100">',
- u' <rect x="5" y="5" width="265" height="90" rx="10" ry="10"/>',
- u' </symbol>',
- u' <symbol id="keyW600" viewBox="0 0 600 100">',
- u' <rect x="5" y="5" width="590" height="90" rx="10" ry="10"/>',
- u' </symbol>',
- u' <symbol id="keyH200" viewBox="0 0 100 200">',
- u' <rect x="5" y="5" width="90" height="190" rx="10" ry="10"/>',
- u' </symbol>',
- u'</defs>',
- u'',
- u'<!-- Background -->',
- u'<rect x="0" y="0" width="2300" height="650" ' +
- u'stroke="none" fill="silver"/>',
- u'',
- ]
- return Lines
- #-----------------------------------------------------------------------------
- def EpilogueLines():
- Lines = [
- u'',
- u'</svg>'
- ]
- return Lines
- #-----------------------------------------------------------------------------
- def BodyLines():
- Lines = []
- DefaultLL = LegendLayouts[0]
- Lines.append(u'<g stroke-width="5" stroke="black" fill="white"')
- for Str in DefaultLL[0][0]:
- Lines.append(u' ' + Str)
- Lines[-1] += '>'
- Lines.append(u'')
- for GIx, GroupData in enumerate(KeyGroups):
- GroupDesc, Keys = GroupData
- Lines.append(u'<!-- ' + GroupDesc + '-->')
- Lines.append(u'')
- for KIx, Key in enumerate(Keys):
- if Key in KeyCapData:
- KCData = KeyCapData[Key]
- Pos, Size, LegendData = KCData
- LegendStyleIx, LegendStrs = LegendData
- LL = LegendLayouts[LegendStyleIx]
- PosStr = u'%g, %g' % (Pos[0], Pos[1])
- WHStr = u'width="%g" height="%g"' % (Size[0], Size[1])
- SpriteName = KeySpriteNamesByDimensions[Size]
- Lines.append(u' <!-- ' + Key + ' -->')
- Lines.append(u' <g transform="translate(' + PosStr + u')"')
- if LegendStyleIx != 0:
- for Str in LL[0][0]:
- Lines.append(u' ' + Str)
- Lines[-1] += '>'
- Lines.append(u' <use x="0" y="0" ' + WHStr +
- ' xlink:href="#' + SpriteName + '"/>')
- if LegendStrs != []:
- LegendPositions = LL[1][len(LegendStrs) - 1]
- for LIx, Legend in enumerate(LegendStrs):
- AttrsIx = min(LIx, len(LL[0]) - 1)
- Attrs = LL[0][AttrsIx]
- LegendPos = LegendPositions[LIx]
- if Size[1] > 100:
- LegendPos = (LegendPos[0], LegendPos[1] + 50)
- LegendPosStr = u'x="%g" y="%g"' % (LegendPos[0], LegendPos[1])
- TextCmdStr = (u' <text ' + LegendPosStr +
- ' fill="black" stroke="none">' +
- HTMLEscaped(Legend) +
- u'</text>')
- if AttrsIx > 0:
- Lines.append(u' <g')
- if len(Attrs) > 0:
- Lines[-1] += u' ' + Attrs[0]
- for Str in Attrs[1:]:
- Lines.append(u' ' + Str)
- Lines[-1] += '>'
- Lines.append(u' ' + TextCmdStr)
- Lines.append(u' </g>')
- else:
- Lines.append(TextCmdStr)
- Lines.append(u' </g>')
- Lines.append(u'')
- Lines.append(u'</g>')
- Lines.append(u'')
- return Lines
- #-----------------------------------------------------------------------------
- Lines = []
- Lines += PrologueLines();
- Lines += BodyLines();
- Lines += EpilogueLines();
- Lines.append('')
- return '\n'.join(Lines)
- #-------------------------------------------------------------------------------
- # Main
- #-------------------------------------------------------------------------------
- def Main():
- Result = 0
- ErrMsg = ''
- OutputFileName = 'Keys.svg'
- S = ''
- try:
- S = KeyboardSVG()
- Save(S.encode('utf_8'), OutputFileName)
- except (Exception), E:
- exc_type, exc_value, exc_traceback = sys.exc_info()
- ErrLines = traceback.format_exc().splitlines()
- ErrMsg = 'Unhandled exception:\n' + '\n'.join(ErrLines)
- Result = 3
- if ErrMsg != '':
- print >> sys.stderr, sys.argv[0] + ': ' + ErrMsg
- return Result
- #-------------------------------------------------------------------------------
- # Command line trigger
- #-------------------------------------------------------------------------------
- if __name__ == '__main__':
- sys.exit(Main())
- #-------------------------------------------------------------------------------
- # End
- #-------------------------------------------------------------------------------
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement