def set_stroke(self, dc, svg_stroke, line_width=1.0, linecap='butt', dasharray=None): #Patch to avoid to have too dim lines for staff, bar, note stems if line_width < 1: line_width = 1.0 #End Patch if dasharray: # convert from something like "5,5" to (5,5) dasharray = tuple([int(x.strip()) for x in dasharray.split(',')]) # 1.3.6.3 [JWDJ] 2015-3 search cache once instead of twice key = (svg_stroke, line_width, dasharray) pen = self.stroke_cache.get(key) if pen is None: if svg_stroke == 'none': if WX41: pen = self.renderer.CreatePen(wx.GraphicsPenInfo(style=wx.PENSTYLE_TRANSPARENT)) else: pen = self.renderer.CreatePen(wx.NullPen) else: if WX41: wxpen = wx.GraphicsPenInfo(wx_colour(svg_stroke)).Width(line_width) if linecap == 'butt': wxpen.Cap(wx.CAP_BUTT) elif linecap == 'round': wxpen.Cap(wx.CAP_ROUND) else: raise Exception('linecap %s not supported yet' % linecap) # if dasharray: # # 1.3.6.3 [JWDJ] 2015-3 dasharray is always a tuple, never a str or unicode # #if type(dasharray) in (str, unicode): # # dasharray = [int(x.strip()) for x in dasharray.split(',')] # wxpen.Dashes(list(dasharray)) # wxpen.Style(wx.USER_DASH) wxpen.Join(wx.JOIN_MITER) else: wxpen = wx.Pen(wx_colour(svg_stroke), line_width) if linecap == 'butt': wxpen.SetCap(wx.CAP_BUTT) elif linecap == 'round': wxpen.SetCap(wx.CAP_ROUND) else: raise Exception('linecap %s not supported yet' % linecap) if dasharray: # 1.3.6.3 [JWDJ] 2015-3 dasharray is always a tuple, never a str or unicode #if type(dasharray) in (str, unicode): # dasharray = [int(x.strip()) for x in dasharray.split(',')] wxpen.SetDashes(list(dasharray)) wxpen.SetStyle(wx.USER_DASH) wxpen.SetJoin(wx.JOIN_MITER) pen = self.renderer.CreatePen(wxpen) self.stroke_cache[key] = pen dc.SetPen(pen)
def draw_drag_rect(self, dc): if self.drag_rect: dc = wx.GraphicsContext.Create(dc) #z = self.renderer.zoom #dc.Scale(z, z) x, y, width, height = self.drag_rect dc.SetPen( dc.CreatePen(wx.Pen(wx_colour('black'), 1.0, style=wx.DOT )) ) dc.SetBrush(dc.CreateBrush(wx.Brush(wx_colour('#fffbc6'), wx.SOLID))) path = dc.CreatePath() path.MoveToPoint(x, y) path.AddLineToPoint(x+width, y) path.AddLineToPoint(x+width, y+height) path.AddLineToPoint(x, y+height) path.AddLineToPoint(x, y) dc.DrawPath(path)
def set_stroke(self, dc, svg_stroke, line_width=1.0, linecap='butt', dasharray=None): #Patch to avoid to have too dim lines for staff, bar, note stems if line_width < 1: line_width = 1.0 #End Patch if dasharray: # convert from something like "5,5" to (5,5) dasharray = tuple([int(x.strip()) for x in dasharray.split(',')]) # 1.3.6.3 [JWDJ] 2015-3 search cache once instead of twice key = (svg_stroke, line_width, dasharray) pen = self.stroke_cache.get(key) if pen is None: if svg_stroke == 'none': pen = self.renderer.CreatePen(wx.NullPen) else: wxpen = wx.Pen(wx_colour(svg_stroke), line_width) if linecap == 'butt': wxpen.SetCap(wx.CAP_BUTT) elif linecap == 'round': wxpen.SetCap(wx.CAP_ROUND) else: raise Exception('linecap %s not supported yet' % linecap) if dasharray: # 1.3.6.3 [JWDJ] 2015-3 dasharray is always a tuple, never a str or unicode #if type(dasharray) in (str, unicode): # dasharray = [int(x.strip()) for x in dasharray.split(',')] wxpen.SetDashes(list(dasharray)) wxpen.SetStyle(wx.USER_DASH) wxpen.SetJoin(wx.JOIN_MITER) pen = self.renderer.CreatePen(wxpen) self.stroke_cache[key] = pen dc.SetPen(pen)
def draw_drag_rect(self, dc): if self.drag_rect: dc = wx.GraphicsContext.Create(dc) #z = self.renderer.zoom #dc.Scale(z, z) x, y, width, height = self.drag_rect dc.SetPen( dc.CreatePen(wx.Pen(wx_colour('black'), 1.0, style=wx.DOT))) dc.SetBrush( dc.CreateBrush(wx.Brush(wx_colour('#fffbc6'), wx.SOLID))) path = dc.CreatePath() path.MoveToPoint(x, y) path.AddLineToPoint(x + width, y) path.AddLineToPoint(x + width, y + height) path.AddLineToPoint(x, y + height) path.AddLineToPoint(x, y) dc.DrawPath(path)
def set_fill(self, dc, svg_fill): # 1.3.6.3 [JWDJ] 2015-3 search cache once instead of twice brush = self.fill_cache.get(svg_fill) if brush is None: if svg_fill == 'none': brush = self.renderer.CreateBrush(wx.NullBrush) elif svg_fill == 'white': brush = self.renderer.CreateBrush(wx.WHITE_BRUSH) elif svg_fill == 'black': brush = self.renderer.CreateBrush(wx.BLACK_BRUSH) elif svg_fill.startswith('#'): # 1.3.6.2 [JWdJ] 2015-02-12 Added voicecolor brush = self.renderer.CreateBrush(wx.Brush(svg_fill, wx.SOLID)) else: brush = self.renderer.CreateBrush(wx.Brush(wx_colour(svg_fill), wx.SOLID)) self.fill_cache[svg_fill] = brush dc.SetBrush(brush)
def draw_svg_element(self, page, dc, svg_element, highlight, current_color): ''' This is the main engine for converting the svg items in the svg file into graphics displayed in the music pane. The book SVG Essentials by J. David Eisenberg describes all the elements used (eg. g, use, ellipse, ...) In addition there is an item <abc> which contains annotation and information for matching the graphics element with the note in the abc file. The <abc> element id indicates the type of object. (N - notes, R - rest, B - bar line, b - beam joining notes, e - note flag, M - time signature, K - key signature, 'c' octave shift in clef) ''' name = svg_element.name if name == 'defs': return attr = svg_element.attributes transform = attr.get('transform') if transform: dc.PushState() self.do_transform(dc, transform) # 1.3.6.2 [JWdJ] 2015-02-12 Added voicecolor if name == 'g': style = attr.get('style') if style: m = self.color_re.match(style) if m: current_color = m.group(1).upper() # 1.3.6.2 [JWdJ] 2015-02-14 Only 'g' and 'defs' have children for child in svg_element.children: self.draw_svg_element(page, dc, child, highlight, current_color) # if something is going to be drawn, prepare else: # 1.3.6.3 [JWDJ] 2015-3 Only set fill if fill is specified (where 'none' is not the same as None) fill = attr.get('fill') if fill is None and name == 'circle': fill = current_color # 1.3.6.4 To draw the two dots in !segno! if fill is not None: if fill == 'currentColor': fill = current_color if highlight and fill != 'none': fill = self.highlight_color self.set_fill(dc, fill) stroke = attr.get('stroke', 'none') if stroke == 'currentColor': stroke = current_color if highlight and stroke != 'none': stroke = self.highlight_color self.set_stroke(dc, stroke, float(attr.get('stroke-width', 1.0)), attr.get('stroke-linecap', 'butt'), attr.get('stroke-dasharray', None)) #print 'setmatrix', matrix.Get(), '[%s]' % attr.get('transform', '') # 1.3.6.2 [JWdJ] 2015-02-14 Process most common names first (path, ellipse, use) if name == 'path': path = self.parse_path(attr['d']) #Patch from Seymour regarding Debian 7.0 to be tested on other platform #if wx.Platform != "__WXMAC__": #At least the SetPen has some side effect on Mac didn't tried on other. So do not apply Seymour Patch if under Mac # dc.SetPen(wx.Pen('#000000', 1, wx.SOLID)) #End of patch dc.DrawPath(path, wx.WINDING_RULE) elif name == 'use': x, y = float(attr.get('x', 0)), float(attr.get('y', 0)) element_id = attr[href_tag][1:] # abcm2ps specific: desc = attr.get('desc') if desc: user_x, user_y = self.transform_point(dc, x, y) abc_row, abc_col = desc[1], desc[2] page.notes.append((user_x, user_y, abc_row, abc_col, desc)) note_index = len(page.notes) - 1 if note_index in page.selected_indices: highlight = True dc.PushState() dc.Translate(x, y) self.draw_svg_element(page, dc, page.id_to_element[element_id], highlight, current_color) if desc: page.note_draw_info.append( (element_id, current_color, dc.GetTransform().Get())) dc.PopState() elif name == 'ellipse': cx, cy, rx, ry = attr.get('cx', 0), attr.get('cy', 0), attr['rx'], attr['ry'] cx, cy, rx, ry = map(float, (cx, cy, rx, ry)) path = dc.CreatePath() path.AddEllipse(cx - rx, cy - ry, rx + rx, ry + ry) dc.DrawPath(path) elif name == 'circle': cx, cy, r = map(float, (attr.get('cx', 0), attr.get('cy', 0), attr['r'])) path = dc.CreatePath() path.AddCircle(cx, cy, r) dc.DrawPath(path) elif name == 'text': text = attr['text'] if not self.can_draw_sharps_and_flats: text = text.replace(u'\u266d', 'b').replace(u'\u266f', '#').replace(u'\u266e', '=') x, y = float(attr.get('x', 0)), float(attr.get('y', 0)) if attr.get('font-style') == 'italic': style = wx.FONTSTYLE_ITALIC else: style = wx.FONTSTYLE_NORMAL if attr.get('font-weight') == 'bold': weight = wx.FONTWEIGHT_BOLD else: weight = wx.FONTWEIGHT_NORMAL font_size = int(round(float(attr.get('font-size', 12)) * 1)) # 1.3.6.3 [JWDJ] 2015-3 bugfix: use correct font family font_face = '' svg_to_wx_font_family = { 'serif': wx.FONTFAMILY_ROMAN, 'sans-serif': wx.FONTFAMILY_SWISS, 'monospace': wx.FONTFAMILY_MODERN, 'bookman': wx.FONTFAMILY_ROMAN, 'sans': wx.FONTFAMILY_SWISS, # should be 'sans-serif' (abcm2ps bug?) } svg_font_family = attr.get('font-family', 'serif').lower() font_family = svg_to_wx_font_family.get(svg_font_family) if font_family is None: font_family = wx.FONTFAMILY_DEFAULT font_face = svg_font_family # 1.3.6.4 [JWDJ] if font family is not known then assume it is a font face ##print repr(text), font_face, attr.get('font-size'), attr.get('font-weight') wxfont = wx.Font(font_size, font_family, style, weight, False, font_face, wx.FONTENCODING_DEFAULT) if '__WXMSW__' in wx.PlatformInfo: wxfont.SetPixelSize((font_size, font_size)) y += 1 else: wxfont.SetPointSize(font_size) font = dc.CreateFont(wxfont, wx_colour(attr.get('fill', 'black'))) dc.SetFont(font) (width, height, descent, externalLeading) = dc.GetFullTextExtent(text) if attr.get('text-anchor') == 'middle': x -= width / 2 elif attr.get('text-anchor') == 'end': x -= width try: dc.DrawText(text, x, y - height + descent) except wx.PyAssertionError: raise Exception( u'Could not draw text, text=%s, font=%s (%s / %s), size=%s, fill=%s, weight=%s, style=%s, x=%s, y=%s, height=%s, descent=%s, transform=%s' % (repr(text), font_face, wxfont.GetFaceName(), wxfont.GetDefaultEncoding(), font_size, attr.get('fill', 'black'), attr.get('font-weight', '<none>'), attr.get('font-style', '<none>'), x, y, height, descent, dc.GetTransform().Get())) elif name == 'rect': x, y, width, height = attr.get('x', 0), attr.get( 'y', 0), attr['width'], attr['height'] if '%' in width: # 1.3.6.2 [JWdJ] 2015-02-12 Added for %%bgcolor if width == height == '100%': x, y, width, height = map(float, (0, 0, self.buffer.GetWidth(), self.buffer.GetHeight())) else: return else: x, y, width, height = map(float, (x, y, width, height)) path = dc.CreatePath() path.MoveToPoint(x, y) path.AddLineToPoint(x + width, y) path.AddLineToPoint(x + width, y + height) path.AddLineToPoint(x, y + height) path.AddLineToPoint(x, y) dc.DrawPath(path) elif name == 'line': x1, y1, x2, y2 = map( float, (attr['x1'], attr['y1'], attr['x2'], attr['y2'])) # 1.3.6.3 [JWDJ] 2015-3 Fill and stroke already have been set # self.set_fill(dc, 'none') # self.set_stroke(dc, stroke, float(attr.get('stroke-width', 1.0)), attr.get('stroke-linecap', 'butt'), attr.get('stroke-dasharray', None)) # 1.3.6.3 [JWDJ] 2015-3 Fixes line in !segno! dc.DrawLines([(x1, y1), (x2, y2)]) if transform: dc.PopState()
def draw_svg_element(self, page, dc, svg_element, highlight, current_color): ''' This is the main engine for converting the svg items in the svg file into graphics displayed in the music pane. The book SVG Essentials by J. David Eisenberg describes all the elements used (eg. g, use, ellipse, ...) In addition there is an item <abc> which contains annotation and information for matching the graphics element with the note in the abc file. The <abc> element id indicates the type of object. (N - notes, R - rest, B - bar line, b - beam joining notes, e - note flag, M - time signature, K - key signature, 'c' octave shift in clef) ''' name = svg_element.name if name == 'defs': return attr = svg_element.attributes transform = attr.get('transform') if transform: dc.PushState() self.do_transform(dc, transform) # 1.3.6.2 [JWdJ] 2015-02-12 Added voicecolor if name == 'g': style = attr.get('style') if style: m = self.color_re.match(style) if m: current_color = m.group(1).upper() # 1.3.6.2 [JWdJ] 2015-02-14 Only 'g' and 'defs' have children for child in svg_element.children: self.draw_svg_element(page, dc, child, highlight, current_color) # if something is going to be drawn, prepare else: # 1.3.6.3 [JWDJ] 2015-3 Only set fill if fill is specified (where 'none' is not the same as None) fill = attr.get('fill') if fill is None and name == 'circle': fill = current_color # 1.3.6.4 To draw the two dots in !segno! if fill is not None: if fill == 'currentColor': fill = current_color if highlight and fill != 'none': fill = self.highlight_color self.set_fill(dc, fill) stroke = attr.get('stroke', 'none') if stroke == 'currentColor': stroke = current_color if highlight and stroke != 'none': stroke = self.highlight_color self.set_stroke(dc, stroke, float(attr.get('stroke-width', 1.0)), attr.get('stroke-linecap', 'butt'), attr.get('stroke-dasharray', None)) #print 'setmatrix', matrix.Get(), '[%s]' % attr.get('transform', '') # 1.3.6.2 [JWdJ] 2015-02-14 Process most common names first (path, ellipse, use) if name == 'path': path = self.parse_path(attr['d']) #Patch from Seymour regarding Debian 7.0 to be tested on other platform #if wx.Platform != "__WXMAC__": #At least the SetPen has some side effect on Mac didn't tried on other. So do not apply Seymour Patch if under Mac # dc.SetPen(wx.Pen('#000000', 1, wx.SOLID)) #End of patch dc.DrawPath(path, wx.WINDING_RULE) elif name == 'use': x, y = float(attr.get('x', 0)), float(attr.get('y', 0)) element_id = attr[href_tag][1:] # abcm2ps specific: desc = attr.get('desc') if desc: user_x, user_y = self.transform_point(dc, x, y) abc_row, abc_col = desc[1], desc[2] page.notes.append((user_x, user_y, abc_row, abc_col, desc)) note_index = len(page.notes)-1 if note_index in page.selected_indices: highlight = True dc.PushState() dc.Translate(x, y) self.draw_svg_element(page, dc, page.id_to_element[element_id], highlight, current_color) if desc: page.note_draw_info.append((element_id, current_color, dc.GetTransform().Get())) dc.PopState() elif name == 'ellipse': cx, cy, rx, ry = attr.get('cx', 0), attr.get('cy', 0), attr['rx'], attr['ry'] cx, cy, rx, ry = map(float, (cx, cy, rx, ry)) path = dc.CreatePath() path.AddEllipse(cx-rx, cy-ry, rx+rx, ry+ry) dc.DrawPath(path) elif name == 'circle': cx, cy, r = map(float, (attr.get('cx', 0), attr.get('cy', 0), attr['r'])) path = dc.CreatePath() path.AddCircle(cx, cy, r) dc.DrawPath(path) elif name == 'text': text = attr['text'] if not self.can_draw_sharps_and_flats: text = text.replace(u'\u266d', 'b').replace(u'\u266f', '#').replace(u'\u266e', '=') x, y = float(attr.get('x', 0)), float(attr.get('y', 0)) if attr.get('font-style') == 'italic': style = wx.FONTSTYLE_ITALIC else: style = wx.FONTSTYLE_NORMAL if attr.get('font-weight') == 'bold': weight = wx.FONTWEIGHT_BOLD else: weight = wx.FONTWEIGHT_NORMAL font_size = int(round(float(attr.get('font-size', 12))*1)) # 1.3.6.3 [JWDJ] 2015-3 bugfix: use correct font family font_face = '' svg_to_wx_font_family = { 'serif': wx.FONTFAMILY_ROMAN, 'sans-serif': wx.FONTFAMILY_SWISS, 'monospace': wx.FONTFAMILY_MODERN, 'bookman': wx.FONTFAMILY_ROMAN, 'sans': wx.FONTFAMILY_SWISS, # should be 'sans-serif' (abcm2ps bug?) } svg_font_family = attr.get('font-family', 'serif').lower() font_family = svg_to_wx_font_family.get(svg_font_family) if font_family is None: font_family = wx.FONTFAMILY_DEFAULT font_face = svg_font_family # 1.3.6.4 [JWDJ] if font family is not known then assume it is a font face ##print repr(text), font_face, attr.get('font-size'), attr.get('font-weight') wxfont = wx.Font(font_size, font_family, style, weight, False, font_face, wx.FONTENCODING_DEFAULT) if wx.VERSION >= (3, 0) or '__WXMSW__' in wx.PlatformInfo: wxfont.SetPixelSize((font_size, font_size)) y += 1 else: wxfont.SetPointSize(font_size) font = dc.CreateFont(wxfont, wx_colour(attr.get('fill', 'black'))) dc.SetFont(font) (width, height, descent, externalLeading) = dc.GetFullTextExtent(text) if attr.get('text-anchor') == 'middle': x -= width / 2 elif attr.get('text-anchor') == 'end': x -= width try: dc.DrawText(text, x, y-height+descent) except wx.PyAssertionError: raise Exception(u'Could not draw text, text=%s, font=%s (%s / %s), size=%s, fill=%s, weight=%s, style=%s, x=%s, y=%s, height=%s, descent=%s, transform=%s' % (repr(text), font_face, wxfont.GetFaceName(), wxfont.GetDefaultEncoding(), font_size, attr.get('fill', 'black'), attr.get('font-weight', '<none>'), attr.get('font-style', '<none>'), x, y, height, descent, dc.GetTransform().Get())) elif name == 'rect': x, y, width, height = attr.get('x', 0), attr.get('y', 0), attr['width'], attr['height'] if '%' in width: # 1.3.6.2 [JWdJ] 2015-02-12 Added for %%bgcolor if width == height == '100%': x, y, width, height = map(float, (0, 0, self.buffer.GetWidth(), self.buffer.GetHeight())) else: return else: x, y, width, height = map(float, (x, y, width, height)) path = dc.CreatePath() path.MoveToPoint(x, y) path.AddLineToPoint(x+width, y) path.AddLineToPoint(x+width, y+height) path.AddLineToPoint(x, y+height) path.AddLineToPoint(x, y) dc.DrawPath(path) elif name == 'line': x1, y1, x2, y2 = map(float, (attr['x1'], attr['y1'], attr['x2'], attr['y2'])) # 1.3.6.3 [JWDJ] 2015-3 Fill and stroke already have been set # self.set_fill(dc, 'none') # self.set_stroke(dc, stroke, float(attr.get('stroke-width', 1.0)), attr.get('stroke-linecap', 'butt'), attr.get('stroke-dasharray', None)) # 1.3.6.3 [JWDJ] 2015-3 Fixes line in !segno! dc.DrawLines([(x1, y1), (x2, y2)]) if transform: dc.PopState()