/* * Edit control * * Copyright David W. Metcalfe, 1994 * Copyright William Magro, 1995, 1996 * Copyright Frans van Dorsselaer, 1996 * */ /* * UNDER CONSTRUCTION, please read EDIT.TODO */ #include #include #include #include "windows.h" #include "win.h" #include "local.h" #include "stddebug.h" #include "debug.h" #include "xmalloc.h" #include "callback.h" #define BUFLIMIT_MULTI 65534 /* maximum text buffer length (not including '\0') */ #define BUFLIMIT_SINGLE 32766 #define BUFSTART_MULTI 1024 /* starting length for multi-line control */ #define BUFSTART_SINGLE 256 /* starting length for single line control */ #define GROWLENGTH 64 /* buffers grow by this much */ #define HSCROLL_FRACTION 3 /* scroll window by 1/3 width */ typedef enum { END_0 = 0, END_DELIMIT, END_NONE, END_HARD, END_SOFT, } LINE_END; typedef struct { UINT offset; UINT length; LINE_END ending; } LINEDEF; typedef struct { UINT TextWidth; /* width of the widest line in pixels */ HLOCAL16 hBuf; char *text; HFONT hFont; LINEDEF *LineDefs; UINT XOffset; /* offset of the viewport in pixels */ UINT FirstVisibleLine; UINT LineCount; UINT LineHeight; /* height of a screen line in pixels */ UINT AveCharWidth; /* average character width in pixels */ UINT BufLimit; UINT BufSize; BOOL TextChanged; BOOL Redraw; UINT SelStart; /* offset of selection start, == SelEnd if no selection */ UINT SelEnd; /* offset of selection end == current caret position */ UINT NumTabStops; LPINT16 TabStops; EDITWORDBREAKPROC WordBreakProc; char PasswordChar; } EDITSTATE; #define SWAP_UINT(x,y) do { UINT temp = (UINT)(x); (x) = (UINT)(y); (y) = temp; } while(0) #define ORDER_UINT(x,y) do { if ((UINT)(y) < (UINT)(x)) SWAP_UINT((x),(y)); } while(0) /* macros to access window styles */ #define IsMultiLine(wndPtr) ((wndPtr)->dwStyle & ES_MULTILINE) #define IsVScrollBar(wndPtr) ((wndPtr)->dwStyle & WS_VSCROLL) #define IsHScrollBar(wndPtr) ((wndPtr)->dwStyle & WS_HSCROLL) #define IsReadOnly(wndPtr) ((wndPtr)->dwStyle & ES_READONLY) #define IsWordWrap(wndPtr) (((wndPtr)->dwStyle & ES_AUTOHSCROLL) == 0) #define IsPassword(wndPtr) ((wndPtr)->dwStyle & ES_PASSWORD) #define IsLower(wndPtr) ((wndPtr)->dwStyle & ES_LOWERCASE) #define IsUpper(wndPtr) ((wndPtr)->dwStyle & ES_UPPERCASE) #define EDITSTATEPTR(wndPtr) (*(EDITSTATE **)((wndPtr)->wExtra)) #define EDIT_SEND_CTLCOLOR(wndPtr,hdc) \ (SendMessage32A((wndPtr)->parent->hwndSelf, WM_CTLCOLOREDIT, \ (WPARAM)(hdc), (LPARAM)(wndPtr)->hwndSelf )) #define EDIT_NOTIFY_PARENT(wndPtr, wNotifyCode) \ (SendMessage32A((wndPtr)->parent->hwndSelf, WM_COMMAND, \ MAKEWPARAM((wndPtr)->wIDmenu, wNotifyCode), \ (LPARAM)(wndPtr)->hwndSelf )) #define DPRINTF_EDIT_MSG(str) \ dprintf_edit(stddeb, \ "edit: " str ": hwnd=%04x, wParam=%04x, lParam=%08x\n", \ (UINT32)hwnd, (UINT32)wParam, (UINT32)lParam) /********************************************************************* * * Declarations * * Files like these should really be kept in alphabetical order. * */ LRESULT EditWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam); static void EDIT_BuildLineDefs(WND *wndPtr); static INT EDIT_CallWordBreakProc(WND *wndPtr, char *s, INT index, INT count, INT action); static UINT EDIT_ColFromWndX(WND *wndPtr, UINT line, INT x); static void EDIT_DelEnd(WND *wndPtr); static void EDIT_DelLeft(WND *wndPtr); static void EDIT_DelRight(WND *wndPtr); static UINT EDIT_GetAveCharWidth(WND *wndPtr); static UINT EDIT_GetLineHeight(WND *wndPtr); static void EDIT_GetLineRect(WND *wndPtr, UINT line, UINT scol, UINT ecol, LPRECT16 rc); static char * EDIT_GetPointer(WND *wndPtr); static char * EDIT_GetPasswordPointer(WND *wndPtr); static LRESULT EDIT_GetRect(WND *wndPtr, WPARAM wParam, LPARAM lParam); static BOOL EDIT_GetRedraw(WND *wndPtr); static UINT EDIT_GetTextWidth(WND *wndPtr); static UINT EDIT_GetVisibleLineCount(WND *wndPtr); static UINT EDIT_GetWndWidth(WND *wndPtr); static UINT EDIT_GetXOffset(WND *wndPtr); static void EDIT_InvalidateText(WND *wndPtr, UINT start, UINT end); static UINT EDIT_LineFromWndY(WND *wndPtr, INT y); static BOOL EDIT_MakeFit(WND *wndPtr, UINT size); static void EDIT_MoveBackward(WND *wndPtr, BOOL extend); static void EDIT_MoveDownward(WND *wndPtr, BOOL extend); static void EDIT_MoveEnd(WND *wndPtr, BOOL extend); static void EDIT_MoveForward(WND *wndPtr, BOOL extend); static void EDIT_MoveHome(WND *wndPtr, BOOL extend); static void EDIT_MovePageDown(WND *wndPtr, BOOL extend); static void EDIT_MovePageUp(WND *wndPtr, BOOL extend); static void EDIT_MoveUpward(WND *wndPtr, BOOL extend); static void EDIT_MoveWordBackward(WND *wndPtr, BOOL extend); static void EDIT_MoveWordForward(WND *wndPtr, BOOL extend); static void EDIT_PaintLine(WND *wndPtr, HDC hdc, UINT line, BOOL rev); static UINT EDIT_PaintText(WND *wndPtr, HDC hdc, INT x, INT y, UINT line, UINT col, UINT count, BOOL rev); static void EDIT_ReleasePointer(WND *wndPtr); static LRESULT EDIT_ReplaceSel(WND *wndPtr, WPARAM wParam, LPARAM lParam); static void EDIT_ScrollIntoView(WND *wndPtr); static INT EDIT_WndXFromCol(WND *wndPtr, UINT line, UINT col); static INT EDIT_WndYFromLine(WND *wndPtr, UINT line); static INT EDIT_WordBreakProc(char *s, INT index, INT count, INT action); static LRESULT EDIT_EM_CanUndo(WND *wndPtr, WPARAM wParam, LPARAM lParam); static LRESULT EDIT_EM_EmptyUndoBuffer(WND *wndPtr, WPARAM wParam, LPARAM lParam); static LRESULT EDIT_EM_FmtLines(WND *wndPtr, WPARAM wParam, LPARAM lParam); static LRESULT EDIT_EM_GetFirstVisibleLine(WND *wndPtr, WPARAM wParam, LPARAM lParam); static LRESULT EDIT_EM_GetHandle(WND *wndPtr, WPARAM wParam, LPARAM lParam); static LRESULT EDIT_EM_GetLine(WND *wndPtr, WPARAM wParam, LPARAM lParam); static LRESULT EDIT_EM_GetLineCount(WND *wndPtr, WPARAM wParam, LPARAM lParam); static LRESULT EDIT_EM_GetModify(WND *wndPtr, WPARAM wParam, LPARAM lParam); static LRESULT EDIT_EM_GetPasswordChar(WND *wndPtr, WPARAM wParam, LPARAM lParam); static LRESULT EDIT_EM_GetRect(WND *wndPtr, WPARAM wParam, LPARAM lParam); static LRESULT EDIT_EM_GetSel(WND *wndPtr, WPARAM wParam, LPARAM lParam); static LRESULT EDIT_EM_GetThumb(WND *wndPtr, WPARAM wParam, LPARAM lParam); static LRESULT EDIT_EM_GetWordBreakProc(WND *wndPtr, WPARAM wParam, LPARAM lParam); static LRESULT EDIT_EM_LimitText(WND *wndPtr, WPARAM wParam, LPARAM lParam); static LRESULT EDIT_EM_LineFromChar(WND *wndPtr, WPARAM wParam, LPARAM lParam); static LRESULT EDIT_EM_LineIndex(WND *wndPtr, WPARAM wParam, LPARAM lParam); static LRESULT EDIT_EM_LineLength(WND *wndPtr, WPARAM wParam, LPARAM lParam); static LRESULT EDIT_EM_LineScroll(WND *wndPtr, WPARAM wParam, LPARAM lParam); static LRESULT EDIT_EM_ReplaceSel(WND *wndPtr, WPARAM wParam, LPARAM lParam); static LRESULT EDIT_EM_Scroll(WND *wndPtr, WPARAM wParam, LPARAM lParam); static LRESULT EDIT_EM_SetHandle(WND *wndPtr, WPARAM wParam, LPARAM lParam); static LRESULT EDIT_EM_SetModify(WND *wndPtr, WPARAM wParam, LPARAM lParam); static LRESULT EDIT_EM_SetPasswordChar(WND *wndPtr, WPARAM wParam, LPARAM lParam); static LRESULT EDIT_EM_SetReadOnly(WND *wndPtr, WPARAM wParam, LPARAM lParam); static LRESULT EDIT_EM_SetRect(WND *wndPtr, WPARAM wParam, LPARAM lParam); static LRESULT EDIT_EM_SetRectNP(WND *wndPtr, WPARAM wParam, LPARAM lParam); static LRESULT EDIT_EM_SetSel(WND *wndPtr, WPARAM wParam, LPARAM lParam); static LRESULT EDIT_EM_SetTabStops(WND *wndPtr, WPARAM wParam, LPARAM lParam); static LRESULT EDIT_EM_SetWordBreakProc(WND *wndPtr, WPARAM wParam, LPARAM lParam); static LRESULT EDIT_EM_Undo(WND *wndPtr, WPARAM wParam, LPARAM lParam); static LRESULT EDIT_WM_Char(WND *wndPtr, WPARAM wParam, LPARAM lParam); static LRESULT EDIT_WM_Clear(WND *wndPtr, WPARAM wParam, LPARAM lParam); static LRESULT EDIT_WM_Copy(WND *wndPtr, WPARAM wParam, LPARAM lParam); static LRESULT EDIT_WM_Cut(WND *wndPtr, WPARAM wParam, LPARAM lParam); static LRESULT EDIT_WM_Create(WND *wndPtr, WPARAM wParam, LPARAM lParam); static LRESULT EDIT_WM_Destroy(WND *wndPtr, WPARAM wParam, LPARAM lParam); static LRESULT EDIT_WM_Enable(WND *wndPtr, WPARAM wParam, LPARAM lParam); static LRESULT EDIT_WM_EraseBkGnd(WND *wndPtr, WPARAM wParam, LPARAM lParam); static LRESULT EDIT_WM_GetDlgCode(WND *wndPtr, WPARAM wParam, LPARAM lParam); static LRESULT EDIT_WM_GetFont(WND *wndPtr, WPARAM wParam, LPARAM lParam); static LRESULT EDIT_WM_GetText(WND *wndPtr, WPARAM wParam, LPARAM lParam); static LRESULT EDIT_WM_GetTextLength(WND *wndPtr, WPARAM wParam, LPARAM lParam); static LRESULT EDIT_WM_HScroll(WND *wndPtr, WPARAM wParam, LPARAM lParam); static LRESULT EDIT_WM_KeyDown(WND *wndPtr, WPARAM wParam, LPARAM lParam); static LRESULT EDIT_WM_KillFocus(WND *wndPtr, WPARAM wParam, LPARAM lParam); static LRESULT EDIT_WM_LButtonDblClk(WND *wndPtr, WPARAM wParam, LPARAM lParam); static LRESULT EDIT_WM_LButtonDown(WND *wndPtr, WPARAM wParam, LPARAM lParam); static LRESULT EDIT_WM_LButtonUp(WND *wndPtr, WPARAM wParam, LPARAM lParam); static LRESULT EDIT_WM_MouseMove(WND *wndPtr, WPARAM wParam, LPARAM lParam); static LRESULT EDIT_WM_Paint(WND *wndPtr, WPARAM wParam, LPARAM lParam); static LRESULT EDIT_WM_Paste(WND *wndPtr, WPARAM wParam, LPARAM lParam); static LRESULT EDIT_WM_SetCursor(WND *wndPtr, WPARAM wParam, LPARAM lParam); static LRESULT EDIT_WM_SetFocus(WND *wndPtr, WPARAM wParam, LPARAM lParam); static LRESULT EDIT_WM_SetFont(WND *wndPtr, WPARAM wParam, LPARAM lParam); static LRESULT EDIT_WM_SetRedraw(WND *wndPtr, WPARAM wParam, LPARAM lParam); static LRESULT EDIT_WM_SetText(WND *wndPtr, WPARAM wParam, LPARAM lParam); static LRESULT EDIT_WM_Size(WND *wndPtr, WPARAM wParam, LPARAM lParam); static LRESULT EDIT_WM_VScroll(WND *wndPtr, WPARAM wParam, LPARAM lParam); /********************************************************************* * * General shortcuts for variable names: * * UINT l; line * UINT c; column * UINT s; offset of selection start * UINT e; offset of selection end * UINT sl; line on which the selection starts * UINT el; line on which the selection ends * UINT sc; column on which the selection starts * UINT ec; column on which the selection ends * UINT li; line index (offset) * UINT fv; first visible line * UINT vlc; vissible line count * UINT lc; line count * UINT lh; line height (in pixels) * UINT tw; text width (in pixels) * UINT ww; window width (in pixels) * UINT cw; character width (average, in pixels) * */ /********************************************************************* * * EditWndProc() * */ LRESULT EditWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { LRESULT lResult = 0L; WND *wndPtr = WIN_FindWndPtr(hwnd); switch (msg) { case EM_CANUNDO: DPRINTF_EDIT_MSG("EM_CANUNDO"); lResult = EDIT_EM_CanUndo(wndPtr, wParam, lParam); break; case EM_EMPTYUNDOBUFFER: DPRINTF_EDIT_MSG("EM_EMPTYUNDOBUFFER"); lResult = EDIT_EM_EmptyUndoBuffer(wndPtr, wParam, lParam); break; case EM_FMTLINES: DPRINTF_EDIT_MSG("EM_FMTLINES"); lResult = EDIT_EM_FmtLines(wndPtr, wParam, lParam); break; case EM_GETFIRSTVISIBLELINE: DPRINTF_EDIT_MSG("EM_GETFIRSTVISIBLELINE"); lResult = EDIT_EM_GetFirstVisibleLine(wndPtr, wParam, lParam); break; case EM_GETHANDLE: DPRINTF_EDIT_MSG("EM_GETHANDLE"); lResult = EDIT_EM_GetHandle(wndPtr, wParam, lParam); break; case EM_GETLINE: DPRINTF_EDIT_MSG("EM_GETLINE"); lResult = EDIT_EM_GetLine(wndPtr, wParam, lParam); break; case EM_GETLINECOUNT: DPRINTF_EDIT_MSG("EM_GETLINECOUNT"); lResult = EDIT_EM_GetLineCount(wndPtr, wParam, lParam); break; case EM_GETMODIFY: DPRINTF_EDIT_MSG("EM_GETMODIFY"); lResult = EDIT_EM_GetModify(wndPtr, wParam, lParam); break; case EM_GETPASSWORDCHAR: DPRINTF_EDIT_MSG("EM_GETPASSWORDCHAR"); lResult = EDIT_EM_GetPasswordChar(wndPtr, wParam, lParam); break; case EM_GETRECT: DPRINTF_EDIT_MSG("EM_GETRECT"); lResult = EDIT_EM_GetRect(wndPtr, wParam, lParam); break; case EM_GETSEL: DPRINTF_EDIT_MSG("EM_GETSEL"); lResult = EDIT_EM_GetSel(wndPtr, wParam, lParam); break; case EM_GETTHUMB: DPRINTF_EDIT_MSG("EM_GETTHUMB"); lResult = EDIT_EM_GetThumb(wndPtr, wParam, lParam); break; case EM_GETWORDBREAKPROC: DPRINTF_EDIT_MSG("EM_GETWORDBREAKPROC"); lResult = EDIT_EM_GetWordBreakProc(wndPtr, wParam, lParam); break; case EM_LIMITTEXT: DPRINTF_EDIT_MSG("EM_LIMITTEXT"); lResult = EDIT_EM_LimitText(wndPtr, wParam, lParam); break; case EM_LINEFROMCHAR: DPRINTF_EDIT_MSG("EM_LINEFROMCHAR"); lResult = EDIT_EM_LineFromChar(wndPtr, wParam, lParam); break; case EM_LINEINDEX: DPRINTF_EDIT_MSG("EM_LINEINDEX"); lResult = EDIT_EM_LineIndex(wndPtr, wParam, lParam); break; case EM_LINELENGTH: DPRINTF_EDIT_MSG("EM_LINELENGTH"); lResult = EDIT_EM_LineLength(wndPtr, wParam, lParam); break; case EM_LINESCROLL: DPRINTF_EDIT_MSG("EM_LINESCROLL"); lResult = EDIT_EM_LineScroll(wndPtr, wParam, lParam); break; case EM_REPLACESEL: DPRINTF_EDIT_MSG("EM_REPLACESEL"); lResult = EDIT_EM_ReplaceSel(wndPtr, wParam, lParam); break; case EM_SCROLL: DPRINTF_EDIT_MSG("EM_SCROLL"); lResult = EDIT_EM_Scroll(wndPtr, wParam, lParam); break; case EM_SETHANDLE: DPRINTF_EDIT_MSG("EM_SETHANDLE"); lResult = EDIT_EM_SetHandle(wndPtr, wParam, lParam); break; case EM_SETMODIFY: DPRINTF_EDIT_MSG("EM_SETMODIFY"); lResult = EDIT_EM_SetModify(wndPtr, wParam, lParam); break; case EM_SETPASSWORDCHAR: DPRINTF_EDIT_MSG("EM_SETPASSWORDCHAR"); lResult = EDIT_EM_SetPasswordChar(wndPtr, wParam, lParam); break; case EM_SETREADONLY: DPRINTF_EDIT_MSG("EM_SETREADONLY"); lResult = EDIT_EM_SetReadOnly(wndPtr, wParam, lParam); break; case EM_SETRECT: DPRINTF_EDIT_MSG("EM_SETRECT"); lResult = EDIT_EM_SetRect(wndPtr, wParam, lParam); break; case EM_SETRECTNP: DPRINTF_EDIT_MSG("EM_SETRECTNP"); lResult = EDIT_EM_SetRectNP(wndPtr, wParam, lParam); break; case EM_SETSEL: DPRINTF_EDIT_MSG("EM_SETSEL"); lResult = EDIT_EM_SetSel(wndPtr, wParam, lParam); break; case EM_SETTABSTOPS: DPRINTF_EDIT_MSG("EM_SETTABSTOPS"); lResult = EDIT_EM_SetTabStops(wndPtr, wParam, lParam); break; case EM_SETWORDBREAKPROC: DPRINTF_EDIT_MSG("EM_SETWORDBREAKPROC"); lResult = EDIT_EM_SetWordBreakProc(wndPtr, wParam, lParam); break; case EM_UNDO: case WM_UNDO: DPRINTF_EDIT_MSG("EM_UNDO / WM_UNDO"); lResult = EDIT_EM_Undo(wndPtr, wParam, lParam); break; case WM_GETDLGCODE: DPRINTF_EDIT_MSG("WM_GETDLGCODE"); lResult = EDIT_WM_GetDlgCode(wndPtr, wParam, lParam); break; case WM_CHAR: DPRINTF_EDIT_MSG("WM_CHAR"); lResult = EDIT_WM_Char(wndPtr, wParam, lParam); break; case WM_CLEAR: DPRINTF_EDIT_MSG("WM_CLEAR"); lResult = EDIT_WM_Clear(wndPtr, wParam, lParam); break; case WM_COPY: DPRINTF_EDIT_MSG("WM_COPY"); lResult = EDIT_WM_Copy(wndPtr, wParam, lParam); break; case WM_CREATE: DPRINTF_EDIT_MSG("WM_CREATE"); lResult = EDIT_WM_Create(wndPtr, wParam, lParam); break; case WM_CUT: DPRINTF_EDIT_MSG("WM_CUT"); lResult = EDIT_WM_Cut(wndPtr, wParam, lParam); break; case WM_DESTROY: DPRINTF_EDIT_MSG("WM_DESTROY"); lResult = EDIT_WM_Destroy(wndPtr, wParam, lParam); break; case WM_ENABLE: DPRINTF_EDIT_MSG("WM_ENABLE"); lResult = EDIT_WM_Enable(wndPtr, wParam, lParam); break; case WM_ERASEBKGND: DPRINTF_EDIT_MSG("WM_ERASEBKGND"); lResult = EDIT_WM_EraseBkGnd(wndPtr, wParam, lParam); break; case WM_GETFONT: DPRINTF_EDIT_MSG("WM_GETFONT"); lResult = EDIT_WM_GetFont(wndPtr, wParam, lParam); break; case WM_GETTEXT: DPRINTF_EDIT_MSG("WM_GETTEXT"); lResult = EDIT_WM_GetText(wndPtr, wParam, lParam); break; case WM_GETTEXTLENGTH: DPRINTF_EDIT_MSG("WM_GETTEXTLENGTH"); lResult = EDIT_WM_GetTextLength(wndPtr, wParam, lParam); break; case WM_HSCROLL: DPRINTF_EDIT_MSG("WM_HSCROLL"); lResult = EDIT_WM_HScroll(wndPtr, wParam, lParam); break; case WM_KEYDOWN: DPRINTF_EDIT_MSG("WM_KEYDOWN"); lResult = EDIT_WM_KeyDown(wndPtr, wParam, lParam); break; case WM_KILLFOCUS: DPRINTF_EDIT_MSG("WM_KILLFOCUS"); lResult = EDIT_WM_KillFocus(wndPtr, wParam, lParam); break; case WM_LBUTTONDBLCLK: DPRINTF_EDIT_MSG("WM_LBUTTONDBLCLK"); lResult = EDIT_WM_LButtonDblClk(wndPtr, wParam, lParam); break; case WM_LBUTTONDOWN: DPRINTF_EDIT_MSG("WM_LBUTTONDOWN"); lResult = EDIT_WM_LButtonDown(wndPtr, wParam, lParam); break; case WM_LBUTTONUP: DPRINTF_EDIT_MSG("WM_LBUTTONUP"); lResult = EDIT_WM_LButtonUp(wndPtr, wParam, lParam); break; case WM_MOUSEMOVE: /* * DPRINTF_EDIT_MSG("WM_MOUSEMOVE"); */ lResult = EDIT_WM_MouseMove(wndPtr, wParam, lParam); break; case WM_PAINT: DPRINTF_EDIT_MSG("WM_PAINT"); lResult = EDIT_WM_Paint(wndPtr, wParam, lParam); break; case WM_PASTE: DPRINTF_EDIT_MSG("WM_PASTE"); lResult = EDIT_WM_Paste(wndPtr, wParam, lParam); break; case WM_SETCURSOR: /* * DPRINTF_EDIT_MSG("WM_SETCURSOR"); */ lResult = EDIT_WM_SetCursor(wndPtr, wParam, lParam); break; case WM_SETFOCUS: DPRINTF_EDIT_MSG("WM_SETFOCUS"); lResult = EDIT_WM_SetFocus(wndPtr, wParam, lParam); break; case WM_SETFONT: DPRINTF_EDIT_MSG("WM_SETFONT"); lResult = EDIT_WM_SetFont(wndPtr, wParam, lParam); break; case WM_SETREDRAW: DPRINTF_EDIT_MSG("WM_SETREDRAW"); lResult = EDIT_WM_SetRedraw(wndPtr, wParam, lParam); break; case WM_SETTEXT: DPRINTF_EDIT_MSG("WM_SETTEXT"); lResult = EDIT_WM_SetText(wndPtr, wParam, lParam); break; case WM_SIZE: DPRINTF_EDIT_MSG("WM_SIZE"); lResult = EDIT_WM_Size(wndPtr, wParam, lParam); break; case WM_VSCROLL: DPRINTF_EDIT_MSG("WM_VSCROLL"); lResult = EDIT_WM_VScroll(wndPtr, wParam, lParam); break; default: if (msg >= WM_USER) fprintf(stdnimp, "edit: undocumented message %d >= WM_USER, please report.\n", msg); lResult = DefWindowProc16(hwnd, msg, wParam, lParam); break; } EDIT_ReleasePointer(wndPtr); return lResult; } /********************************************************************* * * EDIT_BuildLineDefs * * Build array of pointers to text lines. * Lines can end with '\0' (last line), nothing (if it is too long), * a delimiter (usually ' '), a soft return '\r\r\n' or a hard return '\r\n' * */ static void EDIT_BuildLineDefs(WND *wndPtr) { EDITSTATE *es = EDITSTATEPTR(wndPtr); char *text = EDIT_GetPasswordPointer(wndPtr); int ww = EDIT_GetWndWidth(wndPtr); HDC32 hdc; HFONT hFont; HFONT oldFont = 0; char *start, *cp; int prev, next; int width; int length; LINE_END ending; hdc = GetDC32(wndPtr->hwndSelf); hFont = (HFONT)EDIT_WM_GetFont(wndPtr, 0, 0L); if (hFont) oldFont = SelectObject(hdc, hFont); if (!IsMultiLine(wndPtr)) { es->LineCount = 1; es->LineDefs = xrealloc(es->LineDefs, sizeof(LINEDEF)); es->LineDefs[0].offset = 0; es->LineDefs[0].length = EDIT_WM_GetTextLength(wndPtr, 0, 0L); es->LineDefs[0].ending = END_0; es->TextWidth = LOWORD(GetTabbedTextExtent(hdc, text, es->LineDefs[0].length, es->NumTabStops, es->TabStops)); } else { es->LineCount = 0; start = text; do { if (!(cp = strstr(start, "\r\n"))) { ending = END_0; length = strlen(start); } else if ((cp > start) && (*(cp - 1) == '\r')) { ending = END_SOFT; length = cp - start - 1; } else { ending = END_HARD; length = cp - start; } width = LOWORD(GetTabbedTextExtent(hdc, start, length, es->NumTabStops, es->TabStops)); if (IsWordWrap(wndPtr) && (width > ww)) { next = 0; do { prev = next; next = EDIT_CallWordBreakProc(wndPtr, start, prev + 1, length, WB_RIGHT); width = LOWORD(GetTabbedTextExtent(hdc, start, next, es->NumTabStops, es->TabStops)); } while (width <= ww); if (!prev) { next = 0; do { prev = next; next++; width = LOWORD(GetTabbedTextExtent(hdc, start, next, es->NumTabStops, es->TabStops)); } while (width <= ww); if(!prev) prev = 1; } length = prev; if (EDIT_CallWordBreakProc(wndPtr, start, length - 1, length, WB_ISDELIMITER)) { length--; ending = END_DELIMIT; } else ending = END_NONE; width = LOWORD(GetTabbedTextExtent(hdc, start, length, es->NumTabStops, es->TabStops)); } es->LineDefs = xrealloc(es->LineDefs, (es->LineCount + 1) * sizeof(LINEDEF)); es->LineDefs[es->LineCount].offset = start - text; es->LineDefs[es->LineCount].length = length; es->LineDefs[es->LineCount].ending = ending; es->LineCount++; es->TextWidth = MAX(es->TextWidth, width); start += length; switch (ending) { case END_SOFT: start += 3; break; case END_HARD: start += 2; break; case END_DELIMIT: start++; break; default: break; } } while (*start || (ending == END_SOFT) || (ending == END_HARD)); } if (hFont) SelectObject(hdc, oldFont); ReleaseDC32(wndPtr->hwndSelf, hdc); free(text); } /********************************************************************* * * EDIT_CallWordBreakProc * * Call appropriate WordBreakProc (internal or external). * */ static INT EDIT_CallWordBreakProc(WND *wndPtr, char *s, INT index, INT count, INT action) { EDITWORDBREAKPROC wbp = (EDITWORDBREAKPROC)EDIT_EM_GetWordBreakProc(wndPtr, 0, 0L); if (!wbp) return EDIT_WordBreakProc(s, index, count, action); else { /* We need a SEGPTR here */ EDITSTATE *es = EDITSTATEPTR(wndPtr); SEGPTR ptr = LOCAL_LockSegptr( wndPtr->hInstance, es->hBuf ) + (UINT16)(s - EDIT_GetPointer(wndPtr)); INT ret = CallWordBreakProc( (FARPROC16)wbp, ptr, index, count, action); LOCAL_Unlock( wndPtr->hInstance, es->hBuf ); return ret; } } /********************************************************************* * * EDIT_ColFromWndX * * Calculates, for a given line and X-coordinate on the screen, the column. * */ static UINT EDIT_ColFromWndX(WND *wndPtr, UINT line, INT x) { UINT lc = (UINT)EDIT_EM_GetLineCount(wndPtr, 0, 0L); UINT li = (UINT)EDIT_EM_LineIndex(wndPtr, line, 0L); UINT ll = (UINT)EDIT_EM_LineLength(wndPtr, li, 0L); UINT i; line = MAX(0, MIN(line, lc - 1)); for (i = 0 ; i < ll ; i++) if (EDIT_WndXFromCol(wndPtr, line, i) >= x) break; return i; } /********************************************************************* * * EDIT_DelEnd * * Delete all characters on this line to right of cursor. * */ static void EDIT_DelEnd(WND *wndPtr) { EDIT_EM_SetSel(wndPtr, 1, MAKELPARAM(-1, 0)); EDIT_MoveEnd(wndPtr, TRUE); EDIT_WM_Clear(wndPtr, 0, 0L); } /********************************************************************* * * EDIT_DelLeft * * Delete character to left of cursor. * */ static void EDIT_DelLeft(WND *wndPtr) { EDIT_EM_SetSel(wndPtr, 1, MAKELPARAM(-1, 0)); EDIT_MoveBackward(wndPtr, TRUE); EDIT_WM_Clear(wndPtr, 0, 0L); } /********************************************************************* * * EDIT_DelRight * * Delete character to right of cursor. * */ static void EDIT_DelRight(WND *wndPtr) { EDIT_EM_SetSel(wndPtr, 1, MAKELPARAM(-1, 0)); EDIT_MoveForward(wndPtr, TRUE); EDIT_WM_Clear(wndPtr, 0, 0L); } /********************************************************************* * * EDIT_GetAveCharWidth * */ static UINT EDIT_GetAveCharWidth(WND *wndPtr) { EDITSTATE *es = EDITSTATEPTR(wndPtr); return es->AveCharWidth; } /********************************************************************* * * EDIT_GetLineHeight * */ static UINT EDIT_GetLineHeight(WND *wndPtr) { EDITSTATE *es = EDITSTATEPTR(wndPtr); return es->LineHeight; } /********************************************************************* * * EDIT_GetLineRect * * Calculates the bounding rectangle for a line from a starting * column to an ending column. * */ static void EDIT_GetLineRect(WND *wndPtr, UINT line, UINT scol, UINT ecol, LPRECT16 rc) { rc->top = EDIT_WndYFromLine(wndPtr, line); rc->bottom = rc->top + EDIT_GetLineHeight(wndPtr); rc->left = EDIT_WndXFromCol(wndPtr, line, scol); rc->right = ((INT)ecol == -1) ? EDIT_GetWndWidth(wndPtr) : EDIT_WndXFromCol(wndPtr, line, ecol); } /********************************************************************* * * EDIT_GetPointer * * This acts as a LOCAL_Lock(), but it locks only once. This way * you can call it whenever you like, without unlocking. * */ static char *EDIT_GetPointer(WND *wndPtr) { EDITSTATE *es = EDITSTATEPTR(wndPtr); if (!es->text && es->hBuf) es->text = LOCAL_Lock(wndPtr->hInstance, es->hBuf); return es->text; } /********************************************************************* * * EDIT_GetPasswordPointer * * */ static char *EDIT_GetPasswordPointer(WND *wndPtr) { EDITSTATE *es = EDITSTATEPTR(wndPtr); char *text = xstrdup(EDIT_GetPointer(wndPtr)); char *p; if(es->PasswordChar) { p = text; while(*p != '\0') { if(*p != '\r' && *p != '\n') *p = es->PasswordChar; p++; } } return text; } /********************************************************************* * * EDIT_GetRect * * Beware: This is not the function called on EM_GETRECT. * It expects a (LPRECT) in lParam, not a (SEGPTR). * It is used internally, as if there were no pointer difficulties. * */ static LRESULT EDIT_GetRect(WND *wndPtr, WPARAM wParam, LPARAM lParam) { GetClientRect16( wndPtr->hwndSelf, (LPRECT16)lParam ); return 0L; } /********************************************************************* * * EDIT_GetRedraw * */ static BOOL EDIT_GetRedraw(WND *wndPtr) { EDITSTATE *es = EDITSTATEPTR(wndPtr); return es->Redraw; } /********************************************************************* * * EDIT_GetTextWidth * */ static UINT EDIT_GetTextWidth(WND *wndPtr) { EDITSTATE *es = EDITSTATEPTR(wndPtr); return es->TextWidth; } /********************************************************************* * * EDIT_GetVisibleLineCount * */ static UINT EDIT_GetVisibleLineCount(WND *wndPtr) { RECT16 rc; EDIT_GetRect(wndPtr, 0, (LPARAM)&rc); return MAX(1, MAX(rc.bottom - rc.top, 0) / EDIT_GetLineHeight(wndPtr)); } /********************************************************************* * * EDIT_GetWndWidth * */ static UINT EDIT_GetWndWidth(WND *wndPtr) { RECT16 rc; EDIT_GetRect(wndPtr, 0, (LPARAM)&rc); return rc.right - rc.left; } /********************************************************************* * * EDIT_GetXOffset * */ static UINT EDIT_GetXOffset(WND *wndPtr) { EDITSTATE *es = EDITSTATEPTR(wndPtr); return es->XOffset; } /********************************************************************* * * EDIT_InvalidateText * * Invalidate the text from offset start upto, but not including, * offset end. Useful for (re)painting the selection. * Regions outside the linewidth are not invalidated. * end == -1 means end == TextLength. * start and end need not be ordered. * */ static void EDIT_InvalidateText(WND *wndPtr, UINT start, UINT end) { UINT fv = (UINT)EDIT_EM_GetFirstVisibleLine(wndPtr, 0, 0L); UINT vlc = EDIT_GetVisibleLineCount(wndPtr); UINT sl; UINT el; UINT sc; UINT ec; RECT16 rcWnd; RECT16 rcLine; RECT16 rcUpdate; UINT l; if (end == start ) return; if ((INT)end == -1) end = (UINT)EDIT_WM_GetTextLength(wndPtr, 0, 0L); ORDER_UINT(start, end); sl = (UINT)EDIT_EM_LineFromChar(wndPtr, start, 0L); el = (UINT)EDIT_EM_LineFromChar(wndPtr, end, 0L); if ((el < fv) || (sl > fv + vlc)) return; sc = start - (UINT)EDIT_EM_LineIndex(wndPtr, sl, 0L); ec = end - (UINT)EDIT_EM_LineIndex(wndPtr, el, 0L); if (sl < fv) { sl = fv; sc = 0; } if (el > fv + vlc) { el = fv + vlc; ec = (UINT)EDIT_EM_LineLength(wndPtr, (UINT)EDIT_EM_LineIndex(wndPtr, el, 0L), 0L); } EDIT_GetRect(wndPtr, 0, (LPARAM)&rcWnd); if (sl == el) { EDIT_GetLineRect(wndPtr, sl, sc, ec, &rcLine); if (IntersectRect16(&rcUpdate, &rcWnd, &rcLine)) InvalidateRect16( wndPtr->hwndSelf, &rcUpdate, FALSE ); } else { EDIT_GetLineRect(wndPtr, sl, sc, (UINT)EDIT_EM_LineLength(wndPtr, (UINT)EDIT_EM_LineIndex(wndPtr, sl, 0L), 0L), &rcLine); if (IntersectRect16(&rcUpdate, &rcWnd, &rcLine)) InvalidateRect16( wndPtr->hwndSelf, &rcUpdate, FALSE ); for (l = sl + 1 ; l < el ; l++) { EDIT_GetLineRect(wndPtr, l, 0, (UINT)EDIT_EM_LineLength(wndPtr, (UINT)EDIT_EM_LineIndex(wndPtr, l, 0L), 0L), &rcLine); if (IntersectRect16(&rcUpdate, &rcWnd, &rcLine)) InvalidateRect16(wndPtr->hwndSelf, &rcUpdate, FALSE); } EDIT_GetLineRect(wndPtr, el, 0, ec, &rcLine); if (IntersectRect16(&rcUpdate, &rcWnd, &rcLine)) InvalidateRect16( wndPtr->hwndSelf, &rcUpdate, FALSE ); } } /********************************************************************* * * EDIT_LineFromWndY * * Calculates, for a given Y-coordinate on the screen, the line. * */ static UINT EDIT_LineFromWndY(WND *wndPtr, INT y) { UINT fv = (UINT)EDIT_EM_GetFirstVisibleLine(wndPtr, 0, 0L); UINT lh = EDIT_GetLineHeight(wndPtr); UINT lc = (UINT)EDIT_EM_GetLineCount(wndPtr, 0, 0L); return MAX(0, MIN(lc - 1, y / lh + fv)); } /********************************************************************* * * EDIT_MakeFit * * Try to fit size + 1 bytes in the buffer. Constrain to limits. * */ static BOOL EDIT_MakeFit(WND *wndPtr, UINT size) { EDITSTATE *es = EDITSTATEPTR(wndPtr); if (size <= es->BufSize) return TRUE; if (size > es->BufLimit) return FALSE; size = ((size / GROWLENGTH) + 1) * GROWLENGTH; if (size > es->BufLimit) size = es->BufLimit; dprintf_edit(stddeb, "edit: EDIT_MakeFit: trying to ReAlloc to %d+1\n", size); if (LOCAL_ReAlloc(wndPtr->hInstance, es->hBuf, size + 1, LMEM_MOVEABLE)) { es->BufSize = MIN(LOCAL_Size(wndPtr->hInstance, es->hBuf) - 1, es->BufLimit); return TRUE; } else return FALSE; } /********************************************************************* * * EDIT_MoveBackward * */ static void EDIT_MoveBackward(WND *wndPtr, BOOL extend) { UINT s = LOWORD(EDIT_EM_GetSel(wndPtr, 0, 0L)); UINT e = HIWORD(EDIT_EM_GetSel(wndPtr, 0, 0L)); UINT l = (UINT)EDIT_EM_LineFromChar(wndPtr, e, 0L); UINT li = (UINT)EDIT_EM_LineIndex(wndPtr, l, 0L); if (e - li == 0) { if (l) { li = (UINT)EDIT_EM_LineIndex(wndPtr, l - 1, 0L); e = li + (UINT)EDIT_EM_LineLength(wndPtr, li, 0L); } } else e--; if (!extend) s = e; EDIT_EM_SetSel(wndPtr, 0, MAKELPARAM(s, e)); } /********************************************************************* * * EDIT_MoveDownward * */ static void EDIT_MoveDownward(WND *wndPtr, BOOL extend) { UINT s = LOWORD(EDIT_EM_GetSel(wndPtr, 0, 0L)); UINT e = HIWORD(EDIT_EM_GetSel(wndPtr, 0, 0L)); UINT l = (UINT)EDIT_EM_LineFromChar(wndPtr, e, 0L); UINT lc = (UINT)EDIT_EM_GetLineCount(wndPtr, e, 0L); UINT li = (UINT)EDIT_EM_LineIndex(wndPtr, l, 0L); INT x; if (l < lc - 1) { x = EDIT_WndXFromCol(wndPtr, l, e - li); l++; e = (UINT)EDIT_EM_LineIndex(wndPtr, l, 0L) + EDIT_ColFromWndX(wndPtr, l, x); } if (!extend) s = e; EDIT_EM_SetSel(wndPtr, 0, MAKELPARAM(s, e)); } /********************************************************************* * * EDIT_MoveEnd * */ static void EDIT_MoveEnd(WND *wndPtr, BOOL extend) { UINT s = LOWORD(EDIT_EM_GetSel(wndPtr, 0, 0L)); UINT e = HIWORD(EDIT_EM_GetSel(wndPtr, 0, 0L)); UINT l = (UINT)EDIT_EM_LineFromChar(wndPtr, e, 0L); UINT ll = (UINT)EDIT_EM_LineLength(wndPtr, e, 0L); UINT li = (UINT)EDIT_EM_LineIndex(wndPtr, l, 0L); e = li + ll; if (!extend) s = e; EDIT_EM_SetSel(wndPtr, 0, MAKELPARAM(s, e)); } /********************************************************************* * * EDIT_MoveForward * */ static void EDIT_MoveForward(WND *wndPtr, BOOL extend) { UINT s = LOWORD(EDIT_EM_GetSel(wndPtr, 0, 0L)); UINT e = HIWORD(EDIT_EM_GetSel(wndPtr, 0, 0L)); UINT l = (UINT)EDIT_EM_LineFromChar(wndPtr, e, 0L); UINT lc = (UINT)EDIT_EM_GetLineCount(wndPtr, e, 0L); UINT ll = (UINT)EDIT_EM_LineLength(wndPtr, e, 0L); UINT li = (UINT)EDIT_EM_LineIndex(wndPtr, l, 0L); if (e - li == ll) { if (l != lc - 1) e = (UINT)EDIT_EM_LineIndex(wndPtr, l + 1, 0L); } else e++; if (!extend) s = e; EDIT_EM_SetSel(wndPtr, 0, MAKELPARAM(s, e)); } /********************************************************************* * * EDIT_MoveHome * * Home key: move to beginning of line. * */ static void EDIT_MoveHome(WND *wndPtr, BOOL extend) { UINT s = LOWORD(EDIT_EM_GetSel(wndPtr, 0, 0L)); UINT e = HIWORD(EDIT_EM_GetSel(wndPtr, 0, 0L)); UINT l = (UINT)EDIT_EM_LineFromChar(wndPtr, e, 0L); UINT li = (UINT)EDIT_EM_LineIndex(wndPtr, l, 0L); e = li; if (!extend) s = e; EDIT_EM_SetSel(wndPtr, 0, MAKELPARAM(s, e)); } /********************************************************************* * * EDIT_MovePageDown * */ static void EDIT_MovePageDown(WND *wndPtr, BOOL extend) { UINT s = LOWORD(EDIT_EM_GetSel(wndPtr, 0, 0L)); UINT e = HIWORD(EDIT_EM_GetSel(wndPtr, 0, 0L)); UINT l = (UINT)EDIT_EM_LineFromChar(wndPtr, e, 0L); UINT lc = (UINT)EDIT_EM_GetLineCount(wndPtr, e, 0L); UINT li = (UINT)EDIT_EM_LineIndex(wndPtr, l, 0L); INT x; if (l < lc - 1) { x = EDIT_WndXFromCol(wndPtr, l, e - li); l = MIN(lc - 1, l + EDIT_GetVisibleLineCount(wndPtr)); e = (UINT)EDIT_EM_LineIndex(wndPtr, l, 0L) + EDIT_ColFromWndX(wndPtr, l, x); } if (!extend) s = e; EDIT_EM_SetSel(wndPtr, 0, MAKELPARAM(s, e)); } /********************************************************************* * * EDIT_MovePageUp * */ static void EDIT_MovePageUp(WND *wndPtr, BOOL extend) { UINT s = LOWORD(EDIT_EM_GetSel(wndPtr, 0, 0L)); UINT e = HIWORD(EDIT_EM_GetSel(wndPtr, 0, 0L)); UINT l = (UINT)EDIT_EM_LineFromChar(wndPtr, e, 0L); UINT li = (UINT)EDIT_EM_LineIndex(wndPtr, l, 0L); INT x; if (l) { x = EDIT_WndXFromCol(wndPtr, l, e - li); l = MAX(0, l - EDIT_GetVisibleLineCount(wndPtr)); e = (UINT)EDIT_EM_LineIndex(wndPtr, l, 0L) + EDIT_ColFromWndX(wndPtr, l, x); } if (!extend) s = e; EDIT_EM_SetSel(wndPtr, 0, MAKELPARAM(s, e)); } /********************************************************************* * * EDIT_MoveUpward * */ static void EDIT_MoveUpward(WND *wndPtr, BOOL extend) { UINT s = LOWORD(EDIT_EM_GetSel(wndPtr, 0, 0L)); UINT e = HIWORD(EDIT_EM_GetSel(wndPtr, 0, 0L)); UINT l = (UINT)EDIT_EM_LineFromChar(wndPtr, e, 0L); UINT li = (UINT)EDIT_EM_LineIndex(wndPtr, l, 0L); INT x; if (l) { x = EDIT_WndXFromCol(wndPtr, l, e - li); l--; e = (UINT)EDIT_EM_LineIndex(wndPtr, l, 0L) + EDIT_ColFromWndX(wndPtr, l, x); } if (!extend) s = e; EDIT_EM_SetSel(wndPtr, 0, MAKELPARAM(s, e)); } /********************************************************************* * * EDIT_MoveWordBackward * */ static void EDIT_MoveWordBackward(WND *wndPtr, BOOL extend) { UINT s = LOWORD(EDIT_EM_GetSel(wndPtr, 0, 0L)); UINT e = HIWORD(EDIT_EM_GetSel(wndPtr, 0, 0L)); UINT l = (UINT)EDIT_EM_LineFromChar(wndPtr, e, 0L); UINT ll = (UINT)EDIT_EM_LineLength(wndPtr, e, 0L); UINT li = (UINT)EDIT_EM_LineIndex(wndPtr, l, 0L); char *text; if (e - li == 0) { if (l) { li = (UINT)EDIT_EM_LineIndex(wndPtr, l - 1, 0L); e = li + (UINT)EDIT_EM_LineLength(wndPtr, li, 0L); } } else { text = EDIT_GetPointer(wndPtr); e = li + (UINT)EDIT_CallWordBreakProc(wndPtr, text + li, e - li, ll, WB_LEFT); } if (!extend) s = e; EDIT_EM_SetSel(wndPtr, 0, MAKELPARAM(s, e)); } /********************************************************************* * * EDIT_MoveWordForward * */ static void EDIT_MoveWordForward(WND *wndPtr, BOOL extend) { UINT s = LOWORD(EDIT_EM_GetSel(wndPtr, 0, 0L)); UINT e = HIWORD(EDIT_EM_GetSel(wndPtr, 0, 0L)); UINT l = (UINT)EDIT_EM_LineFromChar(wndPtr, e, 0L); UINT lc = (UINT)EDIT_EM_GetLineCount(wndPtr, e, 0L); UINT ll = (UINT)EDIT_EM_LineLength(wndPtr, e, 0L); UINT li = (UINT)EDIT_EM_LineIndex(wndPtr, l, 0L); char *text; if (e - li == ll) { if (l != lc - 1) e = (UINT)EDIT_EM_LineIndex(wndPtr, l + 1, 0L); } else { text = EDIT_GetPointer(wndPtr); e = li + (UINT)EDIT_CallWordBreakProc(wndPtr, text + li, e - li + 1, ll, WB_RIGHT); } if (!extend) s = e; EDIT_EM_SetSel(wndPtr, 0, MAKELPARAM(s, e)); } /********************************************************************* * * EDIT_PaintLine * */ static void EDIT_PaintLine(WND *wndPtr, HDC hdc, UINT line, BOOL rev) { UINT fv = (UINT)EDIT_EM_GetFirstVisibleLine(wndPtr, 0, 0L); UINT vlc = EDIT_GetVisibleLineCount(wndPtr); UINT lc = (UINT)EDIT_EM_GetLineCount(wndPtr, 0, 0L); UINT li; UINT ll; UINT s; UINT e; INT x; INT y; if ((line < fv) || (line > fv + vlc) || (line >= lc)) return; dprintf_edit(stddeb, "edit: EDIT_PaintLine: line=%d\n", line); x = EDIT_WndXFromCol(wndPtr, line, 0); y = EDIT_WndYFromLine(wndPtr, line); li = (UINT)EDIT_EM_LineIndex(wndPtr, line, 0L); ll = (UINT)EDIT_EM_LineLength(wndPtr, li, 0L); s = LOWORD(EDIT_EM_GetSel(wndPtr, 0, 0L)); e = HIWORD(EDIT_EM_GetSel(wndPtr, 0, 0L)); ORDER_UINT(s, e); s = MIN(li + ll, MAX(li, s)); e = MIN(li + ll, MAX(li, e)); if (rev && (s != e) && ((GetFocus32() == wndPtr->hwndSelf) || (wndPtr->dwStyle & ES_NOHIDESEL))) { x += EDIT_PaintText(wndPtr, hdc, x, y, line, 0, s - li, FALSE); x += EDIT_PaintText(wndPtr, hdc, x, y, line, s - li, e - s, TRUE); x += EDIT_PaintText(wndPtr, hdc, x, y, line, e - li, li + ll - e, FALSE); } else x += EDIT_PaintText(wndPtr, hdc, x, y, line, 0, ll, FALSE); } /********************************************************************* * * EDIT_PaintText * */ static UINT EDIT_PaintText(WND *wndPtr, HDC hdc, INT x, INT y, UINT line, UINT col, UINT count, BOOL rev) { EDITSTATE *es = EDITSTATEPTR(wndPtr); COLORREF BkColor; COLORREF TextColor; UINT ret; char *text; UINT li; UINT xoff; if (!count) return 0; BkColor = GetBkColor(hdc); TextColor = GetTextColor(hdc); if (rev) { SetBkColor(hdc, GetSysColor(COLOR_HIGHLIGHT)); SetTextColor(hdc, GetSysColor(COLOR_HIGHLIGHTTEXT)); } text = EDIT_GetPasswordPointer(wndPtr); li = (UINT)EDIT_EM_LineIndex(wndPtr, line, 0L); xoff = EDIT_GetXOffset(wndPtr); ret = LOWORD(TabbedTextOut(hdc, x, y, text + li + col, count, es->NumTabStops, es->TabStops, -xoff)); free(text); if (rev) { SetBkColor(hdc, BkColor); SetTextColor(hdc, TextColor); } return ret; } /********************************************************************* * * EDIT_ReleasePointer * * This is the only helper function that can be called with es = NULL. * It is called at the end of EditWndProc() to unlock the buffer. * */ static void EDIT_ReleasePointer(WND *wndPtr) { EDITSTATE *es = EDITSTATEPTR(wndPtr); if (!es) return; if (es->text && es->hBuf) LOCAL_Unlock(wndPtr->hInstance, es->hBuf); es->text = NULL; } /********************************************************************* * * EDIT_ReplaceSel * * Beware: This is not the function called on EM_REPLACESEL. * It expects a (char *) in lParam, not a (SEGPTR). * It is used internally, as if there were no pointer difficulties. * */ static LRESULT EDIT_ReplaceSel(WND *wndPtr, WPARAM wParam, LPARAM lParam) { const char *str = (char *)lParam; int strl = strlen(str); UINT tl = (UINT)EDIT_WM_GetTextLength(wndPtr, 0, 0L); UINT s = LOWORD(EDIT_EM_GetSel(wndPtr, 0, 0L)); UINT e = HIWORD(EDIT_EM_GetSel(wndPtr, 0, 0L)); int i; char *p; char *text; BOOL redraw; ORDER_UINT(s,e); if (!EDIT_MakeFit(wndPtr, tl - (e - s) + strl)) { EDIT_NOTIFY_PARENT(wndPtr, EN_MAXTEXT); return 0L; } redraw = EDIT_GetRedraw(wndPtr); EDIT_WM_SetRedraw(wndPtr, FALSE, 0L); EDIT_WM_Clear(wndPtr, 0, 0L); tl = EDIT_WM_GetTextLength(wndPtr, 0, 0L); e = HIWORD(EDIT_EM_GetSel(wndPtr, 0, 0L)); text = EDIT_GetPointer(wndPtr); for (p = text + tl ; p >= text + e ; p--) p[strl] = p[0]; for (i = 0 , p = text + e ; i < strl ; i++) p[i] = str[i]; if(IsUpper(wndPtr)) AnsiUpperBuff(p, strl); else if(IsLower(wndPtr)) AnsiLowerBuff(p, strl); EDIT_BuildLineDefs(wndPtr); e += strl; EDIT_EM_SetSel(wndPtr, 0, MAKELPARAM(e, e)); EDIT_EM_SetModify(wndPtr, TRUE, 0L); EDIT_NOTIFY_PARENT(wndPtr, EN_UPDATE); EDIT_WM_SetRedraw(wndPtr, redraw, 0L); if (redraw) { InvalidateRect32( wndPtr->hwndSelf, NULL, TRUE ); EDIT_NOTIFY_PARENT(wndPtr, EN_CHANGE); } return 0L; } /********************************************************************* * * EDIT_ScrollIntoView * * Makes sure the caret is visible. * */ static void EDIT_ScrollIntoView(WND *wndPtr) { UINT e = HIWORD(EDIT_EM_GetSel(wndPtr, 0, 0L)); UINT l = (UINT)EDIT_EM_LineFromChar(wndPtr, e, 0L); UINT li = (UINT)EDIT_EM_LineIndex(wndPtr, l, 0L); UINT fv = (UINT)EDIT_EM_GetFirstVisibleLine(wndPtr, 0, 0L); UINT vlc = EDIT_GetVisibleLineCount(wndPtr); UINT ww = EDIT_GetWndWidth(wndPtr); UINT cw = EDIT_GetAveCharWidth(wndPtr); INT x = EDIT_WndXFromCol(wndPtr, l, e - li); int dy = 0; int dx = 0; if (l >= fv + vlc) dy = l - vlc + 1 - fv; if (l < fv) dy = l - fv; if (x < 0) dx = x - ww / HSCROLL_FRACTION / cw * cw; if (x > ww) dx = x - (HSCROLL_FRACTION - 1) * ww / HSCROLL_FRACTION / cw * cw; if (dy || dx) { EDIT_EM_LineScroll(wndPtr, 0, MAKELPARAM(dy, dx)); if (dy) EDIT_NOTIFY_PARENT(wndPtr, EN_VSCROLL); if (dx) EDIT_NOTIFY_PARENT(wndPtr, EN_HSCROLL); } } /********************************************************************* * * EDIT_WndXFromCol * * Calculates, for a given line and column, the X-coordinate on the screen. * */ static INT EDIT_WndXFromCol(WND *wndPtr, UINT line, UINT col) { EDITSTATE *es = EDITSTATEPTR(wndPtr); char *text = EDIT_GetPasswordPointer(wndPtr); INT ret; HDC32 hdc; HFONT hFont; HFONT oldFont = 0; UINT lc = (UINT)EDIT_EM_GetLineCount(wndPtr, 0, 0L); UINT li = (UINT)EDIT_EM_LineIndex(wndPtr, line, 0L); UINT ll = (UINT)EDIT_EM_LineLength(wndPtr, li, 0L); UINT xoff = EDIT_GetXOffset(wndPtr); hdc = GetDC32(wndPtr->hwndSelf); hFont = (HFONT)EDIT_WM_GetFont(wndPtr, 0, 0L); if (hFont) oldFont = SelectObject(hdc, hFont); line = MAX(0, MIN(line, lc - 1)); col = MIN(col, ll); ret = LOWORD(GetTabbedTextExtent(hdc, text + li, col, es->NumTabStops, es->TabStops)) - xoff; if (hFont) SelectObject(hdc, oldFont); ReleaseDC32(wndPtr->hwndSelf, hdc); free(text); return ret; } /********************************************************************* * * EDIT_WndYFromLine * * Calculates, for a given line, the Y-coordinate on the screen. * */ static INT EDIT_WndYFromLine(WND *wndPtr, UINT line) { UINT fv = (UINT)EDIT_EM_GetFirstVisibleLine(wndPtr, 0, 0L); UINT lh = EDIT_GetLineHeight(wndPtr); return (line - fv) * lh; } /********************************************************************* * * EDIT_WordBreakProc * * Find the beginning of words. * Note: unlike the specs for a WordBreakProc, this function only * allows to be called without linebreaks between s[0] upto * s[count - 1]. Remember it is only called * internally, so we can decide this for ourselves. * */ static INT EDIT_WordBreakProc(char *s, INT index, INT count, INT action) { INT ret = 0; dprintf_edit(stddeb, "edit: EDIT_WordBreakProc: s=%p, index=%d" ", count=%d, action=%d\n", s, index, count, action); switch (action) { case WB_LEFT: if (!count) break; if (index) index--; if (s[index] == ' ') { while (index && (s[index] == ' ')) index--; if (index) { while (index && (s[index] != ' ')) index--; if (s[index] == ' ') index++; } } else { while (index && (s[index] != ' ')) index--; if (s[index] == ' ') index++; } ret = index; break; case WB_RIGHT: if (!count) break; if (index) index--; if (s[index] == ' ') while ((index < count) && (s[index] == ' ')) index++; else { while (s[index] && (s[index] != ' ') && (index < count)) index++; while ((s[index] == ' ') && (index < count)) index++; } ret = index; break; case WB_ISDELIMITER: ret = (s[index] == ' '); break; default: fprintf(stderr, "edit: EDIT_WordBreakProc: unknown action code, please report !\n"); break; } return ret; } /********************************************************************* * * EM_CANUNDO * */ static LRESULT EDIT_EM_CanUndo(WND *wndPtr, WPARAM wParam, LPARAM lParam) { return 0L; } /********************************************************************* * * EM_EMPTYUNDOBUFFER * */ static LRESULT EDIT_EM_EmptyUndoBuffer(WND *wndPtr, WPARAM wParam, LPARAM lParam) { return 0L; } /********************************************************************* * * EM_FMTLINES * */ static LRESULT EDIT_EM_FmtLines(WND *wndPtr, WPARAM wParam, LPARAM lParam) { fprintf(stdnimp, "edit: EM_FMTLINES: message not implemented.\n"); return wParam ? -1L : 0L; } /********************************************************************* * * EM_GETFIRSTVISIBLELINE * */ static LRESULT EDIT_EM_GetFirstVisibleLine(WND *wndPtr, WPARAM wParam, LPARAM lParam) { EDITSTATE *es = EDITSTATEPTR(wndPtr); return (LRESULT)es->FirstVisibleLine; } /********************************************************************* * * EM_GETHANDLE * */ static LRESULT EDIT_EM_GetHandle(WND *wndPtr, WPARAM wParam, LPARAM lParam) { EDITSTATE *es = EDITSTATEPTR(wndPtr); return (LRESULT)es->hBuf; } /********************************************************************* * * EM_GETLINE * */ static LRESULT EDIT_EM_GetLine(WND *wndPtr, WPARAM wParam, LPARAM lParam) { char *text; char *src; char *dst; UINT len; UINT i; UINT lc = (UINT)EDIT_EM_GetLineCount(wndPtr, 0, 0L); if (!IsMultiLine(wndPtr)) wParam = 0; if ((UINT)wParam >= lc) return 0L; text = EDIT_GetPointer(wndPtr); src = text + (UINT)EDIT_EM_LineIndex(wndPtr, wParam, 0L); dst = (char *)PTR_SEG_TO_LIN(lParam); len = MIN(*(WORD *)dst, (UINT)EDIT_EM_LineLength(wndPtr, wParam, 0L)); for (i = 0 ; i < len ; i++) { *dst = *src; src++; dst++; } return (LRESULT)len; } /********************************************************************* * * EM_GETLINECOUNT * */ static LRESULT EDIT_EM_GetLineCount(WND *wndPtr, WPARAM wParam, LPARAM lParam) { EDITSTATE *es = EDITSTATEPTR(wndPtr); return (LRESULT)es->LineCount; } /********************************************************************* * * EM_GETMODIFY * */ static LRESULT EDIT_EM_GetModify(WND *wndPtr, WPARAM wParam, LPARAM lParam) { EDITSTATE *es = EDITSTATEPTR(wndPtr); return (LRESULT)es->TextChanged; } /********************************************************************* * * EM_GETPASSWORDCHAR * */ static LRESULT EDIT_EM_GetPasswordChar(WND *wndPtr, WPARAM wParam, LPARAM lParam) { EDITSTATE *es = EDITSTATEPTR(wndPtr); return (LRESULT)es->PasswordChar; } /********************************************************************* * * EM_GETRECT * */ static LRESULT EDIT_EM_GetRect(WND *wndPtr, WPARAM wParam, LPARAM lParam) { return EDIT_GetRect(wndPtr, wParam, (LPARAM)PTR_SEG_TO_LIN(lParam)); } /********************************************************************* * * EM_GETSEL * */ static LRESULT EDIT_EM_GetSel(WND *wndPtr, WPARAM wParam, LPARAM lParam) { EDITSTATE *es = EDITSTATEPTR(wndPtr); return MAKELONG(es->SelStart, es->SelEnd); } /********************************************************************* * * EM_GETTHUMB * * FIXME: undocumented: is this right ? * */ static LRESULT EDIT_EM_GetThumb(WND *wndPtr, WPARAM wParam, LPARAM lParam) { return MAKELONG(EDIT_WM_VScroll(wndPtr, EM_GETTHUMB, 0L), EDIT_WM_HScroll(wndPtr, EM_GETTHUMB, 0L)); } /********************************************************************* * * EM_GETWORDBREAKPROC * */ static LRESULT EDIT_EM_GetWordBreakProc(WND *wndPtr, WPARAM wParam, LPARAM lParam) { EDITSTATE *es = EDITSTATEPTR(wndPtr); return (LRESULT)es->WordBreakProc; } /********************************************************************* * * EM_LIMITTEXT * */ static LRESULT EDIT_EM_LimitText(WND *wndPtr, WPARAM wParam, LPARAM lParam) { EDITSTATE *es = EDITSTATEPTR(wndPtr); if (IsMultiLine(wndPtr)) { if (wParam) es->BufLimit = MIN((UINT)wParam, BUFLIMIT_MULTI); else es->BufLimit = BUFLIMIT_MULTI; } else { if (wParam) es->BufLimit = MIN((UINT)wParam, BUFLIMIT_SINGLE); else es->BufLimit = BUFLIMIT_SINGLE; } return 0L; } /********************************************************************* * * EM_LINEFROMCHAR * */ static LRESULT EDIT_EM_LineFromChar(WND *wndPtr, WPARAM wParam, LPARAM lParam) { UINT l; if (!IsMultiLine(wndPtr)) return 0L; if ((INT)wParam == -1) wParam = HIWORD(EDIT_EM_GetSel(wndPtr, 0, 0L)); l = (UINT)EDIT_EM_GetLineCount(wndPtr, 0, 0L) - 1; while ((UINT)EDIT_EM_LineIndex(wndPtr, l, 0L) > (UINT)wParam) l--; return (LRESULT)l; } /********************************************************************* * * EM_LINEINDEX * */ static LRESULT EDIT_EM_LineIndex(WND *wndPtr, WPARAM wParam, LPARAM lParam) { EDITSTATE *es = EDITSTATEPTR(wndPtr); UINT e; UINT l; UINT lc = (UINT)EDIT_EM_GetLineCount(wndPtr, 0, 0L); if ((INT)wParam == -1) { e = HIWORD(EDIT_EM_GetSel(wndPtr, 0, 0L)); l = lc - 1; while (es->LineDefs[l].offset > e) l--; return (LRESULT)es->LineDefs[l].offset; } if ((UINT)wParam >= lc) return -1L; return (LRESULT)es->LineDefs[(UINT)wParam].offset; } /********************************************************************* * * EM_LINELENGTH * */ static LRESULT EDIT_EM_LineLength(WND *wndPtr, WPARAM wParam, LPARAM lParam) { EDITSTATE *es = EDITSTATEPTR(wndPtr); UINT s; UINT e; UINT sl; UINT el; if (!IsMultiLine(wndPtr)) return (LRESULT)es->LineDefs[0].length; if ((INT)wParam == -1) { s = LOWORD(EDIT_EM_GetSel(wndPtr, 0, 0L)); e = HIWORD(EDIT_EM_GetSel(wndPtr, 0, 0L)); sl = (UINT)EDIT_EM_LineFromChar(wndPtr, s, 0L); el = (UINT)EDIT_EM_LineFromChar(wndPtr, e, 0L); return (LRESULT)(s - es->LineDefs[sl].offset + es->LineDefs[el].offset + es->LineDefs[el].length - e); } return (LRESULT)es->LineDefs[(UINT)EDIT_EM_LineFromChar(wndPtr, wParam, 0L)].length; } /********************************************************************* * * EM_LINESCROLL * */ static LRESULT EDIT_EM_LineScroll(WND *wndPtr, WPARAM wParam, LPARAM lParam) { EDITSTATE *es = EDITSTATEPTR(wndPtr); UINT lc = (UINT)EDIT_EM_GetLineCount(wndPtr, 0, 0L); UINT fv = (UINT)EDIT_EM_GetFirstVisibleLine(wndPtr, 0, 0L); UINT nfv = MAX(0, fv + (INT)LOWORD(lParam)); UINT xoff = EDIT_GetXOffset(wndPtr); UINT nxoff = MAX(0, xoff + (INT)HIWORD(lParam)); UINT tw = EDIT_GetTextWidth(wndPtr); INT dx; INT dy; POINT16 pos; if (nfv >= lc) nfv = lc - 1; if (nxoff >= tw) nxoff = tw; dx = xoff - nxoff; dy = EDIT_WndYFromLine(wndPtr, fv) - EDIT_WndYFromLine(wndPtr, nfv); if (dx || dy) { if (wndPtr->hwndSelf == GetFocus32()) HideCaret(wndPtr->hwndSelf); if (EDIT_GetRedraw(wndPtr)) ScrollWindow(wndPtr->hwndSelf, dx, dy, NULL, NULL); es->FirstVisibleLine = nfv; es->XOffset = nxoff; if (IsVScrollBar(wndPtr)) SetScrollPos32(wndPtr->hwndSelf, SB_VERT, EDIT_WM_VScroll(wndPtr, EM_GETTHUMB, 0L), TRUE); if (IsHScrollBar(wndPtr)) SetScrollPos32(wndPtr->hwndSelf, SB_HORZ, EDIT_WM_HScroll(wndPtr, EM_GETTHUMB, 0L), TRUE); if (wndPtr->hwndSelf == GetFocus32()) { GetCaretPos16(&pos); SetCaretPos(pos.x + dx, pos.y + dy); ShowCaret(wndPtr->hwndSelf); } } return -1L; } /********************************************************************* * * EM_REPLACESEL * */ static LRESULT EDIT_EM_ReplaceSel(WND *wndPtr, WPARAM wParam, LPARAM lParam) { return (LRESULT)EDIT_ReplaceSel(wndPtr, wParam, (LPARAM)(char *)PTR_SEG_TO_LIN(lParam)); } /********************************************************************* * * EM_SCROLL * * FIXME: undocumented message. * */ static LRESULT EDIT_EM_Scroll(WND *wndPtr, WPARAM wParam, LPARAM lParam) { fprintf(stdnimp, "edit: EM_SCROLL: message not implemented (undocumented), please report.\n"); return 0L; } /********************************************************************* * * EM_SETHANDLE * */ static LRESULT EDIT_EM_SetHandle(WND *wndPtr, WPARAM wParam, LPARAM lParam) { EDITSTATE *es = EDITSTATEPTR(wndPtr); if (IsMultiLine(wndPtr)) { EDIT_ReleasePointer(wndPtr); /* * old buffer is freed by caller */ es->hBuf = (HLOCAL16)wParam; es->BufSize = LOCAL_Size(wndPtr->hInstance, es->hBuf) - 1; es->LineCount = 0; es->FirstVisibleLine = 0; es->SelStart = es->SelEnd = 0; EDIT_EM_EmptyUndoBuffer(wndPtr, 0, 0L); EDIT_EM_SetModify(wndPtr, FALSE, 0L); EDIT_BuildLineDefs(wndPtr); if (EDIT_GetRedraw(wndPtr)) InvalidateRect32( wndPtr->hwndSelf, NULL, TRUE ); EDIT_ScrollIntoView(wndPtr); } return 0L; } /********************************************************************* * * EM_SETMODIFY * */ static LRESULT EDIT_EM_SetModify(WND *wndPtr, WPARAM wParam, LPARAM lParam) { EDITSTATE *es = EDITSTATEPTR(wndPtr); es->TextChanged = (BOOL)wParam; return 0L; } /********************************************************************* * * EM_SETPASSWORDCHAR * */ static LRESULT EDIT_EM_SetPasswordChar(WND *wndPtr, WPARAM wParam, LPARAM lParam) { EDITSTATE *es = EDITSTATEPTR(wndPtr); es->PasswordChar = (char)wParam; return 0L; } /********************************************************************* * * EM_SETREADONLY * */ static LRESULT EDIT_EM_SetReadOnly(WND *wndPtr, WPARAM wParam, LPARAM lParam) { if ((BOOL)wParam) wndPtr->dwStyle |= ES_READONLY; else wndPtr->dwStyle &= ~(DWORD)ES_READONLY; return 0L; } /********************************************************************* * * EM_SETRECT * */ static LRESULT EDIT_EM_SetRect(WND *wndPtr, WPARAM wParam, LPARAM lParam) { fprintf(stdnimp,"edit: EM_SETRECT: message not implemented, please report.\n"); return 0L; } /********************************************************************* * * EM_SETRECTNP * */ static LRESULT EDIT_EM_SetRectNP(WND *wndPtr, WPARAM wParam, LPARAM lParam) { fprintf(stdnimp,"edit: EM_SETRECTNP: message not implemented, please report.\n"); return 0L; } /********************************************************************* * * EM_SETSEL * */ static LRESULT EDIT_EM_SetSel(WND *wndPtr, WPARAM wParam, LPARAM lParam) { EDITSTATE *es = EDITSTATEPTR(wndPtr); UINT ns = LOWORD(lParam); UINT ne = HIWORD(lParam); UINT s = LOWORD(EDIT_EM_GetSel(wndPtr, 0, 0L)); UINT e = HIWORD(EDIT_EM_GetSel(wndPtr, 0, 0L)); UINT el; UINT eli; UINT tl = (UINT)EDIT_WM_GetTextLength(wndPtr, 0, 0L); if ((INT)ns == -1) { ns = e; ne = e; } else { ns = MIN(ns, tl); ne = MIN(ne, tl); } es->SelStart = ns; es->SelEnd = ne; if (wndPtr->hwndSelf == GetFocus32()) { el = (UINT)EDIT_EM_LineFromChar(wndPtr, ne, 0L); eli = (UINT)EDIT_EM_LineIndex(wndPtr, el, 0L); SetCaretPos(EDIT_WndXFromCol(wndPtr, el, ne - eli), EDIT_WndYFromLine(wndPtr, el)); } if (!wParam) EDIT_ScrollIntoView(wndPtr); if (EDIT_GetRedraw(wndPtr)) { ORDER_UINT(s, e); ORDER_UINT(s, ns); ORDER_UINT(s, ne); ORDER_UINT(e, ns); ORDER_UINT(e, ne); ORDER_UINT(ns, ne); if (e != ns) { EDIT_InvalidateText(wndPtr, s, e); EDIT_InvalidateText(wndPtr, ns, ne); } else EDIT_InvalidateText(wndPtr, s, ne); } return -1L; } /********************************************************************* * * EM_SETTABSTOPS * */ static LRESULT EDIT_EM_SetTabStops(WND *wndPtr, WPARAM wParam, LPARAM lParam) { EDITSTATE *es = EDITSTATEPTR(wndPtr); if (!IsMultiLine(wndPtr)) return 0L; if (es->TabStops) free(es->TabStops); es->NumTabStops = (UINT)wParam; if (!wParam) es->TabStops = NULL; else { es->TabStops = (LPINT16)xmalloc(wParam * sizeof(INT16)); memcpy(es->TabStops, (LPINT16)PTR_SEG_TO_LIN(lParam), (UINT)wParam * sizeof(INT16)); } return 1L; } /********************************************************************* * * EM_SETWORDBREAKPROC * */ static LRESULT EDIT_EM_SetWordBreakProc(WND *wndPtr, WPARAM wParam, LPARAM lParam) { EDITSTATE *es = EDITSTATEPTR(wndPtr); es->WordBreakProc = (EDITWORDBREAKPROC)lParam; return 0L; } /********************************************************************* * * EM_UNDO * */ static LRESULT EDIT_EM_Undo(WND *wndPtr, WPARAM wParam, LPARAM lParam) { return 0L; } /********************************************************************* * * WM_CHAR * */ static LRESULT EDIT_WM_Char(WND *wndPtr, WPARAM wParam, LPARAM lParam) { char str[2]; unsigned char c = (unsigned char)wParam; switch (c) { case '\r': case '\n': if (IsMultiLine(wndPtr)) { if (IsReadOnly(wndPtr)) { EDIT_MoveHome(wndPtr, FALSE); EDIT_MoveDownward(wndPtr, FALSE); } else EDIT_ReplaceSel(wndPtr, 0, (LPARAM)"\r\n"); } break; case '\t': if (IsMultiLine(wndPtr) && !IsReadOnly(wndPtr)) EDIT_ReplaceSel(wndPtr, 0, (LPARAM)"\t"); break; default: if (!IsReadOnly(wndPtr) && (c >= ' ') && (c != 127)) { str[0] = c; str[1] = '\0'; EDIT_ReplaceSel(wndPtr, 0, (LPARAM)str); } break; } return 0L; } /********************************************************************* * * WM_CLEAR * */ static LRESULT EDIT_WM_Clear(WND *wndPtr, WPARAM wParam, LPARAM lParam) { UINT s = LOWORD(EDIT_EM_GetSel(wndPtr, 0, 0L)); UINT e = HIWORD(EDIT_EM_GetSel(wndPtr, 0, 0L)); char *text; BOOL redraw; if (s != e) { redraw = EDIT_GetRedraw(wndPtr); EDIT_WM_SetRedraw(wndPtr, FALSE, 0L); ORDER_UINT(s, e); text = EDIT_GetPointer(wndPtr); strcpy(text + s, text + e); EDIT_BuildLineDefs(wndPtr); EDIT_EM_SetSel(wndPtr, 0, MAKELPARAM(s, s)); EDIT_EM_SetModify(wndPtr, TRUE, 0L); EDIT_NOTIFY_PARENT(wndPtr, EN_UPDATE); EDIT_WM_SetRedraw(wndPtr, redraw, 0L); if (redraw) { InvalidateRect32( wndPtr->hwndSelf, NULL, TRUE ); EDIT_NOTIFY_PARENT(wndPtr, EN_CHANGE); } } return -1L; } /********************************************************************* * * WM_COPY * */ static LRESULT EDIT_WM_Copy(WND *wndPtr, WPARAM wParam, LPARAM lParam) { UINT s = LOWORD(EDIT_EM_GetSel(wndPtr, 0, 0L)); UINT e = HIWORD(EDIT_EM_GetSel(wndPtr, 0, 0L)); HGLOBAL16 hdst; char *text; char *dst; char *src; int i; if (e == s) return -1L; ORDER_UINT(s, e); hdst = GlobalAlloc16(GMEM_MOVEABLE, (DWORD)(e - s + 1)); dst = GlobalLock16(hdst); text = EDIT_GetPointer(wndPtr); src = text + s; for (i = 0 ; i < e - s ; i++) *dst++ = *src++; *dst = '\0'; GlobalUnlock16(hdst); OpenClipboard(wndPtr->hwndSelf); EmptyClipboard(); SetClipboardData(CF_TEXT, hdst); CloseClipboard(); return -1L; } /********************************************************************* * * WM_CREATE * */ static LRESULT EDIT_WM_Create(WND *wndPtr, WPARAM wParam, LPARAM lParam) { CREATESTRUCT16 *cs = (CREATESTRUCT16 *)PTR_SEG_TO_LIN(lParam); EDITSTATE *es; char *text; es = xmalloc(sizeof(EDITSTATE)); memset(es, 0, sizeof(EDITSTATE)); *(EDITSTATE **)wndPtr->wExtra = es; if (cs->style & WS_VSCROLL) cs->style |= ES_AUTOVSCROLL; if (cs->style & WS_HSCROLL) cs->style |= ES_AUTOHSCROLL; /* 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 ((cs->style & WS_BORDER) && (cs->style & WS_DLGFRAME)) cs->style ^= WS_DLGFRAME; if (IsMultiLine(wndPtr)) { es->BufSize = BUFSTART_MULTI; es->BufLimit = BUFLIMIT_MULTI; es->PasswordChar = '\0'; } else { es->BufSize = BUFSTART_SINGLE; es->BufLimit = BUFLIMIT_SINGLE; es->PasswordChar = (cs->style & ES_PASSWORD) ? '*' : '\0'; } if (!LOCAL_HeapSize(wndPtr->hInstance)) { if (!LocalInit(wndPtr->hInstance, 0, GlobalSize16(wndPtr->hInstance))) { fprintf(stderr, "edit: WM_CREATE: could not initialize local heap\n"); return -1L; } dprintf_edit(stddeb, "edit: WM_CREATE: local heap initialized\n"); } if (!(es->hBuf = LOCAL_Alloc(wndPtr->hInstance, LMEM_MOVEABLE, es->BufSize + 1))) { fprintf(stderr, "edit: WM_CREATE: unable to allocate buffer\n"); return -1L; } es->BufSize = LOCAL_Size(wndPtr->hInstance, es->hBuf) - 1; text = EDIT_GetPointer(wndPtr); *text = '\0'; EDIT_BuildLineDefs(wndPtr); EDIT_WM_SetFont(wndPtr, 0, 0L); if (cs->lpszName && *(char *)PTR_SEG_TO_LIN(cs->lpszName) != '\0') EDIT_EM_ReplaceSel(wndPtr, FALSE, (LPARAM)cs->lpszName); EDIT_WM_SetRedraw(wndPtr, TRUE, 0L); return 0L; } /********************************************************************* * * WM_CUT * */ static LRESULT EDIT_WM_Cut(WND *wndPtr, WPARAM wParam, LPARAM lParam) { EDIT_WM_Copy(wndPtr, 0, 0L); EDIT_WM_Clear(wndPtr, 0, 0L); return -1L; } /********************************************************************* * * WM_DESTROY * */ static LRESULT EDIT_WM_Destroy(WND *wndPtr, WPARAM wParam, LPARAM lParam) { EDITSTATE *es = EDITSTATEPTR(wndPtr); free(es->LineDefs); if (es->TabStops) free(es->TabStops); EDIT_ReleasePointer(wndPtr); LOCAL_Free(wndPtr->hInstance, es->hBuf); free(es); *(EDITSTATE **)&wndPtr->wExtra = NULL; return 0L; } /********************************************************************* * * WM_ENABLE * */ static LRESULT EDIT_WM_Enable(WND *wndPtr, WPARAM wParam, LPARAM lParam) { EDIT_InvalidateText(wndPtr, 0, -1); return 0L; } /********************************************************************* * * WM_ERASEBKGND * */ static LRESULT EDIT_WM_EraseBkGnd(WND *wndPtr, WPARAM wParam, LPARAM lParam) { HBRUSH hBrush; RECT16 rc; hBrush = (HBRUSH)EDIT_SEND_CTLCOLOR(wndPtr, wParam); if (!hBrush) hBrush = (HBRUSH)GetStockObject(WHITE_BRUSH); GetClientRect16(wndPtr->hwndSelf, &rc); IntersectClipRect((HDC)wParam, rc.left, rc.top, rc.right, rc.bottom); GetClipBox16((HDC)wParam, &rc); /* * FIXME: specs say that we should UnrealizeObject() the brush, * but the specs of UnrealizeObject() say that we shouldn't * unrealize a stock object. The default brush that * DefWndProc() returns is ... a stock object. */ FillRect16((HDC)wParam, &rc, hBrush); return -1L; } /********************************************************************* * * WM_GETDLGCODE * */ static LRESULT EDIT_WM_GetDlgCode(WND *wndPtr, WPARAM wParam, LPARAM lParam) { return DLGC_HASSETSEL | DLGC_WANTCHARS | DLGC_WANTARROWS; } /********************************************************************* * * WM_GETFONT * */ static LRESULT EDIT_WM_GetFont(WND *wndPtr, WPARAM wParam, LPARAM lParam) { EDITSTATE *es = EDITSTATEPTR(wndPtr); return (LRESULT)es->hFont; } /********************************************************************* * * WM_GETTEXT * */ static LRESULT EDIT_WM_GetText(WND *wndPtr, WPARAM wParam, LPARAM lParam) { char *text = EDIT_GetPointer(wndPtr); int len; LRESULT lResult = 0L; len = strlen(text); if ((UINT)wParam > len) { strcpy((char *)PTR_SEG_TO_LIN(lParam), text); lResult = (LRESULT)len ; } return lResult; } /********************************************************************* * * WM_GETTEXTLENGTH * */ static LRESULT EDIT_WM_GetTextLength(WND *wndPtr, WPARAM wParam, LPARAM lParam) { char *text = EDIT_GetPointer(wndPtr); return (LRESULT)strlen(text); } /********************************************************************* * * WM_HSCROLL * * FIXME: scrollbar code itself is broken, so this one is a hack. * */ static LRESULT EDIT_WM_HScroll(WND *wndPtr, WPARAM wParam, LPARAM lParam) { UINT ww = EDIT_GetWndWidth(wndPtr); UINT tw = EDIT_GetTextWidth(wndPtr); UINT cw = EDIT_GetAveCharWidth(wndPtr); UINT xoff = EDIT_GetXOffset(wndPtr); INT dx = 0; BOOL not = TRUE; LRESULT ret = 0L; switch (wParam) { case SB_LINELEFT: dx = -cw; break; case SB_LINERIGHT: dx = cw; break; case SB_PAGELEFT: dx = -ww / HSCROLL_FRACTION / cw * cw; break; case SB_PAGERIGHT: dx = ww / HSCROLL_FRACTION / cw * cw; break; case SB_LEFT: dx = -xoff; break; case SB_RIGHT: dx = tw - xoff; break; case SB_THUMBTRACK: /* * not = FALSE; */ case SB_THUMBPOSITION: dx = LOWORD(lParam) * tw / 100 - xoff; break; /* The next two are undocumented ! */ case EM_GETTHUMB: ret = tw ? MAKELONG(xoff * 100 / tw, 0) : 0; break; case EM_LINESCROLL: dx = LOWORD(lParam); break; case SB_ENDSCROLL: default: break; } if (dx) { EDIT_EM_LineScroll(wndPtr, 0, MAKELPARAM(0, dx)); if (not) EDIT_NOTIFY_PARENT(wndPtr, EN_HSCROLL); } return ret; } /********************************************************************* * * WM_KEYDOWN * * Handling of special keys that don't produce a WM_CHAR * (i.e. non-printable keys) & Backspace & Delete * */ static LRESULT EDIT_WM_KeyDown(WND *wndPtr, WPARAM wParam, LPARAM lParam) { UINT s = LOWORD(EDIT_EM_GetSel(wndPtr, 0, 0L)); UINT e = HIWORD(EDIT_EM_GetSel(wndPtr, 0, 0L)); BOOL shift; BOOL control; if (GetKeyState(VK_MENU) & 0x8000) return 0L; shift = GetKeyState(VK_SHIFT) & 0x8000; control = GetKeyState(VK_CONTROL) & 0x8000; switch (wParam) { case VK_LEFT: case VK_UP: if (IsMultiLine(wndPtr) && (wParam == VK_UP)) EDIT_MoveUpward(wndPtr, shift); else if (control) EDIT_MoveWordBackward(wndPtr, shift); else EDIT_MoveBackward(wndPtr, shift); break; case VK_RIGHT: case VK_DOWN: if (IsMultiLine(wndPtr) && (wParam == VK_DOWN)) EDIT_MoveDownward(wndPtr, shift); else if (control) EDIT_MoveWordForward(wndPtr, shift); else EDIT_MoveForward(wndPtr, shift); break; case VK_HOME: EDIT_MoveHome(wndPtr, shift); break; case VK_END: EDIT_MoveEnd(wndPtr, shift); break; case VK_PRIOR: if (IsMultiLine(wndPtr)) EDIT_MovePageUp(wndPtr, shift); break; case VK_NEXT: if (IsMultiLine(wndPtr)) EDIT_MovePageDown(wndPtr, shift); break; case VK_BACK: if (!IsReadOnly(wndPtr) && !control) if (e != s) EDIT_WM_Clear(wndPtr, 0, 0L); else EDIT_DelLeft(wndPtr); break; case VK_DELETE: if (!IsReadOnly(wndPtr) && !(shift && control)) if (e != s) { if (shift) EDIT_WM_Cut(wndPtr, 0, 0L); else EDIT_WM_Clear(wndPtr, 0, 0L); } else { if (shift) EDIT_DelLeft(wndPtr); else if (control) EDIT_DelEnd(wndPtr); else EDIT_DelRight(wndPtr); } break; case VK_INSERT: if (shift) { if (!IsReadOnly(wndPtr)) EDIT_WM_Paste(wndPtr, 0, 0L); } else if (control) EDIT_WM_Copy(wndPtr, 0, 0L); break; } return 0L; } /********************************************************************* * * WM_KILLFOCUS * */ static LRESULT EDIT_WM_KillFocus(WND *wndPtr, WPARAM wParam, LPARAM lParam) { UINT s; UINT e; DestroyCaret(); if(!(wndPtr->dwStyle & ES_NOHIDESEL)) { s = LOWORD(EDIT_EM_GetSel(wndPtr, 0, 0L)); e = HIWORD(EDIT_EM_GetSel(wndPtr, 0, 0L)); EDIT_InvalidateText(wndPtr, s, e); } EDIT_NOTIFY_PARENT(wndPtr, EN_KILLFOCUS); return 0L; } /********************************************************************* * * WM_LBUTTONDBLCLK * * The caret position has been set on the WM_LBUTTONDOWN message * */ static LRESULT EDIT_WM_LButtonDblClk(WND *wndPtr, WPARAM wParam, LPARAM lParam) { UINT s; UINT e = HIWORD(EDIT_EM_GetSel(wndPtr, 0, 0L)); UINT l = (UINT)EDIT_EM_LineFromChar(wndPtr, e, 0L); UINT li = (UINT)EDIT_EM_LineIndex(wndPtr, l, 0L); UINT ll = (UINT)EDIT_EM_LineLength(wndPtr, e, 0L); char *text = EDIT_GetPointer(wndPtr); s = li + EDIT_CallWordBreakProc (wndPtr, text + li, e - li, ll, WB_LEFT); e = li + EDIT_CallWordBreakProc(wndPtr, text + li, e - li, ll, WB_RIGHT); EDIT_EM_SetSel(wndPtr, 0, MAKELPARAM(s, e)); return 0L; } /********************************************************************* * * WM_LBUTTONDOWN * */ static LRESULT EDIT_WM_LButtonDown(WND *wndPtr, WPARAM wParam, LPARAM lParam) { INT x = (INT)LOWORD(lParam); INT y = (INT)HIWORD(lParam); UINT l = EDIT_LineFromWndY(wndPtr, y); UINT c; UINT s; UINT e; UINT fv = (UINT)EDIT_EM_GetFirstVisibleLine(wndPtr, 0, 0L); UINT vlc = EDIT_GetVisibleLineCount(wndPtr); UINT li; SetFocus32(wndPtr->hwndSelf); SetCapture32(wndPtr->hwndSelf); l = MIN(fv + vlc - 1, MAX(fv, l)); x = MIN(EDIT_GetWndWidth(wndPtr), MAX(0, x)); c = EDIT_ColFromWndX(wndPtr, l, x); li = (UINT)EDIT_EM_LineIndex(wndPtr, l, 0L); e = li + c; if (GetKeyState(VK_SHIFT) & 0x8000) s = LOWORD(EDIT_EM_GetSel(wndPtr, 0, 0L)); else s = e; EDIT_EM_SetSel(wndPtr, 0, MAKELPARAM(s, e)); return 0L; } /********************************************************************* * * WM_LBUTTONUP * */ static LRESULT EDIT_WM_LButtonUp(WND *wndPtr, WPARAM wParam, LPARAM lParam) { if (GetCapture32() == wndPtr->hwndSelf) ReleaseCapture(); return 0L; } /********************************************************************* * * WM_MOUSEMOVE * */ static LRESULT EDIT_WM_MouseMove(WND *wndPtr, WPARAM wParam, LPARAM lParam) { INT x; INT y; UINT l; UINT c; UINT s; UINT fv; UINT vlc; UINT li; if (GetCapture32() == wndPtr->hwndSelf) { x = (INT)LOWORD(lParam); y = (INT)HIWORD(lParam); fv = (UINT)EDIT_EM_GetFirstVisibleLine(wndPtr, 0, 0L); vlc = EDIT_GetVisibleLineCount(wndPtr); l = EDIT_LineFromWndY(wndPtr, y); l = MIN(fv + vlc - 1, MAX(fv, l)); x = MIN(EDIT_GetWndWidth(wndPtr), MAX(0, x)); c = EDIT_ColFromWndX(wndPtr, l, x); s = LOWORD(EDIT_EM_GetSel(wndPtr, 0, 0L)); li = (UINT)EDIT_EM_LineIndex(wndPtr, l, 0L); EDIT_EM_SetSel(wndPtr, 1, MAKELPARAM(s, li + c)); } return 0L; } /********************************************************************* * * WM_PAINT * */ static LRESULT EDIT_WM_Paint(WND *wndPtr, WPARAM wParam, LPARAM lParam) { PAINTSTRUCT16 ps; UINT i; UINT fv = (UINT)EDIT_EM_GetFirstVisibleLine(wndPtr, 0, 0L); UINT vlc = EDIT_GetVisibleLineCount(wndPtr); UINT lc = (UINT)EDIT_EM_GetLineCount(wndPtr, 0, 0L); HDC16 hdc; HFONT hFont; HFONT oldFont = 0; RECT16 rc; RECT16 rcLine; RECT16 rcRgn; BOOL rev = IsWindowEnabled(wndPtr->hwndSelf) && ((GetFocus32() == wndPtr->hwndSelf) || (wndPtr->dwStyle & ES_NOHIDESEL)); hdc = BeginPaint16(wndPtr->hwndSelf, &ps); GetClientRect16(wndPtr->hwndSelf, &rc); IntersectClipRect(hdc, rc.left, rc.top, rc.right, rc.bottom); hFont = EDIT_WM_GetFont(wndPtr, 0, 0L); if (hFont) oldFont = SelectObject(hdc, hFont); EDIT_SEND_CTLCOLOR(wndPtr, hdc); if (!IsWindowEnabled(wndPtr->hwndSelf)) SetTextColor(hdc, GetSysColor(COLOR_GRAYTEXT)); GetClipBox16(hdc, &rcRgn); for (i = fv ; i <= MIN(fv + vlc, fv + lc - 1) ; i++ ) { EDIT_GetLineRect(wndPtr, i, 0, -1, &rcLine); if (IntersectRect16(&rc, &rcRgn, &rcLine)) EDIT_PaintLine(wndPtr, hdc, i, rev); } if (hFont) SelectObject(hdc, oldFont); EndPaint16(wndPtr->hwndSelf, &ps); return 0L; } /********************************************************************* * * WM_PASTE * */ static LRESULT EDIT_WM_Paste(WND *wndPtr, WPARAM wParam, LPARAM lParam) { HGLOBAL16 hsrc; char *src; OpenClipboard(wndPtr->hwndSelf); if ((hsrc = GetClipboardData(CF_TEXT))) { src = (char *)GlobalLock16(hsrc); EDIT_ReplaceSel(wndPtr, 0, (LPARAM)src); GlobalUnlock16(hsrc); } CloseClipboard(); return -1L; } /********************************************************************* * * WM_SETCURSOR * */ static LRESULT EDIT_WM_SetCursor(WND *wndPtr, WPARAM wParam, LPARAM lParam) { if (LOWORD(lParam) == HTCLIENT) { SetCursor(LoadCursor16(0, IDC_IBEAM)); return -1L; } else return 0L; } /********************************************************************* * * WM_SETFOCUS * */ static LRESULT EDIT_WM_SetFocus(WND *wndPtr, WPARAM wParam, LPARAM lParam) { UINT s = LOWORD(EDIT_EM_GetSel(wndPtr, 0, 0L)); UINT e = HIWORD(EDIT_EM_GetSel(wndPtr, 0, 0L)); CreateCaret(wndPtr->hwndSelf, 0, 2, EDIT_GetLineHeight(wndPtr)); EDIT_EM_SetSel(wndPtr, 1, MAKELPARAM(s, e)); if(!(wndPtr->dwStyle & ES_NOHIDESEL)) EDIT_InvalidateText(wndPtr, s, e); ShowCaret(wndPtr->hwndSelf); EDIT_NOTIFY_PARENT(wndPtr, EN_SETFOCUS); return 0L; } /********************************************************************* * * WM_SETFONT * */ static LRESULT EDIT_WM_SetFont(WND *wndPtr, WPARAM wParam, LPARAM lParam) { TEXTMETRIC16 tm; EDITSTATE *es = EDITSTATEPTR(wndPtr); LPARAM sel = EDIT_EM_GetSel(wndPtr, 0, 0L); HDC32 hdc; HFONT oldFont = 0; es->hFont = (HFONT)wParam; hdc = GetDC32(wndPtr->hwndSelf); if (es->hFont) oldFont = SelectObject(hdc, es->hFont); GetTextMetrics16(hdc, &tm); es->LineHeight = HIWORD(GetTextExtent(hdc, "X", 1)); es->AveCharWidth = tm.tmAveCharWidth; if (es->hFont) SelectObject(hdc, oldFont); ReleaseDC32(wndPtr->hwndSelf, hdc); EDIT_BuildLineDefs(wndPtr); if ((BOOL)lParam && EDIT_GetRedraw(wndPtr)) InvalidateRect32( wndPtr->hwndSelf, NULL, TRUE ); if (wndPtr->hwndSelf == GetFocus32()) { DestroyCaret(); CreateCaret(wndPtr->hwndSelf, 0, 2, EDIT_GetLineHeight(wndPtr)); EDIT_EM_SetSel(wndPtr, 1, sel); ShowCaret(wndPtr->hwndSelf); } return 0L; } /********************************************************************* * * WM_SETREDRAW * */ static LRESULT EDIT_WM_SetRedraw(WND *wndPtr, WPARAM wParam, LPARAM lParam) { EDITSTATE *es = EDITSTATEPTR(wndPtr); es->Redraw = (BOOL)wParam; return 0L; } /********************************************************************* * * WM_SETTEXT * */ static LRESULT EDIT_WM_SetText(WND *wndPtr, WPARAM wParam, LPARAM lParam) { EDIT_EM_SetSel(wndPtr, 1, MAKELPARAM(0, -1)); EDIT_WM_Clear(wndPtr, 0, 0L); if (lParam) EDIT_EM_ReplaceSel(wndPtr, 0, lParam); EDIT_EM_EmptyUndoBuffer(wndPtr, 0, 0L); EDIT_EM_SetModify(wndPtr, TRUE, 0L); EDIT_ScrollIntoView(wndPtr); return 0L; } /********************************************************************* * * WM_SIZE * */ static LRESULT EDIT_WM_Size(WND *wndPtr, WPARAM wParam, LPARAM lParam) { if (EDIT_GetRedraw(wndPtr) && ((wParam == SIZE_MAXIMIZED) || (wParam == SIZE_RESTORED))) { if (IsMultiLine(wndPtr) && IsWordWrap(wndPtr)) EDIT_BuildLineDefs(wndPtr); InvalidateRect32( wndPtr->hwndSelf, NULL, TRUE ); } return 0L; } /********************************************************************* * * WM_VSCROLL * * FIXME: scrollbar code itself is broken, so this one is a hack. * */ static LRESULT EDIT_WM_VScroll(WND *wndPtr, WPARAM wParam, LPARAM lParam) { UINT lc = (UINT)EDIT_EM_GetLineCount(wndPtr, 0, 0L); UINT fv = (UINT)EDIT_EM_GetFirstVisibleLine(wndPtr, 0, 0L); UINT vlc = EDIT_GetVisibleLineCount(wndPtr); INT dy = 0; BOOL not = TRUE; LRESULT ret = 0L; switch (wParam) { case SB_LINEUP: dy = -1; break; case SB_LINEDOWN: dy = 1; break; case SB_PAGEUP: dy = -vlc; break; case SB_PAGEDOWN: dy = vlc; break; case SB_TOP: dy = -fv; break; case SB_BOTTOM: dy = lc - 1 - fv; break; case SB_THUMBTRACK: /* * not = FALSE; */ case SB_THUMBPOSITION: dy = LOWORD(lParam) * (lc - 1) / 100 - fv; break; /* The next two are undocumented ! */ case EM_GETTHUMB: ret = (lc > 1) ? MAKELONG(fv * 100 / (lc - 1), 0) : 0L; break; case EM_LINESCROLL: dy = LOWORD(lParam); break; case SB_ENDSCROLL: default: break; } if (dy) { EDIT_EM_LineScroll(wndPtr, 0, MAKELPARAM(dy, 0)); if (not) EDIT_NOTIFY_PARENT(wndPtr, EN_VSCROLL); } return ret; }