Release 950216
[wine.git] / controls / edit.c
blobe81ab13a1328a0fdf7e265c84e3ce68bb194ed17
1 /*
2 * Edit control
4 * Copyright David W. Metcalfe, 1994
6 * Release 3, July 1994
8 static char Copyright[] = "Copyright David W. Metcalfe, 1994";
9 */
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <string.h>
14 #include <windows.h>
15 #include <heap.h>
16 #include "win.h"
17 #include "class.h"
18 #include "user.h"
19 #include "stddebug.h"
20 /* #define DEBUG_EDIT */
21 /* #undef DEBUG_EDIT */
22 #include "debug.h"
25 #define NOTIFY_PARENT(hWndCntrl, wNotifyCode) \
26 SendMessage(GetParent(hWndCntrl), WM_COMMAND, \
27 GetDlgCtrlID(hWndCntrl), MAKELPARAM(hWndCntrl, wNotifyCode));
29 #define MAXTEXTLEN 30000 /* maximum text buffer length */
30 #define EDITLEN 1024 /* starting length for multi-line control */
31 #define ENTRYLEN 256 /* starting length for single line control */
32 #define GROWLENGTH 64 /* buffers grow by this much */
34 #define HSCROLLDIM (ClientWidth(wndPtr) / 3)
35 /* "line" dimension for horizontal scroll */
37 typedef struct
39 int wlines; /* number of lines of text */
40 int wtop; /* top line that is displayed */
41 int wleft; /* left pixel that is displayed */
42 unsigned int textlen; /* text buffer length */
43 int textwidth; /* width of longest line in pixels */
44 RECT fmtrc; /* rectangle in which to format text */
45 int txtht; /* height of text line in pixels */
46 HANDLE hText; /* handle to text buffer */
47 HANDLE hCharWidths; /* widths of chars in font */
48 HANDLE hTextPtrs; /* list of line offsets */
49 HANDLE hBlankLine; /* to fill blank lines quickly */
50 int CurrCol; /* current column */
51 int CurrLine; /* current line */
52 int WndCol; /* current window column */
53 int WndRow; /* current window row */
54 BOOL TextChanged; /* TRUE if text has changed */
55 BOOL PaintBkgd; /* paint control background */
56 unsigned int MaxTextLen; /* maximum text buffer length */
57 int SelBegLine; /* beginning line of selection */
58 int SelBegCol; /* beginning column of selection */
59 int SelEndLine; /* ending line of selection */
60 int SelEndCol; /* ending column of selection */
61 HFONT hFont; /* handle of current font (if not default) */
62 HANDLE hDeletedText; /* handle to deleted txet buffer for undo */
63 int DeletedLength; /* length of deleted text */
64 int DeletedCurrLine; /* starting line from which text was deleted */
65 int DeletedCurrCol; /* starting col from which text was deleted */
66 int NumTabStops; /* number of tab stops in buffer hTabStops */
67 HANDLE hTabStops; /* handle of tab stops buffer */
68 } EDITSTATE;
71 #define ClientWidth(wndPtr) \
72 (wndPtr->rectClient.right > wndPtr->rectClient.left ? \
73 wndPtr->rectClient.right - wndPtr->rectClient.left : 0)
74 #define ClientHeight(wndPtr, es) \
75 (wndPtr->rectClient.bottom > wndPtr->rectClient.top ? \
76 (wndPtr->rectClient.bottom - wndPtr->rectClient.top) / es->txtht : 0)
77 #define EditBufLen(wndPtr) (wndPtr->dwStyle & ES_MULTILINE \
78 ? EDITLEN : ENTRYLEN)
79 #define CurrChar (EDIT_TextLine(hwnd, es->CurrLine) + es->CurrCol)
80 #define SelMarked(es) (es->SelBegLine != 0 || es->SelBegCol != 0 || \
81 es->SelEndLine != 0 || es->SelEndCol != 0)
82 #define ROUNDUP(numer, denom) (((numer) % (denom)) \
83 ? ((((numer) + (denom)) / (denom)) * (denom)) \
84 : (numer) + (denom))
86 /* macros to access window styles */
87 #define IsAutoVScroll() (wndPtr->dwStyle & ES_AUTOVSCROLL)
88 #define IsAutoHScroll() (wndPtr->dwStyle & ES_AUTOHSCROLL)
89 #define IsMultiLine() (wndPtr->dwStyle & ES_MULTILINE)
90 #define IsVScrollBar() (wndPtr->dwStyle & WS_VSCROLL)
91 #define IsHScrollBar() (wndPtr->dwStyle & WS_HSCROLL)
93 /* internal variables */
94 static BOOL TextMarking; /* TRUE if text marking in progress */
95 static BOOL ButtonDown; /* TRUE if left mouse button down */
96 static int ButtonRow; /* row in text buffer when button pressed */
97 static int ButtonCol; /* col in text buffer when button pressed */
100 LONG EditWndProc(HWND hWnd, WORD uMsg, WORD wParam, LONG lParam);
101 long EDIT_NCCreateMsg(HWND hwnd, LONG lParam);
102 long EDIT_CreateMsg(HWND hwnd, LONG lParam);
103 void EDIT_ClearTextPointers(HWND hwnd);
104 void EDIT_BuildTextPointers(HWND hwnd);
105 void EDIT_ModTextPointers(HWND hwnd, int lineno, int var);
106 void EDIT_PaintMsg(HWND hwnd);
107 HANDLE EDIT_GetTextLine(HWND hwnd, int selection);
108 char *EDIT_TextLine(HWND hwnd, int sel);
109 int EDIT_StrLength(HWND hwnd, unsigned char *str, int len, int pcol);
110 int EDIT_LineLength(HWND hwnd, int num);
111 void EDIT_WriteTextLine(HWND hwnd, RECT *rc, int y);
112 void EDIT_WriteText(HWND hwnd, char *lp, int off, int len, int row,
113 int col, RECT *rc, BOOL blank, BOOL reverse);
114 HANDLE EDIT_GetStr(HWND hwnd, char *lp, int off, int len, int *diff);
115 void EDIT_CharMsg(HWND hwnd, WORD wParam);
116 void EDIT_KeyTyped(HWND hwnd, short ch);
117 int EDIT_CharWidth(HWND hwnd, short ch, int pcol);
118 int EDIT_GetNextTabStop(HWND hwnd, int pcol);
119 void EDIT_Forward(HWND hwnd);
120 void EDIT_Downward(HWND hwnd);
121 void EDIT_Upward(HWND hwnd);
122 void EDIT_Backward(HWND hwnd);
123 void EDIT_End(HWND hwnd);
124 void EDIT_Home(HWND hwnd);
125 void EDIT_StickEnd(HWND hwnd);
126 void EDIT_KeyDownMsg(HWND hwnd, WORD wParam);
127 void EDIT_KeyHScroll(HWND hwnd, WORD opt);
128 void EDIT_KeyVScrollLine(HWND hwnd, WORD opt);
129 void EDIT_KeyVScrollPage(HWND hwnd, WORD opt);
130 void EDIT_KeyVScrollDoc(HWND hwnd, WORD opt);
131 int EDIT_ComputeVScrollPos(HWND hwnd);
132 int EDIT_ComputeHScrollPos(HWND hwnd);
133 void EDIT_DelKey(HWND hwnd);
134 void EDIT_VScrollMsg(HWND hwnd, WORD wParam, LONG lParam);
135 void EDIT_VScrollLine(HWND hwnd, WORD opt);
136 void EDIT_VScrollPage(HWND hwnd, WORD opt);
137 void EDIT_HScrollMsg(HWND hwnd, WORD wParam, LONG lParam);
138 void EDIT_SizeMsg(HWND hwnd, WORD wParam, LONG lParam);
139 void EDIT_LButtonDownMsg(HWND hwnd, WORD wParam, LONG lParam);
140 void EDIT_MouseMoveMsg(HWND hwnd, WORD wParam, LONG lParam);
141 int EDIT_PixelToChar(HWND hwnd, int row, int *pixel);
142 LONG EDIT_SetTextMsg(HWND hwnd, LONG lParam);
143 void EDIT_ClearText(HWND hwnd);
144 void EDIT_SetSelMsg(HWND hwnd, WORD wParam, LONG lParam);
145 void EDIT_GetLineCol(HWND hwnd, int off, int *line, int *col);
146 void EDIT_DeleteSel(HWND hwnd);
147 void EDIT_ClearSel(HWND hwnd);
148 int EDIT_TextLineNumber(HWND hwnd, char *lp);
149 void EDIT_SetAnchor(HWND hwnd, int row, int col);
150 void EDIT_ExtendSel(HWND hwnd, int x, int y);
151 void EDIT_WriteSel(HWND hwnd, int y, int start, int end);
152 void EDIT_StopMarking(HWND hwnd);
153 LONG EDIT_GetLineMsg(HWND hwnd, WORD wParam, LONG lParam);
154 LONG EDIT_GetSelMsg(HWND hwnd);
155 void EDIT_ReplaceSel(HWND hwnd, LONG lParam);
156 void EDIT_InsertText(HWND hwnd, char *str, int len);
157 LONG EDIT_LineFromCharMsg(HWND hwnd, WORD wParam);
158 LONG EDIT_LineIndexMsg(HWND hwnd, WORD wParam);
159 LONG EDIT_LineLengthMsg(HWND hwnd, WORD wParam);
160 void EDIT_SetFont(HWND hwnd, WORD wParam, LONG lParam);
161 void EDIT_SaveDeletedText(HWND hwnd, char *deltext, int len, int line,
162 int col);
163 void EDIT_ClearDeletedText(HWND hwnd);
164 LONG EDIT_UndoMsg(HWND hwnd);
165 unsigned int EDIT_HeapAlloc(HWND hwnd, int bytes);
166 void *EDIT_HeapAddr(HWND hwnd, unsigned int handle);
167 unsigned int EDIT_HeapReAlloc(HWND hwnd, unsigned int handle, int bytes);
168 void EDIT_HeapFree(HWND hwnd, unsigned int handle);
169 unsigned int EDIT_HeapSize(HWND hwnd, unsigned int handle);
170 void EDIT_SetHandleMsg(HWND hwnd, WORD wParam);
171 LONG EDIT_SetTabStopsMsg(HWND hwnd, WORD wParam, LONG lParam);
172 void EDIT_CopyToClipboard(HWND hwnd);
173 void EDIT_PasteMsg(HWND hwnd);
174 void swap(int *a, int *b);
177 LONG EditWndProc(HWND hwnd, WORD uMsg, WORD wParam, LONG lParam)
179 LONG lResult = 0L;
180 char *textPtr;
181 int len;
182 WND *wndPtr = WIN_FindWndPtr(hwnd);
183 EDITSTATE *es =
184 (EDITSTATE *)EDIT_HeapAddr(hwnd, (HANDLE)(*(wndPtr->wExtra)));
186 switch (uMsg) {
187 case EM_CANUNDO:
188 lResult = es->hDeletedText;
189 break;
191 case EM_EMPTYUNDOBUFFER:
192 EDIT_ClearDeletedText(hwnd);
193 break;
195 case EM_FMTLINES:
196 fprintf(stdnimp,"edit: EM_FMTLINES message received\n");
197 if (!wParam)
198 lResult = 1L;
199 else
200 lResult = 0L;
201 break;
203 case EM_GETFIRSTVISIBLELINE:
204 lResult = es->wtop;
205 break;
207 case EM_GETHANDLE:
208 lResult = es->hText;
209 break;
211 case EM_GETLINE:
212 if (IsMultiLine())
213 lResult = EDIT_GetLineMsg(hwnd, wParam, lParam);
214 else
215 lResult = 0L;
216 break;
218 case EM_GETLINECOUNT:
219 if (IsMultiLine())
220 lResult = es->wlines;
221 else
222 lResult = 0L;
223 break;
225 case EM_GETMODIFY:
226 lResult = es->TextChanged;
227 break;
229 case EM_GETPASSWORDCHAR:
230 fprintf(stdnimp,"edit: cannot process EM_GETPASSWORDCHAR message\n");
231 break;
233 case EM_GETRECT:
234 GetWindowRect(hwnd, (LPRECT)lParam);
235 break;
237 case EM_GETSEL:
238 lResult = EDIT_GetSelMsg(hwnd);
239 break;
241 case EM_GETWORDBREAKPROC:
242 fprintf(stdnimp,"edit: cannot process EM_GETWORDBREAKPROC message\n");
243 break;
245 case EM_LIMITTEXT:
246 if (wParam)
247 es->MaxTextLen = wParam;
248 else if (IsMultiLine())
249 es->MaxTextLen = 65535;
250 else
251 es->MaxTextLen = 32767;
252 break;
254 case EM_LINEFROMCHAR:
255 lResult = EDIT_LineFromCharMsg(hwnd, wParam);
256 break;
258 case EM_LINEINDEX:
259 if (IsMultiLine())
260 lResult = EDIT_LineIndexMsg(hwnd, wParam);
261 else
262 lResult = 0L;
263 break;
265 case EM_LINELENGTH:
266 lResult = EDIT_LineLengthMsg(hwnd, wParam);
267 break;
269 case EM_LINESCROLL:
270 fprintf(stdnimp,"edit: cannot process EM_LINESCROLL message\n");
271 break;
273 case EM_REPLACESEL:
274 HideCaret(hwnd);
275 EDIT_ReplaceSel(hwnd, lParam);
276 SetCaretPos(es->WndCol, es->WndRow * es->txtht);
277 ShowCaret(hwnd);
278 break;
280 case EM_SETHANDLE:
281 HideCaret(hwnd);
282 EDIT_SetHandleMsg(hwnd, wParam);
283 SetCaretPos(es->WndCol, es->WndRow * es->txtht);
284 ShowCaret(hwnd);
285 break;
287 case EM_SETMODIFY:
288 es->TextChanged = wParam;
289 break;
291 case EM_SETPASSWORDCHAR:
292 fprintf(stdnimp,"edit: cannot process EM_SETPASSWORDCHAR message\n");
293 break;
295 case EM_SETREADONLY:
296 fprintf(stdnimp,"edit: cannot process EM_SETREADONLY message\n");
297 break;
299 case EM_SETRECT:
300 case EM_SETRECTNP:
301 fprintf(stdnimp,"edit: cannot process EM_SETRECT(NP) message\n");
302 break;
304 case EM_SETSEL:
305 HideCaret(hwnd);
306 EDIT_SetSelMsg(hwnd, wParam, lParam);
307 SetCaretPos(es->WndCol, es->WndRow * es->txtht);
308 ShowCaret(hwnd);
309 break;
311 case EM_SETTABSTOPS:
312 lResult = EDIT_SetTabStopsMsg(hwnd, wParam, lParam);
313 break;
315 case EM_SETWORDBREAKPROC:
316 fprintf(stdnimp,"edit: cannot process EM_SETWORDBREAKPROC message\n");
317 break;
319 case EM_UNDO:
320 HideCaret(hwnd);
321 lResult = EDIT_UndoMsg(hwnd);
322 SetCaretPos(es->WndCol, es->WndRow * es->txtht);
323 ShowCaret(hwnd);
324 break;
326 case WM_GETDLGCODE:
327 return DLGC_HASSETSEL | DLGC_WANTCHARS | DLGC_WANTARROWS;
329 case WM_CHAR:
330 EDIT_CharMsg(hwnd, wParam);
331 break;
333 case WM_COPY:
334 EDIT_CopyToClipboard(hwnd);
335 EDIT_ClearSel(hwnd);
336 break;
338 case WM_CREATE:
339 lResult = EDIT_CreateMsg(hwnd, lParam);
340 break;
342 case WM_CUT:
343 EDIT_CopyToClipboard(hwnd);
344 EDIT_DeleteSel(hwnd);
345 break;
347 case WM_DESTROY:
348 EDIT_HeapFree(hwnd, es->hTextPtrs);
349 EDIT_HeapFree(hwnd, es->hCharWidths);
350 EDIT_HeapFree(hwnd, es->hText);
351 EDIT_HeapFree(hwnd, (HANDLE)(*(wndPtr->wExtra)));
352 break;
354 case WM_ENABLE:
355 InvalidateRect(hwnd, NULL, FALSE);
356 break;
358 case WM_GETTEXT:
359 textPtr = EDIT_HeapAddr(hwnd, es->hText);
360 if ((int)wParam > (len = strlen(textPtr)))
362 strcpy((char *)lParam, textPtr);
363 lResult = (DWORD)len ;
365 else
366 lResult = 0L;
367 break;
369 case WM_GETTEXTLENGTH:
370 textPtr = EDIT_HeapAddr(hwnd, es->hText);
371 lResult = (DWORD)strlen(textPtr);
372 break;
374 case WM_HSCROLL:
375 EDIT_HScrollMsg(hwnd, wParam, lParam);
376 break;
378 case WM_KEYDOWN:
379 EDIT_KeyDownMsg(hwnd, wParam);
380 break;
382 case WM_KILLFOCUS:
383 DestroyCaret();
384 NOTIFY_PARENT(hwnd, EN_KILLFOCUS);
385 break;
387 case WM_LBUTTONDOWN:
388 HideCaret(hwnd);
389 SetFocus(hwnd);
390 EDIT_LButtonDownMsg(hwnd, wParam, lParam);
391 SetCaretPos(es->WndCol, es->WndRow * es->txtht);
392 ShowCaret(hwnd);
393 break;
395 case WM_LBUTTONUP:
396 ButtonDown = FALSE;
397 if (TextMarking)
398 EDIT_StopMarking(hwnd);
399 break;
401 case WM_MOUSEMOVE:
402 HideCaret(hwnd);
403 EDIT_MouseMoveMsg(hwnd, wParam, lParam);
404 SetCaretPos(es->WndCol, es->WndRow * es->txtht);
405 ShowCaret(hwnd);
406 break;
408 case WM_MOVE:
409 lResult = 0;
410 break;
412 case WM_NCCREATE:
413 lResult = EDIT_NCCreateMsg(hwnd, lParam);
414 break;
416 case WM_PAINT:
417 EDIT_PaintMsg(hwnd);
418 break;
420 case WM_PASTE:
421 EDIT_PasteMsg(hwnd);
422 break;
424 case WM_SETFOCUS:
425 CreateCaret(hwnd, 0, 2, es->txtht);
426 SetCaretPos(es->WndCol, es->WndRow * es->txtht);
427 ShowCaret(hwnd);
428 NOTIFY_PARENT(hwnd, EN_SETFOCUS);
429 break;
431 case WM_SETFONT:
432 HideCaret(hwnd);
433 EDIT_SetFont(hwnd, wParam, lParam);
434 SetCaretPos(es->WndCol, es->WndRow * es->txtht);
435 ShowCaret(hwnd);
436 break;
437 #if 0
438 case WM_SETREDRAW:
439 dprintf_edit(stddeb, "WM_SETREDRAW: hwnd=%d, wParam=%x\n",
440 hwnd, wParam);
441 lResult = 0;
442 break;
443 #endif
444 case WM_SETTEXT:
445 EDIT_SetTextMsg(hwnd, lParam);
446 break;
448 case WM_SIZE:
449 EDIT_SizeMsg(hwnd, wParam, lParam);
450 lResult = 0;
451 break;
453 case WM_VSCROLL:
454 EDIT_VScrollMsg(hwnd, wParam, lParam);
455 break;
457 default:
458 lResult = DefWindowProc(hwnd, uMsg, wParam, lParam);
459 break;
462 return lResult;
466 /*********************************************************************
467 * WM_NCCREATE message function
470 long EDIT_NCCreateMsg(HWND hwnd, LONG lParam)
472 CREATESTRUCT *createStruct = (CREATESTRUCT *)lParam;
473 WND *wndPtr = WIN_FindWndPtr(hwnd);
474 EDITSTATE *es;
475 unsigned int *textPtrs;
476 char *text;
478 /* store pointer to local or global heap in window structure so that */
479 /* EDITSTATE structure itself can be stored on local heap */
480 if (HEAP_LocalFindHeap(createStruct->hInstance)!=NULL)
481 (MDESC **)*(LONG *)(wndPtr->wExtra + 2) =
482 &HEAP_LocalFindHeap(createStruct->hInstance)->free_list;
483 else
485 (MDESC **)*(LONG *)(wndPtr->wExtra + 2) =
486 GlobalLock(createStruct->hInstance);
487 /* GlobalUnlock(createStruct->hInstance); */
489 /* allocate space for state variable structure */
490 (HANDLE)(*(wndPtr->wExtra)) = EDIT_HeapAlloc(hwnd, sizeof(EDITSTATE));
491 es = (EDITSTATE *)EDIT_HeapAddr(hwnd, (HANDLE)(*(wndPtr->wExtra)));
492 es->hTextPtrs = EDIT_HeapAlloc(hwnd, sizeof(int));
493 textPtrs = (unsigned int *)EDIT_HeapAddr(hwnd, es->hTextPtrs);
494 es->hCharWidths = EDIT_HeapAlloc(hwnd, 256 * sizeof(short));
496 /* --- text buffer */
497 es->MaxTextLen = MAXTEXTLEN + 1;
498 if (!(createStruct->lpszName))
500 es->textlen = EditBufLen(wndPtr) + 1;
501 es->hText = EDIT_HeapAlloc(hwnd, EditBufLen(wndPtr) + 2);
502 text = EDIT_HeapAddr(hwnd, es->hText);
503 memset(text, 0, es->textlen + 2);
504 EDIT_ClearTextPointers(hwnd);
506 else
508 if (strlen(createStruct->lpszName) < EditBufLen(wndPtr))
510 es->textlen = EditBufLen(wndPtr) + 1;
511 es->hText = EDIT_HeapAlloc(hwnd, EditBufLen(wndPtr) + 2);
512 text = EDIT_HeapAddr(hwnd, es->hText);
513 strcpy(text, createStruct->lpszName);
514 *(text + es->textlen) = '\0';
516 else
518 es->hText = EDIT_HeapAlloc(hwnd,
519 strlen(createStruct->lpszName) + 2);
520 text = EDIT_HeapAddr(hwnd, es->hText);
521 strcpy(text, createStruct->lpszName);
522 es->textlen = strlen(createStruct->lpszName) + 1;
524 *(text + es->textlen + 1) = '\0';
525 EDIT_BuildTextPointers(hwnd);
528 /* ES_AUTOVSCROLL and ES_AUTOHSCROLL are automatically applied if */
529 /* the corresponding WS_* style is set */
530 if (createStruct->style & WS_VSCROLL)
531 wndPtr->dwStyle |= ES_AUTOVSCROLL;
532 if (createStruct->style & WS_HSCROLL)
533 wndPtr->dwStyle |= ES_AUTOHSCROLL;
535 /* remove the WS_CAPTION style if it has been set - this is really a */
536 /* pseudo option made from a combination of WS_BORDER and WS_DLGFRAME */
537 if (wndPtr->dwStyle & WS_BORDER && wndPtr->dwStyle & WS_DLGFRAME)
538 wndPtr->dwStyle ^= WS_DLGFRAME;
540 return 1;
544 /*********************************************************************
545 * WM_CREATE message function
548 long EDIT_CreateMsg(HWND hwnd, LONG lParam)
550 HDC hdc;
551 WND *wndPtr = WIN_FindWndPtr(hwnd);
552 EDITSTATE *es =
553 (EDITSTATE *)EDIT_HeapAddr(hwnd, (HANDLE)(*(wndPtr->wExtra)));
554 CLASS *classPtr;
555 short *charWidths;
556 TEXTMETRIC tm;
557 char *text;
559 /* initialize state variable structure */
560 hdc = GetDC(hwnd);
562 /* --- char width array */
563 /* only initialise chars <= 32 as X returns strange widths */
564 /* for other chars */
565 charWidths = (short *)EDIT_HeapAddr(hwnd, es->hCharWidths);
566 memset(charWidths, 0, 256 * sizeof(short));
567 GetCharWidth(hdc, 32, 254, &charWidths[32]);
569 /* --- other structure variables */
570 GetTextMetrics(hdc, &tm);
571 es->txtht = tm.tmHeight + tm.tmExternalLeading;
572 es->wlines = 0;
573 es->wtop = es->wleft = 0;
574 es->CurrCol = es->CurrLine = 0;
575 es->WndCol = es->WndRow = 0;
576 es->TextChanged = FALSE;
577 es->textwidth = 0;
578 es->SelBegLine = es->SelBegCol = 0;
579 es->SelEndLine = es->SelEndCol = 0;
580 es->hFont = 0;
581 es->hDeletedText = 0;
582 es->DeletedLength = 0;
583 es->NumTabStops = 0;
584 es->hTabStops = EDIT_HeapAlloc(hwnd, sizeof(int));
586 /* allocate space for a line full of blanks to speed up */
587 /* line filling */
588 es->hBlankLine = EDIT_HeapAlloc(hwnd, (ClientWidth(wndPtr) /
589 charWidths[32]) + 2);
590 text = EDIT_HeapAddr(hwnd, es->hBlankLine);
591 memset(text, ' ', (ClientWidth(wndPtr) / charWidths[32]) + 2);
593 /* set up text cursor for edit class */
594 CLASS_FindClassByName("EDIT", 0, &classPtr);
595 classPtr->wc.hCursor = LoadCursor(0, IDC_IBEAM);
597 /* paint background on first WM_PAINT */
598 es->PaintBkgd = TRUE;
600 ReleaseDC(hwnd, hdc);
601 return 0L;
605 /*********************************************************************
606 * EDIT_ClearTextPointers
608 * Clear and initialize text line pointer array.
611 void EDIT_ClearTextPointers(HWND hwnd)
613 unsigned int *textPtrs;
614 WND *wndPtr = WIN_FindWndPtr(hwnd);
615 EDITSTATE *es =
616 (EDITSTATE *)EDIT_HeapAddr(hwnd, (HANDLE)(*(wndPtr->wExtra)));
618 es->hTextPtrs = EDIT_HeapReAlloc(hwnd, es->hTextPtrs, sizeof(int));
619 textPtrs = (unsigned int *)EDIT_HeapAddr(hwnd, es->hTextPtrs);
620 *textPtrs = 0;
624 /*********************************************************************
625 * EDIT_BuildTextPointers
627 * Build array of pointers to text lines.
630 #define INITLINES 100
632 void EDIT_BuildTextPointers(HWND hwnd)
634 WND *wndPtr = WIN_FindWndPtr(hwnd);
635 char *text, *cp;
636 int incrs = INITLINES;
637 unsigned int off, len;
638 EDITSTATE *es;
639 unsigned int *textPtrs;
640 short *charWidths;
642 es = (EDITSTATE *)EDIT_HeapAddr(hwnd, (HANDLE)(*(wndPtr->wExtra)));
643 text = EDIT_HeapAddr(hwnd, es->hText);
644 textPtrs = (unsigned int *)EDIT_HeapAddr(hwnd, es->hTextPtrs);
645 charWidths = (short *)EDIT_HeapAddr(hwnd, es->hCharWidths);
647 es->textwidth = es->wlines = 0;
648 cp = text;
650 /* advance through text buffer */
651 while (*cp)
653 /* increase size of text pointer array */
654 if (incrs == INITLINES)
656 incrs = 0;
657 es->hTextPtrs = EDIT_HeapReAlloc(hwnd, es->hTextPtrs,
658 (es->wlines + INITLINES) * sizeof(int));
659 textPtrs = (unsigned int *)EDIT_HeapAddr(hwnd, es->hTextPtrs);
661 off = (unsigned int)(cp - text); /* offset of beginning of line */
662 *(textPtrs + es->wlines) = off;
663 es->wlines++;
664 incrs++;
665 len = 0;
667 /* advance through current line */
668 while (*cp && *cp != '\n')
670 len += EDIT_CharWidth(hwnd, (BYTE)*cp, len);
671 /* width of line in pixels */
672 cp++;
674 es->textwidth = max(es->textwidth, len);
675 if (*cp)
676 cp++; /* skip '\n' */
679 off = (unsigned int)(cp - text);
680 *(textPtrs + es->wlines) = off;
684 /*********************************************************************
685 * EDIT_ModTextPointers
687 * Modify text pointers from a specified position.
690 void EDIT_ModTextPointers(HWND hwnd, int lineno, int var)
692 WND *wndPtr = WIN_FindWndPtr(hwnd);
693 EDITSTATE *es =
694 (EDITSTATE *)EDIT_HeapAddr(hwnd, (HANDLE)(*(wndPtr->wExtra)));
695 unsigned int *textPtrs =
696 (unsigned int *)EDIT_HeapAddr(hwnd, es->hTextPtrs);
698 while (lineno < es->wlines)
699 *(textPtrs + lineno++) += var;
703 /*********************************************************************
704 * WM_PAINT message function
707 void EDIT_PaintMsg(HWND hwnd)
709 PAINTSTRUCT ps;
710 HDC hdc;
711 int y;
712 RECT rc;
713 WND *wndPtr = WIN_FindWndPtr(hwnd);
714 EDITSTATE *es =
715 (EDITSTATE *)EDIT_HeapAddr(hwnd, (HANDLE)(*(wndPtr->wExtra)));
717 hdc = BeginPaint(hwnd, &ps);
718 rc = ps.rcPaint;
720 dprintf_edit(stddeb,"WM_PAINT: rc=(%d,%d), (%d,%d)\n", rc.left, rc.top,
721 rc.right, rc.bottom);
723 if (es->PaintBkgd)
724 FillWindow(GetParent(hwnd), hwnd, hdc, CTLCOLOR_EDIT);
726 for (y = (rc.top / es->txtht); y <= (rc.bottom / es->txtht); y++)
728 if (y < es->wlines - es->wtop)
729 EDIT_WriteTextLine(hwnd, &rc, y + es->wtop);
732 EndPaint(hwnd, &ps);
736 /*********************************************************************
737 * EDIT_GetTextLine
739 * Get a copy of the text in the specified line.
742 HANDLE EDIT_GetTextLine(HWND hwnd, int selection)
744 char *line;
745 HANDLE hLine;
746 int len = 0;
747 char *cp, *cp1;
749 dprintf_edit(stddeb,"GetTextLine %d\n", selection);
750 cp = cp1 = EDIT_TextLine(hwnd, selection);
751 /* advance through line */
752 while (*cp && *cp != '\r')
754 len++;
755 cp++;
758 /* store selected line and return handle */
759 hLine = EDIT_HeapAlloc(hwnd, len + 6);
760 line = (char *)EDIT_HeapAddr(hwnd, hLine);
761 memmove(line, cp1, len);
762 line[len] = '\0';
763 return hLine;
767 /*********************************************************************
768 * EDIT_TextLine
770 * Return a pointer to the text in the specified line.
773 char *EDIT_TextLine(HWND hwnd, int sel)
775 WND *wndPtr = WIN_FindWndPtr(hwnd);
776 EDITSTATE *es =
777 (EDITSTATE *)EDIT_HeapAddr(hwnd, (HANDLE)(*(wndPtr->wExtra)));
778 char *text = EDIT_HeapAddr(hwnd, es->hText);
779 unsigned int *textPtrs =
780 (unsigned int *)EDIT_HeapAddr(hwnd, es->hTextPtrs);
782 if(sel>es->wlines)return NULL;
783 return (text + *(textPtrs + sel));
787 /*********************************************************************
788 * EDIT_StrLength
790 * Return length of string _str_ of length _len_ characters in pixels.
791 * The current column offset in pixels _pcol_ is required to calculate
792 * the width of a tab.
795 int EDIT_StrLength(HWND hwnd, unsigned char *str, int len, int pcol)
797 int i, plen = 0;
799 for (i = 0; i < len; i++)
800 plen += EDIT_CharWidth(hwnd, (BYTE)(*(str + i)), pcol + plen);
802 dprintf_edit(stddeb,"EDIT_StrLength: returning %d\n", plen);
803 return plen;
807 /*********************************************************************
808 * EDIT_LineLength
810 * Return length of line _num_ in characters.
813 int EDIT_LineLength(HWND hwnd, int num)
815 char *cp = EDIT_TextLine(hwnd, num);
816 char *cp1;
818 if(!cp)return 0;
819 cp1 = strchr(cp, '\r');
820 return cp1 ? (int)(cp1 - cp) : strlen(cp);
824 /*********************************************************************
825 * EDIT_WriteTextLine
827 * Write the line of text at offset _y_ in text buffer to a window.
830 void EDIT_WriteTextLine(HWND hwnd, RECT *rect, int y)
832 int len = 0;
833 HANDLE hLine;
834 unsigned char *lp;
835 int lnlen, lnlen1;
836 int col, off = 0;
837 int sbl, sel, sbc, sec;
838 RECT rc;
839 WND *wndPtr = WIN_FindWndPtr(hwnd);
840 EDITSTATE *es =
841 (EDITSTATE *)EDIT_HeapAddr(hwnd, (HANDLE)(*(wndPtr->wExtra)));
843 /* initialize rectangle if NULL, else copy */
844 if (rect)
845 CopyRect(&rc, rect);
846 else
847 GetClientRect(hwnd, &rc);
849 dprintf_edit(stddeb,"WriteTextLine %d\n", y);
851 /* make sure y is inside the window */
852 if (y < es->wtop || y > (es->wtop + ClientHeight(wndPtr, es)))
854 dprintf_edit(stddeb,"EDIT_WriteTextLine: y (%d) is not a displayed line\n", y);
855 return;
858 /* make sure rectangle is within window */
859 if (rc.left >= ClientWidth(wndPtr) - 1)
861 dprintf_edit(stddeb,"EDIT_WriteTextLine: rc.left (%d) is greater than right edge\n",
862 rc.left);
863 return;
865 if (rc.right <= 0)
867 dprintf_edit(stddeb,"EDIT_WriteTextLine: rc.right (%d) is less than left edge\n",
868 rc.right);
869 return;
871 if (y - es->wtop < (rc.top / es->txtht) ||
872 y - es->wtop > (rc.bottom / es->txtht))
874 dprintf_edit(stddeb,"EDIT_WriteTextLine: y (%d) is outside window\n", y);
875 return;
878 /* get the text and length of line */
879 if ((hLine = EDIT_GetTextLine(hwnd, y)) == 0)
880 return;
881 lp = (unsigned char *)EDIT_HeapAddr(hwnd, hLine);
882 lnlen = EDIT_StrLength(hwnd, lp, strlen(lp), 0);
883 lnlen1 = lnlen;
885 /* build the line to display */
886 if (lnlen < es->wleft)
887 lnlen = 0;
888 else
889 off += es->wleft;
891 if (lnlen > rc.left)
893 off += rc.left;
894 lnlen = lnlen1 - off;
895 len = min(lnlen, rc.right - rc.left);
898 if (SelMarked(es))
900 sbl = es->SelBegLine;
901 sel = es->SelEndLine;
902 sbc = es->SelBegCol;
903 sec = es->SelEndCol;
905 /* put lowest marker first */
906 if (sbl > sel)
908 swap(&sbl, &sel);
909 swap(&sbc, &sec);
911 if (sbl == sel && sbc > sec)
912 swap(&sbc, &sec);
914 if (y < sbl || y > sel)
915 EDIT_WriteText(hwnd, lp, off, len, y - es->wtop, rc.left, &rc,
916 TRUE, FALSE);
917 else if (y > sbl && y < sel)
918 EDIT_WriteText(hwnd, lp, off, len, y - es->wtop, rc.left, &rc,
919 TRUE, TRUE);
920 else if (y == sbl)
922 col = EDIT_StrLength(hwnd, lp, sbc, 0);
923 if (col > (es->wleft + rc.left))
925 len = min(col - off, rc.right - off);
926 EDIT_WriteText(hwnd, lp, off, len, y - es->wtop,
927 rc.left, &rc, FALSE, FALSE);
928 off = col;
930 if (y == sel)
932 col = EDIT_StrLength(hwnd, lp, sec, 0);
933 if (col < (es->wleft + rc.right))
935 len = min(col - off, rc.right - off);
936 EDIT_WriteText(hwnd, lp, off, len, y - es->wtop,
937 off - es->wleft, &rc, FALSE, TRUE);
938 off = col;
939 len = min(lnlen - off, rc.right - off);
940 EDIT_WriteText(hwnd, lp, off, len, y - es->wtop,
941 off - es->wleft, &rc, TRUE, FALSE);
943 else
945 len = min(lnlen - off, rc.right - off);
946 EDIT_WriteText(hwnd, lp, off, len, y - es->wtop,
947 off - es->wleft, &rc, TRUE, TRUE);
950 else
952 len = min(lnlen - off, rc.right - off);
953 if (col < (es->wleft + rc.right))
954 EDIT_WriteText(hwnd, lp, off, len, y - es->wtop,
955 off - es->wleft, &rc, TRUE, TRUE);
958 else if (y == sel)
960 col = EDIT_StrLength(hwnd, lp, sec, 0);
961 if (col < (es->wleft + rc.right))
963 len = min(col - off, rc.right - off);
964 EDIT_WriteText(hwnd, lp, off, len, y - es->wtop,
965 off - es->wleft, &rc, FALSE, TRUE);
966 off = col;
967 len = min(lnlen - off, rc.right - off);
968 EDIT_WriteText(hwnd, lp, off, len, y - es->wtop,
969 off - es->wleft, &rc, TRUE, FALSE);
973 else
974 EDIT_WriteText(hwnd, lp, off, len, y - es->wtop, rc.left, &rc,
975 TRUE, FALSE);
977 EDIT_HeapFree(hwnd, hLine);
981 /*********************************************************************
982 * EDIT_WriteText
984 * Write text to a window
985 * lp - text line
986 * off - offset in text line (in pixels)
987 * len - length from off (in pixels)
988 * row - line in window
989 * col - column in window
990 * rc - rectangle in which to display line
991 * blank - blank remainder of line?
992 * reverse - reverse color of line?
995 void EDIT_WriteText(HWND hwnd, char *lp, int off, int len, int row,
996 int col, RECT *rc, BOOL blank, BOOL reverse)
998 HDC hdc;
999 HANDLE hStr;
1000 char *str, *cp, *cp1;
1001 int diff, num_spaces, tabwidth, scol;
1002 HRGN hrgnClip;
1003 COLORREF oldTextColor, oldBkgdColor;
1004 HFONT oldfont;
1005 WND *wndPtr = WIN_FindWndPtr(hwnd);
1006 EDITSTATE *es =
1007 (EDITSTATE *)EDIT_HeapAddr(hwnd, (HANDLE)(*(wndPtr->wExtra)));
1008 short *charWidths = (short *)EDIT_HeapAddr(hwnd, es->hCharWidths);
1009 char *blanks = (char *)EDIT_HeapAddr(hwnd, es->hBlankLine);
1011 dprintf_edit(stddeb,"EDIT_WriteText lp=%s, off=%d, len=%d, row=%d, col=%d, reverse=%d\n", lp, off, len, row, col, reverse);
1013 hdc = GetDC(hwnd);
1014 hStr = EDIT_GetStr(hwnd, lp, off, len, &diff);
1015 str = (char *)EDIT_HeapAddr(hwnd, hStr);
1016 hrgnClip = CreateRectRgnIndirect(rc);
1017 SelectClipRgn(hdc, hrgnClip);
1019 if (es->hFont)
1020 oldfont = (HFONT)SelectObject(hdc, (HANDLE)es->hFont);
1022 SendMessage(GetParent(hwnd), WM_CTLCOLOR, (WORD)hdc,
1023 MAKELPARAM(hwnd, CTLCOLOR_EDIT));
1025 if (reverse)
1027 oldBkgdColor = GetBkColor(hdc);
1028 oldTextColor = GetTextColor(hdc);
1029 SetBkColor(hdc, oldTextColor);
1030 SetTextColor(hdc, oldBkgdColor);
1033 if (strlen(blanks) < (ClientWidth(wndPtr) / charWidths[32]) + 2)
1035 es->hBlankLine = EDIT_HeapReAlloc(hwnd, es->hBlankLine,
1036 (ClientWidth(wndPtr) / charWidths[32]) + 2);
1037 blanks = EDIT_HeapAddr(hwnd, es->hBlankLine);
1038 memset(blanks, ' ', (ClientWidth(wndPtr) / charWidths[32]) + 2);
1041 if (!(cp = strchr(str, VK_TAB)))
1042 TextOut(hdc, col - diff, row * es->txtht, str, strlen(str));
1043 else
1045 TextOut(hdc, col - diff, row * es->txtht, str, (int)(cp - str));
1046 scol = EDIT_StrLength(hwnd, str, (int)(cp - str), 0);
1047 tabwidth = EDIT_CharWidth(hwnd, VK_TAB, scol);
1048 num_spaces = tabwidth / charWidths[32] + 1;
1049 TextOut(hdc, scol, row * es->txtht, blanks, num_spaces);
1050 cp++;
1051 scol += tabwidth;
1053 while ((cp1 = strchr(cp, VK_TAB)))
1055 TextOut(hdc, scol, row * es->txtht, cp, (int)(cp1 - cp));
1056 scol += EDIT_StrLength(hwnd, cp, (int)(cp1 - cp), scol);
1057 tabwidth = EDIT_CharWidth(hwnd, VK_TAB, scol);
1058 num_spaces = tabwidth / charWidths[32] + 1;
1059 TextOut(hdc, scol, row * es->txtht, blanks, num_spaces);
1060 cp = ++cp1;
1061 scol += tabwidth;
1064 TextOut(hdc, scol, row * es->txtht, cp, strlen(cp));
1067 if (reverse)
1069 SetBkColor(hdc, oldBkgdColor);
1070 SetTextColor(hdc, oldTextColor);
1073 /* blank out remainder of line if appropriate */
1074 if (blank)
1076 if ((rc->right - col) > len)
1078 num_spaces = (rc->right - col - len) / charWidths[32];
1079 TextOut(hdc, col + len, row * es->txtht, blanks, num_spaces);
1083 if (es->hFont)
1084 SelectObject(hdc, (HANDLE)oldfont);
1086 EDIT_HeapFree(hwnd, hStr);
1087 ReleaseDC(hwnd, hdc);
1091 /*********************************************************************
1092 * EDIT_GetStr
1094 * Return sub-string starting at pixel _off_ of length _len_ pixels.
1095 * If _off_ is part way through a character, the negative offset of
1096 * the beginning of the character is returned in _diff_, else _diff_
1097 * will be zero.
1100 HANDLE EDIT_GetStr(HWND hwnd, char *lp, int off, int len, int *diff)
1102 HANDLE hStr;
1103 char *str;
1104 int ch = 0, i = 0, j, s_i=0;
1105 int ch1;
1107 dprintf_edit(stddeb,"EDIT_GetStr lp='%s' off=%d len=%d\n", lp, off, len);
1109 if (off < 0) off = 0;
1110 while (i < off)
1112 s_i = i;
1113 i += EDIT_CharWidth(hwnd, (BYTE)(*(lp + ch)), i);
1114 ch++;
1116 /* if stepped past _off_, go back a character */
1117 if (i - off)
1119 i = s_i;
1120 ch--;
1122 *diff = off - i;
1123 ch1 = ch;
1124 while (i < len + off)
1126 if (*(lp + ch) == '\r' || *(lp + ch) == '\n')
1127 break;
1128 i += EDIT_CharWidth(hwnd, (BYTE)(*(lp + ch)), i);
1129 ch++;
1132 hStr = EDIT_HeapAlloc(hwnd, ch - ch1 + 3);
1133 str = (char *)EDIT_HeapAddr(hwnd, hStr);
1134 for (i = ch1, j = 0; i < ch; i++, j++)
1135 str[j] = lp[i];
1136 str[++j] = '\0';
1137 dprintf_edit(stddeb,"EDIT_GetStr: returning %s\n", str);
1138 return hStr;
1142 /*********************************************************************
1143 * WM_CHAR message function
1146 void EDIT_CharMsg(HWND hwnd, WORD wParam)
1148 WND *wndPtr = WIN_FindWndPtr(hwnd);
1150 dprintf_edit(stddeb,"EDIT_CharMsg: wParam=%c\n", (char)wParam);
1152 switch (wParam)
1154 case '\r':
1155 case '\n':
1156 if (!IsMultiLine())
1157 break;
1158 wParam = '\n';
1159 EDIT_KeyTyped(hwnd, wParam);
1160 break;
1162 case VK_TAB:
1163 if (!IsMultiLine())
1164 break;
1165 EDIT_KeyTyped(hwnd, wParam);
1166 break;
1168 default:
1169 if (wParam >= 20 && wParam <= 126)
1170 EDIT_KeyTyped(hwnd, wParam);
1171 break;
1176 /*********************************************************************
1177 * EDIT_KeyTyped
1179 * Process keystrokes that produce displayable characters.
1182 void EDIT_KeyTyped(HWND hwnd, short ch)
1184 WND *wndPtr = WIN_FindWndPtr(hwnd);
1185 EDITSTATE *es =
1186 (EDITSTATE *)EDIT_HeapAddr(hwnd, (HANDLE)(*(wndPtr->wExtra)));
1187 char *text = EDIT_HeapAddr(hwnd, es->hText);
1188 char *currchar = CurrChar;
1189 RECT rc;
1190 BOOL FullPaint = FALSE;
1192 dprintf_edit(stddeb,"EDIT_KeyTyped: ch=%c\n", (char)ch);
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 = '\r';
1209 *(currchar + 1) = '\n';
1210 *(currchar + 2) = '\0';
1211 EDIT_BuildTextPointers(hwnd);
1214 /* insert the typed character */
1215 if (text[es->textlen - 1] != '\0')
1217 /* current text buffer is full */
1218 if (es->textlen == es->MaxTextLen)
1220 /* text buffer is at maximum size */
1221 NOTIFY_PARENT(hwnd, EN_ERRSPACE);
1222 return;
1225 /* increase the text buffer size */
1226 es->textlen += GROWLENGTH;
1227 /* but not above maximum size */
1228 if (es->textlen > es->MaxTextLen)
1229 es->textlen = es->MaxTextLen;
1230 es->hText = EDIT_HeapReAlloc(hwnd, es->hText, es->textlen + 2);
1231 if (!es->hText)
1232 NOTIFY_PARENT(hwnd, EN_ERRSPACE);
1233 text = EDIT_HeapAddr(hwnd, es->hText);
1234 text[es->textlen - 1] = '\0';
1235 currchar = CurrChar;
1237 /* make space for new character and put char in buffer */
1238 if (ch == '\n')
1240 memmove(currchar + 2, currchar, strlen(currchar) + 1);
1241 *currchar = '\r';
1242 *(currchar + 1) = '\n';
1243 EDIT_ModTextPointers(hwnd, es->CurrLine + 1, 2);
1245 else
1247 memmove(currchar + 1, currchar, strlen(currchar) + 1);
1248 *currchar = ch;
1249 EDIT_ModTextPointers(hwnd, es->CurrLine + 1, 1);
1251 es->TextChanged = TRUE;
1252 NOTIFY_PARENT(hwnd, EN_UPDATE);
1254 /* re-adjust textwidth, if necessary, and redraw line */
1255 HideCaret(hwnd);
1256 if (IsMultiLine() && es->wlines > 1)
1258 es->textwidth = max(es->textwidth,
1259 EDIT_StrLength(hwnd, EDIT_TextLine(hwnd, es->CurrLine),
1260 (int)(EDIT_TextLine(hwnd, es->CurrLine + 1) -
1261 EDIT_TextLine(hwnd, es->CurrLine)), 0));
1263 else
1264 es->textwidth = max(es->textwidth,
1265 EDIT_StrLength(hwnd, text, strlen(text), 0));
1266 EDIT_WriteTextLine(hwnd, NULL, es->wtop + es->WndRow);
1268 if (ch == '\n')
1270 if (es->wleft > 0)
1271 FullPaint = TRUE;
1272 es->wleft = 0;
1273 EDIT_BuildTextPointers(hwnd);
1274 EDIT_End(hwnd);
1275 EDIT_Forward(hwnd);
1277 /* invalidate rest of window */
1278 GetClientRect(hwnd, &rc);
1279 if (!FullPaint)
1280 rc.top = es->WndRow * es->txtht;
1281 InvalidateRect(hwnd, &rc, FALSE);
1283 SetCaretPos(es->WndCol, es->WndRow * es->txtht);
1284 ShowCaret(hwnd);
1285 UpdateWindow(hwnd);
1286 NOTIFY_PARENT(hwnd, EN_CHANGE);
1287 return;
1290 /* test end of window */
1291 if (es->WndCol >= ClientWidth(wndPtr) -
1292 EDIT_CharWidth(hwnd, (BYTE)ch, es->WndCol + es->wleft))
1294 /* TODO:- Word wrap to be handled here */
1296 /* if (!(currchar == text + es->MaxTextLen - 2)) */
1297 EDIT_KeyHScroll(hwnd, SB_LINEDOWN);
1299 es->WndCol += EDIT_CharWidth(hwnd, (BYTE)ch, es->WndCol + es->wleft);
1300 es->CurrCol++;
1301 SetCaretPos(es->WndCol, es->WndRow * es->txtht);
1302 ShowCaret(hwnd);
1303 NOTIFY_PARENT(hwnd, EN_CHANGE);
1307 /*********************************************************************
1308 * EDIT_CharWidth
1310 * Return the width of the given character in pixels.
1311 * The current column offset in pixels _pcol_ is required to calculate
1312 * the width of a tab.
1315 int EDIT_CharWidth(HWND hwnd, short ch, int pcol)
1317 WND *wndPtr = WIN_FindWndPtr(hwnd);
1318 EDITSTATE *es =
1319 (EDITSTATE *)EDIT_HeapAddr(hwnd, (HANDLE)(*(wndPtr->wExtra)));
1320 short *charWidths = (short *)EDIT_HeapAddr(hwnd, es->hCharWidths);
1322 if (ch != VK_TAB)
1323 return (charWidths[ch]);
1324 else
1325 return (EDIT_GetNextTabStop(hwnd, pcol) - pcol);
1329 /*********************************************************************
1330 * EDIT_GetNextTabStop
1332 * Return the next tab stop beyond _pcol_.
1335 int EDIT_GetNextTabStop(HWND hwnd, int pcol)
1337 int i;
1338 int baseUnitWidth = LOWORD(GetDialogBaseUnits());
1339 WND *wndPtr = WIN_FindWndPtr(hwnd);
1340 EDITSTATE *es =
1341 (EDITSTATE *)EDIT_HeapAddr(hwnd, (HANDLE)(*(wndPtr->wExtra)));
1342 unsigned short *tabstops = EDIT_HeapAddr(hwnd, es->hTabStops);
1344 if (es->NumTabStops == 0)
1345 return ROUNDUP(pcol, 8 * baseUnitWidth);
1346 else if (es->NumTabStops == 1)
1347 return ROUNDUP(pcol, *tabstops * baseUnitWidth / 4);
1348 else
1350 for (i = 0; i < es->NumTabStops; i++)
1352 if (*(tabstops + i) * baseUnitWidth / 4 >= pcol)
1353 return (*(tabstops + i) * baseUnitWidth / 4);
1355 return pcol;
1360 /*********************************************************************
1361 * EDIT_Forward
1363 * Cursor right key: move right one character position.
1366 void EDIT_Forward(HWND hwnd)
1368 WND *wndPtr = WIN_FindWndPtr(hwnd);
1369 EDITSTATE *es =
1370 (EDITSTATE *)EDIT_HeapAddr(hwnd, (HANDLE)(*(wndPtr->wExtra)));
1372 if (*CurrChar == '\0')
1373 return;
1375 if (*CurrChar == '\r')
1377 EDIT_Home(hwnd);
1378 EDIT_Downward(hwnd);
1380 else
1382 es->WndCol += EDIT_CharWidth(hwnd, (BYTE)(*CurrChar), es->WndCol + es->wleft);
1383 es->CurrCol++;
1384 if (es->WndCol >= ClientWidth(wndPtr))
1385 EDIT_KeyHScroll(hwnd, SB_LINEDOWN);
1391 /*********************************************************************
1392 * EDIT_Downward
1394 * Cursor down key: move down one line.
1397 void EDIT_Downward(HWND hwnd)
1399 WND *wndPtr = WIN_FindWndPtr(hwnd);
1400 EDITSTATE *es =
1401 (EDITSTATE *)EDIT_HeapAddr(hwnd, (HANDLE)(*(wndPtr->wExtra)));
1403 dprintf_edit(stddeb,"EDIT_Downward: WndRow=%d, wtop=%d, wlines=%d\n",
1404 es->WndRow, es->wtop, es->wlines);
1406 if (IsMultiLine() && (es->WndRow + es->wtop + 1 < es->wlines))
1408 es->CurrLine++;
1409 if (es->WndRow == ClientHeight(wndPtr, es) - 1)
1411 es->WndRow++;
1412 EDIT_KeyVScrollLine(hwnd, SB_LINEDOWN);
1414 else
1415 es->WndRow++;
1416 EDIT_StickEnd(hwnd);
1421 /*********************************************************************
1422 * EDIT_Upward
1424 * Cursor up key: move up one line.
1427 void EDIT_Upward(HWND hwnd)
1429 WND *wndPtr = WIN_FindWndPtr(hwnd);
1430 EDITSTATE *es =
1431 (EDITSTATE *)EDIT_HeapAddr(hwnd, (HANDLE)(*(wndPtr->wExtra)));
1433 if (IsMultiLine() && es->CurrLine != 0)
1435 --es->CurrLine;
1436 if (es->WndRow == 0)
1438 --es->WndRow;
1439 EDIT_KeyVScrollLine(hwnd, SB_LINEUP);
1441 else
1442 --es->WndRow;
1443 EDIT_StickEnd(hwnd);
1448 /*********************************************************************
1449 * EDIT_Backward
1451 * Cursor left key: move left one character position.
1454 void EDIT_Backward(HWND hwnd)
1456 WND *wndPtr = WIN_FindWndPtr(hwnd);
1457 EDITSTATE *es =
1458 (EDITSTATE *)EDIT_HeapAddr(hwnd, (HANDLE)(*(wndPtr->wExtra)));
1460 if (es->CurrCol)
1462 --es->CurrCol;
1463 if (*CurrChar == VK_TAB)
1464 es->WndCol -= EDIT_CharWidth(hwnd, (BYTE)(*CurrChar),
1465 EDIT_StrLength(hwnd,
1466 EDIT_TextLine(hwnd, es->CurrLine),
1467 es->CurrCol, 0));
1468 else
1469 es->WndCol -= EDIT_CharWidth(hwnd, (BYTE)(*CurrChar), 0);
1470 if (es->WndCol < 0)
1471 EDIT_KeyHScroll(hwnd, SB_LINEUP);
1473 else if (IsMultiLine() && es->CurrLine != 0)
1475 EDIT_Upward(hwnd);
1476 EDIT_End(hwnd);
1481 /*********************************************************************
1482 * EDIT_End
1484 * End key: move to end of line.
1487 void EDIT_End(HWND hwnd)
1489 WND *wndPtr = WIN_FindWndPtr(hwnd);
1490 EDITSTATE *es =
1491 (EDITSTATE *)EDIT_HeapAddr(hwnd, (HANDLE)(*(wndPtr->wExtra)));
1493 while (*CurrChar && *CurrChar != '\r')
1495 es->WndCol += EDIT_CharWidth(hwnd, (BYTE)(*CurrChar), es->WndCol + es->wleft);
1496 es->CurrCol++;
1499 if (es->WndCol >= ClientWidth(wndPtr))
1501 es->wleft = es->WndCol - ClientWidth(wndPtr) + HSCROLLDIM;
1502 es->WndCol -= es->wleft;
1503 InvalidateRect(hwnd, NULL, FALSE);
1504 UpdateWindow(hwnd);
1509 /*********************************************************************
1510 * EDIT_Home
1512 * Home key: move to beginning of line.
1515 void EDIT_Home(HWND hwnd)
1517 WND *wndPtr = WIN_FindWndPtr(hwnd);
1518 EDITSTATE *es =
1519 (EDITSTATE *)EDIT_HeapAddr(hwnd, (HANDLE)(*(wndPtr->wExtra)));
1521 es->CurrCol = es->WndCol = 0;
1522 if (es->wleft != 0)
1524 es->wleft = 0;
1525 InvalidateRect(hwnd, NULL, FALSE);
1526 UpdateWindow(hwnd);
1531 /*********************************************************************
1532 * EDIT_StickEnd
1534 * Stick the cursor to the end of the line.
1537 void EDIT_StickEnd(HWND hwnd)
1539 WND *wndPtr = WIN_FindWndPtr(hwnd);
1540 EDITSTATE *es =
1541 (EDITSTATE *)EDIT_HeapAddr(hwnd, (HANDLE)(*(wndPtr->wExtra)));
1542 int len = EDIT_LineLength(hwnd, es->CurrLine);
1543 char *cp = EDIT_TextLine(hwnd, es->CurrLine);
1544 char currpel;
1546 es->CurrCol = min(len, es->CurrCol);
1547 es->WndCol = min(EDIT_StrLength(hwnd, cp, len, 0) - es->wleft, es->WndCol);
1548 currpel = EDIT_StrLength(hwnd, cp, es->CurrCol, 0);
1550 if (es->wleft > currpel)
1552 es->wleft = max(0, currpel - 20);
1553 es->WndCol = currpel - es->wleft;
1554 UpdateWindow(hwnd);
1556 else if (currpel - es->wleft >= ClientWidth(wndPtr))
1558 es->wleft = currpel - (ClientWidth(wndPtr) - 5);
1559 es->WndCol = currpel - es->wleft;
1560 UpdateWindow(hwnd);
1565 /*********************************************************************
1566 * WM_KEYDOWN message function
1569 void EDIT_KeyDownMsg(HWND hwnd, WORD wParam)
1571 WND *wndPtr = WIN_FindWndPtr(hwnd);
1572 EDITSTATE *es =
1573 (EDITSTATE *)EDIT_HeapAddr(hwnd, (HANDLE)(*(wndPtr->wExtra)));
1575 dprintf_edit(stddeb,"EDIT_KeyDownMsg: key=%x\n", wParam);
1577 HideCaret(hwnd);
1578 switch (wParam)
1580 case VK_UP:
1581 if (SelMarked(es))
1582 EDIT_ClearSel(hwnd);
1583 if (IsMultiLine())
1584 EDIT_Upward(hwnd);
1585 else
1586 EDIT_Backward(hwnd);
1587 break;
1589 case VK_DOWN:
1590 if (SelMarked(es))
1591 EDIT_ClearSel(hwnd);
1592 if (IsMultiLine())
1593 EDIT_Downward(hwnd);
1594 else
1595 EDIT_Forward(hwnd);
1596 break;
1598 case VK_RIGHT:
1599 if (SelMarked(es))
1600 EDIT_ClearSel(hwnd);
1601 EDIT_Forward(hwnd);
1602 break;
1604 case VK_LEFT:
1605 if (SelMarked(es))
1606 EDIT_ClearSel(hwnd);
1607 EDIT_Backward(hwnd);
1608 break;
1610 case VK_HOME:
1611 if (SelMarked(es))
1612 EDIT_ClearSel(hwnd);
1613 EDIT_Home(hwnd);
1614 break;
1616 case VK_END:
1617 if (SelMarked(es))
1618 EDIT_ClearSel(hwnd);
1619 EDIT_End(hwnd);
1620 break;
1622 case VK_PRIOR:
1623 if (IsMultiLine())
1625 if (SelMarked(es))
1626 EDIT_ClearSel(hwnd);
1627 EDIT_KeyVScrollPage(hwnd, SB_PAGEUP);
1629 break;
1631 case VK_NEXT:
1632 if (IsMultiLine())
1634 if (SelMarked(es))
1635 EDIT_ClearSel(hwnd);
1636 EDIT_KeyVScrollPage(hwnd, SB_PAGEDOWN);
1638 break;
1640 case VK_BACK:
1641 if (SelMarked(es))
1642 EDIT_DeleteSel(hwnd);
1643 else
1645 if (es->CurrCol == 0 && es->CurrLine == 0)
1646 break;
1647 EDIT_Backward(hwnd);
1648 EDIT_DelKey(hwnd);
1650 break;
1652 case VK_DELETE:
1653 if (SelMarked(es))
1654 EDIT_DeleteSel(hwnd);
1655 else
1656 EDIT_DelKey(hwnd);
1657 break;
1660 SetCaretPos(es->WndCol, es->WndRow * es->txtht);
1661 ShowCaret(hwnd);
1665 /*********************************************************************
1666 * EDIT_KeyHScroll
1668 * Scroll text horizontally using cursor keys.
1671 void EDIT_KeyHScroll(HWND hwnd, WORD opt)
1673 int hscrollpos;
1674 WND *wndPtr = WIN_FindWndPtr(hwnd);
1675 EDITSTATE *es =
1676 (EDITSTATE *)EDIT_HeapAddr(hwnd, (HANDLE)(*(wndPtr->wExtra)));
1678 if (opt == SB_LINEDOWN)
1680 es->wleft += HSCROLLDIM;
1681 es->WndCol -= HSCROLLDIM;
1683 else
1685 if (es->wleft == 0)
1686 return;
1687 if (es->wleft - HSCROLLDIM < 0)
1689 es->WndCol += es->wleft;
1690 es->wleft = 0;
1692 else
1694 es->wleft -= HSCROLLDIM;
1695 es->WndCol += HSCROLLDIM;
1699 InvalidateRect(hwnd, NULL, FALSE);
1700 UpdateWindow(hwnd);
1702 if (IsHScrollBar())
1704 hscrollpos = EDIT_ComputeHScrollPos(hwnd);
1705 SetScrollPos(hwnd, SB_HORZ, hscrollpos, TRUE);
1710 /*********************************************************************
1711 * EDIT_KeyVScrollLine
1713 * Scroll text vertically by one line using keyboard.
1716 void EDIT_KeyVScrollLine(HWND hwnd, WORD opt)
1718 RECT rc;
1719 int y, vscrollpos;
1720 WND *wndPtr = WIN_FindWndPtr(hwnd);
1721 EDITSTATE *es =
1722 (EDITSTATE *)EDIT_HeapAddr(hwnd, (HANDLE)(*(wndPtr->wExtra)));
1724 if (!IsMultiLine())
1725 return;
1727 if (opt == SB_LINEDOWN)
1729 /* move down one line */
1730 if (es->wtop + ClientHeight(wndPtr, es) >= es->wlines)
1731 return;
1732 es->wtop++;
1734 else
1736 /* move up one line */
1737 if (es->wtop == 0)
1738 return;
1739 --es->wtop;
1742 if (IsWindowVisible(hwnd))
1744 /* adjust client bottom to nearest whole line */
1745 GetClientRect(hwnd, &rc);
1746 rc.bottom = (rc.bottom / es->txtht) * es->txtht;
1748 if (opt == SB_LINEUP)
1750 /* move up one line (scroll window down) */
1751 ScrollWindow(hwnd, 0, es->txtht, &rc, &rc);
1752 /* write top line */
1753 EDIT_WriteTextLine(hwnd, NULL, es->wtop);
1754 es->WndRow++;
1756 else
1758 /* move down one line (scroll window up) */
1759 ScrollWindow(hwnd, 0, -(es->txtht), &rc, &rc);
1760 /* write bottom line */
1761 y = (((rc.bottom - rc.top) / es->txtht) - 1);
1762 EDIT_WriteTextLine(hwnd, NULL, es->wtop + y);
1763 --es->WndRow;
1767 /* reset the vertical scroll bar */
1768 if (IsVScrollBar())
1770 vscrollpos = EDIT_ComputeVScrollPos(hwnd);
1771 SetScrollPos(hwnd, SB_VERT, vscrollpos, TRUE);
1776 /*********************************************************************
1777 * EDIT_KeyVScrollPage
1779 * Scroll text vertically by one page using keyboard.
1782 void EDIT_KeyVScrollPage(HWND hwnd, WORD opt)
1784 int vscrollpos;
1785 WND *wndPtr = WIN_FindWndPtr(hwnd);
1786 EDITSTATE *es =
1787 (EDITSTATE *)EDIT_HeapAddr(hwnd, (HANDLE)(*(wndPtr->wExtra)));
1789 if (IsMultiLine())
1791 if (opt == SB_PAGEUP)
1793 if (es->wtop)
1794 es->wtop -= ClientHeight(wndPtr, es);
1796 else
1798 if (es->wtop + ClientHeight(wndPtr, es) < es->wlines)
1800 es->wtop += ClientHeight(wndPtr, es);
1801 if (es->wtop > es->wlines - ClientHeight(wndPtr, es))
1802 es->wtop = es->wlines - ClientHeight(wndPtr, es);
1805 if (es->wtop < 0)
1806 es->wtop = 0;
1808 es->CurrLine = es->wtop + es->WndRow;
1809 EDIT_StickEnd(hwnd);
1810 InvalidateRect(hwnd, NULL, TRUE);
1811 UpdateWindow(hwnd);
1813 /* reset the vertical scroll bar */
1814 if (IsVScrollBar())
1816 vscrollpos = EDIT_ComputeVScrollPos(hwnd);
1817 SetScrollPos(hwnd, SB_VERT, vscrollpos, TRUE);
1823 /*********************************************************************
1824 * EDIT_KeyVScrollDoc
1826 * Scroll text to top and bottom of document using keyboard.
1829 void EDIT_KeyVScrollDoc(HWND hwnd, WORD opt)
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 dprintf_edit(stddeb,"EDIT_VScrollLine: direction=%d\n", opt);
2003 if (opt == SB_LINEDOWN)
2005 /* move down one line */
2006 if (es->wtop + ClientHeight(wndPtr, es) >= es->wlines)
2007 return;
2008 es->wtop++;
2010 else
2012 /* move up one line */
2013 if (es->wtop == 0)
2014 return;
2015 --es->wtop;
2018 if (IsWindowVisible(hwnd))
2020 /* adjust client bottom to nearest whole line */
2021 GetClientRect(hwnd, &rc);
2022 rc.bottom = (rc.bottom / es->txtht) * es->txtht;
2024 if (opt == SB_LINEUP)
2026 /* move up one line (scroll window down) */
2027 ScrollWindow(hwnd, 0, es->txtht, &rc, &rc);
2028 /* write top line */
2029 EDIT_WriteTextLine(hwnd, NULL, es->wtop);
2030 es->WndRow++;
2032 else
2034 /* move down one line (scroll window up) */
2035 ScrollWindow(hwnd, 0, -(es->txtht), &rc, &rc);
2036 /* write bottom line */
2037 y = ((rc.bottom - rc.top / es->txtht) - 1);
2038 EDIT_WriteTextLine(hwnd, NULL, es->wtop + y);
2039 --es->WndRow;
2045 /*********************************************************************
2046 * EDIT_VScrollPage
2048 * Scroll text vertically by one page using keyboard.
2051 void EDIT_VScrollPage(HWND hwnd, WORD opt)
2053 int vscrollpos;
2054 WND *wndPtr = WIN_FindWndPtr(hwnd);
2055 EDITSTATE *es =
2056 (EDITSTATE *)EDIT_HeapAddr(hwnd, (HANDLE)(*(wndPtr->wExtra)));
2058 if (opt == SB_PAGEUP)
2060 if (es->wtop)
2061 es->wtop -= ClientHeight(wndPtr, es);
2063 else
2065 if (es->wtop + ClientHeight(wndPtr, es) < es->wlines)
2067 es->wtop += ClientHeight(wndPtr, es);
2068 if (es->wtop > es->wlines - ClientHeight(wndPtr, es))
2069 es->wtop = es->wlines - ClientHeight(wndPtr, es);
2072 if (es->wtop < 0)
2073 es->wtop = 0;
2075 InvalidateRect(hwnd, NULL, TRUE);
2076 UpdateWindow(hwnd);
2078 /* reset the vertical scroll bar */
2079 if (IsVScrollBar())
2081 vscrollpos = EDIT_ComputeVScrollPos(hwnd);
2082 SetScrollPos(hwnd, SB_VERT, vscrollpos, TRUE);
2087 /*********************************************************************
2088 * WM_HSCROLL message function
2091 void EDIT_HScrollMsg(HWND hwnd, WORD wParam, LONG lParam)
2093 WND *wndPtr = WIN_FindWndPtr(hwnd);
2094 EDITSTATE *es =
2095 (EDITSTATE *)EDIT_HeapAddr(hwnd, (HANDLE)(*(wndPtr->wExtra)));
2097 switch (wParam)
2099 case SB_LINEUP:
2100 case SB_LINEDOWN:
2101 HideCaret(hwnd);
2103 SetCaretPos(es->WndCol, es->WndRow * es->txtht);
2104 ShowCaret(hwnd);
2105 break;
2110 /*********************************************************************
2111 * WM_SIZE message function
2114 void EDIT_SizeMsg(HWND hwnd, WORD wParam, LONG lParam)
2116 WND *wndPtr = WIN_FindWndPtr(hwnd);
2117 EDITSTATE *es =
2118 (EDITSTATE *)EDIT_HeapAddr(hwnd, (HANDLE)(*(wndPtr->wExtra)));
2120 if (wParam != SIZE_MAXIMIZED && wParam != SIZE_RESTORED) return;
2122 InvalidateRect(hwnd, NULL, TRUE);
2123 es->PaintBkgd = TRUE;
2124 UpdateWindow(hwnd);
2128 /*********************************************************************
2129 * WM_LBUTTONDOWN message function
2132 void EDIT_LButtonDownMsg(HWND hwnd, WORD wParam, LONG lParam)
2134 char *cp;
2135 int len;
2136 BOOL end = FALSE;
2137 WND *wndPtr = WIN_FindWndPtr(hwnd);
2138 EDITSTATE *es =
2139 (EDITSTATE *)EDIT_HeapAddr(hwnd, (HANDLE)(*(wndPtr->wExtra)));
2141 if (SelMarked(es))
2142 EDIT_ClearSel(hwnd);
2144 es->WndRow = HIWORD(lParam) / es->txtht;
2145 if (es->WndRow > es->wlines - es->wtop - 1)
2147 if (es->wlines)
2148 es->WndRow = es->wlines - es->wtop - 1;
2149 else
2150 es->WndRow = 0;
2151 end = TRUE;
2153 es->CurrLine = es->wtop + es->WndRow;
2155 cp = EDIT_TextLine(hwnd, es->CurrLine);
2156 len = EDIT_LineLength(hwnd, es->CurrLine);
2157 es->WndCol = LOWORD(lParam);
2158 if (es->WndCol > EDIT_StrLength(hwnd, cp, len, 0) - es->wleft || end)
2159 es->WndCol = EDIT_StrLength(hwnd, cp, len, 0) - es->wleft;
2160 es->CurrCol = EDIT_PixelToChar(hwnd, es->CurrLine, &(es->WndCol));
2162 ButtonDown = TRUE;
2163 ButtonRow = es->CurrLine;
2164 ButtonCol = es->CurrCol;
2168 /*********************************************************************
2169 * WM_MOUSEMOVE message function
2172 void EDIT_MouseMoveMsg(HWND hwnd, WORD wParam, LONG lParam)
2174 if (wParam != MK_LBUTTON)
2175 return;
2177 if (ButtonDown)
2179 EDIT_SetAnchor(hwnd, ButtonRow, ButtonCol);
2180 TextMarking = TRUE;
2181 ButtonDown = FALSE;
2184 if (TextMarking)
2185 EDIT_ExtendSel(hwnd, LOWORD(lParam), HIWORD(lParam));
2189 /*********************************************************************
2190 * EDIT_PixelToChar
2192 * Convert a pixel offset in the given row to a character offset,
2193 * adjusting the pixel offset to the nearest whole character if
2194 * necessary.
2197 int EDIT_PixelToChar(HWND hwnd, int row, int *pixel)
2199 int ch = 0, i = 0, s_i = 0;
2200 char *text;
2202 dprintf_edit(stddeb,"EDIT_PixelToChar: row=%d, pixel=%d\n", row, *pixel);
2204 text = EDIT_TextLine(hwnd, row);
2205 while (i < *pixel)
2207 s_i = i;
2208 i += EDIT_CharWidth(hwnd, (BYTE)(*(text + ch)), i);
2209 ch++;
2212 /* if stepped past _pixel_, go back a character */
2213 if (i - *pixel)
2215 i = s_i;
2216 --ch;
2218 *pixel = i;
2219 return ch;
2223 /*********************************************************************
2224 * WM_SETTEXT message function
2227 LONG EDIT_SetTextMsg(HWND hwnd, LONG lParam)
2229 int len;
2230 char *text;
2231 WND *wndPtr = WIN_FindWndPtr(hwnd);
2232 EDITSTATE *es =
2233 (EDITSTATE *)EDIT_HeapAddr(hwnd, (HANDLE)(*(wndPtr->wExtra)));
2235 if (strlen((char *)lParam) <= es->MaxTextLen)
2237 len = ( lParam? strlen((char *)lParam) : 0 );
2238 EDIT_ClearText(hwnd);
2239 es->textlen = len;
2240 es->hText = EDIT_HeapReAlloc(hwnd, es->hText, len + 3);
2241 text = EDIT_HeapAddr(hwnd, es->hText);
2242 if (lParam)
2243 strcpy(text, (char *)lParam);
2244 text[len] = '\0';
2245 text[len + 1] = '\0';
2246 text[len + 2] = '\0';
2247 EDIT_BuildTextPointers(hwnd);
2248 InvalidateRect(hwnd, NULL, TRUE);
2249 es->PaintBkgd = TRUE;
2250 es->TextChanged = TRUE;
2251 return 0L;
2253 else
2254 return EN_ERRSPACE;
2258 /*********************************************************************
2259 * EDIT_ClearText
2261 * Clear text from text buffer.
2264 void EDIT_ClearText(HWND hwnd)
2266 WND *wndPtr = WIN_FindWndPtr(hwnd);
2267 EDITSTATE *es =
2268 (EDITSTATE *)EDIT_HeapAddr(hwnd, (HANDLE)(*(wndPtr->wExtra)));
2269 unsigned int blen = EditBufLen(wndPtr) + 2;
2270 char *text;
2272 es->hText = EDIT_HeapReAlloc(hwnd, es->hText, blen);
2273 text = EDIT_HeapAddr(hwnd, es->hText);
2274 memset(text, 0, blen);
2275 es->textlen = 0;
2276 es->wlines = 0;
2277 es->CurrLine = es->CurrCol = 0;
2278 es->WndRow = es->WndCol = 0;
2279 es->wleft = es->wtop = 0;
2280 es->textwidth = 0;
2281 es->TextChanged = FALSE;
2282 EDIT_ClearTextPointers(hwnd);
2286 /*********************************************************************
2287 * EM_SETSEL message function
2290 void EDIT_SetSelMsg(HWND hwnd, WORD wParam, LONG lParam)
2292 int so, eo;
2293 WND *wndPtr = WIN_FindWndPtr(hwnd);
2294 EDITSTATE *es =
2295 (EDITSTATE *)EDIT_HeapAddr(hwnd, (HANDLE)(*(wndPtr->wExtra)));
2297 so = LOWORD(lParam);
2298 eo = HIWORD(lParam);
2300 if (so == -1) /* if so == -1, clear selection */
2302 EDIT_ClearSel(hwnd);
2303 return;
2306 if (so == eo) /* if so == eo, set caret only */
2308 EDIT_GetLineCol(hwnd, so, &(es->CurrLine), &(es->CurrCol));
2309 es->WndRow = es->CurrLine - es->wtop;
2311 if (!wParam)
2313 if (es->WndRow < 0 || es->WndRow > ClientHeight(wndPtr, es))
2315 es->wtop = es->CurrLine;
2316 es->WndRow = 0;
2318 es->WndCol = EDIT_StrLength(hwnd,
2319 EDIT_TextLine(hwnd, es->CurrLine),
2320 es->CurrCol, 0) - es->wleft;
2321 if (es->WndCol > ClientWidth(wndPtr))
2323 es->wleft = es->WndCol;
2324 es->WndCol = 0;
2326 else if (es->WndCol < 0)
2328 es->wleft += es->WndCol;
2329 es->WndCol = 0;
2333 else /* otherwise set selection */
2335 if (so > eo)
2336 swap(&so, &eo);
2338 EDIT_GetLineCol(hwnd, so, &(es->SelBegLine), &(es->SelBegCol));
2339 EDIT_GetLineCol(hwnd, eo, &(es->SelEndLine), &(es->SelEndCol));
2340 es->CurrLine = es->SelEndLine;
2341 es->CurrCol = es->SelEndCol;
2342 es->WndRow = es->SelEndLine - es->wtop;
2344 if (!wParam) /* don't suppress scrolling of text */
2346 if (es->WndRow < 0)
2348 es->wtop = es->SelEndLine;
2349 es->WndRow = 0;
2351 else if (es->WndRow > ClientHeight(wndPtr, es))
2353 es->wtop += es->WndRow - ClientHeight(wndPtr, es);
2354 es->WndRow = ClientHeight(wndPtr, es);
2356 es->WndCol = EDIT_StrLength(hwnd,
2357 EDIT_TextLine(hwnd, es->SelEndLine),
2358 es->SelEndCol, 0) - es->wleft;
2359 if (es->WndCol > ClientWidth(wndPtr))
2361 es->wleft += es->WndCol - ClientWidth(wndPtr);
2362 es->WndCol = ClientWidth(wndPtr);
2364 else if (es->WndCol < 0)
2366 es->wleft += es->WndCol;
2367 es->WndCol = 0;
2371 InvalidateRect(hwnd, NULL, TRUE);
2372 UpdateWindow(hwnd);
2377 /*********************************************************************
2378 * EDIT_GetLineCol
2380 * Return line and column in text buffer from character offset.
2383 void EDIT_GetLineCol(HWND hwnd, int off, int *line, int *col)
2385 int lineno;
2386 char *cp, *cp1;
2387 WND *wndPtr = WIN_FindWndPtr(hwnd);
2388 EDITSTATE *es =
2389 (EDITSTATE *)EDIT_HeapAddr(hwnd, (HANDLE)(*(wndPtr->wExtra)));
2390 char *text = EDIT_HeapAddr(hwnd, es->hText);
2391 unsigned int *textPtrs =
2392 (unsigned int *)EDIT_HeapAddr(hwnd, es->hTextPtrs);
2394 /* check for (0,0) */
2395 if (!off)
2397 *line = 0;
2398 *col = 0;
2399 return;
2402 if (off > strlen(text)) off = strlen(text);
2403 cp1 = text;
2404 for (lineno = 0; lineno < es->wlines; lineno++)
2406 cp = text + *(textPtrs + lineno);
2407 if (off == (int)(cp - text))
2409 *line = lineno;
2410 *col = 0;
2411 return;
2413 if (off < (int)(cp - text))
2414 break;
2415 cp1 = cp;
2417 *line = lineno - 1;
2418 *col = off - (int)(cp1 - text);
2419 #if 0
2420 if (*(text + *col) == '\0')
2421 (*col)--;
2422 #endif
2426 /*********************************************************************
2427 * EDIT_DeleteSel
2429 * Delete the current selected text (if any)
2432 void EDIT_DeleteSel(HWND hwnd)
2434 char *bbl, *bel;
2435 int len;
2436 WND *wndPtr = WIN_FindWndPtr(hwnd);
2437 EDITSTATE *es =
2438 (EDITSTATE *)EDIT_HeapAddr(hwnd, (HANDLE)(*(wndPtr->wExtra)));
2440 if (SelMarked(es))
2442 bbl = EDIT_TextLine(hwnd, es->SelBegLine) + es->SelBegCol;
2443 bel = EDIT_TextLine(hwnd, es->SelEndLine) + es->SelEndCol;
2444 len = (int)(bel - bbl);
2445 EDIT_SaveDeletedText(hwnd, bbl, len, es->SelBegLine, es->SelBegCol);
2446 es->TextChanged = TRUE;
2447 strcpy(bbl, bel);
2449 es->CurrLine = es->SelBegLine;
2450 es->CurrCol = es->SelBegCol;
2451 es->WndRow = es->SelBegLine - es->wtop;
2452 if (es->WndRow < 0)
2454 es->wtop = es->SelBegLine;
2455 es->WndRow = 0;
2457 es->WndCol = EDIT_StrLength(hwnd, bbl - es->SelBegCol,
2458 es->SelBegCol, 0) - es->wleft;
2460 EDIT_BuildTextPointers(hwnd);
2461 es->PaintBkgd = TRUE;
2462 EDIT_ClearSel(hwnd);
2467 /*********************************************************************
2468 * EDIT_ClearSel
2470 * Clear the current selection.
2473 void EDIT_ClearSel(HWND hwnd)
2475 WND *wndPtr = WIN_FindWndPtr(hwnd);
2476 EDITSTATE *es =
2477 (EDITSTATE *)EDIT_HeapAddr(hwnd, (HANDLE)(*(wndPtr->wExtra)));
2479 es->SelBegLine = es->SelBegCol = 0;
2480 es->SelEndLine = es->SelEndCol = 0;
2482 InvalidateRect(hwnd, NULL, TRUE);
2483 UpdateWindow(hwnd);
2487 /*********************************************************************
2488 * EDIT_TextLineNumber
2490 * Return the line number in the text buffer of the supplied
2491 * character pointer.
2494 int EDIT_TextLineNumber(HWND hwnd, char *lp)
2496 int lineno;
2497 char *cp;
2498 WND *wndPtr = WIN_FindWndPtr(hwnd);
2499 EDITSTATE *es =
2500 (EDITSTATE *)EDIT_HeapAddr(hwnd, (HANDLE)(*(wndPtr->wExtra)));
2501 char *text = EDIT_HeapAddr(hwnd, es->hText);
2502 unsigned int *textPtrs =
2503 (unsigned int *)EDIT_HeapAddr(hwnd, es->hTextPtrs);
2505 for (lineno = 0; lineno < es->wlines; lineno++)
2507 cp = text + *(textPtrs + lineno);
2508 if (cp == lp)
2509 return lineno;
2510 if (cp > lp)
2511 break;
2513 return lineno - 1;
2517 /*********************************************************************
2518 * EDIT_SetAnchor
2520 * Set down anchor for text marking.
2523 void EDIT_SetAnchor(HWND hwnd, int row, int col)
2525 BOOL sel = FALSE;
2526 WND *wndPtr = WIN_FindWndPtr(hwnd);
2527 EDITSTATE *es =
2528 (EDITSTATE *)EDIT_HeapAddr(hwnd, (HANDLE)(*(wndPtr->wExtra)));
2530 if (SelMarked(es))
2531 sel = TRUE;
2532 EDIT_ClearSel(hwnd);
2533 es->SelBegLine = es->SelEndLine = row;
2534 es->SelBegCol = es->SelEndCol = col;
2535 if (sel)
2537 InvalidateRect(hwnd, NULL, FALSE);
2538 UpdateWindow(hwnd);
2543 /*********************************************************************
2544 * EDIT_ExtendSel
2546 * Extend selection to the given screen co-ordinates.
2549 void EDIT_ExtendSel(HWND hwnd, int x, int y)
2551 int bbl, bel, bbc, bec;
2552 char *cp;
2553 int len, line;
2554 BOOL end = FALSE;
2555 WND *wndPtr = WIN_FindWndPtr(hwnd);
2556 EDITSTATE *es =
2557 (EDITSTATE *)EDIT_HeapAddr(hwnd, (HANDLE)(*(wndPtr->wExtra)));
2559 dprintf_edit(stddeb,"EDIT_ExtendSel: x=%d, y=%d\n", x, y);
2561 bbl = es->SelEndLine;
2562 bbc = es->SelEndCol;
2563 line = es->wtop + y / es->txtht;
2564 if (line > es->wlines)
2565 line = es->wlines;
2566 cp = EDIT_TextLine(hwnd, line);
2567 len = EDIT_LineLength(hwnd, line);
2569 es->WndRow = y / es->txtht;
2570 if (es->WndRow > es->wlines - es->wtop - 1)
2572 if (es->wlines)
2573 es->WndRow = es->wlines - es->wtop - 1;
2574 else
2575 es->WndRow = 0;
2576 end = TRUE;
2578 es->CurrLine = es->wtop + es->WndRow;
2579 es->SelEndLine = es->CurrLine;
2581 es->WndCol = x;
2582 if (es->WndCol > EDIT_StrLength(hwnd, cp, len, 0) - es->wleft || end)
2583 es->WndCol = EDIT_StrLength(hwnd, cp, len, 0) - es->wleft;
2584 es->CurrCol = EDIT_PixelToChar(hwnd, es->CurrLine, &(es->WndCol));
2585 es->SelEndCol = es->CurrCol;
2587 bel = es->SelEndLine;
2588 bec = es->SelEndCol;
2590 /* return if no new characters to mark */
2591 if (bbl == bel && bbc == bec)
2592 return;
2594 /* put lowest marker first */
2595 if (bbl > bel)
2597 swap(&bbl, &bel);
2598 swap(&bbc, &bec);
2600 if (bbl == bel && bbc > bec)
2601 swap(&bbc, &bec);
2603 for (y = bbl; y <= bel; y++)
2605 if (y == bbl && y == bel)
2606 EDIT_WriteSel(hwnd, y, bbc, bec);
2607 else if (y == bbl)
2608 EDIT_WriteSel(hwnd, y, bbc, -1);
2609 else if (y == bel)
2610 EDIT_WriteSel(hwnd, y, 0, bec);
2611 else
2612 EDIT_WriteSel(hwnd, y, 0, -1);
2617 /*********************************************************************
2618 * EDIT_WriteSel
2620 * Display selection by reversing pixels in selected text.
2621 * If end == -1, selection applies to end of line.
2624 void EDIT_WriteSel(HWND hwnd, int y, int start, int end)
2626 RECT rc;
2627 int scol, ecol;
2628 char *cp;
2629 HDC hdc;
2630 HBRUSH hbrush, holdbrush;
2631 int olddm;
2632 WND *wndPtr = WIN_FindWndPtr(hwnd);
2633 EDITSTATE *es =
2634 (EDITSTATE *)EDIT_HeapAddr(hwnd, (HANDLE)(*(wndPtr->wExtra)));
2636 dprintf_edit(stddeb,"EDIT_WriteSel: y=%d start=%d end=%d\n", y, start,end);
2637 GetClientRect(hwnd, &rc);
2639 /* make sure y is within the window */
2640 if (y < es->wtop || y > (es->wtop + ClientHeight(wndPtr, es)))
2641 return;
2643 /* get pointer to text */
2644 cp = EDIT_TextLine(hwnd, y);
2646 /* get length of line if end == -1 */
2647 if (end == -1)
2648 end = EDIT_LineLength(hwnd, y);
2650 /* For some reason Rectangle, when called with R2_XORPEN filling,
2651 * appears to leave a 2 pixel gap between characters and between
2652 * lines. I have kludged this by adding on two pixels to ecol and
2653 * to the line height in the call to Rectangle.
2655 scol = EDIT_StrLength(hwnd, cp, start, 0);
2656 if (scol > rc.right) return;
2657 if (scol < rc.left) scol = rc.left;
2658 ecol = EDIT_StrLength(hwnd, cp, end, 0) + 2; /* ??? */
2659 if (ecol < rc.left) return;
2660 if (ecol > rc.right) ecol = rc.right;
2662 hdc = GetDC(hwnd);
2663 hbrush = GetStockObject(BLACK_BRUSH);
2664 holdbrush = (HBRUSH)SelectObject(hdc, (HANDLE)hbrush);
2665 olddm = SetROP2(hdc, R2_XORPEN);
2666 Rectangle(hdc, scol, y * es->txtht, ecol, (y + 1) * es->txtht + 2);
2667 SetROP2(hdc, olddm);
2668 SelectObject(hdc, (HANDLE)holdbrush);
2669 ReleaseDC(hwnd, hdc);
2673 /*********************************************************************
2674 * EDIT_StopMarking
2676 * Stop text marking (selection).
2679 void EDIT_StopMarking(HWND hwnd)
2681 WND *wndPtr = WIN_FindWndPtr(hwnd);
2682 EDITSTATE *es =
2683 (EDITSTATE *)EDIT_HeapAddr(hwnd, (HANDLE)(*(wndPtr->wExtra)));
2685 TextMarking = FALSE;
2686 if (es->SelBegLine > es->SelEndLine)
2688 swap(&(es->SelBegLine), &(es->SelEndLine));
2689 swap(&(es->SelBegCol), &(es->SelEndCol));
2691 if (es->SelBegLine == es->SelEndLine && es->SelBegCol > es->SelEndCol)
2692 swap(&(es->SelBegCol), &(es->SelEndCol));
2696 /*********************************************************************
2697 * EM_GETLINE message function
2700 LONG EDIT_GetLineMsg(HWND hwnd, WORD wParam, LONG lParam)
2702 char *cp, *cp1;
2703 int len;
2704 char *buffer = (char *)lParam;
2706 cp = EDIT_TextLine(hwnd, wParam);
2707 cp1 = EDIT_TextLine(hwnd, wParam + 1);
2708 len = min((int)(cp1 - cp), (WORD)(*buffer));
2709 strncpy(buffer, cp, len);
2711 return (LONG)len;
2715 /*********************************************************************
2716 * EM_GETSEL message function
2719 LONG EDIT_GetSelMsg(HWND hwnd)
2721 int so, eo;
2722 WND *wndPtr = WIN_FindWndPtr(hwnd);
2723 EDITSTATE *es =
2724 (EDITSTATE *)EDIT_HeapAddr(hwnd, (HANDLE)(*(wndPtr->wExtra)));
2725 unsigned int *textPtrs =
2726 (unsigned int *)EDIT_HeapAddr(hwnd, es->hTextPtrs);
2728 so = *(textPtrs + es->SelBegLine) + es->SelBegCol;
2729 eo = *(textPtrs + es->SelEndLine) + es->SelEndCol;
2731 return MAKELONG(so, eo);
2735 /*********************************************************************
2736 * EM_REPLACESEL message function
2739 void EDIT_ReplaceSel(HWND hwnd, LONG lParam)
2741 EDIT_DeleteSel(hwnd);
2742 EDIT_InsertText(hwnd, (char *)lParam, strlen((char *)lParam));
2743 InvalidateRect(hwnd, NULL, TRUE);
2744 UpdateWindow(hwnd);
2748 /*********************************************************************
2749 * EDIT_InsertText
2751 * Insert text at current line and column.
2754 void EDIT_InsertText(HWND hwnd, char *str, int len)
2756 int plen;
2757 WND *wndPtr = WIN_FindWndPtr(hwnd);
2758 EDITSTATE *es =
2759 (EDITSTATE *)EDIT_HeapAddr(hwnd, (HANDLE)(*(wndPtr->wExtra)));
2760 char *text = EDIT_HeapAddr(hwnd, es->hText);
2762 plen = strlen(text) + len;
2763 if (plen + 1 > es->textlen)
2765 es->hText = EDIT_HeapReAlloc(hwnd, es->hText, es->textlen + len);
2766 es->textlen = plen + 1;
2768 memmove(CurrChar + len, CurrChar, strlen(CurrChar) + 1);
2769 memcpy(CurrChar, str, len);
2771 EDIT_BuildTextPointers(hwnd);
2772 es->PaintBkgd = TRUE;
2773 es->TextChanged = TRUE;
2775 EDIT_GetLineCol(hwnd, (int)((CurrChar + len) - text), &(es->CurrLine),
2776 &(es->CurrCol));
2777 es->WndRow = es->CurrLine - es->wtop;
2778 es->WndCol = EDIT_StrLength(hwnd, EDIT_TextLine(hwnd, es->CurrLine),
2779 es->CurrCol, 0) - es->wleft;
2783 /*********************************************************************
2784 * EM_LINEFROMCHAR message function
2787 LONG EDIT_LineFromCharMsg(HWND hwnd, WORD wParam)
2789 int row, col;
2790 WND *wndPtr = WIN_FindWndPtr(hwnd);
2791 EDITSTATE *es =
2792 (EDITSTATE *)EDIT_HeapAddr(hwnd, (HANDLE)(*(wndPtr->wExtra)));
2794 if (wParam == (WORD)-1)
2795 return (LONG)(es->SelBegLine);
2796 else
2797 EDIT_GetLineCol(hwnd, wParam, &row, &col);
2799 return (LONG)row;
2803 /*********************************************************************
2804 * EM_LINEINDEX message function
2807 LONG EDIT_LineIndexMsg(HWND hwnd, WORD wParam)
2809 WND *wndPtr = WIN_FindWndPtr(hwnd);
2810 EDITSTATE *es =
2811 (EDITSTATE *)EDIT_HeapAddr(hwnd, (HANDLE)(*(wndPtr->wExtra)));
2812 unsigned int *textPtrs =
2813 (unsigned int *)EDIT_HeapAddr(hwnd, es->hTextPtrs);
2815 if (wParam == (WORD)-1)
2816 wParam = es->CurrLine;
2818 return (LONG)(*(textPtrs + wParam));
2822 /*********************************************************************
2823 * EM_LINELENGTH message function
2826 LONG EDIT_LineLengthMsg(HWND hwnd, WORD wParam)
2828 int row, col, len;
2829 int sbl, sbc, sel, sec;
2830 WND *wndPtr = WIN_FindWndPtr(hwnd);
2831 EDITSTATE *es =
2832 (EDITSTATE *)EDIT_HeapAddr(hwnd, (HANDLE)(*(wndPtr->wExtra)));
2833 unsigned int *textPtrs =
2834 (unsigned int *)EDIT_HeapAddr(hwnd, es->hTextPtrs);
2836 if (wParam == (WORD)-1)
2838 if (SelMarked(es))
2840 sbl = es->SelBegLine;
2841 sbc = es->SelBegCol;
2842 sel = es->SelEndLine;
2843 sec = es->SelEndCol;
2845 if (sbl > sel)
2847 swap(&sbl, &sel);
2848 swap(&sbc, &sec);
2850 if (sbl == sel && sbc > sec)
2851 swap(&sbc, &sec);
2853 if (sbc == sel)
2855 len = *(textPtrs + sbl + 1) - *(textPtrs + sbl) - 1;
2856 return len - sec - sbc;
2859 len = *(textPtrs + sel + 1) - *(textPtrs + sel) - sec - 1;
2860 return len + sbc;
2862 else /* no selection marked */
2864 len = *(textPtrs + es->CurrLine + 1) -
2865 *(textPtrs + es->CurrLine) - 1;
2866 return len;
2869 else /* line number specified */
2871 EDIT_GetLineCol(hwnd, wParam, &row, &col);
2872 len = *(textPtrs + row + 1) - *(textPtrs + row);
2873 return len;
2878 /*********************************************************************
2879 * WM_SETFONT message function
2882 void EDIT_SetFont(HWND hwnd, WORD wParam, LONG lParam)
2884 HDC hdc;
2885 TEXTMETRIC tm;
2886 HFONT oldfont;
2887 WND *wndPtr = WIN_FindWndPtr(hwnd);
2888 EDITSTATE *es =
2889 (EDITSTATE *)EDIT_HeapAddr(hwnd, (HANDLE)(*(wndPtr->wExtra)));
2890 short *charWidths = (short *)EDIT_HeapAddr(hwnd, es->hCharWidths);
2892 es->hFont = wParam;
2893 hdc = GetDC(hwnd);
2894 oldfont = (HFONT)SelectObject(hdc, (HANDLE)es->hFont);
2895 GetCharWidth(hdc, 0, 255, charWidths);
2896 GetTextMetrics(hdc, &tm);
2897 es->txtht = tm.tmHeight + tm.tmExternalLeading;
2898 SelectObject(hdc, (HANDLE)oldfont);
2899 ReleaseDC(hwnd, hdc);
2901 es->WndRow = (es->CurrLine - es->wtop) / es->txtht;
2902 es->WndCol = EDIT_StrLength(hwnd, EDIT_TextLine(hwnd, es->CurrLine),
2903 es->CurrCol, 0) - es->wleft;
2905 InvalidateRect(hwnd, NULL, TRUE);
2906 es->PaintBkgd = TRUE;
2907 if (lParam) UpdateWindow(hwnd);
2911 /*********************************************************************
2912 * EDIT_SaveDeletedText
2914 * Save deleted text in deleted text buffer.
2917 void EDIT_SaveDeletedText(HWND hwnd, char *deltext, int len,
2918 int line, int col)
2920 char *text;
2921 WND *wndPtr = WIN_FindWndPtr(hwnd);
2922 EDITSTATE *es =
2923 (EDITSTATE *)EDIT_HeapAddr(hwnd, (HANDLE)(*(wndPtr->wExtra)));
2925 es->hDeletedText = GlobalReAlloc(es->hDeletedText, len, GMEM_MOVEABLE);
2926 if (!es->hDeletedText) return;
2927 text = (char *)GlobalLock(es->hDeletedText);
2928 memcpy(text, deltext, len);
2929 GlobalUnlock(es->hDeletedText);
2930 es->DeletedLength = len;
2931 es->DeletedCurrLine = line;
2932 es->DeletedCurrCol = col;
2936 /*********************************************************************
2937 * EDIT_ClearDeletedText
2939 * Clear deleted text buffer.
2942 void EDIT_ClearDeletedText(HWND hwnd)
2944 WND *wndPtr = WIN_FindWndPtr(hwnd);
2945 EDITSTATE *es =
2946 (EDITSTATE *)EDIT_HeapAddr(hwnd, (HANDLE)(*(wndPtr->wExtra)));
2948 GlobalFree(es->hDeletedText);
2949 es->hDeletedText = 0;
2950 es->DeletedLength = 0;
2954 /*********************************************************************
2955 * EM_UNDO message function
2958 LONG EDIT_UndoMsg(HWND hwnd)
2960 char *text;
2961 WND *wndPtr = WIN_FindWndPtr(hwnd);
2962 EDITSTATE *es =
2963 (EDITSTATE *)EDIT_HeapAddr(hwnd, (HANDLE)(*(wndPtr->wExtra)));
2965 if (es->hDeletedText)
2967 text = (char *)GlobalLock(es->hDeletedText);
2968 es->CurrLine = es->DeletedCurrLine;
2969 es->CurrCol = es->DeletedCurrCol;
2970 EDIT_InsertText(hwnd, text, es->DeletedLength);
2971 GlobalUnlock(es->hDeletedText);
2972 EDIT_ClearDeletedText(hwnd);
2974 es->SelBegLine = es->CurrLine;
2975 es->SelBegCol = es->CurrCol;
2976 EDIT_GetLineCol(hwnd, (int)((CurrChar + es->DeletedLength) - text),
2977 &(es->CurrLine), &(es->CurrCol));
2978 es->WndRow = es->CurrLine - es->wtop;
2979 es->WndCol = EDIT_StrLength(hwnd, EDIT_TextLine(hwnd, es->CurrLine),
2980 es->CurrCol, 0) - es->wleft;
2981 es->SelEndLine = es->CurrLine;
2982 es->SelEndCol = es->CurrCol;
2984 InvalidateRect(hwnd, NULL, TRUE);
2985 UpdateWindow(hwnd);
2986 return 1;
2988 else
2989 return 0;
2993 /*********************************************************************
2994 * EDIT_HeapAlloc
2996 * Allocate the specified number of bytes on the specified local heap.
2999 unsigned int EDIT_HeapAlloc(HWND hwnd, int bytes)
3001 WND *wndPtr = WIN_FindWndPtr(hwnd);
3002 unsigned int ret;
3003 ret = ((unsigned int)HEAP_Alloc((MDESC **)
3004 *(LONG *)(wndPtr->wExtra + 2),
3005 GMEM_MOVEABLE, bytes) & 0xffff);
3006 if (ret == 0)
3007 printf("EDIT_HeapAlloc: Out of heap-memory\n");
3008 return ret;
3012 /*********************************************************************
3013 * EDIT_HeapAddr
3015 * Return the address of the memory pointed to by the handle.
3018 void *EDIT_HeapAddr(HWND hwnd, unsigned int handle)
3020 WND *wndPtr = WIN_FindWndPtr(hwnd);
3022 return ((void *)((handle) ? ((handle) | ((unsigned int)
3023 (*(MDESC **)*(LONG *)(wndPtr->wExtra + 2))
3024 & 0xffff0000)) : 0));
3028 /*********************************************************************
3029 * EDIT_HeapReAlloc
3031 * Reallocate the memory pointed to by the handle.
3034 unsigned int EDIT_HeapReAlloc(HWND hwnd, unsigned int handle, int bytes)
3036 WND *wndPtr = WIN_FindWndPtr(hwnd);
3038 return ((unsigned int)HEAP_ReAlloc((MDESC **)
3039 *(LONG *)(wndPtr->wExtra + 2),
3040 EDIT_HeapAddr(hwnd, handle),
3041 bytes, GMEM_MOVEABLE) & 0xffff);
3045 /*********************************************************************
3046 * EDIT_HeapFree
3048 * Frees the memory pointed to by the handle.
3051 void EDIT_HeapFree(HWND hwnd, unsigned int handle)
3053 WND *wndPtr = WIN_FindWndPtr(hwnd);
3055 HEAP_Free((MDESC **)*(LONG *)(wndPtr->wExtra + 2),
3056 EDIT_HeapAddr(hwnd, handle));
3060 /*********************************************************************
3061 * EDIT_HeapSize
3063 * Return the size of the given object on the local heap.
3066 unsigned int EDIT_HeapSize(HWND hwnd, unsigned int handle)
3068 WND *wndPtr = WIN_FindWndPtr(hwnd);
3070 return HEAP_LocalSize((MDESC **)*(LONG *)(wndPtr->wExtra + 2), handle);
3074 /*********************************************************************
3075 * EM_SETHANDLE message function
3078 void EDIT_SetHandleMsg(HWND hwnd, WORD wParam)
3080 WND *wndPtr = WIN_FindWndPtr(hwnd);
3081 EDITSTATE *es =
3082 (EDITSTATE *)EDIT_HeapAddr(hwnd, (HANDLE)(*(wndPtr->wExtra)));
3084 if (IsMultiLine())
3086 es->hText = wParam;
3087 es->textlen = EDIT_HeapSize(hwnd, es->hText);
3088 es->wlines = 0;
3089 es->wtop = es->wleft = 0;
3090 es->CurrLine = es->CurrCol = 0;
3091 es->WndRow = es->WndCol = 0;
3092 es->TextChanged = FALSE;
3093 es->textwidth = 0;
3094 es->SelBegLine = es->SelBegCol = 0;
3095 es->SelEndLine = es->SelEndCol = 0;
3096 dprintf_edit(stddeb, "EDIT_SetHandleMsg: textlen=%d\n",
3097 es->textlen);
3099 EDIT_BuildTextPointers(hwnd);
3100 es->PaintBkgd = TRUE;
3101 InvalidateRect(hwnd, NULL, TRUE);
3102 UpdateWindow(hwnd);
3107 /*********************************************************************
3108 * EM_SETTABSTOPS message function
3111 LONG EDIT_SetTabStopsMsg(HWND hwnd, WORD wParam, LONG lParam)
3113 unsigned short *tabstops;
3114 WND *wndPtr = WIN_FindWndPtr(hwnd);
3115 EDITSTATE *es =
3116 (EDITSTATE *)EDIT_HeapAddr(hwnd, (HANDLE)(*(wndPtr->wExtra)));
3118 es->NumTabStops = wParam;
3119 if (wParam == 0)
3120 es->hTabStops = EDIT_HeapReAlloc(hwnd, es->hTabStops, 1);
3121 else if (wParam == 1)
3123 es->hTabStops = EDIT_HeapReAlloc(hwnd, es->hTabStops, 1);
3124 tabstops = (unsigned short *)EDIT_HeapAddr(hwnd, es->hTabStops);
3125 *tabstops = (unsigned short)lParam;
3127 else
3129 es->hTabStops = EDIT_HeapReAlloc(hwnd, es->hTabStops, wParam);
3130 tabstops = (unsigned short *)EDIT_HeapAddr(hwnd, es->hTabStops);
3131 memcpy(tabstops, (unsigned short *)lParam, wParam);
3133 return 0L;
3137 /*********************************************************************
3138 * EDIT_CopyToClipboard
3140 * Copy the specified text to the clipboard.
3143 void EDIT_CopyToClipboard(HWND hwnd)
3145 HANDLE hMem;
3146 char *lpMem;
3147 int i, len;
3148 char *bbl, *bel;
3149 WND *wndPtr = WIN_FindWndPtr(hwnd);
3150 EDITSTATE *es =
3151 (EDITSTATE *)EDIT_HeapAddr(hwnd, (HANDLE)(*(wndPtr->wExtra)));
3153 bbl = EDIT_TextLine(hwnd, es->SelBegLine) + es->SelBegCol;
3154 bel = EDIT_TextLine(hwnd, es->SelEndLine) + es->SelEndCol;
3155 len = (int)(bel - bbl);
3157 hMem = GlobalAlloc(GHND, (DWORD)(len + 1));
3158 lpMem = GlobalLock(hMem);
3160 for (i = 0; i < len; i++)
3161 *lpMem++ = *bbl++;
3163 GlobalUnlock(hMem);
3164 OpenClipboard(hwnd);
3165 EmptyClipboard();
3166 SetClipboardData(CF_TEXT, hMem);
3167 CloseClipboard();
3171 /*********************************************************************
3172 * WM_PASTE message function
3175 void EDIT_PasteMsg(HWND hwnd)
3177 HANDLE hClipMem;
3178 char *lpClipMem;
3180 OpenClipboard(hwnd);
3181 if (!(hClipMem = GetClipboardData(CF_TEXT)))
3183 /* no text in clipboard */
3184 CloseClipboard();
3185 return;
3187 lpClipMem = GlobalLock(hClipMem);
3188 EDIT_InsertText(hwnd, lpClipMem, strlen(lpClipMem));
3189 GlobalUnlock(hClipMem);
3190 CloseClipboard();
3191 InvalidateRect(hwnd, NULL, TRUE);
3192 UpdateWindow(hwnd);
3196 /*********************************************************************
3197 * Utility functions
3200 void swap(int *a, int *b)
3202 int x;
3204 x = *a;
3205 *a = *b;
3206 *b = x;