blob: d49bd0413a31670c315fa86abfea901848e93403 [file] [log] [blame]
/*
* Edit control
*
* Copyright David W. Metcalfe, 1994
* Copyright William Magro, 1995, 1996
* Copyright Frans van Dorsselaer, 1996
*
*/
/*
* UNDER CONSTRUCTION, please read EDIT.TODO
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <windows.h>
#include "win.h"
#include "local.h"
#include "stackframe.h"
#include "stddebug.h"
#include "debug.h"
#include "xmalloc.h"
#include "callback.h"
#define BUFLIMIT_MULTI 65535 /* maximum text buffer length */
#define BUFLIMIT_SINGLE 32767 /* maximum text buffer length */
#define BUFSTART_MULTI 1024 /* starting length for multi-line control */
#define BUFSTART_SINGLE 256 /* starting length for single line control */
#define GROWLENGTH 64 /* buffers grow by this much */
#define HSCROLL_FRACTION 3 /* scroll window by 1/3 width */
typedef enum
{
END_0 = 0,
END_DELIMIT,
END_NONE,
END_HARD,
END_SOFT,
} LINE_END;
typedef struct {
int offset;
int length;
LINE_END ending;
} LINEDEF;
typedef struct
{
int TextWidth; /* width of the widest line in pixels */
HLOCAL hBuf;
char *text;
HFONT hFont;
LINEDEF *LineDefs;
int XOffset; /* possitive offset of the viewport in pixels */
int FirstVisibleLine;
int LineCount;
int LineHeight; /* height of a screen line in pixels */
int AveCharWidth; /* average character width in pixels */
unsigned int BufLimit;
unsigned int BufSize;
BOOL TextChanged;
BOOL Redraw;
int SelStart; /* offset of selection start, == SelEnd if no selection */
int SelEnd; /* offset of selection end == current caret position */
int NumTabStops;
LPINT TabStops;
EDITWORDBREAKPROC WordBreakProc;
char PasswordChar;
} EDITSTATE;
#define SWAP_INT(x,y) do { int temp = (x); (x) = (y); (y) = temp; } while(0)
#define ORDER_INT(x,y) do { if ((y) < (x)) SWAP_INT((x),(y)); } while(0)
/* macros to access window styles */
#define IsMultiLine(wndPtr) ((wndPtr)->dwStyle & ES_MULTILINE)
#define IsVScrollBar(wndPtr) ((wndPtr)->dwStyle & WS_VSCROLL)
#define IsHScrollBar(wndPtr) ((wndPtr)->dwStyle & WS_HSCROLL)
#define IsReadOnly(wndPtr) ((wndPtr)->dwStyle & ES_READONLY)
#define IsWordWrap(wndPtr) (((wndPtr)->dwStyle & ES_AUTOHSCROLL) == 0)
#define EDITSTATEPTR(wndPtr) (*(EDITSTATE **)((wndPtr)->wExtra))
#ifdef WINELIB32
#define EDIT_SEND_CTLCOLOR(wndPtr,hdc) \
SendMessage((wndPtr)->parent->hwndSelf, WM_CTLCOLOREDIT, \
(WPARAM)(hdc), (LPARAM)(wndPtr)->hwndSelf)
#define EDIT_NOTIFY_PARENT(wndPtr, wNotifyCode) \
SendMessage((wndPtr)->parent->hwndSelf, WM_COMMAND, \
MAKEWPARAM((wndPtr)->wIDmenu, wNotifyCode), \
(LPARAM)(wndPtr)->hwndSelf )
#define DPRINTF_EDIT_MSG(str) \
dprintf_edit(stddeb, \
"edit: " str ": hwnd=%08x, wParam=%08x, lParam=%08lx\n", \
(UINT)hwnd, (UINT)wParam, (DWORD)lParam)
#else
#define EDIT_SEND_CTLCOLOR(wndPtr,hdc) \
SendMessage((wndPtr)->parent->hwndSelf, WM_CTLCOLOR, \
(WPARAM)(hdc), MAKELPARAM((wndPtr)->hwndSelf, CTLCOLOR_EDIT))
#define EDIT_NOTIFY_PARENT(wndPtr, wNotifyCode) \
SendMessage((wndPtr)->parent->hwndSelf, WM_COMMAND, \
(wndPtr)->wIDmenu, \
MAKELPARAM((wndPtr)->hwndSelf, wNotifyCode))
#define DPRINTF_EDIT_MSG(str) \
dprintf_edit(stddeb, \
"edit: " str ": hwnd=%04x, wParam=%04x, lParam=%08lx\n", \
(UINT)hwnd, (UINT)wParam, (DWORD)lParam)
#endif
/*********************************************************************
*
* Declarations
*
* Files like these should really be kept in alphabetical order.
*
*/
LRESULT EditWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
static void EDIT_BuildLineDefs(WND *wndPtr);
static int EDIT_CallWordBreakProc(WND *wndPtr, char *s, int index, int count, int action);
static int EDIT_ColFromWndX(WND *wndPtr, int line, int x);
static void EDIT_DelEnd(WND *wndPtr);
static void EDIT_DelLeft(WND *wndPtr);
static void EDIT_DelRight(WND *wndPtr);
static int EDIT_GetAveCharWidth(WND *wndPtr);
static int EDIT_GetLineHeight(WND *wndPtr);
static void EDIT_GetLineRect(WND *wndPtr, int line, int scol, int ecol, LPRECT rc);
static char * EDIT_GetPointer(WND *wndPtr);
static LRESULT EDIT_GetRect(WND *wndPtr, WPARAM wParam, LPARAM lParam);
static BOOL EDIT_GetRedraw(WND *wndPtr);
static int EDIT_GetTextWidth(WND *wndPtr);
static int EDIT_GetVisibleLineCount(WND *wndPtr);
static int EDIT_GetWndWidth(WND *wndPtr);
static int EDIT_GetXOffset(WND *wndPtr);
static int EDIT_LineFromWndY(WND *wndPtr, int y);
static BOOL EDIT_MakeFit(WND *wndPtr, int size);
static void EDIT_MoveBackward(WND *wndPtr, BOOL extend);
static void EDIT_MoveDownward(WND *wndPtr, BOOL extend);
static void EDIT_MoveEnd(WND *wndPtr, BOOL extend);
static void EDIT_MoveForward(WND *wndPtr, BOOL extend);
static void EDIT_MoveHome(WND *wndPtr, BOOL extend);
static void EDIT_MovePageDown(WND *wndPtr, BOOL extend);
static void EDIT_MovePageUp(WND *wndPtr, BOOL extend);
static void EDIT_MoveUpward(WND *wndPtr, BOOL extend);
static void EDIT_MoveWordBackward(WND *wndPtr, BOOL extend);
static void EDIT_MoveWordForward(WND *wndPtr, BOOL extend);
static void EDIT_PaintLine(WND *wndPtr, HDC hdc, int line);
static int EDIT_PaintText(WND *wndPtr, HDC hdc, int x, int y, int line, int col, int count, BOOL rev);
static void EDIT_ReleasePointer(WND *wndPtr);
static LRESULT EDIT_ReplaceSel(WND *wndPtr, WPARAM wParam, LPARAM lParam);
static void EDIT_ScrollIntoView(WND *wndPtr);
static int EDIT_WndXFromCol(WND *wndPtr, int line, int col);
static int EDIT_WndYFromLine(WND *wndPtr, int line);
static int EDIT_WordBreakProc(char *s, int index, int count, int action);
static LRESULT EDIT_EM_CanUndo(WND *wndPtr, WPARAM wParam, LPARAM lParam);
static LRESULT EDIT_EM_EmptyUndoBuffer(WND *wndPtr, WPARAM wParam, LPARAM lParam);
static LRESULT EDIT_EM_FmtLines(WND *wndPtr, WPARAM wParam, LPARAM lParam);
static LRESULT EDIT_EM_GetFirstVisibleLine(WND *wndPtr, WPARAM wParam, LPARAM lParam);
static LRESULT EDIT_EM_GetHandle(WND *wndPtr, WPARAM wParam, LPARAM lParam);
static LRESULT EDIT_EM_GetLine(WND *wndPtr, WPARAM wParam, LPARAM lParam);
static LRESULT EDIT_EM_GetLineCount(WND *wndPtr, WPARAM wParam, LPARAM lParam);
static LRESULT EDIT_EM_GetModify(WND *wndPtr, WPARAM wParam, LPARAM lParam);
static LRESULT EDIT_EM_GetPasswordChar(WND *wndPtr, WPARAM wParam, LPARAM lParam);
static LRESULT EDIT_EM_GetRect(WND *wndPtr, WPARAM wParam, LPARAM lParam);
static LRESULT EDIT_EM_GetSel(WND *wndPtr, WPARAM wParam, LPARAM lParam);
static LRESULT EDIT_EM_GetThumb(WND *wndPtr, WPARAM wParam, LPARAM lParam);
static LRESULT EDIT_EM_GetWordBreakProc(WND *wndPtr, WPARAM wParam, LPARAM lParam);
static LRESULT EDIT_EM_LimitText(WND *wndPtr, WPARAM wParam, LPARAM lParam);
static LRESULT EDIT_EM_LineFromChar(WND *wndPtr, WPARAM wParam, LPARAM lParam);
static LRESULT EDIT_EM_LineIndex(WND *wndPtr, WPARAM wParam, LPARAM lParam);
static LRESULT EDIT_EM_LineLength(WND *wndPtr, WPARAM wParam, LPARAM lParam);
static LRESULT EDIT_EM_LineScroll(WND *wndPtr, WPARAM wParam, LPARAM lParam);
static LRESULT EDIT_EM_ReplaceSel(WND *wndPtr, WPARAM wParam, LPARAM lParam);
static LRESULT EDIT_EM_Scroll(WND *wndPtr, WPARAM wParam, LPARAM lParam);
static LRESULT EDIT_EM_SetHandle(WND *wndPtr, WPARAM wParam, LPARAM lParam);
static LRESULT EDIT_EM_SetModify(WND *wndPtr, WPARAM wParam, LPARAM lParam);
static LRESULT EDIT_EM_SetPasswordChar(WND *wndPtr, WPARAM wParam, LPARAM lParam);
static LRESULT EDIT_EM_SetReadOnly(WND *wndPtr, WPARAM wParam, LPARAM lParam);
static LRESULT EDIT_EM_SetRect(WND *wndPtr, WPARAM wParam, LPARAM lParam);
static LRESULT EDIT_EM_SetRectNP(WND *wndPtr, WPARAM wParam, LPARAM lParam);
static LRESULT EDIT_EM_SetSel(WND *wndPtr, WPARAM wParam, LPARAM lParam);
static LRESULT EDIT_EM_SetTabStops(WND *wndPtr, WPARAM wParam, LPARAM lParam);
static LRESULT EDIT_EM_SetWordBreakProc(WND *wndPtr, WPARAM wParam, LPARAM lParam);
static LRESULT EDIT_EM_Undo(WND *wndPtr, WPARAM wParam, LPARAM lParam);
static LRESULT EDIT_WM_Char(WND *wndPtr, WPARAM wParam, LPARAM lParam);
static LRESULT EDIT_WM_Clear(WND *wndPtr, WPARAM wParam, LPARAM lParam);
static LRESULT EDIT_WM_Copy(WND *wndPtr, WPARAM wParam, LPARAM lParam);
static LRESULT EDIT_WM_Cut(WND *wndPtr, WPARAM wParam, LPARAM lParam);
static LRESULT EDIT_WM_Create(WND *wndPtr, WPARAM wParam, LPARAM lParam);
static LRESULT EDIT_WM_Destroy(WND *wndPtr, WPARAM wParam, LPARAM lParam);
static LRESULT EDIT_WM_Enable(WND *wndPtr, WPARAM wParam, LPARAM lParam);
static LRESULT EDIT_WM_EraseBkGnd(WND *wndPtr, WPARAM wParam, LPARAM lParam);
static LRESULT EDIT_WM_GetDlgCode(WND *wndPtr, WPARAM wParam, LPARAM lParam);
static LRESULT EDIT_WM_GetFont(WND *wndPtr, WPARAM wParam, LPARAM lParam);
static LRESULT EDIT_WM_GetText(WND *wndPtr, WPARAM wParam, LPARAM lParam);
static LRESULT EDIT_WM_GetTextLength(WND *wndPtr, WPARAM wParam, LPARAM lParam);
static LRESULT EDIT_WM_HScroll(WND *wndPtr, WPARAM wParam, LPARAM lParam);
static LRESULT EDIT_WM_KeyDown(WND *wndPtr, WPARAM wParam, LPARAM lParam);
static LRESULT EDIT_WM_KillFocus(WND *wndPtr, WPARAM wParam, LPARAM lParam);
static LRESULT EDIT_WM_LButtonDblClk(WND *wndPtr, WPARAM wParam, LPARAM lParam);
static LRESULT EDIT_WM_LButtonDown(WND *wndPtr, WPARAM wParam, LPARAM lParam);
static LRESULT EDIT_WM_LButtonUp(WND *wndPtr, WPARAM wParam, LPARAM lParam);
static LRESULT EDIT_WM_MouseMove(WND *wndPtr, WPARAM wParam, LPARAM lParam);
static LRESULT EDIT_WM_Paint(WND *wndPtr, WPARAM wParam, LPARAM lParam);
static LRESULT EDIT_WM_Paste(WND *wndPtr, WPARAM wParam, LPARAM lParam);
static LRESULT EDIT_WM_SetCursor(WND *wndPtr, WPARAM wParam, LPARAM lParam);
static LRESULT EDIT_WM_SetFocus(WND *wndPtr, WPARAM wParam, LPARAM lParam);
static LRESULT EDIT_WM_SetFont(WND *wndPtr, WPARAM wParam, LPARAM lParam);
static LRESULT EDIT_WM_SetRedraw(WND *wndPtr, WPARAM wParam, LPARAM lParam);
static LRESULT EDIT_WM_SetText(WND *wndPtr, WPARAM wParam, LPARAM lParam);
static LRESULT EDIT_WM_Size(WND *wndPtr, WPARAM wParam, LPARAM lParam);
static LRESULT EDIT_WM_VScroll(WND *wndPtr, WPARAM wParam, LPARAM lParam);
/*********************************************************************
*
* EditWndProc()
*
*/
LRESULT EditWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
LRESULT lResult = 0L;
WND *wndPtr = WIN_FindWndPtr(hwnd);
switch (msg) {
case EM_CANUNDO:
DPRINTF_EDIT_MSG("EM_CANUNDO");
lResult = EDIT_EM_CanUndo(wndPtr, wParam, lParam);
break;
case EM_EMPTYUNDOBUFFER:
DPRINTF_EDIT_MSG("EM_EMPTYUNDOBUFFER");
lResult = EDIT_EM_EmptyUndoBuffer(wndPtr, wParam, lParam);
break;
case EM_FMTLINES:
DPRINTF_EDIT_MSG("EM_FMTLINES");
lResult = EDIT_EM_FmtLines(wndPtr, wParam, lParam);
break;
case EM_GETFIRSTVISIBLELINE:
DPRINTF_EDIT_MSG("EM_GETFIRSTVISIBLELINE");
lResult = EDIT_EM_GetFirstVisibleLine(wndPtr, wParam, lParam);
break;
case EM_GETHANDLE:
DPRINTF_EDIT_MSG("EM_GETHANDLE");
lResult = EDIT_EM_GetHandle(wndPtr, wParam, lParam);
break;
case EM_GETLINE:
DPRINTF_EDIT_MSG("EM_GETLINE");
lResult = EDIT_EM_GetLine(wndPtr, wParam, lParam);
break;
case EM_GETLINECOUNT:
DPRINTF_EDIT_MSG("EM_GETLINECOUNT");
lResult = EDIT_EM_GetLineCount(wndPtr, wParam, lParam);
break;
case EM_GETMODIFY:
DPRINTF_EDIT_MSG("EM_GETMODIFY");
lResult = EDIT_EM_GetModify(wndPtr, wParam, lParam);
break;
case EM_GETPASSWORDCHAR:
DPRINTF_EDIT_MSG("EM_GETPASSWORDCHAR");
lResult = EDIT_EM_GetPasswordChar(wndPtr, wParam, lParam);
break;
case EM_GETRECT:
DPRINTF_EDIT_MSG("EM_GETRECT");
lResult = EDIT_EM_GetRect(wndPtr, wParam, lParam);
break;
case EM_GETSEL:
DPRINTF_EDIT_MSG("EM_GETSEL");
lResult = EDIT_EM_GetSel(wndPtr, wParam, lParam);
break;
case EM_GETTHUMB:
DPRINTF_EDIT_MSG("EM_GETTHUMB");
lResult = EDIT_EM_GetThumb(wndPtr, wParam, lParam);
break;
case EM_GETWORDBREAKPROC:
DPRINTF_EDIT_MSG("EM_GETWORDBREAKPROC");
lResult = EDIT_EM_GetWordBreakProc(wndPtr, wParam, lParam);
break;
case EM_LIMITTEXT:
DPRINTF_EDIT_MSG("EM_LIMITTEXT");
lResult = EDIT_EM_LimitText(wndPtr, wParam, lParam);
break;
case EM_LINEFROMCHAR:
DPRINTF_EDIT_MSG("EM_LINEFROMCHAR");
lResult = EDIT_EM_LineFromChar(wndPtr, wParam, lParam);
break;
case EM_LINEINDEX:
DPRINTF_EDIT_MSG("EM_LINEINDEX");
lResult = EDIT_EM_LineIndex(wndPtr, wParam, lParam);
break;
case EM_LINELENGTH:
DPRINTF_EDIT_MSG("EM_LINELENGTH");
lResult = EDIT_EM_LineLength(wndPtr, wParam, lParam);
break;
case EM_LINESCROLL:
DPRINTF_EDIT_MSG("EM_LINESCROLL");
lResult = EDIT_EM_LineScroll(wndPtr, wParam, lParam);
break;
case EM_REPLACESEL:
DPRINTF_EDIT_MSG("EM_REPLACESEL");
lResult = EDIT_EM_ReplaceSel(wndPtr, wParam, lParam);
break;
case EM_SCROLL:
DPRINTF_EDIT_MSG("EM_SCROLL");
lResult = EDIT_EM_Scroll(wndPtr, wParam, lParam);
break;
case EM_SETHANDLE:
DPRINTF_EDIT_MSG("EM_SETHANDLE");
lResult = EDIT_EM_SetHandle(wndPtr, wParam, lParam);
break;
case EM_SETMODIFY:
DPRINTF_EDIT_MSG("EM_SETMODIFY");
lResult = EDIT_EM_SetModify(wndPtr, wParam, lParam);
break;
case EM_SETPASSWORDCHAR:
DPRINTF_EDIT_MSG("EM_SETPASSWORDCHAR");
lResult = EDIT_EM_SetPasswordChar(wndPtr, wParam, lParam);
break;
case EM_SETREADONLY:
DPRINTF_EDIT_MSG("EM_SETREADONLY");
lResult = EDIT_EM_SetReadOnly(wndPtr, wParam, lParam);
break;
case EM_SETRECT:
DPRINTF_EDIT_MSG("EM_SETRECT");
lResult = EDIT_EM_SetRect(wndPtr, wParam, lParam);
break;
case EM_SETRECTNP:
DPRINTF_EDIT_MSG("EM_SETRECTNP");
lResult = EDIT_EM_SetRectNP(wndPtr, wParam, lParam);
break;
case EM_SETSEL:
DPRINTF_EDIT_MSG("EM_SETSEL");
lResult = EDIT_EM_SetSel(wndPtr, wParam, lParam);
break;
case EM_SETTABSTOPS:
DPRINTF_EDIT_MSG("EM_SETTABSTOPS");
lResult = EDIT_EM_SetTabStops(wndPtr, wParam, lParam);
break;
case EM_SETWORDBREAKPROC:
DPRINTF_EDIT_MSG("EM_SETWORDBREAKPROC");
lResult = EDIT_EM_SetWordBreakProc(wndPtr, wParam, lParam);
break;
case EM_UNDO:
case WM_UNDO:
DPRINTF_EDIT_MSG("EM_UNDO / WM_UNDO");
lResult = EDIT_EM_Undo(wndPtr, wParam, lParam);
break;
case WM_GETDLGCODE:
DPRINTF_EDIT_MSG("WM_GETDLGCODE");
lResult = EDIT_WM_GetDlgCode(wndPtr, wParam, lParam);
break;
case WM_CHAR:
DPRINTF_EDIT_MSG("WM_CHAR");
lResult = EDIT_WM_Char(wndPtr, wParam, lParam);
break;
case WM_CLEAR:
DPRINTF_EDIT_MSG("WM_CLEAR");
lResult = EDIT_WM_Clear(wndPtr, wParam, lParam);
break;
case WM_COPY:
DPRINTF_EDIT_MSG("WM_COPY");
lResult = EDIT_WM_Copy(wndPtr, wParam, lParam);
break;
case WM_CREATE:
DPRINTF_EDIT_MSG("WM_CREATE");
lResult = EDIT_WM_Create(wndPtr, wParam, lParam);
break;
case WM_CUT:
DPRINTF_EDIT_MSG("WM_CUT");
lResult = EDIT_WM_Cut(wndPtr, wParam, lParam);
break;
case WM_DESTROY:
DPRINTF_EDIT_MSG("WM_DESTROY");
lResult = EDIT_WM_Destroy(wndPtr, wParam, lParam);
break;
case WM_ENABLE:
DPRINTF_EDIT_MSG("WM_ENABLE");
lResult = EDIT_WM_Enable(wndPtr, wParam, lParam);
break;
case WM_ERASEBKGND:
DPRINTF_EDIT_MSG("WM_ERASEBKGND");
lResult = EDIT_WM_EraseBkGnd(wndPtr, wParam, lParam);
break;
case WM_GETFONT:
DPRINTF_EDIT_MSG("WM_GETFONT");
lResult = EDIT_WM_GetFont(wndPtr, wParam, lParam);
break;
case WM_GETTEXT:
DPRINTF_EDIT_MSG("WM_GETTEXT");
lResult = EDIT_WM_GetText(wndPtr, wParam, lParam);
break;
case WM_GETTEXTLENGTH:
DPRINTF_EDIT_MSG("WM_GETTEXTLENGTH");
lResult = EDIT_WM_GetTextLength(wndPtr, wParam, lParam);
break;
case WM_HSCROLL:
DPRINTF_EDIT_MSG("WM_HSCROLL");
lResult = EDIT_WM_HScroll(wndPtr, wParam, lParam);
break;
case WM_KEYDOWN:
DPRINTF_EDIT_MSG("WM_KEYDOWN");
lResult = EDIT_WM_KeyDown(wndPtr, wParam, lParam);
break;
case WM_KILLFOCUS:
DPRINTF_EDIT_MSG("WM_KILLFOCUS");
lResult = EDIT_WM_KillFocus(wndPtr, wParam, lParam);
break;
case WM_LBUTTONDBLCLK:
DPRINTF_EDIT_MSG("WM_LBUTTONDBLCLK");
lResult = EDIT_WM_LButtonDblClk(wndPtr, wParam, lParam);
break;
case WM_LBUTTONDOWN:
DPRINTF_EDIT_MSG("WM_LBUTTONDOWN");
lResult = EDIT_WM_LButtonDown(wndPtr, wParam, lParam);
break;
case WM_LBUTTONUP:
DPRINTF_EDIT_MSG("WM_LBUTTONUP");
lResult = EDIT_WM_LButtonUp(wndPtr, wParam, lParam);
break;
case WM_MOUSEMOVE:
/*
* DPRINTF_EDIT_MSG("WM_MOUSEMOVE");
*/
lResult = EDIT_WM_MouseMove(wndPtr, wParam, lParam);
break;
case WM_PAINT:
DPRINTF_EDIT_MSG("WM_PAINT");
lResult = EDIT_WM_Paint(wndPtr, wParam, lParam);
break;
case WM_PASTE:
DPRINTF_EDIT_MSG("WM_PASTE");
lResult = EDIT_WM_Paste(wndPtr, wParam, lParam);
break;
case WM_SETCURSOR:
/*
* DPRINTF_EDIT_MSG("WM_SETCURSOR");
*/
lResult = EDIT_WM_SetCursor(wndPtr, wParam, lParam);
break;
case WM_SETFOCUS:
DPRINTF_EDIT_MSG("WM_SETFOCUS");
lResult = EDIT_WM_SetFocus(wndPtr, wParam, lParam);
break;
case WM_SETFONT:
DPRINTF_EDIT_MSG("WM_SETFONT");
lResult = EDIT_WM_SetFont(wndPtr, wParam, lParam);
break;
case WM_SETREDRAW:
DPRINTF_EDIT_MSG("WM_SETREDRAW");
lResult = EDIT_WM_SetRedraw(wndPtr, wParam, lParam);
break;
case WM_SETTEXT:
DPRINTF_EDIT_MSG("WM_SETTEXT");
lResult = EDIT_WM_SetText(wndPtr, wParam, lParam);
break;
case WM_SIZE:
DPRINTF_EDIT_MSG("WM_SIZE");
lResult = EDIT_WM_Size(wndPtr, wParam, lParam);
break;
case WM_VSCROLL:
DPRINTF_EDIT_MSG("WM_VSCROLL");
lResult = EDIT_WM_VScroll(wndPtr, wParam, lParam);
break;
default:
if (msg >= WM_USER)
fprintf(stdnimp, "edit: undocumented message %d >= WM_USER, please report.\n", msg);
lResult = DefWindowProc(hwnd, msg, wParam, lParam);
break;
}
EDIT_ReleasePointer(wndPtr);
return lResult;
}
/*********************************************************************
*
* EDIT_BuildLineDefs
*
* Build array of pointers to text lines.
* Lines can end with '\0' (last line), nothing (if it is to long),
* a delimiter (usually ' '), a soft return '\r\r\n' or a hard return '\r\n'
*
*/
static void EDIT_BuildLineDefs(WND *wndPtr)
{
EDITSTATE *es = EDITSTATEPTR(wndPtr);
char *text = EDIT_GetPointer(wndPtr);
int ww = EDIT_GetWndWidth(wndPtr);
HDC hdc;
HFONT hFont;
HFONT oldFont = 0;
char *start, *cp;
int prev, next;
int width;
int length;
LINE_END ending;
hdc = GetDC(wndPtr->hwndSelf);
hFont = (HFONT)EDIT_WM_GetFont(wndPtr, 0, 0L);
if (hFont)
oldFont = SelectObject(hdc, hFont);
if (!IsMultiLine(wndPtr)) {
es->LineCount = 1;
es->LineDefs = xrealloc(es->LineDefs, sizeof(LINEDEF));
es->LineDefs[0].offset = 0;
es->LineDefs[0].length = EDIT_WM_GetTextLength(wndPtr, 0, 0L);
es->LineDefs[0].ending = END_0;
es->TextWidth = LOWORD(GetTabbedTextExtent(hdc, text,
es->LineDefs[0].length,
es->NumTabStops, es->TabStops));
} else {
es->LineCount = 0;
start = text;
do {
if (!(cp = strstr(start, "\r\n"))) {
ending = END_0;
length = strlen(start);
} else if ((cp > start) && (*(cp - 1) == '\r')) {
ending = END_SOFT;
length = cp - start - 1;
} else {
ending = END_HARD;
length = cp - start;
}
width = LOWORD(GetTabbedTextExtent(hdc, start, length,
es->NumTabStops, es->TabStops));
if (IsWordWrap(wndPtr) && (width > ww)) {
next = 0;
do {
prev = next;
next = EDIT_CallWordBreakProc(wndPtr, start,
prev + 1, length, WB_RIGHT);
width = LOWORD(GetTabbedTextExtent(hdc, start, next,
es->NumTabStops, es->TabStops));
} while (width <= ww);
if (prev) {
length = prev;
if (EDIT_CallWordBreakProc(wndPtr, start, length - 1,
length, WB_ISDELIMITER)) {
length--;
ending = END_DELIMIT;
} else
ending = END_NONE;
} else {
}
width = LOWORD(GetTabbedTextExtent(hdc, start, length,
es->NumTabStops, es->TabStops));
}
es->LineDefs = xrealloc(es->LineDefs, (es->LineCount + 1) * sizeof(LINEDEF));
es->LineDefs[es->LineCount].offset = start - text;
es->LineDefs[es->LineCount].length = length;
es->LineDefs[es->LineCount].ending = ending;
es->LineCount++;
es->TextWidth = MAX(es->TextWidth, width);
start += length;
switch (ending) {
case END_SOFT:
start += 3;
break;
case END_HARD:
start += 2;
break;
case END_DELIMIT:
start++;
break;
default:
break;
}
} while (*start || (ending == END_SOFT) || (ending == END_HARD));
}
if (hFont)
SelectObject(hdc, oldFont);
ReleaseDC(wndPtr->hwndSelf, hdc);
}
/*********************************************************************
*
* EDIT_CallWordBreakProc
*
* Call appropriate WordBreakProc (internal or external).
*
*/
static int EDIT_CallWordBreakProc(WND *wndPtr, char *s, int index, int count, int action)
{
EDITWORDBREAKPROC wbp = (EDITWORDBREAKPROC)EDIT_EM_GetWordBreakProc(wndPtr, 0, 0L);
if (wbp) {
return CallWordBreakProc((FARPROC)wbp,
(LONG)MAKE_SEGPTR(s), index, count, action);
} else
return EDIT_WordBreakProc(s, index, count, action);
}
/*********************************************************************
*
* EDIT_ColFromWndX
*
* Calculates, for a given line and X-coordinate on the screen, the column.
*
*/
static int EDIT_ColFromWndX(WND *wndPtr, int line, int x)
{
int linecount = EDIT_EM_GetLineCount(wndPtr, 0, 0L);
int lineindex = EDIT_EM_LineIndex(wndPtr, line, 0L);
int linelength = EDIT_EM_LineLength(wndPtr, lineindex, 0L);
int i;
line = MAX(0, MIN(line, linecount - 1));
for (i = 0 ; i < linelength ; i++)
if (EDIT_WndXFromCol(wndPtr, line, i) >= x)
break;
return i;
}
/*********************************************************************
*
* EDIT_DelEnd
*
* Delete all characters on this line to right of cursor.
*
*/
static void EDIT_DelEnd(WND *wndPtr)
{
EDIT_EM_SetSel(wndPtr, FALSE, MAKELPARAM(-1, 0));
EDIT_MoveEnd(wndPtr, TRUE);
EDIT_WM_Clear(wndPtr, 0, 0L);
}
/*********************************************************************
*
* EDIT_DelLeft
*
* Delete character to left of cursor.
*
*/
static void EDIT_DelLeft(WND *wndPtr)
{
EDIT_EM_SetSel(wndPtr, FALSE, MAKELPARAM(-1, 0));
EDIT_MoveBackward(wndPtr, TRUE);
EDIT_WM_Clear(wndPtr, 0, 0L);
}
/*********************************************************************
*
* EDIT_DelRight
*
* Delete character to right of cursor.
*
*/
static void EDIT_DelRight(WND *wndPtr)
{
EDIT_EM_SetSel(wndPtr, FALSE, MAKELPARAM(-1, 0));
EDIT_MoveForward(wndPtr, TRUE);
EDIT_WM_Clear(wndPtr, 0, 0L);
}
/*********************************************************************
*
* EDIT_GetAveCharWidth
*
*/
static int EDIT_GetAveCharWidth(WND *wndPtr)
{
EDITSTATE *es = EDITSTATEPTR(wndPtr);
return es->AveCharWidth;
}
/*********************************************************************
*
* EDIT_GetLineHeight
*
*/
static int EDIT_GetLineHeight(WND *wndPtr)
{
EDITSTATE *es = EDITSTATEPTR(wndPtr);
return es->LineHeight;
}
/*********************************************************************
*
* EDIT_GetLineRect
*
* Calculates the bounding rectangle for a line from a starting
* column to an ending column.
*
*/
static void EDIT_GetLineRect(WND *wndPtr, int line, int scol, int ecol, LPRECT rc)
{
rc->top = EDIT_WndYFromLine(wndPtr, line);
rc->bottom = rc->top + EDIT_GetLineHeight(wndPtr);
rc->left = EDIT_WndXFromCol(wndPtr, line, scol);
rc->right = (ecol < 0) ? EDIT_GetWndWidth(wndPtr) : EDIT_WndXFromCol(wndPtr, line, ecol);
}
/*********************************************************************
*
* EDIT_GetPointer
*
* This acts as a LOCAL_Lock(), but it locks only once. This way
* you can call it whenever you like, without unlocking.
*
*/
static char *EDIT_GetPointer(WND *wndPtr)
{
EDITSTATE *es = EDITSTATEPTR(wndPtr);
if (!es->text && es->hBuf)
es->text = LOCAL_Lock(wndPtr->hInstance, es->hBuf);
return es->text;
}
/*********************************************************************
*
* EDIT_GetRect
*
* Beware: This is not the function called on EM_GETRECT.
* It expects a (LPRECT) in lParam, not a (SEGPTR).
* It is used internally, as if there were no pointer difficulties.
*
*/
static LRESULT EDIT_GetRect(WND *wndPtr, WPARAM wParam, LPARAM lParam)
{
GetClientRect(wndPtr->hwndSelf, (LPRECT)lParam);
return 0L;
}
/*********************************************************************
*
* EDIT_GetRedraw
*
*/
static BOOL EDIT_GetRedraw(WND *wndPtr)
{
EDITSTATE *es = EDITSTATEPTR(wndPtr);
return es->Redraw;
}
/*********************************************************************
*
* EDIT_GetTextWidth
*
*/
static int EDIT_GetTextWidth(WND *wndPtr)
{
EDITSTATE *es = EDITSTATEPTR(wndPtr);
return es->TextWidth;
}
/*********************************************************************
*
* EDIT_GetVisibleLineCount
*
*/
static int EDIT_GetVisibleLineCount(WND *wndPtr)
{
RECT rc;
EDIT_GetRect(wndPtr, 0, (LPARAM)&rc);
return MAX(1, MAX(rc.bottom - rc.top, 0) / EDIT_GetLineHeight(wndPtr));
}
/*********************************************************************
*
* EDIT_GetWndWidth
*
*/
static int EDIT_GetWndWidth(WND *wndPtr)
{
RECT rc;
EDIT_GetRect(wndPtr, 0, (LPARAM)&rc);
return rc.right - rc.left;
}
/*********************************************************************
*
* EDIT_GetXOffset
*
*/
static int EDIT_GetXOffset(WND *wndPtr)
{
EDITSTATE *es = EDITSTATEPTR(wndPtr);
return es->XOffset;
}
/*********************************************************************
*
* EDIT_LineFromWndY
*
* Calculates, for a given Y-coordinate on the screen, the line.
*
*/
static int EDIT_LineFromWndY(WND *wndPtr, int y)
{
int firstvis = EDIT_EM_GetFirstVisibleLine(wndPtr, 0, 0L);
int lineheight = EDIT_GetLineHeight(wndPtr);
int linecount = EDIT_EM_GetLineCount(wndPtr, 0, 0L);
return MAX(0, MIN(linecount - 1, y / lineheight + firstvis));
}
/*********************************************************************
*
* EDIT_MakeFit
*
* Try to fit size + 1 bytes in the buffer. Contrain to limits.
*
*/
static BOOL EDIT_MakeFit(WND *wndPtr, int size)
{
EDITSTATE *es = EDITSTATEPTR(wndPtr);
if (size <= es->BufSize)
return TRUE;
if (size > es->BufLimit)
return FALSE;
es->BufSize = ((size / GROWLENGTH) + 1) * GROWLENGTH;
if (es->BufSize > es->BufLimit)
es->BufSize = es->BufLimit;
dprintf_edit(stddeb, "edit: EDIT_MakeFit: ReAlloc to %d+1\n", es->BufSize);
return LOCAL_ReAlloc(wndPtr->hInstance, es->hBuf, es->BufSize + 1, LMEM_MOVEABLE);
}
/*********************************************************************
*
* EDIT_MoveBackward
*
*/
static void EDIT_MoveBackward(WND *wndPtr, BOOL extend)
{
int s = LOWORD(EDIT_EM_GetSel(wndPtr, 0, 0L));
int e = HIWORD(EDIT_EM_GetSel(wndPtr, 0, 0L));
int l = EDIT_EM_LineFromChar(wndPtr, e, 0L);
int lineindex = EDIT_EM_LineIndex(wndPtr, l, 0L);
if (e - lineindex == 0) {
if (l) {
lineindex = EDIT_EM_LineIndex(wndPtr, l - 1, 0L);
e = lineindex + EDIT_EM_LineLength(wndPtr, lineindex, 0L);
}
} else
e--;
if (!extend)
s = e;
EDIT_EM_SetSel(wndPtr, TRUE, MAKELPARAM(s, e));
}
/*********************************************************************
*
* EDIT_MoveDownward
*
*/
static void EDIT_MoveDownward(WND *wndPtr, BOOL extend)
{
int s = LOWORD(EDIT_EM_GetSel(wndPtr, 0, 0L));
int e = HIWORD(EDIT_EM_GetSel(wndPtr, 0, 0L));
int l = EDIT_EM_LineFromChar(wndPtr, e, 0L);
int linecount = EDIT_EM_GetLineCount(wndPtr, e, 0L);
int lineindex = EDIT_EM_LineIndex(wndPtr, l, 0L);
int x;
if (l < linecount - 1) {
x = EDIT_WndXFromCol(wndPtr, l, e - lineindex);
l++;
e = EDIT_EM_LineIndex(wndPtr, l, 0L) +
EDIT_ColFromWndX(wndPtr, l, x);
}
if (!extend)
s = e;
EDIT_EM_SetSel(wndPtr, TRUE, MAKELPARAM(s, e));
}
/*********************************************************************
*
* EDIT_MoveEnd
*
*/
static void EDIT_MoveEnd(WND *wndPtr, BOOL extend)
{
int s = LOWORD(EDIT_EM_GetSel(wndPtr, 0, 0L));
int e = HIWORD(EDIT_EM_GetSel(wndPtr, 0, 0L));
int l = EDIT_EM_LineFromChar(wndPtr, e, 0L);
int linelength = EDIT_EM_LineLength(wndPtr, e, 0L);
int lineindex = EDIT_EM_LineIndex(wndPtr, l, 0L);
e = lineindex + linelength;
if (!extend)
s = e;
EDIT_EM_SetSel(wndPtr, TRUE, MAKELPARAM(s, e));
}
/*********************************************************************
*
* EDIT_MoveForward
*
*/
static void EDIT_MoveForward(WND *wndPtr, BOOL extend)
{
int s = LOWORD(EDIT_EM_GetSel(wndPtr, 0, 0L));
int e = HIWORD(EDIT_EM_GetSel(wndPtr, 0, 0L));
int l = EDIT_EM_LineFromChar(wndPtr, e, 0L);
int linecount = EDIT_EM_GetLineCount(wndPtr, e, 0L);
int linelength = EDIT_EM_LineLength(wndPtr, e, 0L);
int lineindex = EDIT_EM_LineIndex(wndPtr, l, 0L);
if (e - lineindex == linelength) {
if (l != linecount - 1)
e = EDIT_EM_LineIndex(wndPtr, l + 1, 0L);
} else
e++;
if (!extend)
s = e;
EDIT_EM_SetSel(wndPtr, TRUE, MAKELPARAM(s, e));
}
/*********************************************************************
*
* EDIT_MoveHome
*
* Home key: move to beginning of line.
*
*/
static void EDIT_MoveHome(WND *wndPtr, BOOL extend)
{
int s = LOWORD(EDIT_EM_GetSel(wndPtr, 0, 0L));
int e = HIWORD(EDIT_EM_GetSel(wndPtr, 0, 0L));
int l = EDIT_EM_LineFromChar(wndPtr, e, 0L);
int lineindex = EDIT_EM_LineIndex(wndPtr, l, 0L);
e = lineindex;
if (!extend)
s = e;
EDIT_EM_SetSel(wndPtr, TRUE, MAKELPARAM(s, e));
}
/*********************************************************************
*
* EDIT_MovePageDown
*
*/
static void EDIT_MovePageDown(WND *wndPtr, BOOL extend)
{
int s = LOWORD(EDIT_EM_GetSel(wndPtr, 0, 0L));
int e = HIWORD(EDIT_EM_GetSel(wndPtr, 0, 0L));
int l = EDIT_EM_LineFromChar(wndPtr, e, 0L);
int linecount = EDIT_EM_GetLineCount(wndPtr, e, 0L);
int lineindex = EDIT_EM_LineIndex(wndPtr, l, 0L);
int x;
if (l < linecount - 1) {
x = EDIT_WndXFromCol(wndPtr, l, e - lineindex);
l = MIN(linecount - 1, l + EDIT_GetVisibleLineCount(wndPtr));
e = EDIT_EM_LineIndex(wndPtr, l, 0L) +
EDIT_ColFromWndX(wndPtr, l, x);
}
if (!extend)
s = e;
EDIT_EM_SetSel(wndPtr, TRUE, MAKELPARAM(s, e));
}
/*********************************************************************
*
* EDIT_MovePageUp
*
*/
static void EDIT_MovePageUp(WND *wndPtr, BOOL extend)
{
int s = LOWORD(EDIT_EM_GetSel(wndPtr, 0, 0L));
int e = HIWORD(EDIT_EM_GetSel(wndPtr, 0, 0L));
int l = EDIT_EM_LineFromChar(wndPtr, e, 0L);
int lineindex = EDIT_EM_LineIndex(wndPtr, l, 0L);
int x;
if (l) {
x = EDIT_WndXFromCol(wndPtr, l, e - lineindex);
l = MAX(0, l - EDIT_GetVisibleLineCount(wndPtr));
e = EDIT_EM_LineIndex(wndPtr, l, 0L) +
EDIT_ColFromWndX(wndPtr, l, x);
}
if (!extend)
s = e;
EDIT_EM_SetSel(wndPtr, TRUE, MAKELPARAM(s, e));
}
/*********************************************************************
*
* EDIT_MoveUpward
*
*/
static void EDIT_MoveUpward(WND *wndPtr, BOOL extend)
{
int s = LOWORD(EDIT_EM_GetSel(wndPtr, 0, 0L));
int e = HIWORD(EDIT_EM_GetSel(wndPtr, 0, 0L));
int l = EDIT_EM_LineFromChar(wndPtr, e, 0L);
int lineindex = EDIT_EM_LineIndex(wndPtr, l, 0L);
int x;
if (l) {
x = EDIT_WndXFromCol(wndPtr, l, e - lineindex);
l--;
e = EDIT_EM_LineIndex(wndPtr, l, 0L) +
EDIT_ColFromWndX(wndPtr, l, x);
}
if (!extend)
s = e;
EDIT_EM_SetSel(wndPtr, TRUE, MAKELPARAM(s, e));
}
/*********************************************************************
*
* EDIT_MoveWordBackward
*
*/
static void EDIT_MoveWordBackward(WND *wndPtr, BOOL extend)
{
int s = LOWORD(EDIT_EM_GetSel(wndPtr, 0, 0L));
int e = HIWORD(EDIT_EM_GetSel(wndPtr, 0, 0L));
int l = EDIT_EM_LineFromChar(wndPtr, e, 0L);
int linelength = EDIT_EM_LineLength(wndPtr, e, 0L);
int lineindex = EDIT_EM_LineIndex(wndPtr, l, 0L);
char *text;
if (e - lineindex == 0) {
if (l) {
lineindex = EDIT_EM_LineIndex(wndPtr, l - 1, 0L);
e = lineindex + EDIT_EM_LineLength(wndPtr, lineindex, 0L);
}
} else {
text = EDIT_GetPointer(wndPtr);
e = lineindex + EDIT_CallWordBreakProc(wndPtr, text + lineindex,
e - lineindex, linelength, WB_LEFT);
}
if (!extend)
s = e;
EDIT_EM_SetSel(wndPtr, TRUE, MAKELPARAM(s, e));
}
/*********************************************************************
*
* EDIT_MoveWordForward
*
*/
static void EDIT_MoveWordForward(WND *wndPtr, BOOL extend)
{
int s = LOWORD(EDIT_EM_GetSel(wndPtr, 0, 0L));
int e = HIWORD(EDIT_EM_GetSel(wndPtr, 0, 0L));
int l = EDIT_EM_LineFromChar(wndPtr, e, 0L);
int linecount = EDIT_EM_GetLineCount(wndPtr, e, 0L);
int linelength = EDIT_EM_LineLength(wndPtr, e, 0L);
int lineindex = EDIT_EM_LineIndex(wndPtr, l, 0L);
char *text;
if (e - lineindex == linelength) {
if (l != linecount - 1)
e = EDIT_EM_LineIndex(wndPtr, l + 1, 0L);
} else {
text = EDIT_GetPointer(wndPtr);
e = lineindex + EDIT_CallWordBreakProc(wndPtr, text + lineindex,
e - lineindex + 1, linelength, WB_RIGHT);
}
if (!extend)
s = e;
EDIT_EM_SetSel(wndPtr, TRUE, MAKELPARAM(s, e));
}
/*********************************************************************
*
* EDIT_PaintLine
*
*/
static void EDIT_PaintLine(WND *wndPtr, HDC hdc, int line)
{
EDITSTATE *es = EDITSTATEPTR(wndPtr);
int firstvis = EDIT_EM_GetFirstVisibleLine(wndPtr, 0, 0L);
int viscount = EDIT_GetVisibleLineCount(wndPtr);
int linecount = EDIT_EM_GetLineCount(wndPtr, 0, 0L);
int LineStart;
int LineEnd;
int ReverseStart;
int ReverseEnd;
int x;
int y;
if ((line < firstvis) || (line > firstvis + viscount) || (line >= linecount))
return;
dprintf_edit(stddeb, "edit: EDIT_PaintLine: line=%d\n", line);
x = EDIT_WndXFromCol(wndPtr, line, 0);
y = EDIT_WndYFromLine(wndPtr, line);
LineStart = EDIT_EM_LineIndex(wndPtr, line, 0L);
LineEnd = LineStart + EDIT_EM_LineLength(wndPtr, LineStart, 0L);
ReverseStart = MIN(es->SelStart, es->SelEnd);
ReverseEnd = MAX(es->SelStart, es->SelEnd);
ReverseStart = MIN(LineEnd, MAX(LineStart, ReverseStart));
ReverseEnd = MIN(LineEnd, MAX(LineStart, ReverseEnd));
if (ReverseStart != ReverseEnd) {
x += EDIT_PaintText(wndPtr, hdc, x, y, line,
0, ReverseStart - LineStart, FALSE);
x += EDIT_PaintText(wndPtr, hdc, x, y, line,
ReverseStart - LineStart,
ReverseEnd - ReverseStart, TRUE);
x += EDIT_PaintText(wndPtr, hdc, x, y, line,
ReverseEnd - LineStart,
LineEnd - ReverseEnd, FALSE);
} else
x += EDIT_PaintText(wndPtr, hdc, x, y, line,
0, LineEnd - LineStart, FALSE);
}
/*********************************************************************
*
* EDIT_PaintText
*
*/
static int EDIT_PaintText(WND *wndPtr, HDC hdc, int x, int y, int line, int col, int count, BOOL rev)
{
EDITSTATE *es = EDITSTATEPTR(wndPtr);
COLORREF BkColor;
COLORREF TextColor;
int ret;
char *text;
int lineindex = EDIT_EM_LineIndex(wndPtr, line, 0L);
int xoffset = EDIT_GetXOffset(wndPtr);
if (count < 1)
return 0;
BkColor = GetBkColor(hdc);
TextColor = GetTextColor(hdc);
if (rev) {
SetBkColor(hdc, GetSysColor(COLOR_HIGHLIGHT));
SetTextColor(hdc, GetSysColor(COLOR_HIGHLIGHTTEXT));
}
text = EDIT_GetPointer(wndPtr);
ret = LOWORD(TabbedTextOut(hdc, x, y, text + lineindex + col, count,
es->NumTabStops, es->TabStops, -xoffset));
if (rev) {
SetBkColor(hdc, BkColor);
SetTextColor(hdc, TextColor);
}
return ret;
}
/*********************************************************************
*
* EDIT_ReleasePointer
*
* This is the only helper function that can be called with es = NULL.
* It is called at the end of EditWndProc() to unlock the buffer.
*
*/
static void EDIT_ReleasePointer(WND *wndPtr)
{
EDITSTATE *es = EDITSTATEPTR(wndPtr);
if (!es)
return;
if (es->text && es->hBuf)
LOCAL_Unlock(wndPtr->hInstance, es->hBuf);
es->text = NULL;
}
/*********************************************************************
*
* EDIT_ReplaceSel
*
* Beware: This is not the function called on EM_REPLACESEL.
* It expects a (char *) in lParam, not a (SEGPTR).
* It is used internally, as if there were no pointer difficulties.
*
*/
static LRESULT EDIT_ReplaceSel(WND *wndPtr, WPARAM wParam, LPARAM lParam)
{
const char *str = (char *)lParam;
int strl = strlen(str);
int tl = EDIT_WM_GetTextLength(wndPtr, 0, 0L);
int s = LOWORD(EDIT_EM_GetSel(wndPtr, 0, 0L));
int e = HIWORD(EDIT_EM_GetSel(wndPtr, 0, 0L));
int i;
char *p;
char *text;
BOOL redraw;
ORDER_INT(s,e);
if (!EDIT_MakeFit(wndPtr, tl - (e - s) + strl)) {
EDIT_NOTIFY_PARENT(wndPtr, EN_MAXTEXT);
return 0L;
}
redraw = EDIT_GetRedraw(wndPtr);
EDIT_WM_SetRedraw(wndPtr, FALSE, 0L);
EDIT_WM_Clear(wndPtr, 0, 0L);
tl = EDIT_WM_GetTextLength(wndPtr, 0, 0L);
e = HIWORD(EDIT_EM_GetSel(wndPtr, 0, 0L));
text = EDIT_GetPointer(wndPtr);
for (p = text + tl ; p >= text + e ; p--)
p[strl] = p[0];
for (i = 0 , p = text + e ; i < strl ; i++)
p[i] = str[i];
EDIT_BuildLineDefs(wndPtr);
e += strl;
EDIT_EM_SetSel(wndPtr, TRUE, MAKELPARAM(e, e));
EDIT_EM_SetModify(wndPtr, TRUE, 0L);
EDIT_NOTIFY_PARENT(wndPtr, EN_UPDATE);
EDIT_WM_SetRedraw(wndPtr, redraw, 0L);
if (redraw) {
InvalidateRect(wndPtr->hwndSelf, NULL, TRUE);
EDIT_NOTIFY_PARENT(wndPtr, EN_CHANGE);
}
return 0L;
}
/*********************************************************************
*
* EDIT_ScrollIntoView
*
* Makes sure the caret is visible.
*
*/
static void EDIT_ScrollIntoView(WND *wndPtr)
{
int e = HIWORD(EDIT_EM_GetSel(wndPtr, 0, 0L));
int l = EDIT_EM_LineFromChar(wndPtr, e, 0L);
int lineindex = EDIT_EM_LineIndex(wndPtr, l, 0L);
int firstvis = EDIT_EM_GetFirstVisibleLine(wndPtr, 0, 0L);
int vislinecount = EDIT_GetVisibleLineCount(wndPtr);
int wndwidth = EDIT_GetWndWidth(wndPtr);
int charwidth = EDIT_GetAveCharWidth(wndPtr);
int x = EDIT_WndXFromCol(wndPtr, l, e - lineindex);
int dy = 0;
int dx = 0;
if (l >= firstvis + vislinecount)
dy = l - vislinecount + 1 - firstvis;
if (l < firstvis)
dy = l - firstvis;
if (x < 0)
dx = x - wndwidth / HSCROLL_FRACTION / charwidth * charwidth;
if (x > wndwidth)
dx = x - (HSCROLL_FRACTION - 1) * wndwidth / HSCROLL_FRACTION / charwidth * charwidth;
if (dy || dx) {
EDIT_EM_LineScroll(wndPtr, 0, MAKELPARAM(dy, dx));
if (dy)
EDIT_NOTIFY_PARENT(wndPtr, EN_VSCROLL);
if (dx)
EDIT_NOTIFY_PARENT(wndPtr, EN_HSCROLL);
}
}
/*********************************************************************
*
* EDIT_WndXFromCol
*
* Calculates, for a given line and column, the X-coordinate on the screen.
*
*/
static int EDIT_WndXFromCol(WND *wndPtr, int line, int col)
{
EDITSTATE *es = EDITSTATEPTR(wndPtr);
char *text = EDIT_GetPointer(wndPtr);
int ret;
HDC hdc;
HFONT hFont;
HFONT oldFont = 0;
int linecount = EDIT_EM_GetLineCount(wndPtr, 0, 0L);
int lineindex = EDIT_EM_LineIndex(wndPtr, line, 0L);
int linelength = EDIT_EM_LineLength(wndPtr, lineindex, 0L);
int xoffset = EDIT_GetXOffset(wndPtr);
hdc = GetDC(wndPtr->hwndSelf);
hFont = (HFONT)EDIT_WM_GetFont(wndPtr, 0, 0L);
if (hFont)
oldFont = SelectObject(hdc, hFont);
line = MAX(0, MIN(line, linecount - 1));
col = MAX(0, MIN(col, linelength));
ret = LOWORD(GetTabbedTextExtent(hdc,
text + lineindex, col,
es->NumTabStops, es->TabStops)) - xoffset;
if (hFont)
SelectObject(hdc, oldFont);
ReleaseDC(wndPtr->hwndSelf, hdc);
return ret;
}
/*********************************************************************
*
* EDIT_WndYFromLine
*
* Calculates, for a given line, the Y-coordinate on the screen.
*
*/
static int EDIT_WndYFromLine(WND *wndPtr, int line)
{
int firstvis = EDIT_EM_GetFirstVisibleLine(wndPtr, 0, 0L);
int lineheight = EDIT_GetLineHeight(wndPtr);
return (line - firstvis) * lineheight;
}
/*********************************************************************
*
* EDIT_WordBreakProc
*
* Find the beginning of words.
* Note: unlike the specs for a WordBreakProc, this function only
* allows to be called without linebreaks between s[0] upto
* s[count - 1]. Remember it is only called
* internally, so we can decide this for ourselves.
*
*/
static int EDIT_WordBreakProc(char *s, int index, int count, int action)
{
int ret = 0;
dprintf_edit(stddeb, "edit: EDIT_WordBreakProc: s=%p, index=%d"
", count=%d, action=%d\n", s, index, count, action);
switch (action) {
case WB_LEFT:
if (!count)
break;
if (index)
index--;
if (s[index] == ' ') {
while (index && (s[index] == ' '))
index--;
if (index) {
while (index && (s[index] != ' '))
index--;
if (s[index] == ' ')
index++;
}
} else {
while (index && (s[index] != ' '))
index--;
if (s[index] == ' ')
index++;
}
ret = index;
break;
case WB_RIGHT:
if (!count)
break;
if (index)
index--;
if (s[index] == ' ')
while ((index < count) && (s[index] == ' ')) index++;
else {
while (s[index] && (s[index] != ' ') && (index < count))
index++;
while ((s[index] == ' ') && (index < count)) index++;
}
ret = index;
break;
case WB_ISDELIMITER:
ret = (s[index] == ' ');
break;
default:
fprintf(stderr, "edit: EDIT_WordBreakProc: unknown action code, please report !\n");
break;
}
return ret;
}
/*********************************************************************
*
* EM_CANUNDO
*
*/
static LRESULT EDIT_EM_CanUndo(WND *wndPtr, WPARAM wParam, LPARAM lParam)
{
return 0L;
}
/*********************************************************************
*
* EM_EMPTYUNDOBUFFER
*
*/
static LRESULT EDIT_EM_EmptyUndoBuffer(WND *wndPtr, WPARAM wParam, LPARAM lParam)
{
return 0L;
}
/*********************************************************************
*
* EM_FMTLINES
*
*/
static LRESULT EDIT_EM_FmtLines(WND *wndPtr, WPARAM wParam, LPARAM lParam)
{
fprintf(stdnimp, "edit: EM_FMTLINES: message not implemented.\n");
return wParam ? -1L : 0L;
}
/*********************************************************************
*
* EM_GETFIRSTVISIBLELINE
*
*/
static LRESULT EDIT_EM_GetFirstVisibleLine(WND *wndPtr, WPARAM wParam, LPARAM lParam)
{
EDITSTATE *es = EDITSTATEPTR(wndPtr);
return (LRESULT)es->FirstVisibleLine;
}
/*********************************************************************
*
* EM_GETHANDLE
*
*/
static LRESULT EDIT_EM_GetHandle(WND *wndPtr, WPARAM wParam, LPARAM lParam)
{
EDITSTATE *es = EDITSTATEPTR(wndPtr);
return (LRESULT)es->hBuf;
}
/*********************************************************************
*
* EM_GETLINE
*
*/
static LRESULT EDIT_EM_GetLine(WND *wndPtr, WPARAM wParam, LPARAM lParam)
{
char *text;
char *src;
char *dst;
int len;
int i;
int linecount = EDIT_EM_GetLineCount(wndPtr, 0, 0L);
if (!IsMultiLine(wndPtr))
wParam = 0;
if ((UINT)wParam >= linecount)
return 0L;
text = EDIT_GetPointer(wndPtr);
src = text + EDIT_EM_LineIndex(wndPtr, wParam, 0L);
dst = (char *)PTR_SEG_TO_LIN(lParam);
len = MIN(*(WORD *)dst, EDIT_EM_LineLength(wndPtr, wParam, 0L));
for (i = 0 ; i < len ; i++) {
*dst = *src;
src++;
dst++;
}
return (LRESULT)len;
}
/*********************************************************************
*
* EM_GETLINECOUNT
*
*/
static LRESULT EDIT_EM_GetLineCount(WND *wndPtr, WPARAM wParam, LPARAM lParam)
{
EDITSTATE *es = EDITSTATEPTR(wndPtr);
return (LRESULT)es->LineCount;
}
/*********************************************************************
*
* EM_GETMODIFY
*
*/
static LRESULT EDIT_EM_GetModify(WND *wndPtr, WPARAM wParam, LPARAM lParam)
{
EDITSTATE *es = EDITSTATEPTR(wndPtr);
return (LRESULT)es->TextChanged;
}
/*********************************************************************
*
* EM_GETPASSWORDCHAR
*
*/
static LRESULT EDIT_EM_GetPasswordChar(WND *wndPtr, WPARAM wParam, LPARAM lParam)
{
EDITSTATE *es = EDITSTATEPTR(wndPtr);
return (LRESULT)es->PasswordChar;
}
/*********************************************************************
*
* EM_GETRECT
*
*/
static LRESULT EDIT_EM_GetRect(WND *wndPtr, WPARAM wParam, LPARAM lParam)
{
return EDIT_GetRect(wndPtr, wParam, (LPARAM)PTR_SEG_TO_LIN(lParam));
}
/*********************************************************************
*
* EM_GETSEL
*
*/
static LRESULT EDIT_EM_GetSel(WND *wndPtr, WPARAM wParam, LPARAM lParam)
{
EDITSTATE *es = EDITSTATEPTR(wndPtr);
return MAKELONG(es->SelStart, es->SelEnd);
}
/*********************************************************************
*
* EM_GETTHUMB
*
* undocumented: is this right ?
*
*/
static LRESULT EDIT_EM_GetThumb(WND *wndPtr, WPARAM wParam, LPARAM lParam)
{
return MAKELONG(EDIT_WM_VScroll(wndPtr, EM_GETTHUMB, 0L),
EDIT_WM_HScroll(wndPtr, EM_GETTHUMB, 0L));
}
/*********************************************************************
*
* EM_GETWORDBREAKPROC
*
*/
static LRESULT EDIT_EM_GetWordBreakProc(WND *wndPtr, WPARAM wParam, LPARAM lParam)
{
EDITSTATE *es = EDITSTATEPTR(wndPtr);
return (LRESULT)es->WordBreakProc;
}
/*********************************************************************
*
* EM_LIMITTEXT
*
*/
static LRESULT EDIT_EM_LimitText(WND *wndPtr, WPARAM wParam, LPARAM lParam)
{
EDITSTATE *es = EDITSTATEPTR(wndPtr);
if (IsMultiLine(wndPtr)) {
if (wParam)
es->BufLimit = MIN((UINT)wParam, BUFLIMIT_MULTI);
else
es->BufLimit = BUFLIMIT_MULTI;
} else {
if (wParam)
es->BufLimit = MIN((UINT)wParam, BUFLIMIT_SINGLE);
else
es->BufLimit = BUFLIMIT_SINGLE;
}
return 0L;
}
/*********************************************************************
*
* EM_LINEFROMCHAR
*
*/
static LRESULT EDIT_EM_LineFromChar(WND *wndPtr, WPARAM wParam, LPARAM lParam)
{
int l;
if (!IsMultiLine(wndPtr))
return 0L;
if ((INT)wParam == -1)
wParam = HIWORD(EDIT_EM_GetSel(wndPtr, 0, 0L));
l = EDIT_EM_GetLineCount(wndPtr, 0, 0L) - 1;
while (EDIT_EM_LineIndex(wndPtr, l, 0L) > (UINT)wParam)
l--;
return (LRESULT)l;
}
/*********************************************************************
*
* EM_LINEINDEX
*
*/
static LRESULT EDIT_EM_LineIndex(WND *wndPtr, WPARAM wParam, LPARAM lParam)
{
EDITSTATE *es = EDITSTATEPTR(wndPtr);
int e;
int l;
if ((INT)wParam < 0) {
e = HIWORD(EDIT_EM_GetSel(wndPtr, 0, 0L));
l = EDIT_EM_GetLineCount(wndPtr, 0, 0L) - 1;
while (es->LineDefs[l].offset > (UINT)wParam)
l--;
return (LRESULT)es->LineDefs[l].offset;
}
if (wParam >= es->LineCount)
return -1L;
return (LRESULT)es->LineDefs[wParam].offset;
}
/*********************************************************************
*
* EM_LINELENGTH
*
*/
static LRESULT EDIT_EM_LineLength(WND *wndPtr, WPARAM wParam, LPARAM lParam)
{
EDITSTATE *es = EDITSTATEPTR(wndPtr);
int SelStartLine;
int SelEndLine;
if (!IsMultiLine(wndPtr))
return (LRESULT)es->LineDefs[0].length;
if ((INT)wParam >= 0)
return (LRESULT)es->LineDefs[EDIT_EM_LineFromChar(wndPtr, wParam, 0L)].length;
SelStartLine = EDIT_EM_LineFromChar(wndPtr, es->SelStart, 0L);
SelEndLine = EDIT_EM_LineFromChar(wndPtr, es->SelEnd, 0L);
return (LRESULT)(es->SelStart - es->LineDefs[SelStartLine].offset +
es->LineDefs[SelEndLine].offset +
es->LineDefs[SelEndLine].length - es->SelEnd);
}
/*********************************************************************
*
* EM_LINESCROLL
*
*/
static LRESULT EDIT_EM_LineScroll(WND *wndPtr, WPARAM wParam, LPARAM lParam)
{
EDITSTATE *es = EDITSTATEPTR(wndPtr);
int linecount = EDIT_EM_GetLineCount(wndPtr, 0, 0L);
int firstvis = EDIT_EM_GetFirstVisibleLine(wndPtr, 0, 0L);
int newfirstvis = firstvis + (INT)LOWORD(lParam);
int xoffset = EDIT_GetXOffset(wndPtr);
int newxoffset = xoffset + (INT)HIWORD(lParam);
int textwidth = EDIT_GetTextWidth(wndPtr);
int dx;
int dy;
POINT pos;
HRGN hRgn;
if (newfirstvis < 0)
newfirstvis = 0;
if (newfirstvis >= linecount)
newfirstvis = linecount - 1;
if (newxoffset < 0)
newxoffset = 0;
if (newxoffset >= textwidth)
newxoffset = textwidth;
dx = xoffset - newxoffset;
dy = EDIT_WndYFromLine(wndPtr, firstvis) - EDIT_WndYFromLine(wndPtr, newfirstvis);
if (dx || dy) {
if (wndPtr->hwndSelf == GetFocus())
HideCaret(wndPtr->hwndSelf);
if (EDIT_GetRedraw(wndPtr)) {
hRgn = CreateRectRgn(0, 0, 0, 0);
GetUpdateRgn(wndPtr->hwndSelf, hRgn, FALSE);
ValidateRgn(wndPtr->hwndSelf, 0);
OffsetRgn(hRgn, dx, dy);
InvalidateRgn(wndPtr->hwndSelf, hRgn, TRUE);
DeleteObject(hRgn);
ScrollWindow(wndPtr->hwndSelf, dx, dy, NULL, NULL);
}
es->FirstVisibleLine = newfirstvis;
es->XOffset = newxoffset;
if (IsVScrollBar(wndPtr))
SetScrollPos(wndPtr->hwndSelf, SB_VERT,
EDIT_WM_VScroll(wndPtr, EM_GETTHUMB, 0L), TRUE);
if (IsHScrollBar(wndPtr))
SetScrollPos(wndPtr->hwndSelf, SB_HORZ,
EDIT_WM_HScroll(wndPtr, EM_GETTHUMB, 0L), TRUE);
if (wndPtr->hwndSelf == GetFocus()) {
GetCaretPos(&pos);
SetCaretPos(pos.x + dx, pos.y + dy);
ShowCaret(wndPtr->hwndSelf);
}
}
return -1L;
}
/*********************************************************************
*
* EM_REPLACESEL
*
*/
static LRESULT EDIT_EM_ReplaceSel(WND *wndPtr, WPARAM wParam, LPARAM lParam)
{
return (LRESULT)EDIT_ReplaceSel(wndPtr, wParam,
(LPARAM)(char *)PTR_SEG_TO_LIN(lParam));
}
/*********************************************************************
*
* EM_SCROLL
*
* FIXME: undocumented message.
*/
static LRESULT EDIT_EM_Scroll(WND *wndPtr, WPARAM wParam, LPARAM lParam)
{
fprintf(stdnimp, "edit: EM_SCROLL: message not implemented (undocumented), please report.\n");
return 0L;
}
/*********************************************************************
*
* EM_SETHANDLE
*
*/
static LRESULT EDIT_EM_SetHandle(WND *wndPtr, WPARAM wParam, LPARAM lParam)
{
EDITSTATE *es = EDITSTATEPTR(wndPtr);
if (IsMultiLine(wndPtr)) {
EDIT_ReleasePointer(wndPtr);
/*
* FIXME: specs say: old buffer should be freed
* by the aplication, but e.g. Notepad doesn't.
* Should we LOCAL_Free() the old hBuf ?
*/
LOCAL_Free(wndPtr->hInstance, es->hBuf);
es->hBuf = (HLOCAL)wParam;
es->BufSize = MIN(1, LOCAL_Size(wndPtr->hInstance, es->hBuf)) - 1;
es->hBuf = LOCAL_ReAlloc(wndPtr->hInstance, es->hBuf, es->BufSize + 1, LMEM_MOVEABLE);
es->LineCount = 0;
es->FirstVisibleLine = 0;
es->SelStart = es->SelEnd = 0;
EDIT_EM_EmptyUndoBuffer(wndPtr, 0, 0L);
EDIT_EM_SetModify(wndPtr, FALSE, 0L);
EDIT_BuildLineDefs(wndPtr);
if (EDIT_GetRedraw(wndPtr))
InvalidateRect(wndPtr->hwndSelf, NULL, TRUE);
}
return 0L;
}
/*********************************************************************
*
* EM_SETMODIFY
*
*/
static LRESULT EDIT_EM_SetModify(WND *wndPtr, WPARAM wParam, LPARAM lParam)
{
EDITSTATE *es = EDITSTATEPTR(wndPtr);
es->TextChanged = wParam;
return 0L;
}
/*********************************************************************
*
* EM_SETPASSWORDCHAR
*
*/
static LRESULT EDIT_EM_SetPasswordChar(WND *wndPtr, WPARAM wParam, LPARAM lParam)
{
EDITSTATE *es = EDITSTATEPTR(wndPtr);
es->PasswordChar = (char)wParam;
return 0L;
}
/*********************************************************************
*
* EM_SETREADONLY
*
*/
static LRESULT EDIT_EM_SetReadOnly(WND *wndPtr, WPARAM wParam, LPARAM lParam)
{
if ((BOOL)wParam)
wndPtr->dwStyle |= ES_READONLY;
else
wndPtr->dwStyle &= ~(DWORD)ES_READONLY;
return 0L;
}
/*********************************************************************
*
* EM_SETRECT
*
*/
static LRESULT EDIT_EM_SetRect(WND *wndPtr, WPARAM wParam, LPARAM lParam)
{
fprintf(stdnimp,"edit: EM_SETRECT: message not implemented, please report.\n");
return 0L;
}
/*********************************************************************
*
* EM_SETRECTNP
*
*/
static LRESULT EDIT_EM_SetRectNP(WND *wndPtr, WPARAM wParam, LPARAM lParam)
{
fprintf(stdnimp,"edit: EM_SETRECTNP: message not implemented, please report.\n");
return 0L;
}
/*********************************************************************
*
* EM_SETSEL
*
*/
static LRESULT EDIT_EM_SetSel(WND *wndPtr, WPARAM wParam, LPARAM lParam)
{
EDITSTATE *es = EDITSTATEPTR(wndPtr);
int ns = (INT)LOWORD(lParam);
int ne = (INT)HIWORD(lParam);
int s = LOWORD(EDIT_EM_GetSel(wndPtr, 0, 0L));
int e = HIWORD(EDIT_EM_GetSel(wndPtr, 0, 0L));
int sl;
int el;
int sc;
int ec;
int elineindex;
int tl = EDIT_WM_GetTextLength(wndPtr, 0, 0L);
RECT rc;
HRGN hRgn1, hRgn2;
HRGN oldRgn, newRgn;
if (ns < 0) {
ne = e;
ns = e;
} else {
ns = MIN(ns, tl);
if (ne < 0)
ne = tl;
ne = MIN(ne, tl);
}
es->SelStart = ns;
es->SelEnd = ne;
if (wndPtr->hwndSelf == GetFocus()) {
el = EDIT_EM_LineFromChar(wndPtr, ne, 0L);
elineindex = EDIT_EM_LineIndex(wndPtr, el, 0L);
SetCaretPos(EDIT_WndXFromCol(wndPtr, el, ne - elineindex),
EDIT_WndYFromLine(wndPtr, el));
}
if (wParam)
EDIT_ScrollIntoView(wndPtr);
/*
* Let's do some repainting
*/
ORDER_INT(s, e);
ORDER_INT(ns, ne);
if (EDIT_GetRedraw(wndPtr) &&
!(((s == e) && (ns == ne)) ||
((ns == s) && (ne == e)))) {
/* Yes, there is something to paint */
hRgn1 = CreateRectRgn(0, 0, 0, 0);
hRgn2 = CreateRectRgn(0, 0, 0, 0);
oldRgn = CreateRectRgn(0, 0, 0, 0);
newRgn = CreateRectRgn(0, 0, 0, 0);
/* Build the old selection region */
sl = EDIT_EM_LineFromChar(wndPtr, s, 0L);
el = EDIT_EM_LineFromChar(wndPtr, e, 0L);
sc = s - EDIT_EM_LineIndex(wndPtr, sl, 0L);
ec = e - EDIT_EM_LineIndex(wndPtr, el, 0L);
if (sl == el) {
EDIT_GetLineRect(wndPtr, sl, sc, ec, &rc);
SetRectRgn(oldRgn, rc.left, rc.top, rc.right, rc.bottom);
} else {
EDIT_GetLineRect(wndPtr, sl, sc, -1, &rc);
SetRectRgn(hRgn1, rc.left, rc.top, rc.right, rc.bottom);
EDIT_GetLineRect(wndPtr, el, 0, ec, &rc);
SetRectRgn(hRgn2, rc.left, rc.top, rc.right, rc.bottom);
CombineRgn(oldRgn, hRgn1, hRgn2, RGN_OR);
if (el > sl + 1) {
EDIT_GetLineRect(wndPtr, sl + 1, 0, -1, &rc);
rc.bottom = rc.top + (rc.bottom - rc.top) * (el - sl - 1);
CombineRgn(hRgn1, oldRgn, 0, RGN_COPY);
SetRectRgn(hRgn2, rc.left, rc.top, rc.right, rc.bottom);
CombineRgn(oldRgn, hRgn1, hRgn2, RGN_OR);
}
}
/* Build the new selection region */
sl = EDIT_EM_LineFromChar(wndPtr, ns, 0L);
el = EDIT_EM_LineFromChar(wndPtr, ne, 0L);
sc = ns - EDIT_EM_LineIndex(wndPtr, sl, 0L);
ec = ne - EDIT_EM_LineIndex(wndPtr, el, 0L);
if (sl == el) {
EDIT_GetLineRect(wndPtr, sl, sc, ec, &rc);
SetRectRgn(newRgn, rc.left, rc.top, rc.right, rc.bottom);
} else {
EDIT_GetLineRect(wndPtr, sl, sc, -1, &rc);
SetRectRgn(hRgn1, rc.left, rc.top, rc.right, rc.bottom);
EDIT_GetLineRect(wndPtr, el, 0, ec, &rc);
SetRectRgn(hRgn2, rc.left, rc.top, rc.right, rc.bottom);
CombineRgn(newRgn, hRgn1, hRgn2, RGN_OR);
if (el > sl + 1) {
EDIT_GetLineRect(wndPtr, sl + 1, 0, -1, &rc);
rc.bottom = rc.top + (rc.bottom - rc.top) * (el - sl - 1);
CombineRgn(hRgn1, newRgn, 0, RGN_COPY);
SetRectRgn(hRgn2, rc.left, rc.top, rc.right, rc.bottom);
CombineRgn(newRgn, hRgn1, hRgn2, RGN_OR);
}
}
/* Only difference needs painting */
CombineRgn(hRgn1, oldRgn, newRgn, RGN_XOR);
/* Only part in formatting RECT needs painting */
InvalidateRgn(wndPtr->hwndSelf, hRgn1, FALSE);
DeleteObject(hRgn1);
DeleteObject(hRgn2);
DeleteObject(oldRgn);
DeleteObject(newRgn);
}
return -1L;
}
/*********************************************************************
*
* EM_SETTABSTOPS
*
*/
static LRESULT EDIT_EM_SetTabStops(WND *wndPtr, WPARAM wParam, LPARAM lParam)
{
EDITSTATE *es = EDITSTATEPTR(wndPtr);
if (!IsMultiLine(wndPtr))
return 0L;
if (es->TabStops)
free(es->TabStops);
es->NumTabStops = wParam;
if (wParam == 0)
es->TabStops = NULL;
else {
es->TabStops = (unsigned short *)xmalloc(wParam * sizeof(unsigned short));
memcpy(es->TabStops, (unsigned short *)PTR_SEG_TO_LIN(lParam),
wParam * sizeof(unsigned short));
}
return 1L;
}
/*********************************************************************
*
* EM_SETWORDBREAKPROC
*
*/
static LRESULT EDIT_EM_SetWordBreakProc(WND *wndPtr, WPARAM wParam, LPARAM lParam)
{
EDITSTATE *es = EDITSTATEPTR(wndPtr);
es->WordBreakProc = (EDITWORDBREAKPROC)lParam;
return 0L;
}
/*********************************************************************
*
* EM_UNDO
*
*/
static LRESULT EDIT_EM_Undo(WND *wndPtr, WPARAM wParam, LPARAM lParam)
{
return 0L;
}
/*********************************************************************
*
* WM_CHAR
*
*/
static LRESULT EDIT_WM_Char(WND *wndPtr, WPARAM wParam, LPARAM lParam)
{
char str[2];
char c = (char)wParam;
switch (c) {
case '\r':
case '\n':
if (IsMultiLine(wndPtr)) {
if (IsReadOnly(wndPtr)) {
EDIT_MoveHome(wndPtr, FALSE);
EDIT_MoveDownward(wndPtr, FALSE);
} else
EDIT_ReplaceSel(wndPtr, 0, (LPARAM)"\r\n");
}
break;
case '\t':
if (IsMultiLine(wndPtr) && !IsReadOnly(wndPtr))
EDIT_ReplaceSel(wndPtr, 0, (LPARAM)"\t");
break;
default:
if (!IsReadOnly(wndPtr) && (c >= ' ') && (c != 127)) {
str[0] = c;
str[1] = '\0';
EDIT_ReplaceSel(wndPtr, 0, (LPARAM)str);
}
break;
}
return 0L;
}
/*********************************************************************
*
* WM_CLEAR
*
*/
static LRESULT EDIT_WM_Clear(WND *wndPtr, WPARAM wParam, LPARAM lParam)
{
int s = LOWORD(EDIT_EM_GetSel(wndPtr, 0, 0L));
int e = HIWORD(EDIT_EM_GetSel(wndPtr, 0, 0L));
char *text;
BOOL redraw;
if (s != e) {
redraw = EDIT_GetRedraw(wndPtr);
EDIT_WM_SetRedraw(wndPtr, FALSE, 0L);
ORDER_INT(s, e);
text = EDIT_GetPointer(wndPtr);
strcpy(text + s, text + e);
EDIT_BuildLineDefs(wndPtr);
EDIT_EM_SetSel(wndPtr, TRUE, MAKELPARAM(s, s));
EDIT_EM_SetModify(wndPtr, TRUE, 0L);
EDIT_NOTIFY_PARENT(wndPtr, EN_UPDATE);
EDIT_WM_SetRedraw(wndPtr, redraw, 0L);
if (redraw) {
InvalidateRect(wndPtr->hwndSelf, NULL, TRUE);
EDIT_NOTIFY_PARENT(wndPtr, EN_CHANGE);
}
}
return -1L;
}
/*********************************************************************
*
* WM_COPY
*
*/
static LRESULT EDIT_WM_Copy(WND *wndPtr, WPARAM wParam, LPARAM lParam)
{
int s = LOWORD(EDIT_EM_GetSel(wndPtr, 0, 0L));
int e = HIWORD(EDIT_EM_GetSel(wndPtr, 0, 0L));
HGLOBAL hdst;
char *text;
char *dst;
char *src;
int i;
if (e == s)
return -1L;
ORDER_INT(s, e);
hdst = GlobalAlloc(GMEM_MOVEABLE, (DWORD)(e - s + 1));
dst = GlobalLock(hdst);
text = EDIT_GetPointer(wndPtr);
src = text + s;
for (i = 0 ; i < e - s ; i++)
*dst++ = *src++;
*dst = '\0';
GlobalUnlock(hdst);
OpenClipboard(wndPtr->hwndSelf);
EmptyClipboard();
SetClipboardData(CF_TEXT, hdst);
CloseClipboard();
return -1L;
}
/*********************************************************************
*
* WM_CREATE
*
*/
static LRESULT EDIT_WM_Create(WND *wndPtr, WPARAM wParam, LPARAM lParam)
{
CREATESTRUCT *cs = (CREATESTRUCT *)PTR_SEG_TO_LIN(lParam);
EDITSTATE *es;
char *windowName = NULL;
char *text;
es = xmalloc(sizeof(EDITSTATE));
memset(es, 0, sizeof(EDITSTATE));
*(EDITSTATE **)wndPtr->wExtra = es;
if (IsMultiLine(wndPtr)) {
es->BufLimit = BUFLIMIT_MULTI;
es->PasswordChar = '\0';
} else {
es->BufLimit = BUFLIMIT_SINGLE;
es->PasswordChar = (cs->style & ES_PASSWORD) ? '*' : '\0';
}
es->BufSize = IsMultiLine(wndPtr) ? BUFSTART_MULTI : BUFSTART_SINGLE;
if (cs->lpszName)
windowName = (char *)PTR_SEG_TO_LIN(cs->lpszName);
if (windowName)
es->BufSize = MAX(es->BufSize, strlen(windowName));
es->hBuf = LOCAL_Alloc(wndPtr->hInstance, LMEM_MOVEABLE, es->BufSize + 1);
text = EDIT_GetPointer(wndPtr);
if (!text) {
fprintf(stderr, "edit: WM_CREATE: unable to heap buffer, please report !\n");
return -1L;
}
if (windowName)
strcpy(text, windowName);
else
text[0] = '\0';
if (cs->style & WS_VSCROLL)
cs->style |= ES_AUTOVSCROLL;
if (cs->style & WS_HSCROLL)
cs->style |= ES_AUTOHSCROLL;
/* remove the WS_CAPTION style if it has been set - this is really a */
/* pseudo option made from a combination of WS_BORDER and WS_DLGFRAME */
if ((cs->style & WS_BORDER) && (cs->style & WS_DLGFRAME))
cs->style ^= WS_DLGFRAME;
EDIT_WM_SetFont(wndPtr, 0, 0L);
EDIT_WM_SetRedraw(wndPtr, TRUE, 0L);
return 0L;
}
/*********************************************************************
*
* WM_CUT
*
*/
static LRESULT EDIT_WM_Cut(WND *wndPtr, WPARAM wParam, LPARAM lParam)
{
EDIT_WM_Copy(wndPtr, 0, 0L);
EDIT_WM_Clear(wndPtr, 0, 0L);
return -1L;
}
/*********************************************************************
*
* WM_DESTROY
*
*/
static LRESULT EDIT_WM_Destroy(WND *wndPtr, WPARAM wParam, LPARAM lParam)
{
EDITSTATE *es = EDITSTATEPTR(wndPtr);
free(es->LineDefs);
if (es->TabStops)
free(es->TabStops);
EDIT_ReleasePointer(wndPtr);
LOCAL_Free(wndPtr->hInstance, es->hBuf);
free(es);
*(EDITSTATE **)&wndPtr->wExtra = NULL;
return 0L;
}
/*********************************************************************
*
* WM_ENABLE
*
*/
static LRESULT EDIT_WM_Enable(WND *wndPtr, WPARAM wParam, LPARAM lParam)
{
return 0L;
}
/*********************************************************************
*
* WM_ERASEBKGND
*
*/
static LRESULT EDIT_WM_EraseBkGnd(WND *wndPtr, WPARAM wParam, LPARAM lParam)
{
HBRUSH hBrush;
RECT rc;
hBrush = (HBRUSH)EDIT_SEND_CTLCOLOR(wndPtr, wParam);
GetClientRect(wndPtr->hwndSelf, &rc);
IntersectClipRect((HDC)wParam, rc.left, rc.top, rc.right, rc.bottom);
GetClipBox((HDC)wParam, &rc);
/*
* FIXME: specs say that we should UnrealizeObject() the brush,
* but the specs of UnrealizeObject() say that we shouldn't
* unrealize a stock object. The default brush that
* DefWndProc() returns is ... a stock object.
*/
FillRect((HDC)wParam, &rc, hBrush);
return -1L;
}
/*********************************************************************
*
* WM_GETDLGCODE
*
*/
static LRESULT EDIT_WM_GetDlgCode(WND *wndPtr, WPARAM wParam, LPARAM lParam)
{
return DLGC_HASSETSEL | DLGC_WANTCHARS | DLGC_WANTARROWS;
}
/*********************************************************************
*
* WM_GETFONT
*
*/
static LRESULT EDIT_WM_GetFont(WND *wndPtr, WPARAM wParam, LPARAM lParam)
{
EDITSTATE *es = EDITSTATEPTR(wndPtr);
return (LRESULT)es->hFont;
}
/*********************************************************************
*
* WM_GETTEXT
*
*/
static LRESULT EDIT_WM_GetText(WND *wndPtr, WPARAM wParam, LPARAM lParam)
{
char *text = EDIT_GetPointer(wndPtr);
int len;
LRESULT lResult = 0L;
len = strlen(text);
if ((int)wParam > len) {
strcpy((char *)PTR_SEG_TO_LIN(lParam), text);
lResult = (LRESULT)len ;
}
return lResult;
}
/*********************************************************************
*
* WM_GETTEXTLENGTH
*
*/
static LRESULT EDIT_WM_GetTextLength(WND *wndPtr, WPARAM wParam, LPARAM lParam)
{
LRESULT ret;
char *text = EDIT_GetPointer(wndPtr);
ret = (LRESULT)strlen(text);
return ret;
}
/*********************************************************************
*
* WM_HSCROLL
*
* FIXME: scrollbar code itself is broken, so this one is a hack.
*
*/
static LRESULT EDIT_WM_HScroll(WND *wndPtr, WPARAM wParam, LPARAM lParam)
{
int wndwidth = EDIT_GetWndWidth(wndPtr);
int textwidth = EDIT_GetTextWidth(wndPtr);
int charwidth = EDIT_GetAveCharWidth(wndPtr);
int xoffset = EDIT_GetXOffset(wndPtr);
int dx = 0;
BOOL not = TRUE;
LRESULT ret = 0L;
switch (wParam) {
case SB_LINELEFT:
dx = -charwidth;
break;
case SB_LINERIGHT:
dx = charwidth;
break;
case SB_PAGELEFT:
dx = -wndwidth / HSCROLL_FRACTION / charwidth * charwidth;
break;
case SB_PAGERIGHT:
dx = wndwidth / HSCROLL_FRACTION / charwidth * charwidth;
break;
case SB_LEFT:
dx = -xoffset;
break;
case SB_RIGHT:
dx = textwidth - xoffset;
break;
case SB_THUMBTRACK:
/*
* not = FALSE;
*/
case SB_THUMBPOSITION:
dx = LOWORD(lParam) * textwidth / 100 - xoffset;
break;
/* The next two are undocumented ! */
case EM_GETTHUMB:
ret = textwidth ? MAKELONG(xoffset * 100 / textwidth, 0) : 0;
break;
case EM_LINESCROLL:
dx = LOWORD(lParam);
break;
case SB_ENDSCROLL:
default:
break;
}
if (dx) {
EDIT_EM_LineScroll(wndPtr, 0, MAKELPARAM(0, dx));
if (not)
EDIT_NOTIFY_PARENT(wndPtr, EN_HSCROLL);
}
return ret;
}
/*********************************************************************
*
* WM_KEYDOWN
*
* Handling of special keys that don't produce a WM_CHAR
* (i.e. non-printable keys) & Backspace & Delete
*
*/
static LRESULT EDIT_WM_KeyDown(WND *wndPtr, WPARAM wParam, LPARAM lParam)
{
int s = LOWORD(EDIT_EM_GetSel(wndPtr, 0, 0L));
int e = HIWORD(EDIT_EM_GetSel(wndPtr, 0, 0L));
BOOL shift;
BOOL control;
if (GetKeyState(VK_MENU) & 0x8000)
return 0L;
shift = GetKeyState(VK_SHIFT) & 0x8000;
control = GetKeyState(VK_CONTROL) & 0x8000;
switch (wParam) {
case VK_LEFT:
case VK_UP:
if (IsMultiLine(wndPtr) && (wParam == VK_UP))
EDIT_MoveUpward(wndPtr, shift);
else
if (control)
EDIT_MoveWordBackward(wndPtr, shift);
else
EDIT_MoveBackward(wndPtr, shift);
break;
case VK_RIGHT:
case VK_DOWN:
if (IsMultiLine(wndPtr) && (wParam == VK_DOWN))
EDIT_MoveDownward(wndPtr, shift);
else if (control)
EDIT_MoveWordForward(wndPtr, shift);
else
EDIT_MoveForward(wndPtr, shift);
break;
case VK_HOME:
EDIT_MoveHome(wndPtr, shift);
break;
case VK_END:
EDIT_MoveEnd(wndPtr, shift);
break;
case VK_PRIOR:
if (IsMultiLine(wndPtr))
EDIT_MovePageUp(wndPtr, shift);
break;
case VK_NEXT:
if (IsMultiLine(wndPtr))
EDIT_MovePageDown(wndPtr, shift);
break;
case VK_BACK:
if (!IsReadOnly(wndPtr) && !control)
if (e != s)
EDIT_WM_Clear(wndPtr, 0, 0L);
else
EDIT_DelLeft(wndPtr);
break;
case VK_DELETE:
if (!IsReadOnly(wndPtr) && !(shift && control))
if (e != s) {
if (shift)
EDIT_WM_Cut(wndPtr, 0, 0L);
else
EDIT_WM_Clear(wndPtr, 0, 0L);
} else {
if (shift)
EDIT_DelLeft(wndPtr);
else if (control)
EDIT_DelEnd(wndPtr);
else
EDIT_DelRight(wndPtr);
}
break;
case VK_INSERT:
if (shift) {
if (!IsReadOnly(wndPtr))
EDIT_WM_Paste(wndPtr, 0, 0L);
} else if (control)
EDIT_WM_Copy(wndPtr, 0, 0L);
break;
}
return 0L;
}
/*********************************************************************
*
* WM_KILLFOCUS
*
*/
static LRESULT EDIT_WM_KillFocus(WND *wndPtr, WPARAM wParam, LPARAM lParam)
{
DestroyCaret();
if(!(wndPtr->dwStyle & ES_NOHIDESEL))
EDIT_EM_SetSel(wndPtr, FALSE, MAKELPARAM(-1, 0));
EDIT_NOTIFY_PARENT(wndPtr, EN_KILLFOCUS);
return 0L;
}
/*********************************************************************
*
* WM_LBUTTONDBLCLK
*
*/
static LRESULT EDIT_WM_LButtonDblClk(WND *wndPtr, WPARAM wParam, LPARAM lParam)
{
int s;
int e = HIWORD(EDIT_EM_GetSel(wndPtr, 0, 0L));
int l = EDIT_EM_LineFromChar(wndPtr, e, 0L);
int lineindex = EDIT_EM_LineIndex(wndPtr, l, 0L);
int linelength = EDIT_EM_LineLength(wndPtr, e, 0L);
char *text = EDIT_GetPointer(wndPtr);
s = lineindex + EDIT_CallWordBreakProc(wndPtr, text + lineindex, e - lineindex, linelength, WB_LEFT);
e = lineindex + EDIT_CallWordBreakProc(wndPtr, text + lineindex, e - lineindex, linelength, WB_RIGHT);
EDIT_EM_SetSel(wndPtr, TRUE, MAKELPARAM(s, e));
return 0L;
}
/*********************************************************************
*
* WM_LBUTTONDOWN
*
*/
static LRESULT EDIT_WM_LButtonDown(WND *wndPtr, WPARAM wParam, LPARAM lParam)
{
int l;
int s;
int e;
SetFocus(wndPtr->hwndSelf);
SetCapture(wndPtr->hwndSelf);
l = EDIT_LineFromWndY(wndPtr, (INT)HIWORD(lParam));
e = EDIT_EM_LineIndex(wndPtr, l ,0L) +
EDIT_ColFromWndX(wndPtr, l, (INT)LOWORD(lParam));
if (GetKeyState(VK_SHIFT) & 0x8000)
s = LOWORD(EDIT_EM_GetSel(wndPtr, 0, 0L));
else
s = e;
EDIT_EM_SetSel(wndPtr, TRUE, MAKELPARAM(s, e));
return 0L;
}
/*********************************************************************
*
* WM_LBUTTONUP
*
*/
static LRESULT EDIT_WM_LButtonUp(WND *wndPtr, WPARAM wParam, LPARAM lParam)
{
if (GetCapture() == wndPtr->hwndSelf)
ReleaseCapture();
return 0L;
}
/*********************************************************************
*
* WM_MOUSEMOVE
*
*/
static LRESULT EDIT_WM_MouseMove(WND *wndPtr, WPARAM wParam, LPARAM lParam)
{
EDITSTATE *es = EDITSTATEPTR(wndPtr);
int Line;
int Col;
int x = (INT)LOWORD(lParam);
if (GetCapture() == wndPtr->hwndSelf) {
Line = EDIT_LineFromWndY(wndPtr, (INT)HIWORD(lParam));
Line = MAX(Line, EDIT_EM_GetFirstVisibleLine(wndPtr, 0, 0L));
Line = MIN(Line, EDIT_EM_GetFirstVisibleLine(wndPtr, 0, 0L) + EDIT_GetVisibleLineCount(wndPtr) - 1);
x = MIN(EDIT_GetWndWidth(wndPtr), MAX(0, x));
Col = EDIT_ColFromWndX(wndPtr, Line, x);
EDIT_EM_SetSel(wndPtr, FALSE, MAKELPARAM(es->SelStart,
EDIT_EM_LineIndex(wndPtr, Line, 0L) + Col));
}
return 0L;
}
/*********************************************************************
*
* WM_PAINT
*
*/
static LRESULT EDIT_WM_Paint(WND *wndPtr, WPARAM wParam, LPARAM lParam)
{
EDITSTATE *es = EDITSTATEPTR(wndPtr);
PAINTSTRUCT ps;
int i;
int firstvis = EDIT_EM_GetFirstVisibleLine(wndPtr, 0, 0L);
HDC hdc;
HFONT hFont;
HFONT oldFont = 0;
RECT rc;
RECT rcLine;
RECT rcRgn;
hdc = BeginPaint(wndPtr->hwndSelf, &ps);
GetClientRect(wndPtr->hwndSelf, &rc);
IntersectClipRect(hdc, rc.left, rc.top, rc.right, rc.bottom);
hFont = EDIT_WM_GetFont(wndPtr, 0, 0L);
if (hFont)
oldFont = SelectObject(hdc, hFont);
EDIT_SEND_CTLCOLOR(wndPtr, hdc);
GetClipBox(hdc, &rcRgn);
for (i = firstvis ; i <= MIN(firstvis + EDIT_GetVisibleLineCount(wndPtr), firstvis + es->LineCount - 1) ; i++ ) {
EDIT_GetLineRect(wndPtr, i, 0, -1, &rcLine);
if (IntersectRect(&rc, &rcRgn, &rcLine))
EDIT_PaintLine(wndPtr, hdc, i);
}
if (hFont)
SelectObject(hdc, oldFont);
EndPaint(wndPtr->hwndSelf, &ps);
return 0L;
}
/*********************************************************************
*
* WM_PASTE
*
*/
static LRESULT EDIT_WM_Paste(WND *wndPtr, WPARAM wParam, LPARAM lParam)
{
HGLOBAL hsrc;
char *src;
OpenClipboard(wndPtr->hwndSelf);
if ((hsrc = GetClipboardData(CF_TEXT))) {
src = (char *)GlobalLock(hsrc);
EDIT_ReplaceSel(wndPtr, 0, (LPARAM)src);
GlobalUnlock(hsrc);
}
CloseClipboard();
return -1L;
}
/*********************************************************************
*
* WM_SETCURSOR
*
*/
static LRESULT EDIT_WM_SetCursor(WND *wndPtr, WPARAM wParam, LPARAM lParam)
{
if (LOWORD(lParam) == HTCLIENT) {
SetCursor(LoadCursor(0, IDC_IBEAM));
return -1L;
} else
return 0L;
}
/*********************************************************************
*
* WM_SETFOCUS
*
*/
static LRESULT EDIT_WM_SetFocus(WND *wndPtr, WPARAM wParam, LPARAM lParam)
{
LPARAM sel = EDIT_EM_GetSel(wndPtr, 0, 0L);
CreateCaret(wndPtr->hwndSelf, 0, 2, EDIT_GetLineHeight(wndPtr));
EDIT_EM_SetSel(wndPtr, FALSE, sel);
ShowCaret(wndPtr->hwndSelf);
EDIT_NOTIFY_PARENT(wndPtr, EN_SETFOCUS);
return 0L;
}
/*********************************************************************
*
* WM_SETFONT
*
*/
static LRESULT EDIT_WM_SetFont(WND *wndPtr, WPARAM wParam, LPARAM lParam)
{
TEXTMETRIC tm;
EDITSTATE *es = EDITSTATEPTR(wndPtr);
LPARAM sel = EDIT_EM_GetSel(wndPtr, 0, 0L);
HDC hdc;
HFONT oldFont = 0;
es->hFont = (HFONT)wParam;
hdc = GetDC(wndPtr->hwndSelf);
if (es->hFont)
oldFont = SelectObject(hdc, es->hFont);
GetTextMetrics(hdc, &tm);
es->LineHeight = HIWORD(GetTextExtent(hdc, "", 0));
es->AveCharWidth = tm.tmAveCharWidth;
if (es->hFont)
SelectObject(hdc, oldFont);
ReleaseDC(wndPtr->hwndSelf, hdc);
EDIT_BuildLineDefs(wndPtr);
if (lParam && EDIT_GetRedraw(wndPtr))
InvalidateRect(wndPtr->hwndSelf, NULL, TRUE);
if (wndPtr->hwndSelf == GetFocus()) {
DestroyCaret();
CreateCaret(wndPtr->hwndSelf, 0, 2, EDIT_GetLineHeight(wndPtr));
EDIT_EM_SetSel(wndPtr, FALSE, sel);
ShowCaret(wndPtr->hwndSelf);
}
return 0L;
}
/*********************************************************************
*
* WM_SETREDRAW
*
*/
static LRESULT EDIT_WM_SetRedraw(WND *wndPtr, WPARAM wParam, LPARAM lParam)
{
EDITSTATE *es = EDITSTATEPTR(wndPtr);
es->Redraw = wParam ? TRUE : FALSE;
return 0L;
}
/*********************************************************************
*
* WM_SETTEXT
*
*/
static LRESULT EDIT_WM_SetText(WND *wndPtr, WPARAM wParam, LPARAM lParam)
{
EDIT_EM_SetSel(wndPtr, FALSE, MAKELPARAM(0, -1));
EDIT_WM_Clear(wndPtr, 0, 0L);
if (lParam)
EDIT_EM_ReplaceSel(wndPtr, 0, lParam);
EDIT_EM_EmptyUndoBuffer(wndPtr, 0, 0L);
EDIT_EM_SetModify(wndPtr, TRUE, 0L);
return 0L;
}
/*********************************************************************
*
* WM_SIZE
*
*/
static LRESULT EDIT_WM_Size(WND *wndPtr, WPARAM wParam, LPARAM lParam)
{
if (EDIT_GetRedraw(wndPtr) &&
((wParam == SIZE_MAXIMIZED) ||
(wParam == SIZE_RESTORED)))
InvalidateRect(wndPtr->hwndSelf, NULL, TRUE);
return 0L;
}
/*********************************************************************
*
* WM_VSCROLL
*
* FIXME: scrollbar code itself is broken, so this one is a hack.
*
*/
static LRESULT EDIT_WM_VScroll(WND *wndPtr, WPARAM wParam, LPARAM lParam)
{
int linecount = EDIT_EM_GetLineCount(wndPtr, 0, 0L);
int firstvis = EDIT_EM_GetFirstVisibleLine(wndPtr, 0, 0L);
int vislinecount = EDIT_GetVisibleLineCount(wndPtr);
int dy = 0;
BOOL not = TRUE;
LRESULT ret = 0L;
switch (wParam) {
case SB_LINEUP:
dy = -1;
break;
case SB_LINEDOWN:
dy = 1;
break;
case SB_PAGEUP:
dy = -vislinecount;
break;
case SB_PAGEDOWN:
dy = vislinecount;
break;
case SB_TOP:
dy = -firstvis;
break;
case SB_BOTTOM:
dy = linecount - 1 - firstvis;
break;
case SB_THUMBTRACK:
/*
* not = FALSE;
*/
case SB_THUMBPOSITION:
dy = LOWORD(lParam) * (linecount - 1) / 100 - firstvis;
break;
/* The next two are undocumented ! */
case EM_GETTHUMB:
ret = (linecount > 1) ? MAKELONG(firstvis * 100 / (linecount - 1), 0) : 0L;
break;
case EM_LINESCROLL:
dy = LOWORD(lParam);
break;
case SB_ENDSCROLL:
default:
break;
}
if (dy) {
EDIT_EM_LineScroll(wndPtr, 0, MAKELPARAM(dy, 0));
if (not)
EDIT_NOTIFY_PARENT(wndPtr, EN_VSCROLL);
}
return ret;
}