Arma Reforger Explorer 1.7.0.54
Arma Reforger Code Explorer by Zeroy - Thanks to MisterOutofTime
Loading...
Searching...
No Matches
SCR_MapCursorModule.c
Go to the documentation of this file.
1//------------------------------------------------------------------------------------------------
4{
5 static bool isGamepad; // is using gamepad
6 bool isFixedMode = true; // determines whether cursor is fixed to the screen center
7
8 static int x, y; // by default, all screen position are DPI Unscaled, when scaled, these will return a range from 0 to window resolution in pixels
9 static int startPos[2]; // state start pos pan
10 static int startPosMultiSel[2]; // state start pos multi select
11 int lastX, lastY; // last pos of x & y
12 EMapCursorEdgePos edgeFlags; // cursor screen edge flags
13
14 static WorkspaceWidget m_WorkspaceWidget;
15
16 //------------------------------------------------------------------------------------------------
18 static int Scale(int pos)
19 {
20 if (!m_WorkspaceWidget)
21 m_WorkspaceWidget = GetGame().GetWorkspace();
22
23 return m_WorkspaceWidget.DPIScale(pos);
24 }
25
26 //------------------------------------------------------------------------------------------------
28 {
29 x = 0;
30 y = 0;
31 startPos = {0, 0};
32 startPosMultiSel = {0, 0};
33 }
34}
35
36//------------------------------------------------------------------------------------------------
39class SCR_MapCursorModule : SCR_MapModuleBase
40{
41 [Attribute(defvalue: "1.5", uiwidget: UIWidgets.EditBox, desc: "Panning: multiplier of keyboard panning speed", params: "0.1 10")]
42 protected float m_fPanKBMMultiplier;
43
44 [Attribute(defvalue: "1.5", uiwidget: UIWidgets.EditBox, desc: "Panning: multiplier of thubmstick panning speed", params: "0.1 10")]
45 protected float m_fPanStickMultiplier;
46
47 [Attribute(defvalue: "1", uiwidget: UIWidgets.CheckBox, desc: "Enables panning by moving cursor to the screen edges")]
48 protected bool m_bEnableCursorEdgePan;
49
50 [Attribute(defvalue: "1", uiwidget: UIWidgets.CheckBox, desc: "Center KBM cursor on map open")]
51 protected bool m_bIsCursorCenteredOnOpen;
52
53 [Attribute(defvalue: "0.1", uiwidget: UIWidgets.EditBox, desc: "Time it takes to perform zooming of a single step", params: "0.01 10")]
54 protected float m_fZoomAnimTime;
55
56 [Attribute(defvalue: "2", uiwidget: UIWidgets.EditBox, desc: "Each zoom step is increased/decreased by the currentZoom/thisVariable, lower number means faster steps", params: "0.1 10")]
57 protected float m_fZoomStrength;
58
59 [Attribute(defvalue: "100", uiwidget: UIWidgets.EditBox, desc: "This is multiplier of average frame time resulting in a rotation degree value", params: "100 1000")]
60 protected int m_iRotateSpeedMouse;
61
62 [Attribute(defvalue: "1", uiwidget: UIWidgets.CheckBox, desc: "Enables custom map crosshair visuals")]
63 protected bool m_bEnableMapCrosshairVisuals;
64
65 [Attribute(defvalue: "1", uiwidget: UIWidgets.CheckBox, desc: "Enables crosshair grid coordinate display")]
66 protected bool m_bEnableCrosshairCoords;
67
68 [Attribute(defvalue: "0.01", uiwidget: UIWidgets.EditBox, desc: "How precise grid display should be by multiplying current grid by this value and discarding everything that will be after the comma", params: "0.0001 1")]
69 protected float m_fGridPrecision;
70
71 [Attribute(defvalue: "1", uiwidget: UIWidgets.CheckBox, desc: "Enables crosshair height above sea level display")]
72 protected bool m_bEnableCrosshairHeightASL;
73
74 [Attribute(defvalue: "5", uiwidget: UIWidgets.EditBox, desc: "How accurate should be the display of the height", params: "1 1000 1")]
75 protected int m_iHeightPrecision;
76
77 [Attribute("0 0 0 1", UIWidgets.ColorPicker, desc: "Cursor grid/guide lines color")]
78 protected ref Color m_GuidelineColor;
79
80 [Attribute("", UIWidgets.Object, "Cursor state configuration")]
81 protected ref array<ref SCR_CursorVisualState> m_aCursorStatesConfig;
82
83 protected ref map<EMapCursorState, SCR_CursorVisualState> m_aCursorStatesMap = new map<EMapCursorState, SCR_CursorVisualState>; // used to quickly fetch a desired cursor state from config
84
85 //static
86 protected static bool m_bRecentlyTraced; // recently performed widget trace
87 protected static ref array<Widget> s_aTracedWidgets = {};
88
89 // const
90 protected const int MAX_GRID_COORD = 1000;
91 protected const int CURSOR_CAPTURE_OFFSET = 10; // hardcoded(code) screen edges in pixels for cursor capture
92 protected const int GUILDING_LINE_WIDTH = 16;
93 protected const float PAN_DEFAULT_COUNTDOWN = 0.1;
94 protected const float SINGLE_SELECTION_RANGE = 50.0; // range in world pos
95 protected const float CIRCLE_SELECTION_RANGE = 500.0; // range in world pos
96 protected const float FREE_CURSOR_RESET = 3.0; // seconds, time before free cursor resets to locked mode on controller
97 protected static const LocalizedString TEXT_METERS = "#AR-ValueUnit_Short_Meters";
98 protected static const LocalizedString TEXT_GRID = "%1 %2";
99
100 static const EMapCursorState CUSTOM_CURSOR_LOCKED = EMapCursorState.CS_DISABLE;
101 static const EMapCursorState STATE_PAN_RESTRICTED = EMapCursorState.CS_DRAG | EMapCursorState.CS_MODIFIER | EMapCursorState.CS_CONTEXTUAL_MENU | EMapCursorState.CS_DIALOG;
102 static const EMapCursorState STATE_ZOOM_RESTRICTED = EMapCursorState.CS_DRAG | EMapCursorState.CS_MODIFIER | EMapCursorState.CS_CONTEXTUAL_MENU;
103 static const EMapCursorState STATE_HOVER_RESTRICTED = EMapCursorState.CS_PAN | EMapCursorState.CS_ZOOM | EMapCursorState.CS_MULTI_SELECTION
104 | EMapCursorState.CS_DRAG | EMapCursorState.CS_DRAW | EMapCursorState.CS_CONTEXTUAL_MENU;
105 static const EMapCursorState STATE_SELECT_RESTRICTED = EMapCursorState.CS_MULTI_SELECTION | EMapCursorState.CS_CONTEXTUAL_MENU | EMapCursorState.CS_DRAG | EMapCursorState.CS_DRAW;
106 static const EMapCursorState STATE_MULTISELECT_RESTRICTED = EMapCursorState.CS_DRAG | EMapCursorState.CS_DRAW | EMapCursorState.CS_CONTEXTUAL_MENU | EMapCursorState.CS_MODIFIER;
107 static const EMapCursorState STATE_DRAG_RESTRICTED = EMapCursorState.CS_CONTEXTUAL_MENU | EMapCursorState.CS_MULTI_SELECTION | EMapCursorState.CS_ROTATE;
108 static const EMapCursorState STATE_ROTATE_RESTRICTED = EMapCursorState.CS_PAN | EMapCursorState.CS_ZOOM | EMapCursorState.CS_CONTEXTUAL_MENU;
109 static const EMapCursorState STATE_DRAW_RESTRICTED = EMapCursorState.CS_PAN | EMapCursorState.CS_ZOOM | EMapCursorState.CS_CONTEXTUAL_MENU | EMapCursorState.CS_DIALOG;
110 static const EMapCursorState STATE_SUBMENU_RESTRICTED = EMapCursorState.CS_CONTEXTUAL_MENU | EMapCursorState.CS_DIALOG;
111 static const EMapCursorState STATE_CTXMENU_RESTRICTED = EMapCursorState.CS_DRAG | EMapCursorState.CS_DRAW | EMapCursorState.CS_ROTATE;
112 static const EMapCursorState STATE_RESET_RESTRICTED = EMapCursorState.CS_DRAG | EMapCursorState.CS_DRAW | EMapCursorState.CS_ROTATE;
113 static const EMapCursorState STATE_POPUP_RESTRICTED = EMapCursorState.CS_PAN | EMapCursorState.CS_DRAW | EMapCursorState.CS_ROTATE | EMapCursorState.CS_COMMAND_NEGATIVE | EMapCursorState.CS_COMMAND_POSITIVE;
114
115 // timers
116 protected float m_fPanCountdown; // used to stop panning cursor state and refresh start position for next drag panning
117 protected float m_fModifActionDelay; // delay between modifier action activation
118 protected float m_fZoomHoldTime; // zoom hold time for adjusting speed of zoom
119 protected float m_fHoverTime; // hover activation
120 protected float m_fFreeCursorTime; // free cursor deactivation
121 protected float m_fSelectHoldTime; // determines activation of multiselect, which is not using input filters so it doesnt create initial click pos delay
122
123 // enums
124 EMapCursorSelectType m_eMultiSelType; // multiselect type
125 protected EMapCursorState m_CursorState = EMapCursorState.CS_DEFAULT; // keeps current cursor state
126
127 protected bool m_bIsInit; // is module initiated
128 protected bool m_bIsDisabled; // temporary module disable
129 protected bool m_bIsDraggingAvailable;
130 protected bool m_bIsSelectionAvailable;
131 protected bool m_bIsModifierActive;
132 protected bool m_bIsJournalActive;
133 protected int m_iRotationDirVal;
134 protected float m_fZoomMultiplierWheel = 1;
135 protected InputManager m_InputManager;
136 protected ref SCR_MapCursorInfo m_CursorInfo;
137 protected ref SCR_CursorCustom m_CustomCursor;
138 protected CanvasWidget m_MapWidget;
139 protected SCR_MapSelectionModule m_SelectionModule;
140
141 // positioning & sizing
142 protected Widget m_wCrossGrid; // cross grid root
143 protected ImageWidget m_wCrossLTop; // top left fill image, width and height determined by the cursor pos
144 protected ImageWidget m_wCrossRTop; // top right fill image, width by (screen reso - cursor pos), height determined by cursos pos
145 protected ImageWidget m_wCrossLBot; // bot left fill image, width set by top left fill, height by (screen reso - cursor pos)
146 protected ImageWidget m_wGLLeft; // guiding line sizing
147 protected ImageWidget m_wGLTop; // guiding line sizing
148 protected Widget m_wCrossMCenter; // used for centering
149
150 // Rest of guide lines for coloring
151 protected ImageWidget m_wGLRight;
152 protected ImageWidget m_wGLBot;
153 protected ImageWidget m_wGLFadeTop;
154 protected ImageWidget m_wGLFadeLeft;
155 protected ImageWidget m_wGLFadeRight;
156 protected ImageWidget m_wGLFadeBot;
157 protected TextWidget m_wCoordText;
158 protected TextWidget m_wHeightASLText;
159
160 //------------------------------------------------------------------------------------------------
161 // GETTERS / SETTERS
162 //------------------------------------------------------------------------------------------------
164 SCR_MapCursorInfo GetCursorInfo() { return m_CursorInfo; }
165
166 //------------------------------------------------------------------------------------------------
168 EMapCursorState GetCursorState() { return m_CursorState; }
169
170 //------------------------------------------------------------------------------------------------
172 static array<Widget> GetMapWidgetsUnderCursor()
173 {
174 if (!SCR_MapEntity.GetMapInstance().IsOpen())
175 {
176 s_aTracedWidgets.Clear();
177 return s_aTracedWidgets;
178 }
179
180 if (!m_bRecentlyTraced)
181 TraceMapWidgets();
182
183 return s_aTracedWidgets;
184 }
185
186 //------------------------------------------------------------------------------------------------
189 protected void SetCursorState(EMapCursorState state)
190 {
191 if (!m_bIsInit) // some map components may call this when the module already disabled map cursor
192 return;
193
194 m_CursorState |= state;
195 SetCursorType(m_CursorState);
196 }
197
198 //------------------------------------------------------------------------------------------------
201 protected void UnsetCursorState(EMapCursorState state)
202 {
203 m_CursorState &= ~state;
204 SetCursorType(m_CursorState);
205 }
206
207 //------------------------------------------------------------------------------------------------
209 protected void SetCursorType(EMapCursorState type)
210 {
211 if (!m_bEnableMapCrosshairVisuals)
212 return;
213
214 SCR_CursorVisualState cursorState = GetCursorStateCfg();
215
216 if (type == EMapCursorState.CS_DISABLE || m_bIsDisabled)
217 m_CustomCursor.SetCursorVisual(null);
218 else
219 m_CustomCursor.SetCursorVisual(cursorState);
220
221 SetCrosshairGridVisible(!cursorState.m_DisableCursorLines);
222 }
223
224 //------------------------------------------------------------------------------------------------
226 protected void SetCrosshairGridVisible(bool state)
227 {
228 if (!m_wCrossGrid || !m_bEnableMapCrosshairVisuals)
229 return;
230
231 m_wCrossGrid.SetVisible(state);
232 }
233
234 //------------------------------------------------------------------------------------------------
236 protected void OnInputDeviceIsGamepad(bool isGamepad)
237 {
238 m_CursorInfo.isGamepad = isGamepad;
239 if (m_CursorInfo.isGamepad)
240 ForceCenterCursor();
241 else if (m_fFreeCursorTime != 0) // if scheme switched during fade
242 m_CustomCursor.SetOpacity(1);
243 }
244
245 //------------------------------------------------------------------------------------------------
247 void SetWheelZoomMultiplier(float value)
248 {
249 m_fZoomMultiplierWheel = value;
250 }
251
252 //------------------------------------------------------------------------------------------------
255 void ForceCenterCursor()
256 {
257 float screenX, screenY;
258 m_MapWidget.GetScreenSize(screenX, screenY);
259 m_InputManager.SetCursorPosition(screenX * 0.5, screenY * 0.5);
260
261 WorkspaceWidget workspace = GetGame().GetWorkspace();
262 m_CursorInfo.x = workspace.DPIUnscale(screenX * 0.5);
263 m_CursorInfo.y = workspace.DPIUnscale(screenY * 0.5);
264
265 if (!m_CursorInfo.isFixedMode)
266 m_fFreeCursorTime = FREE_CURSOR_RESET;
267 }
268
269 //------------------------------------------------------------------------------------------------
270 // CURSOR STATE HANDLERS
271 //------------------------------------------------------------------------------------------------
273 protected void HandleMove()
274 {
275 //begin move
276 if (m_CursorInfo.lastX != m_CursorInfo.x || m_CursorInfo.lastY != m_CursorInfo.y)
277 {
278 WorkspaceWidget workspace = GetGame().GetWorkspace();
279 if (m_CursorInfo.isGamepad && workspace)
280 m_InputManager.SetCursorPosition(workspace.DPIScale(m_CursorInfo.x), workspace.DPIScale(m_CursorInfo.y));
281
282
283 if (~m_CursorState & EMapCursorState.CS_MOVE)
284 SetCursorState(EMapCursorState.CS_MOVE);
285 }
286 //end move
287 else if (m_CursorState & EMapCursorState.CS_MOVE)
288 UnsetCursorState(EMapCursorState.CS_MOVE);
289 }
290
291 //------------------------------------------------------------------------------------------------
293 protected void HandlePan(float timeSlice)
294 {
295 // pan disabled
296 if (m_CursorState & STATE_PAN_RESTRICTED)
297 {
298 if (m_CursorState & EMapCursorState.CS_PAN)
299 m_fPanCountdown = 0;
300 else
301 return;
302 }
303
304 // Start panning if cursor is on the screen edges
305 if (m_CursorInfo.edgeFlags > 0 && (m_CursorState & EMapCursorState.CS_PAN) == 0) // dont allow edge panning while panning using another method
306 {
307 if (m_fPanCountdown == 0)
308 m_fPanCountdown = PAN_DEFAULT_COUNTDOWN;
309
310 float frameTime = System.GetFrameTimeS();
311 int px = (int)(frameTime * 1000) * m_fPanKBMMultiplier;
312
313 if (m_CursorInfo.edgeFlags & EMapCursorEdgePos.LEFT)
314 m_MapEntity.Pan(EMapPanMode.HORIZONTAL, px);
315 else if (m_CursorInfo.edgeFlags & EMapCursorEdgePos.RIGHT)
316 m_MapEntity.Pan(EMapPanMode.HORIZONTAL, -px);
317
318 if (m_CursorInfo.edgeFlags & EMapCursorEdgePos.TOP)
319 m_MapEntity.Pan(EMapPanMode.VERTICAL, px);
320 else if (m_CursorInfo.edgeFlags & EMapCursorEdgePos.BOTTOM)
321 m_MapEntity.Pan(EMapPanMode.VERTICAL, -px);
322 }
323
324 // stop pan state
325 if (m_fPanCountdown <= 0)
326 {
327 if (m_CursorState & EMapCursorState.CS_PAN)
328 {
329 UnsetCursorState(EMapCursorState.CS_PAN);
330 m_CursorInfo.startPos = {0, 0};
331 }
332
333 return;
334 }
335 // begin pan state
336 if (~m_CursorState & EMapCursorState.CS_PAN)
337 SetCursorState(EMapCursorState.CS_PAN);
338
339 m_fPanCountdown -= timeSlice;
340 }
341
342 //------------------------------------------------------------------------------------------------
344 protected void HandleZoom()
345 {
346 // stop zoom state
347 if (!m_MapEntity.IsZooming())
348 {
349 if (m_CursorState & EMapCursorState.CS_ZOOM)
350 {
351 UnsetCursorState(EMapCursorState.CS_ZOOM);
352 }
353
354 return;
355 }
356
358 if (m_CursorState & STATE_ZOOM_RESTRICTED)
359 return;
360
361 // begin zoom state
362 if (~m_CursorState & EMapCursorState.CS_ZOOM)
363 {
364 SetCursorState(EMapCursorState.CS_ZOOM);
365 }
366 }
367
368 //------------------------------------------------------------------------------------------------
370 protected void HandleHover(float timeSlice)
371 {
372 // begin hover
373 if (m_CursorState == EMapCursorState.CS_DEFAULT)
374 {
375 m_fHoverTime += timeSlice;
376
377 if (m_fHoverTime >= 0.25)
378 {
379 float worldX, worldY;
380 m_MapEntity.ScreenToWorldNoFlip(m_CursorInfo.Scale(m_CursorInfo.x), m_CursorInfo.Scale(m_CursorInfo.y), worldX, worldY);
381 vector curPos = Vector(worldX, 0, worldY);
382
383 MapItem closeItem = m_MapEntity.GetClose(curPos, SINGLE_SELECTION_RANGE / m_MapEntity.GetCurrentZoom());
384 if (closeItem)
385 {
386 SetCursorState(EMapCursorState.CS_HOVER);
387 m_MapEntity.HoverItem(closeItem);
388 }
389
390 return;
391 }
392 }
393 // end hover
394 else if (m_CursorState & EMapCursorState.CS_HOVER)
395 {
396 float worldX, worldY;
397 m_MapEntity.ScreenToWorldNoFlip(m_CursorInfo.Scale(m_CursorInfo.x), m_CursorInfo.Scale(m_CursorInfo.y), worldX, worldY);
398 vector curPos = Vector(worldX, 0, worldY);
399 MapItem closeItem = m_MapEntity.GetClose(curPos, SINGLE_SELECTION_RANGE / m_MapEntity.GetCurrentZoom());
400
401 if ((m_CursorState & STATE_HOVER_RESTRICTED)
402 || !closeItem
403 || (closeItem && closeItem != m_MapEntity.GetHoveredItem())
404 )
405 {
407 m_fHoverTime = 0;
408 UnsetCursorState(EMapCursorState.CS_HOVER);
409 }
410 }
411 }
412
413 //------------------------------------------------------------------------------------------------
415 protected void HandleSelect()
416 {
418 if (m_CursorState & STATE_SELECT_RESTRICTED)
419 return;
420
421 vector vScreenPos = Vector(m_CursorInfo.Scale(m_CursorInfo.x), 0, m_CursorInfo.Scale(m_CursorInfo.y));
422 m_MapEntity.InvokeOnSelect(vScreenPos);
423
424 // start select
425 if (~m_CursorState & EMapCursorState.CS_SELECT)
426 {
427 SetCursorState(EMapCursorState.CS_SELECT);
428
429 float worldX, worldY;
430 m_MapEntity.ScreenToWorldNoFlip(m_CursorInfo.Scale(m_CursorInfo.x), m_CursorInfo.Scale(m_CursorInfo.y), worldX, worldY);
431 vector curPos = Vector(worldX, 0, worldY);
432
433 MapItem selected = m_MapEntity.GetClose(curPos, SINGLE_SELECTION_RANGE / m_MapEntity.GetCurrentZoom());
434 autoptr array<MapItem> selectedItems = new array<MapItem>;
435 m_MapEntity.GetSelected(selectedItems);
436
437 // only select if different item or multiple selected
438 if (selected && (selectedItems.Count() != 1 || selectedItems[0] != selected))
439 {
441 m_MapEntity.SelectItem(selected);
442 }
443 else
445
446 }
447
448 // Selection state end instantly after a click
449 UnsetCursorState(EMapCursorState.CS_SELECT);
450 }
451
452 //------------------------------------------------------------------------------------------------
454 protected void HandleMultiSelect(bool activate)
455 {
456 // multiselect state end or disabled
457 if ((m_CursorState & STATE_MULTISELECT_RESTRICTED) != 0 || !activate)
458 {
459 // never started
460 if (~m_CursorState & EMapCursorState.CS_MULTI_SELECTION)
461 return;
462
463 // select items
465 autoptr array<MapItem> selectedItems = new array<MapItem>;
466 GetCursorSelection(selectedItems);
467 int count = selectedItems.Count();
468
469 for (int i = 0; i < count; i++)
470 {
471 m_MapEntity.SelectItem(selectedItems[i]);
472 }
473
474 // multiselect end
475 UnsetCursorState(EMapCursorState.CS_MULTI_SELECTION);
476 m_CursorInfo.startPosMultiSel = {0, 0};
477 }
478 else if (activate)
479 {
480 // multiselect begin
481 if (~m_CursorState & EMapCursorState.CS_MULTI_SELECTION)
482 SetCursorState(EMapCursorState.CS_MULTI_SELECTION);
483
484 // highlight for items within selection
485 m_MapEntity.ResetHighlighted();
486 autoptr array<MapItem> selectedItems = new array<MapItem>;
487 GetCursorSelection(selectedItems);
488 int count = selectedItems.Count();
489
490 for (int i = 0; i < count; i++)
491 {
492 selectedItems[i].SetHighlighted(true);
493 }
494 }
495 }
496
497 //------------------------------------------------------------------------------------------------
500 protected void HandleDrag(bool startDrag)
501 {
502 // begin drag
503 if (startDrag)
504 {
505 // disable drag state
506 if (m_CursorState & STATE_DRAG_RESTRICTED)
507 return;
508
509 if (~m_CursorState & EMapCursorState.CS_DRAG)
510 {
511 if (SCR_MapToolInteractionUI.StartDrag())
512 {
513 SetCursorState(EMapCursorState.CS_DRAG);
514 }
515 }
516 }
517 // end drag
518 else
519 {
520 if (m_CursorState & EMapCursorState.CS_DRAG)
521 {
522 UnsetCursorState(EMapCursorState.CS_DRAG);
523 SCR_MapToolInteractionUI.EndDrag();
524 }
525 }
526 }
527
528 //------------------------------------------------------------------------------------------------
530 protected void HandleRotateTool(bool startRotate)
531 {
532 if (m_CursorState & STATE_ROTATE_RESTRICTED)
533 return;
534
535 if (startRotate)
536 {
537 if (~m_CursorState & EMapCursorState.CS_ROTATE)
538 {
539 if (m_CursorState & EMapCursorState.CS_DRAG)
540 HandleDrag(false);
541
542 if (SCR_MapToolInteractionUI.StartRotate())
543 SetCursorState(EMapCursorState.CS_ROTATE);
544 }
545 }
546 else
547 {
548 if (m_CursorState & EMapCursorState.CS_ROTATE)
549 {
550 UnsetCursorState(EMapCursorState.CS_ROTATE);
551 SCR_MapToolInteractionUI.EndRotate();
552 }
553 }
554 }
555
556 //------------------------------------------------------------------------------------------------
558 bool HandleDraw(bool active)
559 {
560 // begin draw state
561 if (active && (m_CursorState & STATE_DRAW_RESTRICTED) == 0)
562 {
563 if (~m_CursorState & EMapCursorState.CS_DRAW)
564 {
565 SetCursorState(EMapCursorState.CS_DRAW);
566 return true;
567 }
568 }
569 // end draw state
570 else if (m_CursorState & EMapCursorState.CS_DRAW)
571 {
572 UnsetCursorState(EMapCursorState.CS_DRAW);
573 }
574
575 return false;
576 }
577
578 //------------------------------------------------------------------------------------------------
580 bool HandleSubMenu(bool active)
581 {
582 // begin sub menu state
583 if (active && (m_CursorState & STATE_SUBMENU_RESTRICTED) == 0)
584 {
585 if (~m_CursorState & EMapCursorState.CS_SUB_MENU)
586 {
587 SetCursorState(EMapCursorState.CS_SUB_MENU);
588 return true;
589 }
590 }
591 // end sub menu state
592 else if (m_CursorState & EMapCursorState.CS_SUB_MENU)
593 {
594 UnsetCursorState(EMapCursorState.CS_SUB_MENU);
595 }
596
597 return false;
598 }
599
600 //------------------------------------------------------------------------------------------------
602 bool HandleDialog(bool active)
603 {
604 if (active)
605 {
606 if (~m_CursorState & EMapCursorState.CS_DIALOG)
607 {
608 if (m_CursorInfo.isGamepad)
609 ForceCenterCursor();
610
611 SetCursorState(EMapCursorState.CS_DIALOG);
612
613 return true;
614 }
615 }
616 else if (m_CursorState & EMapCursorState.CS_DIALOG)
617 {
618 UnsetCursorState(EMapCursorState.CS_DIALOG);
619
620 if (m_CursorInfo.isGamepad)
621 ForceCenterCursor();
622 }
623
624 return false;
625 }
626
627 //------------------------------------------------------------------------------------------------
628 void ToggleFastTravelDestinationSelection(bool enable)
629 {
630 if (enable)
631 SetCursorState(EMapCursorState.CS_ASSIGN_WP);
632 else
633 UnsetCursorState(EMapCursorState.CS_ASSIGN_WP);
634 }
635
636 //------------------------------------------------------------------------------------------------
639 void ToggleMapCommandPositiveCursor(bool enable)
640 {
641 if (enable)
642 SetCursorState(EMapCursorState.CS_COMMAND_POSITIVE);
643 else
644 UnsetCursorState(EMapCursorState.CS_COMMAND_POSITIVE);
645 }
646
647 //------------------------------------------------------------------------------------------------
650 void ToggleMapCommandNegativeCursor(bool enable)
651 {
652 if (enable)
653 SetCursorState(EMapCursorState.CS_COMMAND_NEGATIVE);
654 else
655 UnsetCursorState(EMapCursorState.CS_COMMAND_NEGATIVE);
656 }
657
658 //------------------------------------------------------------------------------------------------
659 void ToggleLocationSelection(bool enable)
660 {
661 if (enable)
662 SetCursorState(EMapCursorState.CS_ASSIGN_WP);
663 else
664 UnsetCursorState(EMapCursorState.CS_ASSIGN_WP);
665 }
666
667 //------------------------------------------------------------------------------------------------
671 bool HandleContextualMenu(bool doClose = false)
672 {
674 if ((m_CursorState & STATE_CTXMENU_RESTRICTED) != 0 && !doClose)
675 return false;
676
677 SCR_MapRadialUI radialMenu = SCR_MapRadialUI.Cast(m_MapEntity.GetMapUIComponent(SCR_MapRadialUI));
678 if (!radialMenu)
679 return false;
680
681 if (doClose) // close
682 {
683 if (m_CursorState & EMapCursorState.CS_CONTEXTUAL_MENU)
684 {
685 UnsetCursorState(EMapCursorState.CS_CONTEXTUAL_MENU);
686
687 return false;
688 }
689 }
690 else if (~m_CursorState & EMapCursorState.CS_CONTEXTUAL_MENU) // open
691 {
692 SetCursorState(EMapCursorState.CS_CONTEXTUAL_MENU);
693
694 return true;
695 }
696
697 return false;
698 }
699
700 //------------------------------------------------------------------------------------------------
703 void SetJournalVisibility(bool isOpened)
704 {
705 m_bIsJournalActive = isOpened;
706 }
707
708 //------------------------------------------------------------------------------------------------
709 // SUPPORT METHODS
710 //------------------------------------------------------------------------------------------------
713 protected void GetCursorSelection(out array<MapItem> mapItems)
714 {
716 float startWorldX, startWorldY, worldX, worldY;
717 m_MapEntity.ScreenToWorldNoFlip(m_CursorInfo.Scale(m_CursorInfo.startPosMultiSel[0]), m_CursorInfo.Scale(m_CursorInfo.startPosMultiSel[1]), startWorldX, startWorldY);
718 m_MapEntity.ScreenToWorldNoFlip(m_CursorInfo.Scale(m_CursorInfo.x), m_CursorInfo.Scale(m_CursorInfo.y), worldX, worldY);
719 vector startPos = Vector(startWorldX, 0, startWorldY);
720 vector curPos = Vector(worldX, 0, worldY);
721
723 if (m_eMultiSelType == EMapCursorSelectType.RECTANGLE)
724 m_MapEntity.GetInsideRect(mapItems, startPos, curPos);
725 else if (m_eMultiSelType == EMapCursorSelectType.CIRCLE)
726 {
727 float circleRadius = m_SelectionModule.GetSelCircleSize() / 2; // size is in pixels while we want radius
728 m_MapEntity.GetInsideCircle(mapItems, curPos, circleRadius / m_MapEntity.GetCurrentZoom());
729 }
730 }
731
732 //------------------------------------------------------------------------------------------------
736 protected void GetCursorPosition(out int x, out int y)
737 {
738 WorkspaceWidget workspace = GetGame().GetWorkspace();
739
740 if (!m_MapWidget)
741 m_MapWidget = m_MapEntity.GetMapWidget();
742
743 float screenX, screenY, offX, offY;
744 m_MapWidget.GetScreenSize(screenX, screenY);
745 m_MapWidget.GetScreenPos(offX, offY);
746
747 // Needed for precision sake
748 float fX, fY;
749
750 // gamepad cursor
751 if (m_CursorInfo.isGamepad)
752 {
753 fX = workspace.DPIScale(x);
754 fY = workspace.DPIScale(y);
755 }
756 else
757 {
758 int iX, iY;
759 WidgetManager.GetMousePos(iX, iY);
760 fX = iX;
761 fY = iY;
762 }
763
764 // If the widget is not fullscreen, cursor position needs to be offset to match it
765 fX -= offX;
766 fY -= offY;
767
768 // Screen edge pan
769 EMapEntityMode mode = m_MapEntity.GetMapConfig().MapEntityMode;
770 if (m_bEnableCursorEdgePan)
771 TestEdgePan(fX, fY, screenX, screenY);
772
773 // unscale the result
774 x = workspace.DPIUnscale(fX);
775 y = workspace.DPIUnscale(fY);
776 }
777
778 //------------------------------------------------------------------------------------------------
784 protected void TestEdgePan(inout float x, inout float y, int screenX, int screenY)
785 {
786 float windowWidth, windowHeight;
787 m_MapWidget.GetScreenSize(windowWidth, windowHeight);
788
789 if (x == 0) // hack so the game doesnt autoscroll to top left when cursor is in default pos (f.e. during window unfocus)
790 return;
791
792 if (x <= CURSOR_CAPTURE_OFFSET)
793 m_CursorInfo.edgeFlags |= EMapCursorEdgePos.LEFT;
794 else
795 m_CursorInfo.edgeFlags &= ~EMapCursorEdgePos.LEFT;
796
797 if (y <= CURSOR_CAPTURE_OFFSET)
798 m_CursorInfo.edgeFlags |= EMapCursorEdgePos.TOP;
799 else
800 m_CursorInfo.edgeFlags &= ~EMapCursorEdgePos.TOP;
801
802 if (x >= (int)windowWidth - CURSOR_CAPTURE_OFFSET - 1)
803 m_CursorInfo.edgeFlags |= EMapCursorEdgePos.RIGHT;
804 else
805 m_CursorInfo.edgeFlags &= ~EMapCursorEdgePos.RIGHT;
806
807 if (y >= (int)windowHeight - CURSOR_CAPTURE_OFFSET - 1)
808 m_CursorInfo.edgeFlags |= EMapCursorEdgePos.BOTTOM;
809 else
810 m_CursorInfo.edgeFlags &= ~EMapCursorEdgePos.BOTTOM;
811 }
812
813 //------------------------------------------------------------------------------------------------
814 // INPUTS
815 //------------------------------------------------------------------------------------------------
817 protected void OnInputPanDrag(float value, EActionTrigger reason)
818 {
819 // pan disabled
820 if (m_CursorState & STATE_PAN_RESTRICTED)
821 return;
822
823 m_fPanCountdown = PAN_DEFAULT_COUNTDOWN;
825 }
826
827 //------------------------------------------------------------------------------------------------
829 protected void OnInputPanH(float value, EActionTrigger reason)
830 {
831 CalculatePan(value, EMapPanMode.HORIZONTAL, m_fPanKBMMultiplier); // value determines direction for digital inputs
832 }
833
834 //------------------------------------------------------------------------------------------------
836 protected void OnInputPanV(float value, EActionTrigger reason)
837 {
838 CalculatePan(value, EMapPanMode.VERTICAL, m_fPanKBMMultiplier); // value determines direction for digital inputs
839 }
840
841 //------------------------------------------------------------------------------------------------
843 protected void OnInputPanHGamepad(float value, EActionTrigger reason)
844 {
845 if (value == 0)
846 return;
847
848 CalculatePan(1, EMapPanMode.HORIZONTAL, value * m_fPanStickMultiplier);
849 }
850
851 //------------------------------------------------------------------------------------------------
853 protected void OnInputPanVGamepad(float value, EActionTrigger reason)
854 {
855 if (value == 0)
856 return;
857
858 CalculatePan(1, EMapPanMode.VERTICAL, value * m_fPanStickMultiplier);
859 }
860
861 //------------------------------------------------------------------------------------------------
866 protected void CalculatePan(float direction, EMapPanMode panMode, float multiPlier)
867 {
868 if (m_CursorState & STATE_PAN_RESTRICTED)
869 return;
870
871 m_fPanCountdown = PAN_DEFAULT_COUNTDOWN;
872 int px = (System.GetFrameTimeS() * 1000); // speed of pan based on time elapsed to avoid slowdown during lower fps
873
874 if ((int)direction == 1)
875 px = px * multiPlier;
876 else if ((int)direction == 2)
877 px = -px * multiPlier;
878
879 m_MapEntity.Pan(panMode, px);
880 }
881
882 //------------------------------------------------------------------------------------------------
884 protected void OnInputGamepadCursorH(float value, EActionTrigger reason)
885 {
886 if (!m_CursorInfo.isGamepad)
887 return;
888
889 if (value == 0)
890 return;
891
892 m_fFreeCursorTime = 0;
893 m_CustomCursor.SetOpacity(1);
894 m_CursorInfo.isFixedMode = false;
895
896 float maxX, maxY;
897 WorkspaceWidget workspace = GetGame().GetWorkspace();
898 if (m_wRootWidget && workspace)
899 {
900 m_wRootWidget.GetScreenSize(maxX, maxY);
901 maxX = workspace.DPIUnscale(maxX);
902 maxY = workspace.DPIUnscale(maxY);
903 }
904
905 m_CursorInfo.x = Math.Clamp(m_CursorInfo.x + value * System.GetFrameTimeS() * 1000 * m_fPanStickMultiplier, 1, maxX);
906 }
907
908 //------------------------------------------------------------------------------------------------
910 protected void OnInputGamepadCursorV(float value, EActionTrigger reason)
911 {
912 if (!m_CursorInfo.isGamepad)
913 return;
914
915 if (value == 0)
916 return;
917
918 m_fFreeCursorTime = 0;
919 m_CustomCursor.SetOpacity(1);
920 m_CursorInfo.isFixedMode = false;
921
922 float maxX, maxY;
923 WorkspaceWidget workspace = GetGame().GetWorkspace();
924 if (m_wRootWidget && workspace)
925 {
926 m_wRootWidget.GetScreenSize(maxX, maxY);
927 maxX = workspace.DPIUnscale(maxX);
928 maxY = workspace.DPIUnscale(maxY);
929 }
930
931 m_CursorInfo.y = Math.Clamp(m_CursorInfo.y - value * System.GetFrameTimeS() * 1000 * m_fPanStickMultiplier, 1, maxY);
932 }
933
934 //------------------------------------------------------------------------------------------------
936 protected void OnInputZoomIn(float value, EActionTrigger reason)
937 {
938 if (Math.AbsFloat(value) < 0.001)
939 return;
940
942 if (m_CursorState & STATE_ZOOM_RESTRICTED)
943 return;
944
945 m_fZoomHoldTime += System.GetFrameTimeS();
946 if ((m_CursorState & EMapCursorState.CS_ZOOM) && m_fZoomHoldTime < 0.05) // if pressed, call once every 0.05 second
947 return;
948
949 float zoomPPU = m_MapEntity.GetCurrentZoom();
950 if (value != 0)
951 {
952 float zoomValue = value.Sign() * Math.Min(1, value * value) * zoomPPU / m_fZoomStrength;
953 m_MapEntity.ZoomSmooth(zoomPPU + zoomValue, m_fZoomAnimTime, false);
954 }
955
956 m_fZoomHoldTime = 0;
957 }
958
959 //------------------------------------------------------------------------------------------------
961 protected void OnInputZoomOut(float value, EActionTrigger reason)
962 {
963 if (Math.AbsFloat(value) < 0.001)
964 return;
965
967 if (m_CursorState & STATE_ZOOM_RESTRICTED)
968 return;
969
970 m_fZoomHoldTime += System.GetFrameTimeS();
971 if ((m_CursorState & EMapCursorState.CS_ZOOM) && m_fZoomHoldTime < 0.05) // if pressed, call once every 0.05 second
972 return;
973
974 float zoomPPU = m_MapEntity.GetCurrentZoom();
975 if (value != 0)
976 {
977 float zoomValue = -1 * Math.Min(1, value * value) * zoomPPU / m_fZoomStrength;
978 m_MapEntity.ZoomSmooth(zoomPPU + zoomValue, m_fZoomAnimTime, false);
979 }
980
981 m_fZoomHoldTime = 0;
982 }
983
984
985 //------------------------------------------------------------------------------------------------
987 protected void OnInputZoomWheelUp(float value, EActionTrigger reason)
988 {
990 if (m_bIsJournalActive || m_CursorState & STATE_ZOOM_RESTRICTED)
991 return;
992
993 float targetPPU = m_MapEntity.GetTargetZoomPPU();
994 value = value * m_fZoomMultiplierWheel;
995 m_MapEntity.ZoomSmooth(targetPPU + targetPPU * (value * 0.001), m_fZoomAnimTime, false); // the const here is adjusting the value to match the input with zoom range
996 }
997
998 //------------------------------------------------------------------------------------------------
1000 protected void OnInputZoomWheelDown(float value, EActionTrigger reason)
1001 {
1003 if (m_bIsJournalActive || m_CursorState & STATE_ZOOM_RESTRICTED)
1004 return;
1005
1006 float targetPPU = m_MapEntity.GetTargetZoomPPU();
1007 value = value * m_fZoomMultiplierWheel;
1008 m_MapEntity.ZoomSmooth(targetPPU - targetPPU/ 2 * (value * 0.001), m_fZoomAnimTime, false); // the const here is adjusting the value to match the input with zoom range
1009 }
1010
1011 //------------------------------------------------------------------------------------------------
1013 protected void OnInputDrag(float value, EActionTrigger reason)
1014 {
1015 if (!m_bIsDraggingAvailable)
1016 return;
1017
1018 if (m_CursorState & EMapCursorState.CS_MODIFIER)
1019 return;
1020
1021 if (reason == EActionTrigger.DOWN)
1022 HandleDrag(true);
1023 else
1024 HandleDrag(false);
1025 }
1026
1027 //------------------------------------------------------------------------------------------------
1029 protected void OnInputDragToggle(float value, EActionTrigger reason)
1030 {
1031 if (!m_bIsDraggingAvailable)
1032 return;
1033
1034 if (m_CursorState & EMapCursorState.CS_MODIFIER)
1035 return;
1036
1037 if (~m_CursorState & EMapCursorState.CS_DRAG)
1038 HandleDrag(true);
1039 else
1040 HandleDrag(false);
1041 }
1042
1043 //------------------------------------------------------------------------------------------------
1045 protected void OnInputModifier(float value, EActionTrigger reason)
1046 {
1047 if (reason == EActionTrigger.DOWN)
1048 {
1049 SetCursorState(EMapCursorState.CS_MODIFIER);
1050 if (!SCR_MapToolInteractionUI.s_bIsRotating)
1051 HandleRotateTool(true);
1052 }
1053 else
1054 {
1055 UnsetCursorState(EMapCursorState.CS_MODIFIER);
1056 if (SCR_MapToolInteractionUI.s_bIsRotating)
1057 HandleRotateTool(false);
1058 }
1059 }
1060
1061 //------------------------------------------------------------------------------------------------
1063 protected void OnInputModifClick(float value, EActionTrigger reason)
1064 {
1065 SCR_MapToolInteractionUI.ActivateAction();
1066 }
1067
1068 //------------------------------------------------------------------------------------------------
1070 protected void OnInputMultiSel(float value, EActionTrigger reason)
1071 {
1072 if (reason == EActionTrigger.PRESSED)
1073 {
1074 if (m_fSelectHoldTime == 0) // first call
1075 m_CursorInfo.startPosMultiSel = {m_CursorInfo.x, m_CursorInfo.y};
1076
1077 m_fSelectHoldTime += System.GetFrameTimeS();
1078 if (m_fSelectHoldTime < 0.2)
1079 return;
1080
1081 HandleMultiSelect(true);
1082 m_eMultiSelType = EMapCursorSelectType.RECTANGLE;
1083
1084 }
1085 else
1086 {
1087 HandleMultiSelect(false);
1088 m_fSelectHoldTime = 0;
1089 }
1090 }
1091
1092 //------------------------------------------------------------------------------------------------
1094 protected void OnInputMultiSelGamepad(float value, EActionTrigger reason)
1095 {
1096 if (reason == EActionTrigger.PRESSED)
1097 {
1098 m_CursorInfo.startPosMultiSel = {m_CursorInfo.x, m_CursorInfo.y};
1099 HandleMultiSelect(true);
1100 m_eMultiSelType = EMapCursorSelectType.CIRCLE;
1101 }
1102 else
1103 HandleMultiSelect(false);
1104
1105 }
1106
1107 //------------------------------------------------------------------------------------------------
1109 protected void OnPauseMenuOpened()
1110 {
1111 m_bIsDisabled = true;
1112 m_CursorState = EMapCursorState.CS_DEFAULT;
1113 SetCursorType(EMapCursorState.CS_DISABLE);
1114 }
1115
1116 //------------------------------------------------------------------------------------------------
1118 protected void OnPauseMenuClosed()
1119 {
1120 m_bIsDisabled = false;
1121 SetCursorType(m_CursorState);
1122 }
1123
1124 //------------------------------------------------------------------------------------------------
1127 protected SCR_CursorVisualState GetCursorStateCfg()
1128 {
1129 EMapCursorState state = EMapCursorState.CS_LAST;
1130 EMapCursorState stateMin = EMapCursorState.CS_DEFAULT;
1131 SCR_CursorVisualState cfg;
1132 while (state != stateMin)
1133 {
1134 if (m_CursorState & state)
1135 {
1136 cfg = m_aCursorStatesMap.Get(state);
1137 if (cfg)
1138 return cfg;
1139 }
1140
1141 state = state >> 1;
1142 }
1143
1144 return m_aCursorStatesMap.Get(EMapCursorState.CS_DEFAULT);
1145 }
1146
1147 //------------------------------------------------------------------------------------------------
1149 protected void UpdateCrosshairUI()
1150 {
1151 float sizeX, sizeY, cursorX, cursorY;
1152 m_wCrossMCenter.GetScreenSize(sizeX, sizeY);
1153
1154 cursorX = m_CursorInfo.x;
1155 cursorY = m_CursorInfo.y;
1156
1157 // calculate and set new size of top & left fill imageWidgets
1158 WorkspaceWidget workspace = GetGame().GetWorkspace();
1159 cursorX = cursorX - workspace.DPIUnscale(sizeX)/ 2;
1160 cursorY = cursorY - workspace.DPIUnscale(sizeY)/ 2;
1161
1162 m_CustomCursor.Update(m_CursorInfo.x, m_CursorInfo.y);
1163
1164 m_MapWidget.GetScreenSize(sizeX, sizeY);
1165
1166 m_wCrossLTop.SetSize(cursorX, cursorY);
1167 m_wCrossRTop.SetSize(workspace.DPIUnscale(sizeX) - cursorX, cursorY);
1168 m_wCrossLBot.SetSize(0, workspace.DPIUnscale(sizeY) - cursorY);
1169 m_wGLTop.SetSize(GUILDING_LINE_WIDTH, cursorY);
1170 m_wGLLeft.SetSize(cursorX, GUILDING_LINE_WIDTH);
1171
1172 float wX, wY;
1173 m_MapEntity.ScreenToWorld(m_CursorInfo.Scale(m_CursorInfo.x), m_CursorInfo.Scale(m_CursorInfo.y), wX, wY);
1174
1175 if (m_bEnableCrosshairHeightASL)
1176 {
1177 float heightASL = Math.Round(GetGame().GetWorld().GetSurfaceY(wX, wY) / m_iHeightPrecision) * m_iHeightPrecision;
1178 m_wHeightASLText.SetTextFormat(TEXT_METERS, heightASL.ToString(0, 0));
1179 }
1180
1181 if (m_bEnableCrosshairCoords)
1182 {
1183 wX *= m_fGridPrecision;
1184 if (wX < 0)
1185 wX = MAX_GRID_COORD + wX;
1186
1187 wY *= m_fGridPrecision;
1188 if (wY < 0)
1189 wY = MAX_GRID_COORD + wY;
1190
1191 string posY = (Math.Floor(wY)).ToString(3, 0); // to match grid precision
1192 string posX = (Math.Floor(wX)).ToString(3, 0); // to match grid precision
1193 m_wCoordText.SetTextFormat(TEXT_GRID, posX, posY);
1194 }
1195 }
1196
1197 //------------------------------------------------------------------------------------------------
1199 protected static void TraceMapWidgets()
1200 {
1201 WidgetManager.TraceWidgets(SCR_MapCursorInfo.Scale(SCR_MapCursorInfo.x), SCR_MapCursorInfo.Scale(SCR_MapCursorInfo.y), SCR_MapEntity.GetMapInstance().GetMapMenuRoot(), s_aTracedWidgets);
1202 m_bRecentlyTraced = true;
1203 }
1204
1205 //------------------------------------------------------------------------------------------------
1207 protected void InitWidgets(Widget root)
1208 {
1209 m_MapWidget = m_MapEntity.GetMapWidget();
1210
1211 m_wCrossGrid = root.FindAnyWidget("CursorCrosshair");
1212 if (m_bEnableMapCrosshairVisuals)
1213 {
1214 SetCrosshairGridVisible(true);
1215 // positioning widgets
1216 m_wCrossMCenter = m_wCrossGrid.FindAnyWidget("CrossMCenter");
1217 m_wCrossRTop = ImageWidget.Cast(m_wCrossGrid.FindAnyWidget("CrossRTop"));
1218 m_wCrossLTop = ImageWidget.Cast(m_wCrossGrid.FindAnyWidget("CrossLTop"));
1219 m_wCrossLBot = ImageWidget.Cast(m_wCrossGrid.FindAnyWidget("CrossLBot"));
1220 m_wGLTop = ImageWidget.Cast(m_wCrossGrid.FindAnyWidget("GLTop"));
1221 m_wGLLeft = ImageWidget.Cast(m_wCrossGrid.FindAnyWidget("GLLeft"));
1222 // guidelines
1223 m_wGLFadeLeft = ImageWidget.Cast(m_wCrossGrid.FindAnyWidget("GLFadeLeft"));
1224 m_wGLRight = ImageWidget.Cast(m_wCrossGrid.FindAnyWidget("GLRight"));
1225 m_wGLFadeRight = ImageWidget.Cast(m_wCrossGrid.FindAnyWidget("GLFadeRight"));
1226 m_wGLBot = ImageWidget.Cast(m_wCrossGrid.FindAnyWidget("GLBot"));
1227 m_wGLFadeBot = ImageWidget.Cast(m_wCrossGrid.FindAnyWidget("GLFadeBot"));
1228 m_wGLFadeTop = ImageWidget.Cast(m_wCrossGrid.FindAnyWidget("GLFadeTop"));
1229 m_wCoordText = TextWidget.Cast(m_wCrossGrid.FindAnyWidget("CoordText"));
1230 m_wHeightASLText = TextWidget.Cast(m_wCrossGrid.FindAnyWidget("HeightText"));
1231
1232 // TODO configuration
1233 // Colors
1234 m_wGLTop.SetColor(m_GuidelineColor);
1235 m_wGLLeft.SetColor(m_GuidelineColor);
1236 m_wGLRight.SetColor(m_GuidelineColor);
1237 m_wGLBot.SetColor(m_GuidelineColor);
1238 m_wGLFadeTop.SetColor(m_GuidelineColor);
1239 m_wGLFadeLeft.SetColor(m_GuidelineColor);
1240 m_wGLFadeRight.SetColor(m_GuidelineColor);
1241 m_wGLFadeBot.SetColor(m_GuidelineColor);
1242 m_wCoordText.SetColor(m_GuidelineColor);
1243 m_wHeightASLText.SetColor(m_GuidelineColor);
1244
1245 m_wCoordText.SetOpacity(0); // text
1246
1247 if (m_bEnableCrosshairCoords)
1248 m_wCoordText.SetOpacity(1);
1249
1250 if (m_bEnableCrosshairHeightASL)
1251 m_wHeightASLText.SetOpacity(1);
1252 }
1253 else
1254 {
1255 SetCrosshairGridVisible(false);
1256 }
1257
1258 // cursor
1259 if (!m_CustomCursor)
1260 m_CustomCursor = new SCR_CursorCustom();
1261 }
1262
1263 //------------------------------------------------------------------------------------------------
1265 protected void InitInputs()
1266 {
1268
1269 // controller detection
1270 OnInputDeviceIsGamepad(!GetGame().GetInputManager().IsUsingMouseAndKeyboard());
1271 GetGame().OnInputDeviceIsGamepadInvoker().Insert(OnInputDeviceIsGamepad);
1272
1273 // pause menu
1274 PauseMenuUI.m_OnPauseMenuOpened.Insert(OnPauseMenuOpened);
1275 PauseMenuUI.m_OnPauseMenuClosed.Insert(OnPauseMenuClosed);
1276
1277 m_InputManager.AddActionListener("MapPanDrag", EActionTrigger.PRESSED, OnInputPanDrag);
1278 m_InputManager.AddActionListener("MapPanH", EActionTrigger.PRESSED, OnInputPanH);
1279 m_InputManager.AddActionListener("MapPanV", EActionTrigger.PRESSED, OnInputPanV);
1280 m_InputManager.AddActionListener("MapPanHGamepad", EActionTrigger.VALUE, OnInputPanHGamepad); // requires trigger by value since thumbstick val ranges from -1 to 1
1281 m_InputManager.AddActionListener("MapPanVGamepad", EActionTrigger.VALUE, OnInputPanVGamepad);
1282 m_InputManager.AddActionListener("MapGamepadCursorX", EActionTrigger.VALUE, OnInputGamepadCursorH);
1283 m_InputManager.AddActionListener("MapGamepadCursorY", EActionTrigger.VALUE, OnInputGamepadCursorV);
1284
1285 m_InputManager.AddActionListener("MapZoomIn", EActionTrigger.VALUE, OnInputZoomIn);
1286 m_InputManager.AddActionListener("MapZoomOut", EActionTrigger.VALUE, OnInputZoomOut);
1287
1288 m_InputManager.AddActionListener("MapWheelUp", EActionTrigger.PRESSED, OnInputZoomWheelUp);
1289 m_InputManager.AddActionListener("MapWheelDown", EActionTrigger.PRESSED, OnInputZoomWheelDown);
1290 m_InputManager.AddActionListener("MapSelect", EActionTrigger.UP, HandleSelect);
1291
1292 // multi selection
1293 m_SelectionModule = SCR_MapSelectionModule.Cast(m_MapEntity.GetMapModule(SCR_MapSelectionModule));
1294 if (m_SelectionModule)
1295 {
1296 m_InputManager.AddActionListener("MapMultiSelect", EActionTrigger.PRESSED, OnInputMultiSel);
1297 m_InputManager.AddActionListener("MapMultiSelect", EActionTrigger.UP, OnInputMultiSel);
1298 m_InputManager.AddActionListener("MapMultiSelectGamepad", EActionTrigger.PRESSED, OnInputMultiSelGamepad);
1299 m_InputManager.AddActionListener("MapMultiSelectGamepad", EActionTrigger.UP, OnInputMultiSelGamepad);
1300 }
1301
1302 // tool interaction UI
1303 if (SCR_MapToolInteractionUI.Cast(m_MapEntity.GetMapUIComponent(SCR_MapToolInteractionUI)))
1304 {
1305 m_bIsDraggingAvailable = true;
1306
1307 m_InputManager.AddActionListener("MapModifierKey", EActionTrigger.DOWN, OnInputModifier);
1308 m_InputManager.AddActionListener("MapModifierKey", EActionTrigger.UP, OnInputModifier);
1309 m_InputManager.AddActionListener("MapModifClick", EActionTrigger.DOWN, OnInputModifClick);
1310 m_InputManager.AddActionListener("MapDrag", EActionTrigger.DOWN, OnInputDrag);
1311 m_InputManager.AddActionListener("MapDrag", EActionTrigger.UP, OnInputDrag);
1312 m_InputManager.AddActionListener("MapDragGamepad", EActionTrigger.DOWN, OnInputDragToggle);
1313 }
1314 else
1315 m_bIsDraggingAvailable = false;
1316
1317 }
1318
1319 //------------------------------------------------------------------------------------------------
1321 protected void CleanupInputs()
1322 {
1323 if (!m_InputManager)
1325
1326 // controller detection
1327 GetGame().OnInputDeviceIsGamepadInvoker().Remove(OnInputDeviceIsGamepad);
1328
1329 // pause menu
1330 PauseMenuUI.m_OnPauseMenuOpened.Remove(OnPauseMenuOpened);
1331 PauseMenuUI.m_OnPauseMenuClosed.Remove(OnPauseMenuClosed);
1332
1333 m_InputManager.RemoveActionListener("MapPanDrag", EActionTrigger.PRESSED, OnInputPanDrag);
1334 m_InputManager.RemoveActionListener("MapPanH", EActionTrigger.PRESSED, OnInputPanH);
1335 m_InputManager.RemoveActionListener("MapPanV", EActionTrigger.PRESSED, OnInputPanV);
1336 m_InputManager.RemoveActionListener("MapPanHGamepad", EActionTrigger.VALUE, OnInputPanHGamepad);
1337 m_InputManager.RemoveActionListener("MapPanVGamepad", EActionTrigger.VALUE, OnInputPanVGamepad);
1338 m_InputManager.RemoveActionListener("MapGamepadCursorX", EActionTrigger.VALUE, OnInputGamepadCursorH);
1339 m_InputManager.RemoveActionListener("MapGamepadCursorY", EActionTrigger.VALUE, OnInputGamepadCursorV);
1340
1341 m_InputManager.RemoveActionListener("MapZoomIn", EActionTrigger.VALUE, OnInputZoomIn);
1342 m_InputManager.RemoveActionListener("MapZoomOut", EActionTrigger.VALUE, OnInputZoomOut);
1343
1344 m_InputManager.RemoveActionListener("MapWheelUp", EActionTrigger.PRESSED, OnInputZoomWheelUp);
1345 m_InputManager.RemoveActionListener("MapWheelDown", EActionTrigger.PRESSED, OnInputZoomWheelDown);
1346 m_InputManager.RemoveActionListener("MapSelect", EActionTrigger.UP, HandleSelect);
1347
1348 m_InputManager.RemoveActionListener("MapModifierKey", EActionTrigger.DOWN, OnInputModifier);
1349 m_InputManager.RemoveActionListener("MapModifierKey", EActionTrigger.UP, OnInputModifier);
1350 m_InputManager.RemoveActionListener("MapModifClick", EActionTrigger.DOWN, OnInputModifClick);
1351 m_InputManager.RemoveActionListener("MapDrag", EActionTrigger.DOWN, OnInputDrag);
1352 m_InputManager.RemoveActionListener("MapDrag", EActionTrigger.UP, OnInputDrag);
1353 m_InputManager.RemoveActionListener("MapDragGamepad", EActionTrigger.DOWN, OnInputDragToggle);
1354
1355 m_InputManager.RemoveActionListener("MapMultiSelect", EActionTrigger.PRESSED, OnInputMultiSel);
1356 m_InputManager.RemoveActionListener("MapMultiSelect", EActionTrigger.UP, OnInputMultiSel);
1357 m_InputManager.RemoveActionListener("MapMultiSelectGamepad", EActionTrigger.PRESSED, OnInputMultiSelGamepad);
1358 m_InputManager.RemoveActionListener("MapMultiSelectGamepad", EActionTrigger.UP, OnInputMultiSelGamepad);
1359 }
1360
1361 //------------------------------------------------------------------------------------------------
1362 // OVERRIDES
1363 //------------------------------------------------------------------------------------------------
1364 override void OnMapOpen(MapConfiguration config)
1365 {
1366 if (!m_CursorInfo)
1367 m_CursorInfo = new SCR_MapCursorInfo();
1368
1369 m_bIsDisabled = false;
1370 InitWidgets(config.RootWidgetRef);
1371 InitInputs();
1372 m_bIsInit = true;
1373
1374 SetCursorType(m_CursorState);
1375
1376 if (m_bIsCursorCenteredOnOpen || m_CursorInfo.isGamepad)
1377 ForceCenterCursor();
1378 }
1379
1380 //------------------------------------------------------------------------------------------------
1381 override void OnMapClose(MapConfiguration config)
1382 {
1383 m_CursorState = EMapCursorState.CS_DEFAULT;
1384 SetCursorType(EMapCursorState.CS_DISABLE);
1385 CleanupInputs();
1386
1387 m_bIsInit = false;
1388 }
1389
1390 //------------------------------------------------------------------------------------------------
1391 override void Update(float timeSlice)
1392 {
1393 if (m_bIsDisabled)
1394 return;
1395
1396 m_bRecentlyTraced = false;
1397
1398 // update current pos
1399 GetCursorPosition(m_CursorInfo.x, m_CursorInfo.y);
1400
1401 // frame handlers
1402 HandleMove();
1403 HandleHover(timeSlice);
1404 HandlePan(timeSlice);
1405 HandleZoom();
1406
1407 // crosshair grid lines
1408 if (m_bEnableMapCrosshairVisuals && (m_CursorState & CUSTOM_CURSOR_LOCKED) == 0)
1409 UpdateCrosshairUI();
1410 }
1411
1412 //------------------------------------------------------------------------------------------------
1413 void SCR_MapCursorModule()
1414 {
1415 foreach (SCR_CursorVisualState cursorState : m_aCursorStatesConfig)
1416 {
1417 EMapCursorState stateEnum = cursorState.m_eCursorState;
1418 if (stateEnum)
1419 m_aCursorStatesMap.Insert(stateEnum, cursorState);
1420 }
1421 }
1422}
1423
1424//------------------------------------------------------------------------------------------------
1426[BaseContainerProps(), SCR_CursorStateTitle()]
1427class SCR_CursorVisualState
1428{
1429 [Attribute("1", UIWidgets.ComboBox, "Configure selected cursor state", "", ParamEnumArray.FromEnum(EMapCursorState))]
1430 int m_eCursorState;
1431
1432 [Attribute("{E75FB4134580A496}UI/Textures/Cursor/cursors.imageset", UIWidgets.ResourceNamePicker, desc: "Imageset selection", params: "imageset")]
1433 ResourceName m_sCursorIconsImageset;
1434
1435 [Attribute("default", UIWidgets.EditBox, desc: "imageset quad")]
1436 string m_sImageQuad;
1437
1438 [Attribute("", UIWidgets.EditBox, desc: "imageset quad when controller is active instead of KBM \nIf this is not defined, attibute from above is used for both cases")]
1439 string m_sImageQuadController;
1440
1441 [Attribute("0", UIWidgets.Slider, desc: "Padding from top, in pixels", "-32 32 1")]
1442 float m_fPaddingTop;
1443
1444 [Attribute("0", UIWidgets.Slider, desc: "Padding from left, in pixels", "-32 32 1")]
1445 float m_fPaddingLeft;
1446
1447 [Attribute("0.76 0.38 0.08 1", UIWidgets.ColorPicker, desc: "Cursor color")]
1448 ref Color m_Color;
1449
1450 [Attribute(desc: "Cursor lines are disabled in this state if otherwise active")]
1451 bool m_DisableCursorLines;
1452}
1453
1454//------------------------------------------------------------------------------------------------
1456class SCR_CursorStateTitle : BaseContainerCustomTitle
1457{
1458 //------------------------------------------------------------------------------------------------
1459 override bool _WB_GetCustomTitle(BaseContainer source, out string title)
1460 {
1461 int type;
1462 source.Get("m_eCursorState", type);
1463 title = typename.EnumToString(EMapCursorState, type);
1464
1465 return true;
1466 }
1467}
ArmaReforgerScripted GetGame()
Definition game.c:1398
string LocalizedString
SCR_AIAnimation_Loitering BaseContainerProps
Commanding menu commanding element class.
InputManager GetInputManager()
InputManager m_InputManager
void OnInputDeviceIsGamepad(bool isGamepad)
void SetCursorType(EEditorCursor type)
Widget m_wRootWidget
EDamageType type
vector direction
ref Color m_Color
EMapPanMode
Panning modes.
EMapCursorState
Map cursor state.
EMapCursorEdgePos
Flags for when cursor is placed on screen edges.
EMapEntityMode
Mode of the map.
EMapCursorSelectType
Map cursor multiselection type.
SCR_MapEntity m_MapEntity
SCR_PossessingManagerComponentClass int
UI Textures DeployMenu Briefing conflict_HintBanner_1_UI desc
void OnPauseMenuClosed()
PauseMenuUI Event.
bool m_bIsDisabled
void OnPauseMenuOpened()
PauseMenuUI Event.
Definition Color.c:13
sealed InputManager GetInputManager()
Definition Game.c:14
SCR_MapModuleBase GetMapModule(typename moduleType)
void Pan(EMapPanMode panMode, float panValue=0)
CanvasWidget GetMapWidget()
Get map widget.
void InvokeOnSelect(vector selectionPos)
MapConfiguration GetMapConfig()
Get map config.
MapItem GetHoveredItem()
Get hovered item.
bool IsZooming()
Get whether zoom interpolation is ongoing.
void ZoomSmooth(float targetPixPerUnit, float zoomTime=0.25, bool zoomToCenter=true, bool reinitZoom=false)
void ScreenToWorld(int screenPosX, int screenPosY, out float worldX, out float worldY)
Use scaled screen coords to get canvas world coords, flips the y-axis.
SCR_MapUIBaseComponent GetMapUIComponent(typename componentType)
float GetTargetZoomPPU()
Get target zoom in the form of PixelPerUnit value, which is different from current zoom if interpolat...
void SelectItem(MapItem item)
void HoverItem(MapItem item)
float GetCurrentZoom()
void ScreenToWorldNoFlip(int screenPosX, int screenPosY, out float worldX, out float worldY)
Use scaled screen coords to get canvas world coords without flipping the y-axis.
void ClearHover()
Clear hover state.
void ClearSelection()
Clear selected items.
Map module base class.
void OnMapClose(MapConfiguration config)
SCR_MapEntity event.
void OnMapOpen(MapConfiguration config)
SCR_MapEntity event.
Definition Types.c:486
Game g_Game
Game singleton instance.
Definition gameLib.c:13
float Scale
Definition gameLib.c:128
SCR_FieldOfViewSettings Attribute
EActionTrigger
class SCR_BaseManualCameraComponent _WB_GetCustomTitle(BaseContainer source, out string title)
proto native vector Vector(float x, float y, float z)