#------------------------------------------------------------------------------ # # PyGUI - TextEditor Printing - Gtk # #------------------------------------------------------------------------------ import re from Printing import Printable class TextEditorPrintView(Printable): def __init__(self, base_view, page_setup): self.base_view = base_view; self.width = page_setup.page_width; self.page_height = page_setup.page_height; self.lay_out_text(); lines_per_page = int(page_setup.page_height / base_view.font.line_height); self.lines_per_page = lines_per_page; num_lines = len(self.lines); self.num_pages = (num_lines + lines_per_page - 1) // lines_per_page self.height = self.num_pages * self.page_height print "TextEditorPrintView: lines_per_page =", self.lines_per_page ### print "...num_lines =", num_lines ### print "...height =", self.height ### print "...page_height =", self.page_height ### def lay_out_text(self): base_view = self.base_view font = base_view.font space_width = font.width(" ") tab_spacing = base_view.tab_spacing page_width = self.width wrap = not base_view.get_hscrolling() if wrap: pat = re.compile(r"[ \t]|[^ \t]+") else: pat = re.compile(r"\t|[^ \t]+") lines = [] line = [] x = 0 for text_line in base_view.text.splitlines(): for match in pat.finditer(text_line): item = match.group() if item == " ": item_width = space_width item = "" elif item == "\t": item_width = tab_spacing - x % tab_spacing item = "" else: item_width = font.width(item) if wrap and x + item_width > page_width and x > 0: lines.append(line); line = []; x = 0 line.append((x, item)) x += item_width lines.append(line); line = []; x = 0 self.lines = lines def get_print_extent(self): return self.width, self.height def draw(self, canvas, page_rect): l, t, r, b = page_rect page_no = int(t / self.page_height) print "TextEditorPrintView.draw: page_no =", page_no ### n = self.lines_per_page i = page_no * n font = self.base_view.font y = t + font.ascent dy = font.line_height for line in self.lines[i : i + n]: for x, item in line: canvas.moveto(x, y) canvas.show_text(item) y += dy #------------------------------------------------------------------------------ # # PyGUI - Printing - Generic # #------------------------------------------------------------------------------ from __future__ import division from math import ceil import cPickle as pickle from Properties import overridable_property from Globals import application class PageSetup(object): """Holder of information specified by the "Page Setup" command.""" paper_name = overridable_property('paper_name') paper_width = overridable_property('paper_width') paper_height = overridable_property('paper_height') left_margin = overridable_property('left_margin') top_margin = overridable_property('top_margin') right_margin = overridable_property('right_margin') bottom_margin = overridable_property('bottom_margin') orientation = overridable_property('orientation') paper_size = overridable_property('paper_size') margins = overridable_property('margins') page_width = overridable_property('page_width') page_height = overridable_property('page_height') page_size = overridable_property('page_size') page_rect = overridable_property('page_rect') printable_rect = overridable_property('printable_rect') # May not work printer_name = overridable_property('printer_name') _pickle_attributes = ['paper_name', 'paper_size', 'margins', 'printer_name', 'orientation'] def __getstate__(self): state = {} for name in self._pickle_attributes: state[name] = getattr(self, name) return state def __setstate__(self, state): for name, value in state.iteritems(): setattr(self, name, value) def from_string(s): """Restore a pickled PageSetup object from a string.""" return pickle.loads(s) from_string = staticmethod(from_string) def to_string(self): """Pickle the PageSetup object and return it as a string.""" return pickle.dumps(self, 2) def get_paper_size(self): return self.paper_width, self.paper_height def set_paper_size(self, x): self.paper_width, self.paper_height = x def get_margins(self): return self.left_margin, self.top_margin, self.right_margin, self.bottom_margin def set_margins(self, x): self.left_margin, self.top_margin, self.right_margin, self.bottom_margin = x def get_page_width(self): return self.paper_width - self.left_margin - self.right_margin def get_page_height(self): return self.paper_height - self.top_margin - self.bottom_margin def get_page_size(self): return (self.page_width, self.page_height) def get_page_rect(self): lm, tm, rm, bm = self.margins pw, ph = self.paper_size return (lm, tm, pw - rm, ph - bm) #------------------------------------------------------------------------------ class Printable(object): """Mixin class for components implementing the "Print" command.""" printable = overridable_property('printable', "Whether this component should handle the 'Print' command.") page_setup = overridable_property('page_setup', "The PageSetup object to use for printing.") print_title = overridable_property('print_title', "Title for print job.") _printable = True def get_printable(self): return self._printable def set_printable(self, x): self._printable = x def get_print_title(self): window = self.window if window: return window.title else: return "" def get_page_setup(self): result = None model = getattr(self, 'model', None) if model: result = getattr(model, 'page_setup', None) if not result: result = application().page_setup return result def setup_menus(self, m): if self.printable: m.print_cmd.enabled = True def print_cmd(self): if self.printable: page_setup = self.page_setup if page_setup: self.print_view(page_setup) else: self.pass_to_next_handler('print_cmd') #------------------------------------------------------------------------------ class Paginator(object): """Used internally. A generic pagination algorithm for printing.""" def __init__(self, view, page_setup): self.view = view extent_width, extent_height = view.get_print_extent() #paper_width, paper_height = page_setup.paper_size #lm, tm, rm, bm = page_setup.margins #page_width = int(paper_width - lm - rm) #page_height = int(paper_height - tm - bm) page_width, page_height = page_setup.page_size if page_width <= 0 or page_height <= 0: from AlertFunctions import stop_alert stop_alert("Margins are too large for the page size.") return self.extent_rect = (0, 0, extent_width, extent_height) self.page_width = page_width self.page_height = page_height self.left_margin = page_setup.left_margin self.top_margin = page_setup.top_margin self.pages_wide = int(ceil(extent_width / page_width)) self.pages_high = int(ceil(extent_height / page_height)) self.num_pages = self.pages_wide * self.pages_high def draw_page(self, canvas, page_num): row, col = divmod(page_num, self.pages_wide) view_left = col * self.page_width view_top = row * self.page_height view_right = view_left + self.page_width view_bottom = view_top + self.page_height view_rect = (view_left, view_top, view_right, view_bottom) dx = self.left_margin - view_left dy = self.top_margin - view_top canvas.translate(dx, dy) canvas.rectclip(self.extent_rect) canvas.rectclip(view_rect) canvas._printing = True self.view.draw(canvas, view_rect)