<filename>GUI/Win32/Printing.py
#------------------------------------------------------------------------------
#
#   PyGUI - Printing - Win32
#
#------------------------------------------------------------------------------

import WinPageSetup as wps, WinPrint as wp
import win32print as wp2
from GUI.GPrinting import PageSetup as GPageSetup, Printable as GPrintable, \
	Paginator
from GUI import Canvas

#------------------------------------------------------------------------------

win_paper_names = {
	1: "Letter", # Letter 8 1/2 x 11 in
	2: "Letter Small", # Letter Small 8 1/2 x 11 in
	3: "Tabloid", # Tabloid 11 x 17 in
	4: "Ledger", # Ledger 17 x 11 in
	5: "Legal", # Legal 8 1/2 x 14 in
	6: "Statement", # Statement 5 1/2 x 8 1/2 in
	7: "Executive", # Executive 7 1/4 x 10 1/2 in
	8: "A3", # A3 297 x 420 mm
	9: "A4", # A4 210 x 297 mm
	10: "A4 Small", # A4 Small 210 x 297 mm
	11: "A5", # A5 148 x 210 mm
	12: "B4 (JIS)", # B4 (JIS) 250 x 354
	13: "B5 (JIS)", # B5 (JIS) 182 x 257 mm
	14: "Folio", # Folio 8 1/2 x 13 in
	15: "Quarto", # Quarto 215 x 275 mm
	16: "10x14", # 10x14 in
	17: "11x17", # 11x17 in
	18: "Note", # Note 8 1/2 x 11 in
	19: "Envelope #9", # Envelope #9 3 7/8 x 8 7/8
	20: "Envelope #10", # Envelope #10 4 1/8 x 9 1/2
	21: "Envelope #11", # Envelope #11 4 1/2 x 10 3/8
	22: "Envelope #12", # Envelope #12 4 \276 x 11
	23: "Envelope #14", # Envelope #14 5 x 11 1/2
	24: "C Sheet", # C size sheet
	25: "D Sheet", # D size sheet
	26: "E Sheet", # E size sheet
	27: "Envelope DL", # Envelope DL 110 x 220mm
	28: "Envelope C5", # Envelope C5 162 x 229 mm
	29: "Envelope C3", # Envelope C3  324 x 458 mm
	30: "Envelope C4", # Envelope C4  229 x 324 mm
	31: "Envelope C6", # Envelope C6  114 x 162 mm
	32: "Envelope C65", # Envelope C65 114 x 229 mm
	33: "Envelope B4", # Envelope B4  250 x 353 mm
	34: "Envelope B5", # Envelope B5  176 x 250 mm
	35: "Envelope B6", # Envelope B6  176 x 125 mm
	36: "Envelope", # Envelope 110 x 230 mm
	37: "Envelope Monarch", # Envelope Monarch 3.875 x 7.5 in
	38: "6 3/4 Envelope", # 6 3/4 Envelope 3 5/8 x 6 1/2 in
	39: "US Std Fanfold", # US Std Fanfold 14 7/8 x 11 in
	40: "German Std Fanfold", # German Std Fanfold 8 1/2 x 12 in
	41: "German Legal Fanfold", # German Legal Fanfold 8 1/2 x 13 in
	42: "B4", # B4 (ISO) 250 x 353 mm
	43: "Japanese Postcard", # Japanese Postcard 100 x 148 mm
	44: "9x11", # 9 x 11 in
	45: "10x11", # 10 x 11 in
	46: "15x11", # 15 x 11 in
	47: "Envelope Invite", # Envelope Invite 220 x 220 mm
	#48: "", # RESERVED--DO NOT USE
	#49: "", # RESERVED--DO NOT USE
	50: "Letter Extra", # Letter Extra 9 \275 x 12 in
	51: "Legal Extra", # Legal Extra 9 \275 x 15 in
	52: "Tabloid Extra", # Tabloid Extra 11.69 x 18 in
	53: "A4 Extra", # A4 Extra 9.27 x 12.69 in
	54: "Letter Transverse", # Letter Transverse 8 \275 x 11 in
	55: "A4 Transverse", # A4 Transverse 210 x 297 mm
	56: "Letter Extra Transverse", # Letter Extra Transverse 9\275 x 12 in
	57: "SuperA", # SuperA/SuperA/A4 227 x 356 mm
	58: "SuperB", # SuperB/SuperB/A3 305 x 487 mm
	59: "Letter Plus", # Letter Plus 8.5 x 12.69 in
	60: "A4 Plus", # A4 Plus 210 x 330 mm
	61: "A5 Transverse", # A5 Transverse 148 x 210 mm
	62: "B5 (JIS) Transverse", # B5 (JIS) Transverse 182 x 257 mm
	63: "A3 Extra", # A3 Extra 322 x 445 mm
	64: "A5 Extra", # A5 Extra 174 x 235 mm
	65: "B5 (ISO) Extra", # B5 (ISO) Extra 201 x 276 mm
	66: "A2", # A2 420 x 594 mm
	67: "A3 Transverse", # A3 Transverse 297 x 420 mm
	68: "A3 Extra Transverse", # A3 Extra Transverse 322 x 445 mm
}

win_paper_codes = dict([(name, code)
	for (code, name) in win_paper_names.iteritems()])
	
def ti_to_pts(x):
	return x * 0.072

def pts_to_ti(x):
	return int(round(x / 0.072))

#------------------------------------------------------------------------------

class PageSetup(GPageSetup):

	def __new__(cls):
		self = GPageSetup.__new__(cls)
		self._win_psd = wps.get_defaults()
		return self
	
	def __init__(self):
		self.margins = (36, 36, 36, 36)
	
	def __getstate__(self):
		psd = self._win_psd
		state = GPageSetup.__getstate__(self)
		state['_win_devmode'] = wps.get_handle_contents(psd.hDevMode)
		state['_win_devnames'] = wps.get_handle_contents(psd.hDevNames)
		return state
	
	def __setstate__(self, state):
		psd = self._win_psd
		dm = state.pop('_win_devmode', None)
		dn = state.pop('_win_devnames', None)
		GPageSetup.__setstate__(self, state)
		if dm:
			wps.GlobalFree(psd.hDevMode)
			psd.hDevMode = handle_with_contents(dm)
		if dn:
			wps.GlobalFree(psd.hDevNames)
			psd.hDevNames = handle_with_contents(dn)
	
	def _win_lock_devmode(self):
		return wps.lock_devmode_handle(self._win_psd.hDevMode)
	
	def _win_unlock_devmode(self):
		wps.GlobalUnlock(self._win_psd.hDevMode)
	
	def get_printable_rect(self):
		psd = self._win_psd
		pw, ph = self.paper_size
		mm = psd.rtMinMargin
		ml = ti_to_pts(mm.left)
		mt = ti_to_pts(mm.top)
		mr = ti_to_pts(mm.right)
		mb = ti_to_pts(mm.bottom)
		return (ml, mt, pw - mr, ph - mb)
	
	def get_paper_name(self):
		dm = self._win_lock_devmode()
		result = win_paper_names.get(dm.dmPaperSize, "Custom")
		self._win_unlock_devmode()
		return result
	
	def set_paper_name(self, name):
		dm = self._win_lock_devmode()
		dm.dmPaperSize = win_paper_codes.get(name, 0)
		self._win_unlock_devmode()
	
	def get_paper_width(self):
		return ti_to_pts(self._win_psd.ptPaperSize.x)

	def get_paper_height(self):
		return ti_to_pts(self._win_psd.ptPaperSize.y)
	
	def set_paper_width(self, v):
		self._win_psd.ptPaperSize.x = pts_to_ti(v)

	def set_paper_height(self, v):
		self._win_psd.ptPaperSize.y = pts_to_ti(v)
	
	def get_left_margin(self):
		return ti_to_pts(self._win_psd.rtMargin.left)

	def get_top_margin(self):
		return ti_to_pts(self._win_psd.rtMargin.top)

	def get_right_margin(self):
		return ti_to_pts(self._win_psd.rtMargin.right)

	def get_bottom_margin(self):
		return ti_to_pts(self._win_psd.rtMargin.bottom)
	
	def set_left_margin(self, v):
		self._win_psd.rtMargin.left = pts_to_ti(v)

	def set_top_margin(self, v):
		self._win_psd.rtMargin.top = pts_to_ti(v)

	def set_right_margin(self, v):
		self._win_psd.rtMargin.right = pts_to_ti(v)

	def set_bottom_margin(self, v):
		self._win_psd.rtMargin.bottom = pts_to_ti(v)
	
	def get_orientation(self):
		dm = self._win_lock_devmode()
		result = win_orientation_names.get(dm.dmOrientation, 'portrait')
		self._win_unlock_devmode()
		return result
	
	def set_orientation(self, v):
		dm = self._win_lock_devmode()
		dm.dmOrientation = win_orientation_codes.get(v, 1)
		self._win_unlock_devmode()
	
	def get_printer_name(self):
		dm = self._win_lock_devmode()
		result = dm.dmDeviceName
		self._win_unlock_devmode()
		return result
	
	def set_printer_name(self, v):
		dm = self._win_lock_devmode()
		dm.dmDeviceName = v
		self._win_unlock_devmode()

#------------------------------------------------------------------------------

class Printable(GPrintable):

	def print_view(self, page_setup, prompt = True):
		paginator = Paginator(self, page_setup)
		psd = page_setup._win_psd
		pd = wp.PRINTDLG()
		pd.hDevMode = psd.hDevMode
		pd.hDevNames = psd.hDevNames
		pd.nMinPage = 1
		pd.nMaxPage = paginator.num_pages
		pd.nCopies = 1
		if wp.PrintDlg(pd):
			title = self.print_title
			di = wp.DOCINFO()
			di.lpszDocName = title
			devnames = wps.DevNames(psd.hDevNames)
			if devnames.output == "FILE:":
				from FileDialogs import request_new_file
				f = request_new_file("Print '%s' to file:" % title)
				if not f:
					return
				output_path = f.path
				di.lpszOutput = output_path
			try:
				hdc = pd.hDC
				dx, dy = wp.GetPrintingOffset(hdc)
				print "TODO: Printable: Implement a Cancel dialog" ###
				#wp.install_abort_proc(hdc)
				wp.StartDoc(hdc, di)
				for page_num in xrange(pd.nFromPage - 1, pd.nToPage):
					wp.StartPage(hdc)
					canvas = Canvas._from_win_hdc(hdc, for_printing = True)
					canvas.translate(-dx, -dy)
					paginator.draw_page(canvas, page_num)
					wp.EndPage(hdc)
				wp.EndDoc(hdc)
			finally:
				wp.DeleteDC(hdc)

#------------------------------------------------------------------------------

def present_page_setup_dialog(page_setup):
	return wps.PageSetupDlg(page_setup._win_psd)

<filename>GUI/Win32/Printing.py
#------------------------------------------------------------------------------
#
#   PyGUI - Printing - Win32
#
#------------------------------------------------------------------------------

import WinPageSetup as wps, WinPrint as wp
import win32print as wp2
from GUI.GPrinting import PageSetup as GPageSetup, Printable as GPrintable, \
	Paginator
from GUI import Canvas

#------------------------------------------------------------------------------

win_paper_names = {
	1: "Letter", # Letter 8 1/2 x 11 in
	2: "Letter Small", # Letter Small 8 1/2 x 11 in
	3: "Tabloid", # Tabloid 11 x 17 in
	4: "Ledger", # Ledger 17 x 11 in
	5: "Legal", # Legal 8 1/2 x 14 in
	6: "Statement", # Statement 5 1/2 x 8 1/2 in
	7: "Executive", # Executive 7 1/4 x 10 1/2 in
	8: "A3", # A3 297 x 420 mm
	9: "A4", # A4 210 x 297 mm
	10: "A4 Small", # A4 Small 210 x 297 mm
	11: "A5", # A5 148 x 210 mm
	12: "B4 (JIS)", # B4 (JIS) 250 x 354
	13: "B5 (JIS)", # B5 (JIS) 182 x 257 mm
	14: "Folio", # Folio 8 1/2 x 13 in
	15: "Quarto", # Quarto 215 x 275 mm
	16: "10x14", # 10x14 in
	17: "11x17", # 11x17 in
	18: "Note", # Note 8 1/2 x 11 in
	19: "Envelope #9", # Envelope #9 3 7/8 x 8 7/8
	20: "Envelope #10", # Envelope #10 4 1/8 x 9 1/2
	21: "Envelope #11", # Envelope #11 4 1/2 x 10 3/8
	22: "Envelope #12", # Envelope #12 4 \276 x 11
	23: "Envelope #14", # Envelope #14 5 x 11 1/2
	24: "C Sheet", # C size sheet
	25: "D Sheet", # D size sheet
	26: "E Sheet", # E size sheet
	27: "Envelope DL", # Envelope DL 110 x 220mm
	28: "Envelope C5", # Envelope C5 162 x 229 mm
	29: "Envelope C3", # Envelope C3  324 x 458 mm
	30: "Envelope C4", # Envelope C4  229 x 324 mm
	31: "Envelope C6", # Envelope C6  114 x 162 mm
	32: "Envelope C65", # Envelope C65 114 x 229 mm
	33: "Envelope B4", # Envelope B4  250 x 353 mm
	34: "Envelope B5", # Envelope B5  176 x 250 mm
	35: "Envelope B6", # Envelope B6  176 x 125 mm
	36: "Envelope", # Envelope 110 x 230 mm
	37: "Envelope Monarch", # Envelope Monarch 3.875 x 7.5 in
	38: "6 3/4 Envelope", # 6 3/4 Envelope 3 5/8 x 6 1/2 in
	39: "US Std Fanfold", # US Std Fanfold 14 7/8 x 11 in
	40: "German Std Fanfold", # German Std Fanfold 8 1/2 x 12 in
	41: "German Legal Fanfold", # German Legal Fanfold 8 1/2 x 13 in
	42: "B4", # B4 (ISO) 250 x 353 mm
	43: "Japanese Postcard", # Japanese Postcard 100 x 148 mm
	44: "9x11", # 9 x 11 in
	45: "10x11", # 10 x 11 in
	46: "15x11", # 15 x 11 in
	47: "Envelope Invite", # Envelope Invite 220 x 220 mm
	#48: "", # RESERVED--DO NOT USE
	#49: "", # RESERVED--DO NOT USE
	50: "Letter Extra", # Letter Extra 9 \275 x 12 in
	51: "Legal Extra", # Legal Extra 9 \275 x 15 in
	52: "Tabloid Extra", # Tabloid Extra 11.69 x 18 in
	53: "A4 Extra", # A4 Extra 9.27 x 12.69 in
	54: "Letter Transverse", # Letter Transverse 8 \275 x 11 in
	55: "A4 Transverse", # A4 Transverse 210 x 297 mm
	56: "Letter Extra Transverse", # Letter Extra Transverse 9\275 x 12 in
	57: "SuperA", # SuperA/SuperA/A4 227 x 356 mm
	58: "SuperB", # SuperB/SuperB/A3 305 x 487 mm
	59: "Letter Plus", # Letter Plus 8.5 x 12.69 in
	60: "A4 Plus", # A4 Plus 210 x 330 mm
	61: "A5 Transverse", # A5 Transverse 148 x 210 mm
	62: "B5 (JIS) Transverse", # B5 (JIS) Transverse 182 x 257 mm
	63: "A3 Extra", # A3 Extra 322 x 445 mm
	64: "A5 Extra", # A5 Extra 174 x 235 mm
	65: "B5 (ISO) Extra", # B5 (ISO) Extra 201 x 276 mm
	66: "A2", # A2 420 x 594 mm
	67: "A3 Transverse", # A3 Transverse 297 x 420 mm
	68: "A3 Extra Transverse", # A3 Extra Transverse 322 x 445 mm
}

win_paper_codes = dict([(name, code)
	for (code, name) in win_paper_names.iteritems()])
	
def ti_to_pts(x):
	return x * 0.072

def pts_to_ti(x):
	return int(round(x / 0.072))

#------------------------------------------------------------------------------

class PageSetup(GPageSetup):

	def __new__(cls):
		self = GPageSetup.__new__(cls)
		self._win_psd = wps.get_defaults()
		return self
	
	def __init__(self):
		self.margins = (36, 36, 36, 36)
	
	def __getstate__(self):
		psd = self._win_psd
		state = GPageSetup.__getstate__(self)
		state['_win_devmode'] = wps.get_handle_contents(psd.hDevMode)
		state['_win_devnames'] = wps.get_handle_contents(psd.hDevNames)
		return state
	
	def __setstate__(self, state):
		psd = self._win_psd
		dm = state.pop('_win_devmode', None)
		dn = state.pop('_win_devnames', None)
		GPageSetup.__setstate__(self, state)
		if dm:
			wps.GlobalFree(psd.hDevMode)
			psd.hDevMode = handle_with_contents(dm)
		if dn:
			wps.GlobalFree(psd.hDevNames)
			psd.hDevNames = handle_with_contents(dn)
	
	def _win_lock_devmode(self):
		return wps.lock_devmode_handle(self._win_psd.hDevMode)
	
	def _win_unlock_devmode(self):
		wps.GlobalUnlock(self._win_psd.hDevMode)
	
	def get_printable_rect(self):
		psd = self._win_psd
		pw, ph = self.paper_size
		mm = psd.rtMinMargin
		ml = ti_to_pts(mm.left)
		mt = ti_to_pts(mm.top)
		mr = ti_to_pts(mm.right)
		mb = ti_to_pts(mm.bottom)
		return (ml, mt, pw - mr, ph - mb)
	
	def get_paper_name(self):
		dm = self._win_lock_devmode()
		result = win_paper_names.get(dm.dmPaperSize, "Custom")
		self._win_unlock_devmode()
		return result
	
	def set_paper_name(self, name):
		dm = self._win_lock_devmode()
		dm.dmPaperSize = win_paper_codes.get(name, 0)
		self._win_unlock_devmode()
	
	def get_paper_width(self):
		return ti_to_pts(self._win_psd.ptPaperSize.x)

	def get_paper_height(self):
		return ti_to_pts(self._win_psd.ptPaperSize.y)
	
	def set_paper_width(self, v):
		self._win_psd.ptPaperSize.x = pts_to_ti(v)

	def set_paper_height(self, v):
		self._win_psd.ptPaperSize.y = pts_to_ti(v)
	
	def get_left_margin(self):
		return ti_to_pts(self._win_psd.rtMargin.left)

	def get_top_margin(self):
		return ti_to_pts(self._win_psd.rtMargin.top)

	def get_right_margin(self):
		return ti_to_pts(self._win_psd.rtMargin.right)

	def get_bottom_margin(self):
		return ti_to_pts(self._win_psd.rtMargin.bottom)
	
	def set_left_margin(self, v):
		self._win_psd.rtMargin.left = pts_to_ti(v)

	def set_top_margin(self, v):
		self._win_psd.rtMargin.top = pts_to_ti(v)

	def set_right_margin(self, v):
		self._win_psd.rtMargin.right = pts_to_ti(v)

	def set_bottom_margin(self, v):
		self._win_psd.rtMargin.bottom = pts_to_ti(v)
	
	def get_orientation(self):
		dm = self._win_lock_devmode()
		result = win_orientation_names.get(dm.dmOrientation, 'portrait')
		self._win_unlock_devmode()
		return result
	
	def set_orientation(self, v):
		dm = self._win_lock_devmode()
		dm.dmOrientation = win_orientation_codes.get(v, 1)
		self._win_unlock_devmode()
	
	def get_printer_name(self):
		dm = self._win_lock_devmode()
		result = dm.dmDeviceName
		self._win_unlock_devmode()
		return result
	
	def set_printer_name(self, v):
		dm = self._win_lock_devmode()
		dm.dmDeviceName = v
		self._win_unlock_devmode()

#------------------------------------------------------------------------------

class Printable(GPrintable):

	def print_view(self, page_setup, prompt = True):
		paginator = Paginator(self, page_setup)
		psd = page_setup._win_psd
		pd = wp.PRINTDLG()
		pd.hDevMode = psd.hDevMode
		pd.hDevNames = psd.hDevNames
		pd.nMinPage = 1
		pd.nMaxPage = paginator.num_pages
		pd.nCopies = 1
		if wp.PrintDlg(pd):
			title = self.print_title
			di = wp.DOCINFO()
			di.lpszDocName = title
			devnames = wps.DevNames(psd.hDevNames)
			if devnames.output == "FILE:":
				from FileDialogs import request_new_file
				f = request_new_file("Print '%s' to file:" % title)
				if not f:
					return
				output_path = f.path
				di.lpszOutput = output_path
			try:
				hdc = pd.hDC
				dx, dy = wp.GetPrintingOffset(hdc)
				print "TODO: Printable: Implement a Cancel dialog" ###
				#wp.install_abort_proc(hdc)
				wp.StartDoc(hdc, di)
				for page_num in xrange(pd.nFromPage - 1, pd.nToPage):
					wp.StartPage(hdc)
					canvas = Canvas._from_win_hdc(hdc, for_printing = True)
					canvas.translate(-dx, -dy)
					paginator.draw_page(canvas, page_num)
					wp.EndPage(hdc)
				wp.EndDoc(hdc)
			finally:
				wp.DeleteDC(hdc)

#------------------------------------------------------------------------------

def present_page_setup_dialog(page_setup):
	return wps.PageSetupDlg(page_setup._win_psd)

#------------------------------------------------------------------------------ # #   PyGUI - Printing - Win32 # #------------------------------------------------------------------------------ #------------------------------------------------------------------------------ # Letter 8 1/2 x 11 in # Letter Small 8 1/2 x 11 in # Tabloid 11 x 17 in # Ledger 17 x 11 in # Legal 8 1/2 x 14 in # Statement 5 1/2 x 8 1/2 in # Executive 7 1/4 x 10 1/2 in # A3 297 x 420 mm # A4 210 x 297 mm # A4 Small 210 x 297 mm # A5 148 x 210 mm # B4 (JIS) 250 x 354 # B5 (JIS) 182 x 257 mm # Folio 8 1/2 x 13 in # Quarto 215 x 275 mm # 10x14 in # 11x17 in # Note 8 1/2 x 11 in #9", # Envelope #9 3 7/8 x 8 7/8 #10", # Envelope #10 4 1/8 x 9 1/2 #11", # Envelope #11 4 1/2 x 10 3/8 #12", # Envelope #12 4 \276 x 11 #14", # Envelope #14 5 x 11 1/2 # C size sheet # D size sheet # E size sheet # Envelope DL 110 x 220mm # Envelope C5 162 x 229 mm # Envelope C3  324 x 458 mm # Envelope C4  229 x 324 mm # Envelope C6  114 x 162 mm # Envelope C65 114 x 229 mm # Envelope B4  250 x 353 mm # Envelope B5  176 x 250 mm # Envelope B6  176 x 125 mm # Envelope 110 x 230 mm # Envelope Monarch 3.875 x 7.5 in # 6 3/4 Envelope 3 5/8 x 6 1/2 in # US Std Fanfold 14 7/8 x 11 in # German Std Fanfold 8 1/2 x 12 in # German Legal Fanfold 8 1/2 x 13 in # B4 (ISO) 250 x 353 mm # Japanese Postcard 100 x 148 mm # 9 x 11 in # 10 x 11 in # 15 x 11 in # Envelope Invite 220 x 220 mm #48: "", # RESERVED--DO NOT USE #49: "", # RESERVED--DO NOT USE # Letter Extra 9 \275 x 12 in # Legal Extra 9 \275 x 15 in # Tabloid Extra 11.69 x 18 in # A4 Extra 9.27 x 12.69 in # Letter Transverse 8 \275 x 11 in # A4 Transverse 210 x 297 mm # Letter Extra Transverse 9\275 x 12 in # SuperA/SuperA/A4 227 x 356 mm # SuperB/SuperB/A3 305 x 487 mm # Letter Plus 8.5 x 12.69 in # A4 Plus 210 x 330 mm # A5 Transverse 148 x 210 mm # B5 (JIS) Transverse 182 x 257 mm # A3 Extra 322 x 445 mm # A5 Extra 174 x 235 mm # B5 (ISO) Extra 201 x 276 mm # A2 420 x 594 mm # A3 Transverse 297 x 420 mm # A3 Extra Transverse 322 x 445 mm #------------------------------------------------------------------------------ #------------------------------------------------------------------------------ ### #wp.install_abort_proc(hdc) #------------------------------------------------------------------------------