Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1191 lines
34 KiB

  1. /*
  2. ==============================================================================
  3. Application:
  4. Microsoft Windows NT (TM) Performance Monitor
  5. File:
  6. legend.c - legend window routines.
  7. This file contains code creating the legend window, which is
  8. a child of the graph windows. The legend window displays a
  9. legend line for each line in the associated graph. It also
  10. includes an area called the label, which are headers for those
  11. lines.
  12. Copyright 1992, Microsoft Corporation. All Rights Reserved.
  13. ==============================================================================
  14. */
  15. //==========================================================================//
  16. // Includes //
  17. //==========================================================================//
  18. #include <stdio.h> // for sprintf
  19. #include "setedit.h"
  20. #include "legend.h" // external declarations for this file
  21. #include "owndraw.h"
  22. #include "perfmops.h"
  23. #include "grafdata.h" // for EditChart
  24. #include "pmemory.h" // for MemoryXXX (mallloc-type) routines
  25. #include "utils.h"
  26. // #include "valuebar.h" // for StatusTimer
  27. #define eScaleValueSpace TEXT(">9999999999.0")
  28. //==========================================================================//
  29. // Constants //
  30. //==========================================================================//
  31. #define dwGraphLegendClassStyle (CS_HREDRAW | CS_VREDRAW)
  32. #define iGraphLegendClassExtra (0)
  33. #define iGraphLegendWindowExtra (sizeof (PLEGEND))
  34. #define dwGraphLegendWindowStyle (WS_CHILD | WS_VISIBLE)
  35. #define xLegendBorderWidth (xDlgBorderWidth)
  36. #define yLegendBorderHeight (yDlgBorderHeight)
  37. #define iLabelLen 30
  38. #define iLegendColMax 1000
  39. #define LEFTORIENTATION 1
  40. #define CENTERORIENTATION 2
  41. #define RIGHTORIENTATION 3
  42. #define LegendColorCol 0
  43. #define LegendScaleCol 1
  44. #define LegendCounterCol 2
  45. #define LegendInstanceCol 3
  46. #define LegendParentCol 4
  47. #define LegendObjectCol 5
  48. #define LegendSystemCol 6
  49. #define iLegendNumCols 7
  50. #define iLegendMaxVisibleItems 8
  51. #define dwGraphLegendItemsWindowClass TEXT("ListBox")
  52. #define dwGraphLegendItemsWindowStyle \
  53. (LBS_NOTIFY | LBS_NOINTEGRALHEIGHT | LBS_OWNERDRAWFIXED | \
  54. WS_VISIBLE | WS_CHILD | WS_VSCROLL)
  55. //==========================================================================//
  56. // Typedefs //
  57. //==========================================================================//
  58. typedef struct LEGENDCOLSTRUCT {
  59. TCHAR szLabel [iLabelLen] ;
  60. int xMinWidth ;
  61. int xMaxWidth ;
  62. int xWidth ;
  63. int xPos ;
  64. int iOrientation ;
  65. } LEGENDCOL ;
  66. typedef LEGENDCOL *PLEGENDCOL ;
  67. typedef struct LEGENDTRUCT {
  68. HWND hWndItems ;
  69. HFONT hFontItems ;
  70. HFONT hFontLabels ;
  71. int xMinWidth ;
  72. int yLabelHeight ;
  73. int yItemHeight ;
  74. int iNumItemsVisible ;
  75. LEGENDCOL aCols [iLegendNumCols] ;
  76. int iLineType ;
  77. PLINE pCurrentLine ; // current selected line
  78. } LEGEND ;
  79. typedef LEGEND *PLEGEND ;
  80. //==========================================================================//
  81. // Macros //
  82. //==========================================================================//
  83. #define LabelTopMargin() (2)
  84. #define LegendLeftMargin() (3 + ThreeDPad)
  85. #define LegendItemTopMargin() (yBorderHeight)
  86. #define IsLegendLabelVisible() (TRUE)
  87. #define ColCanGrow(pCol) \
  88. (pCol->xMaxWidth > pCol->xWidth)
  89. #define LegendHorzMargin() (3)
  90. //==========================================================================//
  91. // Local Data //
  92. //==========================================================================//
  93. // LEGEND Legend ;
  94. PLEGEND pGraphLegendData ;
  95. #define LegendData(hWnd) \
  96. (pGraphLegendData )
  97. //==========================================================================//
  98. // Local Functions //
  99. //==========================================================================//
  100. void LegendSetCurrentLine (PLEGEND pLegend, INT_PTR iIndex)
  101. {
  102. pLegend->pCurrentLine =
  103. (PLINESTRUCT) LBData (pLegend->hWndItems, iIndex) ;
  104. if (pLegend->pCurrentLine == (PLINESTRUCT) LB_ERR) {
  105. pLegend->pCurrentLine = NULL ;
  106. }
  107. } // LegendSetCurrentLine
  108. PLEGEND AllocateLegendData (HWND hWnd, BOOL bChartLegend)
  109. {
  110. PLEGEND pLegend ;
  111. pLegend = MemoryAllocate (sizeof (LEGEND)) ;
  112. // SetWindowLong (hWnd, 0, (LONG) pLegend) ;
  113. if (bChartLegend) {
  114. hWndGraphLegend = hWnd ;
  115. pGraphLegendData = pLegend ;
  116. }
  117. return (pLegend) ;
  118. }
  119. void DrawLegendLabel (PLEGEND pLegend,
  120. HDC hDC,
  121. HWND hWnd)
  122. { // DrawLegendLabel
  123. int i ;
  124. int xPos ;
  125. RECT rect ;
  126. RECT rectLB ;
  127. INT LocalThreeDPad = ThreeDPad - 1 ;
  128. SetBkColor (hDC, crLightGray) ;
  129. SelectFont (hDC, pLegend->hFontLabels) ;
  130. GetClientRect (hWnd, &rect) ;
  131. // Fill (hDC, crLightGray, &rect) ;
  132. ExtTextOut (hDC, rect.left, rect.top,
  133. ETO_OPAQUE, &(rect), NULL, 0, NULL ) ;
  134. GetWindowRect (pLegend->hWndItems, &rectLB) ;
  135. ScreenRectToClient (hWnd, &rectLB) ;
  136. ThreeDConcave1 (hDC,
  137. rectLB.left - LocalThreeDPad,
  138. rectLB.top - LocalThreeDPad,
  139. rectLB.right + LocalThreeDPad,
  140. rectLB.bottom + LocalThreeDPad) ;
  141. for (i = 0 ;
  142. i < iLegendNumCols ;
  143. i++) { // for
  144. rect.left = pLegend->aCols[i].xPos ;
  145. rect.top = yBorderHeight ;
  146. rect.right = rect.left + pLegend->aCols[i].xWidth - LegendHorzMargin () ;
  147. rect.bottom = pLegend->yLabelHeight ;
  148. switch (pLegend->aCols[i].iOrientation) { // switch
  149. case LEFTORIENTATION:
  150. SetTextAlign (hDC, TA_LEFT) ;
  151. xPos = rect.left ;
  152. break ;
  153. case CENTERORIENTATION:
  154. SetTextAlign (hDC, TA_CENTER) ;
  155. xPos = (rect.left + rect.right) / 2 ;
  156. break ;
  157. case RIGHTORIENTATION:
  158. SetTextAlign (hDC, TA_RIGHT) ;
  159. xPos = rect.right ;
  160. break ;
  161. default:
  162. xPos = rect.left ;
  163. break ;
  164. } // switch
  165. ExtTextOut (hDC,
  166. xPos, rect.top,
  167. ETO_OPAQUE,
  168. &rect,
  169. pLegend->aCols[i].szLabel,
  170. lstrlen (pLegend->aCols[i].szLabel),
  171. NULL) ;
  172. } // for
  173. } // DrawLegendLabel
  174. void DrawColorCol (PLEGEND pLegend,
  175. PLINE pLine,
  176. int iCol,
  177. HDC hDC,
  178. int yPos)
  179. /*
  180. Effect: Draw the "color" column of a legend entry. The color
  181. column displays a small sample of the line drawing.
  182. For charts, the sample is a line of the correct style,
  183. color, and width. Since we are using wide lines,
  184. the round endcaps of the lines will breach the column.
  185. Therefore we need to set the clip region. We could
  186. remove this clipping if we find a way to change the
  187. end cap design.
  188. */
  189. { // DrawColorCol
  190. HBRUSH hBrush, hBrushPrevious ;
  191. RECT rect ;
  192. int yMiddle ;
  193. int iCircle ;
  194. rect.left = pLegend->aCols[iCol].xPos - LegendLeftMargin () + 2 ;
  195. rect.top = yPos + 1 ;
  196. rect.right = rect.left + pLegend->aCols[iCol].xWidth - LegendHorzMargin () ;
  197. rect.bottom = yPos + pLegend->yItemHeight - 1 ;
  198. yMiddle = rect.top + (rect.bottom - rect.top) / 2 ;
  199. iCircle = rect.bottom - rect.top - 2 ;
  200. switch (pLegend->iLineType) { // switch
  201. case LineTypeChart:
  202. if (pLine->Visual.iWidth == 1) {
  203. // simple case with thin pen
  204. hBrush = SelectBrush (hDC, hbLightGray) ;
  205. Rectangle (hDC, rect.left, rect.top, rect.right, rect.bottom) ;
  206. HLine (hDC, pLine->hPen,
  207. rect.left + 1, rect.right - 1, yMiddle) ;
  208. SelectBrush (hDC, hBrush) ;
  209. } else {
  210. // thicker pen width, have to set ClipRect so
  211. // it will not draw otherside the rect.
  212. SaveDC (hDC) ;
  213. hBrush = SelectBrush (hDC, hbLightGray) ;
  214. Rectangle (hDC, rect.left, rect.top, rect.right, rect.bottom) ;
  215. IntersectClipRect (hDC,
  216. rect.left + 1,
  217. rect.top + 1,
  218. rect.right - 1,
  219. rect.bottom - 1) ;
  220. HLine (hDC, pLine->hPen,
  221. rect.left + 1, rect.right - 1, yMiddle) ;
  222. SelectBrush (hDC, hBrush) ;
  223. RestoreDC (hDC, -1) ;
  224. }
  225. break ;
  226. } // switch
  227. } // DrawColorCol
  228. void DrawLegendCol (PLEGEND pLegend,
  229. int iCol,
  230. HDC hDC,
  231. int yPos,
  232. LPTSTR lpszValue)
  233. /*
  234. Effect: Draw the value lpszValue for the column iCol on hDC.
  235. Assert: The foreground and background text colors of hDC are
  236. properly set.
  237. */
  238. { // DrawLegendCol
  239. RECT rect ;
  240. int xPos ;
  241. rect.left = pLegend->aCols[iCol].xPos - LegendLeftMargin () ;
  242. rect.top = yPos ;
  243. rect.right = rect.left + pLegend->aCols[iCol].xWidth - LegendHorzMargin () ;
  244. rect.bottom = yPos + pLegend->yItemHeight ;
  245. // SetTextAlign (hDC, TA_TOP) ;
  246. switch (pLegend->aCols[iCol].iOrientation) { // switch
  247. case LEFTORIENTATION:
  248. SetTextAlign (hDC, TA_LEFT) ;
  249. xPos = rect.left ;
  250. break ;
  251. case CENTERORIENTATION:
  252. SetTextAlign (hDC, TA_CENTER) ;
  253. xPos = (rect.left + rect.right) / 2 ;
  254. break ;
  255. case RIGHTORIENTATION:
  256. SetTextAlign (hDC, TA_RIGHT) ;
  257. xPos = rect.right ;
  258. break ;
  259. default:
  260. xPos = rect.left ;
  261. break ;
  262. } // switch
  263. ExtTextOut (hDC,
  264. xPos, rect.top + LegendItemTopMargin (),
  265. ETO_OPAQUE | ETO_CLIPPED,
  266. &rect,
  267. lpszValue,
  268. lstrlen (lpszValue),
  269. NULL) ;
  270. } // DrawLegendCol
  271. void DrawLegendItem (PLEGEND pLegend,
  272. PLINESTRUCT pLine,
  273. int yPos,
  274. HDC hDC)
  275. {
  276. TCHAR szValue [256] ;
  277. TCHAR szInstance [256] ;
  278. TCHAR szParent [256] ;
  279. TCHAR szNoName[4] ;
  280. szNoName[0] = szNoName[1] = szNoName[2] = TEXT('-') ;
  281. szNoName[3] = TEXT('\0') ;
  282. //=============================//
  283. // Determine Instance, Parent //
  284. //=============================//
  285. // It's possible that there will be no instance, therefore
  286. // the lnInstanceName would be NULL.
  287. if (pLine->lnObject.NumInstances > 0) {
  288. // Test for the parent object instance name title index.
  289. // If there is one, it implies that there will be a valid
  290. // Parent Object Name and a valid Parent Object Instance Name.
  291. // If the Parent Object title index is 0 then
  292. // just display the instance name.
  293. lstrcpy (szInstance, pLine->lnInstanceName) ;
  294. if ((pLine->bUserEdit ||
  295. pLine->lnInstanceDef.ParentObjectTitleIndex) &&
  296. pLine->lnPINName) {
  297. // Get the Parent Object Name.
  298. lstrcpy (szParent, pLine->lnPINName) ;
  299. } else {
  300. lstrcpy (szParent, szNoName) ;
  301. }
  302. } else {
  303. lstrcpy (szInstance, szNoName) ;
  304. lstrcpy (szParent, szNoName) ;
  305. }
  306. //=============================//
  307. // Draw Color //
  308. //=============================//
  309. DrawColorCol (pLegend, pLine, LegendColorCol, hDC, yPos) ;
  310. //=============================//
  311. // Draw Scale/Value //
  312. //=============================//
  313. if (pLegend->iLineType == LineTypeChart) {
  314. if (pLine->eScale < (FLOAT) 1.0) {
  315. TSPRINTF (szValue, TEXT("%7.7f"), pLine->eScale) ;
  316. } else {
  317. TSPRINTF (szValue, TEXT("%10.3f"), pLine->eScale) ;
  318. }
  319. ConvertDecimalPoint (szValue);
  320. }
  321. SetTextAlign (hDC, TA_TOP) ;
  322. DrawLegendCol (pLegend, LegendScaleCol,
  323. hDC, yPos, szValue) ;
  324. //=============================//
  325. // Draw Counter //
  326. //=============================//
  327. DrawLegendCol (pLegend, LegendCounterCol,
  328. hDC, yPos, pLine->lnCounterName) ;
  329. //=============================//
  330. // Draw Instance //
  331. //=============================//
  332. DrawLegendCol (pLegend, LegendInstanceCol,
  333. hDC, yPos, szInstance) ;
  334. //=============================//
  335. // Draw Parent //
  336. //=============================//
  337. DrawLegendCol (pLegend, LegendParentCol,
  338. hDC, yPos, szParent) ;
  339. //=============================//
  340. // Draw Object //
  341. //=============================//
  342. DrawLegendCol (pLegend, LegendObjectCol,
  343. hDC, yPos, pLine->lnObjectName) ;
  344. //=============================//
  345. // Draw System //
  346. //=============================//
  347. DrawLegendCol (pLegend, LegendSystemCol,
  348. hDC, yPos, pLine->lnSystemName) ;
  349. }
  350. //==========================================================================//
  351. // Message Handlers //
  352. //==========================================================================//
  353. BOOL OnLegendCreate (HWND hWnd, LPCREATESTRUCT lpCS)
  354. {
  355. PLEGEND pLegend ;
  356. HDC hDC ;
  357. int iCol ;
  358. BOOL bChartLegend ;
  359. bChartLegend = (lpCS->lpCreateParams) == (LPVOID) TRUE ;
  360. pLegend = AllocateLegendData (hWnd, bChartLegend) ;
  361. if (!pLegend)
  362. return (FALSE) ;
  363. pLegend->iLineType = LineTypeChart ;
  364. pLegend->hFontItems = hFontScales ;
  365. pLegend->hFontLabels = hFontScalesBold ;
  366. hDC = GetDC (hWnd) ;
  367. //=============================//
  368. // Load Labels //
  369. //=============================//
  370. StringLoad (IDS_LABELCOLOR, pLegend->aCols[LegendColorCol].szLabel) ;
  371. if (pLegend->iLineType == LineTypeChart)
  372. StringLoad (IDS_LABELSCALE,
  373. pLegend->aCols[LegendScaleCol].szLabel) ;
  374. else
  375. StringLoad (IDS_LABELVALUE,
  376. pLegend->aCols[LegendScaleCol].szLabel) ;
  377. StringLoad (IDS_LABELCOUNTER, pLegend->aCols[LegendCounterCol].szLabel) ;
  378. StringLoad (IDS_LABELINSTANCE, pLegend->aCols[LegendInstanceCol].szLabel) ;
  379. StringLoad (IDS_LABELPARENT, pLegend->aCols[LegendParentCol].szLabel) ;
  380. StringLoad (IDS_LABELOBJECT, pLegend->aCols[LegendObjectCol].szLabel) ;
  381. StringLoad (IDS_LABELSYSTEM, pLegend->aCols[LegendSystemCol].szLabel) ;
  382. //=============================//
  383. // Label dimensions //
  384. //=============================//
  385. SelectFont (hDC, pLegend->hFontLabels) ;
  386. pLegend->yLabelHeight = FontHeight (hDC, TRUE) + 2 * LabelTopMargin () ;
  387. //=============================//
  388. // Column dimensions //
  389. //=============================//
  390. for (iCol = 0 ;
  391. iCol < iLegendNumCols ;
  392. iCol++) { // for
  393. pLegend->aCols[iCol].iOrientation = LEFTORIENTATION ;
  394. pLegend->aCols[iCol].xMinWidth =
  395. TextWidth (hDC, pLegend->aCols[iCol].szLabel) + LegendHorzMargin () ;
  396. } // for
  397. SelectFont (hDC, pLegend->hFontItems) ;
  398. pLegend->yItemHeight = FontHeight (hDC, TRUE) + 2 * LegendItemTopMargin () ;
  399. pLegend->aCols[LegendColorCol].xMaxWidth = max (3 * xScrollWidth,
  400. pLegend->aCols[LegendColorCol].xMinWidth) ;
  401. pLegend->aCols[LegendScaleCol].xMaxWidth = TextWidth (hDC, eScaleValueSpace) ;
  402. pLegend->aCols[LegendCounterCol].xMaxWidth = iLegendColMax ;
  403. pLegend->aCols[LegendInstanceCol].xMaxWidth = iLegendColMax ;
  404. pLegend->aCols[LegendParentCol].xMaxWidth = iLegendColMax ;
  405. pLegend->aCols[LegendObjectCol].xMaxWidth = iLegendColMax ;
  406. pLegend->aCols[LegendSystemCol].xMaxWidth = iLegendColMax ;
  407. pLegend->aCols[LegendColorCol].iOrientation = LEFTORIENTATION ;
  408. pLegend->aCols[LegendScaleCol].iOrientation = RIGHTORIENTATION ;
  409. ReleaseDC (hWnd, hDC) ;
  410. //=============================//
  411. // Create Legend Items Listbox //
  412. //=============================//
  413. pLegend->hWndItems =
  414. CreateWindow (TEXT("ListBox"), // window class
  415. NULL, // window caption
  416. dwGraphLegendItemsWindowStyle, // window style
  417. 0, 0, 0, 0, // window size and pos
  418. hWnd, // parent window
  419. NULL, // menu
  420. hInstance, // program instance
  421. (LPVOID) TRUE) ; // user-supplied data
  422. return TRUE;
  423. } // OnLegendCreate
  424. void static OnSize (HWND hWnd, int xWidth, int yHeight)
  425. /*
  426. Effect: Perform all actions necessary when the legend window is
  427. being resized. In particular, set the width and starting
  428. position for each column of the legend list and labels.
  429. Internals: What we do is determine the amount of space in the
  430. width that is greater than the minimum, and allocate
  431. that space among each of the columns that is willing to
  432. be larger than minimum. If there is not enough room for
  433. the minimum, don't bother with calculations.
  434. */
  435. { // OnSize
  436. PLEGEND pLegend ;
  437. PLEGENDCOL pCol ;
  438. int xMin ;
  439. int xSlack ;
  440. int iColsToGrow ;
  441. int iCol ;
  442. pLegend = LegendData (hWnd) ;
  443. //=============================//
  444. // Resize Legend Items //
  445. //=============================//
  446. if (IsLegendLabelVisible ())
  447. MoveWindow (pLegend->hWndItems,
  448. LegendLeftMargin (), pLegend->yLabelHeight + ThreeDPad,
  449. xWidth - 2 * LegendLeftMargin (),
  450. yHeight - pLegend->yLabelHeight - yLegendBorderHeight,
  451. TRUE) ;
  452. else
  453. MoveWindow (pLegend->hWndItems,
  454. 0, 0,
  455. xWidth, yHeight,
  456. TRUE) ;
  457. //=============================//
  458. // Allocate width to Columns //
  459. //=============================//
  460. xMin = LegendMinWidth (hWnd) ;
  461. xSlack = max (xWidth - xMin, 0) ;
  462. iColsToGrow = 0 ;
  463. for (iCol = 0 ;
  464. iCol < iLegendNumCols ;
  465. iCol++) { // for
  466. pCol = &(pLegend->aCols[iCol]) ;
  467. pCol->xWidth = pCol->xMinWidth ;
  468. if (ColCanGrow (pCol))
  469. iColsToGrow++ ;
  470. } // for
  471. for (iCol = 0 ;
  472. iCol < iLegendNumCols ;
  473. iCol++) { // for
  474. pCol = &(pLegend->aCols[iCol]) ;
  475. if (ColCanGrow (pCol)) {
  476. if ((pCol->xWidth + xSlack / iColsToGrow) >
  477. pCol->xMaxWidth) { // if
  478. pCol->xWidth = pCol->xMaxWidth ;
  479. xSlack -= (pCol->xMaxWidth - pCol->xMinWidth) ;
  480. iColsToGrow-- ;
  481. } // if
  482. } // if
  483. } // for
  484. for (iCol = 0 ;
  485. iCol < iLegendNumCols ;
  486. iCol++) { // for
  487. pCol = &(pLegend->aCols[iCol]) ;
  488. if (ColCanGrow (pCol))
  489. pCol->xWidth += xSlack / iColsToGrow ;
  490. } // for
  491. if (pLegend->aCols[LegendCounterCol].xWidth <
  492. pLegend->aCols[LegendCounterCol].xMaxWidth) {
  493. // cut some from the other columns and give them to CounterCol
  494. if (pLegend->aCols[LegendColorCol].xWidth - xScrollWidth >=
  495. pLegend->aCols[LegendColorCol].xMinWidth) {
  496. pLegend->aCols[LegendColorCol].xWidth -= xScrollWidth ;
  497. pLegend->aCols[LegendCounterCol].xWidth += xScrollWidth ;
  498. }
  499. if (pLegend->aCols[LegendInstanceCol].xWidth - xScrollWidth >=
  500. pLegend->aCols[LegendInstanceCol].xMinWidth) {
  501. pLegend->aCols[LegendInstanceCol].xWidth -= xScrollWidth ;
  502. pLegend->aCols[LegendCounterCol].xWidth += xScrollWidth ;
  503. }
  504. if (pLegend->aCols[LegendParentCol].xWidth - xScrollWidth >=
  505. pLegend->aCols[LegendParentCol].xMinWidth) {
  506. pLegend->aCols[LegendParentCol].xWidth -= xScrollWidth ;
  507. pLegend->aCols[LegendCounterCol].xWidth += xScrollWidth ;
  508. }
  509. }
  510. //=============================//
  511. // Set Column positions //
  512. //=============================//
  513. pLegend->aCols[0].xPos = LegendLeftMargin () ;
  514. for (iCol = 1 ;
  515. iCol < iLegendNumCols ;
  516. iCol++) { // for
  517. pLegend->aCols[iCol].xPos =
  518. pLegend->aCols[iCol - 1].xPos + pLegend->aCols[iCol - 1].xWidth ;
  519. if (iCol == LegendCounterCol) {
  520. // add some space between Scale/Value col & Counter col
  521. pLegend->aCols[LegendCounterCol].xPos += LegendLeftMargin () ;
  522. }
  523. } // for
  524. } // OnSize
  525. void static OnPaint (HWND hWnd)
  526. { // OnPaint
  527. PLEGEND pLegend ;
  528. HDC hDC ;
  529. PAINTSTRUCT ps ;
  530. hDC = BeginPaint (hWnd, &ps) ;
  531. if (IsLegendLabelVisible ()) {
  532. pLegend = LegendData (hWnd) ;
  533. DrawLegendLabel (pLegend, hDC, hWnd) ;
  534. }
  535. EndPaint (hWnd, &ps) ;
  536. } // OnPaint
  537. void OnDrawLegendItem (HWND hWnd,
  538. LPDRAWITEMSTRUCT lpDI)
  539. { // OnDrawItem
  540. HFONT hFontPrevious ;
  541. HDC hDC ;
  542. PLEGEND pLegend ;
  543. PLINESTRUCT pLine ;
  544. int iLBIndex ;
  545. COLORREF preBkColor ;
  546. COLORREF preTextColor ;
  547. hDC = lpDI->hDC ;
  548. iLBIndex = DIIndex (lpDI) ;
  549. pLegend = LegendData (hWnd) ;
  550. if (iLBIndex == -1)
  551. pLine = NULL ;
  552. else
  553. pLine = (PLINESTRUCT) LBData (pLegend->hWndItems, iLBIndex) ;
  554. //=============================//
  555. // Set DC attributes //
  556. //=============================//
  557. if (DISelected (lpDI)) { // if
  558. preTextColor = SetTextColor (hDC, GetSysColor (COLOR_HIGHLIGHTTEXT)) ;
  559. preBkColor = SetBkColor (hDC, GetSysColor (COLOR_HIGHLIGHT)) ;
  560. } // if
  561. ExtTextOut (hDC, lpDI->rcItem.left, lpDI->rcItem.top,
  562. ETO_OPAQUE, &(lpDI->rcItem), NULL, 0, NULL ) ;
  563. //=============================//
  564. // Draw Legend Item //
  565. //=============================//
  566. hFontPrevious = SelectFont (hDC, pLegend->hFontItems) ;
  567. if (pLine)
  568. DrawLegendItem (pLegend, pLine, lpDI->rcItem.top, hDC) ;
  569. SelectFont (hDC, hFontPrevious) ;
  570. //=============================//
  571. // Draw Focus //
  572. //=============================//
  573. if (DIFocus (lpDI))
  574. DrawFocusRect (hDC, &(lpDI->rcItem)) ;
  575. if (DISelected (lpDI)) { // if
  576. preTextColor = SetTextColor (hDC, preTextColor) ;
  577. preBkColor = SetBkColor (hDC, preBkColor) ;
  578. } // if
  579. } // OnDrawItem
  580. void static OnMeasureItem (HWND hWnd,
  581. LPMEASUREITEMSTRUCT lpMI)
  582. { // OnMeasureItem
  583. PLEGEND pLegend ;
  584. pLegend = LegendData (hWnd) ;
  585. lpMI->itemHeight = pLegend->yItemHeight ;
  586. } // OnMeasureItem
  587. void static OnDestroy (HWND hWnd)
  588. {
  589. PLEGEND pLegend ;
  590. pLegend = LegendData (hWnd) ;
  591. MemoryFree (pLegend) ;
  592. } // OnDestroy
  593. void static OnDoubleClick (HWND hWnd)
  594. {
  595. PLEGEND pLegend ;
  596. pLegend = LegendData (hWnd) ;
  597. if (!pLegend)
  598. return ;
  599. switch (pLegend->iLineType) { // switch
  600. case LineTypeChart:
  601. EditChart (hWndMain) ;
  602. break ;
  603. } // switch
  604. } // OnDoubleClick
  605. void static OnSetFocus (HWND hWnd)
  606. { // OnSetFocus
  607. PLEGEND pLegend ;
  608. pLegend = LegendData (hWnd) ;
  609. SetFocus (pLegend->hWndItems) ;
  610. }
  611. void static OnSelectionChanged (HWND hWnd)
  612. { // OnSelectionChanged
  613. PLEGEND pLegend ;
  614. PGRAPHSTRUCT pGraph ;
  615. INT_PTR iIndex ;
  616. pLegend = LegendData (hWnd) ;
  617. // set the new selected line
  618. iIndex = LBSelection (pLegend->hWndItems) ;
  619. if (iIndex == LB_ERR)
  620. return ;
  621. LegendSetCurrentLine (pLegend, iIndex) ;
  622. } // OnSelectionChanged
  623. //==========================================================================//
  624. // Exported Functions //
  625. //==========================================================================//
  626. LRESULT
  627. APIENTRY
  628. GraphLegendWndProc (
  629. HWND hWnd,
  630. UINT wMsg,
  631. WPARAM wParam,
  632. LPARAM lParam
  633. )
  634. { // GraphLegendWndProc
  635. BOOL bCallDefProc ;
  636. LRESULT lReturnValue ;
  637. bCallDefProc = FALSE ;
  638. lReturnValue = 0L ;
  639. switch (wMsg) { // switch
  640. case WM_DELETEITEM:
  641. break ;
  642. case WM_COMMAND:
  643. switch (HIWORD (wParam)) { // switch
  644. case LBN_DBLCLK:
  645. OnDoubleClick (hWnd) ;
  646. break ;
  647. case LBN_SELCHANGE:
  648. OnSelectionChanged (hWnd) ;
  649. break ;
  650. default:
  651. break ;
  652. } // switch
  653. break ;
  654. case WM_CREATE:
  655. OnLegendCreate (hWnd, (LPCREATESTRUCT) lParam) ;
  656. break ;
  657. case WM_DESTROY:
  658. OnDestroy (hWnd) ;
  659. break ;
  660. case WM_DRAWITEM:
  661. OnDrawLegendItem (hWnd, (LPDRAWITEMSTRUCT) lParam) ;
  662. break ;
  663. case WM_MEASUREITEM:
  664. OnMeasureItem (hWnd, (LPMEASUREITEMSTRUCT) lParam) ;
  665. break ;
  666. case WM_PAINT:
  667. OnPaint (hWnd) ;
  668. break ;
  669. case WM_SIZE:
  670. OnSize (hWnd, LOWORD (lParam), HIWORD (lParam)) ;
  671. break ;
  672. case WM_SETFOCUS:
  673. OnSetFocus (hWnd) ;
  674. break ;
  675. default:
  676. bCallDefProc = TRUE ;
  677. } // switch
  678. if (bCallDefProc)
  679. lReturnValue = DefWindowProc (hWnd, wMsg, wParam, lParam) ;
  680. return (lReturnValue);
  681. } // GraphLegendWndProc
  682. int LegendMinWidth (HWND hWnd)
  683. {
  684. PLEGEND pLegend ;
  685. int iCol ;
  686. int xMinWidth ;
  687. pLegend = LegendData (hWnd) ;
  688. xMinWidth = 0 ;
  689. for (iCol = 0 ;
  690. iCol < iLegendNumCols ;
  691. iCol++) { // for
  692. xMinWidth += pLegend->aCols[iCol].xMinWidth ;
  693. } // for
  694. return (xMinWidth) ;
  695. }
  696. int LegendMinHeight (HWND hWnd)
  697. {
  698. PLEGEND pLegend ;
  699. pLegend = LegendData (hWnd) ;
  700. if (IsLegendLabelVisible ())
  701. return (pLegend->yLabelHeight + pLegend->yItemHeight) ;
  702. else
  703. return (pLegend->yItemHeight) ;
  704. }
  705. int LegendHeight (HWND hWnd, int yGraphHeight)
  706. /*
  707. Effect: Return the best height for the Legend window given the
  708. number of items and label visibility of the legend, as
  709. well as the overall height of the graph.
  710. */
  711. { // LegendHeight
  712. PLEGEND pLegend ;
  713. int yPreferredHeight ;
  714. pLegend = LegendData (hWnd) ;
  715. yPreferredHeight = yLegendBorderHeight +
  716. pLegend->yItemHeight *
  717. PinInclusive (LBNumItems (pLegend->hWndItems),
  718. 1, iLegendMaxVisibleItems) ;
  719. if (IsLegendLabelVisible ())
  720. yPreferredHeight += pLegend->yLabelHeight ;
  721. return (min (yPreferredHeight, yGraphHeight / 2)) ;
  722. } // LegendHeight
  723. int LegendFullHeight (HWND hWnd, HDC hDC)
  724. /*
  725. Effect: Return the best height for the Legend window given the
  726. number of items and label visibility of the legend, as
  727. well as the overall height of the graph.
  728. */
  729. { // LegendHeight
  730. PLEGEND pLegend ;
  731. int yPreferredHeight ;
  732. pLegend = LegendData (hWnd) ;
  733. yPreferredHeight = yLegendBorderHeight +
  734. pLegend->yItemHeight *
  735. LBNumItems (pLegend->hWndItems) ;
  736. if (IsLegendLabelVisible ())
  737. yPreferredHeight += pLegend->yLabelHeight ;
  738. return (yPreferredHeight) ;
  739. } // LegendFullHeight
  740. HWND CreateGraphLegendWindow (HWND hWndGraph)
  741. {
  742. return (CreateWindow (szGraphLegendClass, // class
  743. NULL, // caption
  744. dwGraphLegendWindowStyle, // window style
  745. 0, 0, // position
  746. 0, 0, // size
  747. hWndGraph, // parent window
  748. NULL, // menu
  749. hInstance, // program instance
  750. (LPVOID) TRUE)) ; // user-supplied data
  751. }
  752. BOOL GraphLegendInitializeApplication (void)
  753. /*
  754. Called By: GraphInitializeApplication only
  755. */
  756. {
  757. WNDCLASS wc ;
  758. wc.style = dwGraphLegendClassStyle ;
  759. wc.lpfnWndProc = GraphLegendWndProc ;
  760. wc.hInstance = hInstance ;
  761. wc.cbClsExtra = iGraphLegendClassExtra ;
  762. wc.cbWndExtra = iGraphLegendWindowExtra ;
  763. wc.hIcon = NULL ;
  764. wc.hCursor = LoadCursor (NULL, IDC_ARROW) ;
  765. wc.hbrBackground = hbLightGray ;
  766. wc.lpszMenuName = NULL ;
  767. wc.lpszClassName = szGraphLegendClass ;
  768. return (RegisterClass (&wc)) ;
  769. }
  770. BOOL LegendAddItem (HWND hWnd, PLINESTRUCT pLine)
  771. /*
  772. Effect: Add a legend entry for the line pLine. Don't select
  773. the line as current entry here, because this will cause
  774. the scroll bar to unneccesarily appear for a moment.
  775. If you want this line to be the current line, resize
  776. the legend first, then set as current line.
  777. See Also: ChartInsertLine.
  778. */
  779. { // LegendAddItem
  780. PLEGEND pLegend ;
  781. pLegend = LegendData (hWnd) ;
  782. LBAdd (pLegend->hWndItems, pLine) ;
  783. return (TRUE) ;
  784. } // LegendAddItem
  785. void LegendDeleteItem (HWND hWndLegend,
  786. PLINE pLine)
  787. { // LegendDeleteItem
  788. PLEGEND pLegend ;
  789. INT_PTR iIndex ;
  790. INT_PTR iNextIndex ;
  791. INT_PTR iNumItems ;
  792. PGRAPHSTRUCT pGraph ;
  793. pLegend = LegendData (hWndLegend) ;
  794. if (!pLegend)
  795. return ;
  796. iNumItems = LBNumItems (pLegend->hWndItems) ;
  797. iIndex = LBFind (pLegend->hWndItems, pLine) ;
  798. if (iIndex != LB_ERR) {
  799. LBDelete (pLegend->hWndItems, iIndex) ;
  800. }
  801. // no need to do anything if iNumItems is 1 to begin with
  802. if (iNumItems != LB_ERR && iNumItems > 1) {
  803. if (iIndex == iNumItems - 1) {
  804. // deleting the last line, then set selection
  805. // to the previous legend line
  806. iNextIndex = iIndex - 1 ;
  807. } else {
  808. // set the selection to the next legend line
  809. iNextIndex = iIndex ;
  810. }
  811. LBSetSelection (pLegend->hWndItems, iNextIndex) ;
  812. LegendSetCurrentLine (pLegend, iNextIndex) ;
  813. }
  814. } // LegendDeleteItem
  815. PLINE LegendCurrentLine (HWND hWndLegend)
  816. { // LegendCurrentLine
  817. PLEGEND pLegend ;
  818. pLegend = LegendData (hWndLegend) ;
  819. if (!pLegend)
  820. return (NULL) ;
  821. return (pLegend->pCurrentLine) ;
  822. } // LegendCurrentLine
  823. int LegendNumItems (HWND hWndLegend)
  824. { // LegendNumItems
  825. PLEGEND pLegend ;
  826. pLegend = LegendData (hWndLegend) ;
  827. return (LBNumItems (pLegend->hWndItems)) ;
  828. } // LegendNumItems
  829. void LegendSetSelection (HWND hWndLegend, int iIndex)
  830. { // LegendSetSelection
  831. PLEGEND pLegend ;
  832. pLegend = LegendData (hWndLegend) ;
  833. LBSetSelection (pLegend->hWndItems, iIndex) ;
  834. LegendSetCurrentLine (pLegend, iIndex) ;
  835. } // LegendSetSelection
  836. #ifdef KEEP_PRINT
  837. void PrintLegend (HDC hDC, PGRAPHSTRUCT pGraph, HWND hWndLegend,
  838. RECT rectLegend)
  839. {
  840. PLEGEND pLegend ;
  841. int yItemHeight ;
  842. HFONT hFontItems ;
  843. PLINE pLine ;
  844. int iIndex ;
  845. int iIndexNum ;
  846. pLegend = LegendData (hWndLegend) ;
  847. yItemHeight = pLegend->yItemHeight ;
  848. hFontItems = pLegend->hFontItems ;
  849. pLegend->hFontItems = hFontPrinterScales ;
  850. SelectFont (hDC, pLegend->hFontItems) ;
  851. pLegend->yItemHeight = FontHeight (hDC, TRUE) ;
  852. iIndexNum = LBNumItems (pLegend->hWndItems) ;
  853. for (iIndex = 0 ;
  854. iIndex < iIndexNum ;
  855. iIndex++) { // for
  856. pLine = (PLINE) LBData (pLegend->hWndItems, iIndex) ;
  857. DrawLegendItem (pLegend, pLine, iIndex * pLegend->yItemHeight, hDC) ;
  858. } // for
  859. pLegend->hFontItems = hFontItems ;
  860. pLegend->yItemHeight = yItemHeight ;
  861. SelectBrush (hDC, GetStockObject (HOLLOW_BRUSH)) ;
  862. SelectPen (hDC, GetStockObject (BLACK_PEN)) ;
  863. Rectangle (hDC, 0, 0,
  864. rectLegend.right - rectLegend.left,
  865. rectLegend.bottom - rectLegend.top) ;
  866. }
  867. #endif
  868. void ClearLegend (HWND hWndLegend)
  869. {
  870. PLEGEND pLegend ;
  871. pLegend = LegendData (hWndLegend) ;
  872. if (!pLegend)
  873. return ;
  874. LBReset (pLegend->hWndItems) ;
  875. pLegend->pCurrentLine = NULL ;
  876. }
  877. void LegendSetRedraw (HWND hWndLegend, BOOL bRedraw)
  878. {
  879. PLEGEND pLegend ;
  880. pLegend = LegendData (hWndLegend) ;
  881. if (!pLegend)
  882. return ;
  883. LBSetRedraw (pLegend->hWndItems, bRedraw) ;
  884. }