DayZ Scripts
v1.21.156300 ยท Jun 20, 2023
 
Loading...
Searching...
No Matches
RadialMenu.c
Go to the documentation of this file.
2{
6
8{
9 protected Widget m_Parent;
12 protected ImageWidget m_RadialSelectorImage;
13 protected ImageWidget m_RadialSelectorPointerImage;
18
19 protected float m_AngleRadOffset;
20 protected ref Timer m_UpdateTimer;
21
22 //widget
23 static const string RADIAL_SELECTOR = "RadialSelector";
24 static const string RADIAL_SELECTOR_IMAGE = "SelectorImage";
25 static const string RADIAL_SELECTOR_POINTER = "SelectorPointer";
26 static const string RADIAL_DELIMITER_CONTAINER = "RadialDelimiterContainer";
27 static const string RADIAL_ITEM_CARD_CONTAINER = "RadialItemCardContainer";
28
29 //controls
33 protected float m_ControllerAngle;
34 protected float m_ControllerTilt;
35
36 //controller
37 protected int m_ControllerTimout;
38 protected bool m_IsControllerTimoutEnabled = true; //enables/disables controller deselect timeout reset
39 protected const float CONTROLLER_DESELECT_TIMEOUT = 1000; //timeout [ms] after which selection is automatically deselect when controller is not active
40 protected const float CONTROLLER_TILT_TRESHOLD_SELECT = 0.8; //tilt value (0.0-1.0) for controller sticks after which the selection will be selected
41 protected const float CONTROLLER_TILT_TRESHOLD_EXECUTE = 1.0; //tilt value (0.0-1.0) for controller sticks after which the selection will be executed
42
43 //mouse
44 protected bool m_WidgetInitialized;
45 protected const float MOUSE_SAFE_ZONE_RADIUS = 120; //Radius [px] of safe zone where every previous selection is deselected
46
47 //References
48 protected float m_RadiusOffset; //Radius [% of the main container size]
49 protected float m_ExecuteDistanceOffset; //Distance offset [% of the main container size] after which the selection will be automatically executed
50 protected float m_OffsetFromTop; //first item in the menu won't be directly on top but offset by a rad angle value (clock-wise)
51 protected float m_ItemCardRadiusOffset; //Radius [% of the main container size] for item cards
52 protected string m_DelimiterLayout; //layout file name with path
53
56
57 /*
58
59 RADIAL MENU EVENTS
60
61 Mouse:
62 OnMouseSelect
63 OnMouseDeselect
64 OnMouseExecute - unused, press events used instead
65 OnMousePressLeft
66 OnMousePressRight
67
68 Controller:
69 OnControllerSelect
70 OnControllerDeselect
71 OnControllerExecute - unused, press events used instead
72 OnControllerPressSelect
73 OnControllerPressBack
74
75 Common:
76 OnControlsChanged - controls has been changed (mouse<->controller)
77
78 */
79
80
81 //============================================
82 // RadialMenu
83 //============================================
85 {
86 m_Instance = this;
87
88 //set default control type
89#ifdef PLATFORM_CONSOLE
90 Input inp = GetGame().GetInput();
92 {
94 }
95 else
96 {
98 }
99#endif
100#ifdef PLATFORM_WINDOWS
102#endif
103
106
107 //radial cards
109 m_UpdateTimer = new Timer();
110 m_UpdateTimer.Run(0.01, this, "Update", NULL, true);
111 }
112
114 {
115 }
116
118 {
119 return m_Instance;
120 }
121
122 //Set handler
124 {
126 m_RadialSelector = w.FindAnyWidget(RADIAL_SELECTOR);
127 m_RadialSelectorImage = ImageWidget.Cast(m_RadialSelector.FindAnyWidget(RADIAL_SELECTOR_IMAGE));
129
131 m_RadialSelectorDisabledColor = ARGB(255,150,150,150);
132
133 //parent
134 m_Parent = w;
135 m_Parent.SetHandler(this);
136 }
137
138 //controls
140 {
141 if (m_ControlType != type)
142 {
143 m_ControlType = type;
144 GetGame().GameScript.CallFunction(m_RegisteredClass, "OnControlsChanged", NULL, type);
145 }
146 }
147
149 {
151 {
152 return true;
153 }
154
155 return false;
156 }
157
159 {
160 if (m_ControlType == RadialMenuControlType.CONTROLLER)
161 {
162 return true;
163 }
164
165 return false;
166 }
167
168 void SetWidgetInitialized(bool state)
169 {
170 m_WidgetInitialized = state;
171 }
172
174 {
175 return m_WidgetInitialized;
176 }
177
178 //============================================
179 // Setup
180 //============================================
182 {
184 if (m_UpdateTimer && !m_UpdateTimer.IsRunning())
185 m_UpdateTimer.Run(0.01, this, "Update", NULL, true);
186 }
187
188 //Set radial menu parameters
189 //Radius offset [% of the main container size]
190 void SetRadiusOffset(float radius_offset)
191 {
192 m_RadiusOffset = radius_offset;
193 }
194
195 //Distance offset [% of the main container size] after which the selection will be automatically executed
196 void SetExecuteDistOffset(float execute_dist_offset)
197 {
198 m_ExecuteDistanceOffset = execute_dist_offset;
199 }
200
201 //First item in the menu won't be directly on top but offset by a rad angle value (clock-wise)
202 void SetOffsetFromTop(float offset_from_top)
203 {
204 m_OffsetFromTop = offset_from_top;
205 }
206
207 //Radius [% of the main container size] for item cards
208 void SetItemCardRadiusOffset(float item_card_radius_offset)
209 {
210 m_ItemCardRadiusOffset = item_card_radius_offset;
211 }
212
213 //Enable/Disable controller timeout
215 {
217 }
218
219 void SetWidgetProperties(string delimiter_layout)
220 {
221 m_DelimiterLayout = delimiter_layout;
222 }
223
224 //============================================
225 // Visual
226 //============================================
227 //hide_selector => shows/hides radial selector when refreshing radial menu
228 void Refresh(bool hide_selector = true)
229 {
230 int item_cards_count = GetItemCardsCount();
231 if (item_cards_count > 0)
232 m_AngleRadOffset = 2 * Math.PI / item_cards_count;
233 float angle_rad = -Math.PI / 2;
234
235 //--PARAM top offset--
236 if (m_OffsetFromTop != 0)
237 {
238 angle_rad = angle_rad + m_OffsetFromTop;
239 }
240 //--------------------
241
242 //delete all delimiters
243 Widget delimiters_panel = m_Parent.FindAnyWidget(RADIAL_DELIMITER_CONTAINER);
244 if (delimiters_panel)
245 {
246 Widget del_child = delimiters_panel.GetChildren();
247 while (del_child)
248 {
249 Widget child_to_destroy1 = del_child;
250 del_child = del_child.GetSibling();
251
252 delete child_to_destroy1;
253 }
254 }
255
256 //Position item cards, crate radial delimiters
257 Widget item_cards_panel = m_Parent.FindAnyWidget(RADIAL_ITEM_CARD_CONTAINER);
258 Widget item_card = item_cards_panel.GetChildren();
259
260 //get radius
261 float original_r = GetRadius();
262 float item_cards_r = original_r;
263
264 //--PARAM top offset--....
265 if (m_ItemCardRadiusOffset != 0)
266 {
267 item_cards_r = item_cards_r * m_ItemCardRadiusOffset;
268 if (item_cards_r < 0) item_cards_r = 0; //min radius is 0
269 }
270
271 m_RadialItemCards.Clear();
272 for (int i = 0; i < item_cards_count; ++i)
273 {
274 //position item cards
275 if (item_card)
276 {
277 //creates circle from simple widget items
278 float pos_x = item_cards_r * Math.Cos(angle_rad);
279 float pos_y = item_cards_r * Math.Sin(angle_rad);
280
281 pos_x = pos_x / original_r;
282 pos_y = pos_y / original_r;
283
284 item_card.SetPos(pos_x, pos_y);
285
286 //store item card
287 m_RadialItemCards.Insert(item_card, angle_rad);
288
289 //get next child
290 item_card = item_card.GetSibling();
291 }
292 //-------------------------
293
294 //create delimiter
295 if (item_cards_count > 1 && delimiters_panel && m_DelimiterLayout)
296 {
297 Widget delimiter_widget = GetGame().GetWorkspace().CreateWidgets(m_DelimiterLayout, delimiters_panel);
298 float delim_angle_rad = angle_rad + (m_AngleRadOffset / 2);
299 delimiter_widget.SetPos(0, 0);
300 delimiter_widget.SetRotation(0, 0, GetAngleInDegrees(delim_angle_rad) + 90);
301 }
302
303 //calculate next angle
304 angle_rad += m_AngleRadOffset;
305 }
306
307 //hide selector on refresh
308 if (hide_selector)
309 {
311 }
312 }
313
314 //Radial selector
315 protected void ShowRadialSelector(Widget selected_item)
316 {
317 if (m_RadialSelector && selected_item)
318 {
319 int item_count = m_RadialItemCards.Count();
320 if (item_count > 1)
321 {
322 int angle_deg = GetAngleInDegrees(m_RadialItemCards.Get(selected_item));
323 m_RadialSelector.SetRotation(0, 0, angle_deg + 90); //rotate widget according to its desired rotation
324
325 //set radial selector size
326 float progress = (1 / item_count) * 2;
327 m_RadialSelectorImage.SetMaskProgress(progress);
328
329 m_RadialSelector.Show(true);
330
331 bool grey_selector = selected_item.GetFlags() & WidgetFlags.DISABLED;
332 if (!grey_selector)
333 {
336 }
337 else
338 {
341 }
342 }
343 }
344 }
345
346 protected void HideRadialSelector()
347 {
349 {
350 m_RadialSelector.Show(false);
351 }
352 }
353
354 //============================================
355 // Widget size calculations
356 //============================================
357 protected int GetItemCardsCount()
358 {
359 Widget child = m_ItemCardsContainer.GetChildren();
360 int count = 0;
361
362 while (child)
363 {
364 ++count;
365
366 child = child.GetSibling();
367 }
368
369 return count;
370 }
371
372 protected float GetRadius()
373 {
374 float radius = Math.AbsFloat(GetParentMinSize() * 0.5);
375
376 //PARAM --radius--
377 if (m_RadiusOffset > 0)
378 {
379 return radius * m_RadiusOffset;
380 }
381 //----------------
382
383 return radius;
384 }
385
386 protected void GetParentCenter(out float center_x, out float center_y)
387 {
388 if (m_Parent)
389 {
390 float wx;
391 float wy;
392 m_Parent.GetScreenPos(wx, wy);
393
394 float ww;
395 float wh;
396 m_Parent.GetScreenSize(ww, wh);
397
398 center_x = wx + ww / 2; //center
399 center_y = wy + wh / 2;
400 }
401 }
402
403 protected float GetParentMinSize()
404 {
405 if (m_Parent)
406 {
407 float size_x;
408 float size_y;
409 m_Parent.GetScreenSize(size_x, size_y);
410
411 return Math.Min(size_x, size_y);
412 }
413
414 return 0;
415 }
416
417 //============================================
418 // Angle calculations
419 //============================================
420 //get object by angle (degrees)
421 protected Widget GetObjectByDegAngle(float deg_angle)
422 {
423 for (int i = 0; i < m_RadialItemCards.Count(); ++i)
424 {
425 Widget w = m_RadialItemCards.GetKey(i);
426 float w_angle = GetAngleInDegrees(m_RadialItemCards.Get(w));
427 float offset = GetAngleInDegrees(m_AngleRadOffset) / 2;
428 float min_angle = w_angle - offset;
429 float max_angle = w_angle + offset;
430
431 if (min_angle < 0) min_angle += 360; //clamp 0-360
432 if (max_angle > 360) max_angle -= 360;
433
434 if (min_angle > max_angle) //angle radius is in the cycling point 360->
435 {
436 if (min_angle <= deg_angle) //is cursor position also before this point
437 {
438 if (deg_angle > max_angle)
439 {
440 return w;
441 }
442 }
443 else //is cursor position after this point
444 {
445 if (deg_angle < max_angle)
446 {
447 return w;
448 }
449 }
450 }
451 else
452 {
453 if (deg_angle >= min_angle && deg_angle < max_angle) //min, max angles are within 0-360 radius
454 {
455 return w;
456 }
457 }
458 }
459
460 return NULL;
461 }
462
463 //returns GUI compatible mouse-to-parent angle
464 protected float GetMousePointerAngle()
465 {
466 int mouse_x;
467 int mouse_y;
468 GetGame().GetMousePos(mouse_x, mouse_y);
469
470 float center_x;
471 float center_y;
472 GetParentCenter(center_x, center_y);
473
474 float tan_x = mouse_x - center_x;
475 float tan_y = mouse_y - center_y;
476 float angle = Math.Atan2(tan_y, tan_x);
477
478 return angle;
479 }
480
481 //returns distance from parent center
482 protected float GetMouseDistance()
483 {
484 int mouse_x;
485 int mouse_y;
486 GetGame().GetMousePos(mouse_x, mouse_y);
487
488 float center_x;
489 float center_y;
490 GetParentCenter(center_x, center_y);
491
492 float distance = vector.Distance(Vector(mouse_x, mouse_y, 0), Vector(center_x, center_y, 0));
493
494 return distance;
495 }
496
497 //return angle 0-360 deg
498 protected float GetAngleInDegrees(float rad_angle)
499 {
500 float rad_deg = rad_angle * Math.RAD2DEG;
501
502 int angle_mp = rad_deg / 360;
503
504 if (rad_deg < 0)
505 {
506 rad_deg = rad_deg - (360 * angle_mp);
507 rad_deg += 360;
508 }
509
510 return rad_deg;
511 }
512
513 //============================================
514 // Update
515 //============================================
516 //mouse
517 int last_time = -1;
518 protected void Update()
519 {
520 if (this && !m_RegisteredClass)
521 {
523 return;
524 }
525
526 //get delta time
527 if (last_time < 0)
528 {
530 }
531 int delta_time = GetGame().GetTime() - last_time;
533
534 //controls
535 if (this && m_RegisteredClass && m_RegisteredClass.IsVisible())
536 {
537 //mouse controls
539 {
540 float mouse_angle = GetMousePointerAngle();
541 float mouse_distance = GetMouseDistance();
542
543 //--PARAM --safe zone radius--
544 if (mouse_distance <= MOUSE_SAFE_ZONE_RADIUS)
545 {
546 //Deselect
548 m_SelectedObject = NULL;
549 //hide selector
551 }
552 else
553 {
554 //Deselect
556
557 //Select
560 //show selector
562 }
563 }
564 //controller controls
565 else if (IsUsingController())
566 {
568
569 //Controller tilt
570 if (m_ControllerAngle > -1 && m_ControllerTilt > -1)
571 {
572 //Right analogue stick
574 //Select
575 if (w_selected)
576 {
577 if (w_selected != m_SelectedObject)
578 {
580 {
581 //Deselect
582 GetGame().GameScript.CallFunction(m_RegisteredClass, "OnControllerDeselect", NULL, m_SelectedObject);
583
584 //Select new object
585 m_SelectedObject = w_selected;
586 GetGame().GameScript.CallFunction(m_RegisteredClass, "OnControllerSelect", NULL, m_SelectedObject);
587 //show selector
589 }
590 }
591 }
592 else
593 {
594 GetGame().GameScript.CallFunction(m_RegisteredClass, "OnControllerDeselect", NULL, m_SelectedObject);
595 m_SelectedObject = NULL;
596 //hide selector
598 }
599 }
600 //if controller is giving no feedback
601 else
602 {
604 {
605 m_ControllerTimout += delta_time;
606
608 {
609 GetGame().GameScript.CallFunction(m_RegisteredClass, "OnControllerDeselect", NULL, m_SelectedObject);
610 m_SelectedObject = NULL;
611 //hide selector
613
614 m_ControllerTimout = 0; //reset controller timeout
615 }
616 }
617 }
618
619 m_ControllerAngle = -1; //reset angle and tilt
620 m_ControllerTilt = -1;
621 }
622
623 m_WidgetInitialized = true;
624 }
625 }
626
627 float NormalizeInvertAngle(float angle)
628 {
629 float new_angle = 360 - angle;
630 int angle_mp = new_angle / 360;
631
632 new_angle = new_angle - (360 * angle_mp);
633
634 return new_angle;
635 }
636
637 //============================================
638 // Controls
639 //============================================
641 {
642 Input input = GetGame().GetInput();
643
644 //Controller radial
645 float angle;
646 float tilt;
647 input.GetGamepadThumbDirection(GamepadButton.THUMB_RIGHT, angle, tilt);
648 angle = NormalizeInvertAngle(angle * Math.RAD2DEG);
649
650 m_ControllerAngle = angle;
651 m_ControllerTilt = tilt;
652 m_ControllerTimout = 0; //reset controller timeout
653
654 //Controller buttons
655 //Select (A,cross)
657 {
658 GetGame().GameScript.CallFunction(m_RegisteredClass, "OnControllerPressSelect", NULL, m_SelectedObject);
659 }
660
661 //Back (B,circle)
663 {
664 GetGame().GameScript.CallFunction(m_RegisteredClass, "OnControllerPressBack", NULL, m_SelectedObject);
665 }
666 }
667
668 override bool OnMouseButtonUp(Widget w, int x, int y, int button)
669 {
670 if (button == MouseState.LEFT && m_SelectedObject/* && w == m_SelectedObject*/)
671 {
672 //Execute
674
675 return true;
676 }
677
678 if (button == MouseState.RIGHT)
679 {
680 //Back one level
681 GetGame().GameScript.CallFunction(m_RegisteredClass, "OnMousePressRight", NULL, NULL);
682
683 return true;
684 }
685
686 return false;
687 }
688}
static AnimSoundObjectBuilderBank GetInstance()
Icon x
Icon y
class OptionSelectorMultistate extends OptionSelector class_name
static const string RADIAL_ITEM_CARD_CONTAINER
Definition RadialMenu.c:27
protected float m_ItemCardRadiusOffset
Definition RadialMenu.c:51
protected float GetAngleInDegrees(float rad_angle)
Definition RadialMenu.c:498
protected float m_OffsetFromTop
Definition RadialMenu.c:50
private UAIDWrapper m_BackInputWrapper
Definition RadialMenu.c:32
bool IsUsingController()
Definition RadialMenu.c:158
protected RadialMenuControlType m_ControlType
Definition RadialMenu.c:30
protected const float MOUSE_SAFE_ZONE_RADIUS
Definition RadialMenu.c:45
protected bool m_WidgetInitialized
Definition RadialMenu.c:44
protected void GetParentCenter(out float center_x, out float center_y)
Definition RadialMenu.c:386
protected float GetRadius()
Definition RadialMenu.c:372
void RegisterClass(UIScriptedMenu class_name)
Definition RadialMenu.c:181
static const string RADIAL_SELECTOR
Definition RadialMenu.c:23
protected ImageWidget m_RadialSelectorPointerImage
Definition RadialMenu.c:13
void UpdataControllerInput()
Definition RadialMenu.c:640
void SetExecuteDistOffset(float execute_dist_offset)
Definition RadialMenu.c:196
protected Widget m_ItemCardsContainer
Definition RadialMenu.c:10
void SetWidgetInitialized(bool state)
Definition RadialMenu.c:168
float NormalizeInvertAngle(float angle)
Definition RadialMenu.c:627
void SetOffsetFromTop(float offset_from_top)
Definition RadialMenu.c:202
void SetRadiusOffset(float radius_offset)
Definition RadialMenu.c:190
static const string RADIAL_SELECTOR_POINTER
Definition RadialMenu.c:25
ref UIScriptedMenu m_RegisteredClass
Definition RadialMenu.c:54
RadialMenuControlType
Definition RadialMenu.c:2
@ CONTROLLER
Definition RadialMenu.c:4
@ MOUSE
Definition RadialMenu.c:3
protected bool m_IsControllerTimoutEnabled
Definition RadialMenu.c:38
protected const float CONTROLLER_DESELECT_TIMEOUT
Definition RadialMenu.c:39
protected float m_RadiusOffset
Definition RadialMenu.c:48
static ref RadialMenu m_Instance
Definition RadialMenu.c:55
protected int m_RadialSelectorDisabledColor
Definition RadialMenu.c:15
private UAIDWrapper m_SelectInputWrapper
Definition RadialMenu.c:31
bool IsUsingMouse()
Definition RadialMenu.c:148
void SetControlType(RadialMenuControlType type)
Definition RadialMenu.c:139
protected float GetMouseDistance()
Definition RadialMenu.c:482
protected int GetItemCardsCount()
Definition RadialMenu.c:357
bool IsWidgetInitialized()
Definition RadialMenu.c:173
protected const float CONTROLLER_TILT_TRESHOLD_SELECT
Definition RadialMenu.c:40
protected ImageWidget m_RadialSelectorImage
Definition RadialMenu.c:12
protected float GetParentMinSize()
Definition RadialMenu.c:403
protected Widget m_RadialSelector
Definition RadialMenu.c:11
protected float GetMousePointerAngle()
Definition RadialMenu.c:464
static const string RADIAL_SELECTOR_IMAGE
Definition RadialMenu.c:24
int last_time
Definition RadialMenu.c:517
protected int m_RadialSelectorOriginalColor
Definition RadialMenu.c:14
protected float m_ControllerAngle
Definition RadialMenu.c:33
void SetWidgetProperties(string delimiter_layout)
Definition RadialMenu.c:219
protected float m_ControllerTilt
Definition RadialMenu.c:34
protected ref Timer m_UpdateTimer
Definition RadialMenu.c:20
protected ref map< Widget, float > m_RadialItemCards
Definition RadialMenu.c:17
static const string RADIAL_DELIMITER_CONTAINER
Definition RadialMenu.c:26
void ActivateControllerTimeout(bool state)
Definition RadialMenu.c:214
void SetItemCardRadiusOffset(float item_card_radius_offset)
Definition RadialMenu.c:208
protected const float CONTROLLER_TILT_TRESHOLD_EXECUTE
Definition RadialMenu.c:41
protected Widget m_SelectedObject
Definition RadialMenu.c:16
void ~RadialMenu()
Definition RadialMenu.c:113
protected float m_AngleRadOffset
Definition RadialMenu.c:19
protected Widget GetObjectByDegAngle(float deg_angle)
Definition RadialMenu.c:421
void RadialMenu()
Definition RadialMenu.c:84
protected void HideRadialSelector()
Definition RadialMenu.c:346
protected string m_DelimiterLayout
Definition RadialMenu.c:52
protected float m_ExecuteDistanceOffset
Definition RadialMenu.c:49
protected int m_ControllerTimout
Definition RadialMenu.c:37
protected void ShowRadialSelector(Widget selected_item)
Definition RadialMenu.c:315
protected Widget m_Parent
Definition SizeToChild.c:92
proto native UAInputAPI GetUApi()
proto native Input GetInput()
proto native WorkspaceWidget GetWorkspace()
proto int GetTime()
returns mission time in milliseconds
ScriptModule GameScript
Definition Game.c:12
Definition input.c:11
proto bool GetGamepadThumbDirection(GamepadButton thumbButton, out float angle, out float value)
return true if was deflected button.
proto native bool IsEnabledMouseAndKeyboardEvenOnServer()
Definition EnMath.c:7
map: item x vector(index, width, height)
Definition EnWidgets.c:538
protected LayoutHolder m_Parent
Definition LayoutHolder.c:6
void OnWidgetScriptInit(Widget w)
Definition SizeToChild.c:14
override void Stop()
proto native UAInput InputP()
proto native UAInput GetInputByID(int iID)
returns list of all bindable (i.e. visible) inputs from the active group ('core' by default)
proto native UAIDWrapper GetPersistentWrapper()
proto native bool LocalPress()
static proto native float Distance(vector v1, vector v2)
Returns the distance between tips of two 3D vectors.
proto native CGame GetGame()
proto volatile int CallFunction(Class inst, string function, out void returnVal, void parm)
GamepadButton
Definition EnSystem.c:341
proto native vector Vector(float x, float y, float z)
Vector constructor from components.
static proto float Cos(float angle)
Returns cosinus of angle in radians.
static proto float Atan2(float y, float x)
Returns angle in radians from tangent.
static const float PI
Definition EnMath.c:12
static proto float Min(float x, float y)
Returns smaller of two given values.
static proto float AbsFloat(float f)
Returns absolute value.
static const float RAD2DEG
Definition EnMath.c:16
static proto float Sin(float angle)
Returns sinus of angle in radians.
MouseState
Definition EnSystem.c:311
WidgetFlags
Definition EnWidgets.c:57
proto native external Widget CreateWidgets(string layout, Widget parentWidget=NULL, bool immedUpdate=true)
Create widgets from *.layout file.
bool OnMouseButtonUp(Widget w, int x, int y, int button)
int ARGB(int a, int r, int g, int b)
Definition proto.c:322