ListScreen.cs 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647
  1. //-----------------------------------------------------------------------------
  2. // ListScreen.cs
  3. //
  4. // Microsoft XNA Community Game Platform
  5. // Copyright (C) Microsoft Corporation. All rights reserved.
  6. //-----------------------------------------------------------------------------
  7. using System;
  8. using System.Collections.Generic;
  9. using Microsoft.Xna.Framework;
  10. using Microsoft.Xna.Framework.Graphics;
  11. using Microsoft.Xna.Framework.Content;
  12. using RolePlaying.Data;
  13. using System.Collections.ObjectModel;
  14. using System.IO;
  15. namespace RolePlaying
  16. {
  17. abstract class ListScreen<T> : GameScreen
  18. {
  19. protected readonly Vector2 iconOffset = new Vector2(0f, 0f);
  20. protected readonly Vector2 descriptionTextPosition = new Vector2(200, 550);
  21. private readonly Vector2 listPositionTopPosition = new Vector2(1160, 354);
  22. private readonly Vector2 listPositionBottomPosition = new Vector2(1160, 384);
  23. private Texture2D backgroundTexture;
  24. private readonly Rectangle backgroundDestination =
  25. new Rectangle(0, 0, Session.BACK_BUFFER_WIDTH, Session.BACK_BUFFER_HEIGHT);
  26. private Texture2D fadeTexture;
  27. private Texture2D listTexture;
  28. private readonly Vector2 listTexturePosition = new Vector2(187f, 180f);
  29. protected readonly Vector2 listEntryStartPosition = new Vector2(200f, 195f);
  30. protected const int listLineSpacing = 76;
  31. private Texture2D plankTexture;
  32. private Vector2 plankTexturePosition;
  33. protected string titleText = String.Empty;
  34. protected Texture2D goldTexture;
  35. private readonly Vector2 goldTexturePosition = new Vector2(490f, 640f);
  36. protected string goldText = String.Empty;
  37. private readonly Vector2 goldTextPosition = new Vector2(565f, 648f);
  38. private Texture2D highlightTexture;
  39. private readonly Vector2 highlightStartPosition = new Vector2(170f, 237f);
  40. private Texture2D selectionArrowTexture;
  41. private readonly Vector2 selectionArrowPosition = new Vector2(135f, 245f);
  42. private Texture2D leftTriggerTexture;
  43. private readonly Vector2 leftTriggerTexturePosition = new Vector2(340f, 50f);
  44. protected string leftTriggerText = String.Empty;
  45. private Texture2D rightTriggerTexture;
  46. private readonly Vector2 rightTriggerTexturePosition = new Vector2(900f, 50f);
  47. protected string rightTriggerText = String.Empty;
  48. private Texture2D leftQuantityArrowTexture;
  49. private Texture2D rightQuantityArrowTexture;
  50. private Texture2D backButtonTexture;
  51. private readonly Vector2 backButtonTexturePosition = new Vector2(80f, 640f);
  52. protected string backButtonText = String.Empty;
  53. private Vector2 backButtonTextPosition = new Vector2(90f, 645f); // + tex width
  54. private Texture2D selectButtonTexture;
  55. private readonly Vector2 selectButtonTexturePosition = new Vector2(1150f, 640f);
  56. protected string selectButtonText = String.Empty;
  57. private Texture2D xButtonTexture;
  58. private readonly Vector2 xButtonTexturePosition = new Vector2(240f, 640f);
  59. protected string xButtonText = String.Empty;
  60. private Vector2 xButtonTextPosition = new Vector2(250f, 645f); // + tex width
  61. private Texture2D yButtonTexture;
  62. private readonly Vector2 yButtonTexturePosition = new Vector2(890f, 640f);
  63. protected string yButtonText = String.Empty;
  64. /// <summary>
  65. /// Get the list that this screen displays.
  66. /// </summary>
  67. /// <returns></returns>
  68. public abstract ReadOnlyCollection<T> GetDataList();
  69. /// <summary>
  70. /// The index of the selected entry.
  71. /// </summary>
  72. private int selectedIndex = 0;
  73. /// <summary>
  74. /// The index of the selected entry.
  75. /// </summary>
  76. public int SelectedIndex
  77. {
  78. get { return selectedIndex; }
  79. set
  80. {
  81. if (selectedIndex != value)
  82. {
  83. selectedIndex = value;
  84. EnsureVisible(selectedIndex);
  85. }
  86. }
  87. }
  88. /// <summary>
  89. /// Ensure that the given index is visible on the screen.
  90. /// </summary>
  91. public void EnsureVisible(int index)
  92. {
  93. if (index < startIndex)
  94. {
  95. // if it's above the current selection, set the first entry
  96. startIndex = index;
  97. }
  98. if (selectedIndex > (endIndex - 1))
  99. {
  100. startIndex += selectedIndex - (endIndex - 1);
  101. }
  102. // otherwise, it should be in the current selection already
  103. // -- note that the start and end indices are checked in Draw.
  104. }
  105. /// <summary>
  106. /// Move the current selection up one entry.
  107. /// </summary>
  108. protected virtual void MoveCursorUp()
  109. {
  110. if (SelectedIndex > 0)
  111. {
  112. SelectedIndex--;
  113. }
  114. }
  115. /// <summary>
  116. /// Move the current selection down one entry.
  117. /// </summary>
  118. protected virtual void MoveCursorDown()
  119. {
  120. SelectedIndex++; // safety-checked in Draw()
  121. }
  122. /// <summary>
  123. /// Decrease the selected quantity by one.
  124. /// </summary>
  125. protected virtual void MoveCursorLeft() { }
  126. /// <summary>
  127. /// Increase the selected quantity by one.
  128. /// </summary>
  129. protected virtual void MoveCursorRight() { }
  130. /// <summary>
  131. /// The first index displayed on the screen from the list.
  132. /// </summary>
  133. private int startIndex = 0;
  134. /// <summary>
  135. /// The first index displayed on the screen from the list.
  136. /// </summary>
  137. public int StartIndex
  138. {
  139. get { return startIndex; }
  140. set { startIndex = value; } // safety-checked in Draw
  141. }
  142. /// <summary>
  143. /// The last index displayed on the screen from the list.
  144. /// </summary>
  145. private int endIndex = 0;
  146. /// <summary>
  147. /// The last index displayed on the screen from the list.
  148. /// </summary>
  149. public int EndIndex
  150. {
  151. get { return endIndex; }
  152. set { endIndex = value; } // safety-checked in Draw
  153. }
  154. /// <summary>
  155. /// The maximum number of list entries that the screen can show at once.
  156. /// </summary>
  157. public const int MaximumListEntries = 4;
  158. /// <summary>
  159. /// Constructs a new ListScreen object.
  160. /// </summary>
  161. public ListScreen()
  162. : base()
  163. {
  164. this.IsPopup = true;
  165. }
  166. /// <summary>
  167. /// Load the graphics content from the content manager.
  168. /// </summary>
  169. public override void LoadContent()
  170. {
  171. ContentManager content = ScreenManager.Game.Content;
  172. // load the background textures
  173. fadeTexture = content.Load<Texture2D>(Path.Combine("Textures", "GameScreens", "FadeScreen"));
  174. backgroundTexture =
  175. content.Load<Texture2D>(Path.Combine("Textures", "GameScreens", "GameScreenBkgd"));
  176. listTexture =
  177. content.Load<Texture2D>(Path.Combine("Textures", "GameScreens", "InfoDisplay"));
  178. plankTexture =
  179. content.Load<Texture2D>(Path.Combine("Textures", "MainMenu", "MainMenuPlank03"));
  180. goldTexture =
  181. content.Load<Texture2D>(Path.Combine("Textures", "GameScreens", "GoldIcon"));
  182. // load the foreground textures
  183. highlightTexture =
  184. content.Load<Texture2D>(Path.Combine("Textures", "GameScreens", "HighlightLarge"));
  185. selectionArrowTexture =
  186. content.Load<Texture2D>(Path.Combine("Textures", "GameScreens", "SelectionArrow"));
  187. // load the trigger images
  188. leftTriggerTexture =
  189. content.Load<Texture2D>(Path.Combine("Textures", "Buttons", "LeftTriggerButton"));
  190. rightTriggerTexture =
  191. content.Load<Texture2D>(Path.Combine("Textures", "Buttons", "RightTriggerButton"));
  192. leftQuantityArrowTexture =
  193. content.Load<Texture2D>(Path.Combine("Textures", "Buttons", "QuantityArrowLeft"));
  194. rightQuantityArrowTexture =
  195. content.Load<Texture2D>(Path.Combine("Textures", "Buttons", "QuantityArrowRight"));
  196. backButtonTexture =
  197. content.Load<Texture2D>(Path.Combine("Textures", "Buttons", "BButton"));
  198. selectButtonTexture =
  199. content.Load<Texture2D>(Path.Combine("Textures", "Buttons", "AButton"));
  200. xButtonTexture =
  201. content.Load<Texture2D>(Path.Combine("Textures", "Buttons", "XButton"));
  202. yButtonTexture =
  203. content.Load<Texture2D>(Path.Combine("Textures", "Buttons", "YButton"));
  204. // calculate the centered positions
  205. plankTexturePosition = new Vector2((Session.BACK_BUFFER_WIDTH - plankTexture.Width) / 2f, 67f);
  206. // adjust positions for texture sizes
  207. if (backButtonTexture != null)
  208. {
  209. backButtonTextPosition.X += backButtonTexture.Width;
  210. }
  211. if (xButtonTexture != null)
  212. {
  213. xButtonTextPosition.X += xButtonTexture.Width;
  214. }
  215. base.LoadContent();
  216. }
  217. /// <summary>
  218. /// Handle user input.
  219. /// </summary>
  220. public override void HandleInput()
  221. {
  222. if (InputManager.IsActionTriggered(InputManager.InputAction.PageLeft))
  223. {
  224. PageScreenLeft();
  225. }
  226. else if (InputManager.IsActionTriggered(InputManager.InputAction.PageRight))
  227. {
  228. PageScreenRight();
  229. }
  230. else if (InputManager.IsActionTriggered(InputManager.InputAction.CursorUp))
  231. {
  232. MoveCursorUp();
  233. }
  234. else if (InputManager.IsActionTriggered(InputManager.InputAction.CursorDown))
  235. {
  236. MoveCursorDown();
  237. }
  238. else if (InputManager.IsActionTriggered(InputManager.InputAction.IncreaseAmount))
  239. {
  240. MoveCursorRight();
  241. }
  242. else if (InputManager.IsActionTriggered(InputManager.InputAction.DecreaseAmount))
  243. {
  244. MoveCursorLeft();
  245. }
  246. else if (InputManager.IsActionTriggered(InputManager.InputAction.Back))
  247. {
  248. BackTriggered();
  249. }
  250. else if (InputManager.IsActionTriggered(InputManager.InputAction.Ok))
  251. {
  252. ReadOnlyCollection<T> dataList = GetDataList();
  253. if ((selectedIndex >= 0) && (selectedIndex < dataList.Count))
  254. {
  255. SelectTriggered(dataList[selectedIndex]);
  256. }
  257. }
  258. else if (InputManager.IsActionTriggered(InputManager.InputAction.DropUnEquip))
  259. {
  260. ReadOnlyCollection<T> dataList = GetDataList();
  261. if ((selectedIndex >= 0) && (selectedIndex < dataList.Count))
  262. {
  263. ButtonXPressed(dataList[selectedIndex]);
  264. }
  265. }
  266. else if (InputManager.IsActionTriggered(InputManager.InputAction.TakeView))
  267. {
  268. ReadOnlyCollection<T> dataList = GetDataList();
  269. if ((selectedIndex >= 0) && (selectedIndex < dataList.Count))
  270. {
  271. ButtonYPressed(dataList[selectedIndex]);
  272. }
  273. }
  274. base.HandleInput();
  275. }
  276. /// <summary>
  277. /// Switch to the screen to the "left" of this one in the UI, if any.
  278. /// </summary>
  279. protected virtual void PageScreenLeft() { }
  280. /// <summary>
  281. /// Switch to the screen to the "right" of this one in the UI, if any.
  282. /// </summary>
  283. protected virtual void PageScreenRight() { }
  284. /// <summary>
  285. /// Respond to the triggering of the Back action.
  286. /// </summary>
  287. protected virtual void BackTriggered()
  288. {
  289. ExitScreen();
  290. }
  291. /// <summary>
  292. /// Respond to the triggering of the Select action.
  293. /// </summary>
  294. protected virtual void SelectTriggered(T entry) { }
  295. /// <summary>
  296. /// Respond to the triggering of the X button (and related key).
  297. /// </summary>
  298. protected virtual void ButtonXPressed(T entry) { }
  299. /// <summary>
  300. /// Respond to the triggering of the Y button (and related key).
  301. /// </summary>
  302. protected virtual void ButtonYPressed(T entry) { }
  303. /// <summary>
  304. /// Draws the screen.
  305. /// </summary>
  306. public override void Draw(Microsoft.Xna.Framework.GameTime gameTime)
  307. {
  308. SpriteBatch spriteBatch = ScreenManager.SpriteBatch;
  309. // get the content list
  310. ReadOnlyCollection<T> dataList = GetDataList();
  311. // turn off the buttons if the list is empty
  312. if (dataList.Count <= 0)
  313. {
  314. selectButtonText = String.Empty;
  315. xButtonText = String.Empty;
  316. yButtonText = String.Empty;
  317. }
  318. // fix the indices for the current list size
  319. SelectedIndex = (int)MathHelper.Clamp(SelectedIndex, 0, dataList.Count - 1);
  320. startIndex = (int)MathHelper.Clamp(startIndex, 0,
  321. dataList.Count - MaximumListEntries);
  322. endIndex = Math.Min(startIndex + MaximumListEntries, dataList.Count);
  323. spriteBatch.Begin(SpriteSortMode.Deferred, null, null, null, null, null, ScreenManager.GlobalTransformation);
  324. DrawBackground();
  325. if (dataList.Count > 0)
  326. {
  327. DrawListPosition(SelectedIndex + 1, dataList.Count);
  328. }
  329. DrawButtons();
  330. DrawPartyGold();
  331. DrawColumnHeaders();
  332. DrawTitle();
  333. // draw each item currently shown
  334. Vector2 position = listEntryStartPosition +
  335. new Vector2(0f, listLineSpacing / 2);
  336. if (startIndex >= 0)
  337. {
  338. for (int index = startIndex; index < endIndex; index++)
  339. {
  340. T entry = dataList[index];
  341. if (index == selectedIndex)
  342. {
  343. DrawSelection(position);
  344. DrawEntry(entry, position, true);
  345. DrawSelectedDescription(entry);
  346. }
  347. else
  348. {
  349. DrawEntry(entry, position, false);
  350. }
  351. position.Y += listLineSpacing;
  352. }
  353. }
  354. spriteBatch.End();
  355. }
  356. /// <summary>
  357. /// Draw the entry at the given position in the list.
  358. /// </summary>
  359. /// <param name="entry">The entry to draw.</param>
  360. /// <param name="position">The position to draw the entry at.</param>
  361. /// <param name="isSelected">If true, this entry is selected.</param>
  362. protected abstract void DrawEntry(T entry, Vector2 position, bool isSelected);
  363. /// <summary>
  364. /// Draw the selection graphics over the selected item.
  365. /// </summary>
  366. /// <param name="position"></param>
  367. protected virtual void DrawSelection(Vector2 position)
  368. {
  369. SpriteBatch spriteBatch = ScreenManager.SpriteBatch;
  370. spriteBatch.Draw(highlightTexture,
  371. new Vector2(highlightStartPosition.X, position.Y), Color.White);
  372. spriteBatch.Draw(selectionArrowTexture,
  373. new Vector2(selectionArrowPosition.X, position.Y + 10f), Color.White);
  374. }
  375. /// <summary>
  376. /// Draw the background of the screen.
  377. /// </summary>
  378. protected virtual void DrawBackground()
  379. {
  380. SpriteBatch spriteBatch = ScreenManager.SpriteBatch;
  381. spriteBatch.Draw(fadeTexture, backgroundDestination, Color.White);
  382. spriteBatch.Draw(backgroundTexture, backgroundDestination, Color.White);
  383. spriteBatch.Draw(listTexture, listTexturePosition, Color.White);
  384. }
  385. /// <summary>
  386. /// Draw the current list position in the appropriate location on the screen.
  387. /// </summary>
  388. /// <param name="position">The current position in the list.</param>
  389. /// <param name="total">The total elements in the list.</param>
  390. protected virtual void DrawListPosition(int position, int total)
  391. {
  392. SpriteBatch spriteBatch = ScreenManager.SpriteBatch;
  393. // draw the top number - the current position in the list
  394. string listPositionTopText = position.ToString();
  395. Vector2 drawPosition = listPositionTopPosition;
  396. drawPosition.X -= (float)Math.Ceiling(
  397. Fonts.GearInfoFont.MeasureString(listPositionTopText).X / 2);
  398. spriteBatch.DrawString(Fonts.GearInfoFont, listPositionTopText,
  399. drawPosition, Fonts.CountColor);
  400. // draw the bottom number - the current position in the list
  401. string listPositionBottomText = total.ToString();
  402. drawPosition = listPositionBottomPosition;
  403. drawPosition.X -= (float)Math.Ceiling(
  404. Fonts.GearInfoFont.MeasureString(listPositionBottomText).X / 2);
  405. spriteBatch.DrawString(Fonts.GearInfoFont, listPositionBottomText,
  406. drawPosition, Fonts.CountColor);
  407. }
  408. /// <summary>
  409. /// Draw the party gold text.
  410. /// </summary>
  411. protected virtual void DrawPartyGold()
  412. {
  413. if (!IsActive)
  414. {
  415. return;
  416. }
  417. SpriteBatch spriteBatch = ScreenManager.SpriteBatch;
  418. spriteBatch.Draw(goldTexture, goldTexturePosition, Color.White);
  419. spriteBatch.DrawString(Fonts.ButtonNamesFont,
  420. Fonts.GetGoldString(Session.Party.PartyGold), goldTextPosition,
  421. Color.White);
  422. }
  423. /// <summary>
  424. /// Draw the description of the selected item.
  425. /// </summary>
  426. protected abstract void DrawSelectedDescription(T entry);
  427. /// <summary>
  428. /// Draw the column headers above the list.
  429. /// </summary>
  430. protected abstract void DrawColumnHeaders();
  431. /// <summary>
  432. /// Draw all of the buttons used by the screen.
  433. /// </summary>
  434. protected virtual void DrawButtons()
  435. {
  436. if (!IsActive)
  437. {
  438. return;
  439. }
  440. SpriteBatch spriteBatch = ScreenManager.SpriteBatch;
  441. // draw the left trigger texture and text
  442. if ((leftTriggerTexture != null) && !String.IsNullOrEmpty(leftTriggerText))
  443. {
  444. Vector2 position = leftTriggerTexturePosition + new Vector2(
  445. leftTriggerTexture.Width / 2f - (float)Math.Ceiling(
  446. Fonts.PlayerStatisticsFont.MeasureString(leftTriggerText).X / 2f),
  447. 90f);
  448. spriteBatch.Draw(leftTriggerTexture, leftTriggerTexturePosition,
  449. Color.White);
  450. spriteBatch.DrawString(Fonts.PlayerStatisticsFont, leftTriggerText,
  451. position, Color.Black);
  452. }
  453. // draw the right trigger texture and text
  454. if ((rightTriggerTexture != null) && !String.IsNullOrEmpty(rightTriggerText))
  455. {
  456. Vector2 position = rightTriggerTexturePosition + new Vector2(
  457. rightTriggerTexture.Width / 2f - (float)Math.Ceiling(
  458. Fonts.PlayerStatisticsFont.MeasureString(rightTriggerText).X / 2f),
  459. 90f);
  460. spriteBatch.Draw(rightTriggerTexture, rightTriggerTexturePosition,
  461. Color.White);
  462. spriteBatch.DrawString(Fonts.PlayerStatisticsFont, rightTriggerText,
  463. position, Color.Black);
  464. }
  465. // draw the left trigger texture and text
  466. if ((backButtonTexture != null) && !String.IsNullOrEmpty(backButtonText))
  467. {
  468. spriteBatch.Draw(backButtonTexture, backButtonTexturePosition,
  469. Color.White);
  470. spriteBatch.DrawString(Fonts.ButtonNamesFont, backButtonText,
  471. backButtonTextPosition, Color.White);
  472. }
  473. // draw the left trigger texture and text
  474. if ((selectButtonTexture != null) && !String.IsNullOrEmpty(selectButtonText))
  475. {
  476. spriteBatch.Draw(selectButtonTexture, selectButtonTexturePosition,
  477. Color.White);
  478. Vector2 position = selectButtonTexturePosition - new Vector2(
  479. Fonts.ButtonNamesFont.MeasureString(selectButtonText).X, 0f) +
  480. new Vector2(0f, 5f);
  481. spriteBatch.DrawString(Fonts.ButtonNamesFont, selectButtonText,
  482. position, Color.White);
  483. }
  484. // draw the left trigger texture and text
  485. if ((xButtonTexture != null) && !String.IsNullOrEmpty(xButtonText))
  486. {
  487. spriteBatch.Draw(xButtonTexture, xButtonTexturePosition,
  488. Color.White);
  489. spriteBatch.DrawString(Fonts.ButtonNamesFont, xButtonText,
  490. xButtonTextPosition, Color.White);
  491. }
  492. // draw the left trigger texture and text
  493. if ((yButtonTexture != null) && !String.IsNullOrEmpty(yButtonText))
  494. {
  495. spriteBatch.Draw(yButtonTexture, yButtonTexturePosition,
  496. Color.White);
  497. Vector2 position = yButtonTexturePosition - new Vector2(
  498. Fonts.ButtonNamesFont.MeasureString(yButtonText).X, 0f) +
  499. new Vector2(0f, 5f);
  500. spriteBatch.DrawString(Fonts.ButtonNamesFont, yButtonText,
  501. position, Color.White);
  502. }
  503. }
  504. /// <summary>
  505. /// Draw the title of the screen, if any.
  506. /// </summary>
  507. protected virtual void DrawTitle()
  508. {
  509. SpriteBatch spriteBatch = ScreenManager.SpriteBatch;
  510. // draw the left trigger texture and text
  511. if ((plankTexture != null) && !String.IsNullOrEmpty(titleText))
  512. {
  513. Vector2 titleTextSize = Fonts.HeaderFont.MeasureString(titleText);
  514. Vector2 position = new Vector2(
  515. (float)Math.Floor(Session.BACK_BUFFER_WIDTH / 2 -
  516. titleTextSize.X / 2f), 95f);
  517. spriteBatch.Draw(plankTexture, plankTexturePosition, Color.White);
  518. spriteBatch.DrawString(Fonts.HeaderFont, titleText, position, Fonts.TitleColor, MathHelper.ToRadians(-3.0f), Vector2.Zero, 1.0f, SpriteEffects.None, 0f);
  519. }
  520. }
  521. }
  522. }