Arma Reforger Explorer  1.1.0.42
Arma Reforger Code Explorer by Zeroy - Thanks to MisterOutofTime
SCR_BaseAnalogGauge.c
Go to the documentation of this file.
2 {
3  // Class defined gauge-specific settings
4  float m_fRingLabelOffset = 0.8;
5  int m_fRingLabelFontSize = 20;
6  ResourceName m_AnalogGauge = "{54F7755D48B394FD}UI/Textures/VehicleInfo/AnalogGaugeImageset.imageset";
7  string m_sRingMarkSection = "GaugeMarkSection";
8  string m_sRingMarkSubsection = "GaugeMarkSubsection";
9  string m_sDefaultLayout = "{00F28F3165DB7C83}UI/layouts/HUD/VehicleInfo/VehicleGauge_Default.layout";
10 
11  // Custom attributes
12  string m_sOverlay = "";
13  string m_sCustomNeedle = "";
14 };
15 
16 class SCR_BaseAnalogGauge : SCR_InfoDisplayExtended
17 {
18  // Attributes: widget setup
19  [Attribute("270", UIWidgets.Slider, "Gauge angular range (in degrees)", "30 360 5")]
20  protected float m_fWidgetRange;
21 
22  [Attribute("0", UIWidgets.Slider, "Gauge angular rotation (in degrees)", "0 360 5")]
23  protected float m_fWidgetRotation;
24 
25  [Attribute("0.6", UIWidgets.Slider, "Gauge global scale", "0.25 2 0.05")]
26  protected float m_fWidgetScale;
27 
28 
29  // Attributes: info texts
30  [Attribute("", UIWidgets.EditBox, "Custom text (e.g. units or gauge name). Hidden if empty.")]
31  protected string m_sInfoText;
32 
33  [Attribute("0.5", UIWidgets.Slider, "Units text anchor X-coordinate %-base of widget width.", "0 1 0.05")]
34  protected float m_fInfoPosX;
35 
36  [Attribute("0.15", UIWidgets.Slider, "Units text anchor Y-coordinate %-base of widget height.", "0 1 0.05")]
37  protected float m_fInfoPosY;
38 
39  [Attribute("", UIWidgets.EditBox, "Custom text (e.g. units or gauge name). Hidden if empty.")]
40  protected string m_sInfo2Text;
41 
42  [Attribute("0.5", UIWidgets.Slider, "Units text anchor X-coordinate %-base of widget width.", "0 1 0.05")]
43  protected float m_fInfo2PosX;
44 
45  [Attribute("0.85", UIWidgets.Slider, "Units text anchor Y-coordinate %-base of widget height.", "0 1 0.05")]
46  protected float m_fInfo2PosY;
47 
48  // Attributes: labels
49  [Attribute("1", UIWidgets.SpinBox, "Label value multiplier.")]
50  protected float m_fLabelValueMultiplier;
51 
52  [Attribute("0", UIWidgets.SpinBox, "Label value precision.","-6 6 1")]
53  protected int m_iLabelValuePrecision;
54 
55  [Attribute("1", UIWidgets.CheckBox, "Display absolute values on labels.")]
56  protected bool m_bAbsLabelValues;
57 
58  [Attribute("1", UIWidgets.CheckBox, "Display label for ZERO value.")]
59  protected bool m_bShowLabel0;
60 
61  [Attribute("1", UIWidgets.CheckBox, "Display label for MAX value.")]
62  protected bool m_bShowLabelMax;
63 
64  [Attribute("1", UIWidgets.CheckBox, "Display label for MIN value; both MIN && ZERO needs to be checked.")]
65  protected bool m_bShowLabelMin;
66 
67 
68  protected ref SCR_BaseAnalogGaugeData m_pGaugeData;
69 
70  protected TextWidget m_wInfo;
71  protected TextWidget m_wInfo2;
72  protected Widget m_wInfoAnchor;
73  protected Widget m_wInfo2Anchor;
74 
75  protected ImageWidget m_wRing;
76  protected ImageWidget m_wBackground;
77  protected ImageWidget m_wNeedle;
78  protected ImageWidget m_wNeedleShadow;
79  protected ImageWidget m_wOverlay;
80 
81  protected float m_fGaugeSizeX;
82  protected float m_fGaugeSizeY;
83 
84  protected Widget m_wRingMarks;
85  protected Widget m_wRingLabels;
86 
87  protected float m_fZeroValueRotation; //calculated from m_fWidgetRotation & m_fWidgetRange
88 
89  // Interface for getting value from signal(s) or component
90  //------------------------------------------------------------------------------------------------
91  protected float GetValue()
92  {
93  return 0;
94  }
95 
96  // Interface for getting percentage representation of the value - doesn't need to be always linear
97  //------------------------------------------------------------------------------------------------
98  protected float GetValuePerc(float value)
99  {
100  return 0;
101  }
102 
103  // Interface for getting gauge call specific data
104  //------------------------------------------------------------------------------------------------
105  protected ref SCR_BaseAnalogGaugeData GetGaugeData()
106  {
107  return null;
108  }
109 
110  // Interface for initialization and preprocessing of attribute values
111  //------------------------------------------------------------------------------------------------
112  protected void InitGauge(IEntity owner, out bool bSuccess)
113  {
114  }
115 
116  //------------------------------------------------------------------------------------------------
117  protected void CreateGauge(IEntity owner, out bool bSuccess)
118  {
119  // Gauge (ring, marks, labels)
120  bSuccess = CreateGaugeRing(owner);
121 
122  if (!bSuccess)
123  return;
124 
125  // Gauge needle
126  m_wNeedle = ImageWidget.Cast(m_wRoot.FindAnyWidget("Needle"));
127  m_wNeedleShadow = ImageWidget.Cast(m_wRoot.FindAnyWidget("NeedleShadow"));
128  bSuccess = CreateGaugeNeedle(owner, m_wNeedle, m_wNeedleShadow, m_pGaugeData.m_sCustomNeedle);
129 
130  if (!bSuccess)
131  return;
132 
133  // Gauge overlay (e.g. icon of "fuel stand")
134  m_wOverlay = ImageWidget.Cast(m_wRoot.FindAnyWidget("Overlay"));
135  bSuccess = CreateGaugeOverlay(owner, m_wOverlay, m_pGaugeData.m_sOverlay);
136 
137  if (!bSuccess)
138  return;
139 
140  // Gauge info text
141  m_wInfo = TextWidget.Cast(m_wRoot.FindAnyWidget("InfoText"));
142  m_wInfoAnchor = m_wRoot.FindAnyWidget("InfoAnchor");
143  CreateGaugeInfoText(owner, m_wInfo, m_sInfoText, m_wInfoAnchor, m_fInfoPosX, m_fInfoPosY);
144 
145  // Gauge info text2
146  m_wInfo2 = TextWidget.Cast(m_wRoot.FindAnyWidget("Info2Text"));
147  m_wInfo2Anchor = m_wRoot.FindAnyWidget("Info2Anchor");
148  CreateGaugeInfoText(owner, m_wInfo2, m_sInfo2Text, m_wInfo2Anchor, m_fInfo2PosX, m_fInfo2PosY);
149  }
150 
151  // Creates gauge ring, markings and labels based on dozen of data feeded from gauge attributes
152  //------------------------------------------------------------------------------------------------
153  protected bool CreateGaugeRing(IEntity owner)
154  {
155  m_fZeroValueRotation = m_fWidgetRotation + (360 - m_fWidgetRange) / 2;
156 
157  m_wRing = ImageWidget.Cast(m_wRoot.FindAnyWidget("Ring"));
158  m_wBackground = ImageWidget.Cast(m_wRoot.FindAnyWidget("Background"));
159  m_wRingMarks = m_wRoot.FindAnyWidget("RingMarks");
160  m_wRingLabels = m_wRoot.FindAnyWidget("RingLabels");
161 
162  if (!m_wRing)
163  return false;
164 
165  // Setup gauge ring
166  m_wRing.SetMaskProgress(m_fWidgetRange/360);
167  m_wRing.SetRotation(m_fZeroValueRotation);
168  Scale(m_wRing, m_fWidgetScale);
169 
170  // Setup gauge background
171  Scale(m_wBackground, m_fWidgetScale);
172 
173  // Get scaled gauge size from the Ring, used for dynamic positionning of other elements
174  vector size = m_wRing.GetSize();
175  m_fGaugeSizeX = size[0];
176  m_fGaugeSizeY = size[1];
177 
178  // Terminate if there is no ring marks parent widget
179  if (!m_wRingMarks)
180  return false;
181 
182  return true;
183  }
184 
185  //------------------------------------------------------------------------------------------------
186  protected bool CreateGaugeNeedle(IEntity owner, ImageWidget wNeedle, ImageWidget wNeedleShadow, string sCustomNeedle = "", bool bVisible = true)
187  {
188  if (!wNeedle || !wNeedleShadow)
189  return false;
190 
191  if (sCustomNeedle)
192  {
193  wNeedle.LoadImageFromSet(0, m_pGaugeData.m_AnalogGauge, sCustomNeedle);
194  wNeedleShadow.LoadImageFromSet(0, m_pGaugeData.m_AnalogGauge, sCustomNeedle);
195  }
196  Scale(wNeedle, m_fWidgetScale);
197  Scale(wNeedleShadow, m_fWidgetScale);
198 
199  wNeedle.SetVisible(bVisible);
200  wNeedleShadow.SetVisible(bVisible);
201 
202  return true;
203  }
204 
205  //------------------------------------------------------------------------------------------------
206  protected bool CreateGaugeOverlay(IEntity owner, ImageWidget wOverlay, string sOverlayTexture, bool bVisible = true)
207  {
208  if (!m_wOverlay)
209  return false;
210 
211  if (sOverlayTexture == "")
212  {
213  wOverlay.SetVisible(false);
214  return true;
215  }
216 
217  wOverlay.LoadImageFromSet(0, m_pGaugeData.m_AnalogGauge, sOverlayTexture);
218  wOverlay.SetVisible(bVisible);
219  Scale(wOverlay, m_fWidgetScale);
220 
221  return true;
222  }
223 
224  //------------------------------------------------------------------------------------------------
225  protected bool CreateGaugeInfoText(IEntity owner, TextWidget wInfo, string sText, Widget wAnchor, float fPosX, float fPosY, bool bVisible = true)
226  {
227  if (!wInfo || !wAnchor)
228  return false;
229 
230  if (sText == "")
231  {
232  wInfo.SetVisible(false);
233  return true;
234  }
235 
236  wInfo.SetVisible(bVisible);
237  wInfo.SetText(sText);
238  Scale(wInfo, m_fWidgetScale);
239  MovePerc(wAnchor, fPosX, fPosY);
240 
241  return true;
242  }
243 
244  //------------------------------------------------------------------------------------------------
245  protected void UpdateGauge(IEntity owner, float timeSlice, float value)
246  {
247  // Get unclamped percentage value of the gauge range
248  float fValuePerc = GetValuePerc(value);
249 
250  UpdateGaugeNeedle(owner, timeSlice, m_wNeedle, m_wNeedleShadow, fValuePerc);
251  }
252 
253  // Rotates gauge needle based on % of the value range; supports Clamped / Free360 needle movement behavior
254  //------------------------------------------------------------------------------------------------
255  protected void UpdateGaugeNeedle(IEntity owner, float timeSlice, ImageWidget wNeedle, ImageWidget wNeedleShadow, float fValuePerc, float fScaleValue = 1.00, bool bClamp = true)
256  {
257  if (!m_wNeedle)
258  return;
259 
260  // Scale the value
261  fValuePerc = fValuePerc * fScaleValue;
262 
263  // Ajust the %value for Clamped / Free360 movement behavior
264  if (bClamp)
265  {
266  fValuePerc = Math.Clamp(fValuePerc, 0, 1);
267  }
268  else
269  {
270  fValuePerc = fValuePerc - Math.Floor(fValuePerc);
271 
272  if (fValuePerc < 0)
273  fValuePerc = 1 + fValuePerc;
274  }
275 
276  // Rotate the gauge needle
277  float fAngle = m_fZeroValueRotation + (fValuePerc * m_fWidgetRange);
278 
279  wNeedle.SetRotation(fAngle);
280 
281  if (wNeedleShadow)
282  wNeedleShadow.SetRotation(fAngle);
283  }
284 
285  //------------------------------------------------------------------------------------------------
286  protected void DestroyGauge()
287  {
288  m_pGaugeData = null;
289 
290  if (!m_wRoot)
291  return;
292 
293  if (m_wRoot)
294  m_wRoot.RemoveFromHierarchy();
295 
296  m_wRoot = null;
297  }
298 
299  //------------------------------------------------------------------------------------------------
300  override event void DisplayUpdate(IEntity owner, float timeSlice)
301  {
302  if (!m_wRoot)
303  return;
304 
305  // Get actual value
306  float value = GetValue();
307 
308  UpdateGauge(owner, timeSlice, value);
309  }
310 
311  //------------------------------------------------------------------------------------------------
312  override bool DisplayStartDrawInit(IEntity owner)
313  {
314  // Terminate if widget already exists
315  if (m_wRoot)
316  return false;
317 
318  // Get gauge setup data
319  m_pGaugeData = GetGaugeData();
320 
321  if (!m_pGaugeData)
322  return false;
323 
324  // Force default layout, if layout is not set
325  if (m_LayoutPath == "")
326  m_LayoutPath = m_pGaugeData.m_sDefaultLayout;
327 
328  return true;
329  }
330 
331  //------------------------------------------------------------------------------------------------
332  override void DisplayStartDraw(IEntity owner)
333  {
334  if (!m_wRoot)
335  {
336  m_pGaugeData = null;
337  return;
338  }
339 
340  // Init gauge settings & attributes
341  bool bSuccess = true;
342  InitGauge(owner, bSuccess);
343 
344  if (!bSuccess)
345  DestroyGauge();
346 
347  // Create gauge with all its elements; some are optional and can fail
348  CreateGauge(owner, bSuccess);
349 
350  if (!bSuccess)
351  DestroyGauge();
352  }
353 
354  //------------------------------------------------------------------------------------------------
355  override void DisplayStopDraw(IEntity owner)
356  {
357  DestroyGauge();
358  }
359 
360  //------------------------------------------------------------------------------------------------
361  override void DisplayInit(IEntity owner)
362  {
363  if (m_wRoot)
364  m_wRoot.RemoveFromHierarchy();
365  }
366 
367  //------------------------------------------------------------------------------------------------
368  private void MovePerc(Widget widget, float x, float y)
369  {
370  if (!widget || !m_wRing)
371  return;
372 
373  // Re-adjust x & y as 0,0 should mean the middle
374  x -= 0.5;
375  y -= 0.5;
376 
377  OverlaySlot.SetPadding(widget, x * m_fGaugeSizeX, y * m_fGaugeSizeY, 0, 0);
378  }
379 
380  //------------------------------------------------------------------------------------------------
381  private void Scale(ImageWidget widget, float scale)
382  {
383  if (!widget)
384  return;
385 
386  int imageWidth = 0;
387  int imageHeight = 0;
388  int image = widget.GetImage();
389 
390  widget.GetImageSize(image, imageWidth, imageHeight);
391  widget.SetSize((float)imageWidth * scale, (float)imageHeight * scale);
392  }
393 
394  //------------------------------------------------------------------------------------------------
395  private void Scale(TextWidget widget, float scale)
396  {
397  if (!widget)
398  return;
399 
400  float sizeY = FrameSlot.GetSizeY(widget);
401  FrameSlot.SetSizeY(widget, sizeY * scale);
402  }
403 
404  //------------------------------------------------------------------------------------------------
405  protected void CreateRingLabel(WorkspaceWidget workspace, float angle, float value, bool absValues = true, float labelValueMultiplier = 1, int labelValuePrecision = 0)
406  {
407  value = value * labelValueMultiplier; //doesn't always need to start from 0, even if it's most common
408 
409  if (labelValuePrecision == 0)
410  {
411  value = Math.Round(value);
412  }
413  else
414  {
415  float decimals = labelValuePrecision * 10;
416 
417  if (decimals < 0)
418  decimals = -1 / decimals;
419 
420  value = Math.Round(value * decimals);
421  value = value / decimals;
422  }
423 
424  if (value == 0 && !m_bShowLabel0)
425  return;
426 
427  if (absValues)
428  value = Math.AbsFloat(value);
429 
430  float rads = angle / Math.RAD2DEG;
431 
432  float xcoef = - Math.Sin(rads);
433  float ycoef = Math.Cos(rads);
434 
435  float x = 0.5 * m_fGaugeSizeX * xcoef * m_pGaugeData.m_fRingLabelOffset;
436  float y = 0.5 * m_fGaugeSizeY * ycoef * m_pGaugeData.m_fRingLabelOffset;
437 
438  Widget w = workspace.CreateWidget(WidgetType.TextWidgetTypeID, WidgetFlags.INHERIT_CLIPPING | WidgetFlags.VISIBLE | WidgetFlags.ADDITIVE | WidgetFlags.STRETCH, null, 0, m_wRingLabels);
439  TextWidget wText = TextWidget.Cast(w);
440 
441  wText.SetText(value.ToString());
442  wText.SetFont("{EABA4FE9D014CCEF}UI/Fonts/RobotoCondensed/RobotoCondensed_Bold.fnt");
443  wText.SetExactFontSize(m_pGaugeData.m_fRingLabelFontSize * m_fWidgetScale);
444 
445  float alignx = xcoef / 2 + 0.5;
446  float aligny = ycoef / 2 + 0.5;
447 
448  FrameSlot.SetAlignment(wText, alignx, aligny);
449  FrameSlot.SetAnchorMin(wText, 0.5, 0.5);
450  FrameSlot.SetAnchorMax(wText, 0.5, 0.5);
451  FrameSlot.SetSizeToContent(wText, true);
452  FrameSlot.SetPos(wText, x, y);
453  }
454 
455  //------------------------------------------------------------------------------------------------
456  protected void CreateRingMark(WorkspaceWidget workspace, float angle, string texture)
457  {
458  Widget w = workspace.CreateWidget(WidgetType.ImageWidgetTypeID, WidgetFlags.INHERIT_CLIPPING | WidgetFlags.VISIBLE | WidgetFlags.ADDITIVE | WidgetFlags.STRETCH, null, 0, m_wRingMarks);
459  ImageWidget wImage = ImageWidget.Cast(w);
460 
461  wImage.LoadImageFromSet(0, m_pGaugeData.m_AnalogGauge, texture);
462  FrameSlot.SetAlignment(wImage, 0.5, 0);
463  FrameSlot.SetAnchorMin(wImage, 0.5, 0.5);
464  FrameSlot.SetAnchorMax(wImage, 0.5, 0.5);
465  FrameSlot.SetSizeToContent(wImage, true);
466  FrameSlot.SetPos(wImage, 0, 0);
467 
468  Scale(wImage, m_fWidgetScale);
469 
470  wImage.SetPivot(0.5, 0);
471  wImage.SetRotation(angle);
472  }
473 };
474 
m_wRoot
protected Widget m_wRoot
Definition: SCR_ScenarioFrameworkLayerTaskDefend.c:59
SCR_BaseAnalogGauge
Definition: SCR_BaseAnalogGauge.c:16
Attribute
typedef Attribute
Post-process effect of scripted camera.
SCR_BaseAnalogGaugeData
Definition: SCR_BaseAnalogGauge.c:1
m_wBackground
protected ImageWidget m_wBackground
Definition: SCR_InventoryHitZonePointUI.c:382
m_wOverlay
private Widget m_wOverlay
Definition: SCR_AISettingsComponent.c:46