def gather_forward_lines_from(self, gcdc: wx.GCDC, line_index: int, y: int, style_name: str): template = self.app.template width_in_twips = (template.page_width - template.left_margin - template.right_margin - template.gutter) style = template.styles[style_name] italic = wx.FONTSTYLE_ITALIC if style.italic else wx.FONTSTYLE_NORMAL bold = wx.FONTWEIGHT_BOLD if style.bold else wx.FONTWEIGHT_NORMAL gcdc.SetFont( wx.Font(style.font_size, wx.FONTFAMILY_DEFAULT, italic, bold, faceName=style.font)) size = gcdc.GetTextExtent(" ") width_of_space = size.width lines = [] while True: paragraph = self.gather_paragraph(gcdc, self.lorem_ipsum[line_index], style_name, width_of_space, width_in_twips) while paragraph: lines.append(paragraph.pop(0)) y += style.line_spacing if y > (template.page_height - template.bottom_margin): return lines, line_index, 0 line_index += 1 style_name = CONSTANTS.STYLING.NAMES.NORMAL
def draw_horizontal_ruler(self, gcdc: wx.GCDC, x_offset: int): template = self.app.template # White bar for horizontal ruler thickness = CONSTANTS.UI.PREVIEW.RULER_THICKNESS * self.measure_to_twips gap = CONSTANTS.UI.PREVIEW.GAP * self.measure_to_twips gcdc.SetPen(wx.Pen(self.color_db.Find("WHITE"))) gcdc.DrawRectangle(x_offset, self.y_orig + gap, template.page_width, thickness) font_size = thickness // 2 gcdc.SetFont( wx.Font(font_size, wx.FONTFAMILY_TELETYPE, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL)) gcdc.SetPen(wx.Pen(self.color_db.Find("BLACK"))) # Label the horizontal ruler for index, x in enumerate( range(0, int(template.page_width), CONSTANTS.MEASURING.TWIPS_PER_INCH)): label = str(index) size = gcdc.GetTextExtent(label) gcdc.DrawText( label, x_offset + x - (size.width // 2), self.y_orig + gap + ((thickness - font_size) * CONSTANTS.UI.PREVIEW.RULER_TEXT)) # Draw ticks at the half-inch spots along the horizontal ruler half_inch = CONSTANTS.MEASURING.TWIPS_PER_INCH // 2 for index, x in enumerate( range(half_inch, int(template.page_width), CONSTANTS.MEASURING.TWIPS_PER_INCH)): gcdc.DrawLine( x_offset + x, self.y_orig + gap + (thickness * CONSTANTS.UI.PREVIEW.TICK_FROM), x_offset + x, self.y_orig + gap + (thickness * CONSTANTS.UI.PREVIEW.TICK_TO))
def draw_page(self, gcdc: wx.GCDC, x_offset: int, black: wx.Colour, grey: wx.Colour): template = self.app.template # White box for page gcdc.SetBrush(wx.Brush(self.color_db.Find("WHITE"))) gcdc.SetPen(wx.Pen(black)) gcdc.DrawRectangle(x_offset, 0, template.page_width, template.page_height) gcdc.SetBrush(wx.Brush(grey)) gcdc.SetPen(wx.Pen(grey)) if x_offset: gcdc.DrawRectangle(x_offset, 0, template.gutter, template.page_height) else: gcdc.DrawRectangle(template.page_width - template.gutter, 0, template.gutter, template.page_height) gcdc.SetPen(wx.Pen(black)) gcdc.SetBrush(wx.NullBrush) gcdc.DrawRectangle(x_offset, 0, template.page_width, template.page_height)
def gather_back_lines_to( self, gcdc: wx.GCDC, # Graphic context length_of_text: float # How much text to generate (0.0=None, 1.0=Full page) ) -> List[LINE_TYPE]: # List of line descriptors """Starting at the end of the lorem ipsum, gather lines to fill a percentage of a page.""" template = self.app.template width_in_twips = (template.page_width - template.left_margin - template.right_margin - template.gutter) normal = template.styles[CONSTANTS.STYLING.NAMES.NORMAL] italic = wx.FONTSTYLE_ITALIC if normal.italic else wx.FONTSTYLE_NORMAL bold = wx.FONTWEIGHT_BOLD if normal.bold else wx.FONTWEIGHT_NORMAL gcdc.SetFont( wx.Font(normal.font_size, wx.FONTFAMILY_DEFAULT, italic, bold, faceName=normal.font)) size = gcdc.GetTextExtent(" ") width_of_space = size.width line_index = -1 lines = [] y = template.top_margin while True: paragraph = self.gather_paragraph(gcdc, self.lorem_ipsum[line_index], CONSTANTS.STYLING.NAMES.NORMAL, width_of_space, width_in_twips) while paragraph: lines.insert(0, paragraph.pop()) y += normal.line_spacing if (y / template.page_height) >= length_of_text: return lines line_index -= 1
def gather_paragraph(self, gcdc: wx.GCDC, text: str, style: str, width_of_space: int, width_in_twips: int) -> list: line = text.split(" ") word_and_widths = [] for word in line: size = gcdc.GetTextExtent(word) word_and_widths.append((word, size.width)) paragraph = [] indent = self.app.template.styles[style].first_line_indent line_start = 0 line_end = 1 current_line = None while True: line_width = indent + sum(width for word, width in word_and_widths[line_start:line_end]) + \ (width_of_space * (line_end - line_start - 1)) if line_width > width_in_twips: words, total_width = current_line paragraph.append( (MIDDLE_LINE, indent, words, width_of_space + (width_in_twips - total_width) / (len(words) - 1))) line_start = line_end - 1 word, width = word_and_widths[line_start] current_line = ([(word, width)], width) indent = 0 else: current_line = (word_and_widths[line_start:line_end], line_width) if line_end >= len(word_and_widths): break else: line_end += 1 if paragraph: paragraph[0] = (FIRST_LINE, ) + paragraph[0][1:] paragraph.append( (LAST_LINE, indent, current_line[0], width_of_space)) else: paragraph.append( (ONLY_LINE, indent, current_line[0], width_of_space)) return paragraph
def draw_in_style( self, gcdc: wx.GCDC, # Graphic context x_offset: int, # X-offset of text page y_offset: int, # Y-offset of first line style_name: str, # "Normal" or "First Paragraph" lines: Union[ str, List[LINE_TYPE]], # Either a single string or a list of lines black: wx.Colour, align: Optional[int] = None, # Alignment override ) -> int: # New Y-offset template = self.app.template """Draw lines of text.""" width_in_twips = (template.page_width - template.left_margin - template.right_margin - template.gutter) style = template.styles[style_name] italic = wx.FONTSTYLE_ITALIC if style.italic else wx.FONTSTYLE_NORMAL bold = wx.FONTWEIGHT_BOLD if style.bold else wx.FONTWEIGHT_NORMAL font = wx.Font(style.font_size, wx.FONTFAMILY_DEFAULT, italic, bold, faceName=style.font) gcdc.SetTextForeground(black) gcdc.SetFont(font) size = gcdc.GetTextExtent(" ") width_of_space = size.width if isinstance(lines, str): size = gcdc.GetTextExtent(lines) lines = [(ONLY_LINE, style.first_line_indent, [(lines, size.width) ], 0)] for descriptor, indent, words, spacing in lines: # Technically this resets us back to Normal after each line instead of each paragraph. This isn't ideal but # I'm not certain I care enough to track the end of paragraphs. style_name = CONSTANTS.STYLING.NAMES.NORMAL total_width = sum(width for word, width in words) if descriptor in [FIRST_LINE, ONLY_LINE]: y_offset += style.space_before x = template.left_margin + indent if align is None: align = style.alignment if align == WD_PARAGRAPH_ALIGNMENT.CENTER: x += (width_in_twips - total_width) // 2 elif align == WD_PARAGRAPH_ALIGNMENT.RIGHT: x += width_in_twips - total_width for word, width in words: gcdc.DrawText(word, x_offset + x, y_offset) if align == WD_PARAGRAPH_ALIGNMENT.JUSTIFY: x += width + spacing else: x += width + width_of_space y_offset += style.line_spacing if descriptor in [LAST_LINE, ONLY_LINE]: y_offset += style.space_after return y_offset
def draw_scopes(self, gcdc: wx.GCDC): template = self.app.template mid_offset = CONSTANTS.UI.PREVIEW.MID_TEXT_OFFSET width_in_twips = (template.page_width - template.left_margin - template.right_margin - template.gutter) left_centered = template.left_margin + (width_in_twips // 2) right_centered = left_centered + template.page_width + CONSTANTS.UI.PREVIEW.PAGE_GAP + template.gutter mid_vertical = template.page_height // 2 style = template.styles[CONSTANTS.STYLING.NAMES.HEADING1] part = template.top_margin + style.space_before + (style.font_size * mid_offset) style = template.styles[CONSTANTS.STYLING.NAMES.HEADING2] chapter = template.top_margin + style.space_before + (style.font_size * mid_offset) header = template.header_distance font_size = template.styles[CONSTANTS.STYLING.NAMES.HEADER].font_size even_header = (left_centered, header + (font_size * mid_offset)) odd_header = (right_centered, header + (font_size * mid_offset)) font_size = template.styles[CONSTANTS.STYLING.NAMES.FOOTER].font_size footer = template.page_height - template.footer_distance even_footer = (template.left_margin, footer - (font_size * (1 - mid_offset))) even_page = (template.page_width * 2) + CONSTANTS.UI.PREVIEW.PAGE_GAP - template.right_margin odd_footer = (even_page, footer - (font_size * (1 - mid_offset))) gcdc.SetBrush(wx.Brush(self.color_db.Find("WHITE"))) style = template.styles[CONSTANTS.STYLING.NAMES.HEADER] height = _("Header height: %s") % template.header_imperial margin = _("Top margin: %s") % template.top_imperial if SCOPE_ON_EVEN_HEADER in self.scopes: self.draw_scope(gcdc, even_header[0], even_header[1], [style.font_text, height, "", "", margin, ""]) if SCOPE_ON_ODD_HEADER in self.scopes: self.draw_scope(gcdc, odd_header[0], odd_header[1], [style.font_text, height, "", "", margin, ""]) style = template.styles[CONSTANTS.STYLING.NAMES.FOOTER] height = _("Footer height: %s") % template.footer_imperial if SCOPE_ON_EVEN_FOOTER in self.scopes: margin = _("Left margin: %s") % template.left_imperial self.draw_scope(gcdc, even_footer[0], even_footer[1], [style.font_text, height, "", "", margin, ""]) if SCOPE_ON_ODD_FOOTER in self.scopes: self.draw_scope(gcdc, odd_footer[0], odd_footer[1], [style.font_text, "", "", height]) if SCOPE_ON_LEFT_MARGIN in self.scopes: self.draw_scope(gcdc, template.left_margin, mid_vertical, []) if SCOPE_ON_RIGHT_MARGIN in self.scopes: self.draw_scope(gcdc, (template.page_width * 2) + CONSTANTS.UI.PREVIEW.PAGE_GAP - template.right_margin, mid_vertical, []) if SCOPE_ON_GUTTER in self.scopes: margin = _("Right margin: %s") % template.right_imperial gutter = _("Gutter: %s") % template.gutter_imperial self.draw_scope(gcdc, template.page_width - template.gutter, mid_vertical, [margin, gutter]) if SCOPE_ON_PART in self.scopes: style = template.styles[CONSTANTS.STYLING.NAMES.HEADING1] above = "Space above: %s" % style.before_text self.draw_scope(gcdc, right_centered, part, [above, "", "", "", "", style.font_text]) if SCOPE_ON_CHAPTER in self.scopes: style = template.styles[ CONSTANTS.STYLING.NAMES.HEADING2 if template. part_and_chapter else CONSTANTS.STYLING.NAMES.HEADING1] above = "Space above: %s" % style.before_text below = "Space below: %s" % style.after_text self.draw_scope(gcdc, right_centered, chapter, [style.font_text, above, "", "", "", below, ""])
def draw_scope(self, gcdc: wx.GCDC, x: int, y: int, lines: List[str]): magnification = CONSTANTS.UI.PREVIEW.MAGNIFIER_SCALING points = [(x - self.x_orig + cos(a * 6.283 / 15) * self.scope_radius, y - self.y_orig + sin(a * 6.283 / 15) * self.scope_radius) for a in range(15)] region = wx.Region(points) gcdc.SetDeviceClippingRegion(region) gcdc.SetLogicalOrigin(x - ((x - self.x_orig) / magnification), y - ((y - self.y_orig) / magnification)) gcdc.SetLogicalScale(self.scale * magnification, self.scale * magnification) self.draw_content(gcdc, wx.Colour(*CONSTANTS.UI.PREVIEW.MEDIUM_GREY), wx.Colour(*CONSTANTS.UI.PREVIEW.LIGHT_GREY)) gcdc.DestroyClippingRegion() gcdc.SetLogicalOrigin(self.x_orig, self.y_orig) gcdc.SetLogicalScale(self.scale, self.scale) gcdc.SetBrush(wx.NullBrush) black = self.color_db.Find("BLACK") gcdc.SetPen(wx.Pen(black)) gcdc.SetTextForeground(black) gcdc.DrawCircle(x, y, self.scope_radius) font_size = 0.02 * self.measure_to_twips gcdc.SetFont( wx.Font(font_size, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL)) line_spacing = font_size * CONSTANTS.UI.PREVIEW.LINE_SPACING height = font_size + (line_spacing * (len(lines) - 1)) y_pos = y - (height // 2) for text in lines: size = gcdc.GetTextExtent(text) gcdc.DrawText(text, x - (size.width // 2), y_pos) y_pos += line_spacing