GAUGE.CPP 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539
  1. /*
  2. ** Command & Conquer(tm)
  3. ** Copyright 2025 Electronic Arts Inc.
  4. **
  5. ** This program is free software: you can redistribute it and/or modify
  6. ** it under the terms of the GNU General Public License as published by
  7. ** the Free Software Foundation, either version 3 of the License, or
  8. ** (at your option) any later version.
  9. **
  10. ** This program is distributed in the hope that it will be useful,
  11. ** but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. ** GNU General Public License for more details.
  14. **
  15. ** You should have received a copy of the GNU General Public License
  16. ** along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. /* $Header: F:\projects\c&c\vcs\code\gauge.cpv 2.19 16 Oct 1995 16:50:56 JOE_BOSTIC $ */
  19. /***********************************************************************************************
  20. *** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S ***
  21. ***********************************************************************************************
  22. * *
  23. * Project Name : Command & Conquer *
  24. * *
  25. * File Name : GAUGE.CPP *
  26. * *
  27. * Programmer : Joe L. Bostic, Maria del Mar McCready Legg *
  28. * *
  29. * Start Date : 01/15/95 *
  30. * *
  31. * Last Update : January 16, 1995 [JLB] *
  32. * *
  33. *---------------------------------------------------------------------------------------------*
  34. * Functions: *
  35. * GaugeClass::Action -- Handles input events for the gauge. *
  36. * GaugeClass::Draw_Me -- Draws the body of the gauge. *
  37. * GaugeClass::Value_To_Pixel -- Convert gauge value to pixel offset. *
  38. * GaugeClass::Pixel_To_Value -- Convert a pixel offset into a gauge value. *
  39. * GaugeClass::Set_Value -- Set the value of the gauge. *
  40. * GaugeClass::Set_Maximum -- Sets the maximum value for the gauge. *
  41. * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  42. #include "function.h"
  43. /***************************************************************************
  44. * GAUGECLASS::GAUGECLASS -- class constructor *
  45. * *
  46. * INPUT: id -- button ID *
  47. * *
  48. * x,y -- upper-left corner, in pixels *
  49. * *
  50. * w,h -- width, height, in pixels *
  51. * *
  52. * OUTPUT: none. *
  53. * *
  54. * WARNINGS: none. *
  55. * *
  56. * HISTORY: 01/05/1995 MML : Created. *
  57. *=========================================================================*/
  58. GaugeClass::GaugeClass(unsigned id, int x, int y, int w, int h)
  59. : ControlClass(id, x, y, w, h, LEFTHELD|LEFTPRESS|LEFTRELEASE, true)
  60. {
  61. Set_Maximum(255);
  62. Set_Value(0);
  63. HasThumb = true;
  64. IsHorizontal = (w > h);
  65. IsColorized = true;
  66. ClickDiff = 0;
  67. }
  68. /***********************************************************************************************
  69. * GaugeClass::Set_Maximum -- Sets the maximum value for the gauge. *
  70. * *
  71. * This routine will set the maximum value for the gauge. This is the largest value that *
  72. * the current setting may reach. The ability to change this allows the guage to use and *
  73. * return values that are convenient for the programmer's current needs. *
  74. * *
  75. * INPUT: value -- The value to use as the gauge maximum. *
  76. * *
  77. * OUTPUT: bool; Was the gauge maximum changed? A false indicates that the specified value *
  78. * already matches the current maximum. *
  79. * *
  80. * WARNINGS: none *
  81. * *
  82. * HISTORY: *
  83. * 01/16/1995 JLB : Created. *
  84. *=============================================================================================*/
  85. int GaugeClass::Set_Maximum(int value)
  86. {
  87. if (value != MaxValue) {
  88. MaxValue = value;
  89. Flag_To_Redraw();
  90. return(true);
  91. }
  92. return(false);
  93. }
  94. /***********************************************************************************************
  95. * GaugeClass::Set_Value -- Set the value of the gauge. *
  96. * *
  97. * This routine will set the current value for the gauge. This value is clipped to the *
  98. * limits of the gauge maximum. *
  99. * *
  100. * INPUT: value -- The value to set at the new current value. *
  101. * *
  102. * OUTPUT: bool; Was the current setting changed? A false indicates that the setting *
  103. * specified is the same as what was already there. *
  104. * *
  105. * WARNINGS: none *
  106. * *
  107. * HISTORY: *
  108. * 01/16/1995 JLB : Created. *
  109. *=============================================================================================*/
  110. int GaugeClass::Set_Value(int value)
  111. {
  112. value = Bound(value, 0, MaxValue);
  113. // value = MIN(value, MaxValue);
  114. // value = MAX(value, 0);
  115. if (value != CurValue) {
  116. CurValue = value;
  117. Flag_To_Redraw();
  118. return(true);
  119. }
  120. return(false);
  121. }
  122. /***********************************************************************************************
  123. * GaugeClass::Pixel_To_Value -- Convert a pixel offset into a gauge value. *
  124. * *
  125. * Use this routine to conver the specified pixel offset into a gauge value. This is used *
  126. * in translating mouse clicks into a cooresponding setting for the guage. *
  127. * *
  128. * INPUT: pixel -- The pixel offset form the start of the gauge. *
  129. * *
  130. * OUTPUT: Returns with the setting value in guage coordinates. *
  131. * *
  132. * WARNINGS: none *
  133. * *
  134. * HISTORY: *
  135. * 01/16/1995 JLB : Created. *
  136. *=============================================================================================*/
  137. int GaugeClass::Pixel_To_Value(int pixel)
  138. {
  139. int maximum;
  140. if (IsHorizontal) {
  141. pixel -= X+1;
  142. maximum = Width;
  143. } else {
  144. pixel -= Y+1;
  145. maximum = Height;
  146. }
  147. maximum -= 2;
  148. pixel = Bound(pixel, 0, maximum);
  149. // pixel = MIN(pixel, maximum);
  150. // pixel = MAX(pixel, 0);
  151. return(Fixed_To_Cardinal(MaxValue, Cardinal_To_Fixed(maximum, pixel)));
  152. }
  153. /***********************************************************************************************
  154. * GaugeClass::Value_To_Pixel -- Convert gauge value to pixel offset. *
  155. * *
  156. * Use this routine to convert the specified gauge value into a pixel offset from the *
  157. * star of the gauge. This is used for thumb positioning. *
  158. * *
  159. * INPUT: value -- The value to convert to a pixel offset. *
  160. * *
  161. * OUTPUT: Returns with the pixel offset of the specified value from the start of the *
  162. * guage. *
  163. * *
  164. * WARNINGS: none *
  165. * *
  166. * HISTORY: *
  167. * 01/16/1995 JLB : Created. *
  168. *=============================================================================================*/
  169. int GaugeClass::Value_To_Pixel(int value)
  170. {
  171. int maximum;
  172. int start;
  173. if (IsHorizontal) {
  174. maximum = Width;
  175. start = X;
  176. } else {
  177. maximum = Height;
  178. start = Y;
  179. }
  180. maximum -= 2;
  181. return(start + Fixed_To_Cardinal(maximum, Cardinal_To_Fixed(MaxValue, value)));
  182. }
  183. /***********************************************************************************************
  184. * GaugeClass::Draw_Me -- Draws the body of the gauge. *
  185. * *
  186. * This routine will draw the body of the gauge if necessary. *
  187. * *
  188. * INPUT: forced -- Should the gauge be redrawn regardless of the current redraw flag? *
  189. * *
  190. * OUTPUT: bool; Was the gauge redrawn? *
  191. * *
  192. * WARNINGS: none *
  193. * *
  194. * HISTORY: 01/16/1995 JLB : Created. *
  195. *=============================================================================================*/
  196. int GaugeClass::Draw_Me(int forced)
  197. {
  198. if (ControlClass::Draw_Me(forced)) {
  199. /*
  200. ===================== Hide the mouse =====================
  201. */
  202. if (LogicPage == &SeenBuff) {
  203. Conditional_Hide_Mouse(X, Y, X+Width, Y+Height);
  204. }
  205. /*
  206. =========== Draw the body & set text color ===============
  207. */
  208. Draw_Box (X, Y, Width, Height, BOXSTYLE_GREEN_DOWN, true);
  209. /*
  210. ** Colorize the inside of the gauge if indicated.
  211. */
  212. if (IsColorized) {
  213. int middle = Value_To_Pixel(CurValue);
  214. int color = CC_BRIGHT_GREEN;
  215. if (IsHorizontal) {
  216. if (middle >= (X + 1))
  217. LogicPage->Fill_Rect(X+1, Y+1, middle, Y+Height-2, color);
  218. } else {
  219. if (middle >= (Y + 1))
  220. LogicPage->Fill_Rect(X+1, Y+1, X+Width-2, middle, color);
  221. }
  222. }
  223. if (HasThumb)
  224. Draw_Thumb();
  225. /*
  226. =================== Display the mouse ===================
  227. */
  228. if (LogicPage == &SeenBuff) {
  229. Conditional_Show_Mouse();
  230. }
  231. return(true);
  232. }
  233. return(false);
  234. }
  235. /***********************************************************************************************
  236. * GaugeClass::Action -- Handles input events for the gauge. *
  237. * *
  238. * This routine will handle input event processing for the gauge. It will adjust the *
  239. * current setting of the gauge according to the mouse position. *
  240. * *
  241. * INPUT: flags -- The input event that is the reason for this function call. *
  242. * key -- The key code that caused the event. *
  243. * *
  244. * OUTPUT: bool; Was the even recognized, processed, and no further gadget scanning is *
  245. * desird (for this pass). *
  246. * *
  247. * WARNINGS: none *
  248. * HISTORY: *
  249. * 01/16/1995 JLB : Created. *
  250. *=============================================================================================*/
  251. int GaugeClass::Action(unsigned flags, KeyNumType &key)
  252. {
  253. /*
  254. ** If there's no thumb on this gauge, it's a display-only device; ignore
  255. ** any input.
  256. */
  257. if (!HasThumb) {
  258. key = KN_NONE;
  259. return(true);
  260. }
  261. /*
  262. ** We might end up clearing the event bits. Make sure that the sticky
  263. ** process is properly updated anyway.
  264. */
  265. Sticky_Process(flags);
  266. /*
  267. ** If the thumb is currently being "dragged around", then update the slider
  268. ** position according to the mouse position. In all other cases, ignore the
  269. ** button being held down.
  270. */
  271. if ((flags & LEFTPRESS) || ((flags & LEFTHELD) && StuckOn == this)) {
  272. /*
  273. ** Compute the difference between where we clicked, and the edge of
  274. ** the thumb (only if we clicked on the thumb.)
  275. */
  276. if (flags & LEFTPRESS) {
  277. int curpix = Value_To_Pixel(CurValue);
  278. int clickpix = (IsHorizontal ? Get_Mouse_X() : Get_Mouse_Y());
  279. if ( (clickpix > curpix) && (clickpix - curpix) < Thumb_Pixels()) {
  280. ClickDiff = (clickpix - curpix);
  281. } else {
  282. ClickDiff = 0;
  283. }
  284. int testval = Pixel_To_Value(IsHorizontal ?
  285. Get_Mouse_X() - ClickDiff : Get_Mouse_Y() - ClickDiff);
  286. /*
  287. ** Correct for round-down errors in Pixel_To_Value() and
  288. ** Value_To_Pixe(); make ClickDiff exactly right so that
  289. ** at this point, Get_Mouse_n() - ClickDiff converts to
  290. ** CurValue.
  291. */
  292. while (testval < CurValue && ClickDiff > 0) {
  293. ClickDiff--;
  294. testval = Pixel_To_Value(IsHorizontal ?
  295. Get_Mouse_X() - ClickDiff : Get_Mouse_Y() - ClickDiff);
  296. }
  297. }
  298. /*
  299. ** If no change occurred in the gauge, just call Control's Action routine,
  300. ** but turn off the flags so it won't fill in 'key' with the button ID.
  301. ** Thus, no button ID will be returned by Input.
  302. */
  303. if (!Set_Value(Pixel_To_Value(IsHorizontal ?
  304. Get_Mouse_X() - ClickDiff : Get_Mouse_Y() - ClickDiff))) {
  305. flags &= ~(LEFTHELD|LEFTRELEASE|LEFTPRESS);
  306. ControlClass::Action(0,key);
  307. key = KN_NONE;
  308. return(true);
  309. }
  310. } else {
  311. /*
  312. ** Ingore the left mouse button being held down if this gauge is not
  313. ** currently in "sticky" mode. This allows processing of the LEFTPRESS
  314. ** by any derived classes such that this guage can be more closely
  315. ** controlled.
  316. */
  317. flags &= ~LEFTHELD;
  318. }
  319. return(ControlClass::Action(flags, key));
  320. }
  321. /***********************************************************************************************
  322. * GaugeClass::Draw_Thumb -- Draws the body of the gauge. *
  323. * *
  324. * This routine will draw the body of the gauge if necessary. *
  325. * *
  326. * INPUT: none. *
  327. * *
  328. * OUTPUT: none. *
  329. * *
  330. * WARNINGS: none. *
  331. * *
  332. * HISTORY: 01/16/1995 MML : Created. *
  333. *=============================================================================================*/
  334. void GaugeClass::Draw_Thumb(void)
  335. {
  336. int x = Value_To_Pixel(CurValue);
  337. // if ((x + 8) > Value_To_Pixel(MaxValue)) {
  338. if ((x + 4) > Value_To_Pixel(MaxValue)) {
  339. x = Value_To_Pixel(MaxValue) - 2;
  340. }
  341. if (IsHorizontal) {
  342. Draw_Box(x, Y, 4, Height, BOXSTYLE_GREEN_RAISED, true);
  343. //Draw_Box(x, Y, 8, Height, BOXSTYLE_GREEN_RAISED, true);
  344. } else {
  345. Draw_Box(X, x, Width, 4, BOXSTYLE_GREEN_RAISED, true);
  346. //Draw_Box(X, x, Width, 8, BOXSTYLE_GREEN_RAISED, true);
  347. }
  348. }
  349. /***********************************************************************************************
  350. * TriColorGaugeClass::TriColorGaugeClass -- Constructor for 3 color (red\yellow\green) gauge. *
  351. * *
  352. * This routine will draw the body of the gauge if necessary. *
  353. * *
  354. * INPUT: See below. *
  355. * *
  356. * OUTPUT: none. *
  357. * *
  358. * WARNINGS: none. *
  359. * *
  360. * HISTORY: 01/16/1995 MML : Created. *
  361. *=============================================================================================*/
  362. TriColorGaugeClass::TriColorGaugeClass(unsigned id, int x, int y, int w, int h)
  363. : GaugeClass(id, x, y, w, h)
  364. {
  365. RedLimit = 0; // maximum value for red
  366. YellowLimit = 0; // maximum value for yellow
  367. }
  368. /***********************************************************************************************
  369. * TriColorGaugeClass::Set_Red_Limit -- Set the value for the red area of gauge. *
  370. * *
  371. * INPUT: int value. *
  372. * *
  373. * OUTPUT: bool true of false. *
  374. * *
  375. * WARNINGS: none. *
  376. * *
  377. * HISTORY: 01/16/1995 MML : Created. *
  378. *=============================================================================================*/
  379. int TriColorGaugeClass::Set_Red_Limit(int value)
  380. {
  381. if (value >= 0 && value < MaxValue) {
  382. // if (value > YellowLimit) {
  383. // RedLimit = YellowLimit;
  384. // YellowLimit = value;
  385. // } else {
  386. RedLimit = value;
  387. // }
  388. Flag_To_Redraw();
  389. return(true);
  390. }
  391. return(false);
  392. }
  393. /***********************************************************************************************
  394. * TriColorGaugeClass::Set_Yellow_Limit -- Set the value for the yellow area of gauge. *
  395. * *
  396. * INPUT: int value. *
  397. * *
  398. * OUTPUT: bool true of false. *
  399. * *
  400. * WARNINGS: none. *
  401. * *
  402. * HISTORY: 01/16/1995 MML : Created. *
  403. *=============================================================================================*/
  404. int TriColorGaugeClass::Set_Yellow_Limit(int value)
  405. {
  406. if (value >= 0 && value < MaxValue) {
  407. // if (value < RedLimit) {
  408. // YellowLimit = RedLimit;
  409. // RedLimit = value;
  410. // } else {
  411. YellowLimit = value;
  412. // }
  413. Flag_To_Redraw();
  414. return(true);
  415. }
  416. return(false);
  417. }
  418. /***********************************************************************************************
  419. * TriColorGaugeClass::Draw_Me -- Draw the tri color gauge. *
  420. * *
  421. * INPUT: int forced -- draw or not? *
  422. * *
  423. * OUTPUT: bool true of false. *
  424. * *
  425. * WARNINGS: none. *
  426. * *
  427. * HISTORY: 01/16/1995 MML : Created. *
  428. *=============================================================================================*/
  429. int TriColorGaugeClass::Draw_Me(int forced)
  430. {
  431. if (ControlClass::Draw_Me(forced)) {
  432. /*
  433. ===================== Hide the mouse =====================
  434. */
  435. if (LogicPage == &SeenBuff) {
  436. Conditional_Hide_Mouse(X, Y, X+Width, Y+Height);
  437. }
  438. /*
  439. =========== Draw the body & set text color ===============
  440. */
  441. Draw_Box (X, Y, Width, Height, (IsDisabled ? BOXSTYLE_GREEN_RAISED : BOXSTYLE_GREEN_DOWN), true);
  442. /*
  443. ** Colorize the inside of the gauge if indicated.
  444. */
  445. int red = Value_To_Pixel(RedLimit);
  446. int yellow = Value_To_Pixel(YellowLimit);
  447. int middle = Value_To_Pixel(CurValue);
  448. if (CurValue <= RedLimit) {
  449. if (IsHorizontal) {
  450. LogicPage->Fill_Rect(X+1, Y+1, middle, Y+Height-2, PINK);
  451. } else {
  452. LogicPage->Fill_Rect(X+1, Y+1, X+Width-2, middle, PINK);
  453. }
  454. } else if (CurValue > RedLimit && CurValue <= YellowLimit) {
  455. if (IsHorizontal) {
  456. LogicPage->Fill_Rect(X+1, Y+1, red, Y+Height-2, PINK);
  457. LogicPage->Fill_Rect(red, Y+1, middle, Y+Height-2, YELLOW);
  458. } else {
  459. LogicPage->Fill_Rect(X+1, Y+1, X+Width-2, red, PINK);
  460. LogicPage->Fill_Rect(X+1, red, X+Width-2, middle, YELLOW);
  461. }
  462. } else if (CurValue > YellowLimit && CurValue <= MaxValue) {
  463. if (IsHorizontal) {
  464. LogicPage->Fill_Rect(X+1, Y+1, red, Y+Height-2, PINK);
  465. LogicPage->Fill_Rect(red, Y+1, yellow, Y+Height-2, YELLOW);
  466. LogicPage->Fill_Rect(yellow, Y+1, middle, Y+Height-2, GREEN);
  467. } else {
  468. LogicPage->Fill_Rect(X+1, Y+1, X+Width-2, red, PINK);
  469. LogicPage->Fill_Rect(X+1, red, X+Width-2, yellow, YELLOW);
  470. LogicPage->Fill_Rect(X+1, yellow, X+Width-2, middle, GREEN);
  471. }
  472. }
  473. if (HasThumb)
  474. Draw_Thumb();
  475. /*
  476. =================== Display the mouse ===================
  477. */
  478. if (LogicPage == &SeenBuff) {
  479. Conditional_Show_Mouse();
  480. }
  481. return(true);
  482. }
  483. return(false);
  484. }