Vibe search feature
This commit is contained in:
@@ -4,7 +4,7 @@ sessionId: session-260928-112553-atgt
|
|||||||
|
|
||||||
# Delivery Steps
|
# Delivery Steps
|
||||||
|
|
||||||
### * Step 1: Implementation
|
### ✓ Step 1: Implementation
|
||||||
<plan_session_history>
|
<plan_session_history>
|
||||||
History processor: During the current session, you have worked on the following `<previous_issue>`.
|
History processor: During the current session, you have worked on the following `<previous_issue>`.
|
||||||
The `<issue_description>` usually continues or extends your previous work. Consider all `<previous_issue>` and `<issue_description>` together.
|
The `<issue_description>` usually continues or extends your previous work. Consider all `<previous_issue>` and `<issue_description>` together.
|
||||||
@@ -59,6 +59,18 @@ System.TypeLoadException: Method 'get_HasExplicitSafeAreaEdges' in type 'Microso
|
|||||||
tool name: submit
|
tool name: submit
|
||||||
tool parameters:
|
tool parameters:
|
||||||
</previous_issue_solution>
|
</previous_issue_solution>
|
||||||
|
<previous_issue>
|
||||||
|
## Orchestrated Plan Task
|
||||||
|
implement according to the plan
|
||||||
|
</previous_issue>
|
||||||
|
<previous_issue>
|
||||||
|
## Plan Task
|
||||||
|
Add a search feature to the editor that will highlight matching nodes in the ZeroSpace.MapEditor
|
||||||
|
</previous_issue>
|
||||||
|
<previous_issue_solution>
|
||||||
|
tool name: submit
|
||||||
|
tool parameters:
|
||||||
|
</previous_issue_solution>
|
||||||
</plan_session_history>
|
</plan_session_history>
|
||||||
|
|
||||||
<plan_task>
|
<plan_task>
|
||||||
|
|||||||
-61660
File diff suppressed because one or more lines are too long
@@ -27,4 +27,6 @@ public sealed class MapNode
|
|||||||
}
|
}
|
||||||
|
|
||||||
public bool IsSelected { get; set; }
|
public bool IsSelected { get; set; }
|
||||||
|
|
||||||
|
public bool IsHighlighted { get; set; }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -58,11 +58,18 @@ public sealed class MapDrawable : IDrawable
|
|||||||
canvas.FillColor = ColorForKind(node.Doc.Kind);
|
canvas.FillColor = ColorForKind(node.Doc.Kind);
|
||||||
canvas.FillCircle(center, radius);
|
canvas.FillCircle(center, radius);
|
||||||
|
|
||||||
|
if (node.IsHighlighted)
|
||||||
|
{
|
||||||
|
canvas.StrokeColor = Color.FromArgb("#FFD700");
|
||||||
|
canvas.StrokeSize = 3;
|
||||||
|
canvas.DrawCircle(center, radius + 4);
|
||||||
|
}
|
||||||
|
|
||||||
if (node.IsSelected)
|
if (node.IsSelected)
|
||||||
{
|
{
|
||||||
canvas.StrokeColor = Colors.White;
|
canvas.StrokeColor = Colors.White;
|
||||||
canvas.StrokeSize = 3;
|
canvas.StrokeSize = 3;
|
||||||
canvas.DrawCircle(center, radius + 6);
|
canvas.DrawCircle(center, node.IsHighlighted ? radius + 8 : radius + 6);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,6 +10,11 @@
|
|||||||
<Button Text="+" WidthRequest="44" Clicked="OnZoomInClicked" />
|
<Button Text="+" WidthRequest="44" Clicked="OnZoomInClicked" />
|
||||||
<Button Text="−" WidthRequest="44" Clicked="OnZoomOutClicked" />
|
<Button Text="−" WidthRequest="44" Clicked="OnZoomOutClicked" />
|
||||||
<Button Text="Reset View" Clicked="OnResetViewClicked" />
|
<Button Text="Reset View" Clicked="OnResetViewClicked" />
|
||||||
|
<SearchBar x:Name="SearchControl"
|
||||||
|
Placeholder="Search systems..."
|
||||||
|
WidthRequest="220"
|
||||||
|
TextChanged="OnSearchTextChanged"
|
||||||
|
SearchButtonPressed="OnSearchButtonPressed" />
|
||||||
<Label x:Name="StatusLabel"
|
<Label x:Name="StatusLabel"
|
||||||
Text="No folder loaded."
|
Text="No folder loaded."
|
||||||
VerticalOptions="Center"
|
VerticalOptions="Center"
|
||||||
|
|||||||
@@ -82,6 +82,84 @@ public partial class MapEditorPage : ContentPage
|
|||||||
FitView();
|
FitView();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void CenterOnNode(MapNode node)
|
||||||
|
{
|
||||||
|
var width = MapView.Width;
|
||||||
|
var height = MapView.Height;
|
||||||
|
if (width > 0 && height > 0)
|
||||||
|
{
|
||||||
|
_drawable.OffsetX = width / 2 - node.X * _drawable.Scale;
|
||||||
|
_drawable.OffsetY = height / 2 - node.Y * _drawable.Scale;
|
||||||
|
MapView.Invalidate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----- search -----
|
||||||
|
|
||||||
|
private void OnSearchTextChanged(object? sender, TextChangedEventArgs e) => ApplySearch(e.NewTextValue);
|
||||||
|
|
||||||
|
private void OnSearchButtonPressed(object? sender, EventArgs e)
|
||||||
|
{
|
||||||
|
ApplySearch(SearchControl.Text);
|
||||||
|
FocusFirstMatch();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ApplySearch(string? query)
|
||||||
|
{
|
||||||
|
var trimmed = query?.Trim();
|
||||||
|
if (string.IsNullOrEmpty(trimmed))
|
||||||
|
{
|
||||||
|
foreach (var node in _nodes)
|
||||||
|
{
|
||||||
|
node.IsHighlighted = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_folder is not null)
|
||||||
|
{
|
||||||
|
StatusLabel.Text = $"{_nodes.Count} systems loaded from {_folder}.";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
StatusLabel.Text = "No folder loaded.";
|
||||||
|
}
|
||||||
|
|
||||||
|
MapView.Invalidate();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var matchCount = 0;
|
||||||
|
foreach (var node in _nodes)
|
||||||
|
{
|
||||||
|
var isMatch = node.Doc.Name.Contains(trimmed, StringComparison.OrdinalIgnoreCase);
|
||||||
|
node.IsHighlighted = isMatch;
|
||||||
|
if (isMatch)
|
||||||
|
{
|
||||||
|
matchCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (matchCount == 0)
|
||||||
|
{
|
||||||
|
StatusLabel.Text = $"No systems matching '{trimmed}'.";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
StatusLabel.Text = $"Found {matchCount} matching system{(matchCount == 1 ? string.Empty : "s")}.";
|
||||||
|
}
|
||||||
|
|
||||||
|
MapView.Invalidate();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void FocusFirstMatch()
|
||||||
|
{
|
||||||
|
var match = _nodes.FirstOrDefault(static n => n.IsHighlighted);
|
||||||
|
if (match is not null)
|
||||||
|
{
|
||||||
|
Select(match);
|
||||||
|
CenterOnNode(match);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// ----- pointer interaction -----
|
// ----- pointer interaction -----
|
||||||
|
|
||||||
private MapNode? HitTest(Point screen)
|
private MapNode? HitTest(Point screen)
|
||||||
@@ -321,8 +399,16 @@ public partial class MapEditorPage : ContentPage
|
|||||||
FitView();
|
FitView();
|
||||||
Preferences.Set("MapEditorFolder", folder);
|
Preferences.Set("MapEditorFolder", folder);
|
||||||
UpdateDirtyState();
|
UpdateDirtyState();
|
||||||
|
|
||||||
|
if (!string.IsNullOrWhiteSpace(SearchControl.Text))
|
||||||
|
{
|
||||||
|
ApplySearch(SearchControl.Text);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
StatusLabel.Text = $"{_nodes.Count} systems loaded from {folder}.";
|
StatusLabel.Text = $"{_nodes.Count} systems loaded from {folder}.";
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private async void OnOpenFolderClicked(object? sender, EventArgs e)
|
private async void OnOpenFolderClicked(object? sender, EventArgs e)
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user