Skip to content

Commit 15d16cd

Browse files
committed
add: 终端添加字符,重叠的情况还没写完
1 parent f9aecef commit 15d16cd

File tree

4 files changed

+235
-42
lines changed

4 files changed

+235
-42
lines changed

llcomNext/LLCOM/Models/TerminalBlock.cs

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System;
2+
using System.Collections.Generic;
23
using Avalonia.Media;
34
using Wcwidth;
45

@@ -49,7 +50,43 @@ public string Text
4950

5051
public int Length => _length;
5152

52-
53+
/// <summary>
54+
/// 生成一个新的终端块
55+
/// 格式和当前的终端块一致
56+
/// </summary>
57+
public TerminalBlock MakeNew(string text) =>
58+
new TerminalBlock(text, Background, Foreground, IsBold, IsUnderLine, IsItalic);
59+
60+
//合并样式相同的数据块,优化性能
61+
public static void OptimizeBlocks(List<TerminalBlock> blocks)
62+
{
63+
if (blocks.Count == 0)
64+
return;
65+
var newBlocks = new List<TerminalBlock>();
66+
var currentBlock = blocks[0];
67+
foreach (var block in blocks)
68+
{
69+
if(block == currentBlock)//第一个块是自己
70+
continue;
71+
if (block.Background != currentBlock.Background ||
72+
block.Foreground != currentBlock.Foreground ||
73+
block.IsBold != currentBlock.IsBold ||
74+
block.IsUnderLine != currentBlock.IsUnderLine ||
75+
block.IsItalic != currentBlock.IsItalic)
76+
{
77+
newBlocks.Add(currentBlock);
78+
currentBlock = block;
79+
}
80+
else
81+
{
82+
currentBlock.Text += block.Text;
83+
}
84+
}
85+
newBlocks.Add(currentBlock);
86+
blocks.Clear();
87+
blocks.AddRange(newBlocks);
88+
}
89+
5390
/// <summary>
5491
/// 一个终端块,包含各项信息
5592
/// </summary>

llcomNext/LLCOM/Models/TerminalObject.cs

Lines changed: 176 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
using System;
22
using System.Collections.Generic;
3+
using System.Linq;
4+
using System.Text;
35
using CommunityToolkit.Mvvm.ComponentModel;
46
using LLCOM.Services;
7+
using Wcwidth;
58

69
namespace LLCOM.Models;
710

@@ -22,6 +25,166 @@ private void TerminalChanged()
2225
TerminalChangedEvent?.Invoke(this, GetShowLines());
2326
}
2427

28+
//用于存放终端数据的缓存
29+
private readonly List<List<TerminalBlock>> _cacheLines = [];
30+
31+
//当前光标位置
32+
//X从0开始,最大可到达窗口宽度(再增加就需要换行了)
33+
//Y从0开始,最大可到达窗口高度-1
34+
private int _positionX = 0;
35+
private int _positionY = 0;
36+
37+
//当前的颜色、字体等信息,存到TerminalBlock中
38+
private TerminalBlock _currentState = new(String.Empty);
39+
40+
//MaxCacheLines表示终端缓存的行数,超过这个行数后会删除最上面的行
41+
private readonly int _maxCacheLines = Utils.Setting.TerminalBufferLines;
42+
43+
//可视范围内的宽高
44+
private int _windowWidth;
45+
private int _windowHeight;
46+
47+
//添加新的一行上去
48+
private void AddLine()
49+
{
50+
//添加行
51+
_cacheLines.Add([]);
52+
//如果超过了最大行数,删除最上面的行
53+
if (_cacheLines.Count > _maxCacheLines)
54+
_cacheLines.RemoveAt(0);
55+
if (_currentLine != 0)
56+
{
57+
_currentLine--;
58+
//如果当前行数超过了最大行数,设置为最大行数
59+
if (_currentLine > _cacheLines.Count - _windowHeight)
60+
_currentLine = _cacheLines.Count - _windowHeight;
61+
if (_currentLine < 0) _currentLine = 0;
62+
}
63+
}
64+
65+
/// <summary>
66+
/// 基于当前光标,往后追加文本
67+
/// 文本不得包含不可见字符
68+
/// </summary>
69+
/// <param name="text">待添加的文本</param>
70+
public void AddText(char[] texts)//TODO)) 保持private
71+
{
72+
//防止没有设置窗口大小的时候就添加数据
73+
if(_windowWidth == 0 || _windowHeight == 0)
74+
return;
75+
76+
var chars = texts[..];
77+
while (chars.Length > 0)
78+
{
79+
//当前光标位置后还有多少个字符的空间
80+
var space = _windowWidth - _positionX;
81+
//剩余空间不足,添加新行
82+
if (space <= 0)
83+
{
84+
_positionX = 0;
85+
_positionY++;//超过高度后面再管
86+
space = _windowWidth;
87+
}
88+
//记录一下修改前的X光标位置
89+
var oldX = _positionX;
90+
91+
//放置文本
92+
var sb = new StringBuilder();
93+
while (space > 0 && chars.Length > 0)
94+
{
95+
//获取实际的字符宽度
96+
var length = UnicodeCalculator.GetWidth(chars[0]);
97+
//挖去可用空间
98+
space -= length;
99+
if(space < 0)//剩余空间不足,别添加了
100+
break;
101+
//添加字符
102+
sb.Append(chars[0]);
103+
//去除掉已经添加的字符
104+
chars = chars[1..];
105+
//光标位置往后挪动
106+
_positionX += length;
107+
}
108+
//添加文本
109+
var text = sb.ToString();
110+
var line = _currentState.MakeNew(text);
111+
112+
//这一行数据要修改
113+
List<TerminalBlock> needChangeLine;
114+
115+
//超过了最大高度,说明要新开一行
116+
if (_positionY >= _windowHeight)
117+
{
118+
_positionY = _windowHeight - 1;
119+
AddLine();
120+
needChangeLine = _cacheLines[^1];
121+
}
122+
//当前缓存的行数还没有达到显示行高,也开新行
123+
else if (_cacheLines.Count - 1 < _positionY)
124+
{
125+
var needLineCount = _positionY - _cacheLines.Count + 1;
126+
for (int i = 0; i < needLineCount; i++)
127+
AddLine();
128+
needChangeLine = _cacheLines[^1];
129+
}
130+
//不是新行,需要更改当前行的数据
131+
else
132+
{
133+
//计算开始行下标的偏移量
134+
var lineStartOffset = _cacheLines.Count - _windowHeight;
135+
if(lineStartOffset < 0)
136+
lineStartOffset = 0;
137+
//使用当前行
138+
needChangeLine = _cacheLines[_positionY + lineStartOffset];
139+
}
140+
141+
var allLength = needChangeLine.Sum(l => l.Length);
142+
//光标没有重叠,说明可以直接添加到当前行
143+
if (oldX >= allLength)
144+
{
145+
//看有没有缺的空间,有的话用空格补齐
146+
if (oldX > allLength)
147+
needChangeLine.Add(new(new(' ', oldX - allLength)));
148+
needChangeLine.Add(line);
149+
}
150+
else
151+
{
152+
//TODO)) 这里需要处理光标重叠的情况
153+
// //查找一下看开始的位置是重叠到哪个元素了
154+
// var hitIndex = 0;
155+
// var hitLength = 0;
156+
// foreach (var block in oldLine)
157+
// {
158+
// if (hitLength + block.Length > oldX)
159+
// break;
160+
// hitLength += block.Length;
161+
// hitIndex++;
162+
// }
163+
// //查找看看结束的位置是重叠到哪个元素了
164+
// var endIndex = hitIndex;
165+
// var endLength = hitLength;
166+
// for(int i = hitIndex; i < oldLine.Count; i++)
167+
// {
168+
// if (endLength + oldLine[i].Length > _positionX)
169+
// break;
170+
// endLength += oldLine[i].Length;
171+
// endIndex++;
172+
// }
173+
174+
}
175+
176+
//优化当前这一行数据块
177+
TerminalBlock.OptimizeBlocks(needChangeLine);
178+
}
179+
}
180+
181+
//TODO)) 仅用于测试
182+
public void ChangePosition(int x, int y)
183+
{
184+
_positionX = x;
185+
_positionY = y;
186+
}
187+
25188
/// <summary>
26189
/// 获取可以显示的行数据
27190
/// </summary>
@@ -48,15 +211,22 @@ public List<List<TerminalBlock>> GetShowLines()
48211
cacheLines.Add(line);
49212
}
50213

214+
//如果行数不够,补齐空行
215+
for (int i = cacheLines.Count; i < _windowHeight; i++)
216+
{
217+
//添加空行
218+
cacheLines.Add([]);
219+
}
220+
//把当前光标位置背景和前景色反色处理
221+
var posY = _positionY;
222+
if (posY < _cacheLines.Count)
223+
{
224+
//TODO)) 这里需要处理光标位置
225+
}
226+
51227
return cacheLines;
52228
}
53229

54-
//MaxCacheLines表示终端缓存的行数,超过这个行数后会删除最上面的行
55-
private readonly int _maxCacheLines = Utils.Setting.TerminalBufferLines;
56-
57-
//可视范围内的宽高
58-
private int _windowWidth;
59-
private int _windowHeight;
60230
//窗口大小变化
61231
public void ChangeWindowSize(int width, int height)
62232
{
@@ -65,9 +235,6 @@ public void ChangeWindowSize(int width, int height)
65235
TerminalChanged();
66236
}
67237

68-
//用于存放终端数据的缓存
69-
private readonly List<List<TerminalBlock>> _cacheLines = new();
70-
71238
//当前所在的行数相比较于终端最底部的行数,0表示在最底部,其余数字表示向上挪动的行数
72239
private int _currentLine = 0;
73240

@@ -102,25 +269,4 @@ public void ScrollBarChanged(double value)
102269
if(lastCurrentLine != _currentLine)
103270
TerminalChanged();
104271
}
105-
106-
107-
//TODO)) 仅供测试使用
108-
public void AddLine(List<TerminalBlock> line)
109-
{
110-
//添加行
111-
_cacheLines.Add(line);
112-
//如果超过了最大行数,删除最上面的行
113-
if (_cacheLines.Count > _maxCacheLines)
114-
_cacheLines.RemoveAt(0);
115-
if (_currentLine != 0)
116-
{
117-
_currentLine--;
118-
//如果当前行数超过了最大行数,设置为最大行数
119-
if (_currentLine > _cacheLines.Count - _windowHeight)
120-
_currentLine = _cacheLines.Count - _windowHeight;
121-
}
122-
123-
//更新数据
124-
TerminalChanged();
125-
}
126272
}

llcomNext/LLCOM/ViewModels/DataViews/TerminalViewModel.cs

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -27,21 +27,31 @@ public TerminalViewModel(Func<Type, ViewModelBase> getService)
2727
//更新数据
2828
TerminalChangedEvent?.Invoke(this, args);
2929
};
30+
}
31+
32+
[RelayCommand]
33+
private void Test()
34+
{
35+
TerminalObject.ChangePosition(0, 0);
36+
TerminalObject.AddText($"A".ToCharArray());
37+
TerminalObject.ChangePosition(20, 0);
38+
TerminalObject.AddText($"B".ToCharArray());
39+
TerminalObject.ChangePosition(0, 20);
40+
TerminalObject.AddText($"C".ToCharArray());
41+
TerminalObject.ChangePosition(20, 20);
42+
TerminalObject.AddText($"D".ToCharArray());
3043

31-
for(int i=0;i<200;i++)
32-
{
33-
var line = new List<TerminalBlock>();
34-
line.Add(new TerminalBlock($"test string {i} line.", 0, 0, false, false, false));
35-
line.Add(new TerminalBlock($"balabala", 0, 31, false, false, false));
36-
TerminalObject.AddLine(line);
37-
}
44+
TerminalChangedEvent?.Invoke(this, TerminalObject.GetShowLines());
3845
}
3946

40-
//终端对象,后续需要为每项操作加锁 TODO))
47+
//终端对象, TODO)) 后续需要为每项操作加锁
4148
public readonly TerminalObject TerminalObject = new TerminalObject();
4249

4350
//窗口大小变化
44-
public void ChangeWindowSize((int,int) size) => TerminalObject.ChangeWindowSize(size.Item1, size.Item2);
51+
public void ChangeWindowSize((int, int) size)
52+
{
53+
TerminalObject.ChangeWindowSize(size.Item1, size.Item2);
54+
}
4555

4656
//滚轮事件
4757
public double MoveUp(int delta) => TerminalObject.CurrentLineMoveUp(delta);

llcomNext/LLCOM/Views/DataViews/TerminalView.axaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,11 @@
2424
HorizontalAlignment="Right"
2525
Orientation="Horizontal"
2626
Spacing="8">
27-
<TextBlock VerticalAlignment="Center" Text="选择数据输入源" />
27+
<TextBlock VerticalAlignment="Center" Text="数据源" />
2828
<ComboBox Width="200" SelectedIndex="0">
2929
<ComboBoxItem Content="串口1" />
3030
</ComboBox>
31-
<Button Content="清空数据" />
31+
<Button Command="{Binding TestCommand}" Content="清空数据" />
3232
</StackPanel>
3333
</Border>
3434
<Panel

0 commit comments

Comments
 (0)