Release 950620
[wine/multimedia.git] / controls / edit.c
blobd860e84fd0feddd4091915909bc2fa1cc9006ed7
1 /*
2 * Edit control
4 * Copyright David W. Metcalfe, 1994
6 * Release 3, July 1994
7 * April 1995 bug fixes (William Magro)
8 */
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <string.h>
13 #include <windows.h>
14 #include "local.h"
15 #include "win.h"
16 #include "class.h"
17 #include "user.h"
18 #include "stddebug.h"
19 #include "debug.h"
22 #define NOTIFY_PARENT(hWndCntrl, wNotifyCode) \
23 SendMessage(GetParent(hWndCntrl), WM_COMMAND, \
24 GetDlgCtrlID(hWndCntrl), MAKELPARAM(hWndCntrl, wNotifyCode));
26 #define MAXTEXTLEN 30000 /* maximum text buffer length */
27 #define EDITLEN 1024 /* starting length for multi-line control */
28 #define ENTRYLEN 256 /* starting length for single line control */
29 #define GROWLENGTH 64 /* buffers grow by this much */
31 typedef struct
33 int wlines; /* number of lines of text */
34 int wtop; /* top line that is displayed */
35 int wleft; /* left pixel that is displayed */
36 unsigned int textlen; /* text buffer length */
37 int textwidth; /* width of longest line in pixels */
38 RECT fmtrc; /* rectangle in which to format text */
39 int txtht; /* height of text line in pixels */
40 HANDLE hText; /* handle to text buffer */
41 short *CharWidths; /* widths of chars in font */
42 unsigned int *textptrs; /* list of line offsets */
43 char *BlankLine; /* to fill blank lines quickly */
44 int CurrCol; /* current column */
45 int CurrLine; /* current line */
46 int WndCol; /* current window column */
47 int WndRow; /* current window row */
48 BOOL TextChanged; /* TRUE if text has changed */
49 BOOL PaintBkgd; /* paint control background */
50 unsigned int MaxTextLen; /* maximum text buffer length */
51 int SelBegLine; /* beginning line of selection */
52 int SelBegCol; /* beginning column of selection */
53 int SelEndLine; /* ending line of selection */
54 int SelEndCol; /* ending column of selection */
55 HFONT hFont; /* handle of current font (if not default) */
56 HANDLE hDeletedText; /* handle to deleted txet buffer for undo */
57 int DeletedLength; /* length of deleted text */
58 int DeletedCurrLine; /* starting line from which text was deleted */
59 int DeletedCurrCol; /* starting col from which text was deleted */
60 int NumTabStops; /* number of tab stops in buffer hTabStops */
61 unsigned short *TabStops;/* tab stops buffer */
62 BOOL HaveFocus; /* TRUE if this edit has the focus */
63 int ClientWidth; /* computed from the window's ClientRect */
64 int ClientHeight; /* dito */
65 } EDITSTATE;
67 #define EditBufStartLen(hwnd) (GetWindowLong(hwnd,GWL_STYLE) & ES_MULTILINE \
68 ? EDITLEN : ENTRYLEN)
69 #define CurrChar (EDIT_TextLine(hwnd, es->CurrLine) + es->CurrCol)
70 #define SelMarked(es) ((es)->SelBegLine != 0 || (es)->SelBegCol != 0 || \
71 (es)->SelEndLine != 0 || (es)->SelEndCol != 0)
72 #define ROUNDUP(numer, denom) (((numer) % (denom)) \
73 ? ((((numer) + (denom)) / (denom)) * (denom)) \
74 : (numer) + (denom))
76 /* "line" dimension for horizontal scroll */
77 #define HSCROLLDIM(es) ((es)->ClientWidth / 3)
79 /* macros to access window styles */
80 #define IsMultiLine(hwnd) (GetWindowLong(hwnd,GWL_STYLE) & ES_MULTILINE)
81 #define IsVScrollBar(hwnd) (GetWindowLong(hwnd,GWL_STYLE) & WS_VSCROLL)
82 #define IsHScrollBar(hwnd) (GetWindowLong(hwnd,GWL_STYLE) & WS_HSCROLL)
84 /* internal variables */
85 static BOOL TextMarking; /* TRUE if text marking in progress */
86 static BOOL ButtonDown; /* TRUE if left mouse button down */
87 static int ButtonRow; /* row in text buffer when button pressed */
88 static int ButtonCol; /* col in text buffer when button pressed */
90 #define SWAP_INT(x,y) do { int temp = (x); (x) = (y); (y) = temp; } while(0)
92 /*********************************************************************
93 * EDIT_HeapAlloc
95 * Allocate the specified number of bytes on the specified local heap.
97 static unsigned int EDIT_HeapAlloc(HWND hwnd, int bytes, WORD flags)
99 unsigned int ret;
101 ret = LOCAL_Alloc( GetWindowWord(hwnd,GWW_HINSTANCE), flags, bytes );
102 if (ret == 0)
103 printf("EDIT_HeapAlloc: Out of heap-memory\n");
104 return ret;
107 /*********************************************************************
108 * EDIT_HeapLock
110 * Return the address of the memory pointed to by the handle.
112 static void *EDIT_HeapLock(HWND hwnd, unsigned int handle)
114 WORD hinstance = GetWindowWord( hwnd, GWW_HINSTANCE );
115 WORD offs;
117 if (handle == 0) return 0;
118 offs = LOCAL_Lock( hinstance, handle );
119 return PTR_SEG_OFF_TO_LIN( hinstance, offs );
122 /*********************************************************************
123 * EDIT_HeapUnlock
125 static void EDIT_HeapUnlock(HWND hwnd, unsigned int handle)
127 if (handle == 0) return;
128 LOCAL_Unlock( GetWindowWord( hwnd, GWW_HINSTANCE ), handle );
131 /*********************************************************************
132 * EDIT_HeapReAlloc
134 * Reallocate the memory pointed to by the handle.
136 static unsigned int EDIT_HeapReAlloc(HWND hwnd, unsigned int handle, int bytes)
138 return LOCAL_ReAlloc( GetWindowWord(hwnd,GWW_HINSTANCE), handle, bytes,
139 LMEM_FIXED );
143 /*********************************************************************
144 * EDIT_HeapFree
146 * Frees the memory pointed to by the handle.
148 static void EDIT_HeapFree(HWND hwnd, unsigned int handle)
150 LOCAL_Free( GetWindowWord(hwnd,GWW_HINSTANCE), handle );
154 /*********************************************************************
155 * EDIT_HeapSize
157 * Return the size of the given object on the local heap.
159 static unsigned int EDIT_HeapSize(HWND hwnd, unsigned int handle)
161 return LOCAL_Size( GetWindowWord(hwnd,GWW_HINSTANCE), handle );
164 /********************************************************************
165 * EDIT_RecalcSize
167 * Sets the ClientWidth/ClientHeight fields of the EDITSTATE
168 * Called on WM_SIZE and WM_SetFont messages
170 static void EDIT_RecalcSize(HWND hwnd, EDITSTATE *es)
172 RECT rect;
173 GetClientRect(hwnd,&rect);
174 es->ClientWidth = rect.right > rect.left ? rect.right - rect.left : 0;
175 es->ClientHeight = rect.bottom > rect.top ? (rect.bottom - rect.top) / es->txtht : 0;
178 /*********************************************************************
179 * EDIT_GetEditState
181 static EDITSTATE *EDIT_GetEditState(HWND hwnd)
183 return (EDITSTATE *)GetWindowLong(hwnd,0);
186 /*********************************************************************
187 * EDIT_GetNextTabStop
189 * Return the next tab stop beyond _pcol_.
191 static int EDIT_GetNextTabStop(HWND hwnd, int pcol)
193 int i;
194 int baseUnitWidth = LOWORD(GetDialogBaseUnits());
195 EDITSTATE *es = EDIT_GetEditState(hwnd);
197 if (es->NumTabStops == 0)
198 return ROUNDUP(pcol, 8 * baseUnitWidth);
199 if (es->NumTabStops == 1)
200 return ROUNDUP(pcol, es->TabStops[0] * baseUnitWidth / 4);
201 for (i = 0; i < es->NumTabStops; i++)
203 if (es->TabStops[i] * baseUnitWidth / 4 >= pcol)
204 return es->TabStops[i] * baseUnitWidth / 4;
206 return pcol;
209 /*********************************************************************
210 * EDIT_CharWidth
212 * Return the width of the given character in pixels.
213 * The current column offset in pixels _pcol_ is required to calculate
214 * the width of a tab.
216 static int EDIT_CharWidth(HWND hwnd, short ch, int pcol)
218 EDITSTATE *es = EDIT_GetEditState(hwnd);
220 if (ch == VK_TAB) return EDIT_GetNextTabStop(hwnd, pcol) - pcol;
221 return es->CharWidths[ch];
224 /*********************************************************************
225 * EDIT_ClearTextPointers
227 * Clear and initialize text line pointer array.
229 static void EDIT_ClearTextPointers(HWND hwnd)
231 EDITSTATE *es = EDIT_GetEditState(hwnd);
233 dprintf_edit( stddeb, "EDIT_ClerTextPointers\n" );
234 es->textptrs = realloc(es->textptrs, sizeof(int));
235 es->textptrs[0] = 0;
238 /*********************************************************************
239 * EDIT_BuildTextPointers
241 * Build array of pointers to text lines.
243 static void EDIT_BuildTextPointers(HWND hwnd)
245 char *text, *cp;
246 unsigned int off, len, line;
247 EDITSTATE *es;
249 es = EDIT_GetEditState(hwnd);
250 text = EDIT_HeapLock(hwnd, es->hText);
252 es->textwidth = 0;
253 if (IsMultiLine(hwnd)) {
254 es->wlines = 0;
255 cp = text;
256 while ((cp = strchr(cp,'\n')) != NULL) {
257 es->wlines++; cp++;
259 } else es->wlines = 1;
261 dprintf_edit( stddeb, "EDIT_BuildTextPointers: realloc\n" );
262 es->textptrs = realloc(es->textptrs, (es->wlines + 2) * sizeof(int));
264 cp = text;
265 dprintf_edit(stddeb,"BuildTextPointers: %d lines, pointer %p\n",
266 es->wlines, es->textptrs);
268 /* advance through text buffer */
269 line = 0;
270 while (*cp)
272 off = cp - text; /* offset of beginning of line */
273 dprintf_edit(stddeb,"BuildTextPointers: line %d offs %d\n", line, off);
274 es->textptrs[line] = off;
275 line++;
276 len = 0;
278 /* advance through current line */
279 while (*cp && *cp != '\n')
281 len += EDIT_CharWidth(hwnd, (BYTE)*cp, len);
282 /* width of line in pixels */
283 cp++;
285 es->textwidth = max(es->textwidth, len);
286 if (*cp)
287 cp++; /* skip '\n' */
289 off = cp - text;
290 es->textptrs[line] = off;
291 EDIT_HeapUnlock(hwnd, es->hText);
294 /*********************************************************************
295 * EDIT_ModTextPointers
297 * Modify text pointers from a specified position.
299 static void EDIT_ModTextPointers(HWND hwnd, int lineno, int var)
301 EDITSTATE *es = EDIT_GetEditState(hwnd);
302 for(;lineno < es->wlines; lineno++) es->textptrs[lineno] += var;
305 /*********************************************************************
306 * EDIT_TextLine
308 * Return a pointer to the text in the specified line.
310 static char *EDIT_TextLine(HWND hwnd, int sel)
312 EDITSTATE *es = EDIT_GetEditState(hwnd);
313 char *text = EDIT_HeapLock(hwnd, es->hText);
315 if (sel > es->wlines) return NULL;
316 dprintf_edit(stddeb,"EDIT_TextLine: text %p, line %d offs %d\n",
317 text, sel, es->textptrs[sel]);
318 return text + es->textptrs[sel];
321 /*********************************************************************
322 * EDIT_GetTextLine
324 * Get a copy of the text in the specified line.
326 static char *EDIT_GetTextLine(HWND hwnd, int selection)
328 int len;
329 char *cp, *cp1;
331 dprintf_edit(stddeb,"GetTextLine %d\n", selection);
332 cp1 = EDIT_TextLine(hwnd, selection);
334 /* Find end of line */
335 cp = strchr( cp1, '\r' );
336 if (cp == NULL) len = strlen(cp1);
337 else len = cp - cp1;
339 /* store selected line and return handle */
340 cp = malloc( len + 1 );
341 strncpy( cp, cp1, len);
342 cp[len] = 0;
343 return cp;
346 /*********************************************************************
347 * EDIT_StrWidth
349 * Return length of string _str_ of length _len_ characters in pixels.
350 * The current column offset in pixels _pcol_ is required to calculate
351 * the width of a tab.
353 static int EDIT_StrWidth(HWND hwnd, unsigned char *str, int len, int pcol)
355 int i, plen = 0;
357 for (i = 0; i < len; i++)
358 plen += EDIT_CharWidth(hwnd, (BYTE)(*(str + i)), pcol + plen);
360 dprintf_edit(stddeb,"EDIT_StrWidth: returning %d, len=%d\n", plen,len);
361 return plen;
364 /*********************************************************************
365 * EDIT_LineLength
367 * Return length of line _num_ in characters.
369 static int EDIT_LineLength(HWND hwnd, int num)
371 char *cp = EDIT_TextLine(hwnd, num);
372 char *cp1;
374 if(!cp)return 0;
375 cp1 = strchr(cp, '\r');
376 return cp1 ? (cp1 - cp) : strlen(cp);
379 /*********************************************************************
380 * EDIT_GetStr
382 * Return sub-string starting at pixel _off_ of length _len_ pixels.
383 * If _off_ is part way through a character, the negative offset of
384 * the beginning of the character is returned in _diff_, else _diff_
385 * will be zero.
387 static HANDLE EDIT_GetStr(HWND hwnd, char *lp, int off, int len, int *diff)
389 HANDLE hStr;
390 char *str;
391 int ch = 0, i = 0, j, s_i=0;
392 int ch1;
394 dprintf_edit(stddeb,"EDIT_GetStr lp='%s' off=%d len=%d\n", lp, off, len);
396 if (off < 0) off = 0;
397 while (i < off)
399 s_i = i;
400 i += EDIT_CharWidth(hwnd, (BYTE)(*(lp + ch)), i);
401 ch++;
403 /* if stepped past _off_, go back a character */
404 if (i > off)
406 i = s_i;
407 ch--;
409 *diff = off - i;
410 ch1 = ch;
411 while (i < len + off)
413 if (*(lp + ch) == '\r' || *(lp + ch) == '\n')
414 break;
415 i += EDIT_CharWidth(hwnd, (BYTE)(*(lp + ch)), i);
416 ch++;
419 hStr = EDIT_HeapAlloc(hwnd, ch - ch1 + 3, LMEM_FIXED);
420 str = (char *)EDIT_HeapLock(hwnd, hStr);
421 for (i = ch1, j = 0; i < ch; i++, j++)
422 str[j] = lp[i];
423 str[j] = '\0';
424 dprintf_edit(stddeb,"EDIT_GetStr: returning %s\n", str);
425 return hStr;
428 /*********************************************************************
429 * EDIT_WriteText
431 * Write text to a window
432 * lp - text line
433 * off - offset in text line (in pixels)
434 * len - length from off (in pixels)
435 * row - line in window
436 * col - column in window
437 * rc - rectangle in which to display line
438 * blank - blank remainder of line?
439 * reverse - reverse color of line?
441 static void EDIT_WriteText(HWND hwnd, char *lp, int off, int len, int row,
442 int col, RECT *rc, BOOL blank, BOOL reverse)
444 HDC hdc;
445 HANDLE hStr;
446 char *str, *cp, *cp1;
447 int diff=0, num_spaces, tabwidth, scol;
448 HRGN hrgnClip;
449 COLORREF oldTextColor, oldBkgdColor;
450 HFONT oldfont;
451 EDITSTATE *es = EDIT_GetEditState(hwnd);
453 dprintf_edit(stddeb,"EDIT_WriteText lp=%s, off=%d, len=%d, row=%d, col=%d, reverse=%d\n", lp, off, len, row, col, reverse);
455 if( off < 0 ) {
456 len += off;
457 col -= off;
458 off = 0;
461 hdc = GetDC(hwnd);
462 hStr = EDIT_GetStr(hwnd, lp, off, len, &diff);
463 str = (char *)EDIT_HeapLock(hwnd, hStr);
464 hrgnClip = CreateRectRgnIndirect(rc);
465 SelectClipRgn(hdc, hrgnClip);
467 if (es->hFont)
468 oldfont = (HFONT)SelectObject(hdc, (HANDLE)es->hFont);
469 else
470 oldfont = 0; /* -Wall does not see the use of if */
472 SendMessage(GetParent(hwnd), WM_CTLCOLOR, (WORD)hdc,
473 MAKELPARAM(hwnd, CTLCOLOR_EDIT));
475 if (reverse)
477 oldBkgdColor = GetBkColor(hdc);
478 oldTextColor = GetTextColor(hdc);
479 SetBkColor(hdc, oldTextColor);
480 SetTextColor(hdc, oldBkgdColor);
482 else /* -Wall does not see the use of if */
483 oldTextColor = oldBkgdColor = 0;
485 if (strlen(es->BlankLine) < (es->ClientWidth / es->CharWidths[32]) + 2)
487 dprintf_edit( stddeb, "EDIT_WriteText: realloc\n" );
488 es->BlankLine = realloc(es->BlankLine,
489 (es->ClientWidth / es->CharWidths[32]) + 2);
490 memset(es->BlankLine, ' ', (es->ClientWidth / es->CharWidths[32]) + 2);
491 es->BlankLine[(es->ClientWidth / es->CharWidths[32]) + 1] = 0;
494 if (!(cp = strchr(str, VK_TAB)))
495 TextOut(hdc, col - diff, row * es->txtht, str, strlen(str));
496 else
498 TextOut(hdc, col - diff, row * es->txtht, str, (int)(cp - str));
499 scol = EDIT_StrWidth(hwnd, str, (int)(cp - str), 0);
500 tabwidth = EDIT_CharWidth(hwnd, VK_TAB, scol);
501 num_spaces = tabwidth / es->CharWidths[32] + 1;
502 TextOut(hdc, scol, row * es->txtht, es->BlankLine, num_spaces);
503 cp++;
504 scol += tabwidth;
506 while ((cp1 = strchr(cp, VK_TAB)))
508 TextOut(hdc, scol, row * es->txtht, cp, (int)(cp1 - cp));
509 scol += EDIT_StrWidth(hwnd, cp, (int)(cp1 - cp), scol);
510 tabwidth = EDIT_CharWidth(hwnd, VK_TAB, scol);
511 num_spaces = tabwidth / es->CharWidths[32] + 1;
512 TextOut(hdc, scol, row * es->txtht, es->BlankLine, num_spaces);
513 cp = ++cp1;
514 scol += tabwidth;
517 TextOut(hdc, scol, row * es->txtht, cp, strlen(cp));
520 if (reverse)
522 SetBkColor(hdc, oldBkgdColor);
523 SetTextColor(hdc, oldTextColor);
526 /* blank out remainder of line if appropriate */
527 if (blank)
529 if ((rc->right - col) > len)
531 num_spaces = (rc->right - col - len) / es->CharWidths[32];
532 TextOut(hdc, col + len, row * es->txtht, es->BlankLine, num_spaces);
536 if (es->hFont)
537 SelectObject(hdc, (HANDLE)oldfont);
539 EDIT_HeapFree(hwnd, hStr);
540 ReleaseDC(hwnd, hdc);
543 /*********************************************************************
544 * EDIT_WriteTextLine
546 * Write the line of text at offset _y_ in text buffer to a window.
548 static void EDIT_WriteTextLine(HWND hwnd, RECT *rect, int y)
550 int len = 0;
551 unsigned char *lp;
552 int lnlen, lnlen1;
553 int col, off = 0;
554 int sbl, sel, sbc, sec;
555 RECT rc;
556 EDITSTATE *es = EDIT_GetEditState(hwnd);
558 /* initialize rectangle if NULL, else copy */
559 if (rect)
560 CopyRect(&rc, rect);
561 else
562 GetClientRect(hwnd, &rc);
564 dprintf_edit(stddeb,"WriteTextLine %d\n", y);
566 /* make sure y is inside the window */
567 if (y < es->wtop || y > (es->wtop + es->ClientHeight))
569 dprintf_edit(stddeb,"EDIT_WriteTextLine: y (%d) is not a displayed line\n", y);
570 return;
573 /* make sure rectangle is within window */
574 if (rc.left >= es->ClientWidth - 1)
576 dprintf_edit(stddeb,"EDIT_WriteTextLine: rc.left (%d) is greater than right edge\n",
577 rc.left);
578 return;
580 if (rc.right <= 0)
582 dprintf_edit(stddeb,"EDIT_WriteTextLine: rc.right (%d) is less than left edge\n",
583 rc.right);
584 return;
586 if (y - es->wtop < (rc.top / es->txtht) ||
587 y - es->wtop > (rc.bottom / es->txtht))
589 dprintf_edit(stddeb,"EDIT_WriteTextLine: y (%d) is outside window\n", y);
590 return;
593 /* get the text and length of line */
594 lp = EDIT_GetTextLine( hwnd, y );
595 if (lp == NULL) return;
597 lnlen = EDIT_StrWidth( hwnd, lp, strlen(lp), 0 );
598 lnlen1 = lnlen;
600 /* build the line to display */
601 if (lnlen < (es->wleft + rc.left))
603 lnlen = 0;
604 return;
606 else
608 off += es->wleft;
609 lnlen -= off;
612 if (lnlen > rc.left)
614 off += rc.left;
615 lnlen = lnlen1 - off;
617 len = min(lnlen, rc.right - rc.left);
619 if (SelMarked(es))
621 sbl = es->SelBegLine;
622 sel = es->SelEndLine;
623 sbc = es->SelBegCol;
624 sec = es->SelEndCol;
626 /* put lowest marker first */
627 if (sbl > sel)
629 SWAP_INT(sbl, sel);
630 SWAP_INT(sbc, sec);
632 if (sbl == sel && sbc > sec)
633 SWAP_INT(sbc, sec);
635 if (y < sbl || y > sel)
636 EDIT_WriteText(hwnd, lp, off, len, y - es->wtop, rc.left, &rc,
637 TRUE, FALSE);
638 else if (y > sbl && y < sel)
639 EDIT_WriteText(hwnd, lp, off, len, y - es->wtop, rc.left, &rc,
640 TRUE, TRUE);
641 else if (y == sbl)
643 col = EDIT_StrWidth(hwnd, lp, sbc, 0);
644 if (col > (es->wleft + rc.left))
646 len = min(col - off, rc.right - off);
647 EDIT_WriteText(hwnd, lp, off, len, y - es->wtop,
648 rc.left, &rc, FALSE, FALSE);
649 off = col;
651 if (y == sel)
653 col = EDIT_StrWidth(hwnd, lp, sec, 0);
654 if (col < (es->wleft + rc.right))
656 len = min(col - off, rc.right - off);
657 EDIT_WriteText(hwnd, lp, off, len, y - es->wtop,
658 off - es->wleft, &rc, FALSE, TRUE);
659 off = col;
660 len = min(lnlen - off, rc.right - off);
661 EDIT_WriteText(hwnd, lp, off, len, y - es->wtop,
662 off - es->wleft, &rc, TRUE, FALSE);
664 else
666 len = min(lnlen - off, rc.right - off);
667 EDIT_WriteText(hwnd, lp, off, len, y - es->wtop,
668 off - es->wleft, &rc, TRUE, TRUE);
671 else
673 len = min(lnlen - off, rc.right - off);
674 if (col < (es->wleft + rc.right))
675 EDIT_WriteText(hwnd, lp, off, len, y - es->wtop,
676 off - es->wleft, &rc, TRUE, TRUE);
679 else if (y == sel)
681 col = EDIT_StrWidth(hwnd, lp, sec, 0);
682 if (col < (es->wleft + rc.right))
684 len = min(col - off, rc.right - off);
685 EDIT_WriteText(hwnd, lp, off, len, y - es->wtop,
686 off - es->wleft, &rc, FALSE, TRUE);
687 off = col;
688 len = min(lnlen - off, rc.right - off);
689 EDIT_WriteText(hwnd, lp, off, len, y - es->wtop,
690 off - es->wleft, &rc, TRUE, FALSE);
694 else
695 EDIT_WriteText(hwnd, lp, off, len, y - es->wtop, rc.left, &rc,
696 TRUE, FALSE);
698 free( lp );
701 /*********************************************************************
702 * EDIT_ComputeVScrollPos
704 * Compute the vertical scroll bar position from the window
705 * position and text width.
707 static int EDIT_ComputeVScrollPos(HWND hwnd)
709 int vscrollpos;
710 short minpos, maxpos;
711 EDITSTATE *es = EDIT_GetEditState(hwnd);
713 GetScrollRange(hwnd, SB_VERT, &minpos, &maxpos);
715 if (es->wlines > es->ClientHeight)
716 vscrollpos = (double)(es->wtop) / (double)(es->wlines -
717 es->ClientHeight) * (maxpos - minpos);
718 else
719 vscrollpos = minpos;
721 return vscrollpos;
724 /*********************************************************************
725 * EDIT_ComputeHScrollPos
727 * Compute the horizontal scroll bar position from the window
728 * position and text width.
730 static int EDIT_ComputeHScrollPos(HWND hwnd)
732 int hscrollpos;
733 short minpos, maxpos;
734 EDITSTATE *es = EDIT_GetEditState(hwnd);
736 GetScrollRange(hwnd, SB_HORZ, &minpos, &maxpos);
738 if (es->textwidth > es->ClientWidth)
739 hscrollpos = (double)(es->wleft) / (double)(es->textwidth -
740 es->ClientWidth) * (maxpos - minpos);
741 else
742 hscrollpos = minpos;
744 return hscrollpos;
747 /*********************************************************************
748 * EDIT_KeyHScroll
750 * Scroll text horizontally using cursor keys.
752 static void EDIT_KeyHScroll(HWND hwnd, WORD opt)
754 int hscrollpos;
755 EDITSTATE *es = EDIT_GetEditState(hwnd);
757 if (opt == SB_LINEDOWN)
759 es->wleft += HSCROLLDIM(es);
760 es->WndCol -= HSCROLLDIM(es);
762 else
764 if (es->wleft == 0)
765 return;
766 if (es->wleft - HSCROLLDIM(es) < 0)
768 es->WndCol += es->wleft;
769 es->wleft = 0;
771 else
773 es->wleft -= HSCROLLDIM(es);
774 es->WndCol += HSCROLLDIM(es);
778 InvalidateRect(hwnd, NULL, FALSE);
779 UpdateWindow(hwnd);
781 if (IsHScrollBar(hwnd))
783 hscrollpos = EDIT_ComputeHScrollPos(hwnd);
784 SetScrollPos(hwnd, SB_HORZ, hscrollpos, TRUE);
788 /*********************************************************************
789 * EDIT_KeyVScrollLine
791 * Scroll text vertically by one line using keyboard.
793 static void EDIT_KeyVScrollLine(HWND hwnd, WORD opt)
795 RECT rc;
796 int y, vscrollpos;
797 EDITSTATE *es = EDIT_GetEditState(hwnd);
799 if (!IsMultiLine(hwnd))
800 return;
802 if (opt == SB_LINEDOWN)
804 /* move down one line */
805 if (es->wtop + es->ClientHeight >= es->wlines)
806 return;
807 es->wtop++;
809 else
811 /* move up one line */
812 if (es->wtop == 0)
813 return;
814 --es->wtop;
817 if (IsWindowVisible(hwnd))
819 /* adjust client bottom to nearest whole line */
820 GetClientRect(hwnd, &rc);
821 rc.bottom = (rc.bottom / es->txtht) * es->txtht;
823 if (opt == SB_LINEUP)
825 /* move up one line (scroll window down) */
826 ScrollWindow(hwnd, 0, es->txtht, &rc, &rc);
827 /* write top line */
828 EDIT_WriteTextLine(hwnd, NULL, es->wtop);
829 es->WndRow++;
831 else
833 /* move down one line (scroll window up) */
834 ScrollWindow(hwnd, 0, -(es->txtht), &rc, &rc);
835 /* write bottom line */
836 y = (((rc.bottom - rc.top) / es->txtht) - 1);
837 EDIT_WriteTextLine(hwnd, NULL, es->wtop + y);
838 --es->WndRow;
842 /* reset the vertical scroll bar */
843 if (IsVScrollBar(hwnd))
845 vscrollpos = EDIT_ComputeVScrollPos(hwnd);
846 SetScrollPos(hwnd, SB_VERT, vscrollpos, TRUE);
850 /*********************************************************************
851 * EDIT_End
853 * End key: move to end of line.
855 static void EDIT_End(HWND hwnd)
857 EDITSTATE *es = EDIT_GetEditState(hwnd);
859 while (*CurrChar && *CurrChar != '\r')
861 es->WndCol += EDIT_CharWidth(hwnd, (BYTE)(*CurrChar), es->WndCol + es->wleft);
862 es->CurrCol++;
865 if (es->WndCol >= es->ClientWidth)
867 es->wleft = es->WndCol - es->ClientWidth + HSCROLLDIM(es);
868 es->WndCol -= es->wleft;
869 InvalidateRect(hwnd, NULL, FALSE);
870 UpdateWindow(hwnd);
874 /*********************************************************************
875 * EDIT_Home
877 * Home key: move to beginning of line.
879 static void EDIT_Home(HWND hwnd)
881 EDITSTATE *es = EDIT_GetEditState(hwnd);
883 es->CurrCol = es->WndCol = 0;
884 if (es->wleft != 0)
886 es->wleft = 0;
887 InvalidateRect(hwnd, NULL, FALSE);
888 UpdateWindow(hwnd);
892 /*********************************************************************
893 * EDIT_StickEnd
895 * Stick the cursor to the end of the line.
897 static void EDIT_StickEnd(HWND hwnd)
899 EDITSTATE *es = EDIT_GetEditState(hwnd);
900 int len = EDIT_LineLength(hwnd, es->CurrLine);
901 char *cp = EDIT_TextLine(hwnd, es->CurrLine);
902 int currpel;
904 es->CurrCol = min(len, es->CurrCol);
905 es->WndCol = min(EDIT_StrWidth(hwnd, cp, len, 0) - es->wleft, es->WndCol);
906 currpel = EDIT_StrWidth(hwnd, cp, es->CurrCol, 0);
908 if (es->wleft > currpel)
910 es->wleft = max(0, currpel - 20);
911 es->WndCol = currpel - es->wleft;
912 UpdateWindow(hwnd);
914 else if (currpel - es->wleft >= es->ClientWidth)
916 es->wleft = currpel - (es->ClientWidth - 5);
917 es->WndCol = currpel - es->wleft;
918 UpdateWindow(hwnd);
922 /*********************************************************************
923 * EDIT_Downward
925 * Cursor down key: move down one line.
927 static void EDIT_Downward(HWND hwnd)
929 EDITSTATE *es = EDIT_GetEditState(hwnd);
931 dprintf_edit(stddeb,"EDIT_Downward: WndRow=%d, wtop=%d, wlines=%d\n",
932 es->WndRow, es->wtop, es->wlines);
934 if (IsMultiLine(hwnd) && (es->WndRow + es->wtop + 1 < es->wlines))
936 es->CurrLine++;
937 if (es->WndRow == es->ClientHeight - 1)
939 es->WndRow++;
940 EDIT_KeyVScrollLine(hwnd, SB_LINEDOWN);
942 else
943 es->WndRow++;
944 EDIT_StickEnd(hwnd);
948 /*********************************************************************
949 * EDIT_Upward
951 * Cursor up key: move up one line.
953 static void EDIT_Upward(HWND hwnd)
955 EDITSTATE *es = EDIT_GetEditState(hwnd);
957 if (IsMultiLine(hwnd) && es->CurrLine != 0)
959 --es->CurrLine;
960 if (es->WndRow == 0)
962 --es->WndRow;
963 EDIT_KeyVScrollLine(hwnd, SB_LINEUP);
965 else
966 --es->WndRow;
967 EDIT_StickEnd(hwnd);
971 /*********************************************************************
972 * EDIT_Forward
974 * Cursor right key: move right one character position.
976 static void EDIT_Forward(HWND hwnd)
978 EDITSTATE *es = EDIT_GetEditState(hwnd);
980 if (*CurrChar == '\0')
981 return;
983 if (*CurrChar == '\r')
985 if (es->CurrLine < (es->wlines - 1))
987 EDIT_Home(hwnd);
988 EDIT_Downward(hwnd);
991 else
993 es->WndCol += EDIT_CharWidth(hwnd, (BYTE)(*CurrChar), es->WndCol + es->wleft);
994 es->CurrCol++;
995 if (es->WndCol >= es->ClientWidth)
996 EDIT_KeyHScroll(hwnd, SB_LINEDOWN);
1000 /*********************************************************************
1001 * EDIT_Backward
1003 * Cursor left key: move left one character position.
1005 static void EDIT_Backward(HWND hwnd)
1007 EDITSTATE *es = EDIT_GetEditState(hwnd);
1009 if (es->CurrCol)
1011 --es->CurrCol;
1012 if (*CurrChar == VK_TAB)
1013 es->WndCol -= EDIT_CharWidth(hwnd, (BYTE)(*CurrChar),
1014 EDIT_StrWidth(hwnd,
1015 EDIT_TextLine(hwnd, es->CurrLine),
1016 es->CurrCol, 0));
1017 else
1018 es->WndCol -= EDIT_CharWidth(hwnd, (BYTE)(*CurrChar), 0);
1019 if (es->WndCol < 0)
1020 EDIT_KeyHScroll(hwnd, SB_LINEUP);
1022 else if (IsMultiLine(hwnd) && es->CurrLine != 0)
1024 EDIT_Upward(hwnd);
1025 EDIT_End(hwnd);
1029 /*********************************************************************
1030 * EDIT_KeyVScrollPage
1032 * Scroll text vertically by one page using keyboard.
1034 static void EDIT_KeyVScrollPage(HWND hwnd, WORD opt)
1036 int vscrollpos;
1037 EDITSTATE *es = EDIT_GetEditState(hwnd);
1039 if (IsMultiLine(hwnd))
1041 if (opt == SB_PAGEUP)
1043 if (es->wtop > es->ClientHeight) es->wtop -= es->ClientHeight;
1045 else
1047 if (es->wtop + es->ClientHeight < es->wlines)
1049 es->wtop += es->ClientHeight;
1050 if (es->wtop > es->wlines - es->ClientHeight)
1051 es->wtop = es->wlines - es->ClientHeight;
1054 if (es->wtop < 0)
1055 es->wtop = 0;
1057 es->CurrLine = es->wtop + es->WndRow;
1058 EDIT_StickEnd(hwnd);
1059 InvalidateRect(hwnd, NULL, TRUE);
1060 UpdateWindow(hwnd);
1062 /* reset the vertical scroll bar */
1063 if (IsVScrollBar(hwnd))
1065 vscrollpos = EDIT_ComputeVScrollPos(hwnd);
1066 SetScrollPos(hwnd, SB_VERT, vscrollpos, TRUE);
1071 /*********************************************************************
1072 * EDIT_KeyVScrollDoc
1074 * Scroll text to top and bottom of document using keyboard.
1076 static void EDIT_KeyVScrollDoc(HWND hwnd, WORD opt)
1078 int vscrollpos;
1079 EDITSTATE *es = EDIT_GetEditState(hwnd);
1081 if (!IsMultiLine(hwnd))
1082 return;
1084 if (opt == SB_TOP)
1085 es->wtop = es->wleft = 0;
1086 else if (es->wtop + es->ClientHeight < es->wlines)
1088 es->wtop = es->wlines - es->ClientHeight;
1089 es->wleft = 0;
1092 es->CurrLine = es->wlines;
1093 es->WndRow = es->wlines - es->wtop;
1094 EDIT_End(hwnd);
1095 InvalidateRect(hwnd, NULL, TRUE);
1096 UpdateWindow(hwnd);
1098 /* reset the vertical scroll bar */
1099 if (IsVScrollBar(hwnd))
1101 vscrollpos = EDIT_ComputeVScrollPos(hwnd);
1102 SetScrollPos(hwnd, SB_VERT, vscrollpos, TRUE);
1106 /*********************************************************************
1107 * EDIT_DelKey
1109 * Delete character to right of cursor.
1111 static void EDIT_DelKey(HWND hwnd)
1113 RECT rc;
1114 EDITSTATE *es = EDIT_GetEditState(hwnd);
1115 char *currchar = CurrChar;
1116 BOOL repaint = *currchar == '\n';
1118 if (IsMultiLine(hwnd) && *currchar == '\n' && *(currchar + 1) == '\0')
1119 return;
1120 strcpy(currchar, currchar + 1);
1121 NOTIFY_PARENT(hwnd, EN_UPDATE);
1123 if (repaint)
1125 EDIT_BuildTextPointers(hwnd);
1126 GetClientRect(hwnd, &rc);
1127 rc.top = es->WndRow * es->txtht;
1128 InvalidateRect(hwnd, &rc, FALSE);
1129 UpdateWindow(hwnd);
1131 else
1133 EDIT_ModTextPointers(hwnd, es->CurrLine + 1, -1);
1134 EDIT_WriteTextLine(hwnd, NULL, es->WndRow + es->wtop);
1137 es->TextChanged = TRUE;
1138 NOTIFY_PARENT(hwnd, EN_CHANGE);
1141 /*********************************************************************
1142 * EDIT_VScrollLine
1144 * Scroll text vertically by one line using scrollbars.
1146 static void EDIT_VScrollLine(HWND hwnd, WORD opt)
1148 RECT rc;
1149 int y;
1150 EDITSTATE *es = EDIT_GetEditState(hwnd);
1152 dprintf_edit(stddeb,"EDIT_VScrollLine: direction=%d\n", opt);
1154 if (opt == SB_LINEDOWN)
1156 /* move down one line */
1157 if (es->wtop + es->ClientHeight >= es->wlines)
1158 return;
1159 es->wtop++;
1161 else
1163 /* move up one line */
1164 if (es->wtop == 0)
1165 return;
1166 --es->wtop;
1169 if (IsWindowVisible(hwnd))
1171 /* adjust client bottom to nearest whole line */
1172 GetClientRect(hwnd, &rc);
1173 rc.bottom = (rc.bottom / es->txtht) * es->txtht;
1175 if (opt == SB_LINEUP)
1177 /* move up one line (scroll window down) */
1178 ScrollWindow(hwnd, 0, es->txtht, &rc, &rc);
1179 /* write top line */
1180 EDIT_WriteTextLine(hwnd, NULL, es->wtop);
1181 es->WndRow++;
1183 else
1185 /* move down one line (scroll window up) */
1186 ScrollWindow(hwnd, 0, -(es->txtht), &rc, &rc);
1187 /* write bottom line */
1188 y = ((rc.bottom - rc.top / es->txtht) - 1);
1189 EDIT_WriteTextLine(hwnd, NULL, es->wtop + y);
1190 --es->WndRow;
1196 /*********************************************************************
1197 * EDIT_VScrollPage
1199 * Scroll text vertically by one page using keyboard.
1201 static void EDIT_VScrollPage(HWND hwnd, WORD opt)
1203 int vscrollpos;
1204 EDITSTATE *es = EDIT_GetEditState(hwnd);
1206 if (opt == SB_PAGEUP)
1208 if (es->wtop)
1209 es->wtop -= es->ClientHeight;
1211 else
1213 if (es->wtop + es->ClientHeight < es->wlines)
1215 es->wtop += es->ClientHeight;
1216 if (es->wtop > es->wlines - es->ClientHeight)
1217 es->wtop = es->wlines - es->ClientHeight;
1220 if (es->wtop < 0)
1221 es->wtop = 0;
1223 InvalidateRect(hwnd, NULL, TRUE);
1224 UpdateWindow(hwnd);
1226 /* reset the vertical scroll bar */
1227 if (IsVScrollBar(hwnd))
1229 vscrollpos = EDIT_ComputeVScrollPos(hwnd);
1230 SetScrollPos(hwnd, SB_VERT, vscrollpos, TRUE);
1234 /*********************************************************************
1235 * EDIT_PixelToChar
1237 * Convert a pixel offset in the given row to a character offset,
1238 * adjusting the pixel offset to the nearest whole character if
1239 * necessary.
1241 static int EDIT_PixelToChar(HWND hwnd, int row, int *pixel)
1243 int ch = 0, i = 0, s_i = 0;
1244 char *text;
1246 dprintf_edit(stddeb,"EDIT_PixelToChar: row=%d, pixel=%d\n", row, *pixel);
1248 text = EDIT_TextLine(hwnd, row);
1249 while (i < *pixel)
1251 s_i = i;
1252 i += EDIT_CharWidth(hwnd, (BYTE)(*(text + ch)), i);
1253 ch++;
1256 /* if stepped past _pixel_, go back a character */
1257 if (i - *pixel)
1259 i = s_i;
1260 --ch;
1262 *pixel = i;
1263 return ch;
1266 /*********************************************************************
1267 * EDIT_ClearText
1269 * Clear text from text buffer.
1271 static void EDIT_ClearText(HWND hwnd)
1273 EDITSTATE *es = EDIT_GetEditState(hwnd);
1274 unsigned int blen = EditBufStartLen(hwnd) + 2;
1275 char *text;
1277 dprintf_edit(stddeb,"EDIT_ClearText %d\n",blen);
1278 es->hText = EDIT_HeapReAlloc(hwnd, es->hText, blen);
1279 text = EDIT_HeapLock(hwnd, es->hText);
1280 memset(text, 0, blen);
1281 es->textlen = 0;
1282 es->wlines = 0;
1283 es->CurrLine = es->CurrCol = 0;
1284 es->WndRow = es->WndCol = 0;
1285 es->wleft = es->wtop = 0;
1286 es->textwidth = 0;
1287 es->TextChanged = FALSE;
1288 EDIT_ClearTextPointers(hwnd);
1291 /*********************************************************************
1292 * EDIT_GetLineCol
1294 * Return line and column in text buffer from character offset.
1296 static void EDIT_GetLineCol(HWND hwnd, int off, int *line, int *col)
1298 int lineno;
1299 char *cp, *cp1;
1300 EDITSTATE *es = EDIT_GetEditState(hwnd);
1301 char *text = EDIT_HeapLock(hwnd, es->hText);
1303 /* check for (0,0) */
1304 if (!off || !es->wlines)
1306 *line = 0;
1307 *col = 0;
1308 return;
1311 if (off < 0 || off > strlen(text)) off = strlen(text);
1312 cp1 = text;
1313 for (lineno = 0; lineno < es->wlines; lineno++)
1315 cp = text + es->textptrs[lineno];
1316 if (off == (int)(cp - text))
1318 *line = lineno;
1319 *col = 0;
1320 return;
1322 if (off < (int)(cp - text))
1323 break;
1324 cp1 = cp;
1326 *line = lineno - 1;
1327 *col = off - (int)(cp1 - text);
1328 #if 0
1329 if (*(text + *col) == '\0')
1330 (*col)--;
1331 #endif
1334 /*********************************************************************
1335 * EDIT_ClearSel
1337 * Clear the current selection.
1339 static void EDIT_ClearSel(HWND hwnd)
1341 EDITSTATE *es = EDIT_GetEditState(hwnd);
1343 es->SelBegLine = es->SelBegCol = 0;
1344 es->SelEndLine = es->SelEndCol = 0;
1346 InvalidateRect(hwnd, NULL, TRUE);
1347 UpdateWindow(hwnd);
1350 /*********************************************************************
1351 * EDIT_SaveDeletedText
1353 * Save deleted text in deleted text buffer.
1355 static void EDIT_SaveDeletedText(HWND hwnd, char *deltext, int len,
1356 int line, int col)
1358 char *text;
1359 EDITSTATE *es = EDIT_GetEditState(hwnd);
1361 dprintf_edit( stddeb, "EDIT_SaveDeletedText\n" );
1362 if (!es->hDeletedText)
1363 es->hDeletedText = GlobalAlloc( GMEM_MOVEABLE, len );
1364 else
1365 es->hDeletedText = GlobalReAlloc(es->hDeletedText, len, GMEM_MOVEABLE);
1366 if (!es->hDeletedText) return;
1367 text = (char *)GlobalLock(es->hDeletedText);
1368 memcpy(text, deltext, len);
1369 GlobalUnlock(es->hDeletedText);
1370 es->DeletedLength = len;
1371 es->DeletedCurrLine = line;
1372 es->DeletedCurrCol = col;
1375 /*********************************************************************
1376 * EDIT_DeleteSel
1378 * Delete the current selected text (if any)
1380 static void EDIT_DeleteSel(HWND hwnd)
1382 char *bbl, *bel;
1383 int len;
1384 EDITSTATE *es = EDIT_GetEditState(hwnd);
1386 if (SelMarked(es))
1388 bbl = EDIT_TextLine(hwnd, es->SelBegLine) + es->SelBegCol;
1389 bel = EDIT_TextLine(hwnd, es->SelEndLine) + es->SelEndCol;
1390 len = (int)(bel - bbl);
1391 EDIT_SaveDeletedText(hwnd, bbl, len, es->SelBegLine, es->SelBegCol);
1392 es->TextChanged = TRUE;
1393 strcpy(bbl, bel);
1395 es->CurrLine = es->SelBegLine;
1396 es->CurrCol = es->SelBegCol;
1397 es->WndRow = es->SelBegLine - es->wtop;
1398 if (es->WndRow < 0)
1400 es->wtop = es->SelBegLine;
1401 es->WndRow = 0;
1403 es->WndCol = EDIT_StrWidth(hwnd, bbl - es->SelBegCol,
1404 es->SelBegCol, 0) - es->wleft;
1406 EDIT_BuildTextPointers(hwnd);
1407 es->PaintBkgd = TRUE;
1408 EDIT_ClearSel(hwnd);
1412 /*********************************************************************
1413 * EDIT_TextLineNumber
1415 * Return the line number in the text buffer of the supplied
1416 * character pointer.
1418 static int EDIT_TextLineNumber(HWND hwnd, char *lp)
1420 int lineno;
1421 char *cp;
1422 EDITSTATE *es = EDIT_GetEditState(hwnd);
1423 char *text = EDIT_HeapLock(hwnd, es->hText);
1425 for (lineno = 0; lineno < es->wlines; lineno++)
1427 cp = text + es->textptrs[lineno];
1428 if (cp == lp)
1429 return lineno;
1430 if (cp > lp)
1431 break;
1433 return lineno - 1;
1436 /*********************************************************************
1437 * EDIT_SetAnchor
1439 * Set down anchor for text marking.
1441 static void EDIT_SetAnchor(HWND hwnd, int row, int col)
1443 BOOL sel = FALSE;
1444 EDITSTATE *es = EDIT_GetEditState(hwnd);
1446 if (SelMarked(es))
1448 sel = TRUE;
1449 EDIT_ClearSel(hwnd);
1451 es->SelBegLine = es->SelEndLine = row;
1452 es->SelBegCol = es->SelEndCol = col;
1453 if (sel)
1455 InvalidateRect(hwnd, NULL, FALSE);
1456 UpdateWindow(hwnd);
1460 /*********************************************************************
1461 * EDIT_WriteSel
1463 * Display selection by reversing pixels in selected text.
1464 * If end == -1, selection applies to end of line.
1466 static void EDIT_WriteSel(HWND hwnd, int y, int start, int end)
1468 RECT rc, rcInvert;
1469 int scol, ecol;
1470 char *cp;
1471 HDC hdc;
1472 EDITSTATE *es = EDIT_GetEditState(hwnd);
1474 dprintf_edit(stddeb,"EDIT_WriteSel: y=%d start=%d end=%d\n", y, start,end);
1475 GetClientRect(hwnd, &rc);
1477 /* make sure y is within the window */
1478 if (y < es->wtop || y > (es->wtop + es->ClientHeight))
1479 return;
1481 /* get pointer to text */
1482 cp = EDIT_TextLine(hwnd, y);
1484 /* get length of line if end == -1 */
1485 if (end == -1)
1486 end = EDIT_LineLength(hwnd, y);
1488 scol = EDIT_StrWidth(hwnd, cp, start, 0) - es->wleft;
1489 if (scol > rc.right) return;
1490 if (scol < rc.left) scol = rc.left;
1491 ecol = EDIT_StrWidth(hwnd, cp, end, 0) - es->wleft;
1492 if (ecol < rc.left) return;
1493 if (ecol > rc.right) ecol = rc.right;
1495 hdc = GetDC(hwnd);
1496 rcInvert.left = scol;
1497 rcInvert.top = (y - es->wtop) * es->txtht;
1498 rcInvert.right = ecol;
1499 rcInvert.bottom = (y - es->wtop + 1) * es->txtht;
1500 InvertRect(hdc, (LPRECT) &rcInvert);
1501 ReleaseDC(hwnd, hdc);
1504 /*********************************************************************
1505 * EDIT_ExtendSel
1507 * Extend selection to the given screen co-ordinates.
1509 static void EDIT_ExtendSel(HWND hwnd, INT x, INT y)
1511 int bbl, bel, bbc, bec;
1512 char *cp;
1513 int len, line;
1514 EDITSTATE *es = EDIT_GetEditState(hwnd);
1516 dprintf_edit(stddeb,"EDIT_ExtendSel: x=%d, y=%d\n", x, y);
1518 bbl = es->SelEndLine;
1519 bbc = es->SelEndCol;
1520 y = max(y,0);
1521 if (IsMultiLine(hwnd))
1523 if ((line = es->wtop + y / es->txtht) >= es->wlines)
1524 line = es->wlines - 1;
1526 else
1527 line = 0;
1529 cp = EDIT_TextLine(hwnd, line);
1530 len = EDIT_LineLength(hwnd, line);
1532 es->WndRow = y / es->txtht;
1533 if (!IsMultiLine(hwnd))
1534 es->WndRow = 0;
1535 else if (es->WndRow > es->wlines - es->wtop - 1)
1536 es->WndRow = es->wlines - es->wtop - 1;
1537 es->CurrLine = es->wtop + es->WndRow;
1538 es->SelEndLine = es->CurrLine;
1540 es->WndCol = es->wleft + max(x,0);
1541 if (es->WndCol > EDIT_StrWidth(hwnd, cp, len, 0))
1542 es->WndCol = EDIT_StrWidth(hwnd, cp, len, 0);
1543 es->CurrCol = EDIT_PixelToChar(hwnd, es->CurrLine, &(es->WndCol));
1544 es->WndCol -= es->wleft;
1545 es->SelEndCol = es->CurrCol;
1547 bel = es->SelEndLine;
1548 bec = es->SelEndCol;
1550 /* return if no new characters to mark */
1551 if (bbl == bel && bbc == bec)
1552 return;
1554 /* put lowest marker first */
1555 if (bbl > bel)
1557 SWAP_INT(bbl, bel);
1558 SWAP_INT(bbc, bec);
1560 if (bbl == bel && bbc > bec)
1561 SWAP_INT(bbc, bec);
1563 for (y = bbl; y <= bel; y++)
1565 if (y == bbl && y == bel)
1566 EDIT_WriteSel(hwnd, y, bbc, bec);
1567 else if (y == bbl)
1568 EDIT_WriteSel(hwnd, y, bbc, -1);
1569 else if (y == bel)
1570 EDIT_WriteSel(hwnd, y, 0, bec);
1571 else
1572 EDIT_WriteSel(hwnd, y, 0, -1);
1576 /*********************************************************************
1577 * EDIT_StopMarking
1579 * Stop text marking (selection).
1581 static void EDIT_StopMarking(HWND hwnd)
1583 EDITSTATE *es = EDIT_GetEditState(hwnd);
1585 TextMarking = FALSE;
1586 if (es->SelBegLine > es->SelEndLine)
1588 SWAP_INT((es->SelBegLine), (es->SelEndLine));
1589 SWAP_INT((es->SelBegCol), (es->SelEndCol));
1591 if (es->SelBegLine == es->SelEndLine && es->SelBegCol > es->SelEndCol)
1592 SWAP_INT((es->SelBegCol), (es->SelEndCol));
1595 /*********************************************************************
1596 * EDIT_InsertText
1598 * Insert text at current line and column.
1600 static void EDIT_InsertText(HWND hwnd, char *str, int len)
1602 int plen;
1603 EDITSTATE *es = EDIT_GetEditState(hwnd);
1604 char *text = EDIT_HeapLock(hwnd, es->hText);
1606 plen = strlen(text) + len;
1607 if (plen + 1 > es->textlen)
1609 dprintf_edit(stddeb,"InsertText: Realloc\n");
1610 es->hText = EDIT_HeapReAlloc(hwnd, es->hText, es->textlen + len);
1611 text = EDIT_HeapLock(hwnd, es->hText);
1612 es->textlen = plen + 1;
1614 memmove(CurrChar + len, CurrChar, strlen(CurrChar) + 1);
1615 memcpy(CurrChar, str, len);
1617 EDIT_BuildTextPointers(hwnd);
1618 es->PaintBkgd = TRUE;
1619 es->TextChanged = TRUE;
1621 EDIT_GetLineCol(hwnd, (int)((CurrChar + len) - text), &(es->CurrLine),
1622 &(es->CurrCol));
1623 es->WndRow = es->CurrLine - es->wtop;
1624 es->WndCol = EDIT_StrWidth(hwnd, EDIT_TextLine(hwnd, es->CurrLine),
1625 es->CurrCol, 0) - es->wleft;
1628 /*********************************************************************
1629 * EDIT_ClearDeletedText
1631 * Clear deleted text buffer.
1633 static void EDIT_ClearDeletedText(HWND hwnd)
1635 EDITSTATE *es = EDIT_GetEditState(hwnd);
1637 GlobalFree(es->hDeletedText);
1638 es->hDeletedText = 0;
1639 es->DeletedLength = 0;
1642 /*********************************************************************
1643 * EDIT_CopyToClipboard
1645 * Copy the specified text to the clipboard.
1647 static void EDIT_CopyToClipboard(HWND hwnd)
1649 HANDLE hMem;
1650 char *lpMem;
1651 int i, len;
1652 char *bbl, *bel;
1653 EDITSTATE *es = EDIT_GetEditState(hwnd);
1655 bbl = EDIT_TextLine(hwnd, es->SelBegLine) + es->SelBegCol;
1656 bel = EDIT_TextLine(hwnd, es->SelEndLine) + es->SelEndCol;
1657 len = (int)(bel - bbl);
1659 hMem = GlobalAlloc(GHND, (DWORD)(len + 1));
1660 lpMem = GlobalLock(hMem);
1662 for (i = 0; i < len; i++)
1663 *lpMem++ = *bbl++;
1665 GlobalUnlock(hMem);
1666 OpenClipboard(hwnd);
1667 EmptyClipboard();
1668 SetClipboardData(CF_TEXT, hMem);
1669 CloseClipboard();
1672 /*********************************************************************
1673 * EDIT_KeyTyped
1675 * Process keystrokes that produce displayable characters.
1677 static void EDIT_KeyTyped(HWND hwnd, short ch)
1679 EDITSTATE *es = EDIT_GetEditState(hwnd);
1680 char *text = EDIT_HeapLock(hwnd, es->hText);
1681 char *currchar;
1682 RECT rc;
1683 BOOL FullPaint = FALSE;
1685 dprintf_edit(stddeb,"EDIT_KeyTyped: ch=%c\n", (char)ch);
1687 /* delete selected text (if any) */
1688 if (SelMarked(es))
1689 EDIT_DeleteSel(hwnd);
1691 /* currchar must be assigned after deleting the selection */
1692 currchar = CurrChar;
1694 /* test for typing at end of maximum buffer size */
1695 if (currchar == text + es->MaxTextLen)
1697 NOTIFY_PARENT(hwnd, EN_ERRSPACE);
1698 return;
1701 if (*currchar == '\0' && IsMultiLine(hwnd))
1703 /* insert a newline at end of text */
1704 *currchar = '\r';
1705 *(currchar + 1) = '\n';
1706 *(currchar + 2) = '\0';
1707 EDIT_BuildTextPointers(hwnd);
1710 /* insert the typed character */
1711 if (text[es->textlen - 1] != '\0')
1713 /* current text buffer is full */
1714 if (es->textlen == es->MaxTextLen)
1716 /* text buffer is at maximum size */
1717 NOTIFY_PARENT(hwnd, EN_ERRSPACE);
1718 return;
1721 /* increase the text buffer size */
1722 es->textlen += GROWLENGTH;
1723 /* but not above maximum size */
1724 if (es->textlen > es->MaxTextLen)
1725 es->textlen = es->MaxTextLen;
1726 dprintf_edit( stddeb, "EDIT_KeyTyped: realloc\n" );
1727 es->hText = EDIT_HeapReAlloc(hwnd, es->hText, es->textlen + 2);
1728 if (!es->hText)
1729 NOTIFY_PARENT(hwnd, EN_ERRSPACE);
1730 text = EDIT_HeapLock(hwnd, es->hText);
1731 text[es->textlen - 1] = '\0';
1732 currchar = CurrChar;
1734 /* make space for new character and put char in buffer */
1735 if (ch == '\n')
1737 memmove(currchar + 2, currchar, strlen(currchar) + 1);
1738 *currchar = '\r';
1739 *(currchar + 1) = '\n';
1740 EDIT_ModTextPointers(hwnd, es->CurrLine + 1, 2);
1742 else
1744 memmove(currchar + 1, currchar, strlen(currchar) + 1);
1745 *currchar = ch;
1746 EDIT_ModTextPointers(hwnd, es->CurrLine + 1, 1);
1748 es->TextChanged = TRUE;
1749 NOTIFY_PARENT(hwnd, EN_UPDATE);
1751 /* re-adjust textwidth, if necessary, and redraw line */
1752 HideCaret(hwnd);
1753 if (IsMultiLine(hwnd) && es->wlines > 1)
1755 es->textwidth = max(es->textwidth,
1756 EDIT_StrWidth(hwnd, EDIT_TextLine(hwnd, es->CurrLine),
1757 (int)(EDIT_TextLine(hwnd, es->CurrLine + 1) -
1758 EDIT_TextLine(hwnd, es->CurrLine)), 0));
1759 } else {
1760 es->textwidth = max(es->textwidth,
1761 EDIT_StrWidth(hwnd, text, strlen(text), 0));
1764 if (ch == '\n')
1766 if (es->wleft > 0)
1767 FullPaint = TRUE;
1768 es->wleft = 0;
1769 EDIT_BuildTextPointers(hwnd);
1770 EDIT_End(hwnd);
1771 EDIT_Forward(hwnd);
1773 /* invalidate rest of window */
1774 GetClientRect(hwnd, &rc);
1775 if (!FullPaint)
1776 rc.top = es->WndRow * es->txtht;
1777 InvalidateRect(hwnd, &rc, FALSE);
1779 SetCaretPos(es->WndCol, es->WndRow * es->txtht);
1780 ShowCaret(hwnd);
1781 UpdateWindow(hwnd);
1782 NOTIFY_PARENT(hwnd, EN_CHANGE);
1783 return;
1786 /* test end of window */
1787 if (es->WndCol >= es->ClientWidth -
1788 EDIT_CharWidth(hwnd, (BYTE)ch, es->WndCol + es->wleft))
1790 /* TODO:- Word wrap to be handled here */
1792 /* if (!(currchar == text + es->MaxTextLen - 2)) */
1793 EDIT_KeyHScroll(hwnd, SB_LINEDOWN);
1795 es->WndCol += EDIT_CharWidth(hwnd, (BYTE)ch, es->WndCol + es->wleft);
1796 es->CurrCol++;
1797 EDIT_WriteTextLine(hwnd, NULL, es->wtop + es->WndRow);
1798 SetCaretPos(es->WndCol, es->WndRow * es->txtht);
1799 ShowCaret(hwnd);
1800 NOTIFY_PARENT(hwnd, EN_CHANGE);
1801 dprintf_edit(stddeb,"KeyTyped O.K.\n");
1804 /*********************************************************************
1805 * EM_UNDO message function
1807 static LONG EDIT_UndoMsg(HWND hwnd)
1809 char *text;
1810 EDITSTATE *es = EDIT_GetEditState(hwnd);
1812 if (es->hDeletedText)
1814 text = (char *)GlobalLock(es->hDeletedText);
1815 es->CurrLine = es->DeletedCurrLine;
1816 es->CurrCol = es->DeletedCurrCol;
1817 EDIT_InsertText(hwnd, text, es->DeletedLength);
1818 GlobalUnlock(es->hDeletedText);
1819 EDIT_ClearDeletedText(hwnd);
1821 es->SelBegLine = es->CurrLine;
1822 es->SelBegCol = es->CurrCol;
1823 EDIT_GetLineCol(hwnd, (int)((CurrChar + es->DeletedLength) - text),
1824 &(es->CurrLine), &(es->CurrCol));
1825 es->WndRow = es->CurrLine - es->wtop;
1826 es->WndCol = EDIT_StrWidth(hwnd, EDIT_TextLine(hwnd, es->CurrLine),
1827 es->CurrCol, 0) - es->wleft;
1828 es->SelEndLine = es->CurrLine;
1829 es->SelEndCol = es->CurrCol;
1831 InvalidateRect(hwnd, NULL, TRUE);
1832 UpdateWindow(hwnd);
1833 return 1;
1835 else
1836 return 0;
1839 /*********************************************************************
1840 * EM_SETHANDLE message function
1842 static void EDIT_SetHandleMsg(HWND hwnd, WORD wParam)
1844 EDITSTATE *es = EDIT_GetEditState(hwnd);
1846 if (IsMultiLine(hwnd))
1848 es->hText = wParam;
1849 es->textlen = EDIT_HeapSize(hwnd, es->hText);
1850 es->wlines = 0;
1851 es->wtop = es->wleft = 0;
1852 es->CurrLine = es->CurrCol = 0;
1853 es->WndRow = es->WndCol = 0;
1854 es->TextChanged = FALSE;
1855 es->textwidth = 0;
1856 es->SelBegLine = es->SelBegCol = 0;
1857 es->SelEndLine = es->SelEndCol = 0;
1858 dprintf_edit(stddeb, "EDIT_SetHandleMsg: handle %04x, textlen=%d\n",
1859 wParam, es->textlen);
1861 EDIT_BuildTextPointers(hwnd);
1862 es->PaintBkgd = TRUE;
1863 InvalidateRect(hwnd, NULL, TRUE);
1864 UpdateWindow(hwnd);
1868 /*********************************************************************
1869 * EM_SETTABSTOPS message function
1871 static LONG EDIT_SetTabStopsMsg(HWND hwnd, WORD wParam, LONG lParam)
1873 EDITSTATE *es = EDIT_GetEditState(hwnd);
1875 dprintf_edit( stddeb, "EDIT_SetTabStops\n" );
1876 es->NumTabStops = wParam;
1877 if (wParam == 0)
1878 es->TabStops = realloc(es->TabStops, 2);
1879 else if (wParam == 1)
1881 es->TabStops = realloc(es->TabStops, 2);
1882 es->TabStops[0] = LOWORD(lParam);
1884 else
1886 es->TabStops = realloc(es->TabStops, wParam * sizeof(*es->TabStops));
1887 memcpy(es->TabStops, (unsigned short *)PTR_SEG_TO_LIN(lParam), wParam);
1889 return 0;
1892 /*********************************************************************
1893 * EM_GETLINE message function
1895 static LONG EDIT_GetLineMsg(HWND hwnd, WORD wParam, LONG lParam)
1897 char *cp, *cp1;
1898 int len;
1899 unsigned char *buffer = (char *)lParam;
1901 cp = EDIT_TextLine(hwnd, wParam);
1902 cp1 = EDIT_TextLine(hwnd, wParam + 1);
1903 len = min((int)(cp1 - cp), (WORD)(*buffer));
1904 dprintf_edit( stddeb, "EDIT_GetLineMsg: %d %d, len %d\n", (int)(WORD)(*buffer), (int)(WORD)(*(char *)buffer), len);
1905 strncpy(buffer, cp, len);
1907 return (LONG)len;
1910 /*********************************************************************
1911 * EM_GETSEL message function
1913 static LONG EDIT_GetSelMsg(HWND hwnd)
1915 int so, eo;
1916 EDITSTATE *es = EDIT_GetEditState(hwnd);
1918 so = es->textptrs[es->SelBegLine] + es->SelBegCol;
1919 eo = es->textptrs[es->SelEndLine] + es->SelEndCol;
1921 return MAKELONG(so, eo);
1924 /*********************************************************************
1925 * EM_REPLACESEL message function
1927 static void EDIT_ReplaceSel(HWND hwnd, LONG lParam)
1929 EDIT_DeleteSel(hwnd);
1930 EDIT_InsertText(hwnd, (char *)PTR_SEG_TO_LIN(lParam),
1931 strlen((char *)PTR_SEG_TO_LIN(lParam)));
1932 InvalidateRect(hwnd, NULL, TRUE);
1933 UpdateWindow(hwnd);
1936 /*********************************************************************
1937 * EM_LINEFROMCHAR message function
1939 static LONG EDIT_LineFromCharMsg(HWND hwnd, WORD wParam)
1941 int row, col;
1942 EDITSTATE *es = EDIT_GetEditState(hwnd);
1944 if (wParam == (WORD)-1)
1945 return (LONG)(es->SelBegLine);
1946 else
1947 EDIT_GetLineCol(hwnd, wParam, &row, &col);
1949 return (LONG)row;
1953 /*********************************************************************
1954 * EM_LINEINDEX message function
1956 static LONG EDIT_LineIndexMsg(HWND hwnd, WORD wParam)
1958 EDITSTATE *es = EDIT_GetEditState(hwnd);
1960 if (wParam == (WORD)-1) wParam = es->CurrLine;
1961 return es->textptrs[wParam];
1965 /*********************************************************************
1966 * EM_LINELENGTH message function
1968 static LONG EDIT_LineLengthMsg(HWND hwnd, WORD wParam)
1970 int row, col, len;
1971 int sbl, sbc, sel, sec;
1972 EDITSTATE *es = EDIT_GetEditState(hwnd);
1974 if (wParam == (WORD)-1)
1976 if (SelMarked(es))
1978 sbl = es->SelBegLine;
1979 sbc = es->SelBegCol;
1980 sel = es->SelEndLine;
1981 sec = es->SelEndCol;
1983 if (sbl > sel)
1985 SWAP_INT(sbl, sel);
1986 SWAP_INT(sbc, sec);
1988 if (sbl == sel && sbc > sec)
1989 SWAP_INT(sbc, sec);
1991 if (sbc == sel)
1993 len = es->textptrs[sbl + 1] - es->textptrs[sbl] - 1;
1994 return len - sec - sbc;
1997 len = es->textptrs[sel + 1] - es->textptrs[sel] - sec - 1;
1998 return len + sbc;
2000 else /* no selection marked */
2002 len = es->textptrs[es->CurrLine + 1] - es->textptrs[es->CurrLine] - 1;
2003 return len;
2006 else /* line number specified */
2008 EDIT_GetLineCol(hwnd, wParam, &row, &col);
2009 len = es->textptrs[row + 1] - es->textptrs[row];
2010 return len;
2014 /*********************************************************************
2015 * EM_SETSEL message function
2017 static void EDIT_SetSelMsg(HWND hwnd, WORD wParam, LONG lParam)
2019 INT so, eo;
2020 EDITSTATE *es = EDIT_GetEditState(hwnd);
2022 so = LOWORD(lParam);
2023 eo = HIWORD(lParam);
2025 if (so == -1) /* if so == -1, clear selection */
2027 EDIT_ClearSel(hwnd);
2028 return;
2031 if (so == eo) /* if so == eo, set caret only */
2033 EDIT_GetLineCol(hwnd, (int) so, &(es->CurrLine), &(es->CurrCol));
2034 es->WndRow = es->CurrLine - es->wtop;
2036 if (!wParam)
2038 if (es->WndRow < 0 || es->WndRow > es->ClientHeight)
2040 es->wtop = es->CurrLine;
2041 es->WndRow = 0;
2043 es->WndCol = EDIT_StrWidth(hwnd,
2044 EDIT_TextLine(hwnd, es->CurrLine),
2045 es->CurrCol, 0) - es->wleft;
2046 if (es->WndCol > es->ClientWidth)
2048 es->wleft = es->WndCol;
2049 es->WndCol = 0;
2051 else if (es->WndCol < 0)
2053 es->wleft += es->WndCol;
2054 es->WndCol = 0;
2058 else /* otherwise set selection */
2060 if (eo >= 0 && so > eo) /* eo == -1 flag to extend to end of text */
2062 INT tmp;
2063 tmp = so;
2064 so = eo;
2065 eo = tmp;
2068 EDIT_GetLineCol(hwnd, (int) so, &(es->SelBegLine), &(es->SelBegCol));
2069 EDIT_GetLineCol(hwnd, (int) eo, &(es->SelEndLine), &(es->SelEndCol));
2070 es->CurrLine = es->SelEndLine;
2071 es->CurrCol = es->SelEndCol;
2072 es->WndRow = es->SelEndLine - es->wtop;
2074 if (!wParam) /* don't suppress scrolling of text */
2076 if (es->WndRow < 0)
2078 es->wtop = es->SelEndLine;
2079 es->WndRow = 0;
2081 else if (es->WndRow > es->ClientHeight)
2083 es->wtop += es->WndRow - es->ClientHeight;
2084 es->WndRow = es->ClientHeight;
2086 es->WndCol = EDIT_StrWidth(hwnd,
2087 EDIT_TextLine(hwnd, es->SelEndLine),
2088 es->SelEndCol, 0) - es->wleft;
2089 if (es->WndCol > es->ClientWidth)
2091 es->wleft += es->WndCol - es->ClientWidth;
2092 es->WndCol = es->ClientWidth;
2094 else if (es->WndCol < 0)
2096 es->wleft += es->WndCol;
2097 es->WndCol = 0;
2101 InvalidateRect(hwnd, NULL, TRUE);
2102 UpdateWindow(hwnd);
2106 /*********************************************************************
2107 * WM_SETFONT
2109 static void EDIT_WM_SetFont(HWND hwnd, WORD wParam, LONG lParam)
2111 HDC hdc;
2112 TEXTMETRIC tm;
2113 HFONT oldfont;
2114 EDITSTATE *es = EDIT_GetEditState(hwnd);
2116 es->hFont = wParam;
2117 hdc = GetDC(hwnd);
2118 oldfont = (HFONT)SelectObject(hdc, (HANDLE)es->hFont);
2119 GetCharWidth(hdc, 0, 255, es->CharWidths);
2120 GetTextMetrics(hdc, &tm);
2121 es->txtht = tm.tmHeight + tm.tmExternalLeading;
2122 SelectObject(hdc, (HANDLE)oldfont);
2123 ReleaseDC(hwnd, hdc);
2125 es->WndRow = (es->CurrLine - es->wtop) / es->txtht;
2126 es->WndCol = EDIT_StrWidth(hwnd, EDIT_TextLine(hwnd, es->CurrLine),
2127 es->CurrCol, 0) - es->wleft;
2129 InvalidateRect(hwnd, NULL, TRUE);
2130 es->PaintBkgd = TRUE;
2131 if (lParam) UpdateWindow(hwnd);
2132 EDIT_RecalcSize(hwnd,es);
2135 /*********************************************************************
2136 * WM_PASTE
2138 static void EDIT_WM_Paste(HWND hwnd)
2140 HANDLE hClipMem;
2141 char *lpClipMem;
2143 OpenClipboard(hwnd);
2144 if (!(hClipMem = GetClipboardData(CF_TEXT)))
2146 /* no text in clipboard */
2147 CloseClipboard();
2148 return;
2150 lpClipMem = GlobalLock(hClipMem);
2151 EDIT_InsertText(hwnd, lpClipMem, strlen(lpClipMem));
2152 GlobalUnlock(hClipMem);
2153 CloseClipboard();
2154 InvalidateRect(hwnd, NULL, TRUE);
2155 UpdateWindow(hwnd);
2158 /*********************************************************************
2159 * WM_PAINT
2161 static void EDIT_WM_Paint(HWND hwnd)
2163 PAINTSTRUCT ps;
2164 HDC hdc;
2165 int y;
2166 RECT rc;
2167 EDITSTATE *es = EDIT_GetEditState(hwnd);
2169 hdc = BeginPaint(hwnd, &ps);
2170 rc = ps.rcPaint;
2172 dprintf_edit(stddeb,"WM_PAINT: rc=(%d,%d), (%d,%d)\n", rc.left, rc.top,
2173 rc.right, rc.bottom);
2175 if (es->PaintBkgd)
2176 FillWindow(GetParent(hwnd), hwnd, hdc, CTLCOLOR_EDIT);
2178 for (y = (rc.top / es->txtht); y <= (rc.bottom / es->txtht); y++)
2180 if (y < (IsMultiLine(hwnd) ? es->wlines : 1) - es->wtop)
2181 EDIT_WriteTextLine(hwnd, &rc, y + es->wtop);
2184 EndPaint(hwnd, &ps);
2187 /*********************************************************************
2188 * WM_NCCREATE
2190 static long EDIT_WM_NCCreate(HWND hwnd, LONG lParam)
2192 CREATESTRUCT *createStruct = (CREATESTRUCT *)PTR_SEG_TO_LIN(lParam);
2193 WND *wndPtr = WIN_FindWndPtr(hwnd);
2194 EDITSTATE *es;
2195 char *text;
2197 /* store pointer to local or global heap in window structure so that */
2198 /* EDITSTATE structure itself can be stored on local heap */
2200 /* allocate space for state variable structure */
2201 es = malloc( sizeof(EDITSTATE) );
2202 SetWindowLong( hwnd, 0, (LONG)es );
2203 es->textptrs = malloc(sizeof(int));
2204 es->CharWidths = malloc(256 * sizeof(short));
2205 es->ClientWidth = es->ClientHeight = 1;
2206 /* --- text buffer */
2207 es->MaxTextLen = MAXTEXTLEN + 1;
2208 if (!(createStruct->lpszName))
2210 dprintf_edit( stddeb, "EDIT_WM_NCCREATE: lpszName == 0\n" );
2211 es->textlen = EditBufStartLen(hwnd) + 1;
2212 es->hText = EDIT_HeapAlloc(hwnd, es->textlen + 2, LMEM_MOVEABLE);
2213 text = EDIT_HeapLock(hwnd, es->hText);
2214 memset(text, 0, es->textlen + 2);
2215 es->wlines = 0;
2216 es->textwidth = 0;
2217 EDIT_ClearTextPointers(hwnd);
2218 if (IsMultiLine(hwnd)) strcpy(text, "\r\n");
2219 EDIT_BuildTextPointers(hwnd);
2221 else
2223 char *windowName = (char *)PTR_SEG_TO_LIN( createStruct->lpszName );
2224 dprintf_edit( stddeb, "EDIT_WM_NCCREATE: lpszName != 0\n" );
2225 if (strlen(windowName) < EditBufStartLen(hwnd))
2227 es->textlen = EditBufStartLen(hwnd) + 3;
2228 es->hText = EDIT_HeapAlloc(hwnd, es->textlen + 2, LMEM_MOVEABLE);
2229 text = EDIT_HeapLock(hwnd, es->hText);
2230 strcpy(text, windowName);
2231 if(IsMultiLine(hwnd)) {
2232 strcat(text, "\r\n");
2234 *(text + es->textlen) = '\0';
2236 else
2238 es->textlen = strlen(windowName) + 3;
2239 es->hText = EDIT_HeapAlloc(hwnd, es->textlen + 2, LMEM_MOVEABLE);
2240 text = EDIT_HeapLock(hwnd, es->hText);
2241 strcpy(text, windowName);
2242 if(IsMultiLine(hwnd)) strcat(text, "\r\n");
2243 *(text + es->textlen) = '\0';
2245 *(text + es->textlen + 1) = '\0';
2246 EDIT_BuildTextPointers(hwnd);
2249 /* ES_AUTOVSCROLL and ES_AUTOHSCROLL are automatically applied if */
2250 /* the corresponding WS_* style is set */
2251 if (createStruct->style & WS_VSCROLL)
2252 wndPtr->dwStyle |= ES_AUTOVSCROLL;
2253 if (createStruct->style & WS_HSCROLL)
2254 wndPtr->dwStyle |= ES_AUTOHSCROLL;
2256 /* remove the WS_CAPTION style if it has been set - this is really a */
2257 /* pseudo option made from a combination of WS_BORDER and WS_DLGFRAME */
2258 if (wndPtr->dwStyle & WS_BORDER && wndPtr->dwStyle & WS_DLGFRAME)
2259 wndPtr->dwStyle ^= WS_DLGFRAME;
2261 return 1;
2264 /*********************************************************************
2265 * WM_CREATE
2267 static long EDIT_WM_Create(HWND hwnd, LONG lParam)
2269 HDC hdc;
2270 EDITSTATE *es = EDIT_GetEditState(hwnd);
2271 CLASS *classPtr;
2272 TEXTMETRIC tm;
2274 /* initialize state variable structure */
2275 hdc = GetDC(hwnd);
2277 /* --- char width array */
2278 /* only initialise chars <= 32 as X returns strange widths */
2279 /* for other chars */
2280 memset(es->CharWidths, 0, 256 * sizeof(short));
2281 GetCharWidth(hdc, 32, 254, &es->CharWidths[32]);
2283 /* --- other structure variables */
2284 GetTextMetrics(hdc, &tm);
2285 es->txtht = tm.tmHeight + tm.tmExternalLeading;
2286 EDIT_RecalcSize(hwnd,es);
2287 es->wtop = es->wleft = 0;
2288 es->CurrCol = es->CurrLine = 0;
2289 es->WndCol = es->WndRow = 0;
2290 es->TextChanged = FALSE;
2291 es->SelBegLine = es->SelBegCol = 0;
2292 es->SelEndLine = es->SelEndCol = 0;
2293 es->hFont = 0;
2294 es->hDeletedText = 0;
2295 es->DeletedLength = 0;
2296 es->NumTabStops = 0;
2297 es->TabStops = malloc( sizeof(short) );
2299 /* allocate space for a line full of blanks to speed up */
2300 /* line filling */
2301 es->BlankLine = malloc( (es->ClientWidth / es->CharWidths[32]) + 2);
2302 memset(es->BlankLine, ' ', (es->ClientWidth / es->CharWidths[32]) + 2);
2303 es->BlankLine[(es->ClientWidth / es->CharWidths[32]) + 1] = 0;
2305 /* set up text cursor for edit class */
2306 CLASS_FindClassByName("EDIT", 0, &classPtr);
2307 classPtr->wc.hCursor = LoadCursor(0, IDC_IBEAM);
2309 /* paint background on first WM_PAINT */
2310 es->PaintBkgd = TRUE;
2312 ReleaseDC(hwnd, hdc);
2313 return 0L;
2316 /*********************************************************************
2317 * WM_VSCROLL
2319 static void EDIT_WM_VScroll(HWND hwnd, WORD wParam, LONG lParam)
2321 EDITSTATE *es = EDIT_GetEditState(hwnd);
2323 if (IsMultiLine(hwnd))
2325 HideCaret(hwnd);
2327 switch (wParam)
2329 case SB_LINEUP:
2330 case SB_LINEDOWN:
2331 EDIT_VScrollLine(hwnd, wParam);
2332 break;
2334 case SB_PAGEUP:
2335 case SB_PAGEDOWN:
2336 EDIT_VScrollPage(hwnd, wParam);
2337 break;
2341 SetCaretPos(es->WndCol, es->WndRow);
2342 ShowCaret(hwnd);
2345 /*********************************************************************
2346 * WM_HSCROLL
2348 static void EDIT_WM_HScroll(HWND hwnd, WORD wParam, LONG lParam)
2350 EDITSTATE *es = EDIT_GetEditState(hwnd);
2352 switch (wParam)
2354 case SB_LINEUP:
2355 case SB_LINEDOWN:
2356 HideCaret(hwnd);
2358 SetCaretPos(es->WndCol, es->WndRow * es->txtht);
2359 ShowCaret(hwnd);
2360 break;
2364 /*********************************************************************
2365 * WM_SIZE
2367 static void EDIT_WM_Size(HWND hwnd, WORD wParam, LONG lParam)
2369 EDITSTATE *es = EDIT_GetEditState(hwnd);
2371 EDIT_RecalcSize(hwnd,es);
2372 if (wParam != SIZE_MAXIMIZED && wParam != SIZE_RESTORED) return;
2373 InvalidateRect(hwnd, NULL, TRUE);
2374 es->PaintBkgd = TRUE;
2375 UpdateWindow(hwnd);
2378 /*********************************************************************
2379 * WM_LBUTTONDOWN
2381 static void EDIT_WM_LButtonDown(HWND hwnd, WORD wParam, LONG lParam)
2383 char *cp;
2384 int len;
2385 BOOL end = FALSE;
2386 EDITSTATE *es = EDIT_GetEditState(hwnd);
2388 if (SelMarked(es))
2389 EDIT_ClearSel(hwnd);
2391 es->WndRow = HIWORD(lParam) / es->txtht;
2392 dprintf_edit( stddeb, "EDIT_LButtonDown: %04x %08lx, WndRow %d\n", wParam,
2393 lParam, es->WndRow );
2394 if (!IsMultiLine(hwnd)) es->WndRow = 0;
2395 else if (es->WndRow > es->wlines - es->wtop - 1)
2397 es->WndRow = es->wlines - es->wtop - 1;
2398 end = TRUE;
2400 es->CurrLine = es->wtop + es->WndRow;
2402 cp = EDIT_TextLine(hwnd, es->CurrLine);
2403 len = EDIT_LineLength(hwnd, es->CurrLine);
2404 es->WndCol = LOWORD(lParam) + es->wleft;
2405 if (end || es->WndCol > EDIT_StrWidth(hwnd, cp, len, 0))
2406 es->WndCol = EDIT_StrWidth(hwnd, cp, len, 0);
2407 dprintf_edit( stddeb, "EDIT_LButtonDown: CurrLine %d wtop %d wndcol %d\n",
2408 es->CurrLine, es->wtop, es->WndCol);
2409 es->CurrCol = EDIT_PixelToChar(hwnd, es->CurrLine, &(es->WndCol));
2410 es->WndCol -= es->wleft;
2412 ButtonDown = TRUE;
2413 ButtonRow = es->CurrLine;
2414 ButtonCol = es->CurrCol;
2417 /*********************************************************************
2418 * WM_MOUSEMOVE
2420 static void EDIT_WM_MouseMove(HWND hwnd, WORD wParam, LONG lParam)
2422 EDITSTATE *es = EDIT_GetEditState(hwnd);
2424 if (wParam != MK_LBUTTON)
2425 return;
2427 HideCaret(hwnd);
2428 if (ButtonDown)
2430 EDIT_SetAnchor(hwnd, ButtonRow, ButtonCol);
2431 TextMarking = TRUE;
2432 ButtonDown = FALSE;
2435 if (TextMarking)
2437 EDIT_ExtendSel(hwnd, LOWORD(lParam), HIWORD(lParam));
2438 SetCaretPos(es->WndCol, es->WndRow * es->txtht);
2440 ShowCaret(hwnd);
2443 /*********************************************************************
2444 * WM_CHAR
2446 static void EDIT_WM_Char(HWND hwnd, WORD wParam)
2448 dprintf_edit(stddeb,"EDIT_WM_Char: wParam=%c\n", (char)wParam);
2450 switch (wParam)
2452 case '\r':
2453 case '\n':
2454 if (!IsMultiLine(hwnd))
2455 break;
2456 wParam = '\n';
2457 EDIT_KeyTyped(hwnd, wParam);
2458 break;
2460 case VK_TAB:
2461 if (!IsMultiLine(hwnd))
2462 break;
2463 EDIT_KeyTyped(hwnd, wParam);
2464 break;
2466 default:
2467 if (wParam >= 20 && wParam <= 254 && wParam != 127 )
2468 EDIT_KeyTyped(hwnd, wParam);
2469 break;
2473 /*********************************************************************
2474 * WM_KEYDOWN
2476 static void EDIT_WM_KeyDown(HWND hwnd, WORD wParam)
2478 EDITSTATE *es = EDIT_GetEditState(hwnd);
2480 dprintf_edit(stddeb,"EDIT_WM_KeyDown: key=%x\n", wParam);
2482 HideCaret(hwnd);
2483 switch (wParam)
2485 case VK_UP:
2486 if (SelMarked(es))
2487 EDIT_ClearSel(hwnd);
2488 if (IsMultiLine(hwnd))
2489 EDIT_Upward(hwnd);
2490 else
2491 EDIT_Backward(hwnd);
2492 break;
2494 case VK_DOWN:
2495 if (SelMarked(es))
2496 EDIT_ClearSel(hwnd);
2497 if (IsMultiLine(hwnd))
2498 EDIT_Downward(hwnd);
2499 else
2500 EDIT_Forward(hwnd);
2501 break;
2503 case VK_RIGHT:
2504 if (SelMarked(es))
2505 EDIT_ClearSel(hwnd);
2506 EDIT_Forward(hwnd);
2507 break;
2509 case VK_LEFT:
2510 if (SelMarked(es))
2511 EDIT_ClearSel(hwnd);
2512 EDIT_Backward(hwnd);
2513 break;
2515 case VK_HOME:
2516 if (SelMarked(es))
2517 EDIT_ClearSel(hwnd);
2518 EDIT_Home(hwnd);
2519 break;
2521 case VK_END:
2522 if (SelMarked(es))
2523 EDIT_ClearSel(hwnd);
2524 EDIT_End(hwnd);
2525 break;
2527 case VK_PRIOR:
2528 if (IsMultiLine(hwnd))
2530 if (SelMarked(es))
2531 EDIT_ClearSel(hwnd);
2532 EDIT_KeyVScrollPage(hwnd, SB_PAGEUP);
2534 break;
2536 case VK_NEXT:
2537 if (IsMultiLine(hwnd))
2539 if (SelMarked(es))
2540 EDIT_ClearSel(hwnd);
2541 EDIT_KeyVScrollPage(hwnd, SB_PAGEDOWN);
2543 break;
2545 case VK_BACK:
2546 if (SelMarked(es))
2547 EDIT_DeleteSel(hwnd);
2548 else
2550 if (es->CurrCol == 0 && es->CurrLine == 0)
2551 break;
2552 EDIT_Backward(hwnd);
2553 EDIT_DelKey(hwnd);
2555 break;
2557 case VK_DELETE:
2558 if (SelMarked(es))
2559 EDIT_DeleteSel(hwnd);
2560 else
2561 EDIT_DelKey(hwnd);
2562 break;
2565 SetCaretPos(es->WndCol, es->WndRow * es->txtht);
2566 ShowCaret(hwnd);
2569 /*********************************************************************
2570 * WM_SETTEXT
2572 static LONG EDIT_WM_SetText(HWND hwnd, LONG lParam)
2574 int len;
2575 char *text,*settext;
2576 EDITSTATE *es = EDIT_GetEditState(hwnd);
2578 settext = PTR_SEG_TO_LIN( lParam );
2579 dprintf_edit( stddeb,"WM_SetText, length %d\n",strlen(settext) );
2580 if (strlen(settext) <= es->MaxTextLen)
2582 len = settext != NULL ? strlen(settext) : 0;
2583 EDIT_ClearText(hwnd);
2584 es->textlen = len;
2585 dprintf_edit( stddeb, "EDIT_WM_SetText: realloc\n" );
2586 es->hText = EDIT_HeapReAlloc(hwnd, es->hText, len + 3);
2587 text = EDIT_HeapLock(hwnd, es->hText);
2588 if (lParam)
2589 strcpy(text, (char *)PTR_SEG_TO_LIN(lParam));
2590 text[len] = '\0';
2591 text[len + 1] = '\0';
2592 text[len + 2] = '\0';
2593 EDIT_BuildTextPointers(hwnd);
2594 InvalidateRect(hwnd, NULL, TRUE);
2595 es->PaintBkgd = TRUE;
2596 es->TextChanged = TRUE;
2597 return 0;
2599 else
2600 return EN_ERRSPACE;
2603 /*********************************************************************
2604 * EditWndProc()
2606 LONG EditWndProc(HWND hwnd, WORD uMsg, WORD wParam, LONG lParam)
2608 LONG lResult = 0;
2609 char *textPtr;
2610 int len;
2611 EDITSTATE *es = EDIT_GetEditState(hwnd);
2613 switch (uMsg) {
2614 case EM_CANUNDO:
2615 lResult = es->hDeletedText;
2616 break;
2618 case EM_EMPTYUNDOBUFFER:
2619 EDIT_ClearDeletedText(hwnd);
2620 break;
2622 case EM_FMTLINES:
2623 fprintf(stdnimp,"edit: EM_FMTLINES message received\n");
2624 if (!wParam)
2625 lResult = 1L;
2626 else
2627 lResult = 0L;
2628 break;
2630 case EM_GETFIRSTVISIBLELINE:
2631 lResult = es->wtop;
2632 break;
2634 case EM_GETHANDLE:
2635 lResult = es->hText;
2636 break;
2638 case EM_GETLINE:
2639 if (IsMultiLine(hwnd))
2640 lResult = EDIT_GetLineMsg(hwnd, wParam, lParam);
2641 else
2642 lResult = 0L;
2643 break;
2645 case EM_GETLINECOUNT:
2646 if (IsMultiLine(hwnd))
2647 lResult = es->wlines;
2648 else
2649 lResult = 0L;
2650 break;
2652 case EM_GETMODIFY:
2653 lResult = es->TextChanged;
2654 break;
2656 case EM_GETPASSWORDCHAR:
2657 fprintf(stdnimp,"edit: cannot process EM_GETPASSWORDCHAR message\n");
2658 break;
2660 case EM_GETRECT:
2661 GetWindowRect(hwnd, (LPRECT)PTR_SEG_TO_LIN(lParam));
2662 break;
2664 case EM_GETSEL:
2665 lResult = EDIT_GetSelMsg(hwnd);
2666 break;
2668 case EM_GETWORDBREAKPROC:
2669 fprintf(stdnimp,"edit: cannot process EM_GETWORDBREAKPROC message\n");
2670 break;
2672 case EM_LIMITTEXT:
2673 if (wParam)
2674 es->MaxTextLen = wParam;
2675 else if (IsMultiLine(hwnd))
2676 es->MaxTextLen = 65535;
2677 else
2678 es->MaxTextLen = 32767;
2679 break;
2681 case EM_LINEFROMCHAR:
2682 lResult = EDIT_LineFromCharMsg(hwnd, wParam);
2683 break;
2685 case EM_LINEINDEX:
2686 if (IsMultiLine(hwnd))
2687 lResult = EDIT_LineIndexMsg(hwnd, wParam);
2688 else
2689 lResult = 0L;
2690 break;
2692 case EM_LINELENGTH:
2693 lResult = EDIT_LineLengthMsg(hwnd, wParam);
2694 break;
2696 case EM_LINESCROLL:
2697 fprintf(stdnimp,"edit: cannot process EM_LINESCROLL message\n");
2698 break;
2700 case EM_REPLACESEL:
2701 HideCaret(hwnd);
2702 EDIT_ReplaceSel(hwnd, lParam);
2703 SetCaretPos(es->WndCol, es->WndRow * es->txtht);
2704 ShowCaret(hwnd);
2705 break;
2707 case EM_SETHANDLE:
2708 HideCaret(hwnd);
2709 EDIT_SetHandleMsg(hwnd, wParam);
2710 SetCaretPos(es->WndCol, es->WndRow * es->txtht);
2711 ShowCaret(hwnd);
2712 break;
2714 case EM_SETMODIFY:
2715 es->TextChanged = wParam;
2716 break;
2718 case EM_SETPASSWORDCHAR:
2719 fprintf(stdnimp,"edit: cannot process EM_SETPASSWORDCHAR message\n");
2720 break;
2722 case EM_SETREADONLY:
2723 fprintf(stdnimp,"edit: cannot process EM_SETREADONLY message\n");
2724 break;
2726 case EM_SETRECT:
2727 case EM_SETRECTNP:
2728 fprintf(stdnimp,"edit: cannot process EM_SETRECT(NP) message\n");
2729 break;
2731 case EM_SETSEL:
2732 HideCaret(hwnd);
2733 EDIT_SetSelMsg(hwnd, wParam, lParam);
2734 SetCaretPos(es->WndCol, es->WndRow * es->txtht);
2735 ShowCaret(hwnd);
2736 break;
2738 case EM_SETTABSTOPS:
2739 lResult = EDIT_SetTabStopsMsg(hwnd, wParam, lParam);
2740 break;
2742 case EM_SETWORDBREAKPROC:
2743 fprintf(stdnimp,"edit: cannot process EM_SETWORDBREAKPROC message\n");
2744 break;
2746 case EM_UNDO:
2747 HideCaret(hwnd);
2748 lResult = EDIT_UndoMsg(hwnd);
2749 SetCaretPos(es->WndCol, es->WndRow * es->txtht);
2750 ShowCaret(hwnd);
2751 break;
2753 case WM_GETDLGCODE:
2754 return DLGC_HASSETSEL | DLGC_WANTCHARS | DLGC_WANTARROWS;
2756 case WM_CHAR:
2757 EDIT_WM_Char(hwnd, wParam);
2758 break;
2760 case WM_COPY:
2761 EDIT_CopyToClipboard(hwnd);
2762 EDIT_ClearSel(hwnd);
2763 break;
2765 case WM_CREATE:
2766 lResult = EDIT_WM_Create(hwnd, lParam);
2767 break;
2769 case WM_CUT:
2770 EDIT_CopyToClipboard(hwnd);
2771 EDIT_DeleteSel(hwnd);
2772 break;
2774 case WM_DESTROY:
2775 free(es->textptrs);
2776 free(es->CharWidths);
2777 free(es->TabStops);
2778 free(es->BlankLine);
2779 EDIT_HeapFree(hwnd, es->hText);
2780 free( EDIT_GetEditState(hwnd) );
2781 break;
2783 case WM_ENABLE:
2784 InvalidateRect(hwnd, NULL, FALSE);
2785 break;
2787 case WM_GETTEXT:
2788 textPtr = EDIT_HeapLock(hwnd, es->hText);
2789 len = strlen( textPtr );
2790 if ((int)wParam > len)
2792 strcpy((char *)PTR_SEG_TO_LIN(lParam), textPtr);
2793 lResult = (DWORD)len ;
2795 else
2796 lResult = 0L;
2797 EDIT_HeapUnlock(hwnd, es->hText);
2798 break;
2800 case WM_GETTEXTLENGTH:
2801 textPtr = EDIT_HeapLock(hwnd, es->hText);
2802 lResult = (DWORD)strlen(textPtr);
2803 EDIT_HeapUnlock(hwnd, es->hText);
2804 break;
2806 case WM_HSCROLL:
2807 EDIT_WM_HScroll(hwnd, wParam, lParam);
2808 break;
2810 case WM_KEYDOWN:
2811 EDIT_WM_KeyDown(hwnd, wParam);
2812 break;
2814 case WM_KILLFOCUS:
2815 es->HaveFocus = FALSE;
2816 DestroyCaret();
2817 if (SelMarked(es)) EDIT_ClearSel(hwnd);
2818 NOTIFY_PARENT(hwnd, EN_KILLFOCUS);
2819 break;
2821 case WM_LBUTTONDOWN:
2822 HideCaret(hwnd);
2823 SetFocus(hwnd);
2824 SetCapture(hwnd);
2825 EDIT_WM_LButtonDown(hwnd, wParam, lParam);
2826 SetCaretPos(es->WndCol, es->WndRow * es->txtht);
2827 ShowCaret(hwnd);
2828 break;
2830 case WM_LBUTTONUP:
2831 if (GetCapture() != hwnd) break;
2832 ReleaseCapture();
2833 ButtonDown = FALSE;
2834 if (TextMarking)
2835 EDIT_StopMarking(hwnd);
2836 break;
2838 case WM_MOUSEMOVE:
2839 if (es->HaveFocus)
2840 EDIT_WM_MouseMove(hwnd, wParam, lParam);
2841 break;
2843 case WM_MOVE:
2844 lResult = 0;
2845 break;
2847 case WM_NCCREATE:
2848 lResult = EDIT_WM_NCCreate(hwnd, lParam);
2849 break;
2851 case WM_PAINT:
2852 EDIT_WM_Paint(hwnd);
2853 break;
2855 case WM_PASTE:
2856 EDIT_WM_Paste(hwnd);
2857 break;
2859 case WM_SETFOCUS:
2860 es->HaveFocus = TRUE;
2861 CreateCaret(hwnd, 0, 2, es->txtht);
2862 SetCaretPos(es->WndCol, es->WndRow * es->txtht);
2863 ShowCaret(hwnd);
2864 NOTIFY_PARENT(hwnd, EN_SETFOCUS);
2865 break;
2867 case WM_SETFONT:
2868 HideCaret(hwnd);
2869 EDIT_WM_SetFont(hwnd, wParam, lParam);
2870 SetCaretPos(es->WndCol, es->WndRow * es->txtht);
2871 ShowCaret(hwnd);
2872 break;
2873 #if 0
2874 case WM_SETREDRAW:
2875 dprintf_edit(stddeb, "WM_SETREDRAW: hwnd=%d, wParam=%x\n",
2876 hwnd, wParam);
2877 lResult = 0;
2878 break;
2879 #endif
2880 case WM_SETTEXT:
2881 EDIT_WM_SetText(hwnd, lParam);
2882 break;
2884 case WM_SIZE:
2885 EDIT_WM_Size(hwnd, wParam, lParam);
2886 lResult = 0;
2887 break;
2889 case WM_VSCROLL:
2890 EDIT_WM_VScroll(hwnd, wParam, lParam);
2891 break;
2893 default:
2894 lResult = DefWindowProc(hwnd, uMsg, wParam, lParam);
2895 break;
2898 return lResult;