Release 940714
[wine/multimedia.git] / controls / edit.c
blob977923073f179b4b8af22ff1611955efa4e538cc
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 EDIT_HEAP_ALLOC(size) USER_HEAP_ALLOC(GMEM_MOVEABLE,size)
21 #define EDIT_HEAP_REALLOC(handle,size) USER_HEAP_REALLOC(handle,size,\
22 GMEM_MOVEABLE)
23 #define EDIT_HEAP_ADDR(handle) USER_HEAP_ADDR(handle)
24 #define EDIT_HEAP_FREE(handle) USER_HEAP_FREE(handle)
26 /* #define DEBUG_EDIT /* */
28 #define NOTIFY_PARENT(hWndCntrl, wNotifyCode) \
29 SendMessage(GetParent(hWndCntrl), WM_COMMAND, \
30 GetDlgCtrlID(hWndCntrl), MAKELPARAM(hWndCntrl, wNotifyCode));
32 #define MAXTEXTLEN 30000 /* maximum text buffer length */
33 #define EDITLEN 1024 /* starting length for multi-line control */
34 #define ENTRYLEN 256 /* starting length for single line control */
35 #define GROWLENGTH 64 /* buffers grow by this much */
37 #define HSCROLLDIM (ClientWidth(wndPtr) / 3)
38 /* "line" dimension for horizontal scroll */
41 typedef struct
43 int wlines; /* number of lines of text */
44 int wtop; /* top line that is displayed */
45 int wleft; /* left pixel that is displayed */
46 unsigned int textlen; /* text buffer length */
47 int textwidth; /* width of longest line in pixels */
48 RECT fmtrc; /* rectangle in which to format text */
49 int txtht; /* height of text line in pixels */
50 HANDLE hText; /* handle to text buffer */
51 HANDLE hCharWidths; /* widths of chars in font */
52 HANDLE hTextPtrs; /* list of line offsets */
53 HANDLE hBlankLine; /* to fill blank lines quickly */
54 int CurrCol; /* current column */
55 int CurrLine; /* current line */
56 int WndCol; /* current window column */
57 int WndRow; /* current window row */
58 BOOL TextChanged; /* TRUE if text has changed */
59 BOOL PaintBkgd; /* paint control background */
60 unsigned int MaxTextLen; /* maximum text buffer length */
61 int SelBegLine; /* beginning line of selection */
62 int SelBegCol; /* beginning column of selection */
63 int SelEndLine; /* ending line of selection */
64 int SelEndCol; /* ending column of selection */
65 HFONT hFont; /* handle of current font (if not default) */
66 HANDLE hDeletedText; /* handle to deleted txet buffer for undo */
67 int DeletedLength; /* length of deleted text */
68 int DeletedCurrLine; /* starting line from which text was deleted */
69 int DeletedCurrCol; /* starting col from which text was deleted */
70 int NumTabStops; /* number of tab stops in buffer hTabStops */
71 HANDLE hTabStops; /* handle of tab stops buffer */
72 } EDITSTATE;
75 #define ClientWidth(wndPtr) (wndPtr->rectClient.right - \
76 wndPtr->rectClient.left)
77 #define ClientHeight(wndPtr, es) ((wndPtr->rectClient.bottom - \
78 wndPtr->rectClient.top) / es->txtht)
79 #define EditBufLen(wndPtr) (wndPtr->dwStyle & ES_MULTILINE \
80 ? EDITLEN : ENTRYLEN)
81 #define CurrChar (EDIT_TextLine(hwnd, es->CurrLine) + es->CurrCol)
82 #define SelMarked(es) (es->SelBegLine != 0 || es->SelBegCol != 0 || \
83 es->SelEndLine != 0 || es->SelEndCol != 0)
84 #define ROUNDUP(numer, denom) (((numer) % (denom)) \
85 ? ((((numer) + (denom)) / (denom)) * (denom)) \
86 : (numer) + (denom))
88 /* macros to access window styles */
89 #define IsAutoVScroll() (wndPtr->dwStyle & ES_AUTOVSCROLL)
90 #define IsAutoHScroll() (wndPtr->dwStyle & ES_AUTOHSCROLL)
91 #define IsMultiLine() (wndPtr->dwStyle & ES_MULTILINE)
92 #define IsVScrollBar() (wndPtr->dwStyle & WS_VSCROLL)
93 #define IsHScrollBar() (wndPtr->dwStyle & WS_HSCROLL)
95 /* internal variables */
96 static BOOL TextMarking; /* TRUE if text marking in progress */
97 static BOOL ButtonDown; /* TRUE if left mouse button down */
98 static int ButtonRow; /* row in text buffer when button pressed */
99 static int ButtonCol; /* col in text buffer when button pressed */
100 static BOOL Print = FALSE;
103 LONG EditWndProc(HWND hWnd, WORD uMsg, WORD wParam, LONG lParam);
104 long EDIT_NCCreateMsg(HWND hwnd, LONG lParam);
105 long EDIT_CreateMsg(HWND hwnd, LONG lParam);
106 void EDIT_ClearTextPointers(HWND hwnd);
107 void EDIT_BuildTextPointers(HWND hwnd);
108 void EDIT_ModTextPointers(HWND hwnd, int lineno, int var);
109 void EDIT_PaintMsg(HWND hwnd);
110 HANDLE EDIT_GetTextLine(HWND hwnd, int selection);
111 char *EDIT_TextLine(HWND hwnd, int sel);
112 int EDIT_StrLength(HWND hwnd, char *str, int len, int pcol);
113 int EDIT_LineLength(HWND hwnd, int num);
114 void EDIT_WriteTextLine(HWND hwnd, RECT *rc, int y);
115 void EDIT_WriteText(HWND hwnd, char *lp, int off, int len, int row,
116 int col, RECT *rc, BOOL blank, BOOL reverse);
117 HANDLE EDIT_GetStr(HWND hwnd, char *lp, int off, int len, int *diff);
118 void EDIT_CharMsg(HWND hwnd, WORD wParam);
119 void EDIT_KeyTyped(HWND hwnd, short ch);
120 int EDIT_CharWidth(HWND hwnd, short ch, int pcol);
121 int EDIT_GetNextTabStop(HWND hwnd, int pcol);
122 void EDIT_Forward(HWND hwnd);
123 void EDIT_Downward(HWND hwnd);
124 void EDIT_Upward(HWND hwnd);
125 void EDIT_Backward(HWND hwnd);
126 void EDIT_End(HWND hwnd);
127 void EDIT_Home(HWND hwnd);
128 void EDIT_StickEnd(HWND hwnd);
129 void EDIT_KeyDownMsg(HWND hwnd, WORD wParam);
130 void EDIT_KeyHScroll(HWND hwnd, WORD opt);
131 void EDIT_KeyVScrollLine(HWND hwnd, WORD opt);
132 void EDIT_KeyVScrollPage(HWND hwnd, WORD opt);
133 void EDIT_KeyVScrollDoc(HWND hwnd, WORD opt);
134 int EDIT_ComputeVScrollPos(HWND hwnd);
135 int EDIT_ComputeHScrollPos(HWND hwnd);
136 void EDIT_DelKey(HWND hwnd);
137 void EDIT_VScrollMsg(HWND hwnd, WORD wParam, LONG lParam);
138 void EDIT_VScrollLine(HWND hwnd, WORD opt);
139 void EDIT_VScrollPage(HWND hwnd, WORD opt);
140 void EDIT_HScrollMsg(HWND hwnd, WORD wParam, LONG lParam);
141 void EDIT_SizeMsg(HWND hwnd, WORD wParam, LONG lParam);
142 void EDIT_LButtonDownMsg(HWND hwnd, WORD wParam, LONG lParam);
143 void EDIT_MouseMoveMsg(HWND hwnd, WORD wParam, LONG lParam);
144 int EDIT_PixelToChar(HWND hwnd, int row, int *pixel);
145 LONG EDIT_SetTextMsg(HWND hwnd, LONG lParam);
146 void EDIT_ClearText(HWND hwnd);
147 void EDIT_SetSelMsg(HWND hwnd, WORD wParam, LONG lParam);
148 void EDIT_GetLineCol(HWND hwnd, int off, int *line, int *col);
149 void EDIT_DeleteSel(HWND hwnd);
150 void EDIT_ClearSel(HWND hwnd);
151 int EDIT_TextLineNumber(HWND hwnd, char *lp);
152 void EDIT_SetAnchor(HWND hwnd, int row, int col);
153 void EDIT_ExtendSel(HWND hwnd, int x, int y);
154 void EDIT_WriteSel(HWND hwnd, int y, int start, int end);
155 void EDIT_StopMarking(HWND hwnd);
156 LONG EDIT_GetLineMsg(HWND hwnd, WORD wParam, LONG lParam);
157 LONG EDIT_GetSelMsg(HWND hwnd);
158 void EDIT_ReplaceSel(HWND hwnd, LONG lParam);
159 void EDIT_InsertText(HWND hwnd, char *str, int len);
160 LONG EDIT_LineFromCharMsg(HWND hwnd, WORD wParam);
161 LONG EDIT_LineIndexMsg(HWND hwnd, WORD wParam);
162 LONG EDIT_LineLengthMsg(HWND hwnd, WORD wParam);
163 void EDIT_SetFont(HWND hwnd, WORD wParam, LONG lParam);
164 void EDIT_SaveDeletedText(HWND hwnd, char *deltext, int len, int line,
165 int col);
166 void EDIT_ClearDeletedText(HWND hwnd);
167 LONG EDIT_UndoMsg(HWND hwnd);
168 unsigned int EDIT_HeapAlloc(HWND hwnd, int bytes);
169 void *EDIT_HeapAddr(HWND hwnd, unsigned int handle);
170 unsigned int EDIT_HeapReAlloc(HWND hwnd, unsigned int handle, int bytes);
171 void EDIT_HeapFree(HWND hwnd, unsigned int handle);
172 unsigned int EDIT_HeapSize(HWND hwnd, unsigned int handle);
173 void EDIT_SetHandleMsg(HWND hwnd, WORD wParam);
174 LONG EDIT_SetTabStopsMsg(HWND hwnd, WORD wParam, LONG lParam);
175 void swap(int *a, int *b);
178 LONG EditWndProc(HWND hwnd, WORD uMsg, WORD wParam, LONG lParam)
180 LONG lResult = 0L;
181 HDC hdc;
182 char *textPtr;
183 int len;
184 WND *wndPtr = WIN_FindWndPtr(hwnd);
185 EDITSTATE *es =
186 (EDITSTATE *)EDIT_HeapAddr(hwnd, (HANDLE)(*(wndPtr->wExtra)));
188 switch (uMsg) {
189 case EM_CANUNDO:
190 lResult = es->hDeletedText;
191 break;
193 case EM_EMPTYUNDOBUFFER:
194 EDIT_ClearDeletedText(hwnd);
195 break;
197 case EM_FMTLINES:
198 printf("edit: EM_FMTLINES message received\n");
199 if (!wParam)
200 lResult = 1L;
201 else
202 lResult = 0L;
203 break;
205 case EM_GETFIRSTVISIBLELINE:
206 lResult = es->wtop;
207 break;
209 case EM_GETHANDLE:
210 lResult = es->hText;
211 break;
213 case EM_GETLINE:
214 if (IsMultiLine())
215 lResult = EDIT_GetLineMsg(hwnd, wParam, lParam);
216 else
217 lResult = 0L;
218 break;
220 case EM_GETLINECOUNT:
221 if (IsMultiLine())
222 lResult = es->wlines;
223 else
224 lResult = 0L;
225 break;
227 case EM_GETMODIFY:
228 lResult = es->TextChanged;
229 break;
231 case EM_GETPASSWORDCHAR:
232 printf("edit: cannot process EM_GETPASSWORDCHAR message\n");
233 break;
235 case EM_GETRECT:
236 GetWindowRect(hwnd, (LPRECT)lParam);
237 break;
239 case EM_GETSEL:
240 lResult = EDIT_GetSelMsg(hwnd);
241 break;
243 case EM_GETWORDBREAKPROC:
244 printf("edit: cannot process EM_GETWORDBREAKPROC message\n");
245 break;
247 case EM_LIMITTEXT:
248 if (wParam)
249 es->MaxTextLen = wParam;
250 else if (IsMultiLine())
251 es->MaxTextLen = 65535;
252 else
253 es->MaxTextLen = 32767;
254 break;
256 case EM_LINEFROMCHAR:
257 lResult = EDIT_LineFromCharMsg(hwnd, wParam);
258 break;
260 case EM_LINEINDEX:
261 if (IsMultiLine())
262 lResult = EDIT_LineIndexMsg(hwnd, wParam);
263 else
264 lResult = 0L;
265 break;
267 case EM_LINELENGTH:
268 lResult = EDIT_LineLengthMsg(hwnd, wParam);
269 break;
271 case EM_LINESCROLL:
272 printf("edit: cannot process EM_LINESCROLL message\n");
273 break;
275 case EM_REPLACESEL:
276 HideCaret(hwnd);
277 EDIT_ReplaceSel(hwnd, lParam);
278 SetCaretPos(es->WndCol, es->WndRow * es->txtht);
279 ShowCaret(hwnd);
280 break;
282 case EM_SETHANDLE:
283 EDIT_SetHandleMsg(hwnd, wParam);
284 break;
286 case EM_SETMODIFY:
287 es->TextChanged = wParam;
288 break;
290 case EM_SETPASSWORDCHAR:
291 printf("edit: cannot process EM_SETPASSWORDCHAR message\n");
292 break;
294 case EM_SETREADONLY:
295 printf("edit: cannot process EM_SETREADONLY message\n");
296 break;
298 case EM_SETRECT:
299 case EM_SETRECTNP:
300 printf("edit: cannot process EM_SETRECT(NP) message\n");
301 break;
303 case EM_SETSEL:
304 HideCaret(hwnd);
305 EDIT_SetSelMsg(hwnd, wParam, lParam);
306 SetCaretPos(es->WndCol, es->WndRow * es->txtht);
307 ShowCaret(hwnd);
308 break;
310 case EM_SETTABSTOPS:
311 lResult = EDIT_SetTabStopsMsg(hwnd, wParam, lParam);
312 break;
314 case EM_SETWORDBREAKPROC:
315 printf("edit: cannot process EM_SETWORDBREAKPROC message\n");
316 break;
318 case EM_UNDO:
319 HideCaret(hwnd);
320 lResult = EDIT_UndoMsg(hwnd);
321 SetCaretPos(es->WndCol, es->WndRow * es->txtht);
322 ShowCaret(hwnd);
323 break;
325 case WM_CHAR:
326 EDIT_CharMsg(hwnd, wParam);
327 break;
329 case WM_CREATE:
330 lResult = EDIT_CreateMsg(hwnd, lParam);
331 break;
333 case WM_DESTROY:
334 EDIT_HeapFree(hwnd, es->hTextPtrs);
335 EDIT_HeapFree(hwnd, es->hCharWidths);
336 EDIT_HeapFree(hwnd, es->hText);
337 EDIT_HeapFree(hwnd, (HANDLE)(*(wndPtr->wExtra)));
338 break;
340 case WM_ENABLE:
341 InvalidateRect(hwnd, NULL, FALSE);
342 break;
344 case WM_GETTEXT:
345 textPtr = EDIT_HeapAddr(hwnd, es->hText);
346 if ((int)wParam > (len = strlen(textPtr)))
348 strcpy((char *)lParam, textPtr);
349 lResult = (DWORD)len;
351 else
352 lResult = 0L;
353 break;
355 case WM_GETTEXTLENGTH:
356 textPtr = EDIT_HeapAddr(hwnd, es->hText);
357 lResult = (DWORD)strlen(textPtr);
358 break;
360 case WM_HSCROLL:
361 EDIT_HScrollMsg(hwnd, wParam, lParam);
362 break;
364 case WM_KEYDOWN:
365 EDIT_KeyDownMsg(hwnd, wParam);
366 break;
368 case WM_KILLFOCUS:
369 DestroyCaret();
370 NOTIFY_PARENT(hwnd, EN_KILLFOCUS);
371 break;
373 case WM_LBUTTONDOWN:
374 HideCaret(hwnd);
375 SetFocus(hwnd);
376 EDIT_LButtonDownMsg(hwnd, wParam, lParam);
377 SetCaretPos(es->WndCol, es->WndRow * es->txtht);
378 ShowCaret(hwnd);
379 break;
381 case WM_LBUTTONUP:
382 ButtonDown = FALSE;
383 if (TextMarking)
384 EDIT_StopMarking(hwnd);
385 break;
387 case WM_MOUSEMOVE:
388 HideCaret(hwnd);
389 EDIT_MouseMoveMsg(hwnd, wParam, lParam);
390 SetCaretPos(es->WndCol, es->WndRow * es->txtht);
391 ShowCaret(hwnd);
392 break;
394 case WM_MOVE:
395 lResult = 0;
396 break;
398 case WM_NCCREATE:
399 lResult = EDIT_NCCreateMsg(hwnd, lParam);
400 break;
402 case WM_PAINT:
403 EDIT_PaintMsg(hwnd);
404 break;
406 case WM_SETFOCUS:
407 CreateCaret(hwnd, 0, 2, es->txtht);
408 SetCaretPos(es->WndCol, es->WndRow * es->txtht);
409 ShowCaret(hwnd);
410 NOTIFY_PARENT(hwnd, EN_SETFOCUS);
411 break;
413 case WM_SETFONT:
414 HideCaret(hwnd);
415 EDIT_SetFont(hwnd, wParam, lParam);
416 SetCaretPos(es->WndCol, es->WndRow * es->txtht);
417 ShowCaret(hwnd);
418 break;
420 case WM_SETTEXT:
421 EDIT_SetTextMsg(hwnd, lParam);
422 break;
424 case WM_SIZE:
425 EDIT_SizeMsg(hwnd, wParam, lParam);
426 lResult = 0;
427 break;
429 case WM_VSCROLL:
430 EDIT_VScrollMsg(hwnd, wParam, lParam);
431 break;
433 default:
434 lResult = DefWindowProc(hwnd, uMsg, wParam, lParam);
435 break;
438 GlobalUnlock(hwnd);
439 return lResult;
443 /*********************************************************************
444 * WM_NCCREATE message function
447 long EDIT_NCCreateMsg(HWND hwnd, LONG lParam)
449 CREATESTRUCT *createStruct = (CREATESTRUCT *)lParam;
450 WND *wndPtr = WIN_FindWndPtr(hwnd);
451 EDITSTATE *es;
452 unsigned int *textPtrs;
453 char *text;
454 int len;
456 /* store pointer to local heap in window structure so that */
457 /* EDITSTATE structure itself can be stored on local heap */
458 (MDESC **)*(LONG *)(wndPtr->wExtra + 2) =
459 &HEAP_LocalFindHeap(createStruct->hInstance)->free_list;
461 /* allocate space for state variable structure */
462 (HANDLE)(*(wndPtr->wExtra)) = EDIT_HeapAlloc(hwnd, sizeof(EDITSTATE));
463 es = (EDITSTATE *)EDIT_HeapAddr(hwnd, (HANDLE)(*(wndPtr->wExtra)));
464 es->hTextPtrs = EDIT_HeapAlloc(hwnd, sizeof(int));
465 textPtrs = (unsigned int *)EDIT_HeapAddr(hwnd, es->hTextPtrs);
466 es->hCharWidths = EDIT_HeapAlloc(hwnd, 256 * sizeof(short));
468 /* --- text buffer */
469 es->MaxTextLen = MAXTEXTLEN + 1;
470 if (!(createStruct->lpszName))
472 es->textlen = EditBufLen(wndPtr) + 1;
473 es->hText = EDIT_HeapAlloc(hwnd, EditBufLen(wndPtr) + 2);
474 text = EDIT_HeapAddr(hwnd, es->hText);
475 memset(text, 0, es->textlen + 2);
476 EDIT_ClearTextPointers(hwnd);
478 else
480 if (strlen(createStruct->lpszName) < EditBufLen(wndPtr))
482 es->hText = EDIT_HeapAlloc(hwnd, EditBufLen(wndPtr) + 2);
483 text = EDIT_HeapAddr(hwnd, es->hText);
484 strcpy(text, createStruct->lpszName);
485 *(text + es->textlen) = '\0';
486 es->textlen = EditBufLen(wndPtr) + 1;
488 else
490 es->hText = EDIT_HeapAlloc(hwnd,
491 strlen(createStruct->lpszName) + 2);
492 text = EDIT_HeapAddr(hwnd, es->hText);
493 strcpy(text, createStruct->lpszName);
494 es->textlen = strlen(createStruct->lpszName) + 1;
496 *(text + es->textlen + 1) = '\0';
497 EDIT_BuildTextPointers(hwnd);
500 if ((createStruct->style & WS_VSCROLL) ||
501 (createStruct->style & WS_HSCROLL)) NC_CreateScrollBars(hwnd);
503 /* ES_AUTOVSCROLL and ES_AUTOHSCROLL are automatically applied if */
504 /* the corresponding WM_* message is set */
505 if (createStruct->style & WS_VSCROLL)
506 wndPtr->dwStyle |= ES_AUTOVSCROLL;
507 if (createStruct->style & WS_HSCROLL)
508 wndPtr->dwStyle |= ES_AUTOHSCROLL;
510 /* remove the WS_CAPTION style if it has been set - this is really a */
511 /* pseudo option made from a combination of WS_BORDER and WS_DLGFRAME */
512 if (wndPtr->dwStyle & WS_BORDER && wndPtr->dwStyle & WS_DLGFRAME)
513 wndPtr->dwStyle ^= WS_DLGFRAME;
515 return 1;
519 /*********************************************************************
520 * WM_CREATE message function
523 long EDIT_CreateMsg(HWND hwnd, LONG lParam)
525 HDC hdc;
526 WND *wndPtr = WIN_FindWndPtr(hwnd);
527 EDITSTATE *es =
528 (EDITSTATE *)EDIT_HeapAddr(hwnd, (HANDLE)(*(wndPtr->wExtra)));
529 CLASS *classPtr;
530 short *charWidths;
531 TEXTMETRIC tm;
532 char *text;
534 /* initialize state variable structure */
535 /* --- char width array */
536 hdc = GetDC(hwnd);
537 charWidths = (short *)EDIT_HeapAddr(hwnd, es->hCharWidths);
538 memset(charWidths, 0, 256 * sizeof(short));
539 GetCharWidth(hdc, 0, 255, charWidths);
541 /* --- other structure variables */
542 GetTextMetrics(hdc, &tm);
543 es->txtht = tm.tmHeight + tm.tmExternalLeading;
544 es->wlines = 0;
545 es->wtop = es->wleft = 0;
546 es->CurrCol = es->CurrLine = 0;
547 es->WndCol = es->WndRow = 0;
548 es->TextChanged = FALSE;
549 es->textwidth = 0;
550 es->SelBegLine = es->SelBegCol = 0;
551 es->SelEndLine = es->SelEndCol = 0;
552 es->hFont = 0;
553 es->hDeletedText = 0;
554 es->DeletedLength = 0;
555 es->NumTabStops = 0;
556 es->hTabStops = EDIT_HeapAlloc(hwnd, sizeof(int));
558 /* allocate space for a line full of blanks to speed up */
559 /* line filling */
560 es->hBlankLine = EDIT_HeapAlloc(hwnd, (ClientWidth(wndPtr) /
561 charWidths[32]) + 2);
562 text = EDIT_HeapAddr(hwnd, es->hBlankLine);
563 memset(text, ' ', (ClientWidth(wndPtr) / charWidths[32]) + 2);
565 /* set up text cursor for edit class */
566 CLASS_FindClassByName("EDIT", &classPtr);
567 classPtr->wc.hCursor = LoadCursor(0, IDC_IBEAM);
569 /* paint background on first WM_PAINT */
570 es->PaintBkgd = TRUE;
572 ReleaseDC(hwnd, hdc);
573 return 0L;
577 /*********************************************************************
578 * EDIT_ClearTextPointers
580 * Clear and initialize text line pointer array.
583 void EDIT_ClearTextPointers(HWND hwnd)
585 unsigned int *textPtrs;
586 WND *wndPtr = WIN_FindWndPtr(hwnd);
587 EDITSTATE *es =
588 (EDITSTATE *)EDIT_HeapAddr(hwnd, (HANDLE)(*(wndPtr->wExtra)));
590 es->hTextPtrs = EDIT_HeapReAlloc(hwnd, es->hTextPtrs, sizeof(int));
591 textPtrs = (unsigned int *)EDIT_HeapAddr(hwnd, es->hTextPtrs);
592 *textPtrs = 0;
596 /*********************************************************************
597 * EDIT_BuildTextPointers
599 * Build array of pointers to text lines.
602 #define INITLINES 100
604 void EDIT_BuildTextPointers(HWND hwnd)
606 WND *wndPtr = WIN_FindWndPtr(hwnd);
607 char *text, *cp;
608 int incrs = INITLINES;
609 unsigned int off, len, temp;
610 EDITSTATE *es;
611 unsigned int *textPtrs;
612 short *charWidths;
614 es = (EDITSTATE *)EDIT_HeapAddr(hwnd, (HANDLE)(*(wndPtr->wExtra)));
615 text = EDIT_HeapAddr(hwnd, es->hText);
616 textPtrs = (unsigned int *)EDIT_HeapAddr(hwnd, es->hTextPtrs);
617 charWidths = (short *)EDIT_HeapAddr(hwnd, es->hCharWidths);
619 es->textwidth = es->wlines = 0;
620 cp = text;
622 /* advance through text buffer */
623 while (*cp)
625 /* increase size of text pointer array */
626 if (incrs == INITLINES)
628 incrs = 0;
629 es->hTextPtrs = EDIT_HeapReAlloc(hwnd, es->hTextPtrs,
630 (es->wlines + INITLINES) * sizeof(int));
631 textPtrs = (unsigned int *)EDIT_HeapAddr(hwnd, es->hTextPtrs);
633 off = (unsigned int)(cp - text); /* offset of beginning of line */
634 *(textPtrs + es->wlines) = off;
635 es->wlines++;
636 incrs++;
637 len = 0;
639 /* advance through current line */
640 while (*cp && *cp != '\n')
642 len += EDIT_CharWidth(hwnd, *cp, len);
643 /* width of line in pixels */
644 cp++;
646 es->textwidth = max(es->textwidth, len);
647 if (*cp)
648 cp++; /* skip '\n' */
651 off = (unsigned int)(cp - text);
652 *(textPtrs + es->wlines) = off;
656 /*********************************************************************
657 * EDIT_ModTextPointers
659 * Modify text pointers from a specified position.
662 void EDIT_ModTextPointers(HWND hwnd, int lineno, int var)
664 WND *wndPtr = WIN_FindWndPtr(hwnd);
665 EDITSTATE *es =
666 (EDITSTATE *)EDIT_HeapAddr(hwnd, (HANDLE)(*(wndPtr->wExtra)));
667 unsigned int *textPtrs =
668 (unsigned int *)EDIT_HeapAddr(hwnd, es->hTextPtrs);
670 while (lineno < es->wlines)
671 *(textPtrs + lineno++) += var;
675 /*********************************************************************
676 * WM_PAINT message function
679 void EDIT_PaintMsg(HWND hwnd)
681 PAINTSTRUCT ps;
682 HDC hdc;
683 int y;
684 RECT rc;
685 WND *wndPtr = WIN_FindWndPtr(hwnd);
686 EDITSTATE *es =
687 (EDITSTATE *)EDIT_HeapAddr(hwnd, (HANDLE)(*(wndPtr->wExtra)));
689 hdc = BeginPaint(hwnd, &ps);
690 rc = ps.rcPaint;
692 #ifdef DEBUG_EDIT
693 printf("WM_PAINT: rc=(%d,%d), (%d,%d)\n", rc.left, rc.top,
694 rc.right, rc.bottom);
695 #endif
697 if (es->PaintBkgd)
698 FillWindow(GetParent(hwnd), hwnd, hdc, CTLCOLOR_EDIT);
700 for (y = (rc.top / es->txtht); y <= (rc.bottom / es->txtht); y++)
702 if (y < es->wlines - es->wtop)
703 EDIT_WriteTextLine(hwnd, &rc, y + es->wtop);
706 EndPaint(hwnd, &ps);
710 /*********************************************************************
711 * EDIT_GetTextLine
713 * Get a copy of the text in the specified line.
716 HANDLE EDIT_GetTextLine(HWND hwnd, int selection)
718 char *line;
719 HANDLE hLine;
720 int len = 0;
721 char *cp, *cp1;
723 #ifdef DEBUG_EDIT
724 printf("GetTextLine %d\n", selection);
725 #endif
726 cp = cp1 = EDIT_TextLine(hwnd, selection);
727 /* advance through line */
728 while (*cp && *cp != '\n')
730 len++;
731 cp++;
734 /* store selected line and return handle */
735 hLine = EDIT_HeapAlloc(hwnd, len + 6);
736 line = (char *)EDIT_HeapAddr(hwnd, hLine);
737 memmove(line, cp1, len);
738 line[len] = '\0';
739 return hLine;
743 /*********************************************************************
744 * EDIT_TextLine
746 * Return a pointer to the text in the specified line.
749 char *EDIT_TextLine(HWND hwnd, int sel)
751 WND *wndPtr = WIN_FindWndPtr(hwnd);
752 EDITSTATE *es =
753 (EDITSTATE *)EDIT_HeapAddr(hwnd, (HANDLE)(*(wndPtr->wExtra)));
754 char *text = EDIT_HeapAddr(hwnd, es->hText);
755 unsigned int *textPtrs =
756 (unsigned int *)EDIT_HeapAddr(hwnd, es->hTextPtrs);
758 return (text + *(textPtrs + sel));
762 /*********************************************************************
763 * EDIT_StrLength
765 * Return length of string _str_ of length _len_ characters in pixels.
766 * The current column offset in pixels _pcol_ is required to calculate
767 * the width of a tab.
770 int EDIT_StrLength(HWND hwnd, char *str, int len, int pcol)
772 int i, plen = 0;
773 WND *wndPtr = WIN_FindWndPtr(hwnd);
774 EDITSTATE *es =
775 (EDITSTATE *)EDIT_HeapAddr(hwnd, (HANDLE)(*(wndPtr->wExtra)));
777 for (i = 0; i < len; i++)
778 plen += EDIT_CharWidth(hwnd, *(str + i), pcol + plen);
780 #ifdef DEBUG_EDIT
781 printf("EDIT_StrLength: returning %d\n", plen);
782 #endif
783 return plen;
787 /*********************************************************************
788 * EDIT_LineLength
790 * Return length of line _num_ in characters.
793 int EDIT_LineLength(HWND hwnd, int num)
795 WND *wndPtr = WIN_FindWndPtr(hwnd);
796 EDITSTATE *es =
797 (EDITSTATE *)EDIT_HeapAddr(hwnd, (HANDLE)(*(wndPtr->wExtra)));
798 char *cp = EDIT_TextLine(hwnd, num);
799 char *cp1;
801 cp1 = strchr(cp, '\n');
802 return cp1 ? (int)(cp1 - cp) : strlen(cp);
806 /*********************************************************************
807 * EDIT_WriteTextLine
809 * Write the line of text at offset _y_ in text buffer to a window.
812 void EDIT_WriteTextLine(HWND hwnd, RECT *rect, int y)
814 int len = 0;
815 unsigned char line[200];
816 HANDLE hLine;
817 unsigned char *lp;
818 int lnlen, lnlen1;
819 int col, off = 0;
820 int sbl, sel, sbc, sec;
821 RECT rc;
822 BOOL trunc = FALSE;
823 WND *wndPtr = WIN_FindWndPtr(hwnd);
824 EDITSTATE *es =
825 (EDITSTATE *)EDIT_HeapAddr(hwnd, (HANDLE)(*(wndPtr->wExtra)));
827 /* initialize rectangle if NULL, else copy */
828 if (rect)
829 CopyRect(&rc, rect);
830 else
831 GetClientRect(hwnd, &rc);
833 #ifdef DEBUG_EDIT
834 printf("WriteTextLine %d\n", y);
835 #endif
837 /* make sure y is inside the window */
838 if (y < es->wtop || y > (es->wtop + ClientHeight(wndPtr, es)))
840 #ifdef DEBUG_EDIT
841 printf("EDIT_WriteTextLine: y (%d) is not a displayed line\n", y);
842 #endif
843 return;
846 /* make sure rectangle is within window */
847 if (rc.left >= ClientWidth(wndPtr) - 1)
849 #ifdef DEBUG_EDIT
850 printf("EDIT_WriteTextLine: rc.left (%d) is greater than right edge\n",
851 rc.left);
852 #endif
853 return;
855 if (rc.right <= 0)
857 #ifdef DEBUG_EDIT
858 printf("EDIT_WriteTextLine: rc.right (%d) is less than left edge\n",
859 rc.right);
860 #endif
861 return;
863 if (y - es->wtop < (rc.top / es->txtht) ||
864 y - es->wtop > (rc.bottom / es->txtht))
866 #ifdef DEBUG_EDIT
867 printf("EDIT_WriteTextLine: y (%d) is outside window\n", y);
868 #endif
869 return;
872 /* get the text and length of line */
873 if ((hLine = EDIT_GetTextLine(hwnd, y)) == 0)
874 return;
875 lp = (unsigned char *)EDIT_HeapAddr(hwnd, hLine);
876 lnlen = EDIT_StrLength(hwnd, lp, strlen(lp), 0);
877 lnlen1 = lnlen;
879 /* build the line to display */
880 if (lnlen < es->wleft)
881 lnlen = 0;
882 else
883 off += es->wleft;
885 if (lnlen > rc.left)
887 off += rc.left;
888 lnlen = lnlen1 - off;
889 len = min(lnlen, rc.right - rc.left);
892 if (SelMarked(es))
894 sbl = es->SelBegLine;
895 sel = es->SelEndLine;
896 sbc = es->SelBegCol;
897 sec = es->SelEndCol;
899 /* put lowest marker first */
900 if (sbl > sel)
902 swap(&sbl, &sel);
903 swap(&sbc, &sec);
905 if (sbl == sel && sbc > sec)
906 swap(&sbc, &sec);
908 if (y < sbl || y > sel)
909 EDIT_WriteText(hwnd, lp, off, len, y - es->wtop, rc.left, &rc,
910 TRUE, FALSE);
911 else if (y > sbl && y < sel)
912 EDIT_WriteText(hwnd, lp, off, len, y - es->wtop, rc.left, &rc,
913 TRUE, TRUE);
914 else if (y == sbl)
916 col = EDIT_StrLength(hwnd, lp, sbc, 0);
917 if (col > (es->wleft + rc.left))
919 len = min(col - off, rc.right - off);
920 EDIT_WriteText(hwnd, lp, off, len, y - es->wtop,
921 rc.left, &rc, FALSE, FALSE);
922 off = col;
924 if (y == sel)
926 col = EDIT_StrLength(hwnd, lp, sec, 0);
927 if (col < (es->wleft + rc.right))
929 len = min(col - off, rc.right - off);
930 EDIT_WriteText(hwnd, lp, off, len, y - es->wtop,
931 off - es->wleft, &rc, FALSE, TRUE);
932 off = col;
933 len = min(lnlen - off, rc.right - off);
934 EDIT_WriteText(hwnd, lp, off, len, y - es->wtop,
935 off - es->wleft, &rc, TRUE, FALSE);
937 else
939 len = min(lnlen - off, rc.right - off);
940 EDIT_WriteText(hwnd, lp, off, len, y - es->wtop,
941 off - es->wleft, &rc, TRUE, TRUE);
944 else
946 len = min(lnlen - off, rc.right - off);
947 if (col < (es->wleft + rc.right))
948 EDIT_WriteText(hwnd, lp, off, len, y - es->wtop,
949 off - es->wleft, &rc, TRUE, TRUE);
952 else if (y == sel)
954 col = EDIT_StrLength(hwnd, lp, sec, 0);
955 if (col < (es->wleft + rc.right))
957 len = min(col - off, rc.right - off);
958 EDIT_WriteText(hwnd, lp, off, len, y - es->wtop,
959 off - es->wleft, &rc, FALSE, TRUE);
960 off = col;
961 len = min(lnlen - off, rc.right - off);
962 EDIT_WriteText(hwnd, lp, off, len, y - es->wtop,
963 off - es->wleft, &rc, TRUE, FALSE);
967 else
968 EDIT_WriteText(hwnd, lp, off, len, y - es->wtop, rc.left, &rc,
969 TRUE, FALSE);
971 EDIT_HeapFree(hwnd, hLine);
975 /*********************************************************************
976 * EDIT_WriteText
978 * Write text to a window
979 * lp - text line
980 * off - offset in text line (in pixels)
981 * len - length from off (in pixels)
982 * row - line in window
983 * col - column in window
984 * rc - rectangle in which to display line
985 * blank - blank remainder of line?
986 * reverse - reverse color of line?
989 void EDIT_WriteText(HWND hwnd, char *lp, int off, int len, int row,
990 int col, RECT *rc, BOOL blank, BOOL reverse)
992 HDC hdc;
993 HANDLE hStr;
994 char *str, *cp, *cp1;
995 int diff, num_spaces, tabwidth, scol;
996 HRGN hrgnClip;
997 COLORREF oldTextColor, oldBkgdColor;
998 HFONT oldfont;
999 WND *wndPtr = WIN_FindWndPtr(hwnd);
1000 EDITSTATE *es =
1001 (EDITSTATE *)EDIT_HeapAddr(hwnd, (HANDLE)(*(wndPtr->wExtra)));
1002 short *charWidths = (short *)EDIT_HeapAddr(hwnd, es->hCharWidths);
1003 char *blanks = (char *)EDIT_HeapAddr(hwnd, es->hBlankLine);
1005 #ifdef DEBUG_EDIT
1006 printf("EDIT_WriteText lp=%s, off=%d, len=%d, row=%d, col=%d, reverse=%d\n", lp, off, len, row, col, reverse);
1007 #endif
1009 hdc = GetDC(hwnd);
1010 hStr = EDIT_GetStr(hwnd, lp, off, len, &diff);
1011 str = (char *)EDIT_HeapAddr(hwnd, hStr);
1012 hrgnClip = CreateRectRgnIndirect(rc);
1013 SelectClipRgn(hdc, hrgnClip);
1015 if (es->hFont)
1016 oldfont = (HFONT)SelectObject(hdc, (HANDLE)es->hFont);
1018 SendMessage(GetParent(hwnd), WM_CTLCOLOR, (WORD)hdc,
1019 MAKELPARAM(hwnd, CTLCOLOR_EDIT));
1021 if (reverse)
1023 oldBkgdColor = GetBkColor(hdc);
1024 oldTextColor = GetTextColor(hdc);
1025 SetBkColor(hdc, oldTextColor);
1026 SetTextColor(hdc, oldBkgdColor);
1029 if (!(cp = strchr(str, VK_TAB)))
1030 TextOut(hdc, col - diff, row * es->txtht, str, strlen(str));
1031 else
1033 TextOut(hdc, col - diff, row * es->txtht, str, (int)(cp - str));
1034 scol = EDIT_StrLength(hwnd, str, (int)(cp - str), 0);
1035 tabwidth = EDIT_CharWidth(hwnd, VK_TAB, scol);
1036 num_spaces = tabwidth / charWidths[32] + 1;
1037 TextOut(hdc, scol, row * es->txtht, blanks, num_spaces);
1038 cp++;
1039 scol += tabwidth;
1041 while (cp1 = strchr(cp, VK_TAB))
1043 TextOut(hdc, scol, row * es->txtht, cp, (int)(cp1 - cp));
1044 scol += EDIT_StrLength(hwnd, cp, (int)(cp1 - cp), scol);
1045 tabwidth = EDIT_CharWidth(hwnd, VK_TAB, scol);
1046 num_spaces = tabwidth / charWidths[32] + 1;
1047 TextOut(hdc, scol, row * es->txtht, blanks, num_spaces);
1048 cp = ++cp1;
1049 scol += tabwidth;
1052 TextOut(hdc, scol, row * es->txtht, cp, strlen(cp));
1055 if (reverse)
1057 SetBkColor(hdc, oldBkgdColor);
1058 SetTextColor(hdc, oldTextColor);
1061 /* blank out remainder of line if appropriate */
1062 if (blank)
1064 if ((rc->right - col) > len)
1066 num_spaces = (rc->right - col - len) / charWidths[32];
1067 TextOut(hdc, col + len, row * es->txtht, blanks, num_spaces);
1071 if (es->hFont)
1072 SelectObject(hdc, (HANDLE)oldfont);
1074 EDIT_HeapFree(hwnd, hStr);
1075 ReleaseDC(hwnd, hdc);
1079 /*********************************************************************
1080 * EDIT_GetStr
1082 * Return sub-string starting at pixel _off_ of length _len_ pixels.
1083 * If _off_ is part way through a character, the negative offset of
1084 * the beginning of the character is returned in _diff_, else _diff_
1085 * will be zero.
1088 HANDLE EDIT_GetStr(HWND hwnd, char *lp, int off, int len, int *diff)
1090 HANDLE hStr;
1091 char *str;
1092 int ch = 0, i = 0, j, s_i;
1093 int ch1;
1094 WND *wndPtr = WIN_FindWndPtr(hwnd);
1095 EDITSTATE *es =
1096 (EDITSTATE *)EDIT_HeapAddr(hwnd, (HANDLE)(*(wndPtr->wExtra)));
1098 #ifdef DEBUG_EDIT
1099 printf("EDIT_GetStr %s %d %d\n", lp, off, len);
1100 #endif
1102 while (i < off)
1104 s_i = i;
1105 i += EDIT_CharWidth(hwnd, *(lp + ch), i);
1106 ch++;
1109 /* if stepped past _off_, go back a character */
1110 if (i - off)
1112 i = s_i;
1113 ch--;
1115 *diff = off - i;
1116 ch1 = ch;
1118 while (i < len + off)
1120 i += EDIT_CharWidth(hwnd, *(lp + ch), i);
1121 ch++;
1124 hStr = EDIT_HeapAlloc(hwnd, ch - ch1 + 3);
1125 str = (char *)EDIT_HeapAddr(hwnd, hStr);
1126 for (i = ch1, j = 0; i < ch; i++, j++)
1127 str[j] = lp[i];
1128 str[++j] = '\0';
1129 #ifdef DEBUG_EDIT
1130 printf("EDIT_GetStr: returning %s\n", str);
1131 #endif
1132 return hStr;
1136 /*********************************************************************
1137 * WM_CHAR message function
1140 void EDIT_CharMsg(HWND hwnd, WORD wParam)
1142 WND *wndPtr = WIN_FindWndPtr(hwnd);
1143 EDITSTATE *es =
1144 (EDITSTATE *)EDIT_HeapAddr(hwnd, (HANDLE)(*(wndPtr->wExtra)));
1146 #ifdef DEBUG_EDIT
1147 printf("EDIT_CharMsg: wParam=%c\n", (char)wParam);
1148 #endif
1150 switch (wParam)
1152 case '\r':
1153 case '\n':
1154 if (!IsMultiLine())
1155 break;
1156 wParam = '\n';
1157 EDIT_KeyTyped(hwnd, wParam);
1158 break;
1160 case VK_TAB:
1161 if (!IsMultiLine())
1162 break;
1163 EDIT_KeyTyped(hwnd, wParam);
1164 break;
1166 default:
1167 if (wParam >= 20 && wParam <= 126)
1168 EDIT_KeyTyped(hwnd, wParam);
1169 break;
1174 /*********************************************************************
1175 * EDIT_KeyTyped
1177 * Process keystrokes that produce displayable characters.
1180 void EDIT_KeyTyped(HWND hwnd, short ch)
1182 WND *wndPtr = WIN_FindWndPtr(hwnd);
1183 EDITSTATE *es =
1184 (EDITSTATE *)EDIT_HeapAddr(hwnd, (HANDLE)(*(wndPtr->wExtra)));
1185 char *text = EDIT_HeapAddr(hwnd, es->hText);
1186 char *currchar = CurrChar;
1187 RECT rc;
1188 BOOL FullPaint = FALSE;
1190 #ifdef DEBUG_EDIT
1191 printf("EDIT_KeyTyped: ch=%c\n", (char)ch);
1192 #endif
1194 /* delete selected text (if any) */
1195 if (SelMarked(es))
1196 EDIT_DeleteSel(hwnd);
1198 /* test for typing at end of maximum buffer size */
1199 if (currchar == text + es->MaxTextLen)
1201 NOTIFY_PARENT(hwnd, EN_ERRSPACE);
1202 return;
1205 if (*currchar == '\0' && IsMultiLine())
1207 /* insert a newline at end of text */
1208 *currchar = '\n';
1209 *(currchar + 1) = '\0';
1210 EDIT_BuildTextPointers(hwnd);
1213 /* insert the typed character */
1214 if (text[es->textlen - 1] != '\0')
1216 /* current text buffer is full */
1217 if (es->textlen == es->MaxTextLen)
1219 /* text buffer is at maximum size */
1220 NOTIFY_PARENT(hwnd, EN_ERRSPACE);
1221 return;
1224 /* increase the text buffer size */
1225 es->textlen += GROWLENGTH;
1226 /* but not above maximum size */
1227 if (es->textlen > es->MaxTextLen)
1228 es->textlen = es->MaxTextLen;
1229 es->hText = EDIT_HeapReAlloc(hwnd, es->hText, es->textlen + 2);
1230 if (!es->hText)
1231 NOTIFY_PARENT(hwnd, EN_ERRSPACE);
1232 text = EDIT_HeapAddr(hwnd, es->hText);
1233 text[es->textlen - 1] = '\0';
1234 currchar = CurrChar;
1236 /* make space for new character and put char in buffer */
1237 memmove(currchar + 1, currchar, strlen(currchar) + 1);
1238 *currchar = ch;
1239 EDIT_ModTextPointers(hwnd, es->CurrLine + 1, 1);
1240 es->TextChanged = TRUE;
1241 NOTIFY_PARENT(hwnd, EN_UPDATE);
1243 /* re-adjust textwidth, if necessary, and redraw line */
1244 HideCaret(hwnd);
1245 if (IsMultiLine() && es->wlines > 1)
1247 es->textwidth = max(es->textwidth,
1248 EDIT_StrLength(hwnd, EDIT_TextLine(hwnd, es->CurrLine),
1249 (int)(EDIT_TextLine(hwnd, es->CurrLine + 1) -
1250 EDIT_TextLine(hwnd, es->CurrLine)), 0));
1252 else
1253 es->textwidth = max(es->textwidth,
1254 EDIT_StrLength(hwnd, text, strlen(text), 0));
1255 EDIT_WriteTextLine(hwnd, NULL, es->wtop + es->WndRow);
1257 if (ch == '\n')
1259 if (es->wleft > 0)
1260 FullPaint = TRUE;
1261 es->wleft = 0;
1262 EDIT_BuildTextPointers(hwnd);
1263 EDIT_End(hwnd);
1264 EDIT_Forward(hwnd);
1266 /* invalidate rest of window */
1267 GetClientRect(hwnd, &rc);
1268 if (!FullPaint)
1269 rc.top = es->WndRow * es->txtht;
1270 InvalidateRect(hwnd, &rc, FALSE);
1272 SetCaretPos(es->WndCol, es->WndRow * es->txtht);
1273 ShowCaret(hwnd);
1274 UpdateWindow(hwnd);
1275 NOTIFY_PARENT(hwnd, EN_CHANGE);
1276 return;
1279 /* test end of window */
1280 if (es->WndCol >= ClientWidth(wndPtr) -
1281 EDIT_CharWidth(hwnd, ch, es->WndCol + es->wleft))
1283 /* TODO:- Word wrap to be handled here */
1285 /* if (!(currchar == text + es->MaxTextLen - 2)) */
1286 EDIT_KeyHScroll(hwnd, SB_LINEDOWN);
1288 es->WndCol += EDIT_CharWidth(hwnd, ch, es->WndCol + es->wleft);
1289 es->CurrCol++;
1290 SetCaretPos(es->WndCol, es->WndRow * es->txtht);
1291 ShowCaret(hwnd);
1292 NOTIFY_PARENT(hwnd, EN_CHANGE);
1296 /*********************************************************************
1297 * EDIT_CharWidth
1299 * Return the width of the given character in pixels.
1300 * The current column offset in pixels _pcol_ is required to calculate
1301 * the width of a tab.
1304 int EDIT_CharWidth(HWND hwnd, short ch, int pcol)
1306 WND *wndPtr = WIN_FindWndPtr(hwnd);
1307 EDITSTATE *es =
1308 (EDITSTATE *)EDIT_HeapAddr(hwnd, (HANDLE)(*(wndPtr->wExtra)));
1309 short *charWidths = (short *)EDIT_HeapAddr(hwnd, es->hCharWidths);
1311 if (ch != VK_TAB)
1312 return (charWidths[ch]);
1313 else
1314 return (EDIT_GetNextTabStop(hwnd, pcol) - pcol);
1318 /*********************************************************************
1319 * EDIT_GetNextTabStop
1321 * Return the next tab stop beyond _pcol_.
1324 int EDIT_GetNextTabStop(HWND hwnd, int pcol)
1326 int i, tmp;
1327 int baseUnitWidth = LOWORD(GetDialogBaseUnits());
1328 WND *wndPtr = WIN_FindWndPtr(hwnd);
1329 EDITSTATE *es =
1330 (EDITSTATE *)EDIT_HeapAddr(hwnd, (HANDLE)(*(wndPtr->wExtra)));
1331 unsigned short *tabstops = EDIT_HeapAddr(hwnd, es->hTabStops);
1333 if (es->NumTabStops == 0)
1334 return ROUNDUP(pcol, 8 * baseUnitWidth);
1335 else if (es->NumTabStops == 1)
1336 return ROUNDUP(pcol, *tabstops * baseUnitWidth / 4);
1337 else
1339 for (i = 0; i < es->NumTabStops; i++)
1341 if (*(tabstops + i) * baseUnitWidth / 4 >= pcol)
1342 return (*(tabstops + i) * baseUnitWidth / 4);
1344 return pcol;
1349 /*********************************************************************
1350 * EDIT_Forward
1352 * Cursor right key: move right one character position.
1355 void EDIT_Forward(HWND hwnd)
1357 WND *wndPtr = WIN_FindWndPtr(hwnd);
1358 EDITSTATE *es =
1359 (EDITSTATE *)EDIT_HeapAddr(hwnd, (HANDLE)(*(wndPtr->wExtra)));
1360 char *text = EDIT_HeapAddr(hwnd, es->hText);
1362 if (*CurrChar == '\0')
1363 return;
1365 if (*CurrChar == '\n')
1367 EDIT_Home(hwnd);
1368 EDIT_Downward(hwnd);
1370 else
1372 es->WndCol += EDIT_CharWidth(hwnd, *CurrChar, es->WndCol + es->wleft);
1373 es->CurrCol++;
1374 if (es->WndCol >= ClientWidth(wndPtr))
1375 EDIT_KeyHScroll(hwnd, SB_LINEDOWN);
1381 /*********************************************************************
1382 * EDIT_Downward
1384 * Cursor down key: move down one line.
1387 void EDIT_Downward(HWND hwnd)
1389 WND *wndPtr = WIN_FindWndPtr(hwnd);
1390 EDITSTATE *es =
1391 (EDITSTATE *)EDIT_HeapAddr(hwnd, (HANDLE)(*(wndPtr->wExtra)));
1393 #ifdef DEBUG_EDIT
1394 printf("EDIT_Downward: WndRow=%d, wtop=%d, wlines=%d\n", es->WndRow, es->wtop, es->wlines);
1395 #endif
1397 if (IsMultiLine() && (es->WndRow + es->wtop + 1 < es->wlines))
1399 es->CurrLine++;
1400 if (es->WndRow == ClientHeight(wndPtr, es) - 1)
1402 es->WndRow++;
1403 EDIT_KeyVScrollLine(hwnd, SB_LINEDOWN);
1405 else
1406 es->WndRow++;
1407 EDIT_StickEnd(hwnd);
1412 /*********************************************************************
1413 * EDIT_Upward
1415 * Cursor up key: move up one line.
1418 void EDIT_Upward(HWND hwnd)
1420 WND *wndPtr = WIN_FindWndPtr(hwnd);
1421 EDITSTATE *es =
1422 (EDITSTATE *)EDIT_HeapAddr(hwnd, (HANDLE)(*(wndPtr->wExtra)));
1424 if (IsMultiLine() && es->CurrLine != 0)
1426 --es->CurrLine;
1427 if (es->WndRow == 0)
1429 --es->WndRow;
1430 EDIT_KeyVScrollLine(hwnd, SB_LINEUP);
1432 else
1433 --es->WndRow;
1434 EDIT_StickEnd(hwnd);
1439 /*********************************************************************
1440 * EDIT_Backward
1442 * Cursor left key: move left one character position.
1445 void EDIT_Backward(HWND hwnd)
1447 WND *wndPtr = WIN_FindWndPtr(hwnd);
1448 EDITSTATE *es =
1449 (EDITSTATE *)EDIT_HeapAddr(hwnd, (HANDLE)(*(wndPtr->wExtra)));
1450 char *text = EDIT_HeapAddr(hwnd, es->hText);
1452 if (es->CurrCol)
1454 --es->CurrCol;
1455 if (*CurrChar == VK_TAB)
1456 es->WndCol -= EDIT_CharWidth(hwnd, *CurrChar,
1457 EDIT_StrLength(hwnd,
1458 EDIT_TextLine(hwnd, es->CurrLine),
1459 es->CurrCol, 0));
1460 else
1461 es->WndCol -= EDIT_CharWidth(hwnd, *CurrChar, 0);
1462 if (es->WndCol < 0)
1463 EDIT_KeyHScroll(hwnd, SB_LINEUP);
1465 else if (IsMultiLine() && es->CurrLine != 0)
1467 EDIT_Upward(hwnd);
1468 EDIT_End(hwnd);
1473 /*********************************************************************
1474 * EDIT_End
1476 * End key: move to end of line.
1479 void EDIT_End(HWND hwnd)
1481 RECT rc;
1482 WND *wndPtr = WIN_FindWndPtr(hwnd);
1483 EDITSTATE *es =
1484 (EDITSTATE *)EDIT_HeapAddr(hwnd, (HANDLE)(*(wndPtr->wExtra)));
1485 char *text = EDIT_HeapAddr(hwnd, es->hText);
1487 while (*CurrChar && *CurrChar != '\n')
1489 es->WndCol += EDIT_CharWidth(hwnd, *CurrChar, es->WndCol + es->wleft);
1490 es->CurrCol++;
1493 if (es->WndCol >= ClientWidth(wndPtr))
1495 es->wleft = es->WndCol - ClientWidth(wndPtr) + HSCROLLDIM;
1496 es->WndCol -= es->wleft;
1497 InvalidateRect(hwnd, NULL, FALSE);
1498 UpdateWindow(hwnd);
1503 /*********************************************************************
1504 * EDIT_Home
1506 * Home key: move to beginning of line.
1509 void EDIT_Home(HWND hwnd)
1511 RECT rc;
1512 WND *wndPtr = WIN_FindWndPtr(hwnd);
1513 EDITSTATE *es =
1514 (EDITSTATE *)EDIT_HeapAddr(hwnd, (HANDLE)(*(wndPtr->wExtra)));
1516 es->CurrCol = es->WndCol = 0;
1517 if (es->wleft != 0)
1519 es->wleft = 0;
1520 InvalidateRect(hwnd, NULL, FALSE);
1521 UpdateWindow(hwnd);
1526 /*********************************************************************
1527 * EDIT_StickEnd
1529 * Stick the cursor to the end of the line.
1532 void EDIT_StickEnd(HWND hwnd)
1534 WND *wndPtr = WIN_FindWndPtr(hwnd);
1535 EDITSTATE *es =
1536 (EDITSTATE *)EDIT_HeapAddr(hwnd, (HANDLE)(*(wndPtr->wExtra)));
1537 int len = EDIT_LineLength(hwnd, es->CurrLine);
1538 char *cp = EDIT_TextLine(hwnd, es->CurrLine);
1539 char currpel;
1541 es->CurrCol = min(len, es->CurrCol);
1542 es->WndCol = min(EDIT_StrLength(hwnd, cp, len, 0) - es->wleft, es->WndCol);
1543 currpel = EDIT_StrLength(hwnd, cp, es->CurrCol, 0);
1545 if (es->wleft > currpel)
1547 es->wleft = max(0, currpel - 20);
1548 es->WndCol = currpel - es->wleft;
1549 UpdateWindow(hwnd);
1551 else if (currpel - es->wleft >= ClientWidth(wndPtr))
1553 es->wleft = currpel - (ClientWidth(wndPtr) - 5);
1554 es->WndCol = currpel - es->wleft;
1555 UpdateWindow(hwnd);
1560 /*********************************************************************
1561 * WM_KEYDOWN message function
1564 void EDIT_KeyDownMsg(HWND hwnd, WORD wParam)
1566 WND *wndPtr = WIN_FindWndPtr(hwnd);
1567 EDITSTATE *es =
1568 (EDITSTATE *)EDIT_HeapAddr(hwnd, (HANDLE)(*(wndPtr->wExtra)));
1570 #ifdef DEBUG_EDIT
1571 printf("EDIT_KeyDownMsg: key=%x\n", wParam);
1572 #endif
1574 HideCaret(hwnd);
1575 switch (wParam)
1577 case VK_UP:
1578 if (SelMarked(es))
1579 EDIT_ClearSel(hwnd);
1580 if (IsMultiLine())
1581 EDIT_Upward(hwnd);
1582 else
1583 EDIT_Backward(hwnd);
1584 break;
1586 case VK_DOWN:
1587 if (SelMarked(es))
1588 EDIT_ClearSel(hwnd);
1589 if (IsMultiLine())
1590 EDIT_Downward(hwnd);
1591 else
1592 EDIT_Forward(hwnd);
1593 break;
1595 case VK_RIGHT:
1596 if (SelMarked(es))
1597 EDIT_ClearSel(hwnd);
1598 EDIT_Forward(hwnd);
1599 break;
1601 case VK_LEFT:
1602 if (SelMarked(es))
1603 EDIT_ClearSel(hwnd);
1604 EDIT_Backward(hwnd);
1605 break;
1607 case VK_HOME:
1608 if (SelMarked(es))
1609 EDIT_ClearSel(hwnd);
1610 EDIT_Home(hwnd);
1611 break;
1613 case VK_END:
1614 if (SelMarked(es))
1615 EDIT_ClearSel(hwnd);
1616 EDIT_End(hwnd);
1617 break;
1619 case VK_PRIOR:
1620 if (IsMultiLine())
1622 if (SelMarked(es))
1623 EDIT_ClearSel(hwnd);
1624 EDIT_KeyVScrollPage(hwnd, SB_PAGEUP);
1626 break;
1628 case VK_NEXT:
1629 if (IsMultiLine())
1631 if (SelMarked(es))
1632 EDIT_ClearSel(hwnd);
1633 EDIT_KeyVScrollPage(hwnd, SB_PAGEDOWN);
1635 break;
1637 case VK_BACK:
1638 if (SelMarked(es))
1639 EDIT_DeleteSel(hwnd);
1640 else
1642 if (es->CurrCol == 0 && es->CurrLine == 0)
1643 break;
1644 EDIT_Backward(hwnd);
1645 EDIT_DelKey(hwnd);
1647 break;
1649 case VK_DELETE:
1650 if (SelMarked(es))
1651 EDIT_DeleteSel(hwnd);
1652 else
1653 EDIT_DelKey(hwnd);
1654 break;
1657 SetCaretPos(es->WndCol, es->WndRow * es->txtht);
1658 ShowCaret(hwnd);
1662 /*********************************************************************
1663 * EDIT_KeyHScroll
1665 * Scroll text horizontally using cursor keys.
1668 void EDIT_KeyHScroll(HWND hwnd, WORD opt)
1670 RECT rc;
1671 int hscrollpos;
1672 WND *wndPtr = WIN_FindWndPtr(hwnd);
1673 EDITSTATE *es =
1674 (EDITSTATE *)EDIT_HeapAddr(hwnd, (HANDLE)(*(wndPtr->wExtra)));
1676 if (opt == SB_LINEDOWN)
1678 es->wleft += HSCROLLDIM;
1679 es->WndCol -= HSCROLLDIM;
1681 else
1683 if (es->wleft == 0)
1684 return;
1685 if (es->wleft - HSCROLLDIM < 0)
1687 es->WndCol += es->wleft;
1688 es->wleft = 0;
1690 else
1692 es->wleft -= HSCROLLDIM;
1693 es->WndCol += HSCROLLDIM;
1697 InvalidateRect(hwnd, NULL, FALSE);
1698 UpdateWindow(hwnd);
1700 if (IsHScrollBar())
1702 hscrollpos = EDIT_ComputeHScrollPos(hwnd);
1703 SetScrollPos(hwnd, SB_HORZ, hscrollpos, TRUE);
1708 /*********************************************************************
1709 * EDIT_KeyVScrollLine
1711 * Scroll text vertically by one line using keyboard.
1714 void EDIT_KeyVScrollLine(HWND hwnd, WORD opt)
1716 RECT rc;
1717 int y, vscrollpos;
1718 WND *wndPtr = WIN_FindWndPtr(hwnd);
1719 EDITSTATE *es =
1720 (EDITSTATE *)EDIT_HeapAddr(hwnd, (HANDLE)(*(wndPtr->wExtra)));
1722 if (!IsMultiLine())
1723 return;
1725 if (opt == SB_LINEDOWN)
1727 /* move down one line */
1728 if (es->wtop + ClientHeight(wndPtr, es) >= es->wlines)
1729 return;
1730 es->wtop++;
1732 else
1734 /* move up one line */
1735 if (es->wtop == 0)
1736 return;
1737 --es->wtop;
1740 if (IsWindowVisible(hwnd))
1742 /* adjust client bottom to nearest whole line */
1743 GetClientRect(hwnd, &rc);
1744 rc.bottom = (rc.bottom / es->txtht) * es->txtht;
1746 if (opt == SB_LINEUP)
1748 /* move up one line (scroll window down) */
1749 ScrollWindow(hwnd, 0, es->txtht, &rc, &rc);
1750 /* write top line */
1751 EDIT_WriteTextLine(hwnd, NULL, es->wtop);
1752 es->WndRow++;
1754 else
1756 /* move down one line (scroll window up) */
1757 ScrollWindow(hwnd, 0, -(es->txtht), &rc, &rc);
1758 /* write bottom line */
1759 y = (((rc.bottom - rc.top) / es->txtht) - 1);
1760 EDIT_WriteTextLine(hwnd, NULL, es->wtop + y);
1761 --es->WndRow;
1765 /* reset the vertical scroll bar */
1766 if (IsVScrollBar())
1768 vscrollpos = EDIT_ComputeVScrollPos(hwnd);
1769 SetScrollPos(hwnd, SB_VERT, vscrollpos, TRUE);
1774 /*********************************************************************
1775 * EDIT_KeyVScrollPage
1777 * Scroll text vertically by one page using keyboard.
1780 void EDIT_KeyVScrollPage(HWND hwnd, WORD opt)
1782 RECT rc;
1783 int vscrollpos;
1784 WND *wndPtr = WIN_FindWndPtr(hwnd);
1785 EDITSTATE *es =
1786 (EDITSTATE *)EDIT_HeapAddr(hwnd, (HANDLE)(*(wndPtr->wExtra)));
1788 if (IsMultiLine())
1790 if (opt == SB_PAGEUP)
1792 if (es->wtop)
1793 es->wtop -= ClientHeight(wndPtr, es);
1795 else
1797 if (es->wtop + ClientHeight(wndPtr, es) < es->wlines)
1799 es->wtop += ClientHeight(wndPtr, es);
1800 if (es->wtop > es->wlines - ClientHeight(wndPtr, es))
1801 es->wtop = es->wlines - ClientHeight(wndPtr, es);
1804 if (es->wtop < 0)
1805 es->wtop = 0;
1807 es->CurrLine = es->wtop + es->WndRow;
1808 EDIT_StickEnd(hwnd);
1809 InvalidateRect(hwnd, NULL, TRUE);
1810 UpdateWindow(hwnd);
1812 /* reset the vertical scroll bar */
1813 if (IsVScrollBar())
1815 vscrollpos = EDIT_ComputeVScrollPos(hwnd);
1816 SetScrollPos(hwnd, SB_VERT, vscrollpos, TRUE);
1822 /*********************************************************************
1823 * EDIT_KeyVScrollDoc
1825 * Scroll text to top and bottom of document using keyboard.
1828 void EDIT_KeyVScrollDoc(HWND hwnd, WORD opt)
1830 RECT rc;
1831 int vscrollpos;
1832 WND *wndPtr = WIN_FindWndPtr(hwnd);
1833 EDITSTATE *es =
1834 (EDITSTATE *)EDIT_HeapAddr(hwnd, (HANDLE)(*(wndPtr->wExtra)));
1836 if (!IsMultiLine())
1837 return;
1839 if (opt == SB_TOP)
1840 es->wtop = es->wleft = 0;
1841 else if (es->wtop + ClientHeight(wndPtr, es) < es->wlines)
1843 es->wtop = es->wlines - ClientHeight(wndPtr, es);
1844 es->wleft = 0;
1847 es->CurrLine = es->wlines;
1848 es->WndRow = es->wlines - es->wtop;
1849 EDIT_End(hwnd);
1850 InvalidateRect(hwnd, NULL, TRUE);
1851 UpdateWindow(hwnd);
1853 /* reset the vertical scroll bar */
1854 if (IsVScrollBar())
1856 vscrollpos = EDIT_ComputeVScrollPos(hwnd);
1857 SetScrollPos(hwnd, SB_VERT, vscrollpos, TRUE);
1862 /*********************************************************************
1863 * EDIT_ComputeVScrollPos
1865 * Compute the vertical scroll bar position from the window
1866 * position and text width.
1869 int EDIT_ComputeVScrollPos(HWND hwnd)
1871 int vscrollpos;
1872 short minpos, maxpos;
1873 WND *wndPtr = WIN_FindWndPtr(hwnd);
1874 EDITSTATE *es =
1875 (EDITSTATE *)EDIT_HeapAddr(hwnd, (HANDLE)(*(wndPtr->wExtra)));
1877 GetScrollRange(hwnd, SB_VERT, &minpos, &maxpos);
1879 if (es->wlines > ClientHeight(wndPtr, es))
1880 vscrollpos = (double)(es->wtop) / (double)(es->wlines -
1881 ClientHeight(wndPtr, es)) * (maxpos - minpos);
1882 else
1883 vscrollpos = minpos;
1885 return vscrollpos;
1889 /*********************************************************************
1890 * EDIT_ComputeHScrollPos
1892 * Compute the horizontal scroll bar position from the window
1893 * position and text width.
1896 int EDIT_ComputeHScrollPos(HWND hwnd)
1898 int hscrollpos;
1899 short minpos, maxpos;
1900 WND *wndPtr = WIN_FindWndPtr(hwnd);
1901 EDITSTATE *es =
1902 (EDITSTATE *)EDIT_HeapAddr(hwnd, (HANDLE)(*(wndPtr->wExtra)));
1904 GetScrollRange(hwnd, SB_HORZ, &minpos, &maxpos);
1906 if (es->textwidth > ClientWidth(wndPtr))
1907 hscrollpos = (double)(es->wleft) / (double)(es->textwidth -
1908 ClientWidth(wndPtr)) * (maxpos - minpos);
1909 else
1910 hscrollpos = minpos;
1912 return hscrollpos;
1916 /*********************************************************************
1917 * EDIT_DelKey
1919 * Delete character to right of cursor.
1922 void EDIT_DelKey(HWND hwnd)
1924 RECT rc;
1925 WND *wndPtr = WIN_FindWndPtr(hwnd);
1926 EDITSTATE *es =
1927 (EDITSTATE *)EDIT_HeapAddr(hwnd, (HANDLE)(*(wndPtr->wExtra)));
1928 char *currchar = CurrChar;
1929 BOOL repaint = *currchar == '\n';
1931 if (IsMultiLine() && *currchar == '\n' && *(currchar + 1) == '\0')
1932 return;
1933 strcpy(currchar, currchar + 1);
1934 NOTIFY_PARENT(hwnd, EN_UPDATE);
1936 if (repaint)
1938 EDIT_BuildTextPointers(hwnd);
1939 GetClientRect(hwnd, &rc);
1940 rc.top = es->WndRow * es->txtht;
1941 InvalidateRect(hwnd, &rc, FALSE);
1942 UpdateWindow(hwnd);
1944 else
1946 EDIT_ModTextPointers(hwnd, es->CurrLine + 1, -1);
1947 EDIT_WriteTextLine(hwnd, NULL, es->WndRow + es->wtop);
1950 es->TextChanged = TRUE;
1951 NOTIFY_PARENT(hwnd, EN_CHANGE);
1954 /*********************************************************************
1955 * WM_VSCROLL message function
1958 void EDIT_VScrollMsg(HWND hwnd, WORD wParam, LONG lParam)
1960 WND *wndPtr = WIN_FindWndPtr(hwnd);
1961 EDITSTATE *es =
1962 (EDITSTATE *)EDIT_HeapAddr(hwnd, (HANDLE)(*(wndPtr->wExtra)));
1964 if (IsMultiLine())
1966 HideCaret(hwnd);
1968 switch (wParam)
1970 case SB_LINEUP:
1971 case SB_LINEDOWN:
1972 EDIT_VScrollLine(hwnd, wParam);
1973 break;
1975 case SB_PAGEUP:
1976 case SB_PAGEDOWN:
1977 EDIT_VScrollPage(hwnd, wParam);
1978 break;
1982 SetCaretPos(es->WndCol, es->WndRow);
1983 ShowCaret(hwnd);
1987 /*********************************************************************
1988 * EDIT_VScrollLine
1990 * Scroll text vertically by one line using scrollbars.
1993 void EDIT_VScrollLine(HWND hwnd, WORD opt)
1995 RECT rc;
1996 int y;
1997 WND *wndPtr = WIN_FindWndPtr(hwnd);
1998 EDITSTATE *es =
1999 (EDITSTATE *)EDIT_HeapAddr(hwnd, (HANDLE)(*(wndPtr->wExtra)));
2001 #ifdef DEBUG_EDIT
2002 printf("EDIT_VScrollLine: direction=%d\n", opt);
2003 #endif
2005 if (opt == SB_LINEDOWN)
2007 /* move down one line */
2008 if (es->wtop + ClientHeight(wndPtr, es) >= es->wlines)
2009 return;
2010 es->wtop++;
2012 else
2014 /* move up one line */
2015 if (es->wtop == 0)
2016 return;
2017 --es->wtop;
2020 if (IsWindowVisible(hwnd))
2022 /* adjust client bottom to nearest whole line */
2023 GetClientRect(hwnd, &rc);
2024 rc.bottom = (rc.bottom / es->txtht) * es->txtht;
2026 if (opt == SB_LINEUP)
2028 /* move up one line (scroll window down) */
2029 ScrollWindow(hwnd, 0, es->txtht, &rc, &rc);
2030 /* write top line */
2031 EDIT_WriteTextLine(hwnd, NULL, es->wtop);
2032 es->WndRow++;
2034 else
2036 /* move down one line (scroll window up) */
2037 ScrollWindow(hwnd, 0, -(es->txtht), &rc, &rc);
2038 /* write bottom line */
2039 y = ((rc.bottom - rc.top / es->txtht) - 1);
2040 EDIT_WriteTextLine(hwnd, NULL, es->wtop + y);
2041 --es->WndRow;
2047 /*********************************************************************
2048 * EDIT_VScrollPage
2050 * Scroll text vertically by one page using keyboard.
2053 void EDIT_VScrollPage(HWND hwnd, WORD opt)
2055 RECT rc;
2056 int vscrollpos;
2057 WND *wndPtr = WIN_FindWndPtr(hwnd);
2058 EDITSTATE *es =
2059 (EDITSTATE *)EDIT_HeapAddr(hwnd, (HANDLE)(*(wndPtr->wExtra)));
2061 if (opt == SB_PAGEUP)
2063 if (es->wtop)
2064 es->wtop -= ClientHeight(wndPtr, es);
2066 else
2068 if (es->wtop + ClientHeight(wndPtr, es) < es->wlines)
2070 es->wtop += ClientHeight(wndPtr, es);
2071 if (es->wtop > es->wlines - ClientHeight(wndPtr, es))
2072 es->wtop = es->wlines - ClientHeight(wndPtr, es);
2075 if (es->wtop < 0)
2076 es->wtop = 0;
2078 InvalidateRect(hwnd, NULL, TRUE);
2079 UpdateWindow(hwnd);
2081 /* reset the vertical scroll bar */
2082 if (IsVScrollBar())
2084 vscrollpos = EDIT_ComputeVScrollPos(hwnd);
2085 SetScrollPos(hwnd, SB_VERT, vscrollpos, TRUE);
2090 /*********************************************************************
2091 * WM_HSCROLL message function
2094 void EDIT_HScrollMsg(HWND hwnd, WORD wParam, LONG lParam)
2096 WND *wndPtr = WIN_FindWndPtr(hwnd);
2097 EDITSTATE *es =
2098 (EDITSTATE *)EDIT_HeapAddr(hwnd, (HANDLE)(*(wndPtr->wExtra)));
2100 switch (wParam)
2102 case SB_LINEUP:
2103 case SB_LINEDOWN:
2104 HideCaret(hwnd);
2106 SetCaretPos(es->WndCol, es->WndRow * es->txtht);
2107 ShowCaret(hwnd);
2108 break;
2113 /*********************************************************************
2114 * WM_SIZE message function
2117 void EDIT_SizeMsg(HWND hwnd, WORD wParam, LONG lParam)
2119 RECT rc;
2120 WND *wndPtr = WIN_FindWndPtr(hwnd);
2121 EDITSTATE *es =
2122 (EDITSTATE *)EDIT_HeapAddr(hwnd, (HANDLE)(*(wndPtr->wExtra)));
2124 if (wParam != SIZE_MAXIMIZED && wParam != SIZE_RESTORED) return;
2126 InvalidateRect(hwnd, NULL, TRUE);
2127 es->PaintBkgd = TRUE;
2128 UpdateWindow(hwnd);
2132 /*********************************************************************
2133 * WM_LBUTTONDOWN message function
2136 void EDIT_LButtonDownMsg(HWND hwnd, WORD wParam, LONG lParam)
2138 char *cp;
2139 int len;
2140 BOOL end = FALSE;
2141 WND *wndPtr = WIN_FindWndPtr(hwnd);
2142 EDITSTATE *es =
2143 (EDITSTATE *)EDIT_HeapAddr(hwnd, (HANDLE)(*(wndPtr->wExtra)));
2145 if (SelMarked(es))
2146 EDIT_ClearSel(hwnd);
2148 es->WndRow = HIWORD(lParam) / es->txtht;
2149 if (es->WndRow > es->wlines - es->wtop - 1)
2151 if (es->wlines)
2152 es->WndRow = es->wlines - es->wtop - 1;
2153 else
2154 es->WndRow = 0;
2155 end = TRUE;
2157 es->CurrLine = es->wtop + es->WndRow;
2159 cp = EDIT_TextLine(hwnd, es->CurrLine);
2160 len = EDIT_LineLength(hwnd, es->CurrLine);
2161 es->WndCol = LOWORD(lParam);
2162 if (es->WndCol > EDIT_StrLength(hwnd, cp, len, 0) - es->wleft || end)
2163 es->WndCol = EDIT_StrLength(hwnd, cp, len, 0) - es->wleft;
2164 es->CurrCol = EDIT_PixelToChar(hwnd, es->CurrLine, &(es->WndCol));
2166 ButtonDown = TRUE;
2167 ButtonRow = es->CurrLine;
2168 ButtonCol = es->CurrCol;
2172 /*********************************************************************
2173 * WM_MOUSEMOVE message function
2176 void EDIT_MouseMoveMsg(HWND hwnd, WORD wParam, LONG lParam)
2178 if (wParam != MK_LBUTTON)
2179 return;
2181 if (ButtonDown)
2183 EDIT_SetAnchor(hwnd, ButtonRow, ButtonCol);
2184 TextMarking = TRUE;
2185 ButtonDown = FALSE;
2188 if (TextMarking)
2189 EDIT_ExtendSel(hwnd, LOWORD(lParam), HIWORD(lParam));
2193 /*********************************************************************
2194 * EDIT_PixelToChar
2196 * Convert a pixel offset in the given row to a character offset,
2197 * adjusting the pixel offset to the nearest whole character if
2198 * necessary.
2201 int EDIT_PixelToChar(HWND hwnd, int row, int *pixel)
2203 int ch = 0, i = 0, s_i;
2204 char *text;
2205 WND *wndPtr = WIN_FindWndPtr(hwnd);
2206 EDITSTATE *es =
2207 (EDITSTATE *)EDIT_HeapAddr(hwnd, (HANDLE)(*(wndPtr->wExtra)));
2209 #ifdef DEBUG_EDIT
2210 printf("EDIT_PixelToChar: row=%d, pixel=%d\n", row, *pixel);
2211 #endif
2213 text = EDIT_TextLine(hwnd, row);
2214 while (i < *pixel)
2216 s_i = i;
2217 i += EDIT_CharWidth(hwnd, *(text + ch), i);
2218 ch++;
2221 /* if stepped past _pixel_, go back a character */
2222 if (i - *pixel)
2224 i = s_i;
2225 --ch;
2227 *pixel = i;
2228 return ch;
2232 /*********************************************************************
2233 * WM_SETTEXT message function
2236 LONG EDIT_SetTextMsg(HWND hwnd, LONG lParam)
2238 int len;
2239 char *text;
2240 RECT rc;
2241 WND *wndPtr = WIN_FindWndPtr(hwnd);
2242 EDITSTATE *es =
2243 (EDITSTATE *)EDIT_HeapAddr(hwnd, (HANDLE)(*(wndPtr->wExtra)));
2245 if (strlen((char *)lParam) <= es->MaxTextLen)
2247 len = strlen((char *)lParam);
2248 EDIT_ClearText(hwnd);
2249 es->textlen = len;
2250 es->hText = EDIT_HeapReAlloc(hwnd, es->hText, len + 3);
2251 text = EDIT_HeapAddr(hwnd, es->hText);
2252 strcpy(text, (char *)lParam);
2253 text[len + 1] = '\0';
2254 text[len + 2] = '\0';
2255 EDIT_BuildTextPointers(hwnd);
2256 InvalidateRect(hwnd, NULL, TRUE);
2257 es->PaintBkgd = TRUE;
2258 es->TextChanged = TRUE;
2259 return 0L;
2261 else
2262 return EN_ERRSPACE;
2266 /*********************************************************************
2267 * EDIT_ClearText
2269 * Clear text from text buffer.
2272 void EDIT_ClearText(HWND hwnd)
2274 WND *wndPtr = WIN_FindWndPtr(hwnd);
2275 EDITSTATE *es =
2276 (EDITSTATE *)EDIT_HeapAddr(hwnd, (HANDLE)(*(wndPtr->wExtra)));
2277 unsigned int blen = EditBufLen(wndPtr) + 2;
2278 char *text;
2280 es->hText = EDIT_HeapReAlloc(hwnd, es->hText, blen);
2281 text = EDIT_HeapAddr(hwnd, es->hText);
2282 memset(text, 0, blen);
2283 es->textlen = 0;
2284 es->wlines = 0;
2285 es->CurrLine = es->CurrCol = 0;
2286 es->WndRow = es->WndCol = 0;
2287 es->wleft = es->wtop = 0;
2288 es->textwidth = 0;
2289 es->TextChanged = FALSE;
2290 EDIT_ClearTextPointers(hwnd);
2294 /*********************************************************************
2295 * EM_SETSEL message function
2298 void EDIT_SetSelMsg(HWND hwnd, WORD wParam, LONG lParam)
2300 int so, eo;
2301 WND *wndPtr = WIN_FindWndPtr(hwnd);
2302 EDITSTATE *es =
2303 (EDITSTATE *)EDIT_HeapAddr(hwnd, (HANDLE)(*(wndPtr->wExtra)));
2305 so = LOWORD(lParam);
2306 eo = HIWORD(lParam);
2308 if (so == -1) /* if so == -1, clear selection */
2310 EDIT_ClearSel(hwnd);
2311 return;
2314 if (so == eo) /* if so == eo, set caret only */
2316 EDIT_GetLineCol(hwnd, so, &(es->CurrLine), &(es->CurrCol));
2317 es->WndRow = es->CurrLine - es->wtop;
2319 if (!wParam)
2321 if (es->WndRow < 0 || es->WndRow > ClientHeight(wndPtr, es))
2323 es->wtop = es->CurrLine;
2324 es->WndRow = 0;
2326 es->WndCol = EDIT_StrLength(hwnd,
2327 EDIT_TextLine(hwnd, es->CurrLine),
2328 es->CurrCol, 0) - es->wleft;
2329 if (es->WndCol > ClientWidth(wndPtr))
2331 es->wleft = es->WndCol;
2332 es->WndCol = 0;
2334 else if (es->WndCol < 0)
2336 es->wleft += es->WndCol;
2337 es->WndCol = 0;
2341 else /* otherwise set selection */
2343 if (so > eo)
2344 swap(&so, &eo);
2346 EDIT_GetLineCol(hwnd, so, &(es->SelBegLine), &(es->SelBegCol));
2347 EDIT_GetLineCol(hwnd, eo, &(es->SelEndLine), &(es->SelEndCol));
2348 es->CurrLine = es->SelEndLine;
2349 es->CurrCol = es->SelEndCol;
2350 es->WndRow = es->SelEndLine - es->wtop;
2352 if (!wParam) /* don't suppress scrolling of text */
2354 if (es->WndRow < 0)
2356 es->wtop = es->SelEndLine;
2357 es->WndRow = 0;
2359 else if (es->WndRow > ClientHeight(wndPtr, es))
2361 es->wtop += es->WndRow - ClientHeight(wndPtr, es);
2362 es->WndRow = ClientHeight(wndPtr, es);
2364 es->WndCol = EDIT_StrLength(hwnd,
2365 EDIT_TextLine(hwnd, es->SelEndLine),
2366 es->SelEndCol, 0) - es->wleft;
2367 if (es->WndCol > ClientWidth(wndPtr))
2369 es->wleft += es->WndCol - ClientWidth(wndPtr);
2370 es->WndCol = ClientWidth(wndPtr);
2372 else if (es->WndCol < 0)
2374 es->wleft += es->WndCol;
2375 es->WndCol = 0;
2379 InvalidateRect(hwnd, NULL, TRUE);
2380 UpdateWindow(hwnd);
2385 /*********************************************************************
2386 * EDIT_GetLineCol
2388 * Return line and column in text buffer from character offset.
2391 void EDIT_GetLineCol(HWND hwnd, int off, int *line, int *col)
2393 int lineno;
2394 char *cp, *cp1;
2395 WND *wndPtr = WIN_FindWndPtr(hwnd);
2396 EDITSTATE *es =
2397 (EDITSTATE *)EDIT_HeapAddr(hwnd, (HANDLE)(*(wndPtr->wExtra)));
2398 char *text = EDIT_HeapAddr(hwnd, es->hText);
2399 unsigned int *textPtrs =
2400 (unsigned int *)EDIT_HeapAddr(hwnd, es->hTextPtrs);
2402 /* check for (0,0) */
2403 if (!off)
2405 *line = 0;
2406 *col = 0;
2407 return;
2410 if (off > strlen(text)) off = strlen(text);
2411 cp1 = text;
2412 for (lineno = 0; lineno < es->wlines; lineno++)
2414 cp = text + *(textPtrs + lineno);
2415 if (off == (int)(cp - text))
2417 *line = lineno;
2418 *col = 0;
2419 return;
2421 if (off < (int)(cp - text))
2422 break;
2423 cp1 = cp;
2425 *line = lineno - 1;
2426 *col = off - (int)(cp1 - text);
2427 #if 0
2428 if (*(text + *col) == '\0')
2429 (*col)--;
2430 #endif
2434 /*********************************************************************
2435 * EDIT_DeleteSel
2437 * Delete the current selected text (if any)
2440 void EDIT_DeleteSel(HWND hwnd)
2442 char *bbl, *bel;
2443 int len;
2444 WND *wndPtr = WIN_FindWndPtr(hwnd);
2445 EDITSTATE *es =
2446 (EDITSTATE *)EDIT_HeapAddr(hwnd, (HANDLE)(*(wndPtr->wExtra)));
2447 char *text = EDIT_HeapAddr(hwnd, es->hText);
2449 if (SelMarked(es))
2451 bbl = EDIT_TextLine(hwnd, es->SelBegLine) + es->SelBegCol;
2452 bel = EDIT_TextLine(hwnd, es->SelEndLine) + es->SelEndCol;
2453 len = (int)(bel - bbl);
2454 EDIT_SaveDeletedText(hwnd, bbl, len, es->SelBegLine, es->SelBegCol);
2455 es->TextChanged = TRUE;
2456 strcpy(bbl, bel);
2458 es->CurrLine = es->SelBegLine;
2459 es->CurrCol = es->SelBegCol;
2460 es->WndRow = es->SelBegLine - es->wtop;
2461 if (es->WndRow < 0)
2463 es->wtop = es->SelBegLine;
2464 es->WndRow = 0;
2466 es->WndCol = EDIT_StrLength(hwnd, bbl - es->SelBegCol,
2467 es->SelBegCol, 0) - es->wleft;
2469 EDIT_BuildTextPointers(hwnd);
2470 es->PaintBkgd = TRUE;
2471 EDIT_ClearSel(hwnd);
2476 /*********************************************************************
2477 * EDIT_ClearSel
2479 * Clear the current selection.
2482 void EDIT_ClearSel(HWND hwnd)
2484 WND *wndPtr = WIN_FindWndPtr(hwnd);
2485 EDITSTATE *es =
2486 (EDITSTATE *)EDIT_HeapAddr(hwnd, (HANDLE)(*(wndPtr->wExtra)));
2488 es->SelBegLine = es->SelBegCol = 0;
2489 es->SelEndLine = es->SelEndCol = 0;
2491 InvalidateRect(hwnd, NULL, TRUE);
2492 UpdateWindow(hwnd);
2496 /*********************************************************************
2497 * EDIT_TextLineNumber
2499 * Return the line number in the text buffer of the supplied
2500 * character pointer.
2503 int EDIT_TextLineNumber(HWND hwnd, char *lp)
2505 int lineno;
2506 char *cp;
2507 WND *wndPtr = WIN_FindWndPtr(hwnd);
2508 EDITSTATE *es =
2509 (EDITSTATE *)EDIT_HeapAddr(hwnd, (HANDLE)(*(wndPtr->wExtra)));
2510 char *text = EDIT_HeapAddr(hwnd, es->hText);
2511 unsigned int *textPtrs =
2512 (unsigned int *)EDIT_HeapAddr(hwnd, es->hTextPtrs);
2514 for (lineno = 0; lineno < es->wlines; lineno++)
2516 cp = text + *(textPtrs + lineno);
2517 if (cp == lp)
2518 return lineno;
2519 if (cp > lp)
2520 break;
2522 return lineno - 1;
2526 /*********************************************************************
2527 * EDIT_SetAnchor
2529 * Set down anchor for text marking.
2532 void EDIT_SetAnchor(HWND hwnd, int row, int col)
2534 BOOL sel = FALSE;
2535 WND *wndPtr = WIN_FindWndPtr(hwnd);
2536 EDITSTATE *es =
2537 (EDITSTATE *)EDIT_HeapAddr(hwnd, (HANDLE)(*(wndPtr->wExtra)));
2539 if (SelMarked(es))
2540 sel = TRUE;
2541 EDIT_ClearSel(hwnd);
2542 es->SelBegLine = es->SelEndLine = row;
2543 es->SelBegCol = es->SelEndCol = col;
2544 if (sel)
2546 InvalidateRect(hwnd, NULL, FALSE);
2547 UpdateWindow(hwnd);
2552 /*********************************************************************
2553 * EDIT_ExtendSel
2555 * Extend selection to the given screen co-ordinates.
2558 void EDIT_ExtendSel(HWND hwnd, int x, int y)
2560 int bbl, bel, bbc, bec;
2561 char *cp;
2562 int len;
2563 BOOL end = FALSE;
2564 WND *wndPtr = WIN_FindWndPtr(hwnd);
2565 EDITSTATE *es =
2566 (EDITSTATE *)EDIT_HeapAddr(hwnd, (HANDLE)(*(wndPtr->wExtra)));
2568 #ifdef DEBUG_EDIT
2569 printf("EDIT_ExtendSel: x=%d, y=%d\n", x, y);
2570 #endif
2572 bbl = es->SelEndLine;
2573 bbc = es->SelEndCol;
2574 cp = EDIT_TextLine(hwnd, es->wtop + y / es->txtht);
2575 len = EDIT_LineLength(hwnd, es->wtop + y / es->txtht);
2577 es->WndRow = y / es->txtht;
2578 if (es->WndRow > es->wlines - es->wtop - 1)
2580 if (es->wlines)
2581 es->WndRow = es->wlines - es->wtop - 1;
2582 else
2583 es->WndRow = 0;
2584 end = TRUE;
2586 es->CurrLine = es->wtop + es->WndRow;
2587 es->SelEndLine = es->CurrLine;
2589 es->WndCol = x;
2590 if (es->WndCol > EDIT_StrLength(hwnd, cp, len, 0) - es->wleft || end)
2591 es->WndCol = EDIT_StrLength(hwnd, cp, len, 0) - es->wleft;
2592 es->CurrCol = EDIT_PixelToChar(hwnd, es->CurrLine, &(es->WndCol));
2593 es->SelEndCol = es->CurrCol - 1;
2595 bel = es->SelEndLine;
2596 bec = es->SelEndCol;
2598 /* return if no new characters to mark */
2599 if (bbl == bel && bbc == bec)
2600 return;
2602 /* put lowest marker first */
2603 if (bbl > bel)
2605 swap(&bbl, &bel);
2606 swap(&bbc, &bec);
2608 if (bbl == bel && bbc > bec)
2609 swap(&bbc, &bec);
2611 for (y = bbl; y <= bel; y++)
2613 if (y == bbl && y == bel)
2614 EDIT_WriteSel(hwnd, y, bbc, bec);
2615 else if (y == bbl)
2616 EDIT_WriteSel(hwnd, y, bbc, -1);
2617 else if (y == bel)
2618 EDIT_WriteSel(hwnd, y, 0, bec);
2619 else
2620 EDIT_WriteSel(hwnd, y, 0, -1);
2625 /*********************************************************************
2626 * EDIT_WriteSel
2628 * Display selection by reversing pixels in selected text.
2629 * If end == -1, selection applies to end of line.
2632 void EDIT_WriteSel(HWND hwnd, int y, int start, int end)
2634 RECT rc;
2635 int scol, ecol;
2636 char *cp;
2637 HDC hdc;
2638 HBRUSH hbrush, holdbrush;
2639 int olddm;
2640 WND *wndPtr = WIN_FindWndPtr(hwnd);
2641 EDITSTATE *es =
2642 (EDITSTATE *)EDIT_HeapAddr(hwnd, (HANDLE)(*(wndPtr->wExtra)));
2644 #ifdef DEBUG_EDIT
2645 printf("EDIT_WriteSel: y=%d start=%d end=%d\n", y, start, end);
2646 #endif
2647 GetClientRect(hwnd, &rc);
2649 /* make sure y is within the window */
2650 if (y < es->wtop || y > (es->wtop + ClientHeight(wndPtr, es)))
2651 return;
2653 /* get pointer to text */
2654 cp = EDIT_TextLine(hwnd, y);
2656 /* get length of line if end == -1 */
2657 if (end == -1)
2658 end = EDIT_LineLength(hwnd, y);
2660 scol = EDIT_StrLength(hwnd, cp, start, 0);
2661 if (scol > rc.right) return;
2662 if (scol < rc.left) scol = rc.left;
2663 ecol = EDIT_StrLength(hwnd, cp, end, 0);
2664 if (ecol < rc.left) return;
2665 if (ecol > rc.right) ecol = rc.right;
2667 hdc = GetDC(hwnd);
2668 hbrush = GetStockObject(BLACK_BRUSH);
2669 holdbrush = (HBRUSH)SelectObject(hdc, (HANDLE)hbrush);
2670 olddm = SetROP2(hdc, R2_XORPEN);
2671 Rectangle(hdc, scol, y * es->txtht, ecol, (y + 1) * es->txtht);
2672 SetROP2(hdc, olddm);
2673 SelectObject(hdc, (HANDLE)holdbrush);
2674 ReleaseDC(hwnd, hdc);
2678 /*********************************************************************
2679 * EDIT_StopMarking
2681 * Stop text marking (selection).
2684 void EDIT_StopMarking(HWND hwnd)
2686 WND *wndPtr = WIN_FindWndPtr(hwnd);
2687 EDITSTATE *es =
2688 (EDITSTATE *)EDIT_HeapAddr(hwnd, (HANDLE)(*(wndPtr->wExtra)));
2690 TextMarking = FALSE;
2691 if (es->SelBegLine > es->SelEndLine)
2693 swap(&(es->SelBegLine), &(es->SelEndLine));
2694 swap(&(es->SelBegCol), &(es->SelEndCol));
2696 if (es->SelBegLine == es->SelEndLine && es->SelBegCol > es->SelEndCol)
2697 swap(&(es->SelBegCol), &(es->SelEndCol));
2701 /*********************************************************************
2702 * EM_GETLINE message function
2705 LONG EDIT_GetLineMsg(HWND hwnd, WORD wParam, LONG lParam)
2707 char *cp, *cp1;
2708 int len;
2709 char *buffer = (char *)lParam;
2710 WND *wndPtr = WIN_FindWndPtr(hwnd);
2711 EDITSTATE *es =
2712 (EDITSTATE *)EDIT_HeapAddr(hwnd, (HANDLE)(*(wndPtr->wExtra)));
2714 cp = EDIT_TextLine(hwnd, wParam);
2715 cp1 = EDIT_TextLine(hwnd, wParam + 1);
2716 len = min((int)(cp1 - cp), (WORD)(*buffer));
2717 strncpy(buffer, cp, len);
2719 return (LONG)len;
2723 /*********************************************************************
2724 * EM_GETSEL message function
2727 LONG EDIT_GetSelMsg(HWND hwnd)
2729 int so, eo;
2730 WND *wndPtr = WIN_FindWndPtr(hwnd);
2731 EDITSTATE *es =
2732 (EDITSTATE *)EDIT_HeapAddr(hwnd, (HANDLE)(*(wndPtr->wExtra)));
2733 unsigned int *textPtrs =
2734 (unsigned int *)EDIT_HeapAddr(hwnd, es->hTextPtrs);
2736 so = *(textPtrs + es->SelBegLine) + es->SelBegCol;
2737 eo = *(textPtrs + es->SelEndLine) + es->SelEndCol;
2739 return MAKELONG(so, eo);
2743 /*********************************************************************
2744 * EM_REPLACESEL message function
2747 void EDIT_ReplaceSel(HWND hwnd, LONG lParam)
2749 EDIT_DeleteSel(hwnd);
2750 EDIT_InsertText(hwnd, (char *)lParam, strlen((char *)lParam));
2751 InvalidateRect(hwnd, NULL, TRUE);
2752 UpdateWindow(hwnd);
2756 /*********************************************************************
2757 * EDIT_InsertText
2759 * Insert text at current line and column.
2762 void EDIT_InsertText(HWND hwnd, char *str, int len)
2764 int plen;
2765 WND *wndPtr = WIN_FindWndPtr(hwnd);
2766 EDITSTATE *es =
2767 (EDITSTATE *)EDIT_HeapAddr(hwnd, (HANDLE)(*(wndPtr->wExtra)));
2768 char *text = EDIT_HeapAddr(hwnd, es->hText);
2770 plen = strlen(text) + len;
2771 if (plen + 1 > es->textlen)
2773 es->hText = EDIT_HeapReAlloc(hwnd, es->hText, es->textlen + len);
2774 es->textlen = plen + 1;
2776 memmove(CurrChar + len, CurrChar, strlen(CurrChar) + 1);
2777 memcpy(CurrChar, str, len);
2779 EDIT_BuildTextPointers(hwnd);
2780 es->PaintBkgd = TRUE;
2781 es->TextChanged = TRUE;
2783 EDIT_GetLineCol(hwnd, (int)((CurrChar + len) - text), &(es->CurrLine),
2784 &(es->CurrCol));
2785 es->WndRow = es->CurrLine - es->wtop;
2786 es->WndCol = EDIT_StrLength(hwnd, EDIT_TextLine(hwnd, es->CurrLine),
2787 es->CurrCol, 0) - es->wleft;
2791 /*********************************************************************
2792 * EM_LINEFROMCHAR message function
2795 LONG EDIT_LineFromCharMsg(HWND hwnd, WORD wParam)
2797 int row, col;
2798 WND *wndPtr = WIN_FindWndPtr(hwnd);
2799 EDITSTATE *es =
2800 (EDITSTATE *)EDIT_HeapAddr(hwnd, (HANDLE)(*(wndPtr->wExtra)));
2802 if (wParam == (WORD)-1)
2803 return (LONG)(es->SelBegLine);
2804 else
2805 EDIT_GetLineCol(hwnd, wParam, &row, &col);
2807 return (LONG)row;
2811 /*********************************************************************
2812 * EM_LINEINDEX message function
2815 LONG EDIT_LineIndexMsg(HWND hwnd, WORD wParam)
2817 WND *wndPtr = WIN_FindWndPtr(hwnd);
2818 EDITSTATE *es =
2819 (EDITSTATE *)EDIT_HeapAddr(hwnd, (HANDLE)(*(wndPtr->wExtra)));
2820 unsigned int *textPtrs =
2821 (unsigned int *)EDIT_HeapAddr(hwnd, es->hTextPtrs);
2823 if (wParam == (WORD)-1)
2824 wParam = es->CurrLine;
2826 return (LONG)(*(textPtrs + wParam));
2830 /*********************************************************************
2831 * EM_LINELENGTH message function
2834 LONG EDIT_LineLengthMsg(HWND hwnd, WORD wParam)
2836 int row, col, len;
2837 int sbl, sbc, sel, sec;
2838 WND *wndPtr = WIN_FindWndPtr(hwnd);
2839 EDITSTATE *es =
2840 (EDITSTATE *)EDIT_HeapAddr(hwnd, (HANDLE)(*(wndPtr->wExtra)));
2841 unsigned int *textPtrs =
2842 (unsigned int *)EDIT_HeapAddr(hwnd, es->hTextPtrs);
2844 if (wParam == (WORD)-1)
2846 if (SelMarked(es))
2848 sbl = es->SelBegLine;
2849 sbc = es->SelBegCol;
2850 sel = es->SelEndLine;
2851 sec = es->SelEndCol;
2853 if (sbl > sel)
2855 swap(&sbl, &sel);
2856 swap(&sbc, &sec);
2858 if (sbl == sel && sbc > sec)
2859 swap(&sbc, &sec);
2861 if (sbc == sel)
2863 len = *(textPtrs + sbl + 1) - *(textPtrs + sbl) - 1;
2864 return len - sec - sbc;
2867 len = *(textPtrs + sel + 1) - *(textPtrs + sel) - sec - 1;
2868 return len + sbc;
2870 else /* no selection marked */
2872 len = *(textPtrs + es->CurrLine + 1) -
2873 *(textPtrs + es->CurrLine) - 1;
2874 return len;
2877 else /* line number specified */
2879 EDIT_GetLineCol(hwnd, wParam, &row, &col);
2880 len = *(textPtrs + row + 1) - *(textPtrs + row);
2881 return len;
2886 /*********************************************************************
2887 * WM_SETFONT message function
2890 void EDIT_SetFont(HWND hwnd, WORD wParam, LONG lParam)
2892 HDC hdc;
2893 TEXTMETRIC tm;
2894 HFONT oldfont;
2895 WND *wndPtr = WIN_FindWndPtr(hwnd);
2896 EDITSTATE *es =
2897 (EDITSTATE *)EDIT_HeapAddr(hwnd, (HANDLE)(*(wndPtr->wExtra)));
2898 short *charWidths = (short *)EDIT_HeapAddr(hwnd, es->hCharWidths);
2900 es->hFont = wParam;
2901 hdc = GetDC(hwnd);
2902 oldfont = (HFONT)SelectObject(hdc, (HANDLE)es->hFont);
2903 GetCharWidth(hdc, 0, 255, charWidths);
2904 GetTextMetrics(hdc, &tm);
2905 es->txtht = tm.tmHeight + tm.tmExternalLeading;
2906 SelectObject(hdc, (HANDLE)oldfont);
2907 ReleaseDC(hwnd, hdc);
2909 es->WndRow = (es->CurrLine - es->wtop) / es->txtht;
2910 es->WndCol = EDIT_StrLength(hwnd, EDIT_TextLine(hwnd, es->CurrLine),
2911 es->CurrCol, 0) - es->wleft;
2913 InvalidateRect(hwnd, NULL, TRUE);
2914 es->PaintBkgd = TRUE;
2915 if (lParam) UpdateWindow(hwnd);
2919 /*********************************************************************
2920 * EDIT_SaveDeletedText
2922 * Save deleted text in deleted text buffer.
2925 void EDIT_SaveDeletedText(HWND hwnd, char *deltext, int len,
2926 int line, int col)
2928 char *text;
2929 WND *wndPtr = WIN_FindWndPtr(hwnd);
2930 EDITSTATE *es =
2931 (EDITSTATE *)EDIT_HeapAddr(hwnd, (HANDLE)(*(wndPtr->wExtra)));
2933 es->hDeletedText = GlobalReAlloc(es->hDeletedText, len, GMEM_MOVEABLE);
2934 if (!es->hDeletedText) return;
2935 text = (char *)GlobalLock(es->hDeletedText);
2936 memcpy(text, deltext, len);
2937 GlobalUnlock(es->hDeletedText);
2938 es->DeletedLength = len;
2939 es->DeletedCurrLine = line;
2940 es->DeletedCurrCol = col;
2944 /*********************************************************************
2945 * EDIT_ClearDeletedText
2947 * Clear deleted text buffer.
2950 void EDIT_ClearDeletedText(HWND hwnd)
2952 WND *wndPtr = WIN_FindWndPtr(hwnd);
2953 EDITSTATE *es =
2954 (EDITSTATE *)EDIT_HeapAddr(hwnd, (HANDLE)(*(wndPtr->wExtra)));
2956 GlobalFree(es->hDeletedText);
2957 es->hDeletedText = 0;
2958 es->DeletedLength = 0;
2962 /*********************************************************************
2963 * EM_UNDO message function
2966 LONG EDIT_UndoMsg(HWND hwnd)
2968 char *text;
2969 WND *wndPtr = WIN_FindWndPtr(hwnd);
2970 EDITSTATE *es =
2971 (EDITSTATE *)EDIT_HeapAddr(hwnd, (HANDLE)(*(wndPtr->wExtra)));
2973 if (es->hDeletedText)
2975 text = (char *)GlobalLock(es->hDeletedText);
2976 es->CurrLine = es->DeletedCurrLine;
2977 es->CurrCol = es->DeletedCurrCol;
2978 EDIT_InsertText(hwnd, text, es->DeletedLength);
2979 GlobalUnlock(es->hDeletedText);
2980 EDIT_ClearDeletedText(hwnd);
2982 es->SelBegLine = es->CurrLine;
2983 es->SelBegCol = es->CurrCol;
2984 EDIT_GetLineCol(hwnd, (int)((CurrChar + es->DeletedLength) - text),
2985 &(es->CurrLine), &(es->CurrCol));
2986 es->WndRow = es->CurrLine - es->wtop;
2987 es->WndCol = EDIT_StrLength(hwnd, EDIT_TextLine(hwnd, es->CurrLine),
2988 es->CurrCol, 0) - es->wleft;
2989 es->SelEndLine = es->CurrLine;
2990 es->SelEndCol = es->CurrCol;
2992 InvalidateRect(hwnd, NULL, TRUE);
2993 UpdateWindow(hwnd);
2994 return 1;
2996 else
2997 return 0;
3001 /*********************************************************************
3002 * EDIT_HeapAlloc
3004 * Allocate the specified number of bytes on the specified local heap.
3007 unsigned int EDIT_HeapAlloc(HWND hwnd, int bytes)
3009 WND *wndPtr = WIN_FindWndPtr(hwnd);
3011 return ((unsigned int)HEAP_Alloc((MDESC **)
3012 *(LONG *)(wndPtr->wExtra + 2),
3013 GMEM_MOVEABLE, bytes) & 0xffff);
3017 /*********************************************************************
3018 * EDIT_HeapAddr
3020 * Return the address of the memory pointed to by the handle.
3023 void *EDIT_HeapAddr(HWND hwnd, unsigned int handle)
3025 WND *wndPtr = WIN_FindWndPtr(hwnd);
3027 return ((void *)((handle) ? ((handle) | ((unsigned int)
3028 (*(MDESC **)*(LONG *)(wndPtr->wExtra + 2))
3029 & 0xffff0000)) : 0));
3033 /*********************************************************************
3034 * EDIT_HeapReAlloc
3036 * Reallocate the memory pointed to by the handle.
3039 unsigned int EDIT_HeapReAlloc(HWND hwnd, unsigned int handle, int bytes)
3041 WND *wndPtr = WIN_FindWndPtr(hwnd);
3043 return ((unsigned int)HEAP_ReAlloc((MDESC **)
3044 *(LONG *)(wndPtr->wExtra + 2),
3045 EDIT_HeapAddr(hwnd, handle),
3046 bytes, GMEM_MOVEABLE) & 0xffff);
3050 /*********************************************************************
3051 * EDIT_HeapFree
3053 * Frees the memory pointed to by the handle.
3056 void EDIT_HeapFree(HWND hwnd, unsigned int handle)
3058 WND *wndPtr = WIN_FindWndPtr(hwnd);
3060 HEAP_Free((MDESC **)*(LONG *)(wndPtr->wExtra + 2),
3061 EDIT_HeapAddr(hwnd, handle));
3065 /*********************************************************************
3066 * EDIT_HeapSize
3068 * Return the size of the given object on the local heap.
3071 unsigned int EDIT_HeapSize(HWND hwnd, unsigned int handle)
3073 WND *wndPtr = WIN_FindWndPtr(hwnd);
3075 return HEAP_LocalSize((MDESC **)*(LONG *)(wndPtr->wExtra + 2), handle);
3079 /*********************************************************************
3080 * EM_SETHANDLE message function
3083 void EDIT_SetHandleMsg(HWND hwnd, WORD wParam)
3085 MDESC *m;
3086 WND *wndPtr = WIN_FindWndPtr(hwnd);
3087 EDITSTATE *es =
3088 (EDITSTATE *)EDIT_HeapAddr(hwnd, (HANDLE)(*(wndPtr->wExtra)));
3090 if (IsMultiLine())
3092 es->hText = wParam;
3093 es->MaxTextLen = EDIT_HeapSize(hwnd, es->hText);
3094 es->wlines = 0;
3095 es->wtop = es->wleft = 0;
3096 es->CurrLine = es->CurrCol = 0;
3097 es->WndRow = es->WndCol = 0;
3098 es->TextChanged = FALSE;
3099 es->textwidth = 0;
3100 es->SelBegLine = es->SelBegCol = 0;
3101 es->SelEndLine = es->SelEndCol = 0;
3103 es->PaintBkgd = TRUE;
3104 InvalidateRect(hwnd, NULL, TRUE);
3105 UpdateWindow(hwnd);
3110 /*********************************************************************
3111 * EM_SETTABSTOPS message function
3114 LONG EDIT_SetTabStopsMsg(HWND hwnd, WORD wParam, LONG lParam)
3116 unsigned short *tabstops;
3117 WND *wndPtr = WIN_FindWndPtr(hwnd);
3118 EDITSTATE *es =
3119 (EDITSTATE *)EDIT_HeapAddr(hwnd, (HANDLE)(*(wndPtr->wExtra)));
3121 es->NumTabStops = wParam;
3122 if (wParam == 0)
3123 es->hTabStops = EDIT_HeapReAlloc(hwnd, es->hTabStops, 1);
3124 else if (wParam == 1)
3126 es->hTabStops = EDIT_HeapReAlloc(hwnd, es->hTabStops, 1);
3127 tabstops = (unsigned short *)EDIT_HeapAddr(hwnd, es->hTabStops);
3128 *tabstops = (unsigned short)lParam;
3130 else
3132 es->hTabStops = EDIT_HeapReAlloc(hwnd, es->hTabStops, wParam);
3133 tabstops = (unsigned short *)EDIT_HeapAddr(hwnd, es->hTabStops);
3134 memcpy(tabstops, (unsigned short *)lParam, wParam);
3136 return 0L;
3140 /*********************************************************************
3141 * Utility functions
3144 void swap(int *a, int *b)
3146 int x;
3148 x = *a;
3149 *a = *b;
3150 *b = x;