TIMELINE.C



//==========================================================================//
// Includes //
//==========================================================================//


#include "perfmon.h"
#include "intrline.h"
#include "pmemory.h" // for MemoryXXX (mallloc-type) routines
#include "timeline.h"
#include "perfmops.h" // for SystemTimeDateString, et al.
#include "utils.h"
#include "grafdata.h" // for GraphData

//==========================================================================//
// Typedefs //
//==========================================================================//

typedef struct CHARTDATAPOINTSTRUCT
{
int iLogIndex ;
int xDispDataPoint ;
} CHARTDATAPOINT, *PCHARTDATAPOINT ;

typedef struct TLINESTRUCT
{ // TLINE
HWND hWndILine ;
HFONT hFont ;

SYSTEMTIME SystemTimeBegin ;
SYSTEMTIME SystemTimeEnd ;

int yFontHeight ;
int xMaxTimeWidth ;
int xBegin ;
int xEnd ;

RECT rectStartDate ;
RECT rectStartTime ;
RECT rectStopDate ;
RECT rectStopTime ;

PCHARTDATAPOINT pChartDataPoint ;
int iCurrentStartPos ;
int iCurrentStopPos ;
} TLINE ;

typedef TLINE *PTLINE ;

void PlaybackChartDataPoint (PCHARTDATAPOINT pChartDataPoint) ;

// IntrLineFocus is defined and set/clear in Intrline.c
extern BOOL IntrLineFocus ;

//==========================================================================//
// Constants //
//==========================================================================//


#define dwTLineClassStyle (CS_HREDRAW | CS_VREDRAW)
#define iTLineClassExtra (0)
#define iTLineWindowExtra (sizeof (PTLINE))
#define dwTLineWindowStyle (WS_CHILD | WS_VISIBLE)

HWND hTLineWnd ;
BOOL TLineWindowUp ;



PTLINE TLData (HWND hWndTL)
{
return ((PTLINE) GetWindowLong (hWndTL, 0)) ;
}


PTLINE AllocateTLData (HWND hWndTL)
{
PTLINE pTLine ;
PGRAPHSTRUCT pGraph ;

pGraph = GraphData (hWndGraph) ;

pTLine = MemoryAllocate (sizeof (TLINE)) ;


// see if we have to draw the timeline
if (pGraph &&
iPerfmonView == IDM_VIEWCHART &&
pGraph->pLineFirst &&
pGraph->gOptions.iGraphOrHistogram == LINE_GRAPH)
{
pTLine->pChartDataPoint =
MemoryAllocate (sizeof(CHARTDATAPOINT) *
(pGraph->gTimeLine.iValidValues+1)) ;


if (pTLine->pChartDataPoint != NULL)
{
PlaybackChartDataPoint (pTLine->pChartDataPoint) ;
}
}

SetWindowLong (hWndTL, 0, (LONG) pTLine) ;

return (pTLine) ;
}


int MaxTimeWidth (HDC hDC,
PTLINE pTLine)
/*
Effect: Return a reasonable maximum number of pixels to hold
expected time and date strings.

To Do: When we use the alleged local-date and local-time display
functions, we will modify this routine to use them.
*/
{ // MaxTimeWidth
return (max (TextWidth (hDC, TEXT(" 99 XXX 99 ")),
TextWidth (hDC, TEXT(" 99:99:99.9 PM ")))) ;
} // MaxTimeWidth


void TLGetSystemTimeN (HWND hWnd,
int iInterval,
SYSTEMTIME *pSystemTime)
{ // TLGetSystemTimeN
SendMessage (WindowParent (hWnd),
TL_INTERVAL,
iInterval, (LPARAM) pSystemTime) ;
} // TLGetSystemTimeN



void static TLDrawBeginEnd (HDC hDC,
PTLINE pTLine)
{
TCHAR szDate [20] ;
TCHAR szTime [20] ;

SetTextAlign (hDC, TA_TOP) ;
SelectFont (hDC, pTLine->hFont) ;

// Draw the begin time

SystemTimeDateString (&(pTLine->SystemTimeBegin), szDate) ;
SystemTimeTimeString (&(pTLine->SystemTimeBegin), szTime, TRUE) ;

SetTextAlign (hDC, TA_RIGHT) ;
TextOut (hDC, pTLine->xBegin, 0,
szDate, lstrlen (szDate)) ;
TextOut (hDC, pTLine->xBegin, pTLine->yFontHeight,
szTime, lstrlen (szTime)) ;

// Draw The end time

SystemTimeDateString (&(pTLine->SystemTimeEnd), szDate) ;
SystemTimeTimeString (&(pTLine->SystemTimeEnd), szTime, TRUE) ;

SetTextAlign (hDC, TA_LEFT) ;
TextOut (hDC, pTLine->xEnd, 0,
szDate, lstrlen (szDate)) ;
TextOut (hDC,
pTLine->xEnd,
pTLine->yFontHeight,
szTime, lstrlen (szTime)) ;
}

void TLineRedraw (HDC hGraphDC, PGRAPHSTRUCT pGraph)
{
PTLINE pTLine ;

if (!hTLineWnd)
{
return ;
}

pTLine = TLData (hTLineWnd) ;
if (pTLine == NULL)
{
return ;
}

if (pTLine->iCurrentStartPos)
{
// redraw start line
PatBlt (hGraphDC, pTLine->iCurrentStartPos, pGraph->rectData.top,
1, pGraph->rectData.bottom - pGraph->rectData.top + 1,
DSTINVERT) ;
}

if (pTLine->iCurrentStopPos)
{
// redraw stop line
PatBlt (hGraphDC, pTLine->iCurrentStopPos, pGraph->rectData.top,
1, pGraph->rectData.bottom - pGraph->rectData.top+ 1,
DSTINVERT) ;
}
} // TLineRedraw

void DrawOneTimeIndicator (PTLINE pTLine,
PGRAPHSTRUCT pGraph,
HDC hGraphDC,
int iPos,
int *pCurrentPos)
{
int xPos ;
PCHARTDATAPOINT pDataPoint ;

// check if it is within current selected range
if (iPos >= PlaybackLog.StartIndexPos.iPosition &&
iPos <= PlaybackLog.StopIndexPos.iPosition)
{

xPos = 0 ;
pDataPoint = pTLine->pChartDataPoint ;

// check for the x position of this Log Index
while (pDataPoint->iLogIndex != 0)
{
if (iPos >= pDataPoint->iLogIndex)
{
if ((pDataPoint+1)->iLogIndex == 0)
{
// we have reached the end
xPos = pDataPoint->xDispDataPoint ;
break ;
}
else if (iPos <= (pDataPoint+1)->iLogIndex)
{
// we have found the Log index
xPos = (pDataPoint+1)->xDispDataPoint ;
break ;
}
}
else
{
// no need to continue if iPos is smaller than the
// first Log index on the chart
break ;
}

pDataPoint++ ;
}

if (xPos != *pCurrentPos)
{
if (*pCurrentPos)
{
// erase the old line
PatBlt (hGraphDC, *pCurrentPos, pGraph->rectData.top,
1, pGraph->rectData.bottom - pGraph->rectData.top + 1,
DSTINVERT) ;
}

// draw the new line
*pCurrentPos = xPos ;

if (xPos > 0)
{
PatBlt (hGraphDC, xPos, pGraph->rectData.top,
1, pGraph->rectData.bottom - pGraph->rectData.top + 1,
DSTINVERT) ;
}
}
}
else
{
if (*pCurrentPos)
{
// erase the old line
PatBlt (hGraphDC, *pCurrentPos, pGraph->rectData.top,
1, pGraph->rectData.bottom - pGraph->rectData.top + 1,
DSTINVERT) ;
}

*pCurrentPos = 0 ;
}
} // DrawOneTimeIndicator

void DrawTimeIndicators (PTLINE pTLine, int iStart, int iStop)
{

HDC hGraphDC ;
PGRAPHSTRUCT pGraph ;

pGraph = GraphData (hWndGraph) ;
hGraphDC = GetDC (hWndGraph) ;
if (!hGraphDC || !pGraph)
{
return ;
}

DrawOneTimeIndicator (pTLine, pGraph, hGraphDC, iStart, &pTLine->iCurrentStartPos) ;
DrawOneTimeIndicator (pTLine, pGraph, hGraphDC, iStop, &pTLine->iCurrentStopPos) ;

ReleaseDC (hWndGraph, hGraphDC) ;
}

void static TLDrawStartStop (HWND hWnd,
HDC hDC,
PTLINE pTLine)
/*
Effect: Draw the start and stop date/times on the bottom of the
timeline. Draw the start date/time right justified at the
outer edge of the start point and the stop date/time left
justified with the outer edge of the stop point.

Erase previous start and stop date/times in the process.
*/
{ // TLDrawStartStop
RECT rectDate ;
RECT rectTime ;
RECT rectOpaque ;

TCHAR szDate [30] ;
TCHAR szTime [30] ;

int xStart ;
int xStop ;

int iStart ;
int iStop ;

SYSTEMTIME SystemTimeStart ;
SYSTEMTIME SystemTimeStop ;

int xDateTimeWidth ;


SelectFont (hDC, pTLine->hFont) ;
SetTextAlign (hDC, TA_TOP) ;

//=============================//
// Get Start Information //
//=============================//

xStart = pTLine->xBegin + ILineXStart (pTLine->hWndILine) ;

iStart = ILineStart (pTLine->hWndILine) ;
TLGetSystemTimeN (hWnd, iStart, &SystemTimeStart) ;
SystemTimeDateString (&SystemTimeStart, szDate) ;
SystemTimeTimeString (&SystemTimeStart, szTime, TRUE) ;

xDateTimeWidth = max (TextWidth (hDC, szDate),
TextWidth (hDC, szTime)) ;

//=============================//
// Write Start Date //
//=============================//

rectDate.left = xStart - xDateTimeWidth ;
rectDate.top = pTLine->rectStartDate.top ;
rectDate.right = xStart ;
rectDate.bottom = pTLine->rectStartDate.bottom ;

SetTextAlign (hDC, TA_RIGHT) ;
UnionRect (&rectOpaque, &pTLine->rectStartDate, &rectDate) ;

ExtTextOut (hDC,
rectDate.right, rectDate.top,
ETO_OPAQUE,
&rectOpaque,
szDate, lstrlen (szDate),
NULL) ;
pTLine->rectStartDate = rectDate ;

//=============================//
// Write Start Time //
//=============================//

rectTime.left = rectDate.left ;
rectTime.top = pTLine->rectStartTime.top ;
rectTime.right = rectDate.right ;
rectTime.bottom = pTLine->rectStartTime.bottom ;

UnionRect (&rectOpaque, &pTLine->rectStartTime, &rectTime) ;

ExtTextOut (hDC,
rectTime.right, rectTime.top,
ETO_OPAQUE,
&rectOpaque,
szTime, lstrlen (szTime),
NULL) ;
pTLine->rectStartTime = rectTime ;

if (IntrLineFocus)
{
UnionRect (&rectOpaque, &rectDate, &rectTime) ;
DrawFocusRect (hDC, &rectOpaque) ;
}

//=============================//
// Get Stop Information //
//=============================//

xStop = pTLine->xBegin + ILineXStop (pTLine->hWndILine) ;

iStop = ILineStop (pTLine->hWndILine) ;
TLGetSystemTimeN (hWnd, iStop, &SystemTimeStop) ;
SystemTimeDateString (&SystemTimeStop, szDate) ;
SystemTimeTimeString (&SystemTimeStop, szTime, TRUE) ;

xDateTimeWidth = max (TextWidth (hDC, szDate),
TextWidth (hDC, szTime)) ;

//=============================//
// Write Stop Date //
//=============================//

rectDate.left = xStop ;
rectDate.top = pTLine->rectStopDate.top ;
rectDate.right = xStop + xDateTimeWidth ;
rectDate.bottom = pTLine->rectStopDate.bottom ;

SetTextAlign (hDC, TA_LEFT) ;
UnionRect (&rectOpaque, &pTLine->rectStopDate, &rectDate) ;

ExtTextOut (hDC,
rectDate.left, rectDate.top,
ETO_OPAQUE,
&rectOpaque,
szDate, lstrlen (szDate),
NULL) ;
pTLine->rectStopDate = rectDate ;

//=============================//
// Write Stop Time //
//=============================//

rectTime.left = rectDate.left ;
rectTime.top = pTLine->rectStopTime.top ;
rectTime.right = rectDate.right ;
rectTime.bottom = pTLine->rectStopTime.bottom ;

UnionRect (&rectOpaque, &pTLine->rectStopTime, &rectTime) ;

ExtTextOut (hDC,
rectTime.left, rectTime.top,
ETO_OPAQUE,
&rectOpaque,
szTime, lstrlen (szTime),
NULL) ;
pTLine->rectStopTime = rectTime ;

if (IntrLineFocus)
{
UnionRect (&rectOpaque, &rectDate, &rectTime) ;
DrawFocusRect (hDC, &rectOpaque) ;
}

if (pTLine->pChartDataPoint)
{
DrawTimeIndicators (pTLine, iStart, iStop) ;
}
} // TLDrawStartStop



//==========================================================================//
// Message Handlers //
//==========================================================================//



void static OnCreate (HWND hWnd)
{ // OnCreate
PTLINE pTLine ;
HDC hDC ;

pTLine = AllocateTLData (hWnd) ;

pTLine->hFont = hFontScales ;

hDC = GetDC (hWnd) ;
SelectFont (hDC, hFontScales) ;

pTLine->yFontHeight = FontHeight (hDC, TRUE) ;
pTLine->xMaxTimeWidth = MaxTimeWidth (hDC, pTLine) ;

ReleaseDC (hWnd, hDC) ;

hTLineWnd = hWnd ;
TLineWindowUp = TRUE ;

pTLine->hWndILine =
CreateWindow (szILineClass, // class
NULL, // caption
(WS_VISIBLE | WS_CHILD | WS_TABSTOP ), // window style
0, 0, // position
0, 0, // size
hWnd, // parent window
NULL, // menu
hInstance, // program instance
NULL) ; // user-supplied data
} // OnCreate


void static OnDestroy (HWND hWnd)
{
PTLINE pTLine ;

pTLine = TLData (hWnd) ;

if (pTLine->pChartDataPoint)
{
MemoryFree (pTLine->pChartDataPoint) ;
}

MemoryFree (pTLine) ;

hTLineWnd = 0 ;
TLineWindowUp = FALSE ;

}


void static OnSize (HWND hWnd,
int xWidth,
int yHeight)
/*
Effect: Perform all actions needed when the size of the timeline
hWnd has changed. In particular, determine the appropriate
size for the ILine window and set the rectangles for the
top and bottom displays.
*/
{ // OnSize
PTLINE pTLine ;
int yLine ;
int yDate, yTime ;
int xEnd ;

pTLine = TLData (hWnd) ;

xEnd = xWidth - pTLine->xMaxTimeWidth ;
yLine = pTLine->yFontHeight ;
yDate = yHeight - 2 * yLine ;
yTime = yHeight - yLine ;


SetRect (&pTLine->rectStartDate,
0, yDate, 0, yDate + yLine) ;

SetRect (&pTLine->rectStartTime,
0, yTime, 0, yTime + yLine) ;

SetRect (&pTLine->rectStopDate,
xEnd, yDate, xEnd, yDate + yLine) ;

SetRect (&pTLine->rectStopTime,
xEnd, yTime, xEnd, yTime + yLine) ;

MoveWindow (pTLine->hWndILine,
pTLine->xMaxTimeWidth, 2 * pTLine->yFontHeight,
xWidth - 2 * pTLine->xMaxTimeWidth,
yHeight - 4 * pTLine->yFontHeight,
FALSE) ;

pTLine->xBegin = pTLine->xMaxTimeWidth ;
pTLine->xEnd = xWidth - pTLine->xMaxTimeWidth ;
} // OnSize


void static OnPaint (HWND hWnd)
{
HDC hDC ;
PAINTSTRUCT ps ;
PTLINE pTLine ;

hDC = BeginPaint (hWnd, &ps) ;

pTLine = TLData (hWnd) ;
TLDrawBeginEnd (hDC, pTLine) ;
TLDrawStartStop (hWnd, hDC, pTLine) ;

EndPaint (hWnd, &ps) ;
}


void static OnILineChanged (HWND hWnd)
{
HDC hDC ;
PTLINE pTLine ;

pTLine = TLData (hWnd) ;

hDC = GetDC (hWnd) ;
TLDrawStartStop (hWnd, hDC, pTLine) ;
ReleaseDC (hWnd, hDC) ;
}


//==========================================================================//
// Exported Functions //
//==========================================================================//


LONG FAR PASCAL TLineWndProc (HWND hWnd,
unsigned msg,
WPARAM wParam,
LONG lParam)
/*
Note: This function must be declared in the application's
linker-definition file, perfmon.def file.
*/
{ // TLineWndProc
BOOL bCallDefWindowProc ;
LONG lReturnValue ;

bCallDefWindowProc = FALSE ;
lReturnValue = 0L ;

switch (msg)
{ // switch
case WM_SETFOCUS:
{
PTLINE pTLine ;

pTLine = TLData (hWnd) ;
SetFocus (pTLine->hWndILine) ;
}
return 0 ;

case WM_KILLFOCUS:
return 0 ;

case WM_COMMAND:
OnILineChanged (hWnd) ;
break ;

case WM_CREATE:
OnCreate (hWnd) ;
break ;

case WM_DESTROY:
OnDestroy (hWnd) ;
break ;

case WM_PAINT:
OnPaint (hWnd) ;
break ;

case WM_SIZE:
OnSize (hWnd, LOWORD (lParam), HIWORD (lParam)) ;
break ;

default:
bCallDefWindowProc = TRUE ;
} // switch

if (bCallDefWindowProc)
lReturnValue = DefWindowProc (hWnd, msg, wParam, lParam) ;

return (lReturnValue) ;
} // TLineWndProc



BOOL TLineInitializeApplication (void)
/*
Effect: Perform all initializations required before an application
can create an IntervalLine. In particular, register the
IntervalLine window class.

Called By: The application, in its InitializeApplication routine.

Returns: Whether the class could be registered.
*/
{ // TLineInitializeApplication
WNDCLASS wc ;

wc.style = dwTLineClassStyle ;
wc.lpfnWndProc = TLineWndProc ;
wc.cbClsExtra = iTLineClassExtra ;
wc.cbWndExtra = iTLineWindowExtra ;
wc.hInstance = hInstance ;
wc.hIcon = NULL ;
wc.hCursor = LoadCursor (NULL, IDC_ARROW) ;
wc.hbrBackground = (HBRUSH) (COLOR_WINDOW + 1) ;
wc.lpszMenuName = NULL ;
wc.lpszClassName = szTLineClass ;

return (RegisterClass (&wc)) ;
} // TLineInitializeApplication


void TLineSetRange (HWND hWnd,
int iBegin,
int iEnd)
{
PTLINE pTLine ;

pTLine = TLData (hWnd) ;

ILineSetRange (pTLine->hWndILine, iBegin, iEnd) ;
TLGetSystemTimeN (hWnd, iBegin, &pTLine->SystemTimeBegin) ;
TLGetSystemTimeN (hWnd, iEnd, &pTLine->SystemTimeEnd) ;
}


void TLineSetStart (HWND hWnd,
int iStart)
{
PTLINE pTLine ;

pTLine = TLData (hWnd) ;
ILineSetStart (pTLine->hWndILine, iStart) ;
}


void TLineSetStop (HWND hWnd,
int iStop)
{
PTLINE pTLine ;

pTLine = TLData (hWnd) ;
ILineSetStop (pTLine->hWndILine, iStop) ;
}


int TLineStart (HWND hWnd)
{
PTLINE pTLine ;

pTLine = TLData (hWnd) ;

return (ILineStart (pTLine->hWndILine)) ;
}


int TLineStop (HWND hWnd)
{
PTLINE pTLine ;

pTLine = TLData (hWnd) ;

return (ILineStop (pTLine->hWndILine)) ;
}