diff options
Diffstat (limited to 'private/sdktools/fontedit/fontchar.c')
-rw-r--r-- | private/sdktools/fontedit/fontchar.c | 1569 |
1 files changed, 1569 insertions, 0 deletions
diff --git a/private/sdktools/fontedit/fontchar.c b/private/sdktools/fontedit/fontchar.c new file mode 100644 index 000000000..587dacc26 --- /dev/null +++ b/private/sdktools/fontedit/fontchar.c @@ -0,0 +1,1569 @@ +#include "windows.h" +#include <port1632.h> +#include "fontedit.h" +#include "fcntl.h" +#include <stdio.h> + +/****************************************************************************/ +/* Shared Variables */ +/****************************************************************************/ + +POINT SnapPointToGrid(POINT Pt); +LONG APIENTRY FontEditWndProc(HWND, WORD, WPARAM, LONG); +BOOL APIENTRY AboutDlg( + HWND hDlg, + WORD message, + WPARAM wParam, + LONG 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 */ +extern CHAR gszHelpFile[]; +/****************************************************************************/ +/* 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 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) / (LONG)(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 */ + DeleteBitmap(); /* Get rid of memory DC */ + PostQuitMessage(0); /* Cause application to be terminated */ + break; + + case FONT_HELP_CONTENTS: + WinHelp(hFont, gszHelpFile, HELP_CONTENTS, 0L); + break; + + case FONT_HELP_SEARCH: + /* + * Tell winhelp to be sure this app's help file is current, + * then invoke a search with an empty starting key. + */ + WinHelp(hFont, gszHelpFile, HELP_FORCEFILE, 0); + WinHelp(hFont, gszHelpFile, HELP_PARTIALKEY, (DWORD)(LPSTR)""); + 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: +#ifdef DBCS //DBCS_FIX + DupCol(0, kBoxLim - 1); + for (y = 0; y < kBoxLim; y++) + matBox[0][y] = FALSE; /* Clear left column */ + break; +#endif + 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, + LONG 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 (GET_WM_COMMAND_ID(wParam, lParam)) { + 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, GET_WM_COMMAND_ID(wParam, lParam) != 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; + + 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 */ + colorA = (matBox[pt.x][pt.y] ^= TRUE); + break; + + case WM_LBUTTONUP: + break; + + case WM_MOUSEMOVE: + matBox[pt.x][pt.y] = colorA; /* paint */ + break; + } + 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( + HWND 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 + ) +{ +#if DBG + char buf[256]; +#endif +#ifdef JAPAN + SIZE Size; + static LONG cxPrev; + INT nLeftRect; +#endif + + SetROP2(hDst, rop); + Rectangle(hDst, lpRect->left, lpRect->top, + lpRect->right, lpRect->bottom); + +#if DBG + sprintf(buf, "left=%d, top=%d, right=%d, bottom=%d", + lpRect->left, lpRect->top, lpRect->right, lpRect->bottom); + +#ifdef JAPAN + 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; +#endif + 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, + LONG 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 */ + DeleteBitmap(); /* 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) + DeleteBitmap(); /* 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, GET_WM_COMMAND_ID(wParam, lParam)); + 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: + MPOINT2POINT(MAKEMPOINT(lParam), pt); + + 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 { + MPOINT2POINT(MAKEMPOINT(lParam), pt); + 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 */ + + MPOINT2POINT(MAKEMPOINT(lParam), pt); + + 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 > scale * (LONG)wBox + ptBox.x) + BoxRect.right = scale * wBox + ptBox.x; + if (BoxRect.bottom > scale * (LONG)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; +* LONG lParam; +* +* +* Effects: none. +* +\***************************************************************************/ +BOOL APIENTRY +AboutDlg( + HWND hDlg, + WORD message, + WPARAM wParam, + LONG lParam + ) +{ + UNREFERENCED_PARAMETER(lParam); + + switch (message) { + case WM_INITDIALOG: + break; + + case WM_COMMAND: + EndDialog(hDlg, GET_WM_COMMAND_ID(wParam, lParam)); + /* idok or idcancel */ + break; + + default: + return FALSE; + break; + } + return(TRUE); +} |