home *** CD-ROM | disk | FTP | other *** search
/ Hall of Fame / HallofFameCDROM.cdr / pcmag / v9n08.lzh / PRINTCAL.C < prev    next >
C/C++ Source or Header  |  1989-11-05  |  17KB  |  462 lines

  1. /*---------------------------------------------------------------------
  2.    PRINTCAL.C -- OS/2 Presentation Manager program to print a calendar
  3.                  (c) 1990, Ziff Communications Co.
  4.                  PC Magazine * Charles Petzold, 10/89
  5.   ---------------------------------------------------------------------*/
  6.  
  7. #define INCL_WIN
  8. #define INCL_GPI
  9. #define INCL_DEV
  10. #define INCL_DOSPROCESS
  11. #include <os2.h>
  12. #include <mt\process.h>
  13. #include <mt\stdio.h>
  14. #include <mt\stdlib.h>
  15. #include <mt\string.h>
  16. #include "printcal.h"
  17.  
  18. #define LCID_CALFONT          1L
  19. #define STACKSIZE             (4096 * sizeof (int))
  20. #define WM_USER_PRINT_OK      (WM_USER + 0)
  21. #define WM_USER_PRINT_ERROR   (WM_USER + 1)
  22.  
  23. typedef struct
  24.      {
  25.      SHORT sYear, sMonthBeg, sMonthEnd ;
  26.      }
  27.      CALPARAMS ;
  28.  
  29. typedef struct
  30.      {
  31.      int       aiThreadStack[STACKSIZE / sizeof (int)] ;
  32.      CALPARAMS cp ;
  33.      HWND      hwndNotify ;
  34.      }
  35.      THREADPARAMS ;
  36.  
  37. MPARAM EXPENTRY ClientWndProc (HWND, USHORT, MPARAM, MPARAM) ;
  38. MPARAM EXPENTRY AboutDlgProc  (HWND, USHORT, MPARAM, MPARAM) ;
  39. MPARAM EXPENTRY PrintDlgProc  (HWND, USHORT, MPARAM, MPARAM) ;
  40. VOID            DisplayPage   (HPS, SIZEL *, SHORT, SHORT) ;
  41. VOID            Message       (HWND, SHORT, CHAR *) ;
  42. VOID   FAR      PrintThread   (THREADPARAMS *) ;
  43. HDC             OpenDefaultPrinterDC (HAB) ;           // in PRINTDC.C
  44.  
  45. HAB    hab ;
  46. USHORT usActiveThreads = 0 ;
  47.  
  48. int main (void)
  49.      {
  50.      static CHAR  szClientClass[] = "PrintCal" ;
  51.      static ULONG flFrameFlags = FCF_TITLEBAR      | FCF_SYSMENU |
  52.                                  FCF_SIZEBORDER    | FCF_MINMAX  |
  53.                                  FCF_MENU          |
  54.                                  FCF_SHELLPOSITION | FCF_TASKLIST ;
  55.      HMQ          hmq ;
  56.      HWND         hwndFrame, hwndClient ;
  57.      QMSG         qmsg ;
  58.  
  59.      hab = WinInitialize (0) ;
  60.      hmq = WinCreateMsgQueue (hab, 0) ;
  61.      WinRegisterClass (hab, szClientClass, ClientWndProc, CS_SIZEREDRAW, 0) ;
  62.  
  63.      hwndFrame = WinCreateStdWindow (HWND_DESKTOP, WS_VISIBLE,
  64.                                      &flFrameFlags, szClientClass, NULL,
  65.                                      0L, NULL, ID_RESOURCE, &hwndClient) ;
  66.      while (TRUE)
  67.           {
  68.           while (WinGetMsg (hab, &qmsg, NULL, 0, 0))
  69.                WinDispatchMsg (hab, &qmsg) ;
  70.  
  71.           if (usActiveThreads == 0)
  72.                break ;
  73.  
  74.           Message (hwndClient, MB_ICONEXCLAMATION,
  75.                    "Printing thread still active.\n"
  76.                    "Program cannot be closed now.") ;
  77.  
  78.           WinCancelShutdown (hmq, FALSE) ;
  79.           }
  80.  
  81.      WinDestroyWindow (hwndFrame) ;
  82.      WinDestroyMsgQueue (hmq) ;
  83.      WinTerminate (hab) ;
  84.      return 0 ;
  85.      }
  86.  
  87. MPARAM EXPENTRY ClientWndProc (HWND hwnd, USHORT msg, MPARAM mp1, MPARAM mp2)
  88.      {
  89.      static CALPARAMS cp ;
  90.      static HPS       hps ;
  91.      static SIZEL     sizlClient ;
  92.      DATETIME         dt ;
  93.      HDC              hdc ;
  94.      SHORT            sResult ;
  95.      SIZEL            sizlPage ;
  96.      THREADPARAMS     *ptp ;
  97.  
  98.      switch (msg)
  99.           {
  100.           case WM_CREATE:
  101.                hdc = WinOpenWindowDC (hwnd) ;
  102.                sizlPage.cx = 0 ;
  103.                sizlPage.cy = 0 ;
  104.                hps = GpiCreatePS (hab, hdc, &sizlPage,
  105.                                   PU_ARBITRARY | GPIF_DEFAULT |
  106.                                   GPIT_MICRO   | GPIA_ASSOC) ;
  107.  
  108.                DosGetDateTime (&dt) ;
  109.                cp.sYear     = dt.year ;
  110.                cp.sMonthBeg = dt.month - 1 ;
  111.                cp.sMonthEnd = dt.month - 1 ;
  112.                return 0 ;
  113.  
  114.           case WM_SIZE:
  115.                sizlClient.cx = SHORT1FROMMP (mp2) ;
  116.                sizlClient.cy = SHORT2FROMMP (mp2) ;
  117.  
  118.                GpiConvert (hps, CVTC_DEVICE, CVTC_PAGE, 1L,
  119.                            (PPOINTL) &sizlClient) ;
  120.                return 0 ;
  121.  
  122.           case WM_PAINT:
  123.                WinBeginPaint (hwnd, hps, NULL) ;
  124.  
  125.                GpiErase (hps) ;
  126.                DisplayPage (hps, &sizlClient, cp.sYear, cp.sMonthBeg) ;
  127.  
  128.                WinEndPaint (hps) ;
  129.                return 0 ;
  130.  
  131.           case WM_COMMAND:
  132.                switch (COMMANDMSG(&msg)->cmd)
  133.                     {
  134.                     case IDM_ABOUT:
  135.                          WinDlgBox (HWND_DESKTOP, hwnd, AboutDlgProc,
  136.                                     NULL, IDD_ABOUT, NULL) ;
  137.                          return 0 ;
  138.  
  139.                     case IDM_PRINT:
  140.                          sResult = WinDlgBox (HWND_DESKTOP, hwnd, PrintDlgProc,
  141.                                               NULL, IDD_PRINT, &cp) ;
  142.  
  143.                          if (sResult == DID_CANCEL)
  144.                               return 0 ;
  145.  
  146.                          WinInvalidateRect (hwnd, NULL, FALSE) ;
  147.  
  148.                          if (sResult == IDD_PREVIEW)
  149.                               return 0 ;
  150.  
  151.                          if ((ptp = malloc (sizeof (THREADPARAMS))) == NULL)
  152.                               {
  153.                               Message (hwnd, MB_ICONEXCLAMATION,
  154.                                   "Cannot allocate memory for print thread!") ;
  155.                               return 0 ;
  156.                               }
  157.  
  158.                          ptp->cp         = cp ;
  159.                          ptp->hwndNotify = hwnd ;
  160.  
  161.                          if (_beginthread (PrintThread, ptp->aiThreadStack,
  162.                                            STACKSIZE, ptp) == -1)
  163.                               {
  164.                               free (ptp) ;
  165.                               Message (hwnd, MB_ICONEXCLAMATION,
  166.                                        "Cannot create print thread!") ;
  167.                               return 0 ;
  168.                               }
  169.  
  170.                          usActiveThreads++ ;
  171.                          Message (hwnd, MB_ICONASTERISK,
  172.                                   "Print job successfully started.") ;
  173.                          return 0 ;
  174.                     }
  175.                break ;
  176.  
  177.           case WM_USER_PRINT_OK:
  178.                ptp = PVOIDFROMMP (mp1) ;
  179.                free (ptp) ;
  180.                usActiveThreads-- ;
  181.                Message (hwnd, MB_ICONASTERISK,
  182.                         "Print job sent to spooler.") ;
  183.                return 0 ;
  184.  
  185.           case WM_USER_PRINT_ERROR:
  186.                ptp = PVOIDFROMMP (mp1) ;
  187.                free (ptp) ;
  188.                usActiveThreads-- ;
  189.                Message (hwnd, MB_ICONEXCLAMATION,
  190.                         "Error encountered during printing.") ;
  191.                return 0 ;
  192.  
  193.           case WM_DESTROY:
  194.                GpiDestroyPS (hps) ;
  195.                return 0 ;
  196.           }
  197.      return WinDefWindowProc (hwnd, msg, mp1, mp2) ;
  198.      }
  199.  
  200. MRESULT EXPENTRY AboutDlgProc (HWND hwnd, USHORT msg, MPARAM mp1, MPARAM mp2)
  201.      {
  202.      switch (msg)
  203.           {
  204.           case WM_COMMAND:
  205.                switch (COMMANDMSG(&msg)->cmd)
  206.                     {
  207.                     case DID_OK:
  208.                     case DID_CANCEL:
  209.                          WinDismissDlg (hwnd, TRUE) ;
  210.                          return 0 ;
  211.                     }
  212.                break ;
  213.           }
  214.      return WinDefDlgProc (hwnd, msg, mp1, mp2) ;
  215.      }
  216.  
  217. MRESULT EXPENTRY PrintDlgProc (HWND hwnd, USHORT msg, MPARAM mp1, MPARAM mp2)
  218.      {
  219.      static CALPARAMS cpLocal, *pcpCurrent ;
  220.  
  221.      switch (msg)
  222.           {
  223.           case WM_INITDLG:
  224.                pcpCurrent = PVOIDFROMMP (mp2) ;
  225.                cpLocal = *pcpCurrent ;
  226.  
  227.                WinSendDlgItemMsg (hwnd, IDD_MONTHBEG + cpLocal.sMonthBeg,
  228.                                   BM_SETCHECK, MPFROM2SHORT (TRUE, 0), NULL) ;
  229.  
  230.                WinSendDlgItemMsg (hwnd, IDD_MONTHEND + cpLocal.sMonthEnd,
  231.                                   BM_SETCHECK, MPFROM2SHORT (TRUE, 0), NULL) ;
  232.  
  233.                WinSendDlgItemMsg (hwnd, IDD_YEAR, EM_SETTEXTLIMIT,
  234.                                   MPFROM2SHORT (4, 0), NULL) ;
  235.  
  236.                WinSetDlgItemShort (hwnd, IDD_YEAR, cpLocal.sYear, FALSE) ;
  237.                return 0 ;
  238.  
  239.           case WM_CONTROL:
  240.                if (SHORT1FROMMP (mp1) >= IDD_MONTHBEG &&
  241.                    SHORT1FROMMP (mp1) <  IDD_MONTHBEG + 12)
  242.  
  243.                     cpLocal.sMonthBeg = SHORT1FROMMP (mp1) - IDD_MONTHBEG ;
  244.  
  245.                else if (SHORT1FROMMP (mp1) >= IDD_MONTHEND &&
  246.                         SHORT1FROMMP (mp1) <  IDD_MONTHEND + 12)
  247.  
  248.                     cpLocal.sMonthEnd = SHORT1FROMMP (mp1) - IDD_MONTHEND ;
  249.  
  250.                return 0 ;
  251.  
  252.           case WM_COMMAND:
  253.                switch (COMMANDMSG(&msg)->cmd)
  254.                     {
  255.                     case DID_OK:
  256.                     case IDD_PREVIEW:
  257.                          WinQueryDlgItemShort (hwnd, IDD_YEAR,
  258.                                                &cpLocal.sYear, FALSE) ;
  259.  
  260.                          if (cpLocal.sYear < 1900 || cpLocal.sYear > 2099)
  261.                               {
  262.                               Message (hwnd, MB_ICONEXCLAMATION,
  263.                                        "Year must be between 1900 and 2099!") ;
  264.                               WinSetFocus (HWND_DESKTOP,
  265.                                            WinWindowFromID (hwnd, IDD_YEAR)) ;
  266.                               return 0 ;
  267.                               }
  268.  
  269.                          if (cpLocal.sMonthBeg > cpLocal.sMonthEnd)
  270.                               {
  271.                               Message (hwnd, MB_ICONEXCLAMATION,
  272.                                        "Begin month cannot be later "
  273.                                        "than end month!") ;
  274.                               WinSetFocus (HWND_DESKTOP,
  275.                                    WinWindowFromID (hwnd,
  276.                                         IDD_MONTHBEG + cpLocal.sMonthBeg)) ;
  277.                               return 0 ;
  278.                               }
  279.  
  280.                          *pcpCurrent = cpLocal ;
  281.                                                        // fall through
  282.                     case DID_CANCEL:
  283.                          WinDismissDlg (hwnd, COMMANDMSG(&msg)->cmd) ;
  284.                          return 0 ;
  285.                     }
  286.                break ;
  287.           }
  288.      return WinDefDlgProc (hwnd, msg, mp1, mp2) ;
  289.      }
  290.  
  291. VOID DisplayPage (HPS hps, SIZEL *psizlPage, SHORT sYear, SHORT sMonth)
  292.      {
  293.      static CHAR  *apszMonths[]  = { "January", "February", "March",
  294.                                      "April",   "May",      "June",
  295.                                      "July",    "August",   "September",
  296.                                      "October", "November", "December" } ;
  297.      static SHORT asMonthLen[]   = { 31, 28, 31, 30, 31, 30,
  298.                                      31, 31, 30, 31, 30, 31 } ;
  299.      static SHORT asMonthStart[] = {  0,  3,  3,  6,  1,  4,
  300.                                       6,  2,  5,  0,  3,  5 } ;
  301.      CHAR         szBuffer[16] ;
  302.      BOOL         fLeap ;
  303.      FATTRS       fat ;
  304.      LONG         lLength ;
  305.      POINTL       ptl, aptlTextBox[TXTBOX_COUNT] ;
  306.      SHORT        sDayStart, sDay, sExtraDay ;
  307.      SIZEF        sizfx ;
  308.      SIZEL        sizlCell ;
  309.  
  310.      GpiSavePS (hps) ;
  311.  
  312.                // Determine size of day cell
  313.  
  314.      sizlCell.cx = (psizlPage->cx - 1) / 7 ;
  315.      sizlCell.cy = (psizlPage->cy - 1) / 7 ;
  316.  
  317.                // Create the vector font and use it in the PS
  318.  
  319.      fat.usRecordLength  = sizeof fat ;
  320.      fat.fsSelection     = 0 ;
  321.      fat.lMatch          = 0 ;
  322.      fat.idRegistry      = 0 ;
  323.      fat.usCodePage      = GpiQueryCp (hps) ;
  324.      fat.lMaxBaselineExt = 0 ;
  325.      fat.lAveCharWidth   = 0 ;
  326.      fat.fsType          = 0 ;
  327.      fat.fsFontUse       = FATTR_FONTUSE_OUTLINE |
  328.                            FATTR_FONTUSE_TRANSFORMABLE ;
  329.  
  330.      strcpy (fat.szFacename, "Helv") ;
  331.  
  332.      GpiCreateLogFont (hps, NULL, LCID_CALFONT, &fat) ;
  333.      GpiSetCharSet (hps, LCID_CALFONT) ;
  334.  
  335.                // Scale the font for the month and year name
  336.  
  337.      lLength = sprintf (szBuffer, " %s %d ", apszMonths[sMonth], sYear) ;
  338.      GpiQueryTextBox (hps, lLength, szBuffer, TXTBOX_COUNT, aptlTextBox) ;
  339.      GpiQueryCharBox (hps, &sizfx) ;
  340.  
  341.      sizfx.cx = sizlCell.cx * sizfx.cx /  aptlTextBox[TXTBOX_CONCAT].x * 7 ;
  342.      sizfx.cy = sizlCell.cy * sizfx.cy / (aptlTextBox[TXTBOX_TOPLEFT].y -
  343.                                           aptlTextBox[TXTBOX_BOTTOMLEFT].y) ;
  344.  
  345.      sizfx.cx = sizfx.cy = min (sizfx.cx, sizfx.cy) ;
  346.      GpiSetCharBox (hps, &sizfx) ;
  347.      GpiQueryTextBox (hps, lLength, szBuffer, TXTBOX_COUNT, aptlTextBox) ;
  348.  
  349.                // Display month and year at top of page
  350.  
  351.      ptl.x = (psizlPage->cx - aptlTextBox[TXTBOX_CONCAT].x) / 2 ;
  352.      ptl.y =  6 * sizlCell.cy - aptlTextBox[TXTBOX_BOTTOMLEFT].y ;
  353.      GpiCharStringAt (hps, &ptl, lLength, szBuffer) ;
  354.  
  355.                // Set font size for day numbers
  356.  
  357.      sizfx.cx = sizfx.cy = MAKEFIXED (min (sizlCell.cx, sizlCell.cy) / 4, 0) ;
  358.      GpiSetCharBox (hps, &sizfx) ;
  359.  
  360.                // Calculate some variables for showing days in month
  361.  
  362.      fLeap = (sYear % 4 == 0) && ((sYear % 100 != 0) || (sYear % 400 == 0)) ;
  363.      sExtraDay = fLeap && sMonth == 1 ? 1 : 0 ;
  364.  
  365.      sDayStart  = 1 + sYear - 1900 + (sYear - 1901) / 4 ;
  366.      sDayStart += asMonthStart[sMonth] + (fLeap && sMonth > 1 ? 1 : 0) ;
  367.      sDayStart %= 7 ;
  368.  
  369.                // Loop through days
  370.  
  371.      for (sDay = 0 ; sDay < asMonthLen[sMonth] + sExtraDay ; sDay++)
  372.           {
  373.           ptl.x =      (sDayStart + sDay) % 7  * sizlCell.cx ;
  374.           ptl.y = (5 - (sDayStart + sDay) / 7) * sizlCell.cy ;
  375.           GpiMove (hps, &ptl) ;
  376.  
  377.           ptl.x += sizlCell.cx ;
  378.           ptl.y += sizlCell.cy ;
  379.           GpiBox (hps, DRO_OUTLINE, &ptl, 0L, 0L) ;
  380.  
  381.           lLength = sprintf (szBuffer, " %d", sDay + 1) ;
  382.           GpiQueryTextBox (hps, lLength, szBuffer, TXTBOX_COUNT, aptlTextBox) ;
  383.  
  384.           GpiQueryCurrentPosition (hps, &ptl) ;
  385.           ptl.y += sizlCell.cy - aptlTextBox[TXTBOX_TOPLEFT].y ;
  386.           GpiCharStringAt (hps, &ptl, lLength, szBuffer) ;
  387.           }
  388.                // Clean up
  389.  
  390.      GpiSetCharSet (hps, LCID_DEFAULT) ;
  391.      GpiDeleteSetId (hps, LCID_CALFONT) ;
  392.      GpiRestorePS (hps, -1L) ;
  393.      }
  394.  
  395. VOID Message (HWND hwnd, SHORT sIcon, CHAR *pszMessage)
  396.      {
  397.      WinMessageBox (HWND_DESKTOP, hwnd, pszMessage, "PrintCal",
  398.                     0, sIcon | MB_OK | MB_MOVEABLE) ;
  399.      }
  400.  
  401. VOID FAR PrintThread (THREADPARAMS *ptp)
  402.      {
  403.      HAB   hab ;
  404.      HDC   hdcPrinter ;
  405.      HPS   hpsPrinter ;
  406.      SHORT msgReturn ;
  407.      SHORT sMonth ;
  408.      SIZEL sizlPage ;
  409.  
  410.      hab = WinInitialize (0) ;
  411.  
  412.      if ((hdcPrinter = OpenDefaultPrinterDC (hab)) != DEV_ERROR)
  413.           {
  414.                     // Create the presentation space for the printer
  415.  
  416.           sizlPage.cx = 0 ;
  417.           sizlPage.cy = 0 ;
  418.           hpsPrinter = GpiCreatePS (hab, hdcPrinter, &sizlPage,
  419.                                     PU_ARBITRARY | GPIF_DEFAULT |
  420.                                     GPIT_MICRO   | GPIA_ASSOC) ;
  421.  
  422.           GpiQueryPS (hpsPrinter, &sizlPage) ;
  423.  
  424.                     // Start the document
  425.  
  426.           if (DevEscape (hdcPrinter, DEVESC_STARTDOC,
  427.                          8L, "Calendar", NULL, NULL) != DEVESC_ERROR)
  428.                {
  429.                         // Loop through months
  430.  
  431.                for (sMonth  = ptp->cp.sMonthBeg ;
  432.                     sMonth <= ptp->cp.sMonthEnd ; sMonth++)
  433.                     {
  434.                     DisplayPage (hpsPrinter, &sizlPage, ptp->cp.sYear, sMonth);
  435.  
  436.                     DevEscape (hdcPrinter, DEVESC_NEWFRAME,
  437.                                0L, NULL, NULL, NULL) ;
  438.                     }
  439.                          // End the document
  440.  
  441.                DevEscape (hdcPrinter, DEVESC_ENDDOC, 0L, NULL, NULL, NULL) ;
  442.                msgReturn = WM_USER_PRINT_OK ;
  443.                }
  444.           else
  445.                msgReturn = WM_USER_PRINT_ERROR ;
  446.  
  447.                     // Clean up
  448.  
  449.           GpiDestroyPS (hpsPrinter) ;
  450.           DevCloseDC (hdcPrinter) ;
  451.           }
  452.      else
  453.           msgReturn = WM_USER_PRINT_ERROR ;
  454.  
  455.                // Post message to client window and end thread
  456.  
  457.      DosEnterCritSec () ;
  458.      WinPostMsg (ptp->hwndNotify, msgReturn, MPFROMP (ptp), NULL) ;
  459.      WinTerminate (hab) ;
  460.      _endthread () ;
  461.      }
  462.