Author: weiden Date: Fri Oct 19 02:59:33 2007 New Revision: 29665
URL: http://svn.reactos.org/svn/reactos?rev=29665&view=rev Log: Add very basic dragging support to the monitor selection control
Modified: trunk/reactos/dll/cpl/desk/monslctl.c
Modified: trunk/reactos/dll/cpl/desk/monslctl.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/dll/cpl/desk/monslctl.c?rev... ============================================================================== --- trunk/reactos/dll/cpl/desk/monslctl.c (original) +++ trunk/reactos/dll/cpl/desk/monslctl.c Fri Oct 19 02:59:33 2007 @@ -27,11 +27,17 @@ 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 @@ 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); + } } }
@@ -369,6 +394,9 @@ { DWORD Index; BOOL Ret = TRUE; + + if (infoPtr->DraggingMonitor >= 0) + return FALSE;
if (infoPtr->MonitorInfo != NULL) { @@ -466,7 +494,8 @@ 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 @@ 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 @@ 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 @@ MonSelSetExtendedStyle(IN OUT PMONITORSELWND infoPtr, IN DWORD dwExtendedStyle) { + if (infoPtr->DraggingMonitor >= 0) + return FALSE; + if (dwExtendedStyle != infoPtr->ControlExStyle) { infoPtr->ControlExStyle = dwExtendedStyle; @@ -725,12 +759,91 @@ }
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 @@
for (Index = 0; Index < infoPtr->MonitorsCount; Index++) { + if (infoPtr->IsDraggingMonitor && + (DWORD)infoPtr->DraggingMonitor == Index) + { + continue; + } + MonSelRectToScreen(infoPtr, &infoPtr->Monitors[Index].rc, &rc);
- if (!IntersectRect(&rctmp, - &rc, - prcUpdate)) - { - continue; - } - - if ((INT)Index == infoPtr->SelectedMonitor) - { - 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); - } - } - - InflateRect(&rc, - -infoPtr->SelectionFrame.cx, - -infoPtr->SelectionFrame.cy); - - Rectangle(hDC, - rc.left, - rc.top, - rc.right, - rc.bottom); - - InflateRect(&rc, - -1, - -1); - - if (!bHideNumber) - { - 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); + if (IntersectRect(&rctmp, + &rc, + prcUpdate)) + { + MonSelPaintMonitor(infoPtr, + hDC, + Index, + &rc, + crPrevText, + bHideNumber); + } + } + + /* Paint the dragging monitor last */ + if (infoPtr->IsDraggingMonitor && + (DWORD)infoPtr->DraggingMonitor >= 0) + { + MonSelRectToScreen(infoPtr, + &infoPtr->rcDragging, + &rc); + + if (IntersectRect(&rctmp, + &rc, + prcUpdate)) + { + MonSelPaintMonitor(infoPtr, + hDC, + (DWORD)infoPtr->DraggingMonitor, + &rc, + crPrevText, + bHideNumber); } }
@@ -882,6 +959,202 @@ 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 @@ 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 @@ TRUE); }
+ if (Index >= 0 && (uMsg == WM_LBUTTONDOWN || uMsg == WM_LBUTTONDBLCLK)) + { + infoPtr->LeftBtnDown = TRUE; + MonSelInitDragging(infoPtr, + (DWORD)Index, + &pt); + } + /* fall through */ }
@@ -983,6 +1286,13 @@ MonSelContextMenu(infoPtr, (SHORT)LOWORD(lParam), (SHORT)HIWORD(lParam)); + break; + } + + case WM_LBUTTONUP: + { + MonSelCancelDragging(infoPtr); + infoPtr->LeftBtnDown = FALSE; break; }
@@ -1020,6 +1330,7 @@ case WM_KILLFOCUS: { infoPtr->HasFocus = FALSE; + MonSelCancelDragging(infoPtr); MonSelRepaintSelected(infoPtr); break; }