mirror of
https://github.com/reactos/reactos.git
synced 2024-08-14 15:16:27 +00:00
1660 lines
44 KiB
C
1660 lines
44 KiB
C
#include "desk.h"
|
|
|
|
static const TCHAR szMonitorSelWndClass[] = TEXT("MONITORSELWNDCLASS");
|
|
|
|
typedef struct _MONSL_MON
|
|
{
|
|
RECT rc;
|
|
HFONT hFont;
|
|
TCHAR szCaption[12];
|
|
} MONSL_MON, *PMONSL_MON;
|
|
|
|
typedef struct _MONITORSELWND
|
|
{
|
|
HWND hSelf;
|
|
HWND hNotify;
|
|
HFONT hFont;
|
|
SIZE ClientSize;
|
|
DWORD UIState;
|
|
union
|
|
{
|
|
DWORD dwInternalFlags;
|
|
struct
|
|
{
|
|
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;
|
|
RECT rcMonitors;
|
|
RECT rcOldMonitors;
|
|
POINT ScrollPos;
|
|
SIZE Margin;
|
|
SIZE SelectionFrame;
|
|
HBITMAP hbmDisabledPattern;
|
|
HBRUSH hbrDisabled;
|
|
} MONITORSELWND, *PMONITORSELWND;
|
|
|
|
static LRESULT
|
|
MonSelNotify(IN PMONITORSELWND infoPtr,
|
|
IN UINT code,
|
|
IN OUT PVOID data)
|
|
{
|
|
LRESULT Ret = 0;
|
|
|
|
if (infoPtr->hNotify != NULL)
|
|
{
|
|
LPNMHDR pnmh = (LPNMHDR)data;
|
|
|
|
pnmh->hwndFrom = infoPtr->hSelf;
|
|
pnmh->idFrom = GetWindowLongPtr(infoPtr->hSelf,
|
|
GWLP_ID);
|
|
pnmh->code = code;
|
|
|
|
Ret = SendMessage(infoPtr->hNotify,
|
|
WM_NOTIFY,
|
|
(WPARAM)pnmh->idFrom,
|
|
(LPARAM)pnmh);
|
|
}
|
|
|
|
return Ret;
|
|
}
|
|
|
|
static LRESULT
|
|
MonSelNotifyMonitor(IN PMONITORSELWND infoPtr,
|
|
IN UINT code,
|
|
IN INT Index,
|
|
IN OUT PMONSL_MONNMHDR pmonnmh)
|
|
{
|
|
pmonnmh->Index = Index;
|
|
|
|
if (Index >= 0)
|
|
{
|
|
pmonnmh->MonitorInfo = infoPtr->MonitorInfo[Index];
|
|
}
|
|
else
|
|
{
|
|
ZeroMemory(&pmonnmh->MonitorInfo,
|
|
sizeof(pmonnmh->MonitorInfo));
|
|
}
|
|
|
|
return MonSelNotify(infoPtr,
|
|
code,
|
|
pmonnmh);
|
|
}
|
|
|
|
static HFONT
|
|
MonSelChangeFont(IN OUT PMONITORSELWND infoPtr,
|
|
IN HFONT hFont,
|
|
IN BOOL Redraw)
|
|
{
|
|
HFONT hOldFont = infoPtr->hFont;
|
|
infoPtr->hFont = hFont;
|
|
|
|
if (Redraw)
|
|
{
|
|
InvalidateRect(infoPtr->hSelf,
|
|
NULL,
|
|
TRUE);
|
|
}
|
|
|
|
return hOldFont;
|
|
}
|
|
|
|
static VOID
|
|
MonSelRectToScreen(IN PMONITORSELWND infoPtr,
|
|
IN const RECT *prc,
|
|
OUT PRECT prcOnScreen)
|
|
{
|
|
*prcOnScreen = *prc;
|
|
OffsetRect(prcOnScreen,
|
|
-infoPtr->ScrollPos.x,
|
|
-infoPtr->ScrollPos.y);
|
|
}
|
|
|
|
static VOID
|
|
MonSelScreenToPt(IN PMONITORSELWND infoPtr,
|
|
IN const POINT *pptOnScreen,
|
|
OUT PPOINT ppt)
|
|
{
|
|
ppt->x = pptOnScreen->x + infoPtr->ScrollPos.x;
|
|
ppt->y = pptOnScreen->y + infoPtr->ScrollPos.y;
|
|
}
|
|
|
|
static VOID
|
|
MonSelMonInfoToRect(IN const MONSL_MONINFO *pMonInfo,
|
|
OUT PRECT prc)
|
|
{
|
|
prc->left = pMonInfo->Position.x;
|
|
prc->top = pMonInfo->Position.y;
|
|
prc->right = pMonInfo->Position.x + pMonInfo->Size.cx;
|
|
prc->bottom = pMonInfo->Position.y + pMonInfo->Size.cy;
|
|
}
|
|
|
|
static INT
|
|
MonSelHitTest(IN PMONITORSELWND infoPtr,
|
|
IN const POINT *ppt)
|
|
{
|
|
POINT pt;
|
|
INT Index, Ret = -1;
|
|
|
|
if (infoPtr->CanDisplay)
|
|
{
|
|
MonSelScreenToPt(infoPtr,
|
|
ppt,
|
|
&pt);
|
|
|
|
for (Index = 0; Index < (INT)infoPtr->MonitorsCount; Index++)
|
|
{
|
|
if (PtInRect(&infoPtr->Monitors[Index].rc,
|
|
pt))
|
|
{
|
|
Ret = Index;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return Ret;
|
|
}
|
|
|
|
static VOID
|
|
MonSelUpdateExtent(IN OUT PMONITORSELWND infoPtr)
|
|
{
|
|
DWORD Index;
|
|
RECT rcMonitor;
|
|
|
|
/* NOTE: This routine calculates the extent of all monitor coordinates.
|
|
These are not control coordinates! */
|
|
if (infoPtr->MonitorsCount > 0)
|
|
{
|
|
MonSelMonInfoToRect(&infoPtr->MonitorInfo[0],
|
|
&infoPtr->rcExtent);
|
|
|
|
for (Index = 1; Index < infoPtr->MonitorsCount; Index++)
|
|
{
|
|
MonSelMonInfoToRect(&infoPtr->MonitorInfo[Index],
|
|
&rcMonitor);
|
|
|
|
UnionRect(&infoPtr->rcExtent,
|
|
&infoPtr->rcExtent,
|
|
&rcMonitor);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ZeroMemory(&infoPtr->rcExtent,
|
|
sizeof(infoPtr->rcExtent));
|
|
}
|
|
}
|
|
|
|
static VOID
|
|
MonSelScaleRectRelative(IN const RECT *prcBaseFrom,
|
|
IN const RECT *prcFrom,
|
|
IN const RECT *prcBaseTo,
|
|
OUT PRECT prcTo)
|
|
{
|
|
SIZE BaseFrom, BaseTo, From;
|
|
|
|
BaseFrom.cx = prcBaseFrom->right - prcBaseFrom->left;
|
|
BaseFrom.cy = prcBaseFrom->bottom - prcBaseFrom->top;
|
|
BaseTo.cx = prcBaseTo->right - prcBaseTo->left;
|
|
BaseTo.cy = prcBaseTo->bottom - prcBaseTo->top;
|
|
From.cx = prcFrom->right - prcFrom->left;
|
|
From.cy = prcFrom->bottom - prcFrom->top;
|
|
|
|
prcTo->left = prcBaseTo->left + (((prcFrom->left - prcBaseFrom->left) * BaseTo.cx) / BaseFrom.cx);
|
|
prcTo->top = prcBaseTo->top + (((prcFrom->top - prcBaseFrom->top) * BaseTo.cy) / BaseFrom.cy);
|
|
prcTo->right = prcTo->left + ((From.cx * BaseTo.cx) / BaseFrom.cx);
|
|
prcTo->bottom = prcTo->top + ((From.cy * BaseTo.cy) / BaseFrom.cy);
|
|
}
|
|
|
|
static VOID
|
|
ScaleRectSizeFit(IN const RECT *prcContainerRect,
|
|
IN OUT PRECT prcRectToScale)
|
|
{
|
|
SIZE ContainerSize, RectSize;
|
|
|
|
ContainerSize.cx = prcContainerRect->right - prcContainerRect->left;
|
|
ContainerSize.cy = prcContainerRect->bottom - prcContainerRect->top;
|
|
RectSize.cx = prcRectToScale->right - prcRectToScale->left;
|
|
RectSize.cy = prcRectToScale->bottom - prcRectToScale->top;
|
|
|
|
if (((RectSize.cx * 0xFFF) / RectSize.cy) < ((ContainerSize.cx * 0xFFF) / ContainerSize.cy))
|
|
{
|
|
RectSize.cx = (RectSize.cx * ((ContainerSize.cy * 0xFFF) / RectSize.cy)) / 0xFFF;
|
|
RectSize.cy = ContainerSize.cy;
|
|
}
|
|
else
|
|
{
|
|
RectSize.cy = (RectSize.cy * ((ContainerSize.cx * 0xFFF) / RectSize.cx)) / 0xFFF;
|
|
RectSize.cx = ContainerSize.cx;
|
|
}
|
|
|
|
prcRectToScale->right = prcRectToScale->left + RectSize.cx;
|
|
prcRectToScale->bottom = prcRectToScale->top + RectSize.cy;
|
|
|
|
OffsetRect(prcRectToScale,
|
|
prcContainerRect->left + ((ContainerSize.cx - RectSize.cx) / 2),
|
|
prcContainerRect->top + ((ContainerSize.cy - RectSize.cy) / 2));
|
|
}
|
|
|
|
static VOID
|
|
MonSelRepaint(IN PMONITORSELWND infoPtr)
|
|
{
|
|
RECT rc;
|
|
|
|
MonSelRectToScreen(infoPtr,
|
|
&infoPtr->rcMonitors,
|
|
&rc);
|
|
InvalidateRect(infoPtr->hSelf,
|
|
&rc,
|
|
TRUE);
|
|
|
|
if (!EqualRect(&infoPtr->rcMonitors, &infoPtr->rcOldMonitors) &&
|
|
infoPtr->rcOldMonitors.right != infoPtr->rcOldMonitors.left)
|
|
{
|
|
MonSelRectToScreen(infoPtr, &infoPtr->rcOldMonitors, &rc);
|
|
InvalidateRect(infoPtr->hSelf, &rc, TRUE);
|
|
infoPtr->rcOldMonitors = infoPtr->rcMonitors;
|
|
}
|
|
}
|
|
|
|
static VOID
|
|
MonSelRepaintMonitor(IN PMONITORSELWND infoPtr,
|
|
IN DWORD Index)
|
|
{
|
|
RECT rc;
|
|
BOOL NoRepaint = FALSE;
|
|
|
|
if (Index < infoPtr->MonitorsCount)
|
|
{
|
|
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);
|
|
}
|
|
}
|
|
}
|
|
|
|
static VOID
|
|
MonSelRepaintSelected(IN PMONITORSELWND infoPtr)
|
|
{
|
|
if (infoPtr->SelectedMonitor >= 0)
|
|
{
|
|
MonSelRepaintMonitor(infoPtr,
|
|
(DWORD)infoPtr->SelectedMonitor);
|
|
}
|
|
}
|
|
|
|
static VOID
|
|
MonSelResetMonitors(IN OUT PMONITORSELWND infoPtr)
|
|
{
|
|
DWORD Index;
|
|
|
|
for (Index = 0; Index < infoPtr->MonitorsCount; Index++)
|
|
{
|
|
if (infoPtr->Monitors[Index].hFont != NULL)
|
|
{
|
|
DeleteObject(infoPtr->Monitors[Index].hFont);
|
|
infoPtr->Monitors[Index].hFont = NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
static VOID
|
|
MonSelUpdateMonitorsInfo(IN OUT PMONITORSELWND infoPtr,
|
|
IN BOOL bRepaint)
|
|
{
|
|
RECT rcExtSurface, rcExtDisplay;
|
|
DWORD Index;
|
|
|
|
/* Recalculate rcExtent */
|
|
MonSelUpdateExtent(infoPtr);
|
|
|
|
infoPtr-> CanDisplay = infoPtr->MonitorsCount != 0 &&
|
|
(infoPtr->ClientSize.cx > (2 * (infoPtr->Margin.cx + infoPtr->SelectionFrame.cx))) &&
|
|
(infoPtr->ClientSize.cy > (2 * (infoPtr->Margin.cy + infoPtr->SelectionFrame.cy)));
|
|
|
|
if (infoPtr->CanDisplay)
|
|
{
|
|
/* Calculate the rectangle on the control in which may be painted */
|
|
rcExtSurface.left = infoPtr->Margin.cx;
|
|
rcExtSurface.top = infoPtr->Margin.cy;
|
|
rcExtSurface.right = rcExtSurface.left + infoPtr->ClientSize.cx - (2 * infoPtr->Margin.cx);
|
|
rcExtSurface.bottom = rcExtSurface.top + infoPtr->ClientSize.cy - (2 * infoPtr->Margin.cy);
|
|
|
|
/* Calculate the rectangle on the control that is actually painted on */
|
|
rcExtDisplay.left = rcExtDisplay.top = 0;
|
|
rcExtDisplay.right = infoPtr->rcExtent.right - infoPtr->rcExtent.left;
|
|
rcExtDisplay.bottom = infoPtr->rcExtent.bottom - infoPtr->rcExtent.top;
|
|
|
|
ScaleRectSizeFit(&rcExtSurface,
|
|
&rcExtDisplay);
|
|
|
|
infoPtr->rcOldMonitors = infoPtr->rcMonitors;
|
|
infoPtr->rcMonitors = rcExtDisplay;
|
|
|
|
/* Now that we know in which area all monitors are located,
|
|
calculate the monitors selection rectangles on the screen */
|
|
|
|
for (Index = 0; Index < infoPtr->MonitorsCount; Index++)
|
|
{
|
|
MonSelMonInfoToRect(&infoPtr->MonitorInfo[Index],
|
|
&rcExtDisplay);
|
|
|
|
MonSelScaleRectRelative(&infoPtr->rcExtent,
|
|
&rcExtDisplay,
|
|
&infoPtr->rcMonitors,
|
|
&infoPtr->Monitors[Index].rc);
|
|
}
|
|
|
|
MonSelResetMonitors(infoPtr);
|
|
|
|
if (bRepaint)
|
|
MonSelRepaint(infoPtr);
|
|
}
|
|
else if (bRepaint)
|
|
{
|
|
InvalidateRect(infoPtr->hSelf,
|
|
NULL,
|
|
TRUE);
|
|
}
|
|
}
|
|
|
|
static BOOL
|
|
MonSelSetMonitorsInfo(IN OUT PMONITORSELWND infoPtr,
|
|
IN DWORD dwMonitors,
|
|
IN const MONSL_MONINFO *MonitorsInfo)
|
|
{
|
|
DWORD Index;
|
|
BOOL Ret = TRUE;
|
|
|
|
if (infoPtr->DraggingMonitor >= 0)
|
|
return FALSE;
|
|
|
|
if (infoPtr->MonitorInfo != NULL)
|
|
{
|
|
LocalFree((HLOCAL)infoPtr->MonitorInfo);
|
|
infoPtr->MonitorInfo = NULL;
|
|
|
|
MonSelResetMonitors(infoPtr);
|
|
|
|
LocalFree((HLOCAL)infoPtr->Monitors);
|
|
infoPtr->Monitors = NULL;
|
|
|
|
infoPtr->MonitorsCount = 0;
|
|
}
|
|
|
|
if (dwMonitors != 0)
|
|
{
|
|
infoPtr->MonitorInfo = (PMONSL_MONINFO)LocalAlloc(LMEM_FIXED,
|
|
dwMonitors * sizeof(MONSL_MONINFO));
|
|
if (infoPtr->MonitorInfo != NULL)
|
|
{
|
|
infoPtr->Monitors = (PMONSL_MON)LocalAlloc(LMEM_FIXED,
|
|
dwMonitors * sizeof(MONSL_MON));
|
|
if (infoPtr->Monitors != NULL)
|
|
{
|
|
CopyMemory(infoPtr->MonitorInfo,
|
|
MonitorsInfo,
|
|
dwMonitors * sizeof(MONSL_MONINFO));
|
|
ZeroMemory(infoPtr->Monitors,
|
|
dwMonitors * sizeof(MONSL_MON));
|
|
|
|
for (Index = 0; Index < dwMonitors; Index++)
|
|
{
|
|
_stprintf(infoPtr->Monitors[Index].szCaption,
|
|
_T("%u"),
|
|
Index + 1);
|
|
}
|
|
|
|
infoPtr->MonitorsCount = dwMonitors;
|
|
|
|
if (infoPtr->SelectedMonitor >= (INT)infoPtr->MonitorsCount)
|
|
infoPtr->SelectedMonitor = -1;
|
|
|
|
if (!(infoPtr->ControlExStyle & MSLM_EX_ALLOWSELECTNONE) && infoPtr->SelectedMonitor < 0)
|
|
infoPtr->SelectedMonitor = 0;
|
|
|
|
MonSelUpdateMonitorsInfo(infoPtr,
|
|
TRUE);
|
|
}
|
|
else
|
|
{
|
|
LocalFree((HLOCAL)infoPtr->MonitorInfo);
|
|
infoPtr->MonitorInfo = NULL;
|
|
|
|
Ret = FALSE;
|
|
}
|
|
}
|
|
else
|
|
Ret = FALSE;
|
|
}
|
|
|
|
if (!Ret)
|
|
infoPtr->SelectedMonitor = -1;
|
|
|
|
if (!Ret || dwMonitors == 0)
|
|
{
|
|
InvalidateRect(infoPtr->hSelf,
|
|
NULL,
|
|
TRUE);
|
|
}
|
|
|
|
return Ret;
|
|
}
|
|
|
|
static DWORD
|
|
MonSelGetMonitorsInfo(IN PMONITORSELWND infoPtr,
|
|
IN DWORD dwMonitors,
|
|
IN OUT PMONSL_MONINFO MonitorsInfo)
|
|
{
|
|
if (dwMonitors != 0)
|
|
{
|
|
if (dwMonitors > infoPtr->MonitorsCount)
|
|
dwMonitors = infoPtr->MonitorsCount;
|
|
|
|
CopyMemory(MonitorsInfo,
|
|
infoPtr->MonitorInfo,
|
|
dwMonitors * sizeof(MONSL_MONINFO));
|
|
return dwMonitors;
|
|
}
|
|
else
|
|
return infoPtr->MonitorsCount;
|
|
}
|
|
|
|
static BOOL
|
|
MonSelSetMonitorInfo(IN OUT PMONITORSELWND infoPtr,
|
|
IN INT Index,
|
|
IN const MONSL_MONINFO *MonitorsInfo)
|
|
{
|
|
if (infoPtr->DraggingMonitor < 0 &&
|
|
Index >= 0 && Index < (INT)infoPtr->MonitorsCount)
|
|
{
|
|
CopyMemory(&infoPtr->MonitorInfo[Index],
|
|
MonitorsInfo,
|
|
sizeof(MONSL_MONINFO));
|
|
|
|
MonSelUpdateMonitorsInfo(infoPtr,
|
|
TRUE);
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
static BOOL
|
|
MonSelGetMonitorInfo(IN PMONITORSELWND infoPtr,
|
|
IN INT Index,
|
|
IN OUT PMONSL_MONINFO MonitorsInfo)
|
|
{
|
|
if (Index >= 0 && Index < (INT)infoPtr->MonitorsCount)
|
|
{
|
|
CopyMemory(MonitorsInfo,
|
|
&infoPtr->MonitorInfo[Index],
|
|
sizeof(MONSL_MONINFO));
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
static INT
|
|
MonSelGetMonitorRect(IN OUT PMONITORSELWND infoPtr,
|
|
IN INT Index,
|
|
OUT PRECT prc)
|
|
{
|
|
RECT rc, rcClient;
|
|
|
|
if (Index < 0 || (UINT)Index >= infoPtr->MonitorsCount)
|
|
return -1;
|
|
|
|
if (!infoPtr->CanDisplay)
|
|
return 0;
|
|
|
|
MonSelRectToScreen(infoPtr,
|
|
&infoPtr->Monitors[Index].rc,
|
|
prc);
|
|
|
|
rcClient.left = rcClient.top = 0;
|
|
rcClient.right = infoPtr->ClientSize.cx;
|
|
rcClient.bottom = infoPtr->ClientSize.cy;
|
|
|
|
return IntersectRect(&rc,
|
|
&rcClient,
|
|
prc) != FALSE;
|
|
}
|
|
|
|
static BOOL
|
|
MonSelSetCurSelMonitor(IN OUT PMONITORSELWND infoPtr,
|
|
IN INT Index,
|
|
IN BOOL bNotify)
|
|
{
|
|
INT PrevSel;
|
|
BOOL PreventSelect = FALSE;
|
|
BOOL Ret = FALSE;
|
|
|
|
if (infoPtr->DraggingMonitor < 0 &&
|
|
(Index == -1 || Index < (INT)infoPtr->MonitorsCount))
|
|
{
|
|
if (Index != infoPtr->SelectedMonitor)
|
|
{
|
|
if ((infoPtr->MonitorInfo[Index].Flags & MSL_MIF_DISABLED) &&
|
|
!(infoPtr->ControlExStyle & MSLM_EX_ALLOWSELECTDISABLED))
|
|
{
|
|
PreventSelect = TRUE;
|
|
}
|
|
|
|
if (!PreventSelect && bNotify)
|
|
{
|
|
MONSL_MONNMMONITORCHANGING nmi;
|
|
|
|
nmi.PreviousSelected = infoPtr->SelectedMonitor;
|
|
nmi.AllowChanging = TRUE;
|
|
|
|
MonSelNotifyMonitor(infoPtr,
|
|
MSLN_MONITORCHANGING,
|
|
Index,
|
|
&nmi.hdr);
|
|
|
|
PreventSelect = (nmi.AllowChanging == FALSE);
|
|
}
|
|
|
|
if (!PreventSelect)
|
|
{
|
|
PrevSel = infoPtr->SelectedMonitor;
|
|
infoPtr->SelectedMonitor = Index;
|
|
|
|
if (PrevSel >= 0)
|
|
{
|
|
MonSelRepaintMonitor(infoPtr,
|
|
PrevSel);
|
|
}
|
|
|
|
if (infoPtr->SelectedMonitor >= 0)
|
|
MonSelRepaintSelected(infoPtr);
|
|
|
|
if (bNotify)
|
|
{
|
|
MONSL_MONNMHDR nm;
|
|
|
|
MonSelNotifyMonitor(infoPtr,
|
|
MSLN_MONITORCHANGED,
|
|
Index,
|
|
&nm);
|
|
}
|
|
}
|
|
}
|
|
|
|
Ret = TRUE;
|
|
}
|
|
|
|
return Ret;
|
|
}
|
|
|
|
static VOID
|
|
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 | MSLM_EX_SELECTBYARROWKEY;
|
|
return;
|
|
}
|
|
|
|
static VOID
|
|
MonSelDestroy(IN OUT PMONITORSELWND infoPtr)
|
|
{
|
|
/* Free all monitors */
|
|
MonSelSetMonitorsInfo(infoPtr,
|
|
0,
|
|
NULL);
|
|
|
|
if (infoPtr->hbrDisabled != NULL)
|
|
{
|
|
DeleteObject(infoPtr->hbrDisabled);
|
|
infoPtr->hbrDisabled = NULL;
|
|
}
|
|
|
|
if (infoPtr->hbmDisabledPattern != NULL)
|
|
{
|
|
DeleteObject(infoPtr->hbmDisabledPattern);
|
|
infoPtr->hbmDisabledPattern = NULL;
|
|
}
|
|
}
|
|
|
|
static BOOL
|
|
MonSelSetExtendedStyle(IN OUT PMONITORSELWND infoPtr,
|
|
IN DWORD dwExtendedStyle)
|
|
{
|
|
if (infoPtr->DraggingMonitor >= 0)
|
|
return FALSE;
|
|
|
|
if (dwExtendedStyle != infoPtr->ControlExStyle)
|
|
{
|
|
infoPtr->ControlExStyle = dwExtendedStyle;
|
|
|
|
/* Repaint the control */
|
|
InvalidateRect(infoPtr->hSelf,
|
|
NULL,
|
|
TRUE);
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static DWORD
|
|
MonSelGetExtendedStyle(IN PMONITORSELWND infoPtr)
|
|
{
|
|
return infoPtr->ControlExStyle;
|
|
}
|
|
|
|
static HFONT
|
|
MonSelGetMonitorFont(IN OUT PMONITORSELWND infoPtr,
|
|
IN HDC hDC,
|
|
IN INT Index)
|
|
{
|
|
TEXTMETRIC tm;
|
|
SIZE rcsize;
|
|
LOGFONT lf;
|
|
HFONT hPrevFont, hFont;
|
|
//INT len;
|
|
|
|
hFont = infoPtr->Monitors[Index].hFont;
|
|
if (hFont == NULL &&
|
|
GetObject(infoPtr->hFont,
|
|
sizeof(lf),
|
|
&lf) != 0)
|
|
{
|
|
rcsize.cx = infoPtr->Monitors[Index].rc.right - infoPtr->Monitors[Index].rc.left -
|
|
(2 * infoPtr->SelectionFrame.cx) - 2;
|
|
rcsize.cy = infoPtr->Monitors[Index].rc.bottom - infoPtr->Monitors[Index].rc.top -
|
|
(2 * infoPtr->SelectionFrame.cy) - 2;
|
|
rcsize.cy = (rcsize.cy * 60) / 100;
|
|
|
|
//len = _tcslen(infoPtr->Monitors[Index].szCaption);
|
|
|
|
hPrevFont = SelectObject(hDC,
|
|
infoPtr->hFont);
|
|
|
|
if (GetTextMetrics(hDC,
|
|
&tm))
|
|
{
|
|
lf.lfWeight = FW_SEMIBOLD;
|
|
lf.lfHeight = -MulDiv(rcsize.cy - tm.tmExternalLeading,
|
|
GetDeviceCaps(hDC,
|
|
LOGPIXELSY),
|
|
72);
|
|
|
|
hFont = CreateFontIndirect(&lf);
|
|
if (hFont != NULL)
|
|
infoPtr->Monitors[Index].hFont = hFont;
|
|
}
|
|
|
|
SelectObject(hDC,
|
|
hPrevFont);
|
|
}
|
|
|
|
return hFont;
|
|
}
|
|
|
|
static BOOL
|
|
MonSelDrawDisabledRect(IN OUT PMONITORSELWND infoPtr,
|
|
IN HDC hDC,
|
|
IN const RECT *prc)
|
|
{
|
|
BOOL Ret = FALSE;
|
|
|
|
if (infoPtr->hbrDisabled == NULL)
|
|
{
|
|
static const DWORD Pattern[4] = {0x5555AAAA, 0x5555AAAA, 0x5555AAAA, 0x5555AAAA};
|
|
|
|
if (infoPtr->hbmDisabledPattern == NULL)
|
|
{
|
|
infoPtr->hbmDisabledPattern = CreateBitmap(8,
|
|
8,
|
|
1,
|
|
1,
|
|
Pattern);
|
|
}
|
|
|
|
if (infoPtr->hbmDisabledPattern != NULL)
|
|
infoPtr->hbrDisabled = CreatePatternBrush(infoPtr->hbmDisabledPattern);
|
|
}
|
|
|
|
if (infoPtr->hbrDisabled != NULL)
|
|
{
|
|
/* FIXME: Implement */
|
|
}
|
|
|
|
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;
|
|
HBRUSH hbBk, hbOldBk;
|
|
HPEN hpFg, hpOldFg;
|
|
DWORD Index;
|
|
RECT rc, rctmp;
|
|
INT iPrevBkMode;
|
|
BOOL bHideNumber;
|
|
|
|
bHideNumber = (infoPtr->ControlExStyle & MSLM_EX_HIDENUMBERS) ||
|
|
((infoPtr->MonitorsCount == 1) && (infoPtr->ControlExStyle & MSLM_EX_HIDENUMBERONSINGLE));
|
|
|
|
hbBk = GetSysColorBrush(COLOR_BACKGROUND);
|
|
hpFg = CreatePen(PS_SOLID,
|
|
0,
|
|
GetSysColor(COLOR_HIGHLIGHTTEXT));
|
|
|
|
hbOldBk = SelectObject(hDC,
|
|
hbBk);
|
|
hpOldFg = SelectObject(hDC,
|
|
hpFg);
|
|
iPrevBkMode = SetBkMode(hDC,
|
|
TRANSPARENT);
|
|
crPrevText = SetTextColor(hDC,
|
|
GetSysColor(COLOR_HIGHLIGHTTEXT));
|
|
|
|
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))
|
|
{
|
|
MonSelPaintMonitor(infoPtr,
|
|
hDC,
|
|
Index,
|
|
&rc,
|
|
crPrevText,
|
|
bHideNumber);
|
|
}
|
|
}
|
|
|
|
/* Paint the dragging monitor last */
|
|
if (infoPtr->IsDraggingMonitor &&
|
|
infoPtr->DraggingMonitor >= 0)
|
|
{
|
|
MonSelRectToScreen(infoPtr,
|
|
&infoPtr->rcDragging,
|
|
&rc);
|
|
|
|
if (IntersectRect(&rctmp,
|
|
&rc,
|
|
prcUpdate))
|
|
{
|
|
MonSelPaintMonitor(infoPtr,
|
|
hDC,
|
|
(DWORD)infoPtr->DraggingMonitor,
|
|
&rc,
|
|
crPrevText,
|
|
bHideNumber);
|
|
}
|
|
}
|
|
|
|
SetTextColor(hDC,
|
|
crPrevText);
|
|
SetBkMode(hDC,
|
|
iPrevBkMode);
|
|
SelectObject(hDC,
|
|
hpOldFg);
|
|
SelectObject(hDC,
|
|
hbOldBk);
|
|
|
|
DeleteObject(hpFg);
|
|
}
|
|
|
|
static VOID
|
|
MonSelContextMenu(IN OUT PMONITORSELWND infoPtr,
|
|
IN SHORT x,
|
|
IN SHORT y)
|
|
{
|
|
MONSL_MONNMBUTTONCLICKED nm;
|
|
INT Index;
|
|
|
|
if (!infoPtr->HasFocus)
|
|
SetFocus(infoPtr->hSelf);
|
|
|
|
nm.pt.x = x;
|
|
nm.pt.y = y;
|
|
|
|
Index = MonSelHitTest(infoPtr,
|
|
&nm.pt);
|
|
|
|
MonSelNotifyMonitor(infoPtr,
|
|
MSLN_RBUTTONUP,
|
|
Index,
|
|
(PMONSL_MONNMHDR)&nm);
|
|
|
|
/* Send a WM_CONTEXTMENU notification */
|
|
MapWindowPoints(infoPtr->hSelf,
|
|
NULL,
|
|
&nm.pt,
|
|
1);
|
|
|
|
SendMessage(infoPtr->hSelf,
|
|
WM_CONTEXTMENU,
|
|
(WPARAM)infoPtr->hSelf,
|
|
MAKELPARAM(nm.pt.x,
|
|
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,
|
|
IN WPARAM wParam,
|
|
IN LPARAM lParam)
|
|
{
|
|
PMONITORSELWND infoPtr;
|
|
LRESULT Ret = 0;
|
|
|
|
infoPtr = (PMONITORSELWND)GetWindowLongPtrW(hwnd,
|
|
0);
|
|
|
|
if (infoPtr == NULL && uMsg != WM_CREATE)
|
|
{
|
|
goto HandleDefaultMessage;
|
|
}
|
|
|
|
switch (uMsg)
|
|
{
|
|
case WM_PAINT:
|
|
case WM_PRINTCLIENT:
|
|
{
|
|
PAINTSTRUCT ps;
|
|
HDC hDC;
|
|
|
|
if (wParam != 0)
|
|
{
|
|
if (!GetUpdateRect(hwnd,
|
|
&ps.rcPaint,
|
|
TRUE))
|
|
{
|
|
break;
|
|
}
|
|
hDC = (HDC)wParam;
|
|
}
|
|
else
|
|
{
|
|
hDC = BeginPaint(hwnd,
|
|
&ps);
|
|
if (hDC == NULL)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (infoPtr->CanDisplay)
|
|
{
|
|
MonSelPaint(infoPtr,
|
|
hDC,
|
|
&ps.rcPaint);
|
|
}
|
|
|
|
if (wParam == 0)
|
|
{
|
|
EndPaint(hwnd,
|
|
&ps);
|
|
}
|
|
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))
|
|
break;
|
|
|
|
/* Fall through */
|
|
}
|
|
|
|
case WM_LBUTTONDBLCLK:
|
|
case WM_LBUTTONDOWN:
|
|
{
|
|
INT Index;
|
|
POINT pt;
|
|
|
|
if (!infoPtr->HasFocus)
|
|
SetFocus(infoPtr->hSelf);
|
|
|
|
pt.x = (LONG)LOWORD(lParam);
|
|
pt.y = (LONG)HIWORD(lParam);
|
|
|
|
Index = MonSelHitTest(infoPtr,
|
|
&pt);
|
|
if (Index >= 0 || (infoPtr->ControlExStyle & MSLM_EX_ALLOWSELECTNONE))
|
|
{
|
|
MonSelSetCurSelMonitor(infoPtr,
|
|
Index,
|
|
TRUE);
|
|
}
|
|
|
|
if (Index >= 0 && (uMsg == WM_LBUTTONDOWN || uMsg == WM_LBUTTONDBLCLK))
|
|
{
|
|
infoPtr->LeftBtnDown = TRUE;
|
|
MonSelInitDragging(infoPtr,
|
|
(DWORD)Index,
|
|
&pt);
|
|
}
|
|
|
|
/* Fall through */
|
|
}
|
|
|
|
case WM_MBUTTONDOWN:
|
|
{
|
|
if (!infoPtr->HasFocus)
|
|
SetFocus(hwnd);
|
|
break;
|
|
}
|
|
|
|
case WM_RBUTTONUP:
|
|
{
|
|
MonSelContextMenu(infoPtr,
|
|
(SHORT)LOWORD(lParam),
|
|
(SHORT)HIWORD(lParam));
|
|
break;
|
|
}
|
|
|
|
case WM_LBUTTONUP:
|
|
{
|
|
MonSelCancelDragging(infoPtr);
|
|
infoPtr->LeftBtnDown = FALSE;
|
|
break;
|
|
}
|
|
|
|
case WM_GETDLGCODE:
|
|
{
|
|
INT virtKey;
|
|
|
|
virtKey = (lParam != 0 ? (INT)((LPMSG)lParam)->wParam : 0);
|
|
switch (virtKey)
|
|
{
|
|
case VK_TAB:
|
|
{
|
|
/* Change the UI status */
|
|
SendMessage(GetAncestor(hwnd,
|
|
GA_PARENT),
|
|
WM_CHANGEUISTATE,
|
|
MAKEWPARAM(UIS_INITIALIZE,
|
|
0),
|
|
0);
|
|
break;
|
|
}
|
|
}
|
|
|
|
Ret |= DLGC_WANTARROWS;
|
|
|
|
if (infoPtr->ControlExStyle & MSLM_EX_SELECTBYNUMKEY)
|
|
Ret |= DLGC_WANTCHARS;
|
|
break;
|
|
}
|
|
|
|
case WM_SETFOCUS:
|
|
{
|
|
infoPtr->HasFocus = TRUE;
|
|
MonSelRepaintSelected(infoPtr);
|
|
break;
|
|
}
|
|
|
|
case WM_KILLFOCUS:
|
|
{
|
|
infoPtr->HasFocus = FALSE;
|
|
MonSelCancelDragging(infoPtr);
|
|
MonSelRepaintSelected(infoPtr);
|
|
break;
|
|
}
|
|
|
|
case WM_UPDATEUISTATE:
|
|
{
|
|
DWORD OldUIState;
|
|
|
|
Ret = DefWindowProcW(hwnd,
|
|
uMsg,
|
|
wParam,
|
|
lParam);
|
|
|
|
OldUIState = infoPtr->UIState;
|
|
switch (LOWORD(wParam))
|
|
{
|
|
case UIS_SET:
|
|
infoPtr->UIState |= HIWORD(wParam);
|
|
break;
|
|
|
|
case UIS_CLEAR:
|
|
infoPtr->UIState &= ~HIWORD(wParam);
|
|
break;
|
|
}
|
|
|
|
if (infoPtr->UIState != OldUIState)
|
|
MonSelRepaintSelected(infoPtr);
|
|
break;
|
|
}
|
|
|
|
case WM_SETFONT:
|
|
{
|
|
Ret = (LRESULT)MonSelChangeFont(infoPtr,
|
|
(HFONT)wParam,
|
|
(BOOL)LOWORD(lParam));
|
|
break;
|
|
}
|
|
|
|
case WM_SIZE:
|
|
{
|
|
infoPtr->ClientSize.cx = LOWORD(lParam);
|
|
infoPtr->ClientSize.cy = HIWORD(lParam);
|
|
|
|
/* Don't let MonSelUpdateMonitorsInfo repaint the control
|
|
because this won't work properly in case the control
|
|
was sized down! */
|
|
MonSelUpdateMonitorsInfo(infoPtr,
|
|
FALSE);
|
|
InvalidateRect(infoPtr->hSelf,
|
|
NULL,
|
|
TRUE);
|
|
break;
|
|
}
|
|
|
|
case WM_GETFONT:
|
|
{
|
|
Ret = (LRESULT)infoPtr->hFont;
|
|
break;
|
|
}
|
|
|
|
case WM_ENABLE:
|
|
{
|
|
infoPtr->Enabled = ((BOOL)wParam != FALSE);
|
|
MonSelRepaint(infoPtr);
|
|
break;
|
|
}
|
|
|
|
case WM_STYLECHANGED:
|
|
{
|
|
if (wParam == GWL_STYLE)
|
|
{
|
|
unsigned int OldEnabled = infoPtr->Enabled;
|
|
infoPtr->Enabled = !(((LPSTYLESTRUCT)lParam)->styleNew & WS_DISABLED);
|
|
|
|
if (OldEnabled != infoPtr->Enabled)
|
|
MonSelRepaint(infoPtr);
|
|
}
|
|
break;
|
|
}
|
|
|
|
case WM_KEYDOWN:
|
|
{
|
|
INT Index;
|
|
|
|
if (infoPtr->ControlExStyle & MSLM_EX_SELECTBYARROWKEY)
|
|
{
|
|
switch (wParam)
|
|
{
|
|
case VK_UP:
|
|
case VK_LEFT:
|
|
{
|
|
Index = infoPtr->SelectedMonitor;
|
|
|
|
if (infoPtr->MonitorsCount != 0)
|
|
{
|
|
if (Index < 0)
|
|
Index = 0;
|
|
else if (Index > 0)
|
|
Index--;
|
|
}
|
|
|
|
if (Index >= 0)
|
|
{
|
|
MonSelSetCurSelMonitor(infoPtr,
|
|
Index,
|
|
TRUE);
|
|
}
|
|
break;
|
|
}
|
|
|
|
case VK_DOWN:
|
|
case VK_RIGHT:
|
|
{
|
|
Index = infoPtr->SelectedMonitor;
|
|
|
|
if (infoPtr->MonitorsCount != 0)
|
|
{
|
|
if (Index < 0)
|
|
Index = (INT)infoPtr->MonitorsCount - 1;
|
|
else if (Index < (INT)infoPtr->MonitorsCount - 1)
|
|
Index++;
|
|
}
|
|
|
|
if (infoPtr->SelectedMonitor < (INT)infoPtr->MonitorsCount)
|
|
{
|
|
MonSelSetCurSelMonitor(infoPtr,
|
|
Index,
|
|
TRUE);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
case WM_CHAR:
|
|
{
|
|
if ((infoPtr->ControlExStyle & MSLM_EX_SELECTBYNUMKEY) &&
|
|
wParam >= '1' && wParam <= '9')
|
|
{
|
|
INT Index = (INT)(wParam - '1');
|
|
if (Index < (INT)infoPtr->MonitorsCount)
|
|
{
|
|
MonSelSetCurSelMonitor(infoPtr,
|
|
Index,
|
|
TRUE);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
case MSLM_SETMONITORSINFO:
|
|
{
|
|
Ret = MonSelSetMonitorsInfo(infoPtr,
|
|
(DWORD)wParam,
|
|
(const MONSL_MONINFO *)lParam);
|
|
break;
|
|
}
|
|
|
|
case MSLM_GETMONITORSINFO:
|
|
{
|
|
Ret = MonSelGetMonitorsInfo(infoPtr,
|
|
(DWORD)wParam,
|
|
(PMONSL_MONINFO)lParam);
|
|
break;
|
|
}
|
|
|
|
case MSLM_GETMONITORINFOCOUNT:
|
|
{
|
|
Ret = infoPtr->MonitorsCount;
|
|
break;
|
|
}
|
|
|
|
case MSLM_HITTEST:
|
|
{
|
|
Ret = MonSelHitTest(infoPtr,
|
|
(const POINT *)wParam);
|
|
break;
|
|
}
|
|
|
|
case MSLM_SETCURSEL:
|
|
{
|
|
Ret = MonSelSetCurSelMonitor(infoPtr,
|
|
(INT)wParam,
|
|
FALSE);
|
|
break;
|
|
}
|
|
|
|
case MSLM_GETCURSEL:
|
|
{
|
|
Ret = infoPtr->SelectedMonitor;
|
|
break;
|
|
}
|
|
|
|
case MSLM_SETMONITORINFO:
|
|
{
|
|
Ret = MonSelSetMonitorInfo(infoPtr,
|
|
(INT)wParam,
|
|
(const MONSL_MONINFO *)lParam);
|
|
break;
|
|
}
|
|
|
|
case MSLM_GETMONITORINFO:
|
|
{
|
|
Ret = MonSelGetMonitorInfo(infoPtr,
|
|
(INT)wParam,
|
|
(PMONSL_MONINFO)lParam);
|
|
break;
|
|
}
|
|
|
|
case MSLM_SETEXSTYLE:
|
|
{
|
|
Ret = MonSelSetExtendedStyle(infoPtr,
|
|
(DWORD)lParam);
|
|
break;
|
|
}
|
|
|
|
case MSLM_GETEXSTYLE:
|
|
{
|
|
Ret = MonSelGetExtendedStyle(infoPtr);
|
|
break;
|
|
}
|
|
|
|
case MSLM_GETMONITORRECT:
|
|
{
|
|
Ret = (LRESULT)MonSelGetMonitorRect(infoPtr,
|
|
(INT)wParam,
|
|
(PRECT)lParam);
|
|
break;
|
|
}
|
|
|
|
case WM_CREATE:
|
|
{
|
|
infoPtr = (PMONITORSELWND)HeapAlloc(GetProcessHeap(),
|
|
0,
|
|
sizeof(MONITORSELWND));
|
|
if (infoPtr == NULL)
|
|
{
|
|
Ret = (LRESULT)-1;
|
|
break;
|
|
}
|
|
|
|
ZeroMemory(infoPtr,
|
|
sizeof(MONITORSELWND));
|
|
infoPtr->hSelf = hwnd;
|
|
infoPtr->hNotify = ((LPCREATESTRUCTW)lParam)->hwndParent;
|
|
infoPtr->Enabled = !(((LPCREATESTRUCTW)lParam)->style & WS_DISABLED);
|
|
infoPtr->UIState = SendMessage(hwnd,
|
|
WM_QUERYUISTATE,
|
|
0,
|
|
0);
|
|
|
|
SetWindowLongPtrW(hwnd,
|
|
0,
|
|
(LONG_PTR)infoPtr);
|
|
|
|
MonSelCreate(infoPtr);
|
|
break;
|
|
}
|
|
|
|
case WM_DESTROY:
|
|
{
|
|
MonSelDestroy(infoPtr);
|
|
|
|
HeapFree(GetProcessHeap(),
|
|
0,
|
|
infoPtr);
|
|
SetWindowLongPtrW(hwnd,
|
|
0,
|
|
(DWORD_PTR)NULL);
|
|
break;
|
|
}
|
|
|
|
default:
|
|
{
|
|
HandleDefaultMessage:
|
|
Ret = DefWindowProcW(hwnd,
|
|
uMsg,
|
|
wParam,
|
|
lParam);
|
|
break;
|
|
}
|
|
}
|
|
|
|
return Ret;
|
|
}
|
|
|
|
BOOL
|
|
RegisterMonitorSelectionControl(IN HINSTANCE hInstance)
|
|
{
|
|
WNDCLASS wc = {0};
|
|
|
|
wc.style = CS_DBLCLKS;
|
|
wc.lpfnWndProc = MonitorSelWndProc;
|
|
wc.cbWndExtra = sizeof(PMONITORSELWND);
|
|
wc.hInstance = hInstance;
|
|
wc.hCursor = LoadCursorW(NULL,
|
|
(LPWSTR)IDC_ARROW);
|
|
wc.hbrBackground = (HBRUSH)(COLOR_APPWORKSPACE + 1);
|
|
wc.lpszClassName = szMonitorSelWndClass;
|
|
|
|
return RegisterClass(&wc) != 0;
|
|
}
|
|
|
|
VOID
|
|
UnregisterMonitorSelectionControl(IN HINSTANCE hInstance)
|
|
{
|
|
UnregisterClassW(szMonitorSelWndClass,
|
|
hInstance);
|
|
}
|