#------------------------------------------------------------------------------ # # PyGUI - Printing - Generic # #------------------------------------------------------------------------------ from __future__ import division from math import ceil import cPickle as pickle from GUI.Properties import overridable_property from GUI 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)