popup.cpp 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416
  1. #include "pch.h"
  2. /////////////////////////////////////////////////////////////////////////////
  3. //
  4. // IPopup
  5. //
  6. /////////////////////////////////////////////////////////////////////////////
  7. void IPopup::SetContainer(IPopupContainer* pcontainer)
  8. {
  9. m_pcontainer = pcontainer;
  10. }
  11. void IPopup::SetOwner(IPopup* ppopupOwner)
  12. {
  13. m_ppopupOwner = ppopupOwner;
  14. }
  15. void IPopup::OnClose()
  16. {
  17. }
  18. void IPopup::ClosePopup(IPopup* ppopup)
  19. {
  20. m_pcontainer->ClosePopup(ppopup);
  21. }
  22. TRef<Image> IPopup::GetImage(Engine* pengine)
  23. {
  24. return CreatePaneImage(pengine, SurfaceType3D(), true, GetPane());
  25. }
  26. Rect IPopup::GetRect()
  27. {
  28. TRef<Pane> ppane = GetPane();
  29. ppane->UpdateLayout();
  30. return Rect(Point(0, 0), Point::Cast(ppane->GetSize()));
  31. }
  32. //////////////////////////////////////////////////////////////////////////////
  33. //
  34. // PanePopup
  35. //
  36. //////////////////////////////////////////////////////////////////////////////
  37. class PanePopup : public IPopup {
  38. private:
  39. TRef<Pane> m_ppane;
  40. public:
  41. PanePopup(Pane* ppane) :
  42. m_ppane(ppane)
  43. {
  44. }
  45. //
  46. // IPopup methods
  47. //
  48. Pane* GetPane()
  49. {
  50. return m_ppane;
  51. }
  52. };
  53. TRef<IPopup> CreatePanePopup(Pane* ppane)
  54. {
  55. return new PanePopup(ppane);
  56. }
  57. /////////////////////////////////////////////////////////////////////////////
  58. //
  59. // IPopupContainerImpl
  60. //
  61. /////////////////////////////////////////////////////////////////////////////
  62. class PopupContainerImpl :
  63. public IPopupContainerPrivate,
  64. public WrapImage
  65. {
  66. private:
  67. /////////////////////////////////////////////////////////////////////////////
  68. //
  69. // Types
  70. //
  71. /////////////////////////////////////////////////////////////////////////////
  72. class PickImage : public Image {
  73. private:
  74. PopupContainerImpl* m_pppic;
  75. public:
  76. PickImage(PopupContainerImpl* pppic) :
  77. m_pppic(pppic)
  78. {
  79. }
  80. MouseResult HitTest(IInputProvider* pprovider, const Point& point, bool bCaptured)
  81. {
  82. return m_pppic->HitTest();
  83. }
  84. MouseResult Button(
  85. IInputProvider* pprovider,
  86. const Point& point,
  87. int button,
  88. bool bCaptured,
  89. bool bInside,
  90. bool bDown
  91. ) {
  92. if (bDown) {
  93. m_pppic->Picked();
  94. }
  95. return MouseResult();
  96. }
  97. ZString GetFunctionName() { return "ImagePopupContainer"; }
  98. };
  99. class PopupData : public IObject {
  100. public:
  101. TRef<PopupData> m_pdataNext;
  102. TRef<IPopup> m_ppopup;
  103. TRef<Image> m_pimage;
  104. TRef<Image> m_ppickImage;
  105. bool m_bCloseAll;
  106. };
  107. /////////////////////////////////////////////////////////////////////////////
  108. //
  109. // Members
  110. //
  111. /////////////////////////////////////////////////////////////////////////////
  112. TRef<PopupData> m_pdata;
  113. TRef<Engine> m_pengine;
  114. TRef<GroupImage> m_pgroup;
  115. TRef<RectValue> m_prectValue;
  116. bool m_bCascadeRight;
  117. /////////////////////////////////////////////////////////////////////////////
  118. //
  119. // Methods
  120. //
  121. /////////////////////////////////////////////////////////////////////////////
  122. public:
  123. PopupContainerImpl() :
  124. WrapImage(Image::GetEmpty()),
  125. m_bCascadeRight(true)
  126. {
  127. m_pgroup = new GroupImage();
  128. SetImage(m_pgroup);
  129. }
  130. MouseResult HitTest()
  131. {
  132. return (m_pdata != NULL) ? MouseResultHit() : MouseResult();
  133. }
  134. void Picked()
  135. {
  136. //
  137. // Picked outside close all the popups
  138. //
  139. while (m_pdata && m_pdata->m_bCloseAll) {
  140. ClosePopup(m_pdata->m_ppopup);
  141. }
  142. EngineWindow::DoHitTest();
  143. }
  144. /////////////////////////////////////////////////////////////////////////////
  145. //
  146. // IPopupContainerPrivate methods
  147. //
  148. /////////////////////////////////////////////////////////////////////////////
  149. void Initialize(
  150. Engine* pengine,
  151. RectValue* prectValue
  152. ) {
  153. m_pengine = pengine;
  154. m_prectValue = prectValue;
  155. }
  156. /////////////////////////////////////////////////////////////////////////////
  157. //
  158. // IPopupContainer
  159. //
  160. /////////////////////////////////////////////////////////////////////////////
  161. void OpenPopup(IPopup* ppopup, const Point& point, bool bCloseAll, IPopup* ppopupOwner)
  162. {
  163. OpenPopup(ppopup, new PointValue(point), bCloseAll, ppopupOwner);
  164. }
  165. void OpenPopup(IPopup* ppopup, PointValue* ppoint, bool bCloseAll, IPopup* ppopupOwner)
  166. {
  167. //
  168. // Open the popup
  169. //
  170. TRef<PopupData> pdata = new PopupData();
  171. pdata->m_ppopup = ppopup;
  172. pdata->m_bCloseAll = bCloseAll;
  173. pdata->m_pimage =
  174. new TransformImage(
  175. ppopup->GetImage(m_pengine),
  176. new TranslateTransform2(
  177. ppoint
  178. )
  179. );
  180. pdata->m_pdataNext = m_pdata;
  181. m_pdata = pdata;
  182. if (ppopupOwner == NULL) {
  183. pdata->m_ppickImage = new PickImage(this);
  184. m_pgroup->AddImageToTop(pdata->m_ppickImage);
  185. }
  186. m_pgroup->AddImageToTop(pdata->m_pimage);
  187. ppopup->SetContainer(this);
  188. if (ppopupOwner != NULL) {
  189. ppopup->SetOwner(ppopupOwner);
  190. }
  191. EngineWindow::DoHitTest();
  192. }
  193. void OpenPopup(IPopup* ppopup, const Rect& rect, bool bCloseAll, bool bCascadeDown, IPopup* ppopupOwner)
  194. {
  195. //
  196. // Figure out where the popup should go
  197. //
  198. Rect rectPopup = ppopup->GetRect();
  199. Rect rectContainer = m_prectValue->GetValue();
  200. Point point;
  201. //
  202. // x position
  203. //
  204. if (m_bCascadeRight) {
  205. if (rect.XMax() + rectPopup.XSize() > rectContainer.XMax()) {
  206. point.SetX(rect.XMin() - rectPopup.XSize());
  207. } else {
  208. point.SetX(rect.XMax());
  209. }
  210. } else {
  211. if (rect.XMin() - rectPopup.XSize() < 0) {
  212. point.SetX(rect.XMax());
  213. } else {
  214. point.SetX(rect.XMin() - rectPopup.XSize());
  215. }
  216. }
  217. //
  218. // Make sure we actually stay on the screen
  219. //
  220. if (point.X() + rectPopup.XSize() > rectContainer.XMax()) {
  221. point.SetX(rectContainer.XMax() - rectPopup.XSize());
  222. }
  223. if (point.X() < 0) {
  224. point.SetX(0);
  225. }
  226. //
  227. // Check if going up or down would go off the screen
  228. //
  229. if (bCascadeDown) {
  230. if (rect.YMax() - rectPopup.YSize() < 0) {
  231. bCascadeDown = false;
  232. }
  233. } else {
  234. if (rect.YMin() + rectPopup.YSize() > rectContainer.YMax()) {
  235. bCascadeDown = true;
  236. }
  237. }
  238. //
  239. // y position
  240. //
  241. if (bCascadeDown) {
  242. if (rect.YMax() - rectPopup.YSize() < 0) {
  243. point.SetY(0);
  244. } else {
  245. point.SetY(rect.YMax() - rectPopup.YSize());
  246. }
  247. } else {
  248. if (rect.YMin() + rectPopup.YSize() > rectContainer.YMax()) {
  249. point.SetY(rectContainer.YMax() - rectPopup.YSize());
  250. } else {
  251. point.SetY(rect.YMin());
  252. }
  253. }
  254. //
  255. // Open the popup
  256. //
  257. OpenPopup(ppopup, point, bCloseAll, ppopupOwner);
  258. }
  259. class CenterRectPoint : public PointValue {
  260. private:
  261. const Rect& GetContainerRect() { return RectValue::Cast(GetChild(0))->GetValue(); }
  262. const Rect& GetRect() { return RectValue::Cast(GetChild(1))->GetValue(); }
  263. public:
  264. CenterRectPoint(RectValue* prectContainer, RectValue* prect) :
  265. PointValue(prectContainer, prect)
  266. {
  267. }
  268. void Evaluate()
  269. {
  270. GetValueInternal() = (GetContainerRect().Size() - GetRect().Size()) / 2;
  271. }
  272. };
  273. void OpenPopup(IPopup* ppopup, bool bCloseAll, IPopup* ppopupOwner)
  274. {
  275. OpenPopup(
  276. ppopup,
  277. new CenterRectPoint(m_prectValue, new RectValue(ppopup->GetRect())),
  278. bCloseAll,
  279. ppopupOwner
  280. );
  281. }
  282. void ClosePopup(IPopup* ppopup)
  283. {
  284. while (m_pdata) {
  285. m_pgroup->RemoveImage(m_pdata->m_pimage);
  286. m_pgroup->RemoveImage(m_pdata->m_ppickImage);
  287. m_pdata->m_ppopup->OnClose();
  288. if (m_pdata->m_ppopup == ppopup) {
  289. m_pdata = m_pdata->m_pdataNext;
  290. break;
  291. }
  292. m_pdata = m_pdata->m_pdataNext;
  293. }
  294. //
  295. // If this is the first popup start cascading to the right
  296. //
  297. if (m_pdata == NULL) {
  298. m_bCascadeRight = true;
  299. }
  300. EngineWindow::DoHitTest();
  301. }
  302. bool IsEmpty()
  303. {
  304. return (m_pdata == NULL);
  305. }
  306. Image* GetImage()
  307. {
  308. return this;
  309. }
  310. /////////////////////////////////////////////////////////////////////////////
  311. //
  312. // IKeyboardInput
  313. //
  314. /////////////////////////////////////////////////////////////////////////////
  315. bool OnChar(IInputProvider* pprovider, const KeyState& ks)
  316. {
  317. if (m_pdata != NULL) {
  318. m_pdata->m_ppopup->OnChar(pprovider, ks);
  319. return true;
  320. }
  321. return false;
  322. }
  323. bool OnKey(IInputProvider* pprovider, const KeyState& ks, bool& fForceTranslate)
  324. {
  325. if (m_pdata != NULL) {
  326. m_pdata->m_ppopup->OnKey(pprovider, ks, fForceTranslate);
  327. //
  328. // The popup container eats all of the keyboard
  329. // messages if a popup is up.
  330. //
  331. return true;
  332. }
  333. return false;
  334. }
  335. };
  336. TRef<IPopupContainerPrivate> CreatePopupContainer()
  337. {
  338. return new PopupContainerImpl();
  339. }