Skip to content

Commit c63d595

Browse files
committed
feat(ContentSourceHoverTips): enhance hover tip functionality with usability checks and scene path constants
- Added constants for hover tip scene paths to improve maintainability. - Implemented usability checks for nodes in various methods to prevent errors and ensure proper functionality. - Updated methods to use safe addition and removal of nodes, enhancing stability in hover tip management.
1 parent 852fc7c commit c63d595

1 file changed

Lines changed: 54 additions & 9 deletions

File tree

Content/Patches/ContentSourceHoverTipPatches.cs

Lines changed: 54 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ internal static class ContentSourceHoverTipPatchHelper
2323
{
2424
private const string EventBadgeNodeName = "RitsuLibContentSourceBadge";
2525
private const string EventDrawerHotZoneName = "RitsuLibContentSourceHotZone";
26+
private const string HoverTipScenePath = "res://scenes/ui/hover_tip.tscn";
27+
private const string HoverTipSetScenePath = "res://scenes/ui/hover_tip_set.tscn";
2628
private const float EventTipWidth = 360f;
2729
private const float EventTipRightMargin = 42f;
2830
private const float EventTipBottomMargin = 38f;
@@ -74,6 +76,9 @@ private static HoverTip CreateSourceTip(ContentSourceHoverTipFactory.ContentSour
7476

7577
internal static void UpdateEventSourceBadge(NEventLayout layout, EventModel eventModel)
7678
{
79+
if (!IsNodeUsable(layout))
80+
return;
81+
7782
var existing = layout.GetNodeOrNull<NHoverTipSet>(EventBadgeNodeName);
7883
var existingHotZone = layout.GetNodeOrNull<Control>(EventDrawerHotZoneName);
7984
if (!RitsuLibSettingsStore.IsModSourceHoverTipsEnabled() ||
@@ -96,8 +101,8 @@ internal static void UpdateEventSourceBadge(NEventLayout layout, EventModel even
96101
RemoveBadge(layout, existingHotZone);
97102
var tipSet = CreateEventSourceTipSet(layout, source);
98103
var hotZone = CreateEventSourceHotZone();
99-
layout.AddChild(tipSet);
100-
layout.AddChild(hotZone);
104+
layout.AddChildSafely(tipSet);
105+
layout.AddChildSafely(hotZone);
101106
tipSet.Visible = true;
102107
Callable.From(() => PopulateAndPositionEventSourceTipSet(layout, tipSet, hotZone, source)).CallDeferred();
103108
}
@@ -106,7 +111,7 @@ private static NHoverTipSet CreateEventSourceTipSet(Control owner,
106111
ContentSourceHoverTipFactory.ContentSourceInfo source)
107112
{
108113
var tipSet = PreloadManager.Cache
109-
.GetScene("res://scenes/ui/hover_tip_set.tscn")
114+
.GetScene(HoverTipSetScenePath)
110115
.Instantiate<NHoverTipSet>();
111116
tipSet.Name = EventBadgeNodeName;
112117
tipSet.MouseFilter = Control.MouseFilterEnum.Ignore;
@@ -121,7 +126,7 @@ private static void PopulateAndPositionEventSourceTipSet(
121126
Control hotZone,
122127
ContentSourceHoverTipFactory.ContentSourceInfo source)
123128
{
124-
if (!GodotObject.IsInstanceValid(tipSet) || !GodotObject.IsInstanceValid(hotZone))
129+
if (!IsEventSourceBadgeUsable(layout, tipSet, hotZone))
125130
return;
126131

127132
if (tipSet._textHoverTipContainer == null)
@@ -131,6 +136,9 @@ private static void PopulateAndPositionEventSourceTipSet(
131136
return;
132137
}
133138

139+
if (!IsNodeUsable(tipSet._textHoverTipContainer))
140+
return;
141+
134142
AddHoverTipControl(tipSet, new(ContentSourceHoverTipFactory.GetTitle(), source.Format())
135143
{
136144
Id = "ritsulib:event_content_source:" + source.Id,
@@ -142,8 +150,11 @@ private static void PopulateAndPositionEventSourceTipSet(
142150

143151
private static void AddHoverTipControl(NHoverTipSet tipSet, HoverTip hoverTip)
144152
{
153+
if (!IsNodeUsable(tipSet) || !IsNodeUsable(tipSet._textHoverTipContainer))
154+
return;
155+
145156
var tipControl = PreloadManager.Cache
146-
.GetScene("res://scenes/ui/hover_tip.tscn")
157+
.GetScene(HoverTipScenePath)
147158
.Instantiate<Control>();
148159
tipSet._textHoverTipContainer.AddChildSafely(tipControl);
149160

@@ -172,20 +183,30 @@ private static Control CreateEventSourceHotZone()
172183

173184
private static void ConfigureEventSourceTipDrawer(Control layout, NHoverTipSet tipSet, Control hotZone)
174185
{
186+
if (!IsEventSourceBadgeUsable(layout, tipSet, hotZone) ||
187+
!IsNodeUsable(tipSet._textHoverTipContainer))
188+
return;
189+
175190
var textContainer = tipSet._textHoverTipContainer;
176191
textContainer.MouseFilter = Control.MouseFilterEnum.Ignore;
177192
var isExpanded = false;
178193
hotZone.Connect(
179194
Control.SignalName.MouseEntered,
180195
Callable.From(() =>
181196
{
197+
if (!IsEventSourceBadgeUsable(layout, tipSet, hotZone))
198+
return;
199+
182200
isExpanded = true;
183201
PositionEventSourceTipSet(layout, tipSet, true, true);
184202
}));
185203
hotZone.Connect(
186204
Control.SignalName.MouseExited,
187205
Callable.From(() =>
188206
{
207+
if (!IsEventSourceBadgeUsable(layout, tipSet, hotZone))
208+
return;
209+
189210
if (isExpanded)
190211
PositionEventSourceTipSet(layout, tipSet, false, true);
191212
isExpanded = false;
@@ -195,13 +216,20 @@ private static void ConfigureEventSourceTipDrawer(Control layout, NHoverTipSet t
195216
if (inputEvent is not InputEventMouseButton { Pressed: true, ButtonIndex: MouseButton.Left })
196217
return;
197218

219+
if (!IsEventSourceBadgeUsable(layout, tipSet, hotZone))
220+
return;
221+
198222
isExpanded = !isExpanded;
199223
PositionEventSourceTipSet(layout, tipSet, isExpanded, true);
200224
};
201225
}
202226

203227
private static void PositionEventSourceHotZone(Control layout, NHoverTipSet tipSet, Control hotZone)
204228
{
229+
if (!IsEventSourceBadgeUsable(layout, tipSet, hotZone) ||
230+
!IsNodeUsable(tipSet._textHoverTipContainer))
231+
return;
232+
205233
var viewportSize = NGame.Instance?.GetViewportRect().Size ?? layout.GetViewportRect().Size;
206234
var textContainer = tipSet._textHoverTipContainer;
207235
var height = Math.Max(EventTipHotZoneMinHeight,
@@ -213,7 +241,7 @@ private static void PositionEventSourceHotZone(Control layout, NHoverTipSet tipS
213241

214242
private static void PositionEventSourceTipSet(Control layout, NHoverTipSet tipSet, bool expanded, bool animate)
215243
{
216-
if (!GodotObject.IsInstanceValid(tipSet))
244+
if (!IsNodeUsable(layout) || !IsNodeUsable(tipSet) || !IsNodeUsable(tipSet._textHoverTipContainer))
217245
return;
218246

219247
var viewportSize = NGame.Instance?.GetViewportRect().Size ?? layout.GetViewportRect().Size;
@@ -237,11 +265,28 @@ private static void PositionEventSourceTipSet(Control layout, NHoverTipSet tipSe
237265

238266
private static void RemoveBadge(Node owner, Node? badge)
239267
{
240-
if (badge == null)
268+
if (!IsNodeUsable(owner) || badge == null || !IsNodeUsable(badge))
241269
return;
242270

243-
owner.RemoveChild(badge);
244-
badge.QueueFree();
271+
if (badge.GetParent() == owner)
272+
owner.RemoveChildSafely(badge);
273+
badge.QueueFreeSafely();
274+
}
275+
276+
private static bool IsEventSourceBadgeUsable(Control layout, NHoverTipSet tipSet, Control hotZone)
277+
{
278+
return IsNodeUsable(layout) &&
279+
IsNodeUsable(tipSet) &&
280+
IsNodeUsable(hotZone) &&
281+
tipSet.GetParent() == layout &&
282+
hotZone.GetParent() == layout;
283+
}
284+
285+
private static bool IsNodeUsable(Node? node)
286+
{
287+
return node != null &&
288+
GodotObject.IsInstanceValid(node) &&
289+
!node.IsQueuedForDeletion();
245290
}
246291
}
247292

0 commit comments

Comments
 (0)