ProcessGui.cpp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546
  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. // ProcessGui.CPP
  21. //
  22. // History:
  23. // 07/03/97 JMI Started.
  24. //
  25. // 07/03/97 JMI Had not implemented the update func to the feature level
  26. // the comments implied. Implemented.
  27. //
  28. // 07/03/97 JMI Added Init() and Kill(). Init() is called by the con-
  29. // structor. Kill() is called by the destructor. The de-
  30. // structor used to call Unprepare() but the problem with
  31. // that was that Unprepare() did more than just deallocate
  32. // the dynamic stuff and that stuff shouldn't have been done
  33. // upon destruction. So now Unprepare() and the destructor
  34. // call Kill() to take care of dynamic items.
  35. //
  36. // 08/22/97 JMI Now uses rspGeneralLock/Unlock() to ensure the composite
  37. // buffer is locked as necessary.
  38. //
  39. // 09/01/97 JMI Now only sets the focus to the first item if there's no
  40. // focus or the current focus is not a descendant of the
  41. // root item.
  42. // Also, added special behavior flags, m_flags.
  43. //
  44. // 09/06/97 JMI Now filters out the high word of ie.lKey when checking
  45. // for enter. This filters out the the key flags (i.e.,
  46. // shift, control, alt, system).
  47. //
  48. //////////////////////////////////////////////////////////////////////////////
  49. //
  50. // See .h for details.
  51. //
  52. //////////////////////////////////////////////////////////////////////////////
  53. //////////////////////////////////////////////////////////////////////////////
  54. // C Headers -- Must be included before RSPiX.h b/c RSPiX utilizes SHMalloc.
  55. //////////////////////////////////////////////////////////////////////////////
  56. ///////////////////////////////////////////////////////////////////////////////
  57. // RSPiX Headers.
  58. // If PATHS_IN_INCLUDES macro is defined, we can utilize relative
  59. // paths to a header file. In this case we generally go off of our
  60. // RSPiX root directory. System.h MUST be included before this macro
  61. // is evaluated. System.h is the header that, based on the current
  62. // platform (or more so in this case on the compiler), defines
  63. // PATHS_IN_INCLUDES. Blue.h includes system.h so you can include that
  64. // instead.
  65. ///////////////////////////////////////////////////////////////////////////////
  66. #include "System.h"
  67. #ifdef PATHS_IN_INCLUDES
  68. #include "ORANGE/GUI/ProcessGui.h"
  69. #else
  70. #include "ProcessGui.h"
  71. #endif
  72. //////////////////////////////////////////////////////////////////////////////
  73. // Module specific macros.
  74. //////////////////////////////////////////////////////////////////////////////
  75. //////////////////////////////////////////////////////////////////////////////
  76. // Module specific typedefs.
  77. //////////////////////////////////////////////////////////////////////////////
  78. //////////////////////////////////////////////////////////////////////////////
  79. // Exported (extern) variables.
  80. //////////////////////////////////////////////////////////////////////////////
  81. //////////////////////////////////////////////////////////////////////////////
  82. // Module specific (static) variables / Instantiate class statics.
  83. //////////////////////////////////////////////////////////////////////////////
  84. //////////////////////////////////////////////////////////////////////////////
  85. // Module specific (static) protos.
  86. //////////////////////////////////////////////////////////////////////////////
  87. // ID of last item pressed.
  88. long RProcessGui::ms_lPressedId;
  89. //////////////////////////////////////////////////////////////////////////////
  90. // Helper Functions.
  91. //////////////////////////////////////////////////////////////////////////////
  92. //////////////////////////////////////////////////////////////////////////////
  93. // Draw dirty areas if not going direct to screen and
  94. // remove rects from pdrl.
  95. //////////////////////////////////////////////////////////////////////////////
  96. inline
  97. void DrawDirty( // Returns nothing.
  98. RImage* pimDst, // In: Destination buffer.
  99. RImage* pimScr, // In: Screen buffer.
  100. RDirtyRects* pdrl) // In: Dirty rect list of areas to be updated.
  101. {
  102. RDRect* pdr;
  103. // If not going direct to screen . . .
  104. if (pimDst != pimScr)
  105. {
  106. rspShieldMouseCursor();
  107. pdr = pdrl->GetHead();
  108. while (pdr != NULL)
  109. {
  110. // Update screen.
  111. rspBlit( pimDst, pimScr,
  112. pdr->sX, pdr->sY,
  113. pdr->sX, pdr->sY,
  114. pdr->sW, pdr->sH);
  115. pdrl->Remove();
  116. delete pdr;
  117. pdr = pdrl->GetNext();
  118. }
  119. rspUnshieldMouseCursor();
  120. }
  121. }
  122. //////////////////////////////////////////////////////////////////////////////
  123. // Functions.
  124. //////////////////////////////////////////////////////////////////////////////
  125. //////////////////////////////////////////////////////////////////////////////
  126. // Prepare to handle a GUI.
  127. // This must be called to setup components before Do*Gui() is called.
  128. //////////////////////////////////////////////////////////////////////////////
  129. short RProcessGui::Prepare( // Returns 0 on success.
  130. RGuiItem* pguiRoot, // In: GUI to be processed.
  131. RGuiItem* pguiOk/* = NULL*/, // In: If not NULL, specifies GUI
  132. // activated by ENTER key.
  133. RGuiItem* pguiCancel/* = NULL*/) // In: If not NULL, specifies GUI
  134. // activated by ESCAPE key.
  135. {
  136. short sRes = 0; // Assume success.
  137. // Create erase buffer . . .
  138. if (m_imEraser.CreateImage(
  139. pguiRoot->m_im.m_sWidth,
  140. pguiRoot->m_im.m_sHeight,
  141. RImage::BMP8,
  142. 0, // Use default for this width/format/depth.
  143. pguiRoot->m_im.m_sDepth) == 0)
  144. {
  145. // Success.
  146. }
  147. else
  148. {
  149. TRACE("Prepare(): CreateImage() failed.\n");
  150. sRes = -1;
  151. }
  152. m_pguiOk = pguiOk;
  153. m_pguiCancel = pguiCancel;
  154. // These need to call us back.
  155. if (pguiOk)
  156. {
  157. SetGuiToNotify(pguiOk);
  158. }
  159. if (pguiCancel)
  160. {
  161. SetGuiToNotify(pguiCancel);
  162. }
  163. // Make visible and activate.
  164. pguiRoot->SetVisible(TRUE);
  165. if (RGuiItem::ms_pguiFocus)
  166. {
  167. // If the root is not an ancestor of the current focus . . .
  168. if (RGuiItem::ms_pguiFocus->IsAncestor(pguiRoot) == FALSE)
  169. {
  170. // Clear focus.
  171. RGuiItem::SetFocus(NULL);
  172. }
  173. }
  174. // If no current focus . . .
  175. if (RGuiItem::ms_pguiFocus == NULL)
  176. {
  177. // Set focus to first child control or none if there's none.
  178. pguiRoot->SetFocus(pguiRoot->m_listguiChildren.GetHead());
  179. }
  180. return sRes;
  181. }
  182. //////////////////////////////////////////////////////////////////////////////
  183. // This should be called to clean up components when no more Do*Gui()
  184. // calls are to be made on the current GUI.
  185. //////////////////////////////////////////////////////////////////////////////
  186. void RProcessGui::Unprepare(void) // Returns nothing.
  187. {
  188. // If we're allowed . . .
  189. if ( (m_sFlags & NoCleanScreen) == 0)
  190. {
  191. RImage* pimScr;
  192. rspNameBuffers(NULL, &pimScr);
  193. // Draw remaining dirty areas.
  194. DrawDirty(m_pimLastDst, pimScr, &m_drl);
  195. }
  196. // Deallocate dynamic schtuff.
  197. Kill();
  198. }
  199. //////////////////////////////////////////////////////////////////////////////
  200. // Setup GUI to notify this class of presses.
  201. //////////////////////////////////////////////////////////////////////////////
  202. void RProcessGui::SetGuiToNotify( // Returns nothing.
  203. RGuiItem* pgui) // GUI item to setup to notify this class
  204. // of presses.
  205. {
  206. pgui->m_bcUser = PressedCall;
  207. }
  208. //////////////////////////////////////////////////////////////////////////////
  209. // Set all unclaimed GUIs' callbacks to go through this class.
  210. //////////////////////////////////////////////////////////////////////////////
  211. void RProcessGui::SetGuisToNotify( // Returns nothing.
  212. RGuiItem* pguiRoot) // In: All unclaimed child GUIs'
  213. // callbacks are directed through
  214. // ProcessGui.
  215. {
  216. // Enum GUIs directing unclaimed callbacks to PressedCall.
  217. RGuiItem* pguiChild = pguiRoot->m_listguiChildren.GetHead();
  218. while (pguiChild != NULL)
  219. {
  220. // If callback unclaimed . . .
  221. if (pguiChild->m_bcUser == NULL)
  222. {
  223. SetGuiToNotify(pguiChild);
  224. }
  225. // Do this item's children.
  226. SetGuisToNotify(pguiChild);
  227. pguiChild = pguiRoot->m_listguiChildren.GetNext();
  228. }
  229. }
  230. //////////////////////////////////////////////////////////////////////////////
  231. // Call this to process a GUI modally. Once this function is called,
  232. // it will not return until a GUI pressed callback occurs on a GUI
  233. // with an ID other than 0 or the update callback, m_fnUpdate, if any,
  234. // returns non-zero.
  235. //////////////////////////////////////////////////////////////////////////////
  236. long RProcessGui::DoModal( // Returns ID of pressed GUI that terminated
  237. // modal loop or value returned from
  238. // m_fnUpdate, if any.
  239. RGuiItem* pgui, // In: GUI to be processed or NULL.
  240. RGuiItem* pguiOk/* = NULL*/, // In: If not NULL, specifies GUI
  241. // activated by ENTER key.
  242. RGuiItem* pguiCancel/* = NULL*/, // In: If not NULL, specifies GUI
  243. // activated by ESCAPE key.
  244. RImage* pimDst /*= NULL*/) // Where to draw dialog and rspBlit from.
  245. // If this is NULL, the system buffer is
  246. // used.
  247. // rspBlit is used to update this to the
  248. // screen image unless pimDst is the screen
  249. // image.
  250. {
  251. long lId = 0;
  252. // Set up ptrs and erase buffer.
  253. Prepare(pgui, pguiOk, pguiCancel);
  254. RInputEvent ie;
  255. // Process GUI.
  256. while (rspGetQuitStatus() == FALSE && lId == 0)
  257. {
  258. ie.type = RInputEvent::None;
  259. // If there's a user update func . . .
  260. if (m_fnUpdate)
  261. {
  262. lId = m_fnUpdate(&ie);
  263. }
  264. else
  265. {
  266. // Minimum system callage.
  267. rspDoSystem();
  268. rspGetNextInputEvent(&ie);
  269. }
  270. if (lId == 0)
  271. {
  272. lId = DoModeless(pgui, &ie, pimDst);
  273. }
  274. }
  275. // Clean up ptrs, erase buffer, and dirty rect list.
  276. Unprepare();
  277. // Return GUI pressage that terminated.
  278. return lId;
  279. }
  280. //////////////////////////////////////////////////////////////////////////////
  281. // Call this to process a GUI modelessly. This function processes the
  282. // GUI for only one iteration allowing the caller continuous control.
  283. //////////////////////////////////////////////////////////////////////////////
  284. long RProcessGui::DoModeless( // Returns ID of pressed GUI or value.
  285. RGuiItem* pgui, // In: GUI to be processed or NULL.
  286. RInputEvent* pie, // In: Input event to process.
  287. RImage* pimDst /*= NULL*/) // Where to draw dialog and rspBlit from.
  288. // If this is NULL, the system buffer is
  289. // used.
  290. // rspBlit is used to update this to the
  291. // screen image unless pimDst is the screen
  292. // image.
  293. {
  294. RImage* pimScr;
  295. // We update these things every frame in case the video mode has changed.
  296. if (pimDst == NULL)
  297. {
  298. // Get both buffers.
  299. rspNameBuffers(&pimDst, &pimScr);
  300. }
  301. else
  302. {
  303. // Just need screen buffer.
  304. rspNameBuffers(NULL, &pimScr);
  305. }
  306. // Update dirty rect clipping in case video mode changed.
  307. m_drl.m_sClipX = pimDst->m_sWidth - 1;
  308. m_drl.m_sClipY = pimDst->m_sHeight - 1;
  309. // Clear callback ID.
  310. ms_lPressedId = 0;
  311. // Update hots with input event.
  312. // If the event is used by RHot, the sUsed flag will be
  313. // set to TRUE.
  314. // RHot calls GUIs with mouse events, if applicable.
  315. pgui->m_hot.Do(pie);
  316. // Update GUIs.
  317. // This GUI item call sends the event, if not yet used,
  318. // to the GUI focused, and checks for keys that might
  319. // change the focus.
  320. pgui->DoFocus(pie);
  321. // If unused key event . . .
  322. if (pie->sUsed == FALSE && pie->type == RInputEvent::Key)
  323. {
  324. // Check some of our own keys.
  325. switch (pie->lKey & 0x0000FFFF)
  326. {
  327. // Enter == Ok.
  328. case '\r':
  329. RSP_SAFE_GUI_REF_VOID(m_pguiOk, SetClicked(TRUE) );
  330. PressedCall(m_pguiOk);
  331. // Used key.
  332. pie->sUsed = TRUE;
  333. break;
  334. // Escape == Cancel.
  335. case 27:
  336. RSP_SAFE_GUI_REF_VOID(m_pguiCancel, SetClicked(TRUE) );
  337. PressedCall(m_pguiCancel);
  338. // Used key.
  339. pie->sUsed = TRUE;
  340. break;
  341. }
  342. }
  343. // Lock buffer down for access.
  344. rspGeneralLock(pimDst);
  345. // Store area of composite buffer that is to be dirtied.
  346. RRect rect(0, 0, pimDst->m_sWidth, pimDst->m_sHeight);
  347. rspBlit(
  348. pimDst, // Source.
  349. &m_imEraser, // Destination.
  350. pgui->m_sX, // Source.
  351. pgui->m_sY, // Source.
  352. 0, // Destination.
  353. 0, // Destination.
  354. m_imEraser.m_sWidth, // Both.
  355. m_imEraser.m_sHeight, // Both.
  356. NULL, // Destination.
  357. &rect ); // Source.
  358. // If direct to screen . . .
  359. if (pimDst == pimScr)
  360. {
  361. // Shield cursor.
  362. rspShieldMouseCursor();
  363. }
  364. // Draw the GUI tree.
  365. pgui->Draw(pimDst);
  366. // Add rectangle where GUI drew.
  367. m_drl.Add(
  368. pgui->m_sX,
  369. pgui->m_sY,
  370. pgui->m_im.m_sWidth,
  371. pgui->m_im.m_sHeight);
  372. // If not going direct to screen . . .
  373. if (pimDst != pimScr)
  374. {
  375. // We must unlock the buffer so DrawDirty()
  376. // can do an rspUpdateDisplay().
  377. rspGeneralUnlock(pimDst);
  378. }
  379. // Update areas of RSPiX display.
  380. DrawDirty(pimDst, pimScr, &m_drl);
  381. // If not going direct to screen . . .
  382. if (pimDst != pimScr)
  383. {
  384. // Since we unlocked before DrawDirty(),
  385. // we must relock now so we can continue accessing
  386. // the buffer.
  387. rspGeneralLock(pimDst);
  388. }
  389. // Undirty buffer of GUIs.
  390. rspBlit(
  391. &m_imEraser, // Source.
  392. pimDst, // Destination.
  393. 0, // Source.
  394. 0, // Source.
  395. pgui->m_sX, // Destination.
  396. pgui->m_sY, // Destination.
  397. m_imEraser.m_sWidth, // Both.
  398. m_imEraser.m_sHeight, // Both.
  399. NULL, // Destination.
  400. NULL); // Source.
  401. // Done with buffer.
  402. rspGeneralUnlock(pimDst);
  403. // If direct to screen . . .
  404. if (pimDst == pimScr)
  405. {
  406. // Unshield.
  407. rspUnshieldMouseCursor();
  408. }
  409. else // If not direct to screen . . .
  410. {
  411. // Add rectangle that got erased to be update next iteration
  412. // or in Unprepare().
  413. m_drl.Add(
  414. pgui->m_sX,
  415. pgui->m_sY,
  416. pgui->m_im.m_sWidth,
  417. pgui->m_im.m_sHeight);
  418. }
  419. // Remember last dst.
  420. m_pimLastDst = pimDst;
  421. // Check GUI pressage.
  422. return ms_lPressedId;
  423. }
  424. ///////////////////////////////////////////////////////////////////////////
  425. // Querries.
  426. ///////////////////////////////////////////////////////////////////////////
  427. ///////////////////////////////////////////////////////////////////////////
  428. // Internal functions.
  429. ///////////////////////////////////////////////////////////////////////////
  430. ///////////////////////////////////////////////////////////////////////////
  431. // Initialize instantiable data members.
  432. // (protected).
  433. ///////////////////////////////////////////////////////////////////////////
  434. void RProcessGui::Init(void) // Returns nothing.
  435. {
  436. m_pguiOk = NULL;
  437. m_pguiCancel = NULL;
  438. m_fnUpdate = NULL;
  439. m_pimLastDst = NULL;
  440. m_sFlags = 0;
  441. }
  442. ///////////////////////////////////////////////////////////////////////////
  443. // Deallocate any instantiable dynamic members.
  444. // (protected).
  445. ///////////////////////////////////////////////////////////////////////////
  446. void RProcessGui::Kill(void) // Returns nothing.
  447. {
  448. // Destroy image data.
  449. m_imEraser.DestroyData();
  450. // There should be no palette associated with this image.
  451. // Empty dirty rect list.
  452. m_drl.Empty();
  453. // Reset (don't call Init() it does more).
  454. m_pguiOk = NULL;
  455. m_pguiCancel = NULL;
  456. m_pimLastDst = NULL;
  457. }
  458. ///////////////////////////////////////////////////////////////////////////
  459. // Internal static functions.
  460. ///////////////////////////////////////////////////////////////////////////
  461. //////////////////////////////////////////////////////////////////////////////
  462. // Callback for pressed GUIs.
  463. //////////////////////////////////////////////////////////////////////////////
  464. // static.
  465. void RProcessGui::PressedCall( // Returns nothing.
  466. RGuiItem* pgui) // In: Pressed GUI.
  467. {
  468. if (pgui)
  469. {
  470. ms_lPressedId = pgui->m_lId;
  471. }
  472. }
  473. ///////////////////////////////////////////////////////////////////////////////
  474. // EOF
  475. ///////////////////////////////////////////////////////////////////////////////