Skip to content

Commit

Permalink
Fix ComboBox to allow for better text corrections;
Browse files Browse the repository at this point in the history
  • Loading branch information
onepiecefreak3 committed Aug 25, 2024
1 parent 3ae0e05 commit 73fbbd6
Show file tree
Hide file tree
Showing 2 changed files with 64 additions and 37 deletions.
99 changes: 63 additions & 36 deletions ImGui.Forms/Controls/ComboBox.cs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ public class ComboBox<TItem> : Component
public uint MaxShowItems { get; set; } = 10;

#region Events

public event EventHandler SelectedItemChanged;

#endregion
Expand Down Expand Up @@ -92,7 +92,7 @@ protected override unsafe void UpdateInternal(Rectangle contentRect)
ImGuiNET.ImGui.Separator();
foreach (ComboBoxItem<TItem> item in Items)
{
if (!ImGuiNET.ImGui.Selectable(item.Name))
if (!ImGuiNET.ImGui.Selectable(item.Name))
continue;

_input = item.Name;
Expand All @@ -115,73 +115,100 @@ private void OnSelectedItemChanged()
SelectedItemChanged?.Invoke(this, EventArgs.Empty);
}

private bool Identical(string buf, string item)
{
//Check if the item length is shorter or equal --> exclude
if (buf.Length >= item.Length)
return false;

for (var i = 0; i < buf.Length; ++i)
// set the current pos if matching or return the pos if not
if (buf[i] != item[i])
return false;

// Complete match
// and the item size is greater --> include
return true;
}
private string? _prevBuffer;

Check warning on line 118 in ImGui.Forms/Controls/ComboBox.cs

View workflow job for this annotation

GitHub Actions / build

The annotation for nullable reference types should only be used in code within a '#nullable' annotations context.
private string? _prevMatch;

Check warning on line 119 in ImGui.Forms/Controls/ComboBox.cs

View workflow job for this annotation

GitHub Actions / build

The annotation for nullable reference types should only be used in code within a '#nullable' annotations context.

private unsafe int Propose(ImGuiInputTextCallbackData* data)
{
var dataPtr = new ImGuiInputTextCallbackDataPtr(data);
string bufferString = Marshal.PtrToStringUTF8(dataPtr.Buf);
if (bufferString == null)
return 0;

if (dataPtr.SelectionEnd != dataPtr.SelectionStart && bufferString[..dataPtr.SelectionStart] == _prevBuffer)
return 0;

// We don't want to "preselect" anything
if (dataPtr.BufTextLen == 0)
return 0;

// We need to give the user a chance to remove wrong input
if (dataPtr.EventKey == ImGuiKey.Backspace)
if (ImGuiNET.ImGui.IsKeyPressed(ImGuiKey.Backspace))
{
// We delete the last char automatically, since it is what the user wants to delete, but only if there is something (selected/marked/hovered)
// FIXME: This worked fine, when not used as helper function
if (data->SelectionEnd == data->SelectionStart)
if (_prevBuffer != bufferString)
return 0;

if (data->BufTextLen <= 0)
if (dataPtr.BufTextLen <= 0)
return 0; //...and the buffer isn't empty

if (data->CursorPos > 0) //...and the cursor not at pos 0
dataPtr.DeleteChars(data->CursorPos - 1, 1);
if (dataPtr.CursorPos > 0) //...and the cursor not at pos 0
dataPtr.DeleteChars(dataPtr.CursorPos - 1, 1);

return 0;
}

if (dataPtr.EventKey == ImGuiKey.Delete)
if (ImGuiNET.ImGui.IsKeyPressed(ImGuiKey.Delete))
return 0;

string bufferString = Marshal.PtrToStringUTF8(dataPtr.Buf);
int prevDiff = -1;
string? itemName = null;

Check warning on line 156 in ImGui.Forms/Controls/ComboBox.cs

View workflow job for this annotation

GitHub Actions / build

The annotation for nullable reference types should only be used in code within a '#nullable' annotations context.

foreach (ComboBoxItem<TItem> item in Items)
{
if (!Identical(bufferString, item.Name))
if (!Identical(bufferString, item.Name, out int diff))
continue;

int cursor = data->CursorPos;
if (prevDiff < 0 || diff < prevDiff)
{
prevDiff = diff;
itemName = item.Name;
}

//Insert the first match
dataPtr.DeleteChars(0, data->BufTextLen);
dataPtr.InsertChars(0, item.Name);
if (prevDiff == 0)
break;
}

//Reset the cursor position
data->CursorPos = cursor;
_prevBuffer = bufferString;
_prevMatch = itemName;

//Select the text, so the user can simply go on writing
data->SelectionStart = cursor;
data->SelectionEnd = data->BufTextLen;
if (itemName == null)
return 0;

break;
}
int cursor = dataPtr.CursorPos;

// Insert the first match
dataPtr.DeleteChars(0, dataPtr.BufTextLen);
dataPtr.InsertChars(0, itemName);

// Reset the cursor position
dataPtr.CursorPos = cursor;

// Select the text, so the user can simply go on writing
dataPtr.SelectionStart = cursor;
dataPtr.SelectionEnd = dataPtr.BufTextLen;

return 0;
}

private bool Identical(string buf, string item, out int diff)
{
diff = 0;

// Check if the item length is shorter or equal --> exclude
if (buf.Length > item.Length)
return false;

for (var i = 0; i < buf.Length; ++i)
// set the current pos if matching or return the pos if not
if (buf[i] != item[i])
return false;

// Complete match
// and the item size is greater --> include
diff = item.Length - buf.Length;
return true;
}
}
}
2 changes: 1 addition & 1 deletion ImGui.Forms/ImGui.Forms.nuspec
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<package >
<metadata>
<id>Imgui.Forms</id>
<version>1.0.61</version>
<version>1.0.62</version>
<description>A WinForms-inspired object-oriented framework around Dear ImGui (https://github.com/ocornut/imgui)</description>

<authors>onepiecefreak</authors>
Expand Down

0 comments on commit 73fbbd6

Please sign in to comment.