summaryrefslogtreecommitdiffstats
path: root/private/mvdm/wow16/user/editsl.c
diff options
context:
space:
mode:
Diffstat (limited to 'private/mvdm/wow16/user/editsl.c')
-rw-r--r--private/mvdm/wow16/user/editsl.c1785
1 files changed, 1785 insertions, 0 deletions
diff --git a/private/mvdm/wow16/user/editsl.c b/private/mvdm/wow16/user/editsl.c
new file mode 100644
index 000000000..285f322ad
--- /dev/null
+++ b/private/mvdm/wow16/user/editsl.c
@@ -0,0 +1,1785 @@
+/*++
+ *
+ * WOW v1.0
+ *
+ * Copyright (c) 1991, Microsoft Corporation
+ *
+ * EDITSL.C
+ * Win16 edit control code
+ *
+ * History:
+ *
+ * Created 28-May-1991 by Jeff Parsons (jeffpar)
+ * Copied from WIN31 and edited (as little as possible) for WOW16.
+--*/
+
+/****************************************************************************/
+/* editsl.c - Edit controls rewrite. Version II of edit controls. */
+/* */
+/* */
+/* Created: 24-Jul-88 davidds */
+/****************************************************************************/
+
+#define NO_LOCALOBJ_TAGS
+#include "user.h"
+#include "edit.h"
+
+/****************************************************************************/
+/* Single Line Support Routines */
+/****************************************************************************/
+
+void FAR PASCAL SLSetCaretPosition(ped,hdc)
+register PED ped;
+HDC hdc;
+/* effects: If the window has the focus, find where the caret belongs and move
+ * it there.
+ */
+{
+ int xPosition;
+ /* We will only position the caret if we have the focus since we don't want
+ * to move the caret while another window could own it.
+ */
+ if (ped->fNoRedraw || !ped->fFocus)
+ return;
+
+ xPosition = SLIchToLeftXPos(ped, hdc, ped->ichCaret);
+ if (!ped->fAutoHScroll)
+ /* Don't leet caret go out of bounds of edit contol if there is too much
+ * text in a non scrolling edit control.
+ */
+ xPosition = min(xPosition, ped->rcFmt.right-1);
+
+ SetCaretPos(xPosition, ped->rcFmt.top);
+}
+
+
+int NEAR PASCAL SLIchToLeftXPos(ped, hdc, ich)
+register PED ped;
+HDC hdc;
+ICH ich;
+/* effects: Given a character index, find its (left side) x coordinate within
+ * the ped->rcFmt rectangle assuming the character ped->screenStart is at
+ * coordinates (ped->rcFmt.top, ped->rcFmt.left). A negative value is
+ * returned if the character ich is to the left of ped->screenStart. WARNING:
+ * ASSUMES AT MOST 1000 characters will be VISIBLE at one time on the screen.
+ * There may be 64K total characters in the editcontrol, but we can only
+ * display 1000 without scrolling. This shouldn't be a problem obviously.
+ */
+{
+ int textExtent;
+ register PSTR pText;
+
+ /* Check if we are adding lots and lots of chars. A paste for example could
+ * cause this and GetTextExtents could overflow on this.
+ */
+ if (ich > ped->screenStart && ich - ped->screenStart > 1000)
+ return(30000);
+ if (ped->screenStart > ich && ped->screenStart - ich > 1000)
+ return(-30000);
+
+ if (ped->fNonPropFont)
+ return((ich-ped->screenStart)*ped->aveCharWidth + ped->rcFmt.left);
+
+ /* Check if password hidden chars are being used. */
+ if (ped->charPasswordChar)
+ return((ich-ped->screenStart)*ped->cPasswordCharWidth+ped->rcFmt.left);
+
+ pText = LocalLock(ped->hText);
+
+ if (ped->screenStart <= ich)
+ {
+ textExtent = LOWORD(GetTextExtent(hdc,
+ (LPSTR)(pText + ped->screenStart),
+ ich-ped->screenStart));
+ /* In case of signed/unsigned overflow since the text extent may be
+ * greater than maxint. This happens with long single line edit
+ * controls. The rect we edit text in will never be greater than 30000
+ * pixels so we are ok if we just ignore them.
+ */
+ if (textExtent < 0 || textExtent > 31000)
+ textExtent = 30000;
+ }
+ else
+ textExtent = (-1) *
+ (int)LOWORD(GetTextExtent(hdc,(LPSTR)(pText + ich),
+ ped->screenStart-ich));
+
+ LocalUnlock(ped->hText);
+
+ return(textExtent-ped->charOverhang + ped->rcFmt.left);
+}
+
+/* effects: This finds out if the given ichPos falls within the current
+ * Selection range and if so returns TRUE; Else returns FALSE.
+ */
+BOOL NEAR PASCAL SLGetHiliteAttr(PED ped, ICH ichPos)
+{
+ return((ichPos >= ped->ichMinSel) && (ichPos < ped->ichMaxSel));
+}
+
+/* effects: This takes care of erasing the old selection and drawing the new
+ * selection
+ */
+void NEAR PASCAL SLRepaintChangedSelection(
+ PED ped, HDC hdc,
+ ICH ichOldMinSel, ICH ichOldMaxSel)
+{
+ BLOCK Blk[2];
+ int i;
+
+ Blk[0].StPos = ichOldMinSel;
+ Blk[0].EndPos = ichOldMaxSel;
+ Blk[1].StPos = ped->ichMinSel;
+ Blk[1].EndPos = ped->ichMaxSel;
+
+ if(ECCalcChangeSelection(ped, ichOldMinSel, ichOldMaxSel,
+ (LPBLOCK)&Blk[0], (LPBLOCK)&Blk[1]))
+ {
+ UpdateWindow(ped->hwnd);
+ /* Paint the rectangles where selection has changed */
+ /* Paint both Blk[0] and Blk[1], if they exist */
+ for(i = 0; i < 2; i++)
+ {
+ if (Blk[i].StPos != -1)
+ SLDrawLine(ped, hdc, Blk[i].StPos, Blk[i].EndPos - Blk[i].StPos,
+ SLGetHiliteAttr(ped, Blk[i].StPos));
+ }
+ }
+}
+
+
+void FAR PASCAL SLChangeSelection(ped, hdc, ichNewMinSel, ichNewMaxSel)
+register PED ped;
+HDC hdc;
+ICH ichNewMinSel;
+ICH ichNewMaxSel;
+/* effects: Changes the current selection to have the specified starting and
+ * ending values. Properly highlights the new selection and unhighlights
+ * anything deselected. If NewMinSel and NewMaxSel are out of order, we swap
+ * them. Doesn't update the caret position.
+ */
+{
+ ICH temp;
+ ICH ichOldMinSel;
+ ICH ichOldMaxSel;
+
+ if (ichNewMinSel > ichNewMaxSel)
+ {
+ temp = ichNewMinSel;
+ ichNewMinSel = ichNewMaxSel;
+ ichNewMaxSel = temp;
+ }
+ ichNewMinSel = umin(ichNewMinSel, ped->cch);
+ ichNewMaxSel = umin(ichNewMaxSel, ped->cch);
+
+ /* Preserve the Old selection */
+ ichOldMinSel = ped->ichMinSel;
+ ichOldMaxSel = ped->ichMaxSel;
+
+ /* Set new selection */
+ ped->ichMinSel = ichNewMinSel;
+ ped->ichMaxSel = ichNewMaxSel;
+
+ /* We will find the intersection of current selection rectangle with the new
+ * selection rectangle. We will then invert the parts of the two rectangles
+ * not in the intersection.
+ */
+
+ if (!ped->fNoRedraw && (ped->fFocus || ped->fNoHideSel))
+ {
+ if (ped->fFocus)
+ HideCaret(ped->hwnd);
+ SLRepaintChangedSelection(ped, hdc, ichOldMinSel, ichOldMaxSel);
+ SLSetCaretPosition(ped,hdc);
+ if (ped->fFocus)
+ ShowCaret(ped->hwnd);
+ }
+}
+
+
+void NEAR PASCAL SLDrawLine(ped, hdc, ichStart, iCount, fSelStatus)
+
+register PED ped;
+register HDC hdc;
+ICH ichStart;
+int iCount;
+BOOL fSelStatus;
+
+/* This draws the line starting from ichStart, iCount number of characters;
+ * fSelStatus is TRUE, if it is to be drawn with the "selection" attribute.
+ */
+{
+ RECT rc;
+ HBRUSH hBrush;
+ PSTR pText;
+ DWORD rgbSaveBk;
+ DWORD rgbSaveText;
+ int iStCount;
+ DWORD rgbGray=0;
+
+ if (ped->fNoRedraw)
+ return;
+
+ if (ichStart < ped->screenStart)
+ {
+ if (ichStart+iCount < ped->screenStart)
+ return;
+
+ iCount = iCount - (ped->screenStart-ichStart);
+ ichStart = ped->screenStart;
+ }
+
+ CopyRect((LPRECT)&rc,(LPRECT)&ped->rcFmt);
+
+ /* Set the proper clipping rectangle */
+ ECSetEditClip(ped, hdc);
+
+ pText = (PSTR) LocalLock(ped->hText);
+
+ /* Calculates the rectangle area to be wiped out */
+ if (iStCount = ichStart - ped->screenStart)
+ {
+ if (ped->charPasswordChar)
+ rc.left += ped->cPasswordCharWidth * iStCount;
+ else
+ rc.left += LOWORD(GetTextExtent(hdc,
+ (LPSTR)(pText + ped->screenStart),
+ iStCount)) -
+ ped->charOverhang;
+ }
+
+ if (ped->charPasswordChar)
+ rc.right = rc.left + ped->cPasswordCharWidth * iCount;
+ else
+ rc.right = rc.left + LOWORD(GetTextExtent(hdc,
+ (LPSTR)(pText + ichStart),
+ iCount));
+ /* Set the background mode before calling GetControlBrush so that the app
+ * can change it to TRANSPARENT if it wants to.
+ */
+ SetBkMode(hdc, OPAQUE);
+
+ if (fSelStatus)
+ {
+ hBrush = ped->hbrHiliteBk;
+ rgbSaveBk = SetBkColor(hdc, ped->rgbHiliteBk);
+ rgbSaveText = SetTextColor(hdc, ped->rgbHiliteText);
+ }
+ else
+ {
+ /* We always want to send this so that the app has a chance to muck with
+ * the DC
+ */
+ hBrush = GetControlBrush(ped->hwnd, hdc, CTLCOLOR_EDIT);
+ }
+
+ if (ped->fDisabled &&
+ (rgbGray = GetSysColor(COLOR_GRAYTEXT)))
+ {
+ /* Grey the text in the edit control if disabled.
+ */
+ rgbSaveText = SetTextColor(hdc, rgbGray);
+ }
+
+ /* Erase the rectangular area before text is drawn. Note that we inflate the
+ * rect by 1 so that the selection color has a one pixel border around the
+ * text.
+ */
+ InflateRect((LPRECT)&rc, 0, 1);
+ /* Use paint rect so that the brush gets aligned if dithered.
+ */
+ PaintRect(ped->hwndParent, ped->hwnd, hdc, hBrush, (LPRECT)&rc);
+ InflateRect((LPRECT)&rc, 0, -1);
+
+ if (ped->charPasswordChar)
+ {
+ for (iStCount = 0; iStCount < iCount; iStCount++)
+ TextOut(hdc,
+ rc.left+iStCount*ped->cPasswordCharWidth,
+ rc.top,
+ (LPSTR)&ped->charPasswordChar,
+ 1);
+ }
+ else
+ TextOut(hdc,rc.left,rc.top,(LPSTR)(pText+ichStart),iCount);
+
+ if (fSelStatus || rgbGray)
+ {
+ SetTextColor(hdc, rgbSaveText);
+ if (fSelStatus)
+ SetBkColor(hdc, rgbSaveBk);
+
+ }
+
+ LocalUnlock(ped->hText);
+}
+
+int NEAR PASCAL SLGetBlkEnd(ped, ichStart, ichEnd, lpfStatus)
+register PED ped;
+register ICH ichStart;
+ICH ichEnd;
+BOOL FAR *lpfStatus;
+/* Given a Starting point and and end point, this function returns whether the
+ * first few characters fall inside or outside the selection block and if so,
+ * howmany characters?
+ */
+{
+ *lpfStatus = FALSE;
+ if (ichStart >= ped->ichMinSel)
+ {
+ if(ichStart >= ped->ichMaxSel)
+ return(ichEnd - ichStart);
+ *lpfStatus = TRUE;
+ return(min(ichEnd, ped->ichMaxSel) - ichStart);
+ }
+ return(min(ichEnd, ped->ichMinSel) - ichStart);
+}
+
+void NEAR PASCAL SLDrawText(ped, hdc, ichStart)
+register PED ped;
+register HDC hdc;
+ICH ichStart;
+/* effects: Draws text for a single line edit control in the rectangle
+ * specified by ped->rcFmt. If ichStart == 0, starts drawing text at the left
+ * side of the window starting at character index ped->screenStart and draws
+ * as much as will fit. If ichStart > 0, then it appends the characters
+ * starting at ichStart to the end of the text showing in the window. (ie. We
+ * are just growing the text length and keeping the left side
+ * (ped->screenStart to ichStart characters) the same. Assumes the hdc came
+ * from ECGetEditDC so that the caret and such are properly hidden.
+ */
+{
+ ICH cchToDraw;
+ RECT rc;
+
+ PSTR pText;
+ BOOL fSelStatus;
+ int iCount;
+ ICH ichEnd;
+ BOOL fNoSelection;
+
+ if (ped->fNoRedraw)
+ return;
+
+ if (ichStart == 0)
+ ichStart = ped->screenStart;
+
+ CopyRect((LPRECT)&rc,(LPRECT)&ped->rcFmt);
+
+ /* Find out how many characters will fit on the screen so that we don't do
+ * any needless drawing.
+ */
+
+ pText = (PSTR) LocalLock(ped->hText);
+
+ cchToDraw = ECCchInWidth(ped, hdc,
+ (LPSTR)(pText+ped->screenStart),
+ ped->cch-ped->screenStart,
+ rc.right - rc.left);
+ ichEnd = ped->screenStart + cchToDraw;
+
+ /*
+ * There is no selection if,
+ * 1. MinSel and MaxSel are equal OR
+ * 2. (This has lost the focus AND Selection is to be hidden)
+ */
+ fNoSelection = ((ped->ichMinSel == ped->ichMaxSel) ||
+ (!ped->fFocus && !ped->fNoHideSel));
+ while (ichStart < ichEnd)
+ {
+ if (fNoSelection)
+ {
+ fSelStatus = FALSE;
+ iCount = ichEnd - ichStart;
+ }
+ else
+ iCount = SLGetBlkEnd(ped, ichStart, ichEnd,
+ (BOOL FAR *)&fSelStatus);
+
+ SLDrawLine(ped, hdc, ichStart, iCount, fSelStatus);
+ ichStart += iCount;
+ }
+
+ if (cchToDraw)
+ {
+ /* Check if password hidden chars are being used. */
+ if (ped->charPasswordChar)
+ rc.left += ped->cPasswordCharWidth * cchToDraw;
+ else
+ rc.left += LOWORD(GetTextExtent(hdc,
+ (LPSTR)(pText + ped->screenStart), cchToDraw));
+ }
+
+ LocalUnlock(ped->hText);
+
+ /* Check if anything to be erased on the right hand side */
+ if (rc.left < rc.right)
+ {
+ SetBkMode(hdc, OPAQUE);
+ /* Erase the rectangular area before text is drawn. Note that we inflate
+ * the rect by 1 so that the selection color has a one pixel border
+ * around the text.
+ */
+ InflateRect((LPRECT)&rc, 0, 1);
+ PaintRect(ped->hwndParent, ped->hwnd, hdc, NULL, (LPRECT)&rc);
+ }
+
+ SLSetCaretPosition(ped, hdc);
+}
+
+
+BOOL FAR PASCAL SLScrollText(ped, hdc)
+register PED ped;
+HDC hdc;
+/* effects: Scrolls the text to bring the caret into view. If the text is
+ * scrolled, the current selection is unhighlighted. Returns TRUE if the text
+ * is scrolled else returns false.
+ */
+{
+ register PSTR pText;
+ ICH scrollAmount = (ped->rcFmt.right-ped->rcFmt.left)/4/ped->aveCharWidth+1;
+ ICH newScreenStartX = ped->screenStart;
+
+ if (!ped->fAutoHScroll)
+ return(FALSE);
+
+ /* Calculate the new starting screen position */
+ if (ped->ichCaret <= ped->screenStart)
+ {
+ /* Caret is to the left of the starting text on the screen we must
+ * scroll the text backwards to bring it into view. Watch out when
+ * subtracting unsigned numbers when we have the possibility of going
+ * negative.
+ */
+ if (ped->ichCaret > scrollAmount)
+ newScreenStartX = ped->ichCaret - scrollAmount;
+ else
+ newScreenStartX = 0;
+ }
+ else
+ {
+ pText = (PSTR) LocalLock(ped->hText);
+ if ((ped->ichCaret != ped->screenStart) &&
+ (ECCchInWidth(ped, hdc, (LPSTR)(pText+ped->screenStart),
+ ped->ichCaret - ped->screenStart,
+ ped->rcFmt.right-ped->rcFmt.left) <
+ ped->ichCaret - ped->screenStart))
+ {
+ newScreenStartX = ((ped->ichCaret < scrollAmount*2) ? 0 :
+ ped->ichCaret - scrollAmount*2);
+ }
+ LocalUnlock(ped->hText);
+ }
+
+#ifdef DBCS
+ pText = (PSTR) LocalLock(ped->hText);
+ newScreenStartX = ECAdjustIch( ped,pText,newScreenStartX );
+ LocalUnlock(ped->hText);
+#endif
+
+ if (ped->screenStart != newScreenStartX)
+ {
+ ped->screenStart = newScreenStartX;
+ SLDrawText(ped, hdc, 0);
+ /* Caret pos is set by drawtext */
+ return(TRUE);
+ }
+
+ return(FALSE);
+
+}
+
+
+ICH FAR PASCAL SLInsertText(ped, lpText, cchInsert)
+register PED ped;
+LPSTR lpText;
+register ICH cchInsert;
+/* effects: Adds up to cchInsert characters from lpText to the ped starting at
+ * ichCaret. If the ped only allows a maximum number of characters, then we
+ * will only add that many characters to the ped and send a EN_MAXTEXT
+ * notification code to the parent of the ec. Also, if !fAutoHScroll, then we
+ * only allow as many chars as will fit in the client rectangle. The number of
+ * characters actually added is returned (could be 0). If we can't allocate
+ * the required space, we notify the parent with EN_ERRSPACE and no characters
+ * are added.
+ */
+{
+ HDC hdc;
+ PSTR pText;
+ ICH cchInsertCopy = cchInsert;
+ int textWidth;
+
+ /* First determine exactly how many characters from lpText we can insert
+ * into the ped.
+ */
+ if (!ped->fAutoHScroll)
+ {
+ pText = (PSTR)LocalLock(ped->hText);
+ hdc = ECGetEditDC(ped, TRUE);
+
+ /* If ped->fAutoHScroll bit is not set, then we only insert as many
+ * characters as will fit in the ped->rcFmt rectangle upto a maximum of
+ * ped->cchTextMax - ped->cch characters. Note that if password style is
+ * on, we allow the user to enter as many chars as the number of
+ * password chars which fit in the rect.
+ */
+ if (ped->cchTextMax <= ped->cch)
+ cchInsert = 0;
+ else
+ {
+ cchInsert = umin(cchInsert, (unsigned)(ped->cchTextMax - ped->cch));
+ if (ped->charPasswordChar)
+ textWidth = ped->cch * ped->cPasswordCharWidth;
+ else
+ textWidth = LOWORD(GetTextExtent(hdc, (LPSTR)pText, ped->cch));
+
+ cchInsert = umin(cchInsert,
+ ECCchInWidth(ped, hdc, lpText, cchInsert,
+ ped->rcFmt.right-ped->rcFmt.left-
+ textWidth));
+ }
+
+ LocalUnlock(ped->hText);
+ ECReleaseEditDC(ped, hdc, TRUE);
+ }
+ else
+ {
+ if (ped->cchTextMax <= ped->cch)
+ cchInsert = 0;
+ else
+ cchInsert = umin((unsigned)(ped->cchTextMax - ped->cch), cchInsert);
+ }
+
+ /* Now try actually adding the text to the ped */
+ if (cchInsert && !ECInsertText(ped, lpText, cchInsert))
+ {
+ ECNotifyParent(ped, EN_ERRSPACE);
+ return(0);
+ }
+
+ if (cchInsert)
+ ped->fDirty = TRUE; /* Set modify flag */
+
+ if (cchInsert < cchInsertCopy)
+ /* Notify parent that we couldn't insert all the text requested */
+ ECNotifyParent(ped, EN_MAXTEXT);
+
+ /* Update selection extents and the caret position. Note that ECInsertText
+ * updates ped->ichCaret, ped->ichMinSel, and ped->ichMaxSel to all be after
+ * the inserted text.
+ */
+
+ return(cchInsert);
+}
+
+
+ICH PASCAL NEAR SLPasteText(register PED ped)
+/* effects: Pastes a line of text from the clipboard into the edit control
+ * starting at ped->ichMaxSel. Updates ichMaxSel and ichMinSel to point to
+ * the end of the inserted text. Notifies the parent if space cannot be
+ * allocated. Returns how many characters were inserted.
+ */
+{
+ HANDLE hData;
+ LPSTR lpchClip;
+ LPSTR lpchClip2;
+ register ICH cchAdded;
+ ICH clipLength;
+
+ if (!OpenClipboard(ped->hwnd))
+ return(0);
+
+ if (!(hData = GetClipboardData(CF_TEXT)))
+ {
+ CloseClipboard();
+ return(0);
+ }
+
+ lpchClip2 = lpchClip = (LPSTR) GlobalLock(hData);
+
+ /* Find the first carrage return or line feed. Just add text to that point.
+ */
+ clipLength = (WORD)lstrlen(lpchClip);
+ for (cchAdded = 0; cchAdded < clipLength; cchAdded++)
+ if (*lpchClip2++ == 0x0D)
+ break;
+
+ /* Insert the text (SLInsertText checks line length) */
+ cchAdded = SLInsertText(ped, lpchClip, cchAdded);
+
+ GlobalUnlock(hData);
+ CloseClipboard();
+
+ return(cchAdded);
+}
+
+
+void NEAR PASCAL SLReplaceSelHandler(register PED ped,
+ LPSTR lpText)
+/* effects: Replaces the text in the current selection with the given text.
+ */
+{
+ BOOL fUpdate;
+ HDC hdc;
+
+ SwapHandle(&lpText);
+ ECEmptyUndo(ped);
+ fUpdate = (BOOL)ECDeleteText(ped);
+ ECEmptyUndo(ped);
+ SwapHandle(&lpText);
+ fUpdate = (BOOL)SLInsertText(ped, lpText, lstrlen(lpText)) || fUpdate;
+ ECEmptyUndo(ped);
+
+ if (fUpdate)
+ {
+ ECNotifyParent(ped, EN_UPDATE);
+ hdc = ECGetEditDC(ped,FALSE);
+ if (!SLScrollText(ped,hdc))
+ SLDrawText(ped,hdc,0);
+ ECReleaseEditDC(ped,hdc,FALSE);
+ ECNotifyParent(ped,EN_CHANGE);
+ }
+}
+
+
+
+void FAR PASCAL SLCharHandler(ped, keyValue, keyMods)
+register PED ped;
+WORD keyValue;
+int keyMods;
+/* effects: Handles character input (really, no foolin')
+ */
+{
+ register HDC hdc;
+ unsigned char keyPress = LOBYTE(keyValue);
+ BOOL updateText = FALSE;
+#ifdef DBCS
+ PSTR pText;
+ int InsertTextLen = 0;
+ WORD DBCSkey;
+#endif
+
+ if (ped->fMouseDown || ped->fReadOnly)
+ /* Don't do anything if we are in the middle of a mousedown deal or if
+ * this is a read only edit control.
+ */
+ return;
+
+ if ((keyPress == BACKSPACE) || (keyPress >= ' '))
+ {
+ /* Delete the selected text if any */
+ if (ECDeleteText(ped))
+ updateText=TRUE;
+ }
+
+ switch(keyPress)
+ {
+ case BACKSPACE:
+ /* Delete any selected text or delete character left if no sel */
+ if (!updateText && ped->ichMinSel)
+ {
+ /* There was no selection to delete so we just delete character
+ left if available */
+#ifdef DBCS
+ pText = LMHtoP( ped->hText );
+ if( ECAnsiPrev( ped,pText, pText+ped->ichMinSel) == pText+ped->ichMinSel-2)
+ ped->ichMinSel--;
+#endif
+ ped->ichMinSel--;
+ (void) ECDeleteText(ped);
+ updateText = TRUE;
+ }
+ break;
+
+ default:
+ if (keyPress >= ' ')
+ {
+#ifdef DBCS
+ InsertTextLen = 1;
+ if( IsDBCSLeadByte( keyPress ) )
+ if( ( DBCSkey = DBCSCombine( ped->hwnd, keyPress ) ) != NULL )
+ if( SLInsertText( ped, (LPSTR)&DBCSkey, 2 ) == 2){
+ InsertTextLen = 2;
+ updateText = TRUE;
+ }else
+ MessageBeep(0);
+ else
+ MessageBeep(0);
+ else
+#endif
+ if (SLInsertText(ped, (LPSTR) &keyPress, 1))
+ updateText = TRUE;
+ else
+ /* Beep. Since we couldn't add the text */
+ MessageBeep(0);
+ }
+ else
+ /* User hit an illegal control key */
+ MessageBeep(0);
+
+ break;
+ }
+
+
+ if (updateText)
+ {
+ /* Dirty flag (ped->fDirty) was set when we inserted text */
+ ECNotifyParent(ped, EN_UPDATE);
+ hdc = ECGetEditDC(ped,FALSE);
+ if (!SLScrollText(ped,hdc))
+#ifdef DBCS
+ SLDrawText(ped,hdc,(ped->ichCaret == 0 ? 0 :ped->ichCaret - InsertTextLen));
+#else
+ SLDrawText(ped,hdc,(ped->ichCaret == 0 ? 0 :ped->ichCaret - 1));
+#endif
+ ECReleaseEditDC(ped,hdc,FALSE);
+ ECNotifyParent(ped,EN_CHANGE);
+ }
+
+}
+
+
+
+void NEAR PASCAL SLKeyDownHandler(register PED ped,
+ WORD virtKeyCode,
+ int keyMods)
+/* effects: Handles cursor movement and other VIRT KEY stuff. keyMods allows
+ * us to make SLKeyDownHandler calls and specify if the modifier keys (shift
+ * and control) are up or down. This is useful for imnplementing the
+ * cut/paste/clear messages for single line edit controls. If keyMods == 0,
+ * we get the keyboard state using GetKeyState(VK_SHIFT) etc. Otherwise, the
+ * bits in keyMods define the state of the shift and control keys.
+ */
+{
+ HDC hdc;
+
+
+ /* Variables we will use for redrawing the updated text */
+ register ICH newMaxSel = ped->ichMaxSel;
+ ICH newMinSel = ped->ichMinSel;
+
+ /* Flags for drawing the updated text */
+ BOOL updateText = FALSE;
+ BOOL changeSelection = FALSE; /* new selection is specified by
+ newMinSel, newMaxSel */
+
+ /* Comparisons we do often */
+ BOOL MinEqMax = (newMaxSel == newMinSel);
+ BOOL MinEqCar = (ped->ichCaret == newMinSel);
+ BOOL MaxEqCar = (ped->ichCaret == newMaxSel);
+
+ /* State of shift and control keys. */
+ int scState = 0;
+
+ /* Combo box support */
+ BOOL fIsListVisible;
+ BOOL fIsExtendedUI;
+
+#ifdef DBCS
+ PSTR pText;
+#endif
+
+ if (ped->fMouseDown)
+ {
+ /* If we are in the middle of a mouse down handler, then don't do
+ * anything. ie. ignore keyboard input.
+ */
+ return;
+ }
+
+ if (!keyMods)
+ {
+ /* Get state of modifier keys for use later. */
+ scState = ((GetKeyState(VK_CONTROL) & 0x8000) ? 1 : 0);
+ scState += ((GetKeyState(VK_SHIFT) & 0x8000) ? 2 : 0);
+ }
+ else
+ scState = ((keyMods == NOMODIFY) ? 0 : keyMods);
+
+
+
+ switch(virtKeyCode)
+ {
+ case VK_UP:
+ if (ped->listboxHwnd)
+ {
+ /* Handle Combobox support */
+ fIsExtendedUI = SendMessage(ped->hwndParent, CB_GETEXTENDEDUI, 0, 0L);
+ fIsListVisible = SendMessage(ped->hwndParent, CB_GETDROPPEDSTATE, 0, 0L);
+
+ if (!fIsListVisible && fIsExtendedUI)
+ {
+ /* For TandyT
+ */
+DropExtendedUIListBox:
+ /* Since an extendedui combo box doesn't do anything on f4, we
+ * turn off the extended ui, send the f4 to drop, and turn it
+ * back on again.
+ */
+ SendMessage(ped->hwndParent, CB_SETEXTENDEDUI, 0, 0L);
+ SendMessage(ped->listboxHwnd, WM_KEYDOWN, VK_F4, 0L);
+ SendMessage(ped->hwndParent, CB_SETEXTENDEDUI, 1, 0L);
+ return;
+ }
+ else
+ goto SendKeyToListBox;
+ }
+
+ /* else fall through */
+
+ case VK_LEFT:
+ /* If the caret isn't already at 0, we can move left */
+ if (ped->ichCaret)
+ {
+ switch (scState)
+ {
+ case NONEDOWN:
+ /* Clear selection, move caret left */
+#ifdef DBCS
+ pText = LMHtoP( ped->hText );
+ if( ECAnsiPrev( ped, pText, pText + ped->ichCaret ) ==
+ pText + ped->ichCaret - 2 )
+ ped->ichCaret--;
+#endif
+ ped->ichCaret--;
+ newMaxSel = newMinSel = ped->ichCaret;
+ break;
+
+ case CTRLDOWN:
+ /* Clear selection, move caret word left */
+ ped->ichCaret = LOWORD(ECWord(ped,ped->ichCaret,TRUE));
+ newMaxSel = newMinSel = ped->ichCaret;
+ break;
+
+ case SHFTDOWN:
+ /* Extend selection, move caret left */
+#ifdef DBCS
+ pText = LMHtoP( ped->hText );
+ if( ECAnsiPrev( ped, pText, pText + ped->ichCaret ) ==
+ pText + ped->ichCaret - 2 )
+ ped->ichCaret--;
+#endif
+ ped->ichCaret--;
+ if (MaxEqCar && !MinEqMax)
+ /* Reduce selection extent */
+ newMaxSel = ped->ichCaret;
+ else
+ /* Extend selection extent */
+ newMinSel = ped->ichCaret;
+ break;
+
+ case SHCTDOWN:
+ /* Extend selection, move caret word left */
+ ped->ichCaret = LOWORD(ECWord(ped,ped->ichCaret,TRUE));
+ if (MaxEqCar && !MinEqMax)
+ {
+ /* Reduce selection extent */
+ /*
+ * Hint: Suppose WORD. OR is selected. Cursor between R
+ * and D. Hit select word left, we want to just select the
+ * W and leave cursor before the W.
+ */
+ newMinSel = ped->ichMinSel;
+ newMaxSel = ped->ichCaret;
+ }
+ else
+ /* Extend selection extent */
+ newMinSel = ped->ichCaret;
+ break;
+ }
+
+ changeSelection = TRUE;
+ }
+ else
+ {
+ /* If the user tries to move left and we are at the 0th character
+ and there is a selection, then cancel the selection. */
+ if (ped->ichMaxSel != ped->ichMinSel &&
+ (scState == NONEDOWN || scState == CTRLDOWN))
+ {
+ changeSelection = TRUE;
+ newMaxSel = newMinSel = ped->ichCaret;
+ }
+ }
+ break;
+
+ case VK_DOWN:
+ if (ped->listboxHwnd)
+ {
+ /* Handle Combobox support */
+ fIsExtendedUI = SendMessage(ped->hwndParent, CB_GETEXTENDEDUI, 0, 0L);
+ fIsListVisible = SendMessage(ped->hwndParent, CB_GETDROPPEDSTATE, 0, 0L);
+
+ if (!fIsListVisible && fIsExtendedUI)
+ {
+ /* For TandyT
+ */
+ goto DropExtendedUIListBox;
+ }
+ else
+ goto SendKeyToListBox;
+ }
+
+ /* else fall through */
+
+ case VK_RIGHT:
+ /*
+ * If the caret isn't already at ped->cch, we can move right.
+ */
+ if (ped->ichCaret < ped->cch)
+ {
+ switch (scState)
+ {
+ case NONEDOWN:
+ /* Clear selection, move caret right */
+#ifdef DBCS
+ pText = LMHtoP( ped->hText ) + ped->ichCaret;
+ if( ECIsDBCSLeadByte( ped, *pText ) )
+ ped->ichCaret++;
+#endif
+ ped->ichCaret++;
+ newMaxSel = newMinSel = ped->ichCaret;
+ break;
+
+ case CTRLDOWN:
+ /* Clear selection, move caret word right */
+ ped->ichCaret = HIWORD(ECWord(ped,ped->ichCaret,FALSE));
+ newMaxSel = newMinSel = ped->ichCaret;
+ break;
+
+ case SHFTDOWN:
+ /* Extend selection, move caret right */
+#ifdef DBCS
+ pText = LMHtoP( ped->hText ) + ped->ichCaret;
+ if( ECIsDBCSLeadByte( ped, *pText ) )
+ ped->ichCaret++;
+#endif
+ ped->ichCaret++;
+ if (MinEqCar && !MinEqMax)
+ /* Reduce selection extent */
+ newMinSel = ped->ichCaret;
+ else
+ /* Extend selection extent */
+ newMaxSel = ped->ichCaret;
+ break;
+
+ case SHCTDOWN:
+ /* Extend selection, move caret word right */
+ ped->ichCaret = HIWORD(ECWord(ped,ped->ichCaret,FALSE));
+ if (MinEqCar && !MinEqMax)
+ {
+ /* Reduce selection extent */
+ newMinSel = ped->ichCaret;
+ newMaxSel = ped->ichMaxSel;
+ }
+ else
+ /* Extend selection extent */
+ newMaxSel = ped->ichCaret;
+ break;
+ }
+
+ changeSelection = TRUE;
+ }
+ else
+ {
+ /* If the user tries to move right and we are at the last character
+ and there is a selection, then cancel the selection. */
+ if (ped->ichMaxSel != ped->ichMinSel &&
+ (scState == NONEDOWN || scState == CTRLDOWN))
+ {
+ newMaxSel = newMinSel = ped->ichCaret;
+ changeSelection = TRUE;
+ }
+ }
+ break;
+
+ case VK_HOME:
+ ped->ichCaret = 0;
+ switch (scState)
+ {
+ case NONEDOWN:
+ case CTRLDOWN:
+ /* Clear selection, move caret home */
+ newMaxSel = newMinSel = ped->ichCaret;
+ break;
+
+ case SHFTDOWN:
+ case SHCTDOWN:
+ /* Extend selection, move caret home */
+ if (MaxEqCar && !MinEqMax)
+ {
+ /* Reduce/negate selection extent */
+ newMinSel = 0;
+ newMaxSel = ped->ichMinSel;
+ }
+ else
+ /* Extend selection extent */
+ newMinSel = ped->ichCaret;
+ break;
+ }
+
+ changeSelection = TRUE;
+ break;
+
+ case VK_END:
+ newMaxSel = ped->ichCaret = ped->cch;
+ switch (scState)
+ {
+ case NONEDOWN:
+ case CTRLDOWN:
+ /* Clear selection, move caret to end of text */
+ newMinSel = ped->cch;
+ break;
+
+ case SHFTDOWN:
+ case SHCTDOWN:
+ /* Extend selection, move caret to end of text */
+ if (MinEqCar && !MinEqMax)
+ /* Reduce/negate selection extent */
+ newMinSel = ped->ichMaxSel;
+ /* else Extend selection extent */
+ break;
+ }
+
+ changeSelection = TRUE;
+ break;
+
+ case VK_DELETE:
+ if (ped->fReadOnly)
+ break;
+
+ switch (scState)
+ {
+ case NONEDOWN:
+ /* Clear selection. If no selection, delete (clear) character
+ * right.
+ */
+ if ((ped->ichMaxSel<ped->cch) &&
+ (ped->ichMinSel==ped->ichMaxSel))
+ {
+ /* Move cursor forwards and simulate a backspace.
+ */
+#ifdef DBCS
+ pText = LMHtoP( ped->hText ) + ped->ichCaret;
+ if( ECIsDBCSLeadByte( ped, *pText ) )
+ ped->ichCaret++;
+#endif
+ ped->ichCaret++;
+ ped->ichMaxSel = ped->ichMinSel = ped->ichCaret;
+ SLCharHandler(ped, (WORD) BACKSPACE, 0);
+ }
+ if (ped->ichMinSel != ped->ichMaxSel)
+ SLCharHandler(ped, (WORD) BACKSPACE, 0);
+ break;
+
+ case SHFTDOWN:
+ /* CUT selection ie. remove and copy to clipboard, or if no
+ * selection, delete (clear) character left.
+ */
+
+ if (SendMessage(ped->hwnd, WM_COPY, (WORD)0,0L) ||
+ (ped->ichMinSel == ped->ichMaxSel))
+ /* If copy successful, delete the copied text by simulating a
+ * backspace message which will redraw the text and take care
+ * of notifying the parent of changes. Or if there is no
+ * selection, just delete char left.
+ */
+ SLCharHandler(ped, (WORD) BACKSPACE, 0);
+ break;
+
+ case CTRLDOWN:
+ /* Delete to end of line if no selection else delete (clear)
+ * selection.
+ */
+ if ((ped->ichMaxSel<ped->cch) &&
+ (ped->ichMinSel==ped->ichMaxSel))
+ {
+ /* Move cursor to end of line and simulate a backspace.
+ */
+ ped->ichMaxSel = ped->ichCaret = ped->cch;
+ }
+ if (ped->ichMinSel != ped->ichMaxSel)
+ SLCharHandler(ped, (WORD) BACKSPACE, 0);
+ break;
+ }
+
+ /* No need to update text or selection since BACKSPACE message does it
+ * for us.
+ */
+ break;
+
+ case VK_INSERT:
+ switch (scState)
+ {
+ case CTRLDOWN:
+ /* Copy current selection to clipboard */
+ SendMessage(ped->hwnd, WM_COPY, (WORD)NULL, (LONG)NULL);
+ break;
+
+ case SHFTDOWN:
+ if (ped->fReadOnly)
+ break;
+
+ /* Insert contents of clipboard (PASTE) */
+ /* Unhighlight current selection and delete it, if any */
+ ECDeleteText(ped);
+ SLPasteText(ped);
+ updateText = TRUE;
+ ECNotifyParent(ped, EN_UPDATE);
+ break;
+ }
+ break;
+
+ case VK_F4:
+ case VK_PRIOR:
+ case VK_NEXT:
+ /* Send keys to the listbox if we are a part of a combo box. This
+ * assumes the listbox ignores keyup messages which is correct right
+ * now.
+ */
+ if (ped->listboxHwnd)
+ {
+SendKeyToListBox:
+ /* Handle Combobox support */
+ SendMessage(ped->listboxHwnd, WM_KEYDOWN, virtKeyCode, 0L);
+ return;
+ }
+ }
+
+
+
+ if (changeSelection || updateText)
+ {
+ hdc = ECGetEditDC(ped,FALSE);
+ /* Scroll if needed */
+ SLScrollText(ped,hdc);
+
+ if (changeSelection)
+ SLChangeSelection(ped,hdc,newMinSel,newMaxSel);
+ if (updateText)
+ SLDrawText(ped,hdc,0);
+
+ /* SLSetCaretPosition(ped,hdc);*/
+ ECReleaseEditDC(ped,hdc,FALSE);
+ if (updateText)
+ ECNotifyParent(ped, EN_CHANGE);
+ }
+
+}
+
+
+ICH NEAR PASCAL SLMouseToIch(ped, hdc, mousePt)
+register PED ped;
+HDC hdc;
+POINT mousePt;
+/* effects: Returns the closest cch to where the mouse point is.
+ */
+{
+ register PSTR pText;
+ int width = mousePt.x;
+ int textWidth;
+ ICH cch;
+
+ if (width <= ped->rcFmt.left)
+ {
+ /* Return either the first non visible character or return 0 if at
+ * beginning of text
+ */
+ if (ped->screenStart)
+ return(ped->screenStart - 1);
+ else
+ return(0);
+ }
+
+ if (width > ped->rcFmt.right)
+ {
+ pText = LocalLock(ped->hText);
+
+ /* Return last char in text or one plus the last char visible */
+ cch = ECCchInWidth(ped, hdc, (LPSTR)(pText+ped->screenStart),
+ ped->cch - ped->screenStart,
+ ped->rcFmt.right-ped->rcFmt.left) +
+ ped->screenStart;
+ LocalUnlock(ped->hText);
+ if (cch >= ped->cch)
+ return(ped->cch);
+ else
+ return(cch+1);
+ }
+
+ /* Check if password hidden chars are being used. */
+ if (ped->charPasswordChar)
+ return(umin((width-ped->rcFmt.left)/ped->cPasswordCharWidth,ped->cch));
+
+ if (!ped->cch)
+ return(0);
+
+ pText = LocalLock(ped->hText);
+ cch = ped->cch;
+
+ while(((textWidth =
+ LOWORD(GetTextExtent(hdc, (LPSTR)(pText+ped->screenStart),
+ cch-ped->screenStart)))
+ > (width-ped->rcFmt.left)) && (cch-ped->screenStart) )
+ {
+ /* For that "feel" */
+ if ((textWidth - ped->aveCharWidth/2) < (width-ped->rcFmt.left))
+ break;
+
+ cch--;
+ }
+
+#ifdef DBCS
+ cch = ECAdjustIch( ped, pText, cch );
+#endif
+
+ LocalUnlock(ped->hText);
+ return(cch);
+}
+
+
+
+
+void NEAR PASCAL SLMouseMotionHandler(ped, message, virtKeyDown, mousePt)
+register PED ped;
+WORD message;
+WORD virtKeyDown;
+POINT mousePt;
+{
+ LONG selection;
+ BOOL changeSelection = FALSE;
+
+ HDC hdc = ECGetEditDC(ped,FALSE);
+
+ ICH newMaxSel = ped->ichMaxSel;
+ ICH newMinSel = ped->ichMinSel;
+
+ ICH mouseIch = SLMouseToIch(ped, hdc, mousePt);
+
+#ifdef DBCS
+ LPSTR pText;
+
+ pText = LocalLock( ped->hText );
+ mouseIch = ECAdjustIch( ped, pText, mouseIch );
+ LocalUnlock( ped->hText );
+#endif
+
+ switch (message)
+ {
+ case WM_LBUTTONDBLCLK:
+ /* Note that we don't have to worry about this control having the focus
+ * since it got it when the WM_LBUTTONDOWN message was first sent. If
+ * shift key is down, extend selection to word we double clicked on else
+ * clear current selection and select word.
+ */
+#ifdef DBCS
+ pText = LocalLock( ped->hText ) + ped->ichCaret;
+ selection = ECWord(ped,ped->ichCaret,
+ (ECIsDBCSLeadByte(ped,*pText) && ped->ichCaret < ped->cch) ? FALSE : TRUE );
+ LocalUnlock( ped->hText );
+#else
+ selection = ECWord(ped,ped->ichCaret,TRUE);
+#endif
+ newMinSel = LOWORD(selection);
+ newMaxSel = ped->ichCaret = HIWORD(selection);
+ changeSelection = TRUE;
+ /* Set mouse down to false so that the caret isn't reposition on the
+ * mouseup message or on an accidental move...
+ */
+ ped->fMouseDown = FALSE;
+ break;
+
+ case WM_MOUSEMOVE:
+ if (ped->fMouseDown)
+ {
+ changeSelection = TRUE;
+ /* Extend selection, move caret word right */
+ if ((ped->ichMinSel == ped->ichCaret) &&
+ (ped->ichMinSel != ped->ichMaxSel))
+ {
+ /* Reduce selection extent */
+ newMinSel = ped->ichCaret = mouseIch;
+ newMaxSel = ped->ichMaxSel;
+ }
+ else
+ /* Extend selection extent */
+ newMaxSel = ped->ichCaret=mouseIch;
+ }
+ break;
+
+ case WM_LBUTTONDOWN:
+ /*
+ * If we currently don't have the focus yet, try to get it.
+ */
+ if (!ped->fFocus)
+ {
+ if (!ped->fNoHideSel)
+ /* Clear the selection before setting the focus so that we don't
+ * get refresh problems and flicker. Doesn't matter since the
+ * mouse down will end up changing it anyway.
+ */
+ ped->ichMinSel = ped->ichMaxSel = ped->ichCaret;
+
+ SetFocus(ped->hwnd);
+ /* If we are part of a combo box, then this is the first time the
+ * edit control is getting the focus so we just want to highlight
+ * the selection and we don't really want to position the caret.
+ */
+ if (ped->listboxHwnd)
+ break;
+ }
+
+ if (ped->fFocus)
+ {
+ /* Only do this if we have the focus since a clever app may not want
+ * to give us the focus at the SetFocus call above.
+ */
+ ped->fMouseDown = TRUE;
+ SetCapture(ped->hwnd);
+ changeSelection = TRUE;
+ if (!(virtKeyDown & MK_SHIFT))
+ {
+ /*
+ * If shift key isn't down, move caret to mouse point and clear
+ * old selection
+ */
+ newMinSel = newMaxSel = ped->ichCaret = mouseIch;
+ }
+ else
+ {
+ /* Shiftkey is down so we want to maintain the current selection
+ * (if any) and just extend or reduce it
+ */
+ if (ped->ichMinSel == ped->ichCaret)
+ newMinSel = ped->ichCaret = mouseIch;
+ else
+ newMaxSel = ped->ichCaret = mouseIch;
+ }
+ }
+ break;
+
+ case WM_LBUTTONUP:
+ if (ped->fMouseDown)
+ {
+ ReleaseCapture();
+ /*SLSetCaretPosition(ped,hdc);*/
+ ped->fMouseDown = FALSE;
+ }
+ break;
+ }
+
+
+ if (changeSelection)
+ {
+ SLScrollText(ped,hdc);
+ SLChangeSelection(ped, hdc, newMinSel, newMaxSel);
+ }
+
+ ECReleaseEditDC(ped,hdc,FALSE);
+
+}
+
+
+
+
+void NEAR PASCAL SLPaintHandler(ped,althdc)
+register PED ped;
+HDC althdc;
+/* effects: Handles painting of the edit control window. Draws the border if
+ * necessary and draws the text in its current state.
+ */
+{
+ HWND hwnd = ped->hwnd;
+ HBRUSH hBrush;
+ register HDC hdc;
+ PAINTSTRUCT paintstruct;
+ RECT rcEdit;
+ HANDLE hOldFont;
+
+ /* Had to put in hide/show carets. The first one needs to be done before
+ * beginpaint to correctly paint the caret if part is in the update region
+ * and part is out. The second is for 1.03 compatibility. It breaks
+ * micrografix's worksheet edit control if not there.
+ */
+
+ HideCaret(hwnd);
+
+ /* Allow subclassing hdc */
+ if (!althdc)
+ hdc = BeginPaint(hwnd, (PAINTSTRUCT FAR *)&paintstruct);
+ else
+ hdc = althdc;
+
+ HideCaret(hwnd);
+
+ if (!ped->fNoRedraw && IsWindowVisible(ped->hwnd))
+ {
+ /* Erase the background since we don't do it in the erasebkgnd message.
+ */
+ hBrush = GetControlBrush(ped->hwnd, hdc, CTLCOLOR_EDIT);
+ FillWindow(ped->hwndParent, hwnd, hdc, hBrush);
+
+ if (ped->fBorder)
+ {
+ GetClientRect(hwnd, (LPRECT)&rcEdit);
+ DrawFrame(hdc, (LPRECT)&rcEdit, 1, DF_WINDOWFRAME);
+ }
+
+ if (ped->hFont)
+ /* We have to select in the font since this may be a subclassed dc
+ * or a begin paint dc which hasn't been initialized with out fonts
+ * like ECGetEditDC does.
+ */
+ hOldFont = SelectObject(hdc, ped->hFont);
+
+ SLDrawText(ped, hdc, 0);
+
+ if (ped->hFont && hOldFont)
+ SelectObject(hdc, hOldFont);
+
+ }
+ ShowCaret(hwnd);
+
+ if (!althdc)
+ EndPaint(hwnd, (LPPAINTSTRUCT)&paintstruct);
+
+ ShowCaret(hwnd);
+}
+
+
+
+void NEAR PASCAL SLSetFocusHandler(ped)
+register PED ped;
+/* effects: Gives the edit control the focus and notifies the parent
+ * EN_SETFOCUS.
+ */
+{
+ register HDC hdc;
+
+ if (!ped->fFocus)
+ {
+ UpdateWindow(ped->hwnd);
+
+ ped->fFocus = TRUE; /* Set focus */
+
+ /* We don't want to muck with the caret since it isn't created. */
+ hdc = ECGetEditDC(ped,TRUE);
+
+ /* Show the current selection. Only if the selection was hidden when we
+ * lost the focus, must we invert (show) it.
+ */
+ if (!ped->fNoHideSel)
+ SLDrawText(ped, hdc, 0);
+
+ /* Create the caret. Add in the +1 because we have an extra pixel for
+ * highlighting around the text. If the font is at least as wide as the
+ * system font, use a wide caret else use a 1 pixel wide caret.
+ */
+ CreateCaret(ped->hwnd, (HBITMAP)NULL,
+ (ped->cxSysCharWidth > ped->aveCharWidth ? 1 : 2),
+ ped->lineHeight+1);
+ SLSetCaretPosition(ped,hdc);
+ ECReleaseEditDC(ped,hdc,TRUE);
+ ShowCaret(ped->hwnd);
+ }
+
+ /* Notify parent we have the focus */
+ ECNotifyParent(ped, EN_SETFOCUS);
+}
+
+
+
+
+void NEAR PASCAL SLKillFocusHandler(ped, newFocusHwnd)
+register PED ped;
+HWND newFocusHwnd;
+/* effects: The edit control loses the focus and notifies the parent via
+ * EN_KILLFOCUS.
+ */
+{
+ RECT rcEdit;
+
+ if (ped->fFocus)
+ {
+ /* Destroy the caret */
+ HideCaret(ped->hwnd);
+ DestroyCaret();
+
+ ped->fFocus = FALSE; /* Clear focus */
+
+ /* Do this only if we still have the focus. But we always notify the
+ * parent that we lost the focus whether or not we originally had the
+ * focus.
+ */
+ /* Hide the current selection if needed */
+ if (!ped->fNoHideSel && (ped->ichMinSel != ped->ichMaxSel))
+ {
+ GetClientRect(ped->hwnd, (LPRECT)&rcEdit);
+ if (ped->fBorder && rcEdit.right-rcEdit.left &&
+ rcEdit.bottom-rcEdit.top)
+ {
+ /* Don't invalidate the border so that we avoid flicker */
+ InflateRect((LPRECT)&rcEdit, -1, -1);
+ }
+ InvalidateRect(ped->hwnd, (LPRECT)&rcEdit, FALSE);
+ UpdateWindow(ped->hwnd);
+
+#if 0
+ SLSetSelectionHandler(ped, ped->ichCaret, ped->ichCaret);
+#endif
+ }
+ }
+
+ /* If we aren't a combo box, notify parent that we lost the focus.
+ */
+ if (!ped->listboxHwnd)
+ ECNotifyParent(ped, EN_KILLFOCUS);
+ else
+ {
+ /* This editcontrol is part of a combo box and is losing the focus. If
+ * the focus is NOT being sent to another control in the combo box
+ * window, then it means the combo box is losing the focus. So we will
+ * notify the combo box of this fact.
+ */
+ if (!IsChild(ped->hwndParent, newFocusHwnd))
+ {
+ /* Focus is being sent to a window which is not a child of the combo
+ * box window which implies that the combo box is losing the focus.
+ * Send a message to the combo box informing him of this fact so
+ * that he can clean up...
+ */
+ SendMessage(ped->hwndParent, CBEC_KILLCOMBOFOCUS, 0, 0L);
+ }
+ }
+}
+
+
+/*******************/
+/* SLEditWndProc() */
+/*******************/
+LONG FAR PASCAL SLEditWndProc(hwnd, ped, message, wParam, lParam)
+HWND hwnd;
+register PED ped;
+WORD message;
+register WORD wParam;
+LONG lParam;
+/* effects: Class procedure for all single line edit controls.
+ Dispatches all messages to the appropriate handlers which are named
+ as follows:
+ SL (single line) prefixes all single line edit control procedures while
+ EC (edit control) prefixes all common handlers.
+
+ The SLEditWndProc only handles messages specific to single line edit
+ controls.
+ */
+
+{
+ /* Dispatch the various messages we can receive */
+ switch (message)
+ {
+ case WM_CLEAR:
+ /* wParam - not used
+ lParam - not used */
+ /*
+ * Call SLKeyDownHandler with a VK_DELETE keycode to clear the selected
+ * text.
+ */
+ if (ped->ichMinSel != ped->ichMaxSel)
+ SLKeyDownHandler(ped, VK_DELETE, NOMODIFY);
+ break;
+
+ case WM_CHAR:
+ /* wParam - the value of the key
+ lParam - modifiers, repeat count etc (not used) */
+ if (!ped->fEatNextChar)
+ SLCharHandler(ped, wParam, 0);
+ else
+ ped->fEatNextChar = FALSE;
+ break;
+
+ case WM_CUT:
+ /* wParam - not used
+ lParam - not used */
+ /* Call SLKeyDownHandler with a VK_DELETE keycode to cut the selected
+ * text. (Delete key with shift modifier.) This is needed so that apps
+ * can send us WM_PASTE messages.
+ */
+ if (ped->ichMinSel != ped->ichMaxSel)
+ SLKeyDownHandler(ped, VK_DELETE, SHFTDOWN);
+ break;
+
+ case WM_ERASEBKGND:
+ /* wParam - device context handle
+ lParam - not used */
+ /* We do nothing on this message and we don't want DefWndProc to do
+ * anything, so return 1
+ */
+ return(1L);
+ break;
+
+ case WM_GETDLGCODE:
+ /* wParam - not used
+ lParam - not used */
+ return(DLGC_WANTCHARS | DLGC_HASSETSEL | DLGC_WANTARROWS);
+ break;
+
+ case WM_KEYDOWN:
+ /* wParam - virt keycode of the given key
+ lParam - modifiers such as repeat count etc. (not used) */
+ SLKeyDownHandler(ped, wParam, 0);
+ break;
+
+ case WM_KILLFOCUS:
+ /* wParam - handle of the window that receives the input focus
+ lParam - not used */
+ SLKillFocusHandler(ped, (HWND)wParam);
+ break;
+
+ case WM_MOUSEMOVE:
+ case WM_LBUTTONDBLCLK:
+ case WM_LBUTTONDOWN:
+ case WM_LBUTTONUP:
+ /* wParam - contains a value that indicates which virtual keys are down
+ lParam - contains x and y coords of the mouse cursor */
+ SLMouseMotionHandler(ped, message, wParam, MAKEPOINT(lParam));
+ break;
+
+ case WM_CREATE:
+ /* wParam - handle to window being created
+ lParam - points to a CREATESTRUCT that contains copies of parameters
+ passed to the CreateWindow function. */
+ return(SLCreateHandler(hwnd, ped, (LPCREATESTRUCT) lParam));
+ break;
+
+ case WM_PAINT:
+ /* wParam - not used - actually sometimes used as a hdc when subclassing
+ lParam - not used */
+ SLPaintHandler(ped, wParam);
+ break;
+
+ case WM_PASTE:
+ /* wParam - not used
+ lParam - not used */
+ /* Call SLKeyDownHandler with a SHIFT VK_INSERT keycode to paste the
+ * clipboard into the edit control. This is needed so that apps can
+ * send us WM_PASTE messages.
+ */
+ SLKeyDownHandler(ped, VK_INSERT, SHFTDOWN);
+ break;
+
+ case WM_SETFOCUS:
+ /* wParam - handle of window that loses the input focus (may be NULL)
+ lParam - not used */
+ SLSetFocusHandler(ped);
+ break;
+
+ case WM_SETTEXT:
+ /* wParam - not used
+ lParam - points to a null-terminated string that is used to set the
+ window text. */
+ return(SLSetTextHandler(ped, (LPSTR)lParam));
+ break;
+
+ case WM_SIZE:
+ /* wParam - defines the type of resizing fullscreen, sizeiconic,
+ sizenormal etc.
+ lParam - new width in LOWORD, new height in HIGHWORD of client area */
+ SLSizeHandler(ped);
+ return(0L);
+ break;
+
+ case WM_SYSKEYDOWN:
+ if (ped->listboxHwnd && /* Check if we are in a combo box */
+ (lParam & 0x20000000L)) /* Check if the alt key is down */
+ {
+ /*
+ * Handle Combobox support. We want alt up or down arrow to behave
+ * like F4 key which completes the combo box selection
+ */
+ ped->fEatNextChar = FALSE;
+ if (lParam & 0x1000000)
+ {
+ /* This is an extended key such as the arrow keys not on the
+ * numeric keypad so just drop the combobox.
+ */
+ if (wParam == VK_DOWN || wParam == VK_UP)
+ goto DropCombo;
+ else
+ goto foo;
+ }
+
+ if (GetKeyState(VK_NUMLOCK) < 0)
+ {
+ ped->fEatNextChar = FALSE;
+ /* If numlock down, just send all system keys to dwp */
+ goto foo;
+ }
+ else
+ /* Num lock is up. Eat the characters generated by the key board
+ * driver.
+ */
+ ped->fEatNextChar = TRUE;
+
+ if (!(wParam == VK_DOWN || wParam == VK_UP))
+ goto foo;
+
+DropCombo:
+ if (SendMessage(ped->hwndParent, CB_GETEXTENDEDUI, 0, 0L) & 0x00000001)
+ {
+ /* Extended ui doesn't honor VK_F4. */
+ if (SendMessage(ped->hwndParent, CB_GETDROPPEDSTATE, 0, 0L))
+ return(SendMessage(ped->hwndParent, CB_SHOWDROPDOWN, 0, 0L));
+ else
+ return(SendMessage(ped->hwndParent, CB_SHOWDROPDOWN, 1, 0L));
+ }
+ else
+ return(SendMessage(ped->listboxHwnd, WM_KEYDOWN, VK_F4, 0L));
+ }
+foo:
+ if (wParam == VK_BACK)
+ {
+ SendMessage(ped->hwnd, EM_UNDO, 0, 0L);
+ break;
+ }
+ goto PassToDefaultWindowProc;
+ break;
+
+ case EM_GETLINE:
+ /* wParam - line number to copy (always the first line for SL)
+ lParam - buffer to copy text to. FIrst word is max # of bytes to copy
+ */
+ return(ECGetTextHandler(ped, (*(WORD FAR *)lParam), (LPSTR)lParam));
+ break;
+
+ case EM_LINELENGTH:
+ /* wParam - ignored
+ lParam - ignored */
+ return((LONG)ped->cch);
+ break;
+
+ case EM_SETSEL:
+ /* wParam - not used
+ lParam - starting pos in lowword ending pos in high word */
+ SLSetSelectionHandler(ped, LOWORD(lParam), HIWORD(lParam));
+ break;
+
+ case EM_REPLACESEL:
+ /* wParam - not used
+ lParam - points to a null terminated string of replacement text */
+ SLReplaceSelHandler(ped, (LPSTR)lParam);
+ break;
+
+ case WM_UNDO:
+ case EM_UNDO:
+ SLUndoHandler(ped);
+ break;
+
+ default:
+PassToDefaultWindowProc:
+ return(DefWindowProc(hwnd,message,wParam,lParam));
+ break;
+
+ } /* switch (message) */
+
+ return(1L);
+} /* SLEditWndProc */