| /* |
| * Edit control |
| * |
| * Copyright David W. Metcalfe, 1994 |
| * |
| * Release 2, June 1994 |
| */ |
| |
| static char Copyright[] = "Copyright David W. Metcalfe, 1994"; |
| |
| #include <stdlib.h> |
| #include <string.h> |
| #include <windows.h> |
| #include <heap.h> |
| #include "win.h" |
| #include "class.h" |
| #include "user.h" |
| #include "scroll.h" |
| |
| /* #define DEBUG_EDIT /* */ |
| |
| #define NOTIFY_PARENT(hWndCntrl, wNotifyCode) \ |
| SendMessage(GetParent(hWndCntrl), WM_COMMAND, \ |
| GetDlgCtrlID(hWndCntrl), MAKELPARAM(hWndCntrl, wNotifyCode)); |
| |
| #define MAXTEXTLEN 32000 /* maximum text buffer length */ |
| #define EDITLEN 1024 /* starting length for multi-line control */ |
| #define ENTRYLEN 256 /* starting length for single line control */ |
| #define GROWLENGTH 64 /* buffers grow by this much */ |
| |
| #define HSCROLLDIM (ClientWidth(wndPtr) / 3) |
| /* "line" dimension for horizontal scroll */ |
| |
| #define EDIT_HEAP_ALLOC(size) USER_HEAP_ALLOC(GMEM_MOVEABLE,size) |
| #define EDIT_HEAP_REALLOC(handle,size) USER_HEAP_REALLOC(handle,size,\ |
| GMEM_MOVEABLE) |
| #define EDIT_HEAP_ADDR(handle) USER_HEAP_ADDR(handle) |
| #define EDIT_HEAP_FREE(handle) USER_HEAP_FREE(handle) |
| |
| typedef struct |
| { |
| int wlines; /* number of lines of text */ |
| int wtop; /* top line that is displayed */ |
| int wleft; /* left pixel that is displayed */ |
| unsigned int textlen; /* text buffer length */ |
| int textwidth; /* width of longest line in pixels */ |
| RECT fmtrc; /* rectangle in which to format text */ |
| int txtht; /* height of text line in pixels */ |
| MDESC **localheap; /* pointer to application's local heap */ |
| HANDLE hText; /* handle to text buffer */ |
| HANDLE hCharWidths; /* widths of chars in font */ |
| HANDLE hTextPtrs; /* list of line offsets */ |
| HANDLE hBlankLine; /* to fill blank lines quickly */ |
| int CurrCol; /* current column */ |
| int CurrLine; /* current line */ |
| int WndCol; /* current window column */ |
| int WndRow; /* current window row */ |
| BOOL TextChanged; /* TRUE if text has changed */ |
| BOOL PaintBkgd; /* paint control background */ |
| unsigned int MaxTextLen; /* maximum text buffer length */ |
| int SelBegLine; /* beginning line of selection */ |
| int SelBegCol; /* beginning column of selection */ |
| int SelEndLine; /* ending line of selection */ |
| int SelEndCol; /* ending column of selection */ |
| HFONT hFont; /* handle of current font (if not default) */ |
| HANDLE hDeletedText; /* handle to deleted txet buffer for undo */ |
| int DeletedLength; /* length of deleted text */ |
| int DeletedCurrLine; /* starting line from which text was deleted */ |
| int DeletedCurrCol; /* starting col from which text was deleted */ |
| int NumTabStops; /* number of tab stops in buffer hTabStops */ |
| HANDLE hTabStops; /* handle of tab stops buffer */ |
| } EDITSTATE; |
| |
| |
| #define ClientWidth(wndPtr) (wndPtr->rectClient.right - \ |
| wndPtr->rectClient.left) |
| #define ClientHeight(wndPtr, es) ((wndPtr->rectClient.bottom - \ |
| wndPtr->rectClient.top) / es->txtht) |
| #define EditBufLen(wndPtr) (wndPtr->dwStyle & ES_MULTILINE \ |
| ? EDITLEN : ENTRYLEN) |
| #define CurrChar (EDIT_TextLine(hwnd, es->CurrLine) + es->CurrCol) |
| #define SelMarked(es) (es->SelBegLine != 0 || es->SelBegCol != 0 || \ |
| es->SelEndLine != 0 || es->SelEndCol != 0) |
| #define ROUNDUP(numer, denom) ((numer % denom) \ |
| ? (((numer + denom) / denom) * denom) \ |
| : numer) |
| |
| /* macros to access window styles */ |
| #define IsAutoVScroll() (wndPtr->dwStyle & ES_AUTOVSCROLL) |
| #define IsAutoHScroll() (wndPtr->dwStyle & ES_AUTOHSCROLL) |
| #define IsMultiLine() (wndPtr->dwStyle & ES_MULTILINE) |
| #define IsVScrollBar() (wndPtr->dwStyle & WS_VSCROLL) |
| #define IsHScrollBar() (wndPtr->dwStyle & WS_HSCROLL) |
| |
| /* internal variables */ |
| static BOOL TextMarking; /* TRUE if text marking in progress */ |
| static BOOL ButtonDown; /* TRUE if left mouse button down */ |
| static int ButtonRow; /* row in text buffer when button pressed */ |
| static int ButtonCol; /* col in text buffer when button pressed */ |
| static BOOL Print = FALSE; |
| |
| |
| LONG EditWndProc(HWND hWnd, WORD uMsg, WORD wParam, LONG lParam); |
| long EDIT_NCCreateMsg(HWND hwnd, LONG lParam); |
| long EDIT_CreateMsg(HWND hwnd, LONG lParam); |
| void EDIT_ClearTextPointers(HWND hwnd); |
| void EDIT_BuildTextPointers(HWND hwnd); |
| void EDIT_ModTextPointers(HWND hwnd, int lineno, int var); |
| void EDIT_PaintMsg(HWND hwnd); |
| HANDLE EDIT_GetTextLine(HWND hwnd, int selection); |
| char *EDIT_TextLine(HWND hwnd, int sel); |
| int EDIT_StrLength(EDITSTATE *es, char *str, int len, int pcol); |
| int EDIT_LineLength(HWND hwnd, int num); |
| void EDIT_WriteTextLine(HWND hwnd, RECT *rc, int y); |
| void EDIT_WriteText(HWND hwnd, char *lp, int off, int len, int row, |
| int col, RECT *rc, BOOL blank, BOOL reverse); |
| HANDLE EDIT_GetStr(EDITSTATE *es, char *lp, int off, int len, int *diff); |
| void EDIT_CharMsg(HWND hwnd, WORD wParam); |
| void EDIT_KeyTyped(HWND hwnd, short ch); |
| int EDIT_CharWidth(EDITSTATE *es, short ch, int pcol); |
| int EDIT_GetNextTabStop(EDITSTATE *es, int pcol); |
| void EDIT_Forward(HWND hwnd); |
| void EDIT_Downward(HWND hwnd); |
| void EDIT_Upward(HWND hwnd); |
| void EDIT_Backward(HWND hwnd); |
| void EDIT_End(HWND hwnd); |
| void EDIT_Home(HWND hwnd); |
| void EDIT_StickEnd(HWND hwnd); |
| void EDIT_KeyDownMsg(HWND hwnd, WORD wParam); |
| void EDIT_KeyHScroll(HWND hwnd, WORD opt); |
| void EDIT_KeyVScrollLine(HWND hwnd, WORD opt); |
| void EDIT_KeyVScrollPage(HWND hwnd, WORD opt); |
| void EDIT_KeyVScrollDoc(HWND hwnd, WORD opt); |
| int EDIT_ComputeVScrollPos(HWND hwnd); |
| int EDIT_ComputeHScrollPos(HWND hwnd); |
| void EDIT_DelKey(HWND hwnd); |
| void EDIT_VScrollMsg(HWND hwnd, WORD wParam, LONG lParam); |
| void EDIT_VScrollLine(HWND hwnd, WORD opt); |
| void EDIT_VScrollPage(HWND hwnd, WORD opt); |
| void EDIT_HScrollMsg(HWND hwnd, WORD wParam, LONG lParam); |
| void EDIT_SizeMsg(HWND hwnd, WORD wParam, LONG lParam); |
| void EDIT_LButtonDownMsg(HWND hwnd, WORD wParam, LONG lParam); |
| void EDIT_MouseMoveMsg(HWND hwnd, WORD wParam, LONG lParam); |
| int EDIT_PixelToChar(HWND hwnd, int row, int *pixel); |
| LONG EDIT_SetTextMsg(HWND hwnd, LONG lParam); |
| void EDIT_ClearText(HWND hwnd); |
| void EDIT_SetSelMsg(HWND hwnd, LONG lParam); |
| void EDIT_GetLineCol(HWND hwnd, int off, int *line, int *col); |
| void EDIT_DeleteSel(HWND hwnd); |
| void EDIT_ClearSel(HWND hwnd); |
| int EDIT_TextLineNumber(HWND hwnd, char *lp); |
| void EDIT_SetAnchor(HWND hwnd, int row, int col); |
| void EDIT_ExtendSel(HWND hwnd, int x, int y); |
| void EDIT_WriteSel(HWND hwnd, int y, int start, int end); |
| void EDIT_StopMarking(HWND hwnd); |
| LONG EDIT_GetLineMsg(HWND hwnd, WORD wParam, LONG lParam); |
| LONG EDIT_GetSelMsg(HWND hwnd); |
| void EDIT_ReplaceSel(HWND hwnd, LONG lParam); |
| void EDIT_InsertText(HWND hwnd, char *str, int len); |
| LONG EDIT_LineFromCharMsg(HWND hwnd, WORD wParam); |
| LONG EDIT_LineIndexMsg(HWND hwnd, WORD wParam); |
| LONG EDIT_LineLengthMsg(HWND hwnd, WORD wParam); |
| void EDIT_SetFont(HWND hwnd, WORD wParam, LONG lParam); |
| void EDIT_SaveDeletedText(HWND hwnd, char *deltext, int len, int line, |
| int col); |
| void EDIT_ClearDeletedText(HWND hwnd); |
| LONG EDIT_UndoMsg(HWND hwnd); |
| unsigned int EDIT_TextAlloc(EDITSTATE *es, int bytes); |
| void *EDIT_TextAddr(EDITSTATE *es, unsigned int handle); |
| unsigned int EDIT_TextReAlloc(EDITSTATE *es, unsigned int handle, int bytes); |
| void EDIT_SetHandleMsg(HWND hwnd, WORD wParam); |
| LONG EDIT_SetTabStopsMsg(HWND hwnd, WORD wParam, LONG lParam); |
| void swap(int *a, int *b); |
| |
| |
| LONG EditWndProc(HWND hwnd, WORD uMsg, WORD wParam, LONG lParam) |
| { |
| LONG lResult = 0L; |
| HDC hdc; |
| char *textPtr; |
| int len; |
| WND *wndPtr = WIN_FindWndPtr(hwnd); |
| EDITSTATE *es = (EDITSTATE *)EDIT_HEAP_ADDR((HANDLE)(*(wndPtr->wExtra))); |
| |
| switch (uMsg) { |
| case EM_CANUNDO: |
| lResult = es->hDeletedText; |
| break; |
| |
| case EM_EMPTYUNDOBUFFER: |
| EDIT_ClearDeletedText(hwnd); |
| break; |
| |
| case EM_FMTLINES: |
| printf("edit: EM_FMTLINES message received\n"); |
| if (!wParam) |
| lResult = 1L; |
| else |
| lResult = 0L; |
| break; |
| |
| case EM_GETFIRSTVISIBLELINE: |
| lResult = es->wtop; |
| break; |
| |
| case EM_GETHANDLE: |
| lResult = es->hText; |
| break; |
| |
| case EM_GETLINE: |
| if (IsMultiLine()) |
| lResult = EDIT_GetLineMsg(hwnd, wParam, lParam); |
| else |
| lResult = 0L; |
| break; |
| |
| case EM_GETLINECOUNT: |
| if (IsMultiLine()) |
| lResult = es->wlines; |
| else |
| lResult = 0L; |
| break; |
| |
| case EM_GETMODIFY: |
| lResult = es->TextChanged; |
| break; |
| |
| case EM_GETPASSWORDCHAR: |
| printf("edit: cannot process EM_GETPASSWORDCHAR message\n"); |
| break; |
| |
| case EM_GETRECT: |
| GetWindowRect(hwnd, (LPRECT)lParam); |
| break; |
| |
| case EM_GETSEL: |
| lResult = EDIT_GetSelMsg(hwnd); |
| break; |
| |
| case EM_GETWORDBREAKPROC: |
| printf("edit: cannot process EM_GETWORDBREAKPROC message\n"); |
| break; |
| |
| case EM_LIMITTEXT: |
| if (wParam) |
| es->MaxTextLen = wParam; |
| else |
| es->MaxTextLen = 65000; |
| break; |
| |
| case EM_LINEFROMCHAR: |
| lResult = EDIT_LineFromCharMsg(hwnd, wParam); |
| break; |
| |
| case EM_LINEINDEX: |
| if (IsMultiLine()) |
| lResult = EDIT_LineIndexMsg(hwnd, wParam); |
| else |
| lResult = 0L; |
| break; |
| |
| case EM_LINELENGTH: |
| lResult = EDIT_LineLengthMsg(hwnd, wParam); |
| break; |
| |
| case EM_LINESCROLL: |
| printf("edit: cannot process EM_LINESCROLL message\n"); |
| break; |
| |
| case EM_REPLACESEL: |
| HideCaret(hwnd); |
| EDIT_ReplaceSel(hwnd, lParam); |
| SetCaretPos(es->WndCol, es->WndRow * es->txtht); |
| ShowCaret(hwnd); |
| break; |
| |
| case EM_SETHANDLE: |
| EDIT_SetHandleMsg(hwnd, wParam); |
| break; |
| |
| case EM_SETMODIFY: |
| es->TextChanged = wParam; |
| break; |
| |
| case EM_SETPASSWORDCHAR: |
| printf("edit: cannot process EM_SETPASSWORDCHAR message\n"); |
| break; |
| |
| case EM_SETREADONLY: |
| printf("edit: cannot process EM_SETREADONLY message\n"); |
| break; |
| |
| case EM_SETRECT: |
| case EM_SETRECTNP: |
| printf("edit: cannot process EM_SETRECT(NP) message\n"); |
| break; |
| |
| case EM_SETSEL: |
| HideCaret(hwnd); |
| EDIT_SetSelMsg(hwnd, lParam); |
| SetCaretPos(es->WndCol, es->WndRow * es->txtht); |
| ShowCaret(hwnd); |
| break; |
| |
| case EM_SETTABSTOPS: |
| lResult = EDIT_SetTabStopsMsg(hwnd, wParam, lParam); |
| break; |
| |
| case EM_SETWORDBREAKPROC: |
| printf("edit: cannot process EM_SETWORDBREAKPROC message\n"); |
| break; |
| |
| case EM_UNDO: |
| HideCaret(hwnd); |
| lResult = EDIT_UndoMsg(hwnd); |
| SetCaretPos(es->WndCol, es->WndRow * es->txtht); |
| ShowCaret(hwnd); |
| break; |
| |
| case WM_CHAR: |
| EDIT_CharMsg(hwnd, wParam); |
| break; |
| |
| case WM_CREATE: |
| lResult = EDIT_CreateMsg(hwnd, lParam); |
| break; |
| |
| case WM_DESTROY: |
| EDIT_HEAP_FREE(es->hTextPtrs); |
| EDIT_HEAP_FREE(es->hCharWidths); |
| EDIT_HEAP_FREE((HANDLE)(*(wndPtr->wExtra))); |
| break; |
| |
| case WM_ENABLE: |
| InvalidateRect(hwnd, NULL, FALSE); |
| break; |
| |
| case WM_GETTEXT: |
| textPtr = EDIT_TextAddr(es, es->hText); |
| if ((int)wParam > (len = strlen(textPtr))) |
| { |
| strcpy((char *)lParam, textPtr); |
| lResult = (DWORD)len; |
| } |
| else |
| lResult = 0L; |
| break; |
| |
| case WM_GETTEXTLENGTH: |
| textPtr = EDIT_TextAddr(es, es->hText); |
| lResult = (DWORD)strlen(textPtr); |
| break; |
| |
| case WM_HSCROLL: |
| EDIT_HScrollMsg(hwnd, wParam, lParam); |
| break; |
| |
| case WM_KEYDOWN: |
| EDIT_KeyDownMsg(hwnd, wParam); |
| break; |
| |
| case WM_KILLFOCUS: |
| DestroyCaret(); |
| NOTIFY_PARENT(hwnd, EN_KILLFOCUS); |
| break; |
| |
| case WM_LBUTTONDOWN: |
| HideCaret(hwnd); |
| SetFocus(hwnd); |
| EDIT_LButtonDownMsg(hwnd, wParam, lParam); |
| SetCaretPos(es->WndCol, es->WndRow * es->txtht); |
| ShowCaret(hwnd); |
| break; |
| |
| case WM_LBUTTONUP: |
| ButtonDown = FALSE; |
| if (TextMarking) |
| EDIT_StopMarking(hwnd); |
| break; |
| |
| case WM_MOUSEMOVE: |
| HideCaret(hwnd); |
| EDIT_MouseMoveMsg(hwnd, wParam, lParam); |
| SetCaretPos(es->WndCol, es->WndRow * es->txtht); |
| ShowCaret(hwnd); |
| break; |
| |
| case WM_MOVE: |
| lResult = 0; |
| break; |
| |
| case WM_NCCREATE: |
| lResult = EDIT_NCCreateMsg(hwnd, lParam); |
| break; |
| |
| case WM_PAINT: |
| EDIT_PaintMsg(hwnd); |
| break; |
| |
| case WM_SETFOCUS: |
| es = (EDITSTATE *)EDIT_HEAP_ADDR((HANDLE)(*(wndPtr->wExtra))); |
| CreateCaret(hwnd, 0, 2, es->txtht); |
| SetCaretPos(es->WndCol, es->WndRow * es->txtht); |
| ShowCaret(hwnd); |
| NOTIFY_PARENT(hwnd, EN_SETFOCUS); |
| break; |
| |
| case WM_SETFONT: |
| HideCaret(hwnd); |
| EDIT_SetFont(hwnd, wParam, lParam); |
| SetCaretPos(es->WndCol, es->WndRow * es->txtht); |
| ShowCaret(hwnd); |
| break; |
| |
| case WM_SETTEXT: |
| EDIT_SetTextMsg(hwnd, lParam); |
| break; |
| |
| case WM_SIZE: |
| EDIT_SizeMsg(hwnd, wParam, lParam); |
| lResult = 0; |
| break; |
| |
| case WM_VSCROLL: |
| EDIT_VScrollMsg(hwnd, wParam, lParam); |
| break; |
| |
| default: |
| lResult = DefWindowProc(hwnd, uMsg, wParam, lParam); |
| break; |
| } |
| |
| GlobalUnlock(hwnd); |
| return lResult; |
| } |
| |
| |
| /********************************************************************* |
| * WM_NCCREATE message function |
| */ |
| |
| long EDIT_NCCreateMsg(HWND hwnd, LONG lParam) |
| { |
| CREATESTRUCT *createStruct = (CREATESTRUCT *)lParam; |
| WND *wndPtr = WIN_FindWndPtr(hwnd); |
| EDITSTATE *es; |
| unsigned int *textPtrs; |
| char *text; |
| int len; |
| |
| /* allocate space for state variable structure */ |
| (HANDLE)(*(wndPtr->wExtra)) = |
| EDIT_HEAP_ALLOC(sizeof(EDITSTATE)); |
| es = (EDITSTATE *)EDIT_HEAP_ADDR((HANDLE)(*(wndPtr->wExtra))); |
| es->hTextPtrs = EDIT_HEAP_ALLOC(sizeof(int)); |
| textPtrs = (unsigned int *)EDIT_HEAP_ADDR(es->hTextPtrs); |
| es->hCharWidths = EDIT_HEAP_ALLOC(256 * sizeof(short)); |
| |
| /* --- text buffer */ |
| es->localheap = &HEAP_LocalFindHeap(createStruct->hInstance)->free_list; |
| es->MaxTextLen = MAXTEXTLEN + 1; |
| if (!(createStruct->lpszName)) |
| { |
| es->textlen = EditBufLen(wndPtr) + 1; |
| es->hText = EDIT_TextAlloc(es, EditBufLen(wndPtr) + 2); |
| text = EDIT_TextAddr(es, es->hText); |
| memset(text, 0, es->textlen + 2); |
| EDIT_ClearTextPointers(hwnd); |
| } |
| else |
| { |
| if (strlen(createStruct->lpszName) < EditBufLen(wndPtr)) |
| { |
| es->hText = EDIT_TextAlloc(es, EditBufLen(wndPtr) + 2); |
| text = EDIT_TextAddr(es, es->hText); |
| strcpy(text, createStruct->lpszName); |
| *(text + es->textlen) = '\0'; |
| es->textlen = EditBufLen(wndPtr) + 1; |
| } |
| else |
| { |
| es->hText = EDIT_TextAlloc(es, strlen(createStruct->lpszName) + 2); |
| text = EDIT_TextAddr(es, es->hText); |
| strcpy(text, createStruct->lpszName); |
| es->textlen = strlen(createStruct->lpszName) + 1; |
| } |
| *(text + es->textlen + 1) = '\0'; |
| EDIT_BuildTextPointers(hwnd); |
| } |
| |
| if ((createStruct->style & WS_VSCROLL) || |
| (createStruct->style & WS_HSCROLL)) NC_CreateScrollBars(hwnd); |
| |
| /* remove the WS_CAPTION style if it has been set - this is really a */ |
| /* pseudo option made from a combination of WS_BORDER and WS_DLGFRAME */ |
| if (wndPtr->dwStyle & WS_BORDER && wndPtr->dwStyle & WS_DLGFRAME) |
| wndPtr->dwStyle ^= WS_DLGFRAME; |
| |
| return 1; |
| } |
| |
| |
| /********************************************************************* |
| * WM_CREATE message function |
| */ |
| |
| long EDIT_CreateMsg(HWND hwnd, LONG lParam) |
| { |
| HDC hdc; |
| WND *wndPtr = WIN_FindWndPtr(hwnd); |
| EDITSTATE *es = (EDITSTATE *)EDIT_HEAP_ADDR((HANDLE)(*(wndPtr->wExtra))); |
| CLASS *classPtr; |
| short *charWidths; |
| TEXTMETRIC tm; |
| char *text; |
| |
| /* initialize state variable structure */ |
| /* --- char width array */ |
| hdc = GetDC(hwnd); |
| charWidths = (short *)EDIT_HEAP_ADDR(es->hCharWidths); |
| memset(charWidths, 0, 256 * sizeof(short)); |
| GetCharWidth(hdc, 0, 255, charWidths); |
| |
| /* --- other structure variables */ |
| GetTextMetrics(hdc, &tm); |
| es->txtht = tm.tmHeight + tm.tmExternalLeading; |
| es->wlines = 0; |
| es->wtop = es->wleft = 0; |
| es->CurrCol = es->CurrLine = 0; |
| es->WndCol = es->WndRow = 0; |
| es->TextChanged = FALSE; |
| es->textwidth = 0; |
| es->SelBegLine = es->SelBegCol = 0; |
| es->SelEndLine = es->SelEndCol = 0; |
| es->hFont = 0; |
| es->hDeletedText = 0; |
| es->DeletedLength = 0; |
| es->NumTabStops = 0; |
| es->hTabStops = EDIT_HEAP_ALLOC(sizeof(int)); |
| |
| /* allocate space for a line full of blanks to speed up */ |
| /* line filling */ |
| es->hBlankLine = EDIT_HEAP_ALLOC((ClientWidth(wndPtr) / |
| charWidths[32]) + 2); |
| text = EDIT_HEAP_ADDR(es->hBlankLine); |
| memset(text, ' ', (ClientWidth(wndPtr) / charWidths[32]) + 2); |
| |
| /* set up text cursor for edit class */ |
| CLASS_FindClassByName("EDIT", &classPtr); |
| classPtr->wc.hCursor = LoadCursor(0, IDC_IBEAM); |
| |
| /* paint background on first WM_PAINT */ |
| es->PaintBkgd = TRUE; |
| |
| ReleaseDC(hwnd, hdc); |
| return 0L; |
| } |
| |
| |
| /********************************************************************* |
| * EDIT_ClearTextPointers |
| * |
| * Clear and initialize text line pointer array. |
| */ |
| |
| void EDIT_ClearTextPointers(HWND hwnd) |
| { |
| unsigned int *textPtrs; |
| WND *wndPtr = WIN_FindWndPtr(hwnd); |
| EDITSTATE *es = (EDITSTATE *)EDIT_HEAP_ADDR((HANDLE)(*(wndPtr->wExtra))); |
| |
| es->hTextPtrs = EDIT_HEAP_REALLOC(es->hTextPtrs, sizeof(int)); |
| textPtrs = (unsigned int *)EDIT_HEAP_ADDR(es->hTextPtrs); |
| *textPtrs = 0; |
| } |
| |
| |
| /********************************************************************* |
| * EDIT_BuildTextPointers |
| * |
| * Build array of pointers to text lines. |
| */ |
| |
| #define INITLINES 100 |
| |
| void EDIT_BuildTextPointers(HWND hwnd) |
| { |
| WND *wndPtr = WIN_FindWndPtr(hwnd); |
| char *text, *cp; |
| int incrs = INITLINES; |
| unsigned int off, len, temp; |
| EDITSTATE *es; |
| unsigned int *textPtrs; |
| short *charWidths; |
| |
| es = (EDITSTATE *)EDIT_HEAP_ADDR((HANDLE)(*(wndPtr->wExtra))); |
| text = EDIT_TextAddr(es, es->hText); |
| textPtrs = (unsigned int *)EDIT_HEAP_ADDR(es->hTextPtrs); |
| charWidths = (short *)EDIT_HEAP_ADDR(es->hCharWidths); |
| |
| es->textwidth = es->wlines = 0; |
| cp = text; |
| |
| /* advance through text buffer */ |
| while (*cp) |
| { |
| /* increase size of text pointer array */ |
| if (incrs == INITLINES) |
| { |
| incrs = 0; |
| es->hTextPtrs = EDIT_HEAP_REALLOC(es->hTextPtrs, |
| (es->wlines + INITLINES) * sizeof(int)); |
| textPtrs = (unsigned int *)EDIT_HEAP_ADDR(es->hTextPtrs); |
| } |
| off = (unsigned int)(cp - text); /* offset of beginning of line */ |
| *(textPtrs + es->wlines) = off; |
| es->wlines++; |
| incrs++; |
| len = 0; |
| |
| /* advance through current line */ |
| while (*cp && *cp != '\n') |
| { |
| len += EDIT_CharWidth(es, *cp, len); /* width of line in pixels */ |
| cp++; |
| } |
| es->textwidth = max(es->textwidth, len); |
| if (*cp) |
| cp++; /* skip '\n' */ |
| } |
| |
| off = (unsigned int)(cp - text); |
| *(textPtrs + es->wlines) = off; |
| } |
| |
| |
| /********************************************************************* |
| * EDIT_ModTextPointers |
| * |
| * Modify text pointers from a specified position. |
| */ |
| |
| void EDIT_ModTextPointers(HWND hwnd, int lineno, int var) |
| { |
| WND *wndPtr = WIN_FindWndPtr(hwnd); |
| EDITSTATE *es = (EDITSTATE *)EDIT_HEAP_ADDR((HANDLE)(*(wndPtr->wExtra))); |
| unsigned int *textPtrs = (unsigned int *)EDIT_HEAP_ADDR(es->hTextPtrs); |
| |
| while (lineno < es->wlines) |
| *(textPtrs + lineno++) += var; |
| } |
| |
| |
| /********************************************************************* |
| * WM_PAINT message function |
| */ |
| |
| void EDIT_PaintMsg(HWND hwnd) |
| { |
| PAINTSTRUCT ps; |
| HDC hdc; |
| int y; |
| RECT rc; |
| WND *wndPtr = WIN_FindWndPtr(hwnd); |
| EDITSTATE *es = (EDITSTATE *)EDIT_HEAP_ADDR((HANDLE)(*(wndPtr->wExtra))); |
| |
| hdc = BeginPaint(hwnd, &ps); |
| rc = ps.rcPaint; |
| |
| #ifdef DEBUG_EDIT |
| printf("WM_PAINT: rc=(%d,%d), (%d,%d)\n", rc.left, rc.top, |
| rc.right, rc.bottom); |
| #endif |
| |
| if (es->PaintBkgd) |
| FillWindow(GetParent(hwnd), hwnd, hdc, CTLCOLOR_EDIT); |
| |
| for (y = (rc.top / es->txtht); y <= (rc.bottom / es->txtht); y++) |
| { |
| if (y < es->wlines - es->wtop) |
| EDIT_WriteTextLine(hwnd, &rc, y + es->wtop); |
| } |
| |
| EndPaint(hwnd, &ps); |
| } |
| |
| |
| /********************************************************************* |
| * EDIT_GetTextLine |
| * |
| * Get a copy of the text in the specified line. |
| */ |
| |
| HANDLE EDIT_GetTextLine(HWND hwnd, int selection) |
| { |
| char *line; |
| HANDLE hLine; |
| int len = 0; |
| char *cp, *cp1; |
| |
| #ifdef DEBUG_EDIT |
| printf("GetTextLine %d\n", selection); |
| #endif |
| cp = cp1 = EDIT_TextLine(hwnd, selection); |
| /* advance through line */ |
| while (*cp && *cp != '\n') |
| { |
| len++; |
| cp++; |
| } |
| |
| /* store selected line and return handle */ |
| hLine = EDIT_HEAP_ALLOC(len + 6); |
| line = (char *)EDIT_HEAP_ADDR(hLine); |
| memmove(line, cp1, len); |
| line[len] = '\0'; |
| return hLine; |
| } |
| |
| |
| /********************************************************************* |
| * EDIT_TextLine |
| * |
| * Return a pointer to the text in the specified line. |
| */ |
| |
| char *EDIT_TextLine(HWND hwnd, int sel) |
| { |
| WND *wndPtr = WIN_FindWndPtr(hwnd); |
| EDITSTATE *es = (EDITSTATE *)EDIT_HEAP_ADDR((HANDLE)(*(wndPtr->wExtra))); |
| char *text = EDIT_TextAddr(es, es->hText); |
| unsigned int *textPtrs = (unsigned int *)EDIT_HEAP_ADDR(es->hTextPtrs); |
| |
| return (text + *(textPtrs + sel)); |
| } |
| |
| |
| /********************************************************************* |
| * EDIT_StrLength |
| * |
| * Return length of string _str_ of length _len_ characters in pixels. |
| * The current column offset in pixels _pcol_ is required to calculate |
| * the width of a tab. |
| */ |
| |
| int EDIT_StrLength(EDITSTATE *es, char *str, int len, int pcol) |
| { |
| int i, plen = 0; |
| |
| for (i = 0; i < len; i++) |
| plen += EDIT_CharWidth(es, *(str + i), pcol + plen); |
| |
| #ifdef DEBUG_EDIT |
| printf("EDIT_StrLength: returning %d\n", plen); |
| #endif |
| return plen; |
| } |
| |
| |
| /********************************************************************* |
| * EDIT_LineLength |
| * |
| * Return length of line _num_ in characters. |
| */ |
| |
| int EDIT_LineLength(HWND hwnd, int num) |
| { |
| WND *wndPtr = WIN_FindWndPtr(hwnd); |
| EDITSTATE *es = (EDITSTATE *)EDIT_HEAP_ADDR((HANDLE)(*(wndPtr->wExtra))); |
| char *cp = EDIT_TextLine(hwnd, num); |
| char *cp1; |
| |
| cp1 = strchr(cp, '\n'); |
| return cp1 ? (int)(cp1 - cp) : strlen(cp); |
| } |
| |
| |
| /********************************************************************* |
| * EDIT_WriteTextLine |
| * |
| * Write the line of text at offset _y_ in text buffer to a window. |
| */ |
| |
| void EDIT_WriteTextLine(HWND hwnd, RECT *rect, int y) |
| { |
| int len = 0; |
| unsigned char line[200]; |
| HANDLE hLine; |
| unsigned char *lp; |
| int lnlen, lnlen1; |
| int col, off = 0; |
| int sbl, sel, sbc, sec; |
| RECT rc; |
| |
| BOOL trunc = FALSE; |
| WND *wndPtr = WIN_FindWndPtr(hwnd); |
| EDITSTATE *es = (EDITSTATE *)EDIT_HEAP_ADDR((HANDLE)(*(wndPtr->wExtra))); |
| |
| /* initialize rectangle if NULL, else copy */ |
| if (rect) |
| CopyRect(&rc, rect); |
| else |
| GetClientRect(hwnd, &rc); |
| |
| #ifdef DEBUG_EDIT |
| printf("WriteTextLine %d\n", y); |
| #endif |
| |
| /* make sure y is inside the window */ |
| if (y < es->wtop || y > (es->wtop + ClientHeight(wndPtr, es))) |
| { |
| #ifdef DEBUG_EDIT |
| printf("EDIT_WriteTextLine: y (%d) is not a displayed line\n", y); |
| #endif |
| return; |
| } |
| |
| /* make sure rectangle is within window */ |
| if (rc.left >= ClientWidth(wndPtr) - 1) |
| { |
| #ifdef DEBUG_EDIT |
| printf("EDIT_WriteTextLine: rc.left (%d) is greater than right edge\n", |
| rc.left); |
| #endif |
| return; |
| } |
| if (rc.right <= 0) |
| { |
| #ifdef DEBUG_EDIT |
| printf("EDIT_WriteTextLine: rc.right (%d) is less than left edge\n", |
| rc.right); |
| #endif |
| return; |
| } |
| if (y - es->wtop < (rc.top / es->txtht) || |
| y - es->wtop > (rc.bottom / es->txtht)) |
| { |
| #ifdef DEBUG_EDIT |
| printf("EDIT_WriteTextLine: y (%d) is outside window\n", y); |
| #endif |
| return; |
| } |
| |
| /* get the text and length of line */ |
| if ((hLine = EDIT_GetTextLine(hwnd, y)) == 0) |
| return; |
| lp = (unsigned char *)EDIT_HEAP_ADDR(hLine); |
| lnlen = EDIT_StrLength(es, lp, strlen(lp), 0); |
| lnlen1 = lnlen; |
| |
| /* build the line to display */ |
| if (lnlen < es->wleft) |
| lnlen = 0; |
| else |
| off += es->wleft; |
| |
| if (lnlen > rc.left) |
| { |
| off += rc.left; |
| lnlen = lnlen1 - off; |
| len = min(lnlen, rc.right - rc.left); |
| } |
| |
| if (SelMarked(es)) |
| { |
| sbl = es->SelBegLine; |
| sel = es->SelEndLine; |
| sbc = es->SelBegCol; |
| sec = es->SelEndCol; |
| |
| /* put lowest marker first */ |
| if (sbl > sel) |
| { |
| swap(&sbl, &sel); |
| swap(&sbc, &sec); |
| } |
| if (sbl == sel && sbc > sec) |
| swap(&sbc, &sec); |
| |
| if (y < sbl || y > sel) |
| EDIT_WriteText(hwnd, lp, off, len, y - es->wtop, rc.left, &rc, |
| TRUE, FALSE); |
| else if (y > sbl && y < sel) |
| EDIT_WriteText(hwnd, lp, off, len, y - es->wtop, rc.left, &rc, |
| TRUE, TRUE); |
| else if (y == sbl) |
| { |
| col = EDIT_StrLength(es, lp, sbc, 0); |
| if (col > (es->wleft + rc.left)) |
| { |
| len = min(col - off, rc.right - off); |
| EDIT_WriteText(hwnd, lp, off, len, y - es->wtop, |
| rc.left, &rc, FALSE, FALSE); |
| off = col; |
| } |
| if (y == sel) |
| { |
| col = EDIT_StrLength(es, lp, sec, 0); |
| if (col < (es->wleft + rc.right)) |
| { |
| len = min(col - off, rc.right - off); |
| EDIT_WriteText(hwnd, lp, off, len, y - es->wtop, |
| off - es->wleft, &rc, FALSE, TRUE); |
| off = col; |
| len = min(lnlen - off, rc.right - off); |
| EDIT_WriteText(hwnd, lp, off, len, y - es->wtop, |
| off - es->wleft, &rc, TRUE, FALSE); |
| } |
| else |
| { |
| len = min(lnlen - off, rc.right - off); |
| EDIT_WriteText(hwnd, lp, off, len, y - es->wtop, |
| off - es->wleft, &rc, TRUE, TRUE); |
| } |
| } |
| else |
| { |
| len = min(lnlen - off, rc.right - off); |
| if (col < (es->wleft + rc.right)) |
| EDIT_WriteText(hwnd, lp, off, len, y - es->wtop, |
| off - es->wleft, &rc, TRUE, TRUE); |
| } |
| } |
| else if (y == sel) |
| { |
| col = EDIT_StrLength(es, lp, sec, 0); |
| if (col < (es->wleft + rc.right)) |
| { |
| len = min(col - off, rc.right - off); |
| EDIT_WriteText(hwnd, lp, off, len, y - es->wtop, |
| off - es->wleft, &rc, FALSE, TRUE); |
| off = col; |
| len = min(lnlen - off, rc.right - off); |
| EDIT_WriteText(hwnd, lp, off, len, y - es->wtop, |
| off - es->wleft, &rc, TRUE, FALSE); |
| } |
| } |
| } |
| else |
| EDIT_WriteText(hwnd, lp, off, len, y - es->wtop, rc.left, &rc, |
| TRUE, FALSE); |
| |
| EDIT_HEAP_FREE(hLine); |
| } |
| |
| |
| /********************************************************************* |
| * EDIT_WriteText |
| * |
| * Write text to a window |
| * lp - text line |
| * off - offset in text line (in pixels) |
| * len - length from off (in pixels) |
| * row - line in window |
| * col - column in window |
| * rc - rectangle in which to display line |
| * blank - blank remainder of line? |
| * reverse - reverse color of line? |
| */ |
| |
| void EDIT_WriteText(HWND hwnd, char *lp, int off, int len, int row, |
| int col, RECT *rc, BOOL blank, BOOL reverse) |
| { |
| HDC hdc; |
| HANDLE hStr; |
| char *str, *cp, *cp1; |
| int diff, num_spaces, tabwidth, scol; |
| HRGN hrgnClip; |
| COLORREF oldTextColor, oldBkgdColor; |
| HFONT oldfont; |
| WND *wndPtr = WIN_FindWndPtr(hwnd); |
| EDITSTATE *es = (EDITSTATE *)EDIT_HEAP_ADDR((HANDLE)(*(wndPtr->wExtra))); |
| short *charWidths = (short *)EDIT_HEAP_ADDR(es->hCharWidths); |
| char *blanks = (char *)EDIT_HEAP_ADDR(es->hBlankLine); |
| |
| #ifdef DEBUG_EDIT |
| printf("EDIT_WriteText lp=%s, off=%d, len=%d, row=%d, col=%d, reverse=%d\n", lp, off, len, row, col, reverse); |
| #endif |
| |
| hdc = GetDC(hwnd); |
| hStr = EDIT_GetStr(es, lp, off, len, &diff); |
| str = (char *)EDIT_HEAP_ADDR(hStr); |
| hrgnClip = CreateRectRgnIndirect(rc); |
| SelectClipRgn(hdc, hrgnClip); |
| |
| if (es->hFont) |
| oldfont = (HFONT)SelectObject(hdc, (HANDLE)es->hFont); |
| |
| SendMessage(GetParent(hwnd), WM_CTLCOLOR, (WORD)hdc, |
| MAKELPARAM(hwnd, CTLCOLOR_EDIT)); |
| |
| if (reverse) |
| { |
| oldBkgdColor = GetBkColor(hdc); |
| oldTextColor = GetTextColor(hdc); |
| SetBkColor(hdc, oldTextColor); |
| SetTextColor(hdc, oldBkgdColor); |
| } |
| |
| if (!(cp = strchr(str, VK_TAB))) |
| TextOut(hdc, col - diff, row * es->txtht, str, strlen(str)); |
| else |
| { |
| TextOut(hdc, col - diff, row * es->txtht, str, (int)(cp - str)); |
| scol = EDIT_StrLength(es, str, (int)(cp - str), 0); |
| tabwidth = EDIT_CharWidth(es, VK_TAB, scol); |
| num_spaces = tabwidth / charWidths[32] + 1; |
| TextOut(hdc, scol, row * es->txtht, blanks, num_spaces); |
| cp++; |
| scol += tabwidth; |
| |
| while (cp1 = strchr(cp, VK_TAB)) |
| { |
| TextOut(hdc, scol, row * es->txtht, cp, (int)(cp1 - cp)); |
| scol = EDIT_StrLength(es, cp, (int)(cp1 - cp), scol); |
| tabwidth = EDIT_CharWidth(es, VK_TAB, scol); |
| num_spaces = tabwidth / charWidths[32] + 1; |
| TextOut(hdc, scol, row * es->txtht, blanks, num_spaces); |
| cp = ++cp1; |
| scol += tabwidth; |
| } |
| |
| TextOut(hdc, scol, row * es->txtht, cp, strlen(cp)); |
| } |
| |
| if (reverse) |
| { |
| SetBkColor(hdc, oldBkgdColor); |
| SetTextColor(hdc, oldTextColor); |
| } |
| |
| /* blank out remainder of line if appropriate */ |
| if (blank) |
| { |
| if ((rc->right - col) > len) |
| { |
| num_spaces = (rc->right - col - len) / charWidths[32]; |
| TextOut(hdc, col + len, row * es->txtht, blanks, num_spaces); |
| } |
| } |
| |
| if (es->hFont) |
| SelectObject(hdc, (HANDLE)oldfont); |
| |
| EDIT_HEAP_FREE(hStr); |
| ReleaseDC(hwnd, hdc); |
| } |
| |
| |
| /********************************************************************* |
| * EDIT_GetStr |
| * |
| * Return sub-string starting at pixel _off_ of length _len_ pixels. |
| * If _off_ is part way through a character, the negative offset of |
| * the beginning of the character is returned in _diff_, else _diff_ |
| * will be zero. |
| */ |
| |
| HANDLE EDIT_GetStr(EDITSTATE *es, char *lp, int off, int len, int *diff) |
| { |
| HANDLE hStr; |
| char *str; |
| int ch = 0, i = 0, j, s_i; |
| int ch1; |
| |
| #ifdef DEBUG_EDIT |
| printf("EDIT_GetStr %s %d %d\n", lp, off, len); |
| #endif |
| |
| while (i < off) |
| { |
| s_i = i; |
| i += EDIT_CharWidth(es, *(lp + ch), i); |
| ch++; |
| } |
| |
| /* if stepped past _off_, go back a character */ |
| if (i - off) |
| { |
| i = s_i; |
| ch--; |
| } |
| *diff = off - i; |
| ch1 = ch; |
| |
| while (i < len + off) |
| { |
| i += EDIT_CharWidth(es, *(lp + ch), i); |
| ch++; |
| } |
| |
| hStr = EDIT_HEAP_ALLOC(ch - ch1 + 3); |
| str = (char *)EDIT_HEAP_ADDR(hStr); |
| for (i = ch1, j = 0; i < ch; i++, j++) |
| str[j] = lp[i]; |
| str[++j] = '\0'; |
| #ifdef DEBUG_EDIT |
| printf("EDIT_GetStr: returning %s\n", str); |
| #endif |
| return hStr; |
| } |
| |
| |
| /********************************************************************* |
| * WM_CHAR message function |
| */ |
| |
| void EDIT_CharMsg(HWND hwnd, WORD wParam) |
| { |
| WND *wndPtr = WIN_FindWndPtr(hwnd); |
| EDITSTATE *es = (EDITSTATE *)EDIT_HEAP_ADDR((HANDLE)(*(wndPtr->wExtra))); |
| |
| #ifdef DEBUG_EDIT |
| printf("EDIT_CharMsg: wParam=%c\n", (char)wParam); |
| #endif |
| |
| switch (wParam) |
| { |
| case '\r': |
| case '\n': |
| if (!IsMultiLine()) |
| break; |
| wParam = '\n'; |
| EDIT_KeyTyped(hwnd, wParam); |
| break; |
| |
| default: |
| if (wParam >= 20 && wParam <= 126) |
| EDIT_KeyTyped(hwnd, wParam); |
| break; |
| } |
| } |
| |
| |
| /********************************************************************* |
| * EDIT_KeyTyped |
| * |
| * Process keystrokes that produce displayable characters. |
| */ |
| |
| void EDIT_KeyTyped(HWND hwnd, short ch) |
| { |
| WND *wndPtr = WIN_FindWndPtr(hwnd); |
| EDITSTATE *es = (EDITSTATE *)EDIT_HEAP_ADDR((HANDLE)(*(wndPtr->wExtra))); |
| char *text = EDIT_TextAddr(es, es->hText); |
| char *currchar = CurrChar; |
| RECT rc; |
| BOOL FullPaint = FALSE; |
| |
| #ifdef DEBUG_EDIT |
| printf("EDIT_KeyTyped: ch=%c\n", (char)ch); |
| #endif |
| |
| /* delete selected text (if any) */ |
| if (SelMarked(es)) |
| EDIT_DeleteSel(hwnd); |
| |
| /* test for typing at end of maximum buffer size */ |
| if (currchar == text + es->MaxTextLen) |
| { |
| NOTIFY_PARENT(hwnd, EN_ERRSPACE); |
| return; |
| } |
| |
| if (*currchar == '\0' && IsMultiLine()) |
| { |
| /* insert a newline at end of text */ |
| *currchar = '\n'; |
| *(currchar + 1) = '\0'; |
| EDIT_BuildTextPointers(hwnd); |
| } |
| |
| /* insert the typed character */ |
| if (text[es->textlen - 1] != '\0') |
| { |
| /* current text buffer is full */ |
| if (es->textlen == es->MaxTextLen) |
| { |
| /* text buffer is at maximum size */ |
| NOTIFY_PARENT(hwnd, EN_ERRSPACE); |
| return; |
| } |
| |
| /* increase the text buffer size */ |
| es->textlen += GROWLENGTH; |
| /* but not above maximum size */ |
| if (es->textlen > es->MaxTextLen) |
| es->textlen = es->MaxTextLen; |
| es->hText = EDIT_TextReAlloc(es, es->hText, es->textlen + 2); |
| if (!es->hText) |
| NOTIFY_PARENT(hwnd, EN_ERRSPACE); |
| text = EDIT_TextAddr(es, es->hText); |
| text[es->textlen - 1] = '\0'; |
| currchar = CurrChar; |
| } |
| /* make space for new character and put char in buffer */ |
| memmove(currchar + 1, currchar, strlen(currchar) + 1); |
| *currchar = ch; |
| EDIT_ModTextPointers(hwnd, es->CurrLine + 1, 1); |
| es->TextChanged = TRUE; |
| NOTIFY_PARENT(hwnd, EN_UPDATE); |
| |
| /* re-adjust textwidth, if necessary, and redraw line */ |
| HideCaret(hwnd); |
| if (IsMultiLine() && es->wlines > 1) |
| { |
| es->textwidth = max(es->textwidth, |
| EDIT_StrLength(es, EDIT_TextLine(hwnd, es->CurrLine), |
| (int)(EDIT_TextLine(hwnd, es->CurrLine + 1) - |
| EDIT_TextLine(hwnd, es->CurrLine)), 0)); |
| } |
| else |
| es->textwidth = max(es->textwidth, |
| EDIT_StrLength(es, text, strlen(text), 0)); |
| EDIT_WriteTextLine(hwnd, NULL, es->wtop + es->WndRow); |
| |
| if (ch == '\n') |
| { |
| if (es->wleft > 0) |
| FullPaint = TRUE; |
| es->wleft = 0; |
| EDIT_BuildTextPointers(hwnd); |
| EDIT_End(hwnd); |
| EDIT_Forward(hwnd); |
| |
| /* invalidate rest of window */ |
| GetClientRect(hwnd, &rc); |
| if (!FullPaint) |
| rc.top = es->WndRow * es->txtht; |
| InvalidateRect(hwnd, &rc, FALSE); |
| |
| SetCaretPos(es->WndCol, es->WndRow * es->txtht); |
| ShowCaret(hwnd); |
| UpdateWindow(hwnd); |
| NOTIFY_PARENT(hwnd, EN_CHANGE); |
| return; |
| } |
| |
| /* test end of window */ |
| if (es->WndCol >= ClientWidth(wndPtr) - |
| EDIT_CharWidth(es, ch, es->WndCol + es->wleft)) |
| { |
| /* TODO:- Word wrap to be handled here */ |
| |
| /* if (!(currchar == text + es->MaxTextLen - 2)) */ |
| EDIT_KeyHScroll(hwnd, SB_LINEDOWN); |
| } |
| es->WndCol += EDIT_CharWidth(es, ch, es->WndCol + es->wleft); |
| es->CurrCol++; |
| SetCaretPos(es->WndCol, es->WndRow * es->txtht); |
| ShowCaret(hwnd); |
| NOTIFY_PARENT(hwnd, EN_CHANGE); |
| } |
| |
| |
| /********************************************************************* |
| * EDIT_CharWidth |
| * |
| * Return the width of the given character in pixels. |
| * The current column offset in pixels _pcol_ is required to calculate |
| * the width of a tab. |
| */ |
| |
| int EDIT_CharWidth(EDITSTATE *es, short ch, int pcol) |
| { |
| short *charWidths = (short *)EDIT_HEAP_ADDR(es->hCharWidths); |
| |
| if (ch != VK_TAB) |
| return (charWidths[ch]); |
| else |
| return (EDIT_GetNextTabStop(es, pcol) - pcol); |
| } |
| |
| |
| /********************************************************************* |
| * EDIT_GetNextTabStop |
| * |
| * Return the next tab stop beyond _pcol_. |
| */ |
| |
| int EDIT_GetNextTabStop(EDITSTATE *es, int pcol) |
| { |
| int i; |
| int baseUnitWidth = LOWORD(GetDialogBaseUnits()); |
| unsigned short *tabstops = EDIT_HEAP_ADDR(es->hTabStops); |
| |
| if (es->NumTabStops == 0) |
| return ROUNDUP(pcol, 8); |
| else if (es->NumTabStops == 1) |
| return ROUNDUP(pcol, *tabstops * baseUnitWidth / 4); |
| else |
| { |
| for (i = 0; i < es->NumTabStops; i++) |
| { |
| if (*(tabstops + i) * baseUnitWidth / 4 >= pcol) |
| return (*(tabstops + i) * baseUnitWidth / 4); |
| } |
| return pcol; |
| } |
| } |
| |
| |
| /********************************************************************* |
| * EDIT_Forward |
| * |
| * Cursor right key: move right one character position. |
| */ |
| |
| void EDIT_Forward(HWND hwnd) |
| { |
| WND *wndPtr = WIN_FindWndPtr(hwnd); |
| EDITSTATE *es = (EDITSTATE *)EDIT_HEAP_ADDR((HANDLE)(*(wndPtr->wExtra))); |
| char *text = EDIT_TextAddr(es, es->hText); |
| |
| if (*CurrChar == '\0') |
| return; |
| |
| if (*CurrChar == '\n') |
| { |
| EDIT_Home(hwnd); |
| EDIT_Downward(hwnd); |
| } |
| else |
| { |
| es->WndCol += EDIT_CharWidth(es, *CurrChar, es->WndCol + es->wleft); |
| es->CurrCol++; |
| if (es->WndCol >= ClientWidth(wndPtr)) |
| EDIT_KeyHScroll(hwnd, SB_LINEDOWN); |
| } |
| } |
| |
| |
| |
| /********************************************************************* |
| * EDIT_Downward |
| * |
| * Cursor down key: move down one line. |
| */ |
| |
| void EDIT_Downward(HWND hwnd) |
| { |
| WND *wndPtr = WIN_FindWndPtr(hwnd); |
| EDITSTATE *es = (EDITSTATE *)EDIT_HEAP_ADDR((HANDLE)(*(wndPtr->wExtra))); |
| |
| #ifdef DEBUG_EDIT |
| printf("EDIT_Downward: WndRow=%d, wtop=%d, wlines=%d\n", es->WndRow, es->wtop, es->wlines); |
| #endif |
| |
| if (IsMultiLine() && (es->WndRow + es->wtop + 1 < es->wlines)) |
| { |
| es->CurrLine++; |
| if (es->WndRow == ClientHeight(wndPtr, es) - 1) |
| { |
| es->WndRow++; |
| EDIT_KeyVScrollLine(hwnd, SB_LINEDOWN); |
| } |
| else |
| es->WndRow++; |
| EDIT_StickEnd(hwnd); |
| } |
| } |
| |
| |
| /********************************************************************* |
| * EDIT_Upward |
| * |
| * Cursor up key: move up one line. |
| */ |
| |
| void EDIT_Upward(HWND hwnd) |
| { |
| WND *wndPtr = WIN_FindWndPtr(hwnd); |
| EDITSTATE *es = (EDITSTATE *)EDIT_HEAP_ADDR((HANDLE)(*(wndPtr->wExtra))); |
| |
| if (IsMultiLine() && es->CurrLine != 0) |
| { |
| --es->CurrLine; |
| if (es->WndRow == 0) |
| { |
| --es->WndRow; |
| EDIT_KeyVScrollLine(hwnd, SB_LINEUP); |
| } |
| else |
| --es->WndRow; |
| EDIT_StickEnd(hwnd); |
| } |
| } |
| |
| |
| /********************************************************************* |
| * EDIT_Backward |
| * |
| * Cursor left key: move left one character position. |
| */ |
| |
| void EDIT_Backward(HWND hwnd) |
| { |
| WND *wndPtr = WIN_FindWndPtr(hwnd); |
| EDITSTATE *es = (EDITSTATE *)EDIT_HEAP_ADDR((HANDLE)(*(wndPtr->wExtra))); |
| char *text = EDIT_TextAddr(es, es->hText); |
| |
| if (es->CurrCol) |
| { |
| --es->CurrCol; |
| es->WndCol -= EDIT_CharWidth(es, *CurrChar, es->WndCol + es->wleft); |
| if (es->WndCol < 0) |
| EDIT_KeyHScroll(hwnd, SB_LINEUP); |
| } |
| else if (IsMultiLine() && es->CurrLine != 0) |
| { |
| EDIT_Upward(hwnd); |
| EDIT_End(hwnd); |
| } |
| } |
| |
| |
| /********************************************************************* |
| * EDIT_End |
| * |
| * End key: move to end of line. |
| */ |
| |
| void EDIT_End(HWND hwnd) |
| { |
| RECT rc; |
| WND *wndPtr = WIN_FindWndPtr(hwnd); |
| EDITSTATE *es = (EDITSTATE *)EDIT_HEAP_ADDR((HANDLE)(*(wndPtr->wExtra))); |
| char *text = EDIT_TextAddr(es, es->hText); |
| |
| while (*CurrChar && *CurrChar != '\n') |
| { |
| es->WndCol += EDIT_CharWidth(es, *CurrChar, es->WndCol + es->wleft); |
| es->CurrCol++; |
| } |
| |
| if (es->WndCol >= ClientWidth(wndPtr)) |
| { |
| es->wleft = es->WndCol - ClientWidth(wndPtr) + HSCROLLDIM; |
| es->WndCol -= es->wleft; |
| InvalidateRect(hwnd, NULL, FALSE); |
| UpdateWindow(hwnd); |
| } |
| } |
| |
| |
| /********************************************************************* |
| * EDIT_Home |
| * |
| * Home key: move to beginning of line. |
| */ |
| |
| void EDIT_Home(HWND hwnd) |
| { |
| RECT rc; |
| WND *wndPtr = WIN_FindWndPtr(hwnd); |
| EDITSTATE *es = (EDITSTATE *)EDIT_HEAP_ADDR((HANDLE)(*(wndPtr->wExtra))); |
| |
| es->CurrCol = es->WndCol = 0; |
| if (es->wleft != 0) |
| { |
| es->wleft = 0; |
| InvalidateRect(hwnd, NULL, FALSE); |
| UpdateWindow(hwnd); |
| } |
| } |
| |
| |
| /********************************************************************* |
| * EDIT_StickEnd |
| * |
| * Stick the cursor to the end of the line. |
| */ |
| |
| void EDIT_StickEnd(HWND hwnd) |
| { |
| WND *wndPtr = WIN_FindWndPtr(hwnd); |
| EDITSTATE *es = (EDITSTATE *)EDIT_HEAP_ADDR((HANDLE)(*(wndPtr->wExtra))); |
| int len = EDIT_LineLength(hwnd, es->CurrLine); |
| char *cp = EDIT_TextLine(hwnd, es->CurrLine); |
| char currpel; |
| |
| es->CurrCol = min(len, es->CurrCol); |
| es->WndCol = min(EDIT_StrLength(es, cp, len, 0) - es->wleft, es->WndCol); |
| currpel = EDIT_StrLength(es, cp, es->CurrCol, 0); |
| |
| if (es->wleft > currpel) |
| { |
| es->wleft = max(0, currpel - 20); |
| es->WndCol = currpel - es->wleft; |
| UpdateWindow(hwnd); |
| } |
| else if (currpel - es->wleft >= ClientWidth(wndPtr)) |
| { |
| es->wleft = currpel - (ClientWidth(wndPtr) - 5); |
| es->WndCol = currpel - es->wleft; |
| UpdateWindow(hwnd); |
| } |
| } |
| |
| |
| /********************************************************************* |
| * WM_KEYDOWN message function |
| */ |
| |
| void EDIT_KeyDownMsg(HWND hwnd, WORD wParam) |
| { |
| WND *wndPtr = WIN_FindWndPtr(hwnd); |
| EDITSTATE *es = (EDITSTATE *)EDIT_HEAP_ADDR((HANDLE)(*(wndPtr->wExtra))); |
| |
| #ifdef DEBUG_EDIT |
| printf("EDIT_KeyDownMsg: key=%x\n", wParam); |
| #endif |
| |
| HideCaret(hwnd); |
| switch (wParam) |
| { |
| case VK_UP: |
| if (SelMarked(es)) |
| EDIT_ClearSel(hwnd); |
| if (IsMultiLine()) |
| EDIT_Upward(hwnd); |
| else |
| EDIT_Backward(hwnd); |
| break; |
| |
| case VK_DOWN: |
| if (SelMarked(es)) |
| EDIT_ClearSel(hwnd); |
| if (IsMultiLine()) |
| EDIT_Downward(hwnd); |
| else |
| EDIT_Forward(hwnd); |
| break; |
| |
| case VK_RIGHT: |
| if (SelMarked(es)) |
| EDIT_ClearSel(hwnd); |
| EDIT_Forward(hwnd); |
| break; |
| |
| case VK_LEFT: |
| if (SelMarked(es)) |
| EDIT_ClearSel(hwnd); |
| EDIT_Backward(hwnd); |
| break; |
| |
| case VK_HOME: |
| if (SelMarked(es)) |
| EDIT_ClearSel(hwnd); |
| EDIT_Home(hwnd); |
| break; |
| |
| case VK_END: |
| if (SelMarked(es)) |
| EDIT_ClearSel(hwnd); |
| EDIT_End(hwnd); |
| break; |
| |
| case VK_PRIOR: |
| if (IsMultiLine()) |
| { |
| if (SelMarked(es)) |
| EDIT_ClearSel(hwnd); |
| EDIT_KeyVScrollPage(hwnd, SB_PAGEUP); |
| } |
| break; |
| |
| case VK_NEXT: |
| if (IsMultiLine()) |
| { |
| if (SelMarked(es)) |
| EDIT_ClearSel(hwnd); |
| EDIT_KeyVScrollPage(hwnd, SB_PAGEDOWN); |
| } |
| break; |
| |
| case VK_BACK: |
| if (SelMarked(es)) |
| EDIT_DeleteSel(hwnd); |
| else |
| { |
| if (es->CurrCol == 0 && es->CurrLine == 0) |
| break; |
| EDIT_Backward(hwnd); |
| EDIT_DelKey(hwnd); |
| } |
| break; |
| |
| case VK_DELETE: |
| if (SelMarked(es)) |
| EDIT_DeleteSel(hwnd); |
| else |
| EDIT_DelKey(hwnd); |
| break; |
| } |
| |
| SetCaretPos(es->WndCol, es->WndRow * es->txtht); |
| ShowCaret(hwnd); |
| } |
| |
| |
| /********************************************************************* |
| * EDIT_KeyHScroll |
| * |
| * Scroll text horizontally using cursor keys. |
| */ |
| |
| void EDIT_KeyHScroll(HWND hwnd, WORD opt) |
| { |
| RECT rc; |
| int hscrollpos; |
| WND *wndPtr = WIN_FindWndPtr(hwnd); |
| EDITSTATE *es = (EDITSTATE *)EDIT_HEAP_ADDR((HANDLE)(*(wndPtr->wExtra))); |
| |
| if (opt == SB_LINEDOWN) |
| { |
| es->wleft += HSCROLLDIM; |
| es->WndCol -= HSCROLLDIM; |
| } |
| else |
| { |
| if (es->wleft == 0) |
| return; |
| if (es->wleft - HSCROLLDIM < 0) |
| { |
| es->WndCol += es->wleft; |
| es->wleft = 0; |
| } |
| else |
| { |
| es->wleft -= HSCROLLDIM; |
| es->WndCol += HSCROLLDIM; |
| } |
| } |
| |
| InvalidateRect(hwnd, NULL, FALSE); |
| UpdateWindow(hwnd); |
| |
| if (IsHScrollBar()) |
| { |
| hscrollpos = EDIT_ComputeHScrollPos(hwnd); |
| SetScrollPos(hwnd, SB_HORZ, hscrollpos, TRUE); |
| } |
| } |
| |
| |
| /********************************************************************* |
| * EDIT_KeyVScrollLine |
| * |
| * Scroll text vertically by one line using keyboard. |
| */ |
| |
| void EDIT_KeyVScrollLine(HWND hwnd, WORD opt) |
| { |
| RECT rc; |
| int y, vscrollpos; |
| WND *wndPtr = WIN_FindWndPtr(hwnd); |
| EDITSTATE *es = (EDITSTATE *)EDIT_HEAP_ADDR((HANDLE)(*(wndPtr->wExtra))); |
| |
| if (!IsMultiLine()) |
| return; |
| |
| if (opt == SB_LINEDOWN) |
| { |
| /* move down one line */ |
| if (es->wtop + ClientHeight(wndPtr, es) >= es->wlines) |
| return; |
| es->wtop++; |
| } |
| else |
| { |
| /* move up one line */ |
| if (es->wtop == 0) |
| return; |
| --es->wtop; |
| } |
| |
| if (IsWindowVisible(hwnd)) |
| { |
| /* adjust client bottom to nearest whole line */ |
| GetClientRect(hwnd, &rc); |
| rc.bottom = (rc.bottom / es->txtht) * es->txtht; |
| |
| if (opt == SB_LINEUP) |
| { |
| /* move up one line (scroll window down) */ |
| ScrollWindow(hwnd, 0, es->txtht, &rc, &rc); |
| /* write top line */ |
| EDIT_WriteTextLine(hwnd, NULL, es->wtop); |
| es->WndRow++; |
| } |
| else |
| { |
| /* move down one line (scroll window up) */ |
| ScrollWindow(hwnd, 0, -(es->txtht), &rc, &rc); |
| /* write bottom line */ |
| y = (((rc.bottom - rc.top) / es->txtht) - 1); |
| EDIT_WriteTextLine(hwnd, NULL, es->wtop + y); |
| --es->WndRow; |
| } |
| } |
| |
| /* reset the vertical scroll bar */ |
| if (IsVScrollBar()) |
| { |
| vscrollpos = EDIT_ComputeVScrollPos(hwnd); |
| SetScrollPos(hwnd, SB_VERT, vscrollpos, TRUE); |
| } |
| } |
| |
| |
| /********************************************************************* |
| * EDIT_KeyVScrollPage |
| * |
| * Scroll text vertically by one page using keyboard. |
| */ |
| |
| void EDIT_KeyVScrollPage(HWND hwnd, WORD opt) |
| { |
| RECT rc; |
| int vscrollpos; |
| WND *wndPtr = WIN_FindWndPtr(hwnd); |
| EDITSTATE *es = (EDITSTATE *)EDIT_HEAP_ADDR((HANDLE)(*(wndPtr->wExtra))); |
| |
| if (IsMultiLine()) |
| { |
| if (opt == SB_PAGEUP) |
| { |
| if (es->wtop) |
| es->wtop -= ClientHeight(wndPtr, es); |
| } |
| else |
| { |
| if (es->wtop + ClientHeight(wndPtr, es) < es->wlines) |
| { |
| es->wtop += ClientHeight(wndPtr, es); |
| if (es->wtop > es->wlines - ClientHeight(wndPtr, es)) |
| es->wtop = es->wlines - ClientHeight(wndPtr, es); |
| } |
| } |
| if (es->wtop < 0) |
| es->wtop = 0; |
| |
| es->CurrLine = es->wtop + es->WndRow; |
| EDIT_StickEnd(hwnd); |
| InvalidateRect(hwnd, NULL, TRUE); |
| UpdateWindow(hwnd); |
| |
| /* reset the vertical scroll bar */ |
| if (IsVScrollBar()) |
| { |
| vscrollpos = EDIT_ComputeVScrollPos(hwnd); |
| SetScrollPos(hwnd, SB_VERT, vscrollpos, TRUE); |
| } |
| } |
| } |
| |
| |
| /********************************************************************* |
| * EDIT_KeyVScrollDoc |
| * |
| * Scroll text to top and bottom of document using keyboard. |
| */ |
| |
| void EDIT_KeyVScrollDoc(HWND hwnd, WORD opt) |
| { |
| RECT rc; |
| int vscrollpos; |
| WND *wndPtr = WIN_FindWndPtr(hwnd); |
| EDITSTATE *es = (EDITSTATE *)EDIT_HEAP_ADDR((HANDLE)(*(wndPtr->wExtra))); |
| |
| if (!IsMultiLine()) |
| return; |
| |
| if (opt == SB_TOP) |
| es->wtop = es->wleft = 0; |
| else if (es->wtop + ClientHeight(wndPtr, es) < es->wlines) |
| { |
| es->wtop = es->wlines - ClientHeight(wndPtr, es); |
| es->wleft = 0; |
| } |
| |
| es->CurrLine = es->wlines; |
| es->WndRow = es->wlines - es->wtop; |
| EDIT_End(hwnd); |
| InvalidateRect(hwnd, NULL, TRUE); |
| UpdateWindow(hwnd); |
| |
| /* reset the vertical scroll bar */ |
| if (IsVScrollBar()) |
| { |
| vscrollpos = EDIT_ComputeVScrollPos(hwnd); |
| SetScrollPos(hwnd, SB_VERT, vscrollpos, TRUE); |
| } |
| } |
| |
| |
| /********************************************************************* |
| * EDIT_ComputeVScrollPos |
| * |
| * Compute the vertical scroll bar position from the window |
| * position and text width. |
| */ |
| |
| int EDIT_ComputeVScrollPos(HWND hwnd) |
| { |
| int vscrollpos; |
| short minpos, maxpos; |
| WND *wndPtr = WIN_FindWndPtr(hwnd); |
| EDITSTATE *es = (EDITSTATE *)EDIT_HEAP_ADDR((HANDLE)(*(wndPtr->wExtra))); |
| |
| GetScrollRange(hwnd, SB_VERT, &minpos, &maxpos); |
| |
| if (es->wlines > ClientHeight(wndPtr, es)) |
| vscrollpos = (double)(es->wtop) / (double)(es->wlines - |
| ClientHeight(wndPtr, es)) * (maxpos - minpos); |
| else |
| vscrollpos = minpos; |
| |
| return vscrollpos; |
| } |
| |
| |
| /********************************************************************* |
| * EDIT_ComputeHScrollPos |
| * |
| * Compute the horizontal scroll bar position from the window |
| * position and text width. |
| */ |
| |
| int EDIT_ComputeHScrollPos(HWND hwnd) |
| { |
| int hscrollpos; |
| short minpos, maxpos; |
| WND *wndPtr = WIN_FindWndPtr(hwnd); |
| EDITSTATE *es = (EDITSTATE *)EDIT_HEAP_ADDR((HANDLE)(*(wndPtr->wExtra))); |
| |
| GetScrollRange(hwnd, SB_HORZ, &minpos, &maxpos); |
| |
| if (es->textwidth > ClientWidth(wndPtr)) |
| hscrollpos = (double)(es->wleft) / (double)(es->textwidth - |
| ClientWidth(wndPtr)) * (maxpos - minpos); |
| else |
| hscrollpos = minpos; |
| |
| return hscrollpos; |
| } |
| |
| |
| /********************************************************************* |
| * EDIT_DelKey |
| * |
| * Delete character to right of cursor. |
| */ |
| |
| void EDIT_DelKey(HWND hwnd) |
| { |
| RECT rc; |
| WND *wndPtr = WIN_FindWndPtr(hwnd); |
| EDITSTATE *es = (EDITSTATE *)EDIT_HEAP_ADDR((HANDLE)(*(wndPtr->wExtra))); |
| char *currchar = CurrChar; |
| BOOL repaint = *currchar == '\n'; |
| |
| if (IsMultiLine() && *currchar == '\n' && *(currchar + 1) == '\0') |
| return; |
| strcpy(currchar, currchar + 1); |
| NOTIFY_PARENT(hwnd, EN_UPDATE); |
| |
| if (repaint) |
| { |
| EDIT_BuildTextPointers(hwnd); |
| GetClientRect(hwnd, &rc); |
| rc.top = es->WndRow * es->txtht; |
| InvalidateRect(hwnd, &rc, FALSE); |
| UpdateWindow(hwnd); |
| } |
| else |
| { |
| EDIT_ModTextPointers(hwnd, es->CurrLine + 1, -1); |
| EDIT_WriteTextLine(hwnd, NULL, es->WndRow + es->wtop); |
| } |
| |
| es->TextChanged = TRUE; |
| NOTIFY_PARENT(hwnd, EN_CHANGE); |
| } |
| |
| /********************************************************************* |
| * WM_VSCROLL message function |
| */ |
| |
| void EDIT_VScrollMsg(HWND hwnd, WORD wParam, LONG lParam) |
| { |
| WND *wndPtr = WIN_FindWndPtr(hwnd); |
| EDITSTATE *es = (EDITSTATE *)EDIT_HEAP_ADDR((HANDLE)(*(wndPtr->wExtra))); |
| |
| if (IsMultiLine()) |
| { |
| HideCaret(hwnd); |
| |
| switch (wParam) |
| { |
| case SB_LINEUP: |
| case SB_LINEDOWN: |
| EDIT_VScrollLine(hwnd, wParam); |
| break; |
| |
| case SB_PAGEUP: |
| case SB_PAGEDOWN: |
| EDIT_VScrollPage(hwnd, wParam); |
| break; |
| } |
| } |
| |
| SetCaretPos(es->WndCol, es->WndRow); |
| ShowCaret(hwnd); |
| } |
| |
| |
| /********************************************************************* |
| * EDIT_VScrollLine |
| * |
| * Scroll text vertically by one line using scrollbars. |
| */ |
| |
| void EDIT_VScrollLine(HWND hwnd, WORD opt) |
| { |
| RECT rc; |
| int y; |
| WND *wndPtr = WIN_FindWndPtr(hwnd); |
| EDITSTATE *es = (EDITSTATE *)EDIT_HEAP_ADDR((HANDLE)(*(wndPtr->wExtra))); |
| |
| #ifdef DEBUG_EDIT |
| printf("EDIT_VScrollLine: direction=%d\n", opt); |
| #endif |
| |
| if (opt == SB_LINEDOWN) |
| { |
| /* move down one line */ |
| if (es->wtop + ClientHeight(wndPtr, es) >= es->wlines) |
| return; |
| es->wtop++; |
| } |
| else |
| { |
| /* move up one line */ |
| if (es->wtop == 0) |
| return; |
| --es->wtop; |
| } |
| |
| if (IsWindowVisible(hwnd)) |
| { |
| /* adjust client bottom to nearest whole line */ |
| GetClientRect(hwnd, &rc); |
| rc.bottom = (rc.bottom / es->txtht) * es->txtht; |
| |
| if (opt == SB_LINEUP) |
| { |
| /* move up one line (scroll window down) */ |
| ScrollWindow(hwnd, 0, es->txtht, &rc, &rc); |
| /* write top line */ |
| EDIT_WriteTextLine(hwnd, NULL, es->wtop); |
| es->WndRow++; |
| } |
| else |
| { |
| /* move down one line (scroll window up) */ |
| ScrollWindow(hwnd, 0, -(es->txtht), &rc, &rc); |
| /* write bottom line */ |
| y = ((rc.bottom - rc.top / es->txtht) - 1); |
| EDIT_WriteTextLine(hwnd, NULL, es->wtop + y); |
| --es->WndRow; |
| } |
| } |
| } |
| |
| |
| /********************************************************************* |
| * EDIT_VScrollPage |
| * |
| * Scroll text vertically by one page using keyboard. |
| */ |
| |
| void EDIT_VScrollPage(HWND hwnd, WORD opt) |
| { |
| RECT rc; |
| int vscrollpos; |
| WND *wndPtr = WIN_FindWndPtr(hwnd); |
| EDITSTATE *es = (EDITSTATE *)EDIT_HEAP_ADDR((HANDLE)(*(wndPtr->wExtra))); |
| |
| if (opt == SB_PAGEUP) |
| { |
| if (es->wtop) |
| es->wtop -= ClientHeight(wndPtr, es); |
| } |
| else |
| { |
| if (es->wtop + ClientHeight(wndPtr, es) < es->wlines) |
| { |
| es->wtop += ClientHeight(wndPtr, es); |
| if (es->wtop > es->wlines - ClientHeight(wndPtr, es)) |
| es->wtop = es->wlines - ClientHeight(wndPtr, es); |
| } |
| } |
| if (es->wtop < 0) |
| es->wtop = 0; |
| |
| InvalidateRect(hwnd, NULL, TRUE); |
| UpdateWindow(hwnd); |
| |
| /* reset the vertical scroll bar */ |
| if (IsVScrollBar()) |
| { |
| vscrollpos = EDIT_ComputeVScrollPos(hwnd); |
| SetScrollPos(hwnd, SB_VERT, vscrollpos, TRUE); |
| } |
| } |
| |
| |
| /********************************************************************* |
| * WM_HSCROLL message function |
| */ |
| |
| void EDIT_HScrollMsg(HWND hwnd, WORD wParam, LONG lParam) |
| { |
| WND *wndPtr = WIN_FindWndPtr(hwnd); |
| EDITSTATE *es = (EDITSTATE *)EDIT_HEAP_ADDR((HANDLE)(*(wndPtr->wExtra))); |
| |
| switch (wParam) |
| { |
| case SB_LINEUP: |
| case SB_LINEDOWN: |
| HideCaret(hwnd); |
| |
| SetCaretPos(es->WndCol, es->WndRow * es->txtht); |
| ShowCaret(hwnd); |
| break; |
| } |
| } |
| |
| |
| /********************************************************************* |
| * WM_SIZE message function |
| */ |
| |
| void EDIT_SizeMsg(HWND hwnd, WORD wParam, LONG lParam) |
| { |
| RECT rc; |
| WND *wndPtr = WIN_FindWndPtr(hwnd); |
| EDITSTATE *es = (EDITSTATE *)EDIT_HEAP_ADDR((HANDLE)(*(wndPtr->wExtra))); |
| |
| if (wParam != SIZE_MAXIMIZED && wParam != SIZE_RESTORED) return; |
| |
| InvalidateRect(hwnd, NULL, TRUE); |
| es->PaintBkgd = TRUE; |
| UpdateWindow(hwnd); |
| } |
| |
| |
| /********************************************************************* |
| * WM_LBUTTONDOWN message function |
| */ |
| |
| void EDIT_LButtonDownMsg(HWND hwnd, WORD wParam, LONG lParam) |
| { |
| char *cp; |
| int len; |
| BOOL end = FALSE; |
| WND *wndPtr = WIN_FindWndPtr(hwnd); |
| EDITSTATE *es = (EDITSTATE *)EDIT_HEAP_ADDR((HANDLE)(*(wndPtr->wExtra))); |
| |
| if (SelMarked(es)) |
| EDIT_ClearSel(hwnd); |
| |
| es->WndRow = HIWORD(lParam) / es->txtht; |
| if (es->WndRow > es->wlines - es->wtop - 1) |
| { |
| if (es->wlines) |
| es->WndRow = es->wlines - es->wtop - 1; |
| else |
| es->WndRow = 0; |
| end = TRUE; |
| } |
| es->CurrLine = es->wtop + es->WndRow; |
| |
| cp = EDIT_TextLine(hwnd, es->CurrLine); |
| len = EDIT_LineLength(hwnd, es->CurrLine); |
| es->WndCol = LOWORD(lParam); |
| if (es->WndCol > EDIT_StrLength(es, cp, len, 0) - es->wleft || end) |
| es->WndCol = EDIT_StrLength(es, cp, len, 0) - es->wleft; |
| es->CurrCol = EDIT_PixelToChar(hwnd, es->CurrLine, &(es->WndCol)); |
| |
| ButtonDown = TRUE; |
| ButtonRow = es->CurrLine; |
| ButtonCol = es->CurrCol; |
| } |
| |
| |
| /********************************************************************* |
| * WM_MOUSEMOVE message function |
| */ |
| |
| void EDIT_MouseMoveMsg(HWND hwnd, WORD wParam, LONG lParam) |
| { |
| if (wParam != MK_LBUTTON) |
| return; |
| |
| if (ButtonDown) |
| { |
| EDIT_SetAnchor(hwnd, ButtonRow, ButtonCol); |
| TextMarking = TRUE; |
| ButtonDown = FALSE; |
| } |
| |
| if (TextMarking) |
| EDIT_ExtendSel(hwnd, LOWORD(lParam), HIWORD(lParam)); |
| } |
| |
| |
| /********************************************************************* |
| * EDIT_PixelToChar |
| * |
| * Convert a pixel offset in the given row to a character offset, |
| * adjusting the pixel offset to the nearest whole character if |
| * necessary. |
| */ |
| |
| int EDIT_PixelToChar(HWND hwnd, int row, int *pixel) |
| { |
| int ch = 0, i = 0, s_i; |
| char *text; |
| WND *wndPtr = WIN_FindWndPtr(hwnd); |
| EDITSTATE *es = (EDITSTATE *)EDIT_HEAP_ADDR((HANDLE)(*(wndPtr->wExtra))); |
| |
| #ifdef DEBUG_EDIT |
| printf("EDIT_PixelToChar: row=%d, pixel=%d\n", row, *pixel); |
| #endif |
| |
| text = EDIT_TextLine(hwnd, row); |
| while (i < *pixel) |
| { |
| s_i = i; |
| i += EDIT_CharWidth(es, *(text + ch), i); |
| ch++; |
| } |
| |
| /* if stepped past _pixel_, go back a character */ |
| if (i - *pixel) |
| { |
| i = s_i; |
| --ch; |
| } |
| *pixel = i; |
| return ch; |
| } |
| |
| |
| /********************************************************************* |
| * WM_SETTEXT message function |
| */ |
| |
| LONG EDIT_SetTextMsg(HWND hwnd, LONG lParam) |
| { |
| int len; |
| char *text; |
| RECT rc; |
| WND *wndPtr = WIN_FindWndPtr(hwnd); |
| EDITSTATE *es = (EDITSTATE *)EDIT_HEAP_ADDR((HANDLE)(*(wndPtr->wExtra))); |
| |
| if (strlen((char *)lParam) <= es->MaxTextLen) |
| { |
| len = strlen((char *)lParam); |
| EDIT_ClearText(hwnd); |
| es->textlen = len; |
| es->hText = EDIT_TextReAlloc(es, es->hText, len + 3); |
| text = EDIT_TextAddr(es, es->hText); |
| strcpy(text, (char *)lParam); |
| /* text[len] = '\n'; */ /* Removed by Bob Amstadt */ |
| text[len + 1] = '\0'; |
| text[len + 2] = '\0'; |
| EDIT_BuildTextPointers(hwnd); |
| InvalidateRect(hwnd, NULL, TRUE); |
| es->PaintBkgd = TRUE; |
| es->TextChanged = TRUE; |
| return 0L; |
| } |
| else |
| return EN_ERRSPACE; |
| } |
| |
| |
| /********************************************************************* |
| * EDIT_ClearText |
| * |
| * Clear text from text buffer. |
| */ |
| |
| void EDIT_ClearText(HWND hwnd) |
| { |
| WND *wndPtr = WIN_FindWndPtr(hwnd); |
| EDITSTATE *es = (EDITSTATE *)EDIT_HEAP_ADDR((HANDLE)(*(wndPtr->wExtra))); |
| unsigned int blen = EditBufLen(wndPtr) + 2; |
| char *text; |
| |
| es->hText = EDIT_TextReAlloc(es, es->hText, blen); |
| text = EDIT_TextAddr(es, es->hText); |
| memset(text, 0, blen); |
| es->textlen = 0; |
| es->wlines = 0; |
| es->CurrLine = es->CurrCol = 0; |
| es->WndRow = es->WndCol = 0; |
| es->wleft = es->wtop = 0; |
| es->textwidth = 0; |
| es->TextChanged = FALSE; |
| EDIT_ClearTextPointers(hwnd); |
| } |
| |
| |
| /********************************************************************* |
| * EM_SETSEL message function |
| */ |
| |
| void EDIT_SetSelMsg(HWND hwnd, LONG lParam) |
| { |
| int so, eo; |
| WND *wndPtr = WIN_FindWndPtr(hwnd); |
| EDITSTATE *es = (EDITSTATE *)EDIT_HEAP_ADDR((HANDLE)(*(wndPtr->wExtra))); |
| |
| so = LOWORD(lParam); |
| eo = HIWORD(lParam); |
| if (so > eo) |
| swap(&so, &eo); |
| |
| EDIT_GetLineCol(hwnd, so, &(es->SelBegLine), &(es->SelBegCol)); |
| EDIT_GetLineCol(hwnd, eo, &(es->SelEndLine), &(es->SelEndCol)); |
| |
| if (SelMarked(es)) |
| { |
| es->CurrLine = es->SelEndLine; |
| es->CurrCol = es->SelEndCol; |
| es->WndRow = es->SelEndLine - es->wtop; |
| if (es->WndRow < 0) |
| { |
| es->wtop = es->SelEndLine; |
| es->WndRow = 0; |
| } |
| es->WndCol = EDIT_StrLength(es, EDIT_TextLine(hwnd, es->SelEndLine), |
| es->SelEndCol, 0) - es->wleft; |
| } |
| InvalidateRect(hwnd, NULL, TRUE); |
| UpdateWindow(hwnd); |
| } |
| |
| |
| /********************************************************************* |
| * EDIT_GetLineCol |
| * |
| * Return line and column in text buffer from character offset. |
| */ |
| |
| void EDIT_GetLineCol(HWND hwnd, int off, int *line, int *col) |
| { |
| int lineno; |
| char *cp, *cp1; |
| WND *wndPtr = WIN_FindWndPtr(hwnd); |
| EDITSTATE *es = (EDITSTATE *)EDIT_HEAP_ADDR((HANDLE)(*(wndPtr->wExtra))); |
| char *text = EDIT_TextAddr(es, es->hText); |
| unsigned int *textPtrs = (unsigned int *)EDIT_HEAP_ADDR(es->hTextPtrs); |
| |
| /* check for (0,0) */ |
| if (!off) |
| { |
| *line = 0; |
| *col = 0; |
| return; |
| } |
| |
| if (off > strlen(text)) off = strlen(text); |
| cp1 = text; |
| for (lineno = 0; lineno < es->wlines; lineno++) |
| { |
| cp = text + *(textPtrs + lineno); |
| if (off == (int)(cp - text)) |
| { |
| *line = lineno; |
| *col = 0; |
| return; |
| } |
| if (off < (int)(cp - text)) |
| break; |
| cp1 = cp; |
| } |
| *line = lineno - 1; |
| *col = off - (int)(cp1 - text); |
| #if 0 |
| if (*(text + *col) == '\0') |
| (*col)--; |
| #endif |
| } |
| |
| |
| /********************************************************************* |
| * EDIT_DeleteSel |
| * |
| * Delete the current selected text (if any) |
| */ |
| |
| void EDIT_DeleteSel(HWND hwnd) |
| { |
| char *bbl, *bel; |
| int len; |
| WND *wndPtr = WIN_FindWndPtr(hwnd); |
| EDITSTATE *es = (EDITSTATE *)EDIT_HEAP_ADDR((HANDLE)(*(wndPtr->wExtra))); |
| char *text = EDIT_TextAddr(es, es->hText); |
| |
| if (SelMarked(es)) |
| { |
| bbl = EDIT_TextLine(hwnd, es->SelBegLine) + es->SelBegCol; |
| bel = EDIT_TextLine(hwnd, es->SelEndLine) + es->SelEndCol; |
| len = (int)(bel - bbl); |
| EDIT_SaveDeletedText(hwnd, bbl, len, es->SelBegLine, es->SelBegCol); |
| es->TextChanged = TRUE; |
| strcpy(bbl, bel); |
| |
| es->CurrLine = es->SelBegLine; |
| es->CurrCol = es->SelBegCol; |
| es->WndRow = es->SelBegLine - es->wtop; |
| if (es->WndRow < 0) |
| { |
| es->wtop = es->SelBegLine; |
| es->WndRow = 0; |
| } |
| es->WndCol = EDIT_StrLength(es, bbl - es->SelBegCol, |
| es->SelBegCol, 0) - es->wleft; |
| |
| EDIT_BuildTextPointers(hwnd); |
| es->PaintBkgd = TRUE; |
| EDIT_ClearSel(hwnd); |
| } |
| } |
| |
| |
| /********************************************************************* |
| * EDIT_ClearSel |
| * |
| * Clear the current selection. |
| */ |
| |
| void EDIT_ClearSel(HWND hwnd) |
| { |
| WND *wndPtr = WIN_FindWndPtr(hwnd); |
| EDITSTATE *es = (EDITSTATE *)EDIT_HEAP_ADDR((HANDLE)(*(wndPtr->wExtra))); |
| |
| es->SelBegLine = es->SelBegCol = 0; |
| es->SelEndLine = es->SelEndCol = 0; |
| |
| InvalidateRect(hwnd, NULL, TRUE); |
| UpdateWindow(hwnd); |
| } |
| |
| |
| /********************************************************************* |
| * EDIT_TextLineNumber |
| * |
| * Return the line number in the text buffer of the supplied |
| * character pointer. |
| */ |
| |
| int EDIT_TextLineNumber(HWND hwnd, char *lp) |
| { |
| int lineno; |
| char *cp; |
| WND *wndPtr = WIN_FindWndPtr(hwnd); |
| EDITSTATE *es = (EDITSTATE *)EDIT_HEAP_ADDR((HANDLE)(*(wndPtr->wExtra))); |
| char *text = EDIT_TextAddr(es, es->hText); |
| unsigned int *textPtrs = (unsigned int *)EDIT_HEAP_ADDR(es->hTextPtrs); |
| |
| for (lineno = 0; lineno < es->wlines; lineno++) |
| { |
| cp = text + *(textPtrs + lineno); |
| if (cp == lp) |
| return lineno; |
| if (cp > lp) |
| break; |
| } |
| return lineno - 1; |
| } |
| |
| |
| /********************************************************************* |
| * EDIT_SetAnchor |
| * |
| * Set down anchor for text marking. |
| */ |
| |
| void EDIT_SetAnchor(HWND hwnd, int row, int col) |
| { |
| BOOL sel = FALSE; |
| WND *wndPtr = WIN_FindWndPtr(hwnd); |
| EDITSTATE *es = (EDITSTATE *)EDIT_HEAP_ADDR((HANDLE)(*(wndPtr->wExtra))); |
| |
| if (SelMarked(es)) |
| sel = TRUE; |
| EDIT_ClearSel(hwnd); |
| es->SelBegLine = es->SelEndLine = row; |
| es->SelBegCol = es->SelEndCol = col; |
| if (sel) |
| { |
| InvalidateRect(hwnd, NULL, FALSE); |
| UpdateWindow(hwnd); |
| } |
| } |
| |
| |
| /********************************************************************* |
| * EDIT_ExtendSel |
| * |
| * Extend selection to the given screen co-ordinates. |
| */ |
| |
| void EDIT_ExtendSel(HWND hwnd, int x, int y) |
| { |
| int bbl, bel, bbc, bec; |
| char *cp; |
| int len; |
| BOOL end = FALSE; |
| WND *wndPtr = WIN_FindWndPtr(hwnd); |
| EDITSTATE *es = (EDITSTATE *)EDIT_HEAP_ADDR((HANDLE)(*(wndPtr->wExtra))); |
| |
| #ifdef DEBUG_EDIT |
| printf("EDIT_ExtendSel: x=%d, y=%d\n", x, y); |
| #endif |
| |
| bbl = es->SelEndLine; |
| bbc = es->SelEndCol; |
| cp = EDIT_TextLine(hwnd, es->wtop + y / es->txtht); |
| len = EDIT_LineLength(hwnd, es->wtop + y / es->txtht); |
| |
| es->WndRow = y / es->txtht; |
| if (es->WndRow > es->wlines - es->wtop - 1) |
| { |
| if (es->wlines) |
| es->WndRow = es->wlines - es->wtop - 1; |
| else |
| es->WndRow = 0; |
| end = TRUE; |
| } |
| es->CurrLine = es->wtop + es->WndRow; |
| es->SelEndLine = es->CurrLine; |
| |
| es->WndCol = x; |
| if (es->WndCol > EDIT_StrLength(es, cp, len, 0) - es->wleft || end) |
| es->WndCol = EDIT_StrLength(es, cp, len, 0) - es->wleft; |
| es->CurrCol = EDIT_PixelToChar(hwnd, es->CurrLine, &(es->WndCol)); |
| es->SelEndCol = es->CurrCol - 1; |
| |
| bel = es->SelEndLine; |
| bec = es->SelEndCol; |
| |
| /* return if no new characters to mark */ |
| if (bbl == bel && bbc == bec) |
| return; |
| |
| /* put lowest marker first */ |
| if (bbl > bel) |
| { |
| swap(&bbl, &bel); |
| swap(&bbc, &bec); |
| } |
| if (bbl == bel && bbc > bec) |
| swap(&bbc, &bec); |
| |
| for (y = bbl; y <= bel; y++) |
| { |
| if (y == bbl && y == bel) |
| EDIT_WriteSel(hwnd, y, bbc, bec); |
| else if (y == bbl) |
| EDIT_WriteSel(hwnd, y, bbc, -1); |
| else if (y == bel) |
| EDIT_WriteSel(hwnd, y, 0, bec); |
| else |
| EDIT_WriteSel(hwnd, y, 0, -1); |
| } |
| } |
| |
| |
| /********************************************************************* |
| * EDIT_WriteSel |
| * |
| * Display selection by reversing pixels in selected text. |
| * If end == -1, selection applies to end of line. |
| */ |
| |
| void EDIT_WriteSel(HWND hwnd, int y, int start, int end) |
| { |
| RECT rc; |
| int scol, ecol; |
| char *cp; |
| HDC hdc; |
| HBRUSH hbrush, holdbrush; |
| int olddm; |
| WND *wndPtr = WIN_FindWndPtr(hwnd); |
| EDITSTATE *es = (EDITSTATE *)EDIT_HEAP_ADDR((HANDLE)(*(wndPtr->wExtra))); |
| |
| #ifdef DEBUG_EDIT |
| printf("EDIT_WriteSel: y=%d start=%d end=%d\n", y, start, end); |
| #endif |
| GetClientRect(hwnd, &rc); |
| |
| /* make sure y is within the window */ |
| if (y < es->wtop || y > (es->wtop + ClientHeight(wndPtr, es))) |
| return; |
| |
| /* get pointer to text */ |
| cp = EDIT_TextLine(hwnd, y); |
| |
| /* get length of line if end == -1 */ |
| if (end == -1) |
| end = EDIT_LineLength(hwnd, y); |
| |
| scol = EDIT_StrLength(es, cp, start, 0); |
| if (scol > rc.right) return; |
| if (scol < rc.left) scol = rc.left; |
| ecol = EDIT_StrLength(es, cp, end, 0); |
| if (ecol < rc.left) return; |
| if (ecol > rc.right) ecol = rc.right; |
| |
| hdc = GetDC(hwnd); |
| hbrush = GetStockObject(BLACK_BRUSH); |
| holdbrush = (HBRUSH)SelectObject(hdc, (HANDLE)hbrush); |
| olddm = SetROP2(hdc, R2_XORPEN); |
| Rectangle(hdc, scol, y * es->txtht, ecol, (y + 1) * es->txtht); |
| SetROP2(hdc, olddm); |
| SelectObject(hdc, (HANDLE)holdbrush); |
| ReleaseDC(hwnd, hdc); |
| } |
| |
| |
| /********************************************************************* |
| * EDIT_StopMarking |
| * |
| * Stop text marking (selection). |
| */ |
| |
| void EDIT_StopMarking(HWND hwnd) |
| { |
| WND *wndPtr = WIN_FindWndPtr(hwnd); |
| EDITSTATE *es = (EDITSTATE *)EDIT_HEAP_ADDR((HANDLE)(*(wndPtr->wExtra))); |
| |
| TextMarking = FALSE; |
| if (es->SelBegLine > es->SelEndLine) |
| { |
| swap(&(es->SelBegLine), &(es->SelEndLine)); |
| swap(&(es->SelBegCol), &(es->SelEndCol)); |
| } |
| if (es->SelBegLine == es->SelEndLine && es->SelBegCol > es->SelEndCol) |
| swap(&(es->SelBegCol), &(es->SelEndCol)); |
| } |
| |
| |
| /********************************************************************* |
| * EM_GETLINE message function |
| */ |
| |
| LONG EDIT_GetLineMsg(HWND hwnd, WORD wParam, LONG lParam) |
| { |
| char *cp, *cp1; |
| int len; |
| char *buffer = (char *)lParam; |
| WND *wndPtr = WIN_FindWndPtr(hwnd); |
| EDITSTATE *es = (EDITSTATE *)EDIT_HEAP_ADDR((HANDLE)(*(wndPtr->wExtra))); |
| |
| cp = EDIT_TextLine(hwnd, wParam); |
| cp1 = EDIT_TextLine(hwnd, wParam + 1); |
| len = min((int)(cp1 - cp), (WORD)(*buffer)); |
| strncpy(buffer, cp, len); |
| |
| return (LONG)len; |
| } |
| |
| |
| /********************************************************************* |
| * EM_GETSEL message function |
| */ |
| |
| LONG EDIT_GetSelMsg(HWND hwnd) |
| { |
| int so, eo; |
| WND *wndPtr = WIN_FindWndPtr(hwnd); |
| EDITSTATE *es = (EDITSTATE *)EDIT_HEAP_ADDR((HANDLE)(*(wndPtr->wExtra))); |
| unsigned int *textPtrs = (unsigned int *)EDIT_HEAP_ADDR(es->hTextPtrs); |
| |
| so = *(textPtrs + es->SelBegLine) + es->SelBegCol; |
| eo = *(textPtrs + es->SelEndLine) + es->SelEndCol; |
| |
| return MAKELONG(so, eo); |
| } |
| |
| |
| /********************************************************************* |
| * EM_REPLACESEL message function |
| */ |
| |
| void EDIT_ReplaceSel(HWND hwnd, LONG lParam) |
| { |
| EDIT_DeleteSel(hwnd); |
| EDIT_InsertText(hwnd, (char *)lParam, strlen((char *)lParam)); |
| InvalidateRect(hwnd, NULL, TRUE); |
| UpdateWindow(hwnd); |
| } |
| |
| |
| /********************************************************************* |
| * EDIT_InsertText |
| * |
| * Insert text at current line and column. |
| */ |
| |
| void EDIT_InsertText(HWND hwnd, char *str, int len) |
| { |
| int plen; |
| WND *wndPtr = WIN_FindWndPtr(hwnd); |
| EDITSTATE *es = (EDITSTATE *)EDIT_HEAP_ADDR((HANDLE)(*(wndPtr->wExtra))); |
| char *text = EDIT_TextAddr(es, es->hText); |
| |
| plen = strlen(text) + len; |
| if (plen + 1 > es->textlen) |
| { |
| es->hText = EDIT_TextReAlloc(es, es->hText, es->textlen + len); |
| es->textlen = plen + 1; |
| } |
| memmove(CurrChar + len, CurrChar, strlen(CurrChar) + 1); |
| memcpy(CurrChar, str, len); |
| |
| EDIT_BuildTextPointers(hwnd); |
| es->PaintBkgd = TRUE; |
| es->TextChanged = TRUE; |
| |
| EDIT_GetLineCol(hwnd, (int)((CurrChar + len) - text), &(es->CurrLine), |
| &(es->CurrCol)); |
| es->WndRow = es->CurrLine - es->wtop; |
| es->WndCol = EDIT_StrLength(es, EDIT_TextLine(hwnd, es->CurrLine), |
| es->CurrCol, 0) - es->wleft; |
| } |
| |
| |
| /********************************************************************* |
| * EM_LINEFROMCHAR message function |
| */ |
| |
| LONG EDIT_LineFromCharMsg(HWND hwnd, WORD wParam) |
| { |
| int row, col; |
| WND *wndPtr = WIN_FindWndPtr(hwnd); |
| EDITSTATE *es = (EDITSTATE *)EDIT_HEAP_ADDR((HANDLE)(*(wndPtr->wExtra))); |
| |
| if (wParam == (WORD)-1) |
| return (LONG)(es->SelBegLine); |
| else |
| EDIT_GetLineCol(hwnd, wParam, &row, &col); |
| |
| return (LONG)row; |
| } |
| |
| |
| /********************************************************************* |
| * EM_LINEINDEX message function |
| */ |
| |
| LONG EDIT_LineIndexMsg(HWND hwnd, WORD wParam) |
| { |
| WND *wndPtr = WIN_FindWndPtr(hwnd); |
| EDITSTATE *es = (EDITSTATE *)EDIT_HEAP_ADDR((HANDLE)(*(wndPtr->wExtra))); |
| unsigned int *textPtrs = (unsigned int *)EDIT_HEAP_ADDR(es->hTextPtrs); |
| |
| if (wParam == (WORD)-1) |
| wParam = es->CurrLine; |
| |
| return (LONG)(*(textPtrs + wParam)); |
| } |
| |
| |
| /********************************************************************* |
| * EM_LINELENGTH message function |
| */ |
| |
| LONG EDIT_LineLengthMsg(HWND hwnd, WORD wParam) |
| { |
| int row, col, len; |
| int sbl, sbc, sel, sec; |
| WND *wndPtr = WIN_FindWndPtr(hwnd); |
| EDITSTATE *es = (EDITSTATE *)EDIT_HEAP_ADDR((HANDLE)(*(wndPtr->wExtra))); |
| unsigned int *textPtrs = (unsigned int *)EDIT_HEAP_ADDR(es->hTextPtrs); |
| |
| if (wParam == (WORD)-1) |
| { |
| if (SelMarked(es)) |
| { |
| sbl = es->SelBegLine; |
| sbc = es->SelBegCol; |
| sel = es->SelEndLine; |
| sec = es->SelEndCol; |
| |
| if (sbl > sel) |
| { |
| swap(&sbl, &sel); |
| swap(&sbc, &sec); |
| } |
| if (sbl == sel && sbc > sec) |
| swap(&sbc, &sec); |
| |
| if (sbc == sel) |
| { |
| len = *(textPtrs + sbl + 1) - *(textPtrs + sbl) - 1; |
| return len - sec - sbc; |
| } |
| |
| len = *(textPtrs + sel + 1) - *(textPtrs + sel) - sec - 1; |
| return len + sbc; |
| } |
| else /* no selection marked */ |
| { |
| len = *(textPtrs + es->CurrLine + 1) - |
| *(textPtrs + es->CurrLine) - 1; |
| return len; |
| } |
| } |
| else /* line number specified */ |
| { |
| EDIT_GetLineCol(hwnd, wParam, &row, &col); |
| len = *(textPtrs + row + 1) - *(textPtrs + row); |
| return len; |
| } |
| } |
| |
| |
| /********************************************************************* |
| * WM_SETFONT message function |
| */ |
| |
| void EDIT_SetFont(HWND hwnd, WORD wParam, LONG lParam) |
| { |
| HDC hdc; |
| TEXTMETRIC tm; |
| HFONT oldfont; |
| WND *wndPtr = WIN_FindWndPtr(hwnd); |
| EDITSTATE *es = (EDITSTATE *)EDIT_HEAP_ADDR((HANDLE)(*(wndPtr->wExtra))); |
| short *charWidths = (short *)EDIT_HEAP_ADDR(es->hCharWidths); |
| |
| es->hFont = wParam; |
| hdc = GetDC(hwnd); |
| oldfont = (HFONT)SelectObject(hdc, (HANDLE)es->hFont); |
| GetCharWidth(hdc, 0, 255, charWidths); |
| GetTextMetrics(hdc, &tm); |
| es->txtht = tm.tmHeight + tm.tmExternalLeading; |
| SelectObject(hdc, (HANDLE)oldfont); |
| ReleaseDC(hwnd, hdc); |
| |
| es->WndRow = (es->CurrLine - es->wtop) / es->txtht; |
| es->WndCol = EDIT_StrLength(es, EDIT_TextLine(hwnd, es->CurrLine), |
| es->CurrCol, 0) - es->wleft; |
| |
| InvalidateRect(hwnd, NULL, TRUE); |
| es->PaintBkgd = TRUE; |
| if (lParam) UpdateWindow(hwnd); |
| } |
| |
| |
| /********************************************************************* |
| * EDIT_SaveDeletedText |
| * |
| * Save deleted text in deleted text buffer. |
| */ |
| |
| void EDIT_SaveDeletedText(HWND hwnd, char *deltext, int len, |
| int line, int col) |
| { |
| char *text; |
| WND *wndPtr = WIN_FindWndPtr(hwnd); |
| EDITSTATE *es = (EDITSTATE *)EDIT_HEAP_ADDR((HANDLE)(*(wndPtr->wExtra))); |
| |
| es->hDeletedText = EDIT_HEAP_REALLOC(es->hDeletedText, len); |
| if (!es->hDeletedText) return; |
| text = (char *)EDIT_HEAP_ADDR(es->hDeletedText); |
| memcpy(text, deltext, len); |
| es->DeletedLength = len; |
| es->DeletedCurrLine = line; |
| es->DeletedCurrCol = col; |
| } |
| |
| |
| /********************************************************************* |
| * EDIT_ClearDeletedText |
| * |
| * Clear deleted text buffer. |
| */ |
| |
| void EDIT_ClearDeletedText(HWND hwnd) |
| { |
| WND *wndPtr = WIN_FindWndPtr(hwnd); |
| EDITSTATE *es = (EDITSTATE *)EDIT_HEAP_ADDR((HANDLE)(*(wndPtr->wExtra))); |
| |
| EDIT_HEAP_FREE(es->hDeletedText); |
| es->hDeletedText = 0; |
| es->DeletedLength = 0; |
| } |
| |
| |
| /********************************************************************* |
| * EM_UNDO message function |
| */ |
| |
| LONG EDIT_UndoMsg(HWND hwnd) |
| { |
| char *text; |
| WND *wndPtr = WIN_FindWndPtr(hwnd); |
| EDITSTATE *es = (EDITSTATE *)EDIT_HEAP_ADDR((HANDLE)(*(wndPtr->wExtra))); |
| |
| if (es->hDeletedText) |
| { |
| text = (char *)EDIT_HEAP_ADDR(es->hDeletedText); |
| es->CurrLine = es->DeletedCurrLine; |
| es->CurrCol = es->DeletedCurrCol; |
| EDIT_InsertText(hwnd, text, es->DeletedLength); |
| EDIT_ClearDeletedText(hwnd); |
| |
| es->SelBegLine = es->CurrLine; |
| es->SelBegCol = es->CurrCol; |
| EDIT_GetLineCol(hwnd, (int)((CurrChar + es->DeletedLength) - text), |
| &(es->CurrLine), &(es->CurrCol)); |
| es->WndRow = es->CurrLine - es->wtop; |
| es->WndCol = EDIT_StrLength(es, EDIT_TextLine(hwnd, es->CurrLine), |
| es->CurrCol, 0) - es->wleft; |
| es->SelEndLine = es->CurrLine; |
| es->SelEndCol = es->CurrCol; |
| |
| InvalidateRect(hwnd, NULL, TRUE); |
| UpdateWindow(hwnd); |
| return 1; |
| } |
| else |
| return 0; |
| } |
| |
| |
| /********************************************************************* |
| * EDIT_TextAlloc |
| * |
| * Allocate the text buffer. |
| */ |
| |
| unsigned int EDIT_TextAlloc(EDITSTATE *es, int bytes) |
| { |
| return ((unsigned int)HEAP_Alloc(es->localheap, GMEM_MOVEABLE, |
| bytes) & 0xffff); |
| } |
| |
| |
| /********************************************************************* |
| * EDIT_TextAddr |
| * |
| * Return the address of the text buffer. |
| */ |
| |
| void *EDIT_TextAddr(EDITSTATE *es, unsigned int handle) |
| { |
| return ((void *)((handle) ? ((handle) | ((unsigned int)(*(es->localheap)) |
| & 0xffff0000)) : 0)); |
| } |
| |
| |
| /********************************************************************* |
| * EDIT_TextReAlloc |
| * |
| * Reallocate the text buffer. |
| */ |
| |
| unsigned int EDIT_TextReAlloc(EDITSTATE *es, unsigned int handle, int bytes) |
| { |
| return ((unsigned int)HEAP_ReAlloc(es->localheap, |
| EDIT_TextAddr(es, handle), |
| bytes, GMEM_MOVEABLE) & 0xffff); |
| } |
| |
| |
| /********************************************************************* |
| * EM_SETHANDLE message function |
| */ |
| |
| void EDIT_SetHandleMsg(HWND hwnd, WORD wParam) |
| { |
| MDESC *m; |
| WND *wndPtr = WIN_FindWndPtr(hwnd); |
| EDITSTATE *es = (EDITSTATE *)EDIT_HEAP_ADDR((HANDLE)(*(wndPtr->wExtra))); |
| |
| if (IsMultiLine()) |
| { |
| es->hText = wParam; |
| es->MaxTextLen = HEAP_LocalSize(es->localheap, es->hText); |
| es->wlines = 0; |
| es->wtop = es->wleft = 0; |
| es->CurrLine = es->CurrCol = 0; |
| es->WndRow = es->WndCol = 0; |
| es->TextChanged = FALSE; |
| es->textwidth = 0; |
| es->SelBegLine = es->SelBegCol = 0; |
| es->SelEndLine = es->SelEndCol = 0; |
| |
| es->PaintBkgd = TRUE; |
| InvalidateRect(hwnd, NULL, TRUE); |
| UpdateWindow(hwnd); |
| } |
| } |
| |
| |
| /********************************************************************* |
| * EM_SETTABSTOPS message function |
| */ |
| |
| LONG EDIT_SetTabStopsMsg(HWND hwnd, WORD wParam, LONG lParam) |
| { |
| unsigned short *tabstops; |
| WND *wndPtr = WIN_FindWndPtr(hwnd); |
| EDITSTATE *es = (EDITSTATE *)EDIT_HEAP_ADDR((HANDLE)(*(wndPtr->wExtra))); |
| |
| es->NumTabStops = wParam; |
| if (wParam == 0) |
| es->hTabStops = EDIT_HEAP_REALLOC(es->hTabStops, 1); |
| else if (wParam == 1) |
| { |
| es->hTabStops = EDIT_HEAP_REALLOC(es->hTabStops, 1); |
| tabstops = (unsigned short *)EDIT_HEAP_ADDR(es->hTabStops); |
| *tabstops = (unsigned short)lParam; |
| } |
| else |
| { |
| es->hTabStops = EDIT_HEAP_REALLOC(es->hTabStops, wParam); |
| tabstops = (unsigned short *)EDIT_HEAP_ADDR(es->hTabStops); |
| memcpy(tabstops, (unsigned short *)lParam, wParam); |
| } |
| return 0L; |
| } |
| |
| |
| /********************************************************************* |
| * Utility functions |
| */ |
| |
| void swap(int *a, int *b) |
| { |
| int x; |
| |
| x = *a; |
| *a = *b; |
| *b = x; |
| } |
| |