def _load_svg_keys(self, filename): filename = os.path.join(self._root_layout_dir, filename) try: with open_utf8(filename) as svg_file: svg_dom = minidom.parse(svg_file).documentElement svg_nodes = self._parse_svg(svg_dom) svg_nodes = {node.id: node for node in svg_nodes} except Exceptions.LayoutFileError as ex: raise Exceptions.LayoutFileError( "error loading '{}'".format(filename), chained_exception=(ex)) return svg_nodes
def _load_svg_keys(self, filename): filename = os.path.join(self._root_layout_dir, filename) try: with open_utf8(filename) as svg_file: svg_dom = minidom.parse(svg_file).documentElement svg_keys = self._parse_svg(svg_dom) except Exception as xxx_todo_changeme1: (exception) = xxx_todo_changeme1 raise Exceptions.LayoutFileError(_("Error loading ") + filename, chained_exception=exception) return svg_keys
def _parse_key_template(self, node, parent): """ Templates are partially define layout items. Later non-template items inherit attributes of templates with matching id. """ attributes = dict(list(node.attributes.items())) id = attributes.get("id") if not id: raise Exceptions.LayoutFileError( "'id' attribute required for template '{} {}' " "in layout '{}'" \ .format(tag, str(list(attributes.values())), self._layout_filename)) parent.update_templates({(id, RectKey): attributes})
def _parse_svg(self, node): svg_nodes = [] for child in node.childNodes: if child.nodeType == minidom.Node.ELEMENT_NODE: tag = child.tagName if tag in ("rect", "path", "g"): svg_node = SVGNode() id = child.attributes["id"].value svg_node.id = id if tag == "rect": svg_node.bounds = \ Rect(float(child.attributes['x'].value), float(child.attributes['y'].value), float(child.attributes['width'].value), float(child.attributes['height'].value)) elif tag == "path": data = child.attributes['d'].value try: svg_node.path = KeyPath.from_svg_path(data) except ValueError as ex: raise Exceptions.LayoutFileError( "while reading geometry with id '{}'".format( id), chained_exception=(ex)) svg_node.bounds = svg_node.path.get_bounds() elif tag == "g": # group svg_node.children = self._parse_svg(child) svg_nodes.append(svg_node) svg_nodes.extend(self._parse_svg(child)) return svg_nodes
def copy_layout(src_filename, dst_filename): src_dir = os.path.dirname(src_filename) dst_dir, name_ext = os.path.split(dst_filename) dst_basename, ext = os.path.splitext(name_ext) _logger.info( _format("copying layout '{}' to '{}'", src_filename, dst_filename)) domdoc = None svg_filenames = {} fallback_layers = {} try: with open_utf8(src_filename) as f: domdoc = minidom.parse(f) keyboard_node = domdoc.documentElement # check layout format format = LayoutLoaderSVG.LAYOUT_FORMAT_LEGACY if keyboard_node.hasAttribute("format"): format = Version.from_string( keyboard_node.attributes["format"].value) keyboard_node.attributes["id"] = dst_basename if format < LayoutLoaderSVG.LAYOUT_FORMAT_LAYOUT_TREE: raise Exceptions.LayoutFileError( \ _format("copy_layouts failed, unsupported layout format '{}'.", format)) else: # replace the basename of all svg filenames for node in LayoutLoaderSVG._iter_dom_nodes(keyboard_node): if LayoutLoaderSVG.is_layout_node(node): if node.hasAttribute("filename"): filename = node.attributes["filename"].value # Create a replacement layer name for the unlikely # case that the svg-filename doesn't contain a # layer section (as in path/basename-layer.ext). fallback_layer_name = fallback_layers.get( filename, "Layer" + str(len(fallback_layers))) fallback_layers[filename] = fallback_layer_name # replace the basename of this filename new_filename = LayoutLoaderSVG._replace_basename( \ filename, dst_basename, fallback_layer_name) node.attributes[ "filename"].value = new_filename svg_filenames[filename] = new_filename if domdoc: XDGDirs.assure_user_dir_exists(config.get_user_layout_dir()) # write the new layout file with open_utf8(dst_filename, "w") as f: xml = toprettyxml(domdoc) if sys.version_info.major == 2: # python 2? xml = xml.encode("UTF-8") f.write(xml) # copy the svg files for src, dst in list(svg_filenames.items()): dir, name = os.path.split(src) if not dir: src = os.path.join(src_dir, name) dir, name = os.path.split(dst) if not dir: dst = os.path.join(dst_dir, name) _logger.info(_format("copying svg file '{}' to '{}'", \ src, dst)) shutil.copyfile(src, dst) except OSError as ex: _logger.error("copy_layout failed: " + \ unicode_str(ex)) except Exceptions.LayoutFileError as ex: _logger.error(unicode_str(ex))
def _init_key(self, key, attributes): # Re-parse the id to distinguish between the short key_id # and the optional longer theme_id. full_id = attributes["id"] theme_id = attributes.get("theme_id") svg_id = attributes.get("svg_id") key.set_id(full_id, theme_id, svg_id) if "_" in key.get_id(): _logger.warning("underscore in key id '{}', please use dashes" \ .format(key.get_id())) value = attributes.get("modifier") if value: try: key.modifier = modifiers[value] except KeyError as ex: (strerror) = ex raise Exceptions.LayoutFileError("Unrecognized modifier %s in" \ "definition of %s" (strerror, full_id)) value = attributes.get("action") if value: try: key.action = KeyCommon.actions[value] except KeyError as ex: (strerror) = ex raise Exceptions.LayoutFileError("Unrecognized key action {} in" \ "definition of {}".format(strerror, full_id)) if "char" in attributes: key.code = attributes["char"] key.type = KeyCommon.CHAR_TYPE elif "keysym" in attributes: value = attributes["keysym"] key.type = KeyCommon.KEYSYM_TYPE if value[1] == "x": #Deals for when keysym is hex key.code = int(value, 16) else: key.code = int(value, 10) elif "keypress_name" in attributes: key.code = attributes["keypress_name"] key.type = KeyCommon.KEYPRESS_NAME_TYPE elif "macro" in attributes: key.code = attributes["macro"] key.type = KeyCommon.MACRO_TYPE elif "script" in attributes: key.code = attributes["script"] key.type = KeyCommon.SCRIPT_TYPE elif "keycode" in attributes: key.code = int(attributes["keycode"]) key.type = KeyCommon.KEYCODE_TYPE elif "button" in attributes: key.code = key.id[:] key.type = KeyCommon.BUTTON_TYPE elif key.modifier: key.code = None key.type = KeyCommon.LEGACY_MODIFIER_TYPE else: # key without action: just draw it, do nothing on click key.action = None key.action_type = None # get the size group of the key if "group" in attributes: group_name = attributes["group"] else: group_name = "_default" # get the optional image filename if "image" in attributes: if not key.image_filenames: key.image_filenames = {} key.image_filenames[ImageSlot.NORMAL] = attributes["image"].split( ";")[0] if "image_active" in attributes: if not key.image_filenames: key.image_filenames = {} key.image_filenames[ImageSlot.ACTIVE] = attributes["image_active"] # get labels labels = self._parse_key_labels(attributes, key) # Replace label and size group with overrides from # theme and/or system defaults. label_overrides = config.theme_settings.key_label_overrides override = label_overrides.get(key.id) if override: olabel, ogroup = override if olabel: labels = {0: olabel[:]} if ogroup: group_name = ogroup[:] key.labels = labels key.group = group_name # optionally override the theme's default key_style if "key_style" in attributes: key.style = attributes["key_style"] # select what gets drawn, different from "visible" flag as this # doesn't affect the layout. if "show" in attributes: if attributes["show"].lower() == 'false': key.show_face = False key.show_border = False if "show_face" in attributes: if attributes["show_face"].lower() == 'false': key.show_face = False if "show_border" in attributes: if attributes["show_border"].lower() == 'false': key.show_border = False # show_active: allow to display key in latched or locked state # legacy show_active behavior was hard-coded for layer0 if self._format < LayoutLoaderSVG.LAYOUT_FORMAT_3_2: if key.id == "layer0": key.show_active = False if "show_active" in attributes: if attributes["show_active"].lower() == 'false': key.show_active = False if "label_x_align" in attributes: key.label_x_align = float(attributes["label_x_align"]) if "label_y_align" in attributes: key.label_y_align = float(attributes["label_y_align"]) if "label_margin" in attributes: values = attributes["label_margin"].replace(" ", "").split(",") margin = [float(x) if x else key.label_margin[i] \ for i, x in enumerate(values[:2])] margin += margin[:1] * (2 - len(margin)) if margin: key.label_margin = margin if "sticky" in attributes: sticky = attributes["sticky"].lower() if sticky == "true": key.sticky = True elif sticky == "false": key.sticky = False else: raise Exceptions.LayoutFileError( "Invalid value '{}' for 'sticky' attribute of key '{}'" \ .format(sticky, key.id)) else: key.sticky = False # legacy sticky key behavior was hard-coded for CAPS if self._format < LayoutLoaderSVG.LAYOUT_FORMAT_2_2: if key.id == "CAPS": key.sticky_behavior = StickyBehavior.LOCK_ONLY value = attributes.get("sticky_behavior") if value: try: key.sticky_behavior = StickyBehavior.from_string(value) except KeyError as ex: (strerror) = ex raise Exceptions.LayoutFileError("Unrecognized sticky behavior {} in" \ "definition of {}".format(strerror, full_id)) if "tooltip" in attributes: key.tooltip = attributes["tooltip"] if "popup_id" in attributes: key.popup_id = attributes["popup_id"] if "chamfer_size" in attributes: key.chamfer_size = float(attributes["chamfer_size"]) key.color_scheme = self._color_scheme