Dayz Explorer 1.28.160049
Loading...
Searching...
No Matches
radialmenu.c
Go to the documentation of this file.
6
7class RadialMenu : ScriptedWidgetEventHandler
8{
9 protected Widget m_Parent;
10 protected Widget m_ItemCardsContainer;
11 protected Widget m_RadialSelector;
12 protected ImageWidget m_RadialSelectorImage;
13 protected ImageWidget m_RadialSelectorPointerImage;
16 protected Widget m_SelectedObject;
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
31 private UAIDWrapper m_SelectInputWrapper;
32 private UAIDWrapper m_BackInputWrapper;
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
55 ref static RadialMenu m_Instance;
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();
91 if (inp && inp.IsEnabledMouseAndKeyboardEvenOnServer())
92 {
94 }
95 else
96 {
98 }
99#endif
100#ifdef PLATFORM_WINDOWS
102#endif
103
104 m_SelectInputWrapper = GetUApi().GetInputByID(UAUISelect).GetPersistentWrapper();
105 m_BackInputWrapper= GetUApi().GetInputByID(UAUIBack).GetPersistentWrapper();
106
107 //radial cards
109 m_UpdateTimer = new Timer();
110 m_UpdateTimer.Run(0.01, this, "Update", NULL, true);
111 }
112
114 {
115 }
116
117 static RadialMenu GetInstance()
118 {
119 return m_Instance;
120 }
121
122 //Set handler
123 void OnWidgetScriptInit(Widget w)
124 {
125 m_ItemCardsContainer = w.FindAnyWidget(RADIAL_ITEM_CARD_CONTAINER);
126 m_RadialSelector = w.FindAnyWidget(RADIAL_SELECTOR);
127 m_RadialSelectorImage = ImageWidget.Cast(m_RadialSelector.FindAnyWidget(RADIAL_SELECTOR_IMAGE));
128 m_RadialSelectorPointerImage = ImageWidget.Cast(m_RadialSelector.FindAnyWidget(RADIAL_SELECTOR_POINTER));
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 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 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 {
522 m_UpdateTimer.Stop();
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
547 GetGame().GameScript.CallFunction(m_RegisteredClass, "OnMouseDeselect", NULL, m_SelectedObject);
548 m_SelectedObject = NULL;
549 //hide selector
551 }
552 else
553 {
554 //Deselect
555 GetGame().GameScript.CallFunction(m_RegisteredClass, "OnMouseDeselect", NULL, m_SelectedObject);
556
557 //Select
559 GetGame().GameScript.CallFunction(m_RegisteredClass, "OnMouseSelect", NULL, m_SelectedObject);
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
573 Widget w_selected = GetObjectByDegAngle(m_ControllerAngle);
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)
656 if (m_SelectInputWrapper.InputP().LocalPress())
657 {
658 GetGame().GameScript.CallFunction(m_RegisteredClass, "OnControllerPressSelect", NULL, m_SelectedObject);
659 }
660
661 //Back (B,circle)
662 if (m_BackInputWrapper.InputP().LocalPress())
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
673 GetGame().GameScript.CallFunction(m_RegisteredClass, "OnMousePressLeft", NULL, m_SelectedObject);
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}
proto int GetTime()
returns mission time in milliseconds
Definition input.c:11
Definition enmath.c:7
proto native CGame GetGame()
GamepadButton
Definition ensystem.c:341
proto native vector Vector(float x, float y, float z)
Vector constructor from components.
MouseState
Definition ensystem.c:311
proto void GetMousePos(out int x, out int y)
WidgetFlags
Definition enwidgets.c:58
Icon x
Icon y
class OptionSelectorMultistate extends OptionSelector class_name
int ARGB(int a, int r, int g, int b)
Definition proto.c:322
ref map< Widget, float > m_RadialItemCards
Definition radialmenu.c:17
float m_AngleRadOffset
Definition radialmenu.c:19
float GetMousePointerAngle()
Definition radialmenu.c:464
bool IsUsingController()
Definition radialmenu.c:158
float m_RadiusOffset
Definition radialmenu.c:48
void RegisterClass(UIScriptedMenu class_name)
Definition radialmenu.c:181
bool m_WidgetInitialized
Definition radialmenu.c:44
const float CONTROLLER_DESELECT_TIMEOUT
Definition radialmenu.c:39
void HideRadialSelector()
Definition radialmenu.c:346
Widget m_SelectedObject
Definition radialmenu.c:16
Widget m_ItemCardsContainer
Definition radialmenu.c:10
void UpdataControllerInput()
Definition radialmenu.c:640
ImageWidget m_RadialSelectorImage
Definition radialmenu.c:12
void SetExecuteDistOffset(float execute_dist_offset)
Definition radialmenu.c:196
string m_DelimiterLayout
Definition radialmenu.c:52
float m_ItemCardRadiusOffset
Definition radialmenu.c:51
RadialMenuControlType m_ControlType
Definition radialmenu.c:30
bool m_IsControllerTimoutEnabled
Definition radialmenu.c:38
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
void GetParentCenter(out float center_x, out float center_y)
Definition radialmenu.c:386
void ShowRadialSelector(Widget selected_item)
Definition radialmenu.c:315
float GetMouseDistance()
Definition radialmenu.c:482
Widget m_RadialSelector
Definition radialmenu.c:11
ref UIScriptedMenu m_RegisteredClass
Definition radialmenu.c:54
RadialMenuControlType
Definition radialmenu.c:2
@ CONTROLLER
Definition radialmenu.c:4
@ MOUSE
Definition radialmenu.c:3
float m_OffsetFromTop
Definition radialmenu.c:50
const float MOUSE_SAFE_ZONE_RADIUS
Definition radialmenu.c:45
ImageWidget m_RadialSelectorPointerImage
Definition radialmenu.c:13
int m_RadialSelectorDisabledColor
Definition radialmenu.c:15
float m_ControllerTilt
Definition radialmenu.c:34
int GetItemCardsCount()
Definition radialmenu.c:357
bool IsUsingMouse()
Definition radialmenu.c:148
void SetControlType(RadialMenuControlType type)
Definition radialmenu.c:139
float GetRadius()
Definition radialmenu.c:372
const float CONTROLLER_TILT_TRESHOLD_SELECT
Definition radialmenu.c:40
bool IsWidgetInitialized()
Definition radialmenu.c:173
const float CONTROLLER_TILT_TRESHOLD_EXECUTE
Definition radialmenu.c:41
int last_time
Definition radialmenu.c:517
float m_ControllerAngle
Definition radialmenu.c:33
int m_RadialSelectorOriginalColor
Definition radialmenu.c:14
void SetWidgetProperties(string delimiter_layout)
Definition radialmenu.c:219
int m_ControllerTimout
Definition radialmenu.c:37
void ActivateControllerTimeout(bool state)
Definition radialmenu.c:214
void SetItemCardRadiusOffset(float item_card_radius_offset)
Definition radialmenu.c:208
float GetParentMinSize()
Definition radialmenu.c:403
void ~RadialMenu()
Definition radialmenu.c:113
override bool OnMouseButtonUp(Widget w, int x, int y, int button)
Definition radialmenu.c:668
void RadialMenu()
Definition radialmenu.c:84
float GetAngleInDegrees(float rad_angle)
Definition radialmenu.c:498
Widget GetObjectByDegAngle(float deg_angle)
Definition radialmenu.c:421
ref Timer m_UpdateTimer
Definition radialmenu.c:20
float m_ExecuteDistanceOffset
Definition radialmenu.c:49
Widget m_Parent
Definition sizetochild.c:92
void Refresh()
void OnWidgetScriptInit(Widget w)
Definition sizetochild.c:94
proto native UAInputAPI GetUApi()