Client LuaCsForBarotrauma
GUINumberInput.cs
1 using Microsoft.Xna.Framework;
2 using System;
3 using System.Globalization;
4 using System.Linq;
5 
6 namespace Barotrauma
7 {
9  {
10  public delegate void OnValueEnteredHandler(GUINumberInput numberInput);
12 
13  public delegate void OnValueChangedHandler(GUINumberInput numberInput);
15 
16  public GUITextBox TextBox { get; private set; }
17 
18  public override RichString ToolTip
19  {
20  get
21  {
22  return base.ToolTip;
23  }
24  set
25  {
26  base.ToolTip = value;
27  TextBox.ToolTip = value;
28  }
29  }
30 
31  public GUIButton PlusButton { get; private set; }
32  public GUIButton MinusButton { get; private set; }
33 
34  public enum ButtonVisibility { Automatic, Manual, ForceVisible, ForceHidden }
35  private ButtonVisibility _plusMinusButtonVisibility;
42  {
43  get { return _plusMinusButtonVisibility; }
44  set
45  {
46  if (_plusMinusButtonVisibility != value)
47  {
48  _plusMinusButtonVisibility = value;
49  UpdatePlusMinusButtonVisibility();
50  }
51  }
52  }
53 
54  private void UpdatePlusMinusButtonVisibility()
55  {
57  {
58  case ButtonVisibility.ForceHidden:
59  {
60  HidePlusMinusButtons();
61  break;
62  }
63  case ButtonVisibility.ForceVisible:
64  {
65  ShowPlusMinusButtons();
66  break;
67  }
68  case ButtonVisibility.Automatic:
69  {
70  if (inputType == NumberType.Int
71  || (inputType == NumberType.Float
72  && MinValueFloat > float.MinValue
73  && MaxValueFloat < float.MaxValue))
74  {
75  ShowPlusMinusButtons();
76  }
77  else
78  {
79  HidePlusMinusButtons();
80  }
81  break;
82  }
83  case ButtonVisibility.Manual:
84  return;
85  }
86  }
87 
88  private NumberType inputType;
90  {
91  get { return inputType; }
92  set
93  {
94  if (inputType == value) { return; }
95  inputType = value;
96  UpdatePlusMinusButtonVisibility();
97  }
98  }
99 
100  private float? minValueFloat, maxValueFloat;
101  public float? MinValueFloat
102  {
103  get { return minValueFloat; }
104  set
105  {
106  minValueFloat = value;
107  ClampFloatValue();
108  UpdatePlusMinusButtonVisibility();
109  }
110  }
111  public float? MaxValueFloat
112  {
113  get { return maxValueFloat; }
114  set
115  {
116  maxValueFloat = value;
117  ClampFloatValue();
118  UpdatePlusMinusButtonVisibility();
119  }
120  }
121 
122  private float floatValue;
123  public float FloatValue
124  {
125  get
126  {
127  return floatValue;
128  }
129  set
130  {
131  if (Math.Abs(value - floatValue) < 0.0001f && MathUtils.NearlyEqual(value, floatValue)) { return; }
132  floatValue = value;
133  ClampFloatValue();
134  float newValue = floatValue;
135  UpdateText();
136  //UpdateText may remove decimals from the value, force to full accuracy
137  floatValue = newValue;
138  OnValueChanged?.Invoke(this);
139  }
140  }
141 
142  private int decimalsToDisplay = 1;
143  public int DecimalsToDisplay
144  {
145  get { return decimalsToDisplay; }
146  set
147  {
148  decimalsToDisplay = value;
149  UpdateText();
150  }
151  }
152 
153  private int? minValueInt, maxValueInt;
154  public int? MinValueInt
155  {
156  get { return minValueInt; }
157  set
158  {
159  minValueInt = value;
160  ClampIntValue();
161  }
162  }
163  public int? MaxValueInt
164  {
165  get { return maxValueInt; }
166  set
167  {
168  maxValueInt = value;
169  ClampIntValue();
170  }
171  }
172 
173  private int intValue;
174  public int IntValue
175  {
176  get
177  {
178  return intValue;
179  }
180  set
181  {
182  if (value == intValue) { return; }
183  intValue = value;
184  ClampIntValue();
185  UpdateText();
186  }
187  }
188 
189  public override bool Enabled
190  {
191  get => base.Enabled;
192  set
193  {
194  PlusButton.Enabled = true;
195  MinusButton.Enabled = true;
196  if (InputType == NumberType.Int) { ClampIntValue(); } else { ClampFloatValue(); }
197  TextBox.Enabled = value;
198  if (!value)
199  {
200  PlusButton.Enabled = false;
201  MinusButton.Enabled = false;
202  }
203  }
204  }
205 
206  public bool Readonly
207  {
208  get { return TextBox.Readonly; }
209  set
210  {
211  TextBox.Readonly = value;
212  PlusButton.Enabled = !value;
213  MinusButton.Enabled = !value;
214  }
215  }
216 
217  public override GUIFont Font
218  {
219  get
220  {
221  return base.Font;
222  }
223  set
224  {
225  base.Font = value;
226  if (TextBox != null) { TextBox.Font = value; }
227  }
228  }
229 
231  {
232  get;
233  private set;
234  }
235 
239  public bool WrapAround;
240 
241  public float ValueStep;
242 
243  // Enable holding to scroll through values faster
244  private float pressedTimer;
245  private readonly float pressedDelay = 0.5f;
246  private bool IsPressedTimerRunning { get { return pressedTimer > 0; } }
247 
249  RectTransform rectT,
250  NumberType inputType,
251  string style = "",
252  Alignment textAlignment = Alignment.Center,
253  float? relativeButtonAreaWidth = null,
254  ButtonVisibility buttonVisibility = ButtonVisibility.Automatic,
255  (GUIButton PlusButton, GUIButton MinusButton)? customPlusMinusButtons = null) : base(style, rectT)
256  {
257  LayoutGroup = new GUILayoutGroup(new RectTransform(Vector2.One, rectT), isHorizontal: true, childAnchor: Anchor.CenterLeft) { Stretch = true };
258 
259  float _relativeButtonAreaWidth = relativeButtonAreaWidth ?? MathHelper.Clamp(Rect.Height / (float)Rect.Width, 0.1f, 0.25f);
260 
261  TextBox = new GUITextBox(new RectTransform(new Vector2(1.0f - _relativeButtonAreaWidth, 1.0f), LayoutGroup.RectTransform), textAlignment: textAlignment, style: "GUITextBoxNoIcon")
262  {
263  ClampText = false
264  };
266  TextBox.OnTextChanged += TextChanged;
267  TextBox.OnDeselected += (sender, key) =>
268  {
269  if (inputType == NumberType.Int)
270  {
271  ClampIntValue();
272  }
273  else
274  {
275  ClampFloatValue();
276  }
277 
278  OnValueEntered?.Invoke(this);
279  };
280  TextBox.OnEnterPressed += (textBox, text) =>
281  {
282  if (inputType == NumberType.Int)
283  {
284  ClampIntValue();
285  }
286  else
287  {
288  ClampFloatValue();
289  }
290 
291  OnValueEntered?.Invoke(this);
292  return true;
293  };
294 
295  if (customPlusMinusButtons.HasValue)
296  {
297  PlusButton = customPlusMinusButtons.Value.PlusButton;
298  MinusButton = customPlusMinusButtons.Value.MinusButton;
299  }
300  else // generate the default +- buttons
301  {
302  var buttonArea = new GUIFrame(new RectTransform(new Vector2(_relativeButtonAreaWidth, 1.0f), LayoutGroup.RectTransform, Anchor.CenterRight), style: null);
303 
304  PlusButton = new GUIButton(new RectTransform(new Vector2(1.0f, 0.5f), buttonArea.RectTransform), style: null);
305  GUIStyle.Apply(PlusButton, "PlusButton", this);
306 
307  MinusButton = new GUIButton(new RectTransform(new Vector2(1.0f, 0.5f), buttonArea.RectTransform, Anchor.BottomRight), style: null);
308  GUIStyle.Apply(MinusButton, "MinusButton", this);
309  }
310 
311  // Set up default and custom +- buttons the same way to ensure uniform functionality
313  PlusButton.OnButtonDown += () =>
314  {
315  pressedTimer = pressedDelay;
316  return true;
317  };
318  PlusButton.OnClicked += (button, data) =>
319  {
320  IncreaseValue();
321  return true;
322  };
323  PlusButton.OnPressed += () =>
324  {
325  if (!IsPressedTimerRunning)
326  {
327  IncreaseValue();
328  }
329  return true;
330  };
332  MinusButton.OnButtonDown += () =>
333  {
334  pressedTimer = pressedDelay;
335  return true;
336  };
337  MinusButton.OnClicked += (button, data) =>
338  {
339  ReduceValue();
340  return true;
341  };
342  MinusButton.OnPressed += () =>
343  {
344  if (!IsPressedTimerRunning)
345  {
346  ReduceValue();
347  }
348  return true;
349  };
350 
351  PlusMinusButtonVisibility = buttonVisibility;
352 
353  if (inputType == NumberType.Int)
354  {
355  UpdateText();
356  TextBox.OnEnterPressed += (txtBox, txt) =>
357  {
358  UpdateText();
359  TextBox.Deselect();
360  return true;
361  };
362  TextBox.OnDeselected += (txtBox, key) => UpdateText();
363  }
364  else if (inputType == NumberType.Float)
365  {
366  UpdateText();
367  TextBox.OnDeselected += (txtBox, key) => UpdateText();
368  TextBox.OnEnterPressed += (txtBox, txt) =>
369  {
370  UpdateText();
371  TextBox.Deselect();
372  return true;
373  };
374  }
375  InputType = inputType;
376  switch (InputType)
377  {
378  case NumberType.Int:
379  TextBox.textFilterFunction = text => new string(text.Where(c => char.IsNumber(c) || c == '-').ToArray());
380  break;
381  case NumberType.Float:
382  TextBox.textFilterFunction = text => new string(text.Where(c => char.IsDigit(c) || c == '.' || c == '-').ToArray());
383  break;
384  }
385 
386  RectTransform.MinSize = new Point(
387  Math.Max(rectT.MinSize.X, TextBox.RectTransform.MinSize.X),
388  Math.Max(rectT.MinSize.Y, TextBox.RectTransform.MinSize.Y));
390  }
391 
392  private void HidePlusMinusButtons()
393  {
396  TextBox.RectTransform.RelativeSize = Vector2.One;
398  }
399 
400  private void ShowPlusMinusButtons()
401  {
406  }
407 
408  private void ReduceValue()
409  {
410  if (inputType == NumberType.Int)
411  {
412  IntValue -= ValueStep > 0 ? (int)ValueStep : 1;
413  ClampIntValue();
414  }
415  else if (maxValueFloat.HasValue && minValueFloat.HasValue)
416  {
417  FloatValue -= ValueStep > 0 ? ValueStep : Round();
418  ClampFloatValue();
419  }
420  }
421 
422  private void IncreaseValue()
423  {
424  if (inputType == NumberType.Int)
425  {
426  IntValue += ValueStep > 0 ? (int)ValueStep : 1;
427  ClampIntValue();
428  }
429  else if (inputType == NumberType.Float)
430  {
431  FloatValue += ValueStep > 0 ? ValueStep : Round();
432  ClampFloatValue();
433  }
434  }
435 
441  private float Round()
442  {
443  if (!maxValueFloat.HasValue || !minValueFloat.HasValue) { return 0; }
444  float onePercent = MathHelper.Lerp(minValueFloat.Value, maxValueFloat.Value, 0.01f);
445  float diff = maxValueFloat.Value - minValueFloat.Value;
446  int decimals = (int)MathHelper.Lerp(3, 0, MathUtils.InverseLerp(10, 1000, diff));
447  return MathHelper.Clamp((float)Math.Round(onePercent, decimals), 0.1f, 1000);
448  }
449 
450  private bool TextChanged(GUITextBox textBox, string text)
451  {
452  switch (InputType)
453  {
454  case NumberType.Int:
455  if (string.IsNullOrWhiteSpace(text) || text == "-")
456  {
457  intValue = 0;
458  }
459  else if (int.TryParse(text, out int newIntValue))
460  {
461  intValue = newIntValue;
462  }
463  break;
464  case NumberType.Float:
465  if (string.IsNullOrWhiteSpace(text) || text == "-")
466  {
467  floatValue = 0;
468  }
469  else if (float.TryParse(text, NumberStyles.Any, CultureInfo.InvariantCulture, out float newFloatValue))
470  {
471  floatValue = newFloatValue;
472  }
473  break;
474  }
475  OnValueChanged?.Invoke(this);
476  return true;
477  }
478 
479  private void ClampFloatValue()
480  {
481  if (MinValueFloat != null)
482  {
483  floatValue =
484  WrapAround && MinValueFloat.HasValue && floatValue < MinValueFloat.Value ?
485  MaxValueFloat.Value :
486  Math.Max(floatValue, MinValueFloat.Value);
487  MinusButton.Enabled = WrapAround || floatValue > MinValueFloat;
488  }
489  if (MaxValueFloat != null)
490  {
491  floatValue =
492  WrapAround && MaxValueFloat.HasValue && floatValue > MaxValueFloat.Value ?
493  MinValueFloat.Value :
494  Math.Min(floatValue, MaxValueFloat.Value);
495  PlusButton.Enabled = WrapAround || floatValue < MaxValueFloat;
496  }
497 
498  if (Readonly)
499  {
501  }
502  }
503 
504  private void ClampIntValue()
505  {
506  if (MinValueInt != null && intValue < MinValueInt.Value)
507  {
508  intValue = WrapAround && MaxValueInt.HasValue ? MaxValueInt.Value : Math.Max(intValue, MinValueInt.Value);
509  UpdateText();
510  }
511  if (MaxValueInt != null && intValue > MaxValueInt.Value)
512  {
513  intValue = WrapAround && MinValueInt.HasValue ? MinValueInt.Value : Math.Min(intValue, MaxValueInt.Value);
514  UpdateText();
515  }
516 
517  if (Readonly)
518  {
520  }
521  else
522  {
523  PlusButton.Enabled = WrapAround || MaxValueInt == null || intValue < MaxValueInt;
524  MinusButton.Enabled = WrapAround || MinValueInt == null || intValue > MinValueInt;
525  }
526  }
527 
528  private void UpdateText()
529  {
530  switch (InputType)
531  {
532  case NumberType.Float:
533  TextBox.Text = FloatValue.Format(decimalsToDisplay);
534  break;
535  case NumberType.Int:
536  TextBox.Text = IntValue.ToString();
537  break;
538  }
539  }
540 
541  protected override void Update(float deltaTime)
542  {
543  base.Update(deltaTime);
544  if (IsPressedTimerRunning)
545  {
546  pressedTimer -= deltaTime;
547  }
548  }
549  }
550 }
OnClickedHandler OnClicked
Definition: GUIButton.cs:16
override bool Enabled
Definition: GUIButton.cs:27
OnButtonDownHandler OnButtonDown
Definition: GUIButton.cs:22
OnPressedHandler OnPressed
Definition: GUIButton.cs:19
GUISoundType ClickSound
Definition: GUIButton.cs:167
virtual Rectangle Rect
RectTransform RectTransform
delegate void OnValueChangedHandler(GUINumberInput numberInput)
override RichString ToolTip
override void Update(float deltaTime)
OnValueChangedHandler OnValueChanged
OnValueEnteredHandler OnValueEntered
delegate void OnValueEnteredHandler(GUINumberInput numberInput)
ButtonVisibility PlusMinusButtonVisibility
Whether or not the default +- buttons should be shown. Defaults to Automatic, which enables it for al...
GUINumberInput(RectTransform rectT, NumberType inputType, string style="", Alignment textAlignment=Alignment.Center, float? relativeButtonAreaWidth=null, ButtonVisibility buttonVisibility=ButtonVisibility.Automatic,(GUIButton PlusButton, GUIButton MinusButton)? customPlusMinusButtons=null)
bool WrapAround
If enabled, the value wraps around to Max when you go below Min, and vice versa
TextBoxEvent OnDeselected
Definition: GUITextBox.cs:17
override RichString ToolTip
Definition: GUITextBox.cs:186
OnTextChangedHandler OnTextChanged
Don't set the Text property on delegates that register to this event, because modifying the Text will...
Definition: GUITextBox.cs:38
override GUIFont??? Font
Definition: GUITextBox.cs:198
OnEnterHandler OnEnterPressed
Definition: GUITextBox.cs:29
override bool Enabled
Definition: GUITextBox.cs:166
Func< string, string > textFilterFunction
Definition: GUITextBox.cs:26
Vector2 RelativeSize
Relative to the parent rect.
Point?? MinSize
Min size in pixels. Does not affect scaling.
NumberType
Definition: Enums.cs:715
GUISoundType
Definition: GUI.cs:21