Release 940815
[wine/gsoc-2012-control.git] / controls / edit.c
blobbcbe8f28fc618ed082407113bfab24ca1c576945
1 /*
2 * Edit control
4 * Copyright David W. Metcalfe, 1994
6 * Release 3, July 1994
7 */
9 static char Copyright[] = "Copyright David W. Metcalfe, 1994";
11 #include <stdlib.h>
12 #include <string.h>
13 #include <windows.h>
14 #include <heap.h>
15 #include "win.h"
16 #include "class.h"
17 #include "user.h"
18 #include "scroll.h"
20 /* #define DEBUG_EDIT /* */
22 #define NOTIFY_PARENT(hWndCntrl, wNotifyCode) \
23 SendMessage(GetParent(hWndCntrl), WM_COMMAND, \
24 GetDlgCtrlID(hWndCntrl), MAKELPARAM(hWndCntrl, wNotifyCode));
26 #define MAXTEXTLEN 30000 /* maximum text buffer length */
27 #define EDITLEN 1024 /* starting length for multi-line control */
28 #define ENTRYLEN 256 /* starting length for single line control */
29 #define GROWLENGTH 64 /* buffers grow by this much */
31 #define HSCROLLDIM (ClientWidth(wndPtr) / 3)
32 /* "line" dimension for horizontal scroll */
34 typedef struct
36 int wlines; /* number of lines of text */
37 int wtop; /* top line that is displayed */
38 int wleft; /* left pixel that is displayed */
39 unsigned int textlen; /* text buffer length */
40 int textwidth; /* width of longest line in pixels */
41 RECT fmtrc; /* rectangle in which to format text */
42 int txtht; /* height of text line in pixels */
43 HANDLE hText; /* handle to text buffer */
44 HANDLE hCharWidths; /* widths of chars in font */
45 HANDLE hTextPtrs; /* list of line offsets */
46 HANDLE hBlankLine; /* to fill blank lines quickly */
47 int CurrCol; /* current column */
48 int CurrLine; /* current line */
49 int WndCol; /* current window column */
50 int WndRow; /* current window row */
51 BOOL TextChanged; /* TRUE if text has changed */
52 BOOL PaintBkgd; /* paint control background */
53 unsigned int MaxTextLen; /* maximum text buffer length */
54 int SelBegLine; /* beginning line of selection */
55 int SelBegCol; /* beginning column of selection */
56 int SelEndLine; /* ending line of selection */
57 int SelEndCol; /* ending column of selection */
58 HFONT hFont; /* handle of current font (if not default) */
59 HANDLE hDeletedText; /* handle to deleted txet buffer for undo */
60 int DeletedLength; /* length of deleted text */
61 int DeletedCurrLine; /* starting line from which text was deleted */
62 int DeletedCurrCol; /* starting col from which text was deleted */
63 int NumTabStops; /* number of tab stops in buffer hTabStops */
64 HANDLE hTabStops; /* handle of tab stops buffer */
65 } EDITSTATE;
68 #define ClientWidth(wndPtr) (wndPtr->rectClient.right - \
69 wndPtr->rectClient.left)
70 #define ClientHeight(wndPtr, es) ((wndPtr->rectClient.bottom - \
71 wndPtr->rectClient.top) / es->txtht)
72 #define EditBufLen(wndPtr) (wndPtr->dwStyle & ES_MULTILINE \
73 ? EDITLEN : ENTRYLEN)
74 #define CurrChar (EDIT_TextLine(hwnd, es->CurrLine) + es->CurrCol)
75 #define SelMarked(es) (es->SelBegLine != 0 || es->SelBegCol != 0 || \
76 es->SelEndLine != 0 || es->SelEndCol != 0)
77 #define ROUNDUP(numer, denom) (((numer) % (denom)) \
78 ? ((((numer) + (denom)) / (denom)) * (denom)) \
79 : (numer) + (denom))
81 /* macros to access window styles */
82 #define IsAutoVScroll() (wndPtr->dwStyle & ES_AUTOVSCROLL)
83 #define IsAutoHScroll() (wndPtr->dwStyle & ES_AUTOHSCROLL)
84 #define IsMultiLine() (wndPtr->dwStyle & ES_MULTILINE)
85 #define IsVScrollBar() (wndPtr->dwStyle & WS_VSCROLL)
86 #define IsHScrollBar() (wndPtr->dwStyle & WS_HSCROLL)
88 /* internal variables */
89 static BOOL TextMarking; /* TRUE if text marking in progress */
90 static BOOL ButtonDown; /* TRUE if left mouse button down */
91 static int ButtonRow; /* row in text buffer when button pressed */
92 static int ButtonCol; /* col in text buffer when button pressed */
93 static BOOL Print = FALSE;
96 LONG EditWndProc(HWND hWnd, WORD uMsg, WORD wParam, LONG lParam);
97 long EDIT_NCCreateMsg(HWND hwnd, LONG lParam);
98 long EDIT_CreateMsg(HWND hwnd, LONG lParam);
99 void EDIT_ClearTextPointers(HWND hwnd);
100 void EDIT_BuildTextPointers(HWND hwnd);
101 void EDIT_ModTextPointers(HWND hwnd, int lineno, int var);
102 void EDIT_PaintMsg(HWND hwnd);
103 HANDLE EDIT_GetTextLine(HWND hwnd, int selection);
104 char *EDIT_TextLine(HWND hwnd, int sel);
105 int EDIT_StrLength(HWND hwnd, char *str, int len, int pcol);
106 int EDIT_LineLength(HWND hwnd, int num);
107 void EDIT_WriteTextLine(HWND hwnd, RECT *rc, int y);
108 void EDIT_WriteText(HWND hwnd, char *lp, int off, int len, int row,
109 int col, RECT *rc, BOOL blank, BOOL reverse);
110 HANDLE EDIT_GetStr(HWND hwnd, char *lp, int off, int len, int *diff);
111 void EDIT_CharMsg(HWND hwnd, WORD wParam);
112 void EDIT_KeyTyped(HWND hwnd, short ch);
113 int EDIT_CharWidth(HWND hwnd, short ch, int pcol);
114 int EDIT_GetNextTabStop(HWND hwnd, int pcol);
115 void EDIT_Forward(HWND hwnd);
116 void EDIT_Downward(HWND hwnd);
117 void EDIT_Upward(HWND hwnd);
118 void EDIT_Backward(HWND hwnd);
119 void EDIT_End(HWND hwnd);
120 void EDIT_Home(HWND hwnd);
121 void EDIT_StickEnd(HWND hwnd);
122 void EDIT_KeyDownMsg(HWND hwnd, WORD wParam);
123 void EDIT_KeyHScroll(HWND hwnd, WORD opt);
124 void EDIT_KeyVScrollLine(HWND hwnd, WORD opt);
125 void EDIT_KeyVScrollPage(HWND hwnd, WORD opt);
126 void EDIT_KeyVScrollDoc(HWND hwnd, WORD opt);
127 int EDIT_ComputeVScrollPos(HWND hwnd);
128 int EDIT_ComputeHScrollPos(HWND hwnd);
129 void EDIT_DelKey(HWND hwnd);
130 void EDIT_VScrollMsg(HWND hwnd, WORD wParam, LONG lParam);
131 void EDIT_VScrollLine(HWND hwnd, WORD opt);
132 void EDIT_VScrollPage(HWND hwnd, WORD opt);
133 void EDIT_HScrollMsg(HWND hwnd, WORD wParam, LONG lParam);
134 void EDIT_SizeMsg(HWND hwnd, WORD wParam, LONG lParam);
135 void EDIT_LButtonDownMsg(HWND hwnd, WORD wParam, LONG lParam);
136 void EDIT_MouseMoveMsg(HWND hwnd, WORD wParam, LONG lParam);
137 int EDIT_PixelToChar(HWND hwnd, int row, int *pixel);
138 LONG EDIT_SetTextMsg(HWND hwnd, LONG lParam);
139 void EDIT_ClearText(HWND hwnd);
140 void EDIT_SetSelMsg(HWND hwnd, WORD wParam, LONG lParam);
141 void EDIT_GetLineCol(HWND hwnd, int off, int *line, int *col);
142 void EDIT_DeleteSel(HWND hwnd);
143 void EDIT_ClearSel(HWND hwnd);
144 int EDIT_TextLineNumber(HWND hwnd, char *lp);
145 void EDIT_SetAnchor(HWND hwnd, int row, int col);
146 void EDIT_ExtendSel(HWND hwnd, int x, int y);
147 void EDIT_WriteSel(HWND hwnd, int y, int start, int end);
148 void EDIT_StopMarking(HWND hwnd);
149 LONG EDIT_GetLineMsg(HWND hwnd, WORD wParam, LONG lParam);
150 LONG EDIT_GetSelMsg(HWND hwnd);
151 void EDIT_ReplaceSel(HWND hwnd, LONG lParam);
152 void EDIT_InsertText(HWND hwnd, char *str, int len);
153 LONG EDIT_LineFromCharMsg(HWND hwnd, WORD wParam);
154 LONG EDIT_LineIndexMsg(HWND hwnd, WORD wParam);
155 LONG EDIT_LineLengthMsg(HWND hwnd, WORD wParam);
156 void EDIT_SetFont(HWND hwnd, WORD wParam, LONG lParam);
157 void EDIT_SaveDeletedText(HWND hwnd, char *deltext, int len, int line,
158 int col);
159 void EDIT_ClearDeletedText(HWND hwnd);
160 LONG EDIT_UndoMsg(HWND hwnd);
161 unsigned int EDIT_HeapAlloc(HWND hwnd, int bytes);
162 void *EDIT_HeapAddr(HWND hwnd, unsigned int handle);
163 unsigned int EDIT_HeapReAlloc(HWND hwnd, unsigned int handle, int bytes);
164 void EDIT_HeapFree(HWND hwnd, unsigned int handle);
165 unsigned int EDIT_HeapSize(HWND hwnd, unsigned int handle);
166 void EDIT_SetHandleMsg(HWND hwnd, WORD wParam);
167 LONG EDIT_SetTabStopsMsg(HWND hwnd, WORD wParam, LONG lParam);
168 void EDIT_CopyToClipboard(HWND hwnd);
169 void EDIT_PasteMsg(HWND hwnd);
170 void swap(int *a, int *b);
173 LONG EditWndProc(HWND hwnd, WORD uMsg, WORD wParam, LONG lParam)
175 LONG lResult = 0L;
176 HDC hdc;
177 char *textPtr;
178 int len;
179 WND *wndPtr = WIN_FindWndPtr(hwnd);
180 EDITSTATE *es =
181 (EDITSTATE *)EDIT_HeapAddr(hwnd, (HANDLE)(*(wndPtr->wExtra)));
183 switch (uMsg) {
184 case EM_CANUNDO:
185 lResult = es->hDeletedText;
186 break;
188 case EM_EMPTYUNDOBUFFER:
189 EDIT_ClearDeletedText(hwnd);
190 break;
192 case EM_FMTLINES:
193 printf("edit: EM_FMTLINES message received\n");
194 if (!wParam)
195 lResult = 1L;
196 else
197 lResult = 0L;
198 break;
200 case EM_GETFIRSTVISIBLELINE:
201 lResult = es->wtop;
202 break;
204 case EM_GETHANDLE:
205 lResult = es->hText;
206 break;
208 case EM_GETLINE:
209 if (IsMultiLine())
210 lResult = EDIT_GetLineMsg(hwnd, wParam, lParam);
211 else
212 lResult = 0L;
213 break;
215 case EM_GETLINECOUNT:
216 if (IsMultiLine())
217 lResult = es->wlines;
218 else
219 lResult = 0L;
220 break;
222 case EM_GETMODIFY:
223 lResult = es->TextChanged;
224 break;
226 case EM_GETPASSWORDCHAR:
227 printf("edit: cannot process EM_GETPASSWORDCHAR message\n");
228 break;
230 case EM_GETRECT:
231 GetWindowRect(hwnd, (LPRECT)lParam);
232 break;
234 case EM_GETSEL:
235 lResult = EDIT_GetSelMsg(hwnd);
236 break;
238 case EM_GETWORDBREAKPROC:
239 printf("edit: cannot process EM_GETWORDBREAKPROC message\n");
240 break;
242 case EM_LIMITTEXT:
243 if (wParam)
244 es->MaxTextLen = wParam;
245 else if (IsMultiLine())
246 es->MaxTextLen = 65535;
247 else
248 es->MaxTextLen = 32767;
249 break;
251 case EM_LINEFROMCHAR:
252 lResult = EDIT_LineFromCharMsg(hwnd, wParam);
253 break;
255 case EM_LINEINDEX:
256 if (IsMultiLine())
257 lResult = EDIT_LineIndexMsg(hwnd, wParam);
258 else
259 lResult = 0L;
260 break;
262 case EM_LINELENGTH:
263 lResult = EDIT_LineLengthMsg(hwnd, wParam);
264 break;
266 case EM_LINESCROLL:
267 printf("edit: cannot process EM_LINESCROLL message\n");
268 break;
270 case EM_REPLACESEL:
271 HideCaret(hwnd);
272 EDIT_ReplaceSel(hwnd, lParam);
273 SetCaretPos(es->WndCol, es->WndRow * es->txtht);
274 ShowCaret(hwnd);
275 break;
277 case EM_SETHANDLE:
278 EDIT_SetHandleMsg(hwnd, wParam);
279 break;
281 case EM_SETMODIFY:
282 es->TextChanged = wParam;
283 break;
285 case EM_SETPASSWORDCHAR:
286 printf("edit: cannot process EM_SETPASSWORDCHAR message\n");
287 break;
289 case EM_SETREADONLY:
290 printf("edit: cannot process EM_SETREADONLY message\n");
291 break;
293 case EM_SETRECT:
294 case EM_SETRECTNP:
295 printf("edit: cannot process EM_SETRECT(NP) message\n");
296 break;
298 case EM_SETSEL:
299 HideCaret(hwnd);
300 EDIT_SetSelMsg(hwnd, wParam, lParam);
301 SetCaretPos(es->WndCol, es->WndRow * es->txtht);
302 ShowCaret(hwnd);
303 break;
305 case EM_SETTABSTOPS:
306 lResult = EDIT_SetTabStopsMsg(hwnd, wParam, lParam);
307 break;
309 case EM_SETWORDBREAKPROC:
310 printf("edit: cannot process EM_SETWORDBREAKPROC message\n");
311 break;
313 case EM_UNDO:
314 HideCaret(hwnd);
315 lResult = EDIT_UndoMsg(hwnd);
316 SetCaretPos(es->WndCol, es->WndRow * es->txtht);
317 ShowCaret(hwnd);
318 break;
320 case WM_CHAR:
321 EDIT_CharMsg(hwnd, wParam);
322 break;
324 case WM_COPY:
325 EDIT_CopyToClipboard(hwnd);
326 EDIT_ClearSel(hwnd);
327 break;
329 case WM_CREATE:
330 lResult = EDIT_CreateMsg(hwnd, lParam);
331 break;
333 case WM_CUT:
334 EDIT_CopyToClipboard(hwnd);
335 EDIT_DeleteSel(hwnd);
336 break;
338 case WM_DESTROY:
339 EDIT_HeapFree(hwnd, es->hTextPtrs);
340 EDIT_HeapFree(hwnd, es->hCharWidths);
341 EDIT_HeapFree(hwnd, es->hText);
342 EDIT_HeapFree(hwnd, (HANDLE)(*(wndPtr->wExtra)));
343 break;
345 case WM_ENABLE:
346 InvalidateRect(hwnd, NULL, FALSE);
347 break;
349 case WM_GETTEXT:
350 textPtr = EDIT_HeapAddr(hwnd, es->hText);
351 if ((int)wParam > (len = strlen(textPtr)))
353 strcpy((char *)lParam, textPtr);
354 lResult = (DWORD)len;
356 else
357 lResult = 0L;
358 break;
360 case WM_GETTEXTLENGTH:
361 textPtr = EDIT_HeapAddr(hwnd, es->hText);
362 lResult = (DWORD)strlen(textPtr);
363 break;
365 case WM_HSCROLL:
366 EDIT_HScrollMsg(hwnd, wParam, lParam);
367 break;
369 case WM_KEYDOWN:
370 EDIT_KeyDownMsg(hwnd, wParam);
371 break;
373 case WM_KILLFOCUS:
374 DestroyCaret();
375 NOTIFY_PARENT(hwnd, EN_KILLFOCUS);
376 break;
378 case WM_LBUTTONDOWN:
379 HideCaret(hwnd);
380 SetFocus(hwnd);
381 EDIT_LButtonDownMsg(hwnd, wParam, lParam);
382 SetCaretPos(es->WndCol, es->WndRow * es->txtht);
383 ShowCaret(hwnd);
384 break;
386 case WM_LBUTTONUP:
387 ButtonDown = FALSE;
388 if (TextMarking)
389 EDIT_StopMarking(hwnd);
390 break;
392 case WM_MOUSEMOVE:
393 HideCaret(hwnd);
394 EDIT_MouseMoveMsg(hwnd, wParam, lParam);
395 SetCaretPos(es->WndCol, es->WndRow * es->txtht);
396 ShowCaret(hwnd);
397 break;
399 case WM_MOVE:
400 lResult = 0;
401 break;
403 case WM_NCCREATE:
404 lResult = EDIT_NCCreateMsg(hwnd, lParam);
405 break;
407 case WM_PAINT:
408 EDIT_PaintMsg(hwnd);
409 break;
411 case WM_PASTE:
412 EDIT_PasteMsg(hwnd);
413 break;
415 case WM_SETFOCUS:
416 CreateCaret(hwnd, 0, 2, es->txtht);
417 SetCaretPos(es->WndCol, es->WndRow * es->txtht);
418 ShowCaret(hwnd);
419 NOTIFY_PARENT(hwnd, EN_SETFOCUS);
420 break;
422 case WM_SETFONT:
423 HideCaret(hwnd);
424 EDIT_SetFont(hwnd, wParam, lParam);
425 SetCaretPos(es->WndCol, es->WndRow * es->txtht);
426 ShowCaret(hwnd);
427 break;
429 case WM_SETTEXT:
430 EDIT_SetTextMsg(hwnd, lParam);
431 break;
433 case WM_SIZE:
434 EDIT_SizeMsg(hwnd, wParam, lParam);
435 lResult = 0;
436 break;
438 case WM_VSCROLL:
439 EDIT_VScrollMsg(hwnd, wParam, lParam);
440 break;
442 default:
443 lResult = DefWindowProc(hwnd, uMsg, wParam, lParam);
444 break;
447 return lResult;
451 /*********************************************************************
452 * WM_NCCREATE message function
455 long EDIT_NCCreateMsg(HWND hwnd, LONG lParam)
457 CREATESTRUCT *createStruct = (CREATESTRUCT *)lParam;
458 WND *wndPtr = WIN_FindWndPtr(hwnd);
459 EDITSTATE *es;
460 unsigned int *textPtrs;
461 char *text;
462 int len;
464 /* store pointer to local heap in window structure so that */
465 /* EDITSTATE structure itself can be stored on local heap */
466 (MDESC **)*(LONG *)(wndPtr->wExtra + 2) =
467 &HEAP_LocalFindHeap(createStruct->hInstance)->free_list;
469 /* allocate space for state variable structure */
470 (HANDLE)(*(wndPtr->wExtra)) = EDIT_HeapAlloc(hwnd, sizeof(EDITSTATE));
471 es = (EDITSTATE *)EDIT_HeapAddr(hwnd, (HANDLE)(*(wndPtr->wExtra)));
472 es->hTextPtrs = EDIT_HeapAlloc(hwnd, sizeof(int));
473 textPtrs = (unsigned int *)EDIT_HeapAddr(hwnd, es->hTextPtrs);
474 es->hCharWidths = EDIT_HeapAlloc(hwnd, 256 * sizeof(short));
476 /* --- text buffer */
477 es->MaxTextLen = MAXTEXTLEN + 1;
478 if (!(createStruct->lpszName))
480 es->textlen = EditBufLen(wndPtr) + 1;
481 es->hText = EDIT_HeapAlloc(hwnd, EditBufLen(wndPtr) + 2);
482 text = EDIT_HeapAddr(hwnd, es->hText);
483 memset(text, 0, es->textlen + 2);
484 EDIT_ClearTextPointers(hwnd);
486 else
488 if (strlen(createStruct->lpszName) < EditBufLen(wndPtr))
490 es->textlen = EditBufLen(wndPtr) + 1;
491 es->hText = EDIT_HeapAlloc(hwnd, EditBufLen(wndPtr) + 2);
492 text = EDIT_HeapAddr(hwnd, es->hText);
493 strcpy(text, createStruct->lpszName);
494 *(text + es->textlen) = '\0';
496 else
498 es->hText = EDIT_HeapAlloc(hwnd,
499 strlen(createStruct->lpszName) + 2);
500 text = EDIT_HeapAddr(hwnd, es->hText);
501 strcpy(text, createStruct->lpszName);
502 es->textlen = strlen(createStruct->lpszName) + 1;
504 *(text + es->textlen + 1) = '\0';
505 EDIT_BuildTextPointers(hwnd);
508 if ((createStruct->style & WS_VSCROLL) ||
509 (createStruct->style & WS_HSCROLL)) NC_CreateScrollBars(hwnd);
511 /* ES_AUTOVSCROLL and ES_AUTOHSCROLL are automatically applied if */
512 /* the corresponding WM_* message is set */
513 if (createStruct->style & WS_VSCROLL)
514 wndPtr->dwStyle |= ES_AUTOVSCROLL;
515 if (createStruct->style & WS_HSCROLL)
516 wndPtr->dwStyle |= ES_AUTOHSCROLL;
518 /* remove the WS_CAPTION style if it has been set - this is really a */
519 /* pseudo option made from a combination of WS_BORDER and WS_DLGFRAME */
520 if (wndPtr->dwStyle & WS_BORDER && wndPtr->dwStyle & WS_DLGFRAME)
521 wndPtr->dwStyle ^= WS_DLGFRAME;
523 return 1;
527 /*********************************************************************
528 * WM_CREATE message function
531 long EDIT_CreateMsg(HWND hwnd, LONG lParam)
533 HDC hdc;
534 WND *wndPtr = WIN_FindWndPtr(hwnd);
535 EDITSTATE *es =
536 (EDITSTATE *)EDIT_HeapAddr(hwnd, (HANDLE)(*(wndPtr->wExtra)));
537 CLASS *classPtr;
538 short *charWidths;
539 TEXTMETRIC tm;
540 char *text;
542 /* initialize state variable structure */
543 /* --- char width array */
544 hdc = GetDC(hwnd);
545 charWidths = (short *)EDIT_HeapAddr(hwnd, es->hCharWidths);
546 memset(charWidths, 0, 256 * sizeof(short));
547 GetCharWidth(hdc, 0, 255, charWidths);
549 /* --- other structure variables */
550 GetTextMetrics(hdc, &tm);
551 es->txtht = tm.tmHeight + tm.tmExternalLeading;
552 es->wlines = 0;
553 es->wtop = es->wleft = 0;
554 es->CurrCol = es->CurrLine = 0;
555 es->WndCol = es->WndRow = 0;
556 es->TextChanged = FALSE;
557 es->textwidth = 0;
558 es->SelBegLine = es->SelBegCol = 0;
559 es->SelEndLine = es->SelEndCol = 0;
560 es->hFont = 0;
561 es->hDeletedText = 0;
562 es->DeletedLength = 0;
563 es->NumTabStops = 0;
564 es->hTabStops = EDIT_HeapAlloc(hwnd, sizeof(int));
566 /* allocate space for a line full of blanks to speed up */
567 /* line filling */
568 es->hBlankLine = EDIT_HeapAlloc(hwnd, (ClientWidth(wndPtr) /
569 charWidths[32]) + 2);
570 text = EDIT_HeapAddr(hwnd, es->hBlankLine);
571 memset(text, ' ', (ClientWidth(wndPtr) / charWidths[32]) + 2);
573 /* set up text cursor for edit class */
574 CLASS_FindClassByName("EDIT", &classPtr);
575 classPtr->wc.hCursor = LoadCursor(0, IDC_IBEAM);
577 /* paint background on first WM_PAINT */
578 es->PaintBkgd = TRUE;
580 ReleaseDC(hwnd, hdc);
581 return 0L;
585 /*********************************************************************
586 * EDIT_ClearTextPointers
588 * Clear and initialize text line pointer array.
591 void EDIT_ClearTextPointers(HWND hwnd)
593 unsigned int *textPtrs;
594 WND *wndPtr = WIN_FindWndPtr(hwnd);
595 EDITSTATE *es =
596 (EDITSTATE *)EDIT_HeapAddr(hwnd, (HANDLE)(*(wndPtr->wExtra)));
598 es->hTextPtrs = EDIT_HeapReAlloc(hwnd, es->hTextPtrs, sizeof(int));
599 textPtrs = (unsigned int *)EDIT_HeapAddr(hwnd, es->hTextPtrs);
600 *textPtrs = 0;
604 /*********************************************************************
605 * EDIT_BuildTextPointers
607 * Build array of pointers to text lines.
610 #define INITLINES 100
612 void EDIT_BuildTextPointers(HWND hwnd)
614 WND *wndPtr = WIN_FindWndPtr(hwnd);
615 char *text, *cp;
616 int incrs = INITLINES;
617 unsigned int off, len, temp;
618 EDITSTATE *es;
619 unsigned int *textPtrs;
620 short *charWidths;
622 es = (EDITSTATE *)EDIT_HeapAddr(hwnd, (HANDLE)(*(wndPtr->wExtra)));
623 text = EDIT_HeapAddr(hwnd, es->hText);
624 textPtrs = (unsigned int *)EDIT_HeapAddr(hwnd, es->hTextPtrs);
625 charWidths = (short *)EDIT_HeapAddr(hwnd, es->hCharWidths);
627 es->textwidth = es->wlines = 0;
628 cp = text;
630 /* advance through text buffer */
631 while (*cp)
633 /* increase size of text pointer array */
634 if (incrs == INITLINES)
636 incrs = 0;
637 es->hTextPtrs = EDIT_HeapReAlloc(hwnd, es->hTextPtrs,
638 (es->wlines + INITLINES) * sizeof(int));
639 textPtrs = (unsigned int *)EDIT_HeapAddr(hwnd, es->hTextPtrs);
641 off = (unsigned int)(cp - text); /* offset of beginning of line */
642 *(textPtrs + es->wlines) = off;
643 es->wlines++;
644 incrs++;
645 len = 0;
647 /* advance through current line */
648 while (*cp && *cp != '\n')
650 len += EDIT_CharWidth(hwnd, *cp, len);
651 /* width of line in pixels */
652 cp++;
654 es->textwidth = max(es->textwidth, len);
655 if (*cp)
656 cp++; /* skip '\n' */
659 off = (unsigned int)(cp - text);
660 *(textPtrs + es->wlines) = off;
664 /*********************************************************************
665 * EDIT_ModTextPointers
667 * Modify text pointers from a specified position.
670 void EDIT_ModTextPointers(HWND hwnd, int lineno, int var)
672 WND *wndPtr = WIN_FindWndPtr(hwnd);
673 EDITSTATE *es =
674 (EDITSTATE *)EDIT_HeapAddr(hwnd, (HANDLE)(*(wndPtr->wExtra)));
675 unsigned int *textPtrs =
676 (unsigned int *)EDIT_HeapAddr(hwnd, es->hTextPtrs);
678 while (lineno < es->wlines)
679 *(textPtrs + lineno++) += var;
683 /*********************************************************************
684 * WM_PAINT message function
687 void EDIT_PaintMsg(HWND hwnd)
689 PAINTSTRUCT ps;
690 HDC hdc;
691 int y;
692 RECT rc;
693 WND *wndPtr = WIN_FindWndPtr(hwnd);
694 EDITSTATE *es =
695 (EDITSTATE *)EDIT_HeapAddr(hwnd, (HANDLE)(*(wndPtr->wExtra)));
697 hdc = BeginPaint(hwnd, &ps);
698 rc = ps.rcPaint;
700 #ifdef DEBUG_EDIT
701 printf("WM_PAINT: rc=(%d,%d), (%d,%d)\n", rc.left, rc.top,
702 rc.right, rc.bottom);
703 #endif
705 if (es->PaintBkgd)
706 FillWindow(GetParent(hwnd), hwnd, hdc, CTLCOLOR_EDIT);
708 for (y = (rc.top / es->txtht); y <= (rc.bottom / es->txtht); y++)
710 if (y < es->wlines - es->wtop)
711 EDIT_WriteTextLine(hwnd, &rc, y + es->wtop);
714 EndPaint(hwnd, &ps);
718 /*********************************************************************
719 * EDIT_GetTextLine
721 * Get a copy of the text in the specified line.
724 HANDLE EDIT_GetTextLine(HWND hwnd, int selection)
726 char *line;
727 HANDLE hLine;
728 int len = 0;
729 char *cp, *cp1;
731 #ifdef DEBUG_EDIT
732 printf("GetTextLine %d\n", selection);
733 #endif
734 cp = cp1 = EDIT_TextLine(hwnd, selection);
735 /* advance through line */
736 while (*cp && *cp != '\n')
738 len++;
739 cp++;
742 /* store selected line and return handle */
743 hLine = EDIT_HeapAlloc(hwnd, len + 6);
744 line = (char *)EDIT_HeapAddr(hwnd, hLine);
745 memmove(line, cp1, len);
746 line[len] = '\0';
747 return hLine;
751 /*********************************************************************
752 * EDIT_TextLine
754 * Return a pointer to the text in the specified line.
757 char *EDIT_TextLine(HWND hwnd, int sel)
759 WND *wndPtr = WIN_FindWndPtr(hwnd);
760 EDITSTATE *es =
761 (EDITSTATE *)EDIT_HeapAddr(hwnd, (HANDLE)(*(wndPtr->wExtra)));
762 char *text = EDIT_HeapAddr(hwnd, es->hText);
763 unsigned int *textPtrs =
764 (unsigned int *)EDIT_HeapAddr(hwnd, es->hTextPtrs);
766 return (text + *(textPtrs + sel));
770 /*********************************************************************
771 * EDIT_StrLength
773 * Return length of string _str_ of length _len_ characters in pixels.
774 * The current column offset in pixels _pcol_ is required to calculate
775 * the width of a tab.
778 int EDIT_StrLength(HWND hwnd, char *str, int len, int pcol)
780 int i, plen = 0;
781 WND *wndPtr = WIN_FindWndPtr(hwnd);
782 EDITSTATE *es =
783 (EDITSTATE *)EDIT_HeapAddr(hwnd, (HANDLE)(*(wndPtr->wExtra)));
785 for (i = 0; i < len; i++)
786 plen += EDIT_CharWidth(hwnd, *(str + i), pcol + plen);
788 #ifdef DEBUG_EDIT
789 printf("EDIT_StrLength: returning %d\n", plen);
790 #endif
791 return plen;
795 /*********************************************************************
796 * EDIT_LineLength
798 * Return length of line _num_ in characters.
801 int EDIT_LineLength(HWND hwnd, int num)
803 WND *wndPtr = WIN_FindWndPtr(hwnd);
804 EDITSTATE *es =
805 (EDITSTATE *)EDIT_HeapAddr(hwnd, (HANDLE)(*(wndPtr->wExtra)));
806 char *cp = EDIT_TextLine(hwnd, num);
807 char *cp1;
809 cp1 = strchr(cp, '\n');
810 return cp1 ? (int)(cp1 - cp) : strlen(cp);
814 /*********************************************************************
815 * EDIT_WriteTextLine
817 * Write the line of text at offset _y_ in text buffer to a window.
820 void EDIT_WriteTextLine(HWND hwnd, RECT *rect, int y)
822 int len = 0;
823 unsigned char line[200];
824 HANDLE hLine;
825 unsigned char *lp;
826 int lnlen, lnlen1;
827 int col, off = 0;
828 int sbl, sel, sbc, sec;
829 RECT rc;
830 BOOL trunc = FALSE;
831 WND *wndPtr = WIN_FindWndPtr(hwnd);
832 EDITSTATE *es =
833 (EDITSTATE *)EDIT_HeapAddr(hwnd, (HANDLE)(*(wndPtr->wExtra)));
835 /* initialize rectangle if NULL, else copy */
836 if (rect)
837 CopyRect(&rc, rect);
838 else
839 GetClientRect(hwnd, &rc);
841 #ifdef DEBUG_EDIT
842 printf("WriteTextLine %d\n", y);
843 #endif
845 /* make sure y is inside the window */
846 if (y < es->wtop || y > (es->wtop + ClientHeight(wndPtr, es)))
848 #ifdef DEBUG_EDIT
849 printf("EDIT_WriteTextLine: y (%d) is not a displayed line\n", y);
850 #endif
851 return;
854 /* make sure rectangle is within window */
855 if (rc.left >= ClientWidth(wndPtr) - 1)
857 #ifdef DEBUG_EDIT
858 printf("EDIT_WriteTextLine: rc.left (%d) is greater than right edge\n",
859 rc.left);
860 #endif
861 return;
863 if (rc.right <= 0)
865 #ifdef DEBUG_EDIT
866 printf("EDIT_WriteTextLine: rc.right (%d) is less than left edge\n",
867 rc.right);
868 #endif
869 return;
871 if (y - es->wtop < (rc.top / es->txtht) ||
872 y - es->wtop > (rc.bottom / es->txtht))
874 #ifdef DEBUG_EDIT
875 printf("EDIT_WriteTextLine: y (%d) is outside window\n", y);
876 #endif
877 return;
880 /* get the text and length of line */
881 if ((hLine = EDIT_GetTextLine(hwnd, y)) == 0)
882 return;
883 lp = (unsigned char *)EDIT_HeapAddr(hwnd, hLine);
884 lnlen = EDIT_StrLength(hwnd, lp, strlen(lp), 0);
885 lnlen1 = lnlen;
887 /* build the line to display */
888 if (lnlen < es->wleft)
889 lnlen = 0;
890 else
891 off += es->wleft;
893 if (lnlen > rc.left)
895 off += rc.left;
896 lnlen = lnlen1 - off;
897 len = min(lnlen, rc.right - rc.left);
900 if (SelMarked(es))
902 sbl = es->SelBegLine;
903 sel = es->SelEndLine;
904 sbc = es->SelBegCol;
905 sec = es->SelEndCol;
907 /* put lowest marker first */
908 if (sbl > sel)
910 swap(&sbl, &sel);
911 swap(&sbc, &sec);
913 if (sbl == sel && sbc > sec)
914 swap(&sbc, &sec);
916 if (y < sbl || y > sel)
917 EDIT_WriteText(hwnd, lp, off, len, y - es->wtop, rc.left, &rc,
918 TRUE, FALSE);
919 else if (y > sbl && y < sel)
920 EDIT_WriteText(hwnd, lp, off, len, y - es->wtop, rc.left, &rc,
921 TRUE, TRUE);
922 else if (y == sbl)
924 col = EDIT_StrLength(hwnd, lp, sbc, 0);
925 if (col > (es->wleft + rc.left))
927 len = min(col - off, rc.right - off);
928 EDIT_WriteText(hwnd, lp, off, len, y - es->wtop,
929 rc.left, &rc, FALSE, FALSE);
930 off = col;
932 if (y == sel)
934 col = EDIT_StrLength(hwnd, lp, sec, 0);
935 if (col < (es->wleft + rc.right))
937 len = min(col - off, rc.right - off);
938 EDIT_WriteText(hwnd, lp, off, len, y - es->wtop,
939 off - es->wleft, &rc, FALSE, TRUE);
940 off = col;
941 len = min(lnlen - off, rc.right - off);
942 EDIT_WriteText(hwnd, lp, off, len, y - es->wtop,
943 off - es->wleft, &rc, TRUE, FALSE);
945 else
947 len = min(lnlen - off, rc.right - off);
948 EDIT_WriteText(hwnd, lp, off, len, y - es->wtop,
949 off - es->wleft, &rc, TRUE, TRUE);
952 else
954 len = min(lnlen - off, rc.right - off);
955 if (col < (es->wleft + rc.right))
956 EDIT_WriteText(hwnd, lp, off, len, y - es->wtop,
957 off - es->wleft, &rc, TRUE, TRUE);
960 else if (y == sel)
962 col = EDIT_StrLength(hwnd, lp, sec, 0);
963 if (col < (es->wleft + rc.right))
965 len = min(col - off, rc.right - off);
966 EDIT_WriteText(hwnd, lp, off, len, y - es->wtop,
967 off - es->wleft, &rc, FALSE, TRUE);
968 off = col;
969 len = min(lnlen - off, rc.right - off);
970 EDIT_WriteText(hwnd, lp, off, len, y - es->wtop,
971 off - es->wleft, &rc, TRUE, FALSE);
975 else
976 EDIT_WriteText(hwnd, lp, off, len, y - es->wtop, rc.left, &rc,
977 TRUE, FALSE);
979 EDIT_HeapFree(hwnd, hLine);
983 /*********************************************************************
984 * EDIT_WriteText
986 * Write text to a window
987 * lp - text line
988 * off - offset in text line (in pixels)
989 * len - length from off (in pixels)
990 * row - line in window
991 * col - column in window
992 * rc - rectangle in which to display line
993 * blank - blank remainder of line?
994 * reverse - reverse color of line?
997 void EDIT_WriteText(HWND hwnd, char *lp, int off, int len, int row,
998 int col, RECT *rc, BOOL blank, BOOL reverse)
1000 HDC hdc;
1001 HANDLE hStr;
1002 char *str, *cp, *cp1;
1003 int diff, num_spaces, tabwidth, scol;
1004 HRGN hrgnClip;
1005 COLORREF oldTextColor, oldBkgdColor;
1006 HFONT oldfont;
1007 WND *wndPtr = WIN_FindWndPtr(hwnd);
1008 EDITSTATE *es =
1009 (EDITSTATE *)EDIT_HeapAddr(hwnd, (HANDLE)(*(wndPtr->wExtra)));
1010 short *charWidths = (short *)EDIT_HeapAddr(hwnd, es->hCharWidths);
1011 char *blanks = (char *)EDIT_HeapAddr(hwnd, es->hBlankLine);
1013 #ifdef DEBUG_EDIT
1014 printf("EDIT_WriteText lp=%s, off=%d, len=%d, row=%d, col=%d, reverse=%d\n", lp, off, len, row, col, reverse);
1015 #endif
1017 hdc = GetDC(hwnd);
1018 hStr = EDIT_GetStr(hwnd, lp, off, len, &diff);
1019 str = (char *)EDIT_HeapAddr(hwnd, hStr);
1020 hrgnClip = CreateRectRgnIndirect(rc);
1021 SelectClipRgn(hdc, hrgnClip);
1023 if (es->hFont)
1024 oldfont = (HFONT)SelectObject(hdc, (HANDLE)es->hFont);
1026 SendMessage(GetParent(hwnd), WM_CTLCOLOR, (WORD)hdc,
1027 MAKELPARAM(hwnd, CTLCOLOR_EDIT));
1029 if (reverse)
1031 oldBkgdColor = GetBkColor(hdc);
1032 oldTextColor = GetTextColor(hdc);
1033 SetBkColor(hdc, oldTextColor);
1034 SetTextColor(hdc, oldBkgdColor);
1037 if (strlen(blanks) < (ClientWidth(wndPtr) / charWidths[32]) + 2)
1039 es->hBlankLine = EDIT_HeapReAlloc(hwnd, es->hBlankLine,
1040 (ClientWidth(wndPtr) / charWidths[32]) + 2);
1041 blanks = EDIT_HeapAddr(hwnd, es->hBlankLine);
1042 memset(blanks, ' ', (ClientWidth(wndPtr) / charWidths[32]) + 2);
1045 if (!(cp = strchr(str, VK_TAB)))
1046 TextOut(hdc, col - diff, row * es->txtht, str, strlen(str));
1047 else
1049 TextOut(hdc, col - diff, row * es->txtht, str, (int)(cp - str));
1050 scol = EDIT_StrLength(hwnd, str, (int)(cp - str), 0);
1051 tabwidth = EDIT_CharWidth(hwnd, VK_TAB, scol);
1052 num_spaces = tabwidth / charWidths[32] + 1;
1053 TextOut(hdc, scol, row * es->txtht, blanks, num_spaces);
1054 cp++;
1055 scol += tabwidth;
1057 while (cp1 = strchr(cp, VK_TAB))
1059 TextOut(hdc, scol, row * es->txtht, cp, (int)(cp1 - cp));
1060 scol += EDIT_StrLength(hwnd, cp, (int)(cp1 - cp), scol);
1061 tabwidth = EDIT_CharWidth(hwnd, VK_TAB, scol);
1062 num_spaces = tabwidth / charWidths[32] + 1;
1063 TextOut(hdc, scol, row * es->txtht, blanks, num_spaces);
1064 cp = ++cp1;
1065 scol += tabwidth;
1068 TextOut(hdc, scol, row * es->txtht, cp, strlen(cp));
1071 if (reverse)
1073 SetBkColor(hdc, oldBkgdColor);
1074 SetTextColor(hdc, oldTextColor);
1077 /* blank out remainder of line if appropriate */
1078 if (blank)
1080 if ((rc->right - col) > len)
1082 num_spaces = (rc->right - col - len) / charWidths[32];
1083 TextOut(hdc, col + len, row * es->txtht, blanks, num_spaces);
1087 if (es->hFont)
1088 SelectObject(hdc, (HANDLE)oldfont);
1090 EDIT_HeapFree(hwnd, hStr);
1091 ReleaseDC(hwnd, hdc);
1095 /*********************************************************************
1096 * EDIT_GetStr
1098 * Return sub-string starting at pixel _off_ of length _len_ pixels.
1099 * If _off_ is part way through a character, the negative offset of
1100 * the beginning of the character is returned in _diff_, else _diff_
1101 * will be zero.
1104 HANDLE EDIT_GetStr(HWND hwnd, char *lp, int off, int len, int *diff)
1106 HANDLE hStr;
1107 char *str;
1108 int ch = 0, i = 0, j, s_i;
1109 int ch1;
1110 WND *wndPtr = WIN_FindWndPtr(hwnd);
1111 EDITSTATE *es =
1112 (EDITSTATE *)EDIT_HeapAddr(hwnd, (HANDLE)(*(wndPtr->wExtra)));
1114 #ifdef DEBUG_EDIT
1115 printf("EDIT_GetStr %s %d %d\n", lp, off, len);
1116 #endif
1118 while (i < off)
1120 s_i = i;
1121 i += EDIT_CharWidth(hwnd, *(lp + ch), i);
1122 ch++;
1125 /* if stepped past _off_, go back a character */
1126 if (i - off)
1128 i = s_i;
1129 ch--;
1131 *diff = off - i;
1132 ch1 = ch;
1134 while (i < len + off)
1136 i += EDIT_CharWidth(hwnd, *(lp + ch), i);
1137 ch++;
1140 hStr = EDIT_HeapAlloc(hwnd, ch - ch1 + 3);
1141 str = (char *)EDIT_HeapAddr(hwnd, hStr);
1142 for (i = ch1, j = 0; i < ch; i++, j++)
1143 str[j] = lp[i];
1144 str[++j] = '\0';
1145 #ifdef DEBUG_EDIT
1146 printf("EDIT_GetStr: returning %s\n", str);
1147 #endif
1148 return hStr;
1152 /*********************************************************************
1153 * WM_CHAR message function
1156 void EDIT_CharMsg(HWND hwnd, WORD wParam)
1158 WND *wndPtr = WIN_FindWndPtr(hwnd);
1159 EDITSTATE *es =
1160 (EDITSTATE *)EDIT_HeapAddr(hwnd, (HANDLE)(*(wndPtr->wExtra)));
1162 #ifdef DEBUG_EDIT
1163 printf("EDIT_CharMsg: wParam=%c\n", (char)wParam);
1164 #endif
1166 switch (wParam)
1168 case '\r':
1169 case '\n':
1170 if (!IsMultiLine())
1171 break;
1172 wParam = '\n';
1173 EDIT_KeyTyped(hwnd, wParam);
1174 break;
1176 case VK_TAB:
1177 if (!IsMultiLine())
1178 break;
1179 EDIT_KeyTyped(hwnd, wParam);
1180 break;
1182 default:
1183 if (wParam >= 20 && wParam <= 126)
1184 EDIT_KeyTyped(hwnd, wParam);
1185 break;
1190 /*********************************************************************
1191 * EDIT_KeyTyped
1193 * Process keystrokes that produce displayable characters.
1196 void EDIT_KeyTyped(HWND hwnd, short ch)
1198 WND *wndPtr = WIN_FindWndPtr(hwnd);
1199 EDITSTATE *es =
1200 (EDITSTATE *)EDIT_HeapAddr(hwnd, (HANDLE)(*(wndPtr->wExtra)));
1201 char *text = EDIT_HeapAddr(hwnd, es->hText);
1202 char *currchar = CurrChar;
1203 RECT rc;
1204 BOOL FullPaint = FALSE;
1206 #ifdef DEBUG_EDIT
1207 printf("EDIT_KeyTyped: ch=%c\n", (char)ch);
1208 #endif
1210 /* delete selected text (if any) */
1211 if (SelMarked(es))
1212 EDIT_DeleteSel(hwnd);
1214 /* test for typing at end of maximum buffer size */
1215 if (currchar == text + es->MaxTextLen)
1217 NOTIFY_PARENT(hwnd, EN_ERRSPACE);
1218 return;
1221 if (*currchar == '\0' && IsMultiLine())
1223 /* insert a newline at end of text */
1224 *currchar = '\n';
1225 *(currchar + 1) = '\0';
1226 EDIT_BuildTextPointers(hwnd);
1229 /* insert the typed character */
1230 if (text[es->textlen - 1] != '\0')
1232 /* current text buffer is full */
1233 if (es->textlen == es->MaxTextLen)
1235 /* text buffer is at maximum size */
1236 NOTIFY_PARENT(hwnd, EN_ERRSPACE);
1237 return;
1240 /* increase the text buffer size */
1241 es->textlen += GROWLENGTH;
1242 /* but not above maximum size */
1243 if (es->textlen > es->MaxTextLen)
1244 es->textlen = es->MaxTextLen;
1245 es->hText = EDIT_HeapReAlloc(hwnd, es->hText, es->textlen + 2);
1246 if (!es->hText)
1247 NOTIFY_PARENT(hwnd, EN_ERRSPACE);
1248 text = EDIT_HeapAddr(hwnd, es->hText);
1249 text[es->textlen - 1] = '\0';
1250 currchar = CurrChar;
1252 /* make space for new character and put char in buffer */
1253 memmove(currchar + 1, currchar, strlen(currchar) + 1);
1254 *currchar = ch;
1255 EDIT_ModTextPointers(hwnd, es->CurrLine + 1, 1);
1256 es->TextChanged = TRUE;
1257 NOTIFY_PARENT(hwnd, EN_UPDATE);
1259 /* re-adjust textwidth, if necessary, and redraw line */
1260 HideCaret(hwnd);
1261 if (IsMultiLine() && es->wlines > 1)
1263 es->textwidth = max(es->textwidth,
1264 EDIT_StrLength(hwnd, EDIT_TextLine(hwnd, es->CurrLine),
1265 (int)(EDIT_TextLine(hwnd, es->CurrLine + 1) -
1266 EDIT_TextLine(hwnd, es->CurrLine)), 0));
1268 else
1269 es->textwidth = max(es->textwidth,
1270 EDIT_StrLength(hwnd, text, strlen(text), 0));
1271 EDIT_WriteTextLine(hwnd, NULL, es->wtop + es->WndRow);
1273 if (ch == '\n')
1275 if (es->wleft > 0)
1276 FullPaint = TRUE;
1277 es->wleft = 0;
1278 EDIT_BuildTextPointers(hwnd);
1279 EDIT_End(hwnd);
1280 EDIT_Forward(hwnd);
1282 /* invalidate rest of window */
1283 GetClientRect(hwnd, &rc);
1284 if (!FullPaint)
1285 rc.top = es->WndRow * es->txtht;
1286 InvalidateRect(hwnd, &rc, FALSE);
1288 SetCaretPos(es->WndCol, es->WndRow * es->txtht);
1289 ShowCaret(hwnd);
1290 UpdateWindow(hwnd);
1291 NOTIFY_PARENT(hwnd, EN_CHANGE);
1292 return;
1295 /* test end of window */
1296 if (es->WndCol >= ClientWidth(wndPtr) -
1297 EDIT_CharWidth(hwnd, ch, es->WndCol + es->wleft))
1299 /* TODO:- Word wrap to be handled here */
1301 /* if (!(currchar == text + es->MaxTextLen - 2)) */
1302 EDIT_KeyHScroll(hwnd, SB_LINEDOWN);
1304 es->WndCol += EDIT_CharWidth(hwnd, ch, es->WndCol + es->wleft);
1305 es->CurrCol++;
1306 SetCaretPos(es->WndCol, es->WndRow * es->txtht);
1307 ShowCaret(hwnd);
1308 NOTIFY_PARENT(hwnd, EN_CHANGE);
1312 /*********************************************************************
1313 * EDIT_CharWidth
1315 * Return the width of the given character in pixels.
1316 * The current column offset in pixels _pcol_ is required to calculate
1317 * the width of a tab.
1320 int EDIT_CharWidth(HWND hwnd, short ch, int pcol)
1322 WND *wndPtr = WIN_FindWndPtr(hwnd);
1323 EDITSTATE *es =
1324 (EDITSTATE *)EDIT_HeapAddr(hwnd, (HANDLE)(*(wndPtr->wExtra)));
1325 short *charWidths = (short *)EDIT_HeapAddr(hwnd, es->hCharWidths);
1327 if (ch != VK_TAB)
1328 return (charWidths[ch]);
1329 else
1330 return (EDIT_GetNextTabStop(hwnd, pcol) - pcol);
1334 /*********************************************************************
1335 * EDIT_GetNextTabStop
1337 * Return the next tab stop beyond _pcol_.
1340 int EDIT_GetNextTabStop(HWND hwnd, int pcol)
1342 int i, tmp;
1343 int baseUnitWidth = LOWORD(GetDialogBaseUnits());
1344 WND *wndPtr = WIN_FindWndPtr(hwnd);
1345 EDITSTATE *es =
1346 (EDITSTATE *)EDIT_HeapAddr(hwnd, (HANDLE)(*(wndPtr->wExtra)));
1347 unsigned short *tabstops = EDIT_HeapAddr(hwnd, es->hTabStops);
1349 if (es->NumTabStops == 0)
1350 return ROUNDUP(pcol, 8 * baseUnitWidth);
1351 else if (es->NumTabStops == 1)
1352 return ROUNDUP(pcol, *tabstops * baseUnitWidth / 4);
1353 else
1355 for (i = 0; i < es->NumTabStops; i++)
1357 if (*(tabstops + i) * baseUnitWidth / 4 >= pcol)
1358 return (*(tabstops + i) * baseUnitWidth / 4);
1360 return pcol;
1365 /*********************************************************************
1366 * EDIT_Forward
1368 * Cursor right key: move right one character position.
1371 void EDIT_Forward(HWND hwnd)
1373 WND *wndPtr = WIN_FindWndPtr(hwnd);
1374 EDITSTATE *es =
1375 (EDITSTATE *)EDIT_HeapAddr(hwnd, (HANDLE)(*(wndPtr->wExtra)));
1376 char *text = EDIT_HeapAddr(hwnd, es->hText);
1378 if (*CurrChar == '\0')
1379 return;
1381 if (*CurrChar == '\n')
1383 EDIT_Home(hwnd);
1384 EDIT_Downward(hwnd);
1386 else
1388 es->WndCol += EDIT_CharWidth(hwnd, *CurrChar, es->WndCol + es->wleft);
1389 es->CurrCol++;
1390 if (es->WndCol >= ClientWidth(wndPtr))
1391 EDIT_KeyHScroll(hwnd, SB_LINEDOWN);
1397 /*********************************************************************
1398 * EDIT_Downward
1400 * Cursor down key: move down one line.
1403 void EDIT_Downward(HWND hwnd)
1405 WND *wndPtr = WIN_FindWndPtr(hwnd);
1406 EDITSTATE *es =
1407 (EDITSTATE *)EDIT_HeapAddr(hwnd, (HANDLE)(*(wndPtr->wExtra)));
1409 #ifdef DEBUG_EDIT
1410 printf("EDIT_Downward: WndRow=%d, wtop=%d, wlines=%d\n", es->WndRow, es->wtop, es->wlines);
1411 #endif
1413 if (IsMultiLine() && (es->WndRow + es->wtop + 1 < es->wlines))
1415 es->CurrLine++;
1416 if (es->WndRow == ClientHeight(wndPtr, es) - 1)
1418 es->WndRow++;
1419 EDIT_KeyVScrollLine(hwnd, SB_LINEDOWN);
1421 else
1422 es->WndRow++;
1423 EDIT_StickEnd(hwnd);
1428 /*********************************************************************
1429 * EDIT_Upward
1431 * Cursor up key: move up one line.
1434 void EDIT_Upward(HWND hwnd)
1436 WND *wndPtr = WIN_FindWndPtr(hwnd);
1437 EDITSTATE *es =
1438 (EDITSTATE *)EDIT_HeapAddr(hwnd, (HANDLE)(*(wndPtr->wExtra)));
1440 if (IsMultiLine() && es->CurrLine != 0)
1442 --es->CurrLine;
1443 if (es->WndRow == 0)
1445 --es->WndRow;
1446 EDIT_KeyVScrollLine(hwnd, SB_LINEUP);
1448 else
1449 --es->WndRow;
1450 EDIT_StickEnd(hwnd);
1455 /*********************************************************************
1456 * EDIT_Backward
1458 * Cursor left key: move left one character position.
1461 void EDIT_Backward(HWND hwnd)
1463 WND *wndPtr = WIN_FindWndPtr(hwnd);
1464 EDITSTATE *es =
1465 (EDITSTATE *)EDIT_HeapAddr(hwnd, (HANDLE)(*(wndPtr->wExtra)));
1466 char *text = EDIT_HeapAddr(hwnd, es->hText);
1468 if (es->CurrCol)
1470 --es->CurrCol;
1471 if (*CurrChar == VK_TAB)
1472 es->WndCol -= EDIT_CharWidth(hwnd, *CurrChar,
1473 EDIT_StrLength(hwnd,
1474 EDIT_TextLine(hwnd, es->CurrLine),
1475 es->CurrCol, 0));
1476 else
1477 es->WndCol -= EDIT_CharWidth(hwnd, *CurrChar, 0);
1478 if (es->WndCol < 0)
1479 EDIT_KeyHScroll(hwnd, SB_LINEUP);
1481 else if (IsMultiLine() && es->CurrLine != 0)
1483 EDIT_Upward(hwnd);
1484 EDIT_End(hwnd);
1489 /*********************************************************************
1490 * EDIT_End
1492 * End key: move to end of line.
1495 void EDIT_End(HWND hwnd)
1497 RECT rc;
1498 WND *wndPtr = WIN_FindWndPtr(hwnd);
1499 EDITSTATE *es =
1500 (EDITSTATE *)EDIT_HeapAddr(hwnd, (HANDLE)(*(wndPtr->wExtra)));
1501 char *text = EDIT_HeapAddr(hwnd, es->hText);
1503 while (*CurrChar && *CurrChar != '\n')
1505 es->WndCol += EDIT_CharWidth(hwnd, *CurrChar, es->WndCol + es->wleft);
1506 es->CurrCol++;
1509 if (es->WndCol >= ClientWidth(wndPtr))
1511 es->wleft = es->WndCol - ClientWidth(wndPtr) + HSCROLLDIM;
1512 es->WndCol -= es->wleft;
1513 InvalidateRect(hwnd, NULL, FALSE);
1514 UpdateWindow(hwnd);
1519 /*********************************************************************
1520 * EDIT_Home
1522 * Home key: move to beginning of line.
1525 void EDIT_Home(HWND hwnd)
1527 RECT rc;
1528 WND *wndPtr = WIN_FindWndPtr(hwnd);
1529 EDITSTATE *es =
1530 (EDITSTATE *)EDIT_HeapAddr(hwnd, (HANDLE)(*(wndPtr->wExtra)));
1532 es->CurrCol = es->WndCol = 0;
1533 if (es->wleft != 0)
1535 es->wleft = 0;
1536 InvalidateRect(hwnd, NULL, FALSE);
1537 UpdateWindow(hwnd);
1542 /*********************************************************************
1543 * EDIT_StickEnd
1545 * Stick the cursor to the end of the line.
1548 void EDIT_StickEnd(HWND hwnd)
1550 WND *wndPtr = WIN_FindWndPtr(hwnd);
1551 EDITSTATE *es =
1552 (EDITSTATE *)EDIT_HeapAddr(hwnd, (HANDLE)(*(wndPtr->wExtra)));
1553 int len = EDIT_LineLength(hwnd, es->CurrLine);
1554 char *cp = EDIT_TextLine(hwnd, es->CurrLine);
1555 char currpel;
1557 es->CurrCol = min(len, es->CurrCol);
1558 es->WndCol = min(EDIT_StrLength(hwnd, cp, len, 0) - es->wleft, es->WndCol);
1559 currpel = EDIT_StrLength(hwnd, cp, es->CurrCol, 0);
1561 if (es->wleft > currpel)
1563 es->wleft = max(0, currpel - 20);
1564 es->WndCol = currpel - es->wleft;
1565 UpdateWindow(hwnd);
1567 else if (currpel - es->wleft >= ClientWidth(wndPtr))
1569 es->wleft = currpel - (ClientWidth(wndPtr) - 5);
1570 es->WndCol = currpel - es->wleft;
1571 UpdateWindow(hwnd);
1576 /*********************************************************************
1577 * WM_KEYDOWN message function
1580 void EDIT_KeyDownMsg(HWND hwnd, WORD wParam)
1582 WND *wndPtr = WIN_FindWndPtr(hwnd);
1583 EDITSTATE *es =
1584 (EDITSTATE *)EDIT_HeapAddr(hwnd, (HANDLE)(*(wndPtr->wExtra)));
1586 #ifdef DEBUG_EDIT
1587 printf("EDIT_KeyDownMsg: key=%x\n", wParam);
1588 #endif
1590 HideCaret(hwnd);
1591 switch (wParam)
1593 case VK_UP:
1594 if (SelMarked(es))
1595 EDIT_ClearSel(hwnd);
1596 if (IsMultiLine())
1597 EDIT_Upward(hwnd);
1598 else
1599 EDIT_Backward(hwnd);
1600 break;
1602 case VK_DOWN:
1603 if (SelMarked(es))
1604 EDIT_ClearSel(hwnd);
1605 if (IsMultiLine())
1606 EDIT_Downward(hwnd);
1607 else
1608 EDIT_Forward(hwnd);
1609 break;
1611 case VK_RIGHT:
1612 if (SelMarked(es))
1613 EDIT_ClearSel(hwnd);
1614 EDIT_Forward(hwnd);
1615 break;
1617 case VK_LEFT:
1618 if (SelMarked(es))
1619 EDIT_ClearSel(hwnd);
1620 EDIT_Backward(hwnd);
1621 break;
1623 case VK_HOME:
1624 if (SelMarked(es))
1625 EDIT_ClearSel(hwnd);
1626 EDIT_Home(hwnd);
1627 break;
1629 case VK_END:
1630 if (SelMarked(es))
1631 EDIT_ClearSel(hwnd);
1632 EDIT_End(hwnd);
1633 break;
1635 case VK_PRIOR:
1636 if (IsMultiLine())
1638 if (SelMarked(es))
1639 EDIT_ClearSel(hwnd);
1640 EDIT_KeyVScrollPage(hwnd, SB_PAGEUP);
1642 break;
1644 case VK_NEXT:
1645 if (IsMultiLine())
1647 if (SelMarked(es))
1648 EDIT_ClearSel(hwnd);
1649 EDIT_KeyVScrollPage(hwnd, SB_PAGEDOWN);
1651 break;
1653 case VK_BACK:
1654 if (SelMarked(es))
1655 EDIT_DeleteSel(hwnd);
1656 else
1658 if (es->CurrCol == 0 && es->CurrLine == 0)
1659 break;
1660 EDIT_Backward(hwnd);
1661 EDIT_DelKey(hwnd);
1663 break;
1665 case VK_DELETE:
1666 if (SelMarked(es))
1667 EDIT_DeleteSel(hwnd);
1668 else
1669 EDIT_DelKey(hwnd);
1670 break;
1673 SetCaretPos(es->WndCol, es->WndRow * es->txtht);
1674 ShowCaret(hwnd);
1678 /*********************************************************************
1679 * EDIT_KeyHScroll
1681 * Scroll text horizontally using cursor keys.
1684 void EDIT_KeyHScroll(HWND hwnd, WORD opt)
1686 RECT rc;
1687 int hscrollpos;
1688 WND *wndPtr = WIN_FindWndPtr(hwnd);
1689 EDITSTATE *es =
1690 (EDITSTATE *)EDIT_HeapAddr(hwnd, (HANDLE)(*(wndPtr->wExtra)));
1692 if (opt == SB_LINEDOWN)
1694 es->wleft += HSCROLLDIM;
1695 es->WndCol -= HSCROLLDIM;
1697 else
1699 if (es->wleft == 0)
1700 return;
1701 if (es->wleft - HSCROLLDIM < 0)
1703 es->WndCol += es->wleft;
1704 es->wleft = 0;
1706 else
1708 es->wleft -= HSCROLLDIM;
1709 es->WndCol += HSCROLLDIM;
1713 InvalidateRect(hwnd, NULL, FALSE);
1714 UpdateWindow(hwnd);
1716 if (IsHScrollBar())
1718 hscrollpos = EDIT_ComputeHScrollPos(hwnd);
1719 SetScrollPos(hwnd, SB_HORZ, hscrollpos, TRUE);
1724 /*********************************************************************
1725 * EDIT_KeyVScrollLine
1727 * Scroll text vertically by one line using keyboard.
1730 void EDIT_KeyVScrollLine(HWND hwnd, WORD opt)
1732 RECT rc;
1733 int y, vscrollpos;
1734 WND *wndPtr = WIN_FindWndPtr(hwnd);
1735 EDITSTATE *es =
1736 (EDITSTATE *)EDIT_HeapAddr(hwnd, (HANDLE)(*(wndPtr->wExtra)));
1738 if (!IsMultiLine())
1739 return;
1741 if (opt == SB_LINEDOWN)
1743 /* move down one line */
1744 if (es->wtop + ClientHeight(wndPtr, es) >= es->wlines)
1745 return;
1746 es->wtop++;
1748 else
1750 /* move up one line */
1751 if (es->wtop == 0)
1752 return;
1753 --es->wtop;
1756 if (IsWindowVisible(hwnd))
1758 /* adjust client bottom to nearest whole line */
1759 GetClientRect(hwnd, &rc);
1760 rc.bottom = (rc.bottom / es->txtht) * es->txtht;
1762 if (opt == SB_LINEUP)
1764 /* move up one line (scroll window down) */
1765 ScrollWindow(hwnd, 0, es->txtht, &rc, &rc);
1766 /* write top line */
1767 EDIT_WriteTextLine(hwnd, NULL, es->wtop);
1768 es->WndRow++;
1770 else
1772 /* move down one line (scroll window up) */
1773 ScrollWindow(hwnd, 0, -(es->txtht), &rc, &rc);
1774 /* write bottom line */
1775 y = (((rc.bottom - rc.top) / es->txtht) - 1);
1776 EDIT_WriteTextLine(hwnd, NULL, es->wtop + y);
1777 --es->WndRow;
1781 /* reset the vertical scroll bar */
1782 if (IsVScrollBar())
1784 vscrollpos = EDIT_ComputeVScrollPos(hwnd);
1785 SetScrollPos(hwnd, SB_VERT, vscrollpos, TRUE);
1790 /*********************************************************************
1791 * EDIT_KeyVScrollPage
1793 * Scroll text vertically by one page using keyboard.
1796 void EDIT_KeyVScrollPage(HWND hwnd, WORD opt)
1798 RECT rc;
1799 int vscrollpos;
1800 WND *wndPtr = WIN_FindWndPtr(hwnd);
1801 EDITSTATE *es =
1802 (EDITSTATE *)EDIT_HeapAddr(hwnd, (HANDLE)(*(wndPtr->wExtra)));
1804 if (IsMultiLine())
1806 if (opt == SB_PAGEUP)
1808 if (es->wtop)
1809 es->wtop -= ClientHeight(wndPtr, es);
1811 else
1813 if (es->wtop + ClientHeight(wndPtr, es) < es->wlines)
1815 es->wtop += ClientHeight(wndPtr, es);
1816 if (es->wtop > es->wlines - ClientHeight(wndPtr, es))
1817 es->wtop = es->wlines - ClientHeight(wndPtr, es);
1820 if (es->wtop < 0)
1821 es->wtop = 0;
1823 es->CurrLine = es->wtop + es->WndRow;
1824 EDIT_StickEnd(hwnd);
1825 InvalidateRect(hwnd, NULL, TRUE);
1826 UpdateWindow(hwnd);
1828 /* reset the vertical scroll bar */
1829 if (IsVScrollBar())
1831 vscrollpos = EDIT_ComputeVScrollPos(hwnd);
1832 SetScrollPos(hwnd, SB_VERT, vscrollpos, TRUE);
1838 /*********************************************************************
1839 * EDIT_KeyVScrollDoc
1841 * Scroll text to top and bottom of document using keyboard.
1844 void EDIT_KeyVScrollDoc(HWND hwnd, WORD opt)
1846 RECT rc;
1847 int vscrollpos;
1848 WND *wndPtr = WIN_FindWndPtr(hwnd);
1849 EDITSTATE *es =
1850 (EDITSTATE *)EDIT_HeapAddr(hwnd, (HANDLE)(*(wndPtr->wExtra)));
1852 if (!IsMultiLine())
1853 return;
1855 if (opt == SB_TOP)
1856 es->wtop = es->wleft = 0;
1857 else if (es->wtop + ClientHeight(wndPtr, es) < es->wlines)
1859 es->wtop = es->wlines - ClientHeight(wndPtr, es);
1860 es->wleft = 0;
1863 es->CurrLine = es->wlines;
1864 es->WndRow = es->wlines - es->wtop;
1865 EDIT_End(hwnd);
1866 InvalidateRect(hwnd, NULL, TRUE);
1867 UpdateWindow(hwnd);
1869 /* reset the vertical scroll bar */
1870 if (IsVScrollBar())
1872 vscrollpos = EDIT_ComputeVScrollPos(hwnd);
1873 SetScrollPos(hwnd, SB_VERT, vscrollpos, TRUE);
1878 /*********************************************************************
1879 * EDIT_ComputeVScrollPos
1881 * Compute the vertical scroll bar position from the window
1882 * position and text width.
1885 int EDIT_ComputeVScrollPos(HWND hwnd)
1887 int vscrollpos;
1888 short minpos, maxpos;
1889 WND *wndPtr = WIN_FindWndPtr(hwnd);
1890 EDITSTATE *es =
1891 (EDITSTATE *)EDIT_HeapAddr(hwnd, (HANDLE)(*(wndPtr->wExtra)));
1893 GetScrollRange(hwnd, SB_VERT, &minpos, &maxpos);
1895 if (es->wlines > ClientHeight(wndPtr, es))
1896 vscrollpos = (double)(es->wtop) / (double)(es->wlines -
1897 ClientHeight(wndPtr, es)) * (maxpos - minpos);
1898 else
1899 vscrollpos = minpos;
1901 return vscrollpos;
1905 /*********************************************************************
1906 * EDIT_ComputeHScrollPos
1908 * Compute the horizontal scroll bar position from the window
1909 * position and text width.
1912 int EDIT_ComputeHScrollPos(HWND hwnd)
1914 int hscrollpos;
1915 short minpos, maxpos;
1916 WND *wndPtr = WIN_FindWndPtr(hwnd);
1917 EDITSTATE *es =
1918 (EDITSTATE *)EDIT_HeapAddr(hwnd, (HANDLE)(*(wndPtr->wExtra)));
1920 GetScrollRange(hwnd, SB_HORZ, &minpos, &maxpos);
1922 if (es->textwidth > ClientWidth(wndPtr))
1923 hscrollpos = (double)(es->wleft) / (double)(es->textwidth -
1924 ClientWidth(wndPtr)) * (maxpos - minpos);
1925 else
1926 hscrollpos = minpos;
1928 return hscrollpos;
1932 /*********************************************************************
1933 * EDIT_DelKey
1935 * Delete character to right of cursor.
1938 void EDIT_DelKey(HWND hwnd)
1940 RECT rc;
1941 WND *wndPtr = WIN_FindWndPtr(hwnd);
1942 EDITSTATE *es =
1943 (EDITSTATE *)EDIT_HeapAddr(hwnd, (HANDLE)(*(wndPtr->wExtra)));
1944 char *currchar = CurrChar;
1945 BOOL repaint = *currchar == '\n';
1947 if (IsMultiLine() && *currchar == '\n' && *(currchar + 1) == '\0')
1948 return;
1949 strcpy(currchar, currchar + 1);
1950 NOTIFY_PARENT(hwnd, EN_UPDATE);
1952 if (repaint)
1954 EDIT_BuildTextPointers(hwnd);
1955 GetClientRect(hwnd, &rc);
1956 rc.top = es->WndRow * es->txtht;
1957 InvalidateRect(hwnd, &rc, FALSE);
1958 UpdateWindow(hwnd);
1960 else
1962 EDIT_ModTextPointers(hwnd, es->CurrLine + 1, -1);
1963 EDIT_WriteTextLine(hwnd, NULL, es->WndRow + es->wtop);
1966 es->TextChanged = TRUE;
1967 NOTIFY_PARENT(hwnd, EN_CHANGE);
1970 /*********************************************************************
1971 * WM_VSCROLL message function
1974 void EDIT_VScrollMsg(HWND hwnd, WORD wParam, LONG lParam)
1976 WND *wndPtr = WIN_FindWndPtr(hwnd);
1977 EDITSTATE *es =
1978 (EDITSTATE *)EDIT_HeapAddr(hwnd, (HANDLE)(*(wndPtr->wExtra)));
1980 if (IsMultiLine())
1982 HideCaret(hwnd);
1984 switch (wParam)
1986 case SB_LINEUP:
1987 case SB_LINEDOWN:
1988 EDIT_VScrollLine(hwnd, wParam);
1989 break;
1991 case SB_PAGEUP:
1992 case SB_PAGEDOWN:
1993 EDIT_VScrollPage(hwnd, wParam);
1994 break;
1998 SetCaretPos(es->WndCol, es->WndRow);
1999 ShowCaret(hwnd);
2003 /*********************************************************************
2004 * EDIT_VScrollLine
2006 * Scroll text vertically by one line using scrollbars.
2009 void EDIT_VScrollLine(HWND hwnd, WORD opt)
2011 RECT rc;
2012 int y;
2013 WND *wndPtr = WIN_FindWndPtr(hwnd);
2014 EDITSTATE *es =
2015 (EDITSTATE *)EDIT_HeapAddr(hwnd, (HANDLE)(*(wndPtr->wExtra)));
2017 #ifdef DEBUG_EDIT
2018 printf("EDIT_VScrollLine: direction=%d\n", opt);
2019 #endif
2021 if (opt == SB_LINEDOWN)
2023 /* move down one line */
2024 if (es->wtop + ClientHeight(wndPtr, es) >= es->wlines)
2025 return;
2026 es->wtop++;
2028 else
2030 /* move up one line */
2031 if (es->wtop == 0)
2032 return;
2033 --es->wtop;
2036 if (IsWindowVisible(hwnd))
2038 /* adjust client bottom to nearest whole line */
2039 GetClientRect(hwnd, &rc);
2040 rc.bottom = (rc.bottom / es->txtht) * es->txtht;
2042 if (opt == SB_LINEUP)
2044 /* move up one line (scroll window down) */
2045 ScrollWindow(hwnd, 0, es->txtht, &rc, &rc);
2046 /* write top line */
2047 EDIT_WriteTextLine(hwnd, NULL, es->wtop);
2048 es->WndRow++;
2050 else
2052 /* move down one line (scroll window up) */
2053 ScrollWindow(hwnd, 0, -(es->txtht), &rc, &rc);
2054 /* write bottom line */
2055 y = ((rc.bottom - rc.top / es->txtht) - 1);
2056 EDIT_WriteTextLine(hwnd, NULL, es->wtop + y);
2057 --es->WndRow;
2063 /*********************************************************************
2064 * EDIT_VScrollPage
2066 * Scroll text vertically by one page using keyboard.
2069 void EDIT_VScrollPage(HWND hwnd, WORD opt)
2071 RECT rc;
2072 int vscrollpos;
2073 WND *wndPtr = WIN_FindWndPtr(hwnd);
2074 EDITSTATE *es =
2075 (EDITSTATE *)EDIT_HeapAddr(hwnd, (HANDLE)(*(wndPtr->wExtra)));
2077 if (opt == SB_PAGEUP)
2079 if (es->wtop)
2080 es->wtop -= ClientHeight(wndPtr, es);
2082 else
2084 if (es->wtop + ClientHeight(wndPtr, es) < es->wlines)
2086 es->wtop += ClientHeight(wndPtr, es);
2087 if (es->wtop > es->wlines - ClientHeight(wndPtr, es))
2088 es->wtop = es->wlines - ClientHeight(wndPtr, es);
2091 if (es->wtop < 0)
2092 es->wtop = 0;
2094 InvalidateRect(hwnd, NULL, TRUE);
2095 UpdateWindow(hwnd);
2097 /* reset the vertical scroll bar */
2098 if (IsVScrollBar())
2100 vscrollpos = EDIT_ComputeVScrollPos(hwnd);
2101 SetScrollPos(hwnd, SB_VERT, vscrollpos, TRUE);
2106 /*********************************************************************
2107 * WM_HSCROLL message function
2110 void EDIT_HScrollMsg(HWND hwnd, WORD wParam, LONG lParam)
2112 WND *wndPtr = WIN_FindWndPtr(hwnd);
2113 EDITSTATE *es =
2114 (EDITSTATE *)EDIT_HeapAddr(hwnd, (HANDLE)(*(wndPtr->wExtra)));
2116 switch (wParam)
2118 case SB_LINEUP:
2119 case SB_LINEDOWN:
2120 HideCaret(hwnd);
2122 SetCaretPos(es->WndCol, es->WndRow * es->txtht);
2123 ShowCaret(hwnd);
2124 break;
2129 /*********************************************************************
2130 * WM_SIZE message function
2133 void EDIT_SizeMsg(HWND hwnd, WORD wParam, LONG lParam)
2135 RECT rc;
2136 WND *wndPtr = WIN_FindWndPtr(hwnd);
2137 EDITSTATE *es =
2138 (EDITSTATE *)EDIT_HeapAddr(hwnd, (HANDLE)(*(wndPtr->wExtra)));
2140 if (wParam != SIZE_MAXIMIZED && wParam != SIZE_RESTORED) return;
2142 InvalidateRect(hwnd, NULL, TRUE);
2143 es->PaintBkgd = TRUE;
2144 UpdateWindow(hwnd);
2148 /*********************************************************************
2149 * WM_LBUTTONDOWN message function
2152 void EDIT_LButtonDownMsg(HWND hwnd, WORD wParam, LONG lParam)
2154 char *cp;
2155 int len;
2156 BOOL end = FALSE;
2157 WND *wndPtr = WIN_FindWndPtr(hwnd);
2158 EDITSTATE *es =
2159 (EDITSTATE *)EDIT_HeapAddr(hwnd, (HANDLE)(*(wndPtr->wExtra)));
2161 if (SelMarked(es))
2162 EDIT_ClearSel(hwnd);
2164 es->WndRow = HIWORD(lParam) / es->txtht;
2165 if (es->WndRow > es->wlines - es->wtop - 1)
2167 if (es->wlines)
2168 es->WndRow = es->wlines - es->wtop - 1;
2169 else
2170 es->WndRow = 0;
2171 end = TRUE;
2173 es->CurrLine = es->wtop + es->WndRow;
2175 cp = EDIT_TextLine(hwnd, es->CurrLine);
2176 len = EDIT_LineLength(hwnd, es->CurrLine);
2177 es->WndCol = LOWORD(lParam);
2178 if (es->WndCol > EDIT_StrLength(hwnd, cp, len, 0) - es->wleft || end)
2179 es->WndCol = EDIT_StrLength(hwnd, cp, len, 0) - es->wleft;
2180 es->CurrCol = EDIT_PixelToChar(hwnd, es->CurrLine, &(es->WndCol));
2182 ButtonDown = TRUE;
2183 ButtonRow = es->CurrLine;
2184 ButtonCol = es->CurrCol;
2188 /*********************************************************************
2189 * WM_MOUSEMOVE message function
2192 void EDIT_MouseMoveMsg(HWND hwnd, WORD wParam, LONG lParam)
2194 if (wParam != MK_LBUTTON)
2195 return;
2197 if (ButtonDown)
2199 EDIT_SetAnchor(hwnd, ButtonRow, ButtonCol);
2200 TextMarking = TRUE;
2201 ButtonDown = FALSE;
2204 if (TextMarking)
2205 EDIT_ExtendSel(hwnd, LOWORD(lParam), HIWORD(lParam));
2209 /*********************************************************************
2210 * EDIT_PixelToChar
2212 * Convert a pixel offset in the given row to a character offset,
2213 * adjusting the pixel offset to the nearest whole character if
2214 * necessary.
2217 int EDIT_PixelToChar(HWND hwnd, int row, int *pixel)
2219 int ch = 0, i = 0, s_i;
2220 char *text;
2221 WND *wndPtr = WIN_FindWndPtr(hwnd);
2222 EDITSTATE *es =
2223 (EDITSTATE *)EDIT_HeapAddr(hwnd, (HANDLE)(*(wndPtr->wExtra)));
2225 #ifdef DEBUG_EDIT
2226 printf("EDIT_PixelToChar: row=%d, pixel=%d\n", row, *pixel);
2227 #endif
2229 text = EDIT_TextLine(hwnd, row);
2230 while (i < *pixel)
2232 s_i = i;
2233 i += EDIT_CharWidth(hwnd, *(text + ch), i);
2234 ch++;
2237 /* if stepped past _pixel_, go back a character */
2238 if (i - *pixel)
2240 i = s_i;
2241 --ch;
2243 *pixel = i;
2244 return ch;
2248 /*********************************************************************
2249 * WM_SETTEXT message function
2252 LONG EDIT_SetTextMsg(HWND hwnd, LONG lParam)
2254 int len;
2255 char *text;
2256 RECT rc;
2257 WND *wndPtr = WIN_FindWndPtr(hwnd);
2258 EDITSTATE *es =
2259 (EDITSTATE *)EDIT_HeapAddr(hwnd, (HANDLE)(*(wndPtr->wExtra)));
2261 if (strlen((char *)lParam) <= es->MaxTextLen)
2263 len = strlen((char *)lParam);
2264 EDIT_ClearText(hwnd);
2265 es->textlen = len;
2266 es->hText = EDIT_HeapReAlloc(hwnd, es->hText, len + 3);
2267 text = EDIT_HeapAddr(hwnd, es->hText);
2268 strcpy(text, (char *)lParam);
2269 text[len + 1] = '\0';
2270 text[len + 2] = '\0';
2271 EDIT_BuildTextPointers(hwnd);
2272 InvalidateRect(hwnd, NULL, TRUE);
2273 es->PaintBkgd = TRUE;
2274 es->TextChanged = TRUE;
2275 return 0L;
2277 else
2278 return EN_ERRSPACE;
2282 /*********************************************************************
2283 * EDIT_ClearText
2285 * Clear text from text buffer.
2288 void EDIT_ClearText(HWND hwnd)
2290 WND *wndPtr = WIN_FindWndPtr(hwnd);
2291 EDITSTATE *es =
2292 (EDITSTATE *)EDIT_HeapAddr(hwnd, (HANDLE)(*(wndPtr->wExtra)));
2293 unsigned int blen = EditBufLen(wndPtr) + 2;
2294 char *text;
2296 es->hText = EDIT_HeapReAlloc(hwnd, es->hText, blen);
2297 text = EDIT_HeapAddr(hwnd, es->hText);
2298 memset(text, 0, blen);
2299 es->textlen = 0;
2300 es->wlines = 0;
2301 es->CurrLine = es->CurrCol = 0;
2302 es->WndRow = es->WndCol = 0;
2303 es->wleft = es->wtop = 0;
2304 es->textwidth = 0;
2305 es->TextChanged = FALSE;
2306 EDIT_ClearTextPointers(hwnd);
2310 /*********************************************************************
2311 * EM_SETSEL message function
2314 void EDIT_SetSelMsg(HWND hwnd, WORD wParam, LONG lParam)
2316 int so, eo;
2317 WND *wndPtr = WIN_FindWndPtr(hwnd);
2318 EDITSTATE *es =
2319 (EDITSTATE *)EDIT_HeapAddr(hwnd, (HANDLE)(*(wndPtr->wExtra)));
2321 so = LOWORD(lParam);
2322 eo = HIWORD(lParam);
2324 if (so == -1) /* if so == -1, clear selection */
2326 EDIT_ClearSel(hwnd);
2327 return;
2330 if (so == eo) /* if so == eo, set caret only */
2332 EDIT_GetLineCol(hwnd, so, &(es->CurrLine), &(es->CurrCol));
2333 es->WndRow = es->CurrLine - es->wtop;
2335 if (!wParam)
2337 if (es->WndRow < 0 || es->WndRow > ClientHeight(wndPtr, es))
2339 es->wtop = es->CurrLine;
2340 es->WndRow = 0;
2342 es->WndCol = EDIT_StrLength(hwnd,
2343 EDIT_TextLine(hwnd, es->CurrLine),
2344 es->CurrCol, 0) - es->wleft;
2345 if (es->WndCol > ClientWidth(wndPtr))
2347 es->wleft = es->WndCol;
2348 es->WndCol = 0;
2350 else if (es->WndCol < 0)
2352 es->wleft += es->WndCol;
2353 es->WndCol = 0;
2357 else /* otherwise set selection */
2359 if (so > eo)
2360 swap(&so, &eo);
2362 EDIT_GetLineCol(hwnd, so, &(es->SelBegLine), &(es->SelBegCol));
2363 EDIT_GetLineCol(hwnd, eo, &(es->SelEndLine), &(es->SelEndCol));
2364 es->CurrLine = es->SelEndLine;
2365 es->CurrCol = es->SelEndCol;
2366 es->WndRow = es->SelEndLine - es->wtop;
2368 if (!wParam) /* don't suppress scrolling of text */
2370 if (es->WndRow < 0)
2372 es->wtop = es->SelEndLine;
2373 es->WndRow = 0;
2375 else if (es->WndRow > ClientHeight(wndPtr, es))
2377 es->wtop += es->WndRow - ClientHeight(wndPtr, es);
2378 es->WndRow = ClientHeight(wndPtr, es);
2380 es->WndCol = EDIT_StrLength(hwnd,
2381 EDIT_TextLine(hwnd, es->SelEndLine),
2382 es->SelEndCol, 0) - es->wleft;
2383 if (es->WndCol > ClientWidth(wndPtr))
2385 es->wleft += es->WndCol - ClientWidth(wndPtr);
2386 es->WndCol = ClientWidth(wndPtr);
2388 else if (es->WndCol < 0)
2390 es->wleft += es->WndCol;
2391 es->WndCol = 0;
2395 InvalidateRect(hwnd, NULL, TRUE);
2396 UpdateWindow(hwnd);
2401 /*********************************************************************
2402 * EDIT_GetLineCol
2404 * Return line and column in text buffer from character offset.
2407 void EDIT_GetLineCol(HWND hwnd, int off, int *line, int *col)
2409 int lineno;
2410 char *cp, *cp1;
2411 WND *wndPtr = WIN_FindWndPtr(hwnd);
2412 EDITSTATE *es =
2413 (EDITSTATE *)EDIT_HeapAddr(hwnd, (HANDLE)(*(wndPtr->wExtra)));
2414 char *text = EDIT_HeapAddr(hwnd, es->hText);
2415 unsigned int *textPtrs =
2416 (unsigned int *)EDIT_HeapAddr(hwnd, es->hTextPtrs);
2418 /* check for (0,0) */
2419 if (!off)
2421 *line = 0;
2422 *col = 0;
2423 return;
2426 if (off > strlen(text)) off = strlen(text);
2427 cp1 = text;
2428 for (lineno = 0; lineno < es->wlines; lineno++)
2430 cp = text + *(textPtrs + lineno);
2431 if (off == (int)(cp - text))
2433 *line = lineno;
2434 *col = 0;
2435 return;
2437 if (off < (int)(cp - text))
2438 break;
2439 cp1 = cp;
2441 *line = lineno - 1;
2442 *col = off - (int)(cp1 - text);
2443 #if 0
2444 if (*(text + *col) == '\0')
2445 (*col)--;
2446 #endif
2450 /*********************************************************************
2451 * EDIT_DeleteSel
2453 * Delete the current selected text (if any)
2456 void EDIT_DeleteSel(HWND hwnd)
2458 char *bbl, *bel;
2459 int len;
2460 WND *wndPtr = WIN_FindWndPtr(hwnd);
2461 EDITSTATE *es =
2462 (EDITSTATE *)EDIT_HeapAddr(hwnd, (HANDLE)(*(wndPtr->wExtra)));
2463 char *text = EDIT_HeapAddr(hwnd, es->hText);
2465 if (SelMarked(es))
2467 bbl = EDIT_TextLine(hwnd, es->SelBegLine) + es->SelBegCol;
2468 bel = EDIT_TextLine(hwnd, es->SelEndLine) + es->SelEndCol;
2469 len = (int)(bel - bbl);
2470 EDIT_SaveDeletedText(hwnd, bbl, len, es->SelBegLine, es->SelBegCol);
2471 es->TextChanged = TRUE;
2472 strcpy(bbl, bel);
2474 es->CurrLine = es->SelBegLine;
2475 es->CurrCol = es->SelBegCol;
2476 es->WndRow = es->SelBegLine - es->wtop;
2477 if (es->WndRow < 0)
2479 es->wtop = es->SelBegLine;
2480 es->WndRow = 0;
2482 es->WndCol = EDIT_StrLength(hwnd, bbl - es->SelBegCol,
2483 es->SelBegCol, 0) - es->wleft;
2485 EDIT_BuildTextPointers(hwnd);
2486 es->PaintBkgd = TRUE;
2487 EDIT_ClearSel(hwnd);
2492 /*********************************************************************
2493 * EDIT_ClearSel
2495 * Clear the current selection.
2498 void EDIT_ClearSel(HWND hwnd)
2500 WND *wndPtr = WIN_FindWndPtr(hwnd);
2501 EDITSTATE *es =
2502 (EDITSTATE *)EDIT_HeapAddr(hwnd, (HANDLE)(*(wndPtr->wExtra)));
2504 es->SelBegLine = es->SelBegCol = 0;
2505 es->SelEndLine = es->SelEndCol = 0;
2507 InvalidateRect(hwnd, NULL, TRUE);
2508 UpdateWindow(hwnd);
2512 /*********************************************************************
2513 * EDIT_TextLineNumber
2515 * Return the line number in the text buffer of the supplied
2516 * character pointer.
2519 int EDIT_TextLineNumber(HWND hwnd, char *lp)
2521 int lineno;
2522 char *cp;
2523 WND *wndPtr = WIN_FindWndPtr(hwnd);
2524 EDITSTATE *es =
2525 (EDITSTATE *)EDIT_HeapAddr(hwnd, (HANDLE)(*(wndPtr->wExtra)));
2526 char *text = EDIT_HeapAddr(hwnd, es->hText);
2527 unsigned int *textPtrs =
2528 (unsigned int *)EDIT_HeapAddr(hwnd, es->hTextPtrs);
2530 for (lineno = 0; lineno < es->wlines; lineno++)
2532 cp = text + *(textPtrs + lineno);
2533 if (cp == lp)
2534 return lineno;
2535 if (cp > lp)
2536 break;
2538 return lineno - 1;
2542 /*********************************************************************
2543 * EDIT_SetAnchor
2545 * Set down anchor for text marking.
2548 void EDIT_SetAnchor(HWND hwnd, int row, int col)
2550 BOOL sel = FALSE;
2551 WND *wndPtr = WIN_FindWndPtr(hwnd);
2552 EDITSTATE *es =
2553 (EDITSTATE *)EDIT_HeapAddr(hwnd, (HANDLE)(*(wndPtr->wExtra)));
2555 if (SelMarked(es))
2556 sel = TRUE;
2557 EDIT_ClearSel(hwnd);
2558 es->SelBegLine = es->SelEndLine = row;
2559 es->SelBegCol = es->SelEndCol = col;
2560 if (sel)
2562 InvalidateRect(hwnd, NULL, FALSE);
2563 UpdateWindow(hwnd);
2568 /*********************************************************************
2569 * EDIT_ExtendSel
2571 * Extend selection to the given screen co-ordinates.
2574 void EDIT_ExtendSel(HWND hwnd, int x, int y)
2576 int bbl, bel, bbc, bec;
2577 char *cp;
2578 int len;
2579 BOOL end = FALSE;
2580 WND *wndPtr = WIN_FindWndPtr(hwnd);
2581 EDITSTATE *es =
2582 (EDITSTATE *)EDIT_HeapAddr(hwnd, (HANDLE)(*(wndPtr->wExtra)));
2584 #ifdef DEBUG_EDIT
2585 printf("EDIT_ExtendSel: x=%d, y=%d\n", x, y);
2586 #endif
2588 bbl = es->SelEndLine;
2589 bbc = es->SelEndCol;
2590 cp = EDIT_TextLine(hwnd, es->wtop + y / es->txtht);
2591 len = EDIT_LineLength(hwnd, es->wtop + y / es->txtht);
2593 es->WndRow = y / es->txtht;
2594 if (es->WndRow > es->wlines - es->wtop - 1)
2596 if (es->wlines)
2597 es->WndRow = es->wlines - es->wtop - 1;
2598 else
2599 es->WndRow = 0;
2600 end = TRUE;
2602 es->CurrLine = es->wtop + es->WndRow;
2603 es->SelEndLine = es->CurrLine;
2605 es->WndCol = x;
2606 if (es->WndCol > EDIT_StrLength(hwnd, cp, len, 0) - es->wleft || end)
2607 es->WndCol = EDIT_StrLength(hwnd, cp, len, 0) - es->wleft;
2608 es->CurrCol = EDIT_PixelToChar(hwnd, es->CurrLine, &(es->WndCol));
2609 es->SelEndCol = es->CurrCol - 1;
2611 bel = es->SelEndLine;
2612 bec = es->SelEndCol;
2614 /* return if no new characters to mark */
2615 if (bbl == bel && bbc == bec)
2616 return;
2618 /* put lowest marker first */
2619 if (bbl > bel)
2621 swap(&bbl, &bel);
2622 swap(&bbc, &bec);
2624 if (bbl == bel && bbc > bec)
2625 swap(&bbc, &bec);
2627 for (y = bbl; y <= bel; y++)
2629 if (y == bbl && y == bel)
2630 EDIT_WriteSel(hwnd, y, bbc, bec);
2631 else if (y == bbl)
2632 EDIT_WriteSel(hwnd, y, bbc, -1);
2633 else if (y == bel)
2634 EDIT_WriteSel(hwnd, y, 0, bec);
2635 else
2636 EDIT_WriteSel(hwnd, y, 0, -1);
2641 /*********************************************************************
2642 * EDIT_WriteSel
2644 * Display selection by reversing pixels in selected text.
2645 * If end == -1, selection applies to end of line.
2648 void EDIT_WriteSel(HWND hwnd, int y, int start, int end)
2650 RECT rc;
2651 int scol, ecol;
2652 char *cp;
2653 HDC hdc;
2654 HBRUSH hbrush, holdbrush;
2655 int olddm;
2656 WND *wndPtr = WIN_FindWndPtr(hwnd);
2657 EDITSTATE *es =
2658 (EDITSTATE *)EDIT_HeapAddr(hwnd, (HANDLE)(*(wndPtr->wExtra)));
2660 #ifdef DEBUG_EDIT
2661 printf("EDIT_WriteSel: y=%d start=%d end=%d\n", y, start, end);
2662 #endif
2663 GetClientRect(hwnd, &rc);
2665 /* make sure y is within the window */
2666 if (y < es->wtop || y > (es->wtop + ClientHeight(wndPtr, es)))
2667 return;
2669 /* get pointer to text */
2670 cp = EDIT_TextLine(hwnd, y);
2672 /* get length of line if end == -1 */
2673 if (end == -1)
2674 end = EDIT_LineLength(hwnd, y);
2676 scol = EDIT_StrLength(hwnd, cp, start, 0);
2677 if (scol > rc.right) return;
2678 if (scol < rc.left) scol = rc.left;
2679 ecol = EDIT_StrLength(hwnd, cp, end, 0);
2680 if (ecol < rc.left) return;
2681 if (ecol > rc.right) ecol = rc.right;
2683 hdc = GetDC(hwnd);
2684 hbrush = GetStockObject(BLACK_BRUSH);
2685 holdbrush = (HBRUSH)SelectObject(hdc, (HANDLE)hbrush);
2686 olddm = SetROP2(hdc, R2_XORPEN);
2687 Rectangle(hdc, scol, y * es->txtht, ecol, (y + 1) * es->txtht);
2688 SetROP2(hdc, olddm);
2689 SelectObject(hdc, (HANDLE)holdbrush);
2690 ReleaseDC(hwnd, hdc);
2694 /*********************************************************************
2695 * EDIT_StopMarking
2697 * Stop text marking (selection).
2700 void EDIT_StopMarking(HWND hwnd)
2702 WND *wndPtr = WIN_FindWndPtr(hwnd);
2703 EDITSTATE *es =
2704 (EDITSTATE *)EDIT_HeapAddr(hwnd, (HANDLE)(*(wndPtr->wExtra)));
2706 TextMarking = FALSE;
2707 if (es->SelBegLine > es->SelEndLine)
2709 swap(&(es->SelBegLine), &(es->SelEndLine));
2710 swap(&(es->SelBegCol), &(es->SelEndCol));
2712 if (es->SelBegLine == es->SelEndLine && es->SelBegCol > es->SelEndCol)
2713 swap(&(es->SelBegCol), &(es->SelEndCol));
2717 /*********************************************************************
2718 * EM_GETLINE message function
2721 LONG EDIT_GetLineMsg(HWND hwnd, WORD wParam, LONG lParam)
2723 char *cp, *cp1;
2724 int len;
2725 char *buffer = (char *)lParam;
2726 WND *wndPtr = WIN_FindWndPtr(hwnd);
2727 EDITSTATE *es =
2728 (EDITSTATE *)EDIT_HeapAddr(hwnd, (HANDLE)(*(wndPtr->wExtra)));
2730 cp = EDIT_TextLine(hwnd, wParam);
2731 cp1 = EDIT_TextLine(hwnd, wParam + 1);
2732 len = min((int)(cp1 - cp), (WORD)(*buffer));
2733 strncpy(buffer, cp, len);
2735 return (LONG)len;
2739 /*********************************************************************
2740 * EM_GETSEL message function
2743 LONG EDIT_GetSelMsg(HWND hwnd)
2745 int so, eo;
2746 WND *wndPtr = WIN_FindWndPtr(hwnd);
2747 EDITSTATE *es =
2748 (EDITSTATE *)EDIT_HeapAddr(hwnd, (HANDLE)(*(wndPtr->wExtra)));
2749 unsigned int *textPtrs =
2750 (unsigned int *)EDIT_HeapAddr(hwnd, es->hTextPtrs);
2752 so = *(textPtrs + es->SelBegLine) + es->SelBegCol;
2753 eo = *(textPtrs + es->SelEndLine) + es->SelEndCol;
2755 return MAKELONG(so, eo);
2759 /*********************************************************************
2760 * EM_REPLACESEL message function
2763 void EDIT_ReplaceSel(HWND hwnd, LONG lParam)
2765 EDIT_DeleteSel(hwnd);
2766 EDIT_InsertText(hwnd, (char *)lParam, strlen((char *)lParam));
2767 InvalidateRect(hwnd, NULL, TRUE);
2768 UpdateWindow(hwnd);
2772 /*********************************************************************
2773 * EDIT_InsertText
2775 * Insert text at current line and column.
2778 void EDIT_InsertText(HWND hwnd, char *str, int len)
2780 int plen;
2781 WND *wndPtr = WIN_FindWndPtr(hwnd);
2782 EDITSTATE *es =
2783 (EDITSTATE *)EDIT_HeapAddr(hwnd, (HANDLE)(*(wndPtr->wExtra)));
2784 char *text = EDIT_HeapAddr(hwnd, es->hText);
2786 plen = strlen(text) + len;
2787 if (plen + 1 > es->textlen)
2789 es->hText = EDIT_HeapReAlloc(hwnd, es->hText, es->textlen + len);
2790 es->textlen = plen + 1;
2792 memmove(CurrChar + len, CurrChar, strlen(CurrChar) + 1);
2793 memcpy(CurrChar, str, len);
2795 EDIT_BuildTextPointers(hwnd);
2796 es->PaintBkgd = TRUE;
2797 es->TextChanged = TRUE;
2799 EDIT_GetLineCol(hwnd, (int)((CurrChar + len) - text), &(es->CurrLine),
2800 &(es->CurrCol));
2801 es->WndRow = es->CurrLine - es->wtop;
2802 es->WndCol = EDIT_StrLength(hwnd, EDIT_TextLine(hwnd, es->CurrLine),
2803 es->CurrCol, 0) - es->wleft;
2807 /*********************************************************************
2808 * EM_LINEFROMCHAR message function
2811 LONG EDIT_LineFromCharMsg(HWND hwnd, WORD wParam)
2813 int row, col;
2814 WND *wndPtr = WIN_FindWndPtr(hwnd);
2815 EDITSTATE *es =
2816 (EDITSTATE *)EDIT_HeapAddr(hwnd, (HANDLE)(*(wndPtr->wExtra)));
2818 if (wParam == (WORD)-1)
2819 return (LONG)(es->SelBegLine);
2820 else
2821 EDIT_GetLineCol(hwnd, wParam, &row, &col);
2823 return (LONG)row;
2827 /*********************************************************************
2828 * EM_LINEINDEX message function
2831 LONG EDIT_LineIndexMsg(HWND hwnd, WORD wParam)
2833 WND *wndPtr = WIN_FindWndPtr(hwnd);
2834 EDITSTATE *es =
2835 (EDITSTATE *)EDIT_HeapAddr(hwnd, (HANDLE)(*(wndPtr->wExtra)));
2836 unsigned int *textPtrs =
2837 (unsigned int *)EDIT_HeapAddr(hwnd, es->hTextPtrs);
2839 if (wParam == (WORD)-1)
2840 wParam = es->CurrLine;
2842 return (LONG)(*(textPtrs + wParam));
2846 /*********************************************************************
2847 * EM_LINELENGTH message function
2850 LONG EDIT_LineLengthMsg(HWND hwnd, WORD wParam)
2852 int row, col, len;
2853 int sbl, sbc, sel, sec;
2854 WND *wndPtr = WIN_FindWndPtr(hwnd);
2855 EDITSTATE *es =
2856 (EDITSTATE *)EDIT_HeapAddr(hwnd, (HANDLE)(*(wndPtr->wExtra)));
2857 unsigned int *textPtrs =
2858 (unsigned int *)EDIT_HeapAddr(hwnd, es->hTextPtrs);
2860 if (wParam == (WORD)-1)
2862 if (SelMarked(es))
2864 sbl = es->SelBegLine;
2865 sbc = es->SelBegCol;
2866 sel = es->SelEndLine;
2867 sec = es->SelEndCol;
2869 if (sbl > sel)
2871 swap(&sbl, &sel);
2872 swap(&sbc, &sec);
2874 if (sbl == sel && sbc > sec)
2875 swap(&sbc, &sec);
2877 if (sbc == sel)
2879 len = *(textPtrs + sbl + 1) - *(textPtrs + sbl) - 1;
2880 return len - sec - sbc;
2883 len = *(textPtrs + sel + 1) - *(textPtrs + sel) - sec - 1;
2884 return len + sbc;
2886 else /* no selection marked */
2888 len = *(textPtrs + es->CurrLine + 1) -
2889 *(textPtrs + es->CurrLine) - 1;
2890 return len;
2893 else /* line number specified */
2895 EDIT_GetLineCol(hwnd, wParam, &row, &col);
2896 len = *(textPtrs + row + 1) - *(textPtrs + row);
2897 return len;
2902 /*********************************************************************
2903 * WM_SETFONT message function
2906 void EDIT_SetFont(HWND hwnd, WORD wParam, LONG lParam)
2908 HDC hdc;
2909 TEXTMETRIC tm;
2910 HFONT oldfont;
2911 WND *wndPtr = WIN_FindWndPtr(hwnd);
2912 EDITSTATE *es =
2913 (EDITSTATE *)EDIT_HeapAddr(hwnd, (HANDLE)(*(wndPtr->wExtra)));
2914 short *charWidths = (short *)EDIT_HeapAddr(hwnd, es->hCharWidths);
2916 es->hFont = wParam;
2917 hdc = GetDC(hwnd);
2918 oldfont = (HFONT)SelectObject(hdc, (HANDLE)es->hFont);
2919 GetCharWidth(hdc, 0, 255, charWidths);
2920 GetTextMetrics(hdc, &tm);
2921 es->txtht = tm.tmHeight + tm.tmExternalLeading;
2922 SelectObject(hdc, (HANDLE)oldfont);
2923 ReleaseDC(hwnd, hdc);
2925 es->WndRow = (es->CurrLine - es->wtop) / es->txtht;
2926 es->WndCol = EDIT_StrLength(hwnd, EDIT_TextLine(hwnd, es->CurrLine),
2927 es->CurrCol, 0) - es->wleft;
2929 InvalidateRect(hwnd, NULL, TRUE);
2930 es->PaintBkgd = TRUE;
2931 if (lParam) UpdateWindow(hwnd);
2935 /*********************************************************************
2936 * EDIT_SaveDeletedText
2938 * Save deleted text in deleted text buffer.
2941 void EDIT_SaveDeletedText(HWND hwnd, char *deltext, int len,
2942 int line, int col)
2944 char *text;
2945 WND *wndPtr = WIN_FindWndPtr(hwnd);
2946 EDITSTATE *es =
2947 (EDITSTATE *)EDIT_HeapAddr(hwnd, (HANDLE)(*(wndPtr->wExtra)));
2949 es->hDeletedText = GlobalReAlloc(es->hDeletedText, len, GMEM_MOVEABLE);
2950 if (!es->hDeletedText) return;
2951 text = (char *)GlobalLock(es->hDeletedText);
2952 memcpy(text, deltext, len);
2953 GlobalUnlock(es->hDeletedText);
2954 es->DeletedLength = len;
2955 es->DeletedCurrLine = line;
2956 es->DeletedCurrCol = col;
2960 /*********************************************************************
2961 * EDIT_ClearDeletedText
2963 * Clear deleted text buffer.
2966 void EDIT_ClearDeletedText(HWND hwnd)
2968 WND *wndPtr = WIN_FindWndPtr(hwnd);
2969 EDITSTATE *es =
2970 (EDITSTATE *)EDIT_HeapAddr(hwnd, (HANDLE)(*(wndPtr->wExtra)));
2972 GlobalFree(es->hDeletedText);
2973 es->hDeletedText = 0;
2974 es->DeletedLength = 0;
2978 /*********************************************************************
2979 * EM_UNDO message function
2982 LONG EDIT_UndoMsg(HWND hwnd)
2984 char *text;
2985 WND *wndPtr = WIN_FindWndPtr(hwnd);
2986 EDITSTATE *es =
2987 (EDITSTATE *)EDIT_HeapAddr(hwnd, (HANDLE)(*(wndPtr->wExtra)));
2989 if (es->hDeletedText)
2991 text = (char *)GlobalLock(es->hDeletedText);
2992 es->CurrLine = es->DeletedCurrLine;
2993 es->CurrCol = es->DeletedCurrCol;
2994 EDIT_InsertText(hwnd, text, es->DeletedLength);
2995 GlobalUnlock(es->hDeletedText);
2996 EDIT_ClearDeletedText(hwnd);
2998 es->SelBegLine = es->CurrLine;
2999 es->SelBegCol = es->CurrCol;
3000 EDIT_GetLineCol(hwnd, (int)((CurrChar + es->DeletedLength) - text),
3001 &(es->CurrLine), &(es->CurrCol));
3002 es->WndRow = es->CurrLine - es->wtop;
3003 es->WndCol = EDIT_StrLength(hwnd, EDIT_TextLine(hwnd, es->CurrLine),
3004 es->CurrCol, 0) - es->wleft;
3005 es->SelEndLine = es->CurrLine;
3006 es->SelEndCol = es->CurrCol;
3008 InvalidateRect(hwnd, NULL, TRUE);
3009 UpdateWindow(hwnd);
3010 return 1;
3012 else
3013 return 0;
3017 /*********************************************************************
3018 * EDIT_HeapAlloc
3020 * Allocate the specified number of bytes on the specified local heap.
3023 unsigned int EDIT_HeapAlloc(HWND hwnd, int bytes)
3025 WND *wndPtr = WIN_FindWndPtr(hwnd);
3027 return ((unsigned int)HEAP_Alloc((MDESC **)
3028 *(LONG *)(wndPtr->wExtra + 2),
3029 GMEM_MOVEABLE, bytes) & 0xffff);
3033 /*********************************************************************
3034 * EDIT_HeapAddr
3036 * Return the address of the memory pointed to by the handle.
3039 void *EDIT_HeapAddr(HWND hwnd, unsigned int handle)
3041 WND *wndPtr = WIN_FindWndPtr(hwnd);
3043 return ((void *)((handle) ? ((handle) | ((unsigned int)
3044 (*(MDESC **)*(LONG *)(wndPtr->wExtra + 2))
3045 & 0xffff0000)) : 0));
3049 /*********************************************************************
3050 * EDIT_HeapReAlloc
3052 * Reallocate the memory pointed to by the handle.
3055 unsigned int EDIT_HeapReAlloc(HWND hwnd, unsigned int handle, int bytes)
3057 WND *wndPtr = WIN_FindWndPtr(hwnd);
3059 return ((unsigned int)HEAP_ReAlloc((MDESC **)
3060 *(LONG *)(wndPtr->wExtra + 2),
3061 EDIT_HeapAddr(hwnd, handle),
3062 bytes, GMEM_MOVEABLE) & 0xffff);
3066 /*********************************************************************
3067 * EDIT_HeapFree
3069 * Frees the memory pointed to by the handle.
3072 void EDIT_HeapFree(HWND hwnd, unsigned int handle)
3074 WND *wndPtr = WIN_FindWndPtr(hwnd);
3076 HEAP_Free((MDESC **)*(LONG *)(wndPtr->wExtra + 2),
3077 EDIT_HeapAddr(hwnd, handle));
3081 /*********************************************************************
3082 * EDIT_HeapSize
3084 * Return the size of the given object on the local heap.
3087 unsigned int EDIT_HeapSize(HWND hwnd, unsigned int handle)
3089 WND *wndPtr = WIN_FindWndPtr(hwnd);
3091 return HEAP_LocalSize((MDESC **)*(LONG *)(wndPtr->wExtra + 2), handle);
3095 /*********************************************************************
3096 * EM_SETHANDLE message function
3099 void EDIT_SetHandleMsg(HWND hwnd, WORD wParam)
3101 MDESC *m;
3102 WND *wndPtr = WIN_FindWndPtr(hwnd);
3103 EDITSTATE *es =
3104 (EDITSTATE *)EDIT_HeapAddr(hwnd, (HANDLE)(*(wndPtr->wExtra)));
3106 if (IsMultiLine())
3108 es->hText = wParam;
3109 es->MaxTextLen = EDIT_HeapSize(hwnd, es->hText);
3110 es->wlines = 0;
3111 es->wtop = es->wleft = 0;
3112 es->CurrLine = es->CurrCol = 0;
3113 es->WndRow = es->WndCol = 0;
3114 es->TextChanged = FALSE;
3115 es->textwidth = 0;
3116 es->SelBegLine = es->SelBegCol = 0;
3117 es->SelEndLine = es->SelEndCol = 0;
3119 es->PaintBkgd = TRUE;
3120 InvalidateRect(hwnd, NULL, TRUE);
3121 UpdateWindow(hwnd);
3126 /*********************************************************************
3127 * EM_SETTABSTOPS message function
3130 LONG EDIT_SetTabStopsMsg(HWND hwnd, WORD wParam, LONG lParam)
3132 unsigned short *tabstops;
3133 WND *wndPtr = WIN_FindWndPtr(hwnd);
3134 EDITSTATE *es =
3135 (EDITSTATE *)EDIT_HeapAddr(hwnd, (HANDLE)(*(wndPtr->wExtra)));
3137 es->NumTabStops = wParam;
3138 if (wParam == 0)
3139 es->hTabStops = EDIT_HeapReAlloc(hwnd, es->hTabStops, 1);
3140 else if (wParam == 1)
3142 es->hTabStops = EDIT_HeapReAlloc(hwnd, es->hTabStops, 1);
3143 tabstops = (unsigned short *)EDIT_HeapAddr(hwnd, es->hTabStops);
3144 *tabstops = (unsigned short)lParam;
3146 else
3148 es->hTabStops = EDIT_HeapReAlloc(hwnd, es->hTabStops, wParam);
3149 tabstops = (unsigned short *)EDIT_HeapAddr(hwnd, es->hTabStops);
3150 memcpy(tabstops, (unsigned short *)lParam, wParam);
3152 return 0L;
3156 /*********************************************************************
3157 * EDIT_CopyToClipboard
3159 * Copy the specified text to the clipboard.
3162 void EDIT_CopyToClipboard(HWND hwnd)
3164 HANDLE hMem;
3165 char *lpMem;
3166 int i, len;
3167 char *bbl, *bel;
3168 WND *wndPtr = WIN_FindWndPtr(hwnd);
3169 EDITSTATE *es =
3170 (EDITSTATE *)EDIT_HeapAddr(hwnd, (HANDLE)(*(wndPtr->wExtra)));
3172 bbl = EDIT_TextLine(hwnd, es->SelBegLine) + es->SelBegCol;
3173 bel = EDIT_TextLine(hwnd, es->SelEndLine) + es->SelEndCol;
3174 len = (int)(bel - bbl);
3176 hMem = GlobalAlloc(GHND, (DWORD)(len + 1));
3177 lpMem = GlobalLock(hMem);
3179 for (i = 0; i < len; i++)
3180 *lpMem++ = *bbl++;
3182 GlobalUnlock(hMem);
3183 OpenClipboard(hwnd);
3184 EmptyClipboard();
3185 SetClipboardData(CF_TEXT, hMem);
3186 CloseClipboard();
3190 /*********************************************************************
3191 * WM_PASTE message function
3194 void EDIT_PasteMsg(HWND hwnd)
3196 HANDLE hClipMem;
3197 char *lpClipMem;
3199 OpenClipboard(hwnd);
3200 if (!(hClipMem = GetClipboardData(CF_TEXT)))
3202 /* no text in clipboard */
3203 CloseClipboard();
3204 return;
3206 lpClipMem = GlobalLock(hClipMem);
3207 EDIT_InsertText(hwnd, lpClipMem, strlen(lpClipMem));
3208 GlobalUnlock(hClipMem);
3209 CloseClipboard();
3210 InvalidateRect(hwnd, NULL, TRUE);
3211 UpdateWindow(hwnd);
3215 /*********************************************************************
3216 * Utility functions
3219 void swap(int *a, int *b)
3221 int x;
3223 x = *a;
3224 *a = *b;
3225 *b = x;