blob: b333222d022dfb8c61d5c74788f43444d0092d95 [file] [log] [blame]
/*
* Edit control
*
* Copyright David W. Metcalfe, 1994
* Copyright William Magro, 1995, 1996
* Copyright Frans van Dorsselaer, 1996, 1997
*
*/
/*
* please read EDIT.TODO (and update it when you change things)
* It also contains a discussion about the 16 to 32 bit transition.
*
*/
#define NO_TRANSITION_TYPES /* This file is Win32-clean */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "windows.h"
#include "win.h"
#include "local.h"
#include "resource.h"
#include "stddebug.h"
#include "debug.h"
#include "xmalloc.h"
/*
#include "callback.h"
*/
#define BUFLIMIT_MULTI 65534 /* maximum text buffer length (not including '\0') */
/* FIXME: BTW, new specs say 65535 (do you dare ???) */
#define BUFLIMIT_SINGLE 32766
#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 {
INT32 offset;
INT32 length;
LINE_END ending;
} LINEDEF;
typedef struct
{
HLOCAL16 hBuf16; /* For when a 16-bit multiline edit
* control gets a EM_GETHANDLE (which
* should return 16-bit local heap).
* From that point on we _have_ to keep
* using 16-bit local heap (apps rely
* on that ... bummer).
*/
HLOCAL32 hBuf32; /* Don't worry about 'LOCAL'. LOCAL32 is
* identical to GLOBAL32, which is
* essentially a HANDLE32 created with
* HeapAlloc(GetProcessHeap(), ...) plus
* a global32 (and thus local32)
* descriptor, which we can return upon
* EM_GETHANDLE32.
* It is 32-bit linear addressing, so
* everything is fine.
*/
LPSTR text; /* Depending on the fact that we are a
* 16 or 32 bit control, this is the
* pointer that we get after
* LocalLock32(hBuf23) (which is a typecast :-)
* or LOCAL_Lock(hBuf16).
* This is always a 32-bit linear pointer.
*/
HFONT32 hFont;
LINEDEF *LineDefs; /* Internal table for (soft) linebreaks */
INT32 TextWidth; /* width of the widest line in pixels */
INT32 XOffset; /* offset of the viewport in pixels */
INT32 FirstVisibleLine;
INT32 LineCount;
INT32 LineHeight; /* height of a screen line in pixels */
INT32 AveCharWidth; /* average character width in pixels */
INT32 BufLimit;
INT32 BufSize;
BOOL32 TextChanged;
INT32 UndoInsertLen;
INT32 UndoPos;
INT32 UndoBufSize;
HLOCAL32 hUndoBuf;
LPSTR UndoText;
BOOL32 Redraw;
INT32 SelStart; /* offset of selection start, == SelEnd if no selection */
INT32 SelEnd; /* offset of selection end == current caret position */
INT32 NumTabStops;
LPINT16 TabStops;
/*
* FIXME: The following should probably be a (VOID *) that is
* typecast to either 16- or 32-bit callback when used,
* depending on the type of edit control (16 or 32 bit).
*
* EDITWORDBREAKPROC WordBreakProc;
*
* For now: no more application specific wordbreaking.
* (Internal wordbreak function still works)
*/
CHAR PasswordChar;
INT32 LeftMargin;
INT32 RightMargin;
RECT32 FormatRect;
} EDITSTATE;
#define SWAP_INT32(x,y) do { INT32 temp = (INT32)(x); (x) = (INT32)(y); (y) = temp; } while(0)
#define ORDER_INT32(x,y) do { if ((INT32)(y) < (INT32)(x)) SWAP_INT32((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 IsPassword(wndPtr) ((wndPtr)->dwStyle & ES_PASSWORD)
#define IsLower(wndPtr) ((wndPtr)->dwStyle & ES_LOWERCASE)
#define IsUpper(wndPtr) ((wndPtr)->dwStyle & ES_UPPERCASE)
#define EDITSTATEPTR(wndPtr) (*(EDITSTATE **)((wndPtr)->wExtra))
#define EDIT_SEND_CTLCOLOR(wndPtr,hdc) \
(SendMessage32A((wndPtr)->parent->hwndSelf, WM_CTLCOLOREDIT, \
(WPARAM32)(hdc), (LPARAM)(wndPtr)->hwndSelf ))
#define EDIT_NOTIFY_PARENT(wndPtr, wNotifyCode) \
(SendMessage32A((wndPtr)->parent->hwndSelf, WM_COMMAND, \
MAKEWPARAM((wndPtr)->wIDmenu, wNotifyCode), \
(LPARAM)(wndPtr)->hwndSelf ))
#define DPRINTF_EDIT_MSG16(str) \
dprintf_edit(stddeb, \
"edit: 16 bit : " str ": hwnd=%08x, wParam=%08x, lParam=%08x\n", \
(UINT32)hwnd, (UINT32)wParam, (UINT32)lParam)
#define DPRINTF_EDIT_MSG32(str) \
dprintf_edit(stddeb, \
"edit: 32 bit : " str ": hwnd=%08x, wParam=%08x, lParam=%08x\n", \
(UINT32)hwnd, (UINT32)wParam, (UINT32)lParam)
/*********************************************************************
*
* Declarations
*
* Files like these should really be kept in alphabetical order.
*
*/
LRESULT EditWndProc(HWND32 hwnd, UINT32 msg, WPARAM32 wParam, LPARAM lParam);
static void EDIT_BuildLineDefs(WND *wndPtr);
static INT32 EDIT_CallWordBreakProc(WND *wndPtr, LPSTR s, INT32 index, INT32 count, INT32 action);
static INT32 EDIT_ColFromWndX(WND *wndPtr, INT32 line, INT32 x);
static void EDIT_DelEnd(WND *wndPtr);
static void EDIT_DelLeft(WND *wndPtr);
static void EDIT_DelRight(WND *wndPtr);
static INT32 EDIT_GetAveCharWidth(WND *wndPtr);
static INT32 EDIT_GetLineHeight(WND *wndPtr);
static void EDIT_GetLineRect(WND *wndPtr, INT32 line, INT32 scol, INT32 ecol, LPRECT32 rc);
static LPSTR EDIT_GetPointer(WND *wndPtr);
static LPSTR EDIT_GetPasswordPointer(WND *wndPtr);
static BOOL32 EDIT_GetRedraw(WND *wndPtr);
static void EDIT_GetSel(WND *wndPtr, LPINT32 s, LPINT32 e);
static INT32 EDIT_GetTextWidth(WND *wndPtr);
static LPSTR EDIT_GetUndoPointer(WND *wndPtr);
static INT32 EDIT_GetVisibleLineCount(WND *wndPtr);
static INT32 EDIT_GetWndWidth(WND *wndPtr);
static INT32 EDIT_GetXOffset(WND *wndPtr);
static void EDIT_InvalidateText(WND *wndPtr, INT32 start, INT32 end);
static INT32 EDIT_LineFromWndY(WND *wndPtr, INT32 y);
static BOOL32 EDIT_MakeFit(WND *wndPtr, INT32 size);
static BOOL32 EDIT_MakeUndoFit(WND *wndPtr, INT32 size);
static void EDIT_MoveBackward(WND *wndPtr, BOOL32 extend);
static void EDIT_MoveDownward(WND *wndPtr, BOOL32 extend);
static void EDIT_MoveEnd(WND *wndPtr, BOOL32 extend);
static void EDIT_MoveForward(WND *wndPtr, BOOL32 extend);
static void EDIT_MoveHome(WND *wndPtr, BOOL32 extend);
static void EDIT_MovePageDown(WND *wndPtr, BOOL32 extend);
static void EDIT_MovePageUp(WND *wndPtr, BOOL32 extend);
static void EDIT_MoveUpward(WND *wndPtr, BOOL32 extend);
static void EDIT_MoveWordBackward(WND *wndPtr, BOOL32 extend);
static void EDIT_MoveWordForward(WND *wndPtr, BOOL32 extend);
static void EDIT_PaintLine(WND *wndPtr, HDC32 hdc, INT32 line, BOOL32 rev);
static INT32 EDIT_PaintText(WND *wndPtr, HDC32 hdc, INT32 x, INT32 y, INT32 line, INT32 col, INT32 count, BOOL32 rev);
static void EDIT_ReleasePointer(WND *wndPtr);
static void EDIT_ReleaseUndoPointer(WND *wndPtr);
static void EDIT_SetSel(WND *wndPtr, INT32 ns, INT32 ne);
static INT32 EDIT_WndXFromCol(WND *wndPtr, INT32 line, INT32 col);
static INT32 EDIT_WndYFromLine(WND *wndPtr, INT32 line);
static INT32 EDIT_WordBreakProc(LPSTR s, INT32 index, INT32 count, INT32 action);
static LRESULT EDIT_EM_CanUndo(WND *wndPtr, WPARAM32 wParam, LPARAM lParam);
static LRESULT EDIT_EM_CharFromPos(WND *wndPtr, WPARAM32 wParam, LPARAM lParam);
static LRESULT EDIT_EM_EmptyUndoBuffer(WND *wndPtr, WPARAM32 wParam, LPARAM lParam);
static LRESULT EDIT_EM_FmtLines(WND *wndPtr, WPARAM32 wParam, LPARAM lParam);
static LRESULT EDIT_EM_GetFirstVisibleLine(WND *wndPtr, WPARAM32 wParam, LPARAM lParam);
static LRESULT EDIT_EM_GetHandle(WND *wndPtr, WPARAM32 wParam, LPARAM lParam);
static LRESULT EDIT_EM_GetHandle16(WND *wndPtr, WPARAM32 wParam, LPARAM lParam);
static LRESULT EDIT_EM_GetLimitText(WND *wndPtr, WPARAM32 wParam, LPARAM lParam);
static LRESULT EDIT_EM_GetLine(WND *wndPtr, WPARAM32 wParam, LPARAM lParam);
static LRESULT EDIT_EM_GetLineCount(WND *wndPtr, WPARAM32 wParam, LPARAM lParam);
static LRESULT EDIT_EM_GetMargins(WND *wndPtr, WPARAM32 wParam, LPARAM lParam);
static LRESULT EDIT_EM_GetModify(WND *wndPtr, WPARAM32 wParam, LPARAM lParam);
static LRESULT EDIT_EM_GetPasswordChar(WND *wndPtr, WPARAM32 wParam, LPARAM lParam);
static LRESULT EDIT_EM_GetRect(WND *wndPtr, WPARAM32 wParam, LPARAM lParam);
static LRESULT EDIT_EM_GetRect16(WND *wndPtr, WPARAM32 wParam, LPARAM lParam);
static LRESULT EDIT_EM_GetSel(WND *wndPtr, WPARAM32 wParam, LPARAM lParam);
static LRESULT EDIT_EM_GetThumb(WND *wndPtr, WPARAM32 wParam, LPARAM lParam);
static LRESULT EDIT_EM_GetWordBreakProc(WND *wndPtr, WPARAM32 wParam, LPARAM lParam);
static LRESULT EDIT_EM_LineFromChar(WND *wndPtr, WPARAM32 wParam, LPARAM lParam);
static LRESULT EDIT_EM_LineIndex(WND *wndPtr, WPARAM32 wParam, LPARAM lParam);
static LRESULT EDIT_EM_LineLength(WND *wndPtr, WPARAM32 wParam, LPARAM lParam);
static LRESULT EDIT_EM_LineScroll(WND *wndPtr, WPARAM32 wParam, LPARAM lParam);
static LRESULT EDIT_EM_PosFromChar(WND *wndPtr, WPARAM32 wParam, LPARAM lParam);
static LRESULT EDIT_EM_ReplaceSel(WND *wndPtr, WPARAM32 wParam, LPARAM lParam);
static LRESULT EDIT_EM_Scroll(WND *wndPtr, WPARAM32 wParam, LPARAM lParam);
static LRESULT EDIT_EM_ScrollCaret(WND *wndPtr, WPARAM32 wParam, LPARAM lParam);
static LRESULT EDIT_EM_SetHandle(WND *wndPtr, WPARAM32 wParam, LPARAM lParam);
static LRESULT EDIT_EM_SetHandle16(WND *wndPtr, WPARAM32 wParam, LPARAM lParam);
static LRESULT EDIT_EM_SetLimitText(WND *wndPtr, WPARAM32 wParam, LPARAM lParam);
static LRESULT EDIT_EM_SetMargins(WND *wndPtr, WPARAM32 wParam, LPARAM lParam);
static LRESULT EDIT_EM_SetModify(WND *wndPtr, WPARAM32 wParam, LPARAM lParam);
static LRESULT EDIT_EM_SetPasswordChar(WND *wndPtr, WPARAM32 wParam, LPARAM lParam);
static LRESULT EDIT_EM_SetReadOnly(WND *wndPtr, WPARAM32 wParam, LPARAM lParam);
static LRESULT EDIT_EM_SetRect(WND *wndPtr, WPARAM32 wParam, LPARAM lParam);
static LRESULT EDIT_EM_SetRectNP(WND *wndPtr, WPARAM32 wParam, LPARAM lParam);
static LRESULT EDIT_EM_SetSel(WND *wndPtr, WPARAM32 wParam, LPARAM lParam);
static LRESULT EDIT_EM_SetSel16(WND *wndPtr, WPARAM32 wParam, LPARAM lParam);
static LRESULT EDIT_EM_SetTabStops(WND *wndPtr, WPARAM32 wParam, LPARAM lParam);
static LRESULT EDIT_EM_SetTabStops16(WND *wndPtr, WPARAM32 wParam, LPARAM lParam);
static LRESULT EDIT_EM_SetWordBreakProc(WND *wndPtr, WPARAM32 wParam, LPARAM lParam);
static LRESULT EDIT_EM_Undo(WND *wndPtr, WPARAM32 wParam, LPARAM lParam);
static LRESULT EDIT_WM_Char(WND *wndPtr, WPARAM32 wParam, LPARAM lParam);
static LRESULT EDIT_WM_Clear(WND *wndPtr, WPARAM32 wParam, LPARAM lParam);
static LRESULT EDIT_WM_Command(WND *wndPtr, WPARAM32 wParam, LPARAM lParam);
static LRESULT EDIT_WM_ContextMenu(WND *wndPtr, WPARAM32 wParam, LPARAM lParam);
static LRESULT EDIT_WM_Copy(WND *wndPtr, WPARAM32 wParam, LPARAM lParam);
static LRESULT EDIT_WM_Cut(WND *wndPtr, WPARAM32 wParam, LPARAM lParam);
static LRESULT EDIT_WM_Create(WND *wndPtr, WPARAM32 wParam, LPARAM lParam);
static LRESULT EDIT_WM_Destroy(WND *wndPtr, WPARAM32 wParam, LPARAM lParam);
static LRESULT EDIT_WM_Enable(WND *wndPtr, WPARAM32 wParam, LPARAM lParam);
static LRESULT EDIT_WM_EraseBkGnd(WND *wndPtr, WPARAM32 wParam, LPARAM lParam);
static LRESULT EDIT_WM_GetDlgCode(WND *wndPtr, WPARAM32 wParam, LPARAM lParam);
static LRESULT EDIT_WM_GetFont(WND *wndPtr, WPARAM32 wParam, LPARAM lParam);
static LRESULT EDIT_WM_GetText(WND *wndPtr, WPARAM32 wParam, LPARAM lParam);
static LRESULT EDIT_WM_GetTextLength(WND *wndPtr, WPARAM32 wParam, LPARAM lParam);
static LRESULT EDIT_WM_HScroll(WND *wndPtr, WPARAM32 wParam, LPARAM lParam);
static LRESULT EDIT_WM_InitMenuPopup(WND *wndPtr, WPARAM32 wParam, LPARAM lParam);
static LRESULT EDIT_WM_KeyDown(WND *wndPtr, WPARAM32 wParam, LPARAM lParam);
static LRESULT EDIT_WM_KillFocus(WND *wndPtr, WPARAM32 wParam, LPARAM lParam);
static LRESULT EDIT_WM_LButtonDblClk(WND *wndPtr, WPARAM32 wParam, LPARAM lParam);
static LRESULT EDIT_WM_LButtonDown(WND *wndPtr, WPARAM32 wParam, LPARAM lParam);
static LRESULT EDIT_WM_LButtonUp(WND *wndPtr, WPARAM32 wParam, LPARAM lParam);
static LRESULT EDIT_WM_MouseMove(WND *wndPtr, WPARAM32 wParam, LPARAM lParam);
static LRESULT EDIT_WM_Paint(WND *wndPtr, WPARAM32 wParam, LPARAM lParam);
static LRESULT EDIT_WM_Paste(WND *wndPtr, WPARAM32 wParam, LPARAM lParam);
static LRESULT EDIT_WM_SetCursor(WND *wndPtr, WPARAM32 wParam, LPARAM lParam);
static LRESULT EDIT_WM_SetFocus(WND *wndPtr, WPARAM32 wParam, LPARAM lParam);
static LRESULT EDIT_WM_SetFont(WND *wndPtr, WPARAM32 wParam, LPARAM lParam);
static LRESULT EDIT_WM_SetRedraw(WND *wndPtr, WPARAM32 wParam, LPARAM lParam);
static LRESULT EDIT_WM_SetText(WND *wndPtr, WPARAM32 wParam, LPARAM lParam);
static LRESULT EDIT_WM_Size(WND *wndPtr, WPARAM32 wParam, LPARAM lParam);
static LRESULT EDIT_WM_SysKeyDown(WND *wndPtr, WPARAM32 wParam, LPARAM lParam);
static LRESULT EDIT_WM_Timer(WND *wndPtr, WPARAM32 wParam, LPARAM lParam);
static LRESULT EDIT_WM_VScroll(WND *wndPtr, WPARAM32 wParam, LPARAM lParam);
/*********************************************************************
*
* General shortcuts for variable names:
*
* INT32 l; line
* INT32 c; column
* INT32 s; offset of selection start
* INT32 e; offset of selection end
* INT32 sl; line on which the selection starts
* INT32 el; line on which the selection ends
* INT32 sc; column on which the selection starts
* INT32 ec; column on which the selection ends
* INT32 li; line index (offset)
* INT32 fv; first visible line
* INT32 vlc; vissible line count
* INT32 lc; line count
* INT32 lh; line height (in pixels)
* INT32 tw; text width (in pixels)
* INT32 ww; window width (in pixels)
* INT32 cw; character width (average, in pixels)
*
*/
/*********************************************************************
*
* EditWndProc()
*
* The messages are in the order of the actual integer values
* (which can be found in include/windows.h)
* Whereever possible the 16 bit versions are converted to
* the 32 bit ones, so that we can 'fall through' to the
* helper functions. These are mostly 32 bit (with a few
* exceptions, clearly indicated by a '16' extension to their
* names).
*
*/
LRESULT EditWndProc(HWND32 hwnd, UINT32 msg, WPARAM32 wParam, LPARAM lParam)
{
LRESULT lResult = 0;
WND *wndPtr = WIN_FindWndPtr(hwnd);
if ((!EDITSTATEPTR(wndPtr)) && (msg != WM_CREATE))
return DefWindowProc32A(hwnd, msg, wParam, lParam);
switch (msg) {
case EM_GETSEL16:
DPRINTF_EDIT_MSG16("EM_GETSEL");
wParam = 0;
lParam = 0;
/* fall through */
case EM_GETSEL32:
DPRINTF_EDIT_MSG32("EM_GETSEL");
lResult = EDIT_EM_GetSel(wndPtr, wParam, lParam);
break;
case EM_SETSEL16:
DPRINTF_EDIT_MSG16("EM_SETSEL");
lResult = EDIT_EM_SetSel16(wndPtr, wParam, lParam);
break;
case EM_SETSEL32:
DPRINTF_EDIT_MSG32("EM_SETSEL");
lResult = EDIT_EM_SetSel(wndPtr, wParam, lParam);
break;
case EM_GETRECT16:
DPRINTF_EDIT_MSG16("EM_GETRECT");
lResult = EDIT_EM_GetRect16(wndPtr, wParam, lParam);
break;
case EM_GETRECT32:
DPRINTF_EDIT_MSG32("EM_GETRECT");
lResult = EDIT_EM_GetRect(wndPtr, wParam, lParam);
break;
case EM_SETRECT16:
DPRINTF_EDIT_MSG16("EM_SETRECT");
/* fall through */
case EM_SETRECT32:
DPRINTF_EDIT_MSG32("EM_SETRECT");
lResult = EDIT_EM_SetRect(wndPtr, wParam, lParam);
break;
case EM_SETRECTNP16:
DPRINTF_EDIT_MSG16("EM_SETRECTNP");
/* fall through */
case EM_SETRECTNP32:
DPRINTF_EDIT_MSG32("EM_SETRECTNP");
lResult = EDIT_EM_SetRectNP(wndPtr, wParam, lParam);
break;
case EM_SCROLL16:
DPRINTF_EDIT_MSG16("EM_SCROLL");
/* fall through */
case EM_SCROLL32:
DPRINTF_EDIT_MSG32("EM_SCROLL");
lResult = EDIT_EM_Scroll(wndPtr, wParam, lParam);
break;
case EM_LINESCROLL16:
DPRINTF_EDIT_MSG16("EM_LINESCROLL");
wParam = (WPARAM32)(INT32)(INT16)HIWORD(lParam);
lParam = (LPARAM)(INT32)(INT16)LOWORD(lParam);
/* fall through */
case EM_LINESCROLL32:
DPRINTF_EDIT_MSG32("EM_LINESCROLL");
lResult = EDIT_EM_LineScroll(wndPtr, wParam, lParam);
break;
case EM_SCROLLCARET16:
DPRINTF_EDIT_MSG16("EM_SCROLLCARET");
/* fall through */
case EM_SCROLLCARET32:
DPRINTF_EDIT_MSG32("EM_SCROLLCARET");
lResult = EDIT_EM_ScrollCaret(wndPtr, wParam, lParam);
break;
case EM_GETMODIFY16:
DPRINTF_EDIT_MSG16("EM_GETMODIFY");
/* fall through */
case EM_GETMODIFY32:
DPRINTF_EDIT_MSG32("EM_GETMODIFY");
lResult = EDIT_EM_GetModify(wndPtr, wParam, lParam);
break;
case EM_SETMODIFY16:
DPRINTF_EDIT_MSG16("EM_SETMODIFY");
/* fall through */
case EM_SETMODIFY32:
DPRINTF_EDIT_MSG32("EM_SETMODIFY");
lResult = EDIT_EM_SetModify(wndPtr, wParam, lParam);
break;
case EM_GETLINECOUNT16:
DPRINTF_EDIT_MSG16("EM_GETLINECOUNT");
/* fall through */
case EM_GETLINECOUNT32:
DPRINTF_EDIT_MSG32("EM_GETLINECOUNT");
lResult = EDIT_EM_GetLineCount(wndPtr, wParam, lParam);
break;
case EM_LINEINDEX16:
DPRINTF_EDIT_MSG16("EM_LINEINDEX");
/* fall through */
case EM_LINEINDEX32:
DPRINTF_EDIT_MSG32("EM_LINEINDEX");
lResult = EDIT_EM_LineIndex(wndPtr, wParam, lParam);
break;
case EM_SETHANDLE16:
DPRINTF_EDIT_MSG16("EM_SETHANDLE");
lResult = EDIT_EM_SetHandle16(wndPtr, wParam, lParam);
break;
case EM_SETHANDLE32:
DPRINTF_EDIT_MSG32("EM_SETHANDLE");
lResult = EDIT_EM_SetHandle(wndPtr, wParam, lParam);
break;
case EM_GETHANDLE16:
DPRINTF_EDIT_MSG16("EM_GETHANDLE");
lResult = EDIT_EM_GetHandle16(wndPtr, wParam, lParam);
break;
case EM_GETHANDLE32:
DPRINTF_EDIT_MSG32("EM_GETHANDLE");
lResult = EDIT_EM_GetHandle(wndPtr, wParam, lParam);
break;
case EM_GETTHUMB16:
DPRINTF_EDIT_MSG16("EM_GETTHUMB");
/* fall through */
case EM_GETTHUMB32:
DPRINTF_EDIT_MSG32("EM_GETTHUMB");
lResult = EDIT_EM_GetThumb(wndPtr, wParam, lParam);
break;
/* messages 0x00bf and 0x00c0 missing from specs */
case WM_USER+15:
DPRINTF_EDIT_MSG16("undocumented WM_USER+15, please report");
/* fall through */
case 0x00bf:
DPRINTF_EDIT_MSG32("undocumented 0x00bf, please report");
lResult = DefWindowProc32A(hwnd, msg, wParam, lParam);
break;
case WM_USER+16:
DPRINTF_EDIT_MSG16("undocumented WM_USER+16, please report");
/* fall through */
case 0x00c0:
DPRINTF_EDIT_MSG32("undocumented 0x00c0, please report");
lResult = DefWindowProc32A(hwnd, msg, wParam, lParam);
break;
case EM_LINELENGTH16:
DPRINTF_EDIT_MSG16("EM_LINELENGTH");
/* fall through */
case EM_LINELENGTH32:
DPRINTF_EDIT_MSG32("EM_LINELENGTH");
lResult = EDIT_EM_LineLength(wndPtr, wParam, lParam);
break;
case EM_REPLACESEL16:
DPRINTF_EDIT_MSG16("EM_REPLACESEL");
lParam = (LPARAM)PTR_SEG_TO_LIN((SEGPTR)lParam);
/* fall through */
case EM_REPLACESEL32:
DPRINTF_EDIT_MSG32("EM_REPLACESEL");
lResult = EDIT_EM_ReplaceSel(wndPtr, wParam, lParam);
break;
/* message 0x00c3 missing from specs */
case WM_USER+19:
DPRINTF_EDIT_MSG16("undocumented WM_USER+19, please report");
/* fall through */
case 0x00c3:
DPRINTF_EDIT_MSG32("undocumented 0x00c3, please report");
lResult = DefWindowProc32A(hwnd, msg, wParam, lParam);
break;
case EM_GETLINE16:
DPRINTF_EDIT_MSG16("EM_GETLINE");
lParam = (LPARAM)PTR_SEG_TO_LIN((SEGPTR)lParam);
/* fall through */
case EM_GETLINE32:
DPRINTF_EDIT_MSG32("EM_GETLINE");
lResult = EDIT_EM_GetLine(wndPtr, wParam, lParam);
break;
case EM_LIMITTEXT16:
DPRINTF_EDIT_MSG16("EM_LIMITTEXT");
/* fall through */
case EM_SETLIMITTEXT32:
DPRINTF_EDIT_MSG32("EM_SETLIMITTEXT");
lResult = EDIT_EM_SetLimitText(wndPtr, wParam, lParam);
break;
case EM_CANUNDO16:
DPRINTF_EDIT_MSG16("EM_CANUNDO");
/* fall through */
case EM_CANUNDO32:
DPRINTF_EDIT_MSG32("EM_CANUNDO");
lResult = EDIT_EM_CanUndo(wndPtr, wParam, lParam);
break;
case EM_UNDO16:
DPRINTF_EDIT_MSG16("EM_UNDO");
/* fall through */
case EM_UNDO32:
/* fall through */
case WM_UNDO:
DPRINTF_EDIT_MSG32("EM_UNDO / WM_UNDO");
lResult = EDIT_EM_Undo(wndPtr, wParam, lParam);
break;
case EM_FMTLINES16:
DPRINTF_EDIT_MSG16("EM_FMTLINES");
/* fall through */
case EM_FMTLINES32:
DPRINTF_EDIT_MSG32("EM_FMTLINES");
lResult = EDIT_EM_FmtLines(wndPtr, wParam, lParam);
break;
case EM_LINEFROMCHAR16:
DPRINTF_EDIT_MSG16("EM_LINEFROMCHAR");
/* fall through */
case EM_LINEFROMCHAR32:
DPRINTF_EDIT_MSG32("EM_LINEFROMCHAR");
lResult = EDIT_EM_LineFromChar(wndPtr, wParam, lParam);
break;
/* message 0x00ca missing from specs */
case WM_USER+26:
DPRINTF_EDIT_MSG16("undocumented WM_USER+26, please report");
/* fall through */
case 0x00ca:
DPRINTF_EDIT_MSG32("undocumented 0x00ca, please report");
lResult = DefWindowProc32A(hwnd, msg, wParam, lParam);
break;
case EM_SETTABSTOPS16:
DPRINTF_EDIT_MSG16("EM_SETTABSTOPS");
lResult = EDIT_EM_SetTabStops16(wndPtr, wParam, lParam);
break;
case EM_SETTABSTOPS32:
DPRINTF_EDIT_MSG32("EM_SETTABSTOPS");
lResult = EDIT_EM_SetTabStops(wndPtr, wParam, lParam);
break;
case EM_SETPASSWORDCHAR16:
DPRINTF_EDIT_MSG16("EM_SETPASSWORDCHAR");
/* fall through */
case EM_SETPASSWORDCHAR32:
DPRINTF_EDIT_MSG32("EM_SETPASSWORDCHAR");
lResult = EDIT_EM_SetPasswordChar(wndPtr, wParam, lParam);
break;
case EM_EMPTYUNDOBUFFER16:
DPRINTF_EDIT_MSG16("EM_EMPTYUNDOBUFFER");
/* fall through */
case EM_EMPTYUNDOBUFFER32:
DPRINTF_EDIT_MSG32("EM_EMPTYUNDOBUFFER");
lResult = EDIT_EM_EmptyUndoBuffer(wndPtr, wParam, lParam);
break;
case EM_GETFIRSTVISIBLELINE16:
DPRINTF_EDIT_MSG16("EM_GETFIRSTVISIBLELINE");
/* fall through */
case EM_GETFIRSTVISIBLELINE32:
DPRINTF_EDIT_MSG32("EM_GETFIRSTVISIBLELINE");
lResult = EDIT_EM_GetFirstVisibleLine(wndPtr, wParam, lParam);
break;
case EM_SETREADONLY16:
DPRINTF_EDIT_MSG16("EM_SETREADONLY");
/* fall through */
case EM_SETREADONLY32:
DPRINTF_EDIT_MSG32("EM_SETREADONLY");
lResult = EDIT_EM_SetReadOnly(wndPtr, wParam, lParam);
break;
case EM_SETWORDBREAKPROC16:
DPRINTF_EDIT_MSG16("EM_SETWORDBREAKPROC");
/* fall through */
case EM_SETWORDBREAKPROC32:
DPRINTF_EDIT_MSG32("EM_SETWORDBREAKPROC");
lResult = EDIT_EM_SetWordBreakProc(wndPtr, wParam, lParam);
break;
case EM_GETWORDBREAKPROC16:
DPRINTF_EDIT_MSG16("EM_GETWORDBREAKPROC");
/* fall through */
case EM_GETWORDBREAKPROC32:
DPRINTF_EDIT_MSG32("EM_GETWORDBREAKPROC");
lResult = EDIT_EM_GetWordBreakProc(wndPtr, wParam, lParam);
break;
case EM_GETPASSWORDCHAR16:
DPRINTF_EDIT_MSG16("EM_GETPASSWORDCHAR");
/* fall through */
case EM_GETPASSWORDCHAR32:
DPRINTF_EDIT_MSG32("EM_GETPASSWORDCHAR");
lResult = EDIT_EM_GetPasswordChar(wndPtr, wParam, lParam);
break;
/* The following EM_xxx are new to win95 and don't exist for 16 bit */
case EM_SETMARGINS32:
DPRINTF_EDIT_MSG16("EM_SETMARGINS");
lResult = EDIT_EM_SetMargins(wndPtr, wParam, lParam);
break;
case EM_GETMARGINS32:
DPRINTF_EDIT_MSG16("EM_GETMARGINS");
lResult = EDIT_EM_GetMargins(wndPtr, wParam, lParam);
break;
case EM_GETLIMITTEXT32:
DPRINTF_EDIT_MSG16("EM_GETLIMITTEXT");
lResult = EDIT_EM_GetLimitText(wndPtr, wParam, lParam);
break;
case EM_POSFROMCHAR32:
DPRINTF_EDIT_MSG16("EM_POSFROMCHAR");
lResult = EDIT_EM_PosFromChar(wndPtr, wParam, lParam);
break;
case EM_CHARFROMPOS32:
DPRINTF_EDIT_MSG16("EM_CHARFROMPOS");
lResult = EDIT_EM_CharFromPos(wndPtr, wParam, lParam);
break;
case WM_GETDLGCODE:
DPRINTF_EDIT_MSG32("WM_GETDLGCODE");
lResult = EDIT_WM_GetDlgCode(wndPtr, wParam, lParam);
break;
case WM_CHAR:
DPRINTF_EDIT_MSG32("WM_CHAR");
lResult = EDIT_WM_Char(wndPtr, wParam, lParam);
break;
case WM_CLEAR:
DPRINTF_EDIT_MSG32("WM_CLEAR");
lResult = EDIT_WM_Clear(wndPtr, wParam, lParam);
break;
case WM_COMMAND:
DPRINTF_EDIT_MSG32("WM_COMMAND");
lResult = EDIT_WM_Command(wndPtr, wParam, lParam);
break;
/*
* FIXME: when this one is added to WINE, change RBUTTONUP to CONTEXTMENU
* Furthermore, coordinate conversion should no longer be required
*
* case WM_CONTEXTMENU:
*/
case WM_RBUTTONUP:
DPRINTF_EDIT_MSG32("WM_RBUTTONUP");
ClientToScreen16(wndPtr->hwndSelf, (LPPOINT16)&lParam);
lResult = EDIT_WM_ContextMenu(wndPtr, wParam, lParam);
break;
case WM_COPY:
DPRINTF_EDIT_MSG32("WM_COPY");
lResult = EDIT_WM_Copy(wndPtr, wParam, lParam);
break;
case WM_CREATE:
DPRINTF_EDIT_MSG32("WM_CREATE");
lResult = EDIT_WM_Create(wndPtr, wParam, lParam);
break;
case WM_CUT:
DPRINTF_EDIT_MSG32("WM_CUT");
lResult = EDIT_WM_Cut(wndPtr, wParam, lParam);
break;
case WM_DESTROY:
DPRINTF_EDIT_MSG32("WM_DESTROY");
lResult = EDIT_WM_Destroy(wndPtr, wParam, lParam);
break;
case WM_ENABLE:
DPRINTF_EDIT_MSG32("WM_ENABLE");
lResult = EDIT_WM_Enable(wndPtr, wParam, lParam);
break;
case WM_ERASEBKGND:
DPRINTF_EDIT_MSG32("WM_ERASEBKGND");
lResult = EDIT_WM_EraseBkGnd(wndPtr, wParam, lParam);
break;
case WM_GETFONT:
DPRINTF_EDIT_MSG32("WM_GETFONT");
lResult = EDIT_WM_GetFont(wndPtr, wParam, lParam);
break;
case WM_GETTEXT:
DPRINTF_EDIT_MSG32("WM_GETTEXT");
lResult = EDIT_WM_GetText(wndPtr, wParam, lParam);
break;
case WM_GETTEXTLENGTH:
DPRINTF_EDIT_MSG32("WM_GETTEXTLENGTH");
lResult = EDIT_WM_GetTextLength(wndPtr, wParam, lParam);
break;
case WM_HSCROLL:
DPRINTF_EDIT_MSG32("WM_HSCROLL");
lResult = EDIT_WM_HScroll(wndPtr, wParam, lParam);
break;
case WM_INITMENUPOPUP:
DPRINTF_EDIT_MSG32("WM_INITMENUPOPUP");
lResult = EDIT_WM_InitMenuPopup(wndPtr, wParam, lParam);
break;
case WM_KEYDOWN:
DPRINTF_EDIT_MSG32("WM_KEYDOWN");
lResult = EDIT_WM_KeyDown(wndPtr, wParam, lParam);
break;
case WM_KILLFOCUS:
DPRINTF_EDIT_MSG32("WM_KILLFOCUS");
lResult = EDIT_WM_KillFocus(wndPtr, wParam, lParam);
break;
case WM_LBUTTONDBLCLK:
DPRINTF_EDIT_MSG32("WM_LBUTTONDBLCLK");
lResult = EDIT_WM_LButtonDblClk(wndPtr, wParam, lParam);
break;
case WM_LBUTTONDOWN:
DPRINTF_EDIT_MSG32("WM_LBUTTONDOWN");
lResult = EDIT_WM_LButtonDown(wndPtr, wParam, lParam);
break;
case WM_LBUTTONUP:
DPRINTF_EDIT_MSG32("WM_LBUTTONUP");
lResult = EDIT_WM_LButtonUp(wndPtr, wParam, lParam);
break;
case WM_MOUSEMOVE:
/*
* DPRINTF_EDIT_MSG32("WM_MOUSEMOVE");
*/
lResult = EDIT_WM_MouseMove(wndPtr, wParam, lParam);
break;
case WM_PAINT:
DPRINTF_EDIT_MSG32("WM_PAINT");
lResult = EDIT_WM_Paint(wndPtr, wParam, lParam);
break;
case WM_PASTE:
DPRINTF_EDIT_MSG32("WM_PASTE");
lResult = EDIT_WM_Paste(wndPtr, wParam, lParam);
break;
case WM_SETCURSOR:
/*
* DPRINTF_EDIT_MSG32("WM_SETCURSOR");
*/
lResult = EDIT_WM_SetCursor(wndPtr, wParam, lParam);
break;
case WM_SETFOCUS:
DPRINTF_EDIT_MSG32("WM_SETFOCUS");
lResult = EDIT_WM_SetFocus(wndPtr, wParam, lParam);
break;
case WM_SETFONT:
DPRINTF_EDIT_MSG32("WM_SETFONT");
lResult = EDIT_WM_SetFont(wndPtr, wParam, lParam);
break;
case WM_SETREDRAW:
DPRINTF_EDIT_MSG32("WM_SETREDRAW");
lResult = EDIT_WM_SetRedraw(wndPtr, wParam, lParam);
break;
case WM_SETTEXT:
DPRINTF_EDIT_MSG32("WM_SETTEXT");
lResult = EDIT_WM_SetText(wndPtr, wParam, lParam);
break;
case WM_SIZE:
DPRINTF_EDIT_MSG32("WM_SIZE");
lResult = EDIT_WM_Size(wndPtr, wParam, lParam);
break;
case WM_SYSKEYDOWN:
DPRINTF_EDIT_MSG32("WM_SYSKEYDOWN");
lResult = EDIT_WM_SysKeyDown(wndPtr, wParam, lParam);
break;
case WM_TIMER:
DPRINTF_EDIT_MSG32("WM_TIMER");
lResult = EDIT_WM_Timer(wndPtr, wParam, lParam);
break;
case WM_VSCROLL:
DPRINTF_EDIT_MSG32("WM_VSCROLL");
lResult = EDIT_WM_VScroll(wndPtr, wParam, lParam);
break;
default:
lResult = DefWindowProc32A(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 too 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);
LPSTR text = EDIT_GetPasswordPointer(wndPtr);
INT32 ww = EDIT_GetWndWidth(wndPtr);
HDC32 hdc;
HFONT32 hFont;
HFONT32 oldFont = 0;
LPSTR start, cp;
INT32 prev, next;
INT32 width;
INT32 length;
LINE_END ending;
hdc = GetDC32(wndPtr->hwndSelf);
hFont = (HFONT32)EDIT_WM_GetFont(wndPtr, 0, 0);
if (hFont) oldFont = SelectObject32(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, 0);
es->LineDefs[0].ending = END_0;
es->TextWidth = (INT32)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 = lstrlen32A(start);
} else if ((cp > start) && (*(cp - 1) == '\r')) {
ending = END_SOFT;
length = cp - start - 1;
} else {
ending = END_HARD;
length = cp - start;
}
width = (INT32)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 = (INT32)LOWORD(GetTabbedTextExtent(hdc, start, next,
es->NumTabStops, es->TabStops));
} while (width <= ww);
if (!prev) {
next = 0;
do {
prev = next;
next++;
width = (INT32)LOWORD(GetTabbedTextExtent(hdc, start, next,
es->NumTabStops, es->TabStops));
} while (width <= ww);
if(!prev) prev = 1;
}
length = prev;
if (EDIT_CallWordBreakProc(wndPtr, start, length - 1,
length, WB_ISDELIMITER)) {
length--;
ending = END_DELIMIT;
} else
ending = END_NONE;
width = (INT32)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) SelectObject32(hdc, oldFont);
ReleaseDC32(wndPtr->hwndSelf, hdc);
free(text);
}
/*********************************************************************
*
* EDIT_CallWordBreakProc
*
* Call appropriate WordBreakProc (internal or external).
*
* FIXME: Heavily broken now that we have a LOCAL32 buffer.
* External wordbreak functions have been disabled in
* EM_SETWORDBREAKPROC.
*
*/
static INT32 EDIT_CallWordBreakProc(WND *wndPtr, LPSTR s, INT32 index, INT32 count, INT32 action)
{
return EDIT_WordBreakProc(s, index, count, action);
/*
* EDITWORDBREAKPROC wbp = (EDITWORDBREAKPROC)EDIT_EM_GetWordBreakProc(wndPtr, 0, 0);
*
* if (!wbp) return EDIT_WordBreakProc(s, index, count, action);
* else {
* EDITSTATE *es = EDITSTATEPTR(wndPtr);
* SEGPTR ptr = LOCAL_LockSegptr( wndPtr->hInstance, es->hBuf16 ) +
* (INT16)(s - EDIT_GetPointer(wndPtr));
* INT ret = CallWordBreakProc( (FARPROC16)wbp, ptr,
* index, count, action);
* LOCAL_Unlock( wndPtr->hInstance, es->hBuf16 );
* return ret;
* }
*/
}
/*********************************************************************
*
* EDIT_ColFromWndX
*
* Calculates, for a given line and X-coordinate on the screen, the column.
*
*/
static INT32 EDIT_ColFromWndX(WND *wndPtr, INT32 line, INT32 x)
{
INT32 lc = (INT32)EDIT_EM_GetLineCount(wndPtr, 0, 0);
INT32 li = (INT32)EDIT_EM_LineIndex(wndPtr, line, 0);
INT32 ll = (INT32)EDIT_EM_LineLength(wndPtr, li, 0);
INT32 i;
line = MAX(0, MIN(line, lc - 1));
for (i = 0 ; i < ll ; 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, -1, 0);
EDIT_MoveEnd(wndPtr, TRUE);
EDIT_WM_Clear(wndPtr, 0, 0);
}
/*********************************************************************
*
* EDIT_DelLeft
*
* Delete character to left of cursor.
*
*/
static void EDIT_DelLeft(WND *wndPtr)
{
EDIT_EM_SetSel(wndPtr, -1, 0);
EDIT_MoveBackward(wndPtr, TRUE);
EDIT_WM_Clear(wndPtr, 0, 0);
}
/*********************************************************************
*
* EDIT_DelRight
*
* Delete character to right of cursor.
*
*/
static void EDIT_DelRight(WND *wndPtr)
{
EDIT_EM_SetSel(wndPtr, -1, 0);
EDIT_MoveForward(wndPtr, TRUE);
EDIT_WM_Clear(wndPtr, 0, 0);
}
/*********************************************************************
*
* EDIT_GetAveCharWidth
*
*/
static INT32 EDIT_GetAveCharWidth(WND *wndPtr)
{
EDITSTATE *es = EDITSTATEPTR(wndPtr);
return es->AveCharWidth;
}
/*********************************************************************
*
* EDIT_GetLineHeight
*
*/
static INT32 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, INT32 line, INT32 scol, INT32 ecol, LPRECT32 rc)
{
rc->top = EDIT_WndYFromLine(wndPtr, line);
rc->bottom = rc->top + EDIT_GetLineHeight(wndPtr);
rc->left = EDIT_WndXFromCol(wndPtr, line, scol);
rc->right = (ecol == -1) ? 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 LPSTR EDIT_GetPointer(WND *wndPtr)
{
EDITSTATE *es = EDITSTATEPTR(wndPtr);
if (!es->text && (es->hBuf32 || es->hBuf16)) {
if (es->hBuf32)
es->text = (LPSTR)LocalLock32(es->hBuf32);
else
es->text = LOCAL_Lock(wndPtr->hInstance, es->hBuf16);
}
return es->text;
}
/*********************************************************************
*
* EDIT_GetPasswordPointer
*
*
*/
static LPSTR EDIT_GetPasswordPointer(WND *wndPtr)
{
EDITSTATE *es = EDITSTATEPTR(wndPtr);
LPSTR text = xstrdup(EDIT_GetPointer(wndPtr));
LPSTR p;
if(es->PasswordChar) {
p = text;
while(*p != '\0') {
if(*p != '\r' && *p != '\n')
*p = es->PasswordChar;
p++;
}
}
return text;
}
/*********************************************************************
*
* EDIT_GetRedraw
*
*/
static BOOL32 EDIT_GetRedraw(WND *wndPtr)
{
EDITSTATE *es = EDITSTATEPTR(wndPtr);
return es->Redraw;
}
/*********************************************************************
*
* EDIT_GetSel
*
* Beware: This is not the function called on EM_GETSEL.
* This is the unordered version used internally
* (s can be > e). No return value either.
*
*/
static void EDIT_GetSel(WND *wndPtr, LPINT32 s, LPINT32 e)
{
EDITSTATE *es = EDITSTATEPTR(wndPtr);
if (s)
*s = es->SelStart;
if (e)
*e = es->SelEnd;
}
/*********************************************************************
*
* EDIT_GetTextWidth
*
*/
static INT32 EDIT_GetTextWidth(WND *wndPtr)
{
EDITSTATE *es = EDITSTATEPTR(wndPtr);
return es->TextWidth;
}
/*********************************************************************
*
* EDIT_GetUndoPointer
*
* This acts as a LocalLock32(), but it locks only once. This way
* you can call it whenever you like, without unlocking.
*
*/
static LPSTR EDIT_GetUndoPointer(WND *wndPtr)
{
EDITSTATE *es = EDITSTATEPTR(wndPtr);
if (!es->UndoText && es->hUndoBuf)
es->UndoText = (LPSTR)LocalLock32(es->hUndoBuf);
return es->UndoText;
}
/*********************************************************************
*
* EDIT_GetVisibleLineCount
*
*/
static INT32 EDIT_GetVisibleLineCount(WND *wndPtr)
{
RECT32 rc;
EDIT_EM_GetRect(wndPtr, 0, (LPARAM)&rc);
return MAX(1, MAX(rc.bottom - rc.top, 0) / EDIT_GetLineHeight(wndPtr));
}
/*********************************************************************
*
* EDIT_GetWndWidth
*
*/
static INT32 EDIT_GetWndWidth(WND *wndPtr)
{
RECT32 rc;
EDIT_EM_GetRect(wndPtr, 0, (LPARAM)&rc);
return rc.right - rc.left;
}
/*********************************************************************
*
* EDIT_GetXOffset
*
*/
static INT32 EDIT_GetXOffset(WND *wndPtr)
{
EDITSTATE *es = EDITSTATEPTR(wndPtr);
return es->XOffset;
}
/*********************************************************************
*
* EDIT_InvalidateText
*
* Invalidate the text from offset start upto, but not including,
* offset end. Useful for (re)painting the selection.
* Regions outside the linewidth are not invalidated.
* end == -1 means end == TextLength.
* start and end need not be ordered.
*
*/
static void EDIT_InvalidateText(WND *wndPtr, INT32 start, INT32 end)
{
INT32 fv = (INT32)EDIT_EM_GetFirstVisibleLine(wndPtr, 0, 0);
INT32 vlc = EDIT_GetVisibleLineCount(wndPtr);
INT32 sl;
INT32 el;
INT32 sc;
INT32 ec;
RECT32 rcWnd;
RECT32 rcLine;
RECT32 rcUpdate;
INT32 l;
if (end == start)
return;
if (end == -1)
end = (INT32)EDIT_WM_GetTextLength(wndPtr, 0, 0);
ORDER_INT32(start, end);
sl = (INT32)EDIT_EM_LineFromChar(wndPtr, start, 0);
el = (INT32)EDIT_EM_LineFromChar(wndPtr, end, 0);
if ((el < fv) || (sl > fv + vlc))
return;
sc = start - (INT32)EDIT_EM_LineIndex(wndPtr, sl, 0);
ec = end - (INT32)EDIT_EM_LineIndex(wndPtr, el, 0);
if (sl < fv) {
sl = fv;
sc = 0;
}
if (el > fv + vlc) {
el = fv + vlc;
ec = (INT32)EDIT_EM_LineLength(wndPtr,
(INT32)EDIT_EM_LineIndex(wndPtr, el, 0), 0);
}
EDIT_EM_GetRect(wndPtr, 0, (LPARAM)&rcWnd);
if (sl == el) {
EDIT_GetLineRect(wndPtr, sl, sc, ec, &rcLine);
if (IntersectRect32(&rcUpdate, &rcWnd, &rcLine))
InvalidateRect32( wndPtr->hwndSelf, &rcUpdate, FALSE );
} else {
EDIT_GetLineRect(wndPtr, sl, sc,
(INT32)EDIT_EM_LineLength(wndPtr,
(INT32)EDIT_EM_LineIndex(wndPtr, sl, 0), 0),
&rcLine);
if (IntersectRect32(&rcUpdate, &rcWnd, &rcLine))
InvalidateRect32( wndPtr->hwndSelf, &rcUpdate, FALSE );
for (l = sl + 1 ; l < el ; l++) {
EDIT_GetLineRect(wndPtr, l, 0,
(INT32)EDIT_EM_LineLength(wndPtr,
(INT32)EDIT_EM_LineIndex(wndPtr, l, 0), 0),
&rcLine);
if (IntersectRect32(&rcUpdate, &rcWnd, &rcLine))
InvalidateRect32(wndPtr->hwndSelf, &rcUpdate, FALSE);
}
EDIT_GetLineRect(wndPtr, el, 0, ec, &rcLine);
if (IntersectRect32(&rcUpdate, &rcWnd, &rcLine))
InvalidateRect32( wndPtr->hwndSelf, &rcUpdate, FALSE );
}
}
/*********************************************************************
*
* EDIT_LineFromWndY
*
* Calculates, for a given Y-coordinate on the screen, the line.
*
*/
static INT32 EDIT_LineFromWndY(WND *wndPtr, INT32 y)
{
INT32 fv = (INT32)EDIT_EM_GetFirstVisibleLine(wndPtr, 0, 0);
INT32 lh = EDIT_GetLineHeight(wndPtr);
INT32 lc = (INT32)EDIT_EM_GetLineCount(wndPtr, 0, 0);
return MAX(0, MIN(lc - 1, y / lh + fv));
}
/*********************************************************************
*
* EDIT_MakeFit
*
* Try to fit size + 1 bytes in the buffer. Constrain to limits.
*
*/
static BOOL32 EDIT_MakeFit(WND *wndPtr, INT32 size)
{
EDITSTATE *es = EDITSTATEPTR(wndPtr);
HLOCAL32 hNew32;
HLOCAL16 hNew16;
if (size <= es->BufSize)
return TRUE;
if (size > es->BufLimit) {
dprintf_edit(stddeb, "edit: notification EN_MAXTEXT sent\n");
EDIT_NOTIFY_PARENT(wndPtr, EN_MAXTEXT);
return FALSE;
}
size = ((size / GROWLENGTH) + 1) * GROWLENGTH;
if (size > es->BufLimit)
size = es->BufLimit;
dprintf_edit(stddeb, "edit: EDIT_MakeFit: trying to ReAlloc to %d+1\n", size);
EDIT_ReleasePointer(wndPtr);
if (es->hBuf32) {
if ((hNew32 = LocalReAlloc32(es->hBuf32, size + 1, 0))) {
dprintf_edit(stddeb, "edit: EDIT_MakeFit: Old 32 bit handle %08x, new handle %08x\n", es->hBuf32, hNew32);
es->hBuf32 = hNew32;
es->BufSize = MIN(LocalSize32(es->hBuf32) - 1, es->BufLimit);
if (es->BufSize < size) {
dprintf_edit(stddeb, "edit: EDIT_MakeFit: FAILED ! We now have %d+1\n", es->BufSize);
dprintf_edit(stddeb, "edit: notification EN_ERRSPACE sent\n");
EDIT_NOTIFY_PARENT(wndPtr, EN_ERRSPACE);
return FALSE;
}
dprintf_edit(stddeb, "edit: EDIT_MakeFit: We now have %d+1\n", es->BufSize);
return TRUE;
}
} else {
if ((hNew16 = LOCAL_ReAlloc(wndPtr->hInstance, es->hBuf16, size + 1, LMEM_MOVEABLE))) {
dprintf_edit(stddeb, "edit: EDIT_MakeFit: Old 16 bit handle %08x, new handle %08x\n", es->hBuf16, hNew16);
es->hBuf16 = hNew16;
es->BufSize = MIN(LOCAL_Size(wndPtr->hInstance, es->hBuf16) - 1, es->BufLimit);
if (es->BufSize < size) {
dprintf_edit(stddeb, "edit: EDIT_MakeFit: FAILED ! We now have %d+1\n", es->BufSize);
dprintf_edit(stddeb, "edit: notification EN_ERRSPACE sent\n");
EDIT_NOTIFY_PARENT(wndPtr, EN_ERRSPACE);
return FALSE;
}
dprintf_edit(stddeb, "edit: EDIT_MakeFit: We now have %d+1\n", es->BufSize);
return TRUE;
}
}
dprintf_edit(stddeb, "edit: EDIT_MakeFit: Reallocation failed\n");
dprintf_edit(stddeb, "edit: notification EN_ERRSPACE sent\n");
EDIT_NOTIFY_PARENT(wndPtr, EN_ERRSPACE);
return FALSE;
}
/*********************************************************************
*
* EDIT_MakeUndoFit
*
* Try to fit size + 1 bytes in the undo buffer.
*
*/
static BOOL32 EDIT_MakeUndoFit(WND *wndPtr, INT32 size)
{
EDITSTATE *es = EDITSTATEPTR(wndPtr);
HLOCAL32 hNew;
if (size <= es->UndoBufSize)
return TRUE;
size = ((size / GROWLENGTH) + 1) * GROWLENGTH;
dprintf_edit(stddeb, "edit: EDIT_MakeUndoFit: trying to ReAlloc to %d+1\n", size);
EDIT_ReleaseUndoPointer(wndPtr);
if ((hNew = LocalReAlloc32(es->hUndoBuf, size + 1, 0))) {
dprintf_edit(stddeb, "edit: EDIT_MakeUndoFit: Old handle %08x, new handle %08x\n", es->hUndoBuf, hNew);
es->hUndoBuf = hNew;
es->UndoBufSize = LocalSize32(es->hUndoBuf) - 1;
if (es->UndoBufSize < size) {
dprintf_edit(stddeb, "edit: EDIT_MakeUndoFit: FAILED ! We now have %d+1\n", es->UndoBufSize);
return FALSE;
}
dprintf_edit(stddeb, "edit: EDIT_MakeUndoFit: We now have %d+1\n", es->UndoBufSize);
return TRUE;
}
return FALSE;
}
/*********************************************************************
*
* EDIT_MoveBackward
*
*/
static void EDIT_MoveBackward(WND *wndPtr, BOOL32 extend)
{
INT32 s;
INT32 e;
INT32 l;
INT32 li;
EDIT_GetSel(wndPtr, &s, &e);
l = (INT32)EDIT_EM_LineFromChar(wndPtr, e, 0);
li = (INT32)EDIT_EM_LineIndex(wndPtr, l, 0);
if (e - li == 0) {
if (l) {
li = (INT32)EDIT_EM_LineIndex(wndPtr, l - 1, 0);
e = li + (INT32)EDIT_EM_LineLength(wndPtr, li, 0);
}
} else
e--;
if (!extend)
s = e;
EDIT_SetSel(wndPtr, s, e);
EDIT_EM_ScrollCaret(wndPtr, 0, 0);
}
/*********************************************************************
*
* EDIT_MoveDownward
*
*/
static void EDIT_MoveDownward(WND *wndPtr, BOOL32 extend)
{
INT32 s;
INT32 e;
INT32 l;
INT32 lc;
INT32 li;
INT32 x;
EDIT_GetSel(wndPtr, &s, &e);
l = (INT32)EDIT_EM_LineFromChar(wndPtr, e, 0);
lc = (INT32)EDIT_EM_GetLineCount(wndPtr, e, 0);
li = (INT32)EDIT_EM_LineIndex(wndPtr, l, 0);
if (l < lc - 1) {
x = EDIT_WndXFromCol(wndPtr, l, e - li);
l++;
e = (INT32)EDIT_EM_LineIndex(wndPtr, l, 0) +
EDIT_ColFromWndX(wndPtr, l, x);
}
if (!extend)
s = e;
EDIT_SetSel(wndPtr, s, e);
EDIT_EM_ScrollCaret(wndPtr, 0, 0);
}
/*********************************************************************
*
* EDIT_MoveEnd
*
*/
static void EDIT_MoveEnd(WND *wndPtr, BOOL32 extend)
{
INT32 s;
INT32 e;
INT32 l;
INT32 ll;
INT32 li;
EDIT_GetSel(wndPtr, &s, &e);
l = (INT32)EDIT_EM_LineFromChar(wndPtr, e, 0);
ll = (INT32)EDIT_EM_LineLength(wndPtr, e, 0);
li = (INT32)EDIT_EM_LineIndex(wndPtr, l, 0);
e = li + ll;
if (!extend)
s = e;
EDIT_SetSel(wndPtr, s, e);
EDIT_EM_ScrollCaret(wndPtr, 0, 0);
}
/*********************************************************************
*
* EDIT_MoveForward
*
*/
static void EDIT_MoveForward(WND *wndPtr, BOOL32 extend)
{
INT32 s;
INT32 e;
INT32 l;
INT32 lc;
INT32 ll;
INT32 li;
EDIT_GetSel(wndPtr, &s, &e);
l = (INT32)EDIT_EM_LineFromChar(wndPtr, e, 0);
lc = (INT32)EDIT_EM_GetLineCount(wndPtr, e, 0);
ll = (INT32)EDIT_EM_LineLength(wndPtr, e, 0);
li = (INT32)EDIT_EM_LineIndex(wndPtr, l, 0);
if (e - li == ll) {
if (l != lc - 1)
e = (INT32)EDIT_EM_LineIndex(wndPtr, l + 1, 0);
} else
e++;
if (!extend)
s = e;
EDIT_SetSel(wndPtr, s, e);
EDIT_EM_ScrollCaret(wndPtr, 0, 0);
}
/*********************************************************************
*
* EDIT_MoveHome
*
* Home key: move to beginning of line.
*
*/
static void EDIT_MoveHome(WND *wndPtr, BOOL32 extend)
{
INT32 s;
INT32 e;
INT32 l;
INT32 li;
EDIT_GetSel(wndPtr, &s, &e);
l = (INT32)EDIT_EM_LineFromChar(wndPtr, e, 0);
li = (INT32)EDIT_EM_LineIndex(wndPtr, l, 0);
e = li;
if (!extend)
s = e;
EDIT_SetSel(wndPtr, s, e);
EDIT_EM_ScrollCaret(wndPtr, 0, 0);
}
/*********************************************************************
*
* EDIT_MovePageDown
*
*/
static void EDIT_MovePageDown(WND *wndPtr, BOOL32 extend)
{
INT32 s;
INT32 e;
INT32 l;
INT32 lc;
INT32 li;
INT32 x;
EDIT_GetSel(wndPtr, &s, &e);
l = (INT32)EDIT_EM_LineFromChar(wndPtr, e, 0);
lc = (INT32)EDIT_EM_GetLineCount(wndPtr, e, 0);
li = (INT32)EDIT_EM_LineIndex(wndPtr, l, 0);
if (l < lc - 1) {
x = EDIT_WndXFromCol(wndPtr, l, e - li);
l = MIN(lc - 1, l + EDIT_GetVisibleLineCount(wndPtr));
e = (INT32)EDIT_EM_LineIndex(wndPtr, l, 0) +
EDIT_ColFromWndX(wndPtr, l, x);
}
if (!extend)
s = e;
EDIT_SetSel(wndPtr, s, e);
EDIT_EM_ScrollCaret(wndPtr, 0, 0);
}
/*********************************************************************
*
* EDIT_MovePageUp
*
*/
static void EDIT_MovePageUp(WND *wndPtr, BOOL32 extend)
{
INT32 s;
INT32 e;
INT32 l;
INT32 li;
INT32 x;
EDIT_GetSel(wndPtr, &s, &e);
l = (INT32)EDIT_EM_LineFromChar(wndPtr, e, 0);
li = (INT32)EDIT_EM_LineIndex(wndPtr, l, 0);
if (l) {
x = EDIT_WndXFromCol(wndPtr, l, e - li);
l = MAX(0, l - EDIT_GetVisibleLineCount(wndPtr));
e = (INT32)EDIT_EM_LineIndex(wndPtr, l, 0) +
EDIT_ColFromWndX(wndPtr, l, x);
}
if (!extend)
s = e;
EDIT_SetSel(wndPtr, s, e);
EDIT_EM_ScrollCaret(wndPtr, 0, 0);
}
/*********************************************************************
*
* EDIT_MoveUpward
*
*/
static void EDIT_MoveUpward(WND *wndPtr, BOOL32 extend)
{
INT32 s;
INT32 e;
INT32 l;
INT32 li;
INT32 x;
EDIT_GetSel(wndPtr, &s, &e);
l = (INT32)EDIT_EM_LineFromChar(wndPtr, e, 0);
li = (INT32)EDIT_EM_LineIndex(wndPtr, l, 0);
if (l) {
x = EDIT_WndXFromCol(wndPtr, l, e - li);
l--;
e = (INT32)EDIT_EM_LineIndex(wndPtr, l, 0) +
EDIT_ColFromWndX(wndPtr, l, x);
}
if (!extend)
s = e;
EDIT_SetSel(wndPtr, s, e);
EDIT_EM_ScrollCaret(wndPtr, 0, 0);
}
/*********************************************************************
*
* EDIT_MoveWordBackward
*
*/
static void EDIT_MoveWordBackward(WND *wndPtr, BOOL32 extend)
{
INT32 s;
INT32 e;
INT32 l;
INT32 ll;
INT32 li;
LPSTR text;
EDIT_GetSel(wndPtr, &s, &e);
l = (INT32)EDIT_EM_LineFromChar(wndPtr, e, 0);
ll = (INT32)EDIT_EM_LineLength(wndPtr, e, 0);
li = (INT32)EDIT_EM_LineIndex(wndPtr, l, 0);
if (e - li == 0) {
if (l) {
li = (INT32)EDIT_EM_LineIndex(wndPtr, l - 1, 0);
e = li + (INT32)EDIT_EM_LineLength(wndPtr, li, 0);
}
} else {
text = EDIT_GetPointer(wndPtr);
e = li + (INT32)EDIT_CallWordBreakProc(wndPtr,
text + li, e - li, ll, WB_LEFT);
}
if (!extend)
s = e;
EDIT_SetSel(wndPtr, s, e);
EDIT_EM_ScrollCaret(wndPtr, 0, 0);
}
/*********************************************************************
*
* EDIT_MoveWordForward
*
*/
static void EDIT_MoveWordForward(WND *wndPtr, BOOL32 extend)
{
INT32 s;
INT32 e;
INT32 l;
INT32 lc;
INT32 ll;
INT32 li;
LPSTR text;
EDIT_GetSel(wndPtr, &s, &e);
l = (INT32)EDIT_EM_LineFromChar(wndPtr, e, 0);
lc = (INT32)EDIT_EM_GetLineCount(wndPtr, e, 0);
ll = (INT32)EDIT_EM_LineLength(wndPtr, e, 0);
li = (INT32)EDIT_EM_LineIndex(wndPtr, l, 0);
if (e - li == ll) {
if (l != lc - 1)
e = (INT32)EDIT_EM_LineIndex(wndPtr, l + 1, 0);
} else {
text = EDIT_GetPointer(wndPtr);
e = li + EDIT_CallWordBreakProc(wndPtr,
text + li, e - li + 1, ll, WB_RIGHT);
}
if (!extend)
s = e;
EDIT_SetSel(wndPtr, s, e);
EDIT_EM_ScrollCaret(wndPtr, 0, 0);
}
/*********************************************************************
*
* EDIT_PaintLine
*
*/
static void EDIT_PaintLine(WND *wndPtr, HDC32 hdc, INT32 line, BOOL32 rev)
{
INT32 fv = (INT32)EDIT_EM_GetFirstVisibleLine(wndPtr, 0, 0);
INT32 vlc = EDIT_GetVisibleLineCount(wndPtr);
INT32 lc = (INT32)EDIT_EM_GetLineCount(wndPtr, 0, 0);
INT32 li;
INT32 ll;
INT32 s;
INT32 e;
INT32 x;
INT32 y;
if ((line < fv) || (line > fv + vlc) || (line >= lc))
return;
dprintf_edit(stddeb, "edit: EDIT_PaintLine: line=%d\n", line);
x = EDIT_WndXFromCol(wndPtr, line, 0);
y = EDIT_WndYFromLine(wndPtr, line);
li = (INT32)EDIT_EM_LineIndex(wndPtr, line, 0);
ll = (INT32)EDIT_EM_LineLength(wndPtr, li, 0);
EDIT_GetSel(wndPtr, &s, &e);
ORDER_INT32(s, e);
s = MIN(li + ll, MAX(li, s));
e = MIN(li + ll, MAX(li, e));
if (rev && (s != e) &&
((GetFocus32() == wndPtr->hwndSelf) ||
(wndPtr->dwStyle & ES_NOHIDESEL))) {
x += EDIT_PaintText(wndPtr, hdc, x, y, line, 0, s - li, FALSE);
x += EDIT_PaintText(wndPtr, hdc, x, y, line, s - li, e - s, TRUE);
x += EDIT_PaintText(wndPtr, hdc, x, y, line, e - li, li + ll - e, FALSE);
} else
x += EDIT_PaintText(wndPtr, hdc, x, y, line, 0, ll, FALSE);
}
/*********************************************************************
*
* EDIT_PaintText
*
*/
static INT32 EDIT_PaintText(WND *wndPtr, HDC32 hdc, INT32 x, INT32 y, INT32 line, INT32 col, INT32 count, BOOL32 rev)
{
EDITSTATE *es = EDITSTATEPTR(wndPtr);
COLORREF BkColor;
COLORREF TextColor;
INT32 ret;
LPSTR text;
INT32 li;
INT32 xoff;
if (!count)
return 0;
BkColor = GetBkColor32(hdc);
TextColor = GetTextColor32(hdc);
if (rev) {
SetBkColor(hdc, GetSysColor(COLOR_HIGHLIGHT));
SetTextColor(hdc, GetSysColor(COLOR_HIGHLIGHTTEXT));
}
text = EDIT_GetPasswordPointer(wndPtr);
li = (INT32)EDIT_EM_LineIndex(wndPtr, line, 0);
xoff = EDIT_GetXOffset(wndPtr);
ret = (INT32)LOWORD(TabbedTextOut(hdc, x, y, text + li + col, count,
es->NumTabStops, es->TabStops, -xoff));
free(text);
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->hBuf32 || es->hBuf16)) {
if (es->hBuf32)
LocalUnlock32(es->hBuf32);
else
LOCAL_Unlock(wndPtr->hInstance, es->hBuf16);
}
es->text = NULL;
}
/*********************************************************************
*
* EDIT_ReleaseUndoPointer
*
* 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_ReleaseUndoPointer(WND *wndPtr)
{
EDITSTATE *es = EDITSTATEPTR(wndPtr);
if (!es)
return;
if (es->UndoText && es->hUndoBuf)
LocalUnlock32(es->hUndoBuf);
es->UndoText = NULL;
}
/*********************************************************************
*
* EDIT_SetSel
*
* Beware: This is not the function called on EM_SETSEL.
* This is the unordered version used internally
* (s can be > e). Doesn't accept -1 parameters either.
* No range checking.
*
*/
static void EDIT_SetSel(WND *wndPtr, INT32 ns, INT32 ne)
{
EDITSTATE *es = EDITSTATEPTR(wndPtr);
LRESULT pos;
INT32 s;
INT32 e;
EDIT_EM_GetSel(wndPtr, (WPARAM32)&s, (LPARAM)&e);
es->SelStart = ns;
es->SelEnd = ne;
if (EDIT_GetRedraw(wndPtr)) {
if (wndPtr->hwndSelf == GetFocus32()) {
pos = EDIT_EM_PosFromChar(wndPtr, ne, 0);
SetCaretPos((INT16)LOWORD(pos), (INT16)HIWORD(pos));
}
ORDER_INT32(s, ns);
ORDER_INT32(s, ne);
ORDER_INT32(e, ns);
ORDER_INT32(e, ne);
ORDER_INT32(ns, ne);
if (e != ns) {
EDIT_InvalidateText(wndPtr, s, e);
EDIT_InvalidateText(wndPtr, ns, ne);
} else
EDIT_InvalidateText(wndPtr, s, ne);
}
}
/*********************************************************************
*
* EDIT_WndXFromCol
*
* Calculates, for a given line and column, the X-coordinate on the screen.
*
*/
static INT32 EDIT_WndXFromCol(WND *wndPtr, INT32 line, INT32 col)
{
EDITSTATE *es = EDITSTATEPTR(wndPtr);
LPSTR text = EDIT_GetPasswordPointer(wndPtr);
INT32 ret;
HDC32 hdc;
HFONT32 hFont;
HFONT32 oldFont = 0;
INT32 lc = (INT32)EDIT_EM_GetLineCount(wndPtr, 0, 0);
INT32 li = (INT32)EDIT_EM_LineIndex(wndPtr, line, 0);
INT32 ll = (INT32)EDIT_EM_LineLength(wndPtr, li, 0);
INT32 xoff = EDIT_GetXOffset(wndPtr);
hdc = GetDC32(wndPtr->hwndSelf);
hFont = (HFONT32)EDIT_WM_GetFont(wndPtr, 0, 0);
if (hFont) oldFont = SelectObject32(hdc, hFont);
line = MAX(0, MIN(line, lc - 1));
col = MIN(col, ll);
ret = (INT32)LOWORD(GetTabbedTextExtent(hdc,
text + li, col,
es->NumTabStops, es->TabStops)) - xoff;
if (hFont) SelectObject32(hdc, oldFont);
ReleaseDC32(wndPtr->hwndSelf, hdc);
free(text);
return ret;
}
/*********************************************************************
*
* EDIT_WndYFromLine
*
* Calculates, for a given line, the Y-coordinate on the screen.
*
*/
static INT32 EDIT_WndYFromLine(WND *wndPtr, INT32 line)
{
INT32 fv = (INT32)EDIT_EM_GetFirstVisibleLine(wndPtr, 0, 0);
INT32 lh = EDIT_GetLineHeight(wndPtr);
return (line - fv) * lh;
}
/*********************************************************************
*
* 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 INT32 EDIT_WordBreakProc(LPSTR s, INT32 index, INT32 count, INT32 action)
{
INT32 ret = 0;
dprintf_edit(stddeb, "edit: EDIT_WordBreakProc: s=%p, index=%u"
", count=%u, 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, WPARAM32 wParam, LPARAM lParam)
{
EDITSTATE *es = EDITSTATEPTR(wndPtr);
return (LRESULT)(es->UndoInsertLen || lstrlen32A(EDIT_GetUndoPointer(wndPtr)));
}
/*********************************************************************
*
* EM_CHARFROMPOS
*
* FIXME: do the specs mean LineIndex or LineNumber (li v.s. l) ???
*/
static LRESULT EDIT_EM_CharFromPos(WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
{
POINT32 pt;
RECT32 rc;
INT32 l;
INT32 li;
INT32 c;
pt.x = LOWORD(lParam);
pt.y = HIWORD(lParam);
GetClientRect32(wndPtr->hwndSelf, &rc);
if (!PtInRect32(&rc, pt))
return -1;
l = EDIT_LineFromWndY(wndPtr, pt.y);
li = EDIT_EM_LineIndex(wndPtr, l, 0);
c = EDIT_ColFromWndX(wndPtr, l, pt.x);
return (LRESULT)MAKELONG(li + c, li);
}
/*********************************************************************
*
* EM_EMPTYUNDOBUFFER
*
*/
static LRESULT EDIT_EM_EmptyUndoBuffer(WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
{
EDITSTATE *es = EDITSTATEPTR(wndPtr);
es->UndoInsertLen = 0;
*EDIT_GetUndoPointer(wndPtr) = '\0';
return 0;
}
/*********************************************************************
*
* EM_FMTLINES
*
*/
static LRESULT EDIT_EM_FmtLines(WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
{
fprintf(stdnimp, "edit: EM_FMTLINES: message not implemented\n");
return wParam ? TRUE : FALSE;
}
/*********************************************************************
*
* EM_GETFIRSTVISIBLELINE
*
*/
static LRESULT EDIT_EM_GetFirstVisibleLine(WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
{
EDITSTATE *es = EDITSTATEPTR(wndPtr);
if (IsMultiLine(wndPtr))
return (LRESULT)es->FirstVisibleLine;
else
return (LRESULT)EDIT_ColFromWndX(wndPtr, 0, 0);
}
/*********************************************************************
*
* EM_GETHANDLE
*
*/
static LRESULT EDIT_EM_GetHandle(WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
{
EDITSTATE *es = EDITSTATEPTR(wndPtr);
if (!IsMultiLine(wndPtr))
return 0;
if (es->hBuf32)
return (LRESULT)es->hBuf32;
else
return (LRESULT)es->hBuf16;
}
/*********************************************************************
*
* EM_GETHANDLE16
*
* Hopefully this won't fire back at us.
* We always start with a buffer in 32 bit linear memory.
* However, with this message a 16 bit application requests
* a handle of 16 bit local heap memory, where it expects to find
* the text.
* It's a pitty that from this moment on we have to use this
* local heap, because applications may rely on the handle
* in the future.
*
* In this function we'll try to switch to local heap.
*/
static LRESULT EDIT_EM_GetHandle16(WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
{
EDITSTATE *es = EDITSTATEPTR(wndPtr);
LPSTR text;
HLOCAL16 newBuf;
LPSTR newText;
INT16 newSize;
if (!IsMultiLine(wndPtr))
return 0;
if (es->hBuf16)
return (LRESULT)es->hBuf16;
if (!LOCAL_HeapSize(wndPtr->hInstance)) {
if (!LocalInit(wndPtr->hInstance, 0,
GlobalSize16(wndPtr->hInstance))) {
fprintf(stderr, "edit: EM_GETHANDLE: could not initialize local heap\n");
return 0;
}
dprintf_edit(stddeb, "edit: EM_GETHANDLE: local heap initialized\n");
}
if (!(newBuf = LOCAL_Alloc(wndPtr->hInstance,
EDIT_WM_GetTextLength(wndPtr, 0, 0) + 1,
LMEM_MOVEABLE))) {
fprintf(stderr, "edit: EM_GETHANDLE: could not allocate new 16 bit buffer\n");
return 0;
}
newSize = MIN(LOCAL_Size(wndPtr->hInstance, newBuf) - 1, es->BufLimit);
if (!(newText = LOCAL_Lock(wndPtr->hInstance, newBuf))) {
fprintf(stderr, "edit: EM_GETHANDLE: could not lock new 16 bit buffer\n");
LOCAL_Free(wndPtr->hInstance, newBuf);
return 0;
}
text = EDIT_GetPointer(wndPtr);
lstrcpy32A(newText, text);
EDIT_ReleasePointer(wndPtr);
GlobalFree32(es->hBuf32);
es->hBuf32 = (HLOCAL32)NULL;
es->hBuf16 = newBuf;
es->BufSize = newSize;
es->text = newText;
dprintf_edit(stddeb, "edit: EM_GETHANDLE: switched to 16 bit buffer\n");
return (LRESULT)es->hBuf16;
}
/*********************************************************************
*
* EM_GETLIMITTEXT
*
*/
static LRESULT EDIT_EM_GetLimitText(WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
{
EDITSTATE *es = EDITSTATEPTR(wndPtr);
return es->BufLimit;
}
/*********************************************************************
*
* EM_GETLINE
*
*/
static LRESULT EDIT_EM_GetLine(WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
{
LPSTR text;
LPSTR src;
LPSTR dst;
INT32 len;
INT32 i;
INT32 lc = (INT32)EDIT_EM_GetLineCount(wndPtr, 0, 0);
if (!IsMultiLine(wndPtr))
wParam = 0;
if ((INT32)wParam >= lc)
return 0;
text = EDIT_GetPointer(wndPtr);
src = text + (INT32)EDIT_EM_LineIndex(wndPtr, wParam, 0);
dst = (LPSTR)lParam;
len = MIN(*(WORD *)dst, (INT32)EDIT_EM_LineLength(wndPtr, wParam, 0));
for (i = 0 ; i < len ; i++) {
*dst = *src;
src++;
dst++;
}
return (LRESULT)len;
}
/*********************************************************************
*
* EM_GETLINECOUNT
*
*/
static LRESULT EDIT_EM_GetLineCount(WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
{
EDITSTATE *es = EDITSTATEPTR(wndPtr);
return (LRESULT)es->LineCount;
}
/*********************************************************************
*
* EM_GETMARGINS
*
*/
static LRESULT EDIT_EM_GetMargins(WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
{
EDITSTATE *es = EDITSTATEPTR(wndPtr);
return (LRESULT)MAKELONG(es->LeftMargin, es->RightMargin);
}
/*********************************************************************
*
* EM_GETMODIFY
*
*/
static LRESULT EDIT_EM_GetModify(WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
{
EDITSTATE *es = EDITSTATEPTR(wndPtr);
return (LRESULT)es->TextChanged;
}
/*********************************************************************
*
* EM_GETPASSWORDCHAR
*
*/
static LRESULT EDIT_EM_GetPasswordChar(WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
{
EDITSTATE *es = EDITSTATEPTR(wndPtr);
return (LRESULT)es->PasswordChar;
}
/*********************************************************************
*
* EM_GETRECT
*
*/
static LRESULT EDIT_EM_GetRect(WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
{
EDITSTATE *es = EDITSTATEPTR(wndPtr);
CopyRect32((LPRECT32)lParam, &es->FormatRect);
return 0;
}
/*********************************************************************
*
* EM_GETRECT16
*
*/
static LRESULT EDIT_EM_GetRect16(WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
{
EDITSTATE *es = EDITSTATEPTR(wndPtr);
CONV_RECT32TO16(&es->FormatRect, (LPRECT16)PTR_SEG_TO_LIN((SEGPTR)lParam));
return 0;
}
/*********************************************************************
*
* EM_GETSEL
*
* Returns the ordered selection range so that
* LOWORD(result) < HIWORD(result)
*
*/
static LRESULT EDIT_EM_GetSel(WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
{
INT32 s;
INT32 e;
EDIT_GetSel(wndPtr, &s, &e);
ORDER_INT32(s, e);
if (wParam)
*(LPINT32)wParam = s;
if (lParam)
*(LPINT32)lParam = e;
return MAKELONG((INT16)s, (INT16)e);
}
/*********************************************************************
*
* EM_GETTHUMB
*
* FIXME: is this right ? (or should it be only HSCROLL)
* (and maybe only for edit controls that really have their
* own scrollbars) (and maybe only for multiline controls ?)
* All in all: very poorly documented
*
*/
static LRESULT EDIT_EM_GetThumb(WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
{
return MAKELONG(EDIT_WM_VScroll(wndPtr, EM_GETTHUMB16, 0),
EDIT_WM_HScroll(wndPtr, EM_GETTHUMB16, 0));
}
/*********************************************************************
*
* EM_GETWORDBREAKPROC
*
* FIXME: Application defined WordBreakProc should be returned
*
*/
static LRESULT EDIT_EM_GetWordBreakProc(WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
{
/*
EDITSTATE *es = EDITSTATEPTR(wndPtr);
return (LRESULT)es->WordBreakProc;
*/
return 0;
}
/*********************************************************************
*
* EM_LINEFROMCHAR
*
*/
static LRESULT EDIT_EM_LineFromChar(WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
{
INT32 l;
if (!IsMultiLine(wndPtr))
return 0;
if ((INT32)wParam == -1)
EDIT_EM_GetSel(wndPtr, (WPARAM32)&wParam, 0); /* intentional (looks weird, doesn't it ?) */
l = (INT32)EDIT_EM_GetLineCount(wndPtr, 0, 0) - 1;
while ((INT32)EDIT_EM_LineIndex(wndPtr, l, 0) > (INT32)wParam)
l--;
return (LRESULT)l;
}
/*********************************************************************
*
* EM_LINEINDEX
*
*/
static LRESULT EDIT_EM_LineIndex(WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
{
EDITSTATE *es = EDITSTATEPTR(wndPtr);
INT32 e;
INT32 l;
INT32 lc = (INT32)EDIT_EM_GetLineCount(wndPtr, 0, 0);
if ((INT32)wParam == -1) {
EDIT_GetSel(wndPtr, NULL, &e);
l = lc - 1;
while (es->LineDefs[l].offset > e)
l--;
return (LRESULT)es->LineDefs[l].offset;
}
if ((INT32)wParam >= lc)
return -1;
return (LRESULT)es->LineDefs[(INT32)wParam].offset;
}
/*********************************************************************
*
* EM_LINELENGTH
*
*/
static LRESULT EDIT_EM_LineLength(WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
{
EDITSTATE *es = EDITSTATEPTR(wndPtr);
INT32 s;
INT32 e;
INT32 sl;
INT32 el;
if (!IsMultiLine(wndPtr))
return (LRESULT)es->LineDefs[0].length;
if ((INT32)wParam == -1) {
EDIT_GetSel(wndPtr, &s, &e);
sl = (INT32)EDIT_EM_LineFromChar(wndPtr, s, 0);
el = (INT32)EDIT_EM_LineFromChar(wndPtr, e, 0);
return (LRESULT)(s - es->LineDefs[sl].offset +
es->LineDefs[el].offset +
es->LineDefs[el].length - e);
}
return (LRESULT)es->LineDefs[(INT32)EDIT_EM_LineFromChar(wndPtr, wParam, 0)].length;
}
/*********************************************************************
*
* EM_LINESCROLL
*
* FIXME: is wParam in pixels or in average character widths ???
* FIXME: we use this internally to scroll single line controls as well
* (specs are vague about whether this message is valid or not for
* single line controls)
*
*/
static LRESULT EDIT_EM_LineScroll(WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
{
EDITSTATE *es = EDITSTATEPTR(wndPtr);
INT32 lc = (INT32)EDIT_EM_GetLineCount(wndPtr, 0, 0);
INT32 fv = (INT32)EDIT_EM_GetFirstVisibleLine(wndPtr, 0, 0);
INT32 nfv = MAX(0, fv + (INT32)lParam);
INT32 xoff = EDIT_GetXOffset(wndPtr);
INT32 nxoff = MAX(0, xoff + (INT32)wParam);
INT32 tw = EDIT_GetTextWidth(wndPtr);
INT32 dx;
INT32 dy;
if (nfv >= lc)
nfv = lc - 1;
if (nxoff >= tw)
nxoff = tw;
dx = xoff - nxoff;
dy = EDIT_WndYFromLine(wndPtr, fv) - EDIT_WndYFromLine(wndPtr, nfv);
if (dx || dy) {
if (EDIT_GetRedraw(wndPtr))
ScrollWindow32(wndPtr->hwndSelf, dx, dy, NULL, NULL);
es->FirstVisibleLine = nfv;
es->XOffset = nxoff;
if (IsVScrollBar(wndPtr))
SetScrollPos32(wndPtr->hwndSelf, SB_VERT,
EDIT_WM_VScroll(wndPtr, EM_GETTHUMB16, 0), TRUE);
if (IsHScrollBar(wndPtr))
SetScrollPos32(wndPtr->hwndSelf, SB_HORZ,
EDIT_WM_HScroll(wndPtr, EM_GETTHUMB16, 0), TRUE);
}
if (IsMultiLine(wndPtr))
return TRUE;
else
return FALSE;
}
/*********************************************************************
*
* EM_POSFROMCHAR
*
*/
static LRESULT EDIT_EM_PosFromChar(WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
{
INT32 len = (INT32)EDIT_WM_GetTextLength(wndPtr, 0, 0);
INT32 l;
INT32 li;
wParam = MIN(wParam, len);
l = EDIT_EM_LineFromChar(wndPtr, wParam, 0);
li = EDIT_EM_LineIndex(wndPtr, l, 0);
return (LRESULT)MAKELONG(EDIT_WndXFromCol(wndPtr, l, wParam - li),
EDIT_WndYFromLine(wndPtr, l));
}
/*********************************************************************
*
* EM_REPLACESEL
*
*/
static LRESULT EDIT_EM_ReplaceSel(WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
{
EDITSTATE *es = EDITSTATEPTR(wndPtr);
LPCSTR str = (LPCSTR)lParam;
INT32 strl = lstrlen32A(str);
INT32 tl = (INT32)EDIT_WM_GetTextLength(wndPtr, 0, 0);
INT32 utl;
INT32 s;
INT32 e;
INT32 i;
LPSTR p;
LPSTR text;
LPSTR utext;
BOOL32 redraw;
EDIT_EM_GetSel(wndPtr, (WPARAM32)&s, (LPARAM)&e);
if ((s == e) && !strl)
return 0;
if (!EDIT_MakeFit(wndPtr, tl - (e - s) + strl))
return 0;
text = EDIT_GetPointer(wndPtr);
utext = EDIT_GetUndoPointer(wndPtr);
if (e != s) {
/* there is something to be deleted */
if ((BOOL32)wParam) {
/* we have to be able to undo */
utl = lstrlen32A(utext);
if (!es->UndoInsertLen && (*utext && (s == es->UndoPos))) {
/* undo-buffer is extended to the right */
EDIT_MakeUndoFit(wndPtr, utl + e - s);
lstrcpyn32A(utext + utl, text + s, e - s + 1);
} else if (!es->UndoInsertLen && (*utext && (e == es->UndoPos))) {
/* undo-buffer is extended to the left */
EDIT_MakeUndoFit(wndPtr, utl + e - s);
for (p = utext + utl ; p >= utext ; p--)
p[e - s] = p[0];
for (i = 0 , p = utext ; i < e - s ; i++)
p[i] = (text + s)[i];
es->UndoPos = s;
} else {
/* new undo-buffer */
EDIT_MakeUndoFit(wndPtr, e - s);
lstrcpyn32A(utext, text + s, e - s + 1);
es->UndoPos = s;
}
/* any deletion makes the old insertion-undo invalid */
es->UndoInsertLen = 0;
} else
EDIT_EM_EmptyUndoBuffer(wndPtr, 0, 0);
/* now delete */
lstrcpy32A(text + s, text + e);
}
if (strl) {
/* there is an insertion */
if ((BOOL32)wParam) {
/* we have to be able to undo */
if ((s == es->UndoPos) ||
((es->UndoInsertLen) &&
(s == es->UndoPos + es->UndoInsertLen)))
/*
* insertion is new and at delete position or
* an extension to either left or right
*/
es->UndoInsertLen += strl;
else {
/* new insertion undo */
es->UndoPos = s;
es->UndoInsertLen = strl;
/* new insertion makes old delete-buffer invalid */
*utext = '\0';
}
} else
EDIT_EM_EmptyUndoBuffer(wndPtr, 0, 0);
/* now insert */
tl = lstrlen32A(text);
for (p = text + tl ; p >= text + s ; p--)
p[strl] = p[0];
for (i = 0 , p = text + s ; i < strl ; i++)
p[i] = str[i];
if(IsUpper(wndPtr))
CharUpperBuff32A(p, strl);
else if(IsLower(wndPtr))
CharLowerBuff32A(p, strl);
s += strl;
}
redraw = EDIT_GetRedraw(wndPtr);
EDIT_WM_SetRedraw(wndPtr, FALSE, 0);
EDIT_BuildLineDefs(wndPtr);
EDIT_EM_SetSel(wndPtr, s, s);
EDIT_EM_ScrollCaret(wndPtr, 0, 0);
EDIT_EM_SetModify(wndPtr, TRUE, 0);
dprintf_edit(stddeb, "edit: notification EN_UPDATE sent\n");
EDIT_NOTIFY_PARENT(wndPtr, EN_UPDATE);
EDIT_WM_SetRedraw(wndPtr, redraw, 0);
if (redraw) {
InvalidateRect32( wndPtr->hwndSelf, NULL, TRUE );
dprintf_edit(stddeb, "edit: notification EN_CHANGE sent\n");
EDIT_NOTIFY_PARENT(wndPtr, EN_CHANGE);
}
return 0;
}
/*********************************************************************
*
* EM_SCROLL
*
* FIXME: Scroll what ??? And where ???
*
*/
static LRESULT EDIT_EM_Scroll(WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
{
fprintf(stdnimp, "edit: EM_SCROLL: message not implemented\n");
return 0;
}
/*********************************************************************
*
* EM_SCROLLCARET
*
* Makes sure the caret is visible.
* FIXME: We use EM_LINESCROLL, but may we do that for single line
* controls ???
*
*/
static LRESULT EDIT_EM_ScrollCaret(WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
{
INT32 e;
INT32 l;
INT32 li;
INT32 fv = (INT32)EDIT_EM_GetFirstVisibleLine(wndPtr, 0, 0);
INT32 vlc = EDIT_GetVisibleLineCount(wndPtr);
INT32 ww = EDIT_GetWndWidth(wndPtr);
INT32 cw = EDIT_GetAveCharWidth(wndPtr);
INT32 x;
INT32 dy = 0;
INT32 dx = 0;
EDIT_GetSel(wndPtr, NULL, &e);
l = (INT32)EDIT_EM_LineFromChar(wndPtr, e, 0);
li = (INT32)EDIT_EM_LineIndex(wndPtr, l, 0);
x = EDIT_WndXFromCol(wndPtr, l, e - li);
if (l >= fv + vlc)
dy = l - vlc + 1 - fv;
if (l < fv)
dy = l - fv;
if (x < 0)
dx = x - ww / HSCROLL_FRACTION / cw * cw;
if (x > ww)
dx = x - (HSCROLL_FRACTION - 1) * ww / HSCROLL_FRACTION / cw * cw;
if (dy || dx) {
EDIT_EM_LineScroll(wndPtr, dx, dy);
if (dy) {
dprintf_edit(stddeb, "edit: notification EN_VSCROLL sent\n");
EDIT_NOTIFY_PARENT(wndPtr, EN_VSCROLL);
}
if (dx) {
dprintf_edit(stddeb, "edit: notification EN_HSCROLL sent\n");
EDIT_NOTIFY_PARENT(wndPtr, EN_HSCROLL);
}
}
return TRUE;
}
/*********************************************************************
*
* EM_SETHANDLE
*
*/
static LRESULT EDIT_EM_SetHandle(WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
{
EDITSTATE *es = EDITSTATEPTR(wndPtr);
if (IsMultiLine(wndPtr)) {
EDIT_ReleasePointer(wndPtr);
/*
* old buffer is freed by caller
*/
es->hBuf16 = (HLOCAL16)NULL;
es->hBuf32 = (HLOCAL32)wParam;
es->BufSize = LocalSize32(es->hBuf32) - 1;
es->LineCount = 0;
es->FirstVisibleLine = 0;
es->SelStart = es->SelEnd = 0;
EDIT_EM_EmptyUndoBuffer(wndPtr, 0, 0);
EDIT_EM_SetModify(wndPtr, FALSE, 0);
EDIT_BuildLineDefs(wndPtr);
if (EDIT_GetRedraw(wndPtr))
InvalidateRect32( wndPtr->hwndSelf, NULL, TRUE );
EDIT_EM_ScrollCaret(wndPtr, 0, 0);
}
return 0;
}
/*********************************************************************
*
* EM_SETHANDLE16
*
*/
static LRESULT EDIT_EM_SetHandle16(WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
{
EDITSTATE *es = EDITSTATEPTR(wndPtr);
if (IsMultiLine(wndPtr)) {
EDIT_ReleasePointer(wndPtr);
/*
* old buffer is freed by caller
*/
es->hBuf16 = (HLOCAL16)wParam;
es->hBuf32 = (HLOCAL32)NULL;
es->BufSize = LOCAL_Size(wndPtr->hInstance, es->hBuf16) - 1;
es->LineCount = 0;
es->FirstVisibleLine = 0;
es->SelStart = es->SelEnd = 0;
EDIT_EM_EmptyUndoBuffer(wndPtr, 0, 0);
EDIT_EM_SetModify(wndPtr, FALSE, 0);
EDIT_BuildLineDefs(wndPtr);
if (EDIT_GetRedraw(wndPtr))
InvalidateRect32( wndPtr->hwndSelf, NULL, TRUE );
EDIT_EM_ScrollCaret(wndPtr, 0, 0);
}
return 0;
}
/*********************************************************************
*
* EM_SETLIMITTEXT
*
* FIXME: in WinNT maxsize is 0x7FFFFFFF / 0xFFFFFFFF
* However, the windows version is not complied to yet in all of edit.c
*
*/
static LRESULT EDIT_EM_SetLimitText(WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
{
EDITSTATE *es = EDITSTATEPTR(wndPtr);
if (IsMultiLine(wndPtr)) {
if (wParam)
es->BufLimit = MIN((INT32)wParam, BUFLIMIT_MULTI);
else
es->BufLimit = BUFLIMIT_MULTI;
} else {
if (wParam)
es->BufLimit = MIN((INT32)wParam, BUFLIMIT_SINGLE);
else
es->BufLimit = BUFLIMIT_SINGLE;
}
return 0;
}
/*********************************************************************
*
* EM_SETMARGINS
*
* FIXME: We let the margins be set, but we don't use them yet !?!
*
*/
static LRESULT EDIT_EM_SetMargins(WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
{
EDITSTATE *es = EDITSTATEPTR(wndPtr);
if (wParam & EC_USEFONTINFO) {
if (IsMultiLine(wndPtr)) {
/*
* FIXME: do some GetABCCharWidth, or so
* This is just preliminary
*/
es->LeftMargin = es->RightMargin = EDIT_GetAveCharWidth(wndPtr);
} else
es->LeftMargin = es->RightMargin = EDIT_GetAveCharWidth(wndPtr);
return 0;
}
if (wParam & EC_LEFTMARGIN)
es->LeftMargin = LOWORD(lParam);
if (wParam & EC_RIGHTMARGIN)
es->RightMargin = HIWORD(lParam);
return 0;
}
/*********************************************************************
*
* EM_SETMODIFY
*
*/
static LRESULT EDIT_EM_SetModify(WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
{
EDITSTATE *es = EDITSTATEPTR(wndPtr);
es->TextChanged = (BOOL32)wParam;
return 0;
}
/*********************************************************************
*
* EM_SETPASSWORDCHAR
*
* FIXME: This imlementation is way too simple
*
*/
static LRESULT EDIT_EM_SetPasswordChar(WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
{
EDITSTATE *es = EDITSTATEPTR(wndPtr);
es->PasswordChar = (CHAR)wParam;
return 0;
}
/*********************************************************************
*
* EM_SETREADONLY
*
*/
static LRESULT EDIT_EM_SetReadOnly(WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
{
if ((BOOL32)wParam)
wndPtr->dwStyle |= ES_READONLY;
else
wndPtr->dwStyle &= ~(DWORD)ES_READONLY;
return TRUE;
}
/*********************************************************************
*
* EM_SETRECT
*
*/
static LRESULT EDIT_EM_SetRect(WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
{
fprintf(stdnimp,"edit: EM_SETRECT: message not implemented\n");
return 0;
}
/*********************************************************************
*
* EM_SETRECTNP
*
*/
static LRESULT EDIT_EM_SetRectNP(WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
{
fprintf(stdnimp,"edit: EM_SETRECTNP: message not implemented\n");
return 0;
}
/*********************************************************************
*
* EM_SETSEL
*
*/
static LRESULT EDIT_EM_SetSel(WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
{
INT32 ns = (INT32)wParam;
INT32 ne = (INT32)lParam;
INT32 tl = (INT32)EDIT_WM_GetTextLength(wndPtr, 0, 0);
if (ns == -1) {
EDIT_GetSel(wndPtr, NULL, &ne);
ns = ne;
} else if ((!ns) && (ne == -1))
ne = tl;
else {
ns = MAX(0, MIN(ns, tl));
ne = MAX(0, MIN(ne, tl));
ORDER_INT32(ns, ne);
}
EDIT_SetSel(wndPtr, ns, ne);
return -1;
}
/*********************************************************************
*
* EM_SETSEL16
*
*/
static LRESULT EDIT_EM_SetSel16(WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
{
INT32 ns = (INT32)LOWORD(lParam);
INT32 ne = (INT32)HIWORD(lParam);
if ((INT16)LOWORD(lParam) == -1)
ns = -1;
if ((!ns) && ((INT16)HIWORD(lParam) == -1))
ne = -1;
EDIT_EM_SetSel(wndPtr, ns, ne);
if (!wParam)
EDIT_EM_ScrollCaret(wndPtr, 0, 0);
return -1;
}
/*********************************************************************
*
* EM_SETTABSTOPS
*
*/
static LRESULT EDIT_EM_SetTabStops(WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
{
EDITSTATE *es = EDITSTATEPTR(wndPtr);
INT32 i;
if (!IsMultiLine(wndPtr))
return FALSE;
if (es->TabStops)
free(es->TabStops);
es->NumTabStops = (INT32)wParam;
if (!wParam)
es->TabStops = NULL;
else {
es->TabStops = (LPINT16)xmalloc(wParam * sizeof(INT16));
for ( i = 0 ; i < (INT32)wParam ; i++ )
es->TabStops[i] = (INT16)((LPINT32)lParam)[i];
}
return TRUE;
}
/*********************************************************************
*
* EM_SETTABSTOPS16
*
*/
static LRESULT EDIT_EM_SetTabStops16(WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
{
EDITSTATE *es = EDITSTATEPTR(wndPtr);
if (!IsMultiLine(wndPtr))
return FALSE;
if (es->TabStops)
free(es->TabStops);
es->NumTabStops = (INT32)wParam;
if (!wParam)
es->TabStops = NULL;
else {
es->TabStops = (LPINT16)xmalloc(wParam * sizeof(INT16));
memcpy(es->TabStops, (LPINT16)PTR_SEG_TO_LIN(lParam),
(INT32)wParam * sizeof(INT16));
}
return TRUE;
}
/*********************************************************************
*
* EM_SETWORDBREAKPROC
*
*/
static LRESULT EDIT_EM_SetWordBreakProc(WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
{
/*
EDITSTATE *es = EDITSTATEPTR(wndPtr);
es->WordBreakProc = (EDITWORDBREAKPROC)lParam;
*/
return 0;
}
/*********************************************************************
*
* EM_UNDO / WM_UNDO
*
*/
static LRESULT EDIT_EM_Undo(WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
{
EDITSTATE *es = EDITSTATEPTR(wndPtr);
LPSTR utext = xstrdup(EDIT_GetUndoPointer(wndPtr));
dprintf_edit(stddeb, "edit: before UNDO:insertion length = %d, deletion buffer = %s\n",
es->UndoInsertLen, utext);
EDIT_EM_SetSel(wndPtr, es->UndoPos, es->UndoPos + es->UndoInsertLen);
EDIT_EM_EmptyUndoBuffer(wndPtr, 0, 0);
EDIT_EM_ReplaceSel(wndPtr, TRUE, (LPARAM)utext);
EDIT_EM_SetSel(wndPtr, es->UndoPos, es->UndoPos + es->UndoInsertLen);
free(utext);
dprintf_edit(stddeb, "edit: after UNDO: insertion length = %d, deletion buffer = %s\n",
es->UndoInsertLen, EDIT_GetUndoPointer(wndPtr));
return TRUE;
}
/*********************************************************************
*
* WM_CHAR
*
*/
static LRESULT EDIT_WM_Char(WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
{
char str[2];
unsigned char c = (unsigned char)wParam;
switch (c) {
case '\r':
case '\n':
if (IsMultiLine(wndPtr)) {
if (IsReadOnly(wndPtr)) {
EDIT_MoveHome(wndPtr, FALSE);
EDIT_MoveDownward(wndPtr, FALSE);
} else
EDIT_EM_ReplaceSel(wndPtr, (WPARAM32)TRUE, (LPARAM)"\r\n");
}
break;
case '\t':
if (IsMultiLine(wndPtr) && !IsReadOnly(wndPtr))
EDIT_EM_ReplaceSel(wndPtr, (WPARAM32)TRUE, (LPARAM)"\t");
break;
default:
if (!IsReadOnly(wndPtr) && (c >= ' ') && (c != 127)) {
str[0] = c;
str[1] = '\0';
EDIT_EM_ReplaceSel(wndPtr, (WPARAM32)TRUE, (LPARAM)str);
}
break;
}
return 0;
}
/*********************************************************************
*
* WM_CLEAR
*
*/
static LRESULT EDIT_WM_Clear(WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
{
EDIT_EM_ReplaceSel(wndPtr, TRUE, (LPARAM)"");
return -1;
}
/*********************************************************************
*
* WM_COMMAND
*
*/
static LRESULT EDIT_WM_Command(WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
{
if (HIWORD(wParam))
return 0;
switch (LOWORD(wParam)) {
case EM_UNDO32:
EDIT_EM_Undo(wndPtr, 0, 0);
break;
case WM_CUT:
EDIT_WM_Cut(wndPtr, 0, 0);
break;
case WM_COPY:
EDIT_WM_Copy(wndPtr, 0, 0);
break;
case WM_PASTE:
EDIT_WM_Paste(wndPtr, 0, 0);
break;
case WM_CLEAR:
EDIT_WM_Clear(wndPtr, 0, 0);
break;
case EM_SETSEL32:
EDIT_EM_SetSel(wndPtr, 0, -1);
EDIT_EM_ScrollCaret(wndPtr, 0, 0);
break;
default:
dprintf_edit(stddeb, "edit: unknown menu item, please report\n");
break;
}
return -1;
}
/*********************************************************************
*
* WM_CONTEXTMENU
*
* Note: the resource files resource/sysres_??.rc cannot define a
* single popup menu. Hence we use a (dummy) menubar
* containing the single popup menu as its first item.
*
*/
static LRESULT EDIT_WM_ContextMenu(WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
{
HMENU32 hMenu = LoadMenuIndirect32A(SYSRES_GetResPtr(SYSRES_MENU_EDITMENU));
HMENU32 hPopup = GetSubMenu32(hMenu, 0);
TrackPopupMenu32(hPopup, TPM_LEFTALIGN | TPM_RIGHTBUTTON, LOWORD(lParam),
HIWORD(lParam), 0, wndPtr->hwndSelf, NULL);
DestroyMenu32(hMenu);
return 0;
}
/*********************************************************************
*
* WM_COPY
*
*/
static LRESULT EDIT_WM_Copy(WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
{
INT32 s;
INT32 e;
HGLOBAL16 hdst;
LPSTR text;
LPSTR dst;
EDIT_GetSel(wndPtr, &s, &e);
if (e == s)
return -1;
ORDER_INT32(s, e);
hdst = GlobalAlloc16(GMEM_MOVEABLE, (DWORD)(e - s + 1));
dst = GlobalLock16(hdst);
text = EDIT_GetPointer(wndPtr);
lstrcpyn32A(dst, text + s, e - s + 1);
GlobalUnlock16(hdst);
OpenClipboard(wndPtr->hwndSelf);
EmptyClipboard();
SetClipboardData(CF_TEXT, hdst);
CloseClipboard();
return -1;
}
/*********************************************************************
*
* WM_CREATE
*
*/
static LRESULT EDIT_WM_Create(WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
{
CREATESTRUCT32A *cs = (CREATESTRUCT32A *)lParam;
EDITSTATE *es;
LPSTR text;
es = xmalloc(sizeof(EDITSTATE));
memset(es, 0, sizeof(EDITSTATE));
*(EDITSTATE **)wndPtr->wExtra = es;
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;
if (IsMultiLine(wndPtr)) {
es->BufSize = BUFSTART_MULTI;
es->BufLimit = BUFLIMIT_MULTI;
es->PasswordChar = '\0';
} else {
es->BufSize = BUFSTART_SINGLE;
es->BufLimit = BUFLIMIT_SINGLE;
es->PasswordChar = (cs->style & ES_PASSWORD) ? '*' : '\0';
}
if (!(es->hBuf32 = LocalAlloc32(LMEM_MOVEABLE, es->BufSize + 1))) {
fprintf(stderr, "edit: WM_CREATE: unable to allocate buffer\n");
return -1;
}
if (!(es->hUndoBuf = LocalAlloc32(LMEM_MOVEABLE, es->BufSize + 1))) {
fprintf(stderr, "edit: WM_CREATE: unable to allocate undo buffer\n");
LocalFree32(es->hBuf32);
es->hBuf32 = (HLOCAL32)NULL;
return -1;
}
es->BufSize = LocalSize32(es->hBuf32) - 1;
es->UndoBufSize = LocalSize32(es->hUndoBuf) - 1;
EDIT_EM_EmptyUndoBuffer(wndPtr, 0, 0);
text = EDIT_GetPointer(wndPtr);
*text = '\0';
EDIT_BuildLineDefs(wndPtr);
EDIT_WM_SetFont(wndPtr, 0, 0);
if (cs->lpszName && *(cs->lpszName) != '\0')
EDIT_EM_ReplaceSel(wndPtr, (WPARAM32)FALSE, (LPARAM)cs->lpszName);
EDIT_WM_SetRedraw(wndPtr, TRUE, 0);
return 0;
}
/*********************************************************************
*
* WM_CUT
*
*/
static LRESULT EDIT_WM_Cut(WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
{
EDIT_WM_Copy(wndPtr, 0, 0);
EDIT_WM_Clear(wndPtr, 0, 0);
return -1;
}
/*********************************************************************
*
* WM_DESTROY
*
*/
static LRESULT EDIT_WM_Destroy(WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
{
EDITSTATE *es = EDITSTATEPTR(wndPtr);
free(es->LineDefs);
if (es->TabStops)
free(es->TabStops);
EDIT_ReleaseUndoPointer(wndPtr);
LocalFree32(es->hUndoBuf);
EDIT_ReleasePointer(wndPtr);
if (es->hBuf32)
LocalFree32(es->hBuf32);
else
LOCAL_Free(wndPtr->hInstance, es->hBuf16);
free(es);
*(EDITSTATE **)&wndPtr->wExtra = NULL;
return 0;
}
/*********************************************************************
*
* WM_ENABLE
*
*/
static LRESULT EDIT_WM_Enable(WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
{
EDIT_InvalidateText(wndPtr, 0, -1);
return 0;
}
/*********************************************************************
*
* WM_ERASEBKGND
*
*/
static LRESULT EDIT_WM_EraseBkGnd(WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
{
HBRUSH32 hBrush;
RECT32 rc;
hBrush = (HBRUSH32)EDIT_SEND_CTLCOLOR(wndPtr, wParam);
if (!hBrush) hBrush = (HBRUSH32)GetStockObject32(WHITE_BRUSH);
GetClientRect32(wndPtr->hwndSelf, &rc);
IntersectClipRect32((HDC32)wParam, rc.left, rc.top,
rc.right, rc.bottom);
GetClipBox32((HDC32)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.
*/
FillRect32((HDC32)wParam, &rc, hBrush);
return -1;
}
/*********************************************************************
*
* WM_GETDLGCODE
*
*/
static LRESULT EDIT_WM_GetDlgCode(WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
{
return DLGC_HASSETSEL | DLGC_WANTCHARS | DLGC_WANTARROWS;
}
/*********************************************************************
*
* WM_GETFONT
*
*/
static LRESULT EDIT_WM_GetFont(WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
{
EDITSTATE *es = EDITSTATEPTR(wndPtr);
return (LRESULT)es->hFont;
}
/*********************************************************************
*
* WM_GETTEXT
*
*/
static LRESULT EDIT_WM_GetText(WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
{
LPSTR text = EDIT_GetPointer(wndPtr);
INT32 len;
LRESULT lResult = 0;
len = lstrlen32A(text);
if ((INT32)wParam > len) {
lstrcpy32A((LPSTR)lParam, text);
lResult = (LRESULT)len + 1;
}
return lResult;
}
/*********************************************************************
*
* WM_GETTEXTLENGTH
*
*/
static LRESULT EDIT_WM_GetTextLength(WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
{
LPSTR text = EDIT_GetPointer(wndPtr);
return (LRESULT)lstrlen32A(text);
}
/*********************************************************************
*
* WM_HSCROLL
*
* FIXME: scrollbar code itself is broken, so this one is a hack.
*
*/
static LRESULT EDIT_WM_HScroll(WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
{
INT32 ww = EDIT_GetWndWidth(wndPtr);
INT32 tw = EDIT_GetTextWidth(wndPtr);
INT32 cw = EDIT_GetAveCharWidth(wndPtr);
INT32 xoff = EDIT_GetXOffset(wndPtr);
INT32 dx = 0;
BOOL32 not = TRUE;
LRESULT ret = 0;
switch (wParam) {
case SB_LINELEFT:
dx = -cw;
break;
case SB_LINERIGHT:
dx = cw;
break;
case SB_PAGELEFT:
dx = -ww / HSCROLL_FRACTION / cw * cw;
break;
case SB_PAGERIGHT:
dx = ww / HSCROLL_FRACTION / cw * cw;
break;
case SB_LEFT:
dx = -xoff;
break;
case SB_RIGHT:
dx = tw - xoff;
break;
case SB_THUMBTRACK:
/*
* not = FALSE;
*/
case SB_THUMBPOSITION:
dx = HIWORD(wParam) * tw / 100 - xoff;
break;
/* The next two are undocumented ! */
case EM_GETTHUMB16:
ret = tw ? xoff * 100 / tw : 0;
break;
case EM_LINESCROLL16:
dx = (INT16)HIWORD(wParam);
break;
case SB_ENDSCROLL:
default:
break;
}
if (dx) {
EDIT_EM_LineScroll(wndPtr, dx, 0);
if (not) {
dprintf_edit(stddeb, "edit: notification EN_HSCROLL sent\n");
EDIT_NOTIFY_PARENT(wndPtr, EN_HSCROLL);
}
}
return ret;
}
/*********************************************************************
*
* WM_INITMENUPOPUP
*
* FIXME: the message identifiers have been chosen arbitrarily,
* hence we use MF_BYPOSITION.
* We might as well use the "real" values (anybody knows ?)
* The menu definition is in resources/sysres_??.rc.
* Once these are OK, we better use MF_BYCOMMAND here
* (as we do in EDIT_WM_Command()).
*
*/
static LRESULT EDIT_WM_InitMenuPopup(WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
{
HMENU32 hPopup = (HMENU32)wParam;
INT32 s;
INT32 e;
EDIT_EM_GetSel(wndPtr, (WPARAM32)&s, (LPARAM)&e);
/* undo */
EnableMenuItem32(hPopup, 0, MF_BYPOSITION |
(EDIT_EM_CanUndo(wndPtr, 0, 0) ? MF_ENABLED : MF_GRAYED));
/* cut */
EnableMenuItem32(hPopup, 2, MF_BYPOSITION |
((e - s) && !IsPassword(wndPtr) ? MF_ENABLED : MF_GRAYED));
/* copy */
EnableMenuItem32(hPopup, 3, MF_BYPOSITION |
((e - s) && !IsPassword(wndPtr) ? MF_ENABLED : MF_GRAYED));
/* paste */
EnableMenuItem32(hPopup, 4, MF_BYPOSITION |
(IsClipboardFormatAvailable(CF_TEXT) ? MF_ENABLED : MF_GRAYED));
/* delete */
EnableMenuItem32(hPopup, 5, MF_BYPOSITION |
((e - s) ? MF_ENABLED : MF_GRAYED));
/* select all */
EnableMenuItem32(hPopup, 7, MF_BYPOSITION |
(s || (e != EDIT_WM_GetTextLength(wndPtr, 0, 0)) ? MF_ENABLED : MF_GRAYED));
return 0;
}
/*********************************************************************
*
* 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, WPARAM32 wParam, LPARAM lParam)
{
INT32 s;
INT32 e;
BOOL32 shift;
BOOL32 control;
if (GetKeyState32(VK_MENU) & 0x8000)
return 0;
shift = GetKeyState32(VK_SHIFT) & 0x8000;
control = GetKeyState32(VK_CONTROL) & 0x8000;
EDIT_GetSel(wndPtr, &s, &e);
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, 0);
else
EDIT_DelLeft(wndPtr);
break;
case VK_DELETE:
if (!IsReadOnly(wndPtr) && !(shift && control))
if (e != s) {
if (shift)
EDIT_WM_Cut(wndPtr, 0, 0);
else
EDIT_WM_Clear(wndPtr, 0, 0);
} 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, 0);
} else if (control)
EDIT_WM_Copy(wndPtr, 0, 0);
break;
}
return 0;
}
/*********************************************************************
*
* WM_KILLFOCUS
*
*/
static LRESULT EDIT_WM_KillFocus(WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
{
INT32 s;
INT32 e;
DestroyCaret();
if(!(wndPtr->dwStyle & ES_NOHIDESEL)) {
EDIT_EM_GetSel(wndPtr, (WPARAM32)&s, (LPARAM)&e);
EDIT_InvalidateText(wndPtr, s, e);
}
dprintf_edit(stddeb, "edit: notification EN_KILLFOCUS sent\n");
EDIT_NOTIFY_PARENT(wndPtr, EN_KILLFOCUS);
return 0;
}
/*********************************************************************
*
* WM_LBUTTONDBLCLK
*
* The caret position has been set on the WM_LBUTTONDOWN message
*
*/
static LRESULT EDIT_WM_LButtonDblClk(WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
{
INT32 s;
INT32 e;
INT32 l;
INT32 li;
INT32 ll;
LPSTR text = EDIT_GetPointer(wndPtr);
EDIT_GetSel(wndPtr, NULL, &e);
l = (INT32)EDIT_EM_LineFromChar(wndPtr, e, 0);
li = (INT32)EDIT_EM_LineIndex(wndPtr, l, 0);
ll = (INT32)EDIT_EM_LineLength(wndPtr, e, 0);
s = li + EDIT_CallWordBreakProc (wndPtr, text + li, e - li, ll, WB_LEFT);
e = li + EDIT_CallWordBreakProc(wndPtr, text + li, e - li, ll, WB_RIGHT);
EDIT_EM_SetSel(wndPtr, s, e);
EDIT_EM_ScrollCaret(wndPtr, 0, 0);
return 0;
}
/*********************************************************************
*
* WM_LBUTTONDOWN
*
*/
static LRESULT EDIT_WM_LButtonDown(WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
{
INT32 x = (INT32)(INT16)LOWORD(lParam);
INT32 y = (INT32)(INT16)HIWORD(lParam);
INT32 l = EDIT_LineFromWndY(wndPtr, y);
INT32 c;
INT32 s;
INT32 e;
INT32 fv = (INT32)EDIT_EM_GetFirstVisibleLine(wndPtr, 0, 0);
INT32 vlc = EDIT_GetVisibleLineCount(wndPtr);
INT32 li;
SetFocus32(wndPtr->hwndSelf);
SetCapture32(wndPtr->hwndSelf);
l = MIN(fv + vlc - 1, MAX(fv, l));
x = MIN(EDIT_GetWndWidth(wndPtr), MAX(0, x));
c = EDIT_ColFromWndX(wndPtr, l, x);
li = (INT32)EDIT_EM_LineIndex(wndPtr, l, 0);
e = li + c;
if (GetKeyState32(VK_SHIFT) & 0x8000)
EDIT_GetSel(wndPtr, &s, NULL);
else
s = e;
EDIT_SetSel(wndPtr, s, e);
EDIT_EM_ScrollCaret(wndPtr, 0, 0);
SetTimer32(wndPtr->hwndSelf, 0, 100, NULL);
return 0;
}
/*********************************************************************
*
* WM_LBUTTONUP
*
*/
static LRESULT EDIT_WM_LButtonUp(WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
{
if (GetCapture32() == wndPtr->hwndSelf) {
KillTimer32(wndPtr->hwndSelf, 0);
ReleaseCapture();
}
return 0;
}
/*********************************************************************
*
* WM_MOUSEMOVE
*
*/
static LRESULT EDIT_WM_MouseMove(WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
{
INT32 x;
INT32 y;
INT32 l;
INT32 c;
INT32 s;
INT32 fv;
INT32 vlc;
INT32 li;
if (GetCapture32() == wndPtr->hwndSelf) {
x = (INT32)(INT16)LOWORD(lParam);
y = (INT32)(INT16)HIWORD(lParam);
fv = (INT32)EDIT_EM_GetFirstVisibleLine(wndPtr, 0, 0);
vlc = EDIT_GetVisibleLineCount(wndPtr);
l = EDIT_LineFromWndY(wndPtr, y);
l = MIN(fv + vlc - 1, MAX(fv, l));
x = MIN(EDIT_GetWndWidth(wndPtr), MAX(0, x));
c = EDIT_ColFromWndX(wndPtr, l, x);
EDIT_GetSel(wndPtr, &s, NULL);
li = (INT32)EDIT_EM_LineIndex(wndPtr, l, 0);
EDIT_SetSel(wndPtr, s, li + c);
}
/*
* FIXME: gotta do some scrolling if outside client (format ?)
* area. Maybe reset the timer ?
*/
return 0;
}
/*********************************************************************
*
* WM_PAINT
*
*/
static LRESULT EDIT_WM_Paint(WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
{
PAINTSTRUCT32 ps;
INT32 i;
INT32 fv = (INT32)EDIT_EM_GetFirstVisibleLine(wndPtr, 0, 0);
INT32 vlc = EDIT_GetVisibleLineCount(wndPtr);
INT32 lc = (INT32)EDIT_EM_GetLineCount(wndPtr, 0, 0);
HDC32 hdc;
HFONT32 hFont;
HFONT32 oldFont = 0;
RECT32 rc;
RECT32 rcLine;
RECT32 rcRgn;
LRESULT pos;
INT32 e;
BOOL32 rev = IsWindowEnabled32(wndPtr->hwndSelf) &&
((GetFocus32() == wndPtr->hwndSelf) ||
(wndPtr->dwStyle & ES_NOHIDESEL));
hdc = BeginPaint32(wndPtr->hwndSelf, &ps);
GetClientRect32(wndPtr->hwndSelf, &rc);
IntersectClipRect32( hdc, rc.left, rc.top, rc.right, rc.bottom );
hFont = (HFONT32)EDIT_WM_GetFont(wndPtr, 0, 0);
if (hFont)
oldFont = (HFONT32)SelectObject32(hdc, hFont);
EDIT_SEND_CTLCOLOR(wndPtr, hdc);
if (!IsWindowEnabled32(wndPtr->hwndSelf))
SetTextColor(hdc, GetSysColor(COLOR_GRAYTEXT));
GetClipBox32(hdc, &rcRgn);
for (i = fv ; i <= MIN(fv + vlc, fv + lc - 1) ; i++ ) {
EDIT_GetLineRect(wndPtr, i, 0, -1, &rcLine);
if (IntersectRect32(&rc, &rcRgn, &rcLine))
EDIT_PaintLine(wndPtr, hdc, i, rev);
}
if (hFont) SelectObject32(hdc, oldFont);
if (wndPtr->hwndSelf == GetFocus32()) {
EDIT_GetSel(wndPtr, NULL, &e);
pos = EDIT_EM_PosFromChar(wndPtr, e, 0);
SetCaretPos((INT16)LOWORD(pos), (INT16)HIWORD(pos));
}
EndPaint32(wndPtr->hwndSelf, &ps);
return 0;
}
/*********************************************************************
*
* WM_PASTE
*
*/
static LRESULT EDIT_WM_Paste(WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
{
HGLOBAL16 hsrc;
LPSTR src;
OpenClipboard(wndPtr->hwndSelf);
if ((hsrc = GetClipboardData(CF_TEXT))) {
src = (LPSTR)GlobalLock16(hsrc);
EDIT_EM_ReplaceSel(wndPtr, (WPARAM32)TRUE, (LPARAM)src);
GlobalUnlock16(hsrc);
}
CloseClipboard();
return -1;
}
/*********************************************************************
*
* WM_SETCURSOR
*
*/
static LRESULT EDIT_WM_SetCursor(WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
{
if (LOWORD(lParam) == HTCLIENT) {
SetCursor(LoadCursor16(0, IDC_IBEAM));
return -1;
} else
return 0;
}
/*********************************************************************
*
* WM_SETFOCUS
*
*/
static LRESULT EDIT_WM_SetFocus(WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
{
INT32 s;
INT32 e;
EDIT_GetSel(wndPtr, &s, &e);
CreateCaret(wndPtr->hwndSelf, 0, 2, EDIT_GetLineHeight(wndPtr));
EDIT_SetSel(wndPtr, s, e);
if(!(wndPtr->dwStyle & ES_NOHIDESEL))
EDIT_InvalidateText(wndPtr, s, e);
ShowCaret(wndPtr->hwndSelf);
dprintf_edit(stddeb, "edit: notification EN_SETFOCUS sent\n");
EDIT_NOTIFY_PARENT(wndPtr, EN_SETFOCUS);
return 0;
}
/*********************************************************************
*
* WM_SETFONT
*
*/
static LRESULT EDIT_WM_SetFont(WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
{
TEXTMETRIC32A tm;
EDITSTATE *es = EDITSTATEPTR(wndPtr);
INT32 s;
INT32 e;
HDC32 hdc;
HFONT32 oldFont = 0;
EDIT_GetSel(wndPtr, &s, &e);
es->hFont = (HFONT32)wParam;
hdc = GetDC32(wndPtr->hwndSelf);
if (es->hFont) oldFont = SelectObject32(hdc, es->hFont);
GetTextMetrics32A(hdc, &tm);
es->LineHeight = tm.tmHeight;
es->AveCharWidth = tm.tmAveCharWidth;
if (es->hFont) SelectObject32(hdc, oldFont);
ReleaseDC32(wndPtr->hwndSelf, hdc);
EDIT_BuildLineDefs(wndPtr);
if ((BOOL32)lParam && EDIT_GetRedraw(wndPtr))
InvalidateRect32( wndPtr->hwndSelf, NULL, TRUE );
if (wndPtr->hwndSelf == GetFocus32()) {
DestroyCaret();
CreateCaret(wndPtr->hwndSelf, 0, 2, EDIT_GetLineHeight(wndPtr));
EDIT_SetSel(wndPtr, s, e);
ShowCaret(wndPtr->hwndSelf);
}
return 0;
}
/*********************************************************************
*
* WM_SETREDRAW
*
*/
static LRESULT EDIT_WM_SetRedraw(WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
{
EDITSTATE *es = EDITSTATEPTR(wndPtr);
es->Redraw = (BOOL32)wParam;
return 0;
}
/*********************************************************************
*
* WM_SETTEXT
*
*/
static LRESULT EDIT_WM_SetText(WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
{
EDIT_EM_SetSel(wndPtr, 0, -1);
if (lParam)
EDIT_EM_ReplaceSel(wndPtr, (WPARAM32)FALSE, lParam);
EDIT_EM_SetModify(wndPtr, TRUE, 0);
EDIT_EM_ScrollCaret(wndPtr, 0, 0);
return 1;
}
/*********************************************************************
*
* WM_SIZE
*
* FIXME: What about that FormatRect ???
*
*/
static LRESULT EDIT_WM_Size(WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
{
EDITSTATE *es = EDITSTATEPTR(wndPtr);
INT32 e;
EDIT_GetSel(wndPtr, 0, &e);
GetClientRect32(wndPtr->hwndSelf, &es->FormatRect);
if (EDIT_GetRedraw(wndPtr) &&
((wParam == SIZE_MAXIMIZED) ||
(wParam == SIZE_RESTORED))) {
if (IsMultiLine(wndPtr) && IsWordWrap(wndPtr))
EDIT_BuildLineDefs(wndPtr);
InvalidateRect32( wndPtr->hwndSelf, NULL, TRUE );
}
return 0;
}
/*********************************************************************
*
* WM_SYSKEYDOWN
*
*/
static LRESULT EDIT_WM_SysKeyDown(WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
{
if ((wParam == VK_BACK) && (lParam & 0x2000) &&
(BOOL32)EDIT_EM_CanUndo(wndPtr, 0, 0))
EDIT_EM_Undo(wndPtr, 0, 0);
return 0;
}
/*********************************************************************
*
* WM_TIMER
*
*/
static LRESULT EDIT_WM_Timer(WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
{
/*
* FIXME: gotta do some scrolling here, like
* EDIT_EM_LineScroll(wndPtr, 0, 1);
*/
return 0;
}
/*********************************************************************
*
* WM_VSCROLL
*
* FIXME: scrollbar code itself is broken, so this one is a hack.
*
*/
static LRESULT EDIT_WM_VScroll(WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
{
INT32 lc = (INT32)EDIT_EM_GetLineCount(wndPtr, 0, 0);
INT32 fv = (INT32)EDIT_EM_GetFirstVisibleLine(wndPtr, 0, 0);
INT32 vlc = EDIT_GetVisibleLineCount(wndPtr);
INT32 dy = 0;
BOOL32 not = TRUE;
LRESULT ret = 0;
switch (wParam) {
case SB_LINEUP:
dy = -1;
break;
case SB_LINEDOWN:
dy = 1;
break;
case SB_PAGEUP:
dy = -vlc;
break;
case SB_PAGEDOWN:
dy = vlc;
break;
case SB_TOP:
dy = -fv;
break;
case SB_BOTTOM:
dy = lc - 1 - fv;
break;
case SB_THUMBTRACK:
not = FALSE;
/* fall through */
case SB_THUMBPOSITION:
dy = HIWORD(wParam) * (lc - 1) / 100 - fv;
break;
/* The next two are undocumented ! */
case EM_GETTHUMB16:
ret = (lc > 1) ? MAKELONG(fv * 100 / (lc - 1), 0) : 0;
break;
case EM_LINESCROLL16:
dy = (INT16)LOWORD(lParam);
break;
case SB_ENDSCROLL:
default:
break;
}
if (dy) {
EDIT_EM_LineScroll(wndPtr, 0, dy);
if (not) {
dprintf_edit(stddeb, "edit: notification EN_VSCROLL sent\n");
EDIT_NOTIFY_PARENT(wndPtr, EN_VSCROLL);
}
}
return ret;
}