PageRenderTime 340ms CodeModel.GetById 91ms app.highlight 169ms RepoModel.GetById 73ms app.codeStats 0ms

/Scenes/UserInterfaces/Controls/Button.cs

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