meter.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516
  1. ////////////////////////////////////////////////////////////////////////////////
  2. //
  3. // Copyright 2016 RWS Inc, All Rights Reserved
  4. //
  5. // This program is free software; you can redistribute it and/or modify
  6. // it under the terms of version 2 of the GNU General Public License as published by
  7. // the Free Software Foundation
  8. //
  9. // This program is distributed in the hope that it will be useful,
  10. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. // GNU General Public License for more details.
  13. //
  14. // You should have received a copy of the GNU General Public License along
  15. // with this program; if not, write to the Free Software Foundation, Inc.,
  16. // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  17. //
  18. //////////////////////////////////////////////////////////////////////////////
  19. //
  20. // METER.CPP
  21. //
  22. // History:
  23. // 09/19/96 JMI Started.
  24. //
  25. // 09/24/96 JMI Now consists of a CDlg and a CGuiItem.
  26. //
  27. // 10/31/96 JMI Changed:
  28. // Old label: New label:
  29. // ========= =========
  30. // CMeter RMeter
  31. // CImage RImage
  32. // CGuiItem RGuiItem
  33. // NEEDLE Needle
  34. // DIGITAL Digital
  35. // BAR Bar
  36. // HISTOGRAM Histogram
  37. // NUM_DISPLAY_TYPES NumDisplayTypes
  38. // PERCENTAGE Percentage
  39. // VALUE Value
  40. // NUM_INFO_TYPES NumInfoTypes
  41. //
  42. // 11/01/96 JMI Changed:
  43. // Old label: New label:
  44. // ========= =========
  45. // Rect RRect
  46. //
  47. // Also, changed all members referenced in RImage to
  48. // m_ and all position/dimension members referenced in
  49. // RImage to type short usage.
  50. //
  51. // 12/19/96 JMI Uses new m_justification (as m_sJustification) and
  52. // upgraded to new RFont/RPrint.
  53. //
  54. //////////////////////////////////////////////////////////////////////////////
  55. //
  56. // This object allows one to create a meter of varying type with a particular
  57. // value either set explicitly or by calling Start/EndPeriod() to time an
  58. // operation or group of operations. The meter can even be used to time
  59. // itself. If you keep several meters running in debug mode of your program,
  60. // you will be more likely to notice right away when certain changes impact
  61. // performance. Try 'em!
  62. //
  63. //////////////////////////////////////////////////////////////////////////////
  64. //////////////////////////////////////////////////////////////////////////////
  65. // Headers.
  66. //////////////////////////////////////////////////////////////////////////////
  67. #include <stdlib.h>
  68. #include "Blue.h"
  69. #ifdef PATHS_IN_INCLUDES
  70. #include "ORANGE/Meter/meter.h"
  71. #else
  72. #include "meter.h"
  73. #endif // PATHS_IN_INCLUDES
  74. //////////////////////////////////////////////////////////////////////////////
  75. // Module specific macros.
  76. //////////////////////////////////////////////////////////////////////////////
  77. // Sets val to def if val is -1.
  78. #define DEF(val, def) ((val == -1) ? def : val)
  79. #define DEF_WIDTH 75
  80. #define DEF_HEIGHT 50
  81. #define BORDER_THICKNESS 1
  82. #define INIT_MAX 0
  83. #define INIT_MIN 0x7FFFFFFF
  84. //////////////////////////////////////////////////////////////////////////////
  85. // Module specific typedefs.
  86. //////////////////////////////////////////////////////////////////////////////
  87. //////////////////////////////////////////////////////////////////////////////
  88. // Module specific (static) variables.
  89. //////////////////////////////////////////////////////////////////////////////
  90. //////////////////////////////////////////////////////////////////////////////
  91. // Construction/Destruction.
  92. //////////////////////////////////////////////////////////////////////////////
  93. //////////////////////////////////////////////////////////////////////////////
  94. //
  95. // Default constructor.
  96. //
  97. //////////////////////////////////////////////////////////////////////////////
  98. RMeter::RMeter()
  99. {
  100. m_lCurVal = 0L; // Value for next draw.
  101. m_lStartPeriod = 0L; // Start period.
  102. strcpy(m_szUnit, ""); // Unit of measurement text.
  103. m_lMin = 0L; // Minimum value.
  104. m_lMax = 100L; // Maximum value.
  105. m_dtType = (DisplayType)(rand() % NumDisplayTypes); // Type of meter display.
  106. m_itType = (InfoType)(rand() % NumInfoTypes); // Type of meter info.
  107. m_u32Meter = RSP_WHITE_INDEX; // Meter color.
  108. m_u32Needle = RSP_BLACK_INDEX; // Needle, bar, etc. color.
  109. m_u32Overflow = RSP_BLACK_INDEX; // Needle color for over/underflow.
  110. m_lDuration = 100; // Time between updates in milliseconds.
  111. m_lNextUpdate = 0; // Time of next update in
  112. // milliseconds.
  113. m_lCurTotal = 0; // Current total.
  114. m_lNumValues = 0; // Number of values since
  115. // total was last cleared.
  116. m_lMaxValue = INIT_MAX; // Maximum value since
  117. // total was last cleared.
  118. m_lMinValue = INIT_MIN; // Minimum value since
  119. // total was last cleared.
  120. m_lQIndex = 0; // Index for histogram history queue.
  121. memset(m_asQHistory, 0, sizeof(m_asQHistory));
  122. // Override RGuiItem's default justification.
  123. m_justification = RGuiItem::Centered;
  124. m_guiMeter.SetParent(this);
  125. m_guiMeter.m_bcUser = BtnCall;
  126. m_guiMeter.m_ulUserInstance = (ULONG)this;
  127. }
  128. //////////////////////////////////////////////////////////////////////////////
  129. //
  130. // Destructor.
  131. //
  132. //////////////////////////////////////////////////////////////////////////////
  133. RMeter::~RMeter()
  134. {
  135. }
  136. ////////////////////////////////////////////////////////////////////////
  137. // Methods.
  138. ////////////////////////////////////////////////////////////////////////
  139. ////////////////////////////////////////////////////////////////////////
  140. //
  141. // Helper that keeps us from getting TRACE messages from rspRect when
  142. // we have a height or width of 0.
  143. //
  144. ////////////////////////////////////////////////////////////////////////
  145. inline short Rectangle( // Returns 0 on success.
  146. U32 u32Color, // Color.
  147. RImage* pimDst, // Destination.
  148. short sDstX, // Destination x coordinate.
  149. short sDstY, // Destination y coordinate.
  150. short sDstW, // Width.
  151. short sDstH, // Height.
  152. RRect* prClip = NULL) // Optional clipping rectangle.
  153. {
  154. short sRes = 0; // Assume success.
  155. if (sDstW > 0 && sDstH > 0)
  156. {
  157. sRes = rspRect(u32Color, pimDst, sDstX, sDstY, sDstW, sDstH, prClip);
  158. }
  159. return sRes;
  160. }
  161. ////////////////////////////////////////////////////////////////////////
  162. //
  163. // Compose the static portions. Fills the parts of the image
  164. // that don't change.
  165. //
  166. ////////////////////////////////////////////////////////////////////////
  167. void RMeter::Compose( // Returns nothing.
  168. RImage* pimDst /*= NULL*/) // In: Destination. NULL == use
  169. // internal m_im.
  170. {
  171. short sRes = 0; // Assume success.
  172. if (pimDst == NULL)
  173. {
  174. pimDst = &m_im;
  175. }
  176. // Call base class.
  177. RDlg::Compose();
  178. short sX, sY, sW, sH;
  179. GetClient(&sX, &sY, &sW, &sH);
  180. short sCellH;
  181. m_pprint->GetPos(NULL, NULL, NULL, &sCellH);
  182. short sMeterX;
  183. short sMeterY;
  184. short sMeterW;
  185. short sMeterH;
  186. // Behave by type.
  187. switch (m_dtType)
  188. {
  189. case Digital:
  190. sMeterX = sX + BORDER_THICKNESS;
  191. sMeterY = sY + BORDER_THICKNESS;
  192. sMeterW = sW - BORDER_THICKNESS * 2;
  193. sMeterH = sH - BORDER_THICKNESS * 2;
  194. m_sInfoY = sMeterY + (sMeterH / 2 - sCellH / 2);
  195. break;
  196. case Needle:
  197. case Bar:
  198. case Histogram:
  199. sMeterX = sX + BORDER_THICKNESS;
  200. sMeterY = sY + BORDER_THICKNESS;
  201. sMeterW = sW - BORDER_THICKNESS * 2;
  202. sMeterH = sH - BORDER_THICKNESS * 2 - sCellH;
  203. m_sInfoY = sMeterY + sMeterH;
  204. break;
  205. default:
  206. TRACE("Compose(): Invalid display type.\n");
  207. break;
  208. }
  209. m_guiMeter.m_u32BackColor = m_u32Meter;
  210. m_guiMeter.m_u32TextColor = m_u32TextColor;
  211. m_guiMeter.m_u32BorderColor = m_u32BorderColor;
  212. m_guiMeter.m_u32BorderShadowColor = m_u32BorderShadowColor;
  213. m_guiMeter.m_u32BorderHighlightColor = m_u32BorderHighlightColor;
  214. m_guiMeter.m_u32BorderEdgeColor = m_u32BorderEdgeColor;
  215. m_guiMeter.m_sBorderThickness = m_sBorderThickness;
  216. m_guiMeter.m_sInvertedBorder = !m_sInvertedBorder;
  217. // If there is already data . . .
  218. if (m_guiMeter.m_im.m_pData != NULL)
  219. {
  220. m_guiMeter.m_im.DestroyData();
  221. }
  222. // Attempt to create display . . .
  223. if (m_guiMeter.Create(sMeterX, sMeterY, sMeterW, sMeterH,
  224. m_im.m_sDepth) == 0)
  225. {
  226. // Set hot area to entire button.
  227. m_guiMeter.GetClient(
  228. &(m_guiMeter.m_hot.m_sX),
  229. &(m_guiMeter.m_hot.m_sY),
  230. &(m_guiMeter.m_hot.m_sW),
  231. &(m_guiMeter.m_hot.m_sH) );
  232. m_guiMeter.ChildPosToTop(&(m_guiMeter.m_hot.m_sX), &(m_guiMeter.m_hot.m_sY));
  233. }
  234. else
  235. {
  236. TRACE("Compose(): Failed to create meter display Gui.\n");
  237. }
  238. }
  239. ////////////////////////////////////////////////////////////////////////
  240. //
  241. // Composes the meter into the image provided. For consistency, you
  242. // should probably always draw the meter.
  243. //
  244. ////////////////////////////////////////////////////////////////////////
  245. short RMeter::Draw( // Returns 0 on success.
  246. RImage* pimDst, // Destination image.
  247. short sDstX /*= 0*/, // X position in destination.
  248. short sDstY /*= 0*/, // Y position in destination.
  249. short sSrcX /*= 0*/, // X position in source.
  250. short sSrcY /*= 0*/, // Y position in source.
  251. short sW /*= 0*/, // Amount to draw.
  252. short sH /*= 0*/, // Amount to draw.
  253. RRect* prc /*= NULL*/) // Clip to.
  254. {
  255. short sRes = 0; // Assume success.
  256. ASSERT(pimDst != NULL); // Duh!
  257. // If visible . . .
  258. if (m_sVisible != FALSE)
  259. {
  260. long lTime = rspGetMilliseconds();
  261. if (lTime >= m_lNextUpdate)
  262. {
  263. // First copy precomposed stuff.
  264. if (m_im.m_pData != NULL)
  265. {
  266. RDlg::Draw(pimDst, sDstX, sDstY, sSrcX, sSrcY, sW, sH, prc);
  267. }
  268. short sMeterX;
  269. short sMeterY;
  270. short sMeterW;
  271. short sMeterH;
  272. m_guiMeter.GetClient(&sMeterX, &sMeterY, &sMeterW, &sMeterH);
  273. sMeterX += m_sX + m_guiMeter.m_sX + sDstX;
  274. sMeterY += m_sY + m_guiMeter.m_sY + sDstY;
  275. short sInfoY = m_sY + sDstY + m_sInfoY;
  276. long lAvg = 0;
  277. if (m_lNumValues > 0)
  278. {
  279. lAvg = m_lCurTotal / m_lNumValues;
  280. }
  281. // Draw text label.
  282. if (m_pprint->GetFont() != NULL)
  283. {
  284. // Determine info based on type.
  285. long lVal = lAvg;
  286. char szExtra[32] = "";
  287. switch (m_itType)
  288. {
  289. case Value:
  290. break;
  291. case Percentage:
  292. lVal = ((lVal - m_lMin) * 100) / (m_lMax - m_lMin);
  293. strcpy(szExtra, "%");
  294. break;
  295. default:
  296. TRACE("Draw(): Invalid info type.\n");
  297. break;
  298. }
  299. // If digital . . .
  300. if (m_dtType == Digital)
  301. {
  302. m_pprint->SetColor((short)m_u32Needle);
  303. }
  304. SetJustification();
  305. m_pprint->SetDestination(pimDst);
  306. m_pprint->SetColumn(sMeterX, sInfoY, sMeterW, sMeterH);
  307. // Draw text info.
  308. m_pprint->print(sMeterX, sInfoY, "%ld%s%s", lVal, szExtra, m_szUnit);
  309. }
  310. // Contain within range.
  311. lAvg = MIN(m_lMax, lAvg);
  312. lAvg = MAX(m_lMin, lAvg);
  313. m_lMaxValue = MIN(m_lMax, m_lMaxValue);
  314. m_lMaxValue = MAX(m_lMin, m_lMaxValue);
  315. m_lMinValue = MIN(m_lMax, m_lMinValue);
  316. m_lMinValue = MIN(m_lMin, m_lMinValue);
  317. // Amount to adapt value to match meter width.
  318. float fAdaptor;
  319. // Adapted values.
  320. short sMeterVal;
  321. short sMeterMax;
  322. short sMeterMin;
  323. // Draw meter based on type.
  324. switch (m_dtType)
  325. {
  326. case Digital:
  327. // Done.
  328. break;
  329. case Needle:
  330. // Compute adaptor.
  331. fAdaptor = (float)sMeterW / (float)(m_lMax - m_lMin);
  332. // Compute adapted.
  333. sMeterVal = (short)((float)lAvg * fAdaptor);
  334. sMeterMin = (short)((float)m_lMinValue * fAdaptor);
  335. sMeterMax = (short)((float)m_lMaxValue * fAdaptor);
  336. // Draw min.
  337. Rectangle(
  338. m_u32Overflow,
  339. pimDst,
  340. sMeterX + sMeterMin, sMeterY,
  341. 1, sMeterH
  342. );
  343. // Draw avg.
  344. Rectangle(
  345. m_u32Needle,
  346. pimDst,
  347. sMeterX + sMeterVal, sMeterY,
  348. 1, sMeterH
  349. );
  350. // Draw max.
  351. Rectangle(
  352. m_u32Overflow,
  353. pimDst,
  354. sMeterX + sMeterMax, sMeterY,
  355. 1, sMeterH
  356. );
  357. break;
  358. case Bar:
  359. // Compute adaptor.
  360. fAdaptor = (float)sMeterW / (float)(m_lMax - m_lMin);
  361. // Compute adapted.
  362. sMeterVal = (short)((float)lAvg * fAdaptor);
  363. sMeterMin = (short)((float)m_lMinValue * fAdaptor);
  364. sMeterMax = (short)((float)m_lMaxValue * fAdaptor);
  365. // Draw min.
  366. Rectangle(
  367. m_u32Overflow,
  368. pimDst,
  369. sMeterX, sMeterY,
  370. sMeterMin, sMeterH
  371. );
  372. // Draw avg.
  373. Rectangle(
  374. m_u32Needle,
  375. pimDst,
  376. sMeterX + sMeterMin, sMeterY,
  377. sMeterVal - sMeterMin, sMeterH
  378. );
  379. // Draw max.
  380. Rectangle(
  381. m_u32Overflow,
  382. pimDst,
  383. sMeterX + sMeterVal, sMeterY,
  384. sMeterMax - sMeterVal, sMeterH
  385. );
  386. break;
  387. case Histogram:
  388. {
  389. // Compute adaptor.
  390. fAdaptor = (float)sMeterH / (float)(m_lMax - m_lMin);
  391. // Compute adapted.
  392. sMeterVal = (short)((float)lAvg * fAdaptor);
  393. sMeterMin = (short)((float)m_lMinValue * fAdaptor);
  394. sMeterMax = (short)((float)m_lMaxValue * fAdaptor);
  395. // Store new value.
  396. m_asQHistory[m_lQIndex] = sMeterVal;
  397. // Increase index.
  398. m_lQIndex = (m_lQIndex + 1) % METER_HISTOGRAM_HISTORY;
  399. long l;
  400. short sVal;
  401. short sBarWidth = sMeterW / METER_HISTOGRAM_HISTORY;
  402. short sBarPos = sMeterX;
  403. for (l = 0; l < (METER_HISTOGRAM_HISTORY - 1); l++, sBarPos += sBarWidth)
  404. {
  405. // Get value.
  406. sVal = m_asQHistory[(m_lQIndex + l) % METER_HISTOGRAM_HISTORY];
  407. // Draw avg bar.
  408. Rectangle(
  409. m_u32Needle,
  410. pimDst,
  411. sBarPos,
  412. sMeterY + (sMeterH - sVal),
  413. sBarWidth, sVal
  414. );
  415. }
  416. short sPosY = sMeterY + sMeterH - sMeterMax;
  417. short sDiff = sMeterMax - sMeterVal;
  418. Rectangle(
  419. m_u32Overflow,
  420. pimDst,
  421. sBarPos,
  422. sPosY,
  423. sBarWidth, sDiff);
  424. // Draw avg.
  425. sPosY += sDiff;
  426. sDiff = sMeterVal - sMeterMin;
  427. Rectangle(
  428. m_u32Needle,
  429. pimDst,
  430. sBarPos,
  431. sPosY,
  432. sBarWidth, sDiff);
  433. // Draw max.
  434. sPosY += sDiff;
  435. // Draw min.
  436. Rectangle(
  437. m_u32Overflow,
  438. pimDst,
  439. sBarPos,
  440. sPosY,
  441. sBarWidth, sMeterMin);
  442. break;
  443. }
  444. }
  445. // Reset counter, accumulator, max, min.
  446. m_lMaxValue = INIT_MAX;
  447. m_lMinValue = INIT_MIN;
  448. m_lCurTotal = 0;
  449. m_lNumValues = 0;
  450. // Remember when to update next.
  451. m_lNextUpdate = lTime + m_lDuration;
  452. }
  453. }
  454. return sRes;
  455. }
  456. ////////////////////////////////////////////////////////////////////////
  457. // Querries.
  458. ////////////////////////////////////////////////////////////////////////
  459. //////////////////////////////////////////////////////////////////////////////
  460. // EOF
  461. //////////////////////////////////////////////////////////////////////////////