Commit abefc28f authored by Dylan Smith's avatar Dylan Smith Committed by Alexandre Julliard

richedit: Fixed drag and shift selection for words and lines.

Previously word drag and shift selection was not implemented. Line drag selection was working, but shift selection wasn't.
parent 8a3f21f0
......@@ -868,6 +868,63 @@ ME_CharFromPos(ME_TextEditor *editor, int x, int y)
+ cursor.pRun->member.run.nCharOfs + cursor.nOffset);
}
/* Extends the selection with a word, line, or paragraph selection type.
*
* The selection is anchored by editor->pCursors[2-3] such that the text
* between the anchors will remain selected, and one end will be extended.
*
* editor->pCursors[0] should have the position to extend the selection to
* before this function is called.
*
* Nothing will be done if editor->nSelectionType equals stPosition.
*/
static void ME_ExtendAnchorSelection(ME_TextEditor *editor)
{
ME_Cursor tmp_cursor;
int curOfs, anchorStartOfs, anchorEndOfs;
if (editor->nSelectionType == stPosition)
return;
curOfs = ME_GetCursorOfs(editor, 0);
anchorStartOfs = ME_GetCursorOfs(editor, 2);
anchorEndOfs = ME_GetCursorOfs(editor, 3);
tmp_cursor = editor->pCursors[0];
editor->pCursors[0] = editor->pCursors[2];
editor->pCursors[1] = editor->pCursors[3];
if (curOfs < anchorStartOfs)
{
/* Extend the left side of selection */
editor->pCursors[0] = tmp_cursor;
if (editor->nSelectionType == stWord)
ME_MoveCursorWords(editor, &editor->pCursors[0], -1);
else
{
ME_DisplayItem *pItem;
pItem = ME_FindItemBack(editor->pCursors[0].pRun,
diStartRowOrParagraph);
editor->pCursors[0].pRun = ME_FindItemFwd(pItem, diRun);
editor->pCursors[0].nOffset = 0;
}
}
else if (curOfs >= anchorEndOfs)
{
/* Extend the right side of selection */
editor->pCursors[1] = tmp_cursor;
if (editor->nSelectionType == stWord)
ME_MoveCursorWords(editor, &editor->pCursors[1], +1);
else
{
ME_DisplayItem *pItem;
pItem = ME_FindItemFwd(editor->pCursors[1].pRun,
diStartRowOrParagraphOrEnd);
if (pItem->type == diTextEnd)
editor->pCursors[1].pRun = ME_FindItemBack(pItem, diRun);
else
editor->pCursors[1].pRun = ME_FindItemFwd(pItem, diRun);
editor->pCursors[1].nOffset = 0;
}
}
}
void ME_LButtonDown(ME_TextEditor *editor, int x, int y, int clickNum)
{
......@@ -881,51 +938,54 @@ void ME_LButtonDown(ME_TextEditor *editor, int x, int y, int clickNum)
tmp_cursor = editor->pCursors[0];
is_selection = ME_IsSelection(editor);
if (x >= editor->selofs)
ME_FindPixelPos(editor, x, y, &editor->pCursors[0], &editor->bCaretAtEnd);
if (x >= editor->selofs || GetKeyState(VK_SHIFT) < 0)
{
ME_FindPixelPos(editor, x, y, &editor->pCursors[0], &editor->bCaretAtEnd);
if (GetKeyState(VK_SHIFT)>=0)
if (clickNum > 1)
{
/* Shift key is not down */
editor->nSelectionType = stWord;
editor->pCursors[1] = editor->pCursors[0];
if (clickNum > 1)
ME_SelectWord(editor);
ME_SelectWord(editor);
/* Store the anchor positions for extending the selection. */
editor->pCursors[2] = editor->pCursors[0];
editor->pCursors[3] = editor->pCursors[1];
}
else if (!is_selection) {
else if (GetKeyState(VK_SHIFT)>=0)
{
/* Shift is not down */
editor->nSelectionType = stPosition;
editor->pCursors[1] = editor->pCursors[0];
}
else if (!is_selection)
{
editor->nSelectionType = stPosition;
editor->pCursors[1] = tmp_cursor;
is_selection = 1;
}
else if (editor->nSelectionType != stPosition)
{
ME_ExtendAnchorSelection(editor);
}
}
else
{
ME_DisplayItem *pRow;
ME_DisplayItem *pItem;
editor->linesel = 1;
editor->sely = y;
editor->nSelectionType = stLine;
/* 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);
pItem = ME_FindItemFwd(editor->pCursors[0].pRun, diStartRowOrParagraphOrEnd);
assert(pItem);
if (pItem->type == diTextEnd)
editor->pCursors[1].pRun = ME_FindItemBack(pItem, diRun);
else
editor->pCursors[1].pRun = ME_FindItemFwd(pItem, diRun);
editor->pCursors[1].nOffset = 0;
/* 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
* pCursor[2] and [3] are the selection anchors that are backed up
* so they are kept when the selection changes for drag line selection.
*/
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];
}
......@@ -945,31 +1005,26 @@ void ME_MouseMove(ME_TextEditor *editor, int x, int y)
tmp_cursor = editor->pCursors[0];
/* 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_FindPixelPos(editor, x, y, &tmp_cursor, &editor->bCaretAtEnd);
ME_InvalidateSelection(editor);
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;
ME_ExtendAnchorSelection(editor);
if (editor->nSelectionType != stPosition &&
memcmp(&editor->pCursors[1], &editor->pCursors[3], sizeof(ME_Cursor)))
{
editor->pCursors[0] = tmp_cursor;
editor->pCursors[1] = editor->pCursors[3];
/* The scroll the cursor towards the other end, since it was the one
* extended by ME_ExtendAnchorSelection
*/
ME_Cursor tmpCursor = editor->pCursors[0];
editor->pCursors[0] = editor->pCursors[1];
editor->pCursors[1] = tmpCursor;
SendMessageW(editor->hWnd, EM_SCROLLCARET, 0, 0);
editor->pCursors[1] = editor->pCursors[0];
editor->pCursors[0] = tmpCursor;
} else {
SendMessageW(editor->hWnd, EM_SCROLLCARET, 0, 0);
}
HideCaret(editor->hWnd);
......@@ -977,7 +1032,6 @@ void ME_MouseMove(ME_TextEditor *editor, int x, int y)
ME_InvalidateSelection(editor);
ShowCaret(editor->hWnd);
ME_SendSelChange(editor);
SendMessageW(editor->hWnd, EM_SCROLLCARET, 0, 0);
}
static ME_DisplayItem *ME_FindRunInRow(ME_TextEditor *editor, ME_DisplayItem *pRow,
......
......@@ -1537,7 +1537,10 @@ ME_KeyDown(ME_TextEditor *editor, WORD nKey)
{
BOOL ctrl_is_down = GetKeyState(VK_CONTROL) & 0x8000;
BOOL shift_is_down = GetKeyState(VK_SHIFT) & 0x8000;
if (nKey != VK_SHIFT && nKey != VK_CONTROL && nKey != VK_MENU)
editor->nSelectionType = stPosition;
switch (nKey)
{
case VK_LEFT:
......@@ -1612,7 +1615,8 @@ ME_KeyDown(ME_TextEditor *editor, WORD nKey)
static BOOL ME_SetCursor(ME_TextEditor *editor, int x)
{
if ((GetWindowLongW(editor->hWnd, GWL_STYLE) & ES_SELECTIONBAR) &&
(x < editor->selofs || editor->linesel))
(x < editor->selofs ||
(editor->nSelectionType == stLine && GetCapture() == editor->hWnd)))
{
SetCursor(hLeft);
return TRUE;
......@@ -1654,6 +1658,12 @@ ME_TextEditor *ME_MakeEditor(HWND hWnd) {
ed->nZoomNumerator = ed->nZoomDenominator = 0;
ME_MakeFirstParagraph(ed);
ed->bCaretShown = FALSE;
/* The four cursors are for:
* 0 - The position where the caret is shown
* 1 - The anchored end of the selection (for normal selection)
* 2 & 3 - The anchored start and end respectively for word, line,
* or paragraph selection.
*/
ed->nCursors = 4;
ed->pCursors = ALLOC_N_OBJ(ME_Cursor, ed->nCursors);
ed->pCursors[0].pRun = ME_FindItemFwd(ed->pBuffer->pFirst, diRun);
......@@ -1700,7 +1710,7 @@ ME_TextEditor *ME_MakeEditor(HWND hWnd) {
ed->selofs = SELECTIONBAR_WIDTH;
else
ed->selofs = 0;
ed->linesel = 0;
ed->nSelectionType = stPosition;
if (GetWindowLongW(hWnd, GWL_STYLE) & ES_PASSWORD)
ed->cPasswordMask = '*';
......@@ -3000,7 +3010,6 @@ static LRESULT RichEditWndProc_common(HWND hWnd, UINT msg, WPARAM wParam,
else
{
BOOL ret;
editor->linesel = 0;
ret = ME_SetCursor(editor, LOWORD(lParam));
ME_LinkNotify(editor,msg,wParam,lParam);
if (!ret) goto do_default;
......
......@@ -244,6 +244,12 @@ typedef enum {
umAddBackToUndo
} ME_UndoMode;
typedef enum {
stPosition = 0,
stWord,
stLine
} ME_SelectionType;
typedef struct tagME_FontTableItem {
BYTE bCharSet;
WCHAR *szFaceName;
......@@ -333,7 +339,8 @@ typedef struct tagME_TextEditor
BOOL bHaveFocus;
/*for IME */
int imeStartIndex;
DWORD selofs, linesel, sely;
DWORD selofs; /* The size of the selection bar on the left side of control */
ME_SelectionType nSelectionType;
/* Track previous notified selection */
CHARRANGE notified_cr;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment