mirror of
https://github.com/reactos/reactos.git
synced 2024-11-24 12:03:31 +08:00
[COMCTL32][SHELL32] Fix arrow keys and reordering on ListView (#3162)
- Disable special auto-arrange codes in LISTVIEW_GetNextItem function. - Add auto-arrange reordering codes on CDefView. CORE-16875
This commit is contained in:
parent
0f66c66f72
commit
8c87489a43
@ -7449,7 +7449,9 @@ static INT LISTVIEW_GetNextItem(const LISTVIEW_INFO *infoPtr, INT nItem, UINT uF
|
||||
UINT uMask = 0;
|
||||
LVFINDINFOW lvFindInfo;
|
||||
INT nCountPerColumn;
|
||||
#ifndef __REACTOS__
|
||||
INT nCountPerRow;
|
||||
#endif
|
||||
INT i;
|
||||
|
||||
TRACE("nItem=%d, uFlags=%x, nItemCount=%d\n", nItem, uFlags, infoPtr->nItemCount);
|
||||
@ -7490,6 +7492,7 @@ static INT LISTVIEW_GetNextItem(const LISTVIEW_INFO *infoPtr, INT nItem, UINT uF
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifndef __REACTOS__
|
||||
/* Special case for autoarrange - move 'til the top of a list */
|
||||
if (is_autoarrange(infoPtr))
|
||||
{
|
||||
@ -7502,6 +7505,7 @@ static INT LISTVIEW_GetNextItem(const LISTVIEW_INFO *infoPtr, INT nItem, UINT uF
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
lvFindInfo.flags = LVFI_NEARESTXY;
|
||||
lvFindInfo.vkDirection = VK_UP;
|
||||
LISTVIEW_GetItemPosition(infoPtr, nItem, &lvFindInfo.pt);
|
||||
@ -7525,6 +7529,7 @@ static INT LISTVIEW_GetNextItem(const LISTVIEW_INFO *infoPtr, INT nItem, UINT uF
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifndef __REACTOS__
|
||||
/* Special case for autoarrange - move 'til the bottom of a list */
|
||||
if (is_autoarrange(infoPtr))
|
||||
{
|
||||
@ -7537,6 +7542,7 @@ static INT LISTVIEW_GetNextItem(const LISTVIEW_INFO *infoPtr, INT nItem, UINT uF
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
lvFindInfo.flags = LVFI_NEARESTXY;
|
||||
lvFindInfo.vkDirection = VK_DOWN;
|
||||
LISTVIEW_GetItemPosition(infoPtr, nItem, &lvFindInfo.pt);
|
||||
@ -7561,6 +7567,7 @@ static INT LISTVIEW_GetNextItem(const LISTVIEW_INFO *infoPtr, INT nItem, UINT uF
|
||||
}
|
||||
else if ((infoPtr->uView == LV_VIEW_SMALLICON) || (infoPtr->uView == LV_VIEW_ICON))
|
||||
{
|
||||
#ifndef __REACTOS__
|
||||
/* Special case for autoarrange - move 'til the beginning of a row */
|
||||
if (is_autoarrange(infoPtr))
|
||||
{
|
||||
@ -7573,6 +7580,7 @@ static INT LISTVIEW_GetNextItem(const LISTVIEW_INFO *infoPtr, INT nItem, UINT uF
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
lvFindInfo.flags = LVFI_NEARESTXY;
|
||||
lvFindInfo.vkDirection = VK_LEFT;
|
||||
LISTVIEW_GetItemPosition(infoPtr, nItem, &lvFindInfo.pt);
|
||||
@ -7597,6 +7605,7 @@ static INT LISTVIEW_GetNextItem(const LISTVIEW_INFO *infoPtr, INT nItem, UINT uF
|
||||
}
|
||||
else if ((infoPtr->uView == LV_VIEW_SMALLICON) || (infoPtr->uView == LV_VIEW_ICON))
|
||||
{
|
||||
#ifndef __REACTOS__
|
||||
/* Special case for autoarrange - move 'til the end of a row */
|
||||
if (is_autoarrange(infoPtr))
|
||||
{
|
||||
@ -7609,6 +7618,7 @@ static INT LISTVIEW_GetNextItem(const LISTVIEW_INFO *infoPtr, INT nItem, UINT uF
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
lvFindInfo.flags = LVFI_NEARESTXY;
|
||||
lvFindInfo.vkDirection = VK_RIGHT;
|
||||
LISTVIEW_GetItemPosition(infoPtr, nItem, &lvFindInfo.pt);
|
||||
|
@ -57,6 +57,20 @@ typedef struct
|
||||
to call TrackPopupMenu and let it use the 0 value as an indication that the menu was canceled */
|
||||
#define CONTEXT_MENU_BASE_ID 1
|
||||
|
||||
/* Convert client coordinates to listview coordinates */
|
||||
static void
|
||||
ClientToListView(HWND hwndLV, POINT *ppt)
|
||||
{
|
||||
POINT Origin;
|
||||
|
||||
/* FIXME: LVM_GETORIGIN is broken. See CORE-17266 */
|
||||
if (!ListView_GetOrigin(hwndLV, &Origin))
|
||||
return;
|
||||
|
||||
ppt->x += Origin.x;
|
||||
ppt->y += Origin.y;
|
||||
}
|
||||
|
||||
class CDefView :
|
||||
public CWindowImpl<CDefView, CWindow, CControlWinTraits>,
|
||||
public CComObjectRootEx<CComMultiThreadModelNoCS>,
|
||||
@ -117,6 +131,8 @@ class CDefView :
|
||||
BOOL _Sort();
|
||||
HRESULT _DoFolderViewCB(UINT uMsg, WPARAM wParam, LPARAM lParam);
|
||||
HRESULT _GetSnapToGrid();
|
||||
void _MoveSelectionOnAutoArrange(POINT pt);
|
||||
INT _FindInsertableIndexFromPoint(POINT pt);
|
||||
|
||||
public:
|
||||
CDefView();
|
||||
@ -2019,6 +2035,7 @@ LRESULT CDefView::OnNotify(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandl
|
||||
m_pSourceDataObject = pda;
|
||||
m_ptFirstMousePos = params->ptAction;
|
||||
ClientToScreen(&m_ptFirstMousePos);
|
||||
::ClientToListView(m_ListView, &m_ptFirstMousePos);
|
||||
|
||||
HIMAGELIST big_icons, small_icons;
|
||||
Shell_GetImageLists(&big_icons, &small_icons);
|
||||
@ -3263,6 +3280,7 @@ HRESULT CDefView::drag_notify_subitem(DWORD grfKeyState, POINTL pt, DWORD *pdwEf
|
||||
}
|
||||
|
||||
m_ptLastMousePos = htinfo.pt;
|
||||
::ClientToListView(m_ListView, &m_ptLastMousePos);
|
||||
|
||||
/* We need to check if we drag the selection over itself */
|
||||
if (lResult != -1 && m_pSourceDataObject.p != NULL)
|
||||
@ -3378,6 +3396,150 @@ HRESULT WINAPI CDefView::DragLeave()
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
INT CDefView::_FindInsertableIndexFromPoint(POINT pt)
|
||||
{
|
||||
RECT rcBound;
|
||||
INT i, nCount = m_ListView.GetItemCount();
|
||||
DWORD dwSpacing;
|
||||
INT dx, dy;
|
||||
BOOL bSmall = ((m_ListView.GetStyle() & LVS_TYPEMASK) != LVS_ICON);
|
||||
|
||||
/* FIXME: LVM_GETORIGIN is broken. See CORE-17266 */
|
||||
pt.x += m_ListView.GetScrollPos(SB_HORZ);
|
||||
pt.y += m_ListView.GetScrollPos(SB_VERT);
|
||||
|
||||
if (m_ListView.GetStyle() & LVS_ALIGNLEFT)
|
||||
{
|
||||
// vertically
|
||||
for (i = 0; i < nCount; ++i)
|
||||
{
|
||||
dwSpacing = ListView_GetItemSpacing(m_ListView, bSmall);
|
||||
dx = LOWORD(dwSpacing);
|
||||
dy = HIWORD(dwSpacing);
|
||||
ListView_GetItemRect(m_ListView, i, &rcBound, LVIR_SELECTBOUNDS);
|
||||
rcBound.right = rcBound.left + dx;
|
||||
rcBound.bottom = rcBound.top + dy;
|
||||
if (pt.x < rcBound.right && pt.y < (rcBound.top + rcBound.bottom) / 2)
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
for (i = nCount - 1; i >= 0; --i)
|
||||
{
|
||||
ListView_GetItemRect(m_ListView, i, &rcBound, LVIR_SELECTBOUNDS);
|
||||
if (rcBound.left < pt.x && rcBound.top < pt.y)
|
||||
{
|
||||
return i + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// horizontally
|
||||
for (i = 0; i < nCount; ++i)
|
||||
{
|
||||
dwSpacing = ListView_GetItemSpacing(m_ListView, bSmall);
|
||||
dx = LOWORD(dwSpacing);
|
||||
dy = HIWORD(dwSpacing);
|
||||
ListView_GetItemRect(m_ListView, i, &rcBound, LVIR_SELECTBOUNDS);
|
||||
rcBound.right = rcBound.left + dx;
|
||||
rcBound.bottom = rcBound.top + dy;
|
||||
if (pt.y < rcBound.bottom && pt.x < rcBound.left)
|
||||
{
|
||||
return i;
|
||||
}
|
||||
if (pt.y < rcBound.bottom && pt.x < rcBound.right)
|
||||
{
|
||||
return i + 1;
|
||||
}
|
||||
}
|
||||
for (i = nCount - 1; i >= 0; --i)
|
||||
{
|
||||
ListView_GetItemRect(m_ListView, i, &rcBound, LVIR_SELECTBOUNDS);
|
||||
if (rcBound.left < pt.x && rcBound.top < pt.y)
|
||||
{
|
||||
return i + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nCount;
|
||||
}
|
||||
|
||||
typedef CSimpleMap<LPARAM, INT> CLParamIndexMap;
|
||||
|
||||
static INT CALLBACK
|
||||
SelectionMoveCompareFunc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)
|
||||
{
|
||||
CLParamIndexMap *pmap = (CLParamIndexMap *)lParamSort;
|
||||
INT i1 = pmap->Lookup(lParam1), i2 = pmap->Lookup(lParam2);
|
||||
if (i1 < i2)
|
||||
return -1;
|
||||
if (i1 > i2)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void CDefView::_MoveSelectionOnAutoArrange(POINT pt)
|
||||
{
|
||||
// get insertable index from position
|
||||
INT iPosition = _FindInsertableIndexFromPoint(pt);
|
||||
|
||||
// create identity mapping of indexes
|
||||
CSimpleArray<INT> array;
|
||||
INT nCount = m_ListView.GetItemCount();
|
||||
for (INT i = 0; i < nCount; ++i)
|
||||
{
|
||||
array.Add(i);
|
||||
}
|
||||
|
||||
// re-ordering mapping
|
||||
INT iItem = -1;
|
||||
while ((iItem = m_ListView.GetNextItem(iItem, LVNI_SELECTED)) >= 0)
|
||||
{
|
||||
INT iFrom = iItem, iTo = iPosition;
|
||||
if (iFrom < iTo)
|
||||
--iTo;
|
||||
if (iFrom >= nCount)
|
||||
iFrom = nCount - 1;
|
||||
if (iTo >= nCount)
|
||||
iTo = nCount - 1;
|
||||
|
||||
// shift indexes by swapping (like a bucket relay)
|
||||
if (iFrom < iTo)
|
||||
{
|
||||
for (INT i = iFrom; i < iTo; ++i)
|
||||
{
|
||||
// swap array[i] and array[i + 1]
|
||||
INT tmp = array[i];
|
||||
array[i] = array[i + 1];
|
||||
array[i + 1] = tmp;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (INT i = iFrom; i > iTo; --i)
|
||||
{
|
||||
// swap array[i] and array[i - 1]
|
||||
INT tmp = array[i];
|
||||
array[i] = array[i - 1];
|
||||
array[i - 1] = tmp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// create mapping (ListView's lParam to index) from array
|
||||
CLParamIndexMap map;
|
||||
for (INT i = 0; i < nCount; ++i)
|
||||
{
|
||||
LPARAM lParam = m_ListView.GetItemData(array[i]);
|
||||
map.Add(lParam, i);
|
||||
}
|
||||
|
||||
// finally sort
|
||||
m_ListView.SortItems(SelectionMoveCompareFunc, &map);
|
||||
}
|
||||
|
||||
HRESULT WINAPI CDefView::Drop(IDataObject* pDataObject, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect)
|
||||
{
|
||||
ImageList_DragLeave(m_hWnd);
|
||||
@ -3393,23 +3555,31 @@ HRESULT WINAPI CDefView::Drop(IDataObject* pDataObject, DWORD grfKeyState, POINT
|
||||
m_pCurDropTarget.Release();
|
||||
}
|
||||
|
||||
/* Restore the selection */
|
||||
m_ListView.SetItemState(-1, 0, LVIS_SELECTED);
|
||||
for (UINT i = 0 ; i < m_cidl; i++)
|
||||
SelectItem(m_apidl[i], SVSI_SELECT);
|
||||
POINT ptDrop = { pt.x, pt.y };
|
||||
::ScreenToClient(m_ListView, &ptDrop);
|
||||
::ClientToListView(m_ListView, &ptDrop);
|
||||
m_ptLastMousePos = ptDrop;
|
||||
|
||||
/* Reposition the items */
|
||||
int lvIndex = -1;
|
||||
while ((lvIndex = m_ListView.GetNextItem(lvIndex, LVNI_SELECTED)) > -1)
|
||||
m_ListView.SetRedraw(FALSE);
|
||||
if (m_ListView.GetStyle() & LVS_AUTOARRANGE)
|
||||
{
|
||||
_MoveSelectionOnAutoArrange(m_ptLastMousePos);
|
||||
}
|
||||
else
|
||||
{
|
||||
POINT ptItem;
|
||||
if (m_ListView.GetItemPosition(lvIndex, &ptItem))
|
||||
INT iItem = -1;
|
||||
while ((iItem = m_ListView.GetNextItem(iItem, LVNI_SELECTED)) >= 0)
|
||||
{
|
||||
ptItem.x += pt.x - m_ptFirstMousePos.x;
|
||||
ptItem.y += pt.y - m_ptFirstMousePos.y;
|
||||
m_ListView.SetItemPosition(lvIndex, &ptItem);
|
||||
if (m_ListView.GetItemPosition(iItem, &ptItem))
|
||||
{
|
||||
ptItem.x += m_ptLastMousePos.x - m_ptFirstMousePos.x;
|
||||
ptItem.y += m_ptLastMousePos.y - m_ptFirstMousePos.y;
|
||||
m_ListView.SetItemPosition(iItem, &ptItem);
|
||||
}
|
||||
}
|
||||
}
|
||||
m_ListView.SetRedraw(TRUE);
|
||||
}
|
||||
else if (m_pCurDropTarget)
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user