home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Hall of Fame
/
HallofFameCDROM.cdr
/
pcmag
/
v9n08.lzh
/
PRINTCAL.C
< prev
next >
Wrap
C/C++ Source or Header
|
1989-11-05
|
17KB
|
462 lines
/*---------------------------------------------------------------------
PRINTCAL.C -- OS/2 Presentation Manager program to print a calendar
(c) 1990, Ziff Communications Co.
PC Magazine * Charles Petzold, 10/89
---------------------------------------------------------------------*/
#define INCL_WIN
#define INCL_GPI
#define INCL_DEV
#define INCL_DOSPROCESS
#include <os2.h>
#include <mt\process.h>
#include <mt\stdio.h>
#include <mt\stdlib.h>
#include <mt\string.h>
#include "printcal.h"
#define LCID_CALFONT 1L
#define STACKSIZE (4096 * sizeof (int))
#define WM_USER_PRINT_OK (WM_USER + 0)
#define WM_USER_PRINT_ERROR (WM_USER + 1)
typedef struct
{
SHORT sYear, sMonthBeg, sMonthEnd ;
}
CALPARAMS ;
typedef struct
{
int aiThreadStack[STACKSIZE / sizeof (int)] ;
CALPARAMS cp ;
HWND hwndNotify ;
}
THREADPARAMS ;
MPARAM EXPENTRY ClientWndProc (HWND, USHORT, MPARAM, MPARAM) ;
MPARAM EXPENTRY AboutDlgProc (HWND, USHORT, MPARAM, MPARAM) ;
MPARAM EXPENTRY PrintDlgProc (HWND, USHORT, MPARAM, MPARAM) ;
VOID DisplayPage (HPS, SIZEL *, SHORT, SHORT) ;
VOID Message (HWND, SHORT, CHAR *) ;
VOID FAR PrintThread (THREADPARAMS *) ;
HDC OpenDefaultPrinterDC (HAB) ; // in PRINTDC.C
HAB hab ;
USHORT usActiveThreads = 0 ;
int main (void)
{
static CHAR szClientClass[] = "PrintCal" ;
static ULONG flFrameFlags = FCF_TITLEBAR | FCF_SYSMENU |
FCF_SIZEBORDER | FCF_MINMAX |
FCF_MENU |
FCF_SHELLPOSITION | FCF_TASKLIST ;
HMQ hmq ;
HWND hwndFrame, hwndClient ;
QMSG qmsg ;
hab = WinInitialize (0) ;
hmq = WinCreateMsgQueue (hab, 0) ;
WinRegisterClass (hab, szClientClass, ClientWndProc, CS_SIZEREDRAW, 0) ;
hwndFrame = WinCreateStdWindow (HWND_DESKTOP, WS_VISIBLE,
&flFrameFlags, szClientClass, NULL,
0L, NULL, ID_RESOURCE, &hwndClient) ;
while (TRUE)
{
while (WinGetMsg (hab, &qmsg, NULL, 0, 0))
WinDispatchMsg (hab, &qmsg) ;
if (usActiveThreads == 0)
break ;
Message (hwndClient, MB_ICONEXCLAMATION,
"Printing thread still active.\n"
"Program cannot be closed now.") ;
WinCancelShutdown (hmq, FALSE) ;
}
WinDestroyWindow (hwndFrame) ;
WinDestroyMsgQueue (hmq) ;
WinTerminate (hab) ;
return 0 ;
}
MPARAM EXPENTRY ClientWndProc (HWND hwnd, USHORT msg, MPARAM mp1, MPARAM mp2)
{
static CALPARAMS cp ;
static HPS hps ;
static SIZEL sizlClient ;
DATETIME dt ;
HDC hdc ;
SHORT sResult ;
SIZEL sizlPage ;
THREADPARAMS *ptp ;
switch (msg)
{
case WM_CREATE:
hdc = WinOpenWindowDC (hwnd) ;
sizlPage.cx = 0 ;
sizlPage.cy = 0 ;
hps = GpiCreatePS (hab, hdc, &sizlPage,
PU_ARBITRARY | GPIF_DEFAULT |
GPIT_MICRO | GPIA_ASSOC) ;
DosGetDateTime (&dt) ;
cp.sYear = dt.year ;
cp.sMonthBeg = dt.month - 1 ;
cp.sMonthEnd = dt.month - 1 ;
return 0 ;
case WM_SIZE:
sizlClient.cx = SHORT1FROMMP (mp2) ;
sizlClient.cy = SHORT2FROMMP (mp2) ;
GpiConvert (hps, CVTC_DEVICE, CVTC_PAGE, 1L,
(PPOINTL) &sizlClient) ;
return 0 ;
case WM_PAINT:
WinBeginPaint (hwnd, hps, NULL) ;
GpiErase (hps) ;
DisplayPage (hps, &sizlClient, cp.sYear, cp.sMonthBeg) ;
WinEndPaint (hps) ;
return 0 ;
case WM_COMMAND:
switch (COMMANDMSG(&msg)->cmd)
{
case IDM_ABOUT:
WinDlgBox (HWND_DESKTOP, hwnd, AboutDlgProc,
NULL, IDD_ABOUT, NULL) ;
return 0 ;
case IDM_PRINT:
sResult = WinDlgBox (HWND_DESKTOP, hwnd, PrintDlgProc,
NULL, IDD_PRINT, &cp) ;
if (sResult == DID_CANCEL)
return 0 ;
WinInvalidateRect (hwnd, NULL, FALSE) ;
if (sResult == IDD_PREVIEW)
return 0 ;
if ((ptp = malloc (sizeof (THREADPARAMS))) == NULL)
{
Message (hwnd, MB_ICONEXCLAMATION,
"Cannot allocate memory for print thread!") ;
return 0 ;
}
ptp->cp = cp ;
ptp->hwndNotify = hwnd ;
if (_beginthread (PrintThread, ptp->aiThreadStack,
STACKSIZE, ptp) == -1)
{
free (ptp) ;
Message (hwnd, MB_ICONEXCLAMATION,
"Cannot create print thread!") ;
return 0 ;
}
usActiveThreads++ ;
Message (hwnd, MB_ICONASTERISK,
"Print job successfully started.") ;
return 0 ;
}
break ;
case WM_USER_PRINT_OK:
ptp = PVOIDFROMMP (mp1) ;
free (ptp) ;
usActiveThreads-- ;
Message (hwnd, MB_ICONASTERISK,
"Print job sent to spooler.") ;
return 0 ;
case WM_USER_PRINT_ERROR:
ptp = PVOIDFROMMP (mp1) ;
free (ptp) ;
usActiveThreads-- ;
Message (hwnd, MB_ICONEXCLAMATION,
"Error encountered during printing.") ;
return 0 ;
case WM_DESTROY:
GpiDestroyPS (hps) ;
return 0 ;
}
return WinDefWindowProc (hwnd, msg, mp1, mp2) ;
}
MRESULT EXPENTRY AboutDlgProc (HWND hwnd, USHORT msg, MPARAM mp1, MPARAM mp2)
{
switch (msg)
{
case WM_COMMAND:
switch (COMMANDMSG(&msg)->cmd)
{
case DID_OK:
case DID_CANCEL:
WinDismissDlg (hwnd, TRUE) ;
return 0 ;
}
break ;
}
return WinDefDlgProc (hwnd, msg, mp1, mp2) ;
}
MRESULT EXPENTRY PrintDlgProc (HWND hwnd, USHORT msg, MPARAM mp1, MPARAM mp2)
{
static CALPARAMS cpLocal, *pcpCurrent ;
switch (msg)
{
case WM_INITDLG:
pcpCurrent = PVOIDFROMMP (mp2) ;
cpLocal = *pcpCurrent ;
WinSendDlgItemMsg (hwnd, IDD_MONTHBEG + cpLocal.sMonthBeg,
BM_SETCHECK, MPFROM2SHORT (TRUE, 0), NULL) ;
WinSendDlgItemMsg (hwnd, IDD_MONTHEND + cpLocal.sMonthEnd,
BM_SETCHECK, MPFROM2SHORT (TRUE, 0), NULL) ;
WinSendDlgItemMsg (hwnd, IDD_YEAR, EM_SETTEXTLIMIT,
MPFROM2SHORT (4, 0), NULL) ;
WinSetDlgItemShort (hwnd, IDD_YEAR, cpLocal.sYear, FALSE) ;
return 0 ;
case WM_CONTROL:
if (SHORT1FROMMP (mp1) >= IDD_MONTHBEG &&
SHORT1FROMMP (mp1) < IDD_MONTHBEG + 12)
cpLocal.sMonthBeg = SHORT1FROMMP (mp1) - IDD_MONTHBEG ;
else if (SHORT1FROMMP (mp1) >= IDD_MONTHEND &&
SHORT1FROMMP (mp1) < IDD_MONTHEND + 12)
cpLocal.sMonthEnd = SHORT1FROMMP (mp1) - IDD_MONTHEND ;
return 0 ;
case WM_COMMAND:
switch (COMMANDMSG(&msg)->cmd)
{
case DID_OK:
case IDD_PREVIEW:
WinQueryDlgItemShort (hwnd, IDD_YEAR,
&cpLocal.sYear, FALSE) ;
if (cpLocal.sYear < 1900 || cpLocal.sYear > 2099)
{
Message (hwnd, MB_ICONEXCLAMATION,
"Year must be between 1900 and 2099!") ;
WinSetFocus (HWND_DESKTOP,
WinWindowFromID (hwnd, IDD_YEAR)) ;
return 0 ;
}
if (cpLocal.sMonthBeg > cpLocal.sMonthEnd)
{
Message (hwnd, MB_ICONEXCLAMATION,
"Begin month cannot be later "
"than end month!") ;
WinSetFocus (HWND_DESKTOP,
WinWindowFromID (hwnd,
IDD_MONTHBEG + cpLocal.sMonthBeg)) ;
return 0 ;
}
*pcpCurrent = cpLocal ;
// fall through
case DID_CANCEL:
WinDismissDlg (hwnd, COMMANDMSG(&msg)->cmd) ;
return 0 ;
}
break ;
}
return WinDefDlgProc (hwnd, msg, mp1, mp2) ;
}
VOID DisplayPage (HPS hps, SIZEL *psizlPage, SHORT sYear, SHORT sMonth)
{
static CHAR *apszMonths[] = { "January", "February", "March",
"April", "May", "June",
"July", "August", "September",
"October", "November", "December" } ;
static SHORT asMonthLen[] = { 31, 28, 31, 30, 31, 30,
31, 31, 30, 31, 30, 31 } ;
static SHORT asMonthStart[] = { 0, 3, 3, 6, 1, 4,
6, 2, 5, 0, 3, 5 } ;
CHAR szBuffer[16] ;
BOOL fLeap ;
FATTRS fat ;
LONG lLength ;
POINTL ptl, aptlTextBox[TXTBOX_COUNT] ;
SHORT sDayStart, sDay, sExtraDay ;
SIZEF sizfx ;
SIZEL sizlCell ;
GpiSavePS (hps) ;
// Determine size of day cell
sizlCell.cx = (psizlPage->cx - 1) / 7 ;
sizlCell.cy = (psizlPage->cy - 1) / 7 ;
// Create the vector font and use it in the PS
fat.usRecordLength = sizeof fat ;
fat.fsSelection = 0 ;
fat.lMatch = 0 ;
fat.idRegistry = 0 ;
fat.usCodePage = GpiQueryCp (hps) ;
fat.lMaxBaselineExt = 0 ;
fat.lAveCharWidth = 0 ;
fat.fsType = 0 ;
fat.fsFontUse = FATTR_FONTUSE_OUTLINE |
FATTR_FONTUSE_TRANSFORMABLE ;
strcpy (fat.szFacename, "Helv") ;
GpiCreateLogFont (hps, NULL, LCID_CALFONT, &fat) ;
GpiSetCharSet (hps, LCID_CALFONT) ;
// Scale the font for the month and year name
lLength = sprintf (szBuffer, " %s %d ", apszMonths[sMonth], sYear) ;
GpiQueryTextBox (hps, lLength, szBuffer, TXTBOX_COUNT, aptlTextBox) ;
GpiQueryCharBox (hps, &sizfx) ;
sizfx.cx = sizlCell.cx * sizfx.cx / aptlTextBox[TXTBOX_CONCAT].x * 7 ;
sizfx.cy = sizlCell.cy * sizfx.cy / (aptlTextBox[TXTBOX_TOPLEFT].y -
aptlTextBox[TXTBOX_BOTTOMLEFT].y) ;
sizfx.cx = sizfx.cy = min (sizfx.cx, sizfx.cy) ;
GpiSetCharBox (hps, &sizfx) ;
GpiQueryTextBox (hps, lLength, szBuffer, TXTBOX_COUNT, aptlTextBox) ;
// Display month and year at top of page
ptl.x = (psizlPage->cx - aptlTextBox[TXTBOX_CONCAT].x) / 2 ;
ptl.y = 6 * sizlCell.cy - aptlTextBox[TXTBOX_BOTTOMLEFT].y ;
GpiCharStringAt (hps, &ptl, lLength, szBuffer) ;
// Set font size for day numbers
sizfx.cx = sizfx.cy = MAKEFIXED (min (sizlCell.cx, sizlCell.cy) / 4, 0) ;
GpiSetCharBox (hps, &sizfx) ;
// Calculate some variables for showing days in month
fLeap = (sYear % 4 == 0) && ((sYear % 100 != 0) || (sYear % 400 == 0)) ;
sExtraDay = fLeap && sMonth == 1 ? 1 : 0 ;
sDayStart = 1 + sYear - 1900 + (sYear - 1901) / 4 ;
sDayStart += asMonthStart[sMonth] + (fLeap && sMonth > 1 ? 1 : 0) ;
sDayStart %= 7 ;
// Loop through days
for (sDay = 0 ; sDay < asMonthLen[sMonth] + sExtraDay ; sDay++)
{
ptl.x = (sDayStart + sDay) % 7 * sizlCell.cx ;
ptl.y = (5 - (sDayStart + sDay) / 7) * sizlCell.cy ;
GpiMove (hps, &ptl) ;
ptl.x += sizlCell.cx ;
ptl.y += sizlCell.cy ;
GpiBox (hps, DRO_OUTLINE, &ptl, 0L, 0L) ;
lLength = sprintf (szBuffer, " %d", sDay + 1) ;
GpiQueryTextBox (hps, lLength, szBuffer, TXTBOX_COUNT, aptlTextBox) ;
GpiQueryCurrentPosition (hps, &ptl) ;
ptl.y += sizlCell.cy - aptlTextBox[TXTBOX_TOPLEFT].y ;
GpiCharStringAt (hps, &ptl, lLength, szBuffer) ;
}
// Clean up
GpiSetCharSet (hps, LCID_DEFAULT) ;
GpiDeleteSetId (hps, LCID_CALFONT) ;
GpiRestorePS (hps, -1L) ;
}
VOID Message (HWND hwnd, SHORT sIcon, CHAR *pszMessage)
{
WinMessageBox (HWND_DESKTOP, hwnd, pszMessage, "PrintCal",
0, sIcon | MB_OK | MB_MOVEABLE) ;
}
VOID FAR PrintThread (THREADPARAMS *ptp)
{
HAB hab ;
HDC hdcPrinter ;
HPS hpsPrinter ;
SHORT msgReturn ;
SHORT sMonth ;
SIZEL sizlPage ;
hab = WinInitialize (0) ;
if ((hdcPrinter = OpenDefaultPrinterDC (hab)) != DEV_ERROR)
{
// Create the presentation space for the printer
sizlPage.cx = 0 ;
sizlPage.cy = 0 ;
hpsPrinter = GpiCreatePS (hab, hdcPrinter, &sizlPage,
PU_ARBITRARY | GPIF_DEFAULT |
GPIT_MICRO | GPIA_ASSOC) ;
GpiQueryPS (hpsPrinter, &sizlPage) ;
// Start the document
if (DevEscape (hdcPrinter, DEVESC_STARTDOC,
8L, "Calendar", NULL, NULL) != DEVESC_ERROR)
{
// Loop through months
for (sMonth = ptp->cp.sMonthBeg ;
sMonth <= ptp->cp.sMonthEnd ; sMonth++)
{
DisplayPage (hpsPrinter, &sizlPage, ptp->cp.sYear, sMonth);
DevEscape (hdcPrinter, DEVESC_NEWFRAME,
0L, NULL, NULL, NULL) ;
}
// End the document
DevEscape (hdcPrinter, DEVESC_ENDDOC, 0L, NULL, NULL, NULL) ;
msgReturn = WM_USER_PRINT_OK ;
}
else
msgReturn = WM_USER_PRINT_ERROR ;
// Clean up
GpiDestroyPS (hpsPrinter) ;
DevCloseDC (hdcPrinter) ;
}
else
msgReturn = WM_USER_PRINT_ERROR ;
// Post message to client window and end thread
DosEnterCritSec () ;
WinPostMsg (ptp->hwndNotify, msgReturn, MPFROMP (ptp), NULL) ;
WinTerminate (hab) ;
_endthread () ;
}