PageRenderTime 48ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 0ms

/Scenes/UserInterfaces/Controls/Button.cs

#
C# | 507 lines | 262 code | 56 blank | 189 comment | 22 complexity | d73fa62f1883cea99e996262773ca6e0 MD5 | raw file
Possible License(s): Apache-2.0
  1. using Delta.Engine;
  2. using Delta.Engine.SettingsNodes;
  3. using Delta.InputSystem;
  4. using Delta.Scenes.Enums;
  5. using Delta.Utilities;
  6. using Delta.Utilities.Datatypes;
  7. using NUnit.Framework;
  8. using Delta.Multimedia;
  9. namespace Delta.Scenes.UserInterfaces.Controls
  10. {
  11. /// <summary>
  12. /// A button control which supports additionally to the normal control states
  13. /// the 'Pressed' state and also a 'Clicked' event.
  14. /// </summary>
  15. public class Button : Label
  16. {
  17. #region Constants
  18. /// <summary>
  19. /// The name of the control class which is saved in the content data to
  20. /// describe and "detect" the data in the loading code again.
  21. /// </summary>
  22. private const string SavingClassName = "UIButtonControl";
  23. /// <summary>
  24. /// The current version of the implementation of this control class.
  25. /// </summary>
  26. private const int WorkingVersion = 1;
  27. #endregion
  28. #region Delegates
  29. /// <summary>
  30. /// The delegate declaration for any input event that will forwarded to an
  31. /// UI control.
  32. /// </summary>
  33. /// <param name="sender">Sender</param>
  34. /// <param name="input">The data of that event</param>
  35. public delegate void ControlInputEvent(BaseControl sender,
  36. CommandTrigger input);
  37. #endregion
  38. #region Protected
  39. #region FallbackDesign (Protected)
  40. /// <summary>
  41. /// Defines the theme which will be used if no "Theme" was set explicitely.
  42. /// </summary>
  43. protected override ControlDesign FallbackDesign
  44. {
  45. get
  46. {
  47. return Theme.Current.ButtonDesign;
  48. }
  49. }
  50. #endregion
  51. #endregion
  52. #region Clicked (Event)
  53. /// <summary>
  54. /// Occurs if the left pointing device button was pressed.
  55. /// </summary>
  56. public event ControlInputEvent Clicked;
  57. #endregion
  58. #region ClickedSound
  59. /// <summary>
  60. /// The sound which will be played if this button is clicked (Optional).
  61. /// </summary>
  62. public Sound ClickedSound
  63. {
  64. get;
  65. set;
  66. }
  67. #endregion
  68. #region Methods (Private)
  69. #region OnInputEvent
  70. /// <summary>
  71. /// On input event
  72. /// </summary>
  73. /// <param name="input">Input</param>
  74. protected override void OnInputEvent(CommandTrigger input)
  75. {
  76. // If the event was already handled we don't need to do anything
  77. if (input.IsHandled)
  78. {
  79. return;
  80. }
  81. switch (input.CommandName)
  82. {
  83. case Command.UIClickBegin:
  84. //IsInPressedState = true;
  85. State = ElementState.Pressed;
  86. input.IsHandled = true;
  87. //return base.OnInputEvent(inputEvent);
  88. return;
  89. case Command.UIClick:
  90. //Log.Test("UI event '" + command.EventName + "' happened.");
  91. // The button click will only be handled if the click was initiated
  92. // (even by a drag) on this control
  93. if (State != ElementState.Pressed)
  94. {
  95. return;
  96. } // if
  97. // At first give the control the chance to react on that event (for
  98. // internal logic which wasn't thought for any subscribers)
  99. OnClicked(input, IsInControl(input.Position));
  100. // if the input event wasn't needed for its own logic
  101. if (Clicked != null &&
  102. input.IsHandled == false)
  103. {
  104. // then inform all subscribers (if there are ones)
  105. Clicked(this, input);
  106. }
  107. // Finally close the current clicked begin state
  108. //IsInPressedState = false;
  109. // Michael: Added an invisible check so the button
  110. // will correctly be hidden when the state is changed
  111. // during "Clicked" events
  112. if (State != ElementState.Invisible)
  113. {
  114. State =
  115. IsInControl(input.Position)
  116. ? ElementState.Hovered
  117. : ElementState.Enabled;
  118. }
  119. //return inputEvent.IsHandled;
  120. if (Clicked == null &&
  121. input.IsHandled == false)
  122. {
  123. Log.Warning(
  124. "There is no code which handles the '" +input.CommandName +
  125. "' event for button '"+Name+"', which seems to be strange.");
  126. }
  127. return;
  128. default:
  129. // Unknown input event for the UI control
  130. base.OnInputEvent(input);
  131. return;
  132. } // switch
  133. }
  134. #endregion
  135. // OnInputEvent(command)
  136. #region OnClicked
  137. /// <summary>
  138. /// On clicked
  139. /// </summary>
  140. /// <param name="input">Input data like the click position.</param>
  141. /// <param name="isInsideControl">
  142. /// 'True' if the event is occurring inside the control, otherwise 'false'.
  143. /// </param>
  144. protected virtual void OnClicked(CommandTrigger input,
  145. bool isInsideControl)
  146. {
  147. // For a button we only "count" a click if it starts AND ends inside of
  148. // the control, otherwise we just ignore the event
  149. // Note: All other required management stuff of the control like
  150. // restoring the correct state will be still done
  151. if (isInsideControl == false)
  152. {
  153. input.IsHandled = true;
  154. return;
  155. } // if
  156. if (ClickedSound != null)
  157. {
  158. ClickedSound.Play();
  159. } // if
  160. }
  161. #endregion
  162. #endregion
  163. /// <summary>
  164. /// Tests for Button controls
  165. /// </summary>
  166. [Category("Visual")]
  167. internal class ButtonTests
  168. {
  169. #region DisplayButton (Static)
  170. /// <summary>
  171. /// Display button
  172. /// </summary>
  173. [Test]
  174. public static void DisplayButton()
  175. {
  176. int clickCount = 0;
  177. Button button = new Button
  178. {
  179. //LocalArea = new Rectangle(0.25f, 0.25f, 0.5f, 0.15f),
  180. LocalArea = new Rectangle(0.5f, 0.5f, 0.5f, 0.15f),
  181. //Rotation = 45,
  182. //Alignment = AlignmentType.Middle,
  183. Text = "Click me",
  184. };
  185. button.Clicked += delegate(BaseControl sender, CommandTrigger input)
  186. {
  187. button.Text = (++clickCount) + "x clicked";
  188. Log.Test(button.Text);
  189. input.IsHandled = true;
  190. };
  191. // Finally we still have to add the button to a scene that should
  192. // manage the button
  193. Screen testScene = new Screen();
  194. testScene.Add(button);
  195. //Base.UI.ShowDebugInfo = true;
  196. // Open now the scene to "activate" for the test
  197. testScene.Open();
  198. Settings.Debug.SetDrawDebugInfoMode(ProfilingMode.UI, false); // true);
  199. Application.Start();
  200. }
  201. #endregion
  202. #region DisabledButton (Static)
  203. /// <summary>
  204. /// Disabled button
  205. /// </summary>
  206. [Test]
  207. public static void DisabledButton()
  208. {
  209. int clickCount = 0;
  210. Button button = new Button
  211. {
  212. LocalArea = new Rectangle(0.25f, 0.25f, 0.5f, 0.15f),
  213. Text = "Enabled",
  214. //AllowEventsWhenDisabled = true,
  215. };
  216. button.Clicked += delegate(BaseControl control, CommandTrigger input)
  217. {
  218. button.Text = (++clickCount) + "x clicked";
  219. input.IsHandled = true;
  220. };
  221. // Finally we still have to add the button to a screen that should
  222. // manage the button
  223. Screen testScene = new Screen();
  224. testScene.Add(button);
  225. // Open now the scene to "activate" for the test
  226. testScene.Open();
  227. Application.Start(delegate
  228. {
  229. // Start the visual test to see the button
  230. // Disable/enable the button by pressing the keyboard "Space" button
  231. if (Input.Keyboard.SpaceReleased)
  232. {
  233. if (button.State >= ElementState.Enabled)
  234. {
  235. button.State = ElementState.Disabled;
  236. }
  237. else
  238. {
  239. button.State = button.IsInControl(Input.Mouse.Position)
  240. ? ElementState.Hovered
  241. : ElementState.Enabled;
  242. } // else
  243. button.Text = button.State.ToString();
  244. clickCount = 0;
  245. }
  246. });
  247. }
  248. #endregion
  249. #region DestroyButton (Static)
  250. /// <summary>
  251. /// Destroy button
  252. /// </summary>
  253. [Test]
  254. public static void DestroyButton()
  255. {
  256. bool isButtonDestroyed = false;
  257. Button testButton = new Button
  258. {
  259. LocalArea = new Rectangle(0.25f, 0.25f, 0.5f, 0.15f),
  260. };
  261. testButton.Clicked += delegate
  262. {
  263. if (isButtonDestroyed)
  264. {
  265. Log.Test("Hmm...the button should be actually destroyed.");
  266. }
  267. else
  268. {
  269. testButton.Dispose();
  270. isButtonDestroyed = true;
  271. } // else
  272. };
  273. // Finally we still have to add the button to a scene that should
  274. // manage the button
  275. Screen testScene = new Screen();
  276. testScene.Add(testButton);
  277. // Open now the scene to "activate" for the test
  278. testScene.Open();
  279. Application.Start();
  280. }
  281. #endregion
  282. #region CursorMoveTest (Static)
  283. /// <summary>
  284. /// Cursor move test
  285. /// </summary>
  286. [Test]
  287. public static void CursorMoveTest()
  288. {
  289. // Button testButton = new Button
  290. // {
  291. // //ControlArea = new Rectangle(0.4f, 0.4f, 0.2f, 0.2f));
  292. // //ControlArea = new Rectangle(0.4f, 0.4f, 0.4f, 0.4f));
  293. // //ControlArea = new Rectangle(0.0f, 0.0f, 0.5f, 0.5f));
  294. // LocalArea = new Rectangle(0.25f, 0.25f, 0.5f, 0.15f),
  295. // //Rotation = 45,
  296. // Alignment = AlignmentType.Middle,
  297. // //PressedDesign = null,
  298. // };
  299. // testButton.CursorMove += delegate
  300. // {
  301. // Log.Test(Time.Milliseconds + ": CursorMoving on button");
  302. // }; // CursorMoveTest()
  303. // UIScene testScene = new UIScene();
  304. // testScene.Add(testButton);
  305. // // Open now the scene to "activate" for the test
  306. // testScene.Open();
  307. // Application.Start();
  308. }
  309. #endregion
  310. #region UsingChilds (Static)
  311. /// <summary>
  312. /// Using childs
  313. /// </summary>
  314. [Test]
  315. public static void UsingChilds()
  316. {
  317. Settings.Debug.SetDrawDebugInfoMode(ProfilingMode.UI, true);
  318. // The used UI scene for the unit test
  319. Screen testScene = new Screen();
  320. // The "parent" button which contains the "child1" and "child2" buttons
  321. Button parent = new Button
  322. {
  323. Text = "Parent",
  324. LocalArea = new Rectangle(0.3f, 0.5f, 0.4f, 0.1f),
  325. };
  326. //parent.Rotation = 45;
  327. // Child 1 of the "parent" button
  328. Button child1 = new Button
  329. {
  330. Text = "Child 1",
  331. LocalArea = new Rectangle(-0.25f, 0.1f, 0.4f, 0.1f),
  332. };
  333. parent.Add(child1);
  334. // Child 2 of the "parent" button
  335. Button child2 = new Button
  336. {
  337. Text = "Child 2",
  338. LocalArea = new Rectangle(0.25f, 0.1f, 0.4f, 0.1f),
  339. };
  340. parent.Add(child2);
  341. // Finally we still have to add the button to a screen that should
  342. // manage the button
  343. testScene.Add(parent);
  344. // The label control which shows us the current focued control
  345. Label focusLabel = new Label
  346. {
  347. LocalArea = new Rectangle(0.5f, 0.2f, 0.3f, 0.05f),
  348. //Alignment = AlignmentType.Top,
  349. };
  350. // and the "debug" label
  351. testScene.Add(focusLabel);
  352. // Finally we "register" the dragging event for all buttons
  353. //parent.Dragging += DragButton;
  354. //child1.Dragging += DragButton;
  355. //child2.Dragging += DragButton;
  356. // Open now the scene to "activate" for the test
  357. testScene.Open();
  358. // before we finally start the graphical test...
  359. Application.Start(delegate
  360. {
  361. //// Cycling through all alignment modes of the "parent" button by
  362. //// pressing the "Space" key
  363. //if (Input.Keyboard.SpaceReleased)
  364. //{
  365. // parent.Alignment = EnumHelper.NextValue(parent.Alignment);
  366. // parent.Text = "Alignment=" + parent.Alignment;
  367. //}
  368. // For easier checking we just display the current focused on the
  369. // label
  370. Button button = testScene.FocusedControl as Button;
  371. if (testScene.FocusedControl != null)
  372. {
  373. string focusesText = (button != null)
  374. ? button.Text
  375. : testScene.FocusedControl.GetType().Name;
  376. focusLabel.Text = "Focused=" + focusesText;
  377. } // if
  378. else
  379. {
  380. focusLabel.Text = "Nothing Focused";
  381. }
  382. // Start the visual test to see the button
  383. });
  384. }
  385. #endregion
  386. #region Rotation (Static)
  387. /// <summary>
  388. /// Rotation
  389. /// </summary>
  390. [Test]
  391. public static void Rotation()
  392. {
  393. // Button testButton = new Button
  394. // {
  395. // LocalArea = new Rectangle(0.05f, 0.15f, 0.3f, 0.1f),
  396. // //Alignment = AlignmentType.Middle,
  397. // };
  398. // UIScene testScene = new UIScene();
  399. // testScene.Add(testButton);
  400. // // Open now the scene to "activate" for the test
  401. // testScene.Open();
  402. // Application.Start(delegate
  403. // {
  404. // testButton.Rotation += 20.0f * Time.Delta;
  405. // // Start the visual test to see the button
  406. // });
  407. }
  408. #endregion
  409. #region DepthLayers (Static)
  410. /// <summary>
  411. /// Depth layers
  412. /// </summary>
  413. [Test]
  414. public static void DepthLayers()
  415. {
  416. // // The used UI scene for the unit test
  417. // UIScene uiScene = Base.GameScreen.OverlayScreen.UIScene;
  418. // Button buttonDepth6 = new Button
  419. // {
  420. // LocalArea = new Rectangle(0.25f, 0.25f, 0.4f, 0.2f),
  421. // DepthLayer = 6,
  422. // };
  423. // buttonDepth6.Text = "DepthLayer=" + buttonDepth6.DepthLayer;
  424. // buttonDepth6.BlendColor = Color.Green;
  425. // uiScene.Add(buttonDepth6);
  426. // Button buttonDepth10 = new Button
  427. // {
  428. // LocalArea = new Rectangle(0.45f, 0.3f, 0.4f, 0.2f),
  429. // DepthLayer = 10,
  430. // };
  431. // buttonDepth10.Text = "DepthLayer=" + buttonDepth10.DepthLayer;
  432. // buttonDepth10.BlendColor = Color.Blue;
  433. // uiScene.Add(buttonDepth10);
  434. // Button buttonDefaultLayer = new Button
  435. // {
  436. // LocalArea = new Rectangle(0.35f, 0.4f, 0.4f, 0.2f),
  437. // };
  438. // buttonDefaultLayer.Text = "DefaultLayer (DepthLayer=" +
  439. // buttonDefaultLayer.DepthLayer + ")";
  440. // buttonDefaultLayer.BlendColor = Color.Grey;
  441. // uiScene.Add(buttonDefaultLayer);
  442. // Base.UI.ShowDebugInfo = true;
  443. // Base.StartTest("Display Button", delegate
  444. // {
  445. // // Start the visuial test to see the button
  446. // });
  447. }
  448. #endregion
  449. }
  450. }
  451. }