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) ...@@ -868,6 +868,63 @@ ME_CharFromPos(ME_TextEditor *editor, int x, int y)
+ cursor.pRun->member.run.nCharOfs + cursor.nOffset); + 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) 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) ...@@ -881,51 +938,54 @@ void ME_LButtonDown(ME_TextEditor *editor, int x, int y, int clickNum)
tmp_cursor = editor->pCursors[0]; tmp_cursor = editor->pCursors[0];
is_selection = ME_IsSelection(editor); is_selection = ME_IsSelection(editor);
if (x >= editor->selofs)
{
ME_FindPixelPos(editor, x, y, &editor->pCursors[0], &editor->bCaretAtEnd); ME_FindPixelPos(editor, x, y, &editor->pCursors[0], &editor->bCaretAtEnd);
if (GetKeyState(VK_SHIFT)>=0)
if (x >= editor->selofs || GetKeyState(VK_SHIFT) < 0)
{ {
/* Shift key is not down */
editor->pCursors[1] = editor->pCursors[0];
if (clickNum > 1) if (clickNum > 1)
{
editor->nSelectionType = stWord;
editor->pCursors[1] = editor->pCursors[0];
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 (GetKeyState(VK_SHIFT)>=0)
{
/* Shift is not down */
editor->nSelectionType = stPosition;
editor->pCursors[1] = editor->pCursors[0];
} }
else if (!is_selection) { else if (!is_selection)
{
editor->nSelectionType = stPosition;
editor->pCursors[1] = tmp_cursor; editor->pCursors[1] = tmp_cursor;
is_selection = 1; }
else if (editor->nSelectionType != stPosition)
{
ME_ExtendAnchorSelection(editor);
} }
} }
else else
{ {
ME_DisplayItem *pRow; ME_DisplayItem *pItem;
editor->linesel = 1; editor->nSelectionType = stLine;
editor->sely = y;
/* Set pCursors[0] to beginning of line */ /* Set pCursors[0] to beginning of line */
ME_FindPixelPos(editor, x, y, &editor->pCursors[1], &editor->bCaretAtEnd);
/* Set pCursors[1] to end of line */ /* Set pCursors[1] to end of line */
pRow = ME_FindItemFwd(editor->pCursors[1].pRun, diStartRowOrParagraphOrEnd); pItem = ME_FindItemFwd(editor->pCursors[0].pRun, diStartRowOrParagraphOrEnd);
assert(pRow); 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[0] is the position where the cursor will be drawn,
* pCursor[1] is the other end of the selection range * pCursor[1] is the other end of the selection range
* pCursor[2] and [3] are backups of [0] and [1] so I * pCursor[2] and [3] are the selection anchors that are backed up
* don't have to look them up again * 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[2] = editor->pCursors[0];
editor->pCursors[3] = editor->pCursors[1]; editor->pCursors[3] = editor->pCursors[1];
} }
...@@ -945,31 +1005,26 @@ void ME_MouseMove(ME_TextEditor *editor, int x, int y) ...@@ -945,31 +1005,26 @@ void ME_MouseMove(ME_TextEditor *editor, int x, int y)
tmp_cursor = editor->pCursors[0]; tmp_cursor = editor->pCursors[0];
/* FIXME: do something with the return value of ME_FindPixelPos */ /* FIXME: do something with the return value of ME_FindPixelPos */
if (!editor->linesel)
ME_FindPixelPos(editor, x, y, &tmp_cursor, &editor->bCaretAtEnd); 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); 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[0] = tmp_cursor;
editor->pCursors[1] = editor->pCursors[2]; ME_ExtendAnchorSelection(editor);
}
else if (editor->nSelectionType != stPosition &&
memcmp(&editor->pCursors[1], &editor->pCursors[3], sizeof(ME_Cursor)))
{ {
editor->pCursors[0] = tmp_cursor; /* The scroll the cursor towards the other end, since it was the one
editor->pCursors[1] = editor->pCursors[3]; * 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); HideCaret(editor->hWnd);
...@@ -977,7 +1032,6 @@ void ME_MouseMove(ME_TextEditor *editor, int x, int y) ...@@ -977,7 +1032,6 @@ void ME_MouseMove(ME_TextEditor *editor, int x, int y)
ME_InvalidateSelection(editor); ME_InvalidateSelection(editor);
ShowCaret(editor->hWnd); ShowCaret(editor->hWnd);
ME_SendSelChange(editor); ME_SendSelChange(editor);
SendMessageW(editor->hWnd, EM_SCROLLCARET, 0, 0);
} }
static ME_DisplayItem *ME_FindRunInRow(ME_TextEditor *editor, ME_DisplayItem *pRow, static ME_DisplayItem *ME_FindRunInRow(ME_TextEditor *editor, ME_DisplayItem *pRow,
......
...@@ -1538,6 +1538,9 @@ ME_KeyDown(ME_TextEditor *editor, WORD nKey) ...@@ -1538,6 +1538,9 @@ ME_KeyDown(ME_TextEditor *editor, WORD nKey)
BOOL ctrl_is_down = GetKeyState(VK_CONTROL) & 0x8000; BOOL ctrl_is_down = GetKeyState(VK_CONTROL) & 0x8000;
BOOL shift_is_down = GetKeyState(VK_SHIFT) & 0x8000; BOOL shift_is_down = GetKeyState(VK_SHIFT) & 0x8000;
if (nKey != VK_SHIFT && nKey != VK_CONTROL && nKey != VK_MENU)
editor->nSelectionType = stPosition;
switch (nKey) switch (nKey)
{ {
case VK_LEFT: case VK_LEFT:
...@@ -1612,7 +1615,8 @@ ME_KeyDown(ME_TextEditor *editor, WORD nKey) ...@@ -1612,7 +1615,8 @@ ME_KeyDown(ME_TextEditor *editor, WORD nKey)
static BOOL ME_SetCursor(ME_TextEditor *editor, int x) static BOOL ME_SetCursor(ME_TextEditor *editor, int x)
{ {
if ((GetWindowLongW(editor->hWnd, GWL_STYLE) & ES_SELECTIONBAR) && if ((GetWindowLongW(editor->hWnd, GWL_STYLE) & ES_SELECTIONBAR) &&
(x < editor->selofs || editor->linesel)) (x < editor->selofs ||
(editor->nSelectionType == stLine && GetCapture() == editor->hWnd)))
{ {
SetCursor(hLeft); SetCursor(hLeft);
return TRUE; return TRUE;
...@@ -1654,6 +1658,12 @@ ME_TextEditor *ME_MakeEditor(HWND hWnd) { ...@@ -1654,6 +1658,12 @@ ME_TextEditor *ME_MakeEditor(HWND hWnd) {
ed->nZoomNumerator = ed->nZoomDenominator = 0; ed->nZoomNumerator = ed->nZoomDenominator = 0;
ME_MakeFirstParagraph(ed); ME_MakeFirstParagraph(ed);
ed->bCaretShown = FALSE; 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->nCursors = 4;
ed->pCursors = ALLOC_N_OBJ(ME_Cursor, ed->nCursors); ed->pCursors = ALLOC_N_OBJ(ME_Cursor, ed->nCursors);
ed->pCursors[0].pRun = ME_FindItemFwd(ed->pBuffer->pFirst, diRun); ed->pCursors[0].pRun = ME_FindItemFwd(ed->pBuffer->pFirst, diRun);
...@@ -1700,7 +1710,7 @@ ME_TextEditor *ME_MakeEditor(HWND hWnd) { ...@@ -1700,7 +1710,7 @@ ME_TextEditor *ME_MakeEditor(HWND hWnd) {
ed->selofs = SELECTIONBAR_WIDTH; ed->selofs = SELECTIONBAR_WIDTH;
else else
ed->selofs = 0; ed->selofs = 0;
ed->linesel = 0; ed->nSelectionType = stPosition;
if (GetWindowLongW(hWnd, GWL_STYLE) & ES_PASSWORD) if (GetWindowLongW(hWnd, GWL_STYLE) & ES_PASSWORD)
ed->cPasswordMask = '*'; ed->cPasswordMask = '*';
...@@ -3000,7 +3010,6 @@ static LRESULT RichEditWndProc_common(HWND hWnd, UINT msg, WPARAM wParam, ...@@ -3000,7 +3010,6 @@ static LRESULT RichEditWndProc_common(HWND hWnd, UINT msg, WPARAM wParam,
else else
{ {
BOOL ret; BOOL ret;
editor->linesel = 0;
ret = ME_SetCursor(editor, LOWORD(lParam)); ret = ME_SetCursor(editor, LOWORD(lParam));
ME_LinkNotify(editor,msg,wParam,lParam); ME_LinkNotify(editor,msg,wParam,lParam);
if (!ret) goto do_default; if (!ret) goto do_default;
......
...@@ -244,6 +244,12 @@ typedef enum { ...@@ -244,6 +244,12 @@ typedef enum {
umAddBackToUndo umAddBackToUndo
} ME_UndoMode; } ME_UndoMode;
typedef enum {
stPosition = 0,
stWord,
stLine
} ME_SelectionType;
typedef struct tagME_FontTableItem { typedef struct tagME_FontTableItem {
BYTE bCharSet; BYTE bCharSet;
WCHAR *szFaceName; WCHAR *szFaceName;
...@@ -333,7 +339,8 @@ typedef struct tagME_TextEditor ...@@ -333,7 +339,8 @@ typedef struct tagME_TextEditor
BOOL bHaveFocus; BOOL bHaveFocus;
/*for IME */ /*for IME */
int imeStartIndex; 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 */ /* Track previous notified selection */
CHARRANGE notified_cr; 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