- made string operations consistent wrt whitespace handling (which
should greatly improve stability of the wrap code and eliminate regressions of the most recent versions) - completely new scrollbar handling (much more reliable) and related redraw fixes - Page Down handler (no Page Up yet, fixing wrap/redraw/scrollbar bugs was of higher priority)
This commit is contained in:
parent
16779f1e5e
commit
810b261175
|
@ -697,6 +697,54 @@ void ME_ArrowDown(ME_TextEditor *editor, ME_Cursor *pCursor)
|
|||
assert(pCursor->pRun->type == diRun);
|
||||
}
|
||||
|
||||
void ME_ArrowPageDown(ME_TextEditor *editor, ME_Cursor *pCursor)
|
||||
{
|
||||
ME_DisplayItem *pRun = pCursor->pRun;
|
||||
ME_DisplayItem *pLast, *p;
|
||||
int x, y, ys, yd, yp, yprev;
|
||||
ME_Cursor tmp_curs = *pCursor;
|
||||
|
||||
x = ME_GetXForArrow(editor, pCursor);
|
||||
if (!pCursor->nOffset && editor->bCaretAtEnd)
|
||||
pRun = ME_FindItemBack(pRun, diRun);
|
||||
|
||||
p = ME_FindItemBack(pRun, diStartRowOrParagraph);
|
||||
assert(p->type == diStartRow);
|
||||
yp = ME_FindItemBack(p, diParagraph)->member.para.nYPos;
|
||||
yprev = ys = y = yp + p->member.row.nYPos;
|
||||
yd = y + editor->sizeWindow.cy;
|
||||
pLast = p;
|
||||
|
||||
do {
|
||||
p = ME_FindItemFwd(p, diStartRowOrParagraph);
|
||||
if (!p)
|
||||
break;
|
||||
if (p->type == diParagraph) {
|
||||
yp = p->member.para.nYPos;
|
||||
continue;
|
||||
}
|
||||
y = yp + p->member.row.nYPos;
|
||||
if (y >= yd)
|
||||
break;
|
||||
pLast = p;
|
||||
yprev = y;
|
||||
} while(1);
|
||||
|
||||
pCursor->pRun = ME_FindRunInRow(editor, pLast, x, &pCursor->nOffset, &editor->bCaretAtEnd);
|
||||
ME_UpdateSelection(editor, &tmp_curs);
|
||||
if (yprev >= editor->nTotalLength-editor->sizeWindow.cy)
|
||||
{
|
||||
ME_EnsureVisible(editor, ME_FindItemBack(editor->pBuffer->pLast, diRun));
|
||||
ME_Repaint(editor);
|
||||
}
|
||||
else {
|
||||
ME_Repaint(editor);
|
||||
ME_Scroll(editor, 0, ys-yprev);
|
||||
}
|
||||
assert(pCursor->pRun);
|
||||
assert(pCursor->pRun->type == diRun);
|
||||
}
|
||||
|
||||
void ME_ArrowHome(ME_TextEditor *editor, ME_Cursor *pCursor)
|
||||
{
|
||||
ME_DisplayItem *pRow = ME_FindItemBack(pCursor->pRun, diStartRow);
|
||||
|
@ -798,7 +846,7 @@ BOOL ME_CancelSelection(ME_TextEditor *editor, int dir)
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
void ME_RepaintSelection(ME_TextEditor *editor, ME_Cursor *pTempCursor)
|
||||
BOOL ME_UpdateSelection(ME_TextEditor *editor, ME_Cursor *pTempCursor)
|
||||
{
|
||||
ME_Cursor old_anchor = editor->pCursors[1];
|
||||
|
||||
|
@ -807,20 +855,30 @@ void ME_RepaintSelection(ME_TextEditor *editor, ME_Cursor *pTempCursor)
|
|||
/* any selection was present ? if so, it's no more, repaint ! */
|
||||
editor->pCursors[1] = editor->pCursors[0];
|
||||
if (memcmp(pTempCursor, &old_anchor, sizeof(ME_Cursor))) {
|
||||
ME_Repaint(editor);
|
||||
return;
|
||||
return TRUE;
|
||||
}
|
||||
return;
|
||||
return FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!memcmp(pTempCursor, &editor->pCursors[1], sizeof(ME_Cursor))) /* starting selection */
|
||||
{
|
||||
editor->pCursors[1] = *pTempCursor;
|
||||
return TRUE;
|
||||
/* ME_EnsureVisible(editor, editor->pCursors[0].pRun); */
|
||||
}
|
||||
}
|
||||
|
||||
ME_Repaint(editor);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void ME_RepaintSelection(ME_TextEditor *editor, ME_Cursor *pTempCursor)
|
||||
{
|
||||
if (ME_UpdateSelection(editor, pTempCursor)) {
|
||||
ME_EnsureVisible(editor, editor->pCursors[0].pRun);
|
||||
ME_Repaint(editor);
|
||||
}
|
||||
}
|
||||
|
||||
void ME_DeleteSelection(ME_TextEditor *editor)
|
||||
|
@ -883,6 +941,11 @@ BOOL ME_ArrowKey(ME_TextEditor *editor, int nVKey, int nCtrl)
|
|||
ME_RepaintSelection(editor, &tmp_curs);
|
||||
ME_SendSelChange(editor);
|
||||
return TRUE;
|
||||
case VK_NEXT:
|
||||
ME_ArrowPageDown(editor, p);
|
||||
ME_ClearTempStyle(editor);
|
||||
ME_SendSelChange(editor);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
editor->nUDArrowX = -1;
|
||||
|
|
|
@ -505,10 +505,10 @@ static LRESULT ME_StreamIn(ME_TextEditor *editor, DWORD format, EDITSTREAM *stre
|
|||
ME_CommitUndo(editor);
|
||||
ME_ReleaseStyle(style);
|
||||
editor->nEventMask = nEventMask;
|
||||
InvalidateRect(editor->hWnd, NULL, TRUE);
|
||||
ME_UpdateRepaint(editor);
|
||||
if (!(format & SFF_SELECTION)) {
|
||||
ME_ClearTempStyle(editor);
|
||||
ME_EnsureVisible(editor, editor->pCursors[0].pRun);
|
||||
}
|
||||
ME_MoveCaret(editor);
|
||||
ME_SendSelChange(editor);
|
||||
|
@ -1147,6 +1147,8 @@ LRESULT WINAPI RichEditANSIWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lP
|
|||
case WM_SIZE:
|
||||
{
|
||||
ME_MarkAllForWrapping(editor);
|
||||
ME_WrapMarkedParagraphs(editor);
|
||||
ME_UpdateScrollBar(editor);
|
||||
ME_Repaint(editor);
|
||||
return DefWindowProcW(hWnd, msg, wParam, lParam);
|
||||
}
|
||||
|
|
|
@ -161,13 +161,14 @@ void ME_InsertGraphicsFromCursor(ME_TextEditor *editor, int nCursor);
|
|||
void ME_InternalDeleteText(ME_TextEditor *editor, int nOfs, int nChars);
|
||||
int ME_GetTextLength(ME_TextEditor *editor);
|
||||
ME_Style *ME_GetSelectionInsertStyle(ME_TextEditor *editor);
|
||||
BOOL ME_UpdateSelection(ME_TextEditor *editor, ME_Cursor *pTempCursor);
|
||||
|
||||
/* wrap.c */
|
||||
void ME_PrepareParagraphForWrapping(ME_Context *c, ME_DisplayItem *tp);
|
||||
ME_DisplayItem *ME_MakeRow(int height, int baseline, int width);
|
||||
void ME_InsertRowStart(ME_WrapContext *wc, ME_DisplayItem *pEnd);
|
||||
void ME_WrapTextParagraph(ME_Context *c, ME_DisplayItem *tp);
|
||||
void ME_WrapMarkedParagraphs(ME_TextEditor *editor);
|
||||
BOOL ME_WrapMarkedParagraphs(ME_TextEditor *editor);
|
||||
|
||||
/* para.c */
|
||||
ME_DisplayItem *ME_GetParagraph(ME_DisplayItem *run);
|
||||
|
@ -189,10 +190,11 @@ void ME_PaintContent(ME_TextEditor *editor, HDC hDC, BOOL bOnlyNew, RECT *rcUpda
|
|||
void ME_Repaint(ME_TextEditor *editor);
|
||||
void ME_UpdateRepaint(ME_TextEditor *editor);
|
||||
void ME_DrawParagraph(ME_Context *c, ME_DisplayItem *paragraph);
|
||||
void ME_UpdateScrollBar(ME_TextEditor *editor, int ypos);
|
||||
void ME_UpdateScrollBar(ME_TextEditor *editor);
|
||||
int ME_GetScrollPos(ME_TextEditor *editor);
|
||||
void ME_EnsureVisible(ME_TextEditor *editor, ME_DisplayItem *pRun);
|
||||
COLORREF ME_GetBackColor(ME_TextEditor *editor);
|
||||
void ME_Scroll(ME_TextEditor *editor, int cx, int cy);
|
||||
|
||||
/* richole.c */
|
||||
extern LRESULT CreateIRichEditOle(LPVOID *);
|
||||
|
|
|
@ -246,6 +246,7 @@ typedef struct tagME_TextEditor
|
|||
int nLastSelStart, nLastSelEnd;
|
||||
ME_FontCacheItem pFontCache[HFONT_CACHE_SIZE];
|
||||
ME_OutStream *pStream;
|
||||
BOOL bScrollX, bScrollY;
|
||||
} ME_TextEditor;
|
||||
|
||||
typedef struct tagME_Context
|
||||
|
|
|
@ -35,7 +35,9 @@ void ME_PaintContent(ME_TextEditor *editor, HDC hDC, BOOL bOnlyNew, RECT *rcUpda
|
|||
item = editor->pBuffer->pFirst->next;
|
||||
c.pt.y -= yoffset;
|
||||
while(item != editor->pBuffer->pLast) {
|
||||
int ye;
|
||||
assert(item->type == diParagraph);
|
||||
ye = c.pt.y + item->member.para.nHeight;
|
||||
if (!bOnlyNew || (item->member.para.nFlags & MEPF_REPAINT))
|
||||
{
|
||||
BOOL bPaint = (rcUpdate == NULL);
|
||||
|
@ -45,10 +47,11 @@ void ME_PaintContent(ME_TextEditor *editor, HDC hDC, BOOL bOnlyNew, RECT *rcUpda
|
|||
if (bPaint)
|
||||
{
|
||||
ME_DrawParagraph(&c, item);
|
||||
if (!rcUpdate || (rcUpdate->top<=c.pt.y && rcUpdate->bottom>=ye))
|
||||
item->member.para.nFlags &= ~MEPF_REPAINT;
|
||||
}
|
||||
}
|
||||
c.pt.y += item->member.para.nHeight;
|
||||
c.pt.y = ye;
|
||||
item = item->member.para.next_para;
|
||||
}
|
||||
if (c.pt.y<c.rcView.bottom) {
|
||||
|
@ -152,12 +155,15 @@ void ME_Repaint(ME_TextEditor *editor)
|
|||
assert(pRun == pCursor->pRun);
|
||||
assert(nOffset == pCursor->nOffset);
|
||||
ME_MarkSelectionForRepaint(editor);
|
||||
ME_WrapMarkedParagraphs(editor);
|
||||
if (ME_WrapMarkedParagraphs(editor)) {
|
||||
ME_UpdateScrollBar(editor);
|
||||
}
|
||||
hDC = GetDC(editor->hWnd);
|
||||
ME_HideCaret(editor);
|
||||
ME_PaintContent(editor, hDC, TRUE, NULL);
|
||||
ReleaseDC(editor->hWnd, hDC);
|
||||
ME_ShowCaret(editor);
|
||||
ME_EnsureVisible(editor, pCursor->pRun);
|
||||
}
|
||||
|
||||
void ME_UpdateRepaint(ME_TextEditor *editor)
|
||||
|
@ -372,38 +378,67 @@ void ME_DrawParagraph(ME_Context *c, ME_DisplayItem *paragraph) {
|
|||
SetTextAlign(c->hDC, align);
|
||||
}
|
||||
|
||||
void ME_UpdateScrollBar(ME_TextEditor *editor, int ypos)
|
||||
void ME_Scroll(ME_TextEditor *editor, int cx, int cy)
|
||||
{
|
||||
float perc = 0.0;
|
||||
SCROLLINFO si;
|
||||
HWND hWnd = editor->hWnd;
|
||||
int overflow = editor->nTotalLength - editor->sizeWindow.cy;
|
||||
|
||||
si.cbSize = sizeof(SCROLLINFO);
|
||||
si.fMask = SIF_PAGE|SIF_POS|SIF_RANGE|SIF_TRACKPOS;
|
||||
si.fMask = SIF_POS;
|
||||
GetScrollInfo(hWnd, SB_VERT, &si);
|
||||
|
||||
if (ypos < 0) {
|
||||
if (si.nMax<1) si.nMax = 1;
|
||||
perc = 1.0*si.nPos/si.nMax;
|
||||
ypos = perc*overflow;
|
||||
si.nPos -= cy;
|
||||
SetScrollInfo(hWnd, SB_VERT, &si, TRUE);
|
||||
ScrollWindow(hWnd, cx, cy, NULL, NULL);
|
||||
}
|
||||
if (ypos >= overflow && overflow > 0)
|
||||
ypos = overflow - 1;
|
||||
|
||||
if (overflow > 0) {
|
||||
EnableScrollBar(hWnd, SB_VERT, ESB_ENABLE_BOTH);
|
||||
SetScrollRange(hWnd, SB_VERT, 0, overflow, FALSE);
|
||||
SetScrollPos(hWnd, SB_VERT, ypos, TRUE);
|
||||
} else {
|
||||
EnableScrollBar(hWnd, SB_VERT, ESB_DISABLE_BOTH);
|
||||
SetScrollRange(hWnd, SB_VERT, 0, 0, FALSE);
|
||||
SetScrollPos(hWnd, SB_VERT, 0, TRUE);
|
||||
}
|
||||
if (ypos != si.nPos)
|
||||
void ME_UpdateScrollBar(ME_TextEditor *editor)
|
||||
{
|
||||
TRACE("ScrollWindow(%d, %d, %d, %0.4f)\n", si.nPos, si.nMax, ypos, perc);
|
||||
ScrollWindow(hWnd, 0, si.nPos - ypos, NULL, NULL);
|
||||
UpdateWindow(hWnd);
|
||||
HWND hWnd = editor->hWnd;
|
||||
SCROLLINFO si;
|
||||
int nOldLen = editor->nTotalLength;
|
||||
BOOL bScrollY = (editor->nTotalLength > editor->sizeWindow.cy);
|
||||
BOOL bUpdateScrollBars;
|
||||
si.cbSize = sizeof(si);
|
||||
si.fMask = SIF_POS | SIF_RANGE;
|
||||
GetScrollInfo(hWnd, SB_VERT, &si);
|
||||
bUpdateScrollBars = (bScrollY || editor->bScrollY)&& ((si.nMax != nOldLen) || (si.nPage != editor->sizeWindow.cy));
|
||||
|
||||
if (bScrollY != editor->bScrollY)
|
||||
{
|
||||
si.fMask = SIF_RANGE | SIF_PAGE;
|
||||
si.nMin = 0;
|
||||
si.nPage = editor->sizeWindow.cy;
|
||||
if (bScrollY) {
|
||||
si.nMax = editor->nTotalLength;
|
||||
} else {
|
||||
si.nMax = 0;
|
||||
}
|
||||
SetScrollInfo(hWnd, SB_VERT, &si, FALSE);
|
||||
ME_MarkAllForWrapping(editor);
|
||||
editor->bScrollY = bScrollY;
|
||||
ME_WrapMarkedParagraphs(editor);
|
||||
bUpdateScrollBars = TRUE;
|
||||
}
|
||||
if (bUpdateScrollBars) {
|
||||
int nScroll = 0;
|
||||
si.fMask = SIF_PAGE | SIF_RANGE | SIF_POS;
|
||||
if (editor->nTotalLength > editor->sizeWindow.cy) {
|
||||
si.nMax = editor->nTotalLength;
|
||||
si.nPage = editor->sizeWindow.cy;
|
||||
if (si.nPos > si.nMax-si.nPage) {
|
||||
nScroll = (si.nMax-si.nPage)-si.nPos;
|
||||
si.nPos = si.nMax-si.nPage;
|
||||
}
|
||||
}
|
||||
else {
|
||||
si.nMax = 0;
|
||||
si.nPage = 0;
|
||||
si.nPos = 0;
|
||||
}
|
||||
TRACE("min=%d max=%d page=%d pos=%d shift=%d\n", si.nMin, si.nMax, si.nPage, si.nPos, nScroll);
|
||||
SetScrollInfo(hWnd, SB_VERT, &si, TRUE);
|
||||
if (nScroll)
|
||||
ScrollWindow(hWnd, 0, -nScroll, NULL, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -416,18 +451,24 @@ void ME_EnsureVisible(ME_TextEditor *editor, ME_DisplayItem *pRun)
|
|||
{
|
||||
ME_DisplayItem *pRow = ME_FindItemBack(pRun, diStartRow);
|
||||
ME_DisplayItem *pPara = ME_FindItemBack(pRun, diParagraph);
|
||||
int y, yrel, yheight;
|
||||
int y, yrel, yheight, yold;
|
||||
HWND hWnd = editor->hWnd;
|
||||
|
||||
assert(pRow);
|
||||
assert(pPara);
|
||||
|
||||
y = pPara->member.para.nYPos+pRow->member.row.nYPos;
|
||||
yheight = pRow->member.row.nHeight;
|
||||
yrel = y - ME_GetScrollPos(editor);
|
||||
if (yrel < 0)
|
||||
ME_UpdateScrollBar(editor, y);
|
||||
else if (yrel + yheight > editor->sizeWindow.cy)
|
||||
{
|
||||
ME_UpdateScrollBar(editor, y + yheight - editor->sizeWindow.cy);
|
||||
yold = ME_GetScrollPos(editor);
|
||||
yrel = y - yold;
|
||||
if (yrel < 0) {
|
||||
SetScrollPos(hWnd, SB_VERT, y, TRUE);
|
||||
ScrollWindow(hWnd, 0, -yrel, NULL, NULL);
|
||||
UpdateWindow(hWnd);
|
||||
} else if (yrel + yheight > editor->sizeWindow.cy) {
|
||||
int newy = y+yheight-editor->sizeWindow.cy;
|
||||
SetScrollPos(hWnd, SB_VERT, newy, TRUE);
|
||||
ScrollWindow(hWnd, 0, -(newy-yold), NULL, NULL);
|
||||
UpdateWindow(hWnd);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -174,6 +174,8 @@ void ME_JoinRuns(ME_TextEditor *editor, ME_DisplayItem *p)
|
|||
assert(p->member.run.nCharOfs != -1);
|
||||
ME_GetParagraph(p)->member.para.nFlags |= MEPF_REWRAP;
|
||||
|
||||
if (editor->bCaretAtEnd && editor->pCursors[0].pRun == pNext)
|
||||
editor->bCaretAtEnd = FALSE;
|
||||
for (i=0; i<editor->nCursors; i++) {
|
||||
if (editor->pCursors[i].pRun == pNext) {
|
||||
editor->pCursors[i].pRun = p;
|
||||
|
|
|
@ -123,7 +123,6 @@ int ME_IsWhitespaces(ME_String *s)
|
|||
|
||||
int ME_IsSplitable(ME_String *s)
|
||||
{
|
||||
/* FIXME multibyte */
|
||||
WCHAR *pos = s->szData;
|
||||
WCHAR ch;
|
||||
while(ME_IsWSpace(*pos++))
|
||||
|
@ -131,7 +130,7 @@ int ME_IsSplitable(ME_String *s)
|
|||
pos--;
|
||||
while((ch = *pos++) != 0)
|
||||
{
|
||||
if (ME_IsWSpace(*pos++))
|
||||
if (ME_IsWSpace(ch))
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
|
@ -255,7 +254,7 @@ int ME_GetCharBack(ME_String *s, int nPos)
|
|||
|
||||
int ME_FindNonWhitespaceV(ME_String *s, int nVChar) {
|
||||
int i;
|
||||
for (i = nVChar; isspace(s->szData[i]) && i<s->nLen; i++)
|
||||
for (i = nVChar; i<s->nLen && ME_IsWSpace(s->szData[i]); i++)
|
||||
;
|
||||
|
||||
return i;
|
||||
|
@ -264,7 +263,7 @@ int ME_FindNonWhitespaceV(ME_String *s, int nVChar) {
|
|||
/* note: returns offset of the first trailing whitespace */
|
||||
int ME_ReverseFindNonWhitespaceV(ME_String *s, int nVChar) {
|
||||
int i;
|
||||
for (i = nVChar; i>0 && isspace(s->szData[i-1]); i--)
|
||||
for (i = nVChar; i>0 && ME_IsWSpace(s->szData[i-1]); i--)
|
||||
;
|
||||
|
||||
return i;
|
||||
|
@ -273,7 +272,7 @@ int ME_ReverseFindNonWhitespaceV(ME_String *s, int nVChar) {
|
|||
/* note: returns offset of the first trailing nonwhitespace */
|
||||
int ME_ReverseFindWhitespaceV(ME_String *s, int nVChar) {
|
||||
int i;
|
||||
for (i = nVChar; i>0 && !isspace(s->szData[i-1]); i--)
|
||||
for (i = nVChar; i>0 && !ME_IsWSpace(s->szData[i-1]); i--)
|
||||
;
|
||||
|
||||
return i;
|
||||
|
|
|
@ -409,11 +409,12 @@ void ME_PrepareParagraphForWrapping(ME_Context *c, ME_DisplayItem *tp) {
|
|||
}
|
||||
}
|
||||
|
||||
void ME_WrapMarkedParagraphs(ME_TextEditor *editor) {
|
||||
BOOL ME_WrapMarkedParagraphs(ME_TextEditor *editor) {
|
||||
HWND hWnd = editor->hWnd;
|
||||
HDC hDC = GetDC(hWnd);
|
||||
ME_DisplayItem *item;
|
||||
ME_Context c;
|
||||
BOOL bModified = FALSE;
|
||||
|
||||
ME_InitContext(&c, editor, hDC);
|
||||
c.pt.x = 0;
|
||||
|
@ -433,6 +434,8 @@ void ME_WrapMarkedParagraphs(ME_TextEditor *editor) {
|
|||
if (bRedraw)
|
||||
item->member.para.nFlags |= MEPF_REPAINT;
|
||||
|
||||
bModified = bModified | bRedraw;
|
||||
|
||||
c.pt.y += item->member.para.nHeight;
|
||||
item = item->member.para.next_para;
|
||||
}
|
||||
|
@ -442,4 +445,5 @@ void ME_WrapMarkedParagraphs(ME_TextEditor *editor) {
|
|||
|
||||
ME_DestroyContext(&c);
|
||||
ReleaseDC(hWnd, hDC);
|
||||
return bModified;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue