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.
This commit is contained in:
Dylan Smith 2008-07-07 11:03:53 -04:00 committed by Alexandre Julliard
parent 8a3f21f0b1
commit abefc28fe7
3 changed files with 128 additions and 58 deletions

View File

@ -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)
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);
if (x >= editor->selofs || GetKeyState(VK_SHIFT) < 0)
{ {
ME_FindPixelPos(editor, x, y, &editor->pCursors[0], &editor->bCaretAtEnd); if (clickNum > 1)
if (GetKeyState(VK_SHIFT)>=0)
{ {
/* Shift key is not down */ editor->nSelectionType = stWord;
editor->pCursors[1] = editor->pCursors[0]; 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; 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)
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;
editor->pCursors[0] = tmp_cursor; ME_ExtendAnchorSelection(editor);
else if (!memcmp(&tmp_cursor, editor->pCursors+2, sizeof(tmp_cursor)) ||
!memcmp(&tmp_cursor, editor->pCursors+3, sizeof(tmp_cursor))) if (editor->nSelectionType != stPosition &&
memcmp(&editor->pCursors[1], &editor->pCursors[3], sizeof(ME_Cursor)))
{ {
editor->pCursors[0] = editor->pCursors[2]; /* The scroll the cursor towards the other end, since it was the one
editor->pCursors[1] = editor->pCursors[3]; * extended by ME_ExtendAnchorSelection
} */
else if (y < editor->sely) ME_Cursor tmpCursor = editor->pCursors[0];
{ editor->pCursors[0] = editor->pCursors[1];
editor->pCursors[0] = tmp_cursor; editor->pCursors[1] = tmpCursor;
editor->pCursors[1] = editor->pCursors[2]; SendMessageW(editor->hWnd, EM_SCROLLCARET, 0, 0);
} editor->pCursors[1] = editor->pCursors[0];
else editor->pCursors[0] = tmpCursor;
{ } else {
editor->pCursors[0] = tmp_cursor; SendMessageW(editor->hWnd, EM_SCROLLCARET, 0, 0);
editor->pCursors[1] = editor->pCursors[3];
} }
HideCaret(editor->hWnd); HideCaret(editor->hWnd);
@ -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,

View File

@ -1537,7 +1537,10 @@ 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)
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) {
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) {
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,
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;

View File

@ -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
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;