📄 freebusydisplayitem.cpp
字号:
WCHAR *wszTitle,
UINT cchTitle
)
{
PREFAST_ASSERT(wszTitle);
//only draw if we have FB information
if (! m_wstrFreeBusy[0] )
{
wszTitle[0] = 0;
return S_FALSE;
}
HRESULT hr = S_OK;
SYSTEMTIME stNow = {0},
stEnd = {0};
const WCHAR *c_wszDefault = NULL,
*c_wszFmt = NULL,
*c_wszStatus = NULL,
*c_wszNextStatus = NULL;
UINT idxNow = 0;
INT idxChange = 0;
WORD wHourChange, wMinuteChange;
DWORD rgdwFormatMessage[3] = {0};
GetLocalTime(&stNow);
IncrementTime(&stEnd, &m_stStart, c_nTotalWindowHours);
//if the current time if before the start of the work day, or after the end
//of the work day. The string is the default "today's FB status string"
//uses overloaded operator> and operator<
if (stNow < m_stStart || stNow > stEnd)
{
goto use_default;
}
//otherwise we have a valid time within the "visible" fb status range
//We need to determine the current value, by finding the index in the string
//that reprensents the current time.
idxNow = \
(HourDifference(&stNow, &m_stStart) * INTERVALS_PER_HOUR) + //this brings us to the current hour
(stNow.wMinute / c_FreeBusyIntervalAmount); //add the appropriate minute intervals
if (idxNow > m_wstrFreeBusy.length()-1)
{
goto use_default;
}
//OK - we are currently have a status (e.g. "free") - we need to find when that status changes
//If can either be a time, or off the end of the fb string
//We need this to determine XXXX in the string "Free until XXXX"
idxChange = idxNow;
while (
m_wstrFreeBusy[idxChange] == m_wstrFreeBusy[idxNow] &&
idxChange < m_wstrFreeBusy.length()-1
)
{
idxChange++;
}
if (m_wstrFreeBusy[idxChange] == m_wstrFreeBusy[idxNow])
{
idxChange = -1;
}
//Determine the format of the string to use
c_wszStatus = GetStatusString(CharToFBStatus(m_wstrFreeBusy[idxNow]));
c_wszFmt = CommonUtilities_t::LoadString(GlobalData_t::s_ModuleInstance,
(idxChange == -1) ? IDS_FMT_FREEBUSY_FORTHERESTOFTHEDAY :
IDS_FMT_FREEBUSY_UNTIL
);
if (c_wszStatus == NULL || c_wszFmt == NULL)
{
goto use_default;
}
//if this status lasts doesn't go to the end of the day, we need to figure out the
//human-readable time in which it changes (e.g. 3:30)
if (idxChange != -1)
{
wHourChange = ((m_stStart.wHour + (idxChange / INTERVALS_PER_HOUR)) % 24);
if (! wHourChange ) wHourChange = 12; //if the hour was "24" or 12AM
wMinuteChange = (idxChange % INTERVALS_PER_HOUR) * c_FreeBusyIntervalAmount;
}
//format the args for the call to FormatMessage
rgdwFormatMessage[0] = (DWORD)c_wszStatus;
rgdwFormatMessage[1] = (DWORD)((wHourChange > 12) ? wHourChange%12 : wHourChange);
rgdwFormatMessage[2] = (DWORD)wMinuteChange;
return CommonUtilities_t::ToHR(FormatMessage(
FORMAT_MESSAGE_ARGUMENT_ARRAY | FORMAT_MESSAGE_FROM_STRING,
c_wszFmt,
0,
0,
wszTitle,
cchTitle,
(va_list*)rgdwFormatMessage
) != 0);
use_default:
//if something went wrong, load and use the default string
c_wszDefault = CommonUtilities_t::LoadString(GlobalData_t::s_ModuleInstance, IDS_FMT_FREEBUSY_DEFAULT);
if (! c_wszDefault)
{
ASSERT(FALSE);
return E_UNEXPECTED;
}
StringCchCopy(
wszTitle,
cchTitle,
c_wszDefault
);
return S_OK;
}
/*------------------------------------------------------------------------------
CFreeBusyDisplayItem::DrawFreeBusyTitle
Draw the free busy title (e.g. "Free until 3:15")
------------------------------------------------------------------------------*/
HRESULT CFreeBusyDisplayItem::DrawFreeBusyTitle(
HDC hdc,
const RECT * prc
)
{
PREFAST_ASSERT(prc);
PaintHelper_t paint;
HRESULT hr = paint.Attach(hdc);
if (FAILED(hr))
{
ASSERT(FALSE);
return hr;
}
RECT rcDraw = {0};
WCHAR wszBuf[255] = L"";
hr = GetFreeBusyTitle(
wszBuf,
_countof(wszBuf)
);
if (FAILED(hr))
{
ASSERT(FALSE);
return hr;
}
//Draw the status
rcDraw = *prc;
rcDraw.left += Layout_t::FreeBusyMarginWidth();
rcDraw.top += Layout_t::FreeBusyStatusYOffset();
paint.SetFont(PHGetFont(phfInformationText));
hr = paint.DrawText(
wszBuf,
-1,
&rcDraw,
DT_TOP | DT_LEFT | DT_SINGLELINE | DT_NOPREFIX
);
//restore the dc
paint.End();
return hr;
}
/*------------------------------------------------------------------------------
CFreeBusyDisplayItem::DrawFreeBusyGraphics
Draw the freebusy graphics (e.g. blueblock, whiteblock, ...)
------------------------------------------------------------------------------*/
HRESULT CFreeBusyDisplayItem::DrawFreeBusyGraphics(
HDC hdc,
const RECT * prc
)
{
PREFAST_ASSERT(prc);
if (! m_wstrFreeBusy[0])
{
return S_FALSE;
}
HRESULT hr = S_OK;
RECT rcDraw = *prc;
ce::auto_hpen hpnBorder;
HPEN hpnOld;
HBRUSH hbrBackground = NULL,
hbrOld = NULL;
HFONT hfntNumbers = NULL,
hfntOld = NULL;
INT TotalWidth = prc->right - prc->left;
const UINT c_cxGraphicsWidthMax = (TotalWidth - 2*Layout_t::FreeBusyMarginWidth() - 2), // 1 px border on each side of the rect
c_cxPixelPerInterval = (c_cxGraphicsWidthMax / DISPLAY_INTERVALS),
c_cxPixelPerHour = (c_cxPixelPerInterval * INTERVALS_PER_HOUR),
c_cxGraphicsWidth = (c_cxPixelPerInterval * DISPLAY_INTERVALS) + 2; //add 2 - to account for the 1 px border on each side
//Format the rectangle for drawing
rcDraw.left += Layout_t::FreeBusyMarginWidth();
rcDraw.right = rcDraw.left + c_cxGraphicsWidth;
rcDraw.top += Layout_t::FreeBusyGraphicsYOffset();
rcDraw.bottom = rcDraw.top + Layout_t::FreeBusyGraphicsHeight();
hpnBorder = ::CreatePen(PS_SOLID, -1, Colors_t::FreeBusy_GraphicsOutline());
if (hpnBorder == NULL)
{
hr = CommonUtilities_t::GetErrorFromWin32();
}
//First draw the border rectangle
if (SUCCEEDED(hr))
{
hpnOld = (HPEN) SelectObject(hdc, hpnBorder);
hbrOld = (HBRUSH)SelectObject(hdc, GetStockObject(HOLLOW_BRUSH));
hr = CommonUtilities_t::ToHR(Rectangle(
hdc,
rcDraw.left,
rcDraw.top,
rcDraw.right,
rcDraw.bottom
));
SelectObject(hdc, hpnOld);
SelectObject(hdc, hbrOld);
}
//Next draw inside the border rectangle
if (SUCCEEDED(hr))
{
//Don't draw over the border rectangle
rcDraw.left++;
rcDraw.top++;
rcDraw.right--;
rcDraw.bottom--;
//Draw in "runs" (e.g. draw the current status + all the statuses adjacent that
//have the same status) - example: 0000000111111111000 will draw 3 times - a block of
//0's a block of 1's and then another block of 0's
UINT idxCurrentValue = 0,
idxMax = INTERVALS_PER_HOUR*c_nTotalWindowHours;
while (idxCurrentValue < idxMax)
{
UINT idxChange = idxCurrentValue+1;
ce::auto_hbrush hbrDraw;
//Determine when the run ends
while (
m_wstrFreeBusy[idxChange] == m_wstrFreeBusy[idxCurrentValue] &&
idxChange < idxMax
)
{
idxChange++;
}
//Fill the rect with the necessary brush
rcDraw.right = rcDraw.left + (c_cxPixelPerInterval * (idxChange - idxCurrentValue));
hr = DrawRun(
hdc,
&rcDraw,
m_wstrFreeBusy[idxCurrentValue]
);
if (FAILED(hr))
{
break;
}
rcDraw.left = rcDraw.right;
idxCurrentValue = idxChange;
}
}
//Now draw the "now" line, in the appropriate place
if (SUCCEEDED(hr))
{
SYSTEMTIME stNow = {0},
stEnd = {0};
GetLocalTime (&stNow);
IncrementTime(&stEnd, &m_stStart, c_nTotalWindowHours);
//validate that "now" is within our drawing window
if (stNow > m_stStart && stNow < stEnd)
{
ce::auto_hpen hpnDraw = ::CreatePen(PS_SOLID, -1, Colors_t::FreeBusy_NowLine());
hpnOld = (HPEN)SelectObject(hdc, hpnDraw);
//Determine the x value of the drawing line (top and bottom or rcDraw are still accurate)
INT xDraw =
prc->left +
Layout_t::FreeBusyMarginWidth() +
1 +
(HourDifference(&stNow, &m_stStart) * c_cxPixelPerHour) + //pixels in an hour
((stNow.wMinute * c_cxPixelPerHour) / (MINUTES_IN_HOUR)) //percentage of px in an hour
;
POINT rgptDraw[] =
{
xDraw, rcDraw.top,
xDraw, rcDraw.bottom
};
//Draw the line
hr = CommonUtilities_t::ToHR(Polyline(
hdc,
rgptDraw,
_countof(rgptDraw)
));
//restore the dc
SelectObject(hdc, hpnOld);
}
}
//Now draw the time, under the rectangle
if (SUCCEEDED(hr))
{
hfntNumbers = PHGetFont(phfStandardText);
hr = CommonUtilities_t::ToHR(hfntNumbers != NULL);
}
if (SUCCEEDED(hr))
{
//Set up the rectangle for the numbers drawing
rcDraw.top = prc->top + Layout_t::FreeBusyClockYOffset();
rcDraw.bottom = prc->bottom;
rcDraw.left = prc->left + Layout_t::FreeBusyMarginWidth() - 1;
hfntOld = (HFONT)SelectObject(hdc, hfntNumbers);
//Draw each number in our range
for (UINT i = 0; i <= c_nTotalWindowHours; i++)
{
rcDraw.right = rcDraw.left + c_cxPixelPerHour;
WCHAR wszHour[4] = L"";
INT hour = i + m_stStart.wHour;
while (hour > 12)
{
hour -= 12;
}
_snwprintf(wszHour, _countof(wszHour), L"%d", hour % 13);
wszHour[_countof(wszHour) - 1] = L'\0';
hr = CommonUtilities_t::ToHR(::DrawText(
hdc,
wszHour,
-1,
&rcDraw,
DT_TOP | DT_LEFT | DT_SINGLELINE | DT_NOPREFIX
));
if (FAILED(hr))
{
ASSERT(FALSE);
break;
}
rcDraw.left = rcDraw.right;
}
//restore the dc
SelectObject(hdc, hfntOld);
}
return hr;
}
/*------------------------------------------------------------------------------
CFreeBusyDisplayItem::GetSubItemText
Helper function for automation - get each components text
------------------------------------------------------------------------------*/
HRESULT CFreeBusyDisplayItem::GetSubItemText(
int idxSubItem,
WCHAR * wszBuffer,
UINT cchBuffer
)
{
HRESULT hr = S_OK;
UINT idx = 0;
switch (idxSubItem)
{
case c_siDisplayName:
StringCchCopy(
wszBuffer,
cchBuffer,
m_wstrDisplayName
);
break;
#ifdef AUTOMATION
case c_siFreeBusyData:
StringCchCopy(
wszBuffer,
cchBuffer,
m_wstrFreeBusy
);
break;
case c_siFreeBusyStatus:
GetFreeBusyTitle(
wszBuffer,
cchBuffer
);
break;
case c_siBoundaries:
{
SYSTEMTIME stNow = {0}, stEnd = {0};
GetLocalTime(&stNow);
IncrementTime(&stEnd, &m_stStart, c_nTotalWindowHours);
_snwprintf(
wszBuffer,
cchBuffer,
L"Start: %d$Now: %d:%d$End:%d",
((m_stStart.wHour > 12) ? m_stStart.wHour - 12 : m_stStart.wHour) % 13,
stNow.wHour, stNow.wMinute,
((stEnd.wHour > 12) ? stEnd.wHour - 12 : stEnd.wHour) % 13
);
}
break;
#endif
default:
hr = S_FALSE;
break;
}
wszBuffer[ cchBuffer - 1 ] = 0;
return hr;
}
/*------------------------------------------------------------------------------
CFreeBusyDisplayItem::GetText
Gets the DiplayName text of the item
------------------------------------------------------------------------------*/
HRESULT CFreeBusyDisplayItem::GetText(
WCHAR * wszBuffer,
INT cchBuffer
)
{
return GetSubItemText(c_siDisplayName, wszBuffer, cchBuffer);
}
/*------------------------------------------------------------------------------
CFreeBusyDisplayItem::NeedsToolTip
Determine if this item needs tool tip.
------------------------------------------------------------------------------*/
BOOL CFreeBusyDisplayItem::NeedsToolTip(
RECT *prc
)
{
if (! prc)
{
return FALSE;
}
return !CanDrawOnOneLine(
phfStandardTextBold,
m_wstrDisplayName,
m_wstrDisplayName.length(),
prc->right - prc->left
);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -