# A demo of an Application object that has some custom print functionality.

# If you desire, you can also run this from inside Pythonwin, in which
# case it will do the demo inside the Pythonwin environment.

# This sample was contributed by Roger Burnham.

from pywin.mfc import docview, dialog, afxres
from pywin.framework import app

import win32con
import win32ui
import win32api

PRINTDLGORD = 1538
IDC_PRINT_MAG_EDIT = 1010


class PrintDemoTemplate(docview.DocTemplate):
    def _SetupSharedMenu_(self):
        pass


class PrintDemoView(docview.ScrollView):
    def OnInitialUpdate(self):
        ret = self._obj_.OnInitialUpdate()
        self.colors = {
            "Black": (0x00 << 0) + (0x00 << 8) + (0x00 << 16),
            "Red": (0xFF << 0) + (0x00 << 8) + (0x00 << 16),
            "Green": (0x00 << 0) + (0xFF << 8) + (0x00 << 16),
            "Blue": (0x00 << 0) + (0x00 << 8) + (0xFF << 16),
            "Cyan": (0x00 << 0) + (0xFF << 8) + (0xFF << 16),
            "Magenta": (0xFF << 0) + (0x00 << 8) + (0xFF << 16),
            "Yellow": (0xFF << 0) + (0xFF << 8) + (0x00 << 16),
        }
        self.pens = {}
        for name, color in self.colors.items():
            self.pens[name] = win32ui.CreatePen(win32con.PS_SOLID, 5, color)
        self.pen = None
        self.size = (128, 128)
        self.SetScaleToFitSize(self.size)
        self.HookCommand(self.OnFilePrint, afxres.ID_FILE_PRINT)
        self.HookCommand(self.OnFilePrintPreview, win32ui.ID_FILE_PRINT_PREVIEW)
        return ret

    def OnDraw(self, dc):
        oldPen = None
        x, y = self.size
        delta = 2
        colors = list(self.colors.keys())
        colors.sort()
        colors = colors * 2
        for color in colors:
            if oldPen is None:
                oldPen = dc.SelectObject(self.pens[color])
            else:
                dc.SelectObject(self.pens[color])
            dc.MoveTo((delta, delta))
            dc.LineTo((x - delta, delta))
            dc.LineTo((x - delta, y - delta))
            dc.LineTo((delta, y - delta))
            dc.LineTo((delta, delta))
            delta = delta + 4
            if x - delta <= 0 or y - delta <= 0:
                break
        dc.SelectObject(oldPen)

    def OnPrepareDC(self, dc, pInfo):
        if dc.IsPrinting():
            mag = self.prtDlg["mag"]
            dc.SetMapMode(win32con.MM_ANISOTROPIC)
            dc.SetWindowOrg((0, 0))
            dc.SetWindowExt((1, 1))
            dc.SetViewportOrg((0, 0))
            dc.SetViewportExt((mag, mag))

    def OnPreparePrinting(self, pInfo):
        flags = (
            win32ui.PD_USEDEVMODECOPIES
            | win32ui.PD_PAGENUMS
            | win32ui.PD_NOPAGENUMS
            | win32ui.PD_NOSELECTION
        )
        self.prtDlg = ImagePrintDialog(pInfo, PRINTDLGORD, flags)
        pInfo.SetPrintDialog(self.prtDlg)
        pInfo.SetMinPage(1)
        pInfo.SetMaxPage(1)
        pInfo.SetFromPage(1)
        pInfo.SetToPage(1)
        ret = self.DoPreparePrinting(pInfo)
        return ret

    def OnBeginPrinting(self, dc, pInfo):
        return self._obj_.OnBeginPrinting(dc, pInfo)

    def OnEndPrinting(self, dc, pInfo):
        del self.prtDlg
        return self._obj_.OnEndPrinting(dc, pInfo)

    def OnFilePrintPreview(self, *arg):
        self._obj_.OnFilePrintPreview()

    def OnFilePrint(self, *arg):
        self._obj_.OnFilePrint()

    def OnPrint(self, dc, pInfo):
        doc = self.GetDocument()
        metrics = dc.GetTextMetrics()
        cxChar = metrics["tmAveCharWidth"]
        cyChar = metrics["tmHeight"]
        left, top, right, bottom = pInfo.GetDraw()
        dc.TextOut(0, 2 * cyChar, doc.GetTitle())
        top = top + (7 * cyChar) / 2
        dc.MoveTo(left, top)
        dc.LineTo(right, top)
        top = top + cyChar
        # this seems to have not effect...
        # get what I want with the dc.SetWindowOrg calls
        pInfo.SetDraw((left, top, right, bottom))
        dc.SetWindowOrg((0, -top))

        self.OnDraw(dc)
        dc.SetTextAlign(win32con.TA_LEFT | win32con.TA_BOTTOM)

        rect = self.GetWindowRect()
        rect = self.ScreenToClient(rect)
        height = rect[3] - rect[1]
        dc.SetWindowOrg((0, -(top + height + cyChar)))
        dc.MoveTo(left, 0)
        dc.LineTo(right, 0)

        x = 0
        y = (3 * cyChar) / 2

        dc.TextOut(x, y, doc.GetTitle())
        y = y + cyChar


class PrintDemoApp(app.CApp):
    def __init__(self):
        app.CApp.__init__(self)

    def InitInstance(self):
        template = PrintDemoTemplate(None, None, None, PrintDemoView)
        self.AddDocTemplate(template)
        self._obj_.InitMDIInstance()
        self.LoadMainFrame()
        doc = template.OpenDocumentFile(None)
        doc.SetTitle("Custom Print Document")


class ImagePrintDialog(dialog.PrintDialog):

    sectionPos = "Image Print Demo"

    def __init__(self, pInfo, dlgID, flags=win32ui.PD_USEDEVMODECOPIES):
        dialog.PrintDialog.__init__(self, pInfo, dlgID, flags=flags)
        mag = win32ui.GetProfileVal(self.sectionPos, "Document Magnification", 0)
        if mag <= 0:
            mag = 2
            win32ui.WriteProfileVal(self.sectionPos, "Document Magnification", mag)

        self["mag"] = mag

    def OnInitDialog(self):
        self.magCtl = self.GetDlgItem(IDC_PRINT_MAG_EDIT)
        self.magCtl.SetWindowText(repr(self["mag"]))
        return dialog.PrintDialog.OnInitDialog(self)

    def OnOK(self):
        dialog.PrintDialog.OnOK(self)
        strMag = self.magCtl.GetWindowText()
        try:
            self["mag"] = int(strMag)
        except:
            pass
        win32ui.WriteProfileVal(self.sectionPos, "Document Magnification", self["mag"])


if __name__ == "__main__":
    # Running under Pythonwin
    def test():
        template = PrintDemoTemplate(None, None, None, PrintDemoView)
        template.OpenDocumentFile(None)

    test()
else:
    app = PrintDemoApp()
