From a65dc70e71b3e0c58cea40cd3867c7f51bc0a92b Mon Sep 17 00:00:00 2001 From: John Wiggins Date: Tue, 2 Mar 2021 12:01:36 +0100 Subject: [PATCH 1/6] Use a common signature for select_font() --- kiva/celiagg.py | 6 +++--- kiva/pdf.py | 11 ++++++++++- kiva/qpainter.py | 12 ++++++++---- kiva/quartz/ABCGI.pyx | 4 ++-- 4 files changed, 23 insertions(+), 10 deletions(-) diff --git a/kiva/celiagg.py b/kiva/celiagg.py index c88829400..3e6d89dc1 100644 --- a/kiva/celiagg.py +++ b/kiva/celiagg.py @@ -608,15 +608,15 @@ def normalize_image(img): # Drawing Text # ---------------------------------------------------------------- - def select_font(self, name, size, textEncoding): + def select_font(self, face_name, size=12, style='regular', encoding=None): """ Set the font for the current graphics context. """ - self.font = agg.Font(name, size) + self.set_font(Font(face_name, size=size, style=style)) def set_font(self, font): """ Set the font for the current graphics context. """ - self.select_font(font.findfont(), font.size, None) + self.font = agg.Font(font.findfont(), font.size) def set_font_size(self, size): """ Set the font size for the current graphics context. diff --git a/kiva/pdf.py b/kiva/pdf.py index bf1fd7422..54fc2b1ea 100644 --- a/kiva/pdf.py +++ b/kiva/pdf.py @@ -50,6 +50,12 @@ join_style[constants.JOIN_BEVEL] = 2 join_style[constants.JOIN_MITER] = 0 +font_styles = {} +font_styles["regular"] = "" +font_styles["bold"] = "-Bold" +font_styles["italic"] = "-Oblique" +font_styles["bold italic"] = "-BoldOblique" + # stroke, fill, mode path_mode = {} path_mode[constants.FILL_STROKE] = (1, 1, canvas.FILL_NON_ZERO) @@ -612,9 +618,10 @@ def draw_image(self, img, rect=None): # Drawing Text # ---------------------------------------------------------------- - def select_font(self, name, size, textEncoding): + def select_font(self, name, size, style="regular", encoding=None): """ PDF ignores the Encoding variable. """ + name += font_styles.get(style, "") self.gc.setFont(name, size) def set_font(self, font): @@ -625,6 +632,8 @@ def set_font(self, font): if face_name == "": face_name = "Helvetica" + # Apply the style as a suffix to the face name + face_name += font_styles.get(font.style, "") try: self.gc.setFont(face_name, font.size) except KeyError: diff --git a/kiva/qpainter.py b/kiva/qpainter.py index 1f92700b7..38eb5a2e4 100644 --- a/kiva/qpainter.py +++ b/kiva/qpainter.py @@ -690,10 +690,14 @@ def show_text(self, text, point=None): unflip_trans.translate(0, self._height) unflip_trans.scale(1.0, -1.0) - self.gc.save() - self.gc.setTransform(unflip_trans, True) - self.gc.drawText(QtCore.QPointF(pos[0], self._flip_y(pos[1])), text) - self.gc.restore() + # Make some temporary modifications to the state + with self: + # Kiva uses the fill color for text + brush = self.gc.brush() + self.gc.setPen(brush.color()) + self.gc.setTransform(unflip_trans, True) + pos = QtCore.QPointF(pos[0], self._flip_y(pos[1])) + self.gc.drawText(pos, text) def show_text_at_point(self, text, x, y): """ Draw text at some point (x, y). diff --git a/kiva/quartz/ABCGI.pyx b/kiva/quartz/ABCGI.pyx index fdf1aebd6..61e314379 100644 --- a/kiva/quartz/ABCGI.pyx +++ b/kiva/quartz/ABCGI.pyx @@ -787,8 +787,8 @@ cdef class CGContext: # Drawing Text #---------------------------------------------------------------- - def select_font(self, object name, float size, style='regular'): - """ + def select_font(self, object name, float size, style='regular', encoding=None): + """ Select a font to use. """ key = (name, size, style) if key not in self.font_cache: From 6feb10028ddee6fdfc7108b1423af0ce3cda5bb9 Mon Sep 17 00:00:00 2001 From: John Wiggins Date: Tue, 2 Mar 2021 13:16:07 +0100 Subject: [PATCH 2/6] Normalize signatures of other text functions --- kiva/abstract_graphics_context.py | 9 ++++++--- kiva/basecore2d.py | 9 +++++++-- kiva/cairo.py | 8 ++++++-- kiva/celiagg.py | 4 ++++ kiva/pdf.py | 24 +++++------------------- kiva/qpainter.py | 12 +++++++++--- kiva/quartz/ABCGI.pyx | 10 ++++++++-- 7 files changed, 45 insertions(+), 31 deletions(-) diff --git a/kiva/abstract_graphics_context.py b/kiva/abstract_graphics_context.py index 0404979ec..5940aa829 100644 --- a/kiva/abstract_graphics_context.py +++ b/kiva/abstract_graphics_context.py @@ -96,7 +96,8 @@ def set_line_dash(self, line_dash): @abstractmethod def set_fill_color(self, color): - """ Set the color used to fill the region bounded by a path + """ Set the color used to fill the region bounded by a path or when + drawing text. Parameters ---------- @@ -108,7 +109,9 @@ def set_fill_color(self, color): @abstractmethod def get_fill_color(self): - """ Get the color used to fill the region bounded by a path """ + """ Get the color used to fill the region bounded by a path or when + drawing text. + """ @abstractmethod def linear_gradient(self, x1, y1, x2, y2, stops, spread_method, units): @@ -493,7 +496,7 @@ def get_text_position(self): """ Get the current point where text will be drawn """ @abstractmethod - def show_text(self, text): + def show_text(self, text, point=None): """ Draw the specified string at the current point """ @abstractmethod diff --git a/kiva/basecore2d.py b/kiva/basecore2d.py index 28f740722..68a5ce02f 100644 --- a/kiva/basecore2d.py +++ b/kiva/basecore2d.py @@ -1003,7 +1003,7 @@ def get_text_matrix(self): """ return self.state.text_matrix.copy() - def show_text(self, text): + def show_text(self, text, point=None): """ Draws text on the device at the current text position. This calls the device dependent device_show_text() method to @@ -1011,7 +1011,12 @@ def show_text(self, text): It is not clear yet how this should affect the current point. """ - self.device_show_text(text) + if point is not None: + with self: + self.set_text_position(*point) + self.device_show_text(text) + else: + self.device_show_text(text) def show_text_tanslate(self, text, dx, dy): """ Draws text at the specified offset. """ diff --git a/kiva/cairo.py b/kiva/cairo.py index 491d62845..35a41656a 100644 --- a/kiva/cairo.py +++ b/kiva/cairo.py @@ -1082,11 +1082,15 @@ def get_text_matrix(self): """ return copy.copy(self.text_matrix) - def show_text(self, text, point=(0.0, 0.0)): + def show_text(self, text, point=None): """ Draws text on the device at the current text position. Leaves the current point unchanged. """ - self.show_text_at_point(text, point[0], point[1]) + if point is not None: + x, y = point + else: + x, y = 0.0, 0.0 + self.show_text_at_point(text, x, y) def show_glyphs(self): """ diff --git a/kiva/celiagg.py b/kiva/celiagg.py index 3e6d89dc1..a2f40949a 100644 --- a/kiva/celiagg.py +++ b/kiva/celiagg.py @@ -631,6 +631,10 @@ def set_character_spacing(self, spacing): msg = "set_character_spacing not implemented on celiagg yet." raise NotImplementedError(msg) + def get_character_spacing(self): + msg = "get_character_spacing not implemented on celiagg yet." + raise NotImplementedError(msg) + def set_text_drawing_mode(self, mode): try: tmode = text_modes[mode] diff --git a/kiva/pdf.py b/kiva/pdf.py index 54fc2b1ea..73ce2eeb6 100644 --- a/kiva/pdf.py +++ b/kiva/pdf.py @@ -656,20 +656,6 @@ def set_font_size(self, size): font = self.gc._fontname self.gc.setFont(font, size) - def set_character_spacing(self): - """ - """ - pass - - def get_character_spacing(self): - """ Get the current font """ - raise NotImplementedError - - def set_text_drawing_mode(self): - """ - """ - pass - def set_text_position(self, x, y): """ """ @@ -692,22 +678,22 @@ def get_text_matrix(self): a, b, c, d, tx, ty = self.gc._textMatrix return affine.affine_from_values(a, b, c, d, tx, ty) - def show_text(self, text, x=None, y=None): + def show_text(self, text, point=None): """ Draws text on the device at current text position. This is also used for showing text at a particular point - specified by x and y. + specified by ``point``. This ignores the text matrix for now. """ - if x and y: - pass + if point: + x, y = point else: x, y = self.text_xy self.gc.drawString(x, y, text) def show_text_at_point(self, text, x, y): - self.show_text(text, x, y) + self.show_text(text, point=(x, y)) def show_glyphs(self): """ diff --git a/kiva/qpainter.py b/kiva/qpainter.py index 38eb5a2e4..4a4ad3104 100644 --- a/kiva/qpainter.py +++ b/kiva/qpainter.py @@ -644,16 +644,22 @@ def set_font_size(self, size): self.gc.setFont(font) def set_character_spacing(self, spacing): - """ + """ Set the spacing between characters when drawing text """ font = self.gc.font() font.setLetterSpacing(QtGui.QFont.AbsoluteSpacing, spacing) self.gc.setFont(font) - def set_text_drawing_mode(self): + def get_character_spacing(self): + """ Get the spacing between characters when drawing text """ + font = self.gc.font() + return font.letterSpacing() + + def set_text_drawing_mode(self, mode): + """ Set the drawing mode to use with text """ - pass + raise NotImplementedError() def set_text_position(self, x, y): """ diff --git a/kiva/quartz/ABCGI.pyx b/kiva/quartz/ABCGI.pyx index 61e314379..2351acaa0 100644 --- a/kiva/quartz/ABCGI.pyx +++ b/kiva/quartz/ABCGI.pyx @@ -826,13 +826,19 @@ cdef class CGContext: self.current_font = self.font_cache[key] def set_character_spacing(self, float spacing): + """ Set the spacing between characters when drawing text """ - """ - # XXX: Perhaps this should be handled by the kerning attribute # in the attributed string that is used to make a line of text? CGContextSetCharacterSpacing(self.context, spacing) + def get_character_spacing(self): + """ Get the current spacing between characters when drawing text + """ + # XXX: There is no "get" counterpart for CGContextSetCharacterSpacing + msg = "get_character_spacing not implemented for Quartz yet." + raise NotImplementedError(msg) + def set_text_drawing_mode(self, object mode): """ """ From 6812853707c72f7a934622e6473469d7e838e9f2 Mon Sep 17 00:00:00 2001 From: John Wiggins Date: Tue, 2 Mar 2021 13:26:17 +0100 Subject: [PATCH 3/6] Use a common signature for save() --- enable/gcbench/pdf.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/enable/gcbench/pdf.py b/enable/gcbench/pdf.py index dc46af88b..df26ad187 100644 --- a/enable/gcbench/pdf.py +++ b/enable/gcbench/pdf.py @@ -27,4 +27,4 @@ def __init__(self, size, *args, **kw): def save(self, filename, *args, **kw): # Reportlab is a bit silly self.gc._filename = filename - super().save() + super().save(filename, *args, **kw) From 4273a31302ce6a207978434bde4ba5c79fc08367 Mon Sep 17 00:00:00 2001 From: John Wiggins Date: Tue, 2 Mar 2021 13:29:34 +0100 Subject: [PATCH 4/6] Capture the default draw_mode of draw_path_at_points --- kiva/abstract_graphics_context.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/kiva/abstract_graphics_context.py b/kiva/abstract_graphics_context.py index 5940aa829..bd4e5280d 100644 --- a/kiva/abstract_graphics_context.py +++ b/kiva/abstract_graphics_context.py @@ -659,7 +659,8 @@ def draw_marker_at_points(self, point_array, size, marker=SQUARE_MARKER): """ @abstractmethod - def draw_path_at_points(self, point_array, compiled_path, draw_mode): + def draw_path_at_points(self, point_array, compiled_path, + draw_mode=FILL_STROKE): """ Draw a compiled path at a collection of points The starting point of the paths are specified by the points, From 723541a7e96687d783cafaea544ec6d54590e6df Mon Sep 17 00:00:00 2001 From: John Wiggins Date: Tue, 2 Mar 2021 13:34:49 +0100 Subject: [PATCH 5/6] Document the correct signature for set_line_dash() --- kiva/abstract_graphics_context.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/kiva/abstract_graphics_context.py b/kiva/abstract_graphics_context.py index bd4e5280d..65361cf90 100644 --- a/kiva/abstract_graphics_context.py +++ b/kiva/abstract_graphics_context.py @@ -84,7 +84,7 @@ def set_line_cap(self, line_cap): """ @abstractmethod - def set_line_dash(self, line_dash): + def set_line_dash(self, line_dash, phase=0): """ Set the dash style to use when stroking a path Parameters @@ -92,6 +92,8 @@ def set_line_dash(self, line_dash): line_dash An even-lengthed tuple of floats that represents the width of each dash and gap in the dash pattern. + phase : float + Specifies how many units into the dash pattern to start. """ @abstractmethod From 85b71118766fd7c7e3440f64318a4f7df00c4c8e Mon Sep 17 00:00:00 2001 From: John Wiggins Date: Wed, 3 Mar 2021 15:58:31 +0100 Subject: [PATCH 6/6] Fix gradient method default value for units --- kiva/abstract_graphics_context.py | 6 ++++-- kiva/basecore2d.py | 6 ++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/kiva/abstract_graphics_context.py b/kiva/abstract_graphics_context.py index 65361cf90..0daa702ea 100644 --- a/kiva/abstract_graphics_context.py +++ b/kiva/abstract_graphics_context.py @@ -116,7 +116,8 @@ def get_fill_color(self): """ @abstractmethod - def linear_gradient(self, x1, y1, x2, y2, stops, spread_method, units): + def linear_gradient(self, x1, y1, x2, y2, stops, spread_method, + units="userSpaceOnUse"): """ Modify the fill color to be a linear gradient Parameters @@ -142,7 +143,8 @@ def linear_gradient(self, x1, y1, x2, y2, stops, spread_method, units): """ @abstractmethod - def radial_gradient(self, cx, cy, r, fx, fy, stops, spread_method, units): + def radial_gradient(self, cx, cy, r, fx, fy, stops, spread_method, + units="userSpaceOnUse"): """ Modify the fill color to be a radial gradient Parameters diff --git a/kiva/basecore2d.py b/kiva/basecore2d.py index 68a5ce02f..fbc9a7201 100644 --- a/kiva/basecore2d.py +++ b/kiva/basecore2d.py @@ -811,11 +811,13 @@ def get_fill_color(self, color): """ return self.state.fill_color - def linear_gradient(self, x1, y1, x2, y2, stops, spread_method, units): + def linear_gradient(self, x1, y1, x2, y2, stops, spread_method, + units="userSpaceOnUse"): """ Modify the fill color to be a linear gradient """ pass - def radial_gradient(self, cx, cy, r, fx, fy, stops, spread_method, units): + def radial_gradient(self, cx, cy, r, fx, fy, stops, spread_method, + units="userSpaceOnUse"): """ Modify the fill color to be a linear gradient """ pass