#include "windows.h" #include #include "fontedit.h" #include "fcntl.h" #include /****************************************************************************/ /* Shared Variables */ /****************************************************************************/ POINT SnapPointToGrid(POINT Pt); LONG APIENTRY FontEditWndProc(HWND, WORD, WPARAM, LONG); BOOL APIENTRY AboutDlg( HWND hDlg, WORD message, WPARAM wParam, LPARAM lParam ); BOOL NewFile; /* flag indicating that NEW menu item was selected */ extern DLGPROC lpHeaderProc; /* Pointer to Dialog Box Procedure */ extern DLGPROC lpReSizeProc; /* Pointer to Dialog Box Procedure */ extern DLGPROC lpWidthProc; /* Pointer to Dialog Box Procedure */ extern FontHeaderType font; /* Structure of Font File Header */ extern CHAR matBox [wBoxLim] [kBoxLim]; /* array to hold Box */ extern HCURSOR hCross; /* handle to "+" shaped cursor(displayed when in ROW or COLUMN menus */ extern BOOL fReadOnly; extern HANDLE hInst; /* Module Handle */ extern HBRUSH hbrBackGround; extern HWND hFont; extern HWND hBox; extern RECT rectWin; /* Client Rectangle */ extern BOOL fLoaded; /* Set if a file loaded */ extern BOOL fChanged; /* Anything has changed */ extern BOOL fEdited; /* This character changed */ extern DWORD kBox; /* height of character */ extern DWORD wBox; /* Width of character */ extern DWORD kStuff; /* Width of Show Header */ extern INT swH; /* Position in Show Window 0-100 */ extern BYTE iChar; /* Character being edited */ extern BYTE jChar; /* Last Char. of edit block */ extern CHAR szNewFile[]; /* Name of New File */ extern CHAR szFontFile[]; /* Name of Font File */ extern CHAR szFontFileFull[]; /* Name of Font File */ extern CHAR szFileNameTemp[]; extern CHAR *szFileNameSave; extern INT cSysHeight; extern CHAR *vrgsz[]; /* total number of strings */ extern OFSTRUCT ofstrFile; extern CHAR szExt[]; /* default extension */ extern CHAR szAppName[]; extern CHAR szSCC[]; extern HCURSOR hOldCursor; /* handle to old arrow shaped cursor */ /****************************************************************************/ /* Local Variables */ /****************************************************************************/ HBRUSH hbrWhite; HBRUSH hbrBlack; HBRUSH hbrGray; HBRUSH hbrDkGray; HBRUSH hNullBrush; HPEN hWhitePen; DWORD colors[3] = {WHITENESS, BLACKNESS, PATCOPY}; CHAR matBackup [wBoxLim] [kBoxLim]; /* Backup for UNDO */ DWORD wBoxBackup; LONG scale = 7; /* height/width of squares in box */ WORD cursor = 0; /* Add/Del cursor */ BOOL fAll = TRUE; /* Redraw all if TRUE */ POINT ptBox = {10, 5}; /* where edit box is */ RECT rectRubber; /* Rubber banding rectangle */ HDC hDst; /* Rubber banding dc */ POINT ptA; /* Start of draw/rectangle */ POINT ptB; /* End of rectangle */ POINT ptC; /* Current square */ CHAR colorA; /* Color at/under point A */ DWORD newWidth; /* Width set in WIDER option */ BOOL FillingRect = FALSE; BOOL fRubberBanding = FALSE; /* flag indicating if rubberbanding in progress for row/column add/delete */ BOOL fStartRubberBand = FALSE; /* flag indicating that rubberbanding can start */ BOOL fCaptured = FALSE; /* set if mouse is caputred */ BOOL fJustZapped = FALSE; /* Set on row/col add/delete */ RECT FontRect; /* rectangle bounding font pattern */ /****************************************************************************/ /* Local Functions */ /****************************************************************************/ VOID ClearFill(DWORD col, DWORD row, WORD mode); VOID FontEditCommand(HWND hBox, WORD id); VOID BoxRestore(VOID); VOID CharRectDimensions(LPRECT Rect); VOID BoxPaint(VOID); VOID DrawBox(HDC, DWORD, DWORD, DWORD, DWORD, INT, DWORD); VOID PASCAL DrawRubberBand(HDC hDst, LPRECT lpRect, DWORD rop); VOID FontEditPaint(HWND hBox, HDC hDC); BOOL CheckSave(VOID); VOID DupCol(DWORD col, DWORD row); VOID DupRow(DWORD col, DWORD row); VOID ZapCol(DWORD col, DWORD row); VOID ZapRow(DWORD col, DWORD row); VOID AddDel(DWORD col, DWORD row, WORD mode); VOID MouseInBox(HWND hBox, WORD message, POINT ptMouse); VOID BoxBackup(VOID); VOID ReadRect(VOID); /*****************************************************************************/ VOID BoxPaint( VOID ) /* Our call to FontEditPaint */ { HDC hDC; hDC = GetDC(hBox); FontEditPaint(hBox, hDC); ReleaseDC(hBox, hDC); if (fRubberBanding) DrawRubberBand(hDst, &rectRubber, R2_XORPEN); } /****************************************************************************** * FontEditPaint(hBox, hDC) * * purpose: calculates coordinates for text in main window and repaints edit * box,small character boxes and text * * params: HWND hBox : handle to main window * HDC hDC I handle to display context * returns: none * * side effects: alters matBox (global 2-d array with ready pixel info. on * currently displayed box) *****************************************************************************/ VOID FontEditPaint( HWND hBox, HDC hDC ) { CHAR szTemp[20]; DWORD len, yText, xText; if (!fLoaded) /* Must load font first */ return; /* Here the application paints its window. */ if (fAll) { /* Draw box setting */ GetClientRect(hBox, (LPRECT)&rectWin); scale = (rectWin.bottom-rectWin.top-kStuff-20) / (kBox+1); scale = min(scale, (min(320, rectWin.right - rectWin.left) - 90) / ((int)wBox + 1)); scale = max(scale, 4); xText = ptBox.x + scale * wBox + 16; SelectObject(hDC, hbrDkGray); Rectangle(hDC, ptBox.x - 2, ptBox.y - 2, ptBox.x + 3 + wBox * scale, ptBox.y + 5 + kBox * scale); SelectObject(hDC, hbrGray); Rectangle(hDC, /* Surround for font displays */ xText, ptBox.y - 2, xText + wBox + 8, ptBox.y + 3 + kBox * 2 + font.ExtLeading); /* Now put up the text */ yText = 14 + 2 * kBox + font.ExtLeading; len = (DWORD) sprintf(szTemp, vszCHAR, iChar); TextOut(hDC, xText, yText, (LPSTR)szTemp, len); len = (DWORD) sprintf(szTemp, vszWIDTH, wBox); TextOut(hDC, xText, yText + cSysHeight, (LPSTR)szTemp, len); len = (DWORD) sprintf(szTemp, vszHEIGHT, kBox); TextOut(hDC, xText, yText + cSysHeight + cSysHeight, (LPSTR)szTemp, len); } /* Draw Character Box */ DrawBox(hDC, ptBox.x, ptBox.y, wBox, kBox, scale, 1); /* Draw small character */ xText = ptBox.x + scale * wBox + 16; DrawBox(hDC, xText + 4, ptBox.y, wBox, kBox, 1, 0); /* Draw another small character to show leading */ DrawBox(hDC, xText + 4, ptBox.y + kBox + font.ExtLeading, wBox, kBox, 1, 0); fAll = TRUE; } /****************************************************************************** * DrawBox(hDC, xChar, yChar, wChar, kChar, scale, htSep) * * purpose: draws the edit box for the character being edited and colors the * grid squares according to the pixels set for the character. * * params: HDC hDC : handle to display context * DWORD xChar : x-location of char box. * DWORD yChar : y-location of char box * DWORD wChar : width of char box * DWORD kChar : height of char * INT wScale : Scale of the squares. * DWORD htSep : height of square separators * * returns: none * * side effects: alters matBox (global 2-d array with ready pixel info. on * currently displayed box) *****************************************************************************/ VOID DrawBox( HDC hDC, DWORD xChar, /* x-location of char. */ DWORD yChar, /* y-location of char. */ DWORD wChar, /* width of char. */ DWORD kChar, /* height of char */ INT wScale, /* scale of the squares. */ DWORD htSep /* hgt of square separators */ ) /* draw a character of separate squares of height 'scale' with sep. 'htSep' */ { DWORD i, j, sep; if (fAll) { /* redraw them all */ for (j = 0; j < kChar; j++) { sep = (j >= font.Ascent) ? htSep : 0; for (i = 0; i < wChar; i++) { if (wScale == 1) SetPixel(hDC, xChar + i, yChar + j, matBox[i][j] == TRUE ? BLACK : WHITE); else PatBlt(hDC, xChar + wScale * i, yChar + wScale * j + sep, wScale - htSep, wScale - htSep, colors[matBox[i][j] == TRUE ? 1 : 0]); } } } else { /* redraw one just flipped */ if (wScale == 1) SetPixel(hDC, xChar + ptC.x, yChar + ptC.y, matBox[ptC.x][ptC.y] == TRUE ? BLACK : WHITE); else { sep = (((DWORD) ptC.y >= font.Ascent) ? htSep : 0L); SelectObject(hDC, hbrGray); PatBlt(hDC, xChar + wScale * ptC.x, yChar + wScale * ptC.y + sep, wScale - htSep, wScale - htSep, colors[matBox[ptC.x][ptC.y]]); } } } /****************************************************************************** * FontEditCommand(hBox, id) * * purpose: interprets menu id and calls appropriate function to do the task * * params: HWND hBox : handle to main window * WORD id : menu command id * returns: none * * side effects: plenty * *****************************************************************************/ VOID FontEditCommand( HWND hBox, WORD id ) { CHAR * szError; /* String for error messages */ LONG w; DWORD y, i, j; BOOL fRepaint = FALSE; HMENU hMenu; DLGPROC lpprocAboutDlg; MSG message; szError = ""; /* No Errors yet */ switch (id) { case FONT_EXIT: if (!CheckSave()) /* See if any files need saving */ break; /* Window's being destroyed. */ if (fLoaded) /* 4/8/87 Linsh added */ DeleteGlobalBitmap(); /* Get rid of memory DC */ PostQuitMessage(0); /* Cause application to be terminated */ break; case FONT_ABOUT: lpprocAboutDlg = (DLGPROC)AboutDlg; DialogBox (hInst, vszABOUT, hBox, lpprocAboutDlg); FreeProcInstance (lpprocAboutDlg); break; case FONT_LOAD: /* Check File Name */ case FONT_NEW : if (!CheckSave()) /* See if current font needs saving */ return; /* to prevent scrambling of Show window chars, Bring back Show ** window to parent window's client area before invoking the dialog */ if (CommDlgOpen(hBox,&ofstrFile,szNewFile,szExt,szFontFile,id) == FALSE) { InvalidateRect(hFont, (LPRECT)NULL, FALSE); UpdateWindow(hFont); return; } /* else drop thru */ case FONT_START: /* Here if file name passed as argument */ InvalidateRect(hFont, (LPRECT)NULL, FALSE); UpdateWindow(hFont); szError = FontLoad (szNewFile, &ofstrFile); /* Hack : needed to remove umwanted WM_MOUSEMOVE messages from the * queue. * Apparently, Windows needs to reposition the mouse after a dialog * is ended with a mouse double-click (releases mouse capture?) for * which a couple of WM_MOUSEMOVEs may get sent to parent app. * These mess with the edit box below the dialog if they happen to * overlap. */ PeekMessage((LPMSG) &message, hBox, WM_MOUSEMOVE, WM_MOUSEMOVE, PM_REMOVE); if (fLoaded) /* If loaded then do a few things */ { jChar = iChar = 65; /* Show an A */ if ((BYTE)iChar > (BYTE)font.LastChar) jChar = iChar = font.FirstChar; /* .. if we can */ swH = 15; /* Good bet to make A visible */ fEdited = fChanged = FALSE; ResizeShow(); /* Set Box to proper size */ ScrollFont(); /* Set thumb */ CharToBox(iChar); } FontRename(szError); SetFocus(hBox); return; case FONT_SAVE: if (!NewFile) { if (fLoaded && fChanged) { lstrcpy((LPSTR)szNewFile, (LPSTR)szFontFileFull); BoxToChar(iChar); /* Just in case */ szError = FontSave (szNewFile, &ofstrFile); FontRename(szError); /* Rename or Print Error */ return; } else return; } /* else file has been opened by selecting NEW... on menu. * Fall thro' and bring up SaveAs dialog minus default * filename in edit window */ case FONT_SAVEAS: BoxToChar(iChar); /* Just in case */ if (CommDlgSaveAs (hInst, hBox, &ofstrFile, szNewFile, szExt, szFontFile) == TRUE) { szError = FontSave (szNewFile, &ofstrFile); FontRename (szError); /* Rename or Print Error */ } /* to prevent scrambling of Show window chars, repaint show window after dialog is brought down */ InvalidateRect (hFont, (LPRECT)NULL, TRUE); UpdateWindow (hFont); return; case FONT_HEADER: /* to prevent scrambling of Show window chars, * repaint show window after dialog is invoked */ DialogBox(hInst, (LPSTR)vszDHeader, hBox, lpHeaderProc); InvalidateRect(hFont, (LPRECT)NULL, TRUE); UpdateWindow(hFont); return; case FONT_RESIZE: /* to prevent scrambling of Show window chars, repaint show window after dialog is brought down */ if (DialogBox(hInst, (LPSTR)vszDResize, hBox, lpReSizeProc)) { /* BoxToChar(iChar);*/ /* save current before resizing */ ResizeShow(); /* New Font Display Size */ CharToBox(iChar); /* New Box display */ } InvalidateRect(hFont, (LPRECT)NULL, TRUE); UpdateWindow(hFont); return; case FONT_COPY: /* Copy to Clipboard */ BoxToChar(iChar); /* Just in case */ ToClipboard(iChar, wBox, kBox); break; case FONT_PASTE: /* Paste in Character form Clipboard */ BoxBackup(); /* In case we change our minds */ ptA.x = ptA.y = 0; wBox = ClipboardToBox(ptA, wBox, kBox, TRUE); fRepaint = TRUE; break; case WIDER_LEFT: case WIDER_RIGHT: case WIDER_BOTH: case NARROWER_LEFT: case NARROWER_RIGHT: case NARROWER_BOTH: case WIDTH: w = newWidth = wBox; if (font.Family & 1) /* Variable width or else */ { switch (id) { case WIDER_BOTH: w++; case WIDER_LEFT: case WIDER_RIGHT: w++; break; case NARROWER_BOTH: w--; case NARROWER_LEFT: case NARROWER_RIGHT: w--; break; case WIDTH: if (DialogBox(hInst, (LPSTR)vszDWidth, hBox, lpWidthProc)) w = newWidth; break; } if (w < 0 || w >= wBoxLim) { MessageBox(hBox, (LPSTR)vszEdLimits0To64, (LPSTR)szAppName, MB_OK | MB_ICONASTERISK); break; /* Out of range! quit */ } if (w > (LONG) font.MaxWidth) { if (IDOK == MessageBox(hBox, (LPSTR)vszMaxWidthIncrease, (LPSTR)szAppName, MB_OKCANCEL | MB_ICONQUESTION)) font.MaxWidth = (WORD)w; else break; } BoxBackup(); /* In case we change our minds */ wBox = (WORD)w; /* Reset width */ fRepaint = TRUE; /* Signal redraw */ switch (id) { case WIDER_LEFT: DupCol(0, kBoxLim - 1); for (y = 0; y < kBoxLim; y++) matBox[0][y] = FALSE; /* Clear left column */ break; case WIDER_BOTH: /* Shift character one right */ DupCol(0, kBoxLim - 1); for (y = 0; y < kBoxLim; y++) matBox[wBox -1][y] = FALSE; /* Clear right column */ for (y = 0; y < kBoxLim; y++) matBox[0][y] = FALSE; /* Clear left column */ break; case NARROWER_LEFT: case NARROWER_BOTH: /* Shift character one left */ if (wBox) { /* .. unless width is already 0 */ for (j = 0; j <= kBox - 1; j++) for (i = 0; i <= wBox - 1; i++) matBox[i][j] = matBox[i + 1][j]; break; } } } else { MessageBox(hBox, (LPSTR)vszCannotChangeWidth, (LPSTR)szAppName, MB_OK | MB_ICONASTERISK); } break; case ROW_ADD: case ROW_DEL: case COL_ADD: case COL_DEL: /* set cursor to "+" shaped cursor */ SetCapture (hBox); /* so that cursor doesn't get restored before we are done */ hOldCursor = SetCursor (LoadCursor (NULL, IDC_CROSS)); fCaptured = TRUE; cursor = id; break; case BOX_CLEAR: case BOX_FILL: case BOX_INV: case BOX_HATCH: case BOX_LEFTRIGHT: case BOX_TOPBOTTOM: case BOX_COPY: case BOX_PASTE: /* Get one o' da funky cursors */ SetCapture(hBox); hOldCursor = SetCursor(LoadCursor(hInst, MAKEINTRESOURCE(id))); fStartRubberBand = TRUE; CharRectDimensions((LPRECT)&FontRect); cursor = id; break; case BOX_REFRESH: /* Go get old version of character */ BoxBackup(); /* In case we change our minds */ CharToBox(iChar); hMenu = GetMenu(hBox); EnableMenuItem(hMenu, BOX_UNDO, MF_ENABLED); /* Can Unrefresh! */ break; case BOX_UNDO: BoxRestore(); hMenu = GetMenu(hBox); EnableMenuItem(hMenu, BOX_REFRESH, MF_ENABLED); fRepaint = TRUE; break; } if (fRepaint) { fEdited = fChanged = TRUE; InvalidateRect(hBox, (LPRECT)NULL, TRUE); } } VOID CharRectDimensions( LPRECT Rect ) /* returns the dimensions of the edit box */ { Rect->top = ptBox.y; Rect->bottom = ptBox.y + (kBox) * (scale); Rect->left = ptBox.x; Rect->right = ptBox.x + (wBox) * (scale); } /****************************************************************************** * BOOL APIENTRY WidthProc(hDial, message, wParam, lParam) * * purpose: dialog function for Width menu function * * params: same as for all dialog fns. * * side effects: changes Box width variable * *****************************************************************************/ BOOL APIENTRY WidthProc( HWND hDial, WORD message, WPARAM wParam, LPARAM lParam ) { INT i; BOOL fOk; UNREFERENCED_PARAMETER(lParam); switch (message) { default: return FALSE; case WM_INITDIALOG: SetDlgItemInt(hDial, BOX_WIDTH, newWidth, FALSE); break; case WM_COMMAND: switch (LOWORD(wParam)) { case IDOK: fChanged = TRUE; i = GetDlgItemInt(hDial, BOX_WIDTH, (LPBOOL)&fOk, FALSE); if (fOk && i < wBoxLim) newWidth = i; else ErrorBox(hDial, vszWidthOutOfBounds); case IDCANCEL: EndDialog(hDial, LOWORD(wParam) != IDCANCEL); break; default: break; } } return TRUE; } /****************************************************************************** * BOOL CheckSave() * * purpose: checks if font is dirty and prompts user to save font. If yes, * edit box is saved and file save function is called. * * params: none * * returns: TRUE : font has been changed * FALSE: font untouched * * side effects: file dirty flag is reset. * *****************************************************************************/ BOOL CheckSave( VOID ) { CHAR * szError; /* String for error messages */ CHAR szMessage[MAX_STR_LEN+MAX_FNAME_LEN]; /* Check if anything changed */ if (fLoaded && fChanged && (!fReadOnly)) { lstrcpy((LPSTR)szNewFile, (LPSTR)szFontFileFull); DlgMergeStrings(szSCC, szNewFile, szMessage); switch (MessageBox(hFont, (LPSTR)szMessage, (LPSTR)szAppName, MB_YESNOCANCEL | MB_ICONQUESTION)) { case IDYES: BoxToChar(iChar); /* Just in case */ szError = FontSave (szNewFile, &ofstrFile); FontRename(szError); /* Rename or Print Error */ case IDNO: return TRUE; case IDCANCEL: return FALSE; } } return TRUE; } /****************************************************************************** * MouseInBox(hBox, message, ptMouse) * * purpose: do edit operation depending on currently active menu command * * params: HWND hBox : handle to main window * WORD message : Message retrieved by main window's window fn. * POINT ptMouse : current mouse coordinates * returns: none * * side effects: alters matBox (global 2-d array with ready pixel info. on * currently displayed box). Also assigns values to ptA and ptB *****************************************************************************/ VOID MouseInBox( HWND hBox, WORD message, POINT ptMouse ) { POINT pt; BOOL fRepaint = FALSE; short nct = 0 ; pt = SnapPointToGrid(ptMouse); if (pt.x >= 0L && pt.y >= 0L && ((DWORD)pt.x) < wBox && ((DWORD)pt.y) < kBox) { fEdited = fChanged = TRUE; ptC.x = pt.x; ptC.y = pt.y; /* Current square */ if (message == WM_LBUTTONDOWN) BoxBackup(); /* Set up for UNDO */ switch (cursor) { case BOX_COPY: case BOX_PASTE: case BOX_CLEAR: case BOX_FILL: case BOX_INV: case BOX_HATCH: case BOX_LEFTRIGHT: case BOX_TOPBOTTOM: ptA.x = pt.x; ptA.y = pt.y; /* save anchor point */ /* save color under marker */ colorA = matBox[pt.x][pt.y]; fAll = FALSE; fRepaint = TRUE; break; default: AddDel(pt.x, pt.y, cursor); fRepaint = TRUE; cursor = FALSE; break; case FALSE: switch (message) { case WM_LBUTTONDOWN: /*invert */ nct =1 ; colorA = (matBox[pt.x][pt.y] ^= TRUE); break; case WM_LBUTTONUP: break; case WM_MOUSEMOVE: matBox[pt.x][pt.y] = colorA; /* paint */ break; } /* if( nct != 0 ) { */ fRepaint = TRUE; fAll = FALSE; /* Limited redraw */ /* } */ break; } if (fRepaint) { BoxPaint(); return; } } cursor = FALSE; } /****************************************************************************** * ReadRect(ptMouse) * * purpose: defines the rectangular region in edit box to be filled by * fill menu command by fixing top left (ptA) and bottom right * (ptB) coordinates of rect. * * params: * * assumes: that rectRubber is normalized (eg, left < right, botton > top) * * returns: none * * side effects: alters matBox (global 2-d array with ready pixel info. on * currently displayed box). Also assigns values to ptA and ptB *****************************************************************************/ VOID ReadRect( ) { ptA.x = (rectRubber.left-(ptBox.x+1)) / scale; ptA.y = (rectRubber.top-(ptBox.y+1)) / scale; ptB.x = (rectRubber.right-(ptBox.x-2)) / scale - 1; ptB.y = (rectRubber.bottom-(ptBox.y-2)) / scale - 1; if (((DWORD)ptB.x) > wBox - 1) ptB.x = wBox - 1; if (((DWORD)ptB.y) > kBox - 1) ptB.y = kBox - 1; if (ptB.x >= 0 && ptB.y >= 0) { ClearFill((DWORD)ptB.x, (DWORD)ptB.y, cursor); BoxPaint(); } cursor = FALSE; } /****************************************************************************** * ClearFill(col, row, mode) * * purpose: fill the specified rectangular region in edit box with fill type * indicated by mode.Top left corner of rect is global(ptA) * * params: DWORD row : row (of bottom right corner of rect(ptB.x)) * DWORD col : column (of bottom right corner of rect(ptB.y)) * WORD mode: action to be performed * * returns: none * * side effects: alters matBox (global 2-d array with ready pixel info. on * currently displayed box) *****************************************************************************/ VOID ClearFill( DWORD col, DWORD row, WORD mode ) { DWORD i, x, y; CHAR z; if (col < (DWORD)ptA.x) /* if points are reversed */ { i = col; col = ptA.x; ptA.x = i; } /* flip them */ if (row < (DWORD) ptA.y) { i = row; row = ptA.y; ptA.y = i; } /* flip them */ if (mode == BOX_LEFTRIGHT) { for (x = ptA.x; x <= (DWORD)((ptA.x + col) / 2); x++) for (y = ptA.y; y <= row; y++) { z = matBox[x][y]; matBox[x][y] = matBox[ptA.x + col - x][y]; matBox[ptA.x + col - x][y] = z; } return; } if (mode == BOX_TOPBOTTOM) { for (y = ptA.y; y <= ((DWORD)(ptA.y + row) / 2); y++) for (x = ptA.x; x <= col; x++) { z = matBox[x][y]; matBox[x][y] = matBox[x][ptA.y + row - y]; matBox[x][ptA.y + row - y] = z; } return; } if (mode == BOX_COPY) BoxToClipboard(ptA, col - ptA.x + 1, row - ptA.y + 1); if (mode == BOX_PASTE) ClipboardToBox(ptA, col - ptA.x + 1, row - ptA.y + 1, FALSE); for (x = ptA.x; x <= col; x++) for (y = ptA.y; y <= row; y++) { switch (mode) { case BOX_CLEAR: case BOX_FILL: matBox[x][y] = (CHAR)(mode == BOX_FILL); break; case BOX_INV: matBox[x][y] ^= (CHAR)TRUE; break; case BOX_HATCH: matBox[x][y] = (CHAR)((x+y)%2 ? TRUE : FALSE); break; } } } /****************************************************************************** * AddDel(col, row, mode) * * purpose: Add/Delete row/col as per mode * * params: DWORD row : row * DWORD col : column * WORD mode: action to be performed * * returns: none * * side effects: alters matBox (global 2-d array with ready pixel info. on * currently displayed box) *****************************************************************************/ VOID AddDel( DWORD col, DWORD row, WORD mode ) { switch (mode) { case ROW_ADD: DupRow(wBox, row); break; case ROW_DEL: ZapRow(wBox, row); break; case COL_ADD: DupCol(col, kBox); break; case COL_DEL: ZapCol(col, kBox); break; } /* restore arrow cursor */ SetCursor (hOldCursor); ReleaseCapture(); fCaptured = FALSE; fJustZapped = TRUE; } /****************************************************************************** * ZapCol(col, row) * * purpose: delete given column in edit box. Shift cols to right given col * right. Rightmost column gets duplicated. * * params : DWORD col : column * DWORD row : row * returns: none * * side effects: alters matBox (global 2-d array with ready pixel info. on * currently displayed box) *****************************************************************************/ VOID ZapCol( DWORD col, DWORD row ) { DWORD x, y; for (y = 0; y <= row; y++) for (x = col; x < wBox - 1; x++) matBox[x][y] = matBox[x + 1][y]; for (y = 0; y <= row; y++) matBox[x][y] = matBox[x - 1][y]; } /****************************************************************************** * ZapRow(col, row) * * purpose: delete given row in edit box. Shift rows below given row up. Lowest * row gets duplicated * * params: DWORD col : column * DWORD row : row * returns: none * * side effects: alters matBox (global 2-d array with ready pixel info. on * currently displayed box) *****************************************************************************/ VOID ZapRow( DWORD col, DWORD row ) { DWORD x, y; for (x = 0; x <= col; x++) for (y = row; y < kBox - 1; y++) matBox[x][y] = matBox[x][y + 1]; for (x = 0; x <= col; x++) matBox[x][y] = matBox[x][y - 1]; } /****************************************************************************** * DupCol(col, row) * * purpose: duplicate given column in edit box. Shift cols to right of given * col right * * params: DWORD col : column * DWORD row : row * returns: none * * side effects: alters matBox (global 2-d array with ready pixel info. on * currently displayed box) *****************************************************************************/ VOID DupCol( DWORD col, DWORD row ) { DWORD x, y; for (x = wBox - 1; x > col; x--) for (y = 0; y <= row; y++) matBox[x][y] = matBox[x - 1][y]; } /****************************************************************************** * DupRow(col, row) * * purpose: duplicate given row in edit box. Shift rows below given row down. * * params: DWORD col : column * DWORD row : row * returns: none * * side effects: alters matBox (global 2-d array with ready pixel info. on * currently displayed box) *****************************************************************************/ VOID DupRow( DWORD col, DWORD row ) { DWORD x, y; for (x = 0; x <= col; x++) for (y = kBox - 1; y > row; y--) matBox[x][y] = matBox[x][y - 1]; } /****************************************************************************** * ClearBox(col, row, bb) * * purpose: reset all pixels in edit box (make box white) * * params : none * * returns: none * * side effects: alters matBox (global 2-d array with ready pixel info. on * currently displayed box) * *****************************************************************************/ VOID ClearBox( VOID ) /* Clear edit box */ { DWORD x, y; for (x = 0; x < wBoxLim; x++) for (y = 0; y < kBoxLim; y++) matBox[x][y] = FALSE; } /****************************************************************************** * BoxBackup() * * purpose: makes a backup of pix. info. of currently displayed edit box * * params: none * * returns: none * * side effects: alters matBackup (local 2-d array with backup pixel info. * on edit box ) *****************************************************************************/ VOID BoxBackup( VOID ) { DWORD x, y; HMENU hMenu; hMenu = GetMenu(hBox); EnableMenuItem(hMenu, BOX_UNDO, MF_ENABLED); EnableMenuItem(hMenu, BOX_REFRESH, MF_ENABLED); for (x = 0; x < wBoxLim; x++) for (y = 0; y < kBoxLim; y++) matBackup[x][y] = matBox[x][y]; wBoxBackup = wBox; } /****************************************************************************** * BoxRestore() * * purpose : Current edit box and backup box exchange places * * params : none * * returns : none * * side effects: alters matBox (global 2-d array with ready pixel info. on * currently displayed box * *****************************************************************************/ VOID BoxRestore( VOID ) /* Box and Backup exchange places */ { DWORD x, y, temp; CHAR z; for (x = 0; x < wBoxLim; x++) for (y = 0; y < kBoxLim; y++) { z = matBackup[x][y]; matBackup[x][y] = matBox[x][y]; matBox[x][y] = z; } temp = wBox; wBox = wBoxBackup; wBoxBackup = temp; } /****************************************************************************** * POINT SnapPointToGrid (Pt) * * purpose : Intended only for the Fill menu command where rubberbanding rect. * needs to be aligned on the grid lines. Snap the current mouse * coordinates to nearest grid intersection. * * params : POINT Pt : current point mouse is over * * returns : POINT : number of nearest square * * side effects: : current mouse coordinate(global variable) altered to * return value * *****************************************************************************/ POINT SnapPointToGrid( POINT Pt ) { Pt.x = (Pt.x - ptBox.x) / scale; if (Pt.y > (scale * (font.Ascent - 1))) Pt.y = Pt.y - 2; /* Allow for break in box */ Pt.y = (Pt.y - ptBox.y) / scale; return (Pt); } /****************************************************************************** * VOID PASCAL EndRubberBandingRect() * * purpose: Stops rubberbanding rect for Fill menu command and cleans up * * params : HANDLE hDst : handle to dest. DC * * side effects: none * *****************************************************************************/ VOID PASCAL EndRubberBandingRect( HDC hDst /* handle to dest. DC */ ) { fRubberBanding = FALSE; /* reset "in-progress" flag */ ReleaseDC(hBox, hDst); ReleaseCapture(); SetCursor(hOldCursor); } /****************************************************************************** * HDC PASCAL InitialiseRubberBandingRect(hBox) * * purpose: Sets up rubberbanding rect for Fill menu command. * * params : HANDLE hDst : handle to box DC * * returns :handle to destination display context * * side effects: alters few global flags for rubberbanding * *****************************************************************************/ HDC PASCAL InitialiseRubberBandingRect( HDC hBox /* handle to DC of box */ ) { HDC hDst; fRubberBanding = TRUE; /* set "in-progress" flag */ fStartRubberBand = FALSE; /* reset "start-proceedings" flag */ SetCapture(hBox); /* send all msgs to current window */ hDst = GetDC (hBox); /* select pen and fill mode for rectangle*/ hWhitePen = SelectObject(hDst, GetStockObject (WHITE_PEN)); hNullBrush = SelectObject(hDst, GetStockObject (NULL_BRUSH)); SetROP2(hDst, R2_XORPEN); return(hDst); } /****************************************************************************** * VOID PASCAL DrawRubberBand() * * purpose: Draw rubberbanding rect for Fill menu command. * * params : HANDLE hDst : handle to dest. DC * * side effects: alters few global flags for rubberbanding * *****************************************************************************/ VOID PASCAL DrawRubberBand( HDC hDst, /* handle to dest. DC */ LPRECT lpRect, DWORD rop ) { #ifdef DBG char buf[256]; SIZE Size; static LONG cxPrev; INT nLeftRect; #endif SetROP2(hDst, rop); Rectangle(hDst, lpRect->left, lpRect->top, lpRect->right, lpRect->bottom); #ifdef DBG sprintf(buf, "left=%d, top=%d, right=%d, bottom=%d", lpRect->left, lpRect->top, lpRect->right, lpRect->bottom); GetTextExtentPoint32(hDst, buf, lstrlen(buf), &Size); nLeftRect = ptBox.x+scale*wBox+16 + Size.cx; if(nLeftRect < cxPrev) { RECT rc; rc.left = nLeftRect; rc.top = 14+2*kBox+font.ExtLeading+3*cSysHeight; rc.right = cxPrev; rc.bottom = 14+2*kBox+font.ExtLeading+3*cSysHeight + Size.cy; FillRect(hDst, &rc, hbrBackGround); } cxPrev = nLeftRect; TextOut(hDst, ptBox.x+scale*wBox+16, 14+2*kBox+font.ExtLeading+3*cSysHeight, buf, strlen(buf)); #endif } /****************************************************************************** * long APIENTRY FontEditWndProc(hBox, message, wParam, lParam) * * purpose: Master controller for Fontedit's all-encompassing main window * * params : same as for all window functions * * side effects: countless * *****************************************************************************/ LONG APIENTRY FontEditWndProc( HWND hBox, WORD message, WPARAM wParam, LPARAM lParam ) { PAINTSTRUCT ps; HMENU hMenu; WORD mf; POINT pt; RECT BoxRect; switch (message) { case WM_CLOSE: if (!CheckSave()) /* See if any files need saving */ break; /* Window's being destroyed. */ if (fLoaded) /* 4/8/87 Linsh added */ DeleteGlobalBitmap(); /* Get rid of memory DC */ DestroyWindow(hFont); DestroyWindow(hBox); break; case WM_DESTROY: PostQuitMessage(0); /* Cause application to be terminated */ break; case WM_QUERYENDSESSION: if (CheckSave()) /* See if any files need saving */ return TRUE; break; case WM_ENDSESSION: if (fLoaded) DeleteGlobalBitmap(); /* Get rid of memory DC */ break; case WM_SIZE: /* Window's size is changing. lParam contains the width ** and height, in the low and high words, respectively. ** wParam contains SIZENORMAL for "normal" size changes, ** SIZEICONIC when the window is being made iconic, and ** SIZEFULLSCREEN when the window is being made full screen. */ switch (wParam) { case SIZEFULLSCREEN: case SIZENORMAL: ResizeShow(); if (kStuff != GetkStuff()) /* Did it change ? */ ResizeShow(); /* Yes resize again */ break; } break; case WM_MOVE: /* Tell popup to move with us. */ if (!IsIconic(hBox)) ResizeShow(); break; case WM_PAINT: /* Time for the window to draw itself. */ BeginPaint(hBox, (LPPAINTSTRUCT)&ps); FontEditPaint(hBox, ps.hdc); EndPaint(hBox, (LPPAINTSTRUCT)&ps); break; case WM_COMMAND: /* A menu item has been selected, or a control is notifying * its parent. wParam is the menu item value (for menus), * or control ID (for controls). For controls, the low word * of lParam has the window handle of the control, and the hi * word has the notification code. For menus, lParam contains * 0L. */ FontEditCommand(hBox, LOWORD(wParam)); break; /* Data interchange request. */ case WM_CUT: case WM_COPY: case WM_PASTE: case WM_CLEAR: case WM_UNDO: case WM_RENDERFORMAT: case WM_RENDERALLFORMATS: case WM_DESTROYCLIPBOARD: case WM_DRAWCLIPBOARD: break; case WM_INITMENU: hMenu = GetMenu(hBox); /* Gray menu if no clipboard bitmap */ mf = (WORD)(IsClipboardFormatAvailable(CF_BITMAP) ? MF_ENABLED : MF_GRAYED); EnableMenuItem(hMenu, BOX_PASTE, mf); EnableMenuItem(hMenu, FONT_PASTE, mf); break; /* For each of following mouse window messages, wParam contains ** bits indicating whether or not various virtual keys are down, ** and lParam is a POINT containing the mouse coordinates. The ** keydown bits of wParam are: MK_LBUTTON (set if Left Button is ** down); MK_RBUTTON (set if Right Button is down); MK_SHIFT (set ** if Shift Key is down); MK_ALTERNATE (set if Alt Key is down); ** and MK_CONTROL (set if Control Key is down). */ case WM_LBUTTONDOWN: ((pt).x = ((*((POINTS *)&(lParam)))).x, (pt).y = ((*((POINTS *)&(lParam)))).y); if (fStartRubberBand) { /* a green signal to rubberband a rectangle for the * Fill menu command rectangle now has null dimensions. * Snap the current mouse point to nearest grid * intersection thus defining upper left corner of * rectangle */ if (PtInRect((LPRECT)&FontRect, pt)) { pt = SnapPointToGrid(pt); rectRubber.top = pt.y *scale+ptBox.y+1; rectRubber.bottom = (pt.y+1)*scale+ptBox.y-2; rectRubber.left = pt.x *scale+ptBox.x+1; rectRubber.right = (pt.x+1)*scale+ptBox.x-2; hDst = InitialiseRubberBandingRect(hBox); DrawRubberBand(hDst, &rectRubber, R2_XORPEN); } else { fStartRubberBand = fRubberBanding = FALSE; ReleaseCapture(); } } /* do operation depending upon current active command, * but not if we just added/deleted a row/column. */ if (!fJustZapped) { if (fStartRubberBand) { pt.x *= scale; pt.y *= scale; MouseInBox(hBox, message, pt); } else { ((pt).x = ((*((POINTS *)&(lParam)))).x, (pt).y = ((*((POINTS *)&(lParam)))).y); MouseInBox(hBox, message, pt); } } break; case WM_LBUTTONUP: /* Get other corner of rectangle */ fJustZapped = FALSE; if (fRubberBanding) { /* if rubberbanding for the Fill menu command, * terminate proceedings and clean up */ DrawRubberBand(hDst, &rectRubber, R2_NOT); EndRubberBandingRect(hDst); if (cursor) { ReadRect(); } } if (fCaptured ) { /* if cursor is + shaped, restore it to default */ ReleaseCapture(); SetCursor (hOldCursor); } break; case WM_RBUTTONDOWN: case WM_RBUTTONUP: break; case WM_MOUSEMOVE: /* If mouse is down */ ((pt).x = ((*((POINTS *)&(lParam)))).x, (pt).y = ((*((POINTS *)&(lParam)))).y); if ((fRubberBanding) && (wParam & MK_LBUTTON)) { /* if any of Fill menu commands is active ** (AND the mouse key depressed) draw a rubberband ** a rectangle with the mouse movements */ /* get current square number */ pt = SnapPointToGrid(pt); /* calculate grid for new square */ BoxRect.top = pt.y *scale+ptBox.y+1; BoxRect.bottom = (pt.y+1)*scale+ptBox.y-2; BoxRect.left = pt.x *scale+ptBox.x+1; BoxRect.right = (pt.x+1)*scale+ptBox.x-2; /* erase old mark */ DrawRubberBand(hDst, &rectRubber, R2_NOT); /* limit rubber band to box */ if (BoxRect.right > (LONG) (scale * wBox + ptBox.x)) BoxRect.right = scale * wBox + ptBox.x; if (BoxRect.bottom > (LONG) (scale * kBox + ptBox.y)) BoxRect.bottom = scale * kBox + ptBox.y; if (BoxRect.top < 0) BoxRect.top = 1; if (BoxRect.left < 0) BoxRect.left = 1; if (ptA.x == pt.x) { rectRubber.right = BoxRect.right; rectRubber.left = BoxRect.left; } if (ptA.y == pt.y) { rectRubber.bottom = BoxRect.bottom; rectRubber.top = BoxRect.top; } /* almost an IntersectRect */ if (ptA.x >= pt.x) rectRubber.left = BoxRect.left; else rectRubber.right = BoxRect.right; if (ptA.y >= pt.y) rectRubber.top = BoxRect.top; else rectRubber.bottom = BoxRect.bottom; /* Draw new mark */ DrawRubberBand(hDst, &rectRubber, R2_XORPEN); } else { /* if not "Fill"ing(AND mouse key depressed, * paint with the mouse movements */ if ((wParam & MK_LBUTTON) && cursor == FALSE && fJustZapped == FALSE) MouseInBox(hBox, message, pt); } break; case WM_LBUTTONDBLCLK: case WM_RBUTTONDBLCLK: break; default: /* Everything else comes here. This call MUST exist ** in your window proc. */ return(DefWindowProc(hBox, message, wParam, lParam)); break; } /* A window proc should always return something */ return(0L); } /***************************** Public Function ****************************\ * * BOOL APIENTRY AboutDlg(hDlg, message, wParam, lParam) * HWND hDlg; * WORD message; * WPARAM wParam; * LPARAM lParam; * * * Effects: none. * \***************************************************************************/ BOOL APIENTRY AboutDlg( HWND hDlg, WORD message, WPARAM wParam, LPARAM lParam ) { UNREFERENCED_PARAMETER(lParam); switch (message) { case WM_INITDIALOG: break; case WM_COMMAND: EndDialog(hDlg, LOWORD(wParam)); /* idok or idcancel */ break; default: return FALSE; break; } return(TRUE); }