Unstable 0.15.15.0 (and the one before it I forgor)

This commit is contained in:
Markus Isberg
2021-11-18 21:34:30 +09:00
parent 10e5fd5f3e
commit 80f39cd2a3
257 changed files with 4916 additions and 2582 deletions
@@ -494,7 +494,7 @@ namespace Barotrauma
GUIFrame.Parent.Visible = visible;
}
private IEnumerable<object> UpdateMessageAnimation(GUIComponent message, float animDuration)
private IEnumerable<CoroutineStatus> UpdateMessageAnimation(GUIComponent message, float animDuration)
{
float timer = 0.0f;
while (timer < animDuration)
@@ -399,7 +399,7 @@ namespace Barotrauma
" Max: " + GameMain.PerformanceCounter.DrawTimeGraph.LargestValue().ToString("0.00") + " ms",
GUI.Style.Green, Color.Black * 0.8f, font: SmallFont);
y += 15;
GameMain.PerformanceCounter.DrawTimeGraph.Draw(spriteBatch, new Rectangle(300, y, 170, 50), null, 0, GUI.Style.Green);
GameMain.PerformanceCounter.DrawTimeGraph.Draw(spriteBatch, new Rectangle(300, y, 170, 50), color: Style.Green);
y += 50;
DrawString(spriteBatch, new Vector2(300, y),
@@ -407,8 +407,8 @@ namespace Barotrauma
" Max: " + GameMain.PerformanceCounter.UpdateTimeGraph.LargestValue().ToString("0.00") + " ms",
Color.LightBlue, Color.Black * 0.8f, font: SmallFont);
y += 15;
GameMain.PerformanceCounter.UpdateTimeGraph.Draw(spriteBatch, new Rectangle(300, y, 170, 50), null, 0, Color.LightBlue);
GameMain.PerformanceCounter.UpdateIterationsGraph.Draw(spriteBatch, new Rectangle(300, y, 170, 50), 20, 0, GUI.Style.Red);
GameMain.PerformanceCounter.UpdateTimeGraph.Draw(spriteBatch, new Rectangle(300, y, 170, 50), color: Color.LightBlue);
GameMain.PerformanceCounter.UpdateIterationsGraph.Draw(spriteBatch, new Rectangle(300, y, 170, 50), maxValue: 20, color: Style.Red);
y += 50;
foreach (string key in GameMain.PerformanceCounter.GetSavedIdentifiers)
{
@@ -941,7 +941,8 @@ namespace Barotrauma
inventoryIndex = updateList.IndexOf(CharacterHUD.HUDFrame);
}
if ((!PlayerInput.PrimaryMouseButtonHeld() && !PlayerInput.PrimaryMouseButtonClicked()) || (prevMouseOn == null && !PlayerInput.SecondaryMouseButtonHeld()))
if ((!PlayerInput.PrimaryMouseButtonHeld() && !PlayerInput.PrimaryMouseButtonClicked()) ||
(prevMouseOn == null && !PlayerInput.SecondaryMouseButtonHeld() && !Inventory.DraggingItems.Any()))
{
for (var i = updateList.Count - 1; i > inventoryIndex; i--)
{
@@ -1052,10 +1053,10 @@ namespace Barotrauma
// Children in list boxes can be interacted with despite not having
// a GUIButton inside of them so instead of hard coding we check if
// the children can be interacted with by checking their hover state
if (parent is GUIListBox listBox)
if (parent is GUIListBox listBox && c.Parent == listBox.Content)
{
if (listBox.DraggedElement != null) { return CursorState.Dragging; }
if (listBox.CanDragElements) { return CursorState.Move; }
if (listBox.CurrentDragMode != GUIListBox.DragMode.NoDragging) { return CursorState.Move; }
if (listBox.HoverCursor != CursorState.Default)
{
@@ -1148,7 +1149,7 @@ namespace Barotrauma
{
CoroutineManager.StartCoroutine(WaitCursorCoroutine(), "WaitCursorTimeout");
IEnumerable<object> WaitCursorCoroutine()
IEnumerable<CoroutineStatus> WaitCursorCoroutine()
{
MouseCursor = CursorState.Waiting;
var timeOut = DateTime.Now + new TimeSpan(0, 0, waitSeconds);
@@ -1360,7 +1361,7 @@ namespace Barotrauma
float symbolScale = Math.Min(64.0f / sprite.size.X, 1.0f) * scaleMultiplier * Scale;
if (overrideAlpha.HasValue || (dist > visibleRange.Start && dist < visibleRange.End))
if (overrideAlpha.HasValue || visibleRange.Contains(dist))
{
float alpha = overrideAlpha ?? MathUtils.Min((dist - visibleRange.Start) / 100.0f, 1.0f - ((dist - visibleRange.End + 100f) / 100.0f), 1.0f);
Vector2 targetScreenPos = cam.WorldToScreen(worldPosition);
@@ -2254,8 +2255,8 @@ namespace Barotrauma
#region Misc
public static void TogglePauseMenu()
{
if (Screen.Selected == GameMain.MainMenuScreen) return;
if (PreventPauseMenuToggle) return;
if (Screen.Selected == GameMain.MainMenuScreen) { return; }
if (PreventPauseMenuToggle) { return; }
settingsMenuOpen = false;
@@ -2276,162 +2277,121 @@ namespace Barotrauma
Stretch = true,
RelativeSpacing = 0.05f
};
new GUIButton(new RectTransform(new Vector2(0.1f, 0.1f), pauseMenuInner.RectTransform, Anchor.TopRight) { AbsoluteOffset = new Point((int)(15 * GUI.Scale)) },
new GUIButton(new RectTransform(new Vector2(0.1f, 0.1f), pauseMenuInner.RectTransform, Anchor.TopRight) { AbsoluteOffset = new Point((int)(15 * GUI.Scale)) },
"", style: "GUIBugButton")
{
IgnoreLayoutGroups = true,
ToolTip = TextManager.Get("bugreportbutton"),
ToolTip = TextManager.Get("bugreportbutton") + $" (v{GameMain.Version})",
OnClicked = (btn, userdata) => { GameMain.Instance.ShowBugReporter(); return true; }
};
new GUIButton(new RectTransform(new Vector2(1.0f, 0.1f), buttonContainer.RectTransform), TextManager.Get("PauseMenuResume"))
{
OnClicked = TogglePauseMenu
};
new GUIButton(new RectTransform(new Vector2(1.0f, 0.1f), buttonContainer.RectTransform), TextManager.Get("PauseMenuSettings"))
{
OnClicked = (btn, userData) =>
{
TogglePauseMenu();
settingsMenuOpen = !settingsMenuOpen;
return true;
}
};
CreateButton("PauseMenuResume", buttonContainer, null);
CreateButton("PauseMenuSettings", buttonContainer, () => { settingsMenuOpen = !settingsMenuOpen; });
bool IsOutpostLevel() => GameMain.GameSession != null && Level.IsLoadedOutpost;
if (Screen.Selected == GameMain.GameScreen && GameMain.GameSession != null)
{
if (GameMain.GameSession.GameMode is SinglePlayerCampaign spMode)
{
var retryButton = new GUIButton(new RectTransform(new Vector2(1.0f, 0.1f), buttonContainer.RectTransform), TextManager.Get("PauseMenuRetry"));
retryButton.OnClicked += (btn, userData) =>
CreateButton("PauseMenuRetry", buttonContainer, verificationTextTag: "PauseMenuRetryVerification", action: () =>
{
var msgBox = new GUIMessageBox("", TextManager.Get("PauseMenuRetryVerification"), new string[] { TextManager.Get("Yes"), TextManager.Get("Cancel") })
if (GameMain.GameSession.RoundSummary?.Frame != null)
{
UserData = "verificationprompt"
};
msgBox.Buttons[0].OnClicked = (_, userdata) =>
{
if (GameMain.GameSession.RoundSummary?.Frame != null)
{
GUIMessageBox.MessageBoxes.Remove(GameMain.GameSession.RoundSummary.Frame);
}
GUIMessageBox.MessageBoxes.Remove(GameMain.GameSession.RoundSummary.Frame);
}
GUIMessageBox.MessageBoxes.RemoveAll(mb => mb.UserData as string == "ConversationAction");
GameMain.GameSession.LoadPreviousSave();
});
GUIMessageBox.MessageBoxes.RemoveAll(mb => mb.UserData as string == "ConversationAction");
TogglePauseMenu(btn, userData);
GameMain.GameSession.LoadPreviousSave();
return true;
};
msgBox.Buttons[0].OnClicked += msgBox.Close;
msgBox.Buttons[1].OnClicked = (_, userdata) =>
{
TogglePauseMenu(btn, userData);
msgBox.Close();
return true;
};
return true;
};
if (IsOutpostLevel())
{
var saveAndQuitButton = new GUIButton(new RectTransform(new Vector2(1.0f, 0.1f), buttonContainer.RectTransform), TextManager.Get("PauseMenuSaveQuit"))
CreateButton("PauseMenuSaveQuit", buttonContainer, verificationTextTag: "PauseMenuSaveAndReturnToMainMenuVerification", action: () =>
{
UserData = "save",
OnClicked = (btn, userData) =>
{
pauseMenuOpen = false;
if (IsOutpostLevel())
{
GameMain.QuitToMainMenu(save: true);
}
return true;
}
};
if (IsOutpostLevel()) { GameMain.QuitToMainMenu(save: true); }
});
}
}
else if (GameMain.GameSession.GameMode is TestGameMode)
{
new GUIButton(new RectTransform(new Vector2(1.0f, 0.1f), buttonContainer.RectTransform), text: TextManager.Get("PauseMenuReturnToEditor"))
CreateButton("PauseMenuReturnToEditor", buttonContainer, action: () =>
{
OnClicked = (btn, userdata) =>
{
GameMain.GameSession.EndRound("");
pauseMenuOpen = false;
return true;
}
};
GameMain.GameSession?.EndRound("");
});
}
else if (!GameMain.GameSession.GameMode.IsSinglePlayer && GameMain.Client != null && GameMain.Client.HasPermission(ClientPermissions.ManageRound))
{
new GUIButton(new RectTransform(new Vector2(1.0f, 0.1f), buttonContainer.RectTransform),
text: TextManager.Get(GameMain.GameSession.GameMode is CampaignMode ? "ReturnToServerlobby": "EndRound"))
bool canSave = GameMain.GameSession.GameMode is CampaignMode && IsOutpostLevel();
if (canSave)
{
OnClicked = (btn, userdata) =>
CreateButton("PauseMenuSaveQuit", buttonContainer, verificationTextTag: "PauseMenuSaveAndReturnToServerLobbyVerification", action: () =>
{
if (!GameMain.Client.HasPermission(ClientPermissions.ManageRound)) { return false; }
if (GameMain.GameSession.GameMode is CampaignMode && !IsOutpostLevel() || (!Submarine.MainSub.AtStartExit && !Submarine.MainSub.AtEndExit))
{
var msgBox = new GUIMessageBox("",
TextManager.Get(GameMain.GameSession.GameMode is CampaignMode ? "PauseMenuReturnToServerLobbyVerification" : "EndRoundSubNotAtLevelEnd"),
new string[] { TextManager.Get("Yes"), TextManager.Get("No") })
{
UserData = "verificationprompt"
};
msgBox.Buttons[0].OnClicked = (_, __) =>
{
pauseMenuOpen = false;
GameMain.Client.RequestRoundEnd();
return true;
};
msgBox.Buttons[0].OnClicked += msgBox.Close;
msgBox.Buttons[1].OnClicked += msgBox.Close;
}
else
{
pauseMenuOpen = false;
GameMain.Client.RequestRoundEnd();
}
return true;
}
};
GameMain.Client?.RequestRoundEnd(save: true);
});
}
CreateButton(GameMain.GameSession.GameMode is CampaignMode ? "ReturnToServerlobby" : "EndRound", buttonContainer,
verificationTextTag: GameMain.GameSession.GameMode is CampaignMode ? "PauseMenuReturnToServerLobbyVerification" : "EndRoundSubNotAtLevelEnd",
action: () =>
{
GameMain.Client?.RequestRoundEnd(save: false);
});
}
}
var quitButton = new GUIButton(new RectTransform(new Vector2(1.0f, 0.1f), buttonContainer.RectTransform), TextManager.Get("PauseMenuQuit"));
quitButton.OnClicked += (btn, userData) =>
if (GameMain.GameSession != null || Screen.Selected is CharacterEditorScreen || Screen.Selected is SubEditorScreen)
{
if (GameMain.GameSession != null || (Screen.Selected is CharacterEditorScreen || Screen.Selected is SubEditorScreen))
{
string text = GameMain.GameSession == null ? "PauseMenuQuitVerificationEditor" : "PauseMenuQuitVerification";
var msgBox = new GUIMessageBox("", TextManager.Get(text), new string[] { TextManager.Get("Yes"), TextManager.Get("Cancel") })
{
UserData = "verificationprompt"
};
msgBox.Buttons[0].OnClicked = (yesBtn, userdata) =>
CreateButton("PauseMenuQuit", buttonContainer,
verificationTextTag: GameMain.GameSession == null ? "PauseMenuQuitVerificationEditor" : "PauseMenuQuitVerification",
action: () =>
{
GameMain.QuitToMainMenu(save: false);
pauseMenuOpen = false;
return true;
};
msgBox.Buttons[0].OnClicked += msgBox.Close;
msgBox.Buttons[1].OnClicked = (_, userdata) =>
{
pauseMenuOpen = false;
msgBox.Close();
return true;
};
}
else
{
GameMain.QuitToMainMenu(save: false);
pauseMenuOpen = false;
}
return true;
};
});
}
else
{
CreateButton("PauseMenuQuit", buttonContainer, action: () => { GameMain.QuitToMainMenu(save: false); });
}
GUITextBlock.AutoScaleAndNormalize(buttonContainer.Children.Where(c => c is GUIButton).Select(c => ((GUIButton)c).TextBlock));
}
void CreateButton(string textTag, GUIComponent parent, Action action, string verificationTextTag = null)
{
new GUIButton(new RectTransform(new Vector2(1.0f, 0.1f), parent.RectTransform), TextManager.Get(textTag))
{
OnClicked = (btn, userData) =>
{
if (string.IsNullOrEmpty(verificationTextTag))
{
pauseMenuOpen = false;
action?.Invoke();
}
else
{
CreateVerificationPrompt(verificationTextTag, action);
}
return true;
}
};
}
void CreateVerificationPrompt(string textTag, Action confirmAction)
{
var msgBox = new GUIMessageBox("", TextManager.Get(textTag),
new string[] { TextManager.Get("Yes"), TextManager.Get("No") })
{
UserData = "verificationprompt"
};
msgBox.Buttons[0].OnClicked = (_, __) =>
{
pauseMenuOpen = false;
confirmAction?.Invoke();
return true;
};
msgBox.Buttons[0].OnClicked += msgBox.Close;
msgBox.Buttons[1].OnClicked += msgBox.Close;
}
}
private static bool TogglePauseMenu(GUIButton button, object obj)
@@ -531,6 +531,17 @@ namespace Barotrauma
}
}
public virtual void ForceLayoutRecalculation()
{
//This is very ugly but it gets the job done, it
//would be real nice to un-jank this some day
ForceUpdate();
ForceUpdate();
foreach (var child in Children) { child.ForceLayoutRecalculation(); }
}
public void ForceUpdate() => Update((float)Timing.Step);
/// <summary>
/// Updates all the children manually.
/// </summary>
@@ -831,7 +842,7 @@ namespace Barotrauma
CoroutineManager.StartCoroutine(SlideToPosition(duration, 0.0f, targetPos));
}
private IEnumerable<object> SlideToPosition(float duration, float wait, Vector2 target)
private IEnumerable<CoroutineStatus> SlideToPosition(float duration, float wait, Vector2 target)
{
float t = 0.0f;
var (startX, startY) = RectTransform.ScreenSpaceOffset.ToVector2();
@@ -855,7 +866,7 @@ namespace Barotrauma
yield return CoroutineStatus.Success;
}
private IEnumerable<object> LerpAlpha(float to, float duration, bool removeAfter, float wait = 0.0f)
private IEnumerable<CoroutineStatus> LerpAlpha(float to, float duration, bool removeAfter, float wait = 0.0f)
{
State = ComponentState.None;
float t = 0.0f;
@@ -894,7 +905,7 @@ namespace Barotrauma
pulsateCoroutine = CoroutineManager.StartCoroutine(DoPulsate(startScale, endScale, duration), "Pulsate" + ToString());
}
private IEnumerable<object> DoPulsate(Vector2 startScale, Vector2 endScale, float duration)
private IEnumerable<CoroutineStatus> DoPulsate(Vector2 startScale, Vector2 endScale, float duration)
{
float t = 0.0f;
while (t < duration)
@@ -34,7 +34,7 @@ namespace Barotrauma
public GUIScrollBar ScrollBar { get; private set; }
private readonly Dictionary<GUIComponent, bool> childVisible = new Dictionary<GUIComponent, bool>();
private int totalSize;
private bool childrenNeedsRecalculation;
private bool scrollBarNeedsRecalculation;
@@ -53,7 +53,23 @@ namespace Barotrauma
}
}
public bool SelectMultiple;
public enum SelectMode
{
SelectSingle,
SelectMultiple,
RequireShiftToSelectMultiple
}
public SelectMode CurrentSelectMode = SelectMode.SelectSingle;
public bool SelectMultiple
{
get { return CurrentSelectMode != SelectMode.SelectSingle; }
set
{
CurrentSelectMode = value ? SelectMode.SelectMultiple : SelectMode.SelectSingle;
}
}
public bool HideChildrenOutsideFrame = true;
@@ -103,7 +119,7 @@ namespace Barotrauma
/// <summary>
/// true if mouse down should select elements instead of mouse up
/// </summary>
private bool useMouseDownToSelect = false;
private readonly bool useMouseDownToSelect = false;
private Vector4? overridePadding;
public Vector4 Padding
@@ -132,10 +148,7 @@ namespace Barotrauma
// TODO: fix implicit hiding
public bool Selected { get; set; }
public List<GUIComponent> AllSelected
{
get { return selected; }
}
public IReadOnlyList<GUIComponent> AllSelected => selected;
public object SelectedData
{
@@ -214,25 +227,34 @@ namespace Barotrauma
public bool AutoHideScrollBar { get; set; } = true;
private bool IsScrollBarOnDefaultSide { get; set; }
public bool CanDragElements
public enum DragMode
{
NoDragging,
DragWithinBox,
DragOutsideBox
}
private DragMode currentDragMode = DragMode.NoDragging;
public DragMode CurrentDragMode
{
get
{
return canDragElements;
return currentDragMode;
}
set
{
if (value == false && canDragElements && draggedElement != null)
if (value == DragMode.NoDragging && currentDragMode != DragMode.NoDragging && isDraggingElement)
{
DraggedElement = null;
}
canDragElements = value;
currentDragMode = value;
}
}
private bool canDragElements = false;
private GUIComponent draggedElement;
private Rectangle draggedReferenceRectangle;
private Point draggedReferenceOffset;
private Point dragMousePosRelativeToTopLeftCorner;
private bool isDraggingElement => draggedElement != null;
public bool HasDraggedElementIndexChanged { get; private set; }
public GUIComponent DraggedElement
@@ -246,8 +268,24 @@ namespace Barotrauma
if (value == draggedElement) { return; }
draggedElement = value;
HasDraggedElementIndexChanged = false;
if (value == null) { return; }
dragMousePosRelativeToTopLeftCorner = PlayerInput.MousePosition.ToPoint() - value.Rect.Location;
if (SelectMultiple)
{
if (!AllSelected.Contains(DraggedElement))
{
Select(DraggedElement.ToEnumerable());
}
}
}
}
//This exists to work around the fact that rendering child
//elements on top of the listbox's siblings is a clusterfuck.
public bool HideDraggedElement = false;
private readonly bool isHorizontal;
@@ -354,7 +392,7 @@ namespace Barotrauma
(child.UserData == null && userData == null))
{
Select(i, force, autoScroll);
if (!SelectMultiple) return;
if (!SelectMultiple) { return; }
}
i++;
}
@@ -363,9 +401,10 @@ namespace Barotrauma
private Point CalculateFrameSize(bool isHorizontal, int scrollBarSize)
=> isHorizontal ? new Point(Rect.Width, Rect.Height - scrollBarSize) : new Point(Rect.Width - scrollBarSize, Rect.Height);
private void RepositionChildren()
public Vector2 CalculateTopOffset()
{
int x = 0, y = 0;
int x = 0;
int y = 0;
if (ScrollBar.BarSize < 1.0f)
{
if (ScrollBar.IsHorizontal)
@@ -378,53 +417,59 @@ namespace Barotrauma
}
}
return new Vector2(x, y);
}
private void CalculateChildrenOffsets(Action<int, Point> callback)
{
Vector2 topOffset = CalculateTopOffset();
int x = (int)topOffset.X;
int y = (int)topOffset.Y;
for (int i = 0; i < Content.CountChildren; i++)
{
GUIComponent child = Content.GetChild(i);
if (!child.Visible) { continue; }
if (RectTransform != null)
{
if (child != draggedElement && (child.RectTransform.AbsoluteOffset.X != x || child.RectTransform.AbsoluteOffset.Y != y))
{
child.RectTransform.AbsoluteOffset = new Point(x, y);
}
callback(i, new Point(x, y));
}
if (useGridLayout)
{
void advanceGridLayout(
ref int primaryCoord,
ref int secondaryCoord,
int primaryChildDimension,
int secondaryChildDimension,
int primaryParentDimension)
{
if (primaryCoord + primaryChildDimension + Spacing > primaryParentDimension)
{
primaryCoord = 0;
secondaryCoord += secondaryChildDimension + Spacing;
callback(i, new Point(x, y));
}
primaryCoord += primaryChildDimension + Spacing;
}
if (ScrollBar.IsHorizontal)
{
if (y + child.Rect.Height + Spacing > Content.Rect.Height)
{
y = 0;
x += child.Rect.Width + Spacing;
if (child != draggedElement && (child.RectTransform.AbsoluteOffset.X != x || child.RectTransform.AbsoluteOffset.Y != y))
{
child.RectTransform.AbsoluteOffset = new Point(x, y);
}
y += child.Rect.Height + Spacing;
}
else
{
y += child.Rect.Height + Spacing;
}
advanceGridLayout(
primaryCoord: ref y,
secondaryCoord: ref x,
primaryChildDimension: child.Rect.Height,
secondaryChildDimension: child.Rect.Width,
primaryParentDimension: Content.Rect.Height);
}
else
{
if (x + child.Rect.Width + Spacing > Content.Rect.Width)
{
x = 0;
y += child.Rect.Height + Spacing;
if (child != draggedElement && (child.RectTransform.AbsoluteOffset.X != x || child.RectTransform.AbsoluteOffset.Y != y))
{
child.RectTransform.AbsoluteOffset = new Point(x, y);
}
x += child.Rect.Width + Spacing;
}
else
{
x += child.Rect.Width + Spacing;
}
advanceGridLayout(
primaryCoord: ref x,
secondaryCoord: ref y,
primaryChildDimension: child.Rect.Width,
secondaryChildDimension: child.Rect.Height,
primaryParentDimension: Content.Rect.Width);
}
}
else
@@ -440,6 +485,18 @@ namespace Barotrauma
}
}
}
private void RepositionChildren()
{
CalculateChildrenOffsets((index, offset) =>
{
var child = Content.GetChild(index);
if (child != draggedElement && child.RectTransform.AbsoluteOffset != offset)
{
child.RectTransform.AbsoluteOffset = offset;
}
});
}
/// <summary>
/// Scrolls the list to the specific element, currently only works when smooth scrolling and PadBottom are enabled.
@@ -466,7 +523,7 @@ namespace Barotrauma
{
CoroutineManager.StartCoroutine(ScrollCoroutine());
IEnumerable<object> ScrollCoroutine()
IEnumerable<CoroutineStatus> ScrollCoroutine()
{
if (BarSize >= 1.0f)
{
@@ -490,68 +547,122 @@ namespace Barotrauma
}
}
private void UpdateChildrenRect()
private void StartDraggingElement(GUIComponent child)
{
//dragging
if (CanDragElements && draggedElement != null)
DraggedElement = child;
}
private bool UpdateDragging()
{
if (CurrentDragMode == DragMode.NoDragging || !isDraggingElement) { return false; }
if (!PlayerInput.PrimaryMouseButtonHeld())
{
if (!PlayerInput.PrimaryMouseButtonHeld())
var draggedElem = draggedElement;
OnRearranged?.Invoke(this, draggedElem.UserData);
DraggedElement = null;
RepositionChildren();
if (AllSelected.Contains(draggedElem)) { return true; }
}
else
{
Vector2 topOffset = CalculateTopOffset();
var mousePos = PlayerInput.MousePosition.ToPoint();
draggedElement.RectTransform.AbsoluteOffset = mousePos - Content.Rect.Location - dragMousePosRelativeToTopLeftCorner;
if (CurrentDragMode != DragMode.DragOutsideBox)
{
OnRearranged?.Invoke(this, draggedElement.UserData);
DraggedElement = null;
RepositionChildren();
var offset = draggedElement.RectTransform.AbsoluteOffset;
draggedElement.RectTransform.AbsoluteOffset =
isHorizontal ? new Point(offset.X, 0) : new Point(0, offset.Y);
}
int index = Content.RectTransform.GetChildIndex(draggedElement.RectTransform);
int newIndex = index;
Point draggedOffsetWhenReleased = Point.Zero;
CalculateChildrenOffsets((i, offset) =>
{
if (index != i) { return; }
draggedOffsetWhenReleased = offset;
});
Rectangle draggedRectWhenReleased = new Rectangle(Content.Rect.Location + draggedOffsetWhenReleased, draggedElement.Rect.Size);
void shiftIndices(
float mousePos,
ref int draggedRectWhenReleasedLocation,
int draggedRectWhenReleasedSize)
{
while (mousePos > (draggedRectWhenReleasedLocation + draggedRectWhenReleasedSize) && newIndex < Content.CountChildren-1)
{
newIndex++;
draggedRectWhenReleasedLocation += draggedRectWhenReleasedSize;
}
while (mousePos < draggedRectWhenReleasedLocation && newIndex > 0)
{
newIndex--;
draggedRectWhenReleasedLocation -= draggedRectWhenReleasedSize;
}
if (newIndex != index && AllSelected.Count > 1)
{
this.selected.Sort((a, b) => Content.GetChildIndex(a) - Content.GetChildIndex(b));
int draggedPos = AllSelected.IndexOf(draggedElement);
if (newIndex < draggedPos)
{
newIndex = draggedPos;
}
if (newIndex >= Content.CountChildren - (AllSelected.Count - draggedPos))
{
int max = Content.CountChildren - (AllSelected.Count - draggedPos);
newIndex = max;
}
}
}
if (isHorizontal)
{
shiftIndices(
mousePos.X,
ref draggedRectWhenReleased.X,
draggedRectWhenReleased.Width);
}
else
{
draggedElement.RectTransform.AbsoluteOffset = isHorizontal ?
draggedReferenceOffset + new Point((int)PlayerInput.MousePosition.X - draggedReferenceRectangle.Center.X, 0) :
draggedReferenceOffset + new Point(0, (int)PlayerInput.MousePosition.Y - draggedReferenceRectangle.Center.Y);
shiftIndices(
mousePos.Y,
ref draggedRectWhenReleased.Y,
draggedRectWhenReleased.Height);
}
int index = Content.RectTransform.GetChildIndex(draggedElement.RectTransform);
int currIndex = index;
if (isHorizontal)
if (newIndex != index)
{
if (AllSelected.Count > 1)
{
while (currIndex > 0 && PlayerInput.MousePosition.X < draggedReferenceRectangle.Left)
this.selected.Sort((a, b) => Content.GetChildIndex(a) - Content.GetChildIndex(b));
int indexOfDraggedElem = AllSelected.IndexOf(draggedElement);
IEnumerable<GUIComponent> allSelected = AllSelected;
if (newIndex > index) { allSelected = allSelected.Reverse(); }
foreach (var elem in allSelected)
{
currIndex--;
draggedReferenceRectangle.X -= draggedReferenceRectangle.Width;
draggedReferenceOffset.X -= draggedReferenceRectangle.Width;
}
while (currIndex < Content.CountChildren - 1 && PlayerInput.MousePosition.X > draggedReferenceRectangle.Right)
{
currIndex++;
draggedReferenceRectangle.X += draggedReferenceRectangle.Width;
draggedReferenceOffset.X += draggedReferenceRectangle.Width;
elem.RectTransform.RepositionChildInHierarchy(newIndex + AllSelected.IndexOf(elem) - indexOfDraggedElem);
}
}
else
{
while (currIndex > 0 && PlayerInput.MousePosition.Y < draggedReferenceRectangle.Top)
{
currIndex--;
draggedReferenceRectangle.Y -= draggedReferenceRectangle.Height;
draggedReferenceOffset.Y -= draggedReferenceRectangle.Height;
}
while (currIndex < Content.CountChildren - 1 && PlayerInput.MousePosition.Y > draggedReferenceRectangle.Bottom)
{
currIndex++;
draggedReferenceRectangle.Y += draggedReferenceRectangle.Height;
draggedReferenceOffset.Y += draggedReferenceRectangle.Height;
}
draggedElement.RectTransform.RepositionChildInHierarchy(newIndex);
}
if (currIndex != index)
{
draggedElement.RectTransform.RepositionChildInHierarchy(currIndex);
HasDraggedElementIndexChanged = true;
}
return;
HasDraggedElementIndexChanged = true;
}
return true;
}
return false;
}
private void UpdateChildrenRect()
{
if (UpdateDragging()) { return; }
if (SelectTop)
{
foreach (GUIComponent child in Content.Children)
@@ -581,7 +692,7 @@ namespace Barotrauma
for (int i = 0; i < Content.CountChildren; i++)
{
var child = Content.RectTransform.GetChild(i)?.GUIComponent;
if (child == null || !child.Visible) { continue; }
if (!(child is { Visible: true })) { continue; }
// selecting
if (Enabled && (CanBeFocused || CanInteractWhenUnfocusable) && child.CanBeFocused && child.Rect.Contains(PlayerInput.MousePosition) && GUI.IsMouseOn(child))
@@ -595,19 +706,15 @@ namespace Barotrauma
if (SelectTop)
{
ScrollToElement(child);
Select(i, autoScroll: false, takeKeyBoardFocus: true);
}
else
{
Select(i, autoScroll: false, takeKeyBoardFocus: true);
}
Select(i, autoScroll: false, takeKeyBoardFocus: true);
}
if (CanDragElements && PlayerInput.PrimaryMouseButtonDown() && GUI.MouseOn == child)
if (CurrentDragMode != DragMode.NoDragging
&& (CurrentSelectMode != SelectMode.RequireShiftToSelectMultiple || (!PlayerInput.IsShiftDown() && !PlayerInput.IsCtrlDown()))
&& PlayerInput.PrimaryMouseButtonDown() && GUI.MouseOn == child)
{
DraggedElement = child;
draggedReferenceRectangle = child.Rect;
draggedReferenceOffset = child.RectTransform.AbsoluteOffset;
StartDraggingElement(child);
}
}
else if (selected.Contains(child))
@@ -686,6 +793,13 @@ namespace Barotrauma
OnAddedToGUIUpdateList?.Invoke(this);
}
public override void ForceLayoutRecalculation()
{
base.ForceLayoutRecalculation();
Content.ForceLayoutRecalculation();
ScrollBar.ForceLayoutRecalculation();
}
public void RecalculateChildren()
{
foreach (GUIComponent child in Content.Children)
@@ -709,8 +823,6 @@ namespace Barotrauma
}
}
public void ForceUpdate() => Update((float)Timing.Step);
protected override void Update(float deltaTime)
{
if (!Visible) { return; }
@@ -805,7 +917,7 @@ namespace Barotrauma
}
else
{
ScrollBar.BarScroll -= (PlayerInput.ScrollWheelSpeed / 500.0f) * BarSize;
ScrollBar.BarScroll -= (PlayerInput.ScrollWheelSpeed / 500.0f) * ScrollBar.UnclampedBarSize;
}
}
@@ -870,6 +982,7 @@ namespace Barotrauma
if (childIndex >= Content.CountChildren || childIndex < 0) { return; }
GUIComponent child = Content.GetChild(childIndex);
if (child is null) { return; }
bool wasSelected = true;
if (OnSelected != null)
@@ -880,7 +993,8 @@ namespace Barotrauma
if (!wasSelected) { return; }
if (SelectMultiple)
if (CurrentSelectMode == SelectMode.SelectMultiple ||
(CurrentSelectMode == SelectMode.RequireShiftToSelectMultiple && PlayerInput.IsCtrlDown()))
{
if (selected.Contains(child))
{
@@ -891,6 +1005,23 @@ namespace Barotrauma
selected.Add(child);
}
}
else if (CurrentSelectMode == SelectMode.RequireShiftToSelectMultiple && PlayerInput.IsShiftDown())
{
var first = SelectedComponent ?? child;
var last = child;
int firstIndex = Content.GetChildIndex(first);
int lastIndex = Content.GetChildIndex(last);
int sgn = Math.Sign(lastIndex - firstIndex);
selected.Clear(); selected.Add(first);
for (int i = firstIndex + sgn; i != lastIndex; i += sgn)
{
if (Content.GetChild(i) is { Visible: true } interChild)
{
selected.Add(interChild);
}
}
if (first != last) { selected.Add(last); }
}
else
{
selected.Clear();
@@ -937,6 +1068,14 @@ namespace Barotrauma
}
}
public void Select(IEnumerable<GUIComponent> children)
{
Selected = true;
selected.Clear();
selected.AddRange(children.Where(c => Content.Children.Contains(c)));
foreach (var child in selected) { OnSelected?.Invoke(child, child.UserData); }
}
public void Deselect()
{
Selected = false;
@@ -1007,9 +1146,12 @@ namespace Barotrauma
}
float minScrollBarSize = 20.0f;
ScrollBar.UnclampedBarSize = ScrollBar.IsHorizontal ?
Math.Min(Content.Rect.Width / (float)totalSize, 1.0f) :
Math.Min(Content.Rect.Height / (float)totalSize, 1.0f);
ScrollBar.BarSize = ScrollBar.IsHorizontal ?
Math.Max(Math.Min(Content.Rect.Width / (float)totalSize, 1.0f), minScrollBarSize / Content.Rect.Width) :
Math.Max(Math.Min(Content.Rect.Height / (float)totalSize, 1.0f), minScrollBarSize / Content.Rect.Height);
Math.Max(ScrollBar.UnclampedBarSize, minScrollBarSize / Content.Rect.Width) :
Math.Max(ScrollBar.UnclampedBarSize, minScrollBarSize / Content.Rect.Height);
}
public override void ClearChildren()
@@ -1052,10 +1194,11 @@ namespace Barotrauma
int i = 0;
foreach (GUIComponent child in Content.Children)
{
if (!child.Visible) continue;
if (!child.Visible) { continue; }
if (child == draggedElement && CurrentDragMode == DragMode.DragOutsideBox) { continue; }
if (!IsChildInsideFrame(child))
{
if (lastVisible > 0) break;
if (lastVisible > 0) { break; }
continue;
}
lastVisible = i;
@@ -1070,6 +1213,11 @@ namespace Barotrauma
spriteBatch.Begin(SpriteSortMode.Deferred, samplerState: GUI.SamplerState, rasterizerState: GameMain.ScissorTestEnable);
}
if (isDraggingElement && CurrentDragMode == DragMode.DragOutsideBox && !HideDraggedElement)
{
draggedElement.DrawManually(spriteBatch, alsoChildren: true, recursive: true);
}
if (ScrollBarVisible)
{
ScrollBar.DrawManually(spriteBatch, alsoChildren: true, recursive: true);
@@ -183,6 +183,11 @@ namespace Barotrauma
}
}
/// <summary>
/// ListBoxes with lots of content in them clamp the size of the scrollbar above a certain minimum size; this is the relative bar size without the clamping applied.
/// </summary>
public float UnclampedBarSize;
public float BarSize
{
get { return barSize; }
@@ -299,9 +304,15 @@ namespace Barotrauma
}
else
{
float barScale = 1.0f;
if (UnclampedBarSize > 0.0f)
{
barScale = (UnclampedBarSize / BarSize);
}
MoveButton(new Vector2(
Math.Sign(PlayerInput.MousePosition.X - Bar.Rect.Center.X) * Bar.Rect.Width,
Math.Sign(PlayerInput.MousePosition.Y - Bar.Rect.Center.Y) * Bar.Rect.Height));
Math.Sign(PlayerInput.MousePosition.X - Bar.Rect.Center.X) * Bar.Rect.Width * barScale,
Math.Sign(PlayerInput.MousePosition.Y - Bar.Rect.Center.Y) * Bar.Rect.Height * barScale));
}
}
}
@@ -44,6 +44,8 @@ namespace Barotrauma
public UISprite PingCircle { get; private set; }
public UISprite YouAreHereCircle { get; private set; }
public UISprite UIGlowCircular { get; private set; }
public UISprite UIGlowSolidCircular { get; private set; }
@@ -253,6 +255,9 @@ namespace Barotrauma
case "pingcircle":
PingCircle = new UISprite(subElement);
break;
case "youareherecircle":
YouAreHereCircle = new UISprite(subElement);
break;
case "radiation":
RadiationSprite = new UISprite(subElement);
break;
@@ -2,6 +2,7 @@
using Microsoft.Xna.Framework.Graphics;
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
namespace Barotrauma
@@ -376,6 +377,7 @@ namespace Barotrauma
public void SetTextPos()
{
cachedCaretPositions = ImmutableArray<Vector2>.Empty;
if (text == null) { return; }
censoredText = string.IsNullOrEmpty(text) ? "" : new string('\u2022', text.Length);
@@ -389,7 +391,7 @@ namespace Barotrauma
if (Wrap && rect.Width > 0)
{
wrappedText = ToolBox.WrapText(text, rect.Width - padding.X - padding.Z, Font, textScale, playerInput);
wrappedText = ToolBox.WrapText(text, rect.Width - padding.X - padding.Z, Font, textScale);
TextSize = MeasureText(wrappedText);
}
else if (OverflowClip)
@@ -477,108 +479,49 @@ namespace Barotrauma
disabledTextColor = color;
}
protected List<Tuple<Vector2, int>> GetAllPositions()
private ImmutableArray<Vector2> cachedCaretPositions = ImmutableArray<Vector2>.Empty;
public ImmutableArray<Vector2> GetAllCaretPositions()
{
float halfHeight = Font.MeasureString("T").Y * 0.5f * textScale;
string textDrawn = Censor ? CensoredText : WrappedText;
var positions = new List<Tuple<Vector2, int>>();
if (textDrawn.Contains("\n"))
if (cachedCaretPositions.Any())
{
string[] lines = textDrawn.Split('\n');
int index = 0;
int totalIndex = 0;
for (int i = 0; i < lines.Length; i++)
{
string line = lines[i];
totalIndex += line.Length;
float totalTextHeight = Font.MeasureString(textDrawn.Substring(0, totalIndex)).Y * textScale;
for (int j = 0; j <= line.Length; j++)
{
Vector2 lineTextSize = Font.MeasureString(line.Substring(0, j)) * textScale;
Vector2 indexPos = new Vector2(lineTextSize.X, totalTextHeight - halfHeight) + TextPos - Origin * textScale;
//DebugConsole.NewMessage($"index: {index}, pos: {indexPos}", Color.AliceBlue);
positions.Add(new Tuple<Vector2, int>(indexPos, index + j));
}
index = totalIndex;
}
return cachedCaretPositions;
}
else
{
textDrawn = Censor ? CensoredText : Text;
for (int i = 0; i <= Text.Length; i++)
{
Vector2 textSize = Font.MeasureString(textDrawn.Substring(0, i)) * textScale;
Vector2 indexPos = new Vector2(textSize.X, textSize.Y - halfHeight) + TextPos - Origin * textScale;
//DebugConsole.NewMessage($"index: {i}, pos: {indexPos}", Color.WhiteSmoke);
positions.Add(new Tuple<Vector2, int>(indexPos, i));
}
}
return positions;
string textDrawn = Censor ? CensoredText : Text;
float w = Wrap
? (Rect.Width - Padding.X - Padding.Z) / TextScale
: float.PositiveInfinity;
Font.WrapText(textDrawn, w, out Vector2[] positions);
cachedCaretPositions = positions.Select(p => p * TextScale + TextPos - Origin * TextScale).ToImmutableArray();
return cachedCaretPositions;
}
public int GetCaretIndexFromScreenPos(Vector2 pos)
public int GetCaretIndexFromScreenPos(in Vector2 pos)
{
return GetCaretIndexFromLocalPos(pos - Rect.Location.ToVector2());
}
public int GetCaretIndexFromLocalPos(Vector2 pos)
public int GetCaretIndexFromLocalPos(in Vector2 pos)
{
var positions = GetAllPositions();
if (positions.Count == 0) { return 0; }
float halfHeight = Font.MeasureString("T").Y * 0.5f * textScale;
var positions = GetAllCaretPositions();
if (positions.Length == 0) { return 0; }
var currPosition = positions[0];
float topY = positions.Min(p => p.Item1.Y);
for (int i = 1; i < positions.Count; i++)
float closestXDist = float.PositiveInfinity;
float closestYDist = float.PositiveInfinity;
int closestIndex = -1;
for (int i = 0; i < positions.Length; i++)
{
var p1 = positions[i];
var p2 = currPosition;
float diffY = Math.Abs(p1.Item1.Y - pos.Y) - Math.Abs(p2.Item1.Y - pos.Y);
if (diffY < -3.0f)
float xDist = Math.Abs(pos.X - positions[i].X);
float yDist = Math.Abs(pos.Y - (positions[i].Y + Font.LineHeight * 0.5f));
if (yDist < closestYDist || (MathUtils.NearlyEqual(yDist, closestYDist) && xDist < closestXDist))
{
currPosition = p1;
continue;
}
else if (diffY > 3.0f)
{
continue;
}
else
{
diffY = Math.Abs(p1.Item1.Y - pos.Y);
if (diffY < halfHeight || (p1.Item1.Y == topY && pos.Y < topY))
{
//we are on this line, select the nearest character
float diffX = Math.Abs(p1.Item1.X - pos.X) - Math.Abs(p2.Item1.X - pos.X);
if (diffX < -1.0f)
{
currPosition = p1; continue;
}
else
{
continue;
}
}
else
{
//we are on a different line, preserve order
if (p1.Item2 < p2.Item2)
{
if (p1.Item1.Y > pos.Y) { currPosition = p1; }
}
else if (p1.Item2 > p2.Item2)
{
if (p1.Item1.Y < pos.Y) { currPosition = p1; }
}
continue;
}
closestIndex = i;
closestXDist = xDist;
closestYDist = yDist;
}
}
//GUI.AddMessage($"index: {posIndex.Item2}, pos: {posIndex.Item1}", Color.WhiteSmoke);
return currPosition != null ? currPosition.Item2 : Text.Length;
return closestIndex >= 0 ? closestIndex : Text.Length;
}
protected override void Update(float deltaTime)
@@ -44,7 +44,7 @@ namespace Barotrauma
private int? maxTextLength;
private int _caretIndex;
private int CaretIndex
public int CaretIndex
{
get { return _caretIndex; }
set
@@ -343,34 +343,23 @@ namespace Barotrauma
private void CalculateCaretPos()
{
string textDrawn = Censor ? textBlock.CensoredText : textBlock.WrappedText;
if (textDrawn.Contains("\n"))
if (Censor || !Wrap)
{
string[] lines = textDrawn.Split('\n');
int totalIndex = 0;
for (int i = 0; i < lines.Length; i++)
{
int currentLineLength = lines[i].Length;
totalIndex += currentLineLength;
// The caret is on this line
if (CaretIndex < totalIndex || totalIndex == textBlock.Text.Length)
{
int diff = totalIndex - CaretIndex;
int index = currentLineLength - diff;
Vector2 lineTextSize = Font.MeasureString(lines[i].Substring(0, index)) * TextBlock.TextScale;
Vector2 lastLineSize = Font.MeasureString(lines[i]) * TextBlock.TextScale;
float totalTextHeight = Font.MeasureString(textDrawn.Substring(0, totalIndex)).Y * TextBlock.TextScale;
caretPos = new Vector2(lineTextSize.X, totalTextHeight - lastLineSize.Y) + textBlock.TextPos - textBlock.Origin * TextBlock.TextScale;
break;
}
}
string textDrawn = textBlock.CensoredText;
CaretIndex = Math.Min(CaretIndex, textDrawn.Length);
textDrawn = Censor ? textBlock.CensoredText : textBlock.Text;
Vector2 textSize = Font.MeasureString(textDrawn[..CaretIndex]) * TextBlock.TextScale;
caretPos = new Vector2(textSize.X, 0) + textBlock.TextPos - textBlock.Origin * TextBlock.TextScale;
}
else
{
CaretIndex = Math.Min(CaretIndex, textDrawn.Length);
textDrawn = Censor ? textBlock.CensoredText : textBlock.Text;
Vector2 textSize = Font.MeasureString(textDrawn.Substring(0, CaretIndex)) * TextBlock.TextScale;
caretPos = new Vector2(textSize.X, 0) + textBlock.TextPos - textBlock.Origin * TextBlock.TextScale;
CaretIndex = Math.Min(CaretIndex, textBlock.Text.Length);
textBlock.Font.WrapText(
textBlock.Text,
(textBlock.Rect.Width - textBlock.Padding.X - textBlock.Padding.Z) / TextBlock.TextScale,
CaretIndex,
out Vector2 requestedCharPos);
caretPos = requestedCharPos * TextBlock.TextScale + textBlock.TextPos - textBlock.Origin * TextBlock.TextScale;
}
caretPosDirty = false;
}
@@ -383,6 +372,7 @@ namespace Barotrauma
memento.Store(Text);
}
CaretIndex = forcedCaretIndex == - 1 ? textBlock.GetCaretIndexFromScreenPos(PlayerInput.MousePosition) : forcedCaretIndex;
CalculateCaretPos();
ClearSelection();
selected = true;
GUI.KeyboardDispatcher.Subscriber = this;
@@ -538,59 +528,37 @@ namespace Barotrauma
if (textBlock.WrappedText.Contains("\n"))
{
// Multiline selection
string[] lines = textBlock.WrappedText.Split('\n');
int totalIndex = 0;
int previousCharacters = 0;
Vector2 offset = textBlock.TextPos - textBlock.Origin;
for (int i = 0; i < lines.Length; i++)
var characterPositions = textBlock.GetAllCaretPositions();
(int startIndex, int endIndex) = selectionStartIndex < selectionEndIndex
? (selectionStartIndex, selectionEndIndex)
: (selectionEndIndex, selectionStartIndex);
endIndex--;
void drawRect(Vector2 topLeft, Vector2 bottomRight)
{
string currentLine = lines[i];
int currentLineLength = currentLine.Length;
totalIndex += currentLineLength;
bool containsSelection = IsLeftToRight
? selectionStartIndex < totalIndex && selectionEndIndex > previousCharacters
: selectionEndIndex < totalIndex && selectionStartIndex > previousCharacters;
if (containsSelection)
{
Vector2 currentLineSize = Font.MeasureString(currentLine) * TextBlock.TextScale;
if ((IsLeftToRight && selectionStartIndex < previousCharacters && selectionEndIndex > totalIndex)
|| !IsLeftToRight && selectionEndIndex < previousCharacters && selectionStartIndex > totalIndex)
{
// select the whole line
Vector2 topLeft = offset + new Vector2(0, currentLineSize.Y * i);
GUI.DrawRectangle(spriteBatch, Rect.Location.ToVector2() + topLeft, currentLineSize, SelectionColor, isFilled: true);
}
else
{
if (IsLeftToRight)
{
bool selectFromTheBeginning = selectionStartIndex <= previousCharacters;
int startIndex = selectFromTheBeginning ? 0 : Math.Abs(selectionStartIndex - previousCharacters);
int endIndex = Math.Abs(selectionEndIndex - previousCharacters);
int characters = Math.Min(endIndex - startIndex, currentLineLength - startIndex);
Vector2 selectedTextSize = Font.MeasureString(currentLine.Substring(startIndex, characters)) * TextBlock.TextScale;
Vector2 topLeft = selectFromTheBeginning
? new Vector2(offset.X, offset.Y + currentLineSize.Y * i)
: new Vector2(selectionStartPos.X, offset.Y + currentLineSize.Y * i);
GUI.DrawRectangle(spriteBatch, Rect.Location.ToVector2() + topLeft, selectedTextSize, SelectionColor, isFilled: true);
}
else
{
bool selectFromTheBeginning = selectionStartIndex >= totalIndex;
bool selectFromTheStart = selectionEndIndex <= previousCharacters;
int startIndex = selectFromTheBeginning ? currentLineLength : Math.Abs(selectionStartIndex - previousCharacters);
int endIndex = selectFromTheStart ? 0 : Math.Abs(selectionEndIndex - previousCharacters);
int characters = Math.Min(Math.Abs(endIndex - startIndex), currentLineLength);
Vector2 selectedTextSize = Font.MeasureString(currentLine.Substring(endIndex, characters)) * TextBlock.TextScale;
Vector2 topLeft = selectFromTheBeginning
? new Vector2(offset.X + currentLineSize.X - selectedTextSize.X, offset.Y + currentLineSize.Y * i)
: new Vector2(selectionStartPos.X - selectedTextSize.X, offset.Y + currentLineSize.Y * i);
GUI.DrawRectangle(spriteBatch, Rect.Location.ToVector2() + topLeft, selectedTextSize, SelectionColor, isFilled: true);
}
}
}
previousCharacters = totalIndex;
int minWidth = GUI.IntScale(5);
if (bottomRight.X - topLeft.X < minWidth) { bottomRight.X = topLeft.X + minWidth; }
GUI.DrawRectangle(spriteBatch,
Rect.Location.ToVector2() + topLeft,
bottomRight - topLeft,
SelectionColor, isFilled: true);
}
Vector2 topLeft = characterPositions[startIndex];
for (int i = startIndex+1; i <= endIndex; i++)
{
Vector2 currPos = characterPositions[i];
if (!MathUtils.NearlyEqual(topLeft.Y, currPos.Y))
{
Vector2 bottomRight = characterPositions[i - 1];
bottomRight += Font.MeasureChar(Text[i - 1]);
drawRect(topLeft, bottomRight);
topLeft = currPos;
}
}
Vector2 finalBottomRight = characterPositions[endIndex];
finalBottomRight += Font.MeasureChar(Text[endIndex]);
drawRect(topLeft, finalBottomRight);
}
else
{
@@ -728,8 +696,15 @@ namespace Barotrauma
{
InitSelectionStart();
}
float lineHeight = Font.MeasureString("T").Y * TextBlock.TextScale;
int newIndex = textBlock.GetCaretIndexFromLocalPos(new Vector2(caretPos.X, caretPos.Y - lineHeight));
float lineHeight = Font.LineHeight * TextBlock.TextScale;
int newIndex = textBlock.GetCaretIndexFromLocalPos(new Vector2(caretPos.X, caretPos.Y - lineHeight * 0.5f));
textBlock.Font.WrapText(
textBlock.Text,
(textBlock.Rect.Width - textBlock.Padding.X - textBlock.Padding.Z) / TextBlock.TextScale,
newIndex,
out Vector2 requestedCharPos);
requestedCharPos *= TextBlock.TextScale;
if (MathUtils.NearlyEqual(requestedCharPos.Y, caretPos.Y)) { newIndex = 0; }
CaretIndex = newIndex;
caretTimer = 0;
HandleSelection();
@@ -739,8 +714,15 @@ namespace Barotrauma
{
InitSelectionStart();
}
lineHeight = Font.MeasureString("T").Y * TextBlock.TextScale;
newIndex = textBlock.GetCaretIndexFromLocalPos(new Vector2(caretPos.X, caretPos.Y + lineHeight));
lineHeight = Font.LineHeight * TextBlock.TextScale;
newIndex = textBlock.GetCaretIndexFromLocalPos(new Vector2(caretPos.X, caretPos.Y + lineHeight * 1.5f));
textBlock.Font.WrapText(
textBlock.Text,
(textBlock.Rect.Width - textBlock.Padding.X - textBlock.Padding.Z) / TextBlock.TextScale,
newIndex,
out Vector2 requestedCharPos2);
requestedCharPos2 *= TextBlock.TextScale;
if (MathUtils.NearlyEqual(requestedCharPos2.Y, caretPos.Y)) { newIndex = Text.Length; }
CaretIndex = newIndex;
caretTimer = 0;
HandleSelection();
@@ -803,6 +785,7 @@ namespace Barotrauma
}
break;
}
if (caretPosDirty) { CalculateCaretPos(); }
OnKeyHit?.Invoke(this, key);
void HandleSelection()
{
@@ -1,5 +1,6 @@
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using System;
using System.Linq;
namespace Barotrauma
@@ -37,39 +38,44 @@ namespace Barotrauma
values[0] = newValue;
}
public void Draw(SpriteBatch spriteBatch, Rectangle rect, float? maxVal, float xOffset, Color color)
public delegate void GraphDelegate(SpriteBatch spriteBatch, float value, int order, Vector2 position);
public void Draw(SpriteBatch spriteBatch, Rectangle rect, float? maxValue = null, float xOffset = 0, Color? color = null, GraphDelegate doForEachValue = null)
{
color ??= Color.White;
float graphMaxVal = 1.0f;
if (maxVal == null)
if (maxValue == null)
{
graphMaxVal = LargestValue();
}
else if (maxVal > 0.0f)
else if (maxValue > 0.0f)
{
graphMaxVal = (float)maxVal;
graphMaxVal = (float)maxValue;
}
GUI.DrawRectangle(spriteBatch, rect, Color.White);
if (values.Length == 0) return;
if (values.Length == 0) { return; }
float lineWidth = (float)rect.Width / (float)(values.Length - 2);
float yScale = (float)rect.Height / graphMaxVal;
float lineWidth = rect.Width / (float)(values.Length - 2);
float yScale = rect.Height / graphMaxVal;
Vector2 prevPoint = new Vector2(rect.Right, rect.Bottom - (values[1] + (values[0] - values[1]) * xOffset) * yScale);
float currX = rect.Right - ((xOffset - 1.0f) * lineWidth);
for (int i = 1; i < values.Length - 1; i++)
{
float value = values[i];
currX -= lineWidth;
Vector2 newPoint = new Vector2(currX, rect.Bottom - values[i] * yScale);
GUI.DrawLine(spriteBatch, prevPoint, newPoint - new Vector2(1.0f, 0), color);
Vector2 newPoint = new Vector2(currX, rect.Bottom - value * yScale);
GUI.DrawLine(spriteBatch, prevPoint, newPoint - new Vector2(1.0f, 0), color.Value);
prevPoint = newPoint;
doForEachValue?.Invoke(spriteBatch, value, i, newPoint);
}
Vector2 lastPoint = new Vector2(rect.X,
rect.Bottom - (values[values.Length - 1] + (values[values.Length - 2] - values[values.Length - 1]) * xOffset) * yScale);
GUI.DrawLine(spriteBatch, prevPoint, lastPoint, color);
int lastIndex = values.Length - 1;
float lastValue = values[lastIndex];
Vector2 lastPoint = new Vector2(rect.X, rect.Bottom - (lastValue + (values[values.Length - 2] - lastValue) * xOffset) * yScale);
GUI.DrawLine(spriteBatch, prevPoint, lastPoint, color.Value);
doForEachValue?.Invoke(spriteBatch, lastValue, lastIndex, lastPoint);
}
}
}
@@ -379,11 +379,42 @@ namespace Barotrauma
if (currSplashScreen.IsPlaying)
{
graphics.Clear(Color.Black);
float videoAspectRatio = (float)currSplashScreen.Width / (float)currSplashScreen.Height;
int width; int height;
if (GameMain.GraphicsHeight * videoAspectRatio > GameMain.GraphicsWidth)
{
width = GameMain.GraphicsWidth;
height = (int)(GameMain.GraphicsWidth / videoAspectRatio);
}
else
{
width = (int)(GameMain.GraphicsHeight * videoAspectRatio);
height = GameMain.GraphicsHeight;
}
spriteBatch.Begin();
spriteBatch.Draw(currSplashScreen.GetTexture(), new Rectangle(0, 0, GameMain.GraphicsWidth, GameMain.GraphicsHeight), Color.White);
spriteBatch.Draw(
currSplashScreen.GetTexture(),
destinationRectangle: new Rectangle(
GameMain.GraphicsWidth / 2 - width / 2,
GameMain.GraphicsHeight / 2 - height / 2,
width,
height),
sourceRectangle: new Rectangle(0, 0, currSplashScreen.Width, currSplashScreen.Height),
Color.White,
rotation: 0.0f,
origin: Vector2.Zero,
SpriteEffects.None,
layerDepth: 0.0f);
spriteBatch.End();
if (DateTime.Now > videoStartTime + new TimeSpan(0, 0, 0, 0, milliseconds: 500) && GameMain.WindowActive && (PlayerInput.KeyHit(Keys.Escape) || PlayerInput.KeyHit(Keys.Space) || PlayerInput.KeyHit(Keys.Enter) || PlayerInput.PrimaryMouseButtonDown()))
if (DateTime.Now > videoStartTime + new TimeSpan(0, 0, 0, 0, milliseconds: 500)
&& GameMain.WindowActive
&& (PlayerInput.KeyHit(Keys.Escape)
|| PlayerInput.KeyHit(Keys.Space)
|| PlayerInput.KeyHit(Keys.Enter)
|| PlayerInput.PrimaryMouseButtonDown()))
{
currSplashScreen.Dispose(); currSplashScreen = null;
}
@@ -395,7 +426,7 @@ namespace Barotrauma
}
bool drawn;
public IEnumerable<object> DoLoading(IEnumerable<object> loader)
public IEnumerable<CoroutineStatus> DoLoading(IEnumerable<CoroutineStatus> loader)
{
drawn = false;
LoadState = null;
@@ -732,7 +732,7 @@ namespace Barotrauma
CoroutineManager.StartCoroutine(DoScaleAnimation(targetSize, duration));
}
private IEnumerable<object> DoMoveAnimation(Point targetPos, float duration)
private IEnumerable<CoroutineStatus> DoMoveAnimation(Point targetPos, float duration)
{
Vector2 startPos = AbsoluteOffset.ToVector2();
float t = 0.0f;
@@ -746,7 +746,7 @@ namespace Barotrauma
animTargetPos = null;
yield return CoroutineStatus.Success;
}
private IEnumerable<object> DoScaleAnimation(Point targetSize, float duration)
private IEnumerable<CoroutineStatus> DoScaleAnimation(Point targetSize, float duration)
{
Vector2 startSize = NonScaledSize.ToVector2();
float t = 0.0f;
@@ -151,9 +151,8 @@ namespace Barotrauma
/// </summary>
public static void DrawPoint(this SpriteBatch spriteBatch, Vector2 position, Color color, float size = 1f)
{
var scale = Vector2.One * size;
var offset = new Vector2(0.5f) - new Vector2(size * 0.5f);
spriteBatch.Draw(GetTexture(spriteBatch), position + offset, null, color, 0.0f, Vector2.Zero, Vector2.One, SpriteEffects.None, 0);
spriteBatch.Draw(GetTexture(spriteBatch), position + offset, null, color, 0.0f, Vector2.Zero, new Vector2(size), SpriteEffects.None, 0);
}
public static void DrawCircle(this SpriteBatch spriteBatch, Vector2 center, float radius, int sides, Color color,
@@ -266,7 +266,7 @@ namespace Barotrauma
};
if (balanceAfterTransaction != CurrentLocation.StoreCurrentBalance)
{
var newStatus = Location.GetStoreBalanceStatus(balanceAfterTransaction);
var newStatus = CurrentLocation.GetStoreBalanceStatus(balanceAfterTransaction);
if (CurrentLocation.ActiveStoreBalanceStatus.SellPriceModifier != newStatus.SellPriceModifier)
{
string tooltipTag = newStatus.SellPriceModifier > CurrentLocation.ActiveStoreBalanceStatus.SellPriceModifier ?
@@ -471,7 +471,7 @@ namespace Barotrauma
}
// Initial submarine selection needs a slight wait to allow the layoutgroups to place content properly
private IEnumerable<object> SelectOwnSubmarineWithDelay(SubmarineInfo info, SubmarineDisplayContent display)
private IEnumerable<CoroutineStatus> SelectOwnSubmarineWithDelay(SubmarineInfo info, SubmarineDisplayContent display)
{
yield return new WaitForSeconds(0.05f);
SelectSubmarine(info, display.background.Rect);
@@ -1541,13 +1541,41 @@ namespace Barotrauma
GUITextBlock.AutoScaleAndNormalize(skillNames);
}
private bool HasUnlockedAllTalents(Character controlledCharacter)
{
if (TalentTree.JobTalentTrees.TryGetValue(controlledCharacter.Info.Job.Prefab.Identifier, out TalentTree talentTree))
{
foreach (TalentSubTree talentSubTree in talentTree.TalentSubTrees)
{
foreach (TalentOption talentOption in talentSubTree.TalentOptionStages)
{
if (talentOption.Talents.None(t => controlledCharacter.HasTalent(t.Identifier)))
{
return false;
}
}
}
}
return true;
}
private void UpdateTalentButtons()
{
Character controlledCharacter = Character.Controlled;
if (controlledCharacter?.Info == null) { return; }
experienceText.Text = $"{controlledCharacter.Info.ExperiencePoints - controlledCharacter.Info.GetExperienceRequiredForCurrentLevel()} / {controlledCharacter.Info.GetExperienceRequiredToLevelUp() - controlledCharacter.Info.GetExperienceRequiredForCurrentLevel()}";
experienceBar.BarSize = controlledCharacter.Info.GetProgressTowardsNextLevel();
//experienceBar.ToolTip = $"{controlledCharacter.Info.ExperiencePoints - controlledCharacter.Info.GetExperienceRequiredForCurrentLevel()} / {controlledCharacter.Info.GetExperienceRequiredToLevelUp() - controlledCharacter.Info.GetExperienceRequiredForCurrentLevel()}";
bool unlockedAllTalents = HasUnlockedAllTalents(controlledCharacter);
if (unlockedAllTalents)
{
experienceText.Text = string.Empty;
experienceBar.BarSize = 1f;
}
else
{
experienceText.Text = $"{controlledCharacter.Info.ExperiencePoints - controlledCharacter.Info.GetExperienceRequiredForCurrentLevel()} / {controlledCharacter.Info.GetExperienceRequiredToLevelUp() - controlledCharacter.Info.GetExperienceRequiredForCurrentLevel()}";
experienceBar.BarSize = controlledCharacter.Info.GetProgressTowardsNextLevel();
}
selectedTalents = TalentTree.CheckTalentSelection(controlledCharacter, selectedTalents);
@@ -1555,7 +1583,11 @@ namespace Barotrauma
int talentCount = selectedTalents.Count - controlledCharacter.Info.GetUnlockedTalentsInTree().Count();
if (talentCount > 0)
if (unlockedAllTalents)
{
talentPointText.SetRichText($"‖color:{XMLExtensions.ToStringHex(Color.Gray)}‖{TextManager.Get("talentmenu.alltalentsunlocked")}‖color:end‖");
}
else if (talentCount > 0)
{
string pointsUsed = $"‖color:{XMLExtensions.ColorToString(GUI.Style.Red)}‖{-talentCount}‖color:end‖";
string localizedString = TextManager.GetWithVariables("talentmenu.points.spending", new []{ "[amount]", "[used]" }, new []{ pointsLeft, pointsUsed});