Add very basic dragging support to the monitor selection control

svn path=/trunk/; revision=29665
This commit is contained in:
Thomas Bluemel 2007-10-18 22:59:33 +00:00
parent cabbd02835
commit 36f1aa644b

View file

@ -27,11 +27,17 @@ typedef struct _MONITORSELWND
UINT Enabled : 1;
UINT HasFocus : 1;
UINT CanDisplay : 1;
UINT LeftBtnDown : 1;
UINT IsDraggingMonitor : 1;
};
};
DWORD ControlExStyle;
DWORD MonitorsCount;
INT SelectedMonitor;
INT DraggingMonitor;
RECT rcDragging;
POINT ptDrag, ptDragBegin;
SIZE DraggingMargin;
PMONSL_MONINFO MonitorInfo;
PMONSL_MON Monitors;
RECT rcExtent;
@ -265,15 +271,34 @@ MonSelRepaintMonitor(IN PMONITORSELWND infoPtr,
IN DWORD Index)
{
RECT rc;
BOOL NoRepaint = FALSE;
if (Index < infoPtr->MonitorsCount)
{
MonSelRectToScreen(infoPtr,
&infoPtr->Monitors[Index].rc,
&rc);
InvalidateRect(infoPtr->hSelf,
&rc,
TRUE);
if (Index == (DWORD)infoPtr->DraggingMonitor)
{
if (infoPtr->IsDraggingMonitor)
{
MonSelRectToScreen(infoPtr,
&infoPtr->rcDragging,
&rc);
}
else
NoRepaint = TRUE;
}
else
{
MonSelRectToScreen(infoPtr,
&infoPtr->Monitors[Index].rc,
&rc);
}
if (!NoRepaint)
{
InvalidateRect(infoPtr->hSelf,
&rc,
TRUE);
}
}
}
@ -370,6 +395,9 @@ MonSelSetMonitorsInfo(IN OUT PMONITORSELWND infoPtr,
DWORD Index;
BOOL Ret = TRUE;
if (infoPtr->DraggingMonitor >= 0)
return FALSE;
if (infoPtr->MonitorInfo != NULL)
{
LocalFree((HLOCAL)infoPtr->MonitorInfo);
@ -466,7 +494,8 @@ MonSelSetMonitorInfo(IN OUT PMONITORSELWND infoPtr,
IN INT Index,
IN const MONSL_MONINFO *MonitorsInfo)
{
if (Index >= 0 && Index < (INT)infoPtr->MonitorsCount)
if (infoPtr->DraggingMonitor < 0 &&
Index >= 0 && Index < (INT)infoPtr->MonitorsCount)
{
CopyMemory(&infoPtr->MonitorInfo[Index],
MonitorsInfo,
@ -531,7 +560,8 @@ MonSelSetCurSelMonitor(IN OUT PMONITORSELWND infoPtr,
BOOL PreventSelect = FALSE;
BOOL Ret = FALSE;
if (Index == -1 || Index < (INT)infoPtr->MonitorsCount)
if (infoPtr->DraggingMonitor < 0 &&
(Index == -1 || Index < (INT)infoPtr->MonitorsCount))
{
if (Index != infoPtr->SelectedMonitor)
{
@ -594,6 +624,7 @@ MonSelCreate(IN OUT PMONITORSELWND infoPtr)
infoPtr->SelectionFrame.cx = infoPtr->SelectionFrame.cy = 4;
infoPtr->Margin.cx = infoPtr->Margin.cy = 20;
infoPtr->SelectedMonitor = -1;
infoPtr->DraggingMonitor = -1;
infoPtr->ControlExStyle = MSLM_EX_ALLOWSELECTDISABLED | MSLM_EX_HIDENUMBERONSINGLE |
MSLM_EX_SELECTONRIGHTCLICK;
return;
@ -624,6 +655,9 @@ static BOOL
MonSelSetExtendedStyle(IN OUT PMONITORSELWND infoPtr,
IN DWORD dwExtendedStyle)
{
if (infoPtr->DraggingMonitor >= 0)
return FALSE;
if (dwExtendedStyle != infoPtr->ControlExStyle)
{
infoPtr->ControlExStyle = dwExtendedStyle;
@ -724,13 +758,92 @@ MonSelDrawDisabledRect(IN OUT PMONITORSELWND infoPtr,
return Ret;
}
static VOID
MonSelPaintMonitor(IN OUT PMONITORSELWND infoPtr,
IN HDC hDC,
IN DWORD Index,
IN OUT PRECT prc,
IN COLORREF crDefFontColor,
IN BOOL bHideNumber)
{
HFONT hFont, hPrevFont;
COLORREF crPrevText;
if ((INT)Index == infoPtr->SelectedMonitor)
{
FillRect(hDC,
prc,
(HBRUSH)(COLOR_HIGHLIGHT + 1));
if (infoPtr->HasFocus && !(infoPtr->UIState & UISF_HIDEFOCUS))
{
/* NOTE: We need to switch the text color to the default, because
DrawFocusRect draws a solid line if the text is white! */
crPrevText = SetTextColor(hDC,
crDefFontColor);
DrawFocusRect(hDC,
prc);
SetTextColor(hDC,
crPrevText);
}
}
InflateRect(prc,
-infoPtr->SelectionFrame.cx,
-infoPtr->SelectionFrame.cy);
Rectangle(hDC,
prc->left,
prc->top,
prc->right,
prc->bottom);
InflateRect(prc,
-1,
-1);
if (!bHideNumber)
{
hFont = MonSelGetMonitorFont(infoPtr,
hDC,
Index);
if (hFont != NULL)
{
hPrevFont = SelectObject(hDC,
hFont);
DrawText(hDC,
infoPtr->Monitors[Index].szCaption,
-1,
prc,
DT_VCENTER | DT_CENTER | DT_NOPREFIX | DT_SINGLELINE);
SelectObject(hDC,
hPrevFont);
}
}
if (infoPtr->MonitorInfo[Index].Flags & MSL_MIF_DISABLED)
{
InflateRect(prc,
1,
1);
MonSelDrawDisabledRect(infoPtr,
hDC,
prc);
}
}
static VOID
MonSelPaint(IN OUT PMONITORSELWND infoPtr,
IN HDC hDC,
IN const RECT *prcUpdate)
{
COLORREF crPrevText, crPrevText2;
HFONT hFont, hPrevFont;
COLORREF crPrevText;
HBRUSH hbBk, hbOldBk;
HPEN hpFg, hpOldFg;
DWORD Index;
@ -757,83 +870,47 @@ MonSelPaint(IN OUT PMONITORSELWND infoPtr,
for (Index = 0; Index < infoPtr->MonitorsCount; Index++)
{
MonSelRectToScreen(infoPtr,
&infoPtr->Monitors[Index].rc,
&rc);
if (!IntersectRect(&rctmp,
&rc,
prcUpdate))
if (infoPtr->IsDraggingMonitor &&
(DWORD)infoPtr->DraggingMonitor == Index)
{
continue;
}
if ((INT)Index == infoPtr->SelectedMonitor)
MonSelRectToScreen(infoPtr,
&infoPtr->Monitors[Index].rc,
&rc);
if (IntersectRect(&rctmp,
&rc,
prcUpdate))
{
FillRect(hDC,
&rc,
(HBRUSH)(COLOR_HIGHLIGHT + 1));
if (infoPtr->HasFocus && !(infoPtr->UIState & UISF_HIDEFOCUS))
{
/* NOTE: We need to switch the text color to the default, because
DrawFocusRect draws a solid line if the text is white! */
crPrevText2 = SetTextColor(hDC,
crPrevText);
DrawFocusRect(hDC,
&rc);
SetTextColor(hDC,
crPrevText2);
}
MonSelPaintMonitor(infoPtr,
hDC,
Index,
&rc,
crPrevText,
bHideNumber);
}
}
InflateRect(&rc,
-infoPtr->SelectionFrame.cx,
-infoPtr->SelectionFrame.cy);
/* Paint the dragging monitor last */
if (infoPtr->IsDraggingMonitor &&
(DWORD)infoPtr->DraggingMonitor >= 0)
{
MonSelRectToScreen(infoPtr,
&infoPtr->rcDragging,
&rc);
Rectangle(hDC,
rc.left,
rc.top,
rc.right,
rc.bottom);
InflateRect(&rc,
-1,
-1);
if (!bHideNumber)
if (IntersectRect(&rctmp,
&rc,
prcUpdate))
{
hFont = MonSelGetMonitorFont(infoPtr,
hDC,
Index);
if (hFont != NULL)
{
hPrevFont = SelectObject(hDC,
hFont);
DrawText(hDC,
infoPtr->Monitors[Index].szCaption,
-1,
&rc,
DT_VCENTER | DT_CENTER | DT_NOPREFIX | DT_SINGLELINE);
SelectObject(hDC,
hPrevFont);
}
}
if (infoPtr->MonitorInfo[Index].Flags & MSL_MIF_DISABLED)
{
InflateRect(&rc,
1,
1);
MonSelDrawDisabledRect(infoPtr,
hDC,
&rc);
MonSelPaintMonitor(infoPtr,
hDC,
(DWORD)infoPtr->DraggingMonitor,
&rc,
crPrevText,
bHideNumber);
}
}
@ -882,6 +959,202 @@ MonSelContextMenu(IN OUT PMONITORSELWND infoPtr,
nm.pt.y));
}
static VOID
MonSelApplyCursorClipping(IN PMONITORSELWND infoPtr,
IN BOOL bClip)
{
RECT rc;
if (bClip)
{
rc.left = rc.top = 0;
rc.right = infoPtr->ClientSize.cx;
rc.bottom = infoPtr->ClientSize.cy;
if (MapWindowPoints(infoPtr->hSelf,
NULL,
(LPPOINT)&rc,
2))
{
ClipCursor(&rc);
}
}
else
{
ClipCursor(NULL);
}
}
static VOID
MonSelMoveDragRect(IN OUT PMONITORSELWND infoPtr,
IN PPOINT ppt)
{
RECT rcPrev, rcUpdate, *prc;
HRGN hRgnPrev;
HDC hDC;
if (infoPtr->CanDisplay)
{
hDC = GetDC(infoPtr->hSelf);
if (hDC != NULL)
{
if (infoPtr->ptDrag.x != ppt->x ||
infoPtr->ptDrag.y != ppt->y)
{
infoPtr->ptDrag = *ppt;
rcPrev = infoPtr->rcDragging;
/* Calculate updated dragging rectangle */
prc = &infoPtr->Monitors[infoPtr->DraggingMonitor].rc;
infoPtr->rcDragging.left = ppt->x - infoPtr->DraggingMargin.cx;
infoPtr->rcDragging.top = ppt->y - infoPtr->DraggingMargin.cy;
infoPtr->rcDragging.right = infoPtr->rcDragging.left + (prc->right - prc->left);
infoPtr->rcDragging.bottom = infoPtr->rcDragging.top + (prc->bottom - prc->top);
hRgnPrev = CreateRectRgn(rcPrev.left,
rcPrev.top,
rcPrev.right,
rcPrev.bottom);
if (hRgnPrev != NULL)
{
if (!ScrollDC(hDC,
infoPtr->rcDragging.left - rcPrev.left,
infoPtr->rcDragging.top - rcPrev.top,
&rcPrev,
NULL,
hRgnPrev,
&rcUpdate) ||
!InvalidateRgn(infoPtr->hSelf,
hRgnPrev,
TRUE))
{
DeleteObject(hRgnPrev);
goto InvRects;
}
DeleteObject(hRgnPrev);
}
else
{
InvRects:
InvalidateRect(infoPtr->hSelf,
&rcPrev,
TRUE);
InvalidateRect(infoPtr->hSelf,
&infoPtr->rcDragging,
TRUE);
}
}
ReleaseDC(infoPtr->hSelf,
hDC);
}
}
}
static VOID
MonSelCancelDragging(IN OUT PMONITORSELWND infoPtr)
{
DWORD Index;
if (infoPtr->DraggingMonitor >= 0)
{
MonSelMoveDragRect(infoPtr,
&infoPtr->ptDragBegin);
Index = (DWORD)infoPtr->DraggingMonitor;
infoPtr->DraggingMonitor = -1;
if (infoPtr->CanDisplay)
{
/* Repaint the area where the monitor was last dragged */
MonSelRepaintMonitor(infoPtr,
Index);
infoPtr->IsDraggingMonitor = FALSE;
/* Repaint the area where the monitor is located */
MonSelRepaintMonitor(infoPtr,
Index);
}
else
infoPtr->IsDraggingMonitor = FALSE;
ReleaseCapture();
MonSelApplyCursorClipping(infoPtr,
FALSE);
}
}
static VOID
MonSelInitDragging(IN OUT PMONITORSELWND infoPtr,
IN DWORD Index,
IN PPOINT ppt)
{
POINT pt;
MonSelCancelDragging(infoPtr);
infoPtr->IsDraggingMonitor = FALSE;
MonSelScreenToPt(infoPtr,
ppt,
&pt);
infoPtr->ptDrag = infoPtr->ptDragBegin = pt;
infoPtr->DraggingMonitor = (INT)Index;
infoPtr->DraggingMargin.cx = ppt->x - infoPtr->Monitors[Index].rc.left;
infoPtr->DraggingMargin.cy = ppt->y - infoPtr->Monitors[Index].rc.top;
infoPtr->rcDragging = infoPtr->Monitors[Index].rc;
MonSelApplyCursorClipping(infoPtr,
TRUE);
}
static VOID
MonSelDrag(IN OUT PMONITORSELWND infoPtr,
IN PPOINT ppt)
{
SIZE szDrag;
POINT pt;
RECT rcDrag;
if (infoPtr->DraggingMonitor >= 0)
{
MonSelScreenToPt(infoPtr,
ppt,
&pt);
if (!infoPtr->IsDraggingMonitor)
{
szDrag.cx = GetSystemMetrics(SM_CXDRAG);
szDrag.cy = GetSystemMetrics(SM_CYDRAG);
rcDrag.left = infoPtr->Monitors[infoPtr->DraggingMonitor].rc.left + infoPtr->DraggingMargin.cx - (szDrag.cx / 2);
rcDrag.top = infoPtr->Monitors[infoPtr->DraggingMonitor].rc.top + infoPtr->DraggingMargin.cy - (szDrag.cy / 2);
rcDrag.right = rcDrag.left + szDrag.cx;
rcDrag.bottom = rcDrag.top + szDrag.cy;
if (!PtInRect(&rcDrag,
pt))
{
/* The user started moving around the mouse: Begin dragging */
infoPtr->IsDraggingMonitor = TRUE;
MonSelMoveDragRect(infoPtr,
&pt);
}
}
else
{
MonSelMoveDragRect(infoPtr,
&pt);
}
}
}
static LRESULT CALLBACK
MonitorSelWndProc(IN HWND hwnd,
IN UINT uMsg,
@ -942,6 +1215,28 @@ MonitorSelWndProc(IN HWND hwnd,
break;
}
case WM_MOUSEMOVE:
{
POINT pt;
if (!(wParam & MK_LBUTTON))
{
MonSelCancelDragging(infoPtr);
break;
}
if (infoPtr->LeftBtnDown)
{
pt.x = (LONG)LOWORD(lParam);
pt.y = (LONG)HIWORD(lParam);
MonSelDrag(infoPtr,
&pt);
}
break;
}
case WM_RBUTTONDOWN:
{
if (!(infoPtr->ControlExStyle & MSLM_EX_SELECTONRIGHTCLICK))
@ -968,6 +1263,14 @@ MonitorSelWndProc(IN HWND hwnd,
TRUE);
}
if (Index >= 0 && (uMsg == WM_LBUTTONDOWN || uMsg == WM_LBUTTONDBLCLK))
{
infoPtr->LeftBtnDown = TRUE;
MonSelInitDragging(infoPtr,
(DWORD)Index,
&pt);
}
/* fall through */
}
@ -986,6 +1289,13 @@ MonitorSelWndProc(IN HWND hwnd,
break;
}
case WM_LBUTTONUP:
{
MonSelCancelDragging(infoPtr);
infoPtr->LeftBtnDown = FALSE;
break;
}
case WM_GETDLGCODE:
{
INT virtKey;
@ -1020,6 +1330,7 @@ MonitorSelWndProc(IN HWND hwnd,
case WM_KILLFOCUS:
{
infoPtr->HasFocus = FALSE;
MonSelCancelDragging(infoPtr);
MonSelRepaintSelected(infoPtr);
break;
}