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
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();
}
}
}
}
}