MultiBtn.cpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568
  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. // MultiBtn.cpp
  21. //
  22. // History:
  23. // 04/10/97 JMI Started this using RPushBtn as a template.
  24. //
  25. // 04/17/97 JMI Added Load and Save components.
  26. //
  27. // 04/22/97 JMI Added NextState().
  28. // CursorEvent() now uses NextState().
  29. // Also, DrawBackgroundRes() now chooses the image indexed
  30. // by m_sState instead of m_sState + 1.
  31. //
  32. // 09/25/97 JMI ReadMembers() was not clearing states that had no
  33. // corresponding images which, since SetNumStates()
  34. // preserves existing state images, could result in old
  35. // images persisting through loads that contained no image
  36. // for that state.
  37. // Also, now, in file version 7, reads and writes the
  38. // current state.
  39. //
  40. //////////////////////////////////////////////////////////////////////////////
  41. //
  42. // This a GUI item that is based on RBtn.
  43. // This overrides CursorEvent() to get information about where a click in its
  44. // RHot occurred.
  45. // This overrides Compose() to add text.
  46. //
  47. // Enhancements/Uses:
  48. // To change the look of a button when pressed, you may want to override the
  49. // Compose() or DrawBorder() in a derived class.
  50. // To get a callback on a click/release pair in the button, set m_bcUser.
  51. //
  52. //////////////////////////////////////////////////////////////////////////////
  53. //////////////////////////////////////////////////////////////////////////////
  54. // Headers.
  55. //////////////////////////////////////////////////////////////////////////////
  56. #include "Blue.h"
  57. #ifdef PATHS_IN_INCLUDES
  58. #include "ORANGE/GUI/MultiBtn.h"
  59. #else
  60. #include "multibtn.h"
  61. #endif // PATHS_IN_INCLUDES
  62. //////////////////////////////////////////////////////////////////////////////
  63. // Module specific macros.
  64. //////////////////////////////////////////////////////////////////////////////
  65. // Sets val to def if val is -1.
  66. #define DEF(val, def) ((val == -1) ? def : val)
  67. //////////////////////////////////////////////////////////////////////////////
  68. // Module specific typedefs.
  69. //////////////////////////////////////////////////////////////////////////////
  70. //////////////////////////////////////////////////////////////////////////////
  71. // Module specific (static) variables.
  72. //////////////////////////////////////////////////////////////////////////////
  73. //////////////////////////////////////////////////////////////////////////////
  74. // Construction/Destruction.
  75. //////////////////////////////////////////////////////////////////////////////
  76. //////////////////////////////////////////////////////////////////////////////
  77. //
  78. // Default constructor.
  79. //
  80. //////////////////////////////////////////////////////////////////////////////
  81. RMultiBtn::RMultiBtn()
  82. {
  83. // Override RGuiItem's/RBtn's defaults.
  84. m_type = MultiBtn; // Indicates type of GUI item.
  85. // Initialize RMultiBtn members.
  86. m_sState = 0; // The button's current state, 0..m_sNumStates - 1.
  87. m_sNumStates = 0; // Number of button states.
  88. m_papimStates = NULL; // Ptr to array of m_sNumStates ptrs to button
  89. // state images.
  90. }
  91. //////////////////////////////////////////////////////////////////////////////
  92. //
  93. // Destructor.
  94. //
  95. //////////////////////////////////////////////////////////////////////////////
  96. RMultiBtn::~RMultiBtn()
  97. {
  98. DestroyStates();
  99. }
  100. ////////////////////////////////////////////////////////////////////////
  101. // Methods.
  102. ////////////////////////////////////////////////////////////////////////
  103. ////////////////////////////////////////////////////////////////////////
  104. //
  105. // Cursor event notification.
  106. // Events in event area.
  107. // (virtual).
  108. //
  109. ////////////////////////////////////////////////////////////////////////
  110. void RMultiBtn::CursorEvent( // Returns nothing.
  111. RInputEvent* pie) // In: Most recent user input event.
  112. // Out: pie->sUsed = TRUE, if used.
  113. {
  114. switch (pie->sEvent)
  115. {
  116. case RSP_MB0_DOUBLECLICK:
  117. case RSP_MB0_RELEASED:
  118. // If we were clicked in . . .
  119. if (m_sPressed != FALSE)
  120. {
  121. // Do change of state right away so user callback gets the new
  122. // value.
  123. // If within event area . . .
  124. if ( pie->sPosX >= m_sEventAreaX && pie->sPosX < m_sEventAreaX + m_sEventAreaW
  125. && pie->sPosY >= m_sEventAreaY && pie->sPosY < m_sEventAreaY + m_sEventAreaH)
  126. {
  127. // Change state.
  128. NextState();
  129. }
  130. }
  131. break;
  132. }
  133. // Call base.
  134. RGuiItem::CursorEvent(pie);
  135. switch (pie->sEvent)
  136. {
  137. case RSP_MB0_DOUBLECLICK:
  138. case RSP_MB0_PRESSED:
  139. // Always recompose on press, since there's so many possibilities
  140. // with this button.
  141. Compose();
  142. // Note that we used it.
  143. pie->sUsed = TRUE;
  144. break;
  145. case RSP_MB0_RELEASED:
  146. // Always recompose on release, since there's so many possibilities
  147. // with this button.
  148. Compose();
  149. // Note that we used it.
  150. pie->sUsed = TRUE;
  151. break;
  152. }
  153. }
  154. ////////////////////////////////////////////////////////////////////////
  155. // Draw background resource, if one is specified.
  156. // Utilizes base class version to place and BLiT the resource.
  157. // (virtual).
  158. ////////////////////////////////////////////////////////////////////////
  159. void RMultiBtn::DrawBackgroundRes( // Returns nothing.
  160. RImage* pim /*= NULL*/) // Dest image, uses m_im, if NULL.
  161. {
  162. // Store old bkd res.
  163. RImage* pimBkdRes = m_pimBkdRes;
  164. // If we have any states . . .
  165. if (m_papimStates != NULL)
  166. {
  167. // Choose proper image.
  168. if (m_sPressed == FALSE)
  169. {
  170. // If the state is available . . .
  171. if (m_sState <= m_sNumStates)
  172. {
  173. // Get the state.
  174. m_pimBkdRes = m_papimStates[m_sState];
  175. }
  176. }
  177. else
  178. {
  179. // Get the pressed feedback.
  180. m_pimBkdRes = m_papimStates[0];
  181. }
  182. }
  183. // Call base.
  184. RBtn::DrawBackgroundRes(pim);
  185. // Restore bkd res.
  186. m_pimBkdRes = pimBkdRes;
  187. }
  188. ////////////////////////////////////////////////////////////////////////
  189. // Set number of states.
  190. // This will clear all existing state images.
  191. ////////////////////////////////////////////////////////////////////////
  192. short RMultiBtn::SetNumStates( // Returns 0 on success.
  193. short sNumStates) // In: New number of states.
  194. {
  195. short sRes = 0; // Assume success.
  196. // Allocate an array of image ptrs and clear them all . . .
  197. RImage** papimNewStates = new RImage*[sNumStates + 1];
  198. if (papimNewStates != NULL)
  199. {
  200. // Clear all the ptrs to NULL.
  201. memset(papimNewStates, 0, sizeof(RImage*) * (sNumStates + 1));
  202. // If there was an old array . . .
  203. if (m_papimStates != NULL)
  204. {
  205. // Copy any currently valid ptrs within new range.
  206. short i;
  207. for (i = 0; i <= sNumStates && i <= m_sNumStates; i++)
  208. {
  209. // Copy entry.
  210. papimNewStates[i] = m_papimStates[i];
  211. // Clear entry so it is not deleted.
  212. m_papimStates[i] = NULL;
  213. }
  214. // Destroy any current states plus array.
  215. DestroyStates();
  216. }
  217. // Store the new number of states.
  218. m_sNumStates = sNumStates;
  219. // Store new arrray.
  220. m_papimStates = papimNewStates;
  221. }
  222. else
  223. {
  224. TRACE("SetNumStates(): Failed to allocate new array of Image ptrs.\n");
  225. sRes = -1;
  226. }
  227. return sRes;
  228. }
  229. ////////////////////////////////////////////////////////////////////////
  230. // Set button state or feedback state image.
  231. ////////////////////////////////////////////////////////////////////////
  232. short RMultiBtn::SetState( // Returns 0 on success.
  233. RImage* pim, // In: Image for state sState.
  234. short sState) // In: State to update (0 == feedback state,
  235. // 1..n == state number).
  236. {
  237. short sRes = 0; // Assume success.
  238. if (m_papimStates == NULL || sState >= m_sNumStates)
  239. {
  240. sRes = SetNumStates(sState);
  241. }
  242. // If successful so far . . .
  243. if (sRes == 0)
  244. {
  245. // Clear current value.
  246. delete m_papimStates[sState];
  247. // Allocate new one . . .
  248. m_papimStates[sState] = new RImage;
  249. if (m_papimStates[sState] != NULL)
  250. {
  251. // Copy specified image.
  252. *(m_papimStates[sState]) = *pim;
  253. }
  254. else
  255. {
  256. TRACE("SetState(): Failed to allocate new RImage.\n");
  257. sRes = -1;
  258. }
  259. }
  260. return sRes;
  261. }
  262. //////////////////////////////////////////////////////////////////////////////
  263. // Set button state or feedback state image.
  264. // The feedback state image is always the last image (m_sNumStates).
  265. //////////////////////////////////////////////////////////////////////////////
  266. short RMultiBtn::SetState( // Returns 0 on success.
  267. char* pszImageName, // In: File name of image for state sState.
  268. short sState) // In: State to update (0 == feedback state,
  269. // 1..n == state number).
  270. {
  271. short sRes = 0; // Assume success.
  272. RImage im;
  273. if (RFileEZLoad(&im, pszImageName, "rb", RFile::LittleEndian) == 0)
  274. {
  275. sRes = SetState(&im, sState);
  276. }
  277. else
  278. {
  279. TRACE("SetState(): RFileEZLoad() failed for \"%s\".\n", pszImageName);
  280. sRes = -1;
  281. }
  282. return sRes;
  283. }
  284. //////////////////////////////////////////////////////////////////////////////
  285. // Clear button state or feedback state image.
  286. // The feedback state image is always the first image.
  287. //////////////////////////////////////////////////////////////////////////////
  288. void RMultiBtn::ClearState( // Returns nothing.
  289. short sState) // In: State to clear (0 == feedback state,
  290. // 1..n == state number).
  291. {
  292. if (sState >= 0 && sState <= m_sNumStates)
  293. {
  294. if (m_papimStates != NULL)
  295. {
  296. // State be gone. Safe for already deallocated states as long as
  297. // they're NULL.
  298. delete m_papimStates[sState];
  299. m_papimStates[sState] = NULL;
  300. }
  301. }
  302. }
  303. //////////////////////////////////////////////////////////////////////////////
  304. // Go to the next logical state.
  305. //////////////////////////////////////////////////////////////////////////////
  306. short RMultiBtn::NextState(void) // Returns new state.
  307. {
  308. if (m_sNumStates > 0)
  309. {
  310. m_sState = (m_sState % m_sNumStates) + 1;
  311. }
  312. else
  313. {
  314. m_sState = 0;
  315. }
  316. return m_sState;
  317. }
  318. //////////////////////////////////////////////////////////////////////////////
  319. // Querries.
  320. //////////////////////////////////////////////////////////////////////////////
  321. //////////////////////////////////////////////////////////////////////////////
  322. // Get the current image for the specified state.
  323. //////////////////////////////////////////////////////////////////////////////
  324. RImage* RMultiBtn::GetState( // Returns image, if available; NULL, otherwise.
  325. short sState) // In: State to get (0 == feedback state,
  326. // 1..n == state number).
  327. {
  328. RImage* pimRes = NULL; // Assume not available.
  329. if (sState >= 0 && sState <= m_sNumStates)
  330. {
  331. if (m_papimStates != NULL)
  332. {
  333. pimRes = m_papimStates[sState];
  334. }
  335. }
  336. return pimRes;
  337. }
  338. //////////////////////////////////////////////////////////////////////////////
  339. // Internal functions.
  340. //////////////////////////////////////////////////////////////////////////////
  341. //////////////////////////////////////////////////////////////////////////////
  342. // Destroys current state bitmaps.
  343. //////////////////////////////////////////////////////////////////////////////
  344. void RMultiBtn::DestroyStates(void) // Returns nothing.
  345. {
  346. if (m_papimStates != NULL)
  347. {
  348. short i;
  349. for (i = 0; i <= m_sNumStates; i++)
  350. {
  351. delete m_papimStates[i];
  352. }
  353. delete []m_papimStates;
  354. m_sNumStates = 0;
  355. }
  356. }
  357. ////////////////////////////////////////////////////////////////////////
  358. // Read item's members from file.
  359. // (virtual/protected (overriden here)).
  360. ////////////////////////////////////////////////////////////////////////
  361. short RMultiBtn::ReadMembers( // Returns 0 on success.
  362. RFile* pfile, // File to read from.
  363. U32 u32Version) // File format version to use.
  364. {
  365. short sRes = 0; // Assume success.
  366. // Invoke base class to read base members.
  367. sRes = RBtn::ReadMembers(pfile, u32Version);
  368. // If okay so far . . .
  369. if (sRes == 0)
  370. {
  371. ASSERT(pfile != NULL);
  372. ASSERT(pfile->IsOpen() != FALSE);
  373. // Switch on version.
  374. switch (u32Version)
  375. {
  376. default:
  377. // Insert additional version numbers here!
  378. case 7:
  379. pfile->Read(&m_sState);
  380. case 6:
  381. case 5:
  382. case 4:
  383. case 3:
  384. case 2:
  385. case 1:
  386. {
  387. short sNumStates = 0; // Safety.
  388. // Read this class's members.
  389. pfile->Read(&sNumStates);
  390. // Set number of states.
  391. if (SetNumStates(sNumStates) == 0)
  392. {
  393. // Read all the images.
  394. short sCurState;
  395. short sImageForState;
  396. for (sCurState = 0; sCurState <= m_sNumStates && sRes == 0; sCurState++)
  397. {
  398. pfile->Read(&sImageForState);
  399. if (sImageForState != FALSE)
  400. {
  401. // There is an image. Load it.
  402. RImage imState;
  403. if (imState.Load(pfile) == 0)
  404. {
  405. // Set that state.
  406. if (SetState(&imState, sCurState) == 0)
  407. {
  408. // Successfully loaded and set state image.
  409. }
  410. else
  411. {
  412. TRACE("ReadMembers9): SetState() failed for state #%d.\n", sCurState);
  413. sRes = -3;
  414. }
  415. }
  416. else
  417. {
  418. TRACE("ReadMembers(): GetState() failed for state #%d.\n", sCurState);
  419. sRes = -2;
  420. }
  421. }
  422. else
  423. {
  424. // Make sure the state is clear.
  425. ClearState(sCurState);
  426. }
  427. }
  428. }
  429. else
  430. {
  431. TRACE("ReadMembers(): SetNumStates() failed.\n");
  432. sRes = -1;
  433. }
  434. }
  435. case 0: // In version 0, only base class RGuiItem members were stored.
  436. // If successful . . .
  437. if (pfile->Error() == FALSE)
  438. {
  439. // Success.
  440. }
  441. else
  442. {
  443. TRACE("ReadMembers(): Error reading RMultiBtn members.\n");
  444. sRes = -1;
  445. }
  446. break;
  447. }
  448. }
  449. return sRes;
  450. }
  451. ////////////////////////////////////////////////////////////////////////
  452. // Write item's members to file.
  453. // (virtual/protected (overriden here)).
  454. ////////////////////////////////////////////////////////////////////////
  455. short RMultiBtn::WriteMembers( // Returns 0 on success.
  456. RFile* pfile) // File to write to.
  457. {
  458. short sRes = 0; // Assume success.
  459. // Invoke base class to read base members.
  460. sRes = RBtn::WriteMembers(pfile);
  461. // If okay so far . . .
  462. if (sRes == 0)
  463. {
  464. ASSERT(pfile != NULL);
  465. ASSERT(pfile->IsOpen() != FALSE);
  466. // Write this class's members.
  467. pfile->Write(m_sState);
  468. pfile->Write(m_sNumStates);
  469. // Write all the images.
  470. short sCurState;
  471. for (sCurState = 0; sCurState <= m_sNumStates && sRes == 0; sCurState++)
  472. {
  473. // If there is a bitmap for this state . . .
  474. RImage* pimState = GetState(sCurState);
  475. if (pimState != NULL)
  476. {
  477. // There is an image. Write flag indicating such.
  478. pfile->Write((short)TRUE);
  479. // Write image.
  480. sRes = pimState->Save(pfile);
  481. }
  482. else
  483. {
  484. // No image. Write flag indicating such.
  485. pfile->Write((short)FALSE);
  486. }
  487. }
  488. // If successful . . .
  489. if (pfile->Error() == FALSE)
  490. {
  491. // Success.
  492. }
  493. else
  494. {
  495. TRACE("WriteMembers(): Error writing RMultiBtn members.\n");
  496. sRes = -1;
  497. }
  498. }
  499. return sRes;
  500. }
  501. //////////////////////////////////////////////////////////////////////////////
  502. // EOF
  503. //////////////////////////////////////////////////////////////////////////////