|
|
1.1 root 1: /*
2: ==============================================================================
3:
4: Application:
5:
6: Microsoft Windows NT (TM) Performance Monitor
7:
8: File:
9: legend.c - legend window routines.
10:
11: This file contains code creating the legend window, which is
12: a child of the graph windows. The legend window displays a
13: legend line for each line in the associated graph. It also
14: includes an area called the label, which are headers for those
15: lines.
16:
17:
18: Copyright 1992, Microsoft Corporation. All Rights Reserved.
19: ==============================================================================
20: */
21:
22:
23: //==========================================================================//
24: // Includes //
25: //==========================================================================//
26:
27:
28: #include <stdio.h> // for sprintf
29: #include "perfmon.h"
30: #include "legend.h" // external declarations for this file
31:
32: #include "owndraw.h"
33:
34: #include "alert.h" // for EditAlert
35: #include "grafdata.h" // for EditChart
36: #include "pmemory.h" // for MemoryXXX (mallloc-type) routines
37: #include "utils.h"
38: #include "valuebar.h" // for StatusTimer
39: #include "playback.h" // for PlayingBackLog()
40:
41: #define eScaleValueSpace TEXT(">9999999999.0")
42:
43: //==========================================================================//
44: // Constants //
45: //==========================================================================//
46:
47:
48: #define dwGraphLegendClassStyle (CS_HREDRAW | CS_VREDRAW)
49: #define iGraphLegendClassExtra (0)
50: #define iGraphLegendWindowExtra (sizeof (PLEGEND))
51: #define dwGraphLegendWindowStyle (WS_CHILD | WS_VISIBLE)
52:
53: #define xLegendBorderWidth (xDlgBorderWidth)
54: #define yLegendBorderHeight (yDlgBorderHeight)
55:
56: #define iLabelLen 30
57: #define iLegendColMax 1000
58:
59: #define LEFTORIENTATION 1
60: #define CENTERORIENTATION 2
61: #define RIGHTORIENTATION 3
62:
63: #define LegendColorCol 0
64: #define LegendScaleCol 1
65: #define LegendCounterCol 2
66: #define LegendInstanceCol 3
67: #define LegendParentCol 4
68: #define LegendObjectCol 5
69: #define LegendSystemCol 6
70:
71: #define iLegendNumCols 7
72:
73: #define iLegendMaxVisibleItems 8
74:
75: #define dwGraphLegendItemsWindowClass TEXT("ListBox")
76: #define dwGraphLegendItemsWindowStyle \
77: (LBS_NOTIFY | LBS_NOINTEGRALHEIGHT | LBS_OWNERDRAWFIXED | \
78: WS_VISIBLE | WS_CHILD | WS_VSCROLL)
79:
80:
81: //==========================================================================//
82: // Typedefs //
83: //==========================================================================//
84:
85:
86: typedef struct LEGENDCOLSTRUCT
87: {
88: TCHAR szLabel [iLabelLen] ;
89: int xMinWidth ;
90: int xMaxWidth ;
91: int xWidth ;
92: int xPos ;
93: int iOrientation ;
94: } LEGENDCOL ;
95:
96: typedef LEGENDCOL *PLEGENDCOL ;
97:
98:
99: typedef struct LEGENDTRUCT
100: {
101: HWND hWndItems ;
102: HFONT hFontItems ;
103: HFONT hFontLabels ;
104: int xMinWidth ;
105: int yLabelHeight ;
106: int yItemHeight ;
107: int iNumItemsVisible ;
108: LEGENDCOL aCols [iLegendNumCols] ;
109: int iLineType ;
110: PLINE pCurrentLine ; // current selected line
111: } LEGEND ;
112:
113: typedef LEGEND *PLEGEND ;
114:
115:
116: //==========================================================================//
117: // Macros //
118: //==========================================================================//
119:
120:
121: #define LabelTopMargin() (2)
122: #define LegendLeftMargin() (3 + ThreeDPad)
123:
124: #define LegendItemTopMargin() (yBorderHeight)
125:
126:
127: #define IsLegendLabelVisible() (TRUE)
128:
129: #define ColCanGrow(pCol) \
130: (pCol->xMaxWidth > pCol->xWidth)
131:
132:
133: #define LegendHorzMargin() (3)
134:
135:
136:
137: //==========================================================================//
138: // Local Data //
139: //==========================================================================//
140:
141:
142: // LEGEND Legend ;
143: PLEGEND pGraphLegendData ;
144: PLEGEND pAlertLegendData ;
145:
146: #define LegendData(hWnd) \
147: ((hWnd == hWndGraphLegend) ? pGraphLegendData : pAlertLegendData )
148:
149: //==========================================================================//
150: // Local Functions //
151: //==========================================================================//
152: void LegendSetCurrentLine (PLEGEND pLegend, int iIndex)
153: {
154: pLegend->pCurrentLine =
155: (PLINESTRUCT) LBData (pLegend->hWndItems, iIndex) ;
156:
157: if (pLegend->pCurrentLine == (PLINESTRUCT) LB_ERR)
158: {
159: pLegend->pCurrentLine = NULL ;
160: }
161: } // LegendSetCurrentLine
162:
163: #if 0
164: PLEGEND LegendData (HWND hWnd)
165: {
166: return ((PLEGEND) GetWindowLong (hWnd, 0)) ;
167: }
168: #endif
169:
170:
171: PLEGEND AllocateLegendData (HWND hWnd, BOOL bChartLegend)
172: {
173: PLEGEND pLegend ;
174:
175: pLegend = MemoryAllocate (sizeof (LEGEND)) ;
176: // SetWindowLong (hWnd, 0, (LONG) pLegend) ;
177:
178: if (bChartLegend)
179: {
180: hWndGraphLegend = hWnd ;
181: pGraphLegendData = pLegend ;
182: }
183: else
184: {
185: hWndAlertLegend = hWnd ;
186: pAlertLegendData = pLegend ;
187: }
188:
189: return (pLegend) ;
190: }
191:
192:
193:
194: void DrawLegendLabel (PLEGEND pLegend,
195: HDC hDC,
196: HWND hWnd)
197: { // DrawLegendLabel
198: int i ;
199: int xPos ;
200: RECT rect ;
201: RECT rectLB ;
202: INT LocalThreeDPad = ThreeDPad - 1 ;
203:
204: SetBkColor (hDC, crLightGray) ;
205:
206: SelectFont (hDC, pLegend->hFontLabels) ;
207:
208: GetClientRect (hWnd, &rect) ;
209: // Fill (hDC, crLightGray, &rect) ;
210: ExtTextOut (hDC, rect.left, rect.top,
211: ETO_OPAQUE, &(rect), NULL, 0, NULL ) ;
212:
213: GetWindowRect (pLegend->hWndItems, &rectLB) ;
214: ScreenRectToClient (hWnd, &rectLB) ;
215: ThreeDConcave1 (hDC,
216: rectLB.left - LocalThreeDPad,
217: rectLB.top - LocalThreeDPad,
218: rectLB.right + LocalThreeDPad,
219: rectLB.bottom + LocalThreeDPad) ;
220:
221: for (i = 0 ;
222: i < iLegendNumCols ;
223: i++)
224: { // for
225: rect.left = pLegend->aCols[i].xPos ;
226: rect.top = yBorderHeight ;
227: rect.right = rect.left + pLegend->aCols[i].xWidth - LegendHorzMargin () ;
228: rect.bottom = pLegend->yLabelHeight ;
229:
230: switch (pLegend->aCols[i].iOrientation)
231: { // switch
232: case LEFTORIENTATION:
233: SetTextAlign (hDC, TA_LEFT) ;
234: xPos = rect.left ;
235: break ;
236:
237: case CENTERORIENTATION:
238: SetTextAlign (hDC, TA_CENTER) ;
239: xPos = (rect.left + rect.right) / 2 ;
240: break ;
241:
242: case RIGHTORIENTATION:
243: SetTextAlign (hDC, TA_RIGHT) ;
244: xPos = rect.right ;
245: break ;
246:
247: default:
248: xPos = rect.left ;
249: break ;
250: } // switch
251:
252: ExtTextOut (hDC,
253: xPos, rect.top,
254: ETO_OPAQUE,
255: &rect,
256: pLegend->aCols[i].szLabel,
257: lstrlen (pLegend->aCols[i].szLabel),
258: NULL) ;
259: } // for
260: } // DrawLegendLabel
261:
262:
263:
264: void DrawColorCol (PLEGEND pLegend,
265: PLINE pLine,
266: int iCol,
267: HDC hDC,
268: int yPos)
269: /*
270: Effect: Draw the "color" column of a legend entry. The color
271: column displays a small sample of the line drawing.
272:
273: For charts, the sample is a line of the correct style,
274: color, and width. Since we are using wide lines,
275: the round endcaps of the lines will breach the column.
276: Therefore we need to set the clip region. We could
277: remove this clipping if we find a way to change the
278: end cap design.
279:
280: For alerts, the sample is a small circle which echos
281: the design in the alert log itself.
282: */
283: { // DrawColorCol
284: HBRUSH hBrush, hBrushPrevious ;
285: RECT rect ;
286: int yMiddle ;
287: int iCircle ;
288:
289:
290:
291: rect.left = pLegend->aCols[iCol].xPos - LegendLeftMargin () + 2 ;
292: rect.top = yPos + 1 ;
293: rect.right = rect.left + pLegend->aCols[iCol].xWidth - LegendHorzMargin () ;
294: rect.bottom = yPos + pLegend->yItemHeight - 1 ;
295:
296: yMiddle = rect.top + (rect.bottom - rect.top) / 2 ;
297: iCircle = rect.bottom - rect.top - 2 ;
298:
299: switch (pLegend->iLineType)
300: { // switch
301: case LineTypeChart:
302:
303: if (pLine->Visual.iWidth == 1)
304: {
305: // simple case with thin pen
306: hBrush = SelectBrush (hDC, hbLightGray) ;
307: Rectangle (hDC, rect.left, rect.top, rect.right, rect.bottom) ;
308:
309: HLine (hDC, pLine->hPen,
310: rect.left + 1, rect.right - 1, yMiddle) ;
311: SelectBrush (hDC, hBrush) ;
312: }
313: else
314: {
315: // thicker pen width, have to set ClipRect so
316: // it will not draw otherside the rect.
317: SaveDC (hDC) ;
318: hBrush = SelectBrush (hDC, hbLightGray) ;
319: Rectangle (hDC, rect.left, rect.top, rect.right, rect.bottom) ;
320:
321: IntersectClipRect (hDC,
322: rect.left + 1,
323: rect.top + 1,
324: rect.right - 1,
325: rect.bottom - 1) ;
326: HLine (hDC, pLine->hPen,
327: rect.left + 1, rect.right - 1, yMiddle) ;
328: SelectBrush (hDC, hBrush) ;
329: RestoreDC (hDC, -1) ;
330: }
331: break ;
332:
333:
334: case LineTypeAlert:
335: hBrushPrevious = SelectBrush (hDC, pLine->hBrush) ;
336:
337: Ellipse (hDC,
338: rect.left + 2,
339: rect.top + 2,
340: rect.left + 2 + iCircle,
341: rect.top + 2 + iCircle) ;
342:
343: SelectBrush (hDC, hBrushPrevious) ;
344: break ;
345: } // switch
346:
347: } // DrawColorCol
348:
349:
350: void DrawLegendCol (PLEGEND pLegend,
351: int iCol,
352: HDC hDC,
353: int yPos,
354: LPTSTR lpszValue)
355: /*
356: Effect: Draw the value lpszValue for the column iCol on hDC.
357:
358: Assert: The foreground and background text colors of hDC are
359: properly set.
360: */
361: { // DrawLegendCol
362: RECT rect ;
363: int xPos ;
364:
365: rect.left = pLegend->aCols[iCol].xPos - LegendLeftMargin () ;
366: rect.top = yPos ;
367: rect.right = rect.left + pLegend->aCols[iCol].xWidth - LegendHorzMargin () ;
368: rect.bottom = yPos + pLegend->yItemHeight ;
369:
370: // SetTextAlign (hDC, TA_TOP) ;
371: switch (pLegend->aCols[iCol].iOrientation)
372: { // switch
373: case LEFTORIENTATION:
374: SetTextAlign (hDC, TA_LEFT) ;
375: xPos = rect.left ;
376: break ;
377:
378: case CENTERORIENTATION:
379: SetTextAlign (hDC, TA_CENTER) ;
380: xPos = (rect.left + rect.right) / 2 ;
381: break ;
382:
383: case RIGHTORIENTATION:
384: SetTextAlign (hDC, TA_RIGHT) ;
385: xPos = rect.right ;
386: break ;
387:
388: default:
389: xPos = rect.left ;
390: break ;
391: } // switch
392:
393: ExtTextOut (hDC,
394: xPos, rect.top + LegendItemTopMargin (),
395: ETO_OPAQUE | ETO_CLIPPED,
396: &rect,
397: lpszValue,
398: lstrlen (lpszValue),
399: NULL) ;
400: } // DrawLegendCol
401:
402:
403: void DrawLegendItem (PLEGEND pLegend,
404: PLINESTRUCT pLine,
405: int yPos,
406: HDC hDC)
407: {
408: TCHAR szValue [256] ;
409: TCHAR szInstance [256] ;
410: TCHAR szParent [256] ;
411: TCHAR szNoName[4] ;
412:
413: szNoName[0] = szNoName[1] = szNoName[2] = TEXT('-') ;
414: szNoName[3] = TEXT('\0') ;
415:
416: //=============================//
417: // Determine Instance, Parent //
418: //=============================//
419:
420: // It's possible that there will be no instance, therefore
421: // the lnInstanceName would be NULL.
422:
423: if (pLine->lnObject.NumInstances > 0)
424: {
425: // Test for the parent object instance name title index.
426: // If there is one, it implies that there will be a valid
427: // Parent Object Name and a valid Parent Object Instance Name.
428:
429: // If the Parent Object title index is 0 then
430: // just display the instance name.
431:
432: lstrcpy (szInstance, pLine->lnInstanceName) ;
433: if (pLine->lnInstanceDef.ParentObjectTitleIndex &&
434: pLine->lnPINName)
435: {
436: // Get the Parent Object Name.
437: lstrcpy (szParent, pLine->lnPINName) ;
438: }
439: else
440: {
441: lstrcpy (szParent, szNoName) ;
442: }
443: }
444: else
445: {
446: lstrcpy (szInstance, szNoName) ;
447: lstrcpy (szParent, szNoName) ;
448: }
449:
450: //=============================//
451: // Draw Color //
452: //=============================//
453:
454: DrawColorCol (pLegend, pLine, LegendColorCol, hDC, yPos) ;
455:
456: //=============================//
457: // Draw Scale/Value //
458: //=============================//
459:
460: if (pLegend->iLineType == LineTypeChart)
461: {
462: if (pLine->eScale < (FLOAT) 1.0)
463: {
464: TSPRINTF (szValue, TEXT("%6.6f"), pLine->eScale) ;
465: }
466: else
467: {
468: TSPRINTF (szValue, TEXT("%10.3f"), pLine->eScale) ;
469: }
470: }
471: else
472: {
473: FLOAT tempAlertValue ;
474:
475: tempAlertValue = pLine->eAlertValue ;
476: if (tempAlertValue < (FLOAT) 0.0)
477: {
478: tempAlertValue = -tempAlertValue ;
479: }
480:
481: if (tempAlertValue >= (FLOAT) 10000.0)
482: {
483: if (tempAlertValue < (FLOAT) 1.0E+8)
484: {
485: TSPRINTF (szValue, TEXT("%c%10.0f"),
486: pLine->bAlertOver ? TEXT('>') : TEXT('<'),
487: pLine->eAlertValue) ;
488: }
489: else
490: {
491: TSPRINTF (szValue, TEXT("%c%10.3e"),
492: pLine->bAlertOver ? TEXT('>') : TEXT('<'),
493: pLine->eAlertValue) ;
494: }
495: }
496: else
497: {
498: TSPRINTF (szValue, TEXT("%c%10.4f"),
499: pLine->bAlertOver ? TEXT('>') : TEXT('<'),
500: pLine->eAlertValue) ;
501: }
502: }
503:
504: SetTextAlign (hDC, TA_TOP) ;
505:
506: DrawLegendCol (pLegend, LegendScaleCol,
507: hDC, yPos, szValue) ;
508:
509:
510: //=============================//
511: // Draw Counter //
512: //=============================//
513:
514: DrawLegendCol (pLegend, LegendCounterCol,
515: hDC, yPos, pLine->lnCounterName) ;
516:
517:
518: //=============================//
519: // Draw Instance //
520: //=============================//
521:
522: DrawLegendCol (pLegend, LegendInstanceCol,
523: hDC, yPos, szInstance) ;
524:
525: //=============================//
526: // Draw Parent //
527: //=============================//
528:
529: DrawLegendCol (pLegend, LegendParentCol,
530: hDC, yPos, szParent) ;
531:
532: //=============================//
533: // Draw Object //
534: //=============================//
535:
536: DrawLegendCol (pLegend, LegendObjectCol,
537: hDC, yPos, pLine->lnObjectName) ;
538:
539: //=============================//
540: // Draw System //
541: //=============================//
542:
543: DrawLegendCol (pLegend, LegendSystemCol,
544: hDC, yPos, pLine->lnSystemName) ;
545:
546: }
547:
548:
549: //==========================================================================//
550: // Message Handlers //
551: //==========================================================================//
552:
553:
554: BOOL OnLegendCreate (HWND hWnd, LPCREATESTRUCT lpCS)
555: {
556: PLEGEND pLegend ;
557: HDC hDC ;
558: int iCol ;
559: BOOL bChartLegend ;
560:
561: bChartLegend = (lpCS->lpCreateParams) == (LPVOID) TRUE ;
562:
563: pLegend = AllocateLegendData (hWnd, bChartLegend) ;
564:
565: if (!pLegend)
566: return (FALSE) ;
567:
568: if (bChartLegend)
569: {
570: pLegend->iLineType = LineTypeChart ;
571: }
572: else
573: {
574: pLegend->iLineType = LineTypeAlert ;
575: }
576:
577: pLegend->hFontItems = hFontScales ;
578: pLegend->hFontLabels = hFontScalesBold ;
579: hDC = GetDC (hWnd) ;
580:
581: //=============================//
582: // Load Labels //
583: //=============================//
584:
585: StringLoad (IDS_LABELCOLOR, pLegend->aCols[LegendColorCol].szLabel) ;
586: if (pLegend->iLineType == LineTypeChart)
587: StringLoad (IDS_LABELSCALE,
588: pLegend->aCols[LegendScaleCol].szLabel) ;
589: else
590: StringLoad (IDS_LABELVALUE,
591: pLegend->aCols[LegendScaleCol].szLabel) ;
592: StringLoad (IDS_LABELCOUNTER, pLegend->aCols[LegendCounterCol].szLabel) ;
593: StringLoad (IDS_LABELINSTANCE, pLegend->aCols[LegendInstanceCol].szLabel) ;
594: StringLoad (IDS_LABELPARENT, pLegend->aCols[LegendParentCol].szLabel) ;
595: StringLoad (IDS_LABELOBJECT, pLegend->aCols[LegendObjectCol].szLabel) ;
596: StringLoad (IDS_LABELSYSTEM, pLegend->aCols[LegendSystemCol].szLabel) ;
597:
598:
599: //=============================//
600: // Label dimensions //
601: //=============================//
602:
603: SelectFont (hDC, pLegend->hFontLabels) ;
604: pLegend->yLabelHeight = FontHeight (hDC, TRUE) + 2 * LabelTopMargin () ;
605:
606: //=============================//
607: // Column dimensions //
608: //=============================//
609:
610: for (iCol = 0 ;
611: iCol < iLegendNumCols ;
612: iCol++)
613: { // for
614: pLegend->aCols[iCol].iOrientation = LEFTORIENTATION ;
615: pLegend->aCols[iCol].xMinWidth =
616: TextWidth (hDC, pLegend->aCols[iCol].szLabel) + LegendHorzMargin () ;
617: } // for
618:
619: SelectFont (hDC, pLegend->hFontItems) ;
620: pLegend->yItemHeight = FontHeight (hDC, TRUE) + 2 * LegendItemTopMargin () ;
621:
622: pLegend->aCols[LegendColorCol].xMaxWidth = max (3 * xScrollWidth,
623: pLegend->aCols[LegendColorCol].xMinWidth) ;
624:
625: pLegend->aCols[LegendScaleCol].xMaxWidth = TextWidth (hDC, eScaleValueSpace) ;
626: pLegend->aCols[LegendCounterCol].xMaxWidth = iLegendColMax ;
627: pLegend->aCols[LegendInstanceCol].xMaxWidth = iLegendColMax ;
628: pLegend->aCols[LegendParentCol].xMaxWidth = iLegendColMax ;
629: pLegend->aCols[LegendObjectCol].xMaxWidth = iLegendColMax ;
630: pLegend->aCols[LegendSystemCol].xMaxWidth = iLegendColMax ;
631:
632: pLegend->aCols[LegendColorCol].iOrientation = LEFTORIENTATION ;
633: pLegend->aCols[LegendScaleCol].iOrientation = RIGHTORIENTATION ;
634:
635: ReleaseDC (hWnd, hDC) ;
636:
637: //=============================//
638: // Create Legend Items Listbox //
639: //=============================//
640:
641: pLegend->hWndItems =
642: CreateWindow (TEXT("ListBox"), // window class
643: NULL, // window caption
644: dwGraphLegendItemsWindowStyle, // window style
645: 0, 0, 0, 0, // window size and pos
646: hWnd, // parent window
647: NULL, // menu
648: hInstance, // program instance
649: (LPVOID) TRUE) ; // user-supplied data
650: } // OnLegendCreate
651:
652:
653: void static OnSize (HWND hWnd, int xWidth, int yHeight)
654: /*
655: Effect: Perform all actions necessary when the legend window is
656: being resized. In particular, set the width and starting
657: position for each column of the legend list and labels.
658:
659: Internals: What we do is determine the amount of space in the
660: width that is greater than the minimum, and allocate
661: that space among each of the columns that is willing to
662: be larger than minimum. If there is not enough room for
663: the minimum, don't bother with calculations.
664: */
665:
666: { // OnSize
667: PLEGEND pLegend ;
668: PLEGENDCOL pCol ;
669: int xMin ;
670: int xSlack ;
671: int iColsToGrow ;
672: int iCol ;
673:
674: pLegend = LegendData (hWnd) ;
675:
676: //=============================//
677: // Resize Legend Items //
678: //=============================//
679:
680: if (IsLegendLabelVisible ())
681: MoveWindow (pLegend->hWndItems,
682: LegendLeftMargin (), pLegend->yLabelHeight + ThreeDPad,
683: xWidth - 2 * LegendLeftMargin (),
684: yHeight - pLegend->yLabelHeight - yLegendBorderHeight,
685: TRUE) ;
686: else
687: MoveWindow (pLegend->hWndItems,
688: 0, 0,
689: xWidth, yHeight,
690: TRUE) ;
691:
692:
693: //=============================//
694: // Allocate width to Columns //
695: //=============================//
696:
697: xMin = LegendMinWidth (hWnd) ;
698: xSlack = max (xWidth - xMin, 0) ;
699: iColsToGrow = 0 ;
700:
701: for (iCol = 0 ;
702: iCol < iLegendNumCols ;
703: iCol++)
704: { // for
705: pCol = &(pLegend->aCols[iCol]) ;
706:
707: pCol->xWidth = pCol->xMinWidth ;
708: if (ColCanGrow (pCol))
709: iColsToGrow++ ;
710: } // for
711:
712: for (iCol = 0 ;
713: iCol < iLegendNumCols ;
714: iCol++)
715: { // for
716: pCol = &(pLegend->aCols[iCol]) ;
717:
718: if (ColCanGrow (pCol))
719: {
720: if ((pCol->xWidth + xSlack / iColsToGrow) >
721: pCol->xMaxWidth)
722: { // if
723: pCol->xWidth = pCol->xMaxWidth ;
724: xSlack -= (pCol->xMaxWidth - pCol->xMinWidth) ;
725: iColsToGrow-- ;
726: } // if
727: } // if
728: } // for
729:
730: for (iCol = 0 ;
731: iCol < iLegendNumCols ;
732: iCol++)
733: { // for
734: pCol = &(pLegend->aCols[iCol]) ;
735:
736: if (ColCanGrow (pCol))
737: pCol->xWidth += xSlack / iColsToGrow ;
738: } // for
739:
740: if (pLegend->aCols[LegendCounterCol].xWidth <
741: pLegend->aCols[LegendCounterCol].xMaxWidth)
742: {
743: // cut some from the other columns and give them to CounterCol
744: if (pLegend->aCols[LegendColorCol].xWidth - xScrollWidth >=
745: pLegend->aCols[LegendColorCol].xMinWidth)
746: {
747: pLegend->aCols[LegendColorCol].xWidth -= xScrollWidth ;
748: pLegend->aCols[LegendCounterCol].xWidth += xScrollWidth ;
749: }
750: if (pLegend->aCols[LegendInstanceCol].xWidth - xScrollWidth >=
751: pLegend->aCols[LegendInstanceCol].xMinWidth)
752: {
753: pLegend->aCols[LegendInstanceCol].xWidth -= xScrollWidth ;
754: pLegend->aCols[LegendCounterCol].xWidth += xScrollWidth ;
755: }
756: if (pLegend->aCols[LegendParentCol].xWidth - xScrollWidth >=
757: pLegend->aCols[LegendParentCol].xMinWidth)
758: {
759: pLegend->aCols[LegendParentCol].xWidth -= xScrollWidth ;
760: pLegend->aCols[LegendCounterCol].xWidth += xScrollWidth ;
761: }
762: }
763:
764:
765: //=============================//
766: // Set Column positions //
767: //=============================//
768:
769: pLegend->aCols[0].xPos = LegendLeftMargin () ;
770: for (iCol = 1 ;
771: iCol < iLegendNumCols ;
772: iCol++)
773: { // for
774: pLegend->aCols[iCol].xPos =
775: pLegend->aCols[iCol - 1].xPos + pLegend->aCols[iCol - 1].xWidth ;
776:
777: if (iCol == LegendCounterCol)
778: {
779: // add some space between Scale/Value col & Counter col
780: pLegend->aCols[LegendCounterCol].xPos += LegendLeftMargin () ;
781: }
782: } // for
783:
784: } // OnSize
785:
786:
787: void static OnPaint (HWND hWnd)
788: { // OnPaint
789: PLEGEND pLegend ;
790: HDC hDC ;
791: PAINTSTRUCT ps ;
792:
793: hDC = BeginPaint (hWnd, &ps) ;
794:
795: if (IsLegendLabelVisible ())
796: {
797: pLegend = LegendData (hWnd) ;
798: DrawLegendLabel (pLegend, hDC, hWnd) ;
799: }
800:
801:
802: EndPaint (hWnd, &ps) ;
803: } // OnPaint
804:
805:
806: void OnDrawLegendItem (HWND hWnd,
807: LPDRAWITEMSTRUCT lpDI)
808: { // OnDrawItem
809: HFONT hFontPrevious ;
810: HDC hDC ;
811: PLEGEND pLegend ;
812: PLINESTRUCT pLine ;
813: int iLBIndex ;
814: COLORREF preBkColor ;
815: COLORREF preTextColor ;
816:
817:
818: hDC = lpDI->hDC ;
819: iLBIndex = DIIndex (lpDI) ;
820:
821: pLegend = LegendData (hWnd) ;
822:
823: if (iLBIndex == -1)
824: pLine = NULL ;
825: else
826: pLine = (PLINESTRUCT) LBData (pLegend->hWndItems, iLBIndex) ;
827:
828: //=============================//
829: // Set DC attributes //
830: //=============================//
831:
832:
833: if (DISelected (lpDI))
834: { // if
835: preTextColor = SetTextColor (hDC, GetSysColor (COLOR_HIGHLIGHTTEXT)) ;
836: preBkColor = SetBkColor (hDC, GetSysColor (COLOR_HIGHLIGHT)) ;
837: } // if
838: ExtTextOut (hDC, lpDI->rcItem.left, lpDI->rcItem.top,
839: ETO_OPAQUE, &(lpDI->rcItem), NULL, 0, NULL ) ;
840:
841:
842: //=============================//
843: // Draw Legend Item //
844: //=============================//
845:
846: hFontPrevious = SelectFont (hDC, pLegend->hFontItems) ;
847: if (pLine)
848: DrawLegendItem (pLegend, pLine, lpDI->rcItem.top, hDC) ;
849: SelectFont (hDC, hFontPrevious) ;
850:
851: //=============================//
852: // Draw Focus //
853: //=============================//
854:
855: if (DIFocus (lpDI))
856: DrawFocusRect (hDC, &(lpDI->rcItem)) ;
857:
858:
859: if (DISelected (lpDI))
860: { // if
861: preTextColor = SetTextColor (hDC, preTextColor) ;
862: preBkColor = SetBkColor (hDC, preBkColor) ;
863: } // if
864: } // OnDrawItem
865:
866:
867: void static OnMeasureItem (HWND hWnd,
868: LPMEASUREITEMSTRUCT lpMI)
869: { // OnMeasureItem
870: PLEGEND pLegend ;
871:
872: pLegend = LegendData (hWnd) ;
873: lpMI->itemHeight = pLegend->yItemHeight ;
874: } // OnMeasureItem
875:
876:
877: void static OnDestroy (HWND hWnd)
878: {
879: PLEGEND pLegend ;
880:
881: pLegend = LegendData (hWnd) ;
882: MemoryFree (pLegend) ;
883: } // OnDestroy
884:
885:
886:
887: void static OnDoubleClick (HWND hWnd)
888: {
889: PLEGEND pLegend ;
890:
891: pLegend = LegendData (hWnd) ;
892: if (!pLegend)
893: return ;
894:
895: switch (pLegend->iLineType)
896: { // switch
897: case LineTypeChart:
898: EditChart (hWndMain) ;
899: break ;
900:
901: case LineTypeAlert:
902: EditAlert (hWndAlert) ;
903: break ;
904: } // switch
905: } // OnDoubleClick
906:
907:
908:
909: void static OnSelectionChanged (HWND hWnd)
910: { // OnSelectionChanged
911: PLEGEND pLegend ;
912: PGRAPHSTRUCT pGraph ;
913: int iIndex ;
914:
915:
916: pLegend = LegendData (hWnd) ;
917:
918: // set the new selected line
919: iIndex = LBSelection (pLegend->hWndItems) ;
920:
921: if (iIndex == LB_ERR)
922: return ;
923:
924: LegendSetCurrentLine (pLegend, iIndex) ;
925:
926: if (pLegend->iLineType == LineTypeChart)
927: {
928: pGraph = GraphData (hWndGraph) ;
929:
930: if (!PlayingBackLog())
931: {
932: // update the min, max, & avg of the current line
933: UpdateValueBarData (pGraph) ;
934: }
935:
936: // update the valuebar display
937: StatusTimer (hWndGraphStatus, TRUE) ;
938:
939: // change the Current highlighted line if necessary
940: if (pGraph && pGraph->HighLightOnOff)
941: {
942: WindowInvalidate (hWndGraphDisplay) ;
943: }
944: }
945: } // OnSelectionChanged
946:
947:
948: //==========================================================================//
949: // Exported Functions //
950: //==========================================================================//
951:
952:
953: LRESULT APIENTRY GraphLegendWndProc (HWND hWnd,
954: WORD wMsg,
955: WPARAM wParam,
956: LONG lParam)
957: { // GraphLegendWndProc
958: BOOL bCallDefProc ;
959: LRESULT lReturnValue ;
960:
961:
962: bCallDefProc = FALSE ;
963: lReturnValue = 0L ;
964:
965: switch (wMsg)
966: { // switch
967: case WM_DELETEITEM:
968: break ;
969:
970: case WM_COMMAND:
971: switch (HIWORD (wParam))
972: { // switch
973: case LBN_DBLCLK:
974: OnDoubleClick (hWnd) ;
975: break ;
976:
977: case LBN_SELCHANGE:
978: OnSelectionChanged (hWnd) ;
979: break ;
980:
981: default:
982: break ;
983: } // switch
984: break ;
985:
986: case WM_CREATE:
987: OnLegendCreate (hWnd, (LPCREATESTRUCT) lParam) ;
988: break ;
989:
990: case WM_DESTROY:
991: OnDestroy (hWnd) ;
992: break ;
993:
994: case WM_DRAWITEM:
995: OnDrawLegendItem (hWnd, (LPDRAWITEMSTRUCT) lParam) ;
996: break ;
997:
998: case WM_MEASUREITEM:
999: OnMeasureItem (hWnd, (LPMEASUREITEMSTRUCT) lParam) ;
1000: break ;
1001:
1002: case WM_PAINT:
1003: OnPaint (hWnd) ;
1004: break ;
1005:
1006: case WM_SIZE:
1007: OnSize (hWnd, LOWORD (lParam), HIWORD (lParam)) ;
1008: break ;
1009:
1010: default:
1011: bCallDefProc = TRUE ;
1012: } // switch
1013:
1014:
1015: if (bCallDefProc)
1016: lReturnValue = DefWindowProc (hWnd, wMsg, wParam, lParam) ;
1017:
1018: return (lReturnValue);
1019: } // GraphLegendWndProc
1020:
1021:
1022: int LegendMinWidth (HWND hWnd)
1023: {
1024: PLEGEND pLegend ;
1025: int iCol ;
1026: int xMinWidth ;
1027:
1028: pLegend = LegendData (hWnd) ;
1029: xMinWidth = 0 ;
1030:
1031: for (iCol = 0 ;
1032: iCol < iLegendNumCols ;
1033: iCol++)
1034: { // for
1035: xMinWidth += pLegend->aCols[iCol].xMinWidth ;
1036: } // for
1037:
1038: return (xMinWidth) ;
1039: }
1040:
1041:
1042: int LegendMinHeight (HWND hWnd)
1043: {
1044: PLEGEND pLegend ;
1045:
1046: pLegend = LegendData (hWnd) ;
1047:
1048: if (IsLegendLabelVisible ())
1049: return (pLegend->yLabelHeight + pLegend->yItemHeight) ;
1050: else
1051: return (pLegend->yItemHeight) ;
1052: }
1053:
1054:
1055: int LegendHeight (HWND hWnd, int yGraphHeight)
1056: /*
1057: Effect: Return the best height for the Legend window given the
1058: number of items and label visibility of the legend, as
1059: well as the overall height of the graph.
1060: */
1061: { // LegendHeight
1062: PLEGEND pLegend ;
1063: int yPreferredHeight ;
1064:
1065: pLegend = LegendData (hWnd) ;
1066:
1067: yPreferredHeight = yLegendBorderHeight +
1068: pLegend->yItemHeight *
1069: PinInclusive (LBNumItems (pLegend->hWndItems),
1070: 1, iLegendMaxVisibleItems) ;
1071: if (IsLegendLabelVisible ())
1072: yPreferredHeight += pLegend->yLabelHeight ;
1073:
1074: return (min (yPreferredHeight, yGraphHeight / 2)) ;
1075: } // LegendHeight
1076:
1077:
1078:
1079: int LegendFullHeight (HWND hWnd, HDC hDC)
1080: /*
1081: Effect: Return the best height for the Legend window given the
1082: number of items and label visibility of the legend, as
1083: well as the overall height of the graph.
1084: */
1085: { // LegendHeight
1086: PLEGEND pLegend ;
1087: int yPreferredHeight ;
1088:
1089: pLegend = LegendData (hWnd) ;
1090:
1091: yPreferredHeight = yLegendBorderHeight +
1092: pLegend->yItemHeight *
1093: LBNumItems (pLegend->hWndItems) ;
1094: if (IsLegendLabelVisible ())
1095: yPreferredHeight += pLegend->yLabelHeight ;
1096:
1097: return (yPreferredHeight) ;
1098: } // LegendFullHeight
1099:
1100:
1101:
1102:
1103: HWND CreateGraphLegendWindow (HWND hWndGraph)
1104: {
1105: return (CreateWindow (szGraphLegendClass, // class
1106: NULL, // caption
1107: dwGraphLegendWindowStyle, // window style
1108: 0, 0, // position
1109: 0, 0, // size
1110: hWndGraph, // parent window
1111: NULL, // menu
1112: hInstance, // program instance
1113: (LPVOID) TRUE)) ; // user-supplied data
1114: }
1115:
1116:
1117: BOOL GraphLegendInitializeApplication (void)
1118: /*
1119: Called By: GraphInitializeApplication only
1120: */
1121: {
1122: WNDCLASS wc ;
1123:
1124: wc.style = dwGraphLegendClassStyle ;
1125: wc.lpfnWndProc = (WNDPROC) GraphLegendWndProc ;
1126: wc.hInstance = hInstance ;
1127: wc.cbClsExtra = iGraphLegendClassExtra ;
1128: wc.cbWndExtra = iGraphLegendWindowExtra ;
1129: wc.hIcon = NULL ;
1130: wc.hCursor = LoadCursor (NULL, IDC_ARROW) ;
1131: wc.hbrBackground = hbLightGray ;
1132: wc.lpszMenuName = NULL ;
1133: wc.lpszClassName = szGraphLegendClass ;
1134:
1135: return (RegisterClass (&wc)) ;
1136: }
1137:
1138:
1139: BOOL LegendAddItem (HWND hWnd, PLINESTRUCT pLine)
1140: /*
1141: Effect: Add a legend entry for the line pLine. Don't select
1142: the line as current entry here, because this will cause
1143: the scroll bar to unneccesarily appear for a moment.
1144: If you want this line to be the current line, resize
1145: the legend first, then set as current line.
1146:
1147: See Also: ChartInsertLine, AlertInsertLine.
1148: */
1149: { // LegendAddItem
1150: PLEGEND pLegend ;
1151:
1152: pLegend = LegendData (hWnd) ;
1153: LBAdd (pLegend->hWndItems, pLine) ;
1154:
1155: return (TRUE) ;
1156: } // LegendAddItem
1157:
1158:
1159: void LegendDeleteItem (HWND hWndLegend,
1160: PLINE pLine)
1161: { // LegendDeleteItem
1162: PLEGEND pLegend ;
1163: int iIndex ;
1164: int iNextIndex ;
1165: int iNumItems ;
1166: PGRAPHSTRUCT pGraph ;
1167:
1168: pLegend = LegendData (hWndLegend) ;
1169: if (!pLegend)
1170: return ;
1171:
1172: iNumItems = LBNumItems (pLegend->hWndItems) ;
1173:
1174: iIndex = LBFind (pLegend->hWndItems, pLine) ;
1175:
1176: if (iIndex != LB_ERR)
1177: {
1178: LBDelete (pLegend->hWndItems, iIndex) ;
1179: }
1180:
1181: // no need to do anything if iNumItems is 1 to begin with
1182: if (iNumItems != LB_ERR && iNumItems > 1)
1183: {
1184: if (iIndex == iNumItems - 1)
1185: {
1186: // deleting the last line, then set selection
1187: // to the previous legend line
1188: iNextIndex = iIndex - 1 ;
1189: }
1190: else
1191: {
1192: // set the selection to the next legend line
1193: iNextIndex = iIndex ;
1194: }
1195:
1196: LBSetSelection (pLegend->hWndItems, iNextIndex) ;
1197: LegendSetCurrentLine (pLegend, iNextIndex) ;
1198:
1199: if (pLegend->iLineType == LineTypeChart)
1200: {
1201: // update the min, max, & avg of the current line
1202: pGraph = GraphData (hWndGraph) ;
1203:
1204: if (!PlayingBackLog())
1205: {
1206: // update the min, max, & avg of the current line
1207: UpdateValueBarData (pGraph) ;
1208: }
1209:
1210: // update the valuebar display
1211: StatusTimer (hWndGraphStatus, TRUE) ;
1212: }
1213: }
1214:
1215: } // LegendDeleteItem
1216:
1217:
1218: PLINE LegendCurrentLine (HWND hWndLegend)
1219: { // LegendCurrentLine
1220: PLEGEND pLegend ;
1221:
1222: pLegend = LegendData (hWndLegend) ;
1223:
1224: if (!pLegend)
1225: return (NULL) ;
1226:
1227: return (pLegend->pCurrentLine) ;
1228:
1229: } // LegendCurrentLine
1230:
1231:
1232:
1233: int LegendNumItems (HWND hWndLegend)
1234: { // LegendNumItems
1235: PLEGEND pLegend ;
1236:
1237: pLegend = LegendData (hWndLegend) ;
1238:
1239: return (LBNumItems (pLegend->hWndItems)) ;
1240: } // LegendNumItems
1241:
1242:
1243:
1244: void LegendSetSelection (HWND hWndLegend, int iIndex)
1245: { // LegendSetSelection
1246: PLEGEND pLegend ;
1247:
1248: pLegend = LegendData (hWndLegend) ;
1249: LBSetSelection (pLegend->hWndItems, iIndex) ;
1250: LegendSetCurrentLine (pLegend, iIndex) ;
1251: } // LegendSetSelection
1252:
1253:
1254:
1255: #ifdef KEEP_PRINT
1256:
1257: void PrintLegend (HDC hDC, PGRAPHSTRUCT pGraph, HWND hWndLegend,
1258: RECT rectLegend)
1259: {
1260: PLEGEND pLegend ;
1261: int yItemHeight ;
1262: HFONT hFontItems ;
1263: PLINE pLine ;
1264: int iIndex ;
1265: int iIndexNum ;
1266:
1267:
1268: pLegend = LegendData (hWndLegend) ;
1269:
1270: yItemHeight = pLegend->yItemHeight ;
1271: hFontItems = pLegend->hFontItems ;
1272:
1273: pLegend->hFontItems = hFontPrinterScales ;
1274: SelectFont (hDC, pLegend->hFontItems) ;
1275:
1276: pLegend->yItemHeight = FontHeight (hDC, TRUE) ;
1277:
1278: iIndexNum = LBNumItems (pLegend->hWndItems) ;
1279: for (iIndex = 0 ;
1280: iIndex < iIndexNum ;
1281: iIndex++)
1282: { // for
1283: pLine = (PLINE) LBData (pLegend->hWndItems, iIndex) ;
1284: DrawLegendItem (pLegend, pLine, iIndex * pLegend->yItemHeight, hDC) ;
1285: } // for
1286:
1287: pLegend->hFontItems = hFontItems ;
1288: pLegend->yItemHeight = yItemHeight ;
1289:
1290:
1291: SelectBrush (hDC, GetStockObject (HOLLOW_BRUSH)) ;
1292: SelectPen (hDC, GetStockObject (BLACK_PEN)) ;
1293: Rectangle (hDC, 0, 0,
1294: rectLegend.right - rectLegend.left,
1295: rectLegend.bottom - rectLegend.top) ;
1296: }
1297: #endif
1298:
1299:
1300: void ClearLegend (HWND hWndLegend)
1301: {
1302: PLEGEND pLegend ;
1303:
1304: pLegend = LegendData (hWndLegend) ;
1305: if (!pLegend)
1306: return ;
1307:
1308: LBReset (pLegend->hWndItems) ;
1309: pLegend->pCurrentLine = NULL ;
1310: }
1311:
1312: void LegendSetRedraw (HWND hWndLegend, BOOL bRedraw)
1313: {
1314: PLEGEND pLegend ;
1315:
1316: pLegend = LegendData (hWndLegend) ;
1317: if (!pLegend)
1318: return ;
1319:
1320: LBSetRedraw (pLegend->hWndItems, bRedraw) ;
1321: }
1322:
1323:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.