The online racing simulator
Insim Button
(16 posts, started , go to first unread)
Insim Button
Alright so im very noob in TCP programming and just started Insim and i have seen React-node-insim
im very impressed with the Text box mainly and im wondering if i can do it in C# if so how? any explanation would be huge help for me im just trying to make it for Fun i know i dont expect much help from people but it better than nothing Big grin
Quote from WildGamerz :Alright so im very noob in TCP programming and just started Insim and i have...

What exactly are you trying to achieve? This is all really vague..
I'm sorry but why do people tend to switch to DM all the time after asking a question? The point of this being in a public forum is that anyone can contribute and help you out. You can just continue in this thread.
my bad i mean he online and i got his dm already so thought like that xd mb
You can view the source code of the TextBox component: https://github.com/simbroadcasts/react-node-insim/blob/main/src/lib/components/ui/TextBox.tsx

I think the logic and button structure could be rewritten into C# - it's a bunch of InSim buttons carefully placed together with some logic handling the scroll position and text splitting into multiple lines, but the part about displaying and updating the buttons needs to be handled differently since C# doesn't have a renderer like I have in React Node InSim.
i did think of that but thought that react node used single button to make all that
and i have a 1 more question does putting ReqI = 1 to both same buttons but with different contents can be displayed i tired it but it not working just wondering if it can work
You can use the same ReqI for multiple buttons (React Node InSim always uses 1 too), but each button must have a unique ClickID (0-239).
Ah yes, the multi-button text component. I really like those.

Nothing like that exists in InSimDotNet. Ideally, you'd need to make a function for something like that, but absolutely achievable.

EDIT:
If i were to do this, I'd make some sort of ButtonBuilder class which would take care of this. But for the sake of simplicity, a function is best.
Thanks for the Help guys i did make it now it working fine exactly like text box from the react node
How about showing your c# button code here such that someone else may use it in the future?
Sure Give me 5mins
Alright here the program.cs press S to show the buttons and h to hide them ofc and it not even that refined but it better than nothing Smile


using System;
using System.Collections.Generic;
using System.Linq;
using InSimDotNet;
using InSimDotNet.Packets;

namespace MultiLineButton
{
public class MultiLineButton
{
private readonly InSim _inSim;
private readonly byte _clickId;
private readonly byte _ucid;
private readonly byte _width;
private readonly byte _height;
private readonly byte _top;
private readonly byte _left;
private readonly byte _rowHeight;
private readonly byte _maxCharsPerRow;
private readonly string _text;
private readonly bool _showScrollbar;
private readonly ButtonStyles _style;
private readonly List<string> _lines;
private int _scrollPosition;
private readonly byte _scrollbarWidth;
private readonly Dictionary<byte, ButtonInfo> _buttonInfo;

private struct ButtonInfo
{
public ButtonType Type { get; set; }
public string Text { get; set; }
}

private enum ButtonType
{
Background,
TextLine,
ScrollUp,
ScrollTrack,
ScrollDown
}

public MultiLineButton(
InSim inSim,
byte clickId,
byte ucid,
byte width,
byte height,
byte top,
byte left,
byte rowHeight,
byte maxCharsPerRow,
string text,
ButtonStyles style = ButtonStyles.ISB_DARK)
{
_inSim = inSim;
_clickId = clickId;
_ucid = ucid;
_width = width;
_height = height;
_top = top;
_left = left;
_rowHeight = rowHeight;
_maxCharsPerRow = maxCharsPerRow;
_text = text;
_style = style;
_scrollPosition = 0;
_scrollbarWidth = (byte)Math.Max(4, Math.Round(rowHeight * 0.75));
_buttonInfo = new Dictionary<byte, ButtonInfo>();
_lines = SplitTextIntoLines(text, maxCharsPerRow);
_showScrollbar = _lines.Count * rowHeight > height;

// Setup event handlers
_inSim.Bind<IS_BTC>((inSim, packet) => HandleButtonClick(packet));
}

public void Show()
{
DrawButtons();
LogButtonInfo();
}

public void Hide()
{
ClearButtons();
}

private void DrawButtons()
{
ClearButtons();
var textAreaWidth = (byte)(_showScrollbar ? _width - _scrollbarWidth : _width);
var maxVisibleRows = _height / _rowHeight;

// Background button
SendButton(
_clickId,
_top,
_left,
_width,
_height,
"",
_style | ButtonStyles.ISB_DARK,
ButtonType.Background
);

// Draw scrollbar if needed
if (_showScrollbar)
{
var canScrollUp = _scrollPosition > 0;
var canScrollDown = _scrollPosition + maxVisibleRows < _lines.Count;
var scrollbarLeft = (byte)(_left + textAreaWidth);

// Up arrow
if (canScrollUp)
{
SendButton(
(byte)(_clickId + 1),
_top,
scrollbarLeft,
_scrollbarWidth,
_rowHeight,
"▲",
_style | ButtonStyles.ISB_CLICK | ButtonStyles.ISB_DARK,
ButtonType.ScrollUp
);
}

// Scrollbar track
if (maxVisibleRows > 2)
{
var scrollbarHeight = (byte)(_height - (2 * _rowHeight));
var scrollbarThumbHeight = (byte)(scrollbarHeight * maxVisibleRows / Math.Max(1, _lines.Count));
var scrollbarPosition = (byte)(_top + _rowHeight +
(_scrollPosition * (scrollbarHeight - scrollbarThumbHeight) /
Math.Max(1, _lines.Count - maxVisibleRows)));

SendButton(
(byte)(_clickId + 2),
scrollbarPosition,
scrollbarLeft,
_scrollbarWidth,
scrollbarThumbHeight,
"",
_style | ButtonStyles.ISB_DARK,
ButtonType.ScrollTrack
);
}

// Down arrow
if (canScrollDown)
{
SendButton(
(byte)(_clickId + 3),
(byte)(_top + _height - _rowHeight),
scrollbarLeft,
_scrollbarWidth,
_rowHeight,
"▼",
_style | ButtonStyles.ISB_CLICK | ButtonStyles.ISB_DARK,
ButtonType.ScrollDown
);
}
}

// Draw text lines
byte currentId = (byte)(_clickId + 4);
for (var i = 0; i < maxVisibleRows && i + _scrollPosition < _lines.Count; i++)
{
var text = _lines[i + _scrollPosition];
// Add ellipsis if there's more text below
if (i == maxVisibleRows - 1 && i + _scrollPosition < _lines.Count - 1)
{
text += "...";
}

SendButton(
currentId++,
(byte)(_top + i * _rowHeight),
_left,
textAreaWidth,
_rowHeight,
text,
_style | ButtonStyles.ISB_C4,
ButtonType.TextLine
);
}
}

private void SendButton(
byte clickId,
byte top,
byte left,
byte width,
byte height,
string text,
ButtonStyles style,
ButtonType type)
{
_buttonInfo[clickId] = new ButtonInfo { Type = type, Text = text };

var button = new IS_BTN
{
ReqI = 1,
ClickID = clickId,
UCID = _ucid,
T = top,
L = left,
W = width,
H = height,
Text = text,
BStyle = style
};

_inSim.Send(button);
}

private void HandleButtonClick(IS_BTC packet)
{
if (!_buttonInfo.ContainsKey(packet.ClickID))
return;

var buttonInfo = _buttonInfo[packet.ClickID];
var maxVisibleRows = _height / _rowHeight;

switch (buttonInfo.Type)
{
case ButtonType.ScrollUp when _scrollPosition > 0:
_scrollPosition--;
DrawButtons();
break;

case ButtonType.ScrollDown when _scrollPosition + maxVisibleRows < _lines.Count:
_scrollPosition++;
DrawButtons();
break;
}
}

private void LogButtonInfo()
{
Console.WriteLine("\nButton Information:");
foreach (KeyValuePair<byte, ButtonInfo> button in _buttonInfo)
{
Console.WriteLine($"ClickID {button.Key}: Type={button.Value.Type}, Text={button.Value.Text}");
}
Console.WriteLine($"Total Buttons: {_buttonInfo.Count}");
}

private void ClearButtons()
{
foreach (var clickId in _buttonInfo.Keys.ToList())
{
var button = new IS_BFN
{
ReqI = 1,
UCID = _ucid,
ClickID = clickId,
SubT = ButtonFunction.BFN_DEL_BTN
};
_inSim.Send(button);
}
_buttonInfo.Clear();
}

private static List<string> SplitTextIntoLines(string text, int maxCharsPerLine)
{
var words = text.Split(' ');
var lines = new List<string>();
var currentLine = "";

foreach (var word in words)
{
if (currentLine.Length + word.Length + 1 <= maxCharsPerLine)
{
if (currentLine.Length > 0)
currentLine += " ";
currentLine += word;
}
else
{
if (currentLine.Length > 0)
lines.Add(currentLine);
currentLine = word;
}
}

if (currentLine.Length > 0)
lines.Add(currentLine);

return lines;
}
}

// Example usage
class Program
{
static void Main(string[] args)
{
Console.WriteLine("=== InSim Multi-line Button Test ===\n");
Console.WriteLine("This test demonstrates the InSim packet flow for multi-line buttons.\n");

var inSim = new InSim();
MultiLineButton multiLineButton = null;

try
{
inSim.Initialize(new InSimSettings
{
Host = "127.0.0.1",
Port = 29999,
Admin = "",
Prefix = '/',
Interval = 100,
Flags = InSimFlags.ISF_LOCAL
});

var testText = @"^7InSim Packets Explained:

1. ^7IS_BTN (Button) Packet:
- ^7ReqI: Request ID (1)
- ^7UCID: Connection ID
- ^7ClickID: Unique button ID
- ^7Inst: 0
- ^7BStyle: Button style flags
- ^7TypeIn: Max chars (0-240)
- ^7L,T: Position
- ^7W,H: Size
- ^7Text: Button text

2. ^7IS_BTC (Button Click):
- ^7ReqI: Copy of button ReqI
- ^7UCID: Connection that clicked
- ^7ClickID: Clicked button ID
- ^7Inst: 0
- ^7CFlags: Click flags

3. ^7IS_BFN (Button Function):
- ^7ReqI: Request ID
- ^7SubT: Delete/clear/etc
- ^7UCID: Target connection
- ^7ClickID: Target button";

multiLineButton = new MultiLineButton(
inSim: inSim,
clickId: 1,
ucid: 0,
width: 40,
height: 30,
top: 20,
left: 20,
rowHeight: 5,
maxCharsPerRow: 20,
text: testText,
style: ButtonStyles.ISB_C1
);

multiLineButton.Show();

Console.WriteLine("\nProgram is running. Press 'H' to hide the button, 'S' to show it again, or 'Q' to quit.");

while (true)
{
var key = Console.ReadKey(true);
switch (char.ToUpper(key.KeyChar))
{
case 'H':
multiLineButton.Hide();
Console.WriteLine("Button hidden");
break;
case 'S':
multiLineButton.Show();
Console.WriteLine("Button shown");
break;
case 'Q':
Console.WriteLine("Exiting...");
return;
}
}
}
catch (Exception ex)
{
Console.WriteLine($"An error occurred: {ex.Message}");
}
finally
{
if (multiLineButton != null)
{
multiLineButton.Hide();
}

if (inSim != null)
{
inSim.Disconnect();
inSim.Dispose();
}
}
}
}
}


Hope it helps new people that are interested in it Smile the text box looks like this hope it helps
Attached images
image_2025-05-21_212541815.png
This is great, tnx man.

Insim Button
(16 posts, started )
FGED GREDG RDFGDR GSFDG