WINE_DEFAULT_DEBUG_CHANNEL(richedit);
-
static BOOL
ME_MoveCursorChars(ME_TextEditor *editor, ME_Cursor *pCursor, int nRelOfs);
-
void ME_GetSelection(ME_TextEditor *editor, int *from, int *to)
{
*from = ME_GetCursorOfs(editor, 0);
}
-int ME_GetTextLengthEx(ME_TextEditor *editor, GETTEXTLENGTHEX *how)
+int ME_GetTextLengthEx(ME_TextEditor *editor, const GETTEXTLENGTHEX *how)
{
int length;
-
+
if (how->flags & GTL_PRECISE && how->flags & GTL_CLOSE)
return E_INVALIDARG;
if (how->flags & GTL_NUMCHARS && how->flags & GTL_NUMBYTES)
return E_INVALIDARG;
length = ME_GetTextLength(editor);
-
- if (how->flags & GTL_USECRLF)
- length += editor->nParagraphs;
+
+ if ((GetWindowLongW(editor->hWnd, GWL_STYLE) & ES_MULTILINE) && (how->flags & GTL_USECRLF))
+ length += editor->nParagraphs - 1;
if (how->flags & GTL_NUMBYTES)
{
}
-void ME_SetSelection(ME_TextEditor *editor, int from, int to)
+int ME_SetSelection(ME_TextEditor *editor, int from, int to)
{
+ int selectionEnd = 0;
+ const int len = ME_GetTextLength(editor);
+
+ /* all negative values are effectively the same */
+ if (from < 0)
+ from = -1;
+ if (to < 0)
+ to = -1;
+
+ /* select all */
if (from == 0 && to == -1)
{
- editor->pCursors[1].pRun = ME_FindItemFwd(editor->pBuffer->pFirst, diRun);
+ editor->pCursors[1].pRun = ME_FindItemFwd(editor->pBuffer->pFirst, diRun);
editor->pCursors[1].nOffset = 0;
editor->pCursors[0].pRun = ME_FindItemBack(editor->pBuffer->pLast, diRun);
- editor->pCursors[0].nOffset = 0;
- ME_Repaint(editor);
+ editor->pCursors[0].nOffset = 0;
+ ME_InvalidateSelection(editor);
ME_ClearTempStyle(editor);
- return;
+ return len + 1;
}
- if (from == -1)
+
+ /* if both values are equal and also out of bound, that means to */
+ /* put the selection at the end of the text */
+ if ((from == to) && (to < 0 || to > len))
{
- editor->pCursors[1] = editor->pCursors[0];
- ME_Repaint(editor);
- ME_ClearTempStyle(editor);
- return;
+ selectionEnd = 1;
+ }
+ else
+ {
+ /* if from is negative and to is positive then selection is */
+ /* deselected and caret moved to end of the current selection */
+ if (from < 0)
+ {
+ int start, end;
+ ME_GetSelection(editor, &start, &end);
+ editor->pCursors[1] = editor->pCursors[0];
+ ME_Repaint(editor);
+ ME_ClearTempStyle(editor);
+ return end;
+ }
+
+ /* adjust to if it's a negative value */
+ if (to < 0)
+ to = len + 1;
+
+ /* flip from and to if they are reversed */
+ if (from>to)
+ {
+ int tmp = from;
+ from = to;
+ to = tmp;
+ }
+
+ /* after fiddling with the values, we find from > len && to > len */
+ if (from > len)
+ selectionEnd = 1;
+ /* special case with to too big */
+ else if (to > len)
+ to = len + 1;
}
- if (from>to)
+
+ if (selectionEnd)
{
- int tmp = from;
- from = to;
- to = tmp;
+ editor->pCursors[1].pRun = editor->pCursors[0].pRun = ME_FindItemBack(editor->pBuffer->pLast, diRun);
+ editor->pCursors[1].nOffset = editor->pCursors[0].nOffset = 0;
+ ME_InvalidateSelection(editor);
+ ME_ClearTempStyle(editor);
+ return len;
}
+
ME_RunOfsFromCharOfs(editor, from, &editor->pCursors[1].pRun, &editor->pCursors[1].nOffset);
- ME_RunOfsFromCharOfs(editor, to, &editor->pCursors[0].pRun, &editor->pCursors[0].nOffset);
+ ME_RunOfsFromCharOfs(editor, to, &editor->pCursors[0].pRun, &editor->pCursors[0].nOffset);
+ return to;
}
assert(!pCursor->nOffset || !editor->bCaretAtEnd);
assert(height && x && y);
+ assert(!(ME_GetParagraph(pCursorRun)->member.para.nFlags & MEPF_REWRAP));
+ assert(pCursor->pRun);
+ assert(pCursor->pRun->type == diRun);
if (pCursorRun->type == diRun) {
ME_DisplayItem *row = ME_FindItemBack(pCursorRun, diStartRowOrParagraph);
HDC hDC = GetDC(editor->hWnd);
ME_Context c;
ME_DisplayItem *run = pCursorRun;
- ME_DisplayItem *para;
+ ME_DisplayItem *para = NULL;
SIZE sz = {0, 0};
ME_InitContext(&c, editor, hDC);
if (!pCursor->nOffset && !editor->bCaretAtEnd)
{
ME_DisplayItem *prev = ME_FindItemBack(pCursorRun, diRunOrStartRow);
+ assert(prev);
if (prev->type == diRun)
pSizeRun = prev;
}
assert(row->type == diStartRow); /* paragraph -> run without start row ?*/
para = ME_FindItemBack(row, diParagraph);
+ assert(para);
+ assert(para->type == diParagraph);
if (editor->bCaretAtEnd && !pCursor->nOffset &&
run == ME_FindItemFwd(row, diRun))
{
ME_DisplayItem *tmp = ME_FindItemBack(row, diRunOrParagraph);
+ assert(tmp);
if (tmp->type == diRun)
{
row = ME_FindItemBack(tmp, diStartRow);
pSizeRun = run = tmp;
+ assert(run);
+ assert(run->type == diRun);
sz = ME_GetRunSize(&c, ¶->member.para, &run->member.run, ME_StrLen(run->member.run.strText));
}
}
{
int x, y, height;
+ if (ME_WrapMarkedParagraphs(editor))
+ ME_UpdateScrollBar(editor);
ME_GetCursorCoordinates(editor, &editor->pCursors[0], &x, &y, &height);
- CreateCaret(editor->hWnd, NULL, 0, height);
- SetCaretPos(x, y);
+ if(editor->bHaveFocus)
+ {
+ CreateCaret(editor->hWnd, NULL, 0, height);
+ SetCaretPos(x, y);
+ }
}
void ME_ShowCaret(ME_TextEditor *ed)
{
ME_MoveCaret(ed);
- ShowCaret(ed->hWnd);
+ if(ed->bHaveFocus)
+ ShowCaret(ed->hWnd);
}
void ME_HideCaret(ME_TextEditor *ed)
{
- HideCaret(ed->hWnd);
- DestroyCaret();
+ if(ed->bHaveFocus)
+ {
+ HideCaret(ed->hWnd);
+ DestroyCaret();
+ }
}
void ME_InternalDeleteText(ME_TextEditor *editor, int nOfs,
int nChars)
{
assert(nCursor>=0 && nCursor<editor->nCursors);
+ /* text operations set modified state */
+ editor->nModifyStep = 1;
ME_InternalDeleteText(editor, ME_GetCursorOfs(editor, nCursor), nChars);
}
{
const WCHAR *pos;
ME_Cursor *p = NULL;
-
- assert(style);
+ int oldLen;
/* FIXME really HERE ? */
if (ME_IsSelection(editor))
ME_DeleteSelection(editor);
+ /* FIXME: is this too slow? */
+ /* Didn't affect performance for WM_SETTEXT (around 50sec/30K) */
+ oldLen = ME_GetTextLength(editor);
+
+ /* text operations set modified state */
+ editor->nModifyStep = 1;
+
+ assert(style);
+
assert(nCursor>=0 && nCursor<editor->nCursors);
if (len == -1)
len = lstrlenW(str);
+
+ /* grow the text limit to fit our text */
+ if(editor->nTextLimit < oldLen +len)
+ editor->nTextLimit = oldLen + len;
+
while (len)
{
pos = str;
continue;
}
}
+ /* handle special \r\r\n sequence (richedit 2.x and higher only) */
+ if (!editor->bEmulateVersion10 && pos-str < len-2 && pos[0] == '\r' && pos[1] == '\r' && pos[2] == '\n') {
+ WCHAR space = ' ';
+
+ if (pos!=str)
+ ME_InternalInsertTextFromCursor(editor, nCursor, str, pos-str, style, 0);
+
+ ME_InternalInsertTextFromCursor(editor, nCursor, &space, 1, style, 0);
+
+ pos+=3;
+ if(pos-str <= len) {
+ len -= pos - str;
+ str = pos;
+ continue;
+ }
+ }
if (pos-str < len) { /* handle EOLs */
ME_DisplayItem *tp, *end_run;
ME_Style *tmp_style;
int ME_GetCursorOfs(ME_TextEditor *editor, int nCursor)
{
ME_Cursor *pCursor = &editor->pCursors[nCursor];
-
return ME_GetParagraph(pCursor->pRun)->member.para.nCharOfs
+ pCursor->pRun->member.run.nCharOfs + pCursor->nOffset;
}
-int ME_FindPixelPos(ME_TextEditor *editor, int x, int y, ME_Cursor *result, BOOL *is_eol)
+static void ME_FindPixelPos(ME_TextEditor *editor, int x, int y, ME_Cursor *result, BOOL *is_eol)
{
ME_DisplayItem *p = editor->pBuffer->pFirst->member.para.next_para;
+ ME_DisplayItem *last = NULL;
int rx = 0;
-
+
if (is_eol)
*is_eol = 0;
- while(p != editor->pBuffer->pLast)
+ /* find paragraph */
+ for (; p != editor->pBuffer->pLast; p = p->member.para.next_para)
{
- if (p->type == diParagraph)
+ assert(p->type == diParagraph);
+ if (y < p->member.para.nYPos + p->member.para.nHeight)
{
- int ry = y - p->member.para.nYPos;
- if (ry < 0)
- {
- result->pRun = ME_FindItemFwd(p, diRun);
- result->nOffset = 0;
- return 0;
- }
- if (ry >= p->member.para.nHeight)
- {
- p = p->member.para.next_para;
- continue;
- }
+ y -= p->member.para.nYPos;
p = ME_FindItemFwd(p, diStartRow);
- y = ry;
- continue;
+ break;
}
- if (p->type == diStartRow)
+ }
+ /* find row */
+ for (; p != editor->pBuffer->pLast; )
+ {
+ ME_DisplayItem *pp;
+ assert(p->type == diStartRow);
+ if (y < p->member.row.nYPos + p->member.row.nHeight)
{
- int ry = y - p->member.row.nYPos;
- if (ry < 0)
- return 0;
- if (ry >= p->member.row.nHeight)
- {
- p = ME_FindItemFwd(p, diStartRowOrParagraphOrEnd);
- if (p->type != diStartRow)
- return 0;
- continue;
- }
- p = ME_FindItemFwd(p, diRun);
- continue;
+ p = ME_FindItemFwd(p, diRun);
+ break;
}
- if (p->type == diRun)
+ pp = ME_FindItemFwd(p, diStartRowOrParagraphOrEnd);
+ if (pp->type != diStartRow)
{
- ME_DisplayItem *pp;
+ p = ME_FindItemFwd(p, diRun);
+ break;
+ }
+ p = pp;
+ }
+ for (; p != editor->pBuffer->pLast; p = p->next)
+ {
+ switch (p->type)
+ {
+ case diRun:
rx = x - p->member.run.pt.x;
- if (rx < 0)
- rx = 0;
- if (rx >= p->member.run.nWidth) /* not this run yet... find next item */
- {
- pp = p;
- do {
- p = p->next;
- if (p->type == diRun)
- {
- rx = x - p->member.run.pt.x;
- goto continue_search;
- }
- if (p->type == diStartRow)
- {
- p = ME_FindItemFwd(p, diRun);
- if (is_eol)
- *is_eol = 1;
- rx = 0; /* FIXME not sure */
- goto found_here;
- }
- if (p->type == diParagraph || p->type == diTextEnd)
- {
- rx = 0; /* FIXME not sure */
- p = pp;
- goto found_here;
- }
- } while(1);
- continue;
- }
- found_here:
- if (p->member.run.nFlags & MERF_ENDPARA)
- rx = 0;
- result->pRun = p;
- result->nOffset = ME_CharFromPointCursor(editor, rx, &p->member.run);
- if (editor->pCursors[0].nOffset == p->member.run.strText->nLen && rx)
+ if (rx < p->member.run.nWidth)
{
- result->pRun = ME_FindItemFwd(editor->pCursors[0].pRun, diRun);
- result->nOffset = 0;
+ found_here:
+ assert(p->type == diRun);
+ if ((p->member.run.nFlags & MERF_ENDPARA) || rx < 0)
+ rx = 0;
+ result->pRun = p;
+ result->nOffset = ME_CharFromPointCursor(editor, rx, &p->member.run);
+ if (editor->pCursors[0].nOffset == p->member.run.strText->nLen && rx)
+ {
+ result->pRun = ME_FindItemFwd(editor->pCursors[0].pRun, diRun);
+ result->nOffset = 0;
+ }
+ return;
}
- return 1;
+ break;
+ case diStartRow:
+ p = ME_FindItemFwd(p, diRun);
+ if (is_eol) *is_eol = 1;
+ rx = 0; /* FIXME not sure */
+ goto found_here;
+ case diParagraph:
+ case diTextEnd:
+ rx = 0; /* FIXME not sure */
+ p = last;
+ goto found_here;
+ default: assert(0);
}
- assert(0);
- continue_search:
- ;
+ last = p;
}
result->pRun = ME_FindItemBack(p, diRun);
result->nOffset = 0;
assert(result->pRun->member.run.nFlags & MERF_ENDPARA);
- return 0;
}
tmp_cursor = editor->pCursors[0];
is_selection = ME_IsSelection(editor);
- ME_FindPixelPos(editor, x, y, &editor->pCursors[0], &editor->bCaretAtEnd);
-
- if (GetKeyState(VK_SHIFT)>=0)
+ if (x >= editor->selofs)
{
- editor->pCursors[1] = editor->pCursors[0];
+ ME_FindPixelPos(editor, x, y, &editor->pCursors[0], &editor->bCaretAtEnd);
+ if (GetKeyState(VK_SHIFT)>=0)
+ {
+ editor->pCursors[1] = editor->pCursors[0];
+ }
+ else if (!is_selection) {
+ editor->pCursors[1] = tmp_cursor;
+ is_selection = 1;
+ }
+
+ ME_InvalidateSelection(editor);
+ HideCaret(editor->hWnd);
+ ME_MoveCaret(editor);
+ ShowCaret(editor->hWnd);
+ ME_ClearTempStyle(editor);
+ ME_SendSelChange(editor);
}
else
{
- if (!is_selection) {
- editor->pCursors[1] = tmp_cursor;
- is_selection = 1;
+ ME_DisplayItem *pRow;
+
+ editor->linesel = 1;
+ editor->sely = y;
+ /* Set pCursors[0] to beginning of line */
+ ME_FindPixelPos(editor, x, y, &editor->pCursors[1], &editor->bCaretAtEnd);
+ /* Set pCursors[1] to end of line */
+ pRow = ME_FindItemFwd(editor->pCursors[1].pRun, diStartRowOrParagraphOrEnd);
+ assert(pRow);
+ /* pCursor[0] is the position where the cursor will be drawn,
+ * pCursor[1] is the other end of the selection range
+ * pCursor[2] and [3] are backups of [0] and [1] so I
+ * don't have to look them up again
+ */
+
+ if (pRow->type == diStartRow) {
+ /* FIXME WTF was I thinking about here ? */
+ ME_DisplayItem *pRun = ME_FindItemFwd(pRow, diRun);
+ assert(pRun);
+ editor->pCursors[0].pRun = pRun;
+ editor->pCursors[0].nOffset = 0;
+ editor->bCaretAtEnd = 1;
+ } else {
+ editor->pCursors[0].pRun = ME_FindItemBack(pRow, diRun);
+ assert(editor->pCursors[0].pRun && editor->pCursors[0].pRun->member.run.nFlags & MERF_ENDPARA);
+ editor->pCursors[0].nOffset = 0;
+ editor->bCaretAtEnd = 0;
}
+ editor->pCursors[2] = editor->pCursors[0];
+ editor->pCursors[3] = editor->pCursors[1];
+ ME_InvalidateSelection(editor);
+ HideCaret(editor->hWnd);
+ ME_MoveCaret(editor);
+ ShowCaret(editor->hWnd);
+ ME_ClearTempStyle(editor);
+ ME_SendSelChange(editor);
}
- ME_InvalidateSelection(editor);
- HideCaret(editor->hWnd);
- ME_MoveCaret(editor);
- ShowCaret(editor->hWnd);
- ME_ClearTempStyle(editor);
- ME_SendSelChange(editor);
}
void ME_MouseMove(ME_TextEditor *editor, int x, int y)
y += ME_GetYScrollPos(editor);
tmp_cursor = editor->pCursors[0];
- if (!ME_FindPixelPos(editor, x, y, &tmp_cursor, &editor->bCaretAtEnd))
- /* return */;
-
- if (tmp_cursor.pRun == editor->pCursors[0].pRun &&
- tmp_cursor.nOffset == editor->pCursors[0].nOffset)
+ /* FIXME: do something with the return value of ME_FindPixelPos */
+ if (!editor->linesel)
+ ME_FindPixelPos(editor, x, y, &tmp_cursor, &editor->bCaretAtEnd);
+ else ME_FindPixelPos(editor, (y > editor->sely) * editor->rcFormat.right, y, &tmp_cursor, &editor->bCaretAtEnd);
+
+ if (!memcmp(&tmp_cursor, editor->pCursors, sizeof(tmp_cursor)))
return;
-
+
ME_InvalidateSelection(editor);
- editor->pCursors[0] = tmp_cursor;
+ if (!editor->linesel)
+ editor->pCursors[0] = tmp_cursor;
+ else if (!memcmp(&tmp_cursor, editor->pCursors+2, sizeof(tmp_cursor)) ||
+ !memcmp(&tmp_cursor, editor->pCursors+3, sizeof(tmp_cursor)))
+ {
+ editor->pCursors[0] = editor->pCursors[2];
+ editor->pCursors[1] = editor->pCursors[3];
+ }
+ else if (y < editor->sely)
+ {
+ editor->pCursors[0] = tmp_cursor;
+ editor->pCursors[1] = editor->pCursors[2];
+ }
+ else
+ {
+ editor->pCursors[0] = tmp_cursor;
+ editor->pCursors[1] = editor->pCursors[3];
+ }
+
HideCaret(editor->hWnd);
ME_MoveCaret(editor);
ME_InvalidateSelection(editor);
ME_EnsureVisible(editor, ME_FindItemFwd(editor->pBuffer->pFirst, diRun));
ME_Repaint(editor);
}
- else {
- ME_Scroll(editor, 0, ys-yprev);
- ME_Repaint(editor);
+ else
+ {
+ ME_ScrollUp(editor, ys-yprev);
}
assert(pCursor->pRun);
assert(pCursor->pRun->type == diRun);
ME_EnsureVisible(editor, ME_FindItemBack(editor->pBuffer->pLast, diRun));
ME_Repaint(editor);
}
- else {
- ME_Scroll(editor, 0, ys-yprev);
- ME_Repaint(editor);
+ else
+ {
+ ME_ScrollUp(editor,ys-yprev);
}
assert(pCursor->pRun);
assert(pCursor->pRun->type == diRun);
static void ME_ArrowHome(ME_TextEditor *editor, ME_Cursor *pCursor)
{
ME_DisplayItem *pRow = ME_FindItemBack(pCursor->pRun, diStartRow);
+ /* bCaretAtEnd doesn't make sense if the cursor isn't set at the
+ first character of the next row */
+ assert(!editor->bCaretAtEnd || !pCursor->nOffset);
+ ME_WrapMarkedParagraphs(editor);
if (pRow) {
ME_DisplayItem *pRun;
if (editor->bCaretAtEnd && !pCursor->nOffset) {
else
return 1;
}
-
-BOOL ME_UpdateSelection(ME_TextEditor *editor, ME_Cursor *pTempCursor)
+
+BOOL ME_UpdateSelection(ME_TextEditor *editor, const ME_Cursor *pTempCursor)
{
ME_Cursor old_anchor = editor->pCursors[1];
{
ME_Style *style;
int from, to;
- ME_Cursor c;
-
+
ME_GetSelection(editor, &from, &to);
- ME_CursorFromCharOfs(editor, from, &c);
if (from != to) {
+ ME_Cursor c;
+ ME_CursorFromCharOfs(editor, from, &c);
style = c.pRun->member.run.style;
ME_AddRefStyle(style); /* ME_GetInsertStyle has already done that */
}
SendMessageW(GetParent(editor->hWnd), WM_NOTIFY, sc.nmhdr.idFrom, (LPARAM)&sc);
}
-
BOOL
ME_ArrowKey(ME_TextEditor *editor, int nVKey, BOOL extend, BOOL ctrl)
{
ME_Cursor *p = &editor->pCursors[nCursor];
ME_Cursor tmp_curs = *p;
BOOL success = FALSE;
-
- if (ME_IsSelection(editor) && !extend)
- ME_InvalidateSelection(editor);
+ ME_CheckCharOffsets(editor);
editor->nUDArrowX = -1;
switch(nVKey) {
case VK_LEFT:
editor->pCursors[1] = tmp_curs;
*p = tmp_curs;
- if (ME_IsSelection(editor))
- ME_InvalidateSelection(editor);
+ ME_InvalidateSelection(editor);
+ ME_Repaint(editor);
HideCaret(editor->hWnd);
ME_EnsureVisible(editor, tmp_curs.pRun);
ME_ShowCaret(editor);