test: editsl.c Source File

Main Page | Class Hierarchy | Class List | File List | Class Members | File Members

# editsl.c

Go to the documentation of this file.

    00001 /****************************************************************************\
    00002 * editsl.c - Edit controls rewrite. Version II of edit controls.
    00003 *
    00004 * Copyright (c) 1985 - 1999, Microsoft Corporation
    00005 *
    00006 * Single Line Support Routines
    00007 *
    00008 * Created: 24-Jul-88 davidds
    00009 *
    00010 * Language pack notes:
    00011 *   With the language pack loaded all positional processing is based on
    00012 *   ped->xOffset rather than ped->ichScreenStart. The non-lpk optimisation of
    00013 *   maintaining ped->ichScreenStart doesn't work because of the
    00014 *   glyph reordering features of complex scripts.
    00015 *
    00016 \****************************************************************************/
    00017
    00018 #include "precomp.h"
    00019 #pragma hdrstop
    00020
    00021 #define SYS_ALTERNATE 0x2000
    00022
    00023 typedef BOOL (*FnGetTextExtentPoint)(HDC, PVOID, int, LPSIZE);
    00024
    00025 /***************************************************************************\
    00026 * SLCalcStringWidth
    00027 *
    00028 \***************************************************************************/
    00029
    00030 int SLCalcStringWidth(PED ped, HDC hdc, ICH ich, ICH cch)
    00031 {
    00032     if (cch == 0)
    00033         return 0;
    00034
    00035     if (ped->charPasswordChar) {
    00036         return cch * ped->cPasswordCharWidth;
    00037     } else {
    00038         SIZE size;
    00039
    00040         if (ped->fNonPropFont && !ped->fDBCS) {
    00041             size.cx = cch * ped->aveCharWidth;
    00042         } else {
    00043             PSTR pText = ECLock(ped);
    00044             if (ped->fAnsi) {
    00045                 GetTextExtentPointA(hdc, (LPSTR)(pText + ich), cch, &size);
    00046             } else {
    00047                 GetTextExtentPointW(hdc, (LPWSTR)pText + ich, cch, &size);
    00048             }
    00049             ECUnlock(ped);
    00050         }
    00051         return size.cx - ped->charOverhang;
    00052     }
    00053 }
    00054
    00055 /***************************************************************************\
    00056 * SLCalcXOffsetLeft
    00057 *
    00058 * Calculates the starting offset for left-aligned strings.
    00059 *
    00060 \***************************************************************************/
    00061
    00062 int SLCalcXOffsetLeft(PED ped, HDC hdc, ICH ich)
    00063 {
    00064     int cch = (int)(ich - ped->ichScreenStart);
    00065
    00066     if (cch <= 0)
    00067         return 0;
    00068
    00069     return SLCalcStringWidth(ped, hdc, ped->ichScreenStart, cch);
    00070 }
    00071
    00072 /***************************************************************************\
    00073 * SLCalcXOffsetSpecial
    00074 *
    00075 * Calculates the horizontal offset (indent) required for right or center
    00076 * justified lines.
    00077 *
    00078 \***************************************************************************/
    00079
    00080 int SLCalcXOffsetSpecial(PED ped, HDC hdc, ICH ich)
    00081 {
    00082     PSTR pText;
    00083     ICH cch, ichStart = ped->ichScreenStart;
    00084     int cx;
    00085
    00086     /*
    00087      * Calc the number of characters from start to right end.
    00088      */
    00089     pText = ECLock(ped);
    00090     cch = ECCchInWidth(ped, hdc, (LPSTR)(pText + ichStart * ped->cbChar),
    00091             ped->cch - ichStart, ped->rcFmt.right - ped->rcFmt.left, TRUE);
    00092     ECUnlock(ped);
    00093
    00094     /*
    00095      * Once the last character of the string has been scrolled out of
    00096      * the view, use normal offset calculation.
    00097      */
    00098     if (ped->ichScreenStart + cch < ped->cch)
    00099         return SLCalcXOffsetLeft(ped, hdc, ich);
    00100
    00101     cx = ped->rcFmt.right - ped->rcFmt.left - SLCalcStringWidth(ped,
    00102             hdc, ichStart, cch);
    00103
    00104     if (ped->format == ES_CENTER) {
    00105          cx = max(0, cx / 2);
    00106     } else if (ped->format == ES_RIGHT) {
    00107         /*
    00108          * Subtract 1 so that the 1 pixel wide cursor will be in the visible
    00109          * region on the very right side of the screen, mle does this.
    00110          */
    00111         cx = max(0, cx - 1);
    00112     }
    00113
    00114     return cx + SLCalcStringWidth(ped, hdc, ichStart, ich - ichStart);
    00115 }
    00116
    00117 /***************************************************************************\
    00118 * SLSetCaretPosition AorW
    00119 *
    00120 * If the window has the focus, find where the caret belongs and move
    00121 * it there.
    00122 *
    00123 * History:
    00124 \***************************************************************************/
    00125
    00126 void SLSetCaretPosition(
    00127     PED ped,
    00128     HDC hdc)
    00129 {
    00130     int xPosition;
    00131
    00132     /*
    00133      * We will only position the caret if we have the focus since we don't want
    00134      * to move the caret while another window could own it.
    00135      */
    00136     if (!ped->fFocus)
    00137         return;
    00138
    00139     if (ped->fCaretHidden) {
    00140         NtUserSetCaretPos(-20000, -20000);
    00141         return;
    00142     }
    00143
    00144     xPosition = SLIchToLeftXPos(ped, hdc, ped->ichCaret);
    00145
    00146     /*
    00147      * Don't let caret go out of bounds of edit control if there is too much
    00148      * text.
    00149      */
    00150     if (ped->pLpkEditCallout) {
    00151         xPosition += ped->iCaretOffset;
    00152         xPosition = max(xPosition , 0);
    00153         xPosition = min(xPosition, ped->rcFmt.right - 1 -
    00154             ((ped->cxSysCharWidth > ped->aveCharWidth) ? 1 : 2));
    00155     } else {
    00156         xPosition = min(xPosition, ped->rcFmt.right -
    00157             ((ped->cxSysCharWidth > ped->aveCharWidth) ? 1 : 2));
    00158     }
    00159
    00160     NtUserSetCaretPos(xPosition, ped->rcFmt.top);
    00161
    00162     // FE_IME SLSetCaretPosition - ECImmSetCompostionWindow( CFS_POINT )
    00163     if (fpImmIsIME(THREAD_HKL())) {
    00164         ECImmSetCompositionWindow(ped, xPosition, ped->rcFmt.top);
    00165     }
    00166 }
    00167
    00168 /***************************************************************************\
    00169 * SLIchToLeftXPos AorW
    00170 *
    00171 * Given a character index, find its (left side) x coordinate within
    00172 * the ped->rcFmt rectangle assuming the character ped->ichScreenStart is at
    00173 * coordinates (ped->rcFmt.top, ped->rcFmt.left). A negative value is
    00174 * return ed if the character ich is to the left of ped->ichScreenStart. WARNING:
    00175 * ASSUMES AT MOST 1000 characters will be VISIBLE at one time on the screen.
    00176 * There may be 64K total characters in the editcontrol, but we can only
    00177 * display 1000 without scrolling. This shouldn't be a problem obviously.
    00178 * !NT
    00179 * History:
    00180 \***************************************************************************/
    00181
    00182 int SLIchToLeftXPos(
    00183     PED ped,
    00184     HDC hdc,
    00185     ICH ich)
    00186 {
    00187     int textExtent;
    00188     PSTR pText;
    00189     SIZE size;
    00190     int  cchDiff;
    00191
    00192     if (ped->pLpkEditCallout) {
    00193
    00194        pText = ECLock(ped);
    00195        textExtent = ped->pLpkEditCallout->EditIchToXY(ped, hdc, pText, ped->cch, ich);
    00196        ECUnlock(ped);
    00197
    00198        return textExtent;
    00199
    00200     }
    00201
    00202     /*
    00203      * Check if we are adding lots and lots of chars. A paste for example could
    00204      * cause this and GetTextExtents could overflow on this.
    00205      */
    00206     cchDiff = (int)ich - (int)ped->ichScreenStart;
    00207     if (cchDiff > 1000)
    00208         return (30000);
    00209     else if (cchDiff < -1000)
    00210         return (-30000);
    00211
    00212     if (ped->format != ES_LEFT)
    00213         return (ped->rcFmt.left + SLCalcXOffsetSpecial(ped, hdc, ich));
    00214
    00215     /*
    00216      * Caret position /w DBCS text, we can not optimize...
    00217      */
    00218     if (ped->fNonPropFont && !ped->fDBCS)
    00219         return (ped->rcFmt.left + cchDiff*ped->aveCharWidth);
    00220
    00221     /*
    00222      * Check if password hidden chars are being used.
    00223      */
    00224     if (ped->charPasswordChar)
    00225         return ( ped->rcFmt.left + cchDiff*ped->cPasswordCharWidth);
    00226
    00227     pText = ECLock(ped);
    00228
    00229     if (ped->fAnsi) {
    00230         if (cchDiff >= 0) {
    00231
    00232             GetTextExtentPointA(hdc, (LPSTR)(pText + ped->ichScreenStart),
    00233                     cchDiff, &size);
    00234             textExtent =  size.cx;
    00235
    00236             /*
    00237              * In case of signed/unsigned overflow since the text extent may be
    00238              * greater than maxint. This happens with long single line edit
    00239              * controls. The rect we edit text in will never be greater than 30000
    00240              * pixels so we are ok if we just ignore them.
    00241              */
    00242             if (textExtent < 0 || textExtent > 31000)
    00243                 textExtent = 30000;
    00244         } else {
    00245             GetTextExtentPointA(hdc,(LPSTR)(pText + ich), -cchDiff, &size);
    00246             textExtent = (-1) * size.cx;
    00247         }
    00248     } else {
    00249         if (cchDiff >= 0) {
    00250
    00251             GetTextExtentPointW(hdc, (LPWSTR)(pText + ped->ichScreenStart*sizeof(WCHAR)),
    00252                     cchDiff, &size);
    00253             textExtent =  size.cx;
    00254
    00255             /*
    00256              * In case of signed/unsigned overflow since the text extent may be
    00257              * greater than maxint. This happens with long single line edit
    00258              * controls. The rect we edit text in will never be greater than 30000
    00259              * pixels so we are ok if we just ignore them.
    00260              */
    00261             if (textExtent < 0 || textExtent > 31000)
    00262                 textExtent = 30000;
    00263         } else {
    00264             GetTextExtentPointW(hdc,(LPWSTR)(pText + ich*sizeof(WCHAR)), -cchDiff, &size);
    00265             textExtent = (-1) * size.cx;
    00266         }
    00267     }
    00268
    00269     ECUnlock(ped);
    00270
    00271     return (ped->rcFmt.left + textExtent -
    00272             (textExtent ? ped->charOverhang : 0));
    00273 }
    00274
    00275 /***************************************************************************\
    00276 * SLSetSelection AorW
    00277 *
    00278 * Sets the PED to have the new selection specified.
    00279 *
    00280 * History:
    00281 \***************************************************************************/
    00282
    00283 void SLSetSelection(
    00284     PED ped,
    00285     ICH ichSelStart,
    00286     ICH ichSelEnd)
    00287 {
    00288     HDC hdc = ECGetEditDC(ped, FALSE );
    00289
    00290     if (ichSelStart == 0xFFFFFFFF) {
    00291
    00292         /*
    00293          * Set no selection if we specify -1
    00294          */
    00295         ichSelStart = ichSelEnd = ped->ichCaret;
    00296     }
    00297
    00298     /*
    00299      * Bounds ichSelStart, ichSelEnd are checked in SLChangeSelection...
    00300      */
    00301     SLChangeSelection(ped, hdc, ichSelStart, ichSelEnd);
    00302
    00303     /*
    00304      * Put the caret at the end of the selected text
    00305      */
    00306     ped->ichCaret = ped->ichMaxSel;
    00307
    00308     SLSetCaretPosition(ped, hdc);
    00309
    00310     /*
    00311      * We may need to scroll the text to bring the caret into view...
    00312      */
    00313     SLScrollText(ped, hdc);
    00314
    00315     ECReleaseEditDC(ped, hdc, FALSE);
    00316 }
    00317
    00318 /***************************************************************************\
    00319 *
    00320 *  SLGetClipRect()
    00321 *
    00322 \***************************************************************************/
    00323 void   SLGetClipRect(
    00324     PED     ped,
    00325     HDC     hdc,
    00326     ICH     ichStart,
    00327     int     iCount,
    00328     LPRECT  lpClipRect )
    00329 {
    00330     int    iStCount;
    00331     PSTR   pText;
    00332
    00333     if (ped->pLpkEditCallout) {
    00334         RIPMSG0(RIP_WARNING, "SLGetClipRect - Error - Invalid call with language pack loaded");
    00335         memset(lpClipRect, 0, sizeof(RECT));
    00336         return;
    00337     }
    00338
    00339     CopyRect(lpClipRect, &ped->rcFmt);
    00340
    00341     pText = ECLock(ped) ;
    00342
    00343     // Calculates the starting pos for this piece of text
    00344     if ((iStCount = (int)(ichStart - ped->ichScreenStart)) > 0) {
    00345         if (ped->format == ES_LEFT) {
    00346             lpClipRect->left += SLCalcXOffsetLeft(ped, hdc, ichStart);
    00347         }
    00348     } else {
    00349             // Reset the values to visible portions
    00350             iCount -= (ped->ichScreenStart - ichStart);
    00351             ichStart = ped->ichScreenStart;
    00352     }
    00353
    00354     if (ped->format != ES_LEFT) {
    00355         lpClipRect->left += SLCalcXOffsetSpecial(ped, hdc, ichStart);
    00356     }
    00357
    00358     if (iCount < 0) {
    00359         /*
    00360          * This is not in the visible area of the edit control, so return
    00361          * an empty rect.
    00362          */
    00363         SetRectEmpty(lpClipRect);
    00364         ECUnlock(ped);
    00365         return;
    00366     }
    00367
    00368     if (ped->charPasswordChar)
    00369              lpClipRect->right = lpClipRect->left + ped->cPasswordCharWidth * iCount;
    00370     else {
    00371         SIZE size ;
    00372
    00373         if ( ped->fAnsi) {
    00374             GetTextExtentPointA(hdc, pText + ichStart, iCount, &size);
    00375         } else {
    00376             GetTextExtentPointW(hdc, ((LPWSTR)pText) + ichStart, iCount, &size);
    00377         }
    00378         lpClipRect->right = lpClipRect->left + size.cx - ped->charOverhang;
    00379     }
    00380
    00381     ECUnlock(ped);
    00382 }
    00383
    00384 /***************************************************************************\
    00385 * SLChangeSelection AorW
    00386 *
    00387 * Changes the current selection to have the specified starting and
    00388 * ending values. Properly highlights the new selection and unhighlights
    00389 * anything deselected. If NewMinSel and NewMaxSel are out of order, we swap
    00390 * them. Doesn't update the caret position.
    00391 *
    00392 * History:
    00393 \***************************************************************************/
    00394
    00395 void SLChangeSelection(
    00396     PED ped,
    00397     HDC hdc,
    00398     ICH ichNewMinSel,
    00399     ICH ichNewMaxSel)
    00400 {
    00401     ICH temp;
    00402     ICH ichOldMinSel;
    00403     ICH ichOldMaxSel;
    00404
    00405     if (ichNewMinSel > ichNewMaxSel) {
    00406         temp = ichNewMinSel;
    00407         ichNewMinSel = ichNewMaxSel;
    00408         ichNewMaxSel = temp;
    00409     }
    00410     ichNewMinSel = min(ichNewMinSel, ped->cch);
    00411     ichNewMaxSel = min(ichNewMaxSel, ped->cch);
    00412
    00413     //
    00414     // To avoid position to half of DBCS, check and ajust position if necessary
    00415     //
    00416     // We check ped->fDBCS and ped->fAnsi though ECAdjustIch checks these bits.
    00417     // We're worrying about the overhead of EcLock and EcUnlock.
    00418     //
    00419     if (ped->fDBCS && ped->fAnsi) {
    00420         PSTR pText;
    00421
    00422         pText = ECLock(ped);
    00423         ichNewMinSel = ECAdjustIch( ped, pText, ichNewMinSel );
    00424         ichNewMaxSel = ECAdjustIch( ped, pText, ichNewMaxSel );
    00425         ECUnlock(ped);
    00426     }
    00427
    00428     /*
    00429      * Preserve the Old selection
    00430      */
    00431     ichOldMinSel = ped->ichMinSel;
    00432     ichOldMaxSel = ped->ichMaxSel;
    00433
    00434     /*
    00435      * Set new selection
    00436      */
    00437     ped->ichMinSel = ichNewMinSel;
    00438     ped->ichMaxSel = ichNewMaxSel;
    00439
    00440     /*
    00441      * We will find the intersection of current selection rectangle with the new
    00442      * selection rectangle. We will then invert the parts of the two rectangles
    00443      * not in the intersection.
    00444      */
    00445     if (_IsWindowVisible(ped->pwnd) && (ped->fFocus || ped->fNoHideSel)) {
    00446         BLOCK Blk[2];
    00447         int   i;
    00448         RECT  rc;
    00449
    00450         if (ped->fFocus)
    00451             NtUserHideCaret(ped->hwnd);
    00452
    00453         if (ped->pLpkEditCallout) {
    00454             /*
    00455              * The language pack handles display while complex script support present
    00456              */
    00457             PSTR pText;
    00458
    00459             ECGetBrush(ped, hdc);   // Give user a chance to manipulate the DC
    00460             pText = ECLock(ped);
    00461             ped->pLpkEditCallout->EditDrawText(ped, hdc, pText, ped->cch, ped->ichMinSel, ped->ichMaxSel, ped->rcFmt.top);
    00462             ECUnlock(ped);
    00463         } else {
    00464             Blk[0].StPos = ichOldMinSel;
    00465             Blk[0].EndPos = ichOldMaxSel;
    00466             Blk[1].StPos = ped->ichMinSel;
    00467             Blk[1].EndPos = ped->ichMaxSel;
    00468
    00469             if (ECCalcChangeSelection(ped, ichOldMinSel, ichOldMaxSel,
    00470                 (LPBLOCK)&Blk[0], (LPBLOCK)&Blk[1])) {
    00471
    00472                 //
    00473                 // Paint the rectangles where selection has changed.
    00474                 // Paint both Blk[0] and Blk[1], if they exist.
    00475                 //
    00476                 for (i = 0; i < 2; i++) {
    00477                     if (Blk[i].StPos != 0xFFFFFFFF) {
    00478                                SLGetClipRect(ped, hdc, Blk[i].StPos,
    00479                                                        Blk[i].EndPos - Blk[i].StPos, (LPRECT)&rc);
    00480                                SLDrawLine(ped, hdc, rc.left, rc.right, Blk[i].StPos,
    00481                                                     Blk[i].EndPos - Blk[i].StPos,
    00482                                           ((Blk[i].StPos >= ped->ichMinSel) &&
    00483                                        (Blk[i].StPos < ped->ichMaxSel)));
    00484                     }
    00485                 }
    00486             }
    00487         }
    00488
    00489         //
    00490         // Update caret.
    00491         //
    00492         SLSetCaretPosition(ped, hdc);
    00493
    00494         if (ped->fFocus)
    00495             NtUserShowCaret(ped->hwnd);
    00496     }
    00497 }
    00498
    00499 /***************************************************************************\
    00500 *
    00501 *  SLDrawLine()
    00502 *
    00503 *  This draws the line starting from ichStart, iCount number of characters;
    00504 *  fSelStatus is TRUE if we're to draw the text as selected.
    00505 *
    00506 \***************************************************************************/
    00507 void SLDrawLine(
    00508     PED     ped,
    00509     HDC     hdc,
    00510     int     xClipStPos,
    00511     int     xClipEndPos,
    00512     ICH     ichStart,
    00513     int     iCount,
    00514     BOOL    fSelStatus )
    00515 {
    00516     RECT    rc;
    00517     RECT    rcClip;
    00518     PSTR    pText;
    00519     DWORD   rgbSaveBk;
    00520     DWORD   rgbSaveText;
    00521     DWORD   wSaveBkMode;
    00522     int     iStCount;
    00523     ICH     ichNewStart;
    00524     HBRUSH  hbrBack;
    00525
    00526     if (ped->pLpkEditCallout) {
    00527         RIPMSG0(RIP_WARNING, "SLDrawLine - Error - Invalid call with language pack loaded");
    00528         return;
    00529     }
    00530
    00531     //
    00532     // Anything to draw?
    00533     //
    00534     if (xClipStPos >= xClipEndPos || !_IsWindowVisible(ped->pwnd) )
    00535         return;
    00536
    00537     if (ped->fAnsi && ped->fDBCS) {
    00538         PSTR pT,pTOrg;
    00539         int iTCount;
    00540
    00541         pText = ECLock(ped);
    00542         ichNewStart = 0;
    00543         if (ichStart > 0) {
    00544             pT = pText + ichStart;
    00545             ichNewStart = ichStart;
    00546
    00547             while (ichNewStart &&
    00548                   (ichStart - ichNewStart < ped->wMaxNegCcharPos)) {
    00549                 pT = ECAnsiPrev(ped, pText, pT);
    00550                 ichNewStart = (ICH)(pT - pText);
    00551                 if (!ichNewStart)
    00552                     break;
    00553             }
    00554
    00555             // B#16152 - win95.
    00556             // In case of T2, SLE always set an additional margin
    00557             // to erase a character (iCount == 0 case), using aveCharWidth.
    00558             // It erases unexpected an extra char if we don't use ichNewStart
    00559             // and it happens when wMaxNegCcharPos == 0.
    00560             //
    00561             if (ped->wMaxNegCcharPos == 0 && iCount == 0) {
    00562                 pT = ECAnsiPrev(ped, pText, pT);
    00563                 ichNewStart = (ICH)(pT - pText);
    00564             }
    00565         }
    00566
    00567         iTCount = 0;
    00568         if (ichStart + iCount < ped->cch) {
    00569             pTOrg = pT = pText + ichStart + iCount;
    00570             while ((iTCount < (int)ped->wMaxNegAcharPos) &&
    00571                    (ichStart + iCount + iTCount < ped->cch)) {
    00572                 pT = ECAnsiNext(ped, pT);
    00573                 iTCount = (int)(pT - pTOrg);
    00574             }
    00575         }
    00576
    00577         ECUnlock(ped);
    00578         iCount = (int)(min(ichStart+iCount+iTCount, ped->cch) - ichNewStart);
    00579     } else {
    00580         // Reset ichStart to take care of the negative C widths
    00581         ichNewStart = max((int)(ichStart - ped->wMaxNegCcharPos), 0);
    00582
    00583         // Reset ichCount to take care of the negative C and A widths
    00584         iCount = (int)(min(ichStart+iCount+ped->wMaxNegAcharPos, ped->cch)
    00585                     - ichNewStart);
    00586     }
    00587     ichStart = ichNewStart;
    00588
    00589     //
    00590     // Reset ichStart and iCount to the first one visible on the screen
    00591     //
    00592     if (ichStart < ped->ichScreenStart) {
    00593         if (ichStart+iCount < ped->ichScreenStart)
    00594             return;
    00595
    00596         iCount -= (ped->ichScreenStart-ichStart);
    00597         ichStart = ped->ichScreenStart;
    00598     }
    00599
    00600     CopyRect(&rc, &ped->rcFmt);
    00601
    00602     //
    00603     // Set the drawing rectangle
    00604     //
    00605     rcClip.left   = xClipStPos;
    00606     rcClip.right  = xClipEndPos;
    00607     rcClip.top    = rc.top;
    00608     rcClip.bottom = rc.bottom;
    00609
    00610     //
    00611     // Set the proper clipping rectangle
    00612     //
    00613     ECSetEditClip(ped, hdc, TRUE);
    00614
    00615     pText = ECLock(ped);
    00616
    00617     //
    00618     // Calculate the starting pos for this piece of text
    00619     //
    00620     if (ped->format == ES_LEFT) {
    00621         if (iStCount = (int)(ichStart - ped->ichScreenStart)) {
    00622             rc.left += SLCalcXOffsetLeft(ped, hdc, ichStart);
    00623         }
    00624     } else {
    00625         rc.left += SLCalcXOffsetSpecial(ped, hdc, ichStart);
    00626     }
    00627
    00628     //
    00629     // Set the background mode before calling NtUserGetControlBrush so that the app
    00630     // can change it to TRANSPARENT if it wants to.
    00631     //
    00632     SetBkMode(hdc, OPAQUE);
    00633
    00634     if (fSelStatus) {
    00635         hbrBack = SYSHBR(HIGHLIGHT);
    00636         if (hbrBack == NULL) {
    00637             goto sldl_errorexit;
    00638         }
    00639         rgbSaveBk = SetBkColor(hdc, GetSysColor(COLOR_HIGHLIGHT));
    00640         rgbSaveText = SetTextColor(hdc, GetSysColor(COLOR_HIGHLIGHTTEXT));
    00641
    00642     } else {
    00643         //
    00644         // We always want to send this so that the app has a chance to muck
    00645         // with the DC.
    00646         //
    00647         // Note that ReadOnly and Disabled edit fields are drawn as "static"
    00648         // instead of as "active."
    00649         //
    00650         hbrBack = ECGetBrush(ped, hdc);
    00651         rgbSaveText = GetTextColor(hdc);
    00652     }
    00653
    00654     //
    00655     // Erase the rectangular area before text is drawn. Note that we inflate
    00656     // the rect by 1 so that the selection color has a one pixel border around
    00657     // the text.
    00658     //
    00659     InflateRect(&rcClip, 0, 1);
    00660     FillRect(hdc, &rcClip, hbrBack);
    00661     InflateRect(&rcClip, 0, -1);
    00662
    00663     if (ped->charPasswordChar) {
    00664         wSaveBkMode = SetBkMode(hdc, TRANSPARENT);
    00665
    00666         for (iStCount = 0; iStCount < iCount; iStCount++) {
    00667             if ( ped->fAnsi )
    00668                 ExtTextOutA(hdc, rc.left, rc.top, ETO_CLIPPED, &rcClip,
    00669                             (LPSTR)&ped->charPasswordChar, 1, NULL);
    00670             else
    00671                 ExtTextOutW(hdc, rc.left, rc.top, ETO_CLIPPED, &rcClip,
    00672                             (LPWSTR)&ped->charPasswordChar, 1, NULL);
    00673
    00674             rc.left += ped->cPasswordCharWidth;
    00675         }
    00676
    00677         SetBkMode(hdc, wSaveBkMode);
    00678     } else {
    00679         if ( ped->fAnsi )
    00680             ExtTextOutA(hdc, rc.left, rc.top, ETO_CLIPPED, &rcClip,
    00681                     pText+ichStart,iCount, NULL);
    00682         else
    00683             ExtTextOutW(hdc, rc.left, rc.top, ETO_CLIPPED, &rcClip,
    00684                     ((LPWSTR)pText)+ichStart,iCount, NULL);
    00685     }
    00686
    00687     SetTextColor(hdc, rgbSaveText);
    00688     if (fSelStatus) {
    00689         SetBkColor(hdc, rgbSaveBk);
    00690     }
    00691
    00692 sldl_errorexit:
    00693     ECUnlock(ped);
    00694 }
    00695
    00696 /***************************************************************************\
    00697 * SLGetBlkEnd AorW
    00698 *
    00699 * Given a Starting point and and end point, this function return s whether the
    00700 * first few characters fall inside or outside the selection block and if so,
    00701 * howmany characters?
    00702 *
    00703 * History:
    00704 \***************************************************************************/
    00705
    00706 int SLGetBlkEnd(
    00707     PED ped,
    00708     ICH ichStart,
    00709     ICH ichEnd,
    00710     BOOL FAR *lpfStatus)
    00711 {
    00712     *lpfStatus = FALSE;
    00713     if (ichStart >= ped->ichMinSel) {
    00714         if (ichStart >= ped->ichMaxSel)
    00715             return (ichEnd - ichStart);
    00716         *lpfStatus = TRUE;
    00717         return (min(ichEnd, ped->ichMaxSel) - ichStart);
    00718     }
    00719     return (min(ichEnd, ped->ichMinSel) - ichStart);
    00720 }
    00721
    00722 /***************************************************************************\
    00723 * SLDrawText AorW
    00724 *
    00725 * Draws text for a single line edit control in the rectangle
    00726 * specified by ped->rcFmt. If ichStart == 0, starts drawing text at the left
    00727 * side of the window starting at character index ped->ichScreenStart and draws
    00728 * as much as will fit. If ichStart > 0, then it appends the characters
    00729 * starting at ichStart to the end of the text showing in the window. (ie. We
    00730 * are just growing the text length and keeping the left side
    00731 * (ped->ichScreenStart to ichStart characters) the same. Assumes the hdc came
    00732 * from ECGetEditDC so that the caret and such are properly hidden.
    00733 *
    00734 * History:
    00735 \***************************************************************************/
    00736
    00737 void SLDrawText(
    00738     PED ped,
    00739     HDC hdc,
    00740     ICH ichStart)
    00741 {
    00742     ICH    cchToDraw;
    00743     RECT   rc;
    00744     PSTR   pText;
    00745     BOOL   fSelStatus;
    00746     int    iCount, iStCount;
    00747     ICH    ichEnd;
    00748     BOOL   fNoSelection;
    00749     BOOL   fCalcRect;
    00750     BOOL   fDrawLeftMargin = FALSE;
    00751     BOOL   fDrawEndOfLineStrip = FALSE;
    00752     SIZE   size;
    00753
    00754     if (!_IsWindowVisible(ped->pwnd))
    00755         return;
    00756
    00757     if (ped->pLpkEditCallout) {
    00758         // The language pack handles display while complex script support present
    00759         ECGetBrush(ped, hdc);   // Give user a chance to manipulate the DC
    00760         pText = ECLock(ped);
    00761         ped->pLpkEditCallout->EditDrawText(ped, hdc, pText, ped->cch, ped->ichMinSel, ped->ichMaxSel, ped->rcFmt.top);
    00762         ECUnlock(ped);
    00763         SLSetCaretPosition(ped, hdc);
    00764         return;
    00765     }
    00766
    00767     /*
    00768      * When drawing the entire visible content of special-aligned sle
    00769      * erase the view.
    00770      */
    00771     if (ped->format != ES_LEFT && ichStart == 0)
    00772         FillRect(hdc, &ped->rcFmt, ECGetBrush(ped, hdc));
    00773
    00774     pText = ECLock(ped);
    00775
    00776     if (ichStart < ped->ichScreenStart) {
    00777 #if DBG
    00778         ICH ichCompare = ECAdjustIch(ped, pText, ped->ichScreenStart);
    00779         UserAssert(ichCompare == ped->ichScreenStart);
    00780 #endif
    00781         ichStart = ped->ichScreenStart;
    00782     }
    00783     else if (ped->fDBCS && ped->fAnsi) {
    00784         /*
    00785          * If ichStart stays on trailing byte of DBCS, we have to
    00786          * adjust it.
    00787          */
    00788         ichStart = ECAdjustIch(ped, pText, ichStart);
    00789     }
    00790
    00791     CopyRect((LPRECT)&rc, (LPRECT)&ped->rcFmt);
    00792
    00793     /*
    00794      * Find out how many characters will fit on the screen so that we don't do
    00795      * any needless drawing.
    00796      */
    00797     cchToDraw = ECCchInWidth(ped, hdc,
    00798             (LPSTR)(pText + ped->ichScreenStart * ped->cbChar),
    00799             ped->cch - ped->ichScreenStart, rc.right - rc.left, TRUE);
    00800     ichEnd = ped->ichScreenStart + cchToDraw;
    00801
    00802     /*
    00803      * There is no selection if,
    00804      * 1. MinSel and MaxSel are equal OR
    00805      * 2. (This has lost the focus AND Selection is to be hidden)
    00806      */
    00807     fNoSelection = ((ped->ichMinSel == ped->ichMaxSel) || (!ped->fFocus && !ped->fNoHideSel));
    00808
    00809     if (ped->format == ES_LEFT) {
    00810         if (iStCount = (int)(ichStart - ped->ichScreenStart)) {
    00811             rc.left += SLCalcXOffsetLeft(ped, hdc, ichStart);
    00812         }
    00813     } else {
    00814         rc.left += SLCalcXOffsetSpecial(ped, hdc, ichStart);
    00815     }
    00816
    00817     //
    00818     // If this is the begining of the whole line, we may have to draw a blank
    00819     // strip at the begining.
    00820     //
    00821     if ((ichStart == 0) && ped->wLeftMargin)
    00822         fDrawLeftMargin = TRUE;
    00823
    00824     //
    00825     // If there is nothing to draw, that means we need to draw the end of
    00826     // line strip, which erases the last character.
    00827     //
    00828     if (ichStart == ichEnd) {
    00829         fDrawEndOfLineStrip = TRUE;
    00830         rc.left -= ped->wLeftMargin;
    00831     }
    00832
    00833     while (ichStart < ichEnd) {
    00834         fCalcRect = TRUE;
    00835
    00836         if (fNoSelection) {
    00837             fSelStatus = FALSE;
    00838             iCount = ichEnd - ichStart;
    00839         } else {
    00840             if (fDrawLeftMargin) {
    00841                 iCount = 0;
    00842                 fSelStatus = FALSE;
    00843                 fCalcRect = FALSE;
    00844                 rc.right = rc.left;
    00845             } else
    00846                 iCount = SLGetBlkEnd(ped, ichStart, ichEnd,
    00847                     (BOOL  *)&fSelStatus);
    00848         }
    00849
    00850
    00851         if (ichStart+iCount == ichEnd) {
    00852             if (fSelStatus)
    00853                 fDrawEndOfLineStrip = TRUE;
    00854             else {
    00855                 rc.right = ped->rcFmt.right + ped->wRightMargin;
    00856                 fCalcRect = FALSE;
    00857             }
    00858         }
    00859
    00860         if (fCalcRect) {
    00861             if (ped->charPasswordChar)
    00862                 rc.right = rc.left + ped->cPasswordCharWidth * iCount;
    00863             else {
    00864                 if ( ped->fAnsi )
    00865                     GetTextExtentPointA(hdc, pText + ichStart,
    00866                                         iCount, &size);
    00867                 else
    00868                     GetTextExtentPointW(hdc, ((LPWSTR)pText) + ichStart,
    00869                                         iCount, &size);
    00870                 rc.right = rc.left + size.cx;
    00871                 /*
    00872                  * The extent is equal to the advance width. So for TrueType fonts
    00873                  *  we need to take care of Neg A and C. For non TrueType, the extent
    00874                  *  includes the overhang.
    00875                  * If drawing the selection, draw only the advance width
    00876                  */
    00877                 if (fSelStatus) {
    00878                     rc.right -= ped->charOverhang;
    00879                 } else if (ped->fTrueType) {
    00880                    rc.right += ped->wMaxNegC;
    00881                    if (iStCount > 0) {
    00882                       rc.right += ped->wMaxNegA;
    00883                       iStCount = 0;
    00884                    }
    00885                 }
    00886
    00887             } /* if (ped->charPasswordChar) */
    00888
    00889         }
    00890
    00891         if (fDrawLeftMargin) {
    00892             fDrawLeftMargin = FALSE;
    00893             rc.left -= ped->wLeftMargin;
    00894             if (rc.right < rc.left) {
    00895                 rc.right = rc.left;
    00896             }
    00897         }
    00898
    00899         SLDrawLine(ped, hdc, rc.left, rc.right, ichStart, iCount, fSelStatus);
    00900         ichStart += iCount;
    00901         rc.left = rc.right;
    00902         /*
    00903          * If we're going to draw the selection, adjust rc.left
    00904          * to include advance width of the selected text
    00905          * For non TT fonts, ped->wMaxNegC equals ped->charOverhang
    00906          */
    00907         if (!fSelStatus && (iCount != 0) && (ichStart < ichEnd)) {
    00908             rc.left -= ped->wMaxNegC;
    00909         }
    00910     }
    00911
    00912     ECUnlock(ped);
    00913
    00914     // Check if anything to be erased on the right hand side
    00915     if (fDrawEndOfLineStrip &&
    00916             (rc.left < (rc.right = (ped->rcFmt.right+ped->wRightMargin))))
    00917         SLDrawLine(ped, hdc, rc.left, rc.right, ichStart, 0, FALSE);
    00918
    00919     SLSetCaretPosition(ped, hdc);
    00920 }
    00921
    00922 /***************************************************************************\
    00923 * SLScrollText AorW
    00924 *
    00925 * Scrolls the text to bring the caret into view. If the text is
    00926 * scrolled, the current selection is unhighlighted. Returns TRUE if the text
    00927 * is scrolled else return s false.
    00928 *
    00929 * History:
    00930 \***************************************************************************/
    00931
    00932 BOOL SLScrollText(
    00933     PED ped,
    00934     HDC hdc)
    00935 {
    00936     PSTR pTextScreenStart;
    00937     ICH scrollAmount;
    00938     ICH newScreenStartX = ped->ichScreenStart;
    00939     ICH cch;
    00940     BOOLEAN fAdjustNext = FALSE;
    00941
    00942     if (!ped->fAutoHScroll)
    00943         return (FALSE);
    00944
    00945     if (ped->pLpkEditCallout) {
    00946         BOOL fChanged;
    00947
    00948         // With complex script glyph reordering, use lpk to do horz scroll
    00949         pTextScreenStart = ECLock(ped);
    00950         fChanged = ped->pLpkEditCallout->EditHScroll(ped, hdc, pTextScreenStart);
    00951         ECUnlock(ped);
    00952
    00953         if (fChanged) {
    00954             SLDrawText(ped, hdc, 0);
    00955         }
    00956
    00957         return fChanged;
    00958     }
    00959
    00960     /*
    00961      * Calculate the new starting screen position
    00962      */
    00963     if (ped->ichCaret <= ped->ichScreenStart) {
    00964
    00965         /*
    00966          * Caret is to the left of the starting text on the screen we must
    00967          * scroll the text backwards to bring it into view. Watch out when
    00968          * subtracting unsigned numbers when we have the possibility of going
    00969          * negative.
    00970          */
    00971         pTextScreenStart = ECLock(ped);
    00972
    00973         scrollAmount = ECCchInWidth(ped, hdc, (LPSTR)pTextScreenStart,
    00974                 ped->ichCaret, (ped->rcFmt.right - ped->rcFmt.left) / 4, FALSE);
    00975
    00976         newScreenStartX = ped->ichCaret - scrollAmount;
    00977         ECUnlock(ped);
    00978     } else if (ped->ichCaret != ped->ichScreenStart) {
    00979         pTextScreenStart = ECLock(ped);
    00980         pTextScreenStart += ped->ichScreenStart * ped->cbChar;
    00981
    00982         cch = ECCchInWidth(ped, hdc, (LPSTR)pTextScreenStart,
    00983                 ped->ichCaret - ped->ichScreenStart,
    00984                 ped->rcFmt.right - ped->rcFmt.left, FALSE);
    00985
    00986         if (cch < ped->ichCaret - ped->ichScreenStart) {
    00987             fAdjustNext = TRUE;
    00988
    00989             /*
    00990              * Scroll Forward 1/4 -- if that leaves some empty space
    00991              * at the end, scroll back enough to fill the space
    00992              */
    00993             newScreenStartX = ped->ichCaret - (3 * cch / 4);
    00994
    00995             cch = ECCchInWidth(ped, hdc, (LPSTR)pTextScreenStart,
    00996                     ped->cch - ped->ichScreenStart,
    00997                     ped->rcFmt.right - ped->rcFmt.left, FALSE);
    00998
    00999             if (newScreenStartX > (ped->cch - cch))
    01000                 newScreenStartX = ped->cch - cch;
    01001         } else if (ped->format != ES_LEFT) {
    01002
    01003             cch = ECCchInWidth(ped, hdc, (LPSTR)pTextScreenStart,
    01004                     ped->cch - ped->ichScreenStart,
    01005                     ped->rcFmt.right - ped->rcFmt.left, FALSE);
    01006
    01007            /*
    01008             * Scroll the text hidden behind the left border back
    01009             * into view.
    01010             */
    01011            if (ped->ichScreenStart == ped->cch - cch) {
    01012
    01013                pTextScreenStart -= ped->ichScreenStart * ped->cbChar;
    01014                cch = ECCchInWidth(ped, hdc, (LPSTR)pTextScreenStart,
    01015                        ped->cch, ped->rcFmt.right - ped->rcFmt.left, FALSE);
    01016
    01017                newScreenStartX = ped->cch - cch;
    01018            }
    01019         }
    01020
    01021         ECUnlock(ped);
    01022     }
    01023
    01024     //
    01025     // Adjust newScreenStartX
    01026     //
    01027     if (ped->fAnsi && ped->fDBCS) {
    01028         newScreenStartX = (fAdjustNext ? ECAdjustIchNext : ECAdjustIch)(ped,
    01029                                                                         ECLock(ped),
    01030                                                                         newScreenStartX);
    01031         ECUnlock(ped);
    01032     }
    01033
    01034     if (ped->ichScreenStart != newScreenStartX) {
    01035         // Check if we have to wipe out the left margin
    01036         if (ped->wLeftMargin && (ped->ichScreenStart == 0)) {
    01037             RECT   rc;
    01038             HBRUSH hBrush;
    01039
    01040             hBrush = ECGetBrush(ped, hdc);
    01041
    01042             CopyInflateRect(&rc, &ped->rcFmt, 0, 1);
    01043             rc.right = rc.left;
    01044             rc.left -= ped->wLeftMargin;
    01045
    01046             FillRect(hdc, &rc, hBrush);
    01047         }
    01048
    01049         ped->ichScreenStart = newScreenStartX;
    01050         SLDrawText(ped, hdc, 0);
    01051
    01052         // Caret pos is set by SLDrawText().
    01053         return TRUE;
    01054     }
    01055
    01056     return FALSE;
    01057 }
    01058
    01059 /***************************************************************************\
    01060 * SLInsertText AorW
    01061 *
    01062 * Adds up to cchInsert characters from lpText to the ped starting at
    01063 * ichCaret. If the ped only allows a maximum number of characters, then we
    01064 * will only add that many characters to the ped and send a EN_MAXTEXT
    01065 * notification code to the parent of the ec. Also, if !fAutoHScroll, then we
    01066 * only allow as many chars as will fit in the client rectangle. The number of
    01067 * characters actually added is return ed (could be 0). If we can't allocate
    01068 * the required space, we notify the parent with EN_ERRSPACE and no characters
    01069 * are added.
    01070 *
    01071 * History:
    01072 \***************************************************************************/
    01073
    01074 ICH SLInsertText(
    01075     PED ped,
    01076     LPSTR lpText,
    01077     ICH cchInsert)
    01078 {
    01079     HDC hdc;
    01080     PSTR pText;
    01081     ICH cchInsertCopy = cchInsert;
    01082     ICH cchT;
    01083     int textWidth;
    01084     SIZE size;
    01085
    01086     /*
    01087      * First determine exactly how many characters from lpText we can insert
    01088      * into the ped.
    01089      */
    01090     if( ped->cchTextMax <= ped->cch)
    01091        cchInsert = 0;
    01092     else {
    01093         if (!ped->fAutoHScroll) {
    01094             pText = ECLock(ped);
    01095             hdc = ECGetEditDC(ped, TRUE);
    01096
    01097             cchInsert = min(cchInsert, (unsigned)(ped->cchTextMax - ped->cch));
    01098             if (ped->charPasswordChar)
    01099                 textWidth = ped->cch * ped->cPasswordCharWidth;
    01100             else {
    01101                 if (ped->fAnsi)
    01102                     GetTextExtentPointA(hdc, (LPSTR)pText,  ped->cch, &size);
    01103                 else
    01104                     GetTextExtentPointW(hdc, (LPWSTR)pText, ped->cch, &size);
    01105                 textWidth = size.cx;
    01106             }
    01107             cchT = ECCchInWidth(ped, hdc, lpText, cchInsert,
    01108                                 ped->rcFmt.right - ped->rcFmt.left -
    01109                                 textWidth, TRUE);
    01110             cchInsert = min(cchInsert, cchT);
    01111
    01112             ECUnlock(ped);
    01113             ECReleaseEditDC(ped, hdc, TRUE);
    01114         } else {
    01115             cchInsert = min((unsigned)(ped->cchTextMax - ped->cch), cchInsert);
    01116         }
    01117     }
    01118
    01119
    01120     /*
    01121      * Now try actually adding the text to the ped
    01122      */
    01123     if (cchInsert && !ECInsertText(ped, lpText, &cchInsert)) {
    01124         ECNotifyParent(ped, EN_ERRSPACE);
    01125         return (0);
    01126     }
    01127     if (cchInsert)
    01128         ped->fDirty = TRUE; /* Set modify flag */
    01129
    01130     if (cchInsert < cchInsertCopy) {
    01131
    01132         /*
    01133          * Notify parent that we couldn't insert all the text requested
    01134          */
    01135         ECNotifyParent(ped, EN_MAXTEXT);
    01136     }
    01137
    01138     /*
    01139      * Update selection extents and the caret position. Note that ECInsertText
    01140      * updates ped->ichCaret, ped->ichMinSel, and ped->ichMaxSel to all be after
    01141      * the inserted text.
    01142      */
    01143     return (cchInsert);
    01144 }
    01145
    01146 /***************************************************************************\
    01147 * SLPasteText AorW
    01148 *
    01149 * Pastes a line of text from the clipboard into the edit control
    01150 * starting at ped->ichMaxSel. Updates ichMaxSel and ichMinSel to point to
    01151 * the end of the inserted text. Notifies the parent if space cannot be
    01152 * allocated. Returns how many characters were inserted.
    01153 *
    01154 * History:
    01155 \***************************************************************************/
    01156
    01157 ICH PASCAL NEAR SLPasteText(
    01158     PED ped)
    01159 {
    01160     HANDLE hData;
    01161     LPSTR lpchClip;
    01162     ICH cchAdded = 0;
    01163     ICH clipLength;
    01164
    01165     if (!OpenClipboard(ped->hwnd))
    01166         goto PasteExitNoCloseClip;
    01167
    01168     if (!(hData = GetClipboardData(ped->fAnsi ? CF_TEXT : CF_UNICODETEXT)) ||
    01169             (GlobalFlags(hData) == GMEM_INVALID_HANDLE)) {
    01170         RIPMSG1(RIP_WARNING, "SLPasteText(): couldn't get a valid handle(%x)", hData);
    01171         goto PasteExit;
    01172     }
    01173
    01174     USERGLOBALLOCK(hData, lpchClip);
    01175     if (lpchClip == NULL) {
    01176         RIPMSG1(RIP_WARNING, "SLPasteText(): USERGLOBALLOCK(%x) failed.", hData);
    01177         goto PasteExit;
    01178     }
    01179
    01180     if (ped->fAnsi) {
    01181         LPSTR lpchClip2 = lpchClip;
    01182
    01183         /*
    01184          * Find the first carrage return or line feed. Just add text to that point.
    01185          */
    01186         clipLength = (UINT)strlen(lpchClip);
    01187         for (cchAdded = 0; cchAdded < clipLength; cchAdded++)
    01188             if (*lpchClip2++ == 0x0D)
    01189                 break;
    01190
    01191     } else { // !fAnsi
    01192         LPWSTR lpwstrClip2 = (LPWSTR)lpchClip;
    01193
    01194         /*
    01195          * Find the first carrage return or line feed. Just add text to that point.
    01196          */
    01197         clipLength = (UINT)wcslen((LPWSTR)lpchClip);
    01198         for (cchAdded = 0; cchAdded < clipLength; cchAdded++)
    01199             if (*lpwstrClip2++ == 0x0D)
    01200                 break;
    01201     }
    01202
    01203     /*
    01204      * Insert the text (SLInsertText checks line length)
    01205      */
    01206     cchAdded = SLInsertText(ped, lpchClip, cchAdded);
    01207
    01208     USERGLOBALUNLOCK(hData);
    01209
    01210 PasteExit:
    01211     NtUserCloseClipboard();
    01212
    01213 PasteExitNoCloseClip:
    01214     return (cchAdded);
    01215 }
    01216
    01217 /***************************************************************************\
    01218 * SLReplaceSel AorW
    01219 *
    01220 * Replaces the text in the current selection with the given text.
    01221 *
    01222 * History:
    01223 \***************************************************************************/
    01224
    01225 void SLReplaceSel(
    01226     PED ped,
    01227     LPSTR lpText)
    01228 {
    01229     UINT cchText;
    01230
    01231     //
    01232     // Delete text, putting it into the clean undo buffer.
    01233     //
    01234     ECEmptyUndo(Pundo(ped));
    01235     ECDeleteText(ped);
    01236
    01237     //
    01238     // B#3356
    01239     // Some apps do "clear" by selecting all of the text, then replacing it
    01240     // with "", in which case SLInsertText() will return 0.  But that
    01241     // doesn't mean failure...
    01242     //
    01243     if ( ped->fAnsi )
    01244         cchText = strlen(lpText);
    01245     else
    01246         cchText = wcslen((LPWSTR)lpText);
    01247
    01248     if (cchText) {
    01249         BOOL fFailed;
    01250         UNDO undo;
    01251         HWND hwndSave;
    01252
    01253         //
    01254         // Save undo buffer, but DO NOT CLEAR IT!
    01255         //
    01256         ECSaveUndo(Pundo(ped), &undo, FALSE);
    01257
    01258         hwndSave = ped->hwnd;
    01259         fFailed = (BOOL) !SLInsertText(ped, lpText, cchText);
    01260         if (!IsWindow(hwndSave))
    01261             return;
    01262
    01263         if (fFailed) {
    01264             //
    01265             // UNDO the previous edit.
    01266             //
    01267             ECSaveUndo(&undo, Pundo(ped), FALSE);
    01268             SLUndo(ped);
    01269             return;
    01270         }
    01271     }
    01272
    01273     //
    01274     // Success.  So update the display
    01275     //
    01276     ECNotifyParent(ped, EN_UPDATE);
    01277
    01278     if (_IsWindowVisible(ped->pwnd)) {
    01279         HDC hdc;
    01280
    01281         hdc = ECGetEditDC(ped, FALSE);
    01282
    01283         if (!SLScrollText(ped, hdc))
    01284             SLDrawText(ped, hdc, 0);
    01285
    01286         ECReleaseEditDC(ped, hdc, FALSE);
    01287     }
    01288
    01289     ECNotifyParent(ped, EN_CHANGE);
    01290
    01291     if (FWINABLE()) {
    01292         NotifyWinEvent(EVENT_OBJECT_VALUECHANGE, ped->hwnd, OBJID_CLIENT, INDEXID_CONTAINER);
    01293     }
    01294 }
    01295
    01296 /***************************************************************************\
    01297 * SLChar AorW
    01298 *
    01299 * Handles character input
    01300 *
    01301 * History:
    01302 \***************************************************************************/
    01303
    01304 void SLChar(
    01305     PED ped,
    01306     DWORD keyValue)
    01307 {
    01308     HDC hdc;
    01309     WCHAR keyPress;
    01310     BOOL updateText = FALSE;
    01311     HWND hwndSave = ped->hwnd;
    01312     int InsertTextLen = 1;
    01313     int DBCSkey;
    01314
    01315     if (ped->fAnsi)
    01316         keyPress = LOBYTE(keyValue);
    01317     else
    01318         keyPress = LOWORD(keyValue);
    01319
    01320     if (ped->fMouseDown || (ped->fReadOnly && keyPress != 3)) {
    01321
    01322         /*
    01323          * Don't do anything if we are in the middle of a mousedown deal or if
    01324          * this is a read only edit control, with exception of allowing
    01325          * ctrl-C in order to copy to the clipboard.
    01326          */
    01327         return ;
    01328     }
    01329
    01330     if (IS_IME_ENABLED()) {
    01331         ECInOutReconversionMode(ped, FALSE);
    01332     }
    01333
    01334     switch (keyPress) {
    01335     case VK_BACK:
    01336 DeleteSelection:
    01337         if (ECDeleteText(ped))
    01338             updateText = TRUE;
    01339         break;
    01340
    01341     default:
    01342         if (keyPress >= TEXT(' '))
    01343         {
    01344             /*
    01345              * If this is in [a-z],[A-Z] and we are an ES_NUMBER
    01346              * edit field, bail.
    01347              */
    01348             if (ped->f40Compat && TestWF(ped->pwnd, EFNUMBER)) {
    01349                 if (!ECIsCharNumeric(ped, keyPress)) {
    01350                     goto IllegalChar;
    01351                 }
    01352             }
    01353             goto DeleteSelection;
    01354         }
    01355         break;
    01356     }
    01357
    01358     switch (keyPress) {
    01359     case 3:
    01360
    01361         /*
    01362          * CTRL-C Copy
    01363          */
    01364         SendMessage(ped->hwnd, WM_COPY, 0, 0L);
    01365         return;
    01366
    01367     case VK_BACK:
    01368
    01369         /*
    01370          * Delete any selected text or delete character left if no sel
    01371          */
    01372         if (!updateText && ped->ichMinSel) {
    01373
    01374             /*
    01375              * There was no selection to delete so we just delete character
    01376                left if available
    01377              */
    01378             //
    01379             // Calling PrevIch rather than just doing a decrement for VK_BACK
    01380             //
    01381             ped->ichMinSel = ECPrevIch( ped, NULL, ped->ichMinSel);
    01382             ECDeleteText(ped);
    01383             updateText = TRUE;
    01384         }
    01385         break;
    01386
    01387     case 22: /* CTRL-V Paste */
    01388         SendMessage(ped->hwnd, WM_PASTE, 0, 0L);
    01389         return;
    01390
    01391     case 24: /* CTRL-X Cut */
    01392         if (ped->ichMinSel == ped->ichMaxSel)
    01393             goto IllegalChar;
    01394
    01395         SendMessage(ped->hwnd, WM_CUT, 0, 0L);
    01396         return;
    01397
    01398     case 26: /* CTRL-Z Undo */
    01399         SendMessage(ped->hwnd, EM_UNDO, 0, 0L);
    01400         return;
    01401
    01402     case VK_RETURN:
    01403     case VK_ESCAPE:
    01404         //
    01405         // If this is an edit control for a combobox and the dropdown list
    01406         // is visible, forward it up to the combo.
    01407         //
    01408         if (ped->listboxHwnd && SendMessage(ped->hwndParent, CB_GETDROPPEDSTATE, 0, 0L)) {
    01409             SendMessage(ped->hwndParent, WM_KEYDOWN, (WPARAM)keyPress, 0L);
    01410         } else
    01411             goto IllegalChar;
    01412         return;
    01413
    01414     default:
    01415         if (keyPress >= 0x1E) {  // 1E,1F are unicode block and segment separators
    01416             /*
    01417              * Hide the cursor if typing, if the mouse is captured, do not mess with this
    01418              * as it is going to desapear forever (no WM_SETCURSOR is sent to restore it
    01419              * at the first mouse-move)
    01420              * MCostea #166951
    01421              */
    01422             NtUserCallNoParam(SFI_ZZZHIDECURSORNOCAPTURE);
    01423
    01424             if (IS_DBCS_ENABLED() && ped->fAnsi && (ECIsDBCSLeadByte(ped,(BYTE)keyPress))) {
    01425                 if ((DBCSkey = DbcsCombine(ped->hwnd, keyPress)) != 0 &&
    01426                      SLInsertText(ped,(LPSTR)&DBCSkey, 2) == 2) {
    01427                     InsertTextLen = 2;
    01428                     updateText = TRUE;
    01429                 } else {
    01430                     NtUserMessageBeep(0);
    01431                 }
    01432             } else {  // Here the original code begins
    01433                 InsertTextLen = 1;
    01434                 if (SLInsertText(ped, (LPSTR)&keyPress, 1))
    01435                     updateText = TRUE;
    01436                 else
    01437
    01438                     /*
    01439                      * Beep. Since we couldn't add the text
    01440                      */
    01441                     NtUserMessageBeep(0);
    01442             } // Here the original code ends
    01443         } else {
    01444
    01445             /*
    01446              * User hit an illegal control key
    01447              */
    01448 IllegalChar:
    01449             NtUserMessageBeep(0);
    01450         }
    01451
    01452         if (!IsWindow(hwndSave))
    01453             return;
    01454         break;
    01455     }
    01456
    01457     if (updateText) {
    01458
    01459         /*
    01460          * Dirty flag (ped->fDirty) was set when we inserted text
    01461          */
    01462         ECNotifyParent(ped, EN_UPDATE);
    01463         hdc = ECGetEditDC(ped, FALSE);
    01464         if (!SLScrollText(ped, hdc)) {
    01465             if (ped->format == ES_LEFT) {
    01466             //
    01467             // Call SLDrawText with correct ichStart
    01468             //
    01469                 SLDrawText(ped, hdc, max(0, (int)(ped->ichCaret - InsertTextLen - ped->wMaxNegCcharPos)));
    01470             } else {
    01471                 /*
    01472                  * We can't just draw from ichStart because string may have
    01473                  * shifted because of alignment.
    01474                  */
    01475                 SLDrawText(ped, hdc, 0);
    01476             }
    01477         }
    01478         ECReleaseEditDC(ped, hdc, FALSE);
    01479         ECNotifyParent(ped, EN_CHANGE);
    01480
    01481         if (FWINABLE()) {
    01482             NotifyWinEvent(EVENT_OBJECT_VALUECHANGE, ped->hwnd, OBJID_CLIENT, INDEXID_CONTAINER);
    01483         }
    01484     }
    01485 }
    01486
    01487 /***************************************************************************\
    01488 * SLMoveSelectionRestricted AorW
    01489 *
    01490 * Moves the selection like MLMoveSelection, but also obeys limitations
    01491 * imposed by some languages such as Thai, where the cursor cannot stop
    01492 * between a character and it's attached vowel or tone marks.
    01493 *
    01494 * Only called if the language pack is loaded.
    01495 *
    01496 \***************************************************************************/
    01497
    01498 ICH SLMoveSelectionRestricted(
    01499     PED  ped,
    01500     ICH  ich,
    01501     BOOL fLeft)
    01502 {
    01503     PSTR pText;
    01504     HDC  hdc;
    01505     ICH  ichResult;
    01506
    01507     pText = ECLock(ped);
    01508     hdc = ECGetEditDC(ped, TRUE);
    01509     ichResult = ped->pLpkEditCallout->EditMoveSelection(ped, hdc, pText, ich, fLeft);
    01510     ECReleaseEditDC(ped, hdc, TRUE);
    01511     ECUnlock(ped);
    01512
    01513     return ichResult;
    01514 }
    01515
    01516 /***************************************************************************\
    01517 * SLKeyDown AorW
    01518 *
    01519 * Handles cursor movement and other VIRT KEY stuff. keyMods allows
    01520 * us to make SLKeyDownHandler calls and specify if the modifier keys (shift
    01521 * and control) are up or down. This is useful for imnplementing the
    01522 * cut/paste/clear messages for single line edit controls. If keyMods == 0,
    01523 * we get the keyboard state using GetKeyState(VK_SHIFT) etc. Otherwise, the
    01524 * bits in keyMods define the state of the shift and control keys.
    01525 *
    01526 * History:
    01527 \***************************************************************************/
    01528
    01529 void SLKeyDown(
    01530     PED ped,
    01531     DWORD virtKeyCode,
    01532     int keyMods)
    01533 {
    01534     HDC hdc;
    01535
    01536     /*
    01537      * Variables we will use for redrawing the updated text
    01538      */
    01539     ICH newMaxSel = ped->ichMaxSel;
    01540     ICH newMinSel = ped->ichMinSel;
    01541
    01542     /*
    01543      * Flags for drawing the updated text
    01544      */
    01545     BOOL updateText = FALSE;
    01546     BOOL changeSelection = FALSE; /* new selection is specified by
    01547                                       newMinSel, newMaxSel */
    01548
    01549     /*
    01550      * Comparisons we do often
    01551      */
    01552     BOOL MinEqMax = (newMaxSel == newMinSel);
    01553     BOOL MinEqCar = (ped->ichCaret == newMinSel);
    01554     BOOL MaxEqCar = (ped->ichCaret == newMaxSel);
    01555
    01556     /*
    01557      * State of shift and control keys.
    01558      */
    01559     int scState;
    01560
    01561     /*
    01562      * Combo box support
    01563      */
    01564     BOOL fIsListVisible;
    01565     BOOL fIsExtendedUI;
    01566
    01567     if (ped->fMouseDown) {
    01568
    01569         /*
    01570          * If we are in the middle of a mouse down handler, then don't do
    01571          * anything. ie. ignore keyboard input.
    01572          */
    01573         return;
    01574     }
    01575
    01576     scState = ECGetModKeys(keyMods);
    01577
    01578     switch (virtKeyCode) {
    01579     case VK_UP:
    01580         if ( ped->listboxHwnd ) {
    01581
    01582             /*
    01583              * Handle Combobox support
    01584              */
    01585             fIsExtendedUI = (BOOL)SendMessage(ped->hwndParent, CB_GETEXTENDEDUI, 0, 0);
    01586             fIsListVisible = (BOOL)SendMessage(ped->hwndParent, CB_GETDROPPEDSTATE, 0, 0);
    01587
    01588             if (!fIsListVisible && fIsExtendedUI) {
    01589
    01590                 /*
    01591                  * For TandyT
    01592                  */
    01593 DropExtendedUIListBox:
    01594
    01595                 /*
    01596                  * Since an extendedui combo box doesn't do anything on f4, we
    01597                  * turn off the extended ui, send the f4 to drop, and turn it
    01598                  * back on again.
    01599                  */
    01600                 SendMessage(ped->hwndParent, CB_SETEXTENDEDUI, 0, 0);
    01601                 SendMessage(ped->listboxHwnd, WM_KEYDOWN, VK_F4, 0);
    01602                 SendMessage(ped->hwndParent, CB_SETEXTENDEDUI, 1, 0);
    01603                 return;
    01604             } else
    01605                 goto SendKeyToListBox;
    01606         }
    01607
    01608     /*
    01609      * else fall through
    01610      */
    01611     case VK_LEFT:
    01612         //
    01613         // If the caret isn't at the beginning, we can move left
    01614         //
    01615         if (ped->ichCaret) {
    01616             //
    01617             // Get new caret pos.
    01618             //
    01619             if (scState & CTRLDOWN) {
    01620                 // Move caret word left
    01621                 ECWord(ped, ped->ichCaret, TRUE, &ped->ichCaret, NULL);
    01622             } else {
    01623                 // Move caret char left
    01624                 if (ped->pLpkEditCallout) {
    01625                     ped->ichCaret = SLMoveSelectionRestricted(ped, ped->ichCaret, TRUE);
    01626                 } else
    01627                 ped->ichCaret = ECPrevIch(ped,NULL,ped->ichCaret);
    01628             }
    01629
    01630             //
    01631             // Get new selection
    01632             //
    01633             if (scState & SHFTDOWN) {
    01634                 if (MaxEqCar && !MinEqMax) {
    01635                     // Reduce selection
    01636                     newMaxSel = ped->ichCaret;
    01637
    01638                     UserAssert(newMinSel == ped->ichMinSel);
    01639                 } else {
    01640                     // Extend selection
    01641                     newMinSel = ped->ichCaret;
    01642                 }
    01643             } else {
    01644                 //
    01645                 // Clear selection
    01646                 //
    01647                 newMaxSel = newMinSel = ped->ichCaret;
    01648             }
    01649
    01650             changeSelection = TRUE;
    01651         } else {
    01652             //
    01653             // If the user tries to move left and we are at the 0th
    01654             // character and there is a selection, then cancel the
    01655             // selection.
    01656             //
    01657             if ( (ped->ichMaxSel != ped->ichMinSel) &&
    01658                 !(scState & SHFTDOWN) ) {
    01659                 changeSelection = TRUE;
    01660                 newMaxSel = newMinSel = ped->ichCaret;
    01661             }
    01662         }
    01663         break;
    01664
    01665     case VK_DOWN:
    01666         if (ped->listboxHwnd) {
    01667
    01668             /*
    01669              * Handle Combobox support
    01670              */
    01671             fIsExtendedUI = (BOOL)SendMessage(ped->hwndParent, CB_GETEXTENDEDUI, 0, 0);
    01672             fIsListVisible = (BOOL)SendMessage(ped->hwndParent, CB_GETDROPPEDSTATE, 0, 0);
    01673
    01674             if (!fIsListVisible && fIsExtendedUI) {
    01675
    01676                 /*
    01677                  * For TandyT
    01678                  */
    01679                 goto DropExtendedUIListBox;
    01680             } else
    01681                 goto SendKeyToListBox;
    01682         }
    01683
    01684     /*
    01685      * else fall through
    01686      */
    01687     case VK_RIGHT:
    01688         //
    01689         // If the caret isn't at the end, we can move right.
    01690         //
    01691         if (ped->ichCaret < ped->cch) {
    01692             //
    01693             // Get new caret pos.
    01694             //
    01695             if (scState & CTRLDOWN) {
    01696                 // Move caret word right
    01697                 ECWord(ped, ped->ichCaret, FALSE, NULL, &ped->ichCaret);
    01698             } else {
    01699                 // Move caret char right
    01700                 if (ped->pLpkEditCallout) {
    01701                     ped->ichCaret = SLMoveSelectionRestricted(ped, ped->ichCaret, FALSE);
    01702                 } else
    01703                 ped->ichCaret = ECNextIch(ped,NULL,ped->ichCaret);
    01704             }
    01705
    01706             //
    01707             // Get new selection.
    01708             //
    01709             if (scState & SHFTDOWN) {
    01710                 if (MinEqCar && !MinEqMax) {
    01711                     // Reduce selection
    01712                     newMinSel = ped->ichCaret;
    01713
    01714                     UserAssert(newMaxSel == ped->ichMaxSel);
    01715                 } else {
    01716                     // Extend selection
    01717                     newMaxSel = ped->ichCaret;
    01718                 }
    01719             } else {
    01720                 // Clear selection
    01721                 newMaxSel = newMinSel = ped->ichCaret;
    01722             }
    01723
    01724             changeSelection = TRUE;
    01725         } else {
    01726             //
    01727             // If the user tries to move right and we are at the last
    01728             // character and there is a selection, then cancel the
    01729             // selection.
    01730             //
    01731             if ( (ped->ichMaxSel != ped->ichMinSel) &&
    01732                 !(scState & SHFTDOWN) ) {
    01733                 newMaxSel = newMinSel = ped->ichCaret;
    01734                 changeSelection = TRUE;
    01735             }
    01736         }
    01737         break;
    01738
    01739     case VK_HOME:
    01740         //
    01741         // Move caret to top.
    01742         //
    01743         ped->ichCaret = 0;
    01744
    01745         //
    01746         // Update selection.
    01747         //
    01748         if (scState & SHFTDOWN) {
    01749             if (MaxEqCar && !MinEqMax) {
    01750                 // Reduce selection
    01751                 newMinSel = ped->ichCaret;
    01752                 newMaxSel = ped->ichMinSel;
    01753             } else {
    01754                 // Extend selection
    01755                 newMinSel = ped->ichCaret;
    01756             }
    01757         } else {
    01758             // Clear selection
    01759             newMaxSel = newMinSel = ped->ichCaret;
    01760         }
    01761
    01762         changeSelection = TRUE;
    01763         break;
    01764
    01765     case VK_END:
    01766         //
    01767         // Move caret to end.
    01768         //
    01769         ped->ichCaret = ped->cch;
    01770
    01771         //
    01772         // Update selection.
    01773         //
    01774         newMaxSel = ped->ichCaret;
    01775         if (scState & SHFTDOWN) {
    01776             if (MinEqCar && !MinEqMax) {
    01777                 // Reduce selection
    01778                 newMinSel = ped->ichMaxSel;
    01779             }
    01780         } else {
    01781             // Clear selection
    01782             newMinSel = ped->ichCaret;
    01783         }
    01784
    01785         changeSelection = TRUE;
    01786         break;
    01787
    01788     case VK_DELETE:
    01789         if (ped->fReadOnly)
    01790             break;
    01791
    01792         switch (scState) {
    01793         case NONEDOWN:
    01794
    01795             /*
    01796              * Clear selection. If no selection, delete (clear) character
    01797              * right.
    01798              */
    01799             if ((ped->ichMaxSel < ped->cch) && (ped->ichMinSel == ped->ichMaxSel)) {
    01800
    01801                 /*
    01802                  * Move cursor forwards and simulate a backspace.
    01803                  */
    01804                 if (ped->pLpkEditCallout) {
    01805                     ped->ichMinSel = ped->ichCaret;
    01806                     ped->ichMaxSel = ped->ichCaret = SLMoveSelectionRestricted(ped, ped->ichCaret, FALSE);
    01807                 } else {
    01808                     ped->ichCaret = ECNextIch(ped,NULL,ped->ichCaret);
    01809                     ped->ichMaxSel = ped->ichMinSel = ped->ichCaret;
    01810                 }
    01811                 SLChar(ped, (UINT)VK_BACK);
    01812             }
    01813             if (ped->ichMinSel != ped->ichMaxSel)
    01814                 SLChar(ped, (UINT)VK_BACK);
    01815             break;
    01816
    01817         case SHFTDOWN:
    01818
    01819             //
    01820             // Send ourself a WM_CUT message if a selection exists.
    01821             // Otherwise, delete the left character.
    01822             //
    01823             if (ped->ichMinSel == ped->ichMaxSel) {
    01824                 UserAssert(!ped->fEatNextChar);
    01825                 SLChar(ped, VK_BACK);
    01826             } else
    01827                 SendMessage(ped->hwnd, WM_CUT, 0, 0L);
    01828
    01829             break;
    01830
    01831         case CTRLDOWN:
    01832
    01833             /*
    01834              * Delete to end of line if no selection else delete (clear)
    01835              * selection.
    01836              */
    01837             if ((ped->ichMaxSel < ped->cch) && (ped->ichMinSel == ped->ichMaxSel)) {
    01838
    01839                 /*
    01840                  * Move cursor to end of line and simulate a backspace.
    01841                  */
    01842                 ped->ichMaxSel = ped->ichCaret = ped->cch;
    01843             }
    01844             if (ped->ichMinSel != ped->ichMaxSel)
    01845                 SLChar(ped, (UINT)VK_BACK);
    01846             break;
    01847
    01848         }
    01849
    01850         /*
    01851          * No need to update text or selection since BACKSPACE message does it
    01852          * for us.
    01853          */
    01854         break;
    01855
    01856     case VK_INSERT:
    01857         switch (scState) {
    01858         case CTRLDOWN:
    01859
    01860             /*
    01861              * Copy current selection to clipboard
    01862              */
    01863             SendMessage(ped->hwnd, WM_COPY, 0, 0);
    01864             break;
    01865
    01866         case SHFTDOWN:
    01867             SendMessage(ped->hwnd, WM_PASTE, 0, 0L);
    01868             break;
    01869         }
    01870         break;
    01871
    01872     // VK_HANJA support
    01873     case VK_HANJA:
    01874         if ( HanjaKeyHandler( ped ) ) {
    01875             changeSelection = TRUE;
    01876             newMinSel = ped->ichCaret;
    01877             newMaxSel = ped->ichCaret + (ped->fAnsi ? 2 : 1);
    01878         }
    01879         break;
    01880
    01881     case VK_F4:
    01882     case VK_PRIOR:
    01883     case VK_NEXT:
    01884
    01885         /*
    01886          * Send keys to the listbox if we are a part of a combo box. This
    01887          * assumes the listbox ignores keyup messages which is correct right
    01888          * now.
    01889          */
    01890 SendKeyToListBox:
    01891         if (ped->listboxHwnd) {
    01892
    01893             /*
    01894              * Handle Combobox support
    01895              */
    01896             SendMessage(ped->listboxHwnd, WM_KEYDOWN, virtKeyCode, 0L);
    01897             return;
    01898         }
    01899     }
    01900
    01901     if (changeSelection || updateText) {
    01902         hdc = ECGetEditDC(ped, FALSE);
    01903
    01904         /*
    01905          * Scroll if needed
    01906          */
    01907         SLScrollText(ped, hdc);
    01908
    01909         if (changeSelection)
    01910             SLChangeSelection(ped, hdc, newMinSel, newMaxSel);
    01911
    01912         if (updateText)
    01913             SLDrawText(ped, hdc, 0);
    01914
    01915         ECReleaseEditDC(ped, hdc, FALSE);
    01916         if (updateText) {
    01917             ECNotifyParent(ped, EN_CHANGE);
    01918
    01919             if (FWINABLE()) {
    01920                 NotifyWinEvent(EVENT_OBJECT_VALUECHANGE, ped->hwnd, OBJID_CLIENT, INDEXID_CONTAINER);
    01921             }
    01922         }
    01923     }
    01924 }
    01925
    01926 /***************************************************************************\
    01927 * SLMouseToIch AorW
    01928 *
    01929 * Returns the closest cch to where the mouse point is.
    01930 *
    01931 * History:
    01932 \***************************************************************************/
    01933
    01934 ICH SLMouseToIch(
    01935     PED ped,
    01936     HDC hdc,
    01937     LPPOINT mousePt)
    01938 {
    01939     PSTR pText;
    01940     int width = mousePt->x;
    01941     int lastHighWidth, lastLowWidth;
    01942     SIZE size;
    01943     ICH cch;
    01944     ICH cchLo, cchHi;
    01945     LPSTR lpText;
    01946     FnGetTextExtentPoint pGetTextExtentPoint;
    01947
    01948     if (ped->pLpkEditCallout) {
    01949         pText = ECLock(ped);
    01950         cch = ped->pLpkEditCallout->EditMouseToIch(ped, hdc, pText, ped->cch, width);
    01951         ECUnlock(ped);
    01952         return cch;
    01953     }
    01954
    01955     if (width <= ped->rcFmt.left) {
    01956
    01957         /*
    01958          * Return either the first non visible character or return 0 if at
    01959          * beginning of text
    01960          */
    01961         if (ped->ichScreenStart)
    01962             return (ped->ichScreenStart - 1);
    01963         else
    01964             return (0);
    01965     }
    01966
    01967     if (width > ped->rcFmt.right) {
    01968         pText = ECLock(ped);
    01969
    01970         /*
    01971          * Return last char in text or one plus the last char visible
    01972          */
    01973         cch = ECCchInWidth(ped, hdc,
    01974                 (LPSTR)(pText + ped->ichScreenStart * ped->cbChar),
    01975                 ped->cch - ped->ichScreenStart, ped->rcFmt.right -
    01976                 ped->rcFmt.left, TRUE) + ped->ichScreenStart;
    01977
    01978         //
    01979         // This is marked as JAPAN in Win31J. But it should be a DBCS
    01980         // issue. LiZ -- 5/5/93
    01981         // We must check DBCS Lead byte. Because ECAdjustIch() pick up Prev Char.
    01982         //  1993.3.9 by yutakas
    01983         //
    01984         if (ped->fAnsi && ped->fDBCS) {
    01985             if (cch >= ped->cch) {
    01986                 cch = ped->cch;
    01987             } else {
    01988                 if (ECIsDBCSLeadByte(ped,*(pText+cch))) {
    01989                     cch += 2;
    01990                 } else {
    01991                     cch ++;
    01992                 }
    01993             }
    01994             ECUnlock(ped);
    01995             return cch;
    01996         } else {
    01997             ECUnlock(ped);
    01998             if (cch >= ped->cch)
    01999                 return (ped->cch);
    02000             else
    02001                 return (cch + 1);
    02002         }
    02003     }
    02004
    02005     if (ped->format != ES_LEFT) {
    02006         width -= SLCalcXOffsetSpecial(ped, hdc, ped->ichScreenStart);
    02007     }
    02008
    02009     /*
    02010      * Check if password hidden chars are being used.
    02011      */
    02012     if (ped->charPasswordChar)
    02013         return min( (DWORD)( (width - ped->rcFmt.left) / ped->cPasswordCharWidth),
    02014                     ped->cch);
    02015
    02016     if (!ped->cch)
    02017         return (0);
    02018
    02019     pText = ECLock(ped);
    02020     lpText = pText + ped->ichScreenStart * ped->cbChar;
    02021
    02022     pGetTextExtentPoint = ped->fAnsi ? (FnGetTextExtentPoint)GetTextExtentPointA
    02023                                      : (FnGetTextExtentPoint)GetTextExtentPointW;
    02024     width -= ped->rcFmt.left;
    02025
    02026     /*
    02027      * If the user clicked past the end of the text, return the last character
    02028      */
    02029     cchHi = ped->cch - ped->ichScreenStart;
    02030     pGetTextExtentPoint(hdc, lpText, cchHi, &size);
    02031     if (size.cx <= width) {
    02032         cch = cchHi;
    02033         goto edAdjust;
    02034     }
    02035     /*
    02036      * Initialize Binary Search Bounds
    02037      */
    02038     cchLo = 0;
    02039     cchHi ++;
    02040     lastLowWidth = 0;
    02041     lastHighWidth = size.cx;
    02042
    02043     /*
    02044      * Binary search for closest char
    02045      */
    02046     while (cchLo < cchHi - 1) {
    02047
    02048         cch = (cchHi + cchLo) / 2;
    02049         pGetTextExtentPoint(hdc, lpText, cch, &size);
    02050
    02051         if (size.cx <= width) {
    02052             cchLo = cch;
    02053             lastLowWidth = size.cx;
    02054         } else {
    02055             cchHi = cch;
    02056             lastHighWidth = size.cx;
    02057         }
    02058     }
    02059
    02060     /*
    02061      * When the while ends, you can't know the exact position.
    02062      * Try to see if the mouse pointer was on the farest half
    02063      * of the char we got and if so, adjust cch.
    02064      */
    02065     if (cchLo == cch) {
    02066         /*
    02067          * Need to compare with lastHighWidth
    02068          */
    02069         if ((lastHighWidth - width) < (width - size.cx)) {
    02070             cch++;
    02071         }
    02072     } else {
    02073         /*
    02074          * Need to compare with lastLowWidth
    02075          */
    02076         if ((width - lastLowWidth) < (size.cx - width)) {
    02077             cch--;
    02078         }
    02079     }
    02080
    02081 edAdjust:
    02082     //
    02083     // Avoid to point the intermediate of double byte character
    02084     //
    02085     cch = ECAdjustIch( ped, pText, cch + ped->ichScreenStart );
    02086     ECUnlock(ped);
    02087     return ( cch );
    02088 }
    02089
    02090 /***************************************************************************\
    02091 * SLMouseMotion AorW
    02092 *
    02093 * <brief description>
    02094 *
    02095 * History:
    02096 \***************************************************************************/
    02097
    02098 void SLMouseMotion(
    02099     PED ped,
    02100     UINT message,
    02101     UINT virtKeyDown,
    02102     LPPOINT mousePt)
    02103 {
    02104     DWORD   selectionl;
    02105     DWORD   selectionh;
    02106     BOOL    changeSelection;
    02107     ICH     newMaxSel;
    02108     ICH     newMinSel;
    02109     HDC     hdc;
    02110     ICH     mouseIch;
    02111     LPSTR   pText;
    02112
    02113     changeSelection = FALSE;
    02114
    02115     newMinSel = ped->ichMinSel;
    02116     newMaxSel = ped->ichMaxSel;
    02117
    02118     hdc = ECGetEditDC(ped, FALSE);
    02119     mouseIch = SLMouseToIch(ped, hdc, mousePt);
    02120
    02121     switch (message) {
    02122         case WM_LBUTTONDBLCLK:
    02123
    02124             // if shift key is down, extend selection to word we double clicked on
    02125             // else clear current selection and select word.
    02126
    02127             // in DBCS, we have different word breaking. LiZ -- 5/5/93
    02128             // In Hangeul Environment we use word selection feature because Hangeul
    02129             // use SPACE as word break
    02130             if (ped->fAnsi && ped->fDBCS) {
    02131                 pText = ECLock(ped) + mouseIch;
    02132                 ECWord(ped, mouseIch,
    02133                        (ECIsDBCSLeadByte(ped,*pText) && mouseIch < ped->cch) ? FALSE : TRUE,
    02134                        &selectionl, &selectionh);
    02135                 ECUnlock(ped);
    02136             } else {
    02137                 ECWord(ped, mouseIch, (mouseIch) ? TRUE : FALSE, &selectionl, &selectionh);
    02138             }
    02139
    02140             if (!(virtKeyDown & MK_SHIFT)) {
    02141                 // If shift key isn't down, move caret to mouse point and clear
    02142                 // old selection
    02143                 newMinSel = selectionl;
    02144                 newMaxSel = ped->ichCaret = selectionh;
    02145             } else {
    02146                 // Shiftkey is down so we want to maintain the current selection
    02147                 // (if any) and just extend or reduce it
    02148                 if (ped->ichMinSel == ped->ichCaret) {
    02149                     newMinSel = ped->ichCaret = selectionl;
    02150                     ECWord(ped, newMaxSel, TRUE, &selectionl, &selectionh);
    02151                 } else {
    02152                     newMaxSel = ped->ichCaret = selectionh;
    02153                     ECWord(ped, newMinSel, FALSE, &selectionl, &selectionh);
    02154                 }
    02155                 /*
    02156                  * v-ronaar: fix bug 24627 - edit selection is weird.
    02157                  */
    02158                 ped->ichMaxSel = ped->ichCaret;
    02159             }
    02160
    02161             ped->ichStartMinSel = selectionl;
    02162             ped->ichStartMaxSel = selectionh;
    02163
    02164             goto InitDragSelect;
    02165
    02166         case WM_MOUSEMOVE:
    02167             //
    02168             // We know the mouse button's down -- otherwise the OPTIMIZE
    02169             // test would've failed in SLEditWndProc and never called
    02170             //
    02171             changeSelection = TRUE;
    02172
    02173             // Extend selection, move caret word right
    02174             if (ped->ichStartMinSel || ped->ichStartMaxSel) {
    02175                 // We're in WORD SELECT mode
    02176                 BOOL fReverse = (mouseIch <= ped->ichStartMinSel);
    02177
    02178                 ECWord(ped, mouseIch, !fReverse, &selectionl, &selectionh);
    02179
    02180                 if (fReverse) {
    02181                     newMinSel = ped->ichCaret = selectionl;
    02182                     newMaxSel = ped->ichStartMaxSel;
    02183                 } else {
    02184                     newMinSel = ped->ichStartMinSel;
    02185                     newMaxSel = ped->ichCaret = selectionh;
    02186                 }
    02187             } else if ((ped->ichMinSel == ped->ichCaret) &&
    02188                 (ped->ichMinSel != ped->ichMaxSel))
    02189                 // Reduce selection extent
    02190                 newMinSel = ped->ichCaret = mouseIch;
    02191             else
    02192                 // Extend selection extent
    02193                 newMaxSel = ped->ichCaret=mouseIch;
    02194             break;
    02195
    02196         case WM_LBUTTONDOWN:
    02197             // If we currently don't have the focus yet, try to get it.
    02198             if (!ped->fFocus) {
    02199                 if (!ped->fNoHideSel)
    02200                     // Clear the selection before setting the focus so that we
    02201                     // don't get refresh problems and flicker. Doesn't matter
    02202                     // since the mouse down will end up changing it anyway.
    02203                     ped->ichMinSel = ped->ichMaxSel = ped->ichCaret;
    02204
    02205                 NtUserSetFocus(ped->hwnd);
    02206
    02207                 //
    02208                 // BOGUS
    02209                 // (1) We should see if SetFocus() succeeds.
    02210                 // (2) We should ignore mouse messages if the first window
    02211                 //      ancestor with a caption isn't "active."
    02212                 //
    02213
    02214                 // If we are part of a combo box, then this is the first time
    02215                 // the edit control is getting the focus so we just want to
    02216                 // highlight the selection and we don't really want to position
    02217                 // the caret.
    02218                 if (ped->listboxHwnd)
    02219                     break;
    02220
    02221                 // We yield at SetFocus -- text might have changed at that point
    02222                 // update selection and caret info accordingly
    02223                 // FIX for bug # 11743 -- JEFFBOG 8/23/91
    02224                 newMaxSel = ped->ichMaxSel;
    02225                 newMinSel = ped->ichMinSel;
    02226                 mouseIch  = min(mouseIch, ped->cch);
    02227             }
    02228
    02229             if (ped->fFocus) {
    02230                 // Only do this if we have the focus since a clever app may not
    02231                 // want to give us the focus at the SetFocus call above.
    02232                 if (!(virtKeyDown & MK_SHIFT)) {
    02233                     // If shift key isn't down, move caret to mouse point and
    02234                     // clear old selection
    02235                     newMinSel = newMaxSel = ped->ichCaret = mouseIch;
    02236                 } else {
    02237                     // Shiftkey is down so we want to maintain the current
    02238                     // selection (if any) and just extend or reduce it
    02239                     if (ped->ichMinSel == ped->ichCaret)
    02240                         newMinSel = ped->ichCaret = mouseIch;
    02241                     else
    02242                         newMaxSel = ped->ichCaret = mouseIch;
    02243                 }
    02244
    02245                 ped->ichStartMinSel = ped->ichStartMaxSel = 0;
    02246
    02247 InitDragSelect:
    02248                 ped->fMouseDown = FALSE;
    02249                 NtUserSetCapture(ped->hwnd);
    02250                 ped->fMouseDown = TRUE;
    02251                 changeSelection = TRUE;
    02252             }
    02253             break;
    02254
    02255         case WM_LBUTTONUP:
    02256             if (ped->fMouseDown) {
    02257                 ped->fMouseDown = FALSE;
    02258                 NtUserReleaseCapture();
    02259             }
    02260             break;
    02261     }
    02262
    02263     if (changeSelection) {
    02264         SLScrollText(ped,hdc);
    02265         SLChangeSelection(ped, hdc, newMinSel, newMaxSel);
    02266     }
    02267
    02268     ECReleaseEditDC(ped, hdc, FALSE);
    02269 }
    02270
    02271 /***************************************************************************\
    02272 * SLPaint AorW
    02273 *
    02274 * Handles painting of the edit control window. Draws the border if
    02275 * necessary and draws the text in its current state.
    02276 *
    02277 * History:
    02278 \***************************************************************************/
    02279
    02280 void SLPaint(
    02281     PED ped,
    02282     HDC hdc)
    02283 {
    02284     HWND   hwnd = ped->hwnd;
    02285     HBRUSH hBrushRemote;
    02286     RECT   rcEdit;
    02287     HANDLE hOldFont;
    02288
    02289     /*
    02290      * Had to put in hide/show carets. The first one needs to be done before
    02291      * beginpaint to correctly paint the caret if part is in the update region
    02292      * and part is out. The second is for 1.03 compatibility. It breaks
    02293      * micrografix's worksheet edit control if not there.
    02294      */
    02295     NtUserHideCaret(hwnd);
    02296
    02297     if (_IsWindowVisible(ped->pwnd)) {
    02298         /*
    02299          * Erase the background since we don't do it in the erasebkgnd message.
    02300          */
    02301         hBrushRemote = ECGetBrush(ped, hdc);
    02302         _GetClientRect(ped->pwnd, (LPRECT)&rcEdit);
    02303         FillRect(hdc, &rcEdit, hBrushRemote);
    02304
    02305         if (ped->fFlatBorder)
    02306         {
    02307             RECT    rcT;
    02308
    02309             _GetClientRect(ped->pwnd, &rcT);
    02310             DrawFrame(hdc, &rcT, 1, DF_WINDOWFRAME);
    02311         }
    02312
    02313         if (ped->hFont != NULL) {
    02314             /*
    02315              * We have to select in the font since this may be a subclassed dc
    02316              * or a begin paint dc which hasn't been initialized with out fonts
    02317              * like ECGetEditDC does.
    02318              */
    02319             hOldFont = SelectObject(hdc, ped->hFont);
    02320         }
    02321
    02322         SLDrawText(ped, hdc, 0);
    02323
    02324         if (ped->hFont != NULL && hOldFont != NULL) {
    02325             SelectObject(hdc, hOldFont);
    02326         }
    02327     }
    02328
    02329     NtUserShowCaret(hwnd);
    02330 }
    02331
    02332 /***************************************************************************\
    02333 * SLSetFocus AorW
    02334 *
    02335 * Gives the edit control the focus and notifies the parent
    02336 * EN_SETFOCUS.
    02337 *
    02338 * History:
    02339 \***************************************************************************/
    02340
    02341 void SLSetFocus(
    02342     PED ped)
    02343 {
    02344     HDC hdc;
    02345
    02346     if (!ped->fFocus) {
    02347
    02348         ped->fFocus = TRUE; /* Set focus */
    02349
    02350         /*
    02351          * We don't want to muck with the caret since it isn't created.
    02352          */
    02353         hdc = ECGetEditDC(ped, TRUE);
    02354
    02355         /*
    02356          * Show the current selection if necessary.
    02357          */
    02358         if (!ped->fNoHideSel)
    02359             SLDrawText(ped, hdc, 0);
    02360
    02361         /*
    02362          * Create the caret
    02363          */
    02364         if (ped->pLpkEditCallout) {
    02365             ped->pLpkEditCallout->EditCreateCaret (ped, hdc, ECGetCaretWidth(),
    02366                                                    ped->lineHeight, 0);
    02367         }
    02368         else {
    02369             NtUserCreateCaret(ped->hwnd, (HBITMAP)NULL,
    02370                     ECGetCaretWidth(),
    02371                     ped->lineHeight );
    02372         }
    02373         SLSetCaretPosition(ped, hdc);
    02374         ECReleaseEditDC(ped, hdc, TRUE);
    02375         NtUserShowCaret(ped->hwnd);
    02376
    02377     }
    02378
    02379     /*
    02380      * Notify parent we have the focus
    02381      */
    02382     ECNotifyParent(ped, EN_SETFOCUS);
    02383 }
    02384
    02385 /***************************************************************************\
    02386 * SLKillFocus AorW
    02387 *
    02388 * The edit control loses the focus and notifies the parent via
    02389 * EN_KILLFOCUS.
    02390 *
    02391 * History:
    02392 \***************************************************************************/
    02393
    02394 void SLKillFocus(
    02395     PED ped,
    02396     HWND newFocusHwnd)
    02397 {
    02398     if (ped->fFocus) {
    02399
    02400         /*
    02401          * Destroy the caret (Win31/Chicago hides it first)
    02402          */
    02403         NtUserDestroyCaret();
    02404
    02405         ped->fFocus = FALSE; /* Clear focus */
    02406         /*
    02407          * Do this only if we still have the focus. But we always notify the
    02408          * parent that we lost the focus whether or not we originally had the
    02409          * focus.
    02410          */
    02411
    02412         /*
    02413          * Hide the current selection if needed
    02414          */
    02415         if (!ped->fNoHideSel && (ped->ichMinSel != ped->ichMaxSel)) {
    02416             NtUserInvalidateRect(ped->hwnd, NULL, FALSE);
    02417 #if 0
    02418             SLSetSelection(ped, ped->ichCaret, ped->ichCaret);
    02419 #endif
    02420         }
    02421     }
    02422
    02423     /*
    02424      * If we aren't a combo box, notify parent that we lost the focus.
    02425      */
    02426     if (!ped->listboxHwnd)
    02427         ECNotifyParent(ped, EN_KILLFOCUS);
    02428     else {
    02429
    02430         /*
    02431          * This editcontrol is part of a combo box and is losing the focus. If
    02432          * the focus is NOT being sent to another control in the combo box
    02433          * window, then it means the combo box is losing the focus. So we will
    02434          * notify the combo box of this fact.
    02435          */
    02436         if ((newFocusHwnd == NULL) ||
    02437                     (!IsChild(ped->hwndParent, newFocusHwnd))) {
    02438             // Excel has a slaker in it's midst.  They're not using our combo
    02439             // boxes, but they still expect to get all the internal messages
    02440             // that we give to OUR comboboxes.  And they expect them to be at
    02441             // the same offset from WM_USER as they were in 3.1.
    02442             //                                           (JEFFBOG - 01/26/94)
    02443             /*
    02444              * Windows NT won't fix the bug described above: it only applies
    02445              * to old 16-bit excel, and WOW converts msgs to Win3.1 values.
    02446              */
    02447
    02448             /*
    02449              * Focus is being sent to a window which is not a child of the combo
    02450              * box window which implies that the combo box is losing the focus.
    02451              * Send a message to the combo box informing him of this fact so
    02452              * that he can clean up...
    02453              */
    02454             SendMessage(ped->hwndParent, CBEC_KILLCOMBOFOCUS, 0, 0L);
    02455         }
    02456     }
    02457 }
    02458
    02459
    02460 /***************************************************************************\
    02461 *
    02462 *  SLPaste()
    02463 *
    02464 *  Does actual text paste and update.
    02465 *
    02466 \***************************************************************************/
    02467 void   SLPaste(PED ped)
    02468 {
    02469     HDC hdc;
    02470
    02471     //
    02472     // Insert contents of clipboard, after unhilighting current selection
    02473     // and deleting it.
    02474     //
    02475     ECDeleteText(ped);
    02476     SLPasteText(ped);
    02477
    02478     //
    02479     // Update display
    02480     //
    02481     ECNotifyParent(ped, EN_UPDATE);
    02482
    02483     hdc = ECGetEditDC(ped,FALSE);
    02484
    02485     SLScrollText(ped, hdc);
    02486     SLDrawText(ped, hdc, 0);
    02487
    02488     ECReleaseEditDC(ped,hdc,FALSE);
    02489
    02490     /*
    02491      * Tell parent our text contents changed.
    02492      */
    02493     ECNotifyParent(ped, EN_CHANGE);
    02494     if (FWINABLE()) {
    02495         NotifyWinEvent(EVENT_OBJECT_VALUECHANGE, ped->hwnd, OBJID_CLIENT, INDEXID_CONTAINER);
    02496     }
    02497 }
    02498
    02499
    02500
    02501 /***************************************************************************\
    02502 * SLEditWndProc
    02503 *
    02504 * Class procedure for all single line edit controls.
    02505 * Dispatches all messages to the appropriate handlers which are named
    02506 * as follows:
    02507 * SL (single line) prefixes all single line edit control procedures while
    02508 * EC (edit control) prefixes all common handlers.
    02509 *
    02510 * The SLEditWndProc only handles messages specific to single line edit
    02511 * controls.
    02512 *
    02513 * WARNING: If you add a message here, add it to gawEditWndProc[] in
    02514 * kernel\server.c too, otherwise EditWndProcA/W will send it straight to
    02515 * DefWindowProcWorker
    02516 *
    02517 * History:
    02518 \***************************************************************************/
    02519
    02520 LRESULT SLEditWndProc(
    02521     HWND hwnd,
    02522     PED ped,
    02523     UINT message,
    02524     WPARAM wParam,
    02525     LPARAM lParam)
    02526 {
    02527     HDC         hdc;
    02528     PAINTSTRUCT ps;
    02529     POINT       pt;
    02530
    02531     /*
    02532      * Dispatch the various messages we can receive
    02533      */
    02534     switch (message) {
    02535
    02536     case WM_INPUTLANGCHANGE:
    02537         if (ped && ped->fFocus && ped->pLpkEditCallout) {
    02538             NtUserHideCaret(hwnd);
    02539             hdc = ECGetEditDC(ped, TRUE);
    02540             NtUserDestroyCaret();
    02541             ped->pLpkEditCallout->EditCreateCaret (ped, hdc, ECGetCaretWidth(), ped->lineHeight, (UINT)lParam);
    02542             SLSetCaretPosition(ped, hdc);
    02543             ECReleaseEditDC(ped, hdc, TRUE);
    02544             NtUserShowCaret(hwnd);
    02545         }
    02546         goto PassToDefaultWindowProc;
    02547
    02548     case WM_STYLECHANGED:
    02549         if (ped && ped->pLpkEditCallout) {
    02550             switch (wParam) {
    02551
    02552                 case GWL_STYLE:
    02553                     ECUpdateFormat(ped,
    02554                         ((LPSTYLESTRUCT)lParam)->styleNew,
    02555                         GetWindowLong(ped->hwnd, GWL_EXSTYLE));
    02556                     return 1L;
    02557
    02558                 case GWL_EXSTYLE:
    02559                     ECUpdateFormat(ped,
    02560                         GetWindowLong(ped->hwnd, GWL_STYLE),
    02561                         ((LPSTYLESTRUCT)lParam)->styleNew);
    02562                     return 1L;
    02563             }
    02564         }
    02565
    02566         goto PassToDefaultWindowProc;
    02567
    02568     case WM_CHAR:
    02569
    02570         /*
    02571          * wParam - the value of the key
    02572            lParam - modifiers, repeat count etc (not used)
    02573          */
    02574         if (!ped->fEatNextChar)
    02575             SLChar(ped, (UINT)wParam);
    02576         else
    02577             ped->fEatNextChar = FALSE;
    02578         break;
    02579
    02580     case WM_ERASEBKGND:
    02581
    02582        /*
    02583         * wParam - device context handle
    02584         * lParam - not used
    02585         * We do nothing on this message and we don't want DefWndProc to do
    02586         * anything, so return 1
    02587         */
    02588         return (1L);
    02589         break;
    02590
    02591     case WM_GETDLGCODE: {
    02592            LONG code = DLGC_WANTCHARS | DLGC_HASSETSEL | DLGC_WANTARROWS;
    02593
    02594            /*
    02595             * If this is a WM_SYSCHAR message generated by the UNDO keystroke
    02596             * we want this message so we can EAT IT in "case WM_SYSCHAR:"
    02597             */
    02598             if (lParam) {
    02599                 switch (((LPMSG)lParam)->message) {
    02600                     case WM_SYSCHAR:
    02601                         if ((HIWORD(((LPMSG)lParam)->lParam) & SYS_ALTERNATE) &&
    02602                             ((WORD)wParam == VK_BACK)) {
    02603                             code |= DLGC_WANTMESSAGE;
    02604                         }
    02605                         break;
    02606
    02607                     case WM_KEYDOWN:
    02608                         if (( (((WORD)wParam == VK_RETURN) ||
    02609                                ((WORD)wParam == VK_ESCAPE)) &&
    02610                             (ped->listboxHwnd)      &&
    02611                             TestWF(ValidateHwnd(ped->hwndParent), CBFDROPDOWN) &&
    02612                             SendMessage(ped->hwndParent, CB_GETDROPPEDSTATE, 0, 0L))) {
    02613                             code |= DLGC_WANTMESSAGE;
    02614                         }
    02615                         break;
    02616                 }
    02617             }
    02618             return code;
    02619         }
    02620
    02621         break;
    02622
    02623     case WM_KEYDOWN:
    02624
    02625         /*
    02626          * wParam - virt keycode of the given key
    02627          * lParam - modifiers such as repeat count etc. (not used)
    02628          */
    02629         SLKeyDown(ped, (UINT)wParam, 0);
    02630         break;
    02631
    02632     case WM_KILLFOCUS:
    02633
    02634         /*
    02635          * wParam - handle of the window that receives the input focus
    02636            lParam - not used
    02637          */
    02638
    02639         SLKillFocus(ped, (HWND)wParam);
    02640         break;
    02641
    02642     case WM_CAPTURECHANGED:
    02643         if (ped->fMouseDown)
    02644             ped->fMouseDown = FALSE;
    02645         break;
    02646
    02647     case WM_MOUSEMOVE:
    02648         UserAssert(ped->fMouseDown);
    02649         /*
    02650          * FALL THRU
    02651          */
    02652
    02653     case WM_LBUTTONDBLCLK:
    02654     case WM_LBUTTONDOWN:
    02655     case WM_LBUTTONUP:
    02656         /*
    02657          * wParam - contains a value that indicates which virtual keys are down
    02658          * lParam - contains x and y coords of the mouse cursor
    02659          */
    02660         POINTSTOPOINT(pt, lParam);
    02661         SLMouseMotion(ped, message, (UINT)wParam, &pt);
    02662         break;
    02663
    02664     case WM_CREATE:
    02665
    02666         /*
    02667          * wParam - handle to window being created
    02668            lParam - points to a CREATESTRUCT that contains copies of parameters
    02669                     passed to the CreateWindow function.
    02670          */
    02671         return (SLCreate(ped, (LPCREATESTRUCT)lParam));
    02672         break;
    02673
    02674     case WM_PRINTCLIENT:
    02675         // wParam --    can be hdc from subclassed paint
    02676         // lParam --    unused
    02677         SLPaint(ped, (HDC) wParam);
    02678         break;
    02679
    02680     case WM_PAINT:
    02681
    02682         /*
    02683          * wParam --    can be hdc from subclassed paint
    02684          * lParam --    unused
    02685          */
    02686         if (wParam)
    02687             hdc = (HDC) wParam;
    02688         else {
    02689             // this hide/show caret is outside Begin/EndPaint to handle the
    02690             // case when the caret is half in/half out of the update region
    02691             NtUserHideCaret(hwnd);
    02692             hdc = NtUserBeginPaint(hwnd, &ps);
    02693         }
    02694
    02695         if (_IsWindowVisible(ped->pwnd))
    02696             SLPaint(ped, hdc);
    02697
    02698         if (!wParam) {
    02699             NtUserEndPaint(hwnd, &ps);
    02700             NtUserShowCaret(hwnd);
    02701         }
    02702         break;
    02703
    02704     case WM_PASTE:
    02705
    02706         /*
    02707          * wParam - not used
    02708          * lParam - not used
    02709          */
    02710         if (!ped->fReadOnly)
    02711             SLPaste(ped);
    02712         break;
    02713
    02714     case WM_SETFOCUS:
    02715
    02716         /*
    02717          * wParam - handle of window that loses the input focus (may be NULL)
    02718            lParam - not used
    02719          */
    02720         SLSetFocus(ped);
    02721         break;
    02722
    02723     case WM_SIZE:
    02724
    02725         /*
    02726          * wParam - defines the type of resizing fullscreen, sizeiconic,
    02727                     sizenormal etc.
    02728            lParam - new width in LOWORD, new height in HIGHWORD of client area
    02729          */
    02730         ECSize(ped, NULL, TRUE);
    02731         return 0L;
    02732
    02733     case WM_SYSKEYDOWN:
    02734         /*
    02735          * wParam --    virtual key code
    02736          * lParam --    modifiers
    02737          */
    02738
    02739         /*
    02740          * Are we in a combobox with the Alt key down?
    02741          */
    02742         if (ped->listboxHwnd && (lParam & 0x20000000L)) {
    02743             /*
    02744              * Handle Combobox support. We want alt up or down arrow to behave
    02745              * like F4 key which completes the combo box selection
    02746              */
    02747             if (lParam & 0x1000000) {
    02748
    02749                 /*
    02750                  * This is an extended key such as the arrow keys not on the
    02751                  * numeric keypad so just drop the combobox.
    02752                  */
    02753                 if (wParam == VK_DOWN || wParam == VK_UP)
    02754                     goto DropCombo;
    02755                 else
    02756                     goto foo;
    02757             }
    02758
    02759             if (!(GetKeyState(VK_NUMLOCK) & 1) &&
    02760                     (wParam == VK_DOWN || wParam == VK_UP)) {
    02761
    02762                 /*
    02763                  * NUMLOCK is up and the keypad up or down arrow hit:
    02764                  * eat character generated by keyboard driver.
    02765                  */
    02766                 ped->fEatNextChar = TRUE;
    02767             } else {
    02768                 goto foo;
    02769             }
    02770
    02771 DropCombo:
    02772             if (SendMessage(ped->hwndParent,
    02773                     CB_GETEXTENDEDUI, 0, 0) & 0x00000001) {
    02774
    02775                 /*
    02776                  * Extended ui doesn't honor VK_F4.
    02777                  */
    02778                 if (SendMessage(ped->hwndParent, CB_GETDROPPEDSTATE, 0, 0))
    02779                     return(SendMessage(ped->hwndParent, CB_SHOWDROPDOWN, 0, 0));
    02780                 else
    02781                     return (SendMessage(ped->hwndParent, CB_SHOWDROPDOWN, 1, 0));
    02782             } else
    02783                 return (SendMessage(ped->listboxHwnd, WM_KEYDOWN, VK_F4, 0));
    02784         }
    02785 foo:
    02786         if (wParam == VK_BACK) {
    02787             SendMessage(ped->hwnd, WM_UNDO, 0, 0L);
    02788             break;
    02789         }
    02790         else
    02791             goto PassToDefaultWindowProc;
    02792         break;
    02793
    02794     case EM_GETLINE:
    02795
    02796         /*
    02797          * wParam - line number to copy (always the first line for SL)
    02798          * lParam - buffer to copy text to. FIrst word is max # of bytes to copy
    02799          */
    02800         return ECGetText(ped, (*(LPWORD)lParam), (LPSTR)lParam, FALSE);
    02801
    02802     case EM_LINELENGTH:
    02803
    02804         /*
    02805          * wParam - ignored
    02806          * lParam - ignored
    02807          */
    02808         return (LONG)ped->cch;
    02809         break;
    02810
    02811     case EM_SETSEL:
    02812         /*
    02813          * wParam -- start pos
    02814          * lParam -- end pos
    02815          */
    02816         SLSetSelection(ped, (ICH)wParam, (ICH)lParam);
    02817         break;
    02818
    02819     case EM_REPLACESEL:
    02820
    02821         /*
    02822          * wParam - flag for 4.0+ apps saying whether to clear undo
    02823          * lParam - points to a null terminated string of replacement text
    02824          */
    02825         SLReplaceSel(ped, (LPSTR)lParam);
    02826         if (!ped->f40Compat || !wParam)
    02827             ECEmptyUndo(Pundo(ped));
    02828         break;
    02829
    02830     case EM_GETFIRSTVISIBLELINE:
    02831
    02832         /*
    02833          * wParam - not used
    02834          * lParam - not used
    02835          *
    02836          * effects: Returns the first visible line for single line edit controls.
    02837          */
    02838         return ped->ichScreenStart;
    02839         break;
    02840
    02841     case EM_POSFROMCHAR:
    02842         //
    02843         // wParam --    char index in text
    02844         // lParam --    not used
    02845         // This function returns the (x,y) position of the character.
    02846         //      y is always 0 for single.
    02847         //
    02848     case EM_CHARFROMPOS:
    02849         //
    02850         // wParam --    unused
    02851         // lParam --    pt in edit client coords
    02852         // This function returns
    02853         //          LOWORD: the position of the _closest_ char
    02854         //                  to the passed in point.
    02855         //          HIWORD: the index of the line (always 0 for single)
    02856
    02857         {
    02858             LONG xyPos;
    02859
    02860             hdc = ECGetEditDC(ped, TRUE);
    02861
    02862             if (message == EM_POSFROMCHAR)
    02863                 xyPos = MAKELONG(SLIchToLeftXPos(ped, hdc, (ICH)wParam), 0);
    02864             else {
    02865                 POINTSTOPOINT(pt, lParam);
    02866                 xyPos = SLMouseToIch(ped, hdc, &pt);
    02867             }
    02868
    02869             ECReleaseEditDC(ped, hdc, TRUE);
    02870             return((LRESULT)xyPos);
    02871             break;
    02872         }
    02873
    02874     case WM_UNDO:
    02875     case EM_UNDO:
    02876         SLUndo(ped);
    02877         break;
    02878
    02879 #if 0
    02880     case WM_NCPAINT: // not in server.c gawEditWndProc[] anyway.
    02881
    02882         /*
    02883          * LATER - This is an NT optimization.  It needs to be revisited
    02884          * for validity once all of the Chicago changes are done - Johnl
    02885          */
    02886
    02887         pwnd = (PWND)HtoP(hwnd);
    02888
    02889         /*
    02890          * Check to see if this window has any non-client areas that
    02891          * would be painted.  If not, don't bother calling DefWindowProc()
    02892          * since it'll be a wasted c/s transition.
    02893          */
    02894         if (!ped->fBorder &&
    02895             TestWF(pwnd, WEFDLGMODALFRAME) == 0 &&
    02896             !TestWF(pwnd, (WFMPRESENT | WFVPRESENT | WFHPRESENT)) &&
    02897             TestWF(pwnd, WFSIZEBOX) == 0) {
    02898             break;
    02899         } else {
    02900             goto PassToDefaultWindowProc;
    02901         }
    02902         break;
    02903 #endif
    02904
    02905     default:
    02906 PassToDefaultWindowProc:
    02907         return DefWindowProcWorker(ped->pwnd, message, wParam, lParam, ped->fAnsi);
    02908         break;
    02909     } /* switch (message) */
    02910
    02911     return 1L;
    02912 } /* SLEditWndProc */